@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,527 @@
1
+ /**
2
+ * Runtime Mapping
3
+ *
4
+ * Maps runtime behavior (traces) to source code (instructions) to intent (purpose).
5
+ *
6
+ * The Three Ideograms:
7
+ * - VESSEL (Instructional State): Source code, activity templates
8
+ * - BECOMING (Transient State): Execution traces, function calls
9
+ * - INSTANCE (Functional State): Running process, outcomes
10
+ *
11
+ * This module bridges these states by:
12
+ * 1. Capturing runtime traces (what happens)
13
+ * 2. Locating source code (what the code says)
14
+ * 3. Inferring intent (why the code exists)
15
+ */
16
+
17
+ import { existsSync, readFileSync, readdirSync, statSync } from 'fs'
18
+ import { join, relative, extname } from 'path'
19
+ import type { SourceLocation, InferredIntent } from './vessel-registry'
20
+
21
+ // =============================================================================
22
+ // TYPES
23
+ // =============================================================================
24
+
25
+ export interface TraceToSourceMapping {
26
+ /** The trace activity ID */
27
+ traceId: string
28
+ /** Function/method that was called */
29
+ functionName: string
30
+ /** Source location if found */
31
+ sourceLocation?: SourceLocation
32
+ /** Inferred intent */
33
+ intent?: InferredIntent
34
+ /** Confidence in the mapping */
35
+ confidence: number
36
+ }
37
+
38
+ export interface CodebaseAnalysis {
39
+ /** Root path of the codebase */
40
+ rootPath: string
41
+ /** All functions/methods found */
42
+ functions: FunctionInfo[]
43
+ /** All classes found */
44
+ classes: ClassInfo[]
45
+ /** Module structure */
46
+ modules: ModuleInfo[]
47
+ /** Entry points */
48
+ entryPoints: string[]
49
+ /** Comments and docstrings */
50
+ documentation: DocumentationInfo[]
51
+ }
52
+
53
+ export interface FunctionInfo {
54
+ name: string
55
+ file: string
56
+ line: number
57
+ params: string[]
58
+ returnType?: string
59
+ isAsync: boolean
60
+ isExported: boolean
61
+ docstring?: string
62
+ comments?: string[]
63
+ }
64
+
65
+ export interface ClassInfo {
66
+ name: string
67
+ file: string
68
+ line: number
69
+ methods: FunctionInfo[]
70
+ properties: string[]
71
+ extends?: string
72
+ implements?: string[]
73
+ docstring?: string
74
+ }
75
+
76
+ export interface ModuleInfo {
77
+ name: string
78
+ file: string
79
+ exports: string[]
80
+ imports: { from: string; items: string[] }[]
81
+ }
82
+
83
+ export interface DocumentationInfo {
84
+ file: string
85
+ line: number
86
+ type: 'comment' | 'docstring' | 'jsdoc' | 'inline'
87
+ content: string
88
+ associatedWith?: string // function/class name
89
+ }
90
+
91
+ // =============================================================================
92
+ // SOURCE ANALYSIS
93
+ // =============================================================================
94
+
95
+ /**
96
+ * Analyze a codebase to extract function/class/module information
97
+ */
98
+ export async function analyzeCodebase(rootPath: string): Promise<CodebaseAnalysis> {
99
+ const functions: FunctionInfo[] = []
100
+ const classes: ClassInfo[] = []
101
+ const modules: ModuleInfo[] = []
102
+ const documentation: DocumentationInfo[] = []
103
+ const entryPoints: string[] = []
104
+
105
+ const sourceExtensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']
106
+
107
+ function walkDirectory(dir: string): void {
108
+ const entries = readdirSync(dir)
109
+
110
+ for (const entry of entries) {
111
+ const fullPath = join(dir, entry)
112
+
113
+ // Skip node_modules, .git, build artifacts, etc.
114
+ if (entry === 'node_modules' || entry === '.git' || entry === 'dist' || entry === 'build' ||
115
+ entry === '.local' || entry === 'test-workspace' || entry === 'coverage' || entry === '.turbo') {
116
+ continue
117
+ }
118
+
119
+ let stat
120
+ try {
121
+ stat = statSync(fullPath)
122
+ } catch (err) {
123
+ // Skip broken symlinks or inaccessible files
124
+ continue
125
+ }
126
+
127
+ if (stat.isDirectory()) {
128
+ walkDirectory(fullPath)
129
+ } else if (sourceExtensions.includes(extname(entry))) {
130
+ analyzeSourceFile(fullPath, rootPath, functions, classes, modules, documentation)
131
+
132
+ // Detect entry points
133
+ if (entry === 'index.ts' || entry === 'index.js' || entry === 'main.ts' || entry === 'main.js') {
134
+ entryPoints.push(relative(rootPath, fullPath))
135
+ }
136
+ }
137
+ }
138
+ }
139
+
140
+ walkDirectory(rootPath)
141
+
142
+ // Also check package.json for entry points
143
+ const packageJsonPath = join(rootPath, 'package.json')
144
+ if (existsSync(packageJsonPath)) {
145
+ try {
146
+ const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8'))
147
+ if (pkg.main) entryPoints.push(pkg.main)
148
+ if (pkg.module) entryPoints.push(pkg.module)
149
+ if (pkg.bin) {
150
+ if (typeof pkg.bin === 'string') {
151
+ entryPoints.push(pkg.bin)
152
+ } else {
153
+ entryPoints.push(...Object.values(pkg.bin) as string[])
154
+ }
155
+ }
156
+ } catch (e) {
157
+ // Ignore parse errors
158
+ }
159
+ }
160
+
161
+ return {
162
+ rootPath,
163
+ functions,
164
+ classes,
165
+ modules,
166
+ entryPoints: [...new Set(entryPoints)],
167
+ documentation,
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Analyze a single source file
173
+ */
174
+ function analyzeSourceFile(
175
+ filePath: string,
176
+ rootPath: string,
177
+ functions: FunctionInfo[],
178
+ classes: ClassInfo[],
179
+ modules: ModuleInfo[],
180
+ documentation: DocumentationInfo[]
181
+ ): void {
182
+ try {
183
+ const content = readFileSync(filePath, 'utf-8')
184
+ const lines = content.split('\n')
185
+ const relativePath = relative(rootPath, filePath)
186
+
187
+ // Extract imports
188
+ const imports: { from: string; items: string[] }[] = []
189
+ const exports: string[] = []
190
+
191
+ // Simple regex-based extraction (more robust would use AST)
192
+ const functionRegex = /(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(/g
193
+ const classRegex = /(?:export\s+)?class\s+(\w+)(?:\s+extends\s+(\w+))?/g
194
+ const arrowFunctionRegex = /(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\([^)]*\)\s*=>/g
195
+ const methodRegex = /(?:async\s+)?(\w+)\s*\([^)]*\)\s*(?::\s*\w+)?\s*\{/g
196
+ const exportRegex = /export\s+(?:default\s+)?(?:const|let|var|function|class|interface|type)\s+(\w+)/g
197
+ const importRegex = /import\s+(?:{([^}]+)}|(\w+))\s+from\s+['"]([^'"]+)['"]/g
198
+ const commentRegex = /\/\*\*([\s\S]*?)\*\/|\/\/\s*(.*)/g
199
+ const docstringRegex = /\/\*\*\s*([\s\S]*?)\s*\*\//g
200
+
201
+ // Extract functions
202
+ let match
203
+ while ((match = functionRegex.exec(content)) !== null) {
204
+ const name = match[1]
205
+ const line = content.slice(0, match.index).split('\n').length
206
+
207
+ // Look for preceding docstring
208
+ const docstring = findPrecedingDocstring(lines, line - 1)
209
+
210
+ functions.push({
211
+ name,
212
+ file: relativePath,
213
+ line,
214
+ params: extractParams(content, match.index),
215
+ isAsync: match[0].includes('async'),
216
+ isExported: match[0].includes('export'),
217
+ docstring,
218
+ })
219
+ }
220
+
221
+ // Extract arrow functions
222
+ while ((match = arrowFunctionRegex.exec(content)) !== null) {
223
+ const name = match[1]
224
+ const line = content.slice(0, match.index).split('\n').length
225
+
226
+ const docstring = findPrecedingDocstring(lines, line - 1)
227
+
228
+ functions.push({
229
+ name,
230
+ file: relativePath,
231
+ line,
232
+ params: extractParams(content, match.index),
233
+ isAsync: match[0].includes('async'),
234
+ isExported: match[0].includes('export'),
235
+ docstring,
236
+ })
237
+ }
238
+
239
+ // Extract classes
240
+ while ((match = classRegex.exec(content)) !== null) {
241
+ const name = match[1]
242
+ const extendsClass = match[2]
243
+ const line = content.slice(0, match.index).split('\n').length
244
+
245
+ const docstring = findPrecedingDocstring(lines, line - 1)
246
+
247
+ // Find methods in the class
248
+ const classEndIndex = findMatchingBrace(content, content.indexOf('{', match.index))
249
+ const classBody = content.slice(match.index, classEndIndex)
250
+ const classMethods: FunctionInfo[] = []
251
+
252
+ let methodMatch
253
+ const classMethodRegex = /(?:async\s+)?(\w+)\s*\([^)]*\)\s*(?::\s*[\w<>\[\]]+)?\s*\{/g
254
+ while ((methodMatch = classMethodRegex.exec(classBody)) !== null) {
255
+ if (methodMatch[1] !== 'constructor' && methodMatch[1] !== 'if' && methodMatch[1] !== 'for' && methodMatch[1] !== 'while') {
256
+ classMethods.push({
257
+ name: methodMatch[1],
258
+ file: relativePath,
259
+ line: line + classBody.slice(0, methodMatch.index).split('\n').length - 1,
260
+ params: extractParams(classBody, methodMatch.index),
261
+ isAsync: methodMatch[0].includes('async'),
262
+ isExported: false,
263
+ })
264
+ }
265
+ }
266
+
267
+ classes.push({
268
+ name,
269
+ file: relativePath,
270
+ line,
271
+ methods: classMethods,
272
+ properties: [],
273
+ extends: extendsClass,
274
+ docstring,
275
+ })
276
+ }
277
+
278
+ // Extract exports
279
+ while ((match = exportRegex.exec(content)) !== null) {
280
+ exports.push(match[1])
281
+ }
282
+
283
+ // Extract imports
284
+ while ((match = importRegex.exec(content)) !== null) {
285
+ const items = (match[1] || match[2]).split(',').map(s => s.trim())
286
+ const from = match[3]
287
+ imports.push({ from, items })
288
+ }
289
+
290
+ if (exports.length > 0 || imports.length > 0) {
291
+ modules.push({
292
+ name: relativePath,
293
+ file: relativePath,
294
+ exports,
295
+ imports,
296
+ })
297
+ }
298
+
299
+ // Extract documentation
300
+ while ((match = docstringRegex.exec(content)) !== null) {
301
+ const line = content.slice(0, match.index).split('\n').length
302
+ documentation.push({
303
+ file: relativePath,
304
+ line,
305
+ type: 'docstring',
306
+ content: match[1].trim(),
307
+ })
308
+ }
309
+
310
+ } catch (error) {
311
+ // Ignore files that can't be read
312
+ }
313
+ }
314
+
315
+ // =============================================================================
316
+ // HELPER FUNCTIONS
317
+ // =============================================================================
318
+
319
+ function findPrecedingDocstring(lines: string[], lineIndex: number): string | undefined {
320
+ // Look backwards for a docstring
321
+ for (let i = lineIndex - 1; i >= 0 && i >= lineIndex - 5; i--) {
322
+ const line = lines[i]?.trim()
323
+ if (line?.startsWith('/**')) {
324
+ // Found start of docstring, collect until */
325
+ const docLines: string[] = []
326
+ for (let j = i; j <= lineIndex; j++) {
327
+ docLines.push(lines[j]?.replace(/^\s*\*\s?/, '').replace(/\*\//, '').trim() || '')
328
+ if (lines[j]?.includes('*/')) break
329
+ }
330
+ return docLines.filter(l => l).join(' ')
331
+ }
332
+ if (line?.startsWith('//')) {
333
+ return line.slice(2).trim()
334
+ }
335
+ if (line && !line.startsWith('*')) {
336
+ break
337
+ }
338
+ }
339
+ return undefined
340
+ }
341
+
342
+ function extractParams(content: string, startIndex: number): string[] {
343
+ const parenStart = content.indexOf('(', startIndex)
344
+ const parenEnd = findMatchingParen(content, parenStart)
345
+ const paramString = content.slice(parenStart + 1, parenEnd)
346
+
347
+ if (!paramString.trim()) return []
348
+
349
+ // Simple param extraction
350
+ return paramString
351
+ .split(',')
352
+ .map(p => p.split(':')[0].trim())
353
+ .filter(p => p && !p.startsWith('{') && !p.startsWith('['))
354
+ }
355
+
356
+ function findMatchingParen(content: string, startIndex: number): number {
357
+ let depth = 0
358
+ for (let i = startIndex; i < content.length; i++) {
359
+ if (content[i] === '(') depth++
360
+ if (content[i] === ')') {
361
+ depth--
362
+ if (depth === 0) return i
363
+ }
364
+ }
365
+ return startIndex
366
+ }
367
+
368
+ function findMatchingBrace(content: string, startIndex: number): number {
369
+ let depth = 0
370
+ for (let i = startIndex; i < content.length; i++) {
371
+ if (content[i] === '{') depth++
372
+ if (content[i] === '}') {
373
+ depth--
374
+ if (depth === 0) return i
375
+ }
376
+ }
377
+ return content.length
378
+ }
379
+
380
+ // =============================================================================
381
+ // INTENT INFERENCE
382
+ // =============================================================================
383
+
384
+ /**
385
+ * Infer the intent of a function from its name, params, and context
386
+ */
387
+ export function inferIntent(
388
+ func: FunctionInfo,
389
+ classes: ClassInfo[],
390
+ documentation: DocumentationInfo[]
391
+ ): InferredIntent {
392
+ const name = func.name
393
+ const docstring = func.docstring
394
+
395
+ // Start with docstring if available
396
+ if (docstring) {
397
+ return {
398
+ purpose: docstring,
399
+ confidence: 0.9,
400
+ source: 'docstring',
401
+ }
402
+ }
403
+
404
+ // Infer from function name patterns
405
+ const patterns: Array<{ regex: RegExp; purpose: (match: RegExpMatchArray) => string }> = [
406
+ { regex: /^get(\w+)$/, purpose: (m) => `Retrieve ${camelToSpaces(m[1])}` },
407
+ { regex: /^set(\w+)$/, purpose: (m) => `Set ${camelToSpaces(m[1])}` },
408
+ { regex: /^is(\w+)$/, purpose: (m) => `Check if ${camelToSpaces(m[1])}` },
409
+ { regex: /^has(\w+)$/, purpose: (m) => `Check if has ${camelToSpaces(m[1])}` },
410
+ { regex: /^create(\w+)$/, purpose: (m) => `Create ${camelToSpaces(m[1])}` },
411
+ { regex: /^delete(\w+)$/, purpose: (m) => `Delete ${camelToSpaces(m[1])}` },
412
+ { regex: /^remove(\w+)$/, purpose: (m) => `Remove ${camelToSpaces(m[1])}` },
413
+ { regex: /^add(\w+)$/, purpose: (m) => `Add ${camelToSpaces(m[1])}` },
414
+ { regex: /^update(\w+)$/, purpose: (m) => `Update ${camelToSpaces(m[1])}` },
415
+ { regex: /^fetch(\w+)$/, purpose: (m) => `Fetch ${camelToSpaces(m[1])} from remote` },
416
+ { regex: /^load(\w+)$/, purpose: (m) => `Load ${camelToSpaces(m[1])}` },
417
+ { regex: /^save(\w+)$/, purpose: (m) => `Save ${camelToSpaces(m[1])}` },
418
+ { regex: /^validate(\w+)$/, purpose: (m) => `Validate ${camelToSpaces(m[1])}` },
419
+ { regex: /^parse(\w+)$/, purpose: (m) => `Parse ${camelToSpaces(m[1])}` },
420
+ { regex: /^convert(\w+)$/, purpose: (m) => `Convert ${camelToSpaces(m[1])}` },
421
+ { regex: /^transform(\w+)$/, purpose: (m) => `Transform ${camelToSpaces(m[1])}` },
422
+ { regex: /^handle(\w+)$/, purpose: (m) => `Handle ${camelToSpaces(m[1])}` },
423
+ { regex: /^process(\w+)$/, purpose: (m) => `Process ${camelToSpaces(m[1])}` },
424
+ { regex: /^send(\w+)$/, purpose: (m) => `Send ${camelToSpaces(m[1])}` },
425
+ { regex: /^receive(\w+)$/, purpose: (m) => `Receive ${camelToSpaces(m[1])}` },
426
+ { regex: /^init(\w*)$/, purpose: (m) => m[1] ? `Initialize ${camelToSpaces(m[1])}` : 'Initialize' },
427
+ { regex: /^start(\w*)$/, purpose: (m) => m[1] ? `Start ${camelToSpaces(m[1])}` : 'Start' },
428
+ { regex: /^stop(\w*)$/, purpose: (m) => m[1] ? `Stop ${camelToSpaces(m[1])}` : 'Stop' },
429
+ { regex: /^on(\w+)$/, purpose: (m) => `Handler for ${camelToSpaces(m[1])} event` },
430
+ ]
431
+
432
+ for (const { regex, purpose } of patterns) {
433
+ const match = name.match(regex)
434
+ if (match) {
435
+ return {
436
+ purpose: purpose(match),
437
+ confidence: 0.7,
438
+ source: 'function-name',
439
+ inputs: func.params,
440
+ }
441
+ }
442
+ }
443
+
444
+ // Fallback to generic inference from name
445
+ return {
446
+ purpose: camelToSpaces(name),
447
+ confidence: 0.4,
448
+ source: 'function-name',
449
+ inputs: func.params,
450
+ }
451
+ }
452
+
453
+ function camelToSpaces(str: string): string {
454
+ return str
455
+ .replace(/([A-Z])/g, ' $1')
456
+ .toLowerCase()
457
+ .trim()
458
+ }
459
+
460
+ // =============================================================================
461
+ // TRACE TO SOURCE MAPPING
462
+ // =============================================================================
463
+
464
+ /**
465
+ * Map a trace's function call to source code location
466
+ */
467
+ export function mapTraceToSource(
468
+ functionName: string,
469
+ analysis: CodebaseAnalysis
470
+ ): TraceToSourceMapping {
471
+ // Search for function in analysis
472
+ const func = analysis.functions.find(f => f.name === functionName)
473
+
474
+ if (func) {
475
+ const intent = inferIntent(func, analysis.classes, analysis.documentation)
476
+
477
+ return {
478
+ traceId: '',
479
+ functionName,
480
+ sourceLocation: {
481
+ file: func.file,
482
+ line: func.line,
483
+ functionName: func.name,
484
+ },
485
+ intent,
486
+ confidence: intent.confidence,
487
+ }
488
+ }
489
+
490
+ // Search in class methods
491
+ for (const cls of analysis.classes) {
492
+ const method = cls.methods.find(m => m.name === functionName)
493
+ if (method) {
494
+ const intent = inferIntent(method, analysis.classes, analysis.documentation)
495
+
496
+ return {
497
+ traceId: '',
498
+ functionName,
499
+ sourceLocation: {
500
+ file: method.file,
501
+ line: method.line,
502
+ functionName: method.name,
503
+ className: cls.name,
504
+ },
505
+ intent,
506
+ confidence: intent.confidence,
507
+ }
508
+ }
509
+ }
510
+
511
+ // Not found
512
+ return {
513
+ traceId: '',
514
+ functionName,
515
+ confidence: 0,
516
+ }
517
+ }
518
+
519
+ // =============================================================================
520
+ // EXPORTS
521
+ // =============================================================================
522
+
523
+ export const runtimeMapping = {
524
+ analyzeCodebase,
525
+ mapTraceToSource,
526
+ inferIntent,
527
+ }