content-forge/.claude/hooks/guardian-check.sh
lizikk 29bcbb89db feat: add claude-md-guardian, thinking commands, and security fixes
- Add claude-md-guardian agent with SessionStart hook for auto CLAUDE.md maintenance
- Add 6 thinking commands: /my-world, /emerge, /challenge, /connect, /today, /close
- Add my-world skill for one-shot vault context loading
- Fix command injection vulnerability in init-vault.sh (use env vars)
- Add error handling and logging to vault-sync.sh
- Update write-article skill with complete frontmatter fields
- Upgrade CLAUDE.md to v1.3.0 with cycle time tracking and exit criteria

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:58:43 +08:00

110 lines
2.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# CLAUDE.md Guardian Check Script
# 在 SessionStart 时运行,检查项目变化
set -euo pipefail
# 获取脚本所在目录的父目录(项目根目录)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
GUARDIAN_DIR="$PROJECT_ROOT/.claude/guardian"
SNAPSHOT_FILE="$GUARDIAN_DIR/snapshot.json"
LOG_FILE="$GUARDIAN_DIR/guardian.log"
# 确保目录存在
mkdir -p "$GUARDIAN_DIR"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"
}
# 计算目录结构哈希(使用绝对路径)
get_structure_hash() {
cd "$PROJECT_ROOT"
find . -type f \( -name "*.md" -o -name "*.sh" -o -name "*.json" \) \
! -path "./content-forge/*" \
! -path "./.git/*" \
! -path "./node_modules/*" \
! -path "./.claude/guardian/*" \
-exec md5sum {} \; 2>/dev/null | sort | md5sum | cut -d' ' -f1
}
# 获取 skills 列表
get_skills() {
ls -1 "$PROJECT_ROOT/.claude/skills/" 2>/dev/null | sort | tr '\n' ',' | sed 's/,$//'
}
# 获取 commands 列表
get_commands() {
ls -1 "$PROJECT_ROOT/.claude/commands/" 2>/dev/null | sed 's/.md$//' | sort | tr '\n' ',' | sed 's/,$//'
}
# 检查是否首次运行
if [[ ! -f "$SNAPSHOT_FILE" ]]; then
log "首次运行,创建初始快照"
HASH=$(get_structure_hash)
SKILLS=$(get_skills)
COMMANDS=$(get_commands)
# 创建初始快照
cat > "$SNAPSHOT_FILE" << EOF
{
"last_check": "$(date -Iseconds)",
"structure_hash": "$HASH",
"skills": "$SKILLS",
"commands": "$COMMANDS",
"version": "1.0.0"
}
EOF
echo "GUARDIAN: 初始化完成,快照已创建"
exit 0
fi
# 对比变化
CURRENT_HASH=$(get_structure_hash)
STORED_HASH=$(jq -r '.structure_hash' "$SNAPSHOT_FILE")
CURRENT_SKILLS=$(get_skills)
STORED_SKILLS=$(jq -r '.skills' "$SNAPSHOT_FILE")
CURRENT_COMMANDS=$(get_commands)
STORED_COMMANDS=$(jq -r '.commands' "$SNAPSHOT_FILE")
CHANGES=""
if [[ "$CURRENT_HASH" != "$STORED_HASH" ]]; then
CHANGES="${CHANGES}结构变化 detected\n"
fi
if [[ "$CURRENT_SKILLS" != "$STORED_SKILLS" ]]; then
CHANGES="${CHANGES}Skills 变化: $STORED_SKILLS -> $CURRENT_SKILLS\n"
fi
if [[ "$CURRENT_COMMANDS" != "$STORED_COMMANDS" ]]; then
CHANGES="${CHANGES}Commands 变化: $STORED_COMMANDS -> $CURRENT_COMMANDS\n"
fi
if [[ -n "$CHANGES" ]]; then
log "检测到变化: $CHANGES"
# 更新快照
cat > "$SNAPSHOT_FILE" << EOF
{
"last_check": "$(date -Iseconds)",
"structure_hash": "$CURRENT_HASH",
"skills": "$CURRENT_SKILLS",
"commands": "$CURRENT_COMMANDS",
"version": "1.0.0"
}
EOF
echo "GUARDIAN: 检测到项目变化,建议更新 CLAUDE.md"
echo "变化内容:"
echo -e "$CHANGES"
echo ""
echo "运行 /claudeforge-skill 来更新 CLAUDE.md"
else
log "无变化"
# 静默退出,不输出任何内容
fi