/** * 직렬 생성 세션 회수 — 디렉터리 생성 시각(13:02:30+ )순 = JOBS 실행 순서. * 각 세션의 exec-*.png 을 JOBS 순서에 매핑해 .gen/--.png 로 복사. * 이후 webp 변환은 convert-images.mjs 가 담당한다. */ import fs from "node:fs"; import path from "node:path"; import os from "node:os"; import { fileURLToPath } from "node:url"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const staging = path.join(__dirname, ".gen"); const genDir = path.join(os.homedir(), ".codex", "generated_images"); const START = new Date("2026-08-21T13:02:30").getTime(); // gen-images.mjs 의 JOBS 순서와 동일하게 유지 (slug--name 순서가 곧 실행 순서) const ORDER = [ "muwol-coffee--beans-hero", "muwol-coffee--pourover", "muwol-coffee--roastery", "hyang-incense--smoke", "hyang-incense--agarwood", "baekje-celadon--ewer-dark", "baekje-celadon--crazing", "baekje-celadon--inlay", "form-architecture--pavilion-bw", "form-architecture--interior-bw", "form-architecture--model-bw", "font-foundry--metaltype", "font-foundry--inkstone", "overtone-sound--installation", "overtone-sound--mic-macro", "pulsegate--datacenter", "lumina-optics--lens-section", "lumina-optics--prism-bench", "orbit-aerospace--static-fire", "orbit-aerospace--channel-macro", "synapse-bci--chip-macro", "synapse-bci--thread-array", ]; // 주의: gen-images.mjs 실제 JOBS 순서는 위와 다를 수 있다 — 아래에서 스크립트에서 // 직접 읽어오지 않고 수동 대조했는지 확인 필요. 안전장치: 개수 일치 검사. const sessions = fs .readdirSync(genDir) .map((s) => { const dir = path.join(genDir, s); let st; try { st = fs.statSync(dir); } catch { return null; } if (!st.isDirectory() || st.birthtimeMs < START) return null; const pngs = fs .readdirSync(dir) .filter((f) => f.startsWith("exec-") && f.endsWith(".png")) .map((f) => ({ f: path.join(dir, f), t: fs.statSync(path.join(dir, f)).mtimeMs })) .sort((a, b) => a.t - b.t); if (!pngs.length) return null; return { dir, born: st.birthtimeMs, png: pngs[pngs.length - 1].f }; }) .filter(Boolean) .sort((a, b) => a.born - b.born); console.log(`sessions after START: ${sessions.length} / expected: ${ORDER.length}`); if (sessions.length !== ORDER.length) { console.error("세션 수가 JOBS 수와 다릅니다 — 자동 매핑 중단. 수동 검토 필요."); sessions.forEach((s, i) => console.log(i, path.basename(s.dir), new Date(s.born).toISOString())); process.exit(1); } fs.mkdirSync(staging, { recursive: true }); sessions.forEach((s, i) => { const out = path.join(staging, `${ORDER[i]}.png`); fs.copyFileSync(s.png, out); console.log(`ok: ${ORDER[i]} <- ${path.basename(s.dir)}`); });