wiggum-cli 0.3.0 → 0.3.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/dist/ai/agents/codebase-analyst.d.ts.map +1 -1
- package/dist/ai/agents/codebase-analyst.js +23 -27
- package/dist/ai/agents/codebase-analyst.js.map +1 -1
- package/dist/ai/agents/index.d.ts.map +1 -1
- package/dist/ai/agents/index.js +38 -2
- package/dist/ai/agents/index.js.map +1 -1
- package/dist/ai/agents/orchestrator.d.ts +1 -1
- package/dist/ai/agents/orchestrator.d.ts.map +1 -1
- package/dist/ai/agents/orchestrator.js +18 -24
- package/dist/ai/agents/orchestrator.js.map +1 -1
- package/dist/ai/agents/stack-researcher.d.ts.map +1 -1
- package/dist/ai/agents/stack-researcher.js +21 -26
- package/dist/ai/agents/stack-researcher.js.map +1 -1
- package/dist/ai/enhancer.d.ts.map +1 -1
- package/dist/ai/enhancer.js +24 -32
- package/dist/ai/enhancer.js.map +1 -1
- package/dist/utils/json-repair.d.ts +14 -0
- package/dist/utils/json-repair.d.ts.map +1 -0
- package/dist/utils/json-repair.js +146 -0
- package/dist/utils/json-repair.js.map +1 -0
- package/dist/utils/tracing.d.ts +25 -0
- package/dist/utils/tracing.d.ts.map +1 -0
- package/dist/utils/tracing.js +64 -0
- package/dist/utils/tracing.js.map +1 -0
- package/package.json +3 -1
- package/src/ai/agents/codebase-analyst.ts +27 -30
- package/src/ai/agents/index.ts +37 -2
- package/src/ai/agents/orchestrator.ts +22 -26
- package/src/ai/agents/stack-researcher.ts +23 -27
- package/src/ai/enhancer.ts +26 -34
- package/src/utils/json-repair.ts +163 -0
- package/src/utils/tracing.ts +76 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Repair Utility
|
|
3
|
+
* Fixes common JSON syntax errors from AI responses
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Fix mismatched brackets in JSON
|
|
7
|
+
* AI sometimes writes } instead of ] or vice versa
|
|
8
|
+
*/
|
|
9
|
+
function fixMismatchedBrackets(text) {
|
|
10
|
+
const chars = text.split('');
|
|
11
|
+
const stack = [];
|
|
12
|
+
let inString = false;
|
|
13
|
+
let escapeNext = false;
|
|
14
|
+
for (let i = 0; i < chars.length; i++) {
|
|
15
|
+
const char = chars[i];
|
|
16
|
+
if (escapeNext) {
|
|
17
|
+
escapeNext = false;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (char === '\\' && inString) {
|
|
21
|
+
escapeNext = true;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (char === '"') {
|
|
25
|
+
inString = !inString;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (inString)
|
|
29
|
+
continue;
|
|
30
|
+
if (char === '{' || char === '[') {
|
|
31
|
+
stack.push({ char, index: i });
|
|
32
|
+
}
|
|
33
|
+
else if (char === '}' || char === ']') {
|
|
34
|
+
if (stack.length > 0) {
|
|
35
|
+
const last = stack.pop();
|
|
36
|
+
const expected = last.char === '{' ? '}' : ']';
|
|
37
|
+
if (char !== expected) {
|
|
38
|
+
// Mismatch! Fix it
|
|
39
|
+
chars[i] = expected;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return chars.join('');
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Attempt to repair malformed JSON from AI responses
|
|
48
|
+
*/
|
|
49
|
+
export function repairJson(text) {
|
|
50
|
+
let json = text;
|
|
51
|
+
// Remove any leading/trailing whitespace
|
|
52
|
+
json = json.trim();
|
|
53
|
+
// Fix mismatched brackets (AI writes } instead of ] or vice versa)
|
|
54
|
+
json = fixMismatchedBrackets(json);
|
|
55
|
+
// Remove trailing commas before ] or }
|
|
56
|
+
json = json.replace(/,(\s*[\]}])/g, '$1');
|
|
57
|
+
// Fix missing commas between array elements or object properties
|
|
58
|
+
// Pattern: value followed by newline and another value without comma
|
|
59
|
+
json = json.replace(/("|\d|true|false|null|\]|\})(\s*\n\s*)("|\[|\{)/g, '$1,$2$3');
|
|
60
|
+
// Fix single quotes to double quotes (but not inside strings)
|
|
61
|
+
// This is a simplified approach - may not work for all cases
|
|
62
|
+
json = json.replace(/'/g, '"');
|
|
63
|
+
// Remove JavaScript-style comments
|
|
64
|
+
json = json.replace(/\/\/.*$/gm, '');
|
|
65
|
+
json = json.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
66
|
+
// Fix unquoted keys (simple cases)
|
|
67
|
+
json = json.replace(/(\{|\,)\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:/g, '$1"$2":');
|
|
68
|
+
// Remove any text before the first { or [
|
|
69
|
+
const firstBrace = json.indexOf('{');
|
|
70
|
+
const firstBracket = json.indexOf('[');
|
|
71
|
+
let startIndex = -1;
|
|
72
|
+
if (firstBrace !== -1 && firstBracket !== -1) {
|
|
73
|
+
startIndex = Math.min(firstBrace, firstBracket);
|
|
74
|
+
}
|
|
75
|
+
else if (firstBrace !== -1) {
|
|
76
|
+
startIndex = firstBrace;
|
|
77
|
+
}
|
|
78
|
+
else if (firstBracket !== -1) {
|
|
79
|
+
startIndex = firstBracket;
|
|
80
|
+
}
|
|
81
|
+
if (startIndex > 0) {
|
|
82
|
+
json = json.substring(startIndex);
|
|
83
|
+
}
|
|
84
|
+
// Remove any text after the last } or ]
|
|
85
|
+
const lastBrace = json.lastIndexOf('}');
|
|
86
|
+
const lastBracket = json.lastIndexOf(']');
|
|
87
|
+
let endIndex = -1;
|
|
88
|
+
if (lastBrace !== -1 && lastBracket !== -1) {
|
|
89
|
+
endIndex = Math.max(lastBrace, lastBracket);
|
|
90
|
+
}
|
|
91
|
+
else if (lastBrace !== -1) {
|
|
92
|
+
endIndex = lastBrace;
|
|
93
|
+
}
|
|
94
|
+
else if (lastBracket !== -1) {
|
|
95
|
+
endIndex = lastBracket;
|
|
96
|
+
}
|
|
97
|
+
if (endIndex !== -1 && endIndex < json.length - 1) {
|
|
98
|
+
json = json.substring(0, endIndex + 1);
|
|
99
|
+
}
|
|
100
|
+
return json;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Parse JSON with repair attempts
|
|
104
|
+
* Tries to fix common issues before parsing
|
|
105
|
+
*/
|
|
106
|
+
export function parseJsonSafe(text) {
|
|
107
|
+
// First try parsing as-is
|
|
108
|
+
try {
|
|
109
|
+
return JSON.parse(text);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// Try with repairs
|
|
113
|
+
}
|
|
114
|
+
// Try repairing the JSON
|
|
115
|
+
try {
|
|
116
|
+
const repaired = repairJson(text);
|
|
117
|
+
return JSON.parse(repaired);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// Repair failed
|
|
121
|
+
}
|
|
122
|
+
// Last resort: try to extract JSON from markdown code blocks
|
|
123
|
+
const jsonMatch = text.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
124
|
+
if (jsonMatch) {
|
|
125
|
+
try {
|
|
126
|
+
const repaired = repairJson(jsonMatch[1]);
|
|
127
|
+
return JSON.parse(repaired);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// Still failed
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Try finding a JSON object
|
|
134
|
+
const objectMatch = text.match(/\{[\s\S]*\}/);
|
|
135
|
+
if (objectMatch) {
|
|
136
|
+
try {
|
|
137
|
+
const repaired = repairJson(objectMatch[0]);
|
|
138
|
+
return JSON.parse(repaired);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// Still failed
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=json-repair.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-repair.js","sourceRoot":"","sources":["../../src/utils/json-repair.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Braintrust Tracing Utility
|
|
3
|
+
* Provides AI call tracing for debugging and analysis
|
|
4
|
+
*/
|
|
5
|
+
import * as ai from 'ai';
|
|
6
|
+
export { traced, currentSpan, wrapTraced } from 'braintrust';
|
|
7
|
+
export declare function initTracing(): void;
|
|
8
|
+
/**
|
|
9
|
+
* Check if tracing is enabled
|
|
10
|
+
*/
|
|
11
|
+
export declare function isTracingEnabled(): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Get wrapped AI SDK functions for automatic tracing
|
|
14
|
+
* Falls back to original functions if tracing not available
|
|
15
|
+
*/
|
|
16
|
+
export declare function getTracedAI(): typeof ai;
|
|
17
|
+
/**
|
|
18
|
+
* Wrap a function with tracing
|
|
19
|
+
* No-op if tracing is not enabled
|
|
20
|
+
*/
|
|
21
|
+
export declare function maybeTraced<T extends (...args: unknown[]) => unknown>(fn: T, options?: {
|
|
22
|
+
type?: string;
|
|
23
|
+
name?: string;
|
|
24
|
+
}): T;
|
|
25
|
+
//# sourceMappingURL=tracing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../../src/utils/tracing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAGzB,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAO7D,wBAAgB,WAAW,IAAI,IAAI,CAkBlC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED;;;GAGG;AACH,wBAAgB,WAAW,cAS1B;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EACnE,EAAE,EAAE,CAAC,EACL,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7C,CAAC,CAUH"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Braintrust Tracing Utility
|
|
3
|
+
* Provides AI call tracing for debugging and analysis
|
|
4
|
+
*/
|
|
5
|
+
import { initLogger, wrapAISDK } from 'braintrust';
|
|
6
|
+
import * as ai from 'ai';
|
|
7
|
+
// Re-export traced utilities
|
|
8
|
+
export { traced, currentSpan, wrapTraced } from 'braintrust';
|
|
9
|
+
/**
|
|
10
|
+
* Initialize Braintrust logger if API key is available
|
|
11
|
+
*/
|
|
12
|
+
let loggerInitialized = false;
|
|
13
|
+
export function initTracing() {
|
|
14
|
+
if (loggerInitialized)
|
|
15
|
+
return;
|
|
16
|
+
const apiKey = process.env.BRAINTRUST_API_KEY;
|
|
17
|
+
if (!apiKey) {
|
|
18
|
+
// Silently skip tracing if no API key
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
initLogger({
|
|
23
|
+
apiKey,
|
|
24
|
+
projectName: process.env.BRAINTRUST_PROJECT_NAME || 'wiggum-cli',
|
|
25
|
+
});
|
|
26
|
+
loggerInitialized = true;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// Silently fail if tracing can't be initialized
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Check if tracing is enabled
|
|
34
|
+
*/
|
|
35
|
+
export function isTracingEnabled() {
|
|
36
|
+
return !!process.env.BRAINTRUST_API_KEY;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get wrapped AI SDK functions for automatic tracing
|
|
40
|
+
* Falls back to original functions if tracing not available
|
|
41
|
+
*/
|
|
42
|
+
export function getTracedAI() {
|
|
43
|
+
initTracing();
|
|
44
|
+
if (isTracingEnabled()) {
|
|
45
|
+
return wrapAISDK(ai);
|
|
46
|
+
}
|
|
47
|
+
// Return original AI SDK functions if tracing not enabled
|
|
48
|
+
return ai;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Wrap a function with tracing
|
|
52
|
+
* No-op if tracing is not enabled
|
|
53
|
+
*/
|
|
54
|
+
export function maybeTraced(fn, options = {}) {
|
|
55
|
+
if (!isTracingEnabled()) {
|
|
56
|
+
return fn;
|
|
57
|
+
}
|
|
58
|
+
const { wrapTraced } = require('braintrust');
|
|
59
|
+
return wrapTraced(fn, {
|
|
60
|
+
type: options.type || 'function',
|
|
61
|
+
name: options.name || fn.name || 'anonymous',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=tracing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracing.js","sourceRoot":"","sources":["../../src/utils/tracing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB,6BAA6B;AAC7B,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7D;;GAEG;AACH,IAAI,iBAAiB,GAAG,KAAK,CAAC;AAE9B,MAAM,UAAU,WAAW;IACzB,IAAI,iBAAiB;QAAE,OAAO;IAE9B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAC9C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,sCAAsC;QACtC,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,UAAU,CAAC;YACT,MAAM;YACN,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,YAAY;SACjE,CAAC,CAAC;QACH,iBAAiB,GAAG,IAAI,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,gDAAgD;IAClD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW;IACzB,WAAW,EAAE,CAAC;IAEd,IAAI,gBAAgB,EAAE,EAAE,CAAC;QACvB,OAAO,SAAS,CAAC,EAAE,CAAC,CAAC;IACvB,CAAC;IAED,0DAA0D;IAC1D,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,EAAK,EACL,UAA4C,EAAE;IAE9C,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC;QACxB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7C,OAAO,UAAU,CAAC,EAAE,EAAE;QACpB,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,UAAU;QAChC,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,IAAI,IAAI,WAAW;KAC7C,CAAC,CAAC;AACL,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wiggum-cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "AI-powered feature development loop CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -28,8 +28,10 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@ai-sdk/anthropic": "^3.0.15",
|
|
30
30
|
"@ai-sdk/openai": "^3.0.12",
|
|
31
|
+
"@braintrust/otel": "^0.2.0",
|
|
31
32
|
"@clack/prompts": "^0.7.0",
|
|
32
33
|
"ai": "^6.0.41",
|
|
34
|
+
"braintrust": "^2.0.2",
|
|
33
35
|
"cfonts": "^3.2.0",
|
|
34
36
|
"commander": "^12.1.0",
|
|
35
37
|
"picocolors": "^1.0.0",
|
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
* Explores the codebase to understand its structure and patterns
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { stepCountIs, type LanguageModel } from 'ai';
|
|
7
7
|
import type { CodebaseAnalysis, CodebaseAnalystInput } from './types.js';
|
|
8
8
|
import { createExplorationTools } from '../tools.js';
|
|
9
9
|
import { isReasoningModel } from '../providers.js';
|
|
10
10
|
import { logger } from '../../utils/logger.js';
|
|
11
|
+
import { parseJsonSafe } from '../../utils/json-repair.js';
|
|
12
|
+
import { getTracedAI } from '../../utils/tracing.js';
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* System prompt for the Codebase Analyst agent
|
|
@@ -82,6 +84,8 @@ Project: ${input.projectRoot}
|
|
|
82
84
|
Start by exploring the directory structure and package.json, then produce your analysis as JSON.`;
|
|
83
85
|
|
|
84
86
|
try {
|
|
87
|
+
const { generateText } = getTracedAI();
|
|
88
|
+
|
|
85
89
|
const result = await generateText({
|
|
86
90
|
model,
|
|
87
91
|
system: CODEBASE_ANALYST_SYSTEM_PROMPT,
|
|
@@ -90,6 +94,10 @@ Start by exploring the directory structure and package.json, then produce your a
|
|
|
90
94
|
stopWhen: stepCountIs(12),
|
|
91
95
|
maxOutputTokens: 3000,
|
|
92
96
|
...(isReasoningModel(modelId) ? {} : { temperature: 0.3 }),
|
|
97
|
+
experimental_telemetry: {
|
|
98
|
+
isEnabled: true,
|
|
99
|
+
metadata: { agent: 'codebase-analyst', projectRoot: input.projectRoot },
|
|
100
|
+
},
|
|
93
101
|
});
|
|
94
102
|
|
|
95
103
|
// Extract JSON from response
|
|
@@ -133,40 +141,29 @@ function parseCodebaseAnalysis(
|
|
|
133
141
|
return null;
|
|
134
142
|
}
|
|
135
143
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
let jsonText = textToParse;
|
|
139
|
-
const jsonMatch = textToParse.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
140
|
-
if (jsonMatch) {
|
|
141
|
-
jsonText = jsonMatch[1];
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Find JSON object
|
|
145
|
-
const objectMatch = jsonText.match(/\{[\s\S]*\}/);
|
|
146
|
-
if (objectMatch) {
|
|
147
|
-
jsonText = objectMatch[0];
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const parsed = JSON.parse(jsonText) as CodebaseAnalysis;
|
|
151
|
-
|
|
152
|
-
// Validate required fields
|
|
153
|
-
if (!parsed.projectContext || !parsed.commands) {
|
|
154
|
-
if (verbose) {
|
|
155
|
-
logger.warn('Codebase Analyst: Missing required fields in response');
|
|
156
|
-
}
|
|
157
|
-
return null;
|
|
158
|
-
}
|
|
144
|
+
// Use safe JSON parser with repair capabilities
|
|
145
|
+
const parsed = parseJsonSafe<CodebaseAnalysis>(textToParse);
|
|
159
146
|
|
|
160
|
-
|
|
161
|
-
if (
|
|
162
|
-
|
|
147
|
+
if (!parsed) {
|
|
148
|
+
if (verbose) {
|
|
149
|
+
logger.warn('Codebase Analyst: Failed to parse JSON response');
|
|
150
|
+
logger.warn(`Response preview: ${textToParse.substring(0, 200)}...`);
|
|
163
151
|
}
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
164
154
|
|
|
165
|
-
|
|
166
|
-
|
|
155
|
+
// Validate required fields
|
|
156
|
+
if (!parsed.projectContext || !parsed.commands) {
|
|
167
157
|
if (verbose) {
|
|
168
|
-
logger.warn(
|
|
158
|
+
logger.warn('Codebase Analyst: Missing required fields in response');
|
|
169
159
|
}
|
|
170
160
|
return null;
|
|
171
161
|
}
|
|
162
|
+
|
|
163
|
+
// Ensure projectType is set
|
|
164
|
+
if (!parsed.projectContext.projectType) {
|
|
165
|
+
parsed.projectContext.projectType = 'Unknown';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return parsed;
|
|
172
169
|
}
|
package/src/ai/agents/index.ts
CHANGED
|
@@ -61,7 +61,7 @@ export async function runMultiAgentAnalysis(
|
|
|
61
61
|
logger.info('Running Codebase Analyst...');
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
let codebaseAnalysis = await runCodebaseAnalyst(
|
|
65
65
|
model,
|
|
66
66
|
modelId,
|
|
67
67
|
{
|
|
@@ -75,7 +75,8 @@ export async function runMultiAgentAnalysis(
|
|
|
75
75
|
if (verbose) {
|
|
76
76
|
logger.warn('Codebase Analyst failed, using defaults');
|
|
77
77
|
}
|
|
78
|
-
|
|
78
|
+
// Use defaults instead of aborting the pipeline
|
|
79
|
+
codebaseAnalysis = getDefaultCodebaseAnalysis(scanResult);
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
// Run Stack Researcher
|
|
@@ -132,6 +133,40 @@ export async function runMultiAgentAnalysis(
|
|
|
132
133
|
return finalResult;
|
|
133
134
|
}
|
|
134
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Get default codebase analysis when agent fails
|
|
138
|
+
*/
|
|
139
|
+
function getDefaultCodebaseAnalysis(scanResult: ScanResult) {
|
|
140
|
+
// Detect project type from scan result
|
|
141
|
+
let projectType = 'Unknown';
|
|
142
|
+
if (scanResult.stack.mcp?.isProject) {
|
|
143
|
+
projectType = 'MCP Server';
|
|
144
|
+
} else if (scanResult.stack.framework?.name.includes('Next')) {
|
|
145
|
+
projectType = 'Next.js App';
|
|
146
|
+
} else if (scanResult.stack.framework?.name.includes('React')) {
|
|
147
|
+
projectType = 'React SPA';
|
|
148
|
+
} else if (scanResult.stack.framework?.name) {
|
|
149
|
+
projectType = `${scanResult.stack.framework.name} Project`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
projectContext: {
|
|
154
|
+
entryPoints: ['src/index.ts'],
|
|
155
|
+
keyDirectories: { 'src': 'Source code' },
|
|
156
|
+
namingConventions: 'camelCase',
|
|
157
|
+
projectType,
|
|
158
|
+
},
|
|
159
|
+
commands: {
|
|
160
|
+
test: 'npm test',
|
|
161
|
+
lint: 'npm run lint',
|
|
162
|
+
build: 'npm run build',
|
|
163
|
+
dev: 'npm run dev',
|
|
164
|
+
},
|
|
165
|
+
implementationGuidelines: ['Follow existing patterns', 'Run tests after changes'],
|
|
166
|
+
possibleMissedTechnologies: [],
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
135
170
|
/**
|
|
136
171
|
* Get default stack research when agent fails
|
|
137
172
|
*/
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Coordinates the multi-agent analysis and merges results
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import type { LanguageModel } from 'ai';
|
|
7
7
|
import type {
|
|
8
8
|
CodebaseAnalysis,
|
|
9
9
|
StackResearch,
|
|
@@ -14,6 +14,8 @@ import type {
|
|
|
14
14
|
import type { DetectedStack } from '../../scanner/types.js';
|
|
15
15
|
import { isReasoningModel } from '../providers.js';
|
|
16
16
|
import { logger } from '../../utils/logger.js';
|
|
17
|
+
import { parseJsonSafe } from '../../utils/json-repair.js';
|
|
18
|
+
import { getTracedAI } from '../../utils/tracing.js';
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
21
|
* System prompt for the Orchestrator
|
|
@@ -67,12 +69,18 @@ export async function runOrchestrator(
|
|
|
67
69
|
const prompt = createOrchestratorPrompt(input);
|
|
68
70
|
|
|
69
71
|
try {
|
|
72
|
+
const { generateText } = getTracedAI();
|
|
73
|
+
|
|
70
74
|
const result = await generateText({
|
|
71
75
|
model,
|
|
72
76
|
system: ORCHESTRATOR_SYSTEM_PROMPT,
|
|
73
77
|
prompt,
|
|
74
78
|
maxOutputTokens: 1000,
|
|
75
79
|
...(isReasoningModel(modelId) ? {} : { temperature: 0.2 }),
|
|
80
|
+
experimental_telemetry: {
|
|
81
|
+
isEnabled: true,
|
|
82
|
+
metadata: { agent: 'orchestrator', projectType: input.codebaseAnalysis.projectContext.projectType },
|
|
83
|
+
},
|
|
76
84
|
});
|
|
77
85
|
|
|
78
86
|
const mcpServers = parseMcpRecommendations(result.text, input.stack, verbose);
|
|
@@ -130,36 +138,24 @@ function parseMcpRecommendations(
|
|
|
130
138
|
return getDefaultMcpRecommendations('Unknown', stack);
|
|
131
139
|
}
|
|
132
140
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
let jsonText = text;
|
|
136
|
-
const jsonMatch = text.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
137
|
-
if (jsonMatch) {
|
|
138
|
-
jsonText = jsonMatch[1];
|
|
139
|
-
}
|
|
141
|
+
// Use safe JSON parser with repair capabilities
|
|
142
|
+
const parsed = parseJsonSafe<{ mcpServers?: McpRecommendations }>(text);
|
|
140
143
|
|
|
141
|
-
|
|
142
|
-
const objectMatch = jsonText.match(/\{[\s\S]*\}/);
|
|
143
|
-
if (objectMatch) {
|
|
144
|
-
jsonText = objectMatch[0];
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const parsed = JSON.parse(jsonText) as { mcpServers?: McpRecommendations };
|
|
148
|
-
|
|
149
|
-
if (parsed.mcpServers) {
|
|
150
|
-
return {
|
|
151
|
-
essential: parsed.mcpServers.essential || ['filesystem', 'git'],
|
|
152
|
-
recommended: parsed.mcpServers.recommended || [],
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return getDefaultMcpRecommendations('Unknown', stack);
|
|
157
|
-
} catch (error) {
|
|
144
|
+
if (!parsed) {
|
|
158
145
|
if (verbose) {
|
|
159
|
-
logger.warn(
|
|
146
|
+
logger.warn('Orchestrator: Failed to parse JSON response');
|
|
160
147
|
}
|
|
161
148
|
return getDefaultMcpRecommendations('Unknown', stack);
|
|
162
149
|
}
|
|
150
|
+
|
|
151
|
+
if (parsed.mcpServers) {
|
|
152
|
+
return {
|
|
153
|
+
essential: parsed.mcpServers.essential || ['filesystem', 'git'],
|
|
154
|
+
recommended: parsed.mcpServers.recommended || [],
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return getDefaultMcpRecommendations('Unknown', stack);
|
|
163
159
|
}
|
|
164
160
|
|
|
165
161
|
/**
|
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
* Gracefully degrades when optional services are unavailable
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { stepCountIs, type LanguageModel, type Tool } from 'ai';
|
|
8
8
|
import type { StackResearch, StackResearcherInput, AgentCapabilities } from './types.js';
|
|
9
9
|
import type { DetectedStack } from '../../scanner/types.js';
|
|
10
10
|
import { createTavilySearchTool } from '../tools/tavily.js';
|
|
11
11
|
import { createContext7Tool } from '../tools/context7.js';
|
|
12
12
|
import { isReasoningModel } from '../providers.js';
|
|
13
13
|
import { logger } from '../../utils/logger.js';
|
|
14
|
+
import { parseJsonSafe } from '../../utils/json-repair.js';
|
|
15
|
+
import { getTracedAI } from '../../utils/tracing.js';
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* System prompt for Stack Researcher with tools
|
|
@@ -200,6 +202,8 @@ export async function runStackResearcher(
|
|
|
200
202
|
const prompt = createResearchPrompt(input.stack, input.projectType, hasTools);
|
|
201
203
|
|
|
202
204
|
try {
|
|
205
|
+
const { generateText } = getTracedAI();
|
|
206
|
+
|
|
203
207
|
const result = await generateText({
|
|
204
208
|
model,
|
|
205
209
|
system: systemPrompt,
|
|
@@ -207,6 +211,10 @@ export async function runStackResearcher(
|
|
|
207
211
|
...(hasTools ? { tools, stopWhen: stepCountIs(8) } : {}),
|
|
208
212
|
maxOutputTokens: 2000,
|
|
209
213
|
...(isReasoningModel(modelId) ? {} : { temperature: 0.3 }),
|
|
214
|
+
experimental_telemetry: {
|
|
215
|
+
isEnabled: true,
|
|
216
|
+
metadata: { agent: 'stack-researcher', researchMode, projectType: input.projectType },
|
|
217
|
+
},
|
|
210
218
|
});
|
|
211
219
|
|
|
212
220
|
// Parse the response
|
|
@@ -250,37 +258,25 @@ function parseStackResearch(
|
|
|
250
258
|
return getDefaultStackResearch(researchMode);
|
|
251
259
|
}
|
|
252
260
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
let jsonText = textToParse;
|
|
256
|
-
const jsonMatch = textToParse.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
257
|
-
if (jsonMatch) {
|
|
258
|
-
jsonText = jsonMatch[1];
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Find JSON object
|
|
262
|
-
const objectMatch = jsonText.match(/\{[\s\S]*\}/);
|
|
263
|
-
if (objectMatch) {
|
|
264
|
-
jsonText = objectMatch[0];
|
|
265
|
-
}
|
|
261
|
+
// Use safe JSON parser with repair capabilities
|
|
262
|
+
const parsed = parseJsonSafe<Partial<StackResearch>>(textToParse);
|
|
266
263
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
// Build result with defaults for missing fields
|
|
270
|
-
return {
|
|
271
|
-
bestPractices: parsed.bestPractices || [],
|
|
272
|
-
antiPatterns: parsed.antiPatterns || [],
|
|
273
|
-
testingTools: parsed.testingTools || [],
|
|
274
|
-
debuggingTools: parsed.debuggingTools || [],
|
|
275
|
-
documentationHints: parsed.documentationHints || [],
|
|
276
|
-
researchMode: researchMode,
|
|
277
|
-
};
|
|
278
|
-
} catch (error) {
|
|
264
|
+
if (!parsed) {
|
|
279
265
|
if (verbose) {
|
|
280
|
-
logger.warn(
|
|
266
|
+
logger.warn('Stack Researcher: Failed to parse JSON response');
|
|
281
267
|
}
|
|
282
268
|
return getDefaultStackResearch(researchMode);
|
|
283
269
|
}
|
|
270
|
+
|
|
271
|
+
// Build result with defaults for missing fields
|
|
272
|
+
return {
|
|
273
|
+
bestPractices: parsed.bestPractices || [],
|
|
274
|
+
antiPatterns: parsed.antiPatterns || [],
|
|
275
|
+
testingTools: parsed.testingTools || [],
|
|
276
|
+
debuggingTools: parsed.debuggingTools || [],
|
|
277
|
+
documentationHints: parsed.documentationHints || [],
|
|
278
|
+
researchMode: researchMode,
|
|
279
|
+
};
|
|
284
280
|
}
|
|
285
281
|
|
|
286
282
|
/**
|