@penpair/web 0.1.3 → 0.2.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 +31 -240
- package/docs/approvals.md +19 -0
- package/docs/artifacts.md +13 -0
- package/docs/audits.md +13 -0
- package/docs/backup.md +54 -0
- package/docs/branch-review.md +59 -0
- package/docs/build-kit.md +57 -0
- package/docs/command-contract.md +27 -0
- package/docs/compatibility.md +46 -0
- package/docs/cookbook.md +25 -0
- package/docs/coverage.md +50 -0
- package/docs/credentials.md +27 -0
- package/docs/design-workflow.md +11 -0
- package/docs/extensions-trust.md +13 -0
- package/docs/formats.md +20 -0
- package/docs/getting-started.md +10 -2
- package/docs/guide.md +83 -9
- package/docs/handoff.md +32 -0
- package/docs/improvements.md +1217 -0
- package/docs/inspection.md +38 -0
- package/docs/layout-settling.md +13 -0
- package/docs/marwes-components.md +34 -0
- package/docs/marwes-tokens.md +46 -2
- package/docs/marwes.md +7 -0
- package/docs/mcp.md +40 -0
- package/docs/mode-verification.md +35 -0
- package/docs/pr-improvements.md +57 -0
- package/docs/recovery.md +25 -0
- package/docs/releasing.md +142 -22
- package/docs/run-file.md +71 -0
- package/docs/shots.md +15 -0
- package/docs/skill-installation.md +16 -0
- package/docs/snapshots.md +20 -0
- package/docs/status.md +7 -0
- package/docs/team.md +17 -0
- package/docs/token-editing.md +22 -0
- package/docs/tradient-followups.md +77 -0
- package/docs/trials/report-template.json +76 -0
- package/docs/trials.md +41 -0
- package/docs/troubleshooting.md +26 -0
- package/docs/upstream/marwes-1.11.0-evidence.json +15 -0
- package/docs/upstream/marwes-requests.md +35 -0
- package/package.json +2 -2
package/docs/shots.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Named exports and ad-hoc shots
|
|
2
|
+
|
|
3
|
+
```sh
|
|
4
|
+
penpair export --name "Dashboard / Desktop" --page Dashboard dashboard.png
|
|
5
|
+
penpair export <shape-id> dashboard.png --page Dashboard
|
|
6
|
+
penpair shots --page Dashboard --prefix "Dashboard /" --out design/shots
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Names match exactly on the selected page, including nested shapes. Zero matches or multiple matches fail; ambiguity reports candidate IDs instead of silently choosing one. Names shared by multiple pages are also refused for name-based page selection. Use an ID when the shape name is ambiguous. The name search visits at most 10,000 nodes and refuses incomplete lookup. A lookup's file/page/revision must still match the stable export before bytes can be published.
|
|
10
|
+
|
|
11
|
+
`shots` selects top-level frames with an optional prefix. It reuses the stable PNG exporter and the capture identity checks. It supports up to 100 selected frames per run; narrow the prefix for larger pages. Empty or unstable selections exit 3 and publish no new manifest. Intervening edits or export failure preserve the previous complete manifest. `--out` is project-relative and cannot escape through a symlink. With no config, built-in capture supports explicit `--standalone`.
|
|
12
|
+
|
|
13
|
+
The output contains immutable `captures/<run-id>/shot-0001.png` images and a `penpair-shots.json` manifest, published after every capture succeeds. Each entry records the original name, target IDs, revision, PNG dimensions/hash and available render environment. No baseline approval is created. Old generations remain usable; review references before cleaning them. Interrupted local publication can leave an unreferenced generation, as described in [artifact publication](artifacts.md).
|
|
14
|
+
|
|
15
|
+
Use `--json` for the shared command envelope. Unknown option errors suggest a nearby spelling when one is plausible, but never reinterpret or execute the suggestion. Named exports keep the existing scale option, and `shots` accepts it too. Stable bytes and geometry are technical capture evidence; review the resulting images before judging visual correctness.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Install skills and integrate project instructions
|
|
2
|
+
|
|
3
|
+
```sh
|
|
4
|
+
penpair skills install --agents AGENTS.md --dry-run
|
|
5
|
+
penpair skills install --agents AGENTS.md
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
The preview lists planned files/links, shows the resolved instruction path and prints the owned-block diff. Dry-run writes nothing, including skill copies and links. Add `--json` for the versioned report. Skill paths reuse the project's existing real skill folder; `--to` selects another project-relative folder. Generated links are relative to the selected instruction file, with spaces and special characters encoded.
|
|
9
|
+
|
|
10
|
+
Without `--agents`, exactly one existing AGENTS.md or CLAUDE.md is selected. If neither exists, installation prints rows and leaves instruction creation to an explicit destination. If both exist, it edits neither and exits 3 with `instructions.status: choice-required`; choose `--agents` explicitly. Skills may still have been installed. `setup --agents <path>` passes that destination to the same installer. Setup without a destination follows the same existing-file policy and reports when instruction integration still needs a choice.
|
|
11
|
+
|
|
12
|
+
The installer appends a skills section when needed or replaces only the contents between `<!-- penpair:skills:start -->` and `<!-- penpair:skills:end -->`. Existing text outside the owned region, including line endings, is preserved. Duplicate, reversed or unmatched markers stop installation before any skill files are written. An instruction file edited after planning is preserved; retry after reviewing its current contents. A repeat run with identical content is a no-op. Existing file permissions are retained.
|
|
13
|
+
|
|
14
|
+
Local outputs must remain inside the project after resolving existing symlinks. An instruction link escaping the project or a dangling link is refused. The resolved destination is shown so a project wrapper or shared in-project target is visible. These operations do not edit global agent configuration. Entry-point/output checks do not sandbox arbitrary extensions.
|
|
15
|
+
|
|
16
|
+
Skill files modified by the project are kept unless `--force` is explicit. Project facts remain project-owned even with force, and rename migration preserves the prior facts. All writes are planned before execution, published as complete files, and instructions are written after skill copies/links. This is not a multi-file transaction: a filesystem failure or a concurrent owner edit can leave skill installation partly applied while preserving the instruction file. Review the report and rerun; unchanged files are skipped.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Structural snapshots for review
|
|
2
|
+
|
|
3
|
+
```sh
|
|
4
|
+
penpair snapshot
|
|
5
|
+
penpair snapshot --write --out design/snapshots/current
|
|
6
|
+
penpair snapshot diff design/snapshots/before --from design/snapshots/current
|
|
7
|
+
penpair snapshot diff design/snapshots/before --from design/snapshots/current --out design/changes.md
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Default mode captures for inspection and writes nothing. `--write` publishes schema-1, page-split structure and token JSON. Every page starts at the actual page root, so loose text/groups outside boards are retained. A reserved structured-inspection selector `@page-root` supports this scope. Page names must be unique for the editor's name-based selection API; ambiguity refuses rather than selecting a similarly named page.
|
|
11
|
+
|
|
12
|
+
The snapshot records file/page/node identities, hierarchy/order, geometry, full text, layout, styles, token bindings, component source IDs/overrides and explicit unknown fields, plus the typed token/theme catalog. All pages and tokens must share the same file/revision, with an independent listing afterward. Changed source, incomplete transfer or credential redaction refuses publication. Capturing can switch the current editor page; no design objects are changed, and the editor remains on the last inspected page.
|
|
13
|
+
|
|
14
|
+
Review budgets: 100 pages, 50,000 total nodes, 8 MiB per page/token artifact, 128 MiB total, five-minute collection budget checked between bounded captures. Individual captures retain I8 call/time/transfer limits. Source fields that the plugin API cannot observe remain explicit unknowns; a complete traversal does not make those fields known.
|
|
15
|
+
|
|
16
|
+
Artifacts use deterministic key/node/page order, with hierarchy indices retained. Volatile capture times and transport metrics are omitted. Identical source produces identical files. Immutable `generations/HASH/` artifacts are written first and a hash-checked `snapshot.json` pointer is published last. A local exclusive publication lock refuses competing writers. An older revision or another file cannot replace the canonical pointer. Prior generations remain available; deleting them is an owner action.
|
|
17
|
+
|
|
18
|
+
Offline `snapshot diff` validates all manifest/artifact hashes and identities, then reports added/removed pages/nodes and changed text, bindings, layout, geometry, styles, metadata and token catalogs. Foreign file IDs are not comparable. Large diffs show an explicit truncated result with an exact total change count (exit 3); full bounded comparisons with changes exit 2, unchanged exit 0. Markdown keeps design-supplied names/text inside literal untrusted-data fences. The command does not post comments or contact a forge.
|
|
19
|
+
|
|
20
|
+
These artifacts are **review evidence**, not full-fidelity backups. They do not embed external library assets, font/image bytes, collaboration history or every native feature. Keep the [archive/hosted restore workflow](backup.md) for disaster recovery; structural diffs cannot establish a successful restore. Native component override proof and live hosted round trips remain pending.
|
package/docs/status.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Project status and file opening
|
|
2
|
+
|
|
3
|
+
`penpair status --json` reports deployment reachability, configured file pin, actual connected identity/revision/pages, observed API capabilities, skill installation differences and baseline coverage for web or local profiles. Unknown/missing evidence remains visible and produces incomplete status; a reachable web page alone cannot make the project healthy. It does not run a write probe, install skills, activate themes or approve images.
|
|
4
|
+
|
|
5
|
+
By default configured adapters are listed as uninspected. `status --adapters` explicitly loads trusted configured modules and their optional `defineAdapter({status: async context => lines})` hooks. Each line has `id`, `label`, `state` (`ok`, `warning`, `failed`, `unknown`) and `detail`. The token adapter contributes declaration freshness, explicitly separate from a live token comparison. Third-party hooks execute project code and should use the context output contract. Status never implies sandboxed imports or complete native/browser acceptance.
|
|
6
|
+
|
|
7
|
+
`penpair open --print` returns the public URL derived from the configured origin and encoded owner-confirmed file ID. `penpair open` invokes the platform browser opener for that same URL. No MCP key enters it. If the deployment needs extra team context, use the owner's full editor link and confirm the ID in doctor. Browser launch success cannot prove that a login/file page rendered; inspect it normally. Tests use a stub opener, not a real browser session.
|
package/docs/team.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Working on a shared design
|
|
2
|
+
|
|
3
|
+
Run `penpair onboard` (or `--json`) in the project for a checklist generated from its configured origin and pinned file. It works offline and does not load adapters. The owner invites each colleague's own account to the shared file. Each person creates their own MCP key, runs `penpair connect`, opens the pinned file and connects the MCP plugin. Share configuration and the file pin through Git; keep personal keys and `.penpair/` recovery evidence private.
|
|
4
|
+
|
|
5
|
+
A direct file link is included when the pin is known. If Penpot needs team context, use the owner's complete editor link and confirm the file ID with doctor. A Docker `localhost` origin is only reachable on that computer; colleagues need a shared deployment. Onboarding does not grant access or provision accounts.
|
|
6
|
+
|
|
7
|
+
## Coordinating writes
|
|
8
|
+
|
|
9
|
+
Journaled CLI archive/registered operations and adapter token pushes acquire an exclusive local file for this checkout and, when supported, a shared `penpair/writer` marker on the Penpot file. The marker contains a random ownership token, run ID, operation, username and times. Another active writer refuses the operation. Read-only inspection stays available. Independent readback confirms ownership after acquisition; every step checks it again. The marker expires after 15 minutes and a longer run stops before its next step. There is no background renewal.
|
|
10
|
+
|
|
11
|
+
Agree on a write window and keep the editor awake. A human can still edit. Penpot's [shared plugin-data API](https://doc.plugins.penpot.app/interfaces/File) supplies separate reads/writes rather than an atomic compare-and-swap, so this is advisory across machines. It cannot prevent two simultaneous acquisitions or act as a distributed mutex. The local lock protects this checkout, not other clones or computers. When shared methods are absent, the command warns and uses only the local lock.
|
|
12
|
+
|
|
13
|
+
A crashed local process can leave a lock behind. Inspect its run with `penpair runs <run-id>`, check the file, and coordinate with the named writer before explicitly adding `--force-lock --apply` to the original command. A still-running local process cannot be forced out. The override can replace a foreign shared marker or abandoned local lock; it is not a safe way to interrupt someone. Simultaneous forced takeovers have no exclusion guarantee. Malformed shared marker data requires manual inspection; force does not silently discard it.
|
|
14
|
+
|
|
15
|
+
Revisions are checked inside each journaled operation mutation. Archive also rechecks candidate IDs and geometry. Adapter pushes compare the CLI's source snapshot before planning and recheck the just-inspected token state inside each mutation. These guards detect stale input but do not make a multi-step build transactional. Known self-writes, including checkpoint and marker creation, occur before subsequent revision observations. Custom snippet authors must verify their own relevant content preconditions as well.
|
|
16
|
+
|
|
17
|
+
Direct library calls that omit journal options, native checkpoint helpers invoked separately, and the explicitly destructive scratch deep probe do not acquire the journal's writer lease. Coordinate those manually. No live two-editor trial has been run for this change. See [recovery](recovery.md) after an uncertain write; do not automatically roll back intervening work.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Guarded token editing
|
|
2
|
+
|
|
3
|
+
All commands inspect by default; add `--apply` to execute one guarded write and independent readback. A project config is required. Existing file pins, write journals, writer coordination, revision checks, optional checkpoints, deadlines and uncertain-write recovery apply.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
penpair tokens add-set 'Project · Page'
|
|
7
|
+
penpair tokens set 'Project · Page' card-radius --type borderRadius --value '"{radius} * 2"' --description 'Project card'
|
|
8
|
+
penpair tokens remove 'Project · Page' card-radius
|
|
9
|
+
penpair tokens promote 'Project · Page' 'Shared · Page'
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`--value` is JSON: quote a string inside shell quotes, or provide a composite string-valued object. The documented [Penpot token types](https://doc.plugins.penpot.app/types/TokenType) are validated before connecting. An omitted description becomes an empty string. Tokens are at most 16 KiB.
|
|
13
|
+
|
|
14
|
+
`add-set` creates an inactive set, or observes an existing one without changes. `set` creates or updates one same-type token. Type replacement requires separate reviewed removal. `remove` removes one token; it never deletes a set. It refuses retained formula references and shape bindings, even if another set might supply the same name. `promote` copies every source token into an existing destination, preserving source, theme membership and active selection. Identical destination tokens are accepted; conflicts refuse the entire plan before writing. Repeating a successful command is idempotent.
|
|
15
|
+
|
|
16
|
+
The operation snapshots the catalog and shape bindings, builds its desired state, and rechecks source content immediately inside the mutation. Independent readback checks the complete observed token state, bindings and active selection. Known font-family/typography storage aliases are normalized for verification. It does not claim resolved per-theme or pixel equivalence. Token edits can affect shapes using those names; inspection includes their IDs.
|
|
17
|
+
|
|
18
|
+
Inspection refuses partial inventories: at most 10000 tokens, 20000 shapes and a conservatively bounded document. The final wrapped request still must fit the 90 KB snippet guard; a large pinned precondition can therefore refuse an edit before delivery. Use a narrower reviewed project operation for larger documents. No local token cache is trusted.
|
|
19
|
+
|
|
20
|
+
On an uncertain response inspect the file and `penpair runs`, then explicitly resume with `--apply --resume <run-id>`. Already-satisfied final state is independently reconciled. A partial promotion whose state differs from both original and final refuses automatic continuation; inspect it and prepare a new reviewed plan. There is no transaction or rollback.
|
|
21
|
+
|
|
22
|
+
These are live editing commands, not declarations of adapter ownership. Declare reproducible project tokens in the adapter configuration. Current API references describe [sets](https://doc.plugins.penpot.app/interfaces/TokenSet) and [catalog ordering](https://doc.plugins.penpot.app/interfaces/TokenCatalog); offline simulations do not establish pinned-version live compatibility.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Tradient adoption proposal — owner review required
|
|
2
|
+
|
|
3
|
+
This is a scoped handoff, not an applied consumer change. Read-only inspection on 2026-10-21 found local `main` at `3aa7a1c` in `/Users/niklaswestman/Documents/tradient/CODE/tradient`. The pre-existing untracked `penpot-poc/` folder remains untouched. No consumer files, commits, configuration, Penpot data or deployment state were changed.
|
|
4
|
+
|
|
5
|
+
## Evidence and corrections
|
|
6
|
+
|
|
7
|
+
- Root dev dependencies pin `@penpair/web` and `@penpair/marwes-ui` to `0.1.3`; the primary UI uses `@marwes-ui/react` `^1.11.0`.
|
|
8
|
+
- Root package scripts contain no `design:*` entries. `.env.example` has no `PENPAIR_MCP_URL` entry; no personal key file was read.
|
|
9
|
+
- `penpair.config.json` names `Tradient`, the `packages/frontend-evolved` app, `tradientLight`/`tradientDark` from its `src/theme.ts`, and `design/marwes-tokens.snapshot.json`. It has neither a file pin nor baselines.
|
|
10
|
+
- The committed snapshot is schema 1 with the generated Core/Dark and Tradient Light/Dark sets. It declares no project extra set or ownership map.
|
|
11
|
+
- `packages/frontend-evolved/src/components/organisms/sidebar-nav.tsx` already exports `SidebarNav`. Reuse and assess that component before proposing another sidebar. A missing upstream-library primitive does not mean the consumer lacks one.
|
|
12
|
+
- The existing API workflow uses Node 20, pnpm 10.12.1 and a frozen lockfile install. Its legacy-frontend typecheck is a separate migration concern; this design-token proposal does not change that job's unrelated behavior.
|
|
13
|
+
|
|
14
|
+
The new commands in this improvement branch are unreleased. A `0.1.3` version string alone does not prove the installed tarball contains these changes. First use an owner-reviewed release or an isolated packed-branch trial; do not edit the consumer to depend on unreviewed branch behavior.
|
|
15
|
+
|
|
16
|
+
## Proposed small adoption change
|
|
17
|
+
|
|
18
|
+
- [ ] Owner authorizes a separate consumer branch and confirms the target checkout/worktree. Preserve `penpot-poc/` and every unrelated change.
|
|
19
|
+
- [ ] Add these entries to the existing root `scripts` object:
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"design:doctor": "penpair doctor",
|
|
24
|
+
"design:tokens:check": "penpair marwes tokens check"
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- [ ] After the existing frozen install in the PR validation workflow, add this offline step:
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
- name: Check design token snapshot
|
|
32
|
+
run: pnpm run design:tokens:check
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
No Penpot key, browser or design-server connection belongs in this CI check. The initial adoption must regenerate the snapshot with the reviewed tool version before enabling a gate that would fail on the old expectation.
|
|
36
|
+
|
|
37
|
+
- [ ] Add only this empty documentation entry to `.env.example`, with a comment that each person creates their own key and stores it locally:
|
|
38
|
+
|
|
39
|
+
```dotenv
|
|
40
|
+
# Personal MCP endpoint; keep its value in ignored local configuration.
|
|
41
|
+
PENPAIR_MCP_URL=
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- [ ] After installing the reviewed file-guard build, run `penpair connect --pin-file` while the owner independently confirms the intended open file. Commit the public file ID in `penpair.config.json`; keep personal keys out of the proposal, chat, diff and logs. Check `doctor --json` and exercise a wrong-file refusal on scratch files.
|
|
45
|
+
- [ ] Reconcile the installed skill path and project-facts reference with the chosen agent client. Use the owned instruction integration rather than replacing unrelated `AGENTS.md` text. Keep file identity in the typed config; facts may point to it.
|
|
46
|
+
- [ ] Declare the project-owned page/radius tokens under `marwes.extras` after reviewing their formulas or C1 measurements. Do not silently promote the field-note constants to authoritative component measurements.
|
|
47
|
+
- [ ] Regenerate the schema-2 token snapshot, review ownership and value changes, then run `design:tokens:check`. Inspect `tokens push` before any separately authorized Penpot mutation. Differing designer values require an explicit adopt/overwrite decision; prune is not a cleanup shortcut.
|
|
48
|
+
|
|
49
|
+
## Baseline and implementation follow-up
|
|
50
|
+
|
|
51
|
+
- [ ] Owner approves the intended `Dashboard / Desktop` frame and confirms its exact page, route and identity. No approval was inferred from the original brief.
|
|
52
|
+
- [ ] Add a baseline block only after that decision. The shape below is a merge template; replace the route with the application's actual route key:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"baselines": {
|
|
57
|
+
"page": "Dashboard",
|
|
58
|
+
"root": "design/baselines",
|
|
59
|
+
"frames": [
|
|
60
|
+
{ "frame": "Dashboard / Desktop", "id": "dashboard-desktop", "route": "OWNER_CONFIRMED_ROUTE" }
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
- [ ] Inspect `baselines`, explicitly authorize the first `--apply`, export/look twice, and commit only the reviewed reference generation. Add rich case metadata and required coverage once state/theme/fixture setup is specified. Rich cases remain pending implementation-provider mappings until those hooks exist.
|
|
67
|
+
- [ ] Establish one working implementation comparison through the existing baseline route before expanding the consumer handoff. Capture stable fonts/data and show desktop/mobile plus one non-happy state. Browser interaction and accessibility checks remain separate.
|
|
68
|
+
- [ ] Review the primary/border-brand/link/focus theme family with C4 lint and actual light/dark screenshots. Confirm supported theme-input fields before editing `src/theme.ts`; keep intentional blue accents when the owner chooses them. Regenerate/review the snapshot after any change.
|
|
69
|
+
- [ ] Compare the app's Marwes 1.11.0 appearance against an isolated 1.4.1 reference when an owner-approved old fixture is available. Do not downgrade or alter the current consumer just to obtain that comparison.
|
|
70
|
+
- [ ] Implement new UI only in `packages/frontend-evolved`, reusing its existing SidebarNav and library primitives. Follow its structure/styling/data patterns and preserve its product semantics. D1 supplies explicit behavior/component metadata; a visual frame alone cannot make this implementation mechanical.
|
|
71
|
+
- [ ] Migrate useful build bodies into reviewed files or registered operations. Split pure helpers, inspection, idempotent mutation and independent readback. Use `@kit` and explicit adapter recipes, stable owned identities and full source hashes; do not copy the throwaway runner's path or name-based deletion shortcuts.
|
|
72
|
+
|
|
73
|
+
## Validation for that future consumer branch
|
|
74
|
+
|
|
75
|
+
Run the new offline design check, the primary app's matching tests/typecheck/build, whitespace checks and a browser review for UI changes. Follow the consumer's own pre-push review instruction before a later authorized push or PR. No deployment, AWS write, publishing or external message is part of this handoff.
|
|
76
|
+
|
|
77
|
+
Owner decisions still needed: which reviewed Penpair build to adopt, the confirmed Penpot file, initial frame approval/route, project-extra constants, intentional theme accents and scope of Dashboard implementation. This proposal keeps those decisions reviewable without applying them.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"kind": "human-trial",
|
|
4
|
+
"status": "not-run",
|
|
5
|
+
"commit": null,
|
|
6
|
+
"artifacts": [],
|
|
7
|
+
"participants": [],
|
|
8
|
+
"environment": {
|
|
9
|
+
"os": null,
|
|
10
|
+
"node": null,
|
|
11
|
+
"packageManager": null,
|
|
12
|
+
"agentClient": null,
|
|
13
|
+
"skillPath": null,
|
|
14
|
+
"penpotDeployment": null,
|
|
15
|
+
"apiVersion": null
|
|
16
|
+
},
|
|
17
|
+
"target": {
|
|
18
|
+
"ownerAuthorized": false,
|
|
19
|
+
"fileIds": [],
|
|
20
|
+
"pageIds": []
|
|
21
|
+
},
|
|
22
|
+
"metrics": {
|
|
23
|
+
"timeToDoctorGreenMs": null,
|
|
24
|
+
"interventions": null,
|
|
25
|
+
"understandableFailures": null,
|
|
26
|
+
"eligibleTokens": null,
|
|
27
|
+
"boundTokens": null,
|
|
28
|
+
"inspectionComplete": null,
|
|
29
|
+
"verifiedOutcomes": null
|
|
30
|
+
},
|
|
31
|
+
"exercises": {
|
|
32
|
+
"onboarding": {
|
|
33
|
+
"status": "not-run",
|
|
34
|
+
"evidence": [],
|
|
35
|
+
"findings": null
|
|
36
|
+
},
|
|
37
|
+
"skillDiscovery": {
|
|
38
|
+
"status": "not-run",
|
|
39
|
+
"evidence": [],
|
|
40
|
+
"findings": null
|
|
41
|
+
},
|
|
42
|
+
"smallBuild": {
|
|
43
|
+
"status": "not-run",
|
|
44
|
+
"evidence": [],
|
|
45
|
+
"findings": null
|
|
46
|
+
},
|
|
47
|
+
"wrongFile": {
|
|
48
|
+
"status": "not-run",
|
|
49
|
+
"evidence": [],
|
|
50
|
+
"findings": null
|
|
51
|
+
},
|
|
52
|
+
"writerConflict": {
|
|
53
|
+
"status": "not-run",
|
|
54
|
+
"evidence": [],
|
|
55
|
+
"findings": null
|
|
56
|
+
},
|
|
57
|
+
"recovery": {
|
|
58
|
+
"status": "not-run",
|
|
59
|
+
"evidence": [],
|
|
60
|
+
"findings": null
|
|
61
|
+
},
|
|
62
|
+
"implementationRoute": {
|
|
63
|
+
"status": "not-run",
|
|
64
|
+
"evidence": [],
|
|
65
|
+
"findings": null
|
|
66
|
+
},
|
|
67
|
+
"cleanup": {
|
|
68
|
+
"status": "not-run",
|
|
69
|
+
"evidence": [],
|
|
70
|
+
"findings": null
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"blockers": [],
|
|
74
|
+
"backlogChanges": [],
|
|
75
|
+
"ownerReviewed": false
|
|
76
|
+
}
|
package/docs/trials.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Human trial runbook (I12)
|
|
2
|
+
|
|
3
|
+
Status: prepared, **not run**. Niklas asked to finish branch code and leave live trials pending (2026-10-21). Offline fixtures exercise control flow, not people, real servers, visual parity or adoption. Keep I12 unchecked until two actual people complete the exercises and review one real design-to-code route.
|
|
4
|
+
|
|
5
|
+
## Preparation
|
|
6
|
+
|
|
7
|
+
Use two consenting people with separate fresh project folders, personal connections and independently owned credentials. The owner must explicitly authorize two disposable Penpot files and identify their public file/page IDs. Never infer authorization from a file name. Keep the editor visible. No telemetry runs in the background.
|
|
8
|
+
|
|
9
|
+
Record commit, tarball SHA-256 hashes, package versions, OS, Node/package manager, actual agent client, Penpot deployment and observed API version in [report-template.json](trials/report-template.json). This branch still reports 0.1.3: the version alone cannot distinguish it from the registry release. Use a reviewed release or pack the complete branch package set. When installing command/adapter tarballs, override `@penpair/core` to the matching local core tarball, as `scripts/smoke-package.mjs` does. Installing only the web tarball may silently resolve an older registry core.
|
|
10
|
+
|
|
11
|
+
Start the clock before setup. Each person enters their own secret through the documented hidden connection flow; never collect the key in a report, shell transcript or screenshot. Run onboarding and `doctor --json`, then configure the owner-confirmed file pin. Record interventions and exact understandable or confusing failures, with credentials redacted.
|
|
12
|
+
|
|
13
|
+
Preview `penpair skills install --dry-run` before installation. Test discovery separately in each actual agent client. Codex scans repository `.agents/skills` from the current folder to the repository root and supports symlinked skill folders; check the skill selector and invoke the skill explicitly before assessing automatic discovery. See [official skill documentation](https://learn.chatgpt.com/docs/build-skills). Record the actual installed path, client version and observed discovery; do not generalize one client's result to another.
|
|
14
|
+
|
|
15
|
+
## Exercises
|
|
16
|
+
|
|
17
|
+
1. Build a small card using the [reviewed Hello-card example](../examples/hello-card/README.md), or use `probe --deep --kit --write` on an authorized scratch file with active typed tokens and an available font. Inspect the private preview. Record eligible/bound token counts with the inspected population and whether traversal was complete. The probe removes its temporary root; any persistent example needs an explicit owner-reviewed cleanup.
|
|
18
|
+
2. Pin file A, open disposable file B, and run `examples/trials/wrong-file-read.js` through `run-file` without a page argument. Expect a file-guard refusal before the body. Basic `pages` inspection only warns by design, so it is not the hard-block exercise. Restore A afterward.
|
|
19
|
+
3. Use a dedicated empty page in A. Copy `examples/trials` into each scratch project. Person A runs the holder below with a fresh marker. Person B attempts the same operation from their own project/key with a different fresh marker while A is writing. Record refusal during the lease, server serialization, overlap, unsupported API or unknown, and timings. Same-checkout tests only prove a local lock; they do not prove cross-client atomic exclusion. A busy attempt can have an uncertain journal even before applying: inspect the recorded steps and retain the actual diagnostic.
|
|
20
|
+
4. Run the recovery example below with `failAfterWrite=true`. It deliberately throws after creating a small owned frame. Record the uncertain run ID and frame ID. Use **the same files and parameters** with explicit `--resume RUN_ID`; independent readback must reconcile the existing frame without a duplicate. Export twice, look at the image, and record the result. A fresh run is not recovery. A renamed/duplicated marker or changed source requires inspection rather than an automatic retry.
|
|
21
|
+
5. Exercise one real implementation route through existing baselines and the Reflection handoff. Obtain explicit frame approval; hold fonts and fixture data stable. Record actual browser comparison and adoption findings. Rich coverage cases require the D4 hooks and cannot be represented as successful default-state checks. Human adoption remains a gate before declaring the C1/D1/E1 expansion accepted.
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
penpair run-file examples/trials/hold-writer.js \
|
|
25
|
+
--inspect examples/trials/hold-inspect.js --readback examples/trials/hold-readback.js \
|
|
26
|
+
--param fileId=OWNER_CONFIRMED_FILE --param pageId=OWNER_CONFIRMED_EMPTY_PAGE \
|
|
27
|
+
--param marker=FRESH_PERSON_A_MARKER --param holdMs=30000 \
|
|
28
|
+
--apply --timeout-ms 45000
|
|
29
|
+
|
|
30
|
+
penpair run-file examples/trials/recovery-build.js \
|
|
31
|
+
--inspect examples/trials/recovery-inspect.js --readback examples/trials/recovery-readback.js \
|
|
32
|
+
--param fileId=OWNER_CONFIRMED_FILE --param pageId=OWNER_CONFIRMED_PAGE \
|
|
33
|
+
--param name=RecoveryTrial --param marker=FRESH_RECOVERY_MARKER \
|
|
34
|
+
--param failAfterWrite=true --apply
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The holder intentionally waits to create a contention window; it is not layout settling. It creates no design nodes but records a `penpair/trial-hold-MARKER` file metadata record with holding/complete state. A partial marker is evidence requiring inspection. A completed marker makes the same operation a verified no-op; use a fresh marker for each new contention exercise. The recovery example leaves an owned frame intentionally. Remove only explicitly confirmed owned IDs/markers with a reviewed operation, or let the owner discard the dedicated scratch files.
|
|
38
|
+
|
|
39
|
+
## Evidence and completion
|
|
40
|
+
|
|
41
|
+
Copy the template under ignored `.penpair/trials/`. Unobserved metrics remain null, not zero. Record time to doctor-green, human interventions, failure comprehension, binding coverage, independent verified outcomes, visual review, blockers and resulting backlog changes. Capture screenshots only after closing secret-entry panels. Commit only owner-reviewed redacted summaries, never keys, raw connection transcripts or private journals. There is no completed human report yet.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
Generated from the core error remedy inventory. Regenerate with `pnpm docs:generate`; tests detect drift.
|
|
4
|
+
|
|
5
|
+
| Core code | Cause and next action |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| `auth-rejected` | Penpot rejected the MCP key. Use the key from Account, Integrations, MCP Server. |
|
|
8
|
+
| `endpoint-invalid` | The configured MCP URL must be a complete http or https URL. |
|
|
9
|
+
| `endpoint-unconfigured` | Set PENPAIR_MCP_URL in the shell or in a git-ignored .env.local to the MCP URL from Penpot (Account, Integrations, MCP Server; do not regenerate the key), or configure an MCP server named 'penpot' for Codex or Claude Code. |
|
|
10
|
+
| `file-mismatch` | Open the project's pinned design file and reconnect its MCP plugin. Use --any-file only when you intend to act on another file. |
|
|
11
|
+
| `incomplete-output` | Required output is missing, truncated or unstable. Narrow the scope or resolve the capture problem before accepting it as complete. |
|
|
12
|
+
| `mcp-unavailable` | Start the Penpot instance and check the MCP URL. Run `penpair probe` to see what answers. |
|
|
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 and keep it visible while a command runs. A suspended-tab error does not mean nothing was written: read the page before running a write again. |
|
|
15
|
+
| `snippet-too-large` | Split the snippet. Penpot's proxy refuses request bodies of about 110 KB, so snippets stay under 90 KB. |
|
|
16
|
+
| `stale-inspection` | The file, revision, query or inspected content changed. Discard the old cursor/chunks and start a fresh capture. |
|
|
17
|
+
| `tool-failed` | Penpot's tool reported a failure; the message above says what. |
|
|
18
|
+
| `write-uncertain` | Do not replay this write blindly. Inspect the intended file independently and reconcile what already changed before explicitly resuming. |
|
|
19
|
+
|
|
20
|
+
## Other diagnostic domains
|
|
21
|
+
|
|
22
|
+
ConfigError uses `missing`, `unreadable`, `invalid-json` and `invalid-config`: repair the named project input; only an absent config can be initialized. Unsupported versions need the producer's migration guidance. These are config-domain codes, not aliases for core connection errors.
|
|
23
|
+
|
|
24
|
+
Command interruption uses `deadline` and `cancelled`; uncertain delivered writes retain exit 4 and their run ID. See [command outcomes](command-contract.md) and [recovery](recovery.md). Argument, lifecycle, registry and adapter errors may have service-specific messages without a stable code: read the named failing precondition instead of assuming every error belongs to this table.
|
|
25
|
+
|
|
26
|
+
For a wrong target, check [team setup](team.md) and the configured public file ID. For incomplete captures, inspect [structured evidence limits](inspection.md) and [artifact provenance](artifacts.md). For conflicting writer/ownership state, keep evidence and coordinate with the recorded owner before an explicit recovery decision.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"kind": "upstream-request-evidence",
|
|
4
|
+
"observedAt": "2026-10-21",
|
|
5
|
+
"method": "read-only installed package declarations and source maps",
|
|
6
|
+
"liveMeasurements": false,
|
|
7
|
+
"artifacts": [
|
|
8
|
+
{"package":"@marwes-ui/react","version":"1.11.0","artifact":"dist/index.js.map","sha256":"5e8dfda3f704a98c07dbb0dba288fd4df8fd0adb8fda07a2507bfa09b9e73791","sources":["../src/components/stat-tile/stat-tile.tsx","../src/components/card/card.tsx"]},
|
|
9
|
+
{"package":"@marwes-ui/core","version":"1.11.0","artifact":"dist/index.js.map","sha256":"29fd794b744da873b63222bc3827870e7031753d3137cc28415aa14acf3e581d","sources":["../src/components/atoms/stat-tile/stat-tile-recipe.ts","../src/components/atoms/stat-tile/stat-tile-a11y.ts","../src/components/atoms/card/card-recipe.ts","../src/theme/theme-vars.ts"]}
|
|
10
|
+
],
|
|
11
|
+
"facts": ["StatTile trendValue and trendDirection are optional", "StatTile omits arbitrary children", "StatCardProps aliases CardProps", "CardProps accepts children", "No Sidebar or SidebarNav in the inspected React export list"],
|
|
12
|
+
"candidateEdgeCases": ["Numeric zero trend is subject to a truthiness condition", "Only string trendValue is passed to the core accessible-label recipe"],
|
|
13
|
+
"notEstablished": ["Latest upstream feature state", "Rendered numerical component values", "Browser/accessibility behavior", "Native Penpot override preservation"],
|
|
14
|
+
"sent": false
|
|
15
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Marwes requests for owner review — 2026-10-21
|
|
2
|
+
|
|
3
|
+
Status: **draft, unsent**. This document does not authorize an email, issue, package change or consumer edit. Review against the maintainer's current version before sending. Evidence is the installed 1.11.0 React/core package source and Claude's dated original trial notes; no new live component measurements were taken.
|
|
4
|
+
|
|
5
|
+
## Correct the starting assumptions
|
|
6
|
+
|
|
7
|
+
- `StatTileProps.trendValue` and `trendDirection` are already optional in React 1.11.0. The source conditionally omits the trend region. Drop the request to add optional trend support. A missing trend in a Penpot helper is an adapter/composition issue until proven otherwise.
|
|
8
|
+
- `StatTile` omits arbitrary `children`, but `StatCardProps` already aliases `CardProps`, which accepts children. Ask whether composing a sparkline in StatCard is the intended route before requesting another slot/API.
|
|
9
|
+
- The installed React export list has no Sidebar/SidebarNav symbol. The consumer already implements its own `SidebarNav`; a new consumer sidebar is unnecessary. An upstream navigation primitive is an optional library discussion, not a blocker for that implementation.
|
|
10
|
+
- Card/StatTile radii and typography values in the original brief are historical observations in one project theme/viewport/state. They are not newly verified universal library constants. The C1 measurement pilot still needs a real fixture and native instance-override proof.
|
|
11
|
+
|
|
12
|
+
## Prioritized requests
|
|
13
|
+
|
|
14
|
+
| Priority | Draft request | Evidence and acceptance |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| P1 | Expose stable component anatomy/measurement metadata and fixture selectors. | Core 1.11.0 recipes expose data-component/slot class names, but those are not a complete versioned measurement contract. Start with Button/Card/StatTile across explicit light/dark/state/viewport fixtures. Ask for documented stable selectors and supported measurements; preserve actual semantic token names instead of inverse-matching equal colors/radii. |
|
|
17
|
+
| P1 | Document or expose component-derived radius and typography roles. | The source theme variable inventory includes general radius/radiusButton and typography scales. Claude reported Card radius 8, StatTile radius 24 and StatTile value 28/600/-0.84 in its trial context. Ask for the relationship to theme inputs and supported semantic roles; let new measurements establish values before proposing named tokens or formulas. Acceptance includes theme changes and explicit fallback constants. |
|
|
18
|
+
| P2 | Clarify the supported StatTile/StatCard composition route for charts. | StatTile has a fixed typed body; StatCard accepts normal Card children. Ask for a documented chart composition recipe first. Add a new slot only if the existing composition cannot preserve intended layout, keyboard behavior and semantics. |
|
|
19
|
+
| P2 | Discuss an upstream sidebar/navigation primitive if several consumers need the same contract. | No export in the inspected 1.11.0 React declarations; the consumer's existing SidebarNav already supplies its local implementation. Acceptance should cover active state, keyboard/focus semantics, responsive collapse and theme roles. Collect a reusable requirement before proposing upstream code. |
|
|
20
|
+
| P3 | Check numeric-zero trend rendering and trend accessible-label input. | React source accepts ReactNode, renders trend with a truthiness check, and passes only string values to the core trend-label recipe. Ask for a focused test of `trendValue={0}` and numeric content. This is a source-based candidate edge case, not an observed browser/accessibility failure. |
|
|
21
|
+
|
|
22
|
+
## Review/send checklist
|
|
23
|
+
|
|
24
|
+
- [ ] Owner selects which requests are useful and approves exact wording.
|
|
25
|
+
- [ ] Maintainer/current-version check confirms the requested capability is still absent or undocumented.
|
|
26
|
+
- [ ] C1 fixture captures exact theme, viewport, state, fonts and source version for numerical claims.
|
|
27
|
+
- [ ] Attach only owner-reviewed, non-private evidence and a minimal reproduction.
|
|
28
|
+
- [ ] Owner decides whether to send; no message or issue has been created here.
|
|
29
|
+
- [ ] Record maintainer response and resulting backlog changes after an authorized exchange.
|
|
30
|
+
|
|
31
|
+
## Reproduction evidence
|
|
32
|
+
|
|
33
|
+
Read [the source inventory](marwes-1.11.0-evidence.json). It records package versions and source-map hashes, with source paths within those maps. It contains no consumer designs, credentials or private project source. Reproduce with the same package artifacts and inspect the named source entries; rendered behavior still needs a real fixture.
|
|
34
|
+
|
|
35
|
+
These corrections strengthen Claude's brief: the useful requests are about reproducible anatomy and explicit semantic contracts. Existing optional props and consumer components should be reused before asking for duplicate capabilities. Equal measured values alone cannot establish token semantics or make design-to-code behavior mechanical.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@penpair/web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.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": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"access": "public"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@penpair/core": "0.
|
|
50
|
+
"@penpair/core": "0.2.0"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"build": "tsc -p tsconfig.json",
|