dsh-office-kit 0.4.2 → 0.4.4
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/assets/skills/excel-live-control/SKILL.md +119 -152
- package/assets/skills/excel-live-control/domain_guidance/financial_models.md +42 -58
- package/assets/skills/excel-live-control/domain_guidance/healthcare.md +36 -42
- package/assets/skills/excel-live-control/domain_guidance/marketing_advertising.md +33 -34
- package/assets/skills/excel-live-control/domain_guidance/scientific_research.md +34 -36
- package/assets/skills/excel-live-control/references/office-automation.md +127 -153
- package/assets/skills/excel-live-control/references/read_only_qna.md +40 -45
- package/assets/skills/excel-live-control/style_guidelines.md +56 -64
- package/assets/skills/excel-live-control/workflows/create_workflows.md +40 -47
- package/assets/skills/excel-live-control/workflows/edit_workflows.md +37 -45
- package/assets/skills/office-documents/SKILL.md +24 -60
- package/assets/skills/office-documents/examples/end_to_end_smoke_test.md +5 -5
- package/assets/skills/office-documents/ooxml/comments.md +8 -8
- package/assets/skills/office-documents/ooxml/hyperlinks_and_fields.md +10 -10
- package/assets/skills/office-documents/ooxml/rels_and_content_types.md +7 -7
- package/assets/skills/office-documents/ooxml/tracked_changes.md +12 -12
- package/assets/skills/office-documents/references/docx-structure.md +11 -13
- package/assets/skills/office-documents/references/template-elicitation.md +11 -13
- package/assets/skills/office-documents/references/writing-quality.md +20 -20
- package/assets/skills/office-documents/scripts/add_tracked_replacements.py +4 -3
- package/assets/skills/office-documents/scripts/docx_kit.py +68 -27
- package/assets/skills/office-documents/scripts/heading_audit.py +3 -4
- package/assets/skills/office-documents/scripts/internal_nav.py +3 -1
- package/assets/skills/office-documents/scripts/merge_docx_append.py +104 -0
- package/assets/skills/office-documents/scripts/table_geometry.py +13 -3
- package/assets/skills/office-documents/scripts/watermark_add.py +6 -5
- package/assets/skills/office-documents/scripts/watermark_audit_remove.py +6 -4
- package/assets/skills/office-documents/tasks/accessibility_a11y.md +16 -22
- package/assets/skills/office-documents/tasks/captions_crossrefs.md +23 -26
- package/assets/skills/office-documents/tasks/clean_tracked_changes.md +17 -22
- package/assets/skills/office-documents/tasks/comments_manage.md +9 -11
- package/assets/skills/office-documents/tasks/compare_diff.md +10 -16
- package/assets/skills/office-documents/tasks/create_edit.md +14 -16
- package/assets/skills/office-documents/tasks/equations.md +17 -28
- package/assets/skills/office-documents/tasks/fields_update.md +14 -16
- package/assets/skills/office-documents/tasks/fixtures_edge_cases.md +19 -33
- package/assets/skills/office-documents/tasks/footnotes_endnotes.md +12 -14
- package/assets/skills/office-documents/tasks/forms_content_controls.md +16 -20
- package/assets/skills/office-documents/tasks/headings_numbering.md +17 -22
- package/assets/skills/office-documents/tasks/images_figures.md +15 -25
- package/assets/skills/office-documents/tasks/multi_doc_merge.md +13 -23
- package/assets/skills/office-documents/tasks/navigation_internal_links.md +18 -21
- package/assets/skills/office-documents/tasks/privacy_scrub_metadata.md +16 -22
- package/assets/skills/office-documents/tasks/protection_restrict_editing.md +19 -21
- package/assets/skills/office-documents/tasks/read_review.md +9 -20
- package/assets/skills/office-documents/tasks/redaction_anonymization.md +17 -18
- package/assets/skills/office-documents/tasks/sections_layout.md +16 -23
- package/assets/skills/office-documents/tasks/style_lint_normalize.md +18 -22
- package/assets/skills/office-documents/tasks/tables_spreadsheets.md +21 -31
- package/assets/skills/office-documents/tasks/templates_style_packs.md +17 -21
- package/assets/skills/office-documents/tasks/toc_workflow.md +10 -14
- package/assets/skills/office-documents/tasks/verify_render.md +11 -23
- package/assets/skills/office-documents/tasks/watermarks_background.md +10 -14
- package/assets/skills/office-documents/troubleshooting/libreoffice_headless.md +6 -6
- package/assets/skills/office-documents/troubleshooting/run_splitting.md +12 -12
- package/assets/skills/office-pdf/SKILL.md +36 -51
- package/assets/skills/office-pdf/references/form-fields.md +20 -20
- package/assets/skills/office-pdf/references/geometry.md +10 -10
- package/assets/skills/office-pdf/references/layout-quality.md +13 -13
- package/assets/skills/office-pdf/references/limits.md +12 -56
- package/assets/skills/office-pdf/tasks/annotations.md +5 -5
- package/assets/skills/office-pdf/tasks/create.md +6 -9
- package/assets/skills/office-pdf/tasks/edit-pages.md +14 -14
- package/assets/skills/office-pdf/tasks/forms.md +15 -15
- package/assets/skills/office-pdf/tasks/read.md +9 -9
- package/assets/skills/office-pdf/tasks/redact.md +18 -18
- package/assets/skills/office-pdf/tasks/stamp.md +10 -10
- package/assets/skills/office-presentations/SKILL.md +71 -91
- package/assets/skills/office-presentations/container_tools/preview_render.py +4 -1
- package/assets/skills/office-presentations/container_tools/render_slides.py +1 -1
- package/assets/skills/office-presentations/domain_guidance/finance.md +16 -16
- package/assets/skills/office-presentations/recipes/README.md +24 -35
- package/assets/skills/office-presentations/recipes/autolayout.md +12 -13
- package/assets/skills/office-presentations/recipes/connectors.md +11 -12
- package/assets/skills/office-presentations/recipes/images.md +11 -12
- package/assets/skills/office-presentations/recipes/master-and-layouts.md +18 -18
- package/assets/skills/office-presentations/recipes/native-charts.md +8 -8
- package/assets/skills/office-presentations/recipes/rich-text-runs.md +13 -13
- package/assets/skills/office-presentations/recipes/speaker-notes.md +7 -7
- package/assets/skills/office-presentations/recipes/tables.md +14 -14
- package/assets/skills/office-presentations/recipes/textbox-at-coordinate.md +9 -9
- package/assets/skills/office-presentations/recipes/theme-tokens.md +7 -8
- package/assets/skills/office-presentations/references/authoring-workflow.md +38 -43
- package/assets/skills/office-presentations/references/finalization.md +10 -12
- package/assets/skills/office-presentations/references/native-bullets.md +14 -18
- package/assets/skills/office-presentations/references/native-evidence.md +18 -32
- package/assets/skills/office-presentations/references/style-guidelines.md +27 -32
- package/assets/skills/office-presentations/references/templates.md +31 -60
- package/assets/skills/office-presentations/routing/google_slides.md +4 -4
- package/assets/skills/office-presentations/tasks/apply-annotations.md +17 -17
- package/assets/skills/office-presentations/tasks/charts-tables-notes.md +20 -23
- package/assets/skills/office-presentations/tasks/create-deck.md +19 -19
- package/assets/skills/office-presentations/tasks/edit-deck.md +14 -16
- package/assets/skills/office-presentations/tasks/inspect-and-verify.md +31 -34
- package/assets/skills/office-presentations/tasks/template-following.md +23 -28
- package/assets/skills/office-spreadsheets/SKILL.md +32 -39
- package/assets/skills/office-spreadsheets/recipes/charts.md +8 -26
- package/assets/skills/office-spreadsheets/recipes/conditional-formats.md +9 -26
- package/assets/skills/office-spreadsheets/recipes/data-tables.md +7 -23
- package/assets/skills/office-spreadsheets/recipes/named-ranges.md +8 -21
- package/assets/skills/office-spreadsheets/recipes/number-formats.md +7 -23
- package/assets/skills/office-spreadsheets/recipes/sparklines.md +7 -20
- package/assets/skills/office-spreadsheets/references/charts.md +15 -34
- package/assets/skills/office-spreadsheets/references/domain/financial-models.md +10 -25
- package/assets/skills/office-spreadsheets/references/domain/healthcare.md +8 -19
- package/assets/skills/office-spreadsheets/references/domain/marketing.md +8 -22
- package/assets/skills/office-spreadsheets/references/domain/research.md +8 -19
- package/assets/skills/office-spreadsheets/references/formula-patterns.md +20 -50
- package/assets/skills/office-spreadsheets/references/style-guidelines.md +19 -44
- package/assets/skills/office-spreadsheets/references/workbook-structure.md +12 -35
- package/assets/skills/office-spreadsheets/routing/google-sheets.md +11 -26
- package/assets/skills/office-spreadsheets/tasks/analyze-workbook.md +10 -25
- package/assets/skills/office-spreadsheets/tasks/annotations.md +12 -30
- package/assets/skills/office-spreadsheets/tasks/create-workbook.md +5 -5
- package/assets/skills/office-spreadsheets/tasks/diff-workbooks.md +2 -2
- package/assets/skills/office-spreadsheets/tasks/edit-workbook.md +5 -5
- package/assets/skills/office-spreadsheets/tasks/inspect-workbook.md +9 -9
- package/assets/skills/office-spreadsheets/tasks/recalc-and-check.md +10 -30
- package/assets/skills/shared/annotation-recipes.md +98 -120
- package/assets/skills/shared/common-workflow.md +70 -80
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/python/office_cli.py +38 -4
|
@@ -1,64 +1,54 @@
|
|
|
1
|
-
# Tables and
|
|
1
|
+
# Tables and layout geometry
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
A table's geometry is three things that must agree: the grid (`w:tblGrid`, one `w:gridCol` per column), the table width (`w:tblW`), and each cell width (`w:tcW`). When they disagree Word shows a table wider than the text block or columns that jump on the first edit.
|
|
3
|
+
Table geometry is three things that must agree: the grid (`w:tblGrid`, one `w:gridCol` per column), the table width (`w:tblW`) and each cell width (`w:tcW`). When they disagree, Word shows a table wider than the text block, or columns that jump on the first edit.
|
|
6
4
|
|
|
7
5
|
## Create
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
"<python>" "<cli>" docx create --spec "<spec.json>" --out "<out.docx>"
|
|
11
|
-
```
|
|
7
|
+
Use `docx create --spec` with a table block:
|
|
12
8
|
|
|
13
9
|
```json
|
|
14
|
-
{
|
|
15
|
-
"type": "table",
|
|
16
|
-
"headers": ["Region", "Revenue", "Growth"],
|
|
17
|
-
"rows": [["EMEA", "4.1M", "12%"], ["APAC", "3.2M", "9%"]],
|
|
18
|
-
"style": "Table Grid"
|
|
19
|
-
}
|
|
10
|
+
{ "type": "table", "headers": ["Region", "Q1"], "rows": [["North", "10"]], "style": "Table Grid" }
|
|
20
11
|
```
|
|
21
12
|
|
|
22
|
-
Header cells are bold.
|
|
13
|
+
Header cells are bold. To repeat the header row on every page:
|
|
23
14
|
|
|
24
15
|
```bash
|
|
25
|
-
"<python>" "<skill>/scripts/a11y_audit.py" "<out.docx>" --fix_table_headers first_row --out "<out-fixed.docx
|
|
16
|
+
"<python>" "<skill>/scripts/a11y_audit.py" "<out.docx>" --fix_table_headers first_row --out "<out-fixed.docx"
|
|
26
17
|
```
|
|
27
18
|
|
|
19
|
+
That writes `w:tblHeader` on row 1.
|
|
20
|
+
|
|
28
21
|
## Inspect and fix geometry
|
|
29
22
|
|
|
30
23
|
```bash
|
|
31
24
|
"<python>" "<skill>/scripts/table_geometry.py" "<file.docx>"
|
|
32
|
-
"<python>" "<skill>/scripts/table_geometry.py" "<file.docx>" --fix --out "<file-fixed.docx
|
|
25
|
+
"<python>" "<skill>/scripts/table_geometry.py" "<file.docx>" --fix --out "<file-fixed.docx"
|
|
33
26
|
```
|
|
34
27
|
|
|
35
|
-
The audit reports `tblW`, layout mode, every grid column in twips
|
|
36
|
-
|
|
37
|
-
Text width on Letter with 1in margins is 9360 twips — that is the number a full-width table should total.
|
|
28
|
+
The audit reports `tblW`, the layout mode, every grid column in twips with their sum, and the narrowest and widest cell. `--fix` writes a fixed-layout table at the text width (page width minus margins), rescales the grid proportionally and rewrites each `tcW`, including `gridSpan`. On Letter with 1in margins the text width is 9360 twips.
|
|
38
29
|
|
|
39
|
-
##
|
|
30
|
+
## Move data between formats
|
|
40
31
|
|
|
41
32
|
```bash
|
|
42
|
-
"<python>" "<skill>/scripts/docx_table_to_csv.py" "<file.docx>" --table_index 0 --out "<table.csv
|
|
33
|
+
"<python>" "<skill>/scripts/docx_table_to_csv.py" "<file.docx>" --table_index 0 --out "<table.csv"
|
|
43
34
|
"<python>" "<skill>/scripts/xlsx_to_docx_table.py" "<book.xlsx>" --sheet Revenue --out "<table.docx>" --title "Revenue by region"
|
|
44
35
|
```
|
|
45
36
|
|
|
46
|
-
|
|
37
|
+
`docx_table_to_csv.py` flattens the table, expands horizontal spans and repeats vertically merged values. `xlsx_to_docx_table.py` writes a bold header row plus `w:tblHeader`; it is the route for "put this spreadsheet in the report", not a screenshot or an embedded object.
|
|
47
38
|
|
|
48
39
|
## Design
|
|
49
40
|
|
|
50
|
-
- Bold header row, light grey `#D9D9D9` borders, no shading
|
|
51
|
-
- Numeric
|
|
52
|
-
- Two or three columns
|
|
53
|
-
- Caption above the table (`tasks/captions_crossrefs.md`)
|
|
54
|
-
- Avoid vertical merges: they look fine in the file and confuse every downstream reader.
|
|
41
|
+
- Bold header row, light grey `#D9D9D9` borders, no shading in the body.
|
|
42
|
+
- Numeric right-aligned, text left-aligned, thousands separators inside the cells.
|
|
43
|
+
- Two or three prose columns at most. A wide table wants landscape through a section break (`tasks/sections_layout.md`), not a smaller font.
|
|
44
|
+
- Caption above the table (`tasks/captions_crossrefs.md`). Avoid vertical merges.
|
|
55
45
|
|
|
56
46
|
## Verify
|
|
57
47
|
|
|
58
|
-
Render
|
|
48
|
+
Render the page: nothing past the right margin, header row intact, no row split across pages, last column not truncated. A table that fits in XML but overflows the page is a real defect that only the render shows.
|
|
59
49
|
|
|
60
50
|
## Pitfalls
|
|
61
51
|
|
|
62
|
-
- A table inside a
|
|
63
|
-
- `autofit` is a request, not a guarantee
|
|
64
|
-
- Cell margins default to 108 twips
|
|
52
|
+
- A table inside a cell inherits the cell width, so check the outer table first.
|
|
53
|
+
- `autofit` is a request, not a guarantee.
|
|
54
|
+
- Cell margins default to 108 twips of padding.
|
|
@@ -1,53 +1,49 @@
|
|
|
1
1
|
# Templates and style packs
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
A `.dotx` is a `.docx` whose package is a template: `styles.xml` defines the look, `numbering.xml` defines lists, and the body is empty. Copying the body would import placeholder text; what you actually need is the styles part, the numbering definitions they reference, and the theme.
|
|
3
|
+
A `.dotx` is a `.docx` whose package is a template: `styles.xml` defines the look, `numbering.xml` defines lists, the body is empty. What you need is the styles part, the numbering definitions they reference, and the theme. Copying the body imports placeholder text.
|
|
6
4
|
|
|
7
5
|
## Ask before guessing
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
Never invent a house style. Get heading fonts and sizes, body font and size, accent colour, margins, table style, and any logo or cover requirement. `references/template-elicitation.md` holds the question set.
|
|
10
8
|
|
|
11
|
-
## Apply
|
|
9
|
+
## Apply
|
|
12
10
|
|
|
13
11
|
```bash
|
|
14
|
-
"<python>" "<skill>/scripts/apply_template_styles.py" --template "<house.dotx>" --target "<draft.docx>" --out "<draft-styled.docx
|
|
12
|
+
"<python>" "<skill>/scripts/apply_template_styles.py" --template "<house.dotx>" --target "<draft.docx>" --out "<draft-styled.docx"
|
|
15
13
|
```
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
Merges style definitions by `styleId` (replacing same-id, appending missing, taking the template's `docDefaults`) and copies `numbering.xml` with its relationship and content-type override. The target's body is untouched.
|
|
18
16
|
|
|
19
|
-
Then
|
|
17
|
+
Then normalise so direct formatting does not override the imported styles:
|
|
20
18
|
|
|
21
19
|
```bash
|
|
22
|
-
"<python>" "<skill>/scripts/style_normalize.py" "<draft-styled.docx>" --out "<draft-final.docx
|
|
20
|
+
"<python>" "<skill>/scripts/style_normalize.py" "<draft-styled.docx>" --out "<draft-final.docx" --clear_paragraph_format
|
|
23
21
|
```
|
|
24
22
|
|
|
25
23
|
## Restyle without a template
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
Set values on styles, not on runs:
|
|
28
26
|
|
|
29
|
-
```
|
|
30
|
-
"<python>" - <<'PY'
|
|
27
|
+
```python
|
|
31
28
|
from docx import Document
|
|
32
29
|
from docx.shared import Pt, RGBColor
|
|
30
|
+
|
|
33
31
|
d = Document(r"<draft.docx>")
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
normal.font.size = Pt(11)
|
|
32
|
+
d.styles["Normal"].font.name = "Calibri"
|
|
33
|
+
d.styles["Normal"].font.size = Pt(11)
|
|
37
34
|
for level, size in ((1, 18), (2, 14), (3, 12)):
|
|
38
35
|
style = d.styles[f"Heading {level}"]
|
|
39
36
|
style.font.size = Pt(size)
|
|
40
37
|
style.font.color.rgb = RGBColor(0, 0, 0)
|
|
41
|
-
d.save(r"<draft-
|
|
42
|
-
PY
|
|
38
|
+
d.save(r"<draft-restyled.docx>")
|
|
43
39
|
```
|
|
44
40
|
|
|
45
41
|
## Verify
|
|
46
42
|
|
|
47
|
-
Render and compare
|
|
43
|
+
Render and compare page by page with the template's own preview: heading sizes, body leading, margins, table borders. A style that looks right in the pane but wrong on the page usually has a leftover direct-formatting run — run the lint (`tasks/style_lint_normalize.md`).
|
|
48
44
|
|
|
49
45
|
## Pitfalls
|
|
50
46
|
|
|
51
|
-
- A template applied over content that references missing styles produces the fallback look, not an error; run `style_lint.py
|
|
52
|
-
- Themes (`word/theme/theme1.xml`) carry fonts and accent colours
|
|
53
|
-
- Keeping the template's `numbering.xml` without its
|
|
47
|
+
- A template applied over content that references missing styles produces the fallback look, not an error; run `style_lint.py`.
|
|
48
|
+
- Themes (`word/theme/theme1.xml`) carry fonts and accent colours, so theme-font styles change with the theme.
|
|
49
|
+
- Keeping the template's `numbering.xml` without its abstractNum ids makes lists share one counter.
|
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
# Table of contents
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A TOC is a `TOC` field: Word fills it on recalculation and the file stores the last result. A hand-typed list looks identical, then goes wrong on the first edit.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## Insert
|
|
5
|
+
Insert:
|
|
8
6
|
|
|
9
7
|
```bash
|
|
10
8
|
"<python>" "<skill>/scripts/insert_toc.py" "<file.docx>" --out "<file-toc.docx>" --levels 1-3
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
The script
|
|
11
|
+
The script fills a placeholder paragraph containing `[[TOC]]` (override with `--placeholder`); with no placeholder it inserts the field at the start of the body. It writes `TOC \o "1-3" \h \z \u`, sets `w:updateFields`, and leaves a short cached hint so the page is not blank before recalculation.
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
Every heading you want listed must use a heading style. `heading_audit.py` finds hand-formatted headings that the TOC silently skips.
|
|
16
14
|
|
|
17
15
|
## Rebuild after edits
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
## Static contents list
|
|
17
|
+
The cached list goes stale after a structural edit. Ask the user to update the field in Word (right-click → Update Field), or delete the field paragraphs and re-run `insert_toc.py`. Do not freeze a TOC with `fields_materialize.py`.
|
|
22
18
|
|
|
23
|
-
|
|
19
|
+
For a fixed PDF export or a hand-built template contents page, generate a static list with `internal_nav.py` instead:
|
|
24
20
|
|
|
25
21
|
```bash
|
|
26
22
|
"<python>" "<skill>/scripts/internal_nav.py" "<file.docx>" --out "<file-nav.docx>" --levels 1 2
|
|
@@ -30,10 +26,10 @@ See `tasks/navigation_internal_links.md`.
|
|
|
30
26
|
|
|
31
27
|
## Verify
|
|
32
28
|
|
|
33
|
-
Render the first pages
|
|
29
|
+
Render the first pages. A line of grey hint text means the renderer never recalculated the field; old headings mean it rendered before the update. Say which happened instead of claiming the contents are correct.
|
|
34
30
|
|
|
35
31
|
## Pitfalls
|
|
36
32
|
|
|
37
|
-
- TOC entries come from outline levels, not from text that
|
|
38
|
-
- A TOC
|
|
39
|
-
- Level 4
|
|
33
|
+
- TOC entries come from outline levels, not from text that looks like a heading.
|
|
34
|
+
- A TOC in a header or text box does not work — body only.
|
|
35
|
+
- Level 4 and deeper are excluded unless you widen `--levels`.
|
|
@@ -1,50 +1,38 @@
|
|
|
1
1
|
# Visual verification
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Render
|
|
3
|
+
See the pages before the user does. A document that parses and a document that looks right are different claims.
|
|
6
4
|
|
|
7
5
|
```bash
|
|
8
6
|
"<python>" "<cli>" docx render --input "<file.docx>" --out-dir "<render-dir>"
|
|
9
7
|
```
|
|
10
8
|
|
|
11
|
-
Writes one PNG per page and prints
|
|
9
|
+
Writes one PNG per page and prints the paths plus the renderer it used (`libreoffice-kit`); add `--pdf` to keep a PDF as well. For a JSON report and page list use `render_docx.py`:
|
|
12
10
|
|
|
13
11
|
```bash
|
|
14
12
|
"<python>" "<skill>/render_docx.py" "<file.docx>" --output_dir "<render-dir>" --dpi 150
|
|
15
13
|
```
|
|
16
14
|
|
|
17
|
-
## Inspect
|
|
18
|
-
|
|
19
15
|
Open every PNG with `read_image` and check, in this order:
|
|
20
16
|
|
|
21
17
|
1. **Hierarchy** — does the page show the structure the user asked for, at a glance?
|
|
22
18
|
2. **Fit** — nothing past the right margin, no clipped table column, no text over a watermark.
|
|
23
19
|
3. **Breaks** — no heading alone at the bottom, no orphaned caption, no half-empty page before a section break.
|
|
24
|
-
4. **Text** — the words
|
|
20
|
+
4. **Text** — the intended words changed, and nothing else moved.
|
|
25
21
|
5. **Glyphs** — dashes, quotes, CJK, currency symbols and maths render, not as boxes.
|
|
26
|
-
6. **Header and footer** — present, correct, not repeated on a first page that should not have
|
|
22
|
+
6. **Header and footer** — present, correct, and not repeated on a first page that should not have one.
|
|
27
23
|
|
|
28
|
-
|
|
24
|
+
Re-render after any script edit. Package-valid is not page-valid: a caption placed before the paragraph it describes, a table grown past the margin, a style merge that changed heading sizes — all are invisible in the XML and obvious in the image. To compare two revisions, `render_and_diff.py` writes a heatmapped difference page; read the diff images yourself, because a ratio is not a conclusion.
|
|
29
25
|
|
|
30
|
-
|
|
26
|
+
## When no renderer exists
|
|
31
27
|
|
|
32
|
-
|
|
28
|
+
`office_status` reports `renderers.available: false` (with a `remedy`) because the DSH LibreOffice kit was not found. `render` then exits non-zero with a JSON error naming the missing renderer, and `render_docx.py` exits 3 with `reason: no_renderer`.
|
|
33
29
|
|
|
34
30
|
- Verify structure with `docx read`, `docx_kit.py parts|text|xml` and the audit scripts.
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
|
|
38
|
-
## After any script edit
|
|
39
|
-
|
|
40
|
-
Re-render. Package-valid is not page-valid: a caption inserted before the paragraph it describes, a table grown past the margin, a style merge that changed heading sizes — all are invisible to the XML and obvious in the image.
|
|
41
|
-
|
|
42
|
-
## Comparing revisions
|
|
43
|
-
|
|
44
|
-
`render_and_diff.py` renders two files and writes a heatmapped difference page. Read the diff images yourself; a ratio is not a conclusion.
|
|
31
|
+
- Say plainly that layout was not visually verified, and that the fix is a harness install shipping the kit (the plugin records its path in `config.json` when it loads), not installing Word or LibreOffice.
|
|
32
|
+
- Never claim a file "looks good" from XML evidence alone.
|
|
45
33
|
|
|
46
34
|
## Pitfalls
|
|
47
35
|
|
|
48
36
|
- Different renderers paginate differently. Compare like with like, and do not promise Word-perfect pagination from a LibreOffice render.
|
|
49
|
-
- A
|
|
50
|
-
- Render into a fresh directory
|
|
37
|
+
- A missing font turns into a blank page: that is a finding, not a rendering bug. `missing_fonts` / `glyph_fallback` in the render JSON shows substitution happened.
|
|
38
|
+
- Render into a fresh directory: stale PNGs from an earlier run are the classic false pass.
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
# Watermarks and background
|
|
1
|
+
# Watermarks and background marks
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
A Word watermark is not a document feature with its own element: it is a VML shape (`v:shape` with `v:textpath`) in a header part, positioned behind the text. That is why it disappears if the header is replaced, and why it can appear on some pages and not others when sections have their own headers.
|
|
3
|
+
A text watermark is a shape inside a header part, behind the body text: Word writes legacy VML (`v:shape` with `v:textpath`), while `watermark_add.py` writes DrawingML (`wps:wsp`) because VML is routinely dropped by non-Word renderers. That is why a watermark disappears when the header is replaced and can differ per section.
|
|
6
4
|
|
|
7
5
|
## Add
|
|
8
6
|
|
|
@@ -10,26 +8,24 @@ A Word watermark is not a document feature with its own element: it is a VML sha
|
|
|
10
8
|
"<python>" "<skill>/scripts/watermark_add.py" "<file.docx>" --out "<file-draft.docx>" --text "DRAFT"
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
Writes the shape into the default header
|
|
14
|
-
|
|
15
|
-
For a per-page mark across a document with several sections, each section's header needs the shape; that is a loop over sections, not one insertion.
|
|
11
|
+
Writes the shape into the default header: light grey, centred on the page, tagged with `descr="DSH Office watermark"`. Word rotates it -45°; renderers that ignore the rotation still show a horizontal mark, so it is always visible. The script refuses to add a second watermark when it finds one, so remove the old one first. For a mark on every page across sections, each section's header needs the shape — loop over the sections.
|
|
16
12
|
|
|
17
13
|
## Find and remove
|
|
18
14
|
|
|
19
15
|
```bash
|
|
20
16
|
"<python>" "<skill>/scripts/watermark_audit_remove.py" "<file.docx>" --mode report
|
|
21
|
-
"<python>" "<skill>/scripts/watermark_audit_remove.py" "<file.docx>" --mode remove --out "<file-clean.docx
|
|
17
|
+
"<python>" "<skill>/scripts/watermark_audit_remove.py" "<file.docx>" --mode remove --out "<file-clean.docx"
|
|
22
18
|
```
|
|
23
19
|
|
|
24
|
-
The report lists
|
|
20
|
+
The report lists every DrawingML watermark and every legacy VML text path, with the part it lives in, and exits 1 when any watermark exists. `--contains` narrows it to a substring, for the "template says Company Confidential" case. Remove deletes the enclosing paragraph from the header.
|
|
25
21
|
|
|
26
22
|
## Verify
|
|
27
23
|
|
|
28
|
-
Render and read the pages: the mark sits behind the text
|
|
24
|
+
Render and read the pages: the mark sits behind the text, inside the page, on every expected page. A light grey drawing that covers a line of body text is still a defect; a mark missing on page two means that section has a different header.
|
|
29
25
|
|
|
30
26
|
## Pitfalls
|
|
31
27
|
|
|
32
|
-
- A watermark in a "different first page" header only
|
|
33
|
-
- Removing the header paragraph can leave an empty header that adds vertical space
|
|
34
|
-
- An image watermark is
|
|
35
|
-
-
|
|
28
|
+
- A watermark in a "different first page" header shows only on page one.
|
|
29
|
+
- Removing the header paragraph can leave an empty header that adds vertical space — check the top margin.
|
|
30
|
+
- An image watermark is `v:imagedata`, not a text shape, so the report will not name it; inspect the header XML.
|
|
31
|
+
- A watermark is not security (`tasks/protection_restrict_editing.md`).
|
|
@@ -6,19 +6,19 @@
|
|
|
6
6
|
"<python>" "<cli>" status
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Check `renderers.kit` and `renderers.can_render`. `can_render.docx: false` means `docx render` fails with `the LibreOffice renderer is not available` — a setup problem, not a document problem.
|
|
10
10
|
|
|
11
11
|
## What renders
|
|
12
12
|
|
|
13
|
-
Rendering goes through the LibreOffice kit
|
|
13
|
+
Rendering goes through the LibreOffice kit DeepSeek Harness ships (`@deepseek-ai/libreoffice-kit`): the kit's native engine on macOS and Windows, the WASM engine on Linux. A separately installed Microsoft Office, WPS Office or system LibreOffice is **not** used and does not make rendering work.
|
|
14
14
|
|
|
15
15
|
The plugin records the kit's location when the harness loads it, and the helper reads that record before anything else:
|
|
16
16
|
|
|
17
17
|
1. `DSH_LIBREOFFICE_KIT_CLI` — an explicit override, also handy for a hand-run helper.
|
|
18
|
-
2. `libreofficeKit` in `~/.dsh/office/config.json`. The host half writes
|
|
18
|
+
2. `libreofficeKit` in `~/.dsh/office/config.json`. The host half writes it at load, resolving the kit from the harness entry point (`process.argv[1]`, e.g. `<dsh>/node_modules/@deepseek-ai/dsh/lib/bin.js`). This is what makes a profile install work, where the kit lives in the harness tree rather than next to the plugin. Configs that pre-0.5 versions wrote in the OS config directory are still read as fallbacks.
|
|
19
19
|
3. Walking up from the plugin directory through `node_modules/@deepseek-ai/libreoffice-kit/lib/cli.js` — covers a checkout or a plugin-local dependency.
|
|
20
20
|
|
|
21
|
-
`DSH_OFFICE_CONFIG` points the helper at a different config file; `DSH_NODE` overrides the node binary
|
|
21
|
+
`DSH_OFFICE_CONFIG` points the helper at a different config file; `DSH_NODE` overrides the node binary when `node` is not on `PATH`.
|
|
22
22
|
|
|
23
23
|
## Common failures
|
|
24
24
|
|
|
@@ -33,7 +33,7 @@ The plugin records the kit's location when the harness loads it, and the helper
|
|
|
33
33
|
|
|
34
34
|
## Working without a renderer
|
|
35
35
|
|
|
36
|
-
Structure, text and metadata are
|
|
36
|
+
Structure, text and metadata are verifiable headlessly (`docx read`, the audit scripts, `docx_kit.py parts|text|xml`). Layout is not. In that state:
|
|
37
37
|
|
|
38
38
|
1. Do the structural verification.
|
|
39
39
|
2. Tell the user that page layout was not visually checked, and why.
|
|
@@ -43,4 +43,4 @@ Never describe a page you did not render.
|
|
|
43
43
|
|
|
44
44
|
## Keep renders disposable
|
|
45
45
|
|
|
46
|
-
Render into a fresh temp directory each time (`--out-dir`). A stale PNG from
|
|
46
|
+
Render into a fresh temp directory each time (`--out-dir`). A stale PNG from an earlier run reads as a pass — the most common false confirmation.
|
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
# Splitting a long job
|
|
2
2
|
|
|
3
|
-
A twenty-section document is not one command.
|
|
3
|
+
A twenty-section document is not one command. Bounded steps keep each change verifiable and stop one failure hiding inside a large edit.
|
|
4
4
|
|
|
5
5
|
## One step per structural change
|
|
6
6
|
|
|
7
7
|
1. **Plan** — the outline (headings and what each section must establish), written down before any file work.
|
|
8
|
-
2. **Skeleton** —
|
|
9
|
-
3. **Content, in batches** —
|
|
10
|
-
4. **Numbers** — captions, cross-references
|
|
8
|
+
2. **Skeleton** — the file with the outline only: heading blocks, no body text.
|
|
9
|
+
3. **Content, in batches** — one batch per top-level section, appended with `append_blocks.py`.
|
|
10
|
+
4. **Numbers** — captions, cross-references and TOC once the structure is final, never while sections are still moving.
|
|
11
11
|
5. **Verify** — render, inspect, fix.
|
|
12
12
|
|
|
13
13
|
## Why this order
|
|
14
14
|
|
|
15
|
-
- Captions and TOC are fields over structure; running them after every batch means renumbering noise and a TOC
|
|
16
|
-
- A
|
|
17
|
-
- The skeleton proves the
|
|
15
|
+
- Captions and TOC are fields over structure; running them after every batch means renumbering noise and a TOC pointing at deleted headings.
|
|
16
|
+
- A one-section batch is small enough to redo when the layout is wrong.
|
|
17
|
+
- The skeleton proves the hierarchy before the text makes changing it expensive.
|
|
18
18
|
|
|
19
19
|
## Batch boundaries
|
|
20
20
|
|
|
21
|
-
- One section per file
|
|
22
|
-
- Keep a `manifest.json` listing section files in order
|
|
21
|
+
- One section per file — `section-01.docx`, `section-02.docx` — then `merge_docx_append.py`. This is the only sane way to draft in parallel or across sessions.
|
|
22
|
+
- Keep a `manifest.json` listing the section files in order, so merging is mechanical and the order is not remembered from chat.
|
|
23
23
|
- Merge before numbering, not after.
|
|
24
24
|
|
|
25
25
|
## When a batch fails
|
|
26
26
|
|
|
27
|
-
Do not patch a large edit inside a large document. Discard the failed batch's output, fix the batch, re-apply it to the previous good file
|
|
27
|
+
Do not patch a large edit inside a large document. Discard the failed batch's output, fix the batch, re-apply it to the previous good file, and keep that good file until the batch is verified.
|
|
28
28
|
|
|
29
29
|
## Context hygiene
|
|
30
30
|
|
|
31
|
-
- Long sessions lose the document design. Keep the plan and the design defaults (page size, font sizes, table borders) in a file
|
|
32
|
-
- When the user changes a decision mid-job (page size, heading style), record it
|
|
31
|
+
- Long sessions lose the document design. Keep the plan and the design defaults (page size, font sizes, table borders) in a workspace file and re-read it instead of trusting recollection.
|
|
32
|
+
- When the user changes a decision mid-job (page size, heading style), record it where they said it and apply it to batches already written.
|
|
33
33
|
|
|
34
34
|
## Smoke test after the join
|
|
35
35
|
|
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Create,
|
|
2
|
+
description: Create, extract, fill forms in, merge, split, redact, stamp, render, and verify PDF files with the bundled Office helper CLI and Python scripts.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# PDF
|
|
6
6
|
|
|
7
|
-
A PDF page is a content stream of text
|
|
7
|
+
A PDF page is a content stream of text and path operators behind a page box. Every job here reads that stream (PyMuPDF, pdfplumber, pypdf), writes a new one (reportlab), or rasterises it to check the result. Inspect first, make the smallest change that satisfies the request, then prove it on a render.
|
|
8
8
|
|
|
9
|
-
| User job |
|
|
10
|
-
| --- | --- |
|
|
11
|
-
| Look at a page, crop, or measure geometry |
|
|
12
|
-
| Extract text
|
|
13
|
-
| Inspect or fill an AcroForm |
|
|
14
|
-
| Remove a region (redaction) |
|
|
15
|
-
| Read or rewrite metadata
|
|
16
|
-
| Merge, split, reorder, rotate, delete pages |
|
|
17
|
-
| Stamp a footer, header, or
|
|
18
|
-
| Build a new document |
|
|
9
|
+
| User job | Fast path |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| Look at a page, crop, or measure geometry | `scripts/render_pages.py`, `pdf render` |
|
|
12
|
+
| Extract text, tables, or page images | `scripts/extract_text.py`, `pdf read`, `tasks/read.md` |
|
|
13
|
+
| Inspect or fill an AcroForm | `scripts/forms.py`, `tasks/forms.md` |
|
|
14
|
+
| Remove a region (redaction) | `scripts/redact_region.py`, `tasks/redact.md` |
|
|
15
|
+
| Read or rewrite metadata (info dictionary only, never page content) | `scripts/metadata.py`, `tasks/edit-pages.md` |
|
|
16
|
+
| Merge, split, reorder, rotate, delete pages | `scripts/page_ops.py`, `scripts/split_pages.py`, `tasks/edit-pages.md` |
|
|
17
|
+
| Stamp a footer, header, or label | `scripts/stamp_overlay.py`, `tasks/stamp.md` |
|
|
18
|
+
| Build a new document | `pdf create`, `tasks/create.md` |
|
|
19
|
+
| Resolve an `office-annotations` region | `tasks/annotations.md` |
|
|
20
|
+
| Decide what a PDF cannot do | `references/limits.md` |
|
|
21
|
+
|
|
22
|
+
Each task file explains the mechanism before giving the command. `references/geometry.md` covers page boxes and normalised regions, `references/layout-quality.md` is the pre-delivery visual checklist, and `references/form-fields.md` covers field flags, appearance streams, and flattening.
|
|
19
23
|
|
|
20
24
|
## Before any file work
|
|
21
25
|
|
|
22
26
|
1. Call the `office_status` tool.
|
|
23
|
-
2. Read the
|
|
27
|
+
2. Read the runtime block appended to this file at runtime; use its `python`, `cli`, `skill`, and `shared` values verbatim, quoted: `"<python>"`, `"<cli>"`, `"<skill>/scripts/<name>.py"`.
|
|
24
28
|
3. If that block reports no working runtime, stop. Give the user the `node "..."` remedy command it names, then call `office_status` again. Never fabricate a PDF result you could not verify.
|
|
25
29
|
|
|
26
30
|
Scripts under `"<skill>/scripts/"` are standalone argparse CLIs. Run `<python> <script> --help` before using one you have not called in this session.
|
|
@@ -29,49 +33,45 @@ Scripts under `"<skill>/scripts/"` are standalone argparse CLIs. Run `<python> <
|
|
|
29
33
|
|
|
30
34
|
Decide the route before you type a command. Every route ends in the same render check.
|
|
31
35
|
|
|
32
|
-
- **
|
|
33
|
-
- **
|
|
34
|
-
- **A script covers the job** → run it, then
|
|
36
|
+
- **No file yet** → create it from a `pdf create` spec, or with reportlab when the layout does not fit the block model (`tasks/create.md`).
|
|
37
|
+
- **Existing file to change** → read it first (`pdf read`, plus a render), then mutate it with the script its task file names. The CLI has no edit verb: it creates, reads, renders, and reports status only, so every change is a `scripts/*.py` call.
|
|
38
|
+
- **A script covers the job** → run it, then check its JSON report and its rendered pages. A refused overwrite or a failed self-check exits non-zero: that is a hard stop.
|
|
35
39
|
- **A read/render verb covers it** → `pdf read`, `pdf render`, or `pdf status`, then verify in the task's own way. Never route a mutation through the CLI.
|
|
36
|
-
- **Neither covers it** → run the
|
|
37
|
-
- **
|
|
40
|
+
- **Neither covers it** → run or adapt the snippet in the matching `tasks/*.md` file. Do not invent a CLI verb, and do not call the job impossible because no verb exists.
|
|
41
|
+
- **Take the smallest operation**: metadata change before rebuild, page move before re-creation, one-line patch before re-typing the page.
|
|
38
42
|
|
|
39
43
|
## Failure handling
|
|
40
44
|
|
|
41
45
|
| Symptom | Meaning | Next step |
|
|
42
46
|
| --- | --- | --- |
|
|
43
|
-
| `
|
|
44
|
-
| `encrypted` in the error | The file needs a password | Ask the user for a decrypted copy; do not guess passwords or write one into a command. |
|
|
45
|
-
| `the LibreOffice renderer is not available` | Media conversion for docx/pptx/xlsx is unavailable because the DSH LibreOffice kit was not found | PDF rendering still works (PyMuPDF); for a PDF this is harmless. For other formats report that appearance could not be checked. |
|
|
47
|
+
| `encrypted` in the error | The file needs a password | Ask the user for a decrypted copy. Do not guess passwords or write one into a command. |
|
|
46
48
|
| `leftover_chars_in_rect` greater than 0 | The redaction rectangle missed text | Enlarge `--pad` or reconvert the region; re-render before delivering. |
|
|
47
|
-
| `not_applied` is not empty | A form value did not persist after save | Treat as a failure: check the field name, its allowed states, and
|
|
48
|
-
| `chars: 0` on a page that shows text | Scanned page, no text layer | Say so; follow `references/limits.md
|
|
49
|
-
| Render shows the change, `pdf read` does not | The edit landed in pixels only | Fix the content stream or note the limitation
|
|
49
|
+
| `not_applied` is not empty | A form value did not persist after save | Treat as a failure: check the field name, its allowed states, and the widget's appearance stream. |
|
|
50
|
+
| `chars: 0` on a page that shows text | Scanned page, no text layer | Say so; follow `references/limits.md`. Never return an empty extraction as success. |
|
|
51
|
+
| Render shows the change, `pdf read` does not | The edit landed in pixels only | Fix the content stream or note the limitation. A visible-only change is usually a cover-up, not an edit. |
|
|
52
|
+
|
|
53
|
+
General CLI failures, missing runtimes, and the `the LibreOffice renderer is not available` result are covered by `"<shared>/common-workflow.md"`; `pdf render` never needs LibreOffice.
|
|
50
54
|
|
|
51
55
|
## Quality rules
|
|
52
56
|
|
|
53
|
-
- One heading scale, one body size,
|
|
54
|
-
- Prove every structural change on a render of the changed page, not
|
|
57
|
+
- One heading scale, one body size, one margin system per document (`references/layout-quality.md`).
|
|
58
|
+
- Prove every structural change on a render of the changed page, not on a text dump.
|
|
55
59
|
- Keep page geometry consistent when merging or stamping: use each page's own box.
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
- Mark deliberate shortcuts (a rebuild instead of a reflow, a stamped patch instead of a content edit) in the reply, so the user knows what kind of change they received.
|
|
59
|
-
- Deliver with `present`, then one sentence about what changed and where the file is.
|
|
60
|
+
- Never claim redaction while the words are still extractable.
|
|
61
|
+
- Mark deliberate shortcuts (a rebuild instead of a reflow, a stamped patch instead of a content edit) in the reply.
|
|
60
62
|
|
|
61
63
|
## Delivery
|
|
62
64
|
|
|
63
|
-
|
|
65
|
+
Hand the finished file to the user with the `present` tool, then one sentence on what changed. A bare path is not delivery: the transcript renders `.docx`/`.pptx`/`.xlsx`/`.pdf` links as "二进制文件,无法显示改动", so the user cannot open them.
|
|
64
66
|
|
|
65
67
|
- Creating a file: write it into the user's workspace, verify it, then `present`.
|
|
66
68
|
- Editing an existing file: never overwrite the original. Write `<original>-edited.<ext>` (or a name the user asked for), verify it, `present` it, and state both paths.
|
|
67
69
|
|
|
68
70
|
## Annotations
|
|
69
71
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
When the payload cannot be mapped to a concrete object (the region is empty or the file has no geometry), do not guess silently — say what you could not locate.
|
|
72
|
+
An `office-annotations` reply is a change request, not editor state: `[{ page, text, requirement, region: { left, top, width, height } }]`. `region` is normalised 0–1 against the rendered preview page the user drew on; `requirement` is free-form. Locate what the region covers, apply the smallest edit that satisfies `requirement`, re-render, confirm the region looks right, and say what you could not locate rather than guessing.
|
|
73
73
|
|
|
74
|
-
For PDF
|
|
74
|
+
For PDF, `page` is the 1-based page of the file, and `region × page.rect` is the real rectangle: convert once with PyMuPDF and work in the device rect; `text` wins over the region when they disagree, and `imageName`, when present, is a screenshot of the marked area to open with `read_image`. Full recipe: `tasks/annotations.md`, payload shapes: `"<shared>/annotation-recipes.md"`.
|
|
75
75
|
|
|
76
76
|
## Verify
|
|
77
77
|
|
|
@@ -81,22 +81,7 @@ Render before you present, and again after every fix:
|
|
|
81
81
|
"<python>" "<cli>" pdf render --input "<file.pdf>" --out-dir "<render-dir>" --dpi 110
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
Open each PNG with `read_image
|
|
85
|
-
|
|
86
|
-
## Tasks
|
|
87
|
-
|
|
88
|
-
| Task | Read |
|
|
89
|
-
| --- | --- |
|
|
90
|
-
| Create a PDF from a spec or reportlab | `tasks/create.md` |
|
|
91
|
-
| Extract text, tables, or page images | `tasks/read.md` |
|
|
92
|
-
| Inspect, fill, or flatten an AcroForm | `tasks/forms.md` |
|
|
93
|
-
| Remove a region of a page | `tasks/redact.md` |
|
|
94
|
-
| Merge, split, reorder, rotate, delete pages | `tasks/edit-pages.md` |
|
|
95
|
-
| Stamp a footer, header, or label | `tasks/stamp.md` |
|
|
96
|
-
| Resolve an `office-annotations` region | `tasks/annotations.md` |
|
|
97
|
-
| Decide what a PDF cannot do | `references/limits.md` |
|
|
98
|
-
|
|
99
|
-
`references/geometry.md` explains page boxes and normalised regions, `references/layout-quality.md` is the pre-delivery visual checklist, `references/form-fields.md` covers field flags, appearance streams, and flattening.
|
|
84
|
+
Open each PNG with `read_image` and compare it with the pre-change render, working through `references/layout-quality.md`. Then run `"<python>" "<cli>" pdf read --input "<file.pdf>"` and confirm the text, page count, and form fields match your edit. Two or three passes are normal; past three, say what still looks wrong instead of calling it fixed.
|
|
100
85
|
|
|
101
86
|
## Shared workflow
|
|
102
87
|
|