wiggum-cli 0.2.5 → 0.3.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.
Files changed (79) 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 +150 -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 +187 -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 +274 -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 +105 -9
  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/package.json +3 -3
  64. package/src/ai/agents/codebase-analyst.ts +172 -0
  65. package/src/ai/agents/index.ts +147 -0
  66. package/src/ai/agents/orchestrator.ts +222 -0
  67. package/src/ai/agents/stack-researcher.ts +298 -0
  68. package/src/ai/agents/types.ts +132 -0
  69. package/src/ai/enhancer.ts +159 -9
  70. package/src/ai/index.ts +31 -1
  71. package/src/ai/prompts.ts +67 -4
  72. package/src/ai/providers.ts +48 -0
  73. package/src/ai/tools/context7.ts +167 -0
  74. package/src/ai/tools/index.ts +17 -0
  75. package/src/ai/tools/tavily.ts +101 -0
  76. package/src/cli.ts +14 -12
  77. package/src/commands/init.ts +278 -173
  78. package/src/utils/colors.ts +11 -3
  79. package/src/utils/header.ts +3 -3
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Codebase Analyst Agent
3
+ * Explores the codebase to understand its structure and patterns
4
+ */
5
+
6
+ import { generateText, 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
+
12
+ /**
13
+ * System prompt for the Codebase Analyst agent
14
+ */
15
+ const CODEBASE_ANALYST_SYSTEM_PROMPT = `You are a Codebase Analyst agent. Your job is to thoroughly explore a codebase and produce a structured analysis.
16
+
17
+ ## Your Mission
18
+ Explore the codebase to understand:
19
+ 1. Project structure and entry points
20
+ 2. Key directories and their purposes
21
+ 3. Naming conventions
22
+ 4. Available commands (from package.json)
23
+ 5. The primary project type
24
+
25
+ ## Exploration Strategy
26
+ 1. First, list the root directory to understand project structure
27
+ 2. Read package.json to understand scripts and dependencies
28
+ 3. Search for key patterns: entry points, routes, components
29
+ 4. Identify the PROJECT TYPE:
30
+ - MCP Server: Has @modelcontextprotocol dependencies
31
+ - REST API: Express/Fastify/Hono with route handlers
32
+ - React SPA: React with components, no server-side rendering
33
+ - Next.js App: Next.js with app or pages directory
34
+ - CLI Tool: Has bin entry in package.json
35
+ - Library: Published package without app entry
36
+
37
+ ## Tools Available
38
+ - searchCode: Search using ripgrep patterns
39
+ - readFile: Read file contents
40
+ - listDirectory: List directory structure
41
+ - getPackageInfo: Get package.json info
42
+
43
+ ## Output Format
44
+ After exploration, output ONLY valid JSON with this exact structure:
45
+ {
46
+ "projectContext": {
47
+ "entryPoints": ["src/index.ts"],
48
+ "keyDirectories": {"src/routes": "API routes"},
49
+ "namingConventions": "camelCase files, PascalCase components",
50
+ "projectType": "MCP Server"
51
+ },
52
+ "commands": {
53
+ "test": "npm test",
54
+ "lint": "npm run lint",
55
+ "build": "npm run build",
56
+ "dev": "npm run dev"
57
+ },
58
+ "implementationGuidelines": [
59
+ "Run npm test after changes",
60
+ "Use Zod for validation"
61
+ ],
62
+ "possibleMissedTechnologies": ["Redis"]
63
+ }
64
+
65
+ Keep each guideline to 5-10 words max. Max 7 guidelines.`;
66
+
67
+ /**
68
+ * Run the Codebase Analyst agent
69
+ */
70
+ export async function runCodebaseAnalyst(
71
+ model: LanguageModel,
72
+ modelId: string,
73
+ input: CodebaseAnalystInput,
74
+ verbose: boolean = false
75
+ ): Promise<CodebaseAnalysis | null> {
76
+ const tools = createExplorationTools(input.projectRoot);
77
+
78
+ const prompt = `Analyze this codebase and produce a structured analysis.
79
+
80
+ Project: ${input.projectRoot}
81
+
82
+ Start by exploring the directory structure and package.json, then produce your analysis as JSON.`;
83
+
84
+ try {
85
+ const result = await generateText({
86
+ model,
87
+ system: CODEBASE_ANALYST_SYSTEM_PROMPT,
88
+ prompt,
89
+ tools,
90
+ stopWhen: stepCountIs(12),
91
+ maxOutputTokens: 3000,
92
+ ...(isReasoningModel(modelId) ? {} : { temperature: 0.3 }),
93
+ });
94
+
95
+ // Extract JSON from response
96
+ const analysis = parseCodebaseAnalysis(result.text, result.steps, verbose);
97
+ return analysis;
98
+ } catch (error) {
99
+ if (verbose) {
100
+ logger.error(`Codebase Analyst error: ${error instanceof Error ? error.message : String(error)}`);
101
+ }
102
+ return null;
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Parse the codebase analysis from agent response
108
+ */
109
+ function parseCodebaseAnalysis(
110
+ text: string,
111
+ steps: Array<{ text?: string }> | undefined,
112
+ verbose: boolean
113
+ ): CodebaseAnalysis | null {
114
+ // Try to get text from the result or steps
115
+ let textToParse = text;
116
+
117
+ if (!textToParse || textToParse.trim() === '') {
118
+ // Look through steps for text content
119
+ const stepsList = steps || [];
120
+ for (let i = stepsList.length - 1; i >= 0; i--) {
121
+ const step = stepsList[i];
122
+ if (step.text && step.text.trim() !== '') {
123
+ textToParse = step.text;
124
+ break;
125
+ }
126
+ }
127
+ }
128
+
129
+ if (!textToParse || textToParse.trim() === '') {
130
+ if (verbose) {
131
+ logger.warn('Codebase Analyst: No text output found');
132
+ }
133
+ return null;
134
+ }
135
+
136
+ try {
137
+ // Remove markdown code blocks if present
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
+ }
159
+
160
+ // Ensure projectType is set
161
+ if (!parsed.projectContext.projectType) {
162
+ parsed.projectContext.projectType = 'Unknown';
163
+ }
164
+
165
+ return parsed;
166
+ } catch (error) {
167
+ if (verbose) {
168
+ logger.warn(`Codebase Analyst: Failed to parse JSON - ${error instanceof Error ? error.message : String(error)}`);
169
+ }
170
+ return null;
171
+ }
172
+ }
@@ -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
+ }
@@ -0,0 +1,222 @@
1
+ /**
2
+ * Orchestrator Agent
3
+ * Coordinates the multi-agent analysis and merges results
4
+ */
5
+
6
+ import { generateText, type LanguageModel } from 'ai';
7
+ import type {
8
+ CodebaseAnalysis,
9
+ StackResearch,
10
+ MultiAgentAnalysis,
11
+ McpRecommendations,
12
+ OrchestratorInput,
13
+ } from './types.js';
14
+ import type { DetectedStack } from '../../scanner/types.js';
15
+ import { isReasoningModel } from '../providers.js';
16
+ import { logger } from '../../utils/logger.js';
17
+
18
+ /**
19
+ * System prompt for the Orchestrator
20
+ */
21
+ const ORCHESTRATOR_SYSTEM_PROMPT = `You are an Orchestrator agent that merges analysis results into final recommendations.
22
+
23
+ Your job is to:
24
+ 1. Review the codebase analysis and stack research
25
+ 2. Recommend appropriate MCP servers for the stack
26
+ 3. Produce a final merged recommendation
27
+
28
+ ## MCP Server Selection Guidelines
29
+ Based on the detected stack, recommend these MCP servers:
30
+
31
+ **Always Essential:**
32
+ - filesystem: For file operations (all projects)
33
+ - git: For version control (all projects)
34
+
35
+ **By Project Type:**
36
+ - MCP Server: memory (for context)
37
+ - REST API: fetch (external APIs), postgres/sqlite (databases)
38
+ - React/Next.js: fetch (data fetching), memory (state persistence)
39
+ - CLI Tool: filesystem (primary), memory (caching)
40
+ - Library: git (versioning)
41
+
42
+ **By Technology:**
43
+ - Docker in use → docker MCP server
44
+ - PostgreSQL → postgres MCP server
45
+ - SQLite → sqlite MCP server
46
+ - AWS services → aws-kb-retrieval MCP server
47
+ - GitHub workflows → github MCP server
48
+
49
+ ## Output Format
50
+ Output ONLY valid JSON:
51
+ {
52
+ "mcpServers": {
53
+ "essential": ["filesystem", "git"],
54
+ "recommended": ["docker", "postgres"]
55
+ }
56
+ }`;
57
+
58
+ /**
59
+ * Run the Orchestrator to merge results and recommend MCP servers
60
+ */
61
+ export async function runOrchestrator(
62
+ model: LanguageModel,
63
+ modelId: string,
64
+ input: OrchestratorInput,
65
+ verbose: boolean = false
66
+ ): Promise<McpRecommendations> {
67
+ const prompt = createOrchestratorPrompt(input);
68
+
69
+ try {
70
+ const result = await generateText({
71
+ model,
72
+ system: ORCHESTRATOR_SYSTEM_PROMPT,
73
+ prompt,
74
+ maxOutputTokens: 1000,
75
+ ...(isReasoningModel(modelId) ? {} : { temperature: 0.2 }),
76
+ });
77
+
78
+ const mcpServers = parseMcpRecommendations(result.text, input.stack, verbose);
79
+ return mcpServers;
80
+ } catch (error) {
81
+ if (verbose) {
82
+ logger.error(`Orchestrator error: ${error instanceof Error ? error.message : String(error)}`);
83
+ }
84
+ // Return default recommendations based on project type
85
+ return getDefaultMcpRecommendations(input.codebaseAnalysis.projectContext.projectType, input.stack);
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Create the orchestrator prompt
91
+ */
92
+ function createOrchestratorPrompt(input: OrchestratorInput): string {
93
+ const { codebaseAnalysis, stackResearch, stack } = input;
94
+
95
+ // Summarize the stack
96
+ const stackSummary: string[] = [];
97
+ if (stack.framework) stackSummary.push(`Framework: ${stack.framework.name}`);
98
+ if (stack.database) stackSummary.push(`Database: ${stack.database.name}`);
99
+ if (stack.orm) stackSummary.push(`ORM: ${stack.orm.name}`);
100
+ if (stack.deployment?.length) stackSummary.push(`Deployment: ${stack.deployment.map(d => d.name).join(', ')}`);
101
+ if (stack.mcp?.isProject) stackSummary.push('This is an MCP Server project');
102
+
103
+ return `Analyze these results and recommend MCP servers:
104
+
105
+ ## Project Type
106
+ ${codebaseAnalysis.projectContext.projectType}
107
+
108
+ ## Detected Stack
109
+ ${stackSummary.join('\n') || 'Unknown'}
110
+
111
+ ## Testing Tools Identified
112
+ ${stackResearch.testingTools.join(', ') || 'None identified'}
113
+
114
+ ## Debugging Tools
115
+ ${stackResearch.debuggingTools.join(', ') || 'None identified'}
116
+
117
+ Based on this analysis, recommend essential and optional MCP servers.
118
+ Output as JSON with "mcpServers" containing "essential" and "recommended" arrays.`;
119
+ }
120
+
121
+ /**
122
+ * Parse MCP recommendations from orchestrator response
123
+ */
124
+ function parseMcpRecommendations(
125
+ text: string,
126
+ stack: DetectedStack,
127
+ verbose: boolean
128
+ ): McpRecommendations {
129
+ if (!text || text.trim() === '') {
130
+ return getDefaultMcpRecommendations('Unknown', stack);
131
+ }
132
+
133
+ try {
134
+ // Remove markdown code blocks
135
+ let jsonText = text;
136
+ const jsonMatch = text.match(/```(?:json)?\s*([\s\S]*?)```/);
137
+ if (jsonMatch) {
138
+ jsonText = jsonMatch[1];
139
+ }
140
+
141
+ // Find JSON object
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) {
158
+ if (verbose) {
159
+ logger.warn(`Orchestrator: Failed to parse JSON - ${error instanceof Error ? error.message : String(error)}`);
160
+ }
161
+ return getDefaultMcpRecommendations('Unknown', stack);
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Get default MCP recommendations based on project type and stack
167
+ */
168
+ function getDefaultMcpRecommendations(projectType: string, stack: DetectedStack): McpRecommendations {
169
+ const essential: string[] = ['filesystem', 'git'];
170
+ const recommended: string[] = [];
171
+
172
+ // Add based on project type
173
+ const lowerType = projectType.toLowerCase();
174
+
175
+ if (lowerType.includes('mcp')) {
176
+ recommended.push('memory');
177
+ }
178
+
179
+ if (lowerType.includes('api') || lowerType.includes('server')) {
180
+ recommended.push('fetch');
181
+ }
182
+
183
+ // Add based on detected stack
184
+ if (stack.database) {
185
+ const dbName = stack.database.name.toLowerCase();
186
+ if (dbName.includes('postgres')) {
187
+ recommended.push('postgres');
188
+ } else if (dbName.includes('sqlite')) {
189
+ recommended.push('sqlite');
190
+ }
191
+ }
192
+
193
+ if (stack.deployment?.some(d => d.name.toLowerCase().includes('docker'))) {
194
+ recommended.push('docker');
195
+ }
196
+
197
+ // Add from existing MCP recommendations in stack
198
+ if (stack.mcp?.recommended) {
199
+ for (const rec of stack.mcp.recommended) {
200
+ if (!essential.includes(rec) && !recommended.includes(rec)) {
201
+ recommended.push(rec);
202
+ }
203
+ }
204
+ }
205
+
206
+ return { essential, recommended };
207
+ }
208
+
209
+ /**
210
+ * Merge all agent results into a final MultiAgentAnalysis
211
+ */
212
+ export function mergeAgentResults(
213
+ codebaseAnalysis: CodebaseAnalysis,
214
+ stackResearch: StackResearch,
215
+ mcpServers: McpRecommendations
216
+ ): MultiAgentAnalysis {
217
+ return {
218
+ codebaseAnalysis,
219
+ stackResearch,
220
+ mcpServers,
221
+ };
222
+ }