# Step 5: DOCX Generation

## MANDATORY EXECUTION RULES (READ FIRST)

- 📖 **Read `references/docx-format-spec.md` first.** It defines fonts, sizes, line spacing, image embedding, and the post-generation grep self-check. Do not deviate from it.
- ✅ Use `{skill_root}/scripts/md2docx.js` for conversion. It already implements the spec (heading style, header fields, body indent, image embed with IHDR pixel reading, etc.). Do NOT hand-write `ImageRun` or `Paragraph` code.
- 🛑 Do NOT inline image alt-text as a substitute for an actual image. If `![alt](path)` is in the markdown, the path MUST resolve and the image MUST be embedded.

## YOUR TASK

Convert the approved disclosure markdown(s) to formatted `.docx` files at `{disclosure_docx_file}`.

## EXECUTION SEQUENCE

### 5.1 Verify environment

```bash
node --version          # need Node 20+
which node
test -f "{skill_root}/scripts/md2docx.js" && echo "script ok"
ls "{patent_output_folder}/media/" 2>/dev/null || echo "no media yet"
```

The `docx` npm package is required at runtime. Resolution order (do NOT auto-`npm install` in the user's project root — that would pollute their `package.json`):

1. If `docx` already resolves from the user's `{project-root}` (`node -e "require.resolve('docx')"` succeeds), use that.
2. Otherwise, install it into the skill's own folder so it stays scoped to the skill:
   ```bash
   cd "{skill_root}" && npm install --no-save --silent --prefix . docx
   ```
3. As a last resort, ask the user to run `npm install -g docx` and re-invoke `PG`.

The script uses `module.paths` fallback when invoked from `{skill_root}`, so step 2 is sufficient.

> **About git hygiene:** the skill ships a `.gitignore` inside `{skill_root}` that excludes `node_modules/`, `package.json`, and `package-lock.json`. If the user's `.gitignore` does NOT already ignore `_xiaoma/`, this local `.gitignore` keeps the `docx` install from being committed.

### 5.2 Verify image references

For each `![alt](relative-path)` in the markdown, confirm the resolved path exists relative to the markdown file. The convention is `media/doc{N}_fig{M}.png` next to the markdown. Missing images will be replaced by a red `[图片缺失]` placeholder by the script — warn the user if any are missing and ask whether to proceed.

### 5.3 Run conversion

```bash
node "{skill_root}/scripts/md2docx.js" \
  "{disclosure_md_file}" \
  "{disclosure_docx_file}"
```

The script auto-handles:

- The big title "技术交底书" (楷体_GB2312, 18pt, bold, centered)
- The five header fields (仿宋_GB2312, 10.5pt, bold, left)
- Section headings (楷体_GB2312, 10.5pt, bold, left)
- Body paragraphs (宋体, 10.5pt, justified, 1.5x line spacing, 2-char first-line indent)
- Tables, lists, inline code, code blocks
- Image embedding with IHDR pixel reading and ≤ 540px width / ≤ 720px height proportional scaling
- Auto figure captions from alt text (centered, 宋体 10pt italic)

### 5.4 Post-generation self-check (optional but recommended)

A `.docx` file is a zip archive of XML — any unzip tool works. Use `unzip` if available, or fall back to `python -m zipfile -e`:

```bash
# Pick whichever is available on the host
unzip -o "{disclosure_docx_file}" -d /tmp/disclosure-unpack/ \
  || python -m zipfile -e "{disclosure_docx_file}" /tmp/disclosure-unpack/

grep -oE 'w:eastAsia="[^"]+"' /tmp/disclosure-unpack/word/document.xml | sort | uniq -c
grep -oE 'w:color w:val="[A-F0-9]+"' /tmp/disclosure-unpack/word/document.xml | sort | uniq -c
ls /tmp/disclosure-unpack/word/media/ 2>/dev/null | wc -l
```

Expected:

- `仿宋_GB2312` → exactly 5 (the five header fields)
- `楷体_GB2312` → ≥ number of section headings
- Everything else → `宋体`
- Color values → only `000000` (unless blue `0000FF` placeholder hints were intentionally kept)
- Media file count → equals number of standalone `![](...)` lines in the markdown

If any expectation fails, the docx is non-compliant — fix the source markdown or `md2docx.js` constants and re-run, do not deliver. If neither `unzip` nor `python` is available, deliver the file but flag the missed self-check to the user.

### 5.5 Final filename convention

`专利交底书-<invention-slug>-<YYYYMMDD>.docx`

Save to `{patent_output_folder}/`.

### 5.6 Delivery

Report to the user:

- Final docx path
- Number of figures embedded
- Result of the grep self-check
- Suggested next action: send to the patent agent, or if the agent uses a different template, see "Custom Template Override" below

### 5.7 Custom template override (when client provides a different `.doc`/.docx)

If the user provides a different template `.doc/.docx`:

1. If the file is `.doc`, convert to `.docx` first (e.g., `libreoffice --headless --convert-to docx 模板.doc`)
2. Unpack the docx (it's a zip): `unzip -o 模板.docx -d /tmp/tmpl/` (or `python -m zipfile -e 模板.docx /tmp/tmpl/`)
3. Read `/tmp/tmpl/word/styles.xml` (defaults) and `/tmp/tmpl/word/document.xml` (sample paragraphs)
4. Extract: default font (`rFontsDefault`), line spacing (`spacing.line + lineRule`), first-line indent (`ind.firstLineChars / firstLine`), heading fonts/colors, placeholder hint color
5. Overwrite the constants at the top of `{skill_root}/scripts/md2docx.js`: `FONT_BODY_EAST / FONT_HEADING_EAST / FONT_TITLE_EAST / FONT_HEADER_FIELD_EAST / SIZE_BODY / SIZE_TITLE / BODY_LINE_SPACING / HEADING_LINE_SPACING / BODY_FIRST_LINE_INDENT`
6. Re-run step 5.3 and 5.4

## WORKFLOW COMPLETE

After delivery, the skill ends. Recommend the user run a separate session for the next invention point, or invoke `PG` directly to regenerate DOCX from an edited markdown.
