feat: export core Hermes skills

This commit is contained in:
2026-07-15 02:45:56 +00:00
parent a028b63eda
commit 54711fee2a
308 changed files with 41310 additions and 1 deletions
@@ -0,0 +1,147 @@
# Strip numPr When Adding Manual Numbering to Auto-Numbered Paragraphs
## Problem (2026-07-01 反委托代发工资协议)
Original contract paragraphs have `<w:numPr>` with actual auto-numbering (e.g., `numId=3 → abstractNum decimal "%1." start=1`). When you insert manual "第X条" numbering as `w:ins` at paragraph start, OnlyOffice renders BOTH:
```
1. 第一条 乙方应严格按照... ← "1." is auto-numbering, "第一条" is your INS
```
This looks broken — two different numbering systems stacked.
## Root Cause
The paragraph's `pPr/numPr` tells the rendering engine to prepend an automatic decimal number. Your INS adds a second, manual number. They coexist independently.
Additionally, if the paragraph has `pPr/pPrChange` (tracking the old paragraph formatting), the old `numPr` inside `pPrChange` can ALSO render in markup view.
## Fix (two-step)
After inserting manual numbering INS elements, strip auto-numbering from ALL affected paragraphs:
```python
for idx in target_paragraph_indices:
p = paras[idx]
ppr = p.find(f'{WNS}pPr')
if ppr is not None:
# Step 1: Remove direct numPr
num_pr = ppr.find(f'{WNS}numPr')
if num_pr is not None:
ppr.remove(num_pr)
# Step 2: Remove numPr inside pPrChange (old formatting record)
ppr_change = ppr.find(f'{WNS}pPrChange')
if ppr_change is not None:
inner_ppr = ppr_change.find(f'{WNS}pPr')
if inner_ppr is not None:
inner_num = inner_ppr.find(f'{WNS}numPr')
if inner_num is not None:
inner_ppr.remove(inner_num)
```
## When This Applies
- You're converting a contract from auto-numbered clauses to manual "第X条" heading-style numbering
- The original .doc/.docx used Word's list numbering for clause structure
- You're adding "第一条 " etc. as INS at paragraph start
## Verification
After fix:
1. `pdftotext -layout` of OnlyOffice render should show NO stray "1." / "2." / "3." before your "第X条"
2. Accept-revisions preview should also be clean (no residual auto-numbers)
## Scenario B: Auto-Numbering Resets Across Tracked-Deleted Paragraphs (2026-07-01 反委托代发工资协议)
### Problem
When paragraphs with `numPr` auto-numbering are interspersed with **entirely deleted paragraphs** (all content in `w:del`), OnlyOffice's auto-number counter **resets to 1** after the deleted block. This makes continuous numbering impossible with `numPr` alone.
Example structure:
```
P6: numPr=1 INS content (clause 1) → renders "1."
P7: numPr=1 continuation → renders "2." (wrong if P7 shouldn't be numbered)
P8: numPr=1 ALL w:del → renders "3." with strikethrough
P9: numPr=1 ALL w:del → renders "4." with strikethrough
P10: numPr=1 INS content (clause 2) → renders "1." ← RESETS! Should be "2."
```
The auto-numbering engine counts visible (non-deleted) items in the `numId` sequence, but deleted paragraphs **break the continuity** in OnlyOffice's rendering.
### Solution: Convert to Manual Text Numbering
Strip `numPr` from ALL paragraphs and insert "N. " as `w:ins` text at paragraph start. This gives identical visual output ("1. 2. 3. ...") without depending on the broken auto-number counter.
```python
# Step 1: Strip ALL numPr (including inside pPrChange)
for i, p in enumerate(paragraphs):
pPr = p.find(f'{{{W}}}pPr')
if pPr is not None:
numPr = pPr.find(f'{{{W}}}numPr')
if numPr is not None:
pPr.remove(numPr)
for pPrChange in pPr.findall(f'{{{W}}}pPrChange'):
old_pPr = pPrChange.find(f'{{{W}}}pPr')
if old_pPr is not None:
old_numPr = old_pPr.find(f'{{{W}}}numPr')
if old_numPr is not None:
old_pPr.remove(old_numPr)
# Step 2: Insert "N. " as w:ins text for each clause paragraph
# Only number paragraphs that have VISIBLE content (not entirely w:del)
clause_map = {6: 1, 10: 2, 11: 3, ...} # para_index: clause_number
for para_idx, clause_num in clause_map.items():
p = paragraphs[para_idx]
# Build INS element with "N. " text
ins_elem = ET.Element(f'{{{W}}}ins')
ins_elem.set(f'{{{W}}}id', str(next_rev_id()))
ins_elem.set(f'{{{W}}}author', rev_author) # from existing INS in doc
ins_elem.set(f'{{{W}}}date', rev_date)
r_elem = ET.SubElement(ins_elem, f'{{{W}}}r')
# Clone rPr from existing runs for font consistency
rPr = get_run_rPr_from_paragraph(p)
if rPr is not None:
r_elem.append(copy.deepcopy(rPr))
t_elem = ET.SubElement(r_elem, f'{{{W}}}t')
t_elem.set('{http://www.w3.org/XML/1998/namespace}space', 'preserve')
t_elem.text = f"{clause_num}. "
# Insert after pPr
pPr = p.find(f'{{{W}}}pPr')
if pPr is not None:
p.insert(list(p).index(pPr) + 1, ins_elem)
else:
p.insert(0, ins_elem)
```
### When to Use This (vs Scenario A)
- **Scenario A** (above): You're CHANGING the numbering scheme (auto "1." → manual "第一条")
- **Scenario B** (this): You're KEEPING the same format ("1. 2. 3.") but converting from auto to manual because auto-numbering resets across w:del paragraphs
- **Trigger**: Original uses numPr auto-numbering + your edits create entirely-deleted paragraphs between numbered items → auto counter resets → switch to manual text
### Key Decision: Which Paragraphs to Number
Only number paragraphs that will be visible after accepting revisions:
- Paragraphs with ONLY `w:del` content → skip (they're deleted)
- Paragraphs that are continuations of the previous clause (no independent number) → skip
- New INS-only paragraphs (new clauses) → number them
- Rewritten paragraphs (mixed INS+DEL, first clause in sequence) → number them
### Verification
After conversion:
1. OnlyOffice render (x2t → PDF) should show continuous "1. 2. 3. ... 11." without resets
2. No stray auto-numbers from numPr remnants
3. Deleted paragraphs (entirely w:del) should NOT show any number
## Distinction from Existing Rules
- Rule 5 (A類 vs B類) talks about NEW clauses inheriting/stripping numPr
- Scenario A is EXISTING paragraphs where you're REPLACING their numbering scheme with a different format via INS
- Scenario B is EXISTING paragraphs where auto-numbering BREAKS due to tracked-deleted paragraphs, requiring conversion to same-format manual text
- numId=0 trap (Rule 5 sub-note) is about fake auto-numbering; BOTH scenarios here are about REAL auto-numbering that renders visible numbers