#!/usr/bin/env node const { spawnSync } = require('child_process'); const args = new Set(process.argv.slice(2)); if (args.has('--help') || args.has('-h')) { console.log('Project Hub MVP readiness check'); console.log(''); console.log('Usage:'); console.log(' node scripts/mvp-check.cjs [--restart-backend]'); console.log(''); console.log('Environment:'); console.log(' API_BASE default: http://localhost:4000/api'); console.log(' WRITE_API_KEY optional x-api-key for write endpoints'); process.exit(0); } const backendPort = process.env.PORT_BACKEND || '4000'; const API_BASE = process.env.API_BASE || `http://localhost:${backendPort}/api`; const HEALTH_URL = API_BASE.replace(/\/api\/?$/, '') + '/health'; const RESTART_BACKEND = args.has('--restart-backend'); function log(msg) { console.log(`[mvp-check] ${msg}`); } function formatCheck(status, name, detail = '') { const suffix = detail ? `: ${detail}` : ''; console.log(`[mvp-check] ${status} ${name}${suffix}`); } async function checkHealth() { try { const response = await fetch(HEALTH_URL, { signal: AbortSignal.timeout(5000) }); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } return { ok: true }; } catch (err) { return { ok: false, detail: err.message }; } } function runNodeScript(scriptPath, scriptArgs = []) { const result = spawnSync(process.execPath, [scriptPath, ...scriptArgs], { env: process.env, encoding: 'utf8', maxBuffer: 10 * 1024 * 1024, }); const output = [result.stdout || '', result.stderr || ''].join('').trim(); const lines = output ? output.split(/\r?\n/).filter(Boolean) : []; const tail = lines.slice(-6).join(' | '); if (result.error) { return { ok: false, detail: result.error.message }; } if (result.status !== 0) { return { ok: false, detail: tail || `exit ${result.status}` }; } return { ok: true, detail: tail }; } async function run() { log('Starting MVP hardening checks...'); log(`API base: ${API_BASE}`); const results = []; const health = await checkHealth(); results.push({ name: 'backend-health', ...health }); formatCheck(health.ok ? 'PASS' : 'FAIL', 'backend-health', health.detail || HEALTH_URL); const wiring = runNodeScript('scripts/wiring-smoke-test.cjs'); results.push({ name: 'wiring-smoke', ...wiring }); formatCheck(wiring.ok ? 'PASS' : 'FAIL', 'wiring-smoke', wiring.detail); const persistenceArgs = RESTART_BACKEND ? ['--restart-backend'] : []; const persistence = runNodeScript('scripts/persistence-self-test.cjs', persistenceArgs); results.push({ name: RESTART_BACKEND ? 'persistence-restart' : 'persistence', ...persistence }); formatCheck(persistence.ok ? 'PASS' : 'FAIL', RESTART_BACKEND ? 'persistence-restart' : 'persistence', persistence.detail); const failed = results.filter(r => !r.ok); if (failed.length > 0) { log('NOT READY'); log(`Failed checks: ${failed.map(f => f.name).join(', ')}`); process.exit(1); } log('READY'); log('All automated MVP hardening checks passed.'); } run().catch(err => { log(`NOT READY: ${err.message}`); process.exit(1); });