#!/usr/bin/env node /** * cli:test-report * Responsabilité : Run tests and produce structured report * Appelé par Claude Code via skill:development-testing * * Usage : * npx --prefer-offline tsx skills/development/testing/cli/test-report/index.ts \ * --spec '{"projectPath":"/path","module":"hrm"}' */ import { parseArgs } from 'node:util' import { validate } from './validate.js' import { execute } from './execute.js' import { executeEnvelope, failExecute, printEnvelope } from '../../../../lib/output.js' const COMMAND = 'test-report' function main(): void { const { values } = parseArgs({ options: { spec: { type: 'string' }, }, strict: true, }) if (!values.spec) { printEnvelope(failExecute(COMMAND, ['--spec is required'])) process.exit(1) } let raw: unknown try { raw = JSON.parse(values.spec) } catch { printEnvelope(failExecute(COMMAND, ['Invalid JSON in --spec'])) process.exit(1) } const validation = validate(raw) if (!validation.valid) { printEnvelope(failExecute(COMMAND, validation.errors)) process.exit(1) } try { const { report, reportPath } = execute(raw as any) // Studio UI event channel — separate from the envelope, parsed by the // Studio renderer to update the live test panel without waiting for the // CLI to exit. console.log(JSON.stringify({ __studio_event__: 'test_report', module: report.module, summary: report.summary, byLayer: report.byLayer, failures: report.failures, })) const failed = report.summary.failed printEnvelope({ ...(failed === 0 ? executeEnvelope(COMMAND, { data: { module: report.module, total: report.summary.total, passed: report.summary.passed, failed, skipped: report.summary.skipped, reportPath, }, report, nextSteps: ['All tests passing. Proceed to next phase.'], }) : { ...failExecute(COMMAND, [`${failed} test(s) failed`]), data: { module: report.module, total: report.summary.total, passed: report.summary.passed, failed, skipped: report.summary.skipped, reportPath, }, report, nextSteps: ['Fix failing tests and re-run'], }), }) process.exit(failed > 0 ? 1 : 0) } catch (err) { printEnvelope(failExecute(COMMAND, [`Internal error: ${err instanceof Error ? err.message : String(err)}`])) process.exit(2) } } main()