pmx-canvas 0.1.19 → 0.1.21
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 +159 -0
- package/Readme.md +19 -6
- package/dist/canvas/global.css +123 -2
- package/dist/canvas/index.js +103 -68
- package/dist/json-render/index.js +109 -109
- package/dist/types/client/canvas/CanvasViewport.d.ts +1 -1
- package/dist/types/client/icons.d.ts +2 -0
- package/dist/types/client/nodes/HtmlNode.d.ts +12 -1
- package/dist/types/client/state/canvas-store.d.ts +2 -0
- package/dist/types/client/types.d.ts +3 -2
- package/dist/types/json-render/charts/components.d.ts +5 -1
- package/dist/types/json-render/renderer/index.d.ts +1 -0
- package/dist/types/json-render/server.d.ts +1 -0
- package/dist/types/mcp/canvas-access.d.ts +3 -0
- package/dist/types/server/canvas-operations.d.ts +4 -0
- package/dist/types/server/canvas-schema.d.ts +19 -3
- package/dist/types/server/canvas-serialization.d.ts +1 -0
- package/dist/types/server/canvas-state.d.ts +6 -2
- package/dist/types/server/html-node-summary.d.ts +2 -0
- package/dist/types/server/html-primitives.d.ts +42 -0
- package/dist/types/server/index.d.ts +26 -0
- package/docs/cli.md +4 -1
- package/docs/http-api.md +11 -1
- package/docs/mcp.md +10 -4
- package/docs/node-types.md +54 -4
- package/docs/screenshot.png +0 -0
- package/docs/sdk.md +12 -0
- package/package.json +1 -1
- package/skills/pmx-canvas/SKILL.md +17 -3
- package/skills/pmx-canvas/references/html-primitives.md +132 -0
- package/src/cli/agent.ts +159 -5
- package/src/cli/index.ts +1 -1
- package/src/client/App.tsx +21 -2
- package/src/client/canvas/AnnotationLayer.tsx +33 -12
- package/src/client/canvas/CanvasViewport.tsx +88 -7
- package/src/client/canvas/CommandPalette.tsx +2 -2
- package/src/client/canvas/ContextMenu.tsx +2 -2
- package/src/client/canvas/ExpandedNodeOverlay.tsx +112 -3
- package/src/client/canvas/auto-fit.ts +5 -1
- package/src/client/icons.tsx +13 -0
- package/src/client/nodes/HtmlNode.tsx +125 -13
- package/src/client/nodes/McpAppNode.tsx +12 -4
- package/src/client/state/canvas-store.ts +15 -5
- package/src/client/state/sse-bridge.ts +5 -4
- package/src/client/theme/global.css +123 -2
- package/src/client/types.ts +2 -1
- package/src/json-render/charts/components.tsx +41 -7
- package/src/json-render/charts/extra-components.tsx +13 -12
- package/src/json-render/renderer/index.tsx +1 -0
- package/src/json-render/server.ts +3 -1
- package/src/mcp/canvas-access.ts +54 -1
- package/src/mcp/server.ts +98 -28
- package/src/server/agent-context.ts +39 -0
- package/src/server/canvas-operations.ts +99 -38
- package/src/server/canvas-provenance.ts +8 -6
- package/src/server/canvas-schema.ts +94 -3
- package/src/server/canvas-serialization.ts +16 -4
- package/src/server/canvas-state.ts +9 -4
- package/src/server/demo-state.json +1143 -0
- package/src/server/demo.ts +25 -777
- package/src/server/html-node-summary.ts +141 -0
- package/src/server/html-primitives.ts +1300 -0
- package/src/server/index.ts +63 -3
- package/src/server/server.ts +154 -17
- package/src/server/spatial-analysis.ts +5 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CanvasNodeState } from '../types';
|
|
2
|
-
type AnnotationTool = 'pen' | 'eraser' | null;
|
|
2
|
+
type AnnotationTool = 'pen' | 'eraser' | 'text' | null;
|
|
3
3
|
interface CanvasViewportProps {
|
|
4
4
|
onNodeContextMenu?: (e: MouseEvent, nodeId: string) => void;
|
|
5
5
|
onCanvasContextMenu?: (e: MouseEvent, canvasX: number, canvasY: number) => void;
|
|
@@ -23,6 +23,8 @@ export declare function IconMoon(p: IconProps): JSX.Element;
|
|
|
23
23
|
export declare function IconPen(p: IconProps): JSX.Element;
|
|
24
24
|
/** Eraser — remove canvas annotations */
|
|
25
25
|
export declare function IconEraser(p: IconProps): JSX.Element;
|
|
26
|
+
/** Text cursor — canvas text annotation mode */
|
|
27
|
+
export declare function IconTextAnnotation(p: IconProps): JSX.Element;
|
|
26
28
|
/** Camera — snapshots */
|
|
27
29
|
export declare function IconSnapshot(p: IconProps): JSX.Element;
|
|
28
30
|
/** Bullseye — trace toggle */
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import type { CanvasNodeState } from '../types';
|
|
2
|
-
export declare function
|
|
2
|
+
export declare function createHtmlNodeSrcDocForTest(userHtml: string, options: {
|
|
3
|
+
theme: string;
|
|
4
|
+
themeCss: string;
|
|
5
|
+
themeToken?: string;
|
|
6
|
+
presentation?: boolean;
|
|
7
|
+
presentationExitToken?: string;
|
|
8
|
+
}): string;
|
|
9
|
+
export declare function shouldShowPresentationControls(node: CanvasNodeState): boolean;
|
|
10
|
+
export declare function HtmlNode({ node, expanded, presentation, presentationExitToken, autoFocus, }: {
|
|
3
11
|
node: CanvasNodeState;
|
|
4
12
|
expanded?: boolean;
|
|
13
|
+
presentation?: boolean;
|
|
14
|
+
presentationExitToken?: string;
|
|
15
|
+
autoFocus?: boolean;
|
|
5
16
|
}): import("preact/src").JSX.Element;
|
|
@@ -45,9 +45,11 @@ export declare function removeEdgesForNode(nodeId: string): void;
|
|
|
45
45
|
export declare function addAnnotation(annotation: CanvasAnnotation): void;
|
|
46
46
|
export declare function removeAnnotation(id: string): void;
|
|
47
47
|
export declare function createAnnotationFromClient(input: {
|
|
48
|
+
type?: CanvasAnnotation['type'];
|
|
48
49
|
points: CanvasAnnotation['points'];
|
|
49
50
|
color: string;
|
|
50
51
|
width: number;
|
|
52
|
+
text?: string;
|
|
51
53
|
label?: string;
|
|
52
54
|
}): Promise<{
|
|
53
55
|
ok: boolean;
|
|
@@ -35,7 +35,7 @@ export interface CanvasAnnotationPoint {
|
|
|
35
35
|
}
|
|
36
36
|
export interface CanvasAnnotation {
|
|
37
37
|
id: string;
|
|
38
|
-
type: 'freehand';
|
|
38
|
+
type: 'freehand' | 'text';
|
|
39
39
|
points: CanvasAnnotationPoint[];
|
|
40
40
|
bounds: {
|
|
41
41
|
x: number;
|
|
@@ -45,13 +45,14 @@ export interface CanvasAnnotation {
|
|
|
45
45
|
};
|
|
46
46
|
color: string;
|
|
47
47
|
width: number;
|
|
48
|
+
text?: string;
|
|
48
49
|
label?: string;
|
|
49
50
|
createdAt: string;
|
|
50
51
|
}
|
|
51
52
|
export type ConnectionStatus = 'connecting' | 'connected' | 'disconnected';
|
|
52
53
|
export declare const TYPE_LABELS: Record<CanvasNodeState['type'], string>;
|
|
53
54
|
/** Node types that support the full-viewport expand/focus overlay. */
|
|
54
|
-
export declare const EXPANDABLE_TYPES: Set<"markdown" | "mcp-app" | "webpage" | "json-render" | "graph" | "prompt" | "response" | "status" | "context" | "ledger" | "trace" | "file" | "image" | "
|
|
55
|
+
export declare const EXPANDABLE_TYPES: Set<"html" | "markdown" | "mcp-app" | "webpage" | "json-render" | "graph" | "prompt" | "response" | "status" | "context" | "ledger" | "trace" | "file" | "image" | "group">;
|
|
55
56
|
export declare const EXCALIDRAW_SERVER_NAME = "Excalidraw";
|
|
56
57
|
export declare const EXCALIDRAW_CREATE_VIEW_TOOL = "create_view";
|
|
57
58
|
export declare function isExcalidrawNode(node: CanvasNodeState): boolean;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* chat example. Each component receives BaseComponentProps<T> and renders
|
|
7
7
|
* a responsive chart inside a styled container.
|
|
8
8
|
*/
|
|
9
|
-
import type
|
|
9
|
+
import { type ReactNode } from 'react';
|
|
10
10
|
import type { BaseComponentProps } from '@json-render/react';
|
|
11
11
|
export declare const CHART_COLORS: string[];
|
|
12
12
|
export type AggregateMode = 'sum' | 'count' | 'avg';
|
|
@@ -56,6 +56,10 @@ export declare const axisTickMargin = 8;
|
|
|
56
56
|
export declare const legendMargin: {
|
|
57
57
|
top: number;
|
|
58
58
|
};
|
|
59
|
+
export declare function useChartFrameHeight(explicitHeight: number | null | undefined, fallbackHeight?: number): {
|
|
60
|
+
frameRef: import("react").RefObject<HTMLDivElement | null>;
|
|
61
|
+
height: number;
|
|
62
|
+
};
|
|
59
63
|
/** Shared wrapper for cartesian charts (Line + Bar). */
|
|
60
64
|
export declare function CartesianChart({ props, children, className, }: {
|
|
61
65
|
props: CartesianChartProps;
|
|
@@ -8,6 +8,8 @@ type AddDiagramInput = Parameters<PmxCanvas['addDiagram']>[0];
|
|
|
8
8
|
type AddJsonRenderNodeInput = Parameters<PmxCanvas['addJsonRenderNode']>[0];
|
|
9
9
|
type AddJsonRenderNodeResult = ReturnType<PmxCanvas['addJsonRenderNode']>;
|
|
10
10
|
type AddHtmlNodeInput = Parameters<PmxCanvas['addHtmlNode']>[0];
|
|
11
|
+
type AddHtmlPrimitiveInput = Parameters<PmxCanvas['addHtmlPrimitive']>[0];
|
|
12
|
+
type AddHtmlPrimitiveResult = ReturnType<PmxCanvas['addHtmlPrimitive']>;
|
|
11
13
|
type AddGraphNodeInput = Parameters<PmxCanvas['addGraphNode']>[0];
|
|
12
14
|
type AddGraphNodeResult = ReturnType<PmxCanvas['addGraphNode']>;
|
|
13
15
|
type UpdateNodePatch = Parameters<PmxCanvas['updateNode']>[1];
|
|
@@ -50,6 +52,7 @@ export interface CanvasAccess {
|
|
|
50
52
|
addDiagram(input: AddDiagramInput): Promise<OpenMcpAppResult>;
|
|
51
53
|
addJsonRenderNode(input: AddJsonRenderNodeInput): Promise<AddJsonRenderNodeResult>;
|
|
52
54
|
addHtmlNode(input: AddHtmlNodeInput): Promise<string>;
|
|
55
|
+
addHtmlPrimitive(input: AddHtmlPrimitiveInput): Promise<AddHtmlPrimitiveResult>;
|
|
53
56
|
addGraphNode(input: AddGraphNodeInput): Promise<AddGraphNodeResult>;
|
|
54
57
|
buildWebArtifact(input: WebArtifactInput): Promise<WebArtifactResult>;
|
|
55
58
|
updateNode(id: string, patch: UpdateNodePatch): Promise<void>;
|
|
@@ -56,6 +56,10 @@ interface CanvasAddNodeInput {
|
|
|
56
56
|
fileMode?: 'path' | 'inline' | 'auto';
|
|
57
57
|
strictSize?: boolean;
|
|
58
58
|
}
|
|
59
|
+
export declare const MARKDOWN_NODE_DEFAULT_SIZE: {
|
|
60
|
+
width: number;
|
|
61
|
+
height: number;
|
|
62
|
+
};
|
|
59
63
|
interface CanvasCreateGroupInput {
|
|
60
64
|
title?: string;
|
|
61
65
|
childIds?: string[];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type JsonRenderComponentDescriptor } from '../json-render/catalog.js';
|
|
2
2
|
import { type GraphNodeInput, type JsonRenderSpec } from '../json-render/server.js';
|
|
3
|
+
import { type HtmlPrimitiveDescriptor } from './html-primitives.js';
|
|
3
4
|
export interface CanvasCreateField {
|
|
4
5
|
name: string;
|
|
5
6
|
type: string;
|
|
@@ -19,8 +20,17 @@ export interface CanvasCreateTypeSchema {
|
|
|
19
20
|
}
|
|
20
21
|
export interface StructuredValidationResult {
|
|
21
22
|
ok: true;
|
|
22
|
-
type: 'json-render' | 'graph';
|
|
23
|
-
normalizedSpec
|
|
23
|
+
type: 'json-render' | 'graph' | 'html-primitive';
|
|
24
|
+
normalizedSpec?: JsonRenderSpec;
|
|
25
|
+
normalizedPrimitive?: {
|
|
26
|
+
kind: string;
|
|
27
|
+
title: string;
|
|
28
|
+
htmlBytes: number;
|
|
29
|
+
defaultSize: {
|
|
30
|
+
width: number;
|
|
31
|
+
height: number;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
24
34
|
summary: Record<string, unknown>;
|
|
25
35
|
}
|
|
26
36
|
declare const CANONICAL_GRAPH_TYPES: readonly ["line", "bar", "pie", "area", "scatter", "radar", "stacked-bar", "composed"];
|
|
@@ -37,6 +47,7 @@ export declare function describeCanvasSchema(): {
|
|
|
37
47
|
graph: {
|
|
38
48
|
graphTypes: CanvasGraphType[];
|
|
39
49
|
};
|
|
50
|
+
htmlPrimitives: HtmlPrimitiveDescriptor[];
|
|
40
51
|
mcp: {
|
|
41
52
|
tools: string[];
|
|
42
53
|
resources: string[];
|
|
@@ -44,8 +55,13 @@ export declare function describeCanvasSchema(): {
|
|
|
44
55
|
};
|
|
45
56
|
};
|
|
46
57
|
export declare function validateStructuredCanvasPayload(input: {
|
|
47
|
-
type: 'json-render' | 'graph';
|
|
58
|
+
type: 'json-render' | 'graph' | 'html-primitive';
|
|
48
59
|
spec?: unknown;
|
|
49
60
|
graph?: GraphNodeInput;
|
|
61
|
+
primitive?: {
|
|
62
|
+
kind: string;
|
|
63
|
+
title?: string;
|
|
64
|
+
data?: Record<string, unknown>;
|
|
65
|
+
};
|
|
50
66
|
}): StructuredValidationResult;
|
|
51
67
|
export {};
|
|
@@ -90,7 +90,7 @@ export interface CanvasAnnotationPoint {
|
|
|
90
90
|
}
|
|
91
91
|
export interface CanvasAnnotation {
|
|
92
92
|
id: string;
|
|
93
|
-
type: 'freehand';
|
|
93
|
+
type: 'freehand' | 'text';
|
|
94
94
|
points: CanvasAnnotationPoint[];
|
|
95
95
|
bounds: {
|
|
96
96
|
x: number;
|
|
@@ -100,6 +100,7 @@ export interface CanvasAnnotation {
|
|
|
100
100
|
};
|
|
101
101
|
color: string;
|
|
102
102
|
width: number;
|
|
103
|
+
text?: string;
|
|
103
104
|
label?: string;
|
|
104
105
|
createdAt: string;
|
|
105
106
|
}
|
|
@@ -134,6 +135,9 @@ interface GroupNodesOptions {
|
|
|
134
135
|
layout?: 'grid' | 'column' | 'flow';
|
|
135
136
|
keepGroupFrame?: boolean;
|
|
136
137
|
}
|
|
138
|
+
interface ApplyUpdatesOptions {
|
|
139
|
+
skipGroupChildTranslation?: boolean;
|
|
140
|
+
}
|
|
137
141
|
declare class CanvasStateManager {
|
|
138
142
|
private nodes;
|
|
139
143
|
private edges;
|
|
@@ -231,7 +235,7 @@ declare class CanvasStateManager {
|
|
|
231
235
|
private removeEdgesForNode;
|
|
232
236
|
getLayout(): CanvasLayout;
|
|
233
237
|
getLayoutForPersistence(): CanvasLayout;
|
|
234
|
-
applyUpdates(updates: CanvasNodeUpdate[]): {
|
|
238
|
+
applyUpdates(updates: CanvasNodeUpdate[], options?: ApplyUpdatesOptions): {
|
|
235
239
|
applied: number;
|
|
236
240
|
skipped: number;
|
|
237
241
|
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export declare const HTML_PRIMITIVE_KINDS: readonly ["choice-grid", "plan-timeline", "review-sheet", "pr-writeup", "system-map", "code-walkthrough", "design-sheet", "component-gallery", "interaction-prototype", "flowchart", "deck", "presentation", "illustration-set", "explainer", "status-report", "incident-report", "triage-board", "config-editor", "prompt-tuner"];
|
|
2
|
+
export type HtmlPrimitiveKind = typeof HTML_PRIMITIVE_KINDS[number];
|
|
3
|
+
export interface HtmlPrimitiveDescriptor {
|
|
4
|
+
kind: HtmlPrimitiveKind;
|
|
5
|
+
title: string;
|
|
6
|
+
description: string;
|
|
7
|
+
useWhen: string;
|
|
8
|
+
defaultSize: {
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
};
|
|
12
|
+
dataShape: string;
|
|
13
|
+
example: Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
export interface HtmlPrimitiveInput {
|
|
16
|
+
kind: HtmlPrimitiveKind;
|
|
17
|
+
title?: string;
|
|
18
|
+
data?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface HtmlPrimitiveBuildResult {
|
|
21
|
+
kind: HtmlPrimitiveKind;
|
|
22
|
+
title: string;
|
|
23
|
+
html: string;
|
|
24
|
+
summary: string;
|
|
25
|
+
defaultSize: {
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
};
|
|
29
|
+
data: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
export interface HtmlPrimitiveSemanticMetadata {
|
|
32
|
+
presentation?: true;
|
|
33
|
+
slideCount?: number;
|
|
34
|
+
slideTitles?: string[];
|
|
35
|
+
speakerNotes?: string[];
|
|
36
|
+
presentationTheme?: string | Record<string, string>;
|
|
37
|
+
}
|
|
38
|
+
export declare function isHtmlPrimitiveKind(value: string): value is HtmlPrimitiveKind;
|
|
39
|
+
export declare function getHtmlPrimitiveDescriptor(kind: HtmlPrimitiveKind): HtmlPrimitiveDescriptor;
|
|
40
|
+
export declare function listHtmlPrimitiveDescriptors(): HtmlPrimitiveDescriptor[];
|
|
41
|
+
export declare function getHtmlPrimitiveSemanticMetadata(data: Record<string, unknown>): HtmlPrimitiveSemanticMetadata;
|
|
42
|
+
export declare function buildHtmlPrimitive(input: HtmlPrimitiveInput): HtmlPrimitiveBuildResult;
|
|
@@ -3,6 +3,7 @@ import type { CanvasAnnotation, CanvasNodeState, CanvasEdge, CanvasLayout } from
|
|
|
3
3
|
import { searchNodes } from './spatial-analysis.js';
|
|
4
4
|
import { diffLayouts } from './mutation-history.js';
|
|
5
5
|
import { fitCanvasView, gcCanvasSnapshots, listCanvasSnapshots } from './canvas-operations.js';
|
|
6
|
+
import type { HtmlPrimitiveKind } from './html-primitives.js';
|
|
6
7
|
import { type WebArtifactBuildInput, type WebArtifactCanvasBuildResult } from './web-artifacts.js';
|
|
7
8
|
import { type ExternalMcpTransportConfig } from './mcp-app-runtime.js';
|
|
8
9
|
import { type DiagramPresetOpenInput } from './diagram-presets.js';
|
|
@@ -181,6 +182,7 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
181
182
|
graph: {
|
|
182
183
|
graphTypes: ("line" | "bar" | "pie" | "area" | "scatter" | "radar" | "composed" | "stacked-bar")[];
|
|
183
184
|
};
|
|
185
|
+
htmlPrimitives: import("./html-primitives.js").HtmlPrimitiveDescriptor[];
|
|
184
186
|
mcp: {
|
|
185
187
|
tools: string[];
|
|
186
188
|
resources: string[];
|
|
@@ -242,12 +244,34 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
242
244
|
addHtmlNode(input: {
|
|
243
245
|
html: string;
|
|
244
246
|
title?: string;
|
|
247
|
+
summary?: string;
|
|
248
|
+
agentSummary?: string;
|
|
249
|
+
description?: string;
|
|
250
|
+
presentation?: boolean;
|
|
251
|
+
slideTitles?: string[];
|
|
252
|
+
embeddedNodeIds?: string[];
|
|
253
|
+
embeddedUrls?: string[];
|
|
245
254
|
x?: number;
|
|
246
255
|
y?: number;
|
|
247
256
|
width?: number;
|
|
248
257
|
height?: number;
|
|
249
258
|
strictSize?: boolean;
|
|
250
259
|
}): string;
|
|
260
|
+
addHtmlPrimitive(input: {
|
|
261
|
+
kind: HtmlPrimitiveKind;
|
|
262
|
+
title?: string;
|
|
263
|
+
data?: Record<string, unknown>;
|
|
264
|
+
x?: number;
|
|
265
|
+
y?: number;
|
|
266
|
+
width?: number;
|
|
267
|
+
height?: number;
|
|
268
|
+
strictSize?: boolean;
|
|
269
|
+
}): {
|
|
270
|
+
id: string;
|
|
271
|
+
kind: HtmlPrimitiveKind;
|
|
272
|
+
title: string;
|
|
273
|
+
htmlBytes: number;
|
|
274
|
+
};
|
|
251
275
|
addGraphNode(input: GraphNodeInput): {
|
|
252
276
|
id: string;
|
|
253
277
|
url: string;
|
|
@@ -275,10 +299,12 @@ export type { SpatialCluster, SpatialContext, SpatialNeighbor, NodeSpatialInfo }
|
|
|
275
299
|
export { mutationHistory, diffLayouts, formatDiff } from './mutation-history.js';
|
|
276
300
|
export { recomputeCodeGraph, buildCodeGraphSummary, formatCodeGraph } from './code-graph.js';
|
|
277
301
|
export { describeCanvasSchema, validateStructuredCanvasPayload } from './canvas-schema.js';
|
|
302
|
+
export { buildHtmlPrimitive, getHtmlPrimitiveSemanticMetadata, isHtmlPrimitiveKind, listHtmlPrimitiveDescriptors } from './html-primitives.js';
|
|
278
303
|
export { buildWebArtifactOnCanvas, executeWebArtifactBuild, openWebArtifactInCanvas, resolveWebArtifactScriptPath, resolveWorkspacePath, } from './web-artifacts.js';
|
|
279
304
|
export { buildGraphSpec, buildJsonRenderViewerHtml, createJsonRenderNodeData, GRAPH_NODE_SIZE, JSON_RENDER_NODE_SIZE, normalizeAndValidateJsonRenderSpec, } from '../json-render/server.js';
|
|
280
305
|
export type { CodeGraphSummary, CodeGraphEdge } from './code-graph.js';
|
|
281
306
|
export type { MutationEntry, MutationSummary, SnapshotDiffResult } from './mutation-history.js';
|
|
282
307
|
export type { WebArtifactBuildInput, WebArtifactBuildOutput, WebArtifactCanvasBuildResult, WebArtifactCanvasOpenResult, } from './web-artifacts.js';
|
|
283
308
|
export type { GraphNodeInput, JsonRenderNodeInput, JsonRenderSpec } from '../json-render/server.js';
|
|
309
|
+
export type { HtmlPrimitiveKind, HtmlPrimitiveDescriptor, HtmlPrimitiveInput, HtmlPrimitiveBuildResult } from './html-primitives.js';
|
|
284
310
|
export { traceManager } from './trace-manager.js';
|
package/docs/cli.md
CHANGED
|
@@ -8,7 +8,7 @@ The CLI is the shell-native way to run and control PMX Canvas. It targets
|
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
pmx-canvas # Start canvas, open browser
|
|
11
|
-
pmx-canvas --demo # Start with the
|
|
11
|
+
pmx-canvas --demo # Start with the saved dashboard demo board
|
|
12
12
|
pmx-canvas --port=8080 # Custom port
|
|
13
13
|
pmx-canvas --no-open # Headless (for agents/CI)
|
|
14
14
|
pmx-canvas --theme=light # dark | light | high-contrast
|
|
@@ -35,6 +35,8 @@ pmx-canvas node add --type web-artifact --title "Dashboard" --app-file ./App.tsx
|
|
|
35
35
|
pmx-canvas node add --type graph --graph-type bar --data-file ./metrics.json --x-key label --y-key value
|
|
36
36
|
pmx-canvas node add --type graph --graph-type bar --data '[{"x":"a","y":1}]' --x-key x --y-key y
|
|
37
37
|
pmx-canvas graph add --graph-type bar --data '[{"x":"a","y":1}]' --x-key x --y-key y # Alias
|
|
38
|
+
pmx-canvas html primitive add --kind choice-grid --data-file ./options.json --title "Options"
|
|
39
|
+
pmx-canvas html primitive schema --summary
|
|
38
40
|
pmx-canvas node add --help --type webpage --json # Schema for one type
|
|
39
41
|
|
|
40
42
|
pmx-canvas external-app add --kind excalidraw --title "Diagram"
|
|
@@ -66,6 +68,7 @@ content.
|
|
|
66
68
|
pmx-canvas node schema --type json-render --component Table --summary
|
|
67
69
|
pmx-canvas validate # Layout validation
|
|
68
70
|
pmx-canvas validate spec --type json-render --spec-file ./dashboard.json --summary
|
|
71
|
+
pmx-canvas validate spec --type html-primitive --kind choice-grid --data-json '{"items":[{"title":"A"}]}' --summary
|
|
69
72
|
```
|
|
70
73
|
|
|
71
74
|
The schema commands surface the running server's data, which is strictly
|
package/docs/http-api.md
CHANGED
|
@@ -22,6 +22,11 @@ curl http://localhost:4313/api/canvas/schema
|
|
|
22
22
|
curl -X POST http://localhost:4313/api/canvas/schema/validate \
|
|
23
23
|
-H "Content-Type: application/json" \
|
|
24
24
|
-d '{"type":"json-render","spec":{"root":"card","elements":{"card":{"type":"Card","props":{"title":"Preview"},"children":[]}}}}'
|
|
25
|
+
|
|
26
|
+
# Validate an HTML primitive without creating a node
|
|
27
|
+
curl -X POST http://localhost:4313/api/canvas/schema/validate \
|
|
28
|
+
-H "Content-Type: application/json" \
|
|
29
|
+
-d '{"type":"html-primitive","kind":"choice-grid","data":{"items":[{"title":"A"}]}}'
|
|
25
30
|
```
|
|
26
31
|
|
|
27
32
|
## Nodes
|
|
@@ -35,7 +40,12 @@ curl -X POST http://localhost:4313/api/canvas/node \
|
|
|
35
40
|
# Add an html node (sandboxed iframe)
|
|
36
41
|
curl -X POST http://localhost:4313/api/canvas/node \
|
|
37
42
|
-H "Content-Type: application/json" \
|
|
38
|
-
-d '{"type":"html","title":"Chart","html":"<canvas id=\"c\"></canvas><script src=\"https://cdn.jsdelivr.net/npm/chart.js\"></script><script>/* ... */</script>"}'
|
|
43
|
+
-d '{"type":"html","title":"Chart","summary":"Cost projection chart for the Q2 plan.","html":"<canvas id=\"c\"></canvas><script src=\"https://cdn.jsdelivr.net/npm/chart.js\"></script><script>/* ... */</script>"}'
|
|
44
|
+
|
|
45
|
+
# Add a generated HTML primitive as a sandboxed html node
|
|
46
|
+
curl -X POST http://localhost:4313/api/canvas/node \
|
|
47
|
+
-H "Content-Type: application/json" \
|
|
48
|
+
-d '{"type":"html-primitive","kind":"choice-grid","title":"Options","data":{"items":[{"title":"Small patch","summary":"Least disruption."}]}}'
|
|
39
49
|
```
|
|
40
50
|
|
|
41
51
|
## Edges
|
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 **42 tools** + **8 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.
|
|
@@ -28,14 +28,19 @@ The canvas auto-starts on first tool call.
|
|
|
28
28
|
|------|-------------|
|
|
29
29
|
| `canvas_add_node` | Add a node (markdown, status, context, file, webpage, html, etc.) |
|
|
30
30
|
| `canvas_add_html_node` | Create an `html` node from a self-contained HTML/JS document (sandboxed iframe) |
|
|
31
|
+
| `canvas_add_html_primitive` | Create a reusable generated HTML communication primitive as a sandboxed `html` node |
|
|
31
32
|
| `canvas_add_diagram` | Hand-drawn diagram via the hosted Excalidraw MCP App (preset alias for `canvas_open_mcp_app`) |
|
|
32
33
|
| `canvas_open_mcp_app` | Open any [MCP Apps](https://modelcontextprotocol.io/docs/extensions/apps) server's `ui://` resource as an iframe node |
|
|
33
|
-
| `canvas_describe_schema` | Describe the running server's create schemas, examples,
|
|
34
|
-
| `canvas_validate_spec` | Validate a json-render spec or
|
|
34
|
+
| `canvas_describe_schema` | Describe the running server's create schemas, examples, json-render catalog, and HTML primitive catalog |
|
|
35
|
+
| `canvas_validate_spec` | Validate a json-render spec, graph payload, or HTML primitive payload without creating a node |
|
|
35
36
|
| `canvas_refresh_webpage_node` | Re-fetch and update a webpage node from its stored URL |
|
|
36
37
|
| `canvas_add_json_render_node` | Create a native json-render node from a validated spec |
|
|
37
38
|
| `canvas_add_graph_node` | Create a native graph node (line, bar, pie, area, scatter, radar, stacked-bar, composed) |
|
|
38
39
|
| `canvas_build_web_artifact` | Build a bundled HTML artifact and open it on the canvas |
|
|
40
|
+
|
|
41
|
+
`canvas_add_html_node` accepts optional `summary`, `agentSummary`, `embeddedNodeIds`, and
|
|
42
|
+
`embeddedUrls`. PMX also derives a bounded text summary from visible HTML, so rich HTML nodes stay
|
|
43
|
+
searchable and readable in pinned/spatial context.
|
|
39
44
|
| `canvas_update_node` | Update content, position, size, collapsed state |
|
|
40
45
|
| `canvas_remove_node` | Remove a node and its edges |
|
|
41
46
|
| `canvas_get_layout` | Get full canvas state |
|
|
@@ -118,6 +123,7 @@ in doubt:
|
|
|
118
123
|
|
|
119
124
|
- `json-render` → `canvas_add_json_render_node`
|
|
120
125
|
- `graph` → `canvas_add_graph_node`
|
|
126
|
+
- `html-primitive` → `canvas_add_html_primitive`
|
|
121
127
|
- `html` → `canvas_add_html_node`
|
|
122
128
|
- `web-artifact` → `canvas_build_web_artifact`
|
|
123
129
|
- `mcp-app` → `canvas_open_mcp_app`
|
|
@@ -128,7 +134,7 @@ in doubt:
|
|
|
128
134
|
## CLI/MCP alignment
|
|
129
135
|
|
|
130
136
|
CLI and MCP are kept aligned for the main canvas operations: node and edge
|
|
131
|
-
creation, graph/json-render/html nodes, web artifacts, external apps, groups,
|
|
137
|
+
creation, graph/json-render/html/html-primitive nodes, web artifacts, external apps, groups,
|
|
132
138
|
batch builds, layout validation, snapshots, search, focus, pins, undo/redo,
|
|
133
139
|
semantic watch streams, WebView automation, and daemon/server control where
|
|
134
140
|
it applies. A few agent-native capabilities — resource subscriptions and
|
package/docs/node-types.md
CHANGED
|
@@ -143,7 +143,7 @@ component catalog before building a spec.
|
|
|
143
143
|
|
|
144
144
|
## HTML nodes
|
|
145
145
|
|
|
146
|
-
`html` nodes render a self-contained HTML/JS document in a sandboxed iframe.
|
|
146
|
+
`html` nodes render a normal self-contained HTML/JS document in a sandboxed iframe.
|
|
147
147
|
They sit between `json-render` (no custom JS) and `web-artifact` (full bundled
|
|
148
148
|
React app) — perfect for Chart.js, D3, custom widgets, and any HTML you can
|
|
149
149
|
write or paste.
|
|
@@ -152,7 +152,8 @@ The sandbox runs with `allow-scripts` only — no same-origin access, no
|
|
|
152
152
|
top-level navigation, no form submission. Inline `<script>` and CDN
|
|
153
153
|
`<script src>` both work. The canvas auto-injects its theme tokens
|
|
154
154
|
(`--c-*` and `--color-*` aliases) into the iframe `<head>` so artifacts can
|
|
155
|
-
match the active theme.
|
|
155
|
+
match the active theme. Theme updates are posted into sandboxed HTML iframes,
|
|
156
|
+
so theme-aware HTML can follow dark/light switches without reopening the node.
|
|
156
157
|
|
|
157
158
|
```ts
|
|
158
159
|
canvas_add_html_node({
|
|
@@ -164,6 +165,54 @@ canvas_add_html_node({
|
|
|
164
165
|
A fragment without `<html>`/`<head>` is wrapped in a full document
|
|
165
166
|
automatically. Default size is 720×640.
|
|
166
167
|
|
|
168
|
+
Presentation mode is opt-in. Raw HTML nodes do not show the browser `Present`
|
|
169
|
+
button unless callers set `presentation: true`; prefer the `presentation`
|
|
170
|
+
primitive when the user explicitly asks for a PowerPoint-like deck, pitch,
|
|
171
|
+
briefing, workshop walkthrough, or fullscreen story.
|
|
172
|
+
|
|
173
|
+
HTML nodes also store an agent-readable semantic sidecar. Callers can pass
|
|
174
|
+
`summary`, `agentSummary`, `embeddedNodeIds`, or `embeddedUrls`; when no summary
|
|
175
|
+
is provided, PMX derives `data.contentSummary` from visible HTML text and stores
|
|
176
|
+
`data.agentSummary` for search, pinned context, and spatial context. Scripts and
|
|
177
|
+
styles are ignored during extraction.
|
|
178
|
+
|
|
179
|
+
### HTML primitives
|
|
180
|
+
|
|
181
|
+
`html-primitive` is a virtual schema type that creates a normal sandboxed
|
|
182
|
+
`html` node from a reusable communication template. Use it when a long markdown
|
|
183
|
+
answer would be easier to review as an option grid, implementation timeline,
|
|
184
|
+
review sheet, PR writeup, code walkthrough, system map, design sheet,
|
|
185
|
+
component gallery, interaction prototype, flowchart, SVG illustration set,
|
|
186
|
+
presentation, explainer, status report, incident report, triage board, config
|
|
187
|
+
editor, or prompt tuner.
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
canvas_add_html_primitive({
|
|
191
|
+
kind: 'choice-grid',
|
|
192
|
+
title: 'Implementation options',
|
|
193
|
+
data: {
|
|
194
|
+
items: [
|
|
195
|
+
{ title: 'Small patch', summary: 'Least disruption.', pros: ['Fast'], cons: ['Less flexible'] },
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
HTTP callers may post either `{ "type": "html-primitive", "kind": "choice-grid", "data": ... }`
|
|
202
|
+
or `{ "type": "html", "primitive": "choice-grid", "data": ... }`. The stored
|
|
203
|
+
node remains `type: "html"` with `data.htmlPrimitive`, `data.primitiveData`, and
|
|
204
|
+
the generated `data.html` payload. Generated primitives also get an
|
|
205
|
+
agent-readable summary sidecar.
|
|
206
|
+
|
|
207
|
+
Only presentation-marked HTML nodes expose a `Present` button in the browser.
|
|
208
|
+
Use the `presentation` primitive for PowerPoint-like decks; it persists
|
|
209
|
+
`presentation`, `slideCount`, `slideTitles`, optional `speakerNotes`, and
|
|
210
|
+
optional `presentationTheme` metadata while the iframe handles
|
|
211
|
+
Arrow/Space/Page Up/Page Down slide navigation. Presentation data supports
|
|
212
|
+
`theme: "canvas" | "midnight" | "paper" | "aurora"` or a custom color object with
|
|
213
|
+
`bg`, `panel`, `surface`, `border`, `text`, `textSecondary`, `textMuted`,
|
|
214
|
+
`accent`, and `colorScheme`.
|
|
215
|
+
|
|
167
216
|
## Web artifacts
|
|
168
217
|
|
|
169
218
|
A **web artifact** is a single-file, fully bundled HTML app (React + Tailwind
|
|
@@ -222,9 +271,9 @@ Agents don't have to guess node shapes. The running server exposes its create
|
|
|
222
271
|
schemas, json-render component catalog, and node-type examples:
|
|
223
272
|
|
|
224
273
|
- `canvas_describe_schema` / `GET /api/canvas/schema` — list all node-create
|
|
225
|
-
schemas, required fields, json-render components, and sample payloads
|
|
274
|
+
schemas, required fields, json-render components, HTML primitives, and sample payloads
|
|
226
275
|
- `canvas_validate_spec` / `POST /api/canvas/schema/validate` — validate a
|
|
227
|
-
json-render spec or
|
|
276
|
+
json-render spec, graph payload, or HTML primitive payload **without** creating a node
|
|
228
277
|
- `canvas_validate` / `GET /api/canvas/validate` — validate the current
|
|
229
278
|
layout for collisions, containment, and missing edge endpoints
|
|
230
279
|
- `canvas://schema` — the same data as an MCP resource
|
|
@@ -236,6 +285,7 @@ MCP node creation uses dedicated tools for structured node families. Read
|
|
|
236
285
|
`mcp.nodeTypeRouting` from `canvas_describe_schema` when in doubt:
|
|
237
286
|
`json-render` → `canvas_add_json_render_node`,
|
|
238
287
|
`graph` → `canvas_add_graph_node`,
|
|
288
|
+
`html-primitive` → `canvas_add_html_primitive`,
|
|
239
289
|
`html` → `canvas_add_html_node`,
|
|
240
290
|
`web-artifact` → `canvas_build_web_artifact`,
|
|
241
291
|
`mcp-app` → `canvas_open_mcp_app`,
|
package/docs/screenshot.png
CHANGED
|
Binary file
|
package/docs/sdk.md
CHANGED
|
@@ -29,9 +29,21 @@ canvas.createGroup({ title: 'Build Pipeline', childIds: [n1, n2] });
|
|
|
29
29
|
// Self-contained HTML in a sandboxed iframe
|
|
30
30
|
canvas.addHtmlNode({
|
|
31
31
|
title: 'Cost projection',
|
|
32
|
+
summary: 'Cost projection chart for the Q2 plan.',
|
|
32
33
|
html: '<canvas id="c"></canvas><script src="https://cdn.jsdelivr.net/npm/chart.js"></script><script>/* ... */</script>',
|
|
33
34
|
});
|
|
34
35
|
|
|
36
|
+
// Generated HTML communication primitive, stored as a sandboxed html node
|
|
37
|
+
canvas.addHtmlPrimitive({
|
|
38
|
+
kind: 'choice-grid',
|
|
39
|
+
title: 'Implementation options',
|
|
40
|
+
data: {
|
|
41
|
+
items: [
|
|
42
|
+
{ title: 'Small patch', summary: 'Least disruption.', pros: ['Fast'], cons: ['Less flexible'] },
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
35
47
|
// Hand-drawn diagram via the Excalidraw MCP-app preset
|
|
36
48
|
await canvas.addDiagram({
|
|
37
49
|
elements: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmx-canvas",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
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",
|
|
@@ -50,6 +50,7 @@ tree:
|
|
|
50
50
|
2. Decide which canvas node type best matches each output:
|
|
51
51
|
- Long-form / narrative results → `markdown`
|
|
52
52
|
- Structured records, tables, dashboards → `json-render` or `graph`
|
|
53
|
+
- Rich reusable communication artifacts → `html-primitive`
|
|
53
54
|
- Interactive tool surfaces with their own UI → `mcp-app` (open with
|
|
54
55
|
`canvas_open_mcp_app`)
|
|
55
56
|
- Local source files → `file` (live-watched)
|
|
@@ -270,6 +271,7 @@ MCP node-type routing:
|
|
|
270
271
|
| Basic nodes (`markdown`, `status`, `context`, `ledger`, `trace`, `file`, `image`, `webpage`) | `canvas_add_node` |
|
|
271
272
|
| `json-render` | `canvas_add_json_render_node` |
|
|
272
273
|
| `graph` | `canvas_add_graph_node` |
|
|
274
|
+
| `html-primitive` | `canvas_add_html_primitive` |
|
|
273
275
|
| `html` | `canvas_add_html_node` |
|
|
274
276
|
| `web-artifact` | `canvas_build_web_artifact` |
|
|
275
277
|
| `external-app` / tool-backed `mcp-app` | `canvas_open_mcp_app` |
|
|
@@ -652,12 +654,23 @@ server's `ui://` resource as an iframe node on the canvas
|
|
|
652
654
|
|
|
653
655
|
### HTML Nodes (Sandboxed iframe)
|
|
654
656
|
|
|
655
|
-
**`canvas_add_html_node`** — Add a self-contained HTML document rendered in a sandboxed iframe
|
|
657
|
+
**`canvas_add_html_node`** — Add a normal self-contained HTML document rendered in a sandboxed iframe
|
|
656
658
|
- Required: `html` (full document or fragment; inline `<script>` and CDN `<script src="...">` are allowed)
|
|
657
|
-
- Optional: `title`, `x`, `y`, `width` (default 720), `height` (default 640), `strictSize`
|
|
659
|
+
- Optional: `title`, `summary`, `agentSummary`, `presentation`, `slideTitles`, `embeddedNodeIds`, `embeddedUrls`, `x`, `y`, `width` (default 720), `height` (default 640), `strictSize`
|
|
658
660
|
- Iframe sandbox is `allow-scripts` only — no same-origin access, no top-navigation, no forms
|
|
659
|
-
- Canvas theme tokens are auto-injected as CSS custom properties (both `--c-*` and common `--color-*` aliases such as `--color-text-primary`, `--color-bg`, `--color-accent`)
|
|
661
|
+
- Canvas theme tokens are auto-injected as CSS custom properties (both `--c-*` and common `--color-*` aliases such as `--color-text-primary`, `--color-bg`, `--color-accent`) and updated live when the canvas theme changes
|
|
660
662
|
- Use for moderate-complexity visualizations and interactive widgets that need real JS but do not warrant a full React build (Chart.js demos, D3 sketches, custom HTML report views)
|
|
663
|
+
- Normal HTML is the default. Only pass `presentation: true` when the user explicitly asks for a deck/fullscreen presentation; otherwise do not mark raw HTML as presentable.
|
|
664
|
+
- Only presentation-marked HTML nodes expose a browser `Present` button. Use it when the HTML is a deck, briefing, or fullscreen review surface; the PMX shell owns the fullscreen overlay and exits via `Esc` or `Exit presentation`.
|
|
665
|
+
- PMX stores a semantic sidecar (`agentSummary`, `contentSummary`, embedded references) so HTML nodes remain understandable in search, pinned context, and spatial context
|
|
666
|
+
|
|
667
|
+
**`canvas_add_html_primitive`** — Generate a reusable HTML communication primitive as a sandboxed `html` node
|
|
668
|
+
- Required: `kind`; run `canvas_describe_schema` and read `htmlPrimitives` for the current catalog
|
|
669
|
+
- Optional: `title`, `data`, `x`, `y`, `width`, `height`, `strictSize`
|
|
670
|
+
- Use when markdown would be too dense and a structured visual artifact is clearer: tradeoff grids, implementation plans, PR reviews, module maps, design sheets, explainers, reports, and lightweight human-editable boards/editors
|
|
671
|
+
- When the human asks for a PowerPoint-like output, pitch deck, briefing, or presentation, use `kind: "presentation"` unless a bespoke raw HTML deck is required. Include `slides` with short titles, one idea per slide, optional `metrics`, `note` fields for speaker notes, and optional `theme: "canvas" | "midnight" | "paper" | "aurora"` or a custom theme object.
|
|
672
|
+
- Read `htmlPrimitives` from `canvas_describe_schema` for the data shape and examples before constructing a payload
|
|
673
|
+
- For payload patterns, export loops, and the primitive catalog, read `references/html-primitives.md` before creating dense or editable artifacts
|
|
661
674
|
|
|
662
675
|
### Choosing the Right Visual Tier
|
|
663
676
|
|
|
@@ -666,6 +679,7 @@ When the output is more than markdown, pick the lightest tier that fits:
|
|
|
666
679
|
| Tier | Tool | Build cost | When to pick it |
|
|
667
680
|
|------|------|------------|-----------------|
|
|
668
681
|
| Declarative UI | `canvas_add_json_render_node` / `canvas_add_graph_node` | None | Schema-driven dashboards, forms, charts; agent-friendly to read back via `canvas_get_node` |
|
|
682
|
+
| Generated HTML primitive | `canvas_add_html_primitive` | None | Reusable communication artifacts such as choices, plans, reviews, maps, reports, presentations/decks, and lightweight editors |
|
|
669
683
|
| Sandboxed HTML+JS | `canvas_add_html_node` | None | Self-contained HTML with inline JS or CDN scripts; one-off visualizations or report views |
|
|
670
684
|
| Hosted MCP app | `canvas_open_mcp_app` / `canvas_add_diagram` | None | Interactive editors backed by an external MCP server (e.g. Excalidraw) |
|
|
671
685
|
| Bundled React app | `canvas_build_web_artifact` | Heavy (npm install + bundle) | Multi-component UIs needing React state, routing, shadcn/ui, or Tailwind class composition |
|