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/setup.js CHANGED
@@ -1,25 +1,9 @@
1
- import { existsSync, readFileSync, writeFileSync, mkdirSync, cpSync } from 'fs';
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
2
2
  import { join, dirname } from 'path';
3
- import { fileURLToPath } from 'url';
4
3
  import { execSync } from 'child_process';
5
4
  import chalk from 'chalk';
6
5
  import ora from 'ora';
7
- import { checkbox, confirm, input, select } from '@inquirer/prompts';
8
-
9
- const __filename = fileURLToPath(import.meta.url);
10
- const __dirname = dirname(__filename);
11
-
12
- // ── Skill 定义 ──
13
-
14
- const SKILLS = [
15
- {
16
- id: 'playwright-e2e',
17
- name: 'Playwright E2E 测试参考',
18
- description: 'E2E 测试编写最佳实践,AI 执行测试任务时自动读取',
19
- source: join(__dirname, '..', 'templates', 'skills', 'playwright-e2e'),
20
- target: 'playwright-e2e',
21
- },
22
- ];
6
+ import { checkbox, input } from '@inquirer/prompts';
23
7
 
24
8
  // ── MCP 工具定义 ──
25
9
 
@@ -298,21 +282,6 @@ export async function cmdSetup(dir, options = {}) {
298
282
  ...dbChoices,
299
283
  ...globalChoices.length > 0 ? [{ name: chalk.bold('── 全局工具 ──'), value: '_global_header', disabled: true }] : [],
300
284
  ...globalChoices,
301
- ...[{ name: chalk.bold('── AI Skills(编写参考)──'), value: '_skill_header', disabled: true }],
302
- ...(() => {
303
- const installed = new Set();
304
- for (const { path } of availableTools) {
305
- const skillDir = join(dir, dirname(path), 'skills');
306
- for (const s of SKILLS) {
307
- if (existsSync(join(skillDir, s.target, 'SKILL.md'))) installed.add(s.id);
308
- }
309
- }
310
- return SKILLS.filter(s => !installed.has(s.id)).map(s => ({
311
- name: `${s.name} — ${s.description}`,
312
- value: `skill:${s.id}`,
313
- checked: false,
314
- }));
315
- })(),
316
285
  ];
317
286
 
318
287
  if (allChoices.length === 0) {
@@ -402,41 +371,6 @@ export async function cmdSetup(dir, options = {}) {
402
371
  }
403
372
  }
404
373
 
405
- // ── 安装 Skills ──
406
-
407
- const selectedSkills = SKILLS.filter(s => selected.includes(`skill:${s.id}`));
408
-
409
- if (selectedSkills.length > 0) {
410
- // 跟 MCP 一样,选择安装到哪些 AI 工具
411
- const skillTargets = availableTools.map(t => ({
412
- name: t.tool,
413
- value: t.key,
414
- checked: true,
415
- }));
416
-
417
- const selectedTools = await checkbox({
418
- message: 'Skill 安装到哪些 AI 工具?',
419
- choices: skillTargets,
420
- });
421
-
422
- const targets = availableTools.filter(t => selectedTools.includes(t.key));
423
-
424
- console.log('');
425
- for (const { tool, path } of targets) {
426
- const spinner = ora(`安装 Skills 到 ${tool}...`).start();
427
- for (const skill of selectedSkills) {
428
- try {
429
- const targetDir = join(dir, dirname(path), 'skills', skill.target);
430
- mkdirSync(targetDir, { recursive: true });
431
- cpSync(skill.source, targetDir, { recursive: true });
432
- spinner.succeed(`${tool} → ${dirname(path)}/skills/${skill.target}/SKILL.md`);
433
- } catch (err) {
434
- spinner.fail(`${skill.name} 安装失败: ${err.message}`);
435
- }
436
- }
437
- }
438
- }
439
-
440
374
  // ── 总结 ──
441
375
 
442
376
  console.log('');
@@ -456,10 +390,6 @@ export async function cmdSetup(dir, options = {}) {
456
390
  console.log(` 🛠️ ${chalk.cyan(g.name)} — ${g.description}`);
457
391
  console.log(chalk.dim(` ${g.url}`));
458
392
  }
459
- for (const s of selectedSkills) {
460
- console.log(` 📚 ${chalk.cyan(s.name)} — ${s.description}`);
461
- console.log(chalk.dim(` → ${s.target}/SKILL.md`));
462
- }
463
393
  console.log('');
464
394
  if (selectedMcp.length > 0) {
465
395
  console.log(chalk.dim(' 重启你的 AI 工具以使 MCP 配置生效。'));
@@ -0,0 +1,54 @@
1
+ export const definition = {
2
+ name: 'archive',
3
+ title: '归档变更',
4
+ description: '规范沉淀,可追溯',
5
+ auxiliary: true,
6
+ steps: [
7
+ {
8
+ name: '任务完成度检查',
9
+ prompt: `检查 tasks.md 中所有 checkbox 是否已勾选。
10
+
11
+ ### 操作
12
+ 1. 读取 \`.sillyspec/changes/<change-name>/tasks.md\`
13
+ 2. 检查所有 checkbox 是否已勾选
14
+ 3. 如有遗漏 → 询问用户是否继续归档
15
+
16
+ ### 输出
17
+ 完成度报告`,
18
+ outputHint: '完成度报告',
19
+ optional: false
20
+ },
21
+ {
22
+ name: '确认归档',
23
+ prompt: `展示即将归档的内容,请用户确认。
24
+
25
+ ### 操作
26
+ 1. 展示:变更目录名、包含的文件列表、生成总结
27
+ 2. 请用户确认是否执行归档
28
+ 3. 确认后:将 \`.sillyspec/changes/<change-name>/\` 移动到 \`.sillyspec/changes/archive/YYYY-MM-DD-<change-name>/\`
29
+ 4. 确保所有 checkbox 都已勾选
30
+
31
+ ### 输出
32
+ 归档确认`,
33
+ outputHint: '归档确认',
34
+ optional: false
35
+ },
36
+ {
37
+ name: '更新路线图和提交',
38
+ prompt: `更新路线图并暂存变更。
39
+
40
+ ### 操作
41
+ 1. 如果 \`.sillyspec/ROADMAP.md\` 存在,标记对应 Phase 为已完成
42
+ 2. \`git add .sillyspec/\` — **不要 commit**,由用户通过统一提交工具处理
43
+ 3. 更新 progress.json:
44
+ - 清除当前变更信息(归档后不再活跃)
45
+ - 如果是主变更(有 MASTER.md),标记所有阶段为 ✅,然后清除
46
+ - 历史记录追加时间 + 归档完成
47
+
48
+ ### 输出
49
+ 归档完成确认 + 累积规范统计`,
50
+ outputHint: '归档完成',
51
+ optional: false
52
+ }
53
+ ]
54
+ }
@@ -0,0 +1,239 @@
1
+ export const definition = {
2
+ name: 'brainstorm',
3
+ title: '头脑风暴',
4
+ description: '探索需求、分析技术方案、识别风险',
5
+ steps: [
6
+ {
7
+ name: '状态检查',
8
+ prompt: `检查 .sillyspec/.runtime/progress.json 确认当前状态。
9
+
10
+ ### 操作
11
+ 1. 运行 \`sillyspec progress show\`
12
+ 2. 确认 currentStage 为 "brainstorm"
13
+ 3. 如果有进行中的 brainstorm,提示选择继续或重新开始
14
+ 4. 如果未初始化,提示先运行 sillyspec init
15
+
16
+ ### 输出
17
+ 当前状态摘要(1-2 句话)
18
+
19
+ ### 注意
20
+ - 以 CLI 返回为准,不要自行推断阶段
21
+ - 如果阶段不对,输出正确提示并停止`,
22
+ outputHint: '状态摘要',
23
+ optional: false
24
+ },
25
+ {
26
+ name: '加载项目上下文',
27
+ prompt: `加载项目现有上下文,理解代码结构和约定。
28
+
29
+ ### 操作
30
+ 1. 读取 CODEBASE-OVERVIEW.md + 共享规范 + 子项目上下文
31
+ 2. 加载项目信息:\`cat .sillyspec/projects/*.yaml 2>/dev/null\`
32
+ 3. 加载本地配置:\`cat .sillyspec/local.yaml 2>/dev/null\`
33
+ 4. 询问本次需求属于哪个子项目
34
+ 5. 棕地项目:读取 docs/<project>/scan/ 下的 STRUCTURE.md、CONVENTIONS.md、ARCHITECTURE.md
35
+ 6. 查看进行中的变更:\`ls .sillyspec/changes/ | grep -v archive\`
36
+
37
+ ### 输出
38
+ 项目现状理解摘要(3-5 句话,关键约定和架构决策)
39
+
40
+ ### 注意
41
+ - 始终询问本次需求属于哪个子项目
42
+ - 棕地项目必须读取数据模型章节`,
43
+ outputHint: '上下文摘要',
44
+ optional: false
45
+ },
46
+ {
47
+ name: '协作与复用检查',
48
+ prompt: `检查是否有同名变更或可复用模板。
49
+
50
+ ### 操作
51
+ 1. 检查已有变更:\`ls .sillyspec/changes/ | grep -v archive\`
52
+ - 有相关变更 → 提示用户,避免重复
53
+ 2. 检查全局模板:\`ls ~/.sillyspec/templates/\`
54
+ - 有匹配模板 → 询问是否基于模板
55
+ 3. 无相关内容 → 跳过,不输出
56
+
57
+ ### 输出
58
+ 检测到的相关变更和可用模板(无则输出"无冲突,继续")`,
59
+ outputHint: '已有变更和可用模板',
60
+ optional: true
61
+ },
62
+ {
63
+ name: '原型/设计图分析',
64
+ prompt: `如果用户提供了截图、图片或 HTML 原型,分析提取结构。
65
+
66
+ ### 操作
67
+ 1. 识别图片中的页面结构(区域、组件、布局)
68
+ 2. 提取表单字段(名称、类型、必填、选项)
69
+ 3. 提取交互流程(页面跳转、按钮行为)
70
+ 4. 提取标注和备注(业务规则、权限说明)
71
+ 5. 展示分析结果,请用户确认遗漏
72
+
73
+ ### 输出
74
+ 页面结构树 + 字段列表 + 交互流程图
75
+
76
+ ### 注意
77
+ - 没有原型则跳过此步骤
78
+ - 多页面时逐页分析,不要一次全部输出
79
+ - 图片信息 > 文字描述,不要忽略视觉信息`,
80
+ outputHint: '页面结构和交互流程',
81
+ optional: true
82
+ },
83
+ {
84
+ name: '需求范围评估',
85
+ prompt: `评估需求复杂度,判断是否需要拆分或走批量模式。
86
+
87
+ ### 操作
88
+ 1. 根据分析结果判断复杂度
89
+ 2. 满足以下任意 2 条建议拆分:
90
+ - 3+ 个可独立交付的功能模块
91
+ - 3+ 种角色有不同权限和视图
92
+ - 跨页面状态流转(审批流、多步表单)
93
+ - 模块间耦合度低可独立开发
94
+ 3. 满足以下条件建议走**批量模式**:
95
+ - 任务数量 > 10 且任务间有重复模式(如 100 个报表、50 个表单、N 个相似页面)
96
+ - 本质是「模板 × 数据」而非 N 个独立功能
97
+ - 直接逐个开发会导致 plan.md 膨胀和上下文溢出
98
+ 4. 需要拆分 → 生成 MASTER.md,规划子阶段
99
+ 5. 检测到批量模式 → 输出提示并建议用户确认
100
+ 6. 都不需要 → 继续
101
+
102
+ ### 批量模式指引
103
+ 确认后,后续 plan/execute 按以下原则调整:
104
+ - **不要**把每个实例列为独立任务(不要写 100 个 checkbox)
105
+ - plan 设计通用架构(引擎/模板/配置格式),任务数控制在 10 个以内
106
+ - 数据转换用脚本完成(Excel → 配置文件),不消耗 AI 上下文
107
+ - execute 每个 Wave 独立模块,Wave 间通过接口定义解耦
108
+ - verify 用脚本全量验证 + AI 抽查边界案例
109
+
110
+ ### 半批量场景
111
+ 如果任务中大部分相似但有少量特殊任务(如 20 个任务中 15 个相似、5 个特殊):
112
+ - **主簇**(>10 个相似)→ 走批量模式(引擎 + 配置)
113
+ - **小簇**(2-5 个相似)→ 走简化版批量(基于主簇模板扩展)
114
+ - **孤立任务**(1 个)→ 走标准开发流程
115
+ - 建议用「继承 + override」配置解决特殊任务,配置解决不了的才写定制代码
116
+ - 架构设计时预留扩展点(hooks/overrides),让特殊任务能"挂上去"而不是"另起炉灶"
117
+
118
+ ### 输出
119
+ 拆分方案 / 批量模式确认 / "无需拆分"确认
120
+
121
+ ### 注意
122
+ - 简单 CRUD 不拆
123
+ - 拆分方案需用户确认
124
+ - 批量模式需用户确认`,
125
+ outputHint: '拆分方案或无需拆分确认',
126
+ optional: true
127
+ },
128
+ {
129
+ name: '对话式探索',
130
+ prompt: `通过对话探索需求细节。
131
+
132
+ ### 操作
133
+ 1. 从最核心的一个问题开始(用户到底想要什么?)
134
+ 2. 等待用户回答后再问下一个
135
+ 3. 根据回答判断:信息够了 → 进入方案 / 需要追问 → 只问一个
136
+ 4. 探索顺序(按需):目的 → 约束 → 边界 → 成功标准
137
+
138
+ ### 输出
139
+ 需求理解摘要(用户确认的需求点列表)
140
+
141
+ ### 铁律
142
+ - 一次只问一个问题
143
+ - 2-3 轮问答就应进入方案讨论
144
+ - 多选题优于开放式问题
145
+ - YAGNI — 砍掉不需要的功能`,
146
+ outputHint: '需求理解摘要',
147
+ optional: false
148
+ },
149
+ {
150
+ name: '提出 2-3 种方案',
151
+ prompt: `基于需求理解,提出 2-3 种实现方案。
152
+
153
+ ### 操作
154
+ 1. 每种方案列出:核心思路、优势、劣势
155
+ 2. 给出推荐方案和理由
156
+ 3. 等待用户选择或调整
157
+
158
+ ### 输出
159
+ 方案对比表 + 推荐方案
160
+
161
+ ### 注意
162
+ - 方案差异要实质性的,不要为了凑数
163
+ - 推荐理由要具体`,
164
+ outputHint: '方案对比和推荐',
165
+ optional: false
166
+ },
167
+ {
168
+ name: '分段展示设计',
169
+ prompt: `按复杂度分段展示设计方案,逐段确认。
170
+
171
+ ### 操作
172
+ 1. 简单项目:几句话整体描述
173
+ 2. 复杂项目:每段 200-300 字,逐段展示
174
+ 3. 每段展示后等待用户确认
175
+ 4. 收集修改意见,调整设计
176
+
177
+ ### 输出
178
+ 用户确认的完整设计方案
179
+
180
+ ### 注意
181
+ - 不要一次输出大段文字
182
+ - 逐段确认,确保用户跟上`,
183
+ outputHint: '用户确认的设计方案',
184
+ optional: false
185
+ },
186
+ {
187
+ name: '写设计文档并自审',
188
+ prompt: `撰写 design 文档并进行 AI 自审。
189
+
190
+ ### 操作
191
+ 1. 确认变更目录存在:\`mkdir -p .sillyspec/changes/<变更名>\`(Windows 用 \`mkdir .sillyspec\\changes\\<变更名>\` 或 PowerShell \`New-Item -ItemType Directory -Force -Path .sillyspec/changes/<变更名>\`)
192
+ 2. 将确认的设计写入 \`.sillyspec/changes/<变更名>/design.md\`
193
+ 3. 自审检查:
194
+ - 需求覆盖:是否完整覆盖 Step 6 确认的需求
195
+ - 约束一致性:是否与 CONVENTIONS.md、ARCHITECTURE.md 一致
196
+ - 真实性:表名/字段名来自真实 schema 或标注"新增"
197
+ - YAGNI:是否包含不必要功能
198
+ - 验收标准:是否具体可测试
199
+ 3. 自审发现问题 → 修改后重新检查
200
+ 4. 全部通过 → 进入下一步
201
+
202
+ ### 输出
203
+ design.md 文件路径 + 自审结果
204
+
205
+ ### 注意
206
+ - 自审不通过不要进入下一步
207
+ - 不确定的问题标注「⚠️ 自审存疑」`,
208
+ outputHint: 'design.md 路径 + 自审结果',
209
+ optional: false
210
+ },
211
+ {
212
+ name: '用户确认并生成规范文件',
213
+ prompt: `用户确认设计方案,生成规范文件。
214
+
215
+ ### 操作
216
+ 1. 展示 design.md 摘要给用户
217
+ 2. 请用户选择:✅ 确认 / ✏️ 修改 / ❌ 推翻重来
218
+ 3. 确认后,在 \`.sillyspec/changes/<变更名>/\` 下生成所有规范文件:
219
+ - **design.md**:架构决策、文件变更清单、数据模型、API 设计、代码风格参照
220
+ - **proposal.md**:动机、变更范围、不在范围内、成功标准
221
+ - **requirements.md**:功能需求、用户场景(Given/When/Then 格式)、非功能需求
222
+ - **tasks.md**:任务列表(只列名称和对应文件路径,细节在 plan 阶段展开)
223
+ - \`git add .sillyspec/\` — **不要 commit**
224
+
225
+ ### 输出
226
+ 所有规范文件路径
227
+
228
+ ### 注意
229
+ - 必须等待用户明确确认
230
+ - 禁止在确认前推进到后续阶段
231
+ - 禁止自动 commit
232
+ - 推翻重来回到 Step 6
233
+ - 表名/字段名必须来自真实 schema 或标注"新增"
234
+ - tasks.md 只列任务名,细节在 plan 阶段展开`,
235
+ outputHint: '规范文件路径',
236
+ optional: false
237
+ }
238
+ ]
239
+ }
@@ -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
+ }