sillyspec 3.12.1 → 3.12.3
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/docs/sillyspec/file-lifecycle.md +12 -5
- 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 +24 -14
- 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
|
@@ -527,7 +527,7 @@ PASS / PASS WITH NOTES / FAIL
|
|
|
527
527
|
|
|
528
528
|
**临时文件:** `_env-detect.md`(环境探测中间产物,扫描完成后删除)
|
|
529
529
|
|
|
530
|
-
**断点续扫:** "
|
|
530
|
+
**断点续扫:** "检查已有扫描文档和子项目列表"步骤检查已有文档,**必须停下来问用户**选择「全部重新扫描」或「只补缺失文档」,不能自行决定跳过。
|
|
531
531
|
|
|
532
532
|
**生命周期:** scan 阶段生成 → 被后续所有阶段(brainstorm/propose/plan/execute/verify)作为上下文读取
|
|
533
533
|
|
|
@@ -578,7 +578,9 @@ modules:
|
|
|
578
578
|
|
|
579
579
|
### `<module>.md` — 模块当前状态描述
|
|
580
580
|
|
|
581
|
-
**创建时机:**
|
|
581
|
+
**创建时机:**
|
|
582
|
+
- scan 阶段"生成模块核心文档"步骤(可选,首次全量生成,需用户确认)
|
|
583
|
+
- archive 阶段 `sync-module-docs` 步骤(首次受影响时创建,后续更新)
|
|
582
584
|
|
|
583
585
|
**大体结构:**
|
|
584
586
|
```markdown
|
|
@@ -627,7 +629,8 @@ modules:
|
|
|
627
629
|
- 更新头部元数据:`> 最后更新:YYYY-MM-DD` 和 `> 最近变更:<change-name>`
|
|
628
630
|
|
|
629
631
|
**更新时机:**
|
|
630
|
-
-
|
|
632
|
+
- scan 阶段"生成模块核心文档"步骤(首次全量生成,需用户确认)
|
|
633
|
+
- archive 阶段 `sync-module-docs` 步骤(通过 module-impact.md 驱动增量更新)
|
|
631
634
|
- quick 阶段"暂存和更新记录"步骤(直接匹配 git diff 文件到模块,同步更新)
|
|
632
635
|
|
|
633
636
|
**消费方:** brainstorm/propose/plan/execute 阶段"加载上下文"时读取,作为开发参考
|
|
@@ -1034,6 +1037,7 @@ graph LR
|
|
|
1034
1037
|
| `AGENTS.md` 等 | 选了 codex/gemini/opencode 工具 | init | AI 工具读取 |
|
|
1035
1038
|
| `projects/*.yaml` | init 自动创建 | init | 子项目上下文加载 |
|
|
1036
1039
|
| `modules/_module-map.yaml` | scan 可选步骤 | scan | archive/plan/execute |
|
|
1040
|
+
| `modules/<module>.md` | scan 可选步骤(全量生成)+ archive sync-module-docs | scan/archive | propose/plan/execute/verify/quick |
|
|
1037
1041
|
| `verify-result.md` | verify 阶段输出 | verify | 验证报告存档 |
|
|
1038
1042
|
|
|
1039
1043
|
|
|
@@ -1047,7 +1051,7 @@ sillyspec init
|
|
|
1047
1051
|
├─→ .sillyspec/knowledge/
|
|
1048
1052
|
└─→ .gitignore (追加 .sillyspec/.runtime/)
|
|
1049
1053
|
|
|
1050
|
-
scan
|
|
1054
|
+
scan 阶段(12 步,完成后重置)
|
|
1051
1055
|
│
|
|
1052
1056
|
├─→ docs/<name>/scan/ARCHITECTURE.md
|
|
1053
1057
|
├─→ docs/<name>/scan/CONVENTIONS.md
|
|
@@ -1057,6 +1061,7 @@ scan 阶段
|
|
|
1057
1061
|
├─→ docs/<name>/scan/CONCERNS.md
|
|
1058
1062
|
├─→ docs/<name>/scan/PROJECT.md
|
|
1059
1063
|
├─→ docs/<name>/modules/_module-map.yaml (可选)
|
|
1064
|
+
├─→ docs/<name>/modules/<module>.md (可选,需用户确认)
|
|
1060
1065
|
└─→ .sillyspec/local.yaml
|
|
1061
1066
|
|
|
1062
1067
|
brainstorm 阶段
|
|
@@ -1093,13 +1098,15 @@ verify 阶段
|
|
|
1093
1098
|
│
|
|
1094
1099
|
└─→ changes/<name>/verify-result.md
|
|
1095
1100
|
|
|
1096
|
-
quick
|
|
1101
|
+
quick 阶段(辅助阶段,不走完整流程,完成后重置)
|
|
1097
1102
|
│
|
|
1098
1103
|
├─→ .sillyspec/quicklog/QUICKLOG-<user>.md (无 --change 时)
|
|
1099
1104
|
├─→ .sillyspec/.runtime/worktrees/<name>/meta.json
|
|
1100
1105
|
├─→ .sillyspec/.runtime/gate-status.json
|
|
1101
1106
|
└─→ docs/<name>/modules/<module>.md (直接同步,不经过 module-impact.md)
|
|
1102
1107
|
|
|
1108
|
+
> quick 阶段"理解任务"步骤会加载模块文档作为上下文参考。
|
|
1109
|
+
|
|
1103
1110
|
archive 阶段
|
|
1104
1111
|
│
|
|
1105
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'
|
|
@@ -146,10 +146,10 @@ async function ensureStageSteps(progress, stageName, cwd) {
|
|
|
146
146
|
/**
|
|
147
147
|
* 输出当前步骤的 prompt
|
|
148
148
|
*/
|
|
149
|
-
function outputStep(stageName, stepIndex, steps, cwd, changeName) {
|
|
149
|
+
async function outputStep(stageName, stepIndex, steps, cwd, changeName, dbProjectName) {
|
|
150
150
|
const step = steps[stepIndex]
|
|
151
151
|
const total = steps.length
|
|
152
|
-
const projectName = basename(cwd)
|
|
152
|
+
const projectName = dbProjectName || basename(cwd)
|
|
153
153
|
|
|
154
154
|
const personas = {
|
|
155
155
|
brainstorm: `### 🎯 你的角色:资深架构师
|
|
@@ -190,7 +190,12 @@ function outputStep(stageName, stepIndex, steps, cwd, changeName) {
|
|
|
190
190
|
console.log(guardrails.trim())
|
|
191
191
|
console.log('')
|
|
192
192
|
}
|
|
193
|
-
|
|
193
|
+
let promptText = step.prompt
|
|
194
|
+
// 替换 prompt 中的占位符
|
|
195
|
+
if (projectName && promptText.includes('<project>')) {
|
|
196
|
+
promptText = promptText.replace(/<project>/g, projectName)
|
|
197
|
+
}
|
|
198
|
+
console.log(promptText)
|
|
194
199
|
console.log(`\n### ⚠️ 铁律`)
|
|
195
200
|
console.log('- **文档是核心资产,代码是文档的产物。** 没有文档就没有代码——文档是 AI 的记忆,是团队协作的基础,是后续维护的唯一依据。任何代码产出必须先有对应的设计/规范文档支撑。')
|
|
196
201
|
console.log('- 只做本步骤描述的操作,不得自行扩展或跳过')
|
|
@@ -268,9 +273,14 @@ export async function runCommand(args, cwd) {
|
|
|
268
273
|
if (autoChange) {
|
|
269
274
|
progress = await pm.initChange(cwd, autoChange)
|
|
270
275
|
} else if (isAuxiliary) {
|
|
271
|
-
// 辅助阶段(scan/explore/quick/doctor/status
|
|
272
|
-
|
|
273
|
-
|
|
276
|
+
// 辅助阶段(scan/explore/quick/doctor/status)自动使用默认变更名
|
|
277
|
+
const autoName = changeName || resolveChangeNameAuto(cwd) || 'default'
|
|
278
|
+
changeName = autoName
|
|
279
|
+
progress = await pm.initChange(cwd, autoName)
|
|
280
|
+
// initChange 可能因 project 表为空返回 null
|
|
281
|
+
if (!progress) {
|
|
282
|
+
progress = { currentStage: stageName, stages: {}, lastActive: new Date().toLocaleString('zh-CN', { hour12: false }), project: '' }
|
|
283
|
+
}
|
|
274
284
|
} else {
|
|
275
285
|
// brainstorm / propose 作为流程入口,自动生成变更名并初始化
|
|
276
286
|
if (stageName === 'brainstorm' || stageName === 'propose') {
|
|
@@ -281,7 +291,7 @@ export async function runCommand(args, cwd) {
|
|
|
281
291
|
progress = await pm.initChange(cwd, autoName)
|
|
282
292
|
changeName = autoName
|
|
283
293
|
} else {
|
|
284
|
-
console.error('❌
|
|
294
|
+
console.error('❌ 未找到进度数据,请先运行 sillyspec init 或指定 --change <变更名>')
|
|
285
295
|
process.exit(1)
|
|
286
296
|
}
|
|
287
297
|
}
|
|
@@ -409,7 +419,7 @@ async function runStage(pm, progress, stageName, cwd, changeName, skipApproval =
|
|
|
409
419
|
|
|
410
420
|
const defSteps = await getStageSteps(stageName, cwd, progress)
|
|
411
421
|
if (defSteps && defSteps[currentIdx]) {
|
|
412
|
-
outputStep(stageName, currentIdx, defSteps, cwd, changeName)
|
|
422
|
+
await outputStep(stageName, currentIdx, defSteps, cwd, changeName, progress.project || null)
|
|
413
423
|
}
|
|
414
424
|
}
|
|
415
425
|
|
|
@@ -654,7 +664,7 @@ async function completeStep(pm, progress, stageName, cwd, outputText, inputText
|
|
|
654
664
|
const defSteps = await getStageSteps(stageName, cwd, progress)
|
|
655
665
|
console.log(`✅ Step ${currentIdx + 1}/${steps.length} 完成:${steps[currentIdx].name}\n`)
|
|
656
666
|
if (printNext) {
|
|
657
|
-
outputStep(stageName, nextPendingIdx, defSteps, cwd, changeName)
|
|
667
|
+
await outputStep(stageName, nextPendingIdx, defSteps, cwd, changeName, progress.project || null)
|
|
658
668
|
}
|
|
659
669
|
return { stageCompleted: false, currentIdx, nextPendingIdx }
|
|
660
670
|
}
|
|
@@ -692,7 +702,7 @@ async function skipStep(pm, progress, stageName, cwd, changeName) {
|
|
|
692
702
|
const nextPendingIdx = steps.findIndex(s => s.status === 'pending')
|
|
693
703
|
if (nextPendingIdx !== -1 && defSteps) {
|
|
694
704
|
console.log('')
|
|
695
|
-
outputStep(stageName, nextPendingIdx, defSteps, cwd, changeName)
|
|
705
|
+
await outputStep(stageName, nextPendingIdx, defSteps, cwd, changeName, progress.project || null)
|
|
696
706
|
}
|
|
697
707
|
}
|
|
698
708
|
|
|
@@ -837,7 +847,7 @@ async function runAutoMode(pm, progress, cwd, flags, changeName) {
|
|
|
837
847
|
}
|
|
838
848
|
}
|
|
839
849
|
}
|
|
840
|
-
outputStep(currentStage, pendingIdx, defSteps, cwd, changeName)
|
|
850
|
+
await outputStep(currentStage, pendingIdx, defSteps, cwd, changeName, progress.project || null)
|
|
841
851
|
return
|
|
842
852
|
}
|
|
843
853
|
|
|
@@ -867,7 +877,7 @@ async function runAutoMode(pm, progress, cwd, flags, changeName) {
|
|
|
867
877
|
}
|
|
868
878
|
}
|
|
869
879
|
}
|
|
870
|
-
outputStep(currentStage, nextPendingIdx, defSteps, cwd, changeName)
|
|
880
|
+
await outputStep(currentStage, nextPendingIdx, defSteps, cwd, changeName, progress.project || null)
|
|
871
881
|
return
|
|
872
882
|
}
|
|
873
883
|
|
|
@@ -909,6 +919,6 @@ async function runAutoMode(pm, progress, cwd, flags, changeName) {
|
|
|
909
919
|
}
|
|
910
920
|
}
|
|
911
921
|
}
|
|
912
|
-
outputStep(next, firstPending, nextSteps, cwd, changeName)
|
|
922
|
+
await outputStep(next, firstPending, nextSteps, cwd, changeName, progress.project || null)
|
|
913
923
|
}
|
|
914
924
|
}
|
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
|
扫描完整性报告
|