mesurer-solid 0.1.6 → 0.1.7-beta.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.
@@ -1,32 +1,10 @@
1
1
  # Mesurer agent integration
2
2
 
3
- Mesurer's agent integration is direct: **the agent reads Mesurer through the same rendered page it is already controlling**.
3
+ Mesurer's agent integration is the rendered page itself. The coding agent reads `window.__MESURER__` through the browser control it already has, consumes human visual intent, edits normal application source, and verifies the real Live result.
4
4
 
5
- There is no Mesurer MCP, WebMCP, ACP, localhost feedback daemon, Send-to-agent callback, chat/session bridge, or harness-specific Mesurer adapter.
5
+ There is no Mesurer MCP server, localhost daemon, Send-to-agent callback, or harness-specific transport.
6
6
 
7
- The page is the shared state boundary. A meaningful Mesurer operation should return evidence that the coding agent actually consumes before it edits source or claims completion.
8
-
9
- ```text
10
- human visual intent
11
-
12
- Arrange / text-style Desired edits / annotation / selection
13
-
14
- window.__MESURER__
15
-
16
- structured rendered evidence + optional harness screenshot
17
-
18
- agent edits normal source
19
-
20
- real render / HMR
21
-
22
- fresh Live review/context
23
-
24
- validated result
25
- ```
26
-
27
- ## Install the portable Agent Skill
28
-
29
- Use the stable package by default:
7
+ ## Install the Agent Skill
30
8
 
31
9
  ```bash
32
10
  npx --yes --package=mesurer-solid mesurer-skill install
@@ -34,7 +12,7 @@ npx --yes --package=mesurer-solid mesurer-skill install
34
12
 
35
13
  Use `mesurer-solid@beta` only when intentionally validating a prerelease.
36
14
 
37
- The installed skill is self-contained:
15
+ The installer writes a self-contained skill and injection artifact:
38
16
 
39
17
  ```text
40
18
  .agents/skills/mesurer-ui/
@@ -43,11 +21,9 @@ The installed skill is self-contained:
43
21
  └── inject-script.js
44
22
  ```
45
23
 
46
- The skill defines the same state-preservation, Arrange, text-edit, context, screenshot, HMR, and completion rules described here.
47
-
48
- ## Reuse a live human instance
24
+ ## Reuse a live instance
49
25
 
50
- Before injecting anything:
26
+ Before injecting anything, check whether Mesurer is already connected:
51
27
 
52
28
  ```js
53
29
  const hasMesurer = Boolean(
@@ -60,107 +36,31 @@ if (hasMesurer) {
60
36
  }
61
37
  ```
62
38
 
63
- If Mesurer exists, use that exact instance. The person may already have arranged elements, edited copy/typography into a Desired state, selected targets, placed guides, measured gaps, held distances, enabled rulers/X-ray, saved annotations, or kept a screenshot preview open. That state is part of the user's visual message.
39
+ If it exists, use that instance. A person may already have selected targets, guides, measurements, annotations, Arrange intent, text/style intent, or screenshot review state. That state is part of the request.
64
40
 
65
- The injector reuses a live injected instance by default. Deliberate destructive replacement requires:
41
+ The injector reuses a connected instance by default. Deliberate replacement requires:
66
42
 
67
43
  ```js
68
44
  window.__MESURER_CONFIG__ = { reuseExisting: false }
69
45
  ```
70
46
 
71
- Do not use that while consuming human review state.
47
+ Do not replace a live instance while consuming human review state.
72
48
 
73
49
  ## Inject only when absent
74
50
 
75
- Default host-project mutation budget is zero. Reuse the browser, Electron, WebView, Playwright, CDP, or other evaluation channel the harness already owns.
76
-
77
- With the installed skill, evaluate `.agents/skills/mesurer-ui/assets/inject-script.js`. With the npm package installed, use `mesurer-solid/inject-script`.
78
-
79
- ```js
80
- import { readFile } from "node:fs/promises"
81
- import { fileURLToPath } from "node:url"
82
-
83
- const source = await readFile(
84
- fileURLToPath(import.meta.resolve("mesurer-solid/inject-script")),
85
- "utf8",
86
- )
87
-
88
- const alreadyPresent = await browser.evaluate(() => Boolean(
89
- window.__MESURER__ &&
90
- window.__MESURER_INSTANCE__?.element?.isConnected
91
- ))
92
-
93
- if (!alreadyPresent) {
94
- await browser.evaluate(source)
95
- }
96
-
97
- await browser.evaluate(() => window.__MESURER__.ready())
98
- ```
51
+ Use the browser, Electron, WebView, Playwright, CDP, or other evaluation channel the harness already owns. With the installed skill, evaluate `.agents/skills/mesurer-ui/assets/inject-script.js`. With the npm package installed, read `mesurer-solid/inject-script`.
99
52
 
100
- Do not create a second browser/CDP connection, Mesurer server, special app build, or source mutation merely to inspect a page the harness already controls.
53
+ Do not mutate application source or create another browser connection merely to get Mesurer into a page the harness can already evaluate.
101
54
 
102
- Normal injection keeps the optional human screenshot plugin disabled unless requested:
55
+ The optional human Screenshot plugin remains disabled during normal agent injection unless configured before first injection:
103
56
 
104
57
  ```js
105
58
  window.__MESURER_CONFIG__ = { screenshot: true }
106
59
  ```
107
60
 
108
- ## Capabilities
61
+ ## Inventory human intent
109
62
 
110
- After `ready()`:
111
-
112
- ```js
113
- window.__MESURER__.capabilities()
114
- ```
115
-
116
- The context-oriented surface is:
117
-
118
- ```text
119
- context
120
- select
121
- annotations
122
- review
123
- capturePlan
124
- textEdits
125
- textEdit
126
- ```
127
-
128
- Direct text editing reports:
129
-
130
- ```text
131
- textEdit
132
- ```
133
-
134
- and exposes:
135
-
136
- ```text
137
- textEdits()
138
- textEdit(id)
139
- ```
140
-
141
- When `arrangePlugin()` is mounted, capabilities also reports:
142
-
143
- ```text
144
- arrange
145
- ```
146
-
147
- and exposes:
148
-
149
- ```text
150
- arrangements()
151
- arrange(id)
152
- showArrange(id, state)
153
- arrangeCapturePlan(id, state)
154
- reviewArrange(id, tolerance?)
155
- ```
156
-
157
- There is no `send`, `screenshots`, or `sendContext` delivery capability. Screenshot bytes stay with the outer browser harness.
158
-
159
- ## Broad Mesurer/context requests mean inspect all human intent
160
-
161
- If the user says “check Mesurer,” “check Measure,” “look at Mesurer context,” “see what I highlighted/moved/annotated/edited,” or otherwise asks generally about Mesurer state, treat that as a request to inspect the **combined live review state**, not only the return value of `context()`.
162
-
163
- Start with a non-destructive inventory:
63
+ For a broad request such as “check Mesurer,” collect all relevant state before editing source:
164
64
 
165
65
  ```js
166
66
  const capabilities = window.__MESURER__.capabilities().capabilities
@@ -179,7 +79,7 @@ try {
179
79
  } catch {}
180
80
  ```
181
81
 
182
- Then resolve the saved human intent that is relevant to the task:
82
+ Resolve relevant records before HMR can replace their DOM targets:
183
83
 
184
84
  ```js
185
85
  const annotationContexts = await Promise.all(
@@ -197,56 +97,35 @@ const textEditIntents = await Promise.all(
197
97
  )
198
98
  ```
199
99
 
200
- Bring the useful pieces together before editing: target-bound notes, current selection, Arrange Before/Desired geometry, text Before/Desired copy and style deltas, guides, measurements, held distances, exact target inspection, layout/style data, rulers/X-ray state, and any existing human screenshot preview that must be preserved.
100
+ Treat annotation notes, Arrange Desired geometry, and text/style Desired state as intent. Treat selection, measurements, distances, geometry, and computed styles as rendered evidence.
201
101
 
202
- The user may have selected one element, annotated another, moved a group with Arrange, edited copy or typography, and left measurements/guides that explain the relationship. Those are not separate conversations. They are one encoded visual request. Do not ask the person to repeat information Mesurer already contains, and do not overwrite one channel before reading the others.
102
+ ## Select exact targets
203
103
 
204
- ## Arrange has high human-intent precedence
205
-
206
- Arrange lets a person reposition selected rendered elements into the layout they want without editing application source. If Arrange is available, consume relevant saved intents before changing human selection or editing source:
104
+ Do not overwrite a meaningful human selection until its context has been retained. When there is no relevant human selection and the exact targets are known:
207
105
 
208
106
  ```js
209
- const arrangements = await window.__MESURER__.arrangements()
210
- const intent = await window.__MESURER__.arrange(arrangeId)
107
+ const context = await window.__MESURER__.select([
108
+ "#pricing-card",
109
+ "#pricing-cta",
110
+ ])
211
111
  ```
212
112
 
213
- Each intent contains exact target identity plus Before and Desired geometry.
113
+ Each selector must resolve to exactly one target. Missing or ambiguous selectors throw rather than binding to a guess.
214
114
 
215
- Desired is a **visual specification**, not an implementation prescription. If a target moved `96px` right, do not blindly write `transform: translateX(96px)` into production CSS. Inspect the rendered layout and implement the appropriate flex/grid alignment, gap, margin, sizing, ordering, component structure, or other semantic source change.
115
+ For multi-selection, inspect every selected target and the relevant pair relationships. Prefer `selection.visualContext.distances`; use `distance(a, b)` when a needed pair has no existing evidence.
216
116
 
217
- ### Capture Before and Desired before source edits
117
+ ## Arrange intent
218
118
 
219
- When screenshot comparison will help, reconstruct and capture both states before HMR can change the baseline:
119
+ Arrange expresses requested geometry, not source implementation.
220
120
 
221
121
  ```js
222
- await window.__MESURER__.showArrange(arrangeId, "before")
223
- const beforePlan = await window.__MESURER__.arrangeCapturePlan(arrangeId, "before")
224
-
225
- await window.__MESURER__.prepareCapture()
226
- try {
227
- // outer harness captures Before with beforePlan
228
- } finally {
229
- await window.__MESURER__.finishCapture()
230
- }
231
-
232
- await window.__MESURER__.showArrange(arrangeId, "desired")
233
- const desiredPlan = await window.__MESURER__.arrangeCapturePlan(arrangeId, "desired")
234
-
235
- await window.__MESURER__.prepareCapture()
236
- try {
237
- // outer harness captures Desired with desiredPlan
238
- } finally {
239
- await window.__MESURER__.finishCapture()
240
- }
122
+ const intents = await window.__MESURER__.arrangements()
123
+ const intent = await window.__MESURER__.arrange(arrangeId)
241
124
  ```
242
125
 
243
- The user should not need to export, attach, or send these screenshots manually. The harness already owns its screenshot primitive; Mesurer supplies the reproducible state and exact capture geometry.
126
+ A 96px Desired offset does not mean production source should use `transform: translateX(96px)`. Implement the visual outcome through the application's real flex/grid, spacing, sizing, ordering, or component structure.
244
127
 
245
- For source-mounted integrations that use this capture workflow, mount `contextPlugin()` together with `arrangePlugin()` so the generic capture preparation methods are available.
246
-
247
- ### Verify the source-produced result
248
-
249
- After editing source:
128
+ After source changes:
250
129
 
251
130
  ```js
252
131
  await window.__MESURER__.stable()
@@ -254,366 +133,90 @@ await window.__MESURER__.showArrange(arrangeId, "live")
254
133
  const review = await window.__MESURER__.reviewArrange(arrangeId)
255
134
  ```
256
135
 
257
- Live removes Arrange's temporary preview. `reviewArrange()` compares the real application layout with Desired and returns exact rectangle deltas plus `connected`, `partial`, or `stale` target status.
258
-
259
- ```text
260
- Before Desired Live
261
- x 120 → x 284 x 276
262
- remaining +8px
263
-
264
- edit source
265
-
266
- Live x 284
267
-
268
- matched ✓
269
- ```
270
-
271
- If review is still numerically wrong, continue editing. If it is `stale` or `partial`, do not silently bind the intent to a different element.
272
-
273
- ## Direct text editing: human UI and durable intent
274
-
275
- Direct text editing records human copy and typography intent without pretending to edit application source. It is not a separate top-level text-edit tool/plugin.
276
-
277
- The human-facing inspection tool is **Typography**. The existing internal compatibility id and stable command remain `text-inspector` / `builtin.text-inspector`; agents should not script the toolbar by label.
278
-
279
- A person enters direct editing while **Select** or **Typography** is active:
280
-
281
- ```text
282
- double-click ordinary direct text
283
- (or double-tap with touch/pen)
284
-
285
- current text is selected in full
286
-
287
- in-place editor uses rendered typography
288
-
289
- Mesurer-style direct typography toolbar
290
- B / I / U / Font / Size / Weight / Color
291
- + separate semantic Text/H1/H2/H3 preset popup
292
- + contextual Typography card for that exact field
293
-
294
- Enter keeps Desired / Shift+Enter newline
295
- ```
296
-
297
- Because Arrange keeps Select active, this same interaction works while Arrange remains selected. Starting the edit contextually activates Typography for the field while Select/Arrange remain active; it does not force the reviewer out of the layout workflow.
136
+ Live removes the temporary Arrange preview before measuring source output.
298
137
 
299
- The typography surface deliberately separates direct properties from semantic meaning:
138
+ Arrange preview ownership is conservative. Mesurer restores an older transform only while the element still carries the exact preview value and priority Mesurer applied. Host-authored transform changes survive review, refresh, and disposal.
300
139
 
301
- - Bold/Italic/Underline, Font, Size, Weight, rendered-page text colors, and custom color are direct toolbar controls;
302
- - the separate semantic popup contains only **Text** plus Heading 1/2/3 for semantic levels actually rendered by visible direct-text page elements;
303
- - each semantic preset uses the page's **dominant rendered typography bundle** for that level: font family, size, weight, style, line height, tracking, text transform, and color;
304
- - non-dominant page variants remain available through the direct Font/Size/Weight/color controls;
305
- - heading levels absent from the rendered page are not invented.
140
+ See [Arrange](../../docs/ARRANGE.md).
306
141
 
307
- The semantic popup must not become a container for Font/Size/Weight/color. Its CSS chevron is part of the visual contract and rotates with popup state.
142
+ ## Text and Typography intent
308
143
 
309
- While the editor owns focus, `Cmd/Ctrl+B`, `Cmd/Ctrl+I`, and `Cmd/Ctrl+U` toggle formatting. Text/H1/H2/H3 use `Option+Cmd+0/1/2/3` on macOS and `Alt+Ctrl+0/1/2/3` elsewhere. If the semantic preset popup is open, the first Escape closes it; Escape with it closed cancels the edit.
144
+ Direct text editing records copy and typography intent without pretending to edit source. The human-facing tool is **Typography**; the internal compatibility id remains `text-inspector`.
310
145
 
311
- Link creation and numbered/bulleted lists are intentionally not exposed as fake controls. Those would require a structural/rich-text intent model rather than ordinary typography deltas.
146
+ Editing starts by double-click/double-tap while Select or Typography is active. Arrange keeps Select active, so editing works while Arrange remains selected.
312
147
 
313
- The contextual Typography card reuses the existing typography/card renderer and reports Family, Size, Weight, Line, Tracking, tag/text information, and CSS-variable references when available. It refreshes during the session. The current editing boundary is intentionally direct text rather than generic rich text: ordinary elements with one unambiguous non-empty direct text node. Native `<input>`, `<textarea>`, `<select>`, `contenteditable`, and ambiguous mixed/nested rich-text structures retain their normal browser/application behavior.
148
+ Native editing stays native. Mesurer does not intercept form controls or descendants that inherit `contenteditable`. A nested `contenteditable="false"` boundary ends inherited editability and can become a Mesurer target when the direct-text rules otherwise pass.
314
149
 
315
- The contextual Typography card is **transient human presentation**, not another durable context channel. Durable intent is the saved text-edit record.
150
+ The editing UI exposes direct B/I/U, Font, Size, Weight, rendered-page colors, custom color, and a separate Text/H1/H2/H3 semantic preset popup. Missing heading levels are not invented.
316
151
 
317
- See the repository's canonical [`docs/TEXT_EDITING.md`](https://github.com/jhomra21/mesurer-solid/blob/main/docs/TEXT_EDITING.md) for the full interaction and runtime contract.
152
+ If Typography was already explicitly selected, the direct-edit session suppresses the older hover/pinned Typography surface so the field has one live card. The normal surface returns when editing ends.
318
153
 
319
- ## Text/style Desired edits are source intent too
320
-
321
- If `capabilities.textEdit` is true, read saved edits before source changes:
154
+ Read durable intent through:
322
155
 
323
156
  ```js
324
157
  const edits = await window.__MESURER__.textEdits()
325
158
  const intent = await window.__MESURER__.textEdit(textEditId)
326
159
  ```
327
160
 
328
- Each intent contains:
161
+ Treat `intent.desired` and style deltas as visual/source requirements, not inline CSS instructions. Look for the application's semantic props, classes, design tokens, CSS variables, theme values, or stylesheet rules that produce the requested render.
329
162
 
330
- ```text
331
- id / createdAt / pageUrl
332
- selector / nodeIndex
333
- before
334
- original text
335
- desired
336
- requested text
337
- styles[]
338
- property
339
- before
340
- desired
341
- ```
163
+ Verification must use Live source with the Desired preview inactive. Text/style preview ownership follows the same conservative rule as Arrange: while the DOM still equals Mesurer's owned value, undo/redo can move it to the restored Desired value; once the application changes it, Mesurer preserves the host value instead of overwriting it during history or cleanup.
342
164
 
343
- Current style deltas can include font family, size, weight, style, line height, letter spacing, text transform, color, and text-decoration line.
165
+ See [Direct text editing and Typography](../../docs/TEXT_EDITING.md).
344
166
 
345
- Treat Desired copy and style deltas as a **visual/source specification**, not a request to paste Mesurer's preview implementation into production. If the person chose a semantic preset or a font, weight, size, or color that already exists on the rendered page, inspect the codebase for the semantic component prop, class, CSS variable, design token, theme value, or stylesheet rule that produces it.
167
+ ## Annotation and context review
346
168
 
347
- Page-derived options are evidence of what the application already renders; they are not a source-code token scanner and do not imply that sampled computed values belong in inline styles.
348
-
349
- While Select or Typography is active, Mesurer may be rendering the saved Desired text/style as a reversible preview. Do not compare against that preview and declare the source implementation correct.
350
-
351
- After editing source:
352
-
353
- 1. retain the text-edit intent;
354
- 2. wait for the real render;
355
- 3. deactivate the active Select/Typography preview without clearing the intent;
356
- 4. inspect the actual target text and computed typography;
357
- 5. compare those Live values with `intent.desired` and `intent.styles`;
358
- 6. reactivate Select only if continued review is useful.
359
-
360
- Mesurer relinquishes ownership when the application itself changes the value, so correct source output remains correct with the temporary preview inactive.
361
-
362
- ## Context acquisition after intent preservation
363
-
364
- Once any relevant Arrange and text-edit intent is retained, use this order for ordinary context.
365
-
366
- ### Existing human selection or annotation
169
+ A saved annotation carries target-bound intent and an immutable baseline:
367
170
 
368
171
  ```js
369
- const workspace = await window.__MESURER__.context()
370
- const annotations = await window.__MESURER__.annotations()
371
-
372
- let selection = null
373
- try {
374
- selection = await window.__MESURER__.context({ scope: "selection" })
375
- } catch {}
376
- ```
377
-
378
- For a relevant annotation:
379
-
380
- ```js
381
- const context = await window.__MESURER__.context({
382
- annotation: annotation.id,
383
- })
384
- ```
385
-
386
- Do not overwrite a meaningful human selection until its context has been retained by the current task.
387
-
388
- ### Ambiguous target
389
-
390
- If the user's visual reference cannot be mapped confidently to exact rendered elements or a region, ask the person to select the intended element(s) or region in Mesurer, then read:
391
-
392
- ```js
393
- const context = await window.__MESURER__.context({ scope: "selection" })
394
- ```
395
-
396
- Do not guess merely to avoid asking for a selection.
397
-
398
- ### Agent knows the exact target
399
-
400
- Use `select()` and consume its return value:
401
-
402
- ```js
403
- const context = await window.__MESURER__.select([
404
- "#pricing-card",
405
- "#pricing-cta",
406
- ])
172
+ const context = await window.__MESURER__.context({ annotation: annotationId })
407
173
  ```
408
174
 
409
- `select()` switches Mesurer to Select, visibly highlights the exact rendered targets, makes them the live selection, waits for the selection to settle, and returns selection-scoped `MesurerContextV1`.
410
-
411
- Every selector must resolve to exactly one page target. Invalid, missing, or ambiguous selectors throw.
412
-
413
- ## What context contains
414
-
415
- `MesurerContextV1` is JSON-safe and uses `viewport-css-px` coordinates:
416
-
417
- ```text
418
- schema / id / createdAt
419
- scope
420
- page
421
- viewport / DPR / scroll
422
- coordinateSpace
423
- regions
424
- visualState
425
- rulersVisible
426
- xrayVisible
427
- targets[]
428
- ref
429
- inspection.selector
430
- inspection.rect
431
- margin / padding / border
432
- typography
433
- appearance
434
- layout
435
- scroll / overflow
436
- visualContext
437
- guides[]
438
- measurements[]
439
- distances[]
440
- ```
441
-
442
- Prefer rendered numbers over screenshot estimates or source assumptions.
443
-
444
- ## Multi-selection is relational
445
-
446
- When several targets are selected, consume each target plus the useful relationships between them. Start with `visualContext.distances`; for a pair not represented there:
447
-
448
- ```js
449
- const pair = window.__MESURER__.distance(selectorA, selectorB)
450
- ```
451
-
452
- A useful result can be:
453
-
454
- ```text
455
- Card A width: 320px
456
- Card B width: 320px
457
- A → B horizontal gap: 24px
458
- A/B top-edge delta: 0px
459
- ```
460
-
461
- For large repeated sets, focus on adjacent or user-relevant relationships rather than dumping all O(n²) pairs.
462
-
463
- ## Fresh evidence is required after visual edits
464
-
465
- Wait for the actual rendered page:
175
+ After source changes:
466
176
 
467
177
  ```js
468
178
  await window.__MESURER__.stable()
469
- ```
470
-
471
- Then use the strongest applicable path.
472
-
473
- Arrange:
474
-
475
- ```js
476
- await window.__MESURER__.showArrange(arrangeId, "live")
477
- const review = await window.__MESURER__.reviewArrange(arrangeId)
478
- ```
479
-
480
- Text/style Desired intent, with its temporary preview inactive:
481
-
482
- ```js
483
- const intent = await window.__MESURER__.textEdit(textEditId)
484
- const live = window.__MESURER__.inspect(intent.selector)
485
- ```
486
-
487
- Compare the actual rendered text and relevant typography values with the saved Desired intent.
488
-
489
- Annotation:
490
-
491
- ```js
492
179
  const review = await window.__MESURER__.review(annotationId)
493
180
  ```
494
181
 
495
- Still-relevant human selection:
496
-
497
- ```js
498
- const after = await window.__MESURER__.context({ scope: "selection" })
499
- ```
500
-
501
- Agent-known changed targets:
502
-
503
- ```js
504
- const after = await window.__MESURER__.select([
505
- changedSelectorA,
506
- changedSelectorB,
507
- ])
508
- ```
509
-
510
- For meaningful visual work, lint/typecheck/tests/build are not enough. They validate implementation mechanics, not the rendered result.
511
-
512
- ## Screenshot ownership
513
-
514
- Mesurer has two different screenshot roles.
515
-
516
- ### Human camera tool
517
-
518
- The optional `mesurer.screenshot` plugin gives the person a camera tool:
519
-
520
- ```ts
521
- import { mountMesurer } from "mesurer-solid"
522
- import { screenshotPlugin } from "mesurer-solid/screenshot"
523
-
524
- const mesurer = mountMesurer({
525
- plugins: [screenshotPlugin()],
526
- })
527
- ```
528
-
529
- It captures HiDPI-aware PNGs and can copy/download them or keep a draggable preview/viewer. Preserve an existing human screenshot preview unless the task explicitly requires manipulating it.
182
+ `review()` can report exact geometry/evidence changes without any external message transport.
530
183
 
531
- ### Agent screenshot evidence
184
+ ## Screenshots
532
185
 
533
- The outer coding harness owns screenshot bytes so it controls the exact browser, viewport, timing, and artifact destination. Mesurer supplies exact geometry and clean capture presentation:
186
+ For ordinary coding-agent evidence, the outer harness owns screenshot bytes while Mesurer prepares capture presentation:
534
187
 
535
188
  ```js
536
- const plan = await window.__MESURER__.capturePlan({ scope: "selection" })
537
-
189
+ const plan = await window.__MESURER__.capturePlan({ annotation: annotationId })
538
190
  await window.__MESURER__.prepareCapture()
539
191
  try {
540
- // use the harness's real screenshot primitive
192
+ // harness screenshot
541
193
  } finally {
542
194
  await window.__MESURER__.finishCapture()
543
195
  }
544
196
  ```
545
197
 
546
- Active direct-editor controls, the semantic preset popup, and the contextual Typography card are Mesurer chrome, not application evidence. Arrange uses the same screenshot ownership model through `arrangeCapturePlan()` while adding explicit Before/Desired/Live presentation.
547
-
548
- Use all three signals when relevant:
549
-
550
- ```text
551
- Mesurer context/review → geometry, box model, styles, distances, overflow
552
- saved Desired intent → requested Arrange geometry + copy/typography
553
- real screenshot → composition, hierarchy, clipping, color, visual judgment
554
- ```
198
+ The optional `mesurer-solid/screenshot` plugin is a separate human camera workflow. It is not an agent delivery capability. Preserve an existing human preview unless the task is specifically about Screenshot behavior.
555
199
 
556
- ## Source-mounted usage
200
+ ## Revalidate after source edits
557
201
 
558
- For context plus Arrange:
559
-
560
- ```ts
561
- import {
562
- contextPlugin,
563
- mountMesurer,
564
- } from "mesurer-solid"
565
- import { arrangePlugin } from "mesurer-solid/arrange"
566
-
567
- const mesurer = mountMesurer({
568
- agent: true,
569
- plugins: [
570
- contextPlugin(),
571
- arrangePlugin(),
572
- ],
573
- })
574
- ```
575
-
576
- The same API is available on `mesurer.agent` and, when configured, `window.__MESURER__`.
577
-
578
- Arrange remains optional. Direct text editing and text-edit intent are part of the base inspector runtime; applications do not need a separate text-edit plugin.
579
-
580
- ## Low-level inspection
581
-
582
- These remain useful for focused queries:
202
+ After HMR or reload settles:
583
203
 
584
204
  ```js
585
- window.__MESURER__.inspect(".selector")
586
- window.__MESURER__.inspectAll(".selector")
587
- window.__MESURER__.at(x, y)
588
- window.__MESURER__.distance(".a", ".b")
589
- window.__MESURER__.viewport()
590
- await window.__MESURER__.feedback([".selector"])
591
- await window.__MESURER__.state()
592
- await window.__MESURER__.textEdits()
593
- await window.__MESURER__.textEdit(textEditId)
594
205
  await window.__MESURER__.stable()
595
206
  ```
596
207
 
597
- Prefer `arrangements()`, `textEdits()`, `context()`, `select()`, `reviewArrange()`, and `review()` for visual development because those paths preserve human meaning and return evidence the agent can reason from directly.
208
+ Then compare the same evidence retained before editing:
598
209
 
599
- ## Completion rule
210
+ - Arrange Desired against Live through `reviewArrange()`;
211
+ - text/style Desired against Live with the text preview inactive;
212
+ - saved annotations through `review()`;
213
+ - current selections and measurements through fresh `context()`;
214
+ - exact geometry through `inspect()`, `distance()`, and `viewport()`.
600
215
 
601
- A good harness-level loop is:
216
+ Do not clear human history merely to expose Live state, and do not reinject just to refresh context.
602
217
 
603
- ```text
604
- 1. discover/reuse Mesurer and preserve human state
605
- 2. if the request is broad, inventory Arrange + text edits + annotations + selection + workspace context before narrowing
606
- 3. consume relevant Arrange and text/style Desired intent first
607
- 4. capture Arrange Before/Desired when useful, before source edits
608
- 5. consume existing annotation/selection context
609
- 6. resolve exact targets; ask only when genuinely ambiguous
610
- 7. edit normal source
611
- 8. wait for stable render
612
- 9. switch Arrange to Live and deactivate text Desired preview when applicable
613
- 10. get fresh source-rendered review/context and optional screenshot
614
- 11. iterate until rendered evidence supports completion
615
- ```
218
+ ## Completion rule
616
219
 
617
- Do not clear Arrange history, clear text-edit history just to reveal Live, alter human measurements/guides, replace live Mesurer state, or use a temporary preview to make unfinished source work appear correct.
220
+ A meaningful Mesurer call should affect the work. If exact geometry is available, use it instead of estimating pixels from a screenshot. If the user already encoded intent in Arrange, text editing, annotations, or selection, consume it before asking them to repeat it.
618
221
 
619
- **Rendered evidence is the output of the Mesurer step, not an optional side effect.**
222
+ The repository's packaged [`mesurer-ui` skill](./skills/mesurer-ui/SKILL.md) carries the operational version of this contract for coding agents. [Browser and agent integration](../../docs/BROWSER_HARNESS.md) documents the outer harness boundary.