pmx-canvas 0.1.22 → 0.1.24
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/.github/extensions/pmx-canvas/extension.mjs +591 -0
- package/CHANGELOG.md +140 -0
- package/Readme.md +40 -8
- package/dist/canvas/global.css +36 -3
- package/dist/canvas/index.js +54 -54
- package/dist/types/client/nodes/ExtAppFrame.d.ts +1 -0
- package/dist/types/client/nodes/iframe-document-url.d.ts +8 -0
- package/dist/types/client/state/intent-bridge.d.ts +4 -0
- package/dist/types/client/types.d.ts +1 -0
- package/dist/types/json-render/catalog.d.ts +1 -1
- package/dist/types/mcp/canvas-access.d.ts +9 -0
- package/dist/types/server/ax-context.d.ts +3 -0
- package/dist/types/server/ax-state.d.ts +43 -0
- package/dist/types/server/canvas-db.d.ts +38 -0
- package/dist/types/server/canvas-state.d.ts +36 -16
- package/dist/types/server/index.d.ts +6 -0
- package/dist/types/server/mutation-history.d.ts +1 -1
- package/docs/cli.md +13 -0
- package/docs/http-api.md +24 -0
- package/docs/mcp.md +20 -2
- package/docs/plans/plan-004-pmx-ax-primitives.md +463 -0
- package/docs/screenshot.png +0 -0
- package/docs/sdk.md +5 -0
- package/package.json +3 -2
- package/skills/pmx-canvas/SKILL.md +22 -4
- package/skills/pmx-canvas/references/codex-app-adapter.md +107 -0
- package/skills/pmx-canvas/references/github-copilot-app-adapter.md +111 -0
- package/src/cli/agent.ts +34 -0
- package/src/cli/index.ts +2 -1
- package/src/client/App.tsx +2 -0
- package/src/client/canvas/CanvasNode.tsx +7 -0
- package/src/client/canvas/CommandPalette.tsx +2 -1
- package/src/client/canvas/use-node-drag.ts +29 -7
- package/src/client/canvas/use-node-resize.ts +27 -7
- package/src/client/nodes/ExtAppFrame.tsx +51 -10
- package/src/client/nodes/HtmlNode.tsx +5 -2
- package/src/client/nodes/iframe-document-url.ts +58 -0
- package/src/client/state/intent-bridge.ts +8 -0
- package/src/client/state/sse-bridge.ts +2 -2
- package/src/client/theme/global.css +36 -3
- package/src/client/types.ts +1 -0
- package/src/mcp/canvas-access.ts +38 -0
- package/src/mcp/server.ts +113 -4
- package/src/server/ax-context.ts +38 -0
- package/src/server/ax-state.ts +130 -0
- package/src/server/canvas-db.ts +745 -0
- package/src/server/canvas-operations.ts +80 -1
- package/src/server/canvas-schema.ts +3 -3
- package/src/server/canvas-state.ts +390 -50
- package/src/server/canvas-validation.ts +6 -0
- package/src/server/index.ts +18 -0
- package/src/server/mutation-history.ts +1 -0
- package/src/server/server.ts +197 -11
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,144 @@
|
|
|
3
3
|
All notable changes to `pmx-canvas` are documented here. This project follows
|
|
4
4
|
[Semantic Versioning](https://semver.org/).
|
|
5
5
|
|
|
6
|
+
## [0.1.24] - 2026-06-03
|
|
7
|
+
|
|
8
|
+
Host-adapter and agent-experience (AX) release. Adds host-agnostic AX
|
|
9
|
+
focus/context primitives across every layer, ships GitHub Copilot and
|
|
10
|
+
Codex canvas adapters, moves embedded HTML/MCP-app iframes onto a
|
|
11
|
+
same-origin frame-document transport (still strictly sandboxed via a
|
|
12
|
+
CSP `sandbox` response header), and fixes a batch of iframe-backed
|
|
13
|
+
node drag/resize/fullscreen interaction glitches.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **PMX AX focus + context primitives.** A new host-agnostic
|
|
18
|
+
"agent experience" focus field lets any surface mark which nodes
|
|
19
|
+
an agent is attending to without moving the viewport. Implemented
|
|
20
|
+
end to end with full parity:
|
|
21
|
+
- State: `CanvasStateManager.getAxFocus()` / `setAxFocus()` /
|
|
22
|
+
`getAxState()`, recorded as a `setAxFocus` mutation-history op
|
|
23
|
+
(undo/redo) and persisted in a new SQLite `ax_state` table.
|
|
24
|
+
- SDK: `PmxCanvas.getAxState()`, `getAxContext()`, `setAxFocus()`.
|
|
25
|
+
- HTTP: `GET`/`PATCH /api/canvas/ax`, `GET /api/canvas/ax/context`,
|
|
26
|
+
`POST /api/canvas/ax/focus`.
|
|
27
|
+
- MCP: `canvas_get_ax`, `canvas_set_ax_focus` (45 tools total),
|
|
28
|
+
plus `canvas://ax` and `canvas://ax-context` resources that emit
|
|
29
|
+
`notifications/resources/updated` on change.
|
|
30
|
+
- CLI: `pmx-canvas ax focus <node-id...>` / `--clear`.
|
|
31
|
+
Focus state carries a `source` tag (`agent`/`api`/`browser`/`cli`/
|
|
32
|
+
`codex`/`copilot`/`mcp`/`sdk`/`system`) and node IDs are validated
|
|
33
|
+
against the live layout.
|
|
34
|
+
- **GitHub Copilot canvas adapter.** A new
|
|
35
|
+
`.github/extensions/pmx-canvas/extension.mjs` (591 lines) plus
|
|
36
|
+
`skills/pmx-canvas/references/github-copilot-app-adapter.md`
|
|
37
|
+
document and implement driving the canvas from GitHub Copilot.
|
|
38
|
+
- **Codex canvas adapter coverage.**
|
|
39
|
+
`skills/pmx-canvas/references/codex-app-adapter.md` documents the
|
|
40
|
+
Codex host integration, with browser regression coverage.
|
|
41
|
+
- **Same-origin frame-document transport for embedded apps.**
|
|
42
|
+
Embedded HTML and MCP-app iframes now load their document from
|
|
43
|
+
`POST /api/canvas/frame-documents` → `GET /api/canvas/frame-
|
|
44
|
+
documents/<id>` instead of an inline `srcdoc`. The served document
|
|
45
|
+
carries `Content-Security-Policy: sandbox <tokens>`,
|
|
46
|
+
`Referrer-Policy: no-referrer`, and `X-Content-Type-Options:
|
|
47
|
+
nosniff`. The sandbox-token allowlist deliberately excludes
|
|
48
|
+
`allow-same-origin` and top-navigation tokens, so frame content
|
|
49
|
+
stays in an opaque origin and cannot reach the canvas host. The
|
|
50
|
+
document store is in-memory, capped at 128 entries (LRU eviction)
|
|
51
|
+
and 5 MB per document.
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
|
|
55
|
+
- **Iframe-backed node drag is flicker-free.** Node drag now
|
|
56
|
+
rAF-throttles pointer moves, clears the browser text selection,
|
|
57
|
+
and toggles an `is-node-dragging` document class to suppress
|
|
58
|
+
selection and attention-field repaint artifacts. Inline app
|
|
59
|
+
iframes are kept pointer-inert near the resize handle so resize
|
|
60
|
+
starts reliably.
|
|
61
|
+
- **Docs tool/resource references updated.** `docs/mcp.md` and the
|
|
62
|
+
README now read 45 tools + 9 core resources; the `AGENTS.md` and
|
|
63
|
+
`CLAUDE.md` MCP tool enumerations were corrected to the full
|
|
64
|
+
45-tool list (they had drifted to 42 and 39 respectively and were
|
|
65
|
+
missing `canvas_fit_view` and the new AX tools).
|
|
66
|
+
|
|
67
|
+
### Internal
|
|
68
|
+
|
|
69
|
+
- Regression coverage for: AX focus set/clear/persistence through
|
|
70
|
+
state, HTTP, MCP, SDK, and CLI; AX focus round-tripping through
|
|
71
|
+
SQLite; arrange-lock interactions; iframe-backed node
|
|
72
|
+
drag/resize/fullscreen behavior (large browser e2e additions); and
|
|
73
|
+
the Copilot/Codex adapter surfaces.
|
|
74
|
+
|
|
75
|
+
## [0.1.23] - 2026-05-12
|
|
76
|
+
|
|
77
|
+
Persistence overhaul. Canvas state, snapshots, context pins, and the
|
|
78
|
+
large-payload blob store all move from filesystem JSON files into a
|
|
79
|
+
single SQLite database at `.pmx-canvas/canvas.db` (WAL mode). The
|
|
80
|
+
old `state.json`, `snapshots/`, and per-blob files are auto-imported
|
|
81
|
+
on first boot and renamed to `.bak`. Adds dock-aware validation and
|
|
82
|
+
arrange behavior, accepts the documented `?type=` query string on
|
|
83
|
+
node creation, and grows the schema-metadata kebab-case aliases to
|
|
84
|
+
include both singular and plural variants.
|
|
85
|
+
|
|
86
|
+
### Added
|
|
87
|
+
|
|
88
|
+
- **SQLite persistence (`src/server/canvas-db.ts`, 710 lines).**
|
|
89
|
+
Canvas state, snapshots, context pins, and the blob sidecar
|
|
90
|
+
store now live in `.pmx-canvas/canvas.db` (Bun SQLite in WAL
|
|
91
|
+
mode). Shape preserved across the migration: nodes, edges,
|
|
92
|
+
annotations, viewport, context pins, history, snapshots, and
|
|
93
|
+
blob payloads with checksum validation.
|
|
94
|
+
- Override DB path: `PMX_CANVAS_DB_PATH` env var.
|
|
95
|
+
- Backward-compatible legacy path: `PMX_CANVAS_STATE_FILE` (if
|
|
96
|
+
you set a `.db` path there, it's used as the DB; if not, it's
|
|
97
|
+
treated as a legacy JSON path for migration).
|
|
98
|
+
- `stopCanvasServer()` now calls `canvasState.close()` which
|
|
99
|
+
checkpoints WAL data into the DB file — stop the server (or
|
|
100
|
+
flush/close the SDK) before committing `canvas.db`.
|
|
101
|
+
- SQLite WAL/SHM files (`*.db-wal`, `*.db-shm`) are gitignored;
|
|
102
|
+
`canvas.db` itself is git-committable.
|
|
103
|
+
- **Legacy migration on first boot.** Existing
|
|
104
|
+
`.pmx-canvas/state.json`, root `.pmx-canvas.json`,
|
|
105
|
+
`.pmx-canvas/snapshots/`, `.pmx-canvas-snapshots/`, and blob
|
|
106
|
+
files are imported into the SQLite database and renamed to
|
|
107
|
+
`.bak` on first start. The migration is idempotent and only
|
|
108
|
+
runs when the DB is empty.
|
|
109
|
+
- **HTTP node create accepts `?type=` query string.** `POST
|
|
110
|
+
/api/canvas/node?type=html-primitive` with the body's `data`
|
|
111
|
+
fields is accepted as an alternative to passing `type` in the
|
|
112
|
+
body — handy for `curl` and shell-based agents. The body form
|
|
113
|
+
still wins when both are present.
|
|
114
|
+
|
|
115
|
+
### Changed
|
|
116
|
+
|
|
117
|
+
- **Docked nodes are excluded from layout collision validation.**
|
|
118
|
+
`validateCanvasLayout` no longer flags `dockPosition !== null`
|
|
119
|
+
nodes as overlap or containment violations. Docked HUD-style
|
|
120
|
+
nodes intentionally sit on top of canvas content; the validator
|
|
121
|
+
now models that.
|
|
122
|
+
- **Docked nodes are treated as arrange-locked.** `arrange()`
|
|
123
|
+
now skips translating nodes with `dockPosition !== null` along
|
|
124
|
+
with pinned and explicitly arrange-locked nodes. Dock geometry
|
|
125
|
+
is anchored to the HUD layer, not the world grid.
|
|
126
|
+
- **Schema kebab-case aliases include plural forms.** `--embedded-
|
|
127
|
+
node-ids`, `--embedded-urls`, and `--slide-titles` are now
|
|
128
|
+
documented aliases for the array-shaped HTML sidecar fields,
|
|
129
|
+
alongside the existing singular `--embedded-node-id`,
|
|
130
|
+
`--embedded-url`, and `--slide-title`.
|
|
131
|
+
- **Bun engine bumped to `>=1.3.14`.** `package.json#engines.bun`
|
|
132
|
+
raised from `>=1.3.12` to `>=1.3.14` to pick up the
|
|
133
|
+
`bun:sqlite` improvements the new persistence layer depends on.
|
|
134
|
+
|
|
135
|
+
### Internal
|
|
136
|
+
|
|
137
|
+
- Regression coverage for: `validateCanvasLayout` ignoring docked
|
|
138
|
+
nodes as collision candidates, html primitive node creation
|
|
139
|
+
accepting the documented query-string `?type=` form, and the
|
|
140
|
+
existing canvas-state and operations suites continuing to pass
|
|
141
|
+
against the SQLite-backed persistence (including snapshot
|
|
142
|
+
save/restore, blob round-trip, and undo/redo history).
|
|
143
|
+
|
|
6
144
|
## [0.1.22] - 2026-05-12
|
|
7
145
|
|
|
8
146
|
CLI ergonomics and response-size polish on top of 0.1.21. Adds a
|
|
@@ -1045,6 +1183,8 @@ otherwise have to discover by trial and error.
|
|
|
1045
1183
|
- Regression coverage for snapshot flat-`id` aliases on both MCP and
|
|
1046
1184
|
HTTP surfaces, plus async / top-level-`await` WebView script bodies.
|
|
1047
1185
|
|
|
1186
|
+
[0.1.24]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.24
|
|
1187
|
+
[0.1.23]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.23
|
|
1048
1188
|
[0.1.22]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.22
|
|
1049
1189
|
[0.1.21]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.21
|
|
1050
1190
|
[0.1.20]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.20
|
package/Readme.md
CHANGED
|
@@ -55,22 +55,40 @@ prompt engineering, no copy-paste — pin a node in the browser and the MCP
|
|
|
55
55
|
server fires a `notifications/resources/updated` event the agent's harness
|
|
56
56
|
picks up immediately.
|
|
57
57
|
|
|
58
|
+
AX context adds a host-agnostic focus layer on top of pins. Core PMX exposes
|
|
59
|
+
`/api/canvas/ax/context`, `canvas://ax-context`, SDK methods, and
|
|
60
|
+
`pmx-canvas ax context|focus`; adapters can map that same primitive to their
|
|
61
|
+
native hook systems without making PMX Canvas GitHub-specific.
|
|
62
|
+
|
|
58
63
|
### 05 / Save
|
|
59
64
|
|
|
60
|
-
Spatial state auto-saves to `.pmx-canvas/
|
|
65
|
+
Spatial state auto-saves to `.pmx-canvas/canvas.db` (debounced ~500 ms) —
|
|
61
66
|
git-committable, shareable across machines, and survives both browser
|
|
62
67
|
refresh and server restart. Named [snapshots](docs/mcp.md#tools), full
|
|
63
68
|
undo/redo, and an auto-detected code graph (JS/TS, Python, Go, Rust) make
|
|
64
|
-
the canvas durable rather than throwaway.
|
|
69
|
+
the canvas durable rather than throwaway. Stop the server before committing
|
|
70
|
+
the DB so SQLite WAL data is checkpointed into the file.
|
|
65
71
|
|
|
66
72
|
### 06 / Any agent
|
|
67
73
|
|
|
68
|
-
Harness-agnostic. Drive the canvas from [MCP](docs/mcp.md) (
|
|
69
|
-
|
|
74
|
+
Harness-agnostic. Drive the canvas from [MCP](docs/mcp.md) (45 tools,
|
|
75
|
+
9 resources, change notifications), the [CLI](docs/cli.md), the
|
|
70
76
|
[HTTP API](docs/http-api.md), or the [Bun SDK](docs/sdk.md). Works with
|
|
71
77
|
Claude Code, GitHub Copilot CLI, Codex, Cursor, Windsurf, or any agent
|
|
72
78
|
that can spawn an MCP stdio server, call a CLI, or hit an HTTP endpoint.
|
|
73
79
|
|
|
80
|
+
The repo also ships a GitHub Copilot app adapter at
|
|
81
|
+
`.github/extensions/pmx-canvas/`. It opens the live PMX workbench in a native
|
|
82
|
+
Copilot canvas panel, injects AX pinned/focused context on prompt submission,
|
|
83
|
+
and exposes adapter actions for status, AX focus, context refresh, and explicit
|
|
84
|
+
session steering.
|
|
85
|
+
|
|
86
|
+
In the Codex app, PMX Canvas is MCP-first plus the Codex in-app Browser: agents
|
|
87
|
+
read `canvas://ax-context` / `canvas_get_ax`, humans use the live `/workbench`
|
|
88
|
+
view, and Codex-originated focus can be labeled with `source: "codex"` through
|
|
89
|
+
`canvas_set_ax_focus`. The CLI remains a fallback for scripts and manual
|
|
90
|
+
debugging, not the native Codex adapter path.
|
|
91
|
+
|
|
74
92
|
## Prerequisites
|
|
75
93
|
|
|
76
94
|
- [Bun](https://bun.sh) >= 1.3.12
|
|
@@ -125,6 +143,20 @@ Add to your agent's MCP config:
|
|
|
125
143
|
|
|
126
144
|
The canvas auto-starts on first tool call.
|
|
127
145
|
|
|
146
|
+
### Use inside the GitHub Copilot app
|
|
147
|
+
|
|
148
|
+
This repository includes a project canvas extension:
|
|
149
|
+
|
|
150
|
+
```text
|
|
151
|
+
.github/extensions/pmx-canvas/extension.mjs
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
When loaded by the Copilot app, it opens the PMX workbench natively, starts a
|
|
155
|
+
matching local PMX server when needed, and injects `AX` pinned/focused context
|
|
156
|
+
as hidden per-turn context. The adapter is thin: PMX state still lives in
|
|
157
|
+
`.pmx-canvas/canvas.db`, and the same HTTP, MCP, CLI, and SDK surfaces remain
|
|
158
|
+
available to non-GitHub agents.
|
|
159
|
+
|
|
128
160
|
### Install the agent skill (recommended)
|
|
129
161
|
|
|
130
162
|
The fastest way to get a working canvas is to install the `pmx-canvas` agent
|
|
@@ -147,8 +179,8 @@ Common harness skill directories: `.claude/skills/` (Claude Code),
|
|
|
147
179
|
`.github/skills/` or `.copilot/skills/` (Copilot CLI),
|
|
148
180
|
`.agents/skills/` (cross-harness convention). Once the canvas is running,
|
|
149
181
|
the agent can read `canvas://skills` and pull in companion skills
|
|
150
|
-
(`web-artifacts-builder`, `json-render-*`,
|
|
151
|
-
`playwright-cli`, etc.) as the work demands.
|
|
182
|
+
(`control-session-orchestrator`, `web-artifacts-builder`, `json-render-*`,
|
|
183
|
+
`pmx-canvas-testing`, `playwright-cli`, etc.) as the work demands.
|
|
152
184
|
|
|
153
185
|
## Documentation
|
|
154
186
|
|
|
@@ -156,7 +188,7 @@ the agent can read `canvas://skills` and pull in companion skills
|
|
|
156
188
|
the three-tier visual matrix (json-render → html → web-artifact)
|
|
157
189
|
- **[CLI reference](docs/cli.md)** — full command surface, daemon mode,
|
|
158
190
|
watch streams, WebView automation
|
|
159
|
-
- **[MCP reference](docs/mcp.md)** —
|
|
191
|
+
- **[MCP reference](docs/mcp.md)** — 45 tools, 9 resources, change
|
|
160
192
|
notifications, node-type routing
|
|
161
193
|
- **[HTTP API](docs/http-api.md)** — REST endpoints, SSE, batch operations
|
|
162
194
|
- **[Bun SDK](docs/sdk.md)** — `createCanvas()` for TypeScript on Bun
|
|
@@ -168,7 +200,7 @@ the agent can read `canvas://skills` and pull in companion skills
|
|
|
168
200
|
one machine. No built-in multi-user auth or presence — collaboration means
|
|
169
201
|
human ↔ agent on the same machine, plus any other browser tab/agent
|
|
170
202
|
pointed at the same `localhost:4313`. To share across machines, commit
|
|
171
|
-
`.pmx-canvas/
|
|
203
|
+
`.pmx-canvas/canvas.db`.
|
|
172
204
|
- **What leaves your machine.** The core canvas runs entirely on
|
|
173
205
|
`localhost`. Network egress only happens for explicit, opt-in flows:
|
|
174
206
|
`webpage` nodes fetch the URL you give them; `mcp-app` /
|
package/dist/canvas/global.css
CHANGED
|
@@ -1107,10 +1107,13 @@ body,
|
|
|
1107
1107
|
position: absolute;
|
|
1108
1108
|
bottom: 0;
|
|
1109
1109
|
right: 0;
|
|
1110
|
-
width:
|
|
1111
|
-
height:
|
|
1110
|
+
width: 32px;
|
|
1111
|
+
height: 32px;
|
|
1112
|
+
background: rgba(0, 0, 0, 0.001);
|
|
1112
1113
|
cursor: nwse-resize;
|
|
1113
|
-
z-index:
|
|
1114
|
+
z-index: 30;
|
|
1115
|
+
pointer-events: auto;
|
|
1116
|
+
touch-action: none;
|
|
1114
1117
|
}
|
|
1115
1118
|
|
|
1116
1119
|
.canvas-node .node-resize-handle::after {
|
|
@@ -1130,6 +1133,36 @@ body,
|
|
|
1130
1133
|
opacity: 1;
|
|
1131
1134
|
}
|
|
1132
1135
|
|
|
1136
|
+
html.is-node-resizing,
|
|
1137
|
+
html.is-node-resizing * {
|
|
1138
|
+
cursor: nwse-resize !important;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
html.is-node-resizing .canvas-node {
|
|
1142
|
+
transition: box-shadow 0.15s ease !important;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
html.is-node-dragging .attention-field-layer {
|
|
1146
|
+
visibility: hidden;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
html.is-node-dragging,
|
|
1150
|
+
html.is-node-dragging * {
|
|
1151
|
+
cursor: grabbing !important;
|
|
1152
|
+
user-select: none !important;
|
|
1153
|
+
-webkit-user-select: none !important;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
html.is-node-dragging iframe,
|
|
1157
|
+
html.is-node-dragging .ext-app-preview-catcher {
|
|
1158
|
+
pointer-events: none !important;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
html.is-node-resizing iframe,
|
|
1162
|
+
html.is-node-resizing .ext-app-preview-catcher {
|
|
1163
|
+
pointer-events: none !important;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1133
1166
|
/* Pinned node indicator */
|
|
1134
1167
|
.canvas-node.pinned {
|
|
1135
1168
|
border-style: dashed;
|