@ornncompute/cli 1.0.75 → 1.0.97

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.
Files changed (52) hide show
  1. package/README.md +32 -5
  2. package/package.json +4 -2
  3. package/src/admin-capacity-reservations.mjs +4 -1
  4. package/src/admin-command-handlers.mjs +2 -0
  5. package/src/admin-node-diagnostics.mjs +1 -5
  6. package/src/admin-node-lifecycle.mjs +23 -125
  7. package/src/admin-node-sanitize.mjs +243 -0
  8. package/src/catalog-shell.mjs +6 -6
  9. package/src/evidence-commands.mjs +4 -6
  10. package/src/external-bucket-commands.mjs +71 -23
  11. package/src/interaction-runtime.mjs +3 -0
  12. package/src/kubernetes-commands.mjs +16 -83
  13. package/src/machine-reference.mjs +33 -56
  14. package/src/slurm-commands.mjs +13 -2
  15. package/src/vm-commands.mjs +39 -59
  16. package/vendor/api-client/commerce.js +743 -0
  17. package/vendor/capabilities/cli.js +7688 -7
  18. package/vendor/capabilities/capabilities/admin-capacity-reservations.js +0 -101
  19. package/vendor/capabilities/capabilities/admin-enrollment.js +0 -322
  20. package/vendor/capabilities/capabilities/admin-node-diagnostics.js +0 -88
  21. package/vendor/capabilities/capabilities/admin-nodes-lifecycle.js +0 -137
  22. package/vendor/capabilities/capabilities/admin.js +0 -91
  23. package/vendor/capabilities/capabilities/cli.js +0 -156
  24. package/vendor/capabilities/capabilities/clusters.js +0 -248
  25. package/vendor/capabilities/capabilities/commerce-market.js +0 -405
  26. package/vendor/capabilities/capabilities/compute.js +0 -523
  27. package/vendor/capabilities/capabilities/credits.js +0 -83
  28. package/vendor/capabilities/capabilities/evidence.js +0 -145
  29. package/vendor/capabilities/capabilities/external-buckets.js +0 -191
  30. package/vendor/capabilities/capabilities/fleet.js +0 -386
  31. package/vendor/capabilities/capabilities/identity.js +0 -129
  32. package/vendor/capabilities/capabilities/listings.js +0 -398
  33. package/vendor/capabilities/capabilities/locality.js +0 -42
  34. package/vendor/capabilities/capabilities/market-shared.js +0 -46
  35. package/vendor/capabilities/capabilities/markets.js +0 -482
  36. package/vendor/capabilities/capabilities/mounts.js +0 -176
  37. package/vendor/capabilities/capabilities/native-listing.js +0 -99
  38. package/vendor/capabilities/capabilities/networks.js +0 -1264
  39. package/vendor/capabilities/capabilities/observability.js +0 -253
  40. package/vendor/capabilities/capabilities/organization-invites.js +0 -53
  41. package/vendor/capabilities/capabilities/reservation-list.js +0 -68
  42. package/vendor/capabilities/capabilities/staff-shared.js +0 -64
  43. package/vendor/capabilities/capabilities/tokens.js +0 -161
  44. package/vendor/capabilities/capabilities/users.js +0 -157
  45. package/vendor/capabilities/capabilities/volumes.js +0 -178
  46. package/vendor/capabilities/capability.js +0 -99
  47. package/vendor/capabilities/cli-catalog.js +0 -73
  48. package/vendor/capabilities/cli-migrations.js +0 -264
  49. package/vendor/capabilities/names.js +0 -6
  50. package/vendor/capabilities/software-catalog.js +0 -82
  51. package/vendor/capabilities/spec-catalog.js +0 -151
  52. package/vendor/capabilities/supplier-directory.js +0 -20
@@ -1,386 +0,0 @@
1
- import { listSupplierOrganizations, listSupplierOrganizationPage } from "../supplier-directory.js";
2
- import { z } from "zod";
3
- import { defineCapability, preview } from "../capability.js";
4
- function queryPath(path, params) {
5
- const parts = [];
6
- for (const [key, value] of Object.entries(params)) {
7
- if (value?.trim())
8
- parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value.trim())}`);
9
- }
10
- return parts.length ? `${path}?${parts.join("&")}` : path;
11
- }
12
- const emptyInput = z.object({});
13
- const suppliersInput = z.object({
14
- q: z.string().optional(),
15
- offset: z.number().int().min(0).optional(),
16
- limit: z.number().int().min(1).max(1000).optional(),
17
- });
18
- const facilitiesInput = z.object({
19
- organization_id: z.string().optional(),
20
- cursor: z.string().optional(),
21
- limit: z.number().int().min(1).max(100).optional(),
22
- });
23
- const nodesInput = z.object({
24
- organization_id: z.string().optional(),
25
- facility_id: z.string().optional(),
26
- status: z.string().optional(),
27
- reservation_id: z.string().optional(),
28
- cursor: z.string().optional(),
29
- max: z.number().int().positive().max(5000).optional(),
30
- limit: z.number().int().positive().max(5000).optional(),
31
- });
32
- const nodeLifecycleInput = z.object({
33
- node_id: z.string().min(1),
34
- node_ref: z.string().optional(),
35
- reason: z.string().optional(),
36
- force: z.boolean().optional(),
37
- skip_cleanup: z.boolean().optional(),
38
- delete_node_record: z.literal(true).optional(),
39
- idempotency_key: z.string().optional(),
40
- yes: z.boolean().optional(),
41
- wait: z.boolean().optional(),
42
- timeout_seconds: z.number().positive().optional(),
43
- });
44
- const nodeExecInput = z.object({
45
- node_id: z.string().min(1),
46
- command: z.string().min(1),
47
- timeout_seconds: z.number().int().positive(),
48
- yes: z.boolean().optional(),
49
- });
50
- export const listSuppliersCapability = defineCapability({
51
- id: "supplier.list",
52
- domain: "fleet",
53
- roles: ["admin"],
54
- description: "List supplier organizations (id, name). Resolve supplier names to organization_id with this before nodes.list or facilities.list. When next_offset is present, pass it back as offset for the next page.",
55
- mutation: "read",
56
- http: { method: "GET", path: "/v1/organizations" },
57
- slack: {
58
- parameters: {
59
- type: "object",
60
- properties: {
61
- q: { type: "string", description: "Search supplier names." },
62
- offset: { type: "integer", description: "Use next_offset to fetch another page." },
63
- limit: { type: "integer", description: "Page size (Slack maximum 10)." },
64
- },
65
- },
66
- },
67
- input: suppliersInput,
68
- execute: async (ctx, input) => {
69
- const parsed = suppliersInput.parse(input);
70
- const paged = parsed.limit !== undefined || parsed.offset !== undefined || parsed.q !== undefined;
71
- const limit = parsed.limit ?? 25;
72
- const offset = parsed.offset ?? 0;
73
- const rows = paged
74
- ? await listSupplierOrganizationPage(ctx.fetch, { ...parsed, limit, offset })
75
- : await listSupplierOrganizations(ctx.fetch);
76
- return {
77
- suppliers: rows.map((org) => ({ id: org.id, name: org.name })),
78
- ...(paged && rows.length === limit ? { next_offset: offset + rows.length } : {}),
79
- };
80
- },
81
- });
82
- export const listFacilitiesCapability = defineCapability({
83
- id: "facilities.list",
84
- domain: "fleet",
85
- roles: ["admin"],
86
- description: "List facilities (id, display name, region, supplier organization id). Optional organization_id filter. When nextCursor is present, pass it back as cursor for the next page. Use facilities.show to resolve one facility id.",
87
- mutation: "read",
88
- http: { method: "GET", path: "/provisioning/facilities" },
89
- slack: {
90
- parameters: {
91
- type: "object",
92
- properties: {
93
- organization_id: {
94
- type: "string",
95
- description: "Optional supplier organization UUID from supplier.list.",
96
- },
97
- cursor: {
98
- type: "string",
99
- description: "Pass the previous response's nextCursor to fetch the next page.",
100
- },
101
- limit: {
102
- type: "integer",
103
- minimum: 1,
104
- maximum: 100,
105
- description: "Optional page size (maximum 100).",
106
- },
107
- },
108
- },
109
- },
110
- input: facilitiesInput,
111
- execute: async (ctx, input) => {
112
- const parsed = facilitiesInput.parse(input);
113
- return ctx.fetch(queryPath("/provisioning/facilities", {
114
- organizationId: parsed.organization_id,
115
- cursor: parsed.cursor,
116
- limit: parsed.limit === undefined ? undefined : String(parsed.limit),
117
- }), { method: "GET" });
118
- },
119
- });
120
- export const facilityShowInput = z.object({ facilityId: z.uuid() });
121
- export const facilityShowCapability = defineCapability({
122
- id: "facilities.show",
123
- domain: "fleet",
124
- roles: ["admin"],
125
- description: "Resolve one facility id (e.g. a listing's facilityId) to its display name, region and status.",
126
- mutation: "read",
127
- http: { method: "GET", path: "/provisioning/facilities/{facilityId}" },
128
- cli: false,
129
- slack: {
130
- parameters: {
131
- type: "object",
132
- properties: {
133
- facilityId: { type: "string", format: "uuid" },
134
- },
135
- required: ["facilityId"],
136
- },
137
- },
138
- input: facilityShowInput,
139
- execute: async (ctx, input) => {
140
- const parsed = facilityShowInput.parse(input);
141
- return ctx.fetch(`/provisioning/facilities/${encodeURIComponent(parsed.facilityId)}`, {
142
- method: "GET",
143
- });
144
- },
145
- });
146
- export const listNodesCapability = defineCapability({
147
- id: "nodes.list",
148
- domain: "fleet",
149
- roles: ["user", "admin"],
150
- description: "List nodes. Users see their own reserved machines. Admins see enrolled, ghost, and off-grid nodes. Call with no filters for the whole fleet. Optional reservation_id lists the nodes on one reservation (find a customer's reservations with reservation.list customerId). Optional organization_id (supplier), facility_id, and status (ghost, off-grid, bare-metal) narrow the same list. Paginate large fleets with cursor + max: pass the response's next_cursor back as cursor to fetch the next page; next_cursor is omitted once the page is not full. Never invent nodes. Never print private keys.",
151
- mutation: "read",
152
- http: { method: "GET", path: "/nodes" },
153
- slack: {
154
- parameters: {
155
- type: "object",
156
- properties: {
157
- organization_id: {
158
- type: "string",
159
- description: "Optional supplier organization UUID from supplier.list.",
160
- },
161
- facility_id: {
162
- type: "string",
163
- description: "Optional commerce facility UUID from facilities.list.",
164
- },
165
- reservation_id: {
166
- type: "string",
167
- description: "Optional reservation UUID from reservation_list. Lists that reservation's nodes.",
168
- },
169
- status: {
170
- type: "string",
171
- enum: ["ghost", "off-grid", "bare-metal"],
172
- description: "Optional orchestrator status filter. Default is all statuses.",
173
- },
174
- cursor: {
175
- type: "string",
176
- description: "Optional. Pass the previous response's next_cursor to fetch the next page.",
177
- },
178
- max: {
179
- type: "integer",
180
- description: "Optional page size (1-5000). Orchestrator default is 500.",
181
- },
182
- },
183
- },
184
- },
185
- input: nodesInput,
186
- execute: async (ctx, input) => {
187
- const parsed = nodesInput.parse(input);
188
- const pagination = {
189
- cursor: parsed.cursor,
190
- limit: parsed.max != null || parsed.limit != null ? String(parsed.max ?? parsed.limit) : undefined,
191
- };
192
- if (ctx.role === "user") {
193
- return ctx.fetch(queryPath("/nodes", pagination), { method: "GET" });
194
- }
195
- return ctx.fetch(queryPath("/nodes", {
196
- organization_id: parsed.organization_id,
197
- facility_id: parsed.facility_id,
198
- status: parsed.status,
199
- reservation_id: parsed.reservation_id,
200
- ...pagination,
201
- }), { method: "GET" });
202
- },
203
- });
204
- export const nodeOffGridCapability = defineCapability({
205
- id: "node.off-grid",
206
- domain: "fleet",
207
- roles: ["admin"],
208
- description: "Admin-only. Take a node off-grid (remove Ornn agent management, leave the host powered on). Slack waits for a human confirm. ",
209
- mutation: "preview-confirm",
210
- http: { method: "POST", path: "/nodes/{id}/off-grid" },
211
- cli: {
212
- command: ["admin", "nodes", "suspend-management"],
213
- vnext: {
214
- audience: "admin",
215
- category: "resource",
216
- command: ["admin", "nodes", "suspend-management"],
217
- outcome: "Remove Ornn management and managed access from one powered-on node.",
218
- human: "ornn admin nodes suspend-management <node-ref> [--reason TEXT] [] [--no-wait]",
219
- automation: "ornn admin nodes suspend-management <node-id> --idempotency-key KEY --format json",
220
- review: "Node, supplier, facility, capacity assignment, management removal, and managed-access loss.",
221
- },
222
- },
223
- slack: {
224
- parameters: {
225
- type: "object",
226
- properties: {
227
- node_id: { type: "string", description: "Node UUID from nodes.list." },
228
- reason: { type: "string" },
229
- },
230
- required: ["node_id"],
231
- },
232
- },
233
- input: nodeLifecycleInput,
234
- execute: async (ctx, input) => {
235
- const parsed = nodeLifecycleInput.parse(input);
236
- const id = parsed.node_id.trim();
237
- const body = {
238
- ...(parsed.idempotency_key ? { request_id: parsed.idempotency_key } : {}),
239
- ...(parsed.reason ? { reason: parsed.reason } : {}),
240
- };
241
- if (!ctx.confirmed) {
242
- return preview("node.off-grid", { node_id: id, ...body });
243
- }
244
- return ctx.fetch(`/nodes/${encodeURIComponent(id)}/off-grid`, {
245
- method: "POST",
246
- body,
247
- ...(parsed.idempotency_key ? { headers: { "Idempotency-Key": parsed.idempotency_key } } : {}),
248
- });
249
- },
250
- });
251
- export const nodeOnGridCapability = defineCapability({
252
- id: "node.on-grid",
253
- domain: "fleet",
254
- roles: ["admin"],
255
- description: "Admin-only. Re-enroll an off-grid node: orchestrator SSHs with the stored admin key and runs the installer with restore_node_id. No caller key. Slack waits for a human confirm. ",
256
- mutation: "preview-confirm",
257
- http: { method: "POST", path: "/nodes/{id}/on-grid" },
258
- cli: {
259
- command: ["admin", "nodes", "resume-management"],
260
- vnext: {
261
- audience: "admin",
262
- category: "resource",
263
- command: ["admin", "nodes", "resume-management"],
264
- outcome: "Restore Ornn management and managed access on one off-grid node.",
265
- human: "ornn admin nodes resume-management <node-ref> [] [--no-wait]",
266
- automation: "ornn admin nodes resume-management <node-id> --idempotency-key KEY --format json",
267
- review: "Node, supplier, facility, capacity assignment, remote re-enrollment, and restored managed access.",
268
- },
269
- },
270
- slack: {
271
- parameters: {
272
- type: "object",
273
- properties: {
274
- node_id: { type: "string", description: "Off-grid node UUID from nodes.list." },
275
- },
276
- required: ["node_id"],
277
- },
278
- },
279
- input: nodeLifecycleInput,
280
- execute: async (ctx, input) => {
281
- const parsed = nodeLifecycleInput.parse(input);
282
- const id = parsed.node_id.trim();
283
- if (!ctx.confirmed) {
284
- return preview("node.on-grid", { node_id: id });
285
- }
286
- return ctx.fetch(`/nodes/${encodeURIComponent(id)}/on-grid`, {
287
- method: "POST",
288
- body: {
289
- ...(parsed.idempotency_key ? { request_id: parsed.idempotency_key } : {}),
290
- },
291
- ...(parsed.idempotency_key ? { headers: { "Idempotency-Key": parsed.idempotency_key } } : {}),
292
- });
293
- },
294
- });
295
- export const nodeExecCapability = defineCapability({
296
- id: "node.exec",
297
- domain: "fleet",
298
- roles: ["admin"],
299
- description: "Admin-only. Run one unrestricted command on an enrolled node over orchestrator SSH with the stored admin key. Always pass timeout_seconds. Not an interactive shell. On NVIDIA hosts use nvidia-smi; on AMD Instinct use amd-smi. Runs on the tool call — no confirm, no y/N.",
300
- mutation: "immediate",
301
- http: { method: "POST", path: "/remote" },
302
- slack: {
303
- parameters: {
304
- type: "object",
305
- properties: {
306
- node_id: { type: "string", description: "Enrolled node UUID from nodes.list." },
307
- command: { type: "string", description: "Exact shell command to run. No allowlist." },
308
- timeout_seconds: {
309
- type: "integer",
310
- description: "Seconds to wait before killing the SSH command. Required. 1-900.",
311
- },
312
- },
313
- required: ["node_id", "command", "timeout_seconds"],
314
- },
315
- },
316
- input: nodeExecInput,
317
- execute: async (ctx, input) => {
318
- const parsed = nodeExecInput.parse(input);
319
- const id = parsed.node_id.trim();
320
- const timeoutSeconds = parsed.timeout_seconds;
321
- return ctx.fetch("/remote", {
322
- method: "POST",
323
- body: { node_id: id, command: parsed.command, timeout_seconds: timeoutSeconds },
324
- });
325
- },
326
- });
327
- export const nodeTerminateCapability = defineCapability({
328
- id: "node.terminate",
329
- domain: "fleet",
330
- roles: ["admin"],
331
- description: "Admin-only. Terminate a node record (best-effort clean + delete). Off-grid nodes need force: true. There is no deenroll verb. Slack waits for a human confirm. ",
332
- mutation: "preview-confirm",
333
- http: { method: "POST", path: "/nodes/{id}/terminate" },
334
- cli: {
335
- command: ["admin", "nodes", "terminate"],
336
- vnext: {
337
- audience: "admin",
338
- category: "resource",
339
- command: ["admin", "nodes", "terminate"],
340
- outcome: "End managed access and permanently delete one exact node record.",
341
- human: "ornn admin nodes terminate <node-ref> --delete-node-record [--skip-cleanup] [--reason TEXT] []",
342
- automation: "ornn admin nodes terminate <node-id> --delete-node-record --idempotency-key KEY --format json",
343
- review: "Node, supplier, facility, reservation/capacity, host cleanup, node-record deletion, and access loss.",
344
- },
345
- },
346
- slack: {
347
- parameters: {
348
- type: "object",
349
- properties: {
350
- node_id: { type: "string", description: "Node UUID from nodes.list." },
351
- reason: { type: "string" },
352
- force: { type: "boolean", description: "Required to delete an off-grid node." },
353
- },
354
- required: ["node_id"],
355
- },
356
- },
357
- input: nodeLifecycleInput,
358
- execute: async (ctx, input) => {
359
- const parsed = nodeLifecycleInput.parse(input);
360
- const id = parsed.node_id.trim();
361
- const force = parsed.force ?? parsed.skip_cleanup;
362
- const body = {
363
- ...(parsed.reason ? { reason: parsed.reason } : {}),
364
- ...(force !== undefined ? { force } : {}),
365
- ...(parsed.idempotency_key ? { request_id: parsed.idempotency_key } : {}),
366
- };
367
- if (!ctx.confirmed) {
368
- return preview("node.terminate", { node_id: id, ...body });
369
- }
370
- return ctx.fetch(`/nodes/${encodeURIComponent(id)}/terminate`, {
371
- method: "POST",
372
- body,
373
- ...(parsed.idempotency_key ? { headers: { "Idempotency-Key": parsed.idempotency_key } } : {}),
374
- });
375
- },
376
- });
377
- export const fleetCapabilities = [
378
- listSuppliersCapability,
379
- listFacilitiesCapability,
380
- facilityShowCapability,
381
- listNodesCapability,
382
- nodeOffGridCapability,
383
- nodeOnGridCapability,
384
- nodeExecCapability,
385
- nodeTerminateCapability,
386
- ];
@@ -1,129 +0,0 @@
1
- import { z } from "zod";
2
- import { defineCapability } from "../capability.js";
3
- const emptyInput = z.object({});
4
- const loginInput = z.object({
5
- authBase: z.string().min(1).optional(),
6
- noBrowser: z.boolean().optional(),
7
- pollInterval: z.number().positive().optional(),
8
- timeout: z.number().positive().optional(),
9
- });
10
- function executeSession(context, command, input) {
11
- if (!context.cli?.session) {
12
- throw new Error("This capability must execute through the Ornn CLI session runtime.");
13
- }
14
- return context.cli.session(command, input);
15
- }
16
- export const loginCapability = defineCapability({
17
- id: "identity.login",
18
- domain: "identity",
19
- roles: ["user"],
20
- description: "Authenticate the CLI with Ornn device authorization.",
21
- mutation: "local",
22
- http: { method: "POST", path: "/v1/cli/device/start" },
23
- input: loginInput,
24
- cli: {
25
- command: ["login"],
26
- vnext: {
27
- audience: "customer",
28
- category: "session",
29
- arguments: "semantic",
30
- outcome: "Authenticate in a browser and return to the terminal.",
31
- human: "ornn login [--no-browser] [--timeout <seconds>]",
32
- automation: "ornn login --format json",
33
- resumableStates: ["browser authorization"],
34
- related: ["context", "logout"],
35
- order: 1,
36
- },
37
- },
38
- mcp: false,
39
- slack: false,
40
- execute: async (context, input) => executeSession(context, "login", input),
41
- });
42
- export const contextCapability = defineCapability({
43
- id: "identity.context",
44
- domain: "identity",
45
- roles: ["user"],
46
- description: "Show the current server-verified organization context.",
47
- mutation: "read",
48
- http: { method: "GET", path: "/v1/cli/session" },
49
- input: emptyInput,
50
- cli: {
51
- command: ["context"],
52
- vnext: {
53
- audience: "customer",
54
- category: "session",
55
- arguments: "semantic",
56
- outcome: "Show the current user, selected organization, approval, and available organizations.",
57
- human: "ornn context",
58
- automation: "ornn context --format json",
59
- related: ["login", "logout"],
60
- order: 2,
61
- },
62
- },
63
- mcp: false,
64
- slack: false,
65
- execute: async (context, input) => executeSession(context, "context", input),
66
- });
67
- export const logoutCapability = defineCapability({
68
- id: "identity.logout",
69
- domain: "identity",
70
- roles: ["user"],
71
- description: "Revoke the remote CLI session and clear its local bearer.",
72
- mutation: "local",
73
- http: { method: "DELETE", path: "/v1/cli/session" },
74
- input: emptyInput,
75
- cli: {
76
- command: ["logout"],
77
- vnext: {
78
- audience: "customer",
79
- category: "session",
80
- outcome: "End the remote session and always remove the local bearer.",
81
- human: "ornn logout",
82
- automation: "ornn logout --format json",
83
- related: ["login", "context"],
84
- order: 3,
85
- },
86
- },
87
- mcp: false,
88
- slack: false,
89
- execute: async (context, input) => executeSession(context, "logout", input),
90
- });
91
- export const whoamiCapability = defineCapability({
92
- id: "identity.whoami",
93
- domain: "identity",
94
- roles: ["user", "admin"],
95
- description: "Show the signed-in Ornn user and organization.",
96
- mutation: "read",
97
- http: { method: "GET", path: "/v1/cli/session" },
98
- input: emptyInput,
99
- execute: async (ctx) => ctx.fetch("/v1/cli/session", { method: "GET" }),
100
- });
101
- export const statusCapability = defineCapability({
102
- id: "identity.status",
103
- domain: "identity",
104
- roles: ["user", "admin"],
105
- description: "Show Ornn platform status.",
106
- mutation: "read",
107
- http: { method: "GET", path: "/v1/cli/status" },
108
- input: emptyInput,
109
- execute: async (ctx) => ctx.fetch("/v1/cli/status", { method: "GET" }),
110
- cli: {
111
- command: ["status"],
112
- vnext: {
113
- audience: "customer",
114
- category: "platform",
115
- outcome: "Check current Ornn platform availability.",
116
- human: "ornn status",
117
- automation: "ornn status --format json",
118
- related: ["version", "resources"],
119
- order: 10,
120
- },
121
- },
122
- });
123
- export const identityCapabilities = [
124
- whoamiCapability,
125
- loginCapability,
126
- contextCapability,
127
- logoutCapability,
128
- statusCapability,
129
- ];