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,567 @@
1
+ /**
2
+ * @module openclaw/cli-integration
3
+ * @description OpenClaw CLI 集成模块 - 提供 pdd openclaw 命令行接口
4
+ * @version 1.0.0
5
+ * @author PDD-Skills Team
6
+ */
7
+
8
+ import { readFile, writeFile, unlink, access } from 'fs/promises';
9
+ import { join, dirname } from 'path';
10
+ import { createReadStream } from 'fs';
11
+ import { OpenClawAdapter, createAdapter } from './openclaw-adapter.js';
12
+ import { fileURLToPath } from 'url';
13
+
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = dirname(__filename);
16
+
17
+ /** PID 文件名 */
18
+ const PID_FILE_NAME = 'openclaw.pid';
19
+
20
+ /** 配置文件名 */
21
+ const CONFIG_FILE_NAME = 'openclaw-config.json';
22
+
23
+ /**
24
+ * OpenClaw CLI 类 - 管理命令行交互和服务控制
25
+ * @class OpenClawCLI
26
+ */
27
+ export class OpenClawCLI {
28
+ /**
29
+ * 创建 CLI 实例
30
+ * @param {Object} options - 配置选项
31
+ * @param {string} [options.baseDir] - 项目根目录
32
+ * @param {string} [options.configDir] - 配置文件目录
33
+ */
34
+ constructor(options = {}) {
35
+ this.baseDir = options.baseDir || process.cwd();
36
+ this.configDir = options.configDir || join(this.baseDir, '.pdd');
37
+
38
+ /** @type {OpenClawAdapter|null} 适配器实例 */
39
+ this.adapter = null;
40
+
41
+ /** @type {Object|null} 当前配置 */
42
+ this.config = null;
43
+ }
44
+
45
+ /**
46
+ * 执行 CLI 命令
47
+ * @param {string} command - 命令名称
48
+ * @param {Object} [options={}] - 命令选项
49
+ * @returns {Promise<*>} 命令执行结果
50
+ */
51
+ async execute(command, options = {}) {
52
+ switch (command) {
53
+ case 'start':
54
+ return this.start(options);
55
+ case 'stop':
56
+ return this.stop();
57
+ case 'status':
58
+ return this.status();
59
+ case 'list-tools':
60
+ return this.listTools();
61
+ case 'test':
62
+ return this.testTool(options);
63
+ case 'logs':
64
+ return this.showLogs(options);
65
+ case 'init':
66
+ return this.initConfig();
67
+ default:
68
+ throw new Error(`Unknown command: ${command}`);
69
+ }
70
+ }
71
+
72
+ /**
73
+ * 启动 OpenClaw 服务
74
+ * @param {Object} options - 启动选项
75
+ * @param {number} [options.port=8080] - 监听端口
76
+ * @param {string} [options.token] - 认证令牌
77
+ * @param {boolean} [options.daemon=false] - 是否以守护进程模式运行
78
+ * @returns {Promise<Object>} 启动结果
79
+ */
80
+ async start(options = {}) {
81
+ // 加载配置
82
+ await this._loadConfig();
83
+
84
+ // 首次运行时显示配置向导
85
+ if (!this.config) {
86
+ console.log('\n📋 首次运行检测到,启动配置向导...\n');
87
+ await this.initConfig();
88
+ await this._loadConfig();
89
+ }
90
+
91
+ const port = options.port || this.config?.port || 8080;
92
+ const token = options.token || this.config?.token;
93
+
94
+ // 检查是否已在运行
95
+ if (await this._isRunning()) {
96
+ const pid = await this._readPidFile();
97
+ return {
98
+ success: false,
99
+ message: `OpenClaw 服务已在运行 (PID: ${pid})`,
100
+ pid
101
+ };
102
+ }
103
+
104
+ console.log(`\n🚀 启动 OpenClaw 服务...`);
105
+ console.log(` 端口: ${port}`);
106
+ console.log(` 端点: http://localhost:${port}\n`);
107
+
108
+ // 创建适配器实例
109
+ this.adapter = createAdapter({
110
+ endpoint: `http://localhost:${port}`,
111
+ token,
112
+ heartbeatInterval: 30000
113
+ });
114
+
115
+ // 绑定事件监听
116
+ this._bindAdapterEvents();
117
+
118
+ try {
119
+ // 连接到服务
120
+ await this.adapter.connect();
121
+
122
+ // 写入 PID 文件
123
+ await this._writePidFile(process.pid);
124
+
125
+ // 如果是守护进程模式
126
+ if (options.daemon) {
127
+ console.log(`✅ OpenClaw 服务已以守护进程模式启动`);
128
+ console.log(` PID: ${process.pid}`);
129
+ } else {
130
+ console.log(`✅ OpenClaw 服务已启动`);
131
+ console.log(` 输入 'pdd openclaw stop' 停止服务`);
132
+ console.log(` 输入 'pdd openclaw status' 查看状态\n`);
133
+
134
+ // 保持进程运行
135
+ await this._keepAlive();
136
+ }
137
+
138
+ return {
139
+ success: true,
140
+ port,
141
+ pid: process.pid,
142
+ endpoint: `http://localhost:${port}`
143
+ };
144
+ } catch (error) {
145
+ return {
146
+ success: false,
147
+ message: `启动失败: ${error.message}`,
148
+ error: error.toString()
149
+ };
150
+ }
151
+ }
152
+
153
+ /**
154
+ * 停止 OpenClaw 服务
155
+ * @returns {Promise<Object>} 停止结果
156
+ */
157
+ async stop() {
158
+ console.log('\n🛑 正在停止 OpenClaw 服务...\n');
159
+
160
+ if (!await this._isRunning()) {
161
+ return {
162
+ success: false,
163
+ message: 'OpenClaw 服务未在运行'
164
+ };
165
+ }
166
+
167
+ try {
168
+ // 断开适配器连接
169
+ if (this.adapter) {
170
+ await this.adapter.disconnect();
171
+ this.adapter = null;
172
+ }
173
+
174
+ // 删除 PID 文件
175
+ await this._removePidFile();
176
+
177
+ console.log('✅ OpenClaw 服务已停止\n');
178
+ return {
179
+ success: true,
180
+ message: 'Service stopped successfully'
181
+ };
182
+ } catch (error) {
183
+ return {
184
+ success: false,
185
+ message: `停止失败: ${error.message}`,
186
+ error: error.toString()
187
+ };
188
+ }
189
+ }
190
+
191
+ /**
192
+ * 查看连接状态
193
+ * @returns {Promise<Object>} 状态信息
194
+ */
195
+ async status() {
196
+ const isRunning = await this._isRunning();
197
+ const pid = isRunning ? await this._readPidFile() : null;
198
+
199
+ let adapterStatus = null;
200
+ if (this.adapter) {
201
+ adapterStatus = this.adapter.getStatusDetails();
202
+ }
203
+
204
+ const status = {
205
+ running: isRunning,
206
+ pid,
207
+ adapter: adapterStatus,
208
+ config: this.config ? {
209
+ port: this.config.port,
210
+ hasToken: !!this.config.token
211
+ } : null
212
+ };
213
+
214
+ // 格式化输出
215
+ console.log('\n📊 OpenClaw 服务状态\n');
216
+ console.log(` 状态: ${isRunning ? '✅ 运行中' : '⏹️ 未运行'}`);
217
+ if (pid) console.log(` PID: ${pid}`);
218
+ if (adapterStatus) {
219
+ console.log(` 连接状态: ${adapterStatus.status}`);
220
+ console.log(` 活跃会话: ${adapterStatus.activeSessions}`);
221
+ console.log(` 已注册能力: ${adapterStatus.capabilitiesCount}`);
222
+ console.log(` 待处理请求: ${adapterStatus.pendingRequests}`);
223
+ if (adapterStatus.uptime > 0) {
224
+ const uptime = this._formatUptime(adapterStatus.uptime);
225
+ console.log(` 运行时间: ${uptime}`);
226
+ }
227
+ }
228
+ console.log('');
229
+
230
+ return status;
231
+ }
232
+
233
+ /**
234
+ * 列出已暴露的工具
235
+ * @returns {Promise<Array<Object>>} 工具列表
236
+ */
237
+ async listTools() {
238
+ if (!this.adapter) {
239
+ // 即使没有活跃连接也返回注册的工具列表
240
+ this.adapter = createAdapter();
241
+ }
242
+
243
+ const tools = this.adapter.registry.toOpenClawTools();
244
+
245
+ console.log('\n🔧 已暴露的 OpenClaw 工具\n');
246
+ console.log(` 总计: ${tools.length} 个工具\n`);
247
+
248
+ for (const tool of tools) {
249
+ const func = tool.function;
250
+ console.log(` 📦 ${func.name}`);
251
+ console.log(` 描述: ${func.description}`);
252
+ if (func.parameters?.properties) {
253
+ const params = Object.keys(func.parameters.properties);
254
+ if (params.length > 0) {
255
+ console.log(` 参数: ${params.join(', ')}`);
256
+ }
257
+ }
258
+ console.log('');
259
+ }
260
+
261
+ return tools;
262
+ }
263
+
264
+ /**
265
+ * 测试工具调用
266
+ * @param {Object} options - 测试选项
267
+ * @param {string} [options.toolName] - 要测试的工具名称
268
+ * @returns {Promise<Object>} 测试结果
269
+ */
270
+ async testTool(options = {}) {
271
+ if (!this.adapter) {
272
+ this.adapter = createAdapter();
273
+ await this.adapter.connect().catch(() => {});
274
+ }
275
+
276
+ const toolName = options.toolName || 'pdd_list_skills';
277
+
278
+ console.log(`\n🧪 测试工具调用: ${toolName}\n`);
279
+
280
+ try {
281
+ const startTime = Date.now();
282
+ const result = await this.adapter.sendRequest(toolName, {});
283
+ const duration = Date.now() - startTime;
284
+
285
+ console.log('✅ 工具调用成功');
286
+ console.log(` 耗时: ${duration}ms`);
287
+ console.log(` 结果:`);
288
+ console.log(` ${JSON.stringify(result, null, 2)}\n`);
289
+
290
+ return {
291
+ success: true,
292
+ tool: toolName,
293
+ duration,
294
+ result
295
+ };
296
+ } catch (error) {
297
+ console.log('❌ 工具调用失败');
298
+ console.log(` 错误: ${error.message}\n`);
299
+
300
+ return {
301
+ success: false,
302
+ tool: toolName,
303
+ error: error.message
304
+ };
305
+ }
306
+ }
307
+
308
+ /**
309
+ * 显示通信日志
310
+ * @param {Object} options - 日志选项
311
+ * @param {boolean} [options.tail=false] - 是否持续跟踪输出
312
+ * @param {number} [options.limit=50] - 显示条数
313
+ * @returns {Promise<Array<Object>>} 日志条目
314
+ */
315
+ async showLogs(options = {}) {
316
+ if (!this.adapter) {
317
+ console.log('\n⚠️ 没有活跃的服务实例,无法获取日志\n');
318
+ return [];
319
+ }
320
+
321
+ const limit = options.limit || 50;
322
+ const logs = this.adapter.getMessageLog({ limit });
323
+
324
+ console.log(`\n📋 OpenClaw 通信日志 (最近 ${logs.length} 条)\n`);
325
+
326
+ for (const entry of logs) {
327
+ const icon = entry.direction === 'outgoing' ? '➡️' :
328
+ entry.direction === 'incoming' ? '⬅️' : '🔵';
329
+ const time = new Date(entry.timestamp).toLocaleTimeString();
330
+ const msg = entry.message;
331
+
332
+ console.log(`${icon} [${time}] ${msg.type}`);
333
+ if (msg.payload?.tool) {
334
+ console.log(` Tool: ${msg.payload.tool}`);
335
+ }
336
+ if (msg.payload?.event) {
337
+ console.log(` Event: ${msg.payload.event}`);
338
+ }
339
+ console.log('');
340
+ }
341
+
342
+ // tail 模式:持续跟踪
343
+ if (options.tail) {
344
+ console.log('... 持续跟踪中 (Ctrl+C 退出) ...\n');
345
+ // 在实际实现中这里会有持续输出的逻辑
346
+ }
347
+
348
+ return logs;
349
+ }
350
+
351
+ /**
352
+ * 初始化配置(交互式向导)
353
+ * @returns {Promise<Object>} 生成的配置
354
+ */
355
+ async initConfig() {
356
+ console.log('\n🔧 OpenClaw 配置向导\n');
357
+ console.log('本向导将帮助你配置 OpenClaw 集成设置。\n');
358
+
359
+ // 使用默认配置或提示用户输入
360
+ const config = {
361
+ port: 8080,
362
+ token: this._generateToken(),
363
+ endpoint: 'http://localhost:8080',
364
+ heartbeatInterval: 30000,
365
+ maxReconnectDelay: 30000,
366
+ logLevel: 'info',
367
+ createdAt: new Date().toISOString()
368
+ };
369
+
370
+ console.log('配置项:');
371
+ console.log(` 端口 (port): ${config.port}`);
372
+ console.log(` 端点 (endpoint): ${config.endpoint}`);
373
+ console.log(` Token: ${config.token.substring(0, 8)}...`);
374
+ console.log(` 心跳间隔: ${config.heartbeatInterval}ms`);
375
+ console.log(` 日志级别: ${config.logLevel}\n`);
376
+
377
+ // 保存配置
378
+ await this._saveConfig(config);
379
+
380
+ console.log('✅ 配置已保存到:', join(this.configDir, CONFIG_FILE_NAME));
381
+ console.log(' 你可以随时使用 "pdd openclaw init" 重新配置\n');
382
+
383
+ return config;
384
+ }
385
+
386
+ /**
387
+ * 绑定适配器事件
388
+ * @private
389
+ */
390
+ _bindAdapterEvents() {
391
+ if (!this.adapter) return;
392
+
393
+ this.adapter.on('connected', () => {
394
+ console.log(' ✅ 已连接到 OpenClaw 服务');
395
+ });
396
+
397
+ this.adapter.on('disconnected', () => {
398
+ console.log(' ⚠️ 与 OpenClaw 服务的连接已断开');
399
+ });
400
+
401
+ this.adapter.on('reconnecting', ({ attempt, delay }) => {
402
+ console.log(` 🔄 正在重连... (第 ${attempt} 次, ${delay}ms 后)`);
403
+ });
404
+
405
+ this.adapter.on('error', (error) => {
406
+ console.error(` ❌ 错误: ${error.message}`);
407
+ });
408
+
409
+ this.adapter.on('message', (message) => {
410
+ if (message.type === 'event' && message.payload?.event === 'pong') {
411
+ // 心跳响应,不输出
412
+ }
413
+ });
414
+ }
415
+
416
+ /**
417
+ * 加载配置
418
+ * @private
419
+ * @returns {Promise<Object|null>} 配置对象
420
+ */
421
+ async _loadConfig() {
422
+ const configPath = join(this.configDir, CONFIG_FILE_NAME);
423
+
424
+ try {
425
+ await access(configPath);
426
+ const content = await readFile(configPath, 'utf-8');
427
+ this.config = JSON.parse(content);
428
+ return this.config;
429
+ } catch {
430
+ this.config = null;
431
+ return null;
432
+ }
433
+ }
434
+
435
+ /**
436
+ * 保存配置
437
+ * @private
438
+ * @param {Object} config - 配置对象
439
+ */
440
+ async _saveConfig(config) {
441
+ const configPath = join(this.configDir, CONFIG_FILE_NAME);
442
+ const content = JSON.stringify(config, null, 2);
443
+ await writeFile(configPath, content, 'utf-8');
444
+ this.config = config;
445
+ }
446
+
447
+ /**
448
+ * 检查服务是否正在运行
449
+ * @private
450
+ * @returns {Promise<boolean>}
451
+ */
452
+ async _isRunning() {
453
+ const pid = await this._readPidFile();
454
+ if (!pid) return false;
455
+
456
+ try {
457
+ // Windows 下检查进程是否存在
458
+ process.kill(pid, 0);
459
+ return true;
460
+ } catch {
461
+ // 进程不存在,清理 PID 文件
462
+ await this._removePidFile();
463
+ return false;
464
+ }
465
+ }
466
+
467
+ /**
468
+ * 读取 PID 文件
469
+ * @private
470
+ * @returns {Promise<number|null>} PID 或 null
471
+ */
472
+ async _readPidFile() {
473
+ const pidPath = join(this.configDir, PID_FILE_NAME);
474
+
475
+ try {
476
+ const content = await readFile(pidPath, 'utf-8');
477
+ return parseInt(content.trim(), 10);
478
+ } catch {
479
+ return null;
480
+ }
481
+ }
482
+
483
+ /**
484
+ * 写入 PID 文件
485
+ * @private
486
+ * @param {number} pid - 进程 ID
487
+ */
488
+ async _writePidFile(pid) {
489
+ const pidPath = join(this.configDir, PID_FILE_NAME);
490
+ await writeFile(pidPath, pid.toString(), 'utf-8');
491
+ }
492
+
493
+ /**
494
+ * 删除 PID 文件
495
+ * @private
496
+ */
497
+ async _removePidFile() {
498
+ const pidPath = join(this.configDir, PID_FILE_NAME);
499
+
500
+ try {
501
+ await unlink(pidPath);
502
+ } catch {
503
+ // 忽略文件不存在的错误
504
+ }
505
+ }
506
+
507
+ /**
508
+ * 保持进程活跃
509
+ * @private
510
+ * @returns {Promise<void>}
511
+ */
512
+ async _keepAlive() {
513
+ return new Promise((resolve) => {
514
+ // 监听退出信号
515
+ const cleanup = async () => {
516
+ console.log('\n\n🛑 正在优雅关闭...\n');
517
+ await this.stop();
518
+ resolve();
519
+ process.exit(0);
520
+ };
521
+
522
+ process.on('SIGINT', cleanup);
523
+ process.on('SIGTERM', cleanup);
524
+ });
525
+ }
526
+
527
+ /**
528
+ * 生成随机 Token
529
+ * @private
530
+ * @returns {string} 随机 token
531
+ */
532
+ _generateToken() {
533
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
534
+ let token = 'oc_';
535
+ for (let i = 0; i < 32; i++) {
536
+ token += chars.charAt(Math.floor(Math.random() * chars.length));
537
+ }
538
+ return token;
539
+ }
540
+
541
+ /**
542
+ * 格式化运行时间
543
+ * @private
544
+ * @param {number} ms - 毫秒数
545
+ * @returns {string} 格式化的时间字符串
546
+ */
547
+ _formatUptime(ms) {
548
+ const seconds = Math.floor(ms / 1000);
549
+ const minutes = Math.floor(seconds / 60);
550
+ const hours = Math.floor(minutes / 60);
551
+ const days = Math.floor(hours / 24);
552
+
553
+ if (days > 0) return `${days}天 ${hours % 24}小时 ${minutes % 60}分钟`;
554
+ if (hours > 0) return `${hours}小时 ${minutes % 60}分钟 ${seconds % 60}秒`;
555
+ if (minutes > 0) return `${minutes}分钟 ${seconds % 60}秒`;
556
+ return `${seconds}秒`;
557
+ }
558
+ }
559
+
560
+ /**
561
+ * 创建 CLI 实例的工厂函数
562
+ * @param {Object} options - 配置选项
563
+ * @returns {OpenClawCLI} CLI 实例
564
+ */
565
+ export function createCLI(options = {}) {
566
+ return new OpenClawCLI(options);
567
+ }