ai-sdlc 0.2.0-alpha.6 → 0.2.0-alpha.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -1058
- package/dist/agents/implementation.d.ts +36 -1
- package/dist/agents/implementation.d.ts.map +1 -1
- package/dist/agents/implementation.js +259 -30
- package/dist/agents/implementation.js.map +1 -1
- package/dist/agents/index.d.ts +2 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +2 -0
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/orchestrator.d.ts +61 -0
- package/dist/agents/orchestrator.d.ts.map +1 -0
- package/dist/agents/orchestrator.js +443 -0
- package/dist/agents/orchestrator.js.map +1 -0
- package/dist/agents/planning.d.ts +1 -1
- package/dist/agents/planning.d.ts.map +1 -1
- package/dist/agents/planning.js +55 -4
- package/dist/agents/planning.js.map +1 -1
- package/dist/agents/refinement.d.ts.map +1 -1
- package/dist/agents/refinement.js +22 -3
- package/dist/agents/refinement.js.map +1 -1
- package/dist/agents/research.d.ts +85 -1
- package/dist/agents/research.d.ts.map +1 -1
- package/dist/agents/research.js +506 -16
- package/dist/agents/research.js.map +1 -1
- package/dist/agents/review.d.ts +103 -2
- package/dist/agents/review.d.ts.map +1 -1
- package/dist/agents/review.js +777 -93
- package/dist/agents/review.js.map +1 -1
- package/dist/agents/rework.d.ts.map +1 -1
- package/dist/agents/rework.js +25 -4
- package/dist/agents/rework.js.map +1 -1
- package/dist/agents/single-task.d.ts +41 -0
- package/dist/agents/single-task.d.ts.map +1 -0
- package/dist/agents/single-task.js +357 -0
- package/dist/agents/single-task.js.map +1 -0
- package/dist/agents/state-assessor.d.ts +3 -3
- package/dist/agents/state-assessor.d.ts.map +1 -1
- package/dist/agents/state-assessor.js +6 -6
- package/dist/agents/state-assessor.js.map +1 -1
- package/dist/agents/test-pattern-detector.d.ts +49 -0
- package/dist/agents/test-pattern-detector.d.ts.map +1 -0
- package/dist/agents/test-pattern-detector.js +273 -0
- package/dist/agents/test-pattern-detector.js.map +1 -0
- package/dist/agents/verification.d.ts +11 -0
- package/dist/agents/verification.d.ts.map +1 -1
- package/dist/agents/verification.js +99 -12
- package/dist/agents/verification.js.map +1 -1
- package/dist/cli/commands/migrate.js +1 -1
- package/dist/cli/commands/migrate.js.map +1 -1
- package/dist/cli/commands.d.ts +66 -3
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +1548 -198
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/daemon.d.ts.map +1 -1
- package/dist/cli/daemon.js +25 -3
- package/dist/cli/daemon.js.map +1 -1
- package/dist/cli/runner.d.ts.map +1 -1
- package/dist/cli/runner.js +35 -12
- package/dist/cli/runner.js.map +1 -1
- package/dist/core/auth.d.ts +43 -0
- package/dist/core/auth.d.ts.map +1 -1
- package/dist/core/auth.js +105 -1
- package/dist/core/auth.js.map +1 -1
- package/dist/core/client.d.ts +25 -1
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/client.js +247 -7
- package/dist/core/client.js.map +1 -1
- package/dist/core/config.d.ts +32 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +146 -3
- package/dist/core/config.js.map +1 -1
- package/dist/core/conflict-detector.d.ts +108 -0
- package/dist/core/conflict-detector.d.ts.map +1 -0
- package/dist/core/conflict-detector.js +413 -0
- package/dist/core/conflict-detector.js.map +1 -0
- package/dist/core/git-utils.d.ts +28 -0
- package/dist/core/git-utils.d.ts.map +1 -0
- package/dist/core/git-utils.js +146 -0
- package/dist/core/git-utils.js.map +1 -0
- package/dist/core/index.d.ts +19 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +19 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/kanban.d.ts +1 -1
- package/dist/core/kanban.d.ts.map +1 -1
- package/dist/core/kanban.js +3 -3
- package/dist/core/kanban.js.map +1 -1
- package/dist/core/llm-utils.d.ts +103 -0
- package/dist/core/llm-utils.d.ts.map +1 -0
- package/dist/core/llm-utils.js +368 -0
- package/dist/core/llm-utils.js.map +1 -0
- package/dist/core/logger.d.ts +92 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +221 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/process-manager.d.ts +15 -0
- package/dist/core/process-manager.d.ts.map +1 -0
- package/dist/core/process-manager.js +132 -0
- package/dist/core/process-manager.js.map +1 -0
- 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/story.d.ts +113 -20
- package/dist/core/story.d.ts.map +1 -1
- package/dist/core/story.js +328 -40
- package/dist/core/story.js.map +1 -1
- package/dist/core/task-parser.d.ts +59 -0
- package/dist/core/task-parser.d.ts.map +1 -0
- package/dist/core/task-parser.js +235 -0
- package/dist/core/task-parser.js.map +1 -0
- package/dist/core/task-progress.d.ts +92 -0
- package/dist/core/task-progress.d.ts.map +1 -0
- package/dist/core/task-progress.js +280 -0
- package/dist/core/task-progress.js.map +1 -0
- package/dist/core/workflow-state.d.ts +45 -6
- package/dist/core/workflow-state.d.ts.map +1 -1
- package/dist/core/workflow-state.js +201 -12
- package/dist/core/workflow-state.js.map +1 -1
- package/dist/core/worktree.d.ts +186 -0
- package/dist/core/worktree.d.ts.map +1 -0
- package/dist/core/worktree.js +554 -0
- package/dist/core/worktree.js.map +1 -0
- package/dist/index.js +145 -5
- package/dist/index.js.map +1 -1
- package/dist/services/error-classifier.d.ts +119 -0
- package/dist/services/error-classifier.d.ts.map +1 -0
- package/dist/services/error-classifier.js +182 -0
- package/dist/services/error-classifier.js.map +1 -0
- package/dist/types/index.d.ts +381 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- package/package.json +5 -2
- package/templates/story.md +5 -0
|
@@ -104,6 +104,22 @@ export interface RetryAttemptOptions {
|
|
|
104
104
|
reworkContext?: string;
|
|
105
105
|
onProgress?: AgentProgressCallback;
|
|
106
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Outcome type for retry attempts
|
|
109
|
+
*/
|
|
110
|
+
export type AttemptOutcome = 'failed_tests' | 'failed_build' | 'no_change';
|
|
111
|
+
/**
|
|
112
|
+
* Result from a single retry attempt
|
|
113
|
+
*/
|
|
114
|
+
export interface AttemptHistoryEntry {
|
|
115
|
+
attempt: number;
|
|
116
|
+
testFailures: number;
|
|
117
|
+
buildFailures: number;
|
|
118
|
+
testSnippet: string;
|
|
119
|
+
buildSnippet: string;
|
|
120
|
+
changesSummary: string;
|
|
121
|
+
outcome: AttemptOutcome;
|
|
122
|
+
}
|
|
107
123
|
/**
|
|
108
124
|
* Attempt implementation with retry logic
|
|
109
125
|
*
|
|
@@ -134,6 +150,18 @@ export declare function captureCurrentDiffHash(workingDir: string): string;
|
|
|
134
150
|
* @returns True if changes occurred (hashes are different)
|
|
135
151
|
*/
|
|
136
152
|
export declare function hasChangesOccurred(previousHash: string, currentHash: string): boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Extract list of changed files from git diff
|
|
155
|
+
* @param workingDir The working directory
|
|
156
|
+
* @returns Comma-separated list of changed files, or descriptive message
|
|
157
|
+
*/
|
|
158
|
+
export declare function extractChangedFiles(workingDir: string): string;
|
|
159
|
+
/**
|
|
160
|
+
* Build formatted retry history section for agent prompts
|
|
161
|
+
* @param history Array of attempt history entries
|
|
162
|
+
* @returns Formatted string for inclusion in retry prompts
|
|
163
|
+
*/
|
|
164
|
+
export declare function buildRetryHistorySection(history: AttemptHistoryEntry[]): string;
|
|
137
165
|
/**
|
|
138
166
|
* Sanitize test output to remove ANSI escape sequences and potential injection patterns
|
|
139
167
|
* @param output Test output string
|
|
@@ -147,12 +175,19 @@ export declare function sanitizeTestOutput(output: string): string;
|
|
|
147
175
|
* @returns Truncated and sanitized output with notice if truncated
|
|
148
176
|
*/
|
|
149
177
|
export declare function truncateTestOutput(output: string, maxLength?: number): string;
|
|
178
|
+
/**
|
|
179
|
+
* Detect if errors are related to missing dependencies
|
|
180
|
+
* Returns module names that are missing, if any
|
|
181
|
+
*/
|
|
182
|
+
export declare function detectMissingDependencies(output: string): string[];
|
|
150
183
|
/**
|
|
151
184
|
* Build retry prompt for implementation agent
|
|
152
185
|
* @param testOutput Test failure output
|
|
186
|
+
* @param buildOutput Build output
|
|
153
187
|
* @param attemptNumber Current attempt number (1-indexed)
|
|
154
188
|
* @param maxRetries Maximum number of retries
|
|
189
|
+
* @param attemptHistory Optional history of previous attempts
|
|
155
190
|
* @returns Prompt string for retry attempt
|
|
156
191
|
*/
|
|
157
|
-
export declare function buildRetryPrompt(testOutput: string, buildOutput: string, attemptNumber: number, maxRetries: number): string;
|
|
192
|
+
export declare function buildRetryPrompt(testOutput: string, buildOutput: string, attemptNumber: number, maxRetries: number, attemptHistory?: AttemptHistoryEntry[]): string;
|
|
158
193
|
//# sourceMappingURL=implementation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"implementation.d.ts","sourceRoot":"","sources":["../../src/agents/implementation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"implementation.d.ts","sourceRoot":"","sources":["../../src/agents/implementation.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAEzE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAa,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAO7C,YAAY,EAAE,qBAAqB,EAAE,CAAC;AAEtC;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,aAAa,CAAC;IACrC,UAAU,CAAC,EAAE,qBAAqB,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,aAAa,CAAC,EAAE,OAAO,aAAa,CAAC;IACrC,aAAa,CAAC,EAAE,OAAO,aAAa,CAAC;IACrC,WAAW,CAAC,EAAE,OAAO,WAAW,CAAC;IACjC,UAAU,CAAC,EAAE,qBAAqB,CAAC;CACpC;AAED,eAAO,MAAM,iBAAiB,8zBAuB+B,CAAC;AAsB9D;;GAEG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAkD9C;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAkD9C;AAWD;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,UAAU,GAAE,OAAO,WAAyB,GAC3C,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiDlD;AAmDD;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CAqCzB;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CAoCzB;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CAwCzB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,cAAc,EACzB,WAAW,EAAE,cAAc,EAC3B,cAAc,EAAE,cAAc,GAC7B,YAAY,CAYd;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAuBrD;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,WAAW,CAAC,CA6ItB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,qBAAqB,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,cAAc,GAAG,cAAc,GAAG,WAAW,CAAC;AAE3E;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,cAAc,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,wBAAsB,gCAAgC,CACpD,OAAO,EAAE,mBAAmB,EAC5B,WAAW,EAAE,MAAM,EAAE,GACpB,OAAO,CAAC,WAAW,CAAC,CAiOtB;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,WAAW,CAAC,CAyPtB;AAgCD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAuBjE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAErF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAuB9D;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,MAAM,CA0C/E;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAkBzD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,GAAE,MAAa,GAAG,MAAM,CAYnF;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAqClE;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,cAAc,CAAC,EAAE,mBAAmB,EAAE,GACrC,MAAM,CAkGR"}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { spawn, spawnSync } from 'child_process';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import {
|
|
3
|
+
import { ProcessManager } from '../core/process-manager.js';
|
|
4
|
+
import { parseStory, writeStory, updateStoryStatus, updateStoryField, resetImplementationRetryCount, incrementImplementationRetryCount, getEffectiveMaxImplementationRetries, incrementTotalRecoveryAttempts, } from '../core/story.js';
|
|
4
5
|
import { runAgentQuery } from '../core/client.js';
|
|
6
|
+
import { getLogger } from '../core/logger.js';
|
|
5
7
|
import { loadConfig, DEFAULT_TDD_CONFIG } from '../core/config.js';
|
|
6
8
|
import { verifyImplementation } from './verification.js';
|
|
7
9
|
import { createHash } from 'crypto';
|
|
10
|
+
import { parseTypeScriptErrors, classifyAndSortErrors } from '../services/error-classifier.js';
|
|
8
11
|
export const TDD_SYSTEM_PROMPT = `You are practicing strict Test-Driven Development.
|
|
9
12
|
|
|
10
13
|
Your workflow MUST follow this exact cycle:
|
|
@@ -59,6 +62,7 @@ export async function runSingleTest(testFile, workingDir, testTimeout) {
|
|
|
59
62
|
cwd: workingDir,
|
|
60
63
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
61
64
|
});
|
|
65
|
+
ProcessManager.getInstance().registerChild(child);
|
|
62
66
|
const timeoutId = setTimeout(() => {
|
|
63
67
|
killed = true;
|
|
64
68
|
child.kill('SIGTERM');
|
|
@@ -106,6 +110,7 @@ export async function runAllTests(workingDir, testTimeout) {
|
|
|
106
110
|
cwd: workingDir,
|
|
107
111
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
108
112
|
});
|
|
113
|
+
ProcessManager.getInstance().registerChild(child);
|
|
109
114
|
const timeoutId = setTimeout(() => {
|
|
110
115
|
killed = true;
|
|
111
116
|
child.kill('SIGTERM');
|
|
@@ -508,7 +513,7 @@ export async function runTDDImplementation(story, sdlcRoot, options = {}) {
|
|
|
508
513
|
story.frontmatter.tdd_test_history = history.slice(-100);
|
|
509
514
|
story.frontmatter.tdd_current_test = cycle;
|
|
510
515
|
// Persist the TDD cycle history to disk
|
|
511
|
-
writeStory(story);
|
|
516
|
+
await writeStory(story);
|
|
512
517
|
changesMade.push(`Completed TDD cycle ${cycleNumber}`);
|
|
513
518
|
// Check if all AC are now covered
|
|
514
519
|
// Re-read story to get latest content (agent may have updated checkboxes)
|
|
@@ -568,7 +573,7 @@ severity issues - these must be resolved. Review the specific feedback and make
|
|
|
568
573
|
}
|
|
569
574
|
// Add retry context if this is a retry attempt
|
|
570
575
|
if (attemptNumber > 1 && lastVerification) {
|
|
571
|
-
prompt += '\n\n' + buildRetryPrompt(lastVerification.testsOutput, lastVerification.buildOutput, attemptNumber, maxRetries);
|
|
576
|
+
prompt += '\n\n' + buildRetryPrompt(lastVerification.testsOutput, lastVerification.buildOutput, attemptNumber, maxRetries, attemptHistory);
|
|
572
577
|
}
|
|
573
578
|
else {
|
|
574
579
|
prompt += `
|
|
@@ -606,18 +611,43 @@ ${implementationResult}
|
|
|
606
611
|
// Append to story content
|
|
607
612
|
const updatedStory = parseStory(storyPath);
|
|
608
613
|
updatedStory.content += '\n\n' + implementationNotes;
|
|
609
|
-
writeStory(updatedStory);
|
|
614
|
+
await writeStory(updatedStory);
|
|
610
615
|
changesMade.push(attemptNumber > 1 ? `Added retry ${attemptNumber - 1} notes` : 'Added implementation notes');
|
|
616
|
+
// PRE-FLIGHT CHECK: Capture diff hash BEFORE verification to detect no-change scenarios early
|
|
617
|
+
const currentDiffHash = captureCurrentDiffHash(workingDir);
|
|
618
|
+
const changesSummary = extractChangedFiles(workingDir);
|
|
619
|
+
// Check for no-change scenario BEFORE running verification (saves ~30 seconds)
|
|
620
|
+
if (attemptNumber > 1 && lastDiffHash && lastDiffHash === currentDiffHash) {
|
|
621
|
+
changesMade.push('No changes detected since last attempt - skipping verification');
|
|
622
|
+
// Record this no-change attempt in history
|
|
623
|
+
attemptHistory.push({
|
|
624
|
+
attempt: attemptNumber,
|
|
625
|
+
testFailures: 0,
|
|
626
|
+
buildFailures: 0,
|
|
627
|
+
testSnippet: '',
|
|
628
|
+
buildSnippet: '',
|
|
629
|
+
changesSummary: 'No changes detected',
|
|
630
|
+
outcome: 'no_change',
|
|
631
|
+
});
|
|
632
|
+
return {
|
|
633
|
+
success: false,
|
|
634
|
+
story: parseStory(storyPath),
|
|
635
|
+
changesMade,
|
|
636
|
+
error: 'No progress detected - agent made no file changes',
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
// Update lastDiffHash for next iteration
|
|
640
|
+
lastDiffHash = currentDiffHash;
|
|
611
641
|
changesMade.push('Running verification before marking complete...');
|
|
612
642
|
const verification = await verifyImplementation(updatedStory, workingDir);
|
|
613
|
-
updateStoryField(updatedStory, 'last_test_run', {
|
|
643
|
+
await updateStoryField(updatedStory, 'last_test_run', {
|
|
614
644
|
passed: verification.passed,
|
|
615
645
|
failures: verification.failures,
|
|
616
646
|
timestamp: verification.timestamp,
|
|
617
647
|
});
|
|
618
648
|
if (verification.passed) {
|
|
619
649
|
// Success! Reset retry count and return success
|
|
620
|
-
resetImplementationRetryCount(updatedStory);
|
|
650
|
+
await resetImplementationRetryCount(updatedStory);
|
|
621
651
|
changesMade.push('Verification passed - implementation successful');
|
|
622
652
|
// Send success progress callback
|
|
623
653
|
if (onProgress) {
|
|
@@ -631,10 +661,10 @@ ${implementationResult}
|
|
|
631
661
|
}
|
|
632
662
|
// Verification failed - check for retry conditions
|
|
633
663
|
lastVerification = verification;
|
|
634
|
-
// Capture current diff hash for no-change detection
|
|
635
|
-
const currentDiffHash = captureCurrentDiffHash(workingDir);
|
|
636
664
|
// Track retry attempt
|
|
637
|
-
incrementImplementationRetryCount(updatedStory);
|
|
665
|
+
await incrementImplementationRetryCount(updatedStory);
|
|
666
|
+
// Increment global recovery counter
|
|
667
|
+
await incrementTotalRecoveryAttempts(updatedStory);
|
|
638
668
|
// Extract first 100 chars of test and build output for history
|
|
639
669
|
const testSnippet = verification.testsOutput.substring(0, 100).replace(/\n/g, ' ');
|
|
640
670
|
const buildSnippet = verification.buildOutput.substring(0, 100).replace(/\n/g, ' ');
|
|
@@ -644,6 +674,8 @@ ${implementationResult}
|
|
|
644
674
|
verification.buildOutput.includes('Error') ||
|
|
645
675
|
verification.buildOutput.includes('failed'));
|
|
646
676
|
const buildFailures = hasBuildErrors ? 1 : 0;
|
|
677
|
+
// Determine outcome based on what failed
|
|
678
|
+
const outcome = hasBuildErrors ? 'failed_build' : 'failed_tests';
|
|
647
679
|
// Record this attempt in history with both test and build failures
|
|
648
680
|
attemptHistory.push({
|
|
649
681
|
attempt: attemptNumber,
|
|
@@ -651,6 +683,8 @@ ${implementationResult}
|
|
|
651
683
|
buildFailures,
|
|
652
684
|
testSnippet,
|
|
653
685
|
buildSnippet,
|
|
686
|
+
changesSummary,
|
|
687
|
+
outcome,
|
|
654
688
|
});
|
|
655
689
|
// Add structured retry entry to changes array
|
|
656
690
|
if (attemptNumber > 1) {
|
|
@@ -659,17 +693,6 @@ ${implementationResult}
|
|
|
659
693
|
else {
|
|
660
694
|
changesMade.push(`Attempt ${attemptNumber}: ${verification.failures} test(s) failing`);
|
|
661
695
|
}
|
|
662
|
-
// Check for no-change scenario (agent made no progress)
|
|
663
|
-
// Only check after first failure (attemptNumber > 1)
|
|
664
|
-
// Check this BEFORE max retries to fail fast on identical changes
|
|
665
|
-
if (attemptNumber > 1 && lastDiffHash && lastDiffHash === currentDiffHash) {
|
|
666
|
-
return {
|
|
667
|
-
success: false,
|
|
668
|
-
story: parseStory(storyPath),
|
|
669
|
-
changesMade,
|
|
670
|
-
error: `Implementation blocked: No progress detected on retry attempt ${attemptNumber - 1}. Agent made identical changes. Stopping retries early.\n\nLast test output:\n${truncateTestOutput(verification.testsOutput, 1000)}`,
|
|
671
|
-
};
|
|
672
|
-
}
|
|
673
696
|
// Check if we've reached max retries
|
|
674
697
|
if (attemptHistory.length > maxRetries) {
|
|
675
698
|
const attemptSummary = attemptHistory
|
|
@@ -700,7 +723,6 @@ ${implementationResult}
|
|
|
700
723
|
error: `Implementation blocked after ${attemptNumber} attempts:\n${attemptSummary}\n\nLast test output:\n${truncateTestOutput(verification.testsOutput, 5000)}`,
|
|
701
724
|
};
|
|
702
725
|
}
|
|
703
|
-
lastDiffHash = currentDiffHash;
|
|
704
726
|
// Continue to next retry attempt - send progress update
|
|
705
727
|
if (onProgress) {
|
|
706
728
|
onProgress({ type: 'assistant_message', content: `Retry ${attemptNumber} failed: ${verification.failures} test(s) failing, attempting retry ${attemptNumber + 1}...` });
|
|
@@ -720,10 +742,16 @@ ${implementationResult}
|
|
|
720
742
|
* Executes the implementation plan, creating code changes and tests.
|
|
721
743
|
*/
|
|
722
744
|
export async function runImplementationAgent(storyPath, sdlcRoot, options = {}) {
|
|
745
|
+
const logger = getLogger();
|
|
746
|
+
const startTime = Date.now();
|
|
723
747
|
let story = parseStory(storyPath);
|
|
724
748
|
let currentStoryPath = storyPath;
|
|
725
749
|
const changesMade = [];
|
|
726
750
|
const workingDir = path.dirname(sdlcRoot);
|
|
751
|
+
logger.info('implementation', 'Starting implementation phase', {
|
|
752
|
+
storyId: story.frontmatter.id,
|
|
753
|
+
retryCount: story.frontmatter.implementation_retry_count || 0,
|
|
754
|
+
});
|
|
727
755
|
try {
|
|
728
756
|
// Security: Validate working directory before git operations
|
|
729
757
|
validateWorkingDir(workingDir);
|
|
@@ -767,7 +795,7 @@ export async function runImplementationAgent(storyPath, sdlcRoot, options = {})
|
|
|
767
795
|
}
|
|
768
796
|
}
|
|
769
797
|
// Update story with branch info
|
|
770
|
-
updateStoryField(story, 'branch', branchName);
|
|
798
|
+
await updateStoryField(story, 'branch', branchName);
|
|
771
799
|
}
|
|
772
800
|
}
|
|
773
801
|
catch {
|
|
@@ -776,13 +804,44 @@ export async function runImplementationAgent(storyPath, sdlcRoot, options = {})
|
|
|
776
804
|
}
|
|
777
805
|
// Update status to in-progress if not already there
|
|
778
806
|
if (story.frontmatter.status !== 'in-progress') {
|
|
779
|
-
story = updateStoryStatus(story, 'in-progress');
|
|
807
|
+
story = await updateStoryStatus(story, 'in-progress');
|
|
780
808
|
currentStoryPath = story.path;
|
|
781
809
|
changesMade.push('Updated status to in-progress');
|
|
782
810
|
}
|
|
783
811
|
// Check if TDD is enabled for this story
|
|
784
812
|
const config = loadConfig(workingDir);
|
|
785
813
|
const tddEnabled = story.frontmatter.tdd_enabled ?? config.tdd?.enabled ?? false;
|
|
814
|
+
// Check if orchestrator is enabled
|
|
815
|
+
if (config.useOrchestrator && !tddEnabled) {
|
|
816
|
+
changesMade.push('Using sequential task orchestrator for implementation');
|
|
817
|
+
const { runImplementationOrchestrator } = await import('./orchestrator.js');
|
|
818
|
+
const orchestratorResult = await runImplementationOrchestrator(currentStoryPath, sdlcRoot, {
|
|
819
|
+
maxRetriesPerTask: config.implementation.maxRetries,
|
|
820
|
+
commitAfterEachTask: true,
|
|
821
|
+
stopOnFirstFailure: true,
|
|
822
|
+
});
|
|
823
|
+
if (!orchestratorResult.success) {
|
|
824
|
+
// Orchestration failed
|
|
825
|
+
const errorDetails = orchestratorResult.failedTasks
|
|
826
|
+
.map((ft) => ` - ${ft.taskId}: ${ft.error} (${ft.attempts} attempts)`)
|
|
827
|
+
.join('\n');
|
|
828
|
+
return {
|
|
829
|
+
success: false,
|
|
830
|
+
story: parseStory(currentStoryPath),
|
|
831
|
+
changesMade,
|
|
832
|
+
error: `Implementation orchestration failed:\n${errorDetails}\n\nCompleted: ${orchestratorResult.tasksCompleted}, Failed: ${orchestratorResult.tasksFailed}, Remaining: ${orchestratorResult.tasksRemaining}`,
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
// Orchestration succeeded - mark implementation complete
|
|
836
|
+
await updateStoryField(story, 'implementation_complete', true);
|
|
837
|
+
changesMade.push('Marked implementation_complete: true');
|
|
838
|
+
changesMade.push(`Orchestration complete: ${orchestratorResult.tasksCompleted} tasks completed in ${orchestratorResult.totalAgentInvocations} agent invocations`);
|
|
839
|
+
return {
|
|
840
|
+
success: true,
|
|
841
|
+
story: parseStory(currentStoryPath),
|
|
842
|
+
changesMade,
|
|
843
|
+
};
|
|
844
|
+
}
|
|
786
845
|
if (tddEnabled) {
|
|
787
846
|
changesMade.push('TDD mode enabled - using Red-Green-Refactor implementation');
|
|
788
847
|
// Run TDD implementation loop
|
|
@@ -795,7 +854,7 @@ export async function runImplementationAgent(storyPath, sdlcRoot, options = {})
|
|
|
795
854
|
// TDD completed all cycles - now verify with retry support
|
|
796
855
|
changesMade.push('Running final verification...');
|
|
797
856
|
const verification = await verifyImplementation(tddResult.story, workingDir);
|
|
798
|
-
updateStoryField(tddResult.story, 'last_test_run', {
|
|
857
|
+
await updateStoryField(tddResult.story, 'last_test_run', {
|
|
799
858
|
passed: verification.passed,
|
|
800
859
|
failures: verification.failures,
|
|
801
860
|
timestamp: verification.timestamp,
|
|
@@ -803,7 +862,7 @@ export async function runImplementationAgent(storyPath, sdlcRoot, options = {})
|
|
|
803
862
|
if (!verification.passed) {
|
|
804
863
|
// TDD final verification failed - this is unexpected since TDD should ensure all tests pass
|
|
805
864
|
// Reset retry count since this is the first failure at this stage
|
|
806
|
-
resetImplementationRetryCount(tddResult.story);
|
|
865
|
+
await resetImplementationRetryCount(tddResult.story);
|
|
807
866
|
return {
|
|
808
867
|
success: false,
|
|
809
868
|
story: parseStory(currentStoryPath),
|
|
@@ -812,8 +871,8 @@ export async function runImplementationAgent(storyPath, sdlcRoot, options = {})
|
|
|
812
871
|
};
|
|
813
872
|
}
|
|
814
873
|
// Success - reset retry count
|
|
815
|
-
resetImplementationRetryCount(tddResult.story);
|
|
816
|
-
updateStoryField(tddResult.story, 'implementation_complete', true);
|
|
874
|
+
await resetImplementationRetryCount(tddResult.story);
|
|
875
|
+
await updateStoryField(tddResult.story, 'implementation_complete', true);
|
|
817
876
|
changesMade.push('Marked implementation_complete: true');
|
|
818
877
|
return {
|
|
819
878
|
success: true,
|
|
@@ -862,8 +921,13 @@ export async function runImplementationAgent(storyPath, sdlcRoot, options = {})
|
|
|
862
921
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
863
922
|
changesMade.push(`Commit warning: ${errorMsg} (continuing implementation)`);
|
|
864
923
|
}
|
|
865
|
-
updateStoryField(updatedStory, 'implementation_complete', true);
|
|
924
|
+
await updateStoryField(updatedStory, 'implementation_complete', true);
|
|
866
925
|
changesMade.push('Marked implementation_complete: true');
|
|
926
|
+
logger.info('implementation', 'Implementation phase complete', {
|
|
927
|
+
storyId: story.frontmatter.id,
|
|
928
|
+
durationMs: Date.now() - startTime,
|
|
929
|
+
changesCount: changesMade.length,
|
|
930
|
+
});
|
|
867
931
|
return {
|
|
868
932
|
success: true,
|
|
869
933
|
story: parseStory(currentStoryPath),
|
|
@@ -871,11 +935,17 @@ export async function runImplementationAgent(storyPath, sdlcRoot, options = {})
|
|
|
871
935
|
};
|
|
872
936
|
}
|
|
873
937
|
catch (error) {
|
|
938
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
939
|
+
logger.error('implementation', 'Implementation phase failed', {
|
|
940
|
+
storyId: story.frontmatter.id,
|
|
941
|
+
durationMs: Date.now() - startTime,
|
|
942
|
+
error: errorMessage,
|
|
943
|
+
});
|
|
874
944
|
return {
|
|
875
945
|
success: false,
|
|
876
946
|
story,
|
|
877
947
|
changesMade,
|
|
878
|
-
error:
|
|
948
|
+
error: errorMessage,
|
|
879
949
|
};
|
|
880
950
|
}
|
|
881
951
|
}
|
|
@@ -942,6 +1012,72 @@ export function captureCurrentDiffHash(workingDir) {
|
|
|
942
1012
|
export function hasChangesOccurred(previousHash, currentHash) {
|
|
943
1013
|
return previousHash !== currentHash;
|
|
944
1014
|
}
|
|
1015
|
+
/**
|
|
1016
|
+
* Extract list of changed files from git diff
|
|
1017
|
+
* @param workingDir The working directory
|
|
1018
|
+
* @returns Comma-separated list of changed files, or descriptive message
|
|
1019
|
+
*/
|
|
1020
|
+
export function extractChangedFiles(workingDir) {
|
|
1021
|
+
try {
|
|
1022
|
+
validateWorkingDir(workingDir);
|
|
1023
|
+
const result = spawnSync('git', ['diff', 'HEAD', '--name-only'], {
|
|
1024
|
+
cwd: workingDir,
|
|
1025
|
+
shell: false,
|
|
1026
|
+
encoding: 'utf-8',
|
|
1027
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
1028
|
+
});
|
|
1029
|
+
if (result.status === 0 && result.stdout) {
|
|
1030
|
+
const files = result.stdout.trim().split('\n').filter(Boolean);
|
|
1031
|
+
if (files.length === 0) {
|
|
1032
|
+
return 'No changes detected';
|
|
1033
|
+
}
|
|
1034
|
+
return files.join(', ');
|
|
1035
|
+
}
|
|
1036
|
+
return 'No changes detected';
|
|
1037
|
+
}
|
|
1038
|
+
catch {
|
|
1039
|
+
return 'Unable to determine changes';
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* Build formatted retry history section for agent prompts
|
|
1044
|
+
* @param history Array of attempt history entries
|
|
1045
|
+
* @returns Formatted string for inclusion in retry prompts
|
|
1046
|
+
*/
|
|
1047
|
+
export function buildRetryHistorySection(history) {
|
|
1048
|
+
if (!history || history.length === 0) {
|
|
1049
|
+
return '';
|
|
1050
|
+
}
|
|
1051
|
+
const recentHistory = history.slice(-3);
|
|
1052
|
+
let section = `PREVIOUS ATTEMPT HISTORY (Last ${recentHistory.length} attempts):
|
|
1053
|
+
|
|
1054
|
+
`;
|
|
1055
|
+
for (const entry of recentHistory) {
|
|
1056
|
+
const outcomeLabel = entry.outcome === 'failed_tests'
|
|
1057
|
+
? 'Tests failed'
|
|
1058
|
+
: entry.outcome === 'failed_build'
|
|
1059
|
+
? 'Build failed'
|
|
1060
|
+
: 'No changes made';
|
|
1061
|
+
section += `Attempt ${entry.attempt}: ${entry.changesSummary} -> ${outcomeLabel}\n`;
|
|
1062
|
+
const errors = [];
|
|
1063
|
+
if (entry.testSnippet && entry.testSnippet.trim()) {
|
|
1064
|
+
errors.push(entry.testSnippet.trim());
|
|
1065
|
+
}
|
|
1066
|
+
if (entry.buildSnippet && entry.buildSnippet.trim()) {
|
|
1067
|
+
errors.push(entry.buildSnippet.trim());
|
|
1068
|
+
}
|
|
1069
|
+
const errorsToShow = errors.slice(0, 2);
|
|
1070
|
+
if (errorsToShow.length > 0) {
|
|
1071
|
+
for (const err of errorsToShow) {
|
|
1072
|
+
section += ` - ${err.substring(0, 100)}\n`;
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
section += `
|
|
1077
|
+
**IMPORTANT: Do NOT repeat the same fixes. Try a different approach.**
|
|
1078
|
+
`;
|
|
1079
|
+
return section;
|
|
1080
|
+
}
|
|
945
1081
|
/**
|
|
946
1082
|
* Sanitize test output to remove ANSI escape sequences and potential injection patterns
|
|
947
1083
|
* @param output Test output string
|
|
@@ -982,21 +1118,114 @@ export function truncateTestOutput(output, maxLength = 5000) {
|
|
|
982
1118
|
const truncated = sanitized.substring(0, maxLength);
|
|
983
1119
|
return truncated + `\n\n[Output truncated. Showing first ${maxLength} characters of ${sanitized.length} total.]`;
|
|
984
1120
|
}
|
|
1121
|
+
/**
|
|
1122
|
+
* Detect if errors are related to missing dependencies
|
|
1123
|
+
* Returns module names that are missing, if any
|
|
1124
|
+
*/
|
|
1125
|
+
export function detectMissingDependencies(output) {
|
|
1126
|
+
if (!output)
|
|
1127
|
+
return [];
|
|
1128
|
+
const missingModules = [];
|
|
1129
|
+
// Pattern: Cannot find module 'package-name'
|
|
1130
|
+
const cannotFindPattern = /Cannot find module ['"]([^'"]+)['"]/g;
|
|
1131
|
+
let match;
|
|
1132
|
+
while ((match = cannotFindPattern.exec(output)) !== null) {
|
|
1133
|
+
const moduleName = match[1];
|
|
1134
|
+
// Only include external packages, not relative imports
|
|
1135
|
+
if (!moduleName.startsWith('.') && !moduleName.startsWith('/')) {
|
|
1136
|
+
// Extract base package name (handle scoped packages like @types/foo)
|
|
1137
|
+
const baseName = moduleName.startsWith('@')
|
|
1138
|
+
? moduleName.split('/').slice(0, 2).join('/')
|
|
1139
|
+
: moduleName.split('/')[0];
|
|
1140
|
+
if (!missingModules.includes(baseName)) {
|
|
1141
|
+
missingModules.push(baseName);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
// Pattern: Module not found: Error: Can't resolve 'package-name'
|
|
1146
|
+
const cantResolvePattern = /(?:Module not found|Can't resolve)[:\s]+['"]([^'"]+)['"]/g;
|
|
1147
|
+
while ((match = cantResolvePattern.exec(output)) !== null) {
|
|
1148
|
+
const moduleName = match[1];
|
|
1149
|
+
if (!moduleName.startsWith('.') && !moduleName.startsWith('/')) {
|
|
1150
|
+
const baseName = moduleName.startsWith('@')
|
|
1151
|
+
? moduleName.split('/').slice(0, 2).join('/')
|
|
1152
|
+
: moduleName.split('/')[0];
|
|
1153
|
+
if (!missingModules.includes(baseName)) {
|
|
1154
|
+
missingModules.push(baseName);
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
return missingModules;
|
|
1159
|
+
}
|
|
985
1160
|
/**
|
|
986
1161
|
* Build retry prompt for implementation agent
|
|
987
1162
|
* @param testOutput Test failure output
|
|
1163
|
+
* @param buildOutput Build output
|
|
988
1164
|
* @param attemptNumber Current attempt number (1-indexed)
|
|
989
1165
|
* @param maxRetries Maximum number of retries
|
|
1166
|
+
* @param attemptHistory Optional history of previous attempts
|
|
990
1167
|
* @returns Prompt string for retry attempt
|
|
991
1168
|
*/
|
|
992
|
-
export function buildRetryPrompt(testOutput, buildOutput, attemptNumber, maxRetries) {
|
|
1169
|
+
export function buildRetryPrompt(testOutput, buildOutput, attemptNumber, maxRetries, attemptHistory) {
|
|
993
1170
|
const truncatedTestOutput = truncateTestOutput(testOutput);
|
|
994
1171
|
const truncatedBuildOutput = truncateTestOutput(buildOutput);
|
|
1172
|
+
// Detect if this is a dependency issue
|
|
1173
|
+
const combinedOutput = (buildOutput || '') + '\n' + (testOutput || '');
|
|
1174
|
+
const missingDeps = detectMissingDependencies(combinedOutput);
|
|
1175
|
+
// Parse and classify TypeScript errors from build output
|
|
1176
|
+
const tsErrors = parseTypeScriptErrors(buildOutput || '');
|
|
1177
|
+
const classified = classifyAndSortErrors(tsErrors);
|
|
995
1178
|
let prompt = `CRITICAL: Tests are failing. You attempted implementation but verification failed.
|
|
996
1179
|
|
|
997
1180
|
This is retry attempt ${attemptNumber} of ${maxRetries}. Previous attempts failed with similar errors.
|
|
998
1181
|
|
|
999
1182
|
`;
|
|
1183
|
+
// Add special guidance for missing dependencies
|
|
1184
|
+
if (missingDeps.length > 0) {
|
|
1185
|
+
prompt += `**DEPENDENCY ISSUE DETECTED**
|
|
1186
|
+
|
|
1187
|
+
The errors indicate missing npm packages: ${missingDeps.join(', ')}
|
|
1188
|
+
|
|
1189
|
+
This is NOT a code bug - the packages need to be installed. Before making any code changes:
|
|
1190
|
+
1. Run \`npm install ${missingDeps.join(' ')}\` to add the missing packages
|
|
1191
|
+
2. If these are type definitions, also run \`npm install -D @types/${missingDeps.filter(d => !d.startsWith('@')).join(' @types/')}\`
|
|
1192
|
+
3. Re-run the build/tests after installing
|
|
1193
|
+
|
|
1194
|
+
`;
|
|
1195
|
+
}
|
|
1196
|
+
// Add TypeScript error classification if errors were found
|
|
1197
|
+
if (classified.source.length > 0 || classified.cascading.length > 0) {
|
|
1198
|
+
prompt += `TYPESCRIPT ERROR CLASSIFICATION
|
|
1199
|
+
|
|
1200
|
+
`;
|
|
1201
|
+
if (classified.source.length > 0) {
|
|
1202
|
+
prompt += `⚠️ SOURCE ERRORS (Fix these first - root causes):
|
|
1203
|
+
|
|
1204
|
+
`;
|
|
1205
|
+
classified.source.forEach((err) => {
|
|
1206
|
+
const location = err.line ? `${err.filePath}:${err.line}` : err.filePath;
|
|
1207
|
+
prompt += `- ${err.code} in ${location}: ${err.message}\n`;
|
|
1208
|
+
});
|
|
1209
|
+
prompt += '\n';
|
|
1210
|
+
}
|
|
1211
|
+
if (classified.cascading.length > 0) {
|
|
1212
|
+
prompt += `💡 CASCADING ERRORS (may automatically resolve):
|
|
1213
|
+
|
|
1214
|
+
`;
|
|
1215
|
+
classified.cascading.forEach((err) => {
|
|
1216
|
+
const location = err.line ? `${err.filePath}:${err.line}` : err.filePath;
|
|
1217
|
+
prompt += `- ${err.code} in ${location}: ${err.message}\n`;
|
|
1218
|
+
});
|
|
1219
|
+
prompt += '\n';
|
|
1220
|
+
}
|
|
1221
|
+
prompt += `**Strategy:** Fix source errors first, as they may automatically resolve multiple cascading errors.
|
|
1222
|
+
|
|
1223
|
+
`;
|
|
1224
|
+
}
|
|
1225
|
+
if (attemptHistory && attemptHistory.length > 0) {
|
|
1226
|
+
prompt += buildRetryHistorySection(attemptHistory);
|
|
1227
|
+
prompt += '\n';
|
|
1228
|
+
}
|
|
1000
1229
|
if (buildOutput && buildOutput.trim().length > 0) {
|
|
1001
1230
|
prompt += `Build Output:
|
|
1002
1231
|
\`\`\`
|