pdd-skills 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/README.md +1478 -0
  2. package/bin/pdd.js +354 -0
  3. package/config/bpmn-rules.yaml +166 -0
  4. package/config/checkstyle.xml +105 -0
  5. package/config/eslint.config.js +48 -0
  6. package/config/pmd.xml +91 -0
  7. package/config/prd-rules.yaml +113 -0
  8. package/config/ruff.toml +45 -0
  9. package/config/sqlfluff.cfg +82 -0
  10. package/hooks/hook-executor.js +332 -0
  11. package/index.js +43 -0
  12. package/lib/api-routes.js +750 -0
  13. package/lib/api-server.js +408 -0
  14. package/lib/cache/cache-config.js +209 -0
  15. package/lib/cache/system-cache.js +852 -0
  16. package/lib/config-manager.js +373 -0
  17. package/lib/generate.js +528 -0
  18. package/lib/grpc/grpc-routes.js +1134 -0
  19. package/lib/grpc/grpc-server.js +912 -0
  20. package/lib/grpc/proto-definitions.js +1033 -0
  21. package/lib/init.js +172 -0
  22. package/lib/iteration/auto-fixer.js +1025 -0
  23. package/lib/iteration/auto-reviewer.js +923 -0
  24. package/lib/iteration/controller.js +577 -0
  25. package/lib/list.js +130 -0
  26. package/lib/mcp-server.js +548 -0
  27. package/lib/openclaw/api-integration.js +535 -0
  28. package/lib/openclaw/cli-integration.js +567 -0
  29. package/lib/openclaw/data-sync.js +845 -0
  30. package/lib/openclaw/openclaw-adapter.js +783 -0
  31. package/lib/plugin/example-plugins/code-stats/index.js +332 -0
  32. package/lib/plugin/example-plugins/code-stats/plugin.json +1 -0
  33. package/lib/plugin/example-plugins/custom-linter/index.js +472 -0
  34. package/lib/plugin/example-plugins/custom-linter/plugin.json +1 -0
  35. package/lib/plugin/example-plugins/hello-world/index.js +86 -0
  36. package/lib/plugin/example-plugins/hello-world/plugin.json +1 -0
  37. package/lib/plugin/plugin-manager.js +655 -0
  38. package/lib/plugin/plugin-sdk.js +565 -0
  39. package/lib/plugin/sandbox.js +627 -0
  40. package/lib/quality/rules/maintainability.js +418 -0
  41. package/lib/quality/rules/performance.js +498 -0
  42. package/lib/quality/rules/readability.js +441 -0
  43. package/lib/quality/rules/robustness.js +504 -0
  44. package/lib/quality/rules/security.js +444 -0
  45. package/lib/quality/scorer.js +576 -0
  46. package/lib/report.js +669 -0
  47. package/lib/sdk-base.js +301 -0
  48. package/lib/sdk-js.js +446 -0
  49. package/lib/sdk-python/README.md +546 -0
  50. package/lib/sdk-python/examples/basic_usage.py +450 -0
  51. package/lib/sdk-python/pdd_sdk/__init__.py +180 -0
  52. package/lib/sdk-python/pdd_sdk/client.py +1170 -0
  53. package/lib/sdk-python/pdd_sdk/events.py +423 -0
  54. package/lib/sdk-python/pdd_sdk/exceptions.py +158 -0
  55. package/lib/sdk-python/pdd_sdk/models.py +518 -0
  56. package/lib/sdk-python/pdd_sdk/utils.py +759 -0
  57. package/lib/token/budget-alert.js +367 -0
  58. package/lib/token/budget-manager.js +485 -0
  59. package/lib/update.js +54 -0
  60. package/lib/utils/logger.js +88 -0
  61. package/lib/verify.js +741 -0
  62. package/lib/version.js +52 -0
  63. package/lib/vm/README.md +102 -0
  64. package/lib/vm/dashboard/api-routes.js +669 -0
  65. package/lib/vm/dashboard/server.js +391 -0
  66. package/lib/vm/dashboard/sse.js +358 -0
  67. package/lib/vm/dashboard/static/css/dashboard.css +1378 -0
  68. package/lib/vm/dashboard/static/index.html +118 -0
  69. package/lib/vm/dashboard/static/js/app.js +949 -0
  70. package/lib/vm/dashboard/static/js/charts.js +913 -0
  71. package/lib/vm/dashboard/static/js/kanban-view.js +1053 -0
  72. package/lib/vm/dashboard/static/js/pipeline-view.js +463 -0
  73. package/lib/vm/dashboard/static/js/quality-view.js +598 -0
  74. package/lib/vm/dashboard/static/js/system-view.js +1021 -0
  75. package/lib/vm/data-provider.js +1191 -0
  76. package/lib/vm/event-bus.js +402 -0
  77. package/lib/vm/hooks/extract-hook.js +307 -0
  78. package/lib/vm/hooks/generate-hook.js +374 -0
  79. package/lib/vm/hooks/hook-interface.js +458 -0
  80. package/lib/vm/hooks/report-hook.js +331 -0
  81. package/lib/vm/hooks/verify-hook.js +454 -0
  82. package/lib/vm/models.js +1003 -0
  83. package/lib/vm/reconciler.js +855 -0
  84. package/lib/vm/scanner.js +988 -0
  85. package/lib/vm/state-schema.js +955 -0
  86. package/lib/vm/state-store.js +733 -0
  87. package/lib/vm/tui/components/card.js +339 -0
  88. package/lib/vm/tui/components/progress-bar.js +368 -0
  89. package/lib/vm/tui/components/sparkline.js +327 -0
  90. package/lib/vm/tui/components/status-light.js +294 -0
  91. package/lib/vm/tui/components/table.js +370 -0
  92. package/lib/vm/tui/input.js +335 -0
  93. package/lib/vm/tui/renderer.js +548 -0
  94. package/lib/vm/tui/screens/kanban-screen.js +397 -0
  95. package/lib/vm/tui/screens/overview-screen.js +357 -0
  96. package/lib/vm/tui/screens/quality-screen.js +336 -0
  97. package/lib/vm/tui/screens/system-screen.js +379 -0
  98. package/lib/vm/tui/tui.js +805 -0
  99. package/package.json +1 -0
  100. package/scripts/cso-analyzer.js +198 -0
  101. package/scripts/eval-runner.js +359 -0
  102. package/scripts/i18n-checker.js +109 -0
  103. package/scripts/linter/activiti-linter.js +272 -0
  104. package/scripts/linter/prd-linter.js +162 -0
  105. package/scripts/linter/report-generator.js +207 -0
  106. package/scripts/linter/run-linters.js +285 -0
  107. package/scripts/linter/sql-linter.js +166 -0
  108. package/scripts/token-analyzer.js +162 -0
  109. package/scripts/vm-test.js +180 -0
  110. package/skills/core/official-doc-writer/LICENSE +21 -0
  111. package/skills/core/official-doc-writer/README.md +232 -0
  112. package/skills/core/official-doc-writer/SKILL.md +475 -0
  113. package/skills/core/official-doc-writer/_meta.json +1 -0
  114. package/skills/core/official-doc-writer/document_generator.py +580 -0
  115. package/skills/core/official-doc-writer/evals/default-evals.json +1 -0
  116. package/skills/core/official-doc-writer/examples.md +150 -0
  117. package/skills/core/official-doc-writer/fonts/FONTS_LIST.md +45 -0
  118. package/skills/core/official-doc-writer/fonts/README.md +141 -0
  119. package/skills/core/official-doc-writer/fonts/SIMFANG.TTF +0 -0
  120. package/skills/core/official-doc-writer/fonts/SIMHEI.TTF +0 -0
  121. package/skills/core/official-doc-writer/fonts/SIMKAI.TTF +0 -0
  122. package/skills/core/official-doc-writer/fonts/SIMSUN.TTC +0 -0
  123. package/skills/core/official-doc-writer/fonts//346/226/271/346/255/243/345/260/217/346/240/207/345/256/213GBK.TTF +0 -0
  124. package/skills/core/official-doc-writer/references/GBT_9704-2012_/345/205/232/346/224/277/346/234/272/345/205/263/345/205/254/346/226/207/346/240/274/345/274/217.md +422 -0
  125. package/skills/core/official-doc-writer/scripts/__pycache__/generate_official_doc.cpython-313.pyc +0 -0
  126. package/skills/core/official-doc-writer/scripts/dialog_manager.py +564 -0
  127. package/skills/core/official-doc-writer/scripts/generate_official_doc.py +252 -0
  128. package/skills/core/official-doc-writer/scripts/install_fonts.py +390 -0
  129. package/skills/core/official-doc-writer/scripts/smart_prompts.py +363 -0
  130. package/skills/core/pdd-ba/SKILL.md +305 -0
  131. package/skills/core/pdd-ba/_meta.json +1 -0
  132. package/skills/core/pdd-ba/evals/default-evals.json +1 -0
  133. package/skills/core/pdd-code-reviewer/SKILL.md +378 -0
  134. package/skills/core/pdd-code-reviewer/_meta.json +1 -0
  135. package/skills/core/pdd-code-reviewer/evals/default-evals.json +1 -0
  136. package/skills/core/pdd-doc-change/SKILL.md +350 -0
  137. package/skills/core/pdd-doc-change/_meta.json +1 -0
  138. package/skills/core/pdd-doc-change/evals/default-evals.json +1 -0
  139. package/skills/core/pdd-doc-gardener/SKILL.md +248 -0
  140. package/skills/core/pdd-doc-gardener/_meta.json +1 -0
  141. package/skills/core/pdd-doc-gardener/evals/default-evals.json +1 -0
  142. package/skills/core/pdd-entropy-reduction/SKILL.md +360 -0
  143. package/skills/core/pdd-entropy-reduction/_meta.json +1 -0
  144. package/skills/core/pdd-entropy-reduction/evals/default-evals.json +1 -0
  145. package/skills/core/pdd-entropy-reduction/references/entropy-report-template.md +287 -0
  146. package/skills/core/pdd-entropy-reduction/references/golden-principles.md +573 -0
  147. package/skills/core/pdd-entropy-reduction/scripts/entropy_scan.py +712 -0
  148. package/skills/core/pdd-extract-features/SKILL.md +320 -0
  149. package/skills/core/pdd-extract-features/_meta.json +1 -0
  150. package/skills/core/pdd-extract-features/evals/default-evals.json +1 -0
  151. package/skills/core/pdd-generate-spec/SKILL.md +418 -0
  152. package/skills/core/pdd-generate-spec/_meta.json +1 -0
  153. package/skills/core/pdd-generate-spec/evals/default-evals.json +1 -0
  154. package/skills/core/pdd-implement-feature/SKILL.md +332 -0
  155. package/skills/core/pdd-implement-feature/_meta.json +1 -0
  156. package/skills/core/pdd-implement-feature/evals/default-evals.json +1 -0
  157. package/skills/core/pdd-main/SKILL.md +540 -0
  158. package/skills/core/pdd-main/_meta.json +1 -0
  159. package/skills/core/pdd-main/evals/default-evals.json +1 -0
  160. package/skills/core/pdd-main/evals/evals.json +215 -0
  161. package/skills/core/pdd-verify-feature/SKILL.md +474 -0
  162. package/skills/core/pdd-verify-feature/_meta.json +1 -0
  163. package/skills/core/pdd-verify-feature/evals/default-evals.json +1 -0
  164. package/skills/core/pdd-vm/evals/default-evals.json +1 -0
  165. package/skills/core/traffic-accident-assessor/LICENSE +29 -0
  166. package/skills/core/traffic-accident-assessor/SKILL.md +439 -0
  167. package/skills/core/traffic-accident-assessor/evals/evals.json +1 -0
  168. package/skills/core/traffic-accident-assessor/references/accident-types.md +369 -0
  169. package/skills/core/traffic-accident-assessor/references/liability-rules.md +287 -0
  170. package/skills/core/traffic-accident-assessor/references/traffic-laws.md +226 -0
  171. package/skills/core/traffic-accident-assessor/references//351/253/230/345/260/224/345/244/253/350/257/264/346/230/216/344/271/246.pdf +32576 -106
  172. package/skills/core/traffic-accident-assessor/scripts/generate_official_statement.py +588 -0
  173. package/skills/core/traffic-accident-assessor/scripts/generate_report.py +495 -0
  174. package/skills/core/traffic-accident-assessor/scripts/generate_statement.py +528 -0
  175. package/skills/core/traffic-accident-assessor.zip +0 -0
  176. package/skills/entropy/expert-arch-enforcer/SKILL.md +292 -0
  177. package/skills/entropy/expert-arch-enforcer/_meta.json +1 -0
  178. package/skills/entropy/expert-arch-enforcer/evals/default-evals.json +1 -0
  179. package/skills/entropy/expert-auto-refactor/SKILL.md +327 -0
  180. package/skills/entropy/expert-auto-refactor/_meta.json +1 -0
  181. package/skills/entropy/expert-auto-refactor/evals/default-evals.json +1 -0
  182. package/skills/entropy/expert-code-quality/SKILL.md +468 -0
  183. package/skills/entropy/expert-code-quality/_meta.json +1 -0
  184. package/skills/entropy/expert-code-quality/evals/default-evals.json +1 -0
  185. package/skills/entropy/expert-code-quality/evals/evals.json +109 -0
  186. package/skills/entropy/expert-code-quality/references/code-smells.md +605 -0
  187. package/skills/entropy/expert-code-quality/references/design-patterns.md +1111 -0
  188. package/skills/entropy/expert-code-quality/references/refactoring-catalog.md +1281 -0
  189. package/skills/entropy/expert-code-quality/references/solid-principles.md +524 -0
  190. package/skills/entropy/expert-entropy-auditor/SKILL.md +276 -0
  191. package/skills/entropy/expert-entropy-auditor/_meta.json +1 -0
  192. package/skills/entropy/expert-entropy-auditor/evals/default-evals.json +1 -0
  193. package/skills/expert/expert-activiti/SKILL.md +497 -0
  194. package/skills/expert/expert-activiti/_meta.json +1 -0
  195. package/skills/expert/expert-mysql/SKILL.md +832 -0
  196. package/skills/expert/expert-mysql/_meta.json +1 -0
  197. package/skills/expert/expert-performance/SKILL.md +379 -0
  198. package/skills/expert/expert-performance/_meta.json +1 -0
  199. package/skills/expert/expert-performance/evals/default-evals.json +1 -0
  200. package/skills/expert/expert-ruoyi/SKILL.md +472 -0
  201. package/skills/expert/expert-ruoyi/_meta.json +1 -0
  202. package/skills/expert/expert-security/SKILL.md +1341 -0
  203. package/skills/expert/expert-security/_meta.json +1 -0
  204. package/skills/expert/expert-security/evals/default-evals.json +1 -0
  205. package/skills/expert/software-architect/SKILL.md +350 -0
  206. package/skills/expert/software-architect/_meta.json +1 -0
  207. package/skills/expert/software-engineer/SKILL.md +437 -0
  208. package/skills/expert/software-engineer/_meta.json +1 -0
  209. package/skills/expert/software-engineer/architecture.md +130 -0
  210. package/skills/expert/software-engineer/patterns.md +151 -0
  211. package/skills/expert/software-engineer/testing.md +135 -0
  212. package/skills/expert/system-architect/SKILL.md +628 -0
  213. package/skills/expert/system-architect/_meta.json +1 -0
  214. package/skills/expert/system-architect/assets/templates/ARCHITECTURE.md +25 -0
  215. package/skills/expert/system-architect/assets/templates/README.md +44 -0
  216. package/skills/expert/system-architect/references/js-ts-standards.md +18 -0
  217. package/skills/expert/system-architect/references/python-standards.md +19 -0
  218. package/skills/expert/system-architect/references/scaffolding.md +61 -0
  219. package/skills/expert/system-architect/references/security-checklist.md +21 -0
  220. package/skills/openspec/openspec-apply-change/SKILL.md +156 -0
  221. package/skills/openspec/openspec-apply-change/_meta.json +1 -0
  222. package/skills/openspec/openspec-archive-change/SKILL.md +114 -0
  223. package/skills/openspec/openspec-archive-change/_meta.json +1 -0
  224. package/skills/openspec/openspec-bulk-archive-change/SKILL.md +246 -0
  225. package/skills/openspec/openspec-bulk-archive-change/_meta.json +1 -0
  226. package/skills/openspec/openspec-continue-change/SKILL.md +118 -0
  227. package/skills/openspec/openspec-continue-change/_meta.json +1 -0
  228. package/skills/openspec/openspec-explore/SKILL.md +288 -0
  229. package/skills/openspec/openspec-explore/_meta.json +1 -0
  230. package/skills/openspec/openspec-ff-change/SKILL.md +101 -0
  231. package/skills/openspec/openspec-ff-change/_meta.json +1 -0
  232. package/skills/openspec/openspec-new-change/SKILL.md +74 -0
  233. package/skills/openspec/openspec-new-change/_meta.json +1 -0
  234. package/skills/openspec/openspec-onboard/SKILL.md +554 -0
  235. package/skills/openspec/openspec-onboard/_meta.json +1 -0
  236. package/skills/openspec/openspec-sync-specs/SKILL.md +138 -0
  237. package/skills/openspec/openspec-sync-specs/_meta.json +1 -0
  238. package/skills/openspec/openspec-verify-change/SKILL.md +168 -0
  239. package/skills/openspec/openspec-verify-change/_meta.json +1 -0
  240. package/skills/pr/pdd-multi-review/SKILL.md +534 -0
  241. package/skills/pr/pdd-multi-review/_meta.json +1 -0
  242. package/skills/pr/pdd-pr-batch/SKILL.md +303 -0
  243. package/skills/pr/pdd-pr-batch/_meta.json +1 -0
  244. package/skills/pr/pdd-pr-create/SKILL.md +344 -0
  245. package/skills/pr/pdd-pr-create/_meta.json +1 -0
  246. package/skills/pr/pdd-pr-merge/SKILL.md +286 -0
  247. package/skills/pr/pdd-pr-merge/_meta.json +1 -0
  248. package/skills/pr/pdd-pr-review/SKILL.md +217 -0
  249. package/skills/pr/pdd-pr-review/_meta.json +1 -0
  250. package/skills/pr/pdd-task-manager/SKILL.md +636 -0
  251. package/skills/pr/pdd-task-manager/_meta.json +1 -0
  252. package/skills/pr/pdd-template-engine/SKILL.md +306 -0
  253. package/skills/pr/pdd-template-engine/_meta.json +1 -0
  254. package/templates/behavior-shaping/iron-law-template.md +87 -0
  255. package/templates/behavior-shaping/rationalization-template.md +62 -0
  256. package/templates/behavior-shaping/red-flags-template.md +70 -0
  257. package/templates/bilingual-template.md +139 -0
  258. package/templates/config/default.yaml +47 -0
  259. package/templates/project/default/README.md +31 -0
  260. package/templates/project/frontend/README.md +46 -0
  261. package/templates/project/java/README.md +48 -0
@@ -0,0 +1,454 @@
1
+ /**
2
+ * @module lib/vm/hooks/verify-hook
3
+ * @description Verify 命令 Hook 实现
4
+ * 负责记录验证命令的前后状态变化,包括:
5
+ * - 前置:标记功能点为 VERIFYING 阶段
6
+ * - 后置:解析验证结果(覆盖率、评分、问题列表、通过率),
7
+ * 根据结果更新质量指标和阶段状态(全部通过 -> DONE)
8
+ *
9
+ * 这是 PDD VM 系统中最重要的质量门禁 Hook
10
+ */
11
+
12
+ import { PDDHook } from './hook-interface.js';
13
+ import { StageEnum, updateStage, addTimelineEvent, getGradeFromScore } from '../models.js';
14
+ import { getStateStore } from '../state-store.js';
15
+
16
+ /**
17
+ * VerifyHook - 处理 `pdd verify` 命令的生命周期事件
18
+ *
19
+ * @class
20
+ * @extends PDDHook
21
+ *
22
+ * @example
23
+ * import { VerifyHook } from './lib/vm/hooks/verify-hook.js';
24
+ * const hook = new VerifyHook();
25
+ * hookManager.register(hook);
26
+ */
27
+ export class VerifyHook extends PDDHook {
28
+ /**
29
+ * 创建 VerifyHook 实例
30
+ */
31
+ constructor() {
32
+ super({ enabled: true });
33
+ /** @override */
34
+ this.name = 'verify';
35
+
36
+ /**
37
+ * StateStore 实例缓存
38
+ * @type {import('../state-store.js').StateStore|null}
39
+ * @private
40
+ */
41
+ this._store = null;
42
+ }
43
+
44
+ /**
45
+ * 获取或初始化 StateStore 实例
46
+ *
47
+ * @async
48
+ * @private
49
+ * @returns {Promise<import('../state-store.js').StateStore>}
50
+ */
51
+ async _getStore() {
52
+ if (!this._store) {
53
+ this._store = await getStateStore();
54
+ }
55
+ return this._store;
56
+ }
57
+
58
+ /**
59
+ * 命令执行前的钩子
60
+ * 主要职责:
61
+ * 1. 将 feature.stage 设置为 StageEnum.VERIFYING
62
+ * 2. 在 timeline 中添加验证开始记录
63
+ *
64
+ * @async
65
+ * @override
66
+ * @param {import('./hook-interface.js').HookContext} ctx - 钩子上下文
67
+ * @returns {Promise<void>}
68
+ */
69
+ async before(ctx) {
70
+ if (!this._isEnabled()) return;
71
+
72
+ try {
73
+ const store = await this._getStore();
74
+ const featureId = ctx.featureId || ctx.options?.feature;
75
+
76
+ if (!featureId) {
77
+ this._log('before', ctx);
78
+ console.log('[VerifyHook] 警告: 未提供 featureId,跳过状态记录');
79
+ return;
80
+ }
81
+
82
+ let feature = store.getFeature(featureId);
83
+
84
+ // 如果 Feature 不存在,自动创建
85
+ if (!feature) {
86
+ console.log(`[VerifyHook] 功能点 ${featureId} 不存在,自动创建`);
87
+ feature = await store.addFeature({
88
+ id: featureId,
89
+ name: ctx.options?.feature || featureId,
90
+ description: `通过 verify 命令自动创建`,
91
+ stage: StageEnum.IMPLEMENTING // verify 前应该是实现阶段
92
+ });
93
+ }
94
+
95
+ // 更新阶段为 VERIFYING
96
+ updateStage(feature, StageEnum.VERIFYING, '开始功能验证');
97
+
98
+ // 添加详细时间线事件
99
+ addTimelineEvent(feature, StageEnum.VERIFYING, '开始功能验证', {
100
+ command: 'verify',
101
+ spec: ctx.options?.spec,
102
+ codeDir: ctx.options?.code,
103
+ verbose: ctx.options?.verbose || false,
104
+ outputJson: ctx.options?.json || false
105
+ });
106
+
107
+ // 持久化
108
+ await store.updateFeature(featureId, {});
109
+
110
+ this._log('before', ctx);
111
+ console.log(
112
+ `[VerifyHook] 已将功能点 ${featureId} 标记为 ${StageEnum.VERIFYING}`
113
+ );
114
+ } catch (error) {
115
+ console.error(`[VerifyHook] before 钩子执行失败: ${error.message}`);
116
+ }
117
+ }
118
+
119
+ /**
120
+ * 命令成功执行后的钩子
121
+ * 主要职责:
122
+ * 1. 解析验证结果 (VerificationResult 对象)
123
+ * 2. 计算并更新质量指标:
124
+ * - quality.coverage = result.coverage 或计算通过率
125
+ * - quality.score = result.overallScore 或基于 pass/fail 计算
126
+ * - quality.grade = 根据 score 映射等级 S(>95)/A(>85)/B(>70)/C(>55)/D(>40)/F(≤40)
127
+ * - quality.issues = result.issues 列表
128
+ * - quality.passRate = passed / (passed + failed) * 100
129
+ * 3. 如果验证全部通过:stage = DONE
130
+ * 4. 否则保持 VERIFYING(或标记为 NEEDS_FIX)
131
+ * 5. 如果有迭代数据:添加 IterationRound
132
+ *
133
+ * @async
134
+ * @override
135
+ * @param {import('./hook-interface.js').HookContext} ctx - 钩子上下文(包含 result)
136
+ * @returns {Promise<void>}
137
+ */
138
+ async after(ctx) {
139
+ if (!this._isEnabled()) return;
140
+
141
+ try {
142
+ const store = await this._getStore();
143
+ const featureId = ctx.featureId || ctx.options?.feature;
144
+ const result = ctx.result;
145
+
146
+ if (!featureId) {
147
+ this._log('after', ctx);
148
+ console.log('[VerifyHook] 警告: 未提供 featureId,跳过结果记录');
149
+ return;
150
+ }
151
+
152
+ const feature = store.getFeature(featureId);
153
+ if (!feature) {
154
+ console.log(
155
+ `[VerifyHook] 功能点 ${featureId} 不存在,无法记录验证结果`
156
+ );
157
+ return;
158
+ }
159
+
160
+ // 解析验证结果
161
+ const verificationResult = this._parseVerificationResult(result);
162
+
163
+ // 构建质量指标对象
164
+ const qualityUpdate = {
165
+ coverage: verificationResult.coverage || 0,
166
+ score: verificationResult.overallScore || 0,
167
+ grade: '',
168
+ issues: verificationResult.issues || [],
169
+ passRate: verificationResult.passRate || 0,
170
+ passed: verificationResult.passed || 0,
171
+ failed: verificationResult.failed || 0,
172
+ lastChecked: new Date()
173
+ };
174
+
175
+ // 计算质量等级
176
+ if (qualityUpdate.score > 0) {
177
+ const gradeInfo = getGradeFromScore(qualityUpdate.score);
178
+ qualityUpdate.grade = gradeInfo.grade;
179
+ } else if (qualityUpdate.passRate >= 0) {
180
+ // 如果没有 score,用 passRate 作为替代
181
+ const gradeInfo = getGradeFromScore(qualityUpdate.passRate);
182
+ qualityUpdate.grade = gradeInfo.grade;
183
+ qualityUpdate.score = qualityUpdate.passRate;
184
+ }
185
+
186
+ // 确定是否需要更新 stage
187
+ let newStage = null;
188
+ let stageNote = '';
189
+
190
+ if (verificationResult.allPassed === true || qualityUpdate.failed === 0) {
191
+ // 全部通过 -> DONE
192
+ newStage = StageEnum.DONE;
193
+ stageNote = `验证通过 (grade=${qualityUpdate.grade}, score=${qualityUpdate.score})`;
194
+ } else if (qualityUpdate.failed > 0 && qualityUpdate.passRate < 50) {
195
+ // 通过率过低 -> NEEDS_FIX
196
+ newStage = StageEnum.NEEDS_FIX;
197
+ stageNote = `验证未通过,需要修复 (${qualityUpdate.failed} 项失败)`;
198
+ }
199
+ // 其他情况保持 VERIFYING
200
+
201
+ // 准备迭代数据(如果有)
202
+ const iterationData = verificationResult.iterationRound
203
+ ? this._buildIterationRound(verificationResult.iterationRound)
204
+ : null;
205
+
206
+ // 构建 updates 对象
207
+ const updates = {
208
+ quality: qualityUpdate
209
+ };
210
+
211
+ // 如果有新阶段,添加 stage 更新
212
+ if (newStage) {
213
+ updates.stage = newStage;
214
+ }
215
+
216
+ // 如果有迭代数据
217
+ if (iterationData) {
218
+ iterations: [...(feature.iterations || []), iterationData];
219
+ }
220
+
221
+ // 执行更新
222
+ await store.updateFeature(featureId, updates);
223
+
224
+ // 手动添加时间线事件(如果阶段变更了)
225
+ if (newStage) {
226
+ addTimelineEvent(feature, newStage, stageNote, {
227
+ qualityMetrics: {
228
+ score: qualityUpdate.score,
229
+ grade: qualityUpdate.grade,
230
+ passRate: qualityUpdate.passRate,
231
+ issuesCount: qualityUpdate.issues.length
232
+ },
233
+ duration: ctx.duration
234
+ });
235
+ await store.saveState();
236
+ } else {
237
+ // 即使没有阶段变更,也记录验证完成事件
238
+ addTimelineEvent(feature, StageEnum.VERIFYING, '验证完成(有未通过项)', {
239
+ qualityMetrics: {
240
+ score: qualityUpdate.score,
241
+ grade: qualityUpdate.grade,
242
+ passRate: qualityUpdate.passRate,
243
+ passed: qualityUpdate.passed,
244
+ failed: qualityUpdate.failed
245
+ },
246
+ duration: ctx.duration
247
+ });
248
+ await store.saveState();
249
+ }
250
+
251
+ this._log('after', ctx);
252
+
253
+ // 输出摘要信息
254
+ console.log(
255
+ `[VerifyHook] 验证结果已记录:\n` +
256
+ ` - 综合评分: ${qualityUpdate.score}\n` +
257
+ ` - 质量等级: ${qualityUpdate.grade}\n` +
258
+ ` - 通过率: ${qualityUpdate.passRate.toFixed(1)}%\n` +
259
+ ` - 通过项: ${qualityUpdate.passed}\n` +
260
+ ` - 失败项: ${qualityUpdate.failed}\n` +
261
+ ` - 问题数: ${qualityUpdate.issues.length}\n` +
262
+ ` - 当前阶段: ${newStage || StageEnum.VERIFYING}`
263
+ );
264
+
265
+ // 如果有问题,输出简要列表
266
+ if (qualityUpdate.issues.length > 0 && qualityUpdate.issues.length <= 5) {
267
+ console.log('\n 问题详情:');
268
+ for (const issue of qualityUpdate.issues.slice(0, 5)) {
269
+ console.log(
270
+ ` [${issue.severity}] ${issue.type}: ${issue.message}`
271
+ );
272
+ }
273
+ if (qualityUpdate.issues.length > 5) {
274
+ console.log(` ... 还有 ${qualityUpdate.issues.length - 5} 个问题`);
275
+ }
276
+ }
277
+ } catch (error) {
278
+ console.error(`[VerifyHook] after 钩子执行失败: ${error.message}`);
279
+ }
280
+ }
281
+
282
+ /**
283
+ * 命令执行出错时的钩子
284
+ * 记录验证错误到 timeline
285
+ *
286
+ * @async
287
+ * @override
288
+ * @param {import('./hook-interface.js').HookContext} ctx - 钩子上下文
289
+ * @returns {Promise<void>}
290
+ */
291
+ async error(ctx) {
292
+ if (!this._isEnabled()) return;
293
+
294
+ try {
295
+ const store = await this._getStore();
296
+ const featureId = ctx.featureId || ctx.options?.feature;
297
+
298
+ if (!featureId) return;
299
+
300
+ const feature = store.getFeature(featureId);
301
+ if (!feature) return;
302
+
303
+ // 记录错误到 timeline
304
+ addTimelineEvent(feature, feature.stage, '验证过程出错', {
305
+ error: {
306
+ message: ctx.error?.message,
307
+ name: ctx.error?.name
308
+ },
309
+ duration: ctx.duration
310
+ });
311
+
312
+ await store.saveState();
313
+
314
+ this._log('error', ctx);
315
+ console.error(
316
+ `[VerifyHook] 已记录功能点 ${featureId} 的验证错误`
317
+ );
318
+ } catch (error) {
319
+ console.error(`[VerifyHook] error 钩子执行失败: ${error.message}`);
320
+ }
321
+ }
322
+
323
+ /**
324
+ * 解析验证命令的结果对象
325
+ * 支持多种可能的返回格式,提取标准化数据
326
+ *
327
+ * @private
328
+ * @param {*} result - verifyFeature 函数的返回值
329
+ * @returns {Object} 标准化的验证结果
330
+ */
331
+ _parseVerificationResult(result) {
332
+ if (!result) {
333
+ return {};
334
+ }
335
+
336
+ const parsed = {
337
+ overallScore: 0,
338
+ coverage: 0,
339
+ passRate: 0,
340
+ passed: 0,
341
+ failed: 0,
342
+ issues: [],
343
+ allPassed: false,
344
+ iterationRound: null
345
+ };
346
+
347
+ // 格式1: 标准 VerificationResult 结构
348
+ if (result.overallScore !== undefined) {
349
+ parsed.overallScore = result.overallScore;
350
+ }
351
+
352
+ if (result.coverage !== undefined) {
353
+ parsed.coverage = result.coverage;
354
+ }
355
+
356
+ // 解析通过/失败统计
357
+ if (result.summary) {
358
+ parsed.passed = result.summary.passed || 0;
359
+ parsed.failed = result.summary.failed || 0;
360
+ parsed.allPassed = result.summary.allPassed === true ||
361
+ result.summary.status === 'passed' ||
362
+ result.failed === 0;
363
+ } else if (result.passed !== undefined || result.failed !== undefined) {
364
+ parsed.passed = result.passed || 0;
365
+ parsed.failed = result.failed || 0;
366
+ parsed.allPassed = (parsed.failed === 0);
367
+ } else if (result.results) {
368
+ // 从 results 数组计算
369
+ for (const check of result.results) {
370
+ if (check.status === 'pass' || check.passed === true) {
371
+ parsed.passed++;
372
+ } else {
373
+ parsed.failed++;
374
+ }
375
+ }
376
+ parsed.allPassed = (parsed.failed === 0);
377
+ }
378
+
379
+ // 计算通过率
380
+ const total = parsed.passed + parsed.failed;
381
+ if (total > 0) {
382
+ parsed.passRate = (parsed.passed / total) * 100;
383
+ }
384
+
385
+ // 解析问题列表
386
+ if (Array.isArray(result.issues)) {
387
+ parsed.issues = result.issues.map(issue => ({
388
+ type: issue.type || issue.checkType || 'unknown',
389
+ name: issue.name || issue.rule || issue.title || '',
390
+ message: issue.message || issue.description || issue.detail || '',
391
+ severity: issue.severity || issue.level || 'medium',
392
+ file: issue.file || issue.filePath || '',
393
+ line: issue.line || issue.lineNumber || null
394
+ }));
395
+ } else if (Array.isArray(result.errors)) {
396
+ parsed.issues = result.errors.map(err => ({
397
+ type: 'error',
398
+ name: err.name || 'Error',
399
+ message: err.message || '',
400
+ severity: 'high',
401
+ file: err.file || '',
402
+ line: err.line || null
403
+ }));
404
+ } else if (Array.isArray(result.warnings)) {
405
+ parsed.issues = [
406
+ ...parsed.issues,
407
+ ...result.warnings.map(warn => ({
408
+ type: 'warning',
409
+ name: warn.name || 'Warning',
410
+ message: warn.message || '',
411
+ severity: 'medium',
412
+ file: warn.file || '',
413
+ line: warn.line || null
414
+ }))
415
+ ];
416
+ }
417
+
418
+ // 解析迭代数据
419
+ if (result.iteration) {
420
+ parsed.iterationRound = result.iteration;
421
+ } else if (result.round) {
422
+ parsed.iterationRound = result.round;
423
+ }
424
+
425
+ // 从 status 字段推断 allPassed
426
+ if (parsed.allPassed === false && result.status === 'passed') {
427
+ parsed.allPassed = true;
428
+ }
429
+
430
+ return parsed;
431
+ }
432
+
433
+ /**
434
+ * 构建迭代轮次记录对象
435
+ *
436
+ * @private
437
+ * @param {Object} rawData - 原始迭代数据
438
+ * @returns {import('../models.js').IterationRound}
439
+ */
440
+ _buildIterationRound(rawData) {
441
+ const now = new Date();
442
+
443
+ return {
444
+ round: rawData.round || 1,
445
+ startTime: rawData.startTime ? new Date(rawData.startTime) : now,
446
+ endTime: rawData.endTime ? new Date(rawData.endTime) : now,
447
+ fixedIssues: rawData.fixedIssues || [],
448
+ metrics: rawData.metrics || {},
449
+ summary: rawData.summary || ''
450
+ };
451
+ }
452
+ }
453
+
454
+ export default VerifyHook;