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,1033 @@
1
+ /**
2
+ * PDD gRPC Proto Definitions
3
+ * Protocol Buffer 类型定义和编解码器(proto3 JSON mapping)
4
+ *
5
+ * 本模块实现轻量级的 Protocol Buffer 支持,无需外部依赖。
6
+ * 遵循 proto3 JSON Mapping 规范:
7
+ * https://protobuf.dev/programming-guides/proto3/#json
8
+ *
9
+ * 支持的字段类型:
10
+ * - 标量类型: string, int32, int64, bool, float, double, bytes
11
+ * - 复合类型: message, enum
12
+ * - 容器类型: repeated (数组), map (键值对)
13
+ *
14
+ * @module lib/grpc/proto-definitions
15
+ * @author PDD-Skills Team
16
+ * @version 3.0.0
17
+ */
18
+
19
+ // ==================== gRPC 状态码定义 ====================
20
+
21
+ /**
22
+ * gRPC 标准状态码
23
+ * 参考: https://grpc.github.io/grpc/core/md_doc_statuscodes.html
24
+ */
25
+ export const GrpcStatus = {
26
+ /** OK - 操作成功完成 */
27
+ OK: 0,
28
+ /** CANCELLED - 操作被调用方取消 */
29
+ CANCELLED: 1,
30
+ /** UNKNOWN - 未知错误 */
31
+ UNKNOWN: 2,
32
+ /** INVALID_ARGUMENT - 客户端指定了无效参数 */
33
+ INVALID_ARGUMENT: 3,
34
+ /** DEADLINE_EXCEEDED - 截止时间在操作完成前已过 */
35
+ DEADLINE_EXCEEDED: 4,
36
+ /** NOT_FOUND - 未找到请求的实体 */
37
+ NOT_FOUND: 5,
38
+ /** ALREADY_EXISTS - 尝试创建的实体已存在 */
39
+ ALREADY_EXISTS: 6,
40
+ /** PERMISSION_DENIED - 调用方没有权限执行指定操作 */
41
+ PERMISSION_DENIED: 7,
42
+ /** RESOURCE_EXHAUSTED - 资源已耗尽(如配额不足) */
43
+ RESOURCE_EXHAUSTED: 8,
44
+ /** FAILED_PRECONDITION - 系统未处于操作执行所需的状态 */
45
+ FAILED_PRECONDITION: 9,
46
+ /** ABORTED - 操作被中止 */
47
+ ABORTED: 10,
48
+ /** OUT_OF_RANGE - 操作尝试超出有效范围 */
49
+ OUT_OF_RANGE: 11,
50
+ /** UNIMPLEMENTED - 操作未实现或不支持/启用 */
51
+ UNIMPLEMENTED: 12,
52
+ /** INTERNAL - 内部错误 */
53
+ INTERNAL: 13,
54
+ /** UNAVAILABLE - 服务当前不可用 */
55
+ UNAVAILABLE: 14,
56
+ /** DATA_LOSS - 不可恢复的数据丢失或损坏 */
57
+ DATA_LOSS: 15,
58
+ /** UNAUTHENTICATED - 请求没有有效的身份验证凭据 */
59
+ UNAUTHENTICATED: 16
60
+ };
61
+
62
+ /**
63
+ * 状态码到描述信息的映射
64
+ */
65
+ export const StatusMessages = {
66
+ [GrpcStatus.OK]: 'OK',
67
+ [GrpcStatus.CANCELLED]: 'Cancelled',
68
+ [GrpcStatus.UNKNOWN]: 'Unknown error',
69
+ [GrpcStatus.INVALID_ARGUMENT]: 'Invalid argument',
70
+ [GrpcStatus.DEADLINE_EXCEEDED]: 'Deadline exceeded',
71
+ [GrpcStatus.NOT_FOUND]: 'Not found',
72
+ [GrpcStatus.ALREADY_EXISTS]: 'Already exists',
73
+ [GrpcStatus.PERMISSION_DENIED]: 'Permission denied',
74
+ [GrpcStatus.RESOURCE_EXHAUSTED]: 'Resource exhausted',
75
+ [GrpcStatus.FAILED_PRECONDITION]: 'Failed precondition',
76
+ [GrpcStatus.ABORTED]: 'Aborted',
77
+ [GrpcStatus.OUT_OF_RANGE]: 'Out of range',
78
+ [GrpcStatus.UNIMPLEMENTED]: 'Unimplemented',
79
+ [GrpcStatus.INTERNAL]: 'Internal error',
80
+ [GrpcStatus.UNAVAILABLE]: 'Unavailable',
81
+ [GrpcStatus.DATA_LOSS]: 'Data loss',
82
+ [GrpcStatus.UNAUTHENTICATED]: 'Unauthenticated'
83
+ };
84
+
85
+ // ==================== Proto3 默认值表 ====================
86
+
87
+ /**
88
+ * Proto3 各类型的默认值
89
+ * @private
90
+ */
91
+ const DEFAULT_VALUES = {
92
+ string: '',
93
+ int32: 0,
94
+ int64: '0', // JSON 中 int64 使用字符串表示
95
+ uint32: 0,
96
+ uint64: '0',
97
+ sint32: 0,
98
+ sint64: '0',
99
+ bool: false,
100
+ float: 0.0,
101
+ double: 0.0,
102
+ bytes: '', // Base64 编码字符串
103
+ enum: 0, // 枚举默认值为第一个值(数值 0)
104
+ message: null // 消息默认值为 null
105
+ };
106
+
107
+ // ==================== Schema 定义工具函数 ====================
108
+
109
+ /**
110
+ * 创建字段 Schema
111
+ * @param {string} type - 字段类型
112
+ * @param {number} fieldNumber - 字段编号(proto 规范要求)
113
+ * @param {Object} options - 可选配置
114
+ * @returns {Object} 字段 Schema 对象
115
+ * @private
116
+ */
117
+ function field(type, fieldNumber, options = {}) {
118
+ return {
119
+ type,
120
+ fieldNumber,
121
+ repeated: options.repeated || false,
122
+ mapKey: options.mapKey || null,
123
+ mapValue: options.mapValue || null,
124
+ required: options.required || false,
125
+ defaultValue: options.defaultValue !== undefined ? options.defaultValue : DEFAULT_VALUES[type]
126
+ };
127
+ }
128
+
129
+ /**
130
+ * 创建枚举 Schema
131
+ * @param {string} name - 枚举名称
132
+ * @param {Object} values - 枚举值映射 { NAME: number }
133
+ * @returns {Object} 枚举 Schema
134
+ * @private
135
+ */
136
+ function enumSchema(name, values) {
137
+ return {
138
+ kind: 'enum',
139
+ name,
140
+ values,
141
+ // 确保存在值为 0 的枚举项(proto3 要求)
142
+ defaultName: Object.entries(values).find(([, v]) => v === 0)?.[name] ||
143
+ Object.keys(values)[0]
144
+ };
145
+ }
146
+
147
+ /**
148
+ * 创建消息 Schema
149
+ * @param {string} name - 消息名称
150
+ * @param {Object} fields - 字段定义 { fieldName: fieldSchema }
151
+ * @returns {Object} 消息 Schema
152
+ * @private
153
+ */
154
+ function messageSchema(name, fields) {
155
+ return {
156
+ kind: 'message',
157
+ name,
158
+ fields
159
+ };
160
+ }
161
+
162
+ // ==================== PDD gRPC Service Schema 定义 ====================
163
+
164
+ /**
165
+ * SpecService 相关 Schema
166
+ */
167
+ export const SpecSchemas = {
168
+ /**
169
+ * GenerateSpec 请求消息
170
+ * 用于基于 PRD 生成开发规格文档
171
+ */
172
+ SpecRequest: messageSchema('SpecRequest', {
173
+ prdPath: field('string', 1),
174
+ outputDir: field('string', 2),
175
+ template: field('string', 3),
176
+ featureId: field('string', 4),
177
+ options: field('message', 5, { mapValue: 'string' })
178
+ }),
179
+
180
+ /**
181
+ * GetSpec 请求消息
182
+ * 获取已生成的规格文档
183
+ */
184
+ GetSpecRequest: messageSchema('GetSpecRequest', {
185
+ specId: field('string', 1),
186
+ specPath: field('string', 2)
187
+ }),
188
+
189
+ /**
190
+ * ListSpecs 请求消息
191
+ * 列出所有规格文档
192
+ */
193
+ ListSpecsRequest: messageSchema('ListSpecsRequest', {
194
+ pageToken: field('string', 1),
195
+ pageSize: field('int32', 2),
196
+ filter: field('message', 3)
197
+ }),
198
+
199
+ /**
200
+ * Spec 响应消息(通用)
201
+ */
202
+ SpecResponse: messageSchema('SpecResponse', {
203
+ success: field('bool', 1),
204
+ specId: field('string', 2),
205
+ specPath: field('string', 3),
206
+ content: field('string', 4),
207
+ featuresCount: field('int32', 5),
208
+ generatedAt: field('string', 6), // RFC3339 格式时间戳
209
+ metadata: field('message', 7, { mapValue: 'string' })
210
+ }),
211
+
212
+ /**
213
+ * ListSpecs 响应消息
214
+ */
215
+ ListSpecsResponse: messageSchema('ListSpecsResponse', {
216
+ specs: field('message', 1, { repeated: true }),
217
+ nextPageToken: field('string', 2),
218
+ totalSize: field('int32', 3)
219
+ }),
220
+
221
+ /**
222
+ * 过滤条件消息
223
+ */
224
+ SpecFilter: messageSchema('SpecFilter', {
225
+ status: field('string', 1),
226
+ featureId: field('string', 2),
227
+ dateFrom: field('string', 3),
228
+ dateTo: field('string', 4)
229
+ })
230
+ };
231
+
232
+ /**
233
+ * CodeService 相关 Schema
234
+ */
235
+ export const CodeSchemas = {
236
+ /**
237
+ * GenerateCode 请求消息
238
+ */
239
+ CodeRequest: messageSchema('CodeRequest', {
240
+ specPath: field('string', 1),
241
+ outputDir: field('string', 2),
242
+ feature: field('string', 3), // 可选:只生成特定功能
243
+ dryRun: field('bool', 4), // 预览模式
244
+ overwrite: field('bool', 5), // 是否覆盖已有文件
245
+ language: field('string', 6), // 目标语言
246
+ framework: field('string', 7) // 目标框架
247
+ }),
248
+
249
+ /**
250
+ * Code 响应消息
251
+ */
252
+ CodeResponse: messageSchema('CodeResponse', {
253
+ success: field('bool', 1),
254
+ outputDir: field('string', 2),
255
+ generatedFiles: field('message', 3, { repeated: true }),
256
+ featuresProcessed: field('int32', 4),
257
+ dryRun: field('bool', 5),
258
+ generatedAt: field('string', 6),
259
+ errors: field('message', 7, { repeated: true }),
260
+ warnings: field('message', 8, { repeated: true })
261
+ }),
262
+
263
+ /**
264
+ * 生成的文件信息
265
+ */
266
+ GeneratedFile: messageSchema('GeneratedFile', {
267
+ path: field('string', 1),
268
+ size: field('int64', 2),
269
+ language: field('string', 3),
270
+ lines: field('int32', 4)
271
+ }),
272
+
273
+ /**
274
+ * 错误信息
275
+ */
276
+ ErrorInfo: messageSchema('ErrorInfo', {
277
+ code: field('string', 1),
278
+ message: field('string', 2),
279
+ file: field('string', 3),
280
+ line: field('int32', 4)
281
+ })
282
+ };
283
+
284
+ /**
285
+ * VerifyService 相关 Schema
286
+ */
287
+ export const VerifySchemas = {
288
+ /**
289
+ * VerifyFeature 请求消息
290
+ */
291
+ VerifyRequest: messageSchema('VerifyRequest', {
292
+ specPath: field('string', 1),
293
+ codePath: field('string', 2),
294
+ verbose: field('bool', 3),
295
+ dimensions: field('string', 4, { repeated: true }) // 验证维度列表
296
+ }),
297
+
298
+ /**
299
+ * Verify 响应消息
300
+ */
301
+ VerifyResponse: messageSchema('VerifyResponse', {
302
+ success: field('bool', 1),
303
+ passed: field('bool', 2),
304
+ score: field('float', 3), // 总体评分 0-100
305
+ verifiedAt: field('string', 4),
306
+ results: field('message', 5, { repeated: true }),
307
+ summary: field('message', 6)
308
+ }),
309
+
310
+ /**
311
+ * 单个维度的验证结果
312
+ */
313
+ DimensionResult: messageSchema('DimensionResult', {
314
+ dimension: field('string', 1),
315
+ passed: field('bool', 2),
316
+ score: field('float', 3),
317
+ details: field('string', 4),
318
+ issues: field('message', 5, { repeated: true })
319
+ }),
320
+
321
+ /**
322
+ * 验证摘要
323
+ */
324
+ VerifySummary: messageSchema('VerifySummary', {
325
+ totalDimensions: field('int32', 1),
326
+ passedDimensions: field('int32', 2),
327
+ totalIssues: field('int32', 3),
328
+ criticalIssues: field('int32', 4),
329
+ passRate: field('float', 5)
330
+ })
331
+ };
332
+
333
+ /**
334
+ * ReportService 相关 Schema
335
+ */
336
+ export const ReportSchemas = {
337
+ /**
338
+ * GenerateReport 请求消息
339
+ */
340
+ ReportRequest: messageSchema('ReportRequest', {
341
+ type: field('string', 1), // 输出格式: md, json, html, pdf
342
+ outputPath: field('string', 2),
343
+ includeStats: field('bool', 3),
344
+ includeCharts: field('bool', 4),
345
+ projectDir: field('string', 5)
346
+ }),
347
+
348
+ /**
349
+ * Report 响应消息
350
+ */
351
+ ReportResponse: messageSchema('ReportResponse', {
352
+ success: field('bool', 1),
353
+ reportPath: field('string', 2),
354
+ format: field('string', 3),
355
+ generatedAt: field('string', 4),
356
+ preview: field('message', 5),
357
+ stats: field('message', 6)
358
+ }),
359
+
360
+ /**
361
+ * 报告预览摘要
362
+ */
363
+ ReportPreview: messageSchema('ReportPreview', {
364
+ totalFiles: field('int32', 1),
365
+ skillsCount: field('int32', 2),
366
+ specsCount: field('int32', 3),
367
+ testsCount: field('int32', 4),
368
+ codeLines: field('int64', 5)
369
+ }),
370
+
371
+ /**
372
+ * 项目统计信息
373
+ */
374
+ ProjectStats: messageSchema('ProjectStats', {
375
+ name: field('string', 1),
376
+ version: field('string', 2),
377
+ fileTypes: field('message', 3, { mapValue: 'int32' }),
378
+ quickCounts: field('message', 4, { mapValue: 'int32' })
379
+ })
380
+ };
381
+
382
+ /**
383
+ * SkillService 相关 Schema
384
+ */
385
+ export const SkillSchemas = {
386
+ /**
387
+ * ListSkills 请求消息
388
+ */
389
+ ListSkillsRequest: messageSchema('ListSkillsRequest', {
390
+ category: field('string', 1), // 可选过滤分类
391
+ pageToken: field('string', 2),
392
+ pageSize: field('int32', 3)
393
+ }),
394
+
395
+ /**
396
+ * GetSkillInfo 请求消息
397
+ */
398
+ GetSkillInfoRequest: messageSchema('GetSkillInfoRequest', {
399
+ category: field('string', 1),
400
+ name: field('string', 2)
401
+ }),
402
+
403
+ /**
404
+ * ListSkills 响应消息
405
+ */
406
+ ListSkillsResponse: messageSchema('ListSkillsResponse', {
407
+ skills: field('message', 1, { repeated: true }),
408
+ nextPageToken: field('string', 2),
409
+ totalSize: field('int32', 3)
410
+ }),
411
+
412
+ /**
413
+ * Skill 信息响应
414
+ */
415
+ SkillInfoResponse: messageSchema('SkillInfoResponse', {
416
+ name: field('string', 1),
417
+ category: field('string', 2),
418
+ title: field('string', 3),
419
+ description: field('string', 4),
420
+ path: field('string', 5),
421
+ triggers: field('string', 6, { repeated: true }),
422
+ contentLength: field('int32', 7),
423
+ lastModified: field('string', 8)
424
+ }),
425
+
426
+ /**
427
+ * Skill 条目(用于列表)
428
+ */
429
+ SkillEntry: messageSchema('SkillEntry', {
430
+ name: field('string', 1),
431
+ category: field('string', 2),
432
+ path: field('string', 3)
433
+ })
434
+ };
435
+
436
+ /**
437
+ * Health Check Service Schema(gRPC 标准健康检查协议)
438
+ */
439
+ export const HealthSchemas = {
440
+ /**
441
+ * HealthCheck 请求
442
+ */
443
+ HealthCheckRequest: messageSchema('HealthCheckRequest', {
444
+ service: field('string', 1) // 要检查的服务名
445
+ }),
446
+
447
+ /**
448
+ * HealthCheck 响应
449
+ */
450
+ HealthCheckResponse: messageSchema('HealthCheckResponse', {
451
+ status: field('enum', 1) // ServingStatus 枚举值
452
+ }),
453
+
454
+ /**
455
+ * ServingStatus 枚举
456
+ */
457
+ ServingStatus: enumSchema('ServingStatus', {
458
+ UNKNOWN: 0,
459
+ SERVING: 1,
460
+ NOT_SERVING: 2,
461
+ SERVICE_UNKNOWN: 3 // 仅用于 Watch 的响应
462
+ })
463
+ };
464
+
465
+ /**
466
+ * 通用错误响应 Schema
467
+ */
468
+ export const CommonSchemas = {
469
+ /**
470
+ * Google RPC Status 消息(标准错误响应格式)
471
+ */
472
+ GoogleRpcStatus: messageSchema('GoogleRpcStatus', {
473
+ code: field('int32', 1),
474
+ message: field('string', 2),
475
+ details: field('message', 3, { repeated: true })
476
+ }),
477
+
478
+ /**
479
+ * Any 类型包装器(用于 details 字段)
480
+ */
481
+ Any: messageSchema('Any', {
482
+ typeUrl: field('string', 1),
483
+ value: field('string', 2) // Base64 编码
484
+ }),
485
+
486
+ /**
487
+ * 空消息(用于无参数 RPC)
488
+ */
489
+ Empty: messageSchema('Empty', {})
490
+ };
491
+
492
+ // ==================== 所有 Schema 注册表 ====================
493
+
494
+ /**
495
+ * 全局 Schema 注册表
496
+ * 将消息名称映射到其 Schema 定义
497
+ */
498
+ export const SchemaRegistry = {
499
+ ...SpecSchemas,
500
+ ...CodeSchemas,
501
+ ...VerifySchemas,
502
+ ...ReportSchemas,
503
+ ...SkillSchemas,
504
+ ...HealthSchemas,
505
+ ...CommonSchemas
506
+ };
507
+
508
+ // ==================== 编解码器核心实现 ====================
509
+
510
+ /**
511
+ * 将 JavaScript 对象编码为 proto3 JSON 格式
512
+ *
513
+ * 编码规则(遵循 proto3 JSON Mapping):
514
+ * - null/undefined 值不输出(使用默认值)
515
+ * - int64 类型输出为字符串
516
+ * - enum 输出为名称字符串或数字
517
+ * - bytes 输出为 base64 字符串
518
+ * - 忽略未知字段
519
+ *
520
+ * @param {Object} data - 要编码的数据对象
521
+ * @param {Object} schema - 消息 Schema 定义
522
+ * @returns {Object} 编码后的 JSON 兼容对象
523
+ * @example
524
+ * encode({ prdPath: './prd.md' }, SpecSchemas.SpecRequest)
525
+ * // => { prdPath: './prd.md' }
526
+ */
527
+ export function encode(data, schema) {
528
+ if (!schema || schema.kind !== 'message') {
529
+ throw new Error(`Invalid schema: expected message schema, got ${schema?.kind}`);
530
+ }
531
+
532
+ if (!data || typeof data !== 'object') {
533
+ return {};
534
+ }
535
+
536
+ const result = {};
537
+ const { fields } = schema;
538
+
539
+ for (const [fieldName, fieldDef] of Object.entries(fields)) {
540
+ const value = data[fieldName];
541
+
542
+ // 跳过 undefined 和 null(proto3 默认行为)
543
+ if (value === undefined || value === null) {
544
+ continue;
545
+ }
546
+
547
+ // 处理各类型
548
+ if (fieldDef.repeated) {
549
+ // repeated 字段
550
+ if (Array.isArray(value) && value.length > 0) {
551
+ result[fieldName] = value.map(item => _encodeFieldValue(item, fieldDef));
552
+ }
553
+ // 空数组不输出
554
+ } else if (fieldDef.mapValue !== null && !fieldDef.repeated) {
555
+ // map 字段
556
+ if (value && typeof value === 'object') {
557
+ result[fieldName] = {};
558
+ for (const [k, v] of Object.entries(value)) {
559
+ result[fieldName][k] = _encodeFieldValue(v, {
560
+ type: fieldDef.mapValue
561
+ });
562
+ }
563
+ }
564
+ } else {
565
+ // 标量或消息字段
566
+ const encoded = _encodeFieldValue(value, fieldDef);
567
+ // 只有非默认值才输出(可选优化)
568
+ result[fieldName] = encoded;
569
+ }
570
+ }
571
+
572
+ return result;
573
+ }
574
+
575
+ /**
576
+ * 编码单个字段值
577
+ * @private
578
+ */
579
+ function _encodeFieldValue(value, fieldDef) {
580
+ switch (fieldDef.type) {
581
+ case 'int64':
582
+ case 'uint64':
583
+ case 'sint64':
584
+ // int64 在 JSON 中必须表示为字符串
585
+ return String(value);
586
+
587
+ case 'bytes':
588
+ // bytes 在 JSON 中表示为 base64 字符串
589
+ if (typeof value === 'string') {
590
+ return value; // 假设已经是 base64
591
+ }
592
+ return Buffer.from(value).toString('base64');
593
+
594
+ case 'bool':
595
+ return Boolean(value);
596
+
597
+ case 'float':
598
+ case 'double':
599
+ return Number(value);
600
+
601
+ case 'message':
602
+ // 嵌套消息需要递归编码
603
+ if (value === null || value === undefined) {
604
+ return null;
605
+ }
606
+ // 查找嵌套消息的 schema
607
+ const nestedSchema = SchemaRegistry[value.__schema] || findSchemaByContext(fieldDef);
608
+ if (nestedSchema) {
609
+ return encode(value, nestedSchema);
610
+ }
611
+ // 无法确定 schema 时直接返回
612
+ return value;
613
+
614
+ case 'enum':
615
+ // enum 可以是数字或字符串名称
616
+ return value;
617
+
618
+ default:
619
+ // string, int32, uint32, sint32 等
620
+ return value;
621
+ }
622
+ }
623
+
624
+ /**
625
+ * 从 proto3 JSON 格式解码为 JavaScript 对象
626
+ *
627
+ * 解码规则:
628
+ * - 缺失字段填充默认值
629
+ * - int64 字符串保持为字符串
630
+ * - 未知字段保留(可选)
631
+ *
632
+ * @param {Object|string} json - JSON 对象或 JSON 字符串
633
+ * @param {Object} schema - 消息 Schema 定义
634
+ * @returns {Object} 解码后的 JavaScript 对象
635
+ * @example
636
+ * decode('{ "prdPath": "./prd.md" }', SpecSchemas.SpecRequest)
637
+ * // => { prdPath: './prd.md', outputDir: '', template: '', ... }
638
+ */
639
+ export function decode(json, schema) {
640
+ if (!schema || schema.kind !== 'message') {
641
+ throw new Error(`Invalid schema: expected message schema, got ${schema?.kind}`);
642
+ }
643
+
644
+ // 如果传入的是字符串,先解析为对象
645
+ let data = json;
646
+ if (typeof json === 'string') {
647
+ try {
648
+ data = JSON.parse(json);
649
+ } catch (e) {
650
+ throw new Error(`Invalid JSON: ${e.message}`);
651
+ }
652
+ }
653
+
654
+ // 确保 data 是对象
655
+ if (!data || typeof data !== 'object') {
656
+ data = {};
657
+ }
658
+
659
+ const result = {};
660
+ const { fields } = schema;
661
+
662
+ for (const [fieldName, fieldDef] of Object.entries(fields)) {
663
+ const value = data[fieldName];
664
+
665
+ if (fieldDef.repeated) {
666
+ // repeated 字段:缺失时为空数组
667
+ if (Array.isArray(value)) {
668
+ result[fieldName] = value.map(item =>
669
+ _decodeFieldValue(item, fieldDef)
670
+ );
671
+ } else {
672
+ result[fieldName] = [];
673
+ }
674
+ } else if (fieldDef.mapValue !== null && !fieldDef.repeated) {
675
+ // map 字段:缺失时为空对象
676
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
677
+ const mapResult = {};
678
+ for (const [k, v] of Object.entries(value)) {
679
+ mapResult[k] = _decodeFieldValue(v, {
680
+ type: fieldDef.mapValue
681
+ });
682
+ }
683
+ result[fieldName] = mapResult;
684
+ } else {
685
+ result[fieldName] = {};
686
+ }
687
+ } else {
688
+ // 标量或消息字段:缺失时使用默认值
689
+ if (value === undefined || value === null) {
690
+ result[fieldName] = _getDefaultValue(fieldDef.type);
691
+ } else {
692
+ result[fieldName] = _decodeFieldValue(value, fieldDef);
693
+ }
694
+ }
695
+ }
696
+
697
+ return result;
698
+ }
699
+
700
+ /**
701
+ * 解码单个字段值
702
+ * @private
703
+ */
704
+ function _decodeFieldValue(value, fieldDef) {
705
+ if (value === null || value === undefined) {
706
+ return _getDefaultValue(fieldDef.type);
707
+ }
708
+
709
+ switch (fieldDef.type) {
710
+ case 'int32':
711
+ case 'uint32':
712
+ case 'sint32':
713
+ return parseInt(value, 10) || 0;
714
+
715
+ case 'int64':
716
+ case 'uint64':
717
+ case 'sint64':
718
+ // 保持为字符串以避免精度丢失
719
+ return String(value);
720
+
721
+ case 'float':
722
+ case 'double':
723
+ return parseFloat(value) || 0.0;
724
+
725
+ case 'bool':
726
+ // 接受 "true"/"false" 字符串和布尔值
727
+ if (typeof value === 'string') {
728
+ return value.toLowerCase() === 'true';
729
+ }
730
+ return Boolean(value);
731
+
732
+ case 'bytes':
733
+ // 返回 base64 字符串(实际解码由使用者决定)
734
+ return String(value);
735
+
736
+ case 'message':
737
+ // 嵌套消息递归解码
738
+ if (typeof value === 'object' && value !== null) {
739
+ const nestedSchema = findSchemaByContext(fieldDef);
740
+ if (nestedSchema) {
741
+ return decode(value, nestedSchema);
742
+ }
743
+ }
744
+ return value;
745
+
746
+ case 'enum':
747
+ // enum 可以是数字或字符串
748
+ if (typeof value === 'string') {
749
+ const num = parseInt(value, 10);
750
+ if (!isNaN(num)) return num;
751
+ return value; // 保持为字符串名称
752
+ }
753
+ return parseInt(value, 10) || 0;
754
+
755
+ default:
756
+ // string 和其他类型
757
+ return String(value);
758
+ }
759
+ }
760
+
761
+ /**
762
+ * 获取类型的默认值
763
+ * @private
764
+ */
765
+ function _getDefaultValue(type) {
766
+ if (type in DEFAULT_VALUES) {
767
+ return DEFAULT_VALUES[type];
768
+ }
769
+ return null; // 未知类型返回 null
770
+ }
771
+
772
+ /**
773
+ * 根据上下文查找嵌套消息的 Schema
774
+ * 这是一个简化的实现,实际场景中可能需要更复杂的查找逻辑
775
+ * @private
776
+ */
777
+ function findSchemaByContext(fieldDef) {
778
+ // 这里可以通过字段命名约定或其他方式推断 schema
779
+ // 当前简化实现:返回 null 让调用者处理
780
+ return null;
781
+ }
782
+
783
+ // ==================== 验证器 ====================
784
+
785
+ /**
786
+ * 验证消息是否符合 Schema 定义
787
+ *
788
+ * @param {Object} data - 要验证的数据
789
+ * @param {Object} schema - 消息 Schema 定义
790
+ * @returns {{ valid: boolean, errors: Array<string> }} 验证结果
791
+ * @example
792
+ * validate({ prdPath: './prd.md' }, SpecSchemas.SpecRequest)
793
+ * // => { valid: true, errors: [] }
794
+ */
795
+ export function validate(data, schema) {
796
+ const errors = [];
797
+
798
+ if (!schema || schema.kind !== 'message') {
799
+ return { valid: false, errors: ['Invalid schema definition'] };
800
+ }
801
+
802
+ if (!data || typeof data !== 'object') {
803
+ return { valid: false, errors: ['Data must be an object'] };
804
+ }
805
+
806
+ _validateMessage(data, schema.fields, '', errors);
807
+
808
+ return {
809
+ valid: errors.length === 0,
810
+ errors
811
+ };
812
+ }
813
+
814
+ /**
815
+ * 递归验证消息字段
816
+ * @private
817
+ */
818
+ function _validateMessage(data, fields, prefix, errors) {
819
+ for (const [fieldName, fieldDef] of Object.entries(fields)) {
820
+ const value = data[fieldName];
821
+ const fullPath = prefix ? `${prefix}.${fieldName}` : fieldName;
822
+
823
+ // 检查必填字段
824
+ if (fieldDef.required && (value === undefined || value === null)) {
825
+ errors.push(`${fullPath}: Required field is missing`);
826
+ continue;
827
+ }
828
+
829
+ // 跳过可选且缺失的字段
830
+ if (value === undefined || value === null) {
831
+ if (fieldDef.repeated) {
832
+ // repeated 字段的 null 应该视为空数组,但这里报错
833
+ errors.push(`${fullPath}: Expected array, got null`);
834
+ }
835
+ continue;
836
+ }
837
+
838
+ // 类型检查
839
+ if (fieldDef.repeated) {
840
+ if (!Array.isArray(value)) {
841
+ errors.push(`${fullPath}: Expected array, got ${typeof value}`);
842
+ continue;
843
+ }
844
+ // 验证数组元素
845
+ value.forEach((item, index) => {
846
+ _validateFieldItem(item, fieldDef, `${fullPath}[${index}]`, errors);
847
+ });
848
+ } else if (fieldDef.mapValue !== null) {
849
+ if (typeof value !== 'object' || Array.isArray(value)) {
850
+ errors.push(`${fullPath}: Expected object, got ${typeof value}`);
851
+ continue;
852
+ }
853
+ // 验证 map 值
854
+ for (const [k, v] of Object.entries(value)) {
855
+ _validateFieldItem(v, { type: fieldDef.mapValue }, `${fullPath}.${k}`, errors);
856
+ }
857
+ } else {
858
+ _validateFieldItem(value, fieldDef, fullPath, errors);
859
+ }
860
+ }
861
+ }
862
+
863
+ /**
864
+ * 验证单个字段值的类型
865
+ * @private
866
+ */
867
+ function _validateFieldItem(value, fieldDef, path, errors) {
868
+ const { type } = fieldDef;
869
+
870
+ switch (type) {
871
+ case 'string':
872
+ if (typeof value !== 'string') {
873
+ errors.push(`${path}: Expected string, got ${typeof value}`);
874
+ }
875
+ break;
876
+
877
+ case 'int32':
878
+ case 'uint32':
879
+ case 'sint32':
880
+ case 'int64':
881
+ case 'uint64':
882
+ case 'sint64':
883
+ if (typeof value !== 'number' && typeof value !== 'string') {
884
+ errors.push(`${path}: Expected integer, got ${typeof value}`);
885
+ } else if (typeof value === 'number' && !Number.isInteger(value)) {
886
+ errors.push(`${path}: Expected integer, got float`);
887
+ }
888
+ break;
889
+
890
+ case 'bool':
891
+ if (typeof value !== 'boolean') {
892
+ errors.push(`${path}: Expected boolean, got ${typeof value}`);
893
+ }
894
+ break;
895
+
896
+ case 'float':
897
+ case 'double':
898
+ if (typeof value !== 'number') {
899
+ errors.push(`${path}: Expected number, got ${typeof value}`);
900
+ }
901
+ break;
902
+
903
+ case 'message':
904
+ if (value !== null && typeof value !== 'object') {
905
+ errors.push(`${path}: Expected object, got ${typeof value}`);
906
+ }
907
+ // 递归验证嵌套消息(如果有 schema)
908
+ const nestedSchema = SchemaRegistry[type] || findSchemaForType(type);
909
+ if (nestedSchema && value !== null) {
910
+ _validateMessage(value, nestedSchema.fields, path, errors);
911
+ }
912
+ break;
913
+
914
+ case 'enum':
915
+ // enum 可以是数字或字符串
916
+ if (typeof value !== 'number' && typeof value !== 'string') {
917
+ errors.push(`${path}: Expected enum (number or string), got ${typeof value}`);
918
+ }
919
+ break;
920
+
921
+ default:
922
+ // 未知类型跳过验证
923
+ break;
924
+ }
925
+ }
926
+
927
+ /**
928
+ * 根据类型名查找 Schema
929
+ * @private
930
+ */
931
+ function findSchemaForType(typeName) {
932
+ // 尝试从注册表中查找
933
+ // 这里的 typeName 可能是引用其他消息类型的名称
934
+ return SchemaRegistry[typeName] || null;
935
+ }
936
+
937
+ // ==================== 导出汇总 ====================
938
+
939
+ /**
940
+ * 所有可用的 gRPC Service 及其方法定义
941
+ * 用于服务注册和反射
942
+ */
943
+ export const ServiceDefinitions = {
944
+ SpecService: {
945
+ name: 'pdd.SpecService',
946
+ methods: {
947
+ GenerateSpec: {
948
+ requestType: 'SpecRequest',
949
+ responseType: 'SpecResponse',
950
+ requestStream: false,
951
+ responseStream: false
952
+ },
953
+ GetSpec: {
954
+ requestType: 'GetSpecRequest',
955
+ responseType: 'SpecResponse',
956
+ requestStream: false,
957
+ responseStream: false
958
+ },
959
+ ListSpecs: {
960
+ requestType: 'ListSpecsRequest',
961
+ responseType: 'ListSpecsResponse',
962
+ requestStream: false,
963
+ responseStream: false
964
+ }
965
+ }
966
+ },
967
+
968
+ CodeService: {
969
+ name: 'pdd.CodeService',
970
+ methods: {
971
+ GenerateCode: {
972
+ requestType: 'CodeRequest',
973
+ responseType: 'CodeResponse',
974
+ requestStream: false,
975
+ responseStream: false
976
+ }
977
+ }
978
+ },
979
+
980
+ VerifyService: {
981
+ name: 'pdd.VerifyService',
982
+ methods: {
983
+ VerifyFeature: {
984
+ requestType: 'VerifyRequest',
985
+ responseType: 'VerifyResponse',
986
+ requestStream: false,
987
+ responseStream: false
988
+ }
989
+ }
990
+ },
991
+
992
+ ReportService: {
993
+ name: 'pdd.ReportService',
994
+ methods: {
995
+ GenerateReport: {
996
+ requestType: 'ReportRequest',
997
+ responseType: 'ReportResponse',
998
+ requestStream: false,
999
+ responseStream: false
1000
+ }
1001
+ }
1002
+ },
1003
+
1004
+ SkillService: {
1005
+ name: 'pdd.SkillService',
1006
+ methods: {
1007
+ ListSkills: {
1008
+ requestType: 'ListSkillsRequest',
1009
+ responseType: 'ListSkillsResponse',
1010
+ requestStream: false,
1011
+ responseStream: false
1012
+ },
1013
+ GetSkillInfo: {
1014
+ requestType: 'GetSkillInfoRequest',
1015
+ responseType: 'SkillInfoResponse',
1016
+ requestStream: false,
1017
+ responseStream: false
1018
+ }
1019
+ }
1020
+ },
1021
+
1022
+ HealthService: {
1023
+ name: 'grpc.health.v1.Health',
1024
+ methods: {
1025
+ Check: {
1026
+ requestType: 'HealthCheckRequest',
1027
+ responseType: 'HealthCheckResponse',
1028
+ requestStream: false,
1029
+ responseStream: false
1030
+ }
1031
+ }
1032
+ }
1033
+ };