Skip to main content

file-compression

Compress and decompress files using jsexec with built-in zlib and manual format parsing. Supports .gz, .tar, .tar.gz, .tgz, .zip.

Quellinformationen

Repository
guyoung/boxagnts
Letzte Quellaktivität
24. Juli 2026 um 13:19
Erkannte Sprache von SKILL.md
Englisch
Sterne
11
Forks
0

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
file-compression
description
Compress and decompress files using jsexec with built-in zlib and manual format parsing. Supports .gz, .tar, .tar.gz, .tgz, .zip.
when_to_use
Use this skill when the user needs to compress files into archives (.tar, .tar.gz, .tgz, .zip, .gz) or decompress/extract existing archives. **⚠️ Limitation: Directory compression is non-recursive — only top-level entries are archived; subdirectory contents are NOT included.**
tools
jsexec, read, write, bash
args
[{"name":"action","description":"Operation to perform — compress or decompress","required":true},{"name":"input","description":"Path to the input file or directory for compress, or the archive file for decompress","required":true},{"name":"output","description":"Output archive path (compress) or extraction directory (decompress). Auto-generated if omitted. For .gz decompress, this is the output TAR file path.","required":false},{"name":"format","description":"Target format for compression (tar, tar.gz, tgz, zip, gz). Auto-detected for decompress.","required":false}]
> **CODE SKILL — VERBATIM REQUIRED** > This skill targets multiple archive formats (TAR, GZIP, ZIP) with manual binary parsing. > The Runnable Entry Point is the sole implementation. 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 TAR header parser or builder — use ONLY the ones in Runnable Entry Point - Do NOT write your own ZIP EOCD scanner or central directory parser — use ONLY the ones in Runnable Entry Point - Do NOT skip any format-specific handling (.tar, .tar.gz, .tgz, .zip, .gz) - Do NOT use shell tools (tar, gzip, unzip) — all operations are pure JavaScript in jsexec - Do NOT alter the entry point dispatch logic (`action === 'compress'` / `action === 'decompress'`) ## Correct Invocation Pattern 1. Copy the **complete script** from `## Runnable Entry Point` below 2. Replace ONLY `{{action}}`, `{{input}}`, `{{output}}`, `{{format}}` with actual values 3. Since the IIFE is large (370+ lines), **persist to a temp file** and execute via `jsexec --file_path <file>` — do NOT embed the entire IIFE inside another JS string 4. Execute with **NO modifications** to core logic ## Argument Details | Arg | Type | Required | Default | Description | |-----|------|----------|---------|-------------| | `action` | `string` | yes | — | `compress` or `decompress` | | `input` | `string` | yes | — | Source file/directory (compress) or archive path (decompress) | | `output` | `string` | no | auto | Output archive path (compress) or extract directory (decompress) | | `format` | `string` | no | auto | `tar` / `tar.gz` / `tgz` / `zip` / `gz` (compress only). **When both `output` and `format` are provided, `format` takes priority.** When `output` is auto-generated, `format` determines the suffix. | > **⚠️ `format` vs `output` extension**: When `format` is explicitly set, it overrides format detection from the `output` file extension. For example, `format=zip` + `output=archive.tar` still produces a valid ZIP. Without `format`, the extension determines the archive type. ## Runnable Entry Point (COMPLETE IIFE, DO NOT MODIFY) ```js // ===== Runnable Entry Point (IIFE) — DO NOT MODIFY ANY CODE BELOW ===== (function() { // ══════════════════════════════════════════════════════════════════════════ // Imports // ══════════════════════════════════════════════════════════════════════════ const zlib = require('zlib'); const fs = require('fs'); const path = require('path'); // ══════════════════════════════════════════════════════════════════════════ // Utility Functions (DO NOT REPLACE) // ══════════════════════════════════════════════════════════════════════════ function ensureDir(dir) { try { fs.mkdirSync(dir); } catch (e) { } } function parseOctal(buf, start, end) { let s = ''; for (let i = start; i < end; i++) { const ch = String.fromCharCode(buf[i]); if (ch >= '0' && ch <= '7') s += ch; else break; } return parseInt(s, 8) || 0; } function crc32(buf) { let crc = 0xFFFFFFFF; const table = new Uint32Array(256); for (let i = 0; i < 256; i++) { let c = i; for (let j = 0; j < 8; j++) c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1); table[i] = c; } for (let i = 0; i < buf.length; i++) crc = table[(crc ^ buf[i]) & 0xFF] ^ (crc >>> 1); return (crc ^ 0xFFFFFFFF) >>> 0; } // ══════════════════════════════════════════════════════════════════════════ // Core Logic — Decompress (DO NOT REPLACE) // ══════════════════════════════════════════════════════════════════════════ function decompressGzip(inputPath, outputPath) { const compressed = fs.readFileSync(inputPath); const decompressed = zlib.gunzipSync(compressed); fs.writeFileSync(outputPath, decompressed); console.log(' ' + path.basename(outputPath) + ' (' + decompressed.length + ' bytes)'); } function extractTar(tarPath, outputDir) { const data = fs.readFileSync(tarPath); ensureDir(outputDir); let offset = 0, files = 0, dirs = 0; while (offset + 512 <= data.length) { const header = data.slice(offset, offset + 512); if (header[0] === 0) break; const name = header.slice(0, 100).toString().replace(/\0/g, '').trim(); const size = parseOctal(data, offset + 124, offset + 136); const typeflag = header[156]; if (!name) break; offset += 512; const content = data.slice(offset, offset + size); offset += Math.ceil(size / 512) * 512; const fullPath = path.join(outputDir, name); if (typeflag === 53) { ensureDir(fullPath); dirs++; } else { ensureDir(path.dirname(fullPath)); fs.writeFileSync(fullPath, content); console.log(' ' + name + ' (' + size + ' bytes)'); files++; } } console.log('Done: ' + files + ' files, ' + dirs + ' dirs'); } function extractZip(zipPath, outputDir) { const data = fs.readFileSync(zipPath); ensureDir(outputDir); let eocdOffset = -1; for (let i = data.length - 22; i >= 0; i--) { if (data[i] === 0x50 && data[i + 1] === 0x4B && data[i + 2] === 0x05 && data[i + 3] === 0x06) { eocdOffset = i; break; } } if (eocdOffset === -1) throw new Error('EOCD not found'); const totalEntries = data.readUInt16LE(eocdOffset + 8); const cdOffset = data.readUInt32LE(eocdOffset + 16); let cdPos = cdOffset; let count = 0, dirCount = 0; for (let i = 0; i < totalEntries; i++) { const sig = data.readUInt32LE(cdPos); if (sig !== 0x02014B50) throw new Error('Corrupt central directory'); const compMethod = data.readUInt16LE(cdPos + 10); const compSize = data.readUInt32LE(cdPos + 20); const nameLen = data.readUInt16LE(cdPos + 28); const extraLen = data.readUInt16LE(cdPos + 30); const localOff = data.readUInt32LE(cdPos + 42); const fileName = data.slice(cdPos + 46, cdPos + 46 + nameLen).toString(); cdPos += 46 + nameLen + extraLen; const localNameLen = data.readUInt16LE(localOff + 26); const localExtraLen = data.readUInt16LE(localOff + 28); const dataStart = localOff + 30 + localNameLen + localExtraLen; const fileData = data.slice(dataStart, dataStart + compSize); const fullPath = path.join(outputDir, fileName); if (fileName.endsWith('/')) { ensureDir(fullPath); dirCount++; continue; } ensureDir(path.dirname(fullPath)); let decompressed; if (compMethod === 0) decompressed = fileData; else if (compMethod === 8) decompressed = zlib.inflateRawSync(fileData); else { continue; } fs.writeFileSync(fullPath, decompressed); console.log(' ' + fileName + ' (' + decompressed.length + ' bytes)'); count++; } console.log('Done: ' + count + ' files, ' + dirCount + ' dirs'); } function decompress(inputPath, outputDir) { try { fs.statSync(inputPath); } catch (e) { console.error('Error: File not found - ' + inputPath); return; } const basename = path.basename(inputPath); if (!outputDir) { const name = basename.replace(/\.tar\.gz$/i, '').replace(/\.tgz$/i, '') .replace(/\.tar$/i, '').replace(/\.gz$/i, '').replace(/\.zip$/i, ''); outputDir = path.join(path.dirname(inputPath), name + '_out'); } console.log('Operation: Decompress'); console.log('Source: ' + basename); console.log('Output: ' + outputDir); if (basename.endsWith('.tar.gz') || basename.endsWith('.tgz')) { const tmp = '/tmp/_t' + Date.now() + '.tar'; fs.writeFileSync(tmp, zlib.gunzipSync(fs.readFileSync(inputPath))); extractTar(tmp, outputDir); try { fs.rmSync(tmp); } catch (e) { } } else if (basename.endsWith('.tar')) { extractTar(inputPath, outputDir); } else if (basename.endsWith('.gz')) { const gzOut = outputDir || path.join(path.dirname(inputPath), basename.replace(/\.gz$/i, '')); decompressGzip(inputPath, gzOut); } else if (basename.endsWith('.zip')) { extractZip(inputPath, outputDir); } else { console.error('Error: Unsupported format - ' + basename); } } // ══════════════════════════════════════════════════════════════════════════ // Core Logic — Compress (DO NOT REPLACE) // ══════════════════════════════════════════════════════════════════════════ function buildTarGz(files, baseDir, outputPath) { const blocks = []; for (const entry of files) { const relPath = typeof entry === 'string' ? entry : entry.name; const isDir = typeof entry === 'object' ? entry.isDir : false; const fullPath = path.join(baseDir, relPath); const header = Buffer.alloc(512, 0); header.write(relPath, 0, 100, 'utf8'); if (isDir) { header.write('0000755', 100, 8, 'utf8'); header.write('0000000', 108, 8, 'utf8'); header.write('0000000', 116, 8, 'utf8'); header[156] = 53; blocks.push(header); console.log(' Added: ' + relPath + '/ (dir)'); continue; } const content = fs.readFileSync(fullPath); header.write('0000644', 100, 8, 'utf8'); header.write('0000000', 108, 8, 'utf8'); header.write('0000000', 116, 8, 'utf8'); const sizeStr = content.length.toString(8).padStart(11, '0'); for (let i = 0; i < 11; i++) header[124 + i] = sizeStr.charCodeAt(i); header[135] = 32; const timeStr = Math.floor(Date.now() / 1000).toString(8).padStart(11, '0'); for (let i = 0; i < 11; i++) header[136 + i] = timeStr.charCodeAt(i); header[147] = 32; header[156] = 48; header.write('ustar', 257, 5, 'utf8'); header[262] = 0; header[263] = 48; header[264] = 48; let checksum = 0; for (let i = 0; i < 512; i++) checksum += header[i]; const chkStr = checksum.toString(8).padStart(6, '0'); for (let i = 0; i < 6; i++) header[148 + i] = chkStr.charCodeAt(i); header[154] = 0; header[155] = 32; blocks.push(header); blocks.push(content); const pad = (512 - content.length % 512) % 512; if (pad > 0) blocks.push(Buffer.alloc(pad, 0)); console.log(' Added: ' + relPath + ' (' + content.length + ' bytes)'); } blocks.push(Buffer.alloc(512, 0)); blocks.push(Buffer.alloc(512, 0)); const tarData = Buffer.concat(blocks); let finalData; let ext = path.extname(outputPath).toLowerCase(); if (ext === '.gz' || ext === '.tgz' || outputPath.endsWith('.tar.gz')) { finalData = zlib.gzipSync(tarData); } else { finalData = tarData; } fs.writeFileSync(outputPath, finalData); console.log('Created: ' + path.basename(outputPath) + ' (' + finalData.length + ' bytes)'); const ratio = finalData.length > 0 ? (100 * (1 - finalData.length / tarData.length)).toFixed(1) : '0.0'; console.log('Compression ratio: ' + ratio + '%'); }
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen