diff --git a/packages/cli/package.json b/packages/cli/package.json index 184484ed..46b26e6a 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@openrouter/spawn", - "version": "0.15.29", + "version": "0.15.30", "type": "module", "bin": { "spawn": "cli.js" diff --git a/packages/cli/src/picker.ts b/packages/cli/src/picker.ts index 6fdf947d..3e35a7f0 100644 --- a/packages/cli/src/picker.ts +++ b/packages/cli/src/picker.ts @@ -120,6 +120,7 @@ type WriteFn = (s: string) => void; interface KeyLoopCallbacks { fallback: () => T; + cancel: () => T; init: (w: WriteFn, cols: number) => void; handleKey: ( key: string, @@ -223,6 +224,7 @@ function withTTYKeyLoop(callbacks: KeyLoopCallbacks): T { // ── key loop ──────────────────────────────────────────────────────────── const buf = Buffer.alloc(8); let finalResult: T | undefined; + let cancelled = false; try { while (true) { @@ -238,8 +240,9 @@ function withTTYKeyLoop(callbacks: KeyLoopCallbacks): T { const key = buf.slice(0, n).toString("binary"); - // Ctrl-C / Escape — universal cancel + // Ctrl-C / Escape — explicit user cancel (not a TTY failure) if (key === "\x03" || key === "\x1b") { + cancelled = true; break; } @@ -253,7 +256,10 @@ function withTTYKeyLoop(callbacks: KeyLoopCallbacks): T { restore(); } - return finalResult !== undefined ? finalResult : callbacks.fallback(); + if (finalResult !== undefined) { + return finalResult; + } + return cancelled ? callbacks.cancel() : callbacks.fallback(); } // ── TTY picker ──────────────────────────────────────────────────────────────── @@ -316,6 +322,7 @@ export function pickToTTYWithActions(config: PickConfig): PickResult { return withTTYKeyLoop({ fallback, + cancel: () => cancel, init(w, cols) { maxW = cols - 1;