@agent-surface/cli 0.12.1 → 0.14.0

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 (38) hide show
  1. package/README.md +44 -6
  2. package/dist/bin.js +22 -13
  3. package/dist/bin.js.map +1 -1
  4. package/dist/check-O7ENP4XP.js +259 -0
  5. package/dist/check-O7ENP4XP.js.map +1 -0
  6. package/dist/chunk-G7Z6PP6C.js +532 -0
  7. package/dist/chunk-G7Z6PP6C.js.map +1 -0
  8. package/dist/chunk-JR4GESLI.js +61 -0
  9. package/dist/chunk-JR4GESLI.js.map +1 -0
  10. package/dist/chunk-LQUL4OIA.js +1441 -0
  11. package/dist/chunk-LQUL4OIA.js.map +1 -0
  12. package/dist/chunk-YUT4FVQQ.js +220 -0
  13. package/dist/chunk-YUT4FVQQ.js.map +1 -0
  14. package/dist/{init-LFQ5R3G7.js → init-64GIHMKV.js} +64 -41
  15. package/dist/init-64GIHMKV.js.map +1 -0
  16. package/dist/{ink-P23VKP4H.js → ink-ICJWXGZC.js} +153 -25
  17. package/dist/ink-ICJWXGZC.js.map +1 -0
  18. package/dist/inspect-6OZ6ZBKZ.js +226 -0
  19. package/dist/inspect-6OZ6ZBKZ.js.map +1 -0
  20. package/dist/snapshot-GTDFQTN2.js +130 -0
  21. package/dist/snapshot-GTDFQTN2.js.map +1 -0
  22. package/package.json +4 -4
  23. package/dist/check-POE5VRSE.js +0 -183
  24. package/dist/check-POE5VRSE.js.map +0 -1
  25. package/dist/chunk-DYDSJM7R.js +0 -170
  26. package/dist/chunk-DYDSJM7R.js.map +0 -1
  27. package/dist/chunk-J2NN3J5N.js +0 -541
  28. package/dist/chunk-J2NN3J5N.js.map +0 -1
  29. package/dist/chunk-Q5WOLWEW.js +0 -984
  30. package/dist/chunk-Q5WOLWEW.js.map +0 -1
  31. package/dist/chunk-QIVOZAWX.js +0 -169
  32. package/dist/chunk-QIVOZAWX.js.map +0 -1
  33. package/dist/init-LFQ5R3G7.js.map +0 -1
  34. package/dist/ink-P23VKP4H.js.map +0 -1
  35. package/dist/inspect-XMDZBSK2.js +0 -119
  36. package/dist/inspect-XMDZBSK2.js.map +0 -1
  37. package/dist/snapshot-FLXE5UC6.js +0 -61
  38. package/dist/snapshot-FLXE5UC6.js.map +0 -1
@@ -0,0 +1,226 @@
1
+ import {
2
+ coverageReport,
3
+ inventoryReport,
4
+ scenarioReport
5
+ } from "./chunk-JR4GESLI.js";
6
+ import {
7
+ createPresenter,
8
+ joinCoverage,
9
+ mountScenarios,
10
+ readInventory,
11
+ scopeCapabilityIds,
12
+ scopeInventory,
13
+ staticConfigScope
14
+ } from "./chunk-YUT4FVQQ.js";
15
+ import {
16
+ write
17
+ } from "./chunk-G7Z6PP6C.js";
18
+ import {
19
+ READING_SOURCE,
20
+ buildView,
21
+ catalogDetailParts,
22
+ catalogRows,
23
+ coverageSections,
24
+ failureSection,
25
+ flatRows,
26
+ mountingLabel,
27
+ neverCallable,
28
+ neverCallableSection,
29
+ noVerdictSection,
30
+ runHeaderBlocks,
31
+ scenarioStats,
32
+ scenarioTable,
33
+ surfaceSummaryRows,
34
+ trackReach
35
+ } from "./chunk-LQUL4OIA.js";
36
+
37
+ // src/commands/inspect.ts
38
+ async function runInspect(options) {
39
+ const analysis = {
40
+ configPath: options.configPath,
41
+ depth: options.depth,
42
+ ...options.scenario ? { scenario: options.scenario } : {},
43
+ ...options.scope ? { scope: options.scope } : {},
44
+ ...options.tsconfig ? { tsconfig: options.tsconfig } : {},
45
+ ...options.baselineDir ? { baselineDir: options.baselineDir } : {}
46
+ };
47
+ const detail = options.detail === true || options.explain === true || options.schemas === true;
48
+ const present = await createPresenter(options);
49
+ if (!options.json) await present.wait(READING_SOURCE);
50
+ const inventory = readInventory(analysis);
51
+ const scenarios = [];
52
+ const stats = [];
53
+ const views = [];
54
+ const reach = /* @__PURE__ */ new Map();
55
+ let plan;
56
+ const scope = () => plan?.scope ?? staticConfigScope(analysis);
57
+ const scopedInventory = () => scopeInventory(inventory, scope());
58
+ const domainCount = () => plan?.domainManifestConfigured ? scopeCapabilityIds(plan.domainCapabilities, scope()).length : void 0;
59
+ const header = async () => {
60
+ present.settle();
61
+ if (options.json) return;
62
+ const active = scope();
63
+ const catalog2 = scopedInventory();
64
+ await present.emit(
65
+ // At `--depth static` the catalog *is* the answer, so it opens the report
66
+ // beside the run it came from. At every other depth it is a detail behind
67
+ // the summary, and prints down there instead.
68
+ {
69
+ kind: "blocks",
70
+ blocks: runHeaderBlocks(
71
+ "SURFACE INSPECT",
72
+ {
73
+ configPath: options.configPath,
74
+ depth: options.depth,
75
+ ...active ? { scope: active } : {},
76
+ ...plan ? { scenarios: plan.scenarios, declaredScenarios: plan.declaredScenarios } : {}
77
+ },
78
+ plan ? void 0 : catalog2,
79
+ domainCount()
80
+ )
81
+ },
82
+ ...!plan && catalog2 ? catalogDetailParts(catalog2, { ...detail ? { detail: true } : {} }) : []
83
+ );
84
+ };
85
+ const runtime = await mountScenarios(analysis, {
86
+ onPlan: async (current) => {
87
+ plan = current;
88
+ await header();
89
+ if (current.scenarios.length > 0) await present.wait(mountingLabel(current.scenarios, 0));
90
+ },
91
+ onEach: async (result) => {
92
+ const view = buildView(result, {
93
+ ...options.explain ? { explain: true } : {},
94
+ ...options.schemas ? { schemas: true } : {}
95
+ });
96
+ trackReach(reach, flatRows(view), result.scenario);
97
+ stats.push(scenarioStats(result));
98
+ if (options.json) {
99
+ scenarios.push(
100
+ scenarioReport(result, {
101
+ ...options.explain ? { attribution: true } : {},
102
+ ...options.schemas ? { schemas: true } : {}
103
+ })
104
+ );
105
+ } else {
106
+ views.push(view);
107
+ }
108
+ if (plan && stats.length < plan.scenarios.length) {
109
+ await present.wait(mountingLabel(plan.scenarios, stats.length));
110
+ }
111
+ }
112
+ });
113
+ present.settle();
114
+ if (!runtime) await header();
115
+ const effectiveScope = options.scope ?? runtime?.scope ?? staticConfigScope(analysis);
116
+ const reportInventory = scopeInventory(inventory, effectiveScope);
117
+ const reportDomain = runtime?.domainManifestConfigured ? scopeCapabilityIds(runtime.domainCapabilities, effectiveScope) : void 0;
118
+ const coverage = joinCoverage(inventory, runtime, analysis);
119
+ const dark = neverCallable(reach);
120
+ if (options.json) {
121
+ write(
122
+ JSON.stringify(
123
+ {
124
+ // One shape whatever the depth, so a consumer never branches on how
125
+ // the command was invoked. A half the depth did not compute is
126
+ // `null`, which is a different statement from `[]` or `{}`.
127
+ depth: options.depth,
128
+ catalog: inventoryReport(reportInventory, reportDomain),
129
+ scenarios,
130
+ failures: runtime?.failures ?? [],
131
+ coverage: coverageReport(coverage),
132
+ // Mounted, and callable in no scenario — a gap the coverage join
133
+ // cannot see, because every one of these *was* reached.
134
+ neverCallable: dark.map((entry) => ({
135
+ capabilityId: entry.capabilityId,
136
+ outcome: entry.best,
137
+ ...entry.note ? { reason: entry.note } : {},
138
+ scenarios: entry.scenarios
139
+ }))
140
+ },
141
+ null,
142
+ 2
143
+ )
144
+ );
145
+ return runtime && runtime.failures.length > 0 ? 2 : 0;
146
+ }
147
+ if (!runtime) return 0;
148
+ for (const failure of runtime.failures) {
149
+ stats.push({
150
+ scenario: failure.scenario,
151
+ callable: 0,
152
+ disabled: 0,
153
+ hidden: 0,
154
+ rejected: 0,
155
+ failed: true,
156
+ failure: failure.message
157
+ });
158
+ }
159
+ stats.sort((a, b) => runtime.scenarios.indexOf(a.scenario) - runtime.scenarios.indexOf(b.scenario));
160
+ const mounted = stats.filter((entry) => !entry.failed).length;
161
+ const parts = [
162
+ {
163
+ kind: "blocks",
164
+ blocks: [
165
+ {
166
+ title: "SURFACE SUMMARY",
167
+ rows: surfaceSummaryRows({
168
+ depth: options.depth,
169
+ ...coverage ? { coverage } : {},
170
+ scenarios: stats,
171
+ failures: runtime.failures.length,
172
+ reach
173
+ })
174
+ }
175
+ ]
176
+ }
177
+ ];
178
+ if (stats.length > 1) {
179
+ const table = scenarioTable(stats);
180
+ parts.push({
181
+ kind: "table",
182
+ title: `SCENARIOS (${stats.length})`,
183
+ headers: table.headers,
184
+ rows: table.rows
185
+ });
186
+ }
187
+ if (runtime.failures.length > 0) {
188
+ parts.push({
189
+ kind: "findings",
190
+ stream: "err",
191
+ sections: [
192
+ failureSection(runtime.failures),
193
+ ...inventory ? [noVerdictSection(runtime.failures)] : []
194
+ ]
195
+ });
196
+ }
197
+ const sections = [
198
+ ...coverage ? coverageSections(coverage) : [],
199
+ ...dark.length > 0 && mounted > 1 ? [neverCallableSection(dark)] : []
200
+ ];
201
+ if (sections.length > 0) parts.push({ kind: "findings", sections });
202
+ const catalog = scopeInventory(inventory, effectiveScope);
203
+ if (catalog) {
204
+ parts.push({
205
+ kind: "blocks",
206
+ blocks: [
207
+ {
208
+ title: "STATIC CATALOG",
209
+ rows: catalogRows(catalog, {
210
+ ...domainCount() === void 0 ? {} : { domainCapabilities: domainCount() },
211
+ mounted: true
212
+ })
213
+ }
214
+ ]
215
+ });
216
+ }
217
+ for (const view of views) {
218
+ parts.push({ kind: "surface", view, ...detail ? { detail: true } : {} });
219
+ }
220
+ await present.emit(...parts);
221
+ return runtime.failures.length > 0 ? 2 : 0;
222
+ }
223
+ export {
224
+ runInspect
225
+ };
226
+ //# sourceMappingURL=inspect-6OZ6ZBKZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/inspect.ts"],"sourcesContent":["import {\n joinCoverage,\n mountScenarios,\n readInventory,\n scopeCapabilityIds,\n scopeInventory,\n staticConfigScope,\n type AnalysisOptions,\n type Depth,\n type RuntimePlan,\n} from \"../analysis.js\";\nimport { buildView, flatRows, type SurfaceView } from \"../render/model.js\";\nimport { createPresenter } from \"../render/present.js\";\nimport {\n catalogDetailParts,\n catalogRows,\n coverageSections,\n failureSection,\n mountingLabel,\n neverCallable,\n neverCallableSection,\n noVerdictSection,\n READING_SOURCE,\n runHeaderBlocks,\n scenarioStats,\n scenarioTable,\n surfaceSummaryRows,\n trackReach,\n type CapabilityReach,\n type FindingSection,\n type ReportPart,\n type ScenarioStats,\n} from \"../render/summary.js\";\nimport { write } from \"../output.js\";\nimport {\n coverageReport,\n inventoryReport,\n scenarioReport,\n type ScenarioReport,\n} from \"../report.js\";\n\nexport interface InspectOptions {\n configPath: string;\n depth: Depth;\n scenario?: string;\n scope?: string[];\n tsconfig?: string;\n baselineDir?: string;\n detail?: boolean;\n explain?: boolean;\n schemas?: boolean;\n json?: boolean;\n plain?: boolean;\n}\n\n/**\n * The whole surface: what this codebase authors, what a mount surfaces, and the\n * difference between them.\n *\n * It answers findings, it does not gate on them — exit `0` whatever it reports,\n * because `check` is the gate and a viewer that sometimes fails is a viewer\n * nobody puts in a pipeline. The exception is `2`, which is not a finding: the\n * command could not run at all.\n *\n * The report is read top-down, so it is written top-down: **summaries first,\n * details after.**\n *\n * 1. **The run** — the config, the depth, the scope, the scenarios. All of it is\n * known before the first mount, and the mounts are the slow half, so it\n * prints immediately rather than making a reader wait to learn what is being\n * measured.\n * 2. **The summary** — reach, what is callable, what the surface can do, the\n * verdict. The answer, before anything it was derived from.\n * 3. **One row per scenario**, for a config with more than one.\n * 4. **The findings** — unreached, never callable, unread call sites — each with\n * what to do about it.\n * 5. **The details** — the static catalog, then each scenario's own table.\n *\n * That order costs the streaming this command used to do: the summary is a\n * statement about every scenario, so it cannot be written until every scenario\n * has mounted. A terminal is told what it is waiting for instead — the header\n * is already on screen and a spinner names the scenario being mounted — and\n * `check`, whose output has always been a report, works the same way.\n */\nexport async function runInspect(options: InspectOptions): Promise<number> {\n const analysis: AnalysisOptions = {\n configPath: options.configPath,\n depth: options.depth,\n ...(options.scenario ? { scenario: options.scenario } : {}),\n ...(options.scope ? { scope: options.scope } : {}),\n ...(options.tsconfig ? { tsconfig: options.tsconfig } : {}),\n ...(options.baselineDir ? { baselineDir: options.baselineDir } : {}),\n };\n\n // Policy chains and JSON Schemas are multi-line by nature, so asking for\n // either is asking for the view that can hold them.\n const detail = options.detail === true || options.explain === true || options.schemas === true;\n const present = await createPresenter(options);\n\n // The TypeScript program is read synchronously and the app loads after it;\n // together that is seconds on a real repository, and a terminal that shows\n // nothing for them looks wedged.\n if (!options.json) await present.wait(READING_SOURCE);\n\n const inventory = readInventory(analysis);\n const scenarios: ScenarioReport[] = [];\n const stats: ScenarioStats[] = [];\n const views: SurfaceView[] = [];\n const reach = new Map<string, CapabilityReach>();\n let plan: RuntimePlan | undefined;\n\n const scope = (): string[] | undefined => plan?.scope ?? staticConfigScope(analysis);\n const scopedInventory = (): ReturnType<typeof scopeInventory> =>\n scopeInventory(inventory, scope());\n const domainCount = (): number | undefined =>\n plan?.domainManifestConfigured\n ? scopeCapabilityIds(plan.domainCapabilities, scope()).length\n : undefined;\n\n const header = async (): Promise<void> => {\n present.settle();\n if (options.json) return;\n const active = scope();\n const catalog = scopedInventory();\n await present.emit(\n // At `--depth static` the catalog *is* the answer, so it opens the report\n // beside the run it came from. At every other depth it is a detail behind\n // the summary, and prints down there instead.\n {\n kind: \"blocks\",\n blocks: runHeaderBlocks(\n \"SURFACE INSPECT\",\n {\n configPath: options.configPath,\n depth: options.depth,\n ...(active ? { scope: active } : {}),\n ...(plan\n ? { scenarios: plan.scenarios, declaredScenarios: plan.declaredScenarios }\n : {}),\n },\n plan ? undefined : catalog,\n domainCount(),\n ),\n },\n ...(!plan && catalog\n ? catalogDetailParts(catalog, { ...(detail ? { detail: true } : {}) })\n : []),\n );\n };\n\n const runtime = await mountScenarios(analysis, {\n onPlan: async (current) => {\n plan = current;\n await header();\n if (current.scenarios.length > 0) await present.wait(mountingLabel(current.scenarios, 0));\n },\n onEach: async (result) => {\n const view = buildView(result, {\n ...(options.explain ? { explain: true } : {}),\n ...(options.schemas ? { schemas: true } : {}),\n });\n trackReach(reach, flatRows(view), result.scenario);\n stats.push(scenarioStats(result));\n if (options.json) {\n scenarios.push(\n scenarioReport(result, {\n ...(options.explain ? { attribution: true } : {}),\n ...(options.schemas ? { schemas: true } : {}),\n }),\n );\n } else {\n views.push(view);\n }\n // Named, and only while there is one left: a spinner announcing work\n // nobody is doing has to be read twice before it can be dismissed.\n if (plan && stats.length < plan.scenarios.length) {\n await present.wait(mountingLabel(plan.scenarios, stats.length));\n }\n },\n });\n present.settle();\n if (!runtime) await header();\n\n const effectiveScope = options.scope ?? runtime?.scope ?? staticConfigScope(analysis);\n const reportInventory = scopeInventory(inventory, effectiveScope);\n const reportDomain = runtime?.domainManifestConfigured\n ? scopeCapabilityIds(runtime.domainCapabilities, effectiveScope)\n : undefined;\n const coverage = joinCoverage(inventory, runtime, analysis);\n const dark = neverCallable(reach);\n\n if (options.json) {\n write(\n JSON.stringify(\n {\n // One shape whatever the depth, so a consumer never branches on how\n // the command was invoked. A half the depth did not compute is\n // `null`, which is a different statement from `[]` or `{}`.\n depth: options.depth,\n catalog: inventoryReport(reportInventory, reportDomain),\n scenarios,\n failures: runtime?.failures ?? [],\n coverage: coverageReport(coverage),\n // Mounted, and callable in no scenario — a gap the coverage join\n // cannot see, because every one of these *was* reached.\n neverCallable: dark.map((entry) => ({\n capabilityId: entry.capabilityId,\n outcome: entry.best,\n ...(entry.note ? { reason: entry.note } : {}),\n scenarios: entry.scenarios,\n })),\n },\n null,\n 2,\n ),\n );\n return runtime && runtime.failures.length > 0 ? 2 : 0;\n }\n\n if (!runtime) return 0;\n\n // A scenario that threw is not in `stats`, and every count below is missing\n // whatever it held — so it takes a row of its own rather than appearing only\n // at the bottom of the report.\n for (const failure of runtime.failures) {\n stats.push({\n scenario: failure.scenario,\n callable: 0,\n disabled: 0,\n hidden: 0,\n rejected: 0,\n failed: true,\n failure: failure.message,\n });\n }\n stats.sort((a, b) => runtime.scenarios.indexOf(a.scenario) - runtime.scenarios.indexOf(b.scenario));\n const mounted = stats.filter((entry) => !entry.failed).length;\n\n const parts: ReportPart[] = [\n {\n kind: \"blocks\",\n blocks: [\n {\n title: \"SURFACE SUMMARY\",\n rows: surfaceSummaryRows({\n depth: options.depth,\n ...(coverage ? { coverage } : {}),\n scenarios: stats,\n failures: runtime.failures.length,\n reach,\n }),\n },\n ],\n },\n ];\n\n // One row per scenario, so a config with more than one can be compared in a\n // single place rather than by scrolling through its tables.\n if (stats.length > 1) {\n const table = scenarioTable(stats);\n parts.push({\n kind: \"table\",\n title: `SCENARIOS (${stats.length})`,\n headers: table.headers,\n rows: table.rows,\n });\n }\n\n if (runtime.failures.length > 0) {\n parts.push({\n kind: \"findings\",\n stream: \"err\",\n sections: [\n failureSection(runtime.failures),\n ...(inventory ? [noVerdictSection(runtime.failures)] : []),\n ],\n });\n }\n\n // Over one scenario, \"never callable\" repeats that scenario's own table row\n // for row. It is a finding only once there is more than one scenario for a\n // capability to have been callable in.\n const sections: FindingSection[] = [\n ...(coverage ? coverageSections(coverage) : []),\n ...(dark.length > 0 && mounted > 1 ? [neverCallableSection(dark)] : []),\n ];\n if (sections.length > 0) parts.push({ kind: \"findings\", sections });\n\n // Details. The catalog first, because the scenario tables below are what it\n // is the denominator of.\n const catalog = scopeInventory(inventory, effectiveScope);\n if (catalog) {\n parts.push({\n kind: \"blocks\",\n blocks: [\n {\n title: \"STATIC CATALOG\",\n rows: catalogRows(catalog, {\n ...(domainCount() === undefined ? {} : { domainCapabilities: domainCount()! }),\n mounted: true,\n }),\n },\n ],\n });\n }\n\n for (const view of views) {\n parts.push({ kind: \"surface\", view, ...(detail ? { detail: true } : {}) });\n }\n\n await present.emit(...parts);\n\n // A scenario that would not mount is not a finding about the surface, it is\n // the command failing to observe one. `2` — the same code a usage error gets,\n // because CI has to tell both apart from \"the surface changed\".\n return runtime.failures.length > 0 ? 2 : 0;\n}\n"],"mappings":"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","names":["catalog"]}
@@ -0,0 +1,130 @@
1
+ import {
2
+ scenarioBaseline
3
+ } from "./chunk-JR4GESLI.js";
4
+ import {
5
+ createPresenter,
6
+ joinCoverage,
7
+ mountScenarios,
8
+ readInventory
9
+ } from "./chunk-YUT4FVQQ.js";
10
+ import {
11
+ UsageError,
12
+ baselinePath,
13
+ writeBaseline,
14
+ writeScenarioManifest
15
+ } from "./chunk-G7Z6PP6C.js";
16
+ import {
17
+ READING_SOURCE,
18
+ buildView,
19
+ coverageSections,
20
+ displayPath,
21
+ failureSection,
22
+ flatRows,
23
+ mountingLabel,
24
+ neverCallable,
25
+ neverCallableSection,
26
+ noVerdictSection,
27
+ runHeaderBlocks,
28
+ scenarioStats,
29
+ surfaceSummaryRows,
30
+ trackReach
31
+ } from "./chunk-LQUL4OIA.js";
32
+
33
+ // src/commands/snapshot.ts
34
+ async function runSnapshot(options) {
35
+ if (options.depth === "static") {
36
+ throw new UsageError(
37
+ "snapshot --depth static has nothing to write \u2014 a baseline is a projection, and at this depth nothing is mounted."
38
+ );
39
+ }
40
+ const analysis = {
41
+ configPath: options.configPath,
42
+ depth: options.depth,
43
+ ...options.scenario ? { scenario: options.scenario } : {},
44
+ ...options.scope ? { scope: options.scope } : {},
45
+ ...options.tsconfig ? { tsconfig: options.tsconfig } : {},
46
+ ...options.baselineDir ? { baselineDir: options.baselineDir } : {}
47
+ };
48
+ const present = await createPresenter(options);
49
+ await present.wait(READING_SOURCE);
50
+ const inventory = readInventory(analysis);
51
+ let scenarios = [];
52
+ let mountedCount = 0;
53
+ const runtime = await mountScenarios(analysis, {
54
+ onPlan: async (plan) => {
55
+ scenarios = plan.scenarios;
56
+ await present.emit({
57
+ kind: "blocks",
58
+ blocks: runHeaderBlocks("SURFACE SNAPSHOT", {
59
+ configPath: options.configPath,
60
+ depth: options.depth,
61
+ ...plan.scope ? { scope: plan.scope } : {},
62
+ scenarios: plan.scenarios,
63
+ declaredScenarios: plan.declaredScenarios
64
+ })
65
+ });
66
+ if (scenarios.length > 0) await present.wait(mountingLabel(scenarios, 0));
67
+ },
68
+ onEach: async () => {
69
+ mountedCount += 1;
70
+ if (mountedCount < scenarios.length) {
71
+ await present.wait(mountingLabel(scenarios, mountedCount));
72
+ }
73
+ }
74
+ });
75
+ present.settle();
76
+ if (!runtime) throw new UsageError("snapshot needs a mount, and this depth performs none");
77
+ const written = [];
78
+ for (const result of runtime.results) {
79
+ const path = baselinePath(runtime.baselineDir, result.scenario);
80
+ writeBaseline(path, scenarioBaseline(result));
81
+ written.push({ cells: [result.scenario, displayPath(path)] });
82
+ }
83
+ writeScenarioManifest(runtime.baselineDir, runtime.declaredScenarios);
84
+ const reach = /* @__PURE__ */ new Map();
85
+ for (const result of runtime.results) {
86
+ trackReach(reach, flatRows(buildView(result)), result.scenario);
87
+ }
88
+ const coverage = joinCoverage(inventory, runtime, analysis);
89
+ const stats = runtime.results.map(scenarioStats);
90
+ const dark = neverCallable(reach);
91
+ const parts = [
92
+ { kind: "table", title: `WROTE (${written.length})`, headers: ["SCENARIO", "FILE"], rows: written }
93
+ ];
94
+ const sections = [
95
+ ...coverage ? coverageSections(coverage) : [],
96
+ ...dark.length > 0 && stats.length > 1 ? [neverCallableSection(dark)] : []
97
+ ];
98
+ if (sections.length > 0) parts.push({ kind: "findings", sections });
99
+ parts.push({
100
+ kind: "blocks",
101
+ blocks: [
102
+ {
103
+ title: "SURFACE SUMMARY",
104
+ rows: surfaceSummaryRows({
105
+ depth: options.depth,
106
+ ...coverage ? { coverage } : {},
107
+ scenarios: stats,
108
+ failures: runtime.failures.length,
109
+ reach
110
+ })
111
+ }
112
+ ]
113
+ });
114
+ if (runtime.failures.length > 0) {
115
+ parts.push({
116
+ kind: "findings",
117
+ stream: "err",
118
+ sections: [
119
+ failureSection(runtime.failures),
120
+ ...inventory ? [noVerdictSection(runtime.failures)] : []
121
+ ]
122
+ });
123
+ }
124
+ await present.emit(...parts);
125
+ return runtime.failures.length > 0 ? 2 : 0;
126
+ }
127
+ export {
128
+ runSnapshot
129
+ };
130
+ //# sourceMappingURL=snapshot-GTDFQTN2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/snapshot.ts"],"sourcesContent":["import {\n joinCoverage,\n mountScenarios,\n readInventory,\n UsageError,\n type AnalysisOptions,\n type Depth,\n} from \"../analysis.js\";\nimport { baselinePath, writeBaseline, writeScenarioManifest } from \"../baseline.js\";\nimport { scenarioBaseline } from \"../report.js\";\nimport { buildView, flatRows } from \"../render/model.js\";\nimport { createPresenter } from \"../render/present.js\";\nimport {\n coverageSections,\n displayPath,\n failureSection,\n mountingLabel,\n neverCallable,\n neverCallableSection,\n noVerdictSection,\n READING_SOURCE,\n runHeaderBlocks,\n scenarioStats,\n surfaceSummaryRows,\n trackReach,\n type CapabilityReach,\n type ReportPart,\n} from \"../render/summary.js\";\n\nexport interface SnapshotOptions {\n configPath: string;\n depth: Depth;\n scenario?: string;\n scope?: string[];\n tsconfig?: string;\n baselineDir?: string;\n json?: boolean;\n plain?: boolean;\n}\n\n/**\n * Writes (or refreshes) the committed baseline `check` compares against.\n *\n * It prints the coverage verdict too. This is the command you run to *accept* a\n * change to the surface, which makes it the last moment before a reviewer sees\n * the diff — and accepting a projection while a capability sits behind a route\n * no scenario visits is exactly the state worth hearing about. It reports;\n * `check` is still the only thing that fails.\n *\n * Its report opens the way every other one does (`AS-CLI-013`): what the run\n * was pointed at, then what it wrote, then the verdict. It used to open with\n * bare `wrote …` lines and no header at all, which left the one command that\n * *changes committed files* as the only one that never said what it had been\n * pointed at while it did.\n */\nexport async function runSnapshot(options: SnapshotOptions): Promise<number> {\n if (options.depth === \"static\") {\n throw new UsageError(\n \"snapshot --depth static has nothing to write — a baseline is a projection, and \" +\n \"at this depth nothing is mounted.\",\n );\n }\n\n const analysis: AnalysisOptions = {\n configPath: options.configPath,\n depth: options.depth,\n ...(options.scenario ? { scenario: options.scenario } : {}),\n ...(options.scope ? { scope: options.scope } : {}),\n ...(options.tsconfig ? { tsconfig: options.tsconfig } : {}),\n ...(options.baselineDir ? { baselineDir: options.baselineDir } : {}),\n };\n\n const present = await createPresenter(options);\n await present.wait(READING_SOURCE);\n\n const inventory = readInventory(analysis);\n let scenarios: string[] = [];\n let mountedCount = 0;\n const runtime = await mountScenarios(analysis, {\n onPlan: async (plan) => {\n scenarios = plan.scenarios;\n await present.emit({\n kind: \"blocks\",\n blocks: runHeaderBlocks(\"SURFACE SNAPSHOT\", {\n configPath: options.configPath,\n depth: options.depth,\n ...(plan.scope ? { scope: plan.scope } : {}),\n scenarios: plan.scenarios,\n declaredScenarios: plan.declaredScenarios,\n }),\n });\n if (scenarios.length > 0) await present.wait(mountingLabel(scenarios, 0));\n },\n onEach: async () => {\n mountedCount += 1;\n if (mountedCount < scenarios.length) {\n await present.wait(mountingLabel(scenarios, mountedCount));\n }\n },\n });\n present.settle();\n if (!runtime) throw new UsageError(\"snapshot needs a mount, and this depth performs none\");\n\n const written: Array<{ cells: string[] }> = [];\n for (const result of runtime.results) {\n const path = baselinePath(runtime.baselineDir, result.scenario);\n writeBaseline(path, scenarioBaseline(result));\n written.push({ cells: [result.scenario, displayPath(path)] });\n }\n writeScenarioManifest(runtime.baselineDir, runtime.declaredScenarios);\n\n const reach = new Map<string, CapabilityReach>();\n for (const result of runtime.results) {\n trackReach(reach, flatRows(buildView(result)), result.scenario);\n }\n const coverage = joinCoverage(inventory, runtime, analysis);\n const stats = runtime.results.map(scenarioStats);\n const dark = neverCallable(reach);\n\n const parts: ReportPart[] = [\n { kind: \"table\", title: `WROTE (${written.length})`, headers: [\"SCENARIO\", \"FILE\"], rows: written },\n ];\n\n // Over one scenario, \"never callable\" repeats that scenario's own table row\n // for row — see neverCallableSection().\n const sections = [\n ...(coverage ? coverageSections(coverage) : []),\n ...(dark.length > 0 && stats.length > 1 ? [neverCallableSection(dark)] : []),\n ];\n if (sections.length > 0) parts.push({ kind: \"findings\", sections });\n\n parts.push({\n kind: \"blocks\",\n blocks: [\n {\n title: \"SURFACE SUMMARY\",\n rows: surfaceSummaryRows({\n depth: options.depth,\n ...(coverage ? { coverage } : {}),\n scenarios: stats,\n failures: runtime.failures.length,\n reach,\n }),\n },\n ],\n });\n\n if (runtime.failures.length > 0) {\n // A baseline written for some scenarios and not others is a baseline that\n // will fail `check` for a reason that has nothing to do with the surface.\n parts.push({\n kind: \"findings\",\n stream: \"err\",\n sections: [\n failureSection(runtime.failures),\n ...(inventory ? [noVerdictSection(runtime.failures)] : []),\n ],\n });\n }\n\n await present.emit(...parts);\n return runtime.failures.length > 0 ? 2 : 0;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDA,eAAsB,YAAY,SAA2C;AAC3E,MAAI,QAAQ,UAAU,UAAU;AAC9B,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAEA,QAAM,WAA4B;AAAA,IAChC,YAAY,QAAQ;AAAA,IACpB,OAAO,QAAQ;AAAA,IACf,GAAI,QAAQ,WAAW,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;AAAA,IACzD,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;AAAA,IAChD,GAAI,QAAQ,WAAW,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;AAAA,IACzD,GAAI,QAAQ,cAAc,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;AAAA,EACpE;AAEA,QAAM,UAAU,MAAM,gBAAgB,OAAO;AAC7C,QAAM,QAAQ,KAAK,cAAc;AAEjC,QAAM,YAAY,cAAc,QAAQ;AACxC,MAAI,YAAsB,CAAC;AAC3B,MAAI,eAAe;AACnB,QAAM,UAAU,MAAM,eAAe,UAAU;AAAA,IAC7C,QAAQ,OAAO,SAAS;AACtB,kBAAY,KAAK;AACjB,YAAM,QAAQ,KAAK;AAAA,QACjB,MAAM;AAAA,QACN,QAAQ,gBAAgB,oBAAoB;AAAA,UAC1C,YAAY,QAAQ;AAAA,UACpB,OAAO,QAAQ;AAAA,UACf,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;AAAA,UAC1C,WAAW,KAAK;AAAA,UAChB,mBAAmB,KAAK;AAAA,QAC1B,CAAC;AAAA,MACH,CAAC;AACD,UAAI,UAAU,SAAS,EAAG,OAAM,QAAQ,KAAK,cAAc,WAAW,CAAC,CAAC;AAAA,IAC1E;AAAA,IACA,QAAQ,YAAY;AAClB,sBAAgB;AAChB,UAAI,eAAe,UAAU,QAAQ;AACnC,cAAM,QAAQ,KAAK,cAAc,WAAW,YAAY,CAAC;AAAA,MAC3D;AAAA,IACF;AAAA,EACF,CAAC;AACD,UAAQ,OAAO;AACf,MAAI,CAAC,QAAS,OAAM,IAAI,WAAW,sDAAsD;AAEzF,QAAM,UAAsC,CAAC;AAC7C,aAAW,UAAU,QAAQ,SAAS;AACpC,UAAM,OAAO,aAAa,QAAQ,aAAa,OAAO,QAAQ;AAC9D,kBAAc,MAAM,iBAAiB,MAAM,CAAC;AAC5C,YAAQ,KAAK,EAAE,OAAO,CAAC,OAAO,UAAU,YAAY,IAAI,CAAC,EAAE,CAAC;AAAA,EAC9D;AACA,wBAAsB,QAAQ,aAAa,QAAQ,iBAAiB;AAEpE,QAAM,QAAQ,oBAAI,IAA6B;AAC/C,aAAW,UAAU,QAAQ,SAAS;AACpC,eAAW,OAAO,SAAS,UAAU,MAAM,CAAC,GAAG,OAAO,QAAQ;AAAA,EAChE;AACA,QAAM,WAAW,aAAa,WAAW,SAAS,QAAQ;AAC1D,QAAM,QAAQ,QAAQ,QAAQ,IAAI,aAAa;AAC/C,QAAM,OAAO,cAAc,KAAK;AAEhC,QAAM,QAAsB;AAAA,IAC1B,EAAE,MAAM,SAAS,OAAO,WAAW,QAAQ,MAAM,KAAK,SAAS,CAAC,YAAY,MAAM,GAAG,MAAM,QAAQ;AAAA,EACrG;AAIA,QAAM,WAAW;AAAA,IACf,GAAI,WAAW,iBAAiB,QAAQ,IAAI,CAAC;AAAA,IAC7C,GAAI,KAAK,SAAS,KAAK,MAAM,SAAS,IAAI,CAAC,qBAAqB,IAAI,CAAC,IAAI,CAAC;AAAA,EAC5E;AACA,MAAI,SAAS,SAAS,EAAG,OAAM,KAAK,EAAE,MAAM,YAAY,SAAS,CAAC;AAElE,QAAM,KAAK;AAAA,IACT,MAAM;AAAA,IACN,QAAQ;AAAA,MACN;AAAA,QACE,OAAO;AAAA,QACP,MAAM,mBAAmB;AAAA,UACvB,OAAO,QAAQ;AAAA,UACf,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,UAC/B,WAAW;AAAA,UACX,UAAU,QAAQ,SAAS;AAAA,UAC3B;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC;AAED,MAAI,QAAQ,SAAS,SAAS,GAAG;AAG/B,UAAM,KAAK;AAAA,MACT,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,UAAU;AAAA,QACR,eAAe,QAAQ,QAAQ;AAAA,QAC/B,GAAI,YAAY,CAAC,iBAAiB,QAAQ,QAAQ,CAAC,IAAI,CAAC;AAAA,MAC1D;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,QAAQ,KAAK,GAAG,KAAK;AAC3B,SAAO,QAAQ,SAAS,SAAS,IAAI,IAAI;AAC3C;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-surface/cli",
3
- "version": "0.12.1",
3
+ "version": "0.14.0",
4
4
  "description": "Inspect and check the agent surface your app exposes — in the terminal and in CI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -31,9 +31,9 @@
31
31
  "typescript": "^5.9.2",
32
32
  "vite": "^7.1.3",
33
33
  "vite-node": "^3.2.4",
34
- "@agent-surface/core": "^0.12.1",
35
- "@agent-surface/react": "^0.12.1",
36
- "@agent-surface/testing": "^0.12.1"
34
+ "@agent-surface/core": "^0.13.0",
35
+ "@agent-surface/testing": "^0.13.0",
36
+ "@agent-surface/react": "^0.13.0"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@testing-library/react": ">=14",
@@ -1,183 +0,0 @@
1
- import {
2
- coverageReport,
3
- renderCheckOverviewPlain,
4
- renderCoveragePlain,
5
- renderDriftPlain,
6
- renderFailuresPlain,
7
- renderNoVerdictPlain,
8
- scenarioBaseline
9
- } from "./chunk-J2NN3J5N.js";
10
- import "./chunk-DYDSJM7R.js";
11
- import {
12
- ALLOWLIST_FILE,
13
- SCENARIO_MANIFEST_FILE,
14
- UNREAD_ALLOWLIST_FILE,
15
- annotate,
16
- baselinePath,
17
- coverageExitCode,
18
- diff,
19
- joinCoverage,
20
- mountScenarios,
21
- readBaseline,
22
- readInventory,
23
- readScenarioManifest
24
- } from "./chunk-Q5WOLWEW.js";
25
- import {
26
- UsageError,
27
- write,
28
- writeError
29
- } from "./chunk-QIVOZAWX.js";
30
-
31
- // src/commands/check.ts
32
- import { existsSync, readdirSync } from "fs";
33
- import { relative } from "path";
34
- async function runCheck(options) {
35
- if (options.depth === "static") {
36
- throw new UsageError(
37
- "check --depth static has nothing to compare \u2014 a baseline is a projection, and at this depth nothing is mounted. Use --depth runtime for drift alone, or full for both."
38
- );
39
- }
40
- const analysis = {
41
- configPath: options.configPath,
42
- depth: options.depth,
43
- ...options.scenario ? { scenario: options.scenario } : {},
44
- ...options.scope ? { scope: options.scope } : {},
45
- ...options.tsconfig ? { tsconfig: options.tsconfig } : {},
46
- ...options.baselineDir ? { baselineDir: options.baselineDir } : {}
47
- };
48
- const inventory = readInventory(analysis);
49
- const runtime = await mountScenarios(analysis);
50
- if (!runtime) throw new UsageError("check needs a mount, and this depth performs none");
51
- const drifted = [];
52
- for (const result of runtime.results) {
53
- const path = baselinePath(runtime.baselineDir, result.scenario);
54
- const expected = readBaseline(path);
55
- if (expected === void 0) {
56
- drifted.push({ scenario: result.scenario, missingBaseline: true, entries: [] });
57
- continue;
58
- }
59
- const actual = scenarioBaseline(result);
60
- const entries = annotate(diff(expected, actual), actual, expected);
61
- if (entries.length > 0) drifted.push({ scenario: result.scenario, entries });
62
- }
63
- const committedScenarios = readScenarioManifest(runtime.baselineDir);
64
- const declared = [...runtime.declaredScenarios].sort();
65
- const scenarioManifestMismatch = committedScenarios === void 0 || JSON.stringify(committedScenarios) !== JSON.stringify(declared);
66
- const reserved = /* @__PURE__ */ new Set([SCENARIO_MANIFEST_FILE, ALLOWLIST_FILE, UNREAD_ALLOWLIST_FILE]);
67
- const staleBaselineFiles = (existsSync(runtime.baselineDir) ? readdirSync(runtime.baselineDir, { withFileTypes: true }) : []).filter((entry) => entry.isFile() && entry.name.endsWith(".json") && !reserved.has(entry.name)).map((entry) => entry.name.slice(0, -5)).filter((scenario) => !runtime.declaredScenarios.includes(scenario)).sort();
68
- const rejected = runtime.results.filter((result) => result.rejections.length > 0).map((result) => ({ scenario: result.scenario, rejections: result.rejections }));
69
- const coverage = joinCoverage(inventory, runtime, analysis);
70
- const coverageFailed = coverage !== void 0 && coverageExitCode(coverage, { allowUnresolved: options.allowUnresolved === true }) !== 0;
71
- const couldNotRun = runtime.failures.length > 0;
72
- const ok = drifted.length === 0 && !coverageFailed && !couldNotRun && rejected.length === 0 && !scenarioManifestMismatch && staleBaselineFiles.length === 0;
73
- if (options.json) {
74
- write(
75
- JSON.stringify(
76
- {
77
- ok,
78
- drifted,
79
- failures: runtime.failures,
80
- rejected,
81
- scenarioManifest: {
82
- expected: declared,
83
- committed: committedScenarios ?? null,
84
- staleBaselines: staleBaselineFiles
85
- },
86
- coverage: coverageReport(coverage)
87
- },
88
- null,
89
- 2
90
- )
91
- );
92
- return couldNotRun ? 2 : ok ? 0 : 1;
93
- }
94
- const overview = renderCheckOverviewPlain({
95
- status: couldNotRun ? "ERROR" : ok ? "PASS" : "FAIL",
96
- ...coverage ? { coverage } : {},
97
- unresolvedAllowed: options.allowUnresolved === true,
98
- baselineCurrent: Math.max(0, runtime.results.length - drifted.length),
99
- baselineTotal: runtime.scenarios.length,
100
- scenarioManifestOk: !scenarioManifestMismatch && staleBaselineFiles.length === 0,
101
- rejected: rejected.reduce((sum, entry) => sum + entry.rejections.length, 0),
102
- mountFailures: runtime.failures.length,
103
- scenarios: runtime.scenarios
104
- });
105
- if (ok) write(overview);
106
- else writeError(overview);
107
- if (coverage) {
108
- const rendered = renderCoveragePlain(coverage, {
109
- compact: true,
110
- ...options.detail ? { detail: true } : {}
111
- });
112
- if (rendered) {
113
- if (coverageFailed) writeError(`
114
- ${rendered}`);
115
- else write(`
116
- ${rendered}`);
117
- }
118
- }
119
- const missing = drifted.filter((entry) => entry.missingBaseline);
120
- const changed = drifted.filter((entry) => !entry.missingBaseline);
121
- if (rejected.length > 0) {
122
- writeError(
123
- [
124
- `${coverage ? "\n" : ""}REJECTED REGISTRATIONS \u2014 the runtime refused authored surface (${rejected.reduce((sum, entry) => sum + entry.rejections.length, 0)})`,
125
- ...rejected.flatMap(
126
- (entry) => entry.rejections.map(
127
- (rejection) => ` ${entry.scenario}: ${rejection.componentType}@${rejection.instanceId} (${rejection.reason})`
128
- )
129
- )
130
- ].join("\n")
131
- );
132
- }
133
- if (scenarioManifestMismatch || staleBaselineFiles.length > 0) {
134
- const committed = committedScenarios?.join(", ") ?? "missing";
135
- writeError(
136
- [
137
- `${coverage || rejected.length > 0 ? "\n" : ""}SCENARIO DRIFT \u2014 committed baselines do not match config`,
138
- ` config: ${declared.join(", ")}`,
139
- ` manifest: ${committed}`,
140
- ...staleBaselineFiles.length > 0 ? [` stale baselines: ${staleBaselineFiles.join(", ")}`] : [],
141
- " run `agent-surface snapshot` and commit the manifest"
142
- ].join("\n")
143
- );
144
- }
145
- if (missing.length > 0) {
146
- writeError(
147
- [
148
- `${coverage ? "\n" : ""}NO BASELINE \u2014 nothing to compare against, which is not the same as a match (${missing.length})`,
149
- ...missing.map(
150
- (entry) => ` ${entry.scenario}: ${relative(
151
- process.cwd(),
152
- baselinePath(runtime.baselineDir, entry.scenario)
153
- )} does not exist \u2014 run \`agent-surface snapshot\` and commit it`
154
- )
155
- ].join("\n")
156
- );
157
- }
158
- if (changed.length > 0) {
159
- writeError(
160
- [
161
- `${coverage || missing.length > 0 ? "\n" : ""}DRIFT \u2014 the surface changed against its baseline (${changed.length})`,
162
- ...changed.map((entry) => renderDriftPlain(entry.scenario, entry.entries)),
163
- "",
164
- `surface drift in ${changed.length} scenario${changed.length === 1 ? "" : "s"} \u2014 review the change, then \`agent-surface snapshot\` to accept it`
165
- ].join("\n")
166
- );
167
- }
168
- if (couldNotRun) {
169
- writeError(`
170
- ${renderFailuresPlain(runtime.failures)}`);
171
- if (inventory) writeError(`
172
- ${renderNoVerdictPlain(runtime.failures)}`);
173
- return 2;
174
- }
175
- if (ok) {
176
- return 0;
177
- }
178
- return 1;
179
- }
180
- export {
181
- runCheck
182
- };
183
- //# sourceMappingURL=check-POE5VRSE.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/check.ts"],"sourcesContent":["import { existsSync, readdirSync } from \"node:fs\";\nimport { relative } from \"node:path\";\nimport {\n UsageError,\n joinCoverage,\n mountScenarios,\n readInventory,\n type AnalysisOptions,\n type Depth,\n} from \"../analysis.js\";\nimport {\n annotate,\n baselinePath,\n diff,\n readBaseline,\n readScenarioManifest,\n SCENARIO_MANIFEST_FILE,\n type DiffEntry,\n} from \"../baseline.js\";\nimport { ALLOWLIST_FILE, coverageExitCode, UNREAD_ALLOWLIST_FILE } from \"../coverage.js\";\nimport {\n renderCoveragePlain,\n renderCheckOverviewPlain,\n renderDriftPlain,\n renderFailuresPlain,\n renderNoVerdictPlain,\n} from \"../render/plain.js\";\nimport { write, writeError } from \"../output.js\";\nimport { coverageReport, scenarioBaseline } from \"../report.js\";\n\nexport interface CheckOptions {\n configPath: string;\n depth: Depth;\n scenario?: string;\n scope?: string[];\n tsconfig?: string;\n baselineDir?: string;\n allowUnresolved?: boolean;\n json?: boolean;\n plain?: boolean;\n detail?: boolean;\n}\n\ninterface ScenarioDrift {\n scenario: string;\n missingBaseline?: boolean;\n entries: DiffEntry[];\n}\n\ninterface RejectedScenario {\n scenario: string;\n rejections: Array<{ componentType: string; instanceId: string; reason: string }>;\n}\n\n/**\n * The gate. The only command in this package that fails on a finding, which is\n * why every finding has to reach it.\n *\n * It used to fail on exactly one class — the projection drifting from its\n * baseline — and print a line telling you that capabilities no scenario mounts\n * were a different command's question. A gate that names the check it is not\n * performing is a gate with a hole in it, and in CI the hole was silent: a\n * whole unreached route sat behind a green tick.\n *\n * So it now fails on every incomplete or changed report:\n *\n * - **drift** — the surface changed against its committed baseline;\n * - **a missing baseline** — nothing to compare, which is not the same as a match;\n * - **an unreached capability** — authored, and no scenario mounts it;\n * - **an unread call site** — the catalog is incomplete, so the third check\n * above is computed over a denominator that is only a floor;\n * - **a rejected registration** — authored surface was refused;\n * - **scenario drift** — config, manifest and baseline files disagree.\n *\n * `.agent-surface/coverage-allow.json` ratchets the third; `--allow-unresolved`\n * accepts the fourth. Both are deliberate, committed decisions rather than\n * flags that quietly widen the gate.\n *\n * Output is always plain, with no rendering framework in its path at all: this\n * is a report that gets pasted into a pull request and read out of a CI log,\n * and neither of those is a terminal.\n */\nexport async function runCheck(options: CheckOptions): Promise<number> {\n if (options.depth === \"static\") {\n throw new UsageError(\n \"check --depth static has nothing to compare — a baseline is a projection, and \" +\n \"at this depth nothing is mounted. Use --depth runtime for drift alone, or full for both.\",\n );\n }\n\n const analysis: AnalysisOptions = {\n configPath: options.configPath,\n depth: options.depth,\n ...(options.scenario ? { scenario: options.scenario } : {}),\n ...(options.scope ? { scope: options.scope } : {}),\n ...(options.tsconfig ? { tsconfig: options.tsconfig } : {}),\n ...(options.baselineDir ? { baselineDir: options.baselineDir } : {}),\n };\n\n const inventory = readInventory(analysis);\n // No streaming here, unlike `inspect`. A report is read top-down and has to\n // lead with its findings, which means every finding has to exist first.\n const runtime = await mountScenarios(analysis);\n if (!runtime) throw new UsageError(\"check needs a mount, and this depth performs none\");\n\n const drifted: ScenarioDrift[] = [];\n for (const result of runtime.results) {\n const path = baselinePath(runtime.baselineDir, result.scenario);\n const expected = readBaseline(path);\n if (expected === undefined) {\n drifted.push({ scenario: result.scenario, missingBaseline: true, entries: [] });\n continue;\n }\n const actual = scenarioBaseline(result);\n const entries = annotate(diff(expected, actual), actual, expected);\n if (entries.length > 0) drifted.push({ scenario: result.scenario, entries });\n }\n\n const committedScenarios = readScenarioManifest(runtime.baselineDir);\n const declared = [...runtime.declaredScenarios].sort();\n const scenarioManifestMismatch =\n committedScenarios === undefined ||\n JSON.stringify(committedScenarios) !== JSON.stringify(declared);\n const reserved = new Set([SCENARIO_MANIFEST_FILE, ALLOWLIST_FILE, UNREAD_ALLOWLIST_FILE]);\n const staleBaselineFiles = (existsSync(runtime.baselineDir)\n ? readdirSync(runtime.baselineDir, { withFileTypes: true })\n : [])\n .filter((entry) => entry.isFile() && entry.name.endsWith(\".json\") && !reserved.has(entry.name))\n .map((entry) => entry.name.slice(0, -5))\n .filter((scenario) => !runtime.declaredScenarios.includes(scenario))\n .sort();\n\n const rejected: RejectedScenario[] = runtime.results\n .filter((result) => result.rejections.length > 0)\n .map((result) => ({ scenario: result.scenario, rejections: result.rejections }));\n\n const coverage = joinCoverage(inventory, runtime, analysis);\n const coverageFailed =\n coverage !== undefined &&\n coverageExitCode(coverage, { allowUnresolved: options.allowUnresolved === true }) !== 0;\n const couldNotRun = runtime.failures.length > 0;\n const ok =\n drifted.length === 0 &&\n !coverageFailed &&\n !couldNotRun &&\n rejected.length === 0 &&\n !scenarioManifestMismatch &&\n staleBaselineFiles.length === 0;\n\n if (options.json) {\n write(\n JSON.stringify(\n {\n ok,\n drifted,\n failures: runtime.failures,\n rejected,\n scenarioManifest: {\n expected: declared,\n committed: committedScenarios ?? null,\n staleBaselines: staleBaselineFiles,\n },\n coverage: coverageReport(coverage),\n },\n null,\n 2,\n ),\n );\n return couldNotRun ? 2 : ok ? 0 : 1;\n }\n\n const overview = renderCheckOverviewPlain({\n status: couldNotRun ? \"ERROR\" : ok ? \"PASS\" : \"FAIL\",\n ...(coverage ? { coverage } : {}),\n unresolvedAllowed: options.allowUnresolved === true,\n baselineCurrent: Math.max(0, runtime.results.length - drifted.length),\n baselineTotal: runtime.scenarios.length,\n scenarioManifestOk: !scenarioManifestMismatch && staleBaselineFiles.length === 0,\n rejected: rejected.reduce((sum, entry) => sum + entry.rejections.length, 0),\n mountFailures: runtime.failures.length,\n scenarios: runtime.scenarios,\n });\n if (ok) write(overview);\n else writeError(overview);\n\n // The gap leads, because it is the finding this command could not previously\n // make at all. Drift follows, because it is the one it always could.\n if (coverage) {\n const rendered = renderCoveragePlain(coverage, {\n compact: true,\n ...(options.detail ? { detail: true } : {}),\n });\n if (rendered) {\n if (coverageFailed) writeError(`\\n${rendered}`);\n else write(`\\n${rendered}`);\n }\n }\n\n // \"No baseline\" is not drift, and filing it under a heading that says the\n // surface changed would be a claim about a comparison that never happened.\n const missing = drifted.filter((entry) => entry.missingBaseline);\n const changed = drifted.filter((entry) => !entry.missingBaseline);\n\n if (rejected.length > 0) {\n writeError(\n [\n `${coverage ? \"\\n\" : \"\"}REJECTED REGISTRATIONS — the runtime refused authored surface (${rejected.reduce((sum, entry) => sum + entry.rejections.length, 0)})`,\n ...rejected.flatMap((entry) =>\n entry.rejections.map(\n (rejection) =>\n ` ${entry.scenario}: ${rejection.componentType}@${rejection.instanceId} (${rejection.reason})`,\n ),\n ),\n ].join(\"\\n\"),\n );\n }\n\n if (scenarioManifestMismatch || staleBaselineFiles.length > 0) {\n const committed = committedScenarios?.join(\", \") ?? \"missing\";\n writeError(\n [\n `${coverage || rejected.length > 0 ? \"\\n\" : \"\"}SCENARIO DRIFT — committed baselines do not match config`,\n ` config: ${declared.join(\", \")}`,\n ` manifest: ${committed}`,\n ...(staleBaselineFiles.length > 0\n ? [` stale baselines: ${staleBaselineFiles.join(\", \")}`]\n : []),\n \" run `agent-surface snapshot` and commit the manifest\",\n ].join(\"\\n\"),\n );\n }\n\n if (missing.length > 0) {\n writeError(\n [\n `${coverage ? \"\\n\" : \"\"}NO BASELINE — nothing to compare against, which is not the same as a match (${missing.length})`,\n ...missing.map(\n (entry) =>\n ` ${entry.scenario}: ${relative(\n process.cwd(),\n baselinePath(runtime.baselineDir, entry.scenario),\n )} does not exist — run \\`agent-surface snapshot\\` and commit it`,\n ),\n ].join(\"\\n\"),\n );\n }\n\n if (changed.length > 0) {\n writeError(\n [\n `${coverage || missing.length > 0 ? \"\\n\" : \"\"}DRIFT — the surface changed against its baseline (${changed.length})`,\n ...changed.map((entry) => renderDriftPlain(entry.scenario, entry.entries)),\n \"\",\n `surface drift in ${changed.length} scenario${\n changed.length === 1 ? \"\" : \"s\"\n } — review the change, then \\`agent-surface snapshot\\` to accept it`,\n ].join(\"\\n\"),\n );\n }\n\n if (couldNotRun) {\n writeError(`\\n${renderFailuresPlain(runtime.failures)}`);\n if (inventory) writeError(`\\n${renderNoVerdictPlain(runtime.failures)}`);\n return 2;\n }\n\n if (ok) {\n return 0;\n }\n return 1;\n}\n"],"mappings":"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","names":[]}