pmx-canvas 0.1.15 → 0.1.17

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/Readme.md +2 -2
  3. package/dist/canvas/global.css +25 -0
  4. package/dist/canvas/index.js +72 -72
  5. package/dist/types/client/canvas/AnnotationLayer.d.ts +4 -0
  6. package/dist/types/client/canvas/CanvasViewport.d.ts +4 -1
  7. package/dist/types/client/canvas/use-pan-zoom.d.ts +2 -1
  8. package/dist/types/client/icons.d.ts +4 -0
  9. package/dist/types/client/nodes/ContextNode.d.ts +11 -2
  10. package/dist/types/client/nodes/StatusNode.d.ts +1 -0
  11. package/dist/types/client/state/canvas-store.d.ts +22 -3
  12. package/dist/types/client/state/intent-bridge.d.ts +2 -0
  13. package/dist/types/client/types.d.ts +20 -0
  14. package/dist/types/mcp/canvas-access.d.ts +1 -0
  15. package/dist/types/server/canvas-serialization.d.ts +23 -1
  16. package/dist/types/server/canvas-state.d.ts +27 -1
  17. package/dist/types/server/index.d.ts +7 -2
  18. package/dist/types/server/mutation-history.d.ts +1 -1
  19. package/dist/types/server/spatial-analysis.d.ts +11 -2
  20. package/package.json +1 -1
  21. package/skills/pmx-canvas/SKILL.md +17 -0
  22. package/src/cli/agent.ts +6 -0
  23. package/src/client/App.tsx +60 -3
  24. package/src/client/canvas/AnnotationLayer.tsx +28 -0
  25. package/src/client/canvas/CanvasViewport.tsx +169 -10
  26. package/src/client/canvas/ContextPinBar.tsx +3 -1
  27. package/src/client/canvas/DockedNode.tsx +4 -3
  28. package/src/client/canvas/use-pan-zoom.ts +10 -5
  29. package/src/client/icons.tsx +22 -0
  30. package/src/client/nodes/ContextNode.tsx +128 -6
  31. package/src/client/nodes/StatusNode.tsx +16 -1
  32. package/src/client/nodes/StatusSummary.tsx +2 -1
  33. package/src/client/state/canvas-store.ts +65 -7
  34. package/src/client/state/intent-bridge.ts +5 -1
  35. package/src/client/state/sse-bridge.ts +36 -2
  36. package/src/client/theme/global.css +25 -0
  37. package/src/client/types.ts +17 -0
  38. package/src/mcp/canvas-access.ts +10 -0
  39. package/src/mcp/server.ts +35 -4
  40. package/src/server/canvas-schema.ts +25 -0
  41. package/src/server/canvas-serialization.ts +69 -1
  42. package/src/server/canvas-state.ts +74 -2
  43. package/src/server/diagram-presets.ts +54 -19
  44. package/src/server/index.ts +20 -3
  45. package/src/server/mutation-history.ts +2 -0
  46. package/src/server/server.ts +101 -3
  47. package/src/server/spatial-analysis.ts +46 -1
  48. package/src/shared/semantic-attention.ts +4 -2
package/CHANGELOG.md CHANGED
@@ -3,6 +3,128 @@
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.17] - 2026-05-04
7
+
8
+ Adds a freehand annotation layer so humans can draw directly on the
9
+ canvas and agents read compact spatial annotation context (bounds,
10
+ target nodes, optional label) without seeing the raw ink. Excalidraw
11
+ bound-text → label hoisting now covers the full set of canonical and
12
+ shorthand shapes the hosted app emits, and the `html` node type gets
13
+ its first-class entry in `canvas_describe_schema` plus a CLI
14
+ `--content` alias that maps to `data.html`.
15
+
16
+ ### Added
17
+
18
+ - **Freehand canvas annotations.** A new top-level annotation layer
19
+ lets humans draw freehand strokes on the canvas with pen and
20
+ eraser tools wired into the toolbar. Annotations live alongside
21
+ nodes and edges in `canvasState` (their own `addAnnotation` /
22
+ `removeAnnotation` history operations), persist into snapshots,
23
+ and are rendered as SVG paths whose default `currentColor` stroke
24
+ follows the active theme via a new `--c-annotation` token.
25
+ Surfaces:
26
+ - HTTP: `POST /api/canvas/annotation`, `DELETE
27
+ /api/canvas/annotation/:id`.
28
+ - MCP: `canvas_remove_annotation` (the canvas now exposes 41 MCP
29
+ tools, was 40).
30
+ - Client: pen / eraser toolbar buttons with theme-aware iconography
31
+ and an `AnnotationLayer` that renders the strokes.
32
+ - **Spatial annotation context for agents.** Each pinned-context /
33
+ spatial-context read now includes a compact
34
+ `SpatialAnnotationContext` per annotation: `id`, `label`,
35
+ `bounds`, `targetNodeIds`, `targetNodeTitles`, and `target`
36
+ summary. Agents see what the annotation *circles* (which nodes it
37
+ overlaps), not the freehand path itself, keeping the read budget
38
+ small while still letting the agent act on the human's intent.
39
+ - **HTML node schema entry in `canvas_describe_schema`.** The `html`
40
+ node type added in 0.1.15 now appears in the schema tour with a
41
+ documented `html` field, `--content` / `--stdin` aliases, the
42
+ sandboxed-iframe note, and an example payload.
43
+ - **CLI `--content` alias for HTML nodes.** `pmx-canvas node add
44
+ --type html --content '<main>Hello</main>'` is accepted as a
45
+ shorthand for setting `data.html` (also supported via `--stdin`).
46
+
47
+ ### Changed
48
+
49
+ - **Excalidraw bound-text → container label hoisting now covers
50
+ every canonical shape.** The diagram preset
51
+ (`normalizeExcalidrawElementsForToolInput`) hoists text into a
52
+ `rectangle` / `ellipse` / `diamond` container's `label` for all
53
+ four patterns the hosted app emits: the canonical
54
+ `containerId`-pointing text, the centered-container variant,
55
+ pre-existing shorthand labels (preserved as-is), and the
56
+ `boundElements`-only path where the text lacks a back-reference.
57
+ Text alignment and vertical-alignment hints are forwarded into
58
+ the label when present.
59
+
60
+ ### Internal
61
+
62
+ - Regression coverage for: annotation persistence and removal in
63
+ `canvasState`, annotation undo/redo history operations,
64
+ annotation create/delete over HTTP, html-content CLI alias
65
+ mapping, all four Excalidraw bound-text patterns, html node
66
+ rendering from server state in the browser (e2e), annotation
67
+ theme contrast plus eraser flow (e2e), and annotation toolbar
68
+ actions preserving the active light theme (e2e).
69
+
70
+ ## [0.1.16] - 2026-05-04
71
+
72
+ Live-context-dock and undo-history hygiene pass on top of 0.1.15. The
73
+ context dock now renders the actual pinned nodes instead of falling back
74
+ to stale context-card data, auto-focus from ext-app opens stops
75
+ polluting undo history, and a couple of HTTP endpoints reject malformed
76
+ payloads instead of creating blank or empty nodes.
77
+
78
+ ### Added
79
+
80
+ - **`ContextNode` renders the active pinned nodes.** A new exported
81
+ `normalizePinnedContextDisplay()` produces a stable `{id, title,
82
+ summary, kind, path}` shape per pinned node, and the component now
83
+ takes a `pinnedNodes` prop. The dock falls back to the previous
84
+ context-card data only when no nodes are pinned, so what the agent
85
+ reads via `canvas://pinned-context` and what the human sees in the
86
+ dock are now the same view.
87
+ - **`StatusNode` exposes `getStatusDisplayPhase()` with a documented
88
+ fallback chain.** The display phase falls back `phase → content
89
+ → status → 'idle'` and is shared by the inline node, the summary,
90
+ and any consumer that needs the phase shown to the user.
91
+
92
+ ### Changed
93
+
94
+ - **`ContextPinBar` is mutually exclusive with the Updates panel.**
95
+ Like the docked context node, the floating pin bar now hides while
96
+ the right-edge attention history panel is open so the two surfaces
97
+ no longer collide on the same anchor.
98
+ - **Browser-driven viewport updates support `recordHistory: false`.**
99
+ Client `focusNode(id, options)` and the matching
100
+ `commitViewportWithOptions()` thread an optional
101
+ `{ recordHistory: false }` flag through to `POST
102
+ /api/canvas/viewport`, which now wraps the mutation in
103
+ `withSuppressedRecording` when the flag is set. Auto-focus
104
+ triggered by ext-app opens uses this path so opening an external
105
+ app no longer fills undo history with viewport churn.
106
+
107
+ ### Fixed
108
+
109
+ - **HTML nodes reject non-string `html` payloads.** `POST
110
+ /api/canvas/node` and the matching MCP path now return a 400
111
+ with a clear error when an html node is created with `html` (or
112
+ `data.html`) set to a non-string value, instead of accepting the
113
+ payload and producing a blank node.
114
+ - **Group creation rejects missing child IDs.** `POST
115
+ /api/canvas/group` (and `canvas_create_group`) no longer silently
116
+ creates an empty group when one or more of the requested children
117
+ do not exist; it returns a 400 listing the missing IDs.
118
+
119
+ ### Internal
120
+
121
+ - Regression coverage for: client status-node display-phase fallback,
122
+ ext-app auto-focus history suppression on the client side, the
123
+ context dock rendering pinned nodes (e2e), HTML-node payload type
124
+ validation over HTTP, group-create child-presence validation over
125
+ HTTP, and the `recordHistory: false` flag on the viewport
126
+ endpoint.
127
+
6
128
  ## [0.1.15] - 2026-05-03
7
129
 
8
130
  A bigger release focused on right-sizing what flows through MCP and the
@@ -605,6 +727,8 @@ otherwise have to discover by trial and error.
605
727
  - Regression coverage for snapshot flat-`id` aliases on both MCP and
606
728
  HTTP surfaces, plus async / top-level-`await` WebView script bodies.
607
729
 
730
+ [0.1.17]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.17
731
+ [0.1.16]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.16
608
732
  [0.1.15]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.15
609
733
  [0.1.14]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.14
610
734
  [0.1.13]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.13
package/Readme.md CHANGED
@@ -58,7 +58,7 @@ the canvas durable rather than throwaway.
58
58
 
59
59
  ### 05 / Any agent
60
60
 
61
- Harness-agnostic. Drive the canvas from [MCP](docs/mcp.md) (40 tools,
61
+ Harness-agnostic. Drive the canvas from [MCP](docs/mcp.md) (41 tools,
62
62
  8 resources, change notifications), the [CLI](docs/cli.md), the
63
63
  [HTTP API](docs/http-api.md), or the [Bun SDK](docs/sdk.md). Works with
64
64
  Claude Code, GitHub Copilot CLI, Codex, Cursor, Windsurf, or any agent
@@ -136,7 +136,7 @@ the agent can read `canvas://skills` and pull in companion skills
136
136
  the three-tier visual matrix (json-render → html → web-artifact)
137
137
  - **[CLI reference](docs/cli.md)** — full command surface, daemon mode,
138
138
  watch streams, WebView automation
139
- - **[MCP reference](docs/mcp.md)** — 40 tools, 8 resources, change
139
+ - **[MCP reference](docs/mcp.md)** — 41 tools, 8 resources, change
140
140
  notifications, node-type routing
141
141
  - **[HTTP API](docs/http-api.md)** — REST endpoints, SSE, batch operations
142
142
  - **[Bun SDK](docs/sdk.md)** — `createCanvas()` for TypeScript on Bun
@@ -50,6 +50,7 @@
50
50
  --c-accent-hover: #6ECAFF;
51
51
  --c-warn-hover: #f5d06b;
52
52
  --c-canvas-wash: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(0, 0, 0, 0));
53
+ --c-annotation: #F4EFE6;
53
54
  /* ── Non-color tokens ────────────────────────────────────── */
54
55
  --font: "IBM Plex Sans", "SF Pro Text", "Avenir Next", system-ui, sans-serif;
55
56
  --mono: "IBM Plex Mono", "SF Mono", "Fira Code", monospace;
@@ -109,6 +110,7 @@
109
110
  --c-accent-hover: #1588CE;
110
111
  --c-warn-hover: #dab040;
111
112
  --c-canvas-wash: linear-gradient(180deg, rgba(255, 255, 255, 0.12), rgba(8, 21, 36, 0.02));
113
+ --c-annotation: #081524;
112
114
  }
113
115
 
114
116
  :root[data-theme="high-contrast"] {
@@ -162,6 +164,7 @@
162
164
  --c-accent-hover: #33ffff;
163
165
  --c-warn-hover: #ffff33;
164
166
  --c-canvas-wash: linear-gradient(180deg, rgba(255, 255, 255, 0.03), rgba(255, 255, 255, 0));
167
+ --c-annotation: #ffff00;
165
168
  }
166
169
 
167
170
  * {
@@ -1471,6 +1474,28 @@ body,
1471
1474
  z-index: 9998;
1472
1475
  }
1473
1476
 
1477
+ .annotation-layer {
1478
+ position: absolute;
1479
+ inset: 0;
1480
+ width: 1px;
1481
+ height: 1px;
1482
+ overflow: visible;
1483
+ pointer-events: none;
1484
+ z-index: 45;
1485
+ }
1486
+
1487
+ .annotation-capture-layer {
1488
+ position: absolute;
1489
+ inset: 0;
1490
+ z-index: 9996;
1491
+ pointer-events: none;
1492
+ background: color-mix(in srgb, var(--c-accent) 5%, transparent);
1493
+ }
1494
+
1495
+ .annotation-capture-layer.erasing {
1496
+ background: color-mix(in srgb, var(--c-danger) 6%, transparent);
1497
+ }
1498
+
1474
1499
  /* ── Drop Zone (file drag-and-drop) ─────────────────────────── */
1475
1500
  .drop-zone-overlay {
1476
1501
  position: absolute;