@ornncompute/cli 1.0.72 → 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 (59) hide show
  1. package/README.md +55 -24
  2. package/package.json +4 -2
  3. package/src/admin-capacity-reservations.mjs +6 -13
  4. package/src/admin-command-handlers.mjs +2 -1
  5. package/src/admin-credits.mjs +1 -2
  6. package/src/admin-enrollment.mjs +22 -30
  7. package/src/admin-mutations.mjs +6 -56
  8. package/src/admin-node-diagnostics.mjs +3 -41
  9. package/src/admin-node-lifecycle.mjs +40 -160
  10. package/src/admin-node-sanitize.mjs +243 -0
  11. package/src/admin-shell.mjs +39 -32
  12. package/src/catalog-shell.mjs +6 -6
  13. package/src/evidence-commands.mjs +4 -6
  14. package/src/external-bucket-commands.mjs +76 -96
  15. package/src/interaction-runtime.mjs +5 -37
  16. package/src/kubernetes-commands.mjs +25 -183
  17. package/src/launch-mode-handlers.mjs +0 -1
  18. package/src/machine-reference.mjs +33 -56
  19. package/src/mount-commands.mjs +25 -131
  20. package/src/slurm-commands.mjs +13 -2
  21. package/src/storage-commands.mjs +2 -87
  22. package/src/vm-commands.mjs +48 -101
  23. package/vendor/api-client/commerce.js +743 -0
  24. package/vendor/capabilities/cli.js +7688 -7
  25. package/vendor/capabilities/capabilities/admin-capacity-reservations.js +0 -101
  26. package/vendor/capabilities/capabilities/admin-enrollment.js +0 -321
  27. package/vendor/capabilities/capabilities/admin-node-diagnostics.js +0 -88
  28. package/vendor/capabilities/capabilities/admin-nodes-lifecycle.js +0 -235
  29. package/vendor/capabilities/capabilities/admin.js +0 -91
  30. package/vendor/capabilities/capabilities/cli.js +0 -156
  31. package/vendor/capabilities/capabilities/clusters.js +0 -248
  32. package/vendor/capabilities/capabilities/commerce-market.js +0 -405
  33. package/vendor/capabilities/capabilities/compute.js +0 -523
  34. package/vendor/capabilities/capabilities/credits.js +0 -78
  35. package/vendor/capabilities/capabilities/evidence.js +0 -145
  36. package/vendor/capabilities/capabilities/external-buckets.js +0 -191
  37. package/vendor/capabilities/capabilities/fleet.js +0 -306
  38. package/vendor/capabilities/capabilities/identity.js +0 -129
  39. package/vendor/capabilities/capabilities/listings.js +0 -398
  40. package/vendor/capabilities/capabilities/locality.js +0 -42
  41. package/vendor/capabilities/capabilities/market-shared.js +0 -46
  42. package/vendor/capabilities/capabilities/markets.js +0 -482
  43. package/vendor/capabilities/capabilities/mounts.js +0 -176
  44. package/vendor/capabilities/capabilities/native-listing.js +0 -99
  45. package/vendor/capabilities/capabilities/networks.js +0 -1264
  46. package/vendor/capabilities/capabilities/observability.js +0 -218
  47. package/vendor/capabilities/capabilities/organization-invites.js +0 -53
  48. package/vendor/capabilities/capabilities/reservation-list.js +0 -68
  49. package/vendor/capabilities/capabilities/staff-shared.js +0 -64
  50. package/vendor/capabilities/capabilities/tokens.js +0 -165
  51. package/vendor/capabilities/capabilities/users.js +0 -159
  52. package/vendor/capabilities/capabilities/volumes.js +0 -178
  53. package/vendor/capabilities/capability.js +0 -99
  54. package/vendor/capabilities/cli-catalog.js +0 -73
  55. package/vendor/capabilities/cli-migrations.js +0 -264
  56. package/vendor/capabilities/names.js +0 -6
  57. package/vendor/capabilities/software-catalog.js +0 -82
  58. package/vendor/capabilities/spec-catalog.js +0 -151
  59. package/vendor/capabilities/supplier-directory.js +0 -20
@@ -640,7 +640,7 @@ async function show(input, runtime, command) {
640
640
  return mountResult(runtime.interaction, await fetchMount(runtime, reservationId), reservationId);
641
641
  }
642
642
 
643
- export async function attachVolumeMount(input, runtime, { skipReview = false } = {}) {
643
+ export async function attachVolumeMount(input, runtime) {
644
644
  const [rawReservation] = positionals(
645
645
  input,
646
646
  1,
@@ -684,50 +684,23 @@ export async function attachVolumeMount(input, runtime, { skipReview = false } =
684
684
  }
685
685
  );
686
686
  }
687
- if (!skipReview) {
688
- const accepted = await runtime.interaction.review({
689
- title: "Attach managed volume",
690
- terms: [
691
- { label: "Capacity reservation", value: reservationId },
692
- { label: "Managed volume", value: `${projectedVolume.name} (${projectedVolume.id})` },
693
- { label: "Access", value: access },
694
- { label: "Machine scope", value: "Every machine in the reservation" },
695
- {
696
- label: "Volume lifecycle",
697
- value: "The volume remains independent from this relationship",
698
- },
699
- ],
700
- prompt: "Attach this volume?",
687
+ const refreshedVolume = safeVolume(await resolveVolume(runtime, projectedVolume.id));
688
+ if (refreshedVolume.id !== projectedVolume.id || refreshedVolume.name !== projectedVolume.name) {
689
+ runtime.interaction.error("The selected managed volume changed before attachment.", {
690
+ code: "volume_selection_changed",
691
+ });
692
+ }
693
+ current = await fetchMount(runtime, reservationId);
694
+ if (current && ["detached", "ended"].includes(current.lifecycle.phase)) current = null;
695
+ if (mountSatisfied(current, goal)) {
696
+ return wait && !mountReady(current)
697
+ ? waitForMount(input, runtime, reservationId, current, "volume-mounts attach")
698
+ : mountResult(runtime.interaction, current, reservationId, { replayed: true });
699
+ }
700
+ if (current) {
701
+ runtime.interaction.error("The volume-mount relationship changed before attachment.", {
702
+ code: "volume_mount_conflict",
701
703
  });
702
- if (!accepted) {
703
- return runtime.interaction.result({
704
- errors: [{ code: "declined", message: "Volume attachment declined.", retryable: false }],
705
- exitCode: 1,
706
- outcome: { class: "ended", phase: "declined" },
707
- presentation: { lines: ["Volume attachment declined. No relationship was created."] },
708
- });
709
- }
710
- const refreshedVolume = safeVolume(await resolveVolume(runtime, projectedVolume.id));
711
- if (
712
- refreshedVolume.id !== projectedVolume.id ||
713
- refreshedVolume.name !== projectedVolume.name
714
- ) {
715
- runtime.interaction.error("The selected managed volume changed after review.", {
716
- code: "volume_selection_changed",
717
- });
718
- }
719
- current = await fetchMount(runtime, reservationId);
720
- if (current && ["detached", "ended"].includes(current.lifecycle.phase)) current = null;
721
- if (mountSatisfied(current, goal)) {
722
- return wait && !mountReady(current)
723
- ? waitForMount(input, runtime, reservationId, current, "volume-mounts attach")
724
- : mountResult(runtime.interaction, current, reservationId, { replayed: true });
725
- }
726
- if (current) {
727
- runtime.interaction.error("The volume-mount relationship changed after review.", {
728
- code: "volume_mount_conflict",
729
- });
730
- }
731
704
  }
732
705
 
733
706
  try {
@@ -805,7 +778,7 @@ async function waitCommand(input, runtime, command) {
805
778
  );
806
779
  }
807
780
 
808
- export async function detachVolumeMount(input, runtime, { skipReview = false } = {}) {
781
+ export async function detachVolumeMount(input, runtime) {
809
782
  const [rawReservation] = positionals(
810
783
  input,
811
784
  1,
@@ -831,42 +804,13 @@ export async function detachVolumeMount(input, runtime, { skipReview = false } =
831
804
  },
832
805
  });
833
806
  }
834
- if (!skipReview) {
835
- const accepted = await runtime.interaction.review({
836
- title: "Detach managed volume",
837
- terms: [
838
- { label: "Capacity reservation", value: reservationId },
839
- {
840
- label: "Managed volume",
841
- value: `${current.volume.name ?? "Managed volume"} (${current.volume.id})`,
842
- },
843
- {
844
- label: "Mounted machines",
845
- value: `${current.readiness.ready} of ${current.readiness.expected}`,
846
- },
847
- {
848
- label: "Consequence",
849
- value: "Mounted access ends; the managed volume and its data remain",
850
- },
851
- ],
852
- prompt: "Detach this volume?",
807
+ const refreshed = await fetchMount(runtime, reservationId);
808
+ if (!refreshed || refreshed.id !== current.id || refreshed.volume.id !== current.volume.id) {
809
+ runtime.interaction.error("The volume-mount relationship changed before detachment.", {
810
+ code: "volume_mount_changed",
853
811
  });
854
- if (!accepted) {
855
- return runtime.interaction.result({
856
- errors: [{ code: "declined", message: "Volume detachment declined.", retryable: false }],
857
- exitCode: 1,
858
- outcome: { class: "ended", phase: "declined" },
859
- presentation: { lines: ["Volume detachment declined. No relationship was changed."] },
860
- });
861
- }
862
- const refreshed = await fetchMount(runtime, reservationId);
863
- if (!refreshed || refreshed.id !== current.id || refreshed.volume.id !== current.volume.id) {
864
- runtime.interaction.error("The volume-mount relationship changed after review.", {
865
- code: "volume_mount_changed",
866
- });
867
- }
868
- current = refreshed;
869
812
  }
813
+ current = refreshed;
870
814
  try {
871
815
  await runtime.fetch(reservationAttachmentPath(reservationId), {
872
816
  method: "DELETE",
@@ -933,28 +877,10 @@ async function deployFilesystem(input, runtime) {
933
877
  ? waitForMount(input, runtime, reservationId, current, "filesystems deploy")
934
878
  : mountResult(runtime.interaction, current, reservationId, { replayed: true });
935
879
  }
936
- const accepted = await runtime.interaction.review({
937
- title: "Deploy managed filesystem",
938
- terms: [
939
- { label: "Capacity reservation", value: reservationId },
940
- { label: "Performance tier", value: performanceTier },
941
- { label: "Capacity", value: `${capacityGib} GiB` },
942
- { label: "Readiness", value: "Reported independently for every machine" },
943
- ],
944
- prompt: "Deploy this filesystem?",
945
- });
946
- if (!accepted) {
947
- return runtime.interaction.result({
948
- errors: [{ code: "declined", message: "Filesystem deployment declined.", retryable: false }],
949
- exitCode: 1,
950
- outcome: { class: "ended", phase: "declined" },
951
- presentation: { lines: ["Filesystem deployment declined. No deployment was created."] },
952
- });
953
- }
954
880
  current = await fetchMount(runtime, reservationId);
955
881
  if (current && ["detached", "ended"].includes(current.lifecycle.phase)) current = null;
956
882
  if (current && !filesystemSatisfied(current, performanceTier, capacityGib)) {
957
- runtime.interaction.error("The managed filesystem relationship changed after review.", {
883
+ runtime.interaction.error("The managed filesystem relationship changed before deployment.", {
958
884
  code: "filesystem_deployment_conflict",
959
885
  });
960
886
  }
@@ -1032,41 +958,9 @@ async function deleteFilesystem(input, runtime) {
1032
958
  },
1033
959
  });
1034
960
  }
1035
- const accepted = await runtime.interaction.review({
1036
- title: "Delete managed filesystem deployment",
1037
- terms: [
1038
- { label: "Capacity reservation", value: reservationId },
1039
- {
1040
- label: "Managed volume",
1041
- value: `${current.volume.name ?? "Managed volume"} (${current.volume.id})`,
1042
- },
1043
- {
1044
- label: "Mounted machines",
1045
- value: `${current.readiness.ready} of ${current.readiness.expected}`,
1046
- },
1047
- {
1048
- label: "Consequence",
1049
- value: "Filesystem access ends; the managed volume and its data remain",
1050
- },
1051
- ],
1052
- prompt: "Delete this filesystem deployment?",
1053
- });
1054
- if (!accepted) {
1055
- return runtime.interaction.result({
1056
- data: {
1057
- filesystem_deployment: current,
1058
- reservation_id: reservationId,
1059
- volume_preserved: current.volume,
1060
- },
1061
- errors: [{ code: "declined", message: "Filesystem deletion declined.", retryable: false }],
1062
- exitCode: 1,
1063
- outcome: { class: "ended", phase: "declined" },
1064
- presentation: { lines: ["Filesystem deletion declined. No relationship was changed."] },
1065
- });
1066
- }
1067
961
  const refreshed = await fetchMount(runtime, reservationId);
1068
962
  if (!refreshed || refreshed.id !== current.id || refreshed.volume.id !== current.volume.id) {
1069
- runtime.interaction.error("The managed filesystem relationship changed after review.", {
963
+ runtime.interaction.error("The managed filesystem relationship changed before deletion.", {
1070
964
  code: "filesystem_deployment_changed",
1071
965
  });
1072
966
  }
@@ -33,6 +33,17 @@ function commandText(invocation) {
33
33
  return [invocation.command, ...invocation.args].map(shellQuote).join(" ");
34
34
  }
35
35
 
36
+ // Preserve the CLI result's summary; reads and picker state use Commerce JSON.
37
+ function reservationSummary(reservation) {
38
+ return {
39
+ id: reservation.reservationId,
40
+ facility: null,
41
+ hardware: reservation.gpuSlug ?? (reservation.reservedGpuCount === 0 ? "cpu" : null),
42
+ machine_count: reservation.reservedNodeCount,
43
+ region: null,
44
+ };
45
+ }
46
+
36
47
  function safeLogin(runtime, credentials, input) {
37
48
  const credentialType = text(credentials.credential_type);
38
49
  if (credentialType && credentialType !== "login-ssh") {
@@ -159,7 +170,7 @@ export function createSlurmConnectModeHandler({ spawnProcess = spawnProcessDefau
159
170
  return {
160
171
  action: retryConnectAction(prepared.cluster),
161
172
  data: {
162
- capacity_reservation: prepared.capacityReservation,
173
+ capacity_reservation: reservationSummary(prepared.capacityReservation),
163
174
  cluster: prepared.cluster,
164
175
  private_transport: transport,
165
176
  ssh: null,
@@ -198,7 +209,7 @@ export function createSlurmConnectModeHandler({ spawnProcess = spawnProcessDefau
198
209
  user: login.user,
199
210
  };
200
211
  const data = {
201
- capacity_reservation: prepared.capacityReservation,
212
+ capacity_reservation: reservationSummary(prepared.capacityReservation),
202
213
  cluster: prepared.cluster,
203
214
  private_transport: transport,
204
215
  ssh,
@@ -21,11 +21,6 @@ import {
21
21
  const DEFAULT_PAGE_LIMIT = 50;
22
22
  const MAX_PAGE_LIMIT = 500;
23
23
  const STORAGE_PREFIX = "/nodes/storage-drives";
24
- const UNSAFE_CONTENT_COMMANDS = new Set([
25
- "storage.volumes.clear",
26
- "storage.volumes.files.delete",
27
- "storage.volumes.folders.delete",
28
- ]);
29
24
 
30
25
  /**
31
26
  * Narrow CLI adapter expected by executeStorageCommand:
@@ -381,48 +376,11 @@ export async function resolveVolume(runtime, reference) {
381
376
  return resolveFromRows(await fetchDrives(runtime), reference);
382
377
  }
383
378
 
384
- async function review(runtime, options) {
385
- const accepted = await runtime.interaction.review(options);
386
- if (accepted !== false) return null;
387
- return runtime.interaction.result({
388
- data: null,
389
- exitCode: 1,
390
- outcome: { class: "ended", phase: "declined" },
391
- });
392
- }
393
-
394
- async function unsafeReview(command, input, runtime, reference, remotePath) {
395
- if (!UNSAFE_CONTENT_COMMANDS.has(command)) return null;
396
- const title =
397
- command === "storage.volumes.clear"
398
- ? "Clear volume contents"
399
- : command === "storage.volumes.files.delete"
400
- ? "Delete volume file"
401
- : "Delete volume folder";
402
- const terms = [
403
- { label: "Volume", value: reference },
404
- ...(remotePath ? [{ label: "Remote path", value: remotePath }] : []),
405
- {
406
- label: "Consequence",
407
- value:
408
- command === "storage.volumes.clear"
409
- ? "Every file and folder will be permanently deleted"
410
- : "The selected content will be permanently deleted",
411
- },
412
- ];
413
- return review(runtime, {
414
- prompt: "Continue?",
415
- requireLive: true,
416
- terms,
417
- title,
418
- });
419
- }
420
-
421
379
  async function createVolume(input, runtime) {
422
380
  positionals(
423
381
  input,
424
382
  0,
425
- "Usage: ornn volumes create --name <name> [--source <volume>] [--yes] [--idempotency-key <key>]"
383
+ "Usage: ornn volumes create --name <name> [--source <volume>] [--idempotency-key <key>]"
426
384
  );
427
385
  requireMachineMutationKey(input, runtime);
428
386
  const name = normalizeVolumeName(input.name);
@@ -439,21 +397,6 @@ async function createVolume(input, runtime) {
439
397
  { code: "volume_name_ambiguous", field: "name" }
440
398
  );
441
399
  }
442
- const declined = await review(runtime, {
443
- prompt: "Create this volume?",
444
- terms: [
445
- { label: "Volume name", value: name },
446
- { label: "Source", value: source ? String(source.id) : "empty volume" },
447
- {
448
- label: "Consequence",
449
- value: source
450
- ? "Create a durable managed volume copied from the selected source"
451
- : "Create an empty durable managed volume",
452
- },
453
- ],
454
- title: "Create volume",
455
- });
456
- if (declined) return declined;
457
400
  if (matches.length === 1) {
458
401
  const existing = matches[0];
459
402
  const existingSource = existing?.source_drive_id ?? existing?.source?.source_drive_id ?? null;
@@ -550,8 +493,6 @@ async function showVolume(input, runtime, { refresh = false } = {}) {
550
493
 
551
494
  async function clearVolume(input, runtime) {
552
495
  const [reference] = positionals(input, 1, "Usage: ornn volumes clear <volume>");
553
- const declined = await unsafeReview("storage.volumes.clear", input, runtime, reference);
554
- if (declined) return declined;
555
496
  const drive = await resolveVolume(runtime, reference);
556
497
  try {
557
498
  const payload = await runtime.fetch(
@@ -590,15 +531,6 @@ async function clearVolume(input, runtime) {
590
531
  async function deleteVolume(input, runtime) {
591
532
  const [reference] = positionals(input, 1, "Usage: ornn volumes delete <volume>");
592
533
  requireMachineMutationKey(input, runtime);
593
- const declined = await review(runtime, {
594
- prompt: "Delete this volume?",
595
- terms: [
596
- { label: "Volume", value: reference },
597
- { label: "Consequence", value: "The volume and all data in it will be permanently deleted" },
598
- ],
599
- title: "Delete volume",
600
- });
601
- if (declined) return declined;
602
534
  const drive = await resolveVolume(runtime, reference);
603
535
  try {
604
536
  await runtime.fetch(
@@ -802,7 +734,7 @@ async function uploadFile(input, runtime) {
802
734
  const [reference, localFile] = positionals(
803
735
  input,
804
736
  2,
805
- "Usage: ornn volumes files upload <volume> <local-file> [--path <remote-path>] [--content-type <type>] [--yes] [--idempotency-key <key>]"
737
+ "Usage: ornn volumes files upload <volume> <local-file> [--path <remote-path>] [--content-type <type>] [--idempotency-key <key>]"
806
738
  );
807
739
  requireMachineMutationKey(input, runtime);
808
740
  let fileInfo;
@@ -825,21 +757,6 @@ async function uploadFile(input, runtime) {
825
757
  ? requiredText(input.contentType, "--content-type")
826
758
  : "application/octet-stream";
827
759
  const drive = await resolveVolume(runtime, reference);
828
- const declined = await review(runtime, {
829
- prompt: "Upload this file?",
830
- terms: [
831
- { label: "Volume", value: `${drive.name} (${drive.id})` },
832
- { label: "Local file", value: localFile },
833
- { label: "Remote path", value: remotePath },
834
- { label: "Bytes", value: String(fileInfo.size) },
835
- {
836
- label: "Consequence",
837
- value: "Create or replace the selected path in the managed volume",
838
- },
839
- ],
840
- title: "Upload volume file",
841
- });
842
- if (declined) return declined;
843
760
  const requestHash = createHash("sha256");
844
761
  for await (const chunk of createReadStream(localFile)) requestHash.update(chunk);
845
762
  const sha256 = requestHash.digest("hex");
@@ -1032,8 +949,6 @@ async function deleteContent(command, input, runtime) {
1032
949
  `Usage: ornn volumes ${kind === "file" ? "files" : "folders"} delete <volume> <remote-path>`
1033
950
  );
1034
951
  const remotePath = normalizeRemotePath(rawRemotePath);
1035
- const declined = await unsafeReview(command, input, runtime, reference, remotePath);
1036
- if (declined) return declined;
1037
952
  const drive = await resolveVolume(runtime, reference);
1038
953
  const endpoint = computeEndpoint(
1039
954
  `${STORAGE_PREFIX}/${encodeURIComponent(String(drive.id))}/${kind}s/${encodedRemotePath(remotePath)}`