refactor: replace string-prefix error detection with typed error classes

Co-Authored-By: mantra <mantra@stack-auth.com>
This commit is contained in:
Devin AI 2026-06-05 00:06:41 +00:00
parent 6fcd7532bf
commit 227ec0ec20
2 changed files with 19 additions and 5 deletions

View File

@ -35,6 +35,20 @@ export type RunClaudeAgentResult = {
resultText: string,
};
export class ClaudeAgentTimeoutError extends Error {
constructor(timeoutMs?: number) {
super(`Claude agent timed out${timeoutMs == null ? "" : ` after ${timeoutMs}ms`}.`);
this.name = "ClaudeAgentTimeoutError";
}
}
export class ClaudeAgentFailureError extends Error {
constructor(subtype: string) {
super(`Claude agent failed (${subtype}).`);
this.name = "ClaudeAgentFailureError";
}
}
function isAbortError(error: unknown): boolean {
return error instanceof Error && error.name === "AbortError";
}
@ -91,13 +105,13 @@ export async function runHeadlessClaudeAgent(options: RunClaudeAgentOptions): Pr
sawResult = true;
resultText = message.result;
} else {
throw new Error(`Claude agent failed (${message.subtype}).`);
throw new ClaudeAgentFailureError(message.subtype);
}
}
}
} catch (error) {
if (abortController.signal.aborted && isAbortError(error)) {
throw new Error(`Claude agent timed out${options.timeoutMs == null ? "" : ` after ${options.timeoutMs}ms`}.`);
throw new ClaudeAgentTimeoutError(options.timeoutMs ?? undefined);
}
throw error;
} finally {

View File

@ -7,7 +7,7 @@ import { createHash } from "crypto";
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
import { createJiti } from "jiti";
import path from "path";
import { getToolWriteTargetPath, isPathInsideDir, runHeadlessClaudeAgent } from "./config-agent";
import { ClaudeAgentFailureError, ClaudeAgentTimeoutError, getToolWriteTargetPath, isPathInsideDir, runHeadlessClaudeAgent } from "./config-agent";
const jiti = createJiti(import.meta.url, { moduleCache: false });
@ -190,10 +190,10 @@ async function runConfigUpdateAgent(options: {
},
});
} catch (error) {
if (error instanceof Error && error.message.startsWith("Claude agent timed out")) {
if (error instanceof ClaudeAgentTimeoutError) {
throw new Error(`Config update agent timed out after ${timeoutMs}ms. It was unable to apply the config changes to the file.`);
}
if (error instanceof Error && error.message.startsWith("Claude agent failed")) {
if (error instanceof ClaudeAgentFailureError) {
throw new Error(`${error.message} It was unable to apply the config changes to the file.`);
}
throw error;