@metabob/minibob 0.1.2

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 (174) hide show
  1. package/ARCHITECTURE.md +255 -0
  2. package/CHANGELOG.md +112 -0
  3. package/README.md +380 -0
  4. package/bin/minibob.js +36 -0
  5. package/dist/acp-gossip.d.ts +72 -0
  6. package/dist/acp-gossip.d.ts.map +1 -0
  7. package/dist/acp-gossip.js +156 -0
  8. package/dist/acp-gossip.js.map +1 -0
  9. package/dist/acp.d.ts +62 -0
  10. package/dist/acp.d.ts.map +1 -0
  11. package/dist/acp.js +292 -0
  12. package/dist/acp.js.map +1 -0
  13. package/dist/activity.d.ts +157 -0
  14. package/dist/activity.d.ts.map +1 -0
  15. package/dist/activity.js +518 -0
  16. package/dist/activity.js.map +1 -0
  17. package/dist/agent-runtime.d.ts +104 -0
  18. package/dist/agent-runtime.d.ts.map +1 -0
  19. package/dist/boredom.d.ts +125 -0
  20. package/dist/boredom.d.ts.map +1 -0
  21. package/dist/boredom.js +244 -0
  22. package/dist/boredom.js.map +1 -0
  23. package/dist/cli/acp-server.d.ts +23 -0
  24. package/dist/cli/acp-server.d.ts.map +1 -0
  25. package/dist/cli/burrow.d.ts +26 -0
  26. package/dist/cli/burrow.d.ts.map +1 -0
  27. package/dist/cli/doctor.d.ts +22 -0
  28. package/dist/cli/doctor.d.ts.map +1 -0
  29. package/dist/cli/goal.d.ts +22 -0
  30. package/dist/cli/goal.d.ts.map +1 -0
  31. package/dist/cli/index.d.ts +47 -0
  32. package/dist/cli/index.d.ts.map +1 -0
  33. package/dist/cli/instance-registry.d.ts +78 -0
  34. package/dist/cli/instance-registry.d.ts.map +1 -0
  35. package/dist/cli/observe.d.ts +35 -0
  36. package/dist/cli/observe.d.ts.map +1 -0
  37. package/dist/cli/vessel.d.ts +14 -0
  38. package/dist/cli/vessel.d.ts.map +1 -0
  39. package/dist/composition-observer.d.ts +96 -0
  40. package/dist/composition-observer.d.ts.map +1 -0
  41. package/dist/config.d.ts +36 -0
  42. package/dist/config.d.ts.map +1 -0
  43. package/dist/config.js +128 -0
  44. package/dist/config.js.map +1 -0
  45. package/dist/docker/Dockerfile +35 -0
  46. package/dist/environment.d.ts +72 -0
  47. package/dist/environment.d.ts.map +1 -0
  48. package/dist/environment.js +142 -0
  49. package/dist/environment.js.map +1 -0
  50. package/dist/goal-processor.d.ts +165 -0
  51. package/dist/goal-processor.d.ts.map +1 -0
  52. package/dist/helm/minibob-cluster/Chart.yaml +13 -0
  53. package/dist/helm/minibob-cluster/templates/_helpers.tpl +60 -0
  54. package/dist/helm/minibob-cluster/templates/configmap.yaml +11 -0
  55. package/dist/helm/minibob-cluster/templates/deployment.yaml +108 -0
  56. package/dist/helm/minibob-cluster/templates/secret.yaml +10 -0
  57. package/dist/helm/minibob-cluster/templates/service.yaml +37 -0
  58. package/dist/helm/minibob-cluster/values-local.yaml +41 -0
  59. package/dist/helm/minibob-cluster/values-production.yaml +57 -0
  60. package/dist/helm/minibob-cluster/values-testing-cluster.yaml +43 -0
  61. package/dist/helm/minibob-cluster/values.yaml +127 -0
  62. package/dist/improviser.d.ts +74 -0
  63. package/dist/improviser.d.ts.map +1 -0
  64. package/dist/impulse-filter.d.ts +74 -0
  65. package/dist/impulse-filter.d.ts.map +1 -0
  66. package/dist/impulse.d.ts +92 -0
  67. package/dist/impulse.d.ts.map +1 -0
  68. package/dist/impulse.js +234 -0
  69. package/dist/impulse.js.map +1 -0
  70. package/dist/lib.d.ts +29 -0
  71. package/dist/lib.d.ts.map +1 -0
  72. package/dist/lib.js +18561 -0
  73. package/dist/lib.js.map +98 -0
  74. package/dist/lifecycle-hooks.d.ts +99 -0
  75. package/dist/lifecycle-hooks.d.ts.map +1 -0
  76. package/dist/lifecycle-hooks.js +135 -0
  77. package/dist/lifecycle-hooks.js.map +1 -0
  78. package/dist/llm.d.ts +31 -0
  79. package/dist/llm.d.ts.map +1 -0
  80. package/dist/llm.js +349 -0
  81. package/dist/llm.js.map +1 -0
  82. package/dist/mcp-activity-bridge.d.ts +66 -0
  83. package/dist/mcp-activity-bridge.d.ts.map +1 -0
  84. package/dist/mcp-activity-bridge.js +126 -0
  85. package/dist/mcp-activity-bridge.js.map +1 -0
  86. package/dist/mcp.d.ts +216 -0
  87. package/dist/mcp.d.ts.map +1 -0
  88. package/dist/mcp.js +292 -0
  89. package/dist/mcp.js.map +1 -0
  90. package/dist/memory-agent.d.ts +92 -0
  91. package/dist/memory-agent.d.ts.map +1 -0
  92. package/dist/memory-agent.js +277 -0
  93. package/dist/memory-agent.js.map +1 -0
  94. package/dist/runtime-mapping.d.ts +97 -0
  95. package/dist/runtime-mapping.d.ts.map +1 -0
  96. package/dist/search-first-executor.d.ts +113 -0
  97. package/dist/search-first-executor.d.ts.map +1 -0
  98. package/dist/session.d.ts +48 -0
  99. package/dist/session.d.ts.map +1 -0
  100. package/dist/template-extractor.d.ts +9 -0
  101. package/dist/template-extractor.d.ts.map +1 -0
  102. package/dist/template-generator.d.ts +12 -0
  103. package/dist/template-generator.d.ts.map +1 -0
  104. package/dist/tools.d.ts +58 -0
  105. package/dist/tools.d.ts.map +1 -0
  106. package/dist/tools.js +771 -0
  107. package/dist/tools.js.map +1 -0
  108. package/dist/types.d.ts +503 -0
  109. package/dist/types.d.ts.map +1 -0
  110. package/dist/types.js +8 -0
  111. package/dist/types.js.map +1 -0
  112. package/dist/understanding/analyzer.d.ts +55 -0
  113. package/dist/understanding/analyzer.d.ts.map +1 -0
  114. package/dist/understanding/explorer.d.ts +73 -0
  115. package/dist/understanding/explorer.d.ts.map +1 -0
  116. package/dist/understanding/index.d.ts +7 -0
  117. package/dist/understanding/index.d.ts.map +1 -0
  118. package/dist/understanding/types.d.ts +136 -0
  119. package/dist/understanding/types.d.ts.map +1 -0
  120. package/dist/validation.d.ts +29 -0
  121. package/dist/validation.d.ts.map +1 -0
  122. package/dist/validation.js +106 -0
  123. package/dist/validation.js.map +1 -0
  124. package/dist/vessel-bootstrap.d.ts +190 -0
  125. package/dist/vessel-bootstrap.d.ts.map +1 -0
  126. package/dist/vessel-registry.d.ts +229 -0
  127. package/dist/vessel-registry.d.ts.map +1 -0
  128. package/index.ts +1329 -0
  129. package/package.json +54 -0
  130. package/src/acp-gossip.ts +193 -0
  131. package/src/acp.ts +362 -0
  132. package/src/activity.ts +1464 -0
  133. package/src/agent-runtime.ts +365 -0
  134. package/src/boredom.ts +423 -0
  135. package/src/cli/acp-server.ts +377 -0
  136. package/src/cli/burrow.ts +896 -0
  137. package/src/cli/doctor.ts +526 -0
  138. package/src/cli/goal.ts +224 -0
  139. package/src/cli/index.ts +147 -0
  140. package/src/cli/instance-registry.ts +271 -0
  141. package/src/cli/observe.ts +682 -0
  142. package/src/cli/vessel.ts +287 -0
  143. package/src/components/SystemOverview.tsx +331 -0
  144. package/src/composition-observer.ts +449 -0
  145. package/src/config.ts +172 -0
  146. package/src/environment.ts +167 -0
  147. package/src/goal-processor.ts +654 -0
  148. package/src/improviser.ts +591 -0
  149. package/src/impulse-filter.ts +273 -0
  150. package/src/impulse.ts +311 -0
  151. package/src/lib.ts +147 -0
  152. package/src/lifecycle-hooks.ts +181 -0
  153. package/src/llm.ts +434 -0
  154. package/src/mcp-activity-bridge.ts +158 -0
  155. package/src/mcp.ts +747 -0
  156. package/src/memory-agent.ts +316 -0
  157. package/src/runtime-mapping.ts +527 -0
  158. package/src/search-first-executor.ts +666 -0
  159. package/src/session.ts +141 -0
  160. package/src/template-extractor.ts +256 -0
  161. package/src/template-generator.ts +130 -0
  162. package/src/tools.ts +924 -0
  163. package/src/types.ts +497 -0
  164. package/src/understanding/analyzer.ts +354 -0
  165. package/src/understanding/explorer.ts +488 -0
  166. package/src/understanding/index.ts +27 -0
  167. package/src/understanding/types.ts +153 -0
  168. package/src/validation.ts +125 -0
  169. package/src/vessel-bootstrap.ts +440 -0
  170. package/src/vessel-registry.ts +621 -0
  171. package/templates/core/edit-file.json +85 -0
  172. package/templates/understanding/diagnose-problem.json +32 -0
  173. package/templates/understanding/explore-codebase-v2.json +57 -0
  174. package/templates/understanding/explore-codebase.json +37 -0
@@ -0,0 +1,488 @@
1
+ /**
2
+ * CodeExplorer - Fast static analysis of codebase structure
3
+ *
4
+ * Uses Bun file APIs to analyze code without LLM calls.
5
+ * Provides foundation for semantic understanding.
6
+ */
7
+
8
+ import type {
9
+ CodeStructure,
10
+ DirectoryNode,
11
+ Dependencies,
12
+ FileAnalysis,
13
+ Import,
14
+ Export,
15
+ FunctionDeclaration,
16
+ Component
17
+ } from './types'
18
+
19
+ export class CodeExplorer {
20
+ private ignorePatterns: string[] = [
21
+ 'node_modules',
22
+ '.git',
23
+ 'dist',
24
+ 'build',
25
+ '.next',
26
+ '.cache',
27
+ 'coverage',
28
+ '.DS_Store',
29
+ '*.log',
30
+ '.env',
31
+ '.env.local',
32
+ 'bun.lockb',
33
+ 'package-lock.json',
34
+ 'yarn.lock'
35
+ ]
36
+
37
+ constructor(
38
+ private workingDir: string = process.cwd(),
39
+ additionalIgnore?: string[]
40
+ ) {
41
+ if (additionalIgnore) {
42
+ this.ignorePatterns.push(...additionalIgnore)
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Safe wrapper for Bun.file() with better error handling
48
+ */
49
+ private safeReadFile(path: string): ReturnType<typeof Bun.file> {
50
+ if (!path || typeof path !== 'string') {
51
+ throw new Error(`Invalid file path: expected string, got ${typeof path}`)
52
+ }
53
+ try {
54
+ return Bun.file(path)
55
+ } catch (error) {
56
+ throw new Error(`Failed to create file handle for '${path}': ${error instanceof Error ? error.message : String(error)}`)
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Explore codebase and return comprehensive structure
62
+ */
63
+ async explore(rootPath: string): Promise<CodeStructure> {
64
+ const absolutePath = this.resolvePath(rootPath)
65
+ const files = await this.listAllFiles(absolutePath)
66
+
67
+ const filesByType = this.groupByExtension(files)
68
+ const dependencies = await this.extractDependencies(absolutePath, files)
69
+ const entryPoints = await this.findEntryPoints(absolutePath, files)
70
+ const { totalSize, totalLoc } = await this.calculateCodebaseSize(absolutePath, files)
71
+ const directoryStructure = await this.analyzeDirectoryStructure(absolutePath)
72
+
73
+ return {
74
+ totalFiles: files.length,
75
+ filesByType,
76
+ directoryStructure,
77
+ dependencies,
78
+ entryPoints,
79
+ totalSize,
80
+ totalLoc
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Analyze specific file in detail
86
+ */
87
+ async analyzeFile(filePath: string): Promise<FileAnalysis> {
88
+ const absolutePath = this.resolvePath(filePath)
89
+ const bunFile = this.safeReadFile(absolutePath)
90
+ const content = await bunFile.text()
91
+ const size = await bunFile.size
92
+
93
+ return {
94
+ path: filePath,
95
+ imports: this.extractImports(content),
96
+ exports: this.extractExports(content),
97
+ functions: this.extractFunctions(content),
98
+ components: this.extractReactComponents(content),
99
+ loc: content.split('\n').length,
100
+ size
101
+ }
102
+ }
103
+
104
+ /**
105
+ * List all files in directory (non-ignored)
106
+ */
107
+ private async listAllFiles(rootPath: string): Promise<string[]> {
108
+ const glob = new Bun.Glob("**/*")
109
+ const files: string[] = []
110
+
111
+ for await (const file of glob.scan({ cwd: rootPath })) {
112
+ if (!this.shouldIgnore(file)) {
113
+ files.push(file)
114
+ }
115
+ }
116
+
117
+ return files
118
+ }
119
+
120
+ /**
121
+ * Check if file should be ignored
122
+ */
123
+ private shouldIgnore(path: string): boolean {
124
+ return this.ignorePatterns.some(pattern => {
125
+ // Simple pattern matching (could be enhanced with minimatch)
126
+ if (pattern.includes('*')) {
127
+ const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$')
128
+ return regex.test(path)
129
+ }
130
+ return path.includes(pattern)
131
+ })
132
+ }
133
+
134
+ /**
135
+ * Group files by extension
136
+ */
137
+ private groupByExtension(files: string[]): Record<string, number> {
138
+ const groups: Record<string, number> = {}
139
+
140
+ for (const file of files) {
141
+ const ext = file.split('.').pop() || 'unknown'
142
+ groups[ext] = (groups[ext] || 0) + 1
143
+ }
144
+
145
+ return groups
146
+ }
147
+
148
+ /**
149
+ * Extract dependencies from package.json files
150
+ */
151
+ private async extractDependencies(rootPath: string, files: string[]): Promise<Dependencies> {
152
+ const packageJsons = files.filter(f => f === 'package.json' || f.endsWith('/package.json'))
153
+ const dependencies: Dependencies = {
154
+ runtime: {},
155
+ dev: {},
156
+ frameworks: [],
157
+ internal: []
158
+ }
159
+
160
+ for (const pkgPath of packageJsons) {
161
+ try {
162
+ const content = await this.safeReadFile(`${rootPath}/${pkgPath}`).text()
163
+ const pkg = JSON.parse(content)
164
+
165
+ // Extract runtime dependencies
166
+ if (pkg.dependencies) {
167
+ Object.assign(dependencies.runtime, pkg.dependencies)
168
+ }
169
+
170
+ // Extract dev dependencies
171
+ if (pkg.devDependencies) {
172
+ Object.assign(dependencies.dev, pkg.devDependencies)
173
+ }
174
+
175
+ // Identify common frameworks
176
+ if (pkg.dependencies?.['react'] || pkg.devDependencies?.['react']) {
177
+ dependencies.frameworks.push('React')
178
+ }
179
+ if (pkg.dependencies?.['@hono/hono'] || pkg.dependencies?.['hono']) {
180
+ dependencies.frameworks.push('Hono')
181
+ }
182
+ if (pkg.dependencies?.['express']) {
183
+ dependencies.frameworks.push('Express')
184
+ }
185
+ if (pkg.dependencies?.['next']) {
186
+ dependencies.frameworks.push('Next.js')
187
+ }
188
+ } catch (error) {
189
+ // Ignore malformed package.json
190
+ console.warn(`Could not parse ${pkgPath}:`, error)
191
+ }
192
+ }
193
+
194
+ // Deduplicate frameworks
195
+ dependencies.frameworks = Array.from(new Set(dependencies.frameworks))
196
+
197
+ return dependencies
198
+ }
199
+
200
+ /**
201
+ * Find application entry points
202
+ */
203
+ private async findEntryPoints(rootPath: string, files: string[]): Promise<string[]> {
204
+ const entryPoints: string[] = []
205
+ const candidates = [
206
+ 'index.ts',
207
+ 'index.js',
208
+ 'index.tsx',
209
+ 'index.jsx',
210
+ 'main.ts',
211
+ 'main.js',
212
+ 'app.ts',
213
+ 'app.js',
214
+ 'server.ts',
215
+ 'server.js',
216
+ 'cli.ts',
217
+ 'cli.js'
218
+ ]
219
+
220
+ for (const candidate of candidates) {
221
+ // Check root level
222
+ if (files.includes(candidate)) {
223
+ entryPoints.push(candidate)
224
+ }
225
+
226
+ // Check src/ directory
227
+ if (files.includes(`src/${candidate}`)) {
228
+ entryPoints.push(`src/${candidate}`)
229
+ }
230
+ }
231
+
232
+ // Also check package.json for main/bin entries
233
+ if (files.includes('package.json')) {
234
+ try {
235
+ const content = await this.safeReadFile(`${rootPath}/package.json`).text()
236
+ const pkg = JSON.parse(content)
237
+
238
+ if (pkg.main && !entryPoints.includes(pkg.main)) {
239
+ entryPoints.push(pkg.main)
240
+ }
241
+
242
+ if (pkg.bin) {
243
+ const binEntries = typeof pkg.bin === 'string' ? [pkg.bin] : Object.values(pkg.bin)
244
+ for (const binEntry of binEntries) {
245
+ if (typeof binEntry === 'string' && !entryPoints.includes(binEntry)) {
246
+ entryPoints.push(binEntry)
247
+ }
248
+ }
249
+ }
250
+ } catch (error) {
251
+ // Ignore
252
+ }
253
+ }
254
+
255
+ return entryPoints
256
+ }
257
+
258
+ /**
259
+ * Calculate total size and lines of code
260
+ */
261
+ private async calculateCodebaseSize(rootPath: string, files: string[]): Promise<{
262
+ totalSize: number
263
+ totalLoc: number
264
+ }> {
265
+ let totalSize = 0
266
+ let totalLoc = 0
267
+
268
+ const codeExtensions = ['ts', 'tsx', 'js', 'jsx', 'py', 'go', 'rs', 'java', 'c', 'cpp', 'h']
269
+
270
+ for (const file of files) {
271
+ const ext = file.split('.').pop()
272
+ if (ext && codeExtensions.includes(ext)) {
273
+ try {
274
+ const filePath = `${rootPath}/${file}`
275
+ const bunFile = this.safeReadFile(filePath)
276
+ totalSize += await bunFile.size
277
+ const content = await bunFile.text()
278
+ totalLoc += content.split('\n').length
279
+ } catch (error) {
280
+ // Skip files we can't read
281
+ }
282
+ }
283
+ }
284
+
285
+ return { totalSize, totalLoc }
286
+ }
287
+
288
+ /**
289
+ * Build directory structure tree
290
+ */
291
+ private async analyzeDirectoryStructure(rootPath: string): Promise<DirectoryNode> {
292
+ const files = await this.listAllFiles(rootPath)
293
+
294
+ const root: DirectoryNode = {
295
+ name: rootPath.split('/').pop() || 'root',
296
+ path: '',
297
+ type: 'directory',
298
+ children: []
299
+ }
300
+
301
+ for (const file of files) {
302
+ const parts = file.split('/')
303
+ let currentNode = root
304
+
305
+ for (let i = 0; i < parts.length; i++) {
306
+ const part = parts[i]
307
+ const isFile = i === parts.length - 1
308
+
309
+ if (!currentNode.children) {
310
+ currentNode.children = []
311
+ }
312
+
313
+ let child = currentNode.children.find(c => c.name === part)
314
+
315
+ if (!child) {
316
+ child = {
317
+ name: part,
318
+ path: parts.slice(0, i + 1).join('/'),
319
+ type: isFile ? 'file' : 'directory',
320
+ children: isFile ? undefined : []
321
+ }
322
+
323
+ if (isFile) {
324
+ child.extension = part.split('.').pop()
325
+ }
326
+
327
+ currentNode.children.push(child)
328
+ }
329
+
330
+ currentNode = child
331
+ }
332
+ }
333
+
334
+ return root
335
+ }
336
+
337
+ /**
338
+ * Extract imports from file content
339
+ */
340
+ private extractImports(content: string): Import[] {
341
+ const imports: Import[] = []
342
+
343
+ // ES6 imports: import { a, b } from 'module'
344
+ const es6ImportRegex = /import\s+(?:{([^}]+)}|(\w+))\s+from\s+['"]([^'"]+)['"]/g
345
+ let match
346
+
347
+ while ((match = es6ImportRegex.exec(content)) !== null) {
348
+ imports.push({
349
+ named: match[1]?.split(',').map(s => s.trim()).filter(Boolean) || [],
350
+ default: match[2] || undefined,
351
+ source: match[3]
352
+ })
353
+ }
354
+
355
+ // CommonJS require: const x = require('module')
356
+ const requireRegex = /(?:const|let|var)\s+(?:{([^}]+)}|(\w+))\s*=\s*require\(['"]([^'"]+)['"]\)/g
357
+
358
+ while ((match = requireRegex.exec(content)) !== null) {
359
+ imports.push({
360
+ named: match[1]?.split(',').map(s => s.trim()).filter(Boolean) || [],
361
+ default: match[2] || undefined,
362
+ source: match[3]
363
+ })
364
+ }
365
+
366
+ return imports
367
+ }
368
+
369
+ /**
370
+ * Extract exports from file content
371
+ */
372
+ private extractExports(content: string): Export[] {
373
+ const exports: Export[] = []
374
+
375
+ // export function name()
376
+ const exportFunctionRegex = /export\s+(?:async\s+)?function\s+(\w+)/g
377
+ let match
378
+
379
+ while ((match = exportFunctionRegex.exec(content)) !== null) {
380
+ exports.push({
381
+ name: match[1],
382
+ type: 'function'
383
+ })
384
+ }
385
+
386
+ // export class Name
387
+ const exportClassRegex = /export\s+class\s+(\w+)/g
388
+
389
+ while ((match = exportClassRegex.exec(content)) !== null) {
390
+ exports.push({
391
+ name: match[1],
392
+ type: 'class'
393
+ })
394
+ }
395
+
396
+ // export const name
397
+ const exportConstRegex = /export\s+const\s+(\w+)/g
398
+
399
+ while ((match = exportConstRegex.exec(content)) !== null) {
400
+ exports.push({
401
+ name: match[1],
402
+ type: 'const'
403
+ })
404
+ }
405
+
406
+ // export default
407
+ if (content.includes('export default')) {
408
+ exports.push({
409
+ name: 'default',
410
+ type: 'default'
411
+ })
412
+ }
413
+
414
+ return exports
415
+ }
416
+
417
+ /**
418
+ * Extract function declarations
419
+ */
420
+ private extractFunctions(content: string): FunctionDeclaration[] {
421
+ const functions: FunctionDeclaration[] = []
422
+
423
+ // function name(params)
424
+ const functionRegex = /(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/g
425
+ let match
426
+
427
+ while ((match = functionRegex.exec(content)) !== null) {
428
+ functions.push({
429
+ name: match[1],
430
+ isAsync: content.substring(match.index, match.index + 20).includes('async'),
431
+ parameters: match[2].split(',').map(s => s.trim()).filter(Boolean)
432
+ })
433
+ }
434
+
435
+ // const name = function(params) or const name = (params) =>
436
+ const arrowFunctionRegex = /const\s+(\w+)\s*=\s*(?:async\s+)?\(?([^)]*)\)?\s*=>/g
437
+
438
+ while ((match = arrowFunctionRegex.exec(content)) !== null) {
439
+ functions.push({
440
+ name: match[1],
441
+ isAsync: content.substring(match.index, match.index + 30).includes('async'),
442
+ parameters: match[2].split(',').map(s => s.trim()).filter(Boolean)
443
+ })
444
+ }
445
+
446
+ return functions
447
+ }
448
+
449
+ /**
450
+ * Extract React components
451
+ */
452
+ private extractReactComponents(content: string): Component[] {
453
+ const components: Component[] = []
454
+
455
+ // Functional components: function Name() or const Name = () =>
456
+ const functionalRegex = /(?:export\s+)?(?:function|const)\s+([A-Z]\w+)\s*[=:()].*(?:React\.FC|=>|:.*JSX\.Element)/g
457
+ let match
458
+
459
+ while ((match = functionalRegex.exec(content)) !== null) {
460
+ components.push({
461
+ name: match[1],
462
+ type: 'functional'
463
+ })
464
+ }
465
+
466
+ // Class components: class Name extends React.Component
467
+ const classRegex = /class\s+([A-Z]\w+)\s+extends\s+(?:React\.)?(?:Component|PureComponent)/g
468
+
469
+ while ((match = classRegex.exec(content)) !== null) {
470
+ components.push({
471
+ name: match[1],
472
+ type: 'class'
473
+ })
474
+ }
475
+
476
+ return components
477
+ }
478
+
479
+ /**
480
+ * Resolve path relative to working directory
481
+ */
482
+ private resolvePath(path: string): string {
483
+ if (path.startsWith('/')) {
484
+ return path
485
+ }
486
+ return `${this.workingDir}/${path}`.replace(/\/+/g, '/')
487
+ }
488
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Understanding module exports
3
+ */
4
+
5
+ export { CodeExplorer } from './explorer'
6
+ export { ApplicationAnalyzer } from './analyzer'
7
+
8
+ export type {
9
+ CodeStructure,
10
+ DirectoryNode,
11
+ Dependencies,
12
+ FileAnalysis,
13
+ Import,
14
+ Export,
15
+ FunctionDeclaration,
16
+ Component,
17
+ AnalyzeOptions,
18
+ Analysis,
19
+ ArchitectureAnalysis,
20
+ ComponentAnalysis,
21
+ DataFlowAnalysis,
22
+ EntryPointAnalysis,
23
+ DependencyAnalysis,
24
+ TechStackAnalysis,
25
+ Diagnosis,
26
+ Pattern
27
+ } from './types'
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Type definitions for understanding capabilities
3
+ */
4
+
5
+ export interface CodeStructure {
6
+ totalFiles: number
7
+ filesByType: Record<string, number>
8
+ directoryStructure: DirectoryNode
9
+ dependencies: Dependencies
10
+ entryPoints: string[]
11
+ totalSize: number
12
+ totalLoc: number
13
+ }
14
+
15
+ export interface DirectoryNode {
16
+ name: string
17
+ path: string
18
+ type: 'file' | 'directory'
19
+ children?: DirectoryNode[]
20
+ size?: number
21
+ extension?: string
22
+ }
23
+
24
+ export interface Dependencies {
25
+ runtime: Record<string, string>
26
+ dev: Record<string, string>
27
+ frameworks: string[]
28
+ internal: string[]
29
+ }
30
+
31
+ export interface FileAnalysis {
32
+ path: string
33
+ imports: Import[]
34
+ exports: Export[]
35
+ functions: FunctionDeclaration[]
36
+ components: Component[]
37
+ loc: number
38
+ size: number
39
+ }
40
+
41
+ export interface Import {
42
+ named: string[]
43
+ default?: string
44
+ source: string
45
+ line?: number
46
+ }
47
+
48
+ export interface Export {
49
+ name: string
50
+ type: 'function' | 'class' | 'const' | 'default'
51
+ line?: number
52
+ }
53
+
54
+ export interface FunctionDeclaration {
55
+ name: string
56
+ isAsync: boolean
57
+ parameters: string[]
58
+ line?: number
59
+ }
60
+
61
+ export interface Component {
62
+ name: string
63
+ type: 'functional' | 'class'
64
+ props?: string[]
65
+ line?: number
66
+ }
67
+
68
+ export interface AnalyzeOptions {
69
+ rootPath: string
70
+ focus?: 'architecture' | 'dependencies' | 'components' | 'all'
71
+ depth?: 'shallow' | 'medium' | 'deep'
72
+ ignorePatterns?: string[]
73
+ }
74
+
75
+ export interface Analysis {
76
+ architecture: ArchitectureAnalysis
77
+ components: ComponentAnalysis
78
+ dataFlow: DataFlowAnalysis
79
+ entryPoints: EntryPointAnalysis
80
+ dependencies: DependencyAnalysis
81
+ techStack: TechStackAnalysis
82
+ }
83
+
84
+ export interface ArchitectureAnalysis {
85
+ pattern: string
86
+ description: string
87
+ layers: string[]
88
+ }
89
+
90
+ export interface ComponentAnalysis {
91
+ summary: string
92
+ keyModules: Array<{
93
+ name: string
94
+ purpose: string
95
+ files: string[]
96
+ }>
97
+ }
98
+
99
+ export interface DataFlowAnalysis {
100
+ description: string
101
+ flows: Array<{
102
+ source: string
103
+ destination: string
104
+ dataType: string
105
+ }>
106
+ }
107
+
108
+ export interface EntryPointAnalysis {
109
+ main: string[]
110
+ server?: string
111
+ client?: string
112
+ cli?: string
113
+ }
114
+
115
+ export interface DependencyAnalysis {
116
+ external: Array<{
117
+ name: string
118
+ version: string
119
+ purpose: string
120
+ }>
121
+ internal: Array<{
122
+ module: string
123
+ dependsOn: string[]
124
+ }>
125
+ }
126
+
127
+ export interface TechStackAnalysis {
128
+ runtime: string
129
+ framework: string[]
130
+ language: string[]
131
+ tools: string[]
132
+ }
133
+
134
+ export interface Diagnosis {
135
+ symptoms: string[]
136
+ rootCause: string
137
+ affectedFiles: string[]
138
+ recommendedFix: string
139
+ validationSteps: string[]
140
+ confidence: 'low' | 'medium' | 'high'
141
+ }
142
+
143
+ export interface Pattern {
144
+ type: 'architecture' | 'design' | 'security' | 'performance'
145
+ name: string
146
+ description: string
147
+ instances: Array<{
148
+ file: string
149
+ line?: number
150
+ context?: string
151
+ }>
152
+ recommendation?: string
153
+ }