From b234d25337142417b07d83a715e7ad4c3391dca4 Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Fri, 7 Aug 2026 16:51:44 +0200 Subject: [PATCH 1/2] fix(vscode): surface exit signals and spawn errors in server startup diagnostics --- .../surface-backend-exit-diagnostics.md | 5 +++ .../src/MarketplacePanelProvider.ts | 12 +++++-- .../cli-backend/connection-service.test.ts | 22 ++++++++++++ .../cli-backend/connection-service.ts | 12 +++---- .../src/services/cli-backend/i18n/ar.ts | 6 ++-- .../src/services/cli-backend/i18n/br.ts | 6 ++-- .../src/services/cli-backend/i18n/bs.ts | 6 ++-- .../src/services/cli-backend/i18n/da.ts | 6 ++-- .../src/services/cli-backend/i18n/de.ts | 3 ++ .../src/services/cli-backend/i18n/en.ts | 2 ++ .../src/services/cli-backend/i18n/es.ts | 6 ++-- .../src/services/cli-backend/i18n/fa.ts | 6 ++-- .../src/services/cli-backend/i18n/fr.ts | 10 +++--- .../src/services/cli-backend/i18n/it.ts | 8 +++-- .../src/services/cli-backend/i18n/ja.ts | 2 ++ .../src/services/cli-backend/i18n/ko.ts | 6 ++-- .../src/services/cli-backend/i18n/nl.ts | 2 ++ .../src/services/cli-backend/i18n/no.ts | 2 ++ .../src/services/cli-backend/i18n/pl.ts | 4 ++- .../src/services/cli-backend/i18n/ru.ts | 2 ++ .../src/services/cli-backend/i18n/th.ts | 6 ++-- .../src/services/cli-backend/i18n/tr.ts | 4 ++- .../src/services/cli-backend/i18n/uk.ts | 4 ++- .../src/services/cli-backend/i18n/zh.ts | 6 ++-- .../src/services/cli-backend/i18n/zht.ts | 6 ++-- .../services/cli-backend/server-manager.ts | 35 ++++++++++++------- .../tests/unit/server-manager-utils.test.ts | 28 +++++++++++++++ 27 files changed, 166 insertions(+), 51 deletions(-) create mode 100644 .changeset/surface-backend-exit-diagnostics.md diff --git a/.changeset/surface-backend-exit-diagnostics.md b/.changeset/surface-backend-exit-diagnostics.md new file mode 100644 index 0000000000..146a00c742 --- /dev/null +++ b/.changeset/surface-backend-exit-diagnostics.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Surface process exit signals and structured spawn failure details in server startup diagnostics diff --git a/packages/kilo-vscode/src/MarketplacePanelProvider.ts b/packages/kilo-vscode/src/MarketplacePanelProvider.ts index 0c704ac580..fc62bf46b9 100644 --- a/packages/kilo-vscode/src/MarketplacePanelProvider.ts +++ b/packages/kilo-vscode/src/MarketplacePanelProvider.ts @@ -6,7 +6,7 @@ import { watchFontSizeConfig } from "./kilo-provider/font-size" import { mapSSEEventToWebviewMessage } from "./kilo-provider-utils" import { resolvePanelProjectDirectory } from "./project-directory" import { seedSessionStatuses } from "./session-status" -import type { KiloConnectionService } from "./services/cli-backend" +import { type KiloConnectionService, ServerStartupError } from "./services/cli-backend" import { MarketplaceService } from "./services/marketplace" import { fetchMarketplaceData, @@ -155,7 +155,15 @@ export class MarketplacePanelProvider implements vscode.Disposable { await this.connection.connect(this.directory()) await this.sync(this.statuses.size === 0) } catch (err) { - this.post({ type: "connectionState", state: "error", error: err instanceof Error ? err.message : String(err) }) + this.post({ + type: "connectionState", + state: "error", + error: err instanceof Error ? err.message : String(err), + ...(err instanceof ServerStartupError && { + userMessage: err.userMessage, + userDetails: err.userDetails, + }), + }) } } diff --git a/packages/kilo-vscode/src/services/cli-backend/connection-service.test.ts b/packages/kilo-vscode/src/services/cli-backend/connection-service.test.ts index 17420f7bc6..262b2d64bf 100644 --- a/packages/kilo-vscode/src/services/cli-backend/connection-service.test.ts +++ b/packages/kilo-vscode/src/services/cli-backend/connection-service.test.ts @@ -282,3 +282,25 @@ describe("KiloConnectionService drainPendingPrompts", () => { expect(cleared).toBe(0) }) }) + +describe("KiloConnectionService server exit handling", () => { + test("reports signal name when process is killed by signal", () => { + const service = new KiloConnectionService({} as any) + let stateErr: Error | undefined + service.onStateChange((state, err) => { + if (state === "error") stateErr = err + }) + ;(service as any).handleServerExit(null, "SIGSEGV") + expect(stateErr?.message).toBe("CLI background process exited with signal SIGSEGV. Retry to reconnect.") + }) + + test("reports exit code when process exits normally with code", () => { + const service = new KiloConnectionService({} as any) + let stateErr: Error | undefined + service.onStateChange((state, err) => { + if (state === "error") stateErr = err + }) + ;(service as any).handleServerExit(1, null) + expect(stateErr?.message).toBe("CLI background process exited with code 1. Retry to reconnect.") + }) +}) diff --git a/packages/kilo-vscode/src/services/cli-backend/connection-service.ts b/packages/kilo-vscode/src/services/cli-backend/connection-service.ts index 7a7e120965..d202eeedba 100644 --- a/packages/kilo-vscode/src/services/cli-backend/connection-service.ts +++ b/packages/kilo-vscode/src/services/cli-backend/connection-service.ts @@ -138,7 +138,7 @@ export class KiloConnectionService { update: async () => undefined, } satisfies Pick) this.sandboxPreference = new SandboxPreference(state) - this.serverManager = new ServerManager(context, (code) => this.handleServerExit(code)) + this.serverManager = new ServerManager(context, (code, signal) => this.handleServerExit(code, signal)) this.active = vscode.window.state.focused this.windowStateDisposable = vscode.window.onDidChangeWindowState((ws) => { this.active = ws.focused @@ -790,13 +790,11 @@ export class KiloConnectionService { this.questionRevision += 1 } - private handleServerExit(code: number | null): void { - console.warn("[Kilo New] ConnectionService: CLI background process exited:", code) + private handleServerExit(code: number | null, signal: NodeJS.Signals | null): void { + const reason = signal ? `signal ${signal}` : `code ${code ?? "unknown"}` + console.warn(`[Kilo New] ConnectionService: CLI background process exited with ${reason}`) this.resetConnection() - this.setState( - "error", - new Error(`CLI background process exited with code ${code ?? "unknown"}. Retry to reconnect.`), - ) + this.setState("error", new Error(`CLI background process exited with ${reason}. Retry to reconnect.`)) } private async doConnect(workspaceDir: string): Promise { diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/ar.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/ar.ts index 1221fb0de3..c938afc5e4 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/ar.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/ar.ts @@ -1,6 +1,8 @@ export const dict = { - "server.processExited": "انتهت عملية CLI بالرمز {{code}} قبل بدء الخادم", - "server.startupTimeout": "انتهت مهلة بدء تشغيل الخادم بعد {{seconds}} ثانية", + "server.processExited": "تم إنهاء عملية CLI بالرمز {{code}} قبل بدء الخادم", + "server.processSignaled": "تم إنهاء عملية CLI بواسطة الإشارة {{signal}} قبل بدء الخادم", + "server.spawnFailed": "فشل في تشغيل الملف الثنائي لـ CLI ({{code}})", + "server.startupTimeout": "انتهت مهلة بدء تشغيل الخادم بعد {{seconds}} ثوانٍ", "remote.connected": "Kilo Remote: متصل", "remote.connecting": "Kilo Remote: جارٍ الاتصال\u2026", } as const diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/br.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/br.ts index c2cb93e6ef..31c166b9c2 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/br.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/br.ts @@ -1,6 +1,8 @@ export const dict = { - "server.processExited": "O processo da CLI foi encerrado com o código {{code}} antes que o servidor fosse iniciado", - "server.startupTimeout": "Tempo limite de inicialização do servidor esgotado após {{seconds}} segundos", + "server.processExited": "O processo da CLI foi encerrado com o código {{code}} antes da inicialização do servidor", + "server.processSignaled": "O processo da CLI foi finalizado pelo sinal {{signal}} antes da inicialização do servidor", + "server.spawnFailed": "Falha ao gerar o binário da CLI ({{code}})", + "server.startupTimeout": "Tempo limite de inicialização do servidor atingido após {{seconds}} segundos", "remote.connected": "Kilo Remote: Conectado", "remote.connecting": "Kilo Remote: Conectando\u2026", } as const diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/bs.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/bs.ts index 87de30b377..6cf1847da9 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/bs.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/bs.ts @@ -1,6 +1,8 @@ export const dict = { - "server.processExited": "CLI proces je izašao sa kodom {{code}} prije nego što se server pokrenuo", - "server.startupTimeout": "Vrijeme pokretanja servera je isteklo nakon {{seconds}} sekundi", + "server.processExited": "CLI proces je izašao s kodom {{code}} prije nego što je server pokrenut", + "server.processSignaled": "CLI proces je prekinut signalom {{signal}} prije pokretanja servera", + "server.spawnFailed": "Neuspjelo pokretanje CLI binarne datoteke ({{code}})", + "server.startupTimeout": "Isteklo je vrijeme za pokretanje servera nakon {{seconds}} sekundi", "remote.connected": "Kilo Remote: Povezano", "remote.connecting": "Kilo Remote: Povezivanje\u2026", } as const diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/da.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/da.ts index 59881a81fe..9bd6d68e93 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/da.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/da.ts @@ -1,6 +1,8 @@ export const dict = { - "server.processExited": "CLI-processen afsluttede med kode {{code}} før serveren startede", - "server.startupTimeout": "Serverens opstartstid udløb efter {{seconds}} sekunder", + "server.processExited": "CLI-processen afsluttedes med kode {{code}}, før serveren startede", + "server.processSignaled": "CLI-processen blev afbrudt af signal {{signal}}, før serveren startede", + "server.spawnFailed": "Kunne ikke starte CLI-binærfil ({{code}})", + "server.startupTimeout": "Timeout for serverstart efter {{seconds}} sekunder", "remote.connected": "Kilo Remote: Forbundet", "remote.connecting": "Kilo Remote: Forbinder\u2026", } as const diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/de.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/de.ts index df45e47ea2..fc3d7b8d5e 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/de.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/de.ts @@ -1,5 +1,8 @@ export const dict = { "server.processExited": "Der CLI-Prozess wurde mit dem Code {{code}} beendet, bevor der Server gestartet wurde", + "server.processSignaled": + "Der CLI-Prozess wurde durch das Signal {{signal}} beendet, bevor der Server gestartet wurde", + "server.spawnFailed": "Fehler beim Starten der CLI-Binärdatei ({{code}})", "server.startupTimeout": "Zeitüberschreitung beim Serverstart nach {{seconds}} Sekunden", "remote.connected": "Kilo Remote: Verbunden", "remote.connecting": "Kilo Remote: Verbindung wird hergestellt\u2026", diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/en.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/en.ts index 0b59af3f34..ccecde0d24 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/en.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/en.ts @@ -1,5 +1,7 @@ export const dict = { "server.processExited": "CLI process exited with code {{code}} before server started", + "server.processSignaled": "CLI process terminated by signal {{signal}} before server started", + "server.spawnFailed": "Failed to spawn CLI binary ({{code}})", "server.startupTimeout": "Server startup timeout after {{seconds}} seconds", "remote.connected": "Kilo Remote: Connected", "remote.connecting": "Kilo Remote: Connecting\u2026", diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/es.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/es.ts index a744fe3345..6491eed1e8 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/es.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/es.ts @@ -1,6 +1,8 @@ export const dict = { - "server.processExited": "El proceso de la CLI finalizó con el código {{code}} antes de que se iniciara el servidor", - "server.startupTimeout": "Tiempo de espera de inicio del servidor agotado después de {{seconds}} segundos", + "server.processExited": "El proceso CLI finalizó con el código {{code}} antes de que se iniciara el servidor", + "server.processSignaled": "El proceso CLI fue terminado por la señal {{signal}} antes de que se iniciara el servidor", + "server.spawnFailed": "Error al generar el binario CLI ({{code}})", + "server.startupTimeout": "Tiempo de espera agotado para el inicio del servidor después de {{seconds}} segundos", "remote.connected": "Kilo Remote: Conectado", "remote.connecting": "Kilo Remote: Conectando\u2026", } as const diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/fa.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/fa.ts index 3aa4dc7483..19729aa5c7 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/fa.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/fa.ts @@ -1,6 +1,8 @@ export const dict = { - "server.processExited": "فرآیند CLI با کد {{code}} قبل از راه‌اندازی سرور خاتمه یافت", + "server.processExited": "فرایند CLI قبل از شروع سرور با کد {{code}} خارج شد", + "server.processSignaled": "فرایند CLI با سیگنال {{signal}} قبل از شروع سرور متوقف شد", + "server.spawnFailed": "اجرای فایل باینری CLI ناموفق بود ({{code}})", "server.startupTimeout": "زمان راه‌اندازی سرور پس از {{seconds}} ثانیه به پایان رسید", "remote.connected": "Kilo Remote: متصل شد", - "remote.connecting": "Kilo Remote: در حال اتصال…", + "remote.connecting": "Kilo Remote: در حال اتصال\u2026", } as const diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/fr.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/fr.ts index 03f7a3024e..dafcad4e76 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/fr.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/fr.ts @@ -1,6 +1,8 @@ export const dict = { - "server.processExited": "Le processus CLI s'est terminé avec le code {{code}} avant le démarrage du serveur", - "server.startupTimeout": "Délai de démarrage du serveur dépassé après {{seconds}} secondes", - "remote.connected": "Kilo Remote\u00a0: Connecté", - "remote.connecting": "Kilo Remote\u00a0: Connexion\u2026", + "server.processExited": "Le processus CLI a quitté avec le code {{code}} avant le démarrage du serveur", + "server.processSignaled": "Le processus CLI a été arrêté par le signal {{signal}} avant le démarrage du serveur", + "server.spawnFailed": "Échec du lancement du binaire CLI ({{code}})", + "server.startupTimeout": "Délai d'attente du démarrage du serveur dépassé après {{seconds}} secondes", + "remote.connected": "Kilo Remote : Connecté", + "remote.connecting": "Kilo Remote : Connexion en cours\u2026", } as const diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/it.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/it.ts index f032870a43..dc4b1d05ff 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/it.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/it.ts @@ -1,6 +1,8 @@ export const dict = { - "server.processExited": "Il processo CLI è uscito con codice {{code}} prima dell'avvio del server", + "server.processExited": "Il processo CLI è terminato con il codice {{code}} prima dell'avvio del server", + "server.processSignaled": "Il processo CLI è stato terminato dal segnale {{signal}} prima dell'avvio del server", + "server.spawnFailed": "Impossibile avviare il binario CLI ({{code}})", "server.startupTimeout": "Timeout di avvio del server dopo {{seconds}} secondi", - "remote.connected": "Kilo Remote: connesso", - "remote.connecting": "Kilo Remote: connessione...", + "remote.connected": "Kilo Remote: Connesso", + "remote.connecting": "Kilo Remote: Connessione in corso\u2026", } as const diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/ja.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/ja.ts index 58e9c3ee9b..966c46fc3c 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/ja.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/ja.ts @@ -1,5 +1,7 @@ export const dict = { "server.processExited": "サーバーが起動する前に、CLI プロセスがコード {{code}} で終了しました", + "server.processSignaled": "サーバーが起動する前に、CLI プロセスがシグナル {{signal}} で終了しました", + "server.spawnFailed": "CLI バイナリの起動に失敗しました ({{code}})", "server.startupTimeout": "サーバーの起動が {{seconds}} 秒後にタイムアウトしました", "remote.connected": "Kilo Remote: 接続済み", "remote.connecting": "Kilo Remote: 接続中\u2026", diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/ko.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/ko.ts index c48eed062e..61ca3601dd 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/ko.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/ko.ts @@ -1,6 +1,8 @@ export const dict = { - "server.processExited": "서버가 시작되기 전에 CLI 프로세스가 코드 {{code}}로 종료되었습니다", - "server.startupTimeout": "{{seconds}}초 후 서버 시작 시간이 초과되었습니다", + "server.processExited": "서버가 시작되기 전에 CLI 프로세스가 코드 {{code}}(으)로 종료되었습니다", + "server.processSignaled": "서버가 시작되기 전에 CLI 프로세스가 신호 {{signal}}(으)로 종료되었습니다", + "server.spawnFailed": "CLI 바이너리를 생성하지 못했습니다 ({{code}})", + "server.startupTimeout": "{{seconds}}초 후 서버 시작 시간 초과", "remote.connected": "Kilo Remote: 연결됨", "remote.connecting": "Kilo Remote: 연결 중\u2026", } as const diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/nl.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/nl.ts index c9cfc6a96e..87336c1c3b 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/nl.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/nl.ts @@ -1,5 +1,7 @@ export const dict = { "server.processExited": "CLI-proces is afgesloten met code {{code}} voordat de server is gestart", + "server.processSignaled": "CLI-proces is beëindigd door signaal {{signal}} voordat de server is gestart", + "server.spawnFailed": "Kan CLI-binair bestand niet starten ({{code}})", "server.startupTimeout": "Time-out bij opstarten van server na {{seconds}} seconden", "remote.connected": "Kilo Remote: Verbonden", "remote.connecting": "Kilo Remote: Verbinden\u2026", diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/no.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/no.ts index a24895f79e..e1148e928e 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/no.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/no.ts @@ -1,5 +1,7 @@ export const dict = { "server.processExited": "CLI-prosessen avsluttet med kode {{code}} før serveren startet", + "server.processSignaled": "CLI-prosessen ble avsluttet av signal {{signal}} før serveren startet", + "server.spawnFailed": "Kunne ikke starte CLI-binærfil ({{code}})", "server.startupTimeout": "Tidsavbrudd for serveroppstart etter {{seconds}} sekunder", "remote.connected": "Kilo Remote: Tilkoblet", "remote.connecting": "Kilo Remote: Kobler til\u2026", diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/pl.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/pl.ts index 7f7415c137..7f5c54e96f 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/pl.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/pl.ts @@ -1,5 +1,7 @@ export const dict = { - "server.processExited": "Proces CLI zakończył się z kodem {{code}} przed uruchomieniem serwera", + "server.processExited": "Proces CLI zakończył działanie z kodem {{code}} przed uruchomieniem serwera", + "server.processSignaled": "Proces CLI został przerwany przez sygnał {{signal}} przed uruchomieniem serwera", + "server.spawnFailed": "Nie udało się uruchomić pliku binarnego CLI ({{code}})", "server.startupTimeout": "Przekroczono limit czasu uruchamiania serwera po {{seconds}} sekundach", "remote.connected": "Kilo Remote: Połączono", "remote.connecting": "Kilo Remote: Łączenie\u2026", diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/ru.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/ru.ts index b9e721e60b..287091788b 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/ru.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/ru.ts @@ -1,5 +1,7 @@ export const dict = { "server.processExited": "Процесс CLI завершился с кодом {{code}} до запуска сервера", + "server.processSignaled": "Процесс CLI был завершен сигналом {{signal}} до запуска сервера", + "server.spawnFailed": "Не удалось запустить исполняемый файл CLI ({{code}})", "server.startupTimeout": "Время ожидания запуска сервера истекло через {{seconds}} секунд", "remote.connected": "Kilo Remote: Подключено", "remote.connecting": "Kilo Remote: Подключение\u2026", diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/th.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/th.ts index aff4ea8f37..05be10cd55 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/th.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/th.ts @@ -1,6 +1,8 @@ export const dict = { - "server.processExited": "กระบวนการ CLI ออกด้วยรหัส {{code}} ก่อนที่เซิร์ฟเวอร์จะเริ่มทำงาน", - "server.startupTimeout": "หมดเวลาการเริ่มต้นเซิร์ฟเวอร์หลังจาก {{seconds}} วินาที", + "server.processExited": "กระบวนการ CLI ออกด้วยรหัส {{code}} ก่อนที่เซิร์ฟเวอร์จะเริ่มต้น", + "server.processSignaled": "กระบวนการ CLI ถูกยุติโดยสัญญาณ {{signal}} ก่อนที่เซิร์ฟเวอร์จะเริ่มต้น", + "server.spawnFailed": "ไม่สามารถเริ่มต้นไบนารี CLI ({{code}})", + "server.startupTimeout": "หมดเวลาเริ่มต้นเซิร์ฟเวอร์หลังจาก {{seconds}} วินาที", "remote.connected": "Kilo Remote: เชื่อมต่อแล้ว", "remote.connecting": "Kilo Remote: กำลังเชื่อมต่อ\u2026", } as const diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/tr.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/tr.ts index 6be397e7a3..4530412f19 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/tr.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/tr.ts @@ -1,5 +1,7 @@ export const dict = { - "server.processExited": "CLI işlemi sunucu başlamadan önce {{code}} koduyla çıktı", + "server.processExited": "CLI işlemi sunucu başlatılmadan önce {{code}} koduyla çıktı", + "server.processSignaled": "CLI işlemi sunucu başlatılmadan önce {{signal}} sinyali ile sonlandırıldı", + "server.spawnFailed": "CLI ikili dosyası başlatılamadı ({{code}})", "server.startupTimeout": "{{seconds}} saniye sonra sunucu başlatma zaman aşımı", "remote.connected": "Kilo Remote: Bağlandı", "remote.connecting": "Kilo Remote: Bağlanıyor\u2026", diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/uk.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/uk.ts index 315d12fa96..5b89093555 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/uk.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/uk.ts @@ -1,6 +1,8 @@ export const dict = { "server.processExited": "Процес CLI завершився з кодом {{code}} до запуску сервера", - "server.startupTimeout": "Час очікування запуску сервера вичерпано після {{seconds}} секунд", + "server.processSignaled": "Процес CLI був завершений сигналом {{signal}} до запуску сервера", + "server.spawnFailed": "Не вдалося запустити двійковий файл CLI ({{code}})", + "server.startupTimeout": "Час очікування запуску сервера минув через {{seconds}} секунд", "remote.connected": "Kilo Remote: Підключено", "remote.connecting": "Kilo Remote: Підключення\u2026", } as const diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/zh.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/zh.ts index 72160d167f..b050faebf4 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/zh.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/zh.ts @@ -1,6 +1,8 @@ export const dict = { - "server.processExited": "在服务器启动之前,CLI 进程已退出,代码为 {{code}}", - "server.startupTimeout": "服务器启动在 {{seconds}} 秒后超时", + "server.processExited": "CLI 进程在服务器启动前以代码 {{code}} 退出", + "server.processSignaled": "CLI 进程在服务器启动前被信号 {{signal}} 终止", + "server.spawnFailed": "生成 CLI 二进制文件失败 ({{code}})", + "server.startupTimeout": "{{seconds}} 秒后服务器启动超时", "remote.connected": "Kilo Remote: 已连接", "remote.connecting": "Kilo Remote: 正在连接\u2026", } as const diff --git a/packages/kilo-vscode/src/services/cli-backend/i18n/zht.ts b/packages/kilo-vscode/src/services/cli-backend/i18n/zht.ts index 61baae8020..799bb17a8f 100644 --- a/packages/kilo-vscode/src/services/cli-backend/i18n/zht.ts +++ b/packages/kilo-vscode/src/services/cli-backend/i18n/zht.ts @@ -1,6 +1,8 @@ export const dict = { - "server.processExited": "在伺服器啟動之前,CLI 處理程序已退出,代碼為 {{code}}", - "server.startupTimeout": "伺服器啟動在 {{seconds}} 秒後逾時", + "server.processExited": "CLI 程序在伺服器啟動前以代碼 {{code}} 退出", + "server.processSignaled": "CLI 程序在伺服器啟動前被信號 {{signal}} 終止", + "server.spawnFailed": "生成 CLI 二進位檔案失敗 ({{code}})", + "server.startupTimeout": "{{seconds}} 秒後伺服器啟動逾時", "remote.connected": "Kilo Remote: 已連線", "remote.connecting": "Kilo Remote: 正在連線\u2026", } as const diff --git a/packages/kilo-vscode/src/services/cli-backend/server-manager.ts b/packages/kilo-vscode/src/services/cli-backend/server-manager.ts index 76cb512571..df6f812195 100644 --- a/packages/kilo-vscode/src/services/cli-backend/server-manager.ts +++ b/packages/kilo-vscode/src/services/cli-backend/server-manager.ts @@ -17,7 +17,7 @@ export interface ServerInstance { const STARTUP_TIMEOUT_SECONDS = 30 type WorkspaceFolderLike = { uri: { fsPath: string } } -type ServerExitListener = (code: number | null) => void +type ServerExitListener = (code: number | null, signal: NodeJS.Signals | null) => void export function resolveServerCwd(folders: readonly WorkspaceFolderLike[] | undefined, storage: string): string { return folders?.[0]?.uri.fsPath ?? storage @@ -182,25 +182,36 @@ export class ServerManager { stderrLines.push(errorOutput) }) - serverProcess.on("error", (error) => { - console.error("[Kilo New] ServerManager: ❌ Process error:", error) + serverProcess.on("error", (err: NodeJS.ErrnoException) => { + console.error("[Kilo New] ServerManager: ❌ Process error:", err) if (!resolved) { - reject(error) + const spawnErr = err as NodeJS.ErrnoException & { spawnargs?: string[] } + const code = err.code || err.name || "UNKNOWN" + const header = t("server.spawnFailed", { code }) + const lines = [ + `Error: ${err.message}`, + ...(err.code ? [`Code: ${err.code}`] : []), + ...(err.errno !== undefined ? [`Errno: ${err.errno}`] : []), + ...(err.syscall ? [`Syscall: ${err.syscall}`] : []), + ...(err.path ? [`Path: ${err.path}`] : []), + ...(Array.isArray(spawnErr.spawnargs) ? [`Spawn args: ${JSON.stringify(spawnErr.spawnargs)}`] : []), + ] + const { userMessage, userDetails } = toErrorMessage(header, [...lines, ...stderrLines], cliPath) + reject(new ServerStartupError(userMessage, userDetails)) } }) - serverProcess.on("exit", (code) => { - console.log("[Kilo New] ServerManager: 🛑 Process exited with code:", code) + serverProcess.on("exit", (code, signal) => { + console.log("[Kilo New] ServerManager: 🛑 Process exited:", { code, signal }) if (this.instance?.process === serverProcess) { this.instance = null - this.onExit?.(code) + this.onExit?.(code, signal) } if (!resolved) { - const { userMessage, userDetails } = toErrorMessage( - t("server.processExited", { code: code ?? "null" }), - stderrLines, - cliPath, - ) + const msg = signal + ? t("server.processSignaled", { signal }) + : t("server.processExited", { code: code ?? "unknown" }) + const { userMessage, userDetails } = toErrorMessage(msg, stderrLines, cliPath) reject(new ServerStartupError(userMessage, userDetails)) } }) diff --git a/packages/kilo-vscode/tests/unit/server-manager-utils.test.ts b/packages/kilo-vscode/tests/unit/server-manager-utils.test.ts index ac811c0532..c62e3b51eb 100644 --- a/packages/kilo-vscode/tests/unit/server-manager-utils.test.ts +++ b/packages/kilo-vscode/tests/unit/server-manager-utils.test.ts @@ -295,6 +295,34 @@ describe("toErrorMessage", () => { const result = toErrorMessage("startup failed", ["some output"]) expect(result.error).toBe("startup failed") }) + + it("formats structured spawn error details with syscall, errno, and args", () => { + const spawnLines = [ + "Error: spawn UNKNOWN", + "Code: UNKNOWN", + "Errno: -86", + "Syscall: spawn", + "Path: /path/to/bin/kilo", + 'Spawn args: ["serve","--port","0"]', + ] + const result = toErrorMessage("Failed to spawn CLI binary (UNKNOWN)", spawnLines, "/path/to/bin/kilo") + expect(result.userMessage).toBe("spawn UNKNOWN") + expect(result.userDetails).toContain("CLI path: /path/to/bin/kilo") + expect(result.userDetails).toContain("Failed to spawn CLI binary (UNKNOWN)") + expect(result.userDetails).toContain("Syscall: spawn") + expect(result.userDetails).toContain("Errno: -86") + }) + + it("handles signal termination without stderr lines cleanly", () => { + const result = toErrorMessage( + "CLI process terminated by signal SIGSEGV before server started", + [], + "/path/to/bin/kilo", + ) + expect(result.userMessage).toBe("CLI process terminated by signal SIGSEGV before server started") + expect(result.userDetails).toContain("CLI path: /path/to/bin/kilo") + expect(result.userDetails).toContain("CLI process terminated by signal SIGSEGV before server started") + }) }) describe("server workspace helpers", () => { From 1541da3deb3c8df7e658938de64c87bb709d2564 Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Fri, 7 Aug 2026 16:58:02 +0200 Subject: [PATCH 2/2] fix(vscode): handle ServerStartupError in MarketplacePanelProvider state change and warn on exit --- packages/kilo-vscode/src/MarketplacePanelProvider.ts | 10 +++++++++- .../src/services/cli-backend/server-manager.ts | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/kilo-vscode/src/MarketplacePanelProvider.ts b/packages/kilo-vscode/src/MarketplacePanelProvider.ts index fc62bf46b9..32fd768b23 100644 --- a/packages/kilo-vscode/src/MarketplacePanelProvider.ts +++ b/packages/kilo-vscode/src/MarketplacePanelProvider.ts @@ -123,7 +123,15 @@ export class MarketplacePanelProvider implements vscode.Disposable { ) this.subscriptions.push( this.connection.onStateChange((state, err) => { - this.post({ type: "connectionState", state, ...(err ? { error: err.message } : {}) }) + this.post({ + type: "connectionState", + state, + ...(err ? { error: err.message } : {}), + ...(err instanceof ServerStartupError && { + userMessage: err.userMessage, + userDetails: err.userDetails, + }), + }) if (state === "connected") void this.sync(false) }), this.connection.onLanguageChanged((locale) => this.post({ type: "languageChanged", locale })), diff --git a/packages/kilo-vscode/src/services/cli-backend/server-manager.ts b/packages/kilo-vscode/src/services/cli-backend/server-manager.ts index df6f812195..9edea2476c 100644 --- a/packages/kilo-vscode/src/services/cli-backend/server-manager.ts +++ b/packages/kilo-vscode/src/services/cli-backend/server-manager.ts @@ -202,7 +202,7 @@ export class ServerManager { }) serverProcess.on("exit", (code, signal) => { - console.log("[Kilo New] ServerManager: 🛑 Process exited:", { code, signal }) + console.warn("[Kilo New] ServerManager: 🛑 Process exited:", { code, signal }) if (this.instance?.process === serverProcess) { this.instance = null this.onExit?.(code, signal)