@penpair/web 0.3.3 → 0.3.5

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/docs/coverage.md CHANGED
@@ -48,3 +48,17 @@ Ordinary `baselines` can publish a coherent capture of its configured frames whi
48
48
  Legacy route/viewport cases continue generating their existing Reflection entries. Rich case metadata moves to `pendingCases`, including its approved provenance and capture scale, until an implementation provider explicitly maps theme setup, fixture/data loading, fonts and state entry. It does not silently generate several copies of a default-state screenshot under different labels. D4 supplies that provider integration.
49
49
 
50
50
  Browser interaction, keyboard and accessibility checks remain separate requirements. A board's dimensions do not establish that it is clickable or WCAG-compliant. The [WCAG target-size guidance](https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html) includes exceptions and spacing rules that need actual target semantics. [Playwright's visual comparison guidance](https://playwright.dev/docs/test-snapshots) also explains why stable rendering environments matter; a screenshot alone does not establish behavior.
51
+
52
+ Baseline entries require `frame` or `frameId`, or both. `frameId` is a unique board UUID and resolves at any depth on the configured page; use it for frames inside section boards on a release page. Name-only entries keep top-level exact-name matching and reject ambiguous names. For example:
53
+
54
+ ```json
55
+ {
56
+ "frameId": "10216397-acdf-805e-8008-d69b71f841d4",
57
+ "frame": "Login / Empty",
58
+ "id": "login-empty"
59
+ }
60
+ ```
61
+
62
+ When both are supplied, a different current board name reports `renamed` and the entry is never captured under its stale name. Review the rename and update the expected name before retrying. ID-only entries follow the ID and report its current name. Page searches stop with an explicit error if the 10,000-shape budget truncates the listing.
63
+
64
+ `approve --case CASE_ID --page PAGE --frame ID` compares `--frame` directly with a configured `frameId`; name-only cases retain the unique-name check. Nested frames use the same exact frame-ID capture identity for approval matching. The baseline manifest continues to record `frameId`; Reflection case format is unchanged.
package/docs/guide.md CHANGED
@@ -104,8 +104,11 @@ For registered writes, supply an explicit `verify({ inspect, apply, readback })`
104
104
  ```
105
105
 
106
106
  - `frame` is the exact name of a top-level frame on the page; two frames with the same name is an error, so the reference is never ambiguous.
107
+ - Each entry requires `frame` or `frameId` (or both). `frameId` is a board UUID, unique across entries, resolved anywhere on the configured page. Frames inside boards, such as release frames inside section boards, need `frameId`. Name-only entries still match top-level frames only.
108
+ - With both fields, `frame` is an expected name: a changed name reports `renamed` and captures nothing for that entry. Review and update the expected name before retrying. ID-only entries use the board's current name in reports. A truncated page search (10,000 shapes) stops the capture instead of using a partial listing.
109
+ - For example: `{ "frameId": "10216397-acdf-805e-8008-d69b71f841d4", "frame": "Login / Empty", "id": "login-empty", "route": "login" }`.
107
110
  - `id` names the image (`<id>.png`) and the check. `route` is the route in your app this frame is the design of; a frame without a route is exported but gets no check.
108
- - Without `--apply` the command only looks and reports each frame as `new`, `same`, `changed`, `unstable` (the export never settled) or `missing`. `--apply` writes new images, `penpair-baselines.json` (file, revision, sizes, hashes) and `reflection-cases.json`. A `changed` image is replaced only with `--apply --update`: that is the act of approving the new design, and the owner's call. The exit code is 2 when a design differs from its image, 1 when a frame is missing or unstable.
111
+ - Without `--apply` the command only looks and reports each frame as `new`, `same`, `changed`, `unstable` (the export never settled) or `missing`/`renamed`. `--apply` writes new images, `penpair-baselines.json` (file, revision, sizes, hashes) and `reflection-cases.json`. A `changed` image is replaced only with `--apply --update`: that is the act of approving the new design, and the owner's call. The exit code is 2 when a design differs from its image, 3 when a frame is missing, renamed or unstable.
109
112
 
110
113
  The generated `reflection-cases.json` holds, per route, the viewports (the image's exact size) and the `visualSmoke` cases (review-only, `strict: false`). A Reflection config uses it like this; only the route's own expectations are written by hand:
111
114
 
package/docs/mcp.md CHANGED
@@ -6,12 +6,29 @@ penpair mcp --root /absolute/path/to/project
6
6
 
7
7
  Use the project's reviewed local executable. Startup requires an absolute root, valid project config and owner-confirmed file pin. The server keeps that target for its lifetime and refuses a changed target until restart/review. Each call gets request-scoped root state; it never calls `process.chdir`. Even basic reads use strict same-execution file guards. Environment/project `.env.local` endpoint resolution remains available; unrelated global Codex/Claude endpoint fallback is disabled. Keep credentials in the private connection flow, outside client configuration examples.
8
8
 
9
- Default tools: pages, bounded tree/audit/inspection, bounded token dump, offline baseline coverage, doctor, derived spec, and stable export to a path inside the project. Export creates/replaces a local file and has a write annotation. There is no raw-code tool or unrestricted command forwarding. Each typed input is validated independently of the client schema. No write tool is advertised by default.
9
+ Default tools: pages, bounded tree/audit/inspection, bounded token dump, offline baseline coverage, doctor, derived spec, and stable export to a path inside the project. Export creates/replaces a local file and has a write annotation. There is no raw-code tool or unrestricted command forwarding. Each typed input is validated independently of the client schema. No Penpot write tool is advertised by default.
10
10
 
11
11
  Explicit `--allow-writes` additionally advertises `run_registered`. It accepts a registered operation name and scalar parameters, defaults to inspection, and requires explicit `apply:true` for design writes. Explicit `resume` requires apply and the original journal; file/instance guards, local/shared advisory lease, same-execution preconditions, checkpoints supported by the underlying command, and independent readback remain in the same services. Registered modules execute trusted project code, including imports; they must keep stdout for MCP and log through the command context. This is not an execution sandbox. Adapter-specific commands remain available through the CLI; the neutral server does not guess library-specific tool schemas.
12
12
 
13
13
  Requests return the version-1 CLI envelope as text plus structured content. Default cooperative deadline: 60 seconds; SDK cancellation propagates into the service. Arbitrary trusted code can ignore cancellation. A 256 KiB response cap returns an explicit incomplete envelope rather than apparently successful truncated data; uncertain writes retain their uncertain outcome/run ID. Use narrower inspection or CLI artifact output for larger evidence. Stdio has no HTTP listener or background polling.
14
14
 
15
+ ## Tool annotations
16
+
17
+ Every advertised tool explicitly declares boolean `readOnlyHint`, `destructiveHint`, `idempotentHint` and `openWorldHint` values. These are advisory metadata; file guards, typed validation and write opt-in still enforce the boundaries.
18
+
19
+ | Tools | readOnlyHint | destructiveHint | idempotentHint | openWorldHint |
20
+ | --- | --- | --- | --- | --- |
21
+ | `run_status`, `baselines_status` (offline local evidence) | true | false | true | false |
22
+ | `pages`, `tree`, `audit`, `inspect`, `tokens_dump`, `project_status`, `doctor`, `design_spec` (may contact Penpot or its deployment) | true | false | true | true |
23
+ | `export` (creates or replaces a local image from live Penpot) | false | true | false | true |
24
+ | `run_registered` (opt-in trusted code, potentially mutating) | false | true | false | true |
25
+
26
+ `export` can overwrite an existing artifact, so its destructive hint is true. It captures the current design, so callers must not assume repeated calls preserve the earlier image. `run_registered` retains conservative hints even when a particular invocation only previews: its metadata must cover the registered code's possible effects. `archive` is an internal registered operation invoked through `run_registered`, not a separately advertised MCP tool.
27
+
28
+ ## Code execution boundaries
29
+
30
+ The host calls layout-settling policy as an ordinary imported function. The same self-contained function is serialized into generated Penpot snippets; the host does not evaluate its source. Project snippet validation parses JavaScript without running it. Registered project modules remain trusted executable code, and design snippets still execute in the connected Penpot editor under the existing guards.
31
+
15
32
  ## Client registration
16
33
 
17
34
  These are reviewable examples; no client settings were edited. Replace executable/root paths for each developer. The executable should be the reviewed project installation, not an automatically fetched latest package.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@penpair/web",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "The penpair command for Penpot on the web (design.penpot.app or your team's own): guided setup, a safe write protocol, skills for AI agents. Includes everything in @penpair/core.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -48,7 +48,7 @@
48
48
  "access": "public"
49
49
  },
50
50
  "dependencies": {
51
- "@penpair/core": "0.3.3"
51
+ "@penpair/core": "0.3.5"
52
52
  },
53
53
  "scripts": {
54
54
  "build": "tsc -p tsconfig.json",