sillyspec 3.9.0 → 3.10.0

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 (206) 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 +105 -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 +17 -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/README.md +19 -11
  21. package/SKILL.md +15 -10
  22. package/package.json +7 -9
  23. package/packages/dashboard/dist/assets/index-BcM2J-hv.css +1 -0
  24. package/packages/dashboard/dist/assets/index-DpLHK4jv.js +7446 -0
  25. package/packages/dashboard/dist/index.html +16 -16
  26. package/packages/dashboard/dist/prototype-dashboard.html +836 -0
  27. package/packages/dashboard/dist/prototype-overview.html +256 -0
  28. package/packages/dashboard/package-lock.json +226 -6
  29. package/packages/dashboard/package.json +8 -5
  30. package/packages/dashboard/public/logo.jpg +0 -0
  31. package/packages/dashboard/public/prototype-dashboard.html +836 -0
  32. package/packages/dashboard/public/prototype-overview.html +256 -0
  33. package/packages/dashboard/server/executor.js +1 -1
  34. package/packages/dashboard/server/index.js +341 -113
  35. package/packages/dashboard/server/parser.js +442 -30
  36. package/packages/dashboard/server/watcher.js +214 -134
  37. package/packages/dashboard/src/App.vue +475 -71
  38. package/packages/dashboard/src/components/ActionBar.vue +36 -43
  39. package/packages/dashboard/src/components/CommandPalette.vue +45 -66
  40. package/packages/dashboard/src/components/DetailPanel.vue +68 -53
  41. package/packages/dashboard/src/components/DocPreview.vue +257 -0
  42. package/packages/dashboard/src/components/DocTree.vue +114 -0
  43. package/packages/dashboard/src/components/HResizeHandle.vue +48 -0
  44. package/packages/dashboard/src/components/LogStream.vue +13 -33
  45. package/packages/dashboard/src/components/PipelineStage.vue +8 -8
  46. package/packages/dashboard/src/components/PipelineView.vue +99 -45
  47. package/packages/dashboard/src/components/ProjectCard.vue +187 -0
  48. package/packages/dashboard/src/components/ProjectList.vue +103 -45
  49. package/packages/dashboard/src/components/ProjectOverview.vue +152 -0
  50. package/packages/dashboard/src/components/StageBadge.vue +13 -13
  51. package/packages/dashboard/src/components/StepCard.vue +15 -15
  52. package/packages/dashboard/src/components/VResizeHandle.vue +61 -0
  53. package/packages/dashboard/src/components/detail/DocsDetail.vue +48 -0
  54. package/packages/dashboard/src/components/detail/GitDetail.vue +61 -0
  55. package/packages/dashboard/src/components/detail/TechDetail.vue +43 -0
  56. package/packages/dashboard/src/composables/useDashboard.js +48 -6
  57. package/packages/dashboard/src/composables/useKeyboard.js +6 -4
  58. package/packages/dashboard/src/composables/useLayout.js +131 -0
  59. package/packages/dashboard/src/main.js +4 -1
  60. package/packages/dashboard/src/style.css +17 -17
  61. package/src/index.js +141 -22
  62. package/src/init.js +93 -231
  63. package/src/migrate.js +117 -0
  64. package/src/progress.js +460 -0
  65. package/src/run.js +635 -0
  66. package/src/setup.js +2 -72
  67. package/src/stages/archive.js +54 -0
  68. package/src/stages/brainstorm.js +264 -0
  69. package/src/stages/doctor.js +303 -0
  70. package/src/stages/execute.js +287 -0
  71. package/src/stages/explore.js +34 -0
  72. package/src/stages/index.js +28 -0
  73. package/src/stages/plan.js +354 -0
  74. package/src/stages/propose.js +115 -0
  75. package/src/stages/quick.js +64 -0
  76. package/src/stages/scan.js +141 -0
  77. package/src/stages/status.js +65 -0
  78. package/src/stages/verify.js +135 -0
  79. package/.sillyspec/changes/dashboard/design.md +0 -219
  80. package/.sillyspec/plans/2026-04-05-dashboard.md +0 -737
  81. package/.sillyspec/specs/2026-04-05-dashboard-design.md +0 -206
  82. package/dist/steps/brainstorm/01-load-context.md +0 -30
  83. package/dist/steps/brainstorm/02-reuse-check.md +0 -6
  84. package/dist/steps/brainstorm/03-prototype-analysis.md +0 -11
  85. package/dist/steps/brainstorm/04-module-split.md +0 -23
  86. package/dist/steps/brainstorm/05-dialog-explore.md +0 -8
  87. package/dist/steps/brainstorm/06-propose-approaches.md +0 -3
  88. package/dist/steps/brainstorm/07-present-design.md +0 -3
  89. package/dist/steps/brainstorm/08-write-design.md +0 -21
  90. package/dist/steps/brainstorm/09-self-review.md +0 -15
  91. package/dist/steps/brainstorm/10-user-confirm.md +0 -3
  92. package/dist/steps/brainstorm/11-output-spec.md +0 -7
  93. package/dist/steps/brainstorm/manifest.yaml +0 -26
  94. package/dist/steps/execute/01-load-context.md +0 -41
  95. package/dist/steps/execute/02-scan-conventions.md +0 -47
  96. package/dist/steps/execute/03-skill-mcp.md +0 -19
  97. package/dist/steps/execute/04-assign-task.md +0 -22
  98. package/dist/steps/execute/04b-prompt-template.md +0 -54
  99. package/dist/steps/execute/05-write-test.md +0 -7
  100. package/dist/steps/execute/06-write-code.md +0 -8
  101. package/dist/steps/execute/07-run-test.md +0 -26
  102. package/dist/steps/execute/08-fix-issues.md +0 -28
  103. package/dist/steps/execute/09-next-task.md +0 -33
  104. package/dist/steps/execute/manifest.yaml +0 -28
  105. package/dist/steps/plan/01-load-context.md +0 -22
  106. package/dist/steps/plan/02-anchor-confirm.md +0 -1
  107. package/dist/steps/plan/03-expand-tasks.md +0 -33
  108. package/dist/steps/plan/04-mark-order.md +0 -15
  109. package/dist/steps/plan/05-e2e-planning.md +0 -17
  110. package/dist/steps/plan/06-self-check.md +0 -16
  111. package/dist/steps/plan/07-save.md +0 -1
  112. package/dist/steps/plan/manifest.yaml +0 -18
  113. package/dist/steps/scan/01-env-detect.md +0 -51
  114. package/dist/steps/scan/02-tech-stack.md +0 -16
  115. package/dist/steps/scan/03-conventions.md +0 -16
  116. package/dist/steps/scan/04-structure.md +0 -19
  117. package/dist/steps/scan/05-quality.md +0 -18
  118. package/dist/steps/scan/06-complete.md +0 -49
  119. package/dist/steps/scan/manifest.yaml +0 -16
  120. package/dist/steps/verify/01-load-specs.md +0 -28
  121. package/dist/steps/verify/02-check-tasks.md +0 -1
  122. package/dist/steps/verify/03-check-design.md +0 -6
  123. package/dist/steps/verify/04-run-tests.md +0 -7
  124. package/dist/steps/verify/05-e2e-tests.md +0 -27
  125. package/dist/steps/verify/05b-e2e-fix.md +0 -33
  126. package/dist/steps/verify/06-code-quality.md +0 -25
  127. package/dist/steps/verify/07-lint-check.md +0 -27
  128. package/dist/steps/verify/08-output-report.md +0 -14
  129. package/dist/steps/verify/manifest.yaml +0 -22
  130. package/docs/.vitepress/config.mts +0 -45
  131. package/docs/.vitepress/dist/404.html +0 -25
  132. package/docs/.vitepress/dist/assets/app.YytxICdd.js +0 -1
  133. package/docs/.vitepress/dist/assets/chunks/framework.Czhw_PXq.js +0 -19
  134. package/docs/.vitepress/dist/assets/chunks/theme.DusTRZQk.js +0 -1
  135. package/docs/.vitepress/dist/assets/index.md.C3VCvtQA.js +0 -1
  136. package/docs/.vitepress/dist/assets/index.md.C3VCvtQA.lean.js +0 -1
  137. package/docs/.vitepress/dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  138. package/docs/.vitepress/dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  139. package/docs/.vitepress/dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  140. package/docs/.vitepress/dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  141. package/docs/.vitepress/dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  142. package/docs/.vitepress/dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  143. package/docs/.vitepress/dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  144. package/docs/.vitepress/dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  145. package/docs/.vitepress/dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  146. package/docs/.vitepress/dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  147. package/docs/.vitepress/dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  148. package/docs/.vitepress/dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  149. package/docs/.vitepress/dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  150. package/docs/.vitepress/dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  151. package/docs/.vitepress/dist/assets/sillyspec_commands.md.CXFFsj08.js +0 -15
  152. package/docs/.vitepress/dist/assets/sillyspec_commands.md.CXFFsj08.lean.js +0 -1
  153. package/docs/.vitepress/dist/assets/sillyspec_dashboard.md.BuPXHqjX.js +0 -4
  154. package/docs/.vitepress/dist/assets/sillyspec_dashboard.md.BuPXHqjX.lean.js +0 -1
  155. package/docs/.vitepress/dist/assets/sillyspec_file-io.md.Cz3x7llx.js +0 -1
  156. package/docs/.vitepress/dist/assets/sillyspec_file-io.md.Cz3x7llx.lean.js +0 -1
  157. package/docs/.vitepress/dist/assets/sillyspec_getting-started.md.ClcvV8k3.js +0 -4
  158. package/docs/.vitepress/dist/assets/sillyspec_getting-started.md.ClcvV8k3.lean.js +0 -1
  159. package/docs/.vitepress/dist/assets/sillyspec_install.md.CKuR2tiT.js +0 -5
  160. package/docs/.vitepress/dist/assets/sillyspec_install.md.CKuR2tiT.lean.js +0 -1
  161. package/docs/.vitepress/dist/assets/sillyspec_lifecycle.md.DY293cR1.js +0 -28
  162. package/docs/.vitepress/dist/assets/sillyspec_lifecycle.md.DY293cR1.lean.js +0 -1
  163. package/docs/.vitepress/dist/assets/sillyspec_structure.md.sVYS4zPs.js +0 -30
  164. package/docs/.vitepress/dist/assets/sillyspec_structure.md.sVYS4zPs.lean.js +0 -1
  165. package/docs/.vitepress/dist/assets/style.DFTx90Kk.css +0 -1
  166. package/docs/.vitepress/dist/hashmap.json +0 -1
  167. package/docs/.vitepress/dist/index.html +0 -28
  168. package/docs/.vitepress/dist/sillyspec/commands.html +0 -42
  169. package/docs/.vitepress/dist/sillyspec/dashboard.html +0 -31
  170. package/docs/.vitepress/dist/sillyspec/file-io.html +0 -28
  171. package/docs/.vitepress/dist/sillyspec/getting-started.html +0 -31
  172. package/docs/.vitepress/dist/sillyspec/install.html +0 -32
  173. package/docs/.vitepress/dist/sillyspec/lifecycle.html +0 -55
  174. package/docs/.vitepress/dist/sillyspec/structure.html +0 -57
  175. package/docs/.vitepress/dist/vp-icons.css +0 -1
  176. package/docs/index.md +0 -34
  177. package/docs/sillyspec/commands.md +0 -218
  178. package/docs/sillyspec/dashboard.md +0 -51
  179. package/docs/sillyspec/file-io.md +0 -34
  180. package/docs/sillyspec/getting-started.md +0 -61
  181. package/docs/sillyspec/install.md +0 -51
  182. package/docs/sillyspec/lifecycle.md +0 -146
  183. package/docs/sillyspec/structure.md +0 -62
  184. package/packages/dashboard/dist/assets/index-Bh-GPjKY.css +0 -1
  185. package/packages/dashboard/dist/assets/index-CrCn5Gg6.js +0 -17
  186. package/src/step.js +0 -543
  187. package/templates/archive.md +0 -120
  188. package/templates/brainstorm.md +0 -170
  189. package/templates/continue.md +0 -32
  190. package/templates/execute.md +0 -304
  191. package/templates/explore.md +0 -59
  192. package/templates/export.md +0 -21
  193. package/templates/init.md +0 -61
  194. package/templates/plan.md +0 -146
  195. package/templates/quick.md +0 -135
  196. package/templates/scan-quick.md +0 -49
  197. package/templates/scan.md +0 -156
  198. package/templates/skills/playwright-e2e/SKILL.md +0 -340
  199. package/templates/status.md +0 -75
  200. package/templates/verify.md +0 -236
  201. package/templates/workspace-sync.md +0 -99
  202. package/templates/workspace.md +0 -70
  203. /package/{docs/.vitepress/dist/logo.jpg → logo.jpg} +0 -0
  204. /package/{docs/.vitepress → packages/dashboard}/dist/favicon.jpg +0 -0
  205. /package/{docs/public → packages/dashboard/dist}/logo.jpg +0 -0
  206. /package/{docs → packages/dashboard}/public/favicon.jpg +0 -0
@@ -0,0 +1,303 @@
1
+ // SillySpec Doctor — 项目自检阶段
2
+ // 检查项通过 prompt 中的 bash 命令执行,此文件仅定义步骤结构
3
+
4
+
5
+ export const definition = {
6
+ name: 'doctor',
7
+ title: '项目自检',
8
+ description: '检查 SillySpec 配置、构建环境和外部依赖',
9
+ auxiliary: true,
10
+ steps: [
11
+ {
12
+ name: 'SillySpec 内部检查',
13
+ prompt: `运行 SillySpec 内部检查。逐项执行以下命令并汇总结果:
14
+
15
+ ### 1. 目录结构完整性
16
+ \`\`\`bash
17
+ # 检查 .sillyspec/ 及子目录
18
+ for d in .sillyspec .sillyspec/projects .sillyspec/docs .sillyspec/changes .sillyspec/.runtime; do
19
+ [ -d "$d" ] && echo "✅ $d" || echo "❌ $d"
20
+ done
21
+ # 检查 progress.json
22
+ [ -f .sillyspec/.runtime/progress.json ] && echo "✅ progress.json 存在" || echo "❌ progress.json 不存在"
23
+ node -e "JSON.parse(require('fs').readFileSync('.sillyspec/.runtime/progress.json','utf8')); console.log('✅ progress.json 可解析')" 2>/dev/null || echo "⚠️ progress.json 不可解析"
24
+ \`\`\`
25
+
26
+ ### 2. 项目配置检查
27
+ \`\`\`bash
28
+ ls .sillyspec/projects/*.yaml 2>/dev/null
29
+ # 对每个 yaml 文件,检查 name 和 path 字段,验证 path 存在
30
+ for f in .sillyspec/projects/*.yaml; do
31
+ [ -f "$f" ] || continue
32
+ name=$(grep '^name:' "$f" | head -1 | sed 's/^name:[[:space:]]*//')
33
+ p=$(grep '^path:' "$f" | head -1 | sed 's/^path:[[:space:]]*//')
34
+ [ -z "$name" ] && echo "⚠️ $(basename $f) — 缺少 name"
35
+ [ -z "$p" ] && echo "⚠️ $(basename $f) — 缺少 path"
36
+ [ -n "$p" ] && [ ! -d "$p" ] && echo "❌ $(basename $f) — path 不存在: $p"
37
+ [ -n "$name" ] && [ -n "$p" ] && [ -d "$p" ] && echo "✅ $(basename $f) — $name ($p)"
38
+ done
39
+ \`\`\`
40
+
41
+ ### 3. 进度数据一致性
42
+ \`\`\`bash
43
+ # 读取 currentChange 并检查目录存在性
44
+ node -e "
45
+ const p = JSON.parse(require('fs').readFileSync('.sillyspec/.runtime/progress.json','utf8'));
46
+ const cc = p.currentChange;
47
+ if (!cc) { console.log('ℹ️ 无当前变更'); process.exit(0); }
48
+ const dir = '.sillyspec/changes/' + cc;
49
+ const exists = require('fs').existsSync(dir);
50
+ console.log(exists ? '✅ currentChange 目录存在: ' + cc : '❌ currentChange 目录不存在: ' + cc);
51
+ // 检查各阶段产出
52
+ const stages = p.stages || {};
53
+ for (const [name, sd] of Object.entries(stages)) {
54
+ if (sd.status === 'completed' && sd.steps.length > 0) {
55
+ const hasOutput = sd.steps.some(s => s.output && s.output.trim());
56
+ console.log(' ' + name + ': ' + (hasOutput ? '✅ 有产出' : '⚠️ 已完成但无产出记录'));
57
+ }
58
+ }
59
+ " 2>/dev/null || echo "⚠️ 无法读取 progress.json"
60
+ \`\`\`
61
+
62
+ ### 4. 孤儿文件检查
63
+ \`\`\`bash
64
+ node -e "
65
+ const fs = require('fs');
66
+ const dir = '.sillyspec/changes';
67
+ if (!fs.existsSync(dir)) { console.log('ℹ️ changes/ 目录不存在'); process.exit(0); }
68
+ const subs = fs.readdirSync(dir).filter(f => fs.statSync(dir+'/'+f).isDirectory());
69
+ if (subs.length === 0) { console.log('ℹ️ 无变更目录'); process.exit(0); }
70
+ let progress;
71
+ try { progress = JSON.parse(fs.readFileSync('.sillyspec/.runtime/progress.json','utf8')); } catch { console.log('⚠️ 无法读取 progress.json'); subs.forEach(s => console.log('❓ ' + s)); process.exit(0); }
72
+ const known = new Set();
73
+ if (progress.currentChange) known.add(progress.currentChange);
74
+ for (const sd of Object.values(progress.stages || {})) {
75
+ (sd.steps || []).forEach(s => { if (s.output) known.add(s.output); });
76
+ }
77
+ subs.forEach(s => {
78
+ console.log(known.has(s) ? '✅ ' + s + ' — 已关联' : '⚠️ ' + s + ' — 孤儿目录(可清理)');
79
+ });
80
+ "
81
+ \`\`\`
82
+
83
+ ### 5. 配置文件检查
84
+ \`\`\`bash
85
+ # 检查 local.yaml 和 STACK.md
86
+ for f in .sillyspec/projects/*.yaml; do
87
+ [ -f "$f" ] || continue
88
+ name=$(grep '^name:' "$f" | head -1 | sed 's/^name:[[:space:]]*//')
89
+ p=$(grep '^path:' "$f" | head -1 | sed 's/^path:[[:space:]]*//')
90
+ [ -z "$p" ] && continue
91
+ local_yaml="$p/.sillyspec/local.yaml"
92
+ stack_md="$p/.sillyspec/STACK.md"
93
+ [ -f "$local_yaml" ] && echo "✅ local.yaml ($name)" || echo "⚠️ local.yaml ($name) — 不存在"
94
+ if [ -f "$local_yaml" ]; then
95
+ grep -q 'build:' "$local_yaml" && echo " ✅ build 命令已配置" || echo " ⚠️ 缺少 build 命令"
96
+ grep -q 'test:' "$local_yaml" && echo " ✅ test 命令已配置" || echo " ⚠️ 缺少 test 命令"
97
+ fi
98
+ [ -f "$stack_md" ] && echo "✅ STACK.md ($name)" || echo "⚠️ STACK.md ($name) — 不存在"
99
+ done
100
+ \`\`\`
101
+
102
+ ### 输出
103
+ 汇总所有检查结果,按以下格式:
104
+ \`\`\`
105
+ ## SillySpec 内部
106
+ ✅/⚠️/❌ 各项状态
107
+ \`\`\`
108
+
109
+ ### 注意
110
+ - 不要编造路径或结果,严格基于命令输出
111
+ - 如果 .sillyspec/ 不存在,直接输出 ❌ 并跳过后续检查`,
112
+ outputHint: 'SillySpec 内部检查结果',
113
+ optional: false
114
+ },
115
+ {
116
+ name: '构建环境检查',
117
+ prompt: `检查项目构建环境。先探测项目使用的构建工具,再逐项检查可用性。
118
+
119
+ ### 1. 探测构建工具
120
+ \`\`\`bash
121
+ # 确定项目路径(使用 progress.json 中的项目或当前目录)
122
+ PROJECT_DIR=$(node -e "
123
+ const fs=require('fs');
124
+ try{const p=JSON.parse(fs.readFileSync('.sillyspec/.runtime/progress.json','utf8'));if(p.project){console.log(p.project);process.exit(0)}}catch{}
125
+ const files=fs.readdirSync('.sillyspec/projects').filter(f=>f.endsWith('.yaml'));
126
+ 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('.')
127
+ " 2>/dev/null)
128
+ echo "项目目录: $PROJECT_DIR"
129
+
130
+ # 探测构建工具
131
+ for f in pom.xml build.gradle package.json requirements.txt pyproject.toml go.mod Cargo.toml; do
132
+ [ -f "$PROJECT_DIR/$f" ] && echo "检测到: $f"
133
+ done
134
+ [ -f "$PROJECT_DIR/.sillyspec/STACK.md" ] && cat "$PROJECT_DIR/.sillyspec/STACK.md" | head -30
135
+ \`\`\`
136
+
137
+ ### 2. 构建工具可用性
138
+ 根据上面检测到的工具,运行对应检查(未检测到的跳过):
139
+
140
+ **Maven 项目:**
141
+ \`\`\`bash
142
+ timeout 10 mvn -v 2>/dev/null | head -1 && echo "✅ Maven 可用" || echo "❌ Maven 不可用"
143
+ [ -f ~/.m2/settings.xml ] && echo "✅ Maven settings.xml 存在" || echo "⚠️ Maven settings.xml 不存在"
144
+ timeout 10 java -version 2>&1 | head -1
145
+ \`\`\`
146
+
147
+ **Gradle 项目:**
148
+ \`\`\`bash
149
+ timeout 10 gradle -v 2>/dev/null | head -1 && echo "✅ Gradle 可用" || echo "❌ Gradle 不可用"
150
+ \`\`\`
151
+
152
+ **Node.js 项目:**
153
+ \`\`\`bash
154
+ timeout 5 node -v 2>/dev/null && echo "✅ Node.js 可用" || echo "❌ Node.js 不可用"
155
+ timeout 5 npm -v 2>/dev/null && echo "✅ npm 可用" || echo "❌ npm 不可用"
156
+ timeout 5 pnpm -v 2>/dev/null && echo "✅ pnpm 可用" || echo "ℹ️ pnpm 未安装"
157
+ # 检查 registry
158
+ npm config get registry 2>/dev/null
159
+ \`\`\`
160
+
161
+ **Python 项目:**
162
+ \`\`\`bash
163
+ timeout 5 python3 --version 2>/dev/null && echo "✅ Python3 可用" || echo "❌ Python3 不可用"
164
+ timeout 5 pip3 --version 2>/dev/null && echo "✅ pip3 可用" || echo "❌ pip3 不可用"
165
+ \`\`\`
166
+
167
+ ### 3. Maven 私服检查(仅 Maven 项目)
168
+ \`\`\`bash
169
+ # 从 settings.xml 提取仓库地址
170
+ if [ -f ~/.m2/settings.xml ]; then
171
+ grep -oP 'https?://[^<"]+:[0-9]+' ~/.m2/settings.xml 2>/dev/null | sort -u | while read url; do
172
+ timeout 5 curl -s -o /dev/null -w "%{http_code}" "$url" 2>/dev/null
173
+ echo " — $url"
174
+ done
175
+ fi
176
+ # 从 pom.xml 提取
177
+ if [ -f "$PROJECT_DIR/pom.xml" ]; then
178
+ grep -oP 'https?://[^<"]+:[0-9]+' "$PROJECT_DIR/pom.xml" 2>/dev/null | sort -u | while read url; do
179
+ code=$(timeout 5 curl -s -o /dev/null -w "%{http_code}" "$url" 2>/dev/null)
180
+ [ "$code" = "000" ] && echo "❌ 私服不可达: $url(超时)" || echo "✅ 私服可达 ($code): $url"
181
+ done
182
+ fi
183
+ \`\`\`
184
+
185
+ ### 4. 运行时环境
186
+ \`\`\`bash
187
+ timeout 5 node -v 2>/dev/null && echo "Node.js: $(node -v)" || echo "❌ Node.js 未安装"
188
+ timeout 5 git --version 2>/dev/null && echo "Git: $(git --version)" || echo "❌ Git 未安装"
189
+ timeout 10 git remote -v 2>/dev/null | head -2
190
+ timeout 5 git ls-remote --heads origin 2>/dev/null >/dev/null && echo "✅ Git remote 可达" || echo "⚠️ Git remote 不可达"
191
+ timeout 5 java -version 2>&1 | head -1
192
+ timeout 5 python3 --version 2>/dev/null
193
+ \`\`\`
194
+
195
+ ### 输出
196
+ 汇总所有检查结果:
197
+ \`\`\`
198
+ ## 构建环境
199
+ ✅/⚠️/❌ 各项状态
200
+ \`\`\`
201
+
202
+ ### 注意
203
+ - 未检测到的构建工具直接跳过,不要报错
204
+ - timeout 超时的命令视为不可用
205
+ - 不编造结果`,
206
+ outputHint: '构建环境检查结果',
207
+ optional: false
208
+ },
209
+ {
210
+ name: '外部依赖检查',
211
+ prompt: `检查外部依赖工具是否可用。
212
+
213
+ ### 1. Context7 MCP
214
+ \`\`\`bash
215
+ # 检查 MCP 配置
216
+ for f in ~/.config/claude/claude_desktop_config.json ~/.cursor/mcp.json ~/.openclaw/mcp.json; do
217
+ [ -f "$f" ] && echo "MCP 配置文件: $f" && grep -i context7 "$f" 2>/dev/null && echo "✅ Context7 已配置" || true
218
+ done
219
+ # 也检查 sillyspec 自身的 setup
220
+ node -e "
221
+ try{const m=require(require('path').join(require('os').homedir(),'.sillyspec','config.json'));console.log('✅ sillyspec config 存在')}catch{console.log('ℹ️ 无 sillyspec 全局配置')}
222
+ " 2>/dev/null
223
+ \`\`\`
224
+
225
+ ### 2. grep.app
226
+ \`\`\`bash
227
+ timeout 5 curl -s -o /dev/null -w "%{http_code}" https://grep.app 2>/dev/null | grep -q "200" && echo "✅ grep.app 可达" || echo "⚠️ grep.app 不可达"
228
+ \`\`\`
229
+
230
+ ### 3. 其他 AI 工具(可选)
231
+ \`\`\`bash
232
+ # 检查常用 AI/开发工具
233
+ timeout 5 which gh 2>/dev/null && echo "✅ GitHub CLI 可用" || echo "ℹ️ GitHub CLI 未安装"
234
+ timeout 5 which docker 2>/dev/null && echo "✅ Docker 可用" || echo "ℹ️ Docker 未安装"
235
+ \`\`\`
236
+
237
+ ### 输出
238
+ \`\`\`
239
+ ## 外部依赖
240
+ ✅/⚠️/❌ 各项状态
241
+ \`\`\`
242
+
243
+ ### 注意
244
+ - 不编造结果
245
+ - 工具未安装用 ℹ️ 标记(非错误),不可达用 ⚠️`,
246
+ outputHint: '外部依赖检查结果',
247
+ optional: false
248
+ },
249
+ {
250
+ name: '汇总报告',
251
+ prompt: `汇总前三步的所有检查结果,生成最终的自检报告。
252
+
253
+ ### 输出格式
254
+ \`\`\`
255
+ 🔍 SillySpec Doctor — 项目自检报告
256
+
257
+ ## SillySpec 内部
258
+ ✅ .sillyspec/ 目录结构 — 正常
259
+ ✅ projects/*.yaml — N 个项目已注册
260
+ ⚠️ local.yaml (xxx) — 缺少 test 命令
261
+ ❌ progress.json — brainstorm 标记完成但 design.md 不存在
262
+
263
+ ## 构建环境
264
+ ✅ Node.js v23.4.0 — 可用
265
+ ✅ npm 10.x — 可用
266
+ ✅ Java 17.0.2 — 可用
267
+ ❌ Maven 私服 (10.0.0.1:8081) — 不可达(超时)
268
+
269
+ ## 外部依赖
270
+ ✅ Context7 MCP — 已配置
271
+ ⚠️ grep.app — 不可达
272
+ \`\`\`
273
+
274
+ ### 要求
275
+ - 基于前 3 步的实际输出汇总,不要编造
276
+ - 每类问题归入对应分区
277
+ - 全部通过给出 🎉
278
+ - 如果有 ❌ 或 ⚠️,在末尾逐项给出修复建议
279
+
280
+ ### 修复建议模板
281
+ 根据问题类型给出具体可操作的修复命令:
282
+
283
+ **常见问题及修复:**
284
+ - CLI 未安装 → \`npm install -g sillyspec\`
285
+ - 缺少 local.yaml → \`sillyspec init\` 重新生成,或手动创建
286
+ - local.yaml 缺少 build/test → 补充对应命令
287
+ - 缺少 STACK.md → \`sillyspec run scan\` 重新扫描
288
+ - progress.json 不一致 → \`sillyspec run <阶段> --reset\` 重置对应阶段
289
+ - 孤儿目录 → 确认后 \`rm -rf .sillyspec/changes/<目录名>\`
290
+ - Maven 私服不可达 → 检查 VPN、settings.xml 配置、私服状态
291
+ - Git remote 不可达 → 检查网络、SSH key 或凭证
292
+ - 工具未安装 → 给出安装命令(如 \`brew install maven\`)
293
+
294
+ 每条建议格式:
295
+ \`\`\`
296
+ 💡 修复:<问题描述>
297
+ <具体命令或操作>
298
+ \`\`\``,
299
+ outputHint: '完整自检报告',
300
+ optional: false
301
+ }
302
+ ]
303
+ }
@@ -0,0 +1,287 @@
1
+ import { existsSync, readFileSync } from 'fs'
2
+ import path from 'path'
3
+
4
+ export const definition = {
5
+ name: 'execute',
6
+ title: '波次执行',
7
+ description: '子代理并行 + 强制 TDD + 两阶段审查',
8
+ steps: [] // 动态构建,由 buildExecuteSteps() 生成
9
+ }
10
+
11
+ // 固定前缀步骤定义
12
+ const fixedPrefix = [
13
+ {
14
+ name: '状态检查',
15
+ prompt: `检查当前状态,确认可以执行 execute。
16
+
17
+ ### 操作
18
+ 1. 运行 \`sillyspec progress show\`
19
+ 2. 确认 currentStage 为 execute
20
+ 3. 如果不是 → 检查是否有未完成的 tasks.md
21
+ 4. 确认执行范围($ARGUMENTS 指定 wave/task 或全部)
22
+
23
+ ### 输出
24
+ 当前状态 + 执行范围确认`,
25
+ outputHint: '当前状态 + 执行范围',
26
+ optional: false
27
+ },
28
+ {
29
+ name: '加载上下文',
30
+ prompt: `加载计划、设计和代码库上下文。
31
+
32
+ ### 操作
33
+ 1. 读取 tasks.md(执行计划)
34
+ 2. 读取 design.md(技术方案)
35
+ 3. 读取 CONVENTIONS.md、ARCHITECTURE.md
36
+ 4. 读取 local.yaml(构建命令)
37
+ 5. 加载 CODEBASE-OVERVIEW.md
38
+
39
+ ### 输出
40
+ 已加载的上下文摘要`,
41
+ outputHint: '上下文摘要',
42
+ optional: false
43
+ },
44
+ {
45
+ name: '确认执行范围',
46
+ prompt: `解析任务,确认执行范围和确认模式。
47
+
48
+ ### 操作
49
+ 1. 从 plan 中解析 Wave 分组和任务列表
50
+ 2. 根据任务描述关键词为每个 Task 建议模型:
51
+ - 架构/复杂推理 → 最强模型
52
+ - 常规实现 → 中等模型
53
+ - 简单修改 → 快速模型
54
+ - 文档/写作 → 写作模型
55
+ 3. 用户在 tasks.md 中的 [model:xxx] 标签优先
56
+ 4. 询问用户执行确认频率:
57
+ - 每个 Wave 确认 — 每个 Wave 完成后展示结果
58
+ - AI 自主判断 — BLOCKED 或计划外变更时才询问
59
+ - 全自动 — 全部自动执行
60
+ 5. 查询知识库:读取 \`.sillyspec/knowledge/INDEX.md\`,根据 Task 关键词匹配
61
+
62
+ ### 输出
63
+ Wave 分组 + 模型分配 + 确认模式 + 知识库匹配结果
64
+
65
+ ### 注意
66
+ - 默认推荐"每个 Wave 确认"`,
67
+ outputHint: 'Wave 分组 + 模型分配',
68
+ optional: false
69
+ }
70
+ ]
71
+
72
+ // 固定后缀步骤定义
73
+ const fixedSuffix = [
74
+ {
75
+ name: '知识库审阅',
76
+ prompt: `检查本轮执行产生的新知识。
77
+
78
+ ### 操作
79
+ 1. 检查 \`.sillyspec/knowledge/uncategorized.md\` 中待确认条目
80
+ 2. 如有 → 提示用户审阅
81
+ 3. 用户确认后改为 [已确认],可归类到专题文件
82
+
83
+ ### 输出
84
+ 新知识条目数量 + 审阅提示(或"无新知识")`,
85
+ outputHint: '知识条目数量',
86
+ optional: true
87
+ },
88
+ {
89
+ name: '完成确认',
90
+ prompt: `所有任务完成后的收尾。
91
+
92
+ ### 操作
93
+ 1. 询问用户下一步:
94
+ - 验证 → sillyspec run verify
95
+ - 归档 → /sillyspec:archive
96
+ - 继续开发
97
+ 2. 提示 git add 暂存变更
98
+
99
+ ### 输出
100
+ 用户选择 + 下一步命令
101
+
102
+ ### 注意
103
+ - 完成后运行 \`sillyspec run execute --done\` 即可自动推进阶段`,
104
+ outputHint: '用户选择',
105
+ optional: false
106
+ }
107
+ ]
108
+
109
+ /**
110
+ * 从 plan 文件解析 Wave 分组
111
+ */
112
+ function parseWavesFromPlan(planContent) {
113
+ const waves = []
114
+ const lines = planContent.split('\n')
115
+ let currentWave = null
116
+ let currentTask = null
117
+
118
+ for (const line of lines) {
119
+ const waveMatch = line.match(/^#+\s*Wave\s+(\d+)/i)
120
+ if (waveMatch) {
121
+ currentWave = { index: parseInt(waveMatch[1]), tasks: [] }
122
+ currentTask = null
123
+ waves.push(currentWave)
124
+ continue
125
+ }
126
+
127
+ if (!currentWave) continue
128
+
129
+ const taskMatch = line.match(/^[-*]\s*\[[ x]\]\s*(.+)/)
130
+ if (taskMatch) {
131
+ const taskNoMatch = taskMatch[1].match(/\btask-(\d+)\b/i)
132
+ currentTask = {
133
+ index: taskNoMatch ? parseInt(taskNoMatch[1], 10) : null,
134
+ name: taskMatch[1].trim(),
135
+ file: '',
136
+ steps: '',
137
+ reference: ''
138
+ }
139
+ // 兼容旧格式:任务名后跟 (文件路径)
140
+ const fileMatch = taskMatch[1].match(/\(([^)]+)\)$/)
141
+ if (fileMatch) {
142
+ currentTask.file = fileMatch[1]
143
+ currentTask.name = taskMatch[1].replace(/\([^)]+\)$/, '').trim()
144
+ }
145
+ currentWave.tasks.push(currentTask)
146
+ continue
147
+ }
148
+
149
+ // 解析子行信息(修改/参考/步骤)
150
+ if (currentTask) {
151
+ const modMatch = line.match(/^\s+-\s*修改:\s*(.+)/)
152
+ if (modMatch) { currentTask.file = modMatch[1].trim(); continue }
153
+
154
+ const refMatch = line.match(/^\s+-\s*参考:\s*(.+)/)
155
+ if (refMatch) { currentTask.reference = refMatch[1].trim(); continue }
156
+
157
+ const stepMatch = line.match(/^\s+-\s*步骤:/)
158
+ if (stepMatch) { currentTask.steps = line.replace(/^\s+-\s*步骤:\s*/, '').trim(); continue }
159
+
160
+ // 步骤续行(数字开头的子步骤)
161
+ if (currentTask.steps && line.match(/^\s+\d+\./)) {
162
+ currentTask.steps += '\n' + line.trim()
163
+ }
164
+ }
165
+ }
166
+
167
+ return waves
168
+ }
169
+
170
+ /**
171
+ * 为 Wave 生成 prompt(强制子代理执行)
172
+ */
173
+ function buildWavePrompt(wave, waveIndex, changeDir) {
174
+ // 构建子代理 prompt 模板(每个任务的蓝图内容)
175
+ const subagentTemplates = wave.tasks.map((t, ti) => {
176
+ const taskNum = String(t.index || (ti + 1)).padStart(2, '0')
177
+ const taskFile = changeDir ? `${changeDir}/tasks/task-${taskNum}.md` : ''
178
+ const taskFileExists = taskFile && existsSync(taskFile)
179
+ let taskContent = ''
180
+ if (taskFileExists) {
181
+ try { taskContent = readFileSync(taskFile, 'utf8').trim() } catch { taskContent = '(无法读取任务蓝图文件)' }
182
+ }
183
+ const fileInfo = t.file ? ` (${t.file})` : ''
184
+ return `\`\`\`
185
+ 任务:${t.name}${fileInfo}
186
+ ${taskContent ? `蓝图内容:\n${taskContent}` : '(无蓝图文件,按任务描述执行)'}
187
+
188
+ 操作:
189
+ 1. 先读后写 — 读取要修改的文件,理解现有结构
190
+ 2. 按 TDD 步骤实现
191
+ 3. 运行对应测试确认通过
192
+ 4. 报告改动文件和测试结果
193
+
194
+ 铁律:
195
+ - 只做蓝图/任务描述里写的事,不增不减
196
+ - 蓝图有问题 → 报告问题,不要自己改
197
+ - 先写测试,再写代码
198
+ - grep 确认方法存在,不要编造
199
+ \`\`\``
200
+ }).join('\n\n')
201
+
202
+ const taskList = wave.tasks.map((t, ti) => {
203
+ const taskNum = String(t.index || (ti + 1)).padStart(2, '0')
204
+ let s = `- [ ] ${t.name}`
205
+ if (t.file) s += ` (${t.file})`
206
+ return s
207
+ }).join('\n')
208
+
209
+ return `## Wave ${waveIndex}: 执行以下任务
210
+
211
+ ## 执行方式(必须严格遵守)
212
+
213
+ **每个任务必须由独立子代理执行,你不要自己写代码。**
214
+
215
+ 你的角色是调度者 + 审查者:
216
+ 1. 为每个任务启动一个子代理(Agent tool),同 Wave 内可并行
217
+ 2. 子代理完成后审查结果
218
+ 3. 勾选 plan.md 中的 checkbox
219
+ 4. 记录改动文件和测试结果
220
+
221
+ ### 子代理 prompt 模板
222
+ 为每个任务使用以下 prompt 启动子代理:
223
+
224
+ ${subagentTemplates}
225
+
226
+ ### Wave 开始前
227
+ 1. 读取 design.md 的「编码铁律」章节(如果存在),严格遵守
228
+ 2. 读取 plan.md 了解全局任务划分和依赖关系
229
+ 3. 确认本 Wave 的输入/输出契约(前置 Wave 产出了什么,本 Wave 需要消费什么)
230
+ 4. 检查前置 Wave 的产出是否完整(文件是否存在、测试是否通过)
231
+ 5. **上下文分层加载**:
232
+ - 🔥 热上下文:design.md 编码铁律 + 当前 Wave 任务(必须加载)
233
+ - 🌡️ 温上下文:CONVENTIONS.md + ARCHITECTURE.md(需要时加载)
234
+ - ❄️ 冷上下文:其他变更的 design.md、历史 plan.md(不要主动加载,除非明确需要)
235
+
236
+ ### 本 Wave 任务
237
+ ${taskList}
238
+
239
+ ### 调度要求
240
+ 1. 同一 Wave 内任务可并行启动子代理
241
+ 2. **Reverse Sync**:子代理报告实现与 design.md 不一致时,先检查是代码错了还是文档有遗漏
242
+ 3. **不要频繁编译!** 编译很慢,只在以下情况运行:
243
+ - 写了大量代码后需要验证语法正确性
244
+ - 最后一个 Wave 完成后做一次全量编译验证
245
+ - 用户明确要求编译时
246
+ 4. 每个任务完成后:
247
+ - 勾选 plan.md / tasks.md 中对应任务的 checkbox
248
+ - 记录改动文件和测试结果
249
+ 5. 遇到 BLOCKED → 记录原因,选择:重试/跳过/停止
250
+
251
+ ### 完成后
252
+ 运行 sillyspec run execute --done --input "用户原始反馈" --output "Wave ${waveIndex} 结果摘要"`
253
+ }
254
+
255
+ /**
256
+ * 动态构建 execute 步骤列表
257
+ * @param {string|null} planFilePath - plan 文件路径,null 则用默认 3 Wave
258
+ * @returns {Array} 步骤列表
259
+ */
260
+ export function buildExecuteSteps(planFilePath = null) {
261
+ let waves
262
+ let changeDir = null
263
+
264
+ if (planFilePath && existsSync(planFilePath)) {
265
+ const planContent = readFileSync(planFilePath, 'utf8')
266
+ waves = parseWavesFromPlan(planContent)
267
+ // 从 planFilePath 推导 changeDir: .sillyspec/changes/<name>/plan.md
268
+ changeDir = path.dirname(planFilePath)
269
+ }
270
+
271
+ // 如果没解析出 Wave,生成默认 3 个
272
+ if (!waves || waves.length === 0) {
273
+ waves = []
274
+ for (let i = 1; i <= 3; i++) {
275
+ waves.push({ index: i, tasks: [{ name: `默认任务 ${i}`, file: 'TBD' }] })
276
+ }
277
+ }
278
+
279
+ const waveSteps = waves.map((wave, i) => ({
280
+ name: `Wave ${i + 1} 执行`,
281
+ prompt: buildWavePrompt(wave, i + 1, changeDir),
282
+ outputHint: `Wave ${i + 1} 执行结果`,
283
+ optional: false
284
+ }))
285
+
286
+ return [...fixedPrefix, ...waveSteps, ...fixedSuffix]
287
+ }
@@ -0,0 +1,34 @@
1
+ export const definition = {
2
+ name: 'explore',
3
+ title: '自由探索',
4
+ description: '讨论、调研、画图,不写实现代码',
5
+ auxiliary: true,
6
+ steps: [
7
+ {
8
+ name: '自由探索',
9
+ prompt: `围绕用户给出的话题做技术探索,不进入实现。
10
+
11
+ ### 操作
12
+ 1. 明确探索边界:这次只讨论、调研、画图和识别风险
13
+ 2. 如果需要代码库上下文,可以读取:
14
+ - \`.sillyspec/projects/*.yaml\`
15
+ - \`.sillyspec/docs/<project>/scan/ARCHITECTURE.md\`
16
+ - \`.sillyspec/docs/<project>/scan/CONVENTIONS.md\`
17
+ - \`.sillyspec/changes/<change-name>/design.md\`
18
+ 3. 可以用 \`rg\` / \`ls\` / \`cat\` 调查已有结构和集成点
19
+ 4. 输出 2-3 个有价值方向、关键风险和下一步建议
20
+ 5. 如果用户要求保存结论,先明确保存位置,再写入对应文档
21
+
22
+ ### 输出
23
+ 探索结论、选项对比、风险清单或 ASCII 图
24
+
25
+ ### 铁律
26
+ - 不写实现代码
27
+ - 不安装依赖
28
+ - 不修改文件,除非用户明确要求保存探索结论
29
+ - 不强行推进到 brainstorm/plan/execute`,
30
+ outputHint: '探索结论',
31
+ optional: false
32
+ }
33
+ ]
34
+ }
@@ -0,0 +1,28 @@
1
+ import { definition as brainstorm } from './brainstorm.js'
2
+ import { definition as propose } from './propose.js'
3
+ import { definition as plan } from './plan.js'
4
+ import { definition as execute } from './execute.js'
5
+ import { definition as verify } from './verify.js'
6
+ import { definition as scan } from './scan.js'
7
+ import { definition as quick } from './quick.js'
8
+ import { definition as explore } from './explore.js'
9
+ import { definition as archive } from './archive.js'
10
+ import { definition as status } from './status.js'
11
+ import { definition as doctor } from './doctor.js'
12
+
13
+ export const stageRegistry = {
14
+ brainstorm,
15
+ propose,
16
+ plan,
17
+ execute,
18
+ verify,
19
+ scan,
20
+ quick,
21
+ explore,
22
+ archive,
23
+ status,
24
+ doctor
25
+ }
26
+
27
+ // 辅助命令(在没有 progress.json 时也可执行)
28
+ export const auxiliaryStages = ['scan', 'quick', 'explore', 'archive', 'status', 'doctor']