@deepwhale-cn/dsh-cn-doc-formatter 0.1.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.
package/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DeepWhale (深鲸)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ────────────────────────────────────────────────────────────────────────
24
+
25
+ 本软件不包含任何字体文件。使用者在文档中选用何种字体,由使用者自行负责
26
+ 取得该字体的合法授权。
package/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # @deepwhale-cn/dsh-cn-doc-formatter
2
+
3
+ **中文公文排版** —— 给 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 用的 skill 插件。
4
+
5
+ 按 **GB/T 9704-2012《党政机关公文格式》** 生成 `.docx` / `.pdf` / `.txt`,
6
+ 并自带**输出自检**——生成完逐项核对页边距、字号、行距、字体、页面尺寸,
7
+ 不符合规范就报错,而不是让你交付一份看起来差不多、实际不合规的文件。
8
+
9
+ ## ⚠️ 本插件不含字体,字体需你自备
10
+
11
+ **这是刻意的设计,不是缺失。**
12
+
13
+ 公文规范要求的仿宋(方正仿宋等)是**商业字体**。其授权允许你在文档中使用,
14
+ 但**不允许再分发字体文件本身**。所以本插件只做「排版引擎」,字体由你提供:
15
+
16
+ ```bash
17
+ # 方式一:直接指定字体文件(推荐,最明确)
18
+ export DSH_CN_FANGSONG=/path/to/仿宋.ttf
19
+ export DSH_CN_FANGSONG_BOLD=/path/to/仿宋加粗.ttf # 可选
20
+
21
+ # 方式二:指定一个目录,脚本在其中按文件名查找
22
+ export DSH_CN_FONT_DIR=~/my-fonts
23
+ ```
24
+
25
+ 也可以直接装进**系统字体目录**(一次装好处处可用):
26
+
27
+ | 系统 | 目录 |
28
+ |---|---|
29
+ | macOS | `~/Library/Fonts/` |
30
+ | Windows | `C:\Windows\Fonts\` |
31
+ | Linux | `~/.fonts/` 或 `~/.local/share/fonts/` |
32
+
33
+ 装 WPS Office 也行 —— 它自带方正仿宋。
34
+
35
+ **找不到字体时不会静默失败**:PDF 退回系统宋体,并在 stderr 打印上面这张获取指引。
36
+ docx 只在文件里声明字体族名(由你机器上的 Word 渲染),不依赖字体文件。
37
+
38
+ > **一个细节**:如果你只有常规仿宋、没有加粗体,**标题会继续使用仿宋**(只是不加粗),
39
+ > 而不是换成宋体。因为「全文统一仿宋」是硬规范,宁可字重不够也不换字体族。
40
+ > reportlab 不做合成粗体,这是引擎限制。
41
+
42
+ ## 它管什么
43
+
44
+ | 项目 | 规范值 |
45
+ |---|---|
46
+ | 标题 | 仿宋,二号(22pt)加粗,居中,行距 33–36 磅 |
47
+ | 一/二/三/四级标题 | 仿宋,三号(16pt)加粗,左空二字 |
48
+ | 正文 | 仿宋,四号(14pt),固定行距 28 磅,首行缩进严格 2 字 |
49
+ | 版头(可选) | 份号 / 密级 / 紧急程度 / 发文字号,仿宋三号 |
50
+ | 署名与日期 | 距正文下空 3 行,日期阿拉伯数字右空 4 字 |
51
+ | 页码 | 「- 1 -」,单页居右空一字、双页居左空一字 |
52
+ | 页边距 | 上 3.7 / 下 3.5 / 左 2.8 / 右 2.6 cm |
53
+ | 文档网格 | 每面 22 行、每行 28 字 |
54
+
55
+ **不出现任何 AI 痕迹**:无水印、无生成标记、无作者信息、无版本说明、无注释。
56
+
57
+ ## 安装
58
+
59
+ ```bash
60
+ dsh plugin --profile <profile> add @deepwhale-cn/dsh-cn-doc-formatter
61
+ ```
62
+
63
+ 然后重启 dsh。技能会在 agent 需要时自动可用。
64
+
65
+ ### Python 依赖
66
+
67
+ 排版脚本是 Python,需要这些库:
68
+
69
+ ```bash
70
+ pip install python-docx reportlab fontTools pypdf
71
+ ```
72
+
73
+ | 库 | 用途 |
74
+ |---|---|
75
+ | `python-docx` | 生成 Word 文档 |
76
+ | `reportlab` | 生成 PDF |
77
+ | `fontTools` | 探测本机已装字体(读字体 name 表) |
78
+ | `pypdf` | 自检时校验 PDF 是否真的嵌入了目标字体 |
79
+
80
+ ## 它比「套个模板」多做了什么
81
+
82
+ **1. 输出自检(`verify_output.py`)**
83
+
84
+ 生成完不是结束。自检会真的打开产出文件,逐项核对:
85
+
86
+ ```
87
+ ── 公文.docx
88
+ ✅ 上边距 3.70cm ✓ ✅ 标题 22pt 加粗 ✓
89
+ ✅ 正文 14.0pt / 行距 28pt ✓
90
+ ✅ 全文统一字体:FangS-SC ✓
91
+ ── 公文.pdf
92
+ ✅ 嵌入字体:/AAAAAA+FangS-SC, /AAAAAA+FangS-SC-Bold
93
+ ✅ 页面 A4 21.0×29.7cm ✓
94
+ ```
95
+
96
+ 退出码 `0` = 通过,`1` = 有不符合项 —— **可以直接用在 CI 或交付卡口上**。
97
+
98
+ **2. Markdown 输入适配(`md_adapter.py`)**
99
+
100
+ 内容常以 Markdown 写就,直接喂给脚本会丢失层级(整篇被当正文):
101
+
102
+ | Markdown | 转成 | 公文层级 |
103
+ |---|---|---|
104
+ | `## 一、小节` | `一、小节` | 一级标题 |
105
+ | `### 1.1 小节` | `(一)小节` | 二级标题 |
106
+ | `#### 更深` | `1. 小节` | 三级标题 |
107
+ | `- 列表项` | 正文 | 正文 |
108
+ | `\| 表格 \|` | `表头:值;表头:值。` | 正文 |
109
+
110
+ 它还会把同一段内的软换行合并成一行 —— 源文档常手动折行,
111
+ 逐行当独立段落会在断句处留下孤立标点(如单独一行的「、」)。
112
+
113
+ **3. 跨平台字体探测**
114
+
115
+ 早期实现用 `fc-list` 探测字体,而 **macOS 不预装 fontconfig**,
116
+ 异常被吞掉后恒返回「字体不存在」,于是**即使装了仿宋也检测不到**,永远走回退分支。
117
+ 本版改为直接读字体文件的 `name` 表,macOS / Windows / Linux 通用。
118
+
119
+ ## 用法
120
+
121
+ 技能正文里有完整命令。核心三条:
122
+
123
+ ```bash
124
+ # 生成 Word / PDF
125
+ python "<插件目录>/scripts/docx_formatter.py" --output <目录> \
126
+ --title "标题" --body "正文..." --sender "发文机关" --date "2026年9月25日"
127
+ python "<插件目录>/scripts/pdf_formatter.py" --output <目录> \
128
+ --title "标题" --body "正文..." --sender "发文机关" --date "2026年9月25日"
129
+
130
+ # 输出自检(不要跳过)
131
+ python "<插件目录>/scripts/verify_output.py" --dir <输出目录>
132
+ ```
133
+
134
+ > ⚠️ **早期文档里的 `--type notice` 参数并不存在**,加上会直接报
135
+ > `unrecognized arguments`。文种由内容决定,脚本不做区分。本版已修正文档。
136
+
137
+ ## 设计取舍
138
+
139
+ **不分发字体。** 见上文——这不是省事,是避免把商业字体的再分发风险
140
+ 转嫁给每一个使用者。
141
+
142
+ **不联网。** 排版、字体探测、自检全部在本地完成,不把文档内容发往任何第三方服务。
143
+
144
+ **文种不参与排版。** 通知 / 报告 / 函 / 决定的排版规范是一致的,
145
+ 差别只在正文怎么写。脚本不为文种分叉,避免维护一堆看似不同实则相同的模板。
146
+
147
+ ## 与其它插件的关系
148
+
149
+ 按 [DSH 插件生态倡议书](https://github.com/anywhere-labs/dsh-desktop/blob/main/docs/plugin-ecosystem.md)
150
+ 的三条原则开发:**组合优先、声明清晰、兼容优先**。不假设、不覆盖其它插件的内部实现。
151
+
152
+ ## 许可
153
+
154
+ MIT。**本软件不包含任何字体文件**;使用者在文档中选用何种字体,由使用者自行负责
155
+ 取得该字体的合法授权。
@@ -0,0 +1,10 @@
1
+ # @deepwhale-cn/dsh-cn-doc-formatter 的组合层
2
+ #
3
+ # profile 在 dsh.profile.bundles 里列出本包后,这一层会把插件本身挂进组合。
4
+ #
5
+ # 约定(官方 verify-cordis-config 强制):每个具名行都必须能从本包自己的
6
+ # 作用域解析。这里 name 写的就是本包已发布的包名 —— 加载器按这个 specifier 导入,
7
+ # 所以它必须与 package.json 的 name 完全一致。
8
+ - insert:
9
+ - id: cn-doc-formatter
10
+ name: '@deepwhale-cn/dsh-cn-doc-formatter'
@@ -0,0 +1,27 @@
1
+ 把仿宋字体文件放进这个目录即可被自动识别(可选做法)。
2
+
3
+ 本插件不随包分发任何字体 —— 方正仿宋等是商业字体,其授权允许在文档中使用,
4
+ 但不允许再分发字体文件本身。
5
+
6
+ 推荐做法(优先级从高到低):
7
+
8
+ 1. 环境变量直接指定文件(最明确,不受文件名限制)
9
+ export DSH_CN_FANGSONG=/path/to/仿宋.ttf
10
+ export DSH_CN_FANGSONG_BOLD=/path/to/仿宋加粗.ttf # 可选
11
+
12
+ 2. 环境变量指定一个目录
13
+ export DSH_CN_FONT_DIR=~/my-fonts
14
+
15
+ 3. 放进系统字体目录(推荐,一次装好处处可用)
16
+ macOS ~/Library/Fonts/
17
+ Windows C:\Windows\Fonts\
18
+ Linux ~/.fonts/ 或 ~/.local/share/fonts/
19
+
20
+ 4. 放进本插件的这个 fonts/ 目录
21
+ ⚠️ 注意:npm 更新本插件时这个目录可能被覆盖,建议用方式 1 / 2 / 3。
22
+
23
+ 脚本可自动识别的文件名:
24
+ FangS-SC.ttf、simfang.ttf、FangSong.ttf、FangSong_GB2312.ttf、
25
+ STFangsong.ttf、FandolFang-Regular.otf、仿宋.ttf、仿宋_GB2312.ttf
26
+
27
+ 文件名不在上面的列表里也没关系 —— 用 DSH_CN_FANGSONG 显式指定即可。
package/lib/index.js ADDED
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @deepwhale-cn/dsh-cn-doc-formatter — 中文公文排版
3
+ *
4
+ * 把 GB/T 9704-2012 党政机关公文格式的排版方法注册为 DSH skill,
5
+ * 使 agent 在需要生成公文时能按规范产出 .docx / .pdf / .txt。
6
+ *
7
+ * ── 关于字体(本插件最重要的设计约束)────────────────────────────────
8
+ * 本插件**不随包分发任何字体文件**。公文规范要求的仿宋(方正仿宋等)是商业字体,
9
+ * 其授权允许在文档中使用,但不允许再分发字体文件本身。因此这里是「排版引擎」,
10
+ * 字体由用户自备,通过环境变量或系统字体目录提供:
11
+ *
12
+ * DSH_CN_FANGSONG 仿宋常规体文件的绝对路径(最高优先)
13
+ * DSH_CN_FANGSONG_BOLD 仿宋加粗体(可选)
14
+ * DSH_CN_FONT_DIR 一个目录,脚本在其中按文件名查找
15
+ *
16
+ * 找不到时的行为见 skill/scripts/pdf_formatter.py 的 register_fonts():
17
+ * 退回系统宋体并在 stderr 打印可操作的指引,不会静默失败。
18
+ *
19
+ * ── 技能标识 ────────────────────────────────────────────────────────
20
+ * SKILL_NAME 取 'cn-doc-formatter' 而非 'chinese-doc-formatter':后者是很多用户
21
+ * 本地已有的私有技能名,重名会与用户自己的技能冲突。加 cn- 前缀以示这是插件内嵌版本。
22
+ *
23
+ * ── 与官方 API 的约定 ───────────────────────────────────────────────
24
+ * 依赖 `ctx.skills`(由 @deepseek-ai/dsh-skill 提供)。缺失时插件不做任何事,
25
+ * 不会影响 profile 启动。
26
+ */
27
+
28
+ import { readFileSync } from 'node:fs';
29
+ import { fileURLToPath } from 'node:url';
30
+ import { dirname, join } from 'node:path';
31
+
32
+ /** 本包根目录(lib/ 的上一级) */
33
+ const packageRoot = join(dirname(fileURLToPath(import.meta.url)), '..');
34
+ /** 随包分发的 skill 与脚本所在目录 */
35
+ const skillDir = join(packageRoot, 'skill');
36
+
37
+ /** 技能正文里用来占位脚本目录的标记 —— 运行期替换成真实绝对路径 */
38
+ const SKILL_DIR_PLACEHOLDER = '<skill目录>';
39
+
40
+ export const name = 'cn-doc-formatter';
41
+ export const inject = ['skills'];
42
+
43
+ /** 技能标识:kebab-case。刻意避开 'chinese-doc-formatter',见文件头说明 */
44
+ const SKILL_NAME = 'cn-doc-formatter';
45
+
46
+ /** 随包分发的 skill 目录绝对路径(安装后位置由加载器决定) */
47
+ export function skillDirPath() {
48
+ return skillDir;
49
+ }
50
+
51
+ function skillBody() {
52
+ const raw = readFileSync(join(skillDir, 'chinese-doc-formatter.md'), 'utf-8');
53
+ // 把占位符替换为真实路径:用户安装到任何位置都能照文档直接跑脚本
54
+ return raw.split(SKILL_DIR_PLACEHOLDER).join(skillDir);
55
+ }
56
+
57
+ export function apply(ctx) {
58
+ // skills 服务缺失时静默跳过:这是一个可选能力,不应阻断 profile 启动
59
+ if (!ctx.skills || typeof ctx.skills.register !== 'function') {
60
+ ctx.logger?.warn?.('[cn-doc-formatter] 未找到 skills 服务,跳过技能注册');
61
+ return;
62
+ }
63
+
64
+ let content;
65
+ try {
66
+ content = skillBody();
67
+ } catch (error) {
68
+ ctx.logger?.error?.(`[cn-doc-formatter] 读取技能正文失败: ${String(error)}`);
69
+ return;
70
+ }
71
+
72
+ ctx.skills.register({
73
+ name: SKILL_NAME,
74
+ // 来源标记:'bundled' = 随插件分发的内嵌技能(区别于磁盘上的 project/user 技能)
75
+ source: 'bundled',
76
+ description:
77
+ '中文公文排版生成器。按 GB/T 9704-2012 规范生成 Word(.docx)、PDF、TXT 中文文书,' +
78
+ '涵盖字体字号、行距、页边距、标题层级与页码。涉及排版、格式、文书、公文、' +
79
+ '字体、行距等需求时使用。',
80
+ whenToUse:
81
+ '需要生成或排版中文公文/正式文书时使用——通知、报告、函、决定、意见等。' +
82
+ '用户提到「排版」「格式」「docx」「pdf」「word」「文书」「公文」「字体」「行距」' +
83
+ '时也必须使用。',
84
+ content,
85
+ });
86
+
87
+ ctx.logger?.info?.(`[cn-doc-formatter] 已注册技能 ${SKILL_NAME}`);
88
+ }
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@deepwhale-cn/dsh-cn-doc-formatter",
3
+ "version": "0.1.0",
4
+ "description": "中文公文排版:按 GB/T 9704-2012 生成 .docx / .pdf / .txt,附输出自检。不含字体文件,字体由用户自备。",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "keywords": [
8
+ "dsh",
9
+ "deepseek-harness",
10
+ "plugin",
11
+ "skill",
12
+ "docx",
13
+ "pdf",
14
+ "公文",
15
+ "排版",
16
+ "仿宋",
17
+ "GB/T 9704"
18
+ ],
19
+ "files": [
20
+ "lib",
21
+ "skill",
22
+ "fonts",
23
+ "cordis.patch.yml",
24
+ "README.md"
25
+ ],
26
+ "main": "./lib/index.js",
27
+ "exports": {
28
+ ".": "./lib/index.js",
29
+ "./package.json": "./package.json"
30
+ },
31
+ "engines": {
32
+ "dsh": ">=0.1.0-rc.6"
33
+ },
34
+ "dsh": {
35
+ "bundle": {
36
+ "patch": "./cordis.patch.yml"
37
+ }
38
+ },
39
+ "peerDependencies": {
40
+ "@deepseek-ai/dsh-skill": "*"
41
+ }
42
+ }
@@ -0,0 +1,328 @@
1
+ ---
2
+ name: chinese-doc-formatter
3
+ description: 中文文书排版生成器。当用户需要生成 Word(.docx)、PDF、TXT 等格式的中文文书或文件,涉及排版、字体、行距、标题加粗等需求时使用。触发词:"排版"、"格式"、"docx"、"pdf"、"word"、"文书"、"文件"、"字体"、"行距"。
4
+ ---
5
+
6
+ # 中文文书排版技能
7
+
8
+ 生成排版规范的中文常规文书(通知、报告、函、文件等)。输出 .docx / .pdf / .txt 三种文件,全文统一使用仿宋(GB2312 简体字集)排版,严格遵循以下规范,且文档内不出现任何 AI 生成痕迹(无水印、无生成标记、无作者信息、无版本说明)。
9
+
10
+ ## 字体字号规范
11
+
12
+ ### 正文内容
13
+
14
+ | 元素 | 字体 | 字号 | 字号对照(磅) |
15
+ |------|------|------|---------------|
16
+ | 标题 | 仿宋(全文统一) | 二号加粗 | 22pt |
17
+ | 正文 | 仿宋 | 四号 | 14pt |
18
+ | 一级标题 | 仿宋 | 三号加粗 | 16pt |
19
+ | 二级标题 | 仿宋 | 三号加粗 | 16pt |
20
+ | 三级标题 | 仿宋 | 三号加粗 | 16pt |
21
+ | 四级标题 | 仿宋 | 三号加粗 | 16pt |
22
+ | 数字/英文 | 仿宋(与全文一致) | 四号 | 14pt |
23
+ | 页码 | 仿宋阿拉伯数字 | 四号半角 | 14pt |
24
+
25
+ ### 版头(可选,仅红头文件需要,常规文书默认不输出)
26
+
27
+ 份号顶格居左第一行、密级第二行、紧急程度第三行(仿宋三号);发文字号仿宋三号(上行文左空一字,否则居中)。不设签发人。
28
+
29
+ ### 附件、落款、日期
30
+
31
+ | 元素 | 字体 | 字号 |
32
+ |------|------|------|
33
+ | 附件说明 | 仿宋 GB2312 | 四号 |
34
+ | 发文机关署名 | 仿宋 GB2312 | 四号 |
35
+ | 成文日期 | 仿宋 GB2312 | 四号 |
36
+
37
+ ## 行距与页边距规范
38
+
39
+ | 项目 | 规范值 |
40
+ |------|--------|
41
+ | 标题行距 | 固定值 33-36 磅 |
42
+ | 正文行距 | 固定值 28 磅 |
43
+ | 上边距 | 3.7 cm |
44
+ | 下边距 | 3.5 cm |
45
+ | 左边距 | 2.8 cm |
46
+ | 右边距 | 2.6 cm |
47
+ | 文档网格 | 每面排 22 行,每行排 28 个字(Word 按 28 磅行距设置 docGrid) |
48
+
49
+ ## 输出文件规范
50
+
51
+ 生成文件须同时输出以下格式:
52
+ 1. **Word 文档 (.docx)** — 标准排版,可编辑
53
+ 2. **PDF 文件 (.pdf)** — 打印级质量,与 Word 排版一致
54
+ 3. **纯文本文件 (.txt)** — 无格式,保留标题层级结构
55
+
56
+ 所有文件保存在用户指定的输出目录(默认为桌面 `公文排版输出/` 目录)。
57
+
58
+ ## 无 AI 痕迹要求
59
+
60
+ 生成的文档必须是纯粹、专业的公文,不得包含:
61
+ - 任何作者署名、AI 标记、生成时间戳
62
+ - 任何解释性文字、注释或说明
63
+ - 任何文档结构说明或元信息
64
+ - 任何来源标注或版权信息
65
+
66
+ 文档应仅包含用户要求的内容本身,格式专业、干净。
67
+
68
+ ## 字体:本插件不随包分发,需用户自备
69
+
70
+ ⚠️ **本插件不含任何字体文件。** 公文规范要求的仿宋(方正仿宋等)是商业字体,
71
+ 其授权允许在文档中使用,但**不允许再分发字体文件本身**。因此本插件只提供排版引擎,
72
+ 字体请自行准备 —— 这是刻意的设计,不是缺失。
73
+
74
+ ### 怎么提供字体
75
+
76
+ PDF 需要真正读取字体文件并嵌入,按以下顺序查找,**命中即用**:
77
+
78
+ | 顺序 | 来源 | 说明 |
79
+ |---|---|---|
80
+ | 1 | 环境变量 `DSH_CN_FANGSONG` | 直接指向仿宋字体文件,**最高优先**,最明确 |
81
+ | 1 | 环境变量 `DSH_CN_FANGSONG_BOLD` | 加粗体(可选;不提供时标题用常规仿宋,见下) |
82
+ | 2 | 环境变量 `DSH_CN_FONT_DIR` | 指定一个目录,脚本在其中按文件名查找 |
83
+ | 3 | 插件自己的 `fonts/` 目录 | 用户自行把字体文件放进去 |
84
+ | 4 | 系统字体目录 | macOS `~/Library/Fonts`/Windows `C:\Windows\Fonts`/Linux `~/.fonts`、`/usr/share/fonts` |
85
+ | 5 | WPS Office 安装目录 | WPS 自带方正仿宋 |
86
+
87
+ **用法示例**:
88
+
89
+ ```bash
90
+ # 方式一:直接指定文件(推荐,最明确、不受文件名限制)
91
+ export DSH_CN_FANGSONG=/path/to/仿宋.ttf
92
+
93
+ # 方式二:指定一个目录
94
+ export DSH_CN_FONT_DIR=~/my-fonts
95
+ ```
96
+
97
+ **可自动识别的仿宋文件名**:`FangS-SC.ttf`、`simfang.ttf`、`FangSong.ttf`、
98
+ `STFangsong.ttf`、`FandolFang-Regular.otf`、`仿宋.ttf` 等。
99
+ 文件名不在列表里的,用 `DSH_CN_FANGSONG` 显式指定即可。
100
+
101
+ **找不到时的行为 —— 不会静默失败**:
102
+ - PDF 退回系统宋体,并在 stderr 打印上面这张获取指引
103
+ - docx 退回本机可用的宋体族名,并打印同样格式的提示
104
+
105
+ ### Word 文档 (.docx)
106
+
107
+ docx 只在文件里**声明字体族名**,实际渲染由用户机器上的 Word 完成,
108
+ 所以 docx 不依赖字体文件本身。脚本会实测本机已装字体,按优先级取第一个命中的族名:
109
+
110
+ | 顺序 | 字体族名 | 说明 |
111
+ |---|---|---|
112
+ | 1 | `仿宋_GB2312` | Windows 标准公文仿宋 |
113
+ | 2 | `FangS-SC` | 方正仿宋(WPS 自带;需自备) |
114
+ | 3 | `仿宋` | Windows 自带仿宋的另一族名 |
115
+ | 4 | `FandolFang R` | macOS 常见仿宋替代(注意真实族名带空格与 R) |
116
+ | 5 | `STFangsong` | macOS 华文仿宋 |
117
+ | 6 | `Songti SC` | 最后回退:宋体 |
118
+
119
+ 标题与小标题通过**加粗**区分,字体族与正文一致:
120
+
121
+ | 元素 | 字体 | 加粗 |
122
+ |------|------|------|
123
+ | 标题 | 上表命中的仿宋族 | 是 |
124
+ | 正文 | 上表命中的仿宋族 | 否 |
125
+ | 一/二/三/四级标题 | 上表命中的仿宋族 | 是 |
126
+ | 附件、署名、日期、页码 | 上表命中的仿宋族 | 否 |
127
+
128
+ ### PDF 文档
129
+
130
+ PDF 需要**嵌入字体**,所以必须有真实字体文件(见上)。
131
+
132
+ - 正文 / 版头 / 页码 → 仿宋常规体
133
+ - 标题 / 各级小标题 → 仿宋加粗体
134
+
135
+ **没有加粗字体时**(用户自备字体的常态):标题**继续使用常规仿宋**,只是不加粗。
136
+ 这样保住了「全文统一仿宋」这条硬规范 —— 宁可字重不够,也不换成宋体。
137
+ 需要真加粗时用 `DSH_CN_FANGSONG_BOLD` 指定加粗体文件。
138
+ (reportlab 不做合成粗体,这是引擎限制。)
139
+
140
+ ### 页码处理
141
+ 页码使用宋体,四号(14pt)半角阿拉伯数字,格式为 `- 1 -`:
142
+ - PDF:每页页脚输出,单页码居右空一字,双页码居左空一字
143
+ - Word:页脚插入 PAGE 域,奇数页居右空一字,偶数页居左空一字
144
+
145
+ ## 工作流程
146
+
147
+ ### 第一步:确认文档类型和内容
148
+
149
+ 向用户确认:
150
+ - 文档类型:一般文书(通知、函、报告等)/ 红头文件 / 其他正式文本
151
+ - 是否需要版头(份号、密级、紧急程度、发文字号;默认不需要)
152
+ - 正文内容是什么
153
+ - 输出目录(默认为桌面)
154
+
155
+ ### 第二步:生成文件
156
+
157
+ 调用脚本生成 docx 和 pdf:
158
+
159
+ ```bash
160
+ # 生成 Word 文档
161
+ python "<skill目录>/scripts/docx_formatter.py" \
162
+ --output /path/to/output \
163
+ --title "标题文字" \
164
+ --body "正文内容..." \
165
+ --sender "发文机关名称" \
166
+ --date "成文日期"
167
+
168
+ # 生成 PDF
169
+ python "<skill目录>/scripts/pdf_formatter.py" \
170
+ --output /path/to/output \
171
+ --title "标题文字" \
172
+ --body "正文内容..." \
173
+ --sender "发文机关名称" \
174
+ --date "成文日期"
175
+ ```
176
+
177
+ ### 第三步:生成 TXT 版本
178
+
179
+ 从内容中提取纯文本,按标题层级保留结构,生成 .txt 文件。
180
+
181
+ ### 第四步:输出自检(**不要跳过**)
182
+
183
+ ```bash
184
+ python "<skill目录>/scripts/verify_output.py" --dir <输出目录>
185
+ ```
186
+
187
+ 逐项核对页边距、标题字号加粗、正文行高、字体是否本机存在、PDF 是否嵌入仿宋、页面是否 A4。
188
+ **退出码 0 = 通过,1 = 有不符合项** —— 必须处理完再交付。
189
+
190
+ ### 第五步:确认输出
191
+
192
+ 告知用户文件位置和格式,附上简要说明。
193
+
194
+ ---
195
+
196
+ ## 从 Markdown 生成(常见场景)
197
+
198
+ 内容常以 Markdown 写就,直接喂给脚本会**丢失层级**(整篇被当正文)。
199
+ 先用 `md_adapter.py` 转换:
200
+
201
+ ```bash
202
+ python "<skill目录>/scripts/md_adapter.py" \
203
+ --input 原文.md --output /tmp/_body.txt [--drop-meta]
204
+ ```
205
+
206
+ 转换规则:
207
+
208
+ | Markdown | 转成 | 公文层级 |
209
+ |---|---|---|
210
+ | `# 标题` | (丢弃,作为 `--title` 传入) | — |
211
+ | `## 一、小节` | `一、小节` | 一级标题 |
212
+ | `### 1.1 小节` | `(一)小节` | 二级标题 |
213
+ | `#### 更深` | `1. 小节` | 三级标题 |
214
+ | `- 列表项` | 正文 | 正文 |
215
+ | `| 表格 |` | `表头:值;表头:值。` | 正文 |
216
+ | `> 引用块` | 正文(连续行自动合并) | 正文 |
217
+
218
+ 再把 `_body.txt` 内容作为 `--body` 传给 docx/pdf 脚本。
219
+
220
+ **注意**:`md_adapter` 会把同一段内的软换行合并成一行(源文档常手动折行,
221
+ 逐行当独立段落会在断句处留下孤立标点,如单独一行的「、」)。
222
+
223
+ ## 文种
224
+
225
+ 公文文种(通知 / 报告 / 函 / 决定 / 意见 等)由**内容本身**决定,脚本不做区分 ——
226
+ 排版规范对所有文种是一致的,差别只在于正文怎么写。
227
+
228
+ 常用文种及其特征,供起草时参考:
229
+
230
+ | 文种 | 特征 |
231
+ |------|------|
232
+ | 通知 | 最常见,含主送机关、正文、发文机关署名、日期 |
233
+ | 报告 | 上行文,汇报工作、反映情况 |
234
+ | 函 | 平行文或不相隶属机关之间的商洽工作 |
235
+ | 决定 | 重要事项决策 |
236
+ | 意见 | 对重要问题提出见解和处理办法 |
237
+
238
+ > ⚠️ 早期版本的本 skill 文档里写过 `--type notice` 参数,**该参数在脚本中并不存在**
239
+ > (命令行会直接报 `unrecognized arguments`)。文种无需传参,已在本版修正。
240
+
241
+ ## 特殊处理
242
+
243
+ ### 版头信息
244
+ - 份号:顶格居左排在版心第一行
245
+ - 密级:第二行;紧急程度:第三行
246
+ - 发文字号:仿宋,三号;上行文左空一字,下行文居中
247
+ - 不设签发人;常规文书默认不带版头
248
+
249
+ ### 标题格式
250
+ - 居中,二号字加粗,仿宋
251
+ - 标题行距 33-36 磅
252
+
253
+ ### 一级标题
254
+ 格式:一、二、三……(仿宋,三号加粗,左空二字)
255
+
256
+ ### 二级标题
257
+ 格式:(一)(二)(三)……(仿宋,三号加粗,左空二字)
258
+
259
+ ### 三级标题
260
+ 格式:1. 2. 3. ……(仿宋,三号加粗,左空二字)
261
+
262
+ ### 四级标题
263
+ 格式:(1)(2)(3)……(仿宋,三号加粗,左空二字)
264
+
265
+ ### 正文段落
266
+ - 四号(14pt)仿宋 GB2312,首行缩进严格 2 字
267
+
268
+ ### 发文机关署名和日期
269
+ - 距正文(或附件说明)下空 3 行
270
+ - 署名以成文日期为准居中编排
271
+ - 日期用阿拉伯数字,右空 4 字
272
+ - 署名在上,日期在下
273
+
274
+ ### 页码
275
+ - 格式:"- 1 -"(单页码右空一字,双页码左空一字)
276
+ - 位置:版心下边缘之下的页脚区(PDF 每页输出;Word 奇偶页页脚插入 PAGE 域)
277
+ - 字体:宋体,四号,半角
278
+
279
+ ---
280
+
281
+ ## 附录:2026-09-22 修复记录
282
+
283
+ 本 skill 曾有四处缺陷,已在当日修复,此处存档以免重犯。
284
+
285
+ ### 1. 字体探测在 macOS 上恒失败(**最严重**)
286
+
287
+ ```python
288
+ # 原实现
289
+ out = subprocess.run(['fc-list', f':family={family}'], ...)
290
+ return bool(out.stdout.strip())
291
+ ```
292
+
293
+ `fc-list` 是 fontconfig 的命令,**macOS 不预装**。异常被 `except` 吞掉后函数恒返回
294
+ `False`,于是**即使机器上装了 `仿宋_GB2312` 也检测不到**,永远走回退分支。
295
+
296
+ → 已改为直接扫描字体文件读 `name` 表(fontTools),macOS / Windows / Linux 通用,
297
+ 并逐个候选名实测,避免再把字体名写错。
298
+
299
+ ### 2. 常规仿宋依赖 WPS 安装路径
300
+
301
+ `pdf_formatter.py` 只从 `/Applications/wpsoffice.app/...` 找 `FangS-SC.ttf`。
302
+ 未装 WPS 的机器会**静默退回宋体**,与「全文仿宋」规范不符。
303
+
304
+ → 当时把 `FangS-SC.ttf` 纳入 `fonts/` 随 skill 分发,查找顺序改为
305
+ 自带 → 用户字体目录 → WPS → 系统。
306
+
307
+ → **2026-09-25 再修正**:该字体是方正商业字体,授权允许在文档中使用,
308
+ **不允许再分发字体文件本身**。本插件改为**不随包分发任何字体**,
309
+ 只提供排版引擎;字体由用户通过 `DSH_CN_FANGSONG` / `DSH_CN_FONT_DIR`
310
+ 或系统字体目录自备。详见前文「字体:本插件不随包分发,需用户自备」。
311
+
312
+ ### 3. 不支持 Markdown 输入
313
+
314
+ 内容以 Markdown 写就时,整篇会被当作正文,层级全部丢失。
315
+
316
+ → 新增 `scripts/md_adapter.py`。
317
+
318
+ ### 4. 没有输出自检
319
+
320
+ 生成完不知道是否真的符合规范(页边距、字号、行距、字体、A4 尺寸)。
321
+
322
+ → 新增 `scripts/verify_output.py`,退出码可用于卡口。
323
+
324
+ ### 安装位置说明
325
+
326
+ skill 实际存放在 `~/.claude/skills/`,同时在 `~/.dsh/skills/` 建了软链接。
327
+ **两处都需要**:前者供 Claude Code 使用,后者供 DSH 自动加载。
328
+ 如新会话未自动加载本 skill,先检查 `~/.dsh/skills/chinese-doc-formatter` 链接是否存在。