From 8542a32f4f76f99481fc52ea816f9d3eb3b0be25 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Sat, 14 Feb 2026 21:28:15 -0800 Subject: [PATCH] refactor(auto-mode): enhance feature retrieval logic in facade and global service - Replaced synchronous feature retrieval with asynchronous logic in both AutoModeServiceFacade and GlobalAutoModeService. - Updated filtering logic to resolve the primary branch name for main worktrees, improving accuracy in feature status checks. - This change enhances the responsiveness and correctness of feature handling in auto mode operations. --- apps/server/src/services/auto-mode/facade.ts | 37 ++++++++----------- .../src/services/auto-mode/global-service.ts | 28 ++++++++------ 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/apps/server/src/services/auto-mode/facade.ts b/apps/server/src/services/auto-mode/facade.ts index 29902a76..83acf678 100644 --- a/apps/server/src/services/auto-mode/facade.ts +++ b/apps/server/src/services/auto-mode/facade.ts @@ -48,15 +48,6 @@ import type { const execAsync = promisify(exec); const logger = createLogger('AutoModeServiceFacade'); -/** - * Generate a unique key for worktree-scoped auto loop state - * (mirrors the function in AutoModeService for status lookups) - */ -function getWorktreeAutoLoopKey(projectPath: string, branchName: string | null): string { - const normalizedBranch = branchName === 'main' ? null : branchName; - return `${projectPath}::${normalizedBranch ?? '__main__'}`; -} - /** * AutoModeServiceFacade provides a clean interface for auto-mode functionality. * @@ -240,18 +231,22 @@ export class AutoModeServiceFacade { // Callbacks (pPath, featureId, useWorktrees, isAutoMode) => facadeInstance!.executeFeature(featureId, useWorktrees, isAutoMode), - (pPath, branchName) => - featureLoader - .getAll(pPath) - .then((features) => - features.filter( - (f) => - (f.status === 'backlog' || f.status === 'ready') && - (branchName === null - ? !f.branchName || f.branchName === 'main' - : f.branchName === branchName) - ) - ), + async (pPath, branchName) => { + const features = await featureLoader.getAll(pPath); + // For main worktree (branchName === null), resolve the actual primary branch name + // so features with branchName matching the primary branch are included + let primaryBranch: string | null = null; + if (branchName === null) { + primaryBranch = await worktreeResolver.getCurrentBranch(pPath); + } + return features.filter( + (f) => + (f.status === 'backlog' || f.status === 'ready') && + (branchName === null + ? !f.branchName || (primaryBranch && f.branchName === primaryBranch) + : f.branchName === branchName) + ); + }, (pPath, branchName, maxConcurrency) => facadeInstance!.saveExecutionStateForProject(branchName, maxConcurrency), (pPath, branchName) => facadeInstance!.clearExecutionState(branchName), diff --git a/apps/server/src/services/auto-mode/global-service.ts b/apps/server/src/services/auto-mode/global-service.ts index ca787440..0e0e7e52 100644 --- a/apps/server/src/services/auto-mode/global-service.ts +++ b/apps/server/src/services/auto-mode/global-service.ts @@ -66,18 +66,22 @@ export class GlobalAutoModeService { ); }, // getBacklogFeaturesFn - (pPath, branchName) => - featureLoader - .getAll(pPath) - .then((features) => - features.filter( - (f) => - (f.status === 'backlog' || f.status === 'ready') && - (branchName === null - ? !f.branchName || f.branchName === 'main' - : f.branchName === branchName) - ) - ), + async (pPath, branchName) => { + const features = await featureLoader.getAll(pPath); + // For main worktree (branchName === null), resolve the actual primary branch name + // so features with branchName matching the primary branch are included + let primaryBranch: string | null = null; + if (branchName === null) { + primaryBranch = await this.worktreeResolver.getCurrentBranch(pPath); + } + return features.filter( + (f) => + (f.status === 'backlog' || f.status === 'ready') && + (branchName === null + ? !f.branchName || (primaryBranch && f.branchName === primaryBranch) + : f.branchName === branchName) + ); + }, // saveExecutionStateFn - placeholder async () => {}, // clearExecutionStateFn - placeholder