|
| 1 | +#!/usr/bin/env bun |
| 2 | +// Packaged-install TUI smoke: prove the TUI entry loads from a PROD npm install |
| 3 | +// living under node_modules — the path OpenCode's plugin cache actually uses. |
| 4 | +// |
| 5 | +// Why this exists: the dev checkout can NEVER catch a TUI packaging break. |
| 6 | +// OpenTUI's Solid transform skips any source under node_modules (sourceFilter |
| 7 | +// negative-lookahead), so a dev checkout (file:// path) gets the host's module |
| 8 | +// remapping while a published install does not — the published install must |
| 9 | +// resolve @opentui/solid and solid-js from its own installed dependencies. |
| 10 | +// v0.31.1 shipped without those runtime deps, passed every dev-path check, and |
| 11 | +// broke the sidebar for every npm install. This smoke packs the real tarball, |
| 12 | +// installs it with --omit=dev under a node_modules path, and imports the TUI |
| 13 | +// entry from there — failing exactly the way OpenCode would. |
| 14 | + |
| 15 | +import { execFileSync } from "node:child_process"; |
| 16 | +import { mkdtempSync, rmSync, writeFileSync, readdirSync } from "node:fs"; |
| 17 | +import { tmpdir } from "node:os"; |
| 18 | +import { join, resolve } from "node:path"; |
| 19 | + |
| 20 | +const pluginRoot = resolve(import.meta.dir, ".."); |
| 21 | +const stage = mkdtempSync(join(tmpdir(), "mc-tui-pack-smoke-")); |
| 22 | + |
| 23 | +function fail(message: string): never { |
| 24 | + console.error(`smoke-tui-pack-install: FAIL — ${message}`); |
| 25 | + process.exit(1); |
| 26 | +} |
| 27 | + |
| 28 | +try { |
| 29 | + // 1. Pack the real publish artifact. |
| 30 | + execFileSync("npm", ["pack", "--pack-destination", stage], { |
| 31 | + cwd: pluginRoot, |
| 32 | + stdio: "pipe", |
| 33 | + }); |
| 34 | + const tarball = readdirSync(stage).find((f) => f.endsWith(".tgz")); |
| 35 | + if (!tarball) fail("npm pack produced no tarball"); |
| 36 | + |
| 37 | + // 2. Install it PROD-ONLY into a scratch package, mirroring OpenCode's |
| 38 | + // plugin cache shape (<root>/node_modules/<pkg>/...). |
| 39 | + writeFileSync(join(stage, "package.json"), JSON.stringify({ name: "smoke-host", private: true })); |
| 40 | + execFileSync("npm", ["install", "--omit=dev", "--no-audit", "--no-fund", join(stage, tarball)], { |
| 41 | + cwd: stage, |
| 42 | + stdio: "pipe", |
| 43 | + }); |
| 44 | + |
| 45 | + // 3. Import the TUI entry from INSIDE node_modules, exactly as the host |
| 46 | + // would. A missing runtime dep (the v0.31.1 failure) throws |
| 47 | + // "Cannot find module '@opentui/solid/jsx-dev-runtime'" here. |
| 48 | + const installed = join(stage, "node_modules", "@cortexkit", "opencode-magic-context"); |
| 49 | + const probe = ` |
| 50 | + const mod = await import(${JSON.stringify(join(installed, "src", "tui", "index.tsx"))}); |
| 51 | + const plugin = mod.default; |
| 52 | + if (!plugin || typeof plugin !== "object") throw new Error("TUI entry has no default export object"); |
| 53 | + console.log("ok packaged TUI entry imports and exports the plugin object"); |
| 54 | + `; |
| 55 | + execFileSync("bun", ["-e", probe], { cwd: stage, stdio: "inherit" }); |
| 56 | + |
| 57 | + console.log("smoke-tui-pack-install: all checks passed"); |
| 58 | +} catch (error) { |
| 59 | + fail(error instanceof Error ? error.message : String(error)); |
| 60 | +} finally { |
| 61 | + rmSync(stage, { recursive: true, force: true }); |
| 62 | +} |
0 commit comments