Files
Project-Manager/scripts/mvp-check.cjs
2026-03-18 13:05:14 -04:00

98 lines
3.1 KiB
JavaScript

#!/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);
});