@tekton-ui/mcp-server 0.3.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 (179) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +980 -0
  3. package/dist/auth/cache.d.ts +28 -0
  4. package/dist/auth/cache.d.ts.map +1 -0
  5. package/dist/auth/cache.js +48 -0
  6. package/dist/auth/cache.js.map +1 -0
  7. package/dist/auth/guard.d.ts +13 -0
  8. package/dist/auth/guard.d.ts.map +1 -0
  9. package/dist/auth/guard.js +21 -0
  10. package/dist/auth/guard.js.map +1 -0
  11. package/dist/auth/state.d.ts +32 -0
  12. package/dist/auth/state.d.ts.map +1 -0
  13. package/dist/auth/state.js +72 -0
  14. package/dist/auth/state.js.map +1 -0
  15. package/dist/auth/theme-access.d.ts +10 -0
  16. package/dist/auth/theme-access.d.ts.map +1 -0
  17. package/dist/auth/theme-access.js +24 -0
  18. package/dist/auth/theme-access.js.map +1 -0
  19. package/dist/auth/verify.d.ts +44 -0
  20. package/dist/auth/verify.d.ts.map +1 -0
  21. package/dist/auth/verify.js +77 -0
  22. package/dist/auth/verify.js.map +1 -0
  23. package/dist/cli/credentials.d.ts +29 -0
  24. package/dist/cli/credentials.d.ts.map +1 -0
  25. package/dist/cli/credentials.js +66 -0
  26. package/dist/cli/credentials.js.map +1 -0
  27. package/dist/cli/index.d.ts +7 -0
  28. package/dist/cli/index.d.ts.map +1 -0
  29. package/dist/cli/index.js +36 -0
  30. package/dist/cli/index.js.map +1 -0
  31. package/dist/cli/login.d.ts +9 -0
  32. package/dist/cli/login.d.ts.map +1 -0
  33. package/dist/cli/login.js +120 -0
  34. package/dist/cli/login.js.map +1 -0
  35. package/dist/cli/logout.d.ts +9 -0
  36. package/dist/cli/logout.d.ts.map +1 -0
  37. package/dist/cli/logout.js +18 -0
  38. package/dist/cli/logout.js.map +1 -0
  39. package/dist/cli/status.d.ts +9 -0
  40. package/dist/cli/status.d.ts.map +1 -0
  41. package/dist/cli/status.js +31 -0
  42. package/dist/cli/status.js.map +1 -0
  43. package/dist/data/component-registry.d.ts +30 -0
  44. package/dist/data/component-registry.d.ts.map +1 -0
  45. package/dist/data/component-registry.js +320 -0
  46. package/dist/data/component-registry.js.map +1 -0
  47. package/dist/data/examples/screen-examples.d.ts +38 -0
  48. package/dist/data/examples/screen-examples.d.ts.map +1 -0
  49. package/dist/data/examples/screen-examples.js +500 -0
  50. package/dist/data/examples/screen-examples.js.map +1 -0
  51. package/dist/data/hint-generator.d.ts +16 -0
  52. package/dist/data/hint-generator.d.ts.map +1 -0
  53. package/dist/data/hint-generator.js +298 -0
  54. package/dist/data/hint-generator.js.map +1 -0
  55. package/dist/data/recipe-resolver.d.ts +48 -0
  56. package/dist/data/recipe-resolver.d.ts.map +1 -0
  57. package/dist/data/recipe-resolver.js +226 -0
  58. package/dist/data/recipe-resolver.js.map +1 -0
  59. package/dist/data/template-matcher.d.ts +50 -0
  60. package/dist/data/template-matcher.d.ts.map +1 -0
  61. package/dist/data/template-matcher.js +240 -0
  62. package/dist/data/template-matcher.js.map +1 -0
  63. package/dist/generators/core-resolver.d.ts +56 -0
  64. package/dist/generators/core-resolver.d.ts.map +1 -0
  65. package/dist/generators/core-resolver.js +490 -0
  66. package/dist/generators/core-resolver.js.map +1 -0
  67. package/dist/generators/css-generator.d.ts +49 -0
  68. package/dist/generators/css-generator.d.ts.map +1 -0
  69. package/dist/generators/css-generator.js +294 -0
  70. package/dist/generators/css-generator.js.map +1 -0
  71. package/dist/generators/index.d.ts +13 -0
  72. package/dist/generators/index.d.ts.map +1 -0
  73. package/dist/generators/index.js +16 -0
  74. package/dist/generators/index.js.map +1 -0
  75. package/dist/generators/llm-generator.d.ts +96 -0
  76. package/dist/generators/llm-generator.d.ts.map +1 -0
  77. package/dist/generators/llm-generator.js +296 -0
  78. package/dist/generators/llm-generator.js.map +1 -0
  79. package/dist/index.d.ts +3 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +818 -0
  82. package/dist/index.js.map +1 -0
  83. package/dist/schemas/mcp-schemas.d.ts +4132 -0
  84. package/dist/schemas/mcp-schemas.d.ts.map +1 -0
  85. package/dist/schemas/mcp-schemas.js +946 -0
  86. package/dist/schemas/mcp-schemas.js.map +1 -0
  87. package/dist/storage/blueprint-storage.d.ts +68 -0
  88. package/dist/storage/blueprint-storage.d.ts.map +1 -0
  89. package/dist/storage/blueprint-storage.js +135 -0
  90. package/dist/storage/blueprint-storage.js.map +1 -0
  91. package/dist/storage/timestamp-manager.d.ts +32 -0
  92. package/dist/storage/timestamp-manager.d.ts.map +1 -0
  93. package/dist/storage/timestamp-manager.js +59 -0
  94. package/dist/storage/timestamp-manager.js.map +1 -0
  95. package/dist/tools/export-screen.d.ts +34 -0
  96. package/dist/tools/export-screen.d.ts.map +1 -0
  97. package/dist/tools/export-screen.js +344 -0
  98. package/dist/tools/export-screen.js.map +1 -0
  99. package/dist/tools/generate-blueprint.d.ts +15 -0
  100. package/dist/tools/generate-blueprint.d.ts.map +1 -0
  101. package/dist/tools/generate-blueprint.js +165 -0
  102. package/dist/tools/generate-blueprint.js.map +1 -0
  103. package/dist/tools/generate-screen.d.ts +13 -0
  104. package/dist/tools/generate-screen.d.ts.map +1 -0
  105. package/dist/tools/generate-screen.js +82 -0
  106. package/dist/tools/generate-screen.js.map +1 -0
  107. package/dist/tools/get-screen-generation-context.d.ts +11 -0
  108. package/dist/tools/get-screen-generation-context.d.ts.map +1 -0
  109. package/dist/tools/get-screen-generation-context.js +316 -0
  110. package/dist/tools/get-screen-generation-context.js.map +1 -0
  111. package/dist/tools/list-components.d.ts +15 -0
  112. package/dist/tools/list-components.d.ts.map +1 -0
  113. package/dist/tools/list-components.js +46 -0
  114. package/dist/tools/list-components.js.map +1 -0
  115. package/dist/tools/list-icon-libraries.d.ts +12 -0
  116. package/dist/tools/list-icon-libraries.d.ts.map +1 -0
  117. package/dist/tools/list-icon-libraries.js +48 -0
  118. package/dist/tools/list-icon-libraries.js.map +1 -0
  119. package/dist/tools/list-screen-templates.d.ts +15 -0
  120. package/dist/tools/list-screen-templates.d.ts.map +1 -0
  121. package/dist/tools/list-screen-templates.js +63 -0
  122. package/dist/tools/list-screen-templates.js.map +1 -0
  123. package/dist/tools/list-themes.d.ts +13 -0
  124. package/dist/tools/list-themes.d.ts.map +1 -0
  125. package/dist/tools/list-themes.js +42 -0
  126. package/dist/tools/list-themes.js.map +1 -0
  127. package/dist/tools/list-tokens.d.ts +13 -0
  128. package/dist/tools/list-tokens.d.ts.map +1 -0
  129. package/dist/tools/list-tokens.js +92 -0
  130. package/dist/tools/list-tokens.js.map +1 -0
  131. package/dist/tools/preview-component.d.ts +18 -0
  132. package/dist/tools/preview-component.d.ts.map +1 -0
  133. package/dist/tools/preview-component.js +178 -0
  134. package/dist/tools/preview-component.js.map +1 -0
  135. package/dist/tools/preview-icon-library.d.ts +13 -0
  136. package/dist/tools/preview-icon-library.d.ts.map +1 -0
  137. package/dist/tools/preview-icon-library.js +63 -0
  138. package/dist/tools/preview-icon-library.js.map +1 -0
  139. package/dist/tools/preview-screen-template.d.ts +18 -0
  140. package/dist/tools/preview-screen-template.d.ts.map +1 -0
  141. package/dist/tools/preview-screen-template.js +101 -0
  142. package/dist/tools/preview-screen-template.js.map +1 -0
  143. package/dist/tools/preview-theme.d.ts +15 -0
  144. package/dist/tools/preview-theme.d.ts.map +1 -0
  145. package/dist/tools/preview-theme.js +71 -0
  146. package/dist/tools/preview-theme.js.map +1 -0
  147. package/dist/tools/validate-environment.d.ts +37 -0
  148. package/dist/tools/validate-environment.d.ts.map +1 -0
  149. package/dist/tools/validate-environment.js +153 -0
  150. package/dist/tools/validate-environment.js.map +1 -0
  151. package/dist/tools/validate-screen-definition.d.ts +10 -0
  152. package/dist/tools/validate-screen-definition.d.ts.map +1 -0
  153. package/dist/tools/validate-screen-definition.js +463 -0
  154. package/dist/tools/validate-screen-definition.js.map +1 -0
  155. package/dist/tools/validate-screen.d.ts +13 -0
  156. package/dist/tools/validate-screen.d.ts.map +1 -0
  157. package/dist/tools/validate-screen.js +106 -0
  158. package/dist/tools/validate-screen.js.map +1 -0
  159. package/dist/utils/dependency-extractor.d.ts +13 -0
  160. package/dist/utils/dependency-extractor.d.ts.map +1 -0
  161. package/dist/utils/dependency-extractor.js +232 -0
  162. package/dist/utils/dependency-extractor.js.map +1 -0
  163. package/dist/utils/error-handler.d.ts +29 -0
  164. package/dist/utils/error-handler.d.ts.map +1 -0
  165. package/dist/utils/error-handler.js +48 -0
  166. package/dist/utils/error-handler.js.map +1 -0
  167. package/dist/utils/logger.d.ts +8 -0
  168. package/dist/utils/logger.d.ts.map +1 -0
  169. package/dist/utils/logger.js +14 -0
  170. package/dist/utils/logger.js.map +1 -0
  171. package/dist/utils/package-json-reader.d.ts +37 -0
  172. package/dist/utils/package-json-reader.d.ts.map +1 -0
  173. package/dist/utils/package-json-reader.js +108 -0
  174. package/dist/utils/package-json-reader.js.map +1 -0
  175. package/dist/utils/tailwind-config-reader.d.ts +23 -0
  176. package/dist/utils/tailwind-config-reader.d.ts.map +1 -0
  177. package/dist/utils/tailwind-config-reader.js +81 -0
  178. package/dist/utils/tailwind-config-reader.js.map +1 -0
  179. package/package.json +72 -0
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Validate Environment MCP Tool
3
+ * SPEC-MCP-005 Phase 2: Check if user's project has required NPM packages installed
4
+ * SPEC-MCP-005: Tailwind CSS 설정 검증 확장
5
+ */
6
+ import type { ValidateEnvironmentInput, ValidateEnvironmentOutput } from '../schemas/mcp-schemas.js';
7
+ /**
8
+ * Validate user's environment for required dependencies
9
+ *
10
+ * Compares required packages against installed packages in package.json
11
+ * and provides installation commands for missing packages.
12
+ * Optionally validates Tailwind CSS configuration for @tekton-ui/ui compatibility.
13
+ *
14
+ * @param input - Project path and required packages to validate
15
+ * @returns Validation result with installed/missing packages and install commands
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const result = await validateEnvironmentTool({
20
+ * projectPath: '/path/to/project',
21
+ * requiredPackages: ['framer-motion', 'react'],
22
+ * checkTailwind: true
23
+ * });
24
+ *
25
+ * if (result.success && result.missing.length > 0) {
26
+ * console.log(`Missing packages: ${result.missing.join(', ')}`);
27
+ * console.log(`Install with: ${result.installCommands.npm}`);
28
+ * }
29
+ *
30
+ * if (result.tailwind?.issues.length) {
31
+ * console.log('Tailwind issues:', result.tailwind.issues);
32
+ * console.log('Fixes:', result.tailwind.fixes);
33
+ * }
34
+ * ```
35
+ */
36
+ export declare function validateEnvironmentTool(input: ValidateEnvironmentInput): Promise<ValidateEnvironmentOutput>;
37
+ //# sourceMappingURL=validate-environment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-environment.d.ts","sourceRoot":"","sources":["../../src/tools/validate-environment.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,2BAA2B,CAAC;AAKnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,yBAAyB,CAAC,CAqGpC"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Validate Environment MCP Tool
3
+ * SPEC-MCP-005 Phase 2: Check if user's project has required NPM packages installed
4
+ * SPEC-MCP-005: Tailwind CSS 설정 검증 확장
5
+ */
6
+ import { readPackageJson } from '../utils/package-json-reader.js';
7
+ import { readTailwindConfig } from '../utils/tailwind-config-reader.js';
8
+ import { extractErrorMessage } from '../utils/error-handler.js';
9
+ /**
10
+ * Validate user's environment for required dependencies
11
+ *
12
+ * Compares required packages against installed packages in package.json
13
+ * and provides installation commands for missing packages.
14
+ * Optionally validates Tailwind CSS configuration for @tekton-ui/ui compatibility.
15
+ *
16
+ * @param input - Project path and required packages to validate
17
+ * @returns Validation result with installed/missing packages and install commands
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const result = await validateEnvironmentTool({
22
+ * projectPath: '/path/to/project',
23
+ * requiredPackages: ['framer-motion', 'react'],
24
+ * checkTailwind: true
25
+ * });
26
+ *
27
+ * if (result.success && result.missing.length > 0) {
28
+ * console.log(`Missing packages: ${result.missing.join(', ')}`);
29
+ * console.log(`Install with: ${result.installCommands.npm}`);
30
+ * }
31
+ *
32
+ * if (result.tailwind?.issues.length) {
33
+ * console.log('Tailwind issues:', result.tailwind.issues);
34
+ * console.log('Fixes:', result.tailwind.fixes);
35
+ * }
36
+ * ```
37
+ */
38
+ export async function validateEnvironmentTool(input) {
39
+ try {
40
+ const { projectPath, requiredPackages, checkTailwind } = input;
41
+ // Step 1: Read package.json from the project
42
+ const readResult = readPackageJson(projectPath);
43
+ if (!readResult.success || !readResult.installedPackages) {
44
+ return {
45
+ success: false,
46
+ error: readResult.error || 'Failed to read package.json',
47
+ };
48
+ }
49
+ const installedPackages = readResult.installedPackages;
50
+ // Step 2: Compare required packages with installed packages
51
+ const installed = {};
52
+ const missing = [];
53
+ for (const packageName of requiredPackages) {
54
+ const version = installedPackages[packageName];
55
+ if (version !== undefined) {
56
+ // Package is installed
57
+ installed[packageName] = version;
58
+ }
59
+ else {
60
+ // Package is missing
61
+ missing.push(packageName);
62
+ }
63
+ }
64
+ // Step 3: Generate install commands for missing packages
65
+ const installCommands = generateInstallCommands(missing);
66
+ // Step 4: Check for potential warnings (optional enhancement)
67
+ const warnings = [];
68
+ // Step 5: Tailwind CSS 설정 검증
69
+ let tailwind;
70
+ if (checkTailwind !== false) {
71
+ const tailwindResult = readTailwindConfig(projectPath);
72
+ const issues = [];
73
+ const fixes = [];
74
+ if (!tailwindResult.found) {
75
+ issues.push('tailwind.config.{ts,js,mjs,cjs} not found in project root');
76
+ fixes.push('Create a tailwind.config.ts file in your project root. ' +
77
+ 'See https://tailwindcss.com/docs/configuration for setup guide.');
78
+ }
79
+ else {
80
+ if (!tailwindResult.hasUiContentPath) {
81
+ issues.push('tailwind.config content paths do not include @tekton-ui/ui — ' +
82
+ 'component styles (Dialog, AlertDialog, Popover, etc.) will not be compiled');
83
+ fixes.push("Add '../../packages/ui/src/**/*.{ts,tsx}' (monorepo) or " +
84
+ "'node_modules/@tekton-ui/ui/dist/**/*.{js,ts,jsx,tsx}' (standalone) " +
85
+ 'to the content array in your tailwind.config');
86
+ }
87
+ if (!tailwindResult.hasAnimatePlugin) {
88
+ issues.push('tailwindcss-animate plugin is not configured — ' +
89
+ 'Radix UI component animations (Dialog open/close, Popover, Tooltip) will not work');
90
+ fixes.push('Install tailwindcss-animate (npm install tailwindcss-animate) and add it to plugins array: ' +
91
+ "import animate from 'tailwindcss-animate'; plugins: [animate]");
92
+ }
93
+ }
94
+ tailwind = {
95
+ configFound: tailwindResult.found,
96
+ configPath: tailwindResult.configPath,
97
+ hasUiContentPath: tailwindResult.hasUiContentPath,
98
+ hasAnimatePlugin: tailwindResult.hasAnimatePlugin,
99
+ issues,
100
+ fixes,
101
+ };
102
+ }
103
+ return {
104
+ success: true,
105
+ installed,
106
+ missing,
107
+ installCommands,
108
+ warnings: warnings.length > 0 ? warnings : undefined,
109
+ tailwind,
110
+ };
111
+ }
112
+ catch (error) {
113
+ return {
114
+ success: false,
115
+ error: extractErrorMessage(error),
116
+ };
117
+ }
118
+ }
119
+ /**
120
+ * Generate installation commands for multiple package managers
121
+ *
122
+ * @param packages - Array of package names to install
123
+ * @returns Install commands for npm, yarn, pnpm, and bun
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * const commands = generateInstallCommands(['react', 'react-dom']);
128
+ * // {
129
+ * // npm: 'npm install react react-dom',
130
+ * // yarn: 'yarn add react react-dom',
131
+ * // pnpm: 'pnpm add react react-dom',
132
+ * // bun: 'bun add react react-dom'
133
+ * // }
134
+ * ```
135
+ */
136
+ function generateInstallCommands(packages) {
137
+ if (packages.length === 0) {
138
+ return {
139
+ npm: '',
140
+ yarn: '',
141
+ pnpm: '',
142
+ bun: '',
143
+ };
144
+ }
145
+ const packageList = packages.join(' ');
146
+ return {
147
+ npm: `npm install ${packageList}`,
148
+ yarn: `yarn add ${packageList}`,
149
+ pnpm: `pnpm add ${packageList}`,
150
+ bun: `bun add ${packageList}`,
151
+ };
152
+ }
153
+ //# sourceMappingURL=validate-environment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-environment.js","sourceRoot":"","sources":["../../src/tools/validate-environment.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Validate Screen Definition MCP Tool
3
+ * SPEC-MCP-004 Phase 3.5: Validates screen definitions with helpful feedback
4
+ */
5
+ import type { ValidateScreenDefinitionInput, ValidateScreenDefinitionOutput } from '../schemas/mcp-schemas.js';
6
+ /**
7
+ * Validate Screen Definition tool implementation
8
+ */
9
+ export declare function validateScreenDefinitionTool(input: ValidateScreenDefinitionInput): Promise<ValidateScreenDefinitionOutput>;
10
+ //# sourceMappingURL=validate-screen-definition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-screen-definition.d.ts","sourceRoot":"","sources":["../../src/tools/validate-screen-definition.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACV,6BAA6B,EAC7B,8BAA8B,EAI/B,MAAM,2BAA2B,CAAC;AA2anC;;GAEG;AACH,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,6BAA6B,GACnC,OAAO,CAAC,8BAA8B,CAAC,CAkGzC"}
@@ -0,0 +1,463 @@
1
+ /**
2
+ * Validate Screen Definition MCP Tool
3
+ * SPEC-MCP-004 Phase 3.5: Validates screen definitions with helpful feedback
4
+ */
5
+ import { COMPONENT_CATALOG } from '@tekton-ui/core';
6
+ import { ScreenDefinitionSchema } from '../schemas/mcp-schemas.js';
7
+ import { extractErrorMessage } from '../utils/error-handler.js';
8
+ /**
9
+ * Valid shell tokens from SPEC-LAYOUT-001 and SPEC-LAYOUT-004
10
+ */
11
+ const VALID_SHELLS = [
12
+ // Web shells
13
+ 'shell.web.app',
14
+ 'shell.web.dashboard',
15
+ 'shell.web.auth',
16
+ 'shell.web.marketing',
17
+ 'shell.web.minimal',
18
+ // Mobile shells (SPEC-LAYOUT-004)
19
+ 'shell.mobile.app',
20
+ 'shell.mobile.fullscreen',
21
+ 'shell.mobile.modal',
22
+ 'shell.mobile.tab',
23
+ 'shell.mobile.drawer',
24
+ 'shell.mobile.detail',
25
+ ];
26
+ /**
27
+ * Valid page tokens from SPEC-LAYOUT-001
28
+ */
29
+ const VALID_PAGES = ['page.dashboard', 'page.detail', 'page.wizard', 'page.resource', 'page.empty'];
30
+ /**
31
+ * Valid section patterns from SPEC-LAYOUT-001
32
+ */
33
+ const VALID_SECTION_PATTERNS = [
34
+ 'section.container',
35
+ 'section.centered',
36
+ 'section.grid-2',
37
+ 'section.grid-3',
38
+ 'section.grid-4',
39
+ 'section.split-50-50',
40
+ 'section.split-60-40',
41
+ 'section.split-70-30',
42
+ 'section.hero',
43
+ 'section.feature',
44
+ ];
45
+ /**
46
+ * Valid slot names
47
+ */
48
+ const VALID_SLOTS = ['header', 'main', 'sidebar', 'footer'];
49
+ /**
50
+ * Get similar values for suggestions (Levenshtein distance based)
51
+ */
52
+ function getSimilarValues(value, validValues) {
53
+ const similar = [];
54
+ for (const valid of validValues) {
55
+ const distance = levenshteinDistance(value.toLowerCase(), valid.toLowerCase());
56
+ if (distance <= 3) {
57
+ similar.push({ value: valid, distance });
58
+ }
59
+ }
60
+ return similar
61
+ .sort((a, b) => a.distance - b.distance)
62
+ .slice(0, 3)
63
+ .map(s => s.value);
64
+ }
65
+ /**
66
+ * Simple Levenshtein distance implementation
67
+ */
68
+ function levenshteinDistance(a, b) {
69
+ const matrix = [];
70
+ for (let i = 0; i <= b.length; i++) {
71
+ matrix[i] = [i];
72
+ }
73
+ for (let j = 0; j <= a.length; j++) {
74
+ matrix[0][j] = j;
75
+ }
76
+ for (let i = 1; i <= b.length; i++) {
77
+ for (let j = 1; j <= a.length; j++) {
78
+ const cost = b.charAt(i - 1) === a.charAt(j - 1) ? 0 : 1;
79
+ matrix[i][j] = Math.min((matrix[i - 1]?.[j] ?? 0) + 1, (matrix[i]?.[j - 1] ?? 0) + 1, (matrix[i - 1]?.[j - 1] ?? 0) + cost);
80
+ }
81
+ }
82
+ return matrix[b.length]?.[a.length] ?? 0;
83
+ }
84
+ /**
85
+ * Validate shell token
86
+ */
87
+ function validateShell(shell, path) {
88
+ const errors = [];
89
+ const warnings = [];
90
+ if (!shell.startsWith('shell.')) {
91
+ errors.push({
92
+ path,
93
+ code: 'INVALID_SHELL_FORMAT',
94
+ message: 'Shell token must start with "shell."',
95
+ expected: 'shell.{platform}.{name}',
96
+ received: shell,
97
+ suggestion: `Use format: shell.web.app or shell.mobile.app`,
98
+ });
99
+ return { errors, warnings };
100
+ }
101
+ if (!VALID_SHELLS.includes(shell)) {
102
+ const similar = getSimilarValues(shell, VALID_SHELLS);
103
+ errors.push({
104
+ path,
105
+ code: 'UNKNOWN_SHELL',
106
+ message: `Unknown shell token: "${shell}"`,
107
+ expected: VALID_SHELLS.slice(0, 5).join(', ') + '...',
108
+ received: shell,
109
+ suggestion: similar.length > 0
110
+ ? `Did you mean: ${similar.join(', ')}?`
111
+ : `Valid shells: ${VALID_SHELLS.join(', ')}`,
112
+ });
113
+ }
114
+ return { errors, warnings };
115
+ }
116
+ /**
117
+ * Validate page token
118
+ */
119
+ function validatePage(page, path) {
120
+ const errors = [];
121
+ const warnings = [];
122
+ if (!page.startsWith('page.')) {
123
+ errors.push({
124
+ path,
125
+ code: 'INVALID_PAGE_FORMAT',
126
+ message: 'Page token must start with "page."',
127
+ expected: 'page.{name}',
128
+ received: page,
129
+ suggestion: 'Use format: page.dashboard, page.detail, etc.',
130
+ });
131
+ return { errors, warnings };
132
+ }
133
+ if (!VALID_PAGES.includes(page)) {
134
+ const similar = getSimilarValues(page, VALID_PAGES);
135
+ errors.push({
136
+ path,
137
+ code: 'UNKNOWN_PAGE',
138
+ message: `Unknown page token: "${page}"`,
139
+ expected: VALID_PAGES.join(', '),
140
+ received: page,
141
+ suggestion: similar.length > 0
142
+ ? `Did you mean: ${similar.join(', ')}?`
143
+ : `Valid pages: ${VALID_PAGES.join(', ')}`,
144
+ });
145
+ }
146
+ return { errors, warnings };
147
+ }
148
+ /**
149
+ * Validate section pattern
150
+ */
151
+ function validateSectionPattern(pattern, path, strict) {
152
+ const errors = [];
153
+ const warnings = [];
154
+ if (!pattern.startsWith('section.')) {
155
+ errors.push({
156
+ path,
157
+ code: 'INVALID_SECTION_FORMAT',
158
+ message: 'Section pattern must start with "section."',
159
+ expected: 'section.{name}',
160
+ received: pattern,
161
+ suggestion: 'Use format: section.container, section.grid-4, etc.',
162
+ });
163
+ return { errors, warnings };
164
+ }
165
+ if (!VALID_SECTION_PATTERNS.includes(pattern)) {
166
+ if (strict) {
167
+ const similar = getSimilarValues(pattern, VALID_SECTION_PATTERNS);
168
+ errors.push({
169
+ path,
170
+ code: 'UNKNOWN_SECTION_PATTERN',
171
+ message: `Unknown section pattern: "${pattern}"`,
172
+ expected: VALID_SECTION_PATTERNS.slice(0, 5).join(', ') + '...',
173
+ received: pattern,
174
+ suggestion: similar.length > 0
175
+ ? `Did you mean: ${similar.join(', ')}?`
176
+ : `Valid patterns: ${VALID_SECTION_PATTERNS.join(', ')}`,
177
+ });
178
+ }
179
+ else {
180
+ warnings.push({
181
+ path,
182
+ code: 'CUSTOM_SECTION_PATTERN',
183
+ message: `Custom section pattern "${pattern}" - ensure it's defined in your layout system`,
184
+ recommendation: `Consider using standard patterns: ${VALID_SECTION_PATTERNS.slice(0, 5).join(', ')}`,
185
+ });
186
+ }
187
+ }
188
+ return { errors, warnings };
189
+ }
190
+ /**
191
+ * Validate component type
192
+ */
193
+ function validateComponentType(type, path, strict) {
194
+ const errors = [];
195
+ const warnings = [];
196
+ // Check if component type exists in catalog (case-insensitive comparison)
197
+ const catalogLower = COMPONENT_CATALOG.map(c => c.toLowerCase());
198
+ const typeLower = type.toLowerCase();
199
+ if (!catalogLower.includes(typeLower)) {
200
+ const similar = getSimilarValues(type, COMPONENT_CATALOG);
201
+ if (strict) {
202
+ errors.push({
203
+ path,
204
+ code: 'UNKNOWN_COMPONENT',
205
+ message: `Unknown component type: "${type}"`,
206
+ expected: 'A component from @tekton-ui/ui catalog',
207
+ received: type,
208
+ suggestion: similar.length > 0
209
+ ? `Did you mean: ${similar.join(', ')}?`
210
+ : 'Use list-components tool to see available components',
211
+ });
212
+ }
213
+ else {
214
+ warnings.push({
215
+ path,
216
+ code: 'CUSTOM_COMPONENT',
217
+ message: `Component "${type}" not found in catalog - ensure it's a valid custom component`,
218
+ recommendation: similar.length > 0
219
+ ? `Did you mean: ${similar.join(', ')}?`
220
+ : 'Use list-components tool to see available components',
221
+ });
222
+ }
223
+ }
224
+ else {
225
+ // Check casing
226
+ const correctCase = COMPONENT_CATALOG.find(c => c.toLowerCase() === typeLower);
227
+ if (correctCase && correctCase !== type) {
228
+ warnings.push({
229
+ path,
230
+ code: 'COMPONENT_CASE',
231
+ message: `Component type "${type}" has incorrect casing`,
232
+ recommendation: `Use "${correctCase}" instead`,
233
+ });
234
+ }
235
+ }
236
+ return { errors, warnings };
237
+ }
238
+ /**
239
+ * Validate slot value
240
+ */
241
+ function validateSlot(slot, path) {
242
+ const errors = [];
243
+ const warnings = [];
244
+ if (!VALID_SLOTS.includes(slot)) {
245
+ const similar = getSimilarValues(slot, VALID_SLOTS);
246
+ errors.push({
247
+ path,
248
+ code: 'INVALID_SLOT',
249
+ message: `Invalid slot value: "${slot}"`,
250
+ expected: VALID_SLOTS.join(', '),
251
+ received: slot,
252
+ suggestion: similar.length > 0
253
+ ? `Did you mean: ${similar.join(', ')}?`
254
+ : `Valid slots: ${VALID_SLOTS.join(', ')}`,
255
+ });
256
+ }
257
+ return { errors, warnings };
258
+ }
259
+ /**
260
+ * Generate improvement suggestions
261
+ */
262
+ function generateSuggestions(definition) {
263
+ const suggestions = [];
264
+ // Handle null/undefined definition
265
+ if (!definition || typeof definition !== 'object') {
266
+ return suggestions;
267
+ }
268
+ // Check for missing name/description
269
+ if (!definition.name) {
270
+ suggestions.push({
271
+ category: 'maintainability',
272
+ message: 'Consider adding a human-readable name for better documentation',
273
+ affectedPath: 'name',
274
+ suggestedChange: 'Add a descriptive name property',
275
+ });
276
+ }
277
+ if (!definition.description) {
278
+ suggestions.push({
279
+ category: 'maintainability',
280
+ message: 'Consider adding a description for documentation purposes',
281
+ affectedPath: 'description',
282
+ suggestedChange: 'Add a brief description of the screen purpose',
283
+ });
284
+ }
285
+ // Check for missing themeId
286
+ if (!definition.themeId) {
287
+ suggestions.push({
288
+ category: 'consistency',
289
+ message: 'Consider specifying a themeId for consistent styling',
290
+ affectedPath: 'themeId',
291
+ suggestedChange: 'Add themeId to enable theme recipe application',
292
+ });
293
+ }
294
+ // Check sections
295
+ if (definition.sections && Array.isArray(definition.sections)) {
296
+ // Check for empty sections
297
+ for (let i = 0; i < definition.sections.length; i++) {
298
+ const section = definition.sections[i];
299
+ if (!section.components || section.components.length === 0) {
300
+ suggestions.push({
301
+ category: 'maintainability',
302
+ message: `Section "${section.id || i}" has no components`,
303
+ affectedPath: `sections[${i}].components`,
304
+ suggestedChange: 'Add components or remove empty section',
305
+ });
306
+ }
307
+ // Check for missing slot
308
+ if (!section.slot) {
309
+ suggestions.push({
310
+ category: 'consistency',
311
+ message: `Section "${section.id || i}" has no slot assigned`,
312
+ affectedPath: `sections[${i}].slot`,
313
+ suggestedChange: 'Assign to a slot (header, main, sidebar, footer) for proper layout positioning',
314
+ });
315
+ }
316
+ // Check components for accessibility
317
+ if (section.components && Array.isArray(section.components)) {
318
+ for (let j = 0; j < section.components.length; j++) {
319
+ const component = section.components[j];
320
+ // Check images for alt text
321
+ if ((component.type === 'Image' || component.type === 'Avatar') &&
322
+ (!component.props || !component.props.alt)) {
323
+ suggestions.push({
324
+ category: 'accessibility',
325
+ message: `${component.type} component is missing alt text`,
326
+ affectedPath: `sections[${i}].components[${j}].props.alt`,
327
+ suggestedChange: 'Add descriptive alt text for screen readers',
328
+ });
329
+ }
330
+ // Check inputs for labels
331
+ if (component.type === 'Input' &&
332
+ component.props &&
333
+ !component.props.label &&
334
+ !component.props['aria-label']) {
335
+ suggestions.push({
336
+ category: 'accessibility',
337
+ message: 'Input component is missing a label',
338
+ affectedPath: `sections[${i}].components[${j}].props.label`,
339
+ suggestedChange: 'Add a label prop or aria-label for accessibility',
340
+ });
341
+ }
342
+ }
343
+ }
344
+ }
345
+ // Check for no main slot
346
+ const hasMainSlot = definition.sections.some((s) => s.slot === 'main' || !s.slot);
347
+ if (!hasMainSlot) {
348
+ suggestions.push({
349
+ category: 'consistency',
350
+ message: 'No section assigned to main slot',
351
+ affectedPath: 'sections',
352
+ suggestedChange: 'Assign at least one section to the main slot',
353
+ });
354
+ }
355
+ }
356
+ return suggestions;
357
+ }
358
+ /**
359
+ * Validate Screen Definition tool implementation
360
+ */
361
+ export async function validateScreenDefinitionTool(input) {
362
+ try {
363
+ const errors = [];
364
+ const warnings = [];
365
+ const strict = input.strict !== false; // Default to strict
366
+ const definition = input.definition;
367
+ // 1. Validate with Zod schema first
368
+ const zodResult = ScreenDefinitionSchema.safeParse(definition);
369
+ if (!zodResult.success) {
370
+ for (const issue of zodResult.error.issues) {
371
+ errors.push({
372
+ path: issue.path.join('.'),
373
+ code: issue.code,
374
+ message: issue.message,
375
+ suggestion: getZodSuggestion(issue),
376
+ });
377
+ }
378
+ }
379
+ // 2. Additional semantic validation (only if basic structure is valid)
380
+ if (definition && typeof definition === 'object') {
381
+ // Validate shell
382
+ if (definition.shell) {
383
+ const shellResult = validateShell(definition.shell, 'shell');
384
+ errors.push(...shellResult.errors);
385
+ warnings.push(...shellResult.warnings);
386
+ }
387
+ // Validate page
388
+ if (definition.page) {
389
+ const pageResult = validatePage(definition.page, 'page');
390
+ errors.push(...pageResult.errors);
391
+ warnings.push(...pageResult.warnings);
392
+ }
393
+ // Validate sections
394
+ if (definition.sections && Array.isArray(definition.sections)) {
395
+ for (let i = 0; i < definition.sections.length; i++) {
396
+ const section = definition.sections[i];
397
+ // Validate pattern
398
+ if (section.pattern) {
399
+ const patternResult = validateSectionPattern(section.pattern, `sections[${i}].pattern`, strict);
400
+ errors.push(...patternResult.errors);
401
+ warnings.push(...patternResult.warnings);
402
+ }
403
+ // Validate slot
404
+ if (section.slot) {
405
+ const slotResult = validateSlot(section.slot, `sections[${i}].slot`);
406
+ errors.push(...slotResult.errors);
407
+ warnings.push(...slotResult.warnings);
408
+ }
409
+ // Validate components
410
+ if (section.components && Array.isArray(section.components)) {
411
+ for (let j = 0; j < section.components.length; j++) {
412
+ const component = section.components[j];
413
+ if (component.type) {
414
+ const typeResult = validateComponentType(component.type, `sections[${i}].components[${j}].type`, strict);
415
+ errors.push(...typeResult.errors);
416
+ warnings.push(...typeResult.warnings);
417
+ }
418
+ }
419
+ }
420
+ }
421
+ }
422
+ }
423
+ // 3. Generate improvement suggestions
424
+ const suggestions = generateSuggestions(definition);
425
+ const isValid = errors.length === 0;
426
+ return {
427
+ success: true,
428
+ valid: isValid,
429
+ errors: errors.length > 0 ? errors : undefined,
430
+ warnings: warnings.length > 0 ? warnings : undefined,
431
+ suggestions: suggestions.length > 0 ? suggestions : undefined,
432
+ };
433
+ }
434
+ catch (error) {
435
+ return {
436
+ success: false,
437
+ error: extractErrorMessage(error),
438
+ };
439
+ }
440
+ }
441
+ /**
442
+ * Get suggestion for Zod validation issue
443
+ */
444
+ function getZodSuggestion(issue) {
445
+ switch (issue.code) {
446
+ case 'invalid_type':
447
+ return `Expected ${issue.expected}, but received ${issue.received}`;
448
+ case 'invalid_string':
449
+ if (issue.validation === 'regex') {
450
+ return 'Check the format - see the pattern in error message';
451
+ }
452
+ return 'Provide a valid string value';
453
+ case 'too_small':
454
+ return `Minimum ${issue.minimum} ${issue.type} required`;
455
+ case 'too_big':
456
+ return `Maximum ${issue.maximum} ${issue.type} allowed`;
457
+ case 'invalid_enum_value':
458
+ return `Valid values: ${issue.options.join(', ')}`;
459
+ default:
460
+ return 'Check the value format and try again';
461
+ }
462
+ }
463
+ //# sourceMappingURL=validate-screen-definition.js.map