flowspec-mcp 5.4.0 → 5.5.1

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 (58) hide show
  1. package/dist/analysis/analysisUtils.d.ts +36 -0
  2. package/dist/analysis/analysisUtils.js +284 -0
  3. package/dist/analysis/analysisUtils.js.map +1 -0
  4. package/dist/db.js +19 -3
  5. package/dist/db.js.map +1 -1
  6. package/dist/export/yamlExporter.d.ts +6 -0
  7. package/dist/export/yamlExporter.js +155 -0
  8. package/dist/export/yamlExporter.js.map +1 -0
  9. package/dist/import/yamlImporter.d.ts +22 -0
  10. package/dist/import/yamlImporter.js +227 -0
  11. package/dist/import/yamlImporter.js.map +1 -0
  12. package/dist/index.js +0 -0
  13. package/dist/layout/semanticLayout.d.ts +24 -0
  14. package/dist/layout/semanticLayout.js +233 -0
  15. package/dist/layout/semanticLayout.js.map +1 -0
  16. package/dist/resources/selection.d.ts +5 -0
  17. package/dist/resources/selection.js +88 -0
  18. package/dist/resources/selection.js.map +1 -0
  19. package/dist/server.js +29 -24
  20. package/dist/server.js.map +1 -1
  21. package/dist/tools/captureScreen.d.ts +48 -0
  22. package/dist/tools/captureScreen.js +135 -0
  23. package/dist/tools/captureScreen.js.map +1 -0
  24. package/dist/tools/createNode.d.ts +2 -2
  25. package/dist/tools/createSubview.d.ts +50 -0
  26. package/dist/tools/createSubview.js +29 -0
  27. package/dist/tools/createSubview.js.map +1 -0
  28. package/dist/tools/deleteSubview.d.ts +24 -0
  29. package/dist/tools/deleteSubview.js +19 -0
  30. package/dist/tools/deleteSubview.js.map +1 -0
  31. package/dist/tools/generateSpec.d.ts +26 -0
  32. package/dist/tools/generateSpec.js +336 -0
  33. package/dist/tools/generateSpec.js.map +1 -0
  34. package/dist/tools/getYaml.d.ts +21 -0
  35. package/dist/tools/getYaml.js +23 -0
  36. package/dist/tools/getYaml.js.map +1 -0
  37. package/dist/tools/healthCheck.d.ts +8 -0
  38. package/dist/tools/healthCheck.js +16 -0
  39. package/dist/tools/healthCheck.js.map +1 -0
  40. package/dist/tools/importYaml.d.ts +33 -0
  41. package/dist/tools/importYaml.js +97 -0
  42. package/dist/tools/importYaml.js.map +1 -0
  43. package/dist/tools/ingestCodebase.d.ts +27 -0
  44. package/dist/tools/ingestCodebase.js +516 -0
  45. package/dist/tools/ingestCodebase.js.map +1 -0
  46. package/dist/tools/listSubviews.d.ts +21 -0
  47. package/dist/tools/listSubviews.js +34 -0
  48. package/dist/tools/listSubviews.js.map +1 -0
  49. package/dist/tools/smartLayout.d.ts +30 -0
  50. package/dist/tools/smartLayout.js +74 -0
  51. package/dist/tools/smartLayout.js.map +1 -0
  52. package/dist/tools/updateSubview.d.ts +53 -0
  53. package/dist/tools/updateSubview.js +33 -0
  54. package/dist/tools/updateSubview.js.map +1 -0
  55. package/dist/utils/selectionHelper.d.ts +61 -0
  56. package/dist/utils/selectionHelper.js +111 -0
  57. package/dist/utils/selectionHelper.js.map +1 -0
  58. package/package.json +1 -1
@@ -0,0 +1,135 @@
1
+ import { z } from 'zod';
2
+ import { uploadImageViaApi } from '../db.js';
3
+ import { detectImageDimensions } from '../image/dimensions.js';
4
+ export const captureScreenSchema = z.object({
5
+ url: z.string().describe('URL to screenshot (http:// or https://)'),
6
+ selector: z.string().optional().describe('CSS selector for specific element (full page if omitted)'),
7
+ viewport: z
8
+ .object({
9
+ width: z.number(),
10
+ height: z.number()
11
+ })
12
+ .optional()
13
+ .describe('Viewport size (default: 1920x1080)'),
14
+ waitFor: z
15
+ .string()
16
+ .optional()
17
+ .describe('CSS selector to wait for before screenshot, or timeout in ms (e.g., "3000")'),
18
+ fullPage: z.boolean().optional().default(false).describe('Capture full page height (default: false)')
19
+ });
20
+ export async function handleCaptureScreen(args) {
21
+ // Validate URL
22
+ if (!args.url.startsWith('http://') && !args.url.startsWith('https://')) {
23
+ return {
24
+ content: [{ type: 'text', text: `Invalid URL. Must start with http:// or https://` }],
25
+ isError: true
26
+ };
27
+ }
28
+ let browser;
29
+ try {
30
+ // Dynamically import playwright (cloud-only dependency)
31
+ const { chromium } = await import('playwright');
32
+ // Launch browser
33
+ browser = await chromium.launch({ headless: true });
34
+ const context = await browser.newContext({
35
+ viewport: args.viewport ?? { width: 1920, height: 1080 }
36
+ });
37
+ const page = await context.newPage();
38
+ // Navigate to URL
39
+ await page.goto(args.url, { waitUntil: 'networkidle' });
40
+ // Wait for selector or timeout if specified
41
+ if (args.waitFor) {
42
+ const timeoutMs = parseInt(args.waitFor, 10);
43
+ if (!isNaN(timeoutMs)) {
44
+ // Wait for timeout
45
+ await page.waitForTimeout(timeoutMs);
46
+ }
47
+ else {
48
+ // Wait for selector
49
+ try {
50
+ await page.waitForSelector(args.waitFor, { timeout: 10000 });
51
+ }
52
+ catch (e) {
53
+ return {
54
+ content: [
55
+ {
56
+ type: 'text',
57
+ text: `Selector "${args.waitFor}" not found within 10s. Screenshot may be incomplete.`
58
+ }
59
+ ],
60
+ isError: true
61
+ };
62
+ }
63
+ }
64
+ }
65
+ // Take screenshot
66
+ let screenshotBuffer;
67
+ if (args.selector) {
68
+ // Screenshot specific element
69
+ const element = await page.$(args.selector);
70
+ if (!element) {
71
+ return {
72
+ content: [
73
+ {
74
+ type: 'text',
75
+ text: `Element not found: ${args.selector}`
76
+ }
77
+ ],
78
+ isError: true
79
+ };
80
+ }
81
+ screenshotBuffer = await element.screenshot({ type: 'png' });
82
+ }
83
+ else {
84
+ // Screenshot full page or viewport
85
+ screenshotBuffer = await page.screenshot({
86
+ type: 'png',
87
+ fullPage: args.fullPage
88
+ });
89
+ }
90
+ await browser.close();
91
+ // Detect dimensions from screenshot
92
+ const detected = detectImageDimensions(new Uint8Array(screenshotBuffer));
93
+ const width = detected?.width ?? args.viewport?.width ?? 1920;
94
+ const height = detected?.height ?? args.viewport?.height ?? 1080;
95
+ // Upload to Vercel Blob (via API)
96
+ const base64Data = screenshotBuffer.toString('base64');
97
+ const filename = `screenshot_${Date.now()}.png`;
98
+ const result = await uploadImageViaApi(base64Data, filename, 'image/png');
99
+ if (!result) {
100
+ return {
101
+ content: [
102
+ {
103
+ type: 'text',
104
+ text: `Failed to upload screenshot. In cloud mode, image upload is not yet supported.`
105
+ }
106
+ ],
107
+ isError: true
108
+ };
109
+ }
110
+ // Return result in same format as uploadImage
111
+ return {
112
+ content: [
113
+ {
114
+ type: 'text',
115
+ text: JSON.stringify({ url: result.url, width, height, filename }, null, 2)
116
+ }
117
+ ]
118
+ };
119
+ }
120
+ catch (error) {
121
+ if (browser) {
122
+ await browser.close();
123
+ }
124
+ return {
125
+ content: [
126
+ {
127
+ type: 'text',
128
+ text: `Screenshot capture failed: ${error.message}`
129
+ }
130
+ ],
131
+ isError: true
132
+ };
133
+ }
134
+ }
135
+ //# sourceMappingURL=captureScreen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captureScreen.js","sourceRoot":"","sources":["../../src/tools/captureScreen.ts"],"names":[],"mappings":"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"}
@@ -14,7 +14,7 @@ export declare const createNodeSchema: z.ZodObject<{
14
14
  }>;
15
15
  data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
16
16
  }, "strip", z.ZodTypeAny, {
17
- type: "datapoint" | "component" | "transform" | "table";
17
+ type: "datapoint" | "table" | "component" | "transform";
18
18
  position: {
19
19
  x: number;
20
20
  y: number;
@@ -22,7 +22,7 @@ export declare const createNodeSchema: z.ZodObject<{
22
22
  data: Record<string, unknown>;
23
23
  projectId: string;
24
24
  }, {
25
- type: "datapoint" | "component" | "transform" | "table";
25
+ type: "datapoint" | "table" | "component" | "transform";
26
26
  position: {
27
27
  x: number;
28
28
  y: number;
@@ -0,0 +1,50 @@
1
+ import { z } from 'zod';
2
+ export declare const createSubviewSchema: z.ZodObject<{
3
+ projectId: z.ZodString;
4
+ name: z.ZodString;
5
+ description: z.ZodOptional<z.ZodString>;
6
+ nodePositions: z.ZodOptional<z.ZodArray<z.ZodObject<{
7
+ nodeId: z.ZodString;
8
+ x: z.ZodNumber;
9
+ y: z.ZodNumber;
10
+ }, "strip", z.ZodTypeAny, {
11
+ x: number;
12
+ y: number;
13
+ nodeId: string;
14
+ }, {
15
+ x: number;
16
+ y: number;
17
+ nodeId: string;
18
+ }>, "many">>;
19
+ }, "strip", z.ZodTypeAny, {
20
+ name: string;
21
+ projectId: string;
22
+ description?: string | undefined;
23
+ nodePositions?: {
24
+ x: number;
25
+ y: number;
26
+ nodeId: string;
27
+ }[] | undefined;
28
+ }, {
29
+ name: string;
30
+ projectId: string;
31
+ description?: string | undefined;
32
+ nodePositions?: {
33
+ x: number;
34
+ y: number;
35
+ nodeId: string;
36
+ }[] | undefined;
37
+ }>;
38
+ export declare function handleCreateSubview(args: z.infer<typeof createSubviewSchema>): Promise<{
39
+ content: {
40
+ type: "text";
41
+ text: string;
42
+ }[];
43
+ isError: boolean;
44
+ } | {
45
+ content: {
46
+ type: "text";
47
+ text: string;
48
+ }[];
49
+ isError?: undefined;
50
+ }>;
@@ -0,0 +1,29 @@
1
+ import { z } from 'zod';
2
+ import { createSubviewViaApi } from '../db.js';
3
+ export const createSubviewSchema = z.object({
4
+ projectId: z.string().describe('UUID of the project'),
5
+ name: z.string().describe('Subview name'),
6
+ description: z.string().optional().describe('Optional subview description'),
7
+ nodePositions: z.array(z.object({
8
+ nodeId: z.string().describe('Node ID from the main canvas'),
9
+ x: z.number().describe('X position in subview canvas'),
10
+ y: z.number().describe('Y position in subview canvas'),
11
+ })).optional().describe('Initial nodes and their positions in the subview'),
12
+ });
13
+ export async function handleCreateSubview(args) {
14
+ const subview = await createSubviewViaApi(args.projectId, args.name, args.description, args.nodePositions ?? []);
15
+ if (!subview) {
16
+ return {
17
+ content: [{ type: 'text', text: `Failed to create subview — project not found: ${args.projectId}` }],
18
+ isError: true,
19
+ };
20
+ }
21
+ const nodeCount = args.nodePositions?.length ?? 0;
22
+ return {
23
+ content: [{
24
+ type: 'text',
25
+ text: `Created subview **${args.name}** (id: ${subview.id}) with ${nodeCount} node${nodeCount === 1 ? '' : 's'}`,
26
+ }],
27
+ };
28
+ }
29
+ //# sourceMappingURL=createSubview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createSubview.js","sourceRoot":"","sources":["../../src/tools/createSubview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAE/C,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;IACrD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;IACzC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;IAC3E,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;QAC9B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;QAC3D,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;QACtD,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;KACvD,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kDAAkD,CAAC;CAC5E,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAyC;IACjF,MAAM,OAAO,GAAG,MAAM,mBAAmB,CACvC,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,aAAa,IAAI,EAAE,CACzB,CAAC;IAEF,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,iDAAiD,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;YAC7G,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC,CAAC;IAClD,OAAO;QACL,OAAO,EAAE,CAAC;gBACR,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,qBAAqB,IAAI,CAAC,IAAI,WAAW,OAAO,CAAC,EAAE,UAAU,SAAS,QAAQ,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;aACjH,CAAC;KACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { z } from 'zod';
2
+ export declare const deleteSubviewSchema: z.ZodObject<{
3
+ projectId: z.ZodString;
4
+ subviewId: z.ZodString;
5
+ }, "strip", z.ZodTypeAny, {
6
+ projectId: string;
7
+ subviewId: string;
8
+ }, {
9
+ projectId: string;
10
+ subviewId: string;
11
+ }>;
12
+ export declare function handleDeleteSubview(args: z.infer<typeof deleteSubviewSchema>): Promise<{
13
+ content: {
14
+ type: "text";
15
+ text: string;
16
+ }[];
17
+ isError: boolean;
18
+ } | {
19
+ content: {
20
+ type: "text";
21
+ text: string;
22
+ }[];
23
+ isError?: undefined;
24
+ }>;
@@ -0,0 +1,19 @@
1
+ import { z } from 'zod';
2
+ import { deleteSubviewViaApi } from '../db.js';
3
+ export const deleteSubviewSchema = z.object({
4
+ projectId: z.string().describe('UUID of the project'),
5
+ subviewId: z.string().describe('UUID of the subview to delete'),
6
+ });
7
+ export async function handleDeleteSubview(args) {
8
+ const ok = await deleteSubviewViaApi(args.projectId, args.subviewId);
9
+ if (!ok) {
10
+ return {
11
+ content: [{ type: 'text', text: `Subview or project not found: ${args.subviewId}` }],
12
+ isError: true,
13
+ };
14
+ }
15
+ return {
16
+ content: [{ type: 'text', text: `Deleted subview ${args.subviewId}` }],
17
+ };
18
+ }
19
+ //# sourceMappingURL=deleteSubview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deleteSubview.js","sourceRoot":"","sources":["../../src/tools/deleteSubview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAE/C,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;IACrD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;CAChE,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAyC;IACjF,MAAM,EAAE,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAErE,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,iCAAiC,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;YAC7F,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAED,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,mBAAmB,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;KAChF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { z } from 'zod';
2
+ export declare const generateSpecSchema: z.ZodObject<{
3
+ projectId: z.ZodString;
4
+ format: z.ZodDefault<z.ZodEnum<["markdown", "json"]>>;
5
+ sections: z.ZodOptional<z.ZodArray<z.ZodEnum<["db_schema", "api_contracts", "component_tree", "validation_rules", "all"]>, "many">>;
6
+ }, "strip", z.ZodTypeAny, {
7
+ projectId: string;
8
+ format: "markdown" | "json";
9
+ sections?: ("db_schema" | "api_contracts" | "component_tree" | "validation_rules" | "all")[] | undefined;
10
+ }, {
11
+ projectId: string;
12
+ format?: "markdown" | "json" | undefined;
13
+ sections?: ("db_schema" | "api_contracts" | "component_tree" | "validation_rules" | "all")[] | undefined;
14
+ }>;
15
+ export declare function handleGenerateSpec(args: z.infer<typeof generateSpecSchema>): Promise<{
16
+ content: {
17
+ type: "text";
18
+ text: string;
19
+ }[];
20
+ isError: boolean;
21
+ } | {
22
+ content: {
23
+ type: "text";
24
+ text: string;
25
+ }[];
26
+ }>;
@@ -0,0 +1,336 @@
1
+ import { z } from 'zod';
2
+ import { getProject } from '../db.js';
3
+ import { handleGetYaml } from './getYaml.js';
4
+ import YAML from 'yaml';
5
+ export const generateSpecSchema = z.object({
6
+ projectId: z.string().describe('UUID of the project to generate spec for'),
7
+ format: z.enum(['markdown', 'json']).default('markdown').describe('Output format'),
8
+ sections: z
9
+ .array(z.enum(['db_schema', 'api_contracts', 'component_tree', 'validation_rules', 'all']))
10
+ .optional()
11
+ .describe('Sections to include (default: all)')
12
+ });
13
+ export async function handleGenerateSpec(args) {
14
+ const project = await getProject(args.projectId);
15
+ if (!project) {
16
+ return {
17
+ content: [{ type: 'text', text: `Project not found: ${args.projectId}` }],
18
+ isError: true
19
+ };
20
+ }
21
+ // Get YAML via existing tool
22
+ const yamlResult = await handleGetYaml({ projectId: args.projectId });
23
+ if (yamlResult.isError) {
24
+ return yamlResult;
25
+ }
26
+ const yamlContent = yamlResult.content[0].text;
27
+ const parsed = YAML.parse(yamlContent);
28
+ // Determine which sections to include
29
+ const sections = args.sections ?? ['all'];
30
+ const includeAll = sections.includes('all');
31
+ // Generate spec
32
+ const spec = args.format === 'markdown'
33
+ ? generateMarkdownSpec(project.name, parsed, {
34
+ db_schema: includeAll || sections.includes('db_schema'),
35
+ api_contracts: includeAll || sections.includes('api_contracts'),
36
+ component_tree: includeAll || sections.includes('component_tree'),
37
+ validation_rules: includeAll || sections.includes('validation_rules')
38
+ })
39
+ : generateJsonSpec(project.name, parsed);
40
+ return {
41
+ content: [{ type: 'text', text: spec }]
42
+ };
43
+ }
44
+ // ─── Markdown Spec Generation ───────────────────────────────────
45
+ function generateMarkdownSpec(projectName, yaml, sections) {
46
+ const lines = [];
47
+ // Header
48
+ lines.push(`# ${projectName} - Technical Specification`);
49
+ lines.push(``);
50
+ lines.push(`**Generated:** ${new Date().toISOString().split('T')[0]}`);
51
+ lines.push(`**FlowSpec Version:** ${yaml.version || '1.2.0'}`);
52
+ lines.push(``);
53
+ lines.push(`---`);
54
+ lines.push(``);
55
+ // Overview
56
+ const dataPoints = yaml.dataPoints || [];
57
+ const components = yaml.components || [];
58
+ const transforms = yaml.transforms || [];
59
+ const tables = yaml.tables || [];
60
+ const screens = yaml.screens || [];
61
+ lines.push(`## Overview`);
62
+ lines.push(``);
63
+ lines.push(`This specification describes the data architecture for **${projectName}**.`);
64
+ lines.push(``);
65
+ lines.push(`- **DataPoints:** ${dataPoints.length} data elements`);
66
+ lines.push(`- **Components:** ${components.length} UI components`);
67
+ lines.push(`- **Transforms:** ${transforms.length} business logic functions`);
68
+ lines.push(`- **Tables:** ${tables.length} database tables/APIs`);
69
+ lines.push(`- **Screens:** ${screens.length} wireframe screens`);
70
+ lines.push(``);
71
+ lines.push(`---`);
72
+ lines.push(``);
73
+ // DataPoints
74
+ lines.push(`## DataPoints`);
75
+ lines.push(``);
76
+ if (dataPoints.length === 0) {
77
+ lines.push(`*No data points defined.*`);
78
+ lines.push(``);
79
+ }
80
+ else {
81
+ lines.push(`| Label | Type | Source | Constraints | Source Definition |`);
82
+ lines.push(`|-------|------|--------|-------------|-------------------|`);
83
+ for (const dp of dataPoints) {
84
+ const label = dp.label || dp.id;
85
+ const type = dp.type || 'string';
86
+ const source = dp.source || 'inferred';
87
+ const constraints = dp.constraints && dp.constraints.length > 0 ? dp.constraints.join(', ') : '-';
88
+ const sourceDef = (dp.sourceDefinition || '').replace(/\|/g, '\\|');
89
+ lines.push(`| ${label} | ${type} | ${source} | ${constraints} | ${sourceDef} |`);
90
+ }
91
+ lines.push(``);
92
+ // Group by source
93
+ const captured = dataPoints.filter((dp) => dp.source === 'captured');
94
+ const inferred = dataPoints.filter((dp) => dp.source === 'inferred');
95
+ lines.push(`**Captured DataPoints (${captured.length}):** User inputs, form fields`);
96
+ lines.push(`**Inferred DataPoints (${inferred.length}):** Computed values, API responses, database queries`);
97
+ lines.push(``);
98
+ }
99
+ lines.push(`---`);
100
+ lines.push(``);
101
+ // Components
102
+ lines.push(`## Components`);
103
+ lines.push(``);
104
+ if (components.length === 0) {
105
+ lines.push(`*No components defined.*`);
106
+ lines.push(``);
107
+ }
108
+ else {
109
+ lines.push(`| Label | Displays | Captures | Wireframe |`);
110
+ lines.push(`|-------|----------|----------|-----------|`);
111
+ for (const comp of components) {
112
+ const label = comp.label || comp.id;
113
+ const displays = comp.displays?.join(', ') || '-';
114
+ const captures = comp.captures?.join(', ') || '-';
115
+ const wireframe = comp.wireframeRef || '-';
116
+ lines.push(`| ${label} | ${displays} | ${captures} | ${wireframe} |`);
117
+ }
118
+ lines.push(``);
119
+ }
120
+ lines.push(`---`);
121
+ lines.push(``);
122
+ // Transforms
123
+ lines.push(`## Transforms`);
124
+ lines.push(``);
125
+ if (transforms.length === 0) {
126
+ lines.push(`*No transforms defined.*`);
127
+ lines.push(``);
128
+ }
129
+ else {
130
+ lines.push(`| Label | Type | Inputs | Outputs | Description |`);
131
+ lines.push(`|-------|------|--------|---------|-------------|`);
132
+ for (const tf of transforms) {
133
+ const label = tf.label || tf.id;
134
+ const type = tf.type || 'formula';
135
+ const inputs = tf.inputs?.join(', ') || '-';
136
+ const outputs = tf.outputs?.join(', ') || '-';
137
+ const description = (tf.description || '').replace(/\|/g, '\\|');
138
+ lines.push(`| ${label} | ${type} | ${inputs} | ${outputs} | ${description} |`);
139
+ }
140
+ lines.push(``);
141
+ // Group by type
142
+ const formulas = transforms.filter((tf) => tf.type === 'formula');
143
+ const validations = transforms.filter((tf) => tf.type === 'validation');
144
+ const workflows = transforms.filter((tf) => tf.type === 'workflow');
145
+ lines.push(`**Formula (${formulas.length}):** Calculations, aggregations`);
146
+ lines.push(`**Validation (${validations.length}):** Data checking, constraint enforcement`);
147
+ lines.push(`**Workflow (${workflows.length}):** Multi-step processes, integrations`);
148
+ lines.push(``);
149
+ }
150
+ lines.push(`---`);
151
+ lines.push(``);
152
+ // Database Schema (if requested)
153
+ if (sections.db_schema && tables.length > 0) {
154
+ lines.push(`## Database Schema`);
155
+ lines.push(``);
156
+ for (const table of tables) {
157
+ const label = table.label || table.id;
158
+ const sourceType = table.sourceType || 'database';
159
+ const endpoint = table.endpoint || '-';
160
+ lines.push(`### Table: \`${label}\``);
161
+ lines.push(``);
162
+ lines.push(`**Source:** ${sourceType} (${endpoint})`);
163
+ lines.push(``);
164
+ if (table.columns && table.columns.length > 0) {
165
+ lines.push(`| Column | Type |`);
166
+ lines.push(`|--------|------|`);
167
+ for (const col of table.columns) {
168
+ lines.push(`| ${col.name} | ${col.type} |`);
169
+ }
170
+ lines.push(``);
171
+ }
172
+ }
173
+ lines.push(`---`);
174
+ lines.push(``);
175
+ }
176
+ // API Contracts (if requested)
177
+ if (sections.api_contracts) {
178
+ lines.push(`## API Contracts`);
179
+ lines.push(``);
180
+ // Infer API endpoints from inferred DataPoints
181
+ const apiDataPoints = dataPoints.filter((dp) => dp.source === 'inferred' && dp.sourceDefinition && dp.sourceDefinition.includes('API'));
182
+ if (apiDataPoints.length === 0) {
183
+ lines.push(`*No API endpoints identified.*`);
184
+ lines.push(``);
185
+ }
186
+ else {
187
+ lines.push(`Suggested API endpoints based on inferred DataPoints:`);
188
+ lines.push(``);
189
+ for (const dp of apiDataPoints) {
190
+ const label = dp.label || dp.id;
191
+ const method = dp.sourceDefinition.includes('POST') ? 'POST' : 'GET';
192
+ const endpoint = `/api/${label.toLowerCase().replace(/\s+/g, '-')}`;
193
+ lines.push(`### ${method} ${endpoint}`);
194
+ lines.push(``);
195
+ lines.push(`**Returns:** ${label} (${dp.type})`);
196
+ lines.push(`**Source:** ${dp.sourceDefinition}`);
197
+ lines.push(``);
198
+ }
199
+ }
200
+ lines.push(`---`);
201
+ lines.push(``);
202
+ }
203
+ // Component Tree (if requested)
204
+ if (sections.component_tree && components.length > 0) {
205
+ lines.push(`## Component Hierarchy`);
206
+ lines.push(``);
207
+ // Simple tree based on wireframe references
208
+ const screenGroups = new Map();
209
+ for (const comp of components) {
210
+ const screen = comp.wireframeRef || 'No Screen';
211
+ const group = screenGroups.get(screen) || [];
212
+ group.push(comp);
213
+ screenGroups.set(screen, group);
214
+ }
215
+ for (const [screen, comps] of screenGroups) {
216
+ lines.push(`### ${screen}`);
217
+ lines.push(``);
218
+ for (const comp of comps) {
219
+ const label = comp.label || comp.id;
220
+ lines.push(`- **${label}**`);
221
+ if (comp.displays && comp.displays.length > 0) {
222
+ lines.push(` - Displays: ${comp.displays.join(', ')}`);
223
+ }
224
+ if (comp.captures && comp.captures.length > 0) {
225
+ lines.push(` - Captures: ${comp.captures.join(', ')}`);
226
+ }
227
+ }
228
+ lines.push(``);
229
+ }
230
+ lines.push(`---`);
231
+ lines.push(``);
232
+ }
233
+ // Validation Rules (if requested)
234
+ if (sections.validation_rules) {
235
+ lines.push(`## Validation Rules`);
236
+ lines.push(``);
237
+ // Extract constraints from DataPoints
238
+ const constrainedDataPoints = dataPoints.filter((dp) => dp.constraints && dp.constraints.length > 0);
239
+ if (constrainedDataPoints.length === 0) {
240
+ lines.push(`*No validation rules defined.*`);
241
+ lines.push(``);
242
+ }
243
+ else {
244
+ lines.push(`| DataPoint | Constraints |`);
245
+ lines.push(`|-----------|-------------|`);
246
+ for (const dp of constrainedDataPoints) {
247
+ const label = dp.label || dp.id;
248
+ const constraints = dp.constraints.join(', ');
249
+ lines.push(`| ${label} | ${constraints} |`);
250
+ }
251
+ lines.push(``);
252
+ }
253
+ // Extract validation transforms
254
+ const validationTransforms = transforms.filter((tf) => tf.type === 'validation');
255
+ if (validationTransforms.length > 0) {
256
+ lines.push(`### Validation Transforms`);
257
+ lines.push(``);
258
+ for (const tf of validationTransforms) {
259
+ const label = tf.label || tf.id;
260
+ const inputs = tf.inputs?.join(', ') || '-';
261
+ const description = tf.description || 'No description';
262
+ lines.push(`- **${label}**`);
263
+ lines.push(` - Validates: ${inputs}`);
264
+ lines.push(` - Logic: ${description}`);
265
+ lines.push(``);
266
+ }
267
+ }
268
+ lines.push(`---`);
269
+ lines.push(``);
270
+ }
271
+ // Implementation Recommendations
272
+ lines.push(`## Implementation Recommendations`);
273
+ lines.push(``);
274
+ lines.push(`1. **Database Schema**`);
275
+ lines.push(` - Create tables: ${tables.map((t) => t.label).join(', ')}`);
276
+ lines.push(` - Set up migrations and seed data`);
277
+ lines.push(``);
278
+ lines.push(`2. **API Contracts**`);
279
+ lines.push(` - Implement endpoints for inferred DataPoints (${dataPoints.filter((dp) => dp.source === 'inferred').length} endpoints)`);
280
+ lines.push(` - Add authentication and authorization`);
281
+ lines.push(``);
282
+ lines.push(`3. **Component Structure**`);
283
+ lines.push(` - Build ${components.length} UI components`);
284
+ lines.push(` - Connect data flows (displays/captures)`);
285
+ lines.push(``);
286
+ lines.push(`4. **Validation Rules**`);
287
+ lines.push(` - Apply constraints at both client and server`);
288
+ lines.push(` - Implement ${transforms.filter((tf) => tf.type === 'validation').length} validation transforms`);
289
+ lines.push(``);
290
+ lines.push(`5. **Business Logic**`);
291
+ lines.push(` - Implement ${transforms.length} transforms`);
292
+ lines.push(` - Test all data flows and edge cases`);
293
+ lines.push(``);
294
+ lines.push(`---`);
295
+ lines.push(``);
296
+ // Quality Metrics (from project analysis)
297
+ const nodes = project.canvas_state?.nodes || [];
298
+ const edges = project.canvas_state?.edges || [];
299
+ lines.push(`## Quality Metrics`);
300
+ lines.push(``);
301
+ lines.push(`- **Total nodes:** ${nodes.length}`);
302
+ lines.push(`- **Total edges:** ${edges.length}`);
303
+ lines.push(`- **Screens:** ${screens.length}`);
304
+ lines.push(`- **Captured DataPoints:** ${dataPoints.filter((dp) => dp.source === 'captured').length}`);
305
+ lines.push(`- **Inferred DataPoints:** ${dataPoints.filter((dp) => dp.source === 'inferred').length}`);
306
+ lines.push(``);
307
+ lines.push(`✅ **Ready for implementation in Claude Code via \`/spec\` skill**`);
308
+ lines.push(``);
309
+ // Footer
310
+ lines.push(`---`);
311
+ lines.push(``);
312
+ lines.push(`*Generated by FlowSpec MCP Server v3.0.0*`);
313
+ return lines.join('\n');
314
+ }
315
+ // ─── JSON Spec Generation ───────────────────────────────────────
316
+ function generateJsonSpec(projectName, yaml) {
317
+ const spec = {
318
+ projectName: projectName,
319
+ generated: new Date().toISOString(),
320
+ version: yaml.version || '1.2.0',
321
+ summary: {
322
+ dataPoints: yaml.dataPoints?.length || 0,
323
+ components: yaml.components?.length || 0,
324
+ transforms: yaml.transforms?.length || 0,
325
+ tables: yaml.tables?.length || 0,
326
+ screens: yaml.screens?.length || 0
327
+ },
328
+ dataPoints: yaml.dataPoints || [],
329
+ components: yaml.components || [],
330
+ transforms: yaml.transforms || [],
331
+ tables: yaml.tables || [],
332
+ screens: yaml.screens || []
333
+ };
334
+ return JSON.stringify(spec, null, 2);
335
+ }
336
+ //# sourceMappingURL=generateSpec.js.map