Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Create ZIP and TAR archives programmatically with Archiver — bundle files, directories, and streams into compressed archives with progress tracking. Use when tasks involve generating downloadable bundles, backing up directories, creating deployment packages, or building export features that zip multiple files together.
.claude/skills/terminalskills-archiver/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-08 | ✗→✓ | ▲ Improved | 10% | 0% |
| case-05 | ✓→✓ | = Same ✓ | -2% | 0% |
| case-14 | ✓→✓ | = Same ✓ | 22% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 39% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 86% | 0% |
Create ZIP and TAR archives from files, directories, and streams. Streaming architecture for large archives.
bash# Install archiver for creating archives. npm install archiver npm install -D @types/archiver
typescript// src/archive/zip.ts — Bundle multiple files into a ZIP archive. import archiver from "archiver"; import fs from "fs"; export async function createZip(files: string[], outputPath: string): Promise<void> { const output = fs.createWriteStream(outputPath); const archive = archiver("zip", { zlib: { level: 9 } }); return new Promise((resolve, reject) => { output.on("close", () => { console.log(`Archive created: ${archive.pointer()} bytes`); resolve(); }); archive.on("error", reject); archive.pipe(output); for (const file of files) { archive.file(file, { name: file.split("/").pop()! }); } archive.finalize(); }); }
typescript// src/archive/directory.ts — Recursively add an entire directory to a ZIP. import archiver from "archiver"; import fs from "fs"; export async function zipDirectory(sourceDir: string, outputPath: string): Promise<void> { const output = fs.createWriteStream(outputPath); const archive = archiver("zip", { zlib: { level: 6 } }); return new Promise((resolve, reject) => { output.on("close", resolve); archive.on("error", reject); archive.pipe(output); // Add entire directory, preserving structure archive.directory(sourceDir, false); // Or nest under a folder name inside the archive // archive.directory(sourceDir, "my-project"); archive.finalize(); }); }
typescript// src/archive/buffers.ts — Add in-memory content (buffers, strings) to archives // without writing temporary files. import archiver from "archiver"; import fs from "fs"; export async function createArchiveFromData( entries: { name: string; content: string | Buffer }[], outputPath: string ): Promise<void> { const output = fs.createWriteStream(outputPath); const archive = archiver("zip", { zlib: { level: 6 } }); return new Promise((resolve, reject) => { output.on("close", resolve); archive.on("error", reject); archive.pipe(output); for (const entry of entries) { archive.append(entry.content, { name: entry.name }); } archive.finalize(); }); } // Example: bundle generated reports // await createArchiveFromData([ // { name: "report.csv", content: csvString }, // { name: "report.json", content: JSON.stringify(data) }, // { name: "README.txt", content: "Generated reports bundle" }, // ], "reports.zip");
typescript// src/archive/tar.ts — Create gzipped TAR archives for deployment or backup. import archiver from "archiver"; import fs from "fs"; export async function createTarGz(sourceDir: string, outputPath: string): Promise<void> { const output = fs.createWriteStream(outputPath); const archive = archiver("tar", { gzip: true, gzipOptions: { level: 9 } }); return new Promise((resolve, reject) => { output.on("close", resolve); archive.on("error", reject); archive.pipe(output); archive.directory(sourceDir, false); archive.finalize(); }); }
typescript// src/archive/progress.ts — Track archive creation progress for large bundles. import archiver from "archiver"; import fs from "fs"; export async function createZipWithProgress( sourceDir: string, outputPath: string, onProgress: (percent: number) => void ): Promise<void> { const output = fs.createWriteStream(outputPath); const archive = archiver("zip", { zlib: { level: 6 } }); return new Promise((resolve, reject) => { output.on("close", resolve); archive.on("error", reject); archive.on("progress", (progress) => { const percent = (progress.entries.processed / progress.entries.total) * 100; onProgress(Math.round(percent)); }); archive.pipe(output); archive.directory(sourceDir, false); archive.finalize(); }); }
typescript// src/archive/api.ts — Stream a ZIP archive directly to an Express response // without writing to disk. import archiver from "archiver"; import type { Response } from "express"; export function streamZipResponse( res: Response, files: { name: string; content: string | Buffer }[] ) { res.setHeader("Content-Type", "application/zip"); res.setHeader("Content-Disposition", "attachment; filename=export.zip"); const archive = archiver("zip", { zlib: { level: 6 } }); archive.pipe(res); for (const file of files) { archive.append(file.content, { name: file.name }); } archive.finalize(); }
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-05 | pass→pass | 11,594 | 6,485 | -44% | 1 | 1 | 0% | 2,056 | 2,008 | -2% | 0 | 0 | — |
case-14 | pass→pass | 7,800 | 3,353 | -57% | 1 | 1 | 0% | 1,439 | 1,750 | +22% | 0 | 0 | — |
case-01 | pass→pass | 9,053 | 5,626 | -38% | 1 | 1 | 0% | 1,814 | 2,514 | +39% | 0 | 0 | — |
case-02 | pass→pass | 8,317 | 11,123 | +34% | 1 | 1 | 0% | 1,701 | 3,162 | +86% | 0 | 0 | — |
case-03 | pass→pass | 16,071 | 12,760 | -21% | 1 | 1 | 0% | 3,505 | 3,828 | +9% | 0 | 0 | — |
case-04 | pass→pass | 10,864 | 7,292 | -33% | 1 | 1 | 0% | 1,697 | 2,434 | +43% | 0 | 0 | — |
case-06 | pass→pass | 4,693 | 3,052 | -35% | 1 | 1 | 0% | 857 | 1,847 | +116% | 0 | 0 | — |
case-07 | pass→pass | 9,057 | 8,621 | -5% | 1 | 1 | 0% | 1,647 | 2,663 | +62% | 0 | 0 | — |
case-08 | fail→pass | 11,160 | 4,711 | -58% | 1 | 1 | 0% | 2,076 | 2,275 | +10% | 0 | 0 | — |
case-09 | pass→pass | 4,100 | 2,669 | -35% | 1 | 1 | 0% | 702 | 1,641 | +134% | 0 | 0 | — |
case-10 | pass→pass | 23,324 | 8,346 | -64% | 1 | 1 | 0% | 2,332 | 3,053 | +31% | 0 | 0 | — |
case-11 | pass→pass | 3,048 | 3,207 | +5% | 1 | 1 | 0% | 494 | 1,781 | +261% | 0 | 0 | — |
case-12 | pass→pass | 1,422 | 1,873 | +32% | 1 | 1 | 0% | 227 | 1,580 | +596% | 0 | 0 | — |
case-13 | pass→pass | 5,795 | 2,982 | -49% | 1 | 1 | 0% | 1,089 | 1,788 | +64% | 0 | 0 | — |
case-15 | pass→pass | 4,217 | 1,621 | -62% | 1 | 1 | 0% | 739 | 1,579 | +114% | 0 | 0 | — |
case-16 | pass→pass | 2,166 | 1,781 | -18% | 1 | 1 | 0% | 326 | 1,542 | +373% | 0 | 0 | — |
case-17 | fail→fail | 16,489 | 12,673 | -23% | 1 | 1 | 0% | 3,325 | 3,873 | +16% | 0 | 0 | — |
case-18 | pass→pass | 6,541 | 2,412 | -63% | 1 | 1 | 0% | 1,270 | 1,675 | +32% | 0 | 0 | — |
case-19 | pass→pass | 4,224 | 1,946 | -54% | 1 | 1 | 0% | 639 | 1,650 | +158% | 0 | 0 | — |
case-20 | pass→pass | 8,855 | 6,203 | -30% | 1 | 1 | 0% | 1,798 | 2,556 | +42% | 0 | 0 | — |
case-21 | pass→pass | 7,309 | 6,813 | -7% | 1 | 1 | 0% | 1,440 | 2,373 | +65% | 0 | 0 | — |
case-22 | pass→pass | 12,535 | 11,589 | -8% | 1 | 1 | 0% | 2,801 | 3,926 | +40% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +5 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.