#!/usr/bin/env node const fs = require('fs'); const path = require('path'); const { spawnSync } = require('child_process'); const ROOT = path.resolve(__dirname, '..'); function main() { const args = parseArgs(process.argv.slice(2)); const outputRoot = path.resolve(args.outputRoot || path.join(ROOT, 'outputs')); const strict = args.strict !== false; fs.mkdirSync(outputRoot, { recursive: true }); const steps = [ { id: 'proof-gap-software-form', command: ['node', ['scripts/export-proof-gap-software-form.js', '--output', path.join(outputRoot, 'tihao-proof-gap-software-form-latest'), '--strict']] }, { id: 'proof-gap-request', command: ['node', ['scripts/generate-proof-gap-request.js', '--output', path.join(outputRoot, 'proof-gap-request-latest')]] }, { id: 'proof-gap-closure', command: ['node', ['scripts/proof-gap-closure-audit.js', '--output', path.join(outputRoot, 'proof-gap-closure-latest')]] }, { id: 'feedback-loop-closure', command: ['node', ['scripts/feedback-loop-closure-audit.js', '--output', path.join(outputRoot, 'feedback-loop-closure-latest')]] }, { id: 'homepage-evidence-readiness', command: ['node', ['scripts/homepage-evidence-readiness-audit.js', '--output', path.join(outputRoot, 'homepage-evidence-readiness-latest')]] }, { id: 'intake-readiness', command: ['node', [ 'scripts/intake-readiness-audit.js', '--data-pack', path.join(outputRoot, 'data-intake-pack-latest'), '--video-pack', path.join(outputRoot, 'video-intake-pack-latest'), '--output', path.join(outputRoot, 'intake-readiness-latest') ]] }, { id: 'video-resource-readiness', command: ['node', [ 'scripts/video-resource-readiness-audit.js', '--input', path.join(outputRoot, 'video-intake-pack-latest', 'video-resource-template.csv'), '--output', path.join(outputRoot, 'video-resource-readiness-latest') ]] }, { id: 'live-preflight', command: ['node', [ 'scripts/live-preflight.js', '--output', path.join(outputRoot, 'live-preflight-latest'), '--strict', '--allow-failure' ]] }, { id: 'longrun-readiness', command: ['node', [ 'scripts/long-run-readiness-audit.js', '--mode', 'full-matrix', '--intake-readiness', path.join(outputRoot, 'intake-readiness-latest', 'intake-readiness-summary.json'), '--proof-gap', path.join(outputRoot, 'proof-gap-request-latest', 'proof-gap-request-summary.json'), '--proof-gap-closure', path.join(outputRoot, 'proof-gap-closure-latest', 'proof-gap-closure-summary.json'), '--output', path.join(outputRoot, 'long-run-readiness-latest') ]] }, { id: 'intake-field-checklist', command: ['node', [ 'scripts/intake-field-checklist.js', '--data-pack', path.join(outputRoot, 'data-intake-pack-latest'), '--video-pack', path.join(outputRoot, 'video-intake-pack-latest'), '--output', path.join(outputRoot, 'intake-field-checklist-latest') ]] }, { id: 'manual-review-label-guide', command: ['node', ['scripts/manual-review-label-guide.js', '--output', path.join(outputRoot, 'manual-review-label-guide-latest'), '--strict']] }, { id: 'proof-gap-operator-pack', command: ['node', ['scripts/proof-gap-operator-pack.js', '--outputs', outputRoot, '--output', path.join(outputRoot, 'proof-gap-operator-pack-latest'), '--strict']] }, { id: 'business-proof-progress', command: ['node', ['scripts/business-proof-progress.js', '--outputs', outputRoot, '--output', path.join(outputRoot, 'business-proof-progress-latest')]] }, { id: 'business-proof-next-actions', command: ['node', ['scripts/business-proof-next-actions.js', '--outputs', outputRoot, '--output', path.join(outputRoot, 'business-proof-next-actions-latest')]] }, { id: 'optimization-completion', command: ['node', ['scripts/optimization-completion-audit.js', '--outputs', outputRoot, '--output', path.join(outputRoot, 'optimization-completion-latest')]] }, { id: 'business-execution-index', command: ['node', ['scripts/business-execution-index.js', '--outputs', outputRoot, '--output', path.join(outputRoot, 'business-execution-index-latest'), '--strict']] }, { id: 'optimization-status', command: ['node', ['scripts/optimization-status-audit.js', '--output', path.join(outputRoot, 'optimization-status-latest')]] }, { id: 'plan-execution-status', command: ['node', ['scripts/plan-execution-status.js', '--outputs', outputRoot, '--output', path.join(outputRoot, 'plan-execution-status-latest'), '--strict']] }, { id: 'real-proof-intake-bundle', command: ['node', ['scripts/real-proof-intake-bundle.js', '--outputs', outputRoot, '--output', path.join(outputRoot, 'real-proof-intake-bundle-latest'), '--strict']] }, { id: 'software-client-list', command: ['node', ['scripts/refresh-software-client-list.js', '--outputs', outputRoot, '--output', path.join(outputRoot, 'software-client-latest')]] }, { id: 'local-seed-material-index', command: ['node', ['scripts/local-seed-material-index.js', '--outputs', outputRoot, '--output', path.join(outputRoot, 'local-seed-material-index-latest')]] }, { id: 'local-seed-to-intake-worklist', command: ['node', ['scripts/local-seed-to-intake-worklist.js', '--outputs', outputRoot, '--output', path.join(outputRoot, 'local-seed-to-intake-worklist-latest')]] }, { id: 'real-gap-material-audit', command: ['node', ['scripts/real-gap-material-audit.js', '--outputs', outputRoot, '--output', path.join(outputRoot, 'real-gap-material-audit-latest'), '--strict']] }, { id: 'real-proof-closure-work-order', command: ['node', ['scripts/real-proof-closure-work-order.js', '--outputs', outputRoot, '--output', path.join(outputRoot, 'real-proof-closure-work-order-latest'), '--strict']] }, { id: 'latest-form-index', command: ['node', ['scripts/latest-form-index.js', '--outputs', outputRoot, '--output', path.join(outputRoot, 'latest-form-index-latest'), '--strict']] }, { id: 'optimization-handoff', command: ['node', ['scripts/generate-optimization-handoff.js', '--outputs', outputRoot, '--output', path.join(outputRoot, 'optimization-handoff-latest')]] }, { id: 'experience-transcript-index', command: ['node', ['scripts/experience-transcript-index.js', '--output', path.join(outputRoot, 'experience-transcript-index-latest')]] }, { id: 'evidence-index', command: ['node', ['scripts/evidence-index.js', '--outputs', outputRoot, '--output', path.join(outputRoot, 'evidence-index-latest')]] }, { id: 'round-deposition', command: ['node', ['scripts/round-deposition-audit.js', '--outputs', outputRoot, '--output', path.join(outputRoot, 'round-deposition-latest'), '--strict']] } ]; const results = steps.map(step => runStep(step, strict)); const summary = { generatedAt: new Date().toISOString(), outputRoot, strict, passed: results.every(item => item.status === 'pass'), steps: results, artifacts: { proofGapSoftwareForm: rel(path.join(outputRoot, 'tihao-proof-gap-software-form-latest', 'tihao-proof-gap-software-form-summary.json')), proofGapRequest: rel(path.join(outputRoot, 'proof-gap-request-latest', 'proof-gap-request-summary.json')), proofGapClosure: rel(path.join(outputRoot, 'proof-gap-closure-latest', 'proof-gap-closure-summary.json')), feedbackLoopClosure: rel(path.join(outputRoot, 'feedback-loop-closure-latest', 'feedback-loop-closure-summary.json')), homepageEvidenceReadiness: rel(path.join(outputRoot, 'homepage-evidence-readiness-latest', 'homepage-evidence-readiness-summary.json')), intakeReadiness: rel(path.join(outputRoot, 'intake-readiness-latest', 'intake-readiness-summary.json')), videoResourceReadiness: rel(path.join(outputRoot, 'video-resource-readiness-latest', 'video-resource-readiness-summary.json')), livePreflight: rel(path.join(outputRoot, 'live-preflight-latest', 'live-preflight-summary.json')), longRunReadiness: rel(path.join(outputRoot, 'long-run-readiness-latest', 'long-run-readiness-summary.json')), intakeFieldChecklist: rel(path.join(outputRoot, 'intake-field-checklist-latest', 'intake-field-checklist-summary.json')), manualReviewLabelGuide: rel(path.join(outputRoot, 'manual-review-label-guide-latest', 'manual-review-label-guide-summary.json')), businessProofProgress: rel(path.join(outputRoot, 'business-proof-progress-latest', 'business-proof-progress-summary.json')), businessProofNextActions: rel(path.join(outputRoot, 'business-proof-next-actions-latest', 'business-proof-next-actions-summary.json')), businessExecutionIndex: rel(path.join(outputRoot, 'business-execution-index-latest', 'business-execution-index-summary.json')), optimizationStatus: rel(path.join(outputRoot, 'optimization-status-latest', 'optimization-status-summary.json')), evidenceIndex: rel(path.join(outputRoot, 'evidence-index-latest', 'evidence-index-summary.json')), handoffSummary: rel(path.join(outputRoot, 'optimization-handoff-latest', 'optimization-handoff-summary.json')), planExecutionStatus: rel(path.join(outputRoot, 'plan-execution-status-latest', 'plan-execution-status-summary.json')), proofGapOperatorPack: rel(path.join(outputRoot, 'proof-gap-operator-pack-latest', 'proof-gap-operator-pack-summary.json')), realProofIntakeBundle: rel(path.join(outputRoot, 'real-proof-intake-bundle-latest', 'real-proof-intake-bundle-summary.json')), softwareClientList: rel(path.join(outputRoot, 'software-client-latest', 'software-client-refresh-summary.json')), latestFormIndex: rel(path.join(outputRoot, 'latest-form-index-latest', 'latest-form-index-summary.json')), optimizationCompletion: rel(path.join(outputRoot, 'optimization-completion-latest', 'optimization-completion-summary.json')), localSeedMaterialIndex: rel(path.join(outputRoot, 'local-seed-material-index-latest', 'local-seed-material-index-summary.json')), localSeedToIntakeWorklist: rel(path.join(outputRoot, 'local-seed-to-intake-worklist-latest', 'local-seed-to-intake-worklist-summary.json')), realGapMaterialAudit: rel(path.join(outputRoot, 'real-gap-material-audit-latest', 'real-gap-material-audit-summary.json')), realProofClosureWorkOrder: rel(path.join(outputRoot, 'real-proof-closure-work-order-latest', 'real-proof-closure-work-order-summary.json')), experienceTranscriptIndex: rel(path.join(outputRoot, 'experience-transcript-index-latest', 'experience-transcript-index-summary.json')), roundDeposition: rel(path.join(outputRoot, 'round-deposition-latest', 'round-deposition-summary.json')) } }; const summaryPath = path.join(outputRoot, 'round-refresh-summary.json'); fs.writeFileSync(summaryPath, JSON.stringify(summary, null, 2), 'utf8'); console.log(JSON.stringify({ outputRoot, summary: summaryPath, passed: summary.passed, steps: summary.steps.map(item => `${item.id}:${item.status}`) }, null, 2)); if (!summary.passed && strict) process.exitCode = 1; } function runStep(step, strict) { const [command, args] = step.command; const resolvedCommand = command === 'node' ? process.execPath : command; const startedAt = new Date().toISOString(); const result = spawnSync(resolvedCommand, args, { cwd: ROOT, encoding: 'utf8', shell: false }); const status = result.status === 0 ? 'pass' : 'fail'; if (result.stdout) process.stdout.write(result.stdout); if (result.stderr) process.stderr.write(result.stderr); if (status === 'fail' && strict) { return { id: step.id, status, startedAt, finishedAt: new Date().toISOString(), exitCode: result.status, error: `${command} ${args.join(' ')} failed` }; } return { id: step.id, status, startedAt, finishedAt: new Date().toISOString(), exitCode: result.status }; } function parseArgs(argv) { const result = {}; for (let index = 0; index < argv.length; index += 1) { const arg = argv[index]; if (!arg.startsWith('--')) continue; const key = arg.slice(2).replace(/-([a-z])/g, (_, char) => char.toUpperCase()); const next = argv[index + 1]; if (!next || next.startsWith('--')) result[key] = true; else { result[key] = next; index += 1; } } return result; } function rel(file) { return path.relative(ROOT, file).replace(/\\/g, '/'); } if (require.main === module) main();