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.
- package/CHANGELOG.md +117 -0
- package/dist/canvas/global.css +56 -59
- package/dist/canvas/index.js +59 -59
- package/dist/json-render/index.js +97 -97
- package/dist/types/client/nodes/surface-url.d.ts +7 -0
- package/dist/types/client/state/canvas-store.d.ts +1 -0
- package/dist/types/client/state/intent-bridge.d.ts +7 -0
- package/dist/types/json-render/renderer/index.d.ts +1 -0
- package/dist/types/json-render/server.d.ts +1 -0
- package/dist/types/server/ax-context.d.ts +24 -1
- package/dist/types/server/canvas-state.d.ts +7 -0
- package/dist/types/server/html-surface.d.ts +29 -0
- package/dist/types/server/index.d.ts +19 -3
- package/dist/types/server/server.d.ts +12 -0
- package/docs/sdk.md +3 -1
- package/package.json +1 -1
- package/skills/pmx-canvas/SKILL.md +96 -1
- package/src/cli/agent.ts +18 -1
- package/src/cli/index.ts +8 -1
- package/src/client/App.tsx +3 -3
- package/src/client/canvas/CanvasNode.tsx +16 -1
- package/src/client/canvas/DockedNode.tsx +38 -38
- package/src/client/canvas/ExpandedNodeOverlay.tsx +12 -1
- package/src/client/nodes/ContextNode.tsx +1 -1
- package/src/client/nodes/HtmlNode.tsx +26 -1
- package/src/client/nodes/McpAppNode.tsx +35 -8
- package/src/client/nodes/StatusNode.tsx +0 -20
- package/src/client/nodes/surface-url.ts +12 -0
- package/src/client/state/canvas-store.ts +4 -0
- package/src/client/state/intent-bridge.ts +19 -0
- package/src/client/state/sse-bridge.ts +17 -0
- package/src/client/theme/global.css +56 -59
- package/src/json-render/renderer/index.tsx +31 -2
- package/src/json-render/server.ts +3 -0
- package/src/mcp/canvas-access.ts +6 -1
- package/src/mcp/server.ts +23 -1
- package/src/server/ax-context.ts +49 -1
- package/src/server/ax-interaction.ts +3 -0
- package/src/server/ax-state.ts +3 -1
- package/src/server/canvas-state.ts +30 -11
- package/src/server/html-surface.ts +70 -13
- package/src/server/index.ts +32 -7
- 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
|
package/dist/canvas/global.css
CHANGED
|
@@ -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 —
|
|
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
|
-
|
|
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
|