@agent-surface/cli 0.13.0 → 0.15.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/dist/bin.js +41 -14
- package/dist/bin.js.map +1 -1
- package/dist/{check-TJIX7NDE.js → check-VWRYNYLN.js} +66 -48
- package/dist/check-VWRYNYLN.js.map +1 -0
- package/dist/chunk-A5UCBF7D.js +246 -0
- package/dist/chunk-A5UCBF7D.js.map +1 -0
- package/dist/chunk-GYYWHZPM.js +532 -0
- package/dist/chunk-GYYWHZPM.js.map +1 -0
- package/dist/chunk-NFK3XWWH.js +1475 -0
- package/dist/chunk-NFK3XWWH.js.map +1 -0
- package/dist/chunk-Y2LSPEVK.js +61 -0
- package/dist/chunk-Y2LSPEVK.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/{init-6XV64LK2.js → init-BVZR6CRS.js} +62 -40
- package/dist/init-BVZR6CRS.js.map +1 -0
- package/dist/{ink-QR7X7TAC.js → ink-ZCQ26EY4.js} +71 -17
- package/dist/ink-ZCQ26EY4.js.map +1 -0
- package/dist/{inspect-NJ4J3MPP.js → inspect-3YFPCYQJ.js} +88 -104
- package/dist/inspect-3YFPCYQJ.js.map +1 -0
- package/dist/snapshot-5QKLZKZI.js +130 -0
- package/dist/snapshot-5QKLZKZI.js.map +1 -0
- package/package.json +4 -4
- package/dist/check-TJIX7NDE.js.map +0 -1
- package/dist/chunk-3AJ343NA.js +0 -178
- package/dist/chunk-3AJ343NA.js.map +0 -1
- package/dist/chunk-IALBMW3R.js +0 -278
- package/dist/chunk-IALBMW3R.js.map +0 -1
- package/dist/chunk-L7GHSC2Z.js +0 -465
- package/dist/chunk-L7GHSC2Z.js.map +0 -1
- package/dist/chunk-UGCLJ5JX.js +0 -724
- package/dist/chunk-UGCLJ5JX.js.map +0 -1
- package/dist/chunk-VX6GBEP3.js +0 -539
- package/dist/chunk-VX6GBEP3.js.map +0 -1
- package/dist/init-6XV64LK2.js.map +0 -1
- package/dist/ink-QR7X7TAC.js.map +0 -1
- package/dist/inspect-NJ4J3MPP.js.map +0 -1
- package/dist/snapshot-ZGTAF2Y5.js +0 -77
- package/dist/snapshot-ZGTAF2Y5.js.map +0 -1
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
import {
|
|
2
|
+
STATUS_WIDTH,
|
|
3
|
+
flatRows,
|
|
4
|
+
reportGrid,
|
|
5
|
+
riskClause
|
|
6
|
+
} from "./chunk-NFK3XWWH.js";
|
|
7
|
+
|
|
8
|
+
// src/contract.ts
|
|
9
|
+
var DEPTHS = ["static", "runtime", "full"];
|
|
10
|
+
function isDepth(value) {
|
|
11
|
+
return typeof value === "string" && DEPTHS.includes(value);
|
|
12
|
+
}
|
|
13
|
+
var UsageError = class extends Error {
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/load.ts
|
|
17
|
+
import { existsSync } from "fs";
|
|
18
|
+
import { dirname, isAbsolute, join, resolve } from "path";
|
|
19
|
+
import { fileURLToPath } from "url";
|
|
20
|
+
import { createServer } from "vite";
|
|
21
|
+
import { ViteNodeServer } from "vite-node/server";
|
|
22
|
+
import { ViteNodeRunner } from "vite-node/client";
|
|
23
|
+
import { installSourcemapsSupport } from "vite-node/source-map";
|
|
24
|
+
var CONFIG_NAMES = [
|
|
25
|
+
"agent-surface.config.tsx",
|
|
26
|
+
"agent-surface.config.ts",
|
|
27
|
+
"agent-surface.config.mjs",
|
|
28
|
+
"agent-surface.config.js"
|
|
29
|
+
];
|
|
30
|
+
function findConfig(from = process.cwd()) {
|
|
31
|
+
let dir = resolve(from);
|
|
32
|
+
for (; ; ) {
|
|
33
|
+
for (const name of CONFIG_NAMES) {
|
|
34
|
+
const candidate = join(dir, name);
|
|
35
|
+
if (existsSync(candidate)) return candidate;
|
|
36
|
+
}
|
|
37
|
+
const parent = dirname(dir);
|
|
38
|
+
if (parent === dir) return void 0;
|
|
39
|
+
dir = parent;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function collectorPath() {
|
|
43
|
+
for (const ext of ["js", "ts"]) {
|
|
44
|
+
const candidate = fileURLToPath(new URL(`./collect.${ext}`, import.meta.url));
|
|
45
|
+
if (existsSync(candidate)) return candidate;
|
|
46
|
+
}
|
|
47
|
+
throw new Error("could not locate the agent-surface collector module");
|
|
48
|
+
}
|
|
49
|
+
async function createSurfaceRunner(configPath) {
|
|
50
|
+
const absoluteConfig = isAbsolute(configPath) ? configPath : resolve(configPath);
|
|
51
|
+
if (!existsSync(absoluteConfig)) {
|
|
52
|
+
throw new Error(`config not found: ${absoluteConfig}`);
|
|
53
|
+
}
|
|
54
|
+
const root = dirname(absoluteConfig);
|
|
55
|
+
let server;
|
|
56
|
+
try {
|
|
57
|
+
server = await createServer({
|
|
58
|
+
root,
|
|
59
|
+
logLevel: "error",
|
|
60
|
+
// `serve` so plugins behave as they do in dev; nothing is ever served.
|
|
61
|
+
server: { middlewareMode: true, watch: null, fs: { strict: false } },
|
|
62
|
+
optimizeDeps: { noDiscovery: true, include: [] },
|
|
63
|
+
resolve: {
|
|
64
|
+
// Both halves of the graph must agree on these. React because two
|
|
65
|
+
// copies break hooks; core because `explainSurface` finds the registry
|
|
66
|
+
// through a Symbol, which is per-module-instance (see collect.ts).
|
|
67
|
+
dedupe: [
|
|
68
|
+
"react",
|
|
69
|
+
"react-dom",
|
|
70
|
+
"@agent-surface/core",
|
|
71
|
+
"@agent-surface/react",
|
|
72
|
+
"@agent-surface/testing"
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
} catch (error) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`could not start Vite for ${root}: ${error instanceof Error ? error.message : String(error)}`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
await server.pluginContainer.buildStart({});
|
|
83
|
+
} catch {
|
|
84
|
+
}
|
|
85
|
+
const nodeServer = new ViteNodeServer(server);
|
|
86
|
+
installSourcemapsSupport({ getSourceMap: (source) => nodeServer.getSourceMap(source) });
|
|
87
|
+
const runner = new ViteNodeRunner({
|
|
88
|
+
root: server.config.root,
|
|
89
|
+
base: server.config.base,
|
|
90
|
+
fetchModule: (id) => nodeServer.fetchModule(id),
|
|
91
|
+
resolveId: (id, importer) => nodeServer.resolveId(id, importer)
|
|
92
|
+
});
|
|
93
|
+
const close = async () => {
|
|
94
|
+
await server.close();
|
|
95
|
+
};
|
|
96
|
+
try {
|
|
97
|
+
const configModule = await runner.executeFile(absoluteConfig);
|
|
98
|
+
const config = configModule.default;
|
|
99
|
+
if (!config || typeof config.mount !== "function") {
|
|
100
|
+
throw new Error(
|
|
101
|
+
`${absoluteConfig} must \`export default defineSurface({ mount, scenarios })\``
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
const scenarioNames = Object.keys(config.scenarios ?? {});
|
|
105
|
+
if (scenarioNames.length === 0) {
|
|
106
|
+
throw new Error(`${absoluteConfig} defines no scenarios`);
|
|
107
|
+
}
|
|
108
|
+
const collector = await runner.executeFile(collectorPath());
|
|
109
|
+
return {
|
|
110
|
+
config,
|
|
111
|
+
scenarioNames,
|
|
112
|
+
collect: async (options) => {
|
|
113
|
+
const globals = globalThis;
|
|
114
|
+
const previous = globals["IS_REACT_ACT_ENVIRONMENT"];
|
|
115
|
+
globals["IS_REACT_ACT_ENVIRONMENT"] = true;
|
|
116
|
+
try {
|
|
117
|
+
return await collector.collect(config, options);
|
|
118
|
+
} finally {
|
|
119
|
+
globals["IS_REACT_ACT_ENVIRONMENT"] = previous;
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
close
|
|
123
|
+
};
|
|
124
|
+
} catch (error) {
|
|
125
|
+
await close();
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/output.ts
|
|
131
|
+
function streamFor(stream) {
|
|
132
|
+
return stream === "err" ? process.stderr : process.stdout;
|
|
133
|
+
}
|
|
134
|
+
function isPlain(flags, stream = "out") {
|
|
135
|
+
if (flags.json) return true;
|
|
136
|
+
if (flags.plain) return true;
|
|
137
|
+
if (process.env["CI"]) return true;
|
|
138
|
+
if (process.env["NO_COLOR"]) return true;
|
|
139
|
+
const target = streamFor(stream);
|
|
140
|
+
if (target.isTTY !== true) return true;
|
|
141
|
+
return !target.columns;
|
|
142
|
+
}
|
|
143
|
+
function write(text, stream = "out") {
|
|
144
|
+
streamFor(stream).write(`${text}
|
|
145
|
+
`);
|
|
146
|
+
}
|
|
147
|
+
function writeError(text) {
|
|
148
|
+
write(text, "err");
|
|
149
|
+
}
|
|
150
|
+
var cached;
|
|
151
|
+
async function loadInk() {
|
|
152
|
+
if (cached !== void 0) return cached;
|
|
153
|
+
try {
|
|
154
|
+
cached = await import("./ink-ZCQ26EY4.js");
|
|
155
|
+
} catch {
|
|
156
|
+
cached = null;
|
|
157
|
+
}
|
|
158
|
+
return cached;
|
|
159
|
+
}
|
|
160
|
+
async function paint(element, stream = "out") {
|
|
161
|
+
const { render } = await import("ink");
|
|
162
|
+
const instance = render(element, { stdout: streamFor(stream) });
|
|
163
|
+
instance.unmount();
|
|
164
|
+
await instance.waitUntilExit();
|
|
165
|
+
}
|
|
166
|
+
async function transient(element) {
|
|
167
|
+
const { render } = await import("ink");
|
|
168
|
+
const instance = render(element);
|
|
169
|
+
return () => {
|
|
170
|
+
instance.clear();
|
|
171
|
+
instance.unmount();
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// src/baseline.ts
|
|
176
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
177
|
+
import { dirname as dirname2, join as join2, resolve as resolve2, sep } from "path";
|
|
178
|
+
import { serializeSurfaceSnapshot } from "@agent-surface/testing";
|
|
179
|
+
var DEFAULT_BASELINE_DIR = ".agent-surface";
|
|
180
|
+
var SCENARIO_MANIFEST_FILE = "scenarios.json";
|
|
181
|
+
function baselineDirFor(configPath, configured) {
|
|
182
|
+
return resolve2(dirname2(configPath), configured ?? DEFAULT_BASELINE_DIR);
|
|
183
|
+
}
|
|
184
|
+
function baselinePath(dir, scenario) {
|
|
185
|
+
const reserved = /* @__PURE__ */ new Set(["scenarios", "coverage-allow", "unresolved-allow"]);
|
|
186
|
+
if (scenario.length === 0 || scenario === "." || scenario === ".." || scenario.includes("/") || scenario.includes("\\") || scenario.includes("\0") || reserved.has(scenario)) {
|
|
187
|
+
throw new Error(`invalid scenario name ${JSON.stringify(scenario)} \u2014 use a filename-safe name`);
|
|
188
|
+
}
|
|
189
|
+
const root = resolve2(dir);
|
|
190
|
+
const path = resolve2(root, `${scenario}.json`);
|
|
191
|
+
if (!path.startsWith(`${root}${sep}`)) {
|
|
192
|
+
throw new Error(`scenario ${JSON.stringify(scenario)} escapes the baseline directory`);
|
|
193
|
+
}
|
|
194
|
+
return path;
|
|
195
|
+
}
|
|
196
|
+
function scenarioManifestPath(dir) {
|
|
197
|
+
return join2(dir, SCENARIO_MANIFEST_FILE);
|
|
198
|
+
}
|
|
199
|
+
function normalize(snapshot) {
|
|
200
|
+
return serializeSurfaceSnapshot(snapshot);
|
|
201
|
+
}
|
|
202
|
+
function readBaseline(path) {
|
|
203
|
+
if (!existsSync2(path)) return void 0;
|
|
204
|
+
try {
|
|
205
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
206
|
+
} catch (error) {
|
|
207
|
+
throw new Error(
|
|
208
|
+
`could not read baseline ${path}: ${error instanceof Error ? error.message : String(error)}`
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function writeBaseline(path, value) {
|
|
213
|
+
mkdirSync(dirname2(path), { recursive: true });
|
|
214
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}
|
|
215
|
+
`, "utf8");
|
|
216
|
+
}
|
|
217
|
+
function readScenarioManifest(dir) {
|
|
218
|
+
const path = scenarioManifestPath(dir);
|
|
219
|
+
const value = readBaseline(path);
|
|
220
|
+
if (value === void 0) return void 0;
|
|
221
|
+
if (typeof value !== "object" || value === null || !Array.isArray(value.scenarios) || !value.scenarios.every((name) => typeof name === "string")) {
|
|
222
|
+
throw new Error(`${path} must contain { "scenarios": string[] }`);
|
|
223
|
+
}
|
|
224
|
+
return [...value.scenarios].sort();
|
|
225
|
+
}
|
|
226
|
+
function writeScenarioManifest(dir, scenarios) {
|
|
227
|
+
writeBaseline(scenarioManifestPath(dir), { scenarios: [...scenarios].sort() });
|
|
228
|
+
}
|
|
229
|
+
var PATH_SEGMENT = /([^.[\]]+)|\[(\d+)\]/g;
|
|
230
|
+
function subjectFor(document, path) {
|
|
231
|
+
let node = document;
|
|
232
|
+
let subject;
|
|
233
|
+
for (const match of path.matchAll(PATH_SEGMENT)) {
|
|
234
|
+
if (typeof node !== "object" || node === null) return subject;
|
|
235
|
+
const record = node;
|
|
236
|
+
const candidate = record["capabilityId"] ?? record["procedureId"];
|
|
237
|
+
if (typeof candidate === "string") subject = candidate;
|
|
238
|
+
const key = match[1] ?? match[2];
|
|
239
|
+
if (key === void 0) return subject;
|
|
240
|
+
node = record[key];
|
|
241
|
+
}
|
|
242
|
+
if (typeof node === "object" && node !== null) {
|
|
243
|
+
const record = node;
|
|
244
|
+
const candidate = record["capabilityId"] ?? record["procedureId"];
|
|
245
|
+
if (typeof candidate === "string") subject = candidate;
|
|
246
|
+
}
|
|
247
|
+
return subject;
|
|
248
|
+
}
|
|
249
|
+
function annotate(entries, after, before) {
|
|
250
|
+
return entries.map((entry) => {
|
|
251
|
+
const subject = subjectFor(after, entry.path) ?? subjectFor(before, entry.path);
|
|
252
|
+
return subject ? { ...entry, subject } : entry;
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
function diff(before, after, path = "") {
|
|
256
|
+
if (Object.is(before, after)) return [];
|
|
257
|
+
const bothArrays = Array.isArray(before) && Array.isArray(after);
|
|
258
|
+
const bothObjects = !bothArrays && typeof before === "object" && typeof after === "object" && before !== null && after !== null;
|
|
259
|
+
if (bothArrays) {
|
|
260
|
+
const entries = [];
|
|
261
|
+
const max = Math.max(before.length, after.length);
|
|
262
|
+
for (let i = 0; i < max; i++) {
|
|
263
|
+
const at = `${path}[${i}]`;
|
|
264
|
+
if (i >= before.length) entries.push({ path: at, kind: "added", after: after[i] });
|
|
265
|
+
else if (i >= after.length) entries.push({ path: at, kind: "removed", before: before[i] });
|
|
266
|
+
else entries.push(...diff(before[i], after[i], at));
|
|
267
|
+
}
|
|
268
|
+
return entries;
|
|
269
|
+
}
|
|
270
|
+
if (bothObjects) {
|
|
271
|
+
const entries = [];
|
|
272
|
+
const beforeRecord = before;
|
|
273
|
+
const afterRecord = after;
|
|
274
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(beforeRecord), ...Object.keys(afterRecord)]);
|
|
275
|
+
for (const key of [...keys].sort()) {
|
|
276
|
+
const at = path ? `${path}.${key}` : key;
|
|
277
|
+
if (!(key in beforeRecord)) {
|
|
278
|
+
entries.push({ path: at, kind: "added", after: afterRecord[key] });
|
|
279
|
+
} else if (!(key in afterRecord)) {
|
|
280
|
+
entries.push({ path: at, kind: "removed", before: beforeRecord[key] });
|
|
281
|
+
} else {
|
|
282
|
+
entries.push(...diff(beforeRecord[key], afterRecord[key], at));
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return entries;
|
|
286
|
+
}
|
|
287
|
+
if (JSON.stringify(before) === JSON.stringify(after)) return [];
|
|
288
|
+
return [{ path: path || "<root>", kind: "changed", before, after }];
|
|
289
|
+
}
|
|
290
|
+
function formatValue(value) {
|
|
291
|
+
if (value === void 0) return "\u2014";
|
|
292
|
+
const text = typeof value === "string" ? value : JSON.stringify(value);
|
|
293
|
+
return text.length > 120 ? `${text.slice(0, 117)}\u2026` : text;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// src/render/plain.ts
|
|
297
|
+
var MARK = { expose: "+", disable: "~", hide: "-" };
|
|
298
|
+
var STATE = { expose: "callable", disable: "disabled", hide: "hidden" };
|
|
299
|
+
var NONE = "\u2014";
|
|
300
|
+
var REPORT_WIDTH = 100;
|
|
301
|
+
function wrapText(text, width) {
|
|
302
|
+
const words = text.split(/\s+/).filter(Boolean);
|
|
303
|
+
const lines = [];
|
|
304
|
+
let line = "";
|
|
305
|
+
for (const word of words) {
|
|
306
|
+
if (line && line.length + 1 + word.length > width) {
|
|
307
|
+
lines.push(line);
|
|
308
|
+
line = word;
|
|
309
|
+
} else {
|
|
310
|
+
line = line ? `${line} ${word}` : word;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
if (line) lines.push(line);
|
|
314
|
+
return lines.length > 0 ? lines : [""];
|
|
315
|
+
}
|
|
316
|
+
function renderTable(headers, rows) {
|
|
317
|
+
const widths = headers.map(
|
|
318
|
+
(header, column) => Math.max(header.length, ...rows.map((row) => (row.cells[column] ?? "").length))
|
|
319
|
+
);
|
|
320
|
+
const line = (cells) => cells.map((cell, column) => column === headers.length - 1 ? cell : cell.padEnd(widths[column])).join(" ").trimEnd();
|
|
321
|
+
const lines = [line(headers)];
|
|
322
|
+
for (const row of rows) {
|
|
323
|
+
lines.push(line(row.cells));
|
|
324
|
+
if (row.note) {
|
|
325
|
+
for (const [index, note] of wrapText(row.note, REPORT_WIDTH - 6).entries()) {
|
|
326
|
+
lines.push(` ${index === 0 ? "\u2937 " : " "}${note}`);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return lines;
|
|
331
|
+
}
|
|
332
|
+
function section(title, gloss, count) {
|
|
333
|
+
return `${title} \u2014 ${gloss} (${count})`;
|
|
334
|
+
}
|
|
335
|
+
function renderReportPlain(blocks, labelWidth) {
|
|
336
|
+
const grid = reportGrid(blocks, labelWidth);
|
|
337
|
+
const renderRow = (row) => `${row.label.padEnd(grid.label)}${grid.statuses ? (row.status ?? "").padEnd(STATUS_WIDTH) : ""}${row.text}`.trimEnd();
|
|
338
|
+
return blocks.filter((block) => block.title || block.rows.length > 0).map((block) => [...block.title ? [block.title] : [], ...block.rows.map(renderRow)].join("\n")).join("\n\n");
|
|
339
|
+
}
|
|
340
|
+
function renderSectionsPlain(sections) {
|
|
341
|
+
return sections.map((entry) => {
|
|
342
|
+
const lines = [
|
|
343
|
+
entry.count > 0 ? section(entry.title, entry.gloss, entry.count) : `${entry.title} \u2014 ${entry.gloss}`
|
|
344
|
+
];
|
|
345
|
+
if (entry.headers && entry.rows) lines.push(...renderTable(entry.headers, entry.rows));
|
|
346
|
+
if (entry.lines) lines.push(...entry.lines.map((line) => ` ${line}`.trimEnd()));
|
|
347
|
+
if (entry.hint) {
|
|
348
|
+
lines.push(
|
|
349
|
+
...wrapText(entry.hint, REPORT_WIDTH - 4).map(
|
|
350
|
+
(line, index) => ` ${index === 0 ? "\u2192" : " "} ${line}`
|
|
351
|
+
)
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
return lines.join("\n");
|
|
355
|
+
}).join("\n\n");
|
|
356
|
+
}
|
|
357
|
+
function renderStepsPlain(title, steps) {
|
|
358
|
+
return [
|
|
359
|
+
title,
|
|
360
|
+
...steps.flatMap(
|
|
361
|
+
(step, index) => wrapText(step, REPORT_WIDTH - 5).map(
|
|
362
|
+
(line, wrapped) => ` ${wrapped === 0 ? `${index + 1}.` : " "} ${line}`
|
|
363
|
+
)
|
|
364
|
+
)
|
|
365
|
+
].join("\n");
|
|
366
|
+
}
|
|
367
|
+
function renderPartPlain(part, labelWidth) {
|
|
368
|
+
switch (part.kind) {
|
|
369
|
+
case "blocks":
|
|
370
|
+
return renderReportPlain(part.blocks, labelWidth);
|
|
371
|
+
case "table":
|
|
372
|
+
return [
|
|
373
|
+
part.title,
|
|
374
|
+
...part.lead ? [part.lead] : [],
|
|
375
|
+
...renderTable(part.headers, part.rows)
|
|
376
|
+
].join("\n");
|
|
377
|
+
case "findings":
|
|
378
|
+
return renderSectionsPlain(part.sections);
|
|
379
|
+
case "surface":
|
|
380
|
+
return renderSurfacePlain(part.view, { ...part.detail ? { detail: true } : {} });
|
|
381
|
+
case "note":
|
|
382
|
+
return [...part.title ? [part.title] : [], ...part.lines].join("\n");
|
|
383
|
+
case "steps":
|
|
384
|
+
return renderStepsPlain(part.title, part.steps);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
function renderDetailRow(row, lines) {
|
|
388
|
+
const tags = row.tags.length > 0 ? ` [${row.tags.join(", ")}]` : "";
|
|
389
|
+
lines.push(` ${MARK[row.outcome]} ${row.name}${tags}`);
|
|
390
|
+
lines.push(` ${row.description}`);
|
|
391
|
+
if (row.reason) lines.push(` reason: ${row.reason}`);
|
|
392
|
+
if (row.policies) {
|
|
393
|
+
if (row.policies.length === 0) {
|
|
394
|
+
lines.push(" policies: none");
|
|
395
|
+
} else {
|
|
396
|
+
for (const policy of row.policies) {
|
|
397
|
+
const vote = policy.discovery ? policy.discovery.decision === "disable" ? `disable \u2014 ${policy.discovery.reason}` : policy.discovery.decision : "no discovery hook";
|
|
398
|
+
const phases = policy.phases.length > 0 ? policy.phases.join("/") : NONE;
|
|
399
|
+
const flags = [
|
|
400
|
+
policy.threw ? "THREW" : "",
|
|
401
|
+
policy.confirmationEscalation ? "escalates-confirmation" : ""
|
|
402
|
+
].filter(Boolean).join(", ");
|
|
403
|
+
lines.push(
|
|
404
|
+
` policy ${policy.name} (${policy.scope}, ${phases}): ${vote}${flags ? ` [${flags}]` : ""}`
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
if (row.availability && !row.availability.available) {
|
|
409
|
+
lines.push(
|
|
410
|
+
` availability: unavailable${row.availability.reason ? ` \u2014 ${row.availability.reason}` : ""}`
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (row.schemas) {
|
|
415
|
+
if (row.schemas.input !== void 0) {
|
|
416
|
+
lines.push(` input: ${JSON.stringify(row.schemas.input)}`);
|
|
417
|
+
}
|
|
418
|
+
if (row.schemas.output !== void 0) {
|
|
419
|
+
lines.push(` output: ${JSON.stringify(row.schemas.output)}`);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
function renderCountsPlain(view) {
|
|
424
|
+
const risk = riskClause(flatRows(view));
|
|
425
|
+
return `${view.counts.callable} callable, ${view.counts.disabled} visible-disabled, ${view.counts.hidden} hidden` + (view.rejections.length > 0 ? `, ${view.rejections.length} registration${view.rejections.length === 1 ? "" : "s"} rejected` : "") + (risk ? ` \xB7 ${risk}` : "");
|
|
426
|
+
}
|
|
427
|
+
function renderHeader(view, lines) {
|
|
428
|
+
lines.push(
|
|
429
|
+
`scenario ${view.scenario}${view.route ? ` route ${view.route}` : ""}${view.scope && view.scope.length > 0 ? ` scope ${view.scope.join(" ")}` : ""}`
|
|
430
|
+
);
|
|
431
|
+
lines.push(renderCountsPlain(view));
|
|
432
|
+
}
|
|
433
|
+
function renderRejections(view, lines) {
|
|
434
|
+
if (view.rejections.length === 0) return;
|
|
435
|
+
lines.push("");
|
|
436
|
+
lines.push(
|
|
437
|
+
section("REJECTED", "the registry refused these during the mount", view.rejections.length)
|
|
438
|
+
);
|
|
439
|
+
for (const rejection of view.rejections) {
|
|
440
|
+
const why = rejection.reason === "duplicate" ? "duplicate \u2014 an earlier registration holds this key" : "guard \u2014 onRegister rejected this registration";
|
|
441
|
+
lines.push(` ! ${rejection.componentType} (${rejection.instanceId}) ${why}`);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
function renderEmpty(view, lines) {
|
|
445
|
+
lines.push("");
|
|
446
|
+
if (view.counts.hidden > 0) {
|
|
447
|
+
lines.push(
|
|
448
|
+
`Nothing is callable here \u2014 all ${view.counts.hidden} registered capabilities were hidden by policy.`
|
|
449
|
+
);
|
|
450
|
+
if (!view.explained) lines.push("Re-run with --explain to see which policy hid them.");
|
|
451
|
+
} else {
|
|
452
|
+
lines.push("Nothing is registered for this scenario \u2014 the agent has no surface here.");
|
|
453
|
+
if (!view.explained) lines.push("Re-run with --explain to see whether a policy hid it.");
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
function renderSurfacePlain(view, options = {}) {
|
|
457
|
+
const lines = [];
|
|
458
|
+
renderHeader(view, lines);
|
|
459
|
+
renderRejections(view, lines);
|
|
460
|
+
const rows = flatRows(view);
|
|
461
|
+
if (rows.length === 0) {
|
|
462
|
+
renderEmpty(view, lines);
|
|
463
|
+
return lines.join("\n");
|
|
464
|
+
}
|
|
465
|
+
if (options.detail) {
|
|
466
|
+
for (const group of view.groups.filter((group2) => group2.rows.length > 0)) {
|
|
467
|
+
lines.push("");
|
|
468
|
+
lines.push(`${group.heading} (${group.rows.length})`);
|
|
469
|
+
for (const row of group.rows) renderDetailRow(row, lines);
|
|
470
|
+
}
|
|
471
|
+
return lines.join("\n");
|
|
472
|
+
}
|
|
473
|
+
lines.push("");
|
|
474
|
+
lines.push(
|
|
475
|
+
...renderTable(
|
|
476
|
+
["CAPABILITY", "KIND", "EFFECT", "STATE", "FLAGS"],
|
|
477
|
+
rows.map((row) => ({
|
|
478
|
+
cells: [
|
|
479
|
+
row.path,
|
|
480
|
+
row.kind,
|
|
481
|
+
row.effect ?? NONE,
|
|
482
|
+
STATE[row.outcome],
|
|
483
|
+
row.flags.length > 0 ? row.flags.join(" \xB7 ") : NONE
|
|
484
|
+
],
|
|
485
|
+
...row.reason ? { note: row.reason } : {}
|
|
486
|
+
}))
|
|
487
|
+
)
|
|
488
|
+
);
|
|
489
|
+
return lines.join("\n");
|
|
490
|
+
}
|
|
491
|
+
function renderDriftPlain(scenario, entries) {
|
|
492
|
+
const lines = [`${scenario}: ${entries.length} change${entries.length === 1 ? "" : "s"}`];
|
|
493
|
+
for (const entry of entries) {
|
|
494
|
+
const where = entry.subject ? `${entry.subject} (${entry.path})` : entry.path;
|
|
495
|
+
if (entry.kind === "added") lines.push(` + ${where} ${formatValue(entry.after)}`);
|
|
496
|
+
else if (entry.kind === "removed") lines.push(` - ${where} ${formatValue(entry.before)}`);
|
|
497
|
+
else {
|
|
498
|
+
lines.push(` ~ ${where}`);
|
|
499
|
+
lines.push(` before: ${formatValue(entry.before)}`);
|
|
500
|
+
lines.push(` after: ${formatValue(entry.after)}`);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
return lines;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
export {
|
|
507
|
+
DEPTHS,
|
|
508
|
+
isDepth,
|
|
509
|
+
UsageError,
|
|
510
|
+
findConfig,
|
|
511
|
+
createSurfaceRunner,
|
|
512
|
+
isPlain,
|
|
513
|
+
write,
|
|
514
|
+
writeError,
|
|
515
|
+
loadInk,
|
|
516
|
+
paint,
|
|
517
|
+
transient,
|
|
518
|
+
SCENARIO_MANIFEST_FILE,
|
|
519
|
+
baselineDirFor,
|
|
520
|
+
baselinePath,
|
|
521
|
+
normalize,
|
|
522
|
+
readBaseline,
|
|
523
|
+
writeBaseline,
|
|
524
|
+
readScenarioManifest,
|
|
525
|
+
writeScenarioManifest,
|
|
526
|
+
annotate,
|
|
527
|
+
diff,
|
|
528
|
+
renderReportPlain,
|
|
529
|
+
renderPartPlain,
|
|
530
|
+
renderDriftPlain
|
|
531
|
+
};
|
|
532
|
+
//# sourceMappingURL=chunk-GYYWHZPM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/contract.ts","../src/load.ts","../src/output.ts","../src/baseline.ts","../src/render/plain.ts"],"sourcesContent":["/**\n * The vocabulary every layer shares, and nothing else.\n *\n * It is its own module because `bin.ts` needs both of these before it has\n * decided which command to run, and everything else in this package pulls in\n * either the TypeScript compiler or Vite the moment it is imported. A `--help`\n * that boots a TypeScript program to print a paragraph is a `--help` nobody\n * runs twice.\n */\n\nexport const DEPTHS = [\"static\", \"runtime\", \"full\"] as const;\n\n/**\n * How much of the surface a command is asked to compute.\n *\n * A presentation surface has two sources of truth and every command needs some\n * mix of both — the **catalog** this codebase authors, which is static, and the\n * **projection** a mounted scenario surfaces, which is not. Splitting those\n * across separate commands is what let a green `check` sit on top of a route no\n * scenario visits, so the split lives here instead.\n *\n * `static` reads the TypeScript program and mounts nothing — no Vite server, no\n * jsdom, no scenarios. It is the only depth that survives an app which will not\n * mount, and the only one that needs no scenarios to exist yet.\n *\n * `runtime` mounts and skips the program read, for a repository whose tsconfig\n * is wide enough that booting it costs more than the answer is worth.\n *\n * `full` does both and joins them, which is the only depth that can answer\n * *did we author something no scenario reaches*. It is the default because a\n * tool that has to be asked for the complete answer mostly gives the\n * incomplete one.\n */\nexport type Depth = (typeof DEPTHS)[number];\n\nexport function isDepth(value: unknown): value is Depth {\n return typeof value === \"string\" && (DEPTHS as readonly string[]).includes(value);\n}\n\n/**\n * The caller asked for something impossible — as opposed to the app being\n * broken, which is what a mount failure is. Both exit `2`: CI has to tell \"the\n * surface changed\" apart from \"the tool never ran\", and these are both the\n * second one.\n */\nexport class UsageError extends Error {}\n","import { existsSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { createServer, type ViteDevServer } from \"vite\";\nimport { ViteNodeServer } from \"vite-node/server\";\nimport { ViteNodeRunner } from \"vite-node/client\";\nimport { installSourcemapsSupport } from \"vite-node/source-map\";\nimport type { CollectOptions, CollectResult } from \"./collect.js\";\nimport type { SurfaceConfig } from \"./config.js\";\n\nconst CONFIG_NAMES = [\n \"agent-surface.config.tsx\",\n \"agent-surface.config.ts\",\n \"agent-surface.config.mjs\",\n \"agent-surface.config.js\",\n];\n\n/** Walks up from `from` looking for an `agent-surface.config.*`. */\nexport function findConfig(from: string = process.cwd()): string | undefined {\n let dir = resolve(from);\n for (;;) {\n for (const name of CONFIG_NAMES) {\n const candidate = join(dir, name);\n if (existsSync(candidate)) return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n}\n\n/** `dist/collect.js` when installed; `src/collect.ts` when run from source. */\nfunction collectorPath(): string {\n for (const ext of [\"js\", \"ts\"]) {\n const candidate = fileURLToPath(new URL(`./collect.${ext}`, import.meta.url));\n if (existsSync(candidate)) return candidate;\n }\n throw new Error(\"could not locate the agent-surface collector module\");\n}\n\nexport interface SurfaceRunner {\n config: SurfaceConfig;\n scenarioNames: string[];\n collect(options: CollectOptions): Promise<CollectResult>;\n close(): Promise<void>;\n}\n\n/**\n * Boots a Vite dev server on the app's own config, so the config file and the\n * app modules it imports are transformed and resolved exactly as the app\n * resolves them — its aliases, its plugins, its TSX.\n */\nexport async function createSurfaceRunner(configPath: string): Promise<SurfaceRunner> {\n const absoluteConfig = isAbsolute(configPath) ? configPath : resolve(configPath);\n if (!existsSync(absoluteConfig)) {\n throw new Error(`config not found: ${absoluteConfig}`);\n }\n const root = dirname(absoluteConfig);\n\n let server: ViteDevServer;\n try {\n server = await createServer({\n root,\n logLevel: \"error\",\n // `serve` so plugins behave as they do in dev; nothing is ever served.\n server: { middlewareMode: true, watch: null, fs: { strict: false } },\n optimizeDeps: { noDiscovery: true, include: [] },\n resolve: {\n // Both halves of the graph must agree on these. React because two\n // copies break hooks; core because `explainSurface` finds the registry\n // through a Symbol, which is per-module-instance (see collect.ts).\n dedupe: [\n \"react\",\n \"react-dom\",\n \"@agent-surface/core\",\n \"@agent-surface/react\",\n \"@agent-surface/testing\",\n ],\n },\n });\n } catch (error) {\n throw new Error(\n `could not start Vite for ${root}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n\n try {\n await server.pluginContainer.buildStart({});\n } catch {\n // Vite keeps moving this; a plugin that needs buildStart will say so itself.\n }\n\n const nodeServer = new ViteNodeServer(server);\n installSourcemapsSupport({ getSourceMap: (source) => nodeServer.getSourceMap(source) });\n\n const runner = new ViteNodeRunner({\n root: server.config.root,\n base: server.config.base,\n fetchModule: (id) => nodeServer.fetchModule(id),\n resolveId: (id, importer) => nodeServer.resolveId(id, importer),\n });\n\n const close = async (): Promise<void> => {\n await server.close();\n };\n\n try {\n const configModule = (await runner.executeFile(absoluteConfig)) as {\n default?: SurfaceConfig;\n };\n const config = configModule.default;\n if (!config || typeof config.mount !== \"function\") {\n throw new Error(\n `${absoluteConfig} must \\`export default defineSurface({ mount, scenarios })\\``,\n );\n }\n const scenarioNames = Object.keys(config.scenarios ?? {});\n if (scenarioNames.length === 0) {\n throw new Error(`${absoluteConfig} defines no scenarios`);\n }\n\n // Same runner ⇒ same module graph ⇒ the collector shares React and core\n // with the app tree it is about to mount.\n const collector = (await runner.executeFile(collectorPath())) as {\n collect(config: SurfaceConfig, options: CollectOptions): Promise<CollectResult>;\n };\n\n return {\n config,\n scenarioNames,\n collect: async (options) => {\n // Scoped to the mount, never process-wide: `act()` needs it, and Ink\n // renders its own React tree afterwards — with the flag still set,\n // every frame of the CLI's own UI prints React's \"not wrapped in\n // act(...)\" warning at the user.\n const globals = globalThis as Record<string, unknown>;\n const previous = globals[\"IS_REACT_ACT_ENVIRONMENT\"];\n globals[\"IS_REACT_ACT_ENVIRONMENT\"] = true;\n try {\n return await collector.collect(config, options);\n } finally {\n globals[\"IS_REACT_ACT_ENVIRONMENT\"] = previous;\n }\n },\n close,\n };\n } catch (error) {\n await close();\n throw error;\n }\n}\n","import type { ReactElement } from \"react\";\nimport type { ReportStream } from \"./render/summary.js\";\n\nexport interface OutputFlags {\n plain?: boolean;\n json?: boolean;\n}\n\nfunction streamFor(stream: ReportStream): NodeJS.WriteStream {\n return stream === \"err\" ? process.stderr : process.stdout;\n}\n\n/**\n * Terminal-aware only when there is a terminal — and asked *per stream*, because\n * the two are redirected independently. `agent-surface check 2> report.txt` on a\n * terminal is a run whose answer is drawn and whose findings are a file, and a\n * file full of cursor escapes is a file nobody can read.\n *\n * `--plain`, `--json`, `CI` and `NO_COLOR` force plain on both: a CLI whose\n * output changes shape when redirected is unusable in a build log.\n */\nexport function isPlain(flags: OutputFlags, stream: ReportStream = \"out\"): boolean {\n if (flags.json) return true;\n if (flags.plain) return true;\n if (process.env[\"CI\"]) return true;\n if (process.env[\"NO_COLOR\"]) return true;\n const target = streamFor(stream);\n if (target.isTTY !== true) return true;\n // A TTY that cannot report its width (some CI ptys, `script` on macOS) makes\n // Ink lay out at zero columns and emit one character per line. Plain text is\n // the only honest rendering for a terminal whose size is unknown.\n return !target.columns;\n}\n\nexport function write(text: string, stream: ReportStream = \"out\"): void {\n streamFor(stream).write(`${text}\\n`);\n}\n\nexport function writeError(text: string): void {\n write(text, \"err\");\n}\n\ntype InkModule = typeof import(\"./render/ink.js\");\n\nlet cached: InkModule | null | undefined;\n\n/**\n * Loads the Ink renderer, or returns `null` when it cannot run here.\n *\n * Two reasons this is lazy rather than a top-level import. It keeps `--plain`\n * and `--json` from paying for a terminal UI they never draw — and Ink drives\n * React through `react-reconciler`, which reads React 19 internals, so a host\n * that pins React 18 globally cannot load it at all. Neither is a reason to\n * fail a command that was about to print text.\n */\nexport async function loadInk(): Promise<InkModule | null> {\n if (cached !== undefined) return cached;\n try {\n cached = await import(\"./render/ink.js\");\n } catch {\n cached = null;\n }\n return cached;\n}\n\n/** Paints an Ink element once, onto one stream, and waits for the flush. */\nexport async function paint(element: ReactElement, stream: ReportStream = \"out\"): Promise<void> {\n const { render } = await import(\"ink\");\n const instance = render(element, { stdout: streamFor(stream) });\n instance.unmount();\n await instance.waitUntilExit();\n}\n\n/** A live Ink frame (spinner) that is cleared before the real output lands. */\nexport async function transient(element: ReactElement): Promise<() => void> {\n const { render } = await import(\"ink\");\n const instance = render(element);\n return () => {\n instance.clear();\n instance.unmount();\n };\n}\n","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","import type { CapabilityRow, SurfaceView } from \"./model.js\";\nimport { flatRows } from \"./model.js\";\nimport {\n checkOverviewParts,\n reportGrid,\n riskClause,\n STATUS_WIDTH,\n type CheckOverview,\n type FindingSection,\n type ReportBlock,\n type ReportPart,\n type ReportRow,\n type TableRow,\n} from \"./summary.js\";\nimport type { DiffEntry } from \"../baseline.js\";\nimport { formatValue } from \"../baseline.js\";\n\n/**\n * The no-colour, no-cursor rendering used when a stream is piped or when\n * `--plain`, `CI` or `NO_COLOR` is set. Same report parts as the Ink UI, so the\n * two cannot disagree about what the surface contains — or about where a block\n * begins.\n */\n\nconst MARK = { expose: \"+\", disable: \"~\", hide: \"-\" } as const;\nconst STATE = { expose: \"callable\", disable: \"disabled\", hide: \"hidden\" } as const;\nconst NONE = \"—\";\nconst REPORT_WIDTH = 100;\n\n/** Deterministic wrapping: readable in logs, independent of terminal width. */\nfunction wrapText(text: string, width: number): string[] {\n const words = text.split(/\\s+/).filter(Boolean);\n const lines: string[] = [];\n let line = \"\";\n for (const word of words) {\n if (line && line.length + 1 + word.length > width) {\n lines.push(line);\n line = word;\n } else {\n line = line ? `${line} ${word}` : word;\n }\n }\n if (line) lines.push(line);\n return lines.length > 0 ? lines : [\"\"];\n}\n\n/**\n * Column widths come from the *content*, never from `process.stdout.columns`.\n *\n * `AS-CLI-003` requires plain output to be byte-stable across runs, and a table\n * laid out against the terminal it happened to run in is stable only until two\n * people diff the same CI log from different windows. Same rows in, same bytes\n * out, everywhere.\n *\n * The last column is not padded, so no line ever carries trailing whitespace —\n * which some diff tools render and others strip, i.e. another way for identical\n * output to look different.\n */\nfunction renderTable(headers: string[], rows: TableRow[]): string[] {\n const widths = headers.map((header, column) =>\n Math.max(header.length, ...rows.map((row) => (row.cells[column] ?? \"\").length)),\n );\n const line = (cells: string[]): string =>\n cells\n .map((cell, column) => (column === headers.length - 1 ? cell : cell.padEnd(widths[column]!)))\n .join(\" \")\n .trimEnd();\n\n const lines = [line(headers)];\n for (const row of rows) {\n lines.push(line(row.cells));\n // The unavailability reason is prose of unbounded length. A column for it\n // would set the table's width by its longest sentence; a continuation line\n // keeps the grid aligned and puts the reason directly under its capability.\n if (row.note) {\n for (const [index, note] of wrapText(row.note, REPORT_WIDTH - 6).entries()) {\n lines.push(` ${index === 0 ? \"⤷ \" : \" \"}${note}`);\n }\n }\n }\n return lines;\n}\n\n/** `UNREACHED — authored, and no scenario mounts it (1)` */\nfunction section(title: string, gloss: string, count: number): string {\n return `${title} — ${gloss} (${count})`;\n}\n\n/**\n * A labelled block: an optional title, then `label STATUS text` rows.\n *\n * The label column is the report's, not this block's (`reportGrid`) — every\n * block in one report shares one text column, whichever renderer drew it.\n */\nexport function renderReportPlain(blocks: ReportBlock[], labelWidth?: number): string {\n const grid = reportGrid(blocks, labelWidth);\n const renderRow = (row: ReportRow): string =>\n `${row.label.padEnd(grid.label)}${\n grid.statuses ? (row.status ?? \"\").padEnd(STATUS_WIDTH) : \"\"\n }${row.text}`.trimEnd();\n\n return blocks\n .filter((block) => block.title || block.rows.length > 0)\n .map((block) => [...(block.title ? [block.title] : []), ...block.rows.map(renderRow)].join(\"\\n\"))\n .join(\"\\n\\n\");\n}\n\n/** Findings, in the order they were built. Tables unindented, lists indented. */\nfunction renderSectionsPlain(sections: FindingSection[]): string {\n return sections\n .map((entry) => {\n const lines = [\n entry.count > 0\n ? section(entry.title, entry.gloss, entry.count)\n : `${entry.title} — ${entry.gloss}`,\n ];\n if (entry.headers && entry.rows) lines.push(...renderTable(entry.headers, entry.rows));\n if (entry.lines) lines.push(...entry.lines.map((line) => ` ${line}`.trimEnd()));\n if (entry.hint) {\n lines.push(\n ...wrapText(entry.hint, REPORT_WIDTH - 4).map(\n (line, index) => ` ${index === 0 ? \"→\" : \" \"} ${line}`,\n ),\n );\n }\n return lines.join(\"\\n\");\n })\n .join(\"\\n\\n\");\n}\n\n/** The commands that clear this report, in the order worth running them. */\nfunction renderStepsPlain(title: string, steps: string[]): string {\n return [\n title,\n ...steps.flatMap((step, index) =>\n wrapText(step, REPORT_WIDTH - 5).map(\n (line, wrapped) => ` ${wrapped === 0 ? `${index + 1}.` : \" \"} ${line}`,\n ),\n ),\n ].join(\"\\n\");\n}\n\n/**\n * One part of a report. Every command's output is a list of these, so a block\n * cannot be laid out one way in `inspect` and another in `check`.\n */\nexport function renderPartPlain(part: ReportPart, labelWidth?: number): string {\n switch (part.kind) {\n case \"blocks\":\n return renderReportPlain(part.blocks, labelWidth);\n case \"table\":\n return [\n part.title,\n ...(part.lead ? [part.lead] : []),\n ...renderTable(part.headers, part.rows),\n ].join(\"\\n\");\n case \"findings\":\n return renderSectionsPlain(part.sections);\n case \"surface\":\n return renderSurfacePlain(part.view, { ...(part.detail ? { detail: true } : {}) });\n case \"note\":\n return [...(part.title ? [part.title] : []), ...part.lines].join(\"\\n\");\n case \"steps\":\n return renderStepsPlain(part.title, part.steps);\n }\n}\n\n/** A whole report, one blank line between parts. */\nexport function renderPartsPlain(parts: ReportPart[], labelWidth?: number): string {\n return parts\n .map((part) => renderPartPlain(part, labelWidth))\n .filter((text) => text.length > 0)\n .join(\"\\n\\n\");\n}\n\nfunction renderDetailRow(row: CapabilityRow, lines: string[]): void {\n const tags = row.tags.length > 0 ? ` [${row.tags.join(\", \")}]` : \"\";\n lines.push(` ${MARK[row.outcome]} ${row.name}${tags}`);\n lines.push(` ${row.description}`);\n if (row.reason) lines.push(` reason: ${row.reason}`);\n\n if (row.policies) {\n if (row.policies.length === 0) {\n lines.push(\" policies: none\");\n } else {\n for (const policy of row.policies) {\n const vote = policy.discovery\n ? policy.discovery.decision === \"disable\"\n ? `disable — ${policy.discovery.reason}`\n : policy.discovery.decision\n : \"no discovery hook\";\n const phases = policy.phases.length > 0 ? policy.phases.join(\"/\") : NONE;\n const flags = [\n policy.threw ? \"THREW\" : \"\",\n policy.confirmationEscalation ? \"escalates-confirmation\" : \"\",\n ]\n .filter(Boolean)\n .join(\", \");\n lines.push(\n ` policy ${policy.name} (${policy.scope}, ${phases}): ${vote}${\n flags ? ` [${flags}]` : \"\"\n }`,\n );\n }\n }\n if (row.availability && !row.availability.available) {\n lines.push(\n ` availability: unavailable${\n row.availability.reason ? ` — ${row.availability.reason}` : \"\"\n }`,\n );\n }\n }\n\n if (row.schemas) {\n if (row.schemas.input !== undefined) {\n lines.push(` input: ${JSON.stringify(row.schemas.input)}`);\n }\n if (row.schemas.output !== undefined) {\n lines.push(` output: ${JSON.stringify(row.schemas.output)}`);\n }\n }\n}\n\n/**\n * The counts line, and everything it is relative to (`AS-CLI-007`).\n *\n * `hidden` is printed unconditionally. It is computed on every run — the\n * explanation is always collected — and suppressing it outside `--explain`\n * meant a surface with a policy-hidden half rendered as a complete one. The\n * *attribution* still needs `--explain`; the count and the rows do not.\n *\n * The risk clause is the same argument one level up: `9 callable` says how much\n * surface there is and nothing about what it can do, and \"one of these deletes\n * a device\" is the part a reader needs before they read anything else.\n */\nfunction renderCountsPlain(view: SurfaceView): string {\n const risk = riskClause(flatRows(view));\n return (\n `${view.counts.callable} callable, ${view.counts.disabled} visible-disabled, ` +\n `${view.counts.hidden} hidden` +\n (view.rejections.length > 0\n ? `, ${view.rejections.length} registration${view.rejections.length === 1 ? \"\" : \"s\"} rejected`\n : \"\") +\n (risk ? ` · ${risk}` : \"\")\n );\n}\n\nfunction renderHeader(view: SurfaceView, lines: string[]): void {\n lines.push(\n `scenario ${view.scenario}${view.route ? ` route ${view.route}` : \"\"}${\n view.scope && view.scope.length > 0 ? ` scope ${view.scope.join(\" \")}` : \"\"\n }`,\n );\n lines.push(renderCountsPlain(view));\n}\n\nfunction renderRejections(view: SurfaceView, lines: string[]): void {\n if (view.rejections.length === 0) return;\n lines.push(\"\");\n lines.push(\n section(\"REJECTED\", \"the registry refused these during the mount\", view.rejections.length),\n );\n for (const rejection of view.rejections) {\n const why =\n rejection.reason === \"duplicate\"\n ? \"duplicate — an earlier registration holds this key\"\n : \"guard — onRegister rejected this registration\";\n lines.push(` ! ${rejection.componentType} (${rejection.instanceId}) ${why}`);\n }\n}\n\nfunction renderEmpty(view: SurfaceView, lines: string[]): void {\n lines.push(\"\");\n // \"Nothing is registered\" is only true when nothing was hidden. Saying it\n // over a surface a policy emptied sends the reader to the wrong file.\n if (view.counts.hidden > 0) {\n lines.push(\n `Nothing is callable here — all ${view.counts.hidden} registered capabilities were hidden by policy.`,\n );\n if (!view.explained) lines.push(\"Re-run with --explain to see which policy hid them.\");\n } else {\n lines.push(\"Nothing is registered for this scenario — the agent has no surface here.\");\n if (!view.explained) lines.push(\"Re-run with --explain to see whether a policy hid it.\");\n }\n}\n\nexport interface SurfaceRenderOptions {\n /** The grouped, one-capability-per-paragraph view. Implied by --explain/--schemas. */\n detail?: boolean;\n}\n\n/**\n * One capability per line, aligned. The default, because the question `inspect`\n * is usually asked is *what is on this surface* — which is a scanning question,\n * and prose does not scan.\n *\n * Policy chains and JSON Schemas are multi-line by nature and cannot live in a\n * cell, so `--explain` and `--schemas` fall back to the detail view rather than\n * producing a table with most of the answer missing.\n */\nexport function renderSurfacePlain(view: SurfaceView, options: SurfaceRenderOptions = {}): string {\n const lines: string[] = [];\n renderHeader(view, lines);\n renderRejections(view, lines);\n\n const rows = flatRows(view);\n if (rows.length === 0) {\n renderEmpty(view, lines);\n return lines.join(\"\\n\");\n }\n\n if (options.detail) {\n for (const group of view.groups.filter((group) => group.rows.length > 0)) {\n lines.push(\"\");\n lines.push(`${group.heading} (${group.rows.length})`);\n for (const row of group.rows) renderDetailRow(row, lines);\n }\n return lines.join(\"\\n\");\n }\n\n lines.push(\"\");\n lines.push(\n ...renderTable(\n [\"CAPABILITY\", \"KIND\", \"EFFECT\", \"STATE\", \"FLAGS\"],\n rows.map((row) => ({\n cells: [\n row.path,\n row.kind,\n row.effect ?? NONE,\n STATE[row.outcome],\n row.flags.length > 0 ? row.flags.join(\" · \") : NONE,\n ],\n ...(row.reason ? { note: row.reason } : {}),\n })),\n ),\n );\n return lines.join(\"\\n\");\n}\n\n/**\n * First-screen answer for `check`: verdict, context, health, then scenarios.\n *\n * Exported for the unit test that drives the matrix through every combination\n * a real run would take minutes to reach. The command itself emits the parts.\n */\nexport function renderCheckOverviewPlain(input: CheckOverview): string {\n return renderPartsPlain(checkOverviewParts(input));\n}\n\n/** One scenario's drift, unindented — the section renderer owns the indent. */\nexport function renderDriftPlain(scenario: string, entries: DiffEntry[]): string[] {\n const lines = [`${scenario}: ${entries.length} change${entries.length === 1 ? \"\" : \"s\"}`];\n for (const entry of entries) {\n const where = entry.subject ? `${entry.subject} (${entry.path})` : entry.path;\n if (entry.kind === \"added\") lines.push(` + ${where} ${formatValue(entry.after)}`);\n else if (entry.kind === \"removed\") lines.push(` - ${where} ${formatValue(entry.before)}`);\n else {\n lines.push(` ~ ${where}`);\n lines.push(` before: ${formatValue(entry.before)}`);\n lines.push(` after: ${formatValue(entry.after)}`);\n }\n }\n return lines;\n}\n"],"mappings":"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","names":["existsSync","dirname","join","resolve","group"]}
|