Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e27ff34
Fix non-functional '+ Add' button for multiple Claude accounts (#1216)
AndyMik90 Jan 17, 2026
3024d54
Fix screenshot state persistence bug in task modals (#1235)
AndyMik90 Jan 17, 2026
3085e39
Fix PR List Update on Post Status Click (#1207)
AndyMik90 Jan 17, 2026
c13d9a4
update gitignore
AndyMik90 Jan 17, 2026
9020446
fix(windows): prevent zombie process accumulation on app close (#1259)
VDT-91 Jan 17, 2026
75a3684
Fix terminal rendering, persistence, and link handling (#1215)
AndyMik90 Jan 17, 2026
ba089c5
fix: auto-commit .gitignore changes during project initialization (#1…
youngmrz Jan 17, 2026
39236f1
fix(terminal): sync worktree config after PTY creation to fix first-a…
AndyMik90 Jan 17, 2026
bff84fe
fix(windows): initialize known_marketplaces.json to prevent CLI crashes
youngmrz Jan 15, 2026
e17f19e
fix: eliminate TOCTOU race condition in known_marketplaces.json check
youngmrz Jan 15, 2026
c77252d
docs: explain why TOCTOU race in fixKnownMarketplacesJson is benign
youngmrz Jan 15, 2026
0d74c68
fix: use isWindows() from platform module instead of direct process.p…
youngmrz Jan 16, 2026
be97c96
refactor: simplify directory creation and consolidate imports
youngmrz Jan 16, 2026
02eb5cf
refactor: use platform abstraction for all process.platform checks in…
youngmrz Jan 17, 2026
3606a63
Draggable Kanban Task Reordering (#1217)
AndyMik90 Jan 17, 2026
d7ed770
fix: enforce 12 terminal limit per project (#1264)
AndyMik90 Jan 17, 2026
4cc8f4d
fix(pr-review): allow re-review when previous review failed (#1268)
AndyMik90 Jan 17, 2026
ea33189
Merge remote-tracking branch 'upstream/develop' into fix/windows-mark…
youngmrz Jan 17, 2026
44304a6
Fix False Stuck Detection During Planning Phase (#1236)
AndyMik90 Jan 17, 2026
f0c3e50
Fix/cleanup 2.7.5 (#1271)
AndyMik90 Jan 17, 2026
31c426d
Merge remote-tracking branch 'upstream/develop' into fix/windows-mark…
youngmrz Jan 17, 2026
7cb9e0a
fix(worktree): prevent cross-worktree file leakage via environment va…
AndyMik90 Jan 17, 2026
b04e32d
Merge remote-tracking branch 'upstream/develop' into fix/windows-mark…
youngmrz Jan 17, 2026
b865590
fix: add retry logic for planning-to-coding transition (#1276)
kaigler Jan 18, 2026
eb739af
fix(terminal): add require polyfill for ESM/Sentry compatibility (#1275)
VDT-91 Jan 18, 2026
5a45424
Merge branch 'develop' into fix/windows-marketplace-init
AndyMik90 Jan 18, 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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,5 @@ OPUS_ANALYSIS_AND_IDEAS.md

# Auto Claude generated files
.security-key
/shared_docs
/shared_docs
Agents.md
53 changes: 48 additions & 5 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,11 +1,52 @@
#!/bin/sh

# Preserve git worktree context - prevent HEAD corruption in worktrees
# =============================================================================
# GIT WORKTREE CONTEXT HANDLING
# =============================================================================
# When running in a worktree, we need to preserve git context to prevent HEAD
# corruption. However, we must also CLEAR these variables when NOT in a worktree
# to prevent cross-worktree contamination (files leaking between worktrees).
#
# The bug: If GIT_DIR/GIT_WORK_TREE are set from a previous worktree session
# and this hook runs in the main repo (where .git is a directory, not a file),
# git commands will target the wrong repository, causing files to appear as
# untracked in the wrong location.
#
# Fix: Explicitly unset these variables when NOT in a worktree context.
# =============================================================================

if [ -f ".git" ]; then
WORKTREE_GIT_DIR=$(sed 's/^gitdir: //' .git)
if [ -n "$WORKTREE_GIT_DIR" ]; then
# We're in a worktree (.git is a file pointing to the actual git dir)
# Use -n with /p to only print lines that match the gitdir: prefix, head -1 for safety
WORKTREE_GIT_DIR=$(sed -n 's/^gitdir: //p' .git | head -1)
if [ -n "$WORKTREE_GIT_DIR" ] && [ -d "$WORKTREE_GIT_DIR" ]; then
export GIT_DIR="$WORKTREE_GIT_DIR"
export GIT_WORK_TREE="$(pwd)"
else
# .git file exists but is malformed or points to non-existent directory
# CRITICAL: Clear any inherited GIT_DIR/GIT_WORK_TREE to prevent cross-worktree leakage
unset GIT_DIR
unset GIT_WORK_TREE
fi
else
# We're in the main repo (.git is a directory)
# CRITICAL: Clear any inherited GIT_DIR/GIT_WORK_TREE to prevent cross-worktree leakage
unset GIT_DIR
unset GIT_WORK_TREE
fi

# =============================================================================
# SAFETY CHECK: Detect and fix corrupted core.worktree configuration
# =============================================================================
# If core.worktree is set in the main repo's config (pointing to a worktree),
# this indicates previous corruption. Fix it automatically.
if [ ! -f ".git" ]; then
CORE_WORKTREE=$(git config --get core.worktree 2>/dev/null || true)
if [ -n "$CORE_WORKTREE" ]; then
echo "Warning: Detected corrupted core.worktree setting, removing it..."
if ! git config --unset core.worktree 2>/dev/null; then
echo "Warning: Failed to unset core.worktree. Manual intervention may be needed."
fi
fi
fi

Expand Down Expand Up @@ -62,8 +103,9 @@ if git diff --cached --name-only | grep -q "^package.json$"; then
sed -i.bak '/<!-- BETA_VERSION_BADGE -->/,/<!-- BETA_VERSION_BADGE_END -->/s|releases/tag/v[0-9.a-z-]*)|releases/tag/v'"$VERSION"')|g' README.md

# Update beta download links (within BETA_DOWNLOADS section only)
# Use perl for cross-platform compatibility (BSD sed doesn't support {block} syntax)
for SUFFIX in "win32-x64.exe" "darwin-arm64.dmg" "darwin-x64.dmg" "linux-x86_64.AppImage" "linux-amd64.deb" "linux-x86_64.flatpak"; do
sed -i.bak '/<!-- BETA_DOWNLOADS -->/,/<!-- BETA_DOWNLOADS_END -->/{s|Auto-Claude-[0-9.a-z-]*-'"$SUFFIX"'](https://github.com/AndyMik90/Auto-Claude/releases/download/v[^/]*/Auto-Claude-[^)]*-'"$SUFFIX"')|Auto-Claude-'"$VERSION"'-'"$SUFFIX"'](https://github.com/AndyMik90/Auto-Claude/releases/download/v'"$VERSION"'/Auto-Claude-'"$VERSION"'-'"$SUFFIX"')|g}' README.md
perl -i -pe 'if (/<!-- BETA_DOWNLOADS -->/ .. /<!-- BETA_DOWNLOADS_END -->/) { s|Auto-Claude-[0-9.a-z-]*-'"$SUFFIX"'\]\(https://github.com/AndyMik90/Auto-Claude/releases/download/v[^/]*/Auto-Claude-[^)]*-'"$SUFFIX"'\)|Auto-Claude-'"$VERSION"'-'"$SUFFIX"'](https://github.com/AndyMik90/Auto-Claude/releases/download/v'"$VERSION"'/Auto-Claude-'"$VERSION"'-'"$SUFFIX"')|g }' README.md
done
else
# STABLE: Update stable sections and top badge
Expand All @@ -78,8 +120,9 @@ if git diff --cached --name-only | grep -q "^package.json$"; then
sed -i.bak '/<!-- STABLE_VERSION_BADGE -->/,/<!-- STABLE_VERSION_BADGE_END -->/s|releases/tag/v[0-9.a-z-]*)|releases/tag/v'"$VERSION"')|g' README.md

# Update stable download links (within STABLE_DOWNLOADS section only)
# Use perl for cross-platform compatibility (BSD sed doesn't support {block} syntax)
for SUFFIX in "win32-x64.exe" "darwin-arm64.dmg" "darwin-x64.dmg" "linux-x86_64.AppImage" "linux-amd64.deb"; do
sed -i.bak '/<!-- STABLE_DOWNLOADS -->/,/<!-- STABLE_DOWNLOADS_END -->/{s|Auto-Claude-[0-9.a-z-]*-'"$SUFFIX"'](https://github.com/AndyMik90/Auto-Claude/releases/download/v[^/]*/Auto-Claude-[^)]*-'"$SUFFIX"')|Auto-Claude-'"$VERSION"'-'"$SUFFIX"'](https://github.com/AndyMik90/Auto-Claude/releases/download/v'"$VERSION"'/Auto-Claude-'"$VERSION"'-'"$SUFFIX"')|g}' README.md
perl -i -pe 'if (/<!-- STABLE_DOWNLOADS -->/ .. /<!-- STABLE_DOWNLOADS_END -->/) { s|Auto-Claude-[0-9.a-z-]*-'"$SUFFIX"'\]\(https://github.com/AndyMik90/Auto-Claude/releases/download/v[^/]*/Auto-Claude-[^)]*-'"$SUFFIX"'\)|Auto-Claude-'"$VERSION"'-'"$SUFFIX"'](https://github.com/AndyMik90/Auto-Claude/releases/download/v'"$VERSION"'/Auto-Claude-'"$VERSION"'-'"$SUFFIX"')|g }' README.md
done
fi

Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@
### Stable Release

<!-- STABLE_VERSION_BADGE -->
[![Stable](https://img.shields.io/badge/stable-2.7.4-blue?style=flat-square)](https://github.com/AndyMik90/Auto-Claude/releases/tag/v2.7.4)
[![Stable](https://img.shields.io/badge/stable-2.7.5-blue?style=flat-square)](https://github.com/AndyMik90/Auto-Claude/releases/tag/v2.7.5)
<!-- STABLE_VERSION_BADGE_END -->

<!-- STABLE_DOWNLOADS -->
| Platform | Download |
|----------|----------|
| **Windows** | [Auto-Claude-2.7.4-win32-x64.exe](https://github.com/AndyMik90/Auto-Claude/releases/download/v2.7.4/Auto-Claude-2.7.4-win32-x64.exe) |
| **macOS (Apple Silicon)** | [Auto-Claude-2.7.4-darwin-arm64.dmg](https://github.com/AndyMik90/Auto-Claude/releases/download/v2.7.4/Auto-Claude-2.7.4-darwin-arm64.dmg) |
| **macOS (Intel)** | [Auto-Claude-2.7.4-darwin-x64.dmg](https://github.com/AndyMik90/Auto-Claude/releases/download/v2.7.4/Auto-Claude-2.7.4-darwin-x64.dmg) |
| **Linux** | [Auto-Claude-2.7.4-linux-x86_64.AppImage](https://github.com/AndyMik90/Auto-Claude/releases/download/v2.7.4/Auto-Claude-2.7.4-linux-x86_64.AppImage) |
| **Linux (Debian)** | [Auto-Claude-2.7.4-linux-amd64.deb](https://github.com/AndyMik90/Auto-Claude/releases/download/v2.7.4/Auto-Claude-2.7.4-linux-amd64.deb) |
| **Windows** | [Auto-Claude-2.7.5-win32-x64.exe](https://github.com/AndyMik90/Auto-Claude/releases/download/v2.7.5/Auto-Claude-2.7.5-win32-x64.exe) |
| **macOS (Apple Silicon)** | [Auto-Claude-2.7.5-darwin-arm64.dmg](https://github.com/AndyMik90/Auto-Claude/releases/download/v2.7.5/Auto-Claude-2.7.5-darwin-arm64.dmg) |
| **macOS (Intel)** | [Auto-Claude-2.7.5-darwin-x64.dmg](https://github.com/AndyMik90/Auto-Claude/releases/download/v2.7.5/Auto-Claude-2.7.5-darwin-x64.dmg) |
| **Linux** | [Auto-Claude-2.7.5-linux-x86_64.AppImage](https://github.com/AndyMik90/Auto-Claude/releases/download/v2.7.5/Auto-Claude-2.7.5-linux-x86_64.AppImage) |
| **Linux (Debian)** | [Auto-Claude-2.7.5-linux-amd64.deb](https://github.com/AndyMik90/Auto-Claude/releases/download/v2.7.5/Auto-Claude-2.7.5-linux-amd64.deb) |
| **Linux (Flatpak)** | [Auto-Claude-2.7.4-linux-x86_64.flatpak](https://github.com/AndyMik90/Auto-Claude/releases/download/v2.7.4/Auto-Claude-2.7.4-linux-x86_64.flatpak) |
<!-- STABLE_DOWNLOADS_END -->

Expand Down
2 changes: 1 addition & 1 deletion apps/backend/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@
See README.md for full documentation.
"""

__version__ = "2.7.4"
__version__ = "2.7.5"
__author__ = "Auto Claude Team"
33 changes: 31 additions & 2 deletions apps/backend/agents/coder.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,9 @@ def _validate_and_fix_implementation_plan() -> tuple[bool, list[str]]:
task_logger.set_session(iteration)
else:
# Switch to coding phase after planning
just_transitioned_from_planning = False
if is_planning_phase:
just_transitioned_from_planning = True
is_planning_phase = False
current_log_phase = LogPhase.CODING
emit_phase(ExecutionPhase.CODING, "Starting implementation")
Expand All @@ -338,8 +340,35 @@ def _validate_and_fix_implementation_plan() -> tuple[bool, list[str]]:
print_status("Phase transition synced to main project", "success")

if not next_subtask:
print("No pending subtasks found - build may be complete!")
break
# FIX for Issue #495: Race condition after planning phase
# The implementation_plan.json may not be fully flushed to disk yet,
# or there may be a brief delay before subtasks become available.
# Retry with exponential backoff before giving up.
if just_transitioned_from_planning:
print_status(
"Waiting for implementation plan to be ready...", "progress"
)
for retry_attempt in range(3):
delay = (retry_attempt + 1) * 2 # 2s, 4s, 6s
await asyncio.sleep(delay)
next_subtask = get_next_subtask(spec_dir)
if next_subtask:
# Update subtask_id and phase_name after successful retry
subtask_id = next_subtask.get("id")
phase_name = next_subtask.get("phase_name")
print_status(
f"Found subtask {subtask_id} after {delay}s delay",
"success",
)
break
print_status(
f"Retry {retry_attempt + 1}/3: No subtask found yet...",
"warning",
)

if not next_subtask:
print("No pending subtasks found - build may be complete!")
break

# Get attempt count for recovery context
attempt_count = recovery_manager.get_attempt_count(subtask_id)
Expand Down
62 changes: 59 additions & 3 deletions apps/backend/core/git_executable.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#!/usr/bin/env python3
"""
Git Executable Finder
======================
Git Executable Finder and Isolation
====================================

Utility to find the git executable, with Windows-specific fallbacks.
Also provides environment isolation to prevent pre-commit hooks and
other git configurations from affecting worktree operations.

Separated into its own module to avoid circular imports.
"""

Expand All @@ -12,9 +15,53 @@
import subprocess
from pathlib import Path

# Git environment variables that can interfere with worktree operations
# when set by pre-commit hooks or other git configurations.
# These must be cleared to prevent cross-worktree contamination.
GIT_ENV_VARS_TO_CLEAR = [
"GIT_DIR",
"GIT_WORK_TREE",
"GIT_INDEX_FILE",
"GIT_OBJECT_DIRECTORY",
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
# Identity variables that could be set by hooks
"GIT_AUTHOR_NAME",
"GIT_AUTHOR_EMAIL",
"GIT_AUTHOR_DATE",
"GIT_COMMITTER_NAME",
"GIT_COMMITTER_EMAIL",
"GIT_COMMITTER_DATE",
]

_cached_git_path: str | None = None


def get_isolated_git_env(base_env: dict | None = None) -> dict:
"""
Create an isolated environment for git operations.

Clears git environment variables that may be set by pre-commit hooks
or other git configurations, preventing cross-worktree contamination
and ensuring git operations target the intended repository.

Args:
base_env: Base environment dict to copy from. If None, uses os.environ.

Returns:
Environment dict safe for git subprocess operations.
"""
env = dict(base_env) if base_env is not None else os.environ.copy()

for key in GIT_ENV_VARS_TO_CLEAR:
env.pop(key, None)

# Disable user's pre-commit hooks during Auto-Claude managed git operations
# to prevent double-hook execution and potential conflicts
env["HUSKY"] = "0"

return env


def get_git_executable() -> str:
"""Find the git executable, with Windows-specific fallbacks.

Expand Down Expand Up @@ -102,19 +149,27 @@ def run_git(
cwd: Path | str | None = None,
timeout: int = 60,
input_data: str | None = None,
env: dict | None = None,
isolate_env: bool = True,
) -> subprocess.CompletedProcess:
"""Run a git command with proper executable finding.
"""Run a git command with proper executable finding and environment isolation.

Args:
args: Git command arguments (without 'git' prefix)
cwd: Working directory for the command
timeout: Command timeout in seconds (default: 60)
input_data: Optional string data to pass to stdin
env: Custom environment dict. If None and isolate_env=True, uses isolated env.
isolate_env: If True (default), clears git env vars to prevent hook interference.

Returns:
CompletedProcess with command results.
"""
git = get_git_executable()

if env is None and isolate_env:
env = get_isolated_git_env()

try:
return subprocess.run(
[git] + args,
Expand All @@ -125,6 +180,7 @@ def run_git(
encoding="utf-8",
errors="replace",
timeout=timeout,
env=env,
)
except subprocess.TimeoutExpired:
return subprocess.CompletedProcess(
Expand Down
Loading
Loading