xlsx-for-ai 1.4.0 → 1.4.2
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 +7 -5
- package/WHY.md +46 -9
- package/index.js +38 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
> 👋 **New here? Not a programmer?** → [Read WHY.md for the plain-English version](WHY.md). The README below is the technical reference.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**The bidirectional bridge between spreadsheets and AI agents.** Reads `.xlsx` (and `.xls`, `.xlsb`, `.ods`, `.csv`, `.tsv`) into the formats LLMs actually consume — markdown, JSON, text, SQL — and writes spreadsheets back out from AI-generated specs. Same tool, both directions.
|
|
6
6
|
|
|
7
|
-
AI tools — Claude, Cursor, Copilot, ChatGPT, and other LLM coding agents — can read text files but **not** `.xlsx` binaries. This CLI
|
|
7
|
+
AI tools — Claude, Cursor, Copilot, ChatGPT, and other LLM coding agents — can read text files but **not** `.xlsx` binaries. This CLI closes the loop:
|
|
8
8
|
|
|
9
|
-
**
|
|
9
|
+
**📖 Read mode (default)** — turn any spreadsheet into LLM-readable output. Every formula, every named range, every merged cell, every fill color, every cross-sheet reference. No more pasting numbers and losing context.
|
|
10
|
+
|
|
11
|
+
**✍️ Write mode (`xlsx-for-ai write`)** — turn an AI-generated JSON or markdown spec into a real `.xlsx` file. Closes the round-trip so an agent that *reviews* your spreadsheet can also *deliver the corrected file*. The output includes a `_xlsx-for-ai` review tab explaining every structural change the round-trip made (with risks, tradeoffs, and overrides) — the supervisor model: AI does the work, the human stays in control of every decision. Verified lossless on 29/30 real workbooks.
|
|
10
12
|
|
|
11
|
-
**
|
|
13
|
+
**Input formats:** `.xlsx` `.xls` `.xlsb` `.ods` `.csv` `.tsv`
|
|
12
14
|
|
|
13
|
-
**
|
|
15
|
+
**Output modes:** text dump, markdown tables (best LLM comprehension per token), JSON, SQL `CREATE TABLE`+`INSERT`, inferred schema, workbook diff, real `.xlsx` (write mode).
|
|
14
16
|
|
|
15
17
|
It extracts everything a human would see in Excel:
|
|
16
18
|
|
package/WHY.md
CHANGED
|
@@ -27,26 +27,63 @@ That's the difference between a friend skimming the printed numbers and an analy
|
|
|
27
27
|
A few examples people find useful:
|
|
28
28
|
|
|
29
29
|
- **Have your AI find errors in a financial model** before you send it to your accountant or your board.
|
|
30
|
-
- **Have your AI hand you back a corrected version** — not just *say* what should change, but actually produce the fixed `.xlsx` with the changes applied. The corrected file even includes a built-in review note explaining what the AI changed, why, and how to override anything you don't agree with. Same shape as having a careful editor mark up your draft.
|
|
31
30
|
- **Compare two versions of the same spreadsheet** ("what changed between V11 and V14?") and get a list of every cell that moved.
|
|
32
31
|
- **Turn a CSV export from QuickBooks into a clean SQL database table** in one command, with the column types figured out automatically.
|
|
33
32
|
- **Walk through a 50-tab model someone else built** and have the AI explain how the sheets reference each other.
|
|
34
33
|
- **Process a folder of legacy `.xls` files** that won't even open in modern Excel without complaint.
|
|
35
34
|
|
|
36
|
-
|
|
35
|
+
But the biggest unlock is the next thing.
|
|
37
36
|
|
|
38
|
-
|
|
37
|
+
## Now your AI can hand you back the file — not just words
|
|
39
38
|
|
|
40
|
-
|
|
39
|
+
Before, even once AI could read your spreadsheet, it could only *tell* you what to change. You'd still have to translate its advice into actual cell edits yourself. Tedious for two cells. Impossible for fifty.
|
|
40
|
+
|
|
41
|
+
Now the AI can do the editing for you. Same starting moment — you ask Claude to review your tax estimate, or update Q4 numbers in your forecast, or fix a broken cap table — but instead of describing the corrections, it builds you the actual fixed `.xlsx` and hands it back.
|
|
42
|
+
|
|
43
|
+
A real moment that gets unlocked:
|
|
44
|
+
|
|
45
|
+
> **You:** *"Here's our 2026 budget V11. Sales asked us to add a Travel line and bump Marketing to $52K each quarter. Update it."*
|
|
46
|
+
>
|
|
47
|
+
> **Claude (after a moment):** *"Done. I added a Travel row at the bottom with placeholder zeros (since you didn't give numbers), bumped Marketing to $52,000 across all four quarters, and updated the totals row to reflect the new sum. Here's V12 — I left a note in the file explaining everything I did."*
|
|
48
|
+
|
|
49
|
+
You open V12 in Excel. Marketing is updated. Travel exists. Totals are right. Then you flip to the rightmost tab — `_xlsx-for-ai` — and find what looks like a careful editor's notes on the changes.
|
|
50
|
+
|
|
51
|
+
## What's in the review tab
|
|
52
|
+
|
|
53
|
+
It's the AI's note to you about exactly what it changed and why, written in plain English. For each kind of change, you get a small block like this:
|
|
54
|
+
|
|
55
|
+
> **Issue: Marketing line update** *(4 cells)*
|
|
56
|
+
>
|
|
57
|
+
> **What happened.** You asked to bump Marketing to $52,000 per quarter.
|
|
58
|
+
>
|
|
59
|
+
> **What we did.** Updated B12, C12, D12, E12 to $52,000 each.
|
|
60
|
+
>
|
|
61
|
+
> **Risk.** The totals row (row 20) recomputes automatically — confirm the new bottom-line totals match what you expected.
|
|
62
|
+
>
|
|
63
|
+
> **Alternative.** If you wanted Marketing scaled differently per quarter (e.g., higher in Q4), tell me and I'll redo it.
|
|
41
64
|
|
|
42
|
-
|
|
65
|
+
You can read the whole tab in 30 seconds. Then you either accept what the AI did, or push back on any individual item. Same shape as a careful editor marking up your draft — observation, reasoning, and a clear way to override.
|
|
43
66
|
|
|
44
|
-
|
|
67
|
+
This is on purpose. The tool is designed around the **supervisor** model: AI does the work, but the human stays in control of every decision. The review tab is what makes that real — without it, the AI would be making silent changes you'd only discover by accident later. With it, every choice the AI made is visible, named, and reversible.
|
|
45
68
|
|
|
46
|
-
|
|
47
|
-
- **Writing:** turns the AI's response back into a real `.xlsx` file you can open, edit, and share. The AI can now hand you a corrected workbook, not just words about it.
|
|
69
|
+
## Why this matters
|
|
48
70
|
|
|
49
|
-
|
|
71
|
+
Without the corrected file, AI is a really expensive consultant. It looks at your spreadsheet, talks for a while, and leaves you with a list of things to do yourself. No leverage on the actual work.
|
|
72
|
+
|
|
73
|
+
With the corrected file, AI is more like a junior analyst. It does the work, hands you the result, explains its reasoning, and waits for your review. Same role you've always wanted — without the hourly rate.
|
|
74
|
+
|
|
75
|
+
## How to actually use it
|
|
76
|
+
|
|
77
|
+
You don't run anything. Your AI does.
|
|
78
|
+
|
|
79
|
+
1. **Install once.** A programmer (or you, if you're comfortable with one terminal command) runs `npm install -g xlsx-for-ai`. Then forget about it.
|
|
80
|
+
2. **Drop a file into Claude, Cursor, Copilot, or ChatGPT** (the desktop apps with code execution, or any agent setup that can run commands). The AI picks up the tool automatically when it sees a spreadsheet.
|
|
81
|
+
3. **Ask whatever you want** — review, fix errors, update numbers, generate reports, compare versions, restructure.
|
|
82
|
+
4. **The AI hands back** either a text answer (when that's what you asked for) or a real `.xlsx` file with the review tab (when you asked for changes).
|
|
83
|
+
|
|
84
|
+
Most users never type a command.
|
|
85
|
+
|
|
86
|
+
If you're the programmer doing the install, the [README](README.md) has the full reference. If you're handing this to a programmer to set up for you, that link is what they'll need.
|
|
50
87
|
|
|
51
88
|
## Why this didn't exist before
|
|
52
89
|
|
package/index.js
CHANGED
|
@@ -599,6 +599,23 @@ function dumpSheetJSON(ws, wb, opts = {}) {
|
|
|
599
599
|
if (col.hidden) out.hiddenColumns.push(letter);
|
|
600
600
|
out.columns.push({ letter, width: col.width || null, hidden: !!col.hidden });
|
|
601
601
|
}
|
|
602
|
+
// Some xlsx files set widths on columns past the populated range (e.g.,
|
|
603
|
+
// columns reserved for future data, or styling-only columns). ExcelJS's
|
|
604
|
+
// columnCount stops at populated cells, so a naive loop misses those widths
|
|
605
|
+
// and they silently drop on round-trip. Walk ws.columns directly to pick up
|
|
606
|
+
// any column metadata beyond endCol.
|
|
607
|
+
try {
|
|
608
|
+
const allCols = ws.columns || [];
|
|
609
|
+
for (let i = endCol; i < allCols.length; i++) {
|
|
610
|
+
const col = allCols[i];
|
|
611
|
+
if (!col) continue;
|
|
612
|
+
if (col.width != null || col.hidden) {
|
|
613
|
+
const letter = colLetter(i + 1);
|
|
614
|
+
if (col.hidden) out.hiddenColumns.push(letter);
|
|
615
|
+
out.columns.push({ letter, width: col.width || null, hidden: !!col.hidden });
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
} catch (_) {}
|
|
602
619
|
|
|
603
620
|
if (ws.autoFilter) out.autoFilter = typeof ws.autoFilter === 'string' ? ws.autoFilter : (ws.autoFilter.ref || null);
|
|
604
621
|
try { if (ws.pageSetup?.printArea) out.printArea = ws.pageSetup.printArea; } catch (_) {}
|
|
@@ -1294,6 +1311,20 @@ function buildWorkbook(spec) {
|
|
|
1294
1311
|
try { ws.getColumn(colNum(letter)).width = width; } catch (_) {}
|
|
1295
1312
|
}
|
|
1296
1313
|
}
|
|
1314
|
+
// Also read widths from the `columns` array — that's the shape `--json`
|
|
1315
|
+
// output produces (`columns: [{letter, width, hidden}, ...]`). Without
|
|
1316
|
+
// this, round-tripping a workbook through `--json` → `write` silently
|
|
1317
|
+
// dropped all column widths, breaking the documented round-trip claim.
|
|
1318
|
+
if (Array.isArray(sheet.columns)) {
|
|
1319
|
+
for (const col of sheet.columns) {
|
|
1320
|
+
if (!col || !col.letter) continue;
|
|
1321
|
+
try {
|
|
1322
|
+
const c = ws.getColumn(colNum(col.letter));
|
|
1323
|
+
if (col.width != null) c.width = col.width;
|
|
1324
|
+
if (col.hidden) c.hidden = true;
|
|
1325
|
+
} catch (_) {}
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1297
1328
|
|
|
1298
1329
|
if (Array.isArray(sheet.cells)) {
|
|
1299
1330
|
// Per-cell mode (round-trip from --json). cells: [{ref, value, ...style}, ...]
|
|
@@ -1631,6 +1662,13 @@ async function mainWrite(argv) {
|
|
|
1631
1662
|
async function main() {
|
|
1632
1663
|
const argv = process.argv.slice(2);
|
|
1633
1664
|
|
|
1665
|
+
// --version / -v: short-circuit before any file parsing so users can ask
|
|
1666
|
+
// the version without it being treated as a filename. Mirrors --help.
|
|
1667
|
+
if (argv[0] === '--version' || argv[0] === '-v') {
|
|
1668
|
+
console.log(require('./package.json').version);
|
|
1669
|
+
process.exit(0);
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1634
1672
|
// Sub-command dispatch
|
|
1635
1673
|
if (argv[0] === 'write') return mainWrite(argv.slice(1));
|
|
1636
1674
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xlsx-for-ai",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.2",
|
|
4
4
|
"description": "CLI that converts .xlsx files into rich text or JSON dumps that AI coding agents (Claude, Cursor, Copilot, ChatGPT, etc.) can read — preserving values, formulas, formatting, colors, column widths, frozen panes, named ranges, tables, and more.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|