- 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>
110 lines
2.8 KiB
Bash
Executable File
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
|