pmx-canvas 0.4.5 → 0.4.7
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/CHANGELOG.md +118 -0
- package/Readme.md +76 -36
- package/dist/canvas/global.css +169 -3
- package/dist/canvas/index.js +112 -87
- package/dist/canvas/mermaid-entry.js +3563 -0
- package/dist/json-render/index.css +1 -1
- package/dist/types/cli/agent.d.ts +1 -0
- package/dist/types/cli/commands/smoke.d.ts +1 -0
- package/dist/types/cli/shared.d.ts +13 -1
- package/dist/types/client/canvas/CanvasNode.d.ts +11 -0
- package/dist/types/client/canvas/EdgeLayer.d.ts +8 -0
- package/dist/types/client/mermaid-entry.d.ts +11 -0
- package/dist/types/client/nodes/AxStepControls.d.ts +4 -0
- package/dist/types/client/nodes/DiffNode.d.ts +20 -0
- package/dist/types/client/nodes/ExtAppFrame.d.ts +0 -2
- package/dist/types/client/nodes/FileNode.d.ts +14 -0
- package/dist/types/client/nodes/MermaidNode.d.ts +12 -0
- package/dist/types/client/state/canvas-store.d.ts +10 -0
- package/dist/types/client/state/intent-bridge.d.ts +9 -0
- package/dist/types/client/types.d.ts +2 -2
- package/dist/types/server/ax-flow-loop.d.ts +5 -0
- package/dist/types/server/ax-interaction.d.ts +21 -2
- package/dist/types/server/canvas-operations.d.ts +5 -0
- package/dist/types/server/canvas-provenance.d.ts +1 -1
- package/dist/types/server/canvas-state.d.ts +18 -1
- package/dist/types/server/canvas-validation.d.ts +28 -1
- package/dist/types/server/file-content.d.ts +46 -0
- package/dist/types/server/html-primitives.d.ts +13 -1
- package/dist/types/server/html-surface.d.ts +8 -0
- package/dist/types/server/index.d.ts +5 -0
- package/dist/types/server/operations/ops/ax-work.d.ts +1 -0
- package/dist/types/server/operations/ops/nodes.d.ts +1 -1
- package/dist/types/server/server.d.ts +1 -0
- package/dist/types/server/web-artifacts.d.ts +14 -0
- package/dist/types/server/workboard.d.ts +46 -0
- package/dist/types/shared/ax-flow.d.ts +51 -0
- package/dist/types/shared/ax-surface-protocol.d.ts +7 -0
- package/dist/types/shared/node-sizes.d.ts +33 -0
- package/docs/cli.md +31 -2
- package/docs/environment.md +1 -0
- package/docs/http-api.md +29 -0
- package/docs/mcp.md +13 -1
- package/docs/node-types.md +47 -1
- package/docs/screenshot.png +0 -0
- package/package.json +5 -4
- package/skills/pmx-canvas/SKILL.md +123 -25
- package/skills/pmx-canvas/evals/evals.json +54 -3
- package/skills/pmx-canvas/references/full-reference.md +11 -6
- package/skills/pmx-canvas-testing/SKILL.md +3 -0
- package/src/cli/agent.ts +2 -0
- package/src/cli/commands/ax.ts +28 -3
- package/src/cli/commands/history.ts +1 -1
- package/src/cli/commands/nodes.ts +2 -2
- package/src/cli/commands/query.ts +1 -1
- package/src/cli/commands/smoke.ts +212 -0
- package/src/cli/commands/view.ts +1 -1
- package/src/cli/index.ts +7 -0
- package/src/cli/shared.ts +35 -5
- package/src/client/App.tsx +28 -15
- package/src/client/canvas/CanvasNode.tsx +54 -5
- package/src/client/canvas/CanvasViewport.tsx +6 -0
- package/src/client/canvas/EdgeLayer.tsx +44 -24
- package/src/client/canvas/ExpandedNodeOverlay.tsx +21 -0
- package/src/client/canvas/Minimap.tsx +2 -0
- package/src/client/canvas/auto-fit.ts +12 -1
- package/src/client/canvas/use-pan-zoom.ts +16 -1
- package/src/client/icons.tsx +4 -0
- package/src/client/mermaid-entry.ts +76 -0
- package/src/client/nodes/AxStepControls.tsx +226 -0
- package/src/client/nodes/DiffNode.tsx +114 -0
- package/src/client/nodes/ExtAppFrame.tsx +259 -84
- package/src/client/nodes/FileNode.tsx +249 -51
- package/src/client/nodes/MermaidNode.tsx +81 -0
- package/src/client/state/canvas-store.ts +19 -0
- package/src/client/state/intent-bridge.ts +32 -0
- package/src/client/state/node-factory.ts +2 -0
- package/src/client/state/sse-bridge.ts +32 -1
- package/src/client/theme/global.css +169 -3
- package/src/client/types.ts +6 -0
- package/src/mcp/server.ts +19 -1
- package/src/server/ax-flow-loop.ts +114 -0
- package/src/server/ax-interaction.ts +305 -4
- package/src/server/canvas-operations.ts +83 -26
- package/src/server/canvas-provenance.ts +2 -0
- package/src/server/canvas-schema.ts +33 -0
- package/src/server/canvas-state.ts +46 -10
- package/src/server/canvas-validation.ts +88 -0
- package/src/server/demo-state.json +4605 -523
- package/src/server/demo.ts +24 -0
- package/src/server/file-content.ts +152 -0
- package/src/server/file-watcher.ts +7 -10
- package/src/server/html-primitives.ts +636 -0
- package/src/server/html-surface.ts +11 -0
- package/src/server/index.ts +25 -6
- package/src/server/operations/composites.ts +3 -2
- package/src/server/operations/ops/ax-work.ts +5 -0
- package/src/server/operations/ops/batch.ts +8 -0
- package/src/server/operations/ops/json-render.ts +44 -0
- package/src/server/operations/ops/nodes.ts +24 -2
- package/src/server/operations/ops/viewport.ts +15 -2
- package/src/server/server.ts +154 -6
- package/src/server/web-artifacts.ts +109 -0
- package/src/server/workboard.ts +159 -0
- package/src/shared/ax-flow.ts +102 -0
- package/src/shared/ax-surface-protocol.ts +8 -0
- package/src/shared/node-sizes.ts +52 -0
- package/src/shared/surface.ts +2 -0
- package/dist/types/server/chart-template.d.ts +0 -29
- package/src/server/chart-template.ts +0 -448
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,122 @@
|
|
|
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.4.7] - 2026-08-09
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- The flow works without the panel too: materialized step nodes get native
|
|
11
|
+
Start / Done / Blocked controls, and the first step adds Run loop / Stop and
|
|
12
|
+
a steer box. That loop runs server-side, so it survives a browser reload and
|
|
13
|
+
keeps advancing while the tab is closed.
|
|
14
|
+
- Two live AX control surfaces you can put on the board: **`ax-board`** (give
|
|
15
|
+
the agent tasks, watch their status change as it works, steer it, and run a
|
|
16
|
+
bounded task loop) and **`ax-flow`** (the same controls drawn as a task flow
|
|
17
|
+
with a loop-back rail, plus a **Materialize to board** button that lays the
|
|
18
|
+
flow out as real nodes joined by edges, each tracking its own status).
|
|
19
|
+
- The demo board is a proper showcase now: every node type, every chart type,
|
|
20
|
+
every HTML primitive, a grouped cluster, labelled edges and context pins —
|
|
21
|
+
laid out in labelled bands instead of the old three-group OKR dashboard.
|
|
22
|
+
- `GET /api/canvas/file-bytes?nodeId=…` serves a file node's bytes from the
|
|
23
|
+
workspace (used by the inline PDF viewer); paths outside the workspace, or
|
|
24
|
+
reached through a symlink out of it, are refused.
|
|
25
|
+
- File nodes now handle more than source code: `.csv` and `.tsv` files render
|
|
26
|
+
as real tables, PDFs render in an embedded viewer, and other binary files
|
|
27
|
+
show a name-and-size placeholder instead of decoded gibberish. Text files
|
|
28
|
+
larger than 2 MB render truncated with a notice rather than being read into
|
|
29
|
+
memory whole.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- The mouse wheel now zooms the canvas (trackpad two-finger scrolling still
|
|
34
|
+
pans, and the toolbar +/- buttons and their keyboard shortcuts both zoom
|
|
35
|
+
around the viewport centre).
|
|
36
|
+
- The browser honors the server's readability floor, so content-fit never
|
|
37
|
+
shrinks a node back below it.
|
|
38
|
+
- `validate` now reports edges whose endpoint node is docked (and therefore
|
|
39
|
+
cannot be drawn) as an advisory `hiddenEdgeEndpoints` list. Like
|
|
40
|
+
`sizeWarnings` it does not fail `ok`, so boards that passed before still
|
|
41
|
+
pass.
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- `strictSize` is no longer dropped on file, image and webpage nodes — it used
|
|
46
|
+
to be honored when sizing the node but never stored, so the browser resized
|
|
47
|
+
the node anyway.
|
|
48
|
+
- Node chrome no longer crowds out short nodes when you zoom out: the title bar
|
|
49
|
+
used to grow until it took most of a small node and clipped its text away.
|
|
50
|
+
- Context nodes no longer dock themselves invisibly: a node you create lands on
|
|
51
|
+
the canvas where you put it, and docking to the HUD column is something you
|
|
52
|
+
ask for. Previously an agent-created context node existed in the API and
|
|
53
|
+
passed validation but never rendered, so edges to it trailed off into empty
|
|
54
|
+
space.
|
|
55
|
+
- `fit` now sizes the board to the connected browser window instead of assuming
|
|
56
|
+
1440x900, so fitting no longer leaves nodes clipped on both sides.
|
|
57
|
+
- Edges stay legible when you zoom out: strokes, dashes, arrowheads, and labels
|
|
58
|
+
now hold their on-screen size instead of shrinking to invisible hairlines,
|
|
59
|
+
and `references` edges use a higher-contrast colour.
|
|
60
|
+
- CLI flag values that begin with a dash now work, so a unified diff starting
|
|
61
|
+
with `--- a/file` can be passed straight to `--content` (and a bare `--` ends
|
|
62
|
+
flag parsing).
|
|
63
|
+
- Web-artifact builds now fail fast with a clear message naming the Node.js
|
|
64
|
+
version they need, instead of an opaque package-manager error.
|
|
65
|
+
|
|
66
|
+
## [0.4.6] - 2026-08-08
|
|
67
|
+
|
|
68
|
+
### Added
|
|
69
|
+
|
|
70
|
+
- A `pmx-canvas smoke` command: one-command check that a running canvas works
|
|
71
|
+
in the current environment — server health + workspace, CLI/server version
|
|
72
|
+
skew, MCP initialize handshake, a temporary node create/search/remove
|
|
73
|
+
round-trip, and board validation. JSON report, exit 1 on failure.
|
|
74
|
+
- The `/health` endpoint now reports the server's package `version`, so tools
|
|
75
|
+
can detect version skew between a CLI and the daemon it targets.
|
|
76
|
+
- The CLI now accepts `--agent-id` on `ax work add/update` and `ax event add`,
|
|
77
|
+
and `--agent-id` / `--target` on `ax steer`; the SDK's work, event, and
|
|
78
|
+
steering methods accept the same identity fields.
|
|
79
|
+
- The skill now teaches in-view placement and content sizing: focus or fit
|
|
80
|
+
newly created user-facing nodes, use per-type default sizes, and keep AX
|
|
81
|
+
state reads lean.
|
|
82
|
+
- A new `diff` node type: unified diffs render with per-file headers, hunk
|
|
83
|
+
rows, and colored added/removed lines instead of a plain code fence.
|
|
84
|
+
- A new `mermaid` node type: flowcharts, sequence and state diagrams render
|
|
85
|
+
client-side from mermaid text — no hosted app needed; Excalidraw remains
|
|
86
|
+
for interactive drawing.
|
|
87
|
+
- A live work-item board: `canvas_render { action: "workboard" }` (HTTP
|
|
88
|
+
`POST /api/canvas/workboard`) materializes one board node showing all AX
|
|
89
|
+
work items by status, and it refreshes automatically whenever work items
|
|
90
|
+
change.
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
### Changed
|
|
94
|
+
|
|
95
|
+
- **Nodes created with unreadably small explicit sizes are now clamped up to a
|
|
96
|
+
per-type minimum.** A request for e.g. 200x100 now yields a readable
|
|
97
|
+
default-ish size instead; pass `strictSize: true` to keep a genuinely small
|
|
98
|
+
fixed frame. `validate` reports any undersized nodes as advisory size
|
|
99
|
+
warnings. Agents doing their own layout arithmetic should read back the
|
|
100
|
+
created size (or set `strictSize`).
|
|
101
|
+
- The README's MCP and Amp orb setup guides now cover portable configs: pin
|
|
102
|
+
the package version in orb setup scripts and avoid hard-coding an absolute
|
|
103
|
+
`PMX_CANVAS_WORKSPACE_ROOT` in committed MCP configs.
|
|
104
|
+
- Focus margins are now screen-space and zoom-aware, so a focused node clears
|
|
105
|
+
the floating toolbar at any scale.
|
|
106
|
+
|
|
107
|
+
### Fixed
|
|
108
|
+
|
|
109
|
+
- A browser panel left open across a `pmx-canvas` upgrade now reloads itself
|
|
110
|
+
once on reconnect instead of silently running the old client bundle (which
|
|
111
|
+
hid new client behavior such as the auto-ghost minimum dwell).
|
|
112
|
+
- A batch that pins nodes now updates the browser's pin state immediately —
|
|
113
|
+
the context menu no longer shows a stale "Pin as context" until reload.
|
|
114
|
+
- The MCP stdio server now exits when its client closes the connection instead
|
|
115
|
+
of remaining as an orphaned process.
|
|
116
|
+
- Black app tiles in WebKit host panels (e.g. the GitHub Copilot app): hosted
|
|
117
|
+
app frames now boot one at a time, confirm they actually painted via a paint
|
|
118
|
+
probe, and recover automatically when they did not — soft resize, then
|
|
119
|
+
remount, then an explicit Retry button instead of a silent black tile. The
|
|
120
|
+
loading overlay stays up until the paint is confirmed.
|
|
121
|
+
|
|
6
122
|
## [0.4.5] - 2026-08-07
|
|
7
123
|
|
|
8
124
|
### Added
|
|
@@ -2989,6 +3105,8 @@ otherwise have to discover by trial and error.
|
|
|
2989
3105
|
- Regression coverage for snapshot flat-`id` aliases on both MCP and
|
|
2990
3106
|
HTTP surfaces, plus async / top-level-`await` WebView script bodies.
|
|
2991
3107
|
|
|
3108
|
+
[0.4.7]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.4.7
|
|
3109
|
+
[0.4.6]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.4.6
|
|
2992
3110
|
[0.4.5]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.4.5
|
|
2993
3111
|
[0.4.4]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.4.4
|
|
2994
3112
|
[0.4.3]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.4.3
|
package/Readme.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# pmx-canvas
|
|
2
2
|
|
|
3
3
|
**A moldable canvas for agent-assisted thinking.** An infinite 2D surface
|
|
4
|
-
where files, plans, status, charts, fetched web pages, annotations,
|
|
5
|
-
|
|
4
|
+
where files, plans, status, charts, fetched web pages, annotations, code
|
|
5
|
+
diffs, and diagrams live side by side. Every node carries its own renderer; agents
|
|
6
6
|
(and you) build new views in the middle of a session — even streaming a
|
|
7
7
|
structured panel into place as they generate it — not as a separate tooling
|
|
8
8
|
project. Pin what matters and the agent reads your spatial curation as
|
|
@@ -35,14 +35,21 @@ neighborhoods) and uses your layout to ground its next action.
|
|
|
35
35
|
|
|
36
36
|
### 02 / Mix any data source
|
|
37
37
|
|
|
38
|
-
Files, web pages, screenshots, structured panels, charts,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
Files, web pages, screenshots, structured panels, charts, diagrams, embedded
|
|
39
|
+
MCP Apps, and bundled web artifacts all live on the same surface. A file node
|
|
40
|
+
follows the file on disk as the agent edits it — source with line numbers, a
|
|
41
|
+
CSV or TSV as a real table, a PDF inline. Anything else binary shows its name
|
|
42
|
+
and size rather than decoded gibberish, and a very large text file renders
|
|
43
|
+
truncated with a note saying so. Code review has its own node: a unified
|
|
44
|
+
diff with per-file headers and colored added and removed lines. Diagrams can
|
|
45
|
+
be drawn by hand in Excalidraw or written as plain mermaid text and rendered
|
|
46
|
+
on the spot. Context cards, execution ledgers, and agent trace pills round out
|
|
47
|
+
the set. Any rich surface — HTML, mermaid, json-render, graph, webpage, or a
|
|
48
|
+
web artifact — can be **opened as a site**, full-page in its own browser tab
|
|
49
|
+
with one click; the canvas and the tab render the same document. The reach of
|
|
50
|
+
the canvas is the union of its [built-in node types](docs/node-types.md) and
|
|
51
|
+
**whatever your agent's harness already has access to** — MCP servers, CLIs,
|
|
52
|
+
file reads, web fetch, anything on its toolbelt.
|
|
46
53
|
|
|
47
54
|
### 03 / Annotate
|
|
48
55
|
|
|
@@ -61,13 +68,17 @@ immediately — an explicit, low-noise control over what the agent sees next.
|
|
|
61
68
|
On top of pins, a host-agnostic **AX (agent-experience) layer** turns the
|
|
62
69
|
canvas into a shared workspace between you and the agent:
|
|
63
70
|
|
|
64
|
-
- **Agent-native nodes** —
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
71
|
+
- **Agent-native nodes** — most node types can act as interactive controls for
|
|
72
|
+
the agent out of the box: a node can focus context, create or update work,
|
|
73
|
+
add evidence, request input or approval, or send steering without leaving the
|
|
74
|
+
board. The sandboxed surfaces — HTML nodes and MCP apps — stay off until a
|
|
75
|
+
node opts in, since their content is author-supplied.
|
|
68
76
|
- **Focus** — promote nodes into the agent's active context without moving the viewport.
|
|
69
77
|
- **Work items & approval gates** — track visible tasks tied to nodes, and gate
|
|
70
|
-
high-impact actions behind a human `pending → approved/rejected` decision.
|
|
78
|
+
high-impact actions behind a human `pending → approved/rejected` decision. A
|
|
79
|
+
linked node shows its work item's status on the title bar, and a live work
|
|
80
|
+
board lays the whole queue out by status and keeps itself current — useful
|
|
81
|
+
when several agents are working at once.
|
|
71
82
|
- **Steering messages & agent-event timeline** — send instructions to the
|
|
72
83
|
active session, and read a normalized, bounded timeline of prompts, tool
|
|
73
84
|
runs, evidence (logs/diffs/screenshots/test-output), and failures.
|
|
@@ -109,8 +120,9 @@ Harness-agnostic. Drive the canvas from [MCP](docs/mcp.md) (22 tools,
|
|
|
109
120
|
14 resources, change notifications), the [CLI](docs/cli.md), the
|
|
110
121
|
[HTTP API](docs/http-api.md), or the [Bun SDK](docs/sdk.md) — all
|
|
111
122
|
[environment variables documented here](docs/environment.md). Works with
|
|
112
|
-
Claude Code, GitHub Copilot CLI, Codex, Cursor, Windsurf, or
|
|
113
|
-
that can spawn an MCP stdio server, call a CLI, or hit an HTTP
|
|
123
|
+
Claude Code, the GitHub Copilot app and CLI, Codex, Amp, Cursor, Windsurf, or
|
|
124
|
+
any agent that can spawn an MCP stdio server, call a CLI, or hit an HTTP
|
|
125
|
+
endpoint.
|
|
114
126
|
|
|
115
127
|
### 07 / Native app adapters
|
|
116
128
|
|
|
@@ -203,15 +215,20 @@ To work on the canvas itself, clone the repo — see [Development](#development)
|
|
|
203
215
|
|
|
204
216
|
```bash
|
|
205
217
|
bunx pmx-canvas # Start canvas, open browser
|
|
206
|
-
bunx pmx-canvas --demo # Start with the
|
|
218
|
+
bunx pmx-canvas --demo # Start with the showcase demo board
|
|
207
219
|
bunx pmx-canvas --no-open # Headless (good for daemons / CI)
|
|
220
|
+
bunx pmx-canvas --theme=volt # Pick a theme (nine ship; PMX_CANVAS_THEME works too)
|
|
208
221
|
bunx pmx-canvas --mcp # Run as MCP server (stdio)
|
|
209
222
|
bunx pmx-canvas --help # All commands
|
|
210
223
|
```
|
|
211
224
|
|
|
225
|
+
Themes are a toolbar picker away too, and any one panel can override the
|
|
226
|
+
shared theme for itself with `?theme=<name|auto>`.
|
|
227
|
+
|
|
212
228
|
The canvas opens at `http://localhost:4313`. Try `--demo` first — it seeds a
|
|
213
|
-
|
|
214
|
-
|
|
229
|
+
showcase board with every node type on it: notes and status, files, a diff, a
|
|
230
|
+
CSV table, charts of every kind, mermaid diagrams, the HTML primitives,
|
|
231
|
+
structured panels, a grouped cluster, labeled edges, and context pins.
|
|
215
232
|
|
|
216
233
|
### Connect your agent (MCP)
|
|
217
234
|
|
|
@@ -228,7 +245,21 @@ Add to your agent's MCP config:
|
|
|
228
245
|
}
|
|
229
246
|
```
|
|
230
247
|
|
|
231
|
-
The canvas auto-starts on first tool call.
|
|
248
|
+
The canvas auto-starts on first tool call. Keep the config portable: commit it
|
|
249
|
+
to the repo and let the workspace default to the launch directory — hard-coding
|
|
250
|
+
an absolute `PMX_CANVAS_WORKSPACE_ROOT` breaks other checkouts and machines.
|
|
251
|
+
Set that env var only when your host spawns the MCP server from an incidental
|
|
252
|
+
directory (e.g. `~/.copilot`) instead of the project root.
|
|
253
|
+
|
|
254
|
+
Verify any environment in one command against a running server:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
bunx pmx-canvas smoke
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
It checks server health + workspace, CLI/server version skew, the MCP stdio
|
|
261
|
+
initialize handshake, a temp-node create/search/remove round-trip, and board
|
|
262
|
+
validation — JSON report, exit 1 on failure.
|
|
232
263
|
|
|
233
264
|
### Use inside the GitHub Copilot app
|
|
234
265
|
|
|
@@ -274,8 +305,9 @@ services:
|
|
|
274
305
|
```
|
|
275
306
|
|
|
276
307
|
```bash
|
|
277
|
-
# .agents/setup — install the CLI (pin the version
|
|
278
|
-
|
|
308
|
+
# .agents/setup — install the CLI (pin the exact version: a fresh orb running
|
|
309
|
+
# @latest can silently pick up a newer release than the one you validated)
|
|
310
|
+
npm install -g pmx-canvas@0.4.7
|
|
279
311
|
```
|
|
280
312
|
|
|
281
313
|
The server binds the portal-assigned `$PORT` automatically (gated on the
|
|
@@ -286,12 +318,15 @@ caveat: WebView automation (`pmx-canvas screenshot`) needs Bun >= 1.3.12 in
|
|
|
286
318
|
the orb image; the canvas itself runs fine without it and says so in the
|
|
287
319
|
error. The canvas detects the orb and the portal's nested-iframe
|
|
288
320
|
embed on its own: live updates arrive over the proxy-safe polling transport,
|
|
289
|
-
and iframe-backed nodes (HTML, graph, json-render, web artifacts)
|
|
290
|
-
inline via `srcdoc` with their theme styling included.
|
|
291
|
-
|
|
292
|
-
|
|
321
|
+
and iframe-backed nodes (HTML, mermaid, graph, json-render, web artifacts)
|
|
322
|
+
render inline via `srcdoc` with their theme styling included. Two things can't
|
|
323
|
+
be inlined and stay blocked by the portal embed: cross-origin hosted apps (e.g.
|
|
324
|
+
the hosted Excalidraw MCP app), and PDF file nodes — a PDF node offers an
|
|
325
|
+
"Open PDF" link there instead of a preview.
|
|
293
326
|
Debug overrides: `/workbench?transport=poll|sse` and
|
|
294
|
-
`?iframe-mode=srcdoc|src`.
|
|
327
|
+
`?iframe-mode=srcdoc|src`. Once the service is up, `pmx-canvas smoke` verifies
|
|
328
|
+
the whole stack (health, versions, MCP handshake, node lifecycle, validation)
|
|
329
|
+
in one command.
|
|
295
330
|
|
|
296
331
|
### Install the agent skill (recommended)
|
|
297
332
|
|
|
@@ -315,7 +350,8 @@ Common harness skill directories: `.claude/skills/` (Claude Code),
|
|
|
315
350
|
`.github/skills/` or `.copilot/skills/` (Copilot CLI),
|
|
316
351
|
`.agents/skills/` (cross-harness convention). Once the canvas is running,
|
|
317
352
|
the agent can read `canvas://skills` and pull in companion skills
|
|
318
|
-
(`
|
|
353
|
+
(`pmx-canvas-orchestration` for running several agents on one board,
|
|
354
|
+
`control-session-orchestrator`, `web-artifacts-builder`, `json-render-*`,
|
|
319
355
|
`pmx-canvas-testing`, `playwright-cli`, etc.) as the work demands.
|
|
320
356
|
|
|
321
357
|
## Documentation
|
|
@@ -341,16 +377,20 @@ the agent can read `canvas://skills` and pull in companion skills
|
|
|
341
377
|
`.pmx-canvas/canvas.db`.
|
|
342
378
|
- **What leaves your machine.** The core canvas runs entirely on
|
|
343
379
|
`localhost`. Network egress only happens for explicit, opt-in flows:
|
|
344
|
-
`webpage` nodes fetch the
|
|
345
|
-
`canvas_app { action: "diagram" }` calls go to whatever
|
|
346
|
-
configure (the Excalidraw preset uses
|
|
347
|
-
`
|
|
348
|
-
|
|
380
|
+
`webpage` nodes and remote-URL `image` nodes fetch the address you give
|
|
381
|
+
them; `mcp-app` / `canvas_app { action: "diagram" }` calls go to whatever
|
|
382
|
+
MCP server URL you configure (the Excalidraw preset uses
|
|
383
|
+
`https://mcp.excalidraw.com/mcp`); building a web artifact runs a package
|
|
384
|
+
manager, which fetches a React/Tailwind toolchain plus that artifact's declared dependencies (and, if neither pnpm nor bun is present, installs pnpm globally) from the npm
|
|
385
|
+
registry; and `bunx` itself reads the registry on first install. Nothing
|
|
386
|
+
else phones home.
|
|
349
387
|
|
|
350
388
|
## Tech stack
|
|
351
389
|
|
|
352
390
|
- **Runtime:** [Bun](https://bun.sh)
|
|
353
|
-
- **UI:** [Preact](https://preactjs.com) + [@preact/signals](https://github.com/preactjs/signals)
|
|
391
|
+
- **UI:** [Preact](https://preactjs.com) + [@preact/signals](https://github.com/preactjs/signals);
|
|
392
|
+
the json-render/graph viewer bundle is React + [recharts](https://recharts.org),
|
|
393
|
+
and mermaid nodes render with [mermaid](https://mermaid.js.org)
|
|
354
394
|
- **Styling:** CSS custom properties + Tailwind (json-render bundle only)
|
|
355
395
|
- **Server:** Bun.serve (HTTP + SSE)
|
|
356
396
|
- **MCP:** [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk) (stdio)
|
|
@@ -363,7 +403,7 @@ cd pmx-canvas
|
|
|
363
403
|
bun install
|
|
364
404
|
bun run build
|
|
365
405
|
bun run dev # Start + open browser
|
|
366
|
-
bun run dev:demo # Start with the demo board
|
|
406
|
+
bun run dev:demo # Start with the showcase demo board
|
|
367
407
|
bun run test # Unit tests
|
|
368
408
|
bun run test:e2e # Playwright end-to-end tests
|
|
369
409
|
bun run test:all # Unit tests + browser smoke
|
package/dist/canvas/global.css
CHANGED
|
@@ -643,6 +643,10 @@ body,
|
|
|
643
643
|
overflow: hidden;
|
|
644
644
|
text-overflow: ellipsis;
|
|
645
645
|
flex: 1;
|
|
646
|
+
/* The name is the one thing that must survive a cramped title bar. Everything
|
|
647
|
+
else in the bar is flex-shrink: 0, so without a floor the title absorbed all
|
|
648
|
+
the pressure and collapsed to an ellipsis on narrow nodes. */
|
|
649
|
+
min-width: 9ch;
|
|
646
650
|
min-width: 0;
|
|
647
651
|
}
|
|
648
652
|
|
|
@@ -670,6 +674,13 @@ body,
|
|
|
670
674
|
}
|
|
671
675
|
|
|
672
676
|
.canvas-node .node-ax-status {
|
|
677
|
+
/* A long status ("in-progress") must not push the node's NAME out of the bar;
|
|
678
|
+
the pill is a glance-level cue, the name is the identity. */
|
|
679
|
+
max-width: 11ch;
|
|
680
|
+
overflow: hidden;
|
|
681
|
+
text-overflow: ellipsis;
|
|
682
|
+
white-space: nowrap;
|
|
683
|
+
flex-shrink: 1;
|
|
673
684
|
font-size: calc(9px * var(--node-chrome-scale, 1));
|
|
674
685
|
padding: calc(1px * var(--node-chrome-scale, 1)) calc(6px * var(--node-chrome-scale, 1));
|
|
675
686
|
border-radius: calc(4px * var(--node-chrome-scale, 1));
|
|
@@ -1846,10 +1857,11 @@ html.is-node-resizing .ext-app-preview-catcher {
|
|
|
1846
1857
|
border-radius: 999px;
|
|
1847
1858
|
}
|
|
1848
1859
|
|
|
1849
|
-
/* Edge labels
|
|
1860
|
+
/* Edge labels — --edge-chrome-scale is set on the edge <svg> so labels keep a
|
|
1861
|
+
constant screen size while zoomed out (see edgeChromeScale in EdgeLayer). */
|
|
1850
1862
|
.edge-label {
|
|
1851
1863
|
font-family: var(--font);
|
|
1852
|
-
font-size: 11px;
|
|
1864
|
+
font-size: calc(11px * var(--edge-chrome-scale, 1));
|
|
1853
1865
|
pointer-events: none;
|
|
1854
1866
|
user-select: none;
|
|
1855
1867
|
}
|
|
@@ -1857,7 +1869,7 @@ html.is-node-resizing .ext-app-preview-catcher {
|
|
|
1857
1869
|
.edge-label-bg {
|
|
1858
1870
|
fill: var(--c-panel-glass);
|
|
1859
1871
|
stroke: var(--c-line);
|
|
1860
|
-
stroke-width: 0.5;
|
|
1872
|
+
stroke-width: calc(0.5 * var(--edge-chrome-scale, 1));
|
|
1861
1873
|
}
|
|
1862
1874
|
|
|
1863
1875
|
/* Trace nodes — compact pills for agent tool/subagent visualization */
|
|
@@ -1895,6 +1907,160 @@ html.is-node-resizing .ext-app-preview-catcher {
|
|
|
1895
1907
|
}
|
|
1896
1908
|
}
|
|
1897
1909
|
|
|
1910
|
+
/* Diff nodes — unified diff viewer with per-file sections */
|
|
1911
|
+
.diff-node {
|
|
1912
|
+
display: flex;
|
|
1913
|
+
flex-direction: column;
|
|
1914
|
+
gap: 10px;
|
|
1915
|
+
height: 100%;
|
|
1916
|
+
overflow: auto;
|
|
1917
|
+
font-family: var(--mono);
|
|
1918
|
+
font-size: 12px;
|
|
1919
|
+
color: var(--c-text);
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1922
|
+
.diff-node.diff-node-empty {
|
|
1923
|
+
align-items: center;
|
|
1924
|
+
justify-content: center;
|
|
1925
|
+
color: var(--c-muted);
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
.diff-node .diff-file {
|
|
1929
|
+
border: 1px solid var(--c-line);
|
|
1930
|
+
border-radius: 6px;
|
|
1931
|
+
overflow: hidden;
|
|
1932
|
+
flex-shrink: 0;
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
.diff-node .diff-file-header {
|
|
1936
|
+
padding: 4px 8px;
|
|
1937
|
+
background: var(--c-panel-overlay);
|
|
1938
|
+
border-bottom: 1px solid var(--c-line);
|
|
1939
|
+
color: var(--c-text-soft);
|
|
1940
|
+
font-weight: 600;
|
|
1941
|
+
white-space: nowrap;
|
|
1942
|
+
overflow: hidden;
|
|
1943
|
+
text-overflow: ellipsis;
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
.diff-node .diff-lines {
|
|
1947
|
+
margin: 0;
|
|
1948
|
+
padding: 4px 0;
|
|
1949
|
+
overflow-x: auto;
|
|
1950
|
+
font-family: inherit;
|
|
1951
|
+
font-size: inherit;
|
|
1952
|
+
line-height: 1.5;
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
.diff-node .diff-lines > div {
|
|
1956
|
+
padding: 0 8px;
|
|
1957
|
+
white-space: pre;
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
.diff-node .diff-hunk {
|
|
1961
|
+
color: var(--c-muted);
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
.diff-node .diff-line-add {
|
|
1965
|
+
color: var(--c-ok);
|
|
1966
|
+
background: var(--c-ok-10);
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
.diff-node .diff-line-remove {
|
|
1970
|
+
color: var(--c-danger);
|
|
1971
|
+
background: var(--c-danger-12);
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
.diff-node .diff-line-context {
|
|
1975
|
+
color: var(--c-text-soft);
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
/* File nodes — delimited-data tables and non-text placeholders */
|
|
1979
|
+
.file-table-shell {
|
|
1980
|
+
display: flex;
|
|
1981
|
+
flex-direction: column;
|
|
1982
|
+
height: 100%;
|
|
1983
|
+
min-height: 0;
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
.file-node-notice {
|
|
1987
|
+
flex-shrink: 0;
|
|
1988
|
+
padding: 4px 10px;
|
|
1989
|
+
color: var(--c-muted);
|
|
1990
|
+
font-size: 10px;
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
/* Own scroll port so a wide CSV scrolls inside the node instead of blowing out
|
|
1994
|
+
the layout — and so the sticky header row has something to stick to. */
|
|
1995
|
+
.file-table-wrap {
|
|
1996
|
+
flex: 1;
|
|
1997
|
+
min-height: 0;
|
|
1998
|
+
overflow: auto;
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
/* The shell/wrap prefix is load-bearing: these rules must out-specify the markdown
|
|
2002
|
+
table styles (`.canvas-node .node-body table` / `th` / `td`), whose 0.5em
|
|
2003
|
+
margin and translucent header background break the sticky header. Borders are
|
|
2004
|
+
separate, not collapsed — collapsed borders belong to the table element, so
|
|
2005
|
+
the header leaks the rows scrolling beneath it. */
|
|
2006
|
+
.file-table-shell .file-table-wrap .file-table {
|
|
2007
|
+
margin: 0;
|
|
2008
|
+
border-collapse: separate;
|
|
2009
|
+
border-spacing: 0;
|
|
2010
|
+
width: max-content;
|
|
2011
|
+
min-width: 100%;
|
|
2012
|
+
font-family: var(--mono);
|
|
2013
|
+
color: var(--c-text);
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
.file-table-shell .file-table-wrap .file-table th,
|
|
2017
|
+
.file-table-shell .file-table-wrap .file-table td {
|
|
2018
|
+
max-width: 320px;
|
|
2019
|
+
padding: 3px 8px;
|
|
2020
|
+
border: none;
|
|
2021
|
+
border-right: 1px solid var(--c-line);
|
|
2022
|
+
border-bottom: 1px solid var(--c-line);
|
|
2023
|
+
text-align: left;
|
|
2024
|
+
white-space: nowrap;
|
|
2025
|
+
overflow: hidden;
|
|
2026
|
+
text-overflow: ellipsis;
|
|
2027
|
+
}
|
|
2028
|
+
|
|
2029
|
+
.file-table-shell .file-table-wrap .file-table th {
|
|
2030
|
+
position: sticky;
|
|
2031
|
+
top: 0;
|
|
2032
|
+
z-index: 1;
|
|
2033
|
+
/* Opaque in every theme — rows must not bleed through while scrolling. */
|
|
2034
|
+
background: var(--c-panel);
|
|
2035
|
+
color: var(--c-text-soft);
|
|
2036
|
+
font-weight: 600;
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
.file-table-shell .file-table-wrap .file-table tbody tr:nth-child(even) {
|
|
2040
|
+
background: var(--c-surface-subtle);
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
.file-node-placeholder {
|
|
2044
|
+
display: flex;
|
|
2045
|
+
flex-direction: column;
|
|
2046
|
+
align-items: center;
|
|
2047
|
+
justify-content: center;
|
|
2048
|
+
gap: 4px;
|
|
2049
|
+
height: 100%;
|
|
2050
|
+
padding: 16px;
|
|
2051
|
+
color: var(--c-muted);
|
|
2052
|
+
text-align: center;
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
.file-node-placeholder-name {
|
|
2056
|
+
color: var(--c-text-soft);
|
|
2057
|
+
word-break: break-all;
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
.file-node-link {
|
|
2061
|
+
color: var(--c-accent);
|
|
2062
|
+
}
|
|
2063
|
+
|
|
1898
2064
|
/* Docked node — compact toolbar-flanking panel */
|
|
1899
2065
|
.docked-node {
|
|
1900
2066
|
min-width: 200px;
|