mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-03 21:03:08 +00:00
feat: implement follow-up and commit features for waiting_approval status
- Added functionality to allow users to send follow-up prompts for features in the waiting_approval status, enabling continued work with additional instructions. - Implemented a commit feature that allows users to mark waiting_approval features as verified and commit changes directly. - Updated the UI to include buttons for follow-up and commit actions on Kanban cards and integrated dialogs for user interaction. - Enhanced the feature loader and executor to handle the new status and actions appropriately. This update improves the workflow for managing features that require manual review and enhances user experience in the auto mode.
This commit is contained in:
@@ -138,10 +138,16 @@ class AutoModeService {
|
||||
const result = await featureExecutor.implementFeature(feature, projectPath, sendToRenderer, execution);
|
||||
|
||||
// Update feature status based on result
|
||||
const newStatus = result.passes ? "verified" : "backlog";
|
||||
// For skipTests features, go to waiting_approval on success instead of verified
|
||||
let newStatus;
|
||||
if (result.passes) {
|
||||
newStatus = feature.skipTests ? "waiting_approval" : "verified";
|
||||
} else {
|
||||
newStatus = "backlog";
|
||||
}
|
||||
await featureLoader.updateFeatureStatus(feature.id, newStatus, projectPath);
|
||||
|
||||
// Delete context file if verified
|
||||
// Delete context file only if verified (not for waiting_approval)
|
||||
if (newStatus === "verified") {
|
||||
await contextManager.deleteContextFile(projectPath, feature.id);
|
||||
}
|
||||
@@ -321,10 +327,16 @@ class AutoModeService {
|
||||
}
|
||||
|
||||
// Update feature status based on final result
|
||||
const newStatus = finalResult.passes ? "verified" : "in_progress";
|
||||
// For skipTests features, go to waiting_approval on success instead of verified
|
||||
let newStatus;
|
||||
if (finalResult.passes) {
|
||||
newStatus = feature.skipTests ? "waiting_approval" : "verified";
|
||||
} else {
|
||||
newStatus = "in_progress";
|
||||
}
|
||||
await featureLoader.updateFeatureStatus(featureId, newStatus, projectPath);
|
||||
|
||||
// Delete context file if verified
|
||||
// Delete context file only if verified (not for waiting_approval)
|
||||
if (newStatus === "verified") {
|
||||
await contextManager.deleteContextFile(projectPath, featureId);
|
||||
}
|
||||
@@ -400,10 +412,16 @@ class AutoModeService {
|
||||
const result = await featureExecutor.implementFeature(nextFeature, projectPath, sendToRenderer, execution);
|
||||
|
||||
// Update feature status based on result
|
||||
const newStatus = result.passes ? "verified" : "backlog";
|
||||
// For skipTests features, go to waiting_approval on success instead of verified
|
||||
let newStatus;
|
||||
if (result.passes) {
|
||||
newStatus = nextFeature.skipTests ? "waiting_approval" : "verified";
|
||||
} else {
|
||||
newStatus = "backlog";
|
||||
}
|
||||
await featureLoader.updateFeatureStatus(nextFeature.id, newStatus, projectPath);
|
||||
|
||||
// Delete context file if verified
|
||||
// Delete context file only if verified (not for waiting_approval)
|
||||
if (newStatus === "verified") {
|
||||
await contextManager.deleteContextFile(projectPath, nextFeature.id);
|
||||
}
|
||||
@@ -500,6 +518,179 @@ class AutoModeService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a specific feature by ID
|
||||
*/
|
||||
async stopFeature({ featureId }) {
|
||||
if (!this.runningFeatures.has(featureId)) {
|
||||
return { success: false, error: `Feature ${featureId} is not running` };
|
||||
}
|
||||
|
||||
console.log(`[AutoMode] Stopping feature: ${featureId}`);
|
||||
|
||||
const execution = this.runningFeatures.get(featureId);
|
||||
if (execution && execution.abortController) {
|
||||
execution.abortController.abort();
|
||||
}
|
||||
|
||||
// Clean up
|
||||
this.runningFeatures.delete(featureId);
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Follow-up on a feature with additional prompt
|
||||
* This continues work on a feature that's in waiting_approval status
|
||||
*/
|
||||
async followUpFeature({ projectPath, featureId, prompt, imagePaths, sendToRenderer }) {
|
||||
// Check if this feature is already running
|
||||
if (this.runningFeatures.has(featureId)) {
|
||||
throw new Error(`Feature ${featureId} is already running`);
|
||||
}
|
||||
|
||||
console.log(`[AutoMode] Follow-up on feature: ${featureId} with prompt: ${prompt}`);
|
||||
|
||||
// Register this feature as running
|
||||
const execution = this.createExecutionContext(featureId);
|
||||
execution.projectPath = projectPath;
|
||||
execution.sendToRenderer = sendToRenderer;
|
||||
this.runningFeatures.set(featureId, execution);
|
||||
|
||||
try {
|
||||
// Load features
|
||||
const features = await featureLoader.loadFeatures(projectPath);
|
||||
const feature = features.find((f) => f.id === featureId);
|
||||
|
||||
if (!feature) {
|
||||
throw new Error(`Feature ${featureId} not found`);
|
||||
}
|
||||
|
||||
console.log(`[AutoMode] Following up on feature: ${feature.description}`);
|
||||
|
||||
// Update status to in_progress
|
||||
await featureLoader.updateFeatureStatus(featureId, "in_progress", projectPath);
|
||||
|
||||
sendToRenderer({
|
||||
type: "auto_mode_feature_start",
|
||||
featureId: feature.id,
|
||||
feature: feature,
|
||||
});
|
||||
|
||||
// Read existing context and append follow-up prompt
|
||||
const previousContext = await contextManager.readContextFile(projectPath, featureId);
|
||||
|
||||
// Append follow-up prompt to context
|
||||
const followUpContext = `${previousContext}\n\n## Follow-up Instructions\n\n${prompt}`;
|
||||
await contextManager.writeToContextFile(projectPath, featureId, `\n\n## Follow-up Instructions\n\n${prompt}`);
|
||||
|
||||
// Resume implementation with follow-up context and optional images
|
||||
const result = await featureExecutor.resumeFeatureWithContext(
|
||||
{ ...feature, followUpPrompt: prompt, followUpImages: imagePaths },
|
||||
projectPath,
|
||||
sendToRenderer,
|
||||
followUpContext,
|
||||
execution
|
||||
);
|
||||
|
||||
// For skipTests features, go to waiting_approval on success instead of verified
|
||||
const newStatus = result.passes
|
||||
? (feature.skipTests ? "waiting_approval" : "verified")
|
||||
: "in_progress";
|
||||
|
||||
await featureLoader.updateFeatureStatus(feature.id, newStatus, projectPath);
|
||||
|
||||
// Delete context file if verified (only for non-skipTests)
|
||||
if (newStatus === "verified") {
|
||||
await contextManager.deleteContextFile(projectPath, feature.id);
|
||||
}
|
||||
|
||||
sendToRenderer({
|
||||
type: "auto_mode_feature_complete",
|
||||
featureId: feature.id,
|
||||
passes: result.passes,
|
||||
message: result.message,
|
||||
});
|
||||
|
||||
return { success: true, passes: result.passes };
|
||||
} catch (error) {
|
||||
console.error("[AutoMode] Error in follow-up:", error);
|
||||
sendToRenderer({
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
featureId: featureId,
|
||||
});
|
||||
throw error;
|
||||
} finally {
|
||||
this.runningFeatures.delete(featureId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit changes for a feature without doing additional work
|
||||
* This marks the feature as verified and commits the changes
|
||||
*/
|
||||
async commitFeature({ projectPath, featureId, sendToRenderer }) {
|
||||
console.log(`[AutoMode] Committing feature: ${featureId}`);
|
||||
|
||||
// Register briefly as running for the commit operation
|
||||
const execution = this.createExecutionContext(featureId);
|
||||
execution.projectPath = projectPath;
|
||||
execution.sendToRenderer = sendToRenderer;
|
||||
this.runningFeatures.set(featureId, execution);
|
||||
|
||||
try {
|
||||
// Load feature to get description for commit message
|
||||
const features = await featureLoader.loadFeatures(projectPath);
|
||||
const feature = features.find((f) => f.id === featureId);
|
||||
|
||||
if (!feature) {
|
||||
throw new Error(`Feature ${featureId} not found`);
|
||||
}
|
||||
|
||||
sendToRenderer({
|
||||
type: "auto_mode_feature_start",
|
||||
featureId: feature.id,
|
||||
feature: { ...feature, description: "Committing changes..." },
|
||||
});
|
||||
|
||||
sendToRenderer({
|
||||
type: "auto_mode_phase",
|
||||
featureId,
|
||||
phase: "action",
|
||||
message: "Committing changes to git...",
|
||||
});
|
||||
|
||||
// Run git commit via the agent
|
||||
const commitResult = await featureExecutor.commitChangesOnly(feature, projectPath, sendToRenderer, execution);
|
||||
|
||||
// Update status to verified
|
||||
await featureLoader.updateFeatureStatus(featureId, "verified", projectPath);
|
||||
|
||||
// Delete context file
|
||||
await contextManager.deleteContextFile(projectPath, featureId);
|
||||
|
||||
sendToRenderer({
|
||||
type: "auto_mode_feature_complete",
|
||||
featureId: feature.id,
|
||||
passes: true,
|
||||
message: "Changes committed successfully",
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error("[AutoMode] Error committing feature:", error);
|
||||
sendToRenderer({
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
featureId: featureId,
|
||||
});
|
||||
throw error;
|
||||
} finally {
|
||||
this.runningFeatures.delete(featureId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleep helper
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user