ai-sdlc 0.2.0-alpha.21 → 0.2.0-alpha.23
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/agents/implementation.d.ts.map +1 -1
- package/dist/agents/implementation.js +19 -1
- package/dist/agents/implementation.js.map +1 -1
- package/dist/agents/planning.d.ts.map +1 -1
- package/dist/agents/planning.js +20 -1
- package/dist/agents/planning.js.map +1 -1
- package/dist/agents/refinement.d.ts.map +1 -1
- package/dist/agents/refinement.js +20 -1
- package/dist/agents/refinement.js.map +1 -1
- package/dist/agents/research.d.ts +71 -1
- package/dist/agents/research.d.ts.map +1 -1
- package/dist/agents/research.js +401 -6
- package/dist/agents/research.js.map +1 -1
- package/dist/agents/review.d.ts.map +1 -1
- package/dist/agents/review.js +19 -0
- package/dist/agents/review.js.map +1 -1
- package/dist/agents/rework.d.ts.map +1 -1
- package/dist/agents/rework.js +19 -0
- package/dist/agents/rework.js.map +1 -1
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +132 -52
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/daemon.d.ts.map +1 -1
- package/dist/cli/daemon.js +17 -0
- package/dist/cli/daemon.js.map +1 -1
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/client.js +34 -2
- package/dist/core/client.js.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/story-logger.d.ts +102 -0
- package/dist/core/story-logger.d.ts.map +1 -0
- package/dist/core/story-logger.js +265 -0
- package/dist/core/story-logger.js.map +1 -0
- package/dist/core/workflow-state.d.ts.map +1 -1
- package/dist/core/workflow-state.js +16 -0
- package/dist/core/workflow-state.js.map +1 -1
- package/dist/index.js +85 -2
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +25 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/package.json +1 -1
package/dist/agents/research.js
CHANGED
|
@@ -3,6 +3,7 @@ import path from 'path';
|
|
|
3
3
|
import { glob } from 'glob';
|
|
4
4
|
import { parseStory, appendToSection, updateStoryField } from '../core/story.js';
|
|
5
5
|
import { runAgentQuery } from '../core/client.js';
|
|
6
|
+
import { getLogger } from '../core/logger.js';
|
|
6
7
|
const RESEARCH_SYSTEM_PROMPT = `You are a technical research specialist. Your job is to research how to implement a user story by analyzing the existing codebase and external best practices.
|
|
7
8
|
|
|
8
9
|
When researching a story, you should:
|
|
@@ -13,6 +14,118 @@ When researching a story, you should:
|
|
|
13
14
|
5. Note any dependencies or prerequisites
|
|
14
15
|
|
|
15
16
|
Output your research findings in markdown format. Be specific about file paths and code patterns.`;
|
|
17
|
+
/**
|
|
18
|
+
* Keywords that indicate a story is purely internal and does not require web research.
|
|
19
|
+
* These keywords suggest refactoring, code organization, or internal maintenance tasks.
|
|
20
|
+
*/
|
|
21
|
+
const WEB_RESEARCH_INTERNAL_KEYWORDS = [
|
|
22
|
+
'refactor internal',
|
|
23
|
+
'move function',
|
|
24
|
+
'rename variable',
|
|
25
|
+
'rename function',
|
|
26
|
+
'move utility',
|
|
27
|
+
'internal refactor',
|
|
28
|
+
'move code',
|
|
29
|
+
'reorganize internal',
|
|
30
|
+
];
|
|
31
|
+
/**
|
|
32
|
+
* Keywords that indicate external dependencies or integrations requiring web research.
|
|
33
|
+
* These keywords suggest the need for library documentation, API references, or best practices.
|
|
34
|
+
*/
|
|
35
|
+
const WEB_RESEARCH_EXTERNAL_KEYWORDS = [
|
|
36
|
+
'integrate',
|
|
37
|
+
'api',
|
|
38
|
+
'library',
|
|
39
|
+
'framework',
|
|
40
|
+
'best practices',
|
|
41
|
+
'npm package',
|
|
42
|
+
'external',
|
|
43
|
+
'third-party',
|
|
44
|
+
'sdk',
|
|
45
|
+
'documentation',
|
|
46
|
+
'webhook',
|
|
47
|
+
'rest api',
|
|
48
|
+
'graphql',
|
|
49
|
+
'oauth',
|
|
50
|
+
'authentication provider',
|
|
51
|
+
];
|
|
52
|
+
/**
|
|
53
|
+
* Web research prompt template for supplementary research phase.
|
|
54
|
+
* Instructs the agent on tool usage, FAR evaluation, and output formatting.
|
|
55
|
+
*/
|
|
56
|
+
const WEB_RESEARCH_PROMPT_TEMPLATE = (storyTitle, storyContent, codebaseContext) => `You are performing supplementary web research for a software development story.
|
|
57
|
+
|
|
58
|
+
**Story Title**: ${storyTitle}
|
|
59
|
+
|
|
60
|
+
**Story Content**:
|
|
61
|
+
${storyContent}
|
|
62
|
+
|
|
63
|
+
**Codebase Context** (already analyzed):
|
|
64
|
+
${codebaseContext}... [truncated]
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Web Research Instructions
|
|
69
|
+
|
|
70
|
+
You have access to these web research tools:
|
|
71
|
+
|
|
72
|
+
1. **Context7** (if available) - Use FIRST for library/framework documentation
|
|
73
|
+
- Best for: npm packages, Python libraries, popular frameworks
|
|
74
|
+
- Example: "Search Context7 for React Query documentation on data fetching"
|
|
75
|
+
|
|
76
|
+
2. **WebSearch** - Use for community knowledge and best practices
|
|
77
|
+
- Best for: Stack Overflow patterns, blog posts, tutorials
|
|
78
|
+
- Example: "Search the web for TypeScript error handling best practices"
|
|
79
|
+
|
|
80
|
+
3. **WebFetch** - Use to read specific authoritative URLs
|
|
81
|
+
- Best for: Official documentation, specific articles
|
|
82
|
+
- Example: "Fetch https://docs.anthropic.com/claude/reference"
|
|
83
|
+
|
|
84
|
+
## Research Strategy
|
|
85
|
+
|
|
86
|
+
- Try Context7 FIRST for any npm packages or popular frameworks mentioned in the story
|
|
87
|
+
- Fall back to WebSearch for general solutions and community patterns
|
|
88
|
+
- Use WebFetch only when you have specific authoritative URLs to read
|
|
89
|
+
- Limit research to 3-5 high-quality sources to avoid information overload
|
|
90
|
+
- Focus on actionable information that directly addresses the story requirements
|
|
91
|
+
|
|
92
|
+
## Output Format
|
|
93
|
+
|
|
94
|
+
For EACH finding, provide:
|
|
95
|
+
|
|
96
|
+
### [Topic Name]
|
|
97
|
+
**Source**: [Context7 - Library Name] or [Web Search Result] or [URL]
|
|
98
|
+
**FAR Score**: Factuality: [1-5], Actionability: [1-5], Relevance: [1-5]
|
|
99
|
+
**Justification**: [Why these scores? How does this help the story?]
|
|
100
|
+
|
|
101
|
+
[Finding content with code examples, patterns, or instructions]
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## FAR Scale Definitions
|
|
106
|
+
|
|
107
|
+
**Factuality (1-5)**: How accurate and verifiable is the information?
|
|
108
|
+
- 1: Unverified/speculative
|
|
109
|
+
- 3: Community knowledge (Stack Overflow, blogs)
|
|
110
|
+
- 5: Official documentation or peer-reviewed
|
|
111
|
+
|
|
112
|
+
**Actionability (1-5)**: Can this be directly applied to the task?
|
|
113
|
+
- 1: Abstract concepts only
|
|
114
|
+
- 3: General patterns or approaches
|
|
115
|
+
- 5: Copy-paste code examples or step-by-step instructions
|
|
116
|
+
|
|
117
|
+
**Relevance (1-5)**: How closely does this match the story requirements?
|
|
118
|
+
- 1: Tangentially related
|
|
119
|
+
- 3: Related but not specific to story
|
|
120
|
+
- 5: Directly addresses a story acceptance criterion
|
|
121
|
+
|
|
122
|
+
## Important Notes
|
|
123
|
+
|
|
124
|
+
- If web tools are unavailable (offline, not configured), simply state: "Web research tools unavailable - skipping web research"
|
|
125
|
+
- If a finding contradicts patterns in the codebase context, note the discrepancy and defer to local patterns
|
|
126
|
+
- Focus on NEW information not already present in codebase analysis
|
|
127
|
+
|
|
128
|
+
Begin web research now. Provide 3-5 high-quality findings with FAR evaluations.`;
|
|
16
129
|
/**
|
|
17
130
|
* Research Agent
|
|
18
131
|
*
|
|
@@ -25,6 +138,8 @@ export async function runResearchAgent(storyPath, sdlcRoot, options = {}) {
|
|
|
25
138
|
try {
|
|
26
139
|
// Gather codebase context
|
|
27
140
|
const codebaseContext = await gatherCodebaseContext(sdlcRoot);
|
|
141
|
+
// Sanitize codebase context before including in prompt (prevent prompt injection)
|
|
142
|
+
const sanitizedContext = sanitizeCodebaseContext(codebaseContext);
|
|
28
143
|
// Build the prompt, including rework context if this is a refinement iteration
|
|
29
144
|
let prompt = `Please research how to implement this story:
|
|
30
145
|
|
|
@@ -34,7 +149,7 @@ Story content:
|
|
|
34
149
|
${story.content}
|
|
35
150
|
|
|
36
151
|
Codebase context:
|
|
37
|
-
${
|
|
152
|
+
${sanitizedContext}`;
|
|
38
153
|
if (options.reworkContext) {
|
|
39
154
|
prompt += `
|
|
40
155
|
|
|
@@ -62,11 +177,33 @@ Format your response as markdown for the Research section of the story.`;
|
|
|
62
177
|
workingDirectory: path.dirname(sdlcRoot),
|
|
63
178
|
onProgress: options.onProgress,
|
|
64
179
|
});
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
180
|
+
// Sanitize research content before storage (prevent ANSI/markdown injection)
|
|
181
|
+
const sanitizedResearch = sanitizeWebResearchContent(researchContent);
|
|
182
|
+
// Append codebase research to the story
|
|
183
|
+
await appendToSection(story, 'Research', sanitizedResearch);
|
|
184
|
+
changesMade.push('Added codebase research findings');
|
|
185
|
+
// Phase 2: Web Research (conditional)
|
|
186
|
+
if (shouldPerformWebResearch(story, sanitizedContext)) {
|
|
187
|
+
const webResearchContent = await performWebResearch(story, sanitizedContext, path.dirname(sdlcRoot), options.onProgress);
|
|
188
|
+
if (webResearchContent.trim()) {
|
|
189
|
+
// Sanitize web research content before storage (prevent ANSI/markdown injection)
|
|
190
|
+
const sanitizedWebResearch = sanitizeWebResearchContent(webResearchContent);
|
|
191
|
+
// Re-parse story to get updated content after codebase research
|
|
192
|
+
const updatedStory = parseStory(storyPath);
|
|
193
|
+
await appendToSection(updatedStory, 'Research', '\n## Web Research Findings\n\n' + sanitizedWebResearch);
|
|
194
|
+
changesMade.push('Added web research findings');
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
getLogger().info('web-research', 'Web research returned empty - tools may be unavailable');
|
|
198
|
+
changesMade.push('Web research skipped: tools unavailable');
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
changesMade.push('Web research skipped: no external dependencies detected');
|
|
203
|
+
}
|
|
204
|
+
// Mark research as complete - re-parse to get latest content including web research
|
|
205
|
+
const finalStory = parseStory(storyPath);
|
|
206
|
+
await updateStoryField(finalStory, 'research_complete', true);
|
|
70
207
|
changesMade.push('Marked research_complete: true');
|
|
71
208
|
return {
|
|
72
209
|
success: true,
|
|
@@ -138,4 +275,262 @@ async function gatherCodebaseContext(sdlcRoot) {
|
|
|
138
275
|
}
|
|
139
276
|
return context.join('\n\n') || 'No codebase context available.';
|
|
140
277
|
}
|
|
278
|
+
/**
|
|
279
|
+
* Determine if web research would add value based on story content and codebase context.
|
|
280
|
+
*
|
|
281
|
+
* Web research is triggered when:
|
|
282
|
+
* 1. External dependencies are referenced (libraries, APIs, frameworks)
|
|
283
|
+
* 2. Unfamiliar APIs/patterns are mentioned
|
|
284
|
+
* 3. Library-specific documentation is needed
|
|
285
|
+
* 4. Best practices are requested
|
|
286
|
+
*
|
|
287
|
+
* Web research is skipped when:
|
|
288
|
+
* - Topic is purely internal (refactoring, moving code, internal utilities)
|
|
289
|
+
* - No external dependencies mentioned
|
|
290
|
+
*/
|
|
291
|
+
export function shouldPerformWebResearch(story, codebaseContext) {
|
|
292
|
+
const content = story.content.toLowerCase();
|
|
293
|
+
const title = story.frontmatter.title.toLowerCase();
|
|
294
|
+
const combinedText = `${title} ${content}`;
|
|
295
|
+
// Skip if purely internal keywords are dominant
|
|
296
|
+
for (const keyword of WEB_RESEARCH_INTERNAL_KEYWORDS) {
|
|
297
|
+
if (combinedText.includes(keyword)) {
|
|
298
|
+
// Sanitize keyword for logging (prevent log injection)
|
|
299
|
+
getLogger().info('web-research', `Skipping web research: purely internal topic detected (${sanitizeForLogging(keyword)})`);
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
// Trigger if external library/API/framework mentioned
|
|
304
|
+
for (const keyword of WEB_RESEARCH_EXTERNAL_KEYWORDS) {
|
|
305
|
+
if (combinedText.includes(keyword)) {
|
|
306
|
+
// Sanitize keyword for logging (prevent log injection)
|
|
307
|
+
getLogger().info('web-research', `Web research triggered: external keyword detected (${sanitizeForLogging(keyword)})`);
|
|
308
|
+
return true;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// Check for package.json mentions (suggests npm dependencies)
|
|
312
|
+
if (codebaseContext.includes('package.json') &&
|
|
313
|
+
(combinedText.includes('npm') || combinedText.includes('install') || combinedText.includes('dependency'))) {
|
|
314
|
+
getLogger().info('web-research', 'Web research triggered: npm dependency context detected');
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
// Default: skip web research for codebase-only topics
|
|
318
|
+
getLogger().info('web-research', 'Skipping web research: no external dependencies detected');
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Maximum input length to prevent DoS attacks.
|
|
323
|
+
* Set to 10,000 chars to accommodate long research findings
|
|
324
|
+
* while preventing memory exhaustion from malicious inputs.
|
|
325
|
+
*/
|
|
326
|
+
const MAX_INPUT_LENGTH = 10000;
|
|
327
|
+
/**
|
|
328
|
+
* Maximum log string length for readability and security.
|
|
329
|
+
* Prevents log injection and maintains log file readability.
|
|
330
|
+
*/
|
|
331
|
+
const MAX_LOG_LENGTH = 200;
|
|
332
|
+
/**
|
|
333
|
+
* Sanitize web research content for safe storage and display.
|
|
334
|
+
* Removes ANSI escape sequences, control characters, and potential injection vectors.
|
|
335
|
+
*
|
|
336
|
+
* Security rationale: Web research content comes from external sources (LLM, web tools)
|
|
337
|
+
* and must be sanitized before storage to prevent:
|
|
338
|
+
* - ANSI injection (terminal control sequence attacks)
|
|
339
|
+
* - Markdown injection (malicious formatting)
|
|
340
|
+
* - Control character injection (null bytes, bell characters, etc.)
|
|
341
|
+
*
|
|
342
|
+
* @param text - Raw web research content from external source
|
|
343
|
+
* @returns Sanitized text safe for storage in markdown files
|
|
344
|
+
*/
|
|
345
|
+
export function sanitizeWebResearchContent(text) {
|
|
346
|
+
if (!text)
|
|
347
|
+
return '';
|
|
348
|
+
// Enforce maximum length to prevent DoS
|
|
349
|
+
if (text.length > MAX_INPUT_LENGTH) {
|
|
350
|
+
text = text.substring(0, MAX_INPUT_LENGTH);
|
|
351
|
+
}
|
|
352
|
+
// Remove ANSI CSI sequences (colors, cursor movement) - e.g., \x1B[31m
|
|
353
|
+
text = text.replace(/\x1B\[[^a-zA-Z\x1B]*[a-zA-Z]?/g, '');
|
|
354
|
+
// Remove OSC sequences (hyperlinks, window titles) - terminated by BEL (\x07) or ST (\x1B\\)
|
|
355
|
+
text = text.replace(/\x1B\][^\x07]*\x07/g, '');
|
|
356
|
+
text = text.replace(/\x1B\][^\x1B]*\x1B\\/g, '');
|
|
357
|
+
// Remove any remaining standalone escape characters
|
|
358
|
+
text = text.replace(/\x1B/g, '');
|
|
359
|
+
// Remove control characters (0x00-0x08, 0x0B-0x0C, 0x0E-0x1F, 0x7F-0x9F)
|
|
360
|
+
// eslint-disable-next-line no-control-regex
|
|
361
|
+
text = text.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F-\x9F]/g, '');
|
|
362
|
+
// Normalize Unicode to prevent homograph attacks and ensure consistent representation
|
|
363
|
+
text = text.normalize('NFC');
|
|
364
|
+
// Validate markdown structure - escape dangerous patterns
|
|
365
|
+
// Triple backticks could be used to break out of code blocks
|
|
366
|
+
text = text.replace(/```/g, '\\`\\`\\`');
|
|
367
|
+
return text;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Sanitize text for logging to prevent log injection attacks.
|
|
371
|
+
* Replaces newlines with spaces and truncates for readability.
|
|
372
|
+
*
|
|
373
|
+
* Security rationale: Log injection attacks use newlines to inject fake log entries.
|
|
374
|
+
* By replacing newlines with spaces, we ensure each log() call produces exactly one log line.
|
|
375
|
+
*
|
|
376
|
+
* @param text - Raw text that will be logged
|
|
377
|
+
* @returns Sanitized text safe for logging (single line, truncated)
|
|
378
|
+
*/
|
|
379
|
+
export function sanitizeForLogging(text) {
|
|
380
|
+
if (!text)
|
|
381
|
+
return '';
|
|
382
|
+
// Remove ANSI escape sequences
|
|
383
|
+
text = text.replace(/\x1B\[[^a-zA-Z\x1B]*[a-zA-Z]?/g, '');
|
|
384
|
+
text = text.replace(/\x1B\][^\x07]*\x07/g, '');
|
|
385
|
+
text = text.replace(/\x1B\][^\x1B]*\x1B\\/g, '');
|
|
386
|
+
text = text.replace(/\x1B/g, '');
|
|
387
|
+
// Replace newlines and carriage returns with spaces to prevent log injection
|
|
388
|
+
text = text.replace(/[\n\r]/g, ' ');
|
|
389
|
+
// Truncate to reasonable length for logs
|
|
390
|
+
if (text.length > MAX_LOG_LENGTH) {
|
|
391
|
+
text = text.substring(0, MAX_LOG_LENGTH) + '...';
|
|
392
|
+
}
|
|
393
|
+
return text.trim();
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Sanitize codebase context before including in LLM prompts.
|
|
397
|
+
* Escapes dangerous patterns that could cause prompt injection.
|
|
398
|
+
*
|
|
399
|
+
* Security rationale: Codebase files may contain malicious content from:
|
|
400
|
+
* - Compromised dependencies
|
|
401
|
+
* - Malicious commits
|
|
402
|
+
* - Untrusted contributors
|
|
403
|
+
*
|
|
404
|
+
* We must prevent prompt injection by escaping patterns that could:
|
|
405
|
+
* - Terminate the prompt early (triple backticks)
|
|
406
|
+
* - Inject commands or instructions
|
|
407
|
+
* - Confuse the LLM's understanding of structure
|
|
408
|
+
*
|
|
409
|
+
* @param text - Raw codebase context
|
|
410
|
+
* @returns Sanitized text safe for LLM prompts
|
|
411
|
+
*/
|
|
412
|
+
export function sanitizeCodebaseContext(text) {
|
|
413
|
+
if (!text)
|
|
414
|
+
return '';
|
|
415
|
+
// Remove ANSI escape sequences
|
|
416
|
+
text = text.replace(/\x1B\[[^a-zA-Z\x1B]*[a-zA-Z]?/g, '');
|
|
417
|
+
text = text.replace(/\x1B\][^\x07]*\x07/g, '');
|
|
418
|
+
text = text.replace(/\x1B\][^\x1B]*\x1B\\/g, '');
|
|
419
|
+
text = text.replace(/\x1B/g, '');
|
|
420
|
+
// Escape triple backticks to prevent breaking out of code blocks
|
|
421
|
+
text = text.replace(/```/g, '\\`\\`\\`');
|
|
422
|
+
// Validate UTF-8 boundaries at truncation points
|
|
423
|
+
// If we need to truncate, ensure we don't split multi-byte characters
|
|
424
|
+
if (text.length > MAX_INPUT_LENGTH) {
|
|
425
|
+
// Use substring which is UTF-16 safe, then validate
|
|
426
|
+
let truncated = text.substring(0, MAX_INPUT_LENGTH);
|
|
427
|
+
// Check if we split a surrogate pair (0xD800-0xDFFF)
|
|
428
|
+
const lastCharCode = truncated.charCodeAt(truncated.length - 1);
|
|
429
|
+
if (lastCharCode >= 0xD800 && lastCharCode <= 0xDFFF) {
|
|
430
|
+
// We split a surrogate pair, remove the incomplete character
|
|
431
|
+
truncated = truncated.substring(0, truncated.length - 1);
|
|
432
|
+
}
|
|
433
|
+
text = truncated;
|
|
434
|
+
}
|
|
435
|
+
return text;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Parse FAR evaluation from web research finding text.
|
|
439
|
+
* Expected format from LLM:
|
|
440
|
+
* **FAR Score**: Factuality: 5, Actionability: 4, Relevance: 5
|
|
441
|
+
* **Justification**: Official documentation provides...
|
|
442
|
+
*
|
|
443
|
+
* Returns default scores (2, 2, 2) with parsingSucceeded: false if parsing fails.
|
|
444
|
+
* Default of 2 (rather than 3) indicates uncertainty rather than average quality.
|
|
445
|
+
*
|
|
446
|
+
* @param finding - Web research finding text to parse
|
|
447
|
+
* @returns FARScore with parsed or default values and parsing status
|
|
448
|
+
*/
|
|
449
|
+
export function evaluateFAR(finding) {
|
|
450
|
+
// Enforce maximum length to prevent ReDoS attacks
|
|
451
|
+
if (finding.length > MAX_INPUT_LENGTH) {
|
|
452
|
+
finding = finding.substring(0, MAX_INPUT_LENGTH);
|
|
453
|
+
}
|
|
454
|
+
try {
|
|
455
|
+
// Look for FAR score pattern
|
|
456
|
+
const scoreMatch = finding.match(/\*\*FAR Score\*\*:.*?Factuality:\s*(\d+).*?Actionability:\s*(\d+).*?Relevance:\s*(\d+)/i);
|
|
457
|
+
const justificationMatch = finding.match(/\*\*Justification\*\*:\s*(.+?)(?:\n\n|\n#|$)/is);
|
|
458
|
+
if (scoreMatch && justificationMatch) {
|
|
459
|
+
const factuality = parseInt(scoreMatch[1], 10);
|
|
460
|
+
const actionability = parseInt(scoreMatch[2], 10);
|
|
461
|
+
const relevance = parseInt(scoreMatch[3], 10);
|
|
462
|
+
const justification = justificationMatch[1].trim();
|
|
463
|
+
// Validate scores are in range 1-5
|
|
464
|
+
if ([factuality, actionability, relevance].every(s => s >= 1 && s <= 5)) {
|
|
465
|
+
return {
|
|
466
|
+
factuality,
|
|
467
|
+
actionability,
|
|
468
|
+
relevance,
|
|
469
|
+
justification,
|
|
470
|
+
parsingSucceeded: true,
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
getLogger().warn('web-research', 'FAR scores out of valid range (1-5), using defaults');
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
else if (scoreMatch && !justificationMatch) {
|
|
478
|
+
getLogger().warn('web-research', 'FAR justification missing, using defaults');
|
|
479
|
+
}
|
|
480
|
+
else if (!scoreMatch && justificationMatch) {
|
|
481
|
+
getLogger().warn('web-research', 'FAR scores not found in finding, using defaults');
|
|
482
|
+
}
|
|
483
|
+
else {
|
|
484
|
+
getLogger().warn('web-research', 'FAR scores and justification not found in finding, using defaults');
|
|
485
|
+
}
|
|
486
|
+
// If parsing failed, return default scores (2/5 indicates uncertainty)
|
|
487
|
+
return {
|
|
488
|
+
factuality: 2,
|
|
489
|
+
actionability: 2,
|
|
490
|
+
relevance: 2,
|
|
491
|
+
justification: 'FAR scores could not be parsed from finding. Default scores (2/5) applied.',
|
|
492
|
+
parsingSucceeded: false,
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
catch (error) {
|
|
496
|
+
getLogger().error('web-research', 'Error parsing FAR scores', { error });
|
|
497
|
+
return {
|
|
498
|
+
factuality: 2,
|
|
499
|
+
actionability: 2,
|
|
500
|
+
relevance: 2,
|
|
501
|
+
justification: 'Error parsing FAR evaluation',
|
|
502
|
+
parsingSucceeded: false,
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Perform web research using Context7/WebSearch/WebFetch.
|
|
508
|
+
* Returns formatted markdown with FAR evaluations, or empty string if all tools unavailable.
|
|
509
|
+
*/
|
|
510
|
+
async function performWebResearch(story, codebaseContext, workingDir, onProgress) {
|
|
511
|
+
const logger = getLogger();
|
|
512
|
+
logger.info('web-research', 'Starting web research phase', { storyId: story.frontmatter.id });
|
|
513
|
+
try {
|
|
514
|
+
const sanitizedContext = sanitizeCodebaseContext(codebaseContext.substring(0, 2000));
|
|
515
|
+
const webResearchPrompt = WEB_RESEARCH_PROMPT_TEMPLATE(story.frontmatter.title, story.content, sanitizedContext);
|
|
516
|
+
const webResearchResult = await runAgentQuery({
|
|
517
|
+
prompt: webResearchPrompt,
|
|
518
|
+
systemPrompt: 'You are a web research specialist. Use available tools to find authoritative documentation and best practices.',
|
|
519
|
+
workingDirectory: workingDir,
|
|
520
|
+
onProgress,
|
|
521
|
+
});
|
|
522
|
+
// Check if web tools were unavailable
|
|
523
|
+
if (webResearchResult.toLowerCase().includes('web research tools unavailable')) {
|
|
524
|
+
logger.info('web-research', 'Web research tools unavailable, skipping');
|
|
525
|
+
return '';
|
|
526
|
+
}
|
|
527
|
+
logger.info('web-research', 'Web research completed successfully');
|
|
528
|
+
return webResearchResult;
|
|
529
|
+
}
|
|
530
|
+
catch (error) {
|
|
531
|
+
logger.error('web-research', 'Web research failed', { error });
|
|
532
|
+
// Gracefully degrade - return empty string to continue with codebase-only research
|
|
533
|
+
return '';
|
|
534
|
+
}
|
|
535
|
+
}
|
|
141
536
|
//# sourceMappingURL=research.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"research.js","sourceRoot":"","sources":["../../src/agents/research.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"research.js","sourceRoot":"","sources":["../../src/agents/research.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/agents/review.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/agents/review.ts"],"names":[],"mappings":"AAQA,OAAO,EAAS,WAAW,EAAE,YAAY,EAAE,WAAW,EAA8E,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAkH5K;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,EAAE,CA0BlE;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,CAOrE;AAiBD;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAsVrJ;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CA+F1F;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,iDAAiD;IACjD,sBAAsB,CAAC,EAAE,4BAA4B,CAAC;CACvD;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,YAAY,CAAC,CA+QvB;AAgCD;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC,CAgItB"}
|
package/dist/agents/review.js
CHANGED
|
@@ -4,6 +4,7 @@ import fs from 'fs';
|
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { parseStory, updateStoryStatus, appendToSection, updateStoryField, isAtMaxRetries, appendReviewHistory, snapshotMaxRetries, getEffectiveMaxRetries } from '../core/story.js';
|
|
6
6
|
import { runAgentQuery } from '../core/client.js';
|
|
7
|
+
import { getLogger } from '../core/logger.js';
|
|
7
8
|
import { loadConfig, DEFAULT_TIMEOUTS } from '../core/config.js';
|
|
8
9
|
import { ReviewDecision, ReviewSeverity } from '../types/index.js';
|
|
9
10
|
import { sanitizeInput, truncateText } from '../cli/formatting.js';
|
|
@@ -526,9 +527,15 @@ export function generateReviewSummary(issues, terminalWidth) {
|
|
|
526
527
|
* Now returns structured ReviewResult with pass/fail and issues.
|
|
527
528
|
*/
|
|
528
529
|
export async function runReviewAgent(storyPath, sdlcRoot, options) {
|
|
530
|
+
const logger = getLogger();
|
|
531
|
+
const startTime = Date.now();
|
|
529
532
|
const story = parseStory(storyPath);
|
|
530
533
|
const changesMade = [];
|
|
531
534
|
const workingDir = path.dirname(sdlcRoot);
|
|
535
|
+
logger.info('review', 'Starting review phase', {
|
|
536
|
+
storyId: story.frontmatter.id,
|
|
537
|
+
retryCount: story.frontmatter.retry_count || 0,
|
|
538
|
+
});
|
|
532
539
|
// Security: Validate working directory before any operations
|
|
533
540
|
try {
|
|
534
541
|
validateWorkingDirectory(workingDir);
|
|
@@ -724,6 +731,13 @@ ${passed ? '✅ **PASSED** - All reviews approved' : '❌ **FAILED** - Issues mu
|
|
|
724
731
|
changesMade.push(`Reviews failed with ${allIssues.length} issue(s) - rework required`);
|
|
725
732
|
// Don't mark reviews_complete, this will trigger rework
|
|
726
733
|
}
|
|
734
|
+
logger.info('review', 'Review phase complete', {
|
|
735
|
+
storyId: story.frontmatter.id,
|
|
736
|
+
durationMs: Date.now() - startTime,
|
|
737
|
+
passed,
|
|
738
|
+
decision,
|
|
739
|
+
issueCount: allIssues.length,
|
|
740
|
+
});
|
|
727
741
|
return {
|
|
728
742
|
success: true,
|
|
729
743
|
story: parseStory(storyPath),
|
|
@@ -739,6 +753,11 @@ ${passed ? '✅ **PASSED** - All reviews approved' : '❌ **FAILED** - Issues mu
|
|
|
739
753
|
catch (error) {
|
|
740
754
|
// Review agent failure - return FAILED decision (doesn't count as retry)
|
|
741
755
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
756
|
+
logger.error('review', 'Review phase failed', {
|
|
757
|
+
storyId: story.frontmatter.id,
|
|
758
|
+
durationMs: Date.now() - startTime,
|
|
759
|
+
error: errorMsg,
|
|
760
|
+
});
|
|
742
761
|
return {
|
|
743
762
|
success: false,
|
|
744
763
|
story,
|