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,331 @@
1
+ /**
2
+ * @module lib/vm/hooks/report-hook
3
+ * @description Report 命令 Hook 实现
4
+ * 负责记录报告生成命令的结果,包括:
5
+ * - after: 将生成的报告路径关联到对应的 Feature
6
+ * 更新 artifacts.report 对象(path/type/lastModified)
7
+ *
8
+ * Report Hook 相对简单,主要关注报告文件的元数据关联
9
+ */
10
+
11
+ import { PDDHook } from './hook-interface.js';
12
+ import { addTimelineEvent } from '../models.js';
13
+ import { getStateStore } from '../state-store.js';
14
+
15
+ /**
16
+ * ReportHook - 处理 `pdd report` 命令的生命周期事件
17
+ *
18
+ * @class
19
+ * @extends PDDHook
20
+ *
21
+ * @example
22
+ * import { ReportHook } from './lib/vm/hooks/report-hook.js';
23
+ * const hook = new ReportHook();
24
+ * hookManager.register(hook);
25
+ */
26
+ export class ReportHook extends PDDHook {
27
+ /**
28
+ * 创建 ReportHook 实例
29
+ */
30
+ constructor() {
31
+ super({ enabled: true });
32
+ /** @override */
33
+ this.name = 'report';
34
+
35
+ /**
36
+ * StateStore 实例缓存
37
+ * @type {import('../state-store.js').StateStore|null}
38
+ * @private
39
+ */
40
+ this._store = null;
41
+ }
42
+
43
+ /**
44
+ * 获取或初始化 StateStore 实例
45
+ *
46
+ * @async
47
+ * @private
48
+ * @returns {Promise<import('../state-store.js').StateStore>}
49
+ */
50
+ async _getStore() {
51
+ if (!this._store) {
52
+ this._store = await getStateStore();
53
+ }
54
+ return this._store;
55
+ }
56
+
57
+ /**
58
+ * 命令执行前的钩子
59
+ * 记录报告生成开始状态
60
+ *
61
+ * @async
62
+ * @override
63
+ * @param {import('./hook-interface.js').HookContext} ctx - 钩子上下文
64
+ * @returns {Promise<void>}
65
+ */
66
+ async before(ctx) {
67
+ if (!this._isEnabled()) return;
68
+
69
+ try {
70
+ this._log('before', ctx);
71
+ console.log(
72
+ `[ReportHook] 开始生成报告\n` +
73
+ ` 报告类型: ${ctx.options?.type || 'md'}\n` +
74
+ ` 输出路径: ${ctx.options?.output || './reports/pdd-report'}\n` +
75
+ ` 包含统计: ${ctx.options?.includeStats || false}\n` +
76
+ ` 包含图表: ${ctx.options?.includeCharts || false}`
77
+ );
78
+ } catch (error) {
79
+ console.error(`[ReportHook] before 钩子执行失败: ${error.message}`);
80
+ }
81
+ }
82
+
83
+ /**
84
+ * 命令成功执行后的钩子
85
+ * 主要职责:
86
+ * 1. 从 result 中获取生成的报告信息
87
+ * 2. 将报告路径关联到对应 feature 的 artifacts.report:
88
+ * - artifacts.report.path = reportOutputPath
89
+ * - artifacts.report.type = reportType (md/json/html)
90
+ * - artifacts.report.lastModified = now
91
+ * 3. 更新对应 feature 的 artifacts
92
+ * 4. 如果报告是针对特定功能点的,更新该功能点;
93
+ * 如果是全局报告,尝试关联到所有相关功能点
94
+ *
95
+ * @async
96
+ * @override
97
+ * @param {import('./hook-interface.js').HookContext} ctx - 钩子上下文(包含 result)
98
+ * @returns {Promise<void>}
99
+ */
100
+ async after(ctx) {
101
+ if (!this._isEnabled()) return;
102
+
103
+ try {
104
+ const store = await this._getStore();
105
+ const result = ctx.result;
106
+ const featureId = ctx.featureId || ctx.options?.feature;
107
+
108
+ // 解析报告结果
109
+ const reportInfo = this._parseReportResult(result, ctx);
110
+
111
+ if (!reportInfo || !reportInfo.path) {
112
+ console.log('[ReportHook] 未获取到有效的报告路径信息');
113
+ this._log('after', ctx);
114
+ return;
115
+ }
116
+
117
+ // 构建标准化的报告对象
118
+ const reportArtifact = {
119
+ path: reportInfo.path,
120
+ type: reportInfo.type || ctx.options?.type || 'md',
121
+ lastModified: new Date(),
122
+ size: reportInfo.size || 0,
123
+ metadata: {
124
+ includeStats: ctx.options?.includeStats || false,
125
+ includeCharts: ctx.options?.includeCharts || false,
126
+ generatedAt: new Date().toISOString()
127
+ }
128
+ };
129
+
130
+ let updatedFeatures = [];
131
+
132
+ if (featureId) {
133
+ // 情况1:针对特定功能点的报告
134
+ const feature = store.getFeature(featureId);
135
+
136
+ if (feature) {
137
+ await store.updateFeature(featureId, {
138
+ artifacts: {
139
+ ...feature.artifacts,
140
+ report: reportArtifact
141
+ }
142
+ });
143
+
144
+ // 添加时间线事件
145
+ addTimelineEvent(feature, feature.stage, `报告已生成 (${reportArtifact.type})`, {
146
+ reportPath: reportArtifact.path,
147
+ reportType: reportArtifact.type,
148
+ duration: ctx.duration
149
+ });
150
+ await store.saveState();
151
+
152
+ updatedFeatures.push(featureId);
153
+ } else {
154
+ console.log(
155
+ `[ReportHook] 功能点 ${featureId} 不存在,无法关联报告`
156
+ );
157
+ }
158
+ } else {
159
+ // 情况2:全局报告,关联到所有活跃的功能点
160
+ const allFeatures = store.getAllFeatures().filter(
161
+ f => f.status === 'active'
162
+ );
163
+
164
+ for (const feature of allFeatures) {
165
+ // 为每个活跃功能点添加报告引用
166
+ await store.updateFeature(feature.id, {
167
+ artifacts: {
168
+ ...feature.artifacts,
169
+ report: reportArtifact
170
+ }
171
+ });
172
+
173
+ updatedFeatures.push(feature.id);
174
+ }
175
+
176
+ console.log(
177
+ `[ReportHook] 全局报告已关联到 ${updatedFeatures.length} 个功能点`
178
+ );
179
+ }
180
+
181
+ this._log('after', ctx);
182
+
183
+ // 输出摘要信息
184
+ console.log(
185
+ `\n[ReportHook] 报告生成结果:\n` +
186
+ ` 报告路径: ${reportArtifact.path}\n` +
187
+ ` 报告类型: ${reportArtifact.type}\n` +
188
+ ` 文件大小: ${this._formatFileSize(reportArtifact.size)}\n` +
189
+ ` 关联功能点: ${updatedFeatures.length} 个\n` +
190
+ ` 生成时间: ${reportArtifact.lastModified.toLocaleString()}`
191
+ );
192
+
193
+ if (updatedFeatures.length > 0 && updatedFeatures.length <= 5) {
194
+ console.log('\n 关联的功能点:');
195
+ for (const fid of updatedFeatures) {
196
+ const f = store.getFeature(fid);
197
+ console.log(` - [${fid}] ${f?.name || '未知'}`);
198
+ }
199
+ }
200
+ } catch (error) {
201
+ console.error(`[ReportHook] after 钩子执行失败: ${error.message}`);
202
+ }
203
+ }
204
+
205
+ /**
206
+ * 命令执行出错时的钩子
207
+ *
208
+ * @async
209
+ * @override
210
+ * @param {import('./hook-interface.js').HookContext} ctx - 钩子上下文
211
+ * @returns {Promise<void>}
212
+ */
213
+ async error(ctx) {
214
+ if (!this._isEnabled()) return;
215
+
216
+ try {
217
+ this._log('error', ctx);
218
+ console.error(
219
+ `[ReportHook] 报告生成失败:\n` +
220
+ ` 错误: ${ctx.error?.message}\n` +
221
+ ` 类型: ${ctx.error?.name}`
222
+ );
223
+ } catch (error) {
224
+ console.error(`[ReportHook] error 钩子执行失败: ${error.message}`);
225
+ }
226
+ }
227
+
228
+ /**
229
+ * 解析 report 命令的结果对象
230
+ * 提取报告文件路径和元数据
231
+ *
232
+ * @private
233
+ * @param {*} result - generateReport 函数的返回值
234
+ * @param {import('./hook-interface.js').HookContext} ctx - 钩子上下文
235
+ * @returns {Object|null} 报告信息对象
236
+ */
237
+ _parseReportResult(result, ctx) {
238
+ if (!result) {
239
+ // 如果没有返回值,从 options 推断输出路径
240
+ return {
241
+ path: ctx.options?.output ?
242
+ `${ctx.options.output}.${ctx.options?.type || 'md'}` :
243
+ './reports/pdd-report.md',
244
+ type: ctx.options?.type || 'md',
245
+ size: 0
246
+ };
247
+ }
248
+
249
+ const parsed = {};
250
+
251
+ // 格式1: { path: ..., type: ..., size: ... }
252
+ if (result.path) {
253
+ parsed.path = result.path;
254
+ }
255
+
256
+ if (result.type) {
257
+ parsed.type = result.type;
258
+ }
259
+
260
+ if (result.size !== undefined) {
261
+ parsed.size = result.size;
262
+ }
263
+
264
+ // 格式2: { outputPath: ..., format: ... }
265
+ if (!parsed.path && result.outputPath) {
266
+ parsed.path = result.outputPath;
267
+ }
268
+
269
+ if (!parsed.type && result.format) {
270
+ parsed.type = result.format;
271
+ }
272
+
273
+ // 格式3: { file: { path, size }, type }
274
+ if (!parsed.path && result.file?.path) {
275
+ parsed.path = result.file.path;
276
+ parsed.size = result.file.size || parsed.size;
277
+ }
278
+
279
+ // 格式4: 直接是字符串(文件路径)
280
+ if (
281
+ !parsed.path &&
282
+ typeof result === 'string' &&
283
+ result.endsWith('.md' || '.json' || '.html')
284
+ ) {
285
+ parsed.path = result;
286
+ }
287
+
288
+ // 确保有默认值
289
+ if (!parsed.path) {
290
+ parsed.path =
291
+ ctx.options?.output ||
292
+ `./reports/pdd-report.${ctx.options?.type || 'md'}`;
293
+ }
294
+
295
+ if (!parsed.type) {
296
+ parsed.type = ctx.options?.type || 'md';
297
+ }
298
+
299
+ if (parsed.size === undefined) {
300
+ parsed.size = 0;
301
+ }
302
+
303
+ return parsed;
304
+ }
305
+
306
+ /**
307
+ * 格式化文件大小显示
308
+ *
309
+ * @private
310
+ * @param {number} bytes - 字节数
311
+ * @returns {string} 格式化后的大小字符串
312
+ */
313
+ _formatFileSize(bytes) {
314
+ if (!bytes || bytes === 0) {
315
+ return '未知';
316
+ }
317
+
318
+ const units = ['B', 'KB', 'MB', 'GB'];
319
+ let size = bytes;
320
+ let unitIndex = 0;
321
+
322
+ while (size >= 1024 && unitIndex < units.length - 1) {
323
+ size /= 1024;
324
+ unitIndex++;
325
+ }
326
+
327
+ return `${size.toFixed(2)} ${units[unitIndex]}`;
328
+ }
329
+ }
330
+
331
+ export default ReportHook;