Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
e61b22c
fix(worktree): filter worktrees by branch pattern and handle orphaned…
Orinks Jan 12, 2026
4747728
chore: add tmpclaude-* to gitignore
Orinks Jan 12, 2026
61ec001
refactor: use top-level rmSync import instead of dynamic require
Orinks Jan 12, 2026
4b1dd4b
fix(tests): make frontend tests cross-platform compatible
Orinks Jan 12, 2026
06b19e5
fix(types): add missing canSkipCleanup and skipCleanup to updateTaskS…
Orinks Jan 12, 2026
1220e57
fix: address code review feedback from Gemini
Orinks Jan 12, 2026
b703d94
refactor: extract BASE_BRANCHES constant to shared location
Orinks Jan 12, 2026
0f4e5b3
refactor: move WorktreeCleanupDialogState type and constant to module…
Orinks Jan 12, 2026
62db459
refactor: extract worktree cleanup helpers to reduce cyclomatic compl…
Orinks Jan 12, 2026
ffc23d6
fix: add cross-language constant validation and debug logging
Orinks Jan 12, 2026
f0da17c
fix: address Auto Claude PR review feedback for worktree handling
Orinks Jan 13, 2026
cc7be0d
fix: remove useless conditional flagged by GitHub security scanner
Orinks Jan 13, 2026
ccaf26e
fix: stop file watcher before worktree cleanup to prevent Windows fil…
Orinks Jan 13, 2026
99c581b
Update tests/test_worktree.py
Orinks Jan 13, 2026
c042f62
fix: propagate orphaned worktree cleanup errors to UI
Orinks Jan 13, 2026
6edb3bb
fix: unwatch file watcher when auto-stopping task on status change
Orinks Jan 13, 2026
a4a2ccb
fix: address additional review feedback
Orinks Jan 12, 2026
799849f
fix: export BASE_BRANCHES constant from Python worktree module
Orinks Jan 13, 2026
62ca32f
fix: surface git error details in merge failure message
Orinks Jan 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ lerna-debug.log*
.auto-claude-status
.claude_settings.json
.update-metadata.json
tmpclaude-*

# ===========================
# Python (apps/backend)
Expand Down
36 changes: 12 additions & 24 deletions apps/backend/core/worktree.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@

T = TypeVar("T")

# Base branches that should be filtered out when listing worktrees
# These indicate orphaned worktrees (e.g., after GitHub PR merge)
# NOTE: Keep in sync with BASE_BRANCHES in apps/frontend/src/shared/constants/git.ts
BASE_BRANCHES = frozenset({"main", "master", "develop", "head"})


def _is_retryable_network_error(stderr: str) -> bool:
"""Check if an error is a retryable network/connection issue."""
Expand Down Expand Up @@ -647,29 +652,10 @@ def merge_worktree(
result = self._run_git(merge_args)

if result.returncode != 0:
# Check if it's "already up to date" - not an error
output = (result.stdout + result.stderr).lower()
if "already up to date" in output or "already up-to-date" in output:
print(f"Branch {info.branch} is already up to date.")
if no_commit:
print("No changes to stage.")
if delete_after:
self.remove_worktree(spec_name, delete_branch=True)
return True
# Check for actual conflicts
if "conflict" in output:
print("Merge conflict! Aborting merge...")
self._run_git(["merge", "--abort"])
return False
# Other error - show details
stderr_msg = (
result.stderr[:200]
if result.stderr
else result.stdout[:200]
if result.stdout
else "<no output>"
error_detail = (
result.stderr.strip() or result.stdout.strip() or "Unknown error"
)
print(f"Merge failed: {stderr_msg}")
print(f"Merge failed: {error_detail}")
self._run_git(["merge", "--abort"])
return False

Expand Down Expand Up @@ -719,7 +705,8 @@ def list_all_worktrees(self) -> list[WorktreeInfo]:
for item in self.worktrees_dir.iterdir():
if item.is_dir():
info = self.get_worktree_info(item.name)
if info:
# Skip worktrees on base branches (orphaned after GitHub merge)
if info and info.branch.lower() not in BASE_BRANCHES:
worktrees.append(info)
seen_specs.add(item.name)

Expand All @@ -729,7 +716,8 @@ def list_all_worktrees(self) -> list[WorktreeInfo]:
for item in legacy_dir.iterdir():
if item.is_dir() and item.name not in seen_specs:
info = self.get_worktree_info(item.name)
if info:
# Skip worktrees on base branches (orphaned after GitHub merge)
if info and info.branch.lower() not in BASE_BRANCHES:
worktrees.append(info)

return worktrees
Expand Down
7 changes: 4 additions & 3 deletions apps/frontend/src/main/__tests__/insights-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,8 @@ describe('InsightsConfig', () => {
expect(env.CLAUDE_CODE_OAUTH_TOKEN).toBe('oauth-token');
expect(env.ANTHROPIC_BASE_URL).toBe('https://api.z.ai');
expect(env.ANTHROPIC_AUTH_TOKEN).toBe('key');
expect(env.PYTHONPATH).toBe(
[path.resolve('/site-packages'), path.resolve('/backend')].join(path.delimiter)
);
// path.resolve() normalizes paths to platform-specific format
expect(env.PYTHONPATH).toBe([path.resolve('/site-packages'), path.resolve('/backend')].join(path.delimiter));
});

it('should clear ANTHROPIC env vars in OAuth mode when no API profile is set', async () => {
Expand All @@ -86,6 +85,7 @@ describe('InsightsConfig', () => {

const env = await config.getProcessEnv();

// path.resolve() normalizes paths to platform-specific format
expect(env.PYTHONPATH).toBe(path.resolve('/backend'));
});

Expand All @@ -96,6 +96,7 @@ describe('InsightsConfig', () => {

const env = await config.getProcessEnv();

// path.resolve() normalizes paths to platform-specific format
expect(env.PYTHONPATH).toBe(path.resolve('/site-packages'));
});
});
Loading
Loading