pmx-canvas 0.1.25 → 0.1.26
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 +42 -0
- package/dist/types/server/index.d.ts +4 -0
- package/package.json +1 -1
- package/skills/pmx-canvas/SKILL.md +13 -0
- package/src/mcp/server.ts +4 -0
- package/src/server/index.ts +16 -0
- package/src/server/server.ts +9 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,47 @@
|
|
|
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.26] - 2026-06-03
|
|
7
|
+
|
|
8
|
+
Small follow-up to 0.1.25. `canvas_add_node` can now create populated
|
|
9
|
+
groups directly, the snapshot diff is available over HTTP, and the
|
|
10
|
+
packaged skill documents host-aware browser-panel etiquette.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`canvas_add_node({ type: 'group' })` creates a populated group.**
|
|
15
|
+
The generic add path (MCP and SDK) now routes `type: 'group'` to
|
|
16
|
+
`createGroup`, accepting `children` / `childIds` (node IDs to
|
|
17
|
+
enclose), an optional `childLayout` (`grid` / `column` / `flow`),
|
|
18
|
+
and a frame `color`. `canvas_create_group` remains the dedicated
|
|
19
|
+
entry point; this just removes the dead-end where `canvas_add_node`
|
|
20
|
+
produced an empty group node. Child-ID validation is inherited from
|
|
21
|
+
`createGroup` (missing / self / nested-group children rejected).
|
|
22
|
+
- **`GET /api/canvas/snapshots/diff` over HTTP.** The snapshot-vs-
|
|
23
|
+
current-layout diff that was previously MCP-only (`canvas_diff`) is
|
|
24
|
+
now reachable over HTTP at
|
|
25
|
+
`/api/canvas/snapshots/diff?name=<name|id>`, returning both the
|
|
26
|
+
structured `diff` and a `text` rendering. Missing name → 400,
|
|
27
|
+
unknown snapshot → 404.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- **Packaged skill documents host-aware browser-panel etiquette.**
|
|
32
|
+
`skills/pmx-canvas/SKILL.md` now tells agents to reuse an existing
|
|
33
|
+
native canvas panel (e.g. the GitHub Copilot `pmx-canvas` extension
|
|
34
|
+
or Codex's in-app Browser on `/workbench`) instead of opening a
|
|
35
|
+
second browser panel to the same workbench, and to open the browser
|
|
36
|
+
workbench only when no native adapter is present. It also restates
|
|
37
|
+
that only same-origin `/api/canvas/frame-documents/<id>` URLs are
|
|
38
|
+
auto-trusted — external `mcp-app` URLs show the unverified-domain
|
|
39
|
+
interstitial by design.
|
|
40
|
+
|
|
41
|
+
### Internal
|
|
42
|
+
|
|
43
|
+
- Regression coverage for: `canvas_add_node` group creation via both
|
|
44
|
+
`children` and `childIds` (MCP), and the HTTP snapshot-diff endpoint
|
|
45
|
+
returning the snapshot name in the structured diff.
|
|
46
|
+
|
|
6
47
|
## [0.1.25] - 2026-06-03
|
|
7
48
|
|
|
8
49
|
Adapter-regression cleanup on top of 0.1.24. Fixes several issues the
|
|
@@ -1235,6 +1276,7 @@ otherwise have to discover by trial and error.
|
|
|
1235
1276
|
- Regression coverage for snapshot flat-`id` aliases on both MCP and
|
|
1236
1277
|
HTTP surfaces, plus async / top-level-`await` WebView script bodies.
|
|
1237
1278
|
|
|
1279
|
+
[0.1.26]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.26
|
|
1238
1280
|
[0.1.25]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.25
|
|
1239
1281
|
[0.1.24]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.24
|
|
1240
1282
|
[0.1.23]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.1.23
|
|
@@ -25,6 +25,10 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
25
25
|
type: CanvasNodeState['type'];
|
|
26
26
|
title?: string;
|
|
27
27
|
content?: string;
|
|
28
|
+
children?: string[];
|
|
29
|
+
childIds?: string[];
|
|
30
|
+
childLayout?: 'grid' | 'column' | 'flow';
|
|
31
|
+
color?: string;
|
|
28
32
|
toolName?: string;
|
|
29
33
|
category?: string;
|
|
30
34
|
status?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmx-canvas",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.26",
|
|
4
4
|
"description": "Spatial canvas workbench for coding agents — infinite 2D canvas with agent-native CLI, MCP integration, nodes, edges, file watching, and snapshots",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/server/index.ts",
|
|
@@ -75,6 +75,19 @@ reference before using adapter-native features:
|
|
|
75
75
|
- `references/codex-app-adapter.md` — Codex app native Browser + MCP adapter, AX context reading,
|
|
76
76
|
focus labeling, and live-test checklist.
|
|
77
77
|
|
|
78
|
+
Host-aware visibility rule:
|
|
79
|
+
- If a native PMX Canvas adapter/panel is available and already represents the workbench (for example
|
|
80
|
+
the GitHub Copilot app `pmx-canvas` canvas extension, or Codex's in-app Browser opened to
|
|
81
|
+
`/workbench`), use that panel. Do **not** also open a separate browser panel to the same workbench;
|
|
82
|
+
it wastes space and confuses which surface is authoritative.
|
|
83
|
+
- If no native adapter/panel is available (generic MCP client, shell-only agent, raw CLI harness,
|
|
84
|
+
or another agent harness without canvas support), open the normal PMX Canvas browser workbench first
|
|
85
|
+
so the human can see mutations as they happen. Use the server URL's `/workbench` route.
|
|
86
|
+
- External URLs in `mcp-app` nodes show the "Unverified domain" interstitial by design. Only
|
|
87
|
+
same-origin `/api/canvas/frame-documents/<id>` URLs are auto-trusted. For external tools, use a
|
|
88
|
+
bundled `web-artifact`, same-origin frame document, or set `data.trustedDomain: true` only when the
|
|
89
|
+
user accepts the risk.
|
|
90
|
+
|
|
78
91
|
The canvas auto-starts on first MCP tool call when running in MCP mode (`pmx-canvas --mcp`).
|
|
79
92
|
For manual start:
|
|
80
93
|
|
package/src/mcp/server.ts
CHANGED
|
@@ -363,6 +363,10 @@ export async function startMcpServer(): Promise<void> {
|
|
|
363
363
|
width: z.number().optional().describe('Width in pixels (default: 720)'),
|
|
364
364
|
height: z.number().optional().describe('Height in pixels (default: 600)'),
|
|
365
365
|
strictSize: z.boolean().optional().describe('Keep explicit width/height fixed and scroll overflowing content instead of browser auto-fitting'),
|
|
366
|
+
children: z.array(z.string()).optional().describe('Group-only alias for childIds. Node IDs to include in a generic group node.'),
|
|
367
|
+
childIds: z.array(z.string()).optional().describe('Group-only field. Node IDs to include in a generic group node. Prefer canvas_create_group for groups.'),
|
|
368
|
+
childLayout: z.enum(['grid', 'column', 'flow']).optional().describe('Group-only optional layout for grouped children.'),
|
|
369
|
+
color: z.string().optional().describe('Group-only frame accent color.'),
|
|
366
370
|
toolName: z.string().optional().describe('Trace node tool or operation label'),
|
|
367
371
|
category: z.string().optional().describe('Trace node category: mcp, file, subagent, or other'),
|
|
368
372
|
status: z.string().optional().describe('Trace node status: running, success, or failed'),
|
package/src/server/index.ts
CHANGED
|
@@ -167,6 +167,10 @@ export class PmxCanvas extends EventEmitter {
|
|
|
167
167
|
type: CanvasNodeState['type'];
|
|
168
168
|
title?: string;
|
|
169
169
|
content?: string;
|
|
170
|
+
children?: string[];
|
|
171
|
+
childIds?: string[];
|
|
172
|
+
childLayout?: 'grid' | 'column' | 'flow';
|
|
173
|
+
color?: string;
|
|
170
174
|
toolName?: string;
|
|
171
175
|
category?: string;
|
|
172
176
|
status?: string;
|
|
@@ -182,6 +186,18 @@ export class PmxCanvas extends EventEmitter {
|
|
|
182
186
|
if (input.type === 'webpage') {
|
|
183
187
|
throw new Error('Use addWebpageNode for webpage nodes so page content is fetched and cached on the server.');
|
|
184
188
|
}
|
|
189
|
+
if (input.type === 'group') {
|
|
190
|
+
return this.createGroup({
|
|
191
|
+
...(typeof input.title === 'string' ? { title: input.title } : {}),
|
|
192
|
+
childIds: input.childIds ?? input.children ?? [],
|
|
193
|
+
...(typeof input.x === 'number' ? { x: input.x } : {}),
|
|
194
|
+
...(typeof input.y === 'number' ? { y: input.y } : {}),
|
|
195
|
+
...(typeof input.width === 'number' ? { width: input.width } : {}),
|
|
196
|
+
...(typeof input.height === 'number' ? { height: input.height } : {}),
|
|
197
|
+
...(typeof input.color === 'string' ? { color: input.color } : {}),
|
|
198
|
+
...(input.childLayout ? { childLayout: input.childLayout } : {}),
|
|
199
|
+
});
|
|
200
|
+
}
|
|
185
201
|
const { id, needsCodeGraphRecompute } = addCanvasNode({
|
|
186
202
|
...input,
|
|
187
203
|
defaultWidth: input.type === 'markdown'
|
package/src/server/server.ts
CHANGED
|
@@ -4584,6 +4584,15 @@ export function startCanvasServer(options: CanvasServerOptions = {}): string | n
|
|
|
4584
4584
|
return handleSnapshotGc(req);
|
|
4585
4585
|
}
|
|
4586
4586
|
|
|
4587
|
+
if (url.pathname === '/api/canvas/snapshots/diff' && req.method === 'GET') {
|
|
4588
|
+
const name = url.searchParams.get('name') ?? url.searchParams.get('id') ?? '';
|
|
4589
|
+
if (!name.trim()) return responseJson({ ok: false, error: 'Missing snapshot name or id.' }, 400);
|
|
4590
|
+
const snapshot = canvasState.getSnapshotData(name);
|
|
4591
|
+
if (!snapshot) return responseJson({ ok: false, error: `Snapshot "${name}" not found.` }, 404);
|
|
4592
|
+
const diff = diffLayouts(snapshot.name, snapshot, canvasState.getLayout());
|
|
4593
|
+
return responseJson({ ok: true, text: formatDiff(diff), diff });
|
|
4594
|
+
}
|
|
4595
|
+
|
|
4587
4596
|
if (url.pathname.startsWith('/api/canvas/snapshots/') && url.pathname.endsWith('/diff') && req.method === 'GET') {
|
|
4588
4597
|
const id = decodeURIComponent(url.pathname.slice('/api/canvas/snapshots/'.length, -'/diff'.length));
|
|
4589
4598
|
const snapshot = canvasState.getSnapshotData(id);
|