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.
Files changed (42) hide show
  1. package/CHANGELOG.md +144 -0
  2. package/Readme.md +35 -8
  3. package/dist/canvas/index.js +69 -69
  4. package/dist/json-render/index.css +1 -1
  5. package/dist/json-render/index.js +1 -1
  6. package/dist/types/client/nodes/ExtAppFrame.d.ts +12 -0
  7. package/dist/types/client/state/canvas-store.d.ts +2 -1
  8. package/dist/types/client/types.d.ts +3 -0
  9. package/dist/types/json-render/charts/components.d.ts +2 -1
  10. package/dist/types/server/canvas-serialization.d.ts +1 -0
  11. package/dist/types/server/diagram-presets.d.ts +13 -0
  12. package/dist/types/server/ext-app-lookup.d.ts +22 -0
  13. package/dist/types/server/index.d.ts +8 -1
  14. package/dist/types/server/web-artifacts.d.ts +1 -0
  15. package/package.json +2 -1
  16. package/skills/pmx-canvas/SKILL.md +35 -10
  17. package/skills/pmx-canvas/references/installing-pmx-canvas.md +66 -0
  18. package/skills/web-artifacts-builder/scripts/bundle-artifact.sh +10 -0
  19. package/skills/web-artifacts-builder/scripts/init-artifact.sh +1 -1
  20. package/src/cli/agent.ts +114 -21
  21. package/src/cli/index.ts +3 -1
  22. package/src/client/App.tsx +2 -1
  23. package/src/client/canvas/CanvasNode.tsx +3 -2
  24. package/src/client/canvas/ExpandedNodeOverlay.tsx +6 -1
  25. package/src/client/nodes/ExtAppFrame.tsx +97 -26
  26. package/src/client/state/canvas-store.ts +63 -1
  27. package/src/client/state/sse-bridge.ts +19 -4
  28. package/src/client/types.ts +12 -0
  29. package/src/json-render/charts/components.tsx +6 -4
  30. package/src/json-render/charts/extra-components.tsx +5 -5
  31. package/src/json-render/renderer/index.css +14 -0
  32. package/src/mcp/server.ts +44 -5
  33. package/src/server/canvas-operations.ts +43 -5
  34. package/src/server/canvas-schema.ts +16 -14
  35. package/src/server/canvas-serialization.ts +19 -1
  36. package/src/server/diagram-presets.ts +219 -4
  37. package/src/server/ext-app-lookup.ts +49 -0
  38. package/src/server/index.ts +33 -25
  39. package/src/server/server.ts +199 -45
  40. package/src/server/web-artifacts/scripts/bundle-artifact.sh +10 -0
  41. package/src/server/web-artifacts/scripts/init-artifact.sh +1 -1
  42. 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 { CanvasEdge, CanvasLayout, CanvasNodeState, ConnectionStatus, ViewportState } from '../types';
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): void;
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;
@@ -9,6 +9,7 @@ export interface WebArtifactBuildInput {
9
9
  outputPath?: string;
10
10
  initScriptPath?: string;
11
11
  bundleScriptPath?: string;
12
+ deps?: string[];
12
13
  timeoutMs?: number;
13
14
  }
14
15
  export interface WebArtifactBuildOutput {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmx-canvas",
3
- "version": "0.1.2",
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 Agent Skill
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 web-artifact --title "Dashboard" --app-file ./App.tsx
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
- - Some `mcp-app` creation flows are still awkward to address immediately after creation. If a
124
- diagram/app flow gives you a session-oriented result first, resolve the final canvas node from
125
- live layout or `node list --type mcp-app` before you try to group it, wire edges to it, or
126
- revisit it later.
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 | Embedded MCP apps or external app content |
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'