@gemini-designer/mcp-server 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 (153) hide show
  1. package/.prettierrc +9 -0
  2. package/dist/components/catalog.d.ts +24 -0
  3. package/dist/components/catalog.d.ts.map +1 -0
  4. package/dist/components/catalog.js +186 -0
  5. package/dist/components/catalog.js.map +1 -0
  6. package/dist/config/index.d.ts +60 -0
  7. package/dist/config/index.d.ts.map +1 -0
  8. package/dist/config/index.js +199 -0
  9. package/dist/config/index.js.map +1 -0
  10. package/dist/context/builder.d.ts +32 -0
  11. package/dist/context/builder.d.ts.map +1 -0
  12. package/dist/context/builder.js +194 -0
  13. package/dist/context/builder.js.map +1 -0
  14. package/dist/context/filter.d.ts +28 -0
  15. package/dist/context/filter.d.ts.map +1 -0
  16. package/dist/context/filter.js +136 -0
  17. package/dist/context/filter.js.map +1 -0
  18. package/dist/context/grounding.d.ts +27 -0
  19. package/dist/context/grounding.d.ts.map +1 -0
  20. package/dist/context/grounding.js +162 -0
  21. package/dist/context/grounding.js.map +1 -0
  22. package/dist/context/guards.d.ts +31 -0
  23. package/dist/context/guards.d.ts.map +1 -0
  24. package/dist/context/guards.js +76 -0
  25. package/dist/context/guards.js.map +1 -0
  26. package/dist/context/repo-hints.d.ts +12 -0
  27. package/dist/context/repo-hints.d.ts.map +1 -0
  28. package/dist/context/repo-hints.js +40 -0
  29. package/dist/context/repo-hints.js.map +1 -0
  30. package/dist/generation/gemini-client.d.ts +27 -0
  31. package/dist/generation/gemini-client.d.ts.map +1 -0
  32. package/dist/generation/gemini-client.js +64 -0
  33. package/dist/generation/gemini-client.js.map +1 -0
  34. package/dist/generation/litellm-client.d.ts +16 -0
  35. package/dist/generation/litellm-client.d.ts.map +1 -0
  36. package/dist/generation/litellm-client.js +98 -0
  37. package/dist/generation/litellm-client.js.map +1 -0
  38. package/dist/generation/remote-client.d.ts +20 -0
  39. package/dist/generation/remote-client.d.ts.map +1 -0
  40. package/dist/generation/remote-client.js +69 -0
  41. package/dist/generation/remote-client.js.map +1 -0
  42. package/dist/index.d.ts +9 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +30 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/output/file-writer.d.ts +39 -0
  47. package/dist/output/file-writer.d.ts.map +1 -0
  48. package/dist/output/file-writer.js +153 -0
  49. package/dist/output/file-writer.js.map +1 -0
  50. package/dist/output/formatter.d.ts +26 -0
  51. package/dist/output/formatter.d.ts.map +1 -0
  52. package/dist/output/formatter.js +156 -0
  53. package/dist/output/formatter.js.map +1 -0
  54. package/dist/server.d.ts +9 -0
  55. package/dist/server.d.ts.map +1 -0
  56. package/dist/server.js +22 -0
  57. package/dist/server.js.map +1 -0
  58. package/dist/stack/detect.d.ts +49 -0
  59. package/dist/stack/detect.d.ts.map +1 -0
  60. package/dist/stack/detect.js +157 -0
  61. package/dist/stack/detect.js.map +1 -0
  62. package/dist/tokens/sync.d.ts +32 -0
  63. package/dist/tokens/sync.d.ts.map +1 -0
  64. package/dist/tokens/sync.js +188 -0
  65. package/dist/tokens/sync.js.map +1 -0
  66. package/dist/tools/analyze-screenshot-ui.d.ts +18 -0
  67. package/dist/tools/analyze-screenshot-ui.d.ts.map +1 -0
  68. package/dist/tools/analyze-screenshot-ui.js +133 -0
  69. package/dist/tools/analyze-screenshot-ui.js.map +1 -0
  70. package/dist/tools/analyze-tokens.d.ts +10 -0
  71. package/dist/tools/analyze-tokens.d.ts.map +1 -0
  72. package/dist/tools/analyze-tokens.js +107 -0
  73. package/dist/tools/analyze-tokens.js.map +1 -0
  74. package/dist/tools/catalog-components.d.ts +14 -0
  75. package/dist/tools/catalog-components.d.ts.map +1 -0
  76. package/dist/tools/catalog-components.js +85 -0
  77. package/dist/tools/catalog-components.js.map +1 -0
  78. package/dist/tools/create-ui.d.ts +10 -0
  79. package/dist/tools/create-ui.d.ts.map +1 -0
  80. package/dist/tools/create-ui.js +167 -0
  81. package/dist/tools/create-ui.js.map +1 -0
  82. package/dist/tools/detect-ui-stack.d.ts +15 -0
  83. package/dist/tools/detect-ui-stack.d.ts.map +1 -0
  84. package/dist/tools/detect-ui-stack.js +52 -0
  85. package/dist/tools/detect-ui-stack.js.map +1 -0
  86. package/dist/tools/generate-component-variants.d.ts +15 -0
  87. package/dist/tools/generate-component-variants.d.ts.map +1 -0
  88. package/dist/tools/generate-component-variants.js +199 -0
  89. package/dist/tools/generate-component-variants.js.map +1 -0
  90. package/dist/tools/generate-vibes.d.ts +10 -0
  91. package/dist/tools/generate-vibes.d.ts.map +1 -0
  92. package/dist/tools/generate-vibes.js +145 -0
  93. package/dist/tools/generate-vibes.js.map +1 -0
  94. package/dist/tools/index.d.ts +12 -0
  95. package/dist/tools/index.d.ts.map +1 -0
  96. package/dist/tools/index.js +36 -0
  97. package/dist/tools/index.js.map +1 -0
  98. package/dist/tools/modify-ui.d.ts +11 -0
  99. package/dist/tools/modify-ui.d.ts.map +1 -0
  100. package/dist/tools/modify-ui.js +207 -0
  101. package/dist/tools/modify-ui.js.map +1 -0
  102. package/dist/tools/scaffold-project.d.ts +10 -0
  103. package/dist/tools/scaffold-project.d.ts.map +1 -0
  104. package/dist/tools/scaffold-project.js +122 -0
  105. package/dist/tools/scaffold-project.js.map +1 -0
  106. package/dist/tools/snippet-ui.d.ts +11 -0
  107. package/dist/tools/snippet-ui.d.ts.map +1 -0
  108. package/dist/tools/snippet-ui.js +194 -0
  109. package/dist/tools/snippet-ui.js.map +1 -0
  110. package/dist/tools/sync-design-tokens.d.ts +14 -0
  111. package/dist/tools/sync-design-tokens.d.ts.map +1 -0
  112. package/dist/tools/sync-design-tokens.js +233 -0
  113. package/dist/tools/sync-design-tokens.js.map +1 -0
  114. package/dist/utils/walk.d.ts +15 -0
  115. package/dist/utils/walk.d.ts.map +1 -0
  116. package/dist/utils/walk.js +63 -0
  117. package/dist/utils/walk.js.map +1 -0
  118. package/eslint.config.js +37 -0
  119. package/package.json +56 -0
  120. package/src/__tests__/builder.test.ts +31 -0
  121. package/src/__tests__/config.test.ts +52 -0
  122. package/src/__tests__/filter.test.ts +109 -0
  123. package/src/components/catalog.ts +214 -0
  124. package/src/config/index.ts +237 -0
  125. package/src/context/builder.ts +233 -0
  126. package/src/context/filter.ts +164 -0
  127. package/src/context/grounding.ts +191 -0
  128. package/src/context/guards.ts +94 -0
  129. package/src/context/repo-hints.ts +43 -0
  130. package/src/generation/gemini-client.ts +94 -0
  131. package/src/generation/litellm-client.ts +121 -0
  132. package/src/generation/remote-client.ts +103 -0
  133. package/src/index.ts +36 -0
  134. package/src/output/file-writer.ts +181 -0
  135. package/src/output/formatter.ts +186 -0
  136. package/src/server.ts +28 -0
  137. package/src/stack/detect.ts +204 -0
  138. package/src/tokens/sync.ts +212 -0
  139. package/src/tools/analyze-screenshot-ui.ts +150 -0
  140. package/src/tools/analyze-tokens.ts +123 -0
  141. package/src/tools/catalog-components.ts +99 -0
  142. package/src/tools/create-ui.ts +194 -0
  143. package/src/tools/detect-ui-stack.ts +64 -0
  144. package/src/tools/generate-component-variants.ts +218 -0
  145. package/src/tools/generate-vibes.ts +177 -0
  146. package/src/tools/index.ts +42 -0
  147. package/src/tools/modify-ui.ts +230 -0
  148. package/src/tools/scaffold-project.ts +138 -0
  149. package/src/tools/snippet-ui.ts +222 -0
  150. package/src/tools/sync-design-tokens.ts +256 -0
  151. package/src/utils/walk.ts +75 -0
  152. package/tsconfig.json +34 -0
  153. package/vitest.config.ts +15 -0
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Context Builder
3
+ *
4
+ * Builds token-optimized context from specified files.
5
+ * Filters out sensitive content and optimizes for relevance.
6
+ * Includes token counting for quota management.
7
+ */
8
+ import * as fs from 'node:fs';
9
+ import * as path from 'node:path';
10
+ import { isPathAllowed, isSensitiveFile, sanitizeContent } from './filter.js';
11
+ // Token estimation: ~4 characters per token for English text/code
12
+ const CHARS_PER_TOKEN = 4;
13
+ const MAX_CONTEXT_TOKENS = 12500; // ~50k chars
14
+ const MAX_FILE_TOKENS = 2500; // ~10k chars per file
15
+ /**
16
+ * Estimate token count from text
17
+ */
18
+ export function estimateTokens(text) {
19
+ return Math.ceil(text.length / CHARS_PER_TOKEN);
20
+ }
21
+ /**
22
+ * Build context from specified file paths with token optimization
23
+ */
24
+ export async function buildContext(paths, config) {
25
+ const result = await buildContextWithMetadata(paths, config);
26
+ return result.content;
27
+ }
28
+ /**
29
+ * Build context with full metadata (tokens, files included, etc.)
30
+ */
31
+ export async function buildContextWithMetadata(paths, config) {
32
+ const contents = [];
33
+ const filesIncluded = [];
34
+ const filesSkipped = [];
35
+ let totalTokens = 0;
36
+ let truncated = false;
37
+ // Sort paths by likely relevance (design tokens first, then components)
38
+ const sortedPaths = sortByRelevance(paths);
39
+ for (const filePath of sortedPaths) {
40
+ // Resolve to absolute path
41
+ const absPath = path.isAbsolute(filePath) ? filePath : path.resolve(process.cwd(), filePath);
42
+ // Security check: path must be in allowed paths
43
+ if (!isPathAllowed(absPath, config.allowedPaths)) {
44
+ if (config.debug) {
45
+ console.error(`[context] Skipping ${filePath}: outside allowed paths`);
46
+ }
47
+ filesSkipped.push(`${filePath} (outside allowed paths)`);
48
+ continue;
49
+ }
50
+ // Security check: not a sensitive file
51
+ if (isSensitiveFile(absPath)) {
52
+ if (config.debug) {
53
+ console.error(`[context] Skipping ${filePath}: sensitive file`);
54
+ }
55
+ filesSkipped.push(`${filePath} (sensitive)`);
56
+ continue;
57
+ }
58
+ // Check if file exists and is a file
59
+ if (!fs.existsSync(absPath)) {
60
+ filesSkipped.push(`${filePath} (not found)`);
61
+ continue;
62
+ }
63
+ const stat = fs.statSync(absPath);
64
+ if (!stat.isFile()) {
65
+ filesSkipped.push(`${filePath} (not a file)`);
66
+ continue;
67
+ }
68
+ try {
69
+ let content = fs.readFileSync(absPath, 'utf-8');
70
+ // Sanitize content to remove any secrets
71
+ content = sanitizeContent(content);
72
+ // Calculate tokens for this file
73
+ let fileTokens = estimateTokens(content);
74
+ const maxFileChars = MAX_FILE_TOKENS * CHARS_PER_TOKEN;
75
+ // Truncate large files
76
+ if (fileTokens > MAX_FILE_TOKENS) {
77
+ content = smartTruncate(content, maxFileChars);
78
+ fileTokens = MAX_FILE_TOKENS;
79
+ }
80
+ // Check if adding this would exceed total limit
81
+ if (totalTokens + fileTokens > MAX_CONTEXT_TOKENS) {
82
+ if (config.debug) {
83
+ console.error(`[context] Stopping: token limit reached`);
84
+ }
85
+ truncated = true;
86
+ break;
87
+ }
88
+ const ext = path.extname(absPath);
89
+ const header = `/* File: ${path.basename(absPath)} (${ext}) - ~${fileTokens} tokens */`;
90
+ contents.push(`${header}\n${content}`);
91
+ filesIncluded.push(filePath);
92
+ totalTokens += fileTokens;
93
+ }
94
+ catch (error) {
95
+ if (config.debug) {
96
+ console.error(`[context] Error reading ${filePath}:`, error);
97
+ }
98
+ filesSkipped.push(`${filePath} (read error)`);
99
+ }
100
+ }
101
+ return {
102
+ content: contents.length > 0 ? contents.join('\n\n---\n\n') : '',
103
+ estimatedTokens: totalTokens,
104
+ filesIncluded,
105
+ filesSkipped,
106
+ truncated,
107
+ };
108
+ }
109
+ /**
110
+ * Sort paths by relevance (design tokens and variables first)
111
+ */
112
+ function sortByRelevance(paths) {
113
+ const priority = {
114
+ tokens: 0,
115
+ variables: 0,
116
+ theme: 1,
117
+ design: 1,
118
+ colors: 2,
119
+ typography: 2,
120
+ styles: 3,
121
+ css: 4,
122
+ };
123
+ return [...paths].sort((a, b) => {
124
+ const aName = path.basename(a).toLowerCase();
125
+ const bName = path.basename(b).toLowerCase();
126
+ let aPriority = 10;
127
+ let bPriority = 10;
128
+ for (const [key, value] of Object.entries(priority)) {
129
+ if (aName.includes(key))
130
+ aPriority = Math.min(aPriority, value);
131
+ if (bName.includes(key))
132
+ bPriority = Math.min(bPriority, value);
133
+ }
134
+ return aPriority - bPriority;
135
+ });
136
+ }
137
+ /**
138
+ * Smart truncate: keep beginning and end, with clear indicator
139
+ */
140
+ function smartTruncate(content, maxChars) {
141
+ if (content.length <= maxChars)
142
+ return content;
143
+ const keepStart = Math.floor(maxChars * 0.7);
144
+ const keepEnd = Math.floor(maxChars * 0.2);
145
+ const start = content.slice(0, keepStart);
146
+ const end = content.slice(-keepEnd);
147
+ return `${start}\n\n/* ... [${Math.round((content.length - maxChars) / 1000)}k chars truncated] ... */\n\n${end}`;
148
+ }
149
+ /**
150
+ * Automatically discover relevant UI files in a directory
151
+ */
152
+ export async function discoverUIFiles(directory, config) {
153
+ const uiPatterns = [
154
+ /\.(css|scss|less|sass)$/,
155
+ /\.(tsx|jsx)$/,
156
+ /\.(vue|svelte)$/,
157
+ /theme\./,
158
+ /design[-_]?tokens?\./,
159
+ /tailwind\.config\./,
160
+ ];
161
+ const files = [];
162
+ function scan(dir, depth = 0) {
163
+ if (depth > 3)
164
+ return; // Max depth
165
+ try {
166
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
167
+ for (const entry of entries) {
168
+ const fullPath = path.join(dir, entry.name);
169
+ // Skip node_modules, .git, etc.
170
+ if (entry.isDirectory()) {
171
+ if (['node_modules', '.git', 'dist', 'build', '.next', '.nuxt'].includes(entry.name)) {
172
+ continue;
173
+ }
174
+ scan(fullPath, depth + 1);
175
+ }
176
+ else if (entry.isFile()) {
177
+ // Check if matches UI patterns
178
+ if (uiPatterns.some((pattern) => pattern.test(entry.name))) {
179
+ if (isPathAllowed(fullPath, config.allowedPaths) && !isSensitiveFile(fullPath)) {
180
+ files.push(fullPath);
181
+ }
182
+ }
183
+ }
184
+ }
185
+ }
186
+ catch {
187
+ // Skip directories we can't read
188
+ }
189
+ }
190
+ scan(directory);
191
+ // Sort by relevance
192
+ return sortByRelevance(files);
193
+ }
194
+ //# sourceMappingURL=builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.js","sourceRoot":"","sources":["../../src/context/builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Context Filter
3
+ *
4
+ * Security patterns to prevent sensitive data from being shared.
5
+ * Ensures only UI-relevant files are included in context.
6
+ */
7
+ /**
8
+ * UI-relevant file patterns (for auto-discovery)
9
+ */
10
+ export declare const UI_INCLUDE_PATTERNS: RegExp[];
11
+ /**
12
+ * Check if a file path matches sensitive patterns
13
+ */
14
+ export declare function isSensitiveFile(filePath: string): boolean;
15
+ /**
16
+ * Check if a file path is within allowed paths
17
+ */
18
+ export declare function isPathAllowed(filePath: string, allowedPaths: string[]): boolean;
19
+ /**
20
+ * Check if a file is UI-relevant
21
+ */
22
+ export declare function isUIRelevant(filePath: string): boolean;
23
+ /**
24
+ * Sanitize file content to remove potential secrets
25
+ * This is a best-effort filter for dynamic content
26
+ */
27
+ export declare function sanitizeContent(content: string): string;
28
+ //# sourceMappingURL=filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/context/filter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2DH;;GAEG;AACH,eAAO,MAAM,mBAAmB,UAkB/B,CAAC;AAEF;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAUzD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAW/E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAUtD;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA0BvD"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Context Filter
3
+ *
4
+ * Security patterns to prevent sensitive data from being shared.
5
+ * Ensures only UI-relevant files are included in context.
6
+ */
7
+ import * as path from 'node:path';
8
+ /**
9
+ * Files/directories that should NEVER be included in context
10
+ */
11
+ const SENSITIVE_PATTERNS = [
12
+ // Environment and secrets
13
+ /\.env/i,
14
+ /secrets?\./i,
15
+ /\.pem$/i,
16
+ /\.key$/i,
17
+ /\.crt$/i,
18
+ /credentials/i,
19
+ /\.htpasswd/i,
20
+ // Private keys and certificates
21
+ /id_rsa/i,
22
+ /id_ed25519/i,
23
+ /\.p12$/i,
24
+ /\.pfx$/i,
25
+ // Config with potential secrets
26
+ /\.npmrc$/i,
27
+ /\.pypirc$/i,
28
+ /kubeconfig/i,
29
+ /\.docker\/config\.json$/i,
30
+ // Database
31
+ /\.sqlite$/i,
32
+ /\.db$/i,
33
+ /migrations?\//i,
34
+ /seeds?\//i,
35
+ // Backend/server code (when isolating UI)
36
+ /\/api\//i,
37
+ /\/server\//i,
38
+ /\/backend\//i,
39
+ /\/functions\//i, // Serverless
40
+ /\/lambda\//i,
41
+ /\/middleware\//i,
42
+ // Auth-related
43
+ /\/auth\//i,
44
+ /passport/i,
45
+ /jwt/i,
46
+ // System and dependencies
47
+ /node_modules\//i,
48
+ /\.git\//i,
49
+ /vendor\//i,
50
+ /\.cache\//i,
51
+ /\.next\//i,
52
+ /\.nuxt\//i,
53
+ /dist\//i,
54
+ /build\//i,
55
+ ];
56
+ /**
57
+ * UI-relevant file patterns (for auto-discovery)
58
+ */
59
+ export const UI_INCLUDE_PATTERNS = [
60
+ // Stylesheets
61
+ /\.(css|scss|less|sass|styl)$/i,
62
+ // Components
63
+ /\.(tsx|jsx)$/i,
64
+ /\.(vue|svelte)$/i,
65
+ // Design tokens
66
+ /theme\./i,
67
+ /tokens?\./i,
68
+ /variables\./i,
69
+ /design[-_]?system/i,
70
+ // Config files for styling
71
+ /tailwind\.config/i,
72
+ /postcss\.config/i,
73
+ /styled-components/i,
74
+ ];
75
+ /**
76
+ * Check if a file path matches sensitive patterns
77
+ */
78
+ export function isSensitiveFile(filePath) {
79
+ const normalized = filePath.replace(/\\/g, '/');
80
+ for (const pattern of SENSITIVE_PATTERNS) {
81
+ if (pattern.test(normalized)) {
82
+ return true;
83
+ }
84
+ }
85
+ return false;
86
+ }
87
+ /**
88
+ * Check if a file path is within allowed paths
89
+ */
90
+ export function isPathAllowed(filePath, allowedPaths) {
91
+ const absPath = path.resolve(filePath);
92
+ for (const allowed of allowedPaths) {
93
+ const absAllowed = path.resolve(allowed);
94
+ if (absPath.startsWith(absAllowed)) {
95
+ return true;
96
+ }
97
+ }
98
+ return false;
99
+ }
100
+ /**
101
+ * Check if a file is UI-relevant
102
+ */
103
+ export function isUIRelevant(filePath) {
104
+ const normalized = filePath.replace(/\\/g, '/');
105
+ for (const pattern of UI_INCLUDE_PATTERNS) {
106
+ if (pattern.test(normalized)) {
107
+ return true;
108
+ }
109
+ }
110
+ return false;
111
+ }
112
+ /**
113
+ * Sanitize file content to remove potential secrets
114
+ * This is a best-effort filter for dynamic content
115
+ */
116
+ export function sanitizeContent(content) {
117
+ // Remove common secret patterns
118
+ const patterns = [
119
+ // API keys (generic patterns)
120
+ /(['"`])?(api[_-]?key|apikey|secret|password|token|auth)(['"`])?[\s]*[:=][\s]*['"`][^'"`]+['"`]/gi,
121
+ // Bearer tokens
122
+ /Bearer\s+[A-Za-z0-9\-_=]+\.[A-Za-z0-9\-_=]+\.?[A-Za-z0-9\-_.+/=]*/gi,
123
+ // AWS keys
124
+ /AKIA[0-9A-Z]{16}/g,
125
+ // Private keys
126
+ /-----BEGIN[\s\w]+PRIVATE KEY-----[\s\S]+?-----END[\s\w]+PRIVATE KEY-----/g,
127
+ // Connection strings
128
+ /(mongodb|postgresql|mysql|redis):\/\/[^\s'"]+/gi,
129
+ ];
130
+ let result = content;
131
+ for (const pattern of patterns) {
132
+ result = result.replace(pattern, '[REDACTED]');
133
+ }
134
+ return result;
135
+ }
136
+ //# sourceMappingURL=filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.js","sourceRoot":"","sources":["../../src/context/filter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * grounding.ts
3
+ *
4
+ * Deterministic “repo grounding” injected into prompts to improve output quality
5
+ * without burning large context windows.
6
+ *
7
+ * This module is used internally by tools like modify_ui and
8
+ * generate_component_variants to:
9
+ * - auto-detect the UI stack (framework/styling/libs)
10
+ * - catalog available components for reuse
11
+ *
12
+ * The output is intentionally concise and stable.
13
+ */
14
+ import { Config } from '../config/index.js';
15
+ export interface RepoGroundingOptions {
16
+ focusFileAbs?: string;
17
+ instruction?: string;
18
+ maxComponents?: number;
19
+ }
20
+ /**
21
+ * Build a concise deterministic “grounding” string.
22
+ *
23
+ * This is safe to include in prompts because it contains only local, deterministic
24
+ * project metadata (no secrets).
25
+ */
26
+ export declare function buildRepoGrounding(config: Config, options?: RepoGroundingOptions): Promise<string>;
27
+ //# sourceMappingURL=grounding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grounding.d.ts","sourceRoot":"","sources":["../../src/context/grounding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AA+H5C,MAAM,WAAW,oBAAoB;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoC5G"}
@@ -0,0 +1,162 @@
1
+ /**
2
+ * grounding.ts
3
+ *
4
+ * Deterministic “repo grounding” injected into prompts to improve output quality
5
+ * without burning large context windows.
6
+ *
7
+ * This module is used internally by tools like modify_ui and
8
+ * generate_component_variants to:
9
+ * - auto-detect the UI stack (framework/styling/libs)
10
+ * - catalog available components for reuse
11
+ *
12
+ * The output is intentionally concise and stable.
13
+ */
14
+ import * as path from 'node:path';
15
+ import { detectUiStack } from '../stack/detect.js';
16
+ import { walkFiles, toPosixPath } from '../utils/walk.js';
17
+ import { buildComponentCatalog } from '../components/catalog.js';
18
+ const CACHE_TTL_MS = 60_000;
19
+ const cache = new Map();
20
+ function resolveRootForFile(absFile, config) {
21
+ const allowed = (config.allowedPaths || []).map((p) => path.resolve(p));
22
+ const fallback = allowed[0] || process.cwd();
23
+ if (!absFile)
24
+ return fallback;
25
+ const abs = path.resolve(absFile);
26
+ // pick the deepest allowed root that contains the file
27
+ const matches = allowed
28
+ .filter((root) => abs === root || abs.startsWith(root + path.sep))
29
+ .sort((a, b) => b.length - a.length);
30
+ return matches[0] || fallback;
31
+ }
32
+ function summarizeStack(stack) {
33
+ const summary = {
34
+ framework: stack.framework,
35
+ typescript: stack.language.typescript,
36
+ styling: stack.styling,
37
+ uiLibraries: stack.uiLibraries,
38
+ iconLibraries: stack.iconLibraries,
39
+ tooling: stack.tooling,
40
+ conventions: {
41
+ srcDir: stack.conventions.srcDir,
42
+ hasAppDir: stack.conventions.hasAppDir,
43
+ hasPagesDir: stack.conventions.hasPagesDir,
44
+ tsconfigPaths: stack.conventions.tsconfigPaths ? Object.keys(stack.conventions.tsconfigPaths) : undefined,
45
+ },
46
+ files: {
47
+ tailwindConfig: stack.files.tailwindConfig,
48
+ componentsJson: stack.files.componentsJson,
49
+ storybookDir: stack.files.storybookDir,
50
+ },
51
+ warnings: stack.warnings,
52
+ };
53
+ return JSON.stringify(summary, null, 2);
54
+ }
55
+ function tokenizeInstruction(instruction) {
56
+ const set = new Set();
57
+ if (!instruction)
58
+ return set;
59
+ const tokens = instruction.match(/[A-Za-z_][A-Za-z0-9_]*/g) || [];
60
+ for (const t of tokens)
61
+ set.add(t.toLowerCase());
62
+ return set;
63
+ }
64
+ function scoreComponent(c, focusDirRel, instructionTokens) {
65
+ let score = 0;
66
+ // Mentioned explicitly in instruction
67
+ if (instructionTokens.has(c.name.toLowerCase()))
68
+ score += 8;
69
+ // Same directory as focused file
70
+ if (focusDirRel && c.file.startsWith(focusDirRel + '/'))
71
+ score += 6;
72
+ // Common reusable directories
73
+ if (c.file.includes('/components/') ||
74
+ c.file.startsWith('components/') ||
75
+ c.file.includes('/ui/') ||
76
+ c.file.includes('/shared/')) {
77
+ score += 3;
78
+ }
79
+ // Prefer TSX
80
+ if (c.file.endsWith('.tsx'))
81
+ score += 1;
82
+ return score;
83
+ }
84
+ function formatCatalogSubset(catalog, subset) {
85
+ const lines = [];
86
+ const header = `scanned_files=${catalog.filesScanned}, total_exports=${catalog.components.length}`;
87
+ lines.push(header);
88
+ if (catalog.warnings.length) {
89
+ lines.push(`warnings: ${catalog.warnings.join(' | ')}`);
90
+ }
91
+ lines.push('');
92
+ lines.push('components:');
93
+ for (const c of subset) {
94
+ const extras = [];
95
+ if (c.exportType)
96
+ extras.push(c.exportType);
97
+ if (c.propsType)
98
+ extras.push(`props: ${c.propsType}`);
99
+ if (c.jsDoc)
100
+ extras.push(`doc: ${c.jsDoc}`);
101
+ const extra = extras.length ? ` (${extras.join(', ')})` : '';
102
+ lines.push(`- ${c.name} — ${c.file}${extra}`);
103
+ }
104
+ return lines.join('\n');
105
+ }
106
+ async function getOrBuildRepoData(root) {
107
+ const now = Date.now();
108
+ const hit = cache.get(root);
109
+ if (hit && now - hit.ts < CACHE_TTL_MS)
110
+ return hit;
111
+ const stack = detectUiStack(root);
112
+ const files = walkFiles(root, {
113
+ includeExtensions: ['.tsx', '.jsx'],
114
+ maxFiles: 5000,
115
+ });
116
+ const catalog = await buildComponentCatalog(root, files);
117
+ const fresh = { ts: now, stack, catalog };
118
+ cache.set(root, fresh);
119
+ return fresh;
120
+ }
121
+ /**
122
+ * Build a concise deterministic “grounding” string.
123
+ *
124
+ * This is safe to include in prompts because it contains only local, deterministic
125
+ * project metadata (no secrets).
126
+ */
127
+ export async function buildRepoGrounding(config, options = {}) {
128
+ const maxComponents = typeof options.maxComponents === 'number' ? options.maxComponents : 120;
129
+ const root = resolveRootForFile(options.focusFileAbs ? path.resolve(options.focusFileAbs) : null, config);
130
+ const data = await getOrBuildRepoData(root);
131
+ const focusRel = options.focusFileAbs ? toPosixPath(path.relative(root, path.resolve(options.focusFileAbs))) : null;
132
+ const focusDirRel = focusRel ? toPosixPath(path.posix.dirname(focusRel)) : null;
133
+ const instructionTokens = tokenizeInstruction(options.instruction);
134
+ // Score and select a small subset for reuse.
135
+ const scored = data.catalog.components
136
+ .map((c) => ({ c, s: scoreComponent(c, focusDirRel, instructionTokens) }))
137
+ .sort((a, b) => b.s - a.s);
138
+ const subset = [];
139
+ const seen = new Set();
140
+ for (const item of scored) {
141
+ if (subset.length >= maxComponents)
142
+ break;
143
+ const key = `${item.c.name}|${item.c.file}|${item.c.exportType}`;
144
+ if (seen.has(key))
145
+ continue;
146
+ // Skip ultra-low relevance if we already have enough
147
+ if (subset.length > 30 && item.s <= 0)
148
+ break;
149
+ subset.push(item.c);
150
+ seen.add(key);
151
+ }
152
+ return [
153
+ 'AUTO PROJECT CONTEXT (deterministic):',
154
+ '',
155
+ 'STACK (json):',
156
+ summarizeStack(data.stack),
157
+ '',
158
+ 'COMPONENT CATALOG (subset for reuse):',
159
+ formatCatalogSubset(data.catalog, subset),
160
+ ].join('\n');
161
+ }
162
+ //# sourceMappingURL=grounding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grounding.js","sourceRoot":"","sources":["../../src/context/grounding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Path Guards
3
+ *
4
+ * Centralized helpers to validate and resolve file paths for tools.
5
+ *
6
+ * Goals:
7
+ * - Prevent accidental reads/writes outside the workspace
8
+ * - Avoid including sensitive files (e.g. .env, private keys)
9
+ * - Provide consistent absolute-path resolution
10
+ */
11
+ import { Config } from '../config/index.js';
12
+ /**
13
+ * Resolve a path to an absolute path (relative paths are resolved from process.cwd()).
14
+ */
15
+ export declare function resolveToAbs(filePath: string): string;
16
+ /**
17
+ * Validate that a path is safe to read according to server config.
18
+ * Returns the resolved absolute path.
19
+ */
20
+ export declare function assertReadablePath(filePath: string, config: Config): string;
21
+ /**
22
+ * Validate that a path is safe to write according to server config.
23
+ * Returns the resolved absolute path.
24
+ */
25
+ export declare function assertWritablePath(filePath: string, config: Config): string;
26
+ /**
27
+ * Validate that a directory path is safe to read according to server config.
28
+ * Returns the resolved absolute path.
29
+ */
30
+ export declare function assertReadableDir(dirPath: string, config: Config): string;
31
+ //# sourceMappingURL=guards.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../../src/context/guards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAG5C;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAqB3E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAY3E;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAqBzE"}