pmx-canvas 0.1.0
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 +38 -0
- package/LICENSE +21 -0
- package/Readme.md +865 -0
- package/dist/canvas/global.css +3173 -0
- package/dist/canvas/index.js +183 -0
- package/dist/json-render/index.css +2 -0
- package/dist/json-render/index.js +389 -0
- package/dist/types/cli/agent.d.ts +13 -0
- package/dist/types/cli/index.d.ts +2 -0
- package/dist/types/cli/watch.d.ts +5 -0
- package/dist/types/client/App.d.ts +1 -0
- package/dist/types/client/canvas/AttentionHistory.d.ts +1 -0
- package/dist/types/client/canvas/AttentionToast.d.ts +1 -0
- package/dist/types/client/canvas/CanvasNode.d.ts +8 -0
- package/dist/types/client/canvas/CanvasViewport.d.ts +8 -0
- package/dist/types/client/canvas/CommandPalette.d.ts +4 -0
- package/dist/types/client/canvas/ContextMenu.d.ts +24 -0
- package/dist/types/client/canvas/ContextPinBar.d.ts +1 -0
- package/dist/types/client/canvas/ContextPinHud.d.ts +1 -0
- package/dist/types/client/canvas/DockedNode.d.ts +4 -0
- package/dist/types/client/canvas/EdgeLayer.d.ts +8 -0
- package/dist/types/client/canvas/ExpandedNodeOverlay.d.ts +1 -0
- package/dist/types/client/canvas/FocusFieldLayer.d.ts +1 -0
- package/dist/types/client/canvas/Minimap.d.ts +23 -0
- package/dist/types/client/canvas/SelectionBar.d.ts +1 -0
- package/dist/types/client/canvas/ShortcutOverlay.d.ts +3 -0
- package/dist/types/client/canvas/SnapshotPanel.d.ts +7 -0
- package/dist/types/client/canvas/snap-guides.d.ts +23 -0
- package/dist/types/client/canvas/use-node-drag.d.ts +15 -0
- package/dist/types/client/canvas/use-node-resize.d.ts +15 -0
- package/dist/types/client/canvas/use-pan-zoom.d.ts +16 -0
- package/dist/types/client/ext-app/bridge.d.ts +161 -0
- package/dist/types/client/icons.d.ts +70 -0
- package/dist/types/client/index.d.ts +1 -0
- package/dist/types/client/nodes/ContextNode.d.ts +34 -0
- package/dist/types/client/nodes/ExtAppFrame.d.ts +18 -0
- package/dist/types/client/nodes/FileNode.d.ts +5 -0
- package/dist/types/client/nodes/GroupNode.d.ts +6 -0
- package/dist/types/client/nodes/ImageNode.d.ts +10 -0
- package/dist/types/client/nodes/InlineFormatBar.d.ts +7 -0
- package/dist/types/client/nodes/InlineMarkdownEditor.d.ts +14 -0
- package/dist/types/client/nodes/LedgerNode.d.ts +4 -0
- package/dist/types/client/nodes/MarkdownNode.d.ts +6 -0
- package/dist/types/client/nodes/McpAppNode.d.ts +4 -0
- package/dist/types/client/nodes/MdFormatBar.d.ts +8 -0
- package/dist/types/client/nodes/PromptNode.d.ts +5 -0
- package/dist/types/client/nodes/ResponseNode.d.ts +5 -0
- package/dist/types/client/nodes/StatusNode.d.ts +4 -0
- package/dist/types/client/nodes/StatusSummary.d.ts +4 -0
- package/dist/types/client/nodes/TraceNode.d.ts +4 -0
- package/dist/types/client/nodes/WebpageNode.d.ts +5 -0
- package/dist/types/client/nodes/image-warnings.d.ts +6 -0
- package/dist/types/client/nodes/inline-editor-commands.d.ts +11 -0
- package/dist/types/client/nodes/md-format.d.ts +25 -0
- package/dist/types/client/state/attention-bridge.d.ts +3 -0
- package/dist/types/client/state/attention-store.d.ts +25 -0
- package/dist/types/client/state/canvas-store.d.ts +74 -0
- package/dist/types/client/state/intent-bridge.d.ts +158 -0
- package/dist/types/client/state/sse-bridge.d.ts +5 -0
- package/dist/types/client/theme/tokens.d.ts +27 -0
- package/dist/types/client/types.d.ts +40 -0
- package/dist/types/client/utils/ext-app-tool-result.d.ts +1 -0
- package/dist/types/client/utils/placement.d.ts +1 -0
- package/dist/types/client/utils/platform.d.ts +2 -0
- package/dist/types/json-render/catalog.d.ts +815 -0
- package/dist/types/json-render/charts/components.d.ts +54 -0
- package/dist/types/json-render/charts/definitions.d.ts +103 -0
- package/dist/types/json-render/charts/extra-components.d.ts +58 -0
- package/dist/types/json-render/charts/extra-definitions.d.ts +181 -0
- package/dist/types/json-render/renderer/index.d.ts +16 -0
- package/dist/types/json-render/schema.d.ts +46 -0
- package/dist/types/json-render/server.d.ts +55 -0
- package/dist/types/mcp/server.d.ts +22 -0
- package/dist/types/server/agent-context.d.ts +21 -0
- package/dist/types/server/artifact-paths.d.ts +3 -0
- package/dist/types/server/canvas-operations.d.ts +154 -0
- package/dist/types/server/canvas-provenance.d.ts +13 -0
- package/dist/types/server/canvas-schema.d.ts +49 -0
- package/dist/types/server/canvas-serialization.d.ts +25 -0
- package/dist/types/server/canvas-state.d.ts +174 -0
- package/dist/types/server/canvas-validation.d.ts +33 -0
- package/dist/types/server/chart-template.d.ts +29 -0
- package/dist/types/server/code-graph.d.ts +67 -0
- package/dist/types/server/context-cards.d.ts +24 -0
- package/dist/types/server/diagram-presets.d.ts +28 -0
- package/dist/types/server/ext-app-call-registry.d.ts +16 -0
- package/dist/types/server/ext-app-tool-result.d.ts +1 -0
- package/dist/types/server/file-watcher.d.ts +16 -0
- package/dist/types/server/index.d.ts +243 -0
- package/dist/types/server/mcp-app-candidate.d.ts +25 -0
- package/dist/types/server/mcp-app-host.d.ts +65 -0
- package/dist/types/server/mcp-app-runtime.d.ts +47 -0
- package/dist/types/server/mutation-history.d.ts +105 -0
- package/dist/types/server/placement.d.ts +37 -0
- package/dist/types/server/server.d.ts +103 -0
- package/dist/types/server/spatial-analysis.d.ts +87 -0
- package/dist/types/server/trace-manager.d.ts +48 -0
- package/dist/types/server/web-artifacts.d.ts +50 -0
- package/dist/types/server/webpage-node.d.ts +25 -0
- package/dist/types/shared/auto-arrange.d.ts +29 -0
- package/dist/types/shared/ext-app-tool-result.d.ts +9 -0
- package/dist/types/shared/placement.d.ts +26 -0
- package/dist/types/shared/semantic-attention.d.ts +97 -0
- package/package.json +109 -0
- package/skills/data-analysis/SKILL.md +324 -0
- package/skills/doc-coauthoring/SKILL.md +375 -0
- package/skills/frontend-design/SKILL.md +45 -0
- package/skills/json-render-codegen/SKILL.md +112 -0
- package/skills/json-render-core/SKILL.md +265 -0
- package/skills/json-render-ink/SKILL.md +273 -0
- package/skills/json-render-mcp/SKILL.md +132 -0
- package/skills/json-render-react/SKILL.md +264 -0
- package/skills/json-render-shadcn/SKILL.md +159 -0
- package/skills/playwright-cli/SKILL.md +67 -0
- package/skills/pmx-canvas/SKILL.md +668 -0
- package/skills/pmx-canvas/evals/evals.json +186 -0
- package/skills/pmx-canvas-testing/SKILL.md +78 -0
- package/skills/published-consumer-e2e/SKILL.md +43 -0
- package/skills/published-consumer-e2e/scripts/run-published-consumer-e2e.sh +241 -0
- package/skills/web-artifacts-builder/SKILL.md +80 -0
- package/skills/web-artifacts-builder/scripts/bundle-artifact.sh +167 -0
- package/skills/web-artifacts-builder/scripts/init-artifact.sh +425 -0
- package/skills/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
- package/skills/web-design-guidelines/SKILL.md +39 -0
- package/src/cli/agent.ts +2144 -0
- package/src/cli/index.ts +622 -0
- package/src/cli/watch.ts +88 -0
- package/src/client/App.tsx +507 -0
- package/src/client/canvas/AttentionHistory.tsx +81 -0
- package/src/client/canvas/AttentionToast.tsx +19 -0
- package/src/client/canvas/CanvasNode.tsx +363 -0
- package/src/client/canvas/CanvasViewport.tsx +590 -0
- package/src/client/canvas/CommandPalette.tsx +302 -0
- package/src/client/canvas/ContextMenu.tsx +601 -0
- package/src/client/canvas/ContextPinBar.tsx +25 -0
- package/src/client/canvas/ContextPinHud.tsx +22 -0
- package/src/client/canvas/DockedNode.tsx +66 -0
- package/src/client/canvas/EdgeLayer.tsx +280 -0
- package/src/client/canvas/ExpandedNodeOverlay.tsx +260 -0
- package/src/client/canvas/FocusFieldLayer.tsx +107 -0
- package/src/client/canvas/Minimap.tsx +301 -0
- package/src/client/canvas/SelectionBar.tsx +69 -0
- package/src/client/canvas/ShortcutOverlay.tsx +69 -0
- package/src/client/canvas/SnapshotPanel.tsx +236 -0
- package/src/client/canvas/snap-guides.ts +170 -0
- package/src/client/canvas/use-node-drag.ts +51 -0
- package/src/client/canvas/use-node-resize.ts +59 -0
- package/src/client/canvas/use-pan-zoom.ts +191 -0
- package/src/client/ext-app/bridge.ts +542 -0
- package/src/client/icons.tsx +424 -0
- package/src/client/index.tsx +7 -0
- package/src/client/nodes/ContextNode.tsx +412 -0
- package/src/client/nodes/ExtAppFrame.tsx +509 -0
- package/src/client/nodes/FileNode.tsx +256 -0
- package/src/client/nodes/GroupNode.tsx +39 -0
- package/src/client/nodes/ImageNode.tsx +160 -0
- package/src/client/nodes/InlineFormatBar.tsx +169 -0
- package/src/client/nodes/InlineMarkdownEditor.tsx +123 -0
- package/src/client/nodes/LedgerNode.tsx +37 -0
- package/src/client/nodes/MarkdownNode.tsx +359 -0
- package/src/client/nodes/McpAppNode.tsx +85 -0
- package/src/client/nodes/MdFormatBar.tsx +109 -0
- package/src/client/nodes/PromptNode.tsx +597 -0
- package/src/client/nodes/ResponseNode.tsx +153 -0
- package/src/client/nodes/StatusNode.tsx +84 -0
- package/src/client/nodes/StatusSummary.tsx +38 -0
- package/src/client/nodes/TraceNode.tsx +120 -0
- package/src/client/nodes/WebpageNode.tsx +288 -0
- package/src/client/nodes/image-warnings.ts +95 -0
- package/src/client/nodes/inline-editor-commands.ts +37 -0
- package/src/client/nodes/md-format.ts +206 -0
- package/src/client/state/attention-bridge.ts +328 -0
- package/src/client/state/attention-store.ts +73 -0
- package/src/client/state/canvas-store.ts +631 -0
- package/src/client/state/intent-bridge.ts +315 -0
- package/src/client/state/sse-bridge.ts +965 -0
- package/src/client/theme/global.css +3173 -0
- package/src/client/theme/tokens.ts +72 -0
- package/src/client/types-shims.d.ts +5 -0
- package/src/client/types.ts +81 -0
- package/src/client/utils/ext-app-tool-result.ts +4 -0
- package/src/client/utils/placement.ts +4 -0
- package/src/client/utils/platform.ts +2 -0
- package/src/json-render/catalog.ts +256 -0
- package/src/json-render/charts/components.tsx +198 -0
- package/src/json-render/charts/definitions.ts +81 -0
- package/src/json-render/charts/extra-components.tsx +267 -0
- package/src/json-render/charts/extra-definitions.ts +145 -0
- package/src/json-render/renderer/index.css +174 -0
- package/src/json-render/renderer/index.tsx +86 -0
- package/src/json-render/schema.ts +62 -0
- package/src/json-render/server.ts +597 -0
- package/src/mcp/server.ts +1377 -0
- package/src/server/agent-context.ts +242 -0
- package/src/server/artifact-paths.ts +17 -0
- package/src/server/canvas-operations.ts +1279 -0
- package/src/server/canvas-provenance.ts +243 -0
- package/src/server/canvas-schema.ts +432 -0
- package/src/server/canvas-serialization.ts +95 -0
- package/src/server/canvas-state.ts +1134 -0
- package/src/server/canvas-validation.ts +114 -0
- package/src/server/chart-template.ts +449 -0
- package/src/server/code-graph.ts +370 -0
- package/src/server/context-cards.ts +31 -0
- package/src/server/diagram-presets.ts +71 -0
- package/src/server/ext-app-call-registry.ts +77 -0
- package/src/server/ext-app-tool-result.ts +4 -0
- package/src/server/file-watcher.ts +121 -0
- package/src/server/index.ts +647 -0
- package/src/server/mcp-app-candidate.ts +174 -0
- package/src/server/mcp-app-host.ts +814 -0
- package/src/server/mcp-app-runtime.ts +459 -0
- package/src/server/mutation-history.ts +350 -0
- package/src/server/placement.ts +125 -0
- package/src/server/server.ts +3846 -0
- package/src/server/spatial-analysis.ts +356 -0
- package/src/server/trace-manager.ts +333 -0
- package/src/server/web-artifacts/scripts/bundle-artifact.sh +167 -0
- package/src/server/web-artifacts/scripts/init-artifact.sh +426 -0
- package/src/server/web-artifacts/scripts/shadcn-components.tar.gz +0 -0
- package/src/server/web-artifacts.ts +442 -0
- package/src/server/webpage-node.ts +328 -0
- package/src/shared/auto-arrange.ts +439 -0
- package/src/shared/ext-app-tool-result.ts +76 -0
- package/src/shared/placement.ts +81 -0
- package/src/shared/semantic-attention.ts +598 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
function logRequestError(action: string, error: unknown): void {
|
|
2
|
+
console.error(`[intent-bridge] ${action} failed`, error);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
async function requestJson<T>(
|
|
6
|
+
action: string,
|
|
7
|
+
url: string,
|
|
8
|
+
fallback: T,
|
|
9
|
+
init?: RequestInit,
|
|
10
|
+
): Promise<T> {
|
|
11
|
+
try {
|
|
12
|
+
const res = await fetch(url, init);
|
|
13
|
+
return (await res.json()) as T;
|
|
14
|
+
} catch (error) {
|
|
15
|
+
logRequestError(action, error);
|
|
16
|
+
return fallback;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function requestOk(
|
|
21
|
+
action: string,
|
|
22
|
+
url: string,
|
|
23
|
+
init?: RequestInit,
|
|
24
|
+
): Promise<{ ok: boolean }> {
|
|
25
|
+
try {
|
|
26
|
+
const res = await fetch(url, init);
|
|
27
|
+
return { ok: res.ok };
|
|
28
|
+
} catch (error) {
|
|
29
|
+
logRequestError(action, error);
|
|
30
|
+
return { ok: false };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function requestBestEffort(
|
|
35
|
+
action: string,
|
|
36
|
+
url: string,
|
|
37
|
+
init?: RequestInit,
|
|
38
|
+
): Promise<void> {
|
|
39
|
+
try {
|
|
40
|
+
await fetch(url, init);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
logRequestError(action, error);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Dispatch user intents from the canvas to the server (for TUI consumption). */
|
|
47
|
+
export async function sendIntent(
|
|
48
|
+
type: string,
|
|
49
|
+
payload: Record<string, unknown> = {},
|
|
50
|
+
): Promise<{ ok: boolean }> {
|
|
51
|
+
return requestJson('sendIntent', '/api/workbench/intent', { ok: false }, {
|
|
52
|
+
method: 'POST',
|
|
53
|
+
headers: { 'Content-Type': 'application/json' },
|
|
54
|
+
body: JSON.stringify({ type, payload }),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Fetch rendered markdown HTML from the server. */
|
|
59
|
+
export async function renderMarkdown(markdown: string): Promise<string> {
|
|
60
|
+
const data = await requestJson<{ html?: string }>('renderMarkdown', '/api/render', {}, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: { 'Content-Type': 'application/json' },
|
|
63
|
+
body: JSON.stringify({ markdown }),
|
|
64
|
+
});
|
|
65
|
+
return data.html ?? '';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Fetch file content from the server. */
|
|
69
|
+
export async function fetchFile(path: string): Promise<{
|
|
70
|
+
content: string;
|
|
71
|
+
provenance?: unknown;
|
|
72
|
+
}> {
|
|
73
|
+
return requestJson('fetchFile', `/api/file?path=${encodeURIComponent(path)}`, { content: '' });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Save file content to the server. */
|
|
77
|
+
export async function saveFile(
|
|
78
|
+
path: string,
|
|
79
|
+
content: string,
|
|
80
|
+
): Promise<{ ok: boolean; updatedAt?: string }> {
|
|
81
|
+
return requestJson('saveFile', '/api/file/save', { ok: false }, {
|
|
82
|
+
method: 'POST',
|
|
83
|
+
headers: { 'Content-Type': 'application/json' },
|
|
84
|
+
body: JSON.stringify({ path, content }),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Fetch current workbench state. */
|
|
89
|
+
export async function fetchWorkbenchState(): Promise<Record<string, unknown>> {
|
|
90
|
+
return requestJson('fetchWorkbenchState', '/api/workbench/state', {});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Open a markdown file in the workbench/canvas. */
|
|
94
|
+
export async function openWorkbenchFile(path: string): Promise<{ ok: boolean }> {
|
|
95
|
+
return requestOk('openWorkbenchFile', '/api/workbench/open', {
|
|
96
|
+
method: 'POST',
|
|
97
|
+
headers: { 'Content-Type': 'application/json' },
|
|
98
|
+
body: JSON.stringify({ path }),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Fetch canvas state from server. */
|
|
103
|
+
export async function fetchCanvasState(): Promise<Record<string, unknown>> {
|
|
104
|
+
return requestJson('fetchCanvasState', '/api/canvas/state', {});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Fetch available slash commands for prompt completion. */
|
|
108
|
+
export async function fetchSlashCommands(): Promise<Array<{ name: string; description: string }>> {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Submit a new canvas prompt. */
|
|
113
|
+
export async function submitCanvasPrompt(
|
|
114
|
+
text: string,
|
|
115
|
+
position?: { x: number; y: number },
|
|
116
|
+
parentNodeId?: string,
|
|
117
|
+
contextNodeIds?: string[],
|
|
118
|
+
threadNodeId?: string,
|
|
119
|
+
): Promise<{ ok: boolean; nodeId?: string; error?: string }> {
|
|
120
|
+
if (!text.trim()) return { ok: false, error: 'Prompt text is required' };
|
|
121
|
+
return requestJson('submitCanvasPrompt', '/api/canvas/prompt', { ok: false, error: 'Network error' }, {
|
|
122
|
+
method: 'POST',
|
|
123
|
+
headers: { 'Content-Type': 'application/json' },
|
|
124
|
+
body: JSON.stringify({
|
|
125
|
+
text,
|
|
126
|
+
...(position ? { position } : {}),
|
|
127
|
+
...(parentNodeId ? { parentNodeId } : {}),
|
|
128
|
+
...(contextNodeIds && contextNodeIds.length > 0 ? { contextNodeIds } : {}),
|
|
129
|
+
...(threadNodeId ? { threadNodeId } : {}),
|
|
130
|
+
}),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Submit a reply into an existing prompt thread. */
|
|
135
|
+
export async function submitThreadReply(
|
|
136
|
+
threadNodeId: string,
|
|
137
|
+
text: string,
|
|
138
|
+
): Promise<{ ok: boolean; nodeId?: string; error?: string }> {
|
|
139
|
+
return submitCanvasPrompt(text, undefined, undefined, undefined, threadNodeId);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Push canvas node updates to server. */
|
|
143
|
+
export async function pushCanvasUpdate(
|
|
144
|
+
updates: Array<{
|
|
145
|
+
id: string;
|
|
146
|
+
position?: { x: number; y: number };
|
|
147
|
+
size?: { width: number; height: number };
|
|
148
|
+
collapsed?: boolean;
|
|
149
|
+
dockPosition?: 'left' | 'right' | null;
|
|
150
|
+
}>,
|
|
151
|
+
): Promise<void> {
|
|
152
|
+
await requestBestEffort('pushCanvasUpdate', '/api/canvas/update', {
|
|
153
|
+
method: 'POST',
|
|
154
|
+
headers: { 'Content-Type': 'application/json' },
|
|
155
|
+
body: JSON.stringify({ updates }),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Create a canvas edge via the server. */
|
|
160
|
+
export async function createEdgeFromClient(
|
|
161
|
+
from: string,
|
|
162
|
+
to: string,
|
|
163
|
+
type: string,
|
|
164
|
+
label?: string,
|
|
165
|
+
): Promise<{ ok: boolean; id?: string }> {
|
|
166
|
+
return requestJson('createEdgeFromClient', '/api/canvas/edge', { ok: false }, {
|
|
167
|
+
method: 'POST',
|
|
168
|
+
headers: { 'Content-Type': 'application/json' },
|
|
169
|
+
body: JSON.stringify({ from, to, type, label }),
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Create a canvas node via the server. Returns the new node ID. */
|
|
174
|
+
export async function createNodeFromClient(opts: {
|
|
175
|
+
type?: string;
|
|
176
|
+
title?: string;
|
|
177
|
+
content?: string;
|
|
178
|
+
x?: number;
|
|
179
|
+
y?: number;
|
|
180
|
+
width?: number;
|
|
181
|
+
height?: number;
|
|
182
|
+
}): Promise<{ ok: boolean; id?: string }> {
|
|
183
|
+
return requestJson('createNodeFromClient', '/api/canvas/node', { ok: false }, {
|
|
184
|
+
method: 'POST',
|
|
185
|
+
headers: { 'Content-Type': 'application/json' },
|
|
186
|
+
body: JSON.stringify(opts),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Update a canvas node via the server. */
|
|
191
|
+
export async function updateNodeFromClient(
|
|
192
|
+
id: string,
|
|
193
|
+
patch: {
|
|
194
|
+
position?: { x: number; y: number };
|
|
195
|
+
size?: { width: number; height: number };
|
|
196
|
+
collapsed?: boolean;
|
|
197
|
+
pinned?: boolean;
|
|
198
|
+
dockPosition?: 'left' | 'right' | null;
|
|
199
|
+
title?: string;
|
|
200
|
+
content?: string;
|
|
201
|
+
data?: Record<string, unknown>;
|
|
202
|
+
},
|
|
203
|
+
): Promise<{ ok: boolean; id?: string }> {
|
|
204
|
+
return requestJson('updateNodeFromClient', `/api/canvas/node/${encodeURIComponent(id)}`, { ok: false }, {
|
|
205
|
+
method: 'PATCH',
|
|
206
|
+
headers: { 'Content-Type': 'application/json' },
|
|
207
|
+
body: JSON.stringify(patch),
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Refresh a webpage node from its persisted URL on the server. */
|
|
212
|
+
export async function refreshWebpageNodeFromClient(
|
|
213
|
+
id: string,
|
|
214
|
+
url?: string,
|
|
215
|
+
): Promise<{ ok: boolean; id?: string; error?: string }> {
|
|
216
|
+
return requestJson('refreshWebpageNodeFromClient', `/api/canvas/node/${encodeURIComponent(id)}/refresh`, { ok: false }, {
|
|
217
|
+
method: 'POST',
|
|
218
|
+
headers: { 'Content-Type': 'application/json' },
|
|
219
|
+
body: JSON.stringify(url ? { url } : {}),
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Remove a canvas node via the server. */
|
|
224
|
+
export async function removeNodeFromClient(id: string): Promise<{ ok: boolean; removed?: string }> {
|
|
225
|
+
return requestJson('removeNodeFromClient', `/api/canvas/node/${encodeURIComponent(id)}`, { ok: false }, {
|
|
226
|
+
method: 'DELETE',
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** Commit the current viewport to the authoritative server state. */
|
|
231
|
+
export async function updateViewportFromClient(
|
|
232
|
+
viewport: { x: number; y: number; scale: number },
|
|
233
|
+
): Promise<{ ok: boolean }> {
|
|
234
|
+
return requestJson('updateViewportFromClient', '/api/canvas/viewport', { ok: false }, {
|
|
235
|
+
method: 'POST',
|
|
236
|
+
headers: { 'Content-Type': 'application/json' },
|
|
237
|
+
body: JSON.stringify(viewport),
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ── Group API ─────────────────────────────────────────────────
|
|
242
|
+
|
|
243
|
+
/** Create a group containing the given child node IDs. */
|
|
244
|
+
export async function createGroupFromClient(opts: {
|
|
245
|
+
title?: string;
|
|
246
|
+
childIds?: string[];
|
|
247
|
+
color?: string;
|
|
248
|
+
x?: number;
|
|
249
|
+
y?: number;
|
|
250
|
+
width?: number;
|
|
251
|
+
height?: number;
|
|
252
|
+
}): Promise<{ ok: boolean; id?: string }> {
|
|
253
|
+
return requestJson('createGroupFromClient', '/api/canvas/group', { ok: false }, {
|
|
254
|
+
method: 'POST',
|
|
255
|
+
headers: { 'Content-Type': 'application/json' },
|
|
256
|
+
body: JSON.stringify(opts),
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** Add nodes to an existing group. */
|
|
261
|
+
export async function addToGroupFromClient(groupId: string, childIds: string[]): Promise<{ ok: boolean }> {
|
|
262
|
+
return requestJson('addToGroupFromClient', '/api/canvas/group/add', { ok: false }, {
|
|
263
|
+
method: 'POST',
|
|
264
|
+
headers: { 'Content-Type': 'application/json' },
|
|
265
|
+
body: JSON.stringify({ groupId, childIds }),
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/** Ungroup all children from a group. */
|
|
270
|
+
export async function ungroupFromClient(groupId: string): Promise<{ ok: boolean }> {
|
|
271
|
+
return requestJson('ungroupFromClient', '/api/canvas/group/ungroup', { ok: false }, {
|
|
272
|
+
method: 'POST',
|
|
273
|
+
headers: { 'Content-Type': 'application/json' },
|
|
274
|
+
body: JSON.stringify({ groupId }),
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// ── Snapshot API ──────────────────────────────────────────────
|
|
279
|
+
|
|
280
|
+
export interface CanvasSnapshotInfo {
|
|
281
|
+
id: string;
|
|
282
|
+
name: string;
|
|
283
|
+
createdAt: string;
|
|
284
|
+
nodeCount: number;
|
|
285
|
+
edgeCount: number;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export async function listSnapshots(): Promise<CanvasSnapshotInfo[]> {
|
|
289
|
+
return requestJson<CanvasSnapshotInfo[]>('listSnapshots', '/api/canvas/snapshots', []);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export async function saveSnapshot(name: string): Promise<{ ok: boolean; snapshot?: CanvasSnapshotInfo }> {
|
|
293
|
+
return requestJson('saveSnapshot', '/api/canvas/snapshots', { ok: false }, {
|
|
294
|
+
method: 'POST',
|
|
295
|
+
headers: { 'Content-Type': 'application/json' },
|
|
296
|
+
body: JSON.stringify({ name }),
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export async function restoreSnapshot(id: string): Promise<{ ok: boolean }> {
|
|
301
|
+
return requestJson('restoreSnapshot', `/api/canvas/snapshots/${id}`, { ok: false }, { method: 'POST' });
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export async function deleteSnapshot(id: string): Promise<{ ok: boolean }> {
|
|
305
|
+
return requestJson('deleteSnapshot', `/api/canvas/snapshots/${id}`, { ok: false }, { method: 'DELETE' });
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/** Remove a canvas edge via the server. */
|
|
309
|
+
export async function removeEdgeFromClient(edgeId: string): Promise<{ ok: boolean }> {
|
|
310
|
+
return requestJson('removeEdgeFromClient', '/api/canvas/edge', { ok: false }, {
|
|
311
|
+
method: 'DELETE',
|
|
312
|
+
headers: { 'Content-Type': 'application/json' },
|
|
313
|
+
body: JSON.stringify({ edge_id: edgeId }),
|
|
314
|
+
});
|
|
315
|
+
}
|