@ornncompute/cli 0.2.9 → 0.2.10
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/package.json +1 -1
- package/vendor/capabilities/capabilities/listings.d.ts +5 -0
- package/vendor/capabilities/capabilities/listings.js +167 -5
- package/vendor/capabilities/capabilities/staff-access.d.ts +3 -1
- package/vendor/capabilities/capabilities/staff-access.js +100 -28
- package/vendor/capabilities/capabilities/staff-commerce.d.ts +91 -14
- package/vendor/capabilities/capabilities/staff-commerce.js +466 -67
- package/vendor/capabilities/capabilities/staff-fleet.d.ts +33 -27
- package/vendor/capabilities/capabilities/staff-fleet.js +143 -44
- package/vendor/capabilities/capabilities/staff-shared.d.ts +29 -0
- package/vendor/capabilities/capabilities/staff-shared.js +64 -0
- package/vendor/capabilities/index.d.ts +2 -2
- package/vendor/capabilities/index.js +2 -2
|
@@ -5,55 +5,50 @@ export declare const enrollmentTokenRevokeInput: z.ZodObject<{
|
|
|
5
5
|
}, z.core.$strip>;
|
|
6
6
|
export declare const enrollmentTokenRevokeCapability: import("../capability.ts").Capability<unknown, unknown>;
|
|
7
7
|
export declare const operatorCreateInput: z.ZodObject<{
|
|
8
|
-
slug: z.ZodString
|
|
9
|
-
displayName: z.ZodString
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
federated: "federated";
|
|
13
|
-
}>>;
|
|
14
|
-
status: z.ZodOptional<z.ZodEnum<{
|
|
15
|
-
active: "active";
|
|
16
|
-
unavailable: "unavailable";
|
|
17
|
-
revoked: "revoked";
|
|
18
|
-
}>>;
|
|
8
|
+
slug: z.ZodOptional<z.ZodString>;
|
|
9
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
10
|
+
display_name: z.ZodOptional<z.ZodString>;
|
|
11
|
+
name: z.ZodOptional<z.ZodString>;
|
|
19
12
|
confirm: z.ZodOptional<z.ZodBoolean>;
|
|
20
13
|
}, z.core.$strip>;
|
|
21
14
|
export declare const operatorCreateCapability: import("../capability.ts").Capability<unknown, unknown>;
|
|
22
15
|
export declare const operatorUpdateInput: z.ZodObject<{
|
|
23
|
-
operatorId: z.ZodString
|
|
16
|
+
operatorId: z.ZodOptional<z.ZodString>;
|
|
17
|
+
operator_id: z.ZodOptional<z.ZodString>;
|
|
24
18
|
displayName: z.ZodOptional<z.ZodString>;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
federated: "federated";
|
|
29
|
-
}>>;
|
|
30
|
-
status: z.ZodOptional<z.ZodEnum<{
|
|
31
|
-
active: "active";
|
|
32
|
-
unavailable: "unavailable";
|
|
33
|
-
revoked: "revoked";
|
|
34
|
-
}>>;
|
|
19
|
+
display_name: z.ZodOptional<z.ZodString>;
|
|
20
|
+
name: z.ZodOptional<z.ZodString>;
|
|
21
|
+
version: z.ZodOptional<z.ZodNumber>;
|
|
35
22
|
confirm: z.ZodOptional<z.ZodBoolean>;
|
|
36
23
|
}, z.core.$strip>;
|
|
37
24
|
export declare const operatorUpdateCapability: import("../capability.ts").Capability<unknown, unknown>;
|
|
38
25
|
export declare const operatorDeleteInput: z.ZodObject<{
|
|
39
|
-
operatorId: z.ZodString
|
|
26
|
+
operatorId: z.ZodOptional<z.ZodString>;
|
|
27
|
+
operator_id: z.ZodOptional<z.ZodString>;
|
|
40
28
|
confirm: z.ZodOptional<z.ZodBoolean>;
|
|
41
29
|
}, z.core.$strip>;
|
|
42
30
|
export declare const operatorDeleteCapability: import("../capability.ts").Capability<unknown, unknown>;
|
|
43
31
|
export declare const facilityCreateInput: z.ZodObject<{
|
|
44
|
-
operatorId: z.ZodString
|
|
45
|
-
|
|
46
|
-
|
|
32
|
+
operatorId: z.ZodOptional<z.ZodString>;
|
|
33
|
+
operator_id: z.ZodOptional<z.ZodString>;
|
|
34
|
+
slug: z.ZodOptional<z.ZodString>;
|
|
35
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
36
|
+
display_name: z.ZodOptional<z.ZodString>;
|
|
37
|
+
name: z.ZodOptional<z.ZodString>;
|
|
47
38
|
region: z.ZodString;
|
|
48
39
|
zone: z.ZodOptional<z.ZodString>;
|
|
49
40
|
confirm: z.ZodOptional<z.ZodBoolean>;
|
|
50
41
|
}, z.core.$strip>;
|
|
51
42
|
export declare const facilityCreateCapability: import("../capability.ts").Capability<unknown, unknown>;
|
|
52
43
|
export declare const facilityUpdateInput: z.ZodObject<{
|
|
53
|
-
facilityId: z.ZodString
|
|
44
|
+
facilityId: z.ZodOptional<z.ZodString>;
|
|
45
|
+
facility_id: z.ZodOptional<z.ZodString>;
|
|
54
46
|
displayName: z.ZodOptional<z.ZodString>;
|
|
47
|
+
display_name: z.ZodOptional<z.ZodString>;
|
|
48
|
+
name: z.ZodOptional<z.ZodString>;
|
|
55
49
|
region: z.ZodOptional<z.ZodString>;
|
|
56
50
|
zone: z.ZodOptional<z.ZodString>;
|
|
51
|
+
version: z.ZodOptional<z.ZodNumber>;
|
|
57
52
|
confirm: z.ZodOptional<z.ZodBoolean>;
|
|
58
53
|
}, z.core.$strip>;
|
|
59
54
|
export declare const facilityUpdateCapability: import("../capability.ts").Capability<unknown, unknown>;
|
|
@@ -100,6 +95,8 @@ export declare const nodeBenchmarkCapability: import("../capability.ts").Capabil
|
|
|
100
95
|
export declare const nodeDeployInput: z.ZodObject<{
|
|
101
96
|
nodeId: z.ZodString;
|
|
102
97
|
targetTenantId: z.ZodString;
|
|
98
|
+
commerceReservationId: z.ZodOptional<z.ZodString>;
|
|
99
|
+
commerce_reservation_id: z.ZodOptional<z.ZodString>;
|
|
103
100
|
targetAuthUserId: z.ZodOptional<z.ZodString>;
|
|
104
101
|
networkMode: z.ZodOptional<z.ZodEnum<{
|
|
105
102
|
public: "public";
|
|
@@ -131,4 +128,13 @@ export declare const nodeAdminKeyInput: z.ZodObject<{
|
|
|
131
128
|
confirm: z.ZodOptional<z.ZodBoolean>;
|
|
132
129
|
}, z.core.$strip>;
|
|
133
130
|
export declare const nodeAdminKeyCapability: import("../capability.ts").Capability<unknown, unknown>;
|
|
131
|
+
export declare const nodeOperatorTransferInput: z.ZodObject<{
|
|
132
|
+
nodeId: z.ZodString;
|
|
133
|
+
operatorId: z.ZodString;
|
|
134
|
+
operatorSlug: z.ZodString;
|
|
135
|
+
facilityId: z.ZodOptional<z.ZodString>;
|
|
136
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
137
|
+
confirm: z.ZodOptional<z.ZodBoolean>;
|
|
138
|
+
}, z.core.$strip>;
|
|
139
|
+
export declare const nodeOperatorTransferCapability: import("../capability.ts").Capability<unknown, unknown>;
|
|
134
140
|
export declare const staffFleetCapabilities: import("../capability.ts").Capability<unknown, unknown>[];
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { defineStaffMcpCapability, preview } from "../capability.js";
|
|
3
|
-
import { mapBody, seg } from "./staff-shared.js";
|
|
3
|
+
import { mapBody, resolveVersion, seg } from "./staff-shared.js";
|
|
4
4
|
// Staff fleet verbs: operators, facilities, nodes, node jobs, and enrollment
|
|
5
5
|
// token revocation. MCP-only — see `defineStaffMcpCapability`.
|
|
6
6
|
const slugSchema = z
|
|
7
7
|
.string()
|
|
8
8
|
.regex(/^[a-z0-9][a-z0-9-]*$/, "slug must be lowercase alphanumeric with dashes")
|
|
9
9
|
.max(80);
|
|
10
|
-
const operatorModeSchema = z.enum(["managed", "federated"]);
|
|
11
|
-
const operatorStatusSchema = z.enum(["active", "unavailable", "revoked"]);
|
|
12
10
|
export const enrollmentTokenRevokeInput = z.object({
|
|
13
11
|
tokenId: z.string(),
|
|
14
12
|
confirm: z.boolean().optional(),
|
|
@@ -28,27 +26,34 @@ export const enrollmentTokenRevokeCapability = defineStaffMcpCapability({
|
|
|
28
26
|
return ctx.fetch(`/enrollment/tokens/${seg(parsed.tokenId)}/revoke`, { method: "POST" });
|
|
29
27
|
},
|
|
30
28
|
});
|
|
31
|
-
export const operatorCreateInput = z
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
export const operatorCreateInput = z
|
|
30
|
+
.object({
|
|
31
|
+
slug: z.string().optional(),
|
|
32
|
+
displayName: z.string().min(1).max(160).optional(),
|
|
33
|
+
display_name: z.string().min(1).max(160).optional(),
|
|
34
|
+
name: z.string().min(1).max(160).optional(),
|
|
36
35
|
confirm: z.boolean().optional(),
|
|
36
|
+
})
|
|
37
|
+
.refine((data) => Boolean(data.displayName || data.display_name || data.name), {
|
|
38
|
+
message: "displayName is required",
|
|
39
|
+
path: ["displayName"],
|
|
37
40
|
});
|
|
38
41
|
export const operatorCreateCapability = defineStaffMcpCapability({
|
|
39
42
|
id: "operator.create",
|
|
40
43
|
domain: "fleet",
|
|
41
44
|
roles: ["admin"],
|
|
42
|
-
description: "Internal staff only: create an operator
|
|
45
|
+
description: "Internal staff only: create an operator. Requires confirm: true. Does not touch any hardware.",
|
|
43
46
|
mutation: "preview-confirm",
|
|
44
47
|
http: { method: "POST", path: "/provisioning/operators" },
|
|
45
48
|
input: operatorCreateInput,
|
|
46
49
|
execute: async (ctx, input) => {
|
|
47
50
|
const parsed = operatorCreateInput.parse(input);
|
|
51
|
+
const displayName = (parsed.displayName || parsed.display_name || parsed.name).trim();
|
|
52
|
+
const rawSlug = parsed.slug ? parsed.slug.trim() : displayName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
53
|
+
const slug = rawSlug.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
48
54
|
const body = {
|
|
49
|
-
slug:
|
|
50
|
-
display_name:
|
|
51
|
-
...mapBody(parsed, { mode: "mode", status: "status" }),
|
|
55
|
+
slug: slug || "operator-" + Date.now(),
|
|
56
|
+
display_name: displayName,
|
|
52
57
|
};
|
|
53
58
|
if (!ctx.confirmed)
|
|
54
59
|
return preview("operator.create", body);
|
|
@@ -56,63 +61,91 @@ export const operatorCreateCapability = defineStaffMcpCapability({
|
|
|
56
61
|
},
|
|
57
62
|
});
|
|
58
63
|
export const operatorUpdateInput = z.object({
|
|
59
|
-
operatorId: z.string(),
|
|
64
|
+
operatorId: z.string().optional(),
|
|
65
|
+
operator_id: z.string().optional(),
|
|
60
66
|
displayName: z.string().min(1).max(160).optional(),
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
67
|
+
display_name: z.string().min(1).max(160).optional(),
|
|
68
|
+
name: z.string().min(1).max(160).optional(),
|
|
69
|
+
version: z.number().int().positive().optional(),
|
|
64
70
|
confirm: z.boolean().optional(),
|
|
65
71
|
});
|
|
66
72
|
export const operatorUpdateCapability = defineStaffMcpCapability({
|
|
67
73
|
id: "operator.update",
|
|
68
74
|
domain: "fleet",
|
|
69
75
|
roles: ["admin"],
|
|
70
|
-
description: "Internal staff only:
|
|
76
|
+
description: "Internal staff only: rename an operator. Display name is the only field commerce can patch; slug, mode, and status are fixed at creation. Requires confirm: true.",
|
|
71
77
|
mutation: "preview-confirm",
|
|
72
78
|
http: { method: "PATCH", path: "/provisioning/operators/{operatorId}" },
|
|
73
79
|
input: operatorUpdateInput,
|
|
74
80
|
execute: async (ctx, input) => {
|
|
75
81
|
const parsed = operatorUpdateInput.parse(input);
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
const operatorId = parsed.operatorId || parsed.operator_id;
|
|
83
|
+
if (!operatorId) {
|
|
84
|
+
throw new Error("operatorId is required");
|
|
85
|
+
}
|
|
86
|
+
const displayName = parsed.displayName || parsed.display_name || parsed.name;
|
|
87
|
+
if (!displayName) {
|
|
88
|
+
throw new Error("displayName is required; it is the only operator field commerce can patch.");
|
|
89
|
+
}
|
|
90
|
+
const body = {
|
|
91
|
+
display_name: displayName,
|
|
92
|
+
version: await resolveVersion(ctx, `/provisioning/operators/${seg(operatorId)}`, parsed.version),
|
|
93
|
+
};
|
|
82
94
|
if (!ctx.confirmed)
|
|
83
95
|
return preview("operator.update", body);
|
|
84
|
-
return ctx.fetch(`/provisioning/operators/${seg(
|
|
96
|
+
return ctx.fetch(`/provisioning/operators/${seg(operatorId)}`, {
|
|
85
97
|
method: "PATCH",
|
|
86
98
|
body,
|
|
87
99
|
});
|
|
88
100
|
},
|
|
89
101
|
});
|
|
90
102
|
export const operatorDeleteInput = z.object({
|
|
91
|
-
operatorId: z.string(),
|
|
103
|
+
operatorId: z.string().optional(),
|
|
104
|
+
operator_id: z.string().optional(),
|
|
92
105
|
confirm: z.boolean().optional(),
|
|
93
106
|
});
|
|
94
107
|
export const operatorDeleteCapability = defineStaffMcpCapability({
|
|
95
108
|
id: "operator.delete",
|
|
96
109
|
domain: "fleet",
|
|
97
110
|
roles: ["admin"],
|
|
98
|
-
description: "Internal staff only: delete an operator
|
|
111
|
+
description: "Internal staff only: delete an operator and cascade-delete every facility attached to it. " +
|
|
112
|
+
"Refuses while any listing still references the operator. Requires confirm: true.",
|
|
99
113
|
mutation: "preview-confirm",
|
|
100
114
|
http: { method: "DELETE", path: "/provisioning/operators/{operatorId}" },
|
|
101
115
|
input: operatorDeleteInput,
|
|
102
116
|
execute: async (ctx, input) => {
|
|
103
117
|
const parsed = operatorDeleteInput.parse(input);
|
|
118
|
+
const operatorId = parsed.operatorId || parsed.operator_id;
|
|
119
|
+
if (!operatorId) {
|
|
120
|
+
throw new Error("operatorId is required");
|
|
121
|
+
}
|
|
104
122
|
if (!ctx.confirmed)
|
|
105
|
-
return preview("operator.delete", { operatorId
|
|
106
|
-
|
|
123
|
+
return preview("operator.delete", { operatorId });
|
|
124
|
+
const result = await ctx.fetch(`/provisioning/operators/${seg(operatorId)}`, {
|
|
125
|
+
method: "DELETE",
|
|
126
|
+
});
|
|
127
|
+
return result ?? { deleted: true, operatorId };
|
|
107
128
|
},
|
|
108
129
|
});
|
|
109
|
-
export const facilityCreateInput = z
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
130
|
+
export const facilityCreateInput = z
|
|
131
|
+
.object({
|
|
132
|
+
operatorId: z.string().optional(),
|
|
133
|
+
operator_id: z.string().optional(),
|
|
134
|
+
slug: z.string().optional(),
|
|
135
|
+
displayName: z.string().min(1).max(160).optional(),
|
|
136
|
+
display_name: z.string().min(1).max(160).optional(),
|
|
137
|
+
name: z.string().min(1).max(160).optional(),
|
|
113
138
|
region: z.string().min(1).max(120),
|
|
114
139
|
zone: z.string().max(120).optional(),
|
|
115
140
|
confirm: z.boolean().optional(),
|
|
141
|
+
})
|
|
142
|
+
.refine((data) => Boolean(data.operatorId || data.operator_id), {
|
|
143
|
+
message: "operatorId is required",
|
|
144
|
+
path: ["operatorId"],
|
|
145
|
+
})
|
|
146
|
+
.refine((data) => Boolean(data.displayName || data.display_name || data.name), {
|
|
147
|
+
message: "displayName is required",
|
|
148
|
+
path: ["displayName"],
|
|
116
149
|
});
|
|
117
150
|
export const facilityCreateCapability = defineStaffMcpCapability({
|
|
118
151
|
id: "facility.create",
|
|
@@ -124,10 +157,14 @@ export const facilityCreateCapability = defineStaffMcpCapability({
|
|
|
124
157
|
input: facilityCreateInput,
|
|
125
158
|
execute: async (ctx, input) => {
|
|
126
159
|
const parsed = facilityCreateInput.parse(input);
|
|
160
|
+
const operatorId = (parsed.operatorId || parsed.operator_id);
|
|
161
|
+
const displayName = (parsed.displayName || parsed.display_name || parsed.name).trim();
|
|
162
|
+
const rawSlug = parsed.slug ? parsed.slug.trim() : displayName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
163
|
+
const slug = rawSlug.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
127
164
|
const body = {
|
|
128
|
-
operator_id:
|
|
129
|
-
slug:
|
|
130
|
-
display_name:
|
|
165
|
+
operator_id: operatorId,
|
|
166
|
+
slug: slug || "facility-" + Date.now(),
|
|
167
|
+
display_name: displayName,
|
|
131
168
|
region: parsed.region,
|
|
132
169
|
zone: parsed.zone ?? null,
|
|
133
170
|
};
|
|
@@ -137,10 +174,14 @@ export const facilityCreateCapability = defineStaffMcpCapability({
|
|
|
137
174
|
},
|
|
138
175
|
});
|
|
139
176
|
export const facilityUpdateInput = z.object({
|
|
140
|
-
facilityId: z.string(),
|
|
177
|
+
facilityId: z.string().optional(),
|
|
178
|
+
facility_id: z.string().optional(),
|
|
141
179
|
displayName: z.string().min(1).max(160).optional(),
|
|
180
|
+
display_name: z.string().min(1).max(160).optional(),
|
|
181
|
+
name: z.string().min(1).max(160).optional(),
|
|
142
182
|
region: z.string().min(1).max(120).optional(),
|
|
143
183
|
zone: z.string().max(120).optional(),
|
|
184
|
+
version: z.number().int().positive().optional(),
|
|
144
185
|
confirm: z.boolean().optional(),
|
|
145
186
|
});
|
|
146
187
|
export const facilityUpdateCapability = defineStaffMcpCapability({
|
|
@@ -153,15 +194,22 @@ export const facilityUpdateCapability = defineStaffMcpCapability({
|
|
|
153
194
|
input: facilityUpdateInput,
|
|
154
195
|
execute: async (ctx, input) => {
|
|
155
196
|
const parsed = facilityUpdateInput.parse(input);
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
197
|
+
const facilityId = parsed.facilityId || parsed.facility_id;
|
|
198
|
+
if (!facilityId) {
|
|
199
|
+
throw new Error("facilityId is required");
|
|
200
|
+
}
|
|
201
|
+
const displayName = parsed.displayName || parsed.display_name || parsed.name;
|
|
202
|
+
const body = {
|
|
203
|
+
...(displayName ? { display_name: displayName } : {}),
|
|
204
|
+
...mapBody(parsed, {
|
|
205
|
+
region: "region",
|
|
206
|
+
zone: "zone",
|
|
207
|
+
}),
|
|
208
|
+
version: await resolveVersion(ctx, `/provisioning/facilities/${seg(facilityId)}`, parsed.version),
|
|
209
|
+
};
|
|
162
210
|
if (!ctx.confirmed)
|
|
163
211
|
return preview("facility.update", body);
|
|
164
|
-
return ctx.fetch(`/provisioning/facilities/${seg(
|
|
212
|
+
return ctx.fetch(`/provisioning/facilities/${seg(facilityId)}`, {
|
|
165
213
|
method: "PATCH",
|
|
166
214
|
body,
|
|
167
215
|
});
|
|
@@ -266,7 +314,18 @@ export const nodeTestTriggerCapability = defineStaffMcpCapability({
|
|
|
266
314
|
};
|
|
267
315
|
if (!ctx.confirmed)
|
|
268
316
|
return preview("node.test-trigger", body);
|
|
269
|
-
|
|
317
|
+
try {
|
|
318
|
+
return await ctx.fetch("/jobs", { method: "POST", body });
|
|
319
|
+
}
|
|
320
|
+
catch (err) {
|
|
321
|
+
const errorObj = err;
|
|
322
|
+
if (errorObj?.status === 409 || errorObj?.message?.includes("409")) {
|
|
323
|
+
const detail = errorObj.detail ||
|
|
324
|
+
"Node is busy: a test or benchmark job is already running on this node.";
|
|
325
|
+
throw new Error(detail);
|
|
326
|
+
}
|
|
327
|
+
throw err;
|
|
328
|
+
}
|
|
270
329
|
},
|
|
271
330
|
});
|
|
272
331
|
export const nodeTestResultInput = z.object({
|
|
@@ -304,6 +363,8 @@ export const nodeBenchmarkCapability = defineStaffMcpCapability({
|
|
|
304
363
|
export const nodeDeployInput = z.object({
|
|
305
364
|
nodeId: z.string(),
|
|
306
365
|
targetTenantId: z.string(),
|
|
366
|
+
commerceReservationId: z.string().optional(),
|
|
367
|
+
commerce_reservation_id: z.string().optional(),
|
|
307
368
|
targetAuthUserId: z.string().optional(),
|
|
308
369
|
networkMode: z.enum(["public", "private"]).optional(),
|
|
309
370
|
notes: z.string().max(2000).optional(),
|
|
@@ -319,8 +380,10 @@ export const nodeDeployCapability = defineStaffMcpCapability({
|
|
|
319
380
|
input: nodeDeployInput,
|
|
320
381
|
execute: async (ctx, input) => {
|
|
321
382
|
const parsed = nodeDeployInput.parse(input);
|
|
383
|
+
const reservationId = parsed.commerceReservationId ?? parsed.commerce_reservation_id;
|
|
322
384
|
const body = {
|
|
323
385
|
target_tenant_id: parsed.targetTenantId,
|
|
386
|
+
...(reservationId ? { commerce_reservation_id: reservationId } : {}),
|
|
324
387
|
...mapBody(parsed, {
|
|
325
388
|
targetAuthUserId: "target_auth_user_id",
|
|
326
389
|
networkMode: "network_mode",
|
|
@@ -419,6 +482,41 @@ export const nodeAdminKeyCapability = defineStaffMcpCapability({
|
|
|
419
482
|
});
|
|
420
483
|
},
|
|
421
484
|
});
|
|
485
|
+
export const nodeOperatorTransferInput = z.object({
|
|
486
|
+
nodeId: z.string(),
|
|
487
|
+
operatorId: z.string(),
|
|
488
|
+
operatorSlug: z.string(),
|
|
489
|
+
facilityId: z.string().optional(),
|
|
490
|
+
reason: z.string().optional(),
|
|
491
|
+
confirm: z.boolean().optional(),
|
|
492
|
+
});
|
|
493
|
+
export const nodeOperatorTransferCapability = defineStaffMcpCapability({
|
|
494
|
+
id: "node.operator-transfer",
|
|
495
|
+
domain: "fleet",
|
|
496
|
+
roles: ["admin"],
|
|
497
|
+
description: "Internal staff only: transfer a node's ownership to a different operator/facility in Orchestrator. Requires confirm: true.",
|
|
498
|
+
mutation: "preview-confirm",
|
|
499
|
+
http: { method: "POST", path: "/internal/nodes/{nodeId}/transfer" },
|
|
500
|
+
input: nodeOperatorTransferInput,
|
|
501
|
+
execute: async (ctx, input) => {
|
|
502
|
+
const parsed = nodeOperatorTransferInput.parse(input);
|
|
503
|
+
const body = {
|
|
504
|
+
operator_id: parsed.operatorId,
|
|
505
|
+
operator_slug: parsed.operatorSlug,
|
|
506
|
+
...mapBody(parsed, {
|
|
507
|
+
facilityId: "facility_id",
|
|
508
|
+
reason: "reason",
|
|
509
|
+
}),
|
|
510
|
+
};
|
|
511
|
+
if (!ctx.confirmed) {
|
|
512
|
+
return preview("node.operator-transfer", { nodeId: parsed.nodeId, ...body });
|
|
513
|
+
}
|
|
514
|
+
return ctx.fetch(`/internal/nodes/${seg(parsed.nodeId)}/transfer`, {
|
|
515
|
+
method: "POST",
|
|
516
|
+
body,
|
|
517
|
+
});
|
|
518
|
+
},
|
|
519
|
+
});
|
|
422
520
|
export const staffFleetCapabilities = [
|
|
423
521
|
enrollmentTokenRevokeCapability,
|
|
424
522
|
operatorCreateCapability,
|
|
@@ -436,4 +534,5 @@ export const staffFleetCapabilities = [
|
|
|
436
534
|
nodeRebootCapability,
|
|
437
535
|
nodeHardResetCapability,
|
|
438
536
|
nodeAdminKeyCapability,
|
|
537
|
+
nodeOperatorTransferCapability,
|
|
439
538
|
];
|
|
@@ -16,3 +16,32 @@ export declare function seg(value: string): string;
|
|
|
16
16
|
* `WebApiError`, say), so read the status structurally.
|
|
17
17
|
*/
|
|
18
18
|
export declare function statusOf(error: unknown): number | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Read a resource's current optimistic-concurrency version.
|
|
21
|
+
*
|
|
22
|
+
* Commerce rejects a PATCH or lifecycle action whose `version` is absent or
|
|
23
|
+
* non-positive ("missing version" / "version must be positive"), but no staff
|
|
24
|
+
* caller has that number to hand. Read it back when it was not supplied, and
|
|
25
|
+
* only once confirmed so a preview stays a pure dry run.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveVersion(ctx: {
|
|
28
|
+
fetch: (path: string, init: {
|
|
29
|
+
method: string;
|
|
30
|
+
}) => Promise<unknown>;
|
|
31
|
+
confirmed?: boolean;
|
|
32
|
+
}, path: string, provided?: number): Promise<number>;
|
|
33
|
+
/**
|
|
34
|
+
* Require a commerce identifier, named by this tool's own parameter.
|
|
35
|
+
*
|
|
36
|
+
* A malformed UUID never reaches a commerce handler's validation: Go fails the
|
|
37
|
+
* JSON decode first and answers with a bare "invalid request body" that names
|
|
38
|
+
* no field at all.
|
|
39
|
+
*/
|
|
40
|
+
export declare function requireUuid(value: string | undefined, field: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* The human-readable text a transport failure carries, wherever it put it.
|
|
43
|
+
*
|
|
44
|
+
* Mirrors how the MCP surface renders an error so a capability can rewrite
|
|
45
|
+
* that same string before it reaches the caller.
|
|
46
|
+
*/
|
|
47
|
+
export declare function errorTextOf(error: unknown): string;
|
|
@@ -32,3 +32,67 @@ export function statusOf(error) {
|
|
|
32
32
|
}
|
|
33
33
|
return undefined;
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Read a resource's current optimistic-concurrency version.
|
|
37
|
+
*
|
|
38
|
+
* Commerce rejects a PATCH or lifecycle action whose `version` is absent or
|
|
39
|
+
* non-positive ("missing version" / "version must be positive"), but no staff
|
|
40
|
+
* caller has that number to hand. Read it back when it was not supplied, and
|
|
41
|
+
* only once confirmed so a preview stays a pure dry run.
|
|
42
|
+
*/
|
|
43
|
+
export async function resolveVersion(ctx, path, provided) {
|
|
44
|
+
if (provided && provided > 0)
|
|
45
|
+
return provided;
|
|
46
|
+
if (!ctx.confirmed)
|
|
47
|
+
return 1;
|
|
48
|
+
try {
|
|
49
|
+
const current = (await ctx.fetch(path, { method: "GET" }));
|
|
50
|
+
if (typeof current?.version === "number" && current.version > 0)
|
|
51
|
+
return current.version;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Fall through: send 1 and let commerce report the conflict, which names
|
|
55
|
+
// the expected version, rather than failing on a lookup the caller can't see.
|
|
56
|
+
}
|
|
57
|
+
return 1;
|
|
58
|
+
}
|
|
59
|
+
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
60
|
+
/**
|
|
61
|
+
* Require a commerce identifier, named by this tool's own parameter.
|
|
62
|
+
*
|
|
63
|
+
* A malformed UUID never reaches a commerce handler's validation: Go fails the
|
|
64
|
+
* JSON decode first and answers with a bare "invalid request body" that names
|
|
65
|
+
* no field at all.
|
|
66
|
+
*/
|
|
67
|
+
export function requireUuid(value, field) {
|
|
68
|
+
const trimmed = (value ?? "").trim();
|
|
69
|
+
if (!trimmed)
|
|
70
|
+
throw new Error(`${field} is required.`);
|
|
71
|
+
if (!UUID_PATTERN.test(trimmed)) {
|
|
72
|
+
throw new Error(`${field} must be a UUID; received ${JSON.stringify(trimmed)}.`);
|
|
73
|
+
}
|
|
74
|
+
return trimmed;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The human-readable text a transport failure carries, wherever it put it.
|
|
78
|
+
*
|
|
79
|
+
* Mirrors how the MCP surface renders an error so a capability can rewrite
|
|
80
|
+
* that same string before it reaches the caller.
|
|
81
|
+
*/
|
|
82
|
+
export function errorTextOf(error) {
|
|
83
|
+
if (error && typeof error === "object" && "detail" in error) {
|
|
84
|
+
const detail = error.detail;
|
|
85
|
+
if (typeof detail === "string" && detail)
|
|
86
|
+
return detail;
|
|
87
|
+
if (detail && typeof detail === "object") {
|
|
88
|
+
for (const key of ["summary", "message", "error", "reason"]) {
|
|
89
|
+
const value = detail[key];
|
|
90
|
+
if (typeof value === "string" && value)
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (error instanceof Error)
|
|
96
|
+
return error.message;
|
|
97
|
+
return String(error);
|
|
98
|
+
}
|
|
@@ -8,8 +8,8 @@ export { createListingCapability, listingCreateInput, listCatalogTermsCapability
|
|
|
8
8
|
export { userCapabilities, usersQueryCapability } from "./capabilities/users.ts";
|
|
9
9
|
export { kubernetesCapabilities, slurmCapabilities } from "./capabilities/clusters.ts";
|
|
10
10
|
export { logsLatestCapability, logsTailCapability, observabilityCapabilities, telemetryLatestCapability, telemetryTailCapability, } from "./capabilities/observability.ts";
|
|
11
|
-
export { enrollmentTokenRevokeCapability, enrollmentTokenRevokeInput, facilityCreateCapability, facilityCreateInput, facilityUpdateCapability, facilityUpdateInput, nodeAdminKeyCapability, nodeAdminKeyInput, nodeBenchmarkCapability, nodeBenchmarkInput, nodeDeployCapability, nodeDeployInput, nodeDetailsUpdateCapability, nodeDetailsUpdateInput, nodeHardResetCapability, nodeHardResetInput, nodeRebootCapability, nodeRebootInput, nodeShowCapability, nodeShowInput, nodeTestResultCapability, nodeTestResultInput, nodeTestTriggerCapability, nodeTestTriggerInput, nodeUpdateCapability, nodeUpdateInput, operatorCreateCapability, operatorCreateInput, operatorDeleteCapability, operatorDeleteInput, operatorUpdateCapability, operatorUpdateInput, staffFleetCapabilities, } from "./capabilities/staff-fleet.ts";
|
|
12
|
-
export { bidAcceptCapability, bidAcceptInput, bidRejectCapability, bidRejectInput, inventoryUpdateCapability, inventoryUpdateInput, reservationCancelCapability, reservationCancelInput, reservationMachinesListCapability, reservationMachinesListInput, reservationPublishCapability, reservationPublishInput, reservationSshKeyAddCapability, reservationSshKeyAddInput, reservationSshKeyRemoveCapability, reservationSshKeyRemoveInput, reservationTransferCapability, reservationTransferInput, staffCommerceCapabilities, tenantCreditProfileShowCapability, tenantCreditProfileShowInput, } from "./capabilities/staff-commerce.ts";
|
|
11
|
+
export { enrollmentTokenRevokeCapability, enrollmentTokenRevokeInput, facilityCreateCapability, facilityCreateInput, facilityUpdateCapability, facilityUpdateInput, nodeAdminKeyCapability, nodeAdminKeyInput, nodeBenchmarkCapability, nodeBenchmarkInput, nodeDeployCapability, nodeDeployInput, nodeDetailsUpdateCapability, nodeDetailsUpdateInput, nodeHardResetCapability, nodeHardResetInput, nodeOperatorTransferCapability, nodeOperatorTransferInput, nodeRebootCapability, nodeRebootInput, nodeShowCapability, nodeShowInput, nodeTestResultCapability, nodeTestResultInput, nodeTestTriggerCapability, nodeTestTriggerInput, nodeUpdateCapability, nodeUpdateInput, operatorCreateCapability, operatorCreateInput, operatorDeleteCapability, operatorDeleteInput, operatorUpdateCapability, operatorUpdateInput, staffFleetCapabilities, } from "./capabilities/staff-fleet.ts";
|
|
12
|
+
export { bidShowCapability, bidShowInput, bidAcceptCapability, bidAcceptInput, bidRejectCapability, bidRejectInput, billingInvoicesListCapability, billingInvoicesListInput, inventoryDelistCapability, inventoryDelistInput, inventoryUpdateCapability, inventoryUpdateInput, reservationActivateCapability, reservationActivateInput, reservationCancelCapability, reservationCancelInput, reservationCompleteCapability, reservationCompleteInput, reservationDraftCreateCapability, reservationDraftCreateInput, reservationListCapability, reservationListInput, reservationMachinesListCapability, reservationMachinesListInput, reservationPublishCapability, reservationPublishInput, reservationShowCapability, reservationShowInput, reservationSshKeyAddCapability, reservationSshKeyAddInput, reservationSshKeyRemoveCapability, reservationSshKeyRemoveInput, reservationTransferCapability, reservationTransferInput, reservationUpdateCapability, reservationUpdateInput, staffCommerceCapabilities, tenantCreditProfileShowCapability, tenantCreditProfileShowInput, } from "./capabilities/staff-commerce.ts";
|
|
13
13
|
export { sshKeyAddCapability, sshKeyAddInput, sshKeyPushCapability, sshKeyPushInput, sshKeyRevokeCapability, sshKeyRevokeInput, staffAccessCapabilities, } from "./capabilities/staff-access.ts";
|
|
14
14
|
export { CLIENTS, parseRole, roleAtLeast, ROLES, type ClientKind, type Role } from "./role.ts";
|
|
15
15
|
export { bindHardwareFields, HARDWARE_CATALOG_PATH, HARDWARE_KINDS, HARDWARE_LISTING_FIELDS, HARDWARE_LISTING_FILTERS, loadHardwareCatalog, looksLikeSpecDump, normalizeCatalogQuery, parseHardwareCatalog, projectCatalogTerms, proposeListingPayload, resolveCatalogTerm, UNRESOLVED_CATALOG_HINT, type CatalogBindResult, type CatalogTerm, type HardwareCatalog, type HardwareKind, type ResolvedCatalogTerm, } from "./spec-catalog.ts";
|
|
@@ -8,8 +8,8 @@ export { createListingCapability, listingCreateInput, listCatalogTermsCapability
|
|
|
8
8
|
export { userCapabilities, usersQueryCapability } from "./capabilities/users.js";
|
|
9
9
|
export { kubernetesCapabilities, slurmCapabilities } from "./capabilities/clusters.js";
|
|
10
10
|
export { logsLatestCapability, logsTailCapability, observabilityCapabilities, telemetryLatestCapability, telemetryTailCapability, } from "./capabilities/observability.js";
|
|
11
|
-
export { enrollmentTokenRevokeCapability, enrollmentTokenRevokeInput, facilityCreateCapability, facilityCreateInput, facilityUpdateCapability, facilityUpdateInput, nodeAdminKeyCapability, nodeAdminKeyInput, nodeBenchmarkCapability, nodeBenchmarkInput, nodeDeployCapability, nodeDeployInput, nodeDetailsUpdateCapability, nodeDetailsUpdateInput, nodeHardResetCapability, nodeHardResetInput, nodeRebootCapability, nodeRebootInput, nodeShowCapability, nodeShowInput, nodeTestResultCapability, nodeTestResultInput, nodeTestTriggerCapability, nodeTestTriggerInput, nodeUpdateCapability, nodeUpdateInput, operatorCreateCapability, operatorCreateInput, operatorDeleteCapability, operatorDeleteInput, operatorUpdateCapability, operatorUpdateInput, staffFleetCapabilities, } from "./capabilities/staff-fleet.js";
|
|
12
|
-
export { bidAcceptCapability, bidAcceptInput, bidRejectCapability, bidRejectInput, inventoryUpdateCapability, inventoryUpdateInput, reservationCancelCapability, reservationCancelInput, reservationMachinesListCapability, reservationMachinesListInput, reservationPublishCapability, reservationPublishInput, reservationSshKeyAddCapability, reservationSshKeyAddInput, reservationSshKeyRemoveCapability, reservationSshKeyRemoveInput, reservationTransferCapability, reservationTransferInput, staffCommerceCapabilities, tenantCreditProfileShowCapability, tenantCreditProfileShowInput, } from "./capabilities/staff-commerce.js";
|
|
11
|
+
export { enrollmentTokenRevokeCapability, enrollmentTokenRevokeInput, facilityCreateCapability, facilityCreateInput, facilityUpdateCapability, facilityUpdateInput, nodeAdminKeyCapability, nodeAdminKeyInput, nodeBenchmarkCapability, nodeBenchmarkInput, nodeDeployCapability, nodeDeployInput, nodeDetailsUpdateCapability, nodeDetailsUpdateInput, nodeHardResetCapability, nodeHardResetInput, nodeOperatorTransferCapability, nodeOperatorTransferInput, nodeRebootCapability, nodeRebootInput, nodeShowCapability, nodeShowInput, nodeTestResultCapability, nodeTestResultInput, nodeTestTriggerCapability, nodeTestTriggerInput, nodeUpdateCapability, nodeUpdateInput, operatorCreateCapability, operatorCreateInput, operatorDeleteCapability, operatorDeleteInput, operatorUpdateCapability, operatorUpdateInput, staffFleetCapabilities, } from "./capabilities/staff-fleet.js";
|
|
12
|
+
export { bidShowCapability, bidShowInput, bidAcceptCapability, bidAcceptInput, bidRejectCapability, bidRejectInput, billingInvoicesListCapability, billingInvoicesListInput, inventoryDelistCapability, inventoryDelistInput, inventoryUpdateCapability, inventoryUpdateInput, reservationActivateCapability, reservationActivateInput, reservationCancelCapability, reservationCancelInput, reservationCompleteCapability, reservationCompleteInput, reservationDraftCreateCapability, reservationDraftCreateInput, reservationListCapability, reservationListInput, reservationMachinesListCapability, reservationMachinesListInput, reservationPublishCapability, reservationPublishInput, reservationShowCapability, reservationShowInput, reservationSshKeyAddCapability, reservationSshKeyAddInput, reservationSshKeyRemoveCapability, reservationSshKeyRemoveInput, reservationTransferCapability, reservationTransferInput, reservationUpdateCapability, reservationUpdateInput, staffCommerceCapabilities, tenantCreditProfileShowCapability, tenantCreditProfileShowInput, } from "./capabilities/staff-commerce.js";
|
|
13
13
|
export { sshKeyAddCapability, sshKeyAddInput, sshKeyPushCapability, sshKeyPushInput, sshKeyRevokeCapability, sshKeyRevokeInput, staffAccessCapabilities, } from "./capabilities/staff-access.js";
|
|
14
14
|
export { CLIENTS, parseRole, roleAtLeast, ROLES } from "./role.js";
|
|
15
15
|
export { bindHardwareFields, HARDWARE_CATALOG_PATH, HARDWARE_KINDS, HARDWARE_LISTING_FIELDS, HARDWARE_LISTING_FILTERS, loadHardwareCatalog, looksLikeSpecDump, normalizeCatalogQuery, parseHardwareCatalog, projectCatalogTerms, proposeListingPayload, resolveCatalogTerm, UNRESOLVED_CATALOG_HINT, } from "./spec-catalog.js";
|