pmx-canvas 0.1.21 → 0.1.23

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,139 @@
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.23] - 2026-05-12
7
+
8
+ Persistence overhaul. Canvas state, snapshots, context pins, and the
9
+ large-payload blob store all move from filesystem JSON files into a
10
+ single SQLite database at `.pmx-canvas/canvas.db` (WAL mode). The
11
+ old `state.json`, `snapshots/`, and per-blob files are auto-imported
12
+ on first boot and renamed to `.bak`. Adds dock-aware validation and
13
+ arrange behavior, accepts the documented `?type=` query string on
14
+ node creation, and grows the schema-metadata kebab-case aliases to
15
+ include both singular and plural variants.
16
+
17
+ ### Added
18
+
19
+ - **SQLite persistence (`src/server/canvas-db.ts`, 710 lines).**
20
+ Canvas state, snapshots, context pins, and the blob sidecar
21
+ store now live in `.pmx-canvas/canvas.db` (Bun SQLite in WAL
22
+ mode). Shape preserved across the migration: nodes, edges,
23
+ annotations, viewport, context pins, history, snapshots, and
24
+ blob payloads with checksum validation.
25
+ - Override DB path: `PMX_CANVAS_DB_PATH` env var.
26
+ - Backward-compatible legacy path: `PMX_CANVAS_STATE_FILE` (if
27
+ you set a `.db` path there, it's used as the DB; if not, it's
28
+ treated as a legacy JSON path for migration).
29
+ - `stopCanvasServer()` now calls `canvasState.close()` which
30
+ checkpoints WAL data into the DB file — stop the server (or
31
+ flush/close the SDK) before committing `canvas.db`.
32
+ - SQLite WAL/SHM files (`*.db-wal`, `*.db-shm`) are gitignored;
33
+ `canvas.db` itself is git-committable.
34
+ - **Legacy migration on first boot.** Existing
35
+ `.pmx-canvas/state.json`, root `.pmx-canvas.json`,
36
+ `.pmx-canvas/snapshots/`, `.pmx-canvas-snapshots/`, and blob
37
+ files are imported into the SQLite database and renamed to
38
+ `.bak` on first start. The migration is idempotent and only
39
+ runs when the DB is empty.
40
+ - **HTTP node create accepts `?type=` query string.** `POST
41
+ /api/canvas/node?type=html-primitive` with the body's `data`
42
+ fields is accepted as an alternative to passing `type` in the
43
+ body — handy for `curl` and shell-based agents. The body form
44
+ still wins when both are present.
45
+
46
+ ### Changed
47
+
48
+ - **Docked nodes are excluded from layout collision validation.**
49
+ `validateCanvasLayout` no longer flags `dockPosition !== null`
50
+ nodes as overlap or containment violations. Docked HUD-style
51
+ nodes intentionally sit on top of canvas content; the validator
52
+ now models that.
53
+ - **Docked nodes are treated as arrange-locked.** `arrange()`
54
+ now skips translating nodes with `dockPosition !== null` along
55
+ with pinned and explicitly arrange-locked nodes. Dock geometry
56
+ is anchored to the HUD layer, not the world grid.
57
+ - **Schema kebab-case aliases include plural forms.** `--embedded-
58
+ node-ids`, `--embedded-urls`, and `--slide-titles` are now
59
+ documented aliases for the array-shaped HTML sidecar fields,
60
+ alongside the existing singular `--embedded-node-id`,
61
+ `--embedded-url`, and `--slide-title`.
62
+ - **Bun engine bumped to `>=1.3.14`.** `package.json#engines.bun`
63
+ raised from `>=1.3.12` to `>=1.3.14` to pick up the
64
+ `bun:sqlite` improvements the new persistence layer depends on.
65
+
66
+ ### Internal
67
+
68
+ - Regression coverage for: `validateCanvasLayout` ignoring docked
69
+ nodes as collision candidates, html primitive node creation
70
+ accepting the documented query-string `?type=` form, and the
71
+ existing canvas-state and operations suites continuing to pass
72
+ against the SQLite-backed persistence (including snapshot
73
+ save/restore, blob round-trip, and undo/redo history).
74
+
75
+ ## [0.1.22] - 2026-05-12
76
+
77
+ CLI ergonomics and response-size polish on top of 0.1.21. Adds a
78
+ `pmx-canvas diagram add` alias, declares kebab-case aliases for the
79
+ HTML sidecar fields in the schema, advertises those flags in `node
80
+ add --help --type html`, elides full file bodies from compact node
81
+ responses, validates presentation theme names with a clear error,
82
+ and improves keyboard focus inside present mode.
83
+
84
+ ### Added
85
+
86
+ - **`pmx-canvas diagram add` CLI alias.** A thin wrapper that
87
+ delegates to `pmx-canvas external-app add --kind excalidraw` so
88
+ diagram creation has a discoverable top-level command. The `diagram`
89
+ subcommand is now registered in `AGENT_COMMANDS` and surfaces in
90
+ `pmx-canvas --help`. The help text for `diagram add` notes the
91
+ equivalence so agents can switch between the two without guessing.
92
+ - **`node add --help --type html` advertises sidecar flags.** The
93
+ help output now includes a dedicated "HTML sidecar flags" section
94
+ listing `--summary`, `--agent-summary`, `--description`,
95
+ `--presentation true`, `--slide-title`, and `--embedded-node-id`,
96
+ matching the sidecars added in 0.1.21.
97
+ - **Kebab-case aliases for HTML sidecar fields in
98
+ `canvas_describe_schema`.** The schema entries for `agentSummary`,
99
+ `embeddedNodeIds`, `embeddedUrls`, and `slideTitles` now declare
100
+ the corresponding kebab-case flag names so agents reading the
101
+ schema discover the CLI shape without trial and error.
102
+
103
+ ### Changed
104
+
105
+ - **Compact node responses elide file content.**
106
+ `serializeCanvasNodeCompact` replaces a file node's full
107
+ `data.fileContent` with `{ omitted: 'file-content', bytes,
108
+ lineCount, sha256 }`. Agents that hit `canvas_get_node`,
109
+ `canvas_get_layout`, or batch-style responses without
110
+ `full: true` no longer re-receive the file body on every read;
111
+ the file `path` is still exposed as `content` so the node remains
112
+ fetchable.
113
+ - **Presentation theme names are validated.** Passing an invalid
114
+ `theme` (or `theme.base`) to a `presentation` primitive now
115
+ fails fast with a clear "use canvas, midnight, paper, aurora, or
116
+ a custom theme object" message instead of silently falling
117
+ through to a default. The HTTP `POST /api/canvas/node?type=html-
118
+ primitive` endpoint wraps `buildHtmlPrimitive` in a try/catch and
119
+ returns a 400 with the message.
120
+ - **Present-mode keyboard focus is tighter.** Tabbing inside the
121
+ presentation overlay now jumps to the Exit button instead of
122
+ escaping to the underlying canvas, Space and Enter on the Exit
123
+ button no longer trigger slide navigation, and the overlay
124
+ re-focuses itself when keyboard focus drifts outside. The deck
125
+ iframe loses its 18px corner radius in present mode for an
126
+ edge-to-edge fullscreen frame.
127
+
128
+ ### Internal
129
+
130
+ - Regression coverage for: `node add` forwarding HTML sidecar flags
131
+ through to the underlying html node, `node add --help --type
132
+ html` advertising the new flags, `diagram add` always invoking
133
+ the Excalidraw external app alias, `diagram` routing through the
134
+ agent CLI (not the server-startup path), presentation primitives
135
+ rejecting unknown theme names, and batch `file` node add
136
+ responses returning compact `file-content` metadata instead of
137
+ the full body.
138
+
6
139
  ## [0.1.21] - 2026-05-09
7
140
 
8
141
  HTML communication maturity pass on top of 0.1.20. Adds a
@@ -981,6 +1114,8 @@ otherwise have to discover by trial and error.
981
1114
  - Regression coverage for snapshot flat-`id` aliases on both MCP and
982
1115
  HTTP surfaces, plus async / top-level-`await` WebView script bodies.
983
1116
 
1117
+ [0.1.23]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.23
1118
+ [0.1.22]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.22
984
1119
  [0.1.21]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.21
985
1120
  [0.1.20]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.20
986
1121
  [0.1.19]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.19
package/Readme.md CHANGED
@@ -57,11 +57,12 @@ picks up immediately.
57
57
 
58
58
  ### 05 / Save
59
59
 
60
- Spatial state auto-saves to `.pmx-canvas/state.json` (debounced ~500 ms) —
60
+ Spatial state auto-saves to `.pmx-canvas/canvas.db` (debounced ~500 ms) —
61
61
  git-committable, shareable across machines, and survives both browser
62
62
  refresh and server restart. Named [snapshots](docs/mcp.md#tools), full
63
63
  undo/redo, and an auto-detected code graph (JS/TS, Python, Go, Rust) make
64
- the canvas durable rather than throwaway.
64
+ the canvas durable rather than throwaway. Stop the server before committing
65
+ the DB so SQLite WAL data is checkpointed into the file.
65
66
 
66
67
  ### 06 / Any agent
67
68
 
@@ -168,7 +169,7 @@ the agent can read `canvas://skills` and pull in companion skills
168
169
  one machine. No built-in multi-user auth or presence — collaboration means
169
170
  human ↔ agent on the same machine, plus any other browser tab/agent
170
171
  pointed at the same `localhost:4313`. To share across machines, commit
171
- `.pmx-canvas/state.json`.
172
+ `.pmx-canvas/canvas.db`.
172
173
  - **What leaves your machine.** The core canvas runs entirely on
173
174
  `localhost`. Network egress only happens for explicit, opt-in flows:
174
175
  `webpage` nodes fetch the URL you give them; `mcp-app` /
@@ -2472,75 +2472,58 @@ body,
2472
2472
  inset: 0;
2473
2473
  z-index: 10050;
2474
2474
  display: flex;
2475
- flex-direction: column;
2476
- gap: 14px;
2477
- padding: clamp(12px, 2vw, 28px);
2475
+ padding: 0;
2478
2476
  background:
2479
2477
  radial-gradient(circle at top left, var(--c-accent-25), transparent 36rem),
2480
2478
  rgba(3, 7, 18, 0.96);
2481
2479
  color: var(--c-text);
2482
2480
  }
2483
2481
 
2484
- .html-presentation-toolbar {
2485
- display: flex;
2486
- align-items: center;
2487
- justify-content: space-between;
2488
- gap: 16px;
2489
- flex-shrink: 0;
2490
- padding: 10px 12px;
2491
- border: 1px solid var(--c-line);
2492
- border-radius: 16px;
2493
- background: var(--c-panel-glass);
2494
- box-shadow: 0 18px 50px var(--c-shadow-heavy);
2495
- }
2496
-
2497
- .html-presentation-kicker {
2498
- color: var(--c-accent);
2499
- font-size: 10px;
2500
- font-weight: 800;
2501
- letter-spacing: 0.14em;
2502
- text-transform: uppercase;
2503
- }
2504
-
2505
- .html-presentation-title {
2506
- max-width: min(72vw, 900px);
2507
- overflow: hidden;
2508
- color: var(--c-text);
2509
- font-size: 14px;
2510
- font-weight: 700;
2511
- text-overflow: ellipsis;
2512
- white-space: nowrap;
2513
- }
2514
-
2515
2482
  .html-presentation-exit {
2516
- flex-shrink: 0;
2517
- padding: 8px 12px;
2483
+ position: fixed;
2484
+ top: 12px;
2485
+ right: 12px;
2486
+ z-index: 1;
2487
+ padding: 10px 14px;
2518
2488
  border: 1px solid var(--c-line);
2519
2489
  border-radius: 999px;
2520
- background: var(--c-panel-soft);
2490
+ background: var(--c-panel-glass);
2491
+ box-shadow: 0 18px 50px var(--c-shadow-heavy);
2521
2492
  color: var(--c-text-soft);
2522
2493
  cursor: pointer;
2523
2494
  font: 600 12px/1 var(--font);
2495
+ opacity: 0;
2496
+ pointer-events: none;
2497
+ transform: translateY(-6px);
2498
+ transition: opacity 0.15s ease, transform 0.15s ease, border-color 0.15s ease, color 0.15s ease;
2524
2499
  }
2525
2500
 
2526
- .html-presentation-exit:hover {
2501
+ .html-presentation-exit:hover,
2502
+ .html-presentation-exit:focus-visible {
2527
2503
  border-color: var(--c-accent);
2528
2504
  color: var(--c-text);
2529
2505
  }
2530
2506
 
2507
+ .html-presentation-exit:focus,
2508
+ .html-presentation-exit:focus-visible {
2509
+ opacity: 1;
2510
+ pointer-events: auto;
2511
+ transform: translateY(0);
2512
+ }
2513
+
2531
2514
  .html-presentation-stage {
2532
2515
  flex: 1;
2533
2516
  min-height: 0;
2534
2517
  display: flex;
2535
- border-radius: 22px;
2518
+ border-radius: 0;
2536
2519
  background: var(--c-bg);
2537
- box-shadow: 0 24px 90px rgba(0, 0, 0, 0.55);
2538
2520
  overflow: hidden;
2539
2521
  }
2540
2522
 
2541
2523
  .html-node-frame-presentation {
2542
2524
  flex: 1;
2543
2525
  min-height: 0;
2526
+ border-radius: 0 !important;
2544
2527
  }
2545
2528
 
2546
2529
  /* ── Context pin button on node title bar ────────────────────── */