mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-03-18 10:23:07 +00:00
refactor: Enhance session management and error handling in AgentService and related components
- Improved session handling by implementing ensureSession to load sessions from disk if not in memory, reducing "session not found" errors. - Enhanced error messages for non-existent sessions, providing clearer diagnostics. - Updated CodexProvider and OpencodeProvider to improve error handling and messaging. - Refactored various routes to use async/await for better readability and error handling. - Added event emission for merge and stash operations in the MergeService and StashService. - Cleaned up error messages in AgentExecutor to remove redundant prefixes and ANSI codes for better clarity.
This commit is contained in:
@@ -33,8 +33,8 @@ export function TruncatedFilePath({ path, className }: TruncatedFilePathProps) {
|
||||
|
||||
return (
|
||||
<span className={cn('flex min-w-0', className)} title={path}>
|
||||
<span className="truncate flex-shrink">{dirPart}</span>
|
||||
<span className="flex-shrink-0 whitespace-nowrap">{filePart}</span>
|
||||
<span className="truncate shrink">{dirPart}</span>
|
||||
<span className="shrink-0 whitespace-nowrap">{filePart}</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -178,6 +178,10 @@ function parseDiff(diffText: string): ParsedFileDiff[] {
|
||||
}
|
||||
|
||||
if (currentHunk) {
|
||||
// Skip trailing empty line produced by split('\n') to avoid phantom context line
|
||||
if (line === '' && i === lines.length - 1) {
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith('+')) {
|
||||
currentHunk.lines.push({
|
||||
type: 'addition',
|
||||
|
||||
@@ -41,10 +41,10 @@ type PullPhase =
|
||||
| 'error'; // Something went wrong
|
||||
|
||||
interface PullResult {
|
||||
branch: string;
|
||||
branch?: string;
|
||||
remote?: string;
|
||||
pulled: boolean;
|
||||
message: string;
|
||||
pulled?: boolean;
|
||||
message?: string;
|
||||
hasLocalChanges?: boolean;
|
||||
localChangedFiles?: string[];
|
||||
hasConflicts?: boolean;
|
||||
@@ -52,6 +52,7 @@ interface PullResult {
|
||||
conflictFiles?: string[];
|
||||
stashed?: boolean;
|
||||
stashRestored?: boolean;
|
||||
stashRecoveryFailed?: boolean;
|
||||
}
|
||||
|
||||
interface GitPullDialogProps {
|
||||
@@ -167,9 +168,10 @@ export function GitPullDialog({
|
||||
if (!worktree || !pullResult || !onCreateConflictResolutionFeature) return;
|
||||
|
||||
const effectiveRemote = pullResult.remote || remote;
|
||||
const branch = pullResult.branch ?? worktree.branch;
|
||||
const conflictInfo: MergeConflictInfo = {
|
||||
sourceBranch: effectiveRemote ? `${effectiveRemote}/${pullResult.branch}` : pullResult.branch,
|
||||
targetBranch: pullResult.branch,
|
||||
sourceBranch: `${effectiveRemote || 'origin'}/${branch}`,
|
||||
targetBranch: branch,
|
||||
targetWorktreePath: worktree.path,
|
||||
conflictFiles: pullResult.conflictFiles || [],
|
||||
operationType: 'merge',
|
||||
@@ -307,14 +309,16 @@ export function GitPullDialog({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{pullResult?.stashed && !pullResult?.stashRestored && (
|
||||
<div className="flex items-start gap-2 p-3 rounded-md bg-amber-500/10 border border-amber-500/20">
|
||||
<AlertTriangle className="w-4 h-4 text-amber-500 mt-0.5 flex-shrink-0" />
|
||||
<span className="text-amber-600 dark:text-amber-400 text-sm">
|
||||
{pullResult.message}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{pullResult?.stashed &&
|
||||
(!pullResult?.stashRestored || pullResult?.stashRecoveryFailed) && (
|
||||
<div className="flex items-start gap-2 p-3 rounded-md bg-amber-500/10 border border-amber-500/20">
|
||||
<AlertTriangle className="w-4 h-4 text-amber-500 mt-0.5 flex-shrink-0" />
|
||||
<span className="text-amber-600 dark:text-amber-400 text-sm">
|
||||
{pullResult?.message ??
|
||||
'Stash could not be restored. Your changes remain in the stash.'}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -284,6 +284,7 @@ export function StashChangesDialog({
|
||||
const [selectedFiles, setSelectedFiles] = useState<Set<string>>(new Set());
|
||||
const [expandedFile, setExpandedFile] = useState<string | null>(null);
|
||||
const [isLoadingDiffs, setIsLoadingDiffs] = useState(false);
|
||||
const [loadDiffsError, setLoadDiffsError] = useState<string | null>(null);
|
||||
|
||||
// Parse diffs
|
||||
const parsedDiffs = useMemo(() => parseDiff(diffContent), [diffContent]);
|
||||
@@ -297,42 +298,47 @@ export function StashChangesDialog({
|
||||
return map;
|
||||
}, [parsedDiffs]);
|
||||
|
||||
// Load diffs when dialog opens
|
||||
useEffect(() => {
|
||||
if (open && worktree) {
|
||||
const loadDiffs = useCallback(
|
||||
async (cancelled: { current: boolean }) => {
|
||||
setIsLoadingDiffs(true);
|
||||
setLoadDiffsError(null);
|
||||
setFiles([]);
|
||||
setDiffContent('');
|
||||
setSelectedFiles(new Set());
|
||||
setExpandedFile(null);
|
||||
|
||||
let cancelled = false;
|
||||
|
||||
const loadDiffs = async () => {
|
||||
try {
|
||||
const api = getHttpApiClient();
|
||||
const result = await api.git.getDiffs(worktree.path);
|
||||
if (result.success) {
|
||||
const fileList = result.files ?? [];
|
||||
if (!cancelled) setFiles(fileList);
|
||||
if (!cancelled) setDiffContent(result.diff ?? '');
|
||||
// Select all files by default
|
||||
if (!cancelled) setSelectedFiles(new Set(fileList.map((f: FileStatus) => f.path)));
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Failed to load diffs for stash dialog:', err);
|
||||
} finally {
|
||||
if (!cancelled) setIsLoadingDiffs(false);
|
||||
try {
|
||||
const api = getHttpApiClient();
|
||||
const result = await api.git.getDiffs(worktree!.path);
|
||||
if (result.success) {
|
||||
const fileList = result.files ?? [];
|
||||
if (!cancelled.current) setFiles(fileList);
|
||||
if (!cancelled.current) setDiffContent(result.diff ?? '');
|
||||
// Select all files by default
|
||||
if (!cancelled.current)
|
||||
setSelectedFiles(new Set(fileList.map((f: FileStatus) => f.path)));
|
||||
}
|
||||
};
|
||||
|
||||
loadDiffs();
|
||||
} catch (err) {
|
||||
console.warn('Failed to load diffs for stash dialog:', err);
|
||||
if (!cancelled.current) {
|
||||
setLoadDiffsError(err instanceof Error ? err.message : 'Failed to load changes');
|
||||
}
|
||||
} finally {
|
||||
if (!cancelled.current) setIsLoadingDiffs(false);
|
||||
}
|
||||
},
|
||||
[worktree]
|
||||
);
|
||||
|
||||
// Load diffs when dialog opens
|
||||
useEffect(() => {
|
||||
if (open && worktree) {
|
||||
const cancelled = { current: false };
|
||||
loadDiffs(cancelled);
|
||||
return () => {
|
||||
cancelled = true;
|
||||
cancelled.current = true;
|
||||
};
|
||||
}
|
||||
}, [open, worktree]);
|
||||
}, [open, worktree, loadDiffs]);
|
||||
|
||||
const handleToggleFile = useCallback((filePath: string) => {
|
||||
setSelectedFiles((prev) => {
|
||||
@@ -466,6 +472,20 @@ export function StashChangesDialog({
|
||||
<Spinner size="sm" className="mr-2" />
|
||||
<span className="text-sm">Loading changes...</span>
|
||||
</div>
|
||||
) : loadDiffsError ? (
|
||||
<div className="flex flex-col items-center justify-center py-6 gap-2 border border-border rounded-lg">
|
||||
<span className="text-sm text-destructive">Failed to load changes</span>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
const cancelled = { current: false };
|
||||
loadDiffs(cancelled);
|
||||
}}
|
||||
>
|
||||
Retry
|
||||
</Button>
|
||||
</div>
|
||||
) : files.length === 0 ? (
|
||||
<div className="flex items-center justify-center py-6 text-muted-foreground border border-border rounded-lg">
|
||||
<span className="text-sm">No changes detected</span>
|
||||
|
||||
@@ -1151,6 +1151,9 @@ export function useBoardActions({
|
||||
if (result.success) {
|
||||
// Refresh features from server to sync React Query cache
|
||||
loadFeatures();
|
||||
toast.success('All verified features archived', {
|
||||
description: `Archived ${verifiedFeatures.length} feature(s).`,
|
||||
});
|
||||
} else {
|
||||
logger.error('Bulk archive failed:', result);
|
||||
// Reload features to sync state with server
|
||||
@@ -1162,10 +1165,6 @@ export function useBoardActions({
|
||||
// Reload features to sync state with server on error
|
||||
loadFeatures();
|
||||
}
|
||||
|
||||
toast.success('All verified features archived', {
|
||||
description: `Archived ${verifiedFeatures.length} feature(s).`,
|
||||
});
|
||||
}, [features, runningAutoTasks, autoMode, updateFeature, currentProject, loadFeatures]);
|
||||
|
||||
const handleDuplicateFeature = useCallback(
|
||||
|
||||
Reference in New Issue
Block a user