mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-02 20:43:36 +00:00
Merge main into feat/extend-models-support
Resolved conflicts: - feature_list.json: Merged all features from both branches - feature-loader.js: Included both model/thinkingLevel and error fields - board-view.tsx: Merged model/thinkingLevel and error fields, kept currentProject check - settings-view.tsx: Merged CLI status checks with navigation/scroll code - app-store.ts: Included both model/thinkingLevel and error fields in Feature interface Fixed linting errors in settings-view.tsx
This commit is contained in:
@@ -181,6 +181,31 @@ class AutoModeService {
|
||||
return { success: true, passes: result.passes };
|
||||
} catch (error) {
|
||||
console.error("[AutoMode] Error running feature:", error);
|
||||
|
||||
// Write error to context file
|
||||
try {
|
||||
await contextManager.writeToContextFile(
|
||||
projectPath,
|
||||
featureId,
|
||||
`\n\n❌ ERROR: ${error.message}\n\n${error.stack || ''}\n`
|
||||
);
|
||||
} catch (contextError) {
|
||||
console.error("[AutoMode] Failed to write error to context:", contextError);
|
||||
}
|
||||
|
||||
// Update feature status to waiting_approval so user can review the error
|
||||
try {
|
||||
await featureLoader.updateFeatureStatus(
|
||||
featureId,
|
||||
"waiting_approval",
|
||||
projectPath,
|
||||
null, // no summary
|
||||
error.message // pass error message
|
||||
);
|
||||
} catch (statusError) {
|
||||
console.error("[AutoMode] Failed to update feature status after error:", statusError);
|
||||
}
|
||||
|
||||
sendToRenderer({
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
@@ -260,6 +285,31 @@ class AutoModeService {
|
||||
return { success: true, passes: result.passes };
|
||||
} catch (error) {
|
||||
console.error("[AutoMode] Error verifying feature:", error);
|
||||
|
||||
// Write error to context file
|
||||
try {
|
||||
await contextManager.writeToContextFile(
|
||||
projectPath,
|
||||
featureId,
|
||||
`\n\n❌ ERROR: ${error.message}\n\n${error.stack || ''}\n`
|
||||
);
|
||||
} catch (contextError) {
|
||||
console.error("[AutoMode] Failed to write error to context:", contextError);
|
||||
}
|
||||
|
||||
// Update feature status to waiting_approval so user can review the error
|
||||
try {
|
||||
await featureLoader.updateFeatureStatus(
|
||||
featureId,
|
||||
"waiting_approval",
|
||||
projectPath,
|
||||
null, // no summary
|
||||
error.message // pass error message
|
||||
);
|
||||
} catch (statusError) {
|
||||
console.error("[AutoMode] Failed to update feature status after error:", statusError);
|
||||
}
|
||||
|
||||
sendToRenderer({
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
@@ -400,6 +450,31 @@ class AutoModeService {
|
||||
return { success: true, passes: finalResult.passes };
|
||||
} catch (error) {
|
||||
console.error("[AutoMode] Error resuming feature:", error);
|
||||
|
||||
// Write error to context file
|
||||
try {
|
||||
await contextManager.writeToContextFile(
|
||||
projectPath,
|
||||
featureId,
|
||||
`\n\n❌ ERROR: ${error.message}\n\n${error.stack || ''}\n`
|
||||
);
|
||||
} catch (contextError) {
|
||||
console.error("[AutoMode] Failed to write error to context:", contextError);
|
||||
}
|
||||
|
||||
// Update feature status to waiting_approval so user can review the error
|
||||
try {
|
||||
await featureLoader.updateFeatureStatus(
|
||||
featureId,
|
||||
"waiting_approval",
|
||||
projectPath,
|
||||
null, // no summary
|
||||
error.message // pass error message
|
||||
);
|
||||
} catch (statusError) {
|
||||
console.error("[AutoMode] Failed to update feature status after error:", statusError);
|
||||
}
|
||||
|
||||
sendToRenderer({
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
@@ -544,6 +619,31 @@ class AutoModeService {
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`[AutoMode] Error running feature ${featureId}:`, error);
|
||||
|
||||
// Write error to context file
|
||||
try {
|
||||
await contextManager.writeToContextFile(
|
||||
projectPath,
|
||||
featureId,
|
||||
`\n\n❌ ERROR: ${error.message}\n\n${error.stack || ''}\n`
|
||||
);
|
||||
} catch (contextError) {
|
||||
console.error("[AutoMode] Failed to write error to context:", contextError);
|
||||
}
|
||||
|
||||
// Update feature status to waiting_approval so user can review the error
|
||||
try {
|
||||
await featureLoader.updateFeatureStatus(
|
||||
featureId,
|
||||
"waiting_approval",
|
||||
projectPath,
|
||||
null, // no summary
|
||||
error.message // pass error message
|
||||
);
|
||||
} catch (statusError) {
|
||||
console.error("[AutoMode] Failed to update feature status after error:", statusError);
|
||||
}
|
||||
|
||||
sendToRenderer({
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
@@ -761,6 +861,31 @@ class AutoModeService {
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("[AutoMode] Error in follow-up:", error);
|
||||
|
||||
// Write error to context file
|
||||
try {
|
||||
await contextManager.writeToContextFile(
|
||||
projectPath,
|
||||
featureId,
|
||||
`\n\n❌ ERROR: ${error.message}\n\n${error.stack || ''}\n`
|
||||
);
|
||||
} catch (contextError) {
|
||||
console.error("[AutoMode] Failed to write error to context:", contextError);
|
||||
}
|
||||
|
||||
// Update feature status to waiting_approval so user can review the error
|
||||
try {
|
||||
await featureLoader.updateFeatureStatus(
|
||||
featureId,
|
||||
"waiting_approval",
|
||||
projectPath,
|
||||
null, // no summary
|
||||
error.message // pass error message
|
||||
);
|
||||
} catch (statusError) {
|
||||
console.error("[AutoMode] Failed to update feature status after error:", statusError);
|
||||
}
|
||||
|
||||
sendToRenderer({
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
|
||||
@@ -3,7 +3,7 @@ const path = require("path");
|
||||
// Load environment variables from .env file
|
||||
require("dotenv").config({ path: path.join(__dirname, "../.env") });
|
||||
|
||||
const { app, BrowserWindow, ipcMain, dialog } = require("electron");
|
||||
const { app, BrowserWindow, ipcMain, dialog, shell } = require("electron");
|
||||
const fs = require("fs/promises");
|
||||
const agentService = require("./agent-service");
|
||||
const autoModeService = require("./auto-mode-service");
|
||||
@@ -12,11 +12,11 @@ let mainWindow = null;
|
||||
|
||||
// Get icon path - works in both dev and production
|
||||
function getIconPath() {
|
||||
// In dev: __dirname is electron/, so ../public/icon_gold.png
|
||||
// In dev: __dirname is electron/, so ../public/logo.png
|
||||
// In production: public folder is included in the app bundle
|
||||
return app.isPackaged
|
||||
? path.join(process.resourcesPath, "app", "public", "icon_gold.png")
|
||||
: path.join(__dirname, "../public/icon_gold.png");
|
||||
? path.join(process.resourcesPath, "app", "public", "logo.png")
|
||||
: path.join(__dirname, "../public/logo.png");
|
||||
}
|
||||
|
||||
function createWindow() {
|
||||
@@ -169,6 +169,15 @@ ipcMain.handle("fs:deleteFile", async (_, filePath) => {
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle("fs:trashItem", async (_, targetPath) => {
|
||||
try {
|
||||
await shell.trashItem(targetPath);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
});
|
||||
|
||||
// App data path
|
||||
ipcMain.handle("app:getPath", (_, name) => {
|
||||
return app.getPath(name);
|
||||
@@ -193,7 +202,9 @@ ipcMain.handle(
|
||||
await fs.mkdir(imagesDir, { recursive: true });
|
||||
|
||||
// Generate unique filename with unique ID
|
||||
const uniqueId = `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
|
||||
const uniqueId = `${Date.now()}-${Math.random()
|
||||
.toString(36)
|
||||
.substring(2, 11)}`;
|
||||
const safeName = filename.replace(/[^a-zA-Z0-9.-]/g, "_");
|
||||
const imageFilePath = path.join(imagesDir, `${uniqueId}_${safeName}`);
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ contextBridge.exposeInMainWorld("electronAPI", {
|
||||
exists: (filePath) => ipcRenderer.invoke("fs:exists", filePath),
|
||||
stat: (filePath) => ipcRenderer.invoke("fs:stat", filePath),
|
||||
deleteFile: (filePath) => ipcRenderer.invoke("fs:deleteFile", filePath),
|
||||
trashItem: (filePath) => ipcRenderer.invoke("fs:trashItem", filePath),
|
||||
|
||||
// App APIs
|
||||
getPath: (name) => ipcRenderer.invoke("app:getPath", name),
|
||||
|
||||
@@ -699,7 +699,8 @@ class FeatureExecutor {
|
||||
const path = require("path");
|
||||
for (const imagePathObj of imagePaths) {
|
||||
try {
|
||||
const imagePath = imagePathObj.path;
|
||||
// Handle both string paths and FeatureImagePath objects
|
||||
const imagePath = typeof imagePathObj === 'string' ? imagePathObj : imagePathObj.path;
|
||||
const imageBuffer = fs.readFileSync(imagePath);
|
||||
const base64Data = imageBuffer.toString("base64");
|
||||
const ext = path.extname(imagePath).toLowerCase();
|
||||
@@ -710,7 +711,9 @@ class FeatureExecutor {
|
||||
".gif": "image/gif",
|
||||
".webp": "image/webp",
|
||||
};
|
||||
const mediaType = mimeTypeMap[ext] || imagePathObj.mimeType || "image/png";
|
||||
const mediaType = typeof imagePathObj === 'string'
|
||||
? (mimeTypeMap[ext] || "image/png")
|
||||
: (mimeTypeMap[ext] || imagePathObj.mimeType || "image/png");
|
||||
|
||||
contentBlocks.push({
|
||||
type: "image",
|
||||
@@ -723,8 +726,9 @@ class FeatureExecutor {
|
||||
|
||||
console.log(`[FeatureExecutor] Added image to resume prompt: ${imagePath}`);
|
||||
} catch (error) {
|
||||
const errorPath = typeof imagePathObj === 'string' ? imagePathObj : imagePathObj.path;
|
||||
console.error(
|
||||
`[FeatureExecutor] Failed to load image ${imagePathObj.path}:`,
|
||||
`[FeatureExecutor] Failed to load image ${errorPath}:`,
|
||||
error
|
||||
);
|
||||
}
|
||||
|
||||
@@ -36,8 +36,9 @@ class FeatureLoader {
|
||||
* @param {string} status - The new status
|
||||
* @param {string} projectPath - Path to the project
|
||||
* @param {string} [summary] - Optional summary of what was done
|
||||
* @param {string} [error] - Optional error message if feature errored
|
||||
*/
|
||||
async updateFeatureStatus(featureId, status, projectPath, summary) {
|
||||
async updateFeatureStatus(featureId, status, projectPath, summary, error) {
|
||||
const featuresPath = path.join(
|
||||
projectPath,
|
||||
".automaker",
|
||||
@@ -98,6 +99,14 @@ class FeatureLoader {
|
||||
feature.summary = summary;
|
||||
}
|
||||
|
||||
// Update the error field (set or clear)
|
||||
if (error) {
|
||||
feature.error = error;
|
||||
} else {
|
||||
// Clear any previous error when status changes without error
|
||||
delete feature.error;
|
||||
}
|
||||
|
||||
// Save back to file
|
||||
const toSave = features.map((f) => {
|
||||
const featureData = {
|
||||
@@ -129,6 +138,9 @@ class FeatureLoader {
|
||||
if (f.thinkingLevel !== undefined) {
|
||||
featureData.thinkingLevel = f.thinkingLevel;
|
||||
}
|
||||
if (f.error !== undefined) {
|
||||
featureData.error = f.error;
|
||||
}
|
||||
return featureData;
|
||||
});
|
||||
|
||||
|
||||
@@ -10,9 +10,18 @@ class PromptBuilder {
|
||||
? `\n**⚠️ IMPORTANT - Manual Testing Mode:**\nThis feature has skipTests=true, which means:\n- DO NOT commit changes automatically\n- DO NOT mark as verified - it will automatically go to "waiting_approval" status\n- The user will manually review and commit the changes\n- Just implement the feature and mark it as verified (it will be converted to waiting_approval)\n`
|
||||
: "";
|
||||
|
||||
const imagesNote = feature.imagePaths && feature.imagePaths.length > 0
|
||||
? `\n**📎 Context Images Attached:**\nThe user has attached ${feature.imagePaths.length} image(s) for context. These images will be provided to you visually to help understand the requirements. Review them carefully before implementing.\n`
|
||||
: "";
|
||||
let imagesNote = "";
|
||||
if (feature.imagePaths && feature.imagePaths.length > 0) {
|
||||
const imagesList = feature.imagePaths.map((img, idx) =>
|
||||
` ${idx + 1}. ${img.filename} (${img.mimeType})\n Path: ${img.path}`
|
||||
).join("\n");
|
||||
|
||||
imagesNote = `\n**📎 Context Images Attached:**\nThe user has attached ${feature.imagePaths.length} image(s) for context. These images are provided both visually (in the initial message) and as files you can read:
|
||||
|
||||
${imagesList}
|
||||
|
||||
You can use the Read tool to view these images at any time during implementation. Review them carefully before implementing.\n`;
|
||||
}
|
||||
|
||||
return `You are working on a feature implementation task.
|
||||
|
||||
@@ -121,9 +130,18 @@ Begin by reading the project structure and then implementing the feature.`;
|
||||
? `\n**⚠️ IMPORTANT - Manual Testing Mode:**\nThis feature has skipTests=true, which means:\n- DO NOT commit changes automatically\n- DO NOT mark as verified - it will automatically go to "waiting_approval" status\n- The user will manually review and commit the changes\n- Just implement the feature and mark it as verified (it will be converted to waiting_approval)\n`
|
||||
: "";
|
||||
|
||||
const imagesNote = feature.imagePaths && feature.imagePaths.length > 0
|
||||
? `\n**📎 Context Images Attached:**\nThe user has attached ${feature.imagePaths.length} image(s) for context. These images will be provided to you visually to help understand the requirements. Review them carefully before implementing.\n`
|
||||
: "";
|
||||
let imagesNote = "";
|
||||
if (feature.imagePaths && feature.imagePaths.length > 0) {
|
||||
const imagesList = feature.imagePaths.map((img, idx) =>
|
||||
` ${idx + 1}. ${img.filename} (${img.mimeType})\n Path: ${img.path}`
|
||||
).join("\n");
|
||||
|
||||
imagesNote = `\n**📎 Context Images Attached:**\nThe user has attached ${feature.imagePaths.length} image(s) for context. These images are provided both visually (in the initial message) and as files you can read:
|
||||
|
||||
${imagesList}
|
||||
|
||||
You can use the Read tool to view these images at any time during implementation. Review them carefully before implementing.\n`;
|
||||
}
|
||||
|
||||
return `You are implementing and verifying a feature until it is complete and working correctly.
|
||||
|
||||
@@ -224,9 +242,24 @@ Begin by reading the project structure and understanding what needs to be implem
|
||||
? `\n**⚠️ IMPORTANT - Manual Testing Mode:**\nThis feature has skipTests=true, which means:\n- DO NOT commit changes automatically\n- DO NOT mark as verified - it will automatically go to "waiting_approval" status\n- The user will manually review and commit the changes\n- Just implement the feature and mark it as verified (it will be converted to waiting_approval)\n`
|
||||
: "";
|
||||
|
||||
const imagesNote = feature.imagePaths && feature.imagePaths.length > 0
|
||||
? `\n**📎 Context Images Attached:**\nThe user has attached ${feature.imagePaths.length} image(s) for context. These images will be provided to you visually to help understand the requirements. Review them carefully.\n`
|
||||
: "";
|
||||
// For resume, check both followUpImages and imagePaths
|
||||
const imagePaths = feature.followUpImages || feature.imagePaths;
|
||||
let imagesNote = "";
|
||||
if (imagePaths && imagePaths.length > 0) {
|
||||
const imagesList = imagePaths.map((img, idx) => {
|
||||
// Handle both FeatureImagePath objects and simple path strings
|
||||
const path = typeof img === 'string' ? img : img.path;
|
||||
const filename = typeof img === 'string' ? path.split('/').pop() : img.filename;
|
||||
const mimeType = typeof img === 'string' ? 'image/*' : img.mimeType;
|
||||
return ` ${idx + 1}. ${filename} (${mimeType})\n Path: ${path}`;
|
||||
}).join("\n");
|
||||
|
||||
imagesNote = `\n**📎 Context Images Attached:**\nThe user has attached ${imagePaths.length} image(s) for context. These images are provided both visually (in the initial message) and as files you can read:
|
||||
|
||||
${imagesList}
|
||||
|
||||
You can use the Read tool to view these images at any time. Review them carefully.\n`;
|
||||
}
|
||||
|
||||
return `You are resuming work on a feature implementation that was previously started.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user