#!/usr/bin/env node // Turns a war-room workflow result into warroom/board.json. // Usage: node materialize.mjs [YYYY-MM-DD] // The workflow result is the task output file; this reads .result = { org, synthesis }. import { readFileSync, writeFileSync } from 'node:fs'; import { join } from 'node:path'; const [, , resultPath, warroomDir = 'warroom', date = 'unknown'] = process.argv; if (!resultPath) { console.error('usage: node materialize.mjs [date]'); process.exit(1); } const raw = JSON.parse(readFileSync(resultPath, 'utf8')); const r = raw.result ?? raw; // task-output wraps in .result const s = r.synthesis; const norm = (x = '') => { const m = String(x).toUpperCase().match(/\b(CEO|CTO|CPO|CMO|COO|CISO|CFO)\b/); return m ? m[1] : x; }; const TEAM = { CEO: 'Strategy & BizDev', CTO: 'Engineering', CPO: 'Product & Design', CMO: 'Growth, Content & SEO', COO: 'Ops, Legal & Finance', }; const org = (r.org || []).map((o) => ({ role: norm(o.role), team: TEAM[norm(o.role)] || o.team, roster: o.roster || [] })); const tickets = (s.tickets || []).map((t) => ({ id: t.id, title: t.title, role: norm(t.role), team: TEAM[norm(t.role)] || t.team || '', priority: t.priority, effort: t.effort || 'M', area: t.area || '', status: t.status || 'backlog', problem: t.problem, acceptance: t.acceptance || [], deps: t.deps || [], comments: [], created: date, })); const board = { meta: { product: (r.meta && r.meta.product) || 'product', generatedBy: 'war-room workflow', generated: date }, org, readiness: s.readiness || null, blockers: s.blockers || [], criticalPath: s.criticalPath || [], sprint0: s.sprint0 || [], crossTeamDeps: s.crossTeamDeps || [], tickets, }; writeFileSync(join(warroomDir, 'board.json'), JSON.stringify(board, null, 2)); console.log(`Wrote ${warroomDir}/board.json — ${tickets.length} tickets. Now run: node ${warroomDir}/build-board.mjs`);