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,458 @@
1
+ /**
2
+ * @module lib/vm/hooks/hook-interface
3
+ * @description PDD Visual Manager Hook 系统核心接口和 HookManager 工厂函数
4
+ * 提供命令执行前后的生命周期钩子管理能力
5
+ *
6
+ * 设计原则:
7
+ * 1. Hook 失败不能影响原始命令执行(隔离机制)
8
+ * 2. 支持 --no-vm 参数完全跳过所有 Hook 记录
9
+ * 3. HookContext 包含足够的上下文信息供后续分析
10
+ */
11
+
12
+ /**
13
+ * 钩子上下文对象 - 传递给每个 Hook 的运行时信息
14
+ *
15
+ * @typedef {Object} HookContext
16
+ * @property {string} command - 命令名称 (generate/verify/extract/report)
17
+ * @property {string} [featureId] - 关联的功能点 ID(可选)
18
+ * @property {Object} [options] - 命令行选项参数
19
+ * @property {Date} timestamp - 命令开始时间戳
20
+ * @property {number} [duration] - 命令执行耗时(毫秒)
21
+ * @property {*} [result] - 命令成功执行的返回结果
22
+ * @property {Error} [error] - 命令执行时的错误对象
23
+ */
24
+
25
+ /**
26
+ * 创建新的 HookContext 实例
27
+ *
28
+ * @param {Object} params - 初始化参数
29
+ * @param {string} params.command - 命令名称
30
+ * @param {string} [params.featureId] - 功能点 ID
31
+ * @param {Object} [params.options={}] - 命令选项
32
+ * @returns {HookContext}
33
+ */
34
+ export function createHookContext({ command, featureId, options = {} }) {
35
+ return {
36
+ command,
37
+ featureId,
38
+ options: { ...options },
39
+ timestamp: new Date(),
40
+ duration: undefined,
41
+ result: undefined,
42
+ error: undefined
43
+ };
44
+ }
45
+
46
+ /**
47
+ * PDDHook 抽象基类 - 所有命令 Hook 的父类
48
+ * 定义了 Hook 的标准接口和通用行为
49
+ *
50
+ * 子类需要实现 before/after/error 方法来处理特定命令的生命周期事件
51
+ *
52
+ * @abstract
53
+ * @class
54
+ * @example
55
+ * class MyCustomHook extends PDDHook {
56
+ * name = 'my-custom'
57
+ *
58
+ * async before(ctx) {
59
+ * console.log(`Before ${ctx.command}`);
60
+ * }
61
+ *
62
+ * async after(ctx) {
63
+ * console.log(`After ${ctx.command}, result:`, ctx.result);
64
+ * }
65
+ * }
66
+ */
67
+ export class PDDHook {
68
+ /**
69
+ * 创建 PDDHook 实例
70
+ * @param {Object} [options={}] - 配置选项
71
+ * @param {boolean} [options.enabled=true] - 是否启用此 Hook
72
+ */
73
+ constructor(options = {}) {
74
+ /** @type {string} Hook 名称(子类必须设置) */
75
+ this.name = 'base';
76
+
77
+ /** @type {boolean} 是否启用 */
78
+ this.enabled = options.enabled !== false;
79
+
80
+ /**
81
+ * 是否禁用 VM 模式(全局 --no-vm 标志)
82
+ * @type {boolean}
83
+ * @protected
84
+ */
85
+ this._vmDisabled = false;
86
+ }
87
+
88
+ /**
89
+ * 设置 VM 禁用状态
90
+ * 当用户传入 --no-vm 参数时调用
91
+ *
92
+ * @param {boolean} disabled - 是否禁用
93
+ * @returns {void}
94
+ */
95
+ setVmDisabled(disabled) {
96
+ this._vmDisabled = disabled;
97
+ }
98
+
99
+ /**
100
+ * 检查当前 Hook 是否应该启用
101
+ * 综合考虑 enabled 标志和全局 _vmDisabled 状态
102
+ *
103
+ * @protected
104
+ * @returns {boolean} 如果应启用返回 true
105
+ */
106
+ _isEnabled() {
107
+ return this.enabled && !this._vmDisabled;
108
+ }
109
+
110
+ /**
111
+ * 命令执行前的钩子方法
112
+ * 用于记录前置状态、初始化资源等
113
+ *
114
+ * @async
115
+ * @param {HookContext} ctx - 钩子上下文
116
+ * @returns {Promise<void>}
117
+ */
118
+ async before(ctx) {
119
+ // 默认空实现 - 子类可覆盖
120
+ if (this._isEnabled()) {
121
+ this._log('before', ctx);
122
+ }
123
+ }
124
+
125
+ /**
126
+ * 命令成功执行后的钩子方法
127
+ * 用于记录结果、更新状态、收集指标等
128
+ *
129
+ * @async
130
+ * @param {HookContext} ctx - 钩子上下文(包含 result)
131
+ * @returns {Promise<void>}
132
+ */
133
+ async after(ctx) {
134
+ // 默认空实现 - 子类可覆盖
135
+ if (this._isEnabled()) {
136
+ this._log('after', ctx);
137
+ }
138
+ }
139
+
140
+ /**
141
+ * 命令执行出错时的钩子方法
142
+ * 用于记录错误、回滚状态等
143
+ *
144
+ * @async
145
+ * @param {HookContext} ctx - 钩子上下文(包含 error)
146
+ * @returns {Promise<void>}
147
+ */
148
+ async error(ctx) {
149
+ // 默认空实现 - 子类可覆盖
150
+ if (this._isEnabled()) {
151
+ this._log('error', ctx);
152
+ }
153
+ }
154
+
155
+ /**
156
+ * 内部日志方法(可被子类覆盖以实现自定义日志)
157
+ *
158
+ * @private
159
+ * @param {string} phase - 生命周期阶段
160
+ * @param {HookContext} ctx - 钩子上下文
161
+ * @returns {void}
162
+ */
163
+ _log(phase, ctx) {
164
+ const time = ctx.timestamp.toISOString();
165
+ console.log(
166
+ `[PDD-Hook][${time}] ${this.name}/${phase}` +
167
+ ` command=${ctx.command}` +
168
+ (ctx.featureId ? ` feature=${ctx.featureId}` : '')
169
+ );
170
+ }
171
+
172
+ /**
173
+ * 安全执行异步操作并捕获异常
174
+ * 所有 Hook 方法都应使用此包装器确保不抛出异常
175
+ *
176
+ * @async
177
+ * @private
178
+ * @param {string} phase - 生命周期阶段名称
179
+ * @param {Function} fn - 要执行的异步函数
180
+ * @returns {Promise<void>}
181
+ */
182
+ async _safeExecute(phase, fn) {
183
+ try {
184
+ await fn();
185
+ } catch (error) {
186
+ // Hook 异常只记录日志,不影响主流程
187
+ console.error(
188
+ `[PDD-Hook-Error] ${this.name}/${phase}: ${error.message}`
189
+ );
190
+ // 可选:将错误写入错误日志文件
191
+ await this._logHookError(phase, error);
192
+ }
193
+ }
194
+
195
+ /**
196
+ * 将 Hook 错误持久化到日志文件
197
+ *
198
+ * @async
199
+ * @private
200
+ * @param {string} phase - 阶段
201
+ * @param {Error} error - 错误对象
202
+ * @returns {Promise<void>}
203
+ */
204
+ async _logHookError(phase, error) {
205
+ try {
206
+ const { promises: fs } = await import('node:fs');
207
+ const logEntry = {
208
+ timestamp: new Date().toISOString(),
209
+ hook: this.name,
210
+ phase,
211
+ error: {
212
+ message: error.message,
213
+ stack: error.stack,
214
+ name: error.name
215
+ }
216
+ };
217
+
218
+ const logLine = JSON.stringify(logEntry) + '\n';
219
+ await fs.appendFile('.pdd-hook-errors.log', logLine, 'utf-8');
220
+ } catch {
221
+ // 日志写入失败时静默忽略,避免级联错误
222
+ }
223
+ }
224
+ }
225
+
226
+ /**
227
+ * HookManager - Hook 注册表和执行调度器
228
+ * 负责管理所有已注册的 Hook 并在适当时机触发它们
229
+ *
230
+ * @class
231
+ * @example
232
+ * const hm = createHookManager();
233
+ * hm.register(new GenerateHook());
234
+ * hm.register(new VerifyHook());
235
+ *
236
+ * await hm.executeBefore('generate', ctx);
237
+ * // ... 执行命令 ...
238
+ * await hm.executeAfter('generate', { ...ctx, result });
239
+ */
240
+ class HookManager {
241
+ constructor() {
242
+ /**
243
+ * 已注册的 Hook 映射表
244
+ * key: hook.name, value: PDDHook instance
245
+ * @type {Map<string, PDDHook>}
246
+ * @private
247
+ */
248
+ this._hooks = new Map();
249
+
250
+ /** @type {boolean} 全局 VM 禁用标志 */
251
+ this._globalVmDisabled = false;
252
+ }
253
+
254
+ /**
255
+ * 注册一个 Hook 实例
256
+ * 同名的 Hook 会被后注册的替换
257
+ *
258
+ * @param {PDDHook} hook - 要注册的 Hook 实例
259
+ * @returns {HookManager} 返回自身以支持链式调用
260
+ * @throws {TypeError} 如果 hook 不是 PDDHook 的实例
261
+ */
262
+ register(hook) {
263
+ if (!(hook instanceof PDDHook)) {
264
+ throw new TypeError('Hook 必须是 PDDHook 的实例');
265
+ }
266
+
267
+ // 同步全局禁用状态
268
+ hook.setVmDisabled(this._globalVmDisabled);
269
+
270
+ this._hooks.set(hook.name, hook);
271
+ return this;
272
+ }
273
+
274
+ /**
275
+ * 设置全局 VM 禁用状态
276
+ * 会同步到所有已注册的 Hook
277
+ *
278
+ * @param {boolean} disabled - 是否禁用
279
+ * @returns {void}
280
+ */
281
+ setGlobalVmDisabled(disabled) {
282
+ this._globalVmDisabled = disabled;
283
+ for (const hook of this._hooks.values()) {
284
+ hook.setVmDisabled(disabled);
285
+ }
286
+ }
287
+
288
+ /**
289
+ * 获取指定名称的 Hook
290
+ *
291
+ * @param {string} name - Hook 名称
292
+ * @returns {PDDHook|undefined}
293
+ */
294
+ getHook(name) {
295
+ return this._hooks.get(name);
296
+ }
297
+
298
+ /**
299
+ * 获取所有已注册的 Hook
300
+ *
301
+ * @returns {PDDHook[]}
302
+ */
303
+ getAllHooks() {
304
+ return Array.from(this._hooks.values());
305
+ }
306
+
307
+ /**
308
+ * 执行指定命令的所有 before 钩子
309
+ * 按注册顺序串行执行,任何单个 Hook 失败不会影响其他 Hook
310
+ *
311
+ * @async
312
+ * @param {string} command - 命令名称
313
+ * @param {HookContext} ctx - 钩子上下文
314
+ * @returns {Promise<void>}
315
+ */
316
+ async executeBefore(command, ctx) {
317
+ for (const [, hook] of this._hooks) {
318
+ await hook._safeExecute('before', () => hook.before({
319
+ ...ctx,
320
+ command
321
+ }));
322
+ }
323
+ }
324
+
325
+ /**
326
+ * 执行指定命令的所有 after 钩子
327
+ * 在命令成功完成后调用
328
+ *
329
+ * @async
330
+ * @param {string} command - 命令名称
331
+ * @param {HookContext} ctx - 钩子上下文(必须包含 result)
332
+ * @returns {Promise<void>}
333
+ */
334
+ async executeAfter(command, ctx) {
335
+ for (const [, hook] of this._hooks) {
336
+ await hook._safeExecute('after', () => hook.after({
337
+ ...ctx,
338
+ command
339
+ }));
340
+ }
341
+ }
342
+
343
+ /**
344
+ * 执行指定命令的所有 error 钩子
345
+ * 在命令执行出错时调用
346
+ *
347
+ * @async
348
+ * @param {string} command - 命令名称
349
+ * @param {HookContext} ctx - 钩子上下文(必须包含 error)
350
+ * @returns {Promise<void>}
351
+ */
352
+ async executeError(command, ctx) {
353
+ for (const [, hook] of this._hooks) {
354
+ await hook._safeExecute('error', () => hook.error({
355
+ ...ctx,
356
+ command
357
+ }));
358
+ }
359
+ }
360
+
361
+ /**
362
+ * 获取 HookManager 的统计信息
363
+ *
364
+ * @returns {{totalHooks: number, hooksByStatus: Object}}
365
+ */
366
+ getStats() {
367
+ let enabledCount = 0;
368
+ let disabledCount = 0;
369
+
370
+ for (const hook of this._hooks.values()) {
371
+ if (hook._isEnabled()) {
372
+ enabledCount++;
373
+ } else {
374
+ disabledCount++;
375
+ }
376
+ }
377
+
378
+ return {
379
+ totalHooks: this._hooks.size,
380
+ hooksByStatus: {
381
+ enabled: enabledCount,
382
+ disabled: disabledCount
383
+ },
384
+ globalVmDisabled: this._globalVmDisabled
385
+ };
386
+ }
387
+ }
388
+
389
+ /**
390
+ * 全局单例 HookManager 实例
391
+ * @type {HookManager|null}
392
+ * @private
393
+ */
394
+ let _singletonInstance = null;
395
+
396
+ /**
397
+ * 创建或获取 HookManager 单例实例
398
+ * 这是工厂函数,也是获取 HookManager 的推荐方式
399
+ *
400
+ * 使用示例:
401
+ * ```javascript
402
+ * import { getHookManager } from './lib/vm/hooks/hook-interface.js';
403
+ *
404
+ * // 获取单例
405
+ * const hm = getHookManager();
406
+ *
407
+ * // 注册内置 Hooks
408
+ * hm.register(new GenerateHook());
409
+ * hm.register(new VerifyHook());
410
+ *
411
+ * // 在 CLI 中使用
412
+ * if (!options.noVm) {
413
+ * await hm.executeBefore('generate', ctx);
414
+ * try {
415
+ * result = await generateCode(options);
416
+ * await hm.executeAfter('generate', { ...ctx, result });
417
+ * } catch (e) {
418
+ * await hm.executeError('generate', { ...ctx, error: e });
419
+ * throw e;
420
+ * }
421
+ * }
422
+ * ```
423
+ *
424
+ * @param {Object} [options={}] - 初始化选项
425
+ * @param {boolean} [options.noVm=false] - 是否禁用 VM 模式
426
+ * @returns {HookManager} HookManager 单例实例
427
+ */
428
+ export function getHookManager(options = {}) {
429
+ if (!_singletonInstance) {
430
+ _singletonInstance = new HookManager();
431
+
432
+ // 自动注册内置 Hook(可选,也可以手动注册)
433
+ // 这里不自动注册,让使用者按需注册
434
+ }
435
+
436
+ // 应用全局禁用配置
437
+ if (options.noVm) {
438
+ _singletonInstance.setGlobalVmDisabled(true);
439
+ }
440
+
441
+ return _singletonInstance;
442
+ }
443
+
444
+ /**
445
+ * 重置单例实例(主要用于测试)
446
+ *
447
+ * @returns {void}
448
+ */
449
+ export function resetHookManager() {
450
+ _singletonInstance = null;
451
+ }
452
+
453
+ export default {
454
+ PDDHook,
455
+ createHookContext,
456
+ getHookManager,
457
+ resetHookManager
458
+ };