FN-6808: handle AI CLI probe spawn failures
Resolve synchronous AI CLI probe launch failures as unavailable auth states. - Catch synchronous spawn failures in Claude and Droid probe helpers so fire-and-forget validation paths do not reject. - Return unavailable/unauthenticated sentinels for Droid model discovery and CLI presence/auth checks. - Add regression coverage for Claude and Droid presence/auth probes plus a patch changeset. Files changed: .../fn-6808-cli-probe-unhandled-rejection.md | 5 ++++ .../src/__tests__/process-manager.test.ts | 25 ++++++++++++++++++++ .../src/__tests__/process-manager.test.ts | 25 ++++++++++++++++++++ packages/pi-claude-cli/src/process-manager.ts | 12 +++++++++- .../src/process-manager.ts | 27 +++++++++++++++++++--- 5 files changed, 90 insertions(+), 4 deletions(-) Fusion-Task-Id: FN-6808 Fusion-Task-Lineage: 79702ef2-e116-4313-a557-da17a6888c30
This commit is contained in:
@@ -219,10 +219,20 @@ export function captureStderr(proc: ChildProcess): () => string {
|
||||
* does this on every chat send), sync probes freeze every other request.
|
||||
* This async variant uses spawn so the loop keeps turning while the subprocess
|
||||
* starts up.
|
||||
*
|
||||
* FNXC:CliRuntime 2026-06-20-17:25:
|
||||
* FN-6808/FN-6801 require this fire-and-forget auth/presence probe to never reject. Catch synchronous spawn throws from the Vitest child-process guard or platform launch errors and resolve 127, matching the async error sentinel so callers degrade to unauthenticated/not-present instead of surfacing unhandled promise rejections.
|
||||
*/
|
||||
function runDroidProbe(args: string[], timeoutMs = 45000): Promise<number> {
|
||||
return new Promise((resolve) => {
|
||||
const proc = spawn("droid", args, { stdio: "ignore" });
|
||||
let proc: ChildProcess;
|
||||
try {
|
||||
proc = spawn("droid", args, { stdio: "ignore" });
|
||||
} catch {
|
||||
resolve(127);
|
||||
return;
|
||||
}
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
try {
|
||||
proc.kill("SIGKILL");
|
||||
@@ -275,11 +285,22 @@ export async function validateCliAuthAsync(): Promise<boolean> {
|
||||
}
|
||||
|
||||
export async function discoverDroidModels(): Promise<string[]> {
|
||||
const attempts: string[][] = [["models", "--json"], ["model", "list", "--json"], ["models"]];
|
||||
const attempts: string[][] = [
|
||||
["models", "--json"],
|
||||
["model", "list", "--json"],
|
||||
["models"],
|
||||
];
|
||||
|
||||
for (const args of attempts) {
|
||||
const models = await new Promise<string[] | null>((resolve) => {
|
||||
const proc = spawn("droid", args, { stdio: ["ignore", "pipe", "ignore"] });
|
||||
let proc: ChildProcess;
|
||||
try {
|
||||
proc = spawn("droid", args, { stdio: ["ignore", "pipe", "ignore"] });
|
||||
} catch {
|
||||
resolve(null);
|
||||
return;
|
||||
}
|
||||
|
||||
let out = "";
|
||||
proc.stdout?.on("data", (chunk: Buffer) => {
|
||||
out += chunk.toString();
|
||||
|
||||
Reference in New Issue
Block a user