@ornncompute/cli 0.2.24 → 1.0.34

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 (90) hide show
  1. package/README.md +351 -426
  2. package/package.json +12 -6
  3. package/src/admin-capacity-reservations.mjs +305 -0
  4. package/src/admin-command-handlers.mjs +57 -0
  5. package/src/admin-enrollment.mjs +681 -0
  6. package/src/admin-mutations.mjs +187 -0
  7. package/src/admin-node-diagnostics.mjs +412 -0
  8. package/src/admin-node-lifecycle.mjs +905 -0
  9. package/src/admin-shell.mjs +456 -0
  10. package/src/api-client.mjs +81 -28
  11. package/src/atomic-output.mjs +112 -0
  12. package/src/auth-store.mjs +182 -11
  13. package/src/capability-catalog.mjs +7 -0
  14. package/src/catalog-shell.mjs +1363 -0
  15. package/src/cli.mjs +123 -10266
  16. package/src/connect-mode-handlers.mjs +170 -0
  17. package/src/device-auth.mjs +179 -62
  18. package/src/evidence-commands.mjs +1354 -0
  19. package/src/external-bucket-commands.mjs +1374 -0
  20. package/src/gpu-catalog.mjs +21 -0
  21. package/src/identity-file.mjs +28 -0
  22. package/src/interaction-runtime.mjs +310 -0
  23. package/src/kubernetes-commands.mjs +2235 -0
  24. package/src/launch-mode-handlers.mjs +119 -0
  25. package/src/machine-reference.mjs +285 -0
  26. package/src/mount-commands.mjs +1148 -0
  27. package/src/session-commands.mjs +565 -0
  28. package/src/slurm-commands.mjs +274 -0
  29. package/src/startup.mjs +34 -11
  30. package/src/storage-commands.mjs +1164 -0
  31. package/src/update.mjs +172 -24
  32. package/src/vm-commands.mjs +4308 -0
  33. package/src/vpn-secret-output.mjs +150 -0
  34. package/src/wait-runtime.mjs +231 -0
  35. package/vendor/capabilities/capabilities/admin-capacity-reservations.js +96 -0
  36. package/vendor/capabilities/capabilities/admin-enrollment.js +321 -0
  37. package/vendor/capabilities/capabilities/admin-node-diagnostics.js +88 -0
  38. package/vendor/capabilities/capabilities/admin-nodes-lifecycle.js +235 -0
  39. package/vendor/capabilities/capabilities/admin.js +89 -0
  40. package/vendor/capabilities/capabilities/cli.js +156 -0
  41. package/vendor/capabilities/capabilities/clusters.js +150 -1
  42. package/vendor/capabilities/capabilities/commerce-market.js +330 -0
  43. package/vendor/capabilities/capabilities/compute.js +522 -0
  44. package/vendor/capabilities/capabilities/evidence.js +145 -0
  45. package/vendor/capabilities/capabilities/external-buckets.js +191 -0
  46. package/vendor/capabilities/capabilities/fleet.js +77 -25
  47. package/vendor/capabilities/capabilities/identity.js +114 -3
  48. package/vendor/capabilities/capabilities/listings.js +141 -144
  49. package/vendor/capabilities/capabilities/market-shared.js +44 -0
  50. package/vendor/capabilities/capabilities/markets.js +449 -0
  51. package/vendor/capabilities/capabilities/mounts.js +176 -0
  52. package/vendor/capabilities/capabilities/networks.js +1264 -0
  53. package/vendor/capabilities/capabilities/observability.js +38 -8
  54. package/vendor/capabilities/capabilities/tokens.js +32 -17
  55. package/vendor/capabilities/capabilities/volumes.js +178 -0
  56. package/vendor/capabilities/capability.js +21 -14
  57. package/vendor/capabilities/cli-catalog.js +67 -0
  58. package/vendor/capabilities/cli-migrations.js +261 -0
  59. package/vendor/capabilities/cli.js +7 -0
  60. package/vendor/capabilities/software-catalog.js +36 -0
  61. package/vendor/capabilities/spec-catalog.js +28 -5
  62. package/vendor/capabilities/supplier-directory.js +20 -0
  63. package/src/catalog-dispatch.mjs +0 -605
  64. package/src/color.mjs +0 -71
  65. package/vendor/capabilities/capabilities/clusters.d.ts +0 -2
  66. package/vendor/capabilities/capabilities/fleet.d.ts +0 -8
  67. package/vendor/capabilities/capabilities/identity.d.ts +0 -3
  68. package/vendor/capabilities/capabilities/listings.d.ts +0 -51
  69. package/vendor/capabilities/capabilities/observability.d.ts +0 -5
  70. package/vendor/capabilities/capabilities/staff-access.d.ts +0 -29
  71. package/vendor/capabilities/capabilities/staff-access.js +0 -278
  72. package/vendor/capabilities/capabilities/staff-commerce.d.ts +0 -160
  73. package/vendor/capabilities/capabilities/staff-commerce.js +0 -689
  74. package/vendor/capabilities/capabilities/staff-fleet.d.ts +0 -140
  75. package/vendor/capabilities/capabilities/staff-fleet.js +0 -538
  76. package/vendor/capabilities/capabilities/staff-gtm.d.ts +0 -142
  77. package/vendor/capabilities/capabilities/staff-gtm.js +0 -521
  78. package/vendor/capabilities/capabilities/staff-shared.d.ts +0 -47
  79. package/vendor/capabilities/capabilities/staff-shared.js +0 -98
  80. package/vendor/capabilities/capabilities/tokens.d.ts +0 -10
  81. package/vendor/capabilities/capabilities/users.d.ts +0 -2
  82. package/vendor/capabilities/capability.d.ts +0 -93
  83. package/vendor/capabilities/catalog.d.ts +0 -3
  84. package/vendor/capabilities/catalog.js +0 -26
  85. package/vendor/capabilities/index.d.ts +0 -16
  86. package/vendor/capabilities/index.js +0 -16
  87. package/vendor/capabilities/names.d.ts +0 -6
  88. package/vendor/capabilities/role.d.ts +0 -6
  89. package/vendor/capabilities/role.js +0 -17
  90. package/vendor/capabilities/spec-catalog.d.ts +0 -78
@@ -0,0 +1,522 @@
1
+ import { z } from "zod";
2
+ import { defineCapability, } from "../capability.js";
3
+ const positionals = z.array(z.string()).default([]);
4
+ export const launchInput = z
5
+ .object({
6
+ $positionals: positionals,
7
+ guided: z.boolean().optional(),
8
+ idempotencyKey: z.string().optional(),
9
+ key: z.string().optional(),
10
+ keyId: z.string().optional(),
11
+ label: z.string().optional(),
12
+ machine: z.string().optional(),
13
+ machines: z.string().optional(),
14
+ mode: z.string().optional(),
15
+ mountAccess: z.string().optional(),
16
+ network: z.string().optional(),
17
+ noWait: z.boolean().optional(),
18
+ nodes: z.union([z.string(), z.number()]).optional(),
19
+ organization: z.string().optional(),
20
+ publicKey: z.string().optional(),
21
+ publicKeyFile: z.string().optional(),
22
+ reservation: z.string().optional(),
23
+ resume: z.union([z.string().min(1), z.literal(true)]).optional(),
24
+ timeout: z.string().optional(),
25
+ username: z.string().optional(),
26
+ wait: z.boolean().optional(),
27
+ yes: z.boolean().optional(),
28
+ volume: z.string().optional(),
29
+ })
30
+ .strict();
31
+ const keyListInput = z
32
+ .object({
33
+ $positionals: positionals,
34
+ cursor: z.string().optional(),
35
+ limit: z.coerce.number().int().min(1).max(500).optional(),
36
+ })
37
+ .strict();
38
+ const keyMutationInput = z
39
+ .object({
40
+ $positionals: positionals,
41
+ idempotencyKey: z.string().optional(),
42
+ key: z.string().optional(),
43
+ keyId: z.string().optional(),
44
+ label: z.string().optional(),
45
+ publicKey: z.string().optional(),
46
+ publicKeyFile: z.string().optional(),
47
+ yes: z.boolean().optional(),
48
+ })
49
+ .strict();
50
+ const machineListInput = z
51
+ .object({
52
+ $positionals: positionals,
53
+ cursor: z.string().optional(),
54
+ limit: z.coerce.number().int().min(1).max(500).optional(),
55
+ })
56
+ .strict();
57
+ const machineShowInput = z
58
+ .object({
59
+ $positionals: positionals,
60
+ guided: z.boolean().optional(),
61
+ })
62
+ .strict();
63
+ const machineWaitInput = z
64
+ .object({
65
+ $positionals: positionals,
66
+ guided: z.boolean().optional(),
67
+ timeout: z.string().optional(),
68
+ })
69
+ .strict();
70
+ const machineSwitchInput = z
71
+ .object({
72
+ $positionals: positionals,
73
+ guided: z.boolean().optional(),
74
+ eraseLocalData: z.boolean().optional(),
75
+ idempotencyKey: z.string().optional(),
76
+ mode: z.string().optional(),
77
+ network: z.string().optional(),
78
+ noWait: z.boolean().optional(),
79
+ timeout: z.string().optional(),
80
+ wait: z.boolean().optional(),
81
+ yes: z.boolean().optional(),
82
+ })
83
+ .strict();
84
+ const machineMaintenanceInput = z
85
+ .object({
86
+ $positionals: positionals,
87
+ eraseLocalData: z.boolean().optional(),
88
+ guided: z.boolean().optional(),
89
+ idempotencyKey: z.string().optional(),
90
+ noWait: z.boolean().optional(),
91
+ timeout: z.string().optional(),
92
+ wait: z.boolean().optional(),
93
+ yes: z.boolean().optional(),
94
+ })
95
+ .strict();
96
+ function runtime(context) {
97
+ const interaction = context.cli?.interaction;
98
+ if (!interaction)
99
+ throw new Error("This capability must execute through the Ornn CLI runtime.");
100
+ return interaction;
101
+ }
102
+ async function executeLaunch(context, input) {
103
+ const interaction = runtime(context);
104
+ if (!interaction.launch)
105
+ throw new Error("No launch mode handlers are registered.");
106
+ return interaction.launch({ context, input, interaction });
107
+ }
108
+ function executeSshKeys(command) {
109
+ return async (context, input) => {
110
+ const interaction = runtime(context);
111
+ if (!interaction.sshKeys)
112
+ throw new Error("SSH-key commands are unavailable.");
113
+ return interaction.sshKeys(command, input, context);
114
+ };
115
+ }
116
+ function executeMachines(command) {
117
+ return async (context, input) => {
118
+ const interaction = runtime(context);
119
+ if (!interaction.machines)
120
+ throw new Error("Machine commands are unavailable.");
121
+ return interaction.machines(command, input, context);
122
+ };
123
+ }
124
+ function cliOnly(specification) {
125
+ return defineCapability({ ...specification, mcp: false, slack: false });
126
+ }
127
+ export const launchCapability = cliOnly({
128
+ id: "access.launch",
129
+ domain: "access",
130
+ roles: ["user"],
131
+ description: "Launch one explicitly selected access mode from active reserved capacity.",
132
+ mutation: "preview-confirm",
133
+ input: launchInput,
134
+ cli: {
135
+ command: ["launch"],
136
+ vnext: {
137
+ arguments: "semantic",
138
+ audience: "customer",
139
+ category: "journey",
140
+ order: 2,
141
+ outcome: "Launch one reviewed VM, Bare Metal machine, Kubernetes cluster, or Slurm cluster from active reserved capacity, including a declared durable Bare Metal workspace.",
142
+ human: "ornn launch [<capacity-reservation>] --mode vm|bare-metal|kubernetes|slurm [--key <ssh-key>]; Bare Metal may add --network shared --volume <managed-volume> --mount-access read-only|read-write; Kubernetes/Slurm prompt for missing --network public|private and --nodes <membership-count>",
143
+ automation: "ornn launch <canonical-reservation-id> --mode vm|bare-metal|kubernetes|slurm --organization <id> --yes --idempotency-key <key> --format json; VM/Bare Metal/Slurm require --key <canonical-key-id>; Bare Metal may add --network shared --volume <canonical-volume-id> --mount-access read-only|read-write; Kubernetes/Slurm require --network public|private --nodes <membership-count> --machines <canonical-machine-ids>",
144
+ acceptedReferences: [
145
+ "canonical capacity-reservation ID",
146
+ "canonical eligible machine IDs",
147
+ "invocation-local eligible reservation and machine choices",
148
+ "exact SSH-key and managed-volume references; organization network shared",
149
+ ],
150
+ review: "organization, active capacity reservation, explicit access mode, native access, exact machine or cluster membership goal, declared SSH key, network and volume-mount relationships, allocation window and quantity, and wait behavior",
151
+ resumableStates: [
152
+ "partial durable workspace",
153
+ "accepted machine or cluster",
154
+ "native access ready",
155
+ "partial membership",
156
+ ],
157
+ related: [
158
+ "connect",
159
+ "machines list",
160
+ "clusters show",
161
+ "volume-mounts show",
162
+ "filesystems show",
163
+ "ssh-keys list",
164
+ "ssh-keys assignments status",
165
+ ],
166
+ },
167
+ },
168
+ execute: executeLaunch,
169
+ });
170
+ export const machineListCapability = cliOnly({
171
+ id: "access.machines.list",
172
+ domain: "access",
173
+ roles: ["user"],
174
+ description: "List direct VM and Bare Metal machines in one bounded page.",
175
+ mutation: "read",
176
+ input: machineListInput,
177
+ cli: {
178
+ command: ["machines", "list"],
179
+ vnext: {
180
+ arguments: "semantic",
181
+ audience: "customer",
182
+ category: "resource",
183
+ order: 460,
184
+ outcome: "List owned direct machines with lifecycle and SSH reachability kept separate.",
185
+ human: "ornn machines list [--limit <1-500>] [--cursor <opaque-cursor>]",
186
+ automation: "ornn machines list --limit 50 --format json",
187
+ acceptedReferences: ["opaque page cursor"],
188
+ related: ["machines show", "machines wait"],
189
+ },
190
+ },
191
+ execute: executeMachines("list"),
192
+ });
193
+ export const machineShowCapability = cliOnly({
194
+ id: "access.machines.show",
195
+ domain: "access",
196
+ roles: ["user"],
197
+ description: "Inspect one exact direct machine without changing it.",
198
+ mutation: "read",
199
+ input: machineShowInput,
200
+ cli: {
201
+ command: ["machines", "show"],
202
+ vnext: {
203
+ arguments: "semantic",
204
+ audience: "customer",
205
+ category: "resource",
206
+ order: 461,
207
+ outcome: "Show one exact VM or Bare Metal machine, its lifecycle, and independent SSH reachability.",
208
+ human: "ornn machines show <canonical-machine-id|exact-hostname>",
209
+ automation: "ornn machines show <canonical-machine-id> --format json",
210
+ acceptedReferences: [
211
+ "canonical machine ID",
212
+ "exact unique hostname",
213
+ "invocation-local guided choice",
214
+ ],
215
+ related: ["connect", "machines wait"],
216
+ },
217
+ },
218
+ execute: executeMachines("show"),
219
+ });
220
+ export const machineWaitCapability = cliOnly({
221
+ id: "access.machines.wait",
222
+ domain: "access",
223
+ roles: ["user"],
224
+ description: "Wait locally for one exact direct machine to become SSH-ready.",
225
+ mutation: "read",
226
+ input: machineWaitInput,
227
+ cli: {
228
+ command: ["machines", "wait"],
229
+ vnext: {
230
+ arguments: "semantic",
231
+ audience: "customer",
232
+ category: "resource",
233
+ order: 462,
234
+ outcome: "Wait for usable SSH without canceling remote work on timeout or interruption.",
235
+ human: "ornn machines wait <canonical-machine-id|exact-hostname> [--timeout <duration>]",
236
+ automation: "ornn machines wait <canonical-machine-id> --timeout <duration> --format json",
237
+ acceptedReferences: [
238
+ "canonical machine ID",
239
+ "exact unique hostname",
240
+ "invocation-local guided choice",
241
+ ],
242
+ resumableStates: ["provisioning", "SSH-key delivery pending", "SSH ready"],
243
+ related: ["machines show", "connect"],
244
+ },
245
+ },
246
+ execute: executeMachines("wait"),
247
+ });
248
+ export const machineSwitchCapability = cliOnly({
249
+ id: "access.machines.switch",
250
+ domain: "access",
251
+ roles: ["user"],
252
+ description: "Switch one direct-machine reservation's mode or network intent.",
253
+ mutation: "preview-confirm",
254
+ input: machineSwitchInput,
255
+ cli: {
256
+ command: ["machines", "switch"],
257
+ vnext: {
258
+ arguments: "semantic",
259
+ audience: "customer",
260
+ category: "resource",
261
+ order: 463,
262
+ outcome: "Change only the explicitly requested VM, Bare Metal, or network goal while retaining SSH-key intent.",
263
+ human: "ornn machines switch <canonical-reservation-id> [--mode vm|bare-metal] [--network public|private] [--erase-local-data]",
264
+ automation: "ornn machines switch <canonical-reservation-id> [--mode vm|bare-metal] [--network public|private] [--erase-local-data] --yes --idempotency-key <key> --format json",
265
+ acceptedReferences: ["canonical capacity-reservation ID"],
266
+ review: "exact reservation, current and requested access mode, network intent, retained SSH keys, access interruption, and permanent local-data erasure for cross-mode changes",
267
+ resumableStates: ["switch accepted", "SSH ready"],
268
+ related: ["machines wait", "connect"],
269
+ },
270
+ },
271
+ execute: executeMachines("switch"),
272
+ });
273
+ export const machineRebootCapability = cliOnly({
274
+ id: "access.machines.reboot",
275
+ domain: "access",
276
+ roles: ["user"],
277
+ description: "Reboot one exact direct machine after reviewing the access interruption.",
278
+ mutation: "preview-confirm",
279
+ input: machineMaintenanceInput,
280
+ cli: {
281
+ command: ["machines", "reboot"],
282
+ vnext: {
283
+ arguments: "semantic",
284
+ audience: "customer",
285
+ category: "resource",
286
+ order: 464,
287
+ outcome: "Reboot one exact machine and normally wait for restored SSH readiness.",
288
+ human: "ornn machines reboot <canonical-machine-id|exact-hostname> [--no-wait]",
289
+ automation: "ornn machines reboot <canonical-machine-id> --yes --idempotency-key <key> --format json",
290
+ acceptedReferences: [
291
+ "canonical machine ID",
292
+ "exact unique hostname",
293
+ "invocation-local guided choice",
294
+ ],
295
+ review: "temporary SSH interruption with SSH keys, network, mounted volume, and local data preserved",
296
+ resumableStates: ["reboot accepted", "SSH ready"],
297
+ related: ["machines wait", "connect"],
298
+ },
299
+ },
300
+ execute: executeMachines("reboot"),
301
+ });
302
+ export const machineResetCapability = cliOnly({
303
+ id: "access.machines.reset",
304
+ domain: "access",
305
+ roles: ["user"],
306
+ description: "Erase local machine data and hard reset one exact direct machine.",
307
+ mutation: "preview-confirm",
308
+ input: machineMaintenanceInput,
309
+ cli: {
310
+ command: ["machines", "reset"],
311
+ vnext: {
312
+ arguments: "semantic",
313
+ audience: "customer",
314
+ category: "resource",
315
+ order: 465,
316
+ outcome: "Hard reset one exact machine only with explicit local-data erasure scope and final consent.",
317
+ human: "ornn machines reset <canonical-machine-id|exact-hostname> --erase-local-data [--no-wait]",
318
+ automation: "ornn machines reset <canonical-machine-id> --erase-local-data --yes --idempotency-key <key> --format json",
319
+ acceptedReferences: [
320
+ "canonical machine ID",
321
+ "exact unique hostname",
322
+ "invocation-local guided choice",
323
+ ],
324
+ review: "permanent local-data erasure, temporary access interruption, restored SSH keys, and preserved external volume relationship",
325
+ resumableStates: ["reset accepted", "SSH ready"],
326
+ related: ["machines wait", "connect"],
327
+ },
328
+ },
329
+ execute: executeMachines("reset"),
330
+ });
331
+ export const sshKeyListCapability = cliOnly({
332
+ id: "access.ssh_keys.list",
333
+ domain: "access",
334
+ roles: ["user"],
335
+ mutation: "read",
336
+ input: keyListInput,
337
+ description: "List organization SSH keys in a bounded page.",
338
+ cli: {
339
+ command: ["ssh-keys", "list"],
340
+ vnext: {
341
+ arguments: "semantic",
342
+ audience: "customer",
343
+ category: "resource",
344
+ order: 450,
345
+ outcome: "List organization SSH keys without exposing key material.",
346
+ human: "ornn ssh-keys list [--limit <1-500>] [--cursor <cursor>]",
347
+ automation: "ornn ssh-keys list --format json [--limit <1-500>] [--cursor <cursor>]",
348
+ acceptedReferences: [],
349
+ related: ["ssh-keys add", "ssh-keys assignments list"],
350
+ },
351
+ },
352
+ execute: executeSshKeys("list"),
353
+ });
354
+ export const sshKeyAddCapability = cliOnly({
355
+ id: "access.ssh_keys.add",
356
+ domain: "access",
357
+ roles: ["user"],
358
+ mutation: "preview-confirm",
359
+ input: keyMutationInput,
360
+ description: "Add or replay one organization SSH public key.",
361
+ cli: {
362
+ command: ["ssh-keys", "add"],
363
+ vnext: {
364
+ arguments: "semantic",
365
+ audience: "customer",
366
+ category: "resource",
367
+ order: 451,
368
+ outcome: "Add one organization SSH public key by durable public-key identity.",
369
+ human: "ornn ssh-keys add --public-key-file <path> --label <label>",
370
+ automation: "ornn ssh-keys add --public-key <public-key> --label <label> --idempotency-key <key> --format json",
371
+ acceptedReferences: ["public key value", "public key file"],
372
+ resumableStates: ["ready"],
373
+ related: ["ssh-keys list", "ssh-keys assignments assign"],
374
+ },
375
+ },
376
+ execute: executeSshKeys("add"),
377
+ });
378
+ export const sshKeyDeleteCapability = cliOnly({
379
+ id: "access.ssh_keys.delete",
380
+ domain: "access",
381
+ roles: ["user"],
382
+ mutation: "preview-confirm",
383
+ input: keyMutationInput,
384
+ description: "Delete one exact organization SSH key after review.",
385
+ cli: {
386
+ command: ["ssh-keys", "delete"],
387
+ vnext: {
388
+ arguments: "semantic",
389
+ audience: "customer",
390
+ category: "resource",
391
+ order: 452,
392
+ outcome: "Delete one exact organization SSH key without implying machine delivery.",
393
+ human: "ornn ssh-keys delete <exact-key-id-or-label>",
394
+ automation: "ornn ssh-keys delete <canonical-key-id> --yes --idempotency-key <key> --format json",
395
+ acceptedReferences: [
396
+ "canonical SSH-key ID",
397
+ "exact unique key label in an eligible terminal",
398
+ ],
399
+ review: "key identity and loss of future access",
400
+ resumableStates: ["ended"],
401
+ related: ["ssh-keys list"],
402
+ },
403
+ },
404
+ execute: executeSshKeys("delete"),
405
+ });
406
+ export const sshKeyAssignmentListCapability = cliOnly({
407
+ id: "access.ssh_key_assignments.list",
408
+ domain: "access",
409
+ roles: ["user"],
410
+ mutation: "read",
411
+ input: keyListInput,
412
+ description: "List SSH keys assigned to one capacity reservation.",
413
+ cli: {
414
+ command: ["ssh-keys", "assignments", "list"],
415
+ vnext: {
416
+ arguments: "semantic",
417
+ audience: "customer",
418
+ category: "resource",
419
+ order: 453,
420
+ outcome: "List the SSH keys assigned to one exact capacity reservation.",
421
+ human: "ornn ssh-keys assignments list <canonical-reservation-id>",
422
+ automation: "ornn ssh-keys assignments list <canonical-reservation-id> --format json",
423
+ acceptedReferences: ["canonical capacity-reservation ID"],
424
+ related: ["ssh-keys assignments status"],
425
+ },
426
+ },
427
+ execute: executeSshKeys("assignments.list"),
428
+ });
429
+ export const sshKeyAssignmentAssignCapability = cliOnly({
430
+ id: "access.ssh_key_assignments.assign",
431
+ domain: "access",
432
+ roles: ["user"],
433
+ mutation: "preview-confirm",
434
+ input: keyMutationInput,
435
+ description: "Assign one existing organization SSH key to one capacity reservation.",
436
+ cli: {
437
+ command: ["ssh-keys", "assignments", "assign"],
438
+ vnext: {
439
+ arguments: "semantic",
440
+ audience: "customer",
441
+ category: "resource",
442
+ order: 454,
443
+ outcome: "Assign or replay one exact SSH-key relationship.",
444
+ human: "ornn ssh-keys assignments assign <canonical-reservation-id> --key <exact-key-id-or-label>",
445
+ automation: "ornn ssh-keys assignments assign <canonical-reservation-id> --key <canonical-key-id> --yes --idempotency-key <key> --format json",
446
+ acceptedReferences: [
447
+ "canonical capacity-reservation ID",
448
+ "canonical SSH-key ID",
449
+ "exact unique key label in an eligible terminal",
450
+ ],
451
+ review: "reservation and SSH-key relationship",
452
+ resumableStates: ["associated", "queued", "installed"],
453
+ related: ["ssh-keys assignments status"],
454
+ },
455
+ },
456
+ execute: executeSshKeys("assignments.assign"),
457
+ });
458
+ export const sshKeyAssignmentSyncCapability = cliOnly({
459
+ id: "access.ssh_key_assignments.sync",
460
+ domain: "access",
461
+ roles: ["user"],
462
+ mutation: "preview-confirm",
463
+ input: keyMutationInput,
464
+ description: "Synchronize assigned SSH keys to every active reservation machine.",
465
+ cli: {
466
+ command: ["ssh-keys", "assignments", "sync"],
467
+ vnext: {
468
+ arguments: "semantic",
469
+ audience: "customer",
470
+ category: "resource",
471
+ order: 455,
472
+ outcome: "Queue idempotent SSH-key synchronization and report delayed delivery honestly.",
473
+ human: "ornn ssh-keys assignments sync <canonical-reservation-id>",
474
+ automation: "ornn ssh-keys assignments sync <canonical-reservation-id> --yes --idempotency-key <key> --format json",
475
+ acceptedReferences: ["canonical capacity-reservation ID"],
476
+ review: "reservation, assigned keys, and target machines",
477
+ resumableStates: ["queued", "installed", "failed"],
478
+ related: ["ssh-keys assignments status"],
479
+ },
480
+ },
481
+ execute: executeSshKeys("assignments.sync"),
482
+ });
483
+ export const sshKeyAssignmentStatusCapability = cliOnly({
484
+ id: "access.ssh_key_assignments.status",
485
+ domain: "access",
486
+ roles: ["user"],
487
+ mutation: "read",
488
+ input: keyListInput,
489
+ description: "Show assigned, queued, installed, and failed SSH-key delivery per machine.",
490
+ cli: {
491
+ command: ["ssh-keys", "assignments", "status"],
492
+ vnext: {
493
+ arguments: "semantic",
494
+ audience: "customer",
495
+ category: "resource",
496
+ order: 456,
497
+ outcome: "Distinguish SSH-key assignment from delayed machine delivery.",
498
+ human: "ornn ssh-keys assignments status <canonical-reservation-id>",
499
+ automation: "ornn ssh-keys assignments status <canonical-reservation-id> --format json",
500
+ acceptedReferences: ["canonical capacity-reservation ID"],
501
+ resumableStates: ["associated", "queued", "installed", "failed"],
502
+ related: ["ssh-keys assignments sync", "connect"],
503
+ },
504
+ },
505
+ execute: executeSshKeys("assignments.status"),
506
+ });
507
+ export const computeCapabilities = [
508
+ launchCapability,
509
+ machineListCapability,
510
+ machineShowCapability,
511
+ machineWaitCapability,
512
+ machineSwitchCapability,
513
+ machineRebootCapability,
514
+ machineResetCapability,
515
+ sshKeyListCapability,
516
+ sshKeyAddCapability,
517
+ sshKeyDeleteCapability,
518
+ sshKeyAssignmentListCapability,
519
+ sshKeyAssignmentAssignCapability,
520
+ sshKeyAssignmentSyncCapability,
521
+ sshKeyAssignmentStatusCapability,
522
+ ];
@@ -0,0 +1,145 @@
1
+ import { z } from "zod";
2
+ import { defineCapability, } from "../capability.js";
3
+ const positionals = z.array(z.string()).default([]);
4
+ export const evidenceInput = z
5
+ .object({
6
+ $positionals: positionals,
7
+ before: z.string().optional(),
8
+ count: z.string().optional(),
9
+ cursor: z.string().optional(),
10
+ end: z.string().optional(),
11
+ follow: z.boolean().optional(),
12
+ guided: z.boolean().optional(),
13
+ interval: z.string().optional(),
14
+ limit: z.string().optional(),
15
+ maxPoints: z.string().optional(),
16
+ start: z.string().optional(),
17
+ stream: z.enum(["kernel", "serial"]).optional(),
18
+ timeout: z.string().optional(),
19
+ })
20
+ .strict();
21
+ function runtime(context) {
22
+ const interaction = context.cli?.interaction;
23
+ if (!interaction?.evidence)
24
+ throw new Error("The CLI evidence runtime is unavailable.");
25
+ return interaction;
26
+ }
27
+ function execute(command) {
28
+ return (context, input) => runtime(context).evidence(command, input, context);
29
+ }
30
+ function cliOnly({ automation, category, command, description, human, id, order, outcome, references, related, }) {
31
+ const executor = command.length === 1 ? "check" : `${command[0]}.${command[1]}`;
32
+ return defineCapability({
33
+ id,
34
+ domain: "observability",
35
+ roles: ["user"],
36
+ description,
37
+ mutation: "read",
38
+ input: evidenceInput,
39
+ cli: {
40
+ command,
41
+ vnext: {
42
+ arguments: "semantic",
43
+ audience: "customer",
44
+ category,
45
+ order,
46
+ outcome,
47
+ human,
48
+ automation,
49
+ acceptedReferences: references,
50
+ resumableStates: ["no data", "unavailable", "streaming", "ended", "interrupted"],
51
+ related,
52
+ },
53
+ },
54
+ mcp: false,
55
+ slack: false,
56
+ execute: execute(executor),
57
+ });
58
+ }
59
+ export const checkCapability = cliOnly({
60
+ id: "evidence.check",
61
+ command: ["check"],
62
+ category: "journey",
63
+ order: 4,
64
+ description: "Compose lifecycle, reachability, authoritative health, metrics, and logs for one machine or cluster.",
65
+ outcome: "Check one exact machine or cluster without turning missing evidence into health.",
66
+ human: "ornn check [<canonical-resource-id-or-exact-hostname>] [--follow] [--start <time> --end <time>]",
67
+ automation: "ornn check <canonical-machine-or-cluster-id> --start <time> --end <time> --max-points 240 --limit 200 --format json",
68
+ references: [
69
+ "canonical machine ID",
70
+ "exact unique machine hostname",
71
+ "canonical cluster ID",
72
+ "invocation-local guided choice",
73
+ ],
74
+ related: [
75
+ "connect",
76
+ "machines metrics",
77
+ "machines logs",
78
+ "clusters metrics",
79
+ "clusters logs",
80
+ "cost",
81
+ ],
82
+ });
83
+ export const machineMetricsCapability = cliOnly({
84
+ id: "evidence.machine_metrics",
85
+ command: ["machines", "metrics"],
86
+ category: "resource",
87
+ order: 560,
88
+ description: "Read or follow bounded customer-safe metrics for one exact machine.",
89
+ outcome: "Return normalized machine metrics with explicit evidence state and window.",
90
+ human: "ornn machines metrics [<machine-id-or-exact-hostname>] [--guided] [--start <time> --end <time>] [--max-points <1-500>] [--follow]",
91
+ automation: "ornn machines metrics <canonical-machine-id> --start <time> --end <time> --max-points 240 --format json",
92
+ references: [
93
+ "canonical machine ID",
94
+ "exact unique machine hostname",
95
+ "invocation-local guided choice",
96
+ ],
97
+ related: ["check", "machines logs"],
98
+ });
99
+ export const machineLogsCapability = cliOnly({
100
+ id: "evidence.machine_logs",
101
+ command: ["machines", "logs"],
102
+ category: "resource",
103
+ order: 561,
104
+ description: "Read or follow bounded customer-safe kernel or serial logs for one exact machine.",
105
+ outcome: "Return normalized machine logs with opaque pagination and unsafe lines omitted.",
106
+ human: "ornn machines logs [<machine-id-or-exact-hostname>] [--guided] [--stream kernel|serial] [--limit <1-500>] [--cursor <cursor>] [--follow]",
107
+ automation: "ornn machines logs <canonical-machine-id> --stream kernel --limit 200 --format json",
108
+ references: [
109
+ "canonical machine ID",
110
+ "exact unique machine hostname",
111
+ "invocation-local guided choice",
112
+ ],
113
+ related: ["check", "machines metrics"],
114
+ });
115
+ export const clusterMetricsCapability = cliOnly({
116
+ id: "evidence.cluster_metrics",
117
+ command: ["clusters", "metrics"],
118
+ category: "resource",
119
+ order: 562,
120
+ description: "Read or follow bounded customer-safe metrics for every member of one exact cluster.",
121
+ outcome: "Return normalized per-machine cluster metrics without changing cluster health.",
122
+ human: "ornn clusters metrics [<cluster-id>] [--guided] [--start <time> --end <time>] [--max-points <1-500>] [--follow]",
123
+ automation: "ornn clusters metrics <canonical-cluster-id> --start <time> --end <time> --max-points 240 --format json",
124
+ references: ["canonical cluster ID", "invocation-local guided choice"],
125
+ related: ["check", "clusters logs"],
126
+ });
127
+ export const clusterLogsCapability = cliOnly({
128
+ id: "evidence.cluster_logs",
129
+ command: ["clusters", "logs"],
130
+ category: "resource",
131
+ order: 563,
132
+ description: "Read or follow bounded customer-safe logs for every member of one exact cluster.",
133
+ outcome: "Return normalized per-machine cluster logs without exposing staff or supplier details.",
134
+ human: "ornn clusters logs [<cluster-id>] [--guided] [--stream kernel|serial] [--limit <1-500>] [--follow]",
135
+ automation: "ornn clusters logs <canonical-cluster-id> --stream kernel --limit 200 --format json",
136
+ references: ["canonical cluster ID", "invocation-local guided choice"],
137
+ related: ["check", "clusters metrics"],
138
+ });
139
+ export const evidenceCapabilities = [
140
+ checkCapability,
141
+ machineMetricsCapability,
142
+ machineLogsCapability,
143
+ clusterMetricsCapability,
144
+ clusterLogsCapability,
145
+ ];