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,783 @@
1
+ /**
2
+ * @module openclaw/openclaw-adapter
3
+ * @description OpenClaw 适配器核心模块 - 实现 PDD 与 OpenClaw 平台的双向集成
4
+ * @version 1.0.0
5
+ * @author PDD-Skills Team
6
+ */
7
+
8
+ import { EventEmitter } from 'events';
9
+ import { randomUUID } from 'crypto';
10
+
11
+ /**
12
+ * 标准消息封装类 - 用于 OpenClaw Protocol 消息格式化
13
+ * @class OpenClawMessage
14
+ */
15
+ export class OpenClawMessage {
16
+ /**
17
+ * 创建消息实例
18
+ * @param {Object} options - 消息配置选项
19
+ * @param {string} options.id - 消息唯一标识符(自动生成)
20
+ * @param {string} options.type - 消息类型 (request/response/event/error)
21
+ * @param {Object} options.payload - 消息负载
22
+ * @param {string} [options.sessionId] - 会话ID
23
+ * @param {number} [options.timestamp] - 时间戳
24
+ */
25
+ constructor({ id, type, payload, sessionId, timestamp }) {
26
+ this.id = id || randomUUID();
27
+ this.type = type;
28
+ this.payload = payload;
29
+ this.sessionId = sessionId;
30
+ this.timestamp = timestamp || Date.now();
31
+ }
32
+
33
+ /**
34
+ * 序列化为 JSON 字符串
35
+ * @returns {string} JSON 格式的消息字符串
36
+ */
37
+ toJSON() {
38
+ return JSON.stringify({
39
+ id: this.id,
40
+ type: this.type,
41
+ payload: this.payload,
42
+ sessionId: this.sessionId,
43
+ timestamp: this.timestamp
44
+ });
45
+ }
46
+
47
+ /**
48
+ * 从 JSON 字符串解析消息
49
+ * @param {string} jsonString - JSON 字符串
50
+ * @returns {OpenClawMessage} 消息实例
51
+ */
52
+ static fromJSON(jsonString) {
53
+ const data = JSON.parse(jsonString);
54
+ return new OpenClawMessage(data);
55
+ }
56
+
57
+ /**
58
+ * 创建请求消息
59
+ * @param {string} toolName - 工具名称
60
+ * @param {Object} params - 参数对象
61
+ * @param {string} [sessionId] - 会话ID
62
+ * @returns {OpenClawMessage} 请求消息实例
63
+ */
64
+ static createRequest(toolName, params, sessionId) {
65
+ return new OpenClawMessage({
66
+ type: 'request',
67
+ payload: {
68
+ tool: toolName,
69
+ params: params || {}
70
+ },
71
+ sessionId
72
+ });
73
+ }
74
+
75
+ /**
76
+ * 创建响应消息
77
+ * @param {string} requestId - 关联的请求ID
78
+ * @param {*} result - 结果数据
79
+ * @param {boolean} [success=true] - 是否成功
80
+ * @returns {OpenClawMessage} 响应消息实例
81
+ */
82
+ static createResponse(requestId, result, success = true) {
83
+ return new OpenClawMessage({
84
+ id: requestId,
85
+ type: 'response',
86
+ payload: {
87
+ success,
88
+ result,
89
+ timestamp: Date.now()
90
+ }
91
+ });
92
+ }
93
+
94
+ /**
95
+ * 创建错误消息
96
+ * @param {string} requestId - 关联的请求ID
97
+ * @param {Error|string} error - 错误信息
98
+ * @param {number} [code] - 错误码
99
+ * @returns {OpenClawMessage} 错误消息实例
100
+ */
101
+ static createError(requestId, error, code) {
102
+ return new OpenClawMessage({
103
+ id: requestId,
104
+ type: 'error',
105
+ payload: {
106
+ success: false,
107
+ error: error instanceof Error ? error.message : error,
108
+ code: code || 500,
109
+ timestamp: Date.now()
110
+ }
111
+ });
112
+ }
113
+ }
114
+
115
+ /**
116
+ * 能力注册表类 - 管理可暴露给 OpenClaw 的工具能力
117
+ * @class CapabilityRegistry
118
+ */
119
+ export class CapabilityRegistry {
120
+ constructor() {
121
+ /** @type {Map<string, Object>} 能力映射表 */
122
+ this.capabilities = new Map();
123
+
124
+ // 注册默认的 PDD 能力映射
125
+ this._registerDefaultCapabilities();
126
+ }
127
+
128
+ /**
129
+ * 注册默认的 PDD → OpenClaw 能力映射
130
+ * @private
131
+ */
132
+ _registerDefaultCapabilities() {
133
+ const defaultCapabilities = [
134
+ {
135
+ name: 'pdd_generate_spec',
136
+ description: '根据功能点生成开发规格和验收标准',
137
+ inputSchema: {
138
+ type: 'object',
139
+ properties: {
140
+ featureId: { type: 'string', description: '功能点ID' },
141
+ prdPath: { type: 'string', description: 'PRD文档路径' }
142
+ },
143
+ required: ['featureId']
144
+ },
145
+ handler: async (params) => ({
146
+ action: 'generate_spec',
147
+ params
148
+ })
149
+ },
150
+ {
151
+ name: 'pdd_generate_code',
152
+ description: '基于开发规格生成实现代码',
153
+ inputSchema: {
154
+ type: 'object',
155
+ properties: {
156
+ specPath: { type: 'string', description: '规格文件路径' },
157
+ outputDir: { type: 'string', description: '输出目录' }
158
+ },
159
+ required: ['specPath']
160
+ },
161
+ handler: async (params) => ({
162
+ action: 'generate_code',
163
+ params
164
+ })
165
+ },
166
+ {
167
+ name: 'pdd_verify_feature',
168
+ description: '验证功能实现是否符合规格和验收标准',
169
+ inputSchema: {
170
+ type: 'object',
171
+ properties: {
172
+ specPath: { type: 'string', description: '规格文件路径' },
173
+ codeDir: { type: 'string', description: '代码目录' }
174
+ },
175
+ required: ['specPath']
176
+ },
177
+ handler: async (params) => ({
178
+ action: 'verify_feature',
179
+ params
180
+ })
181
+ },
182
+ {
183
+ name: 'pdd_code_review',
184
+ description: '执行代码审查并生成审查报告',
185
+ inputSchema: {
186
+ type: 'object',
187
+ properties: {
188
+ codePath: { type: 'string', description: '代码路径' },
189
+ specPath: { type: 'string', description: '规格文件路径' }
190
+ },
191
+ required: ['codePath']
192
+ },
193
+ handler: async (params) => ({
194
+ action: 'code_review',
195
+ params
196
+ })
197
+ },
198
+ {
199
+ name: 'pdd_list_skills',
200
+ description: '列出所有可用的PDD技能',
201
+ inputSchema: {
202
+ type: 'object',
203
+ properties: {
204
+ category: { type: 'string', description: '技能分类' },
205
+ format: { type: 'string', enum: ['text', 'json'] }
206
+ }
207
+ },
208
+ handler: async (params) => ({
209
+ action: 'list_skills',
210
+ params
211
+ })
212
+ },
213
+ {
214
+ name: 'pdd_analyze_project',
215
+ description: '分析项目结构和依赖关系',
216
+ inputSchema: {
217
+ type: 'object',
218
+ properties: {
219
+ projectPath: { type: 'string', description: '项目路径' },
220
+ depth: { type: 'number', description: '分析深度' }
221
+ },
222
+ required: ['projectPath']
223
+ },
224
+ handler: async (params) => ({
225
+ action: 'analyze_project',
226
+ params
227
+ })
228
+ }
229
+ ];
230
+
231
+ for (const cap of defaultCapabilities) {
232
+ this.register(cap.name, cap);
233
+ }
234
+ }
235
+
236
+ /**
237
+ * 注册新能力
238
+ * @param {string} name - 能力名称
239
+ * @param {Object} capability - 能力定义
240
+ * @param {string} capability.description - 能力描述
241
+ * @param {Object} capability.inputSchema - 输入参数 schema
242
+ * @param {Function} capability.handler - 处理函数
243
+ * @returns {boolean} 是否注册成功
244
+ */
245
+ register(name, capability) {
246
+ if (this.capabilities.has(name)) {
247
+ return false;
248
+ }
249
+ this.capabilities.set(name, {
250
+ name,
251
+ description: capability.description || '',
252
+ inputSchema: capability.inputSchema || {},
253
+ handler: capability.handler || (() => ({})),
254
+ registeredAt: Date.now()
255
+ });
256
+ return true;
257
+ }
258
+
259
+ /**
260
+ * 注销能力
261
+ * @param {string} name - 能力名称
262
+ * @returns {boolean} 是否注销成功
263
+ */
264
+ unregister(name) {
265
+ return this.capabilities.delete(name);
266
+ }
267
+
268
+ /**
269
+ * 获取能力定义
270
+ * @param {string} name - 能力名称
271
+ * @returns {Object|undefined} 能力定义
272
+ */
273
+ get(name) {
274
+ return this.capabilities.get(name);
275
+ }
276
+
277
+ /**
278
+ * 列出所有已注册的能力
279
+ * @returns {Array<Object>} 能力列表
280
+ */
281
+ list() {
282
+ return Array.from(this.capabilities.values());
283
+ }
284
+
285
+ /**
286
+ * 获取能力数量
287
+ * @returns {number} 已注册能力总数
288
+ */
289
+ get size() {
290
+ return this.capabilities.size;
291
+ }
292
+
293
+ /**
294
+ * 将能力转换为 OpenClaw tools 格式
295
+ * @returns {Array<Object>} OpenClaw tools 数组
296
+ */
297
+ toOpenClawTools() {
298
+ return this.list().map(cap => ({
299
+ type: 'function',
300
+ function: {
301
+ name: cap.name,
302
+ description: cap.description,
303
+ parameters: cap.inputSchema
304
+ }
305
+ }));
306
+ }
307
+ }
308
+
309
+ /**
310
+ * OpenClaw 适配器核心类 - 管理连接、协议转换和消息处理
311
+ * @class OpenClawAdapter
312
+ * @extends EventEmitter
313
+ */
314
+ export class OpenClawAdapter extends EventEmitter {
315
+ /**
316
+ * 创建适配器实例
317
+ * @param {Object} options - 配置选项
318
+ * @param {string} [options.endpoint='http://localhost:8080'] - OpenClaw 服务端点
319
+ * @param {string} [options.token] - 认证令牌
320
+ * @param {number} [options.timeout=30000] - 请求超时时间(ms)
321
+ * @param {number} [options.heartbeatInterval=30000] - 心跳间隔(ms)
322
+ * @param {number} [options.maxReconnectDelay=30000] - 最大重连延迟(ms)
323
+ */
324
+ constructor(options = {}) {
325
+ super();
326
+
327
+ this.endpoint = options.endpoint || 'http://localhost:8080';
328
+ this.token = options.token;
329
+ this.timeout = options.timeout || 30000;
330
+ this.heartbeatInterval = options.heartbeatInterval || 30000;
331
+ this.maxReconnectDelay = options.maxReconnectDelay || 30000;
332
+
333
+ /** @type {'disconnected'|'connecting'|'connected'|'reconnecting'} 连接状态 */
334
+ this._status = 'disconnected';
335
+
336
+ /** @type {CapabilityRegistry} 能力注册表 */
337
+ this.registry = new CapabilityRegistry();
338
+
339
+ /** @type {Map<string, Function>} 待处理请求回调 */
340
+ this._pendingRequests = new Map();
341
+
342
+ /** @type {Timer|null} 心跳定时器 */
343
+ this._heartbeatTimer = null;
344
+
345
+ /** @type {number} 当前重连延迟 */
346
+ this._reconnectDelay = 1000;
347
+
348
+ /** @type {number} 重连尝试次数 */
349
+ this._reconnectAttempts = 0;
350
+
351
+ /** @type {Array<Object>} 消息日志 */
352
+ this._messageLog = [];
353
+
354
+ /** @type {Map<string, Object>} 会话存储 */
355
+ this._sessions = new Map();
356
+ }
357
+
358
+ /**
359
+ * 获取当前连接状态
360
+ * @returns {string} 状态字符串
361
+ */
362
+ getStatus() {
363
+ return this._status;
364
+ }
365
+
366
+ /**
367
+ * 获取适配器状态详情
368
+ * @returns {Object} 状态信息对象
369
+ */
370
+ getStatusDetails() {
371
+ return {
372
+ status: this._status,
373
+ endpoint: this.endpoint,
374
+ connectedAt: this._connectedAt || null,
375
+ uptime: this._connectedAt ? Date.now() - this._connectedAt : 0,
376
+ pendingRequests: this._pendingRequests.size,
377
+ activeSessions: this._sessions.size,
378
+ capabilitiesCount: this.registry.size,
379
+ reconnectAttempts: this._reconnectAttempts,
380
+ messageLogSize: this._messageLog.length
381
+ };
382
+ }
383
+
384
+ /**
385
+ * 连接到 OpenClaw 服务
386
+ * @param {Object} [options] - 连接选项
387
+ * @param {string} [options.endpoint] - 覆盖默认端点
388
+ * @param {string} [options.token] - 覆盖默认令牌
389
+ * @returns {Promise<boolean>} 是否连接成功
390
+ */
391
+ async connect(options = {}) {
392
+ if (this._status === 'connected') {
393
+ return true;
394
+ }
395
+
396
+ this._status = 'connecting';
397
+ this.emit('connecting');
398
+
399
+ const endpoint = options.endpoint || this.endpoint;
400
+ const token = options.token || this.token;
401
+
402
+ try {
403
+ // 模拟连接过程(实际场景中会建立 WebSocket 或 HTTP 连接)
404
+ await this._simulateConnection(endpoint, token);
405
+
406
+ this._status = 'connected';
407
+ this._connectedAt = Date.now();
408
+ this._reconnectDelay = 1000;
409
+ this._reconnectAttempts = 0;
410
+
411
+ // 启动心跳机制
412
+ this._startHeartbeat();
413
+
414
+ this.emit('connected', {
415
+ endpoint,
416
+ timestamp: Date.now()
417
+ });
418
+
419
+ this._logMessage('system', 'Connected to OpenClaw service');
420
+ return true;
421
+ } catch (error) {
422
+ this._status = 'disconnected';
423
+ this.emit('error', error);
424
+ throw error;
425
+ }
426
+ }
427
+
428
+ /**
429
+ * 断开连接
430
+ * @returns {Promise<void>}
431
+ */
432
+ async disconnect() {
433
+ if (this._status === 'disconnected') {
434
+ return;
435
+ }
436
+
437
+ // 停止心跳
438
+ this._stopHeartbeat();
439
+
440
+ // 清理待处理请求
441
+ for (const [id, callback] of this._pendingRequests) {
442
+ callback(OpenClawMessage.createError(id, 'Connection closed', 503));
443
+ }
444
+ this._pendingRequests.clear();
445
+
446
+ this._status = 'disconnected';
447
+ this._connectedAt = null;
448
+
449
+ this.emit('disconnected', {
450
+ timestamp: Date.now()
451
+ });
452
+
453
+ this._logMessage('system', 'Disconnected from OpenClaw service');
454
+ }
455
+
456
+ /**
457
+ * 重连到服务
458
+ * @returns {Promise<boolean>} 是否重连成功
459
+ */
460
+ async reconnect() {
461
+ if (this._status === 'connected') {
462
+ return true;
463
+ }
464
+
465
+ this._status = 'reconnecting';
466
+ this._reconnectAttempts++;
467
+ this.emit('reconnecting', {
468
+ attempt: this._reconnectAttempts,
469
+ delay: this._reconnectDelay
470
+ });
471
+
472
+ this._logMessage('system', `Reconnecting (attempt ${this._reconnectAttempts}, delay ${this._reconnectDelay}ms)`);
473
+
474
+ // 等待退避时间
475
+ await this._sleep(this._reconnectDelay);
476
+
477
+ try {
478
+ const success = await this.connect();
479
+ if (success) {
480
+ this._logMessage('system', 'Reconnection successful');
481
+ }
482
+ return success;
483
+ } catch (error) {
484
+ // 指数退避:1s -> 2s -> 4s -> 8s -> max 30s
485
+ this._reconnectDelay = Math.min(
486
+ this._reconnectDelay * 2,
487
+ this.maxReconnectDelay
488
+ );
489
+
490
+ this.emit('error', error);
491
+ return false;
492
+ }
493
+ }
494
+
495
+ /**
496
+ * 发送请求消息
497
+ * @param {string} toolName - 目标工具名称
498
+ * @param {Object} params - 参数对象
499
+ * @param {Object} [options] - 请求选项
500
+ * @param {number} [options.timeout] - 自定义超时时间
501
+ * @param {string} [options.sessionId] - 会话ID
502
+ * @returns {Promise<*>} 响应结果
503
+ */
504
+ async sendRequest(toolName, params, options = {}) {
505
+ if (this._status !== 'connected') {
506
+ throw new Error(`Adapter is not connected (current status: ${this._status})`);
507
+ }
508
+
509
+ const message = OpenClawMessage.createRequest(
510
+ toolName,
511
+ params,
512
+ options.sessionId
513
+ );
514
+
515
+ this._logMessage('outgoing', message);
516
+
517
+ return new Promise((resolve, reject) => {
518
+ const timeout = options.timeout || this.timeout;
519
+ const timer = setTimeout(() => {
520
+ this._pendingRequests.delete(message.id);
521
+ reject(new Error(`Request timeout after ${timeout}ms`));
522
+ }, timeout);
523
+
524
+ this._pendingRequests.set(message.id, (response) => {
525
+ clearTimeout(timer);
526
+ this._pendingRequests.delete(message.id);
527
+
528
+ if (response.type === 'error' || !response.payload.success) {
529
+ reject(new Error(response.payload.error || 'Unknown error'));
530
+ } else {
531
+ resolve(response.payload.result);
532
+ }
533
+ });
534
+
535
+ // 模拟发送和处理(实际场景中通过网络发送)
536
+ this._processRequest(message);
537
+ });
538
+ }
539
+
540
+ /**
541
+ * 处理接收到的消息
542
+ * @param {OpenClawMessage|string} message - 接收到的消息
543
+ */
544
+ handleMessage(message) {
545
+ const msg = typeof message === 'string'
546
+ ? OpenClawMessage.fromJSON(message)
547
+ : message;
548
+
549
+ this._logMessage('incoming', msg);
550
+
551
+ switch (msg.type) {
552
+ case 'response':
553
+ case 'error':
554
+ this._handleResponse(msg);
555
+ break;
556
+ case 'event':
557
+ this.emit('message', msg);
558
+ this.emit(`event:${msg.payload.event}`, msg);
559
+ break;
560
+ default:
561
+ this.emit('message', msg);
562
+ }
563
+ }
564
+
565
+ /**
566
+ * 创建新会话
567
+ * @param {Object} [metadata] - 会话元数据
568
+ * @returns {string} 会话ID
569
+ */
570
+ createSession(metadata = {}) {
571
+ const sessionId = randomUUID();
572
+ this._sessions.set(sessionId, {
573
+ id: sessionId,
574
+ createdAt: Date.now(),
575
+ lastActivity: Date.now(),
576
+ metadata,
577
+ messageCount: 0
578
+ });
579
+ return sessionId;
580
+ }
581
+
582
+ /**
583
+ * 销毁会话
584
+ * @param {string} sessionId - 会话ID
585
+ * @returns {boolean} 是否销毁成功
586
+ */
587
+ destroySession(sessionId) {
588
+ return this._sessions.delete(sessionId);
589
+ }
590
+
591
+ /**
592
+ * 获取会话列表
593
+ * @returns {Array<Object>} 会话列表
594
+ */
595
+ listSessions() {
596
+ return Array.from(this._sessions.values());
597
+ }
598
+
599
+ /**
600
+ * 获取消息日志
601
+ * @param {Object} [options] - 过滤选项
602
+ * @param {number} [options.limit=100] - 返回条数限制
603
+ * @param {string} [options.direction] - 方向过滤 (outgoing/incoming/system)
604
+ * @returns {Array<Object>} 消息日志
605
+ */
606
+ getMessageLog(options = {}) {
607
+ let log = [...this._messageLog];
608
+
609
+ if (options.direction) {
610
+ log = log.filter(entry => entry.direction === options.direction);
611
+ }
612
+
613
+ const limit = options.limit || 100;
614
+ return log.slice(-limit);
615
+ }
616
+
617
+ /**
618
+ * 清空消息日志
619
+ */
620
+ clearMessageLog() {
621
+ this._messageLog = [];
622
+ }
623
+
624
+ /**
625
+ * 模拟连接过程
626
+ * @private
627
+ * @param {string} endpoint - 端点URL
628
+ * @param {string} token - 认证令牌
629
+ */
630
+ async _simulateConnection(endpoint, token) {
631
+ // 在实际实现中,这里会建立真实的网络连接
632
+ // 当前为模拟实现
633
+ await this._sleep(100);
634
+
635
+ // 验证端点格式
636
+ if (!endpoint.startsWith('http://') && !endpoint.startsWith('https://')) {
637
+ throw new Error(`Invalid endpoint format: ${endpoint}`);
638
+ }
639
+ }
640
+
641
+ /**
642
+ * 处理请求(模拟)
643
+ * @private
644
+ * @param {OpenClawMessage} message - 请求消息
645
+ */
646
+ async _processRequest(message) {
647
+ // 模拟处理延迟
648
+ await this._sleep(50);
649
+
650
+ const capability = this.registry.get(message.payload.tool);
651
+
652
+ if (!capability) {
653
+ const errorMsg = OpenClawMessage.createError(
654
+ message.id,
655
+ `Unknown tool: ${message.payload.tool}`,
656
+ 404
657
+ );
658
+ this._handleResponse(errorMsg);
659
+ return;
660
+ }
661
+
662
+ try {
663
+ // 执行能力处理器
664
+ const result = await capability.handler(message.payload.params);
665
+
666
+ const response = OpenClawMessage.createResponse(message.id, {
667
+ tool: message.payload.tool,
668
+ ...result
669
+ });
670
+
671
+ this._handleResponse(response);
672
+ } catch (error) {
673
+ const errorMsg = OpenClawMessage.createError(message.id, error, 500);
674
+ this._handleResponse(errorMsg);
675
+ }
676
+ }
677
+
678
+ /**
679
+ * 处理响应消息
680
+ * @private
681
+ * @param {OpenClawMessage} response - 响应消息
682
+ */
683
+ _handleResponse(response) {
684
+ const callback = this._pendingRequests.get(response.id);
685
+ if (callback) {
686
+ callback(response);
687
+ }
688
+ this.emit('message', response);
689
+ }
690
+
691
+ /**
692
+ * 启动心跳机制
693
+ * @private
694
+ */
695
+ _startHeartbeat() {
696
+ this._stopHeartbeat();
697
+
698
+ this._heartbeatTimer = setInterval(() => {
699
+ if (this._status === 'connected') {
700
+ this._sendHeartbeat();
701
+ }
702
+ }, this.heartbeatInterval);
703
+
704
+ // 防止进程退出
705
+ if (this._heartbeatTimer.unref) {
706
+ this._heartbeatTimer.unref();
707
+ }
708
+ }
709
+
710
+ /**
711
+ * 停止心跳机制
712
+ * @private
713
+ */
714
+ _stopHeartbeat() {
715
+ if (this._heartbeatTimer) {
716
+ clearInterval(this._heartbeatTimer);
717
+ this._heartbeatTimer = null;
718
+ }
719
+ }
720
+
721
+ /**
722
+ * 发送心跳包
723
+ * @private
724
+ */
725
+ _sendHeartbeat() {
726
+ const heartbeat = new OpenClawMessage({
727
+ type: 'event',
728
+ payload: { event: 'ping', timestamp: Date.now() }
729
+ });
730
+
731
+ this._logMessage('outgoing', heartbeat);
732
+ this.emit('heartbeat', { direction: 'sent' });
733
+ }
734
+
735
+ /**
736
+ * 记录消息日志
737
+ * @private
738
+ * @param {string} direction - 消息方向
739
+ * @param {OpenClawMessage} message - 消息对象
740
+ */
741
+ _logMessage(direction, message) {
742
+ this._messageLog.push({
743
+ direction,
744
+ message,
745
+ timestamp: Date.now()
746
+ });
747
+
748
+ // 限制日志大小,防止内存泄漏
749
+ if (this._messageLog.length > 10000) {
750
+ this._messageLog = this._messageLog.slice(-5000);
751
+ }
752
+ }
753
+
754
+ /**
755
+ * 异步等待工具函数
756
+ * @private
757
+ * @param {number} ms - 等待毫秒数
758
+ * @returns {Promise<void>}
759
+ */
760
+ _sleep(ms) {
761
+ return new Promise(resolve => setTimeout(resolve, ms));
762
+ }
763
+
764
+ /**
765
+ * 销毁适配器实例,释放所有资源
766
+ * @returns {Promise<void>}
767
+ */
768
+ async destroy() {
769
+ await this.disconnect();
770
+ this._sessions.clear();
771
+ this._messageLog = [];
772
+ this.removeAllListeners();
773
+ }
774
+ }
775
+
776
+ /**
777
+ * 导出模块默认实例创建工厂
778
+ * @param {Object} options - 配置选项
779
+ * @returns {OpenClawAdapter} 适配器实例
780
+ */
781
+ export function createAdapter(options = {}) {
782
+ return new OpenClawAdapter(options);
783
+ }