sillyspec 3.8.7 → 3.9.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.
Files changed (163) hide show
  1. package/.claude/skills/sillyspec-archive/SKILL.md +17 -0
  2. package/.claude/skills/sillyspec-auto/SKILL.md +78 -0
  3. package/.claude/skills/sillyspec-brainstorm/SKILL.md +17 -0
  4. package/{templates/commit.md → .claude/skills/sillyspec-commit/SKILL.md} +32 -47
  5. package/.claude/skills/sillyspec-continue/SKILL.md +45 -0
  6. package/.claude/skills/sillyspec-doctor/SKILL.md +27 -0
  7. package/.claude/skills/sillyspec-execute/SKILL.md +17 -0
  8. package/.claude/skills/sillyspec-explore/SKILL.md +96 -0
  9. package/.claude/skills/sillyspec-export/SKILL.md +53 -0
  10. package/.claude/skills/sillyspec-init/SKILL.md +170 -0
  11. package/.claude/skills/sillyspec-plan/SKILL.md +52 -0
  12. package/.claude/skills/sillyspec-propose/SKILL.md +17 -0
  13. package/.claude/skills/sillyspec-quick/SKILL.md +17 -0
  14. package/.claude/skills/sillyspec-resume/SKILL.md +111 -0
  15. package/.claude/skills/sillyspec-scan/SKILL.md +17 -0
  16. package/.claude/skills/sillyspec-state/SKILL.md +54 -0
  17. package/.claude/skills/sillyspec-status/SKILL.md +17 -0
  18. package/.claude/skills/sillyspec-verify/SKILL.md +17 -0
  19. package/.claude/skills/sillyspec-workspace/SKILL.md +149 -0
  20. package/.sillyspec/changes/archive/2026-04-08-derive-state/design.md +97 -0
  21. package/.sillyspec/changes/archive/2026-04-08-derive-state/plan.md +51 -0
  22. package/.sillyspec/changes/archive/2026-04-08-derive-state/proposal.md +29 -0
  23. package/.sillyspec/changes/archive/2026-04-08-derive-state/requirements.md +34 -0
  24. package/.sillyspec/changes/archive/2026-04-08-derive-state/tasks.md +13 -0
  25. package/.sillyspec/changes/archive/2026-04-08-derive-state/verify-result.md +43 -0
  26. package/.sillyspec/changes/auto-mode/design.md +50 -0
  27. package/.sillyspec/changes/auto-mode/proposal.md +19 -0
  28. package/.sillyspec/changes/auto-mode/requirements.md +21 -0
  29. package/.sillyspec/changes/auto-mode/tasks.md +7 -0
  30. package/.sillyspec/changes/brainstorm-archive/2026-04-05-unified-docs-design.md +199 -0
  31. package/.sillyspec/changes/dashboard/design.md.braindraft +206 -0
  32. package/.sillyspec/changes/run-command-design/design.md +1230 -0
  33. package/.sillyspec/changes/unified-docs-design/design.md +199 -0
  34. package/.sillyspec/docs/sillyspec/scan/.gitkeep +0 -0
  35. package/.sillyspec/knowledge/INDEX.md +8 -0
  36. package/.sillyspec/knowledge/uncategorized.md +3 -0
  37. package/.sillyspec/projects/sillyspec.yaml +3 -0
  38. package/README.md +12 -5
  39. package/package.json +9 -11
  40. package/packages/dashboard/dist/assets/index-CntACGUN.css +1 -0
  41. package/packages/dashboard/dist/assets/index-RsLVPAy7.js +7446 -0
  42. package/packages/dashboard/dist/index.html +3 -2
  43. package/packages/dashboard/package-lock.json +226 -6
  44. package/packages/dashboard/package.json +8 -5
  45. package/packages/dashboard/public/logo.jpg +0 -0
  46. package/packages/dashboard/server/executor.js +1 -1
  47. package/packages/dashboard/server/index.js +336 -113
  48. package/packages/dashboard/server/parser.js +333 -29
  49. package/packages/dashboard/server/watcher.js +203 -131
  50. package/packages/dashboard/src/App.vue +187 -11
  51. package/packages/dashboard/src/components/ActionBar.vue +26 -42
  52. package/packages/dashboard/src/components/CommandPalette.vue +40 -65
  53. package/packages/dashboard/src/components/DetailPanel.vue +68 -53
  54. package/packages/dashboard/src/components/DocPreview.vue +160 -0
  55. package/packages/dashboard/src/components/DocTree.vue +58 -0
  56. package/packages/dashboard/src/components/LogStream.vue +13 -33
  57. package/packages/dashboard/src/components/PipelineStage.vue +8 -8
  58. package/packages/dashboard/src/components/PipelineView.vue +80 -45
  59. package/packages/dashboard/src/components/ProjectList.vue +103 -45
  60. package/packages/dashboard/src/components/ProjectOverview.vue +178 -0
  61. package/packages/dashboard/src/components/StageBadge.vue +13 -13
  62. package/packages/dashboard/src/components/StepCard.vue +15 -15
  63. package/packages/dashboard/src/components/detail/DocsDetail.vue +48 -0
  64. package/packages/dashboard/src/components/detail/GitDetail.vue +61 -0
  65. package/packages/dashboard/src/components/detail/TechDetail.vue +43 -0
  66. package/packages/dashboard/src/composables/useDashboard.js +20 -6
  67. package/packages/dashboard/src/composables/useKeyboard.js +6 -4
  68. package/packages/dashboard/src/main.js +4 -1
  69. package/packages/dashboard/src/style.css +17 -17
  70. package/src/index.js +136 -14
  71. package/src/init.js +83 -228
  72. package/src/migrate.js +117 -0
  73. package/src/progress.js +459 -0
  74. package/src/run.js +624 -0
  75. package/src/setup.js +2 -72
  76. package/src/stages/archive.js +54 -0
  77. package/src/stages/brainstorm.js +239 -0
  78. package/src/stages/doctor.js +303 -0
  79. package/src/stages/execute.js +262 -0
  80. package/src/stages/index.js +26 -0
  81. package/src/stages/plan.js +282 -0
  82. package/src/stages/propose.js +115 -0
  83. package/src/stages/quick.js +64 -0
  84. package/src/stages/scan.js +141 -0
  85. package/src/stages/status.js +65 -0
  86. package/src/stages/verify.js +135 -0
  87. package/docs/.vitepress/config.mts +0 -45
  88. package/docs/.vitepress/dist/404.html +0 -25
  89. package/docs/.vitepress/dist/assets/app.YytxICdd.js +0 -1
  90. package/docs/.vitepress/dist/assets/chunks/framework.Czhw_PXq.js +0 -19
  91. package/docs/.vitepress/dist/assets/chunks/theme.DusTRZQk.js +0 -1
  92. package/docs/.vitepress/dist/assets/index.md.C3VCvtQA.js +0 -1
  93. package/docs/.vitepress/dist/assets/index.md.C3VCvtQA.lean.js +0 -1
  94. package/docs/.vitepress/dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  95. package/docs/.vitepress/dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  96. package/docs/.vitepress/dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  97. package/docs/.vitepress/dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  98. package/docs/.vitepress/dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  99. package/docs/.vitepress/dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  100. package/docs/.vitepress/dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  101. package/docs/.vitepress/dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  102. package/docs/.vitepress/dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  103. package/docs/.vitepress/dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  104. package/docs/.vitepress/dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  105. package/docs/.vitepress/dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  106. package/docs/.vitepress/dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  107. package/docs/.vitepress/dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  108. package/docs/.vitepress/dist/assets/sillyspec_commands.md.CXFFsj08.js +0 -15
  109. package/docs/.vitepress/dist/assets/sillyspec_commands.md.CXFFsj08.lean.js +0 -1
  110. package/docs/.vitepress/dist/assets/sillyspec_dashboard.md.BuPXHqjX.js +0 -4
  111. package/docs/.vitepress/dist/assets/sillyspec_dashboard.md.BuPXHqjX.lean.js +0 -1
  112. package/docs/.vitepress/dist/assets/sillyspec_file-io.md.Cz3x7llx.js +0 -1
  113. package/docs/.vitepress/dist/assets/sillyspec_file-io.md.Cz3x7llx.lean.js +0 -1
  114. package/docs/.vitepress/dist/assets/sillyspec_getting-started.md.ClcvV8k3.js +0 -4
  115. package/docs/.vitepress/dist/assets/sillyspec_getting-started.md.ClcvV8k3.lean.js +0 -1
  116. package/docs/.vitepress/dist/assets/sillyspec_install.md.CKuR2tiT.js +0 -5
  117. package/docs/.vitepress/dist/assets/sillyspec_install.md.CKuR2tiT.lean.js +0 -1
  118. package/docs/.vitepress/dist/assets/sillyspec_lifecycle.md.DY293cR1.js +0 -28
  119. package/docs/.vitepress/dist/assets/sillyspec_lifecycle.md.DY293cR1.lean.js +0 -1
  120. package/docs/.vitepress/dist/assets/sillyspec_structure.md.sVYS4zPs.js +0 -30
  121. package/docs/.vitepress/dist/assets/sillyspec_structure.md.sVYS4zPs.lean.js +0 -1
  122. package/docs/.vitepress/dist/assets/style.DFTx90Kk.css +0 -1
  123. package/docs/.vitepress/dist/hashmap.json +0 -1
  124. package/docs/.vitepress/dist/index.html +0 -28
  125. package/docs/.vitepress/dist/sillyspec/commands.html +0 -42
  126. package/docs/.vitepress/dist/sillyspec/dashboard.html +0 -31
  127. package/docs/.vitepress/dist/sillyspec/file-io.html +0 -28
  128. package/docs/.vitepress/dist/sillyspec/getting-started.html +0 -31
  129. package/docs/.vitepress/dist/sillyspec/install.html +0 -32
  130. package/docs/.vitepress/dist/sillyspec/lifecycle.html +0 -55
  131. package/docs/.vitepress/dist/sillyspec/structure.html +0 -57
  132. package/docs/.vitepress/dist/vp-icons.css +0 -1
  133. package/docs/index.md +0 -34
  134. package/docs/sillyspec/commands.md +0 -218
  135. package/docs/sillyspec/dashboard.md +0 -51
  136. package/docs/sillyspec/file-io.md +0 -34
  137. package/docs/sillyspec/getting-started.md +0 -61
  138. package/docs/sillyspec/install.md +0 -51
  139. package/docs/sillyspec/lifecycle.md +0 -146
  140. package/docs/sillyspec/structure.md +0 -62
  141. package/packages/dashboard/dist/assets/index-Bh-GPjKY.css +0 -1
  142. package/packages/dashboard/dist/assets/index-CrCn5Gg6.js +0 -17
  143. package/templates/archive.md +0 -120
  144. package/templates/brainstorm.md +0 -170
  145. package/templates/continue.md +0 -32
  146. package/templates/execute.md +0 -304
  147. package/templates/explore.md +0 -59
  148. package/templates/export.md +0 -21
  149. package/templates/init.md +0 -61
  150. package/templates/plan.md +0 -146
  151. package/templates/quick.md +0 -135
  152. package/templates/scan-quick.md +0 -49
  153. package/templates/scan.md +0 -156
  154. package/templates/skills/playwright-e2e/SKILL.md +0 -340
  155. package/templates/status.md +0 -75
  156. package/templates/verify.md +0 -236
  157. package/templates/workspace-sync.md +0 -99
  158. package/templates/workspace.md +0 -70
  159. /package/.sillyspec/{specs → changes/brainstorm-archive}/2026-04-05-dashboard-design.md +0 -0
  160. /package/{docs/.vitepress/dist/logo.jpg → logo.jpg} +0 -0
  161. /package/{docs/.vitepress → packages/dashboard}/dist/favicon.jpg +0 -0
  162. /package/{docs/public → packages/dashboard/dist}/logo.jpg +0 -0
  163. /package/{docs → packages/dashboard}/public/favicon.jpg +0 -0
package/src/index.js CHANGED
@@ -4,11 +4,12 @@
4
4
  * SillySpec CLI — 安装工具
5
5
  *
6
6
  * 只负责两件事:init(安装命令模板)和 setup(安装 MCP 工具)。
7
- * 状态管理由 AI 直接读文件(STATE.md)完成,不需要 CLI。
7
+ * 状态管理通过 progress.json 完成,使用 `sillyspec progress` 命令。
8
8
  */
9
- import { existsSync } from 'fs';
10
- import { resolve } from 'path';
9
+ import { existsSync, readdirSync, readFileSync, statSync } from 'fs';
10
+ import { join, resolve } from 'path';
11
11
  import { cmdInit, getVersion } from './init.js';
12
+ import { ProgressManager } from './progress.js';
12
13
 
13
14
  // ── CLI 入口 ──
14
15
 
@@ -19,11 +20,32 @@ SillySpec CLI — 规范驱动开发工具包
19
20
  用法:
20
21
  sillyspec init 初始化(零交互,自动检测工具)
21
22
  [--tool <name>] 只安装指定工具
22
- [--workspace] 工作区模式
23
23
  [--interactive] 交互式引导
24
24
  [--dir <path>] 指定目录
25
+
25
26
  sillyspec setup [--list] 安装推荐 MCP 工具
26
27
  [--list] 查看已安装状态
28
+
29
+ sillyspec run <stage> 执行阶段步骤(核心命令)
30
+ --done --output "..." 完成当前步骤
31
+ --skip 跳过可选步骤
32
+ --status 查看阶段进度
33
+ --reset 重置阶段
34
+ --change <name> 设置当前变更名
35
+ auto 连续推进 brainstorm→plan→execute→verify
36
+
37
+ sillyspec progress <cmd> 进度记录(轻量,不强制顺序)
38
+ init 初始化 progress.json
39
+ show 查看当前进度
40
+ set-stage <stage> 设置当前阶段
41
+ add-step <stage> <name> 添加步骤
42
+ update-step <s> <n> --status <st> [--output <t>]
43
+ complete-stage <stage> 标记阶段完成
44
+ validate 校验并修复
45
+ reset [--stage X] 重置进度
46
+
47
+ sillyspec docs migrate 迁移旧文档到统一结构
48
+
27
49
  sillyspec dashboard 启动 Dashboard Web UI
28
50
  [--port <number>] 指定端口(默认 3456)
29
51
  [--no-open] 不自动打开浏览器
@@ -34,11 +56,9 @@ SillySpec CLI — 规范驱动开发工具包
34
56
 
35
57
  示例:
36
58
  sillyspec init
37
- sillyspec init --tool claude
38
- sillyspec init --workspace
39
- sillyspec setup
59
+ sillyspec run brainstorm
60
+ sillyspec run brainstorm --done --output "需求已澄清"
40
61
  sillyspec setup --list
41
- sillyspec dashboard
42
62
  sillyspec dashboard --port 8080 --no-open
43
63
  `);
44
64
  }
@@ -60,7 +80,6 @@ async function main() {
60
80
  let json = false;
61
81
  let targetDir = process.cwd();
62
82
  let tool = null;
63
- let workspace = false;
64
83
  let interactive = false;
65
84
  const filteredArgs = [];
66
85
 
@@ -73,8 +92,6 @@ async function main() {
73
92
  } else if (args[i] === '--tool' && args[i + 1]) {
74
93
  tool = args[i + 1];
75
94
  i++;
76
- } else if (args[i] === '--workspace' || args[i] === '-w') {
77
- workspace = true;
78
95
  } else if (args[i] === '--interactive' || args[i] === '-i') {
79
96
  interactive = true;
80
97
  } else if (args[i] === '--list' || args[i] === '-l') {
@@ -85,8 +102,18 @@ async function main() {
85
102
  }
86
103
 
87
104
  const command = filteredArgs[0];
105
+ // 支持 sillyspec init /path/to/project 语法:如果第二个参数看起来像路径,当作 targetDir
106
+ if (command === 'init' && filteredArgs[1] && !filteredArgs[1].startsWith('-')) {
107
+ targetDir = resolve(filteredArgs[1]);
108
+ filteredArgs.splice(1, 1);
109
+ }
88
110
  const dir = targetDir;
89
111
 
112
+ if (command === 'init' && !existsSync(dir)) {
113
+ const { mkdirSync } = await import('fs');
114
+ mkdirSync(dir, { recursive: true });
115
+ }
116
+
90
117
  if (!existsSync(dir)) {
91
118
  console.error(`❌ 目录不存在: ${dir}`);
92
119
  process.exit(1);
@@ -94,15 +121,110 @@ async function main() {
94
121
 
95
122
  switch (command) {
96
123
  case 'init':
97
- await cmdInit(dir, { tool, workspace, interactive });
124
+ await cmdInit(dir, { tool, interactive });
98
125
  break;
99
126
  case 'setup':
100
127
  const setupList = filteredArgs.includes('--list') || filteredArgs.includes('-l');
101
128
  await (await import('./setup.js')).cmdSetup(dir, { json, list: setupList });
102
129
  break;
103
- case 'progress':
104
- console.log('⚠️ 阶段控制功能已移除,各阶段独立运行。');
130
+ case 'progress': {
131
+ const pm = new ProgressManager();
132
+ const subCommand = filteredArgs[1];
133
+ const stageIdx = filteredArgs.indexOf('--stage');
134
+ const stage = stageIdx >= 0 && filteredArgs[stageIdx + 1] ? filteredArgs[stageIdx + 1] : null;
135
+
136
+ switch (subCommand) {
137
+ case 'init':
138
+ pm.init(dir);
139
+ break;
140
+ case 'status':
141
+ case 'show':
142
+ pm.show(dir);
143
+ break;
144
+ case 'validate':
145
+ await pm.validate(dir);
146
+ break;
147
+ case 'reset':
148
+ pm.reset(dir, stage);
149
+ break;
150
+ case 'set-stage': {
151
+ const setStageName = filteredArgs[2];
152
+ if (!setStageName) { console.log('❌ 用法: sillyspec progress set-stage <stage>'); break; }
153
+ pm.setStage(dir, setStageName);
154
+ break;
155
+ }
156
+ case 'add-step': {
157
+ const addStepStage = filteredArgs[2];
158
+ const addStepName = filteredArgs[3];
159
+ if (!addStepStage || !addStepName) { console.log('❌ 用法: sillyspec progress add-step <stage> <step-name>'); break; }
160
+ pm.addStep(dir, addStepStage, addStepName);
161
+ break;
162
+ }
163
+ case 'update-step': {
164
+ const updStepStage = filteredArgs[2];
165
+ const updStepName = filteredArgs[3];
166
+ if (!updStepStage || !updStepName) { console.log('❌ 用法: sillyspec progress update-step <stage> <step-name> --status <status> [--output <text>]'); break; }
167
+ // Parse --status and --output from args
168
+ let updStatus = null, updOutput = undefined;
169
+ for (let ai = 0; ai < args.length; ai++) {
170
+ if (args[ai] === '--status' && args[ai + 1]) { updStatus = args[ai + 1]; ai++; }
171
+ if (args[ai] === '--output' && args[ai + 1]) { updOutput = args[ai + 1]; ai++; }
172
+ }
173
+ pm.updateStep(dir, updStepStage, updStepName, { status: updStatus, output: updOutput });
174
+ break;
175
+ }
176
+ case 'complete-stage': {
177
+ const compStageName = filteredArgs[2];
178
+ if (!compStageName) { console.log('❌ 用法: sillyspec progress complete-stage <stage>'); break; }
179
+ pm.completeStage(dir, compStageName);
180
+ break;
181
+ }
182
+ case 'batch': {
183
+ if (filteredArgs.includes('--status')) {
184
+ const bp = pm.readBatchProgress(dir);
185
+ if (!bp) { console.log('📭 无批量进度数据'); break; }
186
+ const line = pm._renderBatchProgress(bp);
187
+ console.log(line || '📭 无批量进度数据');
188
+ console.log(JSON.stringify(bp, null, 2));
189
+ } else {
190
+ let batchData = {};
191
+ const a = args;
192
+ for (let i = 0; i < a.length; i++) {
193
+ if (a[i] === '--total' && a[i + 1]) { batchData.total = parseInt(a[i + 1]); i++; }
194
+ if (a[i] === '--completed' && a[i + 1]) { batchData.completed = parseInt(a[i + 1]); i++; }
195
+ if (a[i] === '--failed' && a[i + 1]) { batchData.failed = parseInt(a[i + 1]); i++; }
196
+ if (a[i] === '--skipped' && a[i + 1]) { batchData.skipped = parseInt(a[i + 1]); i++; }
197
+ }
198
+ if (Object.keys(batchData).length === 0) {
199
+ console.log('用法: sillyspec progress batch --total 100 --completed 73');
200
+ console.log(' sillyspec progress batch --status');
201
+ break;
202
+ }
203
+ pm.updateBatchProgress(dir, batchData);
204
+ console.log('✅ 批量进度已更新');
205
+ }
206
+ break;
207
+ }
208
+ default:
209
+ console.log('用法: sillyspec progress <init|show|validate|reset|set-stage|add-step|update-step|complete-stage>');
210
+ }
211
+ break;
212
+ }
213
+ case 'docs': {
214
+ const docsSubCmd = filteredArgs[1];
215
+ if (docsSubCmd === 'migrate') {
216
+ const { migrateDocs } = await import('./migrate.js');
217
+ migrateDocs(dir);
218
+ } else {
219
+ console.log('用法: sillyspec docs migrate');
220
+ }
105
221
  break;
222
+ }
223
+ case 'run': {
224
+ const { runCommand } = await import('./run.js')
225
+ await runCommand(filteredArgs.slice(1), dir)
226
+ break
227
+ }
106
228
  case 'dashboard': {
107
229
  // Parse dashboard options
108
230
  let port = 3456;
package/src/init.js CHANGED
@@ -1,55 +1,31 @@
1
- import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, copyFileSync } from 'fs';
2
- import { join, resolve, dirname } from 'path';
1
+ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, statSync } from 'fs';
2
+ import { join, resolve, dirname, basename } from 'path';
3
3
  import { fileURLToPath } from 'url';
4
- import { homedir } from 'os';
5
- import { checkbox, select, confirm, input } from '@inquirer/prompts';
4
+ import { checkbox, confirm, input } from '@inquirer/prompts';
5
+ import { ProgressManager } from './progress.js';
6
6
  import chalk from 'chalk';
7
- import ora from 'ora';
8
7
 
9
8
  const __filename = fileURLToPath(import.meta.url);
10
9
  const __dirname = dirname(__filename);
11
- const TEMPLATE_DIR = resolve(__dirname, '..', 'templates');
10
+
11
+ // ── 递归复制目录 ──
12
+ function copyDirSync(src, dst) {
13
+ mkdirSync(dst, { recursive: true });
14
+ for (const entry of readdirSync(src, { withFileTypes: true })) {
15
+ if (entry.name === 'node_modules' || entry.name === '.git') continue;
16
+ const srcPath = join(src, entry.name);
17
+ const dstPath = join(dst, entry.name);
18
+ if (entry.isDirectory()) {
19
+ copyDirSync(srcPath, dstPath);
20
+ } else if (entry.name.endsWith('.md')) {
21
+ writeFileSync(dstPath, readFileSync(srcPath));
22
+ }
23
+ }
24
+ }
12
25
 
13
26
  // ── 元数据映射 ──
14
27
 
15
- const DESCRIPTIONS = {
16
- init: '绿地项目初始化 — 深度提问、调研、需求文档、路线图',
17
- scan: '代码库扫描 — 支持快速扫描和深度扫描两阶段',
18
- explore: '自由思考模式 — 讨论、画图、调研,不写代码',
19
- brainstorm: '需求探索 — 结构化头脑风暴,生成设计文档(创建性工作前必用)',
20
- plan: '编写实现计划 — 任务拆分与实现路径',
21
- execute: '波次执行 — 子代理并行 + 强制 TDD + 两阶段审查',
22
- verify: '验证实现 — 对照规范检查 + 测试套件',
23
- archive: '归档变更 — 规范沉淀,可追溯',
24
- commit: '智能提交 — 自动收集变更信息,生成 commit message',
25
- status: '查看项目进度和状态',
26
- continue: '自动判断并执行下一步',
27
- state: '查看当前工作状态 — 显示 STATE.md 内容',
28
-
29
- quick: '快速任务 — 跳过完整流程,直接做',
30
- workspace: '工作区管理 — 初始化、管理多项目工作区,查看子项目状态',
31
- export: '导出成功方案为可复用模板',
32
- };
33
28
 
34
- const ARG_HINTS = {
35
- init: '[项目名]',
36
- scan: '[可选:指定区域,如 \'api\' 或 \'auth\'] [--deep 深度扫描]',
37
- explore: '[探索主题]',
38
- brainstorm: '[需求或想法描述]',
39
-
40
- plan: '[计划名]',
41
- execute: '[任务编号或 \'all\']',
42
- verify: '[可选:指定验证范围]',
43
- archive: '[变更名]',
44
- commit: '[可选:自定义 commit message]',
45
- status: '',
46
- continue: '',
47
- state: '[可选备注]',
48
-
49
- quick: '[任务描述]',
50
- workspace: '[可选:add/remove/status/info]',
51
- export: '<change-name> [--to <path>]',
52
- };
53
29
 
54
30
  const VALID_TOOLS = ['claude', 'claude_skills', 'cursor', 'openclaw', 'codex', 'gemini', 'opencode'];
55
31
 
@@ -63,8 +39,6 @@ const TOOL_LABELS = {
63
39
  opencode: 'OpenCode (通过 INSTRUCTIONS.md)',
64
40
  };
65
41
 
66
-
67
- // 指令文件工具:注入规范引用到指令文件
68
42
  const INSTRUCTION_TOOLS = ['codex', 'gemini', 'opencode'];
69
43
 
70
44
  const INSTRUCTION_FILE_MAP = {
@@ -78,83 +52,16 @@ const INJECTION_CONTENT = `## SillySpec — 规范驱动开发
78
52
  在执行开发任务时,遵循以下规范:
79
53
 
80
54
  ### 代码规范
81
- - 写代码前先读取 \`.sillyspec/codebase/CONVENTIONS.md\`(代码风格)和 \`.sillyspec/codebase/ARCHITECTURE.md\`(架构)
55
+ - 写代码前先读取 \`.sillyspec/docs/<project>/scan/CONVENTIONS.md\`(代码风格)和 \`.sillyspec/docs/<project>/scan/ARCHITECTURE.md\`(架构)
82
56
  - 调用已有方法前,用 grep 确认方法存在,不许编造
83
- - 遵循 \`.sillyspec/codebase/CONVENTIONS.md\` 中的代码风格
57
+ - 遵循 \`.sillyspec/docs/<project>/scan/CONVENTIONS.md\` 中的代码风格
84
58
 
85
59
  ### 工作流程
86
- - 读取 \`.sillyspec/STATE.md\` 确认当前阶段
60
+ - 读取 \`.sillyspec/.runtime/progress.json\` 确认当前阶段(使用 \`sillyspec progress show\`)
87
61
  - 各阶段产出文件位于 \`.sillyspec/changes/<变更名>/\` 下
88
- - 详细流程参考模板文件:\`.sillyspec/.templates/\`(brainstorm.md, plan.md, execute.md 等)
89
62
  `;
90
63
 
91
- // ── 适配器 ──
92
-
93
- function generateClaude(projectDir, name, desc, body, argHint, version) {
94
- const outDir = join(projectDir, '.claude', 'commands', 'sillyspec');
95
- mkdirSync(outDir, { recursive: true });
96
- writeFileSync(join(outDir, `${name}.md`),
97
- `---
98
- description: ${desc}
99
- argument-hint: "${argHint}"
100
- version: "${version}"
101
- ---
102
-
103
- ${body}`
104
- );
105
- }
106
-
107
- function generateClaudeSkills(projectDir, name, desc, body, argHint, version) {
108
- const outDir = join(projectDir, '.claude', 'skills', `sillyspec-${name}`);
109
- mkdirSync(outDir, { recursive: true });
110
- writeFileSync(join(outDir, 'SKILL.md'),
111
- `---
112
- name: sillyspec:${name}
113
- description: ${desc}
114
- version: "${version}"
115
- ---
116
-
117
- ${body}`
118
- );
119
- }
120
-
121
- function generateCursor(projectDir, name, desc, body, argHint, version) {
122
- const outDir = join(projectDir, '.cursor', 'commands');
123
- mkdirSync(outDir, { recursive: true });
124
- writeFileSync(join(outDir, `sillyspec-${name}.md`),
125
- `---
126
- name: /sillyspec-${name}
127
- id: sillyspec-${name}
128
- description: ${desc}
129
- version: "${version}"
130
- ---
131
-
132
- ${body}`
133
- );
134
- }
135
-
136
- function generateOpenclaw(projectDir, name, desc, body, argHint, version) {
137
- const outDir = join(projectDir, '.openclaw', 'skills', `sillyspec-${name}`);
138
- mkdirSync(outDir, { recursive: true });
139
- writeFileSync(join(outDir, 'SKILL.md'),
140
- `---
141
- name: sillyspec:${name}
142
- description: ${desc}
143
- version: "${version}"
144
- ---
145
-
146
- ${body}`
147
- );
148
- }
149
-
150
- const GENERATORS = {
151
- claude: generateClaude,
152
- claude_skills: generateClaudeSkills,
153
- cursor: generateCursor,
154
- openclaw: generateOpenclaw,
155
- };
156
-
157
- // ── 指令文件注入 ──
64
+ // ── 注入指令文件 ──
158
65
 
159
66
  function injectInstructions(tool, projectDir) {
160
67
  const fileName = INSTRUCTION_FILE_MAP[tool];
@@ -198,22 +105,33 @@ function isTTY() {
198
105
 
199
106
  // ── 核心安装逻辑 ──
200
107
 
201
- async function doInstall(projectDir, tools, isWorkspace, subprojects = []) {
108
+ async function doInstall(projectDir, tools, subprojects = []) {
202
109
  // 创建基础目录
203
- // .sillyspec/codebase/ → scan
204
- // .sillyspec/codebase/details/scan (deep)
205
- // .sillyspec/changes/ brainstorm/plan
206
- // .sillyspec/changes/archive/ archive
207
- // .sillyspec/quicklog/ → quick
208
- // .sillyspec/knowledge/ → archive (spec 沉淀)
209
- // .sillyspec/.runtime/ → runtime data (gitignored)
210
- // (plan 内容已合并到 tasks.md)
211
- if (isWorkspace) {
212
- mkdirSync(join(projectDir, '.sillyspec', 'shared'), { recursive: true });
213
- mkdirSync(join(projectDir, '.sillyspec', 'workspace'), { recursive: true });
110
+ // .sillyspec/projects/ → 项目注册表
111
+ // .sillyspec/docs/<name>/统一文档中心
112
+ // .sillyspec/knowledge/ 跨项目共享知识库
113
+ // .sillyspec/.runtime/ progress (gitignored)
114
+
115
+ // 注册当前项目到 projects/
116
+ const projectName = basename(projectDir) || 'project';
117
+ const projectsDir = join(projectDir, '.sillyspec', 'projects');
118
+ mkdirSync(projectsDir, { recursive: true });
119
+ const projectYamlPath = join(projectsDir, `${projectName}.yaml`);
120
+ if (!existsSync(projectYamlPath)) {
121
+ writeFileSync(projectYamlPath, `name: ${projectName}\npath: .\nstatus: active\n`);
214
122
  }
215
123
 
216
- // 创建知识库骨架(所有模式)
124
+ // 创建 docs/<projectName>/scan/ 子目录(代码扫描结果)
125
+ const scanDir = join(projectDir, '.sillyspec', 'docs', projectName, 'scan');
126
+ mkdirSync(scanDir, { recursive: true });
127
+ const gitkeepPath = join(scanDir, '.gitkeep');
128
+ if (!existsSync(gitkeepPath)) writeFileSync(gitkeepPath, '');
129
+
130
+ // 创建 shared/workspace 目录
131
+ mkdirSync(join(projectDir, '.sillyspec', 'shared'), { recursive: true });
132
+ mkdirSync(join(projectDir, '.sillyspec', 'workspace'), { recursive: true });
133
+
134
+ // 创建知识库骨架
217
135
  const knowledgeDir = join(projectDir, '.sillyspec', 'knowledge');
218
136
  mkdirSync(knowledgeDir, { recursive: true });
219
137
  const indexPath = join(knowledgeDir, 'INDEX.md');
@@ -231,6 +149,13 @@ async function doInstall(projectDir, tools, isWorkspace, subprojects = []) {
231
149
  mkdirSync(join(runtimeDir, sub), { recursive: true });
232
150
  }
233
151
 
152
+ // 创建初始 progress.json
153
+ const progressPath = join(runtimeDir, 'progress.json');
154
+ if (!existsSync(progressPath)) {
155
+ const pm = new ProgressManager();
156
+ pm.init(projectDir);
157
+ }
158
+
234
159
  // 创建初始 user-inputs.md
235
160
  const inputsPath = join(runtimeDir, 'user-inputs.md');
236
161
  if (!existsSync(inputsPath)) {
@@ -238,7 +163,7 @@ async function doInstall(projectDir, tools, isWorkspace, subprojects = []) {
238
163
  }
239
164
 
240
165
  const gitignorePath = join(projectDir, '.gitignore');
241
- const ignoreRules = ['.sillyspec/STATE.md', '.sillyspec/codebase/SCAN-RAW.md', '.sillyspec/local.yaml', '.sillyspec/.runtime/'];
166
+ const ignoreRules = ['.sillyspec/codebase/SCAN-RAW.md', '.sillyspec/local.yaml', '.sillyspec/.runtime/'];
242
167
  if (existsSync(gitignorePath)) {
243
168
  const content = readFileSync(gitignorePath, 'utf8');
244
169
  let updated = content.trimEnd();
@@ -252,83 +177,35 @@ async function doInstall(projectDir, tools, isWorkspace, subprojects = []) {
252
177
  writeFileSync(gitignorePath, ignoreRules.join('\n') + '\n');
253
178
  }
254
179
 
255
- // 生成 slash command 文件
256
- const templateFiles = readdirSync(TEMPLATE_DIR).filter(f => f.endsWith('.md'));
257
- let count = 0;
258
-
180
+ // 注入指令文件(codex/gemini/opencode)
259
181
  for (let i = 0; i < tools.length; i++) {
260
182
  const toolName = tools[i];
261
- const label = TOOL_LABELS[toolName] || toolName;
262
-
263
183
  if (INSTRUCTION_TOOLS.includes(toolName)) {
264
- const spinner = ora(`安装 ${label}... (${i + 1}/${tools.length})`).start();
265
- try {
266
- injectInstructions(toolName, projectDir);
267
- // 复制模板文件到 .sillyspec/.templates/
268
- const templatesSourceDir = join(TEMPLATE_DIR);
269
- const templatesDir = join(projectDir, '.sillyspec', '.templates');
270
- if (!existsSync(templatesDir)) {
271
- mkdirSync(templatesDir, { recursive: true });
272
- for (const file of readdirSync(templatesSourceDir)) {
273
- if (file.endsWith('.md')) {
274
- copyFileSync(join(templatesSourceDir, file), join(templatesDir, file));
275
- }
276
- }
277
- }
278
- spinner.succeed(`${label} 完成`);
279
- count++;
280
- } catch (err) {
281
- spinner.fail(`${label} 失败: ${err.message}`);
282
- throw err;
283
- }
284
- continue;
285
- }
286
-
287
- const spinner = ora(`安装 ${label}... (${i + 1}/${tools.length})`).start();
288
- try {
289
- const gen = GENERATORS[toolName];
290
- const ver = getVersion();
291
- for (const file of templateFiles) {
292
- const name = file.replace('.md', '');
293
- const desc = DESCRIPTIONS[name] || `SillySpec ${name}`;
294
- const argHint = ARG_HINTS[name] || '';
295
- const body = readFileSync(join(TEMPLATE_DIR, file), 'utf8');
296
- gen(projectDir, name, desc, body, argHint, ver);
297
- count++;
298
- }
299
- spinner.succeed(`${label} 完成`);
300
- } catch (err) {
301
- spinner.fail(`${label} 失败: ${err.message}`);
302
- throw err;
184
+ injectInstructions(toolName, projectDir);
303
185
  }
304
186
  }
305
187
 
306
- // 工作区子项目配置 projects/*.yaml
307
- if (isWorkspace && subprojects.length > 0) {
308
- const projectsDir = join(projectDir, '.sillyspec', 'projects');
309
- mkdirSync(projectsDir, { recursive: true });
310
- for (const p of subprojects) {
311
- const pFile = join(projectsDir, `${p.name}.yaml`);
312
- if (!existsSync(pFile)) {
313
- writeFileSync(pFile,
314
- `# ${p.name}
315
- name: ${p.name}
316
- path: ${p.path}
317
- role: ${p.role || p.name}${p.repo ? `\nrepo: ${p.repo}` : ''}
318
- `
319
- );
188
+ // 复制 skills 到 .claude/skills/(给 Claude Code 使用)
189
+ const claudeSkillsDir = join(projectDir, '.claude', 'skills');
190
+ const skillsSource = join(__dirname, '..', '.claude', 'skills');
191
+ if (existsSync(skillsSource)) {
192
+ const sillyspecSkills = readdirSync(skillsSource).filter(f => f.startsWith('sillyspec-') && statSync(join(skillsSource, f)).isDirectory());
193
+ if (sillyspecSkills.length > 0) {
194
+ mkdirSync(claudeSkillsDir, { recursive: true });
195
+ for (const skill of sillyspecSkills) {
196
+ copyDirSync(join(skillsSource, skill), join(claudeSkillsDir, skill));
320
197
  }
198
+ console.log(chalk.green(' ✓ Claude Code skills 已同步 (' + sillyspecSkills.length + ' 个)'));
321
199
  }
200
+ } else {
201
+ console.log(chalk.yellow(' ⚠ 未找到 skills 目录(npm 包内无 .claude/skills/),跳过同步'));
322
202
  }
323
-
324
- return count;
325
203
  }
326
204
 
327
205
  // ── 安装完成总结 ──
328
206
 
329
- function showSummary(version, tools, isWorkspace, count) {
207
+ function showSummary(version, tools) {
330
208
  const toolLabels = tools.map(t => TOOL_LABELS[t] || t);
331
- const mode = isWorkspace ? '多项目工作区' : '单项目';
332
209
 
333
210
  console.log('');
334
211
  console.log(chalk.green(' ═══════════════════════════════════════'));
@@ -336,20 +213,13 @@ function showSummary(version, tools, isWorkspace, count) {
336
213
  console.log(chalk.green(' ═══════════════════════════════════════'));
337
214
  console.log('');
338
215
  console.log(` 已安装工具: ${chalk.cyan(toolLabels.join(', '))}`);
339
- console.log(` 模式: ${chalk.yellow(mode)}`);
340
- console.log('');
341
- console.log(` 📄 ${count} 个命令已就绪`);
342
216
  console.log(' 📁 .sillyspec/ — 项目规范目录');
343
217
  console.log('');
344
- console.log(' 入口选择:');
345
- console.log(' 全新项目:' + chalk.bold('/sillyspec:init'));
346
- console.log(' 已有代码:' + chalk.bold('/sillyspec:scan'));
347
- console.log(' 自由思考:' + chalk.bold('/sillyspec:explore "你的想法"'));
348
- console.log('');
349
- console.log(chalk.gray(' 重启你的 AI 工具以使 slash commands 生效。'));
218
+ console.log(' 下一步:使用 AI 技能开始工作');
219
+ console.log(' OpenClaw: ' + chalk.bold('/sillyspec:brainstorm'));
220
+ console.log(' Claude Code: ' + chalk.bold('/sillyspec:brainstorm'));
350
221
  console.log('');
351
222
  console.log(chalk.dim(' 💡 推荐安装 MCP 工具增强 AI 能力:sillyspec setup'));
352
- console.log(chalk.dim(' Context7 — 查最新文档 | grep.app — 搜开源实现 | Chrome DevTools — 浏览器自动化'));
353
223
  console.log('');
354
224
  }
355
225
 
@@ -367,7 +237,7 @@ export function getVersion() {
367
237
  // ── 主命令 ──
368
238
 
369
239
  export async function cmdInit(projectDir, options = {}) {
370
- const { tool, workspace, interactive } = options;
240
+ const { tool, interactive } = options;
371
241
  const version = getVersion();
372
242
 
373
243
  // ── 交互式模式(--interactive 或 -i)──
@@ -399,20 +269,11 @@ export async function cmdInit(projectDir, options = {}) {
399
269
  validate: (answer) => answer.length > 0 || '至少选择一个工具',
400
270
  });
401
271
 
402
- // 工作区模式
403
- const isWorkspace = await select({
404
- message: '选择项目模式',
405
- choices: [
406
- { name: '单项目模式', value: 'false' },
407
- { name: '多项目工作区', value: 'true' },
408
- ],
409
- }) === 'true';
410
-
411
- // 工作区子项目引导
272
+ // 子项目引导(仅交互模式)
412
273
  let subprojects = [];
413
- if (isWorkspace) {
274
+ {
414
275
  console.log('');
415
- console.log(chalk.yellow('📋 工作区模式 — 添加子项目'));
276
+ console.log(chalk.yellow('📋 添加子项目'));
416
277
  console.log(chalk.dim(' 子项目是工作区中的独立项目目录(如 frontend/、backend/)'));
417
278
  console.log('');
418
279
 
@@ -475,8 +336,8 @@ export async function cmdInit(projectDir, options = {}) {
475
336
  }
476
337
 
477
338
  console.log('');
478
- const count = await doInstall(projectDir, selectedTools, isWorkspace, subprojects);
479
- showSummary(version, selectedTools, isWorkspace, count);
339
+ await doInstall(projectDir, selectedTools, subprojects);
340
+ showSummary(version, selectedTools);
480
341
  return;
481
342
  }
482
343
 
@@ -494,23 +355,17 @@ export async function cmdInit(projectDir, options = {}) {
494
355
  tools = detectTools(projectDir);
495
356
  }
496
357
 
497
- const count = await doInstall(projectDir, tools, !!workspace);
358
+ await doInstall(projectDir, tools);
498
359
 
499
360
  console.log('');
500
361
  console.log(chalk.green(` ✅ SillySpec v${version} 安装完成!`));
501
362
  console.log('');
502
- console.log(` 📄 ${count} 个命令已就绪`);
503
363
  console.log(' 📁 .sillyspec/ — 项目规范目录');
504
364
  console.log('');
505
- console.log(' 下一步:');
506
- console.log(` 全新项目 → ${chalk.bold('/sillyspec:init')}`);
507
- console.log(` 已有代码 ${chalk.bold('/sillyspec:scan')}`);
508
- console.log(` 自由探索 → ${chalk.bold('/sillyspec:explore "你的想法"')}`);
509
- if (workspace) {
510
- console.log(` 管理子项目 → ${chalk.bold('/sillyspec:workspace add')}`);
511
- }
365
+ console.log(' 下一步:使用 AI 技能开始工作');
366
+ console.log(` OpenClaw: ${chalk.bold('/sillyspec:brainstorm')}`);
367
+ console.log(` Claude Code: ${chalk.bold('/sillyspec:brainstorm')}`);
512
368
  console.log('');
513
369
  console.log(chalk.dim(' 💡 增强能力:sillyspec setup(安装 MCP 工具)'));
514
- console.log(chalk.dim(' 💡 完整配置:sillyspec init --interactive'));
515
370
  console.log('');
516
371
  }