feat: add debug option for Electron development

- Introduced a new command `dev:electron:debug` in both package.json files to launch Electron with DevTools open.
- Updated main.js to conditionally open DevTools based on the `OPEN_DEVTOOLS` environment variable.
- Refactored some IPC handler code for better readability and consistency.
This commit is contained in:
Cody Seibert
2025-12-11 21:21:59 -05:00
parent 2cc9e47747
commit ada2703d3e
3 changed files with 70 additions and 50 deletions

View File

@@ -42,7 +42,10 @@ function createWindow() {
const isDev = !app.isPackaged;
if (isDev) {
mainWindow.loadURL("http://localhost:3007");
// mainWindow.webContents.openDevTools();
// Open DevTools if OPEN_DEVTOOLS environment variable is set
if (process.env.OPEN_DEVTOOLS === "true") {
mainWindow.webContents.openDevTools();
}
} else {
mainWindow.loadFile(path.join(__dirname, "../.next/server/app/index.html"));
}
@@ -894,12 +897,9 @@ ipcMain.handle(
async (_, { featureId, status, projectPath, summary }) => {
try {
const featureLoader = require("./services/feature-loader");
await featureLoader.updateFeatureStatus(
featureId,
status,
projectPath,
{ summary }
);
await featureLoader.updateFeatureStatus(featureId, status, projectPath, {
summary,
});
// Notify renderer if window is available
if (mainWindow && !mainWindow.isDestroyed()) {
@@ -931,51 +931,59 @@ let suggestionsExecution = null;
* @param {string} projectPath - The path to the project
* @param {string} suggestionType - Type of suggestions: "features", "refactoring", "security", "performance"
*/
ipcMain.handle("suggestions:generate", async (_, { projectPath, suggestionType = "features" }) => {
try {
// Check if already running
if (suggestionsExecution && suggestionsExecution.isActive()) {
return {
success: false,
error: "Suggestions generation is already running",
};
}
// Create execution context
suggestionsExecution = {
abortController: null,
query: null,
isActive: () => suggestionsExecution !== null,
};
const sendToRenderer = (data) => {
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send("suggestions:event", data);
ipcMain.handle(
"suggestions:generate",
async (_, { projectPath, suggestionType = "features" }) => {
try {
// Check if already running
if (suggestionsExecution && suggestionsExecution.isActive()) {
return {
success: false,
error: "Suggestions generation is already running",
};
}
};
// Start generating suggestions (runs in background)
featureSuggestionsService
.generateSuggestions(projectPath, sendToRenderer, suggestionsExecution, suggestionType)
.catch((error) => {
console.error("[IPC] suggestions:generate background error:", error);
sendToRenderer({
type: "suggestions_error",
error: error.message,
// Create execution context
suggestionsExecution = {
abortController: null,
query: null,
isActive: () => suggestionsExecution !== null,
};
const sendToRenderer = (data) => {
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send("suggestions:event", data);
}
};
// Start generating suggestions (runs in background)
featureSuggestionsService
.generateSuggestions(
projectPath,
sendToRenderer,
suggestionsExecution,
suggestionType
)
.catch((error) => {
console.error("[IPC] suggestions:generate background error:", error);
sendToRenderer({
type: "suggestions_error",
error: error.message,
});
})
.finally(() => {
suggestionsExecution = null;
});
})
.finally(() => {
suggestionsExecution = null;
});
// Return immediately
return { success: true };
} catch (error) {
console.error("[IPC] suggestions:generate error:", error);
suggestionsExecution = null;
return { success: false, error: error.message };
// Return immediately
return { success: true };
} catch (error) {
console.error("[IPC] suggestions:generate error:", error);
suggestionsExecution = null;
return { success: false, error: error.message };
}
}
});
);
/**
* Stop the current suggestions generation
@@ -1248,7 +1256,10 @@ ipcMain.handle(
// Check if already running
if (specRegenerationExecution && specRegenerationExecution.isActive()) {
return { success: false, error: "Spec regeneration is already running" };
return {
success: false,
error: "Spec regeneration is already running",
};
}
// Create execution context
@@ -1266,7 +1277,11 @@ ipcMain.handle(
// Start generating features (runs in background)
specRegenerationService
.generateFeaturesOnly(projectPath, sendToRenderer, specRegenerationExecution)
.generateFeaturesOnly(
projectPath,
sendToRenderer,
specRegenerationExecution
)
.catch((error) => {
console.error(
"[IPC] spec-regeneration:generate-features background error:",
@@ -1788,7 +1803,10 @@ ipcMain.handle(
}
const featureLoader = require("./services/feature-loader");
const content = await featureLoader.getAgentOutput(projectPath, featureId);
const content = await featureLoader.getAgentOutput(
projectPath,
featureId
);
return { success: true, content };
} catch (error) {
console.error("[IPC] features:getAgentOutput error:", error);

View File

@@ -18,6 +18,7 @@
"dev": "next dev -p 3007",
"dev:web": "next dev -p 3007",
"dev:electron": "concurrently \"next dev -p 3007\" \"wait-on http://localhost:3007 && electron .\"",
"dev:electron:debug": "concurrently \"next dev -p 3007\" \"wait-on http://localhost:3007 && OPEN_DEVTOOLS=true electron .\"",
"build": "next build",
"build:electron": "next build && electron-builder",
"start": "next start",

View File

@@ -10,6 +10,7 @@
"dev": "npm run dev --workspace=apps/app",
"dev:web": "npm run dev:web --workspace=apps/app",
"dev:electron": "npm run dev:electron --workspace=apps/app",
"dev:electron:debug": "npm run dev:electron:debug --workspace=apps/app",
"dev:electron:wsl": "npm run dev:electron:wsl --workspace=apps/app",
"dev:electron:wsl:gpu": "npm run dev:electron:wsl:gpu --workspace=apps/app",
"build": "npm run build --workspace=apps/app",