@penpair/web 0.2.0 → 0.3.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/README.md +18 -3
- package/docs/adapters.md +90 -0
- package/docs/build-kit.md +4 -2
- package/docs/conventions/README.md +63 -0
- package/docs/conventions/completion-2026-10-22.md +73 -0
- package/docs/conventions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/docs/conventions/plugin-code.md +23 -0
- package/docs/conventions/structure.md +48 -0
- package/docs/conventions/templates/adapter-command.ts +28 -0
- package/docs/conventions/templates/conventions.test.ts +81 -0
- package/docs/conventions/templates/frame-inspection.ts +27 -0
- package/docs/conventions/templates/frame-label.ts +15 -0
- package/docs/conventions/tsconfig.json +13 -0
- package/docs/conventions/typescript.md +59 -0
- package/docs/conventions/vitest.config.ts +11 -0
- package/docs/design-workflow.md +3 -1
- package/docs/fixtures/browser-capture-2026-10-22.json +217 -0
- package/docs/fixtures/feedback-reproductions.md +12 -0
- package/docs/fixtures/feedback-scratch.template.json +9 -0
- package/docs/formats.md +2 -0
- package/docs/getting-started.md +2 -0
- package/docs/guide.md +2 -2
- package/docs/handoff.md +2 -0
- package/docs/marwes-tokens.md +13 -0
- package/docs/marwes.md +2 -0
- package/docs/plans/registry-polling-fix.md +101 -0
- package/docs/plans/skill-workflow-readiness.md +178 -0
- package/docs/plans/tradient-feedback-0.2.0.md +209 -0
- package/docs/plans/tradient-feedback-review.md +83 -0
- package/docs/recovery.md +8 -0
- package/docs/releasing.md +34 -4
- package/docs/skill-installation.md +21 -0
- package/docs/skill-validation.md +86 -0
- package/docs/snapshots.md +1 -1
- package/docs/theme-previews.md +18 -0
- package/examples/component-pilot/renderer.mjs +100 -0
- package/examples/coverage-matrix.json +126 -0
- package/examples/hello-card/README.md +18 -0
- package/examples/hello-card/build.js +24 -0
- package/examples/hello-card/helpers.js +27 -0
- package/examples/hello-card/inspect.js +4 -0
- package/examples/hello-card/readback.js +3 -0
- package/examples/reflection-browser/README.md +49 -0
- package/examples/reflection-browser/capture.mjs +311 -0
- package/examples/reflection-browser/fixture/Abel-Regular.ttf +0 -0
- package/examples/reflection-browser/fixture/OFL.txt +93 -0
- package/examples/reflection-browser/fixture/index.html +11 -0
- package/examples/reflection-browser/fixture-hooks.mjs +24 -0
- package/examples/reflection-browser/provider.mjs +90 -0
- package/examples/reflection-browser/serve.mjs +37 -0
- package/examples/theme-preview/README.md +21 -0
- package/examples/theme-preview/apply.js +8 -0
- package/examples/theme-preview/helpers.js +12 -0
- package/examples/theme-preview/inspect.js +3 -0
- package/examples/theme-preview/readback.js +7 -0
- package/examples/trials/hold-inspect.js +5 -0
- package/examples/trials/hold-readback.js +8 -0
- package/examples/trials/hold-writer.js +16 -0
- package/examples/trials/recovery-build.js +23 -0
- package/examples/trials/recovery-inspect.js +10 -0
- package/examples/trials/recovery-readback.js +7 -0
- package/examples/trials/wrong-file-read.js +3 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
Inspect structure and tokens, compose reviewed recipes, capture references and hand design evidence to the implementation. Penpot holds the design; Git holds declarations, snapshots and review records.
|
|
6
6
|
|
|
7
|
+
**Design in Penpot → hand off to frontend code → check the implementation.** Add the companion adapters for the parts of that workflow your project uses:
|
|
8
|
+
|
|
9
|
+
| Companion | When to add it | What it helps with |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| [Marwes UI adapter](docs/adapters.md#bring-your-component-library-into-penpot) | Your application uses Marwes UI | Bring library/project tokens into Penpot, detect drift and compose library-aware recipes |
|
|
12
|
+
| [Reflection Check adapter](docs/adapters.md#check-the-frontend-against-the-design) | You implement a frontend from Penpot and want repeatable visual checks | Connect approved design cases to real browser captures and comparison evidence |
|
|
13
|
+
|
|
14
|
+
**Reflection Check is the recommended companion for design-to-frontend verification.** Install it explicitly alongside your command package. It needs approved references and a project browser provider; the [adapter guide](docs/adapters.md) shows installation, registration and readiness steps.
|
|
15
|
+
|
|
7
16
|
## Choose your path
|
|
8
17
|
|
|
9
18
|
| You want to… | Start here |
|
|
@@ -12,6 +21,7 @@ Inspect structure and tokens, compose reviewed recipes, capture references and h
|
|
|
12
21
|
| Let an agent guide setup | [Setup guide skill](skills/penpair-setup-guide/SKILL.md) |
|
|
13
22
|
| Join a shared file | [Team guide](docs/team.md) |
|
|
14
23
|
| Build and review a page | [Design workflow](docs/design-workflow.md) |
|
|
24
|
+
| Choose adapters or check the frontend | [Companion adapters](docs/adapters.md) |
|
|
15
25
|
| Resolve a failure | [Troubleshooting](docs/troubleshooting.md) |
|
|
16
26
|
| Extend the framework | [Guide and reference map](docs/guide.md) |
|
|
17
27
|
|
|
@@ -30,20 +40,25 @@ pnpm exec penpair skills install --dry-run
|
|
|
30
40
|
|
|
31
41
|
Confirm the owner-authorized file ID, then follow the [skill installation preview](docs/skill-installation.md). Each teammate uses their own key. Prefer a team/web Penpot; [Docker is an alternative](packages/core/skills/penpair-setup/references/web-or-docker.md).
|
|
32
42
|
|
|
33
|
-
|
|
43
|
+
Use the installed version's `--help` to confirm available commands. For an unreleased source trial, install the complete matching package set described in the [trial runbook](docs/trials.md). Live/human acceptance gates remain explicit.
|
|
34
44
|
|
|
35
45
|
## Packages and workflows
|
|
36
46
|
|
|
37
|
-
Install one command package: `@penpair/web`, or `@penpair/docker` for a local instance. Both use the neutral `@penpair/core` library.
|
|
47
|
+
Install one command package: `@penpair/web`, or `@penpair/docker` for a local instance. Both use the neutral `@penpair/core` library. Add the [companion adapters](docs/adapters.md) your workflow needs. Keep their versions aligned with the command package. The unscoped `penpair` wrapper currently has a publishing exception; use the scoped command package. Every repository package is versioned together; publishing belongs to the owner.
|
|
38
48
|
|
|
39
49
|
| Shipped skill | Use |
|
|
40
50
|
| --- | --- |
|
|
41
51
|
| [penpair-setup](packages/core/skills/penpair-setup/SKILL.md) | Connect or repair project setup |
|
|
42
52
|
| [penpair-design](packages/core/skills/penpair-design/SKILL.md) | Inspect and operate on a design file |
|
|
43
53
|
| [penpair-recipes](packages/core/skills/penpair-recipes/SKILL.md) | Compose a page with reviewed recipes |
|
|
44
|
-
| [penpair-handoff](packages/core/skills/penpair-handoff/SKILL.md) |
|
|
54
|
+
| [penpair-handoff](packages/core/skills/penpair-handoff/SKILL.md) | Map components and implement from design evidence |
|
|
55
|
+
| [penpair-verify](packages/core/skills/penpair-verify/SKILL.md) | Compare the real frontend, inspect images and recheck fixes |
|
|
45
56
|
| [design-judgment](packages/core/skills/design-judgment/SKILL.md) | Assess page structure and hierarchy |
|
|
46
57
|
|
|
58
|
+
Check a consumer's Codex installation with `pnpm exec penpair skills check --json`.
|
|
59
|
+
[Discovery diagnostics and behavior trials](docs/skill-validation.md) explain what
|
|
60
|
+
that establishes and how to verify actual skill use.
|
|
61
|
+
|
|
47
62
|
[Cookbook](docs/cookbook.md) · [MCP tools](docs/mcp.md) · [Format contracts](docs/formats.md) · [Compatibility](docs/compatibility.md) · [Recovery](docs/recovery.md) · [Living checklist](docs/improvements.md)
|
|
48
63
|
|
|
49
64
|
See [CONTRIBUTING](CONTRIBUTING.md), [SECURITY](SECURITY.md), [release steps](docs/releasing.md), [CHANGELOG](CHANGELOG.md) and the [MIT licence](LICENSE). Comparison metrics supply evidence for review; they do not approve a design.
|
package/docs/adapters.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Companion adapters
|
|
2
|
+
|
|
3
|
+
Penpair connects the design workflow to the libraries and implementation tools a project already uses. Choose the command package for your Penpot connection, then add companions for your intended workflow.
|
|
4
|
+
|
|
5
|
+
| Your workflow | Recommendation | Required project inputs |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| Inspect, build and export Penpot designs | One of `@penpair/web` or `@penpair/docker` | A configured connection and pinned design file |
|
|
8
|
+
| Use Marwes UI in the frontend and Penpot | Add `@penpair/marwes-ui` | Installed library, project theme and reviewed token declarations |
|
|
9
|
+
| Implement frontend code and compare it with Penpot | Add `@penpair/reflection-check` | Approved design baselines, explicit cases and a real browser provider |
|
|
10
|
+
|
|
11
|
+
Adapters are installed and registered explicitly. Both companions can be used together; a comparison workflow does not require the library adapter. Keep the command package, its resolved core and directly installed adapters at the same reviewed version. Do not install both command packages.
|
|
12
|
+
|
|
13
|
+
## Bring your component library into Penpot
|
|
14
|
+
|
|
15
|
+
`@penpair/marwes-ui` connects the installed Marwes library and project theme to token snapshots, ownership-aware drift checks and reviewed token operations. It also provides compositional recipes and a measured-component pilot. Native component generation remains gated on actual override-preservation proof.
|
|
16
|
+
|
|
17
|
+
Use it when your application uses Marwes UI. Follow the [adapter overview](marwes.md), [token configuration](marwes-tokens.md) and [build-kit guide](build-kit.md). Other libraries need their own adapters or explicit project declarations; the core contains no library defaults.
|
|
18
|
+
|
|
19
|
+
## Check the frontend against the design
|
|
20
|
+
|
|
21
|
+
**Recommend `@penpair/reflection-check` whenever frontend implementation and visual verification are part of the task.** It connects an approved Penpot design case to the corresponding running application case:
|
|
22
|
+
|
|
23
|
+
1. Inspect the design and create a [handoff](handoff.md).
|
|
24
|
+
2. Capture and review [baseline cases](coverage.md), including viewport, theme, state, fixture and fonts.
|
|
25
|
+
3. Implement the frontend using the project's actual components and behavior.
|
|
26
|
+
4. Map each approved design case to explicit application setup.
|
|
27
|
+
5. Run a project provider to open that state, read it back, capture the browser and compare the image.
|
|
28
|
+
6. Review the screenshots and differences; record human approval separately.
|
|
29
|
+
|
|
30
|
+
The adapter checks that the returned evidence identifies the requested case and expected state, references the correct unchanged baseline, and has matching PNG dimensions/scale and font evidence. A complete result within the configured difference threshold is technical evidence, not visual approval or an accessibility assessment.
|
|
31
|
+
|
|
32
|
+
The provider is project code with an `async runCase(test)` export. It supplies actual route/theme/state/fixture setup, browser readback, screenshot capture and image comparison through the project's pinned tools. It can integrate the project's existing Reflection/browser checker. The adapter itself does not install a browser or execute a particular Reflection engine automatically.
|
|
33
|
+
|
|
34
|
+
### Install and register
|
|
35
|
+
|
|
36
|
+
First check your installed command version:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
pnpm exec penpair --version
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
For example, a project whose command/core are **0.3.0** installs this matching
|
|
43
|
+
companion. Use the actual installed version when it differs:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
pnpm add -D -E @penpair/reflection-check@0.3.0
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Use the version printed above when it differs. In a pnpm workspace, use the existing dependency location (`-w` when installing at the workspace root). Upgrade directly installed Penpair packages together rather than mixing releases.
|
|
50
|
+
|
|
51
|
+
Append the adapter to the existing `adapters` array in `penpair.config.json`, preserving other fields and already configured adapters:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"adapters": ["@penpair/reflection-check"]
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
That JSON is a fragment to merge, not a replacement project config. The library companion is installed the same way at the matching version and registered as `@penpair/marwes-ui`; only register packages you have installed.
|
|
60
|
+
|
|
61
|
+
### Progress from installed to working
|
|
62
|
+
|
|
63
|
+
- [ ] **Installed and registered:** the matching adapter dependency and config entry exist. `penpair --help` can identify configured extensions without executing them.
|
|
64
|
+
- [ ] **References ready:** configured file pin and baseline frames have current exact approved provenance and explicit case metadata.
|
|
65
|
+
- [ ] **Mapping ready:** `design/implementation-cases.json` maps each baseline case ID to its project setup name.
|
|
66
|
+
- [ ] **Provider ready:** `design/reflection-provider.mjs` exports `runCase` and uses actual browser/checker work; requested inputs are not copied into observed results.
|
|
67
|
+
- [ ] **Verified in the browser:** the plan has no pending cases, the provider executes the intended cases and the owner looks at the resulting images.
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
pnpm exec penpair reflection plan --map design/implementation-cases.json
|
|
71
|
+
pnpm exec penpair reflection check --map design/implementation-cases.json --provider design/reflection-provider.mjs
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Use the [package reference](https://github.com/niklas-westman/penpair/blob/main/packages/reflection-check/README.md) for mapping/provider examples. Exit **0** means complete evidence within threshold, **2** means measured drift and **3** means missing/incomplete evidence. An install, a passing setup check or a stub provider is not a completed frontend comparison.
|
|
75
|
+
|
|
76
|
+
The browser-provider starter ships with the command package; supply real project
|
|
77
|
+
hooks or report integration as pending. The shipped
|
|
78
|
+
[penpair-verify skill](../packages/core/skills/penpair-verify/SKILL.md) guides
|
|
79
|
+
comparison, image inspection, implementation fixes and recapture. For simple
|
|
80
|
+
legacy route/viewport checks, the existing generated `reflection-cases.json` and
|
|
81
|
+
`visualSmoke` configuration remain available; richer cases require explicit setup
|
|
82
|
+
and readback.
|
|
83
|
+
|
|
84
|
+
## Why explicit companions?
|
|
85
|
+
|
|
86
|
+
The design-only workflow can start with one command package. Frontend projects should be guided toward the comparison companion during setup and handoff. Keeping installation explicit lets each project choose its browser/checker and supply meaningful setup instead of treating an added dependency as a finished integration.
|
|
87
|
+
|
|
88
|
+
The shipped setup/handoff skills should recommend the appropriate companion, preserve existing adapter configuration and report readiness at each stage. They must keep missing references or provider work visible and never invent owner approval.
|
|
89
|
+
|
|
90
|
+
Use the shipped [real-browser provider starter](../examples/reflection-browser/README.md) to supply capture plumbing while keeping route/theme/state/fixture hooks project-owned. It includes measured font, pointer, scroll and crop evidence; a browser dependency is not added to the core.
|
package/docs/build-kit.md
CHANGED
|
@@ -24,8 +24,8 @@ The last two examples require the token adapter configured in the adopting proje
|
|
|
24
24
|
| `inst(parent, path, name, textOverrides, library?)` | Exact unique component match; validates named text overrides and never removes/reorders instance children. Defaults to the local library. |
|
|
25
25
|
| `style(shape, options)` | Queues requested styling only; an isolated color update preserves existing spacing and bindings. |
|
|
26
26
|
| `fill`, `fillV` | Sets layout-child horizontal/vertical fill sizing. |
|
|
27
|
-
| `settle(root, options)` |
|
|
28
|
-
| `flush({root, timeoutMs})` | Waits for layout, applies queued values/styles, then awaits queued bindings, then settles again. Active token-context changes refuse. |
|
|
27
|
+
| `settle(root, options)` | `strategy: auto | native | geometry`, default auto. Auto caps native at min(500 ms, remaining/4), then requires three complete equal geometry/hierarchy samples. Time/node/malformed evidence cannot report stable. |
|
|
28
|
+
| `flush({root, timeoutMs, strategy})` | Waits for layout, applies queued values/styles, then awaits queued bindings, then settles again. Active token-context changes refuse. |
|
|
29
29
|
|
|
30
30
|
Always `await pp.flush()` before independent readback/export. There are no fixed 1.2/2.5-second styling sleeps. Layout completion does not prove font download, token persistence or pixels; keep positive readback and stable exports. Queues are local to one execution, not a recovery log. Partial errors are not transactions; the enclosing reviewed operation must own and reconcile its roots. Bindings remain subject to the runtime's supported token properties; A4 owns the broader compatibility whitelist.
|
|
31
31
|
|
|
@@ -55,3 +55,5 @@ These are compositional starting points. They are not generated native component
|
|
|
55
55
|
A verified trial saves a private PNG preview under `.penpair/probes/`, with byte hash and capture identity. Look at the preview as the write protocol requires. `visualApproval: false` remains explicit. Redacted/incomplete evidence cannot publish a preview; an existing differing preview is preserved. No new live pinned-version trial has been performed in this branch.
|
|
56
56
|
|
|
57
57
|
Current references: [flex layout](https://doc.plugins.penpot.app/interfaces/FlexLayout), [font application](https://doc.plugins.penpot.app/interfaces/Font), [component instantiation](https://doc.plugins.penpot.app/interfaces/LibraryComponent), [spacing properties](https://doc.plugins.penpot.app/types/TokenSpacingProps) and [sizing properties](https://doc.plugins.penpot.app/types/TokenSizingProps). Runtime capability and independent evidence remain required.
|
|
58
|
+
|
|
59
|
+
Host operations retain a 30 s total layout deadline; kit settle/flush default to 10 s. `native` reports failure without fallback; `geometry` skips native waiting. Diagnostics include the chosen strategy, native outcome, fallback reason and elapsed time. Neither transport loss, cancellation, changed target nor malformed/truncated data becomes a successful fallback. `run-file`, `export` and `shots` accept `--layout auto|native|geometry`. The default is suitable for ordinary builds; there is no CLI off mode.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Code conventions
|
|
2
|
+
|
|
3
|
+
Start with the row matching the change. Copy the relevant pattern, then use the
|
|
4
|
+
nearest production module's domain vocabulary. The examples compile and run in
|
|
5
|
+
`pnpm conventions:check`; production code never imports them.
|
|
6
|
+
|
|
7
|
+
The [completion report](completion-2026-10-22.md) records the initial rollout,
|
|
8
|
+
resolved problems, verification and limits.
|
|
9
|
+
|
|
10
|
+
| Work | Read | Checked example |
|
|
11
|
+
| --- | --- | --- |
|
|
12
|
+
| Choose a package, folder or module boundary | [Structure](structure.md) | [Comparison adapter](../../packages/reflection-check/src/index.ts) |
|
|
13
|
+
| Write a helper, contract or test | [TypeScript](typescript.md) | [Frame label](templates/frame-label.ts), [tests](templates/conventions.test.ts) |
|
|
14
|
+
| Add an adapter command | [TypeScript](typescript.md), [structure](structure.md) | [Offline command](templates/adapter-command.ts) |
|
|
15
|
+
| Generate code for the Penpot sandbox | [Plugin code](plugin-code.md) | [Read-only snippet](templates/frame-inspection.ts) |
|
|
16
|
+
| Change release or workspace scripts | [Structure](structure.md), [releasing](../releasing.md) | Existing sibling in `scripts/` |
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
pnpm format # Format supported source/configuration files
|
|
20
|
+
pnpm lint:fix # Apply safe lint fixes
|
|
21
|
+
pnpm check:style # Check formatting, focused lint rules and code directory names
|
|
22
|
+
pnpm conventions:check # Typecheck and execute these examples
|
|
23
|
+
pnpm check # Style, build, typecheck, examples, tests and version consistency
|
|
24
|
+
pnpm smoke:package # Verify the packaged installation shapes
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`biome.json` is the formatting authority: two spaces, LF, a 100-column target,
|
|
28
|
+
double quotes, semicolons, expanded object/array layouts and parenthesized arrow
|
|
29
|
+
parameters. Braces and one variable per declaration keep control flow readable.
|
|
30
|
+
Use the editor's Biome extension with the repository's pinned version if desired;
|
|
31
|
+
`.editorconfig` supplies the basic whitespace settings in other editors.
|
|
32
|
+
|
|
33
|
+
Biome checks filenames; `check-code-paths.mjs` checks directories containing code
|
|
34
|
+
under `packages/`, `scripts/`, `examples/` and this folder, including new untracked
|
|
35
|
+
files. Both run in CI through `pnpm check`. Human/agent review still checks whether
|
|
36
|
+
names describe intent and whether responsibilities should be split. A formatter
|
|
37
|
+
cannot judge those decisions.
|
|
38
|
+
|
|
39
|
+
Vertical spacing is also an author/review responsibility: Biome keeps intentional
|
|
40
|
+
blank lines, but does not add separation between declarations or logical steps.
|
|
41
|
+
Follow [TypeScript spacing guidance](typescript.md) even when `check:style` passes.
|
|
42
|
+
|
|
43
|
+
The [repository skill](../../.agents/skills/penpair-code-conventions/SKILL.md)
|
|
44
|
+
applies this workflow to implementation and refactoring work. It develops Penpair
|
|
45
|
+
itself; the separately shipped `packages/core/skills/` teach consumers how to use
|
|
46
|
+
Penpair with their designs.
|
|
47
|
+
|
|
48
|
+
## Coverage and exceptions
|
|
49
|
+
|
|
50
|
+
- Generated `dist/`, dependencies, ignored local artifacts and data fixtures are
|
|
51
|
+
outside formatting. Keep captured evidence unchanged.
|
|
52
|
+
- `docs/trials/` and `docs/upstream/` preserve external evidence.
|
|
53
|
+
- Raw plugin bodies in `examples/hello-card/`, `examples/theme-preview/` and
|
|
54
|
+
`examples/trials/` may contain a top-level `return`, which Biome's module parser
|
|
55
|
+
rejects. Their existing sandbox tests compile them as async function bodies.
|
|
56
|
+
Follow [plugin code](plugin-code.md) when editing them.
|
|
57
|
+
- JavaScript inside template strings is string data to Biome. Format that source
|
|
58
|
+
deliberately and test the generated snippet. Do not run blind whitespace
|
|
59
|
+
rewriting over strings, serialized snapshots or embedded protocols.
|
|
60
|
+
|
|
61
|
+
Add new file-type examples when an actual feature needs a pattern. Keep them
|
|
62
|
+
minimal and executable; do not introduce a framework or dependency just for a
|
|
63
|
+
template.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Readability conventions completion — 2026-10-22
|
|
2
|
+
|
|
3
|
+
Branch: `codex/tradient-feedback`. All repository package versions remain 0.2.0.
|
|
4
|
+
|
|
5
|
+
## Completed checklist and what each update resolves
|
|
6
|
+
|
|
7
|
+
- [x] **Readable formatting baseline.** Pin Biome 2.6.2, use two-space indentation
|
|
8
|
+
and expanded layouts, add braces and separate variable declarations. This
|
|
9
|
+
removes compressed source layouts and makes subsequent diffs consistent. The
|
|
10
|
+
mechanical baseline is its own commit, `b1a9445`, for review.
|
|
11
|
+
- [x] **Maintained conventions.** Add task-based guidance for naming, package
|
|
12
|
+
ownership, module extraction, TypeScript, tests and sandbox code. This gives new
|
|
13
|
+
work a concrete placement and implementation pattern instead of relying on
|
|
14
|
+
memory or copying unrelated frontend conventions.
|
|
15
|
+
- [x] **Checked examples.** Typecheck actual core contracts and run helper,
|
|
16
|
+
sandbox-generation and path-rule tests. This catches stale examples and proves
|
|
17
|
+
that the generated plugin body compiles and behaves as documented.
|
|
18
|
+
- [x] **Agent discovery.** Link the conventions and repository-local
|
|
19
|
+
`penpair-code-conventions` skill from `AGENTS.md`, with contributor routing from
|
|
20
|
+
`CONTRIBUTING.md`. This makes readable names and early responsibility extraction
|
|
21
|
+
part of the implementation workflow.
|
|
22
|
+
- [x] **Continuous enforcement.** Include Biome, directory naming and example
|
|
23
|
+
validation in `pnpm check`, which existing CI already runs. The CI job name stays
|
|
24
|
+
stable for branch protection. These checks prevent automatic style/path drift;
|
|
25
|
+
review still judges the meaning of names and module boundaries.
|
|
26
|
+
- [x] **Comparison adapter extraction.** Replace the dense entrypoint with focused
|
|
27
|
+
public contracts, planning, capture validation, provider validation, PNG I/O,
|
|
28
|
+
orchestration and command modules. Public imports, report fields, approval gates
|
|
29
|
+
and command behavior remain compatible. Shared test fixtures and capture tests
|
|
30
|
+
also have focused files.
|
|
31
|
+
- [x] **Installed contract verification.** Extend package smoke testing to import
|
|
32
|
+
the packed adapter's public functions/default export and typecheck its public
|
|
33
|
+
contracts. This catches missing extracted files or broken declaration exports.
|
|
34
|
+
|
|
35
|
+
## Validation
|
|
36
|
+
|
|
37
|
+
- `pnpm check` passes: **640 package tests plus 3 convention tests**, style/path
|
|
38
|
+
checks, builds, typechecks and the six-package version guard.
|
|
39
|
+
- `pnpm smoke:package` passes for all **six tarballs**, including the new runtime
|
|
40
|
+
export and declaration checks.
|
|
41
|
+
- The comparison package's tests/helpers also pass a separate strict TypeScript
|
|
42
|
+
check. Skill YAML metadata, UI metadata and local convention/skill links resolve.
|
|
43
|
+
- Before the manual extraction, an AST comparison across 199 changed
|
|
44
|
+
JavaScript/TypeScript files found no differences beyond formatting, equivalent
|
|
45
|
+
control-flow blocks and separate declarations. The initial formatted baseline
|
|
46
|
+
passed all 630 pre-existing tests.
|
|
47
|
+
- `git diff --check` passes. A patch Changeset records the delivered refactor and
|
|
48
|
+
documentation. No version bump, push, publication or live Penpot write occurred.
|
|
49
|
+
|
|
50
|
+
## Limits
|
|
51
|
+
|
|
52
|
+
Biome cannot determine whether a name expresses the right domain meaning or when
|
|
53
|
+
responsibilities deserve separate modules; the skill and review cover those
|
|
54
|
+
decisions. Raw async plugin bodies, JavaScript inside strings, generated artifacts
|
|
55
|
+
and captured fixtures retain the handling described in the [conventions index](README.md).
|
|
56
|
+
This update does not constitute new live Penpot or browser acceptance. The
|
|
57
|
+
[existing pending acceptance](../plans/tradient-feedback-review.md#remaining-acceptance)
|
|
58
|
+
stays open.
|
|
59
|
+
|
|
60
|
+
## Vertical spacing correction
|
|
61
|
+
|
|
62
|
+
- [x] Separate declarations and individual steps in the component pilot module.
|
|
63
|
+
- [x] Clarify that Biome retains author-supplied blank lines but does not insert
|
|
64
|
+
the separation required by the conventions.
|
|
65
|
+
|
|
66
|
+
Resolved: `packages/marwes-ui/src/components.ts` passed Biome while remaining
|
|
67
|
+
visually dense. The file now has blank lines between its contracts, functions,
|
|
68
|
+
guards and work steps. The diff contains only added blank lines, and Biome keeps
|
|
69
|
+
them. `pnpm check:style` and all three existing component tests pass. No behavior
|
|
70
|
+
changed; the full suite was not rerun for this whitespace-only follow-up.
|
|
71
|
+
|
|
72
|
+
Automatic vertical-spacing enforcement remains outside the current Biome checks;
|
|
73
|
+
the conventions and code review require it explicitly.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":"3.2.4","results":[[":templates/conventions.test.ts",{"duration":3.757374000000027,"failed":false}]]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Penpot plugin source
|
|
2
|
+
|
|
3
|
+
Node-side TypeScript and the Penpot editor sandbox are different environments.
|
|
4
|
+
The sandbox has `penpot` and explicit injected values such as `CFG`; it cannot
|
|
5
|
+
import Node filesystem modules or reach local project paths. Keep Node I/O outside
|
|
6
|
+
the generated source. Use the neutral kit/snippet APIs and actual upstream names.
|
|
7
|
+
|
|
8
|
+
Raw plugin files are async function bodies and may return at the top level.
|
|
9
|
+
`*.ts` generators are ordinary Node modules and are formatted by Biome; their
|
|
10
|
+
template string contents need deliberate formatting. Prefer readable multiline
|
|
11
|
+
source with descriptive names and braces. Preserve string values and parameter
|
|
12
|
+
serialization when editing whitespace.
|
|
13
|
+
|
|
14
|
+
The [frame inspection example](templates/frame-inspection.ts) shows a small
|
|
15
|
+
read-only generator. Its tests compile the generated body and execute it against
|
|
16
|
+
a sandbox stub. This catches syntax and behavior errors that formatting the
|
|
17
|
+
outer TypeScript module cannot catch.
|
|
18
|
+
|
|
19
|
+
For writes, follow [the write protocol](../../packages/core/skills/penpair-design/references/write-protocol.md):
|
|
20
|
+
inspect, pin a snapshot, perform one idempotent write, independently read back,
|
|
21
|
+
then export and look. Preserve file/page guards, bounded layout settling and the
|
|
22
|
+
under-90-KB transport limit. A syntax test does not prove live Penpot behavior.
|
|
23
|
+
Tests may stub read-only sandbox objects; live acceptance remains separate.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Folder and module structure
|
|
2
|
+
|
|
3
|
+
Place code with the responsibility that owns it. The dependency direction is
|
|
4
|
+
command packages/adapters → core; the core never imports an adapter or names a
|
|
5
|
+
consumer project or component library.
|
|
6
|
+
|
|
7
|
+
| Location | Owns |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `packages/core/src/` | Neutral engine, validation, transport and public extension contracts |
|
|
10
|
+
| `packages/web/`, `packages/docker/`, `packages/penpair/` | Command distribution and profile-specific lifecycle |
|
|
11
|
+
| `packages/<adapter>/src/` | Library/tool knowledge and its adapter commands |
|
|
12
|
+
| `packages/<package>/test/` | That package's behavior and integration contracts |
|
|
13
|
+
| `scripts/` and `scripts/lib/` | Workspace/release tooling and reusable script helpers |
|
|
14
|
+
| `examples/<feature>/` | Consumer-facing workflows and explicit sample project knowledge |
|
|
15
|
+
| `packages/core/skills/` | Shipped consumer workflows |
|
|
16
|
+
| `.agents/skills/` | Skills for developing this repository |
|
|
17
|
+
| `docs/conventions/templates/` | Checked examples, never runtime dependencies |
|
|
18
|
+
|
|
19
|
+
Use kebab-case for new code directories and filenames. Prefer a domain name such
|
|
20
|
+
as `capture-validation.ts` over `helpers.ts`, `utils.ts` or `manager.ts`. Add a
|
|
21
|
+
feature folder when several related files form one cohesive area; keep small
|
|
22
|
+
features as siblings rather than adding a directory around every file. Preserve
|
|
23
|
+
tool-required names such as `AGENTS.md`, `SKILL.md` and `README.md`.
|
|
24
|
+
|
|
25
|
+
## Split as soon as a responsibility stands on its own
|
|
26
|
+
|
|
27
|
+
Extract a responsibility when it has its own inputs/outputs, invariants or useful
|
|
28
|
+
tests. Do this in the change that introduces it. Typical splits are public types,
|
|
29
|
+
argument parsing/provider loading, pure planning, evidence validation and image
|
|
30
|
+
I/O. Keep a package's public `index.ts` focused on exports and adapter wiring.
|
|
31
|
+
Preserve public imports when moving implementations.
|
|
32
|
+
|
|
33
|
+
The comparison adapter demonstrates this shape: `case-plan.ts` plans approved
|
|
34
|
+
cases, `evidence-validation.ts` validates observed state, `capture-validation.ts`
|
|
35
|
+
checks browser geometry, `png-evidence.ts` reads bounded images, `run-cases.ts`
|
|
36
|
+
orchestrates evidence collection, and `command.ts` handles CLI/provider loading.
|
|
37
|
+
|
|
38
|
+
Do not split tightly coupled steps solely to make files short. Avoid one-line
|
|
39
|
+
forwarders and a forest of generic folders. Repeated domain code, mixed I/O and
|
|
40
|
+
validation, a long boolean condition, or unrelated reasons for a file to change
|
|
41
|
+
are stronger signals than a line count. Around 200 lines in a module or 40 lines
|
|
42
|
+
in a function is a review prompt, not an automatic failure or a reason to hide
|
|
43
|
+
complexity in another large helper.
|
|
44
|
+
|
|
45
|
+
Before extracting, identify the public contract and the tests that protect it.
|
|
46
|
+
After extracting, read the orchestration from top to bottom: names should explain
|
|
47
|
+
the workflow without opening every helper. Keep shared types below implementations
|
|
48
|
+
in the dependency direction and avoid circular imports or unnecessary barrels.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AdapterCommand, AdapterContext } from "../../../packages/core/src/adapters.js";
|
|
2
|
+
|
|
3
|
+
async function runExampleStatus(
|
|
4
|
+
context: AdapterContext,
|
|
5
|
+
commandArguments: string[],
|
|
6
|
+
): Promise<number> {
|
|
7
|
+
if (commandArguments.length > 0) {
|
|
8
|
+
throw new Error("Usage: example-status");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const report = {
|
|
12
|
+
configured: Boolean(context.config.file),
|
|
13
|
+
};
|
|
14
|
+
context.output?.result(report);
|
|
15
|
+
context.log(JSON.stringify(report));
|
|
16
|
+
|
|
17
|
+
return report.configured ? 0 : 3;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Register in an adapter's defineAdapter({ commands: [...] }) when adopting this pattern.
|
|
21
|
+
export const exampleStatusCommand: AdapterCommand = {
|
|
22
|
+
name: "example-status",
|
|
23
|
+
summary: "Report offline file-pin readiness",
|
|
24
|
+
usage: [
|
|
25
|
+
"penpair example-status",
|
|
26
|
+
],
|
|
27
|
+
run: runExampleStatus,
|
|
28
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { compiles } from "../../../packages/core/src/snippet.js";
|
|
3
|
+
import { findInvalidCodeDirectories } from "../../../scripts/check-code-paths.mjs";
|
|
4
|
+
import { formatFrameLabel } from "./frame-label.js";
|
|
5
|
+
import { createFrameInspection } from "./frame-inspection.js";
|
|
6
|
+
|
|
7
|
+
describe("convention examples", () => {
|
|
8
|
+
it("normalizes names and refuses incomplete labels", () => {
|
|
9
|
+
expect(
|
|
10
|
+
formatFrameLabel({
|
|
11
|
+
pageName: " Dashboard ",
|
|
12
|
+
frameName: " Empty ",
|
|
13
|
+
}),
|
|
14
|
+
).toBe("Dashboard / Empty");
|
|
15
|
+
expect(() =>
|
|
16
|
+
formatFrameLabel({
|
|
17
|
+
pageName: " ",
|
|
18
|
+
frameName: "Empty",
|
|
19
|
+
}),
|
|
20
|
+
).toThrow("requires");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("compiles and executes the generated read-only sandbox body", async () => {
|
|
24
|
+
const inspection = createFrameInspection("Empty");
|
|
25
|
+
expect(compiles(inspection.code)).toBeUndefined();
|
|
26
|
+
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
|
|
27
|
+
const executeInspection = new AsyncFunction("penpot", inspection.code);
|
|
28
|
+
const frame = {
|
|
29
|
+
id: "frame-1",
|
|
30
|
+
type: "board",
|
|
31
|
+
name: "Empty",
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
expect(
|
|
35
|
+
await executeInspection({
|
|
36
|
+
currentPage: {
|
|
37
|
+
children: [
|
|
38
|
+
frame,
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
).toEqual({
|
|
43
|
+
ok: true,
|
|
44
|
+
frameId: "frame-1",
|
|
45
|
+
frameName: "Empty",
|
|
46
|
+
});
|
|
47
|
+
expect(
|
|
48
|
+
await executeInspection({
|
|
49
|
+
currentPage: {
|
|
50
|
+
children: [
|
|
51
|
+
frame,
|
|
52
|
+
frame,
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
}),
|
|
56
|
+
).toMatchObject({
|
|
57
|
+
ok: false,
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("checks new code folders while leaving data paths outside the code rule", () => {
|
|
62
|
+
expect(
|
|
63
|
+
findInvalidCodeDirectories([
|
|
64
|
+
"packages/core/src/capture-validation.ts",
|
|
65
|
+
"examples/browser-capture/provider.mjs",
|
|
66
|
+
"docs/conventions/templates/frame-label.ts",
|
|
67
|
+
"docs/trials/ImportedEvidence/report.json",
|
|
68
|
+
]),
|
|
69
|
+
).toEqual([]);
|
|
70
|
+
expect(
|
|
71
|
+
findInvalidCodeDirectories([
|
|
72
|
+
"packages/core/src/captureHelpers/geometry.ts",
|
|
73
|
+
"packages/core/src/captureHelpers/fonts.ts",
|
|
74
|
+
"examples/BrowserCapture/provider.mjs",
|
|
75
|
+
]),
|
|
76
|
+
).toEqual([
|
|
77
|
+
"examples/BrowserCapture",
|
|
78
|
+
"packages/core/src/captureHelpers",
|
|
79
|
+
]);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { snippet, type Snippet } from "../../../packages/core/src/snippet.js";
|
|
2
|
+
|
|
3
|
+
export function createFrameInspection(frameName: string): Snippet {
|
|
4
|
+
if (!frameName.trim()) {
|
|
5
|
+
throw new Error("Frame name is required");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return snippet(
|
|
9
|
+
"example-frame-inspection",
|
|
10
|
+
`
|
|
11
|
+
const matchingFrames = penpot.currentPage.children.filter((shape) => {
|
|
12
|
+
return shape.type === "board" && shape.name === CFG.frameName;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
if (matchingFrames.length !== 1) {
|
|
16
|
+
return { ok: false, message: "Expected one uniquely named frame" };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const frame = matchingFrames[0];
|
|
20
|
+
return { ok: true, frameId: frame.id, frameName: frame.name };
|
|
21
|
+
`,
|
|
22
|
+
{
|
|
23
|
+
frameName,
|
|
24
|
+
},
|
|
25
|
+
"read",
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface FrameLabel {
|
|
2
|
+
pageName: string;
|
|
3
|
+
frameName: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function formatFrameLabel(label: FrameLabel): string {
|
|
7
|
+
const pageName = label.pageName.trim();
|
|
8
|
+
const frameName = label.frameName.trim();
|
|
9
|
+
|
|
10
|
+
if (!pageName || !frameName) {
|
|
11
|
+
throw new Error("A frame label requires a page name and a frame name");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return `${pageName} / ${frameName}`;
|
|
15
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# TypeScript and naming
|
|
2
|
+
|
|
3
|
+
Use `pnpm format` and `pnpm check:style`; do not hand-align code against Biome.
|
|
4
|
+
Separate top-level declarations and distinct steps inside a function with blank
|
|
5
|
+
lines. Use braces for every branch and loop, and declare one variable at a time.
|
|
6
|
+
Prefer early exits that leave the main path easy to follow.
|
|
7
|
+
|
|
8
|
+
Biome preserves these blank lines but does not insert them between declarations
|
|
9
|
+
or logical steps. Add them while writing/reviewing code, before running the
|
|
10
|
+
formatter. A passing style check alone does not prove that vertical spacing follows
|
|
11
|
+
this convention. Separate each top-level declaration (including interfaces and
|
|
12
|
+
type aliases), and separate input preparation, guard clauses, work and returns
|
|
13
|
+
inside a function. Keep a documentation comment attached to its declaration.
|
|
14
|
+
|
|
15
|
+
## Names carry intent
|
|
16
|
+
|
|
17
|
+
- Files and folders: `capture-validation.ts`, `page-session/`. Keep conventional
|
|
18
|
+
`index.ts`, `*.test.ts`, `*.config.ts` and tool-required filenames.
|
|
19
|
+
- Values and functions: `captureMetadata`, `baselineImage`, `implementationCase`,
|
|
20
|
+
`validateCaptureMetadata`. Use a verb for an action and a noun for a value.
|
|
21
|
+
- Types: `ImplementationCase`, `BrowserCaptureMetadata`. Prefer interfaces for
|
|
22
|
+
object contracts and unions for finite alternatives.
|
|
23
|
+
- Booleans: `fontsReady`, `hasCurrentApproval`, `isComplete`.
|
|
24
|
+
- Units and encodings: `timeoutMs`, `maxSnippetBytes`, `screenshotHash`,
|
|
25
|
+
`imageWidth`. Make conversions visible where they happen.
|
|
26
|
+
- Avoid one-letter domain names (`c`, `m`, `r`, `b`) and unexplained abbreviations
|
|
27
|
+
(`cfg`, `sub`, `rest`) when the full name makes the next line understandable.
|
|
28
|
+
Familiar small mathematical coordinates (`x`, `y`) remain appropriate.
|
|
29
|
+
- Preserve public field names, CLI flags and external API spelling. Improve a
|
|
30
|
+
local binding without renaming a persisted schema or an upstream property.
|
|
31
|
+
|
|
32
|
+
Use `const` unless reassignment is needed. Export named functions and types;
|
|
33
|
+
adapter definitions retain the default export required by their loader. Give
|
|
34
|
+
exported functions explicit return types. Use `unknown` with validation at input
|
|
35
|
+
boundaries rather than `any` or a cast that pretends an external value was checked.
|
|
36
|
+
|
|
37
|
+
## Functions and errors
|
|
38
|
+
|
|
39
|
+
A function should name one operation at one level of detail. Extract a named
|
|
40
|
+
predicate when a condition combines independently meaningful rules; retain the
|
|
41
|
+
short-circuit checks that protect access to malformed input. Extract filesystem
|
|
42
|
+
work from pure validation when each can be tested independently.
|
|
43
|
+
|
|
44
|
+
Throw errors with actionable domain context. Catch them where a caller can choose
|
|
45
|
+
recovery, report a failed case or return a command exit code. Preserve existing
|
|
46
|
+
error classifications, redaction and cancellation behavior during a refactor.
|
|
47
|
+
Comment on non-obvious reasons; use names to explain routine steps.
|
|
48
|
+
|
|
49
|
+
## Tests
|
|
50
|
+
|
|
51
|
+
Use the package's Vitest runner and its existing `test/` layout. Test observable
|
|
52
|
+
contracts: accepted evidence, rejected malformed/stale evidence, partial progress,
|
|
53
|
+
and filesystem boundaries. Keep fixtures local and deterministic. For a refactor,
|
|
54
|
+
keep a public-entrypoint integration test and add regression cases for the rules
|
|
55
|
+
being extracted. Avoid tests that only search for an implementation's wording.
|
|
56
|
+
|
|
57
|
+
Production TypeScript uses ESM imports with `.js` for local modules. Match the
|
|
58
|
+
existing NodeNext configuration. Documentation templates import actual core types
|
|
59
|
+
so API changes invalidate stale examples during `pnpm check`.
|
package/docs/design-workflow.md
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
4. Present the exact artifact to the owner. [Approval records](approvals.md) retain supplied words and capture hashes; a comparison percentage never supplies approval.
|
|
7
7
|
5. Capture [baselines and case coverage](coverage.md). A changed reference requires matching approval or an explicitly labeled waiver; unsupported cases remain pending.
|
|
8
8
|
6. Generate a [structured handoff](handoff.md) with explicit component mappings. Implement behavior, responsive rules and accessibility from an actual application contract rather than inferred appearance.
|
|
9
|
-
7.
|
|
9
|
+
7. Use the recommended [Reflection Check companion](adapters.md#check-the-frontend-against-the-design) and a real project browser provider to capture the actual implementation case with stable fonts/data. Inspect comparison evidence and images, resolve drift, and report changed behavior, validation and remaining risks. Missing provider/setup work remains pending.
|
|
10
10
|
|
|
11
11
|
[Structural snapshots](snapshots.md) make design review diffable. [Archives and restore trials](backup.md) establish recovery independently. The current branch has offline fixtures and repeatable [human trial instructions](trials.md); it has not completed those real trials.
|
|
12
|
+
|
|
13
|
+
Before expanding variants, choose the primary task and an existing reference, establish hierarchy/context and responsive/focus order, then critique one small first frame. Use `inspect → spec → snapshot/diff → capture/approve → comparison` from installed `penpair --help`. Exact owner words approve only the captured artifact; first-frame critique does not grant approval. Layout strategy and fresh doctor evidence are described in [build kit](build-kit.md) and [recovery](recovery.md).
|