mcp-dndgrid 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.
Files changed (45) hide show
  1. package/PROJECT_SUMMARY.md +482 -0
  2. package/QUICKSTART.md +223 -0
  3. package/README.md +365 -0
  4. package/STATUS.md +315 -0
  5. package/USAGE_GUIDE.md +547 -0
  6. package/dist/chunk-CMGEAPA5.js +157 -0
  7. package/dist/chunk-CMGEAPA5.js.map +1 -0
  8. package/dist/chunk-QZHBI6ZI.js +5281 -0
  9. package/dist/chunk-QZHBI6ZI.js.map +1 -0
  10. package/dist/chunk-SEGVTWSK.js +44 -0
  11. package/dist/chunk-SEGVTWSK.js.map +1 -0
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.js +248012 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/stdio-FWYJXSU7.js +101 -0
  16. package/dist/stdio-FWYJXSU7.js.map +1 -0
  17. package/dist/template-JDMAVVX7.js +9 -0
  18. package/dist/template-JDMAVVX7.js.map +1 -0
  19. package/examples/claude_desktop_config.example.json +12 -0
  20. package/examples/example-complex-editor.tsx +107 -0
  21. package/examples/example-dashboard.tsx +65 -0
  22. package/examples/example-ide-layout.tsx +53 -0
  23. package/examples/test-generator.ts +37 -0
  24. package/examples/test-parser.ts +121 -0
  25. package/examples/test-scenarios.md +496 -0
  26. package/package.json +42 -0
  27. package/src/index.ts +16 -0
  28. package/src/server.ts +314 -0
  29. package/src/tools/analyze-layout.ts +193 -0
  30. package/src/tools/apply-template.ts +125 -0
  31. package/src/tools/generate-layout.ts +235 -0
  32. package/src/tools/interactive-builder.ts +100 -0
  33. package/src/tools/validate-layout.ts +113 -0
  34. package/src/types/layout.ts +48 -0
  35. package/src/types/template.ts +181 -0
  36. package/src/utils/ast-parser.ts +264 -0
  37. package/src/utils/code-generator.ts +123 -0
  38. package/src/utils/layout-analyzer.ts +105 -0
  39. package/src/utils/layout-builder.ts +127 -0
  40. package/src/utils/validator.ts +263 -0
  41. package/stderr.log +1 -0
  42. package/stdout.log +0 -0
  43. package/test-mcp.js +27 -0
  44. package/tsconfig.json +29 -0
  45. package/tsup.config.ts +16 -0
@@ -0,0 +1,263 @@
1
+ import type {
2
+ LayoutTree,
3
+ LayoutNode,
4
+ ValidationError,
5
+ ValidationWarning,
6
+ } from '../types/layout.js';
7
+ import { LayoutAnalyzer } from './layout-analyzer.js';
8
+
9
+ export interface ValidationResult {
10
+ valid: boolean;
11
+ errors: ValidationError[];
12
+ warnings: ValidationWarning[];
13
+ suggestions: string[];
14
+ }
15
+
16
+ /**
17
+ * Validates DndGrid layout structure and constraints
18
+ */
19
+ export class Validator {
20
+ private errors: ValidationError[] = [];
21
+ private warnings: ValidationWarning[] = [];
22
+ private suggestions: string[] = [];
23
+
24
+ /**
25
+ * Validate a layout tree
26
+ */
27
+ validate(layout: LayoutTree, strict: boolean = false): ValidationResult {
28
+ this.errors = [];
29
+ this.warnings = [];
30
+ this.suggestions = [];
31
+
32
+ // Validate container dimensions
33
+ this.validateContainer(layout);
34
+
35
+ // Validate tree structure
36
+ this.validateNode(layout.child);
37
+
38
+ // Strict mode validations
39
+ if (strict) {
40
+ this.validatePerformance(layout);
41
+ }
42
+
43
+ return {
44
+ valid: this.errors.length === 0,
45
+ errors: this.errors,
46
+ warnings: this.warnings,
47
+ suggestions: this.suggestions,
48
+ };
49
+ }
50
+
51
+ /**
52
+ * Validate container properties
53
+ */
54
+ private validateContainer(layout: LayoutTree): void {
55
+ if (layout.width <= 0) {
56
+ this.errors.push({
57
+ type: 'constraint',
58
+ message: `Invalid container width: ${layout.width}. Must be positive.`,
59
+ fix: 'width={1200}',
60
+ });
61
+ }
62
+
63
+ if (layout.height <= 0) {
64
+ this.errors.push({
65
+ type: 'constraint',
66
+ message: `Invalid container height: ${layout.height}. Must be positive.`,
67
+ fix: 'height={800}',
68
+ });
69
+ }
70
+
71
+ if (layout.width < 100 || layout.height < 100) {
72
+ this.warnings.push({
73
+ message: `Very small container dimensions (${layout.width}x${layout.height}). Consider larger sizes.`,
74
+ suggestion: 'Minimum recommended: 400x300',
75
+ });
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Validate a layout node
81
+ */
82
+ private validateNode(node: LayoutNode, depth: number = 1): void {
83
+ if (node.type === 'split') {
84
+ this.validateSplit(node, depth);
85
+ this.validateNode(node.primary, depth + 1);
86
+ this.validateNode(node.secondary, depth + 1);
87
+ } else {
88
+ this.validateItem(node, depth);
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Validate Split node
94
+ */
95
+ private validateSplit(node: LayoutNode, depth: number): void {
96
+ if (node.type !== 'split') return;
97
+
98
+ // Validate ratio
99
+ if (node.ratio <= 0 || node.ratio >= 1) {
100
+ this.errors.push({
101
+ type: 'constraint',
102
+ message: `Invalid split ratio: ${node.ratio}. Must be between 0 and 1 (exclusive).`,
103
+ fix: 'ratio={0.5}',
104
+ });
105
+ }
106
+
107
+ // Warn about extreme ratios
108
+ if (node.ratio < 0.1 || node.ratio > 0.9) {
109
+ this.warnings.push({
110
+ message: `Extreme split ratio: ${node.ratio}. This creates very small panels.`,
111
+ suggestion: 'Consider ratios between 0.2 and 0.8 for better UX',
112
+ });
113
+ }
114
+
115
+ // Validate direction
116
+ if (node.direction !== 'horizontal' && node.direction !== 'vertical') {
117
+ this.errors.push({
118
+ type: 'constraint',
119
+ message: `Invalid direction: ${node.direction}. Must be 'horizontal' or 'vertical'.`,
120
+ fix: 'direction="horizontal"',
121
+ });
122
+ }
123
+
124
+ // Check if both children exist
125
+ if (!node.primary || !node.secondary) {
126
+ this.errors.push({
127
+ type: 'structure',
128
+ message: 'Split must have exactly 2 children (primary and secondary).',
129
+ });
130
+ }
131
+
132
+ // Warn about deep nesting
133
+ if (depth > 5) {
134
+ this.warnings.push({
135
+ message: `Deep nesting detected (depth: ${depth}). This may impact performance.`,
136
+ suggestion: 'Consider flattening the layout structure',
137
+ });
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Validate Item node
143
+ */
144
+ private validateItem(node: LayoutNode, depth: number): void {
145
+ if (node.type !== 'item') return;
146
+
147
+ // Validate component name
148
+ if (!node.component || node.component.trim().length === 0) {
149
+ this.errors.push({
150
+ type: 'structure',
151
+ message: 'Item must have a component name.',
152
+ fix: '<ComponentName />',
153
+ });
154
+ }
155
+
156
+ // Check component naming convention
157
+ if (node.component && !/^[A-Z]/.test(node.component)) {
158
+ this.warnings.push({
159
+ message: `Component name "${node.component}" should start with uppercase letter.`,
160
+ suggestion: `Use "${node.component.charAt(0).toUpperCase() + node.component.slice(1)}"`,
161
+ });
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Validate performance constraints (strict mode)
167
+ */
168
+ private validatePerformance(layout: LayoutTree): void {
169
+ const metadata = LayoutAnalyzer.calculateMetadata(layout);
170
+
171
+ // Check item count
172
+ if (metadata.itemCount > 50) {
173
+ this.errors.push({
174
+ type: 'constraint',
175
+ message: `Too many items: ${metadata.itemCount}. Maximum recommended: 50`,
176
+ });
177
+ } else if (metadata.itemCount > 20) {
178
+ this.warnings.push({
179
+ message: `High item count: ${metadata.itemCount}. Consider reducing for better performance.`,
180
+ suggestion: 'Recommended: < 20 items',
181
+ });
182
+ }
183
+
184
+ // Check depth
185
+ if (metadata.maxDepth > 6) {
186
+ this.errors.push({
187
+ type: 'constraint',
188
+ message: `Tree too deep: ${metadata.maxDepth} levels. Maximum recommended: 6`,
189
+ });
190
+ } else if (metadata.maxDepth > 4) {
191
+ this.warnings.push({
192
+ message: `Deep tree structure: ${metadata.maxDepth} levels.`,
193
+ suggestion: 'Recommended: < 4 levels for optimal performance',
194
+ });
195
+ }
196
+
197
+ // Add performance suggestions
198
+ if (metadata.estimatedPerformance === 'fair' || metadata.estimatedPerformance === 'poor') {
199
+ this.suggestions.push(
200
+ `Performance score: ${metadata.estimatedPerformance}. Consider simplifying the layout.`
201
+ );
202
+ }
203
+
204
+ // Check for optimization opportunities
205
+ if (metadata.splitCount > metadata.itemCount) {
206
+ this.suggestions.push(
207
+ 'More splits than items detected. Some splits may be unnecessary.'
208
+ );
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Validate code string (wrapper for AST parsing)
214
+ */
215
+ validateCode(code: string, strict: boolean = false): ValidationResult {
216
+ this.errors = [];
217
+ this.warnings = [];
218
+ this.suggestions = [];
219
+
220
+ // Check for "use client" directive (Next.js)
221
+ if (!code.includes('"use client"') && !code.includes("'use client'")) {
222
+ this.warnings.push({
223
+ message: 'Missing "use client" directive for Next.js App Router.',
224
+ suggestion: 'Add "use client"; at the top of the file',
225
+ });
226
+ }
227
+
228
+ // Check for required imports
229
+ if (!code.includes('DndGridContainer')) {
230
+ this.errors.push({
231
+ type: 'structure',
232
+ message: 'Missing DndGridContainer import.',
233
+ fix: "import { DndGridContainer } from 'zerojin/components';",
234
+ });
235
+ }
236
+
237
+ // Basic syntax checks
238
+ const openBraces = (code.match(/{/g) || []).length;
239
+ const closeBraces = (code.match(/}/g) || []).length;
240
+ if (openBraces !== closeBraces) {
241
+ this.errors.push({
242
+ type: 'syntax',
243
+ message: `Mismatched braces: ${openBraces} opening, ${closeBraces} closing.`,
244
+ });
245
+ }
246
+
247
+ const openTags = (code.match(/<(?!\/)[A-Z]/g) || []).length;
248
+ const closeTags = (code.match(/<\/[A-Z]/g) || []).length;
249
+ if (openTags !== closeTags) {
250
+ this.errors.push({
251
+ type: 'syntax',
252
+ message: `Mismatched JSX tags: ${openTags} opening, ${closeTags} closing.`,
253
+ });
254
+ }
255
+
256
+ return {
257
+ valid: this.errors.length === 0,
258
+ errors: this.errors,
259
+ warnings: this.warnings,
260
+ suggestions: this.suggestions,
261
+ };
262
+ }
263
+ }
package/stderr.log ADDED
@@ -0,0 +1 @@
1
+ DndGrid MCP Server started
package/stdout.log ADDED
File without changes
package/test-mcp.js ADDED
@@ -0,0 +1,27 @@
1
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
3
+ import { ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
4
+
5
+ async function test() {
6
+ const transport = new StdioClientTransport({
7
+ command: "node",
8
+ args: ["/Users/zero/Desktop/zerojin-core/mcp/dist/index.cjs"],
9
+ });
10
+
11
+ const client = new Client({
12
+ name: "test-client",
13
+ version: "1.0.0",
14
+ }, {
15
+ capabilities: {}
16
+ });
17
+
18
+ await client.connect(transport);
19
+ console.log("Connected to server");
20
+
21
+ const tools = await client.listTools();
22
+ console.log("Tools:", JSON.stringify(tools, null, 2));
23
+
24
+ await transport.close();
25
+ }
26
+
27
+ test().catch(console.error);
package/tsconfig.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "lib": ["ES2022"],
6
+ "moduleResolution": "bundler",
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "allowSyntheticDefaultImports": true,
10
+
11
+ "strict": true,
12
+ "noUnusedLocals": true,
13
+ "noUnusedParameters": true,
14
+ "noFallthroughCasesInSwitch": true,
15
+ "noUncheckedIndexedAccess": true,
16
+ "exactOptionalPropertyTypes": true,
17
+
18
+ "declaration": true,
19
+ "declarationMap": true,
20
+ "sourceMap": true,
21
+ "outDir": "./dist",
22
+ "rootDir": "./src",
23
+
24
+ "resolveJsonModule": true,
25
+ "isolatedModules": true
26
+ },
27
+ "include": ["src/**/*"],
28
+ "exclude": ["node_modules", "dist", "**/*.test.ts"]
29
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { defineConfig } from 'tsup';
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts'],
5
+ format: ['esm'],
6
+ dts: true,
7
+ sourcemap: true,
8
+ clean: true,
9
+ outDir: 'dist',
10
+ target: 'node18',
11
+ shims: false,
12
+ noExternal: [/.*/],
13
+ banner: {
14
+ js: '#!/usr/bin/env node',
15
+ },
16
+ });