Improve pull request flow, add branch selection for worktree creation, fix auto-mode concurrency count (#787)

* Changes from fix/fetch-before-pull-fetch

* feat: Improve pull request flow, add branch selection for worktree creation, fix for automode concurrency count

* feat: Add validation for remote names and improve error handling

* Address PR comments and mobile layout fixes

* ```
refactor: Extract PR target resolution logic into dedicated service
```

* feat: Add app shell UI and improve service imports. Address PR comments

* fix: Improve security validation and cache handling in git operations

* feat: Add GET /list endpoint and improve parameter handling

* chore: Improve validation, accessibility, and error handling across apps

* chore: Format vite server port configuration

* fix: Add error handling for gh pr list command and improve offline fallbacks

* fix: Preserve existing PR creation time and improve remote handling
This commit is contained in:
gsxdsm
2026-02-19 21:55:12 -08:00
committed by GitHub
parent ee52333636
commit 7df2182818
80 changed files with 4729 additions and 1107 deletions

View File

@@ -313,24 +313,69 @@ export function GraphViewPage() {
// Handle add and start feature
const handleAddAndStartFeature = useCallback(
async (featureData: Parameters<typeof handleAddFeature>[0]) => {
const featuresBeforeIds = new Set(useAppStore.getState().features.map((f) => f.id));
try {
const featuresBeforeIds = new Set(useAppStore.getState().features.map((f) => f.id));
await handleAddFeature(featureData);
const latestFeatures = useAppStore.getState().features;
const newFeature = latestFeatures.find((f) => !featuresBeforeIds.has(f.id));
if (newFeature) {
await handleStartImplementation(newFeature);
}
// Create feature directly with in_progress status to avoid brief backlog flash
await handleAddFeature({ ...featureData, initialStatus: 'in_progress' });
} catch (error) {
logger.error('Failed to add and start feature:', error);
logger.error('Failed to create feature:', error);
toast.error(
`Failed to add and start feature: ${error instanceof Error ? error.message : String(error)}`
`Failed to create feature: ${error instanceof Error ? error.message : String(error)}`
);
return;
}
const latestFeatures = useAppStore.getState().features;
const newFeature = latestFeatures.find((f) => !featuresBeforeIds.has(f.id));
if (newFeature) {
try {
await handleStartImplementation(newFeature);
} catch (startError) {
logger.error('Failed to start implementation, rolling back feature status:', startError);
// Rollback: revert the newly created feature back to backlog so it isn't stuck in in_progress
try {
const { updateFeature } = useAppStore.getState();
updateFeature(newFeature.id, { status: 'backlog' });
// Also persist the rollback so it survives page refresh
await persistFeatureUpdate(newFeature.id, { status: 'backlog' });
logger.info(`Rolled back feature ${newFeature.id} status to backlog`);
} catch (rollbackErr) {
logger.error('Failed to rollback feature status:', rollbackErr);
}
toast.error(
`Failed to start feature: ${startError instanceof Error ? startError.message : String(startError)}`
);
}
} else {
// Feature was not found in the store after creation — it may have been
// persisted but not yet visible in the snapshot. Attempt to locate it
// and roll it back so it doesn't remain stuck in 'in_progress'.
logger.error(
'Newly created feature not found in store after handleAddFeature completed. ' +
`Store has ${latestFeatures.length} features, expected a new entry.`
);
// Best-effort: re-read the store to find any feature still in 'in_progress'
// that wasn't in the original set. We must use a fresh snapshot here because
// latestFeatures was captured before the async gap and may not contain the new entry.
const freshFeatures = useAppStore.getState().features;
const stuckFeature = freshFeatures.find(
(f) => f.status === 'in_progress' && !featuresBeforeIds.has(f.id)
);
if (stuckFeature) {
try {
const { updateFeature } = useAppStore.getState();
updateFeature(stuckFeature.id, { status: 'backlog' });
await persistFeatureUpdate(stuckFeature.id, { status: 'backlog' });
logger.info(`Rolled back orphaned feature ${stuckFeature.id} status to backlog`);
} catch (rollbackErr) {
logger.error('Failed to rollback orphaned feature status:', rollbackErr);
}
}
toast.error('Feature was created but could not be started. Please try again.');
}
},
[handleAddFeature, handleStartImplementation]
[handleAddFeature, handleStartImplementation, persistFeatureUpdate]
);
if (!currentProject) {