wiggum-cli 0.4.4 → 0.4.5
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/context-enricher.d.ts +10 -0
- package/dist/ai/agents/context-enricher.d.ts.map +1 -1
- package/dist/ai/agents/context-enricher.js +63 -4
- package/dist/ai/agents/context-enricher.js.map +1 -1
- package/dist/ai/agents/index.js +3 -2
- package/dist/ai/agents/index.js.map +1 -1
- package/dist/ai/agents/mcp-detector.d.ts +3 -2
- package/dist/ai/agents/mcp-detector.d.ts.map +1 -1
- package/dist/ai/agents/mcp-detector.js +23 -3
- package/dist/ai/agents/mcp-detector.js.map +1 -1
- package/dist/ai/agents/stack-researcher.js +2 -0
- package/dist/ai/agents/stack-researcher.js.map +1 -1
- package/dist/ai/agents/synthesis-agent.d.ts.map +1 -1
- package/dist/ai/agents/synthesis-agent.js +32 -9
- package/dist/ai/agents/synthesis-agent.js.map +1 -1
- package/dist/ai/agents/tech-researcher.d.ts +11 -0
- package/dist/ai/agents/tech-researcher.d.ts.map +1 -1
- package/dist/ai/agents/tech-researcher.js +71 -1
- package/dist/ai/agents/tech-researcher.js.map +1 -1
- package/dist/ai/agents/types.d.ts +2 -0
- package/dist/ai/agents/types.d.ts.map +1 -1
- package/dist/ai/enhancer.js +1 -1
- package/dist/ai/enhancer.js.map +1 -1
- package/package.json +1 -1
- package/src/ai/agents/context-enricher.test.ts +190 -0
- package/src/ai/agents/context-enricher.ts +69 -4
- package/src/ai/agents/index.ts +3 -2
- package/src/ai/agents/mcp-detector.test.ts +64 -9
- package/src/ai/agents/mcp-detector.ts +23 -3
- package/src/ai/agents/stack-researcher.ts +2 -0
- package/src/ai/agents/synthesis-agent.ts +46 -9
- package/src/ai/agents/tech-researcher.test.ts +156 -0
- package/src/ai/agents/tech-researcher.ts +86 -1
- package/src/ai/agents/types.ts +2 -0
- package/src/ai/enhancer.ts +1 -1
|
@@ -24,6 +24,11 @@ import { getTracedAI } from '../../utils/tracing.js';
|
|
|
24
24
|
const synthesisOutputSchema = z.object({
|
|
25
25
|
implementationGuidelines: z.array(z.string()).describe('Short, actionable implementation guidelines'),
|
|
26
26
|
possibleMissedTechnologies: z.array(z.string()).describe('Technologies that may have been missed (empty array if none)'),
|
|
27
|
+
technologyTools: z.object({
|
|
28
|
+
testing: z.array(z.string()).describe('Commands to run tests (e.g., "npm test", "npx vitest")'),
|
|
29
|
+
debugging: z.array(z.string()).describe('Debug flags, env vars, tools (e.g., "DEBUG=* npm run dev")'),
|
|
30
|
+
validation: z.array(z.string()).describe('Type checking, linting commands (e.g., "npm run lint", "npx tsc --noEmit")'),
|
|
31
|
+
}).optional(),
|
|
27
32
|
});
|
|
28
33
|
|
|
29
34
|
/**
|
|
@@ -35,6 +40,7 @@ const SYNTHESIS_AGENT_SYSTEM_PROMPT = `You are a Synthesis Agent that merges ana
|
|
|
35
40
|
Based on the enriched context and technology research, generate:
|
|
36
41
|
1. Short implementation guidelines (5-10 words each) describing DISCOVERED patterns
|
|
37
42
|
2. List any technologies that may have been missed
|
|
43
|
+
3. Technology tools for testing, debugging, and validation
|
|
38
44
|
|
|
39
45
|
## Guidelines Style
|
|
40
46
|
- Describe DISCOVERED patterns, not instructions to follow
|
|
@@ -48,6 +54,12 @@ Based on the enriched context and technology research, generate:
|
|
|
48
54
|
- Bad: "Use Zod for validation"
|
|
49
55
|
- Max 7 patterns, prioritize most distinctive features
|
|
50
56
|
|
|
57
|
+
## Technology Tools
|
|
58
|
+
Based on the detected stack and available commands, provide:
|
|
59
|
+
- testing: Commands to verify changes (e.g., "npm test", "npx vitest")
|
|
60
|
+
- debugging: How to debug (e.g., "DEBUG=* npm run dev", "--verbose flag", "NODE_DEBUG=http")
|
|
61
|
+
- validation: Pre-commit checks (e.g., "npm run lint", "npx tsc --noEmit")
|
|
62
|
+
|
|
51
63
|
## Example Output
|
|
52
64
|
{
|
|
53
65
|
"implementationGuidelines": [
|
|
@@ -57,7 +69,12 @@ Based on the enriched context and technology research, generate:
|
|
|
57
69
|
"Zod schemas in src/schemas for API validation",
|
|
58
70
|
"Playwright E2E tests in tests/e2e"
|
|
59
71
|
],
|
|
60
|
-
"possibleMissedTechnologies": ["Redis caching"]
|
|
72
|
+
"possibleMissedTechnologies": ["Redis caching"],
|
|
73
|
+
"technologyTools": {
|
|
74
|
+
"testing": ["npm test", "npx vitest --watch"],
|
|
75
|
+
"debugging": ["DEBUG=* npm run dev", "--verbose flag"],
|
|
76
|
+
"validation": ["npm run lint", "npx tsc --noEmit"]
|
|
77
|
+
}
|
|
61
78
|
}`;
|
|
62
79
|
|
|
63
80
|
/**
|
|
@@ -121,7 +138,7 @@ Generate concise, actionable implementation guidelines based on this analysis.`;
|
|
|
121
138
|
}
|
|
122
139
|
|
|
123
140
|
// Convert to MultiAgentAnalysis format for backward compatibility
|
|
124
|
-
return buildMultiAgentAnalysis(input, synthesis.implementationGuidelines, synthesis.possibleMissedTechnologies);
|
|
141
|
+
return buildMultiAgentAnalysis(input, synthesis.implementationGuidelines, synthesis.possibleMissedTechnologies, synthesis.technologyTools);
|
|
125
142
|
} catch (error) {
|
|
126
143
|
if (verbose) {
|
|
127
144
|
logger.error(`Synthesis Agent error: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -132,13 +149,23 @@ Generate concise, actionable implementation guidelines based on this analysis.`;
|
|
|
132
149
|
}
|
|
133
150
|
}
|
|
134
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Technology tools output from synthesis
|
|
154
|
+
*/
|
|
155
|
+
interface TechnologyTools {
|
|
156
|
+
testing?: string[];
|
|
157
|
+
debugging?: string[];
|
|
158
|
+
validation?: string[];
|
|
159
|
+
}
|
|
160
|
+
|
|
135
161
|
/**
|
|
136
162
|
* Build MultiAgentAnalysis from synthesis input and generated guidelines
|
|
137
163
|
*/
|
|
138
164
|
function buildMultiAgentAnalysis(
|
|
139
165
|
input: SynthesisInput,
|
|
140
166
|
implementationGuidelines: string[],
|
|
141
|
-
possibleMissedTechnologies?: string[]
|
|
167
|
+
possibleMissedTechnologies?: string[],
|
|
168
|
+
technologyTools?: TechnologyTools
|
|
142
169
|
): MultiAgentAnalysis {
|
|
143
170
|
// Convert EnrichedContext to CodebaseAnalysis format
|
|
144
171
|
const codebaseAnalysis: CodebaseAnalysis = {
|
|
@@ -161,7 +188,7 @@ function buildMultiAgentAnalysis(
|
|
|
161
188
|
};
|
|
162
189
|
|
|
163
190
|
// Merge tech research into StackResearch format
|
|
164
|
-
const stackResearch: StackResearch = mergeTechResearch(input.techResearch);
|
|
191
|
+
const stackResearch: StackResearch = mergeTechResearch(input.techResearch, technologyTools);
|
|
165
192
|
|
|
166
193
|
// Convert MCP servers to legacy format
|
|
167
194
|
const mcpServers: McpRecommendations = convertToLegacyMcpRecommendations(input.mcpServers);
|
|
@@ -176,13 +203,22 @@ function buildMultiAgentAnalysis(
|
|
|
176
203
|
/**
|
|
177
204
|
* Merge multiple TechResearchResult into a single StackResearch
|
|
178
205
|
*/
|
|
179
|
-
function mergeTechResearch(
|
|
206
|
+
function mergeTechResearch(
|
|
207
|
+
techResearch: SynthesisInput['techResearch'],
|
|
208
|
+
technologyTools?: TechnologyTools
|
|
209
|
+
): StackResearch {
|
|
210
|
+
// Use technologyTools from synthesis if available
|
|
211
|
+
const synthesisTesting = technologyTools?.testing || [];
|
|
212
|
+
const synthesisDebugging = technologyTools?.debugging || [];
|
|
213
|
+
const synthesisValidation = technologyTools?.validation || [];
|
|
214
|
+
|
|
180
215
|
if (techResearch.length === 0) {
|
|
181
216
|
return {
|
|
182
217
|
bestPractices: ['Follow project conventions'],
|
|
183
218
|
antiPatterns: ['Avoid skipping tests'],
|
|
184
|
-
testingTools: ['npm test'],
|
|
185
|
-
debuggingTools: ['console.log'],
|
|
219
|
+
testingTools: synthesisTesting.length > 0 ? synthesisTesting : ['npm test'],
|
|
220
|
+
debuggingTools: synthesisDebugging.length > 0 ? synthesisDebugging : ['console.log'],
|
|
221
|
+
validationTools: synthesisValidation.length > 0 ? synthesisValidation : ['npm run lint'],
|
|
186
222
|
documentationHints: ['Check official docs'],
|
|
187
223
|
researchMode: 'knowledge-only',
|
|
188
224
|
};
|
|
@@ -191,7 +227,7 @@ function mergeTechResearch(techResearch: SynthesisInput['techResearch']): StackR
|
|
|
191
227
|
// Merge all research results
|
|
192
228
|
const bestPractices: string[] = [];
|
|
193
229
|
const antiPatterns: string[] = [];
|
|
194
|
-
const testingTips: string[] = [];
|
|
230
|
+
const testingTips: string[] = [...synthesisTesting]; // Start with synthesis testing tools
|
|
195
231
|
const documentationHints: string[] = [];
|
|
196
232
|
let researchMode: StackResearch['researchMode'] = 'knowledge-only';
|
|
197
233
|
|
|
@@ -212,7 +248,8 @@ function mergeTechResearch(techResearch: SynthesisInput['techResearch']): StackR
|
|
|
212
248
|
bestPractices: [...new Set(bestPractices)].slice(0, 10),
|
|
213
249
|
antiPatterns: [...new Set(antiPatterns)].slice(0, 10),
|
|
214
250
|
testingTools: [...new Set(testingTips)].slice(0, 5),
|
|
215
|
-
debuggingTools: [],
|
|
251
|
+
debuggingTools: [...new Set(synthesisDebugging)].slice(0, 5),
|
|
252
|
+
validationTools: [...new Set(synthesisValidation)].slice(0, 5),
|
|
216
253
|
documentationHints: [...new Set(documentationHints)].slice(0, 5),
|
|
217
254
|
researchMode,
|
|
218
255
|
};
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Tech Researcher
|
|
3
|
+
*
|
|
4
|
+
* Run with: npx vitest run src/ai/agents/tech-researcher.test.ts
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect } from 'vitest';
|
|
8
|
+
import { getDocumentationHints, DOCUMENTATION_HINTS } from './tech-researcher.js';
|
|
9
|
+
|
|
10
|
+
describe('getDocumentationHints', () => {
|
|
11
|
+
describe('direct matches', () => {
|
|
12
|
+
it('returns hints for exact match "Next.js"', () => {
|
|
13
|
+
const result = getDocumentationHints('Next.js');
|
|
14
|
+
expect(result).toEqual(DOCUMENTATION_HINTS['Next.js']);
|
|
15
|
+
expect(result).toContain('https://nextjs.org/docs/app');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('returns hints for exact match "React"', () => {
|
|
19
|
+
const result = getDocumentationHints('React');
|
|
20
|
+
expect(result).toEqual(DOCUMENTATION_HINTS['React']);
|
|
21
|
+
expect(result).toContain('https://react.dev');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('returns hints for exact match "MCP"', () => {
|
|
25
|
+
const result = getDocumentationHints('MCP');
|
|
26
|
+
expect(result).toEqual(DOCUMENTATION_HINTS['MCP']);
|
|
27
|
+
expect(result).toContain('https://modelcontextprotocol.io/docs');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('returns hints for exact match "Vitest"', () => {
|
|
31
|
+
const result = getDocumentationHints('Vitest');
|
|
32
|
+
expect(result).toEqual(DOCUMENTATION_HINTS['Vitest']);
|
|
33
|
+
expect(result).toContain('https://vitest.dev/guide');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('returns hints for exact match "TypeScript"', () => {
|
|
37
|
+
const result = getDocumentationHints('TypeScript');
|
|
38
|
+
expect(result).toEqual(DOCUMENTATION_HINTS['TypeScript']);
|
|
39
|
+
expect(result).toContain('https://www.typescriptlang.org/docs');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('partial matches (case-insensitive)', () => {
|
|
44
|
+
it('matches "next.js" (lowercase) to Next.js', () => {
|
|
45
|
+
const result = getDocumentationHints('next.js');
|
|
46
|
+
expect(result).toEqual(DOCUMENTATION_HINTS['Next.js']);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('matches "REACT" (uppercase) to React', () => {
|
|
50
|
+
const result = getDocumentationHints('REACT');
|
|
51
|
+
expect(result).toEqual(DOCUMENTATION_HINTS['React']);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('matches "typescript" (lowercase) to TypeScript', () => {
|
|
55
|
+
const result = getDocumentationHints('typescript');
|
|
56
|
+
expect(result).toEqual(DOCUMENTATION_HINTS['TypeScript']);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('matches "vitest" (lowercase) to Vitest', () => {
|
|
60
|
+
const result = getDocumentationHints('vitest');
|
|
61
|
+
expect(result).toEqual(DOCUMENTATION_HINTS['Vitest']);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('partial string matches', () => {
|
|
66
|
+
it('matches "Next.js 14" to Next.js', () => {
|
|
67
|
+
const result = getDocumentationHints('Next.js 14');
|
|
68
|
+
expect(result).toEqual(DOCUMENTATION_HINTS['Next.js']);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('matches "React 18" to React', () => {
|
|
72
|
+
const result = getDocumentationHints('React 18');
|
|
73
|
+
expect(result).toEqual(DOCUMENTATION_HINTS['React']);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('matches "MCP Server" key exactly', () => {
|
|
77
|
+
const result = getDocumentationHints('MCP Server');
|
|
78
|
+
expect(result).toEqual(DOCUMENTATION_HINTS['MCP Server']);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('fallback behavior', () => {
|
|
83
|
+
it('returns generic hint for unknown technology', () => {
|
|
84
|
+
const result = getDocumentationHints('UnknownFramework');
|
|
85
|
+
expect(result).toEqual(['Check official UnknownFramework documentation']);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('returns generic hint for empty string', () => {
|
|
89
|
+
const result = getDocumentationHints('');
|
|
90
|
+
expect(result).toEqual(['Check official documentation']);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('returns generic hint for technology not in mapping', () => {
|
|
94
|
+
const result = getDocumentationHints('SomeRandomLib');
|
|
95
|
+
expect(result).toEqual(['Check official SomeRandomLib documentation']);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('specific technology coverage', () => {
|
|
100
|
+
it('has MCP ecosystem hints', () => {
|
|
101
|
+
expect(DOCUMENTATION_HINTS['MCP']).toBeDefined();
|
|
102
|
+
expect(DOCUMENTATION_HINTS['MCP Server']).toBeDefined();
|
|
103
|
+
expect(DOCUMENTATION_HINTS['@modelcontextprotocol/sdk']).toBeDefined();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('has frontend framework hints', () => {
|
|
107
|
+
expect(DOCUMENTATION_HINTS['Next.js']).toBeDefined();
|
|
108
|
+
expect(DOCUMENTATION_HINTS['React']).toBeDefined();
|
|
109
|
+
expect(DOCUMENTATION_HINTS['Vue']).toBeDefined();
|
|
110
|
+
expect(DOCUMENTATION_HINTS['Svelte']).toBeDefined();
|
|
111
|
+
expect(DOCUMENTATION_HINTS['Nuxt']).toBeDefined();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('has backend framework hints', () => {
|
|
115
|
+
expect(DOCUMENTATION_HINTS['Express']).toBeDefined();
|
|
116
|
+
expect(DOCUMENTATION_HINTS['Fastify']).toBeDefined();
|
|
117
|
+
expect(DOCUMENTATION_HINTS['Hono']).toBeDefined();
|
|
118
|
+
expect(DOCUMENTATION_HINTS['NestJS']).toBeDefined();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('has testing tool hints', () => {
|
|
122
|
+
expect(DOCUMENTATION_HINTS['Vitest']).toBeDefined();
|
|
123
|
+
expect(DOCUMENTATION_HINTS['Jest']).toBeDefined();
|
|
124
|
+
expect(DOCUMENTATION_HINTS['Playwright']).toBeDefined();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('has database/ORM hints', () => {
|
|
128
|
+
expect(DOCUMENTATION_HINTS['Prisma']).toBeDefined();
|
|
129
|
+
expect(DOCUMENTATION_HINTS['Drizzle']).toBeDefined();
|
|
130
|
+
expect(DOCUMENTATION_HINTS['Supabase']).toBeDefined();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('has CLI tool hints', () => {
|
|
134
|
+
expect(DOCUMENTATION_HINTS['Commander']).toBeDefined();
|
|
135
|
+
expect(DOCUMENTATION_HINTS['Yargs']).toBeDefined();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe('DOCUMENTATION_HINTS', () => {
|
|
141
|
+
it('has valid URLs for all entries', () => {
|
|
142
|
+
for (const [tech, hints] of Object.entries(DOCUMENTATION_HINTS)) {
|
|
143
|
+
expect(Array.isArray(hints)).toBe(true);
|
|
144
|
+
expect(hints.length).toBeGreaterThan(0);
|
|
145
|
+
for (const hint of hints) {
|
|
146
|
+
expect(hint).toMatch(/^https?:\/\//);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('has no duplicate entries', () => {
|
|
152
|
+
const keys = Object.keys(DOCUMENTATION_HINTS);
|
|
153
|
+
const uniqueKeys = new Set(keys);
|
|
154
|
+
expect(keys.length).toBe(uniqueKeys.size);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
@@ -13,6 +13,90 @@ import { logger } from '../../utils/logger.js';
|
|
|
13
13
|
import { parseJsonSafe } from '../../utils/json-repair.js';
|
|
14
14
|
import { getTracedAI } from '../../utils/tracing.js';
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Documentation hints mapping for common technologies
|
|
18
|
+
* Used to provide useful links when AI research fails or as supplements
|
|
19
|
+
* Exported for testing
|
|
20
|
+
*/
|
|
21
|
+
export const DOCUMENTATION_HINTS: Record<string, string[]> = {
|
|
22
|
+
// MCP ecosystem
|
|
23
|
+
'MCP': ['https://modelcontextprotocol.io/docs', 'https://modelcontextprotocol.io/docs/tools/inspector'],
|
|
24
|
+
'MCP Server': ['https://modelcontextprotocol.io/docs', 'https://modelcontextprotocol.io/docs/tools/inspector'],
|
|
25
|
+
'@modelcontextprotocol/sdk': ['https://modelcontextprotocol.io/docs/tools/inspector'],
|
|
26
|
+
|
|
27
|
+
// Frontend frameworks
|
|
28
|
+
'Next.js': ['https://nextjs.org/docs/app', 'https://nextjs.org/docs/app/building-your-application'],
|
|
29
|
+
'React': ['https://react.dev', 'https://react.dev/learn'],
|
|
30
|
+
'Vue': ['https://vuejs.org/guide', 'https://vuejs.org/api'],
|
|
31
|
+
'Svelte': ['https://svelte.dev/docs', 'https://kit.svelte.dev/docs'],
|
|
32
|
+
'Nuxt': ['https://nuxt.com/docs', 'https://nuxt.com/docs/api'],
|
|
33
|
+
|
|
34
|
+
// Backend frameworks
|
|
35
|
+
'Express': ['https://expressjs.com/en/guide', 'https://expressjs.com/en/api.html'],
|
|
36
|
+
'Fastify': ['https://fastify.dev/docs/latest', 'https://fastify.dev/docs/latest/Guides/Getting-Started'],
|
|
37
|
+
'Hono': ['https://hono.dev/docs', 'https://hono.dev/docs/guides'],
|
|
38
|
+
'NestJS': ['https://docs.nestjs.com', 'https://docs.nestjs.com/first-steps'],
|
|
39
|
+
|
|
40
|
+
// Testing
|
|
41
|
+
'Vitest': ['https://vitest.dev/guide', 'https://vitest.dev/api'],
|
|
42
|
+
'Jest': ['https://jestjs.io/docs/getting-started', 'https://jestjs.io/docs/api'],
|
|
43
|
+
'Playwright': ['https://playwright.dev/docs/intro', 'https://playwright.dev/docs/api/class-test'],
|
|
44
|
+
|
|
45
|
+
// Validation
|
|
46
|
+
'Zod': ['https://zod.dev', 'https://zod.dev/?id=primitives'],
|
|
47
|
+
'Yup': ['https://github.com/jquense/yup#api'],
|
|
48
|
+
|
|
49
|
+
// Database
|
|
50
|
+
'Prisma': ['https://www.prisma.io/docs', 'https://www.prisma.io/docs/orm/prisma-client'],
|
|
51
|
+
'Drizzle': ['https://orm.drizzle.team/docs/overview', 'https://orm.drizzle.team/docs/sql-schema-declaration'],
|
|
52
|
+
'Supabase': ['https://supabase.com/docs', 'https://supabase.com/docs/guides/database'],
|
|
53
|
+
|
|
54
|
+
// TypeScript
|
|
55
|
+
'TypeScript': ['https://www.typescriptlang.org/docs', 'https://www.typescriptlang.org/docs/handbook'],
|
|
56
|
+
|
|
57
|
+
// CLI tools
|
|
58
|
+
'Commander': ['https://github.com/tj/commander.js#readme'],
|
|
59
|
+
'Yargs': ['https://yargs.js.org/docs'],
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get documentation hints for a technology
|
|
64
|
+
* Exported for testing
|
|
65
|
+
*/
|
|
66
|
+
export function getDocumentationHints(technology: string): string[] {
|
|
67
|
+
// Direct match
|
|
68
|
+
if (DOCUMENTATION_HINTS[technology]) {
|
|
69
|
+
return DOCUMENTATION_HINTS[technology];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Empty string should return generic fallback
|
|
73
|
+
if (!technology.trim()) {
|
|
74
|
+
return [`Check official ${technology} documentation`];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const lowerTech = technology.toLowerCase();
|
|
78
|
+
|
|
79
|
+
// Case-insensitive exact match first
|
|
80
|
+
for (const [key, hints] of Object.entries(DOCUMENTATION_HINTS)) {
|
|
81
|
+
if (key.toLowerCase() === lowerTech) {
|
|
82
|
+
return hints;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Partial match - prefer longer keys to avoid "React" matching "React Native"
|
|
87
|
+
// Sort keys by length descending so longer/more specific matches win
|
|
88
|
+
const sortedKeys = Object.keys(DOCUMENTATION_HINTS).sort((a, b) => b.length - a.length);
|
|
89
|
+
|
|
90
|
+
for (const key of sortedKeys) {
|
|
91
|
+
const lowerKey = key.toLowerCase();
|
|
92
|
+
if (lowerTech.includes(lowerKey) || lowerKey.includes(lowerTech)) {
|
|
93
|
+
return DOCUMENTATION_HINTS[key];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return [`Check official ${technology} documentation`];
|
|
98
|
+
}
|
|
99
|
+
|
|
16
100
|
/**
|
|
17
101
|
* Get the current year for dynamic prompt generation
|
|
18
102
|
*/
|
|
@@ -265,6 +349,7 @@ function parseTechResearch(
|
|
|
265
349
|
|
|
266
350
|
/**
|
|
267
351
|
* Get default tech research when parsing fails
|
|
352
|
+
* Uses the DOCUMENTATION_HINTS mapping for relevant URLs
|
|
268
353
|
*/
|
|
269
354
|
function getDefaultTechResearch(
|
|
270
355
|
technology: string,
|
|
@@ -275,7 +360,7 @@ function getDefaultTechResearch(
|
|
|
275
360
|
bestPractices: ['Follow official documentation', 'Use TypeScript for type safety'],
|
|
276
361
|
antiPatterns: ['Avoid deprecated APIs', 'Don\'t skip error handling'],
|
|
277
362
|
testingTips: ['Write unit tests for core logic', 'Test edge cases'],
|
|
278
|
-
documentationHints:
|
|
363
|
+
documentationHints: getDocumentationHints(technology),
|
|
279
364
|
researchMode,
|
|
280
365
|
};
|
|
281
366
|
}
|
package/src/ai/agents/types.ts
CHANGED
|
@@ -157,6 +157,8 @@ export interface StackResearch {
|
|
|
157
157
|
testingTools: string[];
|
|
158
158
|
/** Technology-specific debugging tools */
|
|
159
159
|
debuggingTools: string[];
|
|
160
|
+
/** Technology-specific validation tools (linting, type checking) */
|
|
161
|
+
validationTools: string[];
|
|
160
162
|
/** Documentation hints and links */
|
|
161
163
|
documentationHints: string[];
|
|
162
164
|
/** Whether research was performed with tools or knowledge-only */
|
package/src/ai/enhancer.ts
CHANGED
|
@@ -452,7 +452,7 @@ function convertMultiAgentToAIAnalysis(multiAgent: MultiAgentAnalysis): AIAnalys
|
|
|
452
452
|
technologyTools: {
|
|
453
453
|
testing: stackResearch.testingTools,
|
|
454
454
|
debugging: stackResearch.debuggingTools,
|
|
455
|
-
validation:
|
|
455
|
+
validation: stackResearch.validationTools,
|
|
456
456
|
},
|
|
457
457
|
technologyPractices: {
|
|
458
458
|
projectType: codebaseAnalysis.projectContext.projectType,
|