#!/usr/bin/env bash # SessionStart: keep an apm-consumed install level with its remote. # # Packages declared as unpinned git refs resolve against the remote default # branch, so the deployed .claude/skills/ and .claude/agents/ go stale the # moment anyone merges. The staleness bites when a session loads skills, which # is why this runs at SessionStart rather than off a git hook — a pull is # neither necessary nor sufficient for the install to have drifted. # # Refreshes in place and asks the host to re-scan, so the running session picks # the new content up without a restart. # # Inert in any project that does not consume packages through apm. set -uo pipefail # No lockfile means nothing was installed through apm here — e.g. a host that # installed this plugin natively. Say nothing and cost nothing. [[ -f apm.lock.yaml ]] || exit 0 command -v apm > /dev/null 2>&1 || exit 0 # `apm outdated` exits 0 whether or not anything is stale, so the answer has to # come from its output. ~0.7s against six remote refs; a hung remote must not # hold the session open. outdated_output="$(timeout 60 apm outdated 2>&1)" || exit 0 grep -q "outdated dependencies found" <<< "$outdated_output" || exit 0 stale_count="$(grep -oE '[0-9]+ outdated dependencies found' <<< "$outdated_output" | grep -oE '^[0-9]+' || true)" [[ "$stale_count" =~ ^[0-9]+$ ]] || stale_count="some" # Only ever emit fixed text plus a digit-checked count — never interpolate # command output into the JSON, which would need escaping this cannot do safely. emit() { printf '{"hookSpecificOutput":{"hookEventName":"SessionStart","reloadSkills":%s,"additionalContext":"%s"}}\n' "$1" "$2" } if timeout 300 apm update --yes > /dev/null 2>&1; then emit true "apm install was ${stale_count} package(s) behind the remote default branch and has been refreshed automatically; skills and agents were redeployed and re-scanned. apm.lock.yaml has been rewritten and is now a modified file in the working tree - commit it or discard it deliberately." else emit false "apm install is ${stale_count} package(s) behind the remote default branch and the automatic refresh failed. Deployed skills and agents may be stale. Run: apm update --yes" fi exit 0