mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-04 09:13:08 +00:00
feat: implement running agents view and enhance auto mode functionality
- Added a new `RunningAgentsView` component to display currently active agents working on features. - Implemented auto-refresh functionality for the running agents list every 2 seconds. - Enhanced the auto mode service to support project-specific operations, including starting and stopping auto mode for individual projects. - Updated IPC handlers to manage auto mode status and running agents more effectively. - Introduced audio settings to mute notifications when agents complete tasks. - Refactored existing components to accommodate new features and improve overall user experience.
This commit is contained in:
@@ -20,11 +20,64 @@ class AutoModeService {
|
||||
constructor() {
|
||||
// Track multiple concurrent feature executions
|
||||
this.runningFeatures = new Map(); // featureId -> { abortController, query, projectPath, sendToRenderer }
|
||||
this.autoLoopRunning = false; // Separate flag for the auto loop
|
||||
this.autoLoopAbortController = null;
|
||||
this.autoLoopInterval = null; // Timer for periodic checking
|
||||
|
||||
// Per-project auto loop state (keyed by projectPath)
|
||||
this.projectLoops = new Map(); // projectPath -> { isRunning, interval, abortController, sendToRenderer, maxConcurrency }
|
||||
|
||||
this.checkIntervalMs = 5000; // Check every 5 seconds
|
||||
this.maxConcurrency = 3; // Default max concurrency
|
||||
this.maxConcurrency = 3; // Default max concurrency (global default)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create project loop state
|
||||
*/
|
||||
getProjectLoopState(projectPath) {
|
||||
if (!this.projectLoops.has(projectPath)) {
|
||||
this.projectLoops.set(projectPath, {
|
||||
isRunning: false,
|
||||
interval: null,
|
||||
abortController: null,
|
||||
sendToRenderer: null,
|
||||
maxConcurrency: this.maxConcurrency,
|
||||
});
|
||||
}
|
||||
return this.projectLoops.get(projectPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any project has auto mode running
|
||||
*/
|
||||
hasAnyAutoLoopRunning() {
|
||||
for (const [, state] of this.projectLoops) {
|
||||
if (state.isRunning) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get running features for a specific project
|
||||
*/
|
||||
getRunningFeaturesForProject(projectPath) {
|
||||
const features = [];
|
||||
for (const [featureId, execution] of this.runningFeatures) {
|
||||
if (execution.projectPath === projectPath) {
|
||||
features.push(featureId);
|
||||
}
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count running features for a specific project
|
||||
*/
|
||||
getRunningCountForProject(projectPath) {
|
||||
let count = 0;
|
||||
for (const [, execution] of this.runningFeatures) {
|
||||
if (execution.projectPath === projectPath) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,6 +96,18 @@ class AutoModeService {
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to emit event with projectPath included
|
||||
*/
|
||||
emitEvent(projectPath, sendToRenderer, event) {
|
||||
if (sendToRenderer) {
|
||||
sendToRenderer({
|
||||
...event,
|
||||
projectPath,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup worktree for a feature
|
||||
* Creates an isolated git worktree where the agent can work
|
||||
@@ -65,7 +130,7 @@ class AutoModeService {
|
||||
return { useWorktree: false, workPath: projectPath };
|
||||
}
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_progress",
|
||||
featureId: feature.id,
|
||||
content: "Creating isolated worktree for feature...\n",
|
||||
@@ -75,7 +140,7 @@ class AutoModeService {
|
||||
|
||||
if (!result.success) {
|
||||
console.warn(`[AutoMode] Failed to create worktree: ${result.error}. Falling back to main project.`);
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_progress",
|
||||
featureId: feature.id,
|
||||
content: `Warning: Could not create worktree (${result.error}). Working directly on main project.\n`,
|
||||
@@ -84,7 +149,7 @@ class AutoModeService {
|
||||
}
|
||||
|
||||
console.log(`[AutoMode] Created worktree at: ${result.worktreePath}, branch: ${result.branchName}`);
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_progress",
|
||||
featureId: feature.id,
|
||||
content: `Working in isolated branch: ${result.branchName}\n`,
|
||||
@@ -107,46 +172,56 @@ class AutoModeService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Start auto mode - continuously implement features
|
||||
* Start auto mode for a specific project - continuously implement features
|
||||
* Each project can have its own independent auto mode loop
|
||||
*/
|
||||
async start({ projectPath, sendToRenderer, maxConcurrency }) {
|
||||
if (this.autoLoopRunning) {
|
||||
throw new Error("Auto mode loop is already running");
|
||||
const projectState = this.getProjectLoopState(projectPath);
|
||||
|
||||
if (projectState.isRunning) {
|
||||
throw new Error(`Auto mode loop is already running for project: ${projectPath}`);
|
||||
}
|
||||
|
||||
this.autoLoopRunning = true;
|
||||
this.maxConcurrency = maxConcurrency || 3;
|
||||
projectState.isRunning = true;
|
||||
projectState.maxConcurrency = maxConcurrency || 3;
|
||||
projectState.sendToRenderer = sendToRenderer;
|
||||
|
||||
console.log(
|
||||
`[AutoMode] Starting auto mode for project: ${projectPath} with max concurrency: ${this.maxConcurrency}`
|
||||
`[AutoMode] Starting auto mode for project: ${projectPath} with max concurrency: ${projectState.maxConcurrency}`
|
||||
);
|
||||
|
||||
// Start the periodic checking loop
|
||||
this.runPeriodicLoop(projectPath, sendToRenderer);
|
||||
// Start the periodic checking loop for this project
|
||||
this.runPeriodicLoopForProject(projectPath);
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop auto mode - stops the auto loop but lets running features complete
|
||||
* Stop auto mode for a specific project - stops the auto loop but lets running features complete
|
||||
* This only turns off the auto toggle to prevent picking up new features.
|
||||
* Running tasks will continue until they complete naturally.
|
||||
*/
|
||||
async stop() {
|
||||
console.log("[AutoMode] Stopping auto mode (letting running features complete)");
|
||||
async stop({ projectPath }) {
|
||||
console.log(`[AutoMode] Stopping auto mode for project: ${projectPath} (letting running features complete)`);
|
||||
|
||||
this.autoLoopRunning = false;
|
||||
const projectState = this.projectLoops.get(projectPath);
|
||||
if (!projectState) {
|
||||
console.log(`[AutoMode] No auto mode state found for project: ${projectPath}`);
|
||||
return { success: true, runningFeatures: 0 };
|
||||
}
|
||||
|
||||
// Clear the interval timer
|
||||
if (this.autoLoopInterval) {
|
||||
clearInterval(this.autoLoopInterval);
|
||||
this.autoLoopInterval = null;
|
||||
projectState.isRunning = false;
|
||||
|
||||
// Clear the interval timer for this project
|
||||
if (projectState.interval) {
|
||||
clearInterval(projectState.interval);
|
||||
projectState.interval = null;
|
||||
}
|
||||
|
||||
// Abort auto loop if running
|
||||
if (this.autoLoopAbortController) {
|
||||
this.autoLoopAbortController.abort();
|
||||
this.autoLoopAbortController = null;
|
||||
if (projectState.abortController) {
|
||||
projectState.abortController.abort();
|
||||
projectState.abortController = null;
|
||||
}
|
||||
|
||||
// NOTE: We intentionally do NOT abort running features here.
|
||||
@@ -154,23 +229,58 @@ class AutoModeService {
|
||||
// from being picked up. Running features will complete naturally.
|
||||
// Use stopFeature() to cancel a specific running feature if needed.
|
||||
|
||||
const runningCount = this.runningFeatures.size;
|
||||
console.log(`[AutoMode] Auto loop stopped. ${runningCount} feature(s) still running and will complete.`);
|
||||
const runningCount = this.getRunningCountForProject(projectPath);
|
||||
console.log(`[AutoMode] Auto loop stopped for ${projectPath}. ${runningCount} feature(s) still running and will complete.`);
|
||||
|
||||
return { success: true, runningFeatures: runningCount };
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status of auto mode
|
||||
* Get status of auto mode (global and per-project)
|
||||
*/
|
||||
getStatus() {
|
||||
getStatus({ projectPath } = {}) {
|
||||
// If projectPath is specified, return status for that project
|
||||
if (projectPath) {
|
||||
const projectState = this.projectLoops.get(projectPath);
|
||||
return {
|
||||
autoLoopRunning: projectState?.isRunning || false,
|
||||
runningFeatures: this.getRunningFeaturesForProject(projectPath),
|
||||
runningCount: this.getRunningCountForProject(projectPath),
|
||||
};
|
||||
}
|
||||
|
||||
// Otherwise return global status
|
||||
const allRunningProjects = [];
|
||||
for (const [path, state] of this.projectLoops) {
|
||||
if (state.isRunning) {
|
||||
allRunningProjects.push(path);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
autoLoopRunning: this.autoLoopRunning,
|
||||
autoLoopRunning: this.hasAnyAutoLoopRunning(),
|
||||
runningProjects: allRunningProjects,
|
||||
runningFeatures: Array.from(this.runningFeatures.keys()),
|
||||
runningCount: this.runningFeatures.size,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status for all projects with auto mode
|
||||
*/
|
||||
getAllProjectStatuses() {
|
||||
const statuses = {};
|
||||
for (const [projectPath, state] of this.projectLoops) {
|
||||
statuses[projectPath] = {
|
||||
isRunning: state.isRunning,
|
||||
runningFeatures: this.getRunningFeaturesForProject(projectPath),
|
||||
runningCount: this.getRunningCountForProject(projectPath),
|
||||
maxConcurrency: state.maxConcurrency,
|
||||
};
|
||||
}
|
||||
return statuses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a specific feature by ID
|
||||
* @param {string} projectPath - Path to the project
|
||||
@@ -218,7 +328,7 @@ class AutoModeService {
|
||||
projectPath
|
||||
);
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_feature_start",
|
||||
featureId: feature.id,
|
||||
feature: { ...feature, worktreePath: worktreeSetup.workPath, branchName: worktreeSetup.branchName },
|
||||
@@ -253,7 +363,7 @@ class AutoModeService {
|
||||
|
||||
// Keep context file for viewing output later (deleted only when card is removed)
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_feature_complete",
|
||||
featureId: feature.id,
|
||||
passes: result.passes,
|
||||
@@ -288,7 +398,7 @@ class AutoModeService {
|
||||
console.error("[AutoMode] Failed to update feature status after error:", statusError);
|
||||
}
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
featureId: featureId,
|
||||
@@ -333,7 +443,7 @@ class AutoModeService {
|
||||
|
||||
console.log(`[AutoMode] Verifying feature: ${feature.description}`);
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_feature_start",
|
||||
featureId: feature.id,
|
||||
feature: feature,
|
||||
@@ -357,7 +467,7 @@ class AutoModeService {
|
||||
|
||||
// Keep context file for viewing output later (deleted only when card is removed)
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_feature_complete",
|
||||
featureId: feature.id,
|
||||
passes: result.passes,
|
||||
@@ -392,7 +502,7 @@ class AutoModeService {
|
||||
console.error("[AutoMode] Failed to update feature status after error:", statusError);
|
||||
}
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
featureId: featureId,
|
||||
@@ -437,7 +547,7 @@ class AutoModeService {
|
||||
|
||||
console.log(`[AutoMode] Resuming feature: ${feature.description}`);
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_feature_start",
|
||||
featureId: feature.id,
|
||||
feature: feature,
|
||||
@@ -481,7 +591,7 @@ class AutoModeService {
|
||||
`\n\n🔄 Auto-retry #${attempts} - Continuing implementation...\n\n`
|
||||
);
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_progress",
|
||||
featureId: feature.id,
|
||||
content: `\n🔄 Auto-retry #${attempts} - Agent ended early, continuing...\n`,
|
||||
@@ -524,7 +634,7 @@ class AutoModeService {
|
||||
|
||||
// Keep context file for viewing output later (deleted only when card is removed)
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_feature_complete",
|
||||
featureId: feature.id,
|
||||
passes: finalResult.passes,
|
||||
@@ -559,7 +669,7 @@ class AutoModeService {
|
||||
console.error("[AutoMode] Failed to update feature status after error:", statusError);
|
||||
}
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
featureId: featureId,
|
||||
@@ -572,42 +682,52 @@ class AutoModeService {
|
||||
}
|
||||
|
||||
/**
|
||||
* New periodic loop - checks available slots and starts features up to max concurrency
|
||||
* New periodic loop for a specific project - checks available slots and starts features up to max concurrency
|
||||
* This loop continues running even if there are no backlog items
|
||||
*/
|
||||
runPeriodicLoop(projectPath, sendToRenderer) {
|
||||
runPeriodicLoopForProject(projectPath) {
|
||||
const projectState = this.getProjectLoopState(projectPath);
|
||||
|
||||
console.log(
|
||||
`[AutoMode] Starting periodic loop with interval: ${this.checkIntervalMs}ms`
|
||||
`[AutoMode] Starting periodic loop for ${projectPath} with interval: ${this.checkIntervalMs}ms`
|
||||
);
|
||||
|
||||
// Initial check immediately
|
||||
this.checkAndStartFeatures(projectPath, sendToRenderer);
|
||||
this.checkAndStartFeaturesForProject(projectPath);
|
||||
|
||||
// Then check periodically
|
||||
this.autoLoopInterval = setInterval(() => {
|
||||
if (this.autoLoopRunning) {
|
||||
this.checkAndStartFeatures(projectPath, sendToRenderer);
|
||||
projectState.interval = setInterval(() => {
|
||||
if (projectState.isRunning) {
|
||||
this.checkAndStartFeaturesForProject(projectPath);
|
||||
}
|
||||
}, this.checkIntervalMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check how many features are running and start new ones if under max concurrency
|
||||
* Check how many features are running for a specific project and start new ones if under max concurrency
|
||||
*/
|
||||
async checkAndStartFeatures(projectPath, sendToRenderer) {
|
||||
async checkAndStartFeaturesForProject(projectPath) {
|
||||
const projectState = this.projectLoops.get(projectPath);
|
||||
if (!projectState || !projectState.isRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sendToRenderer = projectState.sendToRenderer;
|
||||
const maxConcurrency = projectState.maxConcurrency;
|
||||
|
||||
try {
|
||||
// Check how many are currently running
|
||||
const currentRunningCount = this.runningFeatures.size;
|
||||
// Check how many are currently running FOR THIS PROJECT
|
||||
const currentRunningCount = this.getRunningCountForProject(projectPath);
|
||||
|
||||
console.log(
|
||||
`[AutoMode] Checking features - Running: ${currentRunningCount}/${this.maxConcurrency}`
|
||||
`[AutoMode] [${projectPath}] Checking features - Running: ${currentRunningCount}/${maxConcurrency}`
|
||||
);
|
||||
|
||||
// Calculate available slots
|
||||
const availableSlots = this.maxConcurrency - currentRunningCount;
|
||||
// Calculate available slots for this project
|
||||
const availableSlots = maxConcurrency - currentRunningCount;
|
||||
|
||||
if (availableSlots <= 0) {
|
||||
console.log("[AutoMode] At max concurrency, waiting...");
|
||||
console.log(`[AutoMode] [${projectPath}] At max concurrency, waiting...`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -616,7 +736,7 @@ class AutoModeService {
|
||||
const backlogFeatures = features.filter((f) => f.status === "backlog");
|
||||
|
||||
if (backlogFeatures.length === 0) {
|
||||
console.log("[AutoMode] No backlog features available, waiting...");
|
||||
console.log(`[AutoMode] [${projectPath}] No backlog features available, waiting...`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -624,7 +744,7 @@ class AutoModeService {
|
||||
const featuresToStart = backlogFeatures.slice(0, availableSlots);
|
||||
|
||||
console.log(
|
||||
`[AutoMode] Starting ${featuresToStart.length} feature(s) from backlog`
|
||||
`[AutoMode] [${projectPath}] Starting ${featuresToStart.length} feature(s) from backlog`
|
||||
);
|
||||
|
||||
// Start each feature (don't await - run in parallel like drag operations)
|
||||
@@ -632,7 +752,7 @@ class AutoModeService {
|
||||
this.startFeatureAsync(feature, projectPath, sendToRenderer);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[AutoMode] Error checking/starting features:", error);
|
||||
console.error(`[AutoMode] [${projectPath}] Error checking/starting features:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,7 +798,7 @@ class AutoModeService {
|
||||
projectPath
|
||||
);
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_feature_start",
|
||||
featureId: feature.id,
|
||||
feature: { ...feature, worktreePath: worktreeSetup.workPath, branchName: worktreeSetup.branchName },
|
||||
@@ -713,7 +833,7 @@ class AutoModeService {
|
||||
|
||||
// Keep context file for viewing output later (deleted only when card is removed)
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_feature_complete",
|
||||
featureId: feature.id,
|
||||
passes: result.passes,
|
||||
@@ -746,7 +866,7 @@ class AutoModeService {
|
||||
console.error("[AutoMode] Failed to update feature status after error:", statusError);
|
||||
}
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
featureId: featureId,
|
||||
@@ -778,7 +898,7 @@ class AutoModeService {
|
||||
this.runningFeatures.set(analysisId, execution);
|
||||
|
||||
try {
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_feature_start",
|
||||
featureId: analysisId,
|
||||
feature: {
|
||||
@@ -796,7 +916,7 @@ class AutoModeService {
|
||||
execution
|
||||
);
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_feature_complete",
|
||||
featureId: analysisId,
|
||||
passes: result.success,
|
||||
@@ -806,7 +926,7 @@ class AutoModeService {
|
||||
return { success: true, message: result.message };
|
||||
} catch (error) {
|
||||
console.error("[AutoMode] Error analyzing project:", error);
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
featureId: analysisId,
|
||||
@@ -911,7 +1031,7 @@ class AutoModeService {
|
||||
projectPath
|
||||
);
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_feature_start",
|
||||
featureId: feature.id,
|
||||
feature: feature,
|
||||
@@ -956,7 +1076,7 @@ class AutoModeService {
|
||||
|
||||
// Keep context file for viewing output later (deleted only when card is removed)
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_feature_complete",
|
||||
featureId: feature.id,
|
||||
passes: result.passes,
|
||||
@@ -989,7 +1109,7 @@ class AutoModeService {
|
||||
console.error("[AutoMode] Failed to update feature status after error:", statusError);
|
||||
}
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
featureId: featureId,
|
||||
@@ -1021,13 +1141,13 @@ class AutoModeService {
|
||||
throw new Error(`Feature ${featureId} not found`);
|
||||
}
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_feature_start",
|
||||
featureId: feature.id,
|
||||
feature: { ...feature, description: "Committing changes..." },
|
||||
});
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_phase",
|
||||
featureId,
|
||||
phase: "action",
|
||||
@@ -1051,7 +1171,7 @@ class AutoModeService {
|
||||
|
||||
// Keep context file for viewing output later (deleted only when card is removed)
|
||||
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_feature_complete",
|
||||
featureId: feature.id,
|
||||
passes: true,
|
||||
@@ -1061,7 +1181,7 @@ class AutoModeService {
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error("[AutoMode] Error committing feature:", error);
|
||||
sendToRenderer({
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
featureId: featureId,
|
||||
@@ -1108,26 +1228,22 @@ class AutoModeService {
|
||||
// Delete context file
|
||||
await contextManager.deleteContextFile(projectPath, featureId);
|
||||
|
||||
if (sendToRenderer) {
|
||||
sendToRenderer({
|
||||
type: "auto_mode_feature_complete",
|
||||
featureId: featureId,
|
||||
passes: false,
|
||||
message: "Feature reverted - all changes discarded",
|
||||
});
|
||||
}
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_feature_complete",
|
||||
featureId: featureId,
|
||||
passes: false,
|
||||
message: "Feature reverted - all changes discarded",
|
||||
});
|
||||
|
||||
console.log(`[AutoMode] Feature ${featureId} reverted successfully`);
|
||||
return { success: true, removedPath: result.removedPath };
|
||||
} catch (error) {
|
||||
console.error("[AutoMode] Error reverting feature:", error);
|
||||
if (sendToRenderer) {
|
||||
sendToRenderer({
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
featureId: featureId,
|
||||
});
|
||||
}
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
featureId: featureId,
|
||||
});
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
@@ -1147,13 +1263,11 @@ class AutoModeService {
|
||||
throw new Error(`Feature ${featureId} not found`);
|
||||
}
|
||||
|
||||
if (sendToRenderer) {
|
||||
sendToRenderer({
|
||||
type: "auto_mode_progress",
|
||||
featureId: featureId,
|
||||
content: "Merging feature branch into main...\n",
|
||||
});
|
||||
}
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_progress",
|
||||
featureId: featureId,
|
||||
content: "Merging feature branch into main...\n",
|
||||
});
|
||||
|
||||
// Merge the worktree
|
||||
const result = await worktreeManager.mergeWorktree(projectPath, featureId, {
|
||||
@@ -1171,26 +1285,22 @@ class AutoModeService {
|
||||
// Update feature status to verified
|
||||
await featureLoader.updateFeatureStatus(featureId, "verified", projectPath);
|
||||
|
||||
if (sendToRenderer) {
|
||||
sendToRenderer({
|
||||
type: "auto_mode_feature_complete",
|
||||
featureId: featureId,
|
||||
passes: true,
|
||||
message: `Feature merged into ${result.intoBranch}`,
|
||||
});
|
||||
}
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_feature_complete",
|
||||
featureId: featureId,
|
||||
passes: true,
|
||||
message: `Feature merged into ${result.intoBranch}`,
|
||||
});
|
||||
|
||||
console.log(`[AutoMode] Feature ${featureId} merged successfully`);
|
||||
return { success: true, mergedBranch: result.mergedBranch };
|
||||
} catch (error) {
|
||||
console.error("[AutoMode] Error merging feature:", error);
|
||||
if (sendToRenderer) {
|
||||
sendToRenderer({
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
featureId: featureId,
|
||||
});
|
||||
}
|
||||
this.emitEvent(projectPath, sendToRenderer, {
|
||||
type: "auto_mode_error",
|
||||
error: error.message,
|
||||
featureId: featureId,
|
||||
});
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,6 +355,17 @@ ipcMain.handle("ping", () => {
|
||||
return "pong";
|
||||
});
|
||||
|
||||
// Open external link in default browser
|
||||
ipcMain.handle("shell:openExternal", async (_, url) => {
|
||||
try {
|
||||
await shell.openExternal(url);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error("[IPC] shell:openExternal error:", error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Agent IPC Handlers
|
||||
// ============================================================================
|
||||
@@ -574,11 +585,11 @@ ipcMain.handle(
|
||||
);
|
||||
|
||||
/**
|
||||
* Stop auto mode
|
||||
* Stop auto mode for a specific project
|
||||
*/
|
||||
ipcMain.handle("auto-mode:stop", async () => {
|
||||
ipcMain.handle("auto-mode:stop", async (_, { projectPath }) => {
|
||||
try {
|
||||
return await autoModeService.stop();
|
||||
return await autoModeService.stop({ projectPath });
|
||||
} catch (error) {
|
||||
console.error("[IPC] auto-mode:stop error:", error);
|
||||
return { success: false, error: error.message };
|
||||
@@ -586,11 +597,11 @@ ipcMain.handle("auto-mode:stop", async () => {
|
||||
});
|
||||
|
||||
/**
|
||||
* Get auto mode status
|
||||
* Get auto mode status (optionally for a specific project)
|
||||
*/
|
||||
ipcMain.handle("auto-mode:status", () => {
|
||||
ipcMain.handle("auto-mode:status", (_, { projectPath } = {}) => {
|
||||
try {
|
||||
return { success: true, ...autoModeService.getStatus() };
|
||||
return { success: true, ...autoModeService.getStatus({ projectPath }) };
|
||||
} catch (error) {
|
||||
console.error("[IPC] auto-mode:status error:", error);
|
||||
return { success: false, error: error.message };
|
||||
@@ -942,9 +953,11 @@ let suggestionsExecution = null;
|
||||
|
||||
/**
|
||||
* Generate feature suggestions by analyzing the project
|
||||
* @param {string} projectPath - The path to the project
|
||||
* @param {string} suggestionType - Type of suggestions: "features", "refactoring", "security", "performance"
|
||||
*/
|
||||
ipcMain.handle("suggestions:generate", async (_, { projectPath }) => {
|
||||
console.log("[IPC] suggestions:generate called with:", { projectPath });
|
||||
ipcMain.handle("suggestions:generate", async (_, { projectPath, suggestionType = "features" }) => {
|
||||
console.log("[IPC] suggestions:generate called with:", { projectPath, suggestionType });
|
||||
|
||||
try {
|
||||
// Check if already running
|
||||
@@ -970,7 +983,7 @@ ipcMain.handle("suggestions:generate", async (_, { projectPath }) => {
|
||||
|
||||
// Start generating suggestions (runs in background)
|
||||
featureSuggestionsService
|
||||
.generateSuggestions(projectPath, sendToRenderer, suggestionsExecution)
|
||||
.generateSuggestions(projectPath, sendToRenderer, suggestionsExecution, suggestionType)
|
||||
.catch((error) => {
|
||||
console.error("[IPC] suggestions:generate background error:", error);
|
||||
sendToRenderer({
|
||||
@@ -1776,3 +1789,41 @@ ipcMain.handle(
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// ============================================================================
|
||||
// Running Agents IPC Handlers
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Get all currently running agents across all projects
|
||||
*/
|
||||
ipcMain.handle("running-agents:getAll", () => {
|
||||
try {
|
||||
const status = autoModeService.getStatus();
|
||||
const allStatuses = autoModeService.getAllProjectStatuses();
|
||||
|
||||
// Build a list of running agents with their details
|
||||
const runningAgents = [];
|
||||
|
||||
for (const [projectPath, projectStatus] of Object.entries(allStatuses)) {
|
||||
for (const featureId of projectStatus.runningFeatures) {
|
||||
runningAgents.push({
|
||||
featureId,
|
||||
projectPath,
|
||||
projectName: projectPath.split(/[/\\]/).pop() || projectPath,
|
||||
isAutoMode: projectStatus.isRunning,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
runningAgents,
|
||||
totalCount: status.runningCount,
|
||||
autoLoopRunning: status.autoLoopRunning,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("[IPC] running-agents:getAll error:", error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,6 +6,9 @@ contextBridge.exposeInMainWorld("electronAPI", {
|
||||
// IPC test
|
||||
ping: () => ipcRenderer.invoke("ping"),
|
||||
|
||||
// Shell APIs
|
||||
openExternalLink: (url) => ipcRenderer.invoke("shell:openExternal", url),
|
||||
|
||||
// Dialog APIs
|
||||
openDirectory: () => ipcRenderer.invoke("dialog:openDirectory"),
|
||||
openFile: (options) => ipcRenderer.invoke("dialog:openFile", options),
|
||||
@@ -97,15 +100,15 @@ contextBridge.exposeInMainWorld("electronAPI", {
|
||||
|
||||
// Auto Mode API
|
||||
autoMode: {
|
||||
// Start auto mode
|
||||
// Start auto mode for a specific project
|
||||
start: (projectPath, maxConcurrency) =>
|
||||
ipcRenderer.invoke("auto-mode:start", { projectPath, maxConcurrency }),
|
||||
|
||||
// Stop auto mode
|
||||
stop: () => ipcRenderer.invoke("auto-mode:stop"),
|
||||
// Stop auto mode for a specific project
|
||||
stop: (projectPath) => ipcRenderer.invoke("auto-mode:stop", { projectPath }),
|
||||
|
||||
// Get auto mode status
|
||||
status: () => ipcRenderer.invoke("auto-mode:status"),
|
||||
// Get auto mode status (optionally for a specific project)
|
||||
status: (projectPath) => ipcRenderer.invoke("auto-mode:status", { projectPath }),
|
||||
|
||||
// Run a specific feature
|
||||
runFeature: (projectPath, featureId, useWorktrees) =>
|
||||
@@ -243,8 +246,9 @@ contextBridge.exposeInMainWorld("electronAPI", {
|
||||
// Feature Suggestions API
|
||||
suggestions: {
|
||||
// Generate feature suggestions
|
||||
generate: (projectPath) =>
|
||||
ipcRenderer.invoke("suggestions:generate", { projectPath }),
|
||||
// suggestionType can be: "features", "refactoring", "security", "performance"
|
||||
generate: (projectPath, suggestionType = "features") =>
|
||||
ipcRenderer.invoke("suggestions:generate", { projectPath, suggestionType }),
|
||||
|
||||
// Stop generating suggestions
|
||||
stop: () => ipcRenderer.invoke("suggestions:stop"),
|
||||
@@ -382,6 +386,12 @@ contextBridge.exposeInMainWorld("electronAPI", {
|
||||
getAgentOutput: (projectPath, featureId) =>
|
||||
ipcRenderer.invoke("features:getAgentOutput", { projectPath, featureId }),
|
||||
},
|
||||
|
||||
// Running Agents API
|
||||
runningAgents: {
|
||||
// Get all running agents across all projects
|
||||
getAll: () => ipcRenderer.invoke("running-agents:getAll"),
|
||||
},
|
||||
});
|
||||
|
||||
// Also expose a flag to detect if we're in Electron
|
||||
|
||||
@@ -303,6 +303,30 @@ class ClaudeCliDetector {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get installation info and recommendations
|
||||
* @returns {Object} Installation status and recommendations
|
||||
*/
|
||||
static getInstallationInfo() {
|
||||
const detection = this.detectClaudeInstallation();
|
||||
|
||||
if (detection.installed) {
|
||||
return {
|
||||
status: 'installed',
|
||||
method: detection.method,
|
||||
version: detection.version,
|
||||
path: detection.path,
|
||||
recommendation: 'Claude Code CLI is ready for ultrathink'
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: 'not_installed',
|
||||
recommendation: 'Install Claude Code CLI for optimal ultrathink performance',
|
||||
installCommands: this.getInstallCommands()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get installation commands for different platforms
|
||||
* @returns {Object} Installation commands
|
||||
|
||||
@@ -11,10 +11,14 @@ class FeatureSuggestionsService {
|
||||
|
||||
/**
|
||||
* Generate feature suggestions by analyzing the project
|
||||
* @param {string} projectPath - Path to the project
|
||||
* @param {Function} sendToRenderer - Function to send events to renderer
|
||||
* @param {Object} execution - Execution context with abort controller
|
||||
* @param {string} suggestionType - Type of suggestions: "features", "refactoring", "security", "performance"
|
||||
*/
|
||||
async generateSuggestions(projectPath, sendToRenderer, execution) {
|
||||
async generateSuggestions(projectPath, sendToRenderer, execution, suggestionType = "features") {
|
||||
console.log(
|
||||
`[FeatureSuggestions] Generating suggestions for: ${projectPath}`
|
||||
`[FeatureSuggestions] Generating ${suggestionType} suggestions for: ${projectPath}`
|
||||
);
|
||||
|
||||
try {
|
||||
@@ -23,7 +27,7 @@ class FeatureSuggestionsService {
|
||||
|
||||
const options = {
|
||||
model: "claude-sonnet-4-20250514",
|
||||
systemPrompt: this.getSystemPrompt(),
|
||||
systemPrompt: this.getSystemPrompt(suggestionType),
|
||||
maxTurns: 50,
|
||||
cwd: projectPath,
|
||||
allowedTools: ["Read", "Glob", "Grep", "Bash"],
|
||||
@@ -35,7 +39,7 @@ class FeatureSuggestionsService {
|
||||
abortController: abortController,
|
||||
};
|
||||
|
||||
const prompt = this.buildAnalysisPrompt();
|
||||
const prompt = this.buildAnalysisPrompt(suggestionType);
|
||||
|
||||
sendToRenderer({
|
||||
type: "suggestions_progress",
|
||||
@@ -163,36 +167,102 @@ class FeatureSuggestionsService {
|
||||
|
||||
/**
|
||||
* Get the system prompt for feature suggestion analysis
|
||||
* @param {string} suggestionType - Type of suggestions: "features", "refactoring", "security", "performance"
|
||||
*/
|
||||
getSystemPrompt() {
|
||||
return `You are an expert software architect and product manager. Your job is to analyze a codebase and suggest missing features that would improve the application.
|
||||
getSystemPrompt(suggestionType = "features") {
|
||||
const basePrompt = `You are an expert software architect. Your job is to analyze a codebase and provide actionable suggestions.
|
||||
|
||||
You should:
|
||||
1. Thoroughly analyze the project structure, code, and any existing documentation
|
||||
2. Identify what the application does and what features it currently has (look at the .automaker/app_spec.txt file as well if it exists)
|
||||
3. Generate a comprehensive list of missing features that would be valuable to users
|
||||
4. Prioritize features by impact and complexity
|
||||
5. Provide clear, actionable descriptions and implementation steps
|
||||
You have access to file reading and search tools. Use them to understand the codebase.
|
||||
|
||||
When analyzing, look at:
|
||||
- README files and documentation
|
||||
- Package.json, cargo.toml, or similar config files for tech stack
|
||||
- Source code structure and organization
|
||||
- Existing features and their implementation patterns
|
||||
- Common patterns in similar applications
|
||||
- User experience improvements
|
||||
- Developer experience improvements
|
||||
- Performance optimizations
|
||||
- Security enhancements
|
||||
- Existing code patterns and implementation styles`;
|
||||
|
||||
You have access to file reading and search tools. Use them to understand the codebase.`;
|
||||
switch (suggestionType) {
|
||||
case "refactoring":
|
||||
return `${basePrompt}
|
||||
|
||||
Your specific focus is on **refactoring suggestions**. You should:
|
||||
1. Identify code smells and areas that need cleanup
|
||||
2. Find duplicated code that could be consolidated
|
||||
3. Spot overly complex functions or classes that should be broken down
|
||||
4. Look for inconsistent naming conventions or coding patterns
|
||||
5. Find opportunities to improve code organization and modularity
|
||||
6. Identify violations of SOLID principles or common design patterns
|
||||
7. Look for dead code or unused dependencies
|
||||
|
||||
Prioritize suggestions by:
|
||||
- Impact on maintainability
|
||||
- Risk level (lower risk refactorings first)
|
||||
- Complexity of the refactoring`;
|
||||
|
||||
case "security":
|
||||
return `${basePrompt}
|
||||
|
||||
Your specific focus is on **security vulnerabilities and improvements**. You should:
|
||||
1. Identify potential security vulnerabilities (OWASP Top 10)
|
||||
2. Look for hardcoded secrets, API keys, or credentials
|
||||
3. Check for proper input validation and sanitization
|
||||
4. Identify SQL injection, XSS, or command injection risks
|
||||
5. Review authentication and authorization patterns
|
||||
6. Check for secure communication (HTTPS, encryption)
|
||||
7. Look for insecure dependencies or outdated packages
|
||||
8. Review error handling that might leak sensitive information
|
||||
9. Check for proper session management
|
||||
10. Identify insecure file handling or path traversal risks
|
||||
|
||||
Prioritize by severity:
|
||||
- Critical: Exploitable vulnerabilities with high impact
|
||||
- High: Security issues that could lead to data exposure
|
||||
- Medium: Best practice violations that weaken security
|
||||
- Low: Minor improvements to security posture`;
|
||||
|
||||
case "performance":
|
||||
return `${basePrompt}
|
||||
|
||||
Your specific focus is on **performance issues and optimizations**. You should:
|
||||
1. Identify N+1 query problems or inefficient database access
|
||||
2. Look for unnecessary re-renders in React/frontend code
|
||||
3. Find opportunities for caching or memoization
|
||||
4. Identify large bundle sizes or unoptimized imports
|
||||
5. Look for blocking operations that could be async
|
||||
6. Find memory leaks or inefficient memory usage
|
||||
7. Identify slow algorithms or data structure choices
|
||||
8. Look for missing indexes in database schemas
|
||||
9. Find opportunities for lazy loading or code splitting
|
||||
10. Identify unnecessary network requests or API calls
|
||||
|
||||
Prioritize by:
|
||||
- Impact on user experience
|
||||
- Frequency of the slow path
|
||||
- Ease of implementation`;
|
||||
|
||||
default: // "features"
|
||||
return `${basePrompt}
|
||||
|
||||
Your specific focus is on **missing features and improvements**. You should:
|
||||
1. Identify what the application does and what features it currently has
|
||||
2. Look at the .automaker/app_spec.txt file if it exists
|
||||
3. Generate a comprehensive list of missing features that would be valuable to users
|
||||
4. Consider user experience improvements
|
||||
5. Consider developer experience improvements
|
||||
6. Look at common patterns in similar applications
|
||||
|
||||
Prioritize features by:
|
||||
- Impact on users
|
||||
- Alignment with project goals
|
||||
- Complexity of implementation`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the prompt for analyzing the project
|
||||
* @param {string} suggestionType - Type of suggestions: "features", "refactoring", "security", "performance"
|
||||
*/
|
||||
buildAnalysisPrompt() {
|
||||
return `Analyze this project and generate a list of suggested features that are missing or would improve the application.
|
||||
buildAnalysisPrompt(suggestionType = "features") {
|
||||
const commonIntro = `Analyze this project and generate a list of actionable suggestions.
|
||||
|
||||
**Your Task:**
|
||||
|
||||
@@ -200,13 +270,89 @@ You have access to file reading and search tools. Use them to understand the cod
|
||||
- Read README.md, package.json, or similar config files
|
||||
- Scan the source code directory structure
|
||||
- Identify the tech stack and frameworks used
|
||||
- Look at existing features and how they're implemented
|
||||
- Look at existing code and how it's implemented
|
||||
|
||||
2. Identify what the application does:
|
||||
- What is the main purpose?
|
||||
- What features are already implemented?
|
||||
- What patterns and conventions are used?
|
||||
`;
|
||||
|
||||
const commonOutput = `
|
||||
**CRITICAL: Output your suggestions as a JSON array** at the end of your response, formatted like this:
|
||||
|
||||
\`\`\`json
|
||||
[
|
||||
{
|
||||
"category": "Category Name",
|
||||
"description": "Clear description of the suggestion",
|
||||
"steps": [
|
||||
"Step 1 to implement",
|
||||
"Step 2 to implement",
|
||||
"Step 3 to implement"
|
||||
],
|
||||
"priority": 1,
|
||||
"reasoning": "Why this is important"
|
||||
}
|
||||
]
|
||||
\`\`\`
|
||||
|
||||
**Important Guidelines:**
|
||||
- Generate at least 10-15 suggestions
|
||||
- Order them by priority (1 = highest priority)
|
||||
- Each suggestion should have clear, actionable steps
|
||||
- Be specific about what files might need to be modified
|
||||
- Consider the existing tech stack and patterns
|
||||
|
||||
Begin by exploring the project structure.`;
|
||||
|
||||
switch (suggestionType) {
|
||||
case "refactoring":
|
||||
return `${commonIntro}
|
||||
3. Look for refactoring opportunities:
|
||||
- Find code duplication across the codebase
|
||||
- Identify functions or classes that are too long or complex
|
||||
- Look for inconsistent patterns or naming conventions
|
||||
- Find tightly coupled code that should be decoupled
|
||||
- Identify opportunities to extract reusable utilities
|
||||
- Look for dead code or unused exports
|
||||
- Check for proper separation of concerns
|
||||
|
||||
Categories to use: "Code Smell", "Duplication", "Complexity", "Architecture", "Naming", "Dead Code", "Coupling", "Testing"
|
||||
${commonOutput}`;
|
||||
|
||||
case "security":
|
||||
return `${commonIntro}
|
||||
3. Look for security issues:
|
||||
- Check for hardcoded secrets or API keys
|
||||
- Look for potential injection vulnerabilities (SQL, XSS, command)
|
||||
- Review authentication and authorization code
|
||||
- Check input validation and sanitization
|
||||
- Look for insecure dependencies
|
||||
- Review error handling for information leakage
|
||||
- Check for proper HTTPS/TLS usage
|
||||
- Look for insecure file operations
|
||||
|
||||
Categories to use: "Critical", "High", "Medium", "Low" (based on severity)
|
||||
${commonOutput}`;
|
||||
|
||||
case "performance":
|
||||
return `${commonIntro}
|
||||
3. Look for performance issues:
|
||||
- Find N+1 queries or inefficient database access patterns
|
||||
- Look for unnecessary re-renders in React components
|
||||
- Identify missing memoization opportunities
|
||||
- Check bundle size and import patterns
|
||||
- Look for synchronous operations that could be async
|
||||
- Find potential memory leaks
|
||||
- Identify slow algorithms or data structures
|
||||
- Look for missing caching opportunities
|
||||
- Check for unnecessary network requests
|
||||
|
||||
Categories to use: "Database", "Rendering", "Memory", "Bundle Size", "Caching", "Algorithm", "Network"
|
||||
${commonOutput}`;
|
||||
|
||||
default: // "features"
|
||||
return `${commonIntro}
|
||||
3. Generate feature suggestions:
|
||||
- Think about what's missing compared to similar applications
|
||||
- Consider user experience improvements
|
||||
@@ -214,45 +360,9 @@ You have access to file reading and search tools. Use them to understand the cod
|
||||
- Think about performance, security, and reliability
|
||||
- Consider testing and documentation improvements
|
||||
|
||||
4. **CRITICAL: Output your suggestions as a JSON array** at the end of your response, formatted like this:
|
||||
|
||||
\`\`\`json
|
||||
[
|
||||
{
|
||||
"category": "User Experience",
|
||||
"description": "Add dark mode support with system preference detection",
|
||||
"steps": [
|
||||
"Create a ThemeProvider context to manage theme state",
|
||||
"Add a toggle component in the settings or header",
|
||||
"Implement CSS variables for theme colors",
|
||||
"Add localStorage persistence for user preference"
|
||||
],
|
||||
"priority": 1,
|
||||
"reasoning": "Dark mode is a standard feature that improves accessibility and user comfort"
|
||||
},
|
||||
{
|
||||
"category": "Performance",
|
||||
"description": "Implement lazy loading for heavy components",
|
||||
"steps": [
|
||||
"Identify components that are heavy or rarely used",
|
||||
"Use React.lazy() and Suspense for code splitting",
|
||||
"Add loading states for lazy-loaded components"
|
||||
],
|
||||
"priority": 2,
|
||||
"reasoning": "Improves initial load time and reduces bundle size"
|
||||
}
|
||||
]
|
||||
\`\`\`
|
||||
|
||||
**Important Guidelines:**
|
||||
- Generate at least 10-20 feature suggestions
|
||||
- Order them by priority (1 = highest priority)
|
||||
- Each feature should have clear, actionable steps
|
||||
- Categories should be meaningful (e.g., "User Experience", "Performance", "Security", "Testing", "Documentation", "Developer Experience", "Accessibility", etc.)
|
||||
- Be specific about what files might need to be created or modified
|
||||
- Consider the existing tech stack and patterns when suggesting implementation steps
|
||||
|
||||
Begin by exploring the project structure.`;
|
||||
Categories to use: "User Experience", "Performance", "Security", "Testing", "Documentation", "Developer Experience", "Accessibility", etc.
|
||||
${commonOutput}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -251,7 +251,7 @@ class ClaudeProvider extends ModelProvider {
|
||||
|
||||
async detectInstallation() {
|
||||
const claudeCliDetector = require('./claude-cli-detector');
|
||||
return claudeCliDetector.getInstallationInfo();
|
||||
return claudeCliDetector.getFullStatus();
|
||||
}
|
||||
|
||||
getAvailableModels() {
|
||||
|
||||
Reference in New Issue
Block a user