@agent-surface/cli 0.12.0 → 0.13.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.
- package/README.md +45 -7
- package/dist/bin.js +15 -7
- package/dist/bin.js.map +1 -1
- package/dist/check-TJIX7NDE.js +241 -0
- package/dist/check-TJIX7NDE.js.map +1 -0
- package/dist/{chunk-QIVOZAWX.js → chunk-3AJ343NA.js} +12 -3
- package/dist/{chunk-QIVOZAWX.js.map → chunk-3AJ343NA.js.map} +1 -1
- package/dist/chunk-IALBMW3R.js +278 -0
- package/dist/chunk-IALBMW3R.js.map +1 -0
- package/dist/chunk-L7GHSC2Z.js +465 -0
- package/dist/chunk-L7GHSC2Z.js.map +1 -0
- package/dist/{chunk-Q5WOLWEW.js → chunk-UGCLJ5JX.js} +26 -286
- package/dist/chunk-UGCLJ5JX.js.map +1 -0
- package/dist/chunk-VX6GBEP3.js +539 -0
- package/dist/chunk-VX6GBEP3.js.map +1 -0
- package/dist/{init-LFQ5R3G7.js → init-6XV64LK2.js} +9 -8
- package/dist/{init-LFQ5R3G7.js.map → init-6XV64LK2.js.map} +1 -1
- package/dist/{ink-P23VKP4H.js → ink-QR7X7TAC.js} +99 -25
- package/dist/ink-QR7X7TAC.js.map +1 -0
- package/dist/inspect-NJ4J3MPP.js +242 -0
- package/dist/inspect-NJ4J3MPP.js.map +1 -0
- package/dist/{snapshot-3E7MVMVG.js → snapshot-ZGTAF2Y5.js} +28 -12
- package/dist/snapshot-ZGTAF2Y5.js.map +1 -0
- package/package.json +4 -4
- package/dist/check-CS4Z3ZK3.js +0 -169
- package/dist/check-CS4Z3ZK3.js.map +0 -1
- package/dist/chunk-DYDSJM7R.js +0 -170
- package/dist/chunk-DYDSJM7R.js.map +0 -1
- package/dist/chunk-Q5WOLWEW.js.map +0 -1
- package/dist/chunk-TPWRSFK7.js +0 -380
- package/dist/chunk-TPWRSFK7.js.map +0 -1
- package/dist/ink-P23VKP4H.js.map +0 -1
- package/dist/inspect-ELUQ73MZ.js +0 -119
- package/dist/inspect-ELUQ73MZ.js.map +0 -1
- package/dist/snapshot-3E7MVMVG.js.map +0 -1
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import {
|
|
2
|
+
UsageError,
|
|
3
|
+
createSurfaceRunner
|
|
4
|
+
} from "./chunk-3AJ343NA.js";
|
|
5
|
+
import {
|
|
6
|
+
allowlistPathFor,
|
|
7
|
+
authoredIds,
|
|
8
|
+
buildCoverageReport,
|
|
9
|
+
extractCapabilities,
|
|
10
|
+
readAllowlist,
|
|
11
|
+
readLiteralConfigScope,
|
|
12
|
+
unreadAllowlistPathFor,
|
|
13
|
+
unresolved
|
|
14
|
+
} from "./chunk-UGCLJ5JX.js";
|
|
15
|
+
|
|
16
|
+
// src/baseline.ts
|
|
17
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
18
|
+
import { dirname, join, resolve, sep } from "path";
|
|
19
|
+
import { serializeSurfaceSnapshot } from "@agent-surface/testing";
|
|
20
|
+
var DEFAULT_BASELINE_DIR = ".agent-surface";
|
|
21
|
+
var SCENARIO_MANIFEST_FILE = "scenarios.json";
|
|
22
|
+
function baselineDirFor(configPath, configured) {
|
|
23
|
+
return resolve(dirname(configPath), configured ?? DEFAULT_BASELINE_DIR);
|
|
24
|
+
}
|
|
25
|
+
function baselinePath(dir, scenario) {
|
|
26
|
+
const reserved = /* @__PURE__ */ new Set(["scenarios", "coverage-allow", "unresolved-allow"]);
|
|
27
|
+
if (scenario.length === 0 || scenario === "." || scenario === ".." || scenario.includes("/") || scenario.includes("\\") || scenario.includes("\0") || reserved.has(scenario)) {
|
|
28
|
+
throw new Error(`invalid scenario name ${JSON.stringify(scenario)} \u2014 use a filename-safe name`);
|
|
29
|
+
}
|
|
30
|
+
const root = resolve(dir);
|
|
31
|
+
const path = resolve(root, `${scenario}.json`);
|
|
32
|
+
if (!path.startsWith(`${root}${sep}`)) {
|
|
33
|
+
throw new Error(`scenario ${JSON.stringify(scenario)} escapes the baseline directory`);
|
|
34
|
+
}
|
|
35
|
+
return path;
|
|
36
|
+
}
|
|
37
|
+
function scenarioManifestPath(dir) {
|
|
38
|
+
return join(dir, SCENARIO_MANIFEST_FILE);
|
|
39
|
+
}
|
|
40
|
+
function normalize(snapshot) {
|
|
41
|
+
return serializeSurfaceSnapshot(snapshot);
|
|
42
|
+
}
|
|
43
|
+
function readBaseline(path) {
|
|
44
|
+
if (!existsSync(path)) return void 0;
|
|
45
|
+
try {
|
|
46
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
47
|
+
} catch (error) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`could not read baseline ${path}: ${error instanceof Error ? error.message : String(error)}`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function writeBaseline(path, value) {
|
|
54
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
55
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
56
|
+
`, "utf8");
|
|
57
|
+
}
|
|
58
|
+
function readScenarioManifest(dir) {
|
|
59
|
+
const path = scenarioManifestPath(dir);
|
|
60
|
+
const value = readBaseline(path);
|
|
61
|
+
if (value === void 0) return void 0;
|
|
62
|
+
if (typeof value !== "object" || value === null || !Array.isArray(value.scenarios) || !value.scenarios.every((name) => typeof name === "string")) {
|
|
63
|
+
throw new Error(`${path} must contain { "scenarios": string[] }`);
|
|
64
|
+
}
|
|
65
|
+
return [...value.scenarios].sort();
|
|
66
|
+
}
|
|
67
|
+
function writeScenarioManifest(dir, scenarios) {
|
|
68
|
+
writeBaseline(scenarioManifestPath(dir), { scenarios: [...scenarios].sort() });
|
|
69
|
+
}
|
|
70
|
+
var PATH_SEGMENT = /([^.[\]]+)|\[(\d+)\]/g;
|
|
71
|
+
function subjectFor(document, path) {
|
|
72
|
+
let node = document;
|
|
73
|
+
let subject;
|
|
74
|
+
for (const match of path.matchAll(PATH_SEGMENT)) {
|
|
75
|
+
if (typeof node !== "object" || node === null) return subject;
|
|
76
|
+
const record = node;
|
|
77
|
+
const candidate = record["capabilityId"] ?? record["procedureId"];
|
|
78
|
+
if (typeof candidate === "string") subject = candidate;
|
|
79
|
+
const key = match[1] ?? match[2];
|
|
80
|
+
if (key === void 0) return subject;
|
|
81
|
+
node = record[key];
|
|
82
|
+
}
|
|
83
|
+
if (typeof node === "object" && node !== null) {
|
|
84
|
+
const record = node;
|
|
85
|
+
const candidate = record["capabilityId"] ?? record["procedureId"];
|
|
86
|
+
if (typeof candidate === "string") subject = candidate;
|
|
87
|
+
}
|
|
88
|
+
return subject;
|
|
89
|
+
}
|
|
90
|
+
function annotate(entries, after, before) {
|
|
91
|
+
return entries.map((entry) => {
|
|
92
|
+
const subject = subjectFor(after, entry.path) ?? subjectFor(before, entry.path);
|
|
93
|
+
return subject ? { ...entry, subject } : entry;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function diff(before, after, path = "") {
|
|
97
|
+
if (Object.is(before, after)) return [];
|
|
98
|
+
const bothArrays = Array.isArray(before) && Array.isArray(after);
|
|
99
|
+
const bothObjects = !bothArrays && typeof before === "object" && typeof after === "object" && before !== null && after !== null;
|
|
100
|
+
if (bothArrays) {
|
|
101
|
+
const entries = [];
|
|
102
|
+
const max = Math.max(before.length, after.length);
|
|
103
|
+
for (let i = 0; i < max; i++) {
|
|
104
|
+
const at = `${path}[${i}]`;
|
|
105
|
+
if (i >= before.length) entries.push({ path: at, kind: "added", after: after[i] });
|
|
106
|
+
else if (i >= after.length) entries.push({ path: at, kind: "removed", before: before[i] });
|
|
107
|
+
else entries.push(...diff(before[i], after[i], at));
|
|
108
|
+
}
|
|
109
|
+
return entries;
|
|
110
|
+
}
|
|
111
|
+
if (bothObjects) {
|
|
112
|
+
const entries = [];
|
|
113
|
+
const beforeRecord = before;
|
|
114
|
+
const afterRecord = after;
|
|
115
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(beforeRecord), ...Object.keys(afterRecord)]);
|
|
116
|
+
for (const key of [...keys].sort()) {
|
|
117
|
+
const at = path ? `${path}.${key}` : key;
|
|
118
|
+
if (!(key in beforeRecord)) {
|
|
119
|
+
entries.push({ path: at, kind: "added", after: afterRecord[key] });
|
|
120
|
+
} else if (!(key in afterRecord)) {
|
|
121
|
+
entries.push({ path: at, kind: "removed", before: beforeRecord[key] });
|
|
122
|
+
} else {
|
|
123
|
+
entries.push(...diff(beforeRecord[key], afterRecord[key], at));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return entries;
|
|
127
|
+
}
|
|
128
|
+
if (JSON.stringify(before) === JSON.stringify(after)) return [];
|
|
129
|
+
return [{ path: path || "<root>", kind: "changed", before, after }];
|
|
130
|
+
}
|
|
131
|
+
function formatValue(value) {
|
|
132
|
+
if (value === void 0) return "\u2014";
|
|
133
|
+
const text = typeof value === "string" ? value : JSON.stringify(value);
|
|
134
|
+
return text.length > 120 ? `${text.slice(0, 117)}\u2026` : text;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/analysis.ts
|
|
138
|
+
import { dirname as dirname2 } from "path";
|
|
139
|
+
import { matchesScope } from "@agent-surface/core/explain";
|
|
140
|
+
function readInventory(options) {
|
|
141
|
+
if (options.depth === "runtime") return void 0;
|
|
142
|
+
return extractCapabilities({
|
|
143
|
+
root: dirname2(options.configPath),
|
|
144
|
+
...options.tsconfig ? { tsconfig: options.tsconfig } : {}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
function staticConfigScope(options) {
|
|
148
|
+
return options.scope ?? readLiteralConfigScope(options.configPath);
|
|
149
|
+
}
|
|
150
|
+
async function mountScenarios(options, hooks = {}) {
|
|
151
|
+
if (options.depth === "static") return void 0;
|
|
152
|
+
const runner = await createSurfaceRunner(options.configPath);
|
|
153
|
+
try {
|
|
154
|
+
if (options.scenario && !runner.scenarioNames.includes(options.scenario)) {
|
|
155
|
+
throw new UsageError(
|
|
156
|
+
`unknown scenario "${options.scenario}" \u2014 this config defines ` + runner.scenarioNames.map((name) => `"${name}"`).join(", ")
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
const scenarios = options.scenario ? [options.scenario] : runner.scenarioNames;
|
|
160
|
+
const effectiveScope = options.scope ?? runner.config.scope;
|
|
161
|
+
const results = [];
|
|
162
|
+
const failures = [];
|
|
163
|
+
const plan = {
|
|
164
|
+
scenarios,
|
|
165
|
+
declaredScenarios: runner.scenarioNames,
|
|
166
|
+
baselineDir: baselineDirFor(
|
|
167
|
+
options.configPath,
|
|
168
|
+
options.baselineDir ?? runner.config.baselineDir
|
|
169
|
+
),
|
|
170
|
+
...effectiveScope ? { scope: effectiveScope } : {},
|
|
171
|
+
domainCapabilities: Object.keys(runner.config.manifest?.tools ?? {}).map((path) => `domain:${path}`).sort(),
|
|
172
|
+
domainManifestConfigured: runner.config.manifest !== void 0
|
|
173
|
+
};
|
|
174
|
+
await hooks.onPlan?.(plan);
|
|
175
|
+
for (const scenario of scenarios) {
|
|
176
|
+
let result;
|
|
177
|
+
try {
|
|
178
|
+
result = await runner.collect({
|
|
179
|
+
scenario,
|
|
180
|
+
...options.scope ? { scope: options.scope } : {}
|
|
181
|
+
});
|
|
182
|
+
} catch (error) {
|
|
183
|
+
failures.push({
|
|
184
|
+
scenario,
|
|
185
|
+
message: error instanceof Error ? error.message : String(error)
|
|
186
|
+
});
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
results.push(result);
|
|
190
|
+
await hooks.onEach?.(result);
|
|
191
|
+
}
|
|
192
|
+
return { ...plan, results, failures };
|
|
193
|
+
} finally {
|
|
194
|
+
await runner.close();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function componentTypeOf(capabilityId) {
|
|
198
|
+
const withoutPlane = capabilityId.replace(/^(view|domain):/, "");
|
|
199
|
+
const dot = withoutPlane.lastIndexOf(".");
|
|
200
|
+
return dot === -1 ? withoutPlane : withoutPlane.slice(0, dot);
|
|
201
|
+
}
|
|
202
|
+
function scopeInventory(inventory, scope) {
|
|
203
|
+
if (!inventory || !scope) return inventory;
|
|
204
|
+
return {
|
|
205
|
+
...inventory,
|
|
206
|
+
capabilities: inventory.capabilities.filter(
|
|
207
|
+
(capability) => capability.resolution === "unresolved" || matchesScope(componentTypeOf(capability.capabilityId), scope)
|
|
208
|
+
)
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function scopeCapabilityIds(ids, scope) {
|
|
212
|
+
return scope ? ids.filter((id) => matchesScope(componentTypeOf(id), scope)) : ids;
|
|
213
|
+
}
|
|
214
|
+
function joinCoverage(inventory, runtime, options) {
|
|
215
|
+
if (!inventory || !runtime) return void 0;
|
|
216
|
+
if (runtime.failures.length > 0) return void 0;
|
|
217
|
+
const effectiveScope = options.scope ?? runtime.scope;
|
|
218
|
+
const inScope = (capabilityId) => matchesScope(componentTypeOf(capabilityId), effectiveScope);
|
|
219
|
+
const origins = /* @__PURE__ */ new Map();
|
|
220
|
+
for (const capability of inventory.capabilities) {
|
|
221
|
+
if (!origins.has(capability.capabilityId)) {
|
|
222
|
+
origins.set(capability.capabilityId, capability.origin);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
const authored = new Set([...authoredIds(inventory)].filter(inScope));
|
|
226
|
+
for (const capabilityId of runtime.domainCapabilities) {
|
|
227
|
+
if (inScope(capabilityId)) authored.add(capabilityId);
|
|
228
|
+
if (!origins.has(capabilityId)) {
|
|
229
|
+
origins.set(capabilityId, { file: "oRPC manifest", line: 0 });
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const reachedIds = /* @__PURE__ */ new Set();
|
|
233
|
+
for (const result of runtime.results) {
|
|
234
|
+
for (const capability of result.explanation.capabilities) {
|
|
235
|
+
reachedIds.add(capability.capabilityId);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
const allowlistPath = allowlistPathFor(runtime.baselineDir);
|
|
239
|
+
const wholeAllowlist = readAllowlist(allowlistPath);
|
|
240
|
+
const allowlist = Object.fromEntries(
|
|
241
|
+
Object.entries(wholeAllowlist).filter(([id]) => inScope(id))
|
|
242
|
+
);
|
|
243
|
+
const unreadAllowlistPath = unreadAllowlistPathFor(runtime.baselineDir);
|
|
244
|
+
return buildCoverageReport({
|
|
245
|
+
unreadAllowlist: readAllowlist(unreadAllowlistPath, "file#reason#site"),
|
|
246
|
+
unreadAllowlistPath,
|
|
247
|
+
domainAuthoritative: runtime.domainManifestConfigured,
|
|
248
|
+
authored,
|
|
249
|
+
origins,
|
|
250
|
+
reachedIds,
|
|
251
|
+
scenarios: runtime.scenarios,
|
|
252
|
+
...effectiveScope ? { scope: effectiveScope } : {},
|
|
253
|
+
unresolved: unresolved(inventory),
|
|
254
|
+
allowlist,
|
|
255
|
+
allowlistOutOfScope: Object.keys(wholeAllowlist).length - Object.keys(allowlist).length,
|
|
256
|
+
allowlistPath
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export {
|
|
261
|
+
SCENARIO_MANIFEST_FILE,
|
|
262
|
+
baselinePath,
|
|
263
|
+
normalize,
|
|
264
|
+
readBaseline,
|
|
265
|
+
writeBaseline,
|
|
266
|
+
readScenarioManifest,
|
|
267
|
+
writeScenarioManifest,
|
|
268
|
+
annotate,
|
|
269
|
+
diff,
|
|
270
|
+
formatValue,
|
|
271
|
+
readInventory,
|
|
272
|
+
staticConfigScope,
|
|
273
|
+
mountScenarios,
|
|
274
|
+
scopeInventory,
|
|
275
|
+
scopeCapabilityIds,
|
|
276
|
+
joinCoverage
|
|
277
|
+
};
|
|
278
|
+
//# sourceMappingURL=chunk-IALBMW3R.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/baseline.ts","../src/analysis.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, resolve, sep } from \"node:path\";\nimport { serializeSurfaceSnapshot } from \"@agent-surface/testing\";\nimport type { AgentSurfaceSnapshot } from \"@agent-surface/core\";\n\nexport const DEFAULT_BASELINE_DIR = \".agent-surface\";\nexport const SCENARIO_MANIFEST_FILE = \"scenarios.json\";\n\nexport function baselineDirFor(configPath: string, configured?: string): string {\n return resolve(dirname(configPath), configured ?? DEFAULT_BASELINE_DIR);\n}\n\nexport function baselinePath(dir: string, scenario: string): string {\n const reserved = new Set([\"scenarios\", \"coverage-allow\", \"unresolved-allow\"]);\n if (\n scenario.length === 0 ||\n scenario === \".\" ||\n scenario === \"..\" ||\n scenario.includes(\"/\") ||\n scenario.includes(\"\\\\\") ||\n scenario.includes(\"\\0\") ||\n reserved.has(scenario)\n ) {\n throw new Error(`invalid scenario name ${JSON.stringify(scenario)} — use a filename-safe name`);\n }\n const root = resolve(dir);\n const path = resolve(root, `${scenario}.json`);\n if (!path.startsWith(`${root}${sep}`)) {\n throw new Error(`scenario ${JSON.stringify(scenario)} escapes the baseline directory`);\n }\n return path;\n}\n\nexport function scenarioManifestPath(dir: string): string {\n return join(dir, SCENARIO_MANIFEST_FILE);\n}\n\n/**\n * The committed form. `serializeSurfaceSnapshot` is the same normalizer the\n * Vitest matcher uses: registration ids become stable placeholders and the\n * volatile fields (surfaceId, capturedAt, version) drop out, so a baseline\n * diff is a diff of *what agents can see* and nothing else.\n */\nexport function normalize(snapshot: AgentSurfaceSnapshot): unknown {\n return serializeSurfaceSnapshot(snapshot);\n}\n\nexport function readBaseline(path: string): unknown | undefined {\n if (!existsSync(path)) return undefined;\n try {\n return JSON.parse(readFileSync(path, \"utf8\")) as unknown;\n } catch (error) {\n throw new Error(\n `could not read baseline ${path}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\nexport function writeBaseline(path: string, value: unknown): void {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, `${JSON.stringify(value, null, 2)}\\n`, \"utf8\");\n}\n\nexport function readScenarioManifest(dir: string): string[] | undefined {\n const path = scenarioManifestPath(dir);\n const value = readBaseline(path);\n if (value === undefined) return undefined;\n if (\n typeof value !== \"object\" ||\n value === null ||\n !Array.isArray((value as { scenarios?: unknown }).scenarios) ||\n !(value as { scenarios: unknown[] }).scenarios.every((name) => typeof name === \"string\")\n ) {\n throw new Error(`${path} must contain { \"scenarios\": string[] }`);\n }\n return [...(value as { scenarios: string[] }).scenarios].sort();\n}\n\nexport function writeScenarioManifest(dir: string, scenarios: string[]): void {\n writeBaseline(scenarioManifestPath(dir), { scenarios: [...scenarios].sort() });\n}\n\nexport interface DiffEntry {\n path: string;\n kind: \"added\" | \"removed\" | \"changed\";\n before?: unknown;\n after?: unknown;\n /**\n * The capability the change belongs to. A reviewer needs to know that\n * `view:devices.table.sort` changed — `components[3].actions[1]` is the same\n * fact in a form nobody can act on.\n */\n subject?: string;\n}\n\nconst PATH_SEGMENT = /([^.[\\]]+)|\\[(\\d+)\\]/g;\n\n/** Nearest enclosing capability id for a diff path, if the path sits inside one. */\nfunction subjectFor(document: unknown, path: string): string | undefined {\n let node: unknown = document;\n let subject: string | undefined;\n for (const match of path.matchAll(PATH_SEGMENT)) {\n if (typeof node !== \"object\" || node === null) return subject;\n const record = node as Record<string, unknown>;\n const candidate = record[\"capabilityId\"] ?? record[\"procedureId\"];\n if (typeof candidate === \"string\") subject = candidate;\n const key = match[1] ?? match[2];\n if (key === undefined) return subject;\n node = record[key];\n }\n if (typeof node === \"object\" && node !== null) {\n const record = node as Record<string, unknown>;\n const candidate = record[\"capabilityId\"] ?? record[\"procedureId\"];\n if (typeof candidate === \"string\") subject = candidate;\n }\n return subject;\n}\n\n/** Labels each entry with the capability it belongs to, when there is one. */\nexport function annotate(entries: DiffEntry[], after: unknown, before: unknown): DiffEntry[] {\n return entries.map((entry) => {\n const subject = subjectFor(after, entry.path) ?? subjectFor(before, entry.path);\n return subject ? { ...entry, subject } : entry;\n });\n}\n\n/**\n * Structural diff, deliberately total: every difference is drift, including a\n * changed description. Descriptions are the provider's cached prompt prefix\n * (D28) — a silent edit re-bills every conversation, so it is exactly the kind\n * of change a reviewer should see.\n */\nexport function diff(before: unknown, after: unknown, path = \"\"): DiffEntry[] {\n if (Object.is(before, after)) return [];\n\n const bothArrays = Array.isArray(before) && Array.isArray(after);\n const bothObjects =\n !bothArrays &&\n typeof before === \"object\" &&\n typeof after === \"object\" &&\n before !== null &&\n after !== null;\n\n if (bothArrays) {\n const entries: DiffEntry[] = [];\n const max = Math.max(before.length, after.length);\n for (let i = 0; i < max; i++) {\n const at = `${path}[${i}]`;\n if (i >= before.length) entries.push({ path: at, kind: \"added\", after: after[i] });\n else if (i >= after.length) entries.push({ path: at, kind: \"removed\", before: before[i] });\n else entries.push(...diff(before[i], after[i], at));\n }\n return entries;\n }\n\n if (bothObjects) {\n const entries: DiffEntry[] = [];\n const beforeRecord = before as Record<string, unknown>;\n const afterRecord = after as Record<string, unknown>;\n const keys = new Set([...Object.keys(beforeRecord), ...Object.keys(afterRecord)]);\n for (const key of [...keys].sort()) {\n const at = path ? `${path}.${key}` : key;\n if (!(key in beforeRecord)) {\n entries.push({ path: at, kind: \"added\", after: afterRecord[key] });\n } else if (!(key in afterRecord)) {\n entries.push({ path: at, kind: \"removed\", before: beforeRecord[key] });\n } else {\n entries.push(...diff(beforeRecord[key], afterRecord[key], at));\n }\n }\n return entries;\n }\n\n if (JSON.stringify(before) === JSON.stringify(after)) return [];\n return [{ path: path || \"<root>\", kind: \"changed\", before, after }];\n}\n\nexport function formatValue(value: unknown): string {\n if (value === undefined) return \"—\";\n const text = typeof value === \"string\" ? value : JSON.stringify(value);\n return text.length > 120 ? `${text.slice(0, 117)}…` : text;\n}\n","/**\n * The two halves of the surface, and the join between them.\n *\n * A presentation surface has two sources of truth, and every command needs\n * some mix of both:\n *\n * - the **catalog** — what this codebase authors. Static: `type` is a string\n * literal, capability names are object keys, so `view:devices.table.sort` is\n * fully determined by source text ([`extract.ts`](./extract.ts)).\n * - the **projection** — what a mounted scenario actually surfaces, after\n * availability, policy and binding have had their say ([`collect.ts`](./collect.ts)).\n *\n * Splitting those across separate commands is what let a green `check` sit on\n * top of a route no scenario visits. So the split lives here, behind a `depth`\n * dial, and the commands compose the same three steps in whatever order their\n * output needs: `inspect` streams and closes with the verdict, `check` collects\n * and leads with it.\n */\nimport { dirname } from \"node:path\";\nimport { matchesScope } from \"@agent-surface/core/explain\";\nimport { baselineDirFor } from \"./baseline.js\";\nimport { UsageError, type Depth } from \"./contract.js\";\nimport type { CollectResult } from \"./collect.js\";\nimport {\n allowlistPathFor,\n buildCoverageReport,\n readAllowlist,\n unreadAllowlistPathFor,\n type CoverageReport,\n} from \"./coverage.js\";\nimport {\n authoredIds,\n extractCapabilities,\n readLiteralConfigScope,\n unresolved,\n type CapabilityInventory,\n} from \"./extract.js\";\nimport { createSurfaceRunner } from \"./load.js\";\n\nexport type { Depth } from \"./contract.js\";\nexport { UsageError } from \"./contract.js\";\n\nexport interface AnalysisOptions {\n configPath: string;\n depth: Depth;\n scenario?: string;\n scope?: string[];\n tsconfig?: string;\n baselineDir?: string;\n}\n\n/**\n * The static half. `undefined` at `--depth runtime`, which is the caller\n * saying it does not want this computed rather than it having failed.\n */\nexport function readInventory(options: AnalysisOptions): CapabilityInventory | undefined {\n if (options.depth === \"runtime\") return undefined;\n return extractCapabilities({\n root: dirname(options.configPath),\n ...(options.tsconfig ? { tsconfig: options.tsconfig } : {}),\n });\n}\n\nexport function staticConfigScope(options: AnalysisOptions): string[] | undefined {\n return options.scope ?? readLiteralConfigScope(options.configPath);\n}\n\n/** A scenario the config declares whose mount threw. Named, never swallowed. */\nexport interface ScenarioFailure {\n scenario: string;\n message: string;\n}\n\n/**\n * Everything knowable once the config has loaded and before the first mount:\n * which scenarios will run, under which scope, against which manifest.\n *\n * Split out so a command can *say* what it is about to measure. The mounts are\n * the slow half — on a real app, seconds of them — and a report that opens with\n * its qualifiers only after they finish spends that time showing nothing and\n * then asks the reader to re-read the numbers above.\n */\nexport interface RuntimePlan {\n /** Scenarios selected for this run, in config order. */\n scenarios: string[];\n /** Every scenario declared by the config, even when one was selected. */\n declaredScenarios: string[];\n baselineDir: string;\n /** CLI scope wins; otherwise the config scope is effective everywhere. */\n scope?: string[];\n /** Authoritative domain capability ids from the configured oRPC manifest. */\n domainCapabilities: string[];\n domainManifestConfigured: boolean;\n}\n\nexport interface RuntimeAnalysis extends RuntimePlan {\n /** The ones that mounted. */\n results: CollectResult[];\n failures: ScenarioFailure[];\n}\n\nexport interface MountHooks {\n /** Called once, after the config loads and before the first mount. */\n onPlan?: (plan: RuntimePlan) => void | Promise<void>;\n /** Called as each scenario finishes, so a command can print as it goes. */\n onEach?: (result: CollectResult) => void | Promise<void>;\n}\n\n/**\n * The runtime half. `undefined` at `--depth static`.\n *\n * `onEach` is awaited as each scenario finishes, so a command can print as it\n * goes instead of after the last mount — a config with ten scenarios is a long\n * time to look at nothing.\n *\n * A scenario that throws is recorded and the run continues. Before this was\n * one command, `capabilities` was the only thing that still worked on an app\n * that would not mount; merging the commands would have thrown that away if a\n * single bad scenario could abort the run.\n */\nexport async function mountScenarios(\n options: AnalysisOptions,\n hooks: MountHooks = {},\n): Promise<RuntimeAnalysis | undefined> {\n if (options.depth === \"static\") return undefined;\n\n const runner = await createSurfaceRunner(options.configPath);\n try {\n if (options.scenario && !runner.scenarioNames.includes(options.scenario)) {\n throw new UsageError(\n `unknown scenario \"${options.scenario}\" — this config defines ` +\n runner.scenarioNames.map((name) => `\"${name}\"`).join(\", \"),\n );\n }\n const scenarios = options.scenario ? [options.scenario] : runner.scenarioNames;\n const effectiveScope = options.scope ?? runner.config.scope;\n const results: CollectResult[] = [];\n const failures: ScenarioFailure[] = [];\n const plan: RuntimePlan = {\n scenarios,\n declaredScenarios: runner.scenarioNames,\n baselineDir: baselineDirFor(\n options.configPath,\n options.baselineDir ?? runner.config.baselineDir,\n ),\n ...(effectiveScope ? { scope: effectiveScope } : {}),\n domainCapabilities: Object.keys(runner.config.manifest?.tools ?? {})\n .map((path) => `domain:${path}`)\n .sort(),\n domainManifestConfigured: runner.config.manifest !== undefined,\n };\n await hooks.onPlan?.(plan);\n\n for (const scenario of scenarios) {\n let result: CollectResult;\n try {\n result = await runner.collect({\n scenario,\n ...(options.scope ? { scope: options.scope } : {}),\n });\n } catch (error) {\n failures.push({\n scenario,\n message: error instanceof Error ? error.message : String(error),\n });\n continue;\n }\n results.push(result);\n await hooks.onEach?.(result);\n }\n\n return { ...plan, results, failures };\n } finally {\n await runner.close();\n }\n}\n\n/**\n * The component type a capability id belongs to: `view:devices.table.sort` →\n * `devices.table`. Capability names are object keys and cannot contain a dot,\n * so the last one is always the boundary; component types can and do.\n */\nfunction componentTypeOf(capabilityId: string): string {\n const withoutPlane = capabilityId.replace(/^(view|domain):/, \"\");\n const dot = withoutPlane.lastIndexOf(\".\");\n return dot === -1 ? withoutPlane : withoutPlane.slice(0, dot);\n}\n\nexport function scopeInventory(\n inventory: CapabilityInventory | undefined,\n scope: string[] | undefined,\n): CapabilityInventory | undefined {\n if (!inventory || !scope) return inventory;\n return {\n ...inventory,\n capabilities: inventory.capabilities.filter(\n (capability) =>\n capability.resolution === \"unresolved\" ||\n matchesScope(componentTypeOf(capability.capabilityId), scope),\n ),\n };\n}\n\nexport function scopeCapabilityIds(ids: string[], scope: string[] | undefined): string[] {\n return scope ? ids.filter((id) => matchesScope(componentTypeOf(id), scope)) : ids;\n}\n\n/**\n * Authored minus reached (`AS-COVER-004…005`).\n *\n * Two ways this returns `undefined`, and neither is \"no gaps\":\n *\n * - a half was not computed, because the depth did not ask for it;\n * - **a scenario failed to mount.** That scenario reached nothing, so every\n * capability it would have surfaced would be reported as one no scenario\n * reaches. A coverage verdict computed over a partial run is precisely the\n * misleading check this package refuses to emit, so there is no verdict\n * until every scenario mounted. The renderer says which of the two it was.\n */\nexport function joinCoverage(\n inventory: CapabilityInventory | undefined,\n runtime: RuntimeAnalysis | undefined,\n options: AnalysisOptions,\n): CoverageReport | undefined {\n if (!inventory || !runtime) return undefined;\n if (runtime.failures.length > 0) return undefined;\n\n // A scope filters the mount, so it has to filter the catalog by the same\n // predicate — core's own, not a second copy of it. Without this, `--scope\n // devices` reported every `app.navigation` capability as unreached, with the\n // words \"no scenario mounts it\" over two that both scenarios mount.\n const effectiveScope = options.scope ?? runtime.scope;\n const inScope = (capabilityId: string): boolean =>\n matchesScope(componentTypeOf(capabilityId), effectiveScope);\n\n const origins = new Map<string, { file: string; line: number }>();\n for (const capability of inventory.capabilities) {\n if (!origins.has(capability.capabilityId)) {\n origins.set(capability.capabilityId, capability.origin);\n }\n }\n\n const authored = new Set([...authoredIds(inventory)].filter(inScope));\n for (const capabilityId of runtime.domainCapabilities) {\n if (inScope(capabilityId)) authored.add(capabilityId);\n if (!origins.has(capabilityId)) {\n origins.set(capabilityId, { file: \"oRPC manifest\", line: 0 });\n }\n }\n const reachedIds = new Set<string>();\n for (const result of runtime.results) {\n for (const capability of result.explanation.capabilities) {\n reachedIds.add(capability.capabilityId);\n }\n }\n\n // The allowlist is a statement about the whole catalog, and a scoped run has\n // only looked at part of it. Judging an out-of-scope entry either way would\n // be wrong in both directions — it is not an unreached capability this run\n // waved through, and it is not a stale entry either, because nothing here\n // reached it.\n const allowlistPath = allowlistPathFor(runtime.baselineDir);\n const wholeAllowlist = readAllowlist(allowlistPath);\n const allowlist = Object.fromEntries(\n Object.entries(wholeAllowlist).filter(([id]) => inScope(id)),\n );\n\n // Not scope-filtered, deliberately: an unread call site has no capability id,\n // so there is no component type to test a scope prefix against. A scoped run\n // simply reports the same unread sites as an unscoped one.\n const unreadAllowlistPath = unreadAllowlistPathFor(runtime.baselineDir);\n\n return buildCoverageReport({\n unreadAllowlist: readAllowlist(unreadAllowlistPath, \"file#reason#site\"),\n unreadAllowlistPath,\n domainAuthoritative: runtime.domainManifestConfigured,\n authored,\n origins,\n reachedIds,\n scenarios: runtime.scenarios,\n ...(effectiveScope ? { scope: effectiveScope } : {}),\n unresolved: unresolved(inventory),\n allowlist,\n allowlistOutOfScope: Object.keys(wholeAllowlist).length - Object.keys(allowlist).length,\n allowlistPath,\n });\n}\n"],"mappings":"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","names":["dirname","dirname"]}
|