pmx-canvas 0.1.30 → 0.1.32

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 (43) hide show
  1. package/CHANGELOG.md +117 -0
  2. package/dist/canvas/global.css +56 -59
  3. package/dist/canvas/index.js +59 -59
  4. package/dist/json-render/index.js +97 -97
  5. package/dist/types/client/nodes/surface-url.d.ts +7 -0
  6. package/dist/types/client/state/canvas-store.d.ts +1 -0
  7. package/dist/types/client/state/intent-bridge.d.ts +7 -0
  8. package/dist/types/json-render/renderer/index.d.ts +1 -0
  9. package/dist/types/json-render/server.d.ts +1 -0
  10. package/dist/types/server/ax-context.d.ts +24 -1
  11. package/dist/types/server/canvas-state.d.ts +7 -0
  12. package/dist/types/server/html-surface.d.ts +29 -0
  13. package/dist/types/server/index.d.ts +19 -3
  14. package/dist/types/server/server.d.ts +12 -0
  15. package/docs/sdk.md +3 -1
  16. package/package.json +1 -1
  17. package/skills/pmx-canvas/SKILL.md +96 -1
  18. package/src/cli/agent.ts +18 -1
  19. package/src/cli/index.ts +8 -1
  20. package/src/client/App.tsx +3 -3
  21. package/src/client/canvas/CanvasNode.tsx +16 -1
  22. package/src/client/canvas/DockedNode.tsx +38 -38
  23. package/src/client/canvas/ExpandedNodeOverlay.tsx +12 -1
  24. package/src/client/nodes/ContextNode.tsx +1 -1
  25. package/src/client/nodes/HtmlNode.tsx +26 -1
  26. package/src/client/nodes/McpAppNode.tsx +35 -8
  27. package/src/client/nodes/StatusNode.tsx +0 -20
  28. package/src/client/nodes/surface-url.ts +12 -0
  29. package/src/client/state/canvas-store.ts +4 -0
  30. package/src/client/state/intent-bridge.ts +19 -0
  31. package/src/client/state/sse-bridge.ts +17 -0
  32. package/src/client/theme/global.css +56 -59
  33. package/src/json-render/renderer/index.tsx +31 -2
  34. package/src/json-render/server.ts +3 -0
  35. package/src/mcp/canvas-access.ts +6 -1
  36. package/src/mcp/server.ts +23 -1
  37. package/src/server/ax-context.ts +49 -1
  38. package/src/server/ax-interaction.ts +3 -0
  39. package/src/server/ax-state.ts +3 -1
  40. package/src/server/canvas-state.ts +30 -11
  41. package/src/server/html-surface.ts +70 -13
  42. package/src/server/index.ts +32 -7
  43. package/src/server/server.ts +117 -4
package/CHANGELOG.md CHANGED
@@ -3,6 +3,121 @@
3
3
  All notable changes to `pmx-canvas` are documented here. This project follows
4
4
  [Semantic Versioning](https://semver.org/).
5
5
 
6
+ ## [Unreleased]
7
+
8
+ ## [0.1.32] - 2026-06-07
9
+
10
+ ### Added
11
+
12
+ - **Composable AX surfaces (emit + reflect).** AX-enabled `html`, `json-render`,
13
+ and `web-artifact` nodes can now both EMIT AX interactions and RENDER live AX
14
+ state, so an agent (or human) can build an interactive work board / review board
15
+ / inbox as a canvas node. The canvas seeds each surface with a compact AX
16
+ snapshot and pushes live updates over the existing nonce-validated postMessage
17
+ channel: `html` exposes `window.PMX_AX.state` + a `pmx-ax-update` event;
18
+ `json-render` binds the snapshot under `/ax` (e.g. `{ "$state": "/ax/workItems" }`);
19
+ `web-artifact` gets the same `window.PMX_AX` bridge injected at the `/artifact`
20
+ route. New `GET /api/canvas/ax/surface-snapshot`. See the "Building an AX
21
+ surface" section in the pmx-canvas skill.
22
+ - **AX opt-in via MCP/SDK (report #42).** `canvas_add_html_node` and
23
+ `canvas_update_node` accept an `axCapabilities` parameter ({ enabled, allowed })
24
+ so an agent can turn an html node into an AX surface without hand-crafting raw
25
+ HTTP — the previously-missing opt-in that made the (already-working) AX bridge
26
+ look broken. Clamped to the node-type ceiling server-side; cannot escalate.
27
+ (#42 was not a missing listener — the emit bridge + listeners already existed
28
+ and are e2e-verified.)
29
+ - **Open in system browser.** A node-header / expanded-overlay "Open in system
30
+ browser" action (and `POST /api/canvas/open-external`) opens a node's surface in
31
+ the real OS browser via the existing launcher — for hosts (e.g. Codex) whose
32
+ embedded browser makes a normal new tab feel in-place. Accepts only `{ nodeId }`
33
+ (opens this server's own surface URL — no arbitrary-URL launch), honors
34
+ `PMX_CANVAS_DISABLE_BROWSER_OPEN`, and falls back to a normal new tab.
35
+
36
+ ### Changed
37
+
38
+ - **Responsive top HUD (report #41).** The toolbar + docked status/context pills
39
+ now wrap instead of clipping in narrow embedding panels (e.g. the Copilot side
40
+ panel); low-value text (session id, zoom %, counts) is hidden below ~720px.
41
+
42
+ ### Fixed
43
+
44
+ - **Body-only review annotations succeed (report #39).** `ax.review.add` /
45
+ `canvas_add_review_annotation` with only a `body` (no `anchorType`, no `nodeId`)
46
+ now creates an unanchored note instead of returning 400 — `anchorType` defaults
47
+ to a node anchor only when a usable `nodeId` is present. An explicit bad node
48
+ anchor still rejects.
49
+ - **CLI can undock a node (report #40).** `pmx-canvas node update --dock-position
50
+ left|right|none` docks/undocks a node (`none` → `null`). The previous
51
+ `--data '{"dockPosition":null}'` never worked because `--data` is reserved for
52
+ graph datasets; the CLI had no path mapping it to the top-level field.
53
+
54
+ ### Removed
55
+
56
+ - **Status node "Track as work" button.** Tracking a status signal as a work item
57
+ produced a thin, auto-titled item (often just "idle") with no visible effect on
58
+ the board and no proactive agent reaction — confusing UI for little value. The
59
+ underlying AX work-item primitive (`ax.work.create`) is unchanged and still
60
+ available to agents, the SDK/MCP/HTTP API, and authored AX surfaces
61
+ (json-render/HTML bridges) — the better home for a deliberate, in-canvas
62
+ work-item/steering experience.
63
+
64
+ ## [0.1.31] - 2026-06-07
65
+
66
+ ### Added
67
+
68
+ - **Default docked status + context widgets.** A freshly opened canvas now shows
69
+ the agent's status widget docked at the left of the top menu and the context
70
+ widget docked at the right — flanking the toolbar as one continuous bar at the
71
+ same height. They are the same `status-main` / `context-main` nodes the
72
+ agent-event path already creates, just present from the start. Each collapsed
73
+ widget has an expand (▸) and an undock (⊙) control; undocking returns it to the
74
+ canvas as a normal node. Seeded **once on first run** (brand-new workspace
75
+ only) — never added to a canvas that already has content, and deleting or
76
+ undocking them is remembered (they are not re-seeded). `--demo` is unaffected
77
+ (it seeds the demo board instead).
78
+
79
+ ### Changed
80
+
81
+ - **Collapsed docked widgets match the toolbar height.** The collapsed context
82
+ widget now renders inline in the top HUD row (mirroring the status widget)
83
+ instead of as a separate right-edge side-tab, and a shared `--hud-bar-height`
84
+ keeps the toolbar and both docked pills at an identical height.
85
+
86
+ ### Fixed
87
+
88
+ - **Context nodes can be undocked.** Previously a `context` node was re-forced to
89
+ `dockPosition: 'right'` on every write, so it could never leave the dock. The
90
+ right-docked collapsed default is now applied at create time only; updates
91
+ (including undock → `dockPosition: null`) are respected.
92
+
93
+ - **SDK node-response parity (report #31/#32).** `PmxCanvas.addNode`, `getNode`,
94
+ and `addHtmlNode` now return the fully serialized node enriched with a
95
+ `surfaceUrl` (for surface-eligible types) and a `nodeId` alias for `id`,
96
+ matching the HTTP/CLI `node`-create responses field-for-field. `addHtmlNode`
97
+ now returns the created node object instead of a bare id string (consistent
98
+ with `addNode`); read `.id` if you only need the identifier. The internal
99
+ `CanvasAccess` contract is unchanged (still returns a bare id).
100
+
101
+ - **HTML "Open as site" tab title (report #35).** The standalone surface document
102
+ for an `html` node now carries a `<title>` (the node title) when the author
103
+ HTML does not already declare one, so the browser tab shows the node title
104
+ instead of falling back to the raw `/api/canvas/surface/<id>` URL. An
105
+ author-provided `<title>` is never overridden, and the injected title is
106
+ HTML-escaped.
107
+
108
+ ### Notes
109
+
110
+ - **Report #33/#34/#36 — not reproduced.** #33 (elicitation/mode immediate
111
+ resolve) and #34 (delivery "claim" route) were already closed by the tester's
112
+ Codex retest as wrong-route repros. #36 (CLI emitting invalid JSON for html
113
+ primitives) does not reproduce: all 19 primitive kinds return valid JSON
114
+ through both `pmx-canvas html primitive add | jq` and raw `curl | jq`, with
115
+ zero unescaped control characters — the CLI re-serializes via `JSON.stringify`
116
+ and the server uses `Response.json`, both of which always escape U+0000–U+001F.
117
+ The full rendered HTML body is intentionally retained in the create response
118
+ (it is relied upon by consumers and renderer tests; agents wanting a compact
119
+ payload can use the MCP tool, which is already compact by default).
120
+
6
121
  ## [0.1.30] - 2026-06-07
7
122
 
8
123
  ### Added
@@ -1575,6 +1690,8 @@ otherwise have to discover by trial and error.
1575
1690
  - Regression coverage for snapshot flat-`id` aliases on both MCP and
1576
1691
  HTTP surfaces, plus async / top-level-`await` WebView script bodies.
1577
1692
 
1693
+ [0.1.32]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.32
1694
+ [0.1.31]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.31
1578
1695
  [0.1.30]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.30
1579
1696
  [0.1.29]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.29
1580
1697
  [0.1.28]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.28
@@ -56,6 +56,10 @@
56
56
  --mono: "IBM Plex Mono", "SF Mono", "Fira Code", monospace;
57
57
  --radius: 10px;
58
58
  --radius-sm: 6px;
59
+ /* Shared height for the top HUD row so the toolbar and the collapsed docked
60
+ status/context widgets that flank it line up to the same height. Matches the
61
+ toolbar's natural content height (icon buttons at 6px padding). */
62
+ --hud-bar-height: 44px;
59
63
  }
60
64
 
61
65
  :root[data-theme="light"] {
@@ -453,13 +457,15 @@ body,
453
457
  font-weight: 600;
454
458
  }
455
459
 
456
- /* HUD layer — fixed row: [left-dock] [toolbar] [right-dock] */
460
+ /* HUD layer — [left-dock] [toolbar] [right-dock]. Wraps onto multiple rows in a
461
+ narrow embedding panel (e.g. the Copilot side panel) instead of clipping. */
457
462
  .hud-layer {
458
463
  position: fixed;
459
464
  top: 12px;
460
465
  left: 12px;
461
466
  right: 12px;
462
467
  display: flex;
468
+ flex-wrap: wrap;
463
469
  align-items: flex-start;
464
470
  justify-content: center;
465
471
  gap: 8px;
@@ -472,20 +478,24 @@ body,
472
478
  .hud-left,
473
479
  .hud-right {
474
480
  display: flex;
481
+ flex-wrap: wrap;
475
482
  gap: 8px;
476
483
  }
477
484
 
478
485
  /* Toolbar */
479
486
  .canvas-toolbar {
480
487
  display: flex;
488
+ flex-wrap: wrap;
481
489
  align-items: center;
482
490
  gap: 6px;
483
491
  padding: 6px 10px;
492
+ min-height: var(--hud-bar-height);
493
+ max-width: 100%;
494
+ box-sizing: border-box;
484
495
  background: var(--c-panel-glass);
485
496
  backdrop-filter: blur(12px);
486
497
  border: 1px solid var(--c-line);
487
498
  border-radius: var(--radius);
488
- flex-shrink: 0;
489
499
  }
490
500
 
491
501
  .toolbar-tooltip-anchor {
@@ -660,9 +670,11 @@ body,
660
670
 
661
671
  .toolbar-group {
662
672
  display: flex;
673
+ flex-wrap: wrap;
663
674
  align-items: center;
664
675
  gap: 6px;
665
- flex-shrink: 0;
676
+ min-width: 0;
677
+ max-width: 100%;
666
678
  }
667
679
 
668
680
  .canvas-toolbar button svg {
@@ -686,6 +698,15 @@ body,
686
698
  }
687
699
  }
688
700
 
701
+ /* Narrow embedding panels: drop low-value text from the HUD so the icon controls
702
+ fit in fewer rows. Buttons keep their aria-labels + tooltips, so nothing is
703
+ lost for a11y or discovery. */
704
+ @media (max-width: 720px) {
705
+ .hud-collapsible-text {
706
+ display: none;
707
+ }
708
+ }
709
+
689
710
  /* Raw markdown source editor */
690
711
  .md-editor-split {
691
712
  display: flex;
@@ -1409,6 +1430,38 @@ html.is-node-resizing .ext-app-preview-catcher {
1409
1430
  max-width: 320px;
1410
1431
  }
1411
1432
 
1433
+ /* Collapsed docked widget = a single menu-height pill that flanks the toolbar.
1434
+ Pinned to the same height as .canvas-toolbar so the top HUD row reads as one
1435
+ continuous bar (status on the left, context on the right). */
1436
+ .docked-node--collapsed {
1437
+ height: var(--hud-bar-height);
1438
+ box-sizing: border-box;
1439
+ justify-content: center;
1440
+ width: auto;
1441
+ /* Reset the base .docked-node min-width so the collapsed pill hugs its content
1442
+ (badge + count + controls) instead of stretching to a 200px bar. */
1443
+ min-width: 0;
1444
+ }
1445
+ .docked-node--collapsed .docked-node-header {
1446
+ height: 100%;
1447
+ padding: 0 10px;
1448
+ border-bottom: none;
1449
+ }
1450
+ .docked-node-count {
1451
+ min-width: 18px;
1452
+ height: 18px;
1453
+ padding: 0 5px;
1454
+ display: inline-flex;
1455
+ align-items: center;
1456
+ justify-content: center;
1457
+ border-radius: 9px;
1458
+ background: var(--c-accent);
1459
+ color: var(--c-contrast-fg);
1460
+ font-size: 10px;
1461
+ font-weight: 700;
1462
+ flex-shrink: 0;
1463
+ }
1464
+
1412
1465
  .docked-node-header {
1413
1466
  display: flex;
1414
1467
  align-items: center;
@@ -1948,62 +2001,6 @@ html.is-node-resizing .ext-app-preview-catcher {
1948
2001
  max-width: 200px;
1949
2002
  }
1950
2003
 
1951
- /* Context dock — collapsed pill mirrors Updates pill, sits above it */
1952
- .context-dock-tab {
1953
- position: fixed;
1954
- top: 92px;
1955
- right: 0;
1956
- display: flex;
1957
- align-items: center;
1958
- gap: 8px;
1959
- padding: 8px 12px 8px 14px;
1960
- background: color-mix(in srgb, var(--c-panel-glass) 96%, transparent);
1961
- backdrop-filter: blur(16px);
1962
- border: 1px solid color-mix(in srgb, var(--c-line) 82%, var(--c-accent) 18%);
1963
- border-right: 0;
1964
- border-radius: 14px 0 0 14px;
1965
- box-shadow: 0 12px 36px var(--c-shadow);
1966
- color: var(--c-text);
1967
- cursor: pointer;
1968
- font: inherit;
1969
- font-size: 11px;
1970
- font-weight: 600;
1971
- letter-spacing: 0.08em;
1972
- text-transform: uppercase;
1973
- z-index: 60;
1974
- }
1975
-
1976
- .context-dock-tab:hover {
1977
- border-color: color-mix(in srgb, var(--c-accent) 40%, var(--c-line) 60%);
1978
- color: var(--c-accent);
1979
- }
1980
-
1981
- .context-dock-tab svg {
1982
- display: block;
1983
- color: var(--c-accent);
1984
- flex-shrink: 0;
1985
- }
1986
-
1987
- .context-dock-tab-label {
1988
- white-space: nowrap;
1989
- }
1990
-
1991
- .context-dock-tab-badge {
1992
- min-width: 18px;
1993
- height: 18px;
1994
- padding: 0 5px;
1995
- display: inline-flex;
1996
- align-items: center;
1997
- justify-content: center;
1998
- border-radius: 9px;
1999
- background: var(--c-accent);
2000
- color: var(--c-contrast-fg);
2001
- font-size: 10px;
2002
- font-weight: 700;
2003
- letter-spacing: 0;
2004
- text-transform: none;
2005
- }
2006
-
2007
2004
  /* Context dock — expanded panel anchored top-right edge.
2008
2005
  Mutually exclusive with the Updates panel (see DockedNode.tsx and
2009
2006
  AttentionHistory.tsx) — opening one collapses the other, so they can both