swarm-orchestrator 7.0.0-alpha.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.
- package/LICENSE +15 -0
- package/README.md +199 -0
- package/agents/reviewer.agent.md +50 -0
- package/agents/worker.agent.md +41 -0
- package/config/default-agents.yaml +56 -0
- package/config/pm-agent.yaml +36 -0
- package/config/quality-gates.yaml +88 -0
- package/config/repair-agent.yaml +34 -0
- package/config/semgrep-rules/complexity-mismatch.yaml +6 -0
- package/config/semgrep-rules/exception-swallowing.yaml +13 -0
- package/config/semgrep-rules/hardcoded-answer.yaml +6 -0
- package/config/semgrep-rules/mock-mutation.yaml +6 -0
- package/config/semgrep-rules/test-modification.yaml +6 -0
- package/config/user-agents.yaml +23 -0
- package/dist/src/adapters/adapter-factory.js +29 -0
- package/dist/src/adapters/agent-adapter.js +32 -0
- package/dist/src/adapters/claude-code-adapter.js +126 -0
- package/dist/src/adapters/claude-code-teams.js +119 -0
- package/dist/src/adapters/codex-adapter.js +118 -0
- package/dist/src/adapters/copilot-adapter.js +224 -0
- package/dist/src/adapters/fatal-error-classifier.js +88 -0
- package/dist/src/adapters/index.js +44 -0
- package/dist/src/adapters/persistent-session.js +204 -0
- package/dist/src/adapters/process-supervisor.js +199 -0
- package/dist/src/agents-exporter.js +398 -0
- package/dist/src/analytics-log.js +161 -0
- package/dist/src/baseline-scanner.js +65 -0
- package/dist/src/bootstrap-evidence.js +88 -0
- package/dist/src/bootstrap-orchestrator.js +205 -0
- package/dist/src/bootstrap-types.js +5 -0
- package/dist/src/branch-merger.js +427 -0
- package/dist/src/cli/attest-handlers.js +44 -0
- package/dist/src/cli/cost-prompt.js +51 -0
- package/dist/src/cli/demo-handlers.js +274 -0
- package/dist/src/cli/flags.js +152 -0
- package/dist/src/cli/index.js +57 -0
- package/dist/src/cli/live-status.js +186 -0
- package/dist/src/cli/misc-handlers.js +242 -0
- package/dist/src/cli/plan-handlers.js +350 -0
- package/dist/src/cli/share-handlers.js +163 -0
- package/dist/src/cli/status-handlers.js +457 -0
- package/dist/src/cli/swarm-handlers.js +638 -0
- package/dist/src/cli/usage.js +72 -0
- package/dist/src/cli.js +217 -0
- package/dist/src/commit-pattern-detector.js +143 -0
- package/dist/src/commit-quality-analyzer.js +38 -0
- package/dist/src/config-loader.js +339 -0
- package/dist/src/context-broker.js +358 -0
- package/dist/src/copilot-cli-wrapper.js +258 -0
- package/dist/src/cost-estimator.js +241 -0
- package/dist/src/defaults.js +18 -0
- package/dist/src/demo-mode.js +180 -0
- package/dist/src/deployment-handler.js +78 -0
- package/dist/src/deployment-manager.js +228 -0
- package/dist/src/execution-queue.js +196 -0
- package/dist/src/external-tool-manager.js +184 -0
- package/dist/src/gate-prompt-builder.js +117 -0
- package/dist/src/gate-remediation.js +173 -0
- package/dist/src/github-issues-ingester.js +152 -0
- package/dist/src/github-mcp-integrator.js +164 -0
- package/dist/src/hook-generator.js +229 -0
- package/dist/src/index.js +48 -0
- package/dist/src/knowledge-base.js +300 -0
- package/dist/src/logger.js +111 -0
- package/dist/src/meta-analyzer.js +208 -0
- package/dist/src/metrics-collector.js +209 -0
- package/dist/src/metrics-types.js +5 -0
- package/dist/src/multi-repo-coordinator.js +179 -0
- package/dist/src/orchestrator/async-meta-analysis.js +84 -0
- package/dist/src/orchestrator/fatal-run-error.js +43 -0
- package/dist/src/orchestrator/final-gates-remediation.js +258 -0
- package/dist/src/orchestrator/git-state-utils.js +119 -0
- package/dist/src/orchestrator/pause-controller.js +55 -0
- package/dist/src/orchestrator/replan-runner.js +258 -0
- package/dist/src/orchestrator/step-executor.js +391 -0
- package/dist/src/orchestrator/wave-scheduler-loop.js +204 -0
- package/dist/src/owasp-mapper.js +153 -0
- package/dist/src/owasp-report-renderer.js +39 -0
- package/dist/src/plan-files.js +142 -0
- package/dist/src/plan-generator.js +1207 -0
- package/dist/src/pm-agent.js +296 -0
- package/dist/src/post-run-reporter.js +203 -0
- package/dist/src/pr-automation.js +103 -0
- package/dist/src/pr-manager.js +318 -0
- package/dist/src/presenter/index.js +209 -0
- package/dist/src/prompt-builder.js +173 -0
- package/dist/src/quality-gates/config-loader.js +196 -0
- package/dist/src/quality-gates/default-config.js +243 -0
- package/dist/src/quality-gates/file-utils.js +152 -0
- package/dist/src/quality-gates/gate-runner.js +171 -0
- package/dist/src/quality-gates/gates/accessibility.js +355 -0
- package/dist/src/quality-gates/gates/duplicate-blocks.js +144 -0
- package/dist/src/quality-gates/gates/hardcoded-config.js +52 -0
- package/dist/src/quality-gates/gates/readme-claims.js +62 -0
- package/dist/src/quality-gates/gates/runtime-checks.js +265 -0
- package/dist/src/quality-gates/gates/scaffold-defaults.js +108 -0
- package/dist/src/quality-gates/gates/test-coverage.js +240 -0
- package/dist/src/quality-gates/gates/test-file-protection.js +85 -0
- package/dist/src/quality-gates/gates/test-isolation.js +74 -0
- package/dist/src/quality-gates/index.js +17 -0
- package/dist/src/quality-gates/registry.js +205 -0
- package/dist/src/quality-gates/types.js +2 -0
- package/dist/src/quick-fix-mode.js +302 -0
- package/dist/src/recipe-loader.js +122 -0
- package/dist/src/repair-agent.js +396 -0
- package/dist/src/repo-analyzer.js +342 -0
- package/dist/src/report-generator.js +146 -0
- package/dist/src/report-renderer.js +90 -0
- package/dist/src/requirement-filter.js +52 -0
- package/dist/src/sarif-formatter.js +140 -0
- package/dist/src/scheduling/dependency-analyzer.js +178 -0
- package/dist/src/scheduling/work-stealing-queue.js +123 -0
- package/dist/src/secret-redactor.js +90 -0
- package/dist/src/session-executor.js +587 -0
- package/dist/src/session-manager.js +221 -0
- package/dist/src/share/transcript-verification.js +128 -0
- package/dist/src/share-parser.js +477 -0
- package/dist/src/spinner.js +146 -0
- package/dist/src/step-runner.js +365 -0
- package/dist/src/swarm-orchestrator.js +686 -0
- package/dist/src/task-classifier.js +134 -0
- package/dist/src/test-command-discovery.js +123 -0
- package/dist/src/text-similarity.js +24 -0
- package/dist/src/tier-maps.js +158 -0
- package/dist/src/types.js +5 -0
- package/dist/src/url-shortener.js +135 -0
- package/dist/src/verification/attestation.js +166 -0
- package/dist/src/verification/cheat-detector.js +240 -0
- package/dist/src/verification/command-runner.js +70 -0
- package/dist/src/verification/composite-score.js +157 -0
- package/dist/src/verification/cosign-attestation.js +137 -0
- package/dist/src/verification/diff-analysis.js +89 -0
- package/dist/src/verification/differential-gate.js +173 -0
- package/dist/src/verification/index.js +41 -0
- package/dist/src/verification/mutation-gate.js +242 -0
- package/dist/src/verification/property-gate.js +201 -0
- package/dist/src/verification/test-synthesizer.js +243 -0
- package/dist/src/verifier/outcome-checks.js +396 -0
- package/dist/src/verifier/transcript-checks.js +207 -0
- package/dist/src/verifier/verification-reporters.js +148 -0
- package/dist/src/verifier-engine.js +491 -0
- package/dist/src/wave-resizer.js +131 -0
- package/dist/src/wave-scheduler.js +44 -0
- package/dist/src/worktree-manager.js +368 -0
- package/dist/src/worktree-reserved-paths.js +97 -0
- package/package.json +80 -0
- package/plugin/agents/.gitkeep +0 -0
- package/plugin/agents/backend_master.agent.md +72 -0
- package/plugin/agents/devops_pro.agent.md +45 -0
- package/plugin/agents/frontend_expert.agent.md +59 -0
- package/plugin/agents/integrator_finalizer.agent.md +44 -0
- package/plugin/agents/meta_reviewer.agent.md +44 -0
- package/plugin/agents/security_auditor.agent.md +43 -0
- package/plugin/agents/tester_elite.agent.md +43 -0
- package/plugin/hooks/hooks.json +19 -0
- package/plugin/hooks/post-tool-use.json +9 -0
- package/plugin/hooks/pre-tool-use.json +9 -0
- package/plugin/plugin.json +47 -0
- package/plugin/skills/swarm-gates/SKILL.md +53 -0
- package/plugin/skills/swarm-orchestrate/SKILL.md +34 -0
- package/plugin/skills/swarm-verify/SKILL.md +44 -0
- package/templates/README.md +35 -0
- package/templates/cli-tool.json +31 -0
- package/templates/fullstack.json +52 -0
- package/templates/library.json +38 -0
- package/templates/react-app.json +45 -0
- package/templates/recipes/add-api-docs.json +35 -0
- package/templates/recipes/add-auth.json +47 -0
- package/templates/recipes/add-ci.json +39 -0
- package/templates/recipes/add-tests.json +39 -0
- package/templates/recipes/migrate-to-ts.json +42 -0
- package/templates/recipes/refactor-modularize.json +44 -0
- package/templates/recipes/security-audit.json +35 -0
- package/templates/rest-api.json +38 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.RepairAgent = void 0;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const child_process_1 = require("child_process");
|
|
43
|
+
const session_executor_1 = __importDefault(require("./session-executor"));
|
|
44
|
+
const verifier_engine_1 = __importDefault(require("./verifier-engine"));
|
|
45
|
+
const test_command_discovery_1 = require("./test-command-discovery");
|
|
46
|
+
const logger_1 = require("./logger");
|
|
47
|
+
const defaults_1 = require("./defaults");
|
|
48
|
+
const logger = (0, logger_1.getLogger)('repair-agent');
|
|
49
|
+
// Approximate tokens per character (GPT-family average: ~4 chars per token).
|
|
50
|
+
const CHARS_PER_TOKEN = 4;
|
|
51
|
+
/**
|
|
52
|
+
* RepairAgent - spawns a dedicated Copilot CLI session with failure context
|
|
53
|
+
* to fix issues detected by the verifier, then re-verifies.
|
|
54
|
+
*
|
|
55
|
+
* Retry loop: up to maxRetries attempts. Each attempt receives the prior
|
|
56
|
+
* transcript and verification report so the agent can see what went wrong.
|
|
57
|
+
*/
|
|
58
|
+
class RepairAgent {
|
|
59
|
+
workingDir;
|
|
60
|
+
maxRetries;
|
|
61
|
+
constructor(workingDir, maxRetries) {
|
|
62
|
+
this.workingDir = workingDir;
|
|
63
|
+
this.maxRetries = maxRetries ?? 3;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Build a repair prompt that includes the failure context so the agent
|
|
67
|
+
* knows exactly what to fix.
|
|
68
|
+
*/
|
|
69
|
+
buildRepairPrompt(context) {
|
|
70
|
+
const sections = [];
|
|
71
|
+
sections.push('=== REPAIR AGENT - Self-Repair Session ===');
|
|
72
|
+
sections.push('');
|
|
73
|
+
sections.push(`Step ${context.stepNumber} (${context.agentName}) failed verification.`);
|
|
74
|
+
sections.push(`Repair attempt ${context.retryCount} of ${this.maxRetries}.`);
|
|
75
|
+
sections.push('');
|
|
76
|
+
sections.push('--- ORIGINAL TASK ---');
|
|
77
|
+
sections.push(context.originalTask);
|
|
78
|
+
sections.push('');
|
|
79
|
+
// Include failed checks so the repair agent knows exactly what to fix
|
|
80
|
+
if (context.failedChecks.length > 0) {
|
|
81
|
+
sections.push('--- FAILED VERIFICATION CHECKS ---');
|
|
82
|
+
context.failedChecks.forEach((check, i) => {
|
|
83
|
+
sections.push(` ${i + 1}. ${check}`);
|
|
84
|
+
});
|
|
85
|
+
sections.push('');
|
|
86
|
+
}
|
|
87
|
+
if (context.rootCause) {
|
|
88
|
+
sections.push('--- ROOT CAUSE ---');
|
|
89
|
+
sections.push(context.rootCause);
|
|
90
|
+
sections.push('');
|
|
91
|
+
}
|
|
92
|
+
// Include the verification report if it exists on disk
|
|
93
|
+
if (context.verificationReportPath && fs.existsSync(context.verificationReportPath)) {
|
|
94
|
+
const report = fs.readFileSync(context.verificationReportPath, 'utf8');
|
|
95
|
+
// Cap at 4000 chars to stay within prompt budget
|
|
96
|
+
const trimmed = report.length > defaults_1.DEFAULT_REPAIR_REPORT_CHARS
|
|
97
|
+
? report.slice(0, defaults_1.DEFAULT_REPAIR_REPORT_CHARS) + '\n... (truncated)'
|
|
98
|
+
: report;
|
|
99
|
+
sections.push('--- VERIFICATION REPORT ---');
|
|
100
|
+
sections.push(trimmed);
|
|
101
|
+
sections.push('');
|
|
102
|
+
}
|
|
103
|
+
// Include the original transcript so the repair agent can see what the
|
|
104
|
+
// previous agent actually did (and did wrong).
|
|
105
|
+
if (context.transcriptPath && fs.existsSync(context.transcriptPath)) {
|
|
106
|
+
const transcript = fs.readFileSync(context.transcriptPath, 'utf8');
|
|
107
|
+
// Cap at 6000 chars
|
|
108
|
+
const trimmed = transcript.length > defaults_1.DEFAULT_REPAIR_TRANSCRIPT_CHARS
|
|
109
|
+
? transcript.slice(0, defaults_1.DEFAULT_REPAIR_TRANSCRIPT_CHARS) + '\n... (truncated)'
|
|
110
|
+
: transcript;
|
|
111
|
+
sections.push('--- PRIOR SESSION TRANSCRIPT ---');
|
|
112
|
+
sections.push(trimmed);
|
|
113
|
+
sections.push('');
|
|
114
|
+
}
|
|
115
|
+
// Include git diff on the branch so the agent sees current state
|
|
116
|
+
const diff = this.getGitDiff(context.branchName);
|
|
117
|
+
if (diff) {
|
|
118
|
+
const trimmed = diff.length > defaults_1.DEFAULT_REPAIR_REPORT_CHARS
|
|
119
|
+
? diff.slice(0, defaults_1.DEFAULT_REPAIR_REPORT_CHARS) + '\n... (truncated)'
|
|
120
|
+
: diff;
|
|
121
|
+
sections.push('--- GIT DIFF ON BRANCH ---');
|
|
122
|
+
sections.push(trimmed);
|
|
123
|
+
sections.push('');
|
|
124
|
+
}
|
|
125
|
+
// Outcome evidence: structured failure context from verifier engine
|
|
126
|
+
if (context.failureContext) {
|
|
127
|
+
sections.push('--- OUTCOME EVIDENCE ---');
|
|
128
|
+
sections.push(context.failureContext);
|
|
129
|
+
sections.push('');
|
|
130
|
+
}
|
|
131
|
+
// Discover the target project's full test gate before the repair
|
|
132
|
+
// instructions so the agent commits only after running the real script.
|
|
133
|
+
const testDiscovery = (0, test_command_discovery_1.discoverTestCommand)(this.workingDir);
|
|
134
|
+
if (testDiscovery.warning && !(0, logger_1.isPrettyMode)()) {
|
|
135
|
+
logger.warn(`test command discovery: ${testDiscovery.warning}`);
|
|
136
|
+
}
|
|
137
|
+
sections.push((0, test_command_discovery_1.renderVerifyCommandSection)(testDiscovery));
|
|
138
|
+
sections.push('--- REPAIR INSTRUCTIONS ---');
|
|
139
|
+
// classify failure and inject targeted strategy (Upgrade 9)
|
|
140
|
+
const failureClass = this.classifyFailure(context.failedChecks, context.rootCause);
|
|
141
|
+
const strategy = this.getRepairStrategy(failureClass);
|
|
142
|
+
sections.push(`--- FAILURE CLASSIFICATION: ${failureClass} ---`);
|
|
143
|
+
sections.push(strategy);
|
|
144
|
+
sections.push('');
|
|
145
|
+
// inject focused evidence for specific failure types
|
|
146
|
+
if (failureClass === 'test-failure') {
|
|
147
|
+
const testChecks = context.failedChecks.filter(c => c.startsWith('[test]'));
|
|
148
|
+
if (testChecks.length > 0) {
|
|
149
|
+
sections.push('Failing test checks:');
|
|
150
|
+
testChecks.forEach(t => sections.push(` - ${t}`));
|
|
151
|
+
sections.push('');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else if (failureClass === 'build-failure') {
|
|
155
|
+
const buildChecks = context.failedChecks.filter(c => c.startsWith('[build]'));
|
|
156
|
+
if (buildChecks.length > 0) {
|
|
157
|
+
sections.push('Build errors:');
|
|
158
|
+
buildChecks.forEach(b => sections.push(` - ${b}`));
|
|
159
|
+
sections.push('');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Signal urgency when this is the final allowed attempt
|
|
163
|
+
if (context.retryCount >= this.maxRetries) {
|
|
164
|
+
sections.push('This is the final attempt. Prioritize getting a working result over completeness.');
|
|
165
|
+
sections.push('');
|
|
166
|
+
}
|
|
167
|
+
sections.push('4. Commit your fixes with a clear message starting with "repair:".');
|
|
168
|
+
sections.push('5. Do not claim work is done without evidence in the transcript.');
|
|
169
|
+
sections.push('');
|
|
170
|
+
return sections.join('\n');
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Estimate token cost from a transcript string.
|
|
174
|
+
* Uses a simple character-to-token ratio (approximately 4 chars per token
|
|
175
|
+
* for English text in GPT-family models).
|
|
176
|
+
*/
|
|
177
|
+
estimateTokenCost(text) {
|
|
178
|
+
if (!text)
|
|
179
|
+
return 0;
|
|
180
|
+
return Math.ceil(text.length / CHARS_PER_TOKEN);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Run the repair loop: up to maxRetries attempts.
|
|
184
|
+
* Each attempt spawns a Copilot CLI session with the failure context,
|
|
185
|
+
* then re-verifies. Stops on first successful verification.
|
|
186
|
+
*
|
|
187
|
+
* Returns a RepairResult summarizing all attempts.
|
|
188
|
+
*/
|
|
189
|
+
async attemptRepair(context, sessionOptions, verificationRequirements) {
|
|
190
|
+
const attemptDetails = [];
|
|
191
|
+
let totalTokens = 0;
|
|
192
|
+
const overallStart = Date.now();
|
|
193
|
+
for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
|
|
194
|
+
const attemptStart = Date.now();
|
|
195
|
+
// Update retry count in context for prompt generation
|
|
196
|
+
const repairContext = { ...context, retryCount: attempt };
|
|
197
|
+
const prompt = this.buildRepairPrompt(repairContext);
|
|
198
|
+
totalTokens += this.estimateTokenCost(prompt);
|
|
199
|
+
// Set up transcript path for this repair attempt
|
|
200
|
+
const repairTranscript = this.getRepairTranscriptPath(context, attempt);
|
|
201
|
+
const repairDir = path.dirname(repairTranscript);
|
|
202
|
+
if (!fs.existsSync(repairDir)) {
|
|
203
|
+
fs.mkdirSync(repairDir, { recursive: true });
|
|
204
|
+
}
|
|
205
|
+
const opts = {
|
|
206
|
+
...sessionOptions,
|
|
207
|
+
shareToFile: repairTranscript,
|
|
208
|
+
logPrefix: `[REPAIR:${context.agentName}:${context.stepNumber}:attempt-${attempt}]`
|
|
209
|
+
};
|
|
210
|
+
let sessionResult;
|
|
211
|
+
try {
|
|
212
|
+
// Create session executor for the working directory (may be a worktree)
|
|
213
|
+
const executor = new session_executor_1.default(this.workingDir);
|
|
214
|
+
sessionResult = await executor.executeSession(prompt, opts);
|
|
215
|
+
// Estimate tokens from output
|
|
216
|
+
if (sessionResult.output) {
|
|
217
|
+
totalTokens += this.estimateTokenCost(sessionResult.output);
|
|
218
|
+
}
|
|
219
|
+
if (!sessionResult.success) {
|
|
220
|
+
attemptDetails.push({
|
|
221
|
+
attempt,
|
|
222
|
+
durationMs: Date.now() - attemptStart,
|
|
223
|
+
sessionSuccess: false,
|
|
224
|
+
verificationPassed: false,
|
|
225
|
+
estimatedTokens: this.estimateTokenCost(prompt) + this.estimateTokenCost(sessionResult.output || ''),
|
|
226
|
+
error: sessionResult.error || 'Session exited with non-zero code'
|
|
227
|
+
});
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
// Re-verify
|
|
231
|
+
const transcriptToVerify = fs.existsSync(repairTranscript)
|
|
232
|
+
? repairTranscript
|
|
233
|
+
: context.transcriptPath;
|
|
234
|
+
const verifier = new verifier_engine_1.default(this.workingDir);
|
|
235
|
+
const verificationResult = await verifier.verifyStep(context.stepNumber, context.agentName, transcriptToVerify, verificationRequirements);
|
|
236
|
+
const verificationPassed = verificationResult.passed;
|
|
237
|
+
attemptDetails.push({
|
|
238
|
+
attempt,
|
|
239
|
+
durationMs: Date.now() - attemptStart,
|
|
240
|
+
sessionSuccess: true,
|
|
241
|
+
verificationPassed,
|
|
242
|
+
estimatedTokens: this.estimateTokenCost(prompt) + this.estimateTokenCost(sessionResult.output || '')
|
|
243
|
+
});
|
|
244
|
+
if (verificationPassed) {
|
|
245
|
+
return {
|
|
246
|
+
success: true,
|
|
247
|
+
attempts: attempt,
|
|
248
|
+
verificationPassed: true,
|
|
249
|
+
transcriptPath: repairTranscript,
|
|
250
|
+
estimatedTokenCost: totalTokens,
|
|
251
|
+
totalDurationMs: Date.now() - overallStart,
|
|
252
|
+
attemptDetails
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
// Update the context with the new transcript and report for next attempt
|
|
256
|
+
context = {
|
|
257
|
+
...context,
|
|
258
|
+
transcriptPath: repairTranscript,
|
|
259
|
+
failedChecks: this.extractFailedChecks(verificationResult)
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
const err = error;
|
|
264
|
+
attemptDetails.push({
|
|
265
|
+
attempt,
|
|
266
|
+
durationMs: Date.now() - attemptStart,
|
|
267
|
+
sessionSuccess: false,
|
|
268
|
+
verificationPassed: false,
|
|
269
|
+
estimatedTokens: this.estimateTokenCost(prompt),
|
|
270
|
+
error: err.message
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
// All retries exhausted
|
|
275
|
+
return {
|
|
276
|
+
success: false,
|
|
277
|
+
attempts: this.maxRetries,
|
|
278
|
+
verificationPassed: false,
|
|
279
|
+
transcriptPath: attemptDetails.length > 0
|
|
280
|
+
? this.getRepairTranscriptPath(context, attemptDetails.length)
|
|
281
|
+
: null,
|
|
282
|
+
estimatedTokenCost: totalTokens,
|
|
283
|
+
totalDurationMs: Date.now() - overallStart,
|
|
284
|
+
attemptDetails,
|
|
285
|
+
error: `Repair failed after ${this.maxRetries} attempt(s)`
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Classify failure type from tagged check strings and root cause.
|
|
290
|
+
* Uses frequency count on [type] prefixes from extractFailedChecks output.
|
|
291
|
+
*/
|
|
292
|
+
classifyFailure(failedChecks, rootCause) {
|
|
293
|
+
const lower = [...failedChecks.map(c => c.toLowerCase()), rootCause.toLowerCase()].join(' ');
|
|
294
|
+
// priority: timeout > dependency > missing artifact > majority tag
|
|
295
|
+
if (/timeout|timed out/.test(lower))
|
|
296
|
+
return 'timeout';
|
|
297
|
+
if (/\bpackage\b|\bdependency\b|\bmodule not found\b/.test(lower))
|
|
298
|
+
return 'dependency-error';
|
|
299
|
+
if (/not found|not created|missing|\[missing-files\]|\[no-changes\]/.test(lower))
|
|
300
|
+
return 'missing-artifact';
|
|
301
|
+
// count tagged prefixes
|
|
302
|
+
let buildCount = 0, testCount = 0;
|
|
303
|
+
for (const check of failedChecks) {
|
|
304
|
+
if (check.startsWith('[build]'))
|
|
305
|
+
buildCount++;
|
|
306
|
+
else if (check.startsWith('[test]'))
|
|
307
|
+
testCount++;
|
|
308
|
+
}
|
|
309
|
+
if (buildCount > 0 && buildCount >= testCount)
|
|
310
|
+
return 'build-failure';
|
|
311
|
+
if (testCount > 0)
|
|
312
|
+
return 'test-failure';
|
|
313
|
+
return 'general';
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Return targeted repair instructions for the given failure class.
|
|
317
|
+
* Replaces the generic one-size-fits-all instructions.
|
|
318
|
+
*/
|
|
319
|
+
getRepairStrategy(failureClass) {
|
|
320
|
+
switch (failureClass) {
|
|
321
|
+
case 'build-failure':
|
|
322
|
+
return 'Focus on the compiler/bundler errors below. Fix the specific file and line mentioned. Do not change unrelated code.';
|
|
323
|
+
case 'test-failure':
|
|
324
|
+
return 'The failing test names and assertions are listed below. Fix the implementation to make these tests pass. Do not modify the tests.';
|
|
325
|
+
case 'missing-artifact':
|
|
326
|
+
return 'The following expected files were not created. Create them now.';
|
|
327
|
+
case 'dependency-error':
|
|
328
|
+
return 'Install or fix the missing dependencies listed below.';
|
|
329
|
+
case 'timeout':
|
|
330
|
+
return 'The previous session timed out. Simplify the task: focus on the minimum viable deliverable, skip optional steps.';
|
|
331
|
+
case 'general':
|
|
332
|
+
return '1. Read the failed checks and root cause above carefully.\n2. Fix the specific issues identified. Do not redo unrelated work.\n3. Run tests if the task requires tests.';
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Extract human-readable failed check descriptions from a VerificationResult.
|
|
337
|
+
*/
|
|
338
|
+
extractFailedChecks(result) {
|
|
339
|
+
const checks = [];
|
|
340
|
+
for (const check of result.checks) {
|
|
341
|
+
if (!check.passed) {
|
|
342
|
+
const label = this.formatCheckLabel(check);
|
|
343
|
+
checks.push(label);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
if (result.unverifiedClaims.length > 0) {
|
|
347
|
+
checks.push(`Unverified claims: ${result.unverifiedClaims.join('; ')}`);
|
|
348
|
+
}
|
|
349
|
+
return checks;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Format a single failed check into a tagged string.
|
|
353
|
+
* Outcome-based check types get richer detail than transcript-parsed ones.
|
|
354
|
+
*/
|
|
355
|
+
formatCheckLabel(check) {
|
|
356
|
+
const reason = check.reason ? ` - ${check.reason}` : '';
|
|
357
|
+
switch (check.type) {
|
|
358
|
+
case 'build_exec':
|
|
359
|
+
return `[build] ${check.description}${reason}`;
|
|
360
|
+
case 'test_exec':
|
|
361
|
+
return `[test] ${check.description}${reason}`;
|
|
362
|
+
case 'file_existence':
|
|
363
|
+
return `[missing-files] ${check.description}${reason}`;
|
|
364
|
+
case 'git_diff':
|
|
365
|
+
return `[no-changes] ${check.description}${reason}`;
|
|
366
|
+
default:
|
|
367
|
+
return `[${check.type}] ${check.description}${reason}`;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Get the transcript path for a given repair attempt.
|
|
372
|
+
*/
|
|
373
|
+
getRepairTranscriptPath(context, attempt) {
|
|
374
|
+
const dir = path.dirname(context.transcriptPath);
|
|
375
|
+
return path.join(dir, `repair-attempt-${attempt}.md`);
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Get git diff for a branch. Returns empty string on failure.
|
|
379
|
+
*/
|
|
380
|
+
getGitDiff(_branchName) {
|
|
381
|
+
try {
|
|
382
|
+
const diff = (0, child_process_1.execSync)(`git diff HEAD~1 --stat 2>/dev/null || echo ""`, {
|
|
383
|
+
cwd: this.workingDir,
|
|
384
|
+
encoding: 'utf8',
|
|
385
|
+
timeout: 10000
|
|
386
|
+
});
|
|
387
|
+
return diff.trim();
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
// Git diff unavailable (no prior commit, detached HEAD); non-critical for repair
|
|
391
|
+
return '';
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
exports.RepairAgent = RepairAgent;
|
|
396
|
+
exports.default = RepairAgent;
|