UNPKG

@earendil-works/pi-coding-agent

Version:

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

116 lines (115 loc) 6.19 kB
import { resolveCliModel } from "../core/model-resolver.js"; const DEFAULT_BEARER_TOKEN_MIN_EXPIRY_MS = 30 * 60_000; export class CredentialPrintError extends Error { } export function isCredentialPrintHelp(args) { return (args[0] === "auth" && (args[1] === undefined || args[1] === "help" || args[1] === "--help" || args[1] === "-h")); } export function printCredentialPrintHelp() { console.log(`Usage: pi auth print-api-key --model <model> [--provider <provider>] pi auth print-bearer-token --model <model> [--provider <provider>] [--min-expiry <duration>] Prints the configured credential alone on stdout. Provider inference uses configured credentials; specify --provider to select explicitly. Bearer tokens have a 30-minute minimum expiry by default. --min-expiry accepts ms, s, m, or h (for example, 30m).`); } /** Parse the small, extensible `pi auth` command surface before normal startup. */ export function parseCredentialPrintCommand(args) { if (args[0] !== "auth") return undefined; const kind = args[1] === "print-api-key" ? "api_key" : args[1] === "print-bearer-token" ? "bearer_token" : undefined; if (!kind) { throw new CredentialPrintError(`Unknown auth command "${args[1] ?? ""}". Use "pi auth print-api-key" or "pi auth print-bearer-token".`); } const commandArgs = []; let minExpiryMs; for (let index = 2; index < args.length; index++) { if (args[index] !== "--min-expiry") { commandArgs.push(args[index]); continue; } if (kind !== "bearer_token") { throw new CredentialPrintError("--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 CredentialPrintError("--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); } return minExpiryMs === undefined ? { kind, args: commandArgs } : { kind, args: commandArgs, minExpiryMs }; } export function validateCredentialPrintArgs(args) { if (!args.model?.trim()) { throw new CredentialPrintError("Credential printing requires --model <model>"); } if (args.apiKey !== undefined) { throw new CredentialPrintError("Credential printing reads configured credentials; --api-key is not supported"); } if (args.messages.length > 0 || args.fileArgs.length > 0 || args.unknownFlags.size > 0) { throw new CredentialPrintError("Credential printing only accepts --provider and --model"); } } /** * Resolve one request credential for a specific provider/model pair. * * This intentionally calls ModelRuntime.getAuth(), which refreshes and persists * OAuth credentials with less than five minutes remaining through the normal request-auth path. */ export async function resolveCredentialForPrint(args, modelRuntime, kind, minExpiryMs) { validateCredentialPrintArgs(args); const credentialTypes = new Map((await modelRuntime.listCredentials()).map((credential) => [credential.providerId, credential.type])); const models = []; if (args.provider) { const resolved = resolveCliModel({ cliProvider: args.provider, cliModel: args.model, modelRuntime }); if (resolved.error || !resolved.model) { throw new CredentialPrintError(resolved.error ?? "Unable to resolve the requested provider/model"); } models.push(resolved.model); } else { for (const provider of modelRuntime.getProviders()) { if (!credentialTypes.has(provider.id)) continue; const resolved = resolveCliModel({ cliProvider: provider.id, cliModel: args.model, modelRuntime }); if (resolved.model && !resolved.error && !resolved.warning?.includes("Using custom model id")) { models.push(resolved.model); } } if (models.length === 0) { throw new CredentialPrintError(`Model "${args.model}" not found. Use --list-models to see available models.`); } } const credentials = []; for (const model of models) { const type = credentialTypes.get(model.provider); if (kind === "api_key" && type === "oauth") continue; if (kind === "bearer_token" && type !== "oauth") continue; const auth = await modelRuntime.getAuth(model, kind === "bearer_token" ? { minOAuthValidityMs: minExpiryMs ?? DEFAULT_BEARER_TOKEN_MIN_EXPIRY_MS } : undefined); const authorization = Object.entries(auth?.auth.headers ?? {}).find(([name]) => name.toLowerCase() === "authorization")?.[1]; const bearerToken = typeof authorization === "string" ? /^Bearer\s+(.+)$/iu.exec(authorization)?.[1] : undefined; const value = kind === "bearer_token" ? (auth?.auth.apiKey ?? bearerToken) : auth?.auth.apiKey; if (value) credentials.push({ providerId: model.provider, value }); } if (credentials.length === 1) return credentials[0].value; if (credentials.length === 0) { const providerId = models[0]?.provider; const type = providerId ? credentialTypes.get(providerId) : undefined; if (args.provider && kind === "api_key" && type === "oauth") { throw new CredentialPrintError(`Provider "${providerId}" is configured with OAuth, not an API key`); } if (args.provider && kind === "bearer_token" && type !== "oauth") { throw new CredentialPrintError(`Provider "${providerId}" is not configured with an OAuth bearer token`); } throw new CredentialPrintError(`No usable ${kind === "api_key" ? "API key" : "OAuth bearer token"} is configured`); } throw new CredentialPrintError(`Model "${args.model}" has multiple configured providers (${credentials.map(({ providerId }) => providerId).join(", ")}). Specify --provider.`); } //# sourceMappingURL=credential-print.js.map