sillyspec 3.12.0 → 3.12.2
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.md +18 -0
- package/docs/sillyspec/file-lifecycle.md +21 -16
- package/package.json +1 -1
- package/src/hooks/worktree-guard.js +26 -58
- package/src/index.js +2 -2
- package/src/init.js +1 -1
- package/src/progress.js +10 -10
- package/src/run.js +9 -5
- package/src/stages/archive.js +1 -1
- package/src/stages/brainstorm.js +1 -1
- package/src/stages/doctor.js +25 -39
- package/src/stages/execute.js +1 -0
- package/src/stages/index.js +1 -1
- package/src/stages/plan.js +7 -2
- package/src/stages/quick.js +6 -1
- package/src/stages/scan.js +131 -75
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Claude Code 指引
|
|
2
|
+
|
|
3
|
+
## 文件生命周期文档同步
|
|
4
|
+
每次修改 `src/stages/` 下的阶段定义(prompt、步骤、输出文件名等)或 `src/run.js`、`src/progress.js` 等影响文件生命周期的代码后,**必须同步更新** `docs/sillyspec/file-lifecycle.md`,确保文档与代码一致。
|
|
5
|
+
|
|
6
|
+
### 触发更新的典型改动
|
|
7
|
+
- 新增/删除/重命名阶段步骤
|
|
8
|
+
- 修改步骤 prompt 中的输出文件名(如 verify-result.md)
|
|
9
|
+
- 修改阶段间的流转逻辑(如 archive 归档方式)
|
|
10
|
+
- 新增/删除运行时文件类型(如 gate-status.json)
|
|
11
|
+
- 修改 ProgressManager 的数据存储方式(如 SQLite 表结构变更)
|
|
12
|
+
|
|
13
|
+
### 更新检查清单
|
|
14
|
+
- [ ] 文件名引用一致(prompt 输出的文件名 == validateFileLocations 期望的文件名)
|
|
15
|
+
- [ ] 阶段步骤描述与 `src/stages/*.js` 一致
|
|
16
|
+
- [ ] 归档/清理流程描述与实际代码逻辑一致
|
|
17
|
+
- [ ] 数据库 Schema 描述与 `src/db.js` 一致
|
|
18
|
+
- [ ] 更新文档头部 `updated_at` 时间戳
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
author: qinyi
|
|
3
3
|
created_at: 2026-05-31 11:00:00
|
|
4
|
-
updated_at: 2026-05-31
|
|
4
|
+
updated_at: 2026-05-31 21:35:00
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# SillySpec 文件生命周期描述
|
|
@@ -33,7 +33,7 @@ updated_at: 2026-05-31 11:00:00
|
|
|
33
33
|
│ │ ├── tasks/ ← 单任务实现文档目录(plan 阶段创建)
|
|
34
34
|
│ │ │ └── task-NN.md
|
|
35
35
|
│ │ ├── module-impact.md ← 模块影响分析矩阵
|
|
36
|
-
│ │ ├──
|
|
36
|
+
│ │ ├── verify-result.md ← 验证报告(归档产物)
|
|
37
37
|
│ │ ├── prototype-*.html ← HTML 原型(可选,brainstorm 判断)
|
|
38
38
|
│ │ └── MASTER.md ← 大需求拆分主控(可选,brainstorm 判断拆分时)
|
|
39
39
|
│ └── archive/ ← 已归档变更
|
|
@@ -472,9 +472,7 @@ created_at: <YYYY-MM-DD HH:mm:ss>
|
|
|
472
472
|
|
|
473
473
|
---
|
|
474
474
|
|
|
475
|
-
### `verify-result.md`
|
|
476
|
-
|
|
477
|
-
> ⚠️ **代码存在命名不一致**:verify 阶段 prompt 中输出文件名为 `verification.md`,但 `validateFileLocations()` 期望的文件名是 `verify-result.md`。实际运行时 AI 按照 prompt 写入 `verification.md`,但位置校验会报 `verify-result.md` 缺失。这是已知的不一致。
|
|
475
|
+
### `verify-result.md` — 验证报告
|
|
478
476
|
|
|
479
477
|
**创建时机:** verify 阶段"输出验证报告"步骤
|
|
480
478
|
|
|
@@ -529,7 +527,7 @@ PASS / PASS WITH NOTES / FAIL
|
|
|
529
527
|
|
|
530
528
|
**临时文件:** `_env-detect.md`(环境探测中间产物,扫描完成后删除)
|
|
531
529
|
|
|
532
|
-
**断点续扫:** "
|
|
530
|
+
**断点续扫:** "检查已有扫描文档和子项目列表"步骤检查已有文档,**必须停下来问用户**选择「全部重新扫描」或「只补缺失文档」,不能自行决定跳过。
|
|
533
531
|
|
|
534
532
|
**生命周期:** scan 阶段生成 → 被后续所有阶段(brainstorm/propose/plan/execute/verify)作为上下文读取
|
|
535
533
|
|
|
@@ -580,7 +578,9 @@ modules:
|
|
|
580
578
|
|
|
581
579
|
### `<module>.md` — 模块当前状态描述
|
|
582
580
|
|
|
583
|
-
**创建时机:**
|
|
581
|
+
**创建时机:**
|
|
582
|
+
- scan 阶段"生成模块核心文档"步骤(可选,首次全量生成,需用户确认)
|
|
583
|
+
- archive 阶段 `sync-module-docs` 步骤(首次受影响时创建,后续更新)
|
|
584
584
|
|
|
585
585
|
**大体结构:**
|
|
586
586
|
```markdown
|
|
@@ -629,7 +629,8 @@ modules:
|
|
|
629
629
|
- 更新头部元数据:`> 最后更新:YYYY-MM-DD` 和 `> 最近变更:<change-name>`
|
|
630
630
|
|
|
631
631
|
**更新时机:**
|
|
632
|
-
-
|
|
632
|
+
- scan 阶段"生成模块核心文档"步骤(首次全量生成,需用户确认)
|
|
633
|
+
- archive 阶段 `sync-module-docs` 步骤(通过 module-impact.md 驱动增量更新)
|
|
633
634
|
- quick 阶段"暂存和更新记录"步骤(直接匹配 git diff 文件到模块,同步更新)
|
|
634
635
|
|
|
635
636
|
**消费方:** brainstorm/propose/plan/execute 阶段"加载上下文"时读取,作为开发参考
|
|
@@ -758,12 +759,12 @@ test_strategy: module
|
|
|
758
759
|
|
|
759
760
|
### 变更归档流程
|
|
760
761
|
|
|
761
|
-
**触发:** archive 阶段"确认归档"
|
|
762
|
+
**触发:** archive 阶段"确认归档"步骤(AI 直接执行 mkdir + mv 移动变更目录)
|
|
762
763
|
|
|
763
764
|
**操作:**
|
|
764
|
-
1.
|
|
765
|
-
2.
|
|
766
|
-
3.
|
|
765
|
+
1. AI 创建 `archive/` 目录:`mkdir -p .sillyspec/changes/archive`
|
|
766
|
+
2. AI 移动变更目录:`mv .sillyspec/changes/<name> .sillyspec/changes/archive/<name>`
|
|
767
|
+
3. AI 确认移动成功:`ls .sillyspec/changes/archive/<name>/`
|
|
767
768
|
4. `unregisterChange()` 将 `changes.status` 更新为 `archived`(SQL UPDATE)
|
|
768
769
|
|
|
769
770
|
### Worktree 清理流程
|
|
@@ -1036,7 +1037,8 @@ graph LR
|
|
|
1036
1037
|
| `AGENTS.md` 等 | 选了 codex/gemini/opencode 工具 | init | AI 工具读取 |
|
|
1037
1038
|
| `projects/*.yaml` | init 自动创建 | init | 子项目上下文加载 |
|
|
1038
1039
|
| `modules/_module-map.yaml` | scan 可选步骤 | scan | archive/plan/execute |
|
|
1039
|
-
| `
|
|
1040
|
+
| `modules/<module>.md` | scan 可选步骤(全量生成)+ archive sync-module-docs | scan/archive | propose/plan/execute/verify/quick |
|
|
1041
|
+
| `verify-result.md` | verify 阶段输出 | verify | 验证报告存档 |
|
|
1040
1042
|
|
|
1041
1043
|
|
|
1042
1044
|
```
|
|
@@ -1049,7 +1051,7 @@ sillyspec init
|
|
|
1049
1051
|
├─→ .sillyspec/knowledge/
|
|
1050
1052
|
└─→ .gitignore (追加 .sillyspec/.runtime/)
|
|
1051
1053
|
|
|
1052
|
-
scan
|
|
1054
|
+
scan 阶段(12 步,完成后重置)
|
|
1053
1055
|
│
|
|
1054
1056
|
├─→ docs/<name>/scan/ARCHITECTURE.md
|
|
1055
1057
|
├─→ docs/<name>/scan/CONVENTIONS.md
|
|
@@ -1059,6 +1061,7 @@ scan 阶段
|
|
|
1059
1061
|
├─→ docs/<name>/scan/CONCERNS.md
|
|
1060
1062
|
├─→ docs/<name>/scan/PROJECT.md
|
|
1061
1063
|
├─→ docs/<name>/modules/_module-map.yaml (可选)
|
|
1064
|
+
├─→ docs/<name>/modules/<module>.md (可选,需用户确认)
|
|
1062
1065
|
└─→ .sillyspec/local.yaml
|
|
1063
1066
|
|
|
1064
1067
|
brainstorm 阶段
|
|
@@ -1093,15 +1096,17 @@ execute 阶段
|
|
|
1093
1096
|
|
|
1094
1097
|
verify 阶段
|
|
1095
1098
|
│
|
|
1096
|
-
└─→ changes/<name>/
|
|
1099
|
+
└─→ changes/<name>/verify-result.md
|
|
1097
1100
|
|
|
1098
|
-
quick
|
|
1101
|
+
quick 阶段(辅助阶段,不走完整流程,完成后重置)
|
|
1099
1102
|
│
|
|
1100
1103
|
├─→ .sillyspec/quicklog/QUICKLOG-<user>.md (无 --change 时)
|
|
1101
1104
|
├─→ .sillyspec/.runtime/worktrees/<name>/meta.json
|
|
1102
1105
|
├─→ .sillyspec/.runtime/gate-status.json
|
|
1103
1106
|
└─→ docs/<name>/modules/<module>.md (直接同步,不经过 module-impact.md)
|
|
1104
1107
|
|
|
1108
|
+
> quick 阶段"理解任务"步骤会加载模块文档作为上下文参考。
|
|
1109
|
+
|
|
1105
1110
|
archive 阶段
|
|
1106
1111
|
│
|
|
1107
1112
|
├─→ changes/<name>/module-impact.md
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* 纯判断模块,不做实际的 hook 注入。
|
|
6
6
|
*
|
|
7
7
|
* P0 优化:
|
|
8
|
-
* - 阶段检测 fallback:gate-status.json →
|
|
8
|
+
* - 阶段检测 fallback:gate-status.json → sillyspec.db currentStage
|
|
9
9
|
* - 拦截提示针对每个阶段给出具体修复建议
|
|
10
10
|
*/
|
|
11
11
|
|
|
@@ -100,41 +100,27 @@ function readGateStatus(cwd) {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
/**
|
|
103
|
-
* 从
|
|
104
|
-
* 优先级:gate-status.json >
|
|
103
|
+
* 从 sillyspec.db 读取 currentStage
|
|
104
|
+
* 优先级:gate-status.json > sillyspec.db
|
|
105
105
|
* @param {string} cwd
|
|
106
106
|
* @returns {string|null} 阶段名,null 表示无法确定
|
|
107
107
|
*/
|
|
108
108
|
function readCurrentStage(cwd) {
|
|
109
|
-
// 1. gate-status.json
|
|
109
|
+
// 1. gate-status.json(高速缓存,权威来源)
|
|
110
110
|
const gateStatus = readGateStatus(cwd)
|
|
111
111
|
if (gateStatus && gateStatus.stage) return gateStatus.stage
|
|
112
112
|
|
|
113
|
-
// 2.
|
|
114
|
-
const
|
|
115
|
-
if (existsSync(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (existsSync(globalFile)) {
|
|
125
|
-
try {
|
|
126
|
-
const global = JSON.parse(readFileSync(globalFile, 'utf8'))
|
|
127
|
-
const changesDir = path.join(cwd, '.sillyspec', 'changes')
|
|
128
|
-
for (const cn of (global.activeChanges || [])) {
|
|
129
|
-
const pp = path.join(changesDir, cn, 'progress.json')
|
|
130
|
-
if (!existsSync(pp)) continue
|
|
131
|
-
try {
|
|
132
|
-
const data = JSON.parse(readFileSync(pp, 'utf8'))
|
|
133
|
-
if (data.currentStage) return data.currentStage
|
|
134
|
-
} catch { /* skip */ }
|
|
135
|
-
}
|
|
136
|
-
} catch { /* skip */ }
|
|
137
|
-
}
|
|
113
|
+
// 2. 从 sillyspec.db 读取(通过 sqlite3 CLI 同步调用)
|
|
114
|
+
const dbPath = path.join(cwd, '.sillyspec', '.runtime', 'sillyspec.db')
|
|
115
|
+
if (!existsSync(dbPath)) return null
|
|
116
|
+
try {
|
|
117
|
+
const { execSync } = require('child_process')
|
|
118
|
+
const result = execSync(
|
|
119
|
+
`sqlite3 "${dbPath}" "SELECT current_stage FROM changes WHERE status='active' AND current_stage IN ('execute','quick') ORDER BY last_active DESC LIMIT 1"`,
|
|
120
|
+
{ encoding: 'utf8', timeout: 2000 }
|
|
121
|
+
).trim()
|
|
122
|
+
return result || null
|
|
123
|
+
} catch { /* sqlite3 CLI 不可用或查询失败 */ }
|
|
138
124
|
|
|
139
125
|
return null
|
|
140
126
|
}
|
|
@@ -149,35 +135,17 @@ function isNoWorktreeMode(cwd) {
|
|
|
149
135
|
const gateStatus = readGateStatus(cwd)
|
|
150
136
|
if (gateStatus && gateStatus.noWorktree) return true
|
|
151
137
|
|
|
152
|
-
// 2.
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// 3. 检查变更级 progress.json
|
|
165
|
-
const runtimeDir = path.join(cwd, '.sillyspec', '.runtime')
|
|
166
|
-
const globalFile = path.join(runtimeDir, 'global.json')
|
|
167
|
-
if (existsSync(globalFile)) {
|
|
168
|
-
try {
|
|
169
|
-
const global = JSON.parse(readFileSync(globalFile, 'utf8'))
|
|
170
|
-
const changesDir = path.join(cwd, '.sillyspec', 'changes')
|
|
171
|
-
for (const cn of (global.activeChanges || [])) {
|
|
172
|
-
const pp = path.join(changesDir, cn, 'progress.json')
|
|
173
|
-
if (!existsSync(pp)) continue
|
|
174
|
-
try {
|
|
175
|
-
const data = JSON.parse(readFileSync(pp, 'utf8'))
|
|
176
|
-
if (data.noWorktree) return true
|
|
177
|
-
} catch { /* skip */ }
|
|
178
|
-
}
|
|
179
|
-
} catch { /* skip */ }
|
|
180
|
-
}
|
|
138
|
+
// 2. 从 sillyspec.db 读取
|
|
139
|
+
const dbPath = path.join(cwd, '.sillyspec', '.runtime', 'sillyspec.db')
|
|
140
|
+
if (!existsSync(dbPath)) return false
|
|
141
|
+
try {
|
|
142
|
+
const { execSync } = require('child_process')
|
|
143
|
+
const result = execSync(
|
|
144
|
+
`sqlite3 "${dbPath}" "SELECT no_worktree FROM changes WHERE status='active' AND current_stage IN ('execute','quick') LIMIT 1"`,
|
|
145
|
+
{ encoding: 'utf8', timeout: 2000 }
|
|
146
|
+
).trim()
|
|
147
|
+
return result === '1'
|
|
148
|
+
} catch { /* sqlite3 CLI 不可用或查询失败 */ }
|
|
181
149
|
|
|
182
150
|
return false
|
|
183
151
|
}
|
package/src/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SillySpec CLI — 安装工具
|
|
5
5
|
*
|
|
6
6
|
* 只负责两件事:init(安装命令模板)和 setup(安装 MCP 工具)。
|
|
7
|
-
* 状态管理通过
|
|
7
|
+
* 状态管理通过 sillyspec.db(SQLite)完成,使用 `sillyspec progress` 命令。
|
|
8
8
|
*/
|
|
9
9
|
import { existsSync, readdirSync, readFileSync, statSync } from 'fs';
|
|
10
10
|
import { join, resolve } from 'path';
|
|
@@ -39,7 +39,7 @@ SillySpec CLI — 规范驱动开发工具包
|
|
|
39
39
|
quick, explore, status, doctor
|
|
40
40
|
|
|
41
41
|
sillyspec progress <cmd> 进度记录(轻量,不强制顺序)
|
|
42
|
-
init
|
|
42
|
+
init 初始化项目数据库
|
|
43
43
|
show 查看当前进度
|
|
44
44
|
set-stage <stage> 设置当前阶段
|
|
45
45
|
add-step <stage> <name> 添加步骤
|
package/src/init.js
CHANGED
|
@@ -56,7 +56,7 @@ const INJECTION_CONTENT = `## SillySpec — 规范驱动开发
|
|
|
56
56
|
- 遵循 \`.sillyspec/docs/<project>/scan/CONVENTIONS.md\` 中的代码风格
|
|
57
57
|
|
|
58
58
|
### 工作流程
|
|
59
|
-
-
|
|
59
|
+
- 读取 sillyspec.db 确认当前阶段(使用 \`sillyspec progress show\`)
|
|
60
60
|
- 各阶段产出文件位于 \`.sillyspec/changes/<变更名>/\` 下
|
|
61
61
|
`;
|
|
62
62
|
|
package/src/progress.js
CHANGED
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 纯 Node.js,无外部依赖。支持多变更并行。
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* .sillyspec/.runtime/
|
|
8
|
-
* .sillyspec/
|
|
6
|
+
* 存储结构:
|
|
7
|
+
* .sillyspec/.runtime/sillyspec.db — SQLite 数据库(权威状态源)
|
|
8
|
+
* .sillyspec/.runtime/global.json — 全局状态缓存(项目名、活跃变更列表)
|
|
9
|
+
* .sillyspec/.runtime/gate-status.json — worktree-guard 门禁状态缓存
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
+
* 历史迁移:v1/v2 使用 progress.json 文件,v3 已全部迁移至 SQLite。
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, unlinkSync } from 'fs';
|
|
@@ -17,7 +18,6 @@ import { DB } from './db.js';
|
|
|
17
18
|
const RUNTIME_DIR = '.sillyspec/.runtime';
|
|
18
19
|
const CHANGES_DIR = '.sillyspec/changes';
|
|
19
20
|
const GLOBAL_FILE = 'global.json';
|
|
20
|
-
const PROGRESS_FILE = 'progress.json';
|
|
21
21
|
const CURRENT_VERSION = 3;
|
|
22
22
|
const VALID_STAGES = ['scan', 'brainstorm', 'propose', 'plan', 'execute', 'verify', 'archive', 'quick', 'explore'];
|
|
23
23
|
const VALID_STATUSES = ['pending', 'in-progress', 'completed', 'failed', 'blocked'];
|
|
@@ -154,7 +154,7 @@ export class ProgressManager {
|
|
|
154
154
|
* 读取指定变更的 progress(SQL 版)
|
|
155
155
|
* @param {string} cwd
|
|
156
156
|
* @param {string|null} changeName - 变更名,null 时尝试自动检测
|
|
157
|
-
* @returns {Promise<object|null>}
|
|
157
|
+
* @returns {Promise<object|null>} 与 SQLite 查询结果一致的 JS 对象
|
|
158
158
|
*/
|
|
159
159
|
async read(cwd, changeName = null) {
|
|
160
160
|
// 自动检测变更名
|
|
@@ -759,7 +759,7 @@ export class ProgressManager {
|
|
|
759
759
|
async _showChange(cwd, changeName) {
|
|
760
760
|
const data = await this.read(cwd, changeName);
|
|
761
761
|
if (!data) {
|
|
762
|
-
console.log(`❌ 未找到变更 ${changeName}
|
|
762
|
+
console.log(`❌ 未找到变更 ${changeName}`);
|
|
763
763
|
return;
|
|
764
764
|
}
|
|
765
765
|
|
|
@@ -816,7 +816,7 @@ export class ProgressManager {
|
|
|
816
816
|
|
|
817
817
|
async validate(cwd, changeName = null) {
|
|
818
818
|
const data = await this.read(cwd, changeName);
|
|
819
|
-
if (!data) { console.log('❌
|
|
819
|
+
if (!data) { console.log('❌ 无法读取进度数据'); return false; }
|
|
820
820
|
|
|
821
821
|
const errors = [];
|
|
822
822
|
if (!data._version || !Number.isInteger(data._version) || data._version < 1) {
|
|
@@ -825,7 +825,7 @@ export class ProgressManager {
|
|
|
825
825
|
if (!data.stages || typeof data.stages !== 'object') errors.push('缺少 stages');
|
|
826
826
|
if (!VALID_STAGES.every(s => data.stages[s])) errors.push('缺少阶段定义');
|
|
827
827
|
|
|
828
|
-
if (errors.length === 0) { console.log('✅
|
|
828
|
+
if (errors.length === 0) { console.log('✅ 进度数据格式正确'); return true; }
|
|
829
829
|
|
|
830
830
|
console.log(`⚠️ 发现问题,尝试修复...`);
|
|
831
831
|
let fixed = { ...data, stages: { ...data.stages } };
|
|
@@ -852,7 +852,7 @@ export class ProgressManager {
|
|
|
852
852
|
async reset(cwd, stage, changeName = null) {
|
|
853
853
|
if (stage) {
|
|
854
854
|
const data = await this.read(cwd, changeName);
|
|
855
|
-
if (!data) { console.log('❌
|
|
855
|
+
if (!data) { console.log('❌ 无法读取进度数据'); return; }
|
|
856
856
|
if (!data.stages[stage]) { console.log(`❌ 未知阶段: ${stage}`); return; }
|
|
857
857
|
data.stages[stage] = emptyStage();
|
|
858
858
|
data.lastActive = new Date().toLocaleString('zh-CN',{hour12:false});
|
package/src/run.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* sillyspec run 命令实现
|
|
3
3
|
*
|
|
4
4
|
* CLI 成为流程引擎,AI 变成步骤执行器。
|
|
5
|
-
*
|
|
5
|
+
* 支持多变更并行:每个变更状态存储在 sillyspec.db 中。
|
|
6
6
|
*/
|
|
7
7
|
import { basename, join } from 'path'
|
|
8
8
|
import { existsSync, readdirSync, mkdirSync, writeFileSync, appendFileSync, readFileSync, statSync } from 'fs'
|
|
@@ -267,7 +267,11 @@ export async function runCommand(args, cwd) {
|
|
|
267
267
|
const autoChange = changeName || resolveChangeNameAuto(cwd)
|
|
268
268
|
if (autoChange) {
|
|
269
269
|
progress = await pm.initChange(cwd, autoChange)
|
|
270
|
-
} else if (
|
|
270
|
+
} else if (isAuxiliary) {
|
|
271
|
+
// 辅助阶段(scan/explore/quick/doctor/status)不需要 currentChange
|
|
272
|
+
// 但仍然需要初始化一个空的 progress 对象以避免后续引用报错
|
|
273
|
+
progress = { currentStage: stageName, stages: {}, lastActive: new Date().toLocaleString('zh-CN', { hour12: false }) }
|
|
274
|
+
} else {
|
|
271
275
|
// brainstorm / propose 作为流程入口,自动生成变更名并初始化
|
|
272
276
|
if (stageName === 'brainstorm' || stageName === 'propose') {
|
|
273
277
|
const date = new Date().toISOString().slice(0, 10)
|
|
@@ -277,7 +281,7 @@ export async function runCommand(args, cwd) {
|
|
|
277
281
|
progress = await pm.initChange(cwd, autoName)
|
|
278
282
|
changeName = autoName
|
|
279
283
|
} else {
|
|
280
|
-
console.error('❌
|
|
284
|
+
console.error('❌ 未找到进度数据,请先运行 sillyspec init 或指定 --change <变更名>')
|
|
281
285
|
process.exit(1)
|
|
282
286
|
}
|
|
283
287
|
}
|
|
@@ -304,10 +308,10 @@ export async function runCommand(args, cwd) {
|
|
|
304
308
|
|
|
305
309
|
// 确保步骤已初始化
|
|
306
310
|
const changed = await ensureStageSteps(progress, stageName, cwd)
|
|
307
|
-
if (changed) {
|
|
311
|
+
if (changed && effectiveChange) {
|
|
308
312
|
await pm._write(cwd, progress, effectiveChange)
|
|
309
313
|
triggerSync(cwd, effectiveChange)
|
|
310
|
-
progress = await pm.read(cwd, effectiveChange)
|
|
314
|
+
progress = await pm.read(cwd, effectiveChange) || progress
|
|
311
315
|
}
|
|
312
316
|
|
|
313
317
|
// --status
|
package/src/stages/archive.js
CHANGED
|
@@ -165,7 +165,7 @@ module-impact.md 路径 + 影响模块数量 + 未匹配文件数量`,
|
|
|
165
165
|
1. 如果 \`.sillyspec/ROADMAP.md\` 存在,标记对应 Phase 为已完成
|
|
166
166
|
2. \`git add .sillyspec/changes/\` — 暂存归档结果(不要 commit,由用户通过统一提交工具处理)
|
|
167
167
|
3. \`git add .sillyspec/docs/\` — 暂存模块文档更新(如有)
|
|
168
|
-
4. 更新
|
|
168
|
+
4. 更新 sillyspec.db 中的阶段状态:
|
|
169
169
|
- 清除当前变更信息(归档后不再活跃)
|
|
170
170
|
- 如果是主变更(有 MASTER.md),标记所有阶段为 ✅,然后清除
|
|
171
171
|
- 历史记录追加时间 + 归档完成
|
package/src/stages/brainstorm.js
CHANGED
package/src/stages/doctor.js
CHANGED
|
@@ -18,15 +18,10 @@ export const definition = {
|
|
|
18
18
|
for d in .sillyspec .sillyspec/projects .sillyspec/docs .sillyspec/changes .sillyspec/.runtime; do
|
|
19
19
|
[ -d "$d" ] && echo "✅ $d" || echo "❌ $d"
|
|
20
20
|
done
|
|
21
|
-
# 检查
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if [ -z "$PROGRESS_FILE" ]; then
|
|
26
|
-
PROGRESS_FILE='.sillyspec/.runtime/progress.json'
|
|
27
|
-
fi
|
|
28
|
-
[ -f "$PROGRESS_FILE" ] && echo "✅ progress.json 存在 ($PROGRESS_FILE)" || echo "❌ progress.json 不存在"
|
|
29
|
-
node -e "JSON.parse(require('fs').readFileSync('$PROGRESS_FILE','utf8')); console.log('✅ progress.json 可解析')" 2>/dev/null || echo "⚠️ progress.json 不可解析"
|
|
21
|
+
# 检查 sillyspec.db(SQLite 权威状态源)
|
|
22
|
+
DB_FILE='.sillyspec/.runtime/sillyspec.db'
|
|
23
|
+
[ -f "$DB_FILE" ] && echo "✅ sillyspec.db 存在" || echo "❌ sillyspec.db 不存在"
|
|
24
|
+
sqlite3 "$DB_FILE" "SELECT count(*) FROM project" 2>/dev/null && echo "✅ sillyspec.db 可查询" || echo "⚠️ sillyspec.db 不可查询"
|
|
30
25
|
\`\`\`
|
|
31
26
|
|
|
32
27
|
### 2. 项目配置检查
|
|
@@ -46,40 +41,31 @@ done
|
|
|
46
41
|
|
|
47
42
|
### 3. 进度数据一致性
|
|
48
43
|
\`\`\`bash
|
|
49
|
-
#
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
for (const [name, sd] of Object.entries(stages)) {
|
|
60
|
-
if (sd.status === 'completed' && sd.steps.length > 0) {
|
|
61
|
-
const hasOutput = sd.steps.some(s => s.output && s.output.trim());
|
|
62
|
-
console.log(' ' + name + ': ' + (hasOutput ? '✅ 有产出' : '⚠️ 已完成但无产出记录'));
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
" 2>/dev/null || echo "⚠️ 无法读取 progress.json"
|
|
44
|
+
# 从 sillyspec.db 读取活跃变更并检查目录存在性
|
|
45
|
+
DB_FILE='.sillyspec/.runtime/sillyspec.db'
|
|
46
|
+
if [ ! -f "$DB_FILE" ]; then echo "⚠️ sillyspec.db 不存在"; exit 0; fi
|
|
47
|
+
ACTIVE_CHANGE=$(sqlite3 "$DB_FILE" "SELECT name FROM changes WHERE status='active' ORDER BY last_active DESC LIMIT 1" 2>/dev/null)
|
|
48
|
+
if [ -z "$ACTIVE_CHANGE" ]; then echo "ℹ️ 无当前变更"; exit 0; fi
|
|
49
|
+
echo "当前变更: $ACTIVE_CHANGE"
|
|
50
|
+
DIR=".sillyspec/changes/$ACTIVE_CHANGE"
|
|
51
|
+
[ -d "$DIR" ] && echo "✅ 变更目录存在: $ACTIVE_CHANGE" || echo "❌ 变更目录不存在: $ACTIVE_CHANGE"
|
|
52
|
+
# 检查各阶段状态
|
|
53
|
+
sqlite3 -header -column "$DB_FILE" "SELECT stage, status FROM stages s JOIN changes c ON s.change_id=c.id WHERE c.name='$ACTIVE_CHANGE' ORDER BY s.stage" 2>/dev/null || echo "⚠️ 无法查询阶段数据"
|
|
66
54
|
\`\`\`
|
|
67
55
|
|
|
68
56
|
### 4. 孤儿文件检查
|
|
69
57
|
\`\`\`bash
|
|
58
|
+
DB_FILE='.sillyspec/.runtime/sillyspec.db'
|
|
59
|
+
if [ ! -f "$DB_FILE" ]; then echo "⚠️ sillyspec.db 不存在"; exit 0; fi
|
|
70
60
|
node -e "
|
|
71
61
|
const fs = require('fs');
|
|
72
62
|
const dir = '.sillyspec/changes';
|
|
73
63
|
if (!fs.existsSync(dir)) { console.log('ℹ️ changes/ 目录不存在'); process.exit(0); }
|
|
74
64
|
const subs = fs.readdirSync(dir).filter(f => fs.statSync(dir+'/'+f).isDirectory());
|
|
75
65
|
if (subs.length === 0) { console.log('ℹ️ 无变更目录'); process.exit(0); }
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const known = new Set();
|
|
79
|
-
if (progress.currentChange) known.add(progress.currentChange);
|
|
80
|
-
for (const sd of Object.values(progress.stages || {})) {
|
|
81
|
-
(sd.steps || []).forEach(s => { if (s.output) known.add(s.output); });
|
|
82
|
-
}
|
|
66
|
+
const { execSync } = require('child_process');
|
|
67
|
+
let known;
|
|
68
|
+
try { const rows = execSync('sqlite3 -json \".sillyspec/.runtime/sillyspec.db\" \"SELECT name FROM changes WHERE status=\\\"active\\\"\"', {encoding:'utf8'}).trim(); known = new Set(JSON.parse(rows).map(r => r.name)); } catch { known = new Set(); }
|
|
83
69
|
subs.forEach(s => {
|
|
84
70
|
console.log(known.has(s) ? '✅ ' + s + ' — 已关联' : '⚠️ ' + s + ' — 孤儿目录(可清理)');
|
|
85
71
|
});
|
|
@@ -124,12 +110,12 @@ done
|
|
|
124
110
|
|
|
125
111
|
### 1. 探测构建工具
|
|
126
112
|
\`\`\`bash
|
|
127
|
-
# 确定项目路径(使用
|
|
128
|
-
PROJECT_DIR=$(node -e "
|
|
113
|
+
# 确定项目路径(使用 sillyspec.db 中的项目路径或当前目录)
|
|
114
|
+
PROJECT_DIR=$(sqlite3 -json '.sillyspec/.runtime/sillyspec.db' "SELECT name FROM project WHERE id=1" 2>/dev/null | node -e "const r=JSON.parse(require('fs').readFileSync(0,'utf8'));console.log(r.length>0&&r[0].name?r[0].name:'.')" 2>/dev/null || node -e "
|
|
129
115
|
const fs=require('fs');
|
|
130
|
-
try{const
|
|
131
|
-
const files=fs.readdirSync('.sillyspec/projects').filter(f=>f.endsWith('.yaml'));
|
|
116
|
+
try{const files=fs.readdirSync('.sillyspec/projects').filter(f=>f.endsWith('.yaml'));
|
|
132
117
|
if(files.length>0){const c=fs.readFileSync('.sillyspec/projects/'+files[0],'utf8');const m=c.match(/^path:\\s*(.+)/m);console.log(m?m[1].trim():'.')}else console.log('.')
|
|
118
|
+
}catch{console.log('.')}
|
|
133
119
|
" 2>/dev/null)
|
|
134
120
|
echo "项目目录: $PROJECT_DIR"
|
|
135
121
|
|
|
@@ -264,7 +250,7 @@ timeout 5 which docker 2>/dev/null && echo "✅ Docker 可用" || echo "ℹ️ D
|
|
|
264
250
|
✅ .sillyspec/ 目录结构 — 正常
|
|
265
251
|
✅ projects/*.yaml — N 个项目已注册
|
|
266
252
|
⚠️ local.yaml (xxx) — 缺少 test 命令
|
|
267
|
-
❌
|
|
253
|
+
❌ sillyspec.db 阶段状态 — brainstorm 标记完成但 design.md 不存在
|
|
268
254
|
|
|
269
255
|
## 构建环境
|
|
270
256
|
✅ Node.js v23.4.0 — 可用
|
|
@@ -291,7 +277,7 @@ timeout 5 which docker 2>/dev/null && echo "✅ Docker 可用" || echo "ℹ️ D
|
|
|
291
277
|
- 缺少 local.yaml → \`sillyspec init\` 重新生成,或手动创建
|
|
292
278
|
- local.yaml 缺少 build/test → 补充对应命令
|
|
293
279
|
- 缺少 STACK.md → \`sillyspec run scan\` 重新扫描
|
|
294
|
-
-
|
|
280
|
+
- sillyspec.db 状态不一致 → \`sillyspec run <阶段> --reset\` 重置对应阶段
|
|
295
281
|
- 孤儿目录 → 确认后 \`rm -rf .sillyspec/changes/<目录名>\`
|
|
296
282
|
- Maven 私服不可达 → 检查 VPN、settings.xml 配置、私服状态
|
|
297
283
|
- Git remote 不可达 → 检查网络、SSH key 或凭证
|
package/src/stages/execute.js
CHANGED
|
@@ -322,6 +322,7 @@ ${taskSummary}
|
|
|
322
322
|
1. 任务目标(简短描述)
|
|
323
323
|
2. 蓝图文件路径(让子代理自行读取详情)
|
|
324
324
|
3. 编码铁律:先读后写、TDD、不编造方法、只做蓝图里写的事、遵守边界处理规则、不超出 allowed_paths
|
|
325
|
+
4. 如存在模块文档(.sillyspec/docs/*/modules/),按需读取涉及模块的 <module>.md 参考接口约定和数据流
|
|
325
326
|
|
|
326
327
|
### Wave 开始前
|
|
327
328
|
1. 读取 design.md 的「编码铁律」章节(如果存在),严格遵守
|
package/src/stages/index.js
CHANGED
package/src/stages/plan.js
CHANGED
|
@@ -316,8 +316,13 @@ export function buildCoordinatorStep(changeDir, taskNames) {
|
|
|
316
316
|
|
|
317
317
|
操作:
|
|
318
318
|
1. 读取 ${changeDir}/design.md 和 ${changeDir}/plan.md 了解上下文
|
|
319
|
-
2.
|
|
320
|
-
|
|
319
|
+
2. 读取相关模块文档(如存在):
|
|
320
|
+
- \
|
|
321
|
+
ls .sillyspec/docs/*/modules/_module-map.yaml 2>/dev/null\
|
|
322
|
+
确认模块划分,读取涉及模块的 \
|
|
323
|
+
ls .sillyspec/docs/*/modules/*.md 2>/dev/null\
|
|
324
|
+
3. 读取相关源文件了解现有代码
|
|
325
|
+
4. 按以下格式编写任务蓝图并保存到 ${changeDir}/tasks/task-${num}.md:
|
|
321
326
|
|
|
322
327
|
---
|
|
323
328
|
id: task-${num}
|
package/src/stages/quick.js
CHANGED
|
@@ -17,6 +17,11 @@ export const definition = {
|
|
|
17
17
|
6. 如有 \`--change\`,加载设计文档:\`cat .sillyspec/changes/<change-name>/design.md 2>/dev/null\`(理解设计意图)
|
|
18
18
|
7. 如有需要,查询知识库:\`cat .sillyspec/knowledge/INDEX.md 2>/dev/null\`
|
|
19
19
|
|
|
20
|
+
### 模块文档加载
|
|
21
|
+
8. 读取 \`.sillyspec/docs/<project>/modules/_module-map.yaml\`(不存在则跳过以下步骤)
|
|
22
|
+
9. 根据任务描述初步判断可能涉及的模块
|
|
23
|
+
10. 读取匹配到的 \`.sillyspec/docs/<project>/modules/<module>.md\`
|
|
24
|
+
|
|
20
25
|
### 创建任务记录(必须执行)
|
|
21
26
|
理解完任务后,立即创建记录文件:
|
|
22
27
|
1. \`git config user.name\` 获取用户名
|
|
@@ -57,7 +62,7 @@ worktree 路径 + 变更名 + 分支名`,
|
|
|
57
62
|
prompt: `实现任务。
|
|
58
63
|
|
|
59
64
|
### 工作目录
|
|
60
|
-
|
|
65
|
+
你必须在上一步记录的 worktree 路径中工作。
|
|
61
66
|
不要在主工作区修改源码文件。所有代码变更只在 worktree 中进行。
|
|
62
67
|
|
|
63
68
|
### 操作
|
package/src/stages/scan.js
CHANGED
|
@@ -44,11 +44,16 @@ export const definition = {
|
|
|
44
44
|
1. \`ls .sillyspec/projects/*.yaml 2>/dev/null | grep -q .\` — 检查已有文档
|
|
45
45
|
1. \`ls .sillyspec/docs/*/scan/ 2>/dev/null\` — 检查已有文档
|
|
46
46
|
2. \`wc -l .sillyspec/docs/*/scan/*.md 2>/dev/null\` — 文档行数
|
|
47
|
-
3.
|
|
48
|
-
|
|
47
|
+
3. 显示子项目列表供选择扫描范围
|
|
48
|
+
|
|
49
|
+
### ⛔ 重要:已有文档时的处理
|
|
50
|
+
如果发现已有 scan 文档(如 7 份齐全),**必须停下来问用户**:
|
|
51
|
+
- 列出已有文档状态(哪些存在、哪些缺失)
|
|
52
|
+
- 明确提供两个选项:**重新扫描(全部覆盖)** 或 **只补扫描缺失的文档**
|
|
53
|
+
- **不要自行决定跳过**,等用户选择后再继续
|
|
49
54
|
|
|
50
55
|
### 输出
|
|
51
|
-
已有文档状态 +
|
|
56
|
+
已有文档状态 + 等待用户选择`,
|
|
52
57
|
outputHint: '工作区和文档状态',
|
|
53
58
|
optional: false
|
|
54
59
|
},
|
|
@@ -71,7 +76,7 @@ export const definition = {
|
|
|
71
76
|
prompt: `检测已有扫描文档,只生成缺失的。
|
|
72
77
|
|
|
73
78
|
### 操作
|
|
74
|
-
1. \`PROJECT=$(
|
|
79
|
+
1. \`PROJECT=$(sqlite3 -json '.sillyspec/.runtime/sillyspec.db' "SELECT name FROM project WHERE id=1" 2>/dev/null | node -e "const r=JSON.parse(require('fs').readFileSync(0,'utf8'));console.log(r.length>0?r[0].name:'')" 2>/dev/null || basename "$(pwd)")\`
|
|
75
80
|
2. 检查 7 份文档是否存在:ARCHITECTURE、STRUCTURE、CONVENTIONS、INTEGRATIONS、TESTING、CONCERNS、PROJECT
|
|
76
81
|
3. 列出已有 ✅ 和缺失 ⬜
|
|
77
82
|
4. 只生成缺失的文档
|
|
@@ -82,73 +87,67 @@ export const definition = {
|
|
|
82
87
|
optional: false
|
|
83
88
|
},
|
|
84
89
|
{
|
|
85
|
-
name: '深度扫描 —
|
|
86
|
-
prompt:
|
|
87
|
-
|
|
88
|
-
###
|
|
89
|
-
1.
|
|
90
|
-
2.
|
|
91
|
-
3.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
3. 写入 \`.sillyspec/docs/<project>/scan/CONCERNS.md\`(按严重程度分组)
|
|
147
|
-
4. 写入 \`.sillyspec/docs/<project>/scan/PROJECT.md\`(项目信息)
|
|
148
|
-
|
|
149
|
-
### 输出
|
|
150
|
-
TESTING.md、CONCERNS.md、PROJECT.md 路径`,
|
|
151
|
-
outputHint: '三份文档路径',
|
|
90
|
+
name: '深度扫描 — 7 份文档(子代理并行)',
|
|
91
|
+
prompt: `使用子代理并行生成 7 份扫描文档。**你必须使用子代理执行,不要自己写文档。**
|
|
92
|
+
|
|
93
|
+
### 执行方式
|
|
94
|
+
1. 为每个扫描任务启动独立子代理(可并行),每个子代理负责 1-2 份文档
|
|
95
|
+
2. 子代理直接用 grep/rg 搜索源码并写入文件,结果不回传到你的上下文
|
|
96
|
+
3. 等待所有子代理完成后,验证文件是否生成且非空
|
|
97
|
+
|
|
98
|
+
### 子代理任务分配
|
|
99
|
+
|
|
100
|
+
**子代理 A — 技术架构**
|
|
101
|
+
目标文件:\`.sillyspec/docs/<project>/scan/ARCHITECTURE.md\`
|
|
102
|
+
搜索范围:技术栈 + 数据库 Schema + 架构模式
|
|
103
|
+
- 用 grep/rg 搜索(\`@Entity\`、\`schema.prisma\`、\`models.py\` 等),**禁止读源码全文**
|
|
104
|
+
- Schema 只记表名+说明+字段数
|
|
105
|
+
- 包含 \`## 技术栈\` \`## 架构概览\` \`## 数据模型(摘要)\`
|
|
106
|
+
- 参考 _env-detect.md(如存在)
|
|
107
|
+
|
|
108
|
+
**子代理 B — 代码约定**
|
|
109
|
+
目标文件:\`.sillyspec/docs/<project>/scan/CONVENTIONS.md\`
|
|
110
|
+
搜索范围:框架隐形规则 + 实体继承 + 代码风格
|
|
111
|
+
- 用 grep 搜索拦截器/插件/逻辑删除/基类/审计字段,**禁止读源码全文**
|
|
112
|
+
- 根据检测到的语言/框架自行决定搜索什么模式
|
|
113
|
+
- 提取 3-5 个典型示例
|
|
114
|
+
- 包含 \`## 框架隐形规则\` \`## 实体继承规范\` \`## 代码风格\`
|
|
115
|
+
- 参考 _env-detect.md(如存在)
|
|
116
|
+
|
|
117
|
+
**子代理 C — 目录结构 + 外部集成**
|
|
118
|
+
目标文件:\`.sillyspec/docs/<project>/scan/STRUCTURE.md\` + \`.sillyspec/docs/<project>/scan/INTEGRATIONS.md\`
|
|
119
|
+
搜索范围:目录树 + 模块说明 + 外部集成
|
|
120
|
+
- 用 find/ls/tree 和 grep,**禁止读源码全文**
|
|
121
|
+
- 搜索 API 调用、MQ 配置、缓存、第三方 SDK
|
|
122
|
+
- STRUCTURE.md:目录树+模块说明
|
|
123
|
+
- INTEGRATIONS.md:外部集成(按类型分组)
|
|
124
|
+
- 参考 _env-detect.md(如存在)
|
|
125
|
+
|
|
126
|
+
**子代理 D — 测试 + 债务 + 项目概览**
|
|
127
|
+
目标文件:\`.sillyspec/docs/<project>/scan/TESTING.md\` + \`.sillyspec/docs/<project>/scan/CONCERNS.md\` + \`.sillyspec/docs/<project>/scan/PROJECT.md\`
|
|
128
|
+
搜索范围:测试文件 + TODO/FIXME + 过时依赖 + 项目信息
|
|
129
|
+
- 用 grep 搜索测试文件、TODO/FIXME、过时依赖,**禁止读源码全文**
|
|
130
|
+
- TESTING.md:测试结构
|
|
131
|
+
- CONCERNS.md:技术债务(按严重程度分组)
|
|
132
|
+
- PROJECT.md:项目概览
|
|
133
|
+
- 参考 _env-detect.md(如存在)
|
|
134
|
+
|
|
135
|
+
### 每个子代理的共同要求
|
|
136
|
+
- **上下文注入**:主 agent 在启动子代理前,必须将以下信息拼入子代理 prompt:
|
|
137
|
+
- 项目名(<project>)
|
|
138
|
+
- 断点续扫步骤列出的缺失文档列表(哪些要生成、哪些跳过)
|
|
139
|
+
- 环境探测结果摘要(构建工具、语言框架、关键依赖)
|
|
140
|
+
- _env-detect.md 内容(如存在,直接贴入)
|
|
141
|
+
- 路径用反引号,不编造
|
|
142
|
+
- 目标文件不存在则创建,已存在则覆盖
|
|
143
|
+
- 只生成缺失文档(根据断点续扫结果)
|
|
144
|
+
|
|
145
|
+
### 完成后
|
|
146
|
+
验证 7 份文档全部生成且非空,列出结果:
|
|
147
|
+
- ✅ ARCHITECTURE.md / ❌ 缺失
|
|
148
|
+
- ✅ CONVENTIONS.md / ❌ 缺失
|
|
149
|
+
- ...`,
|
|
150
|
+
outputHint: '7 份文档生成状态',
|
|
152
151
|
optional: false
|
|
153
152
|
},
|
|
154
153
|
{
|
|
@@ -235,15 +234,72 @@ _module-map.yaml 生成结果(已存在/已生成/模块列表)`,
|
|
|
235
234
|
outputHint: '_module-map.yaml 生成状态',
|
|
236
235
|
optional: true
|
|
237
236
|
},
|
|
237
|
+
{
|
|
238
|
+
name: '生成模块核心文档',
|
|
239
|
+
prompt: `根据 _module-map.yaml 中的模块划分,为每个模块生成核心文档(用于后续归档和开发上下文)。
|
|
240
|
+
|
|
241
|
+
### 操作
|
|
242
|
+
1. 读取 \`.sillyspec/docs/<project>/modules/_module-map.yaml\`,获取模块列表和路径
|
|
243
|
+
2. 检查 \`.sillyspec/docs/<project>/modules/\` 下已有的模块文档(<module>.md)
|
|
244
|
+
3. 列出每个模块的状态:已有文档 / 缺失
|
|
245
|
+
4. **必须停下来问用户**:
|
|
246
|
+
- 展示模块列表及现有文档状态
|
|
247
|
+
- 明确提供选项:**为缺失模块生成初始文档** / **全部重新生成(覆盖已有)** / **跳过**
|
|
248
|
+
5. 用户选择后执行
|
|
249
|
+
|
|
250
|
+
### 生成方法(子代理并行,只针对用户选中的模块)
|
|
251
|
+
**你必须为每个模块启动独立子代理执行,不要自己写文档。**
|
|
252
|
+
|
|
253
|
+
每个子代理的 prompt(**主 agent 启动前必须拼入**:
|
|
254
|
+
- 模块名和路径(从 _module-map.yaml 读取)
|
|
255
|
+
- 环境探测结果摘要(构建工具、语言框架)
|
|
256
|
+
- scan 文档关键信息摘要(ARCHITECTURE.md 的技术栈、CONVENTIONS.md 的代码风格要点,如已生成)
|
|
257
|
+
\`\`\`
|
|
258
|
+
模块名:<module-name>
|
|
259
|
+
模块路径:<glob patterns>
|
|
260
|
+
目标文件:.sillyspec/docs/<project>/modules/<module>.md
|
|
261
|
+
|
|
262
|
+
操作:
|
|
263
|
+
1. 用 grep/rg 搜索模块路径范围内的源码(禁止读源码全文)
|
|
264
|
+
2. 提取:模块职责、对外接口(导出函数/API)、关键依赖、设计要点
|
|
265
|
+
3. 按以下模板写入目标文件:
|
|
266
|
+
|
|
267
|
+
# <module-name>
|
|
268
|
+
> 最后更新:YYYY-MM-DD
|
|
269
|
+
> 最近变更:scan(初始生成)
|
|
270
|
+
> 模块路径:<glob patterns>
|
|
271
|
+
|
|
272
|
+
## 职责
|
|
273
|
+
## 当前设计
|
|
274
|
+
## 对外接口(表格)
|
|
275
|
+
## 关键数据流
|
|
276
|
+
## 设计决策(表格)
|
|
277
|
+
## 依赖关系
|
|
278
|
+
## 注意事项
|
|
279
|
+
## 变更索引(表格,初始为空)
|
|
280
|
+
|
|
281
|
+
规则:
|
|
282
|
+
- 不要编造接口或依赖,只写 grep/rg 能搜到的
|
|
283
|
+
- 模板与 archive 阶段格式一致
|
|
284
|
+
\`\`\`
|
|
285
|
+
|
|
286
|
+
等待所有子代理完成,验证文件是否生成且非空。
|
|
287
|
+
|
|
288
|
+
### 输出
|
|
289
|
+
已生成的模块文档路径列表`,
|
|
290
|
+
outputHint: '模块文档生成状态',
|
|
291
|
+
optional: true
|
|
292
|
+
},
|
|
238
293
|
{
|
|
239
294
|
name: '自检和提交',
|
|
240
295
|
prompt: `验证扫描完整性,清理并提交。
|
|
241
296
|
|
|
242
297
|
### 操作
|
|
243
|
-
1. 检查 7
|
|
244
|
-
2.
|
|
245
|
-
3.
|
|
246
|
-
4.
|
|
298
|
+
1. 检查 7 份 scan 文档是否全部生成
|
|
299
|
+
2. 检查模块文档状态(如有)
|
|
300
|
+
3. 自检门控:ARCHITECTURE(技术栈+Schema摘要)、CONVENTIONS(隐形规则+代码风格)、STRUCTURE(目录结构)、INTEGRATIONS(外部依赖)、TESTING(测试现状)、CONCERNS(技术债务)、PROJECT(项目概览)
|
|
301
|
+
4. 清理:\`rm -f .sillyspec/docs/<project>/scan/_env-detect.md\`
|
|
302
|
+
5. \`git add .sillyspec/\` — 暂存扫描结果(不要 commit,由用户通过统一提交工具处理)
|
|
247
303
|
|
|
248
304
|
### 输出
|
|
249
305
|
扫描完整性报告
|