refactor(01-03): wire TypedEventBus into AutoModeService

- Import TypedEventBus into AutoModeService
- Add eventBus property initialized via constructor injection
- Remove private emitAutoModeEvent method (now in TypedEventBus)
- Update all 66 emitAutoModeEvent calls to use this.eventBus
- Constructor accepts optional TypedEventBus for testing
This commit is contained in:
Shirone
2026-01-27 14:49:44 +01:00
parent 2a77407aaa
commit 93a6c32c32

View File

@@ -68,6 +68,7 @@ import {
type RunningFeature,
type GetCurrentBranchFn,
} from './concurrency-manager.js';
import { TypedEventBus } from './typed-event-bus.js';
import type { SettingsService } from './settings-service.js';
import { pipelineService, PipelineService } from './pipeline-service.js';
import {
@@ -421,6 +422,7 @@ const FAILURE_WINDOW_MS = 60000; // Failures within 1 minute count as consecutiv
export class AutoModeService {
private events: EventEmitter;
private eventBus: TypedEventBus;
private concurrencyManager: ConcurrencyManager;
private autoLoop: AutoLoopState | null = null;
private featureLoader = new FeatureLoader();
@@ -441,9 +443,11 @@ export class AutoModeService {
constructor(
events: EventEmitter,
settingsService?: SettingsService,
concurrencyManager?: ConcurrencyManager
concurrencyManager?: ConcurrencyManager,
eventBus?: TypedEventBus
) {
this.events = events;
this.eventBus = eventBus ?? new TypedEventBus(events);
this.settingsService = settingsService ?? null;
// Pass the getCurrentBranch function to ConcurrencyManager for worktree counting
this.concurrencyManager = concurrencyManager ?? new ConcurrencyManager(getCurrentBranch);
@@ -653,7 +657,7 @@ export class AutoModeService {
);
// Emit event to notify UI
this.emitAutoModeEvent('auto_mode_paused_failures', {
this.eventBus.emitAutoModeEvent('auto_mode_paused_failures', {
message:
failureCount >= CONSECUTIVE_FAILURE_THRESHOLD
? `Auto Mode paused: ${failureCount} consecutive failures detected. This may indicate a quota limit or API issue. Please check your usage and try again.`
@@ -683,7 +687,7 @@ export class AutoModeService {
);
// Emit event to notify UI
this.emitAutoModeEvent('auto_mode_paused_failures', {
this.eventBus.emitAutoModeEvent('auto_mode_paused_failures', {
message:
failureCount >= CONSECUTIVE_FAILURE_THRESHOLD
? `Auto Mode paused: ${failureCount} consecutive failures detected. This may indicate a quota limit or API issue. Please check your usage and try again.`
@@ -839,7 +843,7 @@ export class AutoModeService {
// Don't fail startup due to reset errors
}
this.emitAutoModeEvent('auto_mode_started', {
this.eventBus.emitAutoModeEvent('auto_mode_started', {
message: `Auto mode started with max ${resolvedMaxConcurrency} concurrent features`,
projectPath,
branchName,
@@ -854,7 +858,7 @@ export class AutoModeService {
const worktreeDescErr = branchName ? `worktree ${branchName}` : 'main worktree';
logger.error(`Loop error for ${worktreeDescErr} in ${projectPath}:`, error);
const errorInfo = classifyError(error);
this.emitAutoModeEvent('auto_mode_error', {
this.eventBus.emitAutoModeEvent('auto_mode_error', {
error: errorInfo.message,
errorType: errorInfo.type,
projectPath,
@@ -909,7 +913,7 @@ export class AutoModeService {
if (pendingFeatures.length === 0) {
// Emit idle event only once when backlog is empty AND no features are running
if (projectRunningCount === 0 && !projectState.hasEmittedIdleEvent) {
this.emitAutoModeEvent('auto_mode_idle', {
this.eventBus.emitAutoModeEvent('auto_mode_idle', {
message: 'No pending features - auto mode idle',
projectPath,
branchName,
@@ -1012,7 +1016,7 @@ export class AutoModeService {
// Emit stop event
if (wasRunning) {
this.emitAutoModeEvent('auto_mode_stopped', {
this.eventBus.emitAutoModeEvent('auto_mode_stopped', {
message: 'Auto mode stopped',
projectPath,
branchName,
@@ -1115,7 +1119,7 @@ export class AutoModeService {
branchName: null,
};
this.emitAutoModeEvent('auto_mode_started', {
this.eventBus.emitAutoModeEvent('auto_mode_started', {
message: `Auto mode started with max ${maxConcurrency} concurrent features`,
projectPath,
});
@@ -1129,7 +1133,7 @@ export class AutoModeService {
this.runAutoLoop().catch((error) => {
logger.error('Loop error:', error);
const errorInfo = classifyError(error);
this.emitAutoModeEvent('auto_mode_error', {
this.eventBus.emitAutoModeEvent('auto_mode_error', {
error: errorInfo.message,
errorType: errorInfo.type,
projectPath,
@@ -1161,7 +1165,7 @@ export class AutoModeService {
// Emit idle event only once when backlog is empty AND no features are running
const runningCount = this.concurrencyManager.getAllRunning().length;
if (runningCount === 0 && !this.hasEmittedIdleEvent) {
this.emitAutoModeEvent('auto_mode_idle', {
this.eventBus.emitAutoModeEvent('auto_mode_idle', {
message: 'No pending features - auto mode idle',
projectPath: this.config!.projectPath,
});
@@ -1225,7 +1229,7 @@ export class AutoModeService {
// Emit stop event immediately when user explicitly stops
if (wasRunning) {
this.emitAutoModeEvent('auto_mode_stopped', {
this.eventBus.emitAutoModeEvent('auto_mode_stopped', {
message: 'Auto mode stopped',
projectPath,
});
@@ -1390,7 +1394,7 @@ export class AutoModeService {
await this.updateFeatureStatus(projectPath, featureId, 'in_progress');
// Emit feature start event AFTER status update so frontend sees correct status
this.emitAutoModeEvent('auto_mode_feature_start', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_start', {
featureId,
projectPath,
branchName: feature.branchName ?? null,
@@ -1442,7 +1446,7 @@ export class AutoModeService {
// Emit planning mode info
if (feature.planningMode && feature.planningMode !== 'skip') {
this.emitAutoModeEvent('planning_started', {
this.eventBus.emitAutoModeEvent('planning_started', {
featureId: feature.id,
mode: feature.planningMode,
message: `Starting ${feature.planningMode} planning phase`,
@@ -1556,7 +1560,7 @@ export class AutoModeService {
console.warn('[AutoMode] Failed to record learnings:', learningError);
}
this.emitAutoModeEvent('auto_mode_feature_complete', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_complete', {
featureId,
featureName: feature.title,
branchName: feature.branchName ?? null,
@@ -1572,7 +1576,7 @@ export class AutoModeService {
const errorInfo = classifyError(error);
if (errorInfo.isAbort) {
this.emitAutoModeEvent('auto_mode_feature_complete', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_complete', {
featureId,
featureName: feature?.title,
branchName: feature?.branchName ?? null,
@@ -1583,7 +1587,7 @@ export class AutoModeService {
} else {
logger.error(`Feature ${featureId} failed:`, error);
await this.updateFeatureStatus(projectPath, featureId, 'backlog');
this.emitAutoModeEvent('auto_mode_error', {
this.eventBus.emitAutoModeEvent('auto_mode_error', {
featureId,
featureName: feature?.title,
branchName: feature?.branchName ?? null,
@@ -1666,14 +1670,14 @@ export class AutoModeService {
// Update feature status to current pipeline step
await this.updateFeatureStatus(projectPath, featureId, pipelineStatus);
this.emitAutoModeEvent('auto_mode_progress', {
this.eventBus.emitAutoModeEvent('auto_mode_progress', {
featureId,
branchName: feature.branchName ?? null,
content: `Starting pipeline step ${i + 1}/${steps.length}: ${step.name}`,
projectPath,
});
this.emitAutoModeEvent('pipeline_step_started', {
this.eventBus.emitAutoModeEvent('pipeline_step_started', {
featureId,
stepId: step.id,
stepName: step.name,
@@ -1720,7 +1724,7 @@ export class AutoModeService {
// No context update
}
this.emitAutoModeEvent('pipeline_step_complete', {
this.eventBus.emitAutoModeEvent('pipeline_step_complete', {
featureId,
stepId: step.id,
stepName: step.name,
@@ -1882,7 +1886,7 @@ Complete the pipeline step instructions above. Review the previous work and appl
);
// Emit event for UI notification
this.emitAutoModeEvent('auto_mode_feature_resuming', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_resuming', {
featureId,
featureName: feature.title,
projectPath,
@@ -1900,7 +1904,7 @@ Complete the pipeline step instructions above. Review the previous work and appl
);
// Emit event for UI notification
this.emitAutoModeEvent('auto_mode_feature_resuming', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_resuming', {
featureId,
featureName: feature.title,
projectPath,
@@ -1978,7 +1982,7 @@ Complete the pipeline step instructions above. Review the previous work and appl
await this.updateFeatureStatus(projectPath, featureId, finalStatus);
this.emitAutoModeEvent('auto_mode_feature_complete', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_complete', {
featureId,
featureName: feature.title,
branchName: feature.branchName ?? null,
@@ -2064,7 +2068,7 @@ Complete the pipeline step instructions above. Review the previous work and appl
// If next status is not a pipeline step, feature is done
if (!pipelineService.isPipelineStatus(nextStatus)) {
await this.updateFeatureStatus(projectPath, featureId, nextStatus);
this.emitAutoModeEvent('auto_mode_feature_complete', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_complete', {
featureId,
featureName: feature.title,
branchName: feature.branchName ?? null,
@@ -2093,7 +2097,7 @@ Complete the pipeline step instructions above. Review the previous work and appl
if (stepsToExecute.length === 0) {
const finalStatus = feature.skipTests ? 'waiting_approval' : 'verified';
await this.updateFeatureStatus(projectPath, featureId, finalStatus);
this.emitAutoModeEvent('auto_mode_feature_complete', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_complete', {
featureId,
featureName: feature.title,
branchName: feature.branchName ?? null,
@@ -2145,7 +2149,7 @@ Complete the pipeline step instructions above. Review the previous work and appl
runningEntry.branchName = branchName ?? null;
// Emit resume event
this.emitAutoModeEvent('auto_mode_feature_start', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_start', {
featureId,
projectPath,
branchName: branchName ?? null,
@@ -2156,7 +2160,7 @@ Complete the pipeline step instructions above. Review the previous work and appl
},
});
this.emitAutoModeEvent('auto_mode_progress', {
this.eventBus.emitAutoModeEvent('auto_mode_progress', {
featureId,
projectPath,
branchName: branchName ?? null,
@@ -2187,7 +2191,7 @@ Complete the pipeline step instructions above. Review the previous work and appl
logger.info(`Pipeline resume completed successfully for feature ${featureId}`);
this.emitAutoModeEvent('auto_mode_feature_complete', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_complete', {
featureId,
featureName: feature.title,
branchName: feature.branchName ?? null,
@@ -2199,7 +2203,7 @@ Complete the pipeline step instructions above. Review the previous work and appl
const errorInfo = classifyError(error);
if (errorInfo.isAbort) {
this.emitAutoModeEvent('auto_mode_feature_complete', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_complete', {
featureId,
featureName: feature.title,
branchName: feature.branchName ?? null,
@@ -2210,7 +2214,7 @@ Complete the pipeline step instructions above. Review the previous work and appl
} else {
logger.error(`Pipeline resume failed for feature ${featureId}:`, error);
await this.updateFeatureStatus(projectPath, featureId, 'backlog');
this.emitAutoModeEvent('auto_mode_error', {
this.eventBus.emitAutoModeEvent('auto_mode_error', {
featureId,
featureName: feature.title,
branchName: feature.branchName ?? null,
@@ -2335,7 +2339,7 @@ Address the follow-up instructions above. Review the previous work and make the
await this.updateFeatureStatus(projectPath, featureId, 'in_progress');
// Emit feature start event AFTER status update so frontend sees correct status
this.emitAutoModeEvent('auto_mode_feature_start', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_start', {
featureId,
projectPath,
branchName,
@@ -2439,7 +2443,7 @@ Address the follow-up instructions above. Review the previous work and make the
// Record success to reset consecutive failure tracking
this.recordSuccess();
this.emitAutoModeEvent('auto_mode_feature_complete', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_complete', {
featureId,
featureName: feature?.title,
branchName: branchName ?? null,
@@ -2452,7 +2456,7 @@ Address the follow-up instructions above. Review the previous work and make the
} catch (error) {
const errorInfo = classifyError(error);
if (!errorInfo.isCancellation) {
this.emitAutoModeEvent('auto_mode_error', {
this.eventBus.emitAutoModeEvent('auto_mode_error', {
featureId,
featureName: feature?.title,
branchName: branchName ?? null,
@@ -2532,7 +2536,7 @@ Address the follow-up instructions above. Review the previous work and make the
}
}
this.emitAutoModeEvent('auto_mode_feature_complete', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_complete', {
featureId,
featureName: feature?.title,
branchName: feature?.branchName ?? null,
@@ -2612,7 +2616,7 @@ Address the follow-up instructions above. Review the previous work and make the
cwd: workDir,
});
this.emitAutoModeEvent('auto_mode_feature_complete', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_complete', {
featureId,
featureName: feature?.title,
branchName: feature?.branchName ?? null,
@@ -2651,7 +2655,7 @@ Address the follow-up instructions above. Review the previous work and make the
const abortController = new AbortController();
const analysisFeatureId = `analysis-${Date.now()}`;
this.emitAutoModeEvent('auto_mode_feature_start', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_start', {
featureId: analysisFeatureId,
projectPath,
branchName: null, // Project analysis is not worktree-specific
@@ -2732,7 +2736,7 @@ Format your response as a structured markdown document.`;
for (const block of msg.message.content) {
if (block.type === 'text') {
analysisResult = block.text || '';
this.emitAutoModeEvent('auto_mode_progress', {
this.eventBus.emitAutoModeEvent('auto_mode_progress', {
featureId: analysisFeatureId,
content: block.text,
projectPath,
@@ -2750,7 +2754,7 @@ Format your response as a structured markdown document.`;
await secureFs.mkdir(automakerDir, { recursive: true });
await secureFs.writeFile(analysisPath, analysisResult);
this.emitAutoModeEvent('auto_mode_feature_complete', {
this.eventBus.emitAutoModeEvent('auto_mode_feature_complete', {
featureId: analysisFeatureId,
featureName: 'Project Analysis',
branchName: null, // Project analysis is not worktree-specific
@@ -2760,7 +2764,7 @@ Format your response as a structured markdown document.`;
});
} catch (error) {
const errorInfo = classifyError(error);
this.emitAutoModeEvent('auto_mode_error', {
this.eventBus.emitAutoModeEvent('auto_mode_error', {
featureId: analysisFeatureId,
featureName: 'Project Analysis',
branchName: null, // Project analysis is not worktree-specific
@@ -3021,7 +3025,7 @@ Format your response as a structured markdown document.`;
await this.updateFeatureStatus(projectPathFromClient, featureId, 'backlog');
this.emitAutoModeEvent('plan_rejected', {
this.eventBus.emitAutoModeEvent('plan_rejected', {
featureId,
projectPath: projectPathFromClient,
feedback,
@@ -3055,7 +3059,7 @@ Format your response as a structured markdown document.`;
// If rejected with feedback, we can store it for the user to see
if (!approved && feedback) {
// Emit event so client knows the rejection reason
this.emitAutoModeEvent('plan_rejected', {
this.eventBus.emitAutoModeEvent('plan_rejected', {
featureId,
projectPath,
feedback,
@@ -3435,7 +3439,7 @@ Format your response as a structured markdown document.`;
await atomicWriteJson(featurePath, feature, { backupCount: DEFAULT_BACKUP_COUNT });
this.emitAutoModeEvent('auto_mode_summary', {
this.eventBus.emitAutoModeEvent('auto_mode_summary', {
featureId,
projectPath,
summary,
@@ -3483,7 +3487,7 @@ Format your response as a structured markdown document.`;
await atomicWriteJson(featurePath, feature, { backupCount: DEFAULT_BACKUP_COUNT });
// Emit event for UI update
this.emitAutoModeEvent('auto_mode_task_status', {
this.eventBus.emitAutoModeEvent('auto_mode_task_status', {
featureId,
projectPath,
taskId,
@@ -3938,14 +3942,14 @@ You can use the Read tool to view these images at any time during implementation
await this.sleep(500);
// Emit mock progress events to simulate agent activity
this.emitAutoModeEvent('auto_mode_progress', {
this.eventBus.emitAutoModeEvent('auto_mode_progress', {
featureId,
content: 'Mock agent: Analyzing the codebase...',
});
await this.sleep(300);
this.emitAutoModeEvent('auto_mode_progress', {
this.eventBus.emitAutoModeEvent('auto_mode_progress', {
featureId,
content: 'Mock agent: Implementing the feature...',
});
@@ -3956,7 +3960,7 @@ You can use the Read tool to view these images at any time during implementation
const mockFilePath = path.join(workDir, 'yellow.txt');
await secureFs.writeFile(mockFilePath, 'yellow');
this.emitAutoModeEvent('auto_mode_progress', {
this.eventBus.emitAutoModeEvent('auto_mode_progress', {
featureId,
content: "Mock agent: Created yellow.txt file with content 'yellow'",
});
@@ -4208,7 +4212,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
// Emit task started
logger.info(`Starting task ${task.id}: ${task.description}`);
this.emitAutoModeEvent('auto_mode_task_started', {
this.eventBus.emitAutoModeEvent('auto_mode_task_started', {
featureId,
projectPath,
branchName,
@@ -4257,7 +4261,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
const text = block.text || '';
taskOutput += text;
responseText += text;
this.emitAutoModeEvent('auto_mode_progress', {
this.eventBus.emitAutoModeEvent('auto_mode_progress', {
featureId,
branchName,
content: text,
@@ -4279,7 +4283,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
}
}
} else if (block.type === 'tool_use') {
this.emitAutoModeEvent('auto_mode_tool', {
this.eventBus.emitAutoModeEvent('auto_mode_tool', {
featureId,
branchName,
tool: block.name,
@@ -4302,7 +4306,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
// Emit task completed
logger.info(`Task ${task.id} completed for feature ${featureId}`);
this.emitAutoModeEvent('auto_mode_task_complete', {
this.eventBus.emitAutoModeEvent('auto_mode_task_complete', {
featureId,
projectPath,
branchName,
@@ -4466,7 +4470,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
const approvalPromise = this.waitForPlanApproval(featureId, projectPath);
// Emit plan_approval_required event
this.emitAutoModeEvent('plan_approval_required', {
this.eventBus.emitAutoModeEvent('plan_approval_required', {
featureId,
projectPath,
branchName,
@@ -4498,7 +4502,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
userFeedback = approvalResult.feedback;
// Emit approval event
this.emitAutoModeEvent('plan_approved', {
this.eventBus.emitAutoModeEvent('plan_approved', {
featureId,
projectPath,
branchName,
@@ -4527,7 +4531,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
planVersion++;
// Emit revision event
this.emitAutoModeEvent('plan_revision_requested', {
this.eventBus.emitAutoModeEvent('plan_revision_requested', {
featureId,
projectPath,
branchName,
@@ -4610,7 +4614,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
for (const block of msg.message.content) {
if (block.type === 'text') {
revisionText += block.text || '';
this.emitAutoModeEvent('auto_mode_progress', {
this.eventBus.emitAutoModeEvent('auto_mode_progress', {
featureId,
content: block.text,
});
@@ -4645,7 +4649,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
`This will cause fallback to single-agent execution. ` +
`The AI may have omitted the required \`\`\`tasks block.`
);
this.emitAutoModeEvent('plan_revision_warning', {
this.eventBus.emitAutoModeEvent('plan_revision_warning', {
featureId,
projectPath,
branchName,
@@ -4684,7 +4688,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
);
// Emit info event for frontend
this.emitAutoModeEvent('plan_auto_approved', {
this.eventBus.emitAutoModeEvent('plan_auto_approved', {
featureId,
projectPath,
branchName,
@@ -4744,7 +4748,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
// Emit task started
logger.info(`Starting task ${task.id}: ${task.description}`);
this.emitAutoModeEvent('auto_mode_task_started', {
this.eventBus.emitAutoModeEvent('auto_mode_task_started', {
featureId,
projectPath,
branchName,
@@ -4794,7 +4798,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
const text = block.text || '';
taskOutput += text;
responseText += text;
this.emitAutoModeEvent('auto_mode_progress', {
this.eventBus.emitAutoModeEvent('auto_mode_progress', {
featureId,
branchName,
content: text,
@@ -4813,7 +4817,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
startTaskId,
'in_progress'
);
this.emitAutoModeEvent('auto_mode_task_started', {
this.eventBus.emitAutoModeEvent('auto_mode_task_started', {
featureId,
projectPath,
branchName,
@@ -4845,7 +4849,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
const phaseNumber = detectPhaseCompleteMarker(text);
if (phaseNumber !== null) {
logger.info(`[PHASE_COMPLETE] detected for Phase ${phaseNumber}`);
this.emitAutoModeEvent('auto_mode_phase_complete', {
this.eventBus.emitAutoModeEvent('auto_mode_phase_complete', {
featureId,
projectPath,
branchName,
@@ -4853,7 +4857,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
});
}
} else if (block.type === 'tool_use') {
this.emitAutoModeEvent('auto_mode_tool', {
this.eventBus.emitAutoModeEvent('auto_mode_tool', {
featureId,
branchName,
tool: block.name,
@@ -4877,7 +4881,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
// Emit task completed
logger.info(`Task ${task.id} completed for feature ${featureId}`);
this.emitAutoModeEvent('auto_mode_task_complete', {
this.eventBus.emitAutoModeEvent('auto_mode_task_complete', {
featureId,
projectPath,
branchName,
@@ -4898,7 +4902,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
// Phase changed, emit phase complete
const phaseMatch = task.phase.match(/Phase\s*(\d+)/i);
if (phaseMatch) {
this.emitAutoModeEvent('auto_mode_phase_complete', {
this.eventBus.emitAutoModeEvent('auto_mode_phase_complete', {
featureId,
projectPath,
branchName,
@@ -4949,13 +4953,13 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
for (const block of msg.message.content) {
if (block.type === 'text') {
responseText += block.text || '';
this.emitAutoModeEvent('auto_mode_progress', {
this.eventBus.emitAutoModeEvent('auto_mode_progress', {
featureId,
branchName,
content: block.text,
});
} else if (block.type === 'tool_use') {
this.emitAutoModeEvent('auto_mode_tool', {
this.eventBus.emitAutoModeEvent('auto_mode_tool', {
featureId,
branchName,
tool: block.name,
@@ -4988,7 +4992,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
logger.info(
`Emitting progress event for ${featureId}, content length: ${block.text?.length || 0}`
);
this.emitAutoModeEvent('auto_mode_progress', {
this.eventBus.emitAutoModeEvent('auto_mode_progress', {
featureId,
branchName,
content: block.text,
@@ -4996,7 +5000,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
}
} else if (block.type === 'tool_use') {
// Emit event for real-time UI
this.emitAutoModeEvent('auto_mode_tool', {
this.eventBus.emitAutoModeEvent('auto_mode_tool', {
featureId,
branchName,
tool: block.name,
@@ -5234,19 +5238,6 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
return prompt;
}
/**
* Emit an auto-mode event wrapped in the correct format for the client.
* All auto-mode events are sent as type "auto-mode:event" with the actual
* event type and data in the payload.
*/
private emitAutoModeEvent(eventType: string, data: Record<string, unknown>): void {
// Wrap the event in auto-mode:event format expected by the client
this.events.emit('auto-mode:event', {
type: eventType,
...data,
});
}
private sleep(ms: number, signal?: AbortSignal): Promise<void> {
return new Promise((resolve, reject) => {
const timeout = setTimeout(resolve, ms);
@@ -5410,7 +5401,7 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
);
// Emit event to notify UI with context information
this.emitAutoModeEvent('auto_mode_resuming_features', {
this.eventBus.emitAutoModeEvent('auto_mode_resuming_features', {
message: `Resuming ${allInterruptedFeatures.length} interrupted feature(s) after server restart`,
projectPath,
featureIds: allInterruptedFeatures.map((f) => f.id),