初始化
This commit is contained in:
218
scripts/ai-guard.sh
Normal file
218
scripts/ai-guard.sh
Normal file
@@ -0,0 +1,218 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# AI Guard — 质量门禁脚本 (PHP Hyperf + Vue 3 双栈)
|
||||
# =============================================================================
|
||||
# 用法:
|
||||
# bash scripts/ai-guard.sh # 运行所有检查
|
||||
# bash scripts/ai-guard.sh --pre # 预提交检查
|
||||
# bash scripts/ai-guard.sh --post # 后执行检查
|
||||
# bash scripts/ai-guard.sh --quick # 快速检查 (lint + types)
|
||||
# =============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
WARN=0
|
||||
|
||||
LOG_DIR=".ai-logs/guard"
|
||||
mkdir -p "$LOG_DIR"
|
||||
LOG_FILE="$LOG_DIR/$(date +%Y-%m-%d).log"
|
||||
|
||||
HAS_NODE=false
|
||||
HAS_PHP=false
|
||||
|
||||
# Detect project stacks
|
||||
[ -f "package.json" ] && HAS_NODE=true
|
||||
[ -f "composer.json" ] && HAS_PHP=true
|
||||
|
||||
# Also check subdirectories
|
||||
[ -f "Case-Database-Frontend-user/package.json" ] && HAS_NODE=true
|
||||
[ -f "Case-Database-Frontend-admin/package.json" ] && HAS_NODE=true
|
||||
[ -f "Case-Database-Backend/composer.json" ] && HAS_PHP=true
|
||||
|
||||
log() {
|
||||
echo "[$(date +%H:%M:%S)] $*" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
check() {
|
||||
local name="$1"
|
||||
local cmd="$2"
|
||||
local required="${3:-true}"
|
||||
|
||||
printf " %-30s" "$name"
|
||||
|
||||
if eval "$cmd" > /dev/null 2>&1; then
|
||||
echo -e "${GREEN}✅ PASS${NC}"
|
||||
PASS=$((PASS + 1))
|
||||
log "PASS: $name"
|
||||
else
|
||||
if [ "$required" = "true" ]; then
|
||||
echo -e "${RED}❌ FAIL${NC}"
|
||||
FAIL=$((FAIL + 1))
|
||||
log "FAIL: $name"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ WARN${NC}"
|
||||
WARN=$((WARN + 1))
|
||||
log "WARN: $name"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# ----- 敏感信息扫描 -----
|
||||
check_secrets() {
|
||||
local name="Secret Scan"
|
||||
printf " %-30s" "$name"
|
||||
|
||||
local patterns=(
|
||||
'AKIA[0-9A-Z]{16}'
|
||||
'password\s*=\s*["'\''"][^"'\''"]+'
|
||||
'api[_-]?key\s*=\s*["'\''"][^"'\''"]+'
|
||||
'BEGIN\s+(RSA\s+)?PRIVATE\s+KEY'
|
||||
'ghp_[a-zA-Z0-9]{36}'
|
||||
'sk-[a-zA-Z0-9]{48}'
|
||||
)
|
||||
|
||||
local found=false
|
||||
for pattern in "${patterns[@]}"; do
|
||||
if git diff --cached --diff-filter=d -U0 2>/dev/null | grep -qiE "$pattern"; then
|
||||
found=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$found" = "true" ]; then
|
||||
echo -e "${RED}❌ FAIL — 检测到疑似密钥/凭证!${NC}"
|
||||
FAIL=$((FAIL + 1))
|
||||
log "FAIL: $name — secrets detected"
|
||||
else
|
||||
echo -e "${GREEN}✅ PASS${NC}"
|
||||
PASS=$((PASS + 1))
|
||||
log "PASS: $name"
|
||||
fi
|
||||
}
|
||||
|
||||
# ----- Context Doctor (lite) -----
|
||||
check_context_lite() {
|
||||
local name="Context Doctor Lite"
|
||||
printf " %-30s" "$name"
|
||||
|
||||
if bash scripts/context-doctor.sh --lite --strict > /dev/null 2>&1; then
|
||||
echo -e "${GREEN}✅ PASS${NC}"
|
||||
PASS=$((PASS + 1))
|
||||
log "PASS: $name"
|
||||
else
|
||||
echo -e "${RED}❌ FAIL${NC}"
|
||||
FAIL=$((FAIL + 1))
|
||||
log "FAIL: $name"
|
||||
echo -e " ${YELLOW}↳ 运行 'bash scripts/context-doctor.sh --lite --strict' 查看详情${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# ----- Frontend checks -----
|
||||
run_frontend_checks() {
|
||||
if [ "$HAS_NODE" = "true" ]; then
|
||||
for dir in Case-Database-Frontend-user Case-Database-Frontend-admin; do
|
||||
if [ -f "$dir/package.json" ]; then
|
||||
echo -e "\n ${BLUE}── Frontend ($dir) ──${NC}"
|
||||
check "ESLint ($dir)" "cd $dir && npm run lint --silent" "${1:-true}"
|
||||
if [ "${2:-false}" = "true" ]; then
|
||||
check "Frontend Tests ($dir)" "cd $dir && npm run test --silent" "false"
|
||||
check "Frontend Build ($dir)" "cd $dir && npm run build --silent" "false"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# ----- Backend checks -----
|
||||
run_backend_checks() {
|
||||
if [ "$HAS_PHP" = "true" ]; then
|
||||
echo -e "\n ${BLUE}── Backend (PHP Hyperf / Swoole) ──${NC}"
|
||||
|
||||
local BACKEND_DIR="."
|
||||
[ -d "Case-Database-Backend" ] && BACKEND_DIR="Case-Database-Backend"
|
||||
|
||||
check "PHPStan" "cd $BACKEND_DIR && composer analyse --no-progress 2>/dev/null || vendor/bin/phpstan analyse --no-progress" "${1:-true}"
|
||||
if [ "${2:-false}" = "true" ]; then
|
||||
check "PHPUnit" "cd $BACKEND_DIR && composer test --no-interaction 2>/dev/null || vendor/bin/phpunit" "false"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# ----- 主逻辑 -----
|
||||
MODE="${1:---post}"
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}🛡️ AI Guard — Quality Gateway (Dual Stack)${NC}"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
|
||||
if [ "$HAS_NODE" = "true" ]; then
|
||||
echo -e " ${GREEN}✓${NC} Frontend detected (package.json)"
|
||||
fi
|
||||
if [ "$HAS_PHP" = "true" ]; then
|
||||
echo -e " ${GREEN}✓${NC} Backend detected (composer.json)"
|
||||
fi
|
||||
|
||||
log "=== AI Guard Run: mode=$MODE node=$HAS_NODE php=$HAS_PHP ==="
|
||||
|
||||
case "$MODE" in
|
||||
--pre)
|
||||
echo -e "\n${BLUE}Mode: Pre-Commit${NC}"
|
||||
check_secrets
|
||||
check "File count (≤10)" "[ $(git diff --cached --name-only | wc -l) -le 10 ]" "false"
|
||||
check_context_lite
|
||||
;;
|
||||
--post)
|
||||
echo -e "\n${BLUE}Mode: Post-Execute${NC}"
|
||||
run_frontend_checks "true"
|
||||
run_backend_checks "true"
|
||||
check_secrets
|
||||
;;
|
||||
--quick)
|
||||
echo -e "\n${BLUE}Mode: Quick Check${NC}"
|
||||
run_frontend_checks "true"
|
||||
run_backend_checks "true"
|
||||
;;
|
||||
*)
|
||||
echo -e "\n${BLUE}Mode: Full Check${NC}"
|
||||
run_frontend_checks "true" "true"
|
||||
run_backend_checks "true" "true"
|
||||
|
||||
if [ "$HAS_NODE" = "true" ]; then
|
||||
for dir in Case-Database-Frontend-user Case-Database-Frontend-admin; do
|
||||
if [ -f "$dir/package.json" ]; then
|
||||
check "npm audit ($dir)" "cd $dir && npm audit --audit-level=high" "false"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if [ "$HAS_PHP" = "true" ]; then
|
||||
BD="."
|
||||
[ -d "Case-Database-Backend" ] && BD="Case-Database-Backend"
|
||||
check "composer audit" "cd $BD && composer audit" "false"
|
||||
fi
|
||||
|
||||
check_secrets
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo -e " ${GREEN}✅ $PASS passed${NC} ${RED}❌ $FAIL failed${NC} ${YELLOW}⚠️ $WARN warnings${NC}"
|
||||
echo ""
|
||||
|
||||
log "Summary: pass=$PASS fail=$FAIL warn=$WARN"
|
||||
|
||||
if [ "$FAIL" -gt 0 ]; then
|
||||
echo -e "${RED}💥 有必须修复的问题!${NC}"
|
||||
exit 1
|
||||
else
|
||||
echo -e "${GREEN}🎉 所有必要检查已通过!${NC}"
|
||||
exit 0
|
||||
fi
|
||||
347
scripts/context-doctor.sh
Normal file
347
scripts/context-doctor.sh
Normal file
@@ -0,0 +1,347 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# Context Doctor — 检查项目上下文健康状态
|
||||
# =============================================================================
|
||||
# 用法:
|
||||
# bash scripts/context-doctor.sh # 全量检查
|
||||
# bash scripts/context-doctor.sh --lite # 轻量检查(提交前)
|
||||
# bash scripts/context-doctor.sh --lite --strict
|
||||
# 功能: 检查规则文件/MCP配置/文档完整性/索引排除等
|
||||
# =============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
BLUE='\033[0;34m'
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
PASS=0
|
||||
WARN=0
|
||||
FAIL=0
|
||||
LITE_MODE=false
|
||||
STRICT_MODE=false
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--lite)
|
||||
LITE_MODE=true
|
||||
;;
|
||||
--strict)
|
||||
STRICT_MODE=true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
check_exists() {
|
||||
local label="$1"
|
||||
local path="$2"
|
||||
local required="${3:-true}"
|
||||
|
||||
printf " %-40s" "$label"
|
||||
if [ -e "$path" ]; then
|
||||
echo -e "${GREEN}✅${NC}"
|
||||
PASS=$((PASS + 1))
|
||||
elif [ "$required" = "true" ]; then
|
||||
echo -e "${RED}❌ Missing${NC}"
|
||||
FAIL=$((FAIL + 1))
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ Optional${NC}"
|
||||
WARN=$((WARN + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
check_mcp_enabled() {
|
||||
local server="$1"
|
||||
local required="${2:-true}"
|
||||
|
||||
printf " %-40s" " $server"
|
||||
if [ ! -f ".cursor/mcp.json" ]; then
|
||||
if [ "$required" = "true" ]; then
|
||||
echo -e "${RED}❌ mcp.json missing${NC}"
|
||||
FAIL=$((FAIL + 1))
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ mcp.json missing${NC}"
|
||||
WARN=$((WARN + 1))
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
if grep -q "\"$server\"" .cursor/mcp.json; then
|
||||
if python3 - <<PY >/dev/null 2>&1
|
||||
import json
|
||||
with open(".cursor/mcp.json", "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
srv = data.get("mcpServers", {}).get("$server", {})
|
||||
raise SystemExit(0 if srv.get("disabled") is False else 1)
|
||||
PY
|
||||
then
|
||||
echo -e "${GREEN}✅ enabled${NC}"
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
if [ "$required" = "true" ]; then
|
||||
echo -e "${YELLOW}⚠️ found but disabled${NC}"
|
||||
WARN=$((WARN + 1))
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ disabled${NC}"
|
||||
WARN=$((WARN + 1))
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [ "$required" = "true" ]; then
|
||||
echo -e "${YELLOW}⚠️ not configured${NC}"
|
||||
WARN=$((WARN + 1))
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ optional / not configured${NC}"
|
||||
WARN=$((WARN + 1))
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}🩺 Context Doctor — Health Check${NC}"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}📐 Cursor Rules${NC}"
|
||||
check_exists "Constitution" ".cursor/rules/000-constitution.mdc"
|
||||
check_exists "Workflow" ".cursor/rules/001-workflow.mdc"
|
||||
check_exists "Safety" ".cursor/rules/002-safety.mdc"
|
||||
check_exists "TypeScript" ".cursor/rules/010-typescript.mdc" "false"
|
||||
check_exists "Vue 3" ".cursor/rules/011-vue.mdc" "false"
|
||||
check_exists "Testing" ".cursor/rules/015-testing.mdc" "false"
|
||||
check_exists "Monitoring" ".cursor/rules/024-monitoring.mdc" "false"
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}🔌 MCP Configuration${NC}"
|
||||
check_exists "MCP Config" ".cursor/mcp.json"
|
||||
|
||||
if [ -f ".cursor/mcp.json" ]; then
|
||||
MCP_COUNT=$(grep -c '"command"' .cursor/mcp.json 2>/dev/null || echo 0)
|
||||
ENABLED_COUNT=$(grep -c '"disabled": false' .cursor/mcp.json 2>/dev/null || echo 0)
|
||||
printf " %-40s" "MCP Servers (total/enabled)"
|
||||
echo -e "${GREEN}$MCP_COUNT / $ENABLED_COUNT${NC}"
|
||||
|
||||
printf " %-40s" "Core MCP status"
|
||||
echo ""
|
||||
# Core servers for this template's workflow quality
|
||||
check_mcp_enabled "filesystem" "true"
|
||||
check_mcp_enabled "git" "true"
|
||||
check_mcp_enabled "context7" "true"
|
||||
check_mcp_enabled "fetch" "true"
|
||||
check_mcp_enabled "memory" "true"
|
||||
check_mcp_enabled "sequential-thinking" "true"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}📚 Documentation${NC}"
|
||||
if [ "$LITE_MODE" = "false" ]; then
|
||||
check_exists "PRD" "docs/vision/PRD.md"
|
||||
check_exists "System Design" "docs/architecture/system-design.md" "false"
|
||||
check_exists "Data Model" "docs/architecture/data-model.md" "false"
|
||||
check_exists "ADR Template" "docs/architecture/decisions/_template.md" "false"
|
||||
else
|
||||
check_exists "PRD" "docs/vision/PRD.md"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}🧠 Agent Skills${NC}"
|
||||
check_exists "Skills Directory" ".cursor/skills"
|
||||
check_exists "Skills Rule" ".cursor/rules/003-skills.mdc"
|
||||
if [ -d ".cursor/skills" ] && [ "$LITE_MODE" = "false" ]; then
|
||||
SKILL_COUNT=0
|
||||
SKILL_ERRORS=0
|
||||
for skill_dir in .cursor/skills/*/; do
|
||||
[ -d "$skill_dir" ] || continue
|
||||
skill_name=$(basename "$skill_dir")
|
||||
if [ -f "$skill_dir/SKILL.md" ]; then
|
||||
SKILL_COUNT=$((SKILL_COUNT + 1))
|
||||
skill_ok=true
|
||||
# 检查 frontmatter 起始符
|
||||
if ! head -1 "$skill_dir/SKILL.md" | grep -q "^---$"; then
|
||||
printf " %-40s" " $skill_name"
|
||||
echo -e "${RED}❌ Missing frontmatter (---)${NC}"
|
||||
SKILL_ERRORS=$((SKILL_ERRORS + 1))
|
||||
FAIL=$((FAIL + 1))
|
||||
skill_ok=false
|
||||
fi
|
||||
# 检查 name 字段
|
||||
if ! grep -q "^name:" "$skill_dir/SKILL.md"; then
|
||||
printf " %-40s" " $skill_name"
|
||||
echo -e "${RED}❌ Missing 'name:' field${NC}"
|
||||
SKILL_ERRORS=$((SKILL_ERRORS + 1))
|
||||
FAIL=$((FAIL + 1))
|
||||
skill_ok=false
|
||||
fi
|
||||
# 检查 description 字段
|
||||
if ! grep -q "^description:" "$skill_dir/SKILL.md"; then
|
||||
printf " %-40s" " $skill_name"
|
||||
echo -e "${RED}❌ Missing 'description:' field${NC}"
|
||||
SKILL_ERRORS=$((SKILL_ERRORS + 1))
|
||||
FAIL=$((FAIL + 1))
|
||||
skill_ok=false
|
||||
fi
|
||||
# 检查 description 长度不超过 1024 字符
|
||||
if grep -q "^description:" "$skill_dir/SKILL.md"; then
|
||||
desc_len=$(awk '/^description:/,/^[a-z]/' "$skill_dir/SKILL.md" | wc -c)
|
||||
if [ "$desc_len" -gt 1024 ]; then
|
||||
printf " %-40s" " $skill_name"
|
||||
echo -e "${YELLOW}⚠️ description > 1024 chars ($desc_len)${NC}"
|
||||
WARN=$((WARN + 1))
|
||||
fi
|
||||
fi
|
||||
else
|
||||
printf " %-40s" " $skill_name"
|
||||
echo -e "${RED}❌ Missing SKILL.md${NC}"
|
||||
SKILL_ERRORS=$((SKILL_ERRORS + 1))
|
||||
FAIL=$((FAIL + 1))
|
||||
fi
|
||||
done
|
||||
printf " %-40s" "Skills installed"
|
||||
if [ "$SKILL_ERRORS" -eq 0 ]; then
|
||||
echo -e "${GREEN}$SKILL_COUNT skills (all valid)${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}$SKILL_COUNT skills ($SKILL_ERRORS with errors)${NC}"
|
||||
fi
|
||||
# Token 成本估算
|
||||
SKILL_TOTAL_LINES=0
|
||||
for f in .cursor/skills/*/SKILL.md; do
|
||||
[ -f "$f" ] || continue
|
||||
lines=$(wc -l < "$f" 2>/dev/null || echo 0)
|
||||
SKILL_TOTAL_LINES=$((SKILL_TOTAL_LINES + lines))
|
||||
done
|
||||
printf " %-40s" "Total skill lines (SKILL.md only)"
|
||||
if [ "$SKILL_TOTAL_LINES" -lt 3000 ]; then
|
||||
echo -e "${GREEN}$SKILL_TOTAL_LINES lines${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}$SKILL_TOTAL_LINES lines (consider trimming)${NC}"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}🛠️ Tooling${NC}"
|
||||
check_exists "AI Guard" "scripts/ai-guard.sh"
|
||||
check_exists ".cursorignore" ".cursorignore"
|
||||
check_exists ".editorconfig" ".editorconfig" "false"
|
||||
check_exists ".gitignore" ".gitignore"
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}🔗 Reference Integrity${NC}"
|
||||
if command -v python3 >/dev/null 2>&1; then
|
||||
REF_CHECK=$(
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
root = Path(".")
|
||||
broken = []
|
||||
skill_refs = 0
|
||||
rule_refs = 0
|
||||
|
||||
# Skills: check references/*.md links in SKILL.md
|
||||
for skill in (root / ".cursor" / "skills").glob("*/SKILL.md"):
|
||||
text = skill.read_text(encoding="utf-8")
|
||||
refs = re.findall(r'`(references/[^`*]+\.md)`', text)
|
||||
for ref in refs:
|
||||
skill_refs += 1
|
||||
target = skill.parent / ref
|
||||
if not target.exists():
|
||||
broken.append((str(skill), ref))
|
||||
|
||||
# Rules: check .cursor/rules/references/*.md links in .mdc
|
||||
for rule in (root / ".cursor" / "rules").glob("*.mdc"):
|
||||
text = rule.read_text(encoding="utf-8")
|
||||
refs = re.findall(r'`(\.cursor/rules/references/[^`*]+\.md)`', text)
|
||||
for ref in refs:
|
||||
rule_refs += 1
|
||||
target = root / ref
|
||||
if not target.exists():
|
||||
broken.append((str(rule), ref))
|
||||
|
||||
print(f"SKILL_REFS={skill_refs}")
|
||||
print(f"RULE_REFS={rule_refs}")
|
||||
print(f"BROKEN={len(broken)}")
|
||||
for path, ref in broken[:10]:
|
||||
print(f"MISS:{path} -> {ref}")
|
||||
PY
|
||||
)
|
||||
|
||||
SKILL_REFS=$(echo "$REF_CHECK" | awk -F= '/^SKILL_REFS=/{print $2}')
|
||||
RULE_REFS=$(echo "$REF_CHECK" | awk -F= '/^RULE_REFS=/{print $2}')
|
||||
BROKEN_REFS=$(echo "$REF_CHECK" | awk -F= '/^BROKEN=/{print $2}')
|
||||
|
||||
printf " %-40s" "Skill reference links checked"
|
||||
echo -e "${GREEN}${SKILL_REFS:-0}${NC}"
|
||||
PASS=$((PASS + 1))
|
||||
|
||||
printf " %-40s" "Rule reference links checked"
|
||||
echo -e "${GREEN}${RULE_REFS:-0}${NC}"
|
||||
PASS=$((PASS + 1))
|
||||
|
||||
printf " %-40s" "Broken reference links"
|
||||
if [ "${BROKEN_REFS:-0}" -eq 0 ]; then
|
||||
echo -e "${GREEN}0${NC}"
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
echo -e "${RED}${BROKEN_REFS} (see below)${NC}"
|
||||
FAIL=$((FAIL + 1))
|
||||
echo "$REF_CHECK" | awk '/^MISS:/ { sub(/^MISS:/, " - "); print }'
|
||||
fi
|
||||
else
|
||||
printf " %-40s" "Reference link check"
|
||||
echo -e "${YELLOW}⚠️ skipped (python3 not found)${NC}"
|
||||
WARN=$((WARN + 1))
|
||||
fi
|
||||
|
||||
if [ "$LITE_MODE" = "false" ]; then
|
||||
echo ""
|
||||
echo -e "${BLUE}📊 Rule File Sizes${NC}"
|
||||
fi
|
||||
if [ -d ".cursor/rules" ] && [ "$LITE_MODE" = "false" ]; then
|
||||
TOTAL_LINES=0
|
||||
for f in .cursor/rules/*.mdc; do
|
||||
lines=$(wc -l < "$f" 2>/dev/null || echo 0)
|
||||
TOTAL_LINES=$((TOTAL_LINES + lines))
|
||||
done
|
||||
RULE_REF_COUNT=0
|
||||
if [ -d ".cursor/rules/references" ]; then
|
||||
RULE_REF_COUNT=$(find .cursor/rules/references -name "*.md" | wc -l)
|
||||
fi
|
||||
printf " %-40s" "Total rule lines"
|
||||
# New baseline after core/deep split:
|
||||
# <1500: lean core rules
|
||||
# <2500: healthy for medium projects
|
||||
# <3500: still usable, but consider more split
|
||||
if [ "$TOTAL_LINES" -lt 1500 ]; then
|
||||
echo -e "${GREEN}$TOTAL_LINES lines (Lean — core rules only)${NC}"
|
||||
elif [ "$TOTAL_LINES" -lt 2500 ]; then
|
||||
echo -e "${GREEN}$TOTAL_LINES lines (Healthy — split mode)${NC}"
|
||||
elif [ "$TOTAL_LINES" -lt 3500 ]; then
|
||||
echo -e "${YELLOW}$TOTAL_LINES lines (Manageable — consider more split)${NC}"
|
||||
else
|
||||
echo -e "${RED}$TOTAL_LINES lines (Heavy — may waste tokens)${NC}"
|
||||
fi
|
||||
if [ "$RULE_REF_COUNT" -gt 0 ]; then
|
||||
printf " %-40s" "Rule deep references"
|
||||
echo -e "${GREEN}$RULE_REF_COUNT files${NC}"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo -e " ${GREEN}✅ $PASS${NC} ${RED}❌ $FAIL${NC} ${YELLOW}⚠️ $WARN${NC}"
|
||||
|
||||
if [ "$FAIL" -gt 0 ]; then
|
||||
echo ""
|
||||
echo -e "${RED}Some critical files are missing. Run: bash scripts/setup.sh${NC}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
if [ "$FAIL" -gt 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$STRICT_MODE" = "true" ] && [ "$WARN" -gt 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
3
scripts/pre-commit
Normal file
3
scripts/pre-commit
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
# Git pre-commit hook — 调用 AI Guard 预提交检查
|
||||
bash scripts/ai-guard.sh --pre
|
||||
179
scripts/setup.sh
Normal file
179
scripts/setup.sh
Normal file
@@ -0,0 +1,179 @@
|
||||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# Vibe Cursor Pro — 一键初始化脚本 (PHP Hyperf + Vue 3 双栈)
|
||||
# =============================================================================
|
||||
# 用法: bash scripts/setup.sh
|
||||
# =============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
BLUE='\033[0;34m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}🚀 Vibe Cursor Pro — Setup (Dual Stack)${NC}"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
|
||||
# 1. 创建日志目录
|
||||
echo -e "${BLUE}📁 Creating directories...${NC}"
|
||||
mkdir -p .ai-logs/{decisions,costs,sessions,errors,guard}
|
||||
echo " ✅ .ai-logs/"
|
||||
|
||||
# 2. 确保脚本可执行
|
||||
chmod +x scripts/*.sh 2>/dev/null || true
|
||||
|
||||
# 3. 设置 Git Hooks
|
||||
if [ -d ".git" ]; then
|
||||
echo -e "${BLUE}🔗 Setting up Git hooks...${NC}"
|
||||
|
||||
mkdir -p .husky
|
||||
git config core.hooksPath .husky
|
||||
|
||||
# Pre-commit hook
|
||||
cat > .husky/pre-commit << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
bash scripts/ai-guard.sh --pre
|
||||
EOF
|
||||
chmod +x .husky/pre-commit
|
||||
|
||||
# Commit-msg hook (Conventional Commits)
|
||||
cat > .husky/commit-msg << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
commit_regex='^(feat|fix|refactor|test|docs|chore|style|perf|ci|build|revert)(\(.+\))?: .{1,100}'
|
||||
if ! grep -qE "$commit_regex" "$1"; then
|
||||
echo "❌ Invalid commit message format!"
|
||||
echo " Expected: type(scope): description"
|
||||
echo " Example: feat(auth): add OAuth login"
|
||||
exit 1
|
||||
fi
|
||||
EOF
|
||||
chmod +x .husky/commit-msg
|
||||
|
||||
echo " ✅ Git hooks installed (.husky, core.hooksPath set)"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ Not a git repository, skipping hooks${NC}"
|
||||
fi
|
||||
|
||||
# 4. 验证 Skills
|
||||
echo -e "${BLUE}🧠 Validating Agent Skills...${NC}"
|
||||
if [ -d ".cursor/skills" ]; then
|
||||
SKILL_COUNT=0
|
||||
for skill_dir in .cursor/skills/*/; do
|
||||
[ -d "$skill_dir" ] && [ -f "$skill_dir/SKILL.md" ] && ((SKILL_COUNT++))
|
||||
done
|
||||
echo " ✅ $SKILL_COUNT skills found"
|
||||
|
||||
find .cursor/skills -name "*.sh" -exec chmod +x {} \; 2>/dev/null || true
|
||||
else
|
||||
echo -e "${YELLOW} ⚠️ No skills directory — creating .cursor/skills/${NC}"
|
||||
mkdir -p .cursor/skills
|
||||
fi
|
||||
|
||||
# 5. 检测前端环境
|
||||
echo -e "${BLUE}🌐 Checking frontend environment...${NC}"
|
||||
if command -v node &> /dev/null; then
|
||||
NODE_VER=$(node --version)
|
||||
echo -e "${GREEN} ✅ Node.js ${NODE_VER} detected${NC}"
|
||||
else
|
||||
echo -e "${YELLOW} ⚠️ Node.js not found — frontend needs Node.js 20+${NC}"
|
||||
fi
|
||||
|
||||
if command -v npm &> /dev/null; then
|
||||
NPM_VER=$(npm --version)
|
||||
echo -e "${GREEN} ✅ npm ${NPM_VER} detected${NC}"
|
||||
else
|
||||
echo -e "${YELLOW} ⚠️ npm not found${NC}"
|
||||
fi
|
||||
|
||||
# 6. 检测后端环境
|
||||
echo -e "${BLUE}🐘 Checking backend environment...${NC}"
|
||||
if command -v php &> /dev/null; then
|
||||
PHP_VER=$(php -r 'echo PHP_VERSION;')
|
||||
echo -e "${GREEN} ✅ PHP ${PHP_VER} detected${NC}"
|
||||
|
||||
# Check minimum version
|
||||
PHP_MAJOR=$(echo "$PHP_VER" | cut -d. -f1)
|
||||
PHP_MINOR=$(echo "$PHP_VER" | cut -d. -f2)
|
||||
if [ "$PHP_MAJOR" -lt 8 ] || ([ "$PHP_MAJOR" -eq 8 ] && [ "$PHP_MINOR" -lt 1 ]); then
|
||||
echo -e "${RED} ❌ PHP >= 8.1 required, found ${PHP_VER}${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e "${YELLOW} ⚠️ PHP not found — backend needs PHP >= 8.1${NC}"
|
||||
fi
|
||||
|
||||
if command -v composer &> /dev/null; then
|
||||
COMPOSER_VER=$(composer --version 2>/dev/null | head -1)
|
||||
echo -e "${GREEN} ✅ ${COMPOSER_VER}${NC}"
|
||||
else
|
||||
echo -e "${YELLOW} ⚠️ Composer not found — install from https://getcomposer.org${NC}"
|
||||
fi
|
||||
|
||||
# Check Swoole extension
|
||||
if php -m 2>/dev/null | grep -qi swoole; then
|
||||
SWOOLE_VER=$(php -r 'echo swoole_version();' 2>/dev/null || echo 'unknown')
|
||||
echo -e "${GREEN} ✅ Swoole ${SWOOLE_VER} detected${NC}"
|
||||
else
|
||||
echo -e "${YELLOW} ⚠️ Swoole extension not found — install via: pecl install swoole${NC}"
|
||||
fi
|
||||
|
||||
# 7. 检测 Docker 环境
|
||||
echo -e "${BLUE}🐳 Checking Docker environment...${NC}"
|
||||
if command -v docker &> /dev/null; then
|
||||
DOCKER_VER=$(docker --version 2>/dev/null | head -1)
|
||||
echo -e "${GREEN} ✅ ${DOCKER_VER}${NC}"
|
||||
else
|
||||
echo -e "${YELLOW} ⚠️ Docker not found (optional for local dev)${NC}"
|
||||
fi
|
||||
|
||||
if docker compose version &> /dev/null; then
|
||||
COMPOSE_VER=$(docker compose version 2>/dev/null | head -1)
|
||||
echo -e "${GREEN} ✅ ${COMPOSE_VER}${NC}"
|
||||
else
|
||||
echo -e "${YELLOW} ⚠️ Docker Compose not found (optional)${NC}"
|
||||
fi
|
||||
|
||||
# 8. 安装依赖(如果目录存在)
|
||||
for dir in Case-Database-Frontend-user Case-Database-Frontend-admin; do
|
||||
if [ -f "$dir/package.json" ]; then
|
||||
echo -e "${BLUE}📦 Installing $dir dependencies...${NC}"
|
||||
(cd "$dir" && npm install) && echo " ✅ $dir dependencies installed" || echo -e "${RED} ❌ $dir install failed${NC}"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -f "Case-Database-Backend/composer.json" ]; then
|
||||
echo -e "${BLUE}📦 Installing backend dependencies...${NC}"
|
||||
(cd Case-Database-Backend && composer install --no-interaction) && echo " ✅ Backend dependencies installed" || echo -e "${RED} ❌ Backend install failed${NC}"
|
||||
fi
|
||||
|
||||
# 9. 添加到 .gitignore
|
||||
if [ -f ".gitignore" ]; then
|
||||
for pattern in ".ai-logs/" ".env*" "!.env.example"; do
|
||||
if ! grep -qF "$pattern" .gitignore; then
|
||||
echo "$pattern" >> .gitignore
|
||||
fi
|
||||
done
|
||||
echo " ✅ .gitignore updated"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}🎉 Setup complete!${NC}"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. Edit .cursor/mcp.json — fill in your API tokens"
|
||||
echo " 2. Edit docs/vision/PRD.md — describe your project"
|
||||
echo " 3. Open the project in Cursor"
|
||||
echo " 4. Tell Cursor: 读取 docs/vision/PRD.md,制定开发计划"
|
||||
echo ""
|
||||
echo "Development:"
|
||||
echo " • Frontend: cd Case-Database-Frontend-user (or Case-Database-Frontend-admin) && npm run dev"
|
||||
echo " • Backend: cd Case-Database-Backend && php bin/hyperf.php start"
|
||||
echo " • Docker: docker compose up -d"
|
||||
echo ""
|
||||
echo "Skills system:"
|
||||
echo " • Skills in .cursor/skills/"
|
||||
echo " • Run 'bash scripts/skill-manager.sh validate' to validate skills"
|
||||
echo " • Create new skills: ask Cursor \"创建新技能\""
|
||||
echo ""
|
||||
271
scripts/skill-manager.sh
Normal file
271
scripts/skill-manager.sh
Normal file
@@ -0,0 +1,271 @@
|
||||
#!/usr/bin/env bash
|
||||
# ================================================================
|
||||
# Skill Manager — Agent Skills 管理工具
|
||||
# 用法: bash scripts/skill-manager.sh <command> [args]
|
||||
# ================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SKILLS_DIR=".cursor/skills"
|
||||
AGENTS_DIR=".cursor/agents"
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
# ================================================================
|
||||
# Commands
|
||||
# ================================================================
|
||||
|
||||
cmd_list() {
|
||||
echo -e "${BLUE}📦 Agent Skills${NC}"
|
||||
echo "─────────────────────────────────────────────"
|
||||
|
||||
if [ ! -d "$SKILLS_DIR" ]; then
|
||||
echo -e "${RED} ✗ Skills 目录不存在${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local count=0
|
||||
for skill_dir in "$SKILLS_DIR"/*/; do
|
||||
[ -d "$skill_dir" ] || continue
|
||||
local skill_file="$skill_dir/SKILL.md"
|
||||
if [ -f "$skill_file" ]; then
|
||||
local name=$(grep -m1 '^name:' "$skill_file" | sed 's/name:\s*//')
|
||||
local desc=$(grep -A2 '^description:' "$skill_file" | tail -1 | sed 's/^\s*//')
|
||||
local lines=$(wc -l < "$skill_file")
|
||||
local has_refs=$( [ -d "${skill_dir}references" ] && echo "📚" || echo " " )
|
||||
local has_scripts=$( [ -d "${skill_dir}scripts" ] && echo "⚡" || echo " " )
|
||||
|
||||
printf " ${GREEN}%-22s${NC} ${has_refs}${has_scripts} (%3d lines) %s\n" \
|
||||
"$name" "$lines" "$desc"
|
||||
count=$((count + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
echo "─────────────────────────────────────────────"
|
||||
echo -e " 共 ${GREEN}${count}${NC} 个技能"
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}🤖 Subagents${NC}"
|
||||
echo "─────────────────────────────────────────────"
|
||||
|
||||
if [ -d "$AGENTS_DIR" ]; then
|
||||
for agent_file in "$AGENTS_DIR"/*.md; do
|
||||
[ -f "$agent_file" ] || continue
|
||||
local name=$(grep -m1 '^name:' "$agent_file" | sed 's/name:\s*//')
|
||||
local desc=$(grep -A1 '^description:' "$agent_file" | tail -1 | sed 's/^\s*//')
|
||||
local readonly_flag=$(grep -m1 '^readonly:' "$agent_file" | sed 's/readonly:\s*//')
|
||||
local mode=$( [ "$readonly_flag" = "true" ] && echo "🔒只读" || echo "✏️读写" )
|
||||
printf " ${GREEN}%-22s${NC} ${mode} %s\n" "$name" "$desc"
|
||||
done
|
||||
else
|
||||
echo -e " ${YELLOW}⚠ Agents 目录不存在${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_validate() {
|
||||
echo -e "${BLUE}🔍 验证 Agent Skills 规范合规性${NC}"
|
||||
echo "─────────────────────────────────────────────"
|
||||
|
||||
local errors=0
|
||||
local warnings=0
|
||||
|
||||
for skill_dir in "$SKILLS_DIR"/*/; do
|
||||
[ -d "$skill_dir" ] || continue
|
||||
local skill_name=$(basename "$skill_dir")
|
||||
local skill_file="$skill_dir/SKILL.md"
|
||||
|
||||
# Check SKILL.md exists
|
||||
if [ ! -f "$skill_file" ]; then
|
||||
echo -e " ${RED}✗${NC} ${skill_name}: 缺少 SKILL.md"
|
||||
errors=$((errors + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check name field
|
||||
if ! grep -q '^name:' "$skill_file"; then
|
||||
echo -e " ${RED}✗${NC} ${skill_name}: 缺少 name 字段"
|
||||
errors=$((errors + 1))
|
||||
fi
|
||||
|
||||
# Check description field
|
||||
if ! grep -q '^description:' "$skill_file"; then
|
||||
echo -e " ${RED}✗${NC} ${skill_name}: 缺少 description 字段"
|
||||
errors=$((errors + 1))
|
||||
fi
|
||||
|
||||
# Check name format (kebab-case)
|
||||
local name_val=$(grep -m1 '^name:' "$skill_file" | sed 's/name:[[:space:]]*//')
|
||||
if ! echo "$name_val" | grep -qE '^[a-z0-9]+(-[a-z0-9]+)*$'; then
|
||||
echo -e " ${RED}✗${NC} ${skill_name}: name 不符合 kebab-case 格式: '${name_val}'"
|
||||
errors=$((errors + 1))
|
||||
fi
|
||||
|
||||
# Check description length
|
||||
local desc_len=$(sed -n '/^description:/,/^---/{/^description:/d;/^---/d;p;}' "$skill_file" | wc -c)
|
||||
if [ "$desc_len" -gt 1024 ]; then
|
||||
echo -e " ${YELLOW}⚠${NC} ${skill_name}: description 超过 1024 字符 (${desc_len})"
|
||||
warnings=$((warnings + 1))
|
||||
fi
|
||||
|
||||
# Check file length
|
||||
local lines=$(wc -l < "$skill_file")
|
||||
if [ "$lines" -gt 300 ]; then
|
||||
echo -e " ${YELLOW}⚠${NC} ${skill_name}: SKILL.md 超过 300 行 (${lines}),建议拆分到 references/"
|
||||
warnings=$((warnings + 1))
|
||||
fi
|
||||
|
||||
# Check YAML frontmatter
|
||||
local fm_count=$(grep -c '^---$' "$skill_file")
|
||||
if [ "$fm_count" -lt 2 ]; then
|
||||
echo -e " ${RED}✗${NC} ${skill_name}: YAML frontmatter 格式不完整"
|
||||
errors=$((errors + 1))
|
||||
fi
|
||||
|
||||
# All checks passed
|
||||
if [ "$errors" -eq 0 ] && [ "$warnings" -eq 0 ]; then
|
||||
echo -e " ${GREEN}✓${NC} ${skill_name}"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "─────────────────────────────────────────────"
|
||||
if [ "$errors" -gt 0 ]; then
|
||||
echo -e " ${RED}✗ ${errors} 个错误${NC}, ${YELLOW}${warnings} 个警告${NC}"
|
||||
return 1
|
||||
elif [ "$warnings" -gt 0 ]; then
|
||||
echo -e " ${GREEN}✓ 全部通过${NC}, ${YELLOW}${warnings} 个警告${NC}"
|
||||
else
|
||||
echo -e " ${GREEN}✓ 全部验证通过${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_stats() {
|
||||
echo -e "${BLUE}📊 Skills 统计${NC}"
|
||||
echo "─────────────────────────────────────────────"
|
||||
|
||||
local total_skills=0
|
||||
local total_lines=0
|
||||
local total_refs=0
|
||||
local total_scripts=0
|
||||
|
||||
for skill_dir in "$SKILLS_DIR"/*/; do
|
||||
[ -d "$skill_dir" ] || continue
|
||||
local skill_file="$skill_dir/SKILL.md"
|
||||
[ -f "$skill_file" ] || continue
|
||||
|
||||
total_skills=$((total_skills + 1))
|
||||
total_lines=$((total_lines + $(wc -l < "$skill_file")))
|
||||
|
||||
if [ -d "${skill_dir}references" ]; then
|
||||
total_refs=$((total_refs + $(find "${skill_dir}references" -name "*.md" | wc -l)))
|
||||
fi
|
||||
if [ -d "${skill_dir}scripts" ]; then
|
||||
total_scripts=$((total_scripts + $(find "${skill_dir}scripts" -type f | wc -l)))
|
||||
fi
|
||||
done
|
||||
|
||||
local agents=0
|
||||
if [ -d "$AGENTS_DIR" ]; then
|
||||
agents=$(find "$AGENTS_DIR" -name "*.md" | wc -l)
|
||||
fi
|
||||
|
||||
echo " Skills: ${total_skills}"
|
||||
echo " Subagents: ${agents}"
|
||||
echo " 总行数: ${total_lines} lines"
|
||||
echo " 平均行数: $((total_lines / (total_skills > 0 ? total_skills : 1))) lines/skill"
|
||||
echo " 参考文档: ${total_refs} files"
|
||||
echo " 脚本: ${total_scripts} files"
|
||||
echo ""
|
||||
echo " 预估 Token (Tier 1 发现): ~$((total_skills * 40)) tokens"
|
||||
echo " 预估 Token (全量加载): ~$((total_lines * 2)) tokens"
|
||||
}
|
||||
|
||||
cmd_create() {
|
||||
local name="${1:-}"
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: skill-manager.sh create <skill-name>${NC}"
|
||||
echo " 名称必须是 kebab-case 格式"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Validate name format
|
||||
if ! echo "$name" | grep -qE '^[a-z0-9]+(-[a-z0-9]+)*$'; then
|
||||
echo -e "${RED}✗ 名称必须是 kebab-case: a-z, 0-9, 连字符${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local dir="$SKILLS_DIR/$name"
|
||||
if [ -d "$dir" ]; then
|
||||
echo -e "${RED}✗ 技能已存在: $dir${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
mkdir -p "$dir"
|
||||
cat > "$dir/SKILL.md" << 'TEMPLATE'
|
||||
---
|
||||
name: SKILL_NAME
|
||||
description: >
|
||||
Describe what this skill does and when to use it.
|
||||
Include trigger keywords in both English and Chinese.
|
||||
---
|
||||
|
||||
# Skill Title
|
||||
|
||||
## 触发条件
|
||||
|
||||
Describe when this skill should be activated.
|
||||
|
||||
## 执行流程
|
||||
|
||||
### 1. Step One
|
||||
|
||||
Specific, actionable instructions.
|
||||
|
||||
### 2. Step Two
|
||||
|
||||
More instructions.
|
||||
|
||||
## 验证
|
||||
|
||||
1. [ ] Check item 1
|
||||
2. [ ] Check item 2
|
||||
TEMPLATE
|
||||
|
||||
sed "s/SKILL_NAME/$name/g" "$dir/SKILL.md" > "$dir/SKILL.md.tmp" && mv "$dir/SKILL.md.tmp" "$dir/SKILL.md"
|
||||
|
||||
echo -e "${GREEN}✓ 技能已创建: $dir${NC}"
|
||||
echo " 编辑 $dir/SKILL.md 完善技能内容"
|
||||
}
|
||||
|
||||
# ================================================================
|
||||
# Main
|
||||
# ================================================================
|
||||
|
||||
cmd="${1:-help}"
|
||||
shift || true
|
||||
|
||||
case "$cmd" in
|
||||
list|ls) cmd_list ;;
|
||||
validate|v) cmd_validate ;;
|
||||
stats|s) cmd_stats ;;
|
||||
create|new) cmd_create "$@" ;;
|
||||
help|--help|-h)
|
||||
echo "Skill Manager — Agent Skills 管理工具"
|
||||
echo ""
|
||||
echo "用法: bash scripts/skill-manager.sh <command>"
|
||||
echo ""
|
||||
echo "命令:"
|
||||
echo " list 列出所有 Skills 和 Subagents"
|
||||
echo " validate 验证 SKILL.md 规范合规性"
|
||||
echo " stats 显示 Skills 统计信息"
|
||||
echo " create 创建新技能脚手架"
|
||||
echo " help 显示此帮助信息"
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}未知命令: $cmd${NC}"
|
||||
echo "运行 'bash scripts/skill-manager.sh help' 查看帮助"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user