sillyspec 3.5.0 → 3.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sillyspec",
3
- "version": "3.5.0",
3
+ "version": "3.5.2",
4
4
  "description": "SillySpec CLI — 流程状态机,让 AI 严格按步骤来",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  import { existsSync, readdirSync, readFileSync, statSync } from 'fs';
11
11
  import { join, resolve } from 'path';
12
- import { cmdInit } from './init.js';
12
+ import { cmdInit, getVersion } from './init.js';
13
13
 
14
14
  const SILLYSPEC_DIR = '.sillyspec';
15
15
  const CODEBASE_DIR = `${SILLYSPEC_DIR}/codebase`;
@@ -501,6 +501,11 @@ SillySpec CLI — 流程状态机
501
501
  async function main() {
502
502
  const args = process.argv.slice(2);
503
503
 
504
+ if (args[0] === '--version' || args[0] === '-v') {
505
+ console.log(getVersion());
506
+ process.exit(0);
507
+ }
508
+
504
509
  if (args.length === 0 || args[0] === 'help' || args[0] === '--help' || args[0] === '-h') {
505
510
  printUsage();
506
511
  process.exit(0);
package/src/init.js CHANGED
@@ -91,33 +91,35 @@ const INJECTION_CONTENT = `## SillySpec — 规范驱动开发
91
91
 
92
92
  // ── 适配器 ──
93
93
 
94
- function generateClaude(projectDir, name, desc, body, argHint) {
94
+ function generateClaude(projectDir, name, desc, body, argHint, version) {
95
95
  const outDir = join(projectDir, '.claude', 'commands', 'sillyspec');
96
96
  mkdirSync(outDir, { recursive: true });
97
97
  writeFileSync(join(outDir, `${name}.md`),
98
98
  `---
99
99
  description: ${desc}
100
100
  argument-hint: "${argHint}"
101
+ version: "${version}"
101
102
  ---
102
103
 
103
104
  ${body}`
104
105
  );
105
106
  }
106
107
 
107
- function generateClaudeSkills(projectDir, name, desc, body, argHint) {
108
+ function generateClaudeSkills(projectDir, name, desc, body, argHint, version) {
108
109
  const outDir = join(projectDir, '.claude', 'skills', `sillyspec-${name}`);
109
110
  mkdirSync(outDir, { recursive: true });
110
111
  writeFileSync(join(outDir, 'SKILL.md'),
111
112
  `---
112
113
  name: sillyspec:${name}
113
114
  description: ${desc}
115
+ version: "${version}"
114
116
  ---
115
117
 
116
118
  ${body}`
117
119
  );
118
120
  }
119
121
 
120
- function generateCursor(projectDir, name, desc, body, argHint) {
122
+ function generateCursor(projectDir, name, desc, body, argHint, version) {
121
123
  const outDir = join(projectDir, '.cursor', 'commands');
122
124
  mkdirSync(outDir, { recursive: true });
123
125
  writeFileSync(join(outDir, `sillyspec-${name}.md`),
@@ -125,19 +127,21 @@ function generateCursor(projectDir, name, desc, body, argHint) {
125
127
  name: /sillyspec-${name}
126
128
  id: sillyspec-${name}
127
129
  description: ${desc}
130
+ version: "${version}"
128
131
  ---
129
132
 
130
133
  ${body}`
131
134
  );
132
135
  }
133
136
 
134
- function generateOpenclaw(projectDir, name, desc, body, argHint) {
137
+ function generateOpenclaw(projectDir, name, desc, body, argHint, version) {
135
138
  const outDir = join(projectDir, '.openclaw', 'skills', `sillyspec-${name}`);
136
139
  mkdirSync(outDir, { recursive: true });
137
140
  writeFileSync(join(outDir, 'SKILL.md'),
138
141
  `---
139
142
  name: sillyspec:${name}
140
143
  description: ${desc}
144
+ version: "${version}"
141
145
  ---
142
146
 
143
147
  ${body}`
@@ -259,12 +263,13 @@ async function doInstall(projectDir, tools, isWorkspace, subprojects = []) {
259
263
  const spinner = ora(`安装 ${label}... (${i + 1}/${tools.length})`).start();
260
264
  try {
261
265
  const gen = GENERATORS[toolName];
266
+ const ver = getVersion();
262
267
  for (const file of templateFiles) {
263
268
  const name = file.replace('.md', '');
264
269
  const desc = DESCRIPTIONS[name] || `SillySpec ${name}`;
265
270
  const argHint = ARG_HINTS[name] || '';
266
271
  const body = readFileSync(join(TEMPLATE_DIR, file), 'utf8');
267
- gen(projectDir, name, desc, body, argHint);
272
+ gen(projectDir, name, desc, body, argHint, ver);
268
273
  count++;
269
274
  }
270
275
  spinner.succeed(`${label} 完成`);
@@ -329,7 +334,7 @@ function showSummary(version, tools, isWorkspace, count) {
329
334
 
330
335
  // ── 读取版本号 ──
331
336
 
332
- function getVersion() {
337
+ export function getVersion() {
333
338
  try {
334
339
  const pkg = JSON.parse(readFileSync(resolve(__dirname, '..', 'package.json'), 'utf8'));
335
340
  return pkg.version;
@@ -45,6 +45,13 @@ cat .sillyspec/codebase/{CONVENTIONS,ARCHITECTURE}.md 2>/dev/null
45
45
  cat .sillyspec/local.yaml 2>/dev/null
46
46
  ```
47
47
 
48
+ **知识库查询(强制步骤):**
49
+ 主代理在 dispatch 每个子代理前,必须执行:
50
+ ```bash
51
+ cat .sillyspec/knowledge/INDEX.md 2>/dev/null
52
+ ```
53
+ 根据当前 task 描述中的关键词(技术名词、模块名、文件路径等)匹配 INDEX.md 条目。命中时读取对应 knowledge 文件,将内容注入子代理 prompt 的「相关知识」段。未命中则跳过,不注入空段。
54
+
48
55
  如果 `$ARGUMENTS` 指定范围(如 `wave-1`、`task-3`),只执行对应部分。
49
56
 
50
57
  ---
@@ -91,6 +98,9 @@ cat .sillyspec/local.yaml 2>/dev/null
91
98
  ## 工作目录
92
99
  {子项目目录路径,工作区模式需要 cd 到此目录}
93
100
 
101
+ ## 相关知识(如有)
102
+ {主代理从 knowledge/ 中按任务关键词匹配到的内容,未命中则删除此段}
103
+
94
104
  ## 铁律(必须遵守)
95
105
  1. **先读后写:** 先 cat 要修改的文件和参考文件,确认风格和方法签名后再写
96
106
  2. **grep 确认:** 调用已有方法前必须 grep 确认存在,grep 不到 → 报告 BLOCKED
@@ -108,6 +118,7 @@ cat .sillyspec/local.yaml 2>/dev/null
108
118
  - **测试结果:** {通过/失败/跳过及原因}
109
119
  - **Commit:** {hash 或 "无"}
110
120
  - **问题:** {BLOCKED 原因 / DONE_WITH_CONCERNS 描述 / 无}
121
+ - **发现的坑:** {执行过程中发现的项目特有规律/陷阱/约定,如无则写"无"。示例:"XxxMapper.selectPage() 第一个参数必须是 IPage 对象,传 null 会 NPE 而非返回全部"}
111
122
  ```
112
123
 
113
124
  ### 子代理结果处理
@@ -121,10 +132,26 @@ cat .sillyspec/local.yaml 2>/dev/null
121
132
  - 跳过(勾选并标注 SKIPPED)
122
133
  - 停止(暂停执行,用户处理后继续)
123
134
 
135
+ **知识库写入:** 如果子代理报告中「发现的坑」不为"无",主代理将内容追加到 `.sillyspec/knowledge/uncategorized.md`,格式:
136
+ ```markdown
137
+ ### [待确认] {简短标题}
138
+ > 来源:{变更名} / {task 编号} | {时间戳}
139
+
140
+ {坑的具体描述}
141
+ ```
142
+
124
143
  ---
125
144
 
126
145
  ## 完成后
127
146
 
147
+ **知识库审阅:** 检查是否有待确认的知识条目:
148
+ ```bash
149
+ grep -c '^\### \[待确认\]' .sillyspec/knowledge/uncategorized.md 2>/dev/null
150
+ ```
151
+ 如果有待确认条目,提示用户:
152
+ > 📚 本轮执行发现了 N 条新知识,请审阅:`cat .sillyspec/knowledge/uncategorized.md`
153
+ > 确认后请将 `[待确认]` 改为 `[已确认]`,并可归类到 knowledge/ 下的专题文件中更新 INDEX.md。
154
+
128
155
  所有任务完成后,用 AskUserQuestion 询问用户下一步:
129
156
  1. **验证** — 执行 `/sillyspec:verify` 全面验证
130
157
  2. **归档** — 跳过 verify,执行 `/sillyspec:archive`
@@ -21,8 +21,13 @@ $ARGUMENTS
21
21
  1. **解析参数:** 检查是否携带 `--change <变更名>`,确定记录方式
22
22
  2. **理解任务:** 模糊则问一个问题确认
23
23
  3. **加载上下文:** `cat .sillyspec/codebase/{CONVENTIONS,ARCHITECTURE}.md 2>/dev/null`
24
- 4. **先读后写:** 调用已有方法前 `cat` 源文件确认签名,`grep` 确认方法存在
25
- 5. **TDD 执行:**
24
+ 4. **知识库查询(强制步骤):**
25
+ ```bash
26
+ cat .sillyspec/knowledge/INDEX.md 2>/dev/null
27
+ ```
28
+ 根据当前任务描述中的关键词匹配 INDEX.md 条目,命中时 `cat` 对应知识文件,将内容纳入后续开发考量。未命中则跳过。
29
+ 5. **先读后写:** 调用已有方法前 `cat` 源文件确认签名,`grep` 确认方法存在
30
+ 6. **TDD 执行:**
26
31
  ```
27
32
  🔴 RED → 先写测试,运行确认失败
28
33
  🟢 GREEN → 写最少代码让测试通过
@@ -32,7 +37,7 @@ $ARGUMENTS
32
37
  测试文件必须保留在项目中,不能删除。违反 TDD → 删掉代码从测试重新开始。
33
38
  - 纯配置/数据/文档可跳过 TDD
34
39
  - 其他情况一律走 TDD
35
- 6. **运行测试:** 先检查 local.yaml 构建命令配置:
40
+ 7. **运行测试:** 先检查 local.yaml 构建命令配置:
36
41
  ```bash
37
42
  cat .sillyspec/local.yaml 2>/dev/null
38
43
  ```
@@ -40,17 +45,30 @@ cat .sillyspec/local.yaml 2>/dev/null
40
45
  ```bash
41
46
  mvn test -pl <模块> -Dtest=<测试类> 2>/dev/null || ./gradlew test --tests <测试类> 2>/dev/null || pnpm test 2>/dev/null || npm test 2>/dev/null || pytest <测试文件> 2>/dev/null
42
47
  ```
43
- 7. **Git commit:** 展示 commit message 给用户确认后提交。**工作区模式下,确认当前在正确的子项目目录中执行 commit。**
44
- 8. **记录:**
48
+ 8. **Git commit:** 展示 commit message 给用户确认后提交。**工作区模式下,确认当前在正确的子项目目录中执行 commit。**
49
+ 9. **记录:**
45
50
  - **有 `--change`:** 在 `.sillyspec/changes/<变更名>/tasks.md` 追加 task 并勾选,**记录精确到秒的时间戳**:
46
51
 
47
52
  ```
48
53
  - [x] [YYYY-MM-DD HH:MM:SS] 任务描述
49
54
  ```
50
55
  - **无 `--change`:** 记录到 `.sillyspec/quicklog/QUICKLOG-<git用户名>.md`(见下方规则)
51
- 9. **检查复杂度:** 任务比预期复杂 → 建议用完整流程
56
+ 10. **检查复杂度:** 任务比预期复杂 → 建议用完整流程
57
+
58
+ 11. **记录发现的坑:** 执行过程中如果发现项目特有的规律、陷阱或约定(如"某方法参数顺序容易搞反"、"某表有隐藏软删除字段"),追加到 `.sillyspec/knowledge/uncategorized.md`,格式:
59
+
60
+ ```markdown
61
+ ### [待确认] {简短标题}
62
+ > 来源:quick / {时间戳}
63
+
64
+ {坑的具体描述}
65
+ ```
66
+
67
+ **工作区模式下:** 只影响当前子项目 → 写入当前子项目 `.sillyspec/knowledge/uncategorized.md`;影响多个子项目 → 写入工作区根目录 `.sillyspec/knowledge/uncategorized.md`。
52
68
 
53
- 10. **记录发现的坑:** 执行过程中如果发现项目特有的规律、陷阱或约定(如"某方法参数顺序容易搞反"、"某表有隐藏软删除字段"),追加到 CONVENTIONS.md 的「注意事项」章节。**工作区模式下:** 只影响当前子项目 → 写入当前子项目 `.sillyspec/codebase/CONVENTIONS.md`;影响多个子项目 → 写入 `.sillyspec/shared/CONVENTIONS.md`(共享规范,所有子项目可见)。
69
+ 12. **知识库审阅提示:** 如果本次执行向 knowledge/ 写入了新条目,提示用户:
70
+ > 📚 本次 quick 发现了新知识,请审阅:`cat .sillyspec/knowledge/uncategorized.md`
71
+ > 确认后请将 `[待确认]` 改为 `[已确认]`,并可归类到 knowledge/ 下的专题文件中更新 INDEX.md。
54
72
 
55
73
  ### QUICKLOG 规则
56
74
 
package/templates/scan.md CHANGED
@@ -112,6 +112,29 @@ for f in ARCHITECTURE STRUCTURE CONVENTIONS INTEGRATIONS TESTING CONCERNS PROJEC
112
112
  [ -f ".sillyspec/codebase/${f}.md" ] && echo "✅ ${f}.md"
113
113
  done
114
114
 
115
+ # 生成知识库骨架
116
+ mkdir -p .sillyspec/knowledge
117
+ if [ ! -f ".sillyspec/knowledge/INDEX.md" ]; then
118
+ cat > .sillyspec/knowledge/INDEX.md << 'EOF'
119
+ # Knowledge Index
120
+
121
+ > 子代理任务开始前查询此文件,按关键词匹配,只读命中的知识文件。
122
+ > execute/quick 执行中发现的坑自动追加到 uncategorized.md,经用户确认后归类到对应文件。
123
+
124
+ <!-- 格式:关键词1|关键词2|关键词3 → 文件路径 -->
125
+ <!-- 示例:mybatis-plus|分页|Page → pagination.md -->
126
+ <!-- 示例:跨域|CORS|preflight → cors.md -->
127
+ EOF
128
+ fi
129
+ if [ ! -f ".sillyspec/knowledge/uncategorized.md" ]; then
130
+ cat > .sillyspec/knowledge/uncategorized.md << 'EOF'
131
+ # 未分类知识
132
+
133
+ > execute/quick 执行中发现的坑暂存于此,用户审阅后归类到对应文件并更新 INDEX.md。
134
+
135
+ EOF
136
+ fi
137
+
115
138
  # 验证 CLI
116
139
  sillyspec status --json # 应返回 phase: "brainstorm"
117
140
  sillyspec next # 推荐给用户