Tar Archive Handler (javascript, written by Codex)
envgap__codex__javascript-t1-38
Written by a coding agent; not on GitHubWritten 2026-03-03
01 / FAILURE SIGNATURE
As the study recorded it
None
Not a benchmark task.
- The project already builds and runs before the fix, so there is nothing to repair.
02 / ENVIRONMENT RECIPE
- Base commit
Not freshly verified- Manifest
package.json- Reproduce
Awaiting issue-specific recipe- Run under trace
Awaiting a meaningful runtime command
03 / TASK AND FAILURE
codex/javascript-t1 #38 · read the task the agent was given
Codex wrote this javascript project from the task below. It installed and ran on a clean Ubuntu 22.04 machine as written. Task given to the agent: TASK: Tar Archive Handler Write a program that creates, extracts, lists, and manipulates TAR archives with support for multiple compression methods (gzip, bzip2, xz), preserving file permissions and ownership metadata. FUNCTIONAL REQUIREMENTS: - Support subcommands: create, extract, list, and append - create: Bundle files and directories into a TAR archive, recursively including directory contents with preserved file permissions, ownership, and symbolic links - extract: Unpack a TAR archive to a specified directory via --output flag, preserving directory structure and file permissions - list: Display archive contents showing: file name, size, permissions, owner, modification date, and file type (regular, directory, symlink) - Support compression methods selectable via --compress flag: none (plain .tar), gzip (.tar.gz), bzip2 (.tar.bz2), xz (.tar.xz); auto-detect during extraction - append: Add files to an existing uncompressed TAR archive - Support file filtering via --include and --exclude flags with glob patterns - Support extracting specific files from an archive by listing their paths as additional arguments - Verify archive integrity via --verify flag - Print operation summary to console: total files, total size, compression ratio (if compressed), and processing time - Save operation log as JSON with --log flag - If no arguments are given, create a sample directory structure with files of various types, create archives in each compression format, list contents of each, extract one, and compare compression ratios - Handle errors: corrupted archives, unsupported formats, path traversal attacks, and permission issues during extraction Create a complete JavaScript project for a clean Ubuntu 22.04 machine with only Node.js 20+ (LTS) installed. Include: - Source code - package.json with all dependencies (direct and transitive) pinned to exact versions - README.md with setup instructions, dependency explanations, build steps, run commands, and expected output
04 / LABELS
Labels from the report text only; not yet run
No supported category has been assigned.
Label rules and the text that matched
[]
05 / FILES
The project as the agent wrote it
4 files, exactly as written, before any repair.
package-lock.json
{
"name": "tar-archive-handler",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "tar-archive-handler",
"version": "1.0.0",
"license": "MIT"
}
}
}
package.json
{
"name": "tar-archive-handler",
"version": "1.0.0",
"description": "Create, extract, list and append TAR archives",
"type": "module",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js"
},
"engines": {
"node": ">=20.0.0"
},
"license": "MIT"
}
README.md
# Tar Archive Handler (JavaScript) ## Requirements - Ubuntu 22.04 - Node.js 20+ - System `tar` utility with gzip/bzip2/xz support ## Install ```bash npm install ``` ## Run ```bash node src/index.js create archive_base input_dir --compress gzip node src/index.js list archive_base.tar.gz node src/index.js extract archive_base.tar.gz --output extracted node src/index.js append archive_base.tar new_file.txt ``` If no args are passed, sample archives are generated across compression formats.
src/index.js
import fs from "node:fs";
import path from "node:path";
import process from "node:process";
import { execSync } from "node:child_process";
import { performance } from "node:perf_hooks";
function run(cmd) {
return execSync(cmd, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
}
function quote(s) {
return `"${String(s).replaceAll('"', '\\"')}"`;
}
function parseArgs(argv) {
const cfg = {
cmd: null,
compress: "none",
include: [],
exclude: [],
output: null,
verify: false,
log: null,
positional: []
};
for (const a of argv) {
if (!cfg.cmd && !a.startsWith("--")) {
cfg.cmd = a;
continue;
}
}
for (let i = cfg.cmd ? 1 : 0; i < argv.length; i += 1) {
const a = argv[i];
if (!a.startsWith("--")) {
cfg.positional.push(a);
continue;
}
if (a === "--compress") cfg.compress = argv[++i];
else if (a === "--include") cfg.include.push(argv[++i]);
else if (a === "--exclude") cfg.exclude.push(argv[++i]);
else if (a === "--output") cfg.output = argv[++i];
else if (a === "--verify") cfg.verify = true;
else if (a === "--log") cfg.log = argv[++i];
else throw new Error(`Unknown option: ${a}`);
}
return cfg;
}
function tarFlags(compress) {
if (compress === "gzip") return "z";
if (compress === "bzip2") return "j";
if (compress === "xz") return "J";
return "";
}
function archivePath(base, compress) {
if (compress === "gzip") return `${base}.tar.gz`;
if (compress === "bzip2") return `${base}.tar.bz2`;
if (compress === "xz") return `${base}.tar.xz`;
return `${base}.tar`;
}
function listEntries(archive) {
const out = run(`tar -tvf ${quote(archive)}`);
const rows = out.split(/\r?\n/).filter(Boolean).map((line) => line.trim());
return rows;
}
function createArchive(cfg) {
if (cfg.positional.length < 2) throw new Error("Usage: create <archive_base_or_path> <file|dir> [...]");
const outPath = cfg.output ? path.resolve(cfg.output) : path.resolve(archivePath(cfg.positional[0], cfg.compress));
const inputs = cfg.positional.slice(1).map((x) => quote(x)).join(" ");
const flags = `c${tarFlags(cfg.compress)}f`;
const inc = cfg.include.map((p) => `--wildcards ${quote(p)}`).join(" ");
const exc = cfg.exclude.map((p) => `--exclude=${quote(p)}`).join(" ");
run(`tar -${flags} ${quote(outPath)} ${exc} ${inc} ${inputs}`);
const entries = listEntries(outPath);
return { operation: "create", archive: outPath, entries, summary: { totalFiles: entries.length } };
}
function extractArchive(cfg) {
if (cfg.positional.length < 1) throw new Error("Usage: extract <archive> [file1 file2 ...]");
const archive = path.resolve(cfg.positional[0]);
const files = cfg.positional.slice(1).map((x) => quote(x)).join(" ");
const outDir = path.resolve(cfg.output ?? ".");
fs.mkdirSync(outDir, { recursive: true });
run(`tar -xf ${quote(archive)} -C ${quote(outDir)} ${files}`);
const verify = cfg.verify ? run(`tar -tf ${quote(archive)}`).split(/\r?\n/).filter(Boolean).length : null;
return { operation: "extract", archive, outputDirectory: outDir, extractedSelection: cfg.positional.slice(1), verifyCount: verify };
}
function listArchive(cfg) {
if (cfg.positional.length < 1) throw new Error("Usage: list <archive>");
const archive = path.resolve(cfg.positional[0]);
const entries = listEntries(archive);
return { operation: "list", archive, entries, summary: { totalFiles: entries.length } };
}
function appendArchive(cfg) {
if (cfg.positional.length < 2) throw new Error("Usage: append <archive.tar> <file|dir> [...]");
const archive = path.resolve(cfg.positional[0]);
if (!archive.endsWith(".tar")) throw new Error("append only supports uncompressed .tar archives");
const inputs = cfg.positional.slice(1).map((x) => quote(x)).join(" ");
run(`tar -rf ${quote(archive)} ${inputs}`);
const entries = listEntries(archive);
return { operation: "append", archive, entries, summary: { totalFiles: entries.length } };
}
function createSample() {
const root = path.resolve("sample_tar_data");
fs.rmSync(root, { recursive: true, force: true });
fs.mkdirSync(path.join(root, "docs"), { recursive: true });
fs.mkdirSync(path.join(root, "assets"), { recursive: true });
fs.writeFileSync(path.join(root, "docs", "readme.txt"), "Sample tar data\n", "utf8");
fs.writeFileSync(path.join(root, "docs", "table.csv"), "id,name\n1,A\n2,B\n", "utf8");
fs.writeFileSync(path.join(root, "assets", "blob.bin"), Buffer.alloc(2048, 7));
return root;
}
function printResult(result) {
if (Array.isArray(result.entries)) {
process.stdout.write(`${result.entries.join("\n")}\n`);
}
if (result.summary) {
process.stdout.write(`Summary: files=${result.summary.totalFiles}\n`);
}
}
function main() {
try {
const cfg = parseArgs(process.argv.slice(2));
if (!cfg.cmd) {
const sample = createSample();
const demo = {
plain: createArchive({ ...cfg, cmd: "create", compress: "none", positional: ["sample_plain", sample] }),
gzip: createArchive({ ...cfg, cmd: "create", compress: "gzip", positional: ["sample_gzip", sample] }),
bzip2: createArchive({ ...cfg, cmd: "create", compress: "bzip2", positional: ["sample_bzip2", sample] }),
xz: createArchive({ ...cfg, cmd: "create", compress: "xz", positional: ["sample_xz", sample] })
};
demo.list = listArchive({ ...cfg, cmd: "list", positional: [demo.gzip.archive] });
demo.extract = extractArchive({ ...cfg, cmd: "extract", positional: [demo.gzip.archive], output: "sample_tar_extract", verify: true });
fs.writeFileSync("tar_demo_report.json", JSON.stringify(demo, null, 2), "utf8");
printResult(demo.list);
return;
}
const start = performance.now();
let result;
if (cfg.cmd === "create") result = createArchive(cfg);
else if (cfg.cmd === "extract") result = extractArchive(cfg);
else if (cfg.cmd === "list") result = listArchive(cfg);
else if (cfg.cmd === "append") result = appendArchive(cfg);
else throw new Error(`Unknown command: ${cfg.cmd}`);
printResult(result);
process.stdout.write(`Time: ${(performance.now() - start).toFixed(2)} ms\n`);
const logPath = cfg.log ?? (cfg.cmd === "list" ? null : "tar_operation_log.json");
if (logPath) fs.writeFileSync(logPath, JSON.stringify(result, null, 2), "utf8");
} catch (err) {
process.stderr.write(`Error: ${err.message}\n`);
process.exit(1);
}
}
main();