mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-03-19 10:43:08 +00:00
refactor(06-04): delete auto-mode-service.ts monolith
- Delete the 2705-line auto-mode-service.ts monolith - Create AutoModeServiceCompat as compatibility layer for routes - Create GlobalAutoModeService for cross-project operations - Update all routes to use AutoModeServiceCompat type - Add SharedServices interface for state sharing across facades - Add getActiveProjects/getActiveWorktrees to AutoLoopCoordinator - Delete obsolete monolith test files Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,12 @@
|
||||
/**
|
||||
* Auto Mode routes - HTTP API for autonomous feature implementation
|
||||
*
|
||||
* Uses the AutoModeService for real feature execution with Claude Agent SDK.
|
||||
* Supports optional facadeFactory for per-project facade creation during migration.
|
||||
* Uses AutoModeServiceCompat which provides the old interface while
|
||||
* delegating to GlobalAutoModeService and per-project facades.
|
||||
*/
|
||||
|
||||
import { Router } from 'express';
|
||||
import type { AutoModeService } from '../../services/auto-mode-service.js';
|
||||
import type { AutoModeServiceFacade } from '../../services/auto-mode/index.js';
|
||||
import type { AutoModeServiceCompat } from '../../services/auto-mode/index.js';
|
||||
import { validatePathParams } from '../../middleware/validate-paths.js';
|
||||
import { createStopFeatureHandler } from './routes/stop-feature.js';
|
||||
import { createStatusHandler } from './routes/status.js';
|
||||
@@ -24,81 +23,63 @@ import { createApprovePlanHandler } from './routes/approve-plan.js';
|
||||
import { createResumeInterruptedHandler } from './routes/resume-interrupted.js';
|
||||
|
||||
/**
|
||||
* Create auto-mode routes with optional facade factory.
|
||||
* Create auto-mode routes.
|
||||
*
|
||||
* @param autoModeService - The AutoModeService instance (for backward compatibility)
|
||||
* @param facadeFactory - Optional factory for creating per-project facades
|
||||
* @param autoModeService - AutoModeServiceCompat instance
|
||||
*/
|
||||
export function createAutoModeRoutes(
|
||||
autoModeService: AutoModeService,
|
||||
facadeFactory?: (projectPath: string) => AutoModeServiceFacade
|
||||
): Router {
|
||||
export function createAutoModeRoutes(autoModeService: AutoModeServiceCompat): Router {
|
||||
const router = Router();
|
||||
|
||||
// Auto loop control routes
|
||||
router.post(
|
||||
'/start',
|
||||
validatePathParams('projectPath'),
|
||||
createStartHandler(autoModeService, facadeFactory)
|
||||
);
|
||||
router.post(
|
||||
'/stop',
|
||||
validatePathParams('projectPath'),
|
||||
createStopHandler(autoModeService, facadeFactory)
|
||||
);
|
||||
router.post('/start', validatePathParams('projectPath'), createStartHandler(autoModeService));
|
||||
router.post('/stop', validatePathParams('projectPath'), createStopHandler(autoModeService));
|
||||
|
||||
// Note: stop-feature doesn't have projectPath, so we pass undefined for facade.
|
||||
// When we fully migrate, we can update stop-feature to use a different approach.
|
||||
router.post('/stop-feature', createStopFeatureHandler(autoModeService));
|
||||
router.post(
|
||||
'/status',
|
||||
validatePathParams('projectPath?'),
|
||||
createStatusHandler(autoModeService, facadeFactory)
|
||||
);
|
||||
router.post('/status', validatePathParams('projectPath?'), createStatusHandler(autoModeService));
|
||||
router.post(
|
||||
'/run-feature',
|
||||
validatePathParams('projectPath'),
|
||||
createRunFeatureHandler(autoModeService, facadeFactory)
|
||||
createRunFeatureHandler(autoModeService)
|
||||
);
|
||||
router.post(
|
||||
'/verify-feature',
|
||||
validatePathParams('projectPath'),
|
||||
createVerifyFeatureHandler(autoModeService, facadeFactory)
|
||||
createVerifyFeatureHandler(autoModeService)
|
||||
);
|
||||
router.post(
|
||||
'/resume-feature',
|
||||
validatePathParams('projectPath'),
|
||||
createResumeFeatureHandler(autoModeService, facadeFactory)
|
||||
createResumeFeatureHandler(autoModeService)
|
||||
);
|
||||
router.post(
|
||||
'/context-exists',
|
||||
validatePathParams('projectPath'),
|
||||
createContextExistsHandler(autoModeService, facadeFactory)
|
||||
createContextExistsHandler(autoModeService)
|
||||
);
|
||||
router.post(
|
||||
'/analyze-project',
|
||||
validatePathParams('projectPath'),
|
||||
createAnalyzeProjectHandler(autoModeService, facadeFactory)
|
||||
createAnalyzeProjectHandler(autoModeService)
|
||||
);
|
||||
router.post(
|
||||
'/follow-up-feature',
|
||||
validatePathParams('projectPath', 'imagePaths[]'),
|
||||
createFollowUpFeatureHandler(autoModeService, facadeFactory)
|
||||
createFollowUpFeatureHandler(autoModeService)
|
||||
);
|
||||
router.post(
|
||||
'/commit-feature',
|
||||
validatePathParams('projectPath', 'worktreePath?'),
|
||||
createCommitFeatureHandler(autoModeService, facadeFactory)
|
||||
createCommitFeatureHandler(autoModeService)
|
||||
);
|
||||
router.post(
|
||||
'/approve-plan',
|
||||
validatePathParams('projectPath'),
|
||||
createApprovePlanHandler(autoModeService, facadeFactory)
|
||||
createApprovePlanHandler(autoModeService)
|
||||
);
|
||||
router.post(
|
||||
'/resume-interrupted',
|
||||
validatePathParams('projectPath'),
|
||||
createResumeInterruptedHandler(autoModeService, facadeFactory)
|
||||
createResumeInterruptedHandler(autoModeService)
|
||||
);
|
||||
|
||||
return router;
|
||||
|
||||
@@ -3,17 +3,13 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { AutoModeService } from '../../../services/auto-mode-service.js';
|
||||
import type { AutoModeServiceFacade } from '../../../services/auto-mode/index.js';
|
||||
import type { AutoModeServiceCompat } from '../../../services/auto-mode/index.js';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
const logger = createLogger('AutoMode');
|
||||
|
||||
export function createAnalyzeProjectHandler(
|
||||
autoModeService: AutoModeService,
|
||||
facadeFactory?: (projectPath: string) => AutoModeServiceFacade
|
||||
) {
|
||||
export function createAnalyzeProjectHandler(autoModeService: AutoModeServiceCompat) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath } = req.body as { projectPath: string };
|
||||
@@ -23,19 +19,6 @@ export function createAnalyzeProjectHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
// Use facade if factory is provided, otherwise fall back to autoModeService
|
||||
if (facadeFactory) {
|
||||
const facade = facadeFactory(projectPath);
|
||||
// Start analysis in background
|
||||
facade.analyzeProject().catch((error) => {
|
||||
logger.error(`[AutoMode] Project analysis error:`, error);
|
||||
});
|
||||
|
||||
res.json({ success: true, message: 'Project analysis started' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Legacy path: use autoModeService directly
|
||||
// Start analysis in background
|
||||
autoModeService.analyzeProject(projectPath).catch((error) => {
|
||||
logger.error(`[AutoMode] Project analysis error:`, error);
|
||||
|
||||
@@ -3,17 +3,13 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { AutoModeService } from '../../../services/auto-mode-service.js';
|
||||
import type { AutoModeServiceFacade } from '../../../services/auto-mode/index.js';
|
||||
import type { AutoModeServiceCompat } from '../../../services/auto-mode/index.js';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
const logger = createLogger('AutoMode');
|
||||
|
||||
export function createApprovePlanHandler(
|
||||
autoModeService: AutoModeService,
|
||||
facadeFactory?: (projectPath: string) => AutoModeServiceFacade
|
||||
) {
|
||||
export function createApprovePlanHandler(autoModeService: AutoModeServiceCompat) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { featureId, approved, editedPlan, feedback, projectPath } = req.body as {
|
||||
@@ -50,37 +46,13 @@ export function createApprovePlanHandler(
|
||||
}${feedback ? ` - Feedback: ${feedback}` : ''}`
|
||||
);
|
||||
|
||||
// Use facade if factory is provided and projectPath is available
|
||||
if (facadeFactory && projectPath) {
|
||||
const facade = facadeFactory(projectPath);
|
||||
const result = await facade.resolvePlanApproval(featureId, approved, editedPlan, feedback);
|
||||
|
||||
if (!result.success) {
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: result.error,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
approved,
|
||||
message: approved
|
||||
? 'Plan approved - implementation will continue'
|
||||
: 'Plan rejected - feature execution stopped',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Legacy path: use autoModeService directly
|
||||
// Resolve the pending approval (with recovery support)
|
||||
const result = await autoModeService.resolvePlanApproval(
|
||||
projectPath || '',
|
||||
featureId,
|
||||
approved,
|
||||
editedPlan,
|
||||
feedback,
|
||||
projectPath
|
||||
feedback
|
||||
);
|
||||
|
||||
if (!result.success) {
|
||||
|
||||
@@ -3,18 +3,10 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { AutoModeService } from '../../../services/auto-mode-service.js';
|
||||
import type { AutoModeServiceFacade } from '../../../services/auto-mode/index.js';
|
||||
import type { AutoModeServiceCompat } from '../../../services/auto-mode/index.js';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
/**
|
||||
* Create commit feature handler with transition compatibility.
|
||||
* Accepts either autoModeService (legacy) or facadeFactory (new).
|
||||
*/
|
||||
export function createCommitFeatureHandler(
|
||||
autoModeService: AutoModeService,
|
||||
facadeFactory?: (projectPath: string) => AutoModeServiceFacade
|
||||
) {
|
||||
export function createCommitFeatureHandler(autoModeService: AutoModeServiceCompat) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, featureId, worktreePath } = req.body as {
|
||||
@@ -31,15 +23,6 @@ export function createCommitFeatureHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
// Use facade if factory is provided, otherwise fall back to autoModeService
|
||||
if (facadeFactory) {
|
||||
const facade = facadeFactory(projectPath);
|
||||
const commitHash = await facade.commitFeature(featureId, worktreePath);
|
||||
res.json({ success: true, commitHash });
|
||||
return;
|
||||
}
|
||||
|
||||
// Legacy path: use autoModeService directly
|
||||
const commitHash = await autoModeService.commitFeature(projectPath, featureId, worktreePath);
|
||||
res.json({ success: true, commitHash });
|
||||
} catch (error) {
|
||||
|
||||
@@ -3,18 +3,10 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { AutoModeService } from '../../../services/auto-mode-service.js';
|
||||
import type { AutoModeServiceFacade } from '../../../services/auto-mode/index.js';
|
||||
import type { AutoModeServiceCompat } from '../../../services/auto-mode/index.js';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
/**
|
||||
* Create context exists handler with transition compatibility.
|
||||
* Accepts either autoModeService (legacy) or facadeFactory (new).
|
||||
*/
|
||||
export function createContextExistsHandler(
|
||||
autoModeService: AutoModeService,
|
||||
facadeFactory?: (projectPath: string) => AutoModeServiceFacade
|
||||
) {
|
||||
export function createContextExistsHandler(autoModeService: AutoModeServiceCompat) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, featureId } = req.body as {
|
||||
@@ -30,15 +22,6 @@ export function createContextExistsHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
// Use facade if factory is provided, otherwise fall back to autoModeService
|
||||
if (facadeFactory) {
|
||||
const facade = facadeFactory(projectPath);
|
||||
const exists = await facade.contextExists(featureId);
|
||||
res.json({ success: true, exists });
|
||||
return;
|
||||
}
|
||||
|
||||
// Legacy path: use autoModeService directly
|
||||
const exists = await autoModeService.contextExists(projectPath, featureId);
|
||||
res.json({ success: true, exists });
|
||||
} catch (error) {
|
||||
|
||||
@@ -3,17 +3,13 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { AutoModeService } from '../../../services/auto-mode-service.js';
|
||||
import type { AutoModeServiceFacade } from '../../../services/auto-mode/index.js';
|
||||
import type { AutoModeServiceCompat } from '../../../services/auto-mode/index.js';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
const logger = createLogger('AutoMode');
|
||||
|
||||
export function createFollowUpFeatureHandler(
|
||||
autoModeService: AutoModeService,
|
||||
facadeFactory?: (projectPath: string) => AutoModeServiceFacade
|
||||
) {
|
||||
export function createFollowUpFeatureHandler(autoModeService: AutoModeServiceCompat) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, featureId, prompt, imagePaths, useWorktrees } = req.body as {
|
||||
@@ -32,40 +28,14 @@ export function createFollowUpFeatureHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
// Use facade if factory is provided, otherwise fall back to autoModeService
|
||||
if (facadeFactory) {
|
||||
const facade = facadeFactory(projectPath);
|
||||
// Start follow-up in background
|
||||
// followUpFeature derives workDir from feature.branchName
|
||||
facade
|
||||
// Default to false to match run-feature/resume-feature behavior.
|
||||
// Worktrees should only be used when explicitly enabled by the user.
|
||||
.followUpFeature(featureId, prompt, imagePaths, useWorktrees ?? false)
|
||||
.catch((error) => {
|
||||
logger.error(`[AutoMode] Follow up feature ${featureId} error:`, error);
|
||||
})
|
||||
.finally(() => {
|
||||
// Release the starting slot when follow-up completes (success or error)
|
||||
// Note: The feature should be in runningFeatures by this point
|
||||
});
|
||||
|
||||
res.json({ success: true });
|
||||
return;
|
||||
}
|
||||
|
||||
// Legacy path: use autoModeService directly
|
||||
// Start follow-up in background
|
||||
// followUpFeature derives workDir from feature.branchName
|
||||
// Default to false to match run-feature/resume-feature behavior.
|
||||
// Worktrees should only be used when explicitly enabled by the user.
|
||||
autoModeService
|
||||
// Default to false to match run-feature/resume-feature behavior.
|
||||
// Worktrees should only be used when explicitly enabled by the user.
|
||||
.followUpFeature(projectPath, featureId, prompt, imagePaths, useWorktrees ?? false)
|
||||
.catch((error) => {
|
||||
logger.error(`[AutoMode] Follow up feature ${featureId} error:`, error);
|
||||
})
|
||||
.finally(() => {
|
||||
// Release the starting slot when follow-up completes (success or error)
|
||||
// Note: The feature should be in runningFeatures by this point
|
||||
});
|
||||
|
||||
res.json({ success: true });
|
||||
|
||||
@@ -3,17 +3,13 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { AutoModeService } from '../../../services/auto-mode-service.js';
|
||||
import type { AutoModeServiceFacade } from '../../../services/auto-mode/index.js';
|
||||
import type { AutoModeServiceCompat } from '../../../services/auto-mode/index.js';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
const logger = createLogger('AutoMode');
|
||||
|
||||
export function createResumeFeatureHandler(
|
||||
autoModeService: AutoModeService,
|
||||
facadeFactory?: (projectPath: string) => AutoModeServiceFacade
|
||||
) {
|
||||
export function createResumeFeatureHandler(autoModeService: AutoModeServiceCompat) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, featureId, useWorktrees } = req.body as {
|
||||
@@ -30,20 +26,6 @@ export function createResumeFeatureHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
// Use facade if factory is provided, otherwise fall back to autoModeService
|
||||
if (facadeFactory) {
|
||||
const facade = facadeFactory(projectPath);
|
||||
// Start resume in background
|
||||
// Default to false - worktrees should only be used when explicitly enabled
|
||||
facade.resumeFeature(featureId, useWorktrees ?? false).catch((error) => {
|
||||
logger.error(`Resume feature ${featureId} error:`, error);
|
||||
});
|
||||
|
||||
res.json({ success: true });
|
||||
return;
|
||||
}
|
||||
|
||||
// Legacy path: use autoModeService directly
|
||||
// Start resume in background
|
||||
// Default to false - worktrees should only be used when explicitly enabled
|
||||
autoModeService
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import type { AutoModeService } from '../../../services/auto-mode-service.js';
|
||||
import type { AutoModeServiceFacade } from '../../../services/auto-mode/index.js';
|
||||
import type { AutoModeServiceCompat } from '../../../services/auto-mode/index.js';
|
||||
|
||||
const logger = createLogger('ResumeInterrupted');
|
||||
|
||||
@@ -16,10 +15,7 @@ interface ResumeInterruptedRequest {
|
||||
projectPath: string;
|
||||
}
|
||||
|
||||
export function createResumeInterruptedHandler(
|
||||
autoModeService: AutoModeService,
|
||||
facadeFactory?: (projectPath: string) => AutoModeServiceFacade
|
||||
) {
|
||||
export function createResumeInterruptedHandler(autoModeService: AutoModeServiceCompat) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
const { projectPath } = req.body as ResumeInterruptedRequest;
|
||||
|
||||
@@ -31,13 +27,7 @@ export function createResumeInterruptedHandler(
|
||||
logger.info(`Checking for interrupted features in ${projectPath}`);
|
||||
|
||||
try {
|
||||
// Use facade if factory is provided, otherwise fall back to autoModeService
|
||||
if (facadeFactory) {
|
||||
const facade = facadeFactory(projectPath);
|
||||
await facade.resumeInterruptedFeatures();
|
||||
} else {
|
||||
await autoModeService.resumeInterruptedFeatures(projectPath);
|
||||
}
|
||||
await autoModeService.resumeInterruptedFeatures(projectPath);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
|
||||
@@ -3,17 +3,13 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { AutoModeService } from '../../../services/auto-mode-service.js';
|
||||
import type { AutoModeServiceFacade } from '../../../services/auto-mode/index.js';
|
||||
import type { AutoModeServiceCompat } from '../../../services/auto-mode/index.js';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
const logger = createLogger('AutoMode');
|
||||
|
||||
export function createRunFeatureHandler(
|
||||
autoModeService: AutoModeService,
|
||||
facadeFactory?: (projectPath: string) => AutoModeServiceFacade
|
||||
) {
|
||||
export function createRunFeatureHandler(autoModeService: AutoModeServiceCompat) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, featureId, useWorktrees } = req.body as {
|
||||
@@ -30,45 +26,6 @@ export function createRunFeatureHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
// Use facade if factory is provided, otherwise fall back to autoModeService
|
||||
if (facadeFactory) {
|
||||
const facade = facadeFactory(projectPath);
|
||||
|
||||
// Check per-worktree capacity before starting
|
||||
const capacity = await facade.checkWorktreeCapacity(featureId);
|
||||
if (!capacity.hasCapacity) {
|
||||
const worktreeDesc = capacity.branchName
|
||||
? `worktree "${capacity.branchName}"`
|
||||
: 'main worktree';
|
||||
res.status(429).json({
|
||||
success: false,
|
||||
error: `Agent limit reached for ${worktreeDesc} (${capacity.currentAgents}/${capacity.maxAgents}). Wait for running tasks to complete or increase the limit.`,
|
||||
details: {
|
||||
currentAgents: capacity.currentAgents,
|
||||
maxAgents: capacity.maxAgents,
|
||||
branchName: capacity.branchName,
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Start execution in background
|
||||
// executeFeature derives workDir from feature.branchName
|
||||
facade
|
||||
.executeFeature(featureId, useWorktrees ?? false, false)
|
||||
.catch((error) => {
|
||||
logger.error(`Feature ${featureId} error:`, error);
|
||||
})
|
||||
.finally(() => {
|
||||
// Release the starting slot when execution completes (success or error)
|
||||
// Note: The feature should be in runningFeatures by this point
|
||||
});
|
||||
|
||||
res.json({ success: true });
|
||||
return;
|
||||
}
|
||||
|
||||
// Legacy path: use autoModeService directly
|
||||
// Check per-worktree capacity before starting
|
||||
const capacity = await autoModeService.checkWorktreeCapacity(projectPath, featureId);
|
||||
if (!capacity.hasCapacity) {
|
||||
@@ -93,10 +50,6 @@ export function createRunFeatureHandler(
|
||||
.executeFeature(projectPath, featureId, useWorktrees ?? false, false)
|
||||
.catch((error) => {
|
||||
logger.error(`Feature ${featureId} error:`, error);
|
||||
})
|
||||
.finally(() => {
|
||||
// Release the starting slot when execution completes (success or error)
|
||||
// Note: The feature should be in runningFeatures by this point
|
||||
});
|
||||
|
||||
res.json({ success: true });
|
||||
|
||||
@@ -3,17 +3,13 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { AutoModeService } from '../../../services/auto-mode-service.js';
|
||||
import type { AutoModeServiceFacade } from '../../../services/auto-mode/index.js';
|
||||
import type { AutoModeServiceCompat } from '../../../services/auto-mode/index.js';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
const logger = createLogger('AutoMode');
|
||||
|
||||
export function createStartHandler(
|
||||
autoModeService: AutoModeService,
|
||||
facadeFactory?: (projectPath: string) => AutoModeServiceFacade
|
||||
) {
|
||||
export function createStartHandler(autoModeService: AutoModeServiceCompat) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, branchName, maxConcurrency } = req.body as {
|
||||
@@ -36,40 +32,6 @@ export function createStartHandler(
|
||||
? `worktree ${normalizedBranchName}`
|
||||
: 'main worktree';
|
||||
|
||||
// Use facade if factory is provided, otherwise fall back to autoModeService
|
||||
if (facadeFactory) {
|
||||
const facade = facadeFactory(projectPath);
|
||||
|
||||
// Check if already running
|
||||
if (facade.isAutoLoopRunning(normalizedBranchName)) {
|
||||
res.json({
|
||||
success: true,
|
||||
message: `Auto mode is already running for ${worktreeDesc}`,
|
||||
alreadyRunning: true,
|
||||
branchName: normalizedBranchName,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Start the auto loop for this project/worktree
|
||||
const resolvedMaxConcurrency = await facade.startAutoLoop(
|
||||
normalizedBranchName,
|
||||
maxConcurrency
|
||||
);
|
||||
|
||||
logger.info(
|
||||
`Started auto loop for ${worktreeDesc} in project: ${projectPath} with maxConcurrency: ${resolvedMaxConcurrency}`
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: `Auto mode started with max ${resolvedMaxConcurrency} concurrent features`,
|
||||
branchName: normalizedBranchName,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Legacy path: use autoModeService directly
|
||||
// Check if already running
|
||||
if (autoModeService.isAutoLoopRunningForProject(projectPath, normalizedBranchName)) {
|
||||
res.json({
|
||||
|
||||
@@ -6,19 +6,13 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { AutoModeService } from '../../../services/auto-mode-service.js';
|
||||
import type { AutoModeServiceFacade } from '../../../services/auto-mode/index.js';
|
||||
import type { AutoModeServiceCompat } from '../../../services/auto-mode/index.js';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
/**
|
||||
* Create status handler with transition compatibility.
|
||||
* Accepts either autoModeService (legacy) or facade (new).
|
||||
* When facade is provided, creates a per-project facade for the request.
|
||||
* Create status handler.
|
||||
*/
|
||||
export function createStatusHandler(
|
||||
autoModeService: AutoModeService,
|
||||
facadeFactory?: (projectPath: string) => AutoModeServiceFacade
|
||||
) {
|
||||
export function createStatusHandler(autoModeService: AutoModeServiceCompat) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, branchName } = req.body as {
|
||||
@@ -31,24 +25,6 @@ export function createStatusHandler(
|
||||
// Normalize branchName: undefined becomes null
|
||||
const normalizedBranchName = branchName ?? null;
|
||||
|
||||
// Use facade if factory is provided, otherwise fall back to autoModeService
|
||||
if (facadeFactory) {
|
||||
const facade = facadeFactory(projectPath);
|
||||
const projectStatus = facade.getStatusForProject(normalizedBranchName);
|
||||
res.json({
|
||||
success: true,
|
||||
isRunning: projectStatus.runningCount > 0,
|
||||
isAutoLoopRunning: projectStatus.isAutoLoopRunning,
|
||||
runningFeatures: projectStatus.runningFeatures,
|
||||
runningCount: projectStatus.runningCount,
|
||||
maxConcurrency: projectStatus.maxConcurrency,
|
||||
projectPath,
|
||||
branchName: normalizedBranchName,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Legacy path: use autoModeService directly
|
||||
const projectStatus = autoModeService.getStatusForProject(
|
||||
projectPath,
|
||||
normalizedBranchName
|
||||
@@ -66,8 +42,7 @@ export function createStatusHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
// Fall back to global status for backward compatibility
|
||||
// Global status uses autoModeService (facade is per-project)
|
||||
// Global status for backward compatibility
|
||||
const status = autoModeService.getStatus();
|
||||
const activeProjects = autoModeService.getActiveAutoLoopProjects();
|
||||
const activeWorktrees = autoModeService.getActiveAutoLoopWorktrees();
|
||||
|
||||
@@ -3,19 +3,10 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { AutoModeService } from '../../../services/auto-mode-service.js';
|
||||
import type { AutoModeServiceFacade } from '../../../services/auto-mode/index.js';
|
||||
import type { AutoModeServiceCompat } from '../../../services/auto-mode/index.js';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
/**
|
||||
* Create stop feature handler with transition compatibility.
|
||||
* Accepts either autoModeService (legacy) or facade (new).
|
||||
* Note: stopFeature is feature-scoped (not project-scoped), so a single facade can be used.
|
||||
*/
|
||||
export function createStopFeatureHandler(
|
||||
autoModeService: AutoModeService,
|
||||
facade?: AutoModeServiceFacade
|
||||
) {
|
||||
export function createStopFeatureHandler(autoModeService: AutoModeServiceCompat) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { featureId } = req.body as { featureId: string };
|
||||
@@ -25,10 +16,7 @@ export function createStopFeatureHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
// Use facade if provided, otherwise fall back to autoModeService
|
||||
const stopped = facade
|
||||
? await facade.stopFeature(featureId)
|
||||
: await autoModeService.stopFeature(featureId);
|
||||
const stopped = await autoModeService.stopFeature(featureId);
|
||||
res.json({ success: true, stopped });
|
||||
} catch (error) {
|
||||
logError(error, 'Stop feature failed');
|
||||
|
||||
@@ -3,21 +3,13 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { AutoModeService } from '../../../services/auto-mode-service.js';
|
||||
import type { AutoModeServiceFacade } from '../../../services/auto-mode/index.js';
|
||||
import type { AutoModeServiceCompat } from '../../../services/auto-mode/index.js';
|
||||
import { createLogger } from '@automaker/utils';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
const logger = createLogger('AutoMode');
|
||||
|
||||
/**
|
||||
* Create stop handler with transition compatibility.
|
||||
* Accepts either autoModeService (legacy) or facadeFactory (new).
|
||||
*/
|
||||
export function createStopHandler(
|
||||
autoModeService: AutoModeService,
|
||||
facadeFactory?: (projectPath: string) => AutoModeServiceFacade
|
||||
) {
|
||||
export function createStopHandler(autoModeService: AutoModeServiceCompat) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, branchName } = req.body as {
|
||||
@@ -39,38 +31,6 @@ export function createStopHandler(
|
||||
? `worktree ${normalizedBranchName}`
|
||||
: 'main worktree';
|
||||
|
||||
// Use facade if factory is provided, otherwise fall back to autoModeService
|
||||
if (facadeFactory) {
|
||||
const facade = facadeFactory(projectPath);
|
||||
|
||||
// Check if running
|
||||
if (!facade.isAutoLoopRunning(normalizedBranchName)) {
|
||||
res.json({
|
||||
success: true,
|
||||
message: `Auto mode is not running for ${worktreeDesc}`,
|
||||
wasRunning: false,
|
||||
branchName: normalizedBranchName,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop the auto loop for this project/worktree
|
||||
const runningCount = await facade.stopAutoLoop(normalizedBranchName);
|
||||
|
||||
logger.info(
|
||||
`Stopped auto loop for ${worktreeDesc} in project: ${projectPath}, ${runningCount} features still running`
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Auto mode stopped',
|
||||
runningFeaturesCount: runningCount,
|
||||
branchName: normalizedBranchName,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Legacy path: use autoModeService directly
|
||||
// Check if running
|
||||
if (!autoModeService.isAutoLoopRunningForProject(projectPath, normalizedBranchName)) {
|
||||
res.json({
|
||||
|
||||
@@ -3,18 +3,10 @@
|
||||
*/
|
||||
|
||||
import type { Request, Response } from 'express';
|
||||
import type { AutoModeService } from '../../../services/auto-mode-service.js';
|
||||
import type { AutoModeServiceFacade } from '../../../services/auto-mode/index.js';
|
||||
import type { AutoModeServiceCompat } from '../../../services/auto-mode/index.js';
|
||||
import { getErrorMessage, logError } from '../common.js';
|
||||
|
||||
/**
|
||||
* Create verify feature handler with transition compatibility.
|
||||
* Accepts either autoModeService (legacy) or facadeFactory (new).
|
||||
*/
|
||||
export function createVerifyFeatureHandler(
|
||||
autoModeService: AutoModeService,
|
||||
facadeFactory?: (projectPath: string) => AutoModeServiceFacade
|
||||
) {
|
||||
export function createVerifyFeatureHandler(autoModeService: AutoModeServiceCompat) {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const { projectPath, featureId } = req.body as {
|
||||
@@ -30,15 +22,6 @@ export function createVerifyFeatureHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
// Use facade if factory is provided, otherwise fall back to autoModeService
|
||||
if (facadeFactory) {
|
||||
const facade = facadeFactory(projectPath);
|
||||
const passes = await facade.verifyFeature(featureId);
|
||||
res.json({ success: true, passes });
|
||||
return;
|
||||
}
|
||||
|
||||
// Legacy path: use autoModeService directly
|
||||
const passes = await autoModeService.verifyFeature(projectPath, featureId);
|
||||
res.json({ success: true, passes });
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user