wiggum-cli 0.2.6 → 0.3.1

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 (89) hide show
  1. package/README.md +73 -60
  2. package/dist/ai/agents/codebase-analyst.d.ts +11 -0
  3. package/dist/ai/agents/codebase-analyst.d.ts.map +1 -0
  4. package/dist/ai/agents/codebase-analyst.js +146 -0
  5. package/dist/ai/agents/codebase-analyst.js.map +1 -0
  6. package/dist/ai/agents/index.d.ts +16 -0
  7. package/dist/ai/agents/index.d.ts.map +1 -0
  8. package/dist/ai/agents/index.js +85 -0
  9. package/dist/ai/agents/index.js.map +1 -0
  10. package/dist/ai/agents/orchestrator.d.ts +15 -0
  11. package/dist/ai/agents/orchestrator.d.ts.map +1 -0
  12. package/dist/ai/agents/orchestrator.js +181 -0
  13. package/dist/ai/agents/orchestrator.js.map +1 -0
  14. package/dist/ai/agents/stack-researcher.d.ts +15 -0
  15. package/dist/ai/agents/stack-researcher.d.ts.map +1 -0
  16. package/dist/ai/agents/stack-researcher.js +269 -0
  17. package/dist/ai/agents/stack-researcher.js.map +1 -0
  18. package/dist/ai/agents/types.d.ts +123 -0
  19. package/dist/ai/agents/types.d.ts.map +1 -0
  20. package/dist/ai/agents/types.js +6 -0
  21. package/dist/ai/agents/types.js.map +1 -0
  22. package/dist/ai/enhancer.d.ts +39 -1
  23. package/dist/ai/enhancer.d.ts.map +1 -1
  24. package/dist/ai/enhancer.js +78 -36
  25. package/dist/ai/enhancer.js.map +1 -1
  26. package/dist/ai/index.d.ts +4 -2
  27. package/dist/ai/index.d.ts.map +1 -1
  28. package/dist/ai/index.js +5 -1
  29. package/dist/ai/index.js.map +1 -1
  30. package/dist/ai/prompts.d.ts +2 -2
  31. package/dist/ai/prompts.d.ts.map +1 -1
  32. package/dist/ai/prompts.js +66 -4
  33. package/dist/ai/prompts.js.map +1 -1
  34. package/dist/ai/providers.d.ts +28 -0
  35. package/dist/ai/providers.d.ts.map +1 -1
  36. package/dist/ai/providers.js +40 -0
  37. package/dist/ai/providers.js.map +1 -1
  38. package/dist/ai/tools/context7.d.ts +34 -0
  39. package/dist/ai/tools/context7.d.ts.map +1 -0
  40. package/dist/ai/tools/context7.js +135 -0
  41. package/dist/ai/tools/context7.js.map +1 -0
  42. package/dist/ai/tools/index.d.ts +7 -0
  43. package/dist/ai/tools/index.d.ts.map +1 -0
  44. package/dist/ai/tools/index.js +7 -0
  45. package/dist/ai/tools/index.js.map +1 -0
  46. package/dist/ai/tools/tavily.d.ts +27 -0
  47. package/dist/ai/tools/tavily.d.ts.map +1 -0
  48. package/dist/ai/tools/tavily.js +75 -0
  49. package/dist/ai/tools/tavily.js.map +1 -0
  50. package/dist/cli.d.ts.map +1 -1
  51. package/dist/cli.js +14 -12
  52. package/dist/cli.js.map +1 -1
  53. package/dist/commands/init.d.ts +2 -5
  54. package/dist/commands/init.d.ts.map +1 -1
  55. package/dist/commands/init.js +233 -154
  56. package/dist/commands/init.js.map +1 -1
  57. package/dist/utils/colors.d.ts.map +1 -1
  58. package/dist/utils/colors.js +10 -3
  59. package/dist/utils/colors.js.map +1 -1
  60. package/dist/utils/header.d.ts +1 -1
  61. package/dist/utils/header.js +3 -3
  62. package/dist/utils/header.js.map +1 -1
  63. package/dist/utils/json-repair.d.ts +14 -0
  64. package/dist/utils/json-repair.d.ts.map +1 -0
  65. package/dist/utils/json-repair.js +103 -0
  66. package/dist/utils/json-repair.js.map +1 -0
  67. package/dist/utils/tracing.d.ts +25 -0
  68. package/dist/utils/tracing.d.ts.map +1 -0
  69. package/dist/utils/tracing.js +64 -0
  70. package/dist/utils/tracing.js.map +1 -0
  71. package/package.json +5 -3
  72. package/src/ai/agents/codebase-analyst.ts +169 -0
  73. package/src/ai/agents/index.ts +147 -0
  74. package/src/ai/agents/orchestrator.ts +218 -0
  75. package/src/ai/agents/stack-researcher.ts +294 -0
  76. package/src/ai/agents/types.ts +132 -0
  77. package/src/ai/enhancer.ts +128 -38
  78. package/src/ai/index.ts +31 -1
  79. package/src/ai/prompts.ts +67 -4
  80. package/src/ai/providers.ts +48 -0
  81. package/src/ai/tools/context7.ts +167 -0
  82. package/src/ai/tools/index.ts +17 -0
  83. package/src/ai/tools/tavily.ts +101 -0
  84. package/src/cli.ts +14 -12
  85. package/src/commands/init.ts +278 -173
  86. package/src/utils/colors.ts +11 -3
  87. package/src/utils/header.ts +3 -3
  88. package/src/utils/json-repair.ts +113 -0
  89. package/src/utils/tracing.ts +76 -0
@@ -0,0 +1,103 @@
1
+ /**
2
+ * JSON Repair Utility
3
+ * Fixes common JSON syntax errors from AI responses
4
+ */
5
+ /**
6
+ * Attempt to repair malformed JSON from AI responses
7
+ */
8
+ export function repairJson(text) {
9
+ let json = text;
10
+ // Remove any leading/trailing whitespace
11
+ json = json.trim();
12
+ // Remove trailing commas before ] or }
13
+ json = json.replace(/,(\s*[\]}])/g, '$1');
14
+ // Fix missing commas between array elements or object properties
15
+ // Pattern: value followed by newline and another value without comma
16
+ json = json.replace(/("|\d|true|false|null|\]|\})(\s*\n\s*)("|\[|\{)/g, '$1,$2$3');
17
+ // Fix single quotes to double quotes (but not inside strings)
18
+ // This is a simplified approach - may not work for all cases
19
+ json = json.replace(/'/g, '"');
20
+ // Remove JavaScript-style comments
21
+ json = json.replace(/\/\/.*$/gm, '');
22
+ json = json.replace(/\/\*[\s\S]*?\*\//g, '');
23
+ // Fix unquoted keys (simple cases)
24
+ json = json.replace(/(\{|\,)\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:/g, '$1"$2":');
25
+ // Remove any text before the first { or [
26
+ const firstBrace = json.indexOf('{');
27
+ const firstBracket = json.indexOf('[');
28
+ let startIndex = -1;
29
+ if (firstBrace !== -1 && firstBracket !== -1) {
30
+ startIndex = Math.min(firstBrace, firstBracket);
31
+ }
32
+ else if (firstBrace !== -1) {
33
+ startIndex = firstBrace;
34
+ }
35
+ else if (firstBracket !== -1) {
36
+ startIndex = firstBracket;
37
+ }
38
+ if (startIndex > 0) {
39
+ json = json.substring(startIndex);
40
+ }
41
+ // Remove any text after the last } or ]
42
+ const lastBrace = json.lastIndexOf('}');
43
+ const lastBracket = json.lastIndexOf(']');
44
+ let endIndex = -1;
45
+ if (lastBrace !== -1 && lastBracket !== -1) {
46
+ endIndex = Math.max(lastBrace, lastBracket);
47
+ }
48
+ else if (lastBrace !== -1) {
49
+ endIndex = lastBrace;
50
+ }
51
+ else if (lastBracket !== -1) {
52
+ endIndex = lastBracket;
53
+ }
54
+ if (endIndex !== -1 && endIndex < json.length - 1) {
55
+ json = json.substring(0, endIndex + 1);
56
+ }
57
+ return json;
58
+ }
59
+ /**
60
+ * Parse JSON with repair attempts
61
+ * Tries to fix common issues before parsing
62
+ */
63
+ export function parseJsonSafe(text) {
64
+ // First try parsing as-is
65
+ try {
66
+ return JSON.parse(text);
67
+ }
68
+ catch {
69
+ // Try with repairs
70
+ }
71
+ // Try repairing the JSON
72
+ try {
73
+ const repaired = repairJson(text);
74
+ return JSON.parse(repaired);
75
+ }
76
+ catch {
77
+ // Repair failed
78
+ }
79
+ // Last resort: try to extract JSON from markdown code blocks
80
+ const jsonMatch = text.match(/```(?:json)?\s*([\s\S]*?)```/);
81
+ if (jsonMatch) {
82
+ try {
83
+ const repaired = repairJson(jsonMatch[1]);
84
+ return JSON.parse(repaired);
85
+ }
86
+ catch {
87
+ // Still failed
88
+ }
89
+ }
90
+ // Try finding a JSON object
91
+ const objectMatch = text.match(/\{[\s\S]*\}/);
92
+ if (objectMatch) {
93
+ try {
94
+ const repaired = repairJson(objectMatch[0]);
95
+ return JSON.parse(repaired);
96
+ }
97
+ catch {
98
+ // Still failed
99
+ }
100
+ }
101
+ return null;
102
+ }
103
+ //# 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,11 +1,11 @@
1
1
  {
2
2
  "name": "wiggum-cli",
3
- "version": "0.2.6",
3
+ "version": "0.3.1",
4
4
  "description": "AI-powered feature development loop CLI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
8
- "ralph": "./bin/ralph.js"
8
+ "wiggum": "./bin/ralph.js"
9
9
  },
10
10
  "scripts": {
11
11
  "build": "tsc && npm run copy-templates",
@@ -23,13 +23,15 @@
23
23
  "code-generation",
24
24
  "tech-stack-detection"
25
25
  ],
26
- "author": "Ralph CLI Contributors",
26
+ "author": "Wiggum CLI Contributors",
27
27
  "license": "MIT",
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",
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Codebase Analyst Agent
3
+ * Explores the codebase to understand its structure and patterns
4
+ */
5
+
6
+ import { stepCountIs, type LanguageModel } from 'ai';
7
+ import type { CodebaseAnalysis, CodebaseAnalystInput } from './types.js';
8
+ import { createExplorationTools } from '../tools.js';
9
+ import { isReasoningModel } from '../providers.js';
10
+ import { logger } from '../../utils/logger.js';
11
+ import { parseJsonSafe } from '../../utils/json-repair.js';
12
+ import { getTracedAI } from '../../utils/tracing.js';
13
+
14
+ /**
15
+ * System prompt for the Codebase Analyst agent
16
+ */
17
+ const CODEBASE_ANALYST_SYSTEM_PROMPT = `You are a Codebase Analyst agent. Your job is to thoroughly explore a codebase and produce a structured analysis.
18
+
19
+ ## Your Mission
20
+ Explore the codebase to understand:
21
+ 1. Project structure and entry points
22
+ 2. Key directories and their purposes
23
+ 3. Naming conventions
24
+ 4. Available commands (from package.json)
25
+ 5. The primary project type
26
+
27
+ ## Exploration Strategy
28
+ 1. First, list the root directory to understand project structure
29
+ 2. Read package.json to understand scripts and dependencies
30
+ 3. Search for key patterns: entry points, routes, components
31
+ 4. Identify the PROJECT TYPE:
32
+ - MCP Server: Has @modelcontextprotocol dependencies
33
+ - REST API: Express/Fastify/Hono with route handlers
34
+ - React SPA: React with components, no server-side rendering
35
+ - Next.js App: Next.js with app or pages directory
36
+ - CLI Tool: Has bin entry in package.json
37
+ - Library: Published package without app entry
38
+
39
+ ## Tools Available
40
+ - searchCode: Search using ripgrep patterns
41
+ - readFile: Read file contents
42
+ - listDirectory: List directory structure
43
+ - getPackageInfo: Get package.json info
44
+
45
+ ## Output Format
46
+ After exploration, output ONLY valid JSON with this exact structure:
47
+ {
48
+ "projectContext": {
49
+ "entryPoints": ["src/index.ts"],
50
+ "keyDirectories": {"src/routes": "API routes"},
51
+ "namingConventions": "camelCase files, PascalCase components",
52
+ "projectType": "MCP Server"
53
+ },
54
+ "commands": {
55
+ "test": "npm test",
56
+ "lint": "npm run lint",
57
+ "build": "npm run build",
58
+ "dev": "npm run dev"
59
+ },
60
+ "implementationGuidelines": [
61
+ "Run npm test after changes",
62
+ "Use Zod for validation"
63
+ ],
64
+ "possibleMissedTechnologies": ["Redis"]
65
+ }
66
+
67
+ Keep each guideline to 5-10 words max. Max 7 guidelines.`;
68
+
69
+ /**
70
+ * Run the Codebase Analyst agent
71
+ */
72
+ export async function runCodebaseAnalyst(
73
+ model: LanguageModel,
74
+ modelId: string,
75
+ input: CodebaseAnalystInput,
76
+ verbose: boolean = false
77
+ ): Promise<CodebaseAnalysis | null> {
78
+ const tools = createExplorationTools(input.projectRoot);
79
+
80
+ const prompt = `Analyze this codebase and produce a structured analysis.
81
+
82
+ Project: ${input.projectRoot}
83
+
84
+ Start by exploring the directory structure and package.json, then produce your analysis as JSON.`;
85
+
86
+ try {
87
+ const { generateText } = getTracedAI();
88
+
89
+ const result = await generateText({
90
+ model,
91
+ system: CODEBASE_ANALYST_SYSTEM_PROMPT,
92
+ prompt,
93
+ tools,
94
+ stopWhen: stepCountIs(12),
95
+ maxOutputTokens: 3000,
96
+ ...(isReasoningModel(modelId) ? {} : { temperature: 0.3 }),
97
+ experimental_telemetry: {
98
+ isEnabled: true,
99
+ metadata: { agent: 'codebase-analyst', projectRoot: input.projectRoot },
100
+ },
101
+ });
102
+
103
+ // Extract JSON from response
104
+ const analysis = parseCodebaseAnalysis(result.text, result.steps, verbose);
105
+ return analysis;
106
+ } catch (error) {
107
+ if (verbose) {
108
+ logger.error(`Codebase Analyst error: ${error instanceof Error ? error.message : String(error)}`);
109
+ }
110
+ return null;
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Parse the codebase analysis from agent response
116
+ */
117
+ function parseCodebaseAnalysis(
118
+ text: string,
119
+ steps: Array<{ text?: string }> | undefined,
120
+ verbose: boolean
121
+ ): CodebaseAnalysis | null {
122
+ // Try to get text from the result or steps
123
+ let textToParse = text;
124
+
125
+ if (!textToParse || textToParse.trim() === '') {
126
+ // Look through steps for text content
127
+ const stepsList = steps || [];
128
+ for (let i = stepsList.length - 1; i >= 0; i--) {
129
+ const step = stepsList[i];
130
+ if (step.text && step.text.trim() !== '') {
131
+ textToParse = step.text;
132
+ break;
133
+ }
134
+ }
135
+ }
136
+
137
+ if (!textToParse || textToParse.trim() === '') {
138
+ if (verbose) {
139
+ logger.warn('Codebase Analyst: No text output found');
140
+ }
141
+ return null;
142
+ }
143
+
144
+ // Use safe JSON parser with repair capabilities
145
+ const parsed = parseJsonSafe<CodebaseAnalysis>(textToParse);
146
+
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)}...`);
151
+ }
152
+ return null;
153
+ }
154
+
155
+ // Validate required fields
156
+ if (!parsed.projectContext || !parsed.commands) {
157
+ if (verbose) {
158
+ logger.warn('Codebase Analyst: Missing required fields in response');
159
+ }
160
+ return null;
161
+ }
162
+
163
+ // Ensure projectType is set
164
+ if (!parsed.projectContext.projectType) {
165
+ parsed.projectContext.projectType = 'Unknown';
166
+ }
167
+
168
+ return parsed;
169
+ }
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Agents Index
3
+ * Exports all agent types and functions
4
+ */
5
+
6
+ // Types
7
+ export type {
8
+ CodebaseAnalysis,
9
+ StackResearch,
10
+ McpRecommendations,
11
+ MultiAgentAnalysis,
12
+ AgentCapabilities,
13
+ AgentOptions,
14
+ CodebaseAnalystInput,
15
+ StackResearcherInput,
16
+ OrchestratorInput,
17
+ } from './types.js';
18
+
19
+ // Agents
20
+ export { runCodebaseAnalyst } from './codebase-analyst.js';
21
+ export { runStackResearcher } from './stack-researcher.js';
22
+ export { runOrchestrator, mergeAgentResults } from './orchestrator.js';
23
+
24
+ // Re-export for convenience
25
+ import type { LanguageModel } from 'ai';
26
+ import type { ScanResult, DetectedStack } from '../../scanner/types.js';
27
+ import type {
28
+ MultiAgentAnalysis,
29
+ AgentCapabilities,
30
+ AgentOptions,
31
+ } from './types.js';
32
+ import { runCodebaseAnalyst } from './codebase-analyst.js';
33
+ import { runStackResearcher } from './stack-researcher.js';
34
+ import { runOrchestrator, mergeAgentResults } from './orchestrator.js';
35
+ import { logger } from '../../utils/logger.js';
36
+
37
+ /**
38
+ * Run the full multi-agent analysis pipeline
39
+ */
40
+ export async function runMultiAgentAnalysis(
41
+ model: LanguageModel,
42
+ modelId: string,
43
+ scanResult: ScanResult,
44
+ options: AgentOptions = {}
45
+ ): Promise<MultiAgentAnalysis | null> {
46
+ const { tavilyApiKey, context7ApiKey, verbose = false } = options;
47
+
48
+ // Determine capabilities
49
+ const capabilities: AgentCapabilities = {
50
+ hasTavily: !!tavilyApiKey,
51
+ hasContext7: !!context7ApiKey,
52
+ };
53
+
54
+ if (verbose) {
55
+ logger.info('Starting multi-agent analysis...');
56
+ logger.info(`Capabilities: Tavily=${capabilities.hasTavily}, Context7=${capabilities.hasContext7}`);
57
+ }
58
+
59
+ // Run Codebase Analyst
60
+ if (verbose) {
61
+ logger.info('Running Codebase Analyst...');
62
+ }
63
+
64
+ const codebaseAnalysis = await runCodebaseAnalyst(
65
+ model,
66
+ modelId,
67
+ {
68
+ scanResult,
69
+ projectRoot: scanResult.projectRoot,
70
+ },
71
+ verbose
72
+ );
73
+
74
+ if (!codebaseAnalysis) {
75
+ if (verbose) {
76
+ logger.warn('Codebase Analyst failed, using defaults');
77
+ }
78
+ return null;
79
+ }
80
+
81
+ // Run Stack Researcher
82
+ if (verbose) {
83
+ logger.info('Running Stack Researcher...');
84
+ }
85
+
86
+ const stackResearch = await runStackResearcher(
87
+ model,
88
+ modelId,
89
+ {
90
+ stack: scanResult.stack,
91
+ projectType: codebaseAnalysis.projectContext.projectType,
92
+ capabilities,
93
+ },
94
+ { tavilyApiKey, context7ApiKey },
95
+ verbose
96
+ );
97
+
98
+ if (!stackResearch) {
99
+ if (verbose) {
100
+ logger.warn('Stack Researcher failed, using defaults');
101
+ }
102
+ // Continue with defaults - stack research is optional
103
+ }
104
+
105
+ // Run Orchestrator to merge results
106
+ if (verbose) {
107
+ logger.info('Running Orchestrator...');
108
+ }
109
+
110
+ const mcpServers = await runOrchestrator(
111
+ model,
112
+ modelId,
113
+ {
114
+ codebaseAnalysis,
115
+ stackResearch: stackResearch || getDefaultStackResearch(),
116
+ stack: scanResult.stack,
117
+ },
118
+ verbose
119
+ );
120
+
121
+ // Merge all results
122
+ const finalResult = mergeAgentResults(
123
+ codebaseAnalysis,
124
+ stackResearch || getDefaultStackResearch(),
125
+ mcpServers
126
+ );
127
+
128
+ if (verbose) {
129
+ logger.info('Multi-agent analysis complete');
130
+ }
131
+
132
+ return finalResult;
133
+ }
134
+
135
+ /**
136
+ * Get default stack research when agent fails
137
+ */
138
+ function getDefaultStackResearch() {
139
+ return {
140
+ bestPractices: ['Follow project conventions'],
141
+ antiPatterns: ['Avoid skipping tests'],
142
+ testingTools: ['npm test'],
143
+ debuggingTools: ['console.log'],
144
+ documentationHints: ['Check official docs'],
145
+ researchMode: 'knowledge-only' as const,
146
+ };
147
+ }