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,408 @@
1
+ /**
2
+ * PDD API Server
3
+ * 基于Node.js内置http模块的RESTful API服务器
4
+ * 提供远程调用PDD能力的接口
5
+ */
6
+
7
+ import http from 'http';
8
+ import { URL } from 'url';
9
+ import { apiRoutes } from './api-routes.js';
10
+
11
+ // 引入chalk用于彩色输出
12
+ let chalk;
13
+ try {
14
+ const chalkModule = await import('chalk');
15
+ chalk = chalkModule.default;
16
+ } catch {
17
+ chalk = {
18
+ cyan: (s) => s,
19
+ green: (s) => s,
20
+ yellow: (s) => s,
21
+ red: (s) => s,
22
+ blue: (s) => s,
23
+ magenta: (s) => s
24
+ };
25
+ }
26
+
27
+ /**
28
+ * 创建HTTP响应的辅助函数
29
+ */
30
+ function createResponse(res, statusCode, data, headers = {}) {
31
+ const body = JSON.stringify(data);
32
+
33
+ res.writeHead(statusCode, {
34
+ 'Content-Type': 'application/json; charset=utf-8',
35
+ 'Content-Length': Buffer.byteLength(body),
36
+ 'Access-Control-Allow-Origin': '*',
37
+ 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
38
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
39
+ ...headers
40
+ });
41
+
42
+ res.end(body);
43
+ }
44
+
45
+ /**
46
+ * 解析请求体
47
+ * @param {http.IncomingMessage} req - HTTP请求对象
48
+ * @returns {Promise<Object>} 解析后的请求体
49
+ */
50
+ function parseRequestBody(req) {
51
+ return new Promise((resolve, reject) => {
52
+ let body = '';
53
+
54
+ req.on('data', chunk => {
55
+ body += chunk.toString();
56
+ // 防止超大请求体(限制为10MB)
57
+ if (body.length > 10 * 1024 * 1024) {
58
+ reject(new Error('Request body too large'));
59
+ req.destroy();
60
+ }
61
+ });
62
+
63
+ req.on('end', () => {
64
+ try {
65
+ if (body) {
66
+ resolve(JSON.parse(body));
67
+ } else {
68
+ resolve({});
69
+ }
70
+ } catch (error) {
71
+ reject(new Error('Invalid JSON in request body'));
72
+ }
73
+ });
74
+
75
+ req.on('error', reject);
76
+ });
77
+ }
78
+
79
+ /**
80
+ * CORS预检请求处理
81
+ * @param {http.ServerResponse} res - HTTP响应对象
82
+ */
83
+ function handleCorsPreflight(req, res) {
84
+ res.writeHead(204, {
85
+ 'Access-Control-Allow-Origin': '*',
86
+ 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
87
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
88
+ 'Access-Control-Max-Age': '86400'
89
+ });
90
+ res.end();
91
+ }
92
+
93
+ /**
94
+ * 请求日志中间件
95
+ * @param {http.IncomingMessage} req - HTTP请求对象
96
+ */
97
+ function logRequest(req, method, pathname) {
98
+ const timestamp = new Date().toISOString();
99
+ const clientIp = req.socket.remoteAddress;
100
+
101
+ console.log(
102
+ `${chalk.gray(timestamp)} ` +
103
+ `${method === 'GET' ? chalk.green(method) : method === 'POST' ? chalk.blue(method) : chalk.yellow(method)} ` +
104
+ `${chalk.cyan(pathname)} ` +
105
+ `${chalk.gray(`from ${clientIp}`)}`
106
+ );
107
+ }
108
+
109
+ /**
110
+ * 简单的速率限制器
111
+ */
112
+ class RateLimiter {
113
+ constructor(maxRequests = 100, windowMs = 60000) {
114
+ this.maxRequests = maxRequests;
115
+ this.windowMs = windowMs;
116
+ this.requests = new Map(); // IP -> [{timestamp}]
117
+ }
118
+
119
+ /**
120
+ * 检查是否允许请求
121
+ * @param {string} ip - 客户端IP
122
+ * @returns {boolean} 是否允许
123
+ */
124
+ isAllowed(ip) {
125
+ const now = Date.now();
126
+ const windowStart = now - this.windowMs;
127
+
128
+ // 获取该IP的请求记录,并清理过期记录
129
+ let requests = this.requests.get(ip) || [];
130
+ requests = requests.filter(r => r.timestamp > windowStart);
131
+
132
+ if (requests.length >= this.maxRequests) {
133
+ return false; // 超过限制
134
+ }
135
+
136
+ // 记录本次请求
137
+ requests.push({ timestamp: now });
138
+ this.requests.set(ip, requests);
139
+
140
+ return true;
141
+ }
142
+
143
+ /**
144
+ * 清理所有记录(定期调用)
145
+ */
146
+ cleanup() {
147
+ const now = Date.now();
148
+ const windowStart = now - this.windowMs;
149
+
150
+ for (const [ip, requests] of this.requests.entries()) {
151
+ const validRequests = requests.filter(r => r.timestamp > windowStart);
152
+ if (validRequests.length === 0) {
153
+ this.requests.delete(ip);
154
+ } else {
155
+ this.requests.set(ip, validRequests);
156
+ }
157
+ }
158
+ }
159
+ }
160
+
161
+ /**
162
+ * 启动API服务器
163
+ * @param {Object} options - 服务器配置选项
164
+ * @param {number} options.port - 监听端口
165
+ * @param {string} options.host - 绑定地址
166
+ * @param {boolean} options.cors - 是否启用CORS
167
+ */
168
+ export async function startApiServer(options = {}) {
169
+ const {
170
+ port = 3000,
171
+ host = 'localhost',
172
+ cors = true,
173
+ rateLimit = { enabled: true, maxRequests: 100, windowMs: 60000 }
174
+ } = options;
175
+
176
+ // 初始化速率限制器
177
+ const rateLimiter = rateLimit.enabled
178
+ ? new RateLimiter(rateLimit.maxRequests, rateLimit.windowMs)
179
+ : null;
180
+
181
+ // 定期清理速率限制记录
182
+ if (rateLimiter) {
183
+ setInterval(() => rateLimiter.cleanup(), 60000);
184
+ }
185
+
186
+ // 创建HTTP服务器
187
+ const server = http.createServer(async (req, res) => {
188
+ try {
189
+ // 解析URL
190
+ const parsedUrl = new URL(req.url, `http://${req.host}`);
191
+ const pathname = decodedURIComponent(parsedUrl.pathname);
192
+ const method = req.method.toUpperCase();
193
+
194
+ // 记录请求日志
195
+ logRequest(req, method, pathname);
196
+
197
+ // CORS预检请求
198
+ if (cors && method === 'OPTIONS') {
199
+ handleCorsPreflight(req, res);
200
+ return;
201
+ }
202
+
203
+ // 速率检查
204
+ if (rateLimiter) {
205
+ const clientIp = req.socket.remoteAddress;
206
+ if (!rateLimiter.isAllowed(clientIp)) {
207
+ createResponse(res, 429, {
208
+ error: 'Too Many Requests',
209
+ message: '请求过于频繁,请稍后再试',
210
+ retryAfter: Math.ceil(rateLimit.windowMs / 1000)
211
+ }, { 'Retry-After': Math.ceil(rateLimit.windowMs / 1000) });
212
+ return;
213
+ }
214
+ }
215
+
216
+ // 查找匹配的路由
217
+ const routeHandler = findRoute(method, pathname);
218
+
219
+ if (routeHandler) {
220
+ // POST/PUT请求需要解析请求体
221
+ let body = {};
222
+ if (['POST', 'PUT', 'PATCH'].includes(method)) {
223
+ try {
224
+ body = await parseRequestBody(req);
225
+ } catch (error) {
226
+ createResponse(res, 400, {
227
+ error: 'Bad Request',
228
+ message: error.message
229
+ });
230
+ return;
231
+ }
232
+ }
233
+
234
+ // 执行路由处理器
235
+ try {
236
+ const result = await routeHandler({
237
+ method,
238
+ pathname,
239
+ query: Object.fromEntries(parsedUrl.searchParams),
240
+ body,
241
+ headers: req.headers,
242
+ params: extractRouteParams(routeHandler.route, pathname)
243
+ });
244
+
245
+ createResponse(res, 200, {
246
+ success: true,
247
+ data: result,
248
+ timestamp: new Date().toISOString()
249
+ });
250
+
251
+ } catch (error) {
252
+ console.error(chalk.red(`路由执行错误: ${error.message}`));
253
+ createResponse(res, 500, {
254
+ error: 'Internal Server Error',
255
+ message: process.env.NODE_ENV === 'development'
256
+ ? error.message
257
+ : '服务器内部错误'
258
+ });
259
+ }
260
+
261
+ } else {
262
+ // 未找到路由
263
+ createResponse(res, 404, {
264
+ error: 'Not Found',
265
+ message: `未找到路由: ${method} ${pathname}`,
266
+ availableRoutes: getAvailableRoutes()
267
+ });
268
+ }
269
+
270
+ } catch (error) {
271
+ console.error(chalk.red(`服务器错误: ${error.message}`));
272
+
273
+ if (!res.headersSent) {
274
+ createResponse(res, 500, {
275
+ error: 'Internal Server Error',
276
+ message: '服务器发生未知错误'
277
+ });
278
+ }
279
+ }
280
+ });
281
+
282
+ // 错误处理
283
+ server.on('error', (error) => {
284
+ if (error.code === 'EADDRINUSE') {
285
+ console.error(chalk.red(`\n❌ 端口 ${port} 已被占用!\n`));
286
+ console.error(`请尝试:\n 1. 更换端口号: pdd api -p ${parseInt(port) + 1}`);
287
+ console.error(` 2. 关闭占用端口的进程\n`);
288
+ process.exit(1);
289
+ } else {
290
+ console.error(chalk.red(`\n❌ 服务器启动失败: ${error.message}\n`));
291
+ process.exit(1);
292
+ }
293
+ });
294
+
295
+ // 启动服务器
296
+ server.listen(port, host, () => {
297
+ console.log('\n' + '='.repeat(70));
298
+ console.log(chalk.green.bold('🚀 PDD API Server 已启动'));
299
+ console.log('='.repeat(70) + '\n');
300
+ console.log(`本地访问: ${chalk.cyan(`http://${host}:${port}`)}`);
301
+ console.log(`API文档: ${chalk.cyan(`http://${host}:${port}/api/v1/docs`)}`);
302
+ console.log(`服务状态: ${chalk.cyan(`http://${host}:${port}/api/v1/status`)}`);
303
+ console.log('');
304
+ console.log(chalk.yellow('可用API端点:'));
305
+ printAvailableRoutes(host, port);
306
+ console.log('\n' + '-'.repeat(70));
307
+ console.log(chalk.gray('按 Ctrl+C 停止服务器'));
308
+ console.log('-'.repeat(70) + '\n');
309
+ });
310
+
311
+ // 优雅关闭
312
+ process.on('SIGINT', () => {
313
+ console.log(chalk.yellow('\n\n🛑 正在关闭服务器...'));
314
+ server.close(() => {
315
+ console.log(chalk.green('✅ 服务器已关闭\n'));
316
+ process.exit(0);
317
+ });
318
+ });
319
+
320
+ return server;
321
+ }
322
+
323
+ /**
324
+ * 查找匹配的路由处理器
325
+ * @param {string} method - HTTP方法
326
+ * @param {string} pathname - 路径
327
+ * @returns {Function|null} 路由处理器函数
328
+ */
329
+ function findRoute(method, pathname) {
330
+ for (const route of apiRoutes) {
331
+ if (route.method !== method) continue;
332
+
333
+ // 将路由模式转换为正则表达式
334
+ const pattern = route.path
335
+ .replace(/:[^/]+/g, '[^/]+') // 将 :param 替换为匹配任意字符
336
+ .replace(/\//g, '\\/'); // 转义斜杠
337
+
338
+ const regex = new RegExp(`^${pattern}$`);
339
+
340
+ if (regex.test(pathname)) {
341
+ routeHandler = route.handler;
342
+ routeHandler.route = route.path; // 保存原始路由用于参数提取
343
+ return routeHandler;
344
+ }
345
+ }
346
+
347
+ return null;
348
+ }
349
+
350
+ /**
351
+ * 从路径中提取路由参数
352
+ * @param {string} routePattern - 路由模式
353
+ * @param {string} actualPath - 实际路径
354
+ * @returns {Object} 参数对象
355
+ */
356
+ function extractRouteParams(routePattern, actualPath) {
357
+ const params = {};
358
+
359
+ const patternParts = routePattern.split('/');
360
+ const pathParts = actualPath.split('/');
361
+
362
+ patternParts.forEach((part, index) => {
363
+ if (part.startsWith(':')) {
364
+ const paramName = part.slice(1);
365
+ params[paramName] = pathParts[index];
366
+ }
367
+ });
368
+
369
+ return params;
370
+ }
371
+
372
+ /**
373
+ * 获取可用路由列表
374
+ * @returns {Array} 路由列表
375
+ */
376
+ function getAvailableRoutes() {
377
+ return apiRoutes.map(route => ({
378
+ method: route.method,
379
+ path: route.path,
380
+ description: route.description
381
+ }));
382
+ }
383
+
384
+ /**
385
+ * 打印可用路由信息
386
+ * @param {string} host - 主机名
387
+ * @param {number} port - 端口
388
+ */
389
+ function printAvailableRoutes(host, port) {
390
+ const baseUrl = `http://${host}:${port}`;
391
+
392
+ for (const route of apiRoutes) {
393
+ const methodColor = {
394
+ 'GET': chalk.green,
395
+ 'POST': chalk.blue,
396
+ 'PUT': chalk.yellow,
397
+ 'DELETE': chalk.red
398
+ };
399
+
400
+ const colorFn = methodColor[route.method] || chalk.white;
401
+ console.log(
402
+ ` ${colorFn(route.method.padEnd(6))} ${baseUrl}${chalk.cyan(route.path)}` +
403
+ (route.description ? chalk.gray(` - ${route.description}`) : '')
404
+ );
405
+ }
406
+ }
407
+
408
+ export default { startApiServer };
@@ -0,0 +1,209 @@
1
+ // lib/cache/cache-config.js - PDD Cache Configuration
2
+ // 定义缓存策略、TTL、容量限制等配置
3
+
4
+ /**
5
+ * 缓存级别枚举
6
+ */
7
+ export const CacheLevel = {
8
+ SESSION: 1, // L1: 会话缓存(内存)
9
+ PROJECT: 2, // L2: 项目缓存(内存)
10
+ GLOBAL: 3 // L3: 全局缓存(磁盘)
11
+ };
12
+
13
+ /**
14
+ * 默认缓存配置
15
+ * 定义各级缓存的默认策略
16
+ */
17
+ export const DEFAULT_CACHE_CONFIG = {
18
+ // L1 会话缓存配置
19
+ session: {
20
+ enabled: true,
21
+ ttl: null, // null表示会话时长(不过期)
22
+ maxSize: 100, // 最大条目数
23
+ evictionPolicy: 'lru', // 淘汰策略:LRU
24
+ description: 'Session-level cache for current operation context'
25
+ },
26
+
27
+ // L2 项目缓存配置
28
+ project: {
29
+ enabled: true,
30
+ ttl: 30 * 60 * 1000, // 30分钟(毫秒)
31
+ maxSize: 500, // 最大条目数
32
+ evictionPolicy: 'lru', // 淘汰策略:LRU
33
+ description: 'Project-level cache shared within project scope'
34
+ },
35
+
36
+ // L3 全局缓存配置
37
+ global: {
38
+ enabled: true,
39
+ ttl: 24 * 60 * 60 * 1000, // 24小时(毫秒)
40
+ maxSize: 2000, // 最大条目数
41
+ evictionPolicy: 'lfu', // 淘汰策略:LFU(磁盘缓存适合LFU)
42
+ persistToDisk: true, // 是否持久化到磁盘
43
+ diskPath: '.pdd-cache', // 磁盘缓存目录
44
+ compression: false, // 是否压缩存储
45
+ description: 'Global cache persisted to disk across sessions'
46
+ }
47
+ };
48
+
49
+ /**
50
+ * 缓存键前缀定义
51
+ * 用于区分不同类型的数据
52
+ */
53
+ export const CACHE_KEY_PREFIXES = {
54
+ SPEC: 'spec:', // 规格文档缓存
55
+ FEATURE: 'feature:', // 功能点矩阵缓存
56
+ REVIEW: 'review:', // 代码审查结果缓存
57
+ STATUS: 'status:', // 项目状态缓存
58
+ ANALYSIS: 'analysis:', // 业务分析结果缓存
59
+ CODE: 'code:', // 生成的代码缓存
60
+ CONFIG: 'config:', // 配置信息缓存
61
+ TOKEN: 'token:' // Token/认证信息缓存
62
+ };
63
+
64
+ /**
65
+ * 特定数据类型的缓存策略覆盖
66
+ * 允许为不同数据类型定制缓存行为
67
+ */
68
+ export const CACHE_STRATEGIES = {
69
+ [CACHE_KEY_PREFIXES.SPEC]: {
70
+ level: CacheLevel.PROJECT,
71
+ ttl: 60 * 60 * 1000, // 1小时
72
+ priority: 'high'
73
+ },
74
+ [CACHE_KEY_PREFIXES.FEATURE]: {
75
+ level: CacheLevel.PROJECT,
76
+ ttl: 2 * 60 * 60 * 1000, // 2小时
77
+ priority: 'high'
78
+ },
79
+ [CACHE_KEY_PREFIXES.REVIEW]: {
80
+ level: CacheLevel.SESSION,
81
+ ttl: 15 * 60 * 1000, // 15分钟
82
+ priority: 'medium'
83
+ },
84
+ [CACHE_KEY_PREFIXES.STATUS]: {
85
+ level: CacheLevel.SESSION,
86
+ ttl: 5 * 60 * 1000, // 5分钟
87
+ priority: 'low'
88
+ },
89
+ [CACHE_KEY_PREFIXES.ANALYSIS]: {
90
+ level: CacheLevel.PROJECT,
91
+ ttl: 4 * 60 * 60 * 1000, // 4小时
92
+ priority: 'medium'
93
+ },
94
+ [CACHE_KEY_PREFIXES.CODE]: {
95
+ level: CacheLevel.SESSION,
96
+ ttl: 30 * 60 * 1000, // 30分钟
97
+ priority: 'high'
98
+ },
99
+ [CACHE_KEY_PREFIXES.CONFIG]: {
100
+ level: CacheLevel.GLOBAL,
101
+ ttl: 24 * 60 * 60 * 1000, // 24小时
102
+ priority: 'low'
103
+ },
104
+ [CACHE_KEY_PREFIXES.TOKEN]: {
105
+ level: CacheLevel.SESSION,
106
+ ttl: null, // 不过期(由Token本身控制)
107
+ priority: 'critical'
108
+ }
109
+ };
110
+
111
+ /**
112
+ * 缓存统计指标定义
113
+ */
114
+ export const CACHE_METRICS = {
115
+ HITS: 'hits',
116
+ MISSES: 'misses',
117
+ EVICTIONS: 'evictions',
118
+ SIZE: 'size',
119
+ MEMORY_USAGE: 'memoryUsage',
120
+ DISK_USAGE: 'diskUsage'
121
+ };
122
+
123
+ /**
124
+ * 创建自定义缓存配置
125
+ * @param {Object} overrides - 配置覆盖项
126
+ * @returns {Object} 合并后的配置
127
+ */
128
+ export function createCacheConfig(overrides = {}) {
129
+ return {
130
+ ...DEFAULT_CACHE_CONFIG,
131
+ ...overrides,
132
+ session: { ...DEFAULT_CACHE_CONFIG.session, ...(overrides.session || {}) },
133
+ project: { ...DEFAULT_CACHE_CONFIG.project, ...(overrides.project || {}) },
134
+ global: { ...DEFAULT_CACHE_CONFIG.global, ...(overrides.global || {}) }
135
+ };
136
+ }
137
+
138
+ /**
139
+ * 根据键名获取推荐的缓存策略
140
+ * @param {string} key - 缓存键
141
+ * @returns {Object} 推荐的缓存策略
142
+ */
143
+ export function getRecommendedStrategy(key) {
144
+ for (const [prefix, strategy] of Object.entries(CACHE_STRATEGIES)) {
145
+ if (key.startsWith(prefix)) {
146
+ return strategy;
147
+ }
148
+ }
149
+
150
+ // 默认策略:使用L2项目缓存
151
+ return {
152
+ level: CacheLevel.PROJECT,
153
+ ttl: DEFAULT_CACHE_CONFIG.project.ttl,
154
+ priority: 'medium'
155
+ };
156
+ }
157
+
158
+ /**
159
+ * 验证缓存配置的有效性
160
+ * @param {Object} config - 缓存配置
161
+ * @returns {Object} 验证结果 { valid: boolean, errors: string[] }
162
+ */
163
+ export function validateCacheConfig(config) {
164
+ const errors = [];
165
+
166
+ if (!config) {
167
+ errors.push('Config object is required');
168
+ return { valid: false, errors };
169
+ }
170
+
171
+ // 验证各级别的配置
172
+ ['session', 'project', 'global'].forEach(level => {
173
+ if (config[level]) {
174
+ const levelConfig = config[level];
175
+
176
+ if (levelConfig.ttl !== null && typeof levelConfig.ttl !== 'number') {
177
+ errors.push(`${level}.ttl must be a number or null`);
178
+ }
179
+
180
+ if (levelConfig.ttl !== null && levelConfig.ttl <= 0) {
181
+ errors.push(`${level}.ttl must be positive or null`);
182
+ }
183
+
184
+ if (typeof levelConfig.maxSize !== 'number' || levelConfig.maxSize <= 0) {
185
+ errors.push(`${level}.maxSize must be a positive number`);
186
+ }
187
+
188
+ if (!['lru', 'lfu', 'fifo'].includes(levelConfig.evictionPolicy)) {
189
+ errors.push(`${level}.evictionPolicy must be one of: lru, lfu, fifo`);
190
+ }
191
+ }
192
+ });
193
+
194
+ return {
195
+ valid: errors.length === 0,
196
+ errors
197
+ };
198
+ }
199
+
200
+ export default {
201
+ CacheLevel,
202
+ DEFAULT_CACHE_CONFIG,
203
+ CACHE_KEY_PREFIXES,
204
+ CACHE_STRATEGIES,
205
+ CACHE_METRICS,
206
+ createCacheConfig,
207
+ getRecommendedStrategy,
208
+ validateCacheConfig
209
+ };