flowspec-mcp 2.0.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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +87 -0
  3. package/dist/config.d.ts +5 -0
  4. package/dist/config.js +16 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/db.d.ts +47 -0
  7. package/dist/db.js +283 -0
  8. package/dist/db.js.map +1 -0
  9. package/dist/export/yamlExporter.d.ts +6 -0
  10. package/dist/export/yamlExporter.js +155 -0
  11. package/dist/export/yamlExporter.js.map +1 -0
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.js +7 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/server.d.ts +2 -0
  16. package/dist/server.js +42 -0
  17. package/dist/server.js.map +1 -0
  18. package/dist/tools/analyseProject.d.ts +21 -0
  19. package/dist/tools/analyseProject.js +105 -0
  20. package/dist/tools/analyseProject.js.map +1 -0
  21. package/dist/tools/createEdge.d.ts +33 -0
  22. package/dist/tools/createEdge.js +31 -0
  23. package/dist/tools/createEdge.js.map +1 -0
  24. package/dist/tools/createNode.d.ts +45 -0
  25. package/dist/tools/createNode.js +31 -0
  26. package/dist/tools/createNode.js.map +1 -0
  27. package/dist/tools/createProject.d.ts +17 -0
  28. package/dist/tools/createProject.js +16 -0
  29. package/dist/tools/createProject.js.map +1 -0
  30. package/dist/tools/deleteEdge.d.ts +24 -0
  31. package/dist/tools/deleteEdge.js +19 -0
  32. package/dist/tools/deleteEdge.js.map +1 -0
  33. package/dist/tools/deleteNode.d.ts +24 -0
  34. package/dist/tools/deleteNode.js +19 -0
  35. package/dist/tools/deleteNode.js.map +1 -0
  36. package/dist/tools/deleteProject.d.ts +21 -0
  37. package/dist/tools/deleteProject.js +18 -0
  38. package/dist/tools/deleteProject.js.map +1 -0
  39. package/dist/tools/getProject.d.ts +21 -0
  40. package/dist/tools/getProject.js +18 -0
  41. package/dist/tools/getProject.js.map +1 -0
  42. package/dist/tools/getScreenContext.d.ts +24 -0
  43. package/dist/tools/getScreenContext.js +65 -0
  44. package/dist/tools/getScreenContext.js.map +1 -0
  45. package/dist/tools/getYaml.d.ts +21 -0
  46. package/dist/tools/getYaml.js +23 -0
  47. package/dist/tools/getYaml.js.map +1 -0
  48. package/dist/tools/listProjects.d.ts +8 -0
  49. package/dist/tools/listProjects.js +14 -0
  50. package/dist/tools/listProjects.js.map +1 -0
  51. package/dist/tools/searchNodes.d.ts +17 -0
  52. package/dist/tools/searchNodes.js +22 -0
  53. package/dist/tools/searchNodes.js.map +1 -0
  54. package/dist/tools/updateNode.d.ts +45 -0
  55. package/dist/tools/updateNode.js +29 -0
  56. package/dist/tools/updateNode.js.map +1 -0
  57. package/dist/tools/updateProject.d.ts +27 -0
  58. package/dist/tools/updateProject.js +25 -0
  59. package/dist/tools/updateProject.js.map +1 -0
  60. package/dist/types.d.ts +92 -0
  61. package/dist/types.js +3 -0
  62. package/dist/types.js.map +1 -0
  63. package/package.json +44 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jktfe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # flowspec-mcp
2
+
3
+ MCP (Model Context Protocol) server for [FlowSpec](https://flowspec.app) — exposes project specifications to Claude Code and other MCP-compatible AI tools.
4
+
5
+ ## Quick Start
6
+
7
+ Add to your `~/.claude.json`:
8
+
9
+ ```json
10
+ {
11
+ "mcpServers": {
12
+ "flowspec": {
13
+ "command": "npx",
14
+ "args": ["-y", "flowspec-mcp"],
15
+ "env": {
16
+ "FLOWSPEC_MODE": "cloud",
17
+ "DATABASE_URL": "your-neon-connection-string",
18
+ "FLOWSPEC_USER_ID": "your-clerk-user-id"
19
+ }
20
+ }
21
+ }
22
+ }
23
+ ```
24
+
25
+ ### Local Mode (with FlowSpec Desktop)
26
+
27
+ ```json
28
+ {
29
+ "mcpServers": {
30
+ "flowspec": {
31
+ "command": "npx",
32
+ "args": ["-y", "flowspec-mcp"],
33
+ "env": {
34
+ "FLOWSPEC_MODE": "local"
35
+ }
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ Local mode connects to the FlowSpec desktop server at `http://localhost:3456`.
42
+
43
+ ## Environment Variables
44
+
45
+ | Variable | Required | Default | Description |
46
+ |----------|----------|---------|-------------|
47
+ | `FLOWSPEC_MODE` | No | `cloud` | `cloud` for direct Neon SQL, `local` for desktop server HTTP |
48
+ | `DATABASE_URL` | Cloud mode | — | Neon Postgres connection string |
49
+ | `FLOWSPEC_USER_ID` | Cloud mode | — | Clerk user ID for project ownership |
50
+ | `FLOWSPEC_LOCAL_URL` | No | `http://localhost:3456` | Desktop server URL (local mode) |
51
+
52
+ ## Available Tools
53
+
54
+ ### Read Tools
55
+ - **`flowspec_list_projects`** — List all projects with names and dates
56
+ - **`flowspec_get_yaml`** — Get full YAML spec for a project (optimised for Claude Code)
57
+ - **`flowspec_get_project`** — Get raw canvas_state JSON
58
+ - **`flowspec_search_nodes`** — Search nodes by label across all projects
59
+ - **`flowspec_get_screen_context`** — Get screen/region/element structure
60
+
61
+ ### Write Tools
62
+ - **`flowspec_create_project`** — Create a new project
63
+ - **`flowspec_update_project`** — Update project name or canvas state
64
+ - **`flowspec_delete_project`** — Delete a project
65
+ - **`flowspec_create_node`** — Add a node (datapoint, component, transform, table)
66
+ - **`flowspec_update_node`** — Update node data or position
67
+ - **`flowspec_delete_node`** — Remove a node and connected edges
68
+ - **`flowspec_create_edge`** — Connect two nodes with an edge type
69
+ - **`flowspec_delete_edge`** — Remove an edge
70
+ - **`flowspec_analyse_project`** — Run orphan node and duplicate label analysis
71
+
72
+ ## Development
73
+
74
+ ```bash
75
+ npm install
76
+ npm run build
77
+ node dist/index.js
78
+ ```
79
+
80
+ ## Notes
81
+
82
+ - MCP SDK pinned to `1.12.1` due to zod v4 compatibility constraints in later versions
83
+ - Node.js >= 18.0.0 required
84
+
85
+ ## License
86
+
87
+ MIT
@@ -0,0 +1,5 @@
1
+ export type FlowSpecMode = 'cloud' | 'local';
2
+ export declare const MODE: FlowSpecMode;
3
+ export declare const LOCAL_API_BASE: string;
4
+ /** Read the local API auth token from the desktop server's token file. */
5
+ export declare function getLocalAuthToken(): string | null;
package/dist/config.js ADDED
@@ -0,0 +1,16 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ export const MODE = process.env.FLOWSPEC_MODE ?? 'cloud';
5
+ export const LOCAL_API_BASE = process.env.FLOWSPEC_LOCAL_URL ?? 'http://localhost:3456';
6
+ /** Read the local API auth token from the desktop server's token file. */
7
+ export function getLocalAuthToken() {
8
+ try {
9
+ const tokenPath = join(homedir(), 'Library', 'Application Support', 'com.flowspec.app', 'auth-token');
10
+ return readFileSync(tokenPath, 'utf-8').trim();
11
+ }
12
+ catch {
13
+ return null;
14
+ }
15
+ }
16
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAIlC,MAAM,CAAC,MAAM,IAAI,GAAkB,OAAO,CAAC,GAAG,CAAC,aAA8B,IAAI,OAAO,CAAC;AAEzF,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,uBAAuB,CAAC;AAExF,0EAA0E;AAC1E,MAAM,UAAU,iBAAiB;IAC/B,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,YAAY,CAAC,CAAC;QACtG,OAAO,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
package/dist/db.d.ts ADDED
@@ -0,0 +1,47 @@
1
+ import type { Project } from './types.js';
2
+ export declare function listProjects(): Promise<Pick<Project, 'id' | 'name' | 'created_at' | 'updated_at'>[]>;
3
+ export declare function getProject(projectId: string): Promise<Project | null>;
4
+ export declare function searchNodes(query: string, nodeType?: string): Promise<Array<{
5
+ projectId: string;
6
+ projectName: string;
7
+ nodeId: string;
8
+ nodeType: string;
9
+ label: string;
10
+ }>>;
11
+ export declare function createProjectViaApi(name: string, canvasState?: unknown): Promise<Project>;
12
+ export declare function updateProjectViaApi(projectId: string, updates: {
13
+ name?: string;
14
+ canvas_state?: unknown;
15
+ }): Promise<Project | null>;
16
+ export declare function deleteProjectViaApi(projectId: string): Promise<boolean>;
17
+ export declare function createNodeViaApi(projectId: string, node: {
18
+ type: string;
19
+ position: {
20
+ x: number;
21
+ y: number;
22
+ };
23
+ data: Record<string, unknown>;
24
+ }): Promise<{
25
+ id: string;
26
+ type: string;
27
+ position: {
28
+ x: number;
29
+ y: number;
30
+ };
31
+ data: Record<string, unknown>;
32
+ } | null>;
33
+ export declare function updateNodeViaApi(projectId: string, nodeId: string, updates: Record<string, unknown>): Promise<Record<string, unknown> | null>;
34
+ export declare function deleteNodeViaApi(projectId: string, nodeId: string): Promise<boolean>;
35
+ export declare function createEdgeViaApi(projectId: string, edge: {
36
+ source: string;
37
+ target: string;
38
+ type?: string;
39
+ data?: Record<string, unknown>;
40
+ }): Promise<{
41
+ id: string;
42
+ source: string;
43
+ target: string;
44
+ type: string;
45
+ data: Record<string, unknown>;
46
+ } | null>;
47
+ export declare function deleteEdgeViaApi(projectId: string, edgeId: string): Promise<boolean>;
package/dist/db.js ADDED
@@ -0,0 +1,283 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { neon } from '@neondatabase/serverless';
3
+ import { MODE, LOCAL_API_BASE, getLocalAuthToken } from './config.js';
4
+ let sql = null;
5
+ let FLOWSPEC_USER_ID = null;
6
+ if (MODE === 'cloud') {
7
+ const DATABASE_URL = process.env.DATABASE_URL;
8
+ if (!DATABASE_URL)
9
+ throw new Error('DATABASE_URL environment variable is required in cloud mode');
10
+ FLOWSPEC_USER_ID = process.env.FLOWSPEC_USER_ID ?? null;
11
+ if (!FLOWSPEC_USER_ID)
12
+ throw new Error('FLOWSPEC_USER_ID environment variable is required in cloud mode');
13
+ sql = neon(DATABASE_URL);
14
+ }
15
+ // ─── Local mode (HTTP to desktop server) ───────────────────────────
16
+ async function fetchLocal(path, options) {
17
+ const token = getLocalAuthToken();
18
+ const headers = {
19
+ 'Content-Type': 'application/json',
20
+ ...(options?.headers ?? {}),
21
+ };
22
+ if (token)
23
+ headers['Authorization'] = `Bearer ${token}`;
24
+ return fetch(`${LOCAL_API_BASE}${path}`, {
25
+ ...options,
26
+ headers,
27
+ });
28
+ }
29
+ // ─── Exported query functions (work in both modes) ─────────────────
30
+ export async function listProjects() {
31
+ if (MODE === 'local') {
32
+ const res = await fetchLocal('/api/projects');
33
+ return res.json();
34
+ }
35
+ const rows = await sql `
36
+ SELECT id, name, created_at, updated_at
37
+ FROM projects
38
+ WHERE user_id = ${FLOWSPEC_USER_ID}
39
+ ORDER BY updated_at DESC
40
+ `;
41
+ return rows;
42
+ }
43
+ export async function getProject(projectId) {
44
+ if (MODE === 'local') {
45
+ const res = await fetchLocal(`/api/projects/${projectId}`);
46
+ if (!res.ok)
47
+ return null;
48
+ return res.json();
49
+ }
50
+ const rows = await sql `
51
+ SELECT id, name, canvas_state, thumbnail_url, user_id, is_public, created_at, updated_at
52
+ FROM projects
53
+ WHERE id = ${projectId} AND user_id = ${FLOWSPEC_USER_ID}
54
+ `;
55
+ return rows[0] ?? null;
56
+ }
57
+ export async function searchNodes(query, nodeType) {
58
+ if (MODE === 'local') {
59
+ // In local mode, fetch all projects and search client-side (same logic as cloud)
60
+ const res = await fetchLocal('/api/projects');
61
+ const summaries = await res.json();
62
+ const results = [];
63
+ const lowerQuery = query.toLowerCase();
64
+ for (const summary of summaries) {
65
+ const projRes = await fetchLocal(`/api/projects/${summary.id}`);
66
+ if (!projRes.ok)
67
+ continue;
68
+ const project = await projRes.json();
69
+ const nodes = project.canvas_state?.nodes ?? [];
70
+ for (const node of nodes) {
71
+ if (node.type === 'image')
72
+ continue;
73
+ if (nodeType && node.type !== nodeType)
74
+ continue;
75
+ const label = node.data?.label ?? '';
76
+ if (label.toLowerCase().includes(lowerQuery)) {
77
+ results.push({
78
+ projectId: project.id,
79
+ projectName: project.name,
80
+ nodeId: node.id,
81
+ nodeType: node.type,
82
+ label,
83
+ });
84
+ }
85
+ }
86
+ }
87
+ return results;
88
+ }
89
+ const rows = await sql `
90
+ SELECT id, name, canvas_state
91
+ FROM projects
92
+ WHERE user_id = ${FLOWSPEC_USER_ID}
93
+ `;
94
+ const results = [];
95
+ const lowerQuery = query.toLowerCase();
96
+ for (const row of rows) {
97
+ const project = row;
98
+ const nodes = project.canvas_state?.nodes ?? [];
99
+ for (const node of nodes) {
100
+ if (node.type === 'image')
101
+ continue;
102
+ if (nodeType && node.type !== nodeType)
103
+ continue;
104
+ const label = node.data?.label ?? '';
105
+ if (label.toLowerCase().includes(lowerQuery)) {
106
+ results.push({
107
+ projectId: project.id,
108
+ projectName: project.name,
109
+ nodeId: node.id,
110
+ nodeType: node.type,
111
+ label,
112
+ });
113
+ }
114
+ }
115
+ }
116
+ return results;
117
+ }
118
+ // ─── Write operations (local mode only for now) ────────────────────
119
+ export async function createProjectViaApi(name, canvasState) {
120
+ if (MODE === 'local') {
121
+ const res = await fetchLocal('/api/projects', {
122
+ method: 'POST',
123
+ body: JSON.stringify({ name, canvas_state: canvasState ?? { nodes: [], edges: [] } }),
124
+ });
125
+ if (!res.ok)
126
+ throw new Error(`Failed to create project: ${res.status}`);
127
+ return res.json();
128
+ }
129
+ // Cloud mode: direct SQL insert
130
+ const rows = await sql `
131
+ INSERT INTO projects (name, canvas_state, user_id)
132
+ VALUES (${name}, ${JSON.stringify(canvasState ?? { nodes: [], edges: [] })}, ${FLOWSPEC_USER_ID})
133
+ RETURNING id, name, canvas_state, thumbnail_url, created_at, updated_at
134
+ `;
135
+ return rows[0];
136
+ }
137
+ export async function updateProjectViaApi(projectId, updates) {
138
+ if (MODE === 'local') {
139
+ const res = await fetchLocal(`/api/projects/${projectId}`, {
140
+ method: 'PUT',
141
+ body: JSON.stringify(updates),
142
+ });
143
+ if (!res.ok)
144
+ return null;
145
+ return res.json();
146
+ }
147
+ const name = updates.name;
148
+ const canvasState = updates.canvas_state;
149
+ const rows = await sql `
150
+ UPDATE projects
151
+ SET name = COALESCE(${name ?? null}, name),
152
+ canvas_state = COALESCE(${canvasState ? JSON.stringify(canvasState) : null}::jsonb, canvas_state),
153
+ updated_at = NOW()
154
+ WHERE id = ${projectId} AND user_id = ${FLOWSPEC_USER_ID}
155
+ RETURNING id, name, canvas_state, thumbnail_url, created_at, updated_at
156
+ `;
157
+ return rows[0] ?? null;
158
+ }
159
+ export async function deleteProjectViaApi(projectId) {
160
+ if (MODE === 'local') {
161
+ const res = await fetchLocal(`/api/projects/${projectId}`, { method: 'DELETE' });
162
+ return res.ok;
163
+ }
164
+ const rows = await sql `
165
+ DELETE FROM projects
166
+ WHERE id = ${projectId} AND user_id = ${FLOWSPEC_USER_ID}
167
+ RETURNING id
168
+ `;
169
+ return rows.length > 0;
170
+ }
171
+ export async function createNodeViaApi(projectId, node) {
172
+ if (MODE === 'local') {
173
+ const res = await fetchLocal(`/api/projects/${projectId}/nodes`, {
174
+ method: 'POST',
175
+ body: JSON.stringify(node),
176
+ });
177
+ if (!res.ok)
178
+ return null;
179
+ return res.json();
180
+ }
181
+ // Cloud mode: read-modify-write on canvas_state
182
+ const project = await getProject(projectId);
183
+ if (!project)
184
+ return null;
185
+ const nodeId = randomUUID();
186
+ const newNode = { id: nodeId, ...node };
187
+ project.canvas_state.nodes.push(newNode);
188
+ await sql `
189
+ UPDATE projects
190
+ SET canvas_state = ${JSON.stringify(project.canvas_state)}::jsonb, updated_at = NOW()
191
+ WHERE id = ${projectId} AND user_id = ${FLOWSPEC_USER_ID}
192
+ `;
193
+ return newNode;
194
+ }
195
+ export async function updateNodeViaApi(projectId, nodeId, updates) {
196
+ if (MODE === 'local') {
197
+ const res = await fetchLocal(`/api/projects/${projectId}/nodes/${nodeId}`, {
198
+ method: 'PUT',
199
+ body: JSON.stringify(updates),
200
+ });
201
+ if (!res.ok)
202
+ return null;
203
+ return res.json();
204
+ }
205
+ const project = await getProject(projectId);
206
+ if (!project)
207
+ return null;
208
+ const idx = project.canvas_state.nodes.findIndex((n) => n.id === nodeId);
209
+ if (idx === -1)
210
+ return null;
211
+ const existing = project.canvas_state.nodes[idx];
212
+ const updated = { ...existing, ...updates, id: nodeId, data: { ...existing.data, ...(updates.data ?? {}) } };
213
+ project.canvas_state.nodes[idx] = updated;
214
+ await sql `
215
+ UPDATE projects
216
+ SET canvas_state = ${JSON.stringify(project.canvas_state)}::jsonb, updated_at = NOW()
217
+ WHERE id = ${projectId} AND user_id = ${FLOWSPEC_USER_ID}
218
+ `;
219
+ return updated;
220
+ }
221
+ export async function deleteNodeViaApi(projectId, nodeId) {
222
+ if (MODE === 'local') {
223
+ const res = await fetchLocal(`/api/projects/${projectId}/nodes/${nodeId}`, { method: 'DELETE' });
224
+ return res.ok;
225
+ }
226
+ const project = await getProject(projectId);
227
+ if (!project)
228
+ return false;
229
+ const idx = project.canvas_state.nodes.findIndex((n) => n.id === nodeId);
230
+ if (idx === -1)
231
+ return false;
232
+ project.canvas_state.nodes.splice(idx, 1);
233
+ project.canvas_state.edges = project.canvas_state.edges.filter((e) => e.source !== nodeId && e.target !== nodeId);
234
+ await sql `
235
+ UPDATE projects
236
+ SET canvas_state = ${JSON.stringify(project.canvas_state)}::jsonb, updated_at = NOW()
237
+ WHERE id = ${projectId} AND user_id = ${FLOWSPEC_USER_ID}
238
+ `;
239
+ return true;
240
+ }
241
+ export async function createEdgeViaApi(projectId, edge) {
242
+ if (MODE === 'local') {
243
+ const res = await fetchLocal(`/api/projects/${projectId}/edges`, {
244
+ method: 'POST',
245
+ body: JSON.stringify(edge),
246
+ });
247
+ if (!res.ok)
248
+ return null;
249
+ return res.json();
250
+ }
251
+ const project = await getProject(projectId);
252
+ if (!project)
253
+ return null;
254
+ const edgeId = randomUUID();
255
+ const newEdge = { id: edgeId, source: edge.source, target: edge.target, type: edge.type ?? 'typed', data: edge.data ?? {} };
256
+ project.canvas_state.edges.push(newEdge);
257
+ await sql `
258
+ UPDATE projects
259
+ SET canvas_state = ${JSON.stringify(project.canvas_state)}::jsonb, updated_at = NOW()
260
+ WHERE id = ${projectId} AND user_id = ${FLOWSPEC_USER_ID}
261
+ `;
262
+ return newEdge;
263
+ }
264
+ export async function deleteEdgeViaApi(projectId, edgeId) {
265
+ if (MODE === 'local') {
266
+ const res = await fetchLocal(`/api/projects/${projectId}/edges/${edgeId}`, { method: 'DELETE' });
267
+ return res.ok;
268
+ }
269
+ const project = await getProject(projectId);
270
+ if (!project)
271
+ return false;
272
+ const idx = project.canvas_state.edges.findIndex((e) => e.id === edgeId);
273
+ if (idx === -1)
274
+ return false;
275
+ project.canvas_state.edges.splice(idx, 1);
276
+ await sql `
277
+ UPDATE projects
278
+ SET canvas_state = ${JSON.stringify(project.canvas_state)}::jsonb, updated_at = NOW()
279
+ WHERE id = ${projectId} AND user_id = ${FLOWSPEC_USER_ID}
280
+ `;
281
+ return true;
282
+ }
283
+ //# sourceMappingURL=db.js.map
package/dist/db.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { CanvasNode, CanvasEdge, Screen } from '../types.js';
2
+ /**
3
+ * Exports canvas state to YAML specification optimised for Claude Code.
4
+ * Adapted from web app — uses plain interfaces instead of @xyflow/svelte types.
5
+ */
6
+ export declare function exportToYaml(nodes: CanvasNode[], edges: CanvasEdge[], projectName?: string, screens?: Screen[]): string;
@@ -0,0 +1,155 @@
1
+ import { stringify } from 'yaml';
2
+ /**
3
+ * Exports canvas state to YAML specification optimised for Claude Code.
4
+ * Adapted from web app — uses plain interfaces instead of @xyflow/svelte types.
5
+ */
6
+ export function exportToYaml(nodes, edges, projectName = 'Untitled Project', screens = []) {
7
+ const exportableNodes = nodes.filter((n) => n.type !== 'image' && n.type !== 'screen');
8
+ const dataPointNodes = exportableNodes.filter((n) => n.type === 'datapoint');
9
+ const componentNodes = exportableNodes.filter((n) => n.type === 'component');
10
+ const transformNodes = exportableNodes.filter((n) => n.type === 'transform');
11
+ const tableNodes = exportableNodes.filter((n) => n.type === 'table');
12
+ const locationMap = buildLocationMap(dataPointNodes, componentNodes, edges);
13
+ // Build node label lookup for screen region export
14
+ const nodeLabelMap = new Map();
15
+ for (const n of exportableNodes) {
16
+ const label = n.data.label ?? 'Untitled';
17
+ nodeLabelMap.set(n.id, { label, type: n.type ?? 'unknown' });
18
+ }
19
+ const spec = {
20
+ version: '1.2.0',
21
+ metadata: {
22
+ projectName,
23
+ exportedAt: new Date().toISOString(),
24
+ nodeCount: exportableNodes.length,
25
+ edgeCount: edges.length,
26
+ },
27
+ dataPoints: dataPointNodes.map((node) => {
28
+ const data = node.data;
29
+ return {
30
+ id: node.id,
31
+ label: data.label,
32
+ type: data.type,
33
+ source: data.source,
34
+ sourceDefinition: data.sourceDefinition,
35
+ constraints: data.constraints,
36
+ locations: locationMap.get(node.id) ?? [],
37
+ };
38
+ }),
39
+ components: componentNodes.map((node) => {
40
+ const data = node.data;
41
+ const result = {
42
+ id: node.id,
43
+ label: data.label,
44
+ displays: data.displays,
45
+ captures: data.captures,
46
+ };
47
+ if (data.wireframeRef) {
48
+ result.wireframeRef = data.wireframeRef;
49
+ }
50
+ return result;
51
+ }),
52
+ transforms: transformNodes.map((node) => {
53
+ const data = node.data;
54
+ return {
55
+ id: node.id,
56
+ type: data.type,
57
+ description: data.description,
58
+ inputs: data.inputs,
59
+ outputs: data.outputs,
60
+ logic: data.logic,
61
+ };
62
+ }),
63
+ dataFlow: edges.filter((e) => {
64
+ return e.data?.edgeType !== 'contains';
65
+ }).map((edge) => {
66
+ const result = {
67
+ from: edge.source,
68
+ to: edge.target,
69
+ edgeType: edge.data?.edgeType ?? 'flows-to',
70
+ };
71
+ if (edge.data?.label) {
72
+ result.label = edge.data.label;
73
+ }
74
+ return result;
75
+ }),
76
+ };
77
+ // Add tables section if table nodes exist
78
+ if (tableNodes.length > 0) {
79
+ spec.tables = tableNodes.map((node) => {
80
+ const data = node.data;
81
+ const result = {
82
+ id: node.id,
83
+ label: data.label,
84
+ sourceType: data.sourceType,
85
+ columns: (data.columns ?? []).map((c) => ({ name: c.name, type: c.type })),
86
+ };
87
+ if (data.endpoint) {
88
+ result.endpoint = data.endpoint;
89
+ }
90
+ return result;
91
+ });
92
+ }
93
+ // Add screens section if screens exist
94
+ if (screens.length > 0) {
95
+ spec.screens = screens.map((sc) => ({
96
+ id: sc.id,
97
+ name: sc.name,
98
+ imageFilename: sc.imageFilename,
99
+ regions: sc.regions.map((r) => {
100
+ const region = {
101
+ id: r.id,
102
+ label: r.label,
103
+ position: {
104
+ x: Math.round(r.position.x * 10) / 10,
105
+ y: Math.round(r.position.y * 10) / 10,
106
+ },
107
+ size: {
108
+ width: Math.round(r.size.width * 10) / 10,
109
+ height: Math.round(r.size.height * 10) / 10,
110
+ },
111
+ elements: r.elementIds.map((eid) => {
112
+ const info = nodeLabelMap.get(eid);
113
+ return {
114
+ nodeId: eid,
115
+ nodeLabel: info?.label ?? 'Missing element',
116
+ nodeType: info?.type ?? 'unknown',
117
+ };
118
+ }),
119
+ };
120
+ if (r.componentNodeId) {
121
+ region.componentNodeId = r.componentNodeId;
122
+ }
123
+ return region;
124
+ }),
125
+ }));
126
+ }
127
+ return stringify(spec, {
128
+ lineWidth: 120,
129
+ indent: 2,
130
+ });
131
+ }
132
+ function buildLocationMap(dataPoints, components, edges) {
133
+ const map = new Map();
134
+ for (const dp of dataPoints) {
135
+ map.set(dp.id, []);
136
+ }
137
+ for (const edge of edges) {
138
+ const sourceIsDataPoint = dataPoints.some((n) => n.id === edge.source);
139
+ const targetIsComponent = components.some((n) => n.id === edge.target);
140
+ if (sourceIsDataPoint && targetIsComponent) {
141
+ const locations = map.get(edge.source) ?? [];
142
+ locations.push({ component: edge.target, role: 'output' });
143
+ map.set(edge.source, locations);
144
+ }
145
+ const sourceIsComponent = components.some((n) => n.id === edge.source);
146
+ const targetIsDataPoint = dataPoints.some((n) => n.id === edge.target);
147
+ if (sourceIsComponent && targetIsDataPoint) {
148
+ const locations = map.get(edge.target) ?? [];
149
+ locations.push({ component: edge.source, role: 'input' });
150
+ map.set(edge.target, locations);
151
+ }
152
+ }
153
+ return map;
154
+ }
155
+ //# sourceMappingURL=yamlExporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yamlExporter.js","sourceRoot":"","sources":["../../src/export/yamlExporter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};