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,565 @@
1
+ /**
2
+ * PDD Plugin SDK - 插件开发工具包
3
+ *
4
+ * 提供插件基类、上下文对象和清单验证器,定义 PDD 插件系统的标准接口。
5
+ * 所有插件必须继承 PluginBase 并实现其生命周期方法。
6
+ *
7
+ * @module plugin-sdk
8
+ * @author PDD Team
9
+ * @version 1.0.0
10
+ * @license MIT
11
+ */
12
+
13
+ import { readFile, stat } from 'node:fs/promises';
14
+ import { join } from 'node:path';
15
+
16
+ // ==================== 插件状态枚举 ====================
17
+
18
+ /**
19
+ * 插件生命周期状态
20
+ * @enum {string}
21
+ */
22
+ export const PluginStatus = {
23
+ /** 已安装,尚未加载 */
24
+ INSTALLED: 'installed',
25
+ /** 已加载到内存 */
26
+ LOADED: 'loaded',
27
+ ** 已激活,可正常使用 */
28
+ ACTIVATED: 'activated',
29
+ /** 已停用 */
30
+ DEACTIVATED: 'deactivated',
31
+ /** 已卸载 */
32
+ UNINSTALLED: 'uninstalled',
33
+ /** 加载或激活出错 */
34
+ ERROR: 'error',
35
+ };
36
+
37
+ // ==================== PluginManifest 清单验证器 ====================
38
+
39
+ /**
40
+ * 插件清单验证器
41
+ * 负责验证 plugin.json 文件的格式和必填字段
42
+ *
43
+ * @class PluginManifest
44
+ */
45
+ export class PluginManifest {
46
+ /**
47
+ * 创建插件清单实例
48
+ * @param {Object} manifest - 原始清单数据
49
+ * @param {string} manifest.name - 插件名称(必填)
50
+ * @param {string} manifest.version - 插件版本(必填)
51
+ * @param {string} [manifest.description] - 插件描述
52
+ * @param {string} [manifest.main] - 入口文件(默认 index.js)
53
+ * @param {string} [manifest.pdd] - 兼容的 PDD 版本范围
54
+ * @param {string[]} [manifest.hooks] - 注册的钩子列表
55
+ * @param {Object} [manifest.dependencies] - 依赖声明
56
+ * @param {Object} [manifest.peerDependencies] - 对等依赖
57
+ * @param {string} [manifest.author] - 作者
58
+ * @param {string} [manifest.license] - 许可证
59
+ * @param {string[]} [manifest.keywords] - 关键词
60
+ */
61
+ constructor(manifest) {
62
+ this.raw = manifest;
63
+ this.errors = [];
64
+ this.warnings = [];
65
+ }
66
+
67
+ /**
68
+ * 验证清单数据是否合法
69
+ * @returns {{ valid: boolean, errors: string[], warnings: string[] }}
70
+ */
71
+ validate() {
72
+ this.errors = [];
73
+ this.warnings = [];
74
+
75
+ // 必填字段检查
76
+ if (!this.raw.name) {
77
+ this.errors.push('缺少必填字段: name');
78
+ } else if (!/^[a-z][a-z0-9-_]*$/.test(this.raw.name)) {
79
+ this.errors.push(`name 格式无效: "${this.raw.name}",仅允许小写字母、数字、连字符和下划线`);
80
+ }
81
+
82
+ if (!this.raw.version) {
83
+ this.errors.push('缺少必填字段: version');
84
+ } else if (!/^\d+\.\d+\.\d+/.test(this.raw.version)) {
85
+ this.errors.push(`version 格式无效: "${this.raw.version}",应为语义化版本`);
86
+ }
87
+
88
+ // 可选字段默认值
89
+ if (!this.raw.main) {
90
+ this.raw.main = 'index.js';
91
+ this.warnings.push('未指定 main 字段,使用默认值: index.js');
92
+ }
93
+
94
+ if (!this.raw.pdd) {
95
+ this.raw.pdd = '>=1.0.0';
96
+ this.warnings.push('未指定 pdd 兼容版本,使用默认值: >=1.0.0');
97
+ }
98
+
99
+ // hooks 格式验证
100
+ if (this.raw.hooks && !Array.isArray(this.raw.hooks)) {
101
+ this.errors.push('hooks 字段必须是数组');
102
+ }
103
+
104
+ return {
105
+ valid: this.errors.length === 0,
106
+ errors: [...this.errors],
107
+ warnings: [...this.warnings],
108
+ };
109
+ }
110
+
111
+ /**
112
+ * 从文件路径加载并验证清单
113
+ * @param {string} manifestPath - plugin.json 的绝对路径
114
+ * @returns {Promise<PluginManifest>}
115
+ * @throws {Error} 文件读取失败时抛出异常
116
+ */
117
+ static async load(manifestPath) {
118
+ const content = await readFile(manifestPath, 'utf-8');
119
+ const data = JSON.parse(content);
120
+ const manifest = new PluginManifest(data);
121
+ return manifest;
122
+ }
123
+ }
124
+
125
+ // ==================== PluginContext 运行时上下文 ====================
126
+
127
+ /**
128
+ * 插件运行时上下文
129
+ * 为插件提供配置访问、日志记录、缓存和 API 调用能力
130
+ *
131
+ * @class PluginContext
132
+ */
133
+ export class PluginContext {
134
+ /**
135
+ * 创建插件上下文实例
136
+ * @param {Object} options - 上下文配置选项
137
+ * @param {Object} options.config - 插件配置对象
138
+ * @param {Object} options.logger - 日志记录器(需实现 info/warn/error/debug 方法)
139
+ * @param {Map} options.cache - 共享缓存实例
140
+ * @param {Object} options.api - PDD 核心 API 对象
141
+ * @param {string} options.pluginDir - 插件根目录绝对路径
142
+ */
143
+ constructor({ config = {}, logger = null, cache = null, api = {}, pluginDir = '' }) {
144
+ /** @type {Object} 插件配置 */
145
+ this.config = config;
146
+
147
+ /** @type {Object|null} 日志记录器 */
148
+ this.logger = logger || this._createDefaultLogger();
149
+
150
+ /** @type {Map|null} 共享缓存 */
151
+ this.cache = cache || new Map();
152
+
153
+ /** @type {Object} PDD 核心 API */
154
+ this.api = api;
155
+
156
+ /** @type {string} 插件根目录 */
157
+ this.pluginDir = pluginDir;
158
+ }
159
+
160
+ /**
161
+ * 创建默认的日志记录器(输出到控制台)
162
+ * @returns {Object} 默认日志记录器
163
+ * @private
164
+ */
165
+ _createDefaultLogger() {
166
+ return {
167
+ info: (...args) => console.log('[INFO]', ...args),
168
+ warn: (...args) => console.warn('[WARN]', ...args),
169
+ error: (...args) => console.error('[ERROR]', ...args),
170
+ debug: (...args) => process.env.DEBUG && console.log('[DEBUG]', ...args),
171
+ };
172
+ }
173
+
174
+ /**
175
+ * 获取配置项
176
+ * @param {string} key - 配置键名(支持点号路径如 "server.port")
177
+ * @param {*} defaultValue - 配置不存在时的默认值
178
+ * @returns {*} 配置值
179
+ */
180
+ getConfig(key, defaultValue = undefined) {
181
+ const keys = key.split('.');
182
+ let value = this.config;
183
+ for (const k of keys) {
184
+ if (value == null || typeof value !== 'object') return defaultValue;
185
+ value = value[k];
186
+ }
187
+ return value ?? defaultValue;
188
+ }
189
+
190
+ /**
191
+ * 设置缓存项
192
+ * @param {string} key - 缓存键
193
+ * @param {*} value - 缓存值
194
+ * @param {number} [ttlMs=0] - 过期时间(毫秒),0 表示永不过期
195
+ */
196
+ setCache(key, value, ttlMs = 0) {
197
+ this.cache.set(key, {
198
+ value,
199
+ expiresAt: ttlMs > 0 ? Date.now() + ttlMs : 0,
200
+ });
201
+ }
202
+
203
+ /**
204
+ * 获取缓存项
205
+ * @param {string} key - 缓存键
206
+ * @returns {*|undefined} 缓存值,不存在或已过期返回 undefined
207
+ */
208
+ getCache(key) {
209
+ const item = this.cache.get(key);
210
+ if (!item) return undefined;
211
+ if (item.expiresAt > 0 && Date.now() > item.expiresAt) {
212
+ this.cache.delete(key);
213
+ return undefined;
214
+ }
215
+ return item.value;
216
+ }
217
+ }
218
+
219
+ // ==================== PluginBase 抽象基类 ====================
220
+
221
+ /**
222
+ * PDD 插件抽象基类
223
+ * 所有 PDD 插件必须继承此类并实现必要的方法
224
+ *
225
+ * @abstract
226
+ * @class PluginBase
227
+ *
228
+ * @example
229
+ * import { PluginBase } from './plugin-sdk.js';
230
+ *
231
+ * export default class MyPlugin extends PluginBase {
232
+ * constructor() {
233
+ * super({
234
+ * name: 'my-plugin',
235
+ * version: '1.0.0',
236
+ * description: '我的插件',
237
+ * });
238
+ * }
239
+ *
240
+ * async onActivate(context) {
241
+ * context.logger.info('插件已激活');
242
+ * this.registerCommand('hello', () => 'Hello World!');
243
+ * }
244
+ * }
245
+ */
246
+ export class PluginBase {
247
+ /**
248
+ * 创建插件实例
249
+ * @param {Object} metadata - 插件元数据
250
+ * @param {string} metadata.name - 插件名称
251
+ * @param {string} metadata.version - 插件版本
252
+ * @param {string} [metadata.description=''] - 插件描述
253
+ * @param {string} [metadata.author=''] - 作者
254
+ * @param {string} [metadata.license='MIT'] - 许可证
255
+ * @param {string[]} [metadata.keywords=[]] - 关键词
256
+ * @param {string} [metadata.pddVersionRange='>=1.0.0'] - 兼容的 PDD 版本范围
257
+ * @param {Object} [metadata.dependencies={}] - 运行时依赖
258
+ * @param {Object} [metadata.peerDependencies={}] - 对等依赖
259
+ */
260
+ constructor({
261
+ name,
262
+ version,
263
+ description = '',
264
+ author = '',
265
+ license = 'MIT',
266
+ keywords = [],
267
+ pddVersionRange = '>=1.0.0',
268
+ dependencies = {},
269
+ peerDependencies = {},
270
+ }) {
271
+ if (new.target === PluginBase) {
272
+ throw new Error('PluginBase 是抽象类,不能直接实例化。请继承此类创建插件。');
273
+ }
274
+
275
+ // ========== 元数据 ==========
276
+ /** @type {string} 插件名称 */
277
+ this.name = name;
278
+ /** @type {string} 插件版本 */
279
+ this.version = version;
280
+ /** @type {string} 插件描述 */
281
+ this.description = description;
282
+ /** @type {string} 作者 */
283
+ this.author = author;
284
+ /** @type {string} 许可证 */
285
+ this.license = license;
286
+ /** @type {string[]} 关键词 */
287
+ this.keywords = keywords;
288
+ /** @type {string} PDD 版本兼容范围 */
289
+ this.pddVersionRange = pddVersionRange;
290
+
291
+ // ========== 依赖声明 ==========
292
+ /** @type {Object} 运行时依赖 */
293
+ this.dependencies = dependencies;
294
+ /** @type {Object} 对等依赖 */
295
+ this.peerDependencies = peerDependencies;
296
+
297
+ // ========== 内部状态 ==========
298
+ /** @type {PluginStatus} 当前状态 */
299
+ this._status = PluginStatus.INSTALLED;
300
+ /** @type {PluginContext|null} 运行时上下文 */
301
+ this._context = null;
302
+ /** @type {Map<string, Function>} 已注册的命令 */
303
+ this._commands = new Map();
304
+ /** @type {Map<string, Function>} 已注册的钩子 */
305
+ this._hooks = new Map();
306
+ /** @type {Map<string, Object>} 已注册的工具 */
307
+ this._tools = new Map();
308
+ /** @type {Map<string, Function>} 已注册的格式化器 */
309
+ this._formatters = new Map();
310
+ }
311
+
312
+ /**
313
+ * 获取当前插件状态
314
+ * @returns {PluginStatus}
315
+ */
316
+ get status() {
317
+ return this._status;
318
+ }
319
+
320
+ /**
321
+ * 设置插件状态(内部使用)
322
+ * @param {PluginStatus} status - 新状态
323
+ * @private
324
+ */
325
+ _setStatus(status) {
326
+ this._status = status;
327
+ }
328
+
329
+ // ==================== 生命周期钩子 ====================
330
+
331
+ /**
332
+ * 安装后回调(可选重写)
333
+ * 在插件文件复制到插件目录后调用
334
+ * @param {PluginContext} context - 插件上下文
335
+ * @returns {Promise<void>}
336
+ */
337
+ async onInstall(context) {}
338
+
339
+ /**
340
+ * 激活回调(必须实现核心逻辑)
341
+ * 插件被激活时调用,在此处注册命令、钩子、工具等
342
+ * @param {PluginContext} context - 插件上下文
343
+ * @returns {Promise<void>}
344
+ * @abstract
345
+ */
346
+ async onActivate(context) {
347
+ throw new Error(`${this.name}: 必须实现 onActivate 方法`);
348
+ }
349
+
350
+ /**
351
+ * 停用回调(可选重写)
352
+ * 插件被停用时调用,在此处清理资源
353
+ * @param {PluginContext} context - 插件上下文
354
+ * @returns {Promise<void>}
355
+ */
356
+ async onDeactivate(context) {}
357
+
358
+ /**
359
+ * 卸载前回调(可选重写)
360
+ * 在插件文件删除前调用
361
+ * @param {PluginContext} context - 插件上下文
362
+ * @returns {Promise<void>}
363
+ */
364
+ async onUninstall(context) {}
365
+
366
+ /**
367
+ * 配置变更回调(可选重写)
368
+ * 当插件的配置项发生变化时调用
369
+ * @param {PluginContext} context - 插件上下文
370
+ * @param {Object} changedKeys - 变更的配置键
371
+ * @returns {Promise<void>}
372
+ */
373
+ async onConfigChange(context, changedKeys) {}
374
+
375
+ // ==================== 能力注册 API ====================
376
+
377
+ /**
378
+ * 注册命令
379
+ * @param {string} name - 命令名称
380
+ * @param {Function} handler - 命令处理函数
381
+ * @param {Object} [options={}] - 命令选项
382
+ * @param {string} [options.description] - 命令描述
383
+ * @throws {Error} 如果命令已存在
384
+ */
385
+ registerCommand(name, handler, options = {}) {
386
+ if (this._commands.has(name)) {
387
+ throw new Error(`命令 "${name}" 已在插件 "${this.name}" 中注册`);
388
+ }
389
+ this._commands.set(name, { handler, options, pluginName: this.name });
390
+ }
391
+
392
+ /**
393
+ * 注册钩子
394
+ * @param {string} name - 钩子名称(如 pre-verify, post-verify)
395
+ * @param {Function} handler - 钩子处理函数
396
+ * @param {number} [priority=100] - 执行优先级(数值越小越先执行)
397
+ * @throws {Error} 如果钩子已存在
398
+ */
399
+ registerHook(name, handler, priority = 100) {
400
+ const key = `${this.name}:${name}`;
401
+ if (this._hooks.has(key)) {
402
+ throw new Error(`钩子 "${name}" 已在插件 "${this.name}" 中注册`);
403
+ }
404
+ this._hooks.set(key, { name, handler, priority, pluginName: this.name });
405
+ }
406
+
407
+ /**
408
+ * 注册工具
409
+ * @param {string} name - 工具名称
410
+ * @param {Object} tool - 工具定义
411
+ * @param {Function} tool.execute - 工具执行函数
412
+ * @param {string} [tool.description] - 工具描述
413
+ * @param {Object} [tool.schema] - 参数 JSON Schema
414
+ * @throws {Error} 如果工具已存在
415
+ */
416
+ registerTool(name, tool) {
417
+ if (this._tools.has(name)) {
418
+ throw new Error(`工具 "${name}" 已在插件 "${this.name}" 中注册`);
419
+ }
420
+ this._tools.set(name, { ...tool, pluginName: this.name });
421
+ }
422
+
423
+ /**
424
+ * 注册格式化器
425
+ * @param {string} name - 格式化器名称(如 json, table, markdown)
426
+ * @param {Function} formatter - 格式化函数
427
+ * @throws {Error} 如果格式化器已存在
428
+ */
429
+ registerFormatter(name, formatter) {
430
+ if (this._formatters.has(name)) {
431
+ throw new Error(`格式化器 "${name}" 已在插件 "${this.name}" 中注册`);
432
+ }
433
+ this._formatters.set(name, { formatter, pluginName: this.name });
434
+ }
435
+
436
+ // ==================== 查询 API ====================
437
+
438
+ /**
439
+ * 获取所有已注册的命令
440
+ * @returns {Map<string, Object>}
441
+ */
442
+ getCommands() {
443
+ return new Map(this._commands);
444
+ }
445
+
446
+ /**
447
+ * 获取所有已注册的钩子
448
+ * @returns {Map<string, Object>}
449
+ */
450
+ getHooks() {
451
+ return new Map(this._hooks);
452
+ }
453
+
454
+ /**
455
+ * 获取所有已注册的工具
456
+ * @returns {Map<string, Object>}
457
+ */
458
+ getTools() {
459
+ return new Map(this._tools);
460
+ }
461
+
462
+ /**
463
+ * 获取所有已注册的格式化器
464
+ * @returns {Map<string, Object>}
465
+ */
466
+ getFormatters() {
467
+ return new Map(this._formatters);
468
+ }
469
+
470
+ /**
471
+ * 获取插件元数据摘要
472
+ * @returns {Object}
473
+ */
474
+ toJSON() {
475
+ return {
476
+ name: this.name,
477
+ version: this.version,
478
+ description: this.description,
479
+ author: this.author,
480
+ license: this.license,
481
+ keywords: this.keywords,
482
+ pddVersionRange: this.pddVersionRange,
483
+ dependencies: this.dependencies,
484
+ peerDependencies: this.peerDependencies,
485
+ status: this._status,
486
+ commandsCount: this._commands.size,
487
+ hooksCount: this._hooks.size,
488
+ toolsCount: this._tools.size,
489
+ formattersCount: this._formatters.size,
490
+ };
491
+ }
492
+ }
493
+
494
+ // ==================== 工厂函数 ====================
495
+
496
+ /**
497
+ * 创建插件实例的工厂函数
498
+ * 简化插件创建流程,自动绑定元数据和上下文
499
+ *
500
+ * @param {Class<PluginBase>} PluginClass - 继承自 PluginBase 的插件类
501
+ * @returns {PluginBase} 插件实例
502
+ *
503
+ * @example
504
+ * import { createPlugin, PluginBase } from './plugin-sdk.js';
505
+ *
506
+ * class MyPlugin extends PluginBase {
507
+ * constructor() {
508
+ * super({ name: 'my-plugin', version: '1.0.0' });
509
+ * }
510
+ * async onActivate(ctx) { /* ... */ }
511
+ * }
512
+ *
513
+ * const plugin = createPlugin(MyPlugin);
514
+ */
515
+ export function createPlugin(PluginClass) {
516
+ if (!PluginClass || typeof PluginClass !== 'function') {
517
+ throw new Error('createPlugin 需要一个继承自 PluginBase 的类');
518
+ }
519
+ const instance = new PluginClass();
520
+ if (!(instance instanceof PluginBase)) {
521
+ throw new Error('插件类必须继承自 PluginBase');
522
+ }
523
+ return instance;
524
+ }
525
+
526
+ // ==================== 版本比较工具 ====================
527
+
528
+ /**
529
+ * 简易版本号比较(仅支持 semver 子集)
530
+ * 用于判断插件是否与当前 PDD 版本兼容
531
+ *
532
+ * @param {string} range - 版本范围表达式(支持 >=, >, <=, <, =)
533
+ * @param {string} version - 实际版本号
534
+ * @returns {boolean} 是否匹配
535
+ * @example
536
+ * matchVersionRange('>=1.0.0', '2.0.0') // true
537
+ * matchVersionRange('>2.0.0', '1.9.0') // false
538
+ */
539
+ export function matchVersionRange(range, version) {
540
+ const rangeMatch = range.match(/^(>=|>|<=|<|=)?(\d+\.\d+\.\d+)$/);
541
+ if (!rangeMatch) return false;
542
+
543
+ const [, operator, rangeVer] = rangeMatch;
544
+ const verParts = version.split('.').map(Number);
545
+ const rangeParts = rangeVer.split('.').map(Number);
546
+
547
+ const compare = (a, b) => {
548
+ for (let i = 0; i < 3; i++) {
549
+ if ((a[i] ?? 0) > (b[i] ?? 0)) return 1;
550
+ if ((a[i] ?? 0) < (b[i] ?? 0)) return -1;
551
+ }
552
+ return 0;
553
+ };
554
+
555
+ const result = compare(verParts, rangeParts);
556
+
557
+ switch (operator) {
558
+ case '>=': return result >= 0;
559
+ case '>': return result > 0;
560
+ case '<=': return result <= 0;
561
+ case '<': return result < 0;
562
+ case '=':
563
+ default: return result === 0;
564
+ }
565
+ }