pmx-canvas 0.1.10 → 0.1.12
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 +131 -0
- package/dist/canvas/index.js +30 -30
- package/dist/json-render/index.js +115 -115
- package/dist/types/json-render/catalog.d.ts +10 -0
- package/dist/types/json-render/charts/components.d.ts +18 -0
- package/dist/types/json-render/charts/definitions.d.ts +4 -0
- package/dist/types/json-render/charts/extra-components.d.ts +3 -0
- package/dist/types/json-render/charts/extra-definitions.d.ts +6 -0
- package/dist/types/json-render/server.d.ts +4 -0
- package/dist/types/mcp/canvas-access.d.ts +87 -0
- package/dist/types/server/canvas-operations.d.ts +2 -0
- package/dist/types/server/index.d.ts +2 -0
- package/dist/types/server/server.d.ts +1 -0
- package/package.json +1 -1
- package/skills/pmx-canvas/SKILL.md +9 -0
- package/src/cli/agent.ts +78 -2
- package/src/cli/index.ts +6 -3
- package/src/client/canvas/CanvasNode.tsx +3 -1
- package/src/client/canvas/auto-fit.ts +1 -1
- package/src/json-render/charts/components.tsx +18 -10
- package/src/json-render/charts/definitions.ts +4 -0
- package/src/json-render/charts/extra-components.tsx +23 -16
- package/src/json-render/charts/extra-definitions.ts +6 -0
- package/src/json-render/server.ts +11 -0
- package/src/mcp/canvas-access.ts +651 -0
- package/src/mcp/server.ts +170 -95
- package/src/server/canvas-operations.ts +21 -1
- package/src/server/canvas-schema.ts +5 -0
- package/src/server/diagram-presets.ts +44 -12
- package/src/server/index.ts +9 -3
- package/src/server/server.ts +37 -3
|
@@ -84,6 +84,7 @@ export declare const allComponentDefinitions: {
|
|
|
84
84
|
axisKey: z.ZodString;
|
|
85
85
|
metrics: z.ZodArray<z.ZodString>;
|
|
86
86
|
height: z.ZodNullable<z.ZodNumber>;
|
|
87
|
+
showLegend: z.ZodOptional<z.ZodBoolean>;
|
|
87
88
|
}, z.core.$strip>;
|
|
88
89
|
readonly description: "Radar chart for comparing multiple metrics across categories. Each metric in `metrics` is plotted as its own polygon.";
|
|
89
90
|
readonly example: {
|
|
@@ -104,6 +105,7 @@ export declare const allComponentDefinitions: {
|
|
|
104
105
|
readonly axisKey: "skill";
|
|
105
106
|
readonly metrics: readonly ["alice", "bob"];
|
|
106
107
|
readonly height: null;
|
|
108
|
+
readonly showLegend: true;
|
|
107
109
|
};
|
|
108
110
|
};
|
|
109
111
|
StackedBarChart: {
|
|
@@ -118,6 +120,7 @@ export declare const allComponentDefinitions: {
|
|
|
118
120
|
avg: "avg";
|
|
119
121
|
}>>;
|
|
120
122
|
height: z.ZodNullable<z.ZodNumber>;
|
|
123
|
+
showLegend: z.ZodOptional<z.ZodBoolean>;
|
|
121
124
|
}, z.core.$strip>;
|
|
122
125
|
readonly description: "Stacked bar chart for compositional data. Each entry in `series` is plotted as its own bar segment per x value.";
|
|
123
126
|
readonly example: {
|
|
@@ -142,6 +145,7 @@ export declare const allComponentDefinitions: {
|
|
|
142
145
|
readonly series: readonly ["north", "south", "east"];
|
|
143
146
|
readonly aggregate: null;
|
|
144
147
|
readonly height: null;
|
|
148
|
+
readonly showLegend: true;
|
|
145
149
|
};
|
|
146
150
|
};
|
|
147
151
|
ComposedChart: {
|
|
@@ -154,6 +158,7 @@ export declare const allComponentDefinitions: {
|
|
|
154
158
|
barColor: z.ZodNullable<z.ZodString>;
|
|
155
159
|
lineColor: z.ZodNullable<z.ZodString>;
|
|
156
160
|
height: z.ZodNullable<z.ZodNumber>;
|
|
161
|
+
showLegend: z.ZodOptional<z.ZodBoolean>;
|
|
157
162
|
}, z.core.$strip>;
|
|
158
163
|
readonly description: "Combined bar + line chart for paired metrics (e.g. counts + a derived rate) on the same axis.";
|
|
159
164
|
readonly example: {
|
|
@@ -177,6 +182,7 @@ export declare const allComponentDefinitions: {
|
|
|
177
182
|
readonly barColor: null;
|
|
178
183
|
readonly lineColor: null;
|
|
179
184
|
readonly height: null;
|
|
185
|
+
readonly showLegend: true;
|
|
180
186
|
};
|
|
181
187
|
};
|
|
182
188
|
LineChart: {
|
|
@@ -254,6 +260,8 @@ export declare const allComponentDefinitions: {
|
|
|
254
260
|
nameKey: z.ZodString;
|
|
255
261
|
valueKey: z.ZodString;
|
|
256
262
|
height: z.ZodNullable<z.ZodNumber>;
|
|
263
|
+
showLegend: z.ZodOptional<z.ZodBoolean>;
|
|
264
|
+
showLabels: z.ZodOptional<z.ZodBoolean>;
|
|
257
265
|
}, z.core.$strip>;
|
|
258
266
|
readonly description: "Pie chart for showing proportions. Provide data as an array of objects with nameKey and valueKey fields.";
|
|
259
267
|
readonly example: {
|
|
@@ -271,6 +279,8 @@ export declare const allComponentDefinitions: {
|
|
|
271
279
|
readonly nameKey: "name";
|
|
272
280
|
readonly valueKey: "share";
|
|
273
281
|
readonly height: null;
|
|
282
|
+
readonly showLegend: true;
|
|
283
|
+
readonly showLabels: true;
|
|
274
284
|
};
|
|
275
285
|
};
|
|
276
286
|
Badge: {
|
|
@@ -26,6 +26,8 @@ interface PieChartProps {
|
|
|
26
26
|
nameKey: string;
|
|
27
27
|
valueKey: string;
|
|
28
28
|
height?: number | null;
|
|
29
|
+
showLegend?: boolean | null;
|
|
30
|
+
showLabels?: boolean | null;
|
|
29
31
|
}
|
|
30
32
|
export declare const axisStyle: {
|
|
31
33
|
fontSize: number;
|
|
@@ -38,6 +40,22 @@ export declare const tooltipStyle: {
|
|
|
38
40
|
color: string;
|
|
39
41
|
fontSize: number;
|
|
40
42
|
};
|
|
43
|
+
export declare const chartMargin: {
|
|
44
|
+
top: number;
|
|
45
|
+
right: number;
|
|
46
|
+
bottom: number;
|
|
47
|
+
left: number;
|
|
48
|
+
};
|
|
49
|
+
export declare const polarChartMargin: {
|
|
50
|
+
top: number;
|
|
51
|
+
right: number;
|
|
52
|
+
bottom: number;
|
|
53
|
+
left: number;
|
|
54
|
+
};
|
|
55
|
+
export declare const axisTickMargin = 8;
|
|
56
|
+
export declare const legendMargin: {
|
|
57
|
+
top: number;
|
|
58
|
+
};
|
|
41
59
|
/** Shared wrapper for cartesian charts (Line + Bar). */
|
|
42
60
|
export declare function CartesianChart({ props, children, className, }: {
|
|
43
61
|
props: CartesianChartProps;
|
|
@@ -81,6 +81,8 @@ export declare const chartComponentDefinitions: {
|
|
|
81
81
|
nameKey: z.ZodString;
|
|
82
82
|
valueKey: z.ZodString;
|
|
83
83
|
height: z.ZodNullable<z.ZodNumber>;
|
|
84
|
+
showLegend: z.ZodOptional<z.ZodBoolean>;
|
|
85
|
+
showLabels: z.ZodOptional<z.ZodBoolean>;
|
|
84
86
|
}, z.core.$strip>;
|
|
85
87
|
readonly description: "Pie chart for showing proportions. Provide data as an array of objects with nameKey and valueKey fields.";
|
|
86
88
|
readonly example: {
|
|
@@ -98,6 +100,8 @@ export declare const chartComponentDefinitions: {
|
|
|
98
100
|
readonly nameKey: "name";
|
|
99
101
|
readonly valueKey: "share";
|
|
100
102
|
readonly height: null;
|
|
103
|
+
readonly showLegend: true;
|
|
104
|
+
readonly showLabels: true;
|
|
101
105
|
};
|
|
102
106
|
};
|
|
103
107
|
};
|
|
@@ -26,6 +26,7 @@ interface RadarChartProps {
|
|
|
26
26
|
axisKey: string;
|
|
27
27
|
metrics: string[];
|
|
28
28
|
height?: number | null;
|
|
29
|
+
showLegend?: boolean | null;
|
|
29
30
|
}
|
|
30
31
|
declare function ChartRadarChart({ props }: BaseComponentProps<RadarChartProps>): import("react/jsx-runtime").JSX.Element;
|
|
31
32
|
interface StackedBarChartProps {
|
|
@@ -35,6 +36,7 @@ interface StackedBarChartProps {
|
|
|
35
36
|
series: string[];
|
|
36
37
|
aggregate?: 'sum' | 'count' | 'avg' | null;
|
|
37
38
|
height?: number | null;
|
|
39
|
+
showLegend?: boolean | null;
|
|
38
40
|
}
|
|
39
41
|
declare function ChartStackedBarChart({ props }: BaseComponentProps<StackedBarChartProps>): import("react/jsx-runtime").JSX.Element;
|
|
40
42
|
interface ComposedChartProps {
|
|
@@ -46,6 +48,7 @@ interface ComposedChartProps {
|
|
|
46
48
|
barColor?: string | null;
|
|
47
49
|
lineColor?: string | null;
|
|
48
50
|
height?: number | null;
|
|
51
|
+
showLegend?: boolean | null;
|
|
49
52
|
}
|
|
50
53
|
declare function ChartComposedChart({ props }: BaseComponentProps<ComposedChartProps>): import("react/jsx-runtime").JSX.Element;
|
|
51
54
|
export declare const extraChartComponents: {
|
|
@@ -83,6 +83,7 @@ export declare const extraChartComponentDefinitions: {
|
|
|
83
83
|
axisKey: z.ZodString;
|
|
84
84
|
metrics: z.ZodArray<z.ZodString>;
|
|
85
85
|
height: z.ZodNullable<z.ZodNumber>;
|
|
86
|
+
showLegend: z.ZodOptional<z.ZodBoolean>;
|
|
86
87
|
}, z.core.$strip>;
|
|
87
88
|
readonly description: "Radar chart for comparing multiple metrics across categories. Each metric in `metrics` is plotted as its own polygon.";
|
|
88
89
|
readonly example: {
|
|
@@ -103,6 +104,7 @@ export declare const extraChartComponentDefinitions: {
|
|
|
103
104
|
readonly axisKey: "skill";
|
|
104
105
|
readonly metrics: readonly ["alice", "bob"];
|
|
105
106
|
readonly height: null;
|
|
107
|
+
readonly showLegend: true;
|
|
106
108
|
};
|
|
107
109
|
};
|
|
108
110
|
readonly StackedBarChart: {
|
|
@@ -117,6 +119,7 @@ export declare const extraChartComponentDefinitions: {
|
|
|
117
119
|
avg: "avg";
|
|
118
120
|
}>>;
|
|
119
121
|
height: z.ZodNullable<z.ZodNumber>;
|
|
122
|
+
showLegend: z.ZodOptional<z.ZodBoolean>;
|
|
120
123
|
}, z.core.$strip>;
|
|
121
124
|
readonly description: "Stacked bar chart for compositional data. Each entry in `series` is plotted as its own bar segment per x value.";
|
|
122
125
|
readonly example: {
|
|
@@ -141,6 +144,7 @@ export declare const extraChartComponentDefinitions: {
|
|
|
141
144
|
readonly series: readonly ["north", "south", "east"];
|
|
142
145
|
readonly aggregate: null;
|
|
143
146
|
readonly height: null;
|
|
147
|
+
readonly showLegend: true;
|
|
144
148
|
};
|
|
145
149
|
};
|
|
146
150
|
readonly ComposedChart: {
|
|
@@ -153,6 +157,7 @@ export declare const extraChartComponentDefinitions: {
|
|
|
153
157
|
barColor: z.ZodNullable<z.ZodString>;
|
|
154
158
|
lineColor: z.ZodNullable<z.ZodString>;
|
|
155
159
|
height: z.ZodNullable<z.ZodNumber>;
|
|
160
|
+
showLegend: z.ZodOptional<z.ZodBoolean>;
|
|
156
161
|
}, z.core.$strip>;
|
|
157
162
|
readonly description: "Combined bar + line chart for paired metrics (e.g. counts + a derived rate) on the same axis.";
|
|
158
163
|
readonly example: {
|
|
@@ -176,6 +181,7 @@ export declare const extraChartComponentDefinitions: {
|
|
|
176
181
|
readonly barColor: null;
|
|
177
182
|
readonly lineColor: null;
|
|
178
183
|
readonly height: null;
|
|
184
|
+
readonly showLegend: true;
|
|
179
185
|
};
|
|
180
186
|
};
|
|
181
187
|
};
|
|
@@ -10,6 +10,7 @@ export interface JsonRenderNodeInput {
|
|
|
10
10
|
y?: number;
|
|
11
11
|
width?: number;
|
|
12
12
|
height?: number;
|
|
13
|
+
strictSize?: boolean;
|
|
13
14
|
}
|
|
14
15
|
export interface GraphNodeInput {
|
|
15
16
|
title?: string;
|
|
@@ -30,10 +31,13 @@ export interface GraphNodeInput {
|
|
|
30
31
|
barColor?: string;
|
|
31
32
|
lineColor?: string;
|
|
32
33
|
height?: number;
|
|
34
|
+
showLegend?: boolean;
|
|
35
|
+
showLabels?: boolean;
|
|
33
36
|
x?: number;
|
|
34
37
|
y?: number;
|
|
35
38
|
width?: number;
|
|
36
39
|
heightPx?: number;
|
|
40
|
+
strictSize?: boolean;
|
|
37
41
|
}
|
|
38
42
|
export declare const JSON_RENDER_NODE_SIZE: {
|
|
39
43
|
width: number;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { type CanvasLayout, type CanvasNodeState, type CanvasSnapshot, type PmxCanvas } from '../server/index.js';
|
|
2
|
+
type AddNodeInput = Parameters<PmxCanvas['addNode']>[0];
|
|
3
|
+
type AddWebpageNodeInput = Parameters<PmxCanvas['addWebpageNode']>[0];
|
|
4
|
+
type RefreshWebpageNodeResult = Awaited<ReturnType<PmxCanvas['refreshWebpageNode']>>;
|
|
5
|
+
type OpenMcpAppInput = Parameters<PmxCanvas['openMcpApp']>[0];
|
|
6
|
+
type OpenMcpAppResult = Awaited<ReturnType<PmxCanvas['openMcpApp']>>;
|
|
7
|
+
type AddDiagramInput = Parameters<PmxCanvas['addDiagram']>[0];
|
|
8
|
+
type AddJsonRenderNodeInput = Parameters<PmxCanvas['addJsonRenderNode']>[0];
|
|
9
|
+
type AddJsonRenderNodeResult = ReturnType<PmxCanvas['addJsonRenderNode']>;
|
|
10
|
+
type AddGraphNodeInput = Parameters<PmxCanvas['addGraphNode']>[0];
|
|
11
|
+
type AddGraphNodeResult = ReturnType<PmxCanvas['addGraphNode']>;
|
|
12
|
+
type UpdateNodePatch = Parameters<PmxCanvas['updateNode']>[1];
|
|
13
|
+
type AddEdgeInput = Parameters<PmxCanvas['addEdge']>[0];
|
|
14
|
+
type CreateGroupInput = Parameters<PmxCanvas['createGroup']>[0];
|
|
15
|
+
type GroupNodesOptions = Parameters<PmxCanvas['groupNodes']>[2];
|
|
16
|
+
type ArrangeLayout = Parameters<PmxCanvas['arrange']>[0];
|
|
17
|
+
type FocusNodeResult = ReturnType<PmxCanvas['focusNode']>;
|
|
18
|
+
type FitViewOptions = Parameters<PmxCanvas['fitView']>[0];
|
|
19
|
+
type FitViewResult = ReturnType<PmxCanvas['fitView']>;
|
|
20
|
+
type SearchResult = ReturnType<PmxCanvas['search']>;
|
|
21
|
+
type UndoRedoResult = Awaited<ReturnType<PmxCanvas['undo']>>;
|
|
22
|
+
type HistoryResult = ReturnType<PmxCanvas['getHistory']>;
|
|
23
|
+
type SetContextPinsResult = ReturnType<PmxCanvas['setContextPins']>;
|
|
24
|
+
type RunBatchInput = Parameters<PmxCanvas['runBatch']>[0];
|
|
25
|
+
type RunBatchResult = Awaited<ReturnType<PmxCanvas['runBatch']>>;
|
|
26
|
+
type SnapshotList = ReturnType<PmxCanvas['listSnapshots']>;
|
|
27
|
+
type DeleteSnapshotResult = ReturnType<PmxCanvas['deleteSnapshot']>;
|
|
28
|
+
type DiffSnapshotResult = ReturnType<PmxCanvas['diffSnapshot']>;
|
|
29
|
+
type CodeGraphResult = ReturnType<PmxCanvas['getCodeGraph']>;
|
|
30
|
+
type ValidationResult = ReturnType<PmxCanvas['validate']>;
|
|
31
|
+
type WebArtifactInput = Parameters<PmxCanvas['buildWebArtifact']>[0];
|
|
32
|
+
type WebArtifactResult = Awaited<ReturnType<PmxCanvas['buildWebArtifact']>>;
|
|
33
|
+
type AutomationWebViewOptions = Parameters<PmxCanvas['startAutomationWebView']>[0];
|
|
34
|
+
type AutomationWebViewStatus = Awaited<ReturnType<PmxCanvas['startAutomationWebView']>>;
|
|
35
|
+
type AutomationEvaluateResult = Awaited<ReturnType<PmxCanvas['evaluateAutomationWebView']>>;
|
|
36
|
+
type AutomationScreenshotOptions = Parameters<PmxCanvas['screenshotAutomationWebView']>[0];
|
|
37
|
+
export interface CanvasAccess {
|
|
38
|
+
readonly port: number;
|
|
39
|
+
readonly remoteBaseUrl: string | null;
|
|
40
|
+
getLayout(): Promise<CanvasLayout>;
|
|
41
|
+
getNode(id: string): Promise<CanvasNodeState | undefined>;
|
|
42
|
+
addNode(input: AddNodeInput): Promise<string>;
|
|
43
|
+
addWebpageNode(input: AddWebpageNodeInput): Promise<Awaited<ReturnType<PmxCanvas['addWebpageNode']>>>;
|
|
44
|
+
refreshWebpageNode(id: string, url?: string): Promise<RefreshWebpageNodeResult>;
|
|
45
|
+
openMcpApp(input: OpenMcpAppInput): Promise<OpenMcpAppResult>;
|
|
46
|
+
addDiagram(input: AddDiagramInput): Promise<OpenMcpAppResult>;
|
|
47
|
+
addJsonRenderNode(input: AddJsonRenderNodeInput): Promise<AddJsonRenderNodeResult>;
|
|
48
|
+
addGraphNode(input: AddGraphNodeInput): Promise<AddGraphNodeResult>;
|
|
49
|
+
buildWebArtifact(input: WebArtifactInput): Promise<WebArtifactResult>;
|
|
50
|
+
updateNode(id: string, patch: UpdateNodePatch): Promise<void>;
|
|
51
|
+
removeNode(id: string): Promise<void>;
|
|
52
|
+
addEdge(input: AddEdgeInput): Promise<string>;
|
|
53
|
+
removeEdge(id: string): Promise<void>;
|
|
54
|
+
createGroup(input: CreateGroupInput): Promise<string>;
|
|
55
|
+
groupNodes(groupId: string, childIds: string[], options?: GroupNodesOptions): Promise<boolean>;
|
|
56
|
+
ungroupNodes(groupId: string): Promise<boolean>;
|
|
57
|
+
arrange(layout?: ArrangeLayout): Promise<void>;
|
|
58
|
+
focusNode(id: string, options?: {
|
|
59
|
+
noPan?: boolean;
|
|
60
|
+
}): Promise<FocusNodeResult>;
|
|
61
|
+
fitView(options?: FitViewOptions): Promise<FitViewResult>;
|
|
62
|
+
clear(): Promise<void>;
|
|
63
|
+
search(query: string): Promise<SearchResult>;
|
|
64
|
+
undo(): Promise<UndoRedoResult>;
|
|
65
|
+
redo(): Promise<UndoRedoResult>;
|
|
66
|
+
getHistory(): Promise<HistoryResult>;
|
|
67
|
+
setContextPins(nodeIds: string[], mode?: 'set' | 'add' | 'remove'): Promise<SetContextPinsResult>;
|
|
68
|
+
getPinnedNodeIds(): Promise<string[]>;
|
|
69
|
+
runBatch(operations: RunBatchInput): Promise<RunBatchResult>;
|
|
70
|
+
listSnapshots(): Promise<SnapshotList>;
|
|
71
|
+
saveSnapshot(name: string): Promise<CanvasSnapshot | null>;
|
|
72
|
+
restoreSnapshot(id: string): Promise<{
|
|
73
|
+
ok: boolean;
|
|
74
|
+
}>;
|
|
75
|
+
deleteSnapshot(id: string): Promise<DeleteSnapshotResult>;
|
|
76
|
+
diffSnapshot(idOrName: string): Promise<DiffSnapshotResult>;
|
|
77
|
+
getCodeGraph(): Promise<CodeGraphResult>;
|
|
78
|
+
validate(): Promise<ValidationResult>;
|
|
79
|
+
getAutomationWebViewStatus(): Promise<AutomationWebViewStatus>;
|
|
80
|
+
startAutomationWebView(options?: AutomationWebViewOptions): Promise<AutomationWebViewStatus>;
|
|
81
|
+
stopAutomationWebView(): Promise<boolean>;
|
|
82
|
+
evaluateAutomationWebView(expression: string): Promise<AutomationEvaluateResult>;
|
|
83
|
+
resizeAutomationWebView(width: number, height: number): Promise<AutomationWebViewStatus>;
|
|
84
|
+
screenshotAutomationWebView(options?: AutomationScreenshotOptions): Promise<Uint8Array>;
|
|
85
|
+
}
|
|
86
|
+
export declare function createCanvasAccess(): Promise<CanvasAccess>;
|
|
87
|
+
export {};
|
|
@@ -32,6 +32,7 @@ export interface CanvasStructuredNodeUpdateInput extends Omit<CanvasGraphNodeUpd
|
|
|
32
32
|
content?: unknown;
|
|
33
33
|
data?: unknown;
|
|
34
34
|
arrangeLocked?: unknown;
|
|
35
|
+
strictSize?: boolean;
|
|
35
36
|
chartHeight?: unknown;
|
|
36
37
|
}
|
|
37
38
|
interface CanvasAddNodeInput {
|
|
@@ -46,6 +47,7 @@ interface CanvasAddNodeInput {
|
|
|
46
47
|
defaultWidth?: number;
|
|
47
48
|
defaultHeight?: number;
|
|
48
49
|
fileMode?: 'path' | 'inline' | 'auto';
|
|
50
|
+
strictSize?: boolean;
|
|
49
51
|
}
|
|
50
52
|
interface CanvasCreateGroupInput {
|
|
51
53
|
title?: string;
|
|
@@ -27,6 +27,7 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
27
27
|
y?: number;
|
|
28
28
|
width?: number;
|
|
29
29
|
height?: number;
|
|
30
|
+
strictSize?: boolean;
|
|
30
31
|
}): string;
|
|
31
32
|
addWebpageNode(input: {
|
|
32
33
|
title?: string;
|
|
@@ -35,6 +36,7 @@ export declare class PmxCanvas extends EventEmitter {
|
|
|
35
36
|
y?: number;
|
|
36
37
|
width?: number;
|
|
37
38
|
height?: number;
|
|
39
|
+
strictSize?: boolean;
|
|
38
40
|
}): Promise<{
|
|
39
41
|
ok: boolean;
|
|
40
42
|
id: string;
|
|
@@ -96,6 +96,7 @@ export interface CanvasServerOptions {
|
|
|
96
96
|
port?: number;
|
|
97
97
|
workspaceRoot?: string;
|
|
98
98
|
autoOpenBrowser?: boolean;
|
|
99
|
+
allowPortFallback?: boolean;
|
|
99
100
|
}
|
|
100
101
|
export declare function startCanvasServer(options?: CanvasServerOptions): string | null;
|
|
101
102
|
export declare function stopCanvasServer(): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmx-canvas",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
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",
|
|
@@ -144,6 +144,11 @@ pmx-canvas open
|
|
|
144
144
|
pmx-canvas arrange --layout flow
|
|
145
145
|
pmx-canvas focus <node-id> --no-pan # Select/raise without moving the user's viewport
|
|
146
146
|
pmx-canvas fit --width 1440 --height 900 # Fit the whole board for screenshots/review
|
|
147
|
+
pmx-canvas screenshot --output ./canvas.png # Shorthand for `webview screenshot`
|
|
148
|
+
pmx-canvas json-render --schema --summary # Inspect json-render component catalog
|
|
149
|
+
pmx-canvas json-render --example --component Table
|
|
150
|
+
pmx-canvas node add --type markdown --title "Long doc" --strict-size # Scroll instead of auto-fit
|
|
151
|
+
pmx-canvas node add --type graph --graphType pie --data-file metrics.json --show-legend false --show-labels false
|
|
147
152
|
pmx-canvas node update <node-id> --spec-file ./dashboard.json
|
|
148
153
|
pmx-canvas validate spec --type json-render --spec-file ./dashboard.json --summary
|
|
149
154
|
pmx-canvas web-artifact build --title "Dashboard" --app-file ./App.tsx --deps recharts --include-logs
|
|
@@ -170,6 +175,10 @@ pmx-canvas spatial
|
|
|
170
175
|
- `search`, `layout`, `status`, `arrange`, `focus` — inspect and navigate the canvas. Prefer
|
|
171
176
|
`focus --no-pan` when you only need to select/raise a node without hijacking the human's camera.
|
|
172
177
|
- `fit [id ...]` — set the server viewport to fit the whole canvas or selected nodes before screenshots or whole-board review
|
|
178
|
+
- `screenshot --output <path>` — top-level shortcut for `webview screenshot`; supports `--format png|jpeg|webp` and `--quality`
|
|
179
|
+
- `json-render --schema|--examples` — inspect the json-render component catalog with `--component`/`--field` filters; same data as `node schema --type json-render` in a more direct shape
|
|
180
|
+
- `--strict-size` (alias `--scroll-overflow`) on `node add`/`node update` — keep explicit width/height fixed and scroll overflowing content instead of letting the renderer auto-fit. Useful for long markdown, dense webpages, and dashboards that should fit a tile-sized frame.
|
|
181
|
+
- `--show-legend false` / `--show-labels false` on `node add --type graph` and `graph add` — hide chart legends and pie slice labels for compact graph nodes in tile-style boards.
|
|
173
182
|
- `open` — open the current workbench in the browser
|
|
174
183
|
- `pin --list|--clear|<ids...>` — manage context pins
|
|
175
184
|
- `undo`, `redo`, `history` — time travel
|
package/src/cli/agent.ts
CHANGED
|
@@ -155,7 +155,7 @@ function parseFlags(args: string[]): { positional: string[]; flags: Record<strin
|
|
|
155
155
|
const BOOL_FLAGS = new Set([
|
|
156
156
|
'help', 'h', 'ids', 'stdin', 'yes', 'list', 'clear', 'set', 'animated', 'dry-run',
|
|
157
157
|
'no-open-in-canvas', 'lock-arrange', 'unlock-arrange', 'json', 'compact', 'summary',
|
|
158
|
-
'verbose', 'include-logs', 'no-pan',
|
|
158
|
+
'verbose', 'include-logs', 'no-pan', 'schema', 'example', 'examples', 'strict-size', 'scroll-overflow',
|
|
159
159
|
]);
|
|
160
160
|
for (let i = 0; i < args.length; i++) {
|
|
161
161
|
const arg = args[i];
|
|
@@ -249,6 +249,10 @@ function optionalBooleanFlag(flags: Record<string, string | true>, name: string,
|
|
|
249
249
|
die(`Invalid value for --${name}: ${String(val)}`, hint);
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
+
function applyStrictSizeFlags(body: Record<string, unknown>, flags: Record<string, string | true>): void {
|
|
253
|
+
if (flags['strict-size'] || flags['scroll-overflow']) body.strictSize = true;
|
|
254
|
+
}
|
|
255
|
+
|
|
252
256
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
253
257
|
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
254
258
|
}
|
|
@@ -606,6 +610,7 @@ async function buildJsonRenderRequestBody(
|
|
|
606
610
|
width: 'Use a positive number, e.g. --width 840',
|
|
607
611
|
height: 'Use a positive number, e.g. --height 620',
|
|
608
612
|
});
|
|
613
|
+
applyStrictSizeFlags(body, flags);
|
|
609
614
|
return body;
|
|
610
615
|
}
|
|
611
616
|
|
|
@@ -665,6 +670,10 @@ async function buildGraphRequestBody(
|
|
|
665
670
|
if (color) body.color = color;
|
|
666
671
|
if (barColor) body.barColor = barColor;
|
|
667
672
|
if (lineColor) body.lineColor = lineColor;
|
|
673
|
+
const showLegend = optionalBooleanFlag(flags, 'show-legend', 'Use --show-legend true or --show-legend false');
|
|
674
|
+
const showLabels = optionalBooleanFlag(flags, 'show-labels', 'Use --show-labels true or --show-labels false');
|
|
675
|
+
if (showLegend !== undefined) body.showLegend = showLegend;
|
|
676
|
+
if (showLabels !== undefined) body.showLabels = showLabels;
|
|
668
677
|
|
|
669
678
|
const chartHeight = optionalPositiveFiniteFlag(flags, 'chart-height', 'Use a positive number, e.g. --chart-height 300');
|
|
670
679
|
const x = optionalFiniteFlag(flags, 'x', 'Use a finite number, e.g. --x 500');
|
|
@@ -682,6 +691,7 @@ async function buildGraphRequestBody(
|
|
|
682
691
|
if (y !== undefined) body.y = y;
|
|
683
692
|
if (width !== undefined) body.width = width;
|
|
684
693
|
if (nodeHeight !== undefined) body.nodeHeight = nodeHeight;
|
|
694
|
+
applyStrictSizeFlags(body, flags);
|
|
685
695
|
return body;
|
|
686
696
|
}
|
|
687
697
|
|
|
@@ -1067,6 +1077,7 @@ cmd('node add', 'Add a node to the canvas', [
|
|
|
1067
1077
|
width: 'Use a positive number, e.g. --width 500',
|
|
1068
1078
|
height: 'Use a positive number, e.g. --height 280',
|
|
1069
1079
|
});
|
|
1080
|
+
applyStrictSizeFlags(body, flags);
|
|
1070
1081
|
|
|
1071
1082
|
// Support --stdin for piping content
|
|
1072
1083
|
if (flags.stdin) {
|
|
@@ -1081,6 +1092,37 @@ cmd('node add', 'Add a node to the canvas', [
|
|
|
1081
1092
|
output(result);
|
|
1082
1093
|
});
|
|
1083
1094
|
|
|
1095
|
+
cmd('json-render', 'Show json-render schema and canonical examples', [
|
|
1096
|
+
'pmx-canvas json-render --schema --summary',
|
|
1097
|
+
'pmx-canvas json-render --examples',
|
|
1098
|
+
'pmx-canvas json-render --example --component Table',
|
|
1099
|
+
'pmx-canvas json-render --schema --component Badge --field variant',
|
|
1100
|
+
], async (args) => {
|
|
1101
|
+
const { flags } = parseFlags(args);
|
|
1102
|
+
if (flags.help || flags.h) return showCommandHelp('json-render');
|
|
1103
|
+
|
|
1104
|
+
const schema = await loadCanvasSchema();
|
|
1105
|
+
const componentName = getStringFlag(flags, 'component');
|
|
1106
|
+
const fieldName = getStringFlag(flags, 'field');
|
|
1107
|
+
|
|
1108
|
+
if (flags.example || flags.examples) {
|
|
1109
|
+
if (fieldName) die('--field is only supported with --schema.', 'Use: pmx-canvas json-render --schema --component Table --field rows');
|
|
1110
|
+
if (componentName) {
|
|
1111
|
+
const component = schema.jsonRender.components.find((entry) => entry.type === componentName);
|
|
1112
|
+
if (!component) die(`Unknown json-render component: ${componentName}`, 'Run: pmx-canvas json-render --schema --summary');
|
|
1113
|
+
output({ component: component.type, example: component.example });
|
|
1114
|
+
return;
|
|
1115
|
+
}
|
|
1116
|
+
output({
|
|
1117
|
+
rootShape: schema.jsonRender.rootShape,
|
|
1118
|
+
examples: Object.fromEntries(schema.jsonRender.components.map((entry) => [entry.type, entry.example])),
|
|
1119
|
+
});
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
output(filterJsonRenderSchemaView(schema.jsonRender, flags));
|
|
1124
|
+
});
|
|
1125
|
+
|
|
1084
1126
|
cmd('graph add', 'Add a graph node to the canvas', [
|
|
1085
1127
|
'pmx-canvas graph add --graph-type bar --data-file ./metrics.json --x-key label --y-key value',
|
|
1086
1128
|
'pmx-canvas graph add --graphType composed --data \'[{"day":"Mon","visits":10,"conversion":0.4}]\' --xKey day --barKey visits --lineKey conversion',
|
|
@@ -1097,6 +1139,7 @@ cmd('node schema', 'Describe server-supported node create schemas and canonical
|
|
|
1097
1139
|
'pmx-canvas node schema',
|
|
1098
1140
|
'pmx-canvas node schema --type webpage',
|
|
1099
1141
|
'pmx-canvas node schema --type json-render',
|
|
1142
|
+
'pmx-canvas json-render --schema --summary',
|
|
1100
1143
|
'pmx-canvas node schema --type json-render --component Table',
|
|
1101
1144
|
'pmx-canvas node schema --type webpage --field url',
|
|
1102
1145
|
'pmx-canvas node schema --summary',
|
|
@@ -1263,6 +1306,8 @@ cmd('node update', 'Update a node by ID', [
|
|
|
1263
1306
|
? false
|
|
1264
1307
|
: undefined;
|
|
1265
1308
|
|
|
1309
|
+
applyStrictSizeFlags(body, flags);
|
|
1310
|
+
|
|
1266
1311
|
if (x !== undefined || y !== undefined || width !== undefined || frameHeight !== undefined || arrangeLocked !== undefined) {
|
|
1267
1312
|
const existing = await api('GET', `/api/canvas/node/${encodeURIComponent(id)}`) as {
|
|
1268
1313
|
position: { x: number; y: number };
|
|
@@ -1294,7 +1339,7 @@ cmd('node update', 'Update a node by ID', [
|
|
|
1294
1339
|
if (Object.keys(body).length === 0) {
|
|
1295
1340
|
die(
|
|
1296
1341
|
'No updates specified',
|
|
1297
|
-
'Use --title, --content, --x, --y, --width, --height, --pinned, --lock-arrange, --unlock-arrange, or --stdin',
|
|
1342
|
+
'Use --title, --content, --x, --y, --width, --height, --strict-size, --pinned, --lock-arrange, --unlock-arrange, or --stdin',
|
|
1298
1343
|
);
|
|
1299
1344
|
}
|
|
1300
1345
|
|
|
@@ -2057,6 +2102,16 @@ cmd('webview screenshot', 'Capture a screenshot from the active Bun.WebView auto
|
|
|
2057
2102
|
});
|
|
2058
2103
|
});
|
|
2059
2104
|
|
|
2105
|
+
cmd('screenshot', 'Capture a screenshot from the active Bun.WebView automation session', [
|
|
2106
|
+
'pmx-canvas screenshot --output ./canvas.png',
|
|
2107
|
+
'pmx-canvas screenshot --output ./canvas.webp --format webp --quality 80',
|
|
2108
|
+
], async (args) => {
|
|
2109
|
+
if (args.includes('--help') || args.includes('-h')) return showCommandHelp('screenshot');
|
|
2110
|
+
const screenshotCommand = COMMANDS['webview screenshot'];
|
|
2111
|
+
if (!screenshotCommand) die('Internal error: webview screenshot command is unavailable.');
|
|
2112
|
+
await screenshotCommand.run(args);
|
|
2113
|
+
});
|
|
2114
|
+
|
|
2060
2115
|
// ── code-graph ───────────────────────────────────────────────
|
|
2061
2116
|
cmd('code-graph', 'Show auto-detected file dependency graph', [
|
|
2062
2117
|
'pmx-canvas code-graph',
|
|
@@ -2193,11 +2248,21 @@ function showCommandHelp(name: string): void {
|
|
|
2193
2248
|
console.log(' pmx-canvas node add --help --type json-render --component Table');
|
|
2194
2249
|
console.log(' pmx-canvas node add --help --type graph');
|
|
2195
2250
|
console.log(' pmx-canvas node add --help --type webpage --json');
|
|
2251
|
+
console.log(' Use --strict-size to keep explicit width/height fixed and scroll overflowing content.');
|
|
2252
|
+
}
|
|
2253
|
+
if (name === 'json-render') {
|
|
2254
|
+
console.log('\nOptions:');
|
|
2255
|
+
console.log(' --schema Show json-render catalog schema (default)');
|
|
2256
|
+
console.log(' --summary Show compact component summaries');
|
|
2257
|
+
console.log(' --component <name> Focus on one component');
|
|
2258
|
+
console.log(' --field <name> Focus on one component prop');
|
|
2259
|
+
console.log(' --example, --examples Print canonical component examples');
|
|
2196
2260
|
}
|
|
2197
2261
|
if (name === 'node add' || name === 'graph add' || name === 'validate spec') {
|
|
2198
2262
|
console.log('\nGraph flags:');
|
|
2199
2263
|
console.log(' Graph fields accept kebab-case CLI flags and camelCase schema names, e.g. --graph-type/--graphType and --x-key/--xKey');
|
|
2200
2264
|
console.log(' Use --node-height/--nodeHeight for canvas frame height; use --chart-height for chart content height. --height is kept as a frame-height alias for compatibility.');
|
|
2265
|
+
console.log(' Pass --show-legend false to hide legends in compact node layouts.');
|
|
2201
2266
|
}
|
|
2202
2267
|
if (name === 'node schema') {
|
|
2203
2268
|
console.log('\nFilters:');
|
|
@@ -2227,6 +2292,13 @@ function showCommandHelp(name: string): void {
|
|
|
2227
2292
|
console.log(' --padding <px> World-space padding around fitted nodes (default 60)');
|
|
2228
2293
|
console.log(' --max-scale <scale> Maximum zoom scale (default 1)');
|
|
2229
2294
|
}
|
|
2295
|
+
if (name === 'screenshot' || name === 'webview screenshot') {
|
|
2296
|
+
console.log('\nOptions:');
|
|
2297
|
+
console.log(' --output <path> Required output image path');
|
|
2298
|
+
console.log(' --format <type> png, jpeg, or webp');
|
|
2299
|
+
console.log(' --quality <number> Encoder quality for lossy formats');
|
|
2300
|
+
console.log(' Requires an active automation session: pmx-canvas webview start');
|
|
2301
|
+
}
|
|
2230
2302
|
if (name === 'external-app add') {
|
|
2231
2303
|
console.log('\nOptions:');
|
|
2232
2304
|
console.log(' --kind excalidraw External app kind to create');
|
|
@@ -2258,6 +2330,7 @@ Node commands:
|
|
|
2258
2330
|
pmx-canvas node get <id> Get a node by ID
|
|
2259
2331
|
pmx-canvas node update <id> [opts] Update a node
|
|
2260
2332
|
pmx-canvas node remove <id> Remove a node
|
|
2333
|
+
pmx-canvas json-render Show json-render schema/examples
|
|
2261
2334
|
pmx-canvas graph add [options] Add a graph node
|
|
2262
2335
|
|
|
2263
2336
|
Edge commands:
|
|
@@ -2277,6 +2350,7 @@ Canvas commands:
|
|
|
2277
2350
|
pmx-canvas watch [options] Watch semantic canvas changes over SSE
|
|
2278
2351
|
pmx-canvas focus <id> Pan viewport to node
|
|
2279
2352
|
pmx-canvas fit [id ...] Fit viewport to canvas or selected nodes
|
|
2353
|
+
pmx-canvas screenshot Save automation screenshot to disk
|
|
2280
2354
|
pmx-canvas external-app add Add hosted external apps like Excalidraw
|
|
2281
2355
|
pmx-canvas webview status Show WebView automation status
|
|
2282
2356
|
pmx-canvas webview start [options] Start or replace automation session
|
|
@@ -2325,6 +2399,8 @@ Examples:
|
|
|
2325
2399
|
pmx-canvas node add --type markdown --title "API Design" --content "# REST API"
|
|
2326
2400
|
pmx-canvas node add --type webpage --url "https://example.com/docs"
|
|
2327
2401
|
pmx-canvas node add --type json-render --title "Dashboard" --spec-file ./dashboard.json
|
|
2402
|
+
pmx-canvas json-render --schema --summary
|
|
2403
|
+
pmx-canvas json-render --example --component Table
|
|
2328
2404
|
pmx-canvas node add --type web-artifact --title "Dashboard" --app-file ./App.tsx
|
|
2329
2405
|
pmx-canvas node add --type graph --graph-type bar --data-file ./metrics.json --x-key label --y-key value
|
|
2330
2406
|
pmx-canvas graph add --graph-type bar --data-file ./metrics.json --x-key label --y-key value
|
package/src/cli/index.ts
CHANGED
|
@@ -29,8 +29,8 @@ if (args.includes('--version') || args.includes('-v')) {
|
|
|
29
29
|
// ── Agent CLI subcommands ────────────────────────────────────
|
|
30
30
|
// If first arg is a known subcommand (not a --flag), route to the agent CLI.
|
|
31
31
|
const AGENT_COMMANDS = new Set([
|
|
32
|
-
'node', 'edge', 'search', 'layout', 'status', 'arrange', 'focus',
|
|
33
|
-
'fit', 'pin', 'undo', 'redo', 'history', 'snapshot', 'diff', 'group', 'webview', 'open',
|
|
32
|
+
'node', 'edge', 'json-render', 'search', 'layout', 'status', 'arrange', 'focus',
|
|
33
|
+
'fit', 'screenshot', 'pin', 'undo', 'redo', 'history', 'snapshot', 'diff', 'group', 'webview', 'open',
|
|
34
34
|
'clear', 'code-graph', 'spatial', 'watch', 'web-artifact', 'external-app', 'graph', 'batch', 'validate', 'serve',
|
|
35
35
|
]);
|
|
36
36
|
|
|
@@ -486,8 +486,10 @@ Server options:
|
|
|
486
486
|
|
|
487
487
|
Agent CLI (works against running server):
|
|
488
488
|
node add|list|get|update|remove Manage nodes
|
|
489
|
+
json-render Show json-render schema/examples
|
|
489
490
|
graph add Add graph nodes (alias for node add --type graph)
|
|
490
491
|
edge add|list|remove Manage edges
|
|
492
|
+
screenshot Save a WebView automation screenshot
|
|
491
493
|
webview status|start|evaluate|resize|screenshot|stop
|
|
492
494
|
Manage Bun.WebView automation session
|
|
493
495
|
search <query> Search nodes
|
|
@@ -540,6 +542,7 @@ Examples:
|
|
|
540
542
|
pmx-canvas node add --type markdown --title "Hello World" Add a node
|
|
541
543
|
pmx-canvas node add --type webpage --url "https://example.com" Add a webpage node
|
|
542
544
|
pmx-canvas node add --type json-render --title "Dashboard" --spec-file ./dashboard.json
|
|
545
|
+
pmx-canvas json-render --schema --summary Show json-render schema info
|
|
543
546
|
pmx-canvas node add --type web-artifact --title "Dashboard" --app-file ./App.tsx
|
|
544
547
|
pmx-canvas graph add --graph-type bar --data-file ./metrics.json --x-key label --y-key value
|
|
545
548
|
pmx-canvas node list List all nodes
|
|
@@ -549,7 +552,7 @@ Examples:
|
|
|
549
552
|
pmx-canvas validate spec --type graph --graph-type bar --data-file ./metrics.json --x-key label --y-key value
|
|
550
553
|
pmx-canvas open Open the workbench in a browser
|
|
551
554
|
pmx-canvas webview status Show WebView automation status
|
|
552
|
-
pmx-canvas
|
|
555
|
+
pmx-canvas screenshot --output ./canvas.png Save a WebView screenshot
|
|
553
556
|
pmx-canvas search "auth" Find nodes
|
|
554
557
|
pmx-canvas arrange --layout column Auto-arrange
|
|
555
558
|
pmx-canvas batch --file ./canvas-ops.json Run batch canvas ops
|
|
@@ -179,12 +179,13 @@ export function CanvasNode({ node, children, onContextMenu }: CanvasNodeProps) {
|
|
|
179
179
|
autoFitPersistTimer.current = null;
|
|
180
180
|
}
|
|
181
181
|
};
|
|
182
|
-
}, [node.id, node.type, node.data.mode, node.collapsed, node.dockPosition, node.size.width, node.size.height]);
|
|
182
|
+
}, [node.id, node.type, node.data.mode, node.data.strictSize, node.collapsed, node.dockPosition, node.size.width, node.size.height]);
|
|
183
183
|
|
|
184
184
|
const isPinned = node.pinned;
|
|
185
185
|
const isTrace = node.type === 'trace';
|
|
186
186
|
const isTraceRunning = isTrace && node.data.status === 'running';
|
|
187
187
|
const isGroup = node.type === 'group';
|
|
188
|
+
const isStrictSize = node.data.strictSize === true;
|
|
188
189
|
const viewportScale = Math.max(viewport.value.scale, 0.01);
|
|
189
190
|
const chromeScale = viewportScale < 1 ? Math.min(2.2, 1 / viewportScale) : 1;
|
|
190
191
|
|
|
@@ -213,6 +214,7 @@ export function CanvasNode({ node, children, onContextMenu }: CanvasNodeProps) {
|
|
|
213
214
|
isTrace ? 'trace-node' : '',
|
|
214
215
|
isTraceRunning ? 'trace-running' : '',
|
|
215
216
|
isGroup ? 'group-node' : '',
|
|
217
|
+
isStrictSize ? 'strict-size' : '',
|
|
216
218
|
]
|
|
217
219
|
.filter(Boolean)
|
|
218
220
|
.join(' ');
|
|
@@ -12,7 +12,7 @@ function hasExplicitStructuredFrame(node: CanvasNodeState): boolean {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export function shouldAutoFitNode(node: CanvasNodeState): boolean {
|
|
15
|
-
return !node.collapsed && !node.dockPosition && node.type !== 'group' && !isExtAppNode(node) && !hasExplicitStructuredFrame(node);
|
|
15
|
+
return !node.collapsed && !node.dockPosition && node.data.strictSize !== true && node.type !== 'group' && !isExtAppNode(node) && !hasExplicitStructuredFrame(node);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export function computeAutoFitHeight(node: CanvasNodeState, contentHeight: number): number | null {
|