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,528 @@
1
+ /**
2
+ * PDD 代码生成模块
3
+ * 基于开发规格文档生成代码实现
4
+ */
5
+
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import { fileURLToPath } from 'url';
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+
13
+ // 引入chalk用于彩色输出
14
+ let chalk;
15
+ try {
16
+ const chalkModule = await import('chalk');
17
+ chalk = chalkModule.default;
18
+ } catch {
19
+ chalk = {
20
+ cyan: (s) => s,
21
+ green: (s) => s,
22
+ yellow: (s) => s,
23
+ red: (s) => s,
24
+ blue: (s) => s,
25
+ magenta: (s) => s
26
+ };
27
+ }
28
+
29
+ /**
30
+ * 解析规格文件,提取功能点信息
31
+ * @param {string} specPath - 规格文件路径
32
+ * @returns {Object} 解析后的规格数据
33
+ */
34
+ async function parseSpecFile(specPath) {
35
+ try {
36
+ if (!fs.existsSync(specPath)) {
37
+ throw new Error(`规格文件不存在: ${specPath}`);
38
+ }
39
+
40
+ const content = await fs.promises.readFile(specPath, 'utf-8');
41
+
42
+ // 简单的Markdown解析器 - 提取功能点信息
43
+ const specData = {
44
+ path: specPath,
45
+ features: [],
46
+ metadata: {}
47
+ };
48
+
49
+ // 提取元数据(标题、版本等)
50
+ const titleMatch = content.match(/^#\s+(.+)$/m);
51
+ if (titleMatch) {
52
+ specData.metadata.title = titleMatch[1];
53
+ }
54
+
55
+ const versionMatch = content.match(/版本[::]\s*(.+)/i);
56
+ if (versionMatch) {
57
+ specData.metadata.version = versionMatch[1].trim();
58
+ }
59
+
60
+ // 提取功能点(## 或 ### 标题)
61
+ const featureRegex = /^(#{2,3})\s+(.+?)(?:\s*\|(.+))?$/gm;
62
+ let match;
63
+
64
+ while ((match = featureRegex.exec(content)) !== null) {
65
+ const level = match[1].length;
66
+ const title = match[2].trim();
67
+ const tags = match[3] ? match[3].split('|').map(t => t.trim()) : [];
68
+
69
+ if (level === 2 || level === 3) {
70
+ specData.features.push({
71
+ level,
72
+ title,
73
+ tags,
74
+ content: extractFeatureContent(content, match.index)
75
+ });
76
+ }
77
+ }
78
+
79
+ console.log(chalk.cyan(`✓ 解析规格文件: ${path.basename(specPath)}`));
80
+ console.log(` 发现 ${specData.features.length} 个功能点\n`);
81
+
82
+ return specData;
83
+ } catch (error) {
84
+ console.error(chalk.red(`解析规格文件失败: ${error.message}`));
85
+ throw error;
86
+ }
87
+ }
88
+
89
+ /**
90
+ * 提取单个功能点的内容
91
+ * @param {string} content - 完整文档内容
92
+ * @param {number} startIndex - 功能点起始位置
93
+ * @returns {string} 功能点内容
94
+ */
95
+ function extractFeatureContent(content, startIndex) {
96
+ // 找到下一个同级或更高级标题的位置
97
+ const remainingContent = content.slice(startIndex);
98
+ const nextHeadingRegex = /\n^(#{1,2})\s+/m;
99
+ const nextMatch = nextHeadingRegex.exec(remainingContent);
100
+
101
+ if (nextMatch && nextMatch.index > 0) {
102
+ return remainingContent.slice(0, nextIndex).trim();
103
+ }
104
+
105
+ return remainingContent.trim();
106
+ }
107
+
108
+ /**
109
+ * 根据规格生成代码
110
+ * @param {Object} options - 命令行选项
111
+ */
112
+ export async function generateCode(options) {
113
+ try {
114
+ console.log(chalk.blue('📖 开始解析开发规格...\n'));
115
+
116
+ // 1. 解析规格文件
117
+ const specData = await parseSpecFile(options.spec);
118
+
119
+ // 2. 如果指定了特定功能点,过滤其他功能点
120
+ let targetFeatures = specData.features;
121
+ if (options.feature) {
122
+ targetFeatures = specData.features.filter(f =>
123
+ f.title.toLowerCase().includes(options.feature.toLowerCase())
124
+ );
125
+
126
+ if (targetFeatures.length === 0) {
127
+ console.log(chalk.yellow(`⚠️ 未找到匹配的功能点: ${options.feature}`));
128
+ console.log(`可用的功能点:\n${specData.features.map((f, i) => ` ${i + 1}. ${f.title}`).join('\n')}\n`);
129
+ return;
130
+ }
131
+
132
+ console.log(chalk.cyan(`🎯 目标功能点: ${options.feature}\n`));
133
+ }
134
+
135
+ // 3. 准备输出目录
136
+ const outputDir = path.resolve(options.output);
137
+ if (!fs.existsSync(outputDir)) {
138
+ await fs.promises.mkdir(outputDir, { recursive: true });
139
+ console.log(chalk.cyan(`📁 创建输出目录: ${outputDir}\n`));
140
+ }
141
+
142
+ // 4. Dry-run模式 - 仅显示将要执行的操作
143
+ if (options.dryRun) {
144
+ console.log(chalk.yellow('\n🔍 Dry-Run 模式 - 以下是将要生成的文件:\n'));
145
+
146
+ for (const feature of targetFeatures) {
147
+ console.log(chalk.magenta(`\n功能点: ${feature.title}`));
148
+ console.log(` 输出路径: ${path.join(outputDir, sanitizeFileName(feature.title))}`);
149
+
150
+ // 分析功能点内容,预测将生成的文件类型
151
+ const predictedFiles = predictGeneratedFiles(feature);
152
+ for (const file of predictedFiles) {
153
+ console.log(` 📄 ${file}`);
154
+ }
155
+ }
156
+
157
+ console.log(chalk.green('\n✅ Dry-Run 完成,未实际生成任何文件\n'));
158
+ return;
159
+ }
160
+
161
+ // 5. 实际代码生成
162
+ console.log(chalk.blue(`\n🔨 开始生成代码 (${targetFeatures.length} 个功能点)...\n`));
163
+
164
+ const generatedFiles = [];
165
+
166
+ for (const feature of targetFeatures) {
167
+ console.log(chalk.cyan(`\n▶ 处理功能点: ${feature.title}`));
168
+
169
+ const featureOutputDir = path.join(outputDir, sanitizeFileName(feature.title));
170
+
171
+ if (!fs.existsSync(featureOutputDir)) {
172
+ await fs.promises.mkdir(featureOutputDir, { recursive: true });
173
+ }
174
+
175
+ // 为每个功能点生成代码文件
176
+ const files = await generateFeatureCode(feature, featureOutputDir);
177
+ generatedFiles.push(...files);
178
+
179
+ console.log(chalk.green(` ✓ 生成 ${files.length} 个文件`));
180
+ }
181
+
182
+ // 6. 生成摘要报告
183
+ await generateGenerationReport(specData, targetFeatures, generatedFiles, outputDir);
184
+
185
+ console.log(chalk.green('\n' + '='.repeat(60)));
186
+ console.log(chalk.green('✅ 代码生成完成!'));
187
+ console.log(` 总计生成 ${generatedFiles.length} 个文件`);
188
+ console.log(` 输出目录: ${outputDir}`);
189
+ console.log(chalk.green('='.repeat(60) + '\n'));
190
+
191
+ } catch (error) {
192
+ console.error(chalk.red(`\n❌ 代码生成失败: ${error.message}\n`));
193
+ process.exit(1);
194
+ }
195
+ }
196
+
197
+ /**
198
+ * 预测将生成的文件列表
199
+ * @param {Object} feature - 功能点对象
200
+ * @returns {string[]} 预测的文件名列表
201
+ */
202
+ function predictGeneratedFiles(feature) {
203
+ const files = [];
204
+ const baseName = sanitizeFileName(feature.title);
205
+
206
+ // 根据标签和内容关键词预测文件类型
207
+ const contentLower = feature.content?.toLowerCase() || '';
208
+ const hasTests = /测试|test|验证|verify/i.test(contentLower);
209
+ hasApi = /api|接口|endpoint|route/i.test(contentLower);
210
+ hasModel = /模型|model|实体|entity|数据结构/i.test(contentLower);
211
+ hasService = /服务|service|业务逻辑/i.test(contentLower);
212
+
213
+ files.push(`${baseName}.js`); // 主文件
214
+
215
+ if (hasModel) files.push(`${baseName}.model.js`);
216
+ if (hasService) files.push(`${baseName}.service.js`);
217
+ if (hasApi) files.push(`${baseName}.route.js`);
218
+ if (hasTests) files.push(`${baseName}.test.js`);
219
+
220
+ files.push(`${baseName}.md`); // 文档
221
+
222
+ return files;
223
+ }
224
+
225
+ /**
226
+ * 为单个功能点生成代码
227
+ * @param {Object} feature - 功能点对象
228
+ * @param {string} outputDir - 输出目录
229
+ * @returns {string[]} 生成的文件列表
230
+ */
231
+ async function generateFeatureCode(feature, outputDir) {
232
+ const generatedFiles = [];
233
+ const baseName = sanitizeFileName(feature.title);
234
+
235
+ // 1. 生成主实现文件
236
+ const mainCode = generateMainImplementation(feature);
237
+ const mainFilePath = path.join(outputDir, `${baseName}.js`);
238
+ await fs.promises.writeFile(mainFilePath, mainCode, 'utf-8');
239
+ generatedFiles.push(mainFilePath);
240
+
241
+ // 2. 生成文档说明
242
+ const docContent = generateFeatureDocumentation(feature);
243
+ const docFilePath = path.join(outputDir, `${baseName}.md`);
244
+ await fs.promises.writeFile(docFilePath, docContent, 'utf-8');
245
+ generatedFiles.push(docFilePath);
246
+
247
+ // 3. 根据内容分析生成额外的辅助文件
248
+ const contentLower = feature.content?.toLowerCase() || '';
249
+
250
+ if (/测试|test|验收标准/i.test(contentLower)) {
251
+ const testCode = generateTestTemplate(feature);
252
+ const testFilePath = path.join(outputDir, `${baseName}.test.js`);
253
+ await fs.promises.writeFile(testFilePath, testCode, 'utf-8');
254
+ generatedFiles.push(testFilePath);
255
+ }
256
+
257
+ return generatedFiles;
258
+ }
259
+
260
+ /**
261
+ * 生成主实现代码模板
262
+ * @param {Object} feature - 功能点对象
263
+ * @returns {string} 生成的代码
264
+ */
265
+ function generateMainImplementation(feature) {
266
+ const timestamp = new Date().toISOString().split('T')[0];
267
+ const className = toClassName(feature.title);
268
+
269
+ return `/**
270
+ * ${feature.title}
271
+ *
272
+ * 自动生成于 ${timestamp}
273
+ * 基于 PDD 开发规格
274
+ *
275
+ * 功能描述:
276
+ * ${feature.content ? feature.content.slice(0, 200) + (feature.content.length > 200 ? '...' : '') : '待补充'}
277
+ */
278
+
279
+ ${feature.tags.includes('class') ? `export class ${className} {
280
+ constructor(options = {}) {
281
+ this.options = options;
282
+ this.initialize();
283
+ }
284
+
285
+ /**
286
+ * 初始化
287
+ */
288
+ initialize() {
289
+ // TODO: 实现初始化逻辑
290
+ }
291
+
292
+ /**
293
+ * 执行主要功能
294
+ */
295
+ async execute() {
296
+ // TODO: 实现 ${feature.title} 的核心逻辑
297
+ throw new Error('方法尚未实现');
298
+ }
299
+ }
300
+ ` : `/**
301
+ * ${feature.title} - 功能实现
302
+ */
303
+
304
+ export async function ${toFunctionName(feature.title)}(options = {}) {
305
+ // TODO: 实现 ${feature.title} 的核心逻辑
306
+
307
+ /**
308
+ * 实现步骤:
309
+ * 1. 解析输入参数
310
+ * 2. 验证参数有效性
311
+ * 3. 执行核心业务逻辑
312
+ * 4. 返回结果
313
+ */
314
+
315
+ console.log('${feature.title} - 开始执行');
316
+
317
+ return {
318
+ success: true,
319
+ message: '${feature.title} 执行完成',
320
+ data: null
321
+ };
322
+ }
323
+ `}
324
+ `;
325
+ }
326
+
327
+ /**
328
+ * 生成测试模板
329
+ * @param {Object} feature - 功能点对象
330
+ * @returns {string} 测试代码
331
+ */
332
+ function generateTestTemplate(feature) {
333
+ const funcName = toFunctionName(feature.title);
334
+ const className = toClassName(feature.title);
335
+
336
+ return `/**
337
+ * ${feature.title} - 单元测试
338
+ * 自动生成于 ${new Date().toISOString().split('T')[0]}
339
+ */
340
+
341
+ import { describe, it, expect, beforeEach } from 'vitest'; // 或使用你的测试框架
342
+ import { ${funcName}, ${className} } from './${toFunctionName(feature.title)}.js';
343
+
344
+ describe('${feature.title}', () => {
345
+
346
+ beforeEach(() => {
347
+ // 测试前准备工作
348
+ });
349
+
350
+ it('应该正确初始化', () => {
351
+ // TODO: 编写初始化测试
352
+ expect(true).toBe(true);
353
+ });
354
+
355
+ it('应该处理正常输入', async () => {
356
+ // TODO: 编写正常流程测试
357
+ const result = await ${funcName}({});
358
+ expect(result.success).toBe(true);
359
+ });
360
+
361
+ it('应该处理错误情况', async () => {
362
+ // TODO: 编写异常处理测试
363
+ // expect(async () => await ${funcName}(invalidOptions)).toThrow();
364
+ });
365
+
366
+ it('应该满足验收标准', () => {
367
+ // TODO: 根据规格中的验收标准编写测试用例
368
+ });
369
+ });
370
+ `;
371
+ }
372
+
373
+ /**
374
+ * 生成功能点文档
375
+ * @param {Object} feature - 功能点对象
376
+ * @returns {string} 文档内容
377
+ */
378
+ function generateFeatureDocumentation(feature) {
379
+ const timestamp = new Date().toISOString();
380
+
381
+ return `# ${feature.title}
382
+
383
+ > 自动生成于 ${timestamp} | 基于 PDD 开发规格
384
+
385
+ ## 概述
386
+
387
+ ${feature.content ? feature.content : '*待补充功能描述*'}
388
+
389
+ ## 标签
390
+
391
+ ${feature.tags.length > 0 ? feature.tags.map(tag => `- \`${tag}\``).join('\n') : '- 无'}
392
+
393
+ ## API 接口
394
+
395
+ \`\`\`javascript
396
+ // 使用示例
397
+ import { ${toFunctionName(feature.title)} } from './${toFunctionName(feature.title)}.js';
398
+
399
+ const result = await ${toFunctionName(feature.title)}({
400
+ // 参数选项
401
+ });
402
+
403
+ console.log(result);
404
+ \`\`\`
405
+
406
+ ## 参数说明
407
+
408
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
409
+ |------|------|------|--------|------|
410
+ | options | Object | 否 | {} | 配置选项 |
411
+
412
+ ## 返回值
413
+
414
+ \`\`\`javascript
415
+ {
416
+ success: boolean, // 是否成功
417
+ message: string, // 结果消息
418
+ data: any // 返回数据
419
+ }
420
+ \`\`\`
421
+
422
+ ## 验收标准
423
+
424
+ - [ ] 功能正常运行
425
+ - [ ] 错误处理完善
426
+ - [ ] 单元测试通过
427
+ - [ ] 代码质量符合规范
428
+
429
+ ## 待办事项
430
+
431
+ - [ ] 完成核心逻辑实现
432
+ - [ ] 补充单元测试
433
+ - [ ] 添加集成测试
434
+ - [ ] 性能优化
435
+
436
+ ---
437
+ *由 PDD-Skills 自动生成*
438
+ `;
439
+ }
440
+
441
+ /**
442
+ * 生成代码生成报告
443
+ * @param {Object} specData - 规格数据
444
+ * @param {Array} features - 处理的功能点
445
+ * @param {Array} files - 生成的文件列表
446
+ * @param {string} outputDir - 输出目录
447
+ */
448
+ async function generateGenerationReport(specData, features, files, outputDir) {
449
+ const reportPath = path.join(outputDir, 'GENERATION_REPORT.md');
450
+
451
+ const report = `# 代码生成报告
452
+
453
+ **生成时间:** ${new Date().toLocaleString()}
454
+ **规格文件:** ${specData.path}
455
+ **功能点数量:** ${features.length}
456
+ **生成文件数:** ${files.length}
457
+
458
+ ## 功能点列表
459
+
460
+ ${features.map((f, i) => `${i + 1}. **${f.title}** - ${f.tags.length > 0 ? f.tags.join(', ') : '无标签'}`).join('\n')}
461
+
462
+ ## 生成文件清单
463
+
464
+ \`\`\`
465
+ ${files.map(f => `📄 ${path.relative(outputDir, f)}`).join('\n')}
466
+ \`\`\`
467
+
468
+ ## 目录结构
469
+
470
+ \`\`\`
471
+ ${outputDir}/
472
+ ├── GENERATION_REPORT.md
473
+ ${features.map(f => `├── ${sanitizeFileName(f.title)}/`).join('')}
474
+ │ ├── ${sanitizeFileName(f.title)}.js
475
+ │ └── ${sanitizeFileName(f.title)}.md
476
+ \`\`\`
477
+
478
+ ---
479
+
480
+ *由 PDD-Skills CLI 工具自动生成*
481
+ `;
482
+
483
+ await fs.promises.writeFile(reportPath, report, 'utf-8');
484
+ console.log(chalk.cyan(`\n📊 生成报告: ${reportPath}`));
485
+ }
486
+
487
+ /**
488
+ * 将标题转换为合法的文件名
489
+ * @param {string} title - 功能点标题
490
+ * @returns {string} 文件名
491
+ */
492
+ function sanitizeFileName(title) {
493
+ return title
494
+ .toLowerCase()
495
+ .replace(/[^a-z0-9\u4e00-\u9fa5_-]/g, '-')
496
+ .replace(/-{2,}/g, '-')
497
+ .replace(/^-|-$/g, '');
498
+ }
499
+
500
+ /**
501
+ * 将标题转换为函数名(驼峰)
502
+ * @param {string} title - 标题
503
+ * @returns {string} 函数名
504
+ */
505
+ function toFunctionName(title) {
506
+ return title
507
+ .replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, ' ')
508
+ .trim()
509
+ .split(/\s+/)
510
+ .map((word, index) => index === 0 ? word.toLowerCase() : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
511
+ .join('');
512
+ }
513
+
514
+ /**
515
+ * 将标题转换为类名(PascalCase)
516
+ * @param {string} title - 标题
517
+ * @returns {string} 类名
518
+ */
519
+ function toClassName(title) {
520
+ return title
521
+ .replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, ' ')
522
+ .trim()
523
+ .split(/\s+/)
524
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
525
+ .join('');
526
+ }
527
+
528
+ export { generateCode, parseSpecFile };