@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.
- package/README.md +55 -24
- package/package.json +4 -2
- package/src/admin-capacity-reservations.mjs +6 -13
- package/src/admin-command-handlers.mjs +2 -1
- package/src/admin-credits.mjs +1 -2
- package/src/admin-enrollment.mjs +22 -30
- package/src/admin-mutations.mjs +6 -56
- package/src/admin-node-diagnostics.mjs +3 -41
- package/src/admin-node-lifecycle.mjs +40 -160
- package/src/admin-node-sanitize.mjs +243 -0
- package/src/admin-shell.mjs +39 -32
- package/src/catalog-shell.mjs +6 -6
- package/src/evidence-commands.mjs +4 -6
- package/src/external-bucket-commands.mjs +76 -96
- package/src/interaction-runtime.mjs +5 -37
- package/src/kubernetes-commands.mjs +25 -183
- package/src/launch-mode-handlers.mjs +0 -1
- package/src/machine-reference.mjs +33 -56
- package/src/mount-commands.mjs +25 -131
- package/src/slurm-commands.mjs +13 -2
- package/src/storage-commands.mjs +2 -87
- package/src/vm-commands.mjs +48 -101
- package/vendor/api-client/commerce.js +743 -0
- package/vendor/capabilities/cli.js +7688 -7
- package/vendor/capabilities/capabilities/admin-capacity-reservations.js +0 -101
- package/vendor/capabilities/capabilities/admin-enrollment.js +0 -321
- package/vendor/capabilities/capabilities/admin-node-diagnostics.js +0 -88
- package/vendor/capabilities/capabilities/admin-nodes-lifecycle.js +0 -235
- package/vendor/capabilities/capabilities/admin.js +0 -91
- package/vendor/capabilities/capabilities/cli.js +0 -156
- package/vendor/capabilities/capabilities/clusters.js +0 -248
- package/vendor/capabilities/capabilities/commerce-market.js +0 -405
- package/vendor/capabilities/capabilities/compute.js +0 -523
- package/vendor/capabilities/capabilities/credits.js +0 -78
- package/vendor/capabilities/capabilities/evidence.js +0 -145
- package/vendor/capabilities/capabilities/external-buckets.js +0 -191
- package/vendor/capabilities/capabilities/fleet.js +0 -306
- package/vendor/capabilities/capabilities/identity.js +0 -129
- package/vendor/capabilities/capabilities/listings.js +0 -398
- package/vendor/capabilities/capabilities/locality.js +0 -42
- package/vendor/capabilities/capabilities/market-shared.js +0 -46
- package/vendor/capabilities/capabilities/markets.js +0 -482
- package/vendor/capabilities/capabilities/mounts.js +0 -176
- package/vendor/capabilities/capabilities/native-listing.js +0 -99
- package/vendor/capabilities/capabilities/networks.js +0 -1264
- package/vendor/capabilities/capabilities/observability.js +0 -218
- package/vendor/capabilities/capabilities/organization-invites.js +0 -53
- package/vendor/capabilities/capabilities/reservation-list.js +0 -68
- package/vendor/capabilities/capabilities/staff-shared.js +0 -64
- package/vendor/capabilities/capabilities/tokens.js +0 -165
- package/vendor/capabilities/capabilities/users.js +0 -159
- package/vendor/capabilities/capabilities/volumes.js +0 -178
- package/vendor/capabilities/capability.js +0 -99
- package/vendor/capabilities/cli-catalog.js +0 -73
- package/vendor/capabilities/cli-migrations.js +0 -264
- package/vendor/capabilities/names.js +0 -6
- package/vendor/capabilities/software-catalog.js +0 -82
- package/vendor/capabilities/spec-catalog.js +0 -151
- package/vendor/capabilities/supplier-directory.js +0 -20
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { defineCapability } from "../capability.js";
|
|
3
|
-
const directoryLimit = z.number().int().min(1).max(100).default(25);
|
|
4
|
-
const directoryOffset = z.number().int().nonnegative().optional();
|
|
5
|
-
export const organizationListInput = z.object({
|
|
6
|
-
q: z.string().trim().optional().describe("Company name, contact/member name, or email."),
|
|
7
|
-
role: z.enum(["consumer", "supplier"]).optional(),
|
|
8
|
-
approved: z.boolean().optional(),
|
|
9
|
-
ids: z.array(z.uuid()).min(1).max(100).optional(),
|
|
10
|
-
limit: directoryLimit,
|
|
11
|
-
offset: directoryOffset,
|
|
12
|
-
});
|
|
13
|
-
export const usersListInput = z.object({
|
|
14
|
-
q: z.string().trim().optional().describe("Person name, email, or company name."),
|
|
15
|
-
organization_id: z.uuid().optional(),
|
|
16
|
-
limit: directoryLimit,
|
|
17
|
-
offset: directoryOffset,
|
|
18
|
-
});
|
|
19
|
-
function directoryPath(input) {
|
|
20
|
-
const params = [
|
|
21
|
-
`limit=${input.limit}`,
|
|
22
|
-
`offset=${input.offset}`,
|
|
23
|
-
"sort=name",
|
|
24
|
-
"direction=asc",
|
|
25
|
-
];
|
|
26
|
-
if (input.q)
|
|
27
|
-
params.push(`q=${encodeURIComponent(input.q)}`);
|
|
28
|
-
if (input.role)
|
|
29
|
-
params.push(`role=${encodeURIComponent(input.role)}`);
|
|
30
|
-
if (input.approved !== undefined) {
|
|
31
|
-
params.push(`approved=${input.approved}`);
|
|
32
|
-
}
|
|
33
|
-
if (input.ids)
|
|
34
|
-
params.push(`ids=${encodeURIComponent(input.ids.join(","))}`);
|
|
35
|
-
return `/v1/organizations?${params.join("&")}`;
|
|
36
|
-
}
|
|
37
|
-
function directoryMembers(organization) {
|
|
38
|
-
return organization.members ?? [];
|
|
39
|
-
}
|
|
40
|
-
function organizationMatchesQuery(organization, query) {
|
|
41
|
-
return (organization.name.toLowerCase().includes(query) ||
|
|
42
|
-
organization.id.toLowerCase() === query ||
|
|
43
|
-
[
|
|
44
|
-
organization.company_profile?.company_name,
|
|
45
|
-
organization.company_profile?.contact_name,
|
|
46
|
-
organization.company_profile?.contact_email,
|
|
47
|
-
organization.company_profile?.work_email,
|
|
48
|
-
].some((value) => value?.toLowerCase().includes(query)));
|
|
49
|
-
}
|
|
50
|
-
export const organizationListCapability = defineCapability({
|
|
51
|
-
id: "organization.list",
|
|
52
|
-
domain: "users",
|
|
53
|
-
roles: ["admin"],
|
|
54
|
-
description: "List organizations from the Authorization directory. Search by company name, contact/member name, or email; filter by role, approval, or UUIDs. Use the organization id as organizationId when recording downtime, and ask the user to choose if matches are ambiguous.",
|
|
55
|
-
mutation: "read",
|
|
56
|
-
http: { method: "GET", path: "/v1/organizations" },
|
|
57
|
-
slack: {
|
|
58
|
-
parameters: {
|
|
59
|
-
type: "object",
|
|
60
|
-
properties: {
|
|
61
|
-
q: {
|
|
62
|
-
type: "string",
|
|
63
|
-
description: "Company name, contact/member name, or email.",
|
|
64
|
-
},
|
|
65
|
-
role: { type: "string", enum: ["consumer", "supplier"] },
|
|
66
|
-
approved: { type: "boolean" },
|
|
67
|
-
ids: {
|
|
68
|
-
type: "array",
|
|
69
|
-
items: { type: "string", format: "uuid" },
|
|
70
|
-
minItems: 1,
|
|
71
|
-
maxItems: 100,
|
|
72
|
-
},
|
|
73
|
-
limit: { type: "integer", minimum: 1, maximum: 100, default: 25 },
|
|
74
|
-
offset: { type: "integer", minimum: 0 },
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
|
-
input: organizationListInput,
|
|
79
|
-
execute: async (ctx, input) => {
|
|
80
|
-
const parsed = organizationListInput.parse(input);
|
|
81
|
-
const limit = parsed.limit;
|
|
82
|
-
const offset = parsed.offset ?? 0;
|
|
83
|
-
const rows = (await ctx.fetch(directoryPath({ ...parsed, limit, offset }), { method: "GET" }));
|
|
84
|
-
return {
|
|
85
|
-
organizations: rows.map((organization) => ({
|
|
86
|
-
id: organization.id,
|
|
87
|
-
name: organization.name,
|
|
88
|
-
role: organization.role,
|
|
89
|
-
approved: organization.approved,
|
|
90
|
-
members: directoryMembers(organization).map((member) => ({
|
|
91
|
-
user_id: member.user_id,
|
|
92
|
-
email: member.email,
|
|
93
|
-
name: member.name ?? null,
|
|
94
|
-
})),
|
|
95
|
-
})),
|
|
96
|
-
...(rows.length === limit ? { next_offset: offset + rows.length } : {}),
|
|
97
|
-
};
|
|
98
|
-
},
|
|
99
|
-
});
|
|
100
|
-
export const usersListCapability = defineCapability({
|
|
101
|
-
id: "users.list",
|
|
102
|
-
domain: "users",
|
|
103
|
-
roles: ["admin"],
|
|
104
|
-
description: "List users who belong to an organization, from the Authorization directory. Search by person name, email, or company name; use organization_id to restrict results to one organization.",
|
|
105
|
-
mutation: "read",
|
|
106
|
-
http: { method: "GET", path: "/v1/organizations" },
|
|
107
|
-
slack: {
|
|
108
|
-
parameters: {
|
|
109
|
-
type: "object",
|
|
110
|
-
properties: {
|
|
111
|
-
q: { type: "string", description: "Person name, email, or company name." },
|
|
112
|
-
organization_id: { type: "string", format: "uuid" },
|
|
113
|
-
limit: {
|
|
114
|
-
type: "integer",
|
|
115
|
-
minimum: 1,
|
|
116
|
-
maximum: 100,
|
|
117
|
-
default: 25,
|
|
118
|
-
description: "Maximum number of organizations to search.",
|
|
119
|
-
},
|
|
120
|
-
offset: { type: "integer", minimum: 0 },
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
input: usersListInput,
|
|
125
|
-
execute: async (ctx, input) => {
|
|
126
|
-
const parsed = usersListInput.parse(input);
|
|
127
|
-
const limit = parsed.limit;
|
|
128
|
-
const offset = parsed.offset ?? 0;
|
|
129
|
-
const rows = (await ctx.fetch(directoryPath({
|
|
130
|
-
limit,
|
|
131
|
-
offset,
|
|
132
|
-
q: parsed.q,
|
|
133
|
-
ids: parsed.organization_id ? [parsed.organization_id] : undefined,
|
|
134
|
-
}), { method: "GET" }));
|
|
135
|
-
const q = parsed.q?.toLowerCase();
|
|
136
|
-
const users = rows.flatMap((organization) => {
|
|
137
|
-
const members = directoryMembers(organization);
|
|
138
|
-
const matchesOrganization = q ? organizationMatchesQuery(organization, q) : false;
|
|
139
|
-
return members
|
|
140
|
-
.filter((member) => !q ||
|
|
141
|
-
matchesOrganization ||
|
|
142
|
-
(member.name ?? "").toLowerCase().includes(q) || member.email.toLowerCase().includes(q))
|
|
143
|
-
.map((member) => ({
|
|
144
|
-
user_id: member.user_id,
|
|
145
|
-
email: member.email,
|
|
146
|
-
name: member.name ?? null,
|
|
147
|
-
organization_id: organization.id,
|
|
148
|
-
organization_name: organization.name,
|
|
149
|
-
organization_role: organization.role,
|
|
150
|
-
approved: organization.approved,
|
|
151
|
-
}));
|
|
152
|
-
});
|
|
153
|
-
return {
|
|
154
|
-
users,
|
|
155
|
-
...(rows.length === limit ? { next_offset: offset + rows.length } : {}),
|
|
156
|
-
};
|
|
157
|
-
},
|
|
158
|
-
});
|
|
159
|
-
export const userCapabilities = [organizationListCapability, usersListCapability];
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { defineCapability, } from "../capability.js";
|
|
3
|
-
const storageCliInput = z
|
|
4
|
-
.object({
|
|
5
|
-
$positionals: z.array(z.string()).optional(),
|
|
6
|
-
contentType: z.string().optional(),
|
|
7
|
-
cursor: z.string().optional(),
|
|
8
|
-
idempotencyKey: z.string().optional(),
|
|
9
|
-
limit: z.union([z.string(), z.number()]).optional(),
|
|
10
|
-
name: z.string().optional(),
|
|
11
|
-
output: z.string().optional(),
|
|
12
|
-
overwrite: z.boolean().optional(),
|
|
13
|
-
path: z.string().optional(),
|
|
14
|
-
prefix: z.string().optional(),
|
|
15
|
-
source: z.string().optional(),
|
|
16
|
-
yes: z.boolean().optional(),
|
|
17
|
-
})
|
|
18
|
-
.strict();
|
|
19
|
-
function storageExecutor(context) {
|
|
20
|
-
const interaction = context.cli?.interaction;
|
|
21
|
-
if (!interaction?.storage) {
|
|
22
|
-
throw new Error("This capability must execute through the Ornn CLI storage runtime.");
|
|
23
|
-
}
|
|
24
|
-
return interaction.storage.bind(interaction);
|
|
25
|
-
}
|
|
26
|
-
function storageCapability({ id, command, description, mutation, outcome, human, automation, acceptedReferences = [], review, related = [], }) {
|
|
27
|
-
return defineCapability({
|
|
28
|
-
id,
|
|
29
|
-
domain: "storage",
|
|
30
|
-
roles: ["user"],
|
|
31
|
-
description,
|
|
32
|
-
mutation,
|
|
33
|
-
input: storageCliInput,
|
|
34
|
-
cli: {
|
|
35
|
-
command,
|
|
36
|
-
vnext: {
|
|
37
|
-
arguments: "semantic",
|
|
38
|
-
audience: "customer",
|
|
39
|
-
category: "resource",
|
|
40
|
-
outcome,
|
|
41
|
-
human,
|
|
42
|
-
automation,
|
|
43
|
-
acceptedReferences,
|
|
44
|
-
...(review ? { review } : {}),
|
|
45
|
-
related,
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
mcp: false,
|
|
49
|
-
slack: false,
|
|
50
|
-
execute: async (context, input) => storageExecutor(context)(id, input),
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
export const volumeCapabilities = [
|
|
54
|
-
storageCapability({
|
|
55
|
-
id: "storage.volumes.list",
|
|
56
|
-
command: ["volumes", "list"],
|
|
57
|
-
description: "List managed volumes in one bounded page.",
|
|
58
|
-
mutation: "read",
|
|
59
|
-
outcome: "List durable managed volumes independently from their mounts.",
|
|
60
|
-
human: "ornn volumes list [--limit <1-100>] [--cursor <cursor>]",
|
|
61
|
-
automation: "ornn volumes list --limit 50 --format json",
|
|
62
|
-
related: ["volumes show", "volumes create"],
|
|
63
|
-
}),
|
|
64
|
-
storageCapability({
|
|
65
|
-
id: "storage.volumes.show",
|
|
66
|
-
command: ["volumes", "show"],
|
|
67
|
-
description: "Inspect one managed volume by canonical ID or exact unique name.",
|
|
68
|
-
mutation: "read",
|
|
69
|
-
outcome: "Inspect one durable volume without changing its lifecycle.",
|
|
70
|
-
human: "ornn volumes show <volume>",
|
|
71
|
-
automation: "ornn volumes show <volume-id> --format json",
|
|
72
|
-
acceptedReferences: ["canonical volume ID", "exact unique volume name"],
|
|
73
|
-
related: ["volumes files list", "volume-mounts show"],
|
|
74
|
-
}),
|
|
75
|
-
storageCapability({
|
|
76
|
-
id: "storage.volumes.create",
|
|
77
|
-
command: ["volumes", "create"],
|
|
78
|
-
description: "Create or rediscover a uniquely named managed volume.",
|
|
79
|
-
mutation: "preview-confirm",
|
|
80
|
-
outcome: "Create one durable volume or safely replay its normalized intent.",
|
|
81
|
-
human: "ornn volumes create --name <name> [--source <volume>] [--yes]",
|
|
82
|
-
automation: "ornn volumes create --name <name> [--source <volume-id>] --yes --idempotency-key <key> --format json",
|
|
83
|
-
acceptedReferences: ["canonical source volume ID", "exact unique source volume name"],
|
|
84
|
-
related: ["volumes show", "volumes files upload"],
|
|
85
|
-
}),
|
|
86
|
-
storageCapability({
|
|
87
|
-
id: "storage.volumes.refresh",
|
|
88
|
-
command: ["volumes", "refresh"],
|
|
89
|
-
description: "Refresh the owner-backed view of one managed volume.",
|
|
90
|
-
mutation: "read",
|
|
91
|
-
outcome: "Refresh and inspect the current durable volume state.",
|
|
92
|
-
human: "ornn volumes refresh <volume>",
|
|
93
|
-
automation: "ornn volumes refresh <volume-id> --format json",
|
|
94
|
-
acceptedReferences: ["canonical volume ID", "exact unique volume name"],
|
|
95
|
-
related: ["volumes show"],
|
|
96
|
-
}),
|
|
97
|
-
storageCapability({
|
|
98
|
-
id: "storage.volumes.clear",
|
|
99
|
-
command: ["volumes", "clear"],
|
|
100
|
-
description: "Erase every file in one volume after a live default-no confirmation.",
|
|
101
|
-
mutation: "preview-confirm",
|
|
102
|
-
outcome: "Permanently clear one volume only from a live interactive terminal.",
|
|
103
|
-
human: "ornn volumes clear <volume>",
|
|
104
|
-
automation: "Unsupported: this command requires a live interactive terminal.",
|
|
105
|
-
acceptedReferences: ["canonical volume ID", "exact unique volume name"],
|
|
106
|
-
review: "Every file and folder in the volume is permanently deleted.",
|
|
107
|
-
related: ["volumes files list", "volume-mounts detach"],
|
|
108
|
-
}),
|
|
109
|
-
storageCapability({
|
|
110
|
-
id: "storage.volumes.delete",
|
|
111
|
-
command: ["volumes", "delete"],
|
|
112
|
-
description: "Delete an explicitly selected, relationship-free managed volume.",
|
|
113
|
-
mutation: "preview-confirm",
|
|
114
|
-
outcome: "Delete one detached volume after explicit consent.",
|
|
115
|
-
human: "ornn volumes delete <volume>",
|
|
116
|
-
automation: "ornn volumes delete <volume-id> --yes --idempotency-key <key> --format json",
|
|
117
|
-
acceptedReferences: ["canonical volume ID", "exact unique volume name"],
|
|
118
|
-
review: "The volume and all of its data are permanently deleted.",
|
|
119
|
-
related: ["volume-mounts detach", "volumes show"],
|
|
120
|
-
}),
|
|
121
|
-
storageCapability({
|
|
122
|
-
id: "storage.volumes.files.list",
|
|
123
|
-
command: ["volumes", "files", "list"],
|
|
124
|
-
description: "List nested files in one volume in a bounded page.",
|
|
125
|
-
mutation: "read",
|
|
126
|
-
outcome: "List nested volume files by semantic remote path.",
|
|
127
|
-
human: "ornn volumes files list <volume> [--prefix <remote-path>] [--limit <1-500>] [--cursor <cursor>]",
|
|
128
|
-
automation: "ornn volumes files list <volume-id> --limit 50 --format json",
|
|
129
|
-
acceptedReferences: ["canonical volume ID", "exact unique volume name"],
|
|
130
|
-
related: ["volumes files upload", "volumes files download"],
|
|
131
|
-
}),
|
|
132
|
-
storageCapability({
|
|
133
|
-
id: "storage.volumes.files.upload",
|
|
134
|
-
command: ["volumes", "files", "upload"],
|
|
135
|
-
description: "Stage, upload, and finalize one local file at a nested volume path.",
|
|
136
|
-
mutation: "preview-confirm",
|
|
137
|
-
outcome: "Upload one file through a reconciled staged transfer.",
|
|
138
|
-
human: "ornn volumes files upload <volume> <local-file> [--path <remote-path>] [--content-type <type>] [--yes]",
|
|
139
|
-
automation: "ornn volumes files upload <volume-id> <local-file> --path <remote-path> --yes --idempotency-key <key> --format json",
|
|
140
|
-
acceptedReferences: ["canonical volume ID", "exact unique volume name"],
|
|
141
|
-
related: ["volumes files list", "volumes refresh"],
|
|
142
|
-
}),
|
|
143
|
-
storageCapability({
|
|
144
|
-
id: "storage.volumes.files.download",
|
|
145
|
-
command: ["volumes", "files", "download"],
|
|
146
|
-
description: "Download one nested volume file to an explicit local path atomically.",
|
|
147
|
-
mutation: "local",
|
|
148
|
-
outcome: "Download one file without partially replacing local data.",
|
|
149
|
-
human: "ornn volumes files download <volume> <remote-path> --output <local-path> [--overwrite]",
|
|
150
|
-
automation: "ornn volumes files download <volume-id> <remote-path> --output <local-path> --format json",
|
|
151
|
-
acceptedReferences: ["canonical volume ID", "exact unique volume name"],
|
|
152
|
-
related: ["volumes files list"],
|
|
153
|
-
}),
|
|
154
|
-
storageCapability({
|
|
155
|
-
id: "storage.volumes.files.delete",
|
|
156
|
-
command: ["volumes", "files", "delete"],
|
|
157
|
-
description: "Delete one nested file after a live default-no confirmation.",
|
|
158
|
-
mutation: "preview-confirm",
|
|
159
|
-
outcome: "Permanently delete one file only from a live interactive terminal.",
|
|
160
|
-
human: "ornn volumes files delete <volume> <remote-path>",
|
|
161
|
-
automation: "Unsupported: this command requires a live interactive terminal.",
|
|
162
|
-
acceptedReferences: ["canonical volume ID", "exact unique volume name"],
|
|
163
|
-
review: "The selected file is permanently deleted.",
|
|
164
|
-
related: ["volumes files list"],
|
|
165
|
-
}),
|
|
166
|
-
storageCapability({
|
|
167
|
-
id: "storage.volumes.folders.delete",
|
|
168
|
-
command: ["volumes", "folders", "delete"],
|
|
169
|
-
description: "Delete one nested folder after a live default-no confirmation.",
|
|
170
|
-
mutation: "preview-confirm",
|
|
171
|
-
outcome: "Permanently delete one folder tree only from a live interactive terminal.",
|
|
172
|
-
human: "ornn volumes folders delete <volume> <remote-path>",
|
|
173
|
-
automation: "Unsupported: this command requires a live interactive terminal.",
|
|
174
|
-
acceptedReferences: ["canonical volume ID", "exact unique volume name"],
|
|
175
|
-
review: "The selected folder and every nested file are permanently deleted.",
|
|
176
|
-
related: ["volumes files list"],
|
|
177
|
-
}),
|
|
178
|
-
];
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { namesFromId } from "./names.js";
|
|
2
|
-
export const DOMAINS = [
|
|
3
|
-
"cli",
|
|
4
|
-
"identity",
|
|
5
|
-
"listings",
|
|
6
|
-
"fleet",
|
|
7
|
-
"users",
|
|
8
|
-
"reservations",
|
|
9
|
-
"markets",
|
|
10
|
-
"access",
|
|
11
|
-
"clusters",
|
|
12
|
-
"slurm",
|
|
13
|
-
"kubernetes",
|
|
14
|
-
"networks",
|
|
15
|
-
"storage",
|
|
16
|
-
"vpn",
|
|
17
|
-
"billing",
|
|
18
|
-
"downtime",
|
|
19
|
-
"observability",
|
|
20
|
-
"gtm",
|
|
21
|
-
];
|
|
22
|
-
/**
|
|
23
|
-
* Build a preview-confirm capability's un-executed result.
|
|
24
|
-
*
|
|
25
|
-
* Previews used to return `{ ok: true, action, payload }`, which is
|
|
26
|
-
* indistinguishable from a completed mutation to anyone skimming the JSON --
|
|
27
|
-
* a human, or an LLM deciding whether its call took effect. ORN-3417 recorded
|
|
28
|
-
* a live `node.off-grid` preview as a confirm-gate failure for exactly that
|
|
29
|
-
* reason. `status: "preview"` states it outright, and carries no `ok`.
|
|
30
|
-
*/
|
|
31
|
-
export function preview(action, payload) {
|
|
32
|
-
return { status: "preview", requiresConfirm: true, confirmed: false, action, payload };
|
|
33
|
-
}
|
|
34
|
-
/** CLI is opt-in; MCP and Slack retain derived names unless explicitly unbound. */
|
|
35
|
-
export function defineCapability(spec) {
|
|
36
|
-
const names = namesFromId(spec.id);
|
|
37
|
-
const { cli, mcp, slack, ...rest } = spec;
|
|
38
|
-
return {
|
|
39
|
-
...rest,
|
|
40
|
-
...(cli !== false && cli !== undefined
|
|
41
|
-
? {
|
|
42
|
-
cli: {
|
|
43
|
-
command: cli.command ?? names.cli,
|
|
44
|
-
...(cli.vnext ? { vnext: cli.vnext } : {}),
|
|
45
|
-
},
|
|
46
|
-
}
|
|
47
|
-
: {}),
|
|
48
|
-
...(mcp === false ? {} : { mcp: { name: mcp?.name ?? names.mcp } }),
|
|
49
|
-
...(slack === false
|
|
50
|
-
? {}
|
|
51
|
-
: {
|
|
52
|
-
slack: {
|
|
53
|
-
name: slack?.name ?? names.slack,
|
|
54
|
-
...(slack?.parameters ? { parameters: slack.parameters } : {}),
|
|
55
|
-
},
|
|
56
|
-
}),
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Fill only the MCP name from `id`.
|
|
61
|
-
*
|
|
62
|
-
* `visibleToClient` gates Slack on `capability.slack != null` and CLI on
|
|
63
|
-
* `capability.cli != null`, so omitting a binding is how the catalog already
|
|
64
|
-
* says "not on that surface" — `defineCapability` just happens to set all
|
|
65
|
-
* three unconditionally. Staff admin verbs need the MCP one only: Slack's
|
|
66
|
-
* staff surface is a deliberately small, human-confirmed set, and `apps/cli`
|
|
67
|
-
* writes each command by hand, so a CLI binding here would advertise a
|
|
68
|
-
* command that does not exist.
|
|
69
|
-
*/
|
|
70
|
-
export function defineStaffMcpCapability(spec) {
|
|
71
|
-
return { ...spec, mcp: { name: namesFromId(spec.id).mcp } };
|
|
72
|
-
}
|
|
73
|
-
export function visibleToClient(capability, client, role) {
|
|
74
|
-
if (!capability.roles.includes(role))
|
|
75
|
-
return false;
|
|
76
|
-
if (client === "slack")
|
|
77
|
-
return capability.slack != null;
|
|
78
|
-
if (client === "cli") {
|
|
79
|
-
const help = capability.cli?.vnext;
|
|
80
|
-
if (!help || !capability.cli)
|
|
81
|
-
return false;
|
|
82
|
-
return help.audience === "customer" ? role === "user" : role === "admin";
|
|
83
|
-
}
|
|
84
|
-
return capability.mcp != null;
|
|
85
|
-
}
|
|
86
|
-
export function forRole(catalog, role, client) {
|
|
87
|
-
return catalog.filter((capability) => visibleToClient(capability, client, role));
|
|
88
|
-
}
|
|
89
|
-
export function byMcpName(catalog, name) {
|
|
90
|
-
return catalog.find((capability) => capability.mcp?.name === name);
|
|
91
|
-
}
|
|
92
|
-
export function bySlackName(catalog, name) {
|
|
93
|
-
return catalog.find((capability) => capability.slack?.name === name);
|
|
94
|
-
}
|
|
95
|
-
export function byCliCommand(catalog, command) {
|
|
96
|
-
return catalog.find((capability) => capability.cli != null &&
|
|
97
|
-
capability.cli.command.length === command.length &&
|
|
98
|
-
capability.cli.command.every((part, index) => part === command[index]));
|
|
99
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { adminCapabilities, bindAdminCapabilities } from "./capabilities/admin.js";
|
|
2
|
-
import { adminCapacityReservationCapabilities } from "./capabilities/admin-capacity-reservations.js";
|
|
3
|
-
import { commerceMarketCapabilities } from "./capabilities/commerce-market.js";
|
|
4
|
-
import { marketCapabilities } from "./capabilities/markets.js";
|
|
5
|
-
import { adminEnrollmentCapabilities, bindAdminEnrollmentCapabilities, } from "./capabilities/admin-enrollment.js";
|
|
6
|
-
import { adminNodeDiagnosticCapabilities } from "./capabilities/admin-node-diagnostics.js";
|
|
7
|
-
import { adminNodeLifecycleCapabilities } from "./capabilities/admin-nodes-lifecycle.js";
|
|
8
|
-
import { computeCapabilities } from "./capabilities/compute.js";
|
|
9
|
-
import { creditGrantCapability } from "./capabilities/credits.js";
|
|
10
|
-
import { cliShellCapabilities } from "./capabilities/cli.js";
|
|
11
|
-
import { clusterCliCapabilities, kubernetesCapabilities, slurmCapabilities, } from "./capabilities/clusters.js";
|
|
12
|
-
import { externalBucketCapabilities } from "./capabilities/external-buckets.js";
|
|
13
|
-
import { evidenceCapabilities } from "./capabilities/evidence.js";
|
|
14
|
-
import { fleetCapabilities } from "./capabilities/fleet.js";
|
|
15
|
-
import { tokenCapabilities } from "./capabilities/tokens.js";
|
|
16
|
-
import { mountCapabilities } from "./capabilities/mounts.js";
|
|
17
|
-
import { identityCapabilities } from "./capabilities/identity.js";
|
|
18
|
-
import { listingCapabilities } from "./capabilities/listings.js";
|
|
19
|
-
import { observabilityCapabilities } from "./capabilities/observability.js";
|
|
20
|
-
import { organizationInviteCapability } from "./capabilities/organization-invites.js";
|
|
21
|
-
import { networkCapabilities } from "./capabilities/networks.js";
|
|
22
|
-
import { reservationListCapability } from "./capabilities/reservation-list.js";
|
|
23
|
-
import { volumeCapabilities } from "./capabilities/volumes.js";
|
|
24
|
-
import { userCapabilities } from "./capabilities/users.js";
|
|
25
|
-
function canonicalCliCatalog(capabilities) {
|
|
26
|
-
return capabilities.map((capability) => {
|
|
27
|
-
const help = capability.cli?.vnext;
|
|
28
|
-
if (!help) {
|
|
29
|
-
const { cli: _retiredCliBinding, ...withoutCli } = capability;
|
|
30
|
-
return withoutCli;
|
|
31
|
-
}
|
|
32
|
-
return {
|
|
33
|
-
...capability,
|
|
34
|
-
cli: {
|
|
35
|
-
command: [...(help.command ?? capability.cli?.command ?? [])],
|
|
36
|
-
vnext: help,
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
/** Canonical operational catalog, without staff-only commerce or CRM modules. */
|
|
42
|
-
export const catalog = [
|
|
43
|
-
...canonicalCliCatalog([
|
|
44
|
-
...bindAdminEnrollmentCapabilities(bindAdminCapabilities([
|
|
45
|
-
...cliShellCapabilities,
|
|
46
|
-
...identityCapabilities,
|
|
47
|
-
...listingCapabilities.filter((capability) => capability.id !== "listings.create"),
|
|
48
|
-
...commerceMarketCapabilities,
|
|
49
|
-
...marketCapabilities,
|
|
50
|
-
...computeCapabilities,
|
|
51
|
-
...fleetCapabilities.filter((capability) => capability.id !== "node.exec"),
|
|
52
|
-
...networkCapabilities,
|
|
53
|
-
...clusterCliCapabilities,
|
|
54
|
-
...tokenCapabilities,
|
|
55
|
-
...userCapabilities,
|
|
56
|
-
...volumeCapabilities,
|
|
57
|
-
...mountCapabilities,
|
|
58
|
-
...externalBucketCapabilities,
|
|
59
|
-
...evidenceCapabilities,
|
|
60
|
-
...observabilityCapabilities,
|
|
61
|
-
...slurmCapabilities,
|
|
62
|
-
...kubernetesCapabilities,
|
|
63
|
-
...adminNodeLifecycleCapabilities,
|
|
64
|
-
])),
|
|
65
|
-
...adminCapabilities.filter((capability) => capability.id === "nodes.health"),
|
|
66
|
-
...adminCapacityReservationCapabilities,
|
|
67
|
-
reservationListCapability,
|
|
68
|
-
...adminNodeDiagnosticCapabilities,
|
|
69
|
-
...adminEnrollmentCapabilities,
|
|
70
|
-
organizationInviteCapability,
|
|
71
|
-
creditGrantCapability,
|
|
72
|
-
]),
|
|
73
|
-
];
|