bun-docx 0.19.2 → 0.20.1
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/README.md +21 -0
- package/dist/index.js +93 -95
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,27 @@
|
|
|
8
8
|
- Agents address text by **stable locators** with character offsets (`p3:5-20`); humans see normal Word formatting on disk.
|
|
9
9
|
- Custom styles, theme colors, embedded objects — all of it survives. The CLI mutates XML in place rather than re-emitting from a lossy model.
|
|
10
10
|
|
|
11
|
+
## Why docx-cli?
|
|
12
|
+
|
|
13
|
+
The default way agents edit Word docs is to unzip the `.docx` and hand-write the OOXML inside. That takes a strong model to get right, burns tokens, and routinely produces a file Word won't open. `docx-cli` hands the agent plain commands plus an annotated-Markdown read view, so it never has to reason about the XML.
|
|
14
|
+
|
|
15
|
+
We measured it — a controlled A/B bake-off: **six real document tasks** (fill an NDA, fill an invoice, restyle a résumé, redline a contract, finalize a contract, author a journal), the same starting files, and one independent judge grading every result from the **Word-rendered pages**. Three runs per arm at each of two model tiers:
|
|
16
|
+
|
|
17
|
+
| | Haiku (weak, cheap) | | Sonnet (strong) | |
|
|
18
|
+
| :------------------------ | ------------------: | --------------------: | --------------: | --------------------: |
|
|
19
|
+
| | **docx-cli** | default skill | **docx-cli** | default skill |
|
|
20
|
+
| Tasks solved (of 6) | **4.3** (4–5) | 0.7 (0–1) | **6.0** (6–6) | 4.0 (4–4) |
|
|
21
|
+
| Rendered correctly (of 6) | 6 | 3.7 | 6.0 | 4.7 |
|
|
22
|
+
| Outright-broken documents | **0** | ~1/run (up to 2) | **0** | 0 |
|
|
23
|
+
| Input tokens | **2.4M** | 6.1M (2.6×) | **1.6M** | 3.6M (2.2×) |
|
|
24
|
+
| Wall-clock | **924 s** | 1,882 s (2.0× slower) | **1,175 s** | 2,029 s (1.7× slower) |
|
|
25
|
+
|
|
26
|
+
- **The correctness gap is widest on the cheap Haiku tier (~6×)**, and a frontier model never closes it — the default skill caps at 4/6, losing the contract redline and the résumé every Sonnet run.
|
|
27
|
+
- **The cost and speed penalties are model-independent** — ~2.2–2.6× more tokens and ~1.7–2× slower at *both* tiers, with token/time ranges that never overlap.
|
|
28
|
+
- **Word couldn't reliably open the default skill's work** — it failed to open 5 of 36 of its outputs; all 36 of docx-cli's opened on the first try.
|
|
29
|
+
|
|
30
|
+
Full methodology, per-task rubric, and side-by-side renders: **[the bake-off writeup](https://kklimuk.github.io/docx-cli/)**.
|
|
31
|
+
|
|
11
32
|
## Install
|
|
12
33
|
|
|
13
34
|
**npm** — the simplest path (requires Bun >= 1.3):
|
package/dist/index.js
CHANGED
|
@@ -4435,6 +4435,20 @@ class XmlNode2 {
|
|
|
4435
4435
|
}
|
|
4436
4436
|
return out;
|
|
4437
4437
|
}
|
|
4438
|
+
collectTextWithBreaks() {
|
|
4439
|
+
if (this.isText)
|
|
4440
|
+
return this.text ?? "";
|
|
4441
|
+
if (this.tag === "w:br" || this.tag === "w:cr")
|
|
4442
|
+
return `
|
|
4443
|
+
`;
|
|
4444
|
+
if (this.tag === "w:tab")
|
|
4445
|
+
return "\t";
|
|
4446
|
+
let out = "";
|
|
4447
|
+
for (const child of this.children) {
|
|
4448
|
+
out += child.collectTextWithBreaks();
|
|
4449
|
+
}
|
|
4450
|
+
return out;
|
|
4451
|
+
}
|
|
4438
4452
|
clone() {
|
|
4439
4453
|
const cloned = new XmlNode2(this.tag, { ...this.attributes });
|
|
4440
4454
|
if (this.text !== undefined)
|
|
@@ -5290,6 +5304,11 @@ function RunElement({ run }) {
|
|
|
5290
5304
|
}
|
|
5291
5305
|
return null;
|
|
5292
5306
|
}
|
|
5307
|
+
function textToRunElements(text) {
|
|
5308
|
+
return textToRuns(text, {}).map((run) => /* @__PURE__ */ jsxDEV(RunElement, {
|
|
5309
|
+
run
|
|
5310
|
+
}, undefined, false, undefined, this)).filter((node) => node !== null);
|
|
5311
|
+
}
|
|
5293
5312
|
function applyParagraphOptionsInPlace(rebuilt, options) {
|
|
5294
5313
|
if (!options.style && !options.alignment && !options.tabs && !options.spacing && !options.indent)
|
|
5295
5314
|
return;
|
|
@@ -17744,14 +17763,7 @@ function noteFirstParagraphRuns({
|
|
|
17744
17763
|
return runs;
|
|
17745
17764
|
if (text2 === undefined)
|
|
17746
17765
|
return [];
|
|
17747
|
-
return
|
|
17748
|
-
/* @__PURE__ */ jsxDEV(w.r, {
|
|
17749
|
-
children: /* @__PURE__ */ jsxDEV(w.t, {
|
|
17750
|
-
"xml:space": "preserve",
|
|
17751
|
-
children: ` ${text2}`
|
|
17752
|
-
}, undefined, false, undefined, this)
|
|
17753
|
-
}, undefined, false, undefined, this)
|
|
17754
|
-
];
|
|
17766
|
+
return textToRunElements(` ${text2}`);
|
|
17755
17767
|
}
|
|
17756
17768
|
function TrackedNoteBody({
|
|
17757
17769
|
config,
|
|
@@ -17761,6 +17773,19 @@ function TrackedNoteBody({
|
|
|
17761
17773
|
}) {
|
|
17762
17774
|
const Note = config.kind === "footnote" ? w.footnote : w.endnote;
|
|
17763
17775
|
const BodyRef = config.kind === "footnote" ? w.footnoteRef : w.endnoteRef;
|
|
17776
|
+
const insRuns = [
|
|
17777
|
+
/* @__PURE__ */ jsxDEV(w.r, {
|
|
17778
|
+
children: [
|
|
17779
|
+
/* @__PURE__ */ jsxDEV(w.rPr, {
|
|
17780
|
+
children: /* @__PURE__ */ jsxDEV(w.rStyle, {
|
|
17781
|
+
"w-val": config.referenceStyle
|
|
17782
|
+
}, undefined, false, undefined, this)
|
|
17783
|
+
}, undefined, false, undefined, this),
|
|
17784
|
+
/* @__PURE__ */ jsxDEV(BodyRef, {}, undefined, false, undefined, this)
|
|
17785
|
+
]
|
|
17786
|
+
}, undefined, true, undefined, this),
|
|
17787
|
+
...textToRunElements(` ${text2}`)
|
|
17788
|
+
];
|
|
17764
17789
|
return /* @__PURE__ */ jsxDEV(Note, {
|
|
17765
17790
|
"w-id": id,
|
|
17766
17791
|
children: /* @__PURE__ */ jsxDEV(w.p, {
|
|
@@ -17772,25 +17797,8 @@ function TrackedNoteBody({
|
|
|
17772
17797
|
}, undefined, false, undefined, this),
|
|
17773
17798
|
/* @__PURE__ */ jsxDEV(Ins, {
|
|
17774
17799
|
meta,
|
|
17775
|
-
children:
|
|
17776
|
-
|
|
17777
|
-
children: [
|
|
17778
|
-
/* @__PURE__ */ jsxDEV(w.rPr, {
|
|
17779
|
-
children: /* @__PURE__ */ jsxDEV(w.rStyle, {
|
|
17780
|
-
"w-val": config.referenceStyle
|
|
17781
|
-
}, undefined, false, undefined, this)
|
|
17782
|
-
}, undefined, false, undefined, this),
|
|
17783
|
-
/* @__PURE__ */ jsxDEV(BodyRef, {}, undefined, false, undefined, this)
|
|
17784
|
-
]
|
|
17785
|
-
}, undefined, true, undefined, this),
|
|
17786
|
-
/* @__PURE__ */ jsxDEV(w.r, {
|
|
17787
|
-
children: /* @__PURE__ */ jsxDEV(w.t, {
|
|
17788
|
-
"xml:space": "preserve",
|
|
17789
|
-
children: ` ${text2}`
|
|
17790
|
-
}, undefined, false, undefined, this)
|
|
17791
|
-
}, undefined, false, undefined, this)
|
|
17792
|
-
]
|
|
17793
|
-
}, undefined, true, undefined, this)
|
|
17800
|
+
children: insRuns
|
|
17801
|
+
}, undefined, false, undefined, this)
|
|
17794
17802
|
]
|
|
17795
17803
|
}, undefined, true, undefined, this)
|
|
17796
17804
|
}, undefined, false, undefined, this);
|
|
@@ -17831,15 +17839,9 @@ function wrapNoteBodyAsEdited(noteBody, newText, insMeta, delMeta) {
|
|
|
17831
17839
|
continue;
|
|
17832
17840
|
}
|
|
17833
17841
|
if (!inserted) {
|
|
17834
|
-
const newRun = /* @__PURE__ */ jsxDEV(w.r, {
|
|
17835
|
-
children: /* @__PURE__ */ jsxDEV(w.t, {
|
|
17836
|
-
"xml:space": "preserve",
|
|
17837
|
-
children: newText
|
|
17838
|
-
}, undefined, false, undefined, this)
|
|
17839
|
-
}, undefined, false, undefined, this);
|
|
17840
17842
|
result.push(/* @__PURE__ */ jsxDEV(Ins, {
|
|
17841
17843
|
meta: insMeta,
|
|
17842
|
-
children:
|
|
17844
|
+
children: textToRunElements(newText)
|
|
17843
17845
|
}, undefined, false, undefined, this));
|
|
17844
17846
|
inserted = true;
|
|
17845
17847
|
}
|
|
@@ -17849,15 +17851,9 @@ function wrapNoteBodyAsEdited(noteBody, newText, insMeta, delMeta) {
|
|
|
17849
17851
|
}, undefined, false, undefined, this));
|
|
17850
17852
|
}
|
|
17851
17853
|
if (!inserted) {
|
|
17852
|
-
const newRun = /* @__PURE__ */ jsxDEV(w.r, {
|
|
17853
|
-
children: /* @__PURE__ */ jsxDEV(w.t, {
|
|
17854
|
-
"xml:space": "preserve",
|
|
17855
|
-
children: newText
|
|
17856
|
-
}, undefined, false, undefined, this)
|
|
17857
|
-
}, undefined, false, undefined, this);
|
|
17858
17854
|
result.push(/* @__PURE__ */ jsxDEV(Ins, {
|
|
17859
17855
|
meta: insMeta,
|
|
17860
|
-
children:
|
|
17856
|
+
children: textToRunElements(newText)
|
|
17861
17857
|
}, undefined, false, undefined, this));
|
|
17862
17858
|
}
|
|
17863
17859
|
paragraph.children = result;
|
|
@@ -17885,6 +17881,7 @@ function isBareWhitespaceRun(run) {
|
|
|
17885
17881
|
return saw;
|
|
17886
17882
|
}
|
|
17887
17883
|
var init_emit3 = __esm(() => {
|
|
17884
|
+
init_blocks();
|
|
17888
17885
|
init_jsx();
|
|
17889
17886
|
init_track_changes();
|
|
17890
17887
|
init_emit2();
|
|
@@ -21138,6 +21135,9 @@ function nodeText(node) {
|
|
|
21138
21135
|
out += child2.collectText();
|
|
21139
21136
|
else if (child2.tag === "w:tab")
|
|
21140
21137
|
out += "\t";
|
|
21138
|
+
else if (child2.tag === "w:br" || child2.tag === "w:cr")
|
|
21139
|
+
out += `
|
|
21140
|
+
`;
|
|
21141
21141
|
}
|
|
21142
21142
|
return out;
|
|
21143
21143
|
}
|
|
@@ -23700,7 +23700,7 @@ class CommentsView {
|
|
|
23700
23700
|
const author = child2.getAttribute("w:author") ?? "";
|
|
23701
23701
|
const date = child2.getAttribute("w:date") ?? "";
|
|
23702
23702
|
const initials = child2.getAttribute("w:initials");
|
|
23703
|
-
const text2 = child2.
|
|
23703
|
+
const text2 = child2.collectTextWithBreaks();
|
|
23704
23704
|
const anchor = anchors.get(commentId) ?? {
|
|
23705
23705
|
startBlockId: "",
|
|
23706
23706
|
startOffset: 0,
|
|
@@ -24218,7 +24218,7 @@ class NotesView {
|
|
|
24218
24218
|
const numericId = child2.getAttribute("w:id");
|
|
24219
24219
|
if (numericId == null)
|
|
24220
24220
|
continue;
|
|
24221
|
-
const text2 = child2.
|
|
24221
|
+
const text2 = child2.collectTextWithBreaks().trim();
|
|
24222
24222
|
out.push({ id: `${config.idPrefix}${numericId}`, text: text2 });
|
|
24223
24223
|
}
|
|
24224
24224
|
return out;
|
|
@@ -35447,12 +35447,7 @@ function CommentBody({
|
|
|
35447
35447
|
children: /* @__PURE__ */ jsxDEV(w.p, {
|
|
35448
35448
|
"w14:paraId": options.paraId,
|
|
35449
35449
|
"w14:textId": "00000000",
|
|
35450
|
-
children:
|
|
35451
|
-
children: /* @__PURE__ */ jsxDEV(w.t, {
|
|
35452
|
-
"xml:space": "preserve",
|
|
35453
|
-
children: options.text
|
|
35454
|
-
}, undefined, false, undefined, this)
|
|
35455
|
-
}, undefined, false, undefined, this)
|
|
35450
|
+
children: textToRunElements(options.text)
|
|
35456
35451
|
}, undefined, false, undefined, this)
|
|
35457
35452
|
}, undefined, false, undefined, this);
|
|
35458
35453
|
}
|
|
@@ -35519,6 +35514,7 @@ function containsCommentReference(run, numericId) {
|
|
|
35519
35514
|
var SpanOutOfRangeError;
|
|
35520
35515
|
var init_markers = __esm(() => {
|
|
35521
35516
|
init_comments();
|
|
35517
|
+
init_blocks();
|
|
35522
35518
|
init_jsx();
|
|
35523
35519
|
init_parser();
|
|
35524
35520
|
init_jsx_dev_runtime();
|
|
@@ -74332,7 +74328,7 @@ function buildContentParagraph(spec, contentWidth) {
|
|
|
74332
74328
|
}, undefined, false, undefined, this)
|
|
74333
74329
|
}, undefined, false, undefined, this)
|
|
74334
74330
|
}, undefined, false, undefined, this),
|
|
74335
|
-
|
|
74331
|
+
textToRunElements(spec.text),
|
|
74336
74332
|
/* @__PURE__ */ jsxDEV(w.r, {
|
|
74337
74333
|
children: /* @__PURE__ */ jsxDEV(w.tab, {}, undefined, false, undefined, this)
|
|
74338
74334
|
}, undefined, false, undefined, this),
|
|
@@ -74357,7 +74353,7 @@ function buildContentParagraph(spec, contentWidth) {
|
|
|
74357
74353
|
alignment ? /* @__PURE__ */ jsxDEV(w.pPr, {
|
|
74358
74354
|
children: alignment
|
|
74359
74355
|
}, undefined, false, undefined, this) : null,
|
|
74360
|
-
hasText ?
|
|
74356
|
+
hasText ? textToRunElements(spec.text) : null
|
|
74361
74357
|
]
|
|
74362
74358
|
}, undefined, true, undefined, this);
|
|
74363
74359
|
}
|
|
@@ -74368,22 +74364,14 @@ function alignChild(align) {
|
|
|
74368
74364
|
"w-val": align
|
|
74369
74365
|
}, undefined, false, undefined, this);
|
|
74370
74366
|
}
|
|
74371
|
-
function textRun(text6) {
|
|
74372
|
-
return /* @__PURE__ */ jsxDEV(w.r, {
|
|
74373
|
-
children: /* @__PURE__ */ jsxDEV(w.t, {
|
|
74374
|
-
"xml:space": "preserve",
|
|
74375
|
-
children: text6
|
|
74376
|
-
}, undefined, false, undefined, this)
|
|
74377
|
-
}, undefined, false, undefined, this);
|
|
74378
|
-
}
|
|
74379
74367
|
function fieldRuns(field) {
|
|
74380
74368
|
switch (field.type) {
|
|
74381
74369
|
case "page":
|
|
74382
74370
|
if (field.ofPages) {
|
|
74383
74371
|
return [
|
|
74384
|
-
|
|
74372
|
+
...textToRunElements("Page "),
|
|
74385
74373
|
fieldSimple(" PAGE ", "1"),
|
|
74386
|
-
|
|
74374
|
+
...textToRunElements(" of "),
|
|
74387
74375
|
fieldSimple(" NUMPAGES ", "1")
|
|
74388
74376
|
];
|
|
74389
74377
|
}
|
|
@@ -74445,6 +74433,7 @@ function relationshipTarget(partName) {
|
|
|
74445
74433
|
}
|
|
74446
74434
|
var NS_W3 = "http://schemas.openxmlformats.org/wordprocessingml/2006/main", NS_R2 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
74447
74435
|
var init_marginals2 = __esm(() => {
|
|
74436
|
+
init_blocks();
|
|
74448
74437
|
init_jsx();
|
|
74449
74438
|
init_sections();
|
|
74450
74439
|
init_track_changes();
|
|
@@ -82687,7 +82676,7 @@ async function resolveBlockOrFail(document4, locator) {
|
|
|
82687
82676
|
return document4.body.resolveBlock(locator);
|
|
82688
82677
|
} catch (err) {
|
|
82689
82678
|
if (err instanceof LocatorResolveError) {
|
|
82690
|
-
return await fail("BLOCK_NOT_FOUND", err.message);
|
|
82679
|
+
return await fail("BLOCK_NOT_FOUND", err.message, STALE_LOCATOR_HINT);
|
|
82691
82680
|
}
|
|
82692
82681
|
throw err;
|
|
82693
82682
|
}
|
|
@@ -82737,7 +82726,7 @@ async function resolveBlockRangeOrFail(document4, locator) {
|
|
|
82737
82726
|
return await fail("INVALID_LOCATOR", err.message);
|
|
82738
82727
|
}
|
|
82739
82728
|
if (err instanceof LocatorResolveError) {
|
|
82740
|
-
return await fail("BLOCK_NOT_FOUND", err.message);
|
|
82729
|
+
return await fail("BLOCK_NOT_FOUND", err.message, STALE_LOCATOR_HINT);
|
|
82741
82730
|
}
|
|
82742
82731
|
throw err;
|
|
82743
82732
|
}
|
|
@@ -82746,7 +82735,7 @@ var EXIT2, stdout = async (text6) => {
|
|
|
82746
82735
|
await Bun.stdout.write(text6);
|
|
82747
82736
|
}, stderr = async (text6) => {
|
|
82748
82737
|
await Bun.stderr.write(text6);
|
|
82749
|
-
}, sinks, verboseAck = false, SAVE_FLAGS;
|
|
82738
|
+
}, sinks, verboseAck = false, STALE_LOCATOR_HINT = "Locator ids are positional and shift after structural edits (insert/delete/section changes) \u2014 an id from an earlier read may now point elsewhere or be gone. Re-read the file to get current ids, then retry. Applying several changes? Do them from ONE read with --batch (edit/insert/delete/replace/comments) so ids never go stale mid-run.", SAVE_FLAGS;
|
|
82750
82739
|
var init_respond = __esm(() => {
|
|
82751
82740
|
init_core2();
|
|
82752
82741
|
EXIT2 = {
|
|
@@ -82797,6 +82786,12 @@ async function rejectShellMangledValue(text6, help, label = "this value") {
|
|
|
82797
82786
|
return await fail("USAGE", `${label} contains "${fragment}" \u2014 a number with no integer part, the signature of a "$" amount gutted by the shell (bash turns double-quoted "$300.00" into ".00" and "$10,000" into ",000"). docx would write the corrupted value verbatim.`, `Wrap any "$"-bearing value in SINGLE quotes ('$300.00') so bash leaves it alone, or supply it via --batch FILE (JSONL never touches the shell). If you really mean "${fragment}", write its integer part (0${fragment}) or use --batch. Help:
|
|
82798
82787
|
${help}`);
|
|
82799
82788
|
}
|
|
82789
|
+
function decodeInlineEscapes(value) {
|
|
82790
|
+
if (value === undefined)
|
|
82791
|
+
return;
|
|
82792
|
+
return value.replace(/\\r\\n|\\[nrt]/g, (match) => match === "\\t" ? "\t" : `
|
|
82793
|
+
`);
|
|
82794
|
+
}
|
|
82800
82795
|
function parseTaskFlag(value) {
|
|
82801
82796
|
const normalized = value.toLowerCase();
|
|
82802
82797
|
if (normalized === "checked" || normalized === "true" || normalized === "1")
|
|
@@ -83206,7 +83201,7 @@ async function run(args) {
|
|
|
83206
83201
|
const atInput = parsed.values.at;
|
|
83207
83202
|
const anchorInput = parsed.values.anchor;
|
|
83208
83203
|
const batchInput = parsed.values.batch;
|
|
83209
|
-
const text6 = parsed.values.text;
|
|
83204
|
+
const text6 = decodeInlineEscapes(parsed.values.text);
|
|
83210
83205
|
const occurrenceRaw = parsed.values.occurrence;
|
|
83211
83206
|
const defaultAuthor = resolveAuthor(parsed.values.author);
|
|
83212
83207
|
const outputPath = parsed.values.output;
|
|
@@ -83690,7 +83685,7 @@ async function run4(args) {
|
|
|
83690
83685
|
if (!path2)
|
|
83691
83686
|
return fail("USAGE", "Missing FILE argument", HELP4);
|
|
83692
83687
|
const parentInput = parsed.values.at;
|
|
83693
|
-
const text6 = parsed.values.text;
|
|
83688
|
+
const text6 = decodeInlineEscapes(parsed.values.text);
|
|
83694
83689
|
if (!parentInput)
|
|
83695
83690
|
return fail("USAGE", "Missing --at cN", HELP4);
|
|
83696
83691
|
if (!text6)
|
|
@@ -83764,6 +83759,7 @@ Examples:
|
|
|
83764
83759
|
`;
|
|
83765
83760
|
var init_reply = __esm(() => {
|
|
83766
83761
|
init_core2();
|
|
83762
|
+
init_parse_helpers();
|
|
83767
83763
|
init_respond();
|
|
83768
83764
|
});
|
|
83769
83765
|
|
|
@@ -84077,12 +84073,7 @@ function DocumentBody({ text: text6 }) {
|
|
|
84077
84073
|
children: /* @__PURE__ */ jsxDEV(w.body, {
|
|
84078
84074
|
children: [
|
|
84079
84075
|
text6 !== undefined ? /* @__PURE__ */ jsxDEV(w.p, {
|
|
84080
|
-
children:
|
|
84081
|
-
children: /* @__PURE__ */ jsxDEV(w.t, {
|
|
84082
|
-
"xml:space": "preserve",
|
|
84083
|
-
children: text6
|
|
84084
|
-
}, undefined, false, undefined, this)
|
|
84085
|
-
}, undefined, false, undefined, this)
|
|
84076
|
+
children: textToRunElements(text6)
|
|
84086
84077
|
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV(w.p, {}, undefined, false, undefined, this),
|
|
84087
84078
|
/* @__PURE__ */ jsxDEV(DefaultSectionProperties, {}, undefined, false, undefined, this)
|
|
84088
84079
|
]
|
|
@@ -84180,6 +84171,7 @@ function serializeWithDeclaration(root2) {
|
|
|
84180
84171
|
}
|
|
84181
84172
|
var DOC_NAMESPACES, CONTENT_TYPES, ROOT_RELS, DOCUMENT_RELS;
|
|
84182
84173
|
var init_template = __esm(() => {
|
|
84174
|
+
init_blocks();
|
|
84183
84175
|
init_jsx();
|
|
84184
84176
|
init_parser();
|
|
84185
84177
|
init_canonical_parts();
|
|
@@ -84260,7 +84252,7 @@ async function run7(args) {
|
|
|
84260
84252
|
if (!path2) {
|
|
84261
84253
|
return fail("USAGE", "Missing FILE argument", HELP7);
|
|
84262
84254
|
}
|
|
84263
|
-
const text6 = parsed.values.text;
|
|
84255
|
+
const text6 = decodeInlineEscapes(parsed.values.text);
|
|
84264
84256
|
const fromPath = parsed.values.from;
|
|
84265
84257
|
const textFilePath = parsed.values["text-file"];
|
|
84266
84258
|
const contentSources = [text6, fromPath, textFilePath].filter((value) => value !== undefined);
|
|
@@ -85841,7 +85833,7 @@ async function validateParagraphEdit(values2, paragraphOptions) {
|
|
|
85841
85833
|
return { kind: "clear", tags };
|
|
85842
85834
|
}
|
|
85843
85835
|
}
|
|
85844
|
-
const text6 = values2.text;
|
|
85836
|
+
const text6 = decodeInlineEscapes(values2.text);
|
|
85845
85837
|
const runsJson = values2.runs;
|
|
85846
85838
|
const codeInline = values2.code;
|
|
85847
85839
|
const codeFile = values2["code-file"];
|
|
@@ -85895,7 +85887,7 @@ async function validateParagraphEdit(values2, paragraphOptions) {
|
|
|
85895
85887
|
}
|
|
85896
85888
|
return { kind: "task", checked };
|
|
85897
85889
|
}
|
|
85898
|
-
const markdownInline = values2.markdown;
|
|
85890
|
+
const markdownInline = decodeInlineEscapes(values2.markdown);
|
|
85899
85891
|
const markdownFile = values2["markdown-file"];
|
|
85900
85892
|
const contentFlags = [
|
|
85901
85893
|
text6 !== undefined,
|
|
@@ -86249,9 +86241,12 @@ General options:
|
|
|
86249
86241
|
-h, --help Show this help
|
|
86250
86242
|
|
|
86251
86243
|
Output:
|
|
86252
|
-
Prints a one-line confirmation on success (exit 0) \u2014
|
|
86253
|
-
nothing to mint. --verbose prints {ok:true, operation,
|
|
86254
|
-
Errors print {code, error, hint?} with a nonzero exit.
|
|
86244
|
+
Prints a one-line confirmation on success (exit 0) \u2014 an in-place edit shifts nothing, so the
|
|
86245
|
+
edited locator is unchanged and there's nothing to mint. --verbose prints {ok:true, operation,
|
|
86246
|
+
path, locator}. Errors print {code, error, hint?} with a nonzero exit.
|
|
86247
|
+
Heads up: a locator you hold from BEFORE a structural edit (an insert/delete elsewhere renumbers
|
|
86248
|
+
ids) is stale \u2014 it lands on the wrong block or errors BLOCK_NOT_FOUND. Re-read after any
|
|
86249
|
+
insert/delete, or apply the whole set from one read with --batch (above). Discover ids with
|
|
86255
86250
|
\`docx read FILE --ast\` (equation ids appear on EquationRun nodes).
|
|
86256
86251
|
|
|
86257
86252
|
Examples:
|
|
@@ -86442,9 +86437,9 @@ async function runAddNote(args, kind) {
|
|
|
86442
86437
|
if (anchorCount > 1) {
|
|
86443
86438
|
return fail("USAGE", "--at and --anchor are mutually exclusive", help);
|
|
86444
86439
|
}
|
|
86445
|
-
const text6 = parsed.values.text;
|
|
86440
|
+
const text6 = decodeInlineEscapes(parsed.values.text);
|
|
86446
86441
|
const runsJson = parsed.values.runs;
|
|
86447
|
-
const markdown2 = parsed.values.markdown;
|
|
86442
|
+
const markdown2 = decodeInlineEscapes(parsed.values.markdown);
|
|
86448
86443
|
const markdownFile = parsed.values["markdown-file"];
|
|
86449
86444
|
const bodyCount = (text6 !== undefined ? 1 : 0) + (runsJson !== undefined ? 1 : 0) + (markdown2 !== undefined ? 1 : 0) + (markdownFile !== undefined ? 1 : 0);
|
|
86450
86445
|
if (bodyCount === 0) {
|
|
@@ -86868,9 +86863,9 @@ async function runEditNote(args, kind) {
|
|
|
86868
86863
|
const config = noteConfig(kind);
|
|
86869
86864
|
if (!idInput)
|
|
86870
86865
|
return fail("USAGE", `Missing --at ${config.idPrefix}N`, help);
|
|
86871
|
-
const text6 = parsed.values.text;
|
|
86866
|
+
const text6 = decodeInlineEscapes(parsed.values.text);
|
|
86872
86867
|
const runsJson = parsed.values.runs;
|
|
86873
|
-
const markdown2 = parsed.values.markdown;
|
|
86868
|
+
const markdown2 = decodeInlineEscapes(parsed.values.markdown);
|
|
86874
86869
|
const markdownFile = parsed.values["markdown-file"];
|
|
86875
86870
|
const bodyCount = (text6 !== undefined ? 1 : 0) + (runsJson !== undefined ? 1 : 0) + (markdown2 !== undefined ? 1 : 0) + (markdownFile !== undefined ? 1 : 0);
|
|
86876
86871
|
if (bodyCount === 0) {
|
|
@@ -87645,7 +87640,7 @@ async function runSetMarginal(args, kind) {
|
|
|
87645
87640
|
if (align !== undefined && !isAlign(align)) {
|
|
87646
87641
|
return fail("USAGE", `Invalid --align: ${align}`, "Valid: left, center, right.");
|
|
87647
87642
|
}
|
|
87648
|
-
const text6 = parsed.values.text;
|
|
87643
|
+
const text6 = decodeInlineEscapes(parsed.values.text);
|
|
87649
87644
|
if (text6 === undefined && field === undefined) {
|
|
87650
87645
|
return fail("USAGE", `Nothing to set \u2014 pass --text and/or a field (--page-number/--date/--style-ref/--field).`, helpFor7(kind));
|
|
87651
87646
|
}
|
|
@@ -87740,6 +87735,7 @@ var OPTION_SPEC4, SAVE_FLAGS_HELP = `Output:
|
|
|
87740
87735
|
-h, --help Show this help`;
|
|
87741
87736
|
var init_set = __esm(() => {
|
|
87742
87737
|
init_core2();
|
|
87738
|
+
init_parse_helpers();
|
|
87743
87739
|
init_respond();
|
|
87744
87740
|
init_shared();
|
|
87745
87741
|
OPTION_SPEC4 = {
|
|
@@ -88879,10 +88875,10 @@ async function buildSingleShotOptions(filePath, values2) {
|
|
|
88879
88875
|
if (typeof spec === "number")
|
|
88880
88876
|
return spec;
|
|
88881
88877
|
if (spec.kind === "text") {
|
|
88882
|
-
const rejected = await rejectMarkdownInText(
|
|
88878
|
+
const rejected = await rejectMarkdownInText(spec.text, HELP20);
|
|
88883
88879
|
if (typeof rejected === "number")
|
|
88884
88880
|
return rejected;
|
|
88885
|
-
const mangled = await rejectShellMangledValue(
|
|
88881
|
+
const mangled = await rejectShellMangledValue(spec.text, HELP20, "--text");
|
|
88886
88882
|
if (typeof mangled === "number")
|
|
88887
88883
|
return mangled;
|
|
88888
88884
|
}
|
|
@@ -89022,7 +89018,7 @@ async function chooseContentSpec(values2) {
|
|
|
89022
89018
|
}
|
|
89023
89019
|
async function resolveMarkdownSpec(values2, flag) {
|
|
89024
89020
|
if (flag === "markdown") {
|
|
89025
|
-
const source2 = values2.markdown;
|
|
89021
|
+
const source2 = decodeInlineEscapes(values2.markdown);
|
|
89026
89022
|
return { kind: "markdown", source: source2 };
|
|
89027
89023
|
}
|
|
89028
89024
|
const path2 = values2["markdown-file"];
|
|
@@ -89067,7 +89063,7 @@ async function parseImageFlags(values2) {
|
|
|
89067
89063
|
const alt = values2.alt;
|
|
89068
89064
|
if (alt !== undefined)
|
|
89069
89065
|
out.alt = alt;
|
|
89070
|
-
const caption = values2.caption;
|
|
89066
|
+
const caption = decodeInlineEscapes(values2.caption);
|
|
89071
89067
|
if (caption !== undefined)
|
|
89072
89068
|
out.caption = caption;
|
|
89073
89069
|
const widthRaw = values2.width;
|
|
@@ -89092,7 +89088,7 @@ function buildTextSpec(values2) {
|
|
|
89092
89088
|
const url = values2.url;
|
|
89093
89089
|
return {
|
|
89094
89090
|
kind: "text",
|
|
89095
|
-
text: values2.text,
|
|
89091
|
+
text: decodeInlineEscapes(values2.text),
|
|
89096
89092
|
format: {
|
|
89097
89093
|
color: values2.color,
|
|
89098
89094
|
bold: values2.bold,
|
|
@@ -91608,7 +91604,7 @@ function formatNote(type, pairs, bareTokens = []) {
|
|
|
91608
91604
|
return `<!-- ${parts.join(" ")} -->`;
|
|
91609
91605
|
}
|
|
91610
91606
|
function htmlAttr(key, value) {
|
|
91611
|
-
const escaped = value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
91607
|
+
const escaped = value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/\n/g, " ").replace(/\r/g, " ").replace(/\t/g, "	");
|
|
91612
91608
|
return `${key}="${escaped}"`;
|
|
91613
91609
|
}
|
|
91614
91610
|
function twipsToInches(twips) {
|
|
@@ -98021,7 +98017,7 @@ Examples:
|
|
|
98021
98017
|
// package.json
|
|
98022
98018
|
var package_default = {
|
|
98023
98019
|
name: "bun-docx",
|
|
98024
|
-
version: "0.
|
|
98020
|
+
version: "0.20.1",
|
|
98025
98021
|
description: "Read, edit, redline, and comment on Microsoft Word .docx files from the command line \u2014 built for AI agents.",
|
|
98026
98022
|
keywords: [
|
|
98027
98023
|
"docx",
|
|
@@ -98144,11 +98140,13 @@ Commands (each one-liner names capabilities you'd otherwise miss; see <command>
|
|
|
98144
98140
|
It is highly recommended to run "docx info locators" and "docx info schema" (neither needs a FILE) to understand the addressing model and AST.
|
|
98145
98141
|
Run "docx <command> --help" for command-specific help.
|
|
98146
98142
|
|
|
98147
|
-
BATCH MANY CHANGES IN ONE READ:
|
|
98148
|
-
one-at-a-time
|
|
98149
|
-
|
|
98150
|
-
|
|
98151
|
-
|
|
98143
|
+
BATCH MANY CHANGES IN ONE READ: locator ids are positional and shift after structural
|
|
98144
|
+
edits (insert/delete/section changes), so going one-at-a-time forces a re-read to refresh
|
|
98145
|
+
ids after each. Miss the change and the next command lands on the wrong block or errors
|
|
98146
|
+
BLOCK_NOT_FOUND. Skip all that: edit / insert / replace / delete and comments
|
|
98147
|
+
(add/resolve/delete) all take --batch FILE.jsonl (one JSON change per line; "-" reads
|
|
98148
|
+
stdin). Every locator addresses the document AS READ, so ids stay valid across the whole
|
|
98149
|
+
batch \u2014 one read, one write, no re-reading between changes. See "<command> --help".
|
|
98152
98150
|
|
|
98153
98151
|
FILL FORMATTED / TABBED LINES WITHOUT REBUILDING RUNS: to fill a template line that
|
|
98154
98152
|
carries formatting (bold/font) or tab stops \u2014 e.g. "**Org Name**\u21E5Date" \u2014 replace just
|