@michaelmagan/dnumb 0.1.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/AGENTS.md +180 -0
- package/LICENSE +21 -0
- package/README.md +297 -0
- package/dist/analysis/cluster.cjs +114 -0
- package/dist/analysis/cluster.d.cts +68 -0
- package/dist/analysis/cluster.d.ts +68 -0
- package/dist/analysis/cluster.js +109 -0
- package/dist/analysis/distances.cjs +124 -0
- package/dist/analysis/distances.d.cts +58 -0
- package/dist/analysis/distances.d.ts +58 -0
- package/dist/analysis/distances.js +119 -0
- package/dist/analysis/geometry.cjs +60 -0
- package/dist/analysis/geometry.d.cts +34 -0
- package/dist/analysis/geometry.d.ts +34 -0
- package/dist/analysis/geometry.js +53 -0
- package/dist/analysis/layout-tree.cjs +245 -0
- package/dist/analysis/layout-tree.d.cts +45 -0
- package/dist/analysis/layout-tree.d.ts +45 -0
- package/dist/analysis/layout-tree.js +242 -0
- package/dist/analysis/region-query.cjs +71 -0
- package/dist/analysis/region-query.d.cts +25 -0
- package/dist/analysis/region-query.d.ts +25 -0
- package/dist/analysis/region-query.js +67 -0
- package/dist/analysis/types.cjs +7 -0
- package/dist/analysis/types.d.cts +143 -0
- package/dist/analysis/types.d.ts +143 -0
- package/dist/analysis/types.js +6 -0
- package/dist/bundle.cjs +182 -0
- package/dist/bundle.d.cts +91 -0
- package/dist/bundle.d.ts +91 -0
- package/dist/bundle.js +175 -0
- package/dist/cli.cjs +755 -0
- package/dist/cli.d.cts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +719 -0
- package/dist/diff/changes.cjs +656 -0
- package/dist/diff/changes.d.cts +2 -0
- package/dist/diff/changes.d.ts +2 -0
- package/dist/diff/changes.js +653 -0
- package/dist/diff/identity.cjs +167 -0
- package/dist/diff/identity.d.cts +62 -0
- package/dist/diff/identity.d.ts +62 -0
- package/dist/diff/identity.js +159 -0
- package/dist/diff/index.cjs +84 -0
- package/dist/diff/index.d.cts +76 -0
- package/dist/diff/index.d.ts +76 -0
- package/dist/diff/index.js +68 -0
- package/dist/diff/match.cjs +156 -0
- package/dist/diff/match.d.cts +17 -0
- package/dist/diff/match.d.ts +17 -0
- package/dist/diff/match.js +152 -0
- package/dist/diff/render.cjs +540 -0
- package/dist/diff/render.d.cts +2 -0
- package/dist/diff/render.d.ts +2 -0
- package/dist/diff/render.js +537 -0
- package/dist/diff/types.cjs +2 -0
- package/dist/diff/types.d.cts +211 -0
- package/dist/diff/types.d.ts +211 -0
- package/dist/diff/types.js +1 -0
- package/dist/digest/index.cjs +8 -0
- package/dist/digest/index.d.cts +4 -0
- package/dist/digest/index.d.ts +4 -0
- package/dist/digest/index.js +2 -0
- package/dist/digest/parse.cjs +163 -0
- package/dist/digest/parse.d.cts +80 -0
- package/dist/digest/parse.d.ts +80 -0
- package/dist/digest/parse.js +160 -0
- package/dist/digest/render.cjs +1575 -0
- package/dist/digest/render.d.cts +41 -0
- package/dist/digest/render.d.ts +41 -0
- package/dist/digest/render.js +1571 -0
- package/dist/digest/types.cjs +10 -0
- package/dist/digest/types.d.cts +86 -0
- package/dist/digest/types.d.ts +86 -0
- package/dist/digest/types.js +9 -0
- package/dist/index.cjs +61 -0
- package/dist/index.d.cts +27 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +19 -0
- package/dist/page.cjs +35 -0
- package/dist/page.d.cts +40 -0
- package/dist/page.d.ts +40 -0
- package/dist/page.js +31 -0
- package/dist/playwright.cjs +138 -0
- package/dist/playwright.d.cts +69 -0
- package/dist/playwright.d.ts +69 -0
- package/dist/playwright.js +131 -0
- package/dist/query.cjs +1152 -0
- package/dist/query.d.cts +47 -0
- package/dist/query.d.ts +47 -0
- package/dist/query.js +1146 -0
- package/dist/snapshot/capture.cjs +80 -0
- package/dist/snapshot/capture.d.cts +34 -0
- package/dist/snapshot/capture.d.ts +34 -0
- package/dist/snapshot/capture.js +77 -0
- package/dist/snapshot/cdp.cjs +450 -0
- package/dist/snapshot/cdp.d.cts +36 -0
- package/dist/snapshot/cdp.d.ts +36 -0
- package/dist/snapshot/cdp.js +447 -0
- package/dist/snapshot/clip.cjs +100 -0
- package/dist/snapshot/clip.d.cts +26 -0
- package/dist/snapshot/clip.d.ts +26 -0
- package/dist/snapshot/clip.js +96 -0
- package/dist/snapshot/collect.cjs +358 -0
- package/dist/snapshot/collect.d.cts +18 -0
- package/dist/snapshot/collect.d.ts +18 -0
- package/dist/snapshot/collect.js +355 -0
- package/dist/snapshot/color.cjs +1039 -0
- package/dist/snapshot/color.d.cts +316 -0
- package/dist/snapshot/color.d.ts +316 -0
- package/dist/snapshot/color.js +1026 -0
- package/dist/snapshot/facts.cjs +167 -0
- package/dist/snapshot/facts.d.cts +48 -0
- package/dist/snapshot/facts.d.ts +48 -0
- package/dist/snapshot/facts.js +161 -0
- package/dist/snapshot/limits.cjs +69 -0
- package/dist/snapshot/limits.d.cts +59 -0
- package/dist/snapshot/limits.d.ts +59 -0
- package/dist/snapshot/limits.js +65 -0
- package/dist/snapshot/not-measured.cjs +44 -0
- package/dist/snapshot/not-measured.d.cts +14 -0
- package/dist/snapshot/not-measured.d.ts +14 -0
- package/dist/snapshot/not-measured.js +41 -0
- package/dist/snapshot/types.cjs +2 -0
- package/dist/snapshot/types.d.cts +238 -0
- package/dist/snapshot/types.d.ts +238 -0
- package/dist/snapshot/types.js +1 -0
- package/dist/spec/index.cjs +9 -0
- package/dist/spec/index.d.cts +15 -0
- package/dist/spec/index.d.ts +15 -0
- package/dist/spec/index.js +6 -0
- package/package.json +141 -0
- package/skills/dnumb/SKILL.md +136 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SPEC_VERSION = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Bumped when the capture format changes in a way a reader must know about.
|
|
6
|
+
* Independent of the package version: a patch release does not move it, and a
|
|
7
|
+
* major release does not necessarily move it either.
|
|
8
|
+
*/
|
|
9
|
+
exports.SPEC_VERSION = 1;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The interop contract: types and a version constant, zero runtime logic and
|
|
3
|
+
* zero dependencies.
|
|
4
|
+
*
|
|
5
|
+
* This exists as a subpath (`dnumb/spec`) rather than a separate package
|
|
6
|
+
* because a second implementer does not exist yet. If one appears, the move to
|
|
7
|
+
* its own package is a re-export away and nothing that imports from here breaks.
|
|
8
|
+
*/
|
|
9
|
+
export type { BoxSides, ClipFact, DocumentBackground, ElementRecord, NotMeasured, Rect, Snapshot, } from "../snapshot/types.cjs";
|
|
10
|
+
/**
|
|
11
|
+
* Bumped when the capture format changes in a way a reader must know about.
|
|
12
|
+
* Independent of the package version: a patch release does not move it, and a
|
|
13
|
+
* major release does not necessarily move it either.
|
|
14
|
+
*/
|
|
15
|
+
export declare const SPEC_VERSION: 1;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The interop contract: types and a version constant, zero runtime logic and
|
|
3
|
+
* zero dependencies.
|
|
4
|
+
*
|
|
5
|
+
* This exists as a subpath (`dnumb/spec`) rather than a separate package
|
|
6
|
+
* because a second implementer does not exist yet. If one appears, the move to
|
|
7
|
+
* its own package is a re-export away and nothing that imports from here breaks.
|
|
8
|
+
*/
|
|
9
|
+
export type { BoxSides, ClipFact, DocumentBackground, ElementRecord, NotMeasured, Rect, Snapshot, } from "../snapshot/types.js";
|
|
10
|
+
/**
|
|
11
|
+
* Bumped when the capture format changes in a way a reader must know about.
|
|
12
|
+
* Independent of the package version: a patch release does not move it, and a
|
|
13
|
+
* major release does not necessarily move it either.
|
|
14
|
+
*/
|
|
15
|
+
export declare const SPEC_VERSION: 1;
|
package/package.json
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@michaelmagan/dnumb",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Turns a rendered page into measurements an agent can read: element geometry, overflow, clipping, and a text diff of what changed between two states.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"agent",
|
|
7
|
+
"ai-agent",
|
|
8
|
+
"playwright",
|
|
9
|
+
"layout",
|
|
10
|
+
"dom",
|
|
11
|
+
"geometry",
|
|
12
|
+
"e2e",
|
|
13
|
+
"testing",
|
|
14
|
+
"cli",
|
|
15
|
+
"accessibility",
|
|
16
|
+
"contrast"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": "Michael Magan <michael.magan92@gmail.com>",
|
|
20
|
+
"homepage": "https://github.com/michaelmagan/dnumb#readme",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/michaelmagan/dnumb.git"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/michaelmagan/dnumb/issues"
|
|
27
|
+
},
|
|
28
|
+
"type": "module",
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=22.12.0"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"skills",
|
|
36
|
+
"AGENTS.md"
|
|
37
|
+
],
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"packageManager": "pnpm@11.24.0",
|
|
42
|
+
"intent": {
|
|
43
|
+
"version": 1,
|
|
44
|
+
"repo": "michaelmagan/dnumb",
|
|
45
|
+
"docs": "https://github.com/michaelmagan/dnumb#readme"
|
|
46
|
+
},
|
|
47
|
+
"zshy": {
|
|
48
|
+
"exports": {
|
|
49
|
+
".": "./src/index.ts",
|
|
50
|
+
"./playwright": "./src/playwright.ts",
|
|
51
|
+
"./spec": "./src/spec/index.ts",
|
|
52
|
+
"./package.json": "./package.json"
|
|
53
|
+
},
|
|
54
|
+
"bin": {
|
|
55
|
+
"dnumb": "./src/cli.ts"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "zshy --project tsconfig.build.json && node scripts/exports-map.mjs",
|
|
60
|
+
"postbuild": "node scripts/exports-map.mjs",
|
|
61
|
+
"typecheck": "tsc --noEmit",
|
|
62
|
+
"lint": "biome check --error-on-warnings .",
|
|
63
|
+
"format": "biome check --write .",
|
|
64
|
+
"test": "vitest run --project unit",
|
|
65
|
+
"test:browser": "vitest run --project browser",
|
|
66
|
+
"test:all": "vitest run",
|
|
67
|
+
"test:travel": "bash scripts/travel-test.sh",
|
|
68
|
+
"check:package": "publint --strict && attw --pack .",
|
|
69
|
+
"prepack": "pnpm run build",
|
|
70
|
+
"prepublishOnly": "pnpm run typecheck && pnpm run lint && pnpm run test && pnpm run test:browser && pnpm run check:package",
|
|
71
|
+
"release": "changeset publish"
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"playwright-core": ">=1.17.0"
|
|
75
|
+
},
|
|
76
|
+
"peerDependenciesMeta": {
|
|
77
|
+
"playwright-core": {
|
|
78
|
+
"optional": true
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"devDependencies": {
|
|
82
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
83
|
+
"@biomejs/biome": "^2.3.0",
|
|
84
|
+
"@changesets/cli": "^3.0.1",
|
|
85
|
+
"@types/node": "^24.0.0",
|
|
86
|
+
"playwright-core": "^1.62.1",
|
|
87
|
+
"publint": "^0.3.24",
|
|
88
|
+
"typescript": "^5.9.0",
|
|
89
|
+
"vitest": "^4.1.0",
|
|
90
|
+
"zshy": "^0.7.3"
|
|
91
|
+
},
|
|
92
|
+
"main": "./dist/index.cjs",
|
|
93
|
+
"module": "./dist/index.js",
|
|
94
|
+
"types": "./dist/index.d.cts",
|
|
95
|
+
"exports": {
|
|
96
|
+
".": {
|
|
97
|
+
"import": {
|
|
98
|
+
"types": "./dist/index.d.ts",
|
|
99
|
+
"default": "./dist/index.js"
|
|
100
|
+
},
|
|
101
|
+
"require": {
|
|
102
|
+
"types": "./dist/index.d.cts",
|
|
103
|
+
"default": "./dist/index.cjs"
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"./playwright": {
|
|
107
|
+
"import": {
|
|
108
|
+
"types": "./dist/playwright.d.ts",
|
|
109
|
+
"default": "./dist/playwright.js"
|
|
110
|
+
},
|
|
111
|
+
"require": {
|
|
112
|
+
"types": "./dist/playwright.d.cts",
|
|
113
|
+
"default": "./dist/playwright.cjs"
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"./spec": {
|
|
117
|
+
"import": {
|
|
118
|
+
"types": "./dist/spec/index.d.ts",
|
|
119
|
+
"default": "./dist/spec/index.js"
|
|
120
|
+
},
|
|
121
|
+
"require": {
|
|
122
|
+
"types": "./dist/spec/index.d.cts",
|
|
123
|
+
"default": "./dist/spec/index.cjs"
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"./package.json": "./package.json"
|
|
127
|
+
},
|
|
128
|
+
"bin": {
|
|
129
|
+
"dnumb": "./dist/cli.cjs"
|
|
130
|
+
},
|
|
131
|
+
"typesVersions": {
|
|
132
|
+
"*": {
|
|
133
|
+
"playwright": [
|
|
134
|
+
"./dist/playwright.d.cts"
|
|
135
|
+
],
|
|
136
|
+
"spec": [
|
|
137
|
+
"./dist/spec/index.d.cts"
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dnumb
|
|
3
|
+
description: Use when a layout or design question needs the page's real numbers instead of a screenshot — is this text truncated and by how much, does this box overflow, is this menu clipped by an ancestor, how far apart are these two elements, what moved between two states, what is at this coordinate. Captures a rendered page as element geometry plus the CSS that says what each measurement means, and renders it as a compact text digest. Load before investigating a layout bug or answering a layout question; it reports measurements and never issues a verdict.
|
|
4
|
+
type: package
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# dnumb
|
|
8
|
+
|
|
9
|
+
**Design, in numbers.** A rendered page as measurements a model can read.
|
|
10
|
+
|
|
11
|
+
**Live example** (`fixture=test/fixtures/flex-min-width-ellipsis.html line=e2`) — one real line out
|
|
12
|
+
of a real capture, checked by `test/browser/doc-examples.test.ts`.
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
e2 h1.heading "Quarterly revenue review for t…" @0,0 668x28 [overflow-x +147px; clip, ellipsis]
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
A heading 668px wide around 815px of content, the box clips, the clipped edge ends in an ellipsis.
|
|
19
|
+
|
|
20
|
+
**Live example** (`fixture=test/fixtures/clipped-menu.html state=menu-open after=__toB line=e5`) —
|
|
21
|
+
one real line out of a real capture, checked the same way.
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
e5 nav.menu "Actions" @39,104 182x109 →-110 [clipped by e2 div; overflow:hidden, not scrollable; 103.8px below, 182x5 visible]
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
A menu overlapping the sibling before it — negative gap — clipped by its own parent's
|
|
28
|
+
`overflow: hidden` with only a 5px sliver surviving. Neither line says "bug". You decide that.
|
|
29
|
+
|
|
30
|
+
## Status: pre-release
|
|
31
|
+
|
|
32
|
+
Not yet published to npm. The library surface below is built and tested. The CLI has a stable verb
|
|
33
|
+
set — `capture`, `look`, `diff`, and `q describe|find|at|within|distance|nearest|facts|color` — worked in
|
|
34
|
+
[README § From the CLI](https://github.com/michaelmagan/dnumb/blob/main/README.md#from-the-cli) and
|
|
35
|
+
[§ Reading a diff](https://github.com/michaelmagan/dnumb/blob/main/README.md#reading-a-diff). This
|
|
36
|
+
file does not restate flags: run `dnumb --help` for the exhaustive, versioned list of what your
|
|
37
|
+
installed copy supports, and trust it over any prose here or there.
|
|
38
|
+
|
|
39
|
+
## The two-call loop
|
|
40
|
+
|
|
41
|
+
In a Playwright test, or any script that has a `page`:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { capture } from '@michaelmagan/dnumb/playwright';
|
|
45
|
+
import { renderDigest } from '@michaelmagan/dnumb';
|
|
46
|
+
|
|
47
|
+
await page.goto('/settings');
|
|
48
|
+
const { bundle } = await capture(page, 'settings-desktop'); // writes .dnumb/settings-desktop.json
|
|
49
|
+
console.log(renderDigest(bundle, { url: bundle.url, viewport: bundle.viewport, state: bundle.name }));
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Read the digest. The header names the URL, the viewport, the capture state, and how many elements
|
|
53
|
+
carry facts. Most elements get their own line; a run of repeated siblings (a list, a table body)
|
|
54
|
+
folds into one summary line instead, naming each folded sibling's id and position but not its
|
|
55
|
+
descendants — see [`docs/digest.md` § The fold
|
|
56
|
+
line](https://github.com/michaelmagan/dnumb/blob/main/docs/digest.md#the-fold-line) before reading
|
|
57
|
+
an absent element in a fold as absent from the page. Anything measurable that does not fit its box
|
|
58
|
+
gets a bracketed fact on its own line.
|
|
59
|
+
|
|
60
|
+
The bundle is a single self-contained JSON file. It travels: attach it to a CI report, commit it,
|
|
61
|
+
send it, and answer questions about that page months later on a machine with no app and no browser.
|
|
62
|
+
|
|
63
|
+
## Install
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install --save-dev @michaelmagan/dnumb
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`playwright-core` is an optional peer. If your e2e suite already has Playwright, you have
|
|
70
|
+
everything — dnumb reuses your browsers and never downloads its own. If it does not, everything
|
|
71
|
+
downstream of a saved bundle still works with no browser at all.
|
|
72
|
+
|
|
73
|
+
## Read this before you use the output
|
|
74
|
+
|
|
75
|
+
**Facts come with counter-facts, and a fact is not a verdict.** The same number means different
|
|
76
|
+
things depending on the CSS beside it:
|
|
77
|
+
|
|
78
|
+
**Illustrative** — hand-composed to contrast three cases; the first is real (see above), the gloss
|
|
79
|
+
after each is plain English, not renderer output.
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
[overflow-x +147px; clip, ellipsis] truncated text
|
|
83
|
+
[overflow-x +227px; clip, wraps] the text wrapped; this is height, not truncation
|
|
84
|
+
[overflow-x +90px; scroll, wraps] a scroll region working as intended
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Report the measurement *and* the consequence tokens, and say which one your conclusion rests on.
|
|
88
|
+
Never report a bare number as a bug. And do not read an absence of facts as "the page is fine" —
|
|
89
|
+
this tool does not measure typography or alignment at all, and where it does measure color and
|
|
90
|
+
contrast, it never says whether a ratio is good enough — that threshold lives in the reader.
|
|
91
|
+
|
|
92
|
+
Five kinds of fact exist in total — `overflow-x`, `overflow-y`, `zero-box`, `clipped`, and `color`
|
|
93
|
+
(the one that never prints inline on an element line — only in the digest's `# colors:` header and
|
|
94
|
+
`q color`) — one line each on what the measurement *is* in
|
|
95
|
+
[AGENTS.md](https://github.com/michaelmagan/dnumb/blob/main/AGENTS.md#facts-with-counter-facts),
|
|
96
|
+
full grammar in
|
|
97
|
+
[`docs/digest.md`](https://github.com/michaelmagan/dnumb/blob/main/docs/digest.md#color).
|
|
98
|
+
|
|
99
|
+
**Element ids are stable within one capture only.** `e13` is an index in capture order, not a DOM
|
|
100
|
+
id. Inserting one element earlier in the document shifts every id after it. Never carry an id
|
|
101
|
+
between captures and never write one into a test expectation; match on the test id, the accessible
|
|
102
|
+
name, or the role.
|
|
103
|
+
|
|
104
|
+
**An overflow number on an ellipsized element includes the ellipsis.** Chromium reserves layout
|
|
105
|
+
space for the ellipsis glyph and counts it in `scrollWidth` — measured at +10px at font-size 10
|
|
106
|
+
and +17px at font-size 20, scaling with the font. When a line says `ellipsis`, the number is an
|
|
107
|
+
upper bound on the hidden content, not an exact width. Do not subtract a constant.
|
|
108
|
+
|
|
109
|
+
**`# facts: N elements carry facts` in the header can be larger than the facts `look` prints.**
|
|
110
|
+
Folding and the line budget hide facts from the body — a folded sibling's own `[...]` bracket
|
|
111
|
+
never shows, only its representative's does — without shrinking that count. `q facts --limit 0`
|
|
112
|
+
(the default `--limit` is 50) lists every fact-carrying element, one per line, unaffected by
|
|
113
|
+
folding or the budget. Reach for it whenever the header's count and what `look` shows disagree, or
|
|
114
|
+
whenever a claim depends on having seen *all* the facts, not just the ones still on-screen.
|
|
115
|
+
|
|
116
|
+
## What it costs
|
|
117
|
+
|
|
118
|
+
Measured on the predecessor to this tool: tool-grounded review cost **25–30% more tokens** than
|
|
119
|
+
screenshot-only, driven by round-trip count rather than payload size. In the same blind
|
|
120
|
+
experiment, vision alone reported 4 fabricated findings on a provably clean page and 10 on
|
|
121
|
+
replication; both tool-grounded arms reported zero, twice.
|
|
122
|
+
|
|
123
|
+
Spend a round-trip when a visual impression needs checking. Do not sweep a page with it.
|
|
124
|
+
|
|
125
|
+
## Full library surface
|
|
126
|
+
|
|
127
|
+
`capture`, `renderDigest`, `parseDigestLine`, `diffCaptures`, `factsFor`, `factsForAll`,
|
|
128
|
+
`renderFacts`, `clipFactFor`, `attachClipFacts`, `formatNotMeasured`, `buildBundle`, `parseBundle`,
|
|
129
|
+
`serializeBundle`, `SPEC_VERSION`, and the geometry primitives `intersect` / `contains` /
|
|
130
|
+
`gapAlong` / `area` / `center`. Types alone, with no runtime code, from `@michaelmagan/dnumb/spec`.
|
|
131
|
+
|
|
132
|
+
The digest grammar — every token, every fact form, the fold and collapse syntax, and the parser
|
|
133
|
+
contract — is specified in
|
|
134
|
+
[`docs/digest.md`](https://github.com/michaelmagan/dnumb/blob/main/docs/digest.md). `diffCaptures`
|
|
135
|
+
and the CLI's `diff` verb share one grammar, worked in
|
|
136
|
+
[README § Reading a diff](https://github.com/michaelmagan/dnumb/blob/main/README.md#reading-a-diff).
|