@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,539 @@
|
|
|
1
|
+
import {
|
|
2
|
+
authoredIds,
|
|
3
|
+
unreadKey,
|
|
4
|
+
unresolved
|
|
5
|
+
} from "./chunk-UGCLJ5JX.js";
|
|
6
|
+
|
|
7
|
+
// src/render/model.ts
|
|
8
|
+
function flatRows(view) {
|
|
9
|
+
return view.groups.flatMap((group) => group.rows);
|
|
10
|
+
}
|
|
11
|
+
function pathOf(capabilityId) {
|
|
12
|
+
return capabilityId.replace(/^(view|domain):/, "");
|
|
13
|
+
}
|
|
14
|
+
function leafOf(capabilityId) {
|
|
15
|
+
const withoutPlane = pathOf(capabilityId);
|
|
16
|
+
const dot = withoutPlane.lastIndexOf(".");
|
|
17
|
+
return dot === -1 ? withoutPlane : withoutPlane.slice(dot + 1);
|
|
18
|
+
}
|
|
19
|
+
function actionFlags(action) {
|
|
20
|
+
const flags = [];
|
|
21
|
+
if (action.idempotent) flags.push("idempotent");
|
|
22
|
+
if (action.reversible) flags.push("reversible");
|
|
23
|
+
if (action.confirmation !== "never") flags.push(`confirmation:${action.confirmation}`);
|
|
24
|
+
return flags;
|
|
25
|
+
}
|
|
26
|
+
function procedureFlags(procedure) {
|
|
27
|
+
const flags = [];
|
|
28
|
+
if (procedure.confirmation !== "never") flags.push(`confirmation:${procedure.confirmation}`);
|
|
29
|
+
for (const field of procedure.boundFields) {
|
|
30
|
+
flags.push(`${field.path} bound${field.locked ? "+locked" : ""}`);
|
|
31
|
+
}
|
|
32
|
+
return flags;
|
|
33
|
+
}
|
|
34
|
+
function explanationIndex(explanation) {
|
|
35
|
+
const index = /* @__PURE__ */ new Map();
|
|
36
|
+
for (const capability of explanation.capabilities) {
|
|
37
|
+
index.set(`${capability.capabilityId}\0${capability.registrationId}`, capability);
|
|
38
|
+
}
|
|
39
|
+
return index;
|
|
40
|
+
}
|
|
41
|
+
function buildView(result, options = {}) {
|
|
42
|
+
const { snapshot, explanation } = result;
|
|
43
|
+
const index = explanationIndex(explanation);
|
|
44
|
+
const groups = [];
|
|
45
|
+
const counts = { callable: 0, disabled: 0, hidden: 0 };
|
|
46
|
+
const enrich = (row, capabilityId, registrationId) => {
|
|
47
|
+
const explained = index.get(`${capabilityId}\0${registrationId}`);
|
|
48
|
+
if (options.explain && explained) {
|
|
49
|
+
row.policies = explained.policies;
|
|
50
|
+
row.availability = explained.availability;
|
|
51
|
+
}
|
|
52
|
+
return row;
|
|
53
|
+
};
|
|
54
|
+
for (const component of snapshot.components) {
|
|
55
|
+
const rows = [];
|
|
56
|
+
for (const observation of component.observations) {
|
|
57
|
+
rows.push(
|
|
58
|
+
enrich(
|
|
59
|
+
rowFor(observation, "observation", void 0, [], options, {
|
|
60
|
+
input: void 0,
|
|
61
|
+
output: observation.outputSchema
|
|
62
|
+
}),
|
|
63
|
+
observation.capabilityId,
|
|
64
|
+
component.registrationId
|
|
65
|
+
)
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
for (const action of component.actions) {
|
|
69
|
+
rows.push(
|
|
70
|
+
enrich(
|
|
71
|
+
rowFor(action, "action", action.effect, actionFlags(action), options, {
|
|
72
|
+
input: action.inputSchema,
|
|
73
|
+
output: action.outputSchema
|
|
74
|
+
}),
|
|
75
|
+
action.capabilityId,
|
|
76
|
+
component.registrationId
|
|
77
|
+
)
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
groups.push({
|
|
81
|
+
heading: component.instanceId === "default" ? component.type : `${component.type}@${component.instanceId}`,
|
|
82
|
+
rows
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (snapshot.procedures.length > 0) {
|
|
86
|
+
groups.push({
|
|
87
|
+
heading: "authoritative (domain)",
|
|
88
|
+
rows: snapshot.procedures.map(
|
|
89
|
+
(procedure) => enrich(
|
|
90
|
+
{
|
|
91
|
+
capabilityId: procedure.procedureId,
|
|
92
|
+
name: procedure.procedureId.replace(/^domain:/, ""),
|
|
93
|
+
path: pathOf(procedure.procedureId),
|
|
94
|
+
kind: "procedure",
|
|
95
|
+
plane: "domain",
|
|
96
|
+
outcome: procedure.available ? "expose" : "disable",
|
|
97
|
+
description: procedure.description,
|
|
98
|
+
...procedure.unavailableReason ? { reason: procedure.unavailableReason } : {},
|
|
99
|
+
effect: procedure.effect,
|
|
100
|
+
flags: procedureFlags(procedure),
|
|
101
|
+
tags: [procedure.effect, ...procedureFlags(procedure)],
|
|
102
|
+
...options.schemas ? { schemas: { input: procedure.inputSchema, output: procedure.outputSchema } } : {}
|
|
103
|
+
},
|
|
104
|
+
procedure.procedureId,
|
|
105
|
+
procedure.registrationId
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
const hidden = explanation.capabilities.filter((c) => c.outcome === "hide");
|
|
111
|
+
if (hidden.length > 0) {
|
|
112
|
+
groups.push({
|
|
113
|
+
heading: "hidden by policy (absent from the snapshot)",
|
|
114
|
+
rows: hidden.map((capability) => ({
|
|
115
|
+
capabilityId: capability.capabilityId,
|
|
116
|
+
name: leafOf(capability.capabilityId),
|
|
117
|
+
path: pathOf(capability.capabilityId),
|
|
118
|
+
kind: capability.kind,
|
|
119
|
+
plane: capability.plane,
|
|
120
|
+
outcome: "hide",
|
|
121
|
+
description: capability.description,
|
|
122
|
+
// No reason line, deliberately. The reason a hidden capability carries
|
|
123
|
+
// is its *availability* reason — "The drawer is not open" — and printing
|
|
124
|
+
// that under a row marked `hidden` says the UI declined when authority
|
|
125
|
+
// did. Authority hides, state discloses (D11/D12), and the two must
|
|
126
|
+
// never look alike. Why it was hidden is a policy question, which is
|
|
127
|
+
// what `--explain` answers.
|
|
128
|
+
//
|
|
129
|
+
// A hidden capability has no snapshot entry, so there is no effect to
|
|
130
|
+
// report — the table prints an em dash rather than inventing one. The
|
|
131
|
+
// capability path already carries the component type; only a non-default
|
|
132
|
+
// instance adds anything.
|
|
133
|
+
flags: capability.component.instanceId === "default" ? [] : [`@${capability.component.instanceId}`],
|
|
134
|
+
tags: [`${capability.component.type}@${capability.component.instanceId}`],
|
|
135
|
+
...options.explain ? { policies: capability.policies, availability: capability.availability } : {}
|
|
136
|
+
}))
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
for (const capability of explanation.capabilities) {
|
|
140
|
+
if (capability.outcome === "expose") counts.callable += 1;
|
|
141
|
+
else if (capability.outcome === "disable") counts.disabled += 1;
|
|
142
|
+
else counts.hidden += 1;
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
scenario: result.scenario,
|
|
146
|
+
...snapshot.route?.path ? { route: snapshot.route.path } : {},
|
|
147
|
+
...result.scope ? { scope: result.scope } : {},
|
|
148
|
+
groups,
|
|
149
|
+
counts,
|
|
150
|
+
rejections: result.rejections ?? [],
|
|
151
|
+
explained: options.explain === true
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function rowFor(descriptor, kind, effect, flags, options, schemas) {
|
|
155
|
+
return {
|
|
156
|
+
capabilityId: descriptor.capabilityId,
|
|
157
|
+
name: descriptor.name,
|
|
158
|
+
path: pathOf(descriptor.capabilityId),
|
|
159
|
+
kind,
|
|
160
|
+
plane: "view",
|
|
161
|
+
outcome: descriptor.available ? "expose" : "disable",
|
|
162
|
+
description: descriptor.description,
|
|
163
|
+
...descriptor.unavailableReason ? { reason: descriptor.unavailableReason } : {},
|
|
164
|
+
...effect ? { effect } : {},
|
|
165
|
+
flags,
|
|
166
|
+
// The grouped detail view prints one combined list, the way it always has.
|
|
167
|
+
tags: effect ? [effect, ...flags] : [kind, ...flags],
|
|
168
|
+
...options.schemas ? { schemas } : {}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// src/render/summary.ts
|
|
173
|
+
import { relative } from "path";
|
|
174
|
+
function displayPath(path) {
|
|
175
|
+
const rel = relative(process.cwd(), path);
|
|
176
|
+
return rel && !rel.startsWith("..") ? rel : path;
|
|
177
|
+
}
|
|
178
|
+
var DEPTH_TEXT = {
|
|
179
|
+
full: "full \u2014 the source is read and every scenario is mounted",
|
|
180
|
+
static: "static \u2014 the source only; nothing is mounted",
|
|
181
|
+
runtime: "runtime \u2014 the scenarios only; the source is not read"
|
|
182
|
+
};
|
|
183
|
+
function runContextRows(context) {
|
|
184
|
+
const rows = [
|
|
185
|
+
{ label: "Config", text: displayPath(context.configPath) },
|
|
186
|
+
{ label: "Depth", text: DEPTH_TEXT[context.depth] },
|
|
187
|
+
{
|
|
188
|
+
label: "Scope",
|
|
189
|
+
text: context.scope && context.scope.length > 0 ? `${context.scope.join(" \xB7 ")} \u2014 every count below is relative to it` : "whole surface \u2014 no component-type prefix filter"
|
|
190
|
+
}
|
|
191
|
+
];
|
|
192
|
+
if (context.scenarios) {
|
|
193
|
+
const declared = context.declaredScenarios ?? context.scenarios;
|
|
194
|
+
const named = context.scenarios.length < declared.length;
|
|
195
|
+
rows.push({
|
|
196
|
+
label: "Scenarios",
|
|
197
|
+
text: `${named ? `${context.scenarios.length} of ${declared.length}` : context.scenarios.length} \u2014 ${context.scenarios.join(", ")}`
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return rows;
|
|
201
|
+
}
|
|
202
|
+
function catalogRows(inventory, options = {}) {
|
|
203
|
+
const resolved = inventory.capabilities.filter((c) => c.resolution !== "unresolved");
|
|
204
|
+
const unreadEntries = unresolved(inventory);
|
|
205
|
+
const dynamicMetadata = resolved.filter((c) => c.resolution === "partial").length;
|
|
206
|
+
const authored = authoredIds(inventory).size + (options.domainCapabilities ?? 0);
|
|
207
|
+
return [
|
|
208
|
+
{
|
|
209
|
+
label: "STATUS",
|
|
210
|
+
tone: unreadEntries.length > 0 ? "warn" : "good",
|
|
211
|
+
text: unreadEntries.length > 0 ? `INCOMPLETE \u2014 ${unreadEntries.length} unread capability identit${unreadEntries.length === 1 ? "y" : "ies"}` : "COMPLETE \u2014 every capability identity resolved"
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
label: "Capabilities",
|
|
215
|
+
text: `${authored} authored (upper bound) \xB7 ${resolved.length} resolved call site${resolved.length === 1 ? "" : "s"}`
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
label: "Program",
|
|
219
|
+
text: `${inventory.filesAnalyzed} file${inventory.filesAnalyzed === 1 ? "" : "s"} analyzed` + (inventory.filesOutsideRoot > 0 ? ` \xB7 ${inventory.filesOutsideRoot} agent-surface implementation file${inventory.filesOutsideRoot === 1 ? "" : "s"} excluded` : "")
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
label: "Metadata",
|
|
223
|
+
text: `${dynamicMetadata} call site${dynamicMetadata === 1 ? "" : "s"} partially read` + (dynamicMetadata > 0 ? " \xB7 identity remains resolved" : "")
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
// Three different statements, and only one of them is a number. "Nobody
|
|
227
|
+
// looked" and "there is nothing to look at" must not read alike (OQ-1).
|
|
228
|
+
label: "Domain",
|
|
229
|
+
...options.mounted && options.domainCapabilities === void 0 ? { tone: "warn" } : {},
|
|
230
|
+
text: options.domainCapabilities !== void 0 ? `${options.domainCapabilities} manifest capabilit${options.domainCapabilities === 1 ? "y" : "ies"}` : options.mounted ? "no authoritative oRPC manifest configured \u2014 that plane has no denominator" : "not analyzed at static depth; full depth reads the oRPC manifest"
|
|
231
|
+
}
|
|
232
|
+
];
|
|
233
|
+
}
|
|
234
|
+
function runHeaderBlocks(title, context, inventory, domainCapabilities) {
|
|
235
|
+
return [
|
|
236
|
+
{ title, rows: runContextRows(context) },
|
|
237
|
+
...inventory ? [
|
|
238
|
+
{
|
|
239
|
+
title: "STATIC CATALOG",
|
|
240
|
+
rows: catalogRows(inventory, {
|
|
241
|
+
...domainCapabilities === void 0 ? {} : { domainCapabilities },
|
|
242
|
+
...context.depth === "static" ? {} : { mounted: true }
|
|
243
|
+
})
|
|
244
|
+
}
|
|
245
|
+
] : []
|
|
246
|
+
];
|
|
247
|
+
}
|
|
248
|
+
function scenarioStats(result) {
|
|
249
|
+
const counts = { expose: 0, disable: 0, hide: 0 };
|
|
250
|
+
for (const capability of result.explanation.capabilities) counts[capability.outcome] += 1;
|
|
251
|
+
return {
|
|
252
|
+
scenario: result.scenario,
|
|
253
|
+
...result.snapshot.route?.path ? { route: result.snapshot.route.path } : {},
|
|
254
|
+
callable: counts.expose,
|
|
255
|
+
disabled: counts.disable,
|
|
256
|
+
hidden: counts.hide,
|
|
257
|
+
rejected: result.rejections.length
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
var NONE = "\u2014";
|
|
261
|
+
function scenarioTable(stats, options = {}) {
|
|
262
|
+
const headers = ["SCENARIO", "ROUTE", "CALLABLE", "DISABLED", "HIDDEN", "REJECTED"];
|
|
263
|
+
if (options.baselines) headers.push("BASELINE");
|
|
264
|
+
return {
|
|
265
|
+
headers,
|
|
266
|
+
rows: stats.map((entry) => ({
|
|
267
|
+
// The baseline column already says `did not mount`, so the note carries
|
|
268
|
+
// only what a reader cannot get anywhere else: why.
|
|
269
|
+
...entry.failed ? {
|
|
270
|
+
note: `${options.baselines ? "" : "did not mount \u2014 "}${entry.failure ?? "the scenario threw during mount"}`
|
|
271
|
+
} : {},
|
|
272
|
+
cells: [
|
|
273
|
+
entry.scenario,
|
|
274
|
+
entry.route ?? NONE,
|
|
275
|
+
...entry.failed ? [NONE, NONE, NONE, NONE] : [
|
|
276
|
+
String(entry.callable),
|
|
277
|
+
String(entry.disabled),
|
|
278
|
+
String(entry.hidden),
|
|
279
|
+
entry.rejected > 0 ? String(entry.rejected) : NONE
|
|
280
|
+
],
|
|
281
|
+
...options.baselines ? [entry.failed ? "did not mount" : entry.baseline ?? NONE] : []
|
|
282
|
+
]
|
|
283
|
+
}))
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
var RANK = { hide: 0, disable: 1, expose: 2 };
|
|
287
|
+
function trackReach(reach, rows, scenario) {
|
|
288
|
+
for (const row of rows) {
|
|
289
|
+
const current = reach.get(row.capabilityId);
|
|
290
|
+
if (!current) {
|
|
291
|
+
reach.set(row.capabilityId, {
|
|
292
|
+
capabilityId: row.capabilityId,
|
|
293
|
+
best: row.outcome,
|
|
294
|
+
...row.effect ? { effect: row.effect } : {},
|
|
295
|
+
flags: row.flags,
|
|
296
|
+
...row.reason ? { note: row.reason } : {},
|
|
297
|
+
scenarios: [scenario]
|
|
298
|
+
});
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
current.scenarios.push(scenario);
|
|
302
|
+
if (!current.effect && row.effect) current.effect = row.effect;
|
|
303
|
+
if (current.flags.length === 0 && row.flags.length > 0) current.flags = row.flags;
|
|
304
|
+
if (RANK[row.outcome] > RANK[current.best]) {
|
|
305
|
+
current.best = row.outcome;
|
|
306
|
+
if (row.reason) current.note = row.reason;
|
|
307
|
+
else delete current.note;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
function neverCallable(reach) {
|
|
312
|
+
return [...reach.values()].filter((entry) => entry.best !== "expose").sort((a, b) => a.capabilityId.localeCompare(b.capabilityId));
|
|
313
|
+
}
|
|
314
|
+
var MUTATING = /* @__PURE__ */ new Set(["server-mutation", "external-side-effect", "destructive"]);
|
|
315
|
+
function riskOf(entries) {
|
|
316
|
+
const present = entries.filter((entry) => entry.outcome !== "hide");
|
|
317
|
+
return {
|
|
318
|
+
present: present.length,
|
|
319
|
+
destructive: present.filter((entry) => entry.effect === "destructive").length,
|
|
320
|
+
mutating: present.filter((entry) => entry.effect && MUTATING.has(entry.effect)).length,
|
|
321
|
+
confirmed: present.filter(
|
|
322
|
+
(entry) => entry.flags.some((flag) => flag.startsWith("confirmation:"))
|
|
323
|
+
).length,
|
|
324
|
+
bound: present.filter((entry) => entry.flags.some((flag) => flag.includes(" bound"))).length
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
function riskParts(risk) {
|
|
328
|
+
return [
|
|
329
|
+
...risk.destructive > 0 ? [`${risk.destructive} destructive`] : [],
|
|
330
|
+
...risk.mutating > risk.destructive ? [`${risk.mutating - risk.destructive} mutating`] : [],
|
|
331
|
+
...risk.confirmed > 0 ? [`${risk.confirmed} confirmation-gated`] : []
|
|
332
|
+
];
|
|
333
|
+
}
|
|
334
|
+
function riskClause(rows) {
|
|
335
|
+
const parts = riskParts(riskOf(rows));
|
|
336
|
+
return parts.join(", ");
|
|
337
|
+
}
|
|
338
|
+
function riskText(reach) {
|
|
339
|
+
const risk = riskOf([...reach.values()].map((entry) => ({ ...entry, outcome: entry.best })));
|
|
340
|
+
const parts = riskParts(risk);
|
|
341
|
+
if (risk.present === 0) {
|
|
342
|
+
return "nothing is on the surface at all \u2014 every capability was hidden by policy";
|
|
343
|
+
}
|
|
344
|
+
if (parts.length === 0) {
|
|
345
|
+
return `nothing mutating or destructive is on the surface \xB7 ${risk.present} read-only or local-state capabilit${risk.present === 1 ? "y" : "ies"}`;
|
|
346
|
+
}
|
|
347
|
+
return [...parts, ...risk.bound > 0 ? [`${risk.bound} with bound input`] : []].join(" \xB7 ");
|
|
348
|
+
}
|
|
349
|
+
function surfaceSummaryRows(input) {
|
|
350
|
+
const rows = [];
|
|
351
|
+
const coverage = input.coverage;
|
|
352
|
+
if (coverage) {
|
|
353
|
+
rows.push({
|
|
354
|
+
label: "Reach",
|
|
355
|
+
tone: coverage.unreached.length > 0 ? "bad" : "good",
|
|
356
|
+
text: `${coverage.reached}/${coverage.authored} authored capabilit${coverage.authored === 1 ? "y" : "ies"} reached` + (coverage.unreached.length > 0 ? ` \xB7 ${coverage.unreached.length} unreached` : "") + (coverage.allowed.length > 0 ? ` \xB7 ${coverage.allowed.length} allowlisted` : "")
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
const mounted = input.reach.size;
|
|
360
|
+
const dark = neverCallable(input.reach);
|
|
361
|
+
if (mounted > 0) {
|
|
362
|
+
const stuck = dark.filter((entry) => entry.best === "disable").length;
|
|
363
|
+
const why = [
|
|
364
|
+
...stuck > 0 ? [`${stuck} disabled`] : [],
|
|
365
|
+
...dark.length > stuck ? [`${dark.length - stuck} hidden`] : []
|
|
366
|
+
].join(", ");
|
|
367
|
+
rows.push({
|
|
368
|
+
label: "Callable",
|
|
369
|
+
tone: dark.length > 0 ? "warn" : "good",
|
|
370
|
+
text: `${mounted - dark.length}/${mounted} mounted capabilit${mounted === 1 ? "y is" : "ies are"} callable in at least one scenario` + (dark.length > 0 ? ` \xB7 ${dark.length} never callable (${why})` : "")
|
|
371
|
+
});
|
|
372
|
+
rows.push({ label: "Risk", text: riskText(input.reach) });
|
|
373
|
+
}
|
|
374
|
+
if (coverage) {
|
|
375
|
+
if (coverage.domainReached.length > 0 || coverage.domainAuthoritative) {
|
|
376
|
+
rows.push({
|
|
377
|
+
label: "Domain",
|
|
378
|
+
tone: coverage.unmanifestedDomain.length > 0 ? "bad" : "good",
|
|
379
|
+
text: coverage.unmanifestedDomain.length > 0 ? `${coverage.unmanifestedDomain.length} mounted capabilit${coverage.unmanifestedDomain.length === 1 ? "y is" : "ies are"} absent from the oRPC manifest` : `${coverage.domainReached.length} capabilit${coverage.domainReached.length === 1 ? "y" : "ies"} reached${coverage.domainAuthoritative ? " against the authoritative oRPC manifest" : " and held apart \u2014 configure the manifest to cover that plane"}`
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
rows.push({
|
|
383
|
+
label: "Catalog",
|
|
384
|
+
tone: coverage.unresolved.length > 0 ? "warn" : "good",
|
|
385
|
+
text: coverage.unresolved.length > 0 ? `${coverage.unresolved.length} unread call site${coverage.unresolved.length === 1 ? "" : "s"} \u2014 every count above is a floor` : `every call site read${coverage.allowedUnread.length > 0 ? ` \xB7 ${coverage.allowedUnread.length} allowlisted` : ""}`
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
rows.push({
|
|
389
|
+
label: "Scenarios",
|
|
390
|
+
tone: input.failures > 0 ? "bad" : void 0,
|
|
391
|
+
text: `${input.scenarios.filter((entry) => !entry.failed).length} mounted` + (input.failures > 0 ? ` \xB7 ${input.failures} did not mount` : "")
|
|
392
|
+
});
|
|
393
|
+
rows.push({ label: "Verdict", tone: verdictTone(input), text: verdictText(input) });
|
|
394
|
+
return rows;
|
|
395
|
+
}
|
|
396
|
+
function verdictTone(input) {
|
|
397
|
+
if (input.failures > 0) return "bad";
|
|
398
|
+
if (!input.coverage) return "warn";
|
|
399
|
+
const clean = input.coverage.unreached.length === 0 && input.coverage.unresolved.length === 0 && input.coverage.staleAllowlist.length === 0 && input.coverage.staleUnreadAllowlist.length === 0 && input.coverage.unmanifestedDomain.length === 0;
|
|
400
|
+
return clean ? "good" : "bad";
|
|
401
|
+
}
|
|
402
|
+
function verdictText(input) {
|
|
403
|
+
if (input.failures > 0) {
|
|
404
|
+
return "a scenario did not mount, so no coverage verdict was computed at all";
|
|
405
|
+
}
|
|
406
|
+
const coverage = input.coverage;
|
|
407
|
+
if (!coverage) {
|
|
408
|
+
return input.depth === "runtime" ? "the source was not read at this depth \u2014 a statement about these scenarios only" : "no coverage verdict at this depth";
|
|
409
|
+
}
|
|
410
|
+
if (coverage.unreached.length > 0) {
|
|
411
|
+
return `${coverage.unreached.length} authored capabilit${coverage.unreached.length === 1 ? "y is" : "ies are"} reached by no scenario`;
|
|
412
|
+
}
|
|
413
|
+
if (coverage.unresolved.length > 0) {
|
|
414
|
+
return "every capability the catalog could read is reached \u2014 and the catalog has holes in it";
|
|
415
|
+
}
|
|
416
|
+
return coverage.allowed.length > 0 ? "no new coverage gaps \u2014 the allowlist still holds the known ones" : "every authored capability is reached by a scenario";
|
|
417
|
+
}
|
|
418
|
+
function coverageSections(report, options = {}) {
|
|
419
|
+
const sections = [];
|
|
420
|
+
if (report.unreached.length > 0) {
|
|
421
|
+
sections.push({
|
|
422
|
+
title: "UNREACHED",
|
|
423
|
+
gloss: "authored, and no scenario mounts it",
|
|
424
|
+
count: report.unreached.length,
|
|
425
|
+
headers: ["CAPABILITY", "ORIGIN"],
|
|
426
|
+
rows: report.unreached.map((entry) => ({
|
|
427
|
+
cells: [entry.capabilityId, `${entry.origin.file}:${entry.origin.line}`]
|
|
428
|
+
})),
|
|
429
|
+
hint: `add a scenario that mounts them, delete the dead component, or record the decision in ${displayPath(report.allowlistPath)}`
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
if (report.undeclared.length > 0) {
|
|
433
|
+
if (!options.compact || options.detail) {
|
|
434
|
+
sections.push({
|
|
435
|
+
title: "UNDECLARED",
|
|
436
|
+
gloss: "present at runtime with no static origin \u2014 a dynamic registration, or a gap here",
|
|
437
|
+
count: report.undeclared.length,
|
|
438
|
+
tone: "notice",
|
|
439
|
+
lines: report.undeclared
|
|
440
|
+
});
|
|
441
|
+
} else {
|
|
442
|
+
sections.push({
|
|
443
|
+
title: "NOTICE",
|
|
444
|
+
gloss: `${report.undeclared.length} runtime capabilit${report.undeclared.length === 1 ? "y has" : "ies have"} no static origin; re-run with --detail to list them`,
|
|
445
|
+
count: 0,
|
|
446
|
+
tone: "notice"
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
if (report.unmanifestedDomain.length > 0) {
|
|
451
|
+
sections.push({
|
|
452
|
+
title: "UNMANIFESTED DOMAIN",
|
|
453
|
+
gloss: "mounted, but absent from the authoritative oRPC manifest",
|
|
454
|
+
count: report.unmanifestedDomain.length,
|
|
455
|
+
lines: report.unmanifestedDomain,
|
|
456
|
+
hint: "add them to the manifest, or stop mounting a router the manifest does not describe"
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
if (report.staleAllowlist.length > 0) {
|
|
460
|
+
sections.push({
|
|
461
|
+
title: "STALE ALLOWLIST",
|
|
462
|
+
gloss: "a scenario reaches these now, so delete them before the list rots",
|
|
463
|
+
count: report.staleAllowlist.length,
|
|
464
|
+
lines: report.staleAllowlist,
|
|
465
|
+
hint: `delete these keys from ${displayPath(report.allowlistPath)}`
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
if (report.staleUnreadAllowlist.length > 0) {
|
|
469
|
+
sections.push({
|
|
470
|
+
title: "STALE UNREAD ALLOWLIST",
|
|
471
|
+
gloss: "the extractor reads these now, so delete them before the list rots",
|
|
472
|
+
count: report.staleUnreadAllowlist.length,
|
|
473
|
+
lines: report.staleUnreadAllowlist,
|
|
474
|
+
hint: `delete these keys from ${displayPath(report.unreadAllowlistPath)}`
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
if (report.unresolved.length > 0) {
|
|
478
|
+
sections.push(unreadSection(report.unresolved, report.unreadAllowlistPath));
|
|
479
|
+
}
|
|
480
|
+
return sections;
|
|
481
|
+
}
|
|
482
|
+
function unreadSection(entries, allowlistPath) {
|
|
483
|
+
return {
|
|
484
|
+
title: "UNREAD CALL SITES",
|
|
485
|
+
gloss: "the catalog is incomplete, so every count above is a floor",
|
|
486
|
+
count: entries.length,
|
|
487
|
+
lines: entries.flatMap((entry) => [
|
|
488
|
+
`${entry.origin.file}:${entry.origin.line}`,
|
|
489
|
+
` ${entry.note ?? "the extractor could not read this call site"}`,
|
|
490
|
+
` allowlist key: ${unreadKey(entry)}`
|
|
491
|
+
]),
|
|
492
|
+
hint: allowlistPath ? `make the call site readable, or accept each key in ${displayPath(allowlistPath)}` : "make the call site readable, or accept each key in .agent-surface/unresolved-allow.json"
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
function neverCallableSection(entries) {
|
|
496
|
+
const stuck = entries.filter((entry) => entry.best === "disable").length;
|
|
497
|
+
const hidden = entries.length - stuck;
|
|
498
|
+
return {
|
|
499
|
+
title: "NEVER CALLABLE",
|
|
500
|
+
gloss: "every scenario mounted these, and none of them could call one",
|
|
501
|
+
count: entries.length,
|
|
502
|
+
tone: "notice",
|
|
503
|
+
headers: ["CAPABILITY", "BEST STATE", "WHY"],
|
|
504
|
+
rows: entries.map((entry) => ({
|
|
505
|
+
cells: [
|
|
506
|
+
entry.capabilityId,
|
|
507
|
+
entry.best === "disable" ? "disabled" : "hidden",
|
|
508
|
+
entry.best === "disable" ? entry.note ?? "the UI reported it unavailable in every scenario" : "a policy hid it in every scenario"
|
|
509
|
+
]
|
|
510
|
+
})),
|
|
511
|
+
hint: [
|
|
512
|
+
...stuck > 0 ? [
|
|
513
|
+
"add a scenario that reaches the state these need \u2014 an open drawer, a filled list, a selected row"
|
|
514
|
+
] : [],
|
|
515
|
+
...hidden > 0 ? [
|
|
516
|
+
`add a scenario whose consumer carries the authority ${stuck > 0 ? "the hidden ones are" : "these are"} waiting for`
|
|
517
|
+
] : []
|
|
518
|
+
].join("; ")
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
export {
|
|
523
|
+
flatRows,
|
|
524
|
+
buildView,
|
|
525
|
+
displayPath,
|
|
526
|
+
runContextRows,
|
|
527
|
+
catalogRows,
|
|
528
|
+
runHeaderBlocks,
|
|
529
|
+
scenarioStats,
|
|
530
|
+
scenarioTable,
|
|
531
|
+
trackReach,
|
|
532
|
+
neverCallable,
|
|
533
|
+
riskClause,
|
|
534
|
+
surfaceSummaryRows,
|
|
535
|
+
coverageSections,
|
|
536
|
+
unreadSection,
|
|
537
|
+
neverCallableSection
|
|
538
|
+
};
|
|
539
|
+
//# sourceMappingURL=chunk-VX6GBEP3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/render/model.ts","../src/render/summary.ts"],"sourcesContent":["import type {\n AgentActionDescriptor,\n AgentObservationDescriptor,\n AgentProcedureDescriptor,\n AgentSurfaceSnapshot,\n} from \"@agent-surface/core\";\nimport type { CapabilityExplanation, SurfaceExplanation } from \"@agent-surface/core/explain\";\nimport type { CollectResult, RegistrationRejection } from \"../collect.js\";\n\n/**\n * One view model, two renderers. The Ink UI and the plain-text fallback both\n * consume this, so `--plain` can never drift into showing something different\n * from what a TTY shows.\n */\nexport interface CapabilityRow {\n capabilityId: string;\n /** Leaf name — the group heading already carries the rest of the id. */\n name: string;\n /**\n * The id minus its plane prefix. The table is flat, so its first column has\n * to carry the whole path; the grouped detail view uses `name`.\n */\n path: string;\n kind: \"observation\" | \"action\" | \"procedure\";\n plane: \"view\" | \"domain\";\n outcome: \"expose\" | \"disable\" | \"hide\";\n description: string;\n reason?: string;\n /** The effect, alone, for the table's own column. Observations have none. */\n effect?: string;\n /** What is left of `tags` once the effect has its own column. */\n flags: string[];\n /** Effect and flags together — what the grouped detail view prints. */\n tags: string[];\n policies?: CapabilityExplanation[\"policies\"];\n availability?: CapabilityExplanation[\"availability\"];\n schemas?: { input?: unknown; output?: unknown };\n}\n\nexport interface CapabilityGroup {\n heading: string;\n rows: CapabilityRow[];\n}\n\nexport interface SurfaceView {\n scenario: string;\n route?: string;\n /**\n * The scope the counts below were computed under (`AS-CLI-007`). A scope\n * filters the snapshot *and* the explanation, so without it on screen the\n * header reads as a statement about the whole surface when it is a statement\n * about one prefix of it.\n */\n scope?: string[];\n groups: CapabilityGroup[];\n counts: { callable: number; disabled: number; hidden: number };\n /** Refused during the mount — absent from both projections (`AS-CLI-006`). */\n rejections: RegistrationRejection[];\n explained: boolean;\n}\n\nexport interface ViewOptions {\n explain?: boolean;\n schemas?: boolean;\n}\n\n/**\n * The table is flat — `groups` exist for the grouped detail view, which is what\n * `--detail`, `--explain` and `--schemas` render. Flattening here rather than in\n * each renderer keeps the two views over one order.\n */\nexport function flatRows(view: SurfaceView): CapabilityRow[] {\n return view.groups.flatMap((group) => group.rows);\n}\n\nfunction pathOf(capabilityId: string): string {\n return capabilityId.replace(/^(view|domain):/, \"\");\n}\n\nfunction leafOf(capabilityId: string): string {\n const withoutPlane = pathOf(capabilityId);\n const dot = withoutPlane.lastIndexOf(\".\");\n return dot === -1 ? withoutPlane : withoutPlane.slice(dot + 1);\n}\n\n/**\n * The effect gets its own table column; everything else is a flag. An\n * observation reads state and has no effect at all, which the table shows as\n * an em dash rather than inventing one.\n */\nfunction actionFlags(action: AgentActionDescriptor): string[] {\n const flags: string[] = [];\n if (action.idempotent) flags.push(\"idempotent\");\n if (action.reversible) flags.push(\"reversible\");\n if (action.confirmation !== \"never\") flags.push(`confirmation:${action.confirmation}`);\n return flags;\n}\n\nfunction procedureFlags(procedure: AgentProcedureDescriptor): string[] {\n const flags: string[] = [];\n if (procedure.confirmation !== \"never\") flags.push(`confirmation:${procedure.confirmation}`);\n for (const field of procedure.boundFields) {\n flags.push(`${field.path} bound${field.locked ? \"+locked\" : \"\"}`);\n }\n return flags;\n}\n\nfunction explanationIndex(explanation: SurfaceExplanation): Map<string, CapabilityExplanation> {\n const index = new Map<string, CapabilityExplanation>();\n for (const capability of explanation.capabilities) {\n // Keyed by id + registration so two instances of one component stay apart.\n index.set(`${capability.capabilityId}\\u0000${capability.registrationId}`, capability);\n }\n return index;\n}\n\nexport function buildView(result: CollectResult, options: ViewOptions = {}): SurfaceView {\n const { snapshot, explanation } = result;\n const index = explanationIndex(explanation);\n const groups: CapabilityGroup[] = [];\n const counts = { callable: 0, disabled: 0, hidden: 0 };\n\n const enrich = (\n row: CapabilityRow,\n capabilityId: string,\n registrationId: string,\n ): CapabilityRow => {\n const explained = index.get(`${capabilityId}\\u0000${registrationId}`);\n if (options.explain && explained) {\n row.policies = explained.policies;\n row.availability = explained.availability;\n }\n return row;\n };\n\n for (const component of snapshot.components) {\n const rows: CapabilityRow[] = [];\n\n for (const observation of component.observations) {\n rows.push(\n enrich(\n rowFor(observation, \"observation\", undefined, [], options, {\n input: undefined,\n output: observation.outputSchema,\n }),\n observation.capabilityId,\n component.registrationId,\n ),\n );\n }\n for (const action of component.actions) {\n rows.push(\n enrich(\n rowFor(action, \"action\", action.effect, actionFlags(action), options, {\n input: action.inputSchema,\n output: action.outputSchema,\n }),\n action.capabilityId,\n component.registrationId,\n ),\n );\n }\n\n groups.push({\n heading:\n component.instanceId === \"default\"\n ? component.type\n : `${component.type}@${component.instanceId}`,\n rows,\n });\n }\n\n if (snapshot.procedures.length > 0) {\n groups.push({\n heading: \"authoritative (domain)\",\n rows: snapshot.procedures.map((procedure) =>\n enrich(\n {\n capabilityId: procedure.procedureId,\n name: procedure.procedureId.replace(/^domain:/, \"\"),\n path: pathOf(procedure.procedureId),\n kind: \"procedure\",\n plane: \"domain\",\n outcome: procedure.available ? \"expose\" : \"disable\",\n description: procedure.description,\n ...(procedure.unavailableReason ? { reason: procedure.unavailableReason } : {}),\n effect: procedure.effect,\n flags: procedureFlags(procedure),\n tags: [procedure.effect, ...procedureFlags(procedure)],\n ...(options.schemas\n ? { schemas: { input: procedure.inputSchema, output: procedure.outputSchema } }\n : {}),\n },\n procedure.procedureId,\n procedure.registrationId,\n ),\n ),\n });\n }\n\n // Hidden capabilities exist only in the explanation — that is the whole point\n // of it. They get their own group so nobody mistakes them for callable.\n //\n // Unconditional, not behind `--explain`, for the reason `AS-CLI-007` moved\n // the hidden *count* out from behind it: signed out, the example app rendered\n // `0 callable, 0 visible-disabled` over eleven perfectly good capabilities\n // that authority had hidden, and a reader who did not know to re-run with a\n // flag read that as an app which annotated nothing. The explanation is\n // collected on every run regardless, so this costs nothing. The policy\n // *attribution* still needs `--explain`; only the rows moved.\n const hidden = explanation.capabilities.filter((c) => c.outcome === \"hide\");\n if (hidden.length > 0) {\n groups.push({\n heading: \"hidden by policy (absent from the snapshot)\",\n rows: hidden.map((capability) => ({\n capabilityId: capability.capabilityId,\n name: leafOf(capability.capabilityId),\n path: pathOf(capability.capabilityId),\n kind: capability.kind,\n plane: capability.plane,\n outcome: \"hide\" as const,\n description: capability.description,\n // No reason line, deliberately. The reason a hidden capability carries\n // is its *availability* reason — \"The drawer is not open\" — and printing\n // that under a row marked `hidden` says the UI declined when authority\n // did. Authority hides, state discloses (D11/D12), and the two must\n // never look alike. Why it was hidden is a policy question, which is\n // what `--explain` answers.\n //\n // A hidden capability has no snapshot entry, so there is no effect to\n // report — the table prints an em dash rather than inventing one. The\n // capability path already carries the component type; only a non-default\n // instance adds anything.\n flags:\n capability.component.instanceId === \"default\"\n ? []\n : [`@${capability.component.instanceId}`],\n tags: [`${capability.component.type}@${capability.component.instanceId}`],\n ...(options.explain\n ? { policies: capability.policies, availability: capability.availability }\n : {}),\n })),\n });\n }\n\n for (const capability of explanation.capabilities) {\n if (capability.outcome === \"expose\") counts.callable += 1;\n else if (capability.outcome === \"disable\") counts.disabled += 1;\n else counts.hidden += 1;\n }\n\n return {\n scenario: result.scenario,\n ...(snapshot.route?.path ? { route: snapshot.route.path } : {}),\n ...(result.scope ? { scope: result.scope } : {}),\n groups,\n counts,\n rejections: result.rejections ?? [],\n explained: options.explain === true,\n };\n}\n\nfunction rowFor(\n descriptor: AgentObservationDescriptor | AgentActionDescriptor,\n kind: \"observation\" | \"action\",\n effect: string | undefined,\n flags: string[],\n options: ViewOptions,\n schemas: { input?: unknown; output?: unknown },\n): CapabilityRow {\n return {\n capabilityId: descriptor.capabilityId,\n name: descriptor.name,\n path: pathOf(descriptor.capabilityId),\n kind,\n plane: \"view\",\n outcome: descriptor.available ? \"expose\" : \"disable\",\n description: descriptor.description,\n ...(descriptor.unavailableReason ? { reason: descriptor.unavailableReason } : {}),\n ...(effect ? { effect } : {}),\n flags,\n // The grouped detail view prints one combined list, the way it always has.\n tags: effect ? [effect, ...flags] : [kind, ...flags],\n ...(options.schemas ? { schemas } : {}),\n };\n}\n","/**\n * The report model both renderers draw: labelled rows, and findings.\n *\n * `inspect` and `check` answer different questions, but they answer them about\n * the same surface and a reader moves between them. So the *shapes* are shared\n * — a run header, a status matrix, a findings section — and only the content\n * differs. A second copy of \"how a finding looks\" is how the two commands drift\n * into disagreeing about what they found.\n *\n * Everything here is data. Plain text renders it in `plain.ts`, the terminal UI\n * in `ink.tsx`, and neither can invent a row the other does not have.\n */\nimport { relative } from \"node:path\";\nimport type { CollectResult } from \"../collect.js\";\nimport type { Depth } from \"../contract.js\";\nimport type { CoverageReport } from \"../coverage.js\";\nimport { unreadKey } from \"../coverage.js\";\nimport { authoredIds, unresolved, type CapabilityInventory } from \"../extract.js\";\nimport type { CapabilityRow } from \"./model.js\";\n\nexport type ReportStatus = \"PASS\" | \"WARN\" | \"FAIL\" | \"ERROR\";\n\n/** Colour hint for the terminal UI. Plain text ignores it — words carry it. */\nexport type ReportTone = \"good\" | \"warn\" | \"bad\";\n\n/** One `label [STATUS] text` line. */\nexport interface ReportRow {\n label: string;\n status?: ReportStatus;\n tone?: ReportTone;\n text: string;\n}\n\nexport interface ReportBlock {\n title?: string;\n rows: ReportRow[];\n}\n\n/**\n * A finding: a heading that says what it is, a gloss that says why it matters,\n * and its entries as either a table or a list. `hint` is what to do about it,\n * printed with the finding rather than left for the reader to infer.\n */\nexport interface FindingSection {\n title: string;\n gloss: string;\n count: number;\n /** `notice` is reported but gates nothing — rendered without alarm. */\n tone?: \"finding\" | \"notice\";\n headers?: string[];\n rows?: Array<{ cells: string[]; note?: string }>;\n lines?: string[];\n hint?: string;\n}\n\n/**\n * A path as the reader will type it. `relative` alone turns a baseline\n * directory outside the working tree into a stack of `..` nobody can read, let\n * alone paste — so anything that escapes the working directory prints absolute.\n */\nexport function displayPath(path: string): string {\n const rel = relative(process.cwd(), path);\n return rel && !rel.startsWith(\"..\") ? rel : path;\n}\n\nconst DEPTH_TEXT: Record<Depth, string> = {\n full: \"full — the source is read and every scenario is mounted\",\n static: \"static — the source only; nothing is mounted\",\n runtime: \"runtime — the scenarios only; the source is not read\",\n};\n\nexport interface RunContext {\n configPath: string;\n depth: Depth;\n /** The effective scope: `--scope` when given, else the config's. */\n scope?: string[];\n /** Scenarios this run covers. Absent when the depth mounts nothing. */\n scenarios?: string[];\n /** Every scenario the config declares, for `n of m` when one was named. */\n declaredScenarios?: string[];\n}\n\n/**\n * What the numbers below are about, before there are any (`AS-CLI-007`).\n *\n * A report that opens with its counts asks the reader to hold them until the\n * qualifier arrives — and on a scoped run, or a run against a config they did\n * not choose, the unqualified number is simply the wrong one.\n */\nexport function runContextRows(context: RunContext): ReportRow[] {\n const rows: ReportRow[] = [\n { label: \"Config\", text: displayPath(context.configPath) },\n { label: \"Depth\", text: DEPTH_TEXT[context.depth] },\n {\n label: \"Scope\",\n text:\n context.scope && context.scope.length > 0\n ? `${context.scope.join(\" · \")} — every count below is relative to it`\n : \"whole surface — no component-type prefix filter\",\n },\n ];\n if (context.scenarios) {\n const declared = context.declaredScenarios ?? context.scenarios;\n const named = context.scenarios.length < declared.length;\n rows.push({\n label: \"Scenarios\",\n text:\n `${named ? `${context.scenarios.length} of ${declared.length}` : context.scenarios.length}` +\n ` — ${context.scenarios.join(\", \")}`,\n });\n }\n return rows;\n}\n\n/**\n * The static catalog's summary (`AS-COVER-001…003`). \"Upper bound\" is in the\n * text on purpose: a tsconfig's include globs are wider than what a bundle\n * reaches, so a capability in a component no route renders any more is counted\n * here. That is dead code — a different finding, not a false positive — and the\n * reader has to be told which number they are holding.\n */\nexport function catalogRows(\n inventory: CapabilityInventory,\n options: { domainCapabilities?: number; mounted?: boolean } = {},\n): ReportRow[] {\n const resolved = inventory.capabilities.filter((c) => c.resolution !== \"unresolved\");\n const unreadEntries = unresolved(inventory);\n const dynamicMetadata = resolved.filter((c) => c.resolution === \"partial\").length;\n const authored = authoredIds(inventory).size + (options.domainCapabilities ?? 0);\n\n return [\n {\n label: \"STATUS\",\n tone: unreadEntries.length > 0 ? \"warn\" : \"good\",\n text:\n unreadEntries.length > 0\n ? `INCOMPLETE — ${unreadEntries.length} unread capability identit${\n unreadEntries.length === 1 ? \"y\" : \"ies\"\n }`\n : \"COMPLETE — every capability identity resolved\",\n },\n {\n label: \"Capabilities\",\n text: `${authored} authored (upper bound) · ${resolved.length} resolved call site${\n resolved.length === 1 ? \"\" : \"s\"\n }`,\n },\n {\n label: \"Program\",\n text:\n `${inventory.filesAnalyzed} file${inventory.filesAnalyzed === 1 ? \"\" : \"s\"} analyzed` +\n (inventory.filesOutsideRoot > 0\n ? ` · ${inventory.filesOutsideRoot} agent-surface implementation file${\n inventory.filesOutsideRoot === 1 ? \"\" : \"s\"\n } excluded`\n : \"\"),\n },\n {\n label: \"Metadata\",\n text:\n `${dynamicMetadata} call site${dynamicMetadata === 1 ? \"\" : \"s\"} partially read` +\n (dynamicMetadata > 0 ? \" · identity remains resolved\" : \"\"),\n },\n {\n // Three different statements, and only one of them is a number. \"Nobody\n // looked\" and \"there is nothing to look at\" must not read alike (OQ-1).\n label: \"Domain\",\n ...(options.mounted && options.domainCapabilities === undefined\n ? { tone: \"warn\" as const }\n : {}),\n text:\n options.domainCapabilities !== undefined\n ? `${options.domainCapabilities} manifest capabilit${\n options.domainCapabilities === 1 ? \"y\" : \"ies\"\n }`\n : options.mounted\n ? \"no authoritative oRPC manifest configured — that plane has no denominator\"\n : \"not analyzed at static depth; full depth reads the oRPC manifest\",\n },\n ];\n}\n\n/**\n * The header a run opens with: what it was pointed at, and the catalog it read\n * before mounting anything.\n */\nexport function runHeaderBlocks(\n title: string,\n context: RunContext,\n inventory?: CapabilityInventory,\n domainCapabilities?: number,\n): ReportBlock[] {\n return [\n { title, rows: runContextRows(context) },\n ...(inventory\n ? [\n {\n title: \"STATIC CATALOG\",\n rows: catalogRows(inventory, {\n ...(domainCapabilities === undefined ? {} : { domainCapabilities }),\n ...(context.depth === \"static\" ? {} : { mounted: true }),\n }),\n },\n ]\n : []),\n ];\n}\n\n/** Per-scenario totals — the row a reader compares scenarios across. */\nexport interface ScenarioStats {\n scenario: string;\n route?: string;\n callable: number;\n disabled: number;\n hidden: number;\n rejected: number;\n /** Set when the scenario threw instead of mounting. */\n failed?: boolean;\n /** Why it threw, printed under its row rather than in a column. */\n failure?: string;\n /** `check` only: how the committed baseline compared. */\n baseline?: string;\n}\n\nexport function scenarioStats(result: CollectResult): ScenarioStats {\n const counts = { expose: 0, disable: 0, hide: 0 };\n for (const capability of result.explanation.capabilities) counts[capability.outcome] += 1;\n return {\n scenario: result.scenario,\n ...(result.snapshot.route?.path ? { route: result.snapshot.route.path } : {}),\n callable: counts.expose,\n disabled: counts.disable,\n hidden: counts.hide,\n rejected: result.rejections.length,\n };\n}\n\nconst NONE = \"—\";\n\n/** One row per scenario: the comparison a list of names cannot make. */\nexport function scenarioTable(\n stats: ScenarioStats[],\n options: { baselines?: boolean } = {},\n): { headers: string[]; rows: Array<{ cells: string[] }> } {\n const headers = [\"SCENARIO\", \"ROUTE\", \"CALLABLE\", \"DISABLED\", \"HIDDEN\", \"REJECTED\"];\n if (options.baselines) headers.push(\"BASELINE\");\n return {\n headers,\n rows: stats.map((entry) => ({\n // The baseline column already says `did not mount`, so the note carries\n // only what a reader cannot get anywhere else: why.\n ...(entry.failed\n ? {\n note: `${options.baselines ? \"\" : \"did not mount — \"}${\n entry.failure ?? \"the scenario threw during mount\"\n }`,\n }\n : {}),\n cells: [\n entry.scenario,\n entry.route ?? NONE,\n ...(entry.failed\n ? [NONE, NONE, NONE, NONE]\n : [\n String(entry.callable),\n String(entry.disabled),\n String(entry.hidden),\n entry.rejected > 0 ? String(entry.rejected) : NONE,\n ]),\n ...(options.baselines ? [entry.failed ? \"did not mount\" : (entry.baseline ?? NONE)] : []),\n ],\n })),\n };\n}\n\n/**\n * What every scenario together made of one capability.\n *\n * `unreached` answers \"did anything mount this\". This answers the question one\n * step in: *it mounted, and could any scenario actually call it?* A drawer\n * every scenario leaves closed registers its `close` action in every snapshot\n * and is callable in none of them — reached by the coverage join, and never\n * exercised. Neither half sees that alone.\n */\nexport interface CapabilityReach {\n capabilityId: string;\n /** The best outcome any scenario produced: expose beats disable beats hide. */\n best: \"expose\" | \"disable\" | \"hide\";\n effect?: string;\n flags: string[];\n /** Why it was not callable, from the scenario that came closest. */\n note?: string;\n scenarios: string[];\n}\n\nconst RANK = { hide: 0, disable: 1, expose: 2 } as const;\n\nexport function trackReach(\n reach: Map<string, CapabilityReach>,\n rows: CapabilityRow[],\n scenario: string,\n): void {\n for (const row of rows) {\n const current = reach.get(row.capabilityId);\n if (!current) {\n reach.set(row.capabilityId, {\n capabilityId: row.capabilityId,\n best: row.outcome,\n ...(row.effect ? { effect: row.effect } : {}),\n flags: row.flags,\n ...(row.reason ? { note: row.reason } : {}),\n scenarios: [scenario],\n });\n continue;\n }\n current.scenarios.push(scenario);\n // The effect is a property of the descriptor, so any scenario that carries\n // one carries the same one — but a policy-hidden row has no snapshot entry\n // to read it from, so the first scenario to see it wins.\n if (!current.effect && row.effect) current.effect = row.effect;\n if (current.flags.length === 0 && row.flags.length > 0) current.flags = row.flags;\n if (RANK[row.outcome] > RANK[current.best]) {\n current.best = row.outcome;\n if (row.reason) current.note = row.reason;\n else delete current.note;\n }\n }\n}\n\nexport function neverCallable(reach: Map<string, CapabilityReach>): CapabilityReach[] {\n return [...reach.values()]\n .filter((entry) => entry.best !== \"expose\")\n .sort((a, b) => a.capabilityId.localeCompare(b.capabilityId));\n}\n\nconst MUTATING = new Set([\"server-mutation\", \"external-side-effect\", \"destructive\"]);\n\ninterface Risk {\n present: number;\n destructive: number;\n mutating: number;\n confirmed: number;\n bound: number;\n}\n\n/**\n * What an agent could do here, as opposed to how much surface there is.\n *\n * Counted over everything the snapshot carries — `callable` *and*\n * `visible-disabled`. A disabled capability is disclosed to the agent and\n * becomes callable the moment the UI state it waits on arrives, so leaving it\n * out would report a surface with a destructive action on it as one without.\n * A hidden capability is genuinely absent: authority removed it, and counting\n * it here would report a policy working as a risk.\n */\nfunction riskOf(\n entries: Array<{ outcome: \"expose\" | \"disable\" | \"hide\"; effect?: string; flags: string[] }>,\n): Risk {\n const present = entries.filter((entry) => entry.outcome !== \"hide\");\n return {\n present: present.length,\n destructive: present.filter((entry) => entry.effect === \"destructive\").length,\n mutating: present.filter((entry) => entry.effect && MUTATING.has(entry.effect)).length,\n confirmed: present.filter((entry) =>\n entry.flags.some((flag) => flag.startsWith(\"confirmation:\")),\n ).length,\n bound: present.filter((entry) => entry.flags.some((flag) => flag.includes(\" bound\"))).length,\n };\n}\n\nfunction riskParts(risk: Risk): string[] {\n return [\n ...(risk.destructive > 0 ? [`${risk.destructive} destructive`] : []),\n ...(risk.mutating > risk.destructive ? [`${risk.mutating - risk.destructive} mutating`] : []),\n ...(risk.confirmed > 0 ? [`${risk.confirmed} confirmation-gated`] : []),\n ];\n}\n\n/**\n * The scenario header's risk clause. Empty when there is nothing to say, so a\n * read-only surface does not carry a row of zeroes to be read and dismissed.\n */\nexport function riskClause(rows: CapabilityRow[]): string {\n const parts = riskParts(riskOf(rows));\n return parts.join(\", \");\n}\n\n/** The same question over every scenario at once, for the closing summary. */\nfunction riskText(reach: Map<string, CapabilityReach>): string {\n const risk = riskOf([...reach.values()].map((entry) => ({ ...entry, outcome: entry.best })));\n const parts = riskParts(risk);\n if (risk.present === 0) {\n return \"nothing is on the surface at all — every capability was hidden by policy\";\n }\n if (parts.length === 0) {\n return (\n `nothing mutating or destructive is on the surface · ${risk.present} ` +\n `read-only or local-state capabilit${risk.present === 1 ? \"y\" : \"ies\"}`\n );\n }\n return [...parts, ...(risk.bound > 0 ? [`${risk.bound} with bound input`] : [])].join(\" · \");\n}\n\nexport interface SurfaceSummaryInput {\n depth: Depth;\n coverage?: CoverageReport;\n scenarios: ScenarioStats[];\n failures: number;\n reach: Map<string, CapabilityReach>;\n}\n\n/**\n * `inspect`'s closing block — the thing a reader who scrolled to the bottom\n * stops on. It states no PASS/FAIL: `inspect` reports findings and never gates\n * on them, and a status word beside a number would read as the exit code it is\n * not.\n */\nexport function surfaceSummaryRows(input: SurfaceSummaryInput): ReportRow[] {\n const rows: ReportRow[] = [];\n const coverage = input.coverage;\n\n if (coverage) {\n rows.push({\n label: \"Reach\",\n tone: coverage.unreached.length > 0 ? \"bad\" : \"good\",\n text:\n `${coverage.reached}/${coverage.authored} authored capabilit${\n coverage.authored === 1 ? \"y\" : \"ies\"\n } reached` +\n (coverage.unreached.length > 0 ? ` · ${coverage.unreached.length} unreached` : \"\") +\n (coverage.allowed.length > 0 ? ` · ${coverage.allowed.length} allowlisted` : \"\"),\n });\n }\n\n const mounted = input.reach.size;\n const dark = neverCallable(input.reach);\n if (mounted > 0) {\n const stuck = dark.filter((entry) => entry.best === \"disable\").length;\n const why = [\n ...(stuck > 0 ? [`${stuck} disabled`] : []),\n ...(dark.length > stuck ? [`${dark.length - stuck} hidden`] : []),\n ].join(\", \");\n rows.push({\n label: \"Callable\",\n tone: dark.length > 0 ? \"warn\" : \"good\",\n text:\n `${mounted - dark.length}/${mounted} mounted capabilit${\n mounted === 1 ? \"y is\" : \"ies are\"\n } callable in at least one scenario` +\n (dark.length > 0 ? ` · ${dark.length} never callable (${why})` : \"\"),\n });\n rows.push({ label: \"Risk\", text: riskText(input.reach) });\n }\n\n if (coverage) {\n if (coverage.domainReached.length > 0 || coverage.domainAuthoritative) {\n rows.push({\n label: \"Domain\",\n tone: coverage.unmanifestedDomain.length > 0 ? \"bad\" : \"good\",\n text:\n coverage.unmanifestedDomain.length > 0\n ? `${coverage.unmanifestedDomain.length} mounted capabilit${\n coverage.unmanifestedDomain.length === 1 ? \"y is\" : \"ies are\"\n } absent from the oRPC manifest`\n : `${coverage.domainReached.length} capabilit${\n coverage.domainReached.length === 1 ? \"y\" : \"ies\"\n } reached${\n coverage.domainAuthoritative\n ? \" against the authoritative oRPC manifest\"\n : \" and held apart — configure the manifest to cover that plane\"\n }`,\n });\n }\n rows.push({\n label: \"Catalog\",\n tone: coverage.unresolved.length > 0 ? \"warn\" : \"good\",\n text:\n coverage.unresolved.length > 0\n ? `${coverage.unresolved.length} unread call site${\n coverage.unresolved.length === 1 ? \"\" : \"s\"\n } — every count above is a floor`\n : `every call site read${\n coverage.allowedUnread.length > 0\n ? ` · ${coverage.allowedUnread.length} allowlisted`\n : \"\"\n }`,\n });\n }\n\n rows.push({\n label: \"Scenarios\",\n tone: input.failures > 0 ? \"bad\" : undefined,\n text:\n `${input.scenarios.filter((entry) => !entry.failed).length} mounted` +\n (input.failures > 0 ? ` · ${input.failures} did not mount` : \"\"),\n });\n\n rows.push({ label: \"Verdict\", tone: verdictTone(input), text: verdictText(input) });\n return rows;\n}\n\nfunction verdictTone(input: SurfaceSummaryInput): ReportTone {\n if (input.failures > 0) return \"bad\";\n if (!input.coverage) return \"warn\";\n const clean =\n input.coverage.unreached.length === 0 &&\n input.coverage.unresolved.length === 0 &&\n input.coverage.staleAllowlist.length === 0 &&\n input.coverage.staleUnreadAllowlist.length === 0 &&\n input.coverage.unmanifestedDomain.length === 0;\n return clean ? \"good\" : \"bad\";\n}\n\n/** The one sentence a reader takes away. Never a status word — see above. */\nfunction verdictText(input: SurfaceSummaryInput): string {\n if (input.failures > 0) {\n return \"a scenario did not mount, so no coverage verdict was computed at all\";\n }\n const coverage = input.coverage;\n if (!coverage) {\n return input.depth === \"runtime\"\n ? \"the source was not read at this depth — a statement about these scenarios only\"\n : \"no coverage verdict at this depth\";\n }\n if (coverage.unreached.length > 0) {\n return `${coverage.unreached.length} authored capabilit${\n coverage.unreached.length === 1 ? \"y is\" : \"ies are\"\n } reached by no scenario`;\n }\n if (coverage.unresolved.length > 0) {\n return \"every capability the catalog could read is reached — and the catalog has holes in it\";\n }\n return coverage.allowed.length > 0\n ? \"no new coverage gaps — the allowlist still holds the known ones\"\n : \"every authored capability is reached by a scenario\";\n}\n\n/**\n * The findings a coverage report carries. Shared by `inspect`, `snapshot` and\n * `check`, so the gate and the viewer cannot describe the same gap differently.\n */\nexport function coverageSections(\n report: CoverageReport,\n options: { compact?: boolean; detail?: boolean } = {},\n): FindingSection[] {\n const sections: FindingSection[] = [];\n\n if (report.unreached.length > 0) {\n sections.push({\n title: \"UNREACHED\",\n gloss: \"authored, and no scenario mounts it\",\n count: report.unreached.length,\n headers: [\"CAPABILITY\", \"ORIGIN\"],\n rows: report.unreached.map((entry) => ({\n cells: [entry.capabilityId, `${entry.origin.file}:${entry.origin.line}`],\n })),\n hint:\n \"add a scenario that mounts them, delete the dead component, or record the decision \" +\n `in ${displayPath(report.allowlistPath)}`,\n });\n }\n\n if (report.undeclared.length > 0) {\n if (!options.compact || options.detail) {\n sections.push({\n title: \"UNDECLARED\",\n gloss: \"present at runtime with no static origin — a dynamic registration, or a gap here\",\n count: report.undeclared.length,\n tone: \"notice\",\n lines: report.undeclared,\n });\n } else {\n sections.push({\n title: \"NOTICE\",\n gloss: `${report.undeclared.length} runtime capabilit${\n report.undeclared.length === 1 ? \"y has\" : \"ies have\"\n } no static origin; re-run with --detail to list them`,\n count: 0,\n tone: \"notice\",\n });\n }\n }\n\n if (report.unmanifestedDomain.length > 0) {\n sections.push({\n title: \"UNMANIFESTED DOMAIN\",\n gloss: \"mounted, but absent from the authoritative oRPC manifest\",\n count: report.unmanifestedDomain.length,\n lines: report.unmanifestedDomain,\n hint: \"add them to the manifest, or stop mounting a router the manifest does not describe\",\n });\n }\n\n if (report.staleAllowlist.length > 0) {\n sections.push({\n title: \"STALE ALLOWLIST\",\n gloss: \"a scenario reaches these now, so delete them before the list rots\",\n count: report.staleAllowlist.length,\n lines: report.staleAllowlist,\n hint: `delete these keys from ${displayPath(report.allowlistPath)}`,\n });\n }\n\n if (report.staleUnreadAllowlist.length > 0) {\n sections.push({\n title: \"STALE UNREAD ALLOWLIST\",\n gloss: \"the extractor reads these now, so delete them before the list rots\",\n count: report.staleUnreadAllowlist.length,\n lines: report.staleUnreadAllowlist,\n hint: `delete these keys from ${displayPath(report.unreadAllowlistPath)}`,\n });\n }\n\n if (report.unresolved.length > 0) {\n sections.push(unreadSection(report.unresolved, report.unreadAllowlistPath));\n }\n\n return sections;\n}\n\n/**\n * Call sites the extractor could not read. Reported with file and line, never\n * dropped: an inventory that silently omitted what it failed to parse would\n * understate the denominator, and every number built on it would claim a\n * completeness it never had.\n *\n * The allowlist key is spelled out because it is `file#reason#site` and the\n * site is a hash — not the line the reader is looking at — so leaving them to\n * infer it guarantees a wrong guess and an entry that never matches.\n */\nexport function unreadSection(\n entries: Array<Parameters<typeof unreadKey>[0]>,\n allowlistPath?: string,\n): FindingSection {\n return {\n title: \"UNREAD CALL SITES\",\n gloss: \"the catalog is incomplete, so every count above is a floor\",\n count: entries.length,\n lines: entries.flatMap((entry) => [\n `${entry.origin.file}:${entry.origin.line}`,\n ` ${entry.note ?? \"the extractor could not read this call site\"}`,\n ` allowlist key: ${unreadKey(entry)}`,\n ]),\n hint: allowlistPath\n ? `make the call site readable, or accept each key in ${displayPath(allowlistPath)}`\n : \"make the call site readable, or accept each key in .agent-surface/unresolved-allow.json\",\n };\n}\n\n/**\n * Mounted, and callable in no scenario. A finding `inspect` reports and the\n * gate does not: unlike an unreached capability, this one *is* covered by a\n * scenario — what is missing is a scenario that puts the app in the state, or\n * under the authority, where it can be used. That is a judgement about the\n * scenarios rather than a defect in the surface.\n *\n * Worth printing only when more than one scenario ran. Over a single scenario\n * \"never callable\" is the same statement its own table already made, one line\n * per capability, and a report that says everything twice is read once.\n */\nexport function neverCallableSection(entries: CapabilityReach[]): FindingSection {\n const stuck = entries.filter((entry) => entry.best === \"disable\").length;\n const hidden = entries.length - stuck;\n return {\n title: \"NEVER CALLABLE\",\n gloss: \"every scenario mounted these, and none of them could call one\",\n count: entries.length,\n tone: \"notice\",\n headers: [\"CAPABILITY\", \"BEST STATE\", \"WHY\"],\n rows: entries.map((entry) => ({\n cells: [\n entry.capabilityId,\n entry.best === \"disable\" ? \"disabled\" : \"hidden\",\n entry.best === \"disable\"\n ? (entry.note ?? \"the UI reported it unavailable in every scenario\")\n : \"a policy hid it in every scenario\",\n ],\n })),\n hint: [\n ...(stuck > 0\n ? [\n \"add a scenario that reaches the state these need — an open drawer, a filled list, \" +\n \"a selected row\",\n ]\n : []),\n ...(hidden > 0\n ? [\n `add a scenario whose consumer carries the authority ${\n stuck > 0 ? \"the hidden ones are\" : \"these are\"\n } waiting for`,\n ]\n : []),\n ].join(\"; \"),\n };\n}\n"],"mappings":"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","names":[]}
|