NODEDC_1C/llm_normalizer/scripts/archiveRunArtifacts.mjs

275 lines
7.2 KiB
JavaScript

#!/usr/bin/env node
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
function parseArgs(argv) {
const args = {
clean: false,
label: "",
dryRun: false
};
for (let i = 0; i < argv.length; i += 1) {
const token = argv[i];
if (token === "--clean") {
args.clean = true;
continue;
}
if (token === "--dry-run") {
args.dryRun = true;
continue;
}
if (token === "--label") {
args.label = String(argv[i + 1] ?? "").trim();
i += 1;
}
}
return args;
}
function sanitizeLabel(value) {
return value
.trim()
.replace(/\s+/g, "_")
.replace(/[^a-zA-Z0-9_-]/g, "")
.slice(0, 48);
}
function formatTimestamp(date) {
const pad = (v) => String(v).padStart(2, "0");
return [
date.getFullYear(),
pad(date.getMonth() + 1),
pad(date.getDate())
].join("-")
+ "_"
+ [pad(date.getHours()), pad(date.getMinutes()), pad(date.getSeconds())].join("-");
}
function ensureDir(dirPath) {
fs.mkdirSync(dirPath, { recursive: true });
}
function listFilesRecursively(rootDir) {
if (!fs.existsSync(rootDir)) {
return [];
}
const output = [];
const stack = [rootDir];
while (stack.length > 0) {
const current = stack.pop();
if (!current) continue;
for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
const full = path.join(current, entry.name);
if (entry.isDirectory()) {
stack.push(full);
} else if (entry.isFile()) {
output.push(full);
}
}
}
return output;
}
function copyFilePreserveRelative(fromPath, baseDir, targetBaseDir) {
const rel = path.relative(baseDir, fromPath);
const target = path.join(targetBaseDir, rel);
ensureDir(path.dirname(target));
fs.copyFileSync(fromPath, target);
return target;
}
function copyDirectoryPreserveRelative(fromDir, baseDir, targetBaseDir) {
const files = listFilesRecursively(fromDir);
const copied = [];
for (const filePath of files) {
copied.push(copyFilePreserveRelative(filePath, baseDir, targetBaseDir));
}
return copied;
}
function removePath(targetPath) {
if (!fs.existsSync(targetPath)) {
return;
}
fs.rmSync(targetPath, { recursive: true, force: true });
}
function pickReportEntries(reportsDir) {
if (!fs.existsSync(reportsDir)) {
return [];
}
const staticKeep = new Set([
"v2_0_1_clarification_eval_plan.md",
"v2_0_2_eval_plan.md",
"v2_pilot_eval_plan.md"
]);
const entries = [];
for (const entry of fs.readdirSync(reportsDir, { withFileTypes: true })) {
const full = path.join(reportsDir, entry.name);
if (entry.isDirectory()) {
if (entry.name.startsWith("minimal_package_")) {
entries.push(full);
}
continue;
}
if (!entry.isFile()) {
continue;
}
if (staticKeep.has(entry.name)) {
continue;
}
const isGenerated =
entry.name.startsWith("assistant-stage1-")
|| entry.name.startsWith("assistant-compare-")
|| entry.name.startsWith("normalizer_eval_")
|| entry.name.startsWith("normalizer_v")
|| entry.name.startsWith("minimal_package_");
if (isGenerated) {
entries.push(full);
}
}
return entries;
}
function pickLogFiles(logDir, filePattern) {
if (!fs.existsSync(logDir)) {
return [];
}
return fs
.readdirSync(logDir, { withFileTypes: true })
.filter((entry) => entry.isFile() && filePattern.test(entry.name))
.map((entry) => path.join(logDir, entry.name));
}
function writeJson(filePath, payload) {
ensureDir(path.dirname(filePath));
fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf-8");
}
function main() {
const args = parseArgs(process.argv.slice(2));
const scriptFile = fileURLToPath(import.meta.url);
const root = path.resolve(path.dirname(scriptFile), "..");
const reportsDir = path.resolve(root, "reports");
const docsRunsDir = path.resolve(root, "docs", "runs");
const tracesDir = path.resolve(root, "data", "traces");
const sessionsDir = path.resolve(root, "data", "assistant_sessions");
const stamp = formatTimestamp(new Date());
const label = sanitizeLabel(args.label);
const runFolderName = label ? `${stamp}_${label}` : stamp;
const runDir = path.join(docsRunsDir, runFolderName);
const reportEntries = pickReportEntries(reportsDir);
const traceFiles = pickLogFiles(tracesDir, /\.json$/i);
const sessionFiles = pickLogFiles(sessionsDir, /\.json$/i);
const copiedReports = [];
const copiedLogs = [];
if (!args.dryRun) {
ensureDir(runDir);
ensureDir(path.join(runDir, "reports"));
ensureDir(path.join(runDir, "logs", "traces"));
ensureDir(path.join(runDir, "logs", "assistant_sessions"));
}
for (const sourcePath of reportEntries) {
const stat = fs.statSync(sourcePath);
if (args.dryRun) {
copiedReports.push(sourcePath);
continue;
}
if (stat.isDirectory()) {
copiedReports.push(...copyDirectoryPreserveRelative(sourcePath, reportsDir, path.join(runDir, "reports")));
} else {
copiedReports.push(copyFilePreserveRelative(sourcePath, reportsDir, path.join(runDir, "reports")));
}
}
for (const sourcePath of traceFiles) {
if (!args.dryRun) {
copiedLogs.push(copyFilePreserveRelative(sourcePath, tracesDir, path.join(runDir, "logs", "traces")));
} else {
copiedLogs.push(sourcePath);
}
}
for (const sourcePath of sessionFiles) {
if (!args.dryRun) {
copiedLogs.push(copyFilePreserveRelative(sourcePath, sessionsDir, path.join(runDir, "logs", "assistant_sessions")));
} else {
copiedLogs.push(sourcePath);
}
}
if (args.clean && !args.dryRun) {
for (const entryPath of reportEntries) {
removePath(entryPath);
}
for (const entryPath of traceFiles) {
removePath(entryPath);
}
for (const entryPath of sessionFiles) {
removePath(entryPath);
}
}
const manifest = {
schema_version: "run_artifact_manifest_v0_1",
run_folder: runDir,
generated_at: new Date().toISOString(),
options: {
clean: args.clean,
dry_run: args.dryRun,
label: label || null
},
counts: {
report_entries_found: reportEntries.length,
trace_logs_found: traceFiles.length,
session_logs_found: sessionFiles.length,
report_files_copied: copiedReports.length,
log_files_copied: copiedLogs.length
},
preserved_static_reports: [
"v2_0_1_clarification_eval_plan.md",
"v2_0_2_eval_plan.md",
"v2_pilot_eval_plan.md"
]
};
if (!args.dryRun) {
writeJson(path.join(runDir, "manifest.json"), manifest);
fs.writeFileSync(
path.join(runDir, "README.md"),
[
"# Run Artifact Bundle",
"",
`- generated_at: ${manifest.generated_at}`,
`- clean_mode: ${args.clean}`,
`- reports_copied: ${manifest.counts.report_files_copied}`,
`- logs_copied: ${manifest.counts.log_files_copied}`
].join("\n"),
"utf-8"
);
}
const summary = [
`run_folder=${runDir}`,
`report_entries_found=${reportEntries.length}`,
`trace_logs_found=${traceFiles.length}`,
`session_logs_found=${sessionFiles.length}`,
`clean_mode=${args.clean}`,
`dry_run=${args.dryRun}`
].join("\n");
process.stdout.write(`${summary}\n`);
}
main();