great-cto 3.56.0 → 3.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "great-cto",
3
3
  "description": "You already have the agent. This is everything around it. great_cto runs Claude Code as a pipeline of 72 specialist agents \u2014 an independent model checks each stage before the next builds on it, spending caps refuse rather than warn, and three decisions stay yours: what gets built, how, and whether it ships.",
4
- "version": "3.56.0",
4
+ "version": "3.57.0",
5
5
  "author": {
6
6
  "name": "Alexander Velikiy",
7
7
  "url": "https://hashnode.com/@Greatcto"
@@ -55,36 +55,36 @@
55
55
  "hooks": [
56
56
  {
57
57
  "type": "command",
58
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; [ -n \"$PLUGIN_DIR\" ] && node \"${PLUGIN_DIR}/scripts/lib/state-gitignore.mjs\" 2>/dev/null; true",
58
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; [ -n \"$PLUGIN_DIR\" ] && node \"${PLUGIN_DIR}/scripts/lib/state-gitignore.mjs\" 2>/dev/null; true",
59
59
  "timeout": 5
60
60
  },
61
61
  {
62
62
  "type": "command",
63
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; export PATH=\"/opt/homebrew/bin:$HOME/.local/bin:/usr/local/bin:$PATH\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; if [ -z \"$PLUGIN_DIR\" ]; then echo 'GREAT_CTO: plugin dir not found \u2014 run /update'; else mkdir -p ~/.great_cto .great_cto; node \"${PLUGIN_DIR}/scripts/lib/sync-managed.mjs\" --plugin-dir \"${PLUGIN_DIR}\" 2>/dev/null || true; cp \"${PLUGIN_DIR}/skills/great_cto/ARCHETYPES.md\" .great_cto/ARCHETYPES.md 2>/dev/null || true; cp \"${PLUGIN_DIR}/skills/great_cto/SKILL.md\" .great_cto/SKILL.md 2>/dev/null || true; { printf \"export PATH=/opt/homebrew/bin:$HOME/.local/bin:/usr/local/bin:$PATH\\nexport ARCHETYPES_MD=.great_cto/ARCHETYPES.md\\n\"; } > .great_cto/env.sh; fi; if [ ! -d ~/.great_cto/catalog ]; then git clone --depth=1 https://github.com/davila7/claude-code-templates.git ~/.great_cto/catalog 2>/dev/null & fi; if [ ! -d ~/.great_cto/anthropic-skills ]; then git clone --depth=1 https://github.com/anthropics/skills.git ~/.great_cto/anthropic-skills 2>/dev/null & elif [ $(($(date +%s) - $(stat -f %m ~/.great_cto/anthropic-skills/.git 2>/dev/null || stat -c %Y ~/.great_cto/anthropic-skills/.git 2>/dev/null || echo 0))) -gt 604800 ]; then (cd ~/.great_cto/anthropic-skills && git pull --quiet 2>/dev/null) & fi; if [ ! -d ~/.great_cto/personal-skills ]; then git clone --depth=1 https://github.com/avelikiy/ai-agent-skills.git ~/.great_cto/personal-skills 2>/dev/null & elif [ $(($(date +%s) - $(stat -f %m ~/.great_cto/personal-skills/.git 2>/dev/null || stat -c %Y ~/.great_cto/personal-skills/.git 2>/dev/null || echo 0))) -gt 86400 ]; then (cd ~/.great_cto/personal-skills && git pull --quiet 2>/dev/null) & fi; if [ ! -f ~/.great_cto/skills-registry.json ] || [ $(($(date +%s) - $(stat -f %m ~/.great_cto/skills-registry.json 2>/dev/null || stat -c %Y ~/.great_cto/skills-registry.json 2>/dev/null || echo 0))) -gt 86400 ]; then [ -x \"${PLUGIN_DIR}/scripts/skill-discover.sh\" ] && bash \"${PLUGIN_DIR}/scripts/skill-discover.sh\" >/dev/null 2>&1 & fi; [ -x \"${PLUGIN_DIR}/scripts/hooks/welcome.sh\" ] && bash \"${PLUGIN_DIR}/scripts/hooks/welcome.sh\" 2>/dev/null || true; bash \"${PLUGIN_DIR}/scripts/apply-model-override.sh\" 2>/dev/null || true; bd prime 2>/dev/null || true; cat \"${PLUGIN_DIR}/scripts/hooks/operating-rules.md\" 2>/dev/null || true; echo '=== PREFERENCES ==='; node \"${PLUGIN_DIR}/scripts/hooks/read-global-memory.mjs\" 2>&1 || true; echo '=== PROJECT ==='; cat .great_cto/PROJECT.md 2>/dev/null || echo 'GREAT_CTO: No PROJECT.md \u2014 run /start'; PHASE=$(grep '^phase:' .great_cto/PROJECT.md 2>/dev/null | awk '{print $2}' || echo implementation); echo '=== PHASE ==='; echo \"$PHASE\"; { [ \"$PHASE\" != review ] && [ \"$PHASE\" != release ]; } && { echo '=== BRAIN ==='; head -30 .great_cto/brain.md 2>/dev/null; } || true; [ \"$PHASE\" = implementation ] && { echo '=== CODEBASE ==='; head -20 .great_cto/CODEBASE.md 2>/dev/null; } || true; echo '=== LOCAL ==='; cat .great_cto/local.md 2>/dev/null || true; [ \"$PHASE\" != planning ] && { echo '=== HANDOFF ==='; cat .great_cto/HANDOFF.md 2>/dev/null || echo 'No handoff state \u2014 fresh session'; } || true; [ \"$PHASE\" = review ] && { echo '=== LATEST QA ==='; ls docs/qa-reports/QA-*.md 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | xargs head -20 2>/dev/null; echo '=== LATEST CSO ==='; ls docs/security/CSO-*.md 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | xargs head -20 2>/dev/null; } || true; [ \"$PHASE\" = release ] && { echo '=== PERF BASELINE ==='; tail -10 .great_cto/perf-baseline.log 2>/dev/null; } || true; echo '=== STATUS ==='; OPEN_GATES=$(bd list --label gate --status open 2>/dev/null | wc -l | tr -d ' '); OPEN_TASKS=$(bd list --status open 2>/dev/null | wc -l | tr -d ' '); BRANCH=$(git branch --show-current 2>/dev/null || echo '?'); LAST_AGENT=$(ls -t .great_cto/verdicts/*.log 2>/dev/null | head -1 | xargs tail -1 2>/dev/null | awk '{print $2}' || echo 'none'); printf 'branch=%s | gates=%s | tasks=%s | last_agent=%s\\n' \"$BRANCH\" \"${OPEN_GATES:-0}\" \"${OPEN_TASKS:-0}\" \"${LAST_AGENT:-none}\"; [ \"${OPEN_GATES:-0}\" -gt 0 ] && echo '\u2192 run /inbox to see pending decisions' || true; P0_OPEN=$(bd list --status open 2>/dev/null | grep -c 'P0'); P0_OPEN=${P0_OPEN:-0}; if [ \"$P0_OPEN\" -gt 0 ]; then echo ''; printf '\\033[41;97m \ud83d\udea8 P0 OPEN: %s \u2014 run /inbox NOW \\033[0m\\n' \"$P0_OPEN\"; bd list --status open 2>/dev/null | grep 'P0' | head -3 | sed 's/^/ /'; fi; NOW_EPOCH=$(date +%s); LAST_AUDIT_FILE=$(find docs/audit -maxdepth 1 -name 'AUDIT-*.md' 2>/dev/null | sort | tail -1); if [ -n \"$LAST_AUDIT_FILE\" ]; then AUD_M=$(stat -f %m \"$LAST_AUDIT_FILE\" 2>/dev/null || stat -c %Y \"$LAST_AUDIT_FILE\" 2>/dev/null || echo $NOW_EPOCH); AUD_AGE=$(( (NOW_EPOCH - AUD_M) / 86400 )); [ \"$AUD_AGE\" -gt 30 ] && echo \"\u26a0 audit $AUD_AGE days old \u2014 run /audit\"; else echo '\u26a0 no audit artefact \u2014 run /audit or /doctor'; fi; if [ -f .great_cto/digest-latest.md ]; then DIG_M=$(stat -f %m .great_cto/digest-latest.md 2>/dev/null || stat -c %Y .great_cto/digest-latest.md 2>/dev/null || echo $NOW_EPOCH); DIG_AGE=$(( (NOW_EPOCH - DIG_M) / 86400 )); [ \"$DIG_AGE\" -gt 8 ] && echo \"\u26a0 digest $DIG_AGE days old \u2014 run /digest 7\"; fi; [ \"$PHASE\" != implementation ] && cat .great_cto/digest-latest.md 2>/dev/null | head -5 || true; [ -f \"${PLUGIN_DIR}/scripts/hooks/auto-attach-reviewers.mjs\" ] && node \"${PLUGIN_DIR}/scripts/hooks/auto-attach-reviewers.mjs\" 2>/dev/null; [ -n \"$PLUGIN_DIR\" ] && [ -f .great_cto/PROJECT.md ] && [ ! -f .great_cto/CODEBASE.md ] && node \"${PLUGIN_DIR}/scripts/first-run-codebase.mjs\" >/dev/null 2>&1 & node \"${PLUGIN_DIR}/scripts/hooks/quota-check.mjs\" 2>/dev/null || true; echo '=== PATTERNS ==='; GP_DIR=\"$HOME/.great_cto/global-patterns\"; ARCH=$(grep '^primary:' .great_cto/PROJECT.md 2>/dev/null | awk '{print $2}' | head -1); if [ -d \"$GP_DIR\" ] && ls \"$GP_DIR\"/GP-*.md >/dev/null 2>&1; then ACTIVE_COUNT=$(grep -rl 'status: active' \"$GP_DIR\" 2>/dev/null | wc -l | tr -d ' '); echo \"Active patterns: ${ACTIVE_COUNT:-0}\"; if [ -n \"$ARCH\" ] && [ \"${ACTIVE_COUNT:-0}\" -gt 0 ]; then grep -rl 'status: active' \"$GP_DIR\" 2>/dev/null | xargs grep -lE \"applies_to:.*$ARCH\" 2>/dev/null | sort -V | tail -5 | while read f; do SLUG=$(basename \"$f\" .md); SYMPT=$(grep -m1 '^symptom:' \"$f\" 2>/dev/null | sed 's/symptom: //'); DETECT=$(grep -A 2 '^detection_order:' \"$f\" 2>/dev/null | grep '^ - ' | head -1 | sed 's/^ - //'); HITS=$(grep -m1 '^hits:' \"$f\" 2>/dev/null | awk '{print $2}'); printf ' %s (hits=%s): %s\\n \\u2192 Check first: %s\\n' \"$SLUG\" \"${HITS:-0}\" \"$SYMPT\" \"$DETECT\"; done || echo \" no patterns match archetype=$ARCH yet \u2014 /crystallize builds the library\"; fi; else echo 'no global patterns yet \u2014 run /crystallize after first incident'; fi; [ -x \"${PLUGIN_DIR}/scripts/check-update.sh\" ] && bash \"${PLUGIN_DIR}/scripts/check-update.sh\" \"${PLUGIN_DIR}/.claude-plugin/plugin.json\" 2>/dev/null || true ; # great_cto-cache-cleanup: keep the newest 3 cached versions, and never one a live session runs from (prune-versions; the check install-local --prune got after 2026-09-11). for CR in \"$HOME\"/.claude/plugins/cache/*/great_cto; do [ -d \"$CR\" ] || continue; node \"${PLUGIN_DIR}/scripts/lib/prune-versions.mjs\" --cache-root \"$CR\" --keep \"${PLUGIN_DIR:-$CR/none}\" --keep-newest 3 2>/dev/null | while IFS= read -r d; do case \"$d\" in \"$CR\"/*) rm -rf \"$d\" ;; esac; done; done 2>/dev/null || true",
63
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; export PATH=\"/opt/homebrew/bin:$HOME/.local/bin:/usr/local/bin:$PATH\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; if [ -z \"$PLUGIN_DIR\" ]; then echo 'GREAT_CTO: plugin dir not found \u2014 run /update'; else mkdir -p ~/.great_cto .great_cto; node \"${PLUGIN_DIR}/scripts/lib/sync-managed.mjs\" --plugin-dir \"${PLUGIN_DIR}\" 2>/dev/null || true; cp \"${PLUGIN_DIR}/skills/great_cto/ARCHETYPES.md\" .great_cto/ARCHETYPES.md 2>/dev/null || true; cp \"${PLUGIN_DIR}/skills/great_cto/SKILL.md\" .great_cto/SKILL.md 2>/dev/null || true; { printf \"export PATH=/opt/homebrew/bin:$HOME/.local/bin:/usr/local/bin:$PATH\\nexport ARCHETYPES_MD=.great_cto/ARCHETYPES.md\\n\"; } > .great_cto/env.sh; fi; if [ ! -d ~/.great_cto/catalog ]; then git clone --depth=1 https://github.com/davila7/claude-code-templates.git ~/.great_cto/catalog 2>/dev/null & fi; if [ ! -d ~/.great_cto/anthropic-skills ]; then git clone --depth=1 https://github.com/anthropics/skills.git ~/.great_cto/anthropic-skills 2>/dev/null & elif [ $(($(date +%s) - $(stat -f %m ~/.great_cto/anthropic-skills/.git 2>/dev/null || stat -c %Y ~/.great_cto/anthropic-skills/.git 2>/dev/null || echo 0))) -gt 604800 ]; then (cd ~/.great_cto/anthropic-skills && git pull --quiet 2>/dev/null) & fi; if [ ! -d ~/.great_cto/personal-skills ]; then git clone --depth=1 https://github.com/avelikiy/ai-agent-skills.git ~/.great_cto/personal-skills 2>/dev/null & elif [ $(($(date +%s) - $(stat -f %m ~/.great_cto/personal-skills/.git 2>/dev/null || stat -c %Y ~/.great_cto/personal-skills/.git 2>/dev/null || echo 0))) -gt 86400 ]; then (cd ~/.great_cto/personal-skills && git pull --quiet 2>/dev/null) & fi; if [ ! -f ~/.great_cto/skills-registry.json ] || [ $(($(date +%s) - $(stat -f %m ~/.great_cto/skills-registry.json 2>/dev/null || stat -c %Y ~/.great_cto/skills-registry.json 2>/dev/null || echo 0))) -gt 86400 ]; then [ -x \"${PLUGIN_DIR}/scripts/skill-discover.sh\" ] && bash \"${PLUGIN_DIR}/scripts/skill-discover.sh\" >/dev/null 2>&1 & fi; [ -x \"${PLUGIN_DIR}/scripts/hooks/welcome.sh\" ] && bash \"${PLUGIN_DIR}/scripts/hooks/welcome.sh\" 2>/dev/null || true; bash \"${PLUGIN_DIR}/scripts/apply-model-override.sh\" 2>/dev/null || true; bd prime 2>/dev/null || true; cat \"${PLUGIN_DIR}/scripts/hooks/operating-rules.md\" 2>/dev/null || true; echo '=== PREFERENCES ==='; node \"${PLUGIN_DIR}/scripts/hooks/read-global-memory.mjs\" 2>&1 || true; echo '=== PROJECT ==='; cat .great_cto/PROJECT.md 2>/dev/null || echo 'GREAT_CTO: No PROJECT.md \u2014 run /start'; PHASE=$(grep '^phase:' .great_cto/PROJECT.md 2>/dev/null | awk '{print $2}' || echo implementation); echo '=== PHASE ==='; echo \"$PHASE\"; { [ \"$PHASE\" != review ] && [ \"$PHASE\" != release ]; } && { echo '=== BRAIN ==='; head -30 .great_cto/brain.md 2>/dev/null; } || true; [ \"$PHASE\" = implementation ] && { echo '=== CODEBASE ==='; head -20 .great_cto/CODEBASE.md 2>/dev/null; } || true; echo '=== LOCAL ==='; cat .great_cto/local.md 2>/dev/null || true; [ \"$PHASE\" != planning ] && { echo '=== HANDOFF ==='; cat .great_cto/HANDOFF.md 2>/dev/null || echo 'No handoff state \u2014 fresh session'; } || true; [ \"$PHASE\" = review ] && { echo '=== LATEST QA ==='; ls docs/qa-reports/QA-*.md 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | xargs head -20 2>/dev/null; echo '=== LATEST CSO ==='; ls docs/security/CSO-*.md 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | xargs head -20 2>/dev/null; } || true; [ \"$PHASE\" = release ] && { echo '=== PERF BASELINE ==='; tail -10 .great_cto/perf-baseline.log 2>/dev/null; } || true; echo '=== STATUS ==='; OPEN_GATES=$(bd list --label gate --status open 2>/dev/null | wc -l | tr -d ' '); OPEN_TASKS=$(bd list --status open 2>/dev/null | wc -l | tr -d ' '); BRANCH=$(git branch --show-current 2>/dev/null || echo '?'); LAST_AGENT=$(ls -t .great_cto/verdicts/*.log 2>/dev/null | head -1 | xargs tail -1 2>/dev/null | awk '{print $2}' || echo 'none'); printf 'branch=%s | gates=%s | tasks=%s | last_agent=%s\\n' \"$BRANCH\" \"${OPEN_GATES:-0}\" \"${OPEN_TASKS:-0}\" \"${LAST_AGENT:-none}\"; [ \"${OPEN_GATES:-0}\" -gt 0 ] && echo '\u2192 run /inbox to see pending decisions' || true; P0_OPEN=$(bd list --status open 2>/dev/null | grep -c 'P0'); P0_OPEN=${P0_OPEN:-0}; if [ \"$P0_OPEN\" -gt 0 ]; then echo ''; printf '\\033[41;97m \ud83d\udea8 P0 OPEN: %s \u2014 run /inbox NOW \\033[0m\\n' \"$P0_OPEN\"; bd list --status open 2>/dev/null | grep 'P0' | head -3 | sed 's/^/ /'; fi; NOW_EPOCH=$(date +%s); LAST_AUDIT_FILE=$(find docs/audit -maxdepth 1 -name 'AUDIT-*.md' 2>/dev/null | sort | tail -1); if [ -n \"$LAST_AUDIT_FILE\" ]; then AUD_M=$(stat -f %m \"$LAST_AUDIT_FILE\" 2>/dev/null || stat -c %Y \"$LAST_AUDIT_FILE\" 2>/dev/null || echo $NOW_EPOCH); AUD_AGE=$(( (NOW_EPOCH - AUD_M) / 86400 )); [ \"$AUD_AGE\" -gt 30 ] && echo \"\u26a0 audit $AUD_AGE days old \u2014 run /audit\"; else echo '\u26a0 no audit artefact \u2014 run /audit or /doctor'; fi; if [ -f .great_cto/digest-latest.md ]; then DIG_M=$(stat -f %m .great_cto/digest-latest.md 2>/dev/null || stat -c %Y .great_cto/digest-latest.md 2>/dev/null || echo $NOW_EPOCH); DIG_AGE=$(( (NOW_EPOCH - DIG_M) / 86400 )); [ \"$DIG_AGE\" -gt 8 ] && echo \"\u26a0 digest $DIG_AGE days old \u2014 run /digest 7\"; fi; [ \"$PHASE\" != implementation ] && cat .great_cto/digest-latest.md 2>/dev/null | head -5 || true; [ -f \"${PLUGIN_DIR}/scripts/hooks/auto-attach-reviewers.mjs\" ] && node \"${PLUGIN_DIR}/scripts/hooks/auto-attach-reviewers.mjs\" 2>/dev/null; [ -n \"$PLUGIN_DIR\" ] && [ -f .great_cto/PROJECT.md ] && [ ! -f .great_cto/CODEBASE.md ] && node \"${PLUGIN_DIR}/scripts/first-run-codebase.mjs\" >/dev/null 2>&1 & node \"${PLUGIN_DIR}/scripts/hooks/quota-check.mjs\" 2>/dev/null || true; echo '=== PATTERNS ==='; GP_DIR=\"$HOME/.great_cto/global-patterns\"; ARCH=$(grep '^primary:' .great_cto/PROJECT.md 2>/dev/null | awk '{print $2}' | head -1); if [ -d \"$GP_DIR\" ] && ls \"$GP_DIR\"/GP-*.md >/dev/null 2>&1; then ACTIVE_COUNT=$(grep -rl 'status: active' \"$GP_DIR\" 2>/dev/null | wc -l | tr -d ' '); echo \"Active patterns: ${ACTIVE_COUNT:-0}\"; if [ -n \"$ARCH\" ] && [ \"${ACTIVE_COUNT:-0}\" -gt 0 ]; then grep -rl 'status: active' \"$GP_DIR\" 2>/dev/null | xargs grep -lE \"applies_to:.*$ARCH\" 2>/dev/null | sort -V | tail -5 | while read f; do SLUG=$(basename \"$f\" .md); SYMPT=$(grep -m1 '^symptom:' \"$f\" 2>/dev/null | sed 's/symptom: //'); DETECT=$(grep -A 2 '^detection_order:' \"$f\" 2>/dev/null | grep '^ - ' | head -1 | sed 's/^ - //'); HITS=$(grep -m1 '^hits:' \"$f\" 2>/dev/null | awk '{print $2}'); printf ' %s (hits=%s): %s\\n \\u2192 Check first: %s\\n' \"$SLUG\" \"${HITS:-0}\" \"$SYMPT\" \"$DETECT\"; done || echo \" no patterns match archetype=$ARCH yet \u2014 /crystallize builds the library\"; fi; else echo 'no global patterns yet \u2014 run /crystallize after first incident'; fi; [ -x \"${PLUGIN_DIR}/scripts/check-update.sh\" ] && bash \"${PLUGIN_DIR}/scripts/check-update.sh\" \"${PLUGIN_DIR}/.claude-plugin/plugin.json\" 2>/dev/null || true ; # great_cto-cache-cleanup: keep the newest 3 cached versions, and never one a live session runs from (prune-versions; the check install-local --prune got after 2026-09-11). for CR in \"$HOME\"/.claude/plugins/cache/*/great_cto; do [ -d \"$CR\" ] || continue; node \"${PLUGIN_DIR}/scripts/lib/prune-versions.mjs\" --cache-root \"$CR\" --keep \"${PLUGIN_DIR:-$CR/none}\" --keep-newest 3 2>/dev/null | while IFS= read -r d; do case \"$d\" in \"$CR\"/*) rm -rf \"$d\" ;; esac; done; done 2>/dev/null || true",
64
64
  "timeout": 30,
65
65
  "statusMessage": "Loading Great CTO context..."
66
66
  },
67
67
  {
68
68
  "type": "command",
69
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/gate-expiry.mjs\" 2>/dev/null || true",
69
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/gate-expiry.mjs\" 2>/dev/null || true",
70
70
  "timeout": 10,
71
71
  "statusMessage": "Checking gate expiry (72h policy)..."
72
72
  },
73
73
  {
74
74
  "type": "command",
75
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; [ -n \"$PLUGIN_DIR\" ] && node \"${PLUGIN_DIR}/scripts/hooks/session-pipeline-resume.mjs\" 2>/dev/null || true",
75
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; [ -n \"$PLUGIN_DIR\" ] && node \"${PLUGIN_DIR}/scripts/hooks/session-pipeline-resume.mjs\" 2>/dev/null || true",
76
76
  "timeout": 10,
77
77
  "statusMessage": "Checking for pipeline work in flight..."
78
78
  },
79
79
  {
80
80
  "type": "command",
81
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed \"s|/$||\")}; [ -n \"$PLUGIN_DIR\" ] && node \"${PLUGIN_DIR}/scripts/hooks/register-project.mjs\" </dev/null 2>/dev/null || true",
81
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed \"s|/$||\")}; [ -n \"$PLUGIN_DIR\" ] && node \"${PLUGIN_DIR}/scripts/hooks/register-project.mjs\" </dev/null 2>/dev/null || true",
82
82
  "timeout": 10,
83
83
  "statusMessage": "Registering project on the board..."
84
84
  },
85
85
  {
86
86
  "type": "command",
87
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed \"s|/$||\")}; [ -n \"$PLUGIN_DIR\" ] && node \"${PLUGIN_DIR}/scripts/hooks/learner-report.mjs\" </dev/null 2>/dev/null || true",
87
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed \"s|/$||\")}; [ -n \"$PLUGIN_DIR\" ] && node \"${PLUGIN_DIR}/scripts/hooks/learner-report.mjs\" </dev/null 2>/dev/null || true",
88
88
  "timeout": 10
89
89
  }
90
90
  ]
@@ -96,7 +96,7 @@
96
96
  "hooks": [
97
97
  {
98
98
  "type": "command",
99
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; bd prime 2>/dev/null; echo '---GREAT_CTO-CONTEXT---'; cat .great_cto/PROJECT.md 2>/dev/null | head -30; echo '---BEADS-READY---'; bd ready 2>/dev/null | head -10; BRANCH=$(git branch --show-current 2>/dev/null || echo 'unknown'); LAST_COMMIT=$(git log --oneline -1 2>/dev/null || echo 'none'); UNCOMMITTED=$(git status --short 2>/dev/null | wc -l | tr -d ' '); OPEN_GATES=$(bd list --label gate --status open 2>/dev/null | head -5 || grep '\\[GATE:' .great_cto/tasks.md 2>/dev/null | head -5 || echo 'none'); OPEN_TASKS=$(bd list --status open 2>/dev/null | head -8 || echo 'none'); LAST_VERDICT=$(ls -t .great_cto/verdicts/*.log 2>/dev/null | head -1 | xargs tail -1 2>/dev/null || echo 'none'); LATEST_ARCH=$(ls docs/architecture/ARCH-*.md 2>/dev/null | sort | tail -1 || echo 'none'); LATEST_QA=$(ls docs/qa-reports/QA-*.md 2>/dev/null | sort | tail -1 || echo 'none'); LATEST_CSO=$(ls docs/security/CSO-*.md 2>/dev/null | sort | tail -1 || echo 'none'); printf '# Auto-Handoff \u2014 %s\\n\\n> Auto-saved by PreCompact hook. Next session: read this, then /inbox.\\n\\n## Git\\n- Branch: `%s` | Last commit: `%s` | Uncommitted: %s files\\n\\n## Open Gates\\n%s\\n\\n## Open Tasks\\n%s\\n\\n## Last Agent Verdict\\n%s\\n\\n## Latest Docs\\n- Arch: %s\\n- QA: %s\\n- Security: %s\\n\\n## Resume\\nRun `/inbox` to see pending gates, then continue pipeline.\\n' \"$(date '+%Y-%m-%d %H:%M')\" \"$BRANCH\" \"$LAST_COMMIT\" \"$UNCOMMITTED\" \"$OPEN_GATES\" \"$OPEN_TASKS\" \"$LAST_VERDICT\" \"$LATEST_ARCH\" \"$LATEST_QA\" \"$LATEST_CSO\" > .great_cto/HANDOFF.md 2>/dev/null; echo '---HANDOFF-SAVED---'; mkdir -p .great_cto/logs; LOG_DATE=$(date +%Y-%m-%d); LOG_TIME=$(date +%H:%M); LOG_FILE=\".great_cto/logs/session-${LOG_DATE}-autocompact.md\"; printf '---\\ndate: %s\\ntime: %s\\nduration: auto-saved (context compact)\\n---\\n\\n# Session: context compact snapshot\\n\\n## Done\\n%s\\n\\n## Pending\\n%s\\n\\n## Commits\\n%s\\n' \"$LOG_DATE\" \"$LOG_TIME\" \"$OPEN_TASKS\" \"$OPEN_TASKS\" \"$LAST_COMMIT\" > \"$LOG_FILE\" 2>/dev/null; echo '---SESSIONLOG-SAVED---'",
99
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; bd prime 2>/dev/null; echo '---GREAT_CTO-CONTEXT---'; cat .great_cto/PROJECT.md 2>/dev/null | head -30; echo '---BEADS-READY---'; bd ready 2>/dev/null | head -10; BRANCH=$(git branch --show-current 2>/dev/null || echo 'unknown'); LAST_COMMIT=$(git log --oneline -1 2>/dev/null || echo 'none'); UNCOMMITTED=$(git status --short 2>/dev/null | wc -l | tr -d ' '); OPEN_GATES=$(bd list --label gate --status open 2>/dev/null | head -5 || grep '\\[GATE:' .great_cto/tasks.md 2>/dev/null | head -5 || echo 'none'); OPEN_TASKS=$(bd list --status open 2>/dev/null | head -8 || echo 'none'); LAST_VERDICT=$(ls -t .great_cto/verdicts/*.log 2>/dev/null | head -1 | xargs tail -1 2>/dev/null || echo 'none'); LATEST_ARCH=$(ls docs/architecture/ARCH-*.md 2>/dev/null | sort | tail -1 || echo 'none'); LATEST_QA=$(ls docs/qa-reports/QA-*.md 2>/dev/null | sort | tail -1 || echo 'none'); LATEST_CSO=$(ls docs/security/CSO-*.md 2>/dev/null | sort | tail -1 || echo 'none'); printf '# Auto-Handoff \u2014 %s\\n\\n> Auto-saved by PreCompact hook. Next session: read this, then /inbox.\\n\\n## Git\\n- Branch: `%s` | Last commit: `%s` | Uncommitted: %s files\\n\\n## Open Gates\\n%s\\n\\n## Open Tasks\\n%s\\n\\n## Last Agent Verdict\\n%s\\n\\n## Latest Docs\\n- Arch: %s\\n- QA: %s\\n- Security: %s\\n\\n## Resume\\nRun `/inbox` to see pending gates, then continue pipeline.\\n' \"$(date '+%Y-%m-%d %H:%M')\" \"$BRANCH\" \"$LAST_COMMIT\" \"$UNCOMMITTED\" \"$OPEN_GATES\" \"$OPEN_TASKS\" \"$LAST_VERDICT\" \"$LATEST_ARCH\" \"$LATEST_QA\" \"$LATEST_CSO\" > .great_cto/HANDOFF.md 2>/dev/null; echo '---HANDOFF-SAVED---'; mkdir -p .great_cto/logs; LOG_DATE=$(date +%Y-%m-%d); LOG_TIME=$(date +%H:%M); LOG_FILE=\".great_cto/logs/session-${LOG_DATE}-autocompact.md\"; printf '---\\ndate: %s\\ntime: %s\\nduration: auto-saved (context compact)\\n---\\n\\n# Session: context compact snapshot\\n\\n## Done\\n%s\\n\\n## Pending\\n%s\\n\\n## Commits\\n%s\\n' \"$LOG_DATE\" \"$LOG_TIME\" \"$OPEN_TASKS\" \"$OPEN_TASKS\" \"$LAST_COMMIT\" > \"$LOG_FILE\" 2>/dev/null; echo '---SESSIONLOG-SAVED---'",
100
100
  "timeout": 15,
101
101
  "statusMessage": "Saving session state to HANDOFF.md..."
102
102
  }
@@ -109,13 +109,13 @@
109
109
  "hooks": [
110
110
  {
111
111
  "type": "command",
112
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; echo '=== PROJECT ==='; cat .great_cto/PROJECT.md 2>/dev/null | head -15; echo '=== BRAIN (stable knowledge) ==='; awk '/^## SEMANTIC/,/^## EPISODIC/' .great_cto/brain.md 2>/dev/null | head -60; echo '---'; awk '/^## PROCEDURAL/,/^## EPISODIC/' .great_cto/brain.md 2>/dev/null | head -40 || head -30 .great_cto/brain.md 2>/dev/null; echo '=== HANDOFF ==='; cat .great_cto/HANDOFF.md 2>/dev/null | head -20",
112
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; echo '=== PROJECT ==='; cat .great_cto/PROJECT.md 2>/dev/null | head -15; echo '=== BRAIN (stable knowledge) ==='; awk '/^## SEMANTIC/,/^## EPISODIC/' .great_cto/brain.md 2>/dev/null | head -60; echo '---'; awk '/^## PROCEDURAL/,/^## EPISODIC/' .great_cto/brain.md 2>/dev/null | head -40 || head -30 .great_cto/brain.md 2>/dev/null; echo '=== HANDOFF ==='; cat .great_cto/HANDOFF.md 2>/dev/null | head -20",
113
113
  "timeout": 5,
114
114
  "statusMessage": "Injecting project + brain + handoff context into agent..."
115
115
  },
116
116
  {
117
117
  "type": "command",
118
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/orchestrator-check.mjs\" 2>/dev/null || true",
118
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/orchestrator-check.mjs\" 2>/dev/null || true",
119
119
  "timeout": 5,
120
120
  "statusMessage": "Loading orchestrator contract..."
121
121
  }
@@ -128,14 +128,14 @@
128
128
  "hooks": [
129
129
  {
130
130
  "type": "command",
131
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/subagent-stop-completion.mjs\" 2>&1; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
131
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/subagent-stop-completion.mjs\" 2>&1; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
132
132
  "timeout": 5,
133
133
  "statusMessage": "Three-state completion check..."
134
134
  },
135
135
  {
136
136
  "type": "command",
137
137
  "async": true,
138
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/turn-snapshot.mjs\" 2>/dev/null || true"
138
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/turn-snapshot.mjs\" 2>/dev/null || true"
139
139
  }
140
140
  ]
141
141
  }
@@ -146,39 +146,9 @@
146
146
  "hooks": [
147
147
  {
148
148
  "type": "command",
149
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/orchestrator-check.mjs\" 2>/dev/null; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
150
- "timeout": 5,
151
- "statusMessage": "Inline subagent check..."
152
- },
153
- {
154
- "type": "command",
155
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/shared-tree-guard.mjs\"; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
156
- "timeout": 5,
157
- "statusMessage": "Checking shared working tree..."
158
- },
159
- {
160
- "type": "command",
161
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/gate-bypass-guard.mjs\"; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
162
- "timeout": 5,
163
- "statusMessage": "Checking git hooks are not skipped..."
164
- },
165
- {
166
- "type": "command",
167
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/destructive-guard.mjs\"; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
168
- "timeout": 5,
169
- "statusMessage": "Destructive-command check..."
170
- },
171
- {
172
- "type": "command",
173
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/frozen-gates-guard.mjs\"; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
174
- "timeout": 5,
175
- "statusMessage": "Checking for writes to frozen gates..."
176
- },
177
- {
178
- "type": "command",
179
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/lesson-tripwire.mjs\"; exit 0",
180
- "timeout": 5,
181
- "statusMessage": "Checking recorded lessons..."
149
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/bash-guards.mjs\"; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
150
+ "timeout": 15,
151
+ "statusMessage": "Checking the command (great_cto guards)..."
182
152
  }
183
153
  ]
184
154
  },
@@ -187,37 +157,37 @@
187
157
  "hooks": [
188
158
  {
189
159
  "type": "command",
190
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/secret-scan.mjs\" 2>&1; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
160
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/secret-scan.mjs\" 2>&1; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
191
161
  "timeout": 5,
192
162
  "statusMessage": "Scanning for secrets..."
193
163
  },
194
164
  {
195
165
  "type": "command",
196
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/frozen-gates-guard.mjs\" 2>&1; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
166
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/frozen-gates-guard.mjs\" 2>&1; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
197
167
  "timeout": 5,
198
168
  "statusMessage": "Checking frozen gates..."
199
169
  },
200
170
  {
201
171
  "type": "command",
202
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/gate-weakening-guard.mjs\"; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
172
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/gate-weakening-guard.mjs\"; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
203
173
  "timeout": 5,
204
174
  "statusMessage": "Checking no check is switched off..."
205
175
  },
206
176
  {
207
177
  "type": "command",
208
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/edit-scope-guard.mjs\" 2>&1; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
178
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/edit-scope-guard.mjs\" 2>&1; EXIT=$?; if [ $EXIT -eq 2 ]; then exit 2; fi; exit 0",
209
179
  "timeout": 5,
210
180
  "statusMessage": "Checking edit scope..."
211
181
  },
212
182
  {
213
183
  "type": "command",
214
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/edit-impact.mjs\" 2>/dev/null; exit 0",
184
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/edit-impact.mjs\" 2>/dev/null; exit 0",
215
185
  "timeout": 5,
216
186
  "statusMessage": "Finding what depends on this file..."
217
187
  },
218
188
  {
219
189
  "type": "command",
220
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/lesson-tripwire.mjs\" 2>/dev/null; exit 0",
190
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/lesson-tripwire.mjs\" 2>/dev/null; exit 0",
221
191
  "timeout": 5,
222
192
  "statusMessage": "Checking recorded lessons..."
223
193
  }
@@ -230,40 +200,40 @@
230
200
  "hooks": [
231
201
  {
232
202
  "type": "command",
233
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; INPUT=$(cat 2>/dev/null); FILE=$(echo \"$INPUT\" | python3 -c \"import sys,json; d=json.load(sys.stdin); print((d.get('tool_input') or {}).get('file_path') or d.get('file_path',''))\" 2>/dev/null); TOOL=$(echo \"$INPUT\" | python3 -c \"import sys,json; d=json.load(sys.stdin); print(d.get('tool_name',''))\" 2>/dev/null); if [ -n \"$FILE\" ]; then mkdir -p .great_cto 2>/dev/null; printf '%s %s %s\\n' \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\" \"$TOOL\" \"$FILE\" >> .great_cto/agent-writes.log 2>/dev/null; fi; true",
203
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; INPUT=$(cat 2>/dev/null); FILE=$(echo \"$INPUT\" | python3 -c \"import sys,json; d=json.load(sys.stdin); print((d.get('tool_input') or {}).get('file_path') or d.get('file_path',''))\" 2>/dev/null); TOOL=$(echo \"$INPUT\" | python3 -c \"import sys,json; d=json.load(sys.stdin); print(d.get('tool_name',''))\" 2>/dev/null); if [ -n \"$FILE\" ]; then mkdir -p .great_cto 2>/dev/null; printf '%s %s %s\\n' \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\" \"$TOOL\" \"$FILE\" >> .great_cto/agent-writes.log 2>/dev/null; fi; true",
234
204
  "timeout": 3,
235
205
  "async": true
236
206
  },
237
207
  {
238
208
  "type": "command",
239
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/format-check.mjs\" 2>/dev/null; true",
209
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/format-check.mjs\" 2>/dev/null; true",
240
210
  "timeout": 12,
241
211
  "async": true
242
212
  },
243
213
  {
244
214
  "type": "command",
245
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/typecheck-accumulate.mjs\" 2>/dev/null; true",
215
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/typecheck-accumulate.mjs\" 2>/dev/null; true",
246
216
  "timeout": 5
247
217
  },
248
218
  {
249
219
  "type": "command",
250
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/summary-enforce.mjs\" 2>/dev/null; true",
220
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/summary-enforce.mjs\" 2>/dev/null; true",
251
221
  "timeout": 5,
252
222
  "async": true
253
223
  },
254
224
  {
255
225
  "type": "command",
256
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/reviewer-nudge.mjs\" 2>/dev/null || true",
226
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/reviewer-nudge.mjs\" 2>/dev/null || true",
257
227
  "timeout": 5,
258
228
  "statusMessage": "Checking reviewer rules for this file..."
259
229
  },
260
230
  {
261
231
  "type": "command",
262
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/lesson-rules-check.mjs\" 2>/dev/null; true"
232
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/lesson-rules-check.mjs\" 2>/dev/null; true"
263
233
  },
264
234
  {
265
235
  "type": "command",
266
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/docs-reference-sync.mjs\" 2>/dev/null; true",
236
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/docs-reference-sync.mjs\" 2>/dev/null; true",
267
237
  "timeout": 25,
268
238
  "async": true
269
239
  }
@@ -274,14 +244,14 @@
274
244
  "hooks": [
275
245
  {
276
246
  "type": "command",
277
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/tool-failure.mjs\" 2>/dev/null || true",
247
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/tool-failure.mjs\" 2>/dev/null || true",
278
248
  "timeout": 3,
279
249
  "statusMessage": "Capturing tool failure...",
280
250
  "async": true
281
251
  },
282
252
  {
283
253
  "type": "command",
284
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/loop-detector.mjs\" 2>/dev/null || true",
254
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/loop-detector.mjs\" 2>/dev/null || true",
285
255
  "timeout": 3
286
256
  }
287
257
  ]
@@ -291,7 +261,7 @@
291
261
  "hooks": [
292
262
  {
293
263
  "type": "command",
294
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/pipeline-dispatcher.mjs\" 2>/dev/null || true",
264
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/pipeline-dispatcher.mjs\" 2>/dev/null || true",
295
265
  "timeout": 5,
296
266
  "statusMessage": "Computing next pipeline stage..."
297
267
  }
@@ -304,13 +274,13 @@
304
274
  "hooks": [
305
275
  {
306
276
  "type": "command",
307
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/session-end.mjs\" 2>/dev/null; true",
277
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/session-end.mjs\" 2>/dev/null; true",
308
278
  "timeout": 8,
309
279
  "statusMessage": "Saving session summary..."
310
280
  },
311
281
  {
312
282
  "type": "command",
313
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/session-status.mjs\" 2>/dev/null; true",
283
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/session-status.mjs\" 2>/dev/null; true",
314
284
  "timeout": 5
315
285
  }
316
286
  ]
@@ -322,22 +292,22 @@
322
292
  "hooks": [
323
293
  {
324
294
  "type": "command",
325
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; python3 \"${PLUGIN_DIR}/scripts/hooks/user-prompt-submit.py\" 2>/dev/null; true",
295
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; python3 \"${PLUGIN_DIR}/scripts/hooks/user-prompt-submit.py\" 2>/dev/null; true",
326
296
  "timeout": 3
327
297
  },
328
298
  {
329
299
  "type": "command",
330
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/cost-guard.mjs\" 2>&1 1>/dev/null; true",
300
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/cost-guard.mjs\" 2>&1 1>/dev/null; true",
331
301
  "timeout": 3
332
302
  },
333
303
  {
334
304
  "type": "command",
335
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; [ -n \"$GREAT_CTO_CLASS_TELEMETRY\" ] && { PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/classify-telemetry.mjs\" 2>/dev/null; }; true",
305
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; [ -n \"$GREAT_CTO_CLASS_TELEMETRY\" ] && { PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/classify-telemetry.mjs\" 2>/dev/null; }; true",
336
306
  "timeout": 3
337
307
  },
338
308
  {
339
309
  "type": "command",
340
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/session-status.mjs\" 2>/dev/null; true",
310
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/session-status.mjs\" 2>/dev/null; true",
341
311
  "timeout": 5
342
312
  }
343
313
  ]
@@ -349,7 +319,7 @@
349
319
  "hooks": [
350
320
  {
351
321
  "type": "command",
352
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; INPUT=$(cat 2>/dev/null); TOOL=$(echo \"$INPUT\" | python3 -c \"import sys,json; d=json.load(sys.stdin); print(d.get('tool_name','unknown'))\" 2>/dev/null); mkdir -p .great_cto 2>/dev/null; printf '%s PERMISSION_DENIED tool=%s\\n' \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\" \"$TOOL\" >> .great_cto/permission-denied.log 2>/dev/null; if [ \"$TOOL\" = \"Bash\" ] || [ \"$TOOL\" = \"Write\" ]; then printf '%s PERMISSION_DENIED %s \u2014 agent may be stuck. Run /inbox.\\n' \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\" \"$TOOL\" >> .great_cto/permission-denied.log 2>/dev/null; fi; true; node \"${CLAUDE_PLUGIN_ROOT}/scripts/lib/agent-events.mjs\" --emit denied --tool \"$TOOL\" 2>/dev/null || true",
322
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; INPUT=$(cat 2>/dev/null); TOOL=$(echo \"$INPUT\" | python3 -c \"import sys,json; d=json.load(sys.stdin); print(d.get('tool_name','unknown'))\" 2>/dev/null); mkdir -p .great_cto 2>/dev/null; printf '%s PERMISSION_DENIED tool=%s\\n' \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\" \"$TOOL\" >> .great_cto/permission-denied.log 2>/dev/null; if [ \"$TOOL\" = \"Bash\" ] || [ \"$TOOL\" = \"Write\" ]; then printf '%s PERMISSION_DENIED %s \u2014 agent may be stuck. Run /inbox.\\n' \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\" \"$TOOL\" >> .great_cto/permission-denied.log 2>/dev/null; fi; true; node \"${CLAUDE_PLUGIN_ROOT}/scripts/lib/agent-events.mjs\" --emit denied --tool \"$TOOL\" 2>/dev/null || true",
353
323
  "timeout": 3
354
324
  }
355
325
  ]
@@ -360,30 +330,30 @@
360
330
  "hooks": [
361
331
  {
362
332
  "type": "command",
363
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/pipeline-stall-guard.mjs\" 2>/dev/null || true"
333
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/pipeline-stall-guard.mjs\" 2>/dev/null || true"
364
334
  },
365
335
  {
366
336
  "type": "command",
367
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/cross-review-gate.mjs\" 2>/dev/null || true"
337
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/cross-review-gate.mjs\" 2>/dev/null || true"
368
338
  },
369
339
  {
370
340
  "type": "command",
371
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/stop-typecheck.mjs\" 2>/dev/null || true",
341
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/stop-typecheck.mjs\" 2>/dev/null || true",
372
342
  "timeout": 90
373
343
  },
374
344
  {
375
345
  "type": "command",
376
346
  "async": true,
377
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/turn-snapshot.mjs\" 2>/dev/null || true"
347
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/turn-snapshot.mjs\" 2>/dev/null || true"
378
348
  },
379
349
  {
380
350
  "type": "command",
381
351
  "async": true,
382
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/register-project.mjs\" 2>/dev/null || true"
352
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; node \"${CLAUDE_PLUGIN_ROOT}/scripts/hooks/register-project.mjs\" 2>/dev/null || true"
383
353
  },
384
354
  {
385
355
  "type": "command",
386
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/session-status.mjs\" 2>/dev/null; true",
356
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/session-status.mjs\" 2>/dev/null; true",
387
357
  "timeout": 5
388
358
  }
389
359
  ]
@@ -395,7 +365,7 @@
395
365
  "hooks": [
396
366
  {
397
367
  "type": "command",
398
- "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/session-status.mjs\" 2>/dev/null; true",
368
+ "command": "_gd=\"$PWD\"; while [ -n \"$_gd\" ] && { [ \"$_gd\" = \"$HOME\" ] || [ ! -f \"$_gd/.great_cto/PROJECT.md\" ]; }; do _gd=\"${_gd%/*}\"; done; [ -n \"$_gd\" ] && cd \"$_gd\"; PLUGIN_DIR=${CLAUDE_PLUGIN_ROOT:-$(ls -d ~/.claude/plugins/cache/*/great_cto/*/ 2>/dev/null | awk -F'/plugins/cache/' '{split($NF,p,\"/\"); print p[3], $0}' | sort -V | tail -1 | cut -d' ' -f2- | sed 's|/$||')}; node \"${PLUGIN_DIR}/scripts/hooks/session-status.mjs\" 2>/dev/null; true",
399
369
  "timeout": 5
400
370
  }
401
371
  ]
@@ -24,6 +24,7 @@
24
24
  // CLI (for hooks written in shell):
25
25
  // node scripts/lib/agent-events.mjs --emit <kind> [--tool <name>] [--agent <name>]
26
26
 
27
+ import { isGlobalLayer } from './great-cto-scope.mjs';
27
28
  import { appendFileSync, closeSync, fstatSync, mkdirSync, openSync, readFileSync, readSync, renameSync, statSync } from 'node:fs';
28
29
  import { join } from 'node:path';
29
30
 
@@ -72,6 +73,8 @@ export function makeEvent(input, { now = Date.now() } = {}) {
72
73
  export function appendEvent(dir, input, { now = Date.now(), env = process.env, maxBytes = MAX_BYTES } = {}) {
73
74
  try {
74
75
  if (env.GREAT_CTO_DISABLE_EVENTS === '1') return { ok: false, why: 'disabled by GREAT_CTO_DISABLE_EVENTS=1' };
76
+ // ~/.great_cto is every project's global layer, never one project's log.
77
+ if (isGlobalLayer(dir)) return { ok: false, why: 'the global layer is not a project' };
75
78
  const e = makeEvent(input, { now });
76
79
  if (!e) return { ok: false, why: `not an event kind: ${JSON.stringify(input?.kind)}` };
77
80
  const line = JSON.stringify(e) + '\n';
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Whose state, whose agent — the two questions a hook must answer before it
3
+ * writes anything or holds a turn.
4
+ *
5
+ * Hooks find "the project" by walking up from the working directory to the
6
+ * first `.great_cto/PROJECT.md`. The home directory has one: ~/.great_cto is
7
+ * the GLOBAL layer, read by every session of every project. So a session in a
8
+ * repository without great_cto walked up to $HOME and treated the global layer
9
+ * as its project — the learner did that until 3.49.1; on 07.10 the completion
10
+ * check wrote a cut-off code-reviewer of one project into ~/.great_cto, and the
11
+ * stall guard then told another session to resume it.
12
+ *
13
+ * And not every subagent is great_cto's: Explore, general-purpose, Plan and
14
+ * other plugins' agents (`feature-dev:code-reviewer`) record no verdict and
15
+ * were being asked for one.
16
+ */
17
+ import { existsSync, readdirSync } from 'node:fs';
18
+ import { homedir } from 'node:os';
19
+ import { dirname, join, resolve } from 'node:path';
20
+ import { fileURLToPath } from 'node:url';
21
+
22
+ export function globalLayerDir(home = homedir()) {
23
+ return resolve(home, '.great_cto');
24
+ }
25
+
26
+ /** The global layer is never a project's state directory. */
27
+ export function isGlobalLayer(dir, home = homedir()) {
28
+ return resolve(String(dir || '.great_cto')) === globalLayerDir(home);
29
+ }
30
+
31
+ /**
32
+ * A project's own state directory: not the global layer, and in use — set up
33
+ * with PROJECT.md, or already holding verdicts (a project can run agents before
34
+ * it is set up; one did, with a verdicts/ directory and no PROJECT.md).
35
+ */
36
+ export function isProjectState(dir, home = homedir()) {
37
+ const d = String(dir || '.great_cto');
38
+ return !isGlobalLayer(d, home) && (existsSync(join(d, 'PROJECT.md')) || existsSync(join(d, 'verdicts')));
39
+ }
40
+
41
+ /** great_cto's agents, by name: the plugin's own agents/ directory (or GREAT_CTO_AGENTS_DIR). */
42
+ export function roster(dir = process.env.GREAT_CTO_AGENTS_DIR || resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', 'agents')) {
43
+ try { return new Set(readdirSync(dir).filter((f) => f.endsWith('.md')).map((f) => f.slice(0, -3))); } catch { return new Set(); }
44
+ }
45
+
46
+ /**
47
+ * Is this subagent one of ours? `great-cto:qa-engineer` and `qa-engineer` are;
48
+ * `feature-dev:code-reviewer` is another plugin's even though the name matches,
49
+ * and `Explore` is Claude Code's. With no roster to compare against, a bare name
50
+ * is given the benefit of the doubt — refusing every check is worse.
51
+ */
52
+ export function isOurAgent(agentType, names = roster()) {
53
+ const raw = String(agentType || '').trim();
54
+ if (!raw) return false;
55
+ const i = raw.lastIndexOf(':');
56
+ const prefix = i > -1 ? raw.slice(0, i) : '';
57
+ const name = i > -1 ? raw.slice(i + 1) : raw;
58
+ if (prefix && !/^great[-_]cto$/.test(prefix)) return false;
59
+ return names.size ? names.has(name) : true;
60
+ }
@@ -11,18 +11,22 @@
11
11
  * The same walk is inlined in shell at the head of every hook command in
12
12
  * plugin.json (ROOT_SNIPPET below), so a hook is already in the root when it runs.
13
13
  */
14
+ import { homedir } from 'node:os';
14
15
  import { existsSync } from 'node:fs';
15
16
  import { dirname, join, resolve } from 'node:path';
16
17
 
17
- export function projectRoot(start = process.cwd()) {
18
+ export function projectRoot(start = process.cwd(), home = homedir()) {
18
19
  let dir = resolve(start);
20
+ const skip = resolve(home);
19
21
  for (;;) {
20
- if (existsSync(join(dir, '.great_cto', 'PROJECT.md'))) return dir;
22
+ // The home directory's .great_cto is the global layer, not a project: a
23
+ // repository without its own PROJECT.md used to resolve to $HOME here.
24
+ if (dir !== skip && existsSync(join(dir, '.great_cto', 'PROJECT.md'))) return dir;
21
25
  const up = dirname(dir);
22
26
  if (up === dir) return resolve(start);
23
27
  dir = up;
24
28
  }
25
29
  }
26
30
 
27
- /** POSIX sh, no subprocess: cd to the nearest ancestor with .great_cto/PROJECT.md, if any. */
28
- export const ROOT_SNIPPET = '_gd="$PWD"; while [ -n "$_gd" ] && [ ! -f "$_gd/.great_cto/PROJECT.md" ]; do _gd="${_gd%/*}"; done; [ -n "$_gd" ] && cd "$_gd"; ';
31
+ /** POSIX sh, no subprocess: cd to the nearest ancestor with .great_cto/PROJECT.md, if any — never $HOME, the global layer. */
32
+ export const ROOT_SNIPPET = '_gd="$PWD"; while [ -n "$_gd" ] && { [ "$_gd" = "$HOME" ] || [ ! -f "$_gd/.great_cto/PROJECT.md" ]; }; do _gd="${_gd%/*}"; done; [ -n "$_gd" ] && cd "$_gd"; ';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "great-cto",
3
- "version": "3.56.0",
3
+ "version": "3.57.0",
4
4
  "description": "One command install for the great_cto Claude Code plugin. Auto-detects your stack, picks the right archetype, bootstraps PROJECT.md.",
5
5
  "keywords": [
6
6
  "claude-code",