mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-03 08:53:36 +00:00
feat: implement structured logging across server components
- Integrated a centralized logging system using createLogger from @automaker/utils, replacing console.log and console.error statements with logger methods for consistent log formatting and improved readability. - Updated various modules, including auth, events, and services, to utilize the new logging system, enhancing error tracking and operational visibility. - Refactored logging messages to provide clearer context and information, ensuring better maintainability and debugging capabilities. This update significantly enhances the observability of the server components, facilitating easier troubleshooting and monitoring.
This commit is contained in:
@@ -25,7 +25,10 @@ import {
|
||||
isAbortError,
|
||||
classifyError,
|
||||
loadContextFiles,
|
||||
createLogger,
|
||||
} from '@automaker/utils';
|
||||
|
||||
const logger = createLogger('AutoMode');
|
||||
import { resolveModelString, resolvePhaseModel, DEFAULT_MODELS } from '@automaker/model-resolver';
|
||||
import { resolveDependencies, areDependenciesSatisfied } from '@automaker/dependency-resolver';
|
||||
import { getFeatureDir, getAutomakerDir, getFeaturesDir } from '@automaker/platform';
|
||||
@@ -262,8 +265,8 @@ export class AutoModeService {
|
||||
|
||||
this.pausedDueToFailures = true;
|
||||
const failureCount = this.consecutiveFailures.length;
|
||||
console.log(
|
||||
`[AutoMode] Pausing auto loop after ${failureCount} consecutive failures. Last error: ${errorInfo.type}`
|
||||
logger.info(
|
||||
`Pausing auto loop after ${failureCount} consecutive failures. Last error: ${errorInfo.type}`
|
||||
);
|
||||
|
||||
// Emit event to notify UI
|
||||
@@ -323,7 +326,7 @@ export class AutoModeService {
|
||||
|
||||
// Run the loop in the background
|
||||
this.runAutoLoop().catch((error) => {
|
||||
console.error('[AutoMode] Loop error:', error);
|
||||
logger.error('Loop error:', error);
|
||||
const errorInfo = classifyError(error);
|
||||
this.emitAutoModeEvent('auto_mode_error', {
|
||||
error: errorInfo.message,
|
||||
@@ -368,13 +371,13 @@ export class AutoModeService {
|
||||
this.config!.useWorktrees,
|
||||
true
|
||||
).catch((error) => {
|
||||
console.error(`[AutoMode] Feature ${nextFeature.id} error:`, error);
|
||||
logger.error(`Feature ${nextFeature.id} error:`, error);
|
||||
});
|
||||
}
|
||||
|
||||
await this.sleep(2000);
|
||||
} catch (error) {
|
||||
console.error('[AutoMode] Loop iteration error:', error);
|
||||
logger.error('Loop iteration error:', error);
|
||||
await this.sleep(5000);
|
||||
}
|
||||
}
|
||||
@@ -447,8 +450,8 @@ export class AutoModeService {
|
||||
if (!options?.continuationPrompt) {
|
||||
const hasExistingContext = await this.contextExists(projectPath, featureId);
|
||||
if (hasExistingContext) {
|
||||
console.log(
|
||||
`[AutoMode] Feature ${featureId} has existing context, resuming instead of starting fresh`
|
||||
logger.info(
|
||||
`Feature ${featureId} has existing context, resuming instead of starting fresh`
|
||||
);
|
||||
// Remove from running features temporarily, resumeFeature will add it back
|
||||
this.runningFeatures.delete(featureId);
|
||||
@@ -483,12 +486,10 @@ export class AutoModeService {
|
||||
worktreePath = await this.findExistingWorktreeForBranch(projectPath, branchName);
|
||||
|
||||
if (worktreePath) {
|
||||
console.log(`[AutoMode] Using worktree for branch "${branchName}": ${worktreePath}`);
|
||||
logger.info(`Using worktree for branch "${branchName}": ${worktreePath}`);
|
||||
} else {
|
||||
// Worktree doesn't exist - log warning and continue with project path
|
||||
console.warn(
|
||||
`[AutoMode] Worktree for branch "${branchName}" not found, using project path`
|
||||
);
|
||||
logger.warn(`Worktree for branch "${branchName}" not found, using project path`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,7 +529,7 @@ export class AutoModeService {
|
||||
// Continuation prompt is used when recovering from a plan approval
|
||||
// The plan was already approved, so skip the planning phase
|
||||
prompt = options.continuationPrompt;
|
||||
console.log(`[AutoMode] Using continuation prompt for feature ${featureId}`);
|
||||
logger.info(`Using continuation prompt for feature ${featureId}`);
|
||||
} else {
|
||||
// Normal flow: build prompt with planning phase
|
||||
const featurePrompt = this.buildFeaturePrompt(feature);
|
||||
@@ -553,8 +554,8 @@ export class AutoModeService {
|
||||
// Get model from feature and determine provider
|
||||
const model = resolveModelString(feature.model, DEFAULT_MODELS.claude);
|
||||
const provider = ProviderFactory.getProviderNameForModel(model);
|
||||
console.log(
|
||||
`[AutoMode] Executing feature ${featureId} with model: ${model}, provider: ${provider} in ${workDir}`
|
||||
logger.info(
|
||||
`Executing feature ${featureId} with model: ${model}, provider: ${provider} in ${workDir}`
|
||||
);
|
||||
|
||||
// Store model and provider in running feature for tracking
|
||||
@@ -628,7 +629,7 @@ export class AutoModeService {
|
||||
projectPath,
|
||||
});
|
||||
} else {
|
||||
console.error(`[AutoMode] Feature ${featureId} failed:`, error);
|
||||
logger.error(`Feature ${featureId} failed:`, error);
|
||||
await this.updateFeatureStatus(projectPath, featureId, 'backlog');
|
||||
this.emitAutoModeEvent('auto_mode_error', {
|
||||
featureId,
|
||||
@@ -653,9 +654,9 @@ export class AutoModeService {
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
console.log(`[AutoMode] Feature ${featureId} execution ended, cleaning up runningFeatures`);
|
||||
console.log(
|
||||
`[AutoMode] Pending approvals at cleanup: ${Array.from(this.pendingApprovals.keys()).join(', ') || 'none'}`
|
||||
logger.info(`Feature ${featureId} execution ended, cleaning up runningFeatures`);
|
||||
logger.info(
|
||||
`Pending approvals at cleanup: ${Array.from(this.pendingApprovals.keys()).join(', ') || 'none'}`
|
||||
);
|
||||
this.runningFeatures.delete(featureId);
|
||||
}
|
||||
@@ -673,7 +674,7 @@ export class AutoModeService {
|
||||
abortController: AbortController,
|
||||
autoLoadClaudeMd: boolean
|
||||
): Promise<void> {
|
||||
console.log(`[AutoMode] Executing ${steps.length} pipeline step(s) for feature ${featureId}`);
|
||||
logger.info(`Executing ${steps.length} pipeline step(s) for feature ${featureId}`);
|
||||
|
||||
// Load context files once
|
||||
const contextResult = await loadContextFiles({
|
||||
@@ -756,12 +757,12 @@ export class AutoModeService {
|
||||
projectPath,
|
||||
});
|
||||
|
||||
console.log(
|
||||
`[AutoMode] Pipeline step ${i + 1}/${steps.length} (${step.name}) completed for feature ${featureId}`
|
||||
logger.info(
|
||||
`Pipeline step ${i + 1}/${steps.length} (${step.name}) completed for feature ${featureId}`
|
||||
);
|
||||
}
|
||||
|
||||
console.log(`[AutoMode] All pipeline steps completed for feature ${featureId}`);
|
||||
logger.info(`All pipeline steps completed for feature ${featureId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -886,7 +887,7 @@ Complete the pipeline step instructions above. Review the previous work and appl
|
||||
|
||||
if (worktreePath) {
|
||||
workDir = worktreePath;
|
||||
console.log(`[AutoMode] Follow-up using worktree for branch "${branchName}": ${workDir}`);
|
||||
logger.info(`Follow-up using worktree for branch "${branchName}": ${workDir}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -942,9 +943,7 @@ Address the follow-up instructions above. Review the previous work and make the
|
||||
// Get model from feature and determine provider early for tracking
|
||||
const model = resolveModelString(feature?.model, DEFAULT_MODELS.claude);
|
||||
const provider = ProviderFactory.getProviderNameForModel(model);
|
||||
console.log(
|
||||
`[AutoMode] Follow-up for feature ${featureId} using model: ${model}, provider: ${provider}`
|
||||
);
|
||||
logger.info(`Follow-up for feature ${featureId} using model: ${model}, provider: ${provider}`);
|
||||
|
||||
this.runningFeatures.set(featureId, {
|
||||
featureId,
|
||||
@@ -994,7 +993,7 @@ Address the follow-up instructions above. Review the previous work and make the
|
||||
// Store the absolute path (external storage uses absolute paths)
|
||||
copiedImagePaths.push(destPath);
|
||||
} catch (error) {
|
||||
console.error(`[AutoMode] Failed to copy follow-up image ${imagePath}:`, error);
|
||||
logger.error(`Failed to copy follow-up image ${imagePath}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1030,7 +1029,7 @@ Address the follow-up instructions above. Review the previous work and make the
|
||||
try {
|
||||
await secureFs.writeFile(featurePath, JSON.stringify(feature, null, 2));
|
||||
} catch (error) {
|
||||
console.error(`[AutoMode] Failed to save feature.json:`, error);
|
||||
logger.error(`Failed to save feature.json:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1178,10 +1177,10 @@ Address the follow-up instructions above. Review the previous work and make the
|
||||
try {
|
||||
await secureFs.access(providedWorktreePath);
|
||||
workDir = providedWorktreePath;
|
||||
console.log(`[AutoMode] Committing in provided worktree: ${workDir}`);
|
||||
logger.info(`Committing in provided worktree: ${workDir}`);
|
||||
} catch {
|
||||
console.log(
|
||||
`[AutoMode] Provided worktree path doesn't exist: ${providedWorktreePath}, using project path`
|
||||
logger.info(
|
||||
`Provided worktree path doesn't exist: ${providedWorktreePath}, using project path`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@@ -1190,9 +1189,9 @@ Address the follow-up instructions above. Review the previous work and make the
|
||||
try {
|
||||
await secureFs.access(legacyWorktreePath);
|
||||
workDir = legacyWorktreePath;
|
||||
console.log(`[AutoMode] Committing in legacy worktree: ${workDir}`);
|
||||
logger.info(`Committing in legacy worktree: ${workDir}`);
|
||||
} catch {
|
||||
console.log(`[AutoMode] No worktree found, committing in project path: ${workDir}`);
|
||||
logger.info(`No worktree found, committing in project path: ${workDir}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1232,7 +1231,7 @@ Address the follow-up instructions above. Review the previous work and make the
|
||||
|
||||
return hash.trim();
|
||||
} catch (error) {
|
||||
console.error(`[AutoMode] Commit failed for ${featureId}:`, error);
|
||||
logger.error(`Commit failed for ${featureId}:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1286,7 +1285,7 @@ Format your response as a structured markdown document.`;
|
||||
settings?.phaseModels?.projectAnalysisModel || DEFAULT_PHASE_MODELS.projectAnalysisModel;
|
||||
const { model: analysisModel, thinkingLevel: analysisThinkingLevel } =
|
||||
resolvePhaseModel(phaseModelEntry);
|
||||
console.log('[AutoMode] Using model for project analysis:', analysisModel);
|
||||
logger.info('Using model for project analysis:', analysisModel);
|
||||
|
||||
const provider = ProviderFactory.getProviderForModel(analysisModel);
|
||||
|
||||
@@ -1432,9 +1431,9 @@ Format your response as a structured markdown document.`;
|
||||
featureId: string,
|
||||
projectPath: string
|
||||
): Promise<{ approved: boolean; editedPlan?: string; feedback?: string }> {
|
||||
console.log(`[AutoMode] Registering pending approval for feature ${featureId}`);
|
||||
console.log(
|
||||
`[AutoMode] Current pending approvals: ${Array.from(this.pendingApprovals.keys()).join(', ') || 'none'}`
|
||||
logger.info(`Registering pending approval for feature ${featureId}`);
|
||||
logger.info(
|
||||
`Current pending approvals: ${Array.from(this.pendingApprovals.keys()).join(', ') || 'none'}`
|
||||
);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.pendingApprovals.set(featureId, {
|
||||
@@ -1443,7 +1442,7 @@ Format your response as a structured markdown document.`;
|
||||
featureId,
|
||||
projectPath,
|
||||
});
|
||||
console.log(`[AutoMode] Pending approval registered for feature ${featureId}`);
|
||||
logger.info(`Pending approval registered for feature ${featureId}`);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1458,27 +1457,23 @@ Format your response as a structured markdown document.`;
|
||||
feedback?: string,
|
||||
projectPathFromClient?: string
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
console.log(
|
||||
`[AutoMode] resolvePlanApproval called for feature ${featureId}, approved=${approved}`
|
||||
);
|
||||
console.log(
|
||||
`[AutoMode] Current pending approvals: ${Array.from(this.pendingApprovals.keys()).join(', ') || 'none'}`
|
||||
logger.info(`resolvePlanApproval called for feature ${featureId}, approved=${approved}`);
|
||||
logger.info(
|
||||
`Current pending approvals: ${Array.from(this.pendingApprovals.keys()).join(', ') || 'none'}`
|
||||
);
|
||||
const pending = this.pendingApprovals.get(featureId);
|
||||
|
||||
if (!pending) {
|
||||
console.log(`[AutoMode] No pending approval in Map for feature ${featureId}`);
|
||||
logger.info(`No pending approval in Map for feature ${featureId}`);
|
||||
|
||||
// RECOVERY: If no pending approval but we have projectPath from client,
|
||||
// check if feature's planSpec.status is 'generated' and handle recovery
|
||||
if (projectPathFromClient) {
|
||||
console.log(`[AutoMode] Attempting recovery with projectPath: ${projectPathFromClient}`);
|
||||
logger.info(`Attempting recovery with projectPath: ${projectPathFromClient}`);
|
||||
const feature = await this.loadFeature(projectPathFromClient, featureId);
|
||||
|
||||
if (feature?.planSpec?.status === 'generated') {
|
||||
console.log(
|
||||
`[AutoMode] Feature ${featureId} has planSpec.status='generated', performing recovery`
|
||||
);
|
||||
logger.info(`Feature ${featureId} has planSpec.status='generated', performing recovery`);
|
||||
|
||||
if (approved) {
|
||||
// Update planSpec to approved
|
||||
@@ -1497,17 +1492,14 @@ Format your response as a structured markdown document.`;
|
||||
}
|
||||
continuationPrompt += `Now proceed with the implementation as specified in the plan:\n\n${planContent}\n\nImplement the feature now.`;
|
||||
|
||||
console.log(`[AutoMode] Starting recovery execution for feature ${featureId}`);
|
||||
logger.info(`Starting recovery execution for feature ${featureId}`);
|
||||
|
||||
// Start feature execution with the continuation prompt (async, don't await)
|
||||
// Pass undefined for providedWorktreePath, use options for continuation prompt
|
||||
this.executeFeature(projectPathFromClient, featureId, true, false, undefined, {
|
||||
continuationPrompt,
|
||||
}).catch((error) => {
|
||||
console.error(
|
||||
`[AutoMode] Recovery execution failed for feature ${featureId}:`,
|
||||
error
|
||||
);
|
||||
logger.error(`Recovery execution failed for feature ${featureId}:`, error);
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
@@ -1531,15 +1523,15 @@ Format your response as a structured markdown document.`;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[AutoMode] ERROR: No pending approval found for feature ${featureId} and recovery not possible`
|
||||
logger.info(
|
||||
`ERROR: No pending approval found for feature ${featureId} and recovery not possible`
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
error: `No pending approval for feature ${featureId}`,
|
||||
};
|
||||
}
|
||||
console.log(`[AutoMode] Found pending approval for feature ${featureId}, proceeding...`);
|
||||
logger.info(`Found pending approval for feature ${featureId}, proceeding...`);
|
||||
|
||||
const { projectPath } = pending;
|
||||
|
||||
@@ -1572,17 +1564,17 @@ Format your response as a structured markdown document.`;
|
||||
* Cancel a pending plan approval (e.g., when feature is stopped).
|
||||
*/
|
||||
cancelPlanApproval(featureId: string): void {
|
||||
console.log(`[AutoMode] cancelPlanApproval called for feature ${featureId}`);
|
||||
console.log(
|
||||
`[AutoMode] Current pending approvals: ${Array.from(this.pendingApprovals.keys()).join(', ') || 'none'}`
|
||||
logger.info(`cancelPlanApproval called for feature ${featureId}`);
|
||||
logger.info(
|
||||
`Current pending approvals: ${Array.from(this.pendingApprovals.keys()).join(', ') || 'none'}`
|
||||
);
|
||||
const pending = this.pendingApprovals.get(featureId);
|
||||
if (pending) {
|
||||
console.log(`[AutoMode] Found and cancelling pending approval for feature ${featureId}`);
|
||||
logger.info(`Found and cancelling pending approval for feature ${featureId}`);
|
||||
pending.reject(new Error('Plan approval cancelled - feature was stopped'));
|
||||
this.pendingApprovals.delete(featureId);
|
||||
} else {
|
||||
console.log(`[AutoMode] No pending approval to cancel for feature ${featureId}`);
|
||||
logger.info(`No pending approval to cancel for feature ${featureId}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1722,7 +1714,7 @@ Format your response as a structured markdown document.`;
|
||||
feature.updatedAt = new Date().toISOString();
|
||||
await secureFs.writeFile(featurePath, JSON.stringify(feature, null, 2));
|
||||
} catch (error) {
|
||||
console.error(`[AutoMode] Failed to update planSpec for ${featureId}:`, error);
|
||||
logger.error(`Failed to update planSpec for ${featureId}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1980,7 +1972,7 @@ This helps parse your summary correctly in the output logs.`;
|
||||
// CI/CD Mock Mode: Return early with mock response when AUTOMAKER_MOCK_AGENT is set
|
||||
// This prevents actual API calls during automated testing
|
||||
if (process.env.AUTOMAKER_MOCK_AGENT === 'true') {
|
||||
console.log(`[AutoMode] MOCK MODE: Skipping real agent execution for feature ${featureId}`);
|
||||
logger.info(`MOCK MODE: Skipping real agent execution for feature ${featureId}`);
|
||||
|
||||
// Simulate some work being done
|
||||
await this.sleep(500);
|
||||
@@ -2030,7 +2022,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
|
||||
await secureFs.mkdir(path.dirname(outputPath), { recursive: true });
|
||||
await secureFs.writeFile(outputPath, mockOutput);
|
||||
|
||||
console.log(`[AutoMode] MOCK MODE: Completed mock execution for feature ${featureId}`);
|
||||
logger.info(`MOCK MODE: Completed mock execution for feature ${featureId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2068,14 +2060,14 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
|
||||
const maxTurns = sdkOptions.maxTurns;
|
||||
const allowedTools = sdkOptions.allowedTools as string[] | undefined;
|
||||
|
||||
console.log(
|
||||
`[AutoMode] runAgent called for feature ${featureId} with model: ${finalModel}, planningMode: ${planningMode}, requiresApproval: ${requiresApproval}`
|
||||
logger.info(
|
||||
`runAgent called for feature ${featureId} with model: ${finalModel}, planningMode: ${planningMode}, requiresApproval: ${requiresApproval}`
|
||||
);
|
||||
|
||||
// Get provider for this model
|
||||
const provider = ProviderFactory.getProviderForModel(finalModel);
|
||||
|
||||
console.log(`[AutoMode] Using provider "${provider.getName()}" for model "${finalModel}"`);
|
||||
logger.info(`Using provider "${provider.getName()}" for model "${finalModel}"`);
|
||||
|
||||
// Build prompt content with images using utility
|
||||
const { content: promptContent } = await buildPromptWithImages(
|
||||
@@ -2087,8 +2079,8 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
|
||||
|
||||
// Debug: Log if system prompt is provided
|
||||
if (options?.systemPrompt) {
|
||||
console.log(
|
||||
`[AutoMode] System prompt provided (${options.systemPrompt.length} chars), first 200 chars:\n${options.systemPrompt.substring(0, 200)}...`
|
||||
logger.info(
|
||||
`System prompt provided (${options.systemPrompt.length} chars), first 200 chars:\n${options.systemPrompt.substring(0, 200)}...`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2109,9 +2101,9 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
|
||||
};
|
||||
|
||||
// Execute via provider
|
||||
console.log(`[AutoMode] Starting stream for feature ${featureId}...`);
|
||||
logger.info(`Starting stream for feature ${featureId}...`);
|
||||
const stream = provider.executeQuery(executeOptions);
|
||||
console.log(`[AutoMode] Stream created, starting to iterate...`);
|
||||
logger.info(`Stream created, starting to iterate...`);
|
||||
// Initialize with previous content if this is a follow-up, with a separator
|
||||
let responseText = previousContent
|
||||
? `${previousContent}\n\n---\n\n## Follow-up Session\n\n`
|
||||
@@ -2157,7 +2149,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
|
||||
await secureFs.appendFile(rawOutputPath, rawOutputLines.join('\n') + '\n');
|
||||
rawOutputLines = []; // Clear after writing
|
||||
} catch (error) {
|
||||
console.error(`[AutoMode] Failed to write raw output for ${featureId}:`, error);
|
||||
logger.error(`Failed to write raw output for ${featureId}:`, error);
|
||||
}
|
||||
}, WRITE_DEBOUNCE_MS);
|
||||
} catch {
|
||||
@@ -2172,7 +2164,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
|
||||
await secureFs.writeFile(outputPath, responseText);
|
||||
} catch (error) {
|
||||
// Log but don't crash - file write errors shouldn't stop execution
|
||||
console.error(`[AutoMode] Failed to write agent output for ${featureId}:`, error);
|
||||
logger.error(`Failed to write agent output for ${featureId}:`, error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2190,7 +2182,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
|
||||
// Log raw stream event for debugging
|
||||
appendRawEvent(msg);
|
||||
|
||||
console.log(`[AutoMode] Stream message received:`, msg.type, msg.subtype || '');
|
||||
logger.info(`Stream message received:`, msg.type, msg.subtype || '');
|
||||
if (msg.type === 'assistant' && msg.message?.content) {
|
||||
for (const block of msg.message.content) {
|
||||
if (block.type === 'text') {
|
||||
@@ -2255,11 +2247,9 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
|
||||
let parsedTasks = parseTasksFromSpec(planContent);
|
||||
const tasksTotal = parsedTasks.length;
|
||||
|
||||
console.log(
|
||||
`[AutoMode] Parsed ${tasksTotal} tasks from spec for feature ${featureId}`
|
||||
);
|
||||
logger.info(`Parsed ${tasksTotal} tasks from spec for feature ${featureId}`);
|
||||
if (parsedTasks.length > 0) {
|
||||
console.log(`[AutoMode] Tasks: ${parsedTasks.map((t) => t.id).join(', ')}`);
|
||||
logger.info(`Tasks: ${parsedTasks.map((t) => t.id).join(', ')}`);
|
||||
}
|
||||
|
||||
// Update planSpec status to 'generated' and save content with parsed tasks
|
||||
@@ -2288,8 +2278,8 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
|
||||
let planApproved = false;
|
||||
|
||||
while (!planApproved) {
|
||||
console.log(
|
||||
`[AutoMode] Spec v${planVersion} generated for feature ${featureId}, waiting for approval`
|
||||
logger.info(
|
||||
`Spec v${planVersion} generated for feature ${featureId}, waiting for approval`
|
||||
);
|
||||
|
||||
// CRITICAL: Register pending approval BEFORE emitting event
|
||||
@@ -2310,9 +2300,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
|
||||
|
||||
if (approvalResult.approved) {
|
||||
// User approved the plan
|
||||
console.log(
|
||||
`[AutoMode] Plan v${planVersion} approved for feature ${featureId}`
|
||||
);
|
||||
logger.info(`Plan v${planVersion} approved for feature ${featureId}`);
|
||||
planApproved = true;
|
||||
|
||||
// If user provided edits, use the edited version
|
||||
@@ -2344,15 +2332,15 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
|
||||
|
||||
if (!hasFeedback && !hasEdits) {
|
||||
// No feedback or edits = explicit cancel
|
||||
console.log(
|
||||
`[AutoMode] Plan rejected without feedback for feature ${featureId}, cancelling`
|
||||
logger.info(
|
||||
`Plan rejected without feedback for feature ${featureId}, cancelling`
|
||||
);
|
||||
throw new Error('Plan cancelled by user');
|
||||
}
|
||||
|
||||
// User wants revisions - regenerate the plan
|
||||
console.log(
|
||||
`[AutoMode] Plan v${planVersion} rejected with feedback for feature ${featureId}, regenerating...`
|
||||
logger.info(
|
||||
`Plan v${planVersion} rejected with feedback for feature ${featureId}, regenerating...`
|
||||
);
|
||||
planVersion++;
|
||||
|
||||
@@ -2429,7 +2417,7 @@ After generating the revised spec, output:
|
||||
|
||||
// Re-parse tasks from revised plan
|
||||
const revisedTasks = parseTasksFromSpec(currentPlanContent);
|
||||
console.log(`[AutoMode] Revised plan has ${revisedTasks.length} tasks`);
|
||||
logger.info(`Revised plan has ${revisedTasks.length} tasks`);
|
||||
|
||||
// Update planSpec with revised content
|
||||
await this.updateFeaturePlanSpec(projectPath, featureId, {
|
||||
@@ -2455,8 +2443,8 @@ After generating the revised spec, output:
|
||||
}
|
||||
} else {
|
||||
// Auto-approve: requirePlanApproval is false, just continue without pausing
|
||||
console.log(
|
||||
`[AutoMode] Spec generated for feature ${featureId}, auto-approving (requirePlanApproval=false)`
|
||||
logger.info(
|
||||
`Spec generated for feature ${featureId}, auto-approving (requirePlanApproval=false)`
|
||||
);
|
||||
|
||||
// Emit info event for frontend
|
||||
@@ -2472,9 +2460,7 @@ After generating the revised spec, output:
|
||||
|
||||
// CRITICAL: After approval, we need to make a second call to continue implementation
|
||||
// The agent is waiting for "approved" - we need to send it and continue
|
||||
console.log(
|
||||
`[AutoMode] Making continuation call after plan approval for feature ${featureId}`
|
||||
);
|
||||
logger.info(`Making continuation call after plan approval for feature ${featureId}`);
|
||||
|
||||
// Update planSpec status to approved (handles both manual and auto-approval paths)
|
||||
await this.updateFeaturePlanSpec(projectPath, featureId, {
|
||||
@@ -2489,8 +2475,8 @@ After generating the revised spec, output:
|
||||
// ========================================
|
||||
|
||||
if (parsedTasks.length > 0) {
|
||||
console.log(
|
||||
`[AutoMode] Starting multi-agent execution: ${parsedTasks.length} tasks for feature ${featureId}`
|
||||
logger.info(
|
||||
`Starting multi-agent execution: ${parsedTasks.length} tasks for feature ${featureId}`
|
||||
);
|
||||
|
||||
// Execute each task with a separate agent
|
||||
@@ -2503,7 +2489,7 @@ After generating the revised spec, output:
|
||||
}
|
||||
|
||||
// Emit task started
|
||||
console.log(`[AutoMode] Starting task ${task.id}: ${task.description}`);
|
||||
logger.info(`Starting task ${task.id}: ${task.description}`);
|
||||
this.emitAutoModeEvent('auto_mode_task_started', {
|
||||
featureId,
|
||||
projectPath,
|
||||
@@ -2570,7 +2556,7 @@ After generating the revised spec, output:
|
||||
}
|
||||
|
||||
// Emit task completed
|
||||
console.log(`[AutoMode] Task ${task.id} completed for feature ${featureId}`);
|
||||
logger.info(`Task ${task.id} completed for feature ${featureId}`);
|
||||
this.emitAutoModeEvent('auto_mode_task_complete', {
|
||||
featureId,
|
||||
projectPath,
|
||||
@@ -2601,13 +2587,11 @@ After generating the revised spec, output:
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[AutoMode] All ${parsedTasks.length} tasks completed for feature ${featureId}`
|
||||
);
|
||||
logger.info(`All ${parsedTasks.length} tasks completed for feature ${featureId}`);
|
||||
} else {
|
||||
// No parsed tasks - fall back to single-agent execution
|
||||
console.log(
|
||||
`[AutoMode] No parsed tasks, using single-agent execution for feature ${featureId}`
|
||||
logger.info(
|
||||
`No parsed tasks, using single-agent execution for feature ${featureId}`
|
||||
);
|
||||
|
||||
const continuationPrompt = `The plan/specification has been approved. Now implement it.
|
||||
@@ -2657,15 +2641,15 @@ Implement all the changes described in the plan above.`;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[AutoMode] Implementation completed for feature ${featureId}`);
|
||||
logger.info(`Implementation completed for feature ${featureId}`);
|
||||
// Exit the original stream loop since continuation is done
|
||||
break streamLoop;
|
||||
}
|
||||
|
||||
// Only emit progress for non-marker text (marker was already handled above)
|
||||
if (!specDetected) {
|
||||
console.log(
|
||||
`[AutoMode] Emitting progress event for ${featureId}, content length: ${block.text?.length || 0}`
|
||||
logger.info(
|
||||
`Emitting progress event for ${featureId}, content length: ${block.text?.length || 0}`
|
||||
);
|
||||
this.emitAutoModeEvent('auto_mode_progress', {
|
||||
featureId,
|
||||
@@ -2719,7 +2703,7 @@ Implement all the changes described in the plan above.`;
|
||||
await secureFs.mkdir(path.dirname(rawOutputPath), { recursive: true });
|
||||
await secureFs.appendFile(rawOutputPath, rawOutputLines.join('\n') + '\n');
|
||||
} catch (error) {
|
||||
console.error(`[AutoMode] Failed to write final raw output for ${featureId}:`, error);
|
||||
logger.error(`Failed to write final raw output for ${featureId}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user