From 55fa48bc166298168342ef64b7f8bcaaf604e2b1 Mon Sep 17 00:00:00 2001 From: NagyVikt Date: Mon, 27 Apr 2026 12:31:56 +0200 Subject: [PATCH] Keep worktree Python commands on repo venv Agent sandboxes already link JavaScript dependency directories from the primary checkout, but Python commands like .venv/bin/python3 still failed inside new worktrees because .venv was absent. Link the root .venv during branch bootstrap so Claude and Codex commands that assume repo-relative Python keep resolving inside the sandbox. Constraint: Claude runs hooks and Bash commands from sandbox worktree cwd. Rejected: Rewrite every Claude command to an absolute recodee path | leaves other repos and direct user commands with the same worktree-layout failure. Confidence: high Scope-risk: narrow Directive: Keep scripts/agent-branch-start.sh and templates/scripts/agent-branch-start.sh in sync for managed setup installs. Tested: bash -n scripts/agent-branch-start.sh templates/scripts/agent-branch-start.sh Tested: node --test test/branch.test.js Co-authored-by: OmX --- scripts/agent-branch-start.sh | 1 + templates/scripts/agent-branch-start.sh | 1 + test/branch.test.js | 14 +++++++++++--- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/scripts/agent-branch-start.sh b/scripts/agent-branch-start.sh index de46199..bfeab2f 100755 --- a/scripts/agent-branch-start.sh +++ b/scripts/agent-branch-start.sh @@ -681,6 +681,7 @@ if [[ -n "$auto_transfer_stash_ref" ]]; then fi fi +hydrate_dependency_dir_symlink_in_worktree "$repo_root" "$worktree_path" ".venv" hydrate_dependency_dir_symlink_in_worktree "$repo_root" "$worktree_path" "node_modules" hydrate_dependency_dir_symlink_in_worktree "$repo_root" "$worktree_path" "apps/frontend/node_modules" hydrate_dependency_dir_symlink_in_worktree "$repo_root" "$worktree_path" "apps/backend/node_modules" diff --git a/templates/scripts/agent-branch-start.sh b/templates/scripts/agent-branch-start.sh index de46199..bfeab2f 100755 --- a/templates/scripts/agent-branch-start.sh +++ b/templates/scripts/agent-branch-start.sh @@ -681,6 +681,7 @@ if [[ -n "$auto_transfer_stash_ref" ]]; then fi fi +hydrate_dependency_dir_symlink_in_worktree "$repo_root" "$worktree_path" ".venv" hydrate_dependency_dir_symlink_in_worktree "$repo_root" "$worktree_path" "node_modules" hydrate_dependency_dir_symlink_in_worktree "$repo_root" "$worktree_path" "apps/frontend/node_modules" hydrate_dependency_dir_symlink_in_worktree "$repo_root" "$worktree_path" "apps/backend/node_modules" diff --git a/test/branch.test.js b/test/branch.test.js index 129c04a..beb87b5 100644 --- a/test/branch.test.js +++ b/test/branch.test.js @@ -269,7 +269,7 @@ test('agent-branch-start leaves removed workflow helpers out of new worktrees', }); -test('agent-branch-start links dependency node_modules directories into new worktrees when present', () => { +test('agent-branch-start links dependency directories into new worktrees when present', () => { const repoDir = initRepo(); seedCommit(repoDir); @@ -284,19 +284,22 @@ test('agent-branch-start links dependency node_modules directories into new work assert.equal(result.status, 0, result.stderr || result.stdout); const infoExcludePath = path.join(repoDir, '.git', 'info', 'exclude'); - fs.appendFileSync(infoExcludePath, '\napps/frontend/node_modules\napps/backend/node_modules\n', 'utf8'); + fs.appendFileSync(infoExcludePath, '\n.venv\napps/frontend/node_modules\napps/backend/node_modules\n', 'utf8'); - const dependencyDirs = ['node_modules', 'apps/frontend/node_modules', 'apps/backend/node_modules']; + const dependencyDirs = ['.venv', 'node_modules', 'apps/frontend/node_modules', 'apps/backend/node_modules']; for (const relativeDir of dependencyDirs) { const sourceDir = path.join(repoDir, relativeDir); fs.mkdirSync(sourceDir, { recursive: true }); fs.writeFileSync(path.join(sourceDir, '.guardex-link-marker'), 'present\n', 'utf8'); } + fs.mkdirSync(path.join(repoDir, '.venv', 'bin'), { recursive: true }); + fs.writeFileSync(path.join(repoDir, '.venv', 'bin', 'python3'), '#!/usr/bin/env python3\n', 'utf8'); result = runBranchStart(['hydrate-deps', 'bot'], repoDir, { GUARDEX_PROTECTED_BRANCHES: 'main', }); assert.equal(result.status, 0, result.stderr || result.stdout); + assert.match(result.stdout, /Linked dependency dir in worktree: \.venv/); assert.match(result.stdout, /Linked dependency dir in worktree: node_modules/); assert.match(result.stdout, /Linked dependency dir in worktree: apps\/frontend\/node_modules/); assert.match(result.stdout, /Linked dependency dir in worktree: apps\/backend\/node_modules/); @@ -314,6 +317,11 @@ test('agent-branch-start links dependency node_modules directories into new work `symlink should expose source contents: ${relativeDir}`, ); } + assert.equal( + fs.existsSync(path.join(createdWorktree, '.venv', 'bin', 'python3')), + true, + 'worktree-local .venv/bin/python3 should resolve through the source venv symlink', + ); });