diff --git a/.claude/hooks/context-forced-eval.sh b/.claude/hooks/context-forced-eval.sh new file mode 100755 index 0000000..24b5b22 --- /dev/null +++ b/.claude/hooks/context-forced-eval.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# context-forced-eval.sh +# Hook: UserPromptSubmit +# Purpose: Inject skill evaluation context when user prompt matches context-related keywords +# Installed by: /contextdocs:context-guard install +# +# Keyword-gated — only fires on context-related prompts to avoid overhead on +# unrelated coding tasks. Advisory only — never blocks. +# +# Claude Code only — OpenCode, Codex CLI, Cursor, and other tools +# do not support Claude Code hooks. + +set -euo pipefail + +# Read hook input from stdin +INPUT=$(cat) + +# Skip in Untether sessions (Telegram stays lean) +[ -n "${UNTETHER_SESSION:-}" ] && echo '{}' && exit 0 + +# Extract prompt +PROMPT=$(echo "$INPUT" | jq -r '.prompt // empty' 2>/dev/null || true) + +# Skip empty prompts +[ -z "$PROMPT" ] && echo '{}' && exit 0 + +# Convert to lowercase for matching +LOWER=$(echo "$PROMPT" | tr '[:upper:]' '[:lower:]') + +# Check for context-related keywords +MATCH=false + +# Slash commands (exact prefix match) +case "$LOWER" in + /ai-context*|/context-guard*|/context-verify*) MATCH=true ;; +esac + +# Keyword matching +if [ "$MATCH" = "false" ]; then + if echo "$LOWER" | grep -qE '(claude\.md|agents\.md|context|stale|hook[s ]|guard|verify|score|health|cursorrules|copilot|memory.*promot|drift|bridge|ai-context|context-guard|context-verify|llms\.txt|windsurfrules|clinerules|gemini\.md)'; then + MATCH=true + fi +fi + +# No match — pass through silently +if [ "$MATCH" = "false" ]; then + echo '{}' + exit 0 +fi + +# Inject skill evaluation context +cat << 'EOF' +{ + "hookSpecificOutput": { + "hookEventName": "UserPromptSubmit", + "additionalContext": "SKILL EVALUATION: This project uses ContextDocs (3 skills). Evaluate whether this prompt matches a skill and activate it via the Skill() tool before responding:\n\n1. ai-context — Generate, update, fix, or audit AI IDE context files (CLAUDE.md, AGENTS.md, bridges). Use for stale context, bootstrapping, MEMORY.md promotion, or drift.\n2. context-guard — Install, uninstall, or check Context Guard hooks. Use for hook setup, commit guards, or freshness enforcement.\n3. context-verify — Validate context file quality with 0-100 scoring. Use for health checks, line budgets, CI verification.\n\nIf a skill matches, call Skill(skill-name) NOW. If none match, proceed normally." + } +} +EOF diff --git a/.claude/skills/ai-context/SKILL.md b/.claude/skills/ai-context/SKILL.md index 63730c6..ab870dc 100644 --- a/.claude/skills/ai-context/SKILL.md +++ b/.claude/skills/ai-context/SKILL.md @@ -1,6 +1,6 @@ --- name: ai-context -description: Generates, updates, and maintains AGENTS-first AI IDE context files with AGENTS.md as canonical shared context and thin tool-specific bridges. Use this skill when the user wants to create a CLAUDE.md, generate AGENTS.md, set up context files for a project, update stale AI context, bootstrap context for a new repo, promote MEMORY.md patterns into CLAUDE.md, audit context for drift, or generate cursorrules, copilot instructions, clinerules, windsurfrules, or GEMINI.md. Use proactively whenever context files may need attention, even if not explicitly requested. +description: Generates, updates, and maintains AGENTS-first AI IDE context files with AGENTS.md as canonical shared context and thin tool-specific bridges. Use this skill when the user wants to create a CLAUDE.md, generate AGENTS.md, set up context files for a project, update or fix out-of-date context files, refresh stale CLAUDE.md or AGENTS.md, bootstrap context for a new repo, move or promote MEMORY.md patterns into CLAUDE.md, audit context for drift, or generate cursorrules, copilot instructions, clinerules, windsurfrules, or GEMINI.md. This is the right skill for updating, regenerating, or fixing context files — not just checking them. Use proactively whenever context files may need attention, even if not explicitly requested. --- # AI Context File Generator diff --git a/.claude/skills/context-guard/SKILL.md b/.claude/skills/context-guard/SKILL.md index cf64164..edb4ef3 100644 --- a/.claude/skills/context-guard/SKILL.md +++ b/.claude/skills/context-guard/SKILL.md @@ -54,6 +54,10 @@ Fires before `git commit`. Checks staging area for structural files without cont Fires at session start. Quick context health check: counts context files, detects stale files (source commits ahead), warns if aggregate line count exceeds budget. Advisory only — cannot block session start. +### context-forced-eval.sh (UserPromptSubmit) + +Fires on every user prompt. Checks for context-related keywords and injects a skill evaluation sequence that instructs Claude to evaluate and activate ContextDocs skills before responding. Keyword-gated to avoid overhead on unrelated prompts. Advisory only — never blocks. + ### context-updater agent Autonomous agent (`.claude/agents/context-updater.md`) launched by Claude in response to hook output. Applies surgical, incremental context file updates. Uses `.git/.context-updater-running` flag for loop prevention. @@ -80,6 +84,9 @@ Autonomous agent (`.claude/agents/context-updater.md`) launched by Claude in res "SessionStart": [ { "hooks": [{ "type": "command", "command": ".claude/hooks/context-session-start.sh" }] } ], + "UserPromptSubmit": [ + { "hooks": [{ "type": "command", "command": ".claude/hooks/context-forced-eval.sh" }] } + ], "Stop": [ { "hooks": [{ "type": "command", "command": ".claude/hooks/context-guard-stop.sh" }] } ] diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..d822bb6 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @littlebearapps/core diff --git a/.gitignore b/.gitignore index 9425473..78a10de 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,11 @@ docs/promotion/ docs/plans/ +# Dev workspace and scratch files +ai-context-workspace/ +incoming/ +tests/activation-results/ + # === Direnv === .envrc.local .direnv/ diff --git a/AGENTS.md b/AGENTS.md index 87cf029..9460ae1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -42,9 +42,10 @@ Invoke as `/contextdocs:command-name` in Claude Code, or as prompts in Codex CLI ## Hooks (Claude Code Only) -6 opt-in hooks, installed via `/contextdocs:context-guard install`. Hooks reference the context-updater agent for autonomous action: +7 opt-in hooks, installed via `/contextdocs:context-guard install`. Hooks reference the context-updater agent for autonomous action: - `context-session-start.sh` — session-start context health check (advisory) +- `context-forced-eval.sh` — keyword-gated skill evaluation on context-related prompts (advisory) - `context-drift-check.sh` — post-commit drift detection - `context-structural-change.sh` — structural change reminders to update `AGENTS.md` first, then bridges - `content-filter-guard.sh` — Write guard for high-risk OSS files diff --git a/CHANGELOG.md b/CHANGELOG.md index 0915113..41c7a2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to ContextDocs will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Fixed + +* Context Guard hooks no longer flag infrastructure rule files as false positives ([#13](https://github.com/littlebearapps/contextdocs/issues/13)) +* ai-context skill triggers more reliably when you describe stale context or MEMORY.md promotion scenarios +* SKILL.md and CLAUDE.md descriptions now match the canonical product definition across all tools + ## [1.4.0](https://github.com/littlebearapps/contextdocs/compare/v1.3.0...v1.4.0) (2026-03-13) diff --git a/_typos.toml b/_typos.toml index 3b9ef8f..8e6c003 100644 --- a/_typos.toml +++ b/_typos.toml @@ -48,6 +48,7 @@ initialised = "initialised" center = "center" # Technical terms +promot = "promot" # regex partial match for promote/promotion in hooks contextdocs = "contextdocs" pitchdocs = "pitchdocs" llms = "llms" diff --git a/commands/context-guard.md b/commands/context-guard.md index 4bf4ca2..d02235b 100644 --- a/commands/context-guard.md +++ b/commands/context-guard.md @@ -28,11 +28,11 @@ Context Guard has two enforcement tiers: - **`install`**: Install Context Guard (Tier 1) into the current project: 1. Create `.claude/hooks/` directory if it does not exist - 2. Copy `context-drift-check.sh`, `context-structural-change.sh`, `content-filter-guard.sh`, `context-guard-stop.sh`, and `context-session-start.sh` from the plugin's `hooks/` directory to `.claude/hooks/` + 2. Copy `context-drift-check.sh`, `context-structural-change.sh`, `content-filter-guard.sh`, `context-guard-stop.sh`, `context-session-start.sh`, and `context-forced-eval.sh` from the plugin's `hooks/` directory to `.claude/hooks/` 3. Make the scripts executable (`chmod +x`) 4. Create `.claude/agents/` directory if it does not exist 5. Copy `context-updater.md` from the plugin's `.claude/agents/` directory to `.claude/agents/context-updater.md` - 6. Merge PreToolUse, PostToolUse, SessionStart, and Stop hook entries into `.claude/settings.json` (create the file if needed; if entries already exist, append without overwriting) + 6. Merge PreToolUse, PostToolUse, SessionStart, UserPromptSubmit, and Stop hook entries into `.claude/settings.json` (create the file if needed; if entries already exist, append without overwriting) 7. Copy `context-quality.md` to `.claude/rules/context-quality.md` (create directory if needed) 8. Report what was installed @@ -43,8 +43,8 @@ Context Guard has two enforcement tiers: 4. Report what was installed, noting Tier 2 is active - **`uninstall`**: Remove all Context Guard hooks from the current project: - 1. Remove `.claude/hooks/context-drift-check.sh`, `.claude/hooks/context-structural-change.sh`, `.claude/hooks/content-filter-guard.sh`, `.claude/hooks/context-guard-stop.sh`, `.claude/hooks/context-session-start.sh`, and `.claude/hooks/context-commit-guard.sh` - 2. Remove all Context Guard hook entries (PreToolUse, PostToolUse, SessionStart, and Stop) from `.claude/settings.json` (preserve other hooks) + 1. Remove `.claude/hooks/context-drift-check.sh`, `.claude/hooks/context-structural-change.sh`, `.claude/hooks/content-filter-guard.sh`, `.claude/hooks/context-guard-stop.sh`, `.claude/hooks/context-session-start.sh`, `.claude/hooks/context-forced-eval.sh`, and `.claude/hooks/context-commit-guard.sh` + 2. Remove all Context Guard hook entries (PreToolUse, PostToolUse, SessionStart, UserPromptSubmit, and Stop) from `.claude/settings.json` (preserve other hooks) 3. Remove `.claude/rules/context-quality.md` 4. Remove `.claude/agents/context-updater.md` 5. Report what was removed @@ -68,9 +68,10 @@ Context Guard installed (Tier 1 — Nudge): ✓ .claude/hooks/content-filter-guard.sh — blocks Write on high-risk OSS files, advises on medium-risk ✓ .claude/hooks/context-guard-stop.sh — nudges to update context docs before session ends ✓ .claude/hooks/context-session-start.sh — quick context health check at session start + ✓ .claude/hooks/context-forced-eval.sh — injects skill evaluation on context-related prompts ✓ .claude/agents/context-updater.md — autonomous agent for surgical context file updates ✓ .claude/rules/context-quality.md — auto-loaded quality standards for context files - ✓ .claude/settings.json — PreToolUse, PostToolUse, SessionStart, and Stop hooks registered + ✓ .claude/settings.json — PreToolUse, PostToolUse, SessionStart, UserPromptSubmit, and Stop hooks registered Tier 2 (Guard) not installed. Run /contextdocs:context-guard install strict to also block commits when structural files change without context doc updates. @@ -88,10 +89,11 @@ Context Guard installed (Tier 1 + Tier 2 — Nudge + Guard): ✓ .claude/hooks/content-filter-guard.sh — blocks Write on high-risk OSS files, advises on medium-risk ✓ .claude/hooks/context-guard-stop.sh — nudges to update context docs before session ends ✓ .claude/hooks/context-session-start.sh — quick context health check at session start + ✓ .claude/hooks/context-forced-eval.sh — injects skill evaluation on context-related prompts ✓ .claude/hooks/context-commit-guard.sh — blocks commits with stale context docs ✓ .claude/agents/context-updater.md — autonomous agent for surgical context file updates ✓ .claude/rules/context-quality.md — auto-loaded quality standards for context files - ✓ .claude/settings.json — PreToolUse, PostToolUse, SessionStart, and Stop hooks registered + ✓ .claude/settings.json — PreToolUse, PostToolUse, SessionStart, UserPromptSubmit, and Stop hooks registered ``` ### Status @@ -99,8 +101,8 @@ Context Guard installed (Tier 1 + Tier 2 — Nudge + Guard): Context Guard Status: ✓ Tier 1 — Nudge (Stop hook active — reminds about context docs before session end) ✓ Tier 2 — Guard (commit blocker active — blocks commits with stale context) - ✓ Base hooks installed (3/3 scripts in .claude/hooks/) - ✓ Settings configured (PreToolUse, PostToolUse, and Stop entries in .claude/settings.json) + ✓ Base hooks installed (scripts in .claude/hooks/) + ✓ Settings configured (PreToolUse, PostToolUse, UserPromptSubmit, and Stop entries in .claude/settings.json) ✓ Context-updater agent installed (.claude/agents/context-updater.md) ✓ Quality rule active (.claude/rules/context-quality.md) diff --git a/hooks/context-forced-eval.sh b/hooks/context-forced-eval.sh new file mode 100755 index 0000000..24b5b22 --- /dev/null +++ b/hooks/context-forced-eval.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# context-forced-eval.sh +# Hook: UserPromptSubmit +# Purpose: Inject skill evaluation context when user prompt matches context-related keywords +# Installed by: /contextdocs:context-guard install +# +# Keyword-gated — only fires on context-related prompts to avoid overhead on +# unrelated coding tasks. Advisory only — never blocks. +# +# Claude Code only — OpenCode, Codex CLI, Cursor, and other tools +# do not support Claude Code hooks. + +set -euo pipefail + +# Read hook input from stdin +INPUT=$(cat) + +# Skip in Untether sessions (Telegram stays lean) +[ -n "${UNTETHER_SESSION:-}" ] && echo '{}' && exit 0 + +# Extract prompt +PROMPT=$(echo "$INPUT" | jq -r '.prompt // empty' 2>/dev/null || true) + +# Skip empty prompts +[ -z "$PROMPT" ] && echo '{}' && exit 0 + +# Convert to lowercase for matching +LOWER=$(echo "$PROMPT" | tr '[:upper:]' '[:lower:]') + +# Check for context-related keywords +MATCH=false + +# Slash commands (exact prefix match) +case "$LOWER" in + /ai-context*|/context-guard*|/context-verify*) MATCH=true ;; +esac + +# Keyword matching +if [ "$MATCH" = "false" ]; then + if echo "$LOWER" | grep -qE '(claude\.md|agents\.md|context|stale|hook[s ]|guard|verify|score|health|cursorrules|copilot|memory.*promot|drift|bridge|ai-context|context-guard|context-verify|llms\.txt|windsurfrules|clinerules|gemini\.md)'; then + MATCH=true + fi +fi + +# No match — pass through silently +if [ "$MATCH" = "false" ]; then + echo '{}' + exit 0 +fi + +# Inject skill evaluation context +cat << 'EOF' +{ + "hookSpecificOutput": { + "hookEventName": "UserPromptSubmit", + "additionalContext": "SKILL EVALUATION: This project uses ContextDocs (3 skills). Evaluate whether this prompt matches a skill and activate it via the Skill() tool before responding:\n\n1. ai-context — Generate, update, fix, or audit AI IDE context files (CLAUDE.md, AGENTS.md, bridges). Use for stale context, bootstrapping, MEMORY.md promotion, or drift.\n2. context-guard — Install, uninstall, or check Context Guard hooks. Use for hook setup, commit guards, or freshness enforcement.\n3. context-verify — Validate context file quality with 0-100 scoring. Use for health checks, line budgets, CI verification.\n\nIf a skill matches, call Skill(skill-name) NOW. If none match, proceed normally." + } +} +EOF diff --git a/llms.txt b/llms.txt index 0db94e5..0ed7de6 100644 --- a/llms.txt +++ b/llms.txt @@ -45,6 +45,7 @@ - [Doc Standards Rule](./.claude/rules/doc-standards.md): Auto-loaded documentation quality standards — 4-Question Test, Lobby Principle, progressive disclosure, banned phrases (PitchDocs, Claude Code only) - [Docs Awareness Rule](./.claude/rules/docs-awareness.md): Auto-loaded documentation trigger map — suggests PitchDocs commands when docs-relevant work is detected (PitchDocs, Claude Code only) - [Context Session Start Hook](./hooks/context-session-start.sh): SessionStart hook that runs a quick context health check — detects stale files, warns on high aggregate line count (Claude Code only) +- [Context Forced Eval Hook](./hooks/context-forced-eval.sh): UserPromptSubmit hook that injects skill evaluation on context-related prompts — keyword-gated, advisory only (Claude Code only) - [Context Drift Check Hook](./hooks/context-drift-check.sh): PostToolUse hook that detects stale AI context files after git commits (Claude Code only) - [Context Structural Change Hook](./hooks/context-structural-change.sh): PostToolUse hook that reminds about AGENTS-first context updates after structural changes (Claude Code only) - [Content Filter Guard Hook](./hooks/content-filter-guard.sh): PreToolUse hook that blocks Write on high-risk OSS files — CODE_OF_CONDUCT.md, LICENSE, SECURITY.md (Claude Code only) diff --git a/scripts/update-installed-hooks.sh b/scripts/update-installed-hooks.sh index 0923de1..454242a 100755 --- a/scripts/update-installed-hooks.sh +++ b/scripts/update-installed-hooks.sh @@ -22,6 +22,7 @@ TIER1_HOOKS=( "context-structural-change.sh" "context-guard-stop.sh" "context-session-start.sh" + "context-forced-eval.sh" ) # Tier 2 hook (only updated if already present) @@ -50,6 +51,16 @@ SESSION_START_ENTRY='{ ] }' +# UserPromptSubmit entry to inject via jq +USER_PROMPT_SUBMIT_ENTRY='{ + "hooks": [ + { + "type": "command", + "command": ".claude/hooks/context-forced-eval.sh" + } + ] +}' + UPDATED=0 SKIPPED=0 WARNINGS=() @@ -135,6 +146,22 @@ for PROJECT in "${PROJECTS[@]}"; do echo " settings.json: added SessionStart entry" fi + # --- Patch settings.json: add UserPromptSubmit if missing --- + HAS_USER_PROMPT_SUBMIT=$(jq ' + .hooks.UserPromptSubmit // [] | + any(.[]; .hooks[]?.command | test("context-forced-eval\\.sh")) + ' "$SETTINGS" 2>/dev/null || echo "false") + + if [ "$HAS_USER_PROMPT_SUBMIT" = "true" ]; then + echo " settings.json: UserPromptSubmit already present" + else + TEMP=$(mktemp) + jq --argjson entry "$USER_PROMPT_SUBMIT_ENTRY" ' + .hooks.UserPromptSubmit = (.hooks.UserPromptSubmit // []) + [$entry] + ' "$SETTINGS" > "$TEMP" && mv "$TEMP" "$SETTINGS" + echo " settings.json: added UserPromptSubmit entry" + fi + # --- Warn if Stop hook entry is missing from settings.json --- HAS_STOP=$(jq ' .hooks.Stop // [] | @@ -144,6 +171,11 @@ for PROJECT in "${PROJECTS[@]}"; do if [ "$HAS_STOP" != "true" ]; then WARNINGS+=("$NAME: Stop hook entry missing from settings.json (context-guard-stop.sh won't run)") fi + + # --- Warn if UserPromptSubmit hook entry is missing from settings.json --- + if [ "$HAS_USER_PROMPT_SUBMIT" != "true" ]; then + WARNINGS+=("$NAME: UserPromptSubmit hook entry missing from settings.json (context-forced-eval.sh won't run)") + fi else echo " settings.json: NOT FOUND — skipping patch" WARNINGS+=("$NAME: no .claude/settings.json found") diff --git a/tests/test-hooks.sh b/tests/test-hooks.sh index 39b5af4..96b4ce4 100755 --- a/tests/test-hooks.sh +++ b/tests/test-hooks.sh @@ -1,6 +1,6 @@ #!/bin/bash # test-hooks.sh -# Unit tests for all 6 ContextDocs hooks. +# Unit tests for all 7 ContextDocs hooks. # Exit 0 = all pass, Exit 1 = failures found set -euo pipefail @@ -628,6 +628,89 @@ teardown_git_repo echo "" +######################################################################## +# SECTION 7: context-forced-eval.sh (UserPromptSubmit) +######################################################################## +HOOK="$ORIG_DIR/hooks/context-forced-eval.sh" +echo "--- Section 7: context-forced-eval.sh ---" +echo "" + +echo "--- Slash command triggers (exit 0 with additionalContext) ---" +run_test "/ai-context init triggers eval" "$HOOK" \ + '{"prompt":"/ai-context init"}' 0 "SKILL EVALUATION" +run_test "/ai-context update triggers eval" "$HOOK" \ + '{"prompt":"/ai-context update"}' 0 "SKILL EVALUATION" +run_test "/context-guard install triggers eval" "$HOOK" \ + '{"prompt":"/context-guard install"}' 0 "SKILL EVALUATION" +run_test "/context-verify triggers eval" "$HOOK" \ + '{"prompt":"/context-verify"}' 0 "SKILL EVALUATION" +run_test "/context-verify ci --min-score 80 triggers eval" "$HOOK" \ + '{"prompt":"/context-verify ci --min-score 80"}' 0 "SKILL EVALUATION" + +echo "" +echo "--- NL keyword triggers (exit 0 with additionalContext) ---" +run_test "CLAUDE.md is out of date" "$HOOK" \ + '{"prompt":"My CLAUDE.md is out of date"}' 0 "SKILL EVALUATION" +run_test "Update my AGENTS.md" "$HOOK" \ + '{"prompt":"Update my AGENTS.md"}' 0 "SKILL EVALUATION" +run_test "Score my context files" "$HOOK" \ + '{"prompt":"Score my context files"}' 0 "SKILL EVALUATION" +run_test "Install context hooks" "$HOOK" \ + '{"prompt":"Install context hooks"}' 0 "SKILL EVALUATION" +run_test "Check context health" "$HOOK" \ + '{"prompt":"Check context health"}' 0 "SKILL EVALUATION" +run_test "Move MEMORY.md patterns into CLAUDE.md" "$HOOK" \ + '{"prompt":"Move MEMORY.md patterns into CLAUDE.md"}' 0 "SKILL EVALUATION" +run_test "My context files are stale" "$HOOK" \ + '{"prompt":"My context files are stale"}' 0 "SKILL EVALUATION" +run_test "Set up commit guard" "$HOOK" \ + '{"prompt":"Set up commit guard"}' 0 "SKILL EVALUATION" +run_test "Check my llms.txt" "$HOOK" \ + '{"prompt":"Check my llms.txt"}' 0 "SKILL EVALUATION" +run_test "Fix context drift" "$HOOK" \ + '{"prompt":"Fix context drift"}' 0 "SKILL EVALUATION" +run_test "Generate cursorrules" "$HOOK" \ + '{"prompt":"Generate cursorrules"}' 0 "SKILL EVALUATION" +run_test "Update copilot instructions" "$HOOK" \ + '{"prompt":"Update copilot instructions"}' 0 "SKILL EVALUATION" +run_test "Update bridge files" "$HOOK" \ + '{"prompt":"Update bridge files"}' 0 "SKILL EVALUATION" + +echo "" +echo "--- Non-matching prompts (exit 0, empty JSON) ---" +run_test "Fix this bug → silent" "$HOOK" \ + '{"prompt":"Fix this bug"}' 0 "{}" +run_test "Run the test suite → silent" "$HOOK" \ + '{"prompt":"Run the test suite"}' 0 "{}" +run_test "Refactor to async/await → silent" "$HOOK" \ + '{"prompt":"Refactor to async/await"}' 0 "{}" +run_test "Deploy to production → silent" "$HOOK" \ + '{"prompt":"Deploy to production"}' 0 "{}" +run_test "Generate a README → silent" "$HOOK" \ + '{"prompt":"Generate a README"}' 0 "{}" +run_test "Add a new API endpoint → silent" "$HOOK" \ + '{"prompt":"Add a new API endpoint"}' 0 "{}" +run_test "Empty JSON → silent" "$HOOK" \ + '{}' 0 "{}" +run_test "Missing prompt field → silent" "$HOOK" \ + '{"tool_name":"Write"}' 0 "{}" + +echo "" +echo "--- Gate logic ---" +export UNTETHER_SESSION="test" +run_test "UNTETHER_SESSION set → silent even with keywords" "$HOOK" \ + '{"prompt":"Update my CLAUDE.md"}' 0 "{}" +unset UNTETHER_SESSION + +run_test "Case insensitivity: CLAUDE.MD" "$HOOK" \ + '{"prompt":"Check CLAUDE.MD"}' 0 "SKILL EVALUATION" +run_test "Case insensitivity: agents.md" "$HOOK" \ + '{"prompt":"Update agents.md"}' 0 "SKILL EVALUATION" +run_test "Case insensitivity: Context Files" "$HOOK" \ + '{"prompt":"Verify my Context Files"}' 0 "SKILL EVALUATION" + +echo "" + ######################################################################## # SUMMARY ########################################################################