mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-31 06:42:03 +00:00
- Refactored AutoModeService to delegate tasks to specialized services: featureLoader, featureExecutor, featureVerifier, contextManager, and projectAnalyzer.
- Implemented feature verification logic in a new FeatureVerifier service, which runs tests and updates feature status.
- Added ProjectAnalyzer service to scan project structure and update app_spec.txt.
- Removed obsolete methods related to feature loading and context management from AutoModeService.
- Updated feature status handling to ensure context files are deleted when features are verified.
This refactor enhances modularity and maintainability of the codebase, allowing for better separation of concerns in feature management.
🤖 Generated with Claude Code
149 lines
4.8 KiB
JavaScript
149 lines
4.8 KiB
JavaScript
const { query, AbortError } = require("@anthropic-ai/claude-agent-sdk");
|
|
const promptBuilder = require("./prompt-builder");
|
|
const contextManager = require("./context-manager");
|
|
const featureLoader = require("./feature-loader");
|
|
const mcpServerFactory = require("./mcp-server-factory");
|
|
|
|
/**
|
|
* Feature Verifier - Handles feature verification by running tests
|
|
*/
|
|
class FeatureVerifier {
|
|
/**
|
|
* Verify feature tests (runs tests and checks if they pass)
|
|
*/
|
|
async verifyFeatureTests(feature, projectPath, sendToRenderer, execution) {
|
|
console.log(`[FeatureVerifier] Verifying tests for: ${feature.description}`);
|
|
|
|
try {
|
|
const verifyMsg = `\n✅ Verifying tests for: ${feature.description}\n`;
|
|
await contextManager.writeToContextFile(projectPath, feature.id, verifyMsg);
|
|
|
|
sendToRenderer({
|
|
type: "auto_mode_phase",
|
|
featureId: feature.id,
|
|
phase: "verification",
|
|
message: `Verifying tests for: ${feature.description}`,
|
|
});
|
|
|
|
const abortController = new AbortController();
|
|
execution.abortController = abortController;
|
|
|
|
// Create custom MCP server with UpdateFeatureStatus tool
|
|
const featureToolsServer = mcpServerFactory.createFeatureToolsServer(
|
|
featureLoader.updateFeatureStatus.bind(featureLoader),
|
|
projectPath
|
|
);
|
|
|
|
const options = {
|
|
model: "claude-opus-4-5-20251101",
|
|
systemPrompt: promptBuilder.getVerificationPrompt(),
|
|
maxTurns: 1000,
|
|
cwd: projectPath,
|
|
mcpServers: {
|
|
"automaker-tools": featureToolsServer
|
|
},
|
|
allowedTools: ["Read", "Write", "Edit", "Glob", "Grep", "Bash", "mcp__automaker-tools__UpdateFeatureStatus"],
|
|
permissionMode: "acceptEdits",
|
|
sandbox: {
|
|
enabled: true,
|
|
autoAllowBashIfSandboxed: true,
|
|
},
|
|
abortController: abortController,
|
|
};
|
|
|
|
const prompt = promptBuilder.buildVerificationPrompt(feature);
|
|
|
|
const runningTestsMsg =
|
|
"Running Playwright tests to verify feature implementation...\n";
|
|
await contextManager.writeToContextFile(projectPath, feature.id, runningTestsMsg);
|
|
|
|
sendToRenderer({
|
|
type: "auto_mode_progress",
|
|
featureId: feature.id,
|
|
content: runningTestsMsg,
|
|
});
|
|
|
|
const currentQuery = query({ prompt, options });
|
|
execution.query = currentQuery;
|
|
|
|
let responseText = "";
|
|
for await (const msg of currentQuery) {
|
|
// Check if this specific feature was aborted
|
|
if (!execution.isActive()) break;
|
|
|
|
if (msg.type === "assistant" && msg.message?.content) {
|
|
for (const block of msg.message.content) {
|
|
if (block.type === "text") {
|
|
responseText += block.text;
|
|
|
|
await contextManager.writeToContextFile(projectPath, feature.id, block.text);
|
|
|
|
sendToRenderer({
|
|
type: "auto_mode_progress",
|
|
featureId: feature.id,
|
|
content: block.text,
|
|
});
|
|
} else if (block.type === "tool_use") {
|
|
const toolMsg = `\n🔧 Tool: ${block.name}\n`;
|
|
await contextManager.writeToContextFile(projectPath, feature.id, toolMsg);
|
|
|
|
sendToRenderer({
|
|
type: "auto_mode_tool",
|
|
featureId: feature.id,
|
|
tool: block.name,
|
|
input: block.input,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
execution.query = null;
|
|
execution.abortController = null;
|
|
|
|
// Re-load features to check if it was marked as verified
|
|
const updatedFeatures = await featureLoader.loadFeatures(projectPath);
|
|
const updatedFeature = updatedFeatures.find((f) => f.id === feature.id);
|
|
const passes = updatedFeature?.status === "verified";
|
|
|
|
const finalMsg = passes
|
|
? "✓ Verification successful: All tests passed\n"
|
|
: "✗ Tests failed or not all passing - feature remains in progress\n";
|
|
|
|
await contextManager.writeToContextFile(projectPath, feature.id, finalMsg);
|
|
|
|
sendToRenderer({
|
|
type: "auto_mode_progress",
|
|
featureId: feature.id,
|
|
content: finalMsg,
|
|
});
|
|
|
|
return {
|
|
passes,
|
|
message: responseText.substring(0, 500),
|
|
};
|
|
} catch (error) {
|
|
if (error instanceof AbortError || error?.name === "AbortError") {
|
|
console.log("[FeatureVerifier] Verification aborted");
|
|
if (execution) {
|
|
execution.abortController = null;
|
|
execution.query = null;
|
|
}
|
|
return {
|
|
passes: false,
|
|
message: "Verification aborted",
|
|
};
|
|
}
|
|
|
|
console.error("[FeatureVerifier] Error verifying feature:", error);
|
|
if (execution) {
|
|
execution.abortController = null;
|
|
execution.query = null;
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = new FeatureVerifier();
|