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,535 @@
1
+ /**
2
+ * @module openclaw/api-integration
3
+ * @description OpenClaw API 集成模块 - 提供 RESTful 和流式接口
4
+ * @version 1.0.0
5
+ * @author PDD-Skills Team
6
+ */
7
+
8
+ import { createServer, IncomingMessage, ServerResponse } from 'http';
9
+ import { randomUUID } from 'crypto';
10
+ import { OpenClawAdapter, createAdapter } from './openclaw-adapter.js';
11
+
12
+ /**
13
+ * 中间件上下文对象
14
+ * @typedef {Object} MiddlewareContext
15
+ * @property {IncomingMessage} req - HTTP 请求对象
16
+ * @property {ServerResponse} res - HTTP 响应对象
17
+ * @property {Object} body - 请求体
18
+ * @property {Object} [user] - 认证用户信息
19
+ * @property {Object} [meta] - 元数据
20
+ */
21
+
22
+ /**
23
+ * 中间件函数类型
24
+ * @callback MiddlewareFunction
25
+ * @param {MiddlewareContext} ctx - 上下文对象
26
+ * @param {Function} next - 下一个中间件
27
+ * @returns {Promise<void>}
28
+ */
29
+
30
+ /**
31
+ * OpenClaw API Bridge 类 - 处理 HTTP/WebSocket 请求
32
+ * @class OpenClawAPIBridge
33
+ */
34
+ export class OpenClawAPIBridge {
35
+ /**
36
+ * 创建 API Bridge 实例
37
+ * @param {Object} options - 配置选项
38
+ * @param {OpenClawAdapter} [options.adapter] - 适配器实例
39
+ * @param {string} [options.apiKey] - API 密钥
40
+ * @param {number} [options.rateLimitMax=100] - 速率限制最大请求数
41
+ * @param {number} [options.rateLimitWindowMs=60000] - 速率限制时间窗口
42
+ */
43
+ constructor(options = {}) {
44
+ this.adapter = options.adapter || createAdapter();
45
+ this.apiKey = options.apiKey;
46
+ this.rateLimitMax = options.rateLimitMax || 100;
47
+ this.rateLimitWindowMs = options.rateLimitWindowMs || 60000;
48
+
49
+ /** @type {Array<MiddlewareFunction>} 中间件链 */
50
+ this.middlewares = [];
51
+
52
+ /** @type {Map<string, Object>} 会话存储 */
53
+ this.sessions = new Map();
54
+
55
+ /** @type {Map<string, Array>} 速率限制计数器 */
56
+ this.rateLimiters = new Map();
57
+
58
+ /** @type {Object|null} HTTP 服务器实例 */
59
+ this.server = null;
60
+
61
+ /** @type {Array<Object>} 请求日志 */
62
+ this.requestLog = [];
63
+
64
+ // 初始化内置中间件
65
+ this._initBuiltInMiddlewares();
66
+ }
67
+
68
+ /**
69
+ * 初始化内置中间件
70
+ * @private
71
+ */
72
+ _initBuiltInMiddlewares() {
73
+ // 认证中间件
74
+ this.use(async (ctx, next) => {
75
+ if (this.apiKey) {
76
+ const authHeader = ctx.req.headers['authorization'];
77
+ const apiKey = ctx.req.headers['x-api-key'];
78
+
79
+ const token = authHeader?.startsWith('Bearer ')
80
+ ? authHeader.substring(7)
81
+ : apiKey;
82
+
83
+ if (!token || token !== this.apiKey) {
84
+ return this._sendError(ctx.res, 401, 'Unauthorized: Invalid or missing API key');
85
+ }
86
+
87
+ ctx.user = { authenticated: true, apiKey: token.substring(0, 8) + '...' };
88
+ }
89
+ await next();
90
+ });
91
+
92
+ // 速率限制中间件
93
+ this.use(async (ctx, next) => {
94
+ const clientId = ctx.req.socket.remoteAddress || 'unknown';
95
+ const now = Date.now();
96
+
97
+ if (!this.rateLimiters.has(clientId)) {
98
+ this.rateLimiters.set(clientId, []);
99
+ }
100
+
101
+ const requests = this.rateLimiters.get(clientId);
102
+ const windowStart = now - this.rateLimitWindowMs;
103
+
104
+ // 清除过期记录
105
+ while (requests.length > 0 && requests[0] < windowStart) {
106
+ requests.shift();
107
+ }
108
+
109
+ if (requests.length >= this.rateLimitMax) {
110
+ return this._sendError(ctx.res, 429, 'Too Many Requests: Rate limit exceeded');
111
+ }
112
+
113
+ requests.push(now);
114
+ await next();
115
+ });
116
+
117
+ // 日志中间件
118
+ this.use(async (ctx, next) => {
119
+ const start = Date.now();
120
+
121
+ await next();
122
+
123
+ const duration = Date.now() - start;
124
+ this._logRequest(ctx, duration);
125
+ });
126
+
127
+ // 路由中间件
128
+ this.use(async (ctx, next) => {
129
+ await this._routeRequest(ctx);
130
+ });
131
+ }
132
+
133
+ /**
134
+ * 添加自定义中间件
135
+ * @param {MiddlewareFunction} middleware - 中间件函数
136
+ * @returns {OpenClawAPIBridge} this(支持链式调用)
137
+ */
138
+ use(middleware) {
139
+ this.middlewares.push(middleware);
140
+ return this;
141
+ }
142
+
143
+ /**
144
+ * 启动 API 服务器
145
+ * @param {number} port - 监听端口
146
+ * @param {string} [host='localhost'] - 绑定地址
147
+ * @returns {Promise<void>}
148
+ */
149
+ async start(port, host = 'localhost') {
150
+ return new Promise((resolve, reject) => {
151
+ this.server = createServer(async (req, res) => {
152
+ try {
153
+ const ctx = {
154
+ req,
155
+ res,
156
+ body: await this._parseBody(req),
157
+ meta: {}
158
+ };
159
+
160
+ // 执行中间件链
161
+ await this._executeMiddlewares(ctx);
162
+ } catch (error) {
163
+ this._sendError(res, 500, `Internal Server Error: ${error.message}`);
164
+ }
165
+ });
166
+
167
+ this.server.listen(port, host, () => {
168
+ console.log(`🌐 OpenClaw API 服务器已启动: http://${host}:${port}`);
169
+ console.log(` 端点:`);
170
+ console.log(` POST /api/openclaw/chat`);
171
+ console.log(` POST /api/openclaw/tools/call`);
172
+ console.log(` GET /api/openclaw/tools`);
173
+ console.log(` GET /api/openclaw/sessions`);
174
+ console.log(` WS /api/openclaw/stream\n`);
175
+ resolve();
176
+ });
177
+
178
+ this.server.on('error', reject);
179
+ });
180
+ }
181
+
182
+ /**
183
+ * 停止服务器
184
+ * @returns {Promise<void>}
185
+ */
186
+ async stop() {
187
+ return new Promise((resolve) => {
188
+ if (!this.server) {
189
+ resolve();
190
+ return;
191
+ }
192
+
193
+ this.server.close(() => {
194
+ this.server = null;
195
+ console.log('🛑 OpenClaw API 服务器已停止');
196
+ resolve();
197
+ });
198
+ });
199
+ }
200
+
201
+ /**
202
+ * 处理聊天接口
203
+ * @private
204
+ * @param {MiddlewareContext} ctx - 上下文
205
+ */
206
+ async _handleChat(ctx) {
207
+ const { messages, stream = false } = ctx.body;
208
+
209
+ if (!messages || !Array.isArray(messages)) {
210
+ return this._sendError(ctx.res, 400, 'messages array is required');
211
+ }
212
+
213
+ if (stream) {
214
+ // SSE 流式响应
215
+ this._setSSEHeaders(ctx.res);
216
+
217
+ for (const message of messages) {
218
+ const response = await this._processChatMessage(message);
219
+ ctx.res.write(`data: ${JSON.stringify(response)}\n\n`);
220
+ }
221
+
222
+ ctx.res.write('data: [DONE]\n\n');
223
+ ctx.res.end();
224
+ } else {
225
+ // 普通响应
226
+ const results = [];
227
+ for (const message of messages) {
228
+ results.push(await this._processChatMessage(message));
229
+ }
230
+
231
+ this._sendJSON(ctx.res, 200, {
232
+ success: true,
233
+ responses: results,
234
+ count: results.length
235
+ });
236
+ }
237
+ }
238
+
239
+ /**
240
+ * 处理单个聊天消息
241
+ * @private
242
+ * @param {Object} message - 消息对象
243
+ * @returns {Promise<Object>} 响应结果
244
+ */
245
+ async _processChatMessage(message) {
246
+ const { role, content, tool_calls } = message;
247
+
248
+ // 如果包含工具调用
249
+ if (tool_calls && tool_calls.length > 0) {
250
+ const results = [];
251
+ for (const call of tool_calls) {
252
+ try {
253
+ const result = await this.adapter.sendRequest(call.function.name, call.function.arguments);
254
+ results.push({
255
+ id: call.id,
256
+ result
257
+ });
258
+ } catch (error) {
259
+ results.push({
260
+ id: call.id,
261
+ error: error.message
262
+ });
263
+ }
264
+ }
265
+
266
+ return {
267
+ role: 'tool',
268
+ content: results
269
+ };
270
+ }
271
+
272
+ // 普通消息处理
273
+ return {
274
+ role: 'assistant',
275
+ content: `Processed: ${typeof content === 'string' ? content.substring(0, 100) : '[complex content]'}`,
276
+ timestamp: Date.now()
277
+ };
278
+ }
279
+
280
+ /**
281
+ * 处理工具调用接口
282
+ * @private
283
+ * @param {MiddlewareContext} ctx - 上下文
284
+ */
285
+ async _handleToolCall(ctx) {
286
+ const { tool_name, parameters, session_id } = ctx.body;
287
+
288
+ if (!tool_name) {
289
+ return this._sendError(ctx.res, 400, 'tool_name is required');
290
+ }
291
+
292
+ try {
293
+ const result = await this.adapter.sendRequest(tool_name, parameters || {}, {
294
+ sessionId: session_id
295
+ });
296
+
297
+ this._sendJSON(ctx.res, 200, {
298
+ success: true,
299
+ tool: tool_name,
300
+ result,
301
+ timestamp: Date.now()
302
+ });
303
+ } catch (error) {
304
+ this._sendError(ctx.res, 500, `Tool execution failed: ${error.message}`);
305
+ }
306
+ }
307
+
308
+ /**
309
+ * 处理工具列表接口
310
+ * @private
311
+ * @param {MiddlewareContext} ctx - 上下文
312
+ */
313
+ async _handleListTools(ctx) {
314
+ const tools = this.adapter.registry.toOpenClawTools();
315
+
316
+ this._sendJSON(ctx.res, 200, {
317
+ success: true,
318
+ tools,
319
+ count: tools.length
320
+ });
321
+ }
322
+
323
+ /**
324
+ * 处理会话列表接口
325
+ * @private
326
+ * @param {MiddlewareContext} ctx - 上下文
327
+ */
328
+ async _handleListSessions(ctx) {
329
+ const sessions = this.adapter.listSessions();
330
+
331
+ this._sendJSON(ctx.res, 200, {
332
+ success: true,
333
+ sessions,
334
+ count: sessions.length
335
+ });
336
+ }
337
+
338
+ /**
339
+ * 创建新会话
340
+ * @param {Object} [metadata] - 会话元数据
341
+ * @returns {string} 会话 ID
342
+ */
343
+ createSession(metadata = {}) {
344
+ return this.adapter.createSession(metadata);
345
+ }
346
+
347
+ /**
348
+ * 销毁会话
349
+ * @param {string} sessionId - 会话 ID
350
+ * @returns {boolean} 是否成功
351
+ */
352
+ destroySession(sessionId) {
353
+ return this.adapter.destroySession(sessionId);
354
+ }
355
+
356
+ /**
357
+ * 批量执行多个工具调用
358
+ * @param {Array<{tool_name: string, parameters?: Object}>} calls - 调用列表
359
+ * @returns {Promise<Array<Object>>} 结果数组
360
+ */
361
+ async batchExecute(calls) {
362
+ const results = await Promise.allSettled(
363
+ calls.map(call =>
364
+ this.adapter.sendRequest(call.tool_name, call.parameters || {})
365
+ )
366
+ );
367
+
368
+ return results.map((result, index) => ({
369
+ index,
370
+ tool_name: calls[index].tool_name,
371
+ status: result.status,
372
+ value: result.status === 'fulfilled' ? result.value : null,
373
+ reason: result.status === 'rejected' ? result.reason.message : null
374
+ }));
375
+ }
376
+
377
+ /**
378
+ * 获取请求日志
379
+ * @param {Object} [options] - 过滤选项
380
+ * @param {number} [options.limit=100] - 返回条数
381
+ * @returns {Array<Object>} 日志条目
382
+ */
383
+ getRequestLog(options = {}) {
384
+ const limit = options.limit || 100;
385
+ return this.requestLog.slice(-limit);
386
+ }
387
+
388
+ /**
389
+ * 路由请求到对应处理器
390
+ * @private
391
+ * @param {MiddlewareContext} ctx - 上下文
392
+ */
393
+ async _routeRequest(ctx) {
394
+ const { method, url } = ctx.req;
395
+ const pathname = url.split('?')[0];
396
+
397
+ const routes = {
398
+ 'POST /api/openclaw/chat': () => this._handleChat(ctx),
399
+ 'POST /api/openclaw/tools/call': () => this._handleToolCall(ctx),
400
+ 'GET /api/openclaw/tools': () => this._handleListTools(ctx),
401
+ 'GET /api/openclaw/sessions': () => this._handleListSessions(ctx)
402
+ };
403
+
404
+ const handler = routes[`${method} ${pathname}`];
405
+
406
+ if (handler) {
407
+ await handler();
408
+ } else {
409
+ this._sendError(ctx.res, 404, `Not Found: ${method} ${pathname}`);
410
+ }
411
+ }
412
+
413
+ /**
414
+ * 执行中间件链
415
+ * @private
416
+ * @param {MiddlewareContext} ctx - 上下文
417
+ */
418
+ async _executeMiddlewares(ctx) {
419
+ let index = 0;
420
+
421
+ const next = async () => {
422
+ if (index < this.middlewares.length) {
423
+ const middleware = this.middlewares[index++];
424
+ await middleware(ctx, next);
425
+ }
426
+ };
427
+
428
+ await next();
429
+ }
430
+
431
+ /**
432
+ * 解析请求体
433
+ * @private
434
+ * @param {IncomingMessage} req - 请求对象
435
+ * @returns {Promise<Object>} 解析后的对象
436
+ */
437
+ async _parseBody(req) {
438
+ if (req.method !== 'POST' && req.method !== 'PUT' && req.method !== 'PATCH') {
439
+ return {};
440
+ }
441
+
442
+ return new Promise((resolve, reject) => {
443
+ let data = '';
444
+
445
+ req.on('data', chunk => {
446
+ data += chunk.toString();
447
+ });
448
+
449
+ req.on('end', () => {
450
+ try {
451
+ resolve(data ? JSON.parse(data) : {});
452
+ } catch (error) {
453
+ reject(new Error(`Invalid JSON: ${error.message}`));
454
+ }
455
+ });
456
+
457
+ req.on('error', reject);
458
+ });
459
+ }
460
+
461
+ /**
462
+ * 发送 JSON 响应
463
+ * @private
464
+ * @param {ServerResponse} res - 响应对象
465
+ * @param {number} statusCode - HTTP 状态码
466
+ * @param {Object} data - 响应数据
467
+ */
468
+ _sendJSON(res, statusCode, data) {
469
+ res.writeHead(statusCode, {
470
+ 'Content-Type': 'application/json',
471
+ 'Access-Control-Allow-Origin': '*'
472
+ });
473
+ res.end(JSON.stringify(data));
474
+ }
475
+
476
+ /**
477
+ * 发送错误响应
478
+ * @private
479
+ * @param {ServerResponse} res - 响应对象
480
+ * @param {number} statusCode - HTTP 状态码
481
+ * @param {string} message - 错误消息
482
+ */
483
+ _sendError(res, statusCode, message) {
484
+ this._sendJSON(res, statusCode, {
485
+ success: false,
486
+ error: message,
487
+ timestamp: Date.now()
488
+ });
489
+ }
490
+
491
+ /**
492
+ * 设置 SSE 响应头
493
+ * @private
494
+ * @param {ServerResponse} res - 响应对象
495
+ */
496
+ _setSSEHeaders(res) {
497
+ res.writeHead(200, {
498
+ 'Content-Type': 'text/event-stream',
499
+ 'Cache-Control': 'no-cache',
500
+ 'Connection': 'keep-alive',
501
+ 'Access-Control-Allow-Origin': '*'
502
+ });
503
+ }
504
+
505
+ /**
506
+ * 记录请求日志
507
+ * @private
508
+ * @param {MiddlewareContext} ctx - 上下文
509
+ * @param {number} duration - 请求耗时
510
+ */
511
+ _logRequest(ctx, duration) {
512
+ this.requestLog.push({
513
+ method: ctx.req.method,
514
+ url: ctx.req.url,
515
+ statusCode: ctx.res.statusCode,
516
+ duration,
517
+ timestamp: Date.now(),
518
+ clientIp: ctx.req.socket.remoteAddress
519
+ });
520
+
521
+ // 限制日志大小
522
+ if (this.requestLog.length > 10000) {
523
+ this.requestLog = this.requestLog.slice(-5000);
524
+ }
525
+ }
526
+ }
527
+
528
+ /**
529
+ * 创建 API Bridge 实例的工厂函数
530
+ * @param {Object} options - 配置选项
531
+ * @returns {OpenClawAPIBridge} API Bridge 实例
532
+ */
533
+ export function createAPIBridge(options = {}) {
534
+ return new OpenClawAPIBridge(options);
535
+ }