| 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
- Copy the complete script from
## Runnable Entry Point below
- Replace ONLY
{{action}}, {{input}}, {{output}}, {{format}} with actual values
- 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
- 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)
(function() {
const zlib = require('zlib');
const fs = require('fs');
const path = require('path');
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) {
crc = ;
table = ();
( i = ; i < ; i++) {
c = i;
( j = ; j < ; j++)
c = (c & ) ? ( ^ (c >>> )) : (c >>> );
table[i] = c;
}
( i = ; i < buf.; i++)
crc = table[(crc ^ buf[i]) & ] ^ (crc >>> );
(crc ^ ) >>> ;
}
() {
compressed = fs.(inputPath);
decompressed = zlib.(compressed);
fs.(outputPath, decompressed);
.( + path.(outputPath) + + decompressed. + );
}
() {
data = fs.(tarPath);
(outputDir);
offset = , files = , dirs = ;
(offset + <= data.) {
header = data.(offset, offset + );
(header[] === ) ;
name = header.(, ).().(, ).();
size = (data, offset + , offset + );
typeflag = header[];
(!name) ;
offset += ;
content = data.(offset, offset + size);
offset += .(size / ) * ;
fullPath = path.(outputDir, name);
(typeflag === ) { (fullPath); dirs++; }
{
(path.(fullPath));
fs.(fullPath, content);
.( + name + + size + );
files++;
}
}
.( + files + + dirs + );
}
() {
data = fs.(zipPath);
(outputDir);
eocdOffset = -;
( i = data. - ; i >= ; i--) {
(data[i] === && data[i + ] === &&
data[i + ] === && data[i + ] === ) {
eocdOffset = i; ;
}
}
(eocdOffset === -) ();
totalEntries = data.(eocdOffset + );
cdOffset = data.(eocdOffset + );
cdPos = cdOffset;
count = , dirCount = ;
( i = ; i < totalEntries; i++) {
sig = data.(cdPos);
(sig !== ) ();
compMethod = data.(cdPos + );
compSize = data.(cdPos + );
nameLen = data.(cdPos + );
extraLen = data.(cdPos + );
localOff = data.(cdPos + );
fileName = data.(cdPos + , cdPos + + nameLen).();
cdPos += + nameLen + extraLen;
localNameLen = data.(localOff + );
localExtraLen = data.(localOff + );
dataStart = localOff + + localNameLen + localExtraLen;
fileData = data.(dataStart, dataStart + compSize);
fullPath = path.(outputDir, fileName);
(fileName.()) { (fullPath); dirCount++; ; }
(path.(fullPath));
decompressed;
(compMethod === ) decompressed = fileData;
(compMethod === ) decompressed = zlib.(fileData);
{ ; }
fs.(fullPath, decompressed);
.( + fileName + + decompressed. + );
count++;
}
.( + count + + dirCount + );
}
() {
{ fs.(inputPath); } (e) {
.( + inputPath); ;
}
basename = path.(inputPath);
(!outputDir) {
name = basename.(, ).(, )
.(, ).(, ).(, );
outputDir = path.(path.(inputPath), name + );
}
.();
.( + basename);
.( + outputDir);
(basename.() || basename.()) {
tmp = + .() + ;
fs.(tmp, zlib.(fs.(inputPath)));
(tmp, outputDir);
{ fs.(tmp); } (e) { }
} (basename.()) {
(inputPath, outputDir);
} (basename.()) {
gzOut = outputDir || path.(path.(inputPath), basename.(, ));
(inputPath, gzOut);
} (basename.()) {
(inputPath, outputDir);
} {
.( + basename);
}
}
() {
blocks = [];
( entry files) {
relPath = entry === ? entry : entry.;
isDir = entry === ? entry. : ;
fullPath = path.(baseDir, relPath);
header = .(, );
header.(relPath, , , );
(isDir) {
header.(, , , );
header.(, , , );
header.(, , , );
header[] = ;
blocks.(header);
.( + relPath + );
;
}
content = fs.(fullPath);
header.(, , , );
header.(, , , );
header.(, , , );
sizeStr = content..().(, );
( i = ; i < ; i++) header[ + i] = sizeStr.(i);
header[] = ;
timeStr = .(.() / ).().(, );
( i = ; i < ; i++) header[ + i] = timeStr.(i);
header[] = ;
header[] = ;
header.(, , , );
header[] = ; header[] = ; header[] = ;
checksum = ;
( i = ; i < ; i++) checksum += header[i];
chkStr = checksum.().(, );
( i = ; i < ; i++) header[ + i] = chkStr.(i);
header[] = ; header[] = ;
blocks.(header);
blocks.(content);
pad = ( - content. % ) % ;
(pad > ) blocks.(.(pad, ));
.( + relPath + + content. + );
}
blocks.(.(, ));
blocks.(.(, ));
tarData = .(blocks);
finalData;
ext = path.(outputPath).();
(ext === || ext === || outputPath.()) {
finalData = zlib.(tarData);
} {
finalData = tarData;
}
fs.(outputPath, finalData);
.( + path.(outputPath) + + finalData. + );
ratio = finalData. > ? ( * ( - finalData. / tarData.)).() : ;
.( + ratio + );
}
() {
localEntries = [];
centralEntries = [];
dataOffset = ;
( entry files) {
relPath = entry === ? entry : entry.;
isDir = entry === ? entry. : ;
fullPath = path.(baseDir, relPath);
fileData;
(isDir) {
fileData = .();
} {
fileData = fs.(fullPath);
}
zipName = isDir ? (relPath.() ? relPath : relPath + ) : relPath;
fileName = .(zipName, );
compressed = isDir ? .() : zlib.(fileData);
crc = isDir ? : (fileData);
localHeader = .();
localHeader.(, );
localHeader.(, );
localHeader.(, );
localHeader.(isDir ? : , );
localHeader.(crc, );
localHeader.(isDir ? : compressed., );
localHeader.(isDir ? : fileData., );
localHeader.(fileName., );
localEntries.(.([localHeader, fileName, compressed]));
centralHeader = .();
centralHeader.(, );
centralHeader.(, );
centralHeader.(, );
centralHeader.(, );
centralHeader.(isDir ? : , );
centralHeader.(crc, );
centralHeader.(isDir ? : compressed., );
centralHeader.(isDir ? : fileData., );
centralHeader.(fileName., );
centralHeader.(, );
centralHeader.(, );
centralHeader.(, );
centralHeader.(, );
centralHeader.(, );
centralHeader.(dataOffset, );
centralEntries.(.([centralHeader, fileName]));
dataOffset += + fileName. + compressed.;
.( + zipName + + fileData. + );
}
localData = .(localEntries);
cdData = .(centralEntries);
eocd = .();
eocd.(, );
eocd.(, );
eocd.(, );
eocd.(centralEntries., );
eocd.(centralEntries., );
eocd.(cdData., );
eocd.(localData., );
eocd.(, );
fs.(zipPath, .([localData, cdData, eocd]));
.( + path.(zipPath) + + (localData. + cdData. + ) + );
}
() {
{ fs.(inputPath); } (e) {
.( + inputPath); ;
}
basename = path.(inputPath);
(!outputPath) {
fmt = format || ;
outputPath = path.(path.(inputPath), basename + + fmt.(, ));
}
stat = fs.(inputPath);
files = [];
(stat.()) {
list = fs.(inputPath);
( f list) {
s = fs.(path.(inputPath, f));
files.(s.() ? { : f, : } : f);
}
} {
files.(basename);
}
.();
.( + (format || ));
.( + outputPath);
baseDir = stat.() ? inputPath : (path.(inputPath) || inputPath);
ext = outputPath.();
useZip = format ? (format === ) : ext.();
(useZip) {
(files, baseDir, outputPath);
} {
(files, baseDir, outputPath);
}
}
action = ;
input = ;
output = ;
format = ;
(action === ) {
(input, output || );
} (action === ) {
(input, output || , format || );
}
})();
Usage Notes
Input / Output
Decompress mode:
input: Path to the archive file (.tar, .tar.gz, .tgz, .zip, .gz)
output: Extraction directory path. If omitted, auto-generated as <archive>_out in the same directory.
- For
.gz: output is treated as the TAR output file path (not directory). The gzip always wraps a TAR archive, so decompressing yields a .tar file, not the original files. Use format=tar decompress on the result to extract.
- For all other formats:
output is treated as an extraction directory.
- Format is auto-detected from file extension
Compress mode:
input: Path to a single file or directory
output: Archive output path. If omitted, auto-generated as <input>.<format>
format: tar, tar.gz, tgz, zip, or gz. Defaults to tar.gz.
- Note on
format=gz: Internally wraps the file(s) in a TAR container first, then gzips. The result is functionally a .tar.gz with a .gz extension. Decompressing it yields a TAR, not the raw original file.
Typical output example:
Operation: Decompress
Source: archive.zip
Output: /output/archive_out
hello.txt (33 bytes)
readme.txt (34 bytes)
sub/
Done: 2 files, 1 dirs
Operation: Compress
Format: tar.gz
Output: /output/myfolder.tar.gz
Added: hello.txt (33 bytes)
Added: readme.txt (34 bytes)
Added: sub/ (dir)
Created: myfolder.tar.gz (263 bytes)
Compression ratio: 68.2%
Feature Support
| Feature | Input | Output |
|---|
| GZIP (.gz) | decompress | TAR file extracted to output path (or same dir if omitted). Note: .gz always contains a TAR archive (gzip wraps TAR), so the decompressed result is a .tar file, not the original files. |
| TAR (.tar) multi-file | decompress | Directory with all files extracted |
| TAR.GZ / TGZ multi-file | decompress | Directory (gunzip + tar parse in tmp) |
| ZIP (.zip) multi-file | decompress | Directory with DEFLATE decompression |
| GZIP (.gz) single file | compress | TAR-wrapped GZIP archive — equivalent to .tar.gz internally, NOT a pure gzip of the file |
| TAR creation | compress | TAR archive from file or directory |
| TAR.GZ / TGZ creation | compress | GZIP-compressed TAR archive |
| ZIP creation | compress | DEFLATE-compressed ZIP archive |
| Directory compression | compress | All top-level entries archived (non-recursive) |
Output Validation
After generation, the output should be validated:
- Decompress: Verify extracted files exist at the output path with correct byte counts
- Compress (TAR):
head -c 512 <file> should show ustar magic at byte 257
- Compress (ZIP): EOCD signature
PK\x05\x06 must exist in the last 22 bytes
- Compress (GZIP): First 2 bytes must be
0x1F 0x8B (GZIP magic)
Quick validation snippets (run with jsexec):
const fs = require('fs');
const d = fs.readFileSync('{{output}}');
console.log('GZIP magic:', d[0] === 0x1F && d[1] === 0x8B ? 'PASS' : 'FAIL');
const fs = require('fs');
const d = fs.readFileSync('{{output}}');
const o = d.length - 22;
console.log('ZIP EOCD:', d[o] === 0x50 && d[o+1] === 0x4B && d[o+2] === 0x05 && d[o+3] === 0x06 ? 'PASS' : 'FAIL');
console.log('Size:', d.length, 'bytes');
const fs = require('fs');
const d = fs.readFileSync('{{output}}');
console.log('TAR ustar:', d.slice(257, 262).toString() === 'ustar' ? 'PASS' : 'FAIL');
console.log('Size:', d.length, 'bytes');
const fs = require('fs');
const path = require('path');
const dir = '{{output}}';
const entries = fs.readdirSync(dir);
entries.forEach(f => {
const s = fs.statSync(path.join(dir, f));
console.log(s.isDirectory() ? f + '/ (dir)' : f + ' (' + s.size + ' bytes)');
});
Common Pitfalls
format vs output extension priority: When both format and output are specified, format takes priority over the output file extension. When only output is specified, the extension determines the archive type. When neither is specified, defaults to tar.gz.
⚠️ format override + decompress mismatch: Decompress auto-detection is based on file extension, NOT the format used during compression. If you compress with format=zip + output=archive.tar, the resulting file is a valid ZIP but decompression will attempt TAR parsing (and fail) because the extension is .tar. To decompress such files, rename them to the correct extension first.
Template literal escaping: The Entry Point uses plain string variables (const action = '{{action}}';), so backticks are safe. However, always use fs.readFileSync() instead if embedding large binary paths or content that may contain special characters.
fs.existsSync() is NOT available: Use try { fs.statSync(path) } catch (e) {} instead.
fs.unlinkSync() is NOT available: Use fs.rmSync() for file deletion.
fs.statSync().size may return 0 in WASM: Always use .length from fs.readFileSync().
TAR size field uses relative offset: Always offset + 124, NOT absolute byte position 124.
Shell tar/gzip/unzip may be limited: All operations are done inside jsexec. Do not fall back to shell tools.
No modification of core logic: The Runnable Entry Point contains the only valid implementation. Format parsers (TAR header, ZIP EOCD, CRC32) must NOT be rewritten or simplified.
C3 Verification
| Check Item | Constraint | Common Omission | Method |
|---|
| Output structure | Archive file or extracted directory produced | Empty output | Check file count / archive size |
| Core constraints | Format headers valid (Compress: TAR→ustar, ZIP→EOCD, GZIP→0x1F8B; Decompress: extracted files readable) | Corrupted format | Binary inspection of header bytes |
| Pipeline integrity | Correct dispatch (compress vs decompress) | Wrong operation | Verify action parameter |
| Format coverage | All 5 formats handled (.tar, .tar.gz, .tgz, .zip, .gz) | Missing format handler | Code review of decompress() |
| CRC-32 correctness | ZIP CRC32 matches standard implementation (compress only) | Wrong checksums | Cross-check against known CRC32 tool |
| Directory handling | TAR typeflag 53 and ZIP trailing '/' supported | Directories lost | Verify dir entries in output |
Note: Header magic validation (ustar/EOCD/GZIP) only applies to compress direction. For decompress, verify extracted file count and content integrity instead.