#!/usr/bin/env node /** * cli:derive-related-tabs-data — entry point. * * DETERMINISTIC replacement of the Phase 3a LLM step « Related-tabs data »: * derives `relatedTabsData[]` (columns ≤5 with the relation FK excluded, * per-locale labels, displayField, createPermission, hasDetail/hasCreateForm) * from the on-disk pagespecs, ready to splice VERBATIM into the * scaffold-component invocation of the entity's DETAIL view. * * Invocation: * npx --prefer-offline tsx skills/ba-develop/cli/derive-related-tabs-data/index.ts \ * --spec '{"moduleRoot":".smartstack/ba//","entity":"Driver"}' * * Envelope: success:false when `errors[]` is non-empty (a target pagespec * exists but nothing derives — heal the pagespec, never ship the empty tab). * `omitted[]` (cross-module PRD not on disk) is fail-open by design: the * generator renders the single createdAt column and validate warns. */ import { parseArgs } from 'node:util' import { validate } from './validate.js' import { deriveRelatedTabsData } from './derive.js' import { executeEnvelope, failExecute, printEnvelope } from '../../../lib/output.js' import type { DeriveRelatedTabsDataReport } from './types.js' const COMMAND = 'derive-related-tabs-data' 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 || !validation.spec) { printEnvelope(failExecute(COMMAND, validation.errors)) process.exit(1) } const report = deriveRelatedTabsData(validation.spec) if (report.errors.length > 0) { printEnvelope(executeEnvelope(COMMAND, { success: false, report, errors: report.errors, warnings: [...report.warnings, ...report.omitted.map(o => `[${o.key}] ${o.reason}`)], })) process.exit(1) } printEnvelope(executeEnvelope(COMMAND, { report, warnings: [...report.warnings, ...report.omitted.map(o => `[${o.key}] ${o.reason}`)], nextSteps: [ `Splice report.relatedTabsData VERBATIM into the scaffold-component --spec of ${report.entity}'s detail view.`, ], })) } main()