pmx-canvas 0.1.17 → 0.1.19

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 CHANGED
@@ -3,6 +3,103 @@
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.19] - 2026-05-05
7
+
8
+ Snapshot ergonomics and reference-doc distribution. Adds `before` /
9
+ `after` ISO timestamp filters on snapshot listing across CLI, HTTP,
10
+ and MCP, ships the `docs/` reference tree inside the npm tarball so
11
+ consumers see the same surface docs as the repo, and surfaces the
12
+ existing trace-field flags in `node update --help`. Also lands the
13
+ deflake of the MCP-app fullscreen reopen e2e (originally
14
+ `LRN-20260505-001`) — 9/20 → 50+/50 stability via a retry-on-stuck-
15
+ iframe helper.
16
+
17
+ ### Added
18
+
19
+ - **`pmx-canvas snapshot list --before / --after`.** Both flags
20
+ accept ISO 8601 timestamps and filter against `snapshot.createdAt`.
21
+ Same surface lands on `GET /api/canvas/snapshots?before=&after=`,
22
+ `RemoteCanvasAccess.listSnapshots()`, and the `canvas_list_snapshots`
23
+ MCP tool schema. The CLI help (`pmx-canvas snapshot list --help`)
24
+ now lists the new flags alongside `--limit`, `--query`, and
25
+ `--all`.
26
+ - **`docs/` shipped in the npm tarball.** The package `files`
27
+ allowlist now includes `docs/`, so consumers installing
28
+ `pmx-canvas` see the same `docs/cli.md`, `docs/http-api.md`,
29
+ `docs/mcp.md`, `docs/node-types.md`, and `docs/sdk.md` reference
30
+ files that ship in the repo.
31
+ - **`node update --help` advertises trace flags.** The CLI help now
32
+ documents `--tool-name` / `--toolName`, `--category`, `--status`,
33
+ `--duration`, `--result-summary` / `--resultSummary`, and `--error`
34
+ so agents discover trace-field updates without reading the source
35
+ or schema.
36
+
37
+ ### Fixed
38
+
39
+ - **MCP-app fullscreen reopen e2e is no longer flaky.** The
40
+ visibility check for the fixture editor used to race the ext-app
41
+ bridge handshake — if the iframe started parsing before the
42
+ parent registered its postMessage listener, the iframe's
43
+ `ui/initialize` request was lost and `app.connect()` hung. The
44
+ test now wraps the assertion in a retry-on-stuck-iframe helper
45
+ that closes and reopens the fullscreen overlay (each remount is
46
+ independent of the prior failed handshake), with three 5s
47
+ attempts to match the original 15s budget. Pass rate moved from
48
+ 9/20 to 50+/50 consecutive runs.
49
+
50
+ ### Internal
51
+
52
+ - Regression coverage for: snapshot list before/after filtering at
53
+ the canvas-state layer and through the CLI, snapshot list help
54
+ advertising the new flags, `node update --help` advertising
55
+ trace flags, the `docs/` allowlist entry surviving in
56
+ `package.json` for npm consumers, and the existing arrange
57
+ operation recording as a single undoable history entry.
58
+
59
+ ## [0.1.18] - 2026-05-05
60
+
61
+ Token-budget polish on top of 0.1.17. Full-mode MCP responses for
62
+ hosted external-MCP-app nodes now elide the rendered shell HTML in
63
+ favor of a compact `{ omitted, resourceUri, bytes, sha256 }` summary,
64
+ so an agent that asks for `full: true` no longer re-receives the same
65
+ ext-app shell HTML on every read. Adds a dedicated
66
+ `excalidraw-diagram-authoring.md` skill reference and folds the
67
+ freehand annotation feature into the README's main feature list.
68
+
69
+ ### Added
70
+
71
+ - **`serializeCanvasNodeForAgent` / `serializeCanvasLayoutForAgent`.**
72
+ New agent-facing serializers wrap the existing
73
+ `serializeCanvasNode` / `serializeCanvasLayout` helpers and replace
74
+ hosted ext-app shell HTML (`mcp-app` nodes in `ext-app` mode that
75
+ carry a `resourceUri`) with a `{ omitted: 'external-mcp-app-html',
76
+ resourceUri, bytes, sha256 }` descriptor. The MCP server uses
77
+ these wrappers for `canvas_get_node` (full), `canvas_get_layout`
78
+ (full), and the full-payload branch of every add-style response.
79
+ Non-external-app HTML — `html` nodes, bundled web-artifact
80
+ output — is preserved exactly as before.
81
+ - **`skills/pmx-canvas/references/excalidraw-diagram-authoring.md`.**
82
+ A 145-line authoring guide for `canvas_add_diagram` covering shape-
83
+ level `label` format, sizing and camera rules, the pastel palette,
84
+ and common pitfalls. The SKILL points to it from the diagram
85
+ guidance section.
86
+
87
+ ### Changed
88
+
89
+ - **README adds an `03 / Annotate` section.** The annotation feature
90
+ shipped in 0.1.17 is now part of the main README feature list
91
+ alongside Curate / Mix / Control / Save / Any agent. Subsequent
92
+ sections were renumbered (Control your context → 04, Save → 05,
93
+ Any agent → 06).
94
+
95
+ ### Internal
96
+
97
+ - Regression coverage for: agent-mode node serialization eliding
98
+ hosted ext-app shell HTML, agent-mode layout serialization not
99
+ repeating the ext-app shell across multiple nodes, non-external-
100
+ app HTML payloads being preserved unchanged, and `canvas_get_node`
101
+ / `canvas_get_layout` full-mode elision through the MCP server.
102
+
6
103
  ## [0.1.17] - 2026-05-04
7
104
 
8
105
  Adds a freehand annotation layer so humans can draw directly on the
@@ -727,6 +824,8 @@ otherwise have to discover by trial and error.
727
824
  - Regression coverage for snapshot flat-`id` aliases on both MCP and
728
825
  HTTP surfaces, plus async / top-level-`await` WebView script bodies.
729
826
 
827
+ [0.1.19]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.19
828
+ [0.1.18]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.18
730
829
  [0.1.17]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.17
731
830
  [0.1.16]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.16
732
831
  [0.1.15]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.15
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, and hand-drawn
5
- diagrams live side by side. Every node carries its own renderer; agents
4
+ where files, plans, status, charts, fetched web pages, annotations, and
5
+ hand-drawn 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, not as a separate
7
7
  tooling project. Pin what matters and the agent reads your spatial
8
8
  curation as structured context.
@@ -41,14 +41,21 @@ surface. The reach of the canvas is the union of its
41
41
  already has access to** — MCP servers, CLIs, file reads, web fetch, anything
42
42
  on its toolbelt.
43
43
 
44
- ### 03 / Control your context
44
+ ### 03 / Annotate
45
+
46
+ Draw freehand marks directly on the canvas to circle, underline, connect, or
47
+ call out what matters without turning the markup into another node. Annotations
48
+ persist with state and snapshots, can be erased in the browser, and appear to
49
+ agents as compact spatial context: target, bounds, and nearby canvas content.
50
+
51
+ ### 04 / Control your context
45
52
 
46
53
  Pinning is an explicit, low-noise control over what the agent sees next. No
47
54
  prompt engineering, no copy-paste — pin a node in the browser and the MCP
48
55
  server fires a `notifications/resources/updated` event the agent's harness
49
56
  picks up immediately.
50
57
 
51
- ### 04 / Save
58
+ ### 05 / Save
52
59
 
53
60
  Spatial state auto-saves to `.pmx-canvas/state.json` (debounced ~500 ms) —
54
61
  git-committable, shareable across machines, and survives both browser
@@ -56,7 +63,7 @@ refresh and server restart. Named [snapshots](docs/mcp.md#tools), full
56
63
  undo/redo, and an auto-detected code graph (JS/TS, Python, Go, Rust) make
57
64
  the canvas durable rather than throwaway.
58
65
 
59
- ### 05 / Any agent
66
+ ### 06 / Any agent
60
67
 
61
68
  Harness-agnostic. Drive the canvas from [MCP](docs/mcp.md) (41 tools,
62
69
  8 resources, change notifications), the [CLI](docs/cli.md), the
@@ -33,8 +33,10 @@ export declare function getCanvasNodeKind(node: CanvasNodeState, data: Record<st
33
33
  export declare function getCanvasNodeTitle(node: CanvasNodeState): string | null;
34
34
  export declare function getCanvasNodeContent(node: CanvasNodeState): string | null;
35
35
  export declare function serializeCanvasNode(node: CanvasNodeState): SerializedCanvasNode;
36
+ export declare function serializeCanvasNodeForAgent(node: CanvasNodeState): SerializedCanvasNode;
36
37
  export declare function serializeCanvasNodeWithBlobSummaries(node: CanvasNodeState): SerializedCanvasNode;
37
38
  export declare function serializeCanvasLayout(layout: CanvasLayout): SerializedCanvasLayout;
39
+ export declare function serializeCanvasLayoutForAgent(layout: CanvasLayout): SerializedCanvasLayout;
38
40
  export declare function serializeCanvasLayoutWithBlobSummaries(layout: CanvasLayout): SerializedCanvasLayout;
39
41
  export declare function summarizeCanvasAnnotation(annotation: CanvasAnnotation): CanvasAnnotationSummary;
40
42
  export declare function summarizeCanvasAnnotationForContext(annotation: CanvasAnnotation, nodes: CanvasNodeState[]): CanvasAnnotationContextSummary;
@@ -39,6 +39,8 @@ export interface CanvasSnapshot {
39
39
  export interface CanvasSnapshotListOptions {
40
40
  limit?: number;
41
41
  query?: string;
42
+ before?: string;
43
+ after?: string;
42
44
  all?: boolean;
43
45
  }
44
46
  export interface CanvasSnapshotGcOptions {
@@ -0,0 +1,153 @@
1
+ # Release process
2
+
3
+ Internal recipe for cutting a new `pmx-canvas` release. Lives in `docs/`
4
+ rather than the README so end-user agents and humans driving the canvas
5
+ aren't distracted by maintainer-only flow. Agents working **on** this
6
+ repo (improving the canvas itself) should treat this file as the
7
+ single source of truth for the release dance — see also
8
+ [`AGENTS.md`](../AGENTS.md) and [`CLAUDE.md`](../CLAUDE.md).
9
+
10
+ ## TL;DR
11
+
12
+ 1. Land all the changes you want in the release on `main` with green CI.
13
+ 2. Bump `package.json` `version`.
14
+ 3. Add a `## [X.Y.Z]` block to `CHANGELOG.md`.
15
+ 4. Commit, push, wait for `test.yml` green.
16
+ 5. `git tag -a vX.Y.Z -m "..." && git push origin vX.Y.Z` →
17
+ `publish.yml` runs `npm publish --access public --provenance`.
18
+ 6. `gh release create vX.Y.Z --notes-file <notes.md>`.
19
+ 7. Smoke-test the published tarball: `bunx pmx-canvas@X.Y.Z --no-open`.
20
+
21
+ ## Pre-flight gates
22
+
23
+ Run these locally before tagging. They mirror what `publish.yml`
24
+ re-runs in CI; a failure here means the publish workflow will also fail.
25
+
26
+ ```bash
27
+ bun install --frozen-lockfile
28
+ bun run typecheck
29
+ bun run build
30
+ bun test tests/unit # 200+ tests, all green
31
+ bun run test:web-canvas # Playwright E2E, all green
32
+ bun run test:e2e-cli # fresh-workspace CLI eval
33
+ bun run release:check # bundles + lints
34
+ bun run release:smoke # packs + boots from a clean dir
35
+ bun run pack:dry-run # confirms the tarball shape
36
+ ```
37
+
38
+ `bun run test:e2e-cli` starts a local server in a fresh temp workspace
39
+ and exercises the CLI flows from
40
+ [`docs/evals/e2e-cli-coverage.md`](evals/e2e-cli-coverage.md).
41
+
42
+ ## Versioning
43
+
44
+ Semantic versioning. While we are still in `0.1.x`:
45
+
46
+ - Patch (`0.1.x → 0.1.x+1`): bug fixes, hardening, internal cleanups,
47
+ additive CLI flags / MCP fields with backwards-compat fallbacks.
48
+ - Minor (`0.1.x → 0.2.0`): documented breaking changes (e.g. dropping
49
+ the `hostMode + path` fallback in `getCanvasNodeKind`, removing legacy
50
+ `ext-app-ext-app-…` ID handling, JSON-shape changes that aren't
51
+ additive).
52
+ - Major (`0.x → 1.0`): production-stability commitment.
53
+
54
+ CLAUDE.md rule #5 (CanvasStateManager / PmxCanvas SDK / HTTP / MCP
55
+ four-layer parity) is the strongest hard rule for what counts as
56
+ non-breaking — a CLI/HTTP-only addition without MCP parity has
57
+ historically required a follow-up patch release to restore parity.
58
+
59
+ ## CHANGELOG
60
+
61
+ `CHANGELOG.md` follows [Keep a Changelog](https://keepachangelog.com/).
62
+ Each release section uses these subheadings:
63
+
64
+ - **Added** — new public surface (HTTP endpoint, MCP tool/resource, CLI
65
+ command/flag, SDK export, JSON shape).
66
+ - **Changed** — behavior changes that aren't strictly bug fixes
67
+ (response shape additions, schema cleanups, stricter validation).
68
+ - **Fixed** — bug fixes.
69
+ - **Internal** — refactors, test additions, docs that don't affect
70
+ the public surface.
71
+
72
+ Don't ship a release without a CHANGELOG entry. The GitHub release
73
+ notes file (`/tmp/pmx-canvas-vX.Y.Z-release-notes.md` by convention)
74
+ expands on the CHANGELOG with examples and migration notes.
75
+
76
+ ## Tag → publish
77
+
78
+ The publish workflow ([`/.github/workflows/publish.yml`](../.github/workflows/publish.yml))
79
+ triggers on tags matching `v*`:
80
+
81
+ ```bash
82
+ git tag -a v0.1.6 -m "v0.1.6 — short summary"
83
+ git push origin v0.1.6
84
+ ```
85
+
86
+ It will:
87
+
88
+ 1. Verify the tag matches `package.json` version.
89
+ 2. Re-run typecheck / build / unit / E2E / pack.
90
+ 3. `npm publish --access public --provenance` using the `NPM_TOKEN`
91
+ secret. Provenance attestations are signed via sigstore and visible
92
+ on the npm package page.
93
+
94
+ Watch it complete:
95
+
96
+ ```bash
97
+ gh run watch
98
+ ```
99
+
100
+ If publish fails after npm has accepted the tarball, you cannot reuse
101
+ the same version number. Bump the patch and re-tag.
102
+
103
+ If this is the first release from your machine, run `bunx npm login`
104
+ once so Bun can reuse your npm credentials. CI does not need this —
105
+ it uses `NPM_TOKEN` directly.
106
+
107
+ ## GitHub release
108
+
109
+ After `npm publish` succeeds:
110
+
111
+ ```bash
112
+ gh release create v0.1.6 \
113
+ --title "pmx-canvas 0.1.6 — short theme" \
114
+ --notes-file /tmp/pmx-canvas-v0.1.6-release-notes.md \
115
+ --verify-tag
116
+ ```
117
+
118
+ `--verify-tag` makes the command fail if the local tag drifted from
119
+ the remote — a small but useful guard.
120
+
121
+ ## Smoke test from npm
122
+
123
+ ```bash
124
+ cd /tmp && rm -rf smoke && mkdir smoke && cd smoke
125
+ bunx --bun pmx-canvas@<version> --no-open --port=4926 > smoke.log &
126
+ SP=$!
127
+ for i in 1 2 3 4 5 6 7 8 9 10; do
128
+ curl -sf http://localhost:4926/health >/dev/null 2>&1 && break
129
+ sleep 1
130
+ done
131
+ curl -s http://localhost:4926/health # → {"ok":true,"workspace":"…"}
132
+ bunx pmx-canvas@<version> --version # → <version>
133
+ kill $SP
134
+ ```
135
+
136
+ If `bunx pmx-canvas@<version>` resolves and the health endpoint replies
137
+ with `ok: true`, the published tarball is intact end-to-end.
138
+
139
+ ## Common gotchas
140
+
141
+ - **`/.pmx-canvas/artifacts/.web-artifacts/sdlc-control-room/.parcel-cache/`**
142
+ files always show as modified after running an artifact build. They
143
+ are workspace-local cache and must not be committed; they're gitignored
144
+ but still appear in `git status`. Use `git restore --staged` if they
145
+ sneak into a `git add -A`.
146
+ - **`docs/screenshot.png`** updates whenever the showcase E2E runs.
147
+ Don't bake those updates into a release commit unless the screenshot
148
+ in `Readme.md` actually needs the refresh.
149
+ - **CHANGELOG dates**: use the actual publish date in the
150
+ `## [version] - YYYY-MM-DD` header, not the day you wrote the entry.
151
+ - **Node 24 deprecation timeline**: GitHub Actions is migrating
152
+ `actions/checkout`, `setup-node`, `upload-artifact` to Node 24 by
153
+ June 2, 2026. The publish workflow already pins `@v5` of all three.
@@ -0,0 +1,296 @@
1
+ # Bun.WebView Integration
2
+
3
+ PMX Canvas now uses Bun's built-in `Bun.WebView` API for **headless canvas automation**, while keeping the current external browser launcher for the normal interactive canvas window.
4
+
5
+ This document tracks:
6
+
7
+ - what is implemented today
8
+ - what was validated on stable Bun `v1.3.12`
9
+ - what still remains future work
10
+
11
+ ## Current Status
12
+
13
+ **Implemented** for Phase 1.
14
+
15
+ The repo now targets Bun `>=1.3.12`, and PMX Canvas ships an opt-in, server-owned WebView automation session that can:
16
+
17
+ - start a headless browser session for `/workbench`
18
+ - report WebView runtime status
19
+ - evaluate JavaScript in the page
20
+ - resize the automation viewport
21
+ - capture screenshots
22
+ - stop and clean up the automation session explicitly
23
+
24
+ What is **not** implemented:
25
+
26
+ - replacing `openUrlInExternalBrowser()` for the visible user-facing canvas window
27
+ - headed Bun.WebView window support
28
+ - Chrome-only CDP tooling
29
+
30
+ ## Why This Exists
31
+
32
+ The existing browser-launch path in [`src/server/server.ts`](../src/server/server.ts) still opens the interactive canvas with platform-specific shell behavior:
33
+
34
+ - macOS: AppleScript / `osascript`
35
+ - Windows: `cmd /c start` or a resolved browser executable
36
+ - Linux: `xdg-open`
37
+
38
+ That path is still appropriate for humans, but it provides no programmatic control once the browser is open.
39
+
40
+ `Bun.WebView` gives PMX Canvas a controlled browser session that the server can own directly. That unlocks:
41
+
42
+ - agent-visible screenshots
43
+ - browser-backed evaluation of rendered canvas state
44
+ - controlled viewport sizing
45
+ - future browser automation tools without depending on Playwright for the basic runtime
46
+
47
+ ## Implemented Surface
48
+
49
+ ### Server layer
50
+
51
+ Implemented in [`src/server/server.ts`](../src/server/server.ts):
52
+
53
+ - `getCanvasAutomationWebViewStatus()`
54
+ - `startCanvasAutomationWebView(url, options)`
55
+ - `stopCanvasAutomationWebView()`
56
+ - `evaluateCanvasAutomationWebView(expression)`
57
+ - `resizeCanvasAutomationWebView(width, height)`
58
+ - `screenshotCanvasAutomationWebView(options)`
59
+
60
+ Important behavior:
61
+
62
+ - runtime-gated: if `Bun.WebView` is unavailable, PMX Canvas returns a clear error
63
+ - headless-only: PMX Canvas does not rely on `headless: false`
64
+ - explicit lifecycle: start and stop are owned by the server
65
+ - screenshot normalization handles Bun return types correctly, including `Blob`
66
+
67
+ ### HTTP API
68
+
69
+ Implemented in [`src/server/server.ts`](../src/server/server.ts):
70
+
71
+ - `GET /api/workbench/webview`
72
+ - `POST /api/workbench/webview/start`
73
+ - `POST /api/workbench/webview/evaluate`
74
+ - `POST /api/workbench/webview/resize`
75
+ - `POST /api/workbench/webview/screenshot`
76
+ - `DELETE /api/workbench/webview`
77
+
78
+ Current HTTP behavior:
79
+
80
+ - `GET` returns runtime support plus active-session status
81
+ - `POST` starts a new headless automation session for the current `/workbench`
82
+ - `POST /evaluate` runs JavaScript in the active automation session and returns JSON
83
+ - `POST /resize` updates the active automation viewport and returns JSON status
84
+ - `POST /screenshot` returns image bytes for the active automation session
85
+ - `DELETE` stops the current automation session
86
+
87
+ Current options accepted by `POST /api/workbench/webview/start`:
88
+
89
+ - `backend`: `"chrome"` or `"webkit"`
90
+ - `width`
91
+ - `height`
92
+ - `chromePath`
93
+ - `chromeArgv`
94
+ - `dataStoreDir`
95
+
96
+ ### SDK
97
+
98
+ Implemented in [`src/server/index.ts`](../src/server/index.ts):
99
+
100
+ - `canvas.start({ automationWebView: ... })`
101
+ - `canvas.startAutomationWebView(options)`
102
+ - `canvas.stopAutomationWebView()`
103
+ - `canvas.getAutomationWebViewStatus()`
104
+ - `canvas.evaluateAutomationWebView(expression)`
105
+ - `canvas.resizeAutomationWebView(width, height)`
106
+ - `canvas.screenshotAutomationWebView(options)`
107
+
108
+ ### CLI
109
+
110
+ Implemented in [`src/cli/index.ts`](../src/cli/index.ts):
111
+
112
+ - `--webview-automation`
113
+ - `--webview-backend`
114
+ - `--webview-width`
115
+ - `--webview-height`
116
+ - `--webview-chrome-path`
117
+ - `--webview-chrome-argv`
118
+ - `--webview-data-dir`
119
+
120
+ Implemented in [`src/cli/agent.ts`](../src/cli/agent.ts):
121
+
122
+ - `pmx-canvas webview status`
123
+ - `pmx-canvas webview start`
124
+ - `pmx-canvas webview evaluate`
125
+ - `pmx-canvas webview resize`
126
+ - `pmx-canvas webview screenshot`
127
+ - `pmx-canvas webview stop`
128
+
129
+ Example:
130
+
131
+ ```bash
132
+ pmx-canvas --no-open --webview-automation
133
+ pmx-canvas --webview-automation --webview-backend=chrome
134
+ pmx-canvas webview start --backend chrome --width 1440 --height 900
135
+ pmx-canvas webview evaluate --expression "document.title"
136
+ pmx-canvas webview resize --width 1280 --height 800
137
+ pmx-canvas webview screenshot --output ./canvas.png
138
+ pmx-canvas webview stop
139
+ ```
140
+
141
+ These flags are intentionally automation-only. They do **not** imply a visible Bun-managed window.
142
+
143
+ ### MCP
144
+
145
+ Implemented in [`src/mcp/server.ts`](../src/mcp/server.ts):
146
+
147
+ - `canvas_webview_status`
148
+ - `canvas_webview_start`
149
+ - `canvas_webview_stop`
150
+ - `canvas_evaluate`
151
+ - `canvas_resize`
152
+ - `canvas_screenshot`
153
+
154
+ Current MCP behavior:
155
+
156
+ - automation lifecycle is explicit rather than implicit
157
+ - screenshot returns an MCP image payload plus JSON metadata
158
+ - evaluate/resize/screenshot require an active automation session
159
+ - start accepts the same backend/viewport/data-store options as the server layer
160
+
161
+ ## Backend Strategy
162
+
163
+ PMX Canvas follows Bun's current stable backend reality.
164
+
165
+ ### WebKit backend
166
+
167
+ - macOS only
168
+ - good default on macOS when CDP is not required
169
+ - zero external Chrome dependency
170
+
171
+ ### Chrome backend
172
+
173
+ - required on Linux and Windows
174
+ - also supported on macOS
175
+ - preferred when backend consistency or future CDP-based tooling matters
176
+
177
+ ### Current default behavior
178
+
179
+ PMX Canvas defaults to:
180
+
181
+ - `webkit` on macOS
182
+ - `chrome` elsewhere
183
+
184
+ If `chromePath` or `chromeArgv` is provided, PMX Canvas forces a Chrome-backed session.
185
+
186
+ ## Bun Runtime Requirements
187
+
188
+ The repo now requires:
189
+
190
+ - Bun `>=1.3.12`
191
+
192
+ That change is reflected in:
193
+
194
+ - [`package.json`](../package.json)
195
+ - [`.github/workflows/test.yml`](../.github/workflows/test.yml)
196
+
197
+ PMX Canvas still keeps a runtime guard because older local Bun versions can exist in user environments. If `Bun.WebView` is missing, startup fails cleanly for the automation path instead of partially starting.
198
+
199
+ ## Validation Results
200
+
201
+ Validated on Bun `v1.3.12`.
202
+
203
+ ### Unit coverage
204
+
205
+ Verified by tests in:
206
+
207
+ - [`tests/unit/server-api.test.ts`](../tests/unit/server-api.test.ts)
208
+ - [`tests/unit/cli-webview.test.ts`](../tests/unit/cli-webview.test.ts)
209
+ - [`tests/unit/webview-automation.test.ts`](../tests/unit/webview-automation.test.ts)
210
+
211
+ Covered behavior:
212
+
213
+ - WebView status over HTTP
214
+ - start/stop lifecycle over HTTP
215
+ - evaluate/resize/screenshot over HTTP
216
+ - CLI status/start/evaluate/resize/screenshot/stop commands
217
+ - graceful unsupported-runtime handling
218
+ - SDK start/evaluate/resize/screenshot flow
219
+
220
+ ### Live runtime smoke
221
+
222
+ Validated manually after upgrading the local runtime to Bun `1.3.12`:
223
+
224
+ - `pmx-canvas --port=4529 --no-open --webview-automation --webview-backend=chrome`
225
+ - `GET /api/workbench/webview`
226
+ - `DELETE /api/workbench/webview`
227
+ - SDK smoke with:
228
+ - `startAutomationWebView`
229
+ - `evaluateAutomationWebView('document.title')`
230
+ - `resizeAutomationWebView(...)`
231
+ - `screenshotAutomationWebView(...)`
232
+
233
+ Observed results:
234
+
235
+ - automation session started successfully
236
+ - status endpoint reported `active: true`
237
+ - JS evaluation returned `"PMX Canvas"`
238
+ - viewport resize updated status correctly
239
+ - screenshots returned non-zero image bytes on both WebKit and Chrome backends during smoke testing
240
+
241
+ ## Implementation Notes
242
+
243
+ ### Screenshot normalization bug
244
+
245
+ During real runtime validation, a bug was found in the first implementation:
246
+
247
+ - PMX Canvas assumed `view.screenshot()` returned only `Uint8Array` or `ArrayBuffer`
248
+ - on this machine, Bun could also return a `Blob`
249
+ - that caused zero-byte screenshots in the wrapper even though Bun was returning valid image data
250
+
251
+ This was fixed in [`src/server/server.ts`](../src/server/server.ts) by normalizing:
252
+
253
+ - `Uint8Array`
254
+ - `ArrayBuffer`
255
+ - `Blob`
256
+
257
+ The regression is now covered by [`tests/unit/webview-automation.test.ts`](../tests/unit/webview-automation.test.ts).
258
+
259
+ ### Why the interactive browser path still exists
260
+
261
+ Even with Bun `v1.3.12`, PMX Canvas should still keep `openUrlInExternalBrowser()` for the normal canvas window because Bun's current documented WebView surface is still effectively headless automation. There is no reason yet to promise a headed replacement window to users.
262
+
263
+ ## Known Limits
264
+
265
+ These are current, accepted constraints:
266
+
267
+ - no visible Bun-managed canvas window
268
+ - no persistent automation-session orchestration beyond the single owned server session
269
+ - no Chrome-only CDP tool surface yet
270
+
271
+ ## Future Work
272
+
273
+ ### Near-term
274
+
275
+ The most obvious next steps are:
276
+
277
+ 1. Add an optional `canvas_cdp` MCP tool for Chrome-backed sessions only
278
+ 2. Decide whether the default macOS backend should stay `webkit` or move to `chrome` for stricter cross-platform parity
279
+ 3. Add more backend-specific test coverage if Bun behavior diverges between WebKit and Chrome
280
+
281
+ ### Later
282
+
283
+ Defer these until Bun's API justifies them:
284
+
285
+ 1. Replace `openUrlInExternalBrowser()` with Bun.WebView for the normal interactive canvas window
286
+ 2. Add headed window management semantics
287
+ 3. Build user-facing browser controls around Bun.WebView if Bun documents those behaviors as stable
288
+
289
+ ## Decision Summary
290
+
291
+ The project should continue with this split:
292
+
293
+ - **Interactive canvas for humans**: external browser
294
+ - **Programmatic canvas automation for agents/server workflows**: Bun.WebView
295
+
296
+ That keeps the current user-facing behavior stable while giving PMX Canvas a real browser automation surface that is built into the runtime.