pmx-canvas 0.1.2 → 0.1.4
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 +144 -0
- package/Readme.md +35 -8
- package/dist/canvas/index.js +69 -69
- package/dist/json-render/index.css +1 -1
- package/dist/json-render/index.js +1 -1
- package/dist/types/client/nodes/ExtAppFrame.d.ts +12 -0
- package/dist/types/client/state/canvas-store.d.ts +2 -1
- package/dist/types/client/types.d.ts +3 -0
- package/dist/types/json-render/charts/components.d.ts +2 -1
- package/dist/types/server/canvas-serialization.d.ts +1 -0
- package/dist/types/server/diagram-presets.d.ts +13 -0
- package/dist/types/server/ext-app-lookup.d.ts +22 -0
- package/dist/types/server/index.d.ts +8 -1
- package/dist/types/server/web-artifacts.d.ts +1 -0
- package/package.json +2 -1
- package/skills/pmx-canvas/SKILL.md +35 -10
- package/skills/pmx-canvas/references/installing-pmx-canvas.md +66 -0
- package/skills/web-artifacts-builder/scripts/bundle-artifact.sh +10 -0
- package/skills/web-artifacts-builder/scripts/init-artifact.sh +1 -1
- package/src/cli/agent.ts +114 -21
- package/src/cli/index.ts +3 -1
- package/src/client/App.tsx +2 -1
- package/src/client/canvas/CanvasNode.tsx +3 -2
- package/src/client/canvas/ExpandedNodeOverlay.tsx +6 -1
- package/src/client/nodes/ExtAppFrame.tsx +97 -26
- package/src/client/state/canvas-store.ts +63 -1
- package/src/client/state/sse-bridge.ts +19 -4
- package/src/client/types.ts +12 -0
- package/src/json-render/charts/components.tsx +6 -4
- package/src/json-render/charts/extra-components.tsx +5 -5
- package/src/json-render/renderer/index.css +14 -0
- package/src/mcp/server.ts +44 -5
- package/src/server/canvas-operations.ts +43 -5
- package/src/server/canvas-schema.ts +16 -14
- package/src/server/canvas-serialization.ts +19 -1
- package/src/server/diagram-presets.ts +219 -4
- package/src/server/ext-app-lookup.ts +49 -0
- package/src/server/index.ts +33 -25
- package/src/server/server.ts +199 -45
- package/src/server/web-artifacts/scripts/bundle-artifact.sh +10 -0
- package/src/server/web-artifacts/scripts/init-artifact.sh +1 -1
- package/src/server/web-artifacts.ts +44 -1
|
@@ -4,6 +4,9 @@ import type { CanvasNodeState } from '../types';
|
|
|
4
4
|
type IframeLoadTarget = Pick<HTMLIFrameElement, 'addEventListener' | 'removeEventListener' | 'contentDocument'>;
|
|
5
5
|
type ExtAppBridgeNotifications = Pick<AppBridge, 'sendToolInput' | 'sendToolResult'>;
|
|
6
6
|
type DisplayMode = 'inline' | 'fullscreen' | 'pip';
|
|
7
|
+
interface ExtAppHostDimensionsTarget {
|
|
8
|
+
getBoundingClientRect(): Pick<DOMRectReadOnly, 'width' | 'height'>;
|
|
9
|
+
}
|
|
7
10
|
export declare function waitForExtAppFrameLoad(target: IframeLoadTarget): Promise<void>;
|
|
8
11
|
export declare function getExtAppBridgeInitKey(node: CanvasNodeState, retryKey: number): string;
|
|
9
12
|
export declare function resolveExtAppDisplayModeRequest(requestedMode: DisplayMode, isExpanded: boolean): {
|
|
@@ -12,6 +15,15 @@ export declare function resolveExtAppDisplayModeRequest(requestedMode: DisplayMo
|
|
|
12
15
|
shouldCollapse: boolean;
|
|
13
16
|
};
|
|
14
17
|
export declare function sendExtAppBootstrapState(bridge: ExtAppBridgeNotifications, toolInput: Record<string, unknown>, toolResult: CallToolResult | undefined): Promise<void>;
|
|
18
|
+
export declare function resolveExtAppSandbox(value: unknown): string;
|
|
19
|
+
export declare function resolveExtAppContainerDimensions(target: ExtAppHostDimensionsTarget | null | undefined, fallback: {
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
}): {
|
|
23
|
+
width: number;
|
|
24
|
+
height: number;
|
|
25
|
+
};
|
|
26
|
+
export declare function shouldApplyExtAppSizeChange(height: unknown, isExpanded: boolean): height is number;
|
|
15
27
|
export declare function ExtAppFrame({ node }: {
|
|
16
28
|
node: CanvasNodeState;
|
|
17
29
|
}): import("preact/jsx-runtime").JSX.Element;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type CanvasEdge, type CanvasLayout, type CanvasNodeState, type ConnectionStatus, type ViewportState } from '../types';
|
|
2
2
|
export declare const viewport: import("@preact/signals-core").Signal<ViewportState>;
|
|
3
3
|
export declare const nodes: import("@preact/signals-core").Signal<Map<string, CanvasNodeState>>;
|
|
4
4
|
export declare const edges: import("@preact/signals-core").Signal<Map<string, CanvasEdge>>;
|
|
@@ -9,6 +9,7 @@ export declare const traceEnabled: import("@preact/signals-core").Signal<boolean
|
|
|
9
9
|
export declare const canvasTheme: import("@preact/signals-core").Signal<string>;
|
|
10
10
|
export declare const hasInitialServerLayout: import("@preact/signals-core").Signal<boolean>;
|
|
11
11
|
export declare const expandedNodeId: import("@preact/signals-core").Signal<string | null>;
|
|
12
|
+
export declare const pendingExpandedNodeCloseId: import("@preact/signals-core").Signal<string | null>;
|
|
12
13
|
export declare const pendingConnection: import("@preact/signals-core").Signal<{
|
|
13
14
|
from: string;
|
|
14
15
|
} | null>;
|
|
@@ -33,6 +33,9 @@ export type ConnectionStatus = 'connecting' | 'connected' | 'disconnected';
|
|
|
33
33
|
export declare const TYPE_LABELS: Record<CanvasNodeState['type'], string>;
|
|
34
34
|
/** Node types that support the full-viewport expand/focus overlay. */
|
|
35
35
|
export declare const EXPANDABLE_TYPES: Set<"markdown" | "mcp-app" | "webpage" | "json-render" | "graph" | "prompt" | "response" | "status" | "context" | "ledger" | "trace" | "file" | "image" | "group">;
|
|
36
|
+
export declare const EXCALIDRAW_SERVER_NAME = "Excalidraw";
|
|
37
|
+
export declare const EXCALIDRAW_CREATE_VIEW_TOOL = "create_view";
|
|
38
|
+
export declare function isExcalidrawNode(node: CanvasNodeState): boolean;
|
|
36
39
|
export interface CanvasLayout {
|
|
37
40
|
viewport: ViewportState;
|
|
38
41
|
nodes: CanvasNodeState[];
|
|
@@ -39,9 +39,10 @@ export declare const tooltipStyle: {
|
|
|
39
39
|
fontSize: number;
|
|
40
40
|
};
|
|
41
41
|
/** Shared wrapper for cartesian charts (Line + Bar). */
|
|
42
|
-
export declare function CartesianChart({ props, children, }: {
|
|
42
|
+
export declare function CartesianChart({ props, children, className, }: {
|
|
43
43
|
props: CartesianChartProps;
|
|
44
44
|
children: (data: Record<string, unknown>[]) => ReactNode;
|
|
45
|
+
className?: string;
|
|
45
46
|
}): import("react/jsx-runtime").JSX.Element;
|
|
46
47
|
declare function ChartLineChart({ props }: BaseComponentProps<CartesianChartProps>): import("react/jsx-runtime").JSX.Element;
|
|
47
48
|
declare function ChartBarChart({ props }: BaseComponentProps<CartesianChartProps>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CanvasLayout, CanvasNodeState, ViewportState } from './canvas-state.js';
|
|
2
2
|
import { type CanvasNodeProvenance } from './canvas-provenance.js';
|
|
3
3
|
export interface SerializedCanvasNode extends CanvasNodeState {
|
|
4
|
+
kind: string;
|
|
4
5
|
title: string | null;
|
|
5
6
|
content: string | null;
|
|
6
7
|
path: string | null;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
1
2
|
import type { ExternalMcpTransportConfig } from './mcp-app-runtime.js';
|
|
2
3
|
export declare const EXCALIDRAW_MCP_URL = "https://mcp.excalidraw.com/mcp";
|
|
3
4
|
export declare const EXCALIDRAW_SERVER_NAME = "Excalidraw";
|
|
4
5
|
export declare const EXCALIDRAW_CREATE_VIEW_TOOL = "create_view";
|
|
6
|
+
export declare const EXCALIDRAW_SAVE_CHECKPOINT_TOOL = "save_checkpoint";
|
|
7
|
+
export declare const EXCALIDRAW_READ_CHECKPOINT_TOOL = "read_checkpoint";
|
|
8
|
+
export declare const DEFAULT_EXCALIDRAW_ELEMENTS: ReadonlyArray<Record<string, unknown>>;
|
|
5
9
|
export declare const EXCALIDRAW_MCP_TRANSPORT: ExternalMcpTransportConfig;
|
|
6
10
|
export interface DiagramPresetOpenInput {
|
|
7
11
|
elements: unknown;
|
|
@@ -24,5 +28,14 @@ export interface ExcalidrawOpenMcpAppInput {
|
|
|
24
28
|
width?: number;
|
|
25
29
|
height?: number;
|
|
26
30
|
}
|
|
31
|
+
export declare function inferExcalidrawCameraUpdate(elements: Array<Record<string, unknown>>): Record<string, unknown> | null;
|
|
27
32
|
export declare function normalizeExcalidrawElements(elements: unknown): string;
|
|
33
|
+
export declare function normalizeExcalidrawElementsForToolInput(elements: unknown): string;
|
|
34
|
+
export declare function normalizeExcalidrawCheckpointDataForToolInput(data: unknown): string | null;
|
|
35
|
+
export declare function buildExcalidrawRestoreCheckpointToolInput(checkpointId: string, data?: unknown): string;
|
|
36
|
+
export declare function isExcalidrawCreateView(serverName: unknown, toolName: unknown): boolean;
|
|
37
|
+
export declare function buildExcalidrawCheckpointId(seed: string): string;
|
|
38
|
+
export declare function getExcalidrawCheckpointIdFromToolResult(result: unknown): string | null;
|
|
39
|
+
export declare function withExcalidrawCheckpointId(result: CallToolResult, checkpointId: string): CallToolResult;
|
|
40
|
+
export declare function ensureExcalidrawCheckpointId(result: CallToolResult, seed: string, checkpointId?: string | null): CallToolResult;
|
|
28
41
|
export declare function buildExcalidrawOpenMcpAppInput(input: DiagramPresetOpenInput): ExcalidrawOpenMcpAppInput;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the canvas node ID for a given ext-app `toolCallId`.
|
|
3
|
+
*
|
|
4
|
+
* v0.1.4 fixed a long-standing `ext-app-ext-app-…` double-prefix bug where
|
|
5
|
+
* both `nodeId` and `toolCallId` carried the `ext-app-` prefix. This helper
|
|
6
|
+
* encodes the lookup contract so it doesn't drift between the
|
|
7
|
+
* `PmxCanvas` SDK class and the HTTP server.
|
|
8
|
+
*
|
|
9
|
+
* Resolution order:
|
|
10
|
+
* 1. The direct prefixed form (`ext-app-<toolCallId>` if not already
|
|
11
|
+
* prefixed, otherwise `toolCallId` as-is).
|
|
12
|
+
* 2. The legacy `ext-app-ext-app-…` form, for canvases persisted before
|
|
13
|
+
* v0.1.4 and still on disk. Remove this fallback in v0.2.x.
|
|
14
|
+
* 3. A scan of the layout for any `mcp-app` ext-app node carrying that
|
|
15
|
+
* `toolCallId` in its data.
|
|
16
|
+
*/
|
|
17
|
+
import type { CanvasNodeState } from './canvas-state.js';
|
|
18
|
+
export interface ExtAppLookupSource {
|
|
19
|
+
getNode(id: string): CanvasNodeState | undefined;
|
|
20
|
+
listNodes(): readonly CanvasNodeState[];
|
|
21
|
+
}
|
|
22
|
+
export declare function findCanvasExtAppNodeId(toolCallId: string, source: ExtAppLookupSource): string | null;
|
|
@@ -83,7 +83,12 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
83
83
|
ungroupNodes(groupId: string): boolean;
|
|
84
84
|
clear(): void;
|
|
85
85
|
arrange(layout?: 'grid' | 'column' | 'flow'): void;
|
|
86
|
-
focusNode(id: string
|
|
86
|
+
focusNode(id: string, options?: {
|
|
87
|
+
noPan?: boolean;
|
|
88
|
+
}): {
|
|
89
|
+
focused: string;
|
|
90
|
+
panned: boolean;
|
|
91
|
+
} | null;
|
|
87
92
|
getLayout(): CanvasLayout;
|
|
88
93
|
getNode(id: string): CanvasNodeState | undefined;
|
|
89
94
|
search(query: string): ReturnType<typeof searchNodes>;
|
|
@@ -190,6 +195,7 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
190
195
|
height?: number;
|
|
191
196
|
}): Promise<{
|
|
192
197
|
ok: true;
|
|
198
|
+
id?: string;
|
|
193
199
|
nodeId: string | null;
|
|
194
200
|
toolCallId: string;
|
|
195
201
|
sessionId: string;
|
|
@@ -197,6 +203,7 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
197
203
|
}>;
|
|
198
204
|
addDiagram(input: DiagramPresetOpenInput): Promise<{
|
|
199
205
|
ok: true;
|
|
206
|
+
id?: string;
|
|
200
207
|
nodeId: string | null;
|
|
201
208
|
toolCallId: string;
|
|
202
209
|
sessionId: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmx-canvas",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
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",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"test:coverage": "bun test tests/unit --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir coverage",
|
|
45
45
|
"test:web-canvas": "PMX_CANVAS_DISABLE_BROWSER_OPEN=1 bun run build && PMX_CANVAS_DISABLE_BROWSER_OPEN=1 bun x playwright test",
|
|
46
46
|
"test:e2e": "bun run test:web-canvas",
|
|
47
|
+
"test:e2e-cli": "bash scripts/e2e-cli-coverage.sh",
|
|
47
48
|
"test:web-canvas:headed": "bun run build && bun x playwright test --headed",
|
|
48
49
|
"test:e2e:headed": "bun run test:web-canvas:headed",
|
|
49
50
|
"test:all": "bun run test && bun run test:web-canvas",
|
|
@@ -10,7 +10,7 @@ description: >
|
|
|
10
10
|
working memory — pin nodes to curate context, read spatial arrangement to understand intent.
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
# PMX Canvas
|
|
13
|
+
# PMX Canvas - Agent Skill
|
|
14
14
|
|
|
15
15
|
PMX Canvas is a spatial canvas workbench you control through MCP tools or HTTP API. It renders an
|
|
16
16
|
infinite 2D canvas in the browser with nodes, edges, groups, pan/zoom, and a minimap. State lives
|
|
@@ -33,6 +33,10 @@ relatedness, clusters imply grouping, reading order (top-left to bottom-right) i
|
|
|
33
33
|
|
|
34
34
|
## Starting the Canvas
|
|
35
35
|
|
|
36
|
+
If this skill is installed before the `pmx-canvas` command exists, install the project first. See
|
|
37
|
+
`references/installing-pmx-canvas.md` for local development, npm/global install, and MCP config
|
|
38
|
+
options.
|
|
39
|
+
|
|
36
40
|
The canvas auto-starts on first MCP tool call when running in MCP mode (`pmx-canvas --mcp`).
|
|
37
41
|
For manual start:
|
|
38
42
|
|
|
@@ -80,7 +84,9 @@ pmx-canvas layout # Full canvas state
|
|
|
80
84
|
pmx-canvas status # Quick summary
|
|
81
85
|
pmx-canvas node add --type markdown --title "Plan"
|
|
82
86
|
pmx-canvas node add --type webpage --url https://example.com/docs
|
|
83
|
-
pmx-canvas node add --type
|
|
87
|
+
pmx-canvas node add --type graph --graph-type bar --data '[{"x":"a","y":1}]' --x-key x --y-key y
|
|
88
|
+
pmx-canvas node add --type graph --graphType bar --data '[{"x":"a","y":1}]' --xKey x --yKey y
|
|
89
|
+
pmx-canvas external-app add --kind excalidraw --title "Diagram"
|
|
84
90
|
pmx-canvas node add --help --type webpage --json
|
|
85
91
|
pmx-canvas node schema --type json-render --component Table --summary
|
|
86
92
|
pmx-canvas node list --type file --ids
|
|
@@ -88,8 +94,11 @@ pmx-canvas edge add --from node-a --to node-b --type depends-on
|
|
|
88
94
|
pmx-canvas search "auth"
|
|
89
95
|
pmx-canvas open
|
|
90
96
|
pmx-canvas arrange --layout flow
|
|
97
|
+
pmx-canvas focus <node-id> --no-pan # Select/raise without moving the user's viewport
|
|
91
98
|
pmx-canvas validate spec --type json-render --spec-file ./dashboard.json --summary
|
|
92
|
-
pmx-canvas web-artifact build --title "Dashboard" --app-file ./App.tsx --include-logs
|
|
99
|
+
pmx-canvas web-artifact build --title "Dashboard" --app-file ./App.tsx --deps recharts --include-logs
|
|
100
|
+
pmx-canvas node list --type web-artifact --summary
|
|
101
|
+
pmx-canvas node list --type external-app --summary
|
|
93
102
|
pmx-canvas pin --list
|
|
94
103
|
pmx-canvas snapshot save --name "before-refactor"
|
|
95
104
|
pmx-canvas code-graph
|
|
@@ -100,10 +109,12 @@ pmx-canvas spatial
|
|
|
100
109
|
|
|
101
110
|
- `node add|list|get|update|remove` — manage nodes
|
|
102
111
|
- `node schema` — inspect running-server create schemas and canonical examples, with `--summary`, `--field`, and `--component` filters
|
|
112
|
+
- Graph CLI fields accept both kebab-case flags and camelCase schema names, e.g. `--graph-type`/`--graphType`, `--x-key`/`--xKey`, and `--bar-color`/`--barColor`.
|
|
103
113
|
- `edge add|list|remove` — manage edges
|
|
104
114
|
- Search-based edge selectors must be specific enough to resolve exactly one node. Queries like
|
|
105
115
|
`"DVT O3"` can be ambiguous; prefer the full visible title such as `"DVT O3 — GitOps"`.
|
|
106
|
-
- `search`, `layout`, `status`, `arrange`, `focus` — inspect and navigate the canvas
|
|
116
|
+
- `search`, `layout`, `status`, `arrange`, `focus` — inspect and navigate the canvas. Prefer
|
|
117
|
+
`focus --no-pan` when you only need to select/raise a node without hijacking the human's camera.
|
|
107
118
|
- `open` — open the current workbench in the browser
|
|
108
119
|
- `pin --list|--clear|<ids...>` — manage context pins
|
|
109
120
|
- `undo`, `redo`, `history` — time travel
|
|
@@ -111,6 +122,8 @@ pmx-canvas spatial
|
|
|
111
122
|
- `group create|add|remove` — manage groups
|
|
112
123
|
- `clear --yes` — destructive clear with explicit confirmation
|
|
113
124
|
- `validate spec` — validate json-render specs and graph payloads without creating nodes
|
|
125
|
+
- `web-artifact build` — build bundled React/Tailwind HTML artifacts; use `--deps` for extra packages and `--include-logs` only when raw logs are useful
|
|
126
|
+
- `external-app add --kind excalidraw` — create the hosted Excalidraw preset; response includes `id` and `nodeId` aliases for the same canvas node
|
|
114
127
|
- `serve status|stop` — inspect and stop daemonized servers started with `serve --daemon`
|
|
115
128
|
- `code-graph`, `spatial` — analysis commands
|
|
116
129
|
|
|
@@ -120,10 +133,12 @@ Current caveat:
|
|
|
120
133
|
through search later in the session. When you plan to curate an app-heavy comparison area,
|
|
121
134
|
capture node IDs immediately after creation and verify membership with `node get --summary`,
|
|
122
135
|
`layout --summary`, or the browser selection state instead of relying on search alone.
|
|
123
|
-
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
136
|
+
- App-like nodes persist as `type: "mcp-app"` internally but serialized results include `kind`:
|
|
137
|
+
`web-artifact`, `external-app`, or `mcp-app`. Prefer `node list --type web-artifact` or
|
|
138
|
+
`node list --type external-app` when you need the operational subtype.
|
|
139
|
+
- Generic `pmx-canvas node add --type mcp-app` is intentionally not supported because app nodes
|
|
140
|
+
need app/session metadata. Use `pmx-canvas web-artifact build` for bundled React artifacts or
|
|
141
|
+
`pmx-canvas external-app add --kind excalidraw` for the Excalidraw preset.
|
|
127
142
|
|
|
128
143
|
The CLI targets `http://localhost:4313` by default. Override with `PMX_CANVAS_URL` or
|
|
129
144
|
`PMX_CANVAS_PORT` when the canvas is running elsewhere.
|
|
@@ -141,7 +156,7 @@ The CLI targets `http://localhost:4313` by default. Override with `PMX_CANVAS_UR
|
|
|
141
156
|
| `context` | Context card | Key context the human should see |
|
|
142
157
|
| `ledger` | Log/ledger viewer | Structured log data, audit trails |
|
|
143
158
|
| `trace` | Trace/timeline viewer | Execution traces, timelines |
|
|
144
|
-
| `mcp-app` | Hosted app/embed frame |
|
|
159
|
+
| `mcp-app` | Hosted app/embed frame | Tool-backed MCP apps or external app content; not generic CLI-created notes |
|
|
145
160
|
| `json-render` | Native structured UI panel | Dashboards, forms, tables, interactive layouts from json-render specs |
|
|
146
161
|
| `graph` | Native chart panel | Line, bar, pie, area, scatter, radar, stacked-bar, and composed charts rendered inside the canvas |
|
|
147
162
|
| `group` | Spatial container/frame | Visually group related nodes together |
|
|
@@ -267,6 +282,8 @@ Use color consistently to convey meaning:
|
|
|
267
282
|
**`canvas_focus_node`** — Pan viewport to center on a specific node
|
|
268
283
|
- `id` (required): node to focus
|
|
269
284
|
- Good for drawing the human's attention
|
|
285
|
+
- Avoid focusing every node in a batch. Focus only the final result or use CLI `focus --no-pan`
|
|
286
|
+
when the goal is selection/raising without camera movement.
|
|
270
287
|
|
|
271
288
|
### Groups
|
|
272
289
|
|
|
@@ -360,6 +377,9 @@ Current product caveats for grouped comparison boards:
|
|
|
360
377
|
text). Can also be a JSON-array string.
|
|
361
378
|
- Optional: `title`, `x`, `y`, `width`, `height`
|
|
362
379
|
- The diagram opens inside an `mcp-app` node with fullscreen editing and draw-on animations
|
|
380
|
+
- CLI equivalent: `pmx-canvas external-app add --kind excalidraw --title "Diagram"`
|
|
381
|
+
- Edits made in expanded/fullscreen mode are persisted back into the node model context and replayed
|
|
382
|
+
when the app iframe remounts.
|
|
363
383
|
- Use this when the human needs a quick sketch, architecture diagram, or flowchart and a
|
|
364
384
|
geometric `graph` node would feel too rigid
|
|
365
385
|
- Prefer labeled shapes (`"label": { "text": "..." }` on rectangle/ellipse/diamond) over
|
|
@@ -380,9 +400,12 @@ server's `ui://` resource as an iframe node on the canvas
|
|
|
380
400
|
|
|
381
401
|
**`canvas_build_web_artifact`** — Build a single-file HTML artifact from React/Tailwind source
|
|
382
402
|
- Required: `title`, `appTsx`
|
|
383
|
-
- Optional: `indexCss`, `mainTsx`, `indexHtml`, extra `files`, `projectPath`, `outputPath`, `includeLogs`
|
|
403
|
+
- Optional: `indexCss`, `mainTsx`, `indexHtml`, extra `files`, `projectPath`, `outputPath`, `deps`, `includeLogs`
|
|
384
404
|
- By default it opens the result on the canvas as an embedded app node
|
|
385
405
|
- By default it returns compact log summaries; set `includeLogs: true` when you need raw stdout/stderr
|
|
406
|
+
- `recharts` is available in the scaffold. For additional libraries, pass CLI `--deps name,name2`
|
|
407
|
+
or MCP/API `deps: ["name"]` before bundling.
|
|
408
|
+
- Failed or empty CLI bundles print `ok: false`, exit non-zero, and do not create a canvas node.
|
|
386
409
|
- Use this when the output should be a richer interactive UI than a simple markdown/file/image node
|
|
387
410
|
- Prefer the dedicated `web-artifacts-builder` skill when you need the full React + shadcn workflow
|
|
388
411
|
- Use the `playwright-cli` skill when you need to validate the built artifact in a live browser
|
|
@@ -451,6 +474,8 @@ All POST/PATCH endpoints accept `Content-Type: application/json`. Default base U
|
|
|
451
474
|
| GET | `/api/canvas/schema` | Get running-server create schemas, examples, and json-render catalog metadata |
|
|
452
475
|
| POST | `/api/canvas/schema/validate` | Validate a json-render spec or graph payload without creating a node |
|
|
453
476
|
| GET | `/api/canvas/json-render/view?nodeId=...` | View a native json-render or graph node |
|
|
477
|
+
| POST | `/api/canvas/diagram` | Create an Excalidraw external app node |
|
|
478
|
+
| POST | `/api/canvas/mcp-app/open` | Open a tool-backed MCP app node |
|
|
454
479
|
| POST | `/api/canvas/web-artifact` | Build a bundled web artifact and optionally open it on canvas |
|
|
455
480
|
| POST | `/api/canvas/group` | Create group |
|
|
456
481
|
| POST | `/api/canvas/group/add` | Add nodes to group |
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Installing PMX Canvas
|
|
2
|
+
|
|
3
|
+
Use this reference when the `pmx-canvas` skill is installed but the `pmx-canvas` command is not available yet.
|
|
4
|
+
|
|
5
|
+
## From npm
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g pmx-canvas
|
|
9
|
+
pmx-canvas serve --daemon --no-open --wait-ms=20000
|
|
10
|
+
pmx-canvas open
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## From a local checkout
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
git clone https://github.com/pskoett/pmx-canvas.git
|
|
17
|
+
cd pmx-canvas
|
|
18
|
+
bun install
|
|
19
|
+
bun run build
|
|
20
|
+
bun run src/cli/index.ts serve --daemon --no-open --wait-ms=20000
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
For development, run commands through Bun from the checkout:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bun run src/cli/index.ts status
|
|
27
|
+
bun run src/cli/index.ts node add --type markdown --title "Hello" --content "# PMX"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## MCP Config
|
|
31
|
+
|
|
32
|
+
For agents that support MCP, configure PMX Canvas as a stdio MCP server:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"canvas": {
|
|
38
|
+
"command": "bunx",
|
|
39
|
+
"args": ["pmx-canvas", "--mcp"]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If you are using a local checkout instead of the published package, point the command at the CLI entry:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"mcpServers": {
|
|
50
|
+
"canvas": {
|
|
51
|
+
"command": "bun",
|
|
52
|
+
"args": ["run", "/path/to/pmx-canvas/src/cli/index.ts", "--mcp"]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Verify
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pmx-canvas --version
|
|
62
|
+
pmx-canvas serve status
|
|
63
|
+
pmx-canvas layout
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The CLI defaults to `http://localhost:4313`. Override with `PMX_CANVAS_URL` or `PMX_CANVAS_PORT` if the server runs elsewhere.
|
|
@@ -152,10 +152,20 @@ rm -rf dist bundle.html
|
|
|
152
152
|
echo "🔨 Building with Parcel..."
|
|
153
153
|
run_with_filtered_stderr run_local_binary parcel build index.html --dist-dir dist --no-source-maps --log-level error
|
|
154
154
|
|
|
155
|
+
if [ ! -s "dist/index.html" ]; then
|
|
156
|
+
echo "❌ Error: Parcel did not produce dist/index.html" >&2
|
|
157
|
+
exit 1
|
|
158
|
+
fi
|
|
159
|
+
|
|
155
160
|
# Inline everything into single HTML
|
|
156
161
|
echo "🎯 Inlining all assets into single HTML file..."
|
|
157
162
|
run_with_filtered_stderr run_local_binary html-inline dist/index.html > bundle.html
|
|
158
163
|
|
|
164
|
+
if [ ! -s "bundle.html" ]; then
|
|
165
|
+
echo "❌ Error: Bundled artifact is empty" >&2
|
|
166
|
+
exit 1
|
|
167
|
+
fi
|
|
168
|
+
|
|
159
169
|
# Get file size
|
|
160
170
|
FILE_SIZE=$(du -h bundle.html | cut -f1)
|
|
161
171
|
|
|
@@ -172,7 +172,7 @@ fi
|
|
|
172
172
|
|
|
173
173
|
echo "📦 Installing Tailwind CSS and dependencies..."
|
|
174
174
|
run_pnpm_allow_build add -D tailwindcss@3.4.1 postcss @types/node tailwindcss-animate parcel @parcel/config-default parcel-resolver-tspaths html-inline
|
|
175
|
-
run_pnpm_quiet add class-variance-authority clsx tailwind-merge lucide-react next-themes
|
|
175
|
+
run_pnpm_quiet add class-variance-authority clsx tailwind-merge lucide-react next-themes recharts
|
|
176
176
|
|
|
177
177
|
echo "⚙️ Creating Tailwind and PostCSS configuration..."
|
|
178
178
|
cat > .postcssrc.json << 'EOF'
|