@capaxle/cli 0.1.0-alpha.1
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/LICENSE +202 -0
- package/README.md +5 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +4 -0
- package/dist/bin.js.map +1 -0
- package/dist/dev.d.ts +40 -0
- package/dist/dev.d.ts.map +1 -0
- package/dist/dev.js +281 -0
- package/dist/dev.js.map +1 -0
- package/dist/framework-cli.d.ts +105 -0
- package/dist/framework-cli.d.ts.map +1 -0
- package/dist/framework-cli.js +781 -0
- package/dist/framework-cli.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1,781 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { createOpenCliArtifactProducer, OPENCLI_SELECTOR, } from "@capaxle/adapter-cli";
|
|
3
|
+
import { createOpenApiArtifactProducer } from "@capaxle/adapter-http";
|
|
4
|
+
import { DOCS_SCHEMA_DIAGNOSTIC_CODES, DOCS_SCHEMA_GENERATOR_VERSION, DOCS_SCHEMA_TARGET, generateDocsSchemaArchive, } from "@capaxle/generator-docs";
|
|
5
|
+
import { createAgentManifestArtifactProducer, createMcpSnapshotArtifactProducer, } from "@capaxle/adapter-mcp";
|
|
6
|
+
import { runFrameworkDev } from "./dev.js";
|
|
7
|
+
import { compileProject, emitCompilerArtifacts, } from "@capaxle/compiler";
|
|
8
|
+
import { generateInternalFacade, INTERNAL_FACADE_ARTIFACT_ID, INTERNAL_FACADE_ARTIFACT_PATH, INTERNAL_FACADE_DIAGNOSTIC_CODES, INTERNAL_FACADE_MEDIA_TYPE, INTERNAL_FACADE_PRODUCER_ID, INTERNAL_FACADE_PRODUCER_VERSION, INTERNAL_FACADE_TARGET, generateSdkHttp, SDK_HTTP_ARTIFACT_ID, SDK_HTTP_ARTIFACT_PATH, SDK_HTTP_DIAGNOSTIC_CODES, SDK_HTTP_MEDIA_TYPE, SDK_HTTP_PRODUCER_ID, SDK_HTTP_PRODUCER_VERSION, SDK_HTTP_TARGET, } from "@capaxle/generator-sdk-ts";
|
|
9
|
+
import { jcs } from "@capaxle/ir";
|
|
10
|
+
import { zodSchemaProvider } from "@capaxle/schema-zod";
|
|
11
|
+
import { createRuntimeKernel, createRuntimeRegistry, } from "@capaxle/runtime";
|
|
12
|
+
export function createInternalFacadeArtifactProducer() {
|
|
13
|
+
return Object.freeze({
|
|
14
|
+
id: INTERNAL_FACADE_PRODUCER_ID,
|
|
15
|
+
version: INTERNAL_FACADE_PRODUCER_VERSION,
|
|
16
|
+
staticInputs: Object.freeze({ contractVersion: "0.1" }),
|
|
17
|
+
diagnosticCodes: INTERNAL_FACADE_DIAGNOSTIC_CODES,
|
|
18
|
+
artifacts: Object.freeze([
|
|
19
|
+
Object.freeze({
|
|
20
|
+
id: INTERNAL_FACADE_ARTIFACT_ID,
|
|
21
|
+
path: INTERNAL_FACADE_ARTIFACT_PATH,
|
|
22
|
+
mediaType: INTERNAL_FACADE_MEDIA_TYPE,
|
|
23
|
+
target: INTERNAL_FACADE_TARGET,
|
|
24
|
+
dependencies: Object.freeze(["document:capability-ir"]),
|
|
25
|
+
produce(context) {
|
|
26
|
+
const bytes = context.dependencyBytes.get("document:capability-ir");
|
|
27
|
+
if (!bytes)
|
|
28
|
+
return Object.freeze({
|
|
29
|
+
ok: false,
|
|
30
|
+
diagnostics: Object.freeze([
|
|
31
|
+
Object.freeze({
|
|
32
|
+
code: "CAP_INTERNAL_FACADE_SCHEMA_UNREPRESENTABLE",
|
|
33
|
+
severity: "error",
|
|
34
|
+
message: "The normalized Capability IR dependency is missing.",
|
|
35
|
+
target: INTERNAL_FACADE_TARGET,
|
|
36
|
+
path: "/",
|
|
37
|
+
}),
|
|
38
|
+
]),
|
|
39
|
+
});
|
|
40
|
+
let document;
|
|
41
|
+
try {
|
|
42
|
+
document = JSON.parse(new TextDecoder().decode(bytes));
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return Object.freeze({
|
|
46
|
+
ok: false,
|
|
47
|
+
diagnostics: Object.freeze([
|
|
48
|
+
Object.freeze({
|
|
49
|
+
code: "CAP_INTERNAL_FACADE_SCHEMA_UNREPRESENTABLE",
|
|
50
|
+
severity: "error",
|
|
51
|
+
message: "The normalized Capability IR dependency is invalid JSON.",
|
|
52
|
+
target: INTERNAL_FACADE_TARGET,
|
|
53
|
+
path: "/",
|
|
54
|
+
}),
|
|
55
|
+
]),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return generateInternalFacade({
|
|
59
|
+
document,
|
|
60
|
+
irHash: context.buildContext.irHash,
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
}),
|
|
64
|
+
]),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export function createSdkHttpArtifactProducer() {
|
|
68
|
+
return Object.freeze({
|
|
69
|
+
id: SDK_HTTP_PRODUCER_ID,
|
|
70
|
+
version: SDK_HTTP_PRODUCER_VERSION,
|
|
71
|
+
staticInputs: Object.freeze({ contractVersion: "0.1" }),
|
|
72
|
+
diagnosticCodes: SDK_HTTP_DIAGNOSTIC_CODES,
|
|
73
|
+
artifacts: Object.freeze([
|
|
74
|
+
Object.freeze({
|
|
75
|
+
id: SDK_HTTP_ARTIFACT_ID,
|
|
76
|
+
path: SDK_HTTP_ARTIFACT_PATH,
|
|
77
|
+
mediaType: SDK_HTTP_MEDIA_TYPE,
|
|
78
|
+
target: SDK_HTTP_TARGET,
|
|
79
|
+
dependencies: Object.freeze(["document:capability-ir"]),
|
|
80
|
+
produce(context) {
|
|
81
|
+
const bytes = context.dependencyBytes.get("document:capability-ir");
|
|
82
|
+
if (!bytes)
|
|
83
|
+
return Object.freeze({
|
|
84
|
+
ok: false,
|
|
85
|
+
diagnostics: Object.freeze([
|
|
86
|
+
Object.freeze({
|
|
87
|
+
code: "CAP_SDK_SCHEMA_UNREPRESENTABLE",
|
|
88
|
+
severity: "error",
|
|
89
|
+
message: "The normalized Capability IR dependency is missing.",
|
|
90
|
+
target: SDK_HTTP_TARGET,
|
|
91
|
+
path: "/",
|
|
92
|
+
}),
|
|
93
|
+
]),
|
|
94
|
+
});
|
|
95
|
+
let document;
|
|
96
|
+
try {
|
|
97
|
+
document = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return Object.freeze({
|
|
101
|
+
ok: false,
|
|
102
|
+
diagnostics: Object.freeze([
|
|
103
|
+
Object.freeze({
|
|
104
|
+
code: "CAP_SDK_SCHEMA_UNREPRESENTABLE",
|
|
105
|
+
severity: "error",
|
|
106
|
+
message: "The normalized Capability IR dependency is invalid JSON.",
|
|
107
|
+
target: SDK_HTTP_TARGET,
|
|
108
|
+
path: "/",
|
|
109
|
+
}),
|
|
110
|
+
]),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return generateSdkHttp({
|
|
114
|
+
document,
|
|
115
|
+
irHash: context.buildContext.irHash,
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
}),
|
|
119
|
+
]),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
export function createDocsSchemaArtifactProducer(options = {}) {
|
|
123
|
+
const profile = options.profile ?? "private";
|
|
124
|
+
const sensitiveRequirementNames = Object.freeze([
|
|
125
|
+
...(options.sensitiveRequirementNames ?? []),
|
|
126
|
+
]);
|
|
127
|
+
const target = DOCS_SCHEMA_TARGET;
|
|
128
|
+
return Object.freeze({
|
|
129
|
+
id: "capaxle.docs-schema-bundle",
|
|
130
|
+
version: DOCS_SCHEMA_GENERATOR_VERSION,
|
|
131
|
+
staticInputs: Object.freeze({ profile, sensitiveRequirementNames }),
|
|
132
|
+
diagnosticCodes: Object.freeze([...DOCS_SCHEMA_DIAGNOSTIC_CODES].sort().map((code) => Object.freeze({
|
|
133
|
+
code,
|
|
134
|
+
severities: Object.freeze(["error"]),
|
|
135
|
+
}))),
|
|
136
|
+
artifacts: Object.freeze([
|
|
137
|
+
Object.freeze({
|
|
138
|
+
id: "capaxle.docs-schema-bundle",
|
|
139
|
+
path: "docs/capability-bundle.tar",
|
|
140
|
+
mediaType: "application/x-tar",
|
|
141
|
+
target,
|
|
142
|
+
dependencies: Object.freeze(["document:capability-ir"]),
|
|
143
|
+
produce(context) {
|
|
144
|
+
const bytes = context.dependencyBytes.get("document:capability-ir");
|
|
145
|
+
if (!bytes)
|
|
146
|
+
return Object.freeze({
|
|
147
|
+
ok: false,
|
|
148
|
+
diagnostics: Object.freeze([
|
|
149
|
+
Object.freeze({
|
|
150
|
+
code: "CAP_DOCS_SCHEMA_INVALID",
|
|
151
|
+
severity: "error",
|
|
152
|
+
message: "The normalized Capability IR dependency is missing.",
|
|
153
|
+
target,
|
|
154
|
+
path: "/",
|
|
155
|
+
}),
|
|
156
|
+
]),
|
|
157
|
+
});
|
|
158
|
+
let document;
|
|
159
|
+
try {
|
|
160
|
+
document = JSON.parse(new TextDecoder().decode(bytes));
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return Object.freeze({
|
|
164
|
+
ok: false,
|
|
165
|
+
diagnostics: Object.freeze([
|
|
166
|
+
Object.freeze({
|
|
167
|
+
code: "CAP_DOCS_SCHEMA_INVALID",
|
|
168
|
+
severity: "error",
|
|
169
|
+
message: "The normalized Capability IR dependency is invalid JSON.",
|
|
170
|
+
target,
|
|
171
|
+
path: "/",
|
|
172
|
+
}),
|
|
173
|
+
]),
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
const generated = generateDocsSchemaArchive(document, {
|
|
177
|
+
irHash: context.buildContext.irHash,
|
|
178
|
+
profile,
|
|
179
|
+
sensitiveRequirementNames,
|
|
180
|
+
...(context.buildContext.cliBinary === undefined
|
|
181
|
+
? {}
|
|
182
|
+
: { cliBinary: context.buildContext.cliBinary }),
|
|
183
|
+
});
|
|
184
|
+
if (generated.ok)
|
|
185
|
+
return Object.freeze({
|
|
186
|
+
ok: true,
|
|
187
|
+
bytes: generated.bytes,
|
|
188
|
+
diagnostics: Object.freeze([]),
|
|
189
|
+
});
|
|
190
|
+
return Object.freeze({
|
|
191
|
+
ok: false,
|
|
192
|
+
diagnostics: Object.freeze(generated.diagnostics.map((diagnostic) => Object.freeze({ ...diagnostic, target }))),
|
|
193
|
+
});
|
|
194
|
+
},
|
|
195
|
+
}),
|
|
196
|
+
]),
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
const commands = new Set([
|
|
200
|
+
"check",
|
|
201
|
+
"build",
|
|
202
|
+
"list",
|
|
203
|
+
"describe",
|
|
204
|
+
"invoke",
|
|
205
|
+
"dev",
|
|
206
|
+
]);
|
|
207
|
+
const idPattern = /^[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)*$/;
|
|
208
|
+
const optionNames = new Set([
|
|
209
|
+
"--project",
|
|
210
|
+
"--output",
|
|
211
|
+
"--format",
|
|
212
|
+
"--strict",
|
|
213
|
+
"--json",
|
|
214
|
+
"--input",
|
|
215
|
+
"--host",
|
|
216
|
+
"--port",
|
|
217
|
+
]);
|
|
218
|
+
function commandDiagnostic(code, subphase, message, details, argumentIndex) {
|
|
219
|
+
return Object.freeze({
|
|
220
|
+
code,
|
|
221
|
+
severity: "error",
|
|
222
|
+
phase: "command",
|
|
223
|
+
subphase,
|
|
224
|
+
message,
|
|
225
|
+
...(argumentIndex === undefined ? {} : { argumentIndex }),
|
|
226
|
+
details: Object.freeze(details),
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
function parseIssue(details, message, argumentIndex) {
|
|
230
|
+
return commandDiagnostic(details.reason === "unknown-command"
|
|
231
|
+
? "CAP_CLI_COMMAND_UNKNOWN"
|
|
232
|
+
: "CAP_CLI_USAGE", "parse", message, details, argumentIndex);
|
|
233
|
+
}
|
|
234
|
+
function compareCodePoints(left, right) {
|
|
235
|
+
const leftPoints = Array.from(left, (item) => item.codePointAt(0));
|
|
236
|
+
const rightPoints = Array.from(right, (item) => item.codePointAt(0));
|
|
237
|
+
for (let index = 0; index < Math.min(leftPoints.length, rightPoints.length); index++) {
|
|
238
|
+
const difference = leftPoints[index] - rightPoints[index];
|
|
239
|
+
if (difference !== 0)
|
|
240
|
+
return difference;
|
|
241
|
+
}
|
|
242
|
+
return leftPoints.length - rightPoints.length;
|
|
243
|
+
}
|
|
244
|
+
function compareOptionalString(left, right) {
|
|
245
|
+
return compareCodePoints(left ?? "", right ?? "");
|
|
246
|
+
}
|
|
247
|
+
function sortCommandDiagnostics(diagnostics) {
|
|
248
|
+
const subphaseRank = { parse: 0, lookup: 1, internal: 2 };
|
|
249
|
+
const sorted = [...diagnostics].sort((left, right) => {
|
|
250
|
+
const phase = subphaseRank[left.subphase] - subphaseRank[right.subphase];
|
|
251
|
+
if (phase !== 0)
|
|
252
|
+
return phase;
|
|
253
|
+
const leftIndex = left.argumentIndex ?? Number.POSITIVE_INFINITY;
|
|
254
|
+
const rightIndex = right.argumentIndex ?? Number.POSITIVE_INFINITY;
|
|
255
|
+
if (leftIndex !== rightIndex)
|
|
256
|
+
return leftIndex - rightIndex;
|
|
257
|
+
return (compareCodePoints(left.code, right.code) ||
|
|
258
|
+
compareCodePoints(jcs(left.details), jcs(right.details)) ||
|
|
259
|
+
compareCodePoints(left.message, right.message));
|
|
260
|
+
});
|
|
261
|
+
return Object.freeze(sorted.filter((item, index) => index === 0 ||
|
|
262
|
+
jcs(item) !==
|
|
263
|
+
jcs(sorted[index - 1])));
|
|
264
|
+
}
|
|
265
|
+
export function parseFrameworkArguments(argv) {
|
|
266
|
+
const commandToken = argv[0];
|
|
267
|
+
if (commandToken === undefined) {
|
|
268
|
+
return Object.freeze({
|
|
269
|
+
ok: false,
|
|
270
|
+
command: null,
|
|
271
|
+
json: false,
|
|
272
|
+
diagnostics: Object.freeze([
|
|
273
|
+
parseIssue({ reason: "missing-command" }, "A framework command is required."),
|
|
274
|
+
]),
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
if (!commands.has(commandToken)) {
|
|
278
|
+
return Object.freeze({
|
|
279
|
+
ok: false,
|
|
280
|
+
command: commandToken,
|
|
281
|
+
json: argv.slice(1).includes("--json"),
|
|
282
|
+
diagnostics: Object.freeze([
|
|
283
|
+
parseIssue({ reason: "unknown-command", token: commandToken }, "The framework command is not recognized.", 0),
|
|
284
|
+
]),
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
const command = commandToken;
|
|
288
|
+
const diagnostics = [];
|
|
289
|
+
const seen = new Set();
|
|
290
|
+
let project;
|
|
291
|
+
let output;
|
|
292
|
+
let outputArgumentIndex;
|
|
293
|
+
let format;
|
|
294
|
+
let input;
|
|
295
|
+
let host;
|
|
296
|
+
let port;
|
|
297
|
+
let strict = false;
|
|
298
|
+
let json = command === "invoke";
|
|
299
|
+
let id;
|
|
300
|
+
let idArgumentIndex;
|
|
301
|
+
for (let index = 1; index < argv.length; index++) {
|
|
302
|
+
const token = argv[index];
|
|
303
|
+
if (token.startsWith("-")) {
|
|
304
|
+
if (!optionNames.has(token)) {
|
|
305
|
+
diagnostics.push(parseIssue({ reason: "unknown-option", option: token }, "The framework option is not recognized.", index));
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
if ((token === "--output" && command !== "build") ||
|
|
309
|
+
(token === "--format" && command !== "build") ||
|
|
310
|
+
(token === "--input" && command !== "invoke") ||
|
|
311
|
+
((token === "--port" || token === "--host") && command !== "dev")) {
|
|
312
|
+
diagnostics.push(parseIssue({ reason: "option-not-allowed", option: token }, "The option is not allowed for this command.", index));
|
|
313
|
+
}
|
|
314
|
+
if (seen.has(token)) {
|
|
315
|
+
diagnostics.push(parseIssue({ reason: "duplicate-option", option: token }, "A framework option may occur at most once.", index));
|
|
316
|
+
}
|
|
317
|
+
seen.add(token);
|
|
318
|
+
if (token === "--strict" || token === "--json") {
|
|
319
|
+
if (token === "--strict")
|
|
320
|
+
strict = true;
|
|
321
|
+
else
|
|
322
|
+
json = true;
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
const value = argv[index + 1];
|
|
326
|
+
if (value === undefined) {
|
|
327
|
+
diagnostics.push(parseIssue({ reason: "missing-option-value", option: token }, "The framework option requires a value.", index));
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
if (token === "--project")
|
|
331
|
+
project = value;
|
|
332
|
+
else if (token === "--format") {
|
|
333
|
+
format = value;
|
|
334
|
+
if (value !== OPENCLI_SELECTOR && value !== SDK_HTTP_TARGET)
|
|
335
|
+
diagnostics.push(parseIssue({ reason: "invalid-option-value", option: token }, `The format must be ${OPENCLI_SELECTOR} or ${SDK_HTTP_TARGET}.`, index));
|
|
336
|
+
}
|
|
337
|
+
else if (token === "--input")
|
|
338
|
+
input = value;
|
|
339
|
+
else if (token === "--host") {
|
|
340
|
+
host = value;
|
|
341
|
+
if (!value || value.startsWith("-"))
|
|
342
|
+
diagnostics.push(parseIssue({ reason: "invalid-option-value", option: token }, "The host must be a non-empty hostname or address.", index));
|
|
343
|
+
}
|
|
344
|
+
else if (token === "--port") {
|
|
345
|
+
if (!/^\d+$/.test(value) || Number(value) > 65535)
|
|
346
|
+
diagnostics.push(parseIssue({ reason: "invalid-option-value", option: token }, "The port must be an integer from 0 through 65535.", index));
|
|
347
|
+
else
|
|
348
|
+
port = Number(value);
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
output = value;
|
|
352
|
+
outputArgumentIndex = index;
|
|
353
|
+
}
|
|
354
|
+
index++;
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
if ((command === "describe" || command === "invoke") && id === undefined) {
|
|
358
|
+
id = token;
|
|
359
|
+
idArgumentIndex = index;
|
|
360
|
+
if (!idPattern.test(token)) {
|
|
361
|
+
diagnostics.push(parseIssue({ reason: "invalid-id", token }, "The capability ID is invalid.", index));
|
|
362
|
+
}
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
diagnostics.push(parseIssue({ reason: "extra-positional", token }, "The command has an extra positional argument.", index));
|
|
366
|
+
}
|
|
367
|
+
if ((command === "describe" || command === "invoke") && id === undefined) {
|
|
368
|
+
diagnostics.push(parseIssue({ reason: "missing-id" }, `The ${command} command requires an ID.`));
|
|
369
|
+
}
|
|
370
|
+
if (command === "invoke" && input === undefined && !seen.has("--input")) {
|
|
371
|
+
diagnostics.push(parseIssue({ reason: "missing-input" }, "The invoke command requires --input with a JSON value."));
|
|
372
|
+
}
|
|
373
|
+
if (diagnostics.length > 0) {
|
|
374
|
+
return Object.freeze({
|
|
375
|
+
ok: false,
|
|
376
|
+
command,
|
|
377
|
+
json,
|
|
378
|
+
diagnostics: sortCommandDiagnostics(diagnostics),
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
return Object.freeze({
|
|
382
|
+
ok: true,
|
|
383
|
+
value: Object.freeze({
|
|
384
|
+
command,
|
|
385
|
+
...(project === undefined ? {} : { project }),
|
|
386
|
+
...(output === undefined
|
|
387
|
+
? {}
|
|
388
|
+
: { output, outputArgumentIndex: outputArgumentIndex }),
|
|
389
|
+
...(format === undefined ? {} : { format }),
|
|
390
|
+
strict,
|
|
391
|
+
json,
|
|
392
|
+
...(input === undefined ? {} : { input }),
|
|
393
|
+
...(host === undefined ? {} : { host }),
|
|
394
|
+
...(port === undefined ? {} : { port }),
|
|
395
|
+
...(id === undefined ? {} : { id, idArgumentIndex: idArgumentIndex }),
|
|
396
|
+
}),
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
const subphaseRanks = new Map([
|
|
400
|
+
"config-name",
|
|
401
|
+
"config-load",
|
|
402
|
+
"config-value",
|
|
403
|
+
"discovery-root",
|
|
404
|
+
"discovery-identity",
|
|
405
|
+
"discovery-module-load",
|
|
406
|
+
"discovery-module-export",
|
|
407
|
+
"discovery-override",
|
|
408
|
+
"discovery-duplicate",
|
|
409
|
+
"discovery-watch",
|
|
410
|
+
"authoring-descriptor",
|
|
411
|
+
"schema-provider",
|
|
412
|
+
"schema-portability",
|
|
413
|
+
"schema-reference",
|
|
414
|
+
"ir-structure",
|
|
415
|
+
"ir-unsupported",
|
|
416
|
+
"ir-identity",
|
|
417
|
+
"ir-schema",
|
|
418
|
+
"ir-policy",
|
|
419
|
+
"ir-execution",
|
|
420
|
+
"ir-projection",
|
|
421
|
+
"ir-normalization",
|
|
422
|
+
"projection-http",
|
|
423
|
+
"projection-cli",
|
|
424
|
+
"projection-mcp",
|
|
425
|
+
"projection-docs",
|
|
426
|
+
"projection-sdk",
|
|
427
|
+
"projection-collision",
|
|
428
|
+
"graph-input",
|
|
429
|
+
"graph-dependency",
|
|
430
|
+
"graph-cycle",
|
|
431
|
+
"graph-execution",
|
|
432
|
+
"emission-producer",
|
|
433
|
+
"emission-stage",
|
|
434
|
+
"emission-commit",
|
|
435
|
+
"emission-cleanup",
|
|
436
|
+
].map((subphase, index) => [subphase, index]));
|
|
437
|
+
const severityRanks = { error: 0, warning: 1, info: 2 };
|
|
438
|
+
function compareSource(left, right) {
|
|
439
|
+
return (compareCodePoints(left.file, right.file) ||
|
|
440
|
+
left.line - right.line ||
|
|
441
|
+
left.column - right.column ||
|
|
442
|
+
(left.endLine ?? left.line) - (right.endLine ?? right.line) ||
|
|
443
|
+
(left.endColumn ?? left.column) - (right.endColumn ?? right.column));
|
|
444
|
+
}
|
|
445
|
+
function normalizedRelated(diagnostic) {
|
|
446
|
+
return [...(diagnostic.related ?? [])].sort((left, right) => compareSource(left.source, right.source) ||
|
|
447
|
+
compareOptionalString(left.path, right.path) ||
|
|
448
|
+
compareCodePoints(left.message, right.message));
|
|
449
|
+
}
|
|
450
|
+
function sortCompilationDiagnostics(diagnostics) {
|
|
451
|
+
const normalized = diagnostics.map((diagnostic) => {
|
|
452
|
+
if (!diagnostic.related)
|
|
453
|
+
return diagnostic;
|
|
454
|
+
return {
|
|
455
|
+
...diagnostic,
|
|
456
|
+
related: normalizedRelated(diagnostic),
|
|
457
|
+
};
|
|
458
|
+
});
|
|
459
|
+
normalized.sort((left, right) => (subphaseRanks.get(left.subphase) ?? Number.POSITIVE_INFINITY) -
|
|
460
|
+
(subphaseRanks.get(right.subphase) ?? Number.POSITIVE_INFINITY) ||
|
|
461
|
+
compareSource(left.source, right.source) ||
|
|
462
|
+
compareOptionalString(left.path, right.path) ||
|
|
463
|
+
compareCodePoints(left.code, right.code) ||
|
|
464
|
+
severityRanks[left.severity] - severityRanks[right.severity] ||
|
|
465
|
+
compareCodePoints(jcs((left.details ?? null)), jcs((right.details ?? null))) ||
|
|
466
|
+
compareCodePoints(left.message, right.message) ||
|
|
467
|
+
compareOptionalString(left.remediation, right.remediation) ||
|
|
468
|
+
compareCodePoints(jcs(normalizedRelated(left)), jcs(normalizedRelated(right))));
|
|
469
|
+
return Object.freeze(normalized.filter((item, index) => index === 0 ||
|
|
470
|
+
jcs(item) !==
|
|
471
|
+
jcs(normalized[index - 1])));
|
|
472
|
+
}
|
|
473
|
+
function sortedDiagnostics(compilation, command = []) {
|
|
474
|
+
return Object.freeze([
|
|
475
|
+
...sortCompilationDiagnostics(compilation),
|
|
476
|
+
...sortCommandDiagnostics(command),
|
|
477
|
+
]);
|
|
478
|
+
}
|
|
479
|
+
function failure(command, exitCode, json, diagnostics) {
|
|
480
|
+
return Object.freeze({
|
|
481
|
+
exitCode,
|
|
482
|
+
json,
|
|
483
|
+
envelope: Object.freeze({
|
|
484
|
+
command,
|
|
485
|
+
ok: false,
|
|
486
|
+
diagnostics,
|
|
487
|
+
}),
|
|
488
|
+
stdout: "",
|
|
489
|
+
diagnostics,
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
function success(json, envelope, stdout, diagnostics) {
|
|
493
|
+
return Object.freeze({ exitCode: 0, json, envelope, stdout, diagnostics });
|
|
494
|
+
}
|
|
495
|
+
function capabilitiesOf(compilation) {
|
|
496
|
+
const document = compilation.document;
|
|
497
|
+
if (typeof document !== "object" ||
|
|
498
|
+
document === null ||
|
|
499
|
+
Array.isArray(document)) {
|
|
500
|
+
throw new TypeError("Compiler returned an invalid document shape.");
|
|
501
|
+
}
|
|
502
|
+
const capabilities = document["capabilities"];
|
|
503
|
+
if (!Array.isArray(capabilities) ||
|
|
504
|
+
!capabilities.every((item) => typeof item === "object" && item !== null && !Array.isArray(item))) {
|
|
505
|
+
throw new TypeError("Compiler returned an invalid document shape.");
|
|
506
|
+
}
|
|
507
|
+
return capabilities;
|
|
508
|
+
}
|
|
509
|
+
function strictFailure(compilation, strict) {
|
|
510
|
+
return (strict &&
|
|
511
|
+
compilation.diagnostics.some(({ severity }) => severity === "warning"));
|
|
512
|
+
}
|
|
513
|
+
function compileFailureExit(result) {
|
|
514
|
+
const diagnostics = sortCompilationDiagnostics(result.diagnostics);
|
|
515
|
+
const firstError = diagnostics.find(({ severity }) => severity === "error");
|
|
516
|
+
return firstError?.subphase === "emission-producer" ? 5 : 3;
|
|
517
|
+
}
|
|
518
|
+
function invocationFailureExit(code) {
|
|
519
|
+
if (code === "CAP_INPUT_INVALID")
|
|
520
|
+
return 2;
|
|
521
|
+
if (code === "CAP_UNAUTHENTICATED" || code === "CAP_PERMISSION_DENIED")
|
|
522
|
+
return 3;
|
|
523
|
+
if (code === "CAP_CONFIRMATION_REQUIRED" ||
|
|
524
|
+
code === "CAP_CONFIRMATION_INVALID" ||
|
|
525
|
+
code === "CAP_IDEMPOTENCY_KEY_REQUIRED" ||
|
|
526
|
+
code === "CAP_IDEMPOTENCY_CONFLICT")
|
|
527
|
+
return 4;
|
|
528
|
+
if (code === "CAP_RATE_LIMITED" ||
|
|
529
|
+
code === "CAP_DEPENDENCY_UNAVAILABLE" ||
|
|
530
|
+
code === "CAP_DEADLINE_EXCEEDED")
|
|
531
|
+
return 6;
|
|
532
|
+
if (code === "CAP_CANCELLED")
|
|
533
|
+
return 130;
|
|
534
|
+
return code.startsWith("CAP_") ? 7 : 5;
|
|
535
|
+
}
|
|
536
|
+
export async function executeFrameworkCli(argv, dependencies, io) {
|
|
537
|
+
const parsed = parseFrameworkArguments(argv);
|
|
538
|
+
if (!parsed.ok) {
|
|
539
|
+
return failure(parsed.command, 2, parsed.json, parsed.diagnostics);
|
|
540
|
+
}
|
|
541
|
+
const options = parsed.value;
|
|
542
|
+
let accumulatedCompilationDiagnostics = [];
|
|
543
|
+
try {
|
|
544
|
+
const projectRoot = resolve(dependencies.cwd(), options.project ?? ".");
|
|
545
|
+
if (options.command === "dev") {
|
|
546
|
+
return await runFrameworkDev(options, projectRoot, dependencies, io);
|
|
547
|
+
}
|
|
548
|
+
const artifactProducers = options.command !== "build"
|
|
549
|
+
? undefined
|
|
550
|
+
: options.format === OPENCLI_SELECTOR
|
|
551
|
+
? Object.freeze([
|
|
552
|
+
dependencies.openCliArtifactProducer ??
|
|
553
|
+
createOpenCliArtifactProducer(),
|
|
554
|
+
])
|
|
555
|
+
: options.format === SDK_HTTP_TARGET
|
|
556
|
+
? Object.freeze([
|
|
557
|
+
dependencies.sdkHttpArtifactProducer ??
|
|
558
|
+
createSdkHttpArtifactProducer(),
|
|
559
|
+
])
|
|
560
|
+
: dependencies.artifactProducers;
|
|
561
|
+
const compilation = await dependencies.compileProject({
|
|
562
|
+
projectRoot,
|
|
563
|
+
schemaProviders: dependencies.schemaProviders,
|
|
564
|
+
...(artifactProducers === undefined ? {} : { artifactProducers }),
|
|
565
|
+
});
|
|
566
|
+
accumulatedCompilationDiagnostics = sortCompilationDiagnostics(compilation.diagnostics);
|
|
567
|
+
if (!compilation.ok) {
|
|
568
|
+
return failure(options.command, compileFailureExit(compilation), options.json, sortCompilationDiagnostics(compilation.diagnostics));
|
|
569
|
+
}
|
|
570
|
+
if (strictFailure(compilation, options.strict)) {
|
|
571
|
+
return failure(options.command, 3, options.json, sortCompilationDiagnostics(compilation.diagnostics));
|
|
572
|
+
}
|
|
573
|
+
if (options.command === "invoke") {
|
|
574
|
+
const registry = createRuntimeRegistry({
|
|
575
|
+
document: compilation.document,
|
|
576
|
+
irHash: compilation.irHash,
|
|
577
|
+
bindings: compilation.runtimeBindings,
|
|
578
|
+
validators: compilation.validators,
|
|
579
|
+
});
|
|
580
|
+
let adapterCandidate;
|
|
581
|
+
try {
|
|
582
|
+
const input = JSON.parse(options.input);
|
|
583
|
+
if (typeof input !== "object" ||
|
|
584
|
+
input === null ||
|
|
585
|
+
Array.isArray(input)) {
|
|
586
|
+
adapterCandidate = {
|
|
587
|
+
ok: false,
|
|
588
|
+
code: "CAP_INPUT_INVALID",
|
|
589
|
+
status: 400,
|
|
590
|
+
safeDetails: { path: "/input", reason: "object-required" },
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
else {
|
|
594
|
+
adapterCandidate = { ok: true, input };
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
catch {
|
|
598
|
+
adapterCandidate = {
|
|
599
|
+
ok: false,
|
|
600
|
+
code: "CAP_INPUT_INVALID",
|
|
601
|
+
status: 400,
|
|
602
|
+
safeDetails: { path: "/input", reason: "invalid-json" },
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
const result = await createRuntimeKernel({ registry }).invoke({
|
|
606
|
+
capability: options.id,
|
|
607
|
+
source: "cli",
|
|
608
|
+
adapterCandidate,
|
|
609
|
+
});
|
|
610
|
+
return Object.freeze({
|
|
611
|
+
exitCode: result.ok ? 0 : invocationFailureExit(result.error.code),
|
|
612
|
+
json: true,
|
|
613
|
+
envelope: result,
|
|
614
|
+
stdout: "",
|
|
615
|
+
diagnostics: Object.freeze([]),
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
if (options.command === "check") {
|
|
619
|
+
const diagnostics = sortCompilationDiagnostics(compilation.diagnostics);
|
|
620
|
+
const envelope = Object.freeze({
|
|
621
|
+
command: "check",
|
|
622
|
+
ok: true,
|
|
623
|
+
irHash: compilation.irHash,
|
|
624
|
+
summary: Object.freeze({
|
|
625
|
+
capabilities: capabilitiesOf(compilation).length,
|
|
626
|
+
warnings: diagnostics.filter(({ severity }) => severity === "warning")
|
|
627
|
+
.length,
|
|
628
|
+
infos: diagnostics.filter(({ severity }) => severity === "info")
|
|
629
|
+
.length,
|
|
630
|
+
}),
|
|
631
|
+
diagnostics,
|
|
632
|
+
});
|
|
633
|
+
return success(options.json, envelope, "", diagnostics);
|
|
634
|
+
}
|
|
635
|
+
if (options.command === "list") {
|
|
636
|
+
const diagnostics = sortCompilationDiagnostics(compilation.diagnostics);
|
|
637
|
+
const capabilities = [...compilation.registry.capabilities]
|
|
638
|
+
.sort((left, right) => compareCodePoints(left.id, right.id))
|
|
639
|
+
.map(({ id, version, summary, exposure }) => ({
|
|
640
|
+
id,
|
|
641
|
+
version,
|
|
642
|
+
summary,
|
|
643
|
+
exposure,
|
|
644
|
+
}));
|
|
645
|
+
const envelope = Object.freeze({
|
|
646
|
+
command: "list",
|
|
647
|
+
ok: true,
|
|
648
|
+
irHash: compilation.irHash,
|
|
649
|
+
capabilities,
|
|
650
|
+
diagnostics,
|
|
651
|
+
});
|
|
652
|
+
return success(options.json, envelope, capabilities.map(({ id, version }) => `${id}@${version}\n`).join(""), diagnostics);
|
|
653
|
+
}
|
|
654
|
+
if (options.command === "describe") {
|
|
655
|
+
const diagnostics = sortCompilationDiagnostics(compilation.diagnostics);
|
|
656
|
+
const capabilities = capabilitiesOf(compilation);
|
|
657
|
+
const capability = capabilities.find((item) => item.id === options.id);
|
|
658
|
+
const registryCapability = compilation.registry.capabilities.find(({ id }) => id === options.id);
|
|
659
|
+
if (!capability || !registryCapability) {
|
|
660
|
+
const lookup = commandDiagnostic("CAP_CLI_CAPABILITY_NOT_FOUND", "lookup", "The capability ID was not found.", { reason: "capability-not-found", id: options.id }, options.idArgumentIndex);
|
|
661
|
+
return failure("describe", 4, options.json, sortedDiagnostics(diagnostics, [lookup]));
|
|
662
|
+
}
|
|
663
|
+
const provenance = registryCapability.provenance;
|
|
664
|
+
const envelope = Object.freeze({
|
|
665
|
+
command: "describe",
|
|
666
|
+
ok: true,
|
|
667
|
+
irHash: compilation.irHash,
|
|
668
|
+
capability,
|
|
669
|
+
provenance,
|
|
670
|
+
diagnostics,
|
|
671
|
+
});
|
|
672
|
+
const described = recursivelySorted({
|
|
673
|
+
capability,
|
|
674
|
+
provenance,
|
|
675
|
+
});
|
|
676
|
+
return success(options.json, envelope, `${JSON.stringify(described, null, 2)}\n`, diagnostics);
|
|
677
|
+
}
|
|
678
|
+
const emission = await dependencies.emitCompilerArtifacts({
|
|
679
|
+
projectRoot,
|
|
680
|
+
compilation,
|
|
681
|
+
...(options.output === undefined
|
|
682
|
+
? {}
|
|
683
|
+
: {
|
|
684
|
+
outputDirectory: options.output,
|
|
685
|
+
outputDiagnosticSource: {
|
|
686
|
+
kind: "command-option",
|
|
687
|
+
command: "build",
|
|
688
|
+
option: "--output",
|
|
689
|
+
argumentIndex: options.outputArgumentIndex,
|
|
690
|
+
},
|
|
691
|
+
}),
|
|
692
|
+
});
|
|
693
|
+
accumulatedCompilationDiagnostics = sortCompilationDiagnostics([
|
|
694
|
+
...compilation.diagnostics,
|
|
695
|
+
...emission.diagnostics,
|
|
696
|
+
]);
|
|
697
|
+
const diagnostics = sortCompilationDiagnostics([
|
|
698
|
+
...compilation.diagnostics,
|
|
699
|
+
...emission.diagnostics,
|
|
700
|
+
]);
|
|
701
|
+
if (!emission.ok) {
|
|
702
|
+
return failure("build", 5, options.json, diagnostics);
|
|
703
|
+
}
|
|
704
|
+
const artifacts = [...emission.artifacts].sort((left, right) => compareCodePoints(left.id, right.id));
|
|
705
|
+
const envelope = Object.freeze({
|
|
706
|
+
command: "build",
|
|
707
|
+
ok: true,
|
|
708
|
+
buildId: emission.buildId,
|
|
709
|
+
irHash: compilation.irHash,
|
|
710
|
+
current: emission.current,
|
|
711
|
+
artifacts,
|
|
712
|
+
diagnostics,
|
|
713
|
+
});
|
|
714
|
+
return success(options.json, envelope, `${emission.current}\n`, diagnostics);
|
|
715
|
+
}
|
|
716
|
+
catch {
|
|
717
|
+
const diagnostic = commandDiagnostic("CAP_CLI_INTERNAL", "internal", "The framework command failed unexpectedly.", { reason: "unexpected" });
|
|
718
|
+
return failure(options.command, 70, options.json, sortedDiagnostics(accumulatedCompilationDiagnostics, [diagnostic]));
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
function recursivelySorted(value) {
|
|
722
|
+
if (Array.isArray(value))
|
|
723
|
+
return value.map(recursivelySorted);
|
|
724
|
+
if (typeof value !== "object" || value === null)
|
|
725
|
+
return value;
|
|
726
|
+
const record = value;
|
|
727
|
+
return Object.fromEntries(Object.keys(record)
|
|
728
|
+
.sort(compareCodePoints)
|
|
729
|
+
.map((key) => [key, recursivelySorted(record[key])]));
|
|
730
|
+
}
|
|
731
|
+
function singleLine(message) {
|
|
732
|
+
return message.replace(/[\r\n]+/gu, " ");
|
|
733
|
+
}
|
|
734
|
+
function humanDiagnostic(diagnostic) {
|
|
735
|
+
if (diagnostic.phase === "command") {
|
|
736
|
+
return `ERROR ${diagnostic.code} argv[${diagnostic.argumentIndex ?? "-"}]: ${singleLine(diagnostic.message)}\n`;
|
|
737
|
+
}
|
|
738
|
+
return `${diagnostic.severity.toUpperCase()} ${diagnostic.code} ${diagnostic.source.file}:${diagnostic.source.line}:${diagnostic.source.column} ${diagnostic.path ?? "-"}: ${singleLine(diagnostic.message)}\n`;
|
|
739
|
+
}
|
|
740
|
+
export function renderFrameworkResult(result) {
|
|
741
|
+
if (result.json) {
|
|
742
|
+
return Object.freeze({
|
|
743
|
+
stdout: `${jcs(result.envelope)}\n`,
|
|
744
|
+
stderr: "",
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
return Object.freeze({
|
|
748
|
+
stdout: result.exitCode === 0 ? result.stdout : "",
|
|
749
|
+
stderr: result.diagnostics.map(humanDiagnostic).join(""),
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
export async function runFrameworkCli(argv, dependencies, io) {
|
|
753
|
+
const result = await executeFrameworkCli(argv, dependencies, io);
|
|
754
|
+
const rendered = renderFrameworkResult(result);
|
|
755
|
+
if (rendered.stdout)
|
|
756
|
+
io.stdout.write(rendered.stdout);
|
|
757
|
+
if (rendered.stderr)
|
|
758
|
+
io.stderr.write(rendered.stderr);
|
|
759
|
+
return result.exitCode;
|
|
760
|
+
}
|
|
761
|
+
export const defaultFrameworkCliDependencies = Object.freeze({
|
|
762
|
+
cwd: () => process.cwd(),
|
|
763
|
+
schemaProviders: Object.freeze([zodSchemaProvider]),
|
|
764
|
+
artifactProducers: Object.freeze([
|
|
765
|
+
createOpenApiArtifactProducer(),
|
|
766
|
+
createMcpSnapshotArtifactProducer({
|
|
767
|
+
profile: "private",
|
|
768
|
+
}),
|
|
769
|
+
createAgentManifestArtifactProducer({
|
|
770
|
+
profile: "private",
|
|
771
|
+
}),
|
|
772
|
+
createInternalFacadeArtifactProducer(),
|
|
773
|
+
createSdkHttpArtifactProducer(),
|
|
774
|
+
createDocsSchemaArtifactProducer(),
|
|
775
|
+
]),
|
|
776
|
+
openCliArtifactProducer: createOpenCliArtifactProducer(),
|
|
777
|
+
sdkHttpArtifactProducer: createSdkHttpArtifactProducer(),
|
|
778
|
+
compileProject,
|
|
779
|
+
emitCompilerArtifacts,
|
|
780
|
+
});
|
|
781
|
+
//# sourceMappingURL=framework-cli.js.map
|