@ornncompute/cli 0.2.8 → 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 -34
- package/vendor/capabilities/capabilities/staff-fleet.js +143 -70
- 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>;
|
|
@@ -79,13 +74,6 @@ export declare const nodeDetailsUpdateInput: z.ZodObject<{
|
|
|
79
74
|
confirm: z.ZodOptional<z.ZodBoolean>;
|
|
80
75
|
}, z.core.$strip>;
|
|
81
76
|
export declare const nodeDetailsUpdateCapability: import("../capability.ts").Capability<unknown, unknown>;
|
|
82
|
-
export declare const nodeReserveListingInput: z.ZodObject<{
|
|
83
|
-
nodeId: z.ZodString;
|
|
84
|
-
availableFrom: z.ZodOptional<z.ZodString>;
|
|
85
|
-
availableTo: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
86
|
-
confirm: z.ZodOptional<z.ZodBoolean>;
|
|
87
|
-
}, z.core.$strip>;
|
|
88
|
-
export declare const nodeReserveListingCapability: import("../capability.ts").Capability<unknown, unknown>;
|
|
89
77
|
export declare const nodeTestTriggerInput: z.ZodObject<{
|
|
90
78
|
nodeId: z.ZodString;
|
|
91
79
|
burnTimeMinutes: z.ZodOptional<z.ZodNumber>;
|
|
@@ -107,6 +95,8 @@ export declare const nodeBenchmarkCapability: import("../capability.ts").Capabil
|
|
|
107
95
|
export declare const nodeDeployInput: z.ZodObject<{
|
|
108
96
|
nodeId: z.ZodString;
|
|
109
97
|
targetTenantId: z.ZodString;
|
|
98
|
+
commerceReservationId: z.ZodOptional<z.ZodString>;
|
|
99
|
+
commerce_reservation_id: z.ZodOptional<z.ZodString>;
|
|
110
100
|
targetAuthUserId: z.ZodOptional<z.ZodString>;
|
|
111
101
|
networkMode: z.ZodOptional<z.ZodEnum<{
|
|
112
102
|
public: "public";
|
|
@@ -138,4 +128,13 @@ export declare const nodeAdminKeyInput: z.ZodObject<{
|
|
|
138
128
|
confirm: z.ZodOptional<z.ZodBoolean>;
|
|
139
129
|
}, z.core.$strip>;
|
|
140
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>;
|
|
141
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
|
});
|
|
@@ -233,31 +281,6 @@ export const nodeDetailsUpdateCapability = defineStaffMcpCapability({
|
|
|
233
281
|
return ctx.fetch(`/internal/nodes/${seg(parsed.nodeId)}/details`, { method: "PATCH", body });
|
|
234
282
|
},
|
|
235
283
|
});
|
|
236
|
-
export const nodeReserveListingInput = z.object({
|
|
237
|
-
nodeId: z.string(),
|
|
238
|
-
availableFrom: z.string().optional(),
|
|
239
|
-
availableTo: z.string().nullable().optional(),
|
|
240
|
-
confirm: z.boolean().optional(),
|
|
241
|
-
});
|
|
242
|
-
export const nodeReserveListingCapability = defineStaffMcpCapability({
|
|
243
|
-
id: "node.reserve-listing",
|
|
244
|
-
domain: "fleet",
|
|
245
|
-
roles: ["admin"],
|
|
246
|
-
description: "Internal staff only: list a GPU node on the reserve marketplace inventory. Requires confirm: true.",
|
|
247
|
-
mutation: "preview-confirm",
|
|
248
|
-
http: { method: "POST", path: "/inventory/{nodeId}" },
|
|
249
|
-
input: nodeReserveListingInput,
|
|
250
|
-
execute: async (ctx, input) => {
|
|
251
|
-
const parsed = nodeReserveListingInput.parse(input);
|
|
252
|
-
const body = mapBody(parsed, {
|
|
253
|
-
availableFrom: "available_from",
|
|
254
|
-
availableTo: "available_to",
|
|
255
|
-
});
|
|
256
|
-
if (!ctx.confirmed)
|
|
257
|
-
return preview("node.reserve-listing", body);
|
|
258
|
-
return ctx.fetch(`/inventory/${seg(parsed.nodeId)}`, { method: "POST", body });
|
|
259
|
-
},
|
|
260
|
-
});
|
|
261
284
|
export const nodeTestTriggerInput = z.object({
|
|
262
285
|
nodeId: z.string(),
|
|
263
286
|
burnTimeMinutes: z.number().optional(),
|
|
@@ -291,7 +314,18 @@ export const nodeTestTriggerCapability = defineStaffMcpCapability({
|
|
|
291
314
|
};
|
|
292
315
|
if (!ctx.confirmed)
|
|
293
316
|
return preview("node.test-trigger", body);
|
|
294
|
-
|
|
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
|
+
}
|
|
295
329
|
},
|
|
296
330
|
});
|
|
297
331
|
export const nodeTestResultInput = z.object({
|
|
@@ -329,6 +363,8 @@ export const nodeBenchmarkCapability = defineStaffMcpCapability({
|
|
|
329
363
|
export const nodeDeployInput = z.object({
|
|
330
364
|
nodeId: z.string(),
|
|
331
365
|
targetTenantId: z.string(),
|
|
366
|
+
commerceReservationId: z.string().optional(),
|
|
367
|
+
commerce_reservation_id: z.string().optional(),
|
|
332
368
|
targetAuthUserId: z.string().optional(),
|
|
333
369
|
networkMode: z.enum(["public", "private"]).optional(),
|
|
334
370
|
notes: z.string().max(2000).optional(),
|
|
@@ -344,8 +380,10 @@ export const nodeDeployCapability = defineStaffMcpCapability({
|
|
|
344
380
|
input: nodeDeployInput,
|
|
345
381
|
execute: async (ctx, input) => {
|
|
346
382
|
const parsed = nodeDeployInput.parse(input);
|
|
383
|
+
const reservationId = parsed.commerceReservationId ?? parsed.commerce_reservation_id;
|
|
347
384
|
const body = {
|
|
348
385
|
target_tenant_id: parsed.targetTenantId,
|
|
386
|
+
...(reservationId ? { commerce_reservation_id: reservationId } : {}),
|
|
349
387
|
...mapBody(parsed, {
|
|
350
388
|
targetAuthUserId: "target_auth_user_id",
|
|
351
389
|
networkMode: "network_mode",
|
|
@@ -444,6 +482,41 @@ export const nodeAdminKeyCapability = defineStaffMcpCapability({
|
|
|
444
482
|
});
|
|
445
483
|
},
|
|
446
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
|
+
});
|
|
447
520
|
export const staffFleetCapabilities = [
|
|
448
521
|
enrollmentTokenRevokeCapability,
|
|
449
522
|
operatorCreateCapability,
|
|
@@ -453,7 +526,6 @@ export const staffFleetCapabilities = [
|
|
|
453
526
|
facilityUpdateCapability,
|
|
454
527
|
nodeShowCapability,
|
|
455
528
|
nodeDetailsUpdateCapability,
|
|
456
|
-
nodeReserveListingCapability,
|
|
457
529
|
nodeTestTriggerCapability,
|
|
458
530
|
nodeTestResultCapability,
|
|
459
531
|
nodeBenchmarkCapability,
|
|
@@ -462,4 +534,5 @@ export const staffFleetCapabilities = [
|
|
|
462
534
|
nodeRebootCapability,
|
|
463
535
|
nodeHardResetCapability,
|
|
464
536
|
nodeAdminKeyCapability,
|
|
537
|
+
nodeOperatorTransferCapability,
|
|
465
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,
|
|
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,
|
|
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";
|