feat: add Gemini API key onboarding
This commit is contained in:
committed by
Peter Steinberger
parent
340d5d03f2
commit
302d51fd40
@@ -165,8 +165,9 @@ Options:
|
|||||||
- `--workspace <dir>`
|
- `--workspace <dir>`
|
||||||
- `--non-interactive`
|
- `--non-interactive`
|
||||||
- `--mode <local|remote>`
|
- `--mode <local|remote>`
|
||||||
- `--auth-choice <oauth|claude-cli|openai-codex|codex-cli|antigravity|apiKey|minimax|skip>`
|
- `--auth-choice <oauth|claude-cli|openai-codex|codex-cli|antigravity|gemini-api-key|apiKey|minimax|skip>`
|
||||||
- `--anthropic-api-key <key>`
|
- `--anthropic-api-key <key>`
|
||||||
|
- `--gemini-api-key <key>`
|
||||||
- `--gateway-port <port>`
|
- `--gateway-port <port>`
|
||||||
- `--gateway-bind <loopback|lan|tailnet|auto>`
|
- `--gateway-bind <loopback|lan|tailnet|auto>`
|
||||||
- `--gateway-auth <off|token|password>`
|
- `--gateway-auth <off|token|password>`
|
||||||
|
|||||||
@@ -170,6 +170,17 @@ clawdbot onboard --non-interactive \
|
|||||||
|
|
||||||
Add `--json` for a machine‑readable summary.
|
Add `--json` for a machine‑readable summary.
|
||||||
|
|
||||||
|
Gemini example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
clawdbot onboard --non-interactive \
|
||||||
|
--mode local \
|
||||||
|
--auth-choice gemini-api-key \
|
||||||
|
--gemini-api-key "$GEMINI_API_KEY" \
|
||||||
|
--gateway-port 18789 \
|
||||||
|
--gateway-bind loopback
|
||||||
|
```
|
||||||
|
|
||||||
Add agent (non‑interactive) example:
|
Add agent (non‑interactive) example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -232,9 +232,10 @@ export function buildProgram() {
|
|||||||
.option("--mode <mode>", "Wizard mode: local|remote")
|
.option("--mode <mode>", "Wizard mode: local|remote")
|
||||||
.option(
|
.option(
|
||||||
"--auth-choice <choice>",
|
"--auth-choice <choice>",
|
||||||
"Auth: oauth|claude-cli|openai-codex|codex-cli|antigravity|apiKey|minimax|skip",
|
"Auth: oauth|claude-cli|openai-codex|codex-cli|antigravity|gemini-api-key|apiKey|minimax|skip",
|
||||||
)
|
)
|
||||||
.option("--anthropic-api-key <key>", "Anthropic API key")
|
.option("--anthropic-api-key <key>", "Anthropic API key")
|
||||||
|
.option("--gemini-api-key <key>", "Gemini API key")
|
||||||
.option("--gateway-port <port>", "Gateway port")
|
.option("--gateway-port <port>", "Gateway port")
|
||||||
.option("--gateway-bind <mode>", "Gateway bind: loopback|lan|tailnet|auto")
|
.option("--gateway-bind <mode>", "Gateway bind: loopback|lan|tailnet|auto")
|
||||||
.option("--gateway-auth <mode>", "Gateway auth: off|token|password")
|
.option("--gateway-auth <mode>", "Gateway auth: off|token|password")
|
||||||
@@ -263,11 +264,13 @@ export function buildProgram() {
|
|||||||
| "openai-codex"
|
| "openai-codex"
|
||||||
| "codex-cli"
|
| "codex-cli"
|
||||||
| "antigravity"
|
| "antigravity"
|
||||||
|
| "gemini-api-key"
|
||||||
| "apiKey"
|
| "apiKey"
|
||||||
| "minimax"
|
| "minimax"
|
||||||
| "skip"
|
| "skip"
|
||||||
| undefined,
|
| undefined,
|
||||||
anthropicApiKey: opts.anthropicApiKey as string | undefined,
|
anthropicApiKey: opts.anthropicApiKey as string | undefined,
|
||||||
|
geminiApiKey: opts.geminiApiKey as string | undefined,
|
||||||
gatewayPort:
|
gatewayPort:
|
||||||
typeof opts.gatewayPort === "string"
|
typeof opts.gatewayPort === "string"
|
||||||
? Number.parseInt(opts.gatewayPort, 10)
|
? Number.parseInt(opts.gatewayPort, 10)
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ export function buildAuthChoiceOptions(params: {
|
|||||||
value: "antigravity",
|
value: "antigravity",
|
||||||
label: "Google Antigravity (Claude Opus 4.5, Gemini 3, etc.)",
|
label: "Google Antigravity (Claude Opus 4.5, Gemini 3, etc.)",
|
||||||
});
|
});
|
||||||
|
options.push({ value: "gemini-api-key", label: "Google Gemini API key" });
|
||||||
options.push({ value: "apiKey", label: "Anthropic API key" });
|
options.push({ value: "apiKey", label: "Anthropic API key" });
|
||||||
options.push({ value: "minimax", label: "Minimax M2.1 (LM Studio)" });
|
options.push({ value: "minimax", label: "Minimax M2.1 (LM Studio)" });
|
||||||
if (params.includeSkip) {
|
if (params.includeSkip) {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import {
|
|||||||
applyMinimaxConfig,
|
applyMinimaxConfig,
|
||||||
applyMinimaxProviderConfig,
|
applyMinimaxProviderConfig,
|
||||||
setAnthropicApiKey,
|
setAnthropicApiKey,
|
||||||
|
setGeminiApiKey,
|
||||||
writeOAuthCredentials,
|
writeOAuthCredentials,
|
||||||
} from "./onboard-auth.js";
|
} from "./onboard-auth.js";
|
||||||
import { openUrl } from "./onboard-helpers.js";
|
import { openUrl } from "./onboard-helpers.js";
|
||||||
@@ -415,6 +416,17 @@ export async function applyAuthChoice(params: {
|
|||||||
"OAuth help",
|
"OAuth help",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} else if (params.authChoice === "gemini-api-key") {
|
||||||
|
const key = await params.prompter.text({
|
||||||
|
message: "Enter Gemini API key",
|
||||||
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
||||||
|
});
|
||||||
|
await setGeminiApiKey(String(key).trim(), params.agentDir);
|
||||||
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
||||||
|
profileId: "google:default",
|
||||||
|
provider: "google",
|
||||||
|
mode: "api_key",
|
||||||
|
});
|
||||||
} else if (params.authChoice === "apiKey") {
|
} else if (params.authChoice === "apiKey") {
|
||||||
const key = await params.prompter.text({
|
const key = await params.prompter.text({
|
||||||
message: "Enter Anthropic API key",
|
message: "Enter Anthropic API key",
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ import {
|
|||||||
applyAuthProfileConfig,
|
applyAuthProfileConfig,
|
||||||
applyMinimaxConfig,
|
applyMinimaxConfig,
|
||||||
setAnthropicApiKey,
|
setAnthropicApiKey,
|
||||||
|
setGeminiApiKey,
|
||||||
writeOAuthCredentials,
|
writeOAuthCredentials,
|
||||||
} from "./onboard-auth.js";
|
} from "./onboard-auth.js";
|
||||||
import {
|
import {
|
||||||
@@ -300,6 +301,7 @@ async function promptAuthConfig(
|
|||||||
| "openai-codex"
|
| "openai-codex"
|
||||||
| "codex-cli"
|
| "codex-cli"
|
||||||
| "antigravity"
|
| "antigravity"
|
||||||
|
| "gemini-api-key"
|
||||||
| "apiKey"
|
| "apiKey"
|
||||||
| "minimax"
|
| "minimax"
|
||||||
| "skip";
|
| "skip";
|
||||||
@@ -513,6 +515,20 @@ async function promptAuthConfig(
|
|||||||
runtime.error(String(err));
|
runtime.error(String(err));
|
||||||
note("Trouble with OAuth? See https://docs.clawd.bot/start/faq", "OAuth");
|
note("Trouble with OAuth? See https://docs.clawd.bot/start/faq", "OAuth");
|
||||||
}
|
}
|
||||||
|
} else if (authChoice === "gemini-api-key") {
|
||||||
|
const key = guardCancel(
|
||||||
|
await text({
|
||||||
|
message: "Enter Gemini API key",
|
||||||
|
validate: (value) => (value?.trim() ? undefined : "Required"),
|
||||||
|
}),
|
||||||
|
runtime,
|
||||||
|
);
|
||||||
|
await setGeminiApiKey(String(key).trim());
|
||||||
|
next = applyAuthProfileConfig(next, {
|
||||||
|
profileId: "google:default",
|
||||||
|
provider: "google",
|
||||||
|
mode: "api_key",
|
||||||
|
});
|
||||||
} else if (authChoice === "apiKey") {
|
} else if (authChoice === "apiKey") {
|
||||||
const key = guardCancel(
|
const key = guardCancel(
|
||||||
await text({
|
await text({
|
||||||
|
|||||||
@@ -33,6 +33,19 @@ export async function setAnthropicApiKey(key: string, agentDir?: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function setGeminiApiKey(key: string, agentDir?: string) {
|
||||||
|
// Write to the multi-agent path so gateway finds credentials on startup
|
||||||
|
upsertAuthProfile({
|
||||||
|
profileId: "google:default",
|
||||||
|
credential: {
|
||||||
|
type: "api_key",
|
||||||
|
provider: "google",
|
||||||
|
key,
|
||||||
|
},
|
||||||
|
agentDir: agentDir ?? resolveDefaultAgentDir(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function applyAuthProfileConfig(
|
export function applyAuthProfileConfig(
|
||||||
cfg: ClawdbotConfig,
|
cfg: ClawdbotConfig,
|
||||||
params: {
|
params: {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import {
|
|||||||
applyAuthProfileConfig,
|
applyAuthProfileConfig,
|
||||||
applyMinimaxConfig,
|
applyMinimaxConfig,
|
||||||
setAnthropicApiKey,
|
setAnthropicApiKey,
|
||||||
|
setGeminiApiKey,
|
||||||
} from "./onboard-auth.js";
|
} from "./onboard-auth.js";
|
||||||
import {
|
import {
|
||||||
applyWizardMetadata,
|
applyWizardMetadata,
|
||||||
@@ -119,6 +120,19 @@ export async function runNonInteractiveOnboarding(
|
|||||||
provider: "anthropic",
|
provider: "anthropic",
|
||||||
mode: "api_key",
|
mode: "api_key",
|
||||||
});
|
});
|
||||||
|
} else if (authChoice === "gemini-api-key") {
|
||||||
|
const key = opts.geminiApiKey?.trim();
|
||||||
|
if (!key) {
|
||||||
|
runtime.error("Missing --gemini-api-key");
|
||||||
|
runtime.exit(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await setGeminiApiKey(key);
|
||||||
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
||||||
|
profileId: "google:default",
|
||||||
|
provider: "google",
|
||||||
|
mode: "api_key",
|
||||||
|
});
|
||||||
} else if (authChoice === "claude-cli") {
|
} else if (authChoice === "claude-cli") {
|
||||||
const store = ensureAuthProfileStore(undefined, {
|
const store = ensureAuthProfileStore(undefined, {
|
||||||
allowKeychainPrompt: false,
|
allowKeychainPrompt: false,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export type AuthChoice =
|
|||||||
| "codex-cli"
|
| "codex-cli"
|
||||||
| "antigravity"
|
| "antigravity"
|
||||||
| "apiKey"
|
| "apiKey"
|
||||||
|
| "gemini-api-key"
|
||||||
| "minimax"
|
| "minimax"
|
||||||
| "skip";
|
| "skip";
|
||||||
export type GatewayAuthChoice = "off" | "token" | "password";
|
export type GatewayAuthChoice = "off" | "token" | "password";
|
||||||
@@ -24,6 +25,7 @@ export type OnboardOptions = {
|
|||||||
nonInteractive?: boolean;
|
nonInteractive?: boolean;
|
||||||
authChoice?: AuthChoice;
|
authChoice?: AuthChoice;
|
||||||
anthropicApiKey?: string;
|
anthropicApiKey?: string;
|
||||||
|
geminiApiKey?: string;
|
||||||
gatewayPort?: number;
|
gatewayPort?: number;
|
||||||
gatewayBind?: GatewayBind;
|
gatewayBind?: GatewayBind;
|
||||||
gatewayAuth?: GatewayAuthChoice;
|
gatewayAuth?: GatewayAuthChoice;
|
||||||
|
|||||||
Reference in New Issue
Block a user