mesurer-solid 0.1.2 → 0.1.3-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,31 +1,29 @@
1
1
  # Mesurer agent integration
2
2
 
3
- Mesurer's agent integration is deliberately direct: **the agent reads and manipulates Mesurer through the same rendered page it is already controlling**.
3
+ Mesurer's agent integration is direct: **the agent reads Mesurer through the same rendered page it is already controlling**.
4
4
 
5
5
  There is no Mesurer MCP, WebMCP, ACP, localhost feedback daemon, Send-to-agent callback, chat/session bridge, or harness-specific Mesurer adapter.
6
6
 
7
- The central contract is stronger than Mesurer is available”:
8
-
9
- > **A Mesurer visual operation should return structured context to the harness.** The agent should consume existing human context before editing and obtain fresh Mesurer context/review for the affected rendered UI before claiming completion.
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.
10
8
 
11
9
  ```text
12
- human selection / annotation OR agent-known changed target
13
-
14
- real page + window.__MESURER__
15
-
16
- context() / select() / review()
17
- structured rendered evidence
18
- agent reasoning + source edit
19
-
20
- normal render/HMR
21
-
22
- fresh context() / select() / review()
23
-
10
+ human visual intent
11
+
12
+ Arrange / 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
24
  validated result
25
25
  ```
26
26
 
27
- The page is the shared state boundary. Mesurer never needs to know which chat, thread, model, or agent is using it.
28
-
29
27
  ## Install the portable Agent Skill
30
28
 
31
29
  Use the stable package by default:
@@ -45,9 +43,9 @@ The installed skill is self-contained:
45
43
  └── inject-script.js
46
44
  ```
47
45
 
48
- The skill defines the same context-first workflow described here, including the distinction between Mesurer's optional human screenshot plugin and screenshots owned by the agent's outer browser harness.
46
+ The skill defines the same state-preservation, Arrange, context, screenshot, HMR, and completion rules described here.
49
47
 
50
- ## Reuse a live human instance first
48
+ ## Reuse a live human instance
51
49
 
52
50
  Before injecting anything:
53
51
 
@@ -62,9 +60,9 @@ if (hasMesurer) {
62
60
  }
63
61
  ```
64
62
 
65
- If Mesurer exists, use that exact instance. The person may already have selected elements, placed guides, measured gaps, held distances, enabled rulers/X-ray, saved annotations, or kept a screenshot preview open. Read and preserve that state before changing it.
63
+ If Mesurer exists, use that exact instance. The person may already have arranged elements, 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.
66
64
 
67
- The injector also reuses a live injected instance by default. Deliberate destructive replacement requires:
65
+ The injector reuses a live injected instance by default. Deliberate destructive replacement requires:
68
66
 
69
67
  ```js
70
68
  window.__MESURER_CONFIG__ = { reuseExisting: false }
@@ -101,15 +99,13 @@ await browser.evaluate(() => window.__MESURER__.ready())
101
99
 
102
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.
103
101
 
104
- Normal injection keeps screenshot capture disabled unless requested:
102
+ Normal injection keeps the optional human screenshot plugin disabled unless requested:
105
103
 
106
104
  ```js
107
105
  window.__MESURER_CONFIG__ = { screenshot: true }
108
106
  ```
109
107
 
110
- The first-party Chrome extension enables the screenshot plugin automatically because its human-facing camera tool can use the extension's visible-tab capture bridge.
111
-
112
- ## Capability contract
108
+ ## Capabilities
113
109
 
114
110
  After `ready()`:
115
111
 
@@ -117,7 +113,7 @@ After `ready()`:
117
113
  window.__MESURER__.capabilities()
118
114
  ```
119
115
 
120
- The context-oriented capability surface is:
116
+ The context-oriented surface is:
121
117
 
122
118
  ```text
123
119
  context
@@ -127,21 +123,98 @@ review
127
123
  capturePlan
128
124
  ```
129
125
 
130
- `select` is an agent/harness operation; it does not add a human context-toolbar button. Human context controls remain:
126
+ When `arrangePlugin()` is mounted, it also reports:
127
+
128
+ ```text
129
+ arrange
130
+ ```
131
+
132
+ and exposes:
133
+
134
+ ```text
135
+ arrangements()
136
+ arrange(id)
137
+ showArrange(id, state)
138
+ arrangeCapturePlan(id, state)
139
+ reviewArrange(id, tolerance?)
140
+ ```
141
+
142
+ There is no `send`, `screenshots`, or `sendContext` delivery capability. Screenshot bytes stay with the outer browser harness.
143
+
144
+ ## Arrange has highest human-intent precedence
145
+
146
+ 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:
147
+
148
+ ```js
149
+ const arrangements = await window.__MESURER__.arrangements()
150
+ const intent = await window.__MESURER__.arrange(arrangeId)
151
+ ```
152
+
153
+ Each intent contains exact target identity plus Before and Desired geometry.
154
+
155
+ 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.
156
+
157
+ ### Capture Before and Desired before source edits
158
+
159
+ When screenshot comparison will help, reconstruct and capture both states before HMR can change the baseline:
160
+
161
+ ```js
162
+ await window.__MESURER__.showArrange(arrangeId, "before")
163
+ const beforePlan = await window.__MESURER__.arrangeCapturePlan(arrangeId, "before")
164
+
165
+ await window.__MESURER__.prepareCapture()
166
+ try {
167
+ // outer harness captures Before with beforePlan
168
+ } finally {
169
+ await window.__MESURER__.finishCapture()
170
+ }
171
+
172
+ await window.__MESURER__.showArrange(arrangeId, "desired")
173
+ const desiredPlan = await window.__MESURER__.arrangeCapturePlan(arrangeId, "desired")
174
+
175
+ await window.__MESURER__.prepareCapture()
176
+ try {
177
+ // outer harness captures Desired with desiredPlan
178
+ } finally {
179
+ await window.__MESURER__.finishCapture()
180
+ }
181
+ ```
182
+
183
+ 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.
184
+
185
+ For source-mounted integrations that use this capture workflow, mount `contextPlugin()` together with `arrangePlugin()` so the generic capture preparation methods are available.
186
+
187
+ ### Verify the source-produced result
188
+
189
+ After editing source:
190
+
191
+ ```js
192
+ await window.__MESURER__.stable()
193
+ await window.__MESURER__.showArrange(arrangeId, "live")
194
+ const review = await window.__MESURER__.reviewArrange(arrangeId)
195
+ ```
196
+
197
+ 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.
131
198
 
132
199
  ```text
133
- Copy Context
134
- Copy Selection
135
- Add Note
200
+ Before Desired Live
201
+ x 120 → x 284 x 276
202
+ remaining +8px
203
+
204
+ edit source
205
+
206
+ Live x 284
207
+
208
+ matched ✓
136
209
  ```
137
210
 
138
- There is no `send`, `screenshots`, or `sendContext` **delivery capability**. The optional `mesurer.screenshot` plugin is a separate human capture tool/service and does not add image delivery to the context API.
211
+ If review is still numerically wrong, continue editing. If it is `stale` or `partial`, do not silently bind the intent to a different element.
139
212
 
140
- ## Context acquisition precedence
213
+ ## Context acquisition after Arrange preservation
141
214
 
142
- Harnesses should follow this order.
215
+ Once any relevant Arrange intent is retained, use this order for ordinary context.
143
216
 
144
- ### 1. Existing human evidence exists → read it first
217
+ ### Existing human selection or annotation
145
218
 
146
219
  ```js
147
220
  const workspace = await window.__MESURER__.context()
@@ -153,7 +226,7 @@ try {
153
226
  } catch {}
154
227
  ```
155
228
 
156
- For relevant annotations:
229
+ For a relevant annotation:
157
230
 
158
231
  ```js
159
232
  const context = await window.__MESURER__.context({
@@ -161,13 +234,11 @@ const context = await window.__MESURER__.context({
161
234
  })
162
235
  ```
163
236
 
164
- Do not overwrite a meaningful live human selection until its context has been consumed and retained by the current agent task.
237
+ Do not overwrite a meaningful human selection until its context has been retained by the current task.
165
238
 
166
- ### 2. No relevant selection and intended target is ambiguous → ask the user
239
+ ### Ambiguous target
167
240
 
168
- When 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 drag the intended region in Mesurer.
169
-
170
- Then read:
241
+ 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:
171
242
 
172
243
  ```js
173
244
  const context = await window.__MESURER__.context({ scope: "selection" })
@@ -175,15 +246,9 @@ const context = await window.__MESURER__.context({ scope: "selection" })
175
246
 
176
247
  Do not guess merely to avoid asking for a selection.
177
248
 
178
- ### 3. No relevant selection and agent knows exact target(s) → use `select()`
179
-
180
- If the harness knows exactly which rendered elements correspond to the change, it should select them itself:
181
-
182
- ```js
183
- const context = await window.__MESURER__.select("#pricing-card")
184
- ```
249
+ ### Agent knows the exact target
185
250
 
186
- or:
251
+ Use `select()` and consume its return value:
187
252
 
188
253
  ```js
189
254
  const context = await window.__MESURER__.select([
@@ -192,30 +257,9 @@ const context = await window.__MESURER__.select([
192
257
  ])
193
258
  ```
194
259
 
195
- `select()` is deliberately context-returning. In one operation it:
196
-
197
- 1. switches Mesurer to Select;
198
- 2. visibly highlights the exact rendered targets;
199
- 3. makes them the live selection;
200
- 4. waits for the selection to settle;
201
- 5. returns selection-scoped `MesurerContextV1`.
260
+ `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`.
202
261
 
203
- The return value is the point. A harness should not call `select()` only for visual highlighting and then ignore the context.
204
-
205
- Every supplied selector must resolve to exactly one target inside Mesurer's page target. Invalid, missing, or ambiguous selectors throw. Refine the selector or ask the user to select the intended target rather than guessing.
206
-
207
- This makes a useful post-edit pattern trivial:
208
-
209
- ```js
210
- await window.__MESURER__.stable()
211
-
212
- const evidence = await window.__MESURER__.select([
213
- changedSelectorA,
214
- changedSelectorB,
215
- ])
216
-
217
- // `evidence` is the exact rendered result the agent should reason from.
218
- ```
262
+ Every selector must resolve to exactly one page target. Invalid, missing, or ambiguous selectors throw.
219
263
 
220
264
  ## What context contains
221
265
 
@@ -246,19 +290,17 @@ visualContext
246
290
  distances[]
247
291
  ```
248
292
 
249
- Prefer these rendered numbers over screenshot estimates or source-level assumptions.
293
+ Prefer rendered numbers over screenshot estimates or source assumptions.
250
294
 
251
295
  ## Multi-selection is relational
252
296
 
253
- When several targets are selected, consume every target's complete inspection and the relevant relationships between them.
254
-
255
- Use existing `visualContext.distances` first. For a needed pair not represented there:
297
+ When several targets are selected, consume each target plus the useful relationships between them. Start with `visualContext.distances`; for a pair not represented there:
256
298
 
257
299
  ```js
258
300
  const pair = window.__MESURER__.distance(selectorA, selectorB)
259
301
  ```
260
302
 
261
- A small selection can produce evidence such as:
303
+ A useful result can be:
262
304
 
263
305
  ```text
264
306
  Card A width: 320px
@@ -267,35 +309,26 @@ A → B horizontal gap: 24px
267
309
  A/B top-edge delta: 0px
268
310
  ```
269
311
 
270
- For large repeated sets, focus on adjacent/repeated/user-relevant relationships instead of dumping all O(n²) pairs.
312
+ For large repeated sets, focus on adjacent or user-relevant relationships rather than dumping all O(n²) pairs.
271
313
 
272
- ## Context is required before and after meaningful visual edits
273
-
274
- ### Before editing
275
-
276
- If the user supplied visual evidence, retain it before HMR can replace nodes:
277
-
278
- ```js
279
- const before = await window.__MESURER__.context({ scope: "selection" })
280
- ```
314
+ ## Fresh evidence is required after visual edits
281
315
 
282
- or:
316
+ Wait for the actual rendered page:
283
317
 
284
318
  ```js
285
- const before = await window.__MESURER__.context({ annotation: annotationId })
319
+ await window.__MESURER__.stable()
286
320
  ```
287
321
 
288
- ### After editing
322
+ Then use the strongest applicable path.
289
323
 
290
- First wait for the actual rendered page:
324
+ Arrange:
291
325
 
292
326
  ```js
293
- await window.__MESURER__.stable()
327
+ await window.__MESURER__.showArrange(arrangeId, "live")
328
+ const review = await window.__MESURER__.reviewArrange(arrangeId)
294
329
  ```
295
330
 
296
- Then obtain fresh evidence using the strongest path.
297
-
298
- Human annotation:
331
+ Annotation:
299
332
 
300
333
  ```js
301
334
  const review = await window.__MESURER__.review(annotationId)
@@ -307,7 +340,7 @@ Still-relevant human selection:
307
340
  const after = await window.__MESURER__.context({ scope: "selection" })
308
341
  ```
309
342
 
310
- Agent knows exact changed rendered targets:
343
+ Agent-known changed targets:
311
344
 
312
345
  ```js
313
346
  const after = await window.__MESURER__.select([
@@ -316,35 +349,15 @@ const after = await window.__MESURER__.select([
316
349
  ])
317
350
  ```
318
351
 
319
- Target identity is ambiguous after the change: ask the user to select the intended result and then read selection context.
320
-
321
- For meaningful visual work, lint/typecheck/tests/build are not enough. If Mesurer is available and the changed UI can be identified, a harness should not report completion without fresh Mesurer evidence for that UI.
322
-
323
- ## Annotation review
324
-
325
- ```js
326
- await window.__MESURER__.stable()
327
- const review = await window.__MESURER__.review(annotationId)
328
- ```
329
-
330
- `review()` compares the human baseline against fresh context and reports exact pixel changes/missing evidence:
352
+ For meaningful visual work, lint/typecheck/tests/build are not enough. They validate implementation mechanics, not the rendered result.
331
353
 
332
- ```text
333
- gap: 37px → 24px
334
- left-edge mismatch: 4px → 0px
335
- width: 318px → 320px
336
- expected target/guide/measurement missing
337
- ```
338
-
339
- If the requested result remains numerically wrong, continue editing.
354
+ ## Screenshot ownership
340
355
 
341
- ## Human screenshot plugin vs agent screenshot evidence
356
+ Mesurer has two different screenshot roles.
342
357
 
343
- Mesurer has two intentionally different screenshot paths.
358
+ ### Human camera tool
344
359
 
345
- ### Human capture tool
346
-
347
- The optional `mesurer.screenshot` plugin gives the person a camera tool inside Mesurer:
360
+ The optional `mesurer.screenshot` plugin gives the person a camera tool:
348
361
 
349
362
  ```ts
350
363
  import { mountMesurer } from "mesurer-solid"
@@ -355,15 +368,11 @@ const mesurer = mountMesurer({
355
368
  })
356
369
  ```
357
370
 
358
- The user can drag a viewport region, capture a real HiDPI-aware PNG, optionally copy/download it, keep a persistent draggable thumbnail, and open a larger Copy/Save viewer. Normal browser hosts use `getDisplayMedia()`; the first-party Chrome extension uses `chrome.tabs.captureVisibleTab()` through its isolated-world bridge and therefore avoids the screen-share chooser.
359
-
360
- For advanced mounted integrations, the typed `MesurerScreenshotService` is available from the plugin host under service id `screenshot`. It is not part of `window.__MESURER__`'s context/delivery capability surface.
361
-
362
- Agents should preserve an existing human screenshot preview unless the task explicitly asks them to test, close, replace, or otherwise manipulate the screenshot feature.
371
+ 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.
363
372
 
364
- ### Agent verification screenshot
373
+ ### Agent screenshot evidence
365
374
 
366
- For coding-agent verification, the outer harness should normally continue to own screenshot bytes so the task can control the exact browser, viewport, timing, and artifact destination. Mesurer supplies clean capture scope/presentation:
375
+ 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:
367
376
 
368
377
  ```js
369
378
  const plan = await window.__MESURER__.capturePlan({ scope: "selection" })
@@ -376,35 +385,38 @@ try {
376
385
  }
377
386
  ```
378
387
 
379
- Use the signals together:
388
+ Arrange uses the same ownership model through `arrangeCapturePlan()` while adding explicit Before/Desired/Live presentation.
389
+
390
+ Use both signals:
380
391
 
381
392
  ```text
382
- Mesurer context → exact geometry, box model, styles, distances, overflow
383
- real screenshot → composition, hierarchy, clipping, color, visual judgment
393
+ Mesurer context/review → geometry, box model, styles, distances, overflow
394
+ real screenshot → composition, hierarchy, clipping, color, visual judgment
384
395
  ```
385
396
 
386
- Do not replace exact Mesurer measurements with pixel estimates from either screenshot path.
387
-
388
397
  ## Source-mounted usage
389
398
 
390
- When Mesurer is intentionally mounted from application code:
399
+ For context plus Arrange:
391
400
 
392
401
  ```ts
393
- import { contextPlugin, mountMesurer } from "mesurer-solid"
402
+ import {
403
+ contextPlugin,
404
+ mountMesurer,
405
+ } from "mesurer-solid"
406
+ import { arrangePlugin } from "mesurer-solid/arrange"
394
407
 
395
408
  const mesurer = mountMesurer({
396
409
  agent: true,
397
- plugins: [contextPlugin()],
410
+ plugins: [
411
+ contextPlugin(),
412
+ arrangePlugin(),
413
+ ],
398
414
  })
399
415
  ```
400
416
 
401
- The same API is available on `mesurer.agent` and, when configured, `window.__MESURER__`:
402
-
403
- ```js
404
- const context = await mesurer.agent.select("#target")
405
- ```
417
+ The same API is available on `mesurer.agent` and, when configured, `window.__MESURER__`.
406
418
 
407
- Screenshot capture can be composed independently with `screenshotPlugin()` when the host wants the human camera tool. No transport callback is involved.
419
+ Arrange remains optional. Applications that only want the base inspector or context workflow do not pay for the Arrange entry-point bundle.
408
420
 
409
421
  ## Low-level inspection
410
422
 
@@ -421,25 +433,25 @@ await window.__MESURER__.state()
421
433
  await window.__MESURER__.stable()
422
434
  ```
423
435
 
424
- Prefer `context()`, `select()`, and `review()` for visual development because they provide context that directly carries human intent or agent-selected affected UI into reasoning.
436
+ Prefer `arrangements()`, `context()`, `select()`, `reviewArrange()`, and `review()` for visual development because those paths preserve human meaning and return evidence the agent can reason from directly.
425
437
 
426
- ## Harness completion rule
438
+ ## Completion rule
427
439
 
428
- A good harness-level visual completion loop is:
440
+ A good harness-level loop is:
429
441
 
430
442
  ```text
431
443
  1. discover/reuse Mesurer and preserve human state
432
- 2. consume existing human context
433
- 3. if target ambiguous, ask user to select
434
- 4. otherwise select known affected rendered target(s) when needed
435
- 5. consume returned context
444
+ 2. consume relevant Arrange intent first
445
+ 3. capture Before/Desired when useful, before source edits
446
+ 4. consume existing annotation/selection context
447
+ 5. resolve exact targets; ask only when genuinely ambiguous
436
448
  6. edit normal source
437
449
  7. wait for stable render
438
- 8. get fresh review/context; use select() for known changed targets
439
- 9. optionally capture a real screenshot through the outer harness
440
- 10. iterate until rendered evidence supports the claim
450
+ 8. switch Arrange to Live when applicable
451
+ 9. get fresh Arrange review/context and optional screenshot
452
+ 10. iterate until rendered evidence supports completion
441
453
  ```
442
454
 
443
- When the task is specifically testing Mesurer's screenshot plugin, exercise its camera/preview/viewer path as the feature under test; otherwise do not substitute it for the harness's normal screenshot primitive.
455
+ Do not clear Arrange history, alter human measurements/guides, replace live Mesurer state, or use a temporary preview to make unfinished source work appear correct.
444
456
 
445
- **Context is the output of the Mesurer step, not an optional side effect.**
457
+ **Rendered evidence is the output of the Mesurer step, not an optional side effect.**