UNPKG

@earendil-works/pi-coding-agent

Version:

Coding agent CLI with read, bash, edit, write tools and session management

127 lines (122 loc) • 6.04 kB
import { APP_NAME } from "../config.js"; export class AuthCommandError extends Error { } const AUTH_COMMAND_USAGE = { check: `${APP_NAME} auth check --provider <provider> [--json] [--credentials] [--no-refresh]`, api_key: `${APP_NAME} auth print-api-key --provider <provider> [--model <model>]`, bearer_token: `${APP_NAME} auth print-bearer-token --provider <provider> [--model <model>] [--min-expiry <duration>]`, }; export function getAuthCommandName(kind) { return kind === "check" ? "auth check" : kind === "api_key" ? "auth print-api-key" : "auth print-bearer-token"; } export function getAuthCommandUsage(kind) { return AUTH_COMMAND_USAGE[kind]; } export function isAuthCommandHelp(args) { return (args[0] === "auth" && (args[1] === undefined || args[1] === "help" || args.includes("--help") || args.includes("-h"))); } export function printAuthCommandHelp() { console.log(`Usage: pi auth login <provider> [--api-key] [--no-browser] pi auth logout <provider> pi auth print-api-key [--provider <provider>] [--model <model>] pi auth print-bearer-token [--provider <provider>] [--model <model>] [--min-expiry <duration>] pi auth check [--provider <provider>] [--model <model>] [--json] [--credentials] [--no-refresh] Log in to and out of model providers, print their credentials for external clients, or check that they are ready. Credentials are stored in ~/.pi/agent/auth.json. Commands: login <provider> Sign in with an account in the browser, or save an API key, then exit logout <provider> Remove the stored credentials; environment variables and models.json stay print-api-key Print the resolved API key print-bearer-token Print a resolved OAuth bearer token (refreshes if expired) check Print ready, not_ready, or invalid; exit with 0, 1, or 2 Options for print-api-key, print-bearer-token, and check (at least one is required): --provider <provider> Resolve credentials for a provider --model <model> Resolve credentials from a model Options for login: --api-key Save an API key instead of signing in with an account --no-browser Do not open a browser; use another sign-in method, e.g. device code Other options: --min-expiry <duration> Minimum remaining token lifetime for print-bearer-token, e.g. 30m or 1h --json Print the check result as JSON --credentials Emit the credential from check, or include it in JSON output --no-refresh Do not refresh expired OAuth credentials during check`); } export function parseAuthCommand(args) { if (args[0] !== "auth") return undefined; const kind = args[1] === "check" ? "check" : args[1] === "print-api-key" ? "api_key" : args[1] === "print-bearer-token" ? "bearer_token" : undefined; if (!kind) { throw new AuthCommandError(`Unknown auth command "${args[1] ?? ""}". Use "${APP_NAME} auth login", "${APP_NAME} auth logout", "${APP_NAME} auth print-api-key", "${APP_NAME} auth print-bearer-token", or "${APP_NAME} auth check".`); } const commandArgs = []; let json = false; let credentials = false; let noRefresh = false; let minExpiryMs; for (let index = 2; index < args.length; index++) { const arg = args[index]; if (arg === "--min-expiry") { if (kind !== "bearer_token") throw new AuthCommandError("--min-expiry is only supported by print-bearer-token"); const value = args[++index]; const match = value ? /^(\d+)(ms|s|m|h)$/iu.exec(value) : undefined; if (!match) throw new AuthCommandError("--min-expiry must use a duration such as 30m or 1h"); const amount = Number(match[1]); const unit = match[2]; minExpiryMs = amount * (unit === "ms" ? 1 : unit === "s" ? 1_000 : unit === "m" ? 60_000 : 3_600_000); continue; } if (arg === "--json" || arg === "--credentials" || arg === "--no-refresh") { if (kind !== "check") throw new AuthCommandError(`${arg} is only supported by auth check`); if (arg === "--json") json = true; else if (arg === "--credentials") credentials = true; else noRefresh = true; continue; } commandArgs.push(arg); } return minExpiryMs === undefined ? { kind, args: commandArgs, json, credentials, noRefresh } : { kind, args: commandArgs, json, credentials, noRefresh, minExpiryMs }; } export function validateAuthCommandArgs(args, kind) { const provider = args.provider?.trim() || undefined; const model = args.model?.trim() || undefined; if (args.unknownFlags.size > 0) { const option = args.unknownFlags.keys().next().value; throw new AuthCommandError(`Unknown option --${option} for "${getAuthCommandName(kind)}".`); } if (args.apiKey !== undefined || args.messages.length > 0 || args.fileArgs.length > 0) { throw new AuthCommandError("Auth commands only accept --provider and --model"); } if (kind === "check") { if (!provider && !model) { throw new AuthCommandError("Auth checks require --provider <provider> or --model <model>"); } return { provider, model }; } if (!provider && !model) { throw new AuthCommandError("Credential printing requires --provider <provider> or --model <model>"); } return { provider, model }; } export function getAuthCredential(auth) { if (auth?.auth.apiKey) return auth.auth.apiKey; const authorization = Object.entries(auth?.auth.headers ?? {}).find(([name]) => name.toLowerCase() === "authorization")?.[1]; return typeof authorization === "string" ? /^Bearer\s+(.+)$/iu.exec(authorization)?.[1] : undefined; } //# sourceMappingURL=auth-command.js.map