bin/worktree: idempotent provision subcommand + .agents/provision hook#2732
bin/worktree: idempotent provision subcommand + .agents/provision hook#2732leshy wants to merge 3 commits into
Conversation
Factor 'new''s provisioning steps (.envrc symlink + uv venv + uv sync --all-groups + direnv allow) into 'bin/worktree provision [dir]', which provisions an EXISTING worktree in place and is idempotent; 'new' now calls it. Add executable .agents/provision at the repo root — a 2-line shim over 'bin/worktree provision' — so an agent harness can auto-set-up a freshly-cut worktree after a bare 'git worktree add'. Verified: provisioned a plain 'git worktree add' scratch tree; pytest 8.3.5, mypy 1.19.0, and 'import dimos' all resolve from the new .venv.
Greptile SummaryThis PR adds a reusable worktree provisioning path. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (3): Last reviewed commit: "fix: resolve .agents/provision when invo..." | Re-trigger Greptile |
| @@ -0,0 +1,3 @@ | |||
| #!/usr/bin/env bash | |||
| # Agent worktree provisioning hook: set this tree up (uv venv/sync, .envrc, direnv). | |||
| exec "$(dirname "$0")/../bin/worktree" provision "$@" | |||
There was a problem hiding this comment.
When an agent invokes this hook by basename from PATH, $0 is just provision, so dirname "$0" becomes . and the script tries to exec ../bin/worktree relative to the caller's current directory. A harness running from a scratch directory can fail before provisioning starts, even though the hook file was found correctly.
| exec "$(dirname "$0")/../bin/worktree" provision "$@" | |
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | |
| exec "$SCRIPT_DIR/../bin/worktree" provision "$@" |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| # allow. Idempotent, so it's safe to re-run and `new` calls it after adding | ||
| # the tree; you can also point it at a bare `git worktree add` dir to set it | ||
| # up after the fact. Defaults to the current directory. | ||
| local DIR="${1:-.}" resolved="" |
There was a problem hiding this comment.
Running bin/worktree provision with no directory now provisions whatever directory the caller is in. If the command is launched from the main checkout instead of a bare worktree, it can run uv venv and uv sync --all-groups against the main tree, which was not reachable through the old new-only provisioning path.
Review findings on #2732: - .agents/provision resolved bin/worktree via a relative dirname "$0", which breaks when invoked from PATH or another cwd; resolve absolutely. - `worktree provision` with no argument provisioned the caller's cwd, so running it from the main checkout would uv-venv/sync the main tree; default to the root of the tree the script lives in instead (explicit dir argument unchanged). REPO_ROOT is likewise anchored on the script location so the shim works from any cwd. - uv venv --allow-existing keeps re-provisioning idempotent with uv versions that refuse an existing .venv.
❌ 1 Tests Failed:
View the full list of 1 ❄️ flaky test(s)
To view more test analytics, go to the Test Analytics Dashboard |
|
Both findings fixed in 998d3ff: the .agents/provision shim now resolves its own directory absolutely ( |
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | ||
| exec "$SCRIPT_DIR/../bin/worktree" provision "$@" |
There was a problem hiding this comment.
When the hook is invoked by basename from PATH, $0 is just provision. In that case dirname "$0" becomes ., so SCRIPT_DIR becomes the caller's current directory and the shim tries to exec $PWD/../bin/worktree. A harness can find .agents/provision on PATH but still fail before provisioning starts when its cwd is not the worktree's .agents directory. Resolve $0 through PATH before deriving SCRIPT_DIR.
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | |
| exec "$SCRIPT_DIR/../bin/worktree" provision "$@" | |
| SELF=$0 | |
| case "$SELF" in | |
| */*) ;; | |
| *) SELF=$(command -v -- "$SELF") ;; | |
| esac | |
| SCRIPT_DIR="$(cd "$(dirname "$SELF")" && pwd)" | |
| exec "$SCRIPT_DIR/../bin/worktree" provision "$@" |
There was a problem hiding this comment.
Fixed in 5b3eaa8: the shim now resolves a slash-less $0 with command -v before computing SCRIPT_DIR, as suggested. Verified from /tmp that both absolute-path invocation and bare-basename-via-PATH invocation provision the script's own tree (/home/lesh/coding/dimos-worktree-provision), not the caller's cwd.
When the shim is run by basename via PATH, $0 has no slash and dirname yields "." (the caller's cwd again); look the name up with command -v first so SCRIPT_DIR is the script's real directory.
Factors the provisioning steps out of
bin/worktree newinto an idempotentbin/worktree provision [dir](newnow calls it), and adds a 2-line executable.agents/provisionshim exec-ing it.This is the repo side of the agent-harness worktree provisioning convention: any tool that cuts a plain
git worktree addtree (agent harnesses, CI) can run.agents/provisionto get a working uv venv + deps + direnv without knowing repo internals.Verified by provisioning a bare
git worktree addscratch tree: pytest, mypy andimport dimosall resolve from the freshly created .venv. Branch was itself dogfooded viabin/worktree new.