UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

255 lines (253 loc) • 11.4 kB
import { MISSING_CONFIG_MESSAGE, findConfigPath } from "../../services/resolution/load.mjs"; import { colors, frames, gradients, icons } from "../../utils/theme.mjs"; import { compareSemver } from "../../services/status.mjs"; import { exitCodeFor } from "../exit-codes.mjs"; import { printConfigView } from "../render/config.mjs"; import { formatTimeAgo } from "../render/logs.mjs"; import { renderPs } from "../render/processes.mjs"; import { existsSync, watch } from "node:fs"; import { dirname, resolve } from "node:path"; import { readFile } from "node:fs/promises"; //#region src/cli/commands/inspect.ts const inspectRenderers = { config: async (result, _ctx) => { if (!result.config) { console.error(MISSING_CONFIG_MESSAGE); process.exit(1); } printConfigView(result.config); process.stdout.write(`${JSON.stringify(result.config, null, 2)}\n`); }, status: async (result, _ctx) => { console.log(); if (exitCodeFor(result) === 1) { console.error(`[CLI] ${result.error || "Unknown error"}`); process.exit(1); } console.log(colors.cyan(frames.top(52))); console.log(` ${icons.app} ${gradients.cyber("STATUS")}`); console.log(colors.cyan(frames.bottom(52))); console.log(); if (result.extends) console.log(` ${colors.dim("Extends:")} ${result.extends}`); if (result.account) console.log(` ${colors.dim("Account:")} ${result.account}`); if (result.domain) console.log(` ${colors.dim("Domain:")} ${result.domain}`); console.log(); console.log(` ${colors.dim("Packages:")}`); for (const pkg of result.packages) { const hasUpdate = pkg.installed && pkg.latest && compareSemver(pkg.installed, pkg.latest) < 0; const versionStr = hasUpdate ? `${pkg.installed} → ${pkg.latest}` : pkg.installed || "not installed"; const label = hasUpdate ? colors.yellow(versionStr) : colors.dim(versionStr); console.log(` ${colors.dim(`${pkg.name}`)} ${label}`); } console.log(); if (result.lastSync) { const ago = formatTimeAgo(result.lastSync); console.log(` ${colors.dim("Last sync:")} ${ago}`); } else console.log(` ${colors.dim("Last sync:")} never`); const envLabel = result.envFile === "found" ? colors.green("found") : result.envFile === "example-only" ? colors.yellow("missing (only .env.example found)") : colors.error("missing"); console.log(` ${colors.dim(".env:")} ${envLabel}`); if (result.parentReachable !== void 0) { const parentLabel = result.parentReachable ? colors.green("reachable") : colors.error("unreachable"); console.log(` ${colors.dim("Parent:")} ${parentLabel}`); } if (result.packages.some((p) => p.installed && p.latest && compareSemver(p.installed, p.latest) < 0)) { console.log(); console.log(colors.dim(` Run ${colors.cyan("bos upgrade")} to update packages and sync template files.`)); } console.log(); }, ps: async (result, _ctx) => { renderPs(result); }, logs: async (result, ctx) => { const input = ctx.input; const logsResult = result; const opts = input; for (const line of logsResult.lines) console.log(line); if (logsResult.lines.length === 0) console.log(colors.dim(` No matching log lines in ${logsResult.logFile}.`)); if (opts.follow) { if (logsResult.logFile === "unknown" || !existsSync(logsResult.logFile)) console.log(colors.dim(" No log file to follow — nothing was found on disk.")); else { const filter = opts.service; let byteOffset = 0; for (const line of logsResult.lines) byteOffset += Buffer.byteLength(line, "utf8") + 1; const followMatch = (line) => { if (!filter) return true; const source = /\] \[([^\]]+)\] \[(?:OUT|ERR)\] /.exec(line)?.[1]; return source === filter || source === `plugin:${filter}`; }; const watcher = watch(logsResult.logFile, (event) => { if (event !== "change") return; readFile(logsResult.logFile, "utf8").then((text) => { const newLines = text.slice(byteOffset).split("\n").filter((line) => line.length > 0 && followMatch(line)); byteOffset = Buffer.byteLength(text, "utf8"); for (const line of newLines) console.log(line); }).catch(() => { watcher.close(); }); }); console.log(colors.dim(" Following — Ctrl+C to stop.")); process.on("SIGINT", () => { watcher.close(); process.exit(0); }); } } }, kill: async (result, ctx) => { const input = ctx.input; const killResult = result; console.log(); if (killResult.status === "error") { console.error(`[CLI] ${killResult.error || "Unknown error"}`); process.exit(1); } if (killResult.killed.length > 0) { console.log(colors.green(`${icons.ok} Sent ${killResult.killed.length} kill signal(s)`)); for (const k of killResult.killed) console.log(` ${colors.dim("pid")} ${k.pid} ${colors.dim(k.configDir)}`); } if (killResult.skipped.length > 0) { console.log(colors.yellow(`${icons.err} ${killResult.skipped.length} skipped`)); for (const s of killResult.skipped) console.log(` ${colors.dim("pid")} ${s.pid} ${colors.dim(s.reason)}`); } if (killResult.killed.length === 0 && killResult.skipped.length === 0) { const opts = input; if (opts.all) console.log(colors.dim(" No tracked processes to kill.")); else { const configPath = findConfigPath(); const dir = opts.configDir ?? (configPath ? resolve(dirname(configPath)) : process.cwd()); console.log(colors.dim(` No tracked processes for ${dir}`)); console.log(colors.dim(` Use ${colors.cyan("--all")} to kill across all directories.`)); } } console.log(); }, typesGen: async (result, _ctx) => { console.log(); if (exitCodeFor(result) === 1) { console.error(`[CLI] ${result.error || "Unknown error"}`); process.exit(1); } console.log(colors.green(`${icons.ok} Types generated`)); if (result.generated.length > 0) { console.log(` ${colors.dim("Written:")}`); for (const f of result.generated) console.log(` ${colors.dim(f)}`); } if (result.fetched.length > 0 || result.skipped.length > 0 || result.failed.length > 0) { console.log(` ${colors.dim("Contract sources:")}`); for (const entry of result.fetched) { const space = entry.indexOf(" "); const key = space !== -1 ? entry.slice(0, space) : entry; const rest = space !== -1 ? entry.slice(space + 1) : ""; const restSpace = rest.indexOf(" "); const detail = restSpace !== -1 ? rest.slice(restSpace + 1) : ""; console.log(` ${key} ${colors.cyan("remote")}${detail ? ` ${colors.dim(detail)}` : ""}`); } for (const entry of result.skipped) { const space = entry.indexOf(" "); const key = space !== -1 ? entry.slice(0, space) : entry; const rest = space !== -1 ? entry.slice(space + 1) : ""; if (rest === "no URL resolved") { console.log(` ${key} ${colors.dim("no URL resolved")}`); continue; } const restSpace = rest.indexOf(" "); const detail = restSpace !== -1 ? rest.slice(restSpace + 1) : ""; console.log(` ${key} ${colors.dim("local")}${detail ? ` ${colors.dim(detail)}` : ""}`); } } if (result.failed.length > 0) { console.log(` ${colors.yellow("Failed:")}`); for (const f of result.failed) { const colon = f.indexOf(": "); if (colon !== -1) console.log(` ${colors.error(f.slice(0, colon))}${colors.dim(f.slice(colon))}`); else console.log(` ${colors.error(f)}`); } } console.log(); }, typecheck: async (result, _ctx) => { console.log(); if (exitCodeFor(result) === 1) { console.error(`[CLI] ${result.error || "Unknown error"}`); process.exit(1); } const failed = result.results.filter((r) => !r.passed); const passed = result.results.filter((r) => r.passed); console.log(colors.cyan(frames.top(52))); console.log(` ${icons.app} ${gradients.cyber("TYPECHECK")}`); console.log(colors.cyan(frames.bottom(52))); console.log(); for (const r of result.results) { const icon = r.passed ? colors.green("✓") : colors.error("✗"); console.log(` ${icon} ${r.workspace}`); } if (result.skipped.length > 0) console.log(` ${colors.dim(`Skipped: ${result.skipped.join(", ")}`)}`); console.log(); if (failed.length > 0) { console.log(` ${colors.error(`${failed.length} failed`)}`); for (const f of failed) if (f.error) console.log(` ${colors.dim(f.error)}`); console.log(); process.exit(1); } console.log(` ${colors.green(`${passed.length} passed`)}`); console.log(); }, mfCheck: async (result, _ctx) => { console.log(); console.log(` ${colors.dim("Host")} ${result.hostReachable ? colors.green("OK ") : colors.error("FAIL")} ${result.hostVersion ?? "unreachable"}${result.hostReason ? ` (${result.hostReason})` : ""}`); for (const r of result.remotes) { const tag = r.ok ? colors.green("OK ") : colors.error("FAIL"); console.log(` ${colors.dim(r.role.padEnd(10))} ${tag} ${r.url} pluginVersion=${r.pluginVersion ?? "?"}${r.reason ? ` ↳ ${r.reason}` : ""}`); } if (result.ui) for (const slot of result.ui.slots) { const tag = slot.ok ? colors.green("OK ") : colors.error("FAIL"); console.log(` ${colors.dim(`ui:${slot.slot}`.padEnd(10))} ${tag} ${slot.url}${slot.reason ? ` ↳ ${slot.reason}` : ""}`); } if (result.platform) { for (const v of result.platform.violations) console.log(` ${colors.dim("platform".padEnd(10))} ${colors.error("FAIL")} ${v.message}`); if (result.platform.ok) console.log(` ${colors.dim("platform".padEnd(10))} ${colors.green("OK ")} release contract satisfied`); } console.log(); if (result.status !== "ok") { console.log(colors.error(" mf-compat: ✗ federation manifests NOT compatible — redeploy affected plugin(s) so pluginVersion and shared versions match host")); console.log(); process.exit(1); } console.log(colors.green(" mf-compat: ✓ all federation manifests compatible")); console.log(); }, platformManifest: async (result, _ctx) => { console.log(); if (result.status === "fail") { console.error(`[CLI] ${result.error || "platform manifest resolution failed"}`); if (result.drift) { console.log(); console.log(colors.error(` parent platform is ${result.drift.published} (published), you pinned ${result.drift.pinned} — run \`bos upgrade\` to realign`)); } console.log(); process.exit(1); } if (result.status === "absent") { console.log(colors.yellow(` ${icons.err} No platform release manifest resolves${result.error ? ` — ${result.error}` : ""}.`)); console.log(colors.dim(" Children fall back to the parent-repo tarball walk (ADR 0034 pt 7).")); console.log(); return; } console.log(` ${colors.dim("Platform")} ${colors.green(result.version ?? "?")} ${colors.dim(`(${result.source}${result.fromCache ? ", cached" : ""})`)}`); if (result.compat) { for (const v of result.compat.violations) console.log(` ${colors.error("FAIL")} ${v.message}`); console.log(); if (!result.compat.ok) { console.log(colors.error(" platform-compat: ✗ the workspace does not satisfy this release's compat contract — bump the framework or clear the pin")); console.log(); process.exit(1); } console.log(colors.green(" platform-compat: ✓ workspace satisfies the release contract")); } console.log(); } }; //#endregion export { inspectRenderers }; //# sourceMappingURL=inspect.mjs.map