@penpair/core 0.1.0 → 0.1.2
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 +9 -212
- package/dist/adapters.d.ts +49 -0
- package/dist/adapters.js +71 -0
- package/dist/cli-main.d.ts +10 -0
- package/dist/cli-main.js +507 -0
- package/dist/cli.js +2 -455
- package/dist/docker-profile.d.ts +114 -0
- package/dist/docker-profile.js +18 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.js +9 -1
- package/dist/instance/config.d.ts +3 -0
- package/dist/instance/config.js +4 -0
- package/dist/instance/init.d.ts +9 -6
- package/dist/instance/init.js +18 -58
- package/dist/instance/setup.d.ts +3 -0
- package/dist/instance/setup.js +9 -10
- package/dist/local-profile.d.ts +95 -0
- package/dist/local-profile.js +8 -0
- package/dist/skills.d.ts +8 -0
- package/dist/skills.js +16 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.js +2 -0
- package/package.json +4 -9
- package/skills/design-judgment/SKILL.md +1 -1
- package/skills/{penpot-design → penpair-design}/SKILL.md +2 -2
- package/skills/{penpot-design → penpair-design}/references/penpot-plugin-gotchas.md +2 -0
- package/skills/penpair-setup/SKILL.md +12 -12
- package/skills/penpair-setup/references/web-or-docker.md +2 -2
- package/docs/compatibility.md +0 -29
- package/docs/getting-started.md +0 -97
- package/docs/guide.md +0 -93
- package/docs/releasing.md +0 -45
- /package/skills/{penpot-design → penpair-design}/references/auto-layout.md +0 -0
- /package/skills/{penpot-design → penpair-design}/references/library-in-penpot.md +0 -0
- /package/skills/{penpot-design → penpair-design}/references/project-facts.md +0 -0
- /package/skills/{penpot-design → penpair-design}/references/write-protocol.md +0 -0
package/docs/getting-started.md
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
# Getting started
|
|
2
|
-
|
|
3
|
-
Draft. Written for someone who has not used a terminal much. The steps marked **(not tried yet)** come from Penpot's help pages, not from a run; the first person to follow this guide on a clean machine should mark what differs.
|
|
4
|
-
|
|
5
|
-
The normal way is to use Penpot on the web (or your team's own Penpot) and connect the AI assistant to it. Nothing runs on your computer except penpair. If you want your own copy of Penpot on your computer instead, see "Alternative: run Penpot on your own computer" at the end.
|
|
6
|
-
|
|
7
|
-
There are two roles. You may be both.
|
|
8
|
-
|
|
9
|
-
- **The designer** works in Penpot in the browser (go to "If you are the designer").
|
|
10
|
-
- **The person who sets it up** connects the AI assistant to that Penpot (go to "If you set it up").
|
|
11
|
-
|
|
12
|
-
## If you are the designer
|
|
13
|
-
You need a link to your team's Penpot and an account.
|
|
14
|
-
|
|
15
|
-
1. Open the link and log in.
|
|
16
|
-
2. Open the design file you will work on.
|
|
17
|
-
3. Choose **File, MCP Server, Connect** (not tried yet). A small window may appear; leave it open.
|
|
18
|
-
4. Keep this browser tab **visible** while the assistant works. If the browser puts the tab to sleep, the assistant stops and says the tab is suspended. Bring the tab to the front and it carries on.
|
|
19
|
-
5. Tell the assistant which page to work on. It works on the page you have open.
|
|
20
|
-
|
|
21
|
-
That is all. The assistant looks first, changes things in one go, and checks its own work; you review the result in Penpot as usual.
|
|
22
|
-
|
|
23
|
-
## If you set it up
|
|
24
|
-
You need: a Mac or Linux computer, **Node.js** (the current LTS version), a terminal, and an account on a Penpot (the hosted one at design.penpot.app is free to start; use your team's address if it runs its own).
|
|
25
|
-
|
|
26
|
-
**The quick way:** in your project's folder run `npx penpair setup`. It asks where your Penpot is (press Enter for the web), does steps 1 to 5 below, and says in plain words what it is waiting for. Run it again if you stop halfway. The rest of this section is what it does, one step at a time, for when you want to do it by hand or something needs fixing.
|
|
27
|
-
|
|
28
|
-
### 1. Connect your project to that Penpot
|
|
29
|
-
In the folder of your project:
|
|
30
|
-
|
|
31
|
-
```
|
|
32
|
-
npx penpair init --external https://design.penpot.app --gitignore
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
`init` writes a small settings file (`penpair.config.json`, commit it) and keeps your private files out of git for you.
|
|
36
|
-
|
|
37
|
-
### 2. Make your account and a file (once)
|
|
38
|
-
Open the Penpot address, create an account and log in. Create a project and a design file for this work.
|
|
39
|
-
|
|
40
|
-
### 3. Connect the assistant (once)
|
|
41
|
-
1. In Penpot open **Account, Integrations, MCP Server** and switch it on (not tried yet). Copy the address it shows; it contains your personal key, so treat it like a password. The key belongs to you, not to the team; each person who uses the assistant makes their own.
|
|
42
|
-
2. In your project folder run `npx penpair connect` and paste the address when asked. Nothing is shown as you paste. It saves the address in `.env.local` (readable only by you, and added to `.gitignore`) and refuses an address that belongs to a different Penpot. (By hand instead: put the line `PENPAIR_MCP_URL=<the address>` in `.env.local` and keep that file out of git.)
|
|
43
|
-
3. Open your design file in Penpot, choose **File, MCP Server, Connect**, and keep that tab visible.
|
|
44
|
-
|
|
45
|
-
### 4. Check that it works
|
|
46
|
-
```
|
|
47
|
-
npx penpair doctor
|
|
48
|
-
```
|
|
49
|
-
Every line should say `ok`. If one says `FAIL`, the line under it says what to do. The usual ones:
|
|
50
|
-
|
|
51
|
-
| It says | What to do |
|
|
52
|
-
| --- | --- |
|
|
53
|
-
| penpot: not answering | Check the address in the config and your internet connection |
|
|
54
|
-
| editor and plugin: the MCP address points at another instance | The address in `.env.local` belongs to a different Penpot. Copy the one from this Penpot |
|
|
55
|
-
| editor and plugin: not connected | Do step 3.3 again and keep the tab visible |
|
|
56
|
-
|
|
57
|
-
Then try: `npx penpair pages` lists the pages in the open file.
|
|
58
|
-
|
|
59
|
-
If you want to know what your Penpot offers before you start, `npx penpair probe` lists its tools and limits. If `execute_code` is missing from that list, penpair cannot work with it. The hosted service, checked 2026-10-20 on Penpot 2.18.4, offers the same four tools and the same limits as a local Penpot (see `compatibility.md`).
|
|
60
|
-
|
|
61
|
-
### 5. Give the assistant its rules (once)
|
|
62
|
-
```
|
|
63
|
-
npx penpair skills install
|
|
64
|
-
```
|
|
65
|
-
This copies the rules the assistant follows (how to work safely in Penpot, and how to judge a screen) into `.skills/` and makes them visible to Codex and Claude Code. It prints a line for each to add to your `AGENTS.md`. Then fill in `.skills/penpot-design/references/project-facts.md` (your file, never replaced): the Penpot file, the token sets, the names you use, who approves.
|
|
66
|
-
|
|
67
|
-
### Every day
|
|
68
|
-
Open the file in Penpot, choose **File, MCP Server, Connect**, keep the tab visible, and start working with the assistant.
|
|
69
|
-
|
|
70
|
-
### Your safety net
|
|
71
|
-
`up`, `down`, `status`, `backup` and `restore` belong to the Docker alternative and do not apply here. Your safety net is Penpot's own version history and the `.penpot` export in the File menu. Whether a `.penpot` export restores everything (components, token sets, themes) is not proven yet; see the [plan](https://github.com/niklas-westman/penpair/blob/main/PLAN.md).
|
|
72
|
-
|
|
73
|
-
## What it will not do
|
|
74
|
-
It needs the Penpot tab open and visible while the assistant works, so it cannot run on its own overnight. It changes one Penpot at a time and only the page you have open.
|
|
75
|
-
|
|
76
|
-
## Alternative: run Penpot on your own computer
|
|
77
|
-
Choose this when you want to work offline, keep the data on your machine, or have one Penpot per project that you can throw away. It needs **Docker Desktop** running in addition to Node.js. The first start downloads about 2 GB.
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
npx penpair init --gitignore
|
|
81
|
-
npx penpair up
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
`init` also writes a hidden folder `.penpair/` with the Penpot settings and secret keys. When `up` says "Penpot is up at http://127.0.0.1:9001" (your port may differ; use `--port 9002` with `init` if one is taken), open that address and create an account (no email confirmation is needed). Then do steps 3 to 5 above in that Penpot. `npx penpair doctor` also checks Docker, the secrets file and the containers:
|
|
85
|
-
|
|
86
|
-
| It says | What to do |
|
|
87
|
-
| --- | --- |
|
|
88
|
-
| docker: not answering | Start Docker Desktop and wait until it says it is running |
|
|
89
|
-
| containers: not running | Run `npx penpair up` |
|
|
90
|
-
| backend: not ready yet | Wait ten seconds and run `doctor` again |
|
|
91
|
-
|
|
92
|
-
Every day: `npx penpair up` (if Docker was restarted) and `npx penpair down` to stop; your designs stay. Back up before big changes with `npx penpair backup`, and prove a backup works with `npx penpair backup verify <the folder it printed>`. The backup contains account data, so never put it in git.
|
|
93
|
-
|
|
94
|
-
## Still to make easier (see the [plan](https://github.com/niklas-westman/penpair/blob/main/PLAN.md))
|
|
95
|
-
- One guided command (`penpair setup`) that does the steps above, waits for each browser step and says what it sees. It will ask "Penpot on the web, or on this computer?" and default to the web.
|
|
96
|
-
- A short illustrated version with a screenshot of each browser step.
|
|
97
|
-
- A shared Penpot for a team, so designers need no setup.
|
package/docs/guide.md
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
# Guide (skeleton)
|
|
2
|
-
|
|
3
|
-
The contract an adopting project works through. It grows with the code; each section ends in a checklist like Reflection's provider guide.
|
|
4
|
-
|
|
5
|
-
## Extension points
|
|
6
|
-
| Point | A project supplies | First implementations |
|
|
7
|
-
| --- | --- | --- |
|
|
8
|
-
| Connection profile | endpoint, Penpot version, where the token comes from | local Docker, shared self-hosted, hosted |
|
|
9
|
-
| Library adapter | where tokens and components come from | Marwes |
|
|
10
|
-
| Snippet registry | named plugin snippets with inputs and a size check | tree, audit, tokens, archive |
|
|
11
|
-
| Verification provider | what "matches the design" means | `penpair baselines` (images and Reflection cases, below), a page-verify gate |
|
|
12
|
-
| Skill pack | rules the agent follows | the Penpot skill, design judgment |
|
|
13
|
-
|
|
14
|
-
## Sections to write
|
|
15
|
-
- Starting from an empty machine
|
|
16
|
-
- Instances (written, below): one per project, ports, volumes, secrets, backup and restore
|
|
17
|
-
- The write protocol
|
|
18
|
-
- Writing a snippet
|
|
19
|
-
- Writing a library adapter
|
|
20
|
-
- What breaks when Penpot is upgraded
|
|
21
|
-
|
|
22
|
-
## Instances
|
|
23
|
-
One Penpot per project, configured in `penpair.config.json` (no secrets, commit it):
|
|
24
|
-
|
|
25
|
-
```json
|
|
26
|
-
{ "instance": "my-app", "penpotVersion": "2.18.3", "ports": { "frontend": 9002, "mail": 1081 }, "directory": ".penpair" }
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
| Command | What it does |
|
|
30
|
-
| --- | --- |
|
|
31
|
-
| `penpair setup [--web \| --docker]` | The guided path: where is Penpot, config, start it if it is Docker, take the key (hidden), wait for the editor, read the file, install the skills |
|
|
32
|
-
| `penpair connect [--replace]` | Only the key and the wait for the editor; accepts a pipe (`pbpaste \| penpair connect`) |
|
|
33
|
-
| `penpair init [--instance <name>] [--port 9002] [--gitignore]` | Writes the config if missing, the compose file, and a secrets file (owner-only) that is never replaced |
|
|
34
|
-
| `penpair up` / `down` / `status` | Start (waits until the backend answers), stop (the data volumes stay), look |
|
|
35
|
-
| `penpair doctor [--json]` | Docker, secrets, containers, frontend, backend, then the editor and plugin through the MCP, and that `.env.local` is kept out of git (a web project checks only the address, the editor and the key file) |
|
|
36
|
-
| `penpair backup` | A Postgres dump and a tarball of the assets, with checksums and counts, in `.penpair/backups/` |
|
|
37
|
-
| `penpair backup verify <dir>` | Restores the dump into a throwaway database and compares counts, revisions and asset files |
|
|
38
|
-
| `penpair restore <dir> --yes` | Replaces the instance's data; a safety backup of the current data comes first; the counts are compared afterwards |
|
|
39
|
-
|
|
40
|
-
Things to know:
|
|
41
|
-
- Two instances never collide: the compose project is `penpair-<instance>`, so containers and volumes have their own names. `composeProject` in the config adopts an instance that was started earlier under another name.
|
|
42
|
-
- Keep `.penpair/` out of git. Backups hold account data (password hashes).
|
|
43
|
-
- The database password must not change while the database volume exists; the secrets file is never regenerated.
|
|
44
|
-
- The frontend answers a few seconds before the backend; `up` and `doctor` look at `/readyz`.
|
|
45
|
-
- `doctor` compares the MCP key's port with the instance's, because a key for another instance silently drives the wrong file.
|
|
46
|
-
- Penpot's accounts come from the first registration in the browser; the MCP key is made in Account, Integrations, MCP Server and goes in `.env.local` as `PENPAIR_MCP_URL`.
|
|
47
|
-
|
|
48
|
-
## Baselines for a check
|
|
49
|
-
|
|
50
|
-
`penpair baselines` hands a page's design to a check that compares the implementation against images. It reads the `baselines` block of `penpair.config.json`:
|
|
51
|
-
|
|
52
|
-
```json
|
|
53
|
-
"baselines": {
|
|
54
|
-
"page": "Candidate",
|
|
55
|
-
"root": "tests/baselines",
|
|
56
|
-
"threshold": 0.05,
|
|
57
|
-
"frames": [
|
|
58
|
-
{ "frame": "F / candidates", "id": "candidates-desktop", "route": "candidates" },
|
|
59
|
-
{ "frame": "F / my work", "id": "my-work" }
|
|
60
|
-
]
|
|
61
|
-
}
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
- `frame` is the exact name of a top-level frame on the page; two frames with the same name is an error, so the reference is never ambiguous.
|
|
65
|
-
- `id` names the image (`<id>.png`) and the check. `route` is the route in your app this frame is the design of; a frame without a route is exported but gets no check.
|
|
66
|
-
- Without `--apply` the command only looks and reports each frame as `new`, `same`, `changed`, `unstable` (the export never settled) or `missing`. `--apply` writes new images, `penpair-baselines.json` (file, revision, sizes, hashes) and `reflection-cases.json`. A `changed` image is replaced only with `--apply --update`: that is the act of approving the new design, and the owner's call. The exit code is 2 when a design differs from its image, 1 when a frame is missing or unstable.
|
|
67
|
-
|
|
68
|
-
The generated `reflection-cases.json` holds, per route, the viewports (the image's exact size) and the `visualSmoke` cases (review-only, `strict: false`). A Reflection config uses it like this; only the route's own expectations are written by hand:
|
|
69
|
-
|
|
70
|
-
```ts
|
|
71
|
-
import { defineReflection } from 'reflection-check';
|
|
72
|
-
import cases from './tests/baselines/reflection-cases.json' with { type: 'json' };
|
|
73
|
-
|
|
74
|
-
export default defineReflection({
|
|
75
|
-
project: 'my-app',
|
|
76
|
-
run: { defaultMode: 'smoke', ciMode: 'smoke' },
|
|
77
|
-
contracts: {
|
|
78
|
-
browser: {
|
|
79
|
-
enabled: true,
|
|
80
|
-
blocking: true,
|
|
81
|
-
baseUrl: 'http://127.0.0.1:5173',
|
|
82
|
-
routes: [
|
|
83
|
-
{ id: 'candidates', name: 'Candidates', path: '/candidates', viewports: cases.routes.candidates.viewports, expects: [{ screenshot: 'final' }] },
|
|
84
|
-
],
|
|
85
|
-
visualSmoke: cases.visualSmoke as never,
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
`baselineRoot` in the generated cases is relative to the Reflection config's folder, so keep the two in the same project root. The same images work with any other image comparison; the Reflection cases are one output of the manifest.
|
|
92
|
-
|
|
93
|
-
The percentage a comparison reports is not a verdict: a correct implementation differs from a Penpot render by about 1 to 2% on text alone, so read the diff image.
|
package/docs/releasing.md
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# Releasing
|
|
2
|
-
|
|
3
|
-
Two packages are published from this repository, always with the same version: `@penpair/core` (the library, the command, the skills; `packages/core`) and `penpair` (the short name for the command; `packages/penpair`). The root of the repository is a private workspace and is never published.
|
|
4
|
-
|
|
5
|
-
Publishing cannot be undone: a version, once published, cannot be replaced. Check first, publish once.
|
|
6
|
-
|
|
7
|
-
## One time
|
|
8
|
-
|
|
9
|
-
1. An npm organisation named `penpair` must exist (npmjs.com, Add organization, free for public packages). `@penpair/core` cannot be published without it.
|
|
10
|
-
2. `npm whoami` must print your user name. If it answers `401`, run `npm login`.
|
|
11
|
-
3. If npm asks for a one-time code, add `--otp=<code>` to each publish.
|
|
12
|
-
|
|
13
|
-
## Before publishing
|
|
14
|
-
|
|
15
|
-
1. Be on `main` with everything committed and pushed, and the version raised in both `packages/core/package.json` and `packages/penpair/package.json` (and `version` in `packages/core/src/index.ts`; a test fails if they differ). A change that existing users could not ignore is major, an additive change is minor, a fix is a patch. Add a section to `CHANGELOG.md`.
|
|
16
|
-
2. Run every check:
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
pnpm check # typecheck, tests, build
|
|
20
|
-
pnpm smoke:package # packs both packages, installs them in an empty project, runs the command and the library
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
3. Check what would be published: `npm pack --dry-run --ignore-scripts` in each package. The core ships `dist`, `skills`, `docs`, `LICENSE` and `README.md`; the wrapper ships `bin`, `LICENSE` and `README.md`. Nothing else. (`prepack` copies the root README and `docs/` into the core for the tarball; the copies are git-ignored.)
|
|
24
|
-
|
|
25
|
-
## Publish
|
|
26
|
-
|
|
27
|
-
The core first, because the wrapper depends on it at this exact version. Use `pnpm publish` so `workspace:*` is replaced by the real version.
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
cd packages/core && pnpm publish --access public
|
|
31
|
-
cd ../penpair && pnpm publish --access public
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Verify
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
npm view @penpair/core version
|
|
38
|
-
npm view penpair version
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Then, in an empty folder, run `npx penpair --version` and `npx penpair setup --help`, so what was tested is what people get. Tag the release (`git tag v<version>`) and push the tag only if you want one.
|
|
42
|
-
|
|
43
|
-
## After publishing
|
|
44
|
-
|
|
45
|
-
Update the version in `PLAN.md` and add the change log line. A problem found in a published version is answered with a new patch or minor version, never by changing a published one.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|