@yansirplus/cli 0.5.17 → 0.5.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -6
- package/agent-catalog/agentOS/SKILL.md +22 -0
- package/agent-catalog/agentOS/references/agent/decision-graph.json +530 -0
- package/agent-catalog/agentOS/references/agent/errors.json +497 -0
- package/agent-catalog/agentOS/references/agent/invariant-matrix.json +337 -0
- package/agent-catalog/agentOS/references/agent/primitives.json +989 -0
- package/agent-catalog/agentOS/references/agent/recipes.json +109 -0
- package/agent-catalog/agentOS/references/agent/start-here.md +25 -0
- package/agent-catalog/agentOS/references/package-map.md +73 -0
- package/agent-catalog/agentOS/references/provenance.json +251 -0
- package/agent-catalog/agentOS/references/public-api/cli.md +20 -0
- package/agent-catalog/agentOS/references/public-api/client.md +90 -0
- package/agent-catalog/agentOS/references/public-api/core.md +1907 -0
- package/agent-catalog/agentOS/references/public-api/runtime.md +843 -0
- package/dist/build/agent-authoring/config.d.ts +20 -5
- package/dist/build/agent-authoring/config.js +132 -32
- package/dist/build/agent-authoring/manifest-compiler.d.ts +131 -2
- package/dist/build/agent-authoring/manifest-compiler.js +630 -8
- package/dist/build/agent-authoring/shared.d.ts +2 -0
- package/dist/build/agent-authoring/shared.js +2 -0
- package/dist/build/agent-authoring/static-target.d.ts +6 -3
- package/dist/build/agent-authoring/static-target.js +1900 -281
- package/dist/build/agent-authoring.d.ts +3 -3
- package/dist/build/agent-authoring.js +1 -1
- package/dist/build/build-cli.d.ts +1 -1
- package/dist/build/build-cli.js +1629 -26
- package/dist/check/algorithmic/client-boundary-checks.mjs +3 -34
- package/dist/check/algorithmic/convergence-smoke-checks.mjs +652 -6
- package/dist/check/algorithmic/distribution-checks.mjs +8 -7
- package/dist/check/algorithmic/package-boundary-checks.mjs +3 -2
- package/dist/check/algorithmic/repo-surface-checks.mjs +55 -1
- package/dist/check/algorithmic/static-target-checks.mjs +83 -5
- package/dist/check/algorithmic-checks.mjs +10 -17
- package/dist/check/default-gate.mjs +3 -3
- package/dist/check/effect-scan-gate.mjs +121 -0
- package/dist/check/package-graph.mjs +2 -32
- package/dist/consumer-overlay.mjs +1281 -0
- package/dist/lib/public-api-model.mjs +19 -0
- package/dist/lib/repo-source-files.mjs +26 -0
- package/dist/lib/ts-module-loader.mjs +44 -0
- package/dist/lib/workspace-manifest.mjs +77 -0
- package/dist/main.mjs +171 -21
- package/dist/release-status.mjs +515 -0
- package/package.json +8 -4
- package/dist/check/check-coverage.mjs +0 -231
- package/dist/generate/generate-agent-docs.mjs +0 -435
- package/dist/generate/generate-carrier-reference.mjs +0 -514
- package/dist/generate/generate-docs.mjs +0 -345
- package/dist/generate/generate-effect-skill-manifests.mjs +0 -193
- package/dist/generate/project-docs-site.mjs +0 -190
- package/dist/lib/boundary-rules.mjs +0 -63
- package/dist/lib/capability-routes.mjs +0 -354
- package/dist/lib/projection-sink.mjs +0 -113
|
@@ -1,514 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { pathToFileURL } from "node:url";
|
|
5
|
-
import {
|
|
6
|
-
checkProjectionSink,
|
|
7
|
-
defineProjectionSpec,
|
|
8
|
-
runProjectionSink,
|
|
9
|
-
} from "../lib/projection-sink.mjs";
|
|
10
|
-
|
|
11
|
-
const root = process.cwd();
|
|
12
|
-
const check = process.argv.includes("--check");
|
|
13
|
-
const surface = JSON.parse(fs.readFileSync(path.join(root, "docs/surface.json"), "utf8"));
|
|
14
|
-
const target = "docs/reference/carriers.md";
|
|
15
|
-
const failures = [];
|
|
16
|
-
|
|
17
|
-
const generatedNotice =
|
|
18
|
-
"<!-- generated by packages/cli/src/generate/generate-carrier-reference.mjs; edit carrier definitions -->";
|
|
19
|
-
|
|
20
|
-
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21
|
-
|
|
22
|
-
const isCarrier = (value) =>
|
|
23
|
-
isRecord(value) &&
|
|
24
|
-
typeof value.ownerId === "string" &&
|
|
25
|
-
typeof value.sourcePackageName === "string" &&
|
|
26
|
-
typeof value.prefix === "string" &&
|
|
27
|
-
isRecord(value.boundaryContract) &&
|
|
28
|
-
isRecord(value.settlementContract) &&
|
|
29
|
-
typeof value.boundaryPackage === "function" &&
|
|
30
|
-
typeof value.decode === "function";
|
|
31
|
-
|
|
32
|
-
const isEventNamespace = (value) =>
|
|
33
|
-
isRecord(value) &&
|
|
34
|
-
typeof value.ownerId === "string" &&
|
|
35
|
-
typeof value.sourcePackageName === "string" &&
|
|
36
|
-
Array.isArray(value.kindPrefixes) &&
|
|
37
|
-
value.kindPrefixes.every((prefix) => typeof prefix === "string" && prefix.length > 0) &&
|
|
38
|
-
typeof value.version === "string";
|
|
39
|
-
|
|
40
|
-
const walk = (relativePath, options = {}) => {
|
|
41
|
-
const absolutePath = path.join(root, relativePath);
|
|
42
|
-
if (!fs.existsSync(absolutePath)) return [];
|
|
43
|
-
const stat = fs.statSync(absolutePath);
|
|
44
|
-
if (stat.isFile()) return [relativePath];
|
|
45
|
-
const ignored = options.ignored ?? new Set(["node_modules", "dist", ".wrangler", ".turbo"]);
|
|
46
|
-
const files = [];
|
|
47
|
-
for (const entry of fs.readdirSync(absolutePath, { withFileTypes: true })) {
|
|
48
|
-
if (entry.isDirectory() && ignored.has(entry.name)) continue;
|
|
49
|
-
const child = path.join(relativePath, entry.name).split(path.sep).join("/");
|
|
50
|
-
if (entry.isDirectory()) files.push(...walk(child, options));
|
|
51
|
-
if (entry.isFile()) files.push(child);
|
|
52
|
-
}
|
|
53
|
-
return files.sort((left, right) => left.localeCompare(right));
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const sourcePackages = surface.packages
|
|
57
|
-
.filter(
|
|
58
|
-
(pkg) =>
|
|
59
|
-
isRecord(pkg) &&
|
|
60
|
-
typeof pkg.name === "string" &&
|
|
61
|
-
typeof pkg.path === "string" &&
|
|
62
|
-
pkg.path.startsWith("packages/") &&
|
|
63
|
-
fs.existsSync(path.join(root, pkg.path, "package.json")),
|
|
64
|
-
)
|
|
65
|
-
.sort(
|
|
66
|
-
(left, right) => right.path.length - left.path.length || left.path.localeCompare(right.path),
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
const sourcePackageForFile = (file) =>
|
|
70
|
-
sourcePackages.find((pkg) => file === pkg.path || file.startsWith(`${pkg.path}/`));
|
|
71
|
-
|
|
72
|
-
const defineCarrierFiles = () =>
|
|
73
|
-
walk("packages")
|
|
74
|
-
.filter((file) => /\/src\/.*\.ts$/u.test(file))
|
|
75
|
-
.filter((file) => fs.readFileSync(path.join(root, file), "utf8").includes("defineCarrier("));
|
|
76
|
-
|
|
77
|
-
const escapeCell = (value) => String(value).replaceAll("|", "\\|").replaceAll("\n", "<br>");
|
|
78
|
-
|
|
79
|
-
const table = (headers, rows) => {
|
|
80
|
-
const escapedHeaders = headers.map(escapeCell);
|
|
81
|
-
const escapedRows = rows.map((row) => row.map(escapeCell));
|
|
82
|
-
const widths = escapedHeaders.map((header, index) =>
|
|
83
|
-
Math.max(header.length, ...escapedRows.map((row) => row[index].length)),
|
|
84
|
-
);
|
|
85
|
-
const pad = (value, width) => `${value}${" ".repeat(Math.max(0, width - value.length))}`;
|
|
86
|
-
const line = (cells) => `| ${cells.map((cell, index) => pad(cell, widths[index])).join(" | ")} |`;
|
|
87
|
-
const divider = `| ${widths.map((width) => "-".repeat(width)).join(" | ")} |`;
|
|
88
|
-
return [line(escapedHeaders), divider, ...escapedRows.map(line)].join("\n");
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const list = (values) =>
|
|
92
|
-
values.length === 0 ? "None." : values.map((value) => `\`${value}\``).join(", ");
|
|
93
|
-
|
|
94
|
-
const describeSchema = (schema) => {
|
|
95
|
-
if (!isRecord(schema)) return "unknown";
|
|
96
|
-
if (Array.isArray(schema.enum)) return `enum(${schema.enum.map(String).join(", ")})`;
|
|
97
|
-
if ("const" in schema) return `const(${String(schema.const)})`;
|
|
98
|
-
if (typeof schema.type === "string") {
|
|
99
|
-
if (schema.type === "object") return "object";
|
|
100
|
-
if (schema.type === "array") return `array<${describeSchema(schema.items)}>`;
|
|
101
|
-
return schema.type;
|
|
102
|
-
}
|
|
103
|
-
if (Array.isArray(schema.anyOf)) return "anyOf";
|
|
104
|
-
if (Array.isArray(schema.oneOf)) return "oneOf";
|
|
105
|
-
return "unknown";
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const payloadFields = (schema) => {
|
|
109
|
-
if (!isRecord(schema) || !isRecord(schema.properties)) return "None.";
|
|
110
|
-
const required = new Set(Array.isArray(schema.required) ? schema.required : []);
|
|
111
|
-
const fields = Object.entries(schema.properties).map(([name, fieldSchema]) => {
|
|
112
|
-
const marker = required.has(name) ? "required" : "optional";
|
|
113
|
-
return `\`${name}\`: ${describeSchema(fieldSchema)} (${marker})`;
|
|
114
|
-
});
|
|
115
|
-
return fields.length === 0 ? "None." : fields.join("<br>");
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
const claimSummary = (claim) => {
|
|
119
|
-
if (claim === undefined) return "none";
|
|
120
|
-
if (claim.phase === "pre") return `pre \`${claim.key}\``;
|
|
121
|
-
if (claim.phase === "lived") {
|
|
122
|
-
return `lived \`${claim.key}\`; anchors ${list(claim.anchorKinds ?? [])}`;
|
|
123
|
-
}
|
|
124
|
-
if (claim.phase === "rejected") {
|
|
125
|
-
return `rejected \`${claim.key}\`; rejections ${list(claim.rejectionKinds ?? [])}`;
|
|
126
|
-
}
|
|
127
|
-
return "unknown";
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
const materialSummary = (material) => {
|
|
131
|
-
if (!isRecord(material)) return "unknown";
|
|
132
|
-
const parts = [`${material.required === false ? "optional" : "required"} ${material.kind}`];
|
|
133
|
-
if (typeof material.provider === "string") parts.push(`provider=${material.provider}`);
|
|
134
|
-
if (typeof material.purpose === "string") parts.push(`purpose=${material.purpose}`);
|
|
135
|
-
if (typeof material.protocol === "string") parts.push(`protocol=${material.protocol}`);
|
|
136
|
-
if (typeof material.bindingKind === "string") parts.push(`binding=${material.bindingKind}`);
|
|
137
|
-
if (typeof material.resourceKind === "string") parts.push(`resource=${material.resourceKind}`);
|
|
138
|
-
return parts.join(", ");
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const materialRows = (materials) =>
|
|
142
|
-
materials.map((material) => [
|
|
143
|
-
`\`${material.slot ?? "<unknown>"}\``,
|
|
144
|
-
material.kind ?? "unknown",
|
|
145
|
-
material.required === false ? "no" : "yes",
|
|
146
|
-
[
|
|
147
|
-
typeof material.provider === "string" ? `provider=${material.provider}` : null,
|
|
148
|
-
typeof material.purpose === "string" ? `purpose=${material.purpose}` : null,
|
|
149
|
-
typeof material.protocol === "string" ? `protocol=${material.protocol}` : null,
|
|
150
|
-
typeof material.bindingKind === "string" ? `binding=${material.bindingKind}` : null,
|
|
151
|
-
typeof material.resourceKind === "string" ? `resource=${material.resourceKind}` : null,
|
|
152
|
-
]
|
|
153
|
-
.filter((value) => value !== null)
|
|
154
|
-
.join(", ") || "-",
|
|
155
|
-
]);
|
|
156
|
-
|
|
157
|
-
const authorityRows = (authorities) =>
|
|
158
|
-
authorities.map((authority) => [
|
|
159
|
-
`\`${authority.authorityRef?.authorityId ?? "<unknown>"}\``,
|
|
160
|
-
authority.authorityRef?.authorityClass ?? "unknown",
|
|
161
|
-
(authority.requiredMaterials ?? [])
|
|
162
|
-
.map((material) => `\`${material.slot}\`: ${materialSummary(material)}`)
|
|
163
|
-
.join("<br>") || "None.",
|
|
164
|
-
]);
|
|
165
|
-
|
|
166
|
-
const validateCarrier = (carrier, pkg) => {
|
|
167
|
-
if (carrier.sourcePackageName !== pkg.name) {
|
|
168
|
-
failures.push(
|
|
169
|
-
`${pkg.name}: carrier sourcePackageName ${carrier.sourcePackageName} does not match surface name`,
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
if (carrier.boundaryContract.ownerId !== carrier.ownerId) {
|
|
173
|
-
failures.push(`${carrier.ownerId}: boundaryContract ownerId mismatch`);
|
|
174
|
-
}
|
|
175
|
-
if (carrier.boundaryContract.sourcePackageName !== carrier.sourcePackageName) {
|
|
176
|
-
failures.push(`${carrier.ownerId}: boundaryContract sourcePackageName mismatch`);
|
|
177
|
-
}
|
|
178
|
-
if (
|
|
179
|
-
!Array.isArray(carrier.boundaryContract.kindPrefixes) ||
|
|
180
|
-
carrier.boundaryContract.kindPrefixes.length === 0
|
|
181
|
-
) {
|
|
182
|
-
failures.push(`${carrier.ownerId}: missing kind prefixes`);
|
|
183
|
-
}
|
|
184
|
-
if (
|
|
185
|
-
!isRecord(carrier.boundaryContract.events) ||
|
|
186
|
-
Object.keys(carrier.boundaryContract.events).length === 0
|
|
187
|
-
) {
|
|
188
|
-
failures.push(`${carrier.ownerId}: missing boundary events`);
|
|
189
|
-
}
|
|
190
|
-
if (
|
|
191
|
-
carrier.boundaryContract.settlement?.settlementId !== carrier.settlementContract.settlementId
|
|
192
|
-
) {
|
|
193
|
-
failures.push(`${carrier.ownerId}: settlement contract mismatch`);
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
const validateNamespace = (namespace, pkg) => {
|
|
198
|
-
if (namespace.sourcePackageName !== pkg.name) {
|
|
199
|
-
failures.push(
|
|
200
|
-
`${pkg.name}: namespace sourcePackageName ${namespace.sourcePackageName} does not match surface name`,
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
const carrierModuleEntries = async (file) => {
|
|
206
|
-
const entries = [];
|
|
207
|
-
const mod = await import(pathToFileURL(path.join(root, file)).href);
|
|
208
|
-
for (const [exportName, value] of Object.entries(mod)) {
|
|
209
|
-
entries.push({ exportName, value, file });
|
|
210
|
-
}
|
|
211
|
-
return entries;
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
const exportedNamespace = (entry, version) => {
|
|
215
|
-
if (isEventNamespace(entry.value)) return entry.value;
|
|
216
|
-
if (typeof entry.value !== "function" || !entry.exportName.endsWith("EventNamespace")) {
|
|
217
|
-
return undefined;
|
|
218
|
-
}
|
|
219
|
-
const value = entry.value(version);
|
|
220
|
-
return isEventNamespace(value) ? value : undefined;
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
/** @returns {string[]} */
|
|
224
|
-
const namespaceEventKinds = (entries, prefixes) => {
|
|
225
|
-
/** @type {Set<string>} */
|
|
226
|
-
const events = new Set();
|
|
227
|
-
for (const entry of entries) {
|
|
228
|
-
if (!isRecord(entry.value)) continue;
|
|
229
|
-
if (!entry.exportName.endsWith("EVENTS") && !entry.exportName.endsWith("KIND")) continue;
|
|
230
|
-
for (const value of Object.values(entry.value)) {
|
|
231
|
-
if (typeof value === "string" && prefixes.some((prefix) => value.startsWith(prefix))) {
|
|
232
|
-
events.add(value);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return [...events].sort((left, right) => left.localeCompare(right));
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
const discoverCarriers = async () => {
|
|
240
|
-
const carriers = [];
|
|
241
|
-
const seenOwnerIds = new Set();
|
|
242
|
-
const seenEventKinds = new Set();
|
|
243
|
-
const files = defineCarrierFiles();
|
|
244
|
-
|
|
245
|
-
for (const file of files) {
|
|
246
|
-
const pkg = sourcePackageForFile(file);
|
|
247
|
-
if (pkg === undefined) {
|
|
248
|
-
failures.push(`${file}: defineCarrier declaration is outside a live workspace package`);
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
const entries = await carrierModuleEntries(file);
|
|
252
|
-
const exportedCarriers = [];
|
|
253
|
-
const seenCarrierOwnerIds = new Set();
|
|
254
|
-
for (const entry of entries) {
|
|
255
|
-
if (!isCarrier(entry.value) || seenCarrierOwnerIds.has(entry.value.ownerId)) continue;
|
|
256
|
-
seenCarrierOwnerIds.add(entry.value.ownerId);
|
|
257
|
-
exportedCarriers.push({ exportName: entry.exportName, carrier: entry.value });
|
|
258
|
-
}
|
|
259
|
-
const exportedNamespaces = [];
|
|
260
|
-
const seenNamespaceOwnerIds = new Set();
|
|
261
|
-
for (const entry of entries) {
|
|
262
|
-
const namespace = exportedNamespace(entry, pkg.version ?? "0.2.9");
|
|
263
|
-
if (namespace === undefined || seenNamespaceOwnerIds.has(namespace.ownerId)) continue;
|
|
264
|
-
seenNamespaceOwnerIds.add(namespace.ownerId);
|
|
265
|
-
exportedNamespaces.push({
|
|
266
|
-
exportName: entry.exportName,
|
|
267
|
-
namespace,
|
|
268
|
-
events: namespaceEventKinds(entries, namespace.kindPrefixes),
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
if (exportedCarriers.length > 1) {
|
|
273
|
-
failures.push(`${file}: exports multiple carrier-shaped values`);
|
|
274
|
-
continue;
|
|
275
|
-
}
|
|
276
|
-
if (exportedCarriers.length === 0 && exportedNamespaces.length > 1) {
|
|
277
|
-
failures.push(`${file}: exports multiple namespace-shaped values`);
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
|
-
if (exportedCarriers.length === 0 && exportedNamespaces.length === 0) {
|
|
281
|
-
failures.push(`${file}: defineCarrier declaration exports no carrier or namespace value`);
|
|
282
|
-
continue;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (exportedCarriers.length === 1) {
|
|
286
|
-
const entry = exportedCarriers[0];
|
|
287
|
-
validateCarrier(entry.carrier, pkg);
|
|
288
|
-
|
|
289
|
-
if (seenOwnerIds.has(entry.carrier.ownerId)) {
|
|
290
|
-
failures.push(`${entry.carrier.ownerId}: duplicate carrier ownerId`);
|
|
291
|
-
}
|
|
292
|
-
seenOwnerIds.add(entry.carrier.ownerId);
|
|
293
|
-
|
|
294
|
-
for (const eventKind of Object.keys(entry.carrier.boundaryContract.events)) {
|
|
295
|
-
if (seenEventKinds.has(eventKind)) {
|
|
296
|
-
failures.push(`${entry.carrier.ownerId}: duplicate event kind ${eventKind}`);
|
|
297
|
-
}
|
|
298
|
-
seenEventKinds.add(eventKind);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
carriers.push({
|
|
302
|
-
kind: "carrier",
|
|
303
|
-
pkg,
|
|
304
|
-
file,
|
|
305
|
-
exportName: entry.exportName,
|
|
306
|
-
carrier: entry.carrier,
|
|
307
|
-
});
|
|
308
|
-
continue;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
const entry = exportedNamespaces[0];
|
|
312
|
-
validateNamespace(entry.namespace, pkg);
|
|
313
|
-
if (seenOwnerIds.has(entry.namespace.ownerId)) {
|
|
314
|
-
failures.push(`${entry.namespace.ownerId}: duplicate carrier ownerId`);
|
|
315
|
-
}
|
|
316
|
-
seenOwnerIds.add(entry.namespace.ownerId);
|
|
317
|
-
for (const eventKind of entry.events) {
|
|
318
|
-
if (seenEventKinds.has(eventKind)) {
|
|
319
|
-
failures.push(`${entry.namespace.ownerId}: duplicate event kind ${eventKind}`);
|
|
320
|
-
}
|
|
321
|
-
seenEventKinds.add(eventKind);
|
|
322
|
-
}
|
|
323
|
-
carriers.push({
|
|
324
|
-
kind: "namespace",
|
|
325
|
-
pkg,
|
|
326
|
-
file,
|
|
327
|
-
exportName: entry.exportName,
|
|
328
|
-
namespace: entry.namespace,
|
|
329
|
-
events: entry.events,
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
if (files.length > 0 && carriers.length === 0) {
|
|
334
|
-
failures.push(
|
|
335
|
-
`carrier reference projected zero carriers from ${files.length} defineCarrier declaration file(s)`,
|
|
336
|
-
);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return carriers.sort((left, right) =>
|
|
340
|
-
(left.kind === "carrier" ? left.carrier.ownerId : left.namespace.ownerId).localeCompare(
|
|
341
|
-
right.kind === "carrier" ? right.carrier.ownerId : right.namespace.ownerId,
|
|
342
|
-
),
|
|
343
|
-
);
|
|
344
|
-
};
|
|
345
|
-
|
|
346
|
-
const renderCarrier = ({ pkg, file, exportName, carrier }) => {
|
|
347
|
-
const boundary = carrier.boundaryContract;
|
|
348
|
-
const settlement = carrier.settlementContract;
|
|
349
|
-
const eventRows = Object.entries(boundary.events)
|
|
350
|
-
.sort(([left], [right]) => left.localeCompare(right))
|
|
351
|
-
.map(([eventKind, contract]) => [
|
|
352
|
-
`\`${eventKind}\``,
|
|
353
|
-
claimSummary(contract.claim),
|
|
354
|
-
payloadFields(contract.payloadSchema),
|
|
355
|
-
]);
|
|
356
|
-
|
|
357
|
-
const sections = [
|
|
358
|
-
`## ${carrier.ownerId}`,
|
|
359
|
-
"",
|
|
360
|
-
`Source package: \`${pkg.name}\``,
|
|
361
|
-
"",
|
|
362
|
-
`Source file: \`${file}\``,
|
|
363
|
-
"",
|
|
364
|
-
`Export: \`${exportName}\``,
|
|
365
|
-
"",
|
|
366
|
-
`Prefix: \`${carrier.prefix}\``,
|
|
367
|
-
"",
|
|
368
|
-
`Roles: ${list(boundary.roles ?? [])}`,
|
|
369
|
-
"",
|
|
370
|
-
"### Event Kinds",
|
|
371
|
-
"",
|
|
372
|
-
table(["Event kind", "Claim", "Payload fields"], eventRows),
|
|
373
|
-
"",
|
|
374
|
-
"### Settlement Vocabulary",
|
|
375
|
-
"",
|
|
376
|
-
`Settlement id: \`${settlement.settlementId}\``,
|
|
377
|
-
"",
|
|
378
|
-
`Anchor kinds: ${list(settlement.anchorKinds ?? [])}`,
|
|
379
|
-
"",
|
|
380
|
-
`Rejection kinds: ${list(settlement.rejectionKinds ?? [])}`,
|
|
381
|
-
"",
|
|
382
|
-
"### Authority Requirements",
|
|
383
|
-
"",
|
|
384
|
-
(boundary.effectAuthorityContracts ?? []).length === 0
|
|
385
|
-
? "None."
|
|
386
|
-
: table(
|
|
387
|
-
["Authority", "Class", "Required materials"],
|
|
388
|
-
authorityRows(boundary.effectAuthorityContracts),
|
|
389
|
-
),
|
|
390
|
-
"",
|
|
391
|
-
"### Material Requirements",
|
|
392
|
-
"",
|
|
393
|
-
(boundary.materialRequirements ?? []).length === 0
|
|
394
|
-
? "None."
|
|
395
|
-
: table(["Slot", "Kind", "Required", "Details"], materialRows(boundary.materialRequirements)),
|
|
396
|
-
"",
|
|
397
|
-
];
|
|
398
|
-
|
|
399
|
-
return sections.join("\n");
|
|
400
|
-
};
|
|
401
|
-
|
|
402
|
-
const renderNamespace = ({ pkg, file, exportName, namespace, events }) => {
|
|
403
|
-
const eventRows = events.map((eventKind) => [`\`${eventKind}\``, "namespace-only", "None."]);
|
|
404
|
-
return [
|
|
405
|
-
`## ${namespace.ownerId}`,
|
|
406
|
-
"",
|
|
407
|
-
`Source package: \`${pkg.name}\``,
|
|
408
|
-
"",
|
|
409
|
-
`Source file: \`${file}\``,
|
|
410
|
-
"",
|
|
411
|
-
`Export: \`${exportName}\``,
|
|
412
|
-
"",
|
|
413
|
-
`Prefix: ${list(namespace.kindPrefixes)}`,
|
|
414
|
-
"",
|
|
415
|
-
"Roles: `reader`",
|
|
416
|
-
"",
|
|
417
|
-
"### Event Kinds",
|
|
418
|
-
"",
|
|
419
|
-
eventRows.length === 0 ? "None." : table(["Event kind", "Claim", "Payload fields"], eventRows),
|
|
420
|
-
"",
|
|
421
|
-
"### Settlement Vocabulary",
|
|
422
|
-
"",
|
|
423
|
-
"None.",
|
|
424
|
-
"",
|
|
425
|
-
"### Authority Requirements",
|
|
426
|
-
"",
|
|
427
|
-
"None.",
|
|
428
|
-
"",
|
|
429
|
-
"### Material Requirements",
|
|
430
|
-
"",
|
|
431
|
-
"None.",
|
|
432
|
-
"",
|
|
433
|
-
].join("\n");
|
|
434
|
-
};
|
|
435
|
-
|
|
436
|
-
const renderReference = (carriers) => {
|
|
437
|
-
const summaryRows = carriers.map((entry) => [
|
|
438
|
-
`\`${entry.kind === "carrier" ? entry.carrier.ownerId : entry.namespace.ownerId}\``,
|
|
439
|
-
`\`${entry.pkg.name}\``,
|
|
440
|
-
entry.kind === "carrier" ? `\`${entry.carrier.prefix}\`` : list(entry.namespace.kindPrefixes),
|
|
441
|
-
String(
|
|
442
|
-
entry.kind === "carrier"
|
|
443
|
-
? Object.keys(entry.carrier.boundaryContract.events).length
|
|
444
|
-
: entry.events.length,
|
|
445
|
-
),
|
|
446
|
-
entry.kind === "carrier" ? list(entry.carrier.boundaryContract.roles ?? []) : "`reader`",
|
|
447
|
-
]);
|
|
448
|
-
|
|
449
|
-
const sections = carriers.map((entry) =>
|
|
450
|
-
entry.kind === "carrier" ? renderCarrier(entry) : renderNamespace(entry),
|
|
451
|
-
);
|
|
452
|
-
|
|
453
|
-
return [
|
|
454
|
-
"# Carrier Reference",
|
|
455
|
-
"",
|
|
456
|
-
generatedNotice,
|
|
457
|
-
"",
|
|
458
|
-
"Generated from live `defineCarrier` declarations. Package docs explain intent; this page owns event, schema, settlement, authority, and material reference facts.",
|
|
459
|
-
"",
|
|
460
|
-
"## Carriers",
|
|
461
|
-
"",
|
|
462
|
-
table(["Owner", "Source package", "Prefix", "Events", "Roles"], summaryRows),
|
|
463
|
-
"",
|
|
464
|
-
...sections,
|
|
465
|
-
].join("\n");
|
|
466
|
-
};
|
|
467
|
-
|
|
468
|
-
const carriers = await discoverCarriers();
|
|
469
|
-
const expected = `${renderReference(carriers).replace(/\s+$/u, "")}\n`;
|
|
470
|
-
const targetPath = path.join(root, target);
|
|
471
|
-
const carrierReferenceSourceFacts = {
|
|
472
|
-
kind: "source-set",
|
|
473
|
-
ref: "docs.generate-carrier-reference.source-facts",
|
|
474
|
-
sources: [{ kind: "carrier-declaration", ref: "defineCarrier declarations under packages/**" }],
|
|
475
|
-
};
|
|
476
|
-
const projection = defineProjectionSpec({
|
|
477
|
-
id: `docs.generate-carrier-reference:${target}`,
|
|
478
|
-
version: 1,
|
|
479
|
-
source: carrierReferenceSourceFacts,
|
|
480
|
-
project: (output, ctx) => ctx.ok(output),
|
|
481
|
-
});
|
|
482
|
-
const sink = {
|
|
483
|
-
id: target,
|
|
484
|
-
read: () =>
|
|
485
|
-
fs.existsSync(targetPath)
|
|
486
|
-
? { _tag: "found", output: fs.readFileSync(targetPath, "utf8") }
|
|
487
|
-
: { _tag: "missing" },
|
|
488
|
-
write: (output) => {
|
|
489
|
-
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
490
|
-
fs.writeFileSync(targetPath, output);
|
|
491
|
-
},
|
|
492
|
-
equals: (actual, projected) => actual === projected,
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
if (check) {
|
|
496
|
-
const result = await checkProjectionSink(projection, expected, sink);
|
|
497
|
-
if (result._tag === "projection_failed") {
|
|
498
|
-
failures.push(`${target} projection failed: ${result.result.reason}`);
|
|
499
|
-
} else if (result._tag === "stale") {
|
|
500
|
-
failures.push(`${target} is stale`);
|
|
501
|
-
}
|
|
502
|
-
} else {
|
|
503
|
-
const result = await runProjectionSink(projection, expected, sink);
|
|
504
|
-
if (result._tag === "projection_failed") {
|
|
505
|
-
failures.push(`${target} projection failed: ${result.result.reason}`);
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
if (failures.length > 0) {
|
|
510
|
-
console.error(failures.join("\n"));
|
|
511
|
-
process.exit(1);
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
console.log(`${check ? "checked" : "generated"} carrier reference for ${carriers.length} carriers`);
|