Add gemini as a client option

This commit is contained in:
Owen
2026-08-20 10:28:25 -04:00
parent c1caa30cb9
commit c1051db4a5
5 changed files with 67 additions and 5 deletions
+1
View File
@@ -1785,6 +1785,7 @@
"aiClientConfigDescriptionClaude": "Anthropic's agentic coding tool for the terminal.",
"aiClientConfigDescriptionCodex": "OpenAI's agentic coding tool for the terminal.",
"aiClientConfigDescriptionOpencode": "Open source terminal coding agent.",
"aiClientConfigDescriptionGemini": "Google's agentic coding tool for the terminal.",
"aiClientConfigSetup": "Setup",
"aiClientConfigTabCli": "Automatic (CLI)",
"aiClientConfigTabManual": "Manual Configuration",
+3
View File
@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.04 19.32Q12 21.51 12 24q0-2.49.93-4.68.96-2.19 2.58-3.81t3.81-2.55Q21.51 12 24 12q-2.49 0-4.68-.93a12.3 12.3 0 0 1-3.81-2.58 12.3 12.3 0 0 1-2.58-3.81Q12 2.49 12 0q0 2.49-.96 4.68-.93 2.19-2.55 3.81a12.3 12.3 0 0 1-3.81 2.58Q2.49 12 0 12q2.49 0 4.68.96 2.19.93 3.81 2.55t2.55 3.81" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 413 B

+3
View File
@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.04 19.32Q12 21.51 12 24q0-2.49.93-4.68.96-2.19 2.58-3.81t3.81-2.55Q21.51 12 24 12q-2.49 0-4.68-.93a12.3 12.3 0 0 1-3.81-2.58 12.3 12.3 0 0 1-2.58-3.81Q12 2.49 12 0q0 2.49-.96 4.68-.93 2.19-2.55 3.81a12.3 12.3 0 0 1-3.81 2.58Q2.49 12 0 12q2.49 0 4.68.96 2.19.93 3.81 2.55t2.55 3.81" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 413 B

@@ -49,6 +49,10 @@ const CLIENT_LOGOS = {
opencode: {
light: "/third-party/opencode-dark.svg",
dark: "/third-party/opencode-light.svg"
},
gemini: {
light: "/third-party/gemini-dark.svg",
dark: "/third-party/gemini-light.svg"
}
} as const;
@@ -65,7 +69,8 @@ export function AiClientConfigSection({
const descriptions: Record<string, string> = {
claude: t("aiClientConfigDescriptionClaude"),
codex: t("aiClientConfigDescriptionCodex"),
opencode: t("aiClientConfigDescriptionOpencode")
opencode: t("aiClientConfigDescriptionOpencode"),
gemini: t("aiClientConfigDescriptionGemini")
};
return (
+54 -4
View File
@@ -1,10 +1,16 @@
export const AI_CLIENT_IDS = ["claude", "codex", "opencode"] as const;
export const AI_CLIENT_IDS = [
"claude",
"codex",
"opencode",
"gemini"
] as const;
export type AiClientId = (typeof AI_CLIENT_IDS)[number];
export const AI_CLIENT_NAMES: Record<AiClientId, string> = {
claude: "Claude Code",
codex: "Codex",
opencode: "OpenCode"
opencode: "OpenCode",
gemini: "Gemini CLI"
};
/** Auth as supplied by callers: the real key isn't fetched yet. */
@@ -74,7 +80,7 @@ export function aiConfigBlockHasPlaceholders(block: AiConfigBlock): boolean {
}
function buildCli(
clientArg: "claude" | "codex" | "opencode",
clientArg: "claude" | "codex" | "opencode" | "gemini",
auth: AiClientAuth,
resourceNiceId?: string
): AiConfigBlock[] {
@@ -351,6 +357,49 @@ function buildOpencodeGuide(
};
}
function buildGeminiGuide(
endpoint: string,
auth: AiClientAuth,
resourceNiceId?: string
): AiClientGuide {
const defaultEnv = block(
"gemini-default-env",
"~/.gemini/.env",
(key) =>
[
`GOOGLE_GEMINI_BASE_URL=${endpoint}`,
`GEMINI_API_KEY=${auth.mode === "keyed" ? key : "none"}`
].join("\n"),
auth
);
const defaultShell = block(
"gemini-default-shell",
"Shell",
(key) =>
[
`export GOOGLE_GEMINI_BASE_URL=${endpoint}`,
`export GEMINI_API_KEY=${auth.mode === "keyed" ? key : "none"}`,
"gemini"
].join("\n"),
auth
);
return {
id: "gemini",
name: AI_CLIENT_NAMES.gemini,
cli: buildCli("gemini", auth, resourceNiceId),
presets: [
{
id: "default",
label: "Default",
relation: "options",
blocks: [defaultEnv, defaultShell]
}
]
};
}
const GUIDE_BUILDERS: Record<
AiClientId,
(
@@ -361,7 +410,8 @@ const GUIDE_BUILDERS: Record<
> = {
claude: buildClaudeGuide,
codex: buildCodexGuide,
opencode: buildOpencodeGuide
opencode: buildOpencodeGuide,
gemini: buildGeminiGuide
};
export function buildAiClientGuide(