@penpair/web 0.4.0 → 0.5.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/README.md +30 -0
- package/docs/browser-sessions.md +147 -0
- package/docs/compatibility.md +4 -2
- package/docs/copy-between-pages.md +204 -0
- package/docs/design-releases.md +27 -2
- package/docs/layout-settling.md +17 -1
- package/docs/mcp.md +63 -3
- package/docs/run-file.md +2 -0
- package/docs/troubleshooting.md +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -56,6 +56,36 @@ Then choose a scratch page and agree on a small design task. The workflow is: in
|
|
|
56
56
|
|
|
57
57
|
The installed skills cover **setup → design → recipes → handoff → verification**, with `design-judgment` for visual hierarchy. Ask the assistant to name the skill it uses. For frontend work, `penpair-handoff` carries design evidence into implementation; `penpair-verify` guides browser comparison, image review, fixes and recapture. [Check skill discovery and behavior](https://github.com/niklas-westman/penpair/blob/main/docs/skill-validation.md).
|
|
58
58
|
|
|
59
|
+
## Where the command and tools live
|
|
60
|
+
|
|
61
|
+
Install one command package in your application project. Both expose the same
|
|
62
|
+
`penpair` command; the core library is installed as a dependency.
|
|
63
|
+
|
|
64
|
+
| Surface | Where it comes from | How you discover it |
|
|
65
|
+
| --- | --- | --- |
|
|
66
|
+
| Hosted/team Penpot CLI | `@penpair/web` | `pnpm exec penpair --help` |
|
|
67
|
+
| CLI with local Penpot containers | `@penpair/docker` | The same command, plus instance lifecycle commands |
|
|
68
|
+
| Engine and shipped agent skills | `@penpair/core` | Library exports and `penpair skills`; core has no executable |
|
|
69
|
+
| Penpair MCP tools | Your installed command, started as a stdio server | Register the executable with `mcp --root /absolute/path/to/project` in your assistant |
|
|
70
|
+
| Your assistant's browser/computer controls | The assistant host, separately from Penpair | Host configuration; installing Penpair does not add these controls |
|
|
71
|
+
|
|
72
|
+
For example, register `/absolute/path/to/project/node_modules/.bin/penpair` with
|
|
73
|
+
arguments `["mcp", "--root", "/absolute/path/to/project"]`. That exposes typed
|
|
74
|
+
inspection, status, doctor, spec and export tools for the pinned project. It does
|
|
75
|
+
not expose every CLI command or arbitrary browser control. See the
|
|
76
|
+
[tool inventory and client configuration](https://github.com/niklas-westman/penpair/blob/main/docs/mcp.md).
|
|
77
|
+
|
|
78
|
+
Explicit `--allow-writes` additionally exposes registered operations and the
|
|
79
|
+
experimental `design_release_copy` tool. Both preview by default; applying a
|
|
80
|
+
native copy also requires a loopback browser debugging port and existing browser
|
|
81
|
+
clipboard read/write capability. Penpair does not grant those permissions. The equivalent CLI
|
|
82
|
+
starts with `penpair design-release copy --source-page PAGE --frame BOARD_ID
|
|
83
|
+
--release 1.2.0`. Copying creates native boards and transfer evidence; it does not
|
|
84
|
+
approve a full design release. Read the
|
|
85
|
+
[native copy guide](https://github.com/niklas-westman/penpair/blob/main/docs/copy-between-pages.md)
|
|
86
|
+
before applying it. `penpair wake` remains CLI-only.
|
|
87
|
+
For Claude and other hosts, read the [CLI/MCP prerequisites and current qualification](https://github.com/niklas-westman/penpair/blob/main/docs/copy-between-pages.md#using-from-claude-or-other-hosts); the native-UI test driver is not shipped as a fallback.
|
|
88
|
+
|
|
59
89
|
## Add your companions
|
|
60
90
|
|
|
61
91
|
| Package | Add it when | What it contributes |
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Recovering a suspended Penpot tab
|
|
2
|
+
|
|
3
|
+
Penpair executes live design operations through the Penpot browser plugin. A
|
|
4
|
+
reachable Penpot server does not establish that its editor tab is responsive.
|
|
5
|
+
Browser timer throttling, freezing and discarding are separate from computer
|
|
6
|
+
sleep; keeping the computer awake does not prevent them.
|
|
7
|
+
|
|
8
|
+
## Wake an existing tab
|
|
9
|
+
|
|
10
|
+
From the configured project, with an owner-confirmed file pin and an existing
|
|
11
|
+
MCP connection:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
penpair wake --debug-port 9222
|
|
15
|
+
penpair wake --debug-port 9222 --timeout-ms 10000 --json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The browser must already expose a debugging endpoint on `127.0.0.1` at the
|
|
19
|
+
specified port. Penpair does not start a browser or enable debugging in an
|
|
20
|
+
existing browser. `--timeout-ms` accepts 1000–30000; the default 5000 ms budget
|
|
21
|
+
covers activation and verification together.
|
|
22
|
+
|
|
23
|
+
Penpair lists the browser's targets, requires exactly one editor page matching
|
|
24
|
+
both the project's Penpot origin and pinned `file-id`, then requests activation
|
|
25
|
+
through `/json/activate/<target-id>`. It refuses duplicate matching tabs rather
|
|
26
|
+
than choosing one. Hosted deployments require an exact origin. For a local
|
|
27
|
+
instance, both `http://127.0.0.1:<frontend-port>` and
|
|
28
|
+
`http://localhost:<frontend-port>` are accepted, matching Penpair's existing
|
|
29
|
+
opening commands. Other hosts and ports are refused; duplicate matching tabs
|
|
30
|
+
across the two aliases still fail.
|
|
31
|
+
|
|
32
|
+
After activation, Penpair performs a fresh read with a challenge and checks the
|
|
33
|
+
actual file ID. Exit 0 means activation was acknowledged and that read verified
|
|
34
|
+
the intended editor. Activation can succeed while readiness fails: JSON then
|
|
35
|
+
reports `activated: true, ready: false`. A browser may also leave a minimized
|
|
36
|
+
window minimized; check the actual window when activation alone is insufficient.
|
|
37
|
+
|
|
38
|
+
This command does not reload, navigate, restart the plugin, inject page code or
|
|
39
|
+
resume a write. Its `keepAlive: "none"` result means activation is momentary
|
|
40
|
+
recovery, with no sustained keep-alive mechanism. Browser focus can affect legacy
|
|
41
|
+
MCP routing, which is why a fresh identity check follows activation. A target can
|
|
42
|
+
navigate between discovery and activation; the acknowledgment is not an atomic
|
|
43
|
+
guarantee of tab identity or exclusive ownership.
|
|
44
|
+
|
|
45
|
+
If a write became uncertain, retain its journal, inspect the intended target
|
|
46
|
+
independently and reconcile it before explicitly resuming. Waking a tab does not
|
|
47
|
+
establish whether the previous write completed. See [recovery](recovery.md).
|
|
48
|
+
|
|
49
|
+
## Understand doctor evidence
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
penpair doctor --json
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Doctor stays read-only: it does not activate tabs or install a keep-alive.
|
|
56
|
+
The execution check exposes `evidence.pluginHealth`:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"state": "suspended",
|
|
61
|
+
"heartbeatAgeMs": 36000,
|
|
62
|
+
"heartbeatSource": "upstream-error",
|
|
63
|
+
"keepAlive": { "method": "unknown", "verified": false }
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
| Field | Meaning |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `state` | `responsive` after a verified fresh read; `suspended` when the upstream failure explicitly reports suspension; otherwise `unknown`. |
|
|
70
|
+
| `heartbeatAgeMs` | Age reported in an upstream error such as `no heartbeat for 36s`; `null` when unavailable. |
|
|
71
|
+
| `heartbeatSource` | `upstream-error` when an age was parsed, otherwise `unavailable`. |
|
|
72
|
+
| `keepAlive` | The current connection does not expose independently verified browser keep-alive telemetry, so its method remains `unknown` and `verified` remains `false`. |
|
|
73
|
+
|
|
74
|
+
The check's `observedAt` records when Penpair observed this evidence. A successful
|
|
75
|
+
read does not imply a zero-second heartbeat age or prove that the next background
|
|
76
|
+
request will succeed. A generic timeout does not establish suspension.
|
|
77
|
+
|
|
78
|
+
## Browser settings and a dedicated window
|
|
79
|
+
|
|
80
|
+
Chrome's **Settings → Performance → Always keep these sites active** exclusion
|
|
81
|
+
can prevent Memory Saver from deactivating the configured Penpot site. It does
|
|
82
|
+
not establish that background timers or Penpot layout will run without delay.
|
|
83
|
+
See [Chrome's performance settings](https://support.google.com/chrome/answer/12929150?hl=en).
|
|
84
|
+
|
|
85
|
+
For an explicit experiment, start a separate Chrome instance with its own profile
|
|
86
|
+
outside the repository. This macOS example uses an installed Google Chrome:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
|
|
90
|
+
--user-data-dir="$HOME/Library/Application Support/Penpair/browser-profile" \
|
|
91
|
+
--remote-debugging-address=127.0.0.1 \
|
|
92
|
+
--remote-debugging-port=9222 \
|
|
93
|
+
--disable-background-timer-throttling \
|
|
94
|
+
--disable-renderer-backgrounding \
|
|
95
|
+
--disable-backgrounding-occluded-windows \
|
|
96
|
+
--new-window https://design.penpot.app
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Use the project's configured origin for a different deployment. These launch
|
|
100
|
+
switches do not retrofit an already running ordinary browser instance. Since
|
|
101
|
+
Chrome 136, remote debugging requires a non-default user-data directory. Keep
|
|
102
|
+
that profile private: it can retain account cookies and cached designs. Keep the
|
|
103
|
+
debugging port on loopback and do not expose it on a network. See
|
|
104
|
+
[Chrome's debugging changes](https://developer.chrome.com/blog/remote-debugging-port/).
|
|
105
|
+
|
|
106
|
+
Login and plugin connection in that dedicated profile remain human setup steps;
|
|
107
|
+
Penpair does not copy credentials or complete them automatically. The flags above
|
|
108
|
+
are an experimental configuration, not a verified guarantee of background
|
|
109
|
+
Penpot operation. No managed-browser lifecycle, browser dependency or browser
|
|
110
|
+
download is added by the wake command.
|
|
111
|
+
|
|
112
|
+
A silent audio track does **not** count for Chrome's audio timer-throttling
|
|
113
|
+
exemption. Web Workers, SharedWorkers and Web Locks have different lifecycle
|
|
114
|
+
behavior, but are not verified here as a complete solution for the Penpot plugin.
|
|
115
|
+
Penpair does not inject these workarounds. See
|
|
116
|
+
[Chrome timer throttling](https://developer.chrome.com/blog/timer-throttling-in-chrome-88)
|
|
117
|
+
and [the Page Lifecycle API](https://developer.chrome.com/docs/web-platform/page-lifecycle-api).
|
|
118
|
+
|
|
119
|
+
## Verification status and the remaining acceptance trial
|
|
120
|
+
|
|
121
|
+
The initial manual trial raised an existing Penpot window through native browser
|
|
122
|
+
controls without reloading it. Port 9222 was unavailable, and the chat's MCP
|
|
123
|
+
connection reported no connected Penpot instance. That trial therefore did not
|
|
124
|
+
prove restored plugin heartbeats. A separate real CDP trial used the installed
|
|
125
|
+
Brave browser with a temporary unauthenticated profile and the three background
|
|
126
|
+
flags above. The wake implementation changed a disposable local fixture page
|
|
127
|
+
from hidden to visible. No Penpot account or design was loaded, so this proves
|
|
128
|
+
browser activation only. Automated tests also cover target selection, activation
|
|
129
|
+
requests, deadlines and refusal paths using fake and local HTTP endpoints.
|
|
130
|
+
|
|
131
|
+
The required sustained-background acceptance trial remains **unverified**. Use an
|
|
132
|
+
owner-authorized disposable file and the intended installed browser build:
|
|
133
|
+
|
|
134
|
+
1. Record the browser version, launch flags, profile, settings and initial doctor
|
|
135
|
+
evidence. Verify the file pin and establish a normal responsive connection.
|
|
136
|
+
2. Run 30 frames, one journaled write per frame, each lasting 20–60 seconds, with
|
|
137
|
+
the Penpot window behind another window. Do not manually focus or reload it.
|
|
138
|
+
3. Independently read back the results, export and visually inspect them. Record
|
|
139
|
+
heartbeat failures, layout timeouts and any required intervention.
|
|
140
|
+
4. Test minimized, occluded and screen-locked states separately; success in one
|
|
141
|
+
state does not establish the others. Computer sleep is a separate boundary.
|
|
142
|
+
5. If any write becomes uncertain, stop and reconcile before replay. Do not
|
|
143
|
+
increase retries or weaken journal, identity or layout checks to pass.
|
|
144
|
+
|
|
145
|
+
One successful activation is not a passing 30-frame run. The dedicated-browser
|
|
146
|
+
configuration and any future plugin keep-alive require that real acceptance
|
|
147
|
+
trial before they can be advertised as reliable background execution.
|
package/docs/compatibility.md
CHANGED
|
@@ -12,9 +12,11 @@ What has been checked, where, and what differs. Update it whenever a Penpot is p
|
|
|
12
12
|
| Deep check (`probe --deep --write`): flex layout, text, token set and binding, components and swap, clone, PNG export, clean-up | all steps pass, nothing left behind (run on a fresh instance's empty file) | all steps pass, nothing left behind (run twice) |
|
|
13
13
|
| `pages`, `tree`, `audit`, `tokens dump`, `export` (waits for a stable render), `archive` with `--apply`, a project snippet that writes (`run seed-demo`) | all in use | all verified on seeded sample content |
|
|
14
14
|
| `doctor` (external profile) | ok | ok |
|
|
15
|
+
| Cross-page clone followed by `appendChild` / `insertChild` | refused with either page active; scratch cleanup verified ([details](copy-between-pages.md)) | not tried |
|
|
15
16
|
| `init`, `up`, `doctor` for a Penpot penpair starts (a fresh instance on its own port, then the owner's account, key and plugin connection) | ok: 16 seconds to answer with the images cached; `doctor` all ok | not applicable |
|
|
16
17
|
|
|
17
18
|
## Differences found
|
|
19
|
+
- **Cross-page reparenting is refused on local 2.18.3.** Clones stay on the source page. Use native editor copy/paste; see [copying between pages](copy-between-pages.md).
|
|
18
20
|
- **A new token set starts inactive, with no themes in the file.** Seen on both the hosted Penpot and a fresh local instance. (An earlier note that local sets start active was wrong or applied to a file with themes.)
|
|
19
21
|
- **A token binding is recorded after the call, not during it.** On the hosted Penpot it appeared after about half a second to a few seconds; reading it straight away shows nothing. Code that checks a binding has to wait for it.
|
|
20
22
|
- **Applying the same token again removes the binding** (seen on the hosted Penpot, as in the local notes).
|
|
@@ -42,11 +44,11 @@ The `Scratch Penpot compatibility smoke` workflow is manual-dispatch only. Confi
|
|
|
42
44
|
|
|
43
45
|
Library helpers accept the project's guarded client:
|
|
44
46
|
|
|
45
|
-
- `waitForStableLayout(client, { shapeId, timeoutMs })`: prefers supported native completion; otherwise polls geometry.
|
|
47
|
+
- `waitForStableLayout(client, { shapeId, timeoutMs })`: prefers supported native completion; otherwise polls geometry. In `auto` mode a failed native wait can fall back to geometry. Budget overflow reports explicitly partial evidence; target changes, malformed samples and timeout cannot pass. Geometry stability does not establish token/font/pixel correctness; independent readback and stable exports remain necessary. Default operation/export and token verification paths use this helper; see [layout settling](layout-settling.md).
|
|
46
48
|
- `validateFileIntegrity(client)`: distinguishes unsupported from a valid empty issue list or actual referential-integrity problems.
|
|
47
49
|
- `createCheckpoint(client, { label, runId }, { apply })`: optional native version history. Without apply it inspects; with apply it saves a run-keyed named version once and independently finds it again. Reusing that run ID reuses an existing checkpoint; it does not provide atomic cross-client locking. No automatic restore/rollback is performed.
|
|
48
50
|
|
|
49
|
-
Current upstream references: [Penpot API](https://doc.plugins.penpot.app/interfaces/Penpot), [File API](https://doc.plugins.penpot.app/interfaces/File), [FileVersion API](https://doc.plugins.penpot.app/interfaces/FileVersion). Unit fixtures cover missing, present and throwing APIs.
|
|
51
|
+
Current upstream references: [Penpot API](https://doc.plugins.penpot.app/interfaces/Penpot), [File API](https://doc.plugins.penpot.app/interfaces/File), [FileVersion API](https://doc.plugins.penpot.app/interfaces/FileVersion). Unit fixtures cover missing, present and throwing APIs. A read-only layout check on local 2.18.3 on 2026-10-25 observed two existing boards: three equal geometry samples covered 192 nodes; a five-node budget returned `method: "partial"`, `nodeCount: 5`, `truncated: true` and both requested root IDs. This does not prove a live write on a page over 10,000 nodes, native wait timing, integrity validation or version-history behavior. Those remain unverified.
|
|
50
52
|
|
|
51
53
|
## Hosted archive candidate
|
|
52
54
|
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Copy native boards between pages
|
|
2
|
+
|
|
3
|
+
`penpair design-release copy` is an experimental native-editor transfer within
|
|
4
|
+
the project's pinned Penpot file. It copies selected boards to
|
|
5
|
+
`release/<version>`, leaves their originals in place and independently captures
|
|
6
|
+
source and destination evidence. It uses the browser's native clipboard rather
|
|
7
|
+
than trying to move a plugin shape proxy between pages.
|
|
8
|
+
|
|
9
|
+
This is a page-copy operation, not a complete design-release assembly or owner
|
|
10
|
+
approval. It produces a private transfer receipt, not a fabricated
|
|
11
|
+
`release.json`. The stricter [design release verification](design-releases.md)
|
|
12
|
+
requirements still apply before a full release can be finalized.
|
|
13
|
+
|
|
14
|
+
## Prerequisites and preview
|
|
15
|
+
|
|
16
|
+
Use the reviewed project installation, with a valid configuration, an
|
|
17
|
+
owner-confirmed file pin and a connected responsive Penpot plugin. Choose one
|
|
18
|
+
source page and 1–100 distinct board IDs from that page. IDs must identify boards,
|
|
19
|
+
not arbitrary shapes; selecting a board together with its descendant board is
|
|
20
|
+
refused. Boards nested in sections can be selected by their IDs.
|
|
21
|
+
The PoC bounds each observed page to 20,000 nodes and the native clipboard
|
|
22
|
+
payload to 16 MiB; exceeding either limit stops the transfer.
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
# Replace these board IDs and page name with observed source identities.
|
|
26
|
+
penpair design-release copy --source-page "Screens" \
|
|
27
|
+
--frame SOURCE_BOARD_ID --frame ANOTHER_BOARD_ID --release 1.2.0
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Preview resolves the source and destination, inventories existing content and
|
|
31
|
+
reports the planned selection. It does not create a page, alter selection or
|
|
32
|
+
use the clipboard. The destination is always `release/1.2.0` in the same pinned
|
|
33
|
+
file; this command does not copy between files or deployments.
|
|
34
|
+
|
|
35
|
+
A unique existing destination can be reused without replacing its content.
|
|
36
|
+
Missing destinations are created on apply. Ambiguous page names, finalized
|
|
37
|
+
release ownership and conflicting ownership markers are refused. New copies
|
|
38
|
+
are arranged separately from existing destination content; existing frames are
|
|
39
|
+
not moved or normalized.
|
|
40
|
+
|
|
41
|
+
## Apply through the native editor
|
|
42
|
+
|
|
43
|
+
Review the preview and authorize the actual transfer before applying:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
penpair design-release copy --source-page "Screens" \
|
|
47
|
+
--frame SOURCE_BOARD_ID --frame ANOTHER_BOARD_ID --release 1.2.0 \
|
|
48
|
+
--debug-port 9222 --apply
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The browser must already expose a loopback debugging port. See
|
|
52
|
+
[browser setup and recovery](browser-sessions.md) for an isolated-profile example.
|
|
53
|
+
Clipboard APIs also require a secure browser context, normally HTTPS or local
|
|
54
|
+
loopback HTTP. See the browser vendor's [clipboard access guidance](https://web.dev/articles/async-clipboard).
|
|
55
|
+
Penpair adds no browser dependency or browser download and does not start a
|
|
56
|
+
managed session. It verifies the browser origin and pinned file; configured local
|
|
57
|
+
instances may use the equivalent `localhost`/`127.0.0.1` HTTP origin on the same
|
|
58
|
+
port. Hosted deployments require the exact configured origin.
|
|
59
|
+
|
|
60
|
+
The bundled transport also requires the browser's existing clipboard read/write
|
|
61
|
+
capability for that editor. Penpair does not grant clipboard permissions. If the
|
|
62
|
+
capability is unavailable, denied or waiting for a browser prompt, the operation
|
|
63
|
+
fails closed before paste. Complete any intended browser permission decision
|
|
64
|
+
separately; a debugging connection alone does not establish clipboard access.
|
|
65
|
+
|
|
66
|
+
Applying changes page and board selection, foregrounds the editor and dispatches
|
|
67
|
+
native Copy/Paste. The Penpot canvas must have focus, with no text field,
|
|
68
|
+
content-editable region, plugin iframe or dialog focused. Penpair refuses unsafe
|
|
69
|
+
focus instead of sending shortcuts into another control. This replaces the
|
|
70
|
+
system clipboard contents; previous clipboard contents are not automatically
|
|
71
|
+
restored. Avoid using the clipboard or changing editor focus during the transfer.
|
|
72
|
+
A local clipboard lease excludes cooperating Penpair sessions, not unrelated
|
|
73
|
+
applications or manual actions.
|
|
74
|
+
|
|
75
|
+
Before dispatching Copy, the transport clears the clipboard to a unique sentinel.
|
|
76
|
+
It then waits for an actual native Penpot JSON/verbose-Transit payload matching
|
|
77
|
+
the pinned file and selected board UUIDs. Validation and SHA-256 calculation run
|
|
78
|
+
inside the browser; the bundled transport does not return, log or persist raw
|
|
79
|
+
clipboard contents. Immediately before Paste it revalidates the payload digest.
|
|
80
|
+
Missing, stale, unrelated or changed clipboard data prevents paste rather than
|
|
81
|
+
reusing whatever was previously on the clipboard. Clearing the clipboard can
|
|
82
|
+
therefore replace its contents even when the transfer subsequently stops.
|
|
83
|
+
|
|
84
|
+
The command captures source inspections and stable exports, prepares the
|
|
85
|
+
same-file destination, fences one native paste attempt, identifies the new
|
|
86
|
+
boards and arranges only those copies. Independent readback checks the copied
|
|
87
|
+
boards and the unchanged originals. It records structural findings and decoded
|
|
88
|
+
pixel comparisons. Review the saved source/target exports visually as part of
|
|
89
|
+
acceptance; a technical result does not supply human approval.
|
|
90
|
+
|
|
91
|
+
## Results and recovery
|
|
92
|
+
|
|
93
|
+
The result includes a `runId`, source/target board pairs, `nativeVerified`,
|
|
94
|
+
`pixelsMatch`, problems and a receipt path:
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
.penpair/native-copy/<run-id>/receipt.json
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The receipt and its referenced inspections/exports are private operation evidence.
|
|
101
|
+
A successful fully verified transfer reports `status: "copied"`; missing native
|
|
102
|
+
proof or a pixel mismatch can leave `status: "incomplete"` and exit 3 even when
|
|
103
|
+
boards already exist in the destination. Read the findings before doing anything
|
|
104
|
+
else. Existing verification limits remain strict: component overrides, masks,
|
|
105
|
+
paths, mixed text styles and other unobserved native fields cannot be accepted
|
|
106
|
+
merely because exported pixels match.
|
|
107
|
+
|
|
108
|
+
Do not rerun a fresh apply to recover a lost response. Inspect the journal and
|
|
109
|
+
destination independently, then use the original inputs and run ID:
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
penpair runs RUN_ID
|
|
113
|
+
penpair design-release copy --source-page "Screens" \
|
|
114
|
+
--frame SOURCE_BOARD_ID --frame ANOTHER_BOARD_ID --release 1.2.0 \
|
|
115
|
+
--debug-port 9222 --resume RUN_ID --apply
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Resume reconciles the observed destination against the original transfer. A
|
|
119
|
+
paste-attempt fence prevents blind replay after an uncertain paste. Changed
|
|
120
|
+
inputs, changed originals or an ambiguous destination require explicit
|
|
121
|
+
reconciliation; neither resume nor browser activation promises rollback.
|
|
122
|
+
|
|
123
|
+
The transfer receipt is not the receipt-list schema consumed by
|
|
124
|
+
`design-release verify --receipts`. Do not rename it to `release.json` or pass it
|
|
125
|
+
as an approved release. Full release plans, maps, source evidence, native-copy
|
|
126
|
+
mapping and exact owner reviews remain separate requirements. Compatibility
|
|
127
|
+
between copy-created page ownership and the full assembly workflow must be
|
|
128
|
+
validated before treating a copied page as an assembled release.
|
|
129
|
+
|
|
130
|
+
## MCP discovery
|
|
131
|
+
|
|
132
|
+
The typed `design_release_copy` tool appears only when the project's Penpair
|
|
133
|
+
stdio server starts with `--allow-writes`. Its inputs are `sourcePage`,
|
|
134
|
+
`frameIds`, `releaseVersion`, optional `debugPort`, `apply` and `resume`. Preview
|
|
135
|
+
is the default; apply requires `debugPort`, and resume requires apply. The tool
|
|
136
|
+
returns the same operation result and keeps the same target/recovery safeguards.
|
|
137
|
+
It does not expose raw page code. See [MCP tools](mcp.md).
|
|
138
|
+
|
|
139
|
+
## Using from Claude or other hosts
|
|
140
|
+
|
|
141
|
+
The standard copy route is host-neutral: an assistant can invoke the installed
|
|
142
|
+
CLI or call the typed Penpair MCP tool. It requires the configured project,
|
|
143
|
+
owner-confirmed file pin and responsive plugin connection described above. Apply
|
|
144
|
+
also requires a debugging-enabled browser on the same computer as the Penpair
|
|
145
|
+
process, the explicit debugging port and existing clipboard read/write access.
|
|
146
|
+
These are the same prerequisites in Claude, Codex and other CLI/MCP-capable hosts.
|
|
147
|
+
|
|
148
|
+
Claude does not need an additional computer-control integration for the standard
|
|
149
|
+
CDP route. Register the reviewed Penpair executable with `--allow-writes` to expose
|
|
150
|
+
`design_release_copy`, or use the CLI directly. Preview first; tool visibility
|
|
151
|
+
alone neither applies the copy nor grants browser permissions. See the
|
|
152
|
+
[Claude registration example](mcp.md#client-registration).
|
|
153
|
+
|
|
154
|
+
The native-UI keyboard driver used in the trial below was an injected test
|
|
155
|
+
driver, not a public CLI/MCP fallback supplied to Claude or other hosts. That
|
|
156
|
+
trial establishes the core-service proof described below; qualification of the
|
|
157
|
+
bundled CDP clipboard path against Penpot remains pending. Installing Penpair or
|
|
158
|
+
adding host computer controls does not turn that pending qualification into a
|
|
159
|
+
passing result.
|
|
160
|
+
|
|
161
|
+
## Evidence and API boundary
|
|
162
|
+
|
|
163
|
+
The hardened bundled CDP transport has not passed end-to-end browser
|
|
164
|
+
qualification. In a disposable unauthenticated Brave fixture, it stopped while
|
|
165
|
+
awaiting clipboard read access and dispatched no paste. Earlier shortcut-only
|
|
166
|
+
fixture results do not establish that the current payload-validation path works
|
|
167
|
+
end to end. A separate native-UI experiment also does not qualify the bundled
|
|
168
|
+
CDP transport or provide a public CLI fallback.
|
|
169
|
+
|
|
170
|
+
An owner-authorized hosted Penpot trial on 25 October 2026 copied two synthetic
|
|
171
|
+
240 × 160 boards with simple rectangle/ellipse children into a disposable release
|
|
172
|
+
page. It used an injected native-UI keyboard driver through the same core copy
|
|
173
|
+
service because that existing browser profile had no debugging port. The actual
|
|
174
|
+
JSON/verbose-Transit clipboard payload was checked locally against the pinned
|
|
175
|
+
file, selected board identities and digest before one paste; arranging the new
|
|
176
|
+
copies was a separate idempotent step. Independent inspection/native-fidelity
|
|
177
|
+
comparison and decoded RGBA pixel hashes passed for both boards, with four mapped
|
|
178
|
+
nodes. Source and copied stable PNG exports were visually inspected.
|
|
179
|
+
|
|
180
|
+
The original trial run then completed explicit resume with `status: "copied"`,
|
|
181
|
+
`nativeVerified: true`, `pixelsMatch: true` and no problems. The copies were
|
|
182
|
+
arranged, the original source hashes remained unchanged, the receipt was saved
|
|
183
|
+
and the journal reached `verified`. Revision drift had safely interrupted the
|
|
184
|
+
first final capture; bounded read-only recapture and reconciliation completed
|
|
185
|
+
verification without another Copy or Paste dispatch.
|
|
186
|
+
|
|
187
|
+
This establishes the limited native-UI/core-service proof of concept. End-to-end
|
|
188
|
+
Penpot qualification of the bundled CDP clipboard transport remains pending;
|
|
189
|
+
the native-UI result does not establish that qualification or record owner
|
|
190
|
+
approval. Unsupported content remains incomplete. Full release assembly adoption
|
|
191
|
+
is not implemented by this transfer proof of concept.
|
|
192
|
+
|
|
193
|
+
The direct plugin API limitation remains: a disposable two-page trial on local
|
|
194
|
+
Penpot 2.18.3 tested a board with one rectangle child. `clone()` remained on the
|
|
195
|
+
source page, and cross-page `appendChild`/`insertChild` attempts failed with
|
|
196
|
+
`Cannot modify a page that is not currently active`. Independent readback found
|
|
197
|
+
the originals unchanged and no destination children. The native clipboard route
|
|
198
|
+
avoids that unsupported operation; it does not make cross-page reparenting safe.
|
|
199
|
+
|
|
200
|
+
The [upstream shape implementation](https://github.com/penpot/penpot/blob/develop/frontend/src/app/plugins/shape.cljs)
|
|
201
|
+
checks active-page ownership. The [Board API](https://doc.plugins.penpot.app/interfaces/Board)
|
|
202
|
+
provides cloning and reparenting, but no cross-page transfer operation. Penpair
|
|
203
|
+
does not patch proxy internals, reconstruct the design from screenshots or
|
|
204
|
+
submit unauthenticated raw backend file changes as a fallback.
|
package/docs/design-releases.md
CHANGED
|
@@ -7,6 +7,27 @@ design cases and immutable evidence so a later implementation agent can identify
|
|
|
7
7
|
what was reviewed. This is a design release, separate from publishing Penpair's
|
|
8
8
|
npm packages or accepting a frontend implementation.
|
|
9
9
|
|
|
10
|
+
## Copy boards to a release page
|
|
11
|
+
|
|
12
|
+
For an experimental same-file page transfer, preview the observed source boards:
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
penpair design-release copy --source-page "Screens" \
|
|
16
|
+
--frame SOURCE_BOARD_ID --release 1.2.0
|
|
17
|
+
# After reviewing and authorizing the transfer:
|
|
18
|
+
penpair design-release copy --source-page "Screens" \
|
|
19
|
+
--frame SOURCE_BOARD_ID --release 1.2.0 --debug-port 9222 --apply
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
This uses native editor copy/paste into `release/1.2.0`, preserving originals and
|
|
23
|
+
existing destination content, and writes private evidence under
|
|
24
|
+
`.penpair/native-copy/<run-id>/`. It can report incomplete native fidelity after
|
|
25
|
+
copying; read the findings and inspect the exports. The transfer receipt is not
|
|
26
|
+
a release manifest, the `verify --receipts` input schema or owner approval.
|
|
27
|
+
Copy-created page ownership does not by itself establish compatibility with the
|
|
28
|
+
full assembly flow below. See [native copy and recovery](copy-between-pages.md)
|
|
29
|
+
for prerequisites, clipboard effects, explicit resume and current proof limits.
|
|
30
|
+
|
|
10
31
|
## Local commands
|
|
11
32
|
|
|
12
33
|
Create the plan from actual source inspection, using your own product SemVer.
|
|
@@ -60,8 +81,12 @@ is not approval of the child graph. See [linked detail maps](integration-maps.md
|
|
|
60
81
|
Keep the release page in the same pinned Penpot file, named `release/<version>`.
|
|
61
82
|
Assembly creates the owned overview/map sections and reports `awaiting-copy`.
|
|
62
83
|
Copy source design frames natively using a reviewed, guided copy/paste operation
|
|
63
|
-
by a person or an authorized AI using existing browser tools.
|
|
64
|
-
|
|
84
|
+
by a person or an authorized AI using existing browser tools. The experimental
|
|
85
|
+
`design-release copy` path separately automates native clipboard transfer; its
|
|
86
|
+
receipt is not automatically a full release's mapping or approval. Assembly
|
|
87
|
+
does not perform an unsupported cross-page clone. The
|
|
88
|
+
[native copy guide](copy-between-pages.md) records both that API boundary and the
|
|
89
|
+
new transport's verification limits.
|
|
65
90
|
Preserve visual fidelity, native components, token bindings, text and layout;
|
|
66
91
|
do not recreate frames from screenshots or normalize their dimensions. A source
|
|
67
92
|
using auto height must retain it. Floating-point geometry noise is not a reason
|
package/docs/layout-settling.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Bounded layout settling
|
|
2
2
|
|
|
3
|
-
Normal operation writes, PNG exports, baselines, shots and token push verification now use `waitForStableLayout`. A supported shape/global native wait is preferred. Older APIs fall back to geometry samples, requiring
|
|
3
|
+
Normal operation writes, PNG exports, baselines, shots and token push verification now use `waitForStableLayout`. A supported shape/global native wait is preferred. Older APIs fall back to geometry samples, requiring three consecutive equal observations of the target subtree. Missing targets, changed file/page identity, malformed sampled geometry and expired budgets cannot establish stability. Native failure falls back to geometry in `auto` mode; `native` mode still requires a successful native wait.
|
|
4
4
|
|
|
5
5
|
The default layout budget is 30 seconds, with 200 ms fallback intervals. A run is also limited to 1,000 samples. Each layout observation forwards its remaining request budget through guards to the MCP SDK and disables suspension retries; a read timeout does not silently restart the budget. Custom clients must honor the optional `ToolCallOptions.timeoutMs` contract. A late native response is rejected even if it claims completion. The overall CLI `--timeout-ms` remains a separate bound on the complete command.
|
|
6
6
|
|
|
@@ -11,3 +11,19 @@ Exports retain the first capture as an initial observation, wait for layout, and
|
|
|
11
11
|
The previous unconditional ten-second operation sleep is replaced by bounded evidence. Library callers can retain an explicitly measured `settleMs` minimum from 0 to 30 seconds for an additional asynchronous contract such as binding persistence. It is a delay, not verification. A missing binding still fails independent readback and may be reconciled through the journal once it arrives. Page switching retains its existing short navigation delay. No new live timing or compatibility claim is made.
|
|
12
12
|
|
|
13
13
|
Library options may select a target and budget through `layout`, or explicitly set `layout: false` when the caller supplies its own settlement evidence. CLI design commands do not expose that opt-out. Multi-step mutations remain nontransactional: a post-write layout failure can leave completed work applied; inspect the run and explicitly resume after resolving it. The later build kit should reuse these primitives rather than introduce another fixed-sleep convention.
|
|
14
|
+
|
|
15
|
+
## Scope and node budgets
|
|
16
|
+
|
|
17
|
+
`run-file`, `run`, `archive`, token edit writers, `export` and `shots` accept:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
penpair run-file design/build.js --inspect design/inspect.js --readback design/readback.js \
|
|
21
|
+
--page Candidate --layout-root BOARD_ID --layout-root OTHER_BOARD_ID \
|
|
22
|
+
--layout-max-nodes 20000 --apply
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Each repeatable `--layout-root` identifies an existing shape on the operation's page. Roots must be distinct, nonoverlapping subtrees. Missing roots refuse rather than falling back to the page. The same roots are observed before planning, after writing and during recovery. New shape IDs cannot be selected before creation; select their existing parent or use the page default. Without explicit roots the current page is sampled; exports retain their existing shape scope. Library callers use `layout.shapeIds` (or the existing singular `shapeId`) and `layout.maxNodes`.
|
|
26
|
+
|
|
27
|
+
`--layout-max-nodes` is an integer from 1 to 100,000, shared across the selected subtrees; the default remains 10,000. When the traversal exceeds it, the observer retains a bounded depth-first prefix. A successful native wait or three equal bounded samples can continue the operation with `method: "partial"` and `truncated: true`. This establishes stability only for the sample, not for unsampled shapes. Invalid geometry, cycles or duplicate IDs encountered in the sample still refuse. Use explicit roots for complete evidence on a large page. Partial evidence never replaces positive independent write readback or visual export inspection.
|
|
28
|
+
|
|
29
|
+
Reports and journal observations, visible through `penpair runs RUN_ID`, record `rootIds`, `nodeCount` (the sampled count), `maxNodes` and `truncated`. The sample count is a lower bound on subtree size when truncated. Journal input hashes retain the chosen scope and budget, so changing either requires a new run. The build kit's `pp.settle(root, {maxNodes})` shares this policy and evidence; it also accepts an array of root shapes.
|
package/docs/mcp.md
CHANGED
|
@@ -6,9 +6,48 @@ 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
|
|
9
|
+
Default tool names are `pages`, `tree`, `audit`, `inspect`, `tokens_dump`, `run_status`, `baselines_status`, `project_status`, `doctor`, `design_spec` and `export`. These cover bounded live inspection, offline run/baseline evidence, diagnostics, derived specs 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
|
-
Explicit `--allow-writes` additionally advertises `run_registered`.
|
|
11
|
+
Explicit `--allow-writes` additionally advertises `run_registered` and `design_release_copy`. The first runs registered operations; the second provides the typed native-copy workflow described below. `run_registered` 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
|
+
|
|
13
|
+
## Native release-page copy
|
|
14
|
+
|
|
15
|
+
Start the reviewed project executable with write tools enabled only when those
|
|
16
|
+
operations are authorized:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
penpair mcp --root /absolute/path/to/project --allow-writes
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The `design_release_copy` tool previews by default. Example input, with observed
|
|
23
|
+
source board IDs substituted:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"sourcePage": "Screens",
|
|
28
|
+
"frameIds": ["SOURCE_BOARD_ID", "ANOTHER_BOARD_ID"],
|
|
29
|
+
"releaseVersion": "1.2.0",
|
|
30
|
+
"apply": false
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Explicit `apply: true` also requires `debugPort` (1–65535) for an already enabled
|
|
35
|
+
loopback browser debugging endpoint and existing clipboard read/write capability.
|
|
36
|
+
Penpair does not grant browser permissions; denied or unavailable access stops
|
|
37
|
+
before paste. `resume` requires apply and the original run ID/inputs. Copy uses the pinned file, preserves originals, and creates or appends
|
|
38
|
+
to `release/1.2.0`; it changes browser focus and selection and replaces the system
|
|
39
|
+
clipboard. The bundled transport clears stale data before Copy, validates the
|
|
40
|
+
native payload against the pinned file and selected boards inside the browser,
|
|
41
|
+
and rechecks its digest before Paste. Raw clipboard data is not returned, logged
|
|
42
|
+
or persisted by that transport. An uncertain paste is reconciled rather than
|
|
43
|
+
automatically replayed.
|
|
44
|
+
An incomplete native/pixel result is not a completed transfer or release
|
|
45
|
+
approval. See [native copy, evidence and recovery](copy-between-pages.md).
|
|
46
|
+
|
|
47
|
+
This tool is absent from the default server. There is no MCP `wake` tool: explicit
|
|
48
|
+
browser activation remains the CLI `penpair wake` command. Native browser/computer
|
|
49
|
+
controls supplied by an assistant host are separate tools and are not installed
|
|
50
|
+
or exposed by Penpair's server.
|
|
12
51
|
|
|
13
52
|
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
53
|
|
|
@@ -22,8 +61,9 @@ Every advertised tool explicitly declares boolean `readOnlyHint`, `destructiveHi
|
|
|
22
61
|
| `pages`, `tree`, `audit`, `inspect`, `tokens_dump`, `project_status`, `doctor`, `design_spec` (may contact Penpot or its deployment) | true | false | true | true |
|
|
23
62
|
| `export` (creates or replaces a local image from live Penpot) | false | true | false | true |
|
|
24
63
|
| `run_registered` (opt-in trusted code, potentially mutating) | false | true | false | true |
|
|
64
|
+
| `design_release_copy` (opt-in native clipboard transfer) | false | false | false | true |
|
|
25
65
|
|
|
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.
|
|
66
|
+
`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. `design_release_copy` preserves source boards and existing destination content, but is still mutating and non-idempotent: it can create native copies, change selection/focus and replace the clipboard. Its preview does not change that tool-wide annotation. `archive` is an internal registered operation invoked through `run_registered`, not a separately advertised MCP tool.
|
|
27
67
|
|
|
28
68
|
## Code execution boundaries
|
|
29
69
|
|
|
@@ -46,6 +86,24 @@ Claude Code supports project `.mcp.json` entries under `mcpServers`; see [offici
|
|
|
46
86
|
}
|
|
47
87
|
```
|
|
48
88
|
|
|
89
|
+
For authorized native-copy work, change that Claude entry's `args` to:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
["mcp", "--root", "/absolute/path/to/project", "--allow-writes"]
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Restart or reconnect the server to discover `design_release_copy`. This enables
|
|
96
|
+
tool visibility; it does not apply a copy or grant browser permissions. The tool
|
|
97
|
+
must be present in the installed Penpair version's tool list. Registering only
|
|
98
|
+
Penpot's upstream MCP server does not expose Penpair's project tools.
|
|
99
|
+
The tool
|
|
100
|
+
still previews by default. Apply requires `apply: true`, `debugPort`, the pinned
|
|
101
|
+
project/plugin connection and existing clipboard read/write access in the
|
|
102
|
+
browser on the Penpair process's computer. The standard CDP route needs no
|
|
103
|
+
additional Claude computer-control integration. The injected native-UI driver
|
|
104
|
+
used in the core-service trial is not a public fallback; bundled CDP/Penpot
|
|
105
|
+
qualification remains pending. See [host prerequisites and qualification](copy-between-pages.md#using-from-claude-or-other-hosts).
|
|
106
|
+
|
|
49
107
|
Codex uses project `.codex/config.toml` for trusted projects, with a server table; see [official Codex MCP configuration](https://learn.chatgpt.com/docs/extend/mcp?surface=cli).
|
|
50
108
|
|
|
51
109
|
```toml
|
|
@@ -55,3 +113,5 @@ args = ["mcp", "--root", "/absolute/path/to/project"]
|
|
|
55
113
|
```
|
|
56
114
|
|
|
57
115
|
Restart/reconnect after reviewed target or tool-capability changes. Keep the actual Penpot editor visible. SDK in-memory tests establish discovery, typed input refusal, explicit write opt-in, root isolation and target-change refusal; actual agent/editor compatibility remains a pending I12 trial.
|
|
116
|
+
|
|
117
|
+
For explicit tab activation, heartbeat diagnostics and the limits of background operation, see [recovering a suspended Penpot tab](browser-sessions.md). The CLI `wake` action is separate from the read-only doctor tool.
|
package/docs/run-file.md
CHANGED
|
@@ -69,3 +69,5 @@ The common verifier requires matching nonempty expected/actual objects. Empty `p
|
|
|
69
69
|
Final wrapped UTF-8 snippets obey the existing 90 KB guard, including helpers, guards, parameters and the captured inspection passed to apply. Every phase compiles offline before connecting; an oversized runtime inspection can still make apply refuse before delivery. Each input file is bounded independently, and at most 20 distinct include paths and 100 parameters are accepted. Reports identify the ordered source text hashes actually prepared. No implicit imports, glob expansion or transpilation occurs.
|
|
70
70
|
|
|
71
71
|
Writes reuse pinned file guards, revisions, writer coordination, positive independent verification and redacted journals. Optional `--checkpoint`, `--force-lock` and explicit `--apply --resume RUN_ID` follow normal recovery rules. Source/parameter changes refuse resume; a final state already independently verified is not written again. Partial unexplained state requires inspection; there is no rollback or enforced idempotency sandbox. A redacted journal cannot be presented as complete verification or automatically resumed.
|
|
72
|
+
|
|
73
|
+
On a large page, scope layout settling to the existing boards touched by the write with repeatable `--layout-root SHAPE_ID`. `--layout-max-nodes N` sets the shared sample budget (1–100,000; default 10,000). The roots must exist before the write and remain present through readback. Reports and `penpair runs RUN_ID` retain the roots and sampled node count. Budget overflow continues with explicitly partial layout evidence; independent readback is still required. See [layout settling](layout-settling.md) for scope and partial-sample limits.
|
package/docs/troubleshooting.md
CHANGED
|
@@ -11,7 +11,7 @@ Generated from the core error remedy inventory. Regenerate with `pnpm docs:gener
|
|
|
11
11
|
| `incomplete-output` | Required output is missing, truncated or unstable. Narrow the scope or resolve the capture problem before accepting it as complete. |
|
|
12
12
|
| `mcp-unavailable` | Start the Penpot instance and check the MCP URL. Run `penpair probe` to see what answers. |
|
|
13
13
|
| `plugin-disconnected` | In the open Penpot file choose File, MCP Server, Connect, and keep that tab visible, then run the command again. |
|
|
14
|
-
| `plugin-suspended` | The browser put the Penpot tab to sleep. Bring it to the foreground
|
|
14
|
+
| `plugin-suspended` | The browser put the Penpot tab to sleep. Bring it to the foreground, or use penpair wake --debug-port PORT with a dedicated debugging browser, then run penpair doctor. Waking is temporary recovery. A suspended-tab error does not mean nothing was written: read the page and reconcile the run before explicitly replaying a write. |
|
|
15
15
|
| `snippet-too-large` | Split the snippet. Penpot's proxy refuses request bodies of about 110 KB, so snippets stay under 90 KB. |
|
|
16
16
|
| `stale-inspection` | The file, revision, query or inspected content changed. Discard the old cursor/chunks and start a fresh capture. |
|
|
17
17
|
| `tool-failed` | Penpot's tool reported a failure; the message above says what. |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@penpair/web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
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.
|
|
51
|
+
"@penpair/core": "0.5.0"
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
|
54
54
|
"build": "tsc -p tsconfig.json",
|