bun-docx 0.17.0 → 0.19.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bun-docx",
3
- "version": "0.17.0",
4
- "description": "CLI for AI agents (Claude, Codex) to read, edit, and comment on .docx files with full format fidelity.",
3
+ "version": "0.19.0",
4
+ "description": "Read, edit, redline, and comment on Microsoft Word .docx files from the command line — built for AI agents.",
5
5
  "keywords": [
6
6
  "docx",
7
7
  "openxml",
@@ -11,8 +11,15 @@
11
11
  "ai",
12
12
  "claude",
13
13
  "codex",
14
- "agentic"
14
+ "agentic",
15
+ "agent-skill",
16
+ "pi-package"
15
17
  ],
18
+ "pi": {
19
+ "skills": [
20
+ "./skills"
21
+ ]
22
+ },
16
23
  "license": "MIT",
17
24
  "author": "Kirill Klimuk",
18
25
  "repository": {
@@ -29,6 +36,7 @@
29
36
  "files": [
30
37
  "dist/index.js",
31
38
  "dist/pdfium-*.wasm",
39
+ "skills/",
32
40
  "README.md",
33
41
  "LICENSE",
34
42
  "LGPL-3.0.txt",
@@ -0,0 +1,125 @@
1
+ ---
2
+ name: docx-cli
3
+ description: "Read, edit, redline, comment on, and create Microsoft Word .docx files. Use to fill out or edit a Word doc, redline a contract with tracked changes, add/resolve comments, replace text keeping its formatting, restyle headings/fonts, edit tables, or read/extract a .docx as Markdown or text. Also BUILD a new .docx — from Markdown or programmatically (code that outputs a Word report with headings, tables, images). Not for PDF, Google Docs, Excel, PowerPoint, or .doc."
4
+ ---
5
+
6
+ # docx-cli
7
+
8
+ `docx` is a command-line tool for reading, editing, redlining, and commenting on
9
+ Microsoft Word `.docx` files. It edits the underlying OOXML **in place** (it never
10
+ rebuilds the document from a lossy view), addresses everything with **stable
11
+ locators**, and signals success through an **exit code** plus a one-line
12
+ confirmation — so even small, cheap models can drive it reliably.
13
+
14
+ ## 0. Make sure the binary is on PATH
15
+
16
+ Run `docx --version`. If you get "command not found", install it:
17
+
18
+ ```sh
19
+ curl -fsSL https://raw.githubusercontent.com/kklimuk/docx-cli/main/install.sh | sh
20
+ ```
21
+
22
+ Or, from this skill folder, run `bash scripts/bootstrap.sh` — it checks the
23
+ installed version against the latest release and self-updates. Every verb works
24
+ against the `.docx` zip directly; only `docx render` needs Word (macOS/Windows)
25
+ or LibreOffice installed.
26
+
27
+ ## 1. The contract is `--help` / `docx info` — start there
28
+
29
+ The help text is authoritative and versioned with the binary. This skill is thin
30
+ on purpose and defers to it. Before doing anything, run (none of these need a FILE):
31
+
32
+ ```sh
33
+ docx --help # every command + a one-line capability hint each
34
+ docx info locators # the addressing grammar — READ THIS, it is the backbone
35
+ docx info schema # the JSON-AST shape that "docx read --ast" emits
36
+ ```
37
+
38
+ Then `docx <command> --help` for any verb before you use it.
39
+
40
+ ## 2. Locators — how you address things
41
+
42
+ - `pN` paragraph, `tN` table, `sN` section; `p3:5-20` = characters 5..19 of `p3`;
43
+ `pN-pM` a block range; `tN:rRcC` a table cell.
44
+ - Entities: `cN` comment, `imgN` image, `linkN` hyperlink, `fnN`/`enN`
45
+ foot/endnote, `tcN` tracked change, `eqN` equation.
46
+ - Get them from `docx read FILE` (locators ride the Markdown as `<!-- pN -->`
47
+ comments) or `docx read FILE --ast` (lossless JSON).
48
+ - **Ids are positional and SHIFT after structural edits.** Re-read between
49
+ mutations — OR apply many changes from ONE read with `--batch` (below).
50
+ - Pass a locator with `--at` (edit / delete / comments / footnotes / images /
51
+ hyperlinks / tables / track-changes), `--after`/`--before` (insert), or
52
+ `--from`/`--to` (read a slice).
53
+ - Don't hand-count character offsets: `docx find FILE "phrase"` returns the exact
54
+ span locator (e.g. `p3:5-20`) to paste into `--at`.
55
+
56
+ ## 3. Golden workflows
57
+
58
+ ### Fill out a form or contract (keeps formatting)
59
+ `docx replace` swaps only the text and preserves the run's bold/font and any tab
60
+ stops — so it fills bold, tabbed template lines without rebuilding runs.
61
+ ```sh
62
+ docx read contract.docx # see content + locators
63
+ docx replace contract.docx "[Client Name]" "Acme, Inc." # one field
64
+ docx replace contract.docx --batch fills.jsonl # many fields, one read/write
65
+ ```
66
+
67
+ ### Redline with tracked changes
68
+ ```sh
69
+ docx track-changes on contract.docx # turn tracking on (doc-level)
70
+ docx replace contract.docx "Net 90" "Net 30" # now auto-emits <w:ins>/<w:del>
71
+ docx edit --at p12:0-40 contract.docx --text "…" --track # or redline one edit
72
+ docx track-changes list contract.docx # the tcN handles
73
+ docx read contract.docx --current # view redlines as CriticMarkup
74
+ docx track-changes accept contract.docx --at tc3 # or --all / reject
75
+ ```
76
+
77
+ ### Comment on clauses
78
+ ```sh
79
+ docx comments add contract.docx --anchor "limitation of liability" --text "Cap is too low."
80
+ docx comments list contract.docx
81
+ docx comments reply contract.docx --at c0 --text "Agreed, raising to \$5M."
82
+ docx comments resolve contract.docx --at c0
83
+ ```
84
+
85
+ ### Read / extract
86
+ ```sh
87
+ docx read FILE # Markdown (default; tracked changes shown accepted-clean)
88
+ docx read FILE --ast # lossless JSON AST
89
+ docx wc FILE # word count (whole doc or a slice)
90
+ docx outline FILE # headings as a locator tree
91
+ ```
92
+
93
+ ### Build from scratch / verify layout
94
+ ```sh
95
+ docx create out.docx --from draft.md # GFM + math + CriticMarkup + inline HTML
96
+ docx render FILE --out pages/ # PNG per page — only when LAYOUT is the question
97
+ ```
98
+
99
+ ## 4. Apply many changes from one read — `--batch`
100
+
101
+ `edit`, `insert`, `replace`, `delete`, and the `comments` verbs take
102
+ `--batch FILE.jsonl` (one JSON change per line; `-` reads stdin). Every locator
103
+ in the batch addresses the document **as read**, so ids stay valid across the whole
104
+ batch — one read, one write, no re-reading between changes. Keys mirror the
105
+ command's flags. This is the right tool for filling a form or applying a review.
106
+
107
+ ## 5. Output & safety contract
108
+
109
+ - **Exit code is the success signal:** `0` ok, `1` error, `2` usage, `3`
110
+ not-found. Every command also prints a one-line text confirmation — you never
111
+ have to re-read just to learn whether a mutation landed.
112
+ - Mutators overwrite `FILE` **in place** (git is your history). `-o/--output PATH`
113
+ writes a copy instead; `--dry-run` previews without writing.
114
+ - A command that mints a new handle (`comments add`→`cN`, `insert`→`pN`,
115
+ `footnotes add`→`fnN`, …) prints the bare locator(s), one per line.
116
+ - Re-read after structural edits (ids shift), or batch from one read.
117
+ - Need exact literal text in (a URL, prose GFM would mangle)? `insert` and
118
+ `create` take `--text-file PATH` (`-` = stdin): every character lands verbatim,
119
+ each newline a new paragraph. No escaping burden.
120
+
121
+ ## 6. Going deeper
122
+
123
+ - `references/commands.md` — the full command surface at a glance.
124
+ - `references/troubleshooting.md` — install, PATH, render runtime, common errors.
125
+ - Or just run `docx <command> --help` — the authoritative, versioned contract.
@@ -0,0 +1,53 @@
1
+ # docx-cli command reference
2
+
3
+ The **authoritative, versioned** reference is `docx <command> --help` (and
4
+ `docx --help` for the index). This file is a quick map; when a detail matters,
5
+ run the help. None of the `info` commands need a FILE:
6
+
7
+ ```sh
8
+ docx --help # every command, one capability hint each
9
+ docx info locators # the addressing grammar (the backbone)
10
+ docx info schema # the JSON-AST shape that `docx read --ast` emits
11
+ docx info skill # this skill, regenerated from the binary
12
+ ```
13
+
14
+ ## Read & query (never mutate)
15
+
16
+ | Command | What it does |
17
+ | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
18
+ | `read FILE` | Render as Markdown with `pN` locators. `--from/--to` slice; `--accepted` (default)/`--current`/`--baseline` tracked views; `--comments`; `--ast` for the lossless JSON AST. |
19
+ | `find FILE [QUERY]` | Find spans by text OR by formatting (`--highlight/--color/--bold/--italic/--underline`); returns locators to feed `--at`. |
20
+ | `wc FILE [LOCATOR]` | Word count for the whole doc or a slice. |
21
+ | `outline FILE` | Headings as a locator tree. |
22
+ | `render FILE` | Render each page to PNG/JPG via Word or LibreOffice — for verifying LAYOUT only. |
23
+ | `styles FILE` | List/describe styles (`--used`, `--at ID`). |
24
+ | `info <topic>` | `schema` / `locators` / `skill` — reference material, no FILE. |
25
+
26
+ ## Mutate (overwrite FILE in place; `-o PATH` writes a copy; `--dry-run` previews)
27
+
28
+ | Command | What it does |
29
+ | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
30
+ | `create FILE` | Create a new `.docx` (`--from PATH.md` / `--from -`; `--text-file` for literal text). |
31
+ | `edit FILE` | Replace/strip text or formatting at a locator (`--clear`, `--track`, `--batch`). |
32
+ | `insert FILE` | Insert a paragraph, image, table, equation, code, markdown, or page break (`--after/--before`, `--track`, `--batch`). |
33
+ | `delete FILE` | Remove a paragraph, range, table, or section break (`--at`, `--track`, `--batch`). |
34
+ | `replace FILE PATTERN REPL` | Substitute text spans sed-style — KEEPS the run's formatting and tabs (`--regex`, `--track`, `--batch`). The form-fill workhorse. |
35
+ | `sections FILE` | Multi-column layout, section breaks, and page setup (margins/orientation/size). The only way to do columns. |
36
+ | `styles set/create/set-default-font` | Restyle every heading at once, mint a style, or set the document font. |
37
+ | `comments` | `add` (`--at` / `--anchor PHRASE` / `--batch`), `reply`, `resolve` (`--unset`), `delete`, `list`. |
38
+ | `footnotes` / `endnotes` | `add` (`--at` / `--anchor`), `edit`, `delete`, `list`. |
39
+ | `headers` / `footers` | `set` / `list` / `clear` — text, page numbers, dates, fields; e.g. `footers set FILE --page-number --of-pages`. |
40
+ | `images` | `add` (`--caption` for a figure), `extract`, `replace`, `delete`, `list`. |
41
+ | `hyperlinks` | `add` (`--url`), `list`, `replace` (`--with`), `delete`. |
42
+ | `tables` | Insert/delete rows & columns, merge/unmerge, set widths, borders, formatting. |
43
+ | `lists` | Renumber a numbered list (`set --at pN --start 5` / `--format upper-roman` / `--restart` / `--continue`). |
44
+ | `track-changes` | `on`/`off`, `list`, `accept`/`reject` (`--at tcN` / `--all`). |
45
+
46
+ ## The two gotchas that can trip you up
47
+
48
+ 1. **Ids shift after structural edits.** Re-read between mutations, or apply many
49
+ changes from ONE read with `--batch FILE.jsonl` — every locator addresses the
50
+ document as read, so ids stay valid across the whole batch.
51
+ 2. **`docx read` is the source of truth for CONTENT.** Only `docx render` (slow —
52
+ spins up Word) shows LAYOUT: columns, page/section breaks, image placement,
53
+ table geometry. Render once at the end, not after every edit.
@@ -0,0 +1,61 @@
1
+ # docx-cli troubleshooting
2
+
3
+ ## `docx: command not found`
4
+
5
+ The binary isn't on PATH. Install it (or run `scripts/bootstrap.sh`, which also
6
+ self-updates a stale install):
7
+
8
+ ```sh
9
+ curl -fsSL https://raw.githubusercontent.com/kklimuk/docx-cli/main/install.sh | sh
10
+ ```
11
+
12
+ It installs to `~/.local/bin/docx` by default. Make sure that directory is on
13
+ your `PATH` (`export PATH="$HOME/.local/bin:$PATH"`). Set `PREFIX=/usr/local/bin`
14
+ before the install to choose another location.
15
+
16
+ ## `docx render` fails or hangs
17
+
18
+ `render` is the **only** command that needs an external app. Everything else
19
+ operates on the `.docx` zip directly. For `render` you need one of:
20
+
21
+ - **Word** (macOS or Windows) — highest-fidelity output.
22
+ - **LibreOffice** (`soffice`) — cross-platform; auto-used when Word isn't present.
23
+
24
+ If neither is installed, every other verb still works — you just can't rasterize
25
+ pages. And you usually don't need to: `docx read` already proves content changes
26
+ through the write→read loop. Render only when the open question is LAYOUT
27
+ (columns, page/section breaks, image sizing, table geometry), and then once.
28
+
29
+ ## "Did my change apply?" — read the exit code
30
+
31
+ Exit code is the contract: `0` ok, `1` error, `2` usage, `3` not-found. Every
32
+ command also prints a one-line confirmation, so you never have to re-read just to
33
+ learn whether a mutation landed. For the full structured ack, add `--verbose`.
34
+
35
+ ## A locator points at the wrong thing
36
+
37
+ Block ids (`pN`, `tN`, `sN`, …) are **positional** and shift after structural
38
+ edits (insert/delete that add or remove blocks). Two fixes:
39
+
40
+ 1. **Re-read** (`docx read FILE` or `--ast`) after a structural edit to get fresh ids.
41
+ 2. **Batch** instead: `--batch FILE.jsonl` applies many changes from a single
42
+ read, so every locator stays valid across the whole batch. This is the right
43
+ tool for filling a form or applying a multi-point review.
44
+
45
+ To get an exact span locator without counting characters, run
46
+ `docx find FILE "phrase"` and paste the result into `--at`.
47
+
48
+ ## My literal text got mangled (a URL autolinked, prose got reformatted)
49
+
50
+ The `--markdown`/`--from` channels parse GFM (+ math + CriticMarkup + inline
51
+ HTML), which can transform literal prose. When you need text in **verbatim**, use
52
+ the parser-free channel: `insert` and `create` take `--text-file PATH` (`-` =
53
+ stdin). Every character lands as-is; each newline starts a new paragraph.
54
+
55
+ ## I edited a file and lost some unusual formatting
56
+
57
+ You shouldn't — docx-cli mutates the underlying XML **in place** and leaves
58
+ constructs it doesn't model untouched. If you rebuilt the document instead
59
+ (`read` → `create`), that round-trips through a view and can drop what the view
60
+ doesn't carry. Prefer in-place `edit`/`replace`/`insert`/`delete` over
61
+ read-then-recreate. `git` is your undo (there's no journal).
@@ -0,0 +1,107 @@
1
+ #!/bin/sh
2
+ # docx-cli skill bootstrap.
3
+ #
4
+ # Ensures the `docx` binary is installed and reasonably current, so an agent that
5
+ # activated this skill can rely on it. Run it once at the start of a session:
6
+ # bash scripts/bootstrap.sh
7
+ #
8
+ # Behavior:
9
+ # - not installed -> install the latest release via the canonical installer
10
+ # - installed -> compare against the latest GitHub release tag; if behind,
11
+ # self-update (re-running the installer, which fetches latest)
12
+ # - no network / can't determine latest -> leave the working binary in place and
13
+ # exit 0 (every verb except `render` works offline anyway)
14
+ #
15
+ # POSIX sh, no bashisms. The binary is the source of truth — this script only keeps
16
+ # it present and fresh; it never edits the skill.
17
+
18
+ set -eu
19
+
20
+ REPO="kklimuk/docx-cli"
21
+ INSTALL_URL="https://raw.githubusercontent.com/${REPO}/main/install.sh"
22
+
23
+ # ─── Pick a downloader (shared by the version check and the installer fetch) ───
24
+ if command -v curl >/dev/null 2>&1; then
25
+ fetch() { curl -fsSL "$1"; }
26
+ elif command -v wget >/dev/null 2>&1; then
27
+ fetch() { wget -qO- "$1"; }
28
+ else
29
+ echo "docx-cli bootstrap: need curl or wget." >&2
30
+ exit 1
31
+ fi
32
+
33
+ # Download install.sh to a temp file FIRST, then run it — so a failed/empty download
34
+ # is caught here instead of being silently swallowed (`fetch | sh` would let `sh` read
35
+ # empty stdin and exit 0, masking the failure). Returns the installer's exit status.
36
+ run_installer() {
37
+ echo "→ Installing docx-cli (latest) ..."
38
+ installer="$(mktemp 2>/dev/null || mktemp -t docx-cli-install)"
39
+ if ! fetch "$INSTALL_URL" > "$installer" || [ ! -s "$installer" ]; then
40
+ rm -f "$installer"
41
+ echo "docx-cli bootstrap: could not download the installer from $INSTALL_URL (offline or rate-limited)." >&2
42
+ return 1
43
+ fi
44
+ if sh "$installer"; then rc=0; else rc=$?; fi
45
+ rm -f "$installer"
46
+ return "$rc"
47
+ }
48
+
49
+ # install.sh drops the binary in ${PREFIX:-$HOME/.local/bin} and only PRINTS a PATH hint
50
+ # — it can't edit the caller's PATH. So after installing, confirm `docx` is actually
51
+ # resolvable and fail LOUDLY if not, rather than reporting a false success the agent
52
+ # trips over on its first `docx` call (and re-downloading from scratch every session).
53
+ ensure_reachable() {
54
+ command -v docx >/dev/null 2>&1 && return 0
55
+ bindir="${PREFIX:-$HOME/.local/bin}"
56
+ echo "docx-cli bootstrap: installed to $bindir, but it is NOT on your PATH." >&2
57
+ echo " Add it: export PATH=\"$bindir:\$PATH\" (then re-run)" >&2
58
+ echo " Or invoke the binary directly: $bindir/docx" >&2
59
+ return 1
60
+ }
61
+
62
+ # ─── Not installed: install, confirm reachable, finish ───
63
+ if ! command -v docx >/dev/null 2>&1; then
64
+ echo "docx not found on PATH."
65
+ run_installer || exit 1
66
+ ensure_reachable || exit 1
67
+ exit 0
68
+ fi
69
+
70
+ installed="$(docx --version 2>/dev/null | awk '{print $NF}')"
71
+ echo "docx-cli present: ${installed:-unknown}"
72
+
73
+ # Couldn't read a version (broken or changed --version output)? Do NOT enter a reinstall
74
+ # loop — the binary is present and resolvable; leave it and exit clean.
75
+ if [ -z "$installed" ]; then
76
+ echo "Could not read the installed version — leaving the present binary in place."
77
+ exit 0
78
+ fi
79
+
80
+ # ─── Determine the latest released version (best-effort) ───
81
+ latest_json="$(fetch "https://api.github.com/repos/${REPO}/releases/latest" 2>/dev/null || true)"
82
+ latest="$(printf '%s' "$latest_json" | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"v\{0,1\}\([^"]*\)".*/\1/p' | head -n 1)"
83
+
84
+ if [ -z "$latest" ]; then
85
+ echo "Could not determine the latest release (offline or rate-limited) — keeping the installed binary."
86
+ exit 0
87
+ fi
88
+
89
+ if [ "$installed" = "$latest" ]; then
90
+ echo "✓ Up to date (${installed})."
91
+ exit 0
92
+ fi
93
+
94
+ # Versions differ. Only UPDATE when installed is OLDER than latest — never downgrade a
95
+ # locally-built/pre-release binary that's ahead of the published release. Use version
96
+ # sort when the platform's `sort` supports -V; otherwise fall back to updating.
97
+ if printf '%s\n' "0.0" "0.1" | sort -V >/dev/null 2>&1; then
98
+ oldest="$(printf '%s\n%s\n' "$installed" "$latest" | sort -V | head -n 1)"
99
+ if [ "$oldest" != "$installed" ]; then
100
+ echo "Installed (${installed}) is newer than the latest release (${latest}) — keeping it."
101
+ exit 0
102
+ fi
103
+ fi
104
+
105
+ echo "A newer release is available: ${installed} -> ${latest}."
106
+ run_installer || { echo "docx-cli bootstrap: update failed — keeping ${installed}." >&2; exit 1; }
107
+ ensure_reachable || exit 1