fix(init): chmod +x workspace hooks in OVERRIDE mode too (#359)
`agnes init` ran `_chmod_workspace_hooks(workspace)` only in DEFAULT mode (inside `if not override_active:`). The OVERRIDE path — used for Initial-Workspace-Template seed-repo flows where the admin's template repo is cloned into the workspace — silently skipped chmod. When the seed repo's git checkout didn't preserve the +x bit (filemode=false, archive extractions, FUSE/NFS mounts), hooks like `.claude/hooks/skill-nudge/nudge.sh` and `.claude/hooks/prompt-history/log-prompt.sh` landed non-executable and every SessionStart fired `Permission denied`. The chmod helper itself already recurses (`rglob`) so the subdir-scoped hook layouts were covered — the bug was the call site. Moved the call out of the override gate to a common step before the first pull. Both DEFAULT and OVERRIDE paths now chmod hooks before the first SessionStart can fire.
This commit is contained in:
parent
a8fe4e8b21
commit
0c9e172ce1
2 changed files with 31 additions and 1 deletions
15
CHANGELOG.md
15
CHANGELOG.md
|
|
@ -10,6 +10,21 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
- `agnes init` now runs `_chmod_workspace_hooks(workspace)` for OVERRIDE
|
||||
mode too (Initial Workspace Template seed-repo flow), not just the
|
||||
DEFAULT path. Override-mode workspaces seeded from an admin's
|
||||
template repo were leaving hooks like
|
||||
`.claude/hooks/skill-nudge/nudge.sh` and
|
||||
`.claude/hooks/prompt-history/log-prompt.sh` non-executable when
|
||||
the seed repo's git checkout didn't preserve the +x bit
|
||||
(`core.filemode=false`, archive extractions, FUSE/NFS mounts), and
|
||||
every SessionStart fired `Permission denied`. The chmod helper
|
||||
already recurses (`rglob`) so subdir-scoped hook layouts were
|
||||
covered — the bug was that the call site sat inside the
|
||||
`if not override_active:` block. Moved out to a common step
|
||||
before the first pull so every init path runs it.
|
||||
|
||||
## [0.55.4] — 2026-05-19
|
||||
|
||||
### Security
|
||||
|
|
|
|||
|
|
@ -493,7 +493,6 @@ def init(
|
|||
), encoding="utf-8")
|
||||
install_claude_hooks(workspace)
|
||||
install_claude_commands(workspace)
|
||||
_chmod_workspace_hooks(workspace)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Step 6: CLAUDE.local.md stub — only when absent. `--force` does NOT
|
||||
|
|
@ -511,6 +510,22 @@ def init(
|
|||
encoding="utf-8",
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Always chmod +x hook scripts that landed on disk, regardless of
|
||||
# which path seeded the workspace. In DEFAULT mode the hooks come
|
||||
# from `install_claude_hooks` above; in OVERRIDE mode they come
|
||||
# from the admin's initial-workspace-template clone — and `git
|
||||
# checkout` of that template doesn't reliably preserve the +x bit
|
||||
# (filemode=false repos, archive extractions, FUSE/NFS mounts),
|
||||
# so hooks like `.claude/hooks/skill-nudge/nudge.sh` or
|
||||
# `.claude/hooks/prompt-history/log-prompt.sh` could land non-
|
||||
# executable and fire `Permission denied` on the very next
|
||||
# SessionStart. `_chmod_workspace_hooks` recurses (`rglob`) so
|
||||
# subdir-scoped hook layouts are covered. Best-effort, no-op on
|
||||
# Windows NTFS.
|
||||
# ------------------------------------------------------------------
|
||||
_chmod_workspace_hooks(workspace)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Step 7: first pull. `run_pull` records per-stage failures inside
|
||||
# `result.errors` rather than raising for transient issues, so any
|
||||
|
|
|
|||
Loading…
Reference in a new issue