UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

224 lines (223 loc) 8.67 kB
import { r as lowercasePreservingWhitespace } from "./string-coerce-mnp54Vah.js"; import "./string-coerce-runtime-CEGJWkQ_.js"; import { n as CLIENT_ID_KEYS, r as CLIENT_SECRET_KEYS } from "./oauth.shared-BD6M390i.js"; import { existsSync, readFileSync, readdirSync, realpathSync } from "node:fs"; import { delimiter, dirname, join } from "node:path"; //#region extensions/google/oauth.credentials.ts const defaultFs = { existsSync, readFileSync, realpathSync, readdirSync }; let credentialFs = defaultFs; const GEMINI_CLI_TREE_SEARCH_DEPTH = 10; function resolveEnv(keys) { for (const key of keys) { const value = process.env[key]?.trim(); if (value) return value; } } let cachedGeminiCliCredentials = null; let geminiCliCredentialExtractError = null; function clearCredentialsCache() { cachedGeminiCliCredentials = null; geminiCliCredentialExtractError = null; } function setOAuthCredentialsFsForTest(overrides) { credentialFs = overrides ? { ...defaultFs, ...overrides } : defaultFs; } function extractGeminiCliCredentials() { if (cachedGeminiCliCredentials) return cachedGeminiCliCredentials; geminiCliCredentialExtractError = null; const diagnostics = { searchedPaths: [], recursiveSearchRoots: [], parseFailures: [], readErrors: [] }; try { const geminiPath = findInPath("gemini"); if (!geminiPath) { geminiCliCredentialExtractError = "Gemini CLI binary was not found in PATH during OAuth credential extraction."; return null; } const resolvedPath = credentialFs.realpathSync(geminiPath); const geminiCliDirs = resolveGeminiCliDirs(geminiPath, resolvedPath); for (const geminiCliDir of geminiCliDirs) { const directCredentials = readGeminiCliCredentialsFromKnownPaths(geminiCliDir, diagnostics); if (directCredentials) { cachedGeminiCliCredentials = directCredentials; return directCredentials; } const bundledCredentials = readGeminiCliCredentialsFromBundle(geminiCliDir, diagnostics); if (bundledCredentials) { cachedGeminiCliCredentials = bundledCredentials; return bundledCredentials; } diagnostics.recursiveSearchRoots.push(geminiCliDir); const discoveredCredentials = findGeminiCliCredentialsInTree(geminiCliDir, GEMINI_CLI_TREE_SEARCH_DEPTH, diagnostics); if (discoveredCredentials) { cachedGeminiCliCredentials = discoveredCredentials; return discoveredCredentials; } } geminiCliCredentialExtractError = formatGeminiCliCredentialExtractError({ geminiPath, resolvedPath, diagnostics }); } catch (error) { geminiCliCredentialExtractError = `Unexpected error while extracting Gemini CLI OAuth credentials: ${formatError(error)}`; } return null; } function formatGeminiCliCredentialExtractError({ geminiPath, resolvedPath, diagnostics }) { const prefix = [ "Found Gemini CLI in PATH, but could not extract OAuth credentials.", `geminiPath=${geminiPath}`, `resolvedPath=${resolvedPath}` ]; if (diagnostics.parseFailures.length > 0) return [ ...prefix, "Candidate credential files did not contain a parseable OAuth client id/secret.", `candidates=${diagnostics.parseFailures.join(", ")}` ].join(" "); if (diagnostics.readErrors.length > 0) return [ ...prefix, "Unexpected errors occurred while reading candidate credential files/directories.", `errors=${diagnostics.readErrors.join(", ")}` ].join(" "); return [ ...prefix, "Could not locate oauth2.js or bundled credential source.", `searched=${diagnostics.searchedPaths.join(", ") || "(none)"}`, `recursiveSearchRoots=${diagnostics.recursiveSearchRoots.join(", ") || "(none)"}`, `recursiveSearchDepth=${GEMINI_CLI_TREE_SEARCH_DEPTH}` ].join(" "); } function formatError(error) { return error instanceof Error ? error.message : String(error); } function resolveGeminiCliDirs(geminiPath, resolvedPath) { const binDir = dirname(geminiPath); const candidates = [ dirname(dirname(resolvedPath)), join(dirname(resolvedPath), "node_modules", "@google", "gemini-cli"), join(binDir, "node_modules", "@google", "gemini-cli"), join(dirname(binDir), "node_modules", "@google", "gemini-cli"), join(dirname(binDir), "lib", "node_modules", "@google", "gemini-cli") ]; const deduped = []; const seen = /* @__PURE__ */ new Set(); for (const candidate of candidates) for (const searchDir of resolveGeminiCliSearchDirs(candidate)) { const key = process.platform === "win32" ? lowercasePreservingWhitespace(searchDir.replace(/\\/g, "/")) : searchDir; if (seen.has(key)) continue; seen.add(key); deduped.push(searchDir); } return deduped; } function resolveGeminiCliSearchDirs(candidate) { return [ candidate, join(candidate, "node_modules", "@google", "gemini-cli"), join(candidate, "lib", "node_modules", "@google", "gemini-cli") ].filter(looksLikeGeminiCliDir); } function looksLikeGeminiCliDir(candidate) { return credentialFs.existsSync(join(candidate, "package.json")) || credentialFs.existsSync(join(candidate, "node_modules", "@google", "gemini-cli-core")); } function findInPath(name) { const exts = process.platform === "win32" ? [ ".cmd", ".bat", ".exe", "" ] : [""]; for (const dir of (process.env.PATH ?? "").split(delimiter)) for (const ext of exts) { const path = join(dir, name + ext); if (credentialFs.existsSync(path)) return path; } return null; } function readGeminiCliCredentialsFile(path, diagnostics) { try { const credentials = parseGeminiCliCredentials(credentialFs.readFileSync(path, "utf8")); if (!credentials) diagnostics.parseFailures.push(path); return credentials; } catch (error) { diagnostics.readErrors.push(`${path}: ${formatError(error)}`); return null; } } function parseGeminiCliCredentials(content) { const clientId = content.match(/OAUTH_CLIENT_ID\s*=\s*["']([^"']+)["']/)?.[1] ?? content.match(/(\d+-[a-z0-9]+\.apps\.googleusercontent\.com)/)?.[1]; const clientSecret = content.match(/OAUTH_CLIENT_SECRET\s*=\s*["']([^"']+)["']/)?.[1] ?? content.match(/(GOCSPX-[A-Za-z0-9_-]+)/)?.[1]; if (!clientId || !clientSecret) return null; return { clientId, clientSecret }; } function readGeminiCliCredentialsFromKnownPaths(geminiCliDir, diagnostics) { const searchPaths = [join(geminiCliDir, "node_modules", "@google", "gemini-cli-core", "dist", "src", "code_assist", "oauth2.js"), join(geminiCliDir, "node_modules", "@google", "gemini-cli-core", "dist", "code_assist", "oauth2.js")]; diagnostics.searchedPaths.push(...searchPaths); for (const path of searchPaths) { if (!credentialFs.existsSync(path)) continue; const credentials = readGeminiCliCredentialsFile(path, diagnostics); if (credentials) return credentials; } return null; } function readGeminiCliCredentialsFromBundle(geminiCliDir, diagnostics) { const bundleDir = join(geminiCliDir, "bundle"); if (!credentialFs.existsSync(bundleDir)) return null; try { for (const entry of credentialFs.readdirSync(bundleDir, { withFileTypes: true })) { if (!entry.isFile() || !entry.name.endsWith(".js")) continue; const credentials = readGeminiCliCredentialsFile(join(bundleDir, entry.name), diagnostics); if (credentials) return credentials; } } catch (error) { diagnostics.readErrors.push(`${bundleDir}: ${formatError(error)}`); } return null; } function findGeminiCliCredentialsInTree(dir, depth, diagnostics) { if (depth <= 0) return null; try { for (const entry of credentialFs.readdirSync(dir, { withFileTypes: true })) { const path = join(dir, entry.name); if (entry.isFile() && entry.name === "oauth2.js") { const credentials = readGeminiCliCredentialsFile(path, diagnostics); if (credentials) return credentials; continue; } if (entry.isDirectory() && !entry.name.startsWith(".")) { const found = findGeminiCliCredentialsInTree(path, depth - 1, diagnostics); if (found) return found; } } } catch (error) { diagnostics.readErrors.push(`${dir}: ${formatError(error)}`); } return null; } function resolveOAuthClientConfig() { const envClientId = resolveEnv(CLIENT_ID_KEYS); const envClientSecret = resolveEnv(CLIENT_SECRET_KEYS); if (envClientId) return { clientId: envClientId, clientSecret: envClientSecret }; const extracted = extractGeminiCliCredentials(); if (extracted) return extracted; const detail = geminiCliCredentialExtractError ? ` Details: ${geminiCliCredentialExtractError}` : ""; throw new Error(`Gemini CLI not found. Install it first: brew install gemini-cli (or npm install -g @google/gemini-cli), or set GEMINI_CLI_OAUTH_CLIENT_ID.${detail}`); } //#endregion export { setOAuthCredentialsFsForTest as i, extractGeminiCliCredentials as n, resolveOAuthClientConfig as r, clearCredentialsCache as t };