fix(cli): restore packaged console startup

This commit is contained in:
Catriel Müller
2026-06-03 12:35:42 -03:00
parent 5e7e158503
commit 1cdc39856f
5 changed files with 94 additions and 5 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@kilocode/cli": patch
---
Restore `kilo console` startup in packaged CLI builds.
+13 -1
View File
@@ -126,7 +126,7 @@ function findBinary() {
}
// kilocode_change end
// kilocode_change start - copy tree-sitter WASM resources next to cached binary
// kilocode_change start - copy runtime resources next to cached binary
function copyTreeSitterResources(binaryPath) {
const source = path.join(path.dirname(binaryPath), "tree-sitter")
const target = path.join(__dirname, "bin", "tree-sitter")
@@ -137,6 +137,17 @@ function copyTreeSitterResources(binaryPath) {
fs.rmSync(target, { recursive: true, force: true })
fs.cpSync(source, target, { recursive: true })
}
function copyConsoleResources(binaryPath) {
const source = path.join(path.dirname(binaryPath), "console")
const target = path.join(__dirname, "bin", "console")
const index = path.join(source, "index.html")
if (!fs.existsSync(index)) return
fs.rmSync(target, { recursive: true, force: true })
fs.cpSync(source, target, { recursive: true })
}
// kilocode_change end
function main() {
@@ -155,6 +166,7 @@ function main() {
fs.copyFileSync(binaryPath, target)
}
copyTreeSitterResources(binaryPath) // kilocode_change
copyConsoleResources(binaryPath) // kilocode_change
fs.chmodSync(target, 0o755)
}
@@ -213,11 +213,15 @@ export namespace Daemon {
return await start(input)
}
export function command(input?: string[]) {
export function command(
input?: string[],
proc = { argv: process.argv, execArgv: process.execArgv, execPath: process.execPath },
) {
if (input?.length) return input
const script = process.argv[1]
if (script && /\.(ts|js|mjs|cjs)$/.test(script)) return [process.execPath, ...clean(process.execArgv), script]
return [process.execPath]
const script = proc.argv[1]
const bundled = script?.startsWith("/$bunfs/") || (script ? /^[A-Za-z]:[\\/]~BUN[\\/]/.test(script) : false)
if (script && !bundled && /\.(ts|js|mjs|cjs)$/.test(script)) return [proc.execPath, ...clean(proc.execArgv), script]
return [proc.execPath]
}
export function clean(input: string[]) {
@@ -7,6 +7,7 @@ import path from "path"
const root = path.join(import.meta.dir, "..", "..")
const wrapper = path.join(root, "bin", "kilo")
const postinstall = path.join(root, "script", "postinstall.mjs")
describe("npm install artifact behavior", () => {
test("keeps the CLI wrapper contract", async () => {
@@ -17,6 +18,40 @@ describe("npm install artifact behavior", () => {
expect(text).toContain("function findBinary(startDir)")
})
test("copies cached binary runtime resources during postinstall", async () => {
if (process.platform === "win32") return
const node = Bun.which("node")
if (!node) {
console.warn("Skipping postinstall artifact test: node is not available in PATH")
return
}
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "kilo-postinstall-artifact-"))
try {
const pkg = path.join(tmp, "node_modules", "@kilocode", "cli")
const native = path.join(tmp, "node_modules", "@kilocode", `cli-${process.platform}-${process.arch}`)
const bin = path.join(native, "bin")
await fs.mkdir(path.join(pkg, "bin"), { recursive: true })
await fs.mkdir(path.join(bin, "tree-sitter"), { recursive: true })
await fs.mkdir(path.join(bin, "console", "assets"), { recursive: true })
await fs.copyFile(postinstall, path.join(pkg, "postinstall.mjs"))
await Bun.write(path.join(native, "package.json"), JSON.stringify({ name: `@kilocode/cli-${process.platform}-${process.arch}` }))
await Bun.write(path.join(bin, "kilo"), "binary")
await Bun.write(path.join(bin, "tree-sitter", "tree-sitter.wasm"), "wasm")
await Bun.write(path.join(bin, "console", "index.html"), "console")
await Bun.write(path.join(bin, "console", "assets", "app.js"), "asset")
const proc = Bun.spawn([node, path.join(pkg, "postinstall.mjs")], { cwd: pkg })
expect(await proc.exited).toBe(0)
expect(await Bun.file(path.join(pkg, "bin", ".kilo")).text()).toBe("binary")
expect(await Bun.file(path.join(pkg, "bin", "tree-sitter", "tree-sitter.wasm")).text()).toBe("wasm")
expect(await Bun.file(path.join(pkg, "bin", "console", "index.html")).text()).toBe("console")
expect(await Bun.file(path.join(pkg, "bin", "console", "assets", "app.js")).text()).toBe("asset")
} finally {
await fs.rm(tmp, { recursive: true, force: true })
}
})
test("links npm bin commands to the wrapper during local install", async () => {
const npmPath = Bun.which("npm")
if (!npmPath) {
@@ -68,6 +68,39 @@ describe("daemon manager", () => {
expect(Daemon.clean(["--cwd=packages/opencode", "--conditions=browser"])).toStrictEqual(["--conditions=browser"])
})
test("does not forward bundled bun entrypoints to the daemon child", () => {
const proc = {
argv: ["/tmp/kilo", "/$bunfs/root/src/index.js", "daemon", "start"],
execArgv: ["--user-agent=kilo/test", "--use-system-ca", "--"],
execPath: "/tmp/kilo",
}
expect(Daemon.command(undefined, proc)).toStrictEqual(["/tmp/kilo"])
expect(
Daemon.command(undefined, {
...proc,
argv: ["C:/tmp/kilo.exe", "B:/~BUN/root/src/index.js", "daemon", "start"],
execPath: "C:/tmp/kilo.exe",
}),
).toStrictEqual(["C:/tmp/kilo.exe"])
expect(
Daemon.command(undefined, {
...proc,
argv: ["C:/tmp/kilo.exe", "b:\\~BUN\\root\\src\\index.js", "daemon", "start"],
execPath: "C:/tmp/kilo.exe",
}),
).toStrictEqual(["C:/tmp/kilo.exe"])
})
test("forwards source entrypoints to the daemon child", () => {
expect(
Daemon.command(undefined, {
argv: ["/tmp/bun", "/tmp/kilo/src/index.ts", "daemon", "start"],
execArgv: ["--conditions=browser"],
execPath: "/tmp/bun",
}),
).toStrictEqual(["/tmp/bun", "--conditions=browser", "/tmp/kilo/src/index.ts"])
})
test("reuses one daemon across caller directories", async () => {
await using tmp = await tmpdir()
const env = opts(tmp.path)