pmx-canvas 0.1.11 → 0.1.13
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 +130 -0
- package/dist/canvas/index.js +34 -34
- package/dist/types/client/nodes/trace-model.d.ts +9 -0
- package/dist/types/client/state/canvas-store.d.ts +2 -0
- package/dist/types/mcp/canvas-access.d.ts +88 -0
- package/dist/types/server/server.d.ts +1 -0
- package/dist/types/server/web-artifacts.d.ts +1 -0
- package/package.json +1 -1
- package/skills/web-artifacts-builder/scripts/init-artifact.sh +9 -8
- package/src/client/nodes/TraceNode.tsx +2 -6
- package/src/client/nodes/trace-model.ts +19 -0
- package/src/client/state/canvas-store.ts +5 -2
- package/src/client/state/sse-bridge.ts +2 -1
- package/src/mcp/canvas-access.ts +676 -0
- package/src/mcp/server.ts +184 -97
- package/src/server/canvas-operations.ts +1 -0
- package/src/server/canvas-schema.ts +11 -0
- package/src/server/diagram-presets.ts +6 -28
- package/src/server/index.ts +2 -2
- package/src/server/server.ts +5 -1
- package/src/server/web-artifacts/scripts/init-artifact.sh +9 -8
- package/src/server/web-artifacts.ts +14 -1
|
@@ -54,6 +54,8 @@ export declare function replaceViewport(next: ViewportState): void;
|
|
|
54
54
|
export declare function commitViewport(next: ViewportState): void;
|
|
55
55
|
export declare function applyServerCanvasLayout(layout: Pick<CanvasLayout, 'nodes' | 'edges'> & {
|
|
56
56
|
viewport?: ViewportState;
|
|
57
|
+
}, options?: {
|
|
58
|
+
applyViewport?: boolean;
|
|
57
59
|
}): void;
|
|
58
60
|
/**
|
|
59
61
|
* Smoothly animate the viewport to a target state.
|
|
@@ -0,0 +1,88 @@
|
|
|
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 refreshCanvasAccess(access: CanvasAccess): Promise<CanvasAccess>;
|
|
87
|
+
export declare function createCanvasAccess(): Promise<CanvasAccess>;
|
|
88
|
+
export {};
|
|
@@ -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;
|
|
@@ -38,6 +38,7 @@ export interface WebArtifactCanvasBuildResult extends WebArtifactBuildOutput {
|
|
|
38
38
|
openedInCanvas: boolean;
|
|
39
39
|
nodeId?: string;
|
|
40
40
|
url?: string;
|
|
41
|
+
completedAt: string;
|
|
41
42
|
}
|
|
42
43
|
export declare function resolveWorkspacePath(pathLike: string, cwd?: string): string;
|
|
43
44
|
export declare function resolveWebArtifactScriptPath(kind: 'init' | 'bundle'): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmx-canvas",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
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",
|
|
@@ -115,12 +115,13 @@ else
|
|
|
115
115
|
echo "✅ Using Vite $VITE_VERSION (Node 18 compatible)"
|
|
116
116
|
fi
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
120
|
-
|
|
121
|
-
else
|
|
122
|
-
|
|
123
|
-
fi
|
|
118
|
+
function sed_in_place() {
|
|
119
|
+
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
120
|
+
sed -i '' "$@"
|
|
121
|
+
else
|
|
122
|
+
sed -i "$@"
|
|
123
|
+
fi
|
|
124
|
+
}
|
|
124
125
|
|
|
125
126
|
declare -a PNPM_CMD
|
|
126
127
|
configure_pnpm
|
|
@@ -158,8 +159,8 @@ fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
|
|
|
158
159
|
"
|
|
159
160
|
|
|
160
161
|
echo "🧹 Cleaning up Vite template..."
|
|
161
|
-
|
|
162
|
-
|
|
162
|
+
sed_in_place '/<link rel="icon".*/d' index.html
|
|
163
|
+
sed_in_place 's/<title>.*<\/title>/<title>'"$PROJECT_NAME"'<\/title>/' index.html
|
|
163
164
|
|
|
164
165
|
echo "📦 Installing base dependencies..."
|
|
165
166
|
run_pnpm_quiet install
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CanvasNodeState } from '../types';
|
|
2
|
+
import { buildTraceDisplayModel } from './trace-model';
|
|
2
3
|
|
|
3
4
|
const CATEGORY_COLORS: Record<string, string> = {
|
|
4
5
|
mcp: 'var(--c-accent)',
|
|
@@ -20,12 +21,7 @@ const STATUS_COLORS: Record<string, string> = {
|
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
export function TraceNode({ node }: { node: CanvasNodeState }) {
|
|
23
|
-
const toolName = (node.data
|
|
24
|
-
const category = (node.data.category as string) || 'other';
|
|
25
|
-
const status = (node.data.status as string) || 'running';
|
|
26
|
-
const duration = (node.data.duration as string) || '';
|
|
27
|
-
const resultSummary = (node.data.resultSummary as string) || '';
|
|
28
|
-
const error = (node.data.error as string) || '';
|
|
24
|
+
const { toolName, category, status, duration, resultSummary, error } = buildTraceDisplayModel(node.data);
|
|
29
25
|
|
|
30
26
|
const catColor = CATEGORY_COLORS[category] ?? CATEGORY_COLORS.other;
|
|
31
27
|
const statusIcon = STATUS_ICONS[status] ?? '◌';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface TraceDisplayModel {
|
|
2
|
+
toolName: string;
|
|
3
|
+
category: string;
|
|
4
|
+
status: string;
|
|
5
|
+
duration: string;
|
|
6
|
+
resultSummary: string;
|
|
7
|
+
error: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function buildTraceDisplayModel(data: Record<string, unknown>): TraceDisplayModel {
|
|
11
|
+
return {
|
|
12
|
+
toolName: (data.toolName as string) || (data.title as string) || 'unknown',
|
|
13
|
+
category: (data.category as string) || 'other',
|
|
14
|
+
status: (data.status as string) || 'running',
|
|
15
|
+
duration: (data.duration as string) || '',
|
|
16
|
+
resultSummary: (data.resultSummary as string) || (data.content as string) || '',
|
|
17
|
+
error: (data.error as string) || '',
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -313,7 +313,10 @@ export function commitViewport(next: ViewportState): void {
|
|
|
313
313
|
void updateViewportFromClient(next);
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
-
export function applyServerCanvasLayout(
|
|
316
|
+
export function applyServerCanvasLayout(
|
|
317
|
+
layout: Pick<CanvasLayout, 'nodes' | 'edges'> & { viewport?: ViewportState },
|
|
318
|
+
options: { applyViewport?: boolean } = {},
|
|
319
|
+
): void {
|
|
317
320
|
const nextNodes = new Map<string, CanvasNodeState>();
|
|
318
321
|
let nextMaxZ = 1;
|
|
319
322
|
for (const node of layout.nodes) {
|
|
@@ -337,7 +340,7 @@ export function applyServerCanvasLayout(layout: Pick<CanvasLayout, 'nodes' | 'ed
|
|
|
337
340
|
const nextContextPinnedNodeIds = filterNodeIdSet(contextPinnedNodeIds.value, nextNodes);
|
|
338
341
|
|
|
339
342
|
batch(() => {
|
|
340
|
-
if (layout.viewport) {
|
|
343
|
+
if (options.applyViewport === true && layout.viewport) {
|
|
341
344
|
viewport.value = layout.viewport;
|
|
342
345
|
}
|
|
343
346
|
maxZ = nextMaxZ;
|
|
@@ -803,6 +803,7 @@ function handleCanvasLayoutUpdate(data: Record<string, unknown>): void {
|
|
|
803
803
|
}
|
|
804
804
|
| undefined;
|
|
805
805
|
if (!layout?.nodes) return;
|
|
806
|
+
const shouldApplyViewport = !hasInitialServerLayout.value;
|
|
806
807
|
hasInitialServerLayout.value = true;
|
|
807
808
|
|
|
808
809
|
const serverNodes = layout.nodes
|
|
@@ -824,7 +825,7 @@ function handleCanvasLayoutUpdate(data: Record<string, unknown>): void {
|
|
|
824
825
|
...(nextViewport ? { viewport: nextViewport } : {}),
|
|
825
826
|
nodes: serverNodes,
|
|
826
827
|
edges: serverEdges,
|
|
827
|
-
});
|
|
828
|
+
}, { applyViewport: shouldApplyViewport });
|
|
828
829
|
|
|
829
830
|
syncAttentionFromSse({ event: 'canvas-layout-update', data });
|
|
830
831
|
}
|