diff --git a/bin/oh-my-opencode.js b/bin/oh-my-opencode.js index 1a151a8c1..a064bf19f 100755 --- a/bin/oh-my-opencode.js +++ b/bin/oh-my-opencode.js @@ -10,6 +10,7 @@ import { fileURLToPath } from "node:url"; import { getPlatformPackageCandidates, getBinaryPath, + getPackageBareName, resolvePlatformPackageBaseName, } from "./platform.js"; @@ -108,7 +109,7 @@ function getInvocationName() { } function shouldRunBundledLazyCodexCli(packageName, invocationName) { - return packageName === "lazycodex" && invocationName === "lazycodex"; + return getPackageBareName(packageName) === "lazycodex" && invocationName === "lazycodex"; } function runBundledLazyCodexCli(invocationName) { diff --git a/bin/oh-my-opencode.test.ts b/bin/oh-my-opencode.test.ts index 5350292b9..c3aecf16b 100644 --- a/bin/oh-my-opencode.test.ts +++ b/bin/oh-my-opencode.test.ts @@ -36,9 +36,34 @@ describe("lazycodex bin wrapper", () => { "--no-tui", ]); }); + + test("runs the bundled Bun CLI when published under an npm scope", async () => { + // #given + const fixture = await createLazyCodexFixture({ packageName: "@code-yeongyu/lazycodex" }); + const nodePath = Bun.which("node") ?? "node"; + + // #when + const result = spawnSync(nodePath, [fixture.lazycodexBin, "install", "--no-tui"], { + encoding: "utf8", + env: { + ...process.env, + CAPTURE_DIR: fixture.captureDir, + PATH: `${fixture.fakeBinDir}:${process.env.PATH ?? ""}`, + }, + }); + + // #then + expect(result.status).toBe(23); + expect((await readFile(join(fixture.captureDir, "env"), "utf8")).trim()).toBe("lazycodex"); + expect((await readFile(join(fixture.captureDir, "args"), "utf8")).trim().split("\n")).toEqual([ + await realpath(fixture.bundledCli), + "install", + "--no-tui", + ]); + }); }); -async function createLazyCodexFixture() { +async function createLazyCodexFixture(options: { packageName?: string } = {}) { const root = await mkdtemp(join(tmpdir(), "lazycodex-bin-wrapper-")); testRoots.push(root); @@ -53,7 +78,7 @@ async function createLazyCodexFixture() { await cp(fileURLToPath(new URL("./oh-my-opencode.js", import.meta.url)), join(binDir, "lazycodex")); await cp(fileURLToPath(new URL("./platform.js", import.meta.url)), join(binDir, "platform.js")); - await writeFile(join(root, "package.json"), JSON.stringify({ name: "lazycodex", type: "module" })); + await writeFile(join(root, "package.json"), JSON.stringify({ name: options.packageName ?? "lazycodex", type: "module" })); await writeFile(distCli, "#!/usr/bin/env bun\n"); const fakeBun = join(fakeBinDir, "bun"); diff --git a/bin/platform.d.ts b/bin/platform.d.ts index f9375b7c1..616c2911c 100644 --- a/bin/platform.d.ts +++ b/bin/platform.d.ts @@ -15,4 +15,6 @@ export declare function getPlatformPackageCandidates(options: { export declare function getBinaryPath(pkg: string, platform: string): string; +export declare function getPackageBareName(packageName: string): string; + export declare function resolvePlatformPackageBaseName(wrapperPackageName: string): string; diff --git a/bin/platform.js b/bin/platform.js index 0ed616615..7028313aa 100644 --- a/bin/platform.js +++ b/bin/platform.js @@ -5,6 +5,10 @@ const PLATFORM_PACKAGE_BASE_BY_WRAPPER_NAME = { lazycodex: "oh-my-opencode", }; +export function getPackageBareName(packageName) { + return packageName.split("/").pop() || packageName; +} + /** * Resolve platform package base from a wrapper package name. * Wrapper aliases can intentionally reuse an existing platform package family. @@ -12,7 +16,8 @@ const PLATFORM_PACKAGE_BASE_BY_WRAPPER_NAME = { * @returns {string} */ export function resolvePlatformPackageBaseName(wrapperPackageName) { - return PLATFORM_PACKAGE_BASE_BY_WRAPPER_NAME[wrapperPackageName] ?? wrapperPackageName; + const bareName = getPackageBareName(wrapperPackageName); + return PLATFORM_PACKAGE_BASE_BY_WRAPPER_NAME[bareName] ?? wrapperPackageName; } /** diff --git a/bin/platform.test.ts b/bin/platform.test.ts index 49eba4d5d..203880027 100644 --- a/bin/platform.test.ts +++ b/bin/platform.test.ts @@ -2,11 +2,25 @@ import { describe, expect, test } from "bun:test"; import { getBinaryPath, + getPackageBareName, getPlatformPackage, getPlatformPackageCandidates, resolvePlatformPackageBaseName, } from "./platform.js"; +describe("getPackageBareName", () => { + test("strips npm scope from package name", () => { + // #given + const packageName = "@code-yeongyu/lazycodex"; + + // #when + const bareName = getPackageBareName(packageName); + + // #then + expect(bareName).toBe("lazycodex"); + }); +}); + describe("resolvePlatformPackageBaseName", () => { test("maps lazycodex wrapper to oh-my-opencode platform package family", () => { // #given @@ -19,6 +33,17 @@ describe("resolvePlatformPackageBaseName", () => { expect(resolvedPlatformBase).toBe("oh-my-opencode"); }); + test("maps scoped lazycodex wrapper to oh-my-opencode platform package family", () => { + // #given + const wrapperPackageName = "@code-yeongyu/lazycodex"; + + // #when + const resolvedPlatformBase = resolvePlatformPackageBaseName(wrapperPackageName); + + // #then + expect(resolvedPlatformBase).toBe("oh-my-opencode"); + }); + test("keeps oh-my-opencode wrapper mapped to oh-my-opencode platform package family", () => { // #given const wrapperPackageName = "oh-my-opencode";