sillyspec 2.4.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.
- package/.claude/commands/sillyspec/archive.md +63 -0
- package/.claude/commands/sillyspec/brainstorm.md +463 -0
- package/.claude/commands/sillyspec/continue.md +44 -0
- package/.claude/commands/sillyspec/execute.md +255 -0
- package/.claude/commands/sillyspec/explore.md +88 -0
- package/.claude/commands/sillyspec/export.md +53 -0
- package/.claude/commands/sillyspec/init.md +166 -0
- package/.claude/commands/sillyspec/plan.md +238 -0
- package/.claude/commands/sillyspec/propose.md +234 -0
- package/.claude/commands/sillyspec/quick.md +62 -0
- package/.claude/commands/sillyspec/resume.md +100 -0
- package/.claude/commands/sillyspec/scan.md +672 -0
- package/.claude/commands/sillyspec/status.md +122 -0
- package/.claude/commands/sillyspec/verify.md +141 -0
- package/.claude/commands/sillyspec/workspace.md +122 -0
- package/README.md +158 -0
- package/SKILL.md +46 -0
- package/adapters/adapters.sh +172 -0
- package/bin/sillyspec.js +2 -0
- package/commands/sillyspec/archive.md +62 -0
- package/commands/sillyspec/brainstorm.md +462 -0
- package/commands/sillyspec/continue.md +41 -0
- package/commands/sillyspec/execute.md +254 -0
- package/commands/sillyspec/explore.md +85 -0
- package/commands/sillyspec/export.md +51 -0
- package/commands/sillyspec/init.md +163 -0
- package/commands/sillyspec/plan.md +237 -0
- package/commands/sillyspec/propose.md +233 -0
- package/commands/sillyspec/quick.md +59 -0
- package/commands/sillyspec/resume.md +99 -0
- package/commands/sillyspec/scan.md +671 -0
- package/commands/sillyspec/status.md +119 -0
- package/commands/sillyspec/verify.md +140 -0
- package/commands/sillyspec/workspace.md +120 -0
- package/package.json +14 -0
- package/scripts/init.sh +2 -0
- package/scripts/install.ps1 +316 -0
- package/scripts/scan-preprocess.sh +378 -0
- package/scripts/validate-all.sh +50 -0
- package/scripts/validate-plan.sh +44 -0
- package/scripts/validate-proposal.sh +87 -0
- package/scripts/validate-scan.sh +90 -0
- package/src/index.js +560 -0
- package/src/init.js +269 -0
- package/templates/archive.md +58 -0
- package/templates/brainstorm.md +458 -0
- package/templates/continue.md +39 -0
- package/templates/execute.md +250 -0
- package/templates/explore.md +83 -0
- package/templates/export.md +48 -0
- package/templates/init.md +161 -0
- package/templates/plan.md +233 -0
- package/templates/propose.md +229 -0
- package/templates/quick.md +57 -0
- package/templates/resume.md +95 -0
- package/templates/scan.md +667 -0
- package/templates/status.md +117 -0
- package/templates/verify.md +136 -0
- package/templates/workspace.md +117 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# SillySpec 扫描预处理脚本
|
|
3
|
+
# 用途:在 AI 介入前完成机械性工作,节省 token + 防止上下文爆炸
|
|
4
|
+
# 输出:.sillyspec/codebase/SCAN-RAW.md
|
|
5
|
+
#
|
|
6
|
+
# 用法:
|
|
7
|
+
# bash scripts/scan-preprocess.sh [目录]
|
|
8
|
+
# bash scripts/scan-preprocess.sh api # 只扫 api 目录
|
|
9
|
+
|
|
10
|
+
set -euo pipefail
|
|
11
|
+
|
|
12
|
+
TARGET_DIR="${1:-.}"
|
|
13
|
+
OUTPUT_DIR=".sillyspec/codebase"
|
|
14
|
+
OUTPUT_FILE="$OUTPUT_DIR/SCAN-RAW.md"
|
|
15
|
+
|
|
16
|
+
# ── 排除目录 ──
|
|
17
|
+
|
|
18
|
+
EXCLUDE_DIRS=(
|
|
19
|
+
"node_modules" "dist" ".git" "vendor" "build"
|
|
20
|
+
"__pycache__" ".next" "coverage" ".nuxt" "target"
|
|
21
|
+
".idea" ".vscode" ".DS_Store" "bin" "obj"
|
|
22
|
+
"tmp" "temp" "logs" ".cache" "out"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
build_exclude_args() {
|
|
26
|
+
local args=()
|
|
27
|
+
for d in "${EXCLUDE_DIRS[@]}"; do
|
|
28
|
+
args+=(-not -path "*/$d/*" -not -path "*/$d")
|
|
29
|
+
done
|
|
30
|
+
echo "${args[@]}"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
EXCLUDE_ARGS=$(build_exclude_args)
|
|
34
|
+
|
|
35
|
+
# ── 统计源文件 ──
|
|
36
|
+
|
|
37
|
+
echo "🔍 SillySpec 扫描预处理"
|
|
38
|
+
echo " 目标目录: $TARGET_DIR"
|
|
39
|
+
echo ""
|
|
40
|
+
|
|
41
|
+
# 文件类型分类
|
|
42
|
+
count_files() {
|
|
43
|
+
local ext="$1" label="$2"
|
|
44
|
+
local cmd="find \"$TARGET_DIR\" -type f -name \"*.$ext\" $EXCLUDE_ARGS 2>/dev/null | wc -l | tr -d ' '"
|
|
45
|
+
local n=$(eval "$cmd")
|
|
46
|
+
if [ "$n" -gt 0 ]; then
|
|
47
|
+
echo " $label: $n 个文件"
|
|
48
|
+
fi
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
echo "📊 文件统计:"
|
|
52
|
+
FILE_COUNT=0
|
|
53
|
+
TOTAL_SIZE=0
|
|
54
|
+
|
|
55
|
+
# 按语言统计
|
|
56
|
+
JAVA_COUNT=$(find "$TARGET_DIR" -type f -name "*.java" $EXCLUDE_ARGS 2>/dev/null | wc -l | tr -d ' ')
|
|
57
|
+
PY_COUNT=$(find "$TARGET_DIR" -type f -name "*.py" $EXCLUDE_ARGS 2>/dev/null | wc -l | tr -d ' ')
|
|
58
|
+
TS_COUNT=$(find "$TARGET_DIR" -type f \( -name "*.ts" -o -name "*.tsx" \) $EXCLUDE_ARGS 2>/dev/null | wc -l | tr -d ' ')
|
|
59
|
+
JS_COUNT=$(find "$TARGET_DIR" -type f \( -name "*.js" -o -name "*.jsx" \) $EXCLUDE_ARGS 2>/dev/null | wc -l | tr -d ' ')
|
|
60
|
+
GO_COUNT=$(find "$TARGET_DIR" -type f -name "*.go" $EXCLUDE_ARGS 2>/dev/null | wc -l | tr -d ' ')
|
|
61
|
+
RB_COUNT=$(find "$TARGET_DIR" -type f -name "*.rb" $EXCLUDE_ARGS 2>/dev/null | wc -l | tr -d ' ')
|
|
62
|
+
PHP_COUNT=$(find "$TARGET_DIR" -type f -name "*.php" $EXCLUDE_ARGS 2>/dev/null | wc -l | tr -d ' ')
|
|
63
|
+
RS_COUNT=$(find "$TARGET_DIR" -type f -name "*.rs" $EXCLUDE_ARGS 2>/dev/null | wc -l | tr -d ' ')
|
|
64
|
+
VUE_COUNT=$(find "$TARGET_DIR" -type f -name "*.vue" $EXCLUDE_ARGS 2>/dev/null | wc -l | tr -d ' ')
|
|
65
|
+
SQL_COUNT=$(find "$TARGET_DIR" -type f \( -name "*.sql" -o -name "*.prisma" \) $EXCLUDE_ARGS 2>/dev/null | wc -l | tr -d ' ')
|
|
66
|
+
YAML_COUNT=$(find "$TARGET_DIR" -type f \( -name "*.yaml" -o -name "*.yml" \) $EXCLUDE_ARGS 2>/dev/null | wc -l | tr -d ' ')
|
|
67
|
+
XML_COUNT=$(find "$TARGET_DIR" -type f \( -name "*.xml" \) $EXCLUDE_ARGS 2>/dev/null | wc -l | tr -d ' ')
|
|
68
|
+
|
|
69
|
+
# 配置文件
|
|
70
|
+
CONFIG_COUNT=$(find "$TARGET_DIR" -maxdepth 3 -type f \( -name "package.json" -o -name "pom.xml" -o -name "build.gradle" -o -name "go.mod" -o -name "requirements.txt" -o -name "Cargo.toml" -o -name "composer.json" -o -name "Gemfile" -o -name "*.csproj" \) $EXCLUDE_ARGS 2>/dev/null | wc -l | tr -d ' ')
|
|
71
|
+
|
|
72
|
+
[ "$JAVA_COUNT" -gt 0 ] && echo " Java: $JAVA_COUNT"
|
|
73
|
+
[ "$PY_COUNT" -gt 0 ] && echo " Python: $PY_COUNT"
|
|
74
|
+
[ "$TS_COUNT" -gt 0 ] && echo " TypeScript: $TS_COUNT"
|
|
75
|
+
[ "$JS_COUNT" -gt 0 ] && echo " JavaScript: $JS_COUNT"
|
|
76
|
+
[ "$GO_COUNT" -gt 0 ] && echo " Go: $GO_COUNT"
|
|
77
|
+
[ "$RB_COUNT" -gt 0 ] && echo " Ruby: $RB_COUNT"
|
|
78
|
+
[ "$PHP_COUNT" -gt 0 ] && echo " PHP: $PHP_COUNT"
|
|
79
|
+
[ "$RS_COUNT" -gt 0 ] && echo " Rust: $RS_COUNT"
|
|
80
|
+
[ "$VUE_COUNT" -gt 0 ] && echo " Vue: $VUE_COUNT"
|
|
81
|
+
[ "$SQL_COUNT" -gt 0 ] && echo " SQL/Schema: $SQL_COUNT"
|
|
82
|
+
[ "$XML_COUNT" -gt 0 ] && echo " XML: $XML_COUNT"
|
|
83
|
+
[ "$YAML_COUNT" -gt 0 ] && echo " YAML: $YAML_COUNT"
|
|
84
|
+
[ "$CONFIG_COUNT" -gt 0 ] && echo " 配置文件: $CONFIG_COUNT"
|
|
85
|
+
|
|
86
|
+
# 总计
|
|
87
|
+
ALL_SOURCE=$(find "$TARGET_DIR" -type f \( -name "*.java" -o -name "*.py" -o -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.go" -o -name "*.rb" -o -name "*.php" -o -name "*.rs" -o -name "*.vue" \) $EXCLUDE_ARGS 2>/dev/null)
|
|
88
|
+
FILE_COUNT=$(echo "$ALL_SOURCE" | wc -l | tr -d ' ')
|
|
89
|
+
[ -z "$FILE_COUNT" ] && FILE_COUNT=0
|
|
90
|
+
TOTAL_SIZE=$(echo "$ALL_SOURCE" | xargs cat 2>/dev/null | wc -c | tr -d ' ')
|
|
91
|
+
[ -z "$TOTAL_SIZE" ] && TOTAL_SIZE=0
|
|
92
|
+
|
|
93
|
+
TOTAL_SIZE_KB=$((TOTAL_SIZE / 1024))
|
|
94
|
+
|
|
95
|
+
echo ""
|
|
96
|
+
echo " ────────────────"
|
|
97
|
+
echo " 源文件总计: $FILE_COUNT 个"
|
|
98
|
+
echo " 源码总大小: ${TOTAL_SIZE_KB}KB"
|
|
99
|
+
|
|
100
|
+
# 时间估算
|
|
101
|
+
if [ "$FILE_COUNT" -lt 50 ]; then
|
|
102
|
+
EST_TIME="约 30 秒"
|
|
103
|
+
RISK="低"
|
|
104
|
+
elif [ "$FILE_COUNT" -lt 150 ]; then
|
|
105
|
+
EST_TIME="约 1-2 分钟"
|
|
106
|
+
RISK="低"
|
|
107
|
+
elif [ "$FILE_COUNT" -lt 300 ]; then
|
|
108
|
+
EST_TIME="约 3-5 分钟"
|
|
109
|
+
RISK="中"
|
|
110
|
+
elif [ "$FILE_COUNT" -lt 500 ]; then
|
|
111
|
+
EST_TIME="约 5-8 分钟"
|
|
112
|
+
RISK="中"
|
|
113
|
+
else
|
|
114
|
+
EST_TIME="约 8-15 分钟"
|
|
115
|
+
RISK="⚠️ 高(建议指定扫描区域)"
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
echo " 预计耗时: $EST_TIME"
|
|
119
|
+
echo " 上下文风险: $RISK"
|
|
120
|
+
|
|
121
|
+
# ── 目录分布 ──
|
|
122
|
+
|
|
123
|
+
echo ""
|
|
124
|
+
echo "📁 目录分布(源文件最多的目录):"
|
|
125
|
+
find "$TARGET_DIR" -type f \( -name "*.java" -o -name "*.py" -o -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.go" -o -name "*.vue" \) $EXCLUDE_ARGS 2>/dev/null \
|
|
126
|
+
| sed 's|/[^/]*$||' \
|
|
127
|
+
| sort | uniq -c | sort -rn | head -10 \
|
|
128
|
+
| while read count dir; do
|
|
129
|
+
echo " $count 个文件 $dir"
|
|
130
|
+
done
|
|
131
|
+
|
|
132
|
+
# ── 提取结构化信息 ──
|
|
133
|
+
|
|
134
|
+
mkdir -p "$OUTPUT_DIR"
|
|
135
|
+
|
|
136
|
+
echo ""
|
|
137
|
+
echo "🔧 提取结构化信息..."
|
|
138
|
+
|
|
139
|
+
{
|
|
140
|
+
echo "# SCAN-RAW.md — 扫描预处理结果"
|
|
141
|
+
echo ""
|
|
142
|
+
echo "> 由 scripts/scan-preprocess.sh 自动生成,AI 深度扫描时读取此文件。"
|
|
143
|
+
echo "> 生成时间: $(date '+%Y-%m-%d %H:%M:%S')"
|
|
144
|
+
echo ""
|
|
145
|
+
echo "## 项目概况"
|
|
146
|
+
echo "- 扫描目录: $TARGET_DIR"
|
|
147
|
+
echo "- 源文件数: $FILE_COUNT"
|
|
148
|
+
echo "- 源码大小: ${TOTAL_SIZE_KB}KB"
|
|
149
|
+
echo "- 预计耗时: $EST_TIME"
|
|
150
|
+
echo ""
|
|
151
|
+
|
|
152
|
+
# ── 配置文件内容 ──
|
|
153
|
+
echo "## 配置文件"
|
|
154
|
+
echo ""
|
|
155
|
+
|
|
156
|
+
for f in $(find "$TARGET_DIR" -maxdepth 3 -type f \( -name "package.json" -o -name "pom.xml" -o -name "build.gradle" -o -name "build.gradle.kts" -o -name "settings.gradle" -o -name "go.mod" -o -name "requirements.txt" -o -name "pyproject.toml" -o -name "Cargo.toml" -o -name "composer.json" -o -name "Gemfile" -o -name "*.csproj" -o -name "application.yml" -o -name "application.yaml" -o -name "application.properties" \) $EXCLUDE_ARGS 2>/dev/null | head -20); do
|
|
157
|
+
echo "### $f"
|
|
158
|
+
echo '```'
|
|
159
|
+
cat "$f" 2>/dev/null | head -50
|
|
160
|
+
echo '```'
|
|
161
|
+
echo ""
|
|
162
|
+
done
|
|
163
|
+
|
|
164
|
+
# ── 目录结构树 ──
|
|
165
|
+
echo "## 目录结构"
|
|
166
|
+
echo ""
|
|
167
|
+
echo '```'
|
|
168
|
+
find "$TARGET_DIR" -type f -not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "*/dist/*" -not -path "*/vendor/*" -not -path "*/build/*" -not -path "*/__pycache__/*" -not -path "*/.next/*" -not -path "*/target/*" -not -path "*/.idea/*" -not -path "*/.vscode/*" -not -path "*/bin/*" -not -path "*/obj/*" -not -path "*/tmp/*" | head -300 | sed "s|$TARGET_DIR/||" | sort
|
|
169
|
+
echo '```'
|
|
170
|
+
echo ""
|
|
171
|
+
|
|
172
|
+
# ── import/依赖关系 ──
|
|
173
|
+
echo "## 依赖关系(import 分析)"
|
|
174
|
+
echo ""
|
|
175
|
+
|
|
176
|
+
# Java imports
|
|
177
|
+
if [ "$JAVA_COUNT" -gt 0 ]; then
|
|
178
|
+
echo "### Java imports(出现频率 Top 30)"
|
|
179
|
+
echo '```'
|
|
180
|
+
find "$TARGET_DIR" -name "*.java" $EXCLUDE_ARGS 2>/dev/null | xargs grep -h "^import " 2>/dev/null | sed 's/import static //' | sort | uniq -c | sort -rn | head -30
|
|
181
|
+
echo '```'
|
|
182
|
+
echo ""
|
|
183
|
+
fi
|
|
184
|
+
|
|
185
|
+
# Python imports
|
|
186
|
+
if [ "$PY_COUNT" -gt 0 ]; then
|
|
187
|
+
echo "### Python imports(出现频率 Top 30)"
|
|
188
|
+
echo '```'
|
|
189
|
+
find "$TARGET_DIR" -name "*.py" $EXCLUDE_ARGS 2>/dev/null | xargs grep -h "^import \|^from " 2>/dev/null | sort | uniq -c | sort -rn | head -30
|
|
190
|
+
echo '```'
|
|
191
|
+
echo ""
|
|
192
|
+
fi
|
|
193
|
+
|
|
194
|
+
# TypeScript/JavaScript imports
|
|
195
|
+
if [ "$TS_COUNT" -gt 0 ] || [ "$JS_COUNT" -gt 0 ]; then
|
|
196
|
+
echo "### JS/TS imports(出现频率 Top 30)"
|
|
197
|
+
echo '```'
|
|
198
|
+
find "$TARGET_DIR" \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.vue" \) $EXCLUDE_ARGS 2>/dev/null | xargs grep -hE "^\s*(import |require\(|from ['\"])" 2>/dev/null | sed "s/.*from ['\"]//;s/.*require(['\"]//;s/['\").*//" | grep -v "^\." | grep -v "^@" | sort | uniq -c | sort -rn | head -30
|
|
199
|
+
echo '```'
|
|
200
|
+
echo ""
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
# Go imports
|
|
204
|
+
if [ "$GO_COUNT" -gt 0 ]; then
|
|
205
|
+
echo "### Go imports(出现频率 Top 30)"
|
|
206
|
+
echo '```'
|
|
207
|
+
find "$TARGET_DIR" -name "*.go" $EXCLUDE_ARGS 2>/dev/null | xargs grep -hE '^\s*"[a-zA-Z]' 2>/dev/null | sort | uniq -c | sort -rn | head -30
|
|
208
|
+
echo '```'
|
|
209
|
+
echo ""
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
# ── 类名/函数名提取 ──
|
|
213
|
+
echo "## 代码结构(类名/函数名)"
|
|
214
|
+
echo ""
|
|
215
|
+
|
|
216
|
+
# Java classes
|
|
217
|
+
if [ "$JAVA_COUNT" -gt 0 ]; then
|
|
218
|
+
echo "### Java 类和接口"
|
|
219
|
+
echo '```'
|
|
220
|
+
find "$TARGET_DIR" -name "*.java" $EXCLUDE_ARGS 2>/dev/null | xargs grep -hE "^\s*(public|protected|private|)?" | grep -E "(class |interface |enum |@Entity|@Table|@Controller|@Service|@Repository|@RestController|@Mapper|@Component)" | head -50
|
|
221
|
+
echo '```'
|
|
222
|
+
echo ""
|
|
223
|
+
fi
|
|
224
|
+
|
|
225
|
+
# Python classes/functions
|
|
226
|
+
if [ "$PY_COUNT" -gt 0 ]; then
|
|
227
|
+
echo "### Python 类和函数(Top 50)"
|
|
228
|
+
echo '```'
|
|
229
|
+
find "$TARGET_DIR" -name "*.py" $EXCLUDE_ARGS 2>/dev/null | xargs grep -hE "^(class |def |async def )" 2>/dev/null | head -50
|
|
230
|
+
echo '```'
|
|
231
|
+
echo ""
|
|
232
|
+
fi
|
|
233
|
+
|
|
234
|
+
# Go structs
|
|
235
|
+
if [ "$GO_COUNT" -gt 0 ]; then
|
|
236
|
+
echo "### Go 结构体和接口"
|
|
237
|
+
echo '```'
|
|
238
|
+
find "$TARGET_DIR" -name "*.go" -not -path "*/vendor/*" 2>/dev/null | xargs grep -hE "^(type .+ struct|type .+ interface)" 2>/dev/null | head -30
|
|
239
|
+
echo '```'
|
|
240
|
+
echo ""
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
# ── 数据库 Schema 文件位置 ──
|
|
244
|
+
echo "## 数据库 Schema 文件"
|
|
245
|
+
echo ""
|
|
246
|
+
|
|
247
|
+
SCHEMA_FILES=""
|
|
248
|
+
# Prisma
|
|
249
|
+
SCHEMA_FILES+="$(find "$TARGET_DIR" -name "schema.prisma" $EXCLUDE_ARGS 2>/dev/null) "
|
|
250
|
+
# MyBatis Mapper XML
|
|
251
|
+
SCHEMA_FILES+="$(find "$TARGET_DIR" -name "*Mapper.xml" $EXCLUDE_ARGS 2>/dev/null) "
|
|
252
|
+
# SQLAlchemy / Django models
|
|
253
|
+
SCHEMA_FILES+="$(find "$TARGET_DIR" -name "models.py" $EXCLUDE_ARGS 2>/dev/null) "
|
|
254
|
+
# TypeORM entities
|
|
255
|
+
SCHEMA_FILES+="$(find "$TARGET_DIR" -name "*.entity.ts" $EXCLUDE_ARGS 2>/dev/null) "
|
|
256
|
+
# Mongoose models
|
|
257
|
+
SCHEMA_FILES+="$(find "$TARGET_DIR" -name "*.model.ts" $EXCLUDE_ARGS 2>/dev/null) "
|
|
258
|
+
# SQL migrations
|
|
259
|
+
SCHEMA_FILES+="$(find "$TARGET_DIR" \( -name "*.sql" -o -name "*migration*" \) $EXCLUDE_ARGS 2>/dev/null) "
|
|
260
|
+
# Java entities
|
|
261
|
+
SCHEMA_FILES+="$(find "$TARGET_DIR" \( -path "*/entity/*" -o -path "*/model/*" \) -name "*.java" $EXCLUDE_ARGS 2>/dev/null) "
|
|
262
|
+
# Drizzle schema
|
|
263
|
+
SCHEMA_FILES+="$(find "$TARGET_DIR" -name "schema.ts" $EXCLUDE_ARGS 2>/dev/null) "
|
|
264
|
+
# Go GORM models
|
|
265
|
+
SCHEMA_FILES+="$(find "$TARGET_DIR" -name "models.go" -o -name "model.go" $EXCLUDE_ARGS 2>/dev/null) "
|
|
266
|
+
|
|
267
|
+
if [ -n "$SCHEMA_FILES" ]; then
|
|
268
|
+
echo "$SCHEMA_FILES" | tr ' ' '\n' | grep -v "^$" | while read -r f; do
|
|
269
|
+
if [ -n "$f" ] && [ -f "$f" ]; then
|
|
270
|
+
echo "- \`$f\`"
|
|
271
|
+
fi
|
|
272
|
+
done
|
|
273
|
+
echo ""
|
|
274
|
+
else
|
|
275
|
+
echo "未检测到数据库 schema 文件。"
|
|
276
|
+
echo ""
|
|
277
|
+
fi
|
|
278
|
+
|
|
279
|
+
# ── 框架检测 ──
|
|
280
|
+
echo "## 框架检测"
|
|
281
|
+
echo ""
|
|
282
|
+
|
|
283
|
+
# 检测 Web 框架
|
|
284
|
+
if find "$TARGET_DIR" -name "*.java" $EXCLUDE_ARGS 2>/dev/null | xargs grep -l "@RestController\|@Controller\|@RequestMapping\|@GetMapping\|@PostMapping" 2>/dev/null | head -1 | grep -q .; then
|
|
285
|
+
echo "- **Java Web**: Spring Boot (Spring MVC annotations detected)"
|
|
286
|
+
fi
|
|
287
|
+
if find "$TARGET_DIR" -name "*.java" $EXCLUDE_ARGS 2>/dev/null | xargs grep -l "mybatis\|MyBatis\|@Mapper\|@Select" 2>/dev/null | head -1 | grep -q .; then
|
|
288
|
+
echo "- **ORM**: MyBatis / MyBatis-Plus"
|
|
289
|
+
fi
|
|
290
|
+
if find "$TARGET_DIR" -name "*.java" $EXCLUDE_ARGS 2>/dev/null | xargs grep -l "@Entity\|@Table\|@Column\|JPA\|javax.persistence\|jakarta.persistence" 2>/dev/null | head -1 | grep -q .; then
|
|
291
|
+
echo "- **ORM**: JPA / Hibernate"
|
|
292
|
+
fi
|
|
293
|
+
if find "$TARGET_DIR" -name "pom.xml" $EXCLUDE_ARGS 2>/dev/null | xargs grep -l "mybatis-plus\|mybatis\|MybatisPlus" 2>/dev/null | head -1 | grep -q .; then
|
|
294
|
+
echo "- **增强**: MyBatis-Plus"
|
|
295
|
+
fi
|
|
296
|
+
|
|
297
|
+
if find "$TARGET_DIR" $EXCLUDE_ARGS 2>/dev/null | xargs grep -l "flask\|Flask" 2>/dev/null | head -1 | grep -q .; then
|
|
298
|
+
echo "- **Python Web**: Flask"
|
|
299
|
+
fi
|
|
300
|
+
if find "$TARGET_DIR" $EXCLUDE_ARGS 2>/dev/null | xargs grep -l "django\|Django" 2>/dev/null | head -1 | grep -q .; then
|
|
301
|
+
echo "- **Python Web**: Django"
|
|
302
|
+
fi
|
|
303
|
+
if find "$TARGET_DIR" $EXCLUDE_ARGS 2>/dev/null | xargs grep -l "fastapi\|FastAPI" 2>/dev/null | head -1 | grep -q .; then
|
|
304
|
+
echo "- **Python Web**: FastAPI"
|
|
305
|
+
fi
|
|
306
|
+
if find "$TARGET_DIR" -name "*.py" $EXCLUDE_ARGS 2>/dev/null | xargs grep -l "sqlalchemy\|SQLAlchemy" 2>/dev/null | head -1 | grep -q .; then
|
|
307
|
+
echo "- **ORM**: SQLAlchemy"
|
|
308
|
+
fi
|
|
309
|
+
|
|
310
|
+
if [ -f "$TARGET_DIR/package.json" ]; then
|
|
311
|
+
if grep -q "vue" "$TARGET_DIR/package.json" 2>/dev/null; then
|
|
312
|
+
echo "- **Frontend**: Vue.js"
|
|
313
|
+
fi
|
|
314
|
+
if grep -q "react\|next" "$TARGET_DIR/package.json" 2>/dev/null; then
|
|
315
|
+
echo "- **Frontend**: React / Next.js"
|
|
316
|
+
fi
|
|
317
|
+
if grep -q "express" "$TARGET_DIR/package.json" 2>/dev/null; then
|
|
318
|
+
echo "- **Backend**: Express.js"
|
|
319
|
+
fi
|
|
320
|
+
if grep -q "nestjs\|NestJS" "$TARGET_DIR/package.json" 2>/dev/null; then
|
|
321
|
+
echo "- **Backend**: NestJS"
|
|
322
|
+
fi
|
|
323
|
+
if grep -q "prisma" "$TARGET_DIR/package.json" 2>/dev/null; then
|
|
324
|
+
echo "- **ORM**: Prisma"
|
|
325
|
+
fi
|
|
326
|
+
if grep -q "typeorm\|TypeORM" "$TARGET_DIR/package.json" 2>/dev/null; then
|
|
327
|
+
echo "- **ORM**: TypeORM"
|
|
328
|
+
fi
|
|
329
|
+
fi
|
|
330
|
+
|
|
331
|
+
if [ "$GO_COUNT" -gt 0 ] && find "$TARGET_DIR" $EXCLUDE_ARGS 2>/dev/null | xargs grep -l "gorm.io\|GORM\|gorm.Model" 2>/dev/null | head -1 | grep -q .; then
|
|
332
|
+
echo "- **ORM**: GORM"
|
|
333
|
+
fi
|
|
334
|
+
if [ "$GO_COUNT" -gt 0 ] && find "$TARGET_DIR" $EXCLUDE_ARGS 2>/dev/null | xargs grep -l "gin\|Gin\|gin.Context" 2>/dev/null | head -1 | grep -q .; then
|
|
335
|
+
echo "- **Web**: Gin"
|
|
336
|
+
fi
|
|
337
|
+
if [ "$GO_COUNT" -gt 0 ] && find "$TARGET_DIR" $EXCLUDE_ARGS 2>/dev/null | xargs grep -l "echo\|Echo\|labstack/echo" 2>/dev/null | head -1 | grep -q .; then
|
|
338
|
+
echo "- **Web**: Echo"
|
|
339
|
+
fi
|
|
340
|
+
|
|
341
|
+
echo ""
|
|
342
|
+
|
|
343
|
+
# ── 框架隐形规则相关文件 ──
|
|
344
|
+
echo "## 框架配置文件(隐形规则扫描参考)"
|
|
345
|
+
echo ""
|
|
346
|
+
|
|
347
|
+
FRAMEWORK_FILES=""
|
|
348
|
+
FRAMEWORK_FILES+="$(find "$TARGET_DIR" \( -name "*Interceptor*.java" -o -name "*Plugin*.java" -o -name "mybatis-config.xml" \) $EXCLUDE_ARGS 2>/dev/null) "
|
|
349
|
+
FRAMEWORK_FILES+="$(find "$TARGET_DIR" \( -name "*Auditor*.java" -o -name "*EventListener*.java" \) $EXCLUDE_ARGS 2>/dev/null) "
|
|
350
|
+
FRAMEWORK_FILES+="$(find "$TARGET_DIR" -name "settings.py" -maxdepth 3 $EXCLUDE_ARGS 2>/dev/null) "
|
|
351
|
+
FRAMEWORK_FILES+="$(find "$TARGET_DIR" \( -name "*event*.py" -o -name "*listener*.py" -o -name "*mixin*.py" \) $EXCLUDE_ARGS 2>/dev/null) "
|
|
352
|
+
FRAMEWORK_FILES+="$(find "$TARGET_DIR" \( -name "Base*.java" -o -name "Abstract*.java" \) \( -path "*/entity/*" -o -path "*/model/*" -o -path "*/po/*" \) $EXCLUDE_ARGS 2>/dev/null) "
|
|
353
|
+
FRAMEWORK_FILES+="$(find "$TARGET_DIR" \( -name "*.rb" \) $EXCLUDE_ARGS 2>/dev/null | xargs grep -l "acts_as_paranoid\|acts_as_tenant" 2>/dev/null) "
|
|
354
|
+
|
|
355
|
+
if [ -n "$FRAMEWORK_FILES" ]; then
|
|
356
|
+
echo "$FRAMEWORK_FILES" | tr ' ' '\n' | grep -v "^$" | while read -r f; do
|
|
357
|
+
if [ -n "$f" ] && [ -f "$f" ]; then
|
|
358
|
+
echo "- \`$f\`"
|
|
359
|
+
fi
|
|
360
|
+
done
|
|
361
|
+
echo ""
|
|
362
|
+
else
|
|
363
|
+
echo "未检测到框架配置文件。"
|
|
364
|
+
echo ""
|
|
365
|
+
fi
|
|
366
|
+
|
|
367
|
+
echo "---"
|
|
368
|
+
echo "预处理完成。AI 深度扫描时读取此文件,不需要再遍历原始源码。"
|
|
369
|
+
|
|
370
|
+
} > "$OUTPUT_FILE"
|
|
371
|
+
|
|
372
|
+
echo ""
|
|
373
|
+
echo "✅ 预处理完成"
|
|
374
|
+
echo " 输出文件: $OUTPUT_FILE"
|
|
375
|
+
echo " 文件大小: $(wc -c < "$OUTPUT_FILE" | tr -d ' ') bytes"
|
|
376
|
+
echo ""
|
|
377
|
+
echo " 下一步: /sillyspec:scan --deep"
|
|
378
|
+
echo " AI 会读取 SCAN-RAW.md 而不是原始源码,大幅节省上下文。"
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# SillySpec 综合校验
|
|
3
|
+
# 用法:validate-all.sh
|
|
4
|
+
|
|
5
|
+
echo "========================================="
|
|
6
|
+
echo " SillySpec 综合校验"
|
|
7
|
+
echo "========================================="
|
|
8
|
+
|
|
9
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
10
|
+
ERRORS=0
|
|
11
|
+
|
|
12
|
+
# 1. 检查 SillySpec 安装
|
|
13
|
+
echo ""
|
|
14
|
+
echo "📦 检查安装状态..."
|
|
15
|
+
if [ -d ".claude/commands/sillyspec" ]; then
|
|
16
|
+
cmd_count=$(ls .claude/commands/sillyspec/*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
17
|
+
echo " ✅ 已安装 $cmd_count 个 commands"
|
|
18
|
+
else
|
|
19
|
+
echo " ❌ 未安装 SillySpec commands"
|
|
20
|
+
((ERRORS++))
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
# 2. 检查当前变更
|
|
24
|
+
echo ""
|
|
25
|
+
echo "📋 检查变更..."
|
|
26
|
+
LATEST=$(ls -d .sillyspec/changes/*/ 2>/dev/null | grep -v archive | tail -1)
|
|
27
|
+
if [ -n "$LATEST" ]; then
|
|
28
|
+
echo " 📁 当前变更: $LATEST"
|
|
29
|
+
"$SCRIPT_DIR/validate-proposal.sh" "$LATEST" || ((ERRORS++))
|
|
30
|
+
else
|
|
31
|
+
echo " ℹ️ 无活跃变更"
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# 3. 检查代码库文档
|
|
35
|
+
echo ""
|
|
36
|
+
echo "🗂️ 检查代码库文档..."
|
|
37
|
+
if [ -d ".sillyspec/codebase" ]; then
|
|
38
|
+
"$SCRIPT_DIR/validate-scan.sh" ".sillyspec/codebase" || ((ERRORS++))
|
|
39
|
+
else
|
|
40
|
+
echo " ℹ️ 无代码库文档(新项目或未 scan)"
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
echo ""
|
|
44
|
+
echo "========================================="
|
|
45
|
+
if [ $ERRORS -eq 0 ]; then
|
|
46
|
+
echo " ✅ 全部通过"
|
|
47
|
+
else
|
|
48
|
+
echo " ❌ $ERRORS 个问题需要处理"
|
|
49
|
+
fi
|
|
50
|
+
echo "========================================="
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# SillySpec 校验:plan 阶段输出
|
|
3
|
+
# 用法:validate-plan.sh <change-dir>
|
|
4
|
+
|
|
5
|
+
CHANGE_DIR="${1:?用法: validate-plan.sh <change-dir>}"
|
|
6
|
+
ERRORS=0
|
|
7
|
+
|
|
8
|
+
echo "🔍 校验计划 $CHANGE_DIR/tasks.md ..."
|
|
9
|
+
|
|
10
|
+
if [ ! -f "$CHANGE_DIR/tasks.md" ]; then
|
|
11
|
+
echo "❌ tasks.md 不存在"
|
|
12
|
+
exit 1
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
# 检查每个 task 是否有文件路径
|
|
16
|
+
task_no_path=0
|
|
17
|
+
while IFS= read -r line; do
|
|
18
|
+
task_name=$(echo "$line" | sed 's/.*Task [0-9]*: //')
|
|
19
|
+
# 简单检查:task 行之后 5 行内是否有路径相关关键词
|
|
20
|
+
echo " 📋 $line"
|
|
21
|
+
done < <(grep '^\- \[ \] Task' "$CHANGE_DIR/tasks.md")
|
|
22
|
+
|
|
23
|
+
# 检查是否有验证命令
|
|
24
|
+
if grep -q "验证" "$CHANGE_DIR/tasks.md"; then
|
|
25
|
+
echo " ✅ 包含验证步骤"
|
|
26
|
+
else
|
|
27
|
+
echo " ⚠️ 建议添加验证步骤"
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# 检查是否有 Wave 分组
|
|
31
|
+
if grep -qi "wave\|并行\|依赖" "$CHANGE_DIR/tasks.md"; then
|
|
32
|
+
echo " ✅ 包含执行顺序标注"
|
|
33
|
+
else
|
|
34
|
+
echo " ⚠️ 建议添加 Wave 分组"
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# 检查文件变更清单一致性
|
|
38
|
+
if [ -f "$CHANGE_DIR/design.md" ]; then
|
|
39
|
+
design_files=$(grep -c '|' "$CHANGE_DIR/design.md" 2>/dev/null)
|
|
40
|
+
echo " ✅ design.md 有 $design_files 行表格"
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
echo ""
|
|
44
|
+
echo "✅ 计划校验完成"
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# SillySpec 校验:propose 阶段输出
|
|
3
|
+
# 用法:validate-proposal.sh <change-dir>
|
|
4
|
+
# 示例:validate-proposal.sh .sillyspec/changes/docsite-redesign
|
|
5
|
+
|
|
6
|
+
CHANGE_DIR="${1:?用法: validate-proposal.sh <change-dir>}"
|
|
7
|
+
ERRORS=0
|
|
8
|
+
|
|
9
|
+
check_section() {
|
|
10
|
+
local file="$1" section="$2"
|
|
11
|
+
if [ -f "$file" ]; then
|
|
12
|
+
if grep -q "## $section" "$file"; then
|
|
13
|
+
echo " ✅ $file: 包含 '$section'"
|
|
14
|
+
else
|
|
15
|
+
echo " ❌ $file: 缺少 '$section'"
|
|
16
|
+
((ERRORS++))
|
|
17
|
+
fi
|
|
18
|
+
else
|
|
19
|
+
echo " ❌ 文件不存在: $file"
|
|
20
|
+
((ERRORS++))
|
|
21
|
+
fi
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
check_file_exists() {
|
|
25
|
+
if [ -f "$1" ]; then
|
|
26
|
+
echo " ✅ $1 存在"
|
|
27
|
+
else
|
|
28
|
+
echo " ❌ $1 不存在"
|
|
29
|
+
((ERRORS++))
|
|
30
|
+
fi
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
echo "🔍 校验 $CHANGE_DIR ..."
|
|
34
|
+
|
|
35
|
+
# proposal.md
|
|
36
|
+
echo ""
|
|
37
|
+
echo "--- proposal.md ---"
|
|
38
|
+
check_section "$CHANGE_DIR/proposal.md" "动机"
|
|
39
|
+
check_section "$CHANGE_DIR/proposal.md" "变更范围"
|
|
40
|
+
check_section "$CHANGE_DIR/proposal.md" "不在范围内"
|
|
41
|
+
check_section "$CHANGE_DIR/proposal.md" "成功标准"
|
|
42
|
+
|
|
43
|
+
# design.md
|
|
44
|
+
echo ""
|
|
45
|
+
echo "--- design.md ---"
|
|
46
|
+
check_file_exists "$CHANGE_DIR/design.md"
|
|
47
|
+
check_section "$CHANGE_DIR/design.md" "文件变更清单"
|
|
48
|
+
if [ -f "$CHANGE_DIR/design.md" ]; then
|
|
49
|
+
if grep -q "|" "$CHANGE_DIR/design.md"; then
|
|
50
|
+
echo " ✅ design.md: 包含变更表格"
|
|
51
|
+
else
|
|
52
|
+
echo " ❌ design.md: 缺少变更表格"
|
|
53
|
+
((ERRORS++))
|
|
54
|
+
fi
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# tasks.md
|
|
58
|
+
echo ""
|
|
59
|
+
echo "--- tasks.md ---"
|
|
60
|
+
check_file_exists "$CHANGE_DIR/tasks.md"
|
|
61
|
+
if [ -f "$CHANGE_DIR/tasks.md" ]; then
|
|
62
|
+
task_count=$(grep -c '^\- \[ \] Task' "$CHANGE_DIR/tasks.md" 2>/dev/null)
|
|
63
|
+
echo " ✅ tasks.md: $task_count 个 task"
|
|
64
|
+
if [ "$task_count" -eq 0 ]; then
|
|
65
|
+
echo " ❌ tasks.md: 没有 task"
|
|
66
|
+
((ERRORS++))
|
|
67
|
+
fi
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# requirements.md
|
|
71
|
+
echo ""
|
|
72
|
+
echo "--- requirements.md ---"
|
|
73
|
+
if [ -f "$CHANGE_DIR/specs/requirements.md" ]; then
|
|
74
|
+
check_section "$CHANGE_DIR/specs/requirements.md" "功能需求"
|
|
75
|
+
check_section "$CHANGE_DIR/specs/requirements.md" "用户场景"
|
|
76
|
+
else
|
|
77
|
+
check_file_exists "$CHANGE_DIR/specs/requirements.md"
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
echo ""
|
|
81
|
+
if [ $ERRORS -eq 0 ]; then
|
|
82
|
+
echo "✅ 校验通过,无错误"
|
|
83
|
+
exit 0
|
|
84
|
+
else
|
|
85
|
+
echo "❌ 校验失败,$ERRORS 个错误"
|
|
86
|
+
exit 1
|
|
87
|
+
fi
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# SillySpec 校验:scan 阶段输出
|
|
3
|
+
# 用法:validate-scan.sh [codebase-dir]
|
|
4
|
+
# 默认检查 .sillyspec/codebase/
|
|
5
|
+
|
|
6
|
+
CODEBASE_DIR="${1:-.sillyspec/codebase}"
|
|
7
|
+
ERRORS=0
|
|
8
|
+
|
|
9
|
+
# ── 路径误放检查 ──
|
|
10
|
+
|
|
11
|
+
MISPLACED=0
|
|
12
|
+
TARGET_DOCS="ARCHITECTURE.md STACK.md STRUCTURE.md CONVENTIONS.md INTEGRATIONS.md TESTING.md CONCERNS.md PROJECT.md SCAN-RAW.md"
|
|
13
|
+
|
|
14
|
+
for name in $TARGET_DOCS; do
|
|
15
|
+
for f in $(find . -maxdepth 2 -name "$name" 2>/dev/null | grep -v "^\.\/$CODEBASE_DIR/"); do
|
|
16
|
+
if [ -f "$f" ]; then
|
|
17
|
+
echo " ❌ 误放: $f(应在 $CODEBASE_DIR/ 下)"
|
|
18
|
+
((MISPLACED++))
|
|
19
|
+
((ERRORS++))
|
|
20
|
+
fi
|
|
21
|
+
done
|
|
22
|
+
done
|
|
23
|
+
|
|
24
|
+
if [ $MISPLACED -gt 0 ]; then
|
|
25
|
+
echo " 💡 运行 /sillyspec:scan 修正路径,或手动移动到 $CODEBASE_DIR/"
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# ── 文件完整性检查 ──
|
|
29
|
+
|
|
30
|
+
echo "🔍 校验代码库扫描 $CODEBASE_DIR ..."
|
|
31
|
+
|
|
32
|
+
if [ ! -d "$CODEBASE_DIR" ]; then
|
|
33
|
+
echo " ❌ 目录 $CODEBASE_DIR 不存在"
|
|
34
|
+
exit 1
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# 深度扫描 7 份
|
|
38
|
+
DEEP_FILES=(
|
|
39
|
+
"STACK.md"
|
|
40
|
+
"ARCHITECTURE.md"
|
|
41
|
+
"STRUCTURE.md"
|
|
42
|
+
"CONVENTIONS.md"
|
|
43
|
+
"INTEGRATIONS.md"
|
|
44
|
+
"TESTING.md"
|
|
45
|
+
"CONCERNS.md"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# 快速扫描 2 份 + PROJECT.md
|
|
49
|
+
QUICK_FILES=(
|
|
50
|
+
"STACK.md"
|
|
51
|
+
"STRUCTURE.md"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# 检查深度扫描文件
|
|
55
|
+
for f in "${DEEP_FILES[@]}"; do
|
|
56
|
+
if [ -f "$CODEBASE_DIR/$f" ]; then
|
|
57
|
+
lines=$(wc -l < "$CODEBASE_DIR/$f" | tr -d ' ')
|
|
58
|
+
if [ "$lines" -gt 3 ]; then
|
|
59
|
+
echo " ✅ $f ($lines 行)"
|
|
60
|
+
else
|
|
61
|
+
echo " ⚠️ $f 只有 $lines 行,内容可能不完整"
|
|
62
|
+
((ERRORS++))
|
|
63
|
+
fi
|
|
64
|
+
else
|
|
65
|
+
echo " ⬜ $f 不存在(深度扫描文件)"
|
|
66
|
+
fi
|
|
67
|
+
done
|
|
68
|
+
|
|
69
|
+
# 检查 PROJECT.md
|
|
70
|
+
if [ -f ".sillyspec/PROJECT.md" ]; then
|
|
71
|
+
echo " ✅ PROJECT.md 存在"
|
|
72
|
+
else
|
|
73
|
+
echo " ⚠️ PROJECT.md 不存在(建议生成)"
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# 检查 SCAN-RAW.md
|
|
77
|
+
if [ -f "$CODEBASE_DIR/SCAN-RAW.md" ]; then
|
|
78
|
+
echo " ✅ SCAN-RAW.md 存在(预处理数据)"
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# ── 结果 ──
|
|
82
|
+
|
|
83
|
+
echo ""
|
|
84
|
+
if [ $ERRORS -eq 0 ]; then
|
|
85
|
+
echo "✅ 扫描校验通过"
|
|
86
|
+
exit 0
|
|
87
|
+
else
|
|
88
|
+
echo "❌ 扫描校验失败,$ERRORS 个问题"
|
|
89
|
+
exit 1
|
|
90
|
+
fi
|