#!/usr/bin/env node /** * CI: ctx.pear static host imports must cover all pearEntries packages. * Safe-on-Bare imports: bare-os-ctx-pear-host.js * Pear-runtime-only (dynamic when globalThis.Pear): bare-os-ctx-pear-host-pear-only.js */ import fs from 'node:fs' import path from 'node:path' import process from 'node:process' import { fileURLToPath } from 'node:url' const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') const libDir = path.join(root, 'packages/bare-os-booter/lib/ctx') const manifestPath = path.join(libDir, 'bare-module-manifest.json') /** @param {string} filePath */ function packagesFromFile(filePath) { const src = fs.readFileSync(filePath, 'utf8') /** @type {string[]} */ const found = [] const staticRe = /^\s*import\s+\w+\s+from\s+['"]([^'"]+)['"]/gm const dynamicRe = /^\s*import\s*\(\s*['"]([^'"]+)['"]\s*\)/gm let m while ((m = staticRe.exec(src))) found.push(m[1]) while ((m = dynamicRe.exec(src))) found.push(m[1]) return found } function main() { const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) const pearEntries = manifest.pearEntries if (!Array.isArray(pearEntries) || pearEntries.length === 0) { console.log('[verify-pear-ctx-host-imports] no pearEntries (skip)') return } const expected = pearEntries.map((e) => e.package).sort() const actual = [ ...packagesFromFile(path.join(libDir, 'bare-os-ctx-pear-host.js')), ...packagesFromFile(path.join(libDir, 'bare-os-ctx-pear-host-pear-only.js')) ].sort() const missing = expected.filter((p) => !actual.includes(p)) const extra = actual.filter((p) => !expected.includes(p)) if (missing.length || extra.length) { console.error('[verify-pear-ctx-host-imports] mismatch') if (missing.length) console.error(' missing in host:', missing.join(', ')) if (extra.length) console.error(' extra in host:', extra.join(', ')) process.exit(1) } console.log( `[verify-pear-ctx-host-imports] ok — ${expected.length} packages aligned` ) } main()