@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.
Files changed (53) hide show
  1. package/README.md +12 -6
  2. package/agent-catalog/agentOS/SKILL.md +22 -0
  3. package/agent-catalog/agentOS/references/agent/decision-graph.json +530 -0
  4. package/agent-catalog/agentOS/references/agent/errors.json +497 -0
  5. package/agent-catalog/agentOS/references/agent/invariant-matrix.json +337 -0
  6. package/agent-catalog/agentOS/references/agent/primitives.json +989 -0
  7. package/agent-catalog/agentOS/references/agent/recipes.json +109 -0
  8. package/agent-catalog/agentOS/references/agent/start-here.md +25 -0
  9. package/agent-catalog/agentOS/references/package-map.md +73 -0
  10. package/agent-catalog/agentOS/references/provenance.json +251 -0
  11. package/agent-catalog/agentOS/references/public-api/cli.md +20 -0
  12. package/agent-catalog/agentOS/references/public-api/client.md +90 -0
  13. package/agent-catalog/agentOS/references/public-api/core.md +1907 -0
  14. package/agent-catalog/agentOS/references/public-api/runtime.md +843 -0
  15. package/dist/build/agent-authoring/config.d.ts +20 -5
  16. package/dist/build/agent-authoring/config.js +132 -32
  17. package/dist/build/agent-authoring/manifest-compiler.d.ts +131 -2
  18. package/dist/build/agent-authoring/manifest-compiler.js +630 -8
  19. package/dist/build/agent-authoring/shared.d.ts +2 -0
  20. package/dist/build/agent-authoring/shared.js +2 -0
  21. package/dist/build/agent-authoring/static-target.d.ts +6 -3
  22. package/dist/build/agent-authoring/static-target.js +1900 -281
  23. package/dist/build/agent-authoring.d.ts +3 -3
  24. package/dist/build/agent-authoring.js +1 -1
  25. package/dist/build/build-cli.d.ts +1 -1
  26. package/dist/build/build-cli.js +1629 -26
  27. package/dist/check/algorithmic/client-boundary-checks.mjs +3 -34
  28. package/dist/check/algorithmic/convergence-smoke-checks.mjs +652 -6
  29. package/dist/check/algorithmic/distribution-checks.mjs +8 -7
  30. package/dist/check/algorithmic/package-boundary-checks.mjs +3 -2
  31. package/dist/check/algorithmic/repo-surface-checks.mjs +55 -1
  32. package/dist/check/algorithmic/static-target-checks.mjs +83 -5
  33. package/dist/check/algorithmic-checks.mjs +10 -17
  34. package/dist/check/default-gate.mjs +3 -3
  35. package/dist/check/effect-scan-gate.mjs +121 -0
  36. package/dist/check/package-graph.mjs +2 -32
  37. package/dist/consumer-overlay.mjs +1281 -0
  38. package/dist/lib/public-api-model.mjs +19 -0
  39. package/dist/lib/repo-source-files.mjs +26 -0
  40. package/dist/lib/ts-module-loader.mjs +44 -0
  41. package/dist/lib/workspace-manifest.mjs +77 -0
  42. package/dist/main.mjs +171 -21
  43. package/dist/release-status.mjs +515 -0
  44. package/package.json +8 -4
  45. package/dist/check/check-coverage.mjs +0 -231
  46. package/dist/generate/generate-agent-docs.mjs +0 -435
  47. package/dist/generate/generate-carrier-reference.mjs +0 -514
  48. package/dist/generate/generate-docs.mjs +0 -345
  49. package/dist/generate/generate-effect-skill-manifests.mjs +0 -193
  50. package/dist/generate/project-docs-site.mjs +0 -190
  51. package/dist/lib/boundary-rules.mjs +0 -63
  52. package/dist/lib/capability-routes.mjs +0 -354
  53. package/dist/lib/projection-sink.mjs +0 -113
@@ -0,0 +1,515 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import crypto from "node:crypto";
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+
6
+ import {
7
+ consumerStatusData,
8
+ exportEquivalenceForInstallManifest,
9
+ resolveConsumerRoot,
10
+ } from "./consumer-overlay.mjs";
11
+
12
+ const releaseStatusSchemaVersion = 1;
13
+
14
+ const readJson = (file) => JSON.parse(fs.readFileSync(file, "utf8"));
15
+
16
+ const sha256File = (file) =>
17
+ crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex");
18
+
19
+ const parseArgs = (args) => {
20
+ const parsed = { _: [] };
21
+ const booleanKeys = new Set(["json", "check-npm"]);
22
+ for (let index = 0; index < args.length; index += 1) {
23
+ const arg = args[index];
24
+ if (!arg.startsWith("--")) {
25
+ parsed._.push(arg);
26
+ continue;
27
+ }
28
+ const eq = arg.indexOf("=");
29
+ if (eq >= 0) {
30
+ parsed[arg.slice(2, eq)] = arg.slice(eq + 1);
31
+ continue;
32
+ }
33
+ const key = arg.slice(2);
34
+ if (booleanKeys.has(key)) {
35
+ parsed[key] = true;
36
+ continue;
37
+ }
38
+ const next = args[index + 1];
39
+ if (next !== undefined && !next.startsWith("--")) {
40
+ parsed[key] = next;
41
+ index += 1;
42
+ } else {
43
+ parsed[key] = true;
44
+ }
45
+ }
46
+ return parsed;
47
+ };
48
+
49
+ const boolArg = (args, name) => args[name] === true || args[name] === "true";
50
+
51
+ const gitValue = (cwd, args) => {
52
+ const result = spawnSync("git", args, {
53
+ cwd,
54
+ encoding: "utf8",
55
+ stdio: ["ignore", "pipe", "ignore"],
56
+ });
57
+ if (result.status !== 0) return undefined;
58
+ const value = result.stdout.trim();
59
+ return value.length === 0 ? undefined : value;
60
+ };
61
+
62
+ const gitSourceProjection = (sourceRoot) => {
63
+ if (typeof sourceRoot !== "string") {
64
+ return {
65
+ owner: "git",
66
+ status: "unavailable",
67
+ reason: "source checkout identity is unavailable in this CLI installation",
68
+ };
69
+ }
70
+ const branch = gitValue(sourceRoot, ["branch", "--show-current"]) ?? "unknown";
71
+ const head = gitValue(sourceRoot, ["rev-parse", "HEAD"]) ?? "unknown";
72
+ const statusShort = gitValue(sourceRoot, ["status", "--short"]);
73
+ const dirty = statusShort === undefined ? undefined : statusShort.length !== 0;
74
+ const upstreamRef = gitValue(sourceRoot, [
75
+ "rev-parse",
76
+ "--abbrev-ref",
77
+ "--symbolic-full-name",
78
+ "@{upstream}",
79
+ ]);
80
+ let upstream = { status: "not_configured" };
81
+ if (upstreamRef !== undefined) {
82
+ const counts = gitValue(sourceRoot, [
83
+ "rev-list",
84
+ "--left-right",
85
+ "--count",
86
+ `${upstreamRef}...HEAD`,
87
+ ]);
88
+ const [behindRaw, aheadRaw] = counts?.split(/\s+/u) ?? [];
89
+ upstream = {
90
+ status: "configured",
91
+ ref: upstreamRef,
92
+ ahead: Number(aheadRaw ?? 0),
93
+ behind: Number(behindRaw ?? 0),
94
+ };
95
+ }
96
+ return {
97
+ owner: "git",
98
+ status: "available",
99
+ repoRoot: sourceRoot,
100
+ branch,
101
+ head,
102
+ dirty: dirty ?? false,
103
+ upstream,
104
+ };
105
+ };
106
+
107
+ const releasePackagePath = (context) => {
108
+ const sourcePackage = path.join(context.sourceRoot ?? "", "package.json");
109
+ if (typeof context.sourceRoot === "string" && fs.existsSync(sourcePackage)) return sourcePackage;
110
+ return path.join(context.packageRoot ?? process.cwd(), "package.json");
111
+ };
112
+
113
+ const releaseIdentityProjection = (context) => {
114
+ const packagePath = releasePackagePath(context);
115
+ const manifest = readJson(packagePath);
116
+ const packageName = typeof manifest.name === "string" ? manifest.name : undefined;
117
+ const packageScope = packageName?.startsWith("@") ? packageName.split("/")[0] : undefined;
118
+ return {
119
+ owner: "package.json#agentOsRelease",
120
+ packageJson: packagePath,
121
+ packageName,
122
+ version:
123
+ typeof manifest.agentOsRelease?.version === "string"
124
+ ? manifest.agentOsRelease.version
125
+ : manifest.version,
126
+ npmScope:
127
+ typeof manifest.agentOsRelease?.npmScope === "string"
128
+ ? manifest.agentOsRelease.npmScope
129
+ : packageScope,
130
+ npmAccess: manifest.agentOsRelease?.npmAccess,
131
+ };
132
+ };
133
+
134
+ const sourcePackageScope = "@agent-os";
135
+
136
+ const publicPackageName = (sourceName, npmScope) => {
137
+ if (typeof npmScope !== "string" || !sourceName.startsWith(`${sourcePackageScope}/`)) {
138
+ return sourceName;
139
+ }
140
+ return `${npmScope}/${sourceName.slice(sourcePackageScope.length + 1)}`;
141
+ };
142
+
143
+ const publishedPackagesProjection = (context, release) => {
144
+ const surfacePath =
145
+ typeof context.sourceRoot === "string"
146
+ ? path.join(context.sourceRoot, "docs", "surface.json")
147
+ : undefined;
148
+ if (surfacePath === undefined || !fs.existsSync(surfacePath)) {
149
+ return [];
150
+ }
151
+ const surface = readJson(surfacePath);
152
+ return (surface.packages ?? [])
153
+ .filter((pkg) => pkg?.published === true && typeof pkg.name === "string")
154
+ .map((pkg) => ({
155
+ sourceName: pkg.name,
156
+ publicName: publicPackageName(pkg.name, release.npmScope),
157
+ path: pkg.path,
158
+ status: pkg.status,
159
+ }))
160
+ .sort((left, right) => left.publicName.localeCompare(right.publicName));
161
+ };
162
+
163
+ const fileSpecPath = (spec) => {
164
+ if (typeof spec !== "string" || !spec.startsWith("file:")) return undefined;
165
+ return spec.slice("file:".length);
166
+ };
167
+
168
+ const artifactProjection = (manifestPath) => {
169
+ const base = {
170
+ owner: "dist/internal-npm/install-manifest.json",
171
+ path: manifestPath,
172
+ };
173
+ if (typeof manifestPath !== "string") {
174
+ return { ...base, status: "unavailable", packages: [] };
175
+ }
176
+ if (!fs.existsSync(manifestPath)) {
177
+ return { ...base, status: "missing", packages: [] };
178
+ }
179
+ try {
180
+ const manifest = readJson(manifestPath);
181
+ const packages = Object.entries(manifest.tarballs ?? {})
182
+ .map(([packageName, entry]) => {
183
+ const tarball = fileSpecPath(entry?.spec);
184
+ const expectedSha = typeof entry?.sha256 === "string" ? entry.sha256 : undefined;
185
+ const exists = typeof tarball === "string" && fs.existsSync(tarball);
186
+ const actualSha = exists ? sha256File(tarball) : undefined;
187
+ const status =
188
+ tarball === undefined || expectedSha === undefined
189
+ ? "invalid"
190
+ : !exists
191
+ ? "missing"
192
+ : actualSha === expectedSha
193
+ ? "verified"
194
+ : "sha_mismatch";
195
+ return {
196
+ packageName,
197
+ tarball,
198
+ expectedSha256: expectedSha,
199
+ actualSha256: actualSha,
200
+ status,
201
+ };
202
+ })
203
+ .sort((left, right) => left.packageName.localeCompare(right.packageName));
204
+ const protocolOk = manifest.protocol === "agentos-install-manifest@1";
205
+ const status =
206
+ protocolOk && packages.length > 0 && packages.every((pkg) => pkg.status === "verified")
207
+ ? "verified"
208
+ : "failed";
209
+ return {
210
+ ...base,
211
+ status,
212
+ sha256: sha256File(manifestPath),
213
+ protocol: manifest.protocol,
214
+ version: manifest.version,
215
+ generatedBy: manifest.generatedBy,
216
+ packages,
217
+ };
218
+ } catch (error) {
219
+ return {
220
+ ...base,
221
+ status: "failed",
222
+ packages: [],
223
+ error: error instanceof Error ? error.message : String(error),
224
+ };
225
+ }
226
+ };
227
+
228
+ const releaseExportEquivalenceProjection = (manifestPath, context) => {
229
+ if (typeof manifestPath !== "string" || !fs.existsSync(manifestPath)) {
230
+ return {
231
+ status: "not_checked",
232
+ packagesChecked: 0,
233
+ packages: [],
234
+ failures: [],
235
+ reason: "install manifest is unavailable",
236
+ };
237
+ }
238
+ try {
239
+ const manifest = readJson(manifestPath);
240
+ return exportEquivalenceForInstallManifest(manifest, { sourceRoot: context.sourceRoot });
241
+ } catch (error) {
242
+ return {
243
+ status: "failed",
244
+ packagesChecked: 0,
245
+ packages: [],
246
+ failures: [
247
+ {
248
+ code: "export_install_manifest_unreadable",
249
+ comparison: "manifest",
250
+ error: error instanceof Error ? error.message : String(error),
251
+ },
252
+ ],
253
+ };
254
+ }
255
+ };
256
+
257
+ const npmProjection = (packages, options) => {
258
+ if (options.checkNpm !== true) {
259
+ return {
260
+ owner: "npm registry",
261
+ status: "not_checked",
262
+ reason: "pass --check-npm to observe npm dist-tags",
263
+ };
264
+ }
265
+ const registry = typeof options.registry === "string" ? options.registry : undefined;
266
+ const rows = {};
267
+ for (const pkg of packages) {
268
+ const args = ["view", pkg.publicName, "dist-tags", "--json"];
269
+ if (registry !== undefined && registry.length > 0) args.push("--registry", registry);
270
+ const result = spawnSync("npm", args, {
271
+ encoding: "utf8",
272
+ stdio: ["ignore", "pipe", "pipe"],
273
+ });
274
+ if (result.status !== 0) {
275
+ rows[pkg.publicName] = {
276
+ status: "unresolved",
277
+ detail: result.stderr.trim() || result.stdout.trim(),
278
+ };
279
+ continue;
280
+ }
281
+ try {
282
+ rows[pkg.publicName] = {
283
+ status: "resolved",
284
+ distTags: JSON.parse(result.stdout.trim()),
285
+ };
286
+ } catch (error) {
287
+ rows[pkg.publicName] = {
288
+ status: "invalid_json",
289
+ detail: error instanceof Error ? error.message : String(error),
290
+ };
291
+ }
292
+ }
293
+ return {
294
+ owner: "npm registry",
295
+ status: "checked",
296
+ ...(registry === undefined ? {} : { registry }),
297
+ packages: rows,
298
+ };
299
+ };
300
+
301
+ const issue = (code, severity, dimension, message, detail = {}) => ({
302
+ code,
303
+ severity,
304
+ dimension,
305
+ message,
306
+ ...detail,
307
+ });
308
+
309
+ const releaseGate = (projection) => {
310
+ const hardFailures = [];
311
+ const signals = [];
312
+ if (projection.artifacts.status === "failed") {
313
+ hardFailures.push(
314
+ issue(
315
+ "local_artifacts_failed",
316
+ "hard",
317
+ "artifacts",
318
+ "local package artifacts failed integrity checks",
319
+ ),
320
+ );
321
+ } else if (projection.artifacts.status !== "verified") {
322
+ signals.push(
323
+ issue(
324
+ "local_artifacts_not_verified",
325
+ "signal",
326
+ "artifacts",
327
+ `local package artifacts are ${projection.artifacts.status}`,
328
+ ),
329
+ );
330
+ }
331
+ for (const failure of projection.exportEquivalence?.failures ?? []) {
332
+ hardFailures.push(
333
+ issue(
334
+ failure.code,
335
+ "hard",
336
+ "export_equivalence",
337
+ `release export equivalence failed: ${failure.code}`,
338
+ { exportIssue: failure },
339
+ ),
340
+ );
341
+ }
342
+ if (projection.source.status !== "available") {
343
+ signals.push(
344
+ issue("source_unavailable", "signal", "source", "source checkout identity is unavailable"),
345
+ );
346
+ } else {
347
+ if (projection.source.dirty === true) {
348
+ signals.push(
349
+ issue("source_dirty", "signal", "source", "source checkout has uncommitted changes"),
350
+ );
351
+ }
352
+ if (
353
+ projection.source.upstream?.status === "configured" &&
354
+ projection.source.upstream.ahead > 0
355
+ ) {
356
+ signals.push(
357
+ issue("source_ahead", "signal", "source", "source checkout is ahead of upstream", {
358
+ ahead: projection.source.upstream.ahead,
359
+ upstream: projection.source.upstream.ref,
360
+ }),
361
+ );
362
+ }
363
+ if (
364
+ projection.source.upstream?.status === "configured" &&
365
+ projection.source.upstream.behind > 0
366
+ ) {
367
+ signals.push(
368
+ issue("source_behind", "signal", "source", "source checkout is behind upstream", {
369
+ behind: projection.source.upstream.behind,
370
+ upstream: projection.source.upstream.ref,
371
+ }),
372
+ );
373
+ }
374
+ }
375
+ if (projection.npm.status === "not_checked") {
376
+ signals.push(issue("npm_not_checked", "signal", "npm", "npm dist-tags were not checked"));
377
+ } else if (projection.npm.status === "checked") {
378
+ for (const [packageName, row] of Object.entries(projection.npm.packages ?? {})) {
379
+ if (row.status !== "resolved") {
380
+ signals.push(
381
+ issue(
382
+ "npm_unresolved",
383
+ "signal",
384
+ "npm",
385
+ `${packageName} npm dist-tags were not resolved`,
386
+ {
387
+ packageName,
388
+ status: row.status,
389
+ },
390
+ ),
391
+ );
392
+ }
393
+ }
394
+ }
395
+ if (projection.consumer === undefined) {
396
+ signals.push(
397
+ issue("consumer_not_checked", "signal", "consumer", "no consumer root was provided"),
398
+ );
399
+ } else {
400
+ for (const failure of projection.consumer.gate?.hardFailures ?? []) {
401
+ hardFailures.push(
402
+ issue(
403
+ failure.code,
404
+ "hard",
405
+ "consumer",
406
+ failure.message ?? `consumer gate failed: ${failure.code}`,
407
+ { consumerIssue: failure },
408
+ ),
409
+ );
410
+ }
411
+ for (const signal of projection.consumer.gate?.signals ?? []) {
412
+ signals.push(
413
+ issue(
414
+ signal.code,
415
+ "signal",
416
+ "consumer",
417
+ signal.message ?? `consumer gate signal: ${signal.code}`,
418
+ { consumerIssue: signal },
419
+ ),
420
+ );
421
+ }
422
+ }
423
+ return {
424
+ status: hardFailures.length > 0 ? "fail" : signals.length > 0 ? "warn" : "pass",
425
+ hardFailures,
426
+ signals,
427
+ };
428
+ };
429
+
430
+ export const releaseStatusData = (input = {}) => {
431
+ const context = input.context ?? {};
432
+ const release = releaseIdentityProjection(context);
433
+ const packages = publishedPackagesProjection(context, release);
434
+ const manifestPath = input.installManifestPath ?? context.defaultInstallManifestPath;
435
+ const projection = {
436
+ schemaVersion: releaseStatusSchemaVersion,
437
+ release: {
438
+ ...release,
439
+ packages,
440
+ },
441
+ source: gitSourceProjection(context.sourceRoot),
442
+ artifacts: artifactProjection(manifestPath),
443
+ exportEquivalence: releaseExportEquivalenceProjection(manifestPath, context),
444
+ npm: npmProjection(packages, {
445
+ checkNpm: input.checkNpm,
446
+ registry: input.registry,
447
+ }),
448
+ ...(input.consumerRoot === undefined
449
+ ? {}
450
+ : {
451
+ consumer: consumerStatusData(input.consumerRoot, {
452
+ packageRoot: context.packageRoot,
453
+ sourceRoot: context.sourceRoot,
454
+ checkNpm: input.checkNpm,
455
+ registry: input.registry,
456
+ }),
457
+ }),
458
+ };
459
+ return {
460
+ ...projection,
461
+ gate: releaseGate(projection),
462
+ };
463
+ };
464
+
465
+ const printReleaseStatus = (status) => {
466
+ console.log(`release version: ${status.release.version}`);
467
+ console.log(`npm scope: ${status.release.npmScope ?? "unknown"}`);
468
+ console.log(`source: ${status.source.status}`);
469
+ if (status.source.status === "available") {
470
+ console.log(
471
+ `source head: ${status.source.branch}@${status.source.head} dirty=${status.source.dirty}`,
472
+ );
473
+ if (status.source.upstream?.status === "configured") {
474
+ console.log(
475
+ `source upstream: ${status.source.upstream.ref} ahead=${status.source.upstream.ahead} behind=${status.source.upstream.behind}`,
476
+ );
477
+ }
478
+ }
479
+ console.log(`artifacts: ${status.artifacts.status}`);
480
+ console.log(`export equivalence: ${status.exportEquivalence.status}`);
481
+ console.log(`npm: ${status.npm.status}`);
482
+ console.log(`consumer: ${status.consumer?.truthMode ?? "not_checked"}`);
483
+ console.log(`gate: ${status.gate.status}`);
484
+ for (const failure of status.gate.hardFailures) {
485
+ console.log(`failure ${failure.code}: ${failure.message}`);
486
+ }
487
+ for (const signal of status.gate.signals) {
488
+ console.log(`signal ${signal.code}: ${signal.message}`);
489
+ }
490
+ };
491
+
492
+ export const releaseStatus = (rawArgs, context = {}) => {
493
+ const args = parseArgs(rawArgs);
494
+ const positional = args._ ?? [];
495
+ if (positional.length > 1) {
496
+ throw new Error("agentos release status: expected at most one consumer path");
497
+ }
498
+ const consumerRoot = positional[0] === undefined ? undefined : resolveConsumerRoot(positional[0]);
499
+ const installManifestPath =
500
+ typeof args["install-manifest"] === "string"
501
+ ? path.resolve(process.cwd(), args["install-manifest"])
502
+ : undefined;
503
+ const status = releaseStatusData({
504
+ context,
505
+ consumerRoot,
506
+ installManifestPath,
507
+ checkNpm: boolArg(args, "check-npm"),
508
+ registry: typeof args.registry === "string" ? args.registry : undefined,
509
+ });
510
+ if (boolArg(args, "json")) {
511
+ console.log(JSON.stringify(status, null, 2));
512
+ } else {
513
+ printReleaseStatus(status);
514
+ }
515
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yansirplus/cli",
3
- "version": "0.5.17",
3
+ "version": "0.5.19",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "publishConfig": {
@@ -19,14 +19,18 @@
19
19
  },
20
20
  "files": [
21
21
  "dist",
22
+ "agent-catalog",
22
23
  "README.md",
23
24
  "PUBLIC_API.md"
24
25
  ],
25
26
  "dependencies": {
26
- "@yansirplus/core": "0.5.17",
27
- "@yansirplus/runtime": "0.5.17"
27
+ "@yansirplus/core": "0.5.19",
28
+ "@yansirplus/evals": "0.5.19",
29
+ "@yansirplus/runtime": "0.5.19",
30
+ "esbuild": "0.27.3",
31
+ "yaml": "2.9.0"
28
32
  },
29
33
  "peerDependencies": {
30
- "effect": "^4.0.0-beta.84"
34
+ "effect": "4.0.0-beta.84"
31
35
  }
32
36
  }