Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 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
c65c632
fix(agent): surface meaningful error messages from stderr in UI
youngmrz Jan 15, 2026
b36492c
fix(agent): surface stderr errors for ideation and roadmap runners
youngmrz Jan 15, 2026
095f706
fix: add missing extractErrorMessage function and stderrCollected var…
youngmrz Jan 15, 2026
b34f9bf
refactor: extract shared error message utility (DRY)
youngmrz Jan 16, 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
12f29b0
Merge remote-tracking branch 'upstream/develop' into fix/error-surfacing
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
4a235e4
Merge remote-tracking branch 'upstream/develop' into fix/error-surfacing
youngmrz Jan 17, 2026
7cb9e0a
fix(worktree): prevent cross-worktree file leakage via environment va…
AndyMik90 Jan 17, 2026
a93742a
Merge remote-tracking branch 'upstream/develop' into fix/error-surfacing
youngmrz Jan 17, 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"
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