@ornncompute/cli 1.0.124 → 1.0.126
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 +4 -1
- package/package.json +1 -1
- package/src/catalog-shell.mjs +2 -0
- package/src/network-commands.mjs +1187 -0
- package/src/vm-commands.mjs +2 -2
- package/vendor/api-client/orchestrator.js +141 -0
- package/vendor/capabilities/cli.js +175 -1011
|
@@ -203,6 +203,77 @@ function updateNodeSanitize(request, nodeId3, jobId, body2) {
|
|
|
203
203
|
return request(sanitizePath(nodeId3, jobId), { method: "PATCH", body: body2 });
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
+
// ../../packages/api-client/dist/orchestrator/networks.js
|
|
207
|
+
var networks = "/v1/orchestrator/networks";
|
|
208
|
+
function networkPath(id) {
|
|
209
|
+
return `${networks}/${encodeURIComponent(id)}`;
|
|
210
|
+
}
|
|
211
|
+
function listNetworks(request, signal) {
|
|
212
|
+
return request(networks, { method: "GET", ...signal ? { signal } : {} });
|
|
213
|
+
}
|
|
214
|
+
function getNetwork(request, id, query3 = {}, signal) {
|
|
215
|
+
const params = new URLSearchParams();
|
|
216
|
+
if (query3.overlay !== void 0)
|
|
217
|
+
params.set("overlay", String(query3.overlay));
|
|
218
|
+
return request(`${networkPath(id)}${params.size ? `?${params}` : ""}`, {
|
|
219
|
+
method: "GET",
|
|
220
|
+
...signal ? { signal } : {}
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
function createNetwork(request, body2, options = {}) {
|
|
224
|
+
return request(networks, { method: "POST", body: body2, ...options });
|
|
225
|
+
}
|
|
226
|
+
function updateNetwork(request, id, body2, options = {}) {
|
|
227
|
+
return request(networkPath(id), { method: "PATCH", body: body2, ...options });
|
|
228
|
+
}
|
|
229
|
+
function deleteNetwork(request, id, options = {}) {
|
|
230
|
+
return request(networkPath(id), { method: "DELETE", ...options });
|
|
231
|
+
}
|
|
232
|
+
function listNetworkPeerConfigs(request, networkId, signal) {
|
|
233
|
+
return request(`${networkPath(networkId)}/peers`, {
|
|
234
|
+
method: "GET",
|
|
235
|
+
...signal ? { signal } : {}
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
function createNetworkPeer(request, networkId, body2, options = {}) {
|
|
239
|
+
return request(`${networkPath(networkId)}/peers`, {
|
|
240
|
+
method: "POST",
|
|
241
|
+
body: body2,
|
|
242
|
+
...options
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
function deleteNetworkPeer(request, networkId, peerId, options = {}) {
|
|
246
|
+
return request(`${networkPath(networkId)}/peers/${encodeURIComponent(peerId)}`, {
|
|
247
|
+
method: "DELETE",
|
|
248
|
+
...options
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ../../packages/api-client/dist/orchestrator/controllers.js
|
|
253
|
+
var controllersSocketPath = "/v1/orchestrator/controllers";
|
|
254
|
+
function controllerPath(id) {
|
|
255
|
+
return `${controllersSocketPath}/${encodeURIComponent(id)}`;
|
|
256
|
+
}
|
|
257
|
+
function createController(request, body2, options) {
|
|
258
|
+
return request(controllersSocketPath, {
|
|
259
|
+
...options,
|
|
260
|
+
method: "POST",
|
|
261
|
+
body: body2
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
function addControllerNode(request, id, nodeId3, options) {
|
|
265
|
+
return request(`${controllerPath(id)}/nodes/${encodeURIComponent(nodeId3)}`, {
|
|
266
|
+
...options,
|
|
267
|
+
method: "POST"
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
function removeControllerNode(request, id, nodeId3, options) {
|
|
271
|
+
return request(`${controllerPath(id)}/nodes/${encodeURIComponent(nodeId3)}`, {
|
|
272
|
+
...options,
|
|
273
|
+
method: "DELETE"
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
206
277
|
// ../../packages/capabilities/dist/capabilities/admin-ssh.js
|
|
207
278
|
import { z } from "zod";
|
|
208
279
|
|
|
@@ -457,11 +528,11 @@ function listOrganizations(request, query3 = {}, signal) {
|
|
|
457
528
|
async function listSupplierOrganizations(request, signal) {
|
|
458
529
|
const rows = [];
|
|
459
530
|
for (let offset = 0; offset < 5e4; offset += 1e3) {
|
|
460
|
-
const
|
|
461
|
-
if (!Array.isArray(
|
|
531
|
+
const page = await listOrganizations(request, { role: "supplier", limit: 1e3, offset, sort: "created_at", direction: "asc" }, signal);
|
|
532
|
+
if (!Array.isArray(page))
|
|
462
533
|
throw new Error("Invalid supplier directory response.");
|
|
463
|
-
rows.push(...
|
|
464
|
-
if (
|
|
534
|
+
rows.push(...page);
|
|
535
|
+
if (page.length < 1e3)
|
|
465
536
|
return rows;
|
|
466
537
|
}
|
|
467
538
|
throw new Error("The supplier directory is too large to load completely.");
|
|
@@ -1443,8 +1514,8 @@ function query(params) {
|
|
|
1443
1514
|
for (const [key, value] of Object.entries(params))
|
|
1444
1515
|
if (value)
|
|
1445
1516
|
search.set(key, value);
|
|
1446
|
-
const
|
|
1447
|
-
return
|
|
1517
|
+
const text = search.toString();
|
|
1518
|
+
return text ? `?${text}` : "";
|
|
1448
1519
|
}
|
|
1449
1520
|
var MARKETS_SOCKET_PATH = `${BASE3}/ws`;
|
|
1450
1521
|
function scope({ saleType: saleType2, region: region2 } = {}) {
|
|
@@ -1574,11 +1645,11 @@ function resolveIdempotencyKey(ctx, supplied) {
|
|
|
1574
1645
|
return ctx.cli?.interaction?.idempotencyKey(supplied) ?? supplied?.trim();
|
|
1575
1646
|
}
|
|
1576
1647
|
async function consent(ctx, action, title, terms, payload) {
|
|
1577
|
-
const
|
|
1578
|
-
if (
|
|
1579
|
-
if (await
|
|
1648
|
+
const interaction = ctx.cli?.interaction;
|
|
1649
|
+
if (interaction) {
|
|
1650
|
+
if (await interaction.review({ title, terms }))
|
|
1580
1651
|
return null;
|
|
1581
|
-
return
|
|
1652
|
+
return interaction.result({
|
|
1582
1653
|
data: null,
|
|
1583
1654
|
errors: [{ code: "action_declined", message: "No changes were made.", retryable: false }],
|
|
1584
1655
|
exitCode: 1,
|
|
@@ -3532,31 +3603,31 @@ var machineMaintenanceInput = z17.object({
|
|
|
3532
3603
|
yes: z17.boolean().optional()
|
|
3533
3604
|
}).strict();
|
|
3534
3605
|
function runtime(context) {
|
|
3535
|
-
const
|
|
3536
|
-
if (!
|
|
3606
|
+
const interaction = context.cli?.interaction;
|
|
3607
|
+
if (!interaction)
|
|
3537
3608
|
throw new Error("This capability must execute through the Ornn CLI runtime.");
|
|
3538
|
-
return
|
|
3609
|
+
return interaction;
|
|
3539
3610
|
}
|
|
3540
3611
|
async function executeLaunch(context, input) {
|
|
3541
|
-
const
|
|
3542
|
-
if (!
|
|
3612
|
+
const interaction = runtime(context);
|
|
3613
|
+
if (!interaction.launch)
|
|
3543
3614
|
throw new Error("No launch mode handlers are registered.");
|
|
3544
|
-
return
|
|
3615
|
+
return interaction.launch({ context, input, interaction });
|
|
3545
3616
|
}
|
|
3546
3617
|
function executeSshKeys(command) {
|
|
3547
3618
|
return async (context, input) => {
|
|
3548
|
-
const
|
|
3549
|
-
if (!
|
|
3619
|
+
const interaction = runtime(context);
|
|
3620
|
+
if (!interaction.sshKeys)
|
|
3550
3621
|
throw new Error("SSH-key commands are unavailable.");
|
|
3551
|
-
return
|
|
3622
|
+
return interaction.sshKeys(command, input, context);
|
|
3552
3623
|
};
|
|
3553
3624
|
}
|
|
3554
3625
|
function executeMachines(command) {
|
|
3555
3626
|
return async (context, input) => {
|
|
3556
|
-
const
|
|
3557
|
-
if (!
|
|
3627
|
+
const interaction = runtime(context);
|
|
3628
|
+
if (!interaction.machines)
|
|
3558
3629
|
throw new Error("Machine commands are unavailable.");
|
|
3559
|
-
return
|
|
3630
|
+
return interaction.machines(command, input, context);
|
|
3560
3631
|
};
|
|
3561
3632
|
}
|
|
3562
3633
|
function cliOnly(specification) {
|
|
@@ -4617,9 +4688,6 @@ var controllerNode = z20.object({
|
|
|
4617
4688
|
nodeId: z20.string(),
|
|
4618
4689
|
confirm: z20.boolean().optional()
|
|
4619
4690
|
});
|
|
4620
|
-
function controllerNodePath(input) {
|
|
4621
|
-
return `/v1/orchestrator/controllers/${encodeURIComponent(input.controllerId)}/nodes/${encodeURIComponent(input.nodeId)}`;
|
|
4622
|
-
}
|
|
4623
4691
|
var clusterCapabilities = [
|
|
4624
4692
|
defineCapability({
|
|
4625
4693
|
id: "cluster.list",
|
|
@@ -4663,21 +4731,16 @@ var clusterCapabilities = [
|
|
|
4663
4731
|
networkMode: z20.enum(["public", "private"]).optional(),
|
|
4664
4732
|
nodeIds: z20.array(z20.string()).optional(),
|
|
4665
4733
|
nodeCount: z20.number().int().positive().optional(),
|
|
4666
|
-
storageLoadSizeBytes: z20.number().int().nonnegative().optional(),
|
|
4667
4734
|
confirm: z20.boolean().optional()
|
|
4668
|
-
}),
|
|
4735
|
+
}).strict(),
|
|
4669
4736
|
mcp: { name: "clusters_create" },
|
|
4670
4737
|
slack: false,
|
|
4671
|
-
execute: (ctx, input) => ctx.fetch
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
...input.nodeCount !== void 0 ? { node_count: input.nodeCount } : {},
|
|
4678
|
-
...input.nodeIds?.length ? { node_ids: input.nodeIds } : {},
|
|
4679
|
-
...input.storageLoadSizeBytes !== void 0 ? { storage_load_size_bytes: input.storageLoadSizeBytes } : {}
|
|
4680
|
-
}
|
|
4738
|
+
execute: (ctx, input) => createController(ctx.fetch, {
|
|
4739
|
+
kind: input.type,
|
|
4740
|
+
reservation_id: input.reservationId,
|
|
4741
|
+
...input.networkMode ? { network_mode: input.networkMode } : {},
|
|
4742
|
+
...input.nodeCount !== void 0 ? { node_count: input.nodeCount } : {},
|
|
4743
|
+
...input.nodeIds?.length ? { node_ids: input.nodeIds } : {}
|
|
4681
4744
|
})
|
|
4682
4745
|
}),
|
|
4683
4746
|
defineCapability({
|
|
@@ -4741,7 +4804,7 @@ var clusterCapabilities = [
|
|
|
4741
4804
|
input: controllerNode,
|
|
4742
4805
|
mcp: { name: "clusters_add_node" },
|
|
4743
4806
|
slack: false,
|
|
4744
|
-
execute: (ctx, input) => ctx.fetch
|
|
4807
|
+
execute: (ctx, input) => addControllerNode(ctx.fetch, input.controllerId, input.nodeId)
|
|
4745
4808
|
}),
|
|
4746
4809
|
defineCapability({
|
|
4747
4810
|
id: "cluster.remove_node",
|
|
@@ -4753,7 +4816,7 @@ var clusterCapabilities = [
|
|
|
4753
4816
|
input: controllerNode,
|
|
4754
4817
|
mcp: { name: "clusters_remove_node" },
|
|
4755
4818
|
slack: false,
|
|
4756
|
-
execute: (ctx, input) => ctx.fetch
|
|
4819
|
+
execute: (ctx, input) => removeControllerNode(ctx.fetch, input.controllerId, input.nodeId)
|
|
4757
4820
|
}),
|
|
4758
4821
|
defineCapability({
|
|
4759
4822
|
id: "cluster.teardown",
|
|
@@ -4824,11 +4887,11 @@ var importInput = z21.object({
|
|
|
4824
4887
|
yes: z21.boolean().optional()
|
|
4825
4888
|
}).strict();
|
|
4826
4889
|
function externalBucketExecutor(context) {
|
|
4827
|
-
const
|
|
4828
|
-
if (!
|
|
4890
|
+
const interaction = context.cli?.interaction;
|
|
4891
|
+
if (!interaction?.externalBuckets) {
|
|
4829
4892
|
throw new Error("This capability must execute through the Ornn CLI external-bucket runtime.");
|
|
4830
4893
|
}
|
|
4831
|
-
return
|
|
4894
|
+
return interaction.externalBuckets.bind(interaction);
|
|
4832
4895
|
}
|
|
4833
4896
|
function externalBucketCapability({ acceptedReferences = [], automation, command, description, human, id, input, mutation, outcome, related = [], resumableStates = [], review }) {
|
|
4834
4897
|
return defineCapability({
|
|
@@ -4969,10 +5032,10 @@ var evidenceInput = z22.object({
|
|
|
4969
5032
|
timeout: z22.string().optional()
|
|
4970
5033
|
}).strict();
|
|
4971
5034
|
function runtime2(context) {
|
|
4972
|
-
const
|
|
4973
|
-
if (!
|
|
5035
|
+
const interaction = context.cli?.interaction;
|
|
5036
|
+
if (!interaction?.evidence)
|
|
4974
5037
|
throw new Error("The CLI evidence runtime is unavailable.");
|
|
4975
|
-
return
|
|
5038
|
+
return interaction;
|
|
4976
5039
|
}
|
|
4977
5040
|
function execute(command) {
|
|
4978
5041
|
return (context, input) => runtime2(context).evidence(command, input, context);
|
|
@@ -5109,11 +5172,11 @@ var mountInput = z23.object({
|
|
|
5109
5172
|
yes: z23.boolean().optional()
|
|
5110
5173
|
}).strict();
|
|
5111
5174
|
function mountExecutor(context) {
|
|
5112
|
-
const
|
|
5113
|
-
if (!
|
|
5175
|
+
const interaction = context.cli?.interaction;
|
|
5176
|
+
if (!interaction?.mounts) {
|
|
5114
5177
|
throw new Error("This capability must execute through the Ornn CLI mount runtime.");
|
|
5115
5178
|
}
|
|
5116
|
-
return
|
|
5179
|
+
return interaction.mounts.bind(interaction);
|
|
5117
5180
|
}
|
|
5118
5181
|
function mountCapability({ acceptedReferences = [], automation, command, description, human, id, mutation, order, outcome, related = [], resumableStates = [], review }) {
|
|
5119
5182
|
return defineCapability({
|
|
@@ -5754,11 +5817,7 @@ var organizationInviteCapability = defineCapability({
|
|
|
5754
5817
|
|
|
5755
5818
|
// ../../packages/capabilities/dist/capabilities/networks.js
|
|
5756
5819
|
import { z as z27 } from "zod";
|
|
5757
|
-
var
|
|
5758
|
-
var DEFAULT_LIMIT = 50;
|
|
5759
|
-
var unknownRecordSchema = z27.record(z27.string(), z27.unknown());
|
|
5760
|
-
var MAX_LIMIT = 500;
|
|
5761
|
-
var NETWORKS_PATH = "/v1/workflows/compute/networks";
|
|
5820
|
+
var NETWORKS_PATH = "/v1/orchestrator/networks";
|
|
5762
5821
|
var globalInput = {
|
|
5763
5822
|
$positionals: z27.array(z27.string()).optional(),
|
|
5764
5823
|
guided: z27.boolean().optional(),
|
|
@@ -5786,892 +5845,11 @@ var vpnConfigureInput = z27.object({
|
|
|
5786
5845
|
output: z27.string().optional(),
|
|
5787
5846
|
privateKey: z27.string().optional()
|
|
5788
5847
|
}).strict();
|
|
5789
|
-
function
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
function interaction(context) {
|
|
5795
|
-
const cli = context.cli;
|
|
5796
|
-
const runtime3 = cli?.interaction;
|
|
5797
|
-
if (!runtime3)
|
|
5798
|
-
throw new Error("This capability must execute through the Ornn CLI interaction runtime.");
|
|
5799
|
-
return runtime3;
|
|
5800
|
-
}
|
|
5801
|
-
function text(value) {
|
|
5802
|
-
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
5803
|
-
}
|
|
5804
|
-
function shellQuote(value) {
|
|
5805
|
-
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
5806
|
-
}
|
|
5807
|
-
function record(value) {
|
|
5808
|
-
const parsed = unknownRecordSchema.safeParse(value);
|
|
5809
|
-
return parsed.success ? parsed.data : {};
|
|
5810
|
-
}
|
|
5811
|
-
function integer(value) {
|
|
5812
|
-
return typeof value === "number" && Number.isInteger(value) ? value : null;
|
|
5813
|
-
}
|
|
5814
|
-
function normalizedName(value) {
|
|
5815
|
-
return value.normalize("NFKC").trim().replace(/\s+/g, " ").toLocaleLowerCase("en-US");
|
|
5816
|
-
}
|
|
5817
|
-
function normalizedCidr(value) {
|
|
5818
|
-
const [address, rawPrefix, ...extra] = value.trim().split("/");
|
|
5819
|
-
const octets = address?.split(".").map(Number) ?? [];
|
|
5820
|
-
const prefix = Number(rawPrefix);
|
|
5821
|
-
if (extra.length || octets.length !== 4 || octets.some((octet) => !Number.isInteger(octet) || octet < 0 || octet > 255) || !Number.isInteger(prefix) || prefix < 0 || prefix > 32) {
|
|
5822
|
-
return value.trim();
|
|
5823
|
-
}
|
|
5824
|
-
const numeric = ((octets[0] * 256 + octets[1]) * 256 + octets[2]) * 256 + octets[3] >>> 0;
|
|
5825
|
-
const mask = prefix === 0 ? 0 : 4294967295 << 32 - prefix >>> 0;
|
|
5826
|
-
const network = (numeric & mask) >>> 0;
|
|
5827
|
-
return `${network >>> 24}.${network >>> 16 & 255}.${network >>> 8 & 255}.${network & 255}/${prefix}`;
|
|
5828
|
-
}
|
|
5829
|
-
function requiredOption(runtime3, value, option, usage) {
|
|
5830
|
-
const parsed = text(value);
|
|
5831
|
-
if (!parsed)
|
|
5832
|
-
runtime3.usage(`${option} is required.
|
|
5833
|
-
${usage}`, { field: option.slice(2) });
|
|
5834
|
-
return parsed;
|
|
5835
|
-
}
|
|
5836
|
-
function exactPositionals(runtime3, positionals4, count, usage) {
|
|
5837
|
-
const values = positionals4 ?? [];
|
|
5838
|
-
if (values.length !== count || values.some((value) => !value.trim()))
|
|
5839
|
-
runtime3.usage(usage);
|
|
5840
|
-
return values.map((value) => value.trim());
|
|
5841
|
-
}
|
|
5842
|
-
function requireCanonicalTarget(runtime3, value) {
|
|
5843
|
-
if (!CANONICAL_ID.test(value)) {
|
|
5844
|
-
runtime3.usage("Private targets currently require a canonical capacity-reservation identifier so connect cannot select an ambiguous resource.", { code: "canonical_reference_required", field: "target" });
|
|
5845
|
-
}
|
|
5846
|
-
return value;
|
|
5847
|
-
}
|
|
5848
|
-
function requireMutationKey(runtime3, input) {
|
|
5849
|
-
if (!runtime3.machine)
|
|
5850
|
-
return text(input.idempotencyKey);
|
|
5851
|
-
const key = text(input.idempotencyKey);
|
|
5852
|
-
if (!key) {
|
|
5853
|
-
runtime3.usage("Machine mutations require --idempotency-key <caller-stable-key> before API I/O.", {
|
|
5854
|
-
code: "idempotency_key_required",
|
|
5855
|
-
field: "idempotencyKey"
|
|
5856
|
-
});
|
|
5857
|
-
}
|
|
5858
|
-
return key;
|
|
5859
|
-
}
|
|
5860
|
-
function mutationHeaders(key) {
|
|
5861
|
-
return key ? { "Idempotency-Key": key } : void 0;
|
|
5862
|
-
}
|
|
5863
|
-
function ownerErrorCode(error) {
|
|
5864
|
-
if (!error || typeof error !== "object" || !("detail" in error))
|
|
5865
|
-
return null;
|
|
5866
|
-
const detail = record(error.detail);
|
|
5867
|
-
const nested = detail.detail ?? detail.error;
|
|
5868
|
-
if (typeof nested === "string")
|
|
5869
|
-
return nested;
|
|
5870
|
-
return text(record(nested).code) ?? text(detail.code);
|
|
5871
|
-
}
|
|
5872
|
-
function lifecycle(statusValue) {
|
|
5873
|
-
const status = text(statusValue)?.toLowerCase() ?? "unknown";
|
|
5874
|
-
if (["active", "ready", "applied", "connected"].includes(status)) {
|
|
5875
|
-
return { class: "ready", phase: "available" };
|
|
5876
|
-
}
|
|
5877
|
-
if (["failed", "degraded", "error"].includes(status)) {
|
|
5878
|
-
return { class: "failed", phase: "needs_attention" };
|
|
5879
|
-
}
|
|
5880
|
-
if (["deleted", "revoked", "disconnected"].includes(status)) {
|
|
5881
|
-
return { class: "ended", phase: "disconnected" };
|
|
5882
|
-
}
|
|
5883
|
-
if (["deleting", "revoking"].includes(status)) {
|
|
5884
|
-
return { class: "working", phase: "disconnecting" };
|
|
5885
|
-
}
|
|
5886
|
-
return { class: "pending", phase: "configuring" };
|
|
5887
|
-
}
|
|
5888
|
-
function reservationTargetLifecycle(statusValue) {
|
|
5889
|
-
const status = text(statusValue)?.toLowerCase() ?? "unknown";
|
|
5890
|
-
if (status === "active")
|
|
5891
|
-
return { class: "ready", phase: "active" };
|
|
5892
|
-
if (["failed", "payment_failed", "error"].includes(status)) {
|
|
5893
|
-
return { class: "failed", phase: status };
|
|
5894
|
-
}
|
|
5895
|
-
if (["cancelled", "canceled", "completed", "ended", "expired", "rejected", "terminated"].includes(status)) {
|
|
5896
|
-
return { class: "ended", phase: status };
|
|
5897
|
-
}
|
|
5898
|
-
return { class: "pending", phase: status };
|
|
5899
|
-
}
|
|
5900
|
-
function projectNetwork(value) {
|
|
5901
|
-
const source = record(value);
|
|
5902
|
-
const attachmentIds = Array.isArray(source.attached_reservation_ids) ? source.attached_reservation_ids.map((value2) => text(value2)).filter((value2) => Boolean(value2 && CANONICAL_ID.test(value2))) : [];
|
|
5903
|
-
return {
|
|
5904
|
-
id: text(source.id),
|
|
5905
|
-
name: text(source.name) ?? "Unnamed private network",
|
|
5906
|
-
cidr: text(source.cidr),
|
|
5907
|
-
lifecycle: lifecycle(source.status),
|
|
5908
|
-
attachment_count: integer(source.attached_reservation_count) ?? attachmentIds.length,
|
|
5909
|
-
attached_reservation_ids: [...new Set(attachmentIds)],
|
|
5910
|
-
created_at: text(source.created_at),
|
|
5911
|
-
updated_at: text(source.updated_at)
|
|
5912
|
-
};
|
|
5913
|
-
}
|
|
5914
|
-
function networkRows(payload) {
|
|
5915
|
-
const source = record(payload);
|
|
5916
|
-
const values = Array.isArray(payload) ? payload : Array.isArray(source.networks) ? source.networks : [];
|
|
5917
|
-
return values.flatMap((value) => {
|
|
5918
|
-
const parsed = unknownRecordSchema.safeParse(value);
|
|
5919
|
-
return parsed.success ? [parsed.data] : [];
|
|
5920
|
-
}).sort((left, right) => {
|
|
5921
|
-
const byName = normalizedName(text(left.name) ?? "").localeCompare(normalizedName(text(right.name) ?? ""));
|
|
5922
|
-
return byName || (text(left.id) ?? "").localeCompare(text(right.id) ?? "");
|
|
5923
|
-
});
|
|
5924
|
-
}
|
|
5925
|
-
function networkFromMutation(payload) {
|
|
5926
|
-
const source = record(payload);
|
|
5927
|
-
return projectNetwork(source.network ?? source);
|
|
5928
|
-
}
|
|
5929
|
-
async function fetchNetworks(context) {
|
|
5930
|
-
return networkRows(await context.fetch(NETWORKS_PATH));
|
|
5931
|
-
}
|
|
5932
|
-
async function resolveNetwork(context, runtime3, reference) {
|
|
5933
|
-
if (CANONICAL_ID.test(reference)) {
|
|
5934
|
-
return record(await context.fetch(`${NETWORKS_PATH}/${encodeURIComponent(reference)}`));
|
|
5935
|
-
}
|
|
5936
|
-
const wanted = normalizedName(reference);
|
|
5937
|
-
const matches = (await fetchNetworks(context)).filter((candidate) => normalizedName(text(candidate.name) ?? "") === wanted);
|
|
5938
|
-
if (matches.length === 0) {
|
|
5939
|
-
runtime3.error(`Private network not found: ${reference}.`, {
|
|
5940
|
-
code: "private_network_not_found"
|
|
5941
|
-
});
|
|
5942
|
-
}
|
|
5943
|
-
if (matches.length > 1) {
|
|
5944
|
-
runtime3.usage(`More than one private network has the exact name "${reference}"; use a canonical identifier.`, {
|
|
5945
|
-
code: "private_network_ambiguous",
|
|
5946
|
-
field: "network"
|
|
5947
|
-
});
|
|
5948
|
-
}
|
|
5949
|
-
return matches[0];
|
|
5950
|
-
}
|
|
5951
|
-
function encodeCursor(command, offset) {
|
|
5952
|
-
return encodeURIComponent(JSON.stringify({ command, offset }));
|
|
5953
|
-
}
|
|
5954
|
-
function decodeCursor(runtime3, command, cursor) {
|
|
5955
|
-
if (!cursor)
|
|
5956
|
-
return 0;
|
|
5957
|
-
try {
|
|
5958
|
-
const parsed = record(JSON.parse(decodeURIComponent(cursor)));
|
|
5959
|
-
if (parsed.command === command && Number.isInteger(parsed.offset) && Number(parsed.offset) >= 0) {
|
|
5960
|
-
return Number(parsed.offset);
|
|
5961
|
-
}
|
|
5962
|
-
} catch {
|
|
5963
|
-
}
|
|
5964
|
-
runtime3.usage("The pagination cursor is invalid or belongs to another command.", {
|
|
5965
|
-
code: "invalid_cursor",
|
|
5966
|
-
field: "cursor"
|
|
5967
|
-
});
|
|
5968
|
-
}
|
|
5969
|
-
function pageLimit2(runtime3, raw) {
|
|
5970
|
-
if (raw === void 0)
|
|
5971
|
-
return DEFAULT_LIMIT;
|
|
5972
|
-
const limit = Number(raw);
|
|
5973
|
-
if (!Number.isInteger(limit) || limit < 1 || limit > MAX_LIMIT) {
|
|
5974
|
-
runtime3.usage(`--limit must be an integer from 1 to ${MAX_LIMIT}.`, { field: "limit" });
|
|
5975
|
-
}
|
|
5976
|
-
return limit;
|
|
5977
|
-
}
|
|
5978
|
-
function page(runtime3, command, rows, input) {
|
|
5979
|
-
const limit = pageLimit2(runtime3, input.limit);
|
|
5980
|
-
const offset = decodeCursor(runtime3, command, input.cursor);
|
|
5981
|
-
const items = rows.slice(offset, offset + limit);
|
|
5982
|
-
const nextOffset = offset + items.length;
|
|
5983
|
-
return {
|
|
5984
|
-
items,
|
|
5985
|
-
page: {
|
|
5986
|
-
limit,
|
|
5987
|
-
returned: items.length,
|
|
5988
|
-
next_cursor: nextOffset < rows.length ? encodeCursor(command, nextOffset) : null
|
|
5989
|
-
}
|
|
5990
|
-
};
|
|
5991
|
-
}
|
|
5992
|
-
function declined(runtime3) {
|
|
5993
|
-
return runtime3.result({
|
|
5994
|
-
data: null,
|
|
5995
|
-
errors: [{ code: "action_declined", message: "No changes were made.", retryable: false }],
|
|
5996
|
-
exitCode: 1,
|
|
5997
|
-
outcome: { class: "ended", phase: "declined" },
|
|
5998
|
-
presentation: { lines: ["No changes were made."] }
|
|
5999
|
-
});
|
|
6000
|
-
}
|
|
6001
|
-
function networkLines(network) {
|
|
6002
|
-
const state = record(network.lifecycle);
|
|
6003
|
-
return [
|
|
6004
|
-
`${String(network.name)} (${String(network.id ?? "unknown")})`,
|
|
6005
|
-
` CIDR: ${String(network.cidr ?? "pending")}`,
|
|
6006
|
-
` State: ${state.class} (${state.phase})`
|
|
6007
|
-
];
|
|
6008
|
-
}
|
|
6009
|
-
function networkMutationExecution(runtime3, network, replayed) {
|
|
6010
|
-
const state = record(network.lifecycle);
|
|
6011
|
-
const stateClass = String(state.class);
|
|
6012
|
-
const ready = stateClass === "ready";
|
|
6013
|
-
const failed = stateClass === "failed";
|
|
6014
|
-
const command = ready ? "ornn connect" : `ornn private-networks show ${String(network.id)}`;
|
|
6015
|
-
return runtime3.result({
|
|
6016
|
-
action: {
|
|
6017
|
-
command,
|
|
6018
|
-
description: ready ? "Continue to an exact compute target." : "Inspect private-network readiness before attaching or connecting.",
|
|
6019
|
-
type: "command"
|
|
6020
|
-
},
|
|
6021
|
-
data: { private_network: network, replayed },
|
|
6022
|
-
exitCode: ready ? 0 : failed ? 4 : 3,
|
|
6023
|
-
outcome: ready ? { class: "ready", phase: "active" } : { class: String(state.class), phase: String(state.phase) },
|
|
6024
|
-
presentation: {
|
|
6025
|
-
lines: [
|
|
6026
|
-
ready ? replayed ? "Private network already satisfies this request." : "Private network created." : failed ? "Private network exists, but provisioning failed." : "Private network creation was accepted and is still provisioning.",
|
|
6027
|
-
...networkLines(network)
|
|
6028
|
-
],
|
|
6029
|
-
next: command
|
|
6030
|
-
},
|
|
6031
|
-
resume: ready ? null : { kind: "private_network", ref: String(network.id) }
|
|
6032
|
-
});
|
|
6033
|
-
}
|
|
6034
|
-
async function listPrivateNetworks(context, input) {
|
|
6035
|
-
const runtime3 = interaction(context);
|
|
6036
|
-
exactPositionals(runtime3, input.$positionals, 0, "Usage: ornn private-networks list [--limit <1-500>] [--cursor <cursor>]");
|
|
6037
|
-
const rows = (await fetchNetworks(context)).map(projectNetwork);
|
|
6038
|
-
const selected = page(runtime3, "private-networks list", rows, input);
|
|
6039
|
-
return runtime3.result({
|
|
6040
|
-
data: { private_networks: selected.items },
|
|
6041
|
-
page: selected.page,
|
|
6042
|
-
presentation: {
|
|
6043
|
-
lines: selected.items.length ? selected.items.flatMap(networkLines) : ["No private networks found."],
|
|
6044
|
-
...selected.page.next_cursor ? { next: `ornn private-networks list --cursor ${selected.page.next_cursor}` } : {}
|
|
6045
|
-
}
|
|
6046
|
-
});
|
|
6047
|
-
}
|
|
6048
|
-
async function showPrivateNetwork(context, input) {
|
|
6049
|
-
const runtime3 = interaction(context);
|
|
6050
|
-
const [reference] = exactPositionals(runtime3, input.$positionals, 1, "Usage: ornn private-networks show <exact-name-or-id>");
|
|
6051
|
-
const network = projectNetwork(await resolveNetwork(context, runtime3, reference));
|
|
6052
|
-
return runtime3.result({
|
|
6053
|
-
data: { private_network: network },
|
|
6054
|
-
presentation: { lines: networkLines(network) }
|
|
6055
|
-
});
|
|
6056
|
-
}
|
|
6057
|
-
async function createPrivateNetwork(context, input) {
|
|
6058
|
-
const runtime3 = interaction(context);
|
|
6059
|
-
const usage = "Usage: ornn private-networks create --name <name> [--cidr <cidr>]";
|
|
6060
|
-
exactPositionals(runtime3, input.$positionals, 0, usage);
|
|
6061
|
-
if (!text(input.name) && input.guided === true && !runtime3.machine) {
|
|
6062
|
-
input.name = await runtime3.ask({ label: "Private network name" });
|
|
6063
|
-
}
|
|
6064
|
-
const name = requiredOption(runtime3, input.name, "--name", usage).normalize("NFKC").trim().replace(/\s+/g, " ");
|
|
6065
|
-
const cidr = text(input.cidr) ? normalizedCidr(String(input.cidr)) : null;
|
|
6066
|
-
const idempotencyKey = requireMutationKey(runtime3, input);
|
|
6067
|
-
const matches = (await fetchNetworks(context)).filter((candidate) => normalizedName(text(candidate.name) ?? "") === normalizedName(name));
|
|
6068
|
-
if (matches.length > 1) {
|
|
6069
|
-
runtime3.usage(`More than one private network has the exact name "${name}"; use a different name.`, {
|
|
6070
|
-
code: "private_network_ambiguous",
|
|
6071
|
-
field: "name"
|
|
6072
|
-
});
|
|
6073
|
-
}
|
|
6074
|
-
if (matches.length === 1) {
|
|
6075
|
-
const existingCidr = text(matches[0].cidr);
|
|
6076
|
-
if (cidr && (!existingCidr || normalizedCidr(existingCidr) !== cidr)) {
|
|
6077
|
-
runtime3.usage(`Private network "${name}" already exists with different effective input. Use a new idempotency key and name after review.`, { code: "private_network_replay_conflict", field: "cidr" });
|
|
6078
|
-
}
|
|
6079
|
-
return networkMutationExecution(runtime3, projectNetwork(matches[0]), true);
|
|
6080
|
-
}
|
|
6081
|
-
if (!await runtime3.review({
|
|
6082
|
-
title: "Create private network",
|
|
6083
|
-
terms: [
|
|
6084
|
-
{ label: "Name", value: name },
|
|
6085
|
-
{ label: "CIDR", value: cidr ?? "Automatically assigned" }
|
|
6086
|
-
]
|
|
6087
|
-
}))
|
|
6088
|
-
return declined(runtime3);
|
|
6089
|
-
const created = await context.fetch(NETWORKS_PATH, {
|
|
6090
|
-
body: { name, ...cidr ? { cidr } : {} },
|
|
6091
|
-
headers: mutationHeaders(idempotencyKey),
|
|
6092
|
-
method: "POST"
|
|
6093
|
-
});
|
|
6094
|
-
return networkMutationExecution(runtime3, networkFromMutation(created), false);
|
|
6095
|
-
}
|
|
6096
|
-
async function updatePrivateNetwork(context, input) {
|
|
6097
|
-
const runtime3 = interaction(context);
|
|
6098
|
-
const usage = "Usage: ornn private-networks update <exact-name-or-id> --name <new-name>";
|
|
6099
|
-
const [reference] = exactPositionals(runtime3, input.$positionals, 1, usage);
|
|
6100
|
-
const name = requiredOption(runtime3, input.name, "--name", usage).normalize("NFKC").trim().replace(/\s+/g, " ");
|
|
6101
|
-
const idempotencyKey = requireMutationKey(runtime3, input);
|
|
6102
|
-
const current = await resolveNetwork(context, runtime3, reference);
|
|
6103
|
-
if (normalizedName(text(current.name) ?? "") === normalizedName(name)) {
|
|
6104
|
-
const network2 = projectNetwork(current);
|
|
6105
|
-
return runtime3.result({
|
|
6106
|
-
data: { private_network: network2, replayed: true },
|
|
6107
|
-
presentation: {
|
|
6108
|
-
lines: ["Private network already has the requested name.", ...networkLines(network2)]
|
|
6109
|
-
}
|
|
6110
|
-
});
|
|
6111
|
-
}
|
|
6112
|
-
if ((await fetchNetworks(context)).some((candidate) => normalizedName(text(candidate.name) ?? "") === normalizedName(name))) {
|
|
6113
|
-
runtime3.usage(`Another private network already has the exact name "${name}".`, {
|
|
6114
|
-
code: "private_network_name_conflict",
|
|
6115
|
-
field: "name"
|
|
6116
|
-
});
|
|
6117
|
-
}
|
|
6118
|
-
if (!await runtime3.review({
|
|
6119
|
-
title: "Update private network",
|
|
6120
|
-
terms: [
|
|
6121
|
-
{
|
|
6122
|
-
label: "Private network",
|
|
6123
|
-
value: `${text(current.name) ?? reference} (${text(current.id) ?? reference})`
|
|
6124
|
-
},
|
|
6125
|
-
{ label: "New name", value: name }
|
|
6126
|
-
]
|
|
6127
|
-
}))
|
|
6128
|
-
return declined(runtime3);
|
|
6129
|
-
const updated = await context.fetch(`${NETWORKS_PATH}/${encodeURIComponent(String(current.id))}`, {
|
|
6130
|
-
body: { name },
|
|
6131
|
-
headers: mutationHeaders(idempotencyKey),
|
|
6132
|
-
method: "PATCH"
|
|
6133
|
-
});
|
|
6134
|
-
const network = networkFromMutation(updated);
|
|
6135
|
-
return runtime3.result({
|
|
6136
|
-
data: { private_network: network, replayed: false },
|
|
6137
|
-
presentation: { lines: ["Private network updated.", ...networkLines(network)] }
|
|
6138
|
-
});
|
|
6139
|
-
}
|
|
6140
|
-
async function deletePrivateNetwork(context, input) {
|
|
6141
|
-
const runtime3 = interaction(context);
|
|
6142
|
-
const [reference] = exactPositionals(runtime3, input.$positionals, 1, "Usage: ornn private-networks delete <exact-name-or-id>");
|
|
6143
|
-
const idempotencyKey = requireMutationKey(runtime3, input);
|
|
6144
|
-
const projected = projectNetwork(await resolveNetwork(context, runtime3, reference));
|
|
6145
|
-
if (!await runtime3.review({
|
|
6146
|
-
title: "Delete private network",
|
|
6147
|
-
terms: [
|
|
6148
|
-
{ label: "Private network", value: `${String(projected.name)} (${String(projected.id)})` },
|
|
6149
|
-
{
|
|
6150
|
-
label: "Consequence",
|
|
6151
|
-
value: "Permanently delete this organization private network when the owner permits deletion."
|
|
6152
|
-
}
|
|
6153
|
-
],
|
|
6154
|
-
prompt: "Delete this private network?"
|
|
6155
|
-
}))
|
|
6156
|
-
return declined(runtime3);
|
|
6157
|
-
try {
|
|
6158
|
-
await context.fetch(`${NETWORKS_PATH}/${encodeURIComponent(String(projected.id))}`, {
|
|
6159
|
-
headers: mutationHeaders(idempotencyKey),
|
|
6160
|
-
method: "DELETE"
|
|
6161
|
-
});
|
|
6162
|
-
} catch (error) {
|
|
6163
|
-
if (ownerErrorCode(error) === "network_in_use") {
|
|
6164
|
-
throw error;
|
|
6165
|
-
}
|
|
6166
|
-
throw error;
|
|
6167
|
-
}
|
|
6168
|
-
return runtime3.result({
|
|
6169
|
-
data: { deleted: true, private_network: projected },
|
|
6170
|
-
outcome: { class: "ended", phase: "deleted" },
|
|
6171
|
-
presentation: {
|
|
6172
|
-
lines: [`Private network deleted: ${String(projected.name)} (${String(projected.id)})`]
|
|
6173
|
-
}
|
|
6174
|
-
});
|
|
6175
|
-
}
|
|
6176
|
-
function vpnPath(reservationId) {
|
|
6177
|
-
return `/v1/workflows/compute/nodes/reservations/${encodeURIComponent(reservationId)}/vpn/peers`;
|
|
6178
|
-
}
|
|
6179
|
-
function vpnPayloadRows(payload) {
|
|
6180
|
-
const source = record(payload);
|
|
6181
|
-
const peers = Array.isArray(source.peers) ? source.peers : [];
|
|
6182
|
-
return peers.flatMap((value) => {
|
|
6183
|
-
const parsed = unknownRecordSchema.safeParse(value);
|
|
6184
|
-
return parsed.success ? [parsed.data] : [];
|
|
6185
|
-
});
|
|
6186
|
-
}
|
|
6187
|
-
function vpnPeer(payload) {
|
|
6188
|
-
const peer = record(payload.peer);
|
|
6189
|
-
return Object.keys(peer).length ? peer : payload;
|
|
6190
|
-
}
|
|
6191
|
-
function projectVpnConnection(payload, reservationId) {
|
|
6192
|
-
const peer = vpnPeer(payload);
|
|
6193
|
-
const network = record(payload.network);
|
|
6194
|
-
return {
|
|
6195
|
-
id: text(peer.id),
|
|
6196
|
-
name: text(peer.label) ?? "VPN connection",
|
|
6197
|
-
reservation_id: reservationId,
|
|
6198
|
-
private_network_id: text(network.network_id) ?? text(network.id),
|
|
6199
|
-
assigned_address: text(peer.assigned_ip),
|
|
6200
|
-
lifecycle: lifecycle(peer.status),
|
|
6201
|
-
created_at: text(peer.created_at)
|
|
6202
|
-
};
|
|
6203
|
-
}
|
|
6204
|
-
function vpnLines(connection) {
|
|
6205
|
-
const state = record(connection.lifecycle);
|
|
6206
|
-
return [
|
|
6207
|
-
`${String(connection.name)} (${String(connection.id ?? "unknown")})`,
|
|
6208
|
-
` Private target: ${String(connection.reservation_id)}`,
|
|
6209
|
-
` State: ${state.class} (${state.phase})`
|
|
6210
|
-
];
|
|
6211
|
-
}
|
|
6212
|
-
async function listVpnPayloads(context, target) {
|
|
6213
|
-
return vpnPayloadRows(await context.fetch(vpnPath(target)));
|
|
6214
|
-
}
|
|
6215
|
-
async function listVpnConnections(context, input) {
|
|
6216
|
-
const runtime3 = interaction(context);
|
|
6217
|
-
const [rawTarget] = exactPositionals(runtime3, input.$positionals, 1, "Usage: ornn vpn-connections list <canonical-reservation-id> [--limit <1-500>] [--cursor <cursor>]");
|
|
6218
|
-
const target = requireCanonicalTarget(runtime3, rawTarget);
|
|
6219
|
-
const connections = (await listVpnPayloads(context, target)).map((payload) => projectVpnConnection(payload, target)).sort((left, right) => normalizedName(String(left.name)).localeCompare(normalizedName(String(right.name))));
|
|
6220
|
-
const selected = page(runtime3, "vpn-connections list", connections, input);
|
|
6221
|
-
return runtime3.result({
|
|
6222
|
-
data: { vpn_connections: selected.items },
|
|
6223
|
-
page: selected.page,
|
|
6224
|
-
presentation: {
|
|
6225
|
-
lines: selected.items.length ? selected.items.flatMap(vpnLines) : [`No VPN connections found for private target ${target}.`],
|
|
6226
|
-
...selected.page.next_cursor ? { next: `ornn vpn-connections list ${target} --cursor ${selected.page.next_cursor}` } : {}
|
|
6227
|
-
}
|
|
6228
|
-
});
|
|
6229
|
-
}
|
|
6230
|
-
function validateSecretExport(runtime3, input) {
|
|
6231
|
-
const hasOutput = Boolean(text(input.output));
|
|
6232
|
-
const shouldPrint = input.print === true;
|
|
6233
|
-
if (hasOutput === shouldPrint) {
|
|
6234
|
-
runtime3.usage("Choose exactly one explicit VPN configuration destination: --print or --output <path>.", {
|
|
6235
|
-
code: "secret_destination_required",
|
|
6236
|
-
field: "output"
|
|
6237
|
-
});
|
|
6238
|
-
}
|
|
6239
|
-
if (shouldPrint && runtime3.formatProvided) {
|
|
6240
|
-
runtime3.usage("--print is incompatible with an explicit --format.", {
|
|
6241
|
-
code: "secret_print_format_conflict",
|
|
6242
|
-
field: "format"
|
|
6243
|
-
});
|
|
6244
|
-
}
|
|
6245
|
-
if (runtime3.machine && shouldPrint) {
|
|
6246
|
-
runtime3.usage("Machine mode cannot mix secret bytes with a result envelope; use --output <path>.", {
|
|
6247
|
-
code: "secret_print_unsupported_in_machine_mode",
|
|
6248
|
-
field: "print"
|
|
6249
|
-
});
|
|
6250
|
-
}
|
|
6251
|
-
if (!runtime3.exportSecret || !runtime3.prepareSecretExport || !runtime3.wireGuardPublicKeyFromFile) {
|
|
6252
|
-
runtime3.error("The CLI secret-output service is unavailable.", {
|
|
6253
|
-
code: "secret_output_unavailable",
|
|
6254
|
-
exitCode: 6,
|
|
6255
|
-
retryable: true
|
|
6256
|
-
});
|
|
6257
|
-
}
|
|
6258
|
-
}
|
|
6259
|
-
async function prepareVpnExport(runtime3, input) {
|
|
6260
|
-
try {
|
|
6261
|
-
await runtime3.prepareSecretExport({
|
|
6262
|
-
outputPath: text(input.output) ?? void 0,
|
|
6263
|
-
overwrite: input.overwrite === true,
|
|
6264
|
-
print: input.print === true
|
|
6265
|
-
});
|
|
6266
|
-
} catch (error) {
|
|
6267
|
-
const code = error && typeof error === "object" && "code" in error ? text(error.code) : null;
|
|
6268
|
-
const message = error instanceof Error && error.message ? error.message : "Could not prepare the VPN configuration destination.";
|
|
6269
|
-
runtime3.error(message, { code: code ?? "vpn_configuration_export_failed" });
|
|
6270
|
-
}
|
|
6271
|
-
}
|
|
6272
|
-
async function exportVpnConfig(runtime3, input, content, privateKeyPath, publicKey) {
|
|
6273
|
-
const config = typeof content === "string" && content.length > 0 ? content : null;
|
|
6274
|
-
if (!config) {
|
|
6275
|
-
runtime3.error("Ornn did not return a usable VPN configuration.", {
|
|
6276
|
-
code: "vpn_configuration_unavailable",
|
|
6277
|
-
exitCode: 6,
|
|
6278
|
-
retryable: true
|
|
6279
|
-
});
|
|
6280
|
-
}
|
|
6281
|
-
try {
|
|
6282
|
-
return await runtime3.exportSecret({
|
|
6283
|
-
content: config,
|
|
6284
|
-
outputPath: text(input.output) ?? void 0,
|
|
6285
|
-
overwrite: input.overwrite === true,
|
|
6286
|
-
print: input.print === true,
|
|
6287
|
-
privateKeyPath,
|
|
6288
|
-
publicKey
|
|
6289
|
-
});
|
|
6290
|
-
} catch (error) {
|
|
6291
|
-
const code = error && typeof error === "object" && "code" in error ? text(error.code) : null;
|
|
6292
|
-
const message = error instanceof Error && error.message ? error.message : "Could not export the VPN configuration.";
|
|
6293
|
-
runtime3.error(message, { code: code ?? "vpn_configuration_export_failed" });
|
|
6294
|
-
}
|
|
6295
|
-
}
|
|
6296
|
-
function vpnConfigureExecution(runtime3, target, connection, exported, replayed) {
|
|
6297
|
-
const state = record(connection.lifecycle);
|
|
6298
|
-
const stateClass = String(state.class);
|
|
6299
|
-
const ready = stateClass === "ready";
|
|
6300
|
-
const failed = stateClass === "failed";
|
|
6301
|
-
const activationCommand = exported.path ? `sudo wg-quick up ${shellQuote(exported.path)}` : "sudo wg-quick up <saved-configuration-path>";
|
|
6302
|
-
const action = ready ? {
|
|
6303
|
-
command: activationCommand,
|
|
6304
|
-
description: "Activate the completed local WireGuard configuration before connecting.",
|
|
6305
|
-
type: "command"
|
|
6306
|
-
} : {
|
|
6307
|
-
command: `ornn vpn-connections configure ${target} --guided`,
|
|
6308
|
-
description: failed ? "Retry applying this exact VPN peer with its original private key." : "Reapply this pending VPN peer after gateway readiness is restored.",
|
|
6309
|
-
type: "command"
|
|
6310
|
-
};
|
|
6311
|
-
return runtime3.result({
|
|
6312
|
-
action,
|
|
6313
|
-
data: { export: exported, replayed, vpn_connection: connection },
|
|
6314
|
-
exitCode: ready ? 3 : failed ? 4 : 3,
|
|
6315
|
-
outcome: ready ? { class: "action_required", phase: "local_vpn_activation_required" } : { class: String(state.class), phase: String(state.phase) },
|
|
6316
|
-
presentation: {
|
|
6317
|
-
lines: [
|
|
6318
|
-
ready ? replayed ? "VPN configuration exported again; local tunnel activation is still required." : "VPN peer is active and the complete local configuration was exported." : failed ? "VPN connection was saved, but the gateway rejected or could not apply it." : "VPN connection was saved and is waiting for gateway application.",
|
|
6319
|
-
...vpnLines(connection),
|
|
6320
|
-
`Configuration fingerprint: ${exported.fingerprint}`,
|
|
6321
|
-
...exported.path ? [`Configuration written to ${exported.path} (${exported.mode}).`] : []
|
|
6322
|
-
],
|
|
6323
|
-
next: action.command
|
|
6324
|
-
},
|
|
6325
|
-
resume: ready ? { kind: "connect", ref: target } : { kind: "vpn_connection", ref: String(connection.id) }
|
|
6326
|
-
});
|
|
6327
|
-
}
|
|
6328
|
-
async function configureVpnConnection(context, input) {
|
|
6329
|
-
const runtime3 = interaction(context);
|
|
6330
|
-
const usage = "Usage: ornn vpn-connections configure <canonical-reservation-id> --name <name> --private-key <path> (--print | --output <path>)";
|
|
6331
|
-
const [rawTarget] = exactPositionals(runtime3, input.$positionals, 1, usage);
|
|
6332
|
-
const target = requireCanonicalTarget(runtime3, rawTarget);
|
|
6333
|
-
if (input.guided === true && !runtime3.machine) {
|
|
6334
|
-
input.name ??= await runtime3.ask({ label: "VPN connection name" });
|
|
6335
|
-
input.privateKey ??= await runtime3.ask({ label: "WireGuard private-key path" });
|
|
6336
|
-
if (input.print !== true && !text(input.output)) {
|
|
6337
|
-
input.output = await runtime3.ask({ label: "VPN configuration output path" });
|
|
6338
|
-
}
|
|
6339
|
-
}
|
|
6340
|
-
const name = requiredOption(runtime3, input.name, "--name", usage).normalize("NFKC").trim().replace(/\s+/g, " ");
|
|
6341
|
-
const privateKeyPath = requiredOption(runtime3, input.privateKey, "--private-key", usage);
|
|
6342
|
-
validateSecretExport(runtime3, input);
|
|
6343
|
-
await prepareVpnExport(runtime3, input);
|
|
6344
|
-
let publicKey = "";
|
|
6345
|
-
try {
|
|
6346
|
-
publicKey = await runtime3.wireGuardPublicKeyFromFile(privateKeyPath);
|
|
6347
|
-
} catch (error) {
|
|
6348
|
-
const code = error && typeof error === "object" && "code" in error ? text(error.code) : null;
|
|
6349
|
-
const message = error instanceof Error && error.message ? error.message : "Could not read the WireGuard private key.";
|
|
6350
|
-
runtime3.error(message, { code: code ?? "invalid_wireguard_private_key", field: "privateKey" });
|
|
6351
|
-
}
|
|
6352
|
-
const idempotencyKey = requireMutationKey(runtime3, input);
|
|
6353
|
-
const existing = await listVpnPayloads(context, target);
|
|
6354
|
-
const sameKey = existing.find((payload) => text(vpnPeer(payload).public_key) === publicKey);
|
|
6355
|
-
let effectiveName = name;
|
|
6356
|
-
if (sameKey) {
|
|
6357
|
-
const existingName = text(vpnPeer(sameKey).label) ?? "VPN connection";
|
|
6358
|
-
effectiveName = existingName;
|
|
6359
|
-
if (normalizedName(existingName) !== normalizedName(name)) {
|
|
6360
|
-
runtime3.usage("This public key already identifies a VPN connection with a different name. Use the original effective input or a new key after review.", { code: "vpn_connection_replay_conflict", field: "name" });
|
|
6361
|
-
}
|
|
6362
|
-
} else if (existing.some((payload) => normalizedName(text(vpnPeer(payload).label) ?? "VPN connection") === normalizedName(name))) {
|
|
6363
|
-
runtime3.usage(`A VPN connection named "${name}" already exists with different key material.`, {
|
|
6364
|
-
code: "vpn_connection_name_conflict",
|
|
6365
|
-
field: "name"
|
|
6366
|
-
});
|
|
6367
|
-
}
|
|
6368
|
-
if (sameKey && lifecycle(text(vpnPeer(sameKey).status)).class === "ready") {
|
|
6369
|
-
const exported2 = await exportVpnConfig(runtime3, input, sameKey.config, privateKeyPath, publicKey);
|
|
6370
|
-
return vpnConfigureExecution(runtime3, target, projectVpnConnection(sameKey, target), exported2, true);
|
|
6371
|
-
}
|
|
6372
|
-
if (!await runtime3.review({
|
|
6373
|
-
title: sameKey ? "Retry VPN connection" : "Configure VPN connection",
|
|
6374
|
-
terms: [
|
|
6375
|
-
{ label: "Private target", value: target },
|
|
6376
|
-
{ label: "VPN connection", value: name },
|
|
6377
|
-
{ label: "WireGuard public key", value: publicKey },
|
|
6378
|
-
{
|
|
6379
|
-
label: "Configuration destination",
|
|
6380
|
-
value: input.print ? "Terminal (explicit --print)" : String(input.output)
|
|
6381
|
-
}
|
|
6382
|
-
]
|
|
6383
|
-
}))
|
|
6384
|
-
return declined(runtime3);
|
|
6385
|
-
const applied = record(await context.fetch(vpnPath(target), {
|
|
6386
|
-
body: { label: effectiveName, public_key: publicKey },
|
|
6387
|
-
headers: mutationHeaders(idempotencyKey),
|
|
6388
|
-
method: "POST"
|
|
6389
|
-
}));
|
|
6390
|
-
const exported = await exportVpnConfig(runtime3, input, applied.config, privateKeyPath, publicKey);
|
|
6391
|
-
const connection = projectVpnConnection(applied, target);
|
|
6392
|
-
return vpnConfigureExecution(runtime3, target, connection, exported, Boolean(sameKey));
|
|
6393
|
-
}
|
|
6394
|
-
async function disconnectVpnConnection(context, input) {
|
|
6395
|
-
const runtime3 = interaction(context);
|
|
6396
|
-
const [rawTarget, reference] = exactPositionals(runtime3, input.$positionals, 2, "Usage: ornn vpn-connections disconnect <canonical-reservation-id> <exact-name-or-id>");
|
|
6397
|
-
const target = requireCanonicalTarget(runtime3, rawTarget);
|
|
6398
|
-
const idempotencyKey = requireMutationKey(runtime3, input);
|
|
6399
|
-
const matches = (await listVpnPayloads(context, target)).filter((payload) => {
|
|
6400
|
-
const peer = vpnPeer(payload);
|
|
6401
|
-
return CANONICAL_ID.test(reference) ? text(peer.id) === reference : normalizedName(text(peer.label) ?? "VPN connection") === normalizedName(reference);
|
|
6402
|
-
});
|
|
6403
|
-
if (matches.length === 0)
|
|
6404
|
-
runtime3.error(`VPN connection not found: ${reference}.`, { code: "vpn_connection_not_found" });
|
|
6405
|
-
if (matches.length > 1) {
|
|
6406
|
-
runtime3.usage(`More than one VPN connection has the exact name "${reference}"; use a canonical identifier.`, {
|
|
6407
|
-
code: "vpn_connection_ambiguous",
|
|
6408
|
-
field: "connection"
|
|
6409
|
-
});
|
|
6410
|
-
}
|
|
6411
|
-
const connection = projectVpnConnection(matches[0], target);
|
|
6412
|
-
if (!await runtime3.review({
|
|
6413
|
-
title: "Disconnect VPN connection",
|
|
6414
|
-
terms: [
|
|
6415
|
-
{ label: "Private target", value: target },
|
|
6416
|
-
{ label: "VPN connection", value: `${String(connection.name)} (${String(connection.id)})` },
|
|
6417
|
-
{
|
|
6418
|
-
label: "Consequence",
|
|
6419
|
-
value: "Private access through this VPN connection ends; the private network remains."
|
|
6420
|
-
}
|
|
6421
|
-
]
|
|
6422
|
-
}))
|
|
6423
|
-
return declined(runtime3);
|
|
6424
|
-
await context.fetch(`${vpnPath(target)}/${encodeURIComponent(String(connection.id))}`, {
|
|
6425
|
-
headers: mutationHeaders(idempotencyKey),
|
|
6426
|
-
method: "DELETE"
|
|
6427
|
-
});
|
|
6428
|
-
return runtime3.result({
|
|
6429
|
-
data: { disconnected: true, vpn_connection: connection },
|
|
6430
|
-
outcome: { class: "ended", phase: "disconnected" },
|
|
6431
|
-
presentation: {
|
|
6432
|
-
lines: [`VPN connection disconnected: ${String(connection.name)} (${String(connection.id)})`]
|
|
6433
|
-
}
|
|
6434
|
-
});
|
|
6435
|
-
}
|
|
6436
|
-
function normalizedConnectAccessMode(value) {
|
|
6437
|
-
const mode = text(value)?.toLowerCase();
|
|
6438
|
-
return mode === "virtual-machine" ? "vm" : mode ?? null;
|
|
6439
|
-
}
|
|
6440
|
-
function validateKnownConnectMode(runtime3, input, mode) {
|
|
6441
|
-
if (mode === "vm" || mode === "bare-metal" || mode === "slurm") {
|
|
6442
|
-
if (input.output || input.overwrite) {
|
|
6443
|
-
runtime3.usage(`${mode === "slurm" ? "Slurm" : mode === "vm" ? "VM" : "Bare Metal"} connect uses native SSH and does not write an output file.`, {
|
|
6444
|
-
code: mode === "slurm" ? "slurm_output_unsupported" : "direct_machine_output_unsupported",
|
|
6445
|
-
field: input.output ? "output" : "overwrite"
|
|
6446
|
-
});
|
|
6447
|
-
}
|
|
6448
|
-
return;
|
|
6449
|
-
}
|
|
6450
|
-
if (mode === "kubernetes" && (input.identityFile || input.user || input.print)) {
|
|
6451
|
-
runtime3.usage("Kubernetes connect writes a kubeconfig and does not accept SSH identity, user, or print options.", {
|
|
6452
|
-
code: input.print ? "kubeconfig_output_required" : "kubernetes_ssh_options_unsupported",
|
|
6453
|
-
field: input.identityFile ? "identityFile" : input.user ? "user" : "output"
|
|
6454
|
-
});
|
|
6455
|
-
}
|
|
6456
|
-
}
|
|
6457
|
-
function blockedPrivateTransport(runtime3, lifecycleValue, action, data, reservationId) {
|
|
6458
|
-
const state = record(lifecycleValue);
|
|
6459
|
-
const outcome = {
|
|
6460
|
-
class: text(state.class) ?? "pending",
|
|
6461
|
-
phase: text(state.phase) ?? "configuring"
|
|
6462
|
-
};
|
|
6463
|
-
return runtime3.result({
|
|
6464
|
-
action,
|
|
6465
|
-
data,
|
|
6466
|
-
exitCode: ["failed", "ended"].includes(outcome.class) ? 1 : 3,
|
|
6467
|
-
outcome,
|
|
6468
|
-
resume: { kind: "connect", ref: reservationId }
|
|
6469
|
-
});
|
|
6470
|
-
}
|
|
6471
|
-
function compareVpnConnections(left, right) {
|
|
6472
|
-
return (text(left.created_at) ?? "").localeCompare(text(right.created_at) ?? "") || (text(left.id) ?? "").localeCompare(text(right.id) ?? "") || normalizedName(text(left.name) ?? "").localeCompare(normalizedName(text(right.name) ?? ""));
|
|
6473
|
-
}
|
|
6474
|
-
async function connectPrivateTarget(context, input) {
|
|
6475
|
-
const runtime3 = interaction(context);
|
|
6476
|
-
const values = input.$positionals ?? [];
|
|
6477
|
-
if (values.length > 1) {
|
|
6478
|
-
runtime3.usage("Usage: ornn connect [<exact-hostname-or-canonical-machine-id>]", {
|
|
6479
|
-
code: "usage_error"
|
|
6480
|
-
});
|
|
6481
|
-
}
|
|
6482
|
-
const rawTarget = text(values[0]);
|
|
6483
|
-
let resolved = null;
|
|
6484
|
-
let target = rawTarget;
|
|
6485
|
-
if (runtime3.resolveConnectTarget) {
|
|
6486
|
-
resolved = await runtime3.resolveConnectTarget({
|
|
6487
|
-
context,
|
|
6488
|
-
input,
|
|
6489
|
-
interaction: runtime3,
|
|
6490
|
-
reference: rawTarget
|
|
6491
|
-
});
|
|
6492
|
-
if (resolved) {
|
|
6493
|
-
validateKnownConnectMode(runtime3, input, normalizedConnectAccessMode(resolved.mode));
|
|
6494
|
-
}
|
|
6495
|
-
if (resolved && resolved.privateTransportRequired !== true && runtime3.continueConnect) {
|
|
6496
|
-
const direct = await runtime3.continueConnect(resolved);
|
|
6497
|
-
if (direct)
|
|
6498
|
-
return runtime3.result(direct);
|
|
6499
|
-
}
|
|
6500
|
-
if (resolved)
|
|
6501
|
-
target = resolved.reservationId;
|
|
6502
|
-
}
|
|
6503
|
-
if (!resolved && rawTarget && CANONICAL_ID.test(rawTarget)) {
|
|
6504
|
-
try {
|
|
6505
|
-
const reservation = await getReservation(context.fetch, rawTarget);
|
|
6506
|
-
const reservationId = text(reservation.reservationId);
|
|
6507
|
-
if (reservationId && reservationId !== rawTarget) {
|
|
6508
|
-
runtime3.error("The gateway returned a different capacity reservation.", {
|
|
6509
|
-
code: "reservation_correlation_changed"
|
|
6510
|
-
});
|
|
6511
|
-
}
|
|
6512
|
-
const status = text(reservation.status)?.toLowerCase() ?? "unknown";
|
|
6513
|
-
const mode = normalizedConnectAccessMode(reservation.provisioningType);
|
|
6514
|
-
if (status !== "active") {
|
|
6515
|
-
const state = reservationTargetLifecycle(status);
|
|
6516
|
-
const waiting = state.class === "pending" || state.class === "working";
|
|
6517
|
-
return runtime3.result({
|
|
6518
|
-
action: waiting ? {
|
|
6519
|
-
command: `ornn reservations show ${reservationId ?? rawTarget}`,
|
|
6520
|
-
description: "Wait for the capacity reservation to become active before launching native compute.",
|
|
6521
|
-
type: "command"
|
|
6522
|
-
} : null,
|
|
6523
|
-
data: {
|
|
6524
|
-
capacity_reservation: {
|
|
6525
|
-
id: reservationId ?? rawTarget,
|
|
6526
|
-
access_mode: mode,
|
|
6527
|
-
lifecycle: state
|
|
6528
|
-
}
|
|
6529
|
-
},
|
|
6530
|
-
exitCode: waiting ? 3 : 1,
|
|
6531
|
-
outcome: state,
|
|
6532
|
-
presentation: {
|
|
6533
|
-
lines: [
|
|
6534
|
-
waiting ? `Capacity reservation ${reservationId ?? rawTarget} is not active yet; it has no native-access target.` : `Capacity reservation ${reservationId ?? rawTarget} is ${state.phase}; it has no launchable native-access target.`
|
|
6535
|
-
]
|
|
6536
|
-
},
|
|
6537
|
-
resume: waiting ? { kind: "reservation", ref: reservationId ?? rawTarget } : null
|
|
6538
|
-
});
|
|
6539
|
-
}
|
|
6540
|
-
validateKnownConnectMode(runtime3, input, mode);
|
|
6541
|
-
return runtime3.actionRequired({
|
|
6542
|
-
action: {
|
|
6543
|
-
command: "ornn launch",
|
|
6544
|
-
description: "Launch compute for this capacity reservation before requesting native access.",
|
|
6545
|
-
type: "command"
|
|
6546
|
-
},
|
|
6547
|
-
data: {
|
|
6548
|
-
capacity_reservation: {
|
|
6549
|
-
id: reservationId ?? rawTarget,
|
|
6550
|
-
access_mode: mode
|
|
6551
|
-
}
|
|
6552
|
-
},
|
|
6553
|
-
resume: { kind: "reservation", ref: reservationId ?? rawTarget }
|
|
6554
|
-
});
|
|
6555
|
-
} catch (error) {
|
|
6556
|
-
if (![400, 404, 422].includes(responseStatus(error) ?? 0))
|
|
6557
|
-
throw error;
|
|
6558
|
-
}
|
|
6559
|
-
}
|
|
6560
|
-
const privateTarget = target ?? "";
|
|
6561
|
-
if (!privateTarget || !CANONICAL_ID.test(privateTarget)) {
|
|
6562
|
-
runtime3.usage("Connect requires an exact unique hostname, canonical machine ID, or eligible guided choice.", {
|
|
6563
|
-
code: "invalid_reference",
|
|
6564
|
-
field: "machine"
|
|
6565
|
-
});
|
|
6566
|
-
}
|
|
6567
|
-
if (!resolved) {
|
|
6568
|
-
runtime3.error("No accessible machine, cluster, or capacity reservation matches this target.", {
|
|
6569
|
-
code: "connect_target_not_found"
|
|
6570
|
-
});
|
|
6571
|
-
}
|
|
6572
|
-
const shared = record(await context.fetch(`${NETWORKS_PATH}/shared?overlay=true`));
|
|
6573
|
-
const privateNetwork = projectNetwork({
|
|
6574
|
-
...record(shared.network),
|
|
6575
|
-
id: "shared",
|
|
6576
|
-
name: "Organization private network"
|
|
6577
|
-
});
|
|
6578
|
-
const networkState = record(privateNetwork.lifecycle);
|
|
6579
|
-
if (networkState.class !== "ready") {
|
|
6580
|
-
const recoverable = ["failed", "ended"].includes(String(networkState.class));
|
|
6581
|
-
return blockedPrivateTransport(runtime3, networkState, {
|
|
6582
|
-
command: `ornn vpn-connections list ${privateTarget}`,
|
|
6583
|
-
description: recoverable ? "Inspect organization VPN connectivity before retrying." : "Wait for organization networking to become ready, then retry connect.",
|
|
6584
|
-
type: "command"
|
|
6585
|
-
}, {
|
|
6586
|
-
private_network: privateNetwork,
|
|
6587
|
-
private_target: { reservation_id: privateTarget },
|
|
6588
|
-
vpn_connection: null
|
|
6589
|
-
}, privateTarget);
|
|
6590
|
-
}
|
|
6591
|
-
const connections = (await listVpnPayloads(context, privateTarget)).map((payload) => projectVpnConnection(payload, privateTarget)).sort(compareVpnConnections);
|
|
6592
|
-
if (connections.length === 0) {
|
|
6593
|
-
return runtime3.actionRequired({
|
|
6594
|
-
action: {
|
|
6595
|
-
command: `ornn vpn-connections configure ${privateTarget} --guided`,
|
|
6596
|
-
description: "Provide one VPN peer and explicit configuration destination, then retry connect.",
|
|
6597
|
-
type: "command"
|
|
6598
|
-
},
|
|
6599
|
-
data: {
|
|
6600
|
-
private_network: privateNetwork,
|
|
6601
|
-
private_target: { reservation_id: privateTarget },
|
|
6602
|
-
vpn_connection: null
|
|
6603
|
-
},
|
|
6604
|
-
resume: { kind: "connect", ref: privateTarget }
|
|
6605
|
-
});
|
|
6606
|
-
}
|
|
6607
|
-
const readyConnections = connections.filter((connection2) => record(connection2.lifecycle).class === "ready");
|
|
6608
|
-
if (readyConnections.length === 0) {
|
|
6609
|
-
const connection2 = connections.find((candidate) => ["pending", "working"].includes(String(record(candidate.lifecycle).class))) ?? connections.find((candidate) => record(candidate.lifecycle).class === "failed") ?? connections[0];
|
|
6610
|
-
const state = record(connection2.lifecycle);
|
|
6611
|
-
const stateClass = String(state.class);
|
|
6612
|
-
const id = text(connection2.id);
|
|
6613
|
-
const failed = stateClass === "failed";
|
|
6614
|
-
const ended = stateClass === "ended";
|
|
6615
|
-
const action = failed && id ? {
|
|
6616
|
-
command: `ornn vpn-connections disconnect ${privateTarget} ${id}`,
|
|
6617
|
-
description: "Remove the failed VPN connection before configuring a replacement.",
|
|
6618
|
-
type: "command"
|
|
6619
|
-
} : ended ? {
|
|
6620
|
-
command: `ornn vpn-connections configure ${privateTarget} --guided`,
|
|
6621
|
-
description: "Configure a new VPN connection, then retry connect.",
|
|
6622
|
-
type: "command"
|
|
6623
|
-
} : {
|
|
6624
|
-
command: `ornn vpn-connections configure ${privateTarget} --guided`,
|
|
6625
|
-
description: "Reapply the pending VPN connection, then retry connect.",
|
|
6626
|
-
type: "command"
|
|
6627
|
-
};
|
|
6628
|
-
return blockedPrivateTransport(runtime3, state, action, {
|
|
6629
|
-
private_network: privateNetwork,
|
|
6630
|
-
private_target: { reservation_id: privateTarget },
|
|
6631
|
-
vpn_connection: connection2
|
|
6632
|
-
}, privateTarget);
|
|
6633
|
-
}
|
|
6634
|
-
const connection = readyConnections.find((candidate) => {
|
|
6635
|
-
const address = text(candidate.assigned_address);
|
|
6636
|
-
return Boolean(address && runtime3.hasLocalNetworkAddress?.(address) === true);
|
|
6637
|
-
}) ?? readyConnections[0];
|
|
6638
|
-
const assignedAddress = text(connection.assigned_address);
|
|
6639
|
-
if (!assignedAddress || runtime3.hasLocalNetworkAddress?.(assignedAddress) !== true) {
|
|
6640
|
-
return runtime3.actionRequired({
|
|
6641
|
-
action: {
|
|
6642
|
-
command: `ornn vpn-connections configure ${privateTarget} --guided`,
|
|
6643
|
-
description: "Export a complete WireGuard configuration, activate it locally, then retry connect.",
|
|
6644
|
-
type: "command"
|
|
6645
|
-
},
|
|
6646
|
-
data: {
|
|
6647
|
-
private_network: privateNetwork,
|
|
6648
|
-
private_target: { reservation_id: privateTarget },
|
|
6649
|
-
vpn_connection: connection
|
|
6650
|
-
},
|
|
6651
|
-
resume: { kind: "connect", ref: privateTarget }
|
|
6652
|
-
});
|
|
6653
|
-
}
|
|
6654
|
-
if (runtime3.continueConnect) {
|
|
6655
|
-
const continuation = await runtime3.continueConnect({
|
|
6656
|
-
...resolved ?? {},
|
|
6657
|
-
privateNetwork,
|
|
6658
|
-
reservationId: privateTarget,
|
|
6659
|
-
vpnConnection: connection
|
|
6660
|
-
});
|
|
6661
|
-
if (continuation)
|
|
6662
|
-
return runtime3.result(continuation);
|
|
6663
|
-
}
|
|
6664
|
-
return runtime3.result({
|
|
6665
|
-
data: {
|
|
6666
|
-
private_network: privateNetwork,
|
|
6667
|
-
private_target: { reservation_id: privateTarget },
|
|
6668
|
-
vpn_connection: connection
|
|
6669
|
-
},
|
|
6670
|
-
outcome: { class: "ready", phase: "private_transport_ready" },
|
|
6671
|
-
presentation: {
|
|
6672
|
-
lines: ["VPN connection is ready for private access.", ...vpnLines(connection)]
|
|
6673
|
-
}
|
|
6674
|
-
});
|
|
5848
|
+
function networkExecutor(context) {
|
|
5849
|
+
const runtime3 = context.cli?.interaction;
|
|
5850
|
+
if (!runtime3?.networks)
|
|
5851
|
+
throw new Error("This capability must execute through the Ornn CLI network runtime.");
|
|
5852
|
+
return runtime3.networks.bind(runtime3);
|
|
6675
5853
|
}
|
|
6676
5854
|
function customerResource(specification) {
|
|
6677
5855
|
return defineCapability({ ...specification, mcp: false, slack: false });
|
|
@@ -6696,7 +5874,7 @@ var privateNetworkListCapability = customerResource({
|
|
|
6696
5874
|
related: ["private-networks show"]
|
|
6697
5875
|
}
|
|
6698
5876
|
},
|
|
6699
|
-
execute:
|
|
5877
|
+
execute: (ctx, input) => networkExecutor(ctx)("private-networks list", input, ctx)
|
|
6700
5878
|
});
|
|
6701
5879
|
var privateNetworkShowCapability = customerResource({
|
|
6702
5880
|
id: "networks.show",
|
|
@@ -6719,7 +5897,7 @@ var privateNetworkShowCapability = customerResource({
|
|
|
6719
5897
|
related: ["private-networks list"]
|
|
6720
5898
|
}
|
|
6721
5899
|
},
|
|
6722
|
-
execute:
|
|
5900
|
+
execute: (ctx, input) => networkExecutor(ctx)("private-networks show", input, ctx)
|
|
6723
5901
|
});
|
|
6724
5902
|
var privateNetworkCreateCapability = customerResource({
|
|
6725
5903
|
id: "networks.create",
|
|
@@ -6743,7 +5921,7 @@ var privateNetworkCreateCapability = customerResource({
|
|
|
6743
5921
|
related: ["private-networks list"]
|
|
6744
5922
|
}
|
|
6745
5923
|
},
|
|
6746
|
-
execute:
|
|
5924
|
+
execute: (ctx, input) => networkExecutor(ctx)("private-networks create", input, ctx)
|
|
6747
5925
|
});
|
|
6748
5926
|
var privateNetworkUpdateCapability = customerResource({
|
|
6749
5927
|
id: "networks.update",
|
|
@@ -6767,7 +5945,7 @@ var privateNetworkUpdateCapability = customerResource({
|
|
|
6767
5945
|
related: ["private-networks show"]
|
|
6768
5946
|
}
|
|
6769
5947
|
},
|
|
6770
|
-
execute:
|
|
5948
|
+
execute: (ctx, input) => networkExecutor(ctx)("private-networks update", input, ctx)
|
|
6771
5949
|
});
|
|
6772
5950
|
var privateNetworkDeleteCapability = customerResource({
|
|
6773
5951
|
id: "networks.delete",
|
|
@@ -6791,7 +5969,7 @@ var privateNetworkDeleteCapability = customerResource({
|
|
|
6791
5969
|
related: ["private-networks list"]
|
|
6792
5970
|
}
|
|
6793
5971
|
},
|
|
6794
|
-
execute:
|
|
5972
|
+
execute: (ctx, input) => networkExecutor(ctx)("private-networks delete", input, ctx)
|
|
6795
5973
|
});
|
|
6796
5974
|
var vpnConnectionListCapability = customerResource({
|
|
6797
5975
|
id: "vpn.connections.list",
|
|
@@ -6814,7 +5992,7 @@ var vpnConnectionListCapability = customerResource({
|
|
|
6814
5992
|
related: ["vpn-connections configure", "connect"]
|
|
6815
5993
|
}
|
|
6816
5994
|
},
|
|
6817
|
-
execute:
|
|
5995
|
+
execute: (ctx, input) => networkExecutor(ctx)("vpn-connections list", input, ctx)
|
|
6818
5996
|
});
|
|
6819
5997
|
var vpnConnectionConfigureCapability = customerResource({
|
|
6820
5998
|
id: "vpn.connections.configure",
|
|
@@ -6839,7 +6017,7 @@ var vpnConnectionConfigureCapability = customerResource({
|
|
|
6839
6017
|
related: ["connect", "vpn-connections disconnect"]
|
|
6840
6018
|
}
|
|
6841
6019
|
},
|
|
6842
|
-
execute:
|
|
6020
|
+
execute: (ctx, input) => networkExecutor(ctx)("vpn-connections configure", input, ctx)
|
|
6843
6021
|
});
|
|
6844
6022
|
var vpnConnectionDisconnectCapability = customerResource({
|
|
6845
6023
|
id: "vpn.connections.disconnect",
|
|
@@ -6867,7 +6045,7 @@ var vpnConnectionDisconnectCapability = customerResource({
|
|
|
6867
6045
|
related: ["vpn-connections configure"]
|
|
6868
6046
|
}
|
|
6869
6047
|
},
|
|
6870
|
-
execute:
|
|
6048
|
+
execute: (ctx, input) => networkExecutor(ctx)("vpn-connections disconnect", input, ctx)
|
|
6871
6049
|
});
|
|
6872
6050
|
var connectCapability = customerResource({
|
|
6873
6051
|
id: "vpn.connect",
|
|
@@ -6897,7 +6075,7 @@ var connectCapability = customerResource({
|
|
|
6897
6075
|
related: ["launch", "vpn-connections configure", "clusters show"]
|
|
6898
6076
|
}
|
|
6899
6077
|
},
|
|
6900
|
-
execute:
|
|
6078
|
+
execute: (ctx, input) => networkExecutor(ctx)("connect", input, ctx)
|
|
6901
6079
|
});
|
|
6902
6080
|
var networkCapabilities = [
|
|
6903
6081
|
privateNetworkListCapability,
|
|
@@ -6910,12 +6088,6 @@ var networkCapabilities = [
|
|
|
6910
6088
|
vpnConnectionDisconnectCapability,
|
|
6911
6089
|
connectCapability
|
|
6912
6090
|
];
|
|
6913
|
-
function networkPath(networkId) {
|
|
6914
|
-
return `${NETWORKS_PATH}/${encodeURIComponent(networkId)}`;
|
|
6915
|
-
}
|
|
6916
|
-
function vpnPeersPath(reservationId) {
|
|
6917
|
-
return `/v1/workflows/compute/nodes/reservations/${encodeURIComponent(reservationId)}/vpn/peers`;
|
|
6918
|
-
}
|
|
6919
6091
|
var networkUpdateFields = z27.object({
|
|
6920
6092
|
networkId: z27.string(),
|
|
6921
6093
|
name: z27.string().optional(),
|
|
@@ -6936,7 +6108,7 @@ var networkVerbCapabilities = [
|
|
|
6936
6108
|
input: z27.object({}),
|
|
6937
6109
|
mcp: { name: "networks_list" },
|
|
6938
6110
|
slack: false,
|
|
6939
|
-
execute: (ctx) => ctx.fetch
|
|
6111
|
+
execute: (ctx) => listNetworks(ctx.fetch)
|
|
6940
6112
|
}),
|
|
6941
6113
|
defineCapability({
|
|
6942
6114
|
id: "network.show",
|
|
@@ -6948,7 +6120,7 @@ var networkVerbCapabilities = [
|
|
|
6948
6120
|
input: z27.object({ networkId: z27.string() }),
|
|
6949
6121
|
mcp: { name: "networks_show" },
|
|
6950
6122
|
slack: false,
|
|
6951
|
-
execute: (ctx, input) => ctx.fetch
|
|
6123
|
+
execute: (ctx, input) => getNetwork(ctx.fetch, input.networkId)
|
|
6952
6124
|
}),
|
|
6953
6125
|
defineCapability({
|
|
6954
6126
|
id: "network.create",
|
|
@@ -6965,13 +6137,10 @@ var networkVerbCapabilities = [
|
|
|
6965
6137
|
}),
|
|
6966
6138
|
mcp: { name: "networks_create" },
|
|
6967
6139
|
slack: false,
|
|
6968
|
-
execute: (ctx, input) => ctx.fetch
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
cidr: input.cidr ?? null,
|
|
6973
|
-
description: input.description ?? null
|
|
6974
|
-
}
|
|
6140
|
+
execute: (ctx, input) => createNetwork(ctx.fetch, {
|
|
6141
|
+
name: input.name,
|
|
6142
|
+
cidr: input.cidr ?? null,
|
|
6143
|
+
description: input.description ?? null
|
|
6975
6144
|
})
|
|
6976
6145
|
}),
|
|
6977
6146
|
defineCapability({
|
|
@@ -6984,12 +6153,9 @@ var networkVerbCapabilities = [
|
|
|
6984
6153
|
input: networkUpdateFields,
|
|
6985
6154
|
mcp: { name: "networks_update" },
|
|
6986
6155
|
slack: false,
|
|
6987
|
-
execute: (ctx, input) => ctx.fetch
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
...input.name !== void 0 ? { name: input.name } : {},
|
|
6991
|
-
...input.clearDescription ? { description: null } : input.description !== void 0 ? { description: input.description } : {}
|
|
6992
|
-
}
|
|
6156
|
+
execute: (ctx, input) => updateNetwork(ctx.fetch, input.networkId, {
|
|
6157
|
+
...input.name !== void 0 ? { name: input.name } : {},
|
|
6158
|
+
...input.clearDescription ? { description: null } : input.description !== void 0 ? { description: input.description } : {}
|
|
6993
6159
|
})
|
|
6994
6160
|
}),
|
|
6995
6161
|
defineCapability({
|
|
@@ -7004,7 +6170,7 @@ var networkVerbCapabilities = [
|
|
|
7004
6170
|
slack: false,
|
|
7005
6171
|
// The route answers 204, so report which network went.
|
|
7006
6172
|
execute: async (ctx, input) => {
|
|
7007
|
-
await ctx.fetch
|
|
6173
|
+
await deleteNetwork(ctx.fetch, input.networkId);
|
|
7008
6174
|
return { deleted: true, network_id: input.networkId };
|
|
7009
6175
|
}
|
|
7010
6176
|
}),
|
|
@@ -7016,12 +6182,12 @@ var networkVerbCapabilities = [
|
|
|
7016
6182
|
mutation: "read",
|
|
7017
6183
|
http: {
|
|
7018
6184
|
method: "GET",
|
|
7019
|
-
path: "/v1/
|
|
6185
|
+
path: "/v1/orchestrator/networks/shared/peers"
|
|
7020
6186
|
},
|
|
7021
6187
|
input: z27.object({ reservationId: z27.string() }),
|
|
7022
6188
|
mcp: { name: "vpn_peers_list" },
|
|
7023
6189
|
slack: false,
|
|
7024
|
-
execute: (ctx
|
|
6190
|
+
execute: (ctx) => listNetworkPeerConfigs(ctx.fetch, "shared")
|
|
7025
6191
|
}),
|
|
7026
6192
|
defineCapability({
|
|
7027
6193
|
id: "vpn.peers.create",
|
|
@@ -7031,7 +6197,7 @@ var networkVerbCapabilities = [
|
|
|
7031
6197
|
mutation: "preview-confirm",
|
|
7032
6198
|
http: {
|
|
7033
6199
|
method: "POST",
|
|
7034
|
-
path: "/v1/
|
|
6200
|
+
path: "/v1/orchestrator/networks/shared/peers"
|
|
7035
6201
|
},
|
|
7036
6202
|
input: z27.object({
|
|
7037
6203
|
reservationId: z27.string(),
|
|
@@ -7041,9 +6207,9 @@ var networkVerbCapabilities = [
|
|
|
7041
6207
|
}),
|
|
7042
6208
|
mcp: { name: "vpn_peers_create" },
|
|
7043
6209
|
slack: false,
|
|
7044
|
-
execute: (ctx, input) => ctx.fetch
|
|
7045
|
-
|
|
7046
|
-
|
|
6210
|
+
execute: (ctx, input) => createNetworkPeer(ctx.fetch, "shared", {
|
|
6211
|
+
public_key: input.publicKey,
|
|
6212
|
+
label: input.label ?? null
|
|
7047
6213
|
})
|
|
7048
6214
|
}),
|
|
7049
6215
|
defineCapability({
|
|
@@ -7054,7 +6220,7 @@ var networkVerbCapabilities = [
|
|
|
7054
6220
|
mutation: "preview-confirm",
|
|
7055
6221
|
http: {
|
|
7056
6222
|
method: "DELETE",
|
|
7057
|
-
path: "/v1/
|
|
6223
|
+
path: "/v1/orchestrator/networks/shared/peers/{peerId}"
|
|
7058
6224
|
},
|
|
7059
6225
|
input: z27.object({
|
|
7060
6226
|
reservationId: z27.string(),
|
|
@@ -7063,9 +6229,7 @@ var networkVerbCapabilities = [
|
|
|
7063
6229
|
}),
|
|
7064
6230
|
mcp: { name: "vpn_peers_delete" },
|
|
7065
6231
|
slack: false,
|
|
7066
|
-
execute: async (ctx, input) => await ctx.fetch
|
|
7067
|
-
method: "DELETE"
|
|
7068
|
-
}) ?? { deleted: true }
|
|
6232
|
+
execute: async (ctx, input) => await deleteNetworkPeer(ctx.fetch, "shared", input.peerId) ?? { deleted: true }
|
|
7069
6233
|
})
|
|
7070
6234
|
];
|
|
7071
6235
|
|
|
@@ -7108,12 +6272,12 @@ function formatBytes(bytes) {
|
|
|
7108
6272
|
}
|
|
7109
6273
|
return `${value >= 10 || unit === 0 ? Math.round(value) : value.toFixed(1)} ${units[unit]}`;
|
|
7110
6274
|
}
|
|
7111
|
-
function repositoryArgument(input,
|
|
6275
|
+
function repositoryArgument(input, interaction) {
|
|
7112
6276
|
const raw = input.repository ?? input.$positionals[0];
|
|
7113
6277
|
if (!raw) {
|
|
7114
6278
|
const message = "Name a repository, such as trainer.";
|
|
7115
|
-
if (
|
|
7116
|
-
|
|
6279
|
+
if (interaction)
|
|
6280
|
+
interaction.usage(message, { code: "repository_required", field: "repository" });
|
|
7117
6281
|
throw new Error(message);
|
|
7118
6282
|
}
|
|
7119
6283
|
const reference = raw.trim();
|
|
@@ -7147,10 +6311,10 @@ var registryShowCapability = defineCapability({
|
|
|
7147
6311
|
slack: false,
|
|
7148
6312
|
execute: async (context) => {
|
|
7149
6313
|
const registry = await getContainerRegistry(context.fetch);
|
|
7150
|
-
const
|
|
7151
|
-
if (!
|
|
6314
|
+
const interaction = cliInteraction(context);
|
|
6315
|
+
if (!interaction)
|
|
7152
6316
|
return registry;
|
|
7153
|
-
return
|
|
6317
|
+
return interaction.result({
|
|
7154
6318
|
data: registry,
|
|
7155
6319
|
presentation: {
|
|
7156
6320
|
lines: [`Image prefix: ${registry.host}/${registry.namespace}`],
|
|
@@ -7182,11 +6346,11 @@ var registryRepositoriesListCapability = defineCapability({
|
|
|
7182
6346
|
slack: false,
|
|
7183
6347
|
execute: async (context) => {
|
|
7184
6348
|
const listed = await listRegistryRepositories(context.fetch);
|
|
7185
|
-
const
|
|
7186
|
-
if (!
|
|
6349
|
+
const interaction = cliInteraction(context);
|
|
6350
|
+
if (!interaction)
|
|
7187
6351
|
return listed;
|
|
7188
6352
|
const registry = await getContainerRegistry(context.fetch);
|
|
7189
|
-
return
|
|
6353
|
+
return interaction.result({
|
|
7190
6354
|
data: listed,
|
|
7191
6355
|
presentation: {
|
|
7192
6356
|
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."]
|
|
@@ -7218,13 +6382,13 @@ var registryTagsListCapability = defineCapability({
|
|
|
7218
6382
|
},
|
|
7219
6383
|
slack: false,
|
|
7220
6384
|
execute: async (context, input) => {
|
|
7221
|
-
const
|
|
6385
|
+
const interaction = cliInteraction(context);
|
|
7222
6386
|
const registry = await getContainerRegistry(context.fetch);
|
|
7223
|
-
const repository = qualifiedRepository(repositoryArgument(input,
|
|
6387
|
+
const repository = qualifiedRepository(repositoryArgument(input, interaction).repository, registry);
|
|
7224
6388
|
const listed = await listRegistryTags(context.fetch, repository);
|
|
7225
|
-
if (!
|
|
6389
|
+
if (!interaction)
|
|
7226
6390
|
return listed;
|
|
7227
|
-
return
|
|
6391
|
+
return interaction.result({
|
|
7228
6392
|
data: listed,
|
|
7229
6393
|
presentation: {
|
|
7230
6394
|
lines: listed.tags.map((tag) => `${tag.tag} ${tag.digest.slice(0, 19)} ${formatBytes(tag.size_bytes)}${tag.created_at ? ` built ${tag.created_at}` : ""}`)
|
|
@@ -7257,20 +6421,20 @@ var registryTagsDeleteCapability = defineCapability({
|
|
|
7257
6421
|
},
|
|
7258
6422
|
slack: false,
|
|
7259
6423
|
execute: async (context, input) => {
|
|
7260
|
-
const
|
|
6424
|
+
const interaction = cliInteraction(context);
|
|
7261
6425
|
const registry = await getContainerRegistry(context.fetch);
|
|
7262
|
-
const argument = repositoryArgument(input,
|
|
6426
|
+
const argument = repositoryArgument(input, interaction);
|
|
7263
6427
|
const repository = qualifiedRepository(argument.repository, registry);
|
|
7264
6428
|
if (!argument.tag) {
|
|
7265
6429
|
const message = "Name the tag to delete, such as trainer:v1.";
|
|
7266
|
-
if (
|
|
7267
|
-
|
|
6430
|
+
if (interaction)
|
|
6431
|
+
interaction.usage(message, { code: "tag_required", field: "tag" });
|
|
7268
6432
|
throw new Error(message);
|
|
7269
6433
|
}
|
|
7270
6434
|
const target = { repository, tag: argument.tag };
|
|
7271
|
-
if (
|
|
6435
|
+
if (interaction) {
|
|
7272
6436
|
if (!input.yes) {
|
|
7273
|
-
const approved = await
|
|
6437
|
+
const approved = await interaction.review({
|
|
7274
6438
|
title: "Delete this image tag?",
|
|
7275
6439
|
terms: [
|
|
7276
6440
|
{ label: "Image", value: `${registry.host}/${repository}:${argument.tag}` },
|
|
@@ -7282,7 +6446,7 @@ var registryTagsDeleteCapability = defineCapability({
|
|
|
7282
6446
|
prompt: "Delete it?"
|
|
7283
6447
|
});
|
|
7284
6448
|
if (!approved) {
|
|
7285
|
-
return
|
|
6449
|
+
return interaction.result({
|
|
7286
6450
|
data: target,
|
|
7287
6451
|
outcome: { class: "cancelled", phase: "review" },
|
|
7288
6452
|
presentation: { lines: ["Nothing was deleted."] }
|
|
@@ -7294,9 +6458,9 @@ var registryTagsDeleteCapability = defineCapability({
|
|
|
7294
6458
|
}
|
|
7295
6459
|
await deleteRegistryTag(context.fetch, target.repository, target.tag);
|
|
7296
6460
|
const deleted = { deleted: true, ...target };
|
|
7297
|
-
if (!
|
|
6461
|
+
if (!interaction)
|
|
7298
6462
|
return deleted;
|
|
7299
|
-
return
|
|
6463
|
+
return interaction.result({
|
|
7300
6464
|
data: deleted,
|
|
7301
6465
|
presentation: { lines: [`Deleted ${shortName(repository, registry)}:${argument.tag}.`] }
|
|
7302
6466
|
});
|
|
@@ -7325,10 +6489,10 @@ var registryUsageCapability = defineCapability({
|
|
|
7325
6489
|
slack: false,
|
|
7326
6490
|
execute: async (context) => {
|
|
7327
6491
|
const usage = await getRegistryUsage(context.fetch);
|
|
7328
|
-
const
|
|
7329
|
-
if (!
|
|
6492
|
+
const interaction = cliInteraction(context);
|
|
6493
|
+
if (!interaction)
|
|
7330
6494
|
return usage;
|
|
7331
|
-
return
|
|
6495
|
+
return interaction.result({
|
|
7332
6496
|
data: usage,
|
|
7333
6497
|
presentation: { lines: [`Storage used: ${formatBytes(usage.bytes)}`] }
|
|
7334
6498
|
});
|
|
@@ -7379,11 +6543,11 @@ var registryLoginCapability = defineCapability({
|
|
|
7379
6543
|
mcp: false,
|
|
7380
6544
|
slack: false,
|
|
7381
6545
|
execute: async (context, input) => {
|
|
7382
|
-
const
|
|
7383
|
-
if (!
|
|
6546
|
+
const interaction = context.cli?.interaction;
|
|
6547
|
+
if (!interaction?.registry) {
|
|
7384
6548
|
throw new Error("ornn registry login runs only in the Ornn CLI.");
|
|
7385
6549
|
}
|
|
7386
|
-
return
|
|
6550
|
+
return interaction.registry.call(interaction, "registry.login", input);
|
|
7387
6551
|
}
|
|
7388
6552
|
});
|
|
7389
6553
|
var registryCapabilities = [
|
|
@@ -7472,11 +6636,11 @@ var storageCliInput = z30.object({
|
|
|
7472
6636
|
yes: z30.boolean().optional()
|
|
7473
6637
|
}).strict();
|
|
7474
6638
|
function storageExecutor(context) {
|
|
7475
|
-
const
|
|
7476
|
-
if (!
|
|
6639
|
+
const interaction = context.cli?.interaction;
|
|
6640
|
+
if (!interaction?.storage) {
|
|
7477
6641
|
throw new Error("This capability must execute through the Ornn CLI storage runtime.");
|
|
7478
6642
|
}
|
|
7479
|
-
return
|
|
6643
|
+
return interaction.storage.bind(interaction);
|
|
7480
6644
|
}
|
|
7481
6645
|
function storageCapability({ id, command, description, mutation, outcome, human, automation, acceptedReferences = [], review, related = [] }) {
|
|
7482
6646
|
return defineCapability({
|