mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-10-30 19:32:39 +08:00
Merge pull request #13472 from Kilo-Org/fix-kilo-startup-black-screen
fix(cli): restore terminal startup
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@kilocode/cli": patch
|
||||
---
|
||||
|
||||
Prevent the CLI from opening to a blank terminal on startup.
|
||||
@@ -4,6 +4,56 @@ import { spawn } from "#pty"
|
||||
|
||||
const TIMEOUT = 15_000
|
||||
|
||||
async function render() {
|
||||
const proc = spawn(process.execPath, ["--pure"], {
|
||||
name: "xterm-256color",
|
||||
cwd: process.cwd(),
|
||||
env: {
|
||||
...process.env,
|
||||
TERM: "xterm-256color",
|
||||
KILO_TERMINAL: "1",
|
||||
KILO_NO_DAEMON: "1",
|
||||
KILO_DISABLE_AUTOUPDATE: "1",
|
||||
KILO_DISABLE_MODELS_FETCH: "1",
|
||||
KILO_DISABLE_PROJECT_CONFIG: "1",
|
||||
KILO_DISABLE_DEFAULT_PLUGINS: "1",
|
||||
KILO_DISABLE_TERMINAL_TITLE: "0",
|
||||
KILO_CONFIG_CONTENT: "{}",
|
||||
KILO_AUTH_CONTENT: "{}",
|
||||
} as Record<string, string>,
|
||||
cols: 100,
|
||||
rows: 40,
|
||||
})
|
||||
const state = { output: "", exited: false }
|
||||
const ready = Promise.withResolvers<void>()
|
||||
const data = proc.onData((chunk) => {
|
||||
state.output = (state.output + chunk).slice(-20_000)
|
||||
if (state.output.includes("Ask anything...")) ready.resolve()
|
||||
})
|
||||
const exit = proc.onExit((event) => {
|
||||
state.exited = true
|
||||
ready.reject(new Error(`TUI exited before rendering (code ${event.exitCode}): ${JSON.stringify(state.output)}`))
|
||||
})
|
||||
const timeout = AbortSignal.timeout(TIMEOUT)
|
||||
|
||||
try {
|
||||
await Promise.race([
|
||||
ready.promise,
|
||||
new Promise<never>((_, reject) =>
|
||||
timeout.addEventListener(
|
||||
"abort",
|
||||
() => reject(new Error(`TUI produced no rendered frame within ${TIMEOUT}ms: ${JSON.stringify(state.output)}`)),
|
||||
{ once: true },
|
||||
),
|
||||
),
|
||||
])
|
||||
} finally {
|
||||
data.dispose()
|
||||
exit.dispose()
|
||||
if (!state.exited) await KiloPtyTermination.terminate(proc)
|
||||
}
|
||||
}
|
||||
|
||||
export async function smoke() {
|
||||
const proc = spawn(Shell.preferred(), [], {
|
||||
name: "xterm-256color",
|
||||
@@ -17,8 +67,7 @@ export async function smoke() {
|
||||
const exited = Promise.withResolvers<number>()
|
||||
const data = proc.onData((chunk) => {
|
||||
state.output += chunk
|
||||
const lines = state.output.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "").split(/\r?\n/)
|
||||
if (lines.some((line) => line.trim() === "KILO_PTY_READY")) output.resolve()
|
||||
if (/(?:^|[\r\n])KILO_PTY_READY(?:\r?\n|$)/.test(state.output)) output.resolve()
|
||||
})
|
||||
const exit = proc.onExit((event) => {
|
||||
state.exited = true
|
||||
@@ -67,6 +116,8 @@ export async function smoke() {
|
||||
} finally {
|
||||
if (!stopped) active.kill()
|
||||
}
|
||||
|
||||
await render()
|
||||
}
|
||||
|
||||
export * as PtySmoke from "./smoke"
|
||||
|
||||
@@ -24,6 +24,7 @@ import { stageBubblewrap } from "./kilocode/bubblewrap"
|
||||
import { LanceDBRuntime } from "../src/kilocode/lancedb"
|
||||
import { KiloSandboxWorker } from "./kilocode/kilo-sandbox-worker"
|
||||
import { KiloSandboxNetwork } from "./kilocode/kilo-sandbox-network"
|
||||
import { KiloCliSmoke } from "./kilocode/cli-smoke"
|
||||
// kilocode_change end
|
||||
|
||||
const singleFlag = process.argv.includes("--single")
|
||||
@@ -312,8 +313,9 @@ for (const item of targets) {
|
||||
// kilocode_change end
|
||||
format: "esm",
|
||||
minify: true,
|
||||
// Bun 1.4 fixes the cross-chunk re-export codegen bug from Bun 1.3.14.
|
||||
splitting: true, // kilocode_change
|
||||
// kilocode_change start - keep the compiled OpenTUI/Solid graph in one chunk to avoid blank startup frames.
|
||||
splitting: false,
|
||||
// kilocode_change end
|
||||
compile: {
|
||||
autoloadBunfig: false,
|
||||
autoloadDotenv: false,
|
||||
@@ -394,6 +396,9 @@ for (const item of targets) {
|
||||
console.log("Models snapshot smoke test passed")
|
||||
await KiloSandboxWorker.smoke(binaryPath)
|
||||
console.log("Kilo sandbox mutation worker smoke test passed")
|
||||
console.log(`Running smoke test: ${binaryPath} --pure __pty-smoke`)
|
||||
await KiloCliSmoke.pty(binaryPath)
|
||||
console.log("Packaged TUI smoke test passed")
|
||||
// kilocode_change end
|
||||
// kilocode_change start
|
||||
} catch (e) {
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import fs from "fs"
|
||||
import os from "os"
|
||||
import path from "path"
|
||||
|
||||
export namespace KiloCliSmoke {
|
||||
export async function pty(binary: string) {
|
||||
const root = await fs.promises.mkdtemp(path.join(os.tmpdir(), "kilo-pty-"))
|
||||
const env = { ...process.env }
|
||||
delete env.KILO_MODELS_PATH
|
||||
delete env.KILO_MODELS_URL
|
||||
delete env.KILO_CONFIG
|
||||
delete env.KILO_CONFIG_DIR
|
||||
|
||||
try {
|
||||
const proc = Bun.spawn([binary, "--pure", "__pty-smoke"], {
|
||||
env: {
|
||||
...env,
|
||||
HOME: root,
|
||||
XDG_DATA_HOME: path.join(root, "data"),
|
||||
XDG_CACHE_HOME: path.join(root, "cache"),
|
||||
XDG_CONFIG_HOME: path.join(root, "config"),
|
||||
XDG_STATE_HOME: path.join(root, "state"),
|
||||
KILO_PTY_SMOKE: "1",
|
||||
KILO_NO_DAEMON: "1",
|
||||
KILO_DISABLE_MODELS_FETCH: "1",
|
||||
KILO_DISABLE_PROJECT_CONFIG: "1",
|
||||
KILO_CONFIG_CONTENT: "{}",
|
||||
KILO_AUTH_CONTENT: "{}",
|
||||
},
|
||||
stdout: "inherit",
|
||||
stderr: "inherit",
|
||||
windowsHide: true,
|
||||
})
|
||||
const code = await proc.exited
|
||||
if (code !== 0) throw new Error(`Compiled TUI smoke test exited with code ${code}`)
|
||||
} finally {
|
||||
await fs.promises.rm(root, { recursive: true, force: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user