From f3a4003356642638fc275e6aa64dcfbe9ada562e Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Fri, 24 Jul 2026 15:09:23 +0200 Subject: [PATCH] fix(cli): resolve bundled OpenTUI native modules --- packages/opencode/script/kilocode/test-cli.ts | 11 ++++++ .../opencode/test/kilocode/test-cli.test.ts | 35 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/packages/opencode/script/kilocode/test-cli.ts b/packages/opencode/script/kilocode/test-cli.ts index 1e763fea58a..e7c7126219f 100644 --- a/packages/opencode/script/kilocode/test-cli.ts +++ b/packages/opencode/script/kilocode/test-cli.ts @@ -24,6 +24,17 @@ export namespace TestCli { }) if (!result.success) throw new AggregateError(result.logs, "Failed to build CLI subprocess test bundle") await fs.cp(path.join(root, "migration"), path.join(dir, "migration"), { recursive: true }) + const meta = JSON.parse(await Bun.file(path.join(root, "node_modules/@opentui/core/package.json")).text()) + const scope = path.join(dir, "node_modules/@opentui") + await fs.mkdir(scope, { recursive: true }) + const core = await fs.realpath(path.join(root, "node_modules/@opentui/core")) + for (const name of Object.keys(meta.optionalDependencies ?? {})) { + const basename = name.replace("@opentui/", "") + const target = path.join(core, "..", basename) + if (await Bun.file(path.join(target, "package.json")).exists()) { + await fs.symlink(target, path.join(scope, basename), "dir") + } + } return path.join(out, "cli.js") } } diff --git a/packages/opencode/test/kilocode/test-cli.test.ts b/packages/opencode/test/kilocode/test-cli.test.ts index 882780b364d..df2516d285a 100644 --- a/packages/opencode/test/kilocode/test-cli.test.ts +++ b/packages/opencode/test/kilocode/test-cli.test.ts @@ -1,5 +1,6 @@ import { describe, expect, test } from "bun:test" import fs from "fs/promises" +import os from "os" import path from "path" import { TestCli } from "../../script/kilocode/test-cli" @@ -52,6 +53,40 @@ describe("CLI subprocess test bundle", () => { const results = await Promise.all(runs) expect(results.map(([code]) => code)).toEqual([0, 0, 0, 0]) for (const [, stderr] of results) expect(stderr).toContain("Commands:") + + const outside = await fs.mkdtemp(path.join(os.tmpdir(), "kilo-test-cli-cwd-")) + const serve = Bun.spawn([process.execPath, "run", entry, "serve", "--hostname", "127.0.0.1", "--port", "0"], { + cwd: outside, + env: { + ...process.env, + KILO_DB: ":memory:", + KILO_CONFIG_CONTENT: "{}", + KILO_AUTH_CONTENT: "{}", + KILO_DISABLE_MODELS_FETCH: "1", + KILO_DISABLE_PROJECT_CONFIG: "1", + KILO_PURE: "1", + }, + stdout: "pipe", + stderr: "pipe", + windowsHide: true, + }) + const stderr = new Response(serve.stderr).text() + const output = await (async () => { + const reader = serve.stdout.getReader() + const decoder = new TextDecoder() + let text = "" + while (!text.includes("kilo server listening on")) { + const chunk = await reader.read() + if (chunk.done) break + text += decoder.decode(chunk.value, { stream: true }) + } + reader.releaseLock() + return text + })() + if (serve.exitCode === null) serve.kill() + const [code, err] = await Promise.all([serve.exited, stderr]) + expect(output, `stdout:\n${output}\nstderr:\n${err}`).toContain("kilo server listening on") + expect(code, `stdout:\n${output}\nstderr:\n${err}`).not.toBe(1) } finally { if (!process.env[TestCli.ENV]) await fs.rm(dir, { recursive: true, force: true }) }