Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ The agent never sees this file. It is the ground-truth definition of "correct" f
- The document still contains **exactly two** embedded images (new logo + footer payment mark).
- Verify via `docx images list FILE`: two entries, and the logo entry's dimensions / source match `assets/logo.svg`.
- Footer payment mark is preserved: the footer image relationship is still present and unreferenced relationships were not dropped.
- **Logo resized + described (`images set`, issue #47)**: the logo's `docx:image` hint reads `size="1.25x…in"` (width within Β±0.05in of 1.25in) and its `<wp:extent>` and `<pic:spPr><a:xfrm><a:ext>` agree; the height/width ratio matches `assets/logo.svg`'s intrinsic ratio (Β±2%) β€” a stretched logo is a fail (caveat: until #46 makes `images replace` refit the frame to the new image's aspect, `--width` keeps the OLD placeholder's ratio, so a distortion inherited from the replace is a tool gap, not an agent error). `<wp:docPr descr="Northwind Robotics logo">` (shown as `![Northwind Robotics logo](…)` in `docx read`). Expected path: `docx images set FILE --at imgN --width 1.25in --alt "Northwind Robotics logo"` (one call). Under track-changes this applies untracked with a `[docx-cli]` audit comment on the image β€” correct, not a defect.

### Stamp text box rewritten (issue #4 β€” text boxes are addressable)
- The document has a floating text box (an `<mc:AlternateContent>` wps shape anchored in the "Thank you for your business." Notes paragraph) whose story was the template warning `TEMPLATE β€” DO NOT SEND`. It must now read exactly `Thank you for your business!` and the strings `TEMPLATE` / `DO NOT SEND` must appear nowhere β€” `docx find FILE "DO NOT SEND"` returns no matches, `docx find FILE "Thank you for your business!"` returns a `tbx0:p0:…` locator.
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/weak-agent-test/scenarios/invoice/task.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ There's a red-bordered stamp box near the bottom of the page that reads "TEMPLAT

## Logo

Replace the placeholder logo in the **top-left corner** with the new company mark at `assets/logo.svg`. Swap that one image only β€” don't add a second logo, and **don't touch the small payment mark in the footer** (it must stay). The document should still have two embedded images when you're done (the new logo + the footer mark).
Replace the placeholder logo in the **top-left corner** with the new company mark at `assets/logo.svg`. Swap that one image only β€” don't add a second logo, and **don't touch the small payment mark in the footer** (it must stay). The document should still have two embedded images when you're done (the new logo + the footer mark). Once the new logo is in, make it about **1.25 inches wide** (keep its proportions β€” no stretching) and give it the alt text **Northwind Robotics logo** so screen readers announce it.

## What done looks like

All `Item 1/2/3`, `$0.00`, `Customer name`, `Your Company Name`, and similar placeholder text is replaced with the values above. Before finishing, do one consolidated sweep for every placeholder family named here β€” item labels, description lines, customer/company names, address prompts, and zero-dollar template amounts β€” rather than checking just one kind and assuming the rest are gone. Leftover placeholder lines (the extra address line, the per-item sub-lines) are removed, not left dangling. The three tables are still present and unbroken. The line-items table has four filled rows, the Description column is the widest, and no dollar value wraps to a second line. Its header row has a light grey fill, the Price and Amount columns are right-aligned, and the header is set to repeat on a second page. The top-left logo is the new mark from `assets/logo.svg`, and the footer's payment mark is untouched. The stamp box near the bottom still exists and now reads "Thank you for your business!" β€” no "TEMPLATE" or "DO NOT SEND" wording anywhere in the document.
All `Item 1/2/3`, `$0.00`, `Customer name`, `Your Company Name`, and similar placeholder text is replaced with the values above. Before finishing, do one consolidated sweep for every placeholder family named here β€” item labels, description lines, customer/company names, address prompts, and zero-dollar template amounts β€” rather than checking just one kind and assuming the rest are gone. Leftover placeholder lines (the extra address line, the per-item sub-lines) are removed, not left dangling. The three tables are still present and unbroken. The line-items table has four filled rows, the Description column is the widest, and no dollar value wraps to a second line. Its header row has a light grey fill, the Price and Amount columns are right-aligned, and the header is set to repeat on a second page. The top-left logo is the new mark from `assets/logo.svg`, about 1.25 inches wide with its proportions intact and the alt text "Northwind Robotics logo", and the footer's payment mark is untouched. The stamp box near the bottom still exists and now reads "Thank you for your business!" β€” no "TEMPLATE" or "DO NOT SEND" wording anywhere in the document.
11 changes: 6 additions & 5 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ docx images add FILE (--after | --before) LOCATOR --image SRC [--alt T] [--w
docx images add FILE (--at-start | --at-end) --image SRC [options] # SRC = path, data: URI, or http(s) URL
docx images extract FILE --to DIR [--at imgN] # --to = output directory; --at picks one image
docx images replace FILE --at imgN --with ./new.png
docx images set FILE --at imgN [--width L | --height L | --size WxH | --fit] [--alt TEXT] # resize in place (one side keeps the aspect; --size = the docx:image hint verbatim; --fit shrinks to the text width, curing overflow="yes"); --batch FILE.jsonl for many
docx images delete FILE --at imgN

docx hyperlinks add FILE --at pN:S-E --url URL
Expand Down Expand Up @@ -409,7 +410,7 @@ Every save of a document with comments already runs the sidecar half of this
0), then the post-fix report; it exits 1 only if errors remain.

> **One rule to memorize: addressing an existing thing is always `--at`.**
> `comments reply/resolve/delete`, `footnotes/endnotes edit/delete`, `images extract/replace/delete`, `hyperlinks replace/delete`, `tables *`, `track-changes accept/reject`, `edit`, `delete`, and `insert` all take `--at LOCATOR`. For insert, `--at` means after an ordinary block and into a bare cell; use `--before`/`--after` when the side matters, or `--at-start`/`--at-end` for document boundaries. The remaining exceptions are positional by nature: `read` slices with `--from`/`--to LOCATOR`; `wc` takes a positional `[LOCATOR]`; `find`/`replace` take a positional `QUERY`/`PATTERN` (and `replace` accepts an optional `--at pN` to _confine_ the substitution to one paragraph). `images extract --to DIR` is an _output directory_, not a locator.
> `comments reply/resolve/delete`, `footnotes/endnotes edit/delete`, `images extract/replace/set/delete`, `hyperlinks replace/delete`, `tables *`, `track-changes accept/reject`, `edit`, `delete`, and `insert` all take `--at LOCATOR`. For insert, `--at` means after an ordinary block and into a bare cell; use `--before`/`--after` when the side matters, or `--at-start`/`--at-end` for document boundaries. The remaining exceptions are positional by nature: `read` slices with `--from`/`--to LOCATOR`; `wc` takes a positional `[LOCATOR]`; `find`/`replace` take a positional `QUERY`/`PATTERN` (and `replace` accepts an optional `--at pN` to _confine_ the substitution to one paragraph). `images extract --to DIR` is an _output directory_, not a locator.

## Output contract

Expand All @@ -433,7 +434,7 @@ The CLI is built for non-interactive agents. **Exit code is the success signal**
| Command class | Default stdout on success | `--verbose` |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| **Mutator that mints a new handle** β€” `comments add`β†’`cN`, `comments reply`β†’`cN`, `footnotes/endnotes add`β†’`fnN`/`enN`, `hyperlinks add`β†’`linkN`, `insert`β†’the new `pN` | the bare locator(s), **one per line** (a multi-block `--markdown` insert prints several) | full `{ok:true,…}` ack |
| **Mutator with no new handle** β€” `edit`, `delete`, `replace`, `create`, `comments resolve/delete`, `images replace/delete`, `hyperlinks replace/delete`, `footnotes/endnotes edit/delete`, `headers/footers set/clear`, `tables *`, `track-changes accept/reject` & toggle | **one-line confirmation** β€” `<operation> <target>` (e.g. `edit t1:r0c1:p0`, `edit 7 changes`, `replace 3 occurrences replaced`) (exit `0`) | full `{ok:true,…}` ack |
| **Mutator with no new handle** β€” `edit`, `delete`, `replace`, `create`, `comments resolve/delete`, `images replace/set/delete`, `hyperlinks replace/delete`, `footnotes/endnotes edit/delete`, `headers/footers set/clear`, `tables *`, `track-changes accept/reject` & toggle | **one-line confirmation** β€” `<operation> <target>` (e.g. `edit t1:r0c1:p0`, `edit 7 changes`, `replace 3 occurrences replaced`) (exit `0`) | full `{ok:true,…}` ack |
| `find` | matched span locators, one per line (no matches β†’ nothing, exit `0`) | `--json` β†’ `{ totalMatches, query, view, matches:[…], normalizedQuery? }` |
| `wc` | the bare count (whole-doc adds a tab-separated `sections` column, like `wc`) | `--json` β†’ `{ words, scope, view, sections? }` |
| `outline` | indented `LOCATORβ‡₯TEXT` tree (two spaces per level) | `--json` β†’ nested `[{ id, locator, level, style, text, children }]` |
Expand All @@ -453,7 +454,7 @@ Locators come in two flavors. **Positional block ids** (`pN`, `tN`, `sN`) are de
| `cN` (comment) | `docx comments list FILE` | `comments reply/resolve/delete --at` |
| `fnN` / `enN` (foot/endnote) | `docx footnotes list FILE` / `docx endnotes list FILE` | `footnotes/endnotes edit/delete --at` |
| `hdrN` / `ftrN` (header/footer) | `docx headers list FILE` / `docx footers list FILE` (or `read --ast` / the `docx:header`/`docx:footer` note) | `raw get --at`, `headers/footers set/clear --at` (or scope by section: `--at sN --type T`) |
| `imgN` (image) | `docx images list FILE` | `images extract/replace/delete --at` |
| `imgN` (image) | `docx images list FILE` | `images extract/replace/set/delete --at` |
| `linkN` (hyperlink) | `docx hyperlinks list FILE` | `hyperlinks replace/delete --at` |
| `tcN` (tracked change) | `docx track-changes list FILE` | `track-changes accept/reject --at` |
| `eqN` (equation) | `docx read FILE --ast` (run `latex` field) | `equations edit --at eqN` |
Expand Down Expand Up @@ -507,7 +508,7 @@ from before, so existing calls keep working:

| Flag(s) | Bare number | Notes |
| -------------------------------------------------------------------------- | ------------------------------- | -------------------------------------------------------------------------------------------- |
| `images add --width/--height` | inches | also `px` (96 dpi): `--width 300px`, `--width 5cm` |
| `images add`/`set --width/--height` (`set --size WxH`) | inches | also `px` (96 dpi): `--width 300px`, `--width 5cm` |
| `tables create --widths`, `--table-width`; `set-widths --widths`; `insert-column --width` | whole twips (1440 = 1in) | a bare 1–9 is refused (2 twips is 0.001in β€” write `2in` or `2tw`); `--table-width`/`set-widths` also take `%` |
| `--space-before/--space-after` | points | |
| `--indent-*`/`--first-line`/`--hanging`, page `--margins` | inches | a bare value above 9 is twips (the `read --ast` number); indents/margins may be negative |
Expand Down Expand Up @@ -566,7 +567,7 @@ docx track-changes apply doc.docx --accept rev0 --reject rev1 # finalize: acce

**Span-aware comments & hyperlinks.** `comments add --at p3:5-20` (and `hyperlinks add`) find the runs containing offsets 5 and 20, split them at the boundaries (preserving `<w:rPr>` on both halves), and insert markers between the slices. Comments authored by older tools that lack `w14:paraId` (required by `commentsExtended.xml`) get a fresh paraId injected automatically on resolve/reply. When a Word-saved file carries Word's comment sidecars (`commentsExtended.xml`, `commentsIds.xml`, `commentsExtensible.xml`), every `comments add`/`reply`/`delete` adds or removes the matching entry in each one, so Word never offers to repair the file. A file without them stays without them.

**Tracked changes.** With `<w:trackRevisions/>` set, `insert`/`edit`/`delete`/`replace` emit native `<w:ins>`/`<w:del>` (attributed via `--author`, `$DOCX_AUTHOR`, or `Reviewer`); pass `--track` to one of those commands (or the `tables` verbs / `images delete`) to track just that invocation even when the doc toggle is off. `edit --at pN --text` runs a word-level diff so unchanged words keep their formatting and only changed words are wrapped β€” the same shape Word produces mid-tracking. `accept`/`reject` handle run-level ins/del/moveFrom/moveTo, `sectPrChange`, paragraph-mark ins/del, and the table-structural revisions (rowIns/rowDel, cellIns/cellDel, tblGridChange, tcPrChange). OOXML has no tracked-change construct for hyperlink edits or image swaps, so under tracking those emit a `[docx-cli]` audit comment instead of a fake revision (image _deletion_ is honest removal β€” it wraps a real `<w:del>`).
**Tracked changes.** With `<w:trackRevisions/>` set, `insert`/`edit`/`delete`/`replace` emit native `<w:ins>`/`<w:del>` (attributed via `--author`, `$DOCX_AUTHOR`, or `Reviewer`); pass `--track` to one of those commands (or the `tables` verbs / `images delete`) to track just that invocation even when the doc toggle is off. `edit --at pN --text` runs a word-level diff so unchanged words keep their formatting and only changed words are wrapped β€” the same shape Word produces mid-tracking. `accept`/`reject` handle run-level ins/del/moveFrom/moveTo, `sectPrChange`, paragraph-mark ins/del, and the table-structural revisions (rowIns/rowDel, cellIns/cellDel, tblGridChange, tcPrChange). OOXML has no tracked-change construct for hyperlink edits or image swaps/resizes (`images replace`/`set`), so under tracking those emit a `[docx-cli]` audit comment instead of a fake revision (image _deletion_ is honest removal β€” it wraps a real `<w:del>`).

**Text boxes and markup compatibility.** Word writes every modern shape and text box as an `<mc:AlternateContent>` pair (a `wps` shape under `<mc:Choice>`, a legacy VML copy under `<mc:Fallback>`), and the markup-compatibility spec lets that wrapper sit at any level β€” around a block, a paragraph's runs, or a run's children β€” and nest. The reader resolves the wrapper wherever it appears (first `Choice`, else `Fallback`), so nothing under it is dropped, and every offset walker descends the same branch (a wrapper with several `Choice`s counts exactly the one the reader read); a `<w:txbxContent>` story surfaces as a `textBox` run whose blocks are addressable `tbxN:pK` paragraphs. Edits land in the `Choice` copy (the one Word reads) and a text box's `Fallback` twin is mirrored from it on save, exactly as Word does when it edits the box. A wrapper that is not a text box has no mirrorable story, so an edit inside it changes the `Choice` only β€” the same two-faced file Word leaves when it preserves a fallback it didn't regenerate.

Expand Down
Loading
Loading