sillyspec 3.20.3 → 3.20.5

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 (225) hide show
  1. package/.claude/skills/sillyspec-archive/SKILL.md +21 -17
  2. package/.claude/skills/sillyspec-auto/SKILL.md +83 -77
  3. package/.claude/skills/sillyspec-brainstorm/SKILL.md +44 -17
  4. package/.claude/skills/sillyspec-commit/SKILL.md +106 -105
  5. package/.claude/skills/sillyspec-continue/SKILL.md +45 -44
  6. package/.claude/skills/sillyspec-doctor/SKILL.md +31 -22
  7. package/.claude/skills/sillyspec-execute/SKILL.md +30 -17
  8. package/.claude/skills/sillyspec-explore/SKILL.md +109 -96
  9. package/.claude/skills/sillyspec-knowledge/SKILL.md +270 -0
  10. package/.claude/skills/sillyspec-plan/SKILL.md +21 -52
  11. package/.claude/skills/sillyspec-propose/SKILL.md +21 -17
  12. package/.claude/skills/sillyspec-quick/SKILL.md +21 -17
  13. package/.claude/skills/sillyspec-resume/SKILL.md +68 -111
  14. package/.claude/skills/sillyspec-scan/SKILL.md +21 -17
  15. package/.claude/skills/sillyspec-state/SKILL.md +54 -54
  16. package/.claude/skills/sillyspec-status/SKILL.md +21 -17
  17. package/.claude/skills/sillyspec-verify/SKILL.md +21 -17
  18. package/.claude/skills/sillyspec-workspace/SKILL.md +157 -149
  19. package/.husky/pre-push +13 -0
  20. package/CLAUDE.md +18 -0
  21. package/README.md +198 -186
  22. package/SKILL.md +90 -87
  23. package/bin/sillyspec.js +2 -2
  24. package/docs/brainstorm-plan-contract.md +64 -0
  25. package/docs/plan-execute-contract.md +123 -0
  26. package/docs/platform-scan-protocol.md +298 -0
  27. package/docs/revision-mode.md +115 -0
  28. package/docs/sillyspec/file-lifecycle/known-implementation-gaps.md +99 -0
  29. package/docs/sillyspec/file-lifecycle/platform-workflows-sync.md +218 -0
  30. package/docs/sillyspec/file-lifecycle/stage-artifacts.md +167 -0
  31. package/docs/sillyspec/file-lifecycle/storage-and-state.md +148 -0
  32. package/docs/sillyspec/file-lifecycle/worktree-and-guard.md +211 -0
  33. package/docs/sillyspec/file-lifecycle.md +131 -0
  34. package/docs/workflow-contract-regression.md +106 -0
  35. package/docs/worktree-isolation.md +252 -0
  36. package/package.json +40 -34
  37. package/packages/dashboard/dist/assets/{index-D1EVTLmc.js → index-Bq_Z2hne.js} +7446 -7446
  38. package/packages/dashboard/dist/assets/index-O2W5RV4z.css +1 -0
  39. package/packages/dashboard/dist/index.html +16 -16
  40. package/packages/dashboard/dist/prototype-dashboard.html +836 -0
  41. package/packages/dashboard/dist/prototype-overview.html +256 -0
  42. package/packages/dashboard/index.html +15 -15
  43. package/packages/dashboard/package-lock.json +2384 -2384
  44. package/packages/dashboard/package.json +25 -25
  45. package/packages/dashboard/public/prototype-dashboard.html +836 -0
  46. package/packages/dashboard/public/prototype-overview.html +256 -0
  47. package/packages/dashboard/server/executor.js +86 -86
  48. package/packages/dashboard/server/index.js +588 -508
  49. package/packages/dashboard/server/parser.js +526 -458
  50. package/packages/dashboard/server/watcher.js +350 -342
  51. package/packages/dashboard/src/App.vue +558 -325
  52. package/packages/dashboard/src/components/ActionBar.vue +93 -84
  53. package/packages/dashboard/src/components/CommandPalette.vue +96 -92
  54. package/packages/dashboard/src/components/DetailPanel.vue +137 -137
  55. package/packages/dashboard/src/components/DocPreview.vue +105 -8
  56. package/packages/dashboard/src/components/DocTree.vue +75 -19
  57. package/packages/dashboard/src/components/HResizeHandle.vue +48 -0
  58. package/packages/dashboard/src/components/LogStream.vue +65 -65
  59. package/packages/dashboard/src/components/PipelineStage.vue +95 -75
  60. package/packages/dashboard/src/components/PipelineView.vue +156 -129
  61. package/packages/dashboard/src/components/ProjectCard.vue +187 -0
  62. package/packages/dashboard/src/components/ProjectList.vue +210 -210
  63. package/packages/dashboard/src/components/ProjectOverview.vue +113 -139
  64. package/packages/dashboard/src/components/StageBadge.vue +67 -53
  65. package/packages/dashboard/src/components/StepCard.vue +94 -89
  66. package/packages/dashboard/src/components/VResizeHandle.vue +61 -0
  67. package/packages/dashboard/src/components/detail/DocsDetail.vue +48 -48
  68. package/packages/dashboard/src/components/detail/GitDetail.vue +61 -61
  69. package/packages/dashboard/src/components/detail/TechDetail.vue +43 -43
  70. package/packages/dashboard/src/composables/useDashboard.js +192 -164
  71. package/packages/dashboard/src/composables/useKeyboard.js +119 -119
  72. package/packages/dashboard/src/composables/useLayout.js +131 -0
  73. package/packages/dashboard/src/composables/useWebSocket.js +129 -129
  74. package/packages/dashboard/src/main.js +8 -8
  75. package/packages/dashboard/src/style.css +132 -132
  76. package/packages/dashboard/vite.config.js +18 -18
  77. package/src/brainstorm-postcheck.js +158 -0
  78. package/src/change-list.js +52 -0
  79. package/src/change-risk-profile.js +352 -0
  80. package/src/classify-change.js +73 -0
  81. package/src/constants.js +70 -0
  82. package/src/contract-matrix.js +278 -0
  83. package/src/db.js +201 -0
  84. package/src/endpoint-extractor.js +315 -0
  85. package/src/hooks/claude-pre-tool-use.cjs +125 -0
  86. package/src/hooks/worktree-guard.js +761 -0
  87. package/src/index.js +922 -252
  88. package/src/init.js +470 -375
  89. package/src/knowledge-match.js +130 -0
  90. package/src/migrate.js +117 -117
  91. package/src/modules.js +482 -0
  92. package/src/progress.js +1734 -508
  93. package/src/run.js +3465 -652
  94. package/src/scan-postcheck.js +387 -0
  95. package/src/setup.js +398 -460
  96. package/src/stage-contract.js +700 -0
  97. package/src/stages/archive.js +160 -54
  98. package/src/stages/brainstorm-auto.js +229 -0
  99. package/src/stages/brainstorm.js +645 -239
  100. package/src/stages/doctor.js +365 -312
  101. package/src/stages/execute.js +634 -264
  102. package/src/stages/explore.js +34 -0
  103. package/src/stages/index.js +29 -35
  104. package/src/stages/knowledge.js +498 -0
  105. package/src/stages/plan-postcheck.js +518 -0
  106. package/src/stages/plan.js +582 -279
  107. package/src/stages/propose.js +174 -115
  108. package/src/stages/quick.js +102 -63
  109. package/src/stages/scan.js +558 -141
  110. package/src/stages/status.js +65 -65
  111. package/src/stages/verify.js +322 -135
  112. package/src/sync.js +497 -0
  113. package/src/task-review.js +346 -0
  114. package/src/workflow.js +785 -0
  115. package/src/worktree-apply.js +549 -0
  116. package/src/worktree-deps.js +185 -0
  117. package/src/worktree.js +982 -0
  118. package/templates/workflows/archive-impact.yaml +79 -0
  119. package/templates/workflows/scan-docs.yaml +132 -0
  120. package/test/brainstorm-plan-contract.test.mjs +273 -0
  121. package/test/check-syntax.mjs +26 -0
  122. package/test/cli-top-level-aliases.test.mjs +174 -0
  123. package/test/contract-artifacts.test.mjs +323 -0
  124. package/test/decision-supersede.test.mjs +277 -0
  125. package/test/knowledge-match.test.mjs +231 -0
  126. package/test/plan-execute-contract.test.mjs +357 -0
  127. package/test/plan-optimization.test.mjs +572 -0
  128. package/test/platform-artifacts.test.mjs +190 -0
  129. package/test/platform-failure-samples.test.mjs +199 -0
  130. package/test/platform-recovery-chain.test.mjs +179 -0
  131. package/test/platform-recovery.test.mjs +167 -0
  132. package/test/platform-scan-p0.test.mjs +175 -0
  133. package/test/revision-v1.test.mjs +1145 -0
  134. package/test/run-sanitize-project-name.test.mjs +51 -0
  135. package/test/run-scan-postcheck-fail.test.mjs +64 -0
  136. package/test/run-scan-project-parse.test.mjs +200 -0
  137. package/test/run-tests.mjs +48 -0
  138. package/test/runtime-cleanup-keeps-worktree.test.mjs +107 -0
  139. package/test/scan-docs-yaml-placeholders.test.mjs +84 -0
  140. package/test/scan-knowledge.test.mjs +175 -0
  141. package/test/scan-paths.test.mjs +68 -0
  142. package/test/scan-postcheck-project-priority.test.mjs +85 -0
  143. package/test/scan-postcheck.test.mjs +197 -0
  144. package/test/scan-workflow-anyfailed-block.test.mjs +52 -0
  145. package/test/spec-dir.test.mjs +206 -0
  146. package/test/stage-contract-failed-post-check.test.mjs +102 -0
  147. package/test/stage-contract.test.mjs +299 -0
  148. package/test/stage-definitions.test.mjs +39 -0
  149. package/test/wait-gates.test.mjs +501 -0
  150. package/test/workflow-spec-base.test.mjs +142 -0
  151. package/test/worktree-deps-provision.test.mjs +148 -0
  152. package/test/worktree-guard.test.mjs +136 -0
  153. package/test/worktree-native-overlay.test.mjs +188 -0
  154. package/.sillyspec/changes/archive/2026-04-08-derive-state/design.md +0 -97
  155. package/.sillyspec/changes/archive/2026-04-08-derive-state/plan.md +0 -51
  156. package/.sillyspec/changes/archive/2026-04-08-derive-state/proposal.md +0 -29
  157. package/.sillyspec/changes/archive/2026-04-08-derive-state/requirements.md +0 -34
  158. package/.sillyspec/changes/archive/2026-04-08-derive-state/tasks.md +0 -13
  159. package/.sillyspec/changes/archive/2026-04-08-derive-state/verify-result.md +0 -43
  160. package/.sillyspec/changes/auto-mode/design.md +0 -50
  161. package/.sillyspec/changes/auto-mode/proposal.md +0 -19
  162. package/.sillyspec/changes/auto-mode/requirements.md +0 -21
  163. package/.sillyspec/changes/auto-mode/tasks.md +0 -7
  164. package/.sillyspec/changes/brainstorm-archive/2026-04-05-dashboard-design.md +0 -206
  165. package/.sillyspec/changes/brainstorm-archive/2026-04-05-unified-docs-design.md +0 -199
  166. package/.sillyspec/changes/dashboard/design.md +0 -219
  167. package/.sillyspec/changes/dashboard/design.md.braindraft +0 -206
  168. package/.sillyspec/changes/run-command-design/design.md +0 -1230
  169. package/.sillyspec/changes/unified-docs-design/design.md +0 -199
  170. package/.sillyspec/docs/sillyspec/scan/.gitkeep +0 -0
  171. package/.sillyspec/knowledge/INDEX.md +0 -8
  172. package/.sillyspec/knowledge/uncategorized.md +0 -3
  173. package/.sillyspec/plans/2026-04-05-dashboard.md +0 -737
  174. package/.sillyspec/projects/sillyspec.yaml +0 -3
  175. package/dist/steps/brainstorm/01-load-context.md +0 -30
  176. package/dist/steps/brainstorm/02-reuse-check.md +0 -6
  177. package/dist/steps/brainstorm/03-prototype-analysis.md +0 -11
  178. package/dist/steps/brainstorm/04-module-split.md +0 -23
  179. package/dist/steps/brainstorm/05-dialog-explore.md +0 -8
  180. package/dist/steps/brainstorm/06-propose-approaches.md +0 -3
  181. package/dist/steps/brainstorm/07-present-design.md +0 -3
  182. package/dist/steps/brainstorm/08-write-design.md +0 -21
  183. package/dist/steps/brainstorm/09-self-review.md +0 -15
  184. package/dist/steps/brainstorm/10-user-confirm.md +0 -3
  185. package/dist/steps/brainstorm/11-output-spec.md +0 -7
  186. package/dist/steps/brainstorm/manifest.yaml +0 -26
  187. package/dist/steps/execute/01-load-context.md +0 -41
  188. package/dist/steps/execute/02-scan-conventions.md +0 -47
  189. package/dist/steps/execute/03-skill-mcp.md +0 -19
  190. package/dist/steps/execute/04-assign-task.md +0 -22
  191. package/dist/steps/execute/04b-prompt-template.md +0 -54
  192. package/dist/steps/execute/05-write-test.md +0 -7
  193. package/dist/steps/execute/06-write-code.md +0 -8
  194. package/dist/steps/execute/07-run-test.md +0 -26
  195. package/dist/steps/execute/08-fix-issues.md +0 -28
  196. package/dist/steps/execute/09-next-task.md +0 -33
  197. package/dist/steps/execute/manifest.yaml +0 -28
  198. package/dist/steps/plan/01-load-context.md +0 -22
  199. package/dist/steps/plan/02-anchor-confirm.md +0 -1
  200. package/dist/steps/plan/03-expand-tasks.md +0 -33
  201. package/dist/steps/plan/04-mark-order.md +0 -15
  202. package/dist/steps/plan/05-e2e-planning.md +0 -17
  203. package/dist/steps/plan/06-self-check.md +0 -16
  204. package/dist/steps/plan/07-save.md +0 -1
  205. package/dist/steps/plan/manifest.yaml +0 -18
  206. package/dist/steps/scan/01-env-detect.md +0 -51
  207. package/dist/steps/scan/02-tech-stack.md +0 -16
  208. package/dist/steps/scan/03-conventions.md +0 -16
  209. package/dist/steps/scan/04-structure.md +0 -19
  210. package/dist/steps/scan/05-quality.md +0 -18
  211. package/dist/steps/scan/06-complete.md +0 -49
  212. package/dist/steps/scan/manifest.yaml +0 -16
  213. package/dist/steps/verify/01-load-specs.md +0 -28
  214. package/dist/steps/verify/02-check-tasks.md +0 -1
  215. package/dist/steps/verify/03-check-design.md +0 -6
  216. package/dist/steps/verify/04-run-tests.md +0 -7
  217. package/dist/steps/verify/05-e2e-tests.md +0 -27
  218. package/dist/steps/verify/05b-e2e-fix.md +0 -33
  219. package/dist/steps/verify/06-code-quality.md +0 -25
  220. package/dist/steps/verify/07-lint-check.md +0 -27
  221. package/dist/steps/verify/08-output-report.md +0 -14
  222. package/dist/steps/verify/manifest.yaml +0 -22
  223. package/packages/dashboard/dist/assets/index-DGe8CqeP.css +0 -1
  224. package/src/derive.js +0 -147
  225. package/src/step.js +0 -543
@@ -1,51 +0,0 @@
1
- **当需要用户从多个选项中做出选择时,必须使用 Claude Code 内置的 AskUserQuestion 工具,将选项以参数传入。**
2
-
3
- 你现在是 SillySpec 代码库扫描器(编排器)。**你不读源码,只编排子代理或串行执行。**
4
-
5
- ## 绝对规则
6
- - ❌ 修改代码 / 编造路径 / 主代理读源码全文
7
- - ✅ 交互模式每步等用户 / 文档只写 `.sillyspec/docs/<project>/scan/`
8
-
9
- ## 参数处理
10
- - 空白 → 交互式引导(逐步询问)
11
- - `--deep` → 直接深度扫描
12
- - 其他 → 快速扫描该区域
13
-
14
- ## 交互式引导(参数为空时)
15
-
16
- ### 检查工作区 & 已有文档
17
-
18
- ```bash
19
- ls .sillyspec/projects/*.yaml 2>/dev/null | grep -q . # 有子项目配置 → 工作区模式
20
- ls .sillyspec/docs/<project>/scan/ 2>/dev/null # 检查已有文档
21
- wc -l .sillyspec/docs/<project>/scan/*.md 2>/dev/null
22
- ```
23
-
24
- - 已有 3 份 → 建议升级深度扫描
25
- - 已有 7 份 → 建议刷新或跳过
26
- - 工作区 → 逐个扫描 / 选子项目 / 退出
27
-
28
- ### 选择扫描模式、范围、排除目录、确认
29
- 按原流程交互,确认后进入扫描。
30
-
31
- ## 构建环境探测(主代理执行)
32
-
33
- ```bash
34
- cat package.json pom.xml build.gradle go.mod Cargo.toml requirements.txt pyproject.toml Gemfile composer.json 2>/dev/null
35
- find . -maxdepth 2 -name "*.config.*" -not -path "*/node_modules/*" -not -path "*/.git/*" | head -20 | xargs cat 2>/dev/null
36
- ```
37
-
38
- 结果保存到 `.sillyspec/docs/<project>/scan/_env-detect.md`(临时文件,扫描完删除)。
39
-
40
- ## 断点续扫
41
-
42
- ```bash
43
- for f in ARCHITECTURE STRUCTURE CONVENTIONS INTEGRATIONS TESTING CONCERNS PROJECT; do
44
- [ -f ".sillyspec/docs/<project>/scan/${f}.md" ] && echo "✅ ${f}.md" || echo "⬜ ${f}.md"
45
- done
46
- ```
47
-
48
- 只生成缺失的文档。
49
-
50
- ## 子代理可用性检测
51
- 检查是否有 Task/Spawn 工具。有 → 子代理模式,无 → 串行模式。
@@ -1,16 +0,0 @@
1
- 扫描技术栈 + 数据库 Schema + 架构模式,生成 `ARCHITECTURE.md`。
2
-
3
- 参考 `.sillyspec/docs/<project>/scan/_env-detect.md`。
4
-
5
- 用 grep/rg 搜索(`@Entity`、`schema.prisma`、`models.py` 等),**禁止读源码全文**。
6
-
7
- Schema 只记表名+说明+字段数。
8
-
9
- 输出文件必须包含以下章节:
10
- - `## 技术栈`
11
- - `## 架构概览`
12
- - `## 数据模型(摘要)`
13
-
14
- 路径用反引号,不编造。保存到 `.sillyspec/docs/<project>/scan/ARCHITECTURE.md`。
15
-
16
- 完成后立即写文件,下一个 area 开始前清除源码上下文。
@@ -1,16 +0,0 @@
1
- 扫描框架隐形规则 + 实体继承 + 代码风格,生成 `CONVENTIONS.md`。
2
-
3
- 参考 `.sillyspec/docs/<project>/scan/_env-detect.md`。
4
-
5
- 用 grep 搜索拦截器/插件/逻辑删除/基类/审计字段,**禁止读源码全文**。
6
-
7
- 根据检测到的语言/框架自行决定搜索什么模式,提取 3-5 个典型示例。
8
-
9
- 输出文件必须包含以下章节:
10
- - `## 框架隐形规则`
11
- - `## 实体继承规范`
12
- - `## 代码风格`
13
-
14
- 路径用反引号,不编造。保存到 `.sillyspec/docs/<project>/scan/CONVENTIONS.md`。
15
-
16
- 完成后立即写文件,下一个 area 开始前清除源码上下文。
@@ -1,19 +0,0 @@
1
- 扫描目录结构 + 外部集成,生成 `STRUCTURE.md` 和 `INTEGRATIONS.md`。
2
-
3
- 参考 `.sillyspec/docs/<project>/scan/_env-detect.md`。
4
-
5
- 用 find/ls/tree 和 grep,**禁止读源码全文**。
6
-
7
- 搜索 API 调用、MQ 配置、缓存、第三方 SDK。
8
-
9
- **STRUCTURE.md** 必须包含:
10
- - 目录树(用 tree 或 find 生成)
11
- - 模块说明
12
-
13
- **INTEGRATIONS.md** 按类型分组(数据库、缓存、MQ、第三方 API 等)。
14
-
15
- 路径用反引号,不编造。分别保存到:
16
- - `.sillyspec/docs/<project>/scan/STRUCTURE.md`
17
- - `.sillyspec/docs/<project>/scan/INTEGRATIONS.md`
18
-
19
- 完成后立即写文件,下一个 area 开始前清除源码上下文。
@@ -1,18 +0,0 @@
1
- 扫描测试现状 + 技术债务 + 项目概览,生成 `TESTING.md`、`CONCERNS.md`、`PROJECT.md`。
2
-
3
- 参考 `.sillyspec/docs/<project>/scan/_env-detect.md`。
4
-
5
- 用 grep 搜索测试文件、TODO/FIXME、过时依赖,**禁止读源码全文**。
6
-
7
- **TESTING.md** 必须包含测试结构(框架、目录、覆盖情况)。
8
-
9
- **CONCERNS.md** 按严重程度分组(🔴 必须 / 🟡 建议 / 🔵 优化)。
10
-
11
- **PROJECT.md** 包含项目基本信息。
12
-
13
- 路径用反引号,不编造。分别保存到:
14
- - `.sillyspec/docs/<project>/scan/TESTING.md`
15
- - `.sillyspec/docs/<project>/scan/CONCERNS.md`
16
- - `.sillyspec/docs/<project>/scan/PROJECT.md`
17
-
18
-
@@ -1,49 +0,0 @@
1
- ## 扫描完成
2
-
3
- ```bash
4
- # 路径校验
5
- for f in ARCHITECTURE STRUCTURE CONVENTIONS INTEGRATIONS TESTING CONCERNS PROJECT; do
6
- [ -f ".sillyspec/docs/<project>/scan/${f}.md" ] && echo "✅ ${f}.md"
7
- done
8
-
9
- # 生成知识库骨架
10
- mkdir -p .sillyspec/knowledge
11
- if [ ! -f ".sillyspec/knowledge/INDEX.md" ]; then
12
- cat > .sillyspec/knowledge/INDEX.md << 'EOF'
13
- # Knowledge Index
14
-
15
- > 子代理任务开始前查询此文件,按关键词匹配,只读命中的知识文件。
16
- > execute/quick 执行中发现的坑自动追加到 uncategorized.md,经用户确认后归类到对应文件。
17
-
18
- <!-- 格式:关键词1|关键词2|关键词3 → 文件路径 -->
19
- EOF
20
- fi
21
- if [ ! -f ".sillyspec/knowledge/uncategorized.md" ]; then
22
- cat > .sillyspec/knowledge/uncategorized.md << 'EOF'
23
- # 未分类知识
24
-
25
- > execute/quick 执行中发现的坑暂存于此,用户审阅后归类到对应文件并更新 INDEX.md。
26
- EOF
27
- fi
28
-
29
- # 记录状态
30
- cat > .sillyspec/STATE.md << 'EOF'
31
- # 项目状态
32
-
33
- ## 最近活动
34
- - $(date '+%Y-%m-%d %H:%M:%S') scan 完成
35
- EOF
36
-
37
- # 清理
38
- rm -f .sillyspec/docs/<project>/scan/_env-detect.md
39
- git add .sillyspec/
40
- ```
41
-
42
- ### 自检门控
43
- - [ ] ARCHITECTURE.md:技术栈 + Schema 摘要?
44
- - [ ] CONVENTIONS.md:隐形规则 + 代码风格?
45
- - [ ] STRUCTURE.md:目录结构?
46
- - [ ] INTEGRATIONS.md:外部依赖?
47
- - [ ] TESTING.md:测试现状?
48
- - [ ] CONCERNS.md:技术债务?
49
- - [ ] PROJECT.md:项目概览?
@@ -1,16 +0,0 @@
1
- phase: scan
2
- description: 项目代码库扫描
3
- requires: []
4
- steps:
5
- - file: 01-env-detect.md
6
- name: 环境探测
7
- - file: 02-tech-stack.md
8
- name: 技术栈识别
9
- - file: 03-conventions.md
10
- name: 代码风格提取
11
- - file: 04-structure.md
12
- name: 项目结构分析
13
- - file: 05-quality.md
14
- name: 质量评估
15
- - file: 06-complete.md
16
- name: 扫描完成
@@ -1,28 +0,0 @@
1
- **当需要用户从多个选项中做出选择时,必须使用 Claude Code 内置的 AskUserQuestion 工具,将选项以参数传入。**
2
-
3
- ## 核心约束(必须遵守)
4
- - ❌ 修改任何代码(只做检查和报告)
5
- - ❌ 自行推进到下一阶段
6
-
7
- ## 加载规范
8
-
9
- ```bash
10
- # 确定变更目录
11
- if [ -n "$ARGUMENTS" ]; then
12
- CHANGE_DIR=".sillyspec/changes/$ARGUMENTS"
13
- else
14
- CHANGE_DIR=$(ls -d .sillyspec/changes/*/ 2>/dev/null | grep -v archive | tail -1)
15
- fi
16
- cat "$CHANGE_DIR"/{design,tasks}.md 2>/dev/null
17
- cat .sillyspec/local.yaml 2>/dev/null
18
- ```
19
-
20
- 锚定确认实际存在的文件。
21
-
22
- ## 工作区模式处理
23
-
24
- 如果 `.sillyspec/projects/` 目录下有 yaml 文件:
25
- 1. 检查工作区根目录 `.sillyspec/changes/` 下的未归档变更
26
- 2. 检查每个子项目 `<子项目路径>/.sillyspec/changes/` 下的未归档变更
27
- 3. 列出所有未归档变更,让用户选择要验证哪个
28
- 4. 根据 $ARGUMENTS 或用户选择,cd 到对应目录执行验证
@@ -1 +0,0 @@
1
- 逐项检查 tasks.md,对每个 checkbox 报告:✅ 已完成 / ❌ 未完成 / ⚠️ 部分完成
@@ -1,6 +0,0 @@
1
- 对照 design.md 检查:
2
-
3
- - 架构决策是否落实?
4
- - 文件变更是否一致?
5
- - 数据模型是否正确?
6
- - API 设计是否符合预期?
@@ -1,7 +0,0 @@
1
- 运行单元测试:
2
-
3
- ```bash
4
- pnpm test 2>/dev/null || npm test 2>/dev/null || pytest 2>/dev/null || go test ./... 2>/dev/null
5
- ```
6
-
7
- 报告测试结果(通过/失败数量)。
@@ -1,27 +0,0 @@
1
- 检测项目中是否有 E2E 测试或测试步骤文件:
2
- ```bash
3
- ls tests/e2e/ e2e/ cypress/e2e/ 2>/dev/null | head -5
4
- cat .sillyspec/changes/*/e2e-steps.md 2>/dev/null | head -5
5
- ```
6
-
7
- **无任何测试** → 跳过此步骤。
8
-
9
- **有测试** → 确认修复策略(AskUserQuestion):
10
- 1. 自动修复,同一用例最多 5 次(超过停止,提示人工介入)
11
- 2. 一直修复直到全绿
12
- 3. 只报告,不自动修复
13
-
14
- **按优先级执行:**
15
-
16
- **优先级 1:专业 E2E 框架(Playwright/Cypress)**
17
- ```bash
18
- npx playwright test 2>/dev/null || npx cypress run 2>/dev/null
19
- ```
20
-
21
- **优先级 2:通用测试框架(jest/vitest)**
22
- ```bash
23
- npx vitest run 2>/dev/null || npx jest 2>/dev/null
24
- ```
25
-
26
- **优先级 3:浏览器 MCP + e2e-steps.md(兜底)**
27
- 读取 `.sillyspec/changes/<变更名>/e2e-steps.md`,按步骤逐条执行。每条标注 ✅/❌。
@@ -1,33 +0,0 @@
1
- **自动修复循环(选了策略 1 或 2 时):**
2
-
3
- ```
4
- ROUND = 1
5
- MAX_ROUNDS = 策略1时为5,策略2时为50
6
-
7
- while ROUND <= MAX_ROUNDS:
8
- 1. 运行失败测试,捕获完整输出
9
- 2. 全部通过 → 跳出循环,标记 ✅
10
- 3. 对每个失败测试:
11
- a. fixAttempts >= MAX_ROUNDS → 跳过,标记 ❌ MAX_REACHED
12
- b. 否则 → 调用修复工具,prompt 必须包含失败测试路径、测试名、完整错误信息、相关源文件路径
13
- c. 修复后重跑确认
14
- d. 通过 → fixAttempts 不变;仍失败 → fixAttempts + 1
15
- 4. 写入 .sillyspec/local.yaml
16
- 5. ROUND++
17
- 6. 本轮无任何修复 → 跳出循环
18
- ```
19
-
20
- **禁止行为:**
21
- - ❌ 只看错误摘要就修复(必须看完整输出)
22
- - ❌ 跳过 fixAttempts 计数
23
- - ❌ 一次修复多个不相关的失败(逐个修复,每次修复后重跑确认)
24
- - ❌ 直接修改代码(verify 阶段禁止改代码)
25
-
26
- **更新测试结果到 `.sillyspec/local.yaml`:**
27
- ```yaml
28
- e2e:
29
- {变更名}:
30
- {测试文件名}:
31
- status: passed/failed
32
- fixAttempts: 0
33
- ```
@@ -1,25 +0,0 @@
1
- 代码质量扫描:
2
-
3
- ```bash
4
- grep -r "TODO\|FIXME\|HACK\|XXX" src/ lib/ app/ --include="*.ts" --include="*.tsx" --include="*.py" --include="*.js" 2>/dev/null | head -20
5
- ```
6
-
7
- 审查 design.md「文件变更」中列出的文件:
8
- - 安全问题(输入校验、SQL拼接、硬编码敏感信息)
9
- - 潜在 bug(空值、边界条件)
10
- - 与 `.sillyspec/docs/<project>/scan/CONVENTIONS.md` 一致性
11
-
12
- 每个问题标 🔴必须 / 🟡建议 / 🔵优化。
13
-
14
- ## MCP 基础设施验证
15
-
16
- 检查当前可用工具列表中是否存在以下 MCP 工具:
17
- - 数据库相关工具(postgres/sqlite/mysql/redis)
18
- - 浏览器相关工具(browser/chrome/puppeteer/playwright/devtools)
19
- - 搜索相关工具(search/web_search)
20
-
21
- **数据库 MCP:** 对照 design.md 验证表/集合、字段类型、约束。⚠️ 只执行 SELECT 查询。
22
-
23
- **浏览器 MCP:** 验证页面加载、UI 元素、基础交互。
24
-
25
- **无 MCP → 跳过此部分。**
@@ -1,27 +0,0 @@
1
- Lint / Format 检查:
2
-
3
- ```bash
4
- # ESLint
5
- if [ -f .eslintrc -o -f .eslintrc.js -o -f .eslintrc.cjs -o -f .eslintrc.json -o -f .eslintrc.yml ] || grep -q '"eslint"' package.json 2>/dev/null; then
6
- npx eslint . --max-warnings 0 2>&1 | tail -50
7
- fi
8
-
9
- # Prettier(检查而非修复)
10
- if [ -f .prettierrc -o -f .prettierrc.js -o -f .prettierrc.json -o -f .prettierrc.yml ] || grep -q '"prettier"' package.json 2>/dev/null; then
11
- npx prettier --check . 2>&1 | tail -30
12
- fi
13
-
14
- # TypeScript 类型检查
15
- if [ -f tsconfig.json ]; then
16
- npx tsc --noEmit 2>&1 | tail -30
17
- fi
18
-
19
- # Stylelint
20
- if [ -f .stylelintrc -o -f .stylelintrc.js -o -f .stylelintrc.json ] || grep -q '"stylelint"' package.json 2>/dev/null; then
21
- npx stylelint "**/*.{css,scss,less}" 2>&1 | tail -30
22
- fi
23
- ```
24
-
25
- **处理策略(AskUserQuestion):**
26
- 1. **自动修复** — 对支持 `--fix` 的工具自动修复后重跑,同一问题最多修复 3 次
27
- 2. **只报告** — 仅列出所有 lint 错误,不修改代码
@@ -1,14 +0,0 @@
1
- 输出验证报告:
2
-
3
- ```markdown
4
- # SillySpec 验证报告
5
- ## 任务完成度:X/Y
6
- ## 设计一致性
7
- ## 测试结果:passed N, failed N
8
- ## 技术债务标记
9
- ## 代码审查:🔴 N / 🟡 N / 🔵 N
10
- ## Lint 检查:ESLint ✅/❌ | Prettier ✅/❌ | TypeScript ✅/❌ | Stylelint ✅/❌
11
- ## MCP 基础设施验证:数据库 ✅/❌/跳过 | 页面 ✅/❌/跳过 | API ✅/❌/跳过
12
- ## E2E 测试:passed N / failed N / fixAttempts 详情
13
- ## 结论:✅ PASS / ⚠️ PASS WITH NOTES / ❌ FAIL
14
- ```
@@ -1,22 +0,0 @@
1
- phase: verify
2
- description: 验证与检查
3
- requires: [execute]
4
- steps:
5
- - file: 01-load-specs.md
6
- name: 加载规范
7
- - file: 02-check-tasks.md
8
- name: 检查任务完成度
9
- - file: 03-check-design.md
10
- name: 对照设计文档
11
- - file: 04-run-tests.md
12
- name: 运行单元测试
13
- - file: 05-e2e-tests.md
14
- name: E2E 测试
15
- - file: 05b-e2e-fix.md
16
- name: E2E 自动修复
17
- - file: 06-code-quality.md
18
- name: 代码质量扫描
19
- - file: 07-lint-check.md
20
- name: Lint 检查
21
- - file: 08-output-report.md
22
- name: 输出验证报告
@@ -1 +0,0 @@
1
- .slide-enter-active[data-v-b5f771a9],.slide-leave-active[data-v-b5f771a9]{transition:all .2s ease}.slide-enter-from[data-v-b5f771a9],.slide-leave-to[data-v-b5f771a9]{opacity:0;max-height:0;overflow:hidden}.slide-enter-to[data-v-b5f771a9],.slide-leave-from[data-v-b5f771a9]{max-height:300px}.line-clamp-2[data-v-fac2f74c]{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.doc-preview[data-v-fc57afbe]{font-size:13px;line-height:1.7;color:#374151}.doc-preview[data-v-fc57afbe] h1{color:#d97706;font-size:18px;font-weight:700;margin:0 0 16px;border-bottom:1px solid #E5E5EA;padding-bottom:8px}.doc-preview[data-v-fc57afbe] h2{color:#1c1c1e;font-size:15px;font-weight:600;margin:20px 0 10px}.doc-preview[data-v-fc57afbe] h3{color:#d97706;font-size:14px;font-weight:600;margin:16px 0 8px}.doc-preview[data-v-fc57afbe] p{margin:8px 0}.doc-preview[data-v-fc57afbe] strong{color:#1c1c1e;font-weight:600}.doc-preview[data-v-fc57afbe] a{color:#d97706;text-decoration:none}.doc-preview[data-v-fc57afbe] a:hover{text-decoration:underline}.doc-preview[data-v-fc57afbe] code{background:#e5e5ea;color:#1c1c1e;padding:1px 5px;border-radius:3px;font-size:12px;font-family:JetBrains Mono,monospace}.doc-preview[data-v-fc57afbe] pre{background:#1c1c1e;color:#e5e5e7;border:1px solid #E5E5EA;border-radius:6px;padding:12px 16px;overflow-x:auto;font-size:12px;margin:8px 0;line-height:1.5}.doc-preview[data-v-fc57afbe] pre code{background:none;color:inherit;padding:0;border-radius:0;font-size:inherit}.doc-preview[data-v-fc57afbe] ul,.doc-preview[data-v-fc57afbe] ol{padding-left:20px;margin:8px 0;color:#374151}.doc-preview[data-v-fc57afbe] li{margin:4px 0}.doc-preview[data-v-fc57afbe] blockquote{border-left:3px solid #D97706;padding-left:12px;margin:12px 0;color:#636366;font-style:italic}.doc-preview[data-v-fc57afbe] table{width:100%;border-collapse:collapse;margin:12px 0;font-size:12px}.doc-preview[data-v-fc57afbe] thead th{background:#f0f0f3;color:#1c1c1e;font-weight:600;text-align:left;padding:8px 12px;border:1px solid #E5E5EA}.doc-preview[data-v-fc57afbe] tbody td{padding:6px 12px;border:1px solid #E5E5EA;color:#374151}.doc-preview[data-v-fc57afbe] tbody tr:hover{background:#f9fafb}.doc-preview[data-v-fc57afbe] hr{border:none;border-top:1px solid #E5E5EA;margin:16px 0}.project-overview[data-v-543019d4]{display:flex;align-items:center;background:#fff;border-bottom:1px solid #E5E5EA;padding:8px 16px;min-height:48px;gap:8px;flex-shrink:0;overflow-x:auto}.ov-section[data-v-543019d4]{display:flex;align-items:center;gap:6px;white-space:nowrap;flex-shrink:0}.ov-clickable[data-v-543019d4]{cursor:pointer;border-radius:4px;padding:2px 6px;margin:-2px -6px;transition:background .15s}.ov-clickable[data-v-543019d4]:hover{background:#d977060f}.ov-name[data-v-543019d4]{font-weight:600;font-size:13px;color:#1c1c1e}.ov-path[data-v-543019d4],.ov-label[data-v-543019d4]{font-size:11px;color:#636366}.ov-value[data-v-543019d4]{font-size:12px;color:#1c1c1e;font-weight:500}.ov-tag[data-v-543019d4]{font-size:10px;padding:1px 8px;border-radius:10px;background:#d9770614;color:#d97706;font-weight:500}.ov-divider[data-v-543019d4]{width:1px;height:20px;background:#e5e5ea;flex-shrink:0}.ov-git[data-v-543019d4]{margin-left:auto;gap:10px}.ov-branch[data-v-543019d4]{font-size:11px;color:#636366;background:#f5f5f7;padding:1px 8px;border-radius:4px}.ov-commit[data-v-543019d4]{font-size:11px;color:#636366;max-width:200px;overflow:hidden;text-overflow:ellipsis}.ov-dirty[data-v-543019d4]{font-size:11px;color:#d97706;font-weight:500}*{margin:0;padding:0;box-sizing:border-box}body{font-family:DM Sans,-apple-system,BlinkMacSystemFont,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#app{width:100vw;height:100vh;overflow:hidden}/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-black:#000;--spacing:.25rem;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wider:.05em;--tracking-widest:.1em;--leading-relaxed:1.625;--radius-sm:.25rem;--radius-md:.375rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--animate-pulse-dot:pulse-dot 1.5s ease-in-out infinite}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing) * 0)}.inset-x-0{inset-inline:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.bottom-0{bottom:calc(var(--spacing) * 0)}.left-0{left:calc(var(--spacing) * 0)}.z-10{z-index:10}.z-20{z-index:20}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.mx-4{margin-inline:calc(var(--spacing) * 4)}.-mt-0\.5{margin-top:calc(var(--spacing) * -.5)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.ml-auto{margin-left:auto}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.list-item{display:list-item}.table{display:table}.h-1{height:calc(var(--spacing) * 1)}.h-2{height:calc(var(--spacing) * 2)}.h-3{height:calc(var(--spacing) * 3)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-6{height:calc(var(--spacing) * 6)}.h-8{height:calc(var(--spacing) * 8)}.h-12{height:calc(var(--spacing) * 12)}.h-\[2px\]{height:2px}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-32{max-height:calc(var(--spacing) * 32)}.max-h-72{max-height:calc(var(--spacing) * 72)}.w-0{width:calc(var(--spacing) * 0)}.w-1{width:calc(var(--spacing) * 1)}.w-2{width:calc(var(--spacing) * 2)}.w-3{width:calc(var(--spacing) * 3)}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-8{width:calc(var(--spacing) * 8)}.w-\[2px\]{width:2px}.w-\[200px\]{width:200px}.w-\[340px\]{width:340px}.w-px{width:1px}.w-screen{width:100vw}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.flex-shrink{flex-shrink:1}.flex-shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.border-collapse{border-collapse:collapse}.rotate-180{rotate:180deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-pulse-dot{animation:var(--animate-pulse-dot)}.cursor-col-resize{cursor:col-resize}.cursor-pointer{cursor:pointer}.resize{resize:both}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-px>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(1px * var(--tw-space-y-reverse));margin-block-end:calc(1px * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.p-3{padding:calc(var(--spacing) * 3)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-px{padding-block:1px}.pt-1\.5{padding-top:calc(var(--spacing) * 1.5)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pt-5{padding-top:calc(var(--spacing) * 5)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pr-4{padding-right:calc(var(--spacing) * 4)}.pb-0{padding-bottom:calc(var(--spacing) * 0)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pb-5{padding-bottom:calc(var(--spacing) * 5)}.pl-3\.5{padding-left:calc(var(--spacing) * 3.5)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-\[3px\]{padding-left:3px}.text-center{text-align:center}.font-\[DM_Sans\,sans-serif\]{font-family:DM Sans,sans-serif}.font-\[JetBrains_Mono\,monospace\]{font-family:JetBrains Mono,monospace}.font-mono{font-family:var(--font-mono)}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[18px\]{font-size:18px}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.2em\]{--tw-tracking:.2em;letter-spacing:.2em}.tracking-\[0\.15em\]{--tw-tracking:.15em;letter-spacing:.15em}.tracking-\[0\.25em\]{--tw-tracking:.25em;letter-spacing:.25em}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.text-black{color:var(--color-black)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.ordinal{--tw-ordinal:ordinal;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.line-through{text-decoration-line:line-through}.underline{text-decoration-line:underline}.opacity-0{opacity:0}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-100{--tw-duration:.1s;transition-duration:.1s}.duration-150{--tw-duration:.15s;transition-duration:.15s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.duration-500{--tw-duration:.5s;transition-duration:.5s}.select-none{-webkit-user-select:none;user-select:none}@media(hover:hover){.hover\:bg-\[\#D97706\]:hover{background-color:#d97706}.hover\:bg-\[\#FEF3C7\]:hover{background-color:#fef3c7}}.active\:bg-\[\#D97706\]:active{background-color:#d97706}}@keyframes pulse-glow{0%,to{box-shadow:0 0 #fbbf2466}50%{box-shadow:0 0 12px 2px #fbbf2426}}@keyframes pulse-dot{0%,to{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(1.5)}}@keyframes breathe{0%,to{opacity:.5}50%{opacity:1}}@keyframes shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}@keyframes slide-in{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}@keyframes glow-border{0%,to{border-color:#fbbf2426}50%{border-color:#fbbf2480}}@keyframes float{0%,to{transform:translateY(0)}50%{transform:translateY(-3px)}}.font-mono-log{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}.noise-bg{position:relative}.noise-bg:before{content:"";pointer-events:none;z-index:0;background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.03'/%3E%3C/svg%3E");position:absolute;top:0;right:0;bottom:0;left:0}.accent-stripe{background:repeating-linear-gradient(-45deg,#0000,#0000 8px,#fbbf2408 8px,#fbbf2408 9px)}.progress-gradient{background:linear-gradient(90deg,#fbbf24,#f59e0b,#fb923c)}.skeleton-shimmer{background:linear-gradient(90deg,#1a1e28 25%,#2a3040,#1a1e28 75%) 0 0/200% 100%;animation:1.5s ease-in-out infinite shimmer}::-webkit-scrollbar{width:5px;height:5px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:#2a3040;border-radius:10px}::-webkit-scrollbar-thumb:hover{background:#3a4555}*{scrollbar-width:thin;scrollbar-color:#2a2a2d transparent}::selection{color:#fbbf24;background:#fbbf2433}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}
package/src/derive.js DELETED
@@ -1,147 +0,0 @@
1
- import { readdirSync, existsSync } from 'fs';
2
- import { join } from 'path';
3
-
4
- /**
5
- * 从 artifacts 文件系统反推状态,与 progress.json 交叉校验。
6
- * 纯函数,零外部副作用(fix 模式除外)。
7
- *
8
- * @param {string} cwd - 项目根目录
9
- * @param {object} options
10
- * @param {'light'|'full'} options.mode - 轻量(当前步骤)或全量扫描
11
- * @param {boolean} options.fix - 是否自动修复明显不一致
12
- * @param {object} options.pm - ProgressManager 实例(fix 模式需要)
13
- * @param {object} options.progress - 已加载的 progress 数据
14
- * @returns {{ issues: Array<{type:string, severity:string, stage:string, step:number, message:string, suggestion:string}>, fixed: number }}
15
- */
16
- export function deriveState(cwd, options = {}) {
17
- const { mode = 'light', fix = false, pm = null, progress = null } = options;
18
-
19
- const issues = [];
20
- let fixed = 0;
21
-
22
- const artifactsDir = join(cwd, '.sillyspec', '.runtime', 'artifacts');
23
- if (!existsSync(artifactsDir)) {
24
- return { issues: [{ type: 'no-artifacts', severity: 'info', stage: '-', step: 0, message: 'artifacts 目录不存在', suggestion: '正常,项目刚开始' }], fixed: 0 };
25
- }
26
-
27
- // 扫描 artifacts 文件,解析 stage/step 信息
28
- const artifactMap = {}; // { "stage:stepN": [filenames] }
29
- const stageStepSet = new Set(); // "stage:stepN"
30
-
31
- let files;
32
- try {
33
- files = readdirSync(artifactsDir).filter(f => f.endsWith('.txt'));
34
- } catch {
35
- return { issues: [], fixed: 0 };
36
- }
37
-
38
- for (const file of files) {
39
- // 格式: {stage}-step{N}-{timestamp}.txt
40
- const match = file.match(/^(.+)-step(\d+)-\d+\.txt$/);
41
- if (match) {
42
- const [, stage, stepStr] = match;
43
- const key = `${stage}:${stepStr}`;
44
- if (!artifactMap[key]) artifactMap[key] = [];
45
- artifactMap[key].push(file);
46
- stageStepSet.add(key);
47
- }
48
- }
49
-
50
- // 需要检查的阶段
51
- let stagesToCheck = [];
52
- if (progress) {
53
- if (mode === 'light') {
54
- // 轻量:只检查 currentStage
55
- const currentStage = progress.currentStage || '';
56
- if (currentStage) stagesToCheck.push(currentStage);
57
- } else {
58
- // 全量:检查所有阶段
59
- stagesToCheck = Object.keys(progress.stages || {});
60
- }
61
- } else {
62
- // 没有 progress 数据,从 artifacts 推断所有阶段
63
- for (const key of stageStepSet) {
64
- const stage = key.split(':')[0];
65
- if (!stagesToCheck.includes(stage)) stagesToCheck.push(stage);
66
- }
67
- }
68
-
69
- for (const stage of stagesToCheck) {
70
- const stageData = progress?.stages?.[stage];
71
- const steps = stageData?.steps || [];
72
-
73
- // 收集 artifacts 中该阶段的步骤编号
74
- const artifactSteps = new Set();
75
- for (const key of stageStepSet) {
76
- const [s, n] = key.split(':');
77
- if (s === stage) artifactSteps.add(parseInt(n));
78
- }
79
-
80
- // 检查1:artifacts 有但 progress 未标记完成
81
- for (const stepNum of artifactSteps) {
82
- const stepIdx = stepNum - 1;
83
- if (stepIdx < steps.length) {
84
- const step = steps[stepIdx];
85
- if (step.status !== 'done') {
86
- issues.push({
87
- type: 'missing-progress',
88
- severity: 'issue',
89
- stage,
90
- step: stepNum,
91
- message: `artifacts 有 ${stage}-step${stepNum} 文件但 progress 未标记完成`,
92
- suggestion: '标记该步骤为 done'
93
- });
94
- if (fix && pm && progress) {
95
- step.status = 'done';
96
- pm._write(cwd, progress);
97
- fixed++;
98
- }
99
- }
100
- }
101
- }
102
-
103
- // 检查2:progress 有但 artifacts 无文件(warning,不修复)
104
- for (let i = 0; i < steps.length; i++) {
105
- const step = steps[i];
106
- if (step.status === 'done' && !artifactSteps.has(i + 1)) {
107
- issues.push({
108
- type: 'missing-artifact',
109
- severity: 'warning',
110
- stage,
111
- step: i + 1,
112
- message: `${stage} step ${i + 1} 标记完成但 artifacts 无对应文件`,
113
- suggestion: '可能被手动清理,忽略即可'
114
- });
115
- }
116
- }
117
-
118
- // 检查3:artifacts 有 step5 但 progress 只到 step3(中间漏记)
119
- if (artifactSteps.size > 0) {
120
- const maxArtifactStep = Math.max(...artifactSteps);
121
- const maxProgressDoneStep = steps.reduce((max, s, i) => s.status === 'done' ? Math.max(max, i + 1) : max, 0);
122
-
123
- if (maxArtifactStep > maxProgressDoneStep && maxProgressDoneStep > 0) {
124
- // 检查中间是否有漏记的
125
- for (let i = maxProgressDoneStep + 1; i <= maxArtifactStep; i++) {
126
- if (artifactSteps.has(i) && i - 1 < steps.length && steps[i - 1].status !== 'done') {
127
- // 已在检查1处理,跳过
128
- }
129
- }
130
- }
131
-
132
- // progress 步骤数少于 artifacts 最大步骤号
133
- if (maxArtifactStep > steps.length) {
134
- issues.push({
135
- type: 'missing-steps',
136
- severity: 'issue',
137
- stage,
138
- step: steps.length + 1,
139
- message: `artifacts 有 step${maxArtifactStep} 但 progress 只有 ${steps.length} 个步骤`,
140
- suggestion: 'progress 数据可能不完整'
141
- });
142
- }
143
- }
144
- }
145
-
146
- return { issues, fixed };
147
- }