| name | xlsx-reader |
| description | Use this skill when the user uploads or points to Excel, XLSX, XLS, spreadsheet, or CSV files and wants them read, summarized, searched, filtered, analyzed, previewed, or aggregated. Triggers on phrases like read this spreadsheet, analyze this Excel file, summarize XLSX, extract rows, filter spreadsheet, search Excel, CSV preview, spreadsheet totals, pull sheet names, and what is in this workbook. Use it to inspect sheets with SheetJS, show previews and aggregates, and avoid dumping huge tables. |
| emoji | 🧩 |
| version | 1.1.0 |
| triggers | read spreadsheet, analyze Excel file, summarize XLSX, extract rows, filter spreadsheet, search Excel, CSV preview, spreadsheet totals, pull sheet names, what is in this workbook, read xlsx, read csv, Excel analysis, workbook preview, sheet summary |
XLSX Reader
Read and analyze Excel spreadsheets using the xlsx (SheetJS) npm package. Pure Node — works on Windows with no Python.
DEPENDENCY CHECK — Run First Time Only
node -e "require('xlsx'); console.log('OK')"
Run from D:\Prometheus. If missing: node workspace\doc-skills-setup.js
How It Works
Write a Node script to workspace, run with shell(), parse the JSON output. Same pattern as all document skills.
Core Sheet Extraction
Gets all sheets and their data as JSON arrays:
const XLSX = require('../node_modules/xlsx');
const path = require('path');
const filePath = process.argv[2];
const absPath = path.isAbsolute(filePath) ? filePath : path.join(__dirname, filePath);
const workbook = XLSX.readFile(absPath);
const result = {
file: path.basename(absPath),
sheetNames: workbook.SheetNames,
sheets: {}
};
for (const sheetName of workbook.SheetNames) {
const sheet = workbook.Sheets[sheetName];
const range = XLSX.utils.decode_range(sheet['!ref'] || 'A1');
const rows = XLSX.utils.sheet_to_json(sheet, { header: 1, defval: '' });
const headers = rows[0] || [];
const dataRows = rows.slice(1).filter( r.( c !== ));
result.[sheetName] = {
: dataRows.,
: headers.,
headers,
: dataRows.(, ),
: dataRows.
};
}
.(.(result, , ));
Targeted Sheet Reading (by name)
When the user wants data from a specific sheet:
const XLSX = require('../node_modules/xlsx');
const path = require('path');
const filePath = process.argv[2];
const sheetName = process.argv[3];
const absPath = path.isAbsolute(filePath) ? filePath : path.join(__dirname, filePath);
const workbook = XLSX.readFile(absPath);
const targetSheet = sheetName || workbook.SheetNames[0];
const sheet = workbook.Sheets[targetSheet];
if (!sheet) {
console.log(JSON.stringify({ error: `Sheet "${targetSheet}" not found`, available: workbook.SheetNames }));
process.exit(1);
}
const rows = XLSX.utils.sheet_to_json(sheet, { defval: null });
console.log(JSON.stringify({
: targetSheet,
: rows.,
: .(rows[] || {}),
: rows.(, )
}, , ));
Aggregation / Summary Script
When the user wants totals, averages, or summaries:
const XLSX = require('../node_modules/xlsx');
const path = require('path');
const filePath = process.argv[2];
const absPath = path.isAbsolute(filePath) ? filePath : path.join(__dirname, filePath);
const workbook = XLSX.readFile(absPath);
const sheet = workbook.Sheets[workbook.SheetNames[0]];
const rows = XLSX.utils.sheet_to_json(sheet, { defval: null });
if (rows.length === 0) { console.log('{}'); process.exit(0); }
const columns = Object.keys(rows[0]);
const summary = {};
for (const col of columns) {
const values = rows.map(r => r[col]).filter(v => v !== null && v !== );
numbers = values.( (v)).( !(n));
summary[col] = {
: values.,
: rows. - values.,
: values.(, )
};
(numbers. > ) {
sum = numbers.( a + b, );
summary[col]. = ;
summary[col]. = .(sum * ) / ;
summary[col]. = .((sum / numbers.) * ) / ;
summary[col]. = .(...numbers);
summary[col]. = .(...numbers);
}
}
.(.({ : rows., columns, summary }, , ));
Row Filter / Search
When the user wants rows matching a condition:
const XLSX = require('../node_modules/xlsx');
const path = require('path');
const filePath = process.argv[2];
const filterCol = process.argv[3];
const filterVal = process.argv[4];
const absPath = path.isAbsolute(filePath) ? filePath : path.join(__dirname, filePath);
const workbook = XLSX.readFile(absPath);
const sheet = workbook.Sheets[workbook.SheetNames[0]];
const rows = XLSX.utils.sheet_to_json(sheet, { defval: null });
const matches = rows.filter(row => {
const cellVal = String(row[filterCol] || '').toLowerCase();
return cellVal.includes(filterVal.toLowerCase());
});
console.log(JSON.({
: filterCol,
: filterVal,
: matches.,
: matches.(, )
}, , ));
CSV Files
SheetJS handles CSV too — same API, just reads differently:
const XLSX = require('../node_modules/xlsx');
const path = require('path');
const fs = require('fs');
const filePath = process.argv[2];
const absPath = path.isAbsolute(filePath) ? filePath : path.join(__dirname, filePath);
const workbook = XLSX.read(fs.readFileSync(absPath, 'utf-8'), { type: 'string' });
const sheet = workbook.Sheets[workbook.SheetNames[0]];
const rows = XLSX.utils.sheet_to_json(sheet, { defval: null });
console.log(JSON.stringify({
rowCount: rows.length,
columns: Object.keys(rows[0] || {}),
preview: rows.slice(0, 20)
}, null, 2));
Presenting Results to the User
After extraction, format the data clearly in chat:
- Sheet overview: list sheet names, row counts, column headers
- Data preview: render as markdown table (max 10–15 rows visible)
- Aggregates: present as KPI-style summary (sum, avg, min, max per numeric column)
- Filtered results: show matching rows as markdown table
- Large datasets: summarize and offer to drill down — don't dump 1000 rows
Error Handling
| Error | Fix |
|---|
Cannot find module 'xlsx' | Run node workspace\doc-skills-setup.js from D:\Prometheus |
ENOENT | Wrong file path — confirm with user |
CFB: Corrupted file | File may be corrupted or in wrong format |
.xls (old format) | SheetJS handles .xls too — same code works |
| Empty sheet | Filter out empty rows with .filter(r => r.some(c => c !== '')) |