@yansirplus/cli 0.5.17

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.
Files changed (47) hide show
  1. package/PUBLIC_API.md +22 -0
  2. package/README.md +34 -0
  3. package/dist/build/agent-authoring/config.d.ts +177 -0
  4. package/dist/build/agent-authoring/config.js +607 -0
  5. package/dist/build/agent-authoring/manifest-compiler.d.ts +159 -0
  6. package/dist/build/agent-authoring/manifest-compiler.js +737 -0
  7. package/dist/build/agent-authoring/shared.d.ts +10 -0
  8. package/dist/build/agent-authoring/shared.js +57 -0
  9. package/dist/build/agent-authoring/static-target.d.ts +59 -0
  10. package/dist/build/agent-authoring/static-target.js +1857 -0
  11. package/dist/build/agent-authoring.d.ts +9 -0
  12. package/dist/build/agent-authoring.js +5 -0
  13. package/dist/build/build-cli.d.ts +2 -0
  14. package/dist/build/build-cli.js +264 -0
  15. package/dist/check/algorithmic/architecture-checks.mjs +971 -0
  16. package/dist/check/algorithmic/client-boundary-checks.mjs +337 -0
  17. package/dist/check/algorithmic/convergence-smoke-checks.mjs +608 -0
  18. package/dist/check/algorithmic/distribution-checks.mjs +919 -0
  19. package/dist/check/algorithmic/owner-checks.mjs +647 -0
  20. package/dist/check/algorithmic/package-boundary-checks.mjs +985 -0
  21. package/dist/check/algorithmic/projection-boundary-checks.mjs +302 -0
  22. package/dist/check/algorithmic/repo-surface-checks.mjs +267 -0
  23. package/dist/check/algorithmic/runtime-structural-checks.mjs +264 -0
  24. package/dist/check/algorithmic/source-alias-checks.mjs +106 -0
  25. package/dist/check/algorithmic/static-target-checks.mjs +447 -0
  26. package/dist/check/algorithmic-checks.mjs +482 -0
  27. package/dist/check/check-coverage.mjs +231 -0
  28. package/dist/check/command-runner.mjs +22 -0
  29. package/dist/check/default-gate.mjs +51 -0
  30. package/dist/check/gate-selector.mjs +305 -0
  31. package/dist/check/manifest-rules.mjs +223 -0
  32. package/dist/check/package-graph.mjs +464 -0
  33. package/dist/generate/generate-agent-docs.mjs +435 -0
  34. package/dist/generate/generate-carrier-reference.mjs +514 -0
  35. package/dist/generate/generate-docs.mjs +345 -0
  36. package/dist/generate/generate-effect-skill-manifests.mjs +193 -0
  37. package/dist/generate/project-docs-site.mjs +190 -0
  38. package/dist/index.d.ts +2 -0
  39. package/dist/index.js +25 -0
  40. package/dist/lib/agent-docs-model.mjs +888 -0
  41. package/dist/lib/boundary-rules.mjs +63 -0
  42. package/dist/lib/capability-routes.mjs +354 -0
  43. package/dist/lib/projection-sink.mjs +113 -0
  44. package/dist/lib/public-api-model.mjs +306 -0
  45. package/dist/main.mjs +233 -0
  46. package/dist/runner.mjs +127 -0
  47. package/package.json +32 -0
@@ -0,0 +1,337 @@
1
+ export const createClientBoundaryChecks = ({
2
+ fs,
3
+ path,
4
+ repoRoot,
5
+ read,
6
+ readJson,
7
+ walk,
8
+ failIfAny,
9
+ }) => {
10
+ const clientBoundaryPackages = {
11
+ clientCore: "@agent-os/client",
12
+ clientReact: "@agent-os/client/react",
13
+ clientSvelte: "@agent-os/client/svelte",
14
+ runtime: "@agent-os/runtime",
15
+ workspaceAgent: "@agent-os/workspace-agent",
16
+ agUiReact: "@agent-os/ag-ui-react",
17
+ agUiSvelte: "@agent-os/ag-ui-svelte",
18
+ };
19
+
20
+ const clientFrameworkSubpaths = [
21
+ {
22
+ specifier: clientBoundaryPackages.clientReact,
23
+ pathPrefix: "packages/client/src/react/",
24
+ framework: "react",
25
+ },
26
+ {
27
+ specifier: clientBoundaryPackages.clientSvelte,
28
+ pathPrefix: "packages/client/src/svelte/",
29
+ framework: "svelte",
30
+ },
31
+ ];
32
+
33
+ const clientSourceFilePattern = /\.(?:ts|tsx|mts|cts|jsx|js|mjs|cjs|svelte|css|scss|less)$/u;
34
+ const clientTypeScriptOnlyPattern = /\.ts$/u;
35
+
36
+ const readJsonFile = (file) => JSON.parse(fs.readFileSync(file, "utf8"));
37
+
38
+ const workspacePackageRecords = () => {
39
+ const rootPackage = readJson("package.json");
40
+ const workspaces = Array.isArray(rootPackage.workspaces)
41
+ ? rootPackage.workspaces
42
+ : Array.isArray(rootPackage.workspaces?.packages)
43
+ ? rootPackage.workspaces.packages
44
+ : [];
45
+ const records = [];
46
+
47
+ for (const workspace of workspaces) {
48
+ if (typeof workspace !== "string") continue;
49
+ if (workspace.endsWith("/*")) {
50
+ const base = workspace.slice(0, -2);
51
+ const baseDir = path.join(repoRoot, base);
52
+ if (!fs.existsSync(baseDir)) continue;
53
+ for (const entry of fs.readdirSync(baseDir, { withFileTypes: true })) {
54
+ if (!entry.isDirectory()) continue;
55
+ const packagePath = `${base}/${entry.name}`;
56
+ const packageJsonPath = path.join(repoRoot, packagePath, "package.json");
57
+ if (!fs.existsSync(packageJsonPath)) continue;
58
+ records.push({ name: readJsonFile(packageJsonPath).name, path: packagePath });
59
+ }
60
+ continue;
61
+ }
62
+
63
+ const packageJsonPath = path.join(repoRoot, workspace, "package.json");
64
+ if (!fs.existsSync(packageJsonPath)) continue;
65
+ records.push({ name: readJsonFile(packageJsonPath).name, path: workspace });
66
+ }
67
+
68
+ return records.sort((left, right) => left.path.localeCompare(right.path));
69
+ };
70
+
71
+ const clientImportSpecifiers = (source) => {
72
+ const specifiers = [];
73
+ const patterns = [
74
+ /\b(?:import|export)\s+(?:type\s+)?(?:[^"'()]*?\s+from\s+)?["']([^"']+)["']/gu,
75
+ /\bimport\s*\(\s*["']([^"']+)["']\s*\)/gu,
76
+ ];
77
+ for (const pattern of patterns) {
78
+ for (const match of source.matchAll(pattern)) specifiers.push(match[1]);
79
+ }
80
+ return specifiers;
81
+ };
82
+
83
+ const clientImportMatches = (specifier, packageName) =>
84
+ specifier === packageName || specifier.startsWith(`${packageName}/`);
85
+
86
+ const clientSectionBody = (source, heading) => {
87
+ const start = source.indexOf(`## ${heading}`);
88
+ if (start === -1) return "";
89
+ const rest = source.slice(start + heading.length + 3);
90
+ const next = rest.search(/^## /mu);
91
+ return next === -1 ? rest : rest.slice(0, next);
92
+ };
93
+
94
+ const clientPackageByName = (packages, name) => packages.find((record) => record.name === name);
95
+
96
+ const clientPackageSourceFiles = (record) =>
97
+ walk(`${record.path}/src`).filter((file) => clientSourceFilePattern.test(path.basename(file)));
98
+
99
+ const checkClientTypeScriptOnlySource = ({ record, failures }) => {
100
+ for (const file of clientPackageSourceFiles(record)) {
101
+ if (!clientTypeScriptOnlyPattern.test(path.basename(file))) {
102
+ failures.push(
103
+ `${file}: client-boundary-source: client/framework packages may contain .ts source only`,
104
+ );
105
+ }
106
+ }
107
+ };
108
+
109
+ const checkClientFrameworkImports = ({ record, kind, failures }) => {
110
+ const recordAllowedFramework =
111
+ record.name === clientBoundaryPackages.agUiReact
112
+ ? "react"
113
+ : record.name === clientBoundaryPackages.agUiSvelte
114
+ ? "svelte"
115
+ : null;
116
+ const frameworkPackages = ["react", "svelte", "svelte/store"];
117
+
118
+ for (const file of clientPackageSourceFiles(record)) {
119
+ const subpathAllowedFramework =
120
+ clientFrameworkSubpaths.find((subpath) => file.startsWith(subpath.pathPrefix))?.framework ??
121
+ null;
122
+ const allowedFramework = subpathAllowedFramework ?? recordAllowedFramework;
123
+ const source = read(file);
124
+ for (const specifier of clientImportSpecifiers(source)) {
125
+ const frameworkImport = frameworkPackages.find((framework) =>
126
+ clientImportMatches(specifier, framework),
127
+ );
128
+ if (frameworkImport === undefined) continue;
129
+ if (allowedFramework === null) {
130
+ failures.push(
131
+ `${file}: client-boundary-framework-import: ${kind} package must not import ${frameworkImport}`,
132
+ );
133
+ } else if (!clientImportMatches(frameworkImport, allowedFramework)) {
134
+ failures.push(
135
+ `${file}: client-boundary-framework-import: ${record.name} must not import ${frameworkImport}`,
136
+ );
137
+ }
138
+ }
139
+ }
140
+ };
141
+
142
+ const checkClientFrameworkBridgeReadModels = ({ record, failures }) => {
143
+ for (const file of clientPackageSourceFiles(record)) {
144
+ if (
145
+ record.name !== clientBoundaryPackages.agUiReact &&
146
+ record.name !== clientBoundaryPackages.agUiSvelte &&
147
+ !clientFrameworkSubpaths.some((subpath) => file.startsWith(subpath.pathPrefix))
148
+ ) {
149
+ continue;
150
+ }
151
+ const source = read(file);
152
+ const objectExportPatterns = [
153
+ /\bexport\s+interface\s+([A-Za-z_$][\w$]*)[^{]*\{/gu,
154
+ /\bexport\s+type\s+([A-Za-z_$][\w$]*)[^=]*=\s*\{/gu,
155
+ ];
156
+ for (const pattern of objectExportPatterns) {
157
+ for (const match of source.matchAll(pattern)) {
158
+ failures.push(
159
+ `${file}: client-boundary-read-model: framework bridges must not declare exported object read-model type ${match[1]}; define canonical DTOs in runtime-protocol, runtime AG-UI projection types, or client core`,
160
+ );
161
+ }
162
+ }
163
+ }
164
+ };
165
+
166
+ const checkClientRetiredImports = ({ records, failures }) => {
167
+ const retiredNames = [clientBoundaryPackages.agUiReact, clientBoundaryPackages.agUiSvelte];
168
+ for (const record of records) {
169
+ for (const file of clientPackageSourceFiles(record)) {
170
+ const source = read(file);
171
+ for (const specifier of clientImportSpecifiers(source)) {
172
+ for (const retiredName of retiredNames) {
173
+ if (record.name !== retiredName && clientImportMatches(specifier, retiredName)) {
174
+ failures.push(
175
+ `${file}: client-boundary-retired-import: ${record.name} imports retired framework package ${retiredName}`,
176
+ );
177
+ }
178
+ }
179
+ }
180
+ }
181
+ }
182
+ };
183
+
184
+ const checkClientRetiredPackageWindow = ({ surfacePackages, records, failures }) => {
185
+ const retiredFrameworkPackages = [
186
+ { retired: clientBoundaryPackages.agUiReact, successor: clientBoundaryPackages.clientReact },
187
+ {
188
+ retired: clientBoundaryPackages.agUiSvelte,
189
+ successor: clientBoundaryPackages.clientSvelte,
190
+ },
191
+ ];
192
+
193
+ for (const item of retiredFrameworkPackages) {
194
+ const retiredRecord = clientPackageByName(records, item.retired);
195
+ const retiredSurface = clientPackageByName(surfacePackages, item.retired);
196
+ const successorRecord = clientPackageByName(records, clientBoundaryPackages.clientCore);
197
+ const successorSurface = clientPackageByName(
198
+ surfacePackages,
199
+ clientBoundaryPackages.clientCore,
200
+ );
201
+
202
+ if (
203
+ (successorRecord !== undefined || successorSurface !== undefined) &&
204
+ retiredRecord !== undefined
205
+ ) {
206
+ failures.push(
207
+ `${retiredRecord.path}: client-boundary-retired-surface: ${item.retired} must be deleted once ${item.successor} exists`,
208
+ );
209
+ }
210
+ if (
211
+ (successorRecord !== undefined || successorSurface !== undefined) &&
212
+ retiredSurface !== undefined
213
+ ) {
214
+ failures.push(
215
+ `docs/surface.json: client-boundary-retired-surface: ${item.retired} must leave the public surface once ${item.successor} exists`,
216
+ );
217
+ }
218
+ if (retiredRecord === undefined && retiredSurface === undefined) continue;
219
+ if (retiredSurface === undefined) {
220
+ failures.push(
221
+ `${item.retired}: client-boundary-retired-surface: retired workspace package must remain source-owned in docs/surface.json until deletion`,
222
+ );
223
+ continue;
224
+ }
225
+ if (!String(retiredSurface.status ?? "").startsWith("retired")) {
226
+ failures.push(
227
+ `docs/surface.json: client-boundary-retired-surface: ${item.retired} must have retired status before deletion`,
228
+ );
229
+ }
230
+ if (!String(retiredSurface.apiStatus ?? "").includes("scheduled for deletion")) {
231
+ failures.push(
232
+ `docs/surface.json: client-boundary-retired-surface: ${item.retired} apiStatus must declare deletion, not compatibility preservation`,
233
+ );
234
+ }
235
+ if (retiredSurface.apiSource !== undefined) {
236
+ const apiSourcePath = path.join(repoRoot, retiredSurface.apiSource);
237
+ if (fs.existsSync(apiSourcePath)) {
238
+ const apiSource = fs.readFileSync(apiSourcePath, "utf8");
239
+ if (clientSectionBody(apiSource, "Public exports").trim() !== "None.") {
240
+ failures.push(
241
+ `${retiredSurface.apiSource}: client-boundary-retired-surface: retired package must expose no active public exports`,
242
+ );
243
+ }
244
+ if (!clientSectionBody(apiSource, "Deprecated exports").includes("`.:")) {
245
+ failures.push(
246
+ `${retiredSurface.apiSource}: client-boundary-retired-surface: retired exports must be declared as deprecated until deletion`,
247
+ );
248
+ }
249
+ }
250
+ }
251
+ }
252
+ };
253
+
254
+ const checkClientCanonicalSurface = ({ surfacePackages, failures }) => {
255
+ const runtime = clientPackageByName(surfacePackages, clientBoundaryPackages.runtime);
256
+ if (runtime === undefined) {
257
+ failures.push(
258
+ "docs/surface.json: client-boundary-canonical-surface: @agent-os/runtime missing",
259
+ );
260
+ return;
261
+ }
262
+ if (!String(runtime.boundary ?? "").includes("./ag-ui")) {
263
+ failures.push(
264
+ "docs/surface.json: client-boundary-canonical-surface: @agent-os/runtime must declare ./ag-ui as the AG-UI wire projection subpath",
265
+ );
266
+ }
267
+ if (!String(runtime.boundary ?? "").includes("runtime-protocol Recorded vocabulary")) {
268
+ failures.push(
269
+ "docs/surface.json: client-boundary-canonical-surface: @agent-os/runtime ./ag-ui boundary must state client state remains runtime-protocol Recorded vocabulary",
270
+ );
271
+ }
272
+ };
273
+
274
+ const checkClientBoundaryDoc = (failures) => {
275
+ const boundaryPath = "packages/cli/src/check/sources/client-workspace-host-boundary.md";
276
+ if (!fs.existsSync(path.join(repoRoot, boundaryPath))) {
277
+ failures.push(
278
+ `${boundaryPath}: client-boundary-contract: missing source-owned boundary freeze`,
279
+ );
280
+ return;
281
+ }
282
+ const source = read(boundaryPath);
283
+ for (const marker of [
284
+ "client state is a projection sink plus a command surface",
285
+ "`@agent-os/runtime/ag-ui` is a framework-neutral opt-in wire projection",
286
+ "`@agent-os/client/react` and `@agent-os/client/svelte` are the only framework",
287
+ "Projection reads are replayable/read-model surfaces",
288
+ "one driver mount",
289
+ "projection sink configuration[]",
290
+ ]) {
291
+ if (!source.includes(marker)) {
292
+ failures.push(`${boundaryPath}: client-boundary-contract: missing marker ${marker}`);
293
+ }
294
+ }
295
+ };
296
+
297
+ const checkClientBoundaries = () => {
298
+ const failures = [];
299
+ const surface = readJson("docs/surface.json");
300
+ const surfacePackages = Array.isArray(surface.packages) ? surface.packages : [];
301
+ const records = workspacePackageRecords();
302
+
303
+ checkClientBoundaryDoc(failures);
304
+ checkClientCanonicalSurface({ surfacePackages, failures });
305
+ checkClientRetiredPackageWindow({ surfacePackages, records, failures });
306
+ checkClientRetiredImports({ records, failures });
307
+
308
+ const guardedNames = new Set([
309
+ clientBoundaryPackages.clientCore,
310
+ clientBoundaryPackages.agUiReact,
311
+ clientBoundaryPackages.agUiSvelte,
312
+ ]);
313
+ for (const record of records) {
314
+ if (!guardedNames.has(record.name)) continue;
315
+ checkClientTypeScriptOnlySource({ record, failures });
316
+ const kind =
317
+ record.name === clientBoundaryPackages.clientCore ? "client core" : "framework bridge";
318
+ checkClientFrameworkImports({ record, kind, failures });
319
+ if (
320
+ record.name === clientBoundaryPackages.clientCore ||
321
+ record.name === clientBoundaryPackages.agUiReact ||
322
+ record.name === clientBoundaryPackages.agUiSvelte
323
+ ) {
324
+ checkClientFrameworkBridgeReadModels({ record, failures });
325
+ }
326
+ }
327
+
328
+ failIfAny("client boundaries", failures);
329
+ };
330
+
331
+ return {
332
+ workspacePackageRecords,
333
+ clientSectionBody,
334
+ clientPackageByName,
335
+ checkClientBoundaries,
336
+ };
337
+ };