Turn on upper-snake-string-unions and convert profile types, failure reasons and anchor sides at their boundaries
This commit is contained in:
+33
-13
@@ -1,6 +1,6 @@
|
||||
// The agent and model a profile runs, which every report names.
|
||||
export interface ProfileIdentity {
|
||||
type: "claude" | "codex" | "opencode";
|
||||
type: "CLAUDE" | "CODEX" | "OPENCODE";
|
||||
model: string;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,19 @@ export function withProfile(body: string, profile: ProfileIdentity): string {
|
||||
return `${body}\n\n${profileFooter(profile)}`;
|
||||
}
|
||||
|
||||
export type FailureReason = "sign-in failed" | "usage exhausted" | "failed";
|
||||
export type FailureReason = "SIGN_IN_FAILED" | "USAGE_EXHAUSTED" | "FAILED";
|
||||
|
||||
// The words a failure reason reads as in logs and posted comments.
|
||||
function toMessage(reason: FailureReason): string {
|
||||
switch (reason) {
|
||||
case "SIGN_IN_FAILED":
|
||||
return "sign-in failed";
|
||||
case "USAGE_EXHAUSTED":
|
||||
return "usage exhausted";
|
||||
case "FAILED":
|
||||
return "failed";
|
||||
}
|
||||
}
|
||||
|
||||
export interface ProfileFailure extends ProfileIdentity {
|
||||
reason: FailureReason;
|
||||
@@ -44,9 +56,9 @@ function isUsageExhausted(error: unknown): boolean {
|
||||
|
||||
function failureReason(error: unknown): FailureReason {
|
||||
if (error instanceof AgentAuthError) {
|
||||
return "sign-in failed";
|
||||
return "SIGN_IN_FAILED";
|
||||
}
|
||||
return isUsageExhausted(error) ? "usage exhausted" : "failed";
|
||||
return isUsageExhausted(error) ? "USAGE_EXHAUSTED" : "FAILED";
|
||||
}
|
||||
|
||||
export function failureFooter(failures: ProfileFailure[]): string {
|
||||
@@ -54,7 +66,7 @@ export function failureFooter(failures: ProfileFailure[]): string {
|
||||
return "> Profile: none";
|
||||
}
|
||||
return `> Tried: ${failures
|
||||
.map(({ type, model, reason }) => `\`${type}\` · \`${model}\` (${reason})`)
|
||||
.map(({ type, model, reason }) => `\`${type}\` · \`${model}\` (${toMessage(reason)})`)
|
||||
.join(", ")}`;
|
||||
}
|
||||
|
||||
@@ -71,10 +83,10 @@ export async function runProfiles<T, P extends ProfileIdentity>(
|
||||
} catch (error) {
|
||||
const reason = failureReason(error);
|
||||
failures.push({ type: profile.type, model: profile.model, reason });
|
||||
if (reason === "failed" || index === profiles.length - 1) {
|
||||
if (reason === "FAILED" || index === profiles.length - 1) {
|
||||
throw error;
|
||||
}
|
||||
console.error(`${profile.type} ${reason}; trying next profile`);
|
||||
console.error(`${profile.type} ${toMessage(reason)}; trying next profile`);
|
||||
}
|
||||
}
|
||||
throw new Error("profiles must contain at least one profile");
|
||||
@@ -120,6 +132,18 @@ export function sanitizedEnvironment(
|
||||
return result;
|
||||
}
|
||||
|
||||
// The environment variable each agent CLI reads its credential from.
|
||||
function tokenVariable(type: ProfileIdentity["type"]): string {
|
||||
switch (type) {
|
||||
case "CLAUDE":
|
||||
return "CLAUDE_CODE_OAUTH_TOKEN";
|
||||
case "CODEX":
|
||||
return "OPENAI_API_KEY";
|
||||
case "OPENCODE":
|
||||
return "OPENROUTER_API_KEY";
|
||||
}
|
||||
}
|
||||
|
||||
export function agentEnvironment(
|
||||
environment: ReadonlyMap<string, string>,
|
||||
profile: ProfileHome,
|
||||
@@ -127,15 +151,11 @@ export function agentEnvironment(
|
||||
): Map<string, string> {
|
||||
const result = sanitizedEnvironment(environment);
|
||||
result.set("HOME", profile.home);
|
||||
if (profile.type === "codex") {
|
||||
if (profile.type === "CODEX") {
|
||||
result.set("CODEX_HOME", `${profile.home}/.codex`);
|
||||
}
|
||||
if (token !== undefined && token !== "") {
|
||||
const tokenName = {
|
||||
claude: "CLAUDE_CODE_OAUTH_TOKEN",
|
||||
codex: "OPENAI_API_KEY",
|
||||
opencode: "OPENROUTER_API_KEY",
|
||||
}[profile.type];
|
||||
const tokenName = tokenVariable(profile.type);
|
||||
result.set(tokenName, token);
|
||||
}
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user