sillyspec 3.20.2 → 3.20.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/.claude/skills/sillyspec-archive/SKILL.md +1 -5
  2. package/.claude/skills/sillyspec-auto/SKILL.md +2 -8
  3. package/.claude/skills/sillyspec-brainstorm/SKILL.md +1 -28
  4. package/.claude/skills/sillyspec-commit/SKILL.md +3 -4
  5. package/.claude/skills/sillyspec-continue/SKILL.md +4 -5
  6. package/.claude/skills/sillyspec-doctor/SKILL.md +3 -12
  7. package/.claude/skills/sillyspec-execute/SKILL.md +2 -15
  8. package/.claude/skills/sillyspec-explore/SKILL.md +1 -14
  9. package/.claude/skills/sillyspec-plan/SKILL.md +36 -5
  10. package/.claude/skills/sillyspec-propose/SKILL.md +0 -4
  11. package/.claude/skills/sillyspec-quick/SKILL.md +1 -5
  12. package/.claude/skills/sillyspec-resume/SKILL.md +66 -23
  13. package/.claude/skills/sillyspec-scan/SKILL.md +1 -5
  14. package/.claude/skills/sillyspec-state/SKILL.md +8 -8
  15. package/.claude/skills/sillyspec-status/SKILL.md +1 -5
  16. package/.claude/skills/sillyspec-verify/SKILL.md +1 -5
  17. package/.claude/skills/sillyspec-workspace/SKILL.md +3 -11
  18. package/.sillyspec/changes/archive/2026-04-08-derive-state/design.md +97 -0
  19. package/.sillyspec/changes/archive/2026-04-08-derive-state/plan.md +51 -0
  20. package/.sillyspec/changes/archive/2026-04-08-derive-state/proposal.md +29 -0
  21. package/.sillyspec/changes/archive/2026-04-08-derive-state/requirements.md +34 -0
  22. package/.sillyspec/changes/archive/2026-04-08-derive-state/tasks.md +13 -0
  23. package/.sillyspec/changes/archive/2026-04-08-derive-state/verify-result.md +43 -0
  24. package/.sillyspec/changes/auto-mode/design.md +50 -0
  25. package/.sillyspec/changes/auto-mode/proposal.md +19 -0
  26. package/.sillyspec/changes/auto-mode/requirements.md +21 -0
  27. package/.sillyspec/changes/auto-mode/tasks.md +7 -0
  28. package/.sillyspec/changes/brainstorm-archive/2026-04-05-dashboard-design.md +206 -0
  29. package/.sillyspec/changes/brainstorm-archive/2026-04-05-unified-docs-design.md +199 -0
  30. package/.sillyspec/changes/dashboard/design.md +219 -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/plans/2026-04-05-dashboard.md +737 -0
  38. package/.sillyspec/projects/sillyspec.yaml +3 -0
  39. package/README.md +11 -13
  40. package/SKILL.md +40 -44
  41. package/dist/steps/brainstorm/01-load-context.md +30 -0
  42. package/dist/steps/brainstorm/02-reuse-check.md +6 -0
  43. package/dist/steps/brainstorm/03-prototype-analysis.md +11 -0
  44. package/dist/steps/brainstorm/04-module-split.md +23 -0
  45. package/dist/steps/brainstorm/05-dialog-explore.md +8 -0
  46. package/dist/steps/brainstorm/06-propose-approaches.md +3 -0
  47. package/dist/steps/brainstorm/07-present-design.md +3 -0
  48. package/dist/steps/brainstorm/08-write-design.md +21 -0
  49. package/dist/steps/brainstorm/09-self-review.md +15 -0
  50. package/dist/steps/brainstorm/10-user-confirm.md +3 -0
  51. package/dist/steps/brainstorm/11-output-spec.md +7 -0
  52. package/dist/steps/brainstorm/manifest.yaml +26 -0
  53. package/dist/steps/execute/01-load-context.md +41 -0
  54. package/dist/steps/execute/02-scan-conventions.md +47 -0
  55. package/dist/steps/execute/03-skill-mcp.md +19 -0
  56. package/dist/steps/execute/04-assign-task.md +22 -0
  57. package/dist/steps/execute/04b-prompt-template.md +54 -0
  58. package/dist/steps/execute/05-write-test.md +7 -0
  59. package/dist/steps/execute/06-write-code.md +8 -0
  60. package/dist/steps/execute/07-run-test.md +26 -0
  61. package/dist/steps/execute/08-fix-issues.md +28 -0
  62. package/dist/steps/execute/09-next-task.md +33 -0
  63. package/dist/steps/execute/manifest.yaml +28 -0
  64. package/dist/steps/plan/01-load-context.md +22 -0
  65. package/dist/steps/plan/02-anchor-confirm.md +1 -0
  66. package/dist/steps/plan/03-expand-tasks.md +33 -0
  67. package/dist/steps/plan/04-mark-order.md +15 -0
  68. package/dist/steps/plan/05-e2e-planning.md +17 -0
  69. package/dist/steps/plan/06-self-check.md +16 -0
  70. package/dist/steps/plan/07-save.md +1 -0
  71. package/dist/steps/plan/manifest.yaml +18 -0
  72. package/dist/steps/scan/01-env-detect.md +51 -0
  73. package/dist/steps/scan/02-tech-stack.md +16 -0
  74. package/dist/steps/scan/03-conventions.md +16 -0
  75. package/dist/steps/scan/04-structure.md +19 -0
  76. package/dist/steps/scan/05-quality.md +18 -0
  77. package/dist/steps/scan/06-complete.md +49 -0
  78. package/dist/steps/scan/manifest.yaml +16 -0
  79. package/dist/steps/verify/01-load-specs.md +28 -0
  80. package/dist/steps/verify/02-check-tasks.md +1 -0
  81. package/dist/steps/verify/03-check-design.md +6 -0
  82. package/dist/steps/verify/04-run-tests.md +7 -0
  83. package/dist/steps/verify/05-e2e-tests.md +27 -0
  84. package/dist/steps/verify/05b-e2e-fix.md +33 -0
  85. package/dist/steps/verify/06-code-quality.md +25 -0
  86. package/dist/steps/verify/07-lint-check.md +27 -0
  87. package/dist/steps/verify/08-output-report.md +14 -0
  88. package/dist/steps/verify/manifest.yaml +22 -0
  89. package/package.json +1 -7
  90. package/packages/dashboard/dist/assets/{index-Bq_Z2hne.js → index-D1EVTLmc.js} +1264 -1264
  91. package/packages/dashboard/dist/assets/index-DGe8CqeP.css +1 -0
  92. package/packages/dashboard/dist/index.html +2 -2
  93. package/packages/dashboard/package-lock.json +6 -6
  94. package/packages/dashboard/server/executor.js +1 -1
  95. package/packages/dashboard/server/index.js +18 -98
  96. package/packages/dashboard/server/parser.js +71 -139
  97. package/packages/dashboard/server/watcher.js +6 -14
  98. package/packages/dashboard/src/App.vue +185 -418
  99. package/packages/dashboard/src/components/ActionBar.vue +1 -10
  100. package/packages/dashboard/src/components/CommandPalette.vue +1 -5
  101. package/packages/dashboard/src/components/DocPreview.vue +8 -105
  102. package/packages/dashboard/src/components/DocTree.vue +19 -75
  103. package/packages/dashboard/src/components/PipelineStage.vue +2 -22
  104. package/packages/dashboard/src/components/PipelineView.vue +5 -32
  105. package/packages/dashboard/src/components/ProjectOverview.vue +139 -113
  106. package/packages/dashboard/src/components/StageBadge.vue +3 -17
  107. package/packages/dashboard/src/components/StepCard.vue +2 -7
  108. package/packages/dashboard/src/composables/useDashboard.js +0 -28
  109. package/src/derive.js +147 -0
  110. package/src/index.js +40 -688
  111. package/src/init.js +63 -119
  112. package/src/migrate.js +7 -7
  113. package/src/progress.js +248 -1474
  114. package/src/run.js +302 -3008
  115. package/src/setup.js +64 -2
  116. package/src/stages/archive.js +17 -123
  117. package/src/stages/brainstorm.js +48 -454
  118. package/src/stages/doctor.js +46 -99
  119. package/src/stages/execute.js +59 -420
  120. package/src/stages/index.js +18 -12
  121. package/src/stages/plan.js +189 -492
  122. package/src/stages/propose.js +11 -70
  123. package/src/stages/quick.js +13 -52
  124. package/src/stages/scan.js +68 -485
  125. package/src/stages/status.js +1 -1
  126. package/src/stages/verify.js +16 -203
  127. package/src/step.js +543 -0
  128. package/.claude/skills/sillyspec-knowledge/SKILL.md +0 -270
  129. package/.husky/pre-push +0 -13
  130. package/CLAUDE.md +0 -18
  131. package/docs/brainstorm-plan-contract.md +0 -64
  132. package/docs/plan-execute-contract.md +0 -123
  133. package/docs/platform-scan-protocol.md +0 -298
  134. package/docs/revision-mode.md +0 -115
  135. package/docs/sillyspec/file-lifecycle/known-implementation-gaps.md +0 -99
  136. package/docs/sillyspec/file-lifecycle/platform-workflows-sync.md +0 -218
  137. package/docs/sillyspec/file-lifecycle/stage-artifacts.md +0 -167
  138. package/docs/sillyspec/file-lifecycle/storage-and-state.md +0 -148
  139. package/docs/sillyspec/file-lifecycle/worktree-and-guard.md +0 -193
  140. package/docs/sillyspec/file-lifecycle.md +0 -125
  141. package/docs/workflow-contract-regression.md +0 -106
  142. package/docs/worktree-isolation.md +0 -252
  143. package/packages/dashboard/dist/assets/index-O2W5RV4z.css +0 -1
  144. package/packages/dashboard/dist/prototype-dashboard.html +0 -836
  145. package/packages/dashboard/dist/prototype-overview.html +0 -256
  146. package/packages/dashboard/public/prototype-dashboard.html +0 -836
  147. package/packages/dashboard/public/prototype-overview.html +0 -256
  148. package/packages/dashboard/src/components/HResizeHandle.vue +0 -48
  149. package/packages/dashboard/src/components/ProjectCard.vue +0 -187
  150. package/packages/dashboard/src/components/VResizeHandle.vue +0 -61
  151. package/packages/dashboard/src/composables/useLayout.js +0 -131
  152. package/src/brainstorm-postcheck.js +0 -158
  153. package/src/change-list.js +0 -52
  154. package/src/change-risk-profile.js +0 -352
  155. package/src/classify-change.js +0 -73
  156. package/src/constants.js +0 -70
  157. package/src/contract-matrix.js +0 -278
  158. package/src/db.js +0 -201
  159. package/src/endpoint-extractor.js +0 -315
  160. package/src/hooks/claude-pre-tool-use.cjs +0 -125
  161. package/src/hooks/worktree-guard.js +0 -761
  162. package/src/knowledge-match.js +0 -130
  163. package/src/modules.js +0 -482
  164. package/src/scan-postcheck.js +0 -383
  165. package/src/stage-contract.js +0 -700
  166. package/src/stages/brainstorm-auto.js +0 -229
  167. package/src/stages/explore.js +0 -34
  168. package/src/stages/knowledge.js +0 -498
  169. package/src/stages/plan-postcheck.js +0 -513
  170. package/src/sync.js +0 -497
  171. package/src/task-review.js +0 -346
  172. package/src/workflow.js +0 -785
  173. package/src/worktree-apply.js +0 -549
  174. package/src/worktree.js +0 -932
  175. package/templates/workflows/archive-impact.yaml +0 -79
  176. package/templates/workflows/scan-docs.yaml +0 -132
  177. package/test/brainstorm-plan-contract.test.mjs +0 -273
  178. package/test/check-syntax.mjs +0 -26
  179. package/test/cli-top-level-aliases.test.mjs +0 -174
  180. package/test/contract-artifacts.test.mjs +0 -323
  181. package/test/decision-supersede.test.mjs +0 -277
  182. package/test/knowledge-match.test.mjs +0 -231
  183. package/test/plan-execute-contract.test.mjs +0 -330
  184. package/test/plan-optimization.test.mjs +0 -572
  185. package/test/platform-artifacts.test.mjs +0 -190
  186. package/test/platform-failure-samples.test.mjs +0 -199
  187. package/test/platform-recovery-chain.test.mjs +0 -179
  188. package/test/platform-recovery.test.mjs +0 -167
  189. package/test/platform-scan-p0.test.mjs +0 -175
  190. package/test/revision-v1.test.mjs +0 -1145
  191. package/test/run-sanitize-project-name.test.mjs +0 -51
  192. package/test/run-scan-postcheck-fail.test.mjs +0 -64
  193. package/test/run-scan-project-parse.test.mjs +0 -200
  194. package/test/run-tests.mjs +0 -48
  195. package/test/scan-docs-yaml-placeholders.test.mjs +0 -84
  196. package/test/scan-knowledge.test.mjs +0 -175
  197. package/test/scan-paths.test.mjs +0 -68
  198. package/test/scan-postcheck-project-priority.test.mjs +0 -85
  199. package/test/scan-postcheck.test.mjs +0 -197
  200. package/test/scan-workflow-anyfailed-block.test.mjs +0 -52
  201. package/test/spec-dir.test.mjs +0 -206
  202. package/test/stage-contract-failed-post-check.test.mjs +0 -102
  203. package/test/stage-contract.test.mjs +0 -299
  204. package/test/stage-definitions.test.mjs +0 -39
  205. package/test/wait-gates.test.mjs +0 -501
  206. package/test/workflow-spec-base.test.mjs +0 -142
  207. package/test/worktree-guard.test.mjs +0 -136
  208. package/test/worktree-native-overlay.test.mjs +0 -188
@@ -1,79 +0,0 @@
1
- name: archive-impact
2
- description: 分析变更影响的模块并同步模块文档
3
- spec_version: 1
4
-
5
- roles:
6
- - id: impact-analyzer
7
- name: "影响分析"
8
- task: "分析 git diff,提取变更影响模块"
9
- inputs:
10
- paths: [".sillyspec/changes/", ".sillyspec/docs/*/modules/"]
11
- hints:
12
- grep_patterns: ["_module-map", "module-impact", "git diff"]
13
- outputs:
14
- - path: ".sillyspec/changes/<change-name>/module-impact.md"
15
- required: true
16
- checks:
17
- - type: file_exists
18
- - type: min_lines
19
- min: 20
20
- - type: contains_sections
21
- sections: ["模块影响矩阵", "未匹配文件"]
22
- constraints:
23
- - "以 git diff 为准(真实 > 声明)"
24
- - "影响类型:逻辑变更/数据结构变更/接口变更/调用关系变更/配置变更/新增"
25
- - "需要 review 标记不确定的影响"
26
-
27
- - id: doc-syncer
28
- name: "文档同步"
29
- task: "根据 module-impact.md 同步更新模块索引和卡片"
30
- depends_on:
31
- - impact-analyzer
32
- inputs:
33
- from_role: impact-analyzer
34
- output: module-impact
35
- output_description: "变更影响分析结果,包含模块影响矩阵"
36
- paths: [".sillyspec/docs/*/modules/"]
37
- hints:
38
- grep_patterns: ["_module-map", "module-impact"]
39
- outputs:
40
- - path: ".sillyspec/docs/sillyspec/modules/_module-map.yaml"
41
- required: false
42
- checks:
43
- - type: file_exists
44
- - path: ".sillyspec/docs/sillyspec/modules/<module-id>.md"
45
- required: false
46
- # checks 跳过:路径含动态 <module-id> 占位符,不适合静态检查
47
- constraints:
48
- - "结构化事实改 _module-map.yaml,语义解释改模块卡片"
49
- - "人工备注区域永远保护,不覆盖"
50
- - "更新前展示 diff 摘要,请用户确认"
51
-
52
- orchestration:
53
- mode: sequential
54
- timeout_per_role: 180
55
-
56
- checks:
57
- role_level:
58
- - type: file_exists
59
- - type: min_lines
60
- min: 10
61
- workflow_level:
62
- - type: file_exists
63
- path: ".sillyspec/changes/<change-name>/module-impact.md"
64
-
65
- retry:
66
- max_attempts: 1
67
- include_failure_context: true
68
- retry_scope: failed_role_only
69
-
70
- on_check_failure: prompt_retry
71
-
72
- permissions:
73
- write_mode: patch_only
74
- write_scope:
75
- - ".sillyspec/docs/"
76
- - ".sillyspec/changes/<change-name>/"
77
- allow_shell: true
78
- allow_network: false
79
- allow_git: true
@@ -1,132 +0,0 @@
1
- name: scan-docs
2
- description: 并行生成项目的扫描文档(7份)
3
- spec_version: 1
4
-
5
- roles:
6
- - id: arch
7
- name: "技术架构"
8
- task: "生成 ARCHITECTURE.md"
9
- inputs:
10
- paths:
11
- - "src/*.js"
12
- - "package.json"
13
- hints:
14
- grep_patterns: ["class ", "export ", "import ", "schema", "CREATE TABLE"]
15
- outputs:
16
- - path: "{SPEC_ROOT}/docs/<project>/scan/ARCHITECTURE.md"
17
- required: true
18
- checks:
19
- - type: file_exists
20
- - type: min_lines
21
- min: 20
22
- - type: contains_sections
23
- sections: ["技术栈", "架构概览"]
24
- constraints:
25
- - "禁止读源码全文,只用 grep/rg 搜索"
26
- - "Schema 只记表名+说明+字段数"
27
-
28
- - id: conventions
29
- name: "代码约定"
30
- task: "生成 CONVENTIONS.md"
31
- inputs:
32
- paths: ["src/"]
33
- hints:
34
- grep_patterns: ["function ", "const ", "async ", "try ", "catch "]
35
- outputs:
36
- - path: "{SPEC_ROOT}/docs/<project>/scan/CONVENTIONS.md"
37
- required: true
38
- checks:
39
- - type: file_exists
40
- - type: min_lines
41
- min: 15
42
- - type: contains_sections
43
- sections: ["框架隐形规则", "代码风格"]
44
- constraints:
45
- - "禁止读源码全文"
46
- - "提取 3-5 个典型模式"
47
-
48
- - id: structure
49
- name: "目录结构+外部集成"
50
- task: "生成 STRUCTURE.md 和 INTEGRATIONS.md"
51
- inputs:
52
- paths: ["./"]
53
- hints:
54
- grep_patterns: ["fetch", "http", "WebSocket", "ws", "chokidar"]
55
- outputs:
56
- - path: "{SPEC_ROOT}/docs/<project>/scan/STRUCTURE.md"
57
- required: true
58
- checks:
59
- - type: file_exists
60
- - type: min_lines
61
- min: 15
62
- - path: "{SPEC_ROOT}/docs/<project>/scan/INTEGRATIONS.md"
63
- required: true
64
- checks:
65
- - type: file_exists
66
- - type: min_lines
67
- min: 15
68
- constraints:
69
- - "STRUCTURE: 目录树+模块说明"
70
- - "INTEGRATIONS: 按类型分组外部依赖"
71
-
72
- - id: quality
73
- name: "测试+债务+概览"
74
- task: "生成 TESTING.md、CONCERNS.md、PROJECT.md"
75
- inputs:
76
- paths: ["src/", "packages/"]
77
- hints:
78
- grep_patterns: ["TODO", "FIXME", "deprecated", "test", "describe"]
79
- outputs:
80
- - path: "{SPEC_ROOT}/docs/<project>/scan/TESTING.md"
81
- required: true
82
- checks:
83
- - type: file_exists
84
- - type: min_lines
85
- min: 10
86
- - type: no_placeholder
87
- - path: "{SPEC_ROOT}/docs/<project>/scan/CONCERNS.md"
88
- required: true
89
- checks:
90
- - type: file_exists
91
- - type: min_lines
92
- min: 10
93
- - type: contains_sections
94
- sections: ["代码质量", "依赖风险"]
95
- - path: "{SPEC_ROOT}/docs/<project>/scan/PROJECT.md"
96
- required: true
97
- checks:
98
- - type: file_exists
99
- - type: min_lines
100
- min: 15
101
- - type: contains_sections
102
- sections: ["项目简介", "技术栈"]
103
- constraints:
104
- - "CONCERNS 按严重程度分组(🔴/🟡/🟢)"
105
- - "不编造不存在的测试"
106
-
107
- orchestration:
108
- mode: parallel
109
- max_concurrent: 4
110
- timeout_per_role: 120
111
-
112
- checks:
113
- workflow_level:
114
- - type: file_count
115
- path: "scan/"
116
- min: 7
117
- - type: no_empty_files
118
-
119
- retry:
120
- max_attempts: 1
121
- include_failure_context: true
122
- retry_scope: failed_role_only
123
-
124
- on_check_failure: prompt_retry
125
-
126
- permissions:
127
- write_mode: direct
128
- write_scope:
129
- - "{SPEC_ROOT}/docs/<project>/scan/"
130
- allow_shell: true
131
- allow_network: false
132
- allow_git: false
@@ -1,273 +0,0 @@
1
- /**
2
- * Brainstorm → Plan Contract v1 测试
3
- *
4
- * 验证 design.md 到 plan 的输入契约:
5
- * 1. 合法 design 通过
6
- * 2. 缺关键章节失败
7
- * 3. warning 不阻断
8
- */
9
- import { validateDesignForPlan } from '../src/stages/plan.js'
10
-
11
- let failed = 0
12
- const failures = []
13
-
14
- function assert(condition, msg) {
15
- if (!condition) {
16
- failed++
17
- failures.push(msg)
18
- console.log(` ❌ FAIL: ${msg}`)
19
- } else {
20
- console.log(` ✅ PASS: ${msg}`)
21
- }
22
- }
23
-
24
- console.log('=== Brainstorm → Plan Contract v1 测试 ===\n')
25
-
26
- // ─────────────────────────────────────────
27
- // Case 1: valid design 通过
28
- // ─────────────────────────────────────────
29
- console.log('--- Case 1: valid design 通过 ---')
30
- {
31
- const design = `# Design: 用户认证系统
32
-
33
- ## 背景
34
- 需要实现用户认证。
35
-
36
- ## 设计目标
37
- - 支持 OAuth2
38
- - 支持手机号登录
39
-
40
- ## 非目标
41
- - 不做 SSO
42
-
43
- ## 总体方案
44
- 使用 JWT + Refresh Token。
45
-
46
- ## 决策
47
- - D-001@v1: 选择 JWT 而非 Session
48
-
49
- ## 约束
50
- - 必须兼容现有 API
51
-
52
- ## 文件变更清单
53
- | 操作 | 文件路径 | 说明 |
54
- |------|---------|------|
55
- | 新增 | src/auth.js | 认证模块 |
56
- `
57
- const result = validateDesignForPlan(design)
58
- assert(result.ok, '完整 design 应校验通过')
59
- assert(result.errors.length === 0, '不应有 errors')
60
- assert(result.warnings.length === 0, '不应有 warnings')
61
- }
62
-
63
- // ─────────────────────────────────────────
64
- // Case 2: empty design 失败
65
- // ─────────────────────────────────────────
66
- console.log('\n--- Case 2: empty design 失败 ---')
67
- {
68
- assert(!validateDesignForPlan('').ok, '空字符串应失败')
69
- assert(!validateDesignForPlan(null).ok, 'null 应失败')
70
- assert(!validateDesignForPlan(' ').ok, '纯空格应失败')
71
- }
72
-
73
- // ─────────────────────────────────────────
74
- // Case 3: missing goal 失败
75
- // ─────────────────────────────────────────
76
- console.log('\n--- Case 3: missing goal/背景 失败 ---')
77
- {
78
- const design = `# Design
79
-
80
- ## 总体方案
81
- 用 JWT。
82
-
83
- ## 决策
84
- D-001@v1: 选 JWT
85
- `
86
- const result = validateDesignForPlan(design)
87
- assert(!result.ok, '缺目标/背景应失败')
88
- assert(result.errors.some(e => e.includes('目标') || e.includes('背景')), '错误应提到目标/背景')
89
- }
90
-
91
- // ─────────────────────────────────────────
92
- // Case 4: missing scope/方案 失败
93
- // ─────────────────────────────────────────
94
- console.log('\n--- Case 4: missing scope/方案 失败 ---')
95
- {
96
- const design = `# Design
97
-
98
- ## 背景
99
- 需要认证。
100
-
101
- ## 决策
102
- D-001@v1: 选 JWT
103
- `
104
- const result = validateDesignForPlan(design)
105
- assert(!result.ok, '缺范围/方案应失败')
106
- assert(result.errors.some(e => e.includes('范围') || e.includes('方案')), '错误应提到范围/方案')
107
- }
108
-
109
- // ─────────────────────────────────────────
110
- // Case 5: missing decisions 失败
111
- // ─────────────────────────────────────────
112
- console.log('\n--- Case 5: missing decisions 失败 ---')
113
- {
114
- const design = `# Design
115
-
116
- ## 背景
117
- 需要认证。
118
-
119
- ## 总体方案
120
- 用 JWT。
121
- `
122
- const result = validateDesignForPlan(design)
123
- assert(!result.ok, '缺决策应失败')
124
- assert(result.errors.some(e => e.includes('决策')), '错误应提到决策')
125
- }
126
-
127
- // ─────────────────────────────────────────
128
- // Case 6: decisions.md 引用也算决策
129
- // ─────────────────────────────────────────
130
- console.log('\n--- Case 6: decisions.md 引用算决策 ---')
131
- {
132
- const design = `# Design
133
-
134
- ## 背景
135
- 需要认证。
136
-
137
- ## 总体方案
138
- 用 JWT。详见 decisions.md。
139
-
140
- ## 文件变更清单
141
- | 操作 | 文件 | 说明 |
142
- `
143
- const result = validateDesignForPlan(design)
144
- assert(result.ok, 'decisions.md 引用应满足决策检查')
145
- }
146
-
147
- // ─────────────────────────────────────────
148
- // Case 7: missing non-goals 只有 warning
149
- // ─────────────────────────────────────────
150
- console.log('\n--- Case 7: missing non-goals warning ---')
151
- {
152
- const design = `# Design
153
-
154
- ## 背景
155
- 需要认证。
156
-
157
- ## 总体方案
158
- 用 JWT。
159
-
160
- ## 决策
161
- D-001@v1: 选 JWT
162
-
163
- ## 约束
164
- 必须兼容现有 API。
165
- `
166
- const result = validateDesignForPlan(design)
167
- assert(result.ok, '缺非目标不应阻断')
168
- assert(result.warnings.some(w => w.includes('非目标') || w.includes('Non-goals')), '应有非目标 warning')
169
- }
170
-
171
- // ─────────────────────────────────────────
172
- // Case 8: missing constraints 只有 warning
173
- // ─────────────────────────────────────────
174
- console.log('\n--- Case 8: missing constraints warning ---')
175
- {
176
- const design = `# Design
177
-
178
- ## 目标
179
- 实现认证。
180
-
181
- ## 设计方案
182
- 用 JWT。
183
-
184
- ## 决策
185
- 选择 JWT。
186
-
187
- ## 非目标
188
- 不做 SSO。
189
- `
190
- const result = validateDesignForPlan(design)
191
- assert(result.ok, '缺约束不应阻断')
192
- assert(result.warnings.some(w => w.includes('约束') || w.includes('风险') || w.includes('Trade-off')), '应有约束/风险 warning')
193
- }
194
-
195
- // ─────────────────────────────────────────
196
- // Case 9: missing 文件变更清单 warning
197
- // ─────────────────────────────────────────
198
- console.log('\n--- Case 9: missing 文件变更清单 warning ---')
199
- {
200
- const design = `# Design
201
-
202
- ## 背景
203
- 需要认证。
204
-
205
- ## 总体方案
206
- 用 JWT。
207
-
208
- ## 决策
209
- D-001@v1: 选 JWT
210
- `
211
- const result = validateDesignForPlan(design)
212
- assert(result.ok, '缺文件变更清单不应阻断')
213
- assert(result.warnings.some(w => w.includes('文件变更')), '应有文件变更 warning')
214
- }
215
-
216
- // ─────────────────────────────────────────
217
- // Case 10: 英文 design 通过
218
- // ─────────────────────────────────────────
219
- console.log('\n--- Case 10: 英文 design 通过 ---')
220
- {
221
- const design = `# Design: Auth System
222
-
223
- ## Background
224
- We need authentication.
225
-
226
- ## Solution
227
- Use JWT + Refresh Token.
228
-
229
- ## Decision
230
- D-001@v1: Choose JWT over Session
231
-
232
- ## Non-goals
233
- No SSO.
234
-
235
- ## Constraints
236
- Must be backwards compatible.
237
- `
238
- const result = validateDesignForPlan(design)
239
- assert(result.ok, '英文 design 应校验通过')
240
- assert(result.errors.length === 0, '不应有 errors')
241
- }
242
-
243
- // ─────────────────────────────────────────
244
- // Case 11: 最小合法 design
245
- // ─────────────────────────────────────────
246
- console.log('\n--- Case 11: 最小合法 design ---')
247
- {
248
- const design = `# Design
249
-
250
- ## 目标
251
- 修 bug。
252
-
253
- ## 方案
254
- 改代码。
255
-
256
- ## 决策
257
- D-001@v1: 直接改。
258
- `
259
- const result = validateDesignForPlan(design)
260
- assert(result.ok, '最小合法 design 应通过')
261
- // 可能有 warning 但 ok
262
- }
263
-
264
- // ── 结果 ──
265
- console.log(`\n${'='.repeat(50)}`)
266
- console.log(`✅ 通过: ${11 - failed} ❌ 失败: ${failed}`)
267
- if (failures.length > 0) {
268
- console.log(`失败项:`)
269
- failures.forEach(f => console.log(` - ${f}`))
270
- }
271
- console.log(`${'='.repeat(50)}`)
272
-
273
- if (failed > 0) process.exit(1)
@@ -1,26 +0,0 @@
1
- import { execFileSync } from 'node:child_process'
2
- import { readdirSync, statSync } from 'node:fs'
3
- import { join } from 'node:path'
4
-
5
- const roots = ['src']
6
- const files = []
7
-
8
- function walk(dir) {
9
- for (const entry of readdirSync(dir)) {
10
- const full = join(dir, entry)
11
- const st = statSync(full)
12
- if (st.isDirectory()) {
13
- walk(full)
14
- continue
15
- }
16
- if (/\.(js|cjs|mjs)$/.test(entry)) files.push(full)
17
- }
18
- }
19
-
20
- for (const root of roots) walk(root)
21
-
22
- for (const file of files.sort()) {
23
- execFileSync(process.execPath, ['--check', file], { stdio: 'inherit' })
24
- }
25
-
26
- console.log(`Checked ${files.length} JavaScript files`)
@@ -1,174 +0,0 @@
1
- /**
2
- * task-10: 顶层命令别名 doctor/scan/status/quick/explore 转发 runCommand
3
- *
4
- * 设计依据:task-10.md §TDD + §验收标准
5
- * - sillyspec doctor / scan / status / quick / explore 不再落 default 分支报"未知命令"
6
- * - 行为与 sillyspec run <stage> 字节一致
7
- * - sillyspec worktree doctor 仍走 worktree 分支
8
- * - sillyspec foobar 仍报未知命令
9
- *
10
- * 断言策略:
11
- * stage 在空目录下可能因无 .sillyspec 进度而 exit != 0(这是 stage 自身行为,
12
- * 不属于本任务路由范围)。因此测试只验证"路由正确"——即 stderr 不含"未知命令"
13
- * 字样(default 分支的特征文案),并且 doctor/scan 两路 stdout 字节一致。
14
- */
15
-
16
- import { spawnSync } from 'node:child_process'
17
- import { mkdirSync, rmSync } from 'node:fs'
18
- import { join, resolve, dirname } from 'node:path'
19
- import { tmpdir } from 'node:os'
20
- import { fileURLToPath } from 'node:url'
21
-
22
- const __filename = fileURLToPath(import.meta.url)
23
- const __dirname = dirname(__filename)
24
- const cliBin = resolve(__dirname, '..', 'bin', 'sillyspec.js')
25
-
26
- let passed = 0
27
- let failed = 0
28
-
29
- function assert(cond, msg) {
30
- if (cond) {
31
- console.log(` ✅ PASS: ${msg}`)
32
- passed++
33
- } else {
34
- console.log(` ❌ FAIL: ${msg}`)
35
- failed++
36
- }
37
- }
38
-
39
- function runCLI(args, cwd) {
40
- const res = spawnSync(process.execPath, [cliBin, ...args], {
41
- cwd,
42
- encoding: 'utf8',
43
- timeout: 15000,
44
- stdio: ['pipe', 'pipe', 'pipe'],
45
- })
46
- return {
47
- stdout: res.stdout || '',
48
- stderr: res.stderr || '',
49
- status: res.status,
50
- combined: (res.stdout || '') + (res.stderr || ''),
51
- }
52
- }
53
-
54
- function cleanSillySpec(cwd) {
55
- // 清掉 sillyspec 写入 cwd 的进度副作用,保证两路字节级环境一致
56
- try { rmSync(join(cwd, '.sillyspec'), { recursive: true, force: true }) } catch {}
57
- try { rmSync(join(cwd, '.sillyspec-platform.json'), { force: true }) } catch {}
58
- }
59
-
60
- const tmpRoot = join(tmpdir(), `sillyspec-cli-aliases-${Date.now()}`)
61
- mkdirSync(tmpRoot, { recursive: true })
62
-
63
- try {
64
- // ── Red/Green: 5 个顶层命令不再报"未知命令" ──
65
- const aliases = ['doctor', 'scan', 'status', 'quick', 'explore']
66
- console.log('\n=== Test 1: 顶层命令别名不落 default 分支 ===')
67
- for (const stage of aliases) {
68
- const res = runCLI([stage], tmpRoot)
69
- const hitUnknown =
70
- res.combined.includes('未知命令') ||
71
- /unknown command/i.test(res.combined)
72
- assert(
73
- !hitUnknown,
74
- `sillyspec ${stage} 不报"未知命令" (exit=${res.status})`
75
- )
76
- }
77
-
78
- // ── Green: doctor 顶层别名 与 sillyspec run doctor 字节一致 ──
79
- // 两路必须在字节级相同环境下运行:同 cwd + 每次跑前清空 .sillyspec
80
- // (否则 progress 持久化会让第二次跑读到旧数据触发平台同步检查)
81
- console.log('\n=== Test 2: sillyspec doctor 与 sillyspec run doctor 等价 ===')
82
- {
83
- const cwd = join(tmpRoot, 'doctor-cmp')
84
- mkdirSync(cwd, { recursive: true })
85
- cleanSillySpec(cwd)
86
- const top = runCLI(['doctor'], cwd)
87
- cleanSillySpec(cwd)
88
- const viaRun = runCLI(['run', 'doctor'], cwd)
89
- assert(
90
- top.status === viaRun.status,
91
- `exit code 一致: doctor=${top.status}, run doctor=${viaRun.status}`
92
- )
93
- assert(
94
- top.stdout === viaRun.stdout,
95
- `stdout 字节一致 (len=${top.stdout.length})`
96
- )
97
- assert(
98
- top.stderr === viaRun.stderr,
99
- `stderr 字节一致 (len=${top.stderr.length})`
100
- )
101
- }
102
-
103
- // ── Green: scan 顶层别名 与 sillyspec run scan 字节一致 ──
104
- console.log('\n=== Test 3: sillyspec scan 与 sillyspec run scan 等价 ===')
105
- {
106
- const cwd = join(tmpRoot, 'scan-cmp')
107
- mkdirSync(cwd, { recursive: true })
108
- cleanSillySpec(cwd)
109
- const top = runCLI(['scan'], cwd)
110
- cleanSillySpec(cwd)
111
- const viaRun = runCLI(['run', 'scan'], cwd)
112
- assert(
113
- top.status === viaRun.status,
114
- `exit code 一致: scan=${top.status}, run scan=${viaRun.status}`
115
- )
116
- assert(
117
- top.stdout === viaRun.stdout,
118
- `stdout 字节一致 (len=${top.stdout.length})`
119
- )
120
- }
121
-
122
- // ── 回归: worktree doctor 走 worktree 分支(与顶层 doctor 不同) ──
123
- console.log('\n=== Test 4: sillyspec worktree doctor 走 worktree 分支 ===')
124
- {
125
- const res = runCLI(['worktree', 'doctor'], tmpRoot)
126
- // worktree doctor 不应报顶层 default 的"未知命令",也不应报"未知阶段"
127
- const hitUnknownCmd =
128
- res.combined.includes('未知命令') && !/worktree/.test(res.combined)
129
- assert(!hitUnknownCmd, `worktree doctor 不报顶层未知命令`)
130
- // worktree 子命令 default 分支会输出"未知子命令: worktree",这里 doctor 合法不应出现
131
- assert(
132
- !res.combined.includes('未知子命令'),
133
- `worktree doctor 不是未知子命令`
134
- )
135
- }
136
-
137
- // ── 回归: foobar 仍落 default 报未知命令 ──
138
- console.log('\n=== Test 5: sillyspec foobar 仍报未知命令 ===')
139
- {
140
- const res = runCLI(['foobar'], tmpRoot)
141
- assert(
142
- res.combined.includes('未知命令'),
143
- `foobar 命中 default 分支,报"未知命令"`
144
- )
145
- assert(
146
- res.status !== 0,
147
- `foobar exit code 非 0 (got ${res.status})`
148
- )
149
- }
150
-
151
- // ── 选项透传: sillyspec doctor --json 与 sillyspec run doctor --json 等价 ──
152
- console.log('\n=== Test 6: doctor --json 选项透传正确 ===')
153
- {
154
- const top = runCLI(['doctor', '--json'], tmpRoot)
155
- const viaRun = runCLI(['run', 'doctor', '--json'], tmpRoot)
156
- assert(
157
- top.stdout === viaRun.stdout,
158
- `doctor --json stdout 与 run doctor --json 一致 (len=${top.stdout.length})`
159
- )
160
- assert(
161
- top.status === viaRun.status,
162
- `doctor --json exit 与 run doctor --json 一致`
163
- )
164
- }
165
- } finally {
166
- try {
167
- rmSync(tmpRoot, { recursive: true, force: true })
168
- } catch {}
169
- }
170
-
171
- console.log(`\n${'='.repeat(50)}`)
172
- console.log(`✅ 通过: ${passed} ❌ 失败: ${failed}`)
173
- console.log(`${'='.repeat(50)}`)
174
- process.exit(failed > 0 ? 1 : 0)