Add orphaned features management routes and UI integration (#819)

* test(copilot): add edge case test for error with code field

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Changes from fix/bug-fixes-1-0

* refactor(auto-mode): enhance orphaned feature detection and improve project initialization

- Updated detectOrphanedFeatures method to accept preloaded features, reducing redundant disk reads.
- Improved project initialization by creating required directories and files in parallel for better performance.
- Adjusted planning mode handling in UI components to clarify approval requirements for different modes.
- Added refresh functionality for file editor tabs to ensure content consistency with disk state.

These changes enhance performance, maintainability, and user experience across the application.

* feat(orphaned-features): add orphaned features management routes and UI integration

- Introduced new routes for managing orphaned features, including listing, resolving, and bulk resolving.
- Updated the UI to include an Orphaned Features section in project settings and navigation.
- Enhanced the execution service to support new orphaned feature functionalities.

These changes improve the application's capability to handle orphaned features effectively, enhancing user experience and project management.

* fix: Normalize line endings and resolve stale dirty states in file editor

* chore: Update .gitignore and enhance orphaned feature handling

- Added a blank line in .gitignore for better readability.
- Introduced a hash to worktree paths in orphaned feature resolution to prevent conflicts.
- Added validation for target branch existence during orphaned feature resolution.
- Improved prompt formatting in execution service for clarity.
- Enhanced error handling in project selector for project initialization failures.
- Refactored orphaned features section to improve state management and UI responsiveness.

These changes improve code maintainability and user experience when managing orphaned features.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
gsxdsm
2026-02-27 22:14:41 -08:00
committed by GitHub
parent 0196911d59
commit 1c0e460dd1
36 changed files with 2048 additions and 406 deletions

View File

@@ -129,12 +129,41 @@ export const isConnectionError = (error: unknown): boolean => {
};
/**
* Handle a server offline error by notifying the UI to redirect.
* Call this when a connection error is detected.
* Handle a server offline error by verifying the server is actually down
* before redirecting to login. Uses debouncing to coalesce rapid errors
* and a health check to confirm the server isn't just experiencing a
* transient network blip.
*/
let serverOfflineCheckPending = false;
export const handleServerOffline = (): void => {
logger.error('Server appears to be offline, redirecting to login...');
notifyServerOffline();
// Debounce: if a check is already in progress, skip
if (serverOfflineCheckPending) return;
serverOfflineCheckPending = true;
// Wait briefly to let transient errors settle, then verify with a health check
setTimeout(() => {
(async () => {
try {
const response = await fetch(`${getServerUrl()}/api/health`, {
method: 'GET',
cache: NO_STORE_CACHE_MODE,
signal: AbortSignal.timeout(5000),
});
if (response.ok) {
logger.info('Server health check passed, ignoring transient connection error');
return;
}
} catch {
// Health check failed - server is genuinely offline
}
logger.error('Server appears to be offline, redirecting to login...');
notifyServerOffline();
})().finally(() => {
serverOfflineCheckPending = false;
});
}, 2000);
};
/**
@@ -2080,6 +2109,44 @@ export class HttpApiClient implements ElectronAPI {
conflictCount?: number;
error?: string;
}> => this.post('/api/features/check-conflicts', { projectPath, data }),
getOrphaned: (
projectPath: string
): Promise<{
success: boolean;
orphanedFeatures?: Array<{ feature: Feature; missingBranch: string }>;
error?: string;
}> => this.post('/api/features/orphaned', { projectPath }),
resolveOrphaned: (
projectPath: string,
featureId: string,
action: 'delete' | 'create-worktree' | 'move-to-branch',
targetBranch?: string | null
): Promise<{
success: boolean;
action?: string;
worktreePath?: string;
branchName?: string;
error?: string;
}> =>
this.post('/api/features/orphaned/resolve', { projectPath, featureId, action, targetBranch }),
bulkResolveOrphaned: (
projectPath: string,
featureIds: string[],
action: 'delete' | 'create-worktree' | 'move-to-branch',
targetBranch?: string | null
): Promise<{
success: boolean;
resolvedCount?: number;
failedCount?: number;
results?: Array<{ featureId: string; success: boolean; action?: string; error?: string }>;
error?: string;
}> =>
this.post('/api/features/orphaned/bulk-resolve', {
projectPath,
featureIds,
action,
targetBranch,
}),
};
// Auto Mode API