pmx-canvas 0.1.26 → 0.1.28
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/.github/extensions/pmx-canvas/extension.mjs +191 -0
- package/CHANGELOG.md +110 -0
- package/Readme.md +74 -27
- package/dist/canvas/index.js +82 -82
- package/dist/json-render/index.css +1 -1
- package/dist/json-render/index.js +944 -164
- package/dist/types/json-render/catalog.d.ts +195 -20
- package/dist/types/json-render/charts/components.d.ts +17 -0
- package/dist/types/json-render/charts/definitions.d.ts +13 -1
- package/dist/types/json-render/charts/tufte-components.d.ts +65 -0
- package/dist/types/json-render/charts/tufte-definitions.d.ts +164 -0
- package/dist/types/json-render/directives.d.ts +33 -0
- package/dist/types/json-render/renderer/index.d.ts +1 -0
- package/dist/types/json-render/server.d.ts +32 -1
- package/dist/types/mcp/canvas-access.d.ts +62 -0
- package/dist/types/server/ax-state.d.ts +170 -0
- package/dist/types/server/canvas-db.d.ts +17 -1
- package/dist/types/server/canvas-operations.d.ts +53 -0
- package/dist/types/server/canvas-schema.d.ts +5 -1
- package/dist/types/server/canvas-state.d.ts +95 -4
- package/dist/types/server/index.d.ts +120 -3
- package/dist/types/server/mutation-history.d.ts +1 -1
- package/docs/cli.md +42 -0
- package/docs/http-api.md +64 -0
- package/docs/mcp.md +23 -5
- package/docs/node-types.md +1 -1
- package/docs/screenshots/codex-app.png +0 -0
- package/docs/screenshots/github-copilot-app.png +0 -0
- package/docs/sdk.md +23 -5
- package/package.json +10 -7
- package/skills/control-session-orchestrator/SKILL.md +359 -0
- package/skills/control-session-orchestrator/evals/evals.json +75 -0
- package/skills/data-analysis/SKILL.md +6 -0
- package/skills/pmx-canvas/SKILL.md +50 -4
- package/skills/pmx-canvas/references/github-copilot-app-adapter.md +6 -0
- package/skills/tufte-viz/SKILL.md +157 -0
- package/skills/tufte-viz/references/analytical-design.md +217 -0
- package/skills/tufte-viz/references/tufte-principles.md +147 -0
- package/src/cli/agent.ts +302 -3
- package/src/cli/index.ts +2 -1
- package/src/client/nodes/ExtAppFrame.tsx +48 -1
- package/src/client/nodes/McpAppNode.tsx +6 -2
- package/src/json-render/catalog.ts +22 -1
- package/src/json-render/charts/components.tsx +127 -15
- package/src/json-render/charts/definitions.ts +19 -2
- package/src/json-render/charts/extra-components.tsx +5 -4
- package/src/json-render/charts/tufte-components.tsx +395 -0
- package/src/json-render/charts/tufte-definitions.ts +128 -0
- package/src/json-render/directives.ts +64 -0
- package/src/json-render/renderer/index.css +107 -1
- package/src/json-render/renderer/index.tsx +33 -0
- package/src/json-render/server.ts +275 -5
- package/src/mcp/canvas-access.ts +264 -1
- package/src/mcp/server.ts +498 -9
- package/src/server/ax-context.ts +8 -3
- package/src/server/ax-state.ts +447 -0
- package/src/server/canvas-db.ts +184 -1
- package/src/server/canvas-operations.ts +123 -2
- package/src/server/canvas-schema.ts +27 -3
- package/src/server/canvas-state.ts +349 -2
- package/src/server/index.ts +259 -7
- package/src/server/mutation-history.ts +6 -0
- package/src/server/server.ts +442 -5
- package/src/server/web-artifacts.ts +31 -5
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { canvasState } from './canvas-state.js';
|
|
2
3
|
import type { CanvasAnnotation, CanvasNodeState, CanvasEdge, CanvasLayout } from './canvas-state.js';
|
|
3
|
-
import type { PmxAxContext, PmxAxFocusState, PmxAxSource, PmxAxState } from './ax-state.js';
|
|
4
|
+
import type { PmxAxApprovalGate, PmxAxContext, PmxAxEvent, PmxAxEvidence, PmxAxEvidenceKind, PmxAxFocusState, PmxAxHostCapability, PmxAxReviewAnchorType, PmxAxReviewAnnotation, PmxAxReviewKind, PmxAxReviewRegion, PmxAxReviewSeverity, PmxAxReviewStatus, PmxAxSource, PmxAxState, PmxAxSteeringMessage, PmxAxWorkItem, PmxAxWorkItemStatus } from './ax-state.js';
|
|
5
|
+
import type { AxTimelineQuery } from './canvas-db.js';
|
|
4
6
|
import { searchNodes } from './spatial-analysis.js';
|
|
5
7
|
import { diffLayouts } from './mutation-history.js';
|
|
6
8
|
import { fitCanvasView, gcCanvasSnapshots, listCanvasSnapshots } from './canvas-operations.js';
|
|
@@ -21,6 +23,11 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
21
23
|
automationWebView?: boolean | CanvasAutomationWebViewOptions;
|
|
22
24
|
}): Promise<void>;
|
|
23
25
|
stop(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Add a node to the canvas and return the created node (including its `id`,
|
|
28
|
+
* resolved geometry, and data). Destructure `const { id } = canvas.addNode(...)`
|
|
29
|
+
* or keep the whole node — both work. (Previously returned a bare id string.)
|
|
30
|
+
*/
|
|
24
31
|
addNode(input: {
|
|
25
32
|
type: CanvasNodeState['type'];
|
|
26
33
|
title?: string;
|
|
@@ -40,7 +47,7 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
40
47
|
width?: number;
|
|
41
48
|
height?: number;
|
|
42
49
|
strictSize?: boolean;
|
|
43
|
-
}):
|
|
50
|
+
}): CanvasNodeState;
|
|
44
51
|
addWebpageNode(input: {
|
|
45
52
|
title?: string;
|
|
46
53
|
url: string;
|
|
@@ -114,6 +121,85 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
114
121
|
setAxFocus(nodeIds: string[], options?: {
|
|
115
122
|
source?: PmxAxSource;
|
|
116
123
|
}): PmxAxFocusState;
|
|
124
|
+
recordAxEvent(input: {
|
|
125
|
+
kind: PmxAxEvent['kind'];
|
|
126
|
+
summary: string;
|
|
127
|
+
detail?: string | null;
|
|
128
|
+
nodeIds?: string[];
|
|
129
|
+
data?: Record<string, unknown> | null;
|
|
130
|
+
}, options?: {
|
|
131
|
+
source?: PmxAxSource;
|
|
132
|
+
}): PmxAxEvent;
|
|
133
|
+
sendSteering(message: string, options?: {
|
|
134
|
+
source?: PmxAxSource;
|
|
135
|
+
}): PmxAxSteeringMessage;
|
|
136
|
+
markSteeringDelivered(id: string): boolean;
|
|
137
|
+
getAxTimeline(query?: AxTimelineQuery): ReturnType<typeof canvasState.getAxTimeline>;
|
|
138
|
+
listWorkItems(): PmxAxWorkItem[];
|
|
139
|
+
addWorkItem(input: {
|
|
140
|
+
title: string;
|
|
141
|
+
status?: PmxAxWorkItemStatus;
|
|
142
|
+
detail?: string | null;
|
|
143
|
+
nodeIds?: string[];
|
|
144
|
+
}, options?: {
|
|
145
|
+
source?: PmxAxSource;
|
|
146
|
+
}): PmxAxWorkItem;
|
|
147
|
+
updateWorkItem(id: string, patch: {
|
|
148
|
+
title?: string;
|
|
149
|
+
status?: PmxAxWorkItemStatus;
|
|
150
|
+
detail?: string | null;
|
|
151
|
+
nodeIds?: string[];
|
|
152
|
+
}, options?: {
|
|
153
|
+
source?: PmxAxSource;
|
|
154
|
+
}): PmxAxWorkItem | null;
|
|
155
|
+
listApprovalGates(): PmxAxApprovalGate[];
|
|
156
|
+
requestApproval(input: {
|
|
157
|
+
title: string;
|
|
158
|
+
detail?: string | null;
|
|
159
|
+
action?: string | null;
|
|
160
|
+
nodeIds?: string[];
|
|
161
|
+
}, options?: {
|
|
162
|
+
source?: PmxAxSource;
|
|
163
|
+
}): PmxAxApprovalGate;
|
|
164
|
+
resolveApproval(id: string, decision: 'approved' | 'rejected', options?: {
|
|
165
|
+
resolution?: string;
|
|
166
|
+
source?: PmxAxSource;
|
|
167
|
+
}): PmxAxApprovalGate | null;
|
|
168
|
+
addEvidence(input: {
|
|
169
|
+
kind: PmxAxEvidenceKind;
|
|
170
|
+
title: string;
|
|
171
|
+
body?: string | null;
|
|
172
|
+
ref?: string | null;
|
|
173
|
+
nodeIds?: string[];
|
|
174
|
+
data?: Record<string, unknown> | null;
|
|
175
|
+
}, options?: {
|
|
176
|
+
source?: PmxAxSource;
|
|
177
|
+
}): PmxAxEvidence;
|
|
178
|
+
listReviewAnnotations(): PmxAxReviewAnnotation[];
|
|
179
|
+
addReviewAnnotation(input: {
|
|
180
|
+
body: string;
|
|
181
|
+
kind?: PmxAxReviewKind;
|
|
182
|
+
severity?: PmxAxReviewSeverity;
|
|
183
|
+
anchorType?: PmxAxReviewAnchorType;
|
|
184
|
+
nodeId?: string | null;
|
|
185
|
+
file?: string | null;
|
|
186
|
+
region?: PmxAxReviewRegion | null;
|
|
187
|
+
author?: string | null;
|
|
188
|
+
}, options?: {
|
|
189
|
+
source?: PmxAxSource;
|
|
190
|
+
}): PmxAxReviewAnnotation | null;
|
|
191
|
+
updateReviewAnnotation(id: string, patch: {
|
|
192
|
+
body?: string;
|
|
193
|
+
status?: PmxAxReviewStatus;
|
|
194
|
+
severity?: PmxAxReviewSeverity;
|
|
195
|
+
kind?: PmxAxReviewKind;
|
|
196
|
+
}, options?: {
|
|
197
|
+
source?: PmxAxSource;
|
|
198
|
+
}): PmxAxReviewAnnotation | null;
|
|
199
|
+
getHostCapability(): PmxAxHostCapability | null;
|
|
200
|
+
reportHostCapability(input: unknown, options?: {
|
|
201
|
+
source?: PmxAxSource;
|
|
202
|
+
}): PmxAxHostCapability;
|
|
117
203
|
fitView(options?: {
|
|
118
204
|
width?: number;
|
|
119
205
|
height?: number;
|
|
@@ -188,9 +274,13 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
188
274
|
jsonRender: {
|
|
189
275
|
rootShape: Record<string, string>;
|
|
190
276
|
components: import("../json-render/catalog.js").JsonRenderComponentDescriptor[];
|
|
277
|
+
directives: Array<{
|
|
278
|
+
name: string;
|
|
279
|
+
usage: string;
|
|
280
|
+
}>;
|
|
191
281
|
};
|
|
192
282
|
graph: {
|
|
193
|
-
graphTypes: ("line" | "bar" | "pie" | "area" | "scatter" | "radar" | "composed" | "stacked-bar")[];
|
|
283
|
+
graphTypes: ("line" | "bar" | "pie" | "area" | "scatter" | "radar" | "composed" | "sparkline" | "bullet" | "slopegraph" | "stacked-bar" | "dot-plot")[];
|
|
194
284
|
};
|
|
195
285
|
htmlPrimitives: import("./html-primitives.js").HtmlPrimitiveDescriptor[];
|
|
196
286
|
mcp: {
|
|
@@ -251,6 +341,31 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
251
341
|
url: string;
|
|
252
342
|
spec: JsonRenderSpec;
|
|
253
343
|
};
|
|
344
|
+
/**
|
|
345
|
+
* Progressively build a json-render node from SpecStream patches. Omit nodeId
|
|
346
|
+
* to create a new streaming node; pass the same nodeId on later calls to
|
|
347
|
+
* append more patches. The server accumulates the spec and the browser
|
|
348
|
+
* reloads the viewer as the specVersion bumps.
|
|
349
|
+
*/
|
|
350
|
+
streamJsonRenderNode(input: {
|
|
351
|
+
nodeId?: string;
|
|
352
|
+
title?: string;
|
|
353
|
+
patches?: unknown[];
|
|
354
|
+
done?: boolean;
|
|
355
|
+
x?: number;
|
|
356
|
+
y?: number;
|
|
357
|
+
width?: number;
|
|
358
|
+
height?: number;
|
|
359
|
+
strictSize?: boolean;
|
|
360
|
+
}): {
|
|
361
|
+
id: string;
|
|
362
|
+
url: string;
|
|
363
|
+
applied: number;
|
|
364
|
+
skipped: number;
|
|
365
|
+
specVersion: number;
|
|
366
|
+
elementCount: number;
|
|
367
|
+
streamStatus: 'open' | 'closed';
|
|
368
|
+
};
|
|
254
369
|
addHtmlNode(input: {
|
|
255
370
|
html: string;
|
|
256
371
|
title?: string;
|
|
@@ -318,3 +433,5 @@ export type { WebArtifactBuildInput, WebArtifactBuildOutput, WebArtifactCanvasBu
|
|
|
318
433
|
export type { GraphNodeInput, JsonRenderNodeInput, JsonRenderSpec } from '../json-render/server.js';
|
|
319
434
|
export type { HtmlPrimitiveKind, HtmlPrimitiveDescriptor, HtmlPrimitiveInput, HtmlPrimitiveBuildResult } from './html-primitives.js';
|
|
320
435
|
export { traceManager } from './trace-manager.js';
|
|
436
|
+
export type { PmxAxApprovalGate, PmxAxApprovalStatus, PmxAxContext, PmxAxEvent, PmxAxEventKind, PmxAxEvidence, PmxAxEvidenceKind, PmxAxFocusState, PmxAxHostCapability, PmxAxReviewAnchorType, PmxAxReviewAnnotation, PmxAxReviewKind, PmxAxReviewRegion, PmxAxReviewSeverity, PmxAxReviewStatus, PmxAxSource, PmxAxState, PmxAxSteeringMessage, PmxAxTimelineSummary, PmxAxWorkItem, PmxAxWorkItemStatus, } from './ax-state.js';
|
|
437
|
+
export type { AxTimelineQuery } from './canvas-db.js';
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* - _replaying flag prevents undo/redo from recording new entries
|
|
13
13
|
*/
|
|
14
14
|
import type { CanvasNodeState, CanvasEdge } from './canvas-state.js';
|
|
15
|
-
export type MutationOp = 'addNode' | 'updateNode' | 'removeNode' | 'addEdge' | 'removeEdge' | 'addAnnotation' | 'removeAnnotation' | 'clear' | 'arrange' | 'restoreSnapshot' | 'setPins' | 'setAxFocus' | 'batch' | 'viewport' | 'groupNodes' | 'ungroupNodes';
|
|
15
|
+
export type MutationOp = 'addNode' | 'updateNode' | 'removeNode' | 'addEdge' | 'removeEdge' | 'addAnnotation' | 'removeAnnotation' | 'clear' | 'arrange' | 'restoreSnapshot' | 'setPins' | 'setAxFocus' | 'addWorkItem' | 'updateWorkItem' | 'requestApproval' | 'resolveApproval' | 'addReviewAnnotation' | 'updateReviewAnnotation' | 'batch' | 'viewport' | 'groupNodes' | 'ungroupNodes';
|
|
16
16
|
export interface MutationEntry {
|
|
17
17
|
id: string;
|
|
18
18
|
timestamp: string;
|
package/docs/cli.md
CHANGED
|
@@ -125,6 +125,48 @@ pmx-canvas ax focus node-1 node-2 # Set AX focus
|
|
|
125
125
|
pmx-canvas ax focus --clear # Clear AX focus
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
+
### AX primitives
|
|
129
|
+
|
|
130
|
+
Host-agnostic agent-experience primitives. Timeline commands persist for
|
|
131
|
+
diagnostics (retention-bounded, not snapshotted); work items, approval gates,
|
|
132
|
+
and review annotations are canvas-bound and ride snapshots/restore.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Timeline
|
|
136
|
+
pmx-canvas ax event add --kind tool-start --summary "ran tests"
|
|
137
|
+
pmx-canvas ax steer "focus on the failing test first"
|
|
138
|
+
pmx-canvas ax evidence add --kind test-output --title "unit pass"
|
|
139
|
+
pmx-canvas ax timeline --limit 50
|
|
140
|
+
|
|
141
|
+
# Work items (canvas-bound)
|
|
142
|
+
pmx-canvas ax work add --title "Wire up auth" --status in-progress node-1
|
|
143
|
+
pmx-canvas ax work update <id> --status done
|
|
144
|
+
pmx-canvas ax work list
|
|
145
|
+
|
|
146
|
+
# Approval gates (canvas-bound; pending → approved/rejected)
|
|
147
|
+
pmx-canvas ax approval request --title "Deploy to prod" --action deploy.prod
|
|
148
|
+
pmx-canvas ax approval resolve <id> --decision approved
|
|
149
|
+
pmx-canvas ax approval list
|
|
150
|
+
|
|
151
|
+
# Review annotations (canvas-bound)
|
|
152
|
+
pmx-canvas ax review add --body "off-by-one" --kind finding --severity error --file src/x.ts
|
|
153
|
+
pmx-canvas ax review list
|
|
154
|
+
|
|
155
|
+
# Host capability (own partition; survives clear)
|
|
156
|
+
pmx-canvas ax host report --host copilot --canvas --session-messaging
|
|
157
|
+
pmx-canvas ax host status
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Copilot adapter
|
|
161
|
+
|
|
162
|
+
Install the bundled GitHub Copilot extension adapter into a repo. The adapter
|
|
163
|
+
maps onto the same neutral AX surfaces (it never makes the core GitHub-specific).
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
pmx-canvas copilot install-extension --dry-run # Preview target, writes nothing
|
|
167
|
+
pmx-canvas copilot install-extension --yes # Install/overwrite into .github/extensions/pmx-canvas/
|
|
168
|
+
```
|
|
169
|
+
|
|
128
170
|
## WebView automation
|
|
129
171
|
|
|
130
172
|
Drive a headless Bun.WebView (Chromium or WebKit) pointed at the workbench:
|
package/docs/http-api.md
CHANGED
|
@@ -117,6 +117,70 @@ curl -X PATCH http://localhost:4313/api/canvas/ax \
|
|
|
117
117
|
-d '{"focus":{"nodeIds":["node-1"],"source":"api"}}'
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
+
## AX primitives (timeline, work, host)
|
|
121
|
+
|
|
122
|
+
Host-agnostic agent-experience primitives across three state partitions.
|
|
123
|
+
Canvas-bound state (work items, approval gates, review annotations) rides
|
|
124
|
+
canvas snapshots; timeline state (events, evidence, steering) persists for
|
|
125
|
+
diagnostics but is retention-bounded and not restored by snapshots; the host
|
|
126
|
+
capability is reported by adapters and survives `canvas_clear`.
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# Timeline — record a normalized agent-event
|
|
130
|
+
curl -X POST http://localhost:4313/api/canvas/ax/event \
|
|
131
|
+
-H "Content-Type: application/json" \
|
|
132
|
+
-d '{"kind":"tool-start","summary":"ran tests","source":"api"}'
|
|
133
|
+
|
|
134
|
+
# Timeline — send a steering message to the active agent session
|
|
135
|
+
curl -X POST http://localhost:4313/api/canvas/ax/steer \
|
|
136
|
+
-H "Content-Type: application/json" \
|
|
137
|
+
-d '{"message":"focus on the failing test first","source":"api"}'
|
|
138
|
+
|
|
139
|
+
# Timeline — record an evidence item (logs/tool-result/screenshot/file/diff/test-output)
|
|
140
|
+
curl -X POST http://localhost:4313/api/canvas/ax/evidence \
|
|
141
|
+
-H "Content-Type: application/json" \
|
|
142
|
+
-d '{"kind":"test-output","title":"unit pass","source":"api"}'
|
|
143
|
+
|
|
144
|
+
# Timeline — read the bounded timeline (default limit 50, max 200)
|
|
145
|
+
curl "http://localhost:4313/api/canvas/ax/timeline?limit=50"
|
|
146
|
+
|
|
147
|
+
# Canvas-bound — add / update a work item
|
|
148
|
+
curl -X POST http://localhost:4313/api/canvas/ax/work \
|
|
149
|
+
-H "Content-Type: application/json" \
|
|
150
|
+
-d '{"title":"Wire up auth","status":"in-progress","nodeIds":["node-1"],"source":"api"}'
|
|
151
|
+
curl -X PATCH http://localhost:4313/api/canvas/ax/work/<id> \
|
|
152
|
+
-H "Content-Type: application/json" \
|
|
153
|
+
-d '{"status":"done"}'
|
|
154
|
+
curl http://localhost:4313/api/canvas/ax/work
|
|
155
|
+
|
|
156
|
+
# Canvas-bound — request / resolve an approval gate (pending → approved/rejected)
|
|
157
|
+
curl -X POST http://localhost:4313/api/canvas/ax/approval \
|
|
158
|
+
-H "Content-Type: application/json" \
|
|
159
|
+
-d '{"title":"Deploy to prod","action":"deploy.prod","source":"api"}'
|
|
160
|
+
curl -X POST http://localhost:4313/api/canvas/ax/approval/<id>/resolve \
|
|
161
|
+
-H "Content-Type: application/json" \
|
|
162
|
+
-d '{"decision":"approved","source":"api"}'
|
|
163
|
+
curl http://localhost:4313/api/canvas/ax/approval
|
|
164
|
+
|
|
165
|
+
# Canvas-bound — add a review annotation (comment/finding) anchored to node/file/region
|
|
166
|
+
curl -X POST http://localhost:4313/api/canvas/ax/review \
|
|
167
|
+
-H "Content-Type: application/json" \
|
|
168
|
+
-d '{"body":"off-by-one","kind":"finding","severity":"error","anchorType":"file","file":"src/x.ts","source":"api"}'
|
|
169
|
+
curl http://localhost:4313/api/canvas/ax/review
|
|
170
|
+
|
|
171
|
+
# Host/session — report and read host capability
|
|
172
|
+
curl -X PUT http://localhost:4313/api/canvas/ax/host-capability \
|
|
173
|
+
-H "Content-Type: application/json" \
|
|
174
|
+
-d '{"host":"copilot","canvas":true,"sessionMessaging":true,"source":"api"}'
|
|
175
|
+
curl http://localhost:4313/api/canvas/ax/host-capability
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Validation: `/ax/event` requires a valid `kind` + `summary` (400 otherwise);
|
|
179
|
+
`/ax/evidence` requires `kind` + `title`; `/ax/steer`, `/ax/work`,
|
|
180
|
+
`/ax/approval`, `/ax/review` require their primary field; `PATCH /ax/work/:id`
|
|
181
|
+
and `PATCH /ax/review/:id` return 404 for unknown IDs; approval resolve returns
|
|
182
|
+
404 if the gate is missing or already resolved.
|
|
183
|
+
|
|
120
184
|
## Diagrams (Excalidraw preset)
|
|
121
185
|
|
|
122
186
|
```bash
|
package/docs/mcp.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# MCP reference
|
|
2
2
|
|
|
3
|
-
PMX Canvas ships an MCP stdio server with **
|
|
3
|
+
PMX Canvas ships an MCP stdio server with **56 tools** + **12 core resources**,
|
|
4
4
|
plus per-skill resources at `canvas://skills/<name>`. The server emits
|
|
5
5
|
`notifications/resources/updated` when canvas state changes — humans pin
|
|
6
6
|
nodes in the browser, agents are notified immediately.
|
|
@@ -35,7 +35,8 @@ The canvas auto-starts on first tool call.
|
|
|
35
35
|
| `canvas_validate_spec` | Validate a json-render spec, graph payload, or HTML primitive payload without creating a node |
|
|
36
36
|
| `canvas_refresh_webpage_node` | Re-fetch and update a webpage node from its stored URL |
|
|
37
37
|
| `canvas_add_json_render_node` | Create a native json-render node from a validated spec |
|
|
38
|
-
| `
|
|
38
|
+
| `canvas_stream_json_render_node` | Progressively build a json-render node from SpecStream JSON-Patch ops (live/streaming panels) |
|
|
39
|
+
| `canvas_add_graph_node` | Create a native graph node (line, bar, pie, area, scatter, radar, stacked-bar, composed, sparkline, dot-plot, bullet, slopegraph) |
|
|
39
40
|
| `canvas_build_web_artifact` | Build a bundled HTML artifact and open it on the canvas |
|
|
40
41
|
|
|
41
42
|
`canvas_add_html_node` accepts optional `summary`, `agentSummary`, `embeddedNodeIds`, and
|
|
@@ -51,8 +52,19 @@ searchable and readable in pinned/spatial context.
|
|
|
51
52
|
| `canvas_arrange` | Auto-arrange (grid/column/flow) |
|
|
52
53
|
| `canvas_validate` | Validate collisions, containment, and missing edge endpoints |
|
|
53
54
|
| `canvas_focus_node` | Pan viewport to a node; use CLI `focus --no-pan` when you only need to select/raise |
|
|
54
|
-
| `
|
|
55
|
+
| `canvas_fit_view` | Fit the canvas viewport to all nodes or a selected subset |
|
|
56
|
+
| `canvas_get_ax` | Read the PMX AX state (focus, work items, approvals, review annotations, host capability) plus pinned/focused context |
|
|
55
57
|
| `canvas_set_ax_focus` | Set the host-agnostic AX focus node set; adapters can pass a source such as `codex` |
|
|
58
|
+
| `canvas_record_ax_event` | Record a normalized timeline `agent-event` (prompt/assistant-message/tool-start/tool-result/failure/approval/steering) |
|
|
59
|
+
| `canvas_send_steering` | Record a `steering-message`: a user instruction from the surface to the active agent session |
|
|
60
|
+
| `canvas_get_ax_timeline` | Read the bounded AX timeline (events, evidence, steering) plus counts |
|
|
61
|
+
| `canvas_add_work_item` | Add a canvas-bound `work-item` (visible task/plan/status tied to nodes) |
|
|
62
|
+
| `canvas_update_work_item` | Update a work item's title/status/detail/nodeIds by ID |
|
|
63
|
+
| `canvas_request_approval` | Request human approval via an `approval-gate` (pending) before a high-impact action |
|
|
64
|
+
| `canvas_resolve_approval` | Resolve a pending approval gate (`approved`/`rejected`) |
|
|
65
|
+
| `canvas_add_evidence` | Record an `evidence-item` on the timeline (logs/tool-result/screenshot/file/diff/test-output) |
|
|
66
|
+
| `canvas_add_review_annotation` | Add a canvas-bound `review-annotation` (comment/finding) anchored to a node, file, or region |
|
|
67
|
+
| `canvas_report_host_capability` | Report a host/session `host-capability` for diagnostics |
|
|
56
68
|
| `canvas_pin_nodes` | Pin nodes to include in agent context |
|
|
57
69
|
| `canvas_clear` | Clear all nodes and edges |
|
|
58
70
|
| `canvas_snapshot` | Save current canvas as a named snapshot |
|
|
@@ -82,8 +94,10 @@ Individual bundled skills are also readable at `canvas://skills/<name>`.
|
|
|
82
94
|
| Resource | Description |
|
|
83
95
|
|----------|-------------|
|
|
84
96
|
| `canvas://pinned-context` | Content of pinned nodes + nearby unpinned neighbors |
|
|
85
|
-
| `canvas://ax` | PMX AX state,
|
|
86
|
-
| `canvas://ax-context` | Agent-readable pinned and focused AX context |
|
|
97
|
+
| `canvas://ax` | PMX AX state: focus, work items, approval gates, review annotations |
|
|
98
|
+
| `canvas://ax-context` | Agent-readable pinned and focused AX context, plus timeline summary and host capability |
|
|
99
|
+
| `canvas://ax-work` | Canvas-bound AX work: work items, approval gates, review annotations |
|
|
100
|
+
| `canvas://ax-timeline` | Bounded AX timeline: recent agent-events, evidence, and steering messages |
|
|
87
101
|
| `canvas://schema` | Running-server create schemas and json-render catalog metadata |
|
|
88
102
|
| `canvas://layout` | Full canvas state (all nodes, edges, viewport) |
|
|
89
103
|
| `canvas://summary` | Compact overview: counts, pinned titles, viewport |
|
|
@@ -99,6 +113,10 @@ changes:
|
|
|
99
113
|
|
|
100
114
|
- Pin changes notify `canvas://pinned-context`, `canvas://ax`, and `canvas://ax-context`
|
|
101
115
|
- AX focus changes notify `canvas://ax` and `canvas://ax-context`
|
|
116
|
+
- Canvas-bound AX mutations (work items, approval gates, review annotations,
|
|
117
|
+
host capability) notify `canvas://ax`, `canvas://ax-work`, and `canvas://ax-context`
|
|
118
|
+
- AX timeline mutations (agent-events, evidence, steering) notify
|
|
119
|
+
`canvas://ax-timeline` and `canvas://ax-context`
|
|
102
120
|
- All mutations notify `canvas://layout`, `canvas://summary`,
|
|
103
121
|
`canvas://spatial-context`, `canvas://history`, and `canvas://code-graph`
|
|
104
122
|
|
package/docs/node-types.md
CHANGED
|
@@ -19,7 +19,7 @@ see [MCP tools](mcp.md), [HTTP API](http-api.md), and [SDK](sdk.md).
|
|
|
19
19
|
| `webpage` | Persisted webpage snapshot with stored URL, extracted text, refresh |
|
|
20
20
|
| `mcp-app` | Tool-backed hosted MCP App iframes (Excalidraw, etc.) |
|
|
21
21
|
| `json-render` | Structured UI from JSON specs (cards, tables, forms) |
|
|
22
|
-
| `graph` | Charts (line, bar, pie, area, scatter, radar, stacked-bar, composed) |
|
|
22
|
+
| `graph` | Charts (line, bar, pie, area, scatter, radar, stacked-bar, composed, plus Tufte primitives: sparkline, dot-plot, bullet, slopegraph) |
|
|
23
23
|
| `html` | Self-contained HTML/JS in a sandboxed iframe |
|
|
24
24
|
| `web-artifact` | Bundled React/Tailwind artifact (full single-file app) |
|
|
25
25
|
| `group` | Spatial container/frame around other nodes |
|
|
Binary file
|
|
Binary file
|
package/docs/sdk.md
CHANGED
|
@@ -15,16 +15,16 @@ import { createCanvas } from 'pmx-canvas';
|
|
|
15
15
|
const canvas = createCanvas({ port: 4313 });
|
|
16
16
|
await canvas.start({ open: true });
|
|
17
17
|
|
|
18
|
-
// Add nodes
|
|
18
|
+
// Add nodes — addNode returns the created node (with `.id`, geometry, and data)
|
|
19
19
|
const n1 = canvas.addNode({ type: 'markdown', title: 'Plan', content: '# Step 1\nDo the thing.' });
|
|
20
20
|
const n2 = canvas.addNode({ type: 'status', title: 'Build', content: 'passing' });
|
|
21
21
|
const n3 = canvas.addNode({ type: 'file', content: 'src/index.ts' });
|
|
22
22
|
|
|
23
|
-
// Connect them
|
|
24
|
-
canvas.addEdge({ from: n1, to: n2, type: 'flow' });
|
|
23
|
+
// Connect them (edges and groups reference node ids)
|
|
24
|
+
canvas.addEdge({ from: n1.id, to: n2.id, type: 'flow' });
|
|
25
25
|
|
|
26
26
|
// Group related nodes
|
|
27
|
-
canvas.createGroup({ title: 'Build Pipeline', childIds: [n1,
|
|
27
|
+
canvas.createGroup({ title: 'Build Pipeline', childIds: [n1.id, n3.id] });
|
|
28
28
|
|
|
29
29
|
// Self-contained HTML in a sandboxed iframe
|
|
30
30
|
canvas.addHtmlNode({
|
|
@@ -85,9 +85,27 @@ console.log(canvas.validate());
|
|
|
85
85
|
console.log(canvas.getLayout());
|
|
86
86
|
|
|
87
87
|
// AX context for host adapters
|
|
88
|
-
canvas.setAxFocus(
|
|
88
|
+
canvas.setAxFocus([n1], { source: 'sdk' });
|
|
89
89
|
console.log(canvas.getAxState());
|
|
90
90
|
console.log(canvas.getAxContext());
|
|
91
|
+
|
|
92
|
+
// AX primitives — host-agnostic agent-experience layer
|
|
93
|
+
// Timeline (persisted for diagnostics, retention-bounded, not snapshotted)
|
|
94
|
+
canvas.recordAxEvent({ kind: 'tool-start', summary: 'ran tests' }, { source: 'sdk' });
|
|
95
|
+
canvas.addEvidence({ kind: 'test-output', title: 'unit pass' }, { source: 'sdk' });
|
|
96
|
+
canvas.sendSteering('focus on the failing test first', { source: 'sdk' });
|
|
97
|
+
console.log(canvas.getAxTimeline({ limit: 50 }));
|
|
98
|
+
|
|
99
|
+
// Canvas-bound (rides snapshots + restore, cleared by canvas.clear())
|
|
100
|
+
const work = canvas.addWorkItem({ title: 'Wire up auth', status: 'in-progress', nodeIds: [n1] }, { source: 'sdk' });
|
|
101
|
+
canvas.updateWorkItem(work.id, { status: 'done' });
|
|
102
|
+
const gate = canvas.requestApproval({ title: 'Deploy to prod', action: 'deploy.prod' }, { source: 'sdk' });
|
|
103
|
+
canvas.resolveApproval(gate.id, 'approved', { source: 'sdk' });
|
|
104
|
+
canvas.addReviewAnnotation({ body: 'off-by-one', kind: 'finding', severity: 'error', anchorType: 'file', file: 'src/x.ts' }, { source: 'sdk' });
|
|
105
|
+
|
|
106
|
+
// Host/session capability (own table, survives clear)
|
|
107
|
+
canvas.reportHostCapability({ host: 'copilot', canvas: true, sessionMessaging: true }, { source: 'sdk' });
|
|
108
|
+
console.log(canvas.getHostCapability());
|
|
91
109
|
```
|
|
92
110
|
|
|
93
111
|
## WebView automation
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmx-canvas",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.28",
|
|
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",
|
|
@@ -56,18 +56,21 @@
|
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@joplin/turndown-plugin-gfm": "^1.0.64",
|
|
59
|
-
"@json-render/core": "
|
|
60
|
-
"@json-render/
|
|
61
|
-
"@json-render/react": "
|
|
62
|
-
"@json-render/
|
|
59
|
+
"@json-render/core": "0.19.0",
|
|
60
|
+
"@json-render/devtools": "0.19.0",
|
|
61
|
+
"@json-render/devtools-react": "0.19.0",
|
|
62
|
+
"@json-render/directives": "0.19.0",
|
|
63
|
+
"@json-render/mcp": "0.19.0",
|
|
64
|
+
"@json-render/react": "0.19.0",
|
|
65
|
+
"@json-render/shadcn": "0.19.0",
|
|
63
66
|
"@modelcontextprotocol/ext-apps": "^1.3.1",
|
|
64
67
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
65
68
|
"@preact/signals": "^2.0.0",
|
|
66
69
|
"@types/turndown": "^5.0.6",
|
|
67
70
|
"marked": "^15.0.0",
|
|
68
71
|
"preact": "^10.25.0",
|
|
69
|
-
"react": "^19.2.
|
|
70
|
-
"react-dom": "^19.2.
|
|
72
|
+
"react": "^19.2.3",
|
|
73
|
+
"react-dom": "^19.2.3",
|
|
71
74
|
"recharts": "^3.2.1",
|
|
72
75
|
"turndown": "^7.2.4",
|
|
73
76
|
"zod": "^4.3.6"
|