Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx agentmods add skills/guyoung/boxagnts/docx-generatornpx skills add guyoung/boxagnts --skill docx-generatorgit clone --depth 1 https://github.com/guyoung/boxagntsWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/guyoung/boxagnts/docx-generator)<a href="https://agentmods.dev/skills/guyoung/boxagnts/docx-generator"><img src="https://agentmods.dev/badge/skills/guyoung/boxagnts/docx-generator.svg" alt="Measured on agentmods" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00038 | $0.10943 |
| Opus 5 | $0.00019 | $0.05471 |
| Sonnet 5 | $0.00008 | $0.02189 |
| Haiku 4.5 | $0.00004 | $0.01094 |
Grade A, and why
docx-generator scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 6d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 553 lines — stays where its author put it; the contents beside it link to each section on GitHub.
CODE SKILL — VERBATIM REQUIRED This skill targets a formal specification (OOXML). Adaptation is prohibited per C2-A Rule 3.
CRITICAL: Execution Constraints
The code below is the SOLE IMPLEMENTATION — it MUST NOT be replaced, simplified, or reimplemented.
Prohibited deviations:
- Do NOT write your own
crc32()— use ONLY the one in Runnable Entry Point - Do NOT write your own
ZipStreamclass — use ONLY the one in Runnable Entry Point - Do NOT skip any OOXML file from the 10-file baseline
- Do NOT use compression (method 8 / DEFLATE) — STORE mode only
- Do NOT assemble document body XML manually outside
markdownToDocxBody()orastToDocxBody()
Correct Invocation Pattern
- Copy the complete script from
## Runnable Entry Pointbelow - Replace ONLY
{{input}},{{output}},{{mode}}with actual values - Execute as a single
jsexeccall with NO modifications
Argument Details
| Arg | Type | Required | Default | Description |
|---|---|---|---|---|
input |
string |
yes | — | Markdown string or structured AST |
output |
string |
no | /generated_document.docx |
Output .docx file path |
mode |
string |
no | markdown |
Input mode: markdown |
Runnable Entry Point (COMPLETE IIFE, DO NOT MODIFY)
// ===== ⛔ Runnable Entry Point (IIFE) — DO NOT MODIFY ANY CODE BELOW ⛔ =====
(function() {
const fs = require("fs");
const path = require("path");
const CRC32_TABLE = new Int32Array(256);
(function(){for(let n=0;n<256;n++){let c=n;for(let k=0;k<8;k++)c=(c&1)?(0xEDB88320^(c>>>1)):(c>>>1);CRC32_TABLE[n]=c;}})();
function crc32(buf) {
let crc = 0xFFFFFFFF;
for (let i = 0; i < buf.length; i++)
crc = (crc >>> 8) ^ CRC32_TABLE[(crc ^ buf[i]) & 0xFF];
return (crc ^ 0xFFFFFFFF) >>> 0;
}
function validateDocx(buf) {
let eocdOff = -1;
for (let i = buf.length - 22; i >= 0; i--) {
if (buf[i]===0x50 && buf[i+1]===0x4B && buf[i+2]===0x05 && buf[i+3]===0x06) {
eocdOff = i; break;
}
}
if (eocdOff === -1) throw new Error("DOCX validation FAILED: no EOCD found");
const total = buf.readUInt16LE(eocdOff + 8);
const cdOff = buf.readUInt32LE(eocdOff + 16);
let pos = cdOff;
const errors = [];
for (let k = 0; k < total; k++) {
if (buf.readUInt32LE(pos) !== 0x02014B50) { errors.push("Bad CD sig at "+k); break; }
const compMethod = buf.readUInt16LE(pos + 10);
const crcStored = buf.readUInt32LE(pos + 16);
const uncompSize = buf.readUInt32LE(pos + 24);
const nameLen = buf.readUInt16LE(pos + 28);
const extraLen = buf.readUInt16LE(pos + 30);
const localOff = buf.readUInt32LE(pos + 42);
const fname = buf.slice(pos + 46, pos + 46 + nameLen).toString('utf8');
if (compMethod !== 0) errors.push(`COMPRESSION: "${fname}" method=${compMethod}, MUST be 0`);
try {
if (!fname.startsWith('word/media/')) {
const localNameLen = buf.readUInt16LE(localOff + 26);
const localExtraLen = buf.readUInt16LE(localOff + 28);
const dataStart = localOff + 30 + localNameLen + localExtraLen;
const storedData = buf.slice(dataStart, dataStart + uncompSize);
const actualCrc = crc32(storedData);
if (actualCrc !== crcStored)
errors.push(`CRC MISMATCH: "${fname}" stored=0x${crcStored.toString(16)} actual=0x${actualCrc.toString(16)}`);
}
} catch (e) { errors.push(`VALIDATION: "${fname}" - ${e.message}`); }
pos += 46 + nameLen + extraLen;
}
if (errors.length > 0)
throw new Error("DOCX validation FAILED before writing:\n" + errors.map(e=>" - "+e).join('\n'));
console.log("OK DOCX validation: " + total + " entries, CRC OK, STORE mode");
}
class ZipStream {
constructor() { this.entries = []; this.chunks = []; this.offset = 0; }
writeFile(name, data) {
const raw = Buffer.isBuffer(data) ? data : Buffer.from(data, 'utf8');
const nameBuf = Buffer.from(name, 'utf8');
const fileCrc = crc32(raw);
const header = Buffer.alloc(30);
header.writeUInt32LE(0x04034b50, 0);
header.writeUInt16LE(20, 4); header.writeUInt16LE(0, 6); header.writeUInt16LE(0, 8);
header.writeUInt32LE(fileCrc, 14); header.writeUInt32LE(raw.length, 18);
header.writeUInt32LE(raw.length, 22); header.writeUInt16LE(nameBuf.length, 26);
const local = Buffer.concat([header, nameBuf]);
this.chunks.push(local, raw);
this.entries.push({ name, crc: fileCrc, size: raw.length, offset: this.offset });
this.offset += local.length + raw.length;
}
finalize() {
const central = [];
for (const e of this.entries) {
const nameBuf = Buffer.from(e.name, 'utf8');
const c = Buffer.alloc(46);
c.writeUInt32LE(0x02014B50, 0); c.writeUInt16LE(20, 4); c.writeUInt16LE(20, 6);
c.writeUInt16LE(0, 8); c.writeUInt16LE(0, 10); c.writeUInt32LE(e.crc, 16);
c.writeUInt32LE(e.size, 20); c.writeUInt32LE(e.size, 24);
c.writeUInt16LE(nameBuf.length, 28); c.writeUInt16LE(0, 30); c.writeUInt16LE(0, 32);
c.writeUInt16LE(0, 34); c.writeUInt16LE(0, 36); c.writeUInt32LE(0, 38); c.writeUInt32LE(e.offset, 42);
central.push(c, nameBuf);
}
const centralBuf = Buffer.concat(central);
const eocd = Buffer.alloc(22);
eocd.writeUInt32LE(0x06054b50, 0); eocd.writeUInt16LE(this.entries.length, 8);
eocd.writeUInt16LE(this.entries.length, 10); eocd.writeUInt32LE(centralBuf.length, 12);
eocd.writeUInt32LE(this.offset, 16);
return Buffer.concat([...this.chunks, centralBuf, eocd]);
}
}
// ── OOXML Generators ──
function contentTypes(images) {
const imgOverrides = images.map(img => ` <Override PartName="/word/media/${img.name}" ContentType="${img.mime}"/>`).join('\n');
return `<?xml version="1.0" encoding="UTF-8"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
<Default Extension="xml" ContentType="application/xml"/>
<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
<Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>
<Override PartName="/word/settings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"/>
<Override PartName="/word/webSettings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml"/>
<Override PartName="/word/fontTable.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"/>
<Override PartName="/word/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/>
<Override PartName="/word/numbering.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"/>
${imgOverrides}
</Types>`;
}
function rootRels() {
return `<?xml version="1.0" encoding="UTF-8"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
</Relationships>`;
}
function docRels(images) {
const imgRels = images.map(img => ` <Relationship Id="${img.rId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/${img.name}"/>`).join('\n');
return `<?xml version="1.0" encoding="UTF-8"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml"/>
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings" Target="webSettings.xml"/>
<Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" Target="fontTable.xml"/>
<Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/>
<Relationship Id="rId6" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering" Target="numbering.xml"/>
${imgRels}
</Relationships>`;
}
function documentXml(body, imageCount) {
const imgNs = imageCount > 0
? '\n xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"\n xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"\n xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"'
: '';
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"${imgNs}>
<w:body>${body}<w:sectPr/></w:body>
</w:document>`;
}
function stylesXml() {
return `<?xml version="1.0" encoding="UTF-8"?>
<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:style w:type="paragraph" w:styleId="Normal" w:default="1"><w:name w:val="Normal"/><w:rPr><w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/><w:sz w:val="22"/></w:rPr></w:style>
<w:style w:type="paragraph" w:styleId="Heading1"><w:name w:val="heading 1"/><w:basedOn w:val="Normal"/><w:rPr><w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/><w:b/><w:color w:val="1F3864"/><w:sz w:val="36"/></w:rPr></w:style>
<w:style w:type="paragraph" w:styleId="Heading2"><w:name w:val="heading 2"/><w:basedOn w:val="Normal"/><w:rPr><w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/><w:b/><w:color w:val="2E75B6"/><w:sz w:val="28"/></w:rPr></w:style>
<w:style w:type="paragraph" w:styleId="Heading3"><w:name w:val="heading 3"/><w:basedOn w:val="Normal"/><w:rPr><w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/><w:b/><w:color w:val="2E75B6"/><w:sz w:val="24"/></w:rPr></w:style>
<w:style w:type="paragraph" w:styleId="Heading4"><w:name w:val="heading 4"/><w:basedOn w:val="Normal"/><w:rPr><w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/><w:b/><w:color w:val="2E75B6"/><w:sz w:val="22"/></w:rPr></w:style>
<w:style w:type="character" w:styleId="Hyperlink"><w:name w:val="Hyperlink"/><w:rPr><w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/><w:color w:val="0563C1"/><w:u w:val="single"/></w:rPr></w:style>
<w:style w:type="paragraph" w:styleId="ListBullet"><w:name w:val="List Bullet"/><w:basedOn w:val="Normal"/><w:rPr><w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/><w:sz w:val="22"/></w:rPr></w:style>
<w:style w:type="paragraph" w:styleId="ListNumber"><w:name w:val="List Number"/><w:basedOn w:val="Normal"/><w:rPr><w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/><w:sz w:val="22"/></w:rPr></w:style>
</w:styles>`;
}
function settingsXml(){return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:settings xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"/>';}
function webSettingsXml(){return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:webSettings xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"/>';}
function fontTableXml(){
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:fonts xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:font w:name="Calibri"><w:panose1 w:val="020F0502020204030204"/><w:charset w:val="00"/><w:family w:val="swiss"/><w:pitch w:val="variable"/></w:font>
<w:font w:name="Courier New"><w:panose1 w:val="02070309020205040304"/><w:charset w:val="00"/><w:family w:val="modern"/><w:pitch w:val="fixed"/></w:font>
</w:fonts>`;
}
function themeXml(){
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme"><a:themeElements>
<a:clrScheme name="Office"><a:dk1><a:srgbClr val="000000"/></a:dk1><a:lt1><a:srgbClr val="FFFFFF"/></a:lt1><a:dk2><a:srgbClr val="1F3864"/></a:dk2><a:lt2><a:srgbClr val="D9E2F3"/></a:lt2><a:accent1><a:srgbClr val="4472C4"/></a:accent1><a:accent2><a:srgbClr val="ED7D31"/></a:accent2><a:accent3><a:srgbClr val="A5A5A5"/></a:accent3><a:accent4><a:srgbClr val="FFC000"/></a:accent4><a:accent5><a:srgbClr val="5B9BD5"/></a:accent5><a:accent6><a:srgbClr val="70AD47"/></a:accent6><a:hlink><a:srgbClr val="0563C1"/></a:hlink><a:folHlink><a:srgbClr val="954F72"/></a:folHlink></a:clrScheme>
<a:fontScheme name="Office"><a:majorFont><a:latin typeface="Calibri"/><a:ea typeface=""/><a:cs typeface=""/></a:majorFont><a:minorFont><a:latin typeface="Calibri"/><a:ea typeface=""/><a:cs typeface=""/></a:minorFont></a:fontScheme>
<a:fmtScheme name="Office"><a:fillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:solidFill><a:schemeClr val="phClr"/></a:solidFill></a:fillStyleLst><a:lnStyleLst><a:ln w="6350"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill></a:ln><a:ln w="6350"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill></a:ln><a:ln w="6350"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill></a:ln></a:lnStyleLst><a:effectStyleLst><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst/></a:effectStyle><a:effectStyle><a:effectLst/></a:effectStyle></a:effectStyleLst><a:bgFillStyleLst><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:solidFill><a:schemeClr val="phClr"/></a:solidFill></a:bgFillStyleLst></a:fmtScheme></a:themeElements></a:theme>`;
}
function numberingXml(){
const bulletNums = Array.from({length:10},(_,i)=>`<w:num w:numId="${i+1}"><w:abstractNumId w:val="0"/></w:num>`).join('');
const decimalNums = Array.from({length:10},(_,i)=>`<w:num w:numId="${i+11}"><w:abstractNumId w:val="1"/></w:num>`).join('');
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:abstractNum w:abstractNumId="0"><w:multiLevelType w:val="hybridMultilevel"/>
<w:lvl w:ilvl="0"><w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlText w:val="●"/><w:lvlJc w:val="left"/><w:pPr><w:ind w:left="720" w:hanging="360"/></w:pPr></w:lvl>
<w:lvl w:ilvl="1"><w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlText w:val="○"/><w:lvlJc w:val="left"/><w:pPr><w:ind w:left="1440" w:hanging="360"/></w:pPr></w:lvl>
<w:lvl w:ilvl="2"><w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlText w:val="■"/><w:lvlJc w:val="left"/><w:pPr><w:ind w:left="2160" w:hanging="360"/></w:pPr></w:lvl>
</w:abstractNum>
<w:abstractNum w:abstractNumId="1"><w:multiLevelType w:val="hybridMultilevel"/>
<w:lvl w:ilvl="0"><w:start w:val="1"/><w:numFmt w:val="decimal"/><w:lvlText w:val="%1."/><w:lvlJc w:val="left"/><w:pPr><w:ind w:left="720" w:hanging="360"/></w:pPr></w:lvl>
<w:lvl w:ilvl="1"><w:start w:val="1"/><w:numFmt w:val="lowerLetter"/><w:lvlText w:val="%2."/><w:lvlJc w:val="left"/><w:pPr><w:ind w:left="1440" w:hanging="360"/></w:pPr></w:lvl>
<w:lvl w:ilvl="2"><w:start w:val="1"/><w:numFmt w:val="lowerRoman"/><w:lvlText w:val="%3."/><w:lvlJc w:val="left"/><w:pPr><w:ind w:left="2160" w:hanging="360"/></w:pPr></w:lvl>
</w:abstractNum>
${bulletNums}${decimalNums}
</w:numbering>`;
}
// ── Renderers ──
function esc(s) {
const clean = String(s).replace(/[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u{10000}-\u{10FFFF}]/gu, '');
return clean.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");
}
function run(text, opts = {}) {
let parts = [];
if (opts.code) parts.push('<w:rFonts w:ascii="Courier New" w:hAnsi="Courier New"/>');
if (opts.bold) parts.push('<w:b/>');
if (opts.italic) parts.push('<w:i/>');
parts.push('<w:sz w:val="22"/>');
return `<w:r><w:rPr>${parts.join('')}</w:rPr><w:t xml:space="preserve">${esc(String(text))}</w:t></w:r>`;
}
function paragraph(runs, style) {
const pPr = style ? `<w:pPr><w:pStyle w:val="${style}"/></w:pPr>` : '';
return `<w:p>${pPr}${runs}</w:p>`;
}
function blockquoteParagraph(text, indentLevel) {
const left = 360 * (indentLevel || 1);
return `<w:p><w:pPr><w:ind w:left="${left}"/></w:pPr>${parseInline(text)}</w:p>`;
}
function parseInline(text) {
const runs = [];
let i = 0;
while (i < text.length) {
if (text[i] === '!') { i++; continue; }
if (text[i]==='*'&&text[i+1]==='*'&&text[i+2]==='*') {
const end=text.indexOf('***',i+3); if(end!==-1){runs.push(run(text.slice(i+3,end),{bold:true,italic:true}));i=end+3;continue;}
runs.push(run('*'));i++;continue;
}
if (text[i]==='*'&&text[i+1]==='*') {
const end=text.indexOf('**',i+2); if(end!==-1){runs.push(run(text.slice(i+2,end),{bold:true}));i=end+2;continue;}
runs.push(run('*'));i++;continue;
}
if (text[i]==='*'&&text[i+1]!=='*') {
const end=text.indexOf('*',i+1); if(end!==-1){runs.push(run(text.slice(i+1,end),{italic:true}));i=end+1;continue;}
runs.push(run('*'));i++;continue;
}
if (text[i]==='`') {
const end=text.indexOf('`',i+1); if(end!==-1){runs.push(run(text.slice(i+1,end),{code:true}));i=end+1;continue;}
runs.push(run('`'));i++;continue;
}
if (text[i]==='[') {
const isImage=i>0&&text[i-1]==='!';
const isImageWS=i>1&&text[i-2]==='!'&&text[i-1]===' ';
if(isImage||isImageWS) {
const close=text.indexOf(']',i); const op=text.indexOf('(',close); const cp=text.indexOf(')',op);
if(close!==-1&&op===close+1&&cp!==-1) {
const alt=text.slice(i+1,close); const imgPath=text.slice(op+1,cp);
if(isImageWS)runs.pop();
runs.push('\x00IMG:'+Buffer.from(JSON.stringify({alt,path:imgPath})).toString('base64')+'\x00');
i=cp+1;continue;
}
}
const close=text.indexOf(']',i); const op=text.indexOf('(',close); const cp=text.indexOf(')',op);
if(close!==-1&&op===close+1&&cp!==-1){
runs.push(`<w:r><w:rPr><w:rStyle w:val="Hyperlink"/></w:rPr><w:t xml:space="preserve">${esc(text.slice(i+1,close))}</w:t></w:r>`);
i=cp+1;continue;
}
runs.push(run('['));i++;continue;
}
let j=i; while(j<text.length&&text[j]!=='*'&&text[j]!=='`'&&text[j]!=='[')j++;
if(j>i)runs.push(run(text.slice(i,j)));
i=j;
}
return runs.join('');
}
function renderTable(headers, dataRows) {
const maxCols = Math.max(headers.length, ...dataRows.map(r=>r.length), 1);
const colWidth = Math.floor(9000/maxCols);
const gridCols = Array.from({length:maxCols},()=>`<w:gridCol w:w="${colWidth}"/>`).join('');
const border = '<w:tblBorders><w:top w:val="single" w:sz="4" w:space="0" w:color="BFBFBF"/><w:left w:val="single" w:sz="4" w:space="0" w:color="BFBFBF"/><w:bottom w:val="single" w:sz="4" w:space="0" w:color="BFBFBF"/><w:right w:val="single" w:sz="4" w:space="0" w:color="BFBFBF"/><w:insideH w:val="single" w:sz="4" w:space="0" w:color="BFBFBF"/><w:insideV w:val="single" w:sz="4" w:space="0" w:color="BFBFBF"/></w:tblBorders>';
function cell(t,isH){
const shd=isH?'<w:shd w:val="clear" w:color="auto" w:fill="D9E2F3"/>':'';
const rPr=isH?'<w:rPr><w:b/></w:rPr>':'';
return`<w:tc><w:tcPr>${shd}</w:tcPr><w:p><w:r>${rPr}<w:t xml:space="preserve">${esc(String(t))}</w:t></w:r></w:p></w:tc>`;}
const pad=r=>[...r,...Array(Math.max(0,maxCols-r.length)).fill('')].slice(0,maxCols);
const hRow=`<w:tr>${pad(headers).map(h=>cell(h,true)).join('')}</w:tr>`;
const dRows=dataRows.map(r=>`<w:tr>${pad(r).map(c=>cell(c,false)).join('')}</w:tr>`).join('');
return`<w:tbl><w:tblPr><w:tblW w:w="9000" w:type="dxa"/>${border}</w:tblPr><w:tblGrid>${gridCols}</w:tblGrid>${hRow}${dRows}</w:tbl>`;
}
function markdownToDocxBody(md) {
const lines=md.split('\n'); const body=[]; let i=0;
let bulletNumId=1,decimalNumId=11;
let currentListType=null,currentNumId=0;
function resetList(){currentListType=null;currentNumId=0;}
while(i<lines.length){
const line=lines[i];
if(line.trim()===''){resetList();body.push('<w:p/>');i++;continue;}
const hMatch=line.match(/^(#{1,6})\s+(.+)/);
if(hMatch){resetList();const lv=Math.min(hMatch[1].length,6);body.push(paragraph(parseInline(hMatch[2]),`Heading${lv}`));i++;continue;}
if(/^[-*_]{3,}\s*$/.test(line.trim())){resetList();body.push('<w:p><w:pPr><w:pBdr><w:bottom w:val="single" w:sz="6" w:space="1" w:color="auto"/></w:pBdr></w:pPr></w:p>');i++;continue;}
let bqMatch=line.match(/^(>+\s*)(.*)/);
if(bqMatch){
const indent=bqMatch[1].split('>').length-1;
body.push(blockquoteParagraph(bqMatch[2],indent));
resetList();i++;continue;
}
const olMatch=line.match(/^(\s*)(\d+)\.\s+(.*)/);
if(olMatch){const indent=Math.floor(olMatch[1].length/2);if(currentListType!=='decimal'){currentListType='decimal';currentNumId=decimalNumId++;}body.push(`<w:p><w:pPr><w:numPr><w:ilvl w:val="${indent}"/><w:numId w:val="${currentNumId}"/></w:numPr></w:pPr>${parseInline(olMatch[3])}</w:p>`);i++;continue;}
const ulMatch=line.match(/^(\s*)[-*+]\s+(.*)/);
if(ulMatch){const indent=Math.floor(ulMatch[1].length/2);if(currentListType!=='bullet'){currentListType='bullet';currentNumId=bulletNumId++;}body.push(`<w:p><w:pPr><w:numPr><w:ilvl w:val="${indent}"/><w:numId w:val="${currentNumId}"/></w:numPr></w:pPr>${parseInline(ulMatch[2])}</w:p>`);i++;continue;}
if(line.trim().startsWith('```')){
resetList(); i++;
const codeLines=[];
let lang='';
const firstLine=lines[i]||'';
const langMatch=firstLine.match(/^([\w+#]+)\s*$/);
if(!langMatch||['python','javascript','js','bash','sh','sql','json','xml','java','cpp','c','go','rust','ruby','swift'].includes(langMatch[1].toLowerCase())){
if(langMatch) lang=langMatch[1];
}
if(langMatch) i++;
while(i<lines.length&&!lines[i].trim().startsWith('```')){codeLines.push(lines[i]);i++;}
if(i<lines.length) i++;
body.push(`<w:p><w:pPr><w:shd w:val="clear" w:color="auto" w:fill="F2F2F2"/></w:pPr>${run(lang||'',{bold:true,code:true})}</w:p>`);
for(const cl of codeLines){body.push(`<w:p><w:pPr><w:shd w:val="clear" w:color="auto" w:fill="F2F2F2"/></w:pPr>${run(cl,{code:true})}</w:p>`);}
continue;
}
if(line.trim().startsWith('|')&&line.trim().endsWith('|')){
resetList();const tblLines=[];
while(i<lines.length&&lines[i].trim().startsWith('|')&&lines[i].trim().endsWith('|')){tblLines.push(lines[i]);i++;}
if(tblLines.length>=2){
const pr=l=>l.trim().slice(1,-1).split('|').map(c=>c.trim());
const hRow=pr(tblLines[0]);
const sRow=pr(tblLines[1]);
if(sRow.every(c=>/^:?-{2,}:?$/.test(c))){
const dRows=tblLines.slice(2).map(pr);
body.push(renderTable(hRow,dRows));body.push('<w:p/>');
continue;
}
}
i=tblLines[0]?lines.indexOf(tblLines[0]):i;
}
resetList();
body.push(paragraph(parseInline(line)));
i++;
}
return body.join('');
}
// ── Image processing ──
function detectImageDimensions(buf, ext) {
const h=buf; try {
if(ext==='png'&&h[0]===0x89&&h[1]===0x50) return {width:h.readUInt32BE(16),height:h.readUInt32BE(20)};
if(ext==='jpg'||ext==='jpeg') {
let off=2; while(off<h.length-4){if(h[off]===0xFF&&(h[off+1]>=0xC0&&h[off+1]<=0xC3)){return{height:h.readUInt16BE(off+5),width:h.readUInt16BE(off+7)};} off+=h.readUInt16BE(off+2)+2;} }
if(ext==='gif') return {width:h.readUInt16LE(6),height:h.readUInt16LE(8)};
if(ext==='bmp') return {width:h.readUInt32LE(18),height:Math.abs(h.readInt32LE(22))};
}catch(_){}
return null;
}
function dimsToEmu(px){
if(!px) return {cx:3810000,cy:2857500};
const MAX_W=600; const scale=px.width>MAX_W?MAX_W/px.width:1;
return {cx:Math.round(px.width*scale*9525),cy:Math.round(px.height*scale*9525)};
}
function mimeFromExt(ext){
const m={png:'image/png',jpg:'image/jpeg',jpeg:'image/jpeg',gif:'image/gif',bmp:'image/bmp'};
return m[ext]||'image/png';
}
function validImageSig(buf,ext){
const h=buf.slice(0,8);
if(ext==='png') return h[0]===0x89&&h[1]===0x50;
if(ext==='jpg'||ext==='jpeg') return h[0]===0xFF&&h[1]===0xD8&&h[2]===0xFF;
return true;
}
function imageDrawing(rId,alt,cx,cy){
return`<w:r><w:drawing><wp:inline distT="0" distB="0" distL="0" distR="0">
<wp:extent cx="${cx}" cy="${cy}"/><wp:effectExtent l="0" t="0" r="0" b="0"/>
<wp:docPr id="1" name="${esc(alt||'Chart')}" descr="${esc(alt||'')}"/>
<a:graphic><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:pic><pic:nvPicPr><pic:cNvPr id="0" name="${esc(alt||'Chart')}"/><pic:cNvPicPr/></pic:nvPicPr>
<pic:blipFill><a:blip r:embed="${rId}"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill>
<pic:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="${cx}" cy="${cy}"/></a:xfrm>
<a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic>
</a:graphicData></a:graphic></wp:inline></w:drawing></w:r>`;
}
// ── Build Pipeline ──
function buildDocx(input, mode, output) {
const outDir = path.dirname(output);
try { fs.mkdirSync(outDir, { recursive: true }); } catch (e) {}
const zip = new ZipStream();
let body;
if (mode === 'markdown') body = markdownToDocxBody(String(input));
else if (mode === 'ast') body = astToDocxBody(input);
else body = paragraph(parseInline(String(input)));
const images = [];
body = body.replace(/\x00IMG:([A-Za-z0-9+/=]+)\x00/g, (match, b64) => {
try {
const info = JSON.parse(Buffer.from(b64, 'base64').toString());
const imgPath = info.path;
let imgBuf;
// ★ FIXED: fallback wrapped in <w:p>
try { imgBuf = fs.readFileSync(imgPath); } catch (e) { return `<w:p><w:r><w:t>[Image: ${esc(info.alt||imgPath)}]</w:t></w:r></w:p>`; }
const ext = path.extname(imgPath).slice(1).toLowerCase() || 'png';
if (!validImageSig(imgBuf, ext)) return `<w:p><w:r><w:t>[Invalid image: ${esc(info.alt||imgPath)}]</w:t></w:r></w:p>`;
const name = `image${images.length + 1}.${ext}`;
const rId = `rIdImg${images.length + 1}`;
images.push({ name, ext, mime: mimeFromExt(ext), rId, data: imgBuf });
const emu = dimsToEmu(detectImageDimensions(imgBuf, ext));
return imageDrawing(rId, info.alt, emu.cx, emu.cy);
} catch (e) { return `<w:p><w:r><w:t>[Image error]</w:t></w:r></w:p>`; }
});
zip.writeFile("[Content_Types].xml", contentTypes(images));
zip.writeFile("_rels/.rels", rootRels());
zip.writeFile("word/document.xml", documentXml(body, images.length));
zip.writeFile("word/_rels/document.xml.rels", docRels(images));
zip.writeFile("word/styles.xml", stylesXml());
zip.writeFile("word/settings.xml", settingsXml());
zip.writeFile("word/webSettings.xml", webSettingsXml());
zip.writeFile("word/fontTable.xml", fontTableXml());
zip.writeFile("word/theme/theme1.xml", themeXml());
zip.writeFile("word/numbering.xml", numberingXml());
for (const img of images) zip.writeFile(`word/media/${img.name}`, img.data);
const buf = zip.finalize();
validateDocx(buf);
fs.writeFileSync(output, buf);
console.log("Done:", output, buf.length);
}
// ★ FIXED: image case now wraps token in <w:p> for OOXML compliance
// Before: parts.push(`\x00IMG:...\x00`); → 裸 <w:r> 在 <w:body> 下 → 违反 schema
// After: parts.push(`<w:p>\x00IMG:...\x00</w:p>`); → <w:r> 在 <w:p> 内 → 合法
function astToDocxBody(ast) {
if (!Array.isArray(ast)) return paragraph(parseInline(String(ast)));
let bulletNumId = 1, decimalNumId = 11;
const parts = [];
for (const node of ast) {
switch (node.type) {
case 'heading': parts.push(paragraph(parseInline(node.text||''), `Heading${Math.min(node.level||1,6)}`)); break;
case 'paragraph': parts.push(paragraph(parseInline(node.text||''))); break;
case 'blockquote': parts.push(blockquoteParagraph(node.text||'', node.indentLevel||1)); break;
case 'table': if(node.headers&&node.rows){parts.push(renderTable(node.headers,node.rows));parts.push('<w:p/>');} break;
// ★ FIXED: image path → token wrapped in <w:p> to keep <w:r> inside block-level element
case 'image': if(node.path) parts.push(`<w:p>\x00IMG:${Buffer.from(JSON.stringify({alt:node.alt||'',path:node.path})).toString('base64')}\x00</w:p>`); break;
case 'horizontal_rule': parts.push('<w:p><w:pPr><w:pBdr><w:bottom w:val="single" w:sz="6" w:space="1" w:color="auto"/></w:pBdr></w:pPr></w:p>'); break;
case 'list': {
const listNumId = node.ordered ? (decimalNumId++) : (bulletNumId++);
for (const item of (node.items||[])) {
const itemText = typeof item === 'string' ? item : (item.text||'');
const itemIndent = typeof item === 'object' ? (item.level||0) : 0;
parts.push(`<w:p><w:pPr><w:pStyle w:val="${node.ordered?'ListNumber':'ListBullet'}"/><w:numPr><w:ilvl w:val="${itemIndent}"/><w:numId w:val="${listNumId}"/></w:numPr></w:pPr>${parseInline(itemText)}</w:p>`);
}
} break;
}
}
return parts.join('');
}
// ⛔ ENTRY POINT
const input = `{{input}}`;
const output = `{{output}}`.replace(/^\{\{output\}\}$/, '') || '/generated_document.docx';
const mode = (`{{mode}}`.replace(/^\{\{mode\}\}$/, '') || 'markdown').toLowerCase();
buildDocx(input, mode, output);
})();
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 6d ago First seen · 553 lines · 38 tokens per session scan A 6b3a2ef87c1a
docx-generator is a skill published in the GitHub repository guyoung/boxagnts (11 stars, last pushed 1mo ago), licensed MIT. It adds 38 tokens to every session and 10,943 once invoked, about $0.0002 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.
Other skills, from other repositories
当用户需要对PDF文件进行任何操作时,请使用此技能。包括从 PDF 中读取或提取文本/表格、合并多个 PDF、拆分 PDF、旋转页面、添加水印、创建新PDF、填写PDF表单、加密/解密 PDF、提取图片,以及对扫描版 PDF 进行 OCR 使其可搜索。如果用户提到 .pdf 文件或要求生成 PDF,请使用此技能。.
pptx
当涉及到 .pptx 文件的任何操作时使用此技能——无论是作为输入、输出还是两者兼有。包括:创建幻灯片、演示文稿或路演材料;读取、解析或提取任何 .pptx 文件中的文本(即使提取的内容将用于其他地方,如邮件或摘要);编辑、修改或更新现有演示文稿;合并或拆分幻灯片文件;处理模板、布局、演讲者备注或批注。当用户提到“演示文稿”、”幻灯片“、”PPT“或引用 .pptx 文件名时触发,无论他们之后打算如何使用内容。如果需要打开、创建或操作 .pptx 文件,就使用此技能。.
nano-pdf
Edits PDF files using natural-language instructions via the nano-pdf CLI. Supports modifying text, changing titles, fixing typos, and updating content on specific pages. Use when the user wants to edit a PDF, modify PDF content, update PDF text, fix a typo in a PDF, change a PDF title, or rewrite part of a PDF page.
hive.pdf
Read, write, merge, split, rotate, watermark, encrypt, and OCR PDF files using Python (pypdf, pdfplumber, reportlab, pypdfium2) and command-line tools (poppler-utils, qpdf). Use when the user asks to extract text/tables/images from a PDF, create or modify a PDF, combine or split PDFs, OCR a scanned PDF…
pdf-toolkit
Structured .pdf operations: extract text/tables, merge pages from multiple PDFs, split a PDF by page ranges, fill PDF form fields, and generate fresh PDFs from JSON. Trigger when the user wants programmatic PDF work without natural-language rewriting — examples: pull tables from a report, combine three PDFs, extract…
pdf-analysis
PDF 文档解析。自动区分文字型 PDF 与扫描型 PDF,覆盖:文本/表格提取、多页全量扫描、嵌入图表 caption、单位感知数值计算。.