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,252 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ 党政机关公文生成脚本
4
+ 符合GB/T 9704-2012《党政机关公文格式》国家标准
5
+ """
6
+
7
+ from docx import Document
8
+ from docx.shared import Pt, Cm, RGBColor
9
+ from docx.enum.text import WD_ALIGN_PARAGRAPH
10
+ from docx.oxml.ns import qn
11
+
12
+
13
+ def add_horizontal_line(doc, color='FF0000', size_pt=2):
14
+ """添加分隔线"""
15
+ p = doc.add_paragraph()
16
+ p.alignment = WD_ALIGN_PARAGRAPH.CENTER
17
+ p.paragraph_format.space_before = Pt(4)
18
+ p.paragraph_format.space_after = Pt(0)
19
+
20
+ run = p.add_run('_' * 100)
21
+ run.font.size = Pt(size_pt)
22
+ run.font.color.rgb = RGBColor(int(color[0:2], 16), int(color[2:4], 16), int(color[4:6], 16))
23
+ run.font.name = '宋体'
24
+ run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
25
+
26
+
27
+ def create_official_document(doc_type, content):
28
+ """
29
+ 创建符合GB/T 9704-2012标准的党政机关公文Word文档
30
+
31
+ 参数:
32
+ doc_type: 公文类型(通知/报告/请示/函/通报/纪要等)
33
+ content: 公文内容字典,包含以下字段:
34
+ - issuer: 发文机关
35
+ - doc_number: 发文字号
36
+ - title: 标题
37
+ - recipient: 主送机关
38
+ - body: 正文内容(列表)
39
+ - signer: 发文机关署名
40
+ - date: 成文日期
41
+ - attachment: 附件说明(可选)
42
+ - copy_to: 抄送机关(可选)
43
+ - issuer_office: 印发机关(可选,默认为发文机关办公室)
44
+ - issue_date: 印发日期(可选,默认为成文日期)
45
+
46
+ 返回:
47
+ Document对象
48
+ """
49
+ doc = Document()
50
+
51
+ # 设置页面格式(A4,页边距符合GB/T 9704-2012标准)
52
+ section = doc.sections[0]
53
+ section.page_width = Cm(21) # A4宽度
54
+ section.page_height = Cm(29.7) # A4高度
55
+ section.top_margin = Cm(3.7) # 天头37mm
56
+ section.bottom_margin = Cm(3.0) # 下白边
57
+ section.left_margin = Cm(2.8) # 订口28mm
58
+ section.right_margin = Cm(2.6) # 切口
59
+
60
+ # ========== 版头部分 ==========
61
+
62
+ # 发文机关标志(红色小标宋体)
63
+ if content.get('issuer'):
64
+ p = doc.add_paragraph()
65
+ p.alignment = WD_ALIGN_PARAGRAPH.CENTER
66
+ p.paragraph_format.space_before = Pt(0)
67
+ p.paragraph_format.space_after = Pt(0)
68
+ run = p.add_run(content['issuer'] + '文件')
69
+ run.font.size = Pt(22) # 小标宋体
70
+ run.font.bold = True
71
+ run.font.color.rgb = RGBColor(255, 0, 0) # 红色
72
+ run.font.name = '方正小标宋_GBK'
73
+ run._element.rPr.rFonts.set(qn('w:eastAsia'), '方正小标宋_GBK')
74
+
75
+ # 发文字号(仿宋体3号)
76
+ if content.get('doc_number'):
77
+ p = doc.add_paragraph()
78
+ p.alignment = WD_ALIGN_PARAGRAPH.CENTER
79
+ p.paragraph_format.space_before = Pt(12)
80
+ p.paragraph_format.space_after = Pt(0)
81
+ run = p.add_run(content['doc_number'])
82
+ run.font.size = Pt(16) # 3号字
83
+ run.font.name = '仿宋_GB2312'
84
+ run._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋_GB2312')
85
+
86
+ # 红色分隔线
87
+ add_horizontal_line(doc, color='FF0000', size_pt=2)
88
+
89
+ # ========== 主体部分 ==========
90
+
91
+ # 标题(小标宋体2号)
92
+ if content.get('title'):
93
+ p = doc.add_paragraph()
94
+ p.alignment = WD_ALIGN_PARAGRAPH.CENTER
95
+ p.paragraph_format.space_before = Pt(24)
96
+ p.paragraph_format.space_after = Pt(0)
97
+ run = p.add_run(content['title'])
98
+ run.font.size = Pt(22) # 2号字
99
+ run.font.bold = True
100
+ run.font.name = '方正小标宋_GBK'
101
+ run._element.rPr.rFonts.set(qn('w:eastAsia'), '方正小标宋_GBK')
102
+
103
+ # 主送机关
104
+ if content.get('recipient'):
105
+ p = doc.add_paragraph()
106
+ p.paragraph_format.space_before = Pt(12)
107
+ p.paragraph_format.space_after = Pt(0)
108
+ p.paragraph_format.left_indent = Pt(0)
109
+ run = p.add_run(content['recipient'] + ':')
110
+ run.font.size = Pt(16) # 3号字
111
+ run.font.name = '仿宋_GB2312'
112
+ run._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋_GB2312')
113
+
114
+ # 正文内容
115
+ if content.get('body'):
116
+ for para_text in content['body']:
117
+ p = doc.add_paragraph()
118
+ p.paragraph_format.space_before = Pt(0)
119
+ p.paragraph_format.space_after = Pt(0)
120
+ p.paragraph_format.first_line_indent = Pt(32) # 首行缩进2字符
121
+ run = p.add_run(para_text)
122
+ run.font.size = Pt(16) # 3号字
123
+ run.font.name = '仿宋_GB2312'
124
+ run._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋_GB2312')
125
+
126
+ # 结尾语(根据公文类型)
127
+ closing_phrases = {
128
+ '通知': '特此通知。',
129
+ '报告': '特此报告。',
130
+ '请示': '妥否,请批示。',
131
+ '函': '请予研究函复。',
132
+ '通报': '特此通报。'
133
+ }
134
+
135
+ if doc_type in closing_phrases:
136
+ p = doc.add_paragraph()
137
+ p.paragraph_format.space_before = Pt(12)
138
+ p.paragraph_format.space_after = Pt(0)
139
+ p.paragraph_format.first_line_indent = Pt(32)
140
+ run = p.add_run(closing_phrases[doc_type])
141
+ run.font.size = Pt(16)
142
+ run.font.name = '仿宋_GB2312'
143
+ run._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋_GB2312')
144
+
145
+ # 附件说明
146
+ if content.get('attachment'):
147
+ p = doc.add_paragraph()
148
+ p.paragraph_format.space_before = Pt(12)
149
+ p.paragraph_format.space_after = Pt(0)
150
+ p.paragraph_format.left_indent = Pt(32)
151
+ run = p.add_run('附件:' + content['attachment'])
152
+ run.font.size = Pt(16)
153
+ run.font.name = '仿宋_GB2312'
154
+ run._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋_GB2312')
155
+
156
+ # 发文机关署名
157
+ if content.get('signer'):
158
+ p = doc.add_paragraph()
159
+ p.alignment = WD_ALIGN_PARAGRAPH.CENTER
160
+ p.paragraph_format.space_before = Pt(24)
161
+ p.paragraph_format.space_after = Pt(0)
162
+ run = p.add_run(content['signer'])
163
+ run.font.size = Pt(16)
164
+ run.font.name = '仿宋_GB2312'
165
+ run._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋_GB2312')
166
+
167
+ # 成文日期
168
+ if content.get('date'):
169
+ p = doc.add_paragraph()
170
+ p.alignment = WD_ALIGN_PARAGRAPH.CENTER
171
+ p.paragraph_format.space_before = Pt(0)
172
+ p.paragraph_format.space_after = Pt(0)
173
+ run = p.add_run(content['date'])
174
+ run.font.size = Pt(16)
175
+ run.font.name = '仿宋_GB2312'
176
+ run._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋_GB2312')
177
+
178
+ # ========== 版记部分 ==========
179
+
180
+ # 版记分隔线(粗线)
181
+ p = doc.add_paragraph()
182
+ p.paragraph_format.space_before = Pt(24)
183
+ p.paragraph_format.space_after = Pt(0)
184
+ run = p.add_run('═' * 100)
185
+ run.font.size = Pt(3)
186
+ run.font.color.rgb = RGBColor(0, 0, 0)
187
+ run.font.name = '宋体'
188
+
189
+ # 抄送机关
190
+ if content.get('copy_to'):
191
+ p = doc.add_paragraph()
192
+ p.paragraph_format.space_before = Pt(0)
193
+ p.paragraph_format.space_after = Pt(0)
194
+ p.paragraph_format.left_indent = Pt(0)
195
+ run = p.add_run('抄送:' + content['copy_to'] + '。')
196
+ run.font.size = Pt(14) # 4号字
197
+ run.font.name = '仿宋_GB2312'
198
+ run._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋_GB2312')
199
+
200
+ # 版记分隔线(细线)
201
+ p = doc.add_paragraph()
202
+ p.paragraph_format.space_before = Pt(0)
203
+ p.paragraph_format.space_after = Pt(0)
204
+ run = p.add_run('─' * 100)
205
+ run.font.size = Pt(2)
206
+ run.font.color.rgb = RGBColor(0, 0, 0)
207
+ run.font.name = '宋体'
208
+
209
+ # 印发机关和印发日期
210
+ issuer_office = content.get('issuer_office', content.get('issuer', '') + '办公室')
211
+ issue_date = content.get('issue_date', content.get('date', ''))
212
+
213
+ p = doc.add_paragraph()
214
+ p.paragraph_format.space_before = Pt(0)
215
+ p.paragraph_format.space_after = Pt(0)
216
+ run = p.add_run(f'{issuer_office} {issue_date}印发')
217
+ run.font.size = Pt(14) # 4号字
218
+ run.font.name = '仿宋_GB2312'
219
+ run._element.rPr.rFonts.set(qn('w:eastAsia'), '仿宋_GB2312')
220
+
221
+ # 版记分隔线(粗线)
222
+ p = doc.add_paragraph()
223
+ p.paragraph_format.space_before = Pt(0)
224
+ p.paragraph_format.space_after = Pt(0)
225
+ run = p.add_run('═' * 100)
226
+ run.font.size = Pt(3)
227
+ run.font.color.rgb = RGBColor(0, 0, 0)
228
+ run.font.name = '宋体'
229
+
230
+ return doc
231
+
232
+
233
+ if __name__ == '__main__':
234
+ # 示例:生成报告类公文
235
+ content = {
236
+ 'issuer': 'XXX公司',
237
+ 'doc_number': 'XX〔2026〕1号',
238
+ 'title': '关于XXX公司情况的报告',
239
+ 'recipient': 'XX市相关主管部门、XX投资集团',
240
+ 'body': [
241
+ 'XXX公司成立于2023年3月,注册资本5亿元,是XX投资集团下属企业,专注于数据相关业务。',
242
+ '作为区域数字经济发展的主力军,公司定位清晰、职能明确,致力于推动本地数字经济发展。'
243
+ ],
244
+ 'signer': 'XXX公司',
245
+ 'date': '2026年3月13日',
246
+ 'attachment': 'XXX公司核心成果及重点项目清单',
247
+ 'copy_to': 'XX市数字经济发展局、XX区人民政府'
248
+ }
249
+
250
+ doc = create_official_document('报告', content)
251
+ doc.save('output.docx')
252
+ print("公文已成功生成:output.docx")
@@ -0,0 +1,390 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ 公文字体安装脚本
4
+ 用于安装GB/T 9704-2012标准所需的公文格式字体
5
+ """
6
+
7
+ import os
8
+ import sys
9
+ import shutil
10
+ import platform
11
+ from pathlib import Path
12
+ from typing import List, Dict, Tuple
13
+
14
+
15
+ class FontInstaller:
16
+ """字体安装器"""
17
+
18
+ def __init__(self, fonts_dir: str = None):
19
+ """
20
+ 初始化字体安装器
21
+
22
+ Args:
23
+ fonts_dir: 字体文件所在目录,默认为脚本所在目录的fonts子目录
24
+ """
25
+ if fonts_dir is None:
26
+ self.fonts_dir = Path(__file__).parent.parent / "fonts"
27
+ else:
28
+ self.fonts_dir = Path(fonts_dir)
29
+
30
+ self.system = platform.system()
31
+ self.installed_fonts = []
32
+ self.failed_fonts = []
33
+
34
+ # 定义所需字体
35
+ self.required_fonts = {
36
+ "方正小标宋_GBK": {
37
+ "files": ["FZXBSJW.TTF", "FZXBSJW_GB.TTF", "方正小标宋GBK.TTF", "方正小标宋_GBK.TTF"],
38
+ "description": "用于发文机关标志、标题",
39
+ "required": True
40
+ },
41
+ "仿宋_GB2312": {
42
+ "files": ["SIMFANG.TTF", "FANGSONG.TTF"],
43
+ "description": "用于正文、发文字号",
44
+ "required": True
45
+ },
46
+ "黑体": {
47
+ "files": ["SIMHEI.TTF", "HEITI.TTF"],
48
+ "description": "用于一级标题、密级",
49
+ "required": True
50
+ },
51
+ "楷体_GB2312": {
52
+ "files": ["SIMKAI.TTF", "KAITI.TTF"],
53
+ "description": "用于二级标题、签发人姓名",
54
+ "required": True
55
+ },
56
+ "宋体": {
57
+ "files": ["SIMSUN.TTF", "SONGTI.TTF", "SIMSUN.TTC", "simsun.ttc"],
58
+ "description": "用于页码",
59
+ "required": True
60
+ }
61
+ }
62
+
63
+ def check_system_fonts(self) -> Dict[str, bool]:
64
+ """
65
+ 检查系统已安装的字体
66
+
67
+ Returns:
68
+ 字体名称到是否已安装的映射
69
+ """
70
+ installed = {}
71
+
72
+ if self.system == "Windows":
73
+ fonts_paths = [
74
+ Path("C:/Windows/Fonts"),
75
+ Path.home() / "AppData/Local/Microsoft/Windows/Fonts"
76
+ ]
77
+ for font_name, font_info in self.required_fonts.items():
78
+ found = False
79
+ for fonts_path in fonts_paths:
80
+ for font_file in font_info["files"]:
81
+ if (fonts_path / font_file).exists():
82
+ found = True
83
+ break
84
+ if found:
85
+ break
86
+ installed[font_name] = found
87
+ elif self.system == "Darwin": # macOS
88
+ fonts_paths = [
89
+ Path("/Library/Fonts"),
90
+ Path("/System/Library/Fonts"),
91
+ Path.home() / "Library/Fonts"
92
+ ]
93
+ for font_name, font_info in self.required_fonts.items():
94
+ found = False
95
+ for fonts_path in fonts_paths:
96
+ for font_file in font_info["files"]:
97
+ if (fonts_path / font_file).exists():
98
+ found = True
99
+ break
100
+ if found:
101
+ break
102
+ installed[font_name] = found
103
+ else: # Linux
104
+ fonts_paths = [
105
+ Path("/usr/share/fonts"),
106
+ Path("/usr/local/share/fonts"),
107
+ Path.home() / ".fonts"
108
+ ]
109
+ for font_name, font_info in self.required_fonts.items():
110
+ found = False
111
+ for fonts_path in fonts_paths:
112
+ for font_file in font_info["files"]:
113
+ if (fonts_path / font_file).exists():
114
+ found = True
115
+ break
116
+ if found:
117
+ break
118
+ installed[font_name] = found
119
+
120
+ return installed
121
+
122
+ def install_font(self, font_file: Path) -> bool:
123
+ """
124
+ 安装单个字体文件
125
+
126
+ Args:
127
+ font_file: 字体文件路径
128
+
129
+ Returns:
130
+ 是否安装成功
131
+ """
132
+ try:
133
+ if self.system == "Windows":
134
+ # Windows系统:复制到Windows\Fonts目录
135
+ dest = Path("C:/Windows/Fonts") / font_file.name
136
+ shutil.copy2(font_file, dest)
137
+
138
+ # 注册字体(需要管理员权限)
139
+ import winreg
140
+ key = winreg.OpenKey(
141
+ winreg.HKEY_LOCAL_MACHINE,
142
+ r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts",
143
+ 0,
144
+ winreg.KEY_SET_VALUE
145
+ )
146
+ font_name = font_file.stem
147
+ winreg.SetValueEx(key, font_name, 0, winreg.REG_SZ, str(dest))
148
+ winreg.CloseKey(key)
149
+
150
+ elif self.system == "Darwin": # macOS
151
+ # macOS系统:复制到用户字体目录
152
+ dest = Path.home() / "Library/Fonts" / font_file.name
153
+ shutil.copy2(font_file, dest)
154
+
155
+ else: # Linux
156
+ # Linux系统:复制到用户字体目录
157
+ dest_dir = Path.home() / ".fonts"
158
+ dest_dir.mkdir(exist_ok=True)
159
+ dest = dest_dir / font_file.name
160
+ shutil.copy2(font_file, dest)
161
+
162
+ # 更新字体缓存
163
+ os.system("fc-cache -fv")
164
+
165
+ return True
166
+
167
+ except Exception as e:
168
+ print(f"安装字体失败: {font_file.name}, 错误: {str(e)}")
169
+ return False
170
+
171
+ def copy_fonts_from_system(self) -> Dict[str, bool]:
172
+ """
173
+ 从系统字体目录复制字体文件到skill的fonts目录
174
+
175
+ Returns:
176
+ 字体名称到是否复制成功的映射
177
+ """
178
+ copied = {}
179
+
180
+ # 定义系统字体目录列表
181
+ if self.system == "Windows":
182
+ system_fonts_paths = [
183
+ Path("C:/Windows/Fonts"),
184
+ Path.home() / "AppData/Local/Microsoft/Windows/Fonts"
185
+ ]
186
+ elif self.system == "Darwin": # macOS
187
+ system_fonts_paths = [
188
+ Path("/Library/Fonts"),
189
+ Path("/System/Library/Fonts"),
190
+ Path.home() / "Library/Fonts"
191
+ ]
192
+ else: # Linux
193
+ system_fonts_paths = [
194
+ Path("/usr/share/fonts"),
195
+ Path("/usr/local/share/fonts"),
196
+ Path.home() / ".fonts"
197
+ ]
198
+
199
+ print(f"从系统字体目录复制字体文件...")
200
+ print("-" * 60)
201
+
202
+ # 确保fonts目录存在
203
+ self.fonts_dir.mkdir(exist_ok=True)
204
+
205
+ for font_name, font_info in self.required_fonts.items():
206
+ copied[font_name] = False
207
+
208
+ # 检查skill的fonts目录是否已有该字体
209
+ skill_has_font = False
210
+ for font_file in font_info["files"]:
211
+ if (self.fonts_dir / font_file).exists():
212
+ skill_has_font = True
213
+ break
214
+
215
+ if skill_has_font:
216
+ print(f" {font_name}: skill目录已存在,跳过")
217
+ copied[font_name] = True
218
+ continue
219
+
220
+ # 从系统目录复制(遍历所有可能的目录)
221
+ for system_fonts_path in system_fonts_paths:
222
+ if not system_fonts_path.exists():
223
+ continue
224
+
225
+ for font_file in font_info["files"]:
226
+ system_font_path = system_fonts_path / font_file
227
+ if system_font_path.exists():
228
+ try:
229
+ dest_path = self.fonts_dir / font_file
230
+ shutil.copy2(system_font_path, dest_path)
231
+ print(f" ✓ {font_name}: 从系统复制 {font_file}")
232
+ copied[font_name] = True
233
+ break
234
+ except Exception as e:
235
+ print(f" ✗ {font_name}: 复制失败 - {str(e)}")
236
+
237
+ if copied[font_name]:
238
+ break
239
+
240
+ print("-" * 60)
241
+ return copied
242
+
243
+ def install_all_fonts(self) -> Tuple[List[str], List[str]]:
244
+ """
245
+ 安装所有所需字体
246
+
247
+ Returns:
248
+ (成功安装的字体列表, 安装失败的字体列表)
249
+ """
250
+ print(f"字体文件目录: {self.fonts_dir}")
251
+ print(f"操作系统: {self.system}")
252
+ print("-" * 60)
253
+
254
+ # 首先尝试从系统复制字体文件
255
+ self.copy_fonts_from_system()
256
+
257
+ # 检查系统已安装的字体
258
+ installed = self.check_system_fonts()
259
+ print("系统字体检查结果:")
260
+ for font_name, is_installed in installed.items():
261
+ status = "✓ 已安装" if is_installed else "✗ 未安装"
262
+ print(f" {font_name}: {status}")
263
+ print("-" * 60)
264
+
265
+ # 安装缺失的字体
266
+ for font_name, font_info in self.required_fonts.items():
267
+ if installed.get(font_name, False):
268
+ print(f"跳过 {font_name}(已安装)")
269
+ continue
270
+
271
+ print(f"正在安装 {font_name}...")
272
+
273
+ # 查找字体文件
274
+ font_found = False
275
+ for font_file in font_info["files"]:
276
+ font_path = self.fonts_dir / font_file
277
+ if font_path.exists():
278
+ if self.install_font(font_path):
279
+ self.installed_fonts.append(font_name)
280
+ font_found = True
281
+ print(f" ✓ {font_file} 安装成功")
282
+ break
283
+ else:
284
+ print(f" ✗ {font_file} 安装失败")
285
+
286
+ if not font_found:
287
+ self.failed_fonts.append(font_name)
288
+ print(f" ✗ 字体文件未找到")
289
+
290
+ print("-" * 60)
291
+ print(f"安装完成: {len(self.installed_fonts)} 个字体")
292
+ if self.failed_fonts:
293
+ print(f"安装失败: {len(self.failed_fonts)} 个字体")
294
+ print("请手动下载并安装以下字体:")
295
+ for font_name in self.failed_fonts:
296
+ font_info = self.required_fonts[font_name]
297
+ print(f" - {font_name}: {font_info['description']}")
298
+
299
+ return self.installed_fonts, self.failed_fonts
300
+
301
+ def generate_font_list(self) -> str:
302
+ """
303
+ 生成字体列表文档
304
+
305
+ Returns:
306
+ 字体列表文档内容
307
+ """
308
+ content = []
309
+ content.append("# 公文字体清单")
310
+ content.append("")
311
+ content.append("根据GB/T 9704-2012《党政机关公文格式》标准,公文生成需要以下字体:")
312
+ content.append("")
313
+ content.append("| 字体名称 | 用途 | 文件名 | 是否必需 |")
314
+ content.append("|---------|------|--------|---------|")
315
+
316
+ for font_name, font_info in self.required_fonts.items():
317
+ required = "是" if font_info["required"] else "否"
318
+ files = ", ".join(font_info["files"])
319
+ content.append(f"| {font_name} | {font_info['description']} | {files} | {required} |")
320
+
321
+ content.append("")
322
+ content.append("## 字体下载说明")
323
+ content.append("")
324
+ content.append("### 方式1:从系统字体目录复制")
325
+ content.append("")
326
+ content.append("Windows系统字体目录:`C:\\Windows\\Fonts`")
327
+ content.append("")
328
+ content.append("### 方式2:从官方渠道下载")
329
+ content.append("")
330
+ content.append("1. **方正小标宋_GBK**")
331
+ content.append(" - 官方网站:http://www.foundertype.com/")
332
+ content.append(" - 说明:方正字库官方提供,需要授权使用")
333
+ content.append("")
334
+ content.append("2. **仿宋_GB2312、黑体、楷体_GB2312、宋体**")
335
+ content.append(" - Windows系统自带,可直接从系统字体目录复制")
336
+ content.append(" - 或从微软官网下载")
337
+ content.append("")
338
+ content.append("## 安装方法")
339
+ content.append("")
340
+ content.append("### Windows系统")
341
+ content.append("```powershell")
342
+ content.append("# 以管理员身份运行PowerShell")
343
+ content.append("python scripts/install_fonts.py")
344
+ content.append("```")
345
+ content.append("")
346
+ content.append("### macOS系统")
347
+ content.append("```bash")
348
+ content.append("python scripts/install_fonts.py")
349
+ content.append("```")
350
+ content.append("")
351
+ content.append("### Linux系统")
352
+ content.append("```bash")
353
+ content.append("python scripts/install_fonts.py")
354
+ content.append("```")
355
+
356
+ return "\n".join(content)
357
+
358
+
359
+ def main():
360
+ """主函数"""
361
+ print("=" * 60)
362
+ print("公文格式字体安装工具")
363
+ print("符合GB/T 9704-2012《党政机关公文格式》标准")
364
+ print("=" * 60)
365
+ print()
366
+
367
+ # 创建字体安装器
368
+ installer = FontInstaller()
369
+
370
+ # 安装字体
371
+ installed, failed = installer.install_all_fonts()
372
+
373
+ # 生成字体列表文档
374
+ fonts_list_path = Path(__file__).parent.parent / "fonts" / "FONTS_LIST.md"
375
+ fonts_list_path.parent.mkdir(exist_ok=True)
376
+ with open(fonts_list_path, "w", encoding="utf-8") as f:
377
+ f.write(installer.generate_font_list())
378
+
379
+ print()
380
+ print(f"字体列表文档已生成: {fonts_list_path}")
381
+
382
+ # 返回状态码
383
+ if failed:
384
+ sys.exit(1)
385
+ else:
386
+ sys.exit(0)
387
+
388
+
389
+ if __name__ == "__main__":
390
+ main()