Improvement/Worktree needs to be manually deleted for early access safety (not delete work that has introduced spend)
This commit is contained in:
@@ -112,9 +112,13 @@ export function TaskReview({
|
||||
onMerge={onMerge}
|
||||
/>
|
||||
) : task.stagedInMainProject ? (
|
||||
<StagedInProjectMessage task={task} />
|
||||
<StagedInProjectMessage
|
||||
task={task}
|
||||
projectPath={stagedProjectPath}
|
||||
hasWorktree={worktreeStatus?.exists || false}
|
||||
/>
|
||||
) : (
|
||||
<NoWorkspaceMessage />
|
||||
<NoWorkspaceMessage task={task} />
|
||||
)}
|
||||
|
||||
{/* QA Feedback Section */}
|
||||
|
||||
+113
-5
@@ -1,4 +1,7 @@
|
||||
import { AlertCircle, GitMerge, Loader2 } from 'lucide-react';
|
||||
import { AlertCircle, GitMerge, Loader2, Trash2, Check } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { Button } from '../../ui/button';
|
||||
import { persistTaskStatus } from '../../../stores/task-store';
|
||||
import type { Task } from '../../../../shared/types';
|
||||
|
||||
interface LoadingMessageProps {
|
||||
@@ -19,31 +22,103 @@ export function LoadingMessage({ message = 'Loading workspace info...' }: Loadin
|
||||
);
|
||||
}
|
||||
|
||||
interface NoWorkspaceMessageProps {
|
||||
task?: Task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays message when no workspace is found for the task
|
||||
*/
|
||||
export function NoWorkspaceMessage() {
|
||||
export function NoWorkspaceMessage({ task }: NoWorkspaceMessageProps) {
|
||||
const [isMarkingDone, setIsMarkingDone] = useState(false);
|
||||
|
||||
const handleMarkDone = async () => {
|
||||
if (!task) return;
|
||||
|
||||
setIsMarkingDone(true);
|
||||
try {
|
||||
await persistTaskStatus(task.id, 'done');
|
||||
} catch (err) {
|
||||
console.error('Error marking task as done:', err);
|
||||
} finally {
|
||||
setIsMarkingDone(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="rounded-xl border border-border bg-secondary/30 p-4">
|
||||
<h3 className="font-medium text-sm text-foreground mb-2 flex items-center gap-2">
|
||||
<AlertCircle className="h-4 w-4 text-muted-foreground" />
|
||||
No Workspace Found
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
<p className="text-sm text-muted-foreground mb-3">
|
||||
No isolated workspace was found for this task. The changes may have been made directly in your project.
|
||||
</p>
|
||||
|
||||
{/* Allow marking as done */}
|
||||
{task && task.status === 'human_review' && (
|
||||
<Button
|
||||
onClick={handleMarkDone}
|
||||
disabled={isMarkingDone}
|
||||
size="sm"
|
||||
variant="default"
|
||||
className="w-full"
|
||||
>
|
||||
{isMarkingDone ? (
|
||||
<>
|
||||
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
|
||||
Updating...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Check className="h-4 w-4 mr-2" />
|
||||
Mark as Done
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface StagedInProjectMessageProps {
|
||||
task: Task;
|
||||
projectPath?: string;
|
||||
hasWorktree?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays message when changes have already been staged in the main project
|
||||
*/
|
||||
export function StagedInProjectMessage({ task }: StagedInProjectMessageProps) {
|
||||
export function StagedInProjectMessage({ task, projectPath, hasWorktree = false }: StagedInProjectMessageProps) {
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const handleDeleteWorktreeAndMarkDone = async () => {
|
||||
setIsDeleting(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
// Call the discard/delete worktree command
|
||||
const result = await window.electronAPI.discardWorktree(task.id);
|
||||
|
||||
if (!result.success) {
|
||||
setError(result.error || 'Failed to delete worktree');
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark task as done
|
||||
await persistTaskStatus(task.id, 'done');
|
||||
|
||||
// Success - the UI will update automatically via the store
|
||||
} catch (err) {
|
||||
console.error('Error deleting worktree:', err);
|
||||
setError(err instanceof Error ? err.message : 'Failed to delete worktree');
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="rounded-xl border border-success/30 bg-success/10 p-4">
|
||||
<h3 className="font-medium text-sm text-foreground mb-2 flex items-center gap-2">
|
||||
@@ -53,7 +128,7 @@ export function StagedInProjectMessage({ task }: StagedInProjectMessageProps) {
|
||||
<p className="text-sm text-muted-foreground mb-3">
|
||||
This task's changes have been staged in your main project{task.stagedAt ? ` on ${new Date(task.stagedAt).toLocaleDateString()}` : ''}.
|
||||
</p>
|
||||
<div className="bg-background/50 rounded-lg p-3">
|
||||
<div className="bg-background/50 rounded-lg p-3 mb-3">
|
||||
<p className="text-xs text-muted-foreground mb-2">Next steps:</p>
|
||||
<ol className="text-xs text-muted-foreground space-y-1 list-decimal list-inside">
|
||||
<li>Review staged changes with <code className="bg-background px-1 rounded">git status</code> and <code className="bg-background px-1 rounded">git diff --staged</code></li>
|
||||
@@ -61,6 +136,39 @@ export function StagedInProjectMessage({ task }: StagedInProjectMessageProps) {
|
||||
<li>Push to remote when satisfied</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
{/* Action buttons */}
|
||||
{hasWorktree && (
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
onClick={handleDeleteWorktreeAndMarkDone}
|
||||
disabled={isDeleting}
|
||||
size="sm"
|
||||
variant="default"
|
||||
className="flex-1"
|
||||
>
|
||||
{isDeleting ? (
|
||||
<>
|
||||
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
|
||||
Cleaning up...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Check className="h-4 w-4 mr-2" />
|
||||
Delete Worktree & Mark Done
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
{error && (
|
||||
<p className="text-xs text-destructive">{error}</p>
|
||||
)}
|
||||
<p className="text-xs text-muted-foreground">
|
||||
This will delete the isolated workspace and mark the task as complete.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -197,22 +197,20 @@ def merge_existing_build(
|
||||
|
||||
if had_conflicts:
|
||||
# Git conflicts were resolved (via AI or lock file exclusion) - changes are already staged
|
||||
_print_merge_success(no_commit, stats)
|
||||
_print_merge_success(no_commit, stats, spec_name=spec_name, keep_worktree=True)
|
||||
|
||||
# Cleanup the worktree since merge is done
|
||||
try:
|
||||
manager.remove_worktree(spec_name, delete_branch=True)
|
||||
except Exception:
|
||||
pass # Best effort cleanup
|
||||
# Don't auto-delete worktree - let user test and manually cleanup
|
||||
# User can delete with: python auto-claude/run.py --spec <name> --discard
|
||||
# Or via UI "Delete Worktree" button
|
||||
|
||||
return True
|
||||
else:
|
||||
# No git conflicts, do standard git merge
|
||||
success_result = manager.merge_worktree(
|
||||
spec_name, delete_after=True, no_commit=no_commit
|
||||
spec_name, delete_after=False, no_commit=no_commit
|
||||
)
|
||||
if success_result:
|
||||
_print_merge_success(no_commit, stats)
|
||||
_print_merge_success(no_commit, stats, spec_name=spec_name, keep_worktree=True)
|
||||
return True
|
||||
elif smart_result.get("git_conflicts"):
|
||||
# Had git conflicts that AI couldn't fully resolve
|
||||
@@ -247,7 +245,7 @@ def merge_existing_build(
|
||||
|
||||
# Fall back to standard git merge
|
||||
success_result = manager.merge_worktree(
|
||||
spec_name, delete_after=True, no_commit=no_commit
|
||||
spec_name, delete_after=False, no_commit=no_commit
|
||||
)
|
||||
|
||||
if success_result:
|
||||
@@ -258,10 +256,13 @@ def merge_existing_build(
|
||||
print("Review the changes in your IDE, then commit:")
|
||||
print(highlight(" git commit -m 'your commit message'"))
|
||||
print()
|
||||
print("Or discard if not satisfied:")
|
||||
print(muted(" git reset --hard HEAD"))
|
||||
print("When satisfied, delete the worktree:")
|
||||
print(muted(f" python auto-claude/run.py --spec {spec_name} --discard"))
|
||||
else:
|
||||
print_status("Your feature has been added to your project.", "success")
|
||||
print()
|
||||
print("When satisfied, delete the worktree:")
|
||||
print(muted(f" python auto-claude/run.py --spec {spec_name} --discard"))
|
||||
return True
|
||||
else:
|
||||
print()
|
||||
|
||||
@@ -70,7 +70,12 @@ def show_changed_files(manager: WorktreeManager, spec_name: str) -> None:
|
||||
print(f" {status} {filepath}")
|
||||
|
||||
|
||||
def print_merge_success(no_commit: bool, stats: dict | None = None) -> None:
|
||||
def print_merge_success(
|
||||
no_commit: bool,
|
||||
stats: dict | None = None,
|
||||
spec_name: str | None = None,
|
||||
keep_worktree: bool = False
|
||||
) -> None:
|
||||
"""Print a success message after merge."""
|
||||
from ui import Icons, box, icon
|
||||
|
||||
@@ -88,6 +93,12 @@ def print_merge_success(no_commit: bool, stats: dict | None = None) -> None:
|
||||
lines.append("Note: Lock files kept from main.")
|
||||
lines.append("Regenerate: npm install / pip install / cargo update")
|
||||
|
||||
# Add worktree cleanup instructions
|
||||
if keep_worktree and spec_name:
|
||||
lines.append("")
|
||||
lines.append("Worktree kept for testing. Delete when satisfied:")
|
||||
lines.append(f" python auto-claude/run.py --spec {spec_name} --discard")
|
||||
|
||||
content = lines
|
||||
else:
|
||||
lines = [
|
||||
@@ -111,12 +122,23 @@ def print_merge_success(no_commit: bool, stats: dict | None = None) -> None:
|
||||
)
|
||||
lines.append("")
|
||||
|
||||
lines.extend(
|
||||
[
|
||||
"Your new feature is now part of your project.",
|
||||
"The separate workspace has been cleaned up.",
|
||||
]
|
||||
)
|
||||
if keep_worktree:
|
||||
lines.extend(
|
||||
[
|
||||
"Your new feature is now part of your project.",
|
||||
"",
|
||||
"Worktree kept for testing. Delete when satisfied:",
|
||||
]
|
||||
)
|
||||
if spec_name:
|
||||
lines.append(f" python auto-claude/run.py --spec {spec_name} --discard")
|
||||
else:
|
||||
lines.extend(
|
||||
[
|
||||
"Your new feature is now part of your project.",
|
||||
"The separate workspace has been cleaned up.",
|
||||
]
|
||||
)
|
||||
content = lines
|
||||
|
||||
print()
|
||||
|
||||
Reference in New Issue
Block a user