gongwen-skill 2.13.0 → 2.14.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/AGENTS.md +0 -2
- package/CHANGELOG.md +18 -0
- package/README.md +2 -2
- package/SKILL.md +2 -2
- package/dsh/index.js +1 -1
- package/engine/core/document/models.py +30 -0
- package/engine/core/document/ooxml_parser.py +39 -0
- package/engine/core/document/parser.py +25 -5
- package/engine/core/rules/checker.py +14 -1
- package/gongwen/__init__.py +1 -1
- package/gongwen/_legacy.py +55 -2
- package/gongwen/cli/content_cmds.py +3 -0
- package/package.json +2 -2
- package/prompts/usage-prompts.md +1 -1
- package/pyproject.toml +1 -1
- package/rules/official/_common.yaml +10 -0
package/AGENTS.md
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,24 @@
|
|
|
4
4
|
Licensed under the MIT License. See the LICENSE file for details.
|
|
5
5
|
-->
|
|
6
6
|
|
|
7
|
+
## v2.14.0 (2026-09-26)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **解析读取可见性(V2.14)**:文本框内容(`w:txbxContent`,公文红头/发文字号常承载于此)与修订追踪摘要(`w:ins`/`w:del`)正式纳入 DocumentModel(`textboxes` / `revisions` 字段),`parse --json` 结构化输出——此前两者在解析层静默丢失(文本框仅挂非 Pydantic 属性、修订因 python-docx 高层 API 不读 `w:ins` 包裹 run 而整体丢失)
|
|
11
|
+
- **文本框内容检查规则 CHK-TBX001**:检测到文本框但内容为空时提示(红头/发文字号可能缺失);无文本框的文档不触发,避免误报
|
|
12
|
+
- **check/optimize 读取可见性提示**:文档含修订(含作者与增删数)或存在空文本框时,非 JSON 路径显式打印提示,不再静默忽略;`optimize --json` 新增 `textboxes` / `revisions` 字段供 Agent 感知解析降级
|
|
13
|
+
- **未知公文类型显式警告**:check/optimize 对 `-t` 拼错类型不再静默回退 common 规则,打印警告并提示 list-types(发布前全功能测试发现)
|
|
14
|
+
- **新增测试**:`tests/test_read_visibility.py`(文本框入模型、修订摘要、JSON 序列化、普通文档默认值、提示输出、CHK-TBX001、reviewers_count 回归等 7 用例,本地)
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- **npm peer 依赖解析失败(P1,GitHub issue #1)**:`@deepseek-ai/dsh-tools` peer 下限由 `>=0.1.0` 修正为 `>=0.1.5-rc.3`。根因:该包在 npm 上仅发布 rc/alpha 预发布版本(latest tag = `0.0.1-rc.1`),而 npm semver 的预发布 tuple 规则使 `>=0.1.0`(无预发布比较器)无法匹配任何版本,导致 pnpm 安装报 `ERR_PNPM_NO_MATCHING_VERSION`;现对齐官方宿主配套版本(`@deepseek-ai/dsh-base ^0.1.5-rc.3` 传递提供的 dsh-tools)
|
|
18
|
+
- **optimize-content tracked 模式 NameError(P1,发布前全功能测试发现)**:`_run_tracked_mode` 打印「审稿角色」时引用从未赋值的 `reviewers_count`(O10 重构遗留),文档已生成但崩溃 rc=1;现从 `args.reviewers` 取值(full 默认 6 / quick 3),rc 恢复 0
|
|
19
|
+
- **SKILL.md 标题与对外展示名统一**:H1 由「公文文档格式化 Skill(GB/T 9704)」改为「公文全流程处理专家(GB/T 9704)」,三副本(根 / `.dsh/skills/gongwen-skill/SKILL.md` / `.dsh/skills/gongwen-skill.md`)已同步
|
|
20
|
+
- **AGENTS.md 尾部重复行清理**:删除重复的「内容由AI生成,仅供参考」一行
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- **README 下载量徽章动态化**:`Downloads-0` 硬编码徽章改为 PyPI 动态下载量徽章(`img.shields.io/pypi/dm/gongwen-skill`)
|
|
24
|
+
|
|
7
25
|
## v2.13.0 (2026-09-11)
|
|
8
26
|
|
|
9
27
|
### Added
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ Licensed under the MIT License. See the LICENSE file for details.
|
|
|
18
18
|

|
|
19
19
|

|
|
20
20
|

|
|
21
|
-

|
|
22
22
|
|
|
23
23
|
本 Skill 源自开源桌面项目 [AI 公文智能优化助手](https://github.com/linhut/document-ai-assistant),将其核心格式引擎抽取、剥离桌面端/数据库依赖后独立发行,支持公文的**模板建立、解析、规则检查、自动修复、内容优化、Markdown 转公文**全流程能力。同时原生集成 **DeepSeek Harness (DSH)** 技能系统,支持 DSH Agent 自动发现与加载。
|
|
24
24
|
|
|
@@ -30,7 +30,7 @@ Licensed under the MIT License. See the LICENSE file for details.
|
|
|
30
30
|
|------|------|------|
|
|
31
31
|
| 📋 列类型 | `list-types` | 列出 25 种支持的公文类型(新增主持词 host_speech;含新闻稿/讲话稿) |
|
|
32
32
|
| 🏗️ 模板生成 | `template` | 按类型生成 GB/T 9704 标准空白模板 |
|
|
33
|
-
| 🔍 解析 | `parse` | `.docx` → 结构化 DocumentModel |
|
|
33
|
+
| 🔍 解析 | `parse` | `.docx` → 结构化 DocumentModel(含文本框/修订摘要) |
|
|
34
34
|
| ✅ 格式检查 | `check` | 按国标检查,分级 P0/P1/P2(只读) |
|
|
35
35
|
| 🔧 格式修复 | `optimize` | 自动修复字体/字号/行距/页边距,输出合规文档;`--verify` 单命令闭环自动复查、P0 存在时退出码非 0;`--json` 结构化输出 |
|
|
36
36
|
| ✍️ **内容优化** | **`optimize-content`** | 内容润色:默认 **Word 原生修订+批注**(审阅面板逐条接受/拒绝),可选行内差异对比版;`--precheck` 预检 changes 与原文一致性、`--preset quick/full/review` 参数收敛 |
|
package/SKILL.md
CHANGED
|
@@ -19,7 +19,7 @@ metadata:
|
|
|
19
19
|
Licensed under the MIT License. See the LICENSE file for details.
|
|
20
20
|
-->
|
|
21
21
|
|
|
22
|
-
#
|
|
22
|
+
# 公文全流程处理专家(GB/T 9704)
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
@@ -900,7 +900,7 @@ python -m gongwen fix-common 文件.docx -o 成品.docx
|
|
|
900
900
|
|
|
901
901
|
| 命令 | 用途 | 最小用法 |
|
|
902
902
|
|------|------|---------|
|
|
903
|
-
| `parse` | .docx → 结构化 DocumentModel JSON | `python -m gongwen parse 公文.docx` |
|
|
903
|
+
| `parse` | .docx → 结构化 DocumentModel JSON(含文本框/修订摘要) | `python -m gongwen parse 公文.docx` |
|
|
904
904
|
| `check` | 按国标检查格式(只读,分级 P0/P1/P2) | `python -m gongwen check 公文.docx -t notice` |
|
|
905
905
|
| `audit` | 审计文档:检查删除线/加粗/AI 声明等痕迹 | `python -m gongwen audit 公文.docx` |
|
|
906
906
|
|
package/dsh/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// 公文全流程处理专家 - DSH plugin bridge (gongwen-skill, v2.
|
|
1
|
+
// 公文全流程处理专家 - DSH plugin bridge (gongwen-skill, v2.14.0+)
|
|
2
2
|
// (c) 2026 Jose AI (https://www.linhut.cn)
|
|
3
3
|
// https://github.com/linhut/gongwen-skill
|
|
4
4
|
// Licensed under the MIT License. See the LICENSE file for details.
|
|
@@ -122,6 +122,32 @@ class HeaderFooter(BaseModel):
|
|
|
122
122
|
has_page_number: bool = False # 是否包含页码域
|
|
123
123
|
|
|
124
124
|
|
|
125
|
+
# ---------------------------------------------------------------------------
|
|
126
|
+
# Read-visibility structures(V2.14:读取可见性)
|
|
127
|
+
# 公文红头/发文字号常承载于文本框(<w:txbxContent>),修订(<w:ins>/<w:del>)
|
|
128
|
+
# 是流转中的草稿核心信息——两者此前在解析层静默丢失,现正式纳入模型。
|
|
129
|
+
# ---------------------------------------------------------------------------
|
|
130
|
+
|
|
131
|
+
class TextBox(BaseModel):
|
|
132
|
+
"""文本框内容(红头、发文字号等常承载于文本框)。"""
|
|
133
|
+
index: int = 0
|
|
134
|
+
text: str = ""
|
|
135
|
+
paragraphs: list[str] = Field(default_factory=list)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class RevisionInfo(BaseModel):
|
|
139
|
+
"""文档修订追踪摘要(w:ins 新增 / w:del 删除)。"""
|
|
140
|
+
insert_count: int = 0
|
|
141
|
+
delete_count: int = 0
|
|
142
|
+
authors: list[str] = Field(default_factory=list)
|
|
143
|
+
inserted_snippets: list[str] = Field(default_factory=list) # 新增内容片段(前 5 条)
|
|
144
|
+
deleted_snippets: list[str] = Field(default_factory=list) # 删除内容片段(前 5 条)
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def has_revisions(self) -> bool:
|
|
148
|
+
return self.insert_count > 0 or self.delete_count > 0
|
|
149
|
+
|
|
150
|
+
|
|
125
151
|
# ---------------------------------------------------------------------------
|
|
126
152
|
# Page setup
|
|
127
153
|
# ---------------------------------------------------------------------------
|
|
@@ -170,6 +196,10 @@ class DocumentModel(BaseModel):
|
|
|
170
196
|
headers: list[HeaderFooter] = Field(default_factory=list)
|
|
171
197
|
footers: list[HeaderFooter] = Field(default_factory=list)
|
|
172
198
|
|
|
199
|
+
# V2.14:读取可见性——文本框内容与修订摘要(此前静默丢失)
|
|
200
|
+
textboxes: list[TextBox] = Field(default_factory=list)
|
|
201
|
+
revisions: RevisionInfo = Field(default_factory=RevisionInfo)
|
|
202
|
+
|
|
173
203
|
# Source file info
|
|
174
204
|
filename: Optional[str] = Field(default=None, exclude=True)
|
|
175
205
|
source_path: Optional[str] = Field(default=None, exclude=True)
|
|
@@ -156,3 +156,42 @@ class OOXMLParser:
|
|
|
156
156
|
def para_text_from_element(p_elem) -> str:
|
|
157
157
|
"""从 <w:p> 节点提取文本(NS4 修复:用 iter 遍历后代,与文本框解析一致)。"""
|
|
158
158
|
return ''.join(t.text or '' for t in p_elem.iter(f'{{{W}}}t'))
|
|
159
|
+
|
|
160
|
+
def parse_revisions(self, docx_path: str | Path) -> Dict[str, Any]:
|
|
161
|
+
"""
|
|
162
|
+
解析文档修订追踪(<w:ins> 新增 / <w:del> 删除)摘要。
|
|
163
|
+
|
|
164
|
+
V2.14:python-docx 高层 API 不读 w:ins 包裹的 run,导致修订内容在
|
|
165
|
+
解析层静默丢失——此处用 OOXML 树直接统计,让流转中的草稿修订可见。
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
dict: {insert_count, delete_count, authors[], inserted_snippets[], deleted_snippets[]}
|
|
169
|
+
"""
|
|
170
|
+
root = self._load_document_xml(docx_path)
|
|
171
|
+
authors: set[str] = set()
|
|
172
|
+
inserted: list[str] = []
|
|
173
|
+
deleted: list[str] = []
|
|
174
|
+
|
|
175
|
+
for ins in root.iter(f'{{{W}}}ins'):
|
|
176
|
+
a = ins.get(f'{{{W}}}author')
|
|
177
|
+
if a:
|
|
178
|
+
authors.add(a)
|
|
179
|
+
txt = ''.join(t.text or '' for t in ins.iter(f'{{{W}}}t'))
|
|
180
|
+
if txt.strip():
|
|
181
|
+
inserted.append(txt.strip())
|
|
182
|
+
|
|
183
|
+
for dl in root.iter(f'{{{W}}}del'):
|
|
184
|
+
a = dl.get(f'{{{W}}}author')
|
|
185
|
+
if a:
|
|
186
|
+
authors.add(a)
|
|
187
|
+
txt = ''.join(t.text or '' for t in dl.iter(f'{{{W}}}delText'))
|
|
188
|
+
if txt.strip():
|
|
189
|
+
deleted.append(txt.strip())
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
'insert_count': len(inserted),
|
|
193
|
+
'delete_count': len(deleted),
|
|
194
|
+
'authors': sorted(authors),
|
|
195
|
+
'inserted_snippets': inserted[:5],
|
|
196
|
+
'deleted_snippets': deleted[:5],
|
|
197
|
+
}
|
|
@@ -582,17 +582,37 @@ def parse_docx(file_path: Path | str) -> DocumentModel:
|
|
|
582
582
|
logger.info(f"Parsed: {len(paragraphs)} paragraphs, {len(tables)} tables, "
|
|
583
583
|
f"{len(headers)} headers, {len(footers)} footers")
|
|
584
584
|
|
|
585
|
-
# I7:
|
|
585
|
+
# I7/V2.14: 文本框(红头区域)内容正式入模型——此前仅挂非 Pydantic 属性,
|
|
586
|
+
# JSON 输出与 check/optimize 均不可见(静默丢失);现纳入 DocumentModel.textboxes
|
|
587
|
+
from engine.core.document.models import TextBox
|
|
586
588
|
try:
|
|
587
589
|
textboxes = ooxml.parse_textboxes(str(file_path))
|
|
590
|
+
model.textboxes = [
|
|
591
|
+
TextBox(index=tb.index, text=tb.text, paragraphs=tb.paragraphs)
|
|
592
|
+
for tb in textboxes
|
|
593
|
+
]
|
|
594
|
+
# 向后兼容 alias:仍挂到非标准属性(防外部模块引用)
|
|
595
|
+
object.__setattr__(model, '_textboxes', [tb.text for tb in textboxes])
|
|
596
|
+
object.__setattr__(model, '_textbox_paragraphs', [tb.paragraphs for tb in textboxes])
|
|
588
597
|
if textboxes:
|
|
589
|
-
object.__setattr__(model, '_textboxes', [tb.text for tb in textboxes])
|
|
590
|
-
object.__setattr__(model, '_textbox_paragraphs', [tb.paragraphs for tb in textboxes])
|
|
591
598
|
logger.info(f"Textboxes extracted: {len(textboxes)} (红头/文本框区域)")
|
|
592
|
-
else:
|
|
593
|
-
object.__setattr__(model, '_textboxes', [])
|
|
594
599
|
except Exception as e:
|
|
595
600
|
logger.debug(f"Textbox extraction skipped: {e}")
|
|
601
|
+
object.__setattr__(model, '_textboxes', [])
|
|
602
|
+
|
|
603
|
+
# V2.14: 修订追踪摘要(w:ins/w:del)——此前 python-docx 层静默丢弃
|
|
604
|
+
try:
|
|
605
|
+
rev = ooxml.parse_revisions(str(file_path))
|
|
606
|
+
model.revisions = type(model.revisions)(
|
|
607
|
+
insert_count=rev['insert_count'], delete_count=rev['delete_count'],
|
|
608
|
+
authors=rev['authors'],
|
|
609
|
+
inserted_snippets=rev['inserted_snippets'],
|
|
610
|
+
deleted_snippets=rev['deleted_snippets'],
|
|
611
|
+
)
|
|
612
|
+
if model.revisions.has_revisions:
|
|
613
|
+
logger.info(f"Revisions detected: {rev['insert_count']} ins / {rev['delete_count']} del")
|
|
614
|
+
except Exception as e:
|
|
615
|
+
logger.debug(f"Revision parse skipped: {e}")
|
|
596
616
|
|
|
597
617
|
# I7: 段落索引映射挂载(供批注锚定等下游使用)
|
|
598
618
|
object.__setattr__(model, '_para_index_map', para_index_map)
|
|
@@ -861,7 +861,20 @@ def _check_header_field(model, rule_id: str, severity: str, name: str,
|
|
|
861
861
|
field_name = field_path.split(".", 1)[1] if "." in field_path else ""
|
|
862
862
|
|
|
863
863
|
try:
|
|
864
|
-
if field_name == "
|
|
864
|
+
if field_name == "textbox":
|
|
865
|
+
# V2.14:文本框内容可见性(CHK-TBX001)——红头/发文字号常承载于文本框;
|
|
866
|
+
# 文本框存在但为空 → 提示缺失;无文本框 → 不报(避免误报)
|
|
867
|
+
tb_list = getattr(model, 'textboxes', None) or []
|
|
868
|
+
empty = [tb for tb in tb_list if not (tb.text or '').strip()]
|
|
869
|
+
if tb_list and empty:
|
|
870
|
+
issues.append(CheckIssue(
|
|
871
|
+
rule_id=rule_id, check_type="content", severity=severity,
|
|
872
|
+
name=name, location=f"textbox:{empty[0].index}",
|
|
873
|
+
original_text="",
|
|
874
|
+
suggested_fix=expected,
|
|
875
|
+
reason=message or f"检测到 {len(empty)} 个空文本框(红头/发文字号可能缺失)",
|
|
876
|
+
))
|
|
877
|
+
elif field_name == "doc_number":
|
|
865
878
|
# 令号模式:〔2026〕1号 / 第1号 / (2026)1号 / 2026年1号 等
|
|
866
879
|
all_text = ''.join((getattr(p, 'text', '') or '') for p in model.paragraphs)
|
|
867
880
|
has_doc_number = re.search(
|
package/gongwen/__init__.py
CHANGED
package/gongwen/_legacy.py
CHANGED
|
@@ -16,7 +16,7 @@ from gongwen.cli.helpers import (
|
|
|
16
16
|
parse_config_overrides as _parse_config_overrides,
|
|
17
17
|
load_rules_with_overrides as _load_rules_with_overrides,
|
|
18
18
|
)
|
|
19
|
-
__version__ = "2.
|
|
19
|
+
__version__ = "2.14.0"
|
|
20
20
|
# 版本号应与 gongwen/__init__.py 保持一致,每次发版同步更新
|
|
21
21
|
"""
|
|
22
22
|
中文公文全流程处理专家 —— 基于 GB/T 9704《党政机关公文格式》国家标准。
|
|
@@ -137,7 +137,12 @@ def cmd_parse(args):
|
|
|
137
137
|
# --json:强制完整 JSON 到 stdout(即使指定了 -o),Agent 可统一解析
|
|
138
138
|
print(text)
|
|
139
139
|
elif args.output:
|
|
140
|
-
|
|
140
|
+
parts = [f"{len(model.paragraphs)} 段落", f"{len(model.tables)} 表格"]
|
|
141
|
+
if model.textboxes:
|
|
142
|
+
parts.append(f"{len(model.textboxes)} 文本框")
|
|
143
|
+
if model.revisions.has_revisions:
|
|
144
|
+
parts.append(f"修订 {model.revisions.insert_count}+/{model.revisions.delete_count}-")
|
|
145
|
+
print(f"已解析: {args.output} ({', '.join(parts)})")
|
|
141
146
|
else:
|
|
142
147
|
print(text)
|
|
143
148
|
|
|
@@ -157,6 +162,9 @@ def cmd_check(args):
|
|
|
157
162
|
if args.severity:
|
|
158
163
|
issues = [i for i in issues if i.severity == args.severity]
|
|
159
164
|
|
|
165
|
+
# V2.14:未知公文类型显式警告(拼错类型不再静默回退 common)
|
|
166
|
+
_warn_unknown_doc_type(args.doc_type)
|
|
167
|
+
|
|
160
168
|
if args.json:
|
|
161
169
|
results = [{
|
|
162
170
|
"severity": i.severity, "rule_id": i.rule_id, "name": i.name,
|
|
@@ -173,6 +181,38 @@ def cmd_check(args):
|
|
|
173
181
|
for i in issues:
|
|
174
182
|
print(f" [{i.severity}] {i.rule_id}: {i.name} @ {i.location}")
|
|
175
183
|
print(f" 实际: {i.original_text} → 期望: {i.suggested_fix}")
|
|
184
|
+
# V2.14:读取可见性提示——文本框/修订不静默忽略
|
|
185
|
+
_print_read_visibility_hints(model)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _print_read_visibility_hints(model):
|
|
189
|
+
"""V2.14:解析层读取可见性提示。
|
|
190
|
+
|
|
191
|
+
文本框(红头/发文字号)与修订(w:ins/w:del)是公文流转的高频信息载体,
|
|
192
|
+
此前在解析层静默丢失;现在解析可见,这里向用户显式告知降级/注意事项。
|
|
193
|
+
"""
|
|
194
|
+
if model.textboxes:
|
|
195
|
+
empty = [tb for tb in model.textboxes if not (tb.text or '').strip()]
|
|
196
|
+
if empty:
|
|
197
|
+
print(f" [提示] 检测到 {len(empty)} 个空文本框(红头/发文字号可能缺失)")
|
|
198
|
+
if model.revisions.has_revisions:
|
|
199
|
+
authors = '、'.join(model.revisions.authors) or '未知'
|
|
200
|
+
print(f" [提示] 文档含修订 {model.revisions.insert_count} 处新增 / "
|
|
201
|
+
f"{model.revisions.delete_count} 处删除(作者: {authors});"
|
|
202
|
+
f"检查基于当前可见内容,建议先接受/拒绝修订后再处理")
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def _warn_unknown_doc_type(doc_type):
|
|
206
|
+
"""V2.14:未知公文类型显式警告(此前静默回退 common 规则,拼错类型难发现)。"""
|
|
207
|
+
if not doc_type:
|
|
208
|
+
return None
|
|
209
|
+
from engine.core.rules.loader import list_available_types
|
|
210
|
+
known = list_available_types()
|
|
211
|
+
if doc_type not in known:
|
|
212
|
+
print(f" ⚠️ 警告: 未知公文类型「{doc_type}」,已回退使用通用规则"
|
|
213
|
+
f"(python -m gongwen list-types 查看 {len(known)} 类)")
|
|
214
|
+
return doc_type
|
|
215
|
+
return None
|
|
176
216
|
|
|
177
217
|
|
|
178
218
|
def cmd_optimize(args):
|
|
@@ -199,6 +239,9 @@ def cmd_optimize(args):
|
|
|
199
239
|
# 确定文档类型(共享辅助函数,优先 -t 参数,其次文件名推断)
|
|
200
240
|
doc_type, type_source = _detect_doc_type(input_path, args.doc_type)
|
|
201
241
|
|
|
242
|
+
# V2.14:未知公文类型显式警告(拼错类型不再静默回退 common)
|
|
243
|
+
_warn_unknown_doc_type(doc_type)
|
|
244
|
+
|
|
202
245
|
# 解析文档并检查
|
|
203
246
|
model = parse_docx(str(input_path))
|
|
204
247
|
issues = engine.check(model, doc_type)
|
|
@@ -232,6 +275,14 @@ def cmd_optimize(args):
|
|
|
232
275
|
"verify_executed": False, "verify_passed": False,
|
|
233
276
|
"verify_p0": None, "verify_p1": None, "verify_p2": None,
|
|
234
277
|
"verify_error": None,
|
|
278
|
+
# V2.14:读取可见性(文本框/修订)——供 Agent 感知解析降级
|
|
279
|
+
"textboxes": len(model.textboxes),
|
|
280
|
+
"revisions": ({
|
|
281
|
+
"has": True,
|
|
282
|
+
"insert": model.revisions.insert_count,
|
|
283
|
+
"delete": model.revisions.delete_count,
|
|
284
|
+
"authors": model.revisions.authors,
|
|
285
|
+
} if model.revisions.has_revisions else None),
|
|
235
286
|
}
|
|
236
287
|
|
|
237
288
|
# === 预览信息(--json 时不打印人类文本)===
|
|
@@ -249,6 +300,8 @@ def cmd_optimize(args):
|
|
|
249
300
|
print(f" - {i.name} @ {i.location}")
|
|
250
301
|
if layout_parts:
|
|
251
302
|
print(f"🎨 版式注入: {', '.join(layout_parts)}")
|
|
303
|
+
# V2.14:读取可见性提示(文本框/修订不静默忽略)
|
|
304
|
+
_print_read_visibility_hints(model)
|
|
252
305
|
|
|
253
306
|
if not args.apply:
|
|
254
307
|
if not is_json:
|
|
@@ -577,6 +577,9 @@ def _run_tracked_mode(args, changes, style_name, style_prompt, content_rules, do
|
|
|
577
577
|
authors = sorted({s.author for s in suggestions})
|
|
578
578
|
print(f" 审阅者: {', '.join(authors)}(可按审阅者筛选)")
|
|
579
579
|
# S2 修复:审稿角色显示映射(默认 6 角色不再误判为 3 角色)
|
|
580
|
+
# V2.14 修复:reviewers_count 此前从未赋值(O10 重构遗留 NameError,
|
|
581
|
+
# 导致 tracked 模式生成文档后 rc=1)——从 args.reviewers 取(full 默认 6、quick 3)
|
|
582
|
+
reviewers_count = int(getattr(args, 'reviewers', 6) or 6)
|
|
580
583
|
_role_display = {
|
|
581
584
|
3: "精简版(3角色)",
|
|
582
585
|
5: "完整版(5角色)",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gongwen-skill",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.0",
|
|
4
4
|
"description": "公文全流程处理专家 - GB/T 9704 格式检查/修复/内容优化/模板生成/版式注入",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dsh/index.js",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@deepseek-ai/cordis": ">=4",
|
|
49
|
-
"@deepseek-ai/dsh-tools": ">=0.1.
|
|
49
|
+
"@deepseek-ai/dsh-tools": ">=0.1.5-rc.3",
|
|
50
50
|
"@deepseek-ai/schemastery": ">=3.18.0",
|
|
51
51
|
"@deepseek-ai/dsh-client-ui-settings-plugins": ">=0.1.2-rc.1"
|
|
52
52
|
},
|
package/prompts/usage-prompts.md
CHANGED
package/pyproject.toml
CHANGED
|
@@ -501,6 +501,16 @@ check_rules:
|
|
|
501
501
|
expected: true
|
|
502
502
|
message: "整段加粗不符合公文规范,通常仅首句或点题词需要加粗"
|
|
503
503
|
|
|
504
|
+
# --- 文本框内容检查 (CHK-TBX001, V2.14) ---
|
|
505
|
+
# 公文红头/发文字号常承载于文本框(w:txbxContent);文本框存在但内容为空
|
|
506
|
+
# 说明红头区域有缺失。仅"检测到文本框"时触发,无文本框的文档不报。
|
|
507
|
+
- id: CHK-TBX001
|
|
508
|
+
name: "文本框内容检查"
|
|
509
|
+
severity: P2
|
|
510
|
+
field: header.textbox
|
|
511
|
+
expected: "文本框内容非空"
|
|
512
|
+
message: "检测到文本框但内容为空(红头/发文字号可能在文本框中缺失)"
|
|
513
|
+
|
|
504
514
|
# --- 主送机关格式检查 (CHK-C026) ---
|
|
505
515
|
- id: CHK-C026
|
|
506
516
|
name: "主送机关格式检查"
|