@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.
- package/ARCHITECTURE.md +255 -0
- package/CHANGELOG.md +112 -0
- package/README.md +380 -0
- package/bin/minibob.js +36 -0
- package/dist/acp-gossip.d.ts +72 -0
- package/dist/acp-gossip.d.ts.map +1 -0
- package/dist/acp-gossip.js +156 -0
- package/dist/acp-gossip.js.map +1 -0
- package/dist/acp.d.ts +62 -0
- package/dist/acp.d.ts.map +1 -0
- package/dist/acp.js +292 -0
- package/dist/acp.js.map +1 -0
- package/dist/activity.d.ts +157 -0
- package/dist/activity.d.ts.map +1 -0
- package/dist/activity.js +518 -0
- package/dist/activity.js.map +1 -0
- package/dist/agent-runtime.d.ts +104 -0
- package/dist/agent-runtime.d.ts.map +1 -0
- package/dist/boredom.d.ts +125 -0
- package/dist/boredom.d.ts.map +1 -0
- package/dist/boredom.js +244 -0
- package/dist/boredom.js.map +1 -0
- package/dist/cli/acp-server.d.ts +23 -0
- package/dist/cli/acp-server.d.ts.map +1 -0
- package/dist/cli/burrow.d.ts +26 -0
- package/dist/cli/burrow.d.ts.map +1 -0
- package/dist/cli/doctor.d.ts +22 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/goal.d.ts +22 -0
- package/dist/cli/goal.d.ts.map +1 -0
- package/dist/cli/index.d.ts +47 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/instance-registry.d.ts +78 -0
- package/dist/cli/instance-registry.d.ts.map +1 -0
- package/dist/cli/observe.d.ts +35 -0
- package/dist/cli/observe.d.ts.map +1 -0
- package/dist/cli/vessel.d.ts +14 -0
- package/dist/cli/vessel.d.ts.map +1 -0
- package/dist/composition-observer.d.ts +96 -0
- package/dist/composition-observer.d.ts.map +1 -0
- package/dist/config.d.ts +36 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +128 -0
- package/dist/config.js.map +1 -0
- package/dist/docker/Dockerfile +35 -0
- package/dist/environment.d.ts +72 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +142 -0
- package/dist/environment.js.map +1 -0
- package/dist/goal-processor.d.ts +165 -0
- package/dist/goal-processor.d.ts.map +1 -0
- package/dist/helm/minibob-cluster/Chart.yaml +13 -0
- package/dist/helm/minibob-cluster/templates/_helpers.tpl +60 -0
- package/dist/helm/minibob-cluster/templates/configmap.yaml +11 -0
- package/dist/helm/minibob-cluster/templates/deployment.yaml +108 -0
- package/dist/helm/minibob-cluster/templates/secret.yaml +10 -0
- package/dist/helm/minibob-cluster/templates/service.yaml +37 -0
- package/dist/helm/minibob-cluster/values-local.yaml +41 -0
- package/dist/helm/minibob-cluster/values-production.yaml +57 -0
- package/dist/helm/minibob-cluster/values-testing-cluster.yaml +43 -0
- package/dist/helm/minibob-cluster/values.yaml +127 -0
- package/dist/improviser.d.ts +74 -0
- package/dist/improviser.d.ts.map +1 -0
- package/dist/impulse-filter.d.ts +74 -0
- package/dist/impulse-filter.d.ts.map +1 -0
- package/dist/impulse.d.ts +92 -0
- package/dist/impulse.d.ts.map +1 -0
- package/dist/impulse.js +234 -0
- package/dist/impulse.js.map +1 -0
- package/dist/lib.d.ts +29 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +18561 -0
- package/dist/lib.js.map +98 -0
- package/dist/lifecycle-hooks.d.ts +99 -0
- package/dist/lifecycle-hooks.d.ts.map +1 -0
- package/dist/lifecycle-hooks.js +135 -0
- package/dist/lifecycle-hooks.js.map +1 -0
- package/dist/llm.d.ts +31 -0
- package/dist/llm.d.ts.map +1 -0
- package/dist/llm.js +349 -0
- package/dist/llm.js.map +1 -0
- package/dist/mcp-activity-bridge.d.ts +66 -0
- package/dist/mcp-activity-bridge.d.ts.map +1 -0
- package/dist/mcp-activity-bridge.js +126 -0
- package/dist/mcp-activity-bridge.js.map +1 -0
- package/dist/mcp.d.ts +216 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +292 -0
- package/dist/mcp.js.map +1 -0
- package/dist/memory-agent.d.ts +92 -0
- package/dist/memory-agent.d.ts.map +1 -0
- package/dist/memory-agent.js +277 -0
- package/dist/memory-agent.js.map +1 -0
- package/dist/runtime-mapping.d.ts +97 -0
- package/dist/runtime-mapping.d.ts.map +1 -0
- package/dist/search-first-executor.d.ts +113 -0
- package/dist/search-first-executor.d.ts.map +1 -0
- package/dist/session.d.ts +48 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/template-extractor.d.ts +9 -0
- package/dist/template-extractor.d.ts.map +1 -0
- package/dist/template-generator.d.ts +12 -0
- package/dist/template-generator.d.ts.map +1 -0
- package/dist/tools.d.ts +58 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +771 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +503 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/understanding/analyzer.d.ts +55 -0
- package/dist/understanding/analyzer.d.ts.map +1 -0
- package/dist/understanding/explorer.d.ts +73 -0
- package/dist/understanding/explorer.d.ts.map +1 -0
- package/dist/understanding/index.d.ts +7 -0
- package/dist/understanding/index.d.ts.map +1 -0
- package/dist/understanding/types.d.ts +136 -0
- package/dist/understanding/types.d.ts.map +1 -0
- package/dist/validation.d.ts +29 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +106 -0
- package/dist/validation.js.map +1 -0
- package/dist/vessel-bootstrap.d.ts +190 -0
- package/dist/vessel-bootstrap.d.ts.map +1 -0
- package/dist/vessel-registry.d.ts +229 -0
- package/dist/vessel-registry.d.ts.map +1 -0
- package/index.ts +1329 -0
- package/package.json +54 -0
- package/src/acp-gossip.ts +193 -0
- package/src/acp.ts +362 -0
- package/src/activity.ts +1464 -0
- package/src/agent-runtime.ts +365 -0
- package/src/boredom.ts +423 -0
- package/src/cli/acp-server.ts +377 -0
- package/src/cli/burrow.ts +896 -0
- package/src/cli/doctor.ts +526 -0
- package/src/cli/goal.ts +224 -0
- package/src/cli/index.ts +147 -0
- package/src/cli/instance-registry.ts +271 -0
- package/src/cli/observe.ts +682 -0
- package/src/cli/vessel.ts +287 -0
- package/src/components/SystemOverview.tsx +331 -0
- package/src/composition-observer.ts +449 -0
- package/src/config.ts +172 -0
- package/src/environment.ts +167 -0
- package/src/goal-processor.ts +654 -0
- package/src/improviser.ts +591 -0
- package/src/impulse-filter.ts +273 -0
- package/src/impulse.ts +311 -0
- package/src/lib.ts +147 -0
- package/src/lifecycle-hooks.ts +181 -0
- package/src/llm.ts +434 -0
- package/src/mcp-activity-bridge.ts +158 -0
- package/src/mcp.ts +747 -0
- package/src/memory-agent.ts +316 -0
- package/src/runtime-mapping.ts +527 -0
- package/src/search-first-executor.ts +666 -0
- package/src/session.ts +141 -0
- package/src/template-extractor.ts +256 -0
- package/src/template-generator.ts +130 -0
- package/src/tools.ts +924 -0
- package/src/types.ts +497 -0
- package/src/understanding/analyzer.ts +354 -0
- package/src/understanding/explorer.ts +488 -0
- package/src/understanding/index.ts +27 -0
- package/src/understanding/types.ts +153 -0
- package/src/validation.ts +125 -0
- package/src/vessel-bootstrap.ts +440 -0
- package/src/vessel-registry.ts +621 -0
- package/templates/core/edit-file.json +85 -0
- package/templates/understanding/diagnose-problem.json +32 -0
- package/templates/understanding/explore-codebase-v2.json +57 -0
- package/templates/understanding/explore-codebase.json +37 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ApplicationAnalyzer - LLM-powered semantic understanding
|
|
3
|
+
*
|
|
4
|
+
* Combines CodeExplorer's static analysis with LLM reasoning
|
|
5
|
+
* to understand application architecture, patterns, and issues.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ActivityExecutor } from '../activity'
|
|
9
|
+
import type { CodeExplorer } from './explorer'
|
|
10
|
+
import type {
|
|
11
|
+
AnalyzeOptions,
|
|
12
|
+
Analysis,
|
|
13
|
+
Diagnosis,
|
|
14
|
+
Pattern
|
|
15
|
+
} from './types'
|
|
16
|
+
import type { Impulse } from '../types'
|
|
17
|
+
|
|
18
|
+
export class ApplicationAnalyzer {
|
|
19
|
+
constructor(
|
|
20
|
+
private executor: ActivityExecutor,
|
|
21
|
+
private explorer: CodeExplorer
|
|
22
|
+
) {}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Safe wrapper for Bun.file() with better error handling
|
|
26
|
+
*/
|
|
27
|
+
private safeReadFile(path: string): ReturnType<typeof Bun.file> {
|
|
28
|
+
if (!path || typeof path !== 'string') {
|
|
29
|
+
throw new Error(`Invalid file path: expected string, got ${typeof path}`)
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
return Bun.file(path)
|
|
33
|
+
} catch (error) {
|
|
34
|
+
throw new Error(`Failed to create file handle for '${path}': ${error instanceof Error ? error.message : String(error)}`)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Analyze application architecture and structure
|
|
40
|
+
*/
|
|
41
|
+
async analyze(options: AnalyzeOptions): Promise<Analysis> {
|
|
42
|
+
// 1. Fast static exploration
|
|
43
|
+
console.log('Exploring codebase structure...')
|
|
44
|
+
const structure = await this.explorer.explore(options.rootPath)
|
|
45
|
+
|
|
46
|
+
// 2. Create impulses from exploration
|
|
47
|
+
const impulses = this.createImpulsesFromStructure(structure, options.focus)
|
|
48
|
+
|
|
49
|
+
// 3. Load and execute analysis activity
|
|
50
|
+
console.log('Performing semantic analysis with LLM...')
|
|
51
|
+
const template = await this.loadTemplate('explore-codebase')
|
|
52
|
+
|
|
53
|
+
const result = await this.executor.execute({
|
|
54
|
+
template,
|
|
55
|
+
variables: {
|
|
56
|
+
structure: JSON.stringify(structure, null, 2),
|
|
57
|
+
focus: options.focus || 'architecture',
|
|
58
|
+
depth: options.depth || 'medium'
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
// 4. Parse structured output from task results
|
|
63
|
+
return this.parseAnalysisResult(result)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Diagnose specific problem in application
|
|
68
|
+
*/
|
|
69
|
+
async diagnose(problem: string, context?: string[]): Promise<Diagnosis> {
|
|
70
|
+
// 1. Gather relevant context files
|
|
71
|
+
const relevantFiles = context || await this.findRelevantFiles(problem)
|
|
72
|
+
|
|
73
|
+
if (relevantFiles.length === 0) {
|
|
74
|
+
return {
|
|
75
|
+
symptoms: [problem],
|
|
76
|
+
rootCause: 'Unable to find relevant files for analysis',
|
|
77
|
+
affectedFiles: [],
|
|
78
|
+
recommendedFix: 'Please provide specific file paths or more context',
|
|
79
|
+
validationSteps: [],
|
|
80
|
+
confidence: 'low'
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 2. Create impulses for relevant files
|
|
85
|
+
const impulses: Impulse[] = relevantFiles.slice(0, 5).map(path => ({
|
|
86
|
+
id: `file_${path.replace(/[^a-zA-Z0-9]/g, '_')}`,
|
|
87
|
+
pointer: { type: 'file', path },
|
|
88
|
+
budget: 2000,
|
|
89
|
+
priority: 'high' as const,
|
|
90
|
+
loaded: false,
|
|
91
|
+
content: null
|
|
92
|
+
}))
|
|
93
|
+
|
|
94
|
+
// 3. Execute diagnosis activity
|
|
95
|
+
console.log(`Diagnosing problem across ${impulses.length} files...`)
|
|
96
|
+
const template = await this.loadTemplate('diagnose-problem')
|
|
97
|
+
|
|
98
|
+
const result = await this.executor.execute({
|
|
99
|
+
template,
|
|
100
|
+
variables: {
|
|
101
|
+
problem,
|
|
102
|
+
files: relevantFiles.join(', ')
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
// 4. Parse diagnosis result
|
|
107
|
+
return this.parseDiagnosis(result)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Detect patterns in codebase
|
|
112
|
+
*/
|
|
113
|
+
async detectPatterns(rootPath: string): Promise<Pattern[]> {
|
|
114
|
+
const structure = await this.explorer.explore(rootPath)
|
|
115
|
+
const patterns: Pattern[] = []
|
|
116
|
+
|
|
117
|
+
// Detect common architecture patterns
|
|
118
|
+
if (structure.dependencies.frameworks.includes('React')) {
|
|
119
|
+
patterns.push({
|
|
120
|
+
type: 'architecture',
|
|
121
|
+
name: 'React SPA',
|
|
122
|
+
description: 'React-based single-page application',
|
|
123
|
+
instances: [{ file: 'package.json' }]
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (structure.dependencies.frameworks.includes('Hono') ||
|
|
128
|
+
structure.dependencies.frameworks.includes('Express')) {
|
|
129
|
+
patterns.push({
|
|
130
|
+
type: 'architecture',
|
|
131
|
+
name: 'HTTP Server',
|
|
132
|
+
description: 'HTTP server application',
|
|
133
|
+
instances: [{ file: 'package.json' }]
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Detect entry point patterns
|
|
138
|
+
if (structure.entryPoints.includes('index.ts') && structure.entryPoints.includes('server.ts')) {
|
|
139
|
+
patterns.push({
|
|
140
|
+
type: 'architecture',
|
|
141
|
+
name: 'Client-Server Split',
|
|
142
|
+
description: 'Separate client and server entry points',
|
|
143
|
+
instances: [
|
|
144
|
+
{ file: 'index.ts', context: 'Client entry' },
|
|
145
|
+
{ file: 'server.ts', context: 'Server entry' }
|
|
146
|
+
]
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return patterns
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Create impulses from codebase structure
|
|
155
|
+
*/
|
|
156
|
+
private createImpulsesFromStructure(
|
|
157
|
+
structure: any,
|
|
158
|
+
focus?: string
|
|
159
|
+
): Impulse[] {
|
|
160
|
+
const impulses: Impulse[] = []
|
|
161
|
+
|
|
162
|
+
// Add entry point impulses (high priority)
|
|
163
|
+
for (const entryPoint of structure.entryPoints.slice(0, 3)) {
|
|
164
|
+
impulses.push({
|
|
165
|
+
id: `entrypoint_${entryPoint.replace(/[^a-zA-Z0-9]/g, '_')}`,
|
|
166
|
+
pointer: { type: 'file', path: entryPoint, limit: 100 },
|
|
167
|
+
budget: 1500,
|
|
168
|
+
priority: 'high' as const,
|
|
169
|
+
loaded: false,
|
|
170
|
+
content: null
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Add package.json for dependency info (medium priority)
|
|
175
|
+
impulses.push({
|
|
176
|
+
id: 'dependencies',
|
|
177
|
+
pointer: { type: 'file', path: 'package.json' },
|
|
178
|
+
budget: 500,
|
|
179
|
+
priority: 'medium' as const,
|
|
180
|
+
loaded: false,
|
|
181
|
+
content: null
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
// Focus-specific impulses
|
|
185
|
+
if (focus === 'components' && structure.filesByType['tsx']) {
|
|
186
|
+
// Add React component files
|
|
187
|
+
impulses.push({
|
|
188
|
+
id: 'react_components',
|
|
189
|
+
pointer: { type: 'memo', content: `Component files: ${structure.filesByType['tsx']} .tsx files found` },
|
|
190
|
+
budget: 300,
|
|
191
|
+
priority: 'medium' as const,
|
|
192
|
+
loaded: false,
|
|
193
|
+
content: null
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return impulses
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Find files relevant to problem description
|
|
202
|
+
*/
|
|
203
|
+
private async findRelevantFiles(problem: string): Promise<string[]> {
|
|
204
|
+
const keywords = this.extractKeywords(problem)
|
|
205
|
+
const structure = await this.explorer.explore(process.cwd())
|
|
206
|
+
|
|
207
|
+
// Build list of all files
|
|
208
|
+
const allFiles: string[] = []
|
|
209
|
+
const collectFiles = (node: any) => {
|
|
210
|
+
if (node.type === 'file') {
|
|
211
|
+
allFiles.push(node.path)
|
|
212
|
+
}
|
|
213
|
+
if (node.children) {
|
|
214
|
+
for (const child of node.children) {
|
|
215
|
+
collectFiles(child)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
collectFiles(structure.directoryStructure)
|
|
220
|
+
|
|
221
|
+
// Filter by keywords
|
|
222
|
+
const relevant = allFiles.filter(file =>
|
|
223
|
+
keywords.some(kw => file.toLowerCase().includes(kw.toLowerCase()))
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
return relevant.slice(0, 10)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Extract keywords from problem description
|
|
231
|
+
*/
|
|
232
|
+
private extractKeywords(text: string): string[] {
|
|
233
|
+
// Remove common words and extract meaningful terms
|
|
234
|
+
const stopWords = new Set(['the', 'is', 'at', 'which', 'on', 'a', 'an', 'and', 'or', 'but', 'in', 'with', 'to', 'for'])
|
|
235
|
+
const words = text.toLowerCase()
|
|
236
|
+
.replace(/[^a-z0-9\s]/g, ' ')
|
|
237
|
+
.split(/\s+/)
|
|
238
|
+
.filter(w => w.length > 2 && !stopWords.has(w))
|
|
239
|
+
|
|
240
|
+
return Array.from(new Set(words))
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Load activity template
|
|
245
|
+
*/
|
|
246
|
+
private async loadTemplate(templateId: string): Promise<any> {
|
|
247
|
+
// Try loading from local templates in multiple locations
|
|
248
|
+
const possiblePaths = [
|
|
249
|
+
`templates/understanding/${templateId}.json`,
|
|
250
|
+
`./templates/understanding/${templateId}.json`,
|
|
251
|
+
`${process.cwd()}/templates/understanding/${templateId}.json`,
|
|
252
|
+
// Also try from minibob directory if we're running elsewhere
|
|
253
|
+
`${__dirname}/../../templates/understanding/${templateId}.json`,
|
|
254
|
+
]
|
|
255
|
+
|
|
256
|
+
for (const templatePath of possiblePaths) {
|
|
257
|
+
try {
|
|
258
|
+
const content = await this.safeReadFile(templatePath).text()
|
|
259
|
+
const template = JSON.parse(content)
|
|
260
|
+
console.log(`Loaded template from: ${templatePath}`)
|
|
261
|
+
return template
|
|
262
|
+
} catch (error) {
|
|
263
|
+
// Try next path
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Template not found in any location
|
|
268
|
+
throw new Error(`Template not found: ${templateId}. Tried paths: ${possiblePaths.join(', ')}`)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Parse analysis result from LLM output
|
|
273
|
+
*/
|
|
274
|
+
private parseAnalysisResult(result: any): Analysis {
|
|
275
|
+
// Extract analysis from task results
|
|
276
|
+
const output = result.taskResults?.[0]?.output || result.output || ''
|
|
277
|
+
|
|
278
|
+
// Try to parse as JSON
|
|
279
|
+
try {
|
|
280
|
+
// Look for JSON in output
|
|
281
|
+
const jsonMatch = output.match(/\{[\s\S]*\}/)
|
|
282
|
+
if (jsonMatch) {
|
|
283
|
+
return JSON.parse(jsonMatch[0])
|
|
284
|
+
}
|
|
285
|
+
} catch (error) {
|
|
286
|
+
// Fallback to text parsing
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Fallback: create structured response from text
|
|
290
|
+
return {
|
|
291
|
+
architecture: {
|
|
292
|
+
pattern: 'Unknown',
|
|
293
|
+
description: output.substring(0, 500),
|
|
294
|
+
layers: []
|
|
295
|
+
},
|
|
296
|
+
components: {
|
|
297
|
+
summary: 'See full output for details',
|
|
298
|
+
keyModules: []
|
|
299
|
+
},
|
|
300
|
+
dataFlow: {
|
|
301
|
+
description: 'Analysis in progress',
|
|
302
|
+
flows: []
|
|
303
|
+
},
|
|
304
|
+
entryPoints: {
|
|
305
|
+
main: []
|
|
306
|
+
},
|
|
307
|
+
dependencies: {
|
|
308
|
+
external: [],
|
|
309
|
+
internal: []
|
|
310
|
+
},
|
|
311
|
+
techStack: {
|
|
312
|
+
runtime: 'Unknown',
|
|
313
|
+
framework: [],
|
|
314
|
+
language: [],
|
|
315
|
+
tools: []
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Parse diagnosis result from LLM output
|
|
322
|
+
*/
|
|
323
|
+
private parseDiagnosis(result: any): Diagnosis {
|
|
324
|
+
const output = result.taskResults?.[0]?.output || result.output || ''
|
|
325
|
+
|
|
326
|
+
// Try to parse as JSON
|
|
327
|
+
try {
|
|
328
|
+
const jsonMatch = output.match(/\{[\s\S]*\}/)
|
|
329
|
+
if (jsonMatch) {
|
|
330
|
+
const parsed = JSON.parse(jsonMatch[0])
|
|
331
|
+
return {
|
|
332
|
+
symptoms: parsed.symptoms || [output.substring(0, 200)],
|
|
333
|
+
rootCause: parsed.rootCause || 'See full analysis',
|
|
334
|
+
affectedFiles: parsed.affectedFiles || [],
|
|
335
|
+
recommendedFix: parsed.recommendedFix || 'Review analysis output',
|
|
336
|
+
validationSteps: parsed.validationSteps || [],
|
|
337
|
+
confidence: parsed.confidence || 'medium'
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
} catch (error) {
|
|
341
|
+
// Fallback
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Fallback: extract from text
|
|
345
|
+
return {
|
|
346
|
+
symptoms: [output.substring(0, 200)],
|
|
347
|
+
rootCause: 'See full analysis in output',
|
|
348
|
+
affectedFiles: [],
|
|
349
|
+
recommendedFix: output,
|
|
350
|
+
validationSteps: ['Review LLM analysis', 'Validate proposed changes'],
|
|
351
|
+
confidence: 'medium'
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|