diff --git a/.gitignore b/.gitignore index 6035a54b..377a2c49 100644 --- a/.gitignore +++ b/.gitignore @@ -118,6 +118,12 @@ src/aipass/*/apps/integrations/** !src/aipass/commons/apps/handlers/artifacts/ !src/aipass/commons/apps/handlers/artifacts/*.py +# hooks boot-shim installer — must ship so fresh clones can install the claude() +# shell function. Collides with the blanket tools/ ignore (line 51). +!src/aipass/hooks/tools/ +src/aipass/hooks/tools/* +!src/aipass/hooks/tools/install_boot_shim.sh + # CI artifacts windows-pytest-results/ diff --git a/CHANGELOG.md b/CHANGELOG.md index f27e6f6f..9527231b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -63,6 +63,17 @@ PyPI version — not the changelog header. ### Fixed +- **The `claude()` boot shim now ships and installs on onboarding (issue #666).** + Its installer (`hooks/tools/install_boot_shim.sh`) lived under a gitignored + `tools/` dir — never version-controlled, never shipped — so the + attach-if-live / start-in-tmux boot feature (and presence-gate-via-boot) was + dev-local only; a macOS user could not attach/resume their session. A root + `.gitignore` negation now tracks exactly that one file (`tools/` re-ignored, + only the installer whitelisted — README stays out), and `setup.sh` runs it + right after hook installation (idempotent via a marker check, non-fatal on + error, venv Python resolved from the script's own location for POSIX/Windows). + Fresh clones and `aipass install` now get the shim. + - **Interactive-occupancy detection is now cross-platform — the wake-back guard no longer goes blind on macOS (issue #680).** `_is_branch_occupied()` and `_read_session_type()` (duplicated in `dispatch/wake.py` and `dispatch/daemon.py`) diff --git a/setup.sh b/setup.sh index 0d433094..85feb0d6 100755 --- a/setup.sh +++ b/setup.sh @@ -804,6 +804,16 @@ else echo "Skipping Claude hooks (bridge not found at src/aipass/hooks/apps/handlers/bridges/claude.py)" fi +# --- Install claude() boot shim (attach-if-live / start-in-tmux) --- +# Ships via the .gitignore negation (#666). Idempotent: the installer checks for +# its marker before appending to the shell rc, and resolves the venv Python from +# its own location (POSIX/Windows/fallback). Composes with presence_gate seeding. +BOOT_SHIM="$SCRIPT_DIR/src/aipass/hooks/tools/install_boot_shim.sh" +if [ -f "$BOOT_SHIM" ]; then + echo "Installing claude() boot shim ..." + bash "$BOOT_SHIM" || echo " boot shim install skipped (non-fatal)" +fi + # --- Install Claude Code commands (provider level) --- # memo.md belongs at provider level — works in all projects. # prep.md stays at repo root only — it's AIPass-specific. diff --git a/src/aipass/hooks/tools/install_boot_shim.sh b/src/aipass/hooks/tools/install_boot_shim.sh new file mode 100755 index 00000000..e49cf4b0 --- /dev/null +++ b/src/aipass/hooks/tools/install_boot_shim.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# install_boot_shim.sh — append the claude() shell function to ~/.bashrc and ~/.zshrc +# +# Usage: bash tools/install_boot_shim.sh +# +# The shim intercepts 'claude' in AIPass branch directories (those with .trinity/) +# and delegates to the session_boot wrapper. Everywhere else, claude runs normally. +# Safe to run multiple times — skips if already installed. + +set -euo pipefail + +MARKER="# >>> AIPass boot shim >>>" + +# Resolve THIS repo's venv Python from the script's own location — no hardcoded +# user path. POSIX (.venv/bin/python) + Windows/git-bash (.venv/Scripts/python.exe) +# aware; falls back to PATH python3 if no venv is found. +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)" +if [ -x "$REPO_ROOT/.venv/bin/python" ]; then + VENV_PY="$REPO_ROOT/.venv/bin/python" +elif [ -x "$REPO_ROOT/.venv/Scripts/python.exe" ]; then + VENV_PY="$REPO_ROOT/.venv/Scripts/python.exe" +else + VENV_PY="python3" +fi + +SHIM=' +# >>> AIPass boot shim >>> +# Intercepts claude in AIPass branch dirs to attach-if-live / start-in-tmux. +# Installed by: tools/install_boot_shim.sh +claude() { + if [ -d ".trinity" ]; then + __VENV_PY__ \ + -m aipass.hooks.apps.handlers.lifecycle.session_boot "$@" + else + command claude "$@" + fi +} +# <<< AIPass boot shim <<< +' + +# Bake the resolved interpreter into the shim (single-quoted above kept "$@" literal). +SHIM="${SHIM//__VENV_PY__/$VENV_PY}" + +for rc in "$HOME/.bashrc" "$HOME/.zshrc"; do + if [ ! -f "$rc" ]; then + echo "⏭ $rc does not exist, skipping" + continue + fi + if grep -qF "$MARKER" "$rc"; then + echo "✓ $rc already has the shim" + else + printf '%s\n' "$SHIM" >> "$rc" + echo "✓ Appended shim to $rc" + fi +done + +echo "" +echo "Done. Source your shell rc or open a new terminal to activate:" +echo " source ~/.bashrc # or ~/.zshrc"