@penpair/web 0.4.0 → 0.4.1
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/browser-sessions.md +147 -0
- package/docs/compatibility.md +4 -2
- package/docs/copy-between-pages.md +54 -0
- package/docs/design-releases.md +2 -0
- package/docs/layout-settling.md +17 -1
- package/docs/mcp.md +2 -0
- package/docs/run-file.md +2 -0
- package/docs/troubleshooting.md +1 -1
- package/package.json +2 -2
|
@@ -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,54 @@
|
|
|
1
|
+
# Copy boards between pages
|
|
2
|
+
|
|
3
|
+
Penpair currently cannot copy or move an existing board between pages through
|
|
4
|
+
the Penpot plugin API. There is no `copy-boards` command. Use native copy/paste
|
|
5
|
+
in the Penpot editor, leaving the originals in place, then independently inspect
|
|
6
|
+
the destination and compare stable exports. Keep component references, token
|
|
7
|
+
bindings, sizes and child counts intact. See [design release assembly](design-releases.md)
|
|
8
|
+
for its additional fidelity requirements.
|
|
9
|
+
|
|
10
|
+
## Tested API boundary
|
|
11
|
+
|
|
12
|
+
A disposable two-page probe on local Penpot 2.18.3 on 2026-10-25 tested a board
|
|
13
|
+
with one rectangle child. Each `clone()` stayed on the source page. Appending or
|
|
14
|
+
inserting the clone into a board on the other page failed with:
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
Cannot modify a page that is not currently active
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Both `appendChild(clone)` and `insertChild(0, clone)` failed with either the
|
|
21
|
+
source page or the destination page active. Independent readback found both
|
|
22
|
+
clones on the source page, no destination children, and the original board and
|
|
23
|
+
child unchanged. Two destination exports were inspected and showed the empty
|
|
24
|
+
board. Both disposable pages were removed; a separate read confirmed their
|
|
25
|
+
absence and the original pages' names and top-level shape IDs were preserved.
|
|
26
|
+
This establishes a local API limitation, not hosted-version or component/token
|
|
27
|
+
copy fidelity.
|
|
28
|
+
|
|
29
|
+
The [upstream shape implementation](https://github.com/penpot/penpot/blob/develop/frontend/src/app/plugins/shape.cljs)
|
|
30
|
+
checks that both parent and child pages are active before either structural
|
|
31
|
+
operation. The [Board API](https://doc.plugins.penpot.app/interfaces/Board)
|
|
32
|
+
provides cloning and reparenting, but no cross-page transfer operation. The
|
|
33
|
+
[File API](https://doc.plugins.penpot.app/interfaces/File) exposes export,
|
|
34
|
+
validation and history, without a file-change submission method.
|
|
35
|
+
|
|
36
|
+
## File-change route
|
|
37
|
+
|
|
38
|
+
Penpair's connection calls the editor's MCP tools; it has no authenticated
|
|
39
|
+
Penpot backend file-change client or supported plugin method for submitting raw
|
|
40
|
+
file changes. Internal `$page` metadata does not provide that capability.
|
|
41
|
+
Changing a proxy's internals, reconstructing a board from its visible properties,
|
|
42
|
+
or patching backend file objects would not establish preserved component
|
|
43
|
+
overrides, token bindings, references, undo behavior or revision coordination.
|
|
44
|
+
|
|
45
|
+
There is therefore no safe file-change route in the current implementation.
|
|
46
|
+
Automatic cross-page copying stops at this boundary. A future supported transfer
|
|
47
|
+
API or separately validated native editor integration would need exact source
|
|
48
|
+
selection, a dry run, journaled recovery, independent fidelity readback and stable
|
|
49
|
+
exports before shipping a copy command. Moving must remain explicit.
|
|
50
|
+
|
|
51
|
+
For large pages, scope a writer's layout observation with repeatable
|
|
52
|
+
`--layout-root <shape-id>` and, when needed, `--layout-max-nodes <n>`; see
|
|
53
|
+
[layout settling](layout-settling.md). Reducing the observation scope does not
|
|
54
|
+
add a cross-page copy capability.
|
package/docs/design-releases.md
CHANGED
|
@@ -62,6 +62,8 @@ Assembly creates the owned overview/map sections and reports `awaiting-copy`.
|
|
|
62
62
|
Copy source design frames natively using a reviewed, guided copy/paste operation
|
|
63
63
|
by a person or an authorized AI using existing browser tools. Assembly does not
|
|
64
64
|
perform an unsupported cross-page clone.
|
|
65
|
+
The [cross-page API assessment](copy-between-pages.md) records the tested
|
|
66
|
+
boundary and why there is no automatic file-change fallback.
|
|
65
67
|
Preserve visual fidelity, native components, token bindings, text and layout;
|
|
66
68
|
do not recreate frames from screenshots or normalize their dimensions. A source
|
|
67
69
|
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
|
@@ -55,3 +55,5 @@ args = ["mcp", "--root", "/absolute/path/to/project"]
|
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
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.
|
|
58
|
+
|
|
59
|
+
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.4.
|
|
3
|
+
"version": "0.4.1",
|
|
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.4.
|
|
51
|
+
"@penpair/core": "0.4.1"
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
|
54
54
|
"build": "tsc -p tsconfig.json",
|