name: mot description: 系统健康检查(MOT)针对技能、代理、钩子和内存 model: sonnet allowed-tools: [Read, Bash, Glob, Grep]
MOT - 系统健康检查
对所有Claude Code组件运行全面的健康检查。
用法
/mot # 全面审计(所有类别)
/mot skills # 仅技能
/mot agents # 仅代理
/mot hooks # 仅钩子
/mot memory # 仅内存系统
/mot --fix # 自动修复简单问题
/mot --quick # 仅P0检查(快速)
审计过程
阶段1:技能审计
# 计数技能
echo "=== 技能 ==="
SKILL_COUNT=$(find .claude/skills -name "SKILL.md" | wc -l | xargs)
echo "找到 $SKILL_COUNT 个技能文件"
# 检查前端元数据解析
FAIL=0
for skill in $(find .claude/skills -name "SKILL.md"); do
if ! head -1 "$skill" | grep -q "^---$"; then
echo "失败:无前端元数据:$skill"
FAIL=$((FAIL+1))
fi
done
echo "前端元数据:$((SKILL_COUNT - FAIL)) 通过,$FAIL 失败"
# 检查名称与目录匹配
FAIL=0
for skill in $(find .claude/skills -name "SKILL.md"); do
dir=$(basename $(dirname "$skill"))
name=$(grep "^name:" "$skill" 2>/dev/null | head -1 | cut -d: -f2 | xargs)
if [ -n "$name" ] && [ "$dir" != "$name" ]; then
echo "失败:名称不匹配 $dir vs $name"
FAIL=$((FAIL+1))
fi
done
echo "名称一致性:$((SKILL_COUNT - FAIL)) 通过,$FAIL 失败"
阶段2:代理审计
echo "=== 代理 ==="
AGENT_COUNT=$(ls .claude/agents/*.md 2>/dev/null | wc -l | xargs)
echo "找到 $AGENT_COUNT 个代理文件"
# 检查必需字段
FAIL=0
for agent in .claude/agents/*.md; do
[ -f "$agent" ] || continue
# 检查名称字段存在
if ! grep -q "^name:" "$agent"; then
echo "失败:缺少名称:$agent"
FAIL=$((FAIL+1))
continue
fi
# 检查模型是否有效
model=$(grep "^model:" "$agent" | head -1 | cut -d: -f2 | xargs)
case "$model" in
opus|sonnet|haiku) ;;
*) echo "失败:无效模型 '$model':$agent"; FAIL=$((FAIL+1)) ;;
esac
done
echo "代理验证:$((AGENT_COUNT - FAIL)) 通过,$FAIL 失败"
# 检查悬空引用(引用不存在的代理)
echo "检查代理交叉引用..."
for agent in .claude/agents/*.md; do
[ -f "$agent" ] || continue
# 查找子代理类型引用
refs=$(grep -oE 'subagent_type[=:]["'\'']*([a-z-]+)' "$agent" 2>/dev/null | sed 's/.*["'\'']//' | sed 's/["'\'']$//')
for ref in $refs; do
if [ ! -f ".claude/agents/$ref.md" ]; then
echo "警告:$agent 引用不存在的代理:$ref"
fi
done
done
阶段3:钩子审计
echo "=== 钩子 ==="
# 检查TypeScript源文件计数
TS_COUNT=$(ls .claude/hooks/src/*.ts 2>/dev/null | wc -l | xargs)
echo "找到 $TS_COUNT 个TypeScript源文件"
# 检查捆绑包是否存在
BUNDLE_COUNT=$(ls .claude/hooks/dist/*.mjs 2>/dev/null | wc -l | xargs)
echo "找到 $BUNDLE_COUNT 个已构建的捆绑包"
# 检查Shell包装器是否可执行
FAIL=0
for sh in .claude/hooks/*.sh; do
[ -f "$sh" ] || continue
if [ ! -x "$sh" ]; then
echo "失败:不可执行:$sh"
FAIL=$((FAIL+1))
fi
done
SH_COUNT=$(ls .claude/hooks/*.sh 2>/dev/null | wc -l | xargs)
echo "Shell包装器:$((SH_COUNT - FAIL)) 个可执行,$FAIL 个需要 chmod +x"
# 检查settings.json中注册的钩子是否存在
echo "检查注册的钩子..."
FAIL=0
# 从settings.json提取钩子命令并验证文件存在
grep -oE '"command":\s*"[^"]*\.sh"' .claude/settings.json 2>/dev/null | \
sed 's/.*"\([^"]*\.sh\)".*/\1/' | \
sed 's|\$CLAUDE_PROJECT_DIR|.claude|g' | \
sed "s|\$HOME|$HOME|g" | \
sort -u | while read hook; do
# 解析到实际路径
resolved=$(echo "$hook" | sed 's|^\./||')
if [ ! -f "$resolved" ] && [ ! -f "./$resolved" ]; then
echo "警告:注册的钩子未找到:$hook"
fi
done
阶段4:内存审计
echo "=== 内存系统 ==="
# 检查 DATABASE_URL
if [ -z "$DATABASE_URL" ]; then
echo "失败:DATABASE_URL 未设置"
else
echo "通过:DATABASE_URL 已设置"
# 测试连接
if psql "$DATABASE_URL" -c "SELECT 1" > /dev/null 2>&1; then
echo "通过:PostgreSQL 可访问"
# 检查 pgvector
if psql "$DATABASE_URL" -c "SELECT extname FROM pg_extension WHERE extname='vector'" 2>/dev/null | grep -q vector; then
echo "通过:pgvector 扩展已安装"
else
echo "失败:pgvector 扩展未安装"
fi
# 检查表是否存在
if psql "$DATABASE_URL" -c "\d archival_memory" > /dev/null 2>&1; then
echo "通过:archival_memory 表存在"
# 计数学习
COUNT=$(psql "$DATABASE_URL" -t -c "SELECT COUNT(*) FROM archival_memory" 2>/dev/null | xargs)
echo "信息:$COUNT 个学习已存储"
else
echo "失败:archival_memory 表缺失"
fi
else
echo "失败:PostgreSQL 不可访问"
fi
fi
# 检查Python依赖
echo "检查Python依赖..."
(cd opc && uv run python -c "import psycopg2; import pgvector; import sentence_transformers" 2>/dev/null) && \
echo "通过:Python 依赖可用" || \
echo "警告:某些 Python 依赖缺失"
阶段5:交叉引用审计
echo "=== 交叉引用 ==="
# 检查技能引用有效代理
echo "检查技能 → 代理引用..."
FAIL=0
for skill in $(find .claude/skills -name "SKILL.md"); do
refs=$(grep -oE 'subagent_type[=:]["'\'']*([a-z-]+)' "$skill" 2>/dev/null | sed 's/.*["'\'']//' | sed 's/["'\'']$//')
for ref in $refs; do
if [ -n "$ref" ] && [ ! -f ".claude/agents/$ref.md" ]; then
echo "失败:$skill 引用缺失的代理:$ref"
FAIL=$((FAIL+1))
fi
done
done
echo "技能→代理引用:$FAIL 个损坏"
自动修复(–fix 标志)
如果指定 --fix,自动修复:
-
使Shell包装器可执行
chmod +x .claude/hooks/*.sh -
如果TypeScript比捆绑包新,重新构建钩子
cd .claude/hooks && npm run build -
创建缺失的缓存目录
mkdir -p .claude/cache/agents/{scout,kraken,oracle,spark} mkdir -p .claude/cache/mot
输出格式
将完整报告写入 .claude/cache/mot/report-{timestamp}.md:
# MOT 健康报告
生成时间:{timestamp}
## 摘要
| 类别 | 通过 | 失败 | 警告 |
|------|------|------|------|
| 技能 | 204 | 2 | 0 |
| 代理 | 47 | 1 | 3 |
| 钩子 | 58 | 2 | 1 |
| 内存 | 4 | 0 | 1 |
| 交叉引用 | 0 | 0 | 2 |
## 发现的问题
### P0 - 关键
- [失败] 钩子构建失败:tldr-context-inject.ts
### P1 - 高
- [失败] 代理引用缺失:scot → scout(拼写错误)
### P2 - 中
- [警告] 3个钩子需要重新构建(dist比src旧)
### P3 - 低
- [信息] VOYAGE_API_KEY 未设置(使用本地 BGE)
退出代码
0- 所有 P0/P1 检查通过1- 任何 P0/P1 失败2- 仅 P2/P3 警告
快速模式(–quick)
仅运行 P0 检查:
- 前端元数据解析
- 钩子构建
- Shell包装器可执行
- PostgreSQL 可访问