@crouton-kit/capture 1.3.7 → 1.3.9
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/bin/capture +32786 -9989
- package/package.json +9 -3
- package/src/capture.ts +86 -163
- package/src/cdp/a11y.ts +113 -14
- package/src/cdp/args.ts +300 -116
- package/src/cdp/bridge/protocol.ts +187 -1
- package/src/cdp/bridge/server.ts +211 -84
- package/src/cdp/bridge/spawn.ts +110 -1
- package/src/cdp/client.ts +13 -3
- package/src/cdp/commands/bridge-serve.ts +35 -4
- package/src/cdp/commands/cdp.ts +266 -69
- package/src/cdp/commands/gate-guard.ts +43 -0
- package/src/cdp/commands/lib.ts +339 -213
- package/src/cdp/commands/measure/census.ts +87 -0
- package/src/cdp/commands/measure/check.ts +109 -0
- package/src/cdp/commands/measure/diff.ts +120 -0
- package/src/cdp/commands/measure/explain.ts +133 -0
- package/src/cdp/commands/measure/index.ts +106 -0
- package/src/cdp/commands/measure/map-ax.ts +52 -0
- package/src/cdp/commands/measure/map-focus.ts +52 -0
- package/src/cdp/commands/measure/map-layers.ts +59 -0
- package/src/cdp/commands/measure/map-scroll.ts +94 -0
- package/src/cdp/commands/measure/snap.ts +416 -0
- package/src/cdp/commands/measure/sweep.ts +227 -0
- package/src/cdp/commands/motion/index.ts +61 -0
- package/src/cdp/commands/motion/jank.ts +132 -0
- package/src/cdp/commands/motion/mask.ts +92 -0
- package/src/cdp/commands/motion/rec.ts +534 -0
- package/src/cdp/commands/motion/response.ts +76 -0
- package/src/cdp/commands/motion/timeline.ts +152 -0
- package/src/cdp/commands/page/click.ts +194 -0
- package/src/cdp/commands/page/elements.ts +154 -0
- package/src/cdp/commands/page/exec.ts +317 -0
- package/src/cdp/commands/page/index.ts +72 -0
- package/src/cdp/commands/page/navigate.ts +330 -0
- package/src/cdp/commands/page/scroll.ts +107 -0
- package/src/cdp/commands/page/shot.ts +208 -0
- package/src/cdp/commands/page/type.ts +104 -0
- package/src/cdp/commands/tab/index.ts +59 -0
- package/src/cdp/commands/tab/list.ts +167 -0
- package/src/cdp/commands/tab/network.ts +162 -0
- package/src/cdp/commands/tab/open.ts +90 -0
- package/src/cdp/commands/tab/reset.ts +160 -0
- package/src/cdp/connection.ts +368 -37
- package/src/cdp/coordinates.ts +158 -0
- package/src/cdp/detect.ts +42 -13
- package/src/cdp/dispatch.ts +76 -26
- package/src/cdp/domains.ts +75 -0
- package/src/cdp/har-recorder.ts +648 -115
- package/src/cdp/leaf-grammar.ts +99 -0
- package/src/cdp/measure/census.ts +205 -0
- package/src/cdp/measure/check.ts +318 -0
- package/src/cdp/measure/collectors/animation.ts +385 -0
- package/src/cdp/measure/collectors/ax.ts +278 -0
- package/src/cdp/measure/collectors/focus.ts +1041 -0
- package/src/cdp/measure/collectors/forms.ts +905 -0
- package/src/cdp/measure/collectors/geometry.ts +1038 -0
- package/src/cdp/measure/collectors/hittest.ts +835 -0
- package/src/cdp/measure/collectors/layers.ts +697 -0
- package/src/cdp/measure/collectors/media.ts +522 -0
- package/src/cdp/measure/collectors/pixels.ts +1584 -0
- package/src/cdp/measure/collectors/queries.ts +464 -0
- package/src/cdp/measure/collectors/scroll.ts +599 -0
- package/src/cdp/measure/collectors/states.ts +992 -0
- package/src/cdp/measure/collectors/style-provenance.ts +643 -0
- package/src/cdp/measure/collectors/styles.ts +355 -0
- package/src/cdp/measure/collectors/text.ts +713 -0
- package/src/cdp/measure/diff.ts +470 -0
- package/src/cdp/measure/explain.ts +498 -0
- package/src/cdp/measure/map-ax.ts +633 -0
- package/src/cdp/measure/map-focus.ts +188 -0
- package/src/cdp/measure/map-layers.ts +177 -0
- package/src/cdp/measure/map-scroll.ts +317 -0
- package/src/cdp/measure/redaction.ts +51 -0
- package/src/cdp/measure/settle.ts +1051 -0
- package/src/cdp/measure/snapshot.ts +390 -0
- package/src/cdp/measure/sweep.ts +330 -0
- package/src/cdp/measure/types.ts +220 -0
- package/src/cdp/measure/v2/collectors.ts +19 -0
- package/src/cdp/measure/v2/orchestrator.ts +46 -0
- package/src/cdp/measure/v2/snap-selection.ts +33 -0
- package/src/cdp/measure/v2/target-lock.ts +15 -0
- package/src/cdp/measure/v2/target.ts +16 -0
- package/src/cdp/motion/jank.ts +433 -0
- package/src/cdp/motion/mask.ts +421 -0
- package/src/cdp/motion/recorder.ts +764 -0
- package/src/cdp/motion/response.ts +356 -0
- package/src/cdp/motion/timeline.ts +215 -0
- package/src/cdp/record.ts +5 -212
- package/src/cdp/recorder-bridge.ts +1894 -0
- package/src/cdp/recorder-client.ts +326 -0
- package/src/cdp/scope-lock.ts +73 -0
- package/src/cdp/screenshot.ts +199 -66
- package/src/cdp/source-map.ts +309 -0
- package/src/cdp/targets.ts +21 -1
- package/src/cdp/timing.ts +87 -0
- package/src/cdp/types.ts +87 -6
- package/src/cdp/viewport.ts +21 -0
- package/src/cdp.ts +12 -58
- package/src/command-help.ts +29 -0
- package/src/command-resolution.ts +22 -0
- package/src/command-walker.ts +35 -0
- package/src/contracts/a11y.ts +33 -0
- package/src/contracts/cursor.ts +35 -0
- package/src/contracts/index.ts +15 -0
- package/src/contracts/motion.ts +19 -0
- package/src/contracts/neutral.ts +56 -0
- package/src/contracts/primitives.ts +205 -0
- package/src/contracts/release.ts +17 -0
- package/src/contracts/results.ts +208 -0
- package/src/contracts/routes.ts +140 -0
- package/src/contracts/snapshot.ts +92 -0
- package/src/cursor/index.ts +13 -0
- package/src/cursor/service.ts +310 -0
- package/src/errors.ts +71 -0
- package/src/har-manager.ts +992 -41
- package/src/interact.ts +410 -98
- package/src/output/artifact-lifecycle.ts +371 -0
- package/src/output/artifact.ts +526 -0
- package/src/output/diff.ts +111 -0
- package/src/output/exact-raw.ts +114 -0
- package/src/output/render.ts +987 -0
- package/src/output/selector.ts +185 -0
- package/src/output/structured.ts +211 -0
- package/src/registry.ts +208 -0
- package/src/session/artifacts.ts +481 -0
- package/src/session/commands.ts +1237 -368
- package/src/session/coordinator.ts +251 -0
- package/src/session/har-filter.ts +57 -0
- package/src/session/log-tailer.ts +653 -0
- package/src/session-context.ts +302 -34
- package/src/vault/bundle.ts +32 -17
- package/src/cdp/commands/exec.ts +0 -105
- package/src/cdp/commands/har.ts +0 -128
- package/src/cdp/commands/tabs.ts +0 -183
- package/src/cdp/commands/traffic.ts +0 -121
- package/src/cdp/commands/ui.ts +0 -172
- package/src/cdp/execute.ts +0 -113
- package/src/cdp/har-output.ts +0 -47
- package/src/cdp/usage.ts +0 -77
- package/src/tab-session.ts +0 -91
package/src/cdp/commands/lib.ts
CHANGED
|
@@ -4,15 +4,30 @@
|
|
|
4
4
|
* Pure local reads, NO CDP connection. Mirrors `nl lib`
|
|
5
5
|
* (northlight apps/core/src/cli/families/lib/lib-cli.provider.ts): same search
|
|
6
6
|
* scoring and the discover→schema→run loop, sourced from on-demand doc-gen
|
|
7
|
-
* (`../../vault/docs.ts`) + sha cache. Output contract
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* (`../../vault/docs.ts`) + sha cache. Output contract: every result is a
|
|
8
|
+
* render.ts block — `<libs>` selection lists for `list`/`search`, a `<lib>`
|
|
9
|
+
* block for `show`/`read` — with `--json` mirroring the same result. Every
|
|
10
|
+
* block naming a lib carries `src` = the absolute path to that lib's `.ts`
|
|
11
|
+
* source, the agent's full-fidelity pointer; `lib read` is the schema-level
|
|
12
|
+
* full-fidelity leaf. Dev-checkout only: with `vault/` source missing
|
|
13
|
+
* (published package) every leaf throws a typed `dev_only` failure, rendered
|
|
14
|
+
* at the root boundary as `<error code="dev_only">`, exit 1. Every failure
|
|
15
|
+
* here throws typed (`CaptureError`) — the `src/capture.ts` root boundary is
|
|
16
|
+
* the one renderer and exit-code authority.
|
|
11
17
|
*/
|
|
12
18
|
|
|
13
19
|
import * as path from "path";
|
|
20
|
+
import { captureError, invalidInput } from "../../errors.js";
|
|
14
21
|
import { type ParsedArgs } from "../types.js";
|
|
15
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
emitResult,
|
|
24
|
+
fact,
|
|
25
|
+
text,
|
|
26
|
+
lineList,
|
|
27
|
+
capped,
|
|
28
|
+
type FactLine,
|
|
29
|
+
} from "../../output/render.js";
|
|
30
|
+
import { vaultLibsDir, listLibs, DEV_ONLY_MSG } from "../../vault/paths.js";
|
|
16
31
|
import {
|
|
17
32
|
getDoc,
|
|
18
33
|
listDocs,
|
|
@@ -20,15 +35,50 @@ import {
|
|
|
20
35
|
type LibraryDoc,
|
|
21
36
|
} from "../../vault/docs.js";
|
|
22
37
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
38
|
+
/** Root-help representation of this leaf, assembled by `src/capture.ts`. */
|
|
39
|
+
export const COMMAND_BLOCK = `<command name="lib">
|
|
40
|
+
vault-lib introspection (dev checkout only) — discover the forked vault libs and their function schemas, then run them in the tab
|
|
41
|
+
use when scripting against a bundled service lib: find the function, read its schema, invoke it via page exec
|
|
42
|
+
list · search · show · read — \`capture lib -h\`
|
|
43
|
+
</command>`;
|
|
44
|
+
|
|
45
|
+
const LIB_USAGE = `capture lib — vault-lib introspection (dev checkout only): discover the
|
|
46
|
+
forked vault libs and their function schemas, then run them in the tab via
|
|
47
|
+
\`capture page exec\`.
|
|
48
|
+
|
|
49
|
+
Pure local reads — no CDP connection. Requires a capture checkout with
|
|
50
|
+
vault/ source + esbuild; the published package answers every leaf with a
|
|
51
|
+
structured dev_only error.
|
|
52
|
+
|
|
53
|
+
<subcommand name="list" args="" whenToUse="list every lib — name, function count, one-line summary"/>
|
|
54
|
+
<subcommand name="search" args="<query> [--limit <n>]" whenToUse="rank functions across all libs against a query (default limit 20, max 500; multi-word queries require every token to match)"/>
|
|
55
|
+
<subcommand name="show" args="<name>" whenToUse="one lib's function summaries — names + one-line descriptions, no schemas"/>
|
|
56
|
+
<subcommand name="read" args="<name> [fn…]" whenToUse="full input/output JSON Schemas for named functions — the full-fidelity step before exec"/>
|
|
57
|
+
|
|
58
|
+
capture lib <leaf> -h Per-leaf usage`;
|
|
59
|
+
|
|
60
|
+
const LEAF_USAGE: Record<string, string> = {
|
|
61
|
+
list: `capture lib list — list every vault lib: name, function count, one-line summary.
|
|
62
|
+
|
|
63
|
+
Input: none.
|
|
64
|
+
Output: <libs count=…> selection block, one row per lib (name — summary — function count).
|
|
65
|
+
Effects: local reads only (doc cache maintained under vault/.cache/docs); no CDP connection. Dev checkout required.`,
|
|
66
|
+
search: `capture lib search <query> [--limit <n>] — rank functions across all libs against a query.
|
|
67
|
+
|
|
68
|
+
Input: <query> (required; multi-word queries require every token to contribute a match); --limit <n> caps rows shown (default 20, max 500).
|
|
69
|
+
Output: <libs query=… hits=… shown=…> selection block, one row per hit (service.function — match kind — summary), best score first.
|
|
70
|
+
Effects: local reads only; no CDP connection. Dev checkout required.`,
|
|
71
|
+
show: `capture lib show <name> — one lib's function summaries, no schemas.
|
|
72
|
+
|
|
73
|
+
Input: <name> (required; exact lib name or unambiguous case-insensitive prefix).
|
|
74
|
+
Output: <lib name=… functions=… src=…> block — description, notes/login when present, one row per function (name — summary).
|
|
75
|
+
Effects: local reads only; no CDP connection. Dev checkout required.`,
|
|
76
|
+
read: `capture lib read <name> [fn…] — full input/output JSON Schemas for named functions.
|
|
77
|
+
|
|
78
|
+
Input: <name> (required; exact lib name or unambiguous case-insensitive prefix); [fn…] function names — with none given, falls back to the function summary list.
|
|
79
|
+
Output: <lib name=… src=…> block — per named function: description, notes, input and output JSON Schema (capped inline; the src path is the full-fidelity pointer).
|
|
80
|
+
Effects: local reads only; no CDP connection. Dev checkout required.`,
|
|
81
|
+
};
|
|
32
82
|
|
|
33
83
|
// ─── scoring (ported verbatim from lib-cli.provider.ts:71-152) ───────────────
|
|
34
84
|
|
|
@@ -120,237 +170,313 @@ function scoreHit(
|
|
|
120
170
|
const svcName = (doc: LibraryDoc): string =>
|
|
121
171
|
doc.library.replace(/^@vallum\//, "");
|
|
122
172
|
|
|
173
|
+
/** Plain-string truncation for thrown messages (the `capped()` render marker
|
|
174
|
+
* only works inside `fact` templates, not in a `CaptureError` message). */
|
|
175
|
+
const cap = (value: string, maxLength: number): string =>
|
|
176
|
+
value.length > maxLength ? `${value.slice(0, maxLength - 1)}…` : value;
|
|
177
|
+
|
|
123
178
|
const srcPathFor = (name: string): string =>
|
|
124
179
|
path.join(vaultLibsDir(), name, "index.ts");
|
|
125
180
|
|
|
126
181
|
/** Resolve a user-supplied name against a candidate set: exact, then ci-prefix. */
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
182
|
+
type NameResolution =
|
|
183
|
+
| { name: string }
|
|
184
|
+
| { ambiguous: string[] }
|
|
185
|
+
| { unknown: true };
|
|
186
|
+
|
|
187
|
+
function resolveName(query: string, names: string[]): NameResolution {
|
|
131
188
|
if (names.includes(query)) return { name: query };
|
|
132
189
|
const lower = query.toLowerCase();
|
|
133
190
|
const prefix = names.filter((n) => n.toLowerCase().startsWith(lower));
|
|
134
191
|
if (prefix.length === 1) return { name: prefix[0] };
|
|
135
|
-
if (prefix.length > 1) {
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
return { error: `Unknown lib "${query}". Available: ${names.join(", ")}` };
|
|
192
|
+
if (prefix.length > 1) return { ambiguous: prefix };
|
|
193
|
+
return { unknown: true };
|
|
139
194
|
}
|
|
140
195
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
196
|
+
/** Resolve a lib name or throw typed (unknown/ambiguous). */
|
|
197
|
+
function resolveNameOrFail(command: string, query: string): string {
|
|
198
|
+
const names = listLibs();
|
|
199
|
+
const r = resolveName(query, names);
|
|
200
|
+
if ("ambiguous" in r) {
|
|
201
|
+
throw invalidInput(
|
|
202
|
+
`${command} received: lib name \`${query}\` — matches ${r.ambiguous.join(", ")}; expected exactly one lib. Re-run with the full lib name.`,
|
|
203
|
+
"ambiguous_lib",
|
|
204
|
+
);
|
|
150
205
|
}
|
|
206
|
+
if ("unknown" in r) {
|
|
207
|
+
throw invalidInput(
|
|
208
|
+
`${command} received: unknown lib \`${query}\`; available: ${cap(names.join(", "), 1600)}. Run \`capture lib list\` for every lib with its summary.`,
|
|
209
|
+
"unknown_lib",
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
return r.name;
|
|
213
|
+
}
|
|
151
214
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
});
|
|
166
|
-
console.log(JSON.stringify(rows, null, 2));
|
|
167
|
-
console.error(
|
|
168
|
-
`\n${rows.length} libs. Next: capture lib show <name> · capture lib read <name> <fn>`,
|
|
215
|
+
/** `getDoc` or throw typed. `DEV_ONLY_MSG` rethrows to the shared dev-only
|
|
216
|
+
* handler in `cmdLib`; any other build failure is a typed doc_unavailable
|
|
217
|
+
* failure. */
|
|
218
|
+
async function getDocOrFail(command: string, name: string): Promise<LibraryDoc> {
|
|
219
|
+
try {
|
|
220
|
+
return await getDoc(name);
|
|
221
|
+
} catch (e) {
|
|
222
|
+
if (e instanceof Error && e.message === DEV_ONLY_MSG) throw e;
|
|
223
|
+
throw captureError(
|
|
224
|
+
"world",
|
|
225
|
+
"doc_unavailable",
|
|
226
|
+
`${command}: doc generation for lib \`${name}\` failed: ${(e as Error).message}`,
|
|
227
|
+
e,
|
|
169
228
|
);
|
|
170
|
-
return;
|
|
171
229
|
}
|
|
230
|
+
}
|
|
172
231
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
232
|
+
// ─── subcommands ─────────────────────────────────────────────────────────────
|
|
233
|
+
|
|
234
|
+
async function libList(parsed: ParsedArgs): Promise<void> {
|
|
235
|
+
const docs = await listDocs();
|
|
236
|
+
const rows = docs.map((d) => {
|
|
237
|
+
const name = svcName(d);
|
|
238
|
+
return fact`${name} — ${capped(d.description ?? "", 160)} (${d.functions.length} functions)`;
|
|
239
|
+
});
|
|
240
|
+
emitResult(
|
|
241
|
+
{
|
|
242
|
+
tag: "libs",
|
|
243
|
+
attrs: { count: docs.length },
|
|
244
|
+
summary: fact`${docs.length} vault libs.`,
|
|
245
|
+
sections: rows.length > 0 ? [lineList(rows)] : undefined,
|
|
246
|
+
followUp: text`\`capture lib show <name>\` lists one lib's functions; \`capture lib read <name> <fn…>\` loads full schemas.`,
|
|
247
|
+
},
|
|
248
|
+
{ json: parsed.json },
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async function libSearch(parsed: ParsedArgs): Promise<void> {
|
|
253
|
+
const query = parsed.positional[1];
|
|
254
|
+
if (!query) {
|
|
255
|
+
throw invalidInput(
|
|
256
|
+
"lib search received: no query; expected: capture lib search <query> [--limit <n>].",
|
|
183
257
|
);
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
258
|
+
}
|
|
259
|
+
const limit = Math.min(
|
|
260
|
+
typeof parsed.limit === "number" && parsed.limit > 0 ? parsed.limit : 20,
|
|
261
|
+
500,
|
|
262
|
+
);
|
|
263
|
+
const docs = await listDocs();
|
|
264
|
+
const hits: Array<{
|
|
265
|
+
service: string;
|
|
266
|
+
fn: string;
|
|
267
|
+
match: string;
|
|
268
|
+
score: number;
|
|
269
|
+
description: string;
|
|
270
|
+
}> = [];
|
|
271
|
+
for (const d of docs) {
|
|
272
|
+
const service = svcName(d);
|
|
273
|
+
for (const fn of d.functions) {
|
|
274
|
+
const { score, match } = scoreHit(
|
|
275
|
+
query,
|
|
276
|
+
service,
|
|
277
|
+
fn.name,
|
|
278
|
+
fn.description ?? "",
|
|
279
|
+
d.description ?? "",
|
|
280
|
+
);
|
|
281
|
+
if (score > 0) {
|
|
282
|
+
hits.push({
|
|
198
283
|
service,
|
|
199
|
-
fn.name,
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
hits.push({
|
|
205
|
-
service,
|
|
206
|
-
function: fn.name,
|
|
207
|
-
match,
|
|
208
|
-
score,
|
|
209
|
-
description: fn.description,
|
|
210
|
-
srcPath: srcPathFor(service),
|
|
211
|
-
});
|
|
212
|
-
}
|
|
284
|
+
fn: fn.name,
|
|
285
|
+
match,
|
|
286
|
+
score,
|
|
287
|
+
description: fn.description ?? "",
|
|
288
|
+
});
|
|
213
289
|
}
|
|
214
290
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
291
|
+
}
|
|
292
|
+
hits.sort((a, b) => b.score - a.score);
|
|
293
|
+
const top = hits.slice(0, limit);
|
|
294
|
+
const rows = top.map(
|
|
295
|
+
(h) =>
|
|
296
|
+
fact`${h.service}.${h.fn} — ${h.match} — ${capped(h.description, 160)}`,
|
|
297
|
+
);
|
|
298
|
+
emitResult(
|
|
299
|
+
{
|
|
300
|
+
tag: "libs",
|
|
301
|
+
attrs: { query, hits: hits.length, shown: top.length },
|
|
302
|
+
summary: fact`${hits.length} functions matched; showing ${top.length}, best score first.`,
|
|
303
|
+
sections: rows.length > 0 ? [lineList(rows)] : undefined,
|
|
304
|
+
followUp: text`\`capture lib read <service> <fn>\` loads the full input/output schemas.`,
|
|
305
|
+
},
|
|
306
|
+
{ json: parsed.json },
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/** The show-style summary block shared by `show` and fn-less `read`. */
|
|
311
|
+
function emitLibSummary(
|
|
312
|
+
parsed: ParsedArgs,
|
|
313
|
+
service: string,
|
|
314
|
+
doc: LibraryDoc,
|
|
315
|
+
followUp: FactLine,
|
|
316
|
+
): void {
|
|
317
|
+
const sections: FactLine[] = [];
|
|
318
|
+
if (doc.loginUrl) sections.push(fact`login: ${doc.loginUrl}`);
|
|
319
|
+
if (doc.notes) sections.push(fact`notes: ${capped(doc.notes, 400)}`);
|
|
320
|
+
if (doc.functions.length > 0) {
|
|
321
|
+
sections.push(
|
|
322
|
+
lineList(
|
|
323
|
+
doc.functions.map(
|
|
324
|
+
(f) => fact`${f.name} — ${capped(f.description ?? "", 160)}`,
|
|
325
|
+
),
|
|
326
|
+
),
|
|
221
327
|
);
|
|
222
|
-
return;
|
|
223
328
|
}
|
|
329
|
+
emitResult(
|
|
330
|
+
{
|
|
331
|
+
tag: "lib",
|
|
332
|
+
attrs: {
|
|
333
|
+
name: service,
|
|
334
|
+
functions: doc.functions.length,
|
|
335
|
+
src: srcPathFor(service),
|
|
336
|
+
},
|
|
337
|
+
summary: fact`${capped(doc.description ?? "", 300)}`,
|
|
338
|
+
sections,
|
|
339
|
+
followUp,
|
|
340
|
+
},
|
|
341
|
+
{ json: parsed.json },
|
|
342
|
+
);
|
|
343
|
+
}
|
|
224
344
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
345
|
+
async function libShow(parsed: ParsedArgs): Promise<void> {
|
|
346
|
+
const name = parsed.positional[1];
|
|
347
|
+
if (!name) {
|
|
348
|
+
throw invalidInput(
|
|
349
|
+
"lib show received: no lib name; expected: capture lib show <name>.",
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
// Resolve + build ONLY the named lib (design §3.1: show is single-lib, not
|
|
353
|
+
// an all-lib bundle). Mirrors the read path; adds show's visibility filter
|
|
354
|
+
// (a present-but-non-visible lib is treated as unknown).
|
|
355
|
+
const resolved = resolveNameOrFail("lib show", name);
|
|
356
|
+
const doc = await getDocOrFail("lib show", resolved);
|
|
357
|
+
if (!isAgentVisible(doc)) {
|
|
358
|
+
throw invalidInput(
|
|
359
|
+
`lib show received: unknown lib \`${name}\`; available: ${cap(listLibs().join(", "), 1600)}. Run \`capture lib list\` for every lib with its summary.`,
|
|
360
|
+
"unknown_lib",
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
emitLibSummary(
|
|
364
|
+
parsed,
|
|
365
|
+
resolved,
|
|
366
|
+
doc,
|
|
367
|
+
fact`\`capture lib read ${resolved} <fn>\` loads full input/output JSON Schemas.`,
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
async function libRead(parsed: ParsedArgs): Promise<void> {
|
|
372
|
+
const name = parsed.positional[1];
|
|
373
|
+
if (!name) {
|
|
374
|
+
throw invalidInput(
|
|
375
|
+
"lib read received: no lib name; expected: capture lib read <name> [fn…].",
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
// `read` may read ANY present lib (no visibility filter).
|
|
379
|
+
const resolved = resolveNameOrFail("lib read", name);
|
|
380
|
+
const doc = await getDocOrFail("lib read", resolved);
|
|
381
|
+
const service = svcName(doc);
|
|
382
|
+
const fns = parsed.positional.slice(2);
|
|
383
|
+
|
|
384
|
+
// No function names → summary fallback (show-style).
|
|
385
|
+
if (fns.length === 0) {
|
|
386
|
+
emitLibSummary(
|
|
387
|
+
parsed,
|
|
255
388
|
service,
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
...(doc.notes ? { notes: doc.notes } : {}),
|
|
259
|
-
srcPath: srcPathFor(service),
|
|
260
|
-
functions: doc.functions.map((f) => ({
|
|
261
|
-
name: f.name,
|
|
262
|
-
description: f.description,
|
|
263
|
-
})),
|
|
264
|
-
};
|
|
265
|
-
console.log(JSON.stringify(out, null, 2));
|
|
266
|
-
console.error(
|
|
267
|
-
`\nSchemas required before exec — capture lib read ${service} <fn>`,
|
|
389
|
+
doc,
|
|
390
|
+
fact`Name functions to load schemas: \`capture lib read ${service} <fn> [fn…]\`.`,
|
|
268
391
|
);
|
|
269
392
|
return;
|
|
270
393
|
}
|
|
271
394
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
const r = resolveName(name, listLibs());
|
|
281
|
-
if ("error" in r) {
|
|
282
|
-
console.error(r.error);
|
|
283
|
-
process.exit(1);
|
|
284
|
-
}
|
|
285
|
-
let doc: LibraryDoc;
|
|
286
|
-
try {
|
|
287
|
-
doc = await getDoc(r.name);
|
|
288
|
-
} catch (e) {
|
|
289
|
-
console.error((e as Error).message);
|
|
290
|
-
process.exit(1);
|
|
291
|
-
}
|
|
292
|
-
const service = svcName(doc);
|
|
293
|
-
const fns = parsed.positional.slice(2);
|
|
395
|
+
const byName = new Map(doc.functions.map((f) => [f.name, f]));
|
|
396
|
+
const found: typeof doc.functions = [];
|
|
397
|
+
const missing: string[] = [];
|
|
398
|
+
for (const op of fns) {
|
|
399
|
+
const fn = byName.get(op);
|
|
400
|
+
if (fn) found.push(fn);
|
|
401
|
+
else missing.push(op);
|
|
402
|
+
}
|
|
294
403
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
description: f.description,
|
|
305
|
-
})),
|
|
306
|
-
};
|
|
307
|
-
console.log(JSON.stringify(out, null, 2));
|
|
308
|
-
console.error(
|
|
309
|
-
`\nName functions to load schemas: capture lib read ${service} <fn> [fn…]`,
|
|
310
|
-
);
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
404
|
+
if (found.length === 0) {
|
|
405
|
+
throw invalidInput(
|
|
406
|
+
`lib read received: ${missing.join(", ")} — not in ${service}; available: ${cap(
|
|
407
|
+
doc.functions.map((f) => f.name).join(", "),
|
|
408
|
+
1600,
|
|
409
|
+
)}. \`capture lib show ${service}\` lists every function with its summary.`,
|
|
410
|
+
"unknown_function",
|
|
411
|
+
);
|
|
412
|
+
}
|
|
313
413
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
414
|
+
const sections: FactLine[] = found.map((f) =>
|
|
415
|
+
lineList([
|
|
416
|
+
fact`${f.name} — ${capped(f.description ?? "", 200)}`,
|
|
417
|
+
...(f.notes ? [fact`notes: ${capped(f.notes, 300)}`] : []),
|
|
418
|
+
fact`input: ${capped(JSON.stringify(f.input), 2000)}`,
|
|
419
|
+
fact`output: ${capped(JSON.stringify(f.output), 2000)}`,
|
|
420
|
+
]),
|
|
421
|
+
);
|
|
422
|
+
if (missing.length > 0) {
|
|
423
|
+
sections.push(fact`not in ${service}: ${missing.join(", ")}`);
|
|
424
|
+
}
|
|
425
|
+
const firstFn = found[0].name;
|
|
426
|
+
emitResult(
|
|
427
|
+
{
|
|
428
|
+
tag: "lib",
|
|
429
|
+
attrs: { name: service, src: srcPathFor(service) },
|
|
430
|
+
summary: fact`${found.length} of ${doc.functions.length} functions, full schemas; full source at the src path.`,
|
|
431
|
+
sections,
|
|
432
|
+
followUp: fact`Run it in the tab: capture page exec "import {${firstFn}} from 'libs/${service}'; return await ${firstFn}({…})".`,
|
|
433
|
+
},
|
|
434
|
+
{ json: parsed.json },
|
|
435
|
+
);
|
|
436
|
+
}
|
|
322
437
|
|
|
323
|
-
|
|
324
|
-
const available = doc.functions.map((f) => f.name).join(", ");
|
|
325
|
-
const label =
|
|
326
|
-
missing.length > 1
|
|
327
|
-
? `Functions "${missing.join('", "')}"`
|
|
328
|
-
: `Function "${missing[0]}"`;
|
|
329
|
-
console.error(`${label} not in ${service}. Available: ${available}`);
|
|
330
|
-
process.exit(1);
|
|
331
|
-
}
|
|
438
|
+
// ─── command ─────────────────────────────────────────────────────────────────
|
|
332
439
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
})),
|
|
343
|
-
...(missing.length > 0 ? { missing } : {}),
|
|
344
|
-
};
|
|
345
|
-
console.log(JSON.stringify(out, null, 2));
|
|
346
|
-
const firstFn = found[0].name;
|
|
347
|
-
console.error(
|
|
348
|
-
`\nRun it: capture exec "import {${firstFn}} from 'libs/${service}'; return await ${firstFn}({…})"`,
|
|
349
|
-
);
|
|
440
|
+
export async function cmdLib(
|
|
441
|
+
parsed: ParsedArgs,
|
|
442
|
+
_args: string[],
|
|
443
|
+
): Promise<void> {
|
|
444
|
+
const sub = parsed.positional[0];
|
|
445
|
+
|
|
446
|
+
// Help never touches vault/ — it must work in the published package too.
|
|
447
|
+
if (parsed.help) {
|
|
448
|
+
console.log(sub && LEAF_USAGE[sub] ? LEAF_USAGE[sub] : LIB_USAGE);
|
|
350
449
|
return;
|
|
351
450
|
}
|
|
352
451
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
452
|
+
try {
|
|
453
|
+
switch (sub) {
|
|
454
|
+
case "list":
|
|
455
|
+
return await libList(parsed);
|
|
456
|
+
case "search":
|
|
457
|
+
return await libSearch(parsed);
|
|
458
|
+
case "show":
|
|
459
|
+
return await libShow(parsed);
|
|
460
|
+
case "read":
|
|
461
|
+
return await libRead(parsed);
|
|
462
|
+
case undefined:
|
|
463
|
+
// Bare `lib` prints branch usage, exit 0 — same posture as the other
|
|
464
|
+
// root branches (page/tab/measure/motion).
|
|
465
|
+
console.log(LIB_USAGE);
|
|
466
|
+
return;
|
|
467
|
+
default:
|
|
468
|
+
// Defense-in-depth mirror of the sibling branch routers; central
|
|
469
|
+
// dispatch (`validateCliInvocation`) rejects unknown lib leaves with
|
|
470
|
+
// the same typed shape before this switch runs.
|
|
471
|
+
throw invalidInput(`Unknown lib leaf: ${sub}.`, "unknown_command");
|
|
472
|
+
}
|
|
473
|
+
} catch (e) {
|
|
474
|
+
// The dev-only gate (vault/ source or esbuild missing) surfaces here from
|
|
475
|
+
// any leaf; gate behavior is unchanged, only its presentation is the
|
|
476
|
+
// typed vocabulary rendered at the root boundary.
|
|
477
|
+
if (e instanceof Error && e.message === DEV_ONLY_MSG) {
|
|
478
|
+
throw captureError("precondition", "dev_only", e.message, e);
|
|
479
|
+
}
|
|
480
|
+
throw e;
|
|
481
|
+
}
|
|
356
482
|
}
|