sillyspec 3.1.0 → 3.2.1
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 +2 -0
- package/.claude/commands/sillyspec/brainstorm.md +1 -1
- package/.claude/commands/sillyspec/execute.md +61 -7
- package/.claude/commands/sillyspec/quick.md +1 -1
- package/.claude/commands/sillyspec/scan.md +96 -7
- package/.claude/commands/sillyspec/status.md +31 -6
- package/.claude/commands/sillyspec/verify.md +27 -14
- package/package.json +1 -1
- package/src/init.js +84 -37
- package/templates/archive.md +2 -0
- package/templates/brainstorm.md +1 -1
- package/templates/execute.md +61 -7
- package/templates/quick.md +1 -1
- package/templates/scan.md +96 -7
- package/templates/status.md +31 -1
- package/templates/verify.md +27 -14
|
@@ -56,6 +56,8 @@ $ARGUMENTS
|
|
|
56
56
|
- **STATE.md:** 清除当前变更信息,历史记录追加归档完成
|
|
57
57
|
- **Git 提交:** `git add .sillyspec/ && git commit -m "docs: archive sillyspec change <change-name>"`
|
|
58
58
|
|
|
59
|
+
**工作区模式下:** 如果变更属于某个子项目,cd 到子项目目录执行 git commit。工作区根目录无 git 则跳过。
|
|
60
|
+
|
|
59
61
|
### 最后说:
|
|
60
62
|
|
|
61
63
|
> ✅ 变更 `<change-name>` 已归档到 `archive/YYYY-MM-DD-<change-name>/`。继续:`/sillyspec:brainstorm "新想法"`
|
|
@@ -53,7 +53,7 @@ $ARGUMENTS
|
|
|
53
53
|
cat .sillyspec/config.yaml 2>/dev/null
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
**工作区模式:** AskUserQuestion
|
|
56
|
+
**工作区模式:** AskUserQuestion 选子项目,**cd 到子项目目录执行**,加载子项目上下文 + 共享规范 + 工作区概览,设计文档保存到子项目 `.sillyspec/changes/`。git commit 在子项目目录执行。
|
|
57
57
|
|
|
58
58
|
**单项目模式:**
|
|
59
59
|
```bash
|
|
@@ -29,7 +29,7 @@ $ARGUMENTS
|
|
|
29
29
|
cat .sillyspec/config.yaml 2>/dev/null
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
**工作区模式:** 根据计划 Task 标注确定子项目,额外加载共享规范 + CODEBASE-OVERVIEW.md
|
|
32
|
+
**工作区模式:** 根据计划 Task 标注确定子项目,额外加载共享规范 + CODEBASE-OVERVIEW.md,**执行前必须 cd 到对应子项目目录**。所有代码修改、测试运行、git commit 都在子项目目录中执行。一个 Task 属于哪个子项目,就 cd 到哪个子项目。
|
|
33
33
|
|
|
34
34
|
**单项目模式:**
|
|
35
35
|
```bash
|
|
@@ -84,17 +84,62 @@ grep -rn "public.*getById" --include="*.java" src/main/java/**/service/
|
|
|
84
84
|
```
|
|
85
85
|
grep 不到 → 不许调用,先查清楚或报告给用户。
|
|
86
86
|
|
|
87
|
-
### 2. TDD
|
|
87
|
+
### 2. TDD(强制执行,不可跳过)
|
|
88
88
|
|
|
89
|
+
#### 🔴 RED — 写失败测试
|
|
90
|
+
|
|
91
|
+
先写测试文件,再写实现代码。写代码前测试必须先存在。
|
|
92
|
+
|
|
93
|
+
**写完测试后,立即运行确认失败:**
|
|
94
|
+
|
|
95
|
+
先检查 local.yaml 是否有构建命令配置:
|
|
96
|
+
```bash
|
|
97
|
+
cat .sillyspec/local.yaml 2>/dev/null 2>/dev/null
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
如果有,使用 local.yaml 中的命令(含 `-s` 等参数);否则使用默认命令:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
mvn test -pl <模块> -Dtest=<测试类> 2>/dev/null || ./gradlew test --tests <测试类> 2>/dev/null || npm test -- --testPathPattern=<测试文件> 2>/dev/null || pytest <测试文件> 2>/dev/null
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
确认:
|
|
107
|
+
- 测试失败(不是编译错误)
|
|
108
|
+
- 失败原因是功能未实现(不是语法错误)
|
|
109
|
+
|
|
110
|
+
**测试直接通过?** 你在测试已有行为,重写测试。**测试编译报错?** 先修测试语法。
|
|
111
|
+
|
|
112
|
+
#### 🟢 GREEN — 写最少代码
|
|
113
|
+
|
|
114
|
+
写刚好让测试通过的最少代码。不加额外功能。
|
|
115
|
+
|
|
116
|
+
**写完后立即运行确认通过:**
|
|
117
|
+
|
|
118
|
+
先检查 local.yaml 是否有构建命令配置:
|
|
119
|
+
```bash
|
|
120
|
+
cat .sillyspec/local.yaml 2>/dev/null 2>/dev/null
|
|
89
121
|
```
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
122
|
+
|
|
123
|
+
如果有,使用 local.yaml 中的命令;否则使用默认命令:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
mvn test -pl <模块> -Dtest=<测试类> 2>/dev/null || ./gradlew test --tests <测试类> 2>/dev/null || npm test -- --testPathPattern=<测试文件> 2>/dev/null || pytest <测试文件> 2>/dev/null
|
|
93
127
|
```
|
|
94
128
|
|
|
95
|
-
|
|
129
|
+
确认:
|
|
130
|
+
- 测试通过
|
|
131
|
+
- 其他已有测试没有因此失败
|
|
132
|
+
- 无编译错误、无 warnings
|
|
133
|
+
|
|
134
|
+
**编译不通过或测试失败?** 修代码,不是改测试。**其他测试被破坏?** 立即修复。
|
|
135
|
+
|
|
136
|
+
#### 🔵 REFACTOR — 清理
|
|
96
137
|
|
|
97
|
-
|
|
138
|
+
在测试全绿的前提下清理:提取重复、改善命名、简化逻辑。重构后重新运行测试确认仍然通过。
|
|
139
|
+
|
|
140
|
+
**TDD 中间步骤(RED→GREEN→REFACTOR)连续执行,不需要每步等用户确认。但每一步都必须运行测试命令并确认结果,不可省略。**
|
|
141
|
+
|
|
142
|
+
**测试文件必须保留**,随代码一起 commit。违反 TDD(先写代码后补测试)→ 删代码重来。
|
|
98
143
|
|
|
99
144
|
**可跳过 TDD(不需要确认):** 纯配置(YAML/properties)、纯数据(SQL seed)、纯文档(README/注释)。
|
|
100
145
|
|
|
@@ -104,8 +149,17 @@ TDD 中间步骤(RED→GREEN→REFACTOR)连续执行,不需要每步等用
|
|
|
104
149
|
|
|
105
150
|
### 4. Git commit
|
|
106
151
|
|
|
152
|
+
**先确认当前在 git 仓库中:**
|
|
153
|
+
```bash
|
|
154
|
+
git rev-parse --is-inside-work-tree 2>/dev/null
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
如果不在 git 仓库中,提示用户当前目录没有 git 管理,跳过 commit 或让用户指定仓库路径。
|
|
158
|
+
|
|
107
159
|
`git add -A` → 生成 commit message → **根据用户选择的确认频率决定是否立即确认或批量确认**。
|
|
108
160
|
|
|
161
|
+
**工作区模式下,每个子项目的 commit 独立执行,不要跨子项目 commit。**
|
|
162
|
+
|
|
109
163
|
---
|
|
110
164
|
|
|
111
165
|
## 偏差处理
|
|
@@ -33,7 +33,7 @@ $ARGUMENTS
|
|
|
33
33
|
- 纯配置/数据/文档可跳过 TDD
|
|
34
34
|
- 其他情况一律走 TDD
|
|
35
35
|
6. **运行相关测试:** `pnpm test 2>/dev/null || npm test 2>/dev/null || pytest 2>/dev/null`
|
|
36
|
-
7. **Git commit:** 展示 commit message
|
|
36
|
+
7. **Git commit:** 展示 commit message 给用户确认后提交。**工作区模式下,确认当前在正确的子项目目录中执行 commit。**
|
|
37
37
|
8. **记录:**
|
|
38
38
|
- **有 `--change`:** 在 `.sillyspec/changes/<变更名>/tasks.md` 追加 task 并勾选 `[x]`
|
|
39
39
|
- **无 `--change`:** 记录到 `.sillyspec/quicklog/QUICKLOG.md`(见下方规则)
|
|
@@ -55,6 +55,24 @@ AskUserQuestion 依次确认:快速⚡/深度🔍、扫描范围(留空全
|
|
|
55
55
|
|
|
56
56
|
汇总选择,用户确认后执行。
|
|
57
57
|
|
|
58
|
+
### 🚨 工作区扫描铁律(防止上下文爆炸)
|
|
59
|
+
|
|
60
|
+
**工作区模式下,必须逐个子项目扫描并写入,禁止跨子项目累积上下文:**
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
子项目 A → 读取 → 写入文档 → 清理上下文
|
|
64
|
+
子项目 B → 读取 → 写入文档 → 清理上下文
|
|
65
|
+
...
|
|
66
|
+
最后 → 生成 CODEBASE-OVERVIEW.md
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- ✅ 每个子项目扫描完成后**立即写入** `.sillyspec/codebase/` 文件
|
|
70
|
+
- ✅ 写入后**不再回头读**该子项目的源码
|
|
71
|
+
- ❌ 禁止同时读取多个子项目的源码再一次性全部写入
|
|
72
|
+
- ❌ 禁止在一个子项目扫描过程中去读另一个子项目的文件
|
|
73
|
+
|
|
74
|
+
**CODEBASE-OVERVIEW.md** 只读各子项目已生成的 ARCHITECTURE.md + CONVENTIONS.md(不读源码),生成汇总。
|
|
75
|
+
|
|
58
76
|
---
|
|
59
77
|
|
|
60
78
|
## 快速扫描
|
|
@@ -76,9 +94,73 @@ find . -type f -not -path "*/node_modules/*" -not -path "*/{dist,.git,vendor,bui
|
|
|
76
94
|
git log --oneline -20
|
|
77
95
|
```
|
|
78
96
|
|
|
79
|
-
## 🚨
|
|
97
|
+
## 🚨 四项强制扫描(快速和深度都必须执行)
|
|
98
|
+
|
|
99
|
+
### A. 构建环境探测(IDE vs 终端差异修复)
|
|
100
|
+
|
|
101
|
+
**目的:** 解决 IDEA 有私服配置但终端跑不了 `mvn test` / `npm test` 的问题。
|
|
102
|
+
|
|
103
|
+
**探测步骤:**
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# 检测项目使用的构建工具
|
|
107
|
+
ls pom.xml build.gradle package.json requirements.txt go.mod Cargo.toml pyproject.toml 2>/dev/null
|
|
108
|
+
# 检测是否有 wrapper
|
|
109
|
+
ls mvnw gradlew package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null
|
|
110
|
+
# 检测是否有 IDEA 特殊配置
|
|
111
|
+
grep -r "mavenHome\|settings\.xml\|gradleHome\|nodeInterpreter" .idea/workspace.xml 2>/dev/null | head -5
|
|
112
|
+
# 检测是否有本地配置文件
|
|
113
|
+
cat .mvn/maven.config 2>/dev/null
|
|
114
|
+
cat .mvn/jvm.config 2>/dev/null
|
|
115
|
+
cat .npmrc 2>/dev/null
|
|
116
|
+
cat pip.conf .pip/pip.conf ~/.pip/pip.conf 2>/dev/null
|
|
117
|
+
cat ~/.gradle/gradle.properties 2>/dev/null
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**AskUserQuestion 询问用户:**
|
|
121
|
+
|
|
122
|
+
> "检测到本项目使用 [Maven/Gradle/npm/pip/Go],终端执行构建命令时是否需要特殊配置?"
|
|
123
|
+
> 选项:
|
|
124
|
+
> - 不需要,默认配置就能跑
|
|
125
|
+
> - 需要指定配置文件(如 Maven 的 settings.xml)→ 让用户输入路径
|
|
126
|
+
> - 需要额外参数(如私服地址、代理等)→ 让用户输入
|
|
127
|
+
> - 不确定,先试试默认命令
|
|
128
|
+
|
|
129
|
+
**如果用户选择了需要配置,测试默认命令是否能跑通:**
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Maven
|
|
133
|
+
mvn test -s <用户提供的路径> --fail-at-end 2>&1 | tail -5
|
|
134
|
+
# Gradle
|
|
135
|
+
./gradlew test 2>&1 | tail -5 || gradle test 2>&1 | tail -5
|
|
136
|
+
# npm
|
|
137
|
+
npm test 2>&1 | tail -5 || pnpm test 2>&1 | tail -5
|
|
138
|
+
# pip
|
|
139
|
+
pip install -e . 2>&1 | tail -5 && pytest --collect-only 2>&1 | tail -5
|
|
140
|
+
# Go
|
|
141
|
+
go test ./... 2>&1 | tail -5
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**写入 `.sillyspec/local.yaml`(本地记忆文件,不提交到 git):**
|
|
145
|
+
|
|
146
|
+
此文件存储每个开发者独立的本地配置。如果文件已存在则追加,已有字段则跳过:
|
|
80
147
|
|
|
81
|
-
|
|
148
|
+
```yaml
|
|
149
|
+
# .sillyspec/local.yaml — 本地记忆文件(已在 .gitignore 中,不提交)
|
|
150
|
+
# 每个开发者独立配置,clone 后重新 scan 即可生成
|
|
151
|
+
|
|
152
|
+
build:
|
|
153
|
+
tool: maven
|
|
154
|
+
test_cmd: 'mvn test -s "D:/software/maven/conf/settings.xml"'
|
|
155
|
+
compile_cmd: 'mvn compile -s "D:/software/maven/conf/settings.xml"'
|
|
156
|
+
single_test_cmd: 'mvn test -s "D:/software/maven/conf/settings.xml" -pl {module} -Dtest={test_class}'
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**铁律:后续 execute / verify 阶段执行构建或测试命令时,必须先读取 `.sillyspec/local.yaml` 中的 build 配置,使用记录的命令执行。如果 local.yaml 不存在或无 build 配置,使用默认命令。**
|
|
160
|
+
|
|
161
|
+
无构建工具 → 跳过此步骤。
|
|
162
|
+
|
|
163
|
+
### B. 数据库 Schema 扫描
|
|
82
164
|
|
|
83
165
|
**目的:** 防止后续阶段编造表名和字段名。
|
|
84
166
|
|
|
@@ -101,7 +183,7 @@ find . \( -name "schema.prisma" -o -name "*.model.ts" -o -name "*.entity.ts" -o
|
|
|
101
183
|
|
|
102
184
|
无数据库 → 写"本项目无数据库"。**铁律:所有阶段引用的表名必须来自此摘要,或 design.md 中声明的新增表。**
|
|
103
185
|
|
|
104
|
-
###
|
|
186
|
+
### C. 框架隐形规则扫描
|
|
105
187
|
|
|
106
188
|
**目的:** 防止 AI 生成的 SQL/代码违反框架自动处理机制(如自动注入字段、逻辑删除拦截器)。
|
|
107
189
|
|
|
@@ -138,7 +220,7 @@ find . \( -name "*.java" -o -name "*.py" -o -name "*.go" -o -name "*.ts" -o -nam
|
|
|
138
220
|
|
|
139
221
|
无发现 → 写"未发现框架级别的自动处理配置"。**铁律:后续阶段生成 SQL/数据操作代码必须遵守这些规则。**
|
|
140
222
|
|
|
141
|
-
###
|
|
223
|
+
### D. 实体继承规范扫描
|
|
142
224
|
|
|
143
225
|
**目的:** 防止新建表时漏掉基类通用字段,导致 ORM 查询报 Unknown column。
|
|
144
226
|
|
|
@@ -163,7 +245,7 @@ find . -name "*.java" -not -path "*/{node_modules,.git}/*" | xargs grep -l "@Map
|
|
|
163
245
|
|
|
164
246
|
无基类 → 写"本项目没有实体基类"。
|
|
165
247
|
|
|
166
|
-
###
|
|
248
|
+
### E. 代码风格深度提取
|
|
167
249
|
|
|
168
250
|
读取 2-3 个典型的 Controller、Service、ServiceImpl、Entity 源文件,提取具体风格(从源码提取,禁止编造):
|
|
169
251
|
|
|
@@ -228,9 +310,16 @@ sillyspec next
|
|
|
228
310
|
|
|
229
311
|
### Git 提交
|
|
230
312
|
|
|
313
|
+
**单项目模式:**
|
|
231
314
|
```bash
|
|
232
|
-
git add .sillyspec/
|
|
233
|
-
|
|
315
|
+
git add .sillyspec/ && git commit -m "chore: sillyspec scan - codebase mapped"
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**工作区模式:** 在每个子项目目录分别 commit(主工作区无 git 则跳过):
|
|
319
|
+
```bash
|
|
320
|
+
for proj in $(cat .sillyspec/config.yaml | grep -oP 'path:\s*\K.*'); do
|
|
321
|
+
cd "$proj" && git add .sillyspec/ 2>/dev/null && git commit -m "chore: sillyspec scan - codebase mapped" && cd - > /dev/null
|
|
322
|
+
done
|
|
234
323
|
```
|
|
235
324
|
|
|
236
325
|
### 路径校验 + 自检门控
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: 查看项目进度和状态
|
|
3
|
-
argument-hint: ""
|
|
4
|
-
---
|
|
5
|
-
|
|
6
1
|
## 交互规范
|
|
7
2
|
**当需要用户从多个选项中做出选择时,必须使用 Claude Code 内置的 AskUserQuestion 工具,将选项以参数传入。**
|
|
8
3
|
|
|
@@ -19,7 +14,37 @@ argument-hint: ""
|
|
|
19
14
|
cat .sillyspec/config.yaml 2>/dev/null
|
|
20
15
|
```
|
|
21
16
|
|
|
22
|
-
**工作区模式:** 读取 config.yaml 子项目列表,对每个子项目检查 PROJECT.md、codebase
|
|
17
|
+
**工作区模式:** 读取 config.yaml 子项目列表,对每个子项目检查 PROJECT.md、codebase 文档数、进行中变更、归档数。**同时检查工作区根目录 `.sillyspec/changes/` 下的未归档变更。** 检查共享规范和工作区概览。输出汇总后结束,不执行单项目流程。
|
|
18
|
+
|
|
19
|
+
工作区变更检查命令:
|
|
20
|
+
```bash
|
|
21
|
+
# 工作区根目录的变更
|
|
22
|
+
ls .sillyspec/changes/ 2>/dev/null | grep -v archive
|
|
23
|
+
ls .sillyspec/changes/archive/ 2>/dev/null | wc -l
|
|
24
|
+
|
|
25
|
+
# 每个子项目的变更
|
|
26
|
+
for proj in $(cat .sillyspec/config.yaml | grep -oP 'path:\s*\K.*'); do
|
|
27
|
+
echo "=== $(basename $proj) changes ==="
|
|
28
|
+
ls "$proj/.sillyspec/changes/" 2>/dev/null | grep -v archive
|
|
29
|
+
ls "$proj/.sillyspec/changes/archive/" 2>/dev/null | wc -l
|
|
30
|
+
done
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**汇总输出格式:**
|
|
34
|
+
```
|
|
35
|
+
📊 SillySpec 状态
|
|
36
|
+
📋 工作区模式 — N 个子项目
|
|
37
|
+
|
|
38
|
+
工作区变更:
|
|
39
|
+
🔄 进行中:sec-bonus-penalty(tasks: 3/5)
|
|
40
|
+
✅ 已归档:1 个
|
|
41
|
+
|
|
42
|
+
┌───────────────────┬────────────┬────────────┬────────┬────────┐
|
|
43
|
+
│ 子项目 │ PROJECT.md │ 代码库文档 │ 进行中 │ 已归档 │
|
|
44
|
+
├───────────────────┼────────────┼────────────┼────────┼────────┤
|
|
45
|
+
│ back-service │ ✗ │ 7 份 │ 1 │ 0 │
|
|
46
|
+
└───────────────────┴────────────┴────────────┴────────┴────────┘
|
|
47
|
+
```
|
|
23
48
|
|
|
24
49
|
**单项目模式:** 继续 Step 2。
|
|
25
50
|
|
|
@@ -11,11 +11,27 @@
|
|
|
11
11
|
## 状态检查(必须先执行)
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
sillyspec
|
|
14
|
+
cat .sillyspec/STATE.md 2>/dev/null
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
检查当前阶段。如果没有 STATE.md,检查是否有未归档变更:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
ls .sillyspec/changes/ 2>/dev/null | grep -v archive
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
无 STATE.md 且无未归档变更 → 提示用户先完成 execute 或用 `/sillyspec:status` 查看状态。
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 工作区模式处理
|
|
28
|
+
|
|
29
|
+
如果 `.sillyspec/config.yaml` 包含 `projects` 字段:
|
|
30
|
+
|
|
31
|
+
1. 检查工作区根目录 `.sillyspec/changes/` 下的未归档变更
|
|
32
|
+
2. 检查每个子项目 `<子项目路径>/.sillyspec/changes/` 下的未归档变更
|
|
33
|
+
3. 列出所有未归档变更,让用户选择要验证哪个
|
|
34
|
+
4. 根据 $ARGUMENTS 或用户选择,cd 到对应目录执行验证
|
|
19
35
|
|
|
20
36
|
---
|
|
21
37
|
|
|
@@ -24,8 +40,13 @@ sillyspec status --json
|
|
|
24
40
|
### 1. 加载规范
|
|
25
41
|
|
|
26
42
|
```bash
|
|
27
|
-
|
|
28
|
-
|
|
43
|
+
# 确定变更目录
|
|
44
|
+
if [ -n "$ARGUMENTS" ]; then
|
|
45
|
+
CHANGE_DIR=".sillyspec/changes/$ARGUMENTS"
|
|
46
|
+
else
|
|
47
|
+
CHANGE_DIR=$(ls -d .sillyspec/changes/*/ 2>/dev/null | grep -v archive | tail -1)
|
|
48
|
+
fi
|
|
49
|
+
cat "$CHANGE_DIR"/{design,tasks}.md 2>/dev/null
|
|
29
50
|
```
|
|
30
51
|
|
|
31
52
|
锚定确认实际存在的文件。
|
|
@@ -61,14 +82,6 @@ grep -r "TODO\|FIXME\|HACK\|XXX" src/ lib/ app/ --include="*.ts" --include="*.ts
|
|
|
61
82
|
## 结论:✅ PASS / ⚠️ PASS WITH NOTES / ❌ FAIL
|
|
62
83
|
```
|
|
63
84
|
|
|
64
|
-
```bash
|
|
65
|
-
bash scripts/validate-all.sh 2>/dev/null
|
|
66
|
-
```
|
|
67
|
-
|
|
68
85
|
### 7. 完成
|
|
69
86
|
|
|
70
|
-
|
|
71
|
-
sillyspec status --json && sillyspec next
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
更新 `.sillyspec/STATE.md`:阶段改为 `verify ✅` 或 `verify ⚠️`。
|
|
87
|
+
更新 `.sillyspec/STATE.md`(如存在):阶段改为 `verify ✅` 或 `verify ⚠️`。
|
package/package.json
CHANGED
package/src/init.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'fs';
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, copyFileSync } from 'fs';
|
|
2
2
|
import { join, resolve, dirname } from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { homedir } from 'os';
|
|
@@ -50,17 +50,45 @@ const ARG_HINTS = {
|
|
|
50
50
|
export: '<change-name> [--to <path>]',
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
-
const VALID_TOOLS = ['claude', 'claude_skills', 'cursor', 'codex', '
|
|
53
|
+
const VALID_TOOLS = ['claude', 'claude_skills', 'cursor', 'openclaw', 'codex', 'gemini', 'opencode'];
|
|
54
54
|
|
|
55
55
|
const TOOL_LABELS = {
|
|
56
56
|
claude: 'Claude Code',
|
|
57
57
|
claude_skills: 'Claude Skills',
|
|
58
58
|
cursor: 'Cursor',
|
|
59
|
-
codex: 'Codex CLI',
|
|
60
|
-
opencode: 'OpenCode',
|
|
61
59
|
openclaw: 'OpenClaw',
|
|
60
|
+
codex: 'OpenAI Codex (通过 AGENTS.md)',
|
|
61
|
+
gemini: 'Gemini CLI (通过 GEMINI.md)',
|
|
62
|
+
opencode: 'OpenCode (通过 INSTRUCTIONS.md)',
|
|
62
63
|
};
|
|
63
64
|
|
|
65
|
+
// Slash commands 工具:安装 markdown 模板命令
|
|
66
|
+
const SLASH_COMMAND_TOOLS = ['claude', 'claude_skills', 'cursor', 'openclaw'];
|
|
67
|
+
|
|
68
|
+
// 指令文件工具:注入规范引用到指令文件
|
|
69
|
+
const INSTRUCTION_TOOLS = ['codex', 'gemini', 'opencode'];
|
|
70
|
+
|
|
71
|
+
const INSTRUCTION_FILE_MAP = {
|
|
72
|
+
codex: 'AGENTS.md',
|
|
73
|
+
gemini: 'GEMINI.md',
|
|
74
|
+
opencode: 'INSTRUCTIONS.md',
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const INJECTION_CONTENT = `## SillySpec — 规范驱动开发
|
|
78
|
+
|
|
79
|
+
在执行开发任务时,遵循以下规范:
|
|
80
|
+
|
|
81
|
+
### 代码规范
|
|
82
|
+
- 写代码前先读取 \`.sillyspec/codebase/CONVENTIONS.md\`(代码风格)和 \`.sillyspec/codebase/ARCHITECTURE.md\`(架构)
|
|
83
|
+
- 调用已有方法前,用 grep 确认方法存在,不许编造
|
|
84
|
+
- 遵循 \`.sillyspec/codebase/CONVENTIONS.md\` 中的代码风格
|
|
85
|
+
|
|
86
|
+
### 工作流程
|
|
87
|
+
- 读取 \`.sillyspec/STATE.md\` 确认当前阶段
|
|
88
|
+
- 各阶段产出文件位于 \`.sillyspec/changes/<变更名>/\` 下
|
|
89
|
+
- 详细流程参考模板文件:\`.sillyspec/.templates/\`(brainstorm.md, plan.md, execute.md 等)
|
|
90
|
+
`;
|
|
91
|
+
|
|
64
92
|
// ── 适配器 ──
|
|
65
93
|
|
|
66
94
|
function generateClaude(projectDir, name, desc, body, argHint) {
|
|
@@ -103,32 +131,6 @@ ${body}`
|
|
|
103
131
|
);
|
|
104
132
|
}
|
|
105
133
|
|
|
106
|
-
function generateCodex(projectDir, name, desc, body, argHint) {
|
|
107
|
-
const outDir = join(homedir(), '.agents', 'skills', `sillyspec-${name}`);
|
|
108
|
-
mkdirSync(outDir, { recursive: true });
|
|
109
|
-
writeFileSync(join(outDir, 'SKILL.md'),
|
|
110
|
-
`---
|
|
111
|
-
name: sillyspec:${name}
|
|
112
|
-
description: ${desc}
|
|
113
|
-
---
|
|
114
|
-
|
|
115
|
-
${body}`
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function generateOpencode(projectDir, name, desc, body, argHint) {
|
|
120
|
-
const outDir = join(projectDir, '.opencode', 'skills', `sillyspec-${name}`);
|
|
121
|
-
mkdirSync(outDir, { recursive: true });
|
|
122
|
-
writeFileSync(join(outDir, 'SKILL.md'),
|
|
123
|
-
`---
|
|
124
|
-
name: sillyspec:${name}
|
|
125
|
-
description: ${desc}
|
|
126
|
-
---
|
|
127
|
-
|
|
128
|
-
${body}`
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
134
|
function generateOpenclaw(projectDir, name, desc, body, argHint) {
|
|
133
135
|
const outDir = join(projectDir, '.openclaw', 'skills', `sillyspec-${name}`);
|
|
134
136
|
mkdirSync(outDir, { recursive: true });
|
|
@@ -146,11 +148,30 @@ const GENERATORS = {
|
|
|
146
148
|
claude: generateClaude,
|
|
147
149
|
claude_skills: generateClaudeSkills,
|
|
148
150
|
cursor: generateCursor,
|
|
149
|
-
codex: generateCodex,
|
|
150
|
-
opencode: generateOpencode,
|
|
151
151
|
openclaw: generateOpenclaw,
|
|
152
152
|
};
|
|
153
153
|
|
|
154
|
+
// ── 指令文件注入 ──
|
|
155
|
+
|
|
156
|
+
function injectInstructions(tool, projectDir) {
|
|
157
|
+
const fileName = INSTRUCTION_FILE_MAP[tool];
|
|
158
|
+
if (!fileName) return;
|
|
159
|
+
const filePath = join(projectDir, fileName);
|
|
160
|
+
|
|
161
|
+
// 文件不存在则创建
|
|
162
|
+
if (!existsSync(filePath)) {
|
|
163
|
+
writeFileSync(filePath, INJECTION_CONTENT);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 已存在 SillySpec 标记则跳过
|
|
168
|
+
const content = readFileSync(filePath, 'utf8');
|
|
169
|
+
if (content.includes('## SillySpec')) return;
|
|
170
|
+
|
|
171
|
+
// 追加到末尾
|
|
172
|
+
writeFileSync(filePath, content.trimEnd() + '\n\n' + INJECTION_CONTENT);
|
|
173
|
+
}
|
|
174
|
+
|
|
154
175
|
// ── 检测工具 ──
|
|
155
176
|
|
|
156
177
|
function detectTools(projectDir) {
|
|
@@ -158,9 +179,10 @@ function detectTools(projectDir) {
|
|
|
158
179
|
if (existsSync(join(projectDir, '.claude'))) found.push('claude');
|
|
159
180
|
if (existsSync(join(projectDir, '.claude', 'skills'))) found.push('claude_skills');
|
|
160
181
|
if (existsSync(join(projectDir, '.cursor'))) found.push('cursor');
|
|
161
|
-
if (existsSync(join(projectDir, '.opencode'))) found.push('opencode');
|
|
162
182
|
if (existsSync(join(projectDir, '.openclaw'))) found.push('openclaw');
|
|
163
|
-
if (existsSync(join(
|
|
183
|
+
if (existsSync(join(projectDir, 'AGENTS.md'))) found.push('codex');
|
|
184
|
+
if (existsSync(join(projectDir, 'GEMINI.md'))) found.push('gemini');
|
|
185
|
+
if (existsSync(join(projectDir, 'INSTRUCTIONS.md'))) found.push('opencode');
|
|
164
186
|
if (found.length === 0) found.push('claude');
|
|
165
187
|
return found;
|
|
166
188
|
}
|
|
@@ -188,7 +210,7 @@ async function doInstall(projectDir, tools, isWorkspace, subprojects = []) {
|
|
|
188
210
|
}
|
|
189
211
|
|
|
190
212
|
const gitignorePath = join(projectDir, '.gitignore');
|
|
191
|
-
const ignoreRules = ['.sillyspec/STATE.md', '.sillyspec/codebase/SCAN-RAW.md'];
|
|
213
|
+
const ignoreRules = ['.sillyspec/STATE.md', '.sillyspec/codebase/SCAN-RAW.md', '.sillyspec/local.yaml'];
|
|
192
214
|
if (existsSync(gitignorePath)) {
|
|
193
215
|
const content = readFileSync(gitignorePath, 'utf8');
|
|
194
216
|
let updated = content.trimEnd();
|
|
@@ -202,13 +224,38 @@ async function doInstall(projectDir, tools, isWorkspace, subprojects = []) {
|
|
|
202
224
|
writeFileSync(gitignorePath, ignoreRules.join('\n') + '\n');
|
|
203
225
|
}
|
|
204
226
|
|
|
205
|
-
//
|
|
227
|
+
// 生成 slash command 文件
|
|
206
228
|
const templateFiles = readdirSync(TEMPLATE_DIR).filter(f => f.endsWith('.md'));
|
|
207
229
|
let count = 0;
|
|
208
230
|
|
|
209
231
|
for (let i = 0; i < tools.length; i++) {
|
|
210
232
|
const toolName = tools[i];
|
|
211
233
|
const label = TOOL_LABELS[toolName] || toolName;
|
|
234
|
+
|
|
235
|
+
if (INSTRUCTION_TOOLS.includes(toolName)) {
|
|
236
|
+
const spinner = ora(`安装 ${label}... (${i + 1}/${tools.length})`).start();
|
|
237
|
+
try {
|
|
238
|
+
injectInstructions(toolName, projectDir);
|
|
239
|
+
// 复制模板文件到 .sillyspec/.templates/
|
|
240
|
+
const templatesSourceDir = join(TEMPLATE_DIR);
|
|
241
|
+
const templatesDir = join(projectDir, '.sillyspec', '.templates');
|
|
242
|
+
if (!existsSync(templatesDir)) {
|
|
243
|
+
mkdirSync(templatesDir, { recursive: true });
|
|
244
|
+
for (const file of readdirSync(templatesSourceDir)) {
|
|
245
|
+
if (file.endsWith('.md')) {
|
|
246
|
+
copyFileSync(join(templatesSourceDir, file), join(templatesDir, file));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
spinner.succeed(`${label} 完成`);
|
|
251
|
+
count++;
|
|
252
|
+
} catch (err) {
|
|
253
|
+
spinner.fail(`${label} 失败: ${err.message}`);
|
|
254
|
+
throw err;
|
|
255
|
+
}
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
|
|
212
259
|
const spinner = ora(`安装 ${label}... (${i + 1}/${tools.length})`).start();
|
|
213
260
|
try {
|
|
214
261
|
const gen = GENERATORS[toolName];
|
|
@@ -345,7 +392,7 @@ export async function cmdInit(projectDir, options = {}) {
|
|
|
345
392
|
const detected = detectTools(projectDir);
|
|
346
393
|
|
|
347
394
|
const toolChoices = VALID_TOOLS.map(v => ({
|
|
348
|
-
name: `${TOOL_LABELS[v]}${v === 'claude' ? ' (
|
|
395
|
+
name: `${TOOL_LABELS[v]}${v === 'claude' ? ' (推荐)' : ''}`,
|
|
349
396
|
value: v,
|
|
350
397
|
checked: detected.includes(v),
|
|
351
398
|
}));
|
package/templates/archive.md
CHANGED
|
@@ -56,6 +56,8 @@ $ARGUMENTS
|
|
|
56
56
|
- **STATE.md:** 清除当前变更信息,历史记录追加归档完成
|
|
57
57
|
- **Git 提交:** `git add .sillyspec/ && git commit -m "docs: archive sillyspec change <change-name>"`
|
|
58
58
|
|
|
59
|
+
**工作区模式下:** 如果变更属于某个子项目,cd 到子项目目录执行 git commit。工作区根目录无 git 则跳过。
|
|
60
|
+
|
|
59
61
|
### 最后说:
|
|
60
62
|
|
|
61
63
|
> ✅ 变更 `<change-name>` 已归档到 `archive/YYYY-MM-DD-<change-name>/`。继续:`/sillyspec:brainstorm "新想法"`
|
package/templates/brainstorm.md
CHANGED
|
@@ -53,7 +53,7 @@ $ARGUMENTS
|
|
|
53
53
|
cat .sillyspec/config.yaml 2>/dev/null
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
**工作区模式:** AskUserQuestion
|
|
56
|
+
**工作区模式:** AskUserQuestion 选子项目,**cd 到子项目目录执行**,加载子项目上下文 + 共享规范 + 工作区概览,设计文档保存到子项目 `.sillyspec/changes/`。git commit 在子项目目录执行。
|
|
57
57
|
|
|
58
58
|
**单项目模式:**
|
|
59
59
|
```bash
|
package/templates/execute.md
CHANGED
|
@@ -29,7 +29,7 @@ $ARGUMENTS
|
|
|
29
29
|
cat .sillyspec/config.yaml 2>/dev/null
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
**工作区模式:** 根据计划 Task 标注确定子项目,额外加载共享规范 + CODEBASE-OVERVIEW.md
|
|
32
|
+
**工作区模式:** 根据计划 Task 标注确定子项目,额外加载共享规范 + CODEBASE-OVERVIEW.md,**执行前必须 cd 到对应子项目目录**。所有代码修改、测试运行、git commit 都在子项目目录中执行。一个 Task 属于哪个子项目,就 cd 到哪个子项目。
|
|
33
33
|
|
|
34
34
|
**单项目模式:**
|
|
35
35
|
```bash
|
|
@@ -84,17 +84,62 @@ grep -rn "public.*getById" --include="*.java" src/main/java/**/service/
|
|
|
84
84
|
```
|
|
85
85
|
grep 不到 → 不许调用,先查清楚或报告给用户。
|
|
86
86
|
|
|
87
|
-
### 2. TDD
|
|
87
|
+
### 2. TDD(强制执行,不可跳过)
|
|
88
88
|
|
|
89
|
+
#### 🔴 RED — 写失败测试
|
|
90
|
+
|
|
91
|
+
先写测试文件,再写实现代码。写代码前测试必须先存在。
|
|
92
|
+
|
|
93
|
+
**写完测试后,立即运行确认失败:**
|
|
94
|
+
|
|
95
|
+
先检查 local.yaml 是否有构建命令配置:
|
|
96
|
+
```bash
|
|
97
|
+
cat .sillyspec/local.yaml 2>/dev/null 2>/dev/null
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
如果有,使用 local.yaml 中的命令(含 `-s` 等参数);否则使用默认命令:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
mvn test -pl <模块> -Dtest=<测试类> 2>/dev/null || ./gradlew test --tests <测试类> 2>/dev/null || npm test -- --testPathPattern=<测试文件> 2>/dev/null || pytest <测试文件> 2>/dev/null
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
确认:
|
|
107
|
+
- 测试失败(不是编译错误)
|
|
108
|
+
- 失败原因是功能未实现(不是语法错误)
|
|
109
|
+
|
|
110
|
+
**测试直接通过?** 你在测试已有行为,重写测试。**测试编译报错?** 先修测试语法。
|
|
111
|
+
|
|
112
|
+
#### 🟢 GREEN — 写最少代码
|
|
113
|
+
|
|
114
|
+
写刚好让测试通过的最少代码。不加额外功能。
|
|
115
|
+
|
|
116
|
+
**写完后立即运行确认通过:**
|
|
117
|
+
|
|
118
|
+
先检查 local.yaml 是否有构建命令配置:
|
|
119
|
+
```bash
|
|
120
|
+
cat .sillyspec/local.yaml 2>/dev/null 2>/dev/null
|
|
89
121
|
```
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
122
|
+
|
|
123
|
+
如果有,使用 local.yaml 中的命令;否则使用默认命令:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
mvn test -pl <模块> -Dtest=<测试类> 2>/dev/null || ./gradlew test --tests <测试类> 2>/dev/null || npm test -- --testPathPattern=<测试文件> 2>/dev/null || pytest <测试文件> 2>/dev/null
|
|
93
127
|
```
|
|
94
128
|
|
|
95
|
-
|
|
129
|
+
确认:
|
|
130
|
+
- 测试通过
|
|
131
|
+
- 其他已有测试没有因此失败
|
|
132
|
+
- 无编译错误、无 warnings
|
|
133
|
+
|
|
134
|
+
**编译不通过或测试失败?** 修代码,不是改测试。**其他测试被破坏?** 立即修复。
|
|
135
|
+
|
|
136
|
+
#### 🔵 REFACTOR — 清理
|
|
96
137
|
|
|
97
|
-
|
|
138
|
+
在测试全绿的前提下清理:提取重复、改善命名、简化逻辑。重构后重新运行测试确认仍然通过。
|
|
139
|
+
|
|
140
|
+
**TDD 中间步骤(RED→GREEN→REFACTOR)连续执行,不需要每步等用户确认。但每一步都必须运行测试命令并确认结果,不可省略。**
|
|
141
|
+
|
|
142
|
+
**测试文件必须保留**,随代码一起 commit。违反 TDD(先写代码后补测试)→ 删代码重来。
|
|
98
143
|
|
|
99
144
|
**可跳过 TDD(不需要确认):** 纯配置(YAML/properties)、纯数据(SQL seed)、纯文档(README/注释)。
|
|
100
145
|
|
|
@@ -104,8 +149,17 @@ TDD 中间步骤(RED→GREEN→REFACTOR)连续执行,不需要每步等用
|
|
|
104
149
|
|
|
105
150
|
### 4. Git commit
|
|
106
151
|
|
|
152
|
+
**先确认当前在 git 仓库中:**
|
|
153
|
+
```bash
|
|
154
|
+
git rev-parse --is-inside-work-tree 2>/dev/null
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
如果不在 git 仓库中,提示用户当前目录没有 git 管理,跳过 commit 或让用户指定仓库路径。
|
|
158
|
+
|
|
107
159
|
`git add -A` → 生成 commit message → **根据用户选择的确认频率决定是否立即确认或批量确认**。
|
|
108
160
|
|
|
161
|
+
**工作区模式下,每个子项目的 commit 独立执行,不要跨子项目 commit。**
|
|
162
|
+
|
|
109
163
|
---
|
|
110
164
|
|
|
111
165
|
## 偏差处理
|
package/templates/quick.md
CHANGED
|
@@ -33,7 +33,7 @@ $ARGUMENTS
|
|
|
33
33
|
- 纯配置/数据/文档可跳过 TDD
|
|
34
34
|
- 其他情况一律走 TDD
|
|
35
35
|
6. **运行相关测试:** `pnpm test 2>/dev/null || npm test 2>/dev/null || pytest 2>/dev/null`
|
|
36
|
-
7. **Git commit:** 展示 commit message
|
|
36
|
+
7. **Git commit:** 展示 commit message 给用户确认后提交。**工作区模式下,确认当前在正确的子项目目录中执行 commit。**
|
|
37
37
|
8. **记录:**
|
|
38
38
|
- **有 `--change`:** 在 `.sillyspec/changes/<变更名>/tasks.md` 追加 task 并勾选 `[x]`
|
|
39
39
|
- **无 `--change`:** 记录到 `.sillyspec/quicklog/QUICKLOG.md`(见下方规则)
|
package/templates/scan.md
CHANGED
|
@@ -55,6 +55,24 @@ AskUserQuestion 依次确认:快速⚡/深度🔍、扫描范围(留空全
|
|
|
55
55
|
|
|
56
56
|
汇总选择,用户确认后执行。
|
|
57
57
|
|
|
58
|
+
### 🚨 工作区扫描铁律(防止上下文爆炸)
|
|
59
|
+
|
|
60
|
+
**工作区模式下,必须逐个子项目扫描并写入,禁止跨子项目累积上下文:**
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
子项目 A → 读取 → 写入文档 → 清理上下文
|
|
64
|
+
子项目 B → 读取 → 写入文档 → 清理上下文
|
|
65
|
+
...
|
|
66
|
+
最后 → 生成 CODEBASE-OVERVIEW.md
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- ✅ 每个子项目扫描完成后**立即写入** `.sillyspec/codebase/` 文件
|
|
70
|
+
- ✅ 写入后**不再回头读**该子项目的源码
|
|
71
|
+
- ❌ 禁止同时读取多个子项目的源码再一次性全部写入
|
|
72
|
+
- ❌ 禁止在一个子项目扫描过程中去读另一个子项目的文件
|
|
73
|
+
|
|
74
|
+
**CODEBASE-OVERVIEW.md** 只读各子项目已生成的 ARCHITECTURE.md + CONVENTIONS.md(不读源码),生成汇总。
|
|
75
|
+
|
|
58
76
|
---
|
|
59
77
|
|
|
60
78
|
## 快速扫描
|
|
@@ -76,9 +94,73 @@ find . -type f -not -path "*/node_modules/*" -not -path "*/{dist,.git,vendor,bui
|
|
|
76
94
|
git log --oneline -20
|
|
77
95
|
```
|
|
78
96
|
|
|
79
|
-
## 🚨
|
|
97
|
+
## 🚨 四项强制扫描(快速和深度都必须执行)
|
|
98
|
+
|
|
99
|
+
### A. 构建环境探测(IDE vs 终端差异修复)
|
|
100
|
+
|
|
101
|
+
**目的:** 解决 IDEA 有私服配置但终端跑不了 `mvn test` / `npm test` 的问题。
|
|
102
|
+
|
|
103
|
+
**探测步骤:**
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# 检测项目使用的构建工具
|
|
107
|
+
ls pom.xml build.gradle package.json requirements.txt go.mod Cargo.toml pyproject.toml 2>/dev/null
|
|
108
|
+
# 检测是否有 wrapper
|
|
109
|
+
ls mvnw gradlew package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null
|
|
110
|
+
# 检测是否有 IDEA 特殊配置
|
|
111
|
+
grep -r "mavenHome\|settings\.xml\|gradleHome\|nodeInterpreter" .idea/workspace.xml 2>/dev/null | head -5
|
|
112
|
+
# 检测是否有本地配置文件
|
|
113
|
+
cat .mvn/maven.config 2>/dev/null
|
|
114
|
+
cat .mvn/jvm.config 2>/dev/null
|
|
115
|
+
cat .npmrc 2>/dev/null
|
|
116
|
+
cat pip.conf .pip/pip.conf ~/.pip/pip.conf 2>/dev/null
|
|
117
|
+
cat ~/.gradle/gradle.properties 2>/dev/null
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**AskUserQuestion 询问用户:**
|
|
121
|
+
|
|
122
|
+
> "检测到本项目使用 [Maven/Gradle/npm/pip/Go],终端执行构建命令时是否需要特殊配置?"
|
|
123
|
+
> 选项:
|
|
124
|
+
> - 不需要,默认配置就能跑
|
|
125
|
+
> - 需要指定配置文件(如 Maven 的 settings.xml)→ 让用户输入路径
|
|
126
|
+
> - 需要额外参数(如私服地址、代理等)→ 让用户输入
|
|
127
|
+
> - 不确定,先试试默认命令
|
|
128
|
+
|
|
129
|
+
**如果用户选择了需要配置,测试默认命令是否能跑通:**
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Maven
|
|
133
|
+
mvn test -s <用户提供的路径> --fail-at-end 2>&1 | tail -5
|
|
134
|
+
# Gradle
|
|
135
|
+
./gradlew test 2>&1 | tail -5 || gradle test 2>&1 | tail -5
|
|
136
|
+
# npm
|
|
137
|
+
npm test 2>&1 | tail -5 || pnpm test 2>&1 | tail -5
|
|
138
|
+
# pip
|
|
139
|
+
pip install -e . 2>&1 | tail -5 && pytest --collect-only 2>&1 | tail -5
|
|
140
|
+
# Go
|
|
141
|
+
go test ./... 2>&1 | tail -5
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**写入 `.sillyspec/local.yaml`(本地记忆文件,不提交到 git):**
|
|
145
|
+
|
|
146
|
+
此文件存储每个开发者独立的本地配置。如果文件已存在则追加,已有字段则跳过:
|
|
80
147
|
|
|
81
|
-
|
|
148
|
+
```yaml
|
|
149
|
+
# .sillyspec/local.yaml — 本地记忆文件(已在 .gitignore 中,不提交)
|
|
150
|
+
# 每个开发者独立配置,clone 后重新 scan 即可生成
|
|
151
|
+
|
|
152
|
+
build:
|
|
153
|
+
tool: maven
|
|
154
|
+
test_cmd: 'mvn test -s "D:/software/maven/conf/settings.xml"'
|
|
155
|
+
compile_cmd: 'mvn compile -s "D:/software/maven/conf/settings.xml"'
|
|
156
|
+
single_test_cmd: 'mvn test -s "D:/software/maven/conf/settings.xml" -pl {module} -Dtest={test_class}'
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**铁律:后续 execute / verify 阶段执行构建或测试命令时,必须先读取 `.sillyspec/local.yaml` 中的 build 配置,使用记录的命令执行。如果 local.yaml 不存在或无 build 配置,使用默认命令。**
|
|
160
|
+
|
|
161
|
+
无构建工具 → 跳过此步骤。
|
|
162
|
+
|
|
163
|
+
### B. 数据库 Schema 扫描
|
|
82
164
|
|
|
83
165
|
**目的:** 防止后续阶段编造表名和字段名。
|
|
84
166
|
|
|
@@ -101,7 +183,7 @@ find . \( -name "schema.prisma" -o -name "*.model.ts" -o -name "*.entity.ts" -o
|
|
|
101
183
|
|
|
102
184
|
无数据库 → 写"本项目无数据库"。**铁律:所有阶段引用的表名必须来自此摘要,或 design.md 中声明的新增表。**
|
|
103
185
|
|
|
104
|
-
###
|
|
186
|
+
### C. 框架隐形规则扫描
|
|
105
187
|
|
|
106
188
|
**目的:** 防止 AI 生成的 SQL/代码违反框架自动处理机制(如自动注入字段、逻辑删除拦截器)。
|
|
107
189
|
|
|
@@ -138,7 +220,7 @@ find . \( -name "*.java" -o -name "*.py" -o -name "*.go" -o -name "*.ts" -o -nam
|
|
|
138
220
|
|
|
139
221
|
无发现 → 写"未发现框架级别的自动处理配置"。**铁律:后续阶段生成 SQL/数据操作代码必须遵守这些规则。**
|
|
140
222
|
|
|
141
|
-
###
|
|
223
|
+
### D. 实体继承规范扫描
|
|
142
224
|
|
|
143
225
|
**目的:** 防止新建表时漏掉基类通用字段,导致 ORM 查询报 Unknown column。
|
|
144
226
|
|
|
@@ -163,7 +245,7 @@ find . -name "*.java" -not -path "*/{node_modules,.git}/*" | xargs grep -l "@Map
|
|
|
163
245
|
|
|
164
246
|
无基类 → 写"本项目没有实体基类"。
|
|
165
247
|
|
|
166
|
-
###
|
|
248
|
+
### E. 代码风格深度提取
|
|
167
249
|
|
|
168
250
|
读取 2-3 个典型的 Controller、Service、ServiceImpl、Entity 源文件,提取具体风格(从源码提取,禁止编造):
|
|
169
251
|
|
|
@@ -228,9 +310,16 @@ sillyspec next
|
|
|
228
310
|
|
|
229
311
|
### Git 提交
|
|
230
312
|
|
|
313
|
+
**单项目模式:**
|
|
231
314
|
```bash
|
|
232
|
-
git add .sillyspec/
|
|
233
|
-
|
|
315
|
+
git add .sillyspec/ && git commit -m "chore: sillyspec scan - codebase mapped"
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**工作区模式:** 在每个子项目目录分别 commit(主工作区无 git 则跳过):
|
|
319
|
+
```bash
|
|
320
|
+
for proj in $(cat .sillyspec/config.yaml | grep -oP 'path:\s*\K.*'); do
|
|
321
|
+
cd "$proj" && git add .sillyspec/ 2>/dev/null && git commit -m "chore: sillyspec scan - codebase mapped" && cd - > /dev/null
|
|
322
|
+
done
|
|
234
323
|
```
|
|
235
324
|
|
|
236
325
|
### 路径校验 + 自检门控
|
package/templates/status.md
CHANGED
|
@@ -14,7 +14,37 @@
|
|
|
14
14
|
cat .sillyspec/config.yaml 2>/dev/null
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
**工作区模式:** 读取 config.yaml 子项目列表,对每个子项目检查 PROJECT.md、codebase
|
|
17
|
+
**工作区模式:** 读取 config.yaml 子项目列表,对每个子项目检查 PROJECT.md、codebase 文档数、进行中变更、归档数。**同时检查工作区根目录 `.sillyspec/changes/` 下的未归档变更。** 检查共享规范和工作区概览。输出汇总后结束,不执行单项目流程。
|
|
18
|
+
|
|
19
|
+
工作区变更检查命令:
|
|
20
|
+
```bash
|
|
21
|
+
# 工作区根目录的变更
|
|
22
|
+
ls .sillyspec/changes/ 2>/dev/null | grep -v archive
|
|
23
|
+
ls .sillyspec/changes/archive/ 2>/dev/null | wc -l
|
|
24
|
+
|
|
25
|
+
# 每个子项目的变更
|
|
26
|
+
for proj in $(cat .sillyspec/config.yaml | grep -oP 'path:\s*\K.*'); do
|
|
27
|
+
echo "=== $(basename $proj) changes ==="
|
|
28
|
+
ls "$proj/.sillyspec/changes/" 2>/dev/null | grep -v archive
|
|
29
|
+
ls "$proj/.sillyspec/changes/archive/" 2>/dev/null | wc -l
|
|
30
|
+
done
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**汇总输出格式:**
|
|
34
|
+
```
|
|
35
|
+
📊 SillySpec 状态
|
|
36
|
+
📋 工作区模式 — N 个子项目
|
|
37
|
+
|
|
38
|
+
工作区变更:
|
|
39
|
+
🔄 进行中:sec-bonus-penalty(tasks: 3/5)
|
|
40
|
+
✅ 已归档:1 个
|
|
41
|
+
|
|
42
|
+
┌───────────────────┬────────────┬────────────┬────────┬────────┐
|
|
43
|
+
│ 子项目 │ PROJECT.md │ 代码库文档 │ 进行中 │ 已归档 │
|
|
44
|
+
├───────────────────┼────────────┼────────────┼────────┼────────┤
|
|
45
|
+
│ back-service │ ✗ │ 7 份 │ 1 │ 0 │
|
|
46
|
+
└───────────────────┴────────────┴────────────┴────────┴────────┘
|
|
47
|
+
```
|
|
18
48
|
|
|
19
49
|
**单项目模式:** 继续 Step 2。
|
|
20
50
|
|
package/templates/verify.md
CHANGED
|
@@ -11,11 +11,27 @@
|
|
|
11
11
|
## 状态检查(必须先执行)
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
sillyspec
|
|
14
|
+
cat .sillyspec/STATE.md 2>/dev/null
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
检查当前阶段。如果没有 STATE.md,检查是否有未归档变更:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
ls .sillyspec/changes/ 2>/dev/null | grep -v archive
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
无 STATE.md 且无未归档变更 → 提示用户先完成 execute 或用 `/sillyspec:status` 查看状态。
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 工作区模式处理
|
|
28
|
+
|
|
29
|
+
如果 `.sillyspec/config.yaml` 包含 `projects` 字段:
|
|
30
|
+
|
|
31
|
+
1. 检查工作区根目录 `.sillyspec/changes/` 下的未归档变更
|
|
32
|
+
2. 检查每个子项目 `<子项目路径>/.sillyspec/changes/` 下的未归档变更
|
|
33
|
+
3. 列出所有未归档变更,让用户选择要验证哪个
|
|
34
|
+
4. 根据 $ARGUMENTS 或用户选择,cd 到对应目录执行验证
|
|
19
35
|
|
|
20
36
|
---
|
|
21
37
|
|
|
@@ -24,8 +40,13 @@ sillyspec status --json
|
|
|
24
40
|
### 1. 加载规范
|
|
25
41
|
|
|
26
42
|
```bash
|
|
27
|
-
|
|
28
|
-
|
|
43
|
+
# 确定变更目录
|
|
44
|
+
if [ -n "$ARGUMENTS" ]; then
|
|
45
|
+
CHANGE_DIR=".sillyspec/changes/$ARGUMENTS"
|
|
46
|
+
else
|
|
47
|
+
CHANGE_DIR=$(ls -d .sillyspec/changes/*/ 2>/dev/null | grep -v archive | tail -1)
|
|
48
|
+
fi
|
|
49
|
+
cat "$CHANGE_DIR"/{design,tasks}.md 2>/dev/null
|
|
29
50
|
```
|
|
30
51
|
|
|
31
52
|
锚定确认实际存在的文件。
|
|
@@ -61,14 +82,6 @@ grep -r "TODO\|FIXME\|HACK\|XXX" src/ lib/ app/ --include="*.ts" --include="*.ts
|
|
|
61
82
|
## 结论:✅ PASS / ⚠️ PASS WITH NOTES / ❌ FAIL
|
|
62
83
|
```
|
|
63
84
|
|
|
64
|
-
```bash
|
|
65
|
-
bash scripts/validate-all.sh 2>/dev/null
|
|
66
|
-
```
|
|
67
|
-
|
|
68
85
|
### 7. 完成
|
|
69
86
|
|
|
70
|
-
|
|
71
|
-
sillyspec status --json && sillyspec next
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
更新 `.sillyspec/STATE.md`:阶段改为 `verify ✅` 或 `verify ⚠️`。
|
|
87
|
+
更新 `.sillyspec/STATE.md`(如存在):阶段改为 `verify ✅` 或 `verify ⚠️`。
|