wiggum-cli 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/dist/ai/agents/codebase-analyst.d.ts +3 -0
- package/dist/ai/agents/codebase-analyst.d.ts.map +1 -1
- package/dist/ai/agents/codebase-analyst.js +3 -0
- package/dist/ai/agents/codebase-analyst.js.map +1 -1
- package/dist/ai/agents/context-enricher.d.ts +11 -0
- package/dist/ai/agents/context-enricher.d.ts.map +1 -0
- package/dist/ai/agents/context-enricher.js +163 -0
- package/dist/ai/agents/context-enricher.js.map +1 -0
- package/dist/ai/agents/evaluator-optimizer.d.ts +13 -0
- package/dist/ai/agents/evaluator-optimizer.d.ts.map +1 -0
- package/dist/ai/agents/evaluator-optimizer.js +231 -0
- package/dist/ai/agents/evaluator-optimizer.js.map +1 -0
- package/dist/ai/agents/index.d.ts +21 -3
- package/dist/ai/agents/index.d.ts.map +1 -1
- package/dist/ai/agents/index.js +151 -82
- package/dist/ai/agents/index.js.map +1 -1
- package/dist/ai/agents/mcp-detector.d.ts +26 -0
- package/dist/ai/agents/mcp-detector.d.ts.map +1 -0
- package/dist/ai/agents/mcp-detector.js +186 -0
- package/dist/ai/agents/mcp-detector.js.map +1 -0
- package/dist/ai/agents/orchestrator.d.ts +3 -0
- package/dist/ai/agents/orchestrator.d.ts.map +1 -1
- package/dist/ai/agents/orchestrator.js +3 -0
- package/dist/ai/agents/orchestrator.js.map +1 -1
- package/dist/ai/agents/planning-orchestrator.d.ts +12 -0
- package/dist/ai/agents/planning-orchestrator.d.ts.map +1 -0
- package/dist/ai/agents/planning-orchestrator.js +133 -0
- package/dist/ai/agents/planning-orchestrator.js.map +1 -0
- package/dist/ai/agents/stack-researcher.d.ts +3 -0
- package/dist/ai/agents/stack-researcher.d.ts.map +1 -1
- package/dist/ai/agents/stack-researcher.js +3 -0
- package/dist/ai/agents/stack-researcher.js.map +1 -1
- package/dist/ai/agents/stack-utils.d.ts +11 -0
- package/dist/ai/agents/stack-utils.d.ts.map +1 -0
- package/dist/ai/agents/stack-utils.js +27 -0
- package/dist/ai/agents/stack-utils.js.map +1 -0
- package/dist/ai/agents/synthesis-agent.d.ts +11 -0
- package/dist/ai/agents/synthesis-agent.d.ts.map +1 -0
- package/dist/ai/agents/synthesis-agent.js +202 -0
- package/dist/ai/agents/synthesis-agent.js.map +1 -0
- package/dist/ai/agents/tech-researcher.d.ts +16 -0
- package/dist/ai/agents/tech-researcher.d.ts.map +1 -0
- package/dist/ai/agents/tech-researcher.js +208 -0
- package/dist/ai/agents/tech-researcher.js.map +1 -0
- package/dist/ai/agents/types.d.ts +121 -0
- package/dist/ai/agents/types.d.ts.map +1 -1
- package/dist/ai/agents/types.js +6 -0
- package/dist/ai/agents/types.js.map +1 -1
- package/dist/ai/index.d.ts +1 -1
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +14 -2
- package/dist/ai/index.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +9 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/utils/tracing.d.ts +5 -0
- package/dist/utils/tracing.d.ts.map +1 -1
- package/dist/utils/tracing.js +40 -1
- package/dist/utils/tracing.js.map +1 -1
- package/package.json +5 -2
- package/src/ai/agents/codebase-analyst.ts +3 -0
- package/src/ai/agents/context-enricher.ts +189 -0
- package/src/ai/agents/evaluator-optimizer.ts +277 -0
- package/src/ai/agents/index.ts +197 -104
- package/src/ai/agents/mcp-detector.test.ts +290 -0
- package/src/ai/agents/mcp-detector.ts +210 -0
- package/src/ai/agents/orchestrator.ts +3 -0
- package/src/ai/agents/planning-orchestrator.ts +140 -0
- package/src/ai/agents/stack-researcher.ts +3 -0
- package/src/ai/agents/stack-utils.ts +34 -0
- package/src/ai/agents/synthesis-agent.ts +240 -0
- package/src/ai/agents/tech-researcher.ts +262 -0
- package/src/ai/agents/types.ts +153 -0
- package/src/ai/index.ts +26 -5
- package/src/commands/init.ts +10 -2
- package/src/utils/tracing.ts +44 -1
- package/tsconfig.json +1 -1
- package/vitest.config.ts +7 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tech Researcher Worker (Phase 2)
|
|
3
|
+
* Researches best practices for a specific technology
|
|
4
|
+
* Multiple instances run in parallel via runTechResearchPool
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { stepCountIs, type LanguageModel, type Tool } from 'ai';
|
|
8
|
+
import type { TechResearcherInput, TechResearchResult, AgentCapabilities, AgentOptions } from './types.js';
|
|
9
|
+
import { createTavilySearchTool } from '../tools/tavily.js';
|
|
10
|
+
import { createContext7Tool } from '../tools/context7.js';
|
|
11
|
+
import { isReasoningModel } from '../providers.js';
|
|
12
|
+
import { logger } from '../../utils/logger.js';
|
|
13
|
+
import { parseJsonSafe } from '../../utils/json-repair.js';
|
|
14
|
+
import { getTracedAI } from '../../utils/tracing.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* System prompt for Tech Researcher with tools
|
|
18
|
+
*/
|
|
19
|
+
const TECH_RESEARCHER_WITH_TOOLS_PROMPT = `You are a Tech Researcher worker focused on a single technology.
|
|
20
|
+
|
|
21
|
+
## Your Mission
|
|
22
|
+
Research the specified technology to find:
|
|
23
|
+
1. Current best practices (2024+)
|
|
24
|
+
2. Common anti-patterns to avoid
|
|
25
|
+
3. Testing tips and patterns
|
|
26
|
+
4. Useful documentation links
|
|
27
|
+
|
|
28
|
+
## Tools Available
|
|
29
|
+
- tavilySearch: Search the web for current best practices
|
|
30
|
+
- context7Lookup: Look up library documentation
|
|
31
|
+
|
|
32
|
+
## Research Strategy
|
|
33
|
+
1. Search for "[technology] best practices 2024"
|
|
34
|
+
2. Search for "[technology] testing patterns"
|
|
35
|
+
3. Look up documentation for key features
|
|
36
|
+
|
|
37
|
+
## Output Format
|
|
38
|
+
Output ONLY valid JSON:
|
|
39
|
+
{
|
|
40
|
+
"technology": "Next.js 14",
|
|
41
|
+
"bestPractices": ["Use App Router for new projects", "Enable strict TypeScript"],
|
|
42
|
+
"antiPatterns": ["Don't use pages/ and app/ together", "Avoid client components for static content"],
|
|
43
|
+
"testingTips": ["Use @testing-library/react", "Mock next/navigation for routing tests"],
|
|
44
|
+
"documentationHints": ["App Router: nextjs.org/docs/app", "Data Fetching: nextjs.org/docs/app/building-your-application/data-fetching"],
|
|
45
|
+
"researchMode": "full"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
Keep each item concise (5-15 words max). Max 5 items per array.`;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* System prompt for Tech Researcher without tools (knowledge-only)
|
|
52
|
+
*/
|
|
53
|
+
const TECH_RESEARCHER_KNOWLEDGE_ONLY_PROMPT = `You are a Tech Researcher worker. You don't have web access, so rely on your training knowledge.
|
|
54
|
+
|
|
55
|
+
## Your Mission
|
|
56
|
+
Based on your knowledge of the specified technology, provide:
|
|
57
|
+
1. Best practices (note if potentially outdated)
|
|
58
|
+
2. Common anti-patterns to avoid
|
|
59
|
+
3. Testing tips
|
|
60
|
+
4. Documentation hints
|
|
61
|
+
|
|
62
|
+
## Output Format
|
|
63
|
+
Output ONLY valid JSON:
|
|
64
|
+
{
|
|
65
|
+
"technology": "React",
|
|
66
|
+
"bestPractices": ["Use functional components with hooks", "Memoize expensive computations"],
|
|
67
|
+
"antiPatterns": ["Don't mutate state directly", "Avoid prop drilling"],
|
|
68
|
+
"testingTips": ["Use React Testing Library", "Test behavior not implementation"],
|
|
69
|
+
"documentationHints": ["React docs: react.dev", "Testing: testing-library.com"],
|
|
70
|
+
"researchMode": "knowledge-only"
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
Keep each item concise (5-15 words max). Max 5 items per array.`;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Determine research mode based on capabilities
|
|
77
|
+
*/
|
|
78
|
+
function getResearchMode(capabilities: AgentCapabilities): TechResearchResult['researchMode'] {
|
|
79
|
+
if (capabilities.hasTavily && capabilities.hasContext7) return 'full';
|
|
80
|
+
if (capabilities.hasTavily) return 'web-only';
|
|
81
|
+
if (capabilities.hasContext7) return 'docs-only';
|
|
82
|
+
return 'knowledge-only';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Run a single Tech Researcher worker for one technology
|
|
87
|
+
*/
|
|
88
|
+
export async function runTechResearcher(
|
|
89
|
+
model: LanguageModel,
|
|
90
|
+
modelId: string,
|
|
91
|
+
input: TechResearcherInput,
|
|
92
|
+
options: AgentOptions,
|
|
93
|
+
verbose: boolean = false
|
|
94
|
+
): Promise<TechResearchResult> {
|
|
95
|
+
const tools: Record<string, Tool> = {};
|
|
96
|
+
|
|
97
|
+
// Add tools based on available keys
|
|
98
|
+
if (options.tavilyApiKey) {
|
|
99
|
+
tools.tavilySearch = createTavilySearchTool(options.tavilyApiKey);
|
|
100
|
+
}
|
|
101
|
+
if (options.context7ApiKey) {
|
|
102
|
+
tools.context7Lookup = createContext7Tool(options.context7ApiKey);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const hasTools = Object.keys(tools).length > 0;
|
|
106
|
+
const researchMode = getResearchMode(input.capabilities);
|
|
107
|
+
|
|
108
|
+
if (verbose) {
|
|
109
|
+
logger.info(`Tech Researcher [${input.technology}]: ${researchMode} mode`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const systemPrompt = hasTools
|
|
113
|
+
? TECH_RESEARCHER_WITH_TOOLS_PROMPT
|
|
114
|
+
: TECH_RESEARCHER_KNOWLEDGE_ONLY_PROMPT;
|
|
115
|
+
|
|
116
|
+
const prompt = `Research best practices for: ${input.technology}
|
|
117
|
+
|
|
118
|
+
Provide current best practices, anti-patterns to avoid, testing tips, and documentation hints.
|
|
119
|
+
Output your findings as JSON.`;
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
const { generateText } = getTracedAI();
|
|
123
|
+
|
|
124
|
+
const result = await generateText({
|
|
125
|
+
model,
|
|
126
|
+
system: systemPrompt,
|
|
127
|
+
prompt,
|
|
128
|
+
...(hasTools ? { tools, stopWhen: stepCountIs(3) } : {}),
|
|
129
|
+
maxOutputTokens: 2000,
|
|
130
|
+
...(isReasoningModel(modelId) ? {} : { temperature: 0.3 }),
|
|
131
|
+
experimental_telemetry: {
|
|
132
|
+
isEnabled: true,
|
|
133
|
+
metadata: {
|
|
134
|
+
agent: 'tech-researcher',
|
|
135
|
+
technology: input.technology,
|
|
136
|
+
researchMode,
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const research = parseTechResearch(result.text, result.steps, input.technology, researchMode, verbose);
|
|
142
|
+
return research;
|
|
143
|
+
} catch (error) {
|
|
144
|
+
if (verbose) {
|
|
145
|
+
logger.error(`Tech Researcher [${input.technology}] error: ${error instanceof Error ? error.message : String(error)}`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return getDefaultTechResearch(input.technology, researchMode);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Run multiple Tech Researchers in parallel for a list of technologies
|
|
154
|
+
*/
|
|
155
|
+
export async function runTechResearchPool(
|
|
156
|
+
model: LanguageModel,
|
|
157
|
+
modelId: string,
|
|
158
|
+
technologies: string[],
|
|
159
|
+
options: AgentOptions,
|
|
160
|
+
verbose: boolean = false
|
|
161
|
+
): Promise<TechResearchResult[]> {
|
|
162
|
+
if (technologies.length === 0) {
|
|
163
|
+
return [];
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Determine capabilities once
|
|
167
|
+
const capabilities: AgentCapabilities = {
|
|
168
|
+
hasTavily: !!options.tavilyApiKey,
|
|
169
|
+
hasContext7: !!options.context7ApiKey,
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
if (verbose) {
|
|
173
|
+
logger.info(`Tech Research Pool: Starting ${technologies.length} parallel researchers`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Run all researchers in parallel
|
|
177
|
+
const results = await Promise.all(
|
|
178
|
+
technologies.map(technology =>
|
|
179
|
+
runTechResearcher(
|
|
180
|
+
model,
|
|
181
|
+
modelId,
|
|
182
|
+
{ technology, capabilities },
|
|
183
|
+
options,
|
|
184
|
+
verbose
|
|
185
|
+
)
|
|
186
|
+
)
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
if (verbose) {
|
|
190
|
+
logger.info(`Tech Research Pool: Completed ${results.length} research tasks`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return results;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Parse tech research from agent response
|
|
198
|
+
*/
|
|
199
|
+
function parseTechResearch(
|
|
200
|
+
text: string,
|
|
201
|
+
steps: Array<{ text?: string }> | undefined,
|
|
202
|
+
technology: string,
|
|
203
|
+
researchMode: TechResearchResult['researchMode'],
|
|
204
|
+
verbose: boolean
|
|
205
|
+
): TechResearchResult {
|
|
206
|
+
// Try to get text from the result or steps
|
|
207
|
+
let textToParse = text;
|
|
208
|
+
|
|
209
|
+
if (!textToParse || textToParse.trim() === '') {
|
|
210
|
+
const stepsList = steps || [];
|
|
211
|
+
for (let i = stepsList.length - 1; i >= 0; i--) {
|
|
212
|
+
const step = stepsList[i];
|
|
213
|
+
if (step.text && step.text.trim() !== '') {
|
|
214
|
+
textToParse = step.text;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (!textToParse || textToParse.trim() === '') {
|
|
221
|
+
if (verbose) {
|
|
222
|
+
logger.warn(`Tech Researcher [${technology}]: No text output found`);
|
|
223
|
+
}
|
|
224
|
+
return getDefaultTechResearch(technology, researchMode);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Use safe JSON parser with repair capabilities
|
|
228
|
+
const parsed = parseJsonSafe<Partial<TechResearchResult>>(textToParse);
|
|
229
|
+
|
|
230
|
+
if (!parsed) {
|
|
231
|
+
if (verbose) {
|
|
232
|
+
logger.warn(`Tech Researcher [${technology}]: Failed to parse JSON response`);
|
|
233
|
+
}
|
|
234
|
+
return getDefaultTechResearch(technology, researchMode);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
technology,
|
|
239
|
+
bestPractices: parsed.bestPractices || [],
|
|
240
|
+
antiPatterns: parsed.antiPatterns || [],
|
|
241
|
+
testingTips: parsed.testingTips || [],
|
|
242
|
+
documentationHints: parsed.documentationHints || [],
|
|
243
|
+
researchMode,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Get default tech research when parsing fails
|
|
249
|
+
*/
|
|
250
|
+
function getDefaultTechResearch(
|
|
251
|
+
technology: string,
|
|
252
|
+
researchMode: TechResearchResult['researchMode']
|
|
253
|
+
): TechResearchResult {
|
|
254
|
+
return {
|
|
255
|
+
technology,
|
|
256
|
+
bestPractices: ['Follow official documentation', 'Use TypeScript for type safety'],
|
|
257
|
+
antiPatterns: ['Avoid deprecated APIs', 'Don\'t skip error handling'],
|
|
258
|
+
testingTips: ['Write unit tests for core logic', 'Test edge cases'],
|
|
259
|
+
documentationHints: [`Check official ${technology} documentation`],
|
|
260
|
+
researchMode,
|
|
261
|
+
};
|
|
262
|
+
}
|
package/src/ai/agents/types.ts
CHANGED
|
@@ -1,12 +1,122 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Agent Types and Interfaces
|
|
3
3
|
* Defines the structure for multi-agent analysis
|
|
4
|
+
*
|
|
5
|
+
* Architecture: Orchestrator-Worker + Evaluator-Optimizer
|
|
6
|
+
* Phase 1: Planning Orchestrator (creates analysis plan)
|
|
7
|
+
* Phase 2: Parallel Workers (context enricher + tech researchers)
|
|
8
|
+
* Phase 3: Synthesis (merge results + MCP detection)
|
|
9
|
+
* Phase 4: Evaluator-Optimizer (QA loop)
|
|
4
10
|
*/
|
|
5
11
|
|
|
6
12
|
import type { ScanResult, DetectedStack } from '../../scanner/types.js';
|
|
7
13
|
|
|
14
|
+
// ============================================================
|
|
15
|
+
// Phase 1: Planning Orchestrator Types
|
|
16
|
+
// ============================================================
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Analysis plan created by the Planning Orchestrator
|
|
20
|
+
* Guides the parallel workers in Phase 2
|
|
21
|
+
*/
|
|
22
|
+
export interface AnalysisPlan {
|
|
23
|
+
/** Key areas to explore in the codebase */
|
|
24
|
+
areasToExplore: string[];
|
|
25
|
+
/** Technologies to research in depth */
|
|
26
|
+
technologiesToResearch: string[];
|
|
27
|
+
/** Specific questions that need answers for implementation guidance */
|
|
28
|
+
questionsToAnswer: string[];
|
|
29
|
+
/** Estimated complexity of the project */
|
|
30
|
+
estimatedComplexity: 'low' | 'medium' | 'high';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ============================================================
|
|
34
|
+
// Phase 2: Worker Types
|
|
35
|
+
// ============================================================
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Enriched context from codebase exploration
|
|
39
|
+
* Output from the Context Enricher worker
|
|
40
|
+
*/
|
|
41
|
+
export interface EnrichedContext {
|
|
42
|
+
/** Key entry point files */
|
|
43
|
+
entryPoints: string[];
|
|
44
|
+
/** Important directories and their purposes */
|
|
45
|
+
keyDirectories: Record<string, string>;
|
|
46
|
+
/** Naming conventions used */
|
|
47
|
+
namingConventions: string;
|
|
48
|
+
/** Detected commands from package.json */
|
|
49
|
+
commands: Record<string, string>;
|
|
50
|
+
/** Answers to the orchestrator's questions */
|
|
51
|
+
answeredQuestions: Record<string, string>;
|
|
52
|
+
/** The primary project type detected */
|
|
53
|
+
projectType: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Research result for a single technology
|
|
58
|
+
* Output from a Tech Researcher worker
|
|
59
|
+
*/
|
|
60
|
+
export interface TechResearchResult {
|
|
61
|
+
/** Technology that was researched */
|
|
62
|
+
technology: string;
|
|
63
|
+
/** Best practices for this technology */
|
|
64
|
+
bestPractices: string[];
|
|
65
|
+
/** Anti-patterns to avoid */
|
|
66
|
+
antiPatterns: string[];
|
|
67
|
+
/** Testing tips and tools */
|
|
68
|
+
testingTips: string[];
|
|
69
|
+
/** Documentation hints and links */
|
|
70
|
+
documentationHints: string[];
|
|
71
|
+
/** Whether research used tools or knowledge only */
|
|
72
|
+
researchMode: 'full' | 'web-only' | 'docs-only' | 'knowledge-only';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ============================================================
|
|
76
|
+
// Phase 3: Synthesis Types
|
|
77
|
+
// ============================================================
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* MCP servers focused on ralph loop essentials
|
|
81
|
+
*/
|
|
82
|
+
export interface RalphMcpServers {
|
|
83
|
+
/** Database MCP server if applicable */
|
|
84
|
+
database?: string;
|
|
85
|
+
/** E2E testing MCP (always playwright for ralph) */
|
|
86
|
+
e2eTesting: string;
|
|
87
|
+
/** Any additional recommended MCPs */
|
|
88
|
+
additional: string[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ============================================================
|
|
92
|
+
// Phase 4: Evaluator-Optimizer Types
|
|
93
|
+
// ============================================================
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Evaluation result from the QA evaluator
|
|
97
|
+
*/
|
|
98
|
+
export interface EvaluationResult {
|
|
99
|
+
/** Quality score from 1-10 */
|
|
100
|
+
qualityScore: number;
|
|
101
|
+
/** Whether entry points were identified */
|
|
102
|
+
hasEntryPoints: boolean;
|
|
103
|
+
/** Whether implementation guidelines were provided */
|
|
104
|
+
hasImplementationGuidelines: boolean;
|
|
105
|
+
/** Whether relevant MCP servers were recommended */
|
|
106
|
+
hasRelevantMcpServers: boolean;
|
|
107
|
+
/** Specific issues found */
|
|
108
|
+
specificIssues: string[];
|
|
109
|
+
/** Suggestions for improvement */
|
|
110
|
+
improvementSuggestions: string[];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ============================================================
|
|
114
|
+
// Legacy Types (kept for backward compatibility)
|
|
115
|
+
// ============================================================
|
|
116
|
+
|
|
8
117
|
/**
|
|
9
118
|
* Codebase analysis result from the Codebase Analyst agent
|
|
119
|
+
* @deprecated Use EnrichedContext for new code
|
|
10
120
|
*/
|
|
11
121
|
export interface CodebaseAnalysis {
|
|
12
122
|
/** Project structure and context */
|
|
@@ -121,6 +231,7 @@ export interface StackResearcherInput {
|
|
|
121
231
|
|
|
122
232
|
/**
|
|
123
233
|
* Input for the Orchestrator agent
|
|
234
|
+
* @deprecated Use new agent architecture
|
|
124
235
|
*/
|
|
125
236
|
export interface OrchestratorInput {
|
|
126
237
|
/** Codebase analysis result */
|
|
@@ -130,3 +241,45 @@ export interface OrchestratorInput {
|
|
|
130
241
|
/** The detected stack */
|
|
131
242
|
stack: DetectedStack;
|
|
132
243
|
}
|
|
244
|
+
|
|
245
|
+
// ============================================================
|
|
246
|
+
// New Agent Input Types
|
|
247
|
+
// ============================================================
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Input for the Context Enricher worker
|
|
251
|
+
*/
|
|
252
|
+
export interface ContextEnricherInput {
|
|
253
|
+
/** The scan result from the scanner */
|
|
254
|
+
scanResult: ScanResult;
|
|
255
|
+
/** Areas to explore from the analysis plan */
|
|
256
|
+
areasToExplore: string[];
|
|
257
|
+
/** Questions to answer from the analysis plan */
|
|
258
|
+
questionsToAnswer: string[];
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Input for a Tech Researcher worker
|
|
263
|
+
*/
|
|
264
|
+
export interface TechResearcherInput {
|
|
265
|
+
/** Technology to research */
|
|
266
|
+
technology: string;
|
|
267
|
+
/** Agent capabilities (determines which tools are available) */
|
|
268
|
+
capabilities: AgentCapabilities;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Input for the Synthesis agent
|
|
273
|
+
*/
|
|
274
|
+
export interface SynthesisInput {
|
|
275
|
+
/** Enriched context from codebase exploration */
|
|
276
|
+
enrichedContext: EnrichedContext;
|
|
277
|
+
/** Research results for each technology */
|
|
278
|
+
techResearch: TechResearchResult[];
|
|
279
|
+
/** Detected MCP servers */
|
|
280
|
+
mcpServers: RalphMcpServers;
|
|
281
|
+
/** The original analysis plan */
|
|
282
|
+
plan: AnalysisPlan;
|
|
283
|
+
/** The detected stack from scanner */
|
|
284
|
+
stack: DetectedStack;
|
|
285
|
+
}
|
package/src/ai/index.ts
CHANGED
|
@@ -44,19 +44,40 @@ export {
|
|
|
44
44
|
canUseContext7,
|
|
45
45
|
} from './tools/index.js';
|
|
46
46
|
|
|
47
|
-
// Agents
|
|
47
|
+
// Agents - New 4-phase architecture
|
|
48
48
|
export {
|
|
49
|
+
// Main orchestration
|
|
49
50
|
runMultiAgentAnalysis,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
// Phase 1: Planning
|
|
52
|
+
runPlanningOrchestrator,
|
|
53
|
+
// Phase 2: Parallel workers
|
|
54
|
+
runContextEnricher,
|
|
55
|
+
runTechResearcher,
|
|
56
|
+
runTechResearchPool,
|
|
57
|
+
// Phase 3: Synthesis + MCP detection
|
|
58
|
+
runSynthesisAgent,
|
|
59
|
+
detectRalphMcpServers,
|
|
60
|
+
convertToLegacyMcpRecommendations,
|
|
61
|
+
// Phase 4: QA loop
|
|
62
|
+
runEvaluatorOptimizer,
|
|
63
|
+
// New types
|
|
64
|
+
type AnalysisPlan,
|
|
65
|
+
type EnrichedContext,
|
|
66
|
+
type TechResearchResult,
|
|
67
|
+
type RalphMcpServers,
|
|
68
|
+
type EvaluationResult,
|
|
69
|
+
// Legacy types (backward compatibility)
|
|
54
70
|
type CodebaseAnalysis,
|
|
55
71
|
type StackResearch,
|
|
56
72
|
type McpRecommendations,
|
|
57
73
|
type MultiAgentAnalysis,
|
|
58
74
|
type AgentCapabilities,
|
|
59
75
|
type AgentOptions,
|
|
76
|
+
// Legacy agents (deprecated, kept for backward compatibility)
|
|
77
|
+
runCodebaseAnalyst,
|
|
78
|
+
runStackResearcher,
|
|
79
|
+
runOrchestrator,
|
|
80
|
+
mergeAgentResults,
|
|
60
81
|
} from './agents/index.js';
|
|
61
82
|
|
|
62
83
|
// AI enhancer
|
package/src/commands/init.ts
CHANGED
|
@@ -26,6 +26,7 @@ import pc from 'picocolors';
|
|
|
26
26
|
import fs from 'fs';
|
|
27
27
|
import path from 'path';
|
|
28
28
|
import { simpson, sectionHeader, drawLine } from '../utils/colors.js';
|
|
29
|
+
import { flushTracing } from '../utils/tracing.js';
|
|
29
30
|
|
|
30
31
|
export interface InitOptions {
|
|
31
32
|
provider?: AIProvider;
|
|
@@ -109,8 +110,8 @@ async function collectApiKeys(
|
|
|
109
110
|
const providerChoice = await prompts.select({
|
|
110
111
|
message: 'Select your AI provider:',
|
|
111
112
|
options: [
|
|
112
|
-
{ value: 'anthropic', label: 'Anthropic
|
|
113
|
-
{ value: 'openai', label: 'OpenAI
|
|
113
|
+
{ value: 'anthropic', label: 'Anthropic', hint: 'recommended' },
|
|
114
|
+
{ value: 'openai', label: 'OpenAI' },
|
|
114
115
|
{ value: 'openrouter', label: 'OpenRouter', hint: 'multiple providers' },
|
|
115
116
|
],
|
|
116
117
|
});
|
|
@@ -261,6 +262,7 @@ export async function initCommand(options: InitOptions): Promise<void> {
|
|
|
261
262
|
if (!apiKeys) {
|
|
262
263
|
// In --yes mode, null means missing API key (hard failure)
|
|
263
264
|
// In interactive mode, null means user cancelled
|
|
265
|
+
await flushTracing();
|
|
264
266
|
if (options.yes) {
|
|
265
267
|
process.exit(1);
|
|
266
268
|
}
|
|
@@ -281,6 +283,7 @@ export async function initCommand(options: InitOptions): Promise<void> {
|
|
|
281
283
|
} catch (error) {
|
|
282
284
|
spinner.stop('Scan failed');
|
|
283
285
|
logger.error(`Failed to scan project: ${error instanceof Error ? error.message : String(error)}`);
|
|
286
|
+
await flushTracing();
|
|
284
287
|
process.exit(1);
|
|
285
288
|
}
|
|
286
289
|
|
|
@@ -342,6 +345,7 @@ export async function initCommand(options: InitOptions): Promise<void> {
|
|
|
342
345
|
});
|
|
343
346
|
|
|
344
347
|
if (prompts.isCancel(shouldContinue) || !shouldContinue) {
|
|
348
|
+
await flushTracing();
|
|
345
349
|
logger.info('Initialization cancelled');
|
|
346
350
|
return;
|
|
347
351
|
}
|
|
@@ -365,6 +369,9 @@ export async function initCommand(options: InitOptions): Promise<void> {
|
|
|
365
369
|
console.log(simpson.yellow('─── Generation Results ───'));
|
|
366
370
|
console.log(formatGenerationResult(generationResult));
|
|
367
371
|
|
|
372
|
+
// Flush tracing spans before completing
|
|
373
|
+
await flushTracing();
|
|
374
|
+
|
|
368
375
|
if (generationResult.success) {
|
|
369
376
|
console.log('');
|
|
370
377
|
logger.success('Ralph initialized successfully!');
|
|
@@ -380,6 +387,7 @@ export async function initCommand(options: InitOptions): Promise<void> {
|
|
|
380
387
|
} catch (error) {
|
|
381
388
|
spinner.stop('Generation failed');
|
|
382
389
|
logger.error(`Failed to generate files: ${error instanceof Error ? error.message : String(error)}`);
|
|
390
|
+
await flushTracing();
|
|
383
391
|
process.exit(1);
|
|
384
392
|
}
|
|
385
393
|
}
|
package/src/utils/tracing.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Provides AI call tracing for debugging and analysis
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { initLogger, wrapAISDK } from 'braintrust';
|
|
6
|
+
import { initLogger, wrapAISDK, flush as braintrustFlush } from 'braintrust';
|
|
7
7
|
import * as ai from 'ai';
|
|
8
8
|
|
|
9
9
|
// Re-export traced utilities
|
|
@@ -13,6 +13,7 @@ export { traced, currentSpan, wrapTraced } from 'braintrust';
|
|
|
13
13
|
* Initialize Braintrust logger if API key is available
|
|
14
14
|
*/
|
|
15
15
|
let loggerInitialized = false;
|
|
16
|
+
let exitHandlersRegistered = false;
|
|
16
17
|
|
|
17
18
|
export function initTracing(): void {
|
|
18
19
|
if (loggerInitialized) return;
|
|
@@ -29,11 +30,53 @@ export function initTracing(): void {
|
|
|
29
30
|
projectName: process.env.BRAINTRUST_PROJECT_NAME || 'wiggum-cli',
|
|
30
31
|
});
|
|
31
32
|
loggerInitialized = true;
|
|
33
|
+
|
|
34
|
+
// Register exit handlers to flush spans before process exits
|
|
35
|
+
registerExitHandlers();
|
|
32
36
|
} catch {
|
|
33
37
|
// Silently fail if tracing can't be initialized
|
|
34
38
|
}
|
|
35
39
|
}
|
|
36
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Register process exit handlers to flush tracing spans
|
|
43
|
+
*/
|
|
44
|
+
function registerExitHandlers(): void {
|
|
45
|
+
if (exitHandlersRegistered) return;
|
|
46
|
+
exitHandlersRegistered = true;
|
|
47
|
+
|
|
48
|
+
// Flush on normal exit
|
|
49
|
+
process.on('beforeExit', async () => {
|
|
50
|
+
await flushTracing();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Flush on SIGINT (Ctrl+C)
|
|
54
|
+
process.on('SIGINT', async () => {
|
|
55
|
+
await flushTracing();
|
|
56
|
+
process.exit(0);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Flush on SIGTERM
|
|
60
|
+
process.on('SIGTERM', async () => {
|
|
61
|
+
await flushTracing();
|
|
62
|
+
process.exit(0);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Flush all pending tracing spans to Braintrust
|
|
68
|
+
* Call this before process exit to ensure all spans are recorded
|
|
69
|
+
*/
|
|
70
|
+
export async function flushTracing(): Promise<void> {
|
|
71
|
+
if (!loggerInitialized) return;
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
await braintrustFlush();
|
|
75
|
+
} catch {
|
|
76
|
+
// Silently fail if flush fails
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
37
80
|
/**
|
|
38
81
|
* Check if tracing is enabled
|
|
39
82
|
*/
|
package/tsconfig.json
CHANGED