diff --git a/.claude/rules/tool-layer-boundary.md b/.claude/rules/tool-layer-boundary.md index c575ce1c..989adf97 100644 --- a/.claude/rules/tool-layer-boundary.md +++ b/.claude/rules/tool-layer-boundary.md @@ -54,6 +54,12 @@ atelier autopilot check stagnation # stdin payload 해석 - 등록 자체도 결정적 변환이므로 `atelier git hook register ` 로 수행한다. LLM 이 `Write` 로 settings.json 을 직접 편집하지 않는다 (#762). +- **plugin-declared hook**: setup·프로젝트 설정과 무관하게 플러그인 활성화만으로 모든 + 세션에 적용돼야 하는 config-free·non-blocking hook(예: `check-cli-version`)은 + 플러그인 루트의 `hooks/hooks.json` 에 리터럴 `${CLAUDE_PLUGIN_ROOT}` 로 선언한다. + 이는 settings.json 편집이 아니므로 `hook register` 가 필요 없고, 활성 플러그인 버전 + 경로로 해석돼 frozen 이 없다. 반대로 프로젝트별 설정이나 차단(exit 2)이 필요한 hook + (guard 류)은 opt-in 이라 `hook register` 로 settings.json 에 등록한다. ## 판단 기준 diff --git a/plugins/atelier/commands/setup.md b/plugins/atelier/commands/setup.md index 0c1c2dc2..9731bd96 100644 --- a/plugins/atelier/commands/setup.md +++ b/plugins/atelier/commands/setup.md @@ -29,6 +29,10 @@ bash "${CLAUDE_PLUGIN_ROOT}/scripts/ensure-binary.sh" - plugin.json 버전과 설치된 `atelier --version` 을 SemVer 비교해 필요 시 빌드/설치합니다 (`~/.local/bin/atelier`) - 실패하면(cargo 부재 등) 이후 Step 을 진행하지 말고 에러를 안내합니다 +> CLI 버전 드리프트 알림(SessionStart)은 setup 이 등록하지 않습니다 — 플러그인이 `hooks/hooks.json` 으로 +> 직접 선언해 활성화 시 자동 적용됩니다(`${CLAUDE_PLUGIN_ROOT}` 해석으로 버전 frozen 없음). Step 0 이 +> *setup 시점* 바이너리를 보장하면, 그 hook 이 *이후 드리프트*를 알리는 한 쌍입니다. + ## Step 1 — 설치 모듈 선택 `AskUserQuestion` 으로 설치할 모듈을 선택합니다 (multiSelect). @@ -86,11 +90,8 @@ bash "${CLAUDE_PLUGIN_ROOT}/scripts/ensure-binary.sh" ## Step 2b — autopilot 모듈 1. 프로젝트 설정 파일 `github-autopilot.local.md` 생성 (기존 스키마/경로 동일 — 호환). -2. autopilot hook 3종 등록 — 로직이 아직 `.sh` 에 있으므로(#776 에서 CLI 이전 예정) `${CLAUDE_PLUGIN_ROOT}` 리터럴 shim 으로 기록: +2. autopilot hook 2종 등록 — 로직이 아직 `.sh` 에 있으므로(#776 에서 CLI 이전 예정) `${CLAUDE_PLUGIN_ROOT}` 리터럴 shim 으로 기록 (버전 드리프트 알림 hook 은 setup 이 등록하지 않음 — Step 0 안내 참조, 플러그인이 `hooks/hooks.json` 으로 직접 선언): ```bash - atelier git hook register SessionStart "*" \ - '${CLAUDE_PLUGIN_ROOT}/hooks/check-cli-version.sh' --project-dir "$HOME" - atelier git hook register PreToolUse "Bash" \ '${CLAUDE_PLUGIN_ROOT}/hooks/guard-pr-base.sh' --project-dir "$HOME" @@ -134,7 +135,9 @@ bash "${CLAUDE_PLUGIN_ROOT}/scripts/ensure-binary.sh" 4. 사용자에게 치환 목록을 보여주고 AskUserQuestion 으로 확인 5. 매칭 entry 마다: atelier git hook unregister --project-dir "$HOME" → 아래 표의 대응 command 로 atelier git hook register (hook register 는 command 기준 - 중복 제거를 하므로 frozen + atelier 양쪽에 있던 hook 도 한 개만 남음) + 중복 제거를 하므로 frozen + atelier 양쪽에 있던 hook 도 한 개만 남음). + 단, 표에서 "제거만" 으로 표시된 hook 은 plugin-declared 로 대체됐으므로 unregister 만 + 하고 재등록하지 않는다 (재등록 시 hooks.json 선언과 SessionStart 이중 실행) ``` > **멱등성**: 이미 atelier 로 재작성된 settings.json 에 재실행하면 변경 0건이어야 합니다. @@ -143,7 +146,7 @@ bash "${CLAUDE_PLUGIN_ROOT}/scripts/ensure-binary.sh" | frozen 경로 | atelier 등록 command | |---|---| -| `github-autopilot/hooks/check-cli-version.sh` | `${CLAUDE_PLUGIN_ROOT}/hooks/check-cli-version.sh` (리터럴) | +| `github-autopilot/hooks/check-cli-version.sh` | **제거만** (재등록 안 함) — 플러그인이 `hooks/hooks.json` 으로 직접 선언 | | `github-autopilot/hooks/guard-pr-base.sh` | `${CLAUDE_PLUGIN_ROOT}/hooks/guard-pr-base.sh` (리터럴) | | `github-autopilot/hooks/protect-stagnation.sh` | `${CLAUDE_PLUGIN_ROOT}/hooks/protect-stagnation.sh` (리터럴) | | `coding-style/hooks/suggest-simplify.sh` | `${CLAUDE_PLUGIN_ROOT}/hooks/suggest-simplify.sh` (리터럴) | diff --git a/plugins/atelier/hooks/check-cli-version.sh b/plugins/atelier/hooks/check-cli-version.sh index c92d8c96..d852e38b 100755 --- a/plugins/atelier/hooks/check-cli-version.sh +++ b/plugins/atelier/hooks/check-cli-version.sh @@ -1,23 +1,18 @@ #!/usr/bin/env bash # check-cli-version.sh — SessionStart hook -# 세션 시작 시 atelier CLI 버전이 plugin.json과 일치하는지 확인합니다. -# 과거 버전이면 업데이트 안내를 출력합니다. +# 세션 시작 시 설치된 atelier CLI 버전이 활성 플러그인 버전과 일치하는지 확인합니다. # -# 트리거: SessionStart +# 트리거: SessionStart (글로벌 등록 — atelier 설치 여부로 스스로 판단) # 동작: -# - autopilot 프로젝트가 아니면 → exit 0 (skip) -# - CLI 미설치 또는 과거 버전 → 안내 출력 후 exit 0 -# - 최신 버전 → exit 0 +# - atelier CLI 미설치 → exit 0 (무음 — atelier 미사용 환경 배려) +# - 설치 버전 < 플러그인 버전 → 업데이트 안내 한 줄 출력 후 exit 0 +# - 최신/상위 버전 → exit 0 (무음) set -euo pipefail -PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}" -CONFIG_FILE="${PROJECT_DIR}/github-autopilot.local.md" - -# autopilot 프로젝트가 아니면 skip -if [[ ! -f "$CONFIG_FILE" ]]; then - exit 0 -fi +# atelier 미설치 환경은 가장 싼 builtin 검사로 먼저 가른다 — 이 hook 은 모든 세션에서 +# 실행되므로(미설치가 다수), plugin.json 파싱·stdin 처리 전에 즉시 종료한다. +command -v atelier &> /dev/null || exit 0 # stdin 소비 (SessionStart hook은 session info를 stdin으로 받음) cat > /dev/null @@ -37,11 +32,6 @@ if [[ -z "$PLUGIN_VERSION" ]]; then fi # --- 설치된 CLI 버전 확인 --- -if ! command -v atelier &> /dev/null; then - echo "atelier CLI가 설치되어 있지 않습니다. /atelier:setup 을 실행하여 설치하세요." - exit 0 -fi - INSTALLED_VERSION=$(atelier --version 2>/dev/null | awk '{print $NF}' || echo "") if [[ -z "$INSTALLED_VERSION" ]]; then diff --git a/plugins/atelier/hooks/hooks.json b/plugins/atelier/hooks/hooks.json new file mode 100644 index 00000000..3b67d244 --- /dev/null +++ b/plugins/atelier/hooks/hooks.json @@ -0,0 +1,15 @@ +{ + "hooks": { + "SessionStart": [ + { + "matcher": "*", + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/hooks/check-cli-version.sh" + } + ] + } + ] + } +}