@kenkaiiii/gg-core 4.4.0 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-USAVZGPP.js → chunk-74Z6I5V7.js} +34 -4
- package/dist/chunk-74Z6I5V7.js.map +1 -0
- package/dist/index.cjs +319 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -2
- package/dist/index.d.ts +66 -2
- package/dist/index.js +276 -7
- package/dist/index.js.map +1 -1
- package/dist/model-registry.cjs +35 -3
- package/dist/model-registry.cjs.map +1 -1
- package/dist/model-registry.d.cts +21 -1
- package/dist/model-registry.d.ts +21 -1
- package/dist/model-registry.js +5 -1
- package/package.json +2 -2
- package/dist/chunk-USAVZGPP.js.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/thinking-level.ts","../src/logger.ts","../src/file-lock.ts","../src/claude-code-version.ts","../src/auth-storage.ts","../src/oauth/anthropic.ts","../src/oauth/pkce.ts","../src/oauth/openai.ts","../src/oauth/gemini.ts","../src/telegram.ts","../src/voice-transcriber.ts","../src/auto-update.ts"],"sourcesContent":["import type { Provider, ThinkingLevel } from \"@kenkaiiii/gg-ai\";\nimport { getMaxThinkingLevel } from \"./model-registry.js\";\n\nconst OPENAI_GPT_THINKING_LEVELS: readonly ThinkingLevel[] = [\"medium\", \"high\", \"xhigh\"];\nconst ANTHROPIC_OPUS_48_47_THINKING_LEVELS: readonly ThinkingLevel[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\",\n \"max\",\n];\nconst ANTHROPIC_ADAPTIVE_THINKING_LEVELS: readonly ThinkingLevel[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"max\",\n];\n\nfunction isOpenAIGptModel(provider: Provider, model: string): boolean {\n return provider === \"openai\" && model.startsWith(\"gpt-\");\n}\n\nfunction isAnthropicOpus48Or47Model(provider: Provider, model: string): boolean {\n return provider === \"anthropic\" && /opus-4-8|opus-4-7/.test(model);\n}\n\nfunction isAnthropicAdaptiveModel(provider: Provider, model: string): boolean {\n return provider === \"anthropic\" && /opus-4-8|opus-4-7|opus-4-6|sonnet-4-6/.test(model);\n}\n\nexport function getSupportedThinkingLevels(\n provider: Provider,\n model: string,\n): readonly ThinkingLevel[] {\n const maxLevel = getMaxThinkingLevel(model);\n if (isAnthropicAdaptiveModel(provider, model)) {\n const levels = isAnthropicOpus48Or47Model(provider, model)\n ? ANTHROPIC_OPUS_48_47_THINKING_LEVELS\n : ANTHROPIC_ADAPTIVE_THINKING_LEVELS;\n const maxIndex = levels.indexOf(maxLevel);\n if (maxIndex === -1) return [\"low\", \"medium\", \"high\"];\n return levels.slice(0, maxIndex + 1);\n }\n\n if (!isOpenAIGptModel(provider, model)) return [maxLevel];\n\n const maxIndex = OPENAI_GPT_THINKING_LEVELS.indexOf(maxLevel);\n if (maxIndex === -1) return [\"medium\"];\n return OPENAI_GPT_THINKING_LEVELS.slice(0, maxIndex + 1);\n}\n\nexport function isThinkingLevelSupported(\n provider: Provider,\n model: string,\n level: ThinkingLevel,\n): boolean {\n return getSupportedThinkingLevels(provider, model).includes(level);\n}\n\nexport function getNextThinkingLevel(\n provider: Provider,\n model: string,\n current: ThinkingLevel | undefined,\n): ThinkingLevel | undefined {\n const supportedLevels = getSupportedThinkingLevels(provider, model);\n const shouldCycleLevels =\n isOpenAIGptModel(provider, model) || isAnthropicAdaptiveModel(provider, model);\n if (!shouldCycleLevels) {\n return current ? undefined : supportedLevels[0];\n }\n\n if (!current) return supportedLevels[0];\n const index = supportedLevels.indexOf(current);\n if (index === -1) return supportedLevels[0];\n return supportedLevels[index + 1];\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { randomBytes } from \"node:crypto\";\n\nexport type LogLevel = \"INFO\" | \"ERROR\" | \"WARN\" | \"DEBUG\";\n\n// Cross-session log retention: the log is appended across launches so you can\n// grep back through prior sessions. Rotated at MAX_BYTES to keep it bounded; we\n// keep one generation (debug.log.1) — enough to survive one rotation's worth of\n// scrollback while bounding disk usage.\nconst MAX_BYTES = 10 * 1024 * 1024; // 10 MB\n\nlet fd: number | null = null;\nlet sessionId = \"\";\nlet appName = \"app\";\nlet cleanups: (() => void)[] = [];\n\nfunction rotateIfNeeded(filePath: string): void {\n try {\n const st = fs.statSync(filePath);\n if (st.size < MAX_BYTES) return;\n const rotated = `${filePath}.1`;\n // Replace prior rotation (fs.renameSync overwrites on POSIX; on Windows it\n // fails if dest exists, so unlink first defensively).\n try {\n fs.unlinkSync(rotated);\n } catch {\n // No prior rotation\n }\n fs.renameSync(filePath, rotated);\n } catch {\n // Log file doesn't exist yet or stat failed — nothing to rotate\n }\n}\n\n/**\n * Open the debug log in append mode, tagging this process with a session id and\n * remembering `name` for the shutdown line. Idempotent — re-calling while open\n * is a no-op. Returns true only when it *newly* opened the file (so callers can\n * write a one-time startup line); returns false if already open or if the file\n * could not be opened.\n */\nexport function openLog(filePath: string, name: string): boolean {\n if (fd !== null) return false;\n appName = name;\n try {\n fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });\n } catch {\n // Directory may already exist or be uncreatable — fall through to open\n }\n rotateIfNeeded(filePath);\n try {\n fd = fs.openSync(filePath, \"a\");\n } catch {\n // Can't open log file — silently disable logging\n return false;\n }\n sessionId = randomBytes(4).toString(\"hex\");\n // Visible separator between sessions when back-reading the log.\n try {\n fs.writeSync(fd, \"\\n\");\n } catch {\n // Write failed — proceed without the separator\n }\n return true;\n}\n\n/** Session identifier included on every log line as `sid=<id>`. */\nexport function getSessionId(): string {\n return sessionId;\n}\n\n/** True if the logger has an open file descriptor. */\nexport function isLoggerOpen(): boolean {\n return fd !== null;\n}\n\n/** Write a timestamped log line. No-op if the logger is not open. */\nexport function log(\n level: LogLevel,\n category: string,\n message: string,\n data?: Record<string, unknown>,\n): void {\n if (fd === null) return;\n const ts = new Date().toISOString();\n let line = `[${ts}] [sid=${sessionId}] [${level}] [${category}] ${message}`;\n if (data) {\n const pairs = Object.entries(data)\n .map(([k, v]) => `${k}=${typeof v === \"string\" ? v : JSON.stringify(v)}`)\n .join(\" \");\n if (pairs) line += ` ${pairs}`;\n }\n line += \"\\n\";\n try {\n fs.writeSync(fd, line);\n } catch {\n // Write failed — don't crash\n }\n}\n\n/**\n * Register a cleanup callback (e.g. an EventBus unsubscriber) to run when the\n * logger closes. Lets app-side bridges hook into the shared lifecycle without\n * the core needing to know about app types.\n */\nexport function registerLogCleanup(fn: () => void): void {\n cleanups.push(fn);\n}\n\n/**\n * Write a shutdown line (unless suppressed), close the file descriptor, and run\n * any registered cleanups.\n */\nexport function closeLogger(opts?: { shutdownLine?: boolean }): void {\n if (fd === null) return;\n if (opts?.shutdownLine !== false) log(\"INFO\", \"shutdown\", `${appName} shutting down`);\n try {\n fs.closeSync(fd);\n } catch {\n // Ignore close errors\n }\n fd = null;\n for (const unsub of cleanups) unsub();\n cleanups = [];\n}\n","import fs from \"node:fs/promises\";\nimport { setTimeout } from \"node:timers/promises\";\n\nconst STALE_TIMEOUT_MS = 10_000; // Lock is stale after 10s\nconst RETRY_INTERVAL_MS = 50; // Retry every 50ms\nconst MAX_WAIT_MS = 5_000; // Give up after 5s\n\ninterface LockInfo {\n pid: number;\n timestamp: number;\n}\n\n/**\n * Simple file-based lock with PID tracking and stale detection.\n * Uses atomic file creation (wx flag) to prevent races.\n */\nexport async function withFileLock<T>(filePath: string, fn: () => Promise<T>): Promise<T> {\n const lockPath = filePath + \".lock\";\n await acquireLock(lockPath);\n try {\n return await fn();\n } finally {\n await releaseLock(lockPath);\n }\n}\n\nasync function acquireLock(lockPath: string): Promise<void> {\n const startTime = Date.now();\n\n while (true) {\n try {\n // O_EXCL: fail if file exists — atomic lock acquisition\n const info: LockInfo = { pid: process.pid, timestamp: Date.now() };\n await fs.writeFile(lockPath, JSON.stringify(info), { flag: \"wx\" });\n return; // Lock acquired\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") throw err;\n\n // Lock file exists — check if it's stale\n try {\n const content = await fs.readFile(lockPath, \"utf-8\");\n const info = JSON.parse(content) as LockInfo;\n\n // Check if the holding process is still alive\n const isProcessAlive = isAlive(info.pid);\n const isStale = Date.now() - info.timestamp > STALE_TIMEOUT_MS;\n\n if (!isProcessAlive || isStale) {\n // Stale lock — remove and retry\n await fs.unlink(lockPath).catch(() => {});\n continue;\n }\n } catch {\n // Corrupt lock file — remove and retry\n await fs.unlink(lockPath).catch(() => {});\n continue;\n }\n\n // Lock is held by a live process — wait and retry\n if (Date.now() - startTime > MAX_WAIT_MS) {\n // Timeout — force break the lock (better than deadlocking)\n await fs.unlink(lockPath).catch(() => {});\n continue;\n }\n\n await setTimeout(RETRY_INTERVAL_MS);\n }\n }\n}\n\nasync function releaseLock(lockPath: string): Promise<void> {\n await fs.unlink(lockPath).catch(() => {});\n}\n\nfunction isAlive(pid: number): boolean {\n try {\n process.kill(pid, 0); // Signal 0 = check existence without killing\n return true;\n } catch (err) {\n // EPERM = process exists but belongs to a different user — still alive\n if ((err as NodeJS.ErrnoException).code === \"EPERM\") return true;\n // ESRCH = no such process — it's dead\n return false;\n }\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getAppPaths } from \"./paths.js\";\nimport { log } from \"./logger.js\";\n\n// Anthropic's OAuth edge rejects requests whose claude-cli UA version lags too\n// far behind the actual Claude Code release. Resolve dynamically from the npm\n// registry so we never ship a stale-version time bomb.\nconst NPM_LATEST_URL = \"https://registry.npmjs.org/@anthropic-ai/claude-code/latest\";\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000;\nconst FETCH_TIMEOUT_MS = 3000;\n// Last known good version at publish time. Used only when the npm fetch fails\n// and no on-disk cache exists (e.g. first run on an offline machine). Keep\n// reasonably current — bump on each ggcoder release.\nconst FALLBACK_VERSION = \"2.1.88\";\n\ntype CachedVersion = { version: string; fetchedAt: number };\n\nlet memoryCache: { version: string; expiresAt: number } | null = null;\nlet inflight: Promise<string> | null = null;\n\nfunction cachePath(): string {\n return path.join(getAppPaths().agentDir, \"claude-code-version.json\");\n}\n\nasync function readDiskCache(): Promise<CachedVersion | null> {\n try {\n const raw = await fs.readFile(cachePath(), \"utf-8\");\n const parsed = JSON.parse(raw) as CachedVersion;\n if (typeof parsed.version === \"string\" && typeof parsed.fetchedAt === \"number\") {\n return parsed;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nasync function writeDiskCache(data: CachedVersion): Promise<void> {\n try {\n await fs.mkdir(getAppPaths().agentDir, { recursive: true, mode: 0o700 });\n await fs.writeFile(cachePath(), JSON.stringify(data), { mode: 0o600 });\n } catch (err) {\n log(\n \"WARN\",\n \"claude-code-version\",\n `Failed to write cache: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n}\n\nasync function fetchLatest(): Promise<string | null> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const response = await fetch(NPM_LATEST_URL, { signal: controller.signal });\n if (!response.ok) return null;\n const data = (await response.json()) as { version?: unknown };\n if (typeof data.version === \"string\" && /^\\d/.test(data.version)) {\n return data.version;\n }\n return null;\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Resolve the current Claude Code release version for spoofing the claude-cli\n * User-Agent on OAuth and inference requests. Cached in-memory for the process\n * lifetime and on disk for 24h. Falls back to a hardcoded constant if the npm\n * registry is unreachable and no cache exists.\n */\nexport async function getClaudeCodeVersion(): Promise<string> {\n if (memoryCache && Date.now() < memoryCache.expiresAt) {\n return memoryCache.version;\n }\n if (inflight) return inflight;\n\n inflight = (async () => {\n const disk = await readDiskCache();\n const diskFresh = disk && Date.now() - disk.fetchedAt < CACHE_TTL_MS;\n if (disk && diskFresh) {\n memoryCache = { version: disk.version, expiresAt: Date.now() + CACHE_TTL_MS };\n return disk.version;\n }\n const fetched = await fetchLatest();\n if (fetched) {\n await writeDiskCache({ version: fetched, fetchedAt: Date.now() });\n memoryCache = { version: fetched, expiresAt: Date.now() + CACHE_TTL_MS };\n return fetched;\n }\n // npm unreachable — prefer stale disk cache over hardcoded fallback.\n const resolved = disk?.version ?? FALLBACK_VERSION;\n // Short TTL so we retry the npm fetch soon, but don't hammer it.\n memoryCache = { version: resolved, expiresAt: Date.now() + 5 * 60 * 1000 };\n log(\n \"WARN\",\n \"claude-code-version\",\n `Failed to fetch latest Claude Code version; using ${resolved}`,\n );\n return resolved;\n })();\n\n try {\n return await inflight;\n } finally {\n inflight = null;\n }\n}\n\n/** Build the User-Agent string Anthropic's OAuth + inference edges expect. */\nexport async function getClaudeCliUserAgent(): Promise<string> {\n const version = await getClaudeCodeVersion();\n return `claude-cli/${version} (external, cli)`;\n}\n","import fs from \"node:fs/promises\";\nimport crypto from \"node:crypto\";\nimport { getAppPaths } from \"./paths.js\";\nimport type { OAuthCredentials } from \"./oauth/types.js\";\nimport { refreshAnthropicToken } from \"./oauth/anthropic.js\";\nimport { refreshOpenAIToken } from \"./oauth/openai.js\";\nimport { refreshGeminiToken } from \"./oauth/gemini.js\";\nimport { withFileLock } from \"./file-lock.js\";\nimport { log } from \"./logger.js\";\n\ntype AuthData = Record<string, OAuthCredentials>;\n\nexport class AuthStorage {\n private data: AuthData = {};\n private filePath: string;\n private loaded = false;\n /** Per-provider lock to serialize concurrent refresh calls. */\n private refreshLocks = new Map<string, Promise<OAuthCredentials>>();\n\n constructor(filePath?: string) {\n this.filePath = filePath ?? getAppPaths().authFile;\n }\n\n /** Path to the on-disk auth file. Useful for status output. */\n get path(): string {\n return this.filePath;\n }\n\n /** List provider keys with stored credentials. */\n async listProviders(): Promise<string[]> {\n await this.ensureLoaded();\n return Object.keys(this.data);\n }\n\n /** True if credentials exist for `provider`. */\n async hasCredentials(provider: string): Promise<boolean> {\n await this.ensureLoaded();\n return Boolean(this.data[provider]);\n }\n\n async load(): Promise<void> {\n await withFileLock(this.filePath, async () => {\n try {\n const content = await fs.readFile(this.filePath, \"utf-8\");\n this.data = JSON.parse(content) as AuthData;\n log(\"INFO\", \"auth\", `Loaded credentials from ${this.filePath}`, {\n providers: Object.keys(this.data).join(\",\") || \"(none)\",\n });\n } catch (err) {\n this.data = {};\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") {\n log(\"INFO\", \"auth\", `No auth file found at ${this.filePath} (first run)`);\n } else {\n log(\n \"ERROR\",\n \"auth\",\n `Failed to load auth file: ${err instanceof Error ? err.message : String(err)}`,\n { path: this.filePath, code: code ?? \"unknown\" },\n );\n }\n }\n });\n this.loaded = true;\n }\n\n private async ensureLoaded(): Promise<void> {\n if (!this.loaded) await this.load();\n }\n\n async getCredentials(provider: string): Promise<OAuthCredentials | undefined> {\n await this.ensureLoaded();\n return this.data[provider];\n }\n\n async setCredentials(provider: string, creds: OAuthCredentials): Promise<void> {\n await this.ensureLoaded();\n this.data[provider] = creds;\n await this.save();\n }\n\n async clearCredentials(provider: string): Promise<void> {\n await this.ensureLoaded();\n delete this.data[provider];\n await this.save();\n }\n\n async clearAll(): Promise<void> {\n this.data = {};\n await this.save();\n }\n\n /**\n * Returns valid credentials, auto-refreshing if expired.\n * If `forceRefresh` is true, refreshes even if the token hasn't expired\n * (useful when the provider rejects a token with 401 before its stored expiry).\n * Throws if not logged in.\n */\n async resolveCredentials(\n provider: string,\n opts?: { forceRefresh?: boolean },\n ): Promise<OAuthCredentials> {\n await this.ensureLoaded();\n const creds = this.data[provider];\n if (!creds) {\n throw new NotLoggedInError(provider);\n }\n\n // GLM and Moonshot use static API keys — no refresh needed\n if (\n provider === \"glm\" ||\n provider === \"moonshot\" ||\n provider === \"xiaomi\" ||\n provider === \"minimax\" ||\n provider === \"deepseek\" ||\n provider === \"openrouter\"\n ) {\n return creds;\n }\n\n // Return if not expired and not force-refreshing\n if (!opts?.forceRefresh && Date.now() < creds.expiresAt) {\n return creds;\n }\n\n // Serialize concurrent refresh calls per provider to avoid races\n const existing = this.refreshLocks.get(provider);\n if (existing) return existing;\n\n const refreshPromise = withFileLock(this.filePath, async () => {\n // Re-read from disk in case another process refreshed while we waited for the lock\n try {\n const content = await fs.readFile(this.filePath, \"utf-8\");\n const freshData = JSON.parse(content) as AuthData;\n const freshCreds = freshData[provider];\n if (freshCreds && !opts?.forceRefresh && Date.now() < freshCreds.expiresAt) {\n // Another process already refreshed — use their token\n this.data[provider] = freshCreds;\n return freshCreds;\n }\n } catch {\n // Fall through to refresh\n }\n\n const refreshFn =\n provider === \"anthropic\"\n ? refreshAnthropicToken\n : provider === \"gemini\"\n ? refreshGeminiToken\n : refreshOpenAIToken;\n let refreshed: OAuthCredentials;\n try {\n refreshed = await refreshFn(creds.refreshToken);\n } catch (err) {\n // Refresh token revoked / expired / invalid → the stored creds are\n // unusable. Wipe them so the next launch surfaces a clean\n // NotLoggedInError instead of hitting the same dead refresh path\n // every time. The user must re-login.\n const msg = err instanceof Error ? err.message : String(err);\n const isAuthFailure =\n /\\((401|400)\\)/.test(msg) ||\n /invalid_grant|invalid_token|invalid.*refresh/i.test(msg) ||\n /unauthorized/i.test(msg);\n if (isAuthFailure) {\n delete this.data[provider];\n await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));\n throw new NotLoggedInError(provider);\n }\n throw err;\n }\n if (!refreshed.accountId && creds.accountId) {\n refreshed.accountId = creds.accountId;\n }\n if (!refreshed.projectId && creds.projectId) {\n refreshed.projectId = creds.projectId;\n }\n this.data[provider] = refreshed;\n // Write atomically (we already hold the file lock)\n await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));\n return refreshed;\n });\n\n this.refreshLocks.set(provider, refreshPromise);\n try {\n return await refreshPromise;\n } finally {\n this.refreshLocks.delete(provider);\n }\n }\n\n /**\n * Returns a valid access token, auto-refreshing if expired.\n * Throws if not logged in.\n */\n async resolveToken(provider: string): Promise<string> {\n const creds = await this.resolveCredentials(provider);\n return creds.accessToken;\n }\n\n private async save(): Promise<void> {\n await withFileLock(this.filePath, async () => {\n await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));\n });\n }\n}\n\n/**\n * Atomic file write using temp file + rename pattern.\n * Prevents partial/corrupt data if the process crashes mid-write.\n */\nasync function atomicWriteFile(filePath: string, content: string): Promise<void> {\n const tmpPath = `${filePath}.${process.pid}.${Date.now()}.${crypto.randomUUID().slice(0, 8)}.tmp`;\n try {\n await fs.writeFile(tmpPath, content, { encoding: \"utf-8\", mode: 0o600 });\n await fs.rename(tmpPath, filePath);\n } catch (err) {\n await fs.unlink(tmpPath).catch(() => {});\n throw err;\n }\n}\n\nexport class NotLoggedInError extends Error {\n provider: string;\n constructor(provider: string) {\n super(`Not logged in to ${provider}. Run \"ggcoder login\" to authenticate.`);\n this.name = \"NotLoggedInError\";\n this.provider = provider;\n }\n}\n","import crypto from \"node:crypto\";\nimport { generatePKCE } from \"./pkce.js\";\nimport { getClaudeCliUserAgent } from \"../claude-code-version.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks } from \"./types.js\";\n\nconst CLIENT_ID = atob(\"OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl\");\nconst AUTHORIZE_URL = \"https://claude.ai/oauth/authorize\";\n// Anthropic migrated OAuth from console.anthropic.com to platform.claude.com\n// in Claude Code v2.1.81+. Try the new endpoint first, fall back to the old one\n// so a transient outage on either edge doesn't wipe the user's credentials.\nconst TOKEN_URLS = [\n \"https://platform.claude.com/v1/oauth/token\",\n \"https://console.anthropic.com/v1/oauth/token\",\n];\nconst REDIRECT_URI = \"https://platform.claude.com/oauth/code/callback\";\nconst SCOPES =\n \"org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload\";\n\ntype TokenResponse = {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n};\n\nasync function postTokenRequest(\n body: Record<string, string>,\n label: string,\n): Promise<TokenResponse> {\n const encoded = JSON.stringify(body);\n // Claude Code identity. Anthropic's OAuth edge intermittently rejects\n // requests without a recognized claude-cli UA + oauth beta header. Resolve\n // the UA version dynamically so it tracks real Claude Code releases.\n const headers = {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": await getClaudeCliUserAgent(),\n \"anthropic-beta\": \"oauth-2025-04-20\",\n };\n let lastError: Error | null = null;\n for (const url of TOKEN_URLS) {\n let response: Response;\n try {\n response = await fetch(url, { method: \"POST\", headers, body: encoded });\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n continue;\n }\n if (response.ok) {\n return (await response.json()) as TokenResponse;\n }\n const text = await response.text();\n // 4xx is an authoritative auth failure (invalid_grant, invalid_client, etc.)\n // — don't paper over it by trying another endpoint, the result will be the\n // same and the caller relies on this signal to wipe stale creds.\n if (response.status >= 400 && response.status < 500) {\n throw new Error(`Anthropic ${label} failed (${response.status}): ${text}`);\n }\n lastError = new Error(`Anthropic ${label} failed (${response.status}): ${text}`);\n }\n throw lastError ?? new Error(`Anthropic ${label} failed: all endpoints unreachable`);\n}\n\nfunction toCredentials(data: TokenResponse): OAuthCredentials {\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n };\n}\n\nexport async function loginAnthropic(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const { verifier, challenge } = await generatePKCE();\n const state = crypto.randomBytes(16).toString(\"hex\");\n\n const params = new URLSearchParams({\n code: \"true\",\n client_id: CLIENT_ID,\n response_type: \"code\",\n redirect_uri: REDIRECT_URI,\n scope: SCOPES,\n code_challenge: challenge,\n code_challenge_method: \"S256\",\n state,\n });\n\n const authUrl = `${AUTHORIZE_URL}?${params}`;\n callbacks.onOpenUrl(authUrl);\n\n const raw = await callbacks.onPromptCode(\"Paste the code from the browser (format: code#state):\");\n\n const parts = raw.trim().split(\"#\");\n if (parts.length !== 2 || !parts[0] || parts[1] !== state) {\n throw new Error(\"Invalid code or state mismatch. Please try again.\");\n }\n\n return exchangeAnthropicCode(parts[0], parts[1], verifier);\n}\n\nasync function exchangeAnthropicCode(\n code: string,\n state: string,\n verifier: string,\n): Promise<OAuthCredentials> {\n const data = await postTokenRequest(\n {\n grant_type: \"authorization_code\",\n client_id: CLIENT_ID,\n code,\n state,\n redirect_uri: REDIRECT_URI,\n code_verifier: verifier,\n },\n \"token exchange\",\n );\n return toCredentials(data);\n}\n\nexport async function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials> {\n const data = await postTokenRequest(\n {\n grant_type: \"refresh_token\",\n client_id: CLIENT_ID,\n refresh_token: refreshToken,\n },\n \"token refresh\",\n );\n return toCredentials(data);\n}\n","function base64urlEncode(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=/g, \"\");\n}\n\nexport async function generatePKCE(): Promise<{ verifier: string; challenge: string }> {\n const verifierBytes = new Uint8Array(32);\n crypto.getRandomValues(verifierBytes);\n const verifier = base64urlEncode(verifierBytes);\n\n const data = new TextEncoder().encode(verifier);\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n const challenge = base64urlEncode(new Uint8Array(hashBuffer));\n\n return { verifier, challenge };\n}\n","import http from \"node:http\";\nimport crypto from \"node:crypto\";\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks } from \"./types.js\";\n\nconst CLIENT_ID = \"app_EMoamEEZ73f0CkXaXp7hrann\";\nconst AUTHORIZE_URL = \"https://auth.openai.com/oauth/authorize\";\nconst TOKEN_URL = \"https://auth.openai.com/oauth/token\";\nconst REDIRECT_URI = \"http://localhost:1455/auth/callback\";\nconst SCOPE = \"openid profile email offline_access api.connectors.read api.connectors.invoke\";\nconst JWT_CLAIM_PATH = \"https://api.openai.com/auth\";\n\nexport async function loginOpenAI(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const { verifier, challenge } = await generatePKCE();\n const state = crypto.randomBytes(16).toString(\"hex\");\n\n const url = new URL(AUTHORIZE_URL);\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"client_id\", CLIENT_ID);\n url.searchParams.set(\"redirect_uri\", REDIRECT_URI);\n url.searchParams.set(\"scope\", SCOPE);\n url.searchParams.set(\"code_challenge\", challenge);\n url.searchParams.set(\"code_challenge_method\", \"S256\");\n url.searchParams.set(\"state\", state);\n url.searchParams.set(\"id_token_add_organizations\", \"true\");\n url.searchParams.set(\"codex_cli_simplified_flow\", \"true\");\n url.searchParams.set(\"originator\", \"ggcoder\");\n\n let code: string;\n\n try {\n code = await loginWithServer(url.toString(), state, callbacks);\n } catch {\n // Fallback: manual code paste\n callbacks.onOpenUrl(url.toString());\n const raw = await callbacks.onPromptCode(\n \"Could not start local server. Paste the callback URL or code from the browser:\",\n );\n const parsed = parseAuthorizationInput(raw);\n if (!parsed.code) {\n throw new Error(\"No authorization code found in input.\");\n }\n code = parsed.code;\n }\n\n const creds = await exchangeOpenAICode(code, verifier);\n\n const accountId = getAccountId(creds.accessToken);\n if (!accountId) {\n throw new Error(\"Failed to extract accountId from OpenAI token.\");\n }\n creds.accountId = accountId;\n\n return creds;\n}\n\nfunction parseAuthorizationInput(input: string): { code?: string; state?: string } {\n const value = input.trim();\n if (!value) return {};\n\n // Full URL\n try {\n const url = new URL(value);\n return {\n code: url.searchParams.get(\"code\") ?? undefined,\n state: url.searchParams.get(\"state\") ?? undefined,\n };\n } catch {\n // not a URL\n }\n\n // code#state\n if (value.includes(\"#\")) {\n const [code, state] = value.split(\"#\", 2);\n return { code, state };\n }\n\n // Query string with code=\n if (value.includes(\"code=\")) {\n const params = new URLSearchParams(value);\n return {\n code: params.get(\"code\") ?? undefined,\n state: params.get(\"state\") ?? undefined,\n };\n }\n\n // Raw code\n return { code: value };\n}\n\nfunction decodeJwt(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) return null;\n const decoded = atob(parts[1]);\n return JSON.parse(decoded) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nfunction getAccountId(accessToken: string): string | null {\n const payload = decodeJwt(accessToken);\n const auth = payload?.[JWT_CLAIM_PATH] as { chatgpt_account_id?: string } | undefined;\n const accountId = auth?.chatgpt_account_id;\n return typeof accountId === \"string\" && accountId.length > 0 ? accountId : null;\n}\n\nasync function loginWithServer(\n authUrl: string,\n expectedState: string,\n callbacks: OAuthLoginCallbacks,\n): Promise<string> {\n return new Promise<string>((resolve, reject) => {\n let receivedCode: string | null = null;\n\n const server = http.createServer((req, res) => {\n const url = new URL(req.url || \"\", \"http://localhost\");\n\n if (url.pathname !== \"/auth/callback\") {\n res.statusCode = 404;\n res.end(\"Not found\");\n return;\n }\n\n if (url.searchParams.get(\"state\") !== expectedState) {\n res.statusCode = 400;\n res.end(\"State mismatch\");\n return;\n }\n\n receivedCode = url.searchParams.get(\"code\");\n\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(\"<html><body><h1>Login successful!</h1><p>You can close this tab.</p></body></html>\");\n\n server.close();\n });\n\n server.on(\"error\", (err) => {\n reject(err);\n });\n\n server.listen(1455, \"127.0.0.1\", () => {\n callbacks.onOpenUrl(authUrl);\n callbacks.onStatus(\"Waiting for browser callback...\");\n });\n\n const timeout = setTimeout(() => {\n if (!receivedCode) {\n server.close();\n }\n }, 120_000);\n timeout.unref();\n\n server.on(\"close\", () => {\n clearTimeout(timeout);\n if (receivedCode) {\n resolve(receivedCode);\n } else {\n reject(new Error(\"Server closed without receiving code\"));\n }\n });\n });\n}\n\nasync function exchangeOpenAICode(code: string, verifier: string): Promise<OAuthCredentials> {\n const response = await fetch(TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"authorization_code\",\n client_id: CLIENT_ID,\n code,\n redirect_uri: REDIRECT_URI,\n code_verifier: verifier,\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`OpenAI token exchange failed (${response.status}): ${text}`);\n }\n\n const data = (await response.json()) as {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n };\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: Date.now() + data.expires_in * 1000,\n };\n}\n\nexport async function refreshOpenAIToken(refreshToken: string): Promise<OAuthCredentials> {\n const response = await fetch(TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n client_id: CLIENT_ID,\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`OpenAI token refresh failed (${response.status}): ${text}`);\n }\n\n const data = (await response.json()) as {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n };\n\n const creds: OAuthCredentials = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: Date.now() + data.expires_in * 1000,\n };\n\n const accountId = getAccountId(creds.accessToken);\n if (accountId) {\n creds.accountId = accountId;\n }\n\n return creds;\n}\n","import http from \"node:http\";\nimport crypto from \"node:crypto\";\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks } from \"./types.js\";\n\nconst CLIENT_ID_ENV = \"GGCODER_GEMINI_OAUTH_CLIENT_ID\";\nconst CLIENT_SECRET_ENV = \"GGCODER_GEMINI_OAUTH_CLIENT_SECRET\";\n// Public \"installed application\" OAuth client shipped with the official Gemini CLI.\n// Unlike the OpenAI/Anthropic flows (pure PKCE, no secret), Google's token endpoint\n// requires a client_secret for the installed-app authorization_code / refresh_token\n// grants — so it must be embedded to support local login like the other providers.\n// This is the published gemini-cli installed-app secret (non-confidential by design);\n// the env vars above override it for users who bring their own Google Cloud client.\nconst DEFAULT_CLIENT_ID =\n \"681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com\";\nconst DEFAULT_CLIENT_SECRET = \"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\";\nconst AUTHORIZE_URL = \"https://accounts.google.com/o/oauth2/v2/auth\";\nconst TOKEN_URL = \"https://oauth2.googleapis.com/token\";\nconst CODE_ASSIST_BASE_URL = \"https://cloudcode-pa.googleapis.com\";\nconst CODE_ASSIST_API_VERSION = \"v1internal\";\nconst CODE_ASSIST_POST_RETRIES = 3;\nconst CODE_ASSIST_POST_RETRY_DELAY_MS = 100;\nconst SCOPE = [\n \"https://www.googleapis.com/auth/cloud-platform\",\n \"https://www.googleapis.com/auth/userinfo.email\",\n \"https://www.googleapis.com/auth/userinfo.profile\",\n].join(\" \");\n\ninterface GoogleTokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n}\n\ninterface GeminiOAuthClientCredentials {\n clientId: string;\n clientSecret: string;\n}\n\ninterface CodeAssistLoadResponse {\n currentTier?: GeminiUserTier | null;\n allowedTiers?: GeminiUserTier[] | null;\n ineligibleTiers?: IneligibleTier[] | null;\n cloudaicompanionProject?: string | null;\n paidTier?: GeminiUserTier | null;\n}\n\ninterface GeminiUserTier {\n id?: string;\n name?: string;\n isDefault?: boolean;\n}\n\ninterface IneligibleTier {\n reasonCode?: string;\n reasonMessage?: string;\n tierName?: string;\n validationUrl?: string;\n}\n\ninterface LongRunningOperationResponse {\n name?: string;\n done?: boolean;\n response?: {\n cloudaicompanionProject?: {\n id?: string;\n name?: string;\n };\n };\n}\n\nconst USER_TIER_FREE = \"free-tier\";\nconst USER_TIER_LEGACY = \"legacy-tier\";\nconst USER_TIER_STANDARD = \"standard-tier\";\nconst VALIDATION_REQUIRED_REASON = \"VALIDATION_REQUIRED\";\nconst VPC_SC_REASON = \"SECURITY_POLICY_VIOLATED\";\n\nclass CodeAssistHttpError extends Error {\n readonly status: number;\n readonly body: string;\n\n constructor(label: string, status: number, body: string) {\n super(`Gemini Code Assist ${label} failed (${status}): ${body}`);\n this.name = \"CodeAssistHttpError\";\n this.status = status;\n this.body = body;\n }\n}\n\nexport async function loginGemini(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const { clientId, clientSecret } = getGeminiOAuthClientCredentials();\n const { verifier, challenge } = await generatePKCE();\n const state = crypto.randomBytes(32).toString(\"hex\");\n const redirectUri = await getLoopbackRedirectUri();\n\n const url = new URL(AUTHORIZE_URL);\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"client_id\", clientId);\n url.searchParams.set(\"redirect_uri\", redirectUri);\n url.searchParams.set(\"scope\", SCOPE);\n url.searchParams.set(\"access_type\", \"offline\");\n url.searchParams.set(\"prompt\", \"consent\");\n url.searchParams.set(\"code_challenge\", challenge);\n url.searchParams.set(\"code_challenge_method\", \"S256\");\n url.searchParams.set(\"state\", state);\n\n let code: string;\n try {\n code = await loginWithServer(url.toString(), redirectUri, state, callbacks);\n } catch {\n callbacks.onOpenUrl(url.toString());\n const raw = await callbacks.onPromptCode(\n \"Could not start local server. Paste the callback URL or code from the browser:\",\n );\n const parsed = parseAuthorizationInput(raw);\n if (!parsed.code) {\n throw new Error(\"No authorization code found in input.\");\n }\n if (parsed.state && parsed.state !== state) {\n throw new Error(\"Invalid state. Please try again.\");\n }\n code = parsed.code;\n }\n\n const creds = await exchangeGeminiCode(code, verifier, redirectUri, clientId, clientSecret);\n callbacks.onStatus(\"Setting up Gemini Code Assist access...\");\n const projectId = await setupCodeAssistProject(creds.accessToken, callbacks);\n\n return {\n ...creds,\n projectId,\n };\n}\n\nexport async function refreshGeminiToken(refreshToken: string): Promise<OAuthCredentials> {\n const { clientId, clientSecret } = getGeminiOAuthClientCredentials();\n const data = await postTokenRequest({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n client_id: clientId,\n client_secret: clientSecret,\n });\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token ?? refreshToken,\n expiresAt: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n };\n}\n\nfunction getGeminiOAuthClientCredentials(): GeminiOAuthClientCredentials {\n const clientId = process.env[CLIENT_ID_ENV]?.trim() || DEFAULT_CLIENT_ID;\n const clientSecret = process.env[CLIENT_SECRET_ENV]?.trim() || DEFAULT_CLIENT_SECRET;\n return { clientId, clientSecret };\n}\n\nasync function getLoopbackRedirectUri(): Promise<string> {\n return new Promise((resolve, reject) => {\n const server = http.createServer();\n server.listen(0, \"127.0.0.1\", () => {\n const addr = server.address();\n server.close(() => {\n if (addr && typeof addr === \"object\") {\n resolve(`http://127.0.0.1:${addr.port}/oauth2callback`);\n } else {\n reject(new Error(\"Failed to allocate OAuth callback port.\"));\n }\n });\n });\n server.on(\"error\", reject);\n });\n}\n\nfunction parseAuthorizationInput(input: string): { code?: string; state?: string } {\n const value = input.trim();\n if (!value) return {};\n\n try {\n const url = new URL(value);\n return {\n code: url.searchParams.get(\"code\") ?? undefined,\n state: url.searchParams.get(\"state\") ?? undefined,\n };\n } catch {\n // not a URL\n }\n\n if (value.includes(\"code=\")) {\n const params = new URLSearchParams(value);\n return {\n code: params.get(\"code\") ?? undefined,\n state: params.get(\"state\") ?? undefined,\n };\n }\n\n return { code: value };\n}\n\nasync function loginWithServer(\n authUrl: string,\n redirectUri: string,\n expectedState: string,\n callbacks: OAuthLoginCallbacks,\n): Promise<string> {\n const redirect = new URL(redirectUri);\n const port = Number(redirect.port);\n\n return new Promise<string>((resolve, reject) => {\n let receivedCode: string | null = null;\n\n const server = http.createServer((req, res) => {\n const url = new URL(req.url || \"\", redirect.origin);\n\n if (url.pathname !== redirect.pathname) {\n res.statusCode = 404;\n res.end(\"Not found\");\n return;\n }\n\n if (url.searchParams.get(\"state\") !== expectedState) {\n res.statusCode = 400;\n res.end(\"State mismatch\");\n return;\n }\n\n receivedCode = url.searchParams.get(\"code\");\n res.writeHead(200, { \"Content-Type\": \"text/html\", Connection: \"close\" });\n res.end(\"<html><body><h1>Login successful!</h1><p>You can close this tab.</p></body></html>\");\n server.close();\n });\n\n server.on(\"error\", (err) => reject(err));\n server.listen(port, \"127.0.0.1\", () => {\n callbacks.onOpenUrl(authUrl);\n callbacks.onStatus(\"Waiting for browser callback...\");\n });\n\n const timeout = setTimeout(() => {\n if (!receivedCode) server.close();\n }, 120_000);\n timeout.unref();\n\n server.on(\"close\", () => {\n clearTimeout(timeout);\n if (receivedCode) {\n resolve(receivedCode);\n } else {\n reject(new Error(\"Server closed without receiving code.\"));\n }\n });\n });\n}\n\nasync function exchangeGeminiCode(\n code: string,\n verifier: string,\n redirectUri: string,\n clientId: string,\n clientSecret: string,\n): Promise<OAuthCredentials> {\n const data = await postTokenRequest({\n grant_type: \"authorization_code\",\n client_id: clientId,\n client_secret: clientSecret,\n code,\n redirect_uri: redirectUri,\n code_verifier: verifier,\n });\n\n if (!data.refresh_token) {\n throw new Error(\"Gemini OAuth did not return a refresh token. Please try login again.\");\n }\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n };\n}\n\nasync function postTokenRequest(body: Record<string, string>): Promise<GoogleTokenResponse> {\n const response = await fetch(TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams(body),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Gemini token request failed (${response.status}): ${text}`);\n }\n\n return (await response.json()) as GoogleTokenResponse;\n}\n\nasync function setupCodeAssistProject(\n accessToken: string,\n callbacks: OAuthLoginCallbacks,\n): Promise<string> {\n const envProject = process.env.GOOGLE_CLOUD_PROJECT ?? process.env.GOOGLE_CLOUD_PROJECT_ID;\n if (envProject && /^\\d+$/.test(envProject)) {\n throw new Error(\"GOOGLE_CLOUD_PROJECT must be a project ID, not a numeric project number.\");\n }\n\n const coreMetadata = {\n ideType: \"IDE_UNSPECIFIED\",\n platform: \"PLATFORM_UNSPECIFIED\",\n pluginType: \"GEMINI\",\n };\n const projectMetadata = {\n ...coreMetadata,\n ...(envProject ? { duetProject: envProject } : {}),\n };\n\n let loadRes: CodeAssistLoadResponse;\n while (true) {\n loadRes = await loadCodeAssist(accessToken, envProject, projectMetadata);\n const validation = getValidationRequiredTier(loadRes);\n if (!validation) break;\n\n callbacks.onStatus(\n `Gemini Code Assist requires account validation${\n validation.reasonMessage ? `: ${validation.reasonMessage}` : \"\"\n }`,\n );\n callbacks.onOpenUrl(validation.validationUrl);\n const answer = await callbacks.onPromptCode(\n \"Complete validation in the browser, then press Enter to retry (or type cancel):\",\n );\n if (answer.trim().toLowerCase() === \"cancel\") {\n throw new Error(\"Gemini Code Assist account validation was cancelled.\");\n }\n }\n\n if (loadRes.currentTier) {\n const project = loadRes.cloudaicompanionProject ?? envProject;\n if (!project) throwProjectError(loadRes);\n return project;\n }\n\n const tier = getOnboardTier(loadRes);\n const onboardReq =\n tier.id === USER_TIER_FREE\n ? {\n tierId: tier.id,\n cloudaicompanionProject: undefined,\n metadata: coreMetadata,\n }\n : {\n tierId: tier.id,\n cloudaicompanionProject: envProject,\n metadata: projectMetadata,\n };\n\n let operation = await codeAssistPost<LongRunningOperationResponse>(\n accessToken,\n \"onboardUser\",\n onboardReq,\n );\n\n while (!operation.done && operation.name) {\n await new Promise((resolve) => setTimeout(resolve, 5_000));\n operation = await codeAssistGet<LongRunningOperationResponse>(accessToken, operation.name);\n }\n\n const project = operation.response?.cloudaicompanionProject?.id ?? envProject;\n if (!project) throwProjectError(loadRes);\n return project;\n}\n\nasync function loadCodeAssist(\n accessToken: string,\n envProject: string | undefined,\n metadata: Record<string, string>,\n): Promise<CodeAssistLoadResponse> {\n try {\n return await codeAssistPost<CodeAssistLoadResponse>(accessToken, \"loadCodeAssist\", {\n ...(envProject ? { cloudaicompanionProject: envProject } : {}),\n metadata,\n });\n } catch (err) {\n if (err instanceof CodeAssistHttpError && isVpcScAffectedError(err)) {\n return { currentTier: { id: USER_TIER_STANDARD } };\n }\n if (\n err instanceof CodeAssistHttpError &&\n err.status === 403 &&\n envProject === \"cloudshell-gca\"\n ) {\n throw new Error(\n \"Access to the default Cloud Shell Gemini project was denied.\\n\" +\n \"Please set your own Google Cloud project by running:\\n\" +\n \"gcloud config set project [PROJECT_ID]\\n\" +\n \"or setting export GOOGLE_CLOUD_PROJECT=...\",\n { cause: err },\n );\n }\n throw err;\n }\n}\n\nfunction getValidationRequiredTier(\n response: CodeAssistLoadResponse,\n): (IneligibleTier & { validationUrl: string }) | undefined {\n return response.ineligibleTiers?.find(\n (tier): tier is IneligibleTier & { validationUrl: string } =>\n tier.reasonCode === VALIDATION_REQUIRED_REASON && typeof tier.validationUrl === \"string\",\n );\n}\n\nfunction getOnboardTier(response: CodeAssistLoadResponse): GeminiUserTier {\n const defaultTier = response.allowedTiers?.find((tier) => tier.isDefault);\n return defaultTier ?? { id: USER_TIER_LEGACY, name: \"\" };\n}\n\nfunction throwProjectError(response: CodeAssistLoadResponse): never {\n const reasons = response.ineligibleTiers\n ?.map((tier) => tier.reasonMessage ?? tier.tierName)\n .filter((reason): reason is string => Boolean(reason));\n if (reasons && reasons.length > 0) {\n throw new Error(`Gemini Code Assist setup failed: ${reasons.join(\", \")}`);\n }\n throw new Error(\n \"Gemini requires a Google Cloud project for this account. Set GOOGLE_CLOUD_PROJECT and try again.\",\n );\n}\n\nasync function codeAssistPost<T>(\n accessToken: string,\n method: string,\n body: Record<string, unknown>,\n): Promise<T> {\n let lastError: Error | undefined;\n for (let attempt = 0; attempt <= CODE_ASSIST_POST_RETRIES; attempt++) {\n try {\n return await codeAssistRequest<T>(getCodeAssistMethodUrl(method), accessToken, method, {\n method: \"POST\",\n body: JSON.stringify(body),\n });\n } catch (err) {\n if (\n !(err instanceof CodeAssistHttpError) ||\n attempt === CODE_ASSIST_POST_RETRIES ||\n !shouldRetryCodeAssistStatus(err.status)\n ) {\n throw err;\n }\n lastError = err;\n }\n await new Promise((resolve) => setTimeout(resolve, CODE_ASSIST_POST_RETRY_DELAY_MS));\n }\n\n throw lastError ?? new Error(`Gemini Code Assist ${method} failed.`);\n}\n\nasync function codeAssistGet<T>(accessToken: string, operationName: string): Promise<T> {\n return codeAssistRequest<T>(getCodeAssistOperationUrl(operationName), accessToken, \"operation\", {\n method: \"GET\",\n });\n}\n\nasync function codeAssistRequest<T>(\n url: string,\n accessToken: string,\n label: string,\n init: Pick<RequestInit, \"method\" | \"body\">,\n): Promise<T> {\n const response = await fetch(url, {\n ...init,\n headers: codeAssistHeaders(accessToken),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new CodeAssistHttpError(label, response.status, text);\n }\n\n return (await response.json()) as T;\n}\n\nfunction getCodeAssistBaseUrl(): string {\n const endpoint = process.env.CODE_ASSIST_ENDPOINT ?? CODE_ASSIST_BASE_URL;\n const version = process.env.CODE_ASSIST_API_VERSION || CODE_ASSIST_API_VERSION;\n return `${endpoint}/${version}`;\n}\n\nfunction getCodeAssistMethodUrl(method: string): string {\n return `${getCodeAssistBaseUrl()}:${method}`;\n}\n\nfunction getCodeAssistOperationUrl(operationName: string): string {\n return `${getCodeAssistBaseUrl()}/${operationName}`;\n}\n\nfunction shouldRetryCodeAssistStatus(status: number): boolean {\n return status === 429 || status === 499 || (status >= 500 && status <= 599);\n}\n\nfunction isVpcScAffectedError(error: CodeAssistHttpError): boolean {\n try {\n const parsed = JSON.parse(error.body) as unknown;\n if (!parsed || typeof parsed !== \"object\" || !(\"error\" in parsed)) return false;\n const details = (parsed as { error?: { details?: unknown[] } }).error?.details;\n return Array.isArray(details)\n ? details.some(\n (detail) =>\n detail != null &&\n typeof detail === \"object\" &&\n \"reason\" in detail &&\n detail.reason === VPC_SC_REASON,\n )\n : false;\n } catch {\n return false;\n }\n}\n\nfunction codeAssistHeaders(accessToken: string): Record<string, string> {\n return {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"google-gemini-cli\",\n \"X-Goog-Api-Client\": \"gemini-cli/0.0.0\",\n };\n}\n","/**\n * Minimal Telegram Bot API client using raw fetch().\n * Supports long polling, markdown messages, inline keyboards, and message splitting.\n */\n\nconst TELEGRAM_API = \"https://api.telegram.org\";\nconst MAX_MESSAGE_LENGTH = 4096;\n\nexport interface TelegramConfig {\n botToken: string;\n /** Only accept messages from this Telegram user ID. */\n allowedUserId: number;\n}\n\nexport interface TelegramUpdate {\n update_id: number;\n message?: {\n message_id: number;\n from: { id: number; first_name: string };\n chat: { id: number; type: string; title?: string };\n text?: string;\n voice?: { file_id: string; duration: number; mime_type?: string; file_size?: number };\n };\n callback_query?: {\n id: string;\n from: { id: number };\n message: { chat: { id: number } };\n data: string;\n };\n my_chat_member?: {\n chat: { id: number; type: string; title?: string };\n from: { id: number };\n new_chat_member: { status: string };\n };\n}\n\nexport interface InlineButton {\n text: string;\n callback_data: string;\n}\n\n/** Incoming message with chat context. */\nexport interface TelegramMessage {\n text: string;\n chatId: number;\n chatType: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n chatTitle?: string;\n}\n\n/** Incoming voice note with chat context. */\nexport interface TelegramVoiceMessage {\n fileId: string;\n duration: number;\n chatId: number;\n chatType: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n chatTitle?: string;\n}\n\nexport class TelegramBot {\n private token: string;\n private allowedUserId: number;\n private offset = 0;\n private running = false;\n\n private onMessage: ((msg: TelegramMessage) => void) | null = null;\n private onVoiceMessage: ((msg: TelegramVoiceMessage) => void) | null = null;\n private onCallback: ((data: string, chatId: number) => void) | null = null;\n private onBotAdded: ((chatId: number, chatTitle?: string) => void) | null = null;\n private onBotRemoved: ((chatId: number) => void) | null = null;\n\n constructor(config: TelegramConfig) {\n this.token = config.botToken;\n this.allowedUserId = config.allowedUserId;\n }\n\n /** Register handler for incoming text messages. */\n onText(handler: (msg: TelegramMessage) => void): void {\n this.onMessage = handler;\n }\n\n /** Register handler for incoming voice notes. */\n onVoice(handler: (msg: TelegramVoiceMessage) => void): void {\n this.onVoiceMessage = handler;\n }\n\n /** Register handler for inline keyboard button presses. */\n onCallbackQuery(handler: (data: string, chatId: number) => void): void {\n this.onCallback = handler;\n }\n\n /** Register handler for when the bot is added to a group. */\n onAddedToGroup(handler: (chatId: number, chatTitle?: string) => void): void {\n this.onBotAdded = handler;\n }\n\n /** Register handler for when the bot is removed from a group. */\n onRemovedFromGroup(handler: (chatId: number) => void): void {\n this.onBotRemoved = handler;\n }\n\n /** Start long polling. Blocks until stop() is called. */\n async start(): Promise<void> {\n this.running = true;\n\n // Verify bot token works\n const me = await this.apiCall(\"getMe\");\n if (!me.ok) {\n throw new Error(`Invalid bot token: ${JSON.stringify(me)}`);\n }\n\n while (this.running) {\n try {\n const updates = await this.getUpdates();\n for (const update of updates) {\n await this.handleUpdate(update);\n }\n } catch (err) {\n if (!this.running) break;\n console.error(`[telegram] Poll error: ${err instanceof Error ? err.message : err}`);\n await sleep(3000);\n }\n }\n }\n\n /** Stop long polling. */\n stop(): void {\n this.running = false;\n }\n\n /** Send a text message to a specific chat. Converts markdown and splits long messages. */\n async send(chatId: number, text: string, buttons?: InlineButton[][]): Promise<void> {\n const converted = toTelegramMarkdown(text);\n const chunks = splitMessage(converted);\n\n for (let i = 0; i < chunks.length; i++) {\n const isLast = i === chunks.length - 1;\n const replyMarkup =\n isLast && buttons\n ? {\n inline_keyboard: buttons.map((row) =>\n row.map((b) => ({ text: b.text, callback_data: b.callback_data })),\n ),\n }\n : undefined;\n\n await this.apiCall(\"sendMessage\", {\n chat_id: chatId,\n text: chunks[i],\n parse_mode: \"Markdown\",\n ...(replyMarkup ? { reply_markup: replyMarkup } : {}),\n });\n }\n }\n\n /** Send a plain text message (no markdown parsing) to a specific chat. */\n async sendPlain(chatId: number, text: string): Promise<void> {\n const chunks = splitMessage(text);\n for (const chunk of chunks) {\n await this.apiCall(\"sendMessage\", {\n chat_id: chatId,\n text: chunk,\n });\n }\n }\n\n /** Send a typing indicator to a specific chat. */\n async sendTyping(chatId: number): Promise<void> {\n await this.apiCall(\"sendChatAction\", {\n chat_id: chatId,\n action: \"typing\",\n });\n }\n\n /** Get a direct download URL for a Telegram file. */\n async getFileUrl(fileId: string): Promise<string> {\n const result = await this.apiCall(\"getFile\", { file_id: fileId });\n if (!result.ok) throw new Error(`Failed to get file: ${JSON.stringify(result)}`);\n const filePath = (result.result as { file_path: string }).file_path;\n return `${TELEGRAM_API}/file/bot${this.token}/${filePath}`;\n }\n\n // ── Private ───────────────────────────────────────────\n\n private async getUpdates(): Promise<TelegramUpdate[]> {\n const result = await this.apiCall(\"getUpdates\", {\n offset: this.offset,\n timeout: 30,\n allowed_updates: [\"message\", \"callback_query\", \"my_chat_member\"],\n });\n\n if (!result.ok || !Array.isArray(result.result)) return [];\n\n const updates = result.result as TelegramUpdate[];\n if (updates.length > 0) {\n this.offset = updates[updates.length - 1]!.update_id + 1;\n }\n return updates;\n }\n\n private async handleUpdate(update: TelegramUpdate): Promise<void> {\n if (update.message) {\n const msg = update.message;\n\n // Auth check\n if (msg.from.id !== this.allowedUserId) {\n return;\n }\n\n if (msg.text && this.onMessage) {\n this.onMessage({\n text: msg.text,\n chatId: msg.chat.id,\n chatType: msg.chat.type as TelegramMessage[\"chatType\"],\n chatTitle: msg.chat.title,\n });\n } else if (msg.voice && this.onVoiceMessage) {\n this.onVoiceMessage({\n fileId: msg.voice.file_id,\n duration: msg.voice.duration,\n chatId: msg.chat.id,\n chatType: msg.chat.type as TelegramMessage[\"chatType\"],\n chatTitle: msg.chat.title,\n });\n }\n }\n\n // Bot membership changed in a group\n if (update.my_chat_member) {\n const member = update.my_chat_member;\n const status = member.new_chat_member.status;\n if ((status === \"member\" || status === \"administrator\") && this.onBotAdded) {\n this.onBotAdded(member.chat.id, member.chat.title);\n } else if ((status === \"left\" || status === \"kicked\") && this.onBotRemoved) {\n this.onBotRemoved(member.chat.id);\n }\n }\n\n if (update.callback_query) {\n const cb = update.callback_query;\n\n if (cb.from.id !== this.allowedUserId) return;\n\n await this.apiCall(\"answerCallbackQuery\", { callback_query_id: cb.id });\n\n if (cb.data && this.onCallback) {\n this.onCallback(cb.data, cb.message.chat.id);\n }\n }\n }\n\n private async apiCall(\n method: string,\n body?: Record<string, unknown>,\n ): Promise<{ ok: boolean; result?: unknown }> {\n const url = `${TELEGRAM_API}/bot${this.token}/${method}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n return { ok: false };\n }\n\n return response.json() as Promise<{ ok: boolean; result?: unknown }>;\n }\n}\n\n// ── Markdown Conversion ──────────────────────────────────\n\n/**\n * Convert GitHub-flavored markdown to Telegram-compatible Markdown.\n *\n * Telegram supports: *bold*, _italic_, `code`, ```pre```, [link](url)\n * Does NOT support: headings, horizontal rules, tables, HTML tags, images\n */\nfunction toTelegramMarkdown(text: string): string {\n const lines = text.split(\"\\n\");\n const result: string[] = [];\n let inCodeBlock = false;\n\n for (const line of lines) {\n if (line.trimStart().startsWith(\"```\")) {\n inCodeBlock = !inCodeBlock;\n result.push(line);\n continue;\n }\n\n if (inCodeBlock) {\n result.push(line);\n continue;\n }\n\n let transformed = line;\n\n // Headings → bold text\n const headingMatch = transformed.match(/^(#{1,6})\\s+(.+)$/);\n if (headingMatch) {\n transformed = `*${headingMatch[2]}*`;\n result.push(transformed);\n continue;\n }\n\n // Horizontal rules → empty line\n if (/^(-{3,}|_{3,}|\\*{3,})$/.test(transformed.trim())) {\n result.push(\"\");\n continue;\n }\n\n // **bold** → *bold*\n transformed = transformed.replace(/\\*\\*(.+?)\\*\\*/g, \"*$1*\");\n\n result.push(transformed);\n }\n\n return result.join(\"\\n\");\n}\n\n// ── Helpers ───────────────────────────────────────────────\n\nfunction splitMessage(text: string): string[] {\n if (text.length <= MAX_MESSAGE_LENGTH) return [text];\n\n const chunks: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= MAX_MESSAGE_LENGTH) {\n chunks.push(remaining);\n break;\n }\n\n let splitAt = remaining.lastIndexOf(\"\\n\", MAX_MESSAGE_LENGTH);\n if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {\n splitAt = remaining.lastIndexOf(\" \", MAX_MESSAGE_LENGTH);\n }\n if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {\n splitAt = MAX_MESSAGE_LENGTH;\n }\n\n chunks.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt).trimStart();\n }\n\n return chunks;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","/**\n * Voice note transcription using local Whisper model.\n * Uses @huggingface/transformers (pure JS/WASM) — no native deps, no API keys.\n * Model (~75MB) is downloaded on first use and cached locally.\n */\n\nimport type { AutomaticSpeechRecognitionPipeline } from \"@huggingface/transformers\";\n\nconst TARGET_SAMPLE_RATE = 16000;\nconst MODEL_ID = \"Xenova/whisper-tiny.en\";\n\nlet transcriber: AutomaticSpeechRecognitionPipeline | null = null;\nlet loadPromise: Promise<AutomaticSpeechRecognitionPipeline> | null = null;\n\n/** Optional callback for model download progress. */\nexport type ProgressCallback = (info: { status: string; progress?: number; file?: string }) => void;\n\nlet onProgress: ProgressCallback | null = null;\n\n/** Set a callback to receive model download progress updates. */\nexport function setProgressCallback(cb: ProgressCallback | null): void {\n onProgress = cb;\n}\n\n/**\n * Resample audio from one sample rate to another using linear interpolation.\n */\nexport function resample(audio: Float32Array, fromRate: number, toRate: number): Float32Array {\n if (fromRate === toRate) return audio;\n const ratio = fromRate / toRate;\n const newLength = Math.round(audio.length / ratio);\n const result = new Float32Array(newLength);\n for (let i = 0; i < newLength; i++) {\n const srcIndex = i * ratio;\n const low = Math.floor(srcIndex);\n const high = Math.min(low + 1, audio.length - 1);\n const frac = srcIndex - low;\n result[i] = audio[low]! * (1 - frac) + audio[high]! * frac;\n }\n return result;\n}\n\n/**\n * Downmix multi-channel audio to mono by averaging all channels.\n */\nexport function downmixToMono(channelData: Float32Array[]): Float32Array {\n if (channelData.length === 0) return new Float32Array();\n if (channelData.length === 1) return channelData[0]!;\n\n const samples = channelData[0]!.length;\n const out = new Float32Array(samples);\n const scale = 1 / channelData.length;\n for (let i = 0; i < samples; i++) {\n let mixed = 0;\n for (const channel of channelData) mixed += channel[i] ?? 0;\n out[i] = mixed * scale;\n }\n return out;\n}\n\n/**\n * Decode OGG Opus audio buffer to 16kHz mono PCM Float32Array.\n */\nexport async function decodeOggOpus(buffer: Uint8Array): Promise<Float32Array> {\n const { OggOpusDecoder } = await import(\"ogg-opus-decoder\");\n const decoder = new OggOpusDecoder();\n await decoder.ready;\n try {\n const decoded = await decoder.decodeFile(buffer);\n\n if (!decoded.channelData?.length || !decoded.channelData[0]?.length) {\n throw new Error(\"Decoded audio is empty\");\n }\n\n const mono = downmixToMono(decoded.channelData);\n return resample(mono, decoded.sampleRate, TARGET_SAMPLE_RATE);\n } finally {\n decoder.free();\n }\n}\n\n/**\n * Get or initialize the Whisper transcription pipeline.\n * Model is downloaded on first use and cached by transformers.js.\n */\nasync function getTranscriber(): Promise<AutomaticSpeechRecognitionPipeline> {\n if (transcriber) return transcriber;\n\n if (!loadPromise) {\n loadPromise = (async () => {\n const { pipeline } = await import(\"@huggingface/transformers\");\n const instance = await pipeline(\"automatic-speech-recognition\", MODEL_ID, {\n dtype: \"fp32\",\n progress_callback: onProgress ?? undefined,\n });\n transcriber = instance;\n return instance;\n })();\n }\n\n return loadPromise;\n}\n\n/** Whether the model has been loaded already. */\nexport function isModelLoaded(): boolean {\n return transcriber !== null;\n}\n\n/**\n * Transcribe a voice message from its Telegram file URL.\n * Downloads the OGG Opus file, decodes to PCM, and runs Whisper locally.\n */\nexport async function transcribeVoice(fileUrl: string): Promise<string> {\n // Download the audio file\n const response = await fetch(fileUrl);\n if (!response.ok) throw new Error(`Failed to download voice file: ${response.status}`);\n const buffer = new Uint8Array(await response.arrayBuffer());\n\n // Decode OGG Opus → 16kHz mono PCM\n const pcm = await decodeOggOpus(buffer);\n\n // Transcribe with Whisper\n const asr = await getTranscriber();\n const result = await asr(pcm);\n\n const text = Array.isArray(result) ? result[0]?.text : (result as { text: string }).text;\n return (text ?? \"\").trim();\n}\n","import { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Provider-agnostic background self-updater. Each app composes its own instance\n * via `createAutoUpdater` with its npm package name and state-file path, so the\n * update logic (registry poll, version compare, detached install, throttling)\n * lives in exactly one place while branding stays in the apps.\n */\n\ninterface UpdateState {\n lastCheckedAt: number;\n latestVersion?: string;\n updatePending?: boolean;\n lastUpdateAttempt?: number;\n}\n\nenum PackageManager {\n NPM = \"npm\",\n PNPM = \"pnpm\",\n YARN = \"yarn\",\n UNKNOWN = \"unknown\",\n}\n\ninterface InstallInfo {\n packageManager: PackageManager;\n updateCommand: string | null;\n}\n\nexport interface AutoUpdateConfig {\n /** npm package to self-update, e.g. \"@kenkaiiii/ggcoder\". */\n packageName: string;\n /**\n * Absolute path to this app's update-state.json, or a thunk resolving it.\n * A thunk keeps path resolution lazy so callers can derive it from\n * `os.homedir()` without freezing the value at module-load time (which\n * breaks tests that mock the home directory after import).\n */\n stateFilePath: string | (() => string);\n /** Builds the in-session \"update available\" notification. */\n periodicMessage?: (args: {\n currentVersion: string;\n latestVersion: string;\n updateCommand: string;\n }) => string;\n}\n\nexport interface AutoUpdater {\n checkAndAutoUpdate(currentVersion: string): string | null;\n getPendingUpdate(currentVersion: string): { latestVersion: string } | null;\n startPeriodicUpdateCheck(currentVersion: string, onUpdate: (message: string) => void): void;\n stopPeriodicUpdateCheck(): void;\n}\n\nconst CHECK_INTERVAL_MS = 60 * 60 * 1000; // 1 hour\nconst FETCH_TIMEOUT_MS = 10_000; // 10s — npm can be slow\n\nfunction compareVersions(a: string, b: string): number {\n const pa = a.split(\".\").map(Number);\n const pb = b.split(\".\").map(Number);\n for (let i = 0; i < 3; i++) {\n const diff = (pa[i] ?? 0) - (pb[i] ?? 0);\n if (diff !== 0) return diff;\n }\n return 0;\n}\n\nfunction performUpdateInBackground(command: string): void {\n try {\n const parts = command.split(\" \");\n const child = spawn(parts[0]!, parts.slice(1), {\n detached: true,\n stdio: \"ignore\",\n env: { ...process.env, npm_config_loglevel: \"silent\" },\n });\n child.unref();\n } catch {\n // Non-fatal — will retry next startup\n }\n}\n\nexport function createAutoUpdater(config: AutoUpdateConfig): AutoUpdater {\n const REGISTRY_URL = `https://registry.npmjs.org/${config.packageName}/latest`;\n const periodicMessage =\n config.periodicMessage ??\n (({ currentVersion, latestVersion, updateCommand }) =>\n `Ken just pushed a fresh update — ${currentVersion} → ${latestVersion}! I'll grab it on next launch (or run ${updateCommand} if you can't wait).`);\n\n let periodicTimer: ReturnType<typeof setInterval> | null = null;\n\n function stateFilePath(): string {\n return typeof config.stateFilePath === \"function\"\n ? config.stateFilePath()\n : config.stateFilePath;\n }\n\n function readState(): UpdateState | null {\n try {\n const raw = fs.readFileSync(stateFilePath(), \"utf-8\");\n return JSON.parse(raw) as UpdateState;\n } catch {\n return null;\n }\n }\n\n function writeState(state: UpdateState): void {\n try {\n const filePath = stateFilePath();\n fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });\n fs.writeFileSync(filePath, JSON.stringify(state));\n } catch {\n // Non-fatal\n }\n }\n\n function detectInstallInfo(): InstallInfo {\n const scriptPath = (process.argv[1] ?? \"\").replace(/\\\\/g, \"/\");\n\n // npx — skip (ephemeral)\n if (scriptPath.includes(\"/_npx/\")) {\n return { packageManager: PackageManager.UNKNOWN, updateCommand: null };\n }\n\n // pnpm global\n if (scriptPath.includes(\"/.pnpm\") || scriptPath.includes(\"/pnpm/global\")) {\n return {\n packageManager: PackageManager.PNPM,\n updateCommand: `pnpm add -g ${config.packageName}@latest`,\n };\n }\n\n // yarn global\n if (scriptPath.includes(\"/.yarn/\") || scriptPath.includes(\"/yarn/global\")) {\n return {\n packageManager: PackageManager.YARN,\n updateCommand: `yarn global add ${config.packageName}@latest`,\n };\n }\n\n // npm global (default)\n return {\n packageManager: PackageManager.NPM,\n updateCommand: `npm install -g ${config.packageName}@latest`,\n };\n }\n\n async function fetchLatestVersion(): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n const response = await fetch(REGISTRY_URL, { signal: controller.signal });\n clearTimeout(timeout);\n const data = (await response.json()) as { version?: string };\n const version = data.version?.trim();\n return version && /^\\d+\\.\\d+\\.\\d+/.test(version) ? version : null;\n } catch {\n return null;\n }\n }\n\n function scheduleBackgroundCheck(currentVersion: string): void {\n fetchLatestVersion()\n .then((latestVersion) => {\n const newState: UpdateState = {\n lastCheckedAt: Date.now(),\n latestVersion: latestVersion ?? undefined,\n updatePending: false,\n };\n if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) {\n newState.updatePending = true;\n }\n writeState(newState);\n })\n .catch(() => {\n // Non-fatal — will retry next time\n });\n }\n\n function checkAndAutoUpdate(currentVersion: string): string | null {\n try {\n const state = readState();\n let message: string | null = null;\n\n // Phase 1: Apply pending update from previous check\n if (state?.updatePending && state.latestVersion) {\n if (compareVersions(state.latestVersion, currentVersion) > 0) {\n const info = detectInstallInfo();\n if (info.updateCommand) {\n performUpdateInBackground(info.updateCommand);\n message = `Ken just shipped ${state.latestVersion}! Installing in the background — takes effect next launch.`;\n writeState({\n ...state,\n lastCheckedAt: Date.now(),\n updatePending: false,\n lastUpdateAttempt: Date.now(),\n });\n }\n } else {\n // Already on latest (user may have updated manually)\n writeState({ ...state, updatePending: false });\n }\n }\n\n // Phase 2: Schedule background check for next startup\n const shouldCheck = !state || Date.now() - state.lastCheckedAt > CHECK_INTERVAL_MS;\n if (shouldCheck) scheduleBackgroundCheck(currentVersion);\n\n return message;\n } catch {\n return null;\n }\n }\n\n function getPendingUpdate(currentVersion: string): { latestVersion: string } | null {\n try {\n const state = readState();\n if (!state?.latestVersion) return null;\n if (compareVersions(state.latestVersion, currentVersion) <= 0) return null;\n return { latestVersion: state.latestVersion };\n } catch {\n return null;\n }\n }\n\n function startPeriodicUpdateCheck(\n currentVersion: string,\n onUpdate: (message: string) => void,\n ): void {\n if (periodicTimer) return; // Already running\n\n periodicTimer = setInterval(() => {\n fetchLatestVersion()\n .then((latestVersion) => {\n if (!latestVersion) return;\n if (compareVersions(latestVersion, currentVersion) <= 0) return;\n\n const info = detectInstallInfo();\n if (!info.updateCommand) return;\n\n writeState({ lastCheckedAt: Date.now(), latestVersion, updatePending: true });\n onUpdate(\n periodicMessage({ currentVersion, latestVersion, updateCommand: info.updateCommand }),\n );\n\n // Stop checking once we've notified\n stopPeriodicUpdateCheck();\n })\n .catch(() => {\n // Non-fatal\n });\n }, CHECK_INTERVAL_MS);\n\n // Don't keep the process alive just for update checks\n periodicTimer.unref();\n }\n\n function stopPeriodicUpdateCheck(): void {\n if (periodicTimer) {\n clearInterval(periodicTimer);\n periodicTimer = null;\n }\n }\n\n return {\n checkAndAutoUpdate,\n getPendingUpdate,\n startPeriodicUpdateCheck,\n stopPeriodicUpdateCheck,\n };\n}\n"],"mappings":"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","names":["maxIndex","fs","setTimeout","fs","path","path","fs","fs","crypto","crypto","crypto","crypto","CLIENT_ID","AUTHORIZE_URL","REDIRECT_URI","crypto","http","crypto","AUTHORIZE_URL","TOKEN_URL","SCOPE","crypto","loginWithServer","parseAuthorizationInput","postTokenRequest","http","project","fs","crypto","fs","path","FETCH_TIMEOUT_MS","fs","path"]}
|
|
1
|
+
{"version":3,"sources":["../src/thinking-level.ts","../src/logger.ts","../src/file-lock.ts","../src/claude-code-version.ts","../src/auth-storage.ts","../src/oauth/anthropic.ts","../src/oauth/pkce.ts","../src/oauth/openai.ts","../src/oauth/gemini.ts","../src/oauth/kimi.ts","../src/telegram.ts","../src/voice-transcriber.ts","../src/auto-update.ts"],"sourcesContent":["import type { Provider, ThinkingLevel } from \"@kenkaiiii/gg-ai\";\nimport { getMaxThinkingLevel } from \"./model-registry.js\";\n\nconst OPENAI_GPT_THINKING_LEVELS: readonly ThinkingLevel[] = [\"medium\", \"high\", \"xhigh\"];\nconst ANTHROPIC_OPUS_48_47_THINKING_LEVELS: readonly ThinkingLevel[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\",\n \"max\",\n];\nconst ANTHROPIC_ADAPTIVE_THINKING_LEVELS: readonly ThinkingLevel[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"max\",\n];\n\nfunction isOpenAIGptModel(provider: Provider, model: string): boolean {\n return provider === \"openai\" && model.startsWith(\"gpt-\");\n}\n\nfunction isAnthropicOpus48Or47Model(provider: Provider, model: string): boolean {\n return provider === \"anthropic\" && /opus-4-8|opus-4-7/.test(model);\n}\n\nfunction isAnthropicAdaptiveModel(provider: Provider, model: string): boolean {\n return provider === \"anthropic\" && /opus-4-8|opus-4-7|opus-4-6|sonnet-4-6/.test(model);\n}\n\nexport function getSupportedThinkingLevels(\n provider: Provider,\n model: string,\n): readonly ThinkingLevel[] {\n const maxLevel = getMaxThinkingLevel(model);\n if (isAnthropicAdaptiveModel(provider, model)) {\n const levels = isAnthropicOpus48Or47Model(provider, model)\n ? ANTHROPIC_OPUS_48_47_THINKING_LEVELS\n : ANTHROPIC_ADAPTIVE_THINKING_LEVELS;\n const maxIndex = levels.indexOf(maxLevel);\n if (maxIndex === -1) return [\"low\", \"medium\", \"high\"];\n return levels.slice(0, maxIndex + 1);\n }\n\n if (!isOpenAIGptModel(provider, model)) return [maxLevel];\n\n const maxIndex = OPENAI_GPT_THINKING_LEVELS.indexOf(maxLevel);\n if (maxIndex === -1) return [\"medium\"];\n return OPENAI_GPT_THINKING_LEVELS.slice(0, maxIndex + 1);\n}\n\nexport function isThinkingLevelSupported(\n provider: Provider,\n model: string,\n level: ThinkingLevel,\n): boolean {\n return getSupportedThinkingLevels(provider, model).includes(level);\n}\n\nexport function getNextThinkingLevel(\n provider: Provider,\n model: string,\n current: ThinkingLevel | undefined,\n): ThinkingLevel | undefined {\n const supportedLevels = getSupportedThinkingLevels(provider, model);\n const shouldCycleLevels =\n isOpenAIGptModel(provider, model) || isAnthropicAdaptiveModel(provider, model);\n if (!shouldCycleLevels) {\n return current ? undefined : supportedLevels[0];\n }\n\n if (!current) return supportedLevels[0];\n const index = supportedLevels.indexOf(current);\n if (index === -1) return supportedLevels[0];\n return supportedLevels[index + 1];\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { randomBytes } from \"node:crypto\";\n\nexport type LogLevel = \"INFO\" | \"ERROR\" | \"WARN\" | \"DEBUG\";\n\n// Cross-session log retention: the log is appended across launches so you can\n// grep back through prior sessions. Rotated at MAX_BYTES to keep it bounded; we\n// keep one generation (debug.log.1) — enough to survive one rotation's worth of\n// scrollback while bounding disk usage.\nconst MAX_BYTES = 10 * 1024 * 1024; // 10 MB\n\nlet fd: number | null = null;\nlet sessionId = \"\";\nlet appName = \"app\";\nlet cleanups: (() => void)[] = [];\n\nfunction rotateIfNeeded(filePath: string): void {\n try {\n const st = fs.statSync(filePath);\n if (st.size < MAX_BYTES) return;\n const rotated = `${filePath}.1`;\n // Replace prior rotation (fs.renameSync overwrites on POSIX; on Windows it\n // fails if dest exists, so unlink first defensively).\n try {\n fs.unlinkSync(rotated);\n } catch {\n // No prior rotation\n }\n fs.renameSync(filePath, rotated);\n } catch {\n // Log file doesn't exist yet or stat failed — nothing to rotate\n }\n}\n\n/**\n * Open the debug log in append mode, tagging this process with a session id and\n * remembering `name` for the shutdown line. Idempotent — re-calling while open\n * is a no-op. Returns true only when it *newly* opened the file (so callers can\n * write a one-time startup line); returns false if already open or if the file\n * could not be opened.\n */\nexport function openLog(filePath: string, name: string): boolean {\n if (fd !== null) return false;\n appName = name;\n try {\n fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });\n } catch {\n // Directory may already exist or be uncreatable — fall through to open\n }\n rotateIfNeeded(filePath);\n try {\n fd = fs.openSync(filePath, \"a\");\n } catch {\n // Can't open log file — silently disable logging\n return false;\n }\n sessionId = randomBytes(4).toString(\"hex\");\n // Visible separator between sessions when back-reading the log.\n try {\n fs.writeSync(fd, \"\\n\");\n } catch {\n // Write failed — proceed without the separator\n }\n return true;\n}\n\n/** Session identifier included on every log line as `sid=<id>`. */\nexport function getSessionId(): string {\n return sessionId;\n}\n\n/** True if the logger has an open file descriptor. */\nexport function isLoggerOpen(): boolean {\n return fd !== null;\n}\n\n/** Write a timestamped log line. No-op if the logger is not open. */\nexport function log(\n level: LogLevel,\n category: string,\n message: string,\n data?: Record<string, unknown>,\n): void {\n if (fd === null) return;\n const ts = new Date().toISOString();\n let line = `[${ts}] [sid=${sessionId}] [${level}] [${category}] ${message}`;\n if (data) {\n const pairs = Object.entries(data)\n .map(([k, v]) => `${k}=${typeof v === \"string\" ? v : JSON.stringify(v)}`)\n .join(\" \");\n if (pairs) line += ` ${pairs}`;\n }\n line += \"\\n\";\n try {\n fs.writeSync(fd, line);\n } catch {\n // Write failed — don't crash\n }\n}\n\n/**\n * Register a cleanup callback (e.g. an EventBus unsubscriber) to run when the\n * logger closes. Lets app-side bridges hook into the shared lifecycle without\n * the core needing to know about app types.\n */\nexport function registerLogCleanup(fn: () => void): void {\n cleanups.push(fn);\n}\n\n/**\n * Write a shutdown line (unless suppressed), close the file descriptor, and run\n * any registered cleanups.\n */\nexport function closeLogger(opts?: { shutdownLine?: boolean }): void {\n if (fd === null) return;\n if (opts?.shutdownLine !== false) log(\"INFO\", \"shutdown\", `${appName} shutting down`);\n try {\n fs.closeSync(fd);\n } catch {\n // Ignore close errors\n }\n fd = null;\n for (const unsub of cleanups) unsub();\n cleanups = [];\n}\n","import fs from \"node:fs/promises\";\nimport { setTimeout } from \"node:timers/promises\";\n\nconst STALE_TIMEOUT_MS = 10_000; // Lock is stale after 10s\nconst RETRY_INTERVAL_MS = 50; // Retry every 50ms\nconst MAX_WAIT_MS = 5_000; // Give up after 5s\n\ninterface LockInfo {\n pid: number;\n timestamp: number;\n}\n\n/**\n * Simple file-based lock with PID tracking and stale detection.\n * Uses atomic file creation (wx flag) to prevent races.\n */\nexport async function withFileLock<T>(filePath: string, fn: () => Promise<T>): Promise<T> {\n const lockPath = filePath + \".lock\";\n await acquireLock(lockPath);\n try {\n return await fn();\n } finally {\n await releaseLock(lockPath);\n }\n}\n\nasync function acquireLock(lockPath: string): Promise<void> {\n const startTime = Date.now();\n\n while (true) {\n try {\n // O_EXCL: fail if file exists — atomic lock acquisition\n const info: LockInfo = { pid: process.pid, timestamp: Date.now() };\n await fs.writeFile(lockPath, JSON.stringify(info), { flag: \"wx\" });\n return; // Lock acquired\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"EEXIST\") throw err;\n\n // Lock file exists — check if it's stale\n try {\n const content = await fs.readFile(lockPath, \"utf-8\");\n const info = JSON.parse(content) as LockInfo;\n\n // Check if the holding process is still alive\n const isProcessAlive = isAlive(info.pid);\n const isStale = Date.now() - info.timestamp > STALE_TIMEOUT_MS;\n\n if (!isProcessAlive || isStale) {\n // Stale lock — remove and retry\n await fs.unlink(lockPath).catch(() => {});\n continue;\n }\n } catch {\n // Corrupt lock file — remove and retry\n await fs.unlink(lockPath).catch(() => {});\n continue;\n }\n\n // Lock is held by a live process — wait and retry\n if (Date.now() - startTime > MAX_WAIT_MS) {\n // Timeout — force break the lock (better than deadlocking)\n await fs.unlink(lockPath).catch(() => {});\n continue;\n }\n\n await setTimeout(RETRY_INTERVAL_MS);\n }\n }\n}\n\nasync function releaseLock(lockPath: string): Promise<void> {\n await fs.unlink(lockPath).catch(() => {});\n}\n\nfunction isAlive(pid: number): boolean {\n try {\n process.kill(pid, 0); // Signal 0 = check existence without killing\n return true;\n } catch (err) {\n // EPERM = process exists but belongs to a different user — still alive\n if ((err as NodeJS.ErrnoException).code === \"EPERM\") return true;\n // ESRCH = no such process — it's dead\n return false;\n }\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getAppPaths } from \"./paths.js\";\nimport { log } from \"./logger.js\";\n\n// Anthropic's OAuth edge rejects requests whose claude-cli UA version lags too\n// far behind the actual Claude Code release. Resolve dynamically from the npm\n// registry so we never ship a stale-version time bomb.\nconst NPM_LATEST_URL = \"https://registry.npmjs.org/@anthropic-ai/claude-code/latest\";\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000;\nconst FETCH_TIMEOUT_MS = 3000;\n// Last known good version at publish time. Used only when the npm fetch fails\n// and no on-disk cache exists (e.g. first run on an offline machine). Keep\n// reasonably current — bump on each ggcoder release.\nconst FALLBACK_VERSION = \"2.1.88\";\n\ntype CachedVersion = { version: string; fetchedAt: number };\n\nlet memoryCache: { version: string; expiresAt: number } | null = null;\nlet inflight: Promise<string> | null = null;\n\nfunction cachePath(): string {\n return path.join(getAppPaths().agentDir, \"claude-code-version.json\");\n}\n\nasync function readDiskCache(): Promise<CachedVersion | null> {\n try {\n const raw = await fs.readFile(cachePath(), \"utf-8\");\n const parsed = JSON.parse(raw) as CachedVersion;\n if (typeof parsed.version === \"string\" && typeof parsed.fetchedAt === \"number\") {\n return parsed;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nasync function writeDiskCache(data: CachedVersion): Promise<void> {\n try {\n await fs.mkdir(getAppPaths().agentDir, { recursive: true, mode: 0o700 });\n await fs.writeFile(cachePath(), JSON.stringify(data), { mode: 0o600 });\n } catch (err) {\n log(\n \"WARN\",\n \"claude-code-version\",\n `Failed to write cache: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n}\n\nasync function fetchLatest(): Promise<string | null> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const response = await fetch(NPM_LATEST_URL, { signal: controller.signal });\n if (!response.ok) return null;\n const data = (await response.json()) as { version?: unknown };\n if (typeof data.version === \"string\" && /^\\d/.test(data.version)) {\n return data.version;\n }\n return null;\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Resolve the current Claude Code release version for spoofing the claude-cli\n * User-Agent on OAuth and inference requests. Cached in-memory for the process\n * lifetime and on disk for 24h. Falls back to a hardcoded constant if the npm\n * registry is unreachable and no cache exists.\n */\nexport async function getClaudeCodeVersion(): Promise<string> {\n if (memoryCache && Date.now() < memoryCache.expiresAt) {\n return memoryCache.version;\n }\n if (inflight) return inflight;\n\n inflight = (async () => {\n const disk = await readDiskCache();\n const diskFresh = disk && Date.now() - disk.fetchedAt < CACHE_TTL_MS;\n if (disk && diskFresh) {\n memoryCache = { version: disk.version, expiresAt: Date.now() + CACHE_TTL_MS };\n return disk.version;\n }\n const fetched = await fetchLatest();\n if (fetched) {\n await writeDiskCache({ version: fetched, fetchedAt: Date.now() });\n memoryCache = { version: fetched, expiresAt: Date.now() + CACHE_TTL_MS };\n return fetched;\n }\n // npm unreachable — prefer stale disk cache over hardcoded fallback.\n const resolved = disk?.version ?? FALLBACK_VERSION;\n // Short TTL so we retry the npm fetch soon, but don't hammer it.\n memoryCache = { version: resolved, expiresAt: Date.now() + 5 * 60 * 1000 };\n log(\n \"WARN\",\n \"claude-code-version\",\n `Failed to fetch latest Claude Code version; using ${resolved}`,\n );\n return resolved;\n })();\n\n try {\n return await inflight;\n } finally {\n inflight = null;\n }\n}\n\n/** Build the User-Agent string Anthropic's OAuth + inference edges expect. */\nexport async function getClaudeCliUserAgent(): Promise<string> {\n const version = await getClaudeCodeVersion();\n return `claude-cli/${version} (external, cli)`;\n}\n","import fs from \"node:fs/promises\";\nimport crypto from \"node:crypto\";\nimport { getAppPaths } from \"./paths.js\";\nimport type { OAuthCredentials } from \"./oauth/types.js\";\nimport { refreshAnthropicToken } from \"./oauth/anthropic.js\";\nimport { refreshOpenAIToken } from \"./oauth/openai.js\";\nimport { refreshGeminiToken } from \"./oauth/gemini.js\";\nimport { refreshKimiToken } from \"./oauth/kimi.js\";\nimport { withFileLock } from \"./file-lock.js\";\nimport { log } from \"./logger.js\";\n\ntype AuthData = Record<string, OAuthCredentials>;\n\n/**\n * Storage key for Kimi Code OAuth credentials. Kept distinct from the\n * `moonshot` API-key entry so a user can configure BOTH and we always\n * prefer OAuth for the logical `moonshot` provider.\n */\nexport const MOONSHOT_OAUTH_KEY = \"moonshot-oauth\";\n\n/** Providers whose credentials are static API keys (no refresh mechanism). */\nconst STATIC_API_KEY_PROVIDERS = new Set([\n \"glm\",\n \"moonshot\",\n \"xiaomi\",\n \"minimax\",\n \"deepseek\",\n \"openrouter\",\n]);\n\nexport class AuthStorage {\n private data: AuthData = {};\n private filePath: string;\n private loaded = false;\n /** Per-provider lock to serialize concurrent refresh calls. */\n private refreshLocks = new Map<string, Promise<OAuthCredentials>>();\n\n constructor(filePath?: string) {\n this.filePath = filePath ?? getAppPaths().authFile;\n }\n\n /** Path to the on-disk auth file. Useful for status output. */\n get path(): string {\n return this.filePath;\n }\n\n /** List provider keys with stored credentials. */\n async listProviders(): Promise<string[]> {\n await this.ensureLoaded();\n return Object.keys(this.data);\n }\n\n /** True if credentials exist for `provider`. */\n async hasCredentials(provider: string): Promise<boolean> {\n await this.ensureLoaded();\n return Boolean(this.data[provider]);\n }\n\n /**\n * True if the user has any usable auth for the logical provider. For\n * `moonshot` this is satisfied by either the Kimi OAuth credential or the\n * Moonshot API key.\n */\n async hasProviderAuth(provider: string): Promise<boolean> {\n await this.ensureLoaded();\n if (provider === \"moonshot\") {\n return Boolean(this.data[MOONSHOT_OAUTH_KEY] || this.data[\"moonshot\"]);\n }\n return Boolean(this.data[provider]);\n }\n\n /**\n * True if the active credential for `provider` is a static API key with no\n * refresh mechanism. For `moonshot` this is only true when the Kimi OAuth\n * credential is absent (a present OAuth credential is refreshable).\n */\n async isStaticApiKey(provider: string): Promise<boolean> {\n await this.ensureLoaded();\n if (provider === \"moonshot\" && this.data[MOONSHOT_OAUTH_KEY]) {\n return false;\n }\n return STATIC_API_KEY_PROVIDERS.has(provider);\n }\n\n async load(): Promise<void> {\n await withFileLock(this.filePath, async () => {\n try {\n const content = await fs.readFile(this.filePath, \"utf-8\");\n this.data = JSON.parse(content) as AuthData;\n log(\"INFO\", \"auth\", `Loaded credentials from ${this.filePath}`, {\n providers: Object.keys(this.data).join(\",\") || \"(none)\",\n });\n } catch (err) {\n this.data = {};\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") {\n log(\"INFO\", \"auth\", `No auth file found at ${this.filePath} (first run)`);\n } else {\n log(\n \"ERROR\",\n \"auth\",\n `Failed to load auth file: ${err instanceof Error ? err.message : String(err)}`,\n { path: this.filePath, code: code ?? \"unknown\" },\n );\n }\n }\n });\n this.loaded = true;\n }\n\n private async ensureLoaded(): Promise<void> {\n if (!this.loaded) await this.load();\n }\n\n async getCredentials(provider: string): Promise<OAuthCredentials | undefined> {\n await this.ensureLoaded();\n return this.data[provider];\n }\n\n async setCredentials(provider: string, creds: OAuthCredentials): Promise<void> {\n await this.ensureLoaded();\n this.data[provider] = creds;\n await this.save();\n }\n\n async clearCredentials(provider: string): Promise<void> {\n await this.ensureLoaded();\n delete this.data[provider];\n await this.save();\n }\n\n async clearAll(): Promise<void> {\n this.data = {};\n await this.save();\n }\n\n /**\n * Returns valid credentials, auto-refreshing if expired.\n * If `forceRefresh` is true, refreshes even if the token hasn't expired\n * (useful when the provider rejects a token with 401 before its stored expiry).\n * Throws if not logged in.\n */\n async resolveCredentials(\n provider: string,\n opts?: { forceRefresh?: boolean },\n ): Promise<OAuthCredentials> {\n await this.ensureLoaded();\n\n // Prefer Kimi OAuth over the Moonshot API key for the logical `moonshot`\n // provider. When an OAuth credential exists, resolve (and refresh) that\n // instead — this is the \"default to OAuth first\" rule.\n if (provider === \"moonshot\" && this.data[MOONSHOT_OAUTH_KEY]) {\n try {\n return await this.resolveCredentials(MOONSHOT_OAUTH_KEY, opts);\n } catch (err) {\n // OAuth refresh token is dead and was wiped. Fall back to the\n // Moonshot API key if the user also configured one.\n if (err instanceof NotLoggedInError && this.data[\"moonshot\"]) {\n return this.data[\"moonshot\"];\n }\n throw err;\n }\n }\n\n const creds = this.data[provider];\n if (!creds) {\n throw new NotLoggedInError(provider);\n }\n\n // Static API-key providers have no refresh mechanism. The Kimi OAuth key\n // (MOONSHOT_OAUTH_KEY) is intentionally excluded — it refreshes below.\n if (STATIC_API_KEY_PROVIDERS.has(provider)) {\n return creds;\n }\n\n // Return if not expired and not force-refreshing\n if (!opts?.forceRefresh && Date.now() < creds.expiresAt) {\n return creds;\n }\n\n // Serialize concurrent refresh calls per provider to avoid races\n const existing = this.refreshLocks.get(provider);\n if (existing) return existing;\n\n const refreshPromise = withFileLock(this.filePath, async () => {\n // Re-read from disk in case another process refreshed while we waited for the lock\n try {\n const content = await fs.readFile(this.filePath, \"utf-8\");\n const freshData = JSON.parse(content) as AuthData;\n const freshCreds = freshData[provider];\n if (freshCreds && !opts?.forceRefresh && Date.now() < freshCreds.expiresAt) {\n // Another process already refreshed — use their token\n this.data[provider] = freshCreds;\n return freshCreds;\n }\n } catch {\n // Fall through to refresh\n }\n\n const refreshFn =\n provider === \"anthropic\"\n ? refreshAnthropicToken\n : provider === \"gemini\"\n ? refreshGeminiToken\n : provider === MOONSHOT_OAUTH_KEY\n ? refreshKimiToken\n : refreshOpenAIToken;\n let refreshed: OAuthCredentials;\n try {\n refreshed = await refreshFn(creds.refreshToken);\n } catch (err) {\n // Refresh token revoked / expired / invalid → the stored creds are\n // unusable. Wipe them so the next launch surfaces a clean\n // NotLoggedInError instead of hitting the same dead refresh path\n // every time. The user must re-login.\n const msg = err instanceof Error ? err.message : String(err);\n const isAuthFailure =\n /\\((401|400)\\)/.test(msg) ||\n /invalid_grant|invalid_token|invalid.*refresh/i.test(msg) ||\n /unauthorized/i.test(msg);\n if (isAuthFailure) {\n delete this.data[provider];\n await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));\n throw new NotLoggedInError(provider);\n }\n throw err;\n }\n if (!refreshed.accountId && creds.accountId) {\n refreshed.accountId = creds.accountId;\n }\n if (!refreshed.projectId && creds.projectId) {\n refreshed.projectId = creds.projectId;\n }\n this.data[provider] = refreshed;\n // Write atomically (we already hold the file lock)\n await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));\n return refreshed;\n });\n\n this.refreshLocks.set(provider, refreshPromise);\n try {\n return await refreshPromise;\n } finally {\n this.refreshLocks.delete(provider);\n }\n }\n\n /**\n * Returns a valid access token, auto-refreshing if expired.\n * Throws if not logged in.\n */\n async resolveToken(provider: string): Promise<string> {\n const creds = await this.resolveCredentials(provider);\n return creds.accessToken;\n }\n\n private async save(): Promise<void> {\n await withFileLock(this.filePath, async () => {\n await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));\n });\n }\n}\n\n/**\n * Atomic file write using temp file + rename pattern.\n * Prevents partial/corrupt data if the process crashes mid-write.\n */\nasync function atomicWriteFile(filePath: string, content: string): Promise<void> {\n const tmpPath = `${filePath}.${process.pid}.${Date.now()}.${crypto.randomUUID().slice(0, 8)}.tmp`;\n try {\n await fs.writeFile(tmpPath, content, { encoding: \"utf-8\", mode: 0o600 });\n await fs.rename(tmpPath, filePath);\n } catch (err) {\n await fs.unlink(tmpPath).catch(() => {});\n throw err;\n }\n}\n\nexport class NotLoggedInError extends Error {\n provider: string;\n constructor(provider: string) {\n super(`Not logged in to ${provider}. Run \"ggcoder login\" to authenticate.`);\n this.name = \"NotLoggedInError\";\n this.provider = provider;\n }\n}\n","import crypto from \"node:crypto\";\nimport { generatePKCE } from \"./pkce.js\";\nimport { getClaudeCliUserAgent } from \"../claude-code-version.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks } from \"./types.js\";\n\nconst CLIENT_ID = atob(\"OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl\");\nconst AUTHORIZE_URL = \"https://claude.ai/oauth/authorize\";\n// Anthropic migrated OAuth from console.anthropic.com to platform.claude.com\n// in Claude Code v2.1.81+. Try the new endpoint first, fall back to the old one\n// so a transient outage on either edge doesn't wipe the user's credentials.\nconst TOKEN_URLS = [\n \"https://platform.claude.com/v1/oauth/token\",\n \"https://console.anthropic.com/v1/oauth/token\",\n];\nconst REDIRECT_URI = \"https://platform.claude.com/oauth/code/callback\";\nconst SCOPES =\n \"org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload\";\n\ntype TokenResponse = {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n};\n\nasync function postTokenRequest(\n body: Record<string, string>,\n label: string,\n): Promise<TokenResponse> {\n const encoded = JSON.stringify(body);\n // Claude Code identity. Anthropic's OAuth edge intermittently rejects\n // requests without a recognized claude-cli UA + oauth beta header. Resolve\n // the UA version dynamically so it tracks real Claude Code releases.\n const headers = {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": await getClaudeCliUserAgent(),\n \"anthropic-beta\": \"oauth-2025-04-20\",\n };\n let lastError: Error | null = null;\n for (const url of TOKEN_URLS) {\n let response: Response;\n try {\n response = await fetch(url, { method: \"POST\", headers, body: encoded });\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n continue;\n }\n if (response.ok) {\n return (await response.json()) as TokenResponse;\n }\n const text = await response.text();\n // 4xx is an authoritative auth failure (invalid_grant, invalid_client, etc.)\n // — don't paper over it by trying another endpoint, the result will be the\n // same and the caller relies on this signal to wipe stale creds.\n if (response.status >= 400 && response.status < 500) {\n throw new Error(`Anthropic ${label} failed (${response.status}): ${text}`);\n }\n lastError = new Error(`Anthropic ${label} failed (${response.status}): ${text}`);\n }\n throw lastError ?? new Error(`Anthropic ${label} failed: all endpoints unreachable`);\n}\n\nfunction toCredentials(data: TokenResponse): OAuthCredentials {\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n };\n}\n\nexport async function loginAnthropic(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const { verifier, challenge } = await generatePKCE();\n const state = crypto.randomBytes(16).toString(\"hex\");\n\n const params = new URLSearchParams({\n code: \"true\",\n client_id: CLIENT_ID,\n response_type: \"code\",\n redirect_uri: REDIRECT_URI,\n scope: SCOPES,\n code_challenge: challenge,\n code_challenge_method: \"S256\",\n state,\n });\n\n const authUrl = `${AUTHORIZE_URL}?${params}`;\n callbacks.onOpenUrl(authUrl);\n\n const raw = await callbacks.onPromptCode(\"Paste the code from the browser (format: code#state):\");\n\n const parts = raw.trim().split(\"#\");\n if (parts.length !== 2 || !parts[0] || parts[1] !== state) {\n throw new Error(\"Invalid code or state mismatch. Please try again.\");\n }\n\n return exchangeAnthropicCode(parts[0], parts[1], verifier);\n}\n\nasync function exchangeAnthropicCode(\n code: string,\n state: string,\n verifier: string,\n): Promise<OAuthCredentials> {\n const data = await postTokenRequest(\n {\n grant_type: \"authorization_code\",\n client_id: CLIENT_ID,\n code,\n state,\n redirect_uri: REDIRECT_URI,\n code_verifier: verifier,\n },\n \"token exchange\",\n );\n return toCredentials(data);\n}\n\nexport async function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials> {\n const data = await postTokenRequest(\n {\n grant_type: \"refresh_token\",\n client_id: CLIENT_ID,\n refresh_token: refreshToken,\n },\n \"token refresh\",\n );\n return toCredentials(data);\n}\n","function base64urlEncode(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=/g, \"\");\n}\n\nexport async function generatePKCE(): Promise<{ verifier: string; challenge: string }> {\n const verifierBytes = new Uint8Array(32);\n crypto.getRandomValues(verifierBytes);\n const verifier = base64urlEncode(verifierBytes);\n\n const data = new TextEncoder().encode(verifier);\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n const challenge = base64urlEncode(new Uint8Array(hashBuffer));\n\n return { verifier, challenge };\n}\n","import http from \"node:http\";\nimport crypto from \"node:crypto\";\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks } from \"./types.js\";\n\nconst CLIENT_ID = \"app_EMoamEEZ73f0CkXaXp7hrann\";\nconst AUTHORIZE_URL = \"https://auth.openai.com/oauth/authorize\";\nconst TOKEN_URL = \"https://auth.openai.com/oauth/token\";\nconst REDIRECT_URI = \"http://localhost:1455/auth/callback\";\nconst SCOPE = \"openid profile email offline_access api.connectors.read api.connectors.invoke\";\nconst JWT_CLAIM_PATH = \"https://api.openai.com/auth\";\n\nexport async function loginOpenAI(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const { verifier, challenge } = await generatePKCE();\n const state = crypto.randomBytes(16).toString(\"hex\");\n\n const url = new URL(AUTHORIZE_URL);\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"client_id\", CLIENT_ID);\n url.searchParams.set(\"redirect_uri\", REDIRECT_URI);\n url.searchParams.set(\"scope\", SCOPE);\n url.searchParams.set(\"code_challenge\", challenge);\n url.searchParams.set(\"code_challenge_method\", \"S256\");\n url.searchParams.set(\"state\", state);\n url.searchParams.set(\"id_token_add_organizations\", \"true\");\n url.searchParams.set(\"codex_cli_simplified_flow\", \"true\");\n url.searchParams.set(\"originator\", \"ggcoder\");\n\n let code: string;\n\n try {\n code = await loginWithServer(url.toString(), state, callbacks);\n } catch {\n // Fallback: manual code paste\n callbacks.onOpenUrl(url.toString());\n const raw = await callbacks.onPromptCode(\n \"Could not start local server. Paste the callback URL or code from the browser:\",\n );\n const parsed = parseAuthorizationInput(raw);\n if (!parsed.code) {\n throw new Error(\"No authorization code found in input.\");\n }\n code = parsed.code;\n }\n\n const creds = await exchangeOpenAICode(code, verifier);\n\n const accountId = getAccountId(creds.accessToken);\n if (!accountId) {\n throw new Error(\"Failed to extract accountId from OpenAI token.\");\n }\n creds.accountId = accountId;\n\n return creds;\n}\n\nfunction parseAuthorizationInput(input: string): { code?: string; state?: string } {\n const value = input.trim();\n if (!value) return {};\n\n // Full URL\n try {\n const url = new URL(value);\n return {\n code: url.searchParams.get(\"code\") ?? undefined,\n state: url.searchParams.get(\"state\") ?? undefined,\n };\n } catch {\n // not a URL\n }\n\n // code#state\n if (value.includes(\"#\")) {\n const [code, state] = value.split(\"#\", 2);\n return { code, state };\n }\n\n // Query string with code=\n if (value.includes(\"code=\")) {\n const params = new URLSearchParams(value);\n return {\n code: params.get(\"code\") ?? undefined,\n state: params.get(\"state\") ?? undefined,\n };\n }\n\n // Raw code\n return { code: value };\n}\n\nfunction decodeJwt(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) return null;\n const decoded = atob(parts[1]);\n return JSON.parse(decoded) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nfunction getAccountId(accessToken: string): string | null {\n const payload = decodeJwt(accessToken);\n const auth = payload?.[JWT_CLAIM_PATH] as { chatgpt_account_id?: string } | undefined;\n const accountId = auth?.chatgpt_account_id;\n return typeof accountId === \"string\" && accountId.length > 0 ? accountId : null;\n}\n\nasync function loginWithServer(\n authUrl: string,\n expectedState: string,\n callbacks: OAuthLoginCallbacks,\n): Promise<string> {\n return new Promise<string>((resolve, reject) => {\n let receivedCode: string | null = null;\n\n const server = http.createServer((req, res) => {\n const url = new URL(req.url || \"\", \"http://localhost\");\n\n if (url.pathname !== \"/auth/callback\") {\n res.statusCode = 404;\n res.end(\"Not found\");\n return;\n }\n\n if (url.searchParams.get(\"state\") !== expectedState) {\n res.statusCode = 400;\n res.end(\"State mismatch\");\n return;\n }\n\n receivedCode = url.searchParams.get(\"code\");\n\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(\"<html><body><h1>Login successful!</h1><p>You can close this tab.</p></body></html>\");\n\n server.close();\n });\n\n server.on(\"error\", (err) => {\n reject(err);\n });\n\n server.listen(1455, \"127.0.0.1\", () => {\n callbacks.onOpenUrl(authUrl);\n callbacks.onStatus(\"Waiting for browser callback...\");\n });\n\n const timeout = setTimeout(() => {\n if (!receivedCode) {\n server.close();\n }\n }, 120_000);\n timeout.unref();\n\n server.on(\"close\", () => {\n clearTimeout(timeout);\n if (receivedCode) {\n resolve(receivedCode);\n } else {\n reject(new Error(\"Server closed without receiving code\"));\n }\n });\n });\n}\n\nasync function exchangeOpenAICode(code: string, verifier: string): Promise<OAuthCredentials> {\n const response = await fetch(TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"authorization_code\",\n client_id: CLIENT_ID,\n code,\n redirect_uri: REDIRECT_URI,\n code_verifier: verifier,\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`OpenAI token exchange failed (${response.status}): ${text}`);\n }\n\n const data = (await response.json()) as {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n };\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: Date.now() + data.expires_in * 1000,\n };\n}\n\nexport async function refreshOpenAIToken(refreshToken: string): Promise<OAuthCredentials> {\n const response = await fetch(TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n client_id: CLIENT_ID,\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`OpenAI token refresh failed (${response.status}): ${text}`);\n }\n\n const data = (await response.json()) as {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n };\n\n const creds: OAuthCredentials = {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: Date.now() + data.expires_in * 1000,\n };\n\n const accountId = getAccountId(creds.accessToken);\n if (accountId) {\n creds.accountId = accountId;\n }\n\n return creds;\n}\n","import http from \"node:http\";\nimport crypto from \"node:crypto\";\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks } from \"./types.js\";\n\nconst CLIENT_ID_ENV = \"GGCODER_GEMINI_OAUTH_CLIENT_ID\";\nconst CLIENT_SECRET_ENV = \"GGCODER_GEMINI_OAUTH_CLIENT_SECRET\";\n// Public \"installed application\" OAuth client shipped with the official Gemini CLI.\n// Unlike the OpenAI/Anthropic flows (pure PKCE, no secret), Google's token endpoint\n// requires a client_secret for the installed-app authorization_code / refresh_token\n// grants — so it must be embedded to support local login like the other providers.\n// This is the published gemini-cli installed-app secret (non-confidential by design);\n// the env vars above override it for users who bring their own Google Cloud client.\nconst DEFAULT_CLIENT_ID =\n \"681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com\";\nconst DEFAULT_CLIENT_SECRET = \"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\";\nconst AUTHORIZE_URL = \"https://accounts.google.com/o/oauth2/v2/auth\";\nconst TOKEN_URL = \"https://oauth2.googleapis.com/token\";\nconst CODE_ASSIST_BASE_URL = \"https://cloudcode-pa.googleapis.com\";\nconst CODE_ASSIST_API_VERSION = \"v1internal\";\nconst CODE_ASSIST_POST_RETRIES = 3;\nconst CODE_ASSIST_POST_RETRY_DELAY_MS = 100;\nconst SCOPE = [\n \"https://www.googleapis.com/auth/cloud-platform\",\n \"https://www.googleapis.com/auth/userinfo.email\",\n \"https://www.googleapis.com/auth/userinfo.profile\",\n].join(\" \");\n\ninterface GoogleTokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in: number;\n}\n\ninterface GeminiOAuthClientCredentials {\n clientId: string;\n clientSecret: string;\n}\n\ninterface CodeAssistLoadResponse {\n currentTier?: GeminiUserTier | null;\n allowedTiers?: GeminiUserTier[] | null;\n ineligibleTiers?: IneligibleTier[] | null;\n cloudaicompanionProject?: string | null;\n paidTier?: GeminiUserTier | null;\n}\n\ninterface GeminiUserTier {\n id?: string;\n name?: string;\n isDefault?: boolean;\n}\n\ninterface IneligibleTier {\n reasonCode?: string;\n reasonMessage?: string;\n tierName?: string;\n validationUrl?: string;\n}\n\ninterface LongRunningOperationResponse {\n name?: string;\n done?: boolean;\n response?: {\n cloudaicompanionProject?: {\n id?: string;\n name?: string;\n };\n };\n}\n\nconst USER_TIER_FREE = \"free-tier\";\nconst USER_TIER_LEGACY = \"legacy-tier\";\nconst USER_TIER_STANDARD = \"standard-tier\";\nconst VALIDATION_REQUIRED_REASON = \"VALIDATION_REQUIRED\";\nconst VPC_SC_REASON = \"SECURITY_POLICY_VIOLATED\";\n\nclass CodeAssistHttpError extends Error {\n readonly status: number;\n readonly body: string;\n\n constructor(label: string, status: number, body: string) {\n super(`Gemini Code Assist ${label} failed (${status}): ${body}`);\n this.name = \"CodeAssistHttpError\";\n this.status = status;\n this.body = body;\n }\n}\n\nexport async function loginGemini(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const { clientId, clientSecret } = getGeminiOAuthClientCredentials();\n const { verifier, challenge } = await generatePKCE();\n const state = crypto.randomBytes(32).toString(\"hex\");\n const redirectUri = await getLoopbackRedirectUri();\n\n const url = new URL(AUTHORIZE_URL);\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"client_id\", clientId);\n url.searchParams.set(\"redirect_uri\", redirectUri);\n url.searchParams.set(\"scope\", SCOPE);\n url.searchParams.set(\"access_type\", \"offline\");\n url.searchParams.set(\"prompt\", \"consent\");\n url.searchParams.set(\"code_challenge\", challenge);\n url.searchParams.set(\"code_challenge_method\", \"S256\");\n url.searchParams.set(\"state\", state);\n\n let code: string;\n try {\n code = await loginWithServer(url.toString(), redirectUri, state, callbacks);\n } catch {\n callbacks.onOpenUrl(url.toString());\n const raw = await callbacks.onPromptCode(\n \"Could not start local server. Paste the callback URL or code from the browser:\",\n );\n const parsed = parseAuthorizationInput(raw);\n if (!parsed.code) {\n throw new Error(\"No authorization code found in input.\");\n }\n if (parsed.state && parsed.state !== state) {\n throw new Error(\"Invalid state. Please try again.\");\n }\n code = parsed.code;\n }\n\n const creds = await exchangeGeminiCode(code, verifier, redirectUri, clientId, clientSecret);\n callbacks.onStatus(\"Setting up Gemini Code Assist access...\");\n const projectId = await setupCodeAssistProject(creds.accessToken, callbacks);\n\n return {\n ...creds,\n projectId,\n };\n}\n\nexport async function refreshGeminiToken(refreshToken: string): Promise<OAuthCredentials> {\n const { clientId, clientSecret } = getGeminiOAuthClientCredentials();\n const data = await postTokenRequest({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n client_id: clientId,\n client_secret: clientSecret,\n });\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token ?? refreshToken,\n expiresAt: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n };\n}\n\nfunction getGeminiOAuthClientCredentials(): GeminiOAuthClientCredentials {\n const clientId = process.env[CLIENT_ID_ENV]?.trim() || DEFAULT_CLIENT_ID;\n const clientSecret = process.env[CLIENT_SECRET_ENV]?.trim() || DEFAULT_CLIENT_SECRET;\n return { clientId, clientSecret };\n}\n\nasync function getLoopbackRedirectUri(): Promise<string> {\n return new Promise((resolve, reject) => {\n const server = http.createServer();\n server.listen(0, \"127.0.0.1\", () => {\n const addr = server.address();\n server.close(() => {\n if (addr && typeof addr === \"object\") {\n resolve(`http://127.0.0.1:${addr.port}/oauth2callback`);\n } else {\n reject(new Error(\"Failed to allocate OAuth callback port.\"));\n }\n });\n });\n server.on(\"error\", reject);\n });\n}\n\nfunction parseAuthorizationInput(input: string): { code?: string; state?: string } {\n const value = input.trim();\n if (!value) return {};\n\n try {\n const url = new URL(value);\n return {\n code: url.searchParams.get(\"code\") ?? undefined,\n state: url.searchParams.get(\"state\") ?? undefined,\n };\n } catch {\n // not a URL\n }\n\n if (value.includes(\"code=\")) {\n const params = new URLSearchParams(value);\n return {\n code: params.get(\"code\") ?? undefined,\n state: params.get(\"state\") ?? undefined,\n };\n }\n\n return { code: value };\n}\n\nasync function loginWithServer(\n authUrl: string,\n redirectUri: string,\n expectedState: string,\n callbacks: OAuthLoginCallbacks,\n): Promise<string> {\n const redirect = new URL(redirectUri);\n const port = Number(redirect.port);\n\n return new Promise<string>((resolve, reject) => {\n let receivedCode: string | null = null;\n\n const server = http.createServer((req, res) => {\n const url = new URL(req.url || \"\", redirect.origin);\n\n if (url.pathname !== redirect.pathname) {\n res.statusCode = 404;\n res.end(\"Not found\");\n return;\n }\n\n if (url.searchParams.get(\"state\") !== expectedState) {\n res.statusCode = 400;\n res.end(\"State mismatch\");\n return;\n }\n\n receivedCode = url.searchParams.get(\"code\");\n res.writeHead(200, { \"Content-Type\": \"text/html\", Connection: \"close\" });\n res.end(\"<html><body><h1>Login successful!</h1><p>You can close this tab.</p></body></html>\");\n server.close();\n });\n\n server.on(\"error\", (err) => reject(err));\n server.listen(port, \"127.0.0.1\", () => {\n callbacks.onOpenUrl(authUrl);\n callbacks.onStatus(\"Waiting for browser callback...\");\n });\n\n const timeout = setTimeout(() => {\n if (!receivedCode) server.close();\n }, 120_000);\n timeout.unref();\n\n server.on(\"close\", () => {\n clearTimeout(timeout);\n if (receivedCode) {\n resolve(receivedCode);\n } else {\n reject(new Error(\"Server closed without receiving code.\"));\n }\n });\n });\n}\n\nasync function exchangeGeminiCode(\n code: string,\n verifier: string,\n redirectUri: string,\n clientId: string,\n clientSecret: string,\n): Promise<OAuthCredentials> {\n const data = await postTokenRequest({\n grant_type: \"authorization_code\",\n client_id: clientId,\n client_secret: clientSecret,\n code,\n redirect_uri: redirectUri,\n code_verifier: verifier,\n });\n\n if (!data.refresh_token) {\n throw new Error(\"Gemini OAuth did not return a refresh token. Please try login again.\");\n }\n\n return {\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n };\n}\n\nasync function postTokenRequest(body: Record<string, string>): Promise<GoogleTokenResponse> {\n const response = await fetch(TOKEN_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams(body),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Gemini token request failed (${response.status}): ${text}`);\n }\n\n return (await response.json()) as GoogleTokenResponse;\n}\n\nasync function setupCodeAssistProject(\n accessToken: string,\n callbacks: OAuthLoginCallbacks,\n): Promise<string> {\n const envProject = process.env.GOOGLE_CLOUD_PROJECT ?? process.env.GOOGLE_CLOUD_PROJECT_ID;\n if (envProject && /^\\d+$/.test(envProject)) {\n throw new Error(\"GOOGLE_CLOUD_PROJECT must be a project ID, not a numeric project number.\");\n }\n\n const coreMetadata = {\n ideType: \"IDE_UNSPECIFIED\",\n platform: \"PLATFORM_UNSPECIFIED\",\n pluginType: \"GEMINI\",\n };\n const projectMetadata = {\n ...coreMetadata,\n ...(envProject ? { duetProject: envProject } : {}),\n };\n\n let loadRes: CodeAssistLoadResponse;\n while (true) {\n loadRes = await loadCodeAssist(accessToken, envProject, projectMetadata);\n const validation = getValidationRequiredTier(loadRes);\n if (!validation) break;\n\n callbacks.onStatus(\n `Gemini Code Assist requires account validation${\n validation.reasonMessage ? `: ${validation.reasonMessage}` : \"\"\n }`,\n );\n callbacks.onOpenUrl(validation.validationUrl);\n const answer = await callbacks.onPromptCode(\n \"Complete validation in the browser, then press Enter to retry (or type cancel):\",\n );\n if (answer.trim().toLowerCase() === \"cancel\") {\n throw new Error(\"Gemini Code Assist account validation was cancelled.\");\n }\n }\n\n if (loadRes.currentTier) {\n const project = loadRes.cloudaicompanionProject ?? envProject;\n if (!project) throwProjectError(loadRes);\n return project;\n }\n\n const tier = getOnboardTier(loadRes);\n const onboardReq =\n tier.id === USER_TIER_FREE\n ? {\n tierId: tier.id,\n cloudaicompanionProject: undefined,\n metadata: coreMetadata,\n }\n : {\n tierId: tier.id,\n cloudaicompanionProject: envProject,\n metadata: projectMetadata,\n };\n\n let operation = await codeAssistPost<LongRunningOperationResponse>(\n accessToken,\n \"onboardUser\",\n onboardReq,\n );\n\n while (!operation.done && operation.name) {\n await new Promise((resolve) => setTimeout(resolve, 5_000));\n operation = await codeAssistGet<LongRunningOperationResponse>(accessToken, operation.name);\n }\n\n const project = operation.response?.cloudaicompanionProject?.id ?? envProject;\n if (!project) throwProjectError(loadRes);\n return project;\n}\n\nasync function loadCodeAssist(\n accessToken: string,\n envProject: string | undefined,\n metadata: Record<string, string>,\n): Promise<CodeAssistLoadResponse> {\n try {\n return await codeAssistPost<CodeAssistLoadResponse>(accessToken, \"loadCodeAssist\", {\n ...(envProject ? { cloudaicompanionProject: envProject } : {}),\n metadata,\n });\n } catch (err) {\n if (err instanceof CodeAssistHttpError && isVpcScAffectedError(err)) {\n return { currentTier: { id: USER_TIER_STANDARD } };\n }\n if (\n err instanceof CodeAssistHttpError &&\n err.status === 403 &&\n envProject === \"cloudshell-gca\"\n ) {\n throw new Error(\n \"Access to the default Cloud Shell Gemini project was denied.\\n\" +\n \"Please set your own Google Cloud project by running:\\n\" +\n \"gcloud config set project [PROJECT_ID]\\n\" +\n \"or setting export GOOGLE_CLOUD_PROJECT=...\",\n { cause: err },\n );\n }\n throw err;\n }\n}\n\nfunction getValidationRequiredTier(\n response: CodeAssistLoadResponse,\n): (IneligibleTier & { validationUrl: string }) | undefined {\n return response.ineligibleTiers?.find(\n (tier): tier is IneligibleTier & { validationUrl: string } =>\n tier.reasonCode === VALIDATION_REQUIRED_REASON && typeof tier.validationUrl === \"string\",\n );\n}\n\nfunction getOnboardTier(response: CodeAssistLoadResponse): GeminiUserTier {\n const defaultTier = response.allowedTiers?.find((tier) => tier.isDefault);\n return defaultTier ?? { id: USER_TIER_LEGACY, name: \"\" };\n}\n\nfunction throwProjectError(response: CodeAssistLoadResponse): never {\n const reasons = response.ineligibleTiers\n ?.map((tier) => tier.reasonMessage ?? tier.tierName)\n .filter((reason): reason is string => Boolean(reason));\n if (reasons && reasons.length > 0) {\n throw new Error(`Gemini Code Assist setup failed: ${reasons.join(\", \")}`);\n }\n throw new Error(\n \"Gemini requires a Google Cloud project for this account. Set GOOGLE_CLOUD_PROJECT and try again.\",\n );\n}\n\nasync function codeAssistPost<T>(\n accessToken: string,\n method: string,\n body: Record<string, unknown>,\n): Promise<T> {\n let lastError: Error | undefined;\n for (let attempt = 0; attempt <= CODE_ASSIST_POST_RETRIES; attempt++) {\n try {\n return await codeAssistRequest<T>(getCodeAssistMethodUrl(method), accessToken, method, {\n method: \"POST\",\n body: JSON.stringify(body),\n });\n } catch (err) {\n if (\n !(err instanceof CodeAssistHttpError) ||\n attempt === CODE_ASSIST_POST_RETRIES ||\n !shouldRetryCodeAssistStatus(err.status)\n ) {\n throw err;\n }\n lastError = err;\n }\n await new Promise((resolve) => setTimeout(resolve, CODE_ASSIST_POST_RETRY_DELAY_MS));\n }\n\n throw lastError ?? new Error(`Gemini Code Assist ${method} failed.`);\n}\n\nasync function codeAssistGet<T>(accessToken: string, operationName: string): Promise<T> {\n return codeAssistRequest<T>(getCodeAssistOperationUrl(operationName), accessToken, \"operation\", {\n method: \"GET\",\n });\n}\n\nasync function codeAssistRequest<T>(\n url: string,\n accessToken: string,\n label: string,\n init: Pick<RequestInit, \"method\" | \"body\">,\n): Promise<T> {\n const response = await fetch(url, {\n ...init,\n headers: codeAssistHeaders(accessToken),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new CodeAssistHttpError(label, response.status, text);\n }\n\n return (await response.json()) as T;\n}\n\nfunction getCodeAssistBaseUrl(): string {\n const endpoint = process.env.CODE_ASSIST_ENDPOINT ?? CODE_ASSIST_BASE_URL;\n const version = process.env.CODE_ASSIST_API_VERSION || CODE_ASSIST_API_VERSION;\n return `${endpoint}/${version}`;\n}\n\nfunction getCodeAssistMethodUrl(method: string): string {\n return `${getCodeAssistBaseUrl()}:${method}`;\n}\n\nfunction getCodeAssistOperationUrl(operationName: string): string {\n return `${getCodeAssistBaseUrl()}/${operationName}`;\n}\n\nfunction shouldRetryCodeAssistStatus(status: number): boolean {\n return status === 429 || status === 499 || (status >= 500 && status <= 599);\n}\n\nfunction isVpcScAffectedError(error: CodeAssistHttpError): boolean {\n try {\n const parsed = JSON.parse(error.body) as unknown;\n if (!parsed || typeof parsed !== \"object\" || !(\"error\" in parsed)) return false;\n const details = (parsed as { error?: { details?: unknown[] } }).error?.details;\n return Array.isArray(details)\n ? details.some(\n (detail) =>\n detail != null &&\n typeof detail === \"object\" &&\n \"reason\" in detail &&\n detail.reason === VPC_SC_REASON,\n )\n : false;\n } catch {\n return false;\n }\n}\n\nfunction codeAssistHeaders(accessToken: string): Record<string, string> {\n return {\n Authorization: `Bearer ${accessToken}`,\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"google-gemini-cli\",\n \"X-Goog-Api-Client\": \"gemini-cli/0.0.0\",\n };\n}\n","/**\n * Kimi Code OAuth — Device Authorization Grant (RFC 8628).\n *\n * Mirrors MoonshotAI/kimi-code's managed-auth flow. Three form-encoded\n * POST endpoints against the OAuth host (default `https://auth.kimi.com`):\n *\n * - `/api/oauth/device_authorization` (client_id) → device + user code\n * - `/api/oauth/token` (grant_type=device_code) → poll until authorized\n * - `/api/oauth/token` (grant_type=refresh_token) → refresh access token\n *\n * Unlike Anthropic/OpenAI/Gemini (browser-redirect PKCE), this is a\n * device-code/poll flow: we show the user a URL + code, they authorize in a\n * browser on any device, and we poll for the token.\n *\n * After login the issued token is used against the managed coding API\n * (`https://api.kimi.com/coding/v1`, distinct from the `api.moonshot.ai`\n * API-key endpoint) via `Authorization: Bearer <access_token>`. We persist\n * that base URL on the credential so the runtime routes there automatically.\n */\n\nimport { execFileSync } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { arch, hostname, release, type } from \"node:os\";\nimport path from \"node:path\";\n\nimport { getAppPaths } from \"../paths.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks } from \"./types.js\";\n\n/** Public OAuth client id registered by Kimi Code (no client secret / PKCE). */\nconst CLIENT_ID = \"17e5f671-d194-4dfb-9706-5516cb48c098\";\n\nconst DEFAULT_OAUTH_HOST = \"https://auth.kimi.com\";\nconst DEFAULT_CODING_BASE_URL = \"https://api.kimi.com/coding/v1\";\n\n/** Platform identifier Kimi Code reports for the device flow. */\nconst KIMI_PLATFORM = \"kimi_code_cli\";\n// Must match (or exceed) the current published `kimi-code` CLI version. The\n// managed coding endpoint gates on the `kimi-code-cli` client identity and\n// REJECTS versions below its expected minimum with a 403 \"only available for\n// Coding Agents\". Keep aligned with the latest npm `kimi-code` release;\n// overridable via KIMI_CODE_VERSION.\nconst DEFAULT_KIMI_VERSION = \"1.0.11\";\n\n/** Local wall-clock budget for the whole device flow (15 min, matches Kimi). */\nconst DEVICE_TIMEOUT_MS = 15 * 60 * 1000;\n\nfunction oauthHost(): string {\n const host =\n process.env.KIMI_CODE_OAUTH_HOST ?? process.env.KIMI_OAUTH_HOST ?? DEFAULT_OAUTH_HOST;\n return host.replace(/\\/+$/, \"\");\n}\n\n/** Managed coding API base URL the issued OAuth token is used against. */\nexport function kimiCodeBaseUrl(): string {\n return (process.env.KIMI_CODE_BASE_URL ?? DEFAULT_CODING_BASE_URL).replace(/\\/+$/, \"\");\n}\n\nfunction kimiVersion(): string {\n const v = process.env.KIMI_CODE_VERSION ?? DEFAULT_KIMI_VERSION;\n return asciiHeader(v, DEFAULT_KIMI_VERSION);\n}\n\nfunction asciiHeader(value: string, fallback = \"unknown\"): string {\n const cleaned = value.replace(/[^\\u0020-\\u007E]/g, \"\").trim();\n return cleaned.length > 0 ? cleaned : fallback;\n}\n\nfunction macOsProductVersion(): string | undefined {\n try {\n const version = execFileSync(\"/usr/bin/sw_vers\", [\"-productVersion\"], {\n encoding: \"utf-8\",\n timeout: 1000,\n }).trim();\n return version.length > 0 ? version : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction deviceModel(): string {\n const os = type();\n const version = release();\n const osArch = arch();\n if (os === \"Darwin\") return `macOS ${macOsProductVersion() ?? version} ${osArch}`;\n if (os === \"Windows_NT\") return `Windows ${version} ${osArch}`;\n return `${os} ${version} ${osArch}`.trim();\n}\n\n/** Stable per-machine device id, persisted under the gg config dir. */\nfunction deviceId(): string {\n const idPath = path.join(getAppPaths().agentDir, \"kimi_device_id\");\n if (existsSync(idPath)) {\n try {\n const text = readFileSync(idPath, \"utf-8\").trim();\n if (text.length > 0) return text;\n } catch {\n // fall through to regenerate\n }\n }\n const id = randomUUID();\n try {\n mkdirSync(getAppPaths().agentDir, { recursive: true, mode: 0o700 });\n writeFileSync(idPath, id, { encoding: \"utf-8\", mode: 0o600 });\n } catch {\n // best-effort: in-memory id still works for this run\n }\n return id;\n}\n\nfunction deviceHeaders(): Record<string, string> {\n return {\n \"X-Msh-Platform\": KIMI_PLATFORM,\n \"X-Msh-Version\": kimiVersion(),\n \"X-Msh-Device-Name\": asciiHeader(hostname()),\n \"X-Msh-Device-Model\": asciiHeader(deviceModel()),\n \"X-Msh-Os-Version\": asciiHeader(release()),\n \"X-Msh-Device-Id\": deviceId(),\n };\n}\n\n/**\n * Headers the Kimi For Coding API requires on every model request. The\n * managed endpoint gates access to recognized coding agents: requests must\n * carry a `kimi_code_cli` platform identity and matching `User-Agent`, or the\n * server rejects with \"only available for Coding Agents\". Attach these to the\n * inference client's default headers whenever the Kimi OAuth token is used.\n */\nexport function kimiCodingHeaders(): Record<string, string> {\n return {\n \"User-Agent\": `kimi-code-cli/${kimiVersion()}`,\n ...deviceHeaders(),\n };\n}\n\n/**\n * True if `baseUrl` targets the Kimi For Coding managed endpoint (the URL\n * persisted on Kimi OAuth credentials). Callers use this to decide whether to\n * attach `kimiCodingHeaders()` — the Moonshot API-key path uses a different\n * host and must NOT receive the coding-agent identity headers.\n */\nexport function isKimiCodingEndpoint(baseUrl: string | undefined): boolean {\n if (typeof baseUrl !== \"string\" || baseUrl.length === 0) return false;\n const normalized = baseUrl.replace(/\\/+$/, \"\");\n return normalized === kimiCodeBaseUrl() || /(^|\\.)kimi\\.com/i.test(normalized);\n}\n\nasync function postForm(\n endpoint: string,\n params: Record<string, string>,\n): Promise<{ status: number; data: Record<string, unknown> }> {\n const response = await fetch(`${oauthHost()}${endpoint}`, {\n method: \"POST\",\n headers: {\n ...deviceHeaders(),\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n Accept: \"application/json\",\n },\n body: new URLSearchParams(params).toString(),\n });\n let data: Record<string, unknown> = {};\n try {\n const parsed: unknown = await response.json();\n if (parsed && typeof parsed === \"object\") data = parsed as Record<string, unknown>;\n } catch {\n // non-JSON response — interpret by status\n }\n return { status: response.status, data };\n}\n\nfunction errorDetail(data: Record<string, unknown>): string {\n const desc = data.error_description ?? data.message ?? data.error;\n return typeof desc === \"string\" && desc.length > 0 ? desc : \"unknown error\";\n}\n\nfunction credsFromTokenResponse(data: Record<string, unknown>): OAuthCredentials {\n const accessToken = data.access_token;\n const refreshToken = data.refresh_token;\n const expiresIn = Number(data.expires_in);\n if (typeof accessToken !== \"string\" || accessToken.length === 0) {\n throw new Error(\"Kimi OAuth response missing access_token.\");\n }\n if (typeof refreshToken !== \"string\" || refreshToken.length === 0) {\n throw new Error(\"Kimi OAuth response missing refresh_token.\");\n }\n if (!Number.isFinite(expiresIn) || expiresIn <= 0) {\n throw new Error(\"Kimi OAuth response missing or invalid expires_in.\");\n }\n return {\n accessToken,\n refreshToken,\n expiresAt: Date.now() + expiresIn * 1000,\n baseUrl: kimiCodeBaseUrl(),\n };\n}\n\ninterface DeviceAuthorization {\n userCode: string;\n deviceCode: string;\n verificationUri: string;\n verificationUriComplete: string;\n interval: number;\n}\n\nasync function requestDeviceAuthorization(): Promise<DeviceAuthorization> {\n const { status, data } = await postForm(\"/api/oauth/device_authorization\", {\n client_id: CLIENT_ID,\n });\n if (status !== 200) {\n throw new Error(`Kimi device authorization failed (${status}): ${errorDetail(data)}`);\n }\n const userCode = data.user_code;\n const deviceCode = data.device_code;\n const verificationUriComplete = data.verification_uri_complete;\n if (typeof userCode !== \"string\" || typeof deviceCode !== \"string\") {\n throw new Error(\"Kimi device authorization response missing user_code/device_code.\");\n }\n return {\n userCode,\n deviceCode,\n verificationUri: typeof data.verification_uri === \"string\" ? data.verification_uri : \"\",\n verificationUriComplete:\n typeof verificationUriComplete === \"string\" ? verificationUriComplete : \"\",\n interval: Number(data.interval ?? 5) || 5,\n };\n}\n\ntype PollResult =\n | { kind: \"success\"; creds: OAuthCredentials }\n | { kind: \"pending\" }\n | { kind: \"slow_down\" }\n | { kind: \"expired\" }\n | { kind: \"denied\" };\n\nasync function pollDeviceToken(deviceCode: string): Promise<PollResult> {\n const { status, data } = await postForm(\"/api/oauth/token\", {\n client_id: CLIENT_ID,\n device_code: deviceCode,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n });\n if (status === 200 && typeof data.access_token === \"string\") {\n return { kind: \"success\", creds: credsFromTokenResponse(data) };\n }\n if (status >= 500) {\n throw new Error(`Kimi token polling server error (${status}): ${errorDetail(data)}`);\n }\n const errorCode = typeof data.error === \"string\" ? data.error : \"unknown_error\";\n switch (errorCode) {\n case \"authorization_pending\":\n return { kind: \"pending\" };\n case \"slow_down\":\n return { kind: \"slow_down\" };\n case \"expired_token\":\n return { kind: \"expired\" };\n case \"access_denied\":\n return { kind: \"denied\" };\n default:\n throw new Error(`Kimi token polling failed (${status}): ${errorDetail(data)}`);\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\n/**\n * Drive the Kimi device-code flow end-to-end. Shows the verification URL +\n * user code via callbacks, opens the browser, and polls until the user\n * authorizes (or a 15-minute local timeout elapses).\n */\nexport async function loginKimi(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const auth = await requestDeviceAuthorization();\n\n callbacks.onStatus(\n `Visit ${auth.verificationUri || auth.verificationUriComplete} and enter code: ${auth.userCode}`,\n );\n callbacks.onOpenUrl(auth.verificationUriComplete || auth.verificationUri);\n callbacks.onStatus(\"Waiting for you to authorize in the browser...\");\n\n const deadline = Date.now() + DEVICE_TIMEOUT_MS;\n let interval = Math.max(auth.interval, 1);\n\n while (Date.now() < deadline) {\n await sleep(interval * 1000);\n const result = await pollDeviceToken(auth.deviceCode);\n if (result.kind === \"success\") return result.creds;\n if (result.kind === \"denied\") {\n throw new Error(\"Kimi authorization was denied.\");\n }\n if (result.kind === \"expired\") {\n throw new Error(\"Kimi device code expired. Please run login again.\");\n }\n if (result.kind === \"slow_down\") {\n interval += 5;\n }\n // pending → keep polling\n }\n\n throw new Error(\"Kimi login timed out. Please run login again.\");\n}\n\n/** Exchange a refresh token for a fresh Kimi access token. */\nexport async function refreshKimiToken(refreshToken: string): Promise<OAuthCredentials> {\n const { status, data } = await postForm(\"/api/oauth/token\", {\n client_id: CLIENT_ID,\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n });\n if (status === 200 && typeof data.access_token === \"string\") {\n return credsFromTokenResponse(data);\n }\n const errorCode = typeof data.error === \"string\" ? data.error : \"\";\n // Surface 401/403/invalid_grant in a shape AuthStorage's refresh-failure\n // detection recognizes, so dead refresh tokens get wiped for re-login.\n throw new Error(`Kimi token refresh failed (${status}): ${errorCode || errorDetail(data)}`);\n}\n","/**\n * Minimal Telegram Bot API client using raw fetch().\n * Supports long polling, markdown messages, inline keyboards, and message splitting.\n */\n\nconst TELEGRAM_API = \"https://api.telegram.org\";\nconst MAX_MESSAGE_LENGTH = 4096;\n\nexport interface TelegramConfig {\n botToken: string;\n /** Only accept messages from this Telegram user ID. */\n allowedUserId: number;\n}\n\nexport interface TelegramUpdate {\n update_id: number;\n message?: {\n message_id: number;\n from: { id: number; first_name: string };\n chat: { id: number; type: string; title?: string };\n text?: string;\n voice?: { file_id: string; duration: number; mime_type?: string; file_size?: number };\n };\n callback_query?: {\n id: string;\n from: { id: number };\n message: { chat: { id: number } };\n data: string;\n };\n my_chat_member?: {\n chat: { id: number; type: string; title?: string };\n from: { id: number };\n new_chat_member: { status: string };\n };\n}\n\nexport interface InlineButton {\n text: string;\n callback_data: string;\n}\n\n/** Incoming message with chat context. */\nexport interface TelegramMessage {\n text: string;\n chatId: number;\n chatType: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n chatTitle?: string;\n}\n\n/** Incoming voice note with chat context. */\nexport interface TelegramVoiceMessage {\n fileId: string;\n duration: number;\n chatId: number;\n chatType: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n chatTitle?: string;\n}\n\nexport class TelegramBot {\n private token: string;\n private allowedUserId: number;\n private offset = 0;\n private running = false;\n\n private onMessage: ((msg: TelegramMessage) => void) | null = null;\n private onVoiceMessage: ((msg: TelegramVoiceMessage) => void) | null = null;\n private onCallback: ((data: string, chatId: number) => void) | null = null;\n private onBotAdded: ((chatId: number, chatTitle?: string) => void) | null = null;\n private onBotRemoved: ((chatId: number) => void) | null = null;\n\n constructor(config: TelegramConfig) {\n this.token = config.botToken;\n this.allowedUserId = config.allowedUserId;\n }\n\n /** Register handler for incoming text messages. */\n onText(handler: (msg: TelegramMessage) => void): void {\n this.onMessage = handler;\n }\n\n /** Register handler for incoming voice notes. */\n onVoice(handler: (msg: TelegramVoiceMessage) => void): void {\n this.onVoiceMessage = handler;\n }\n\n /** Register handler for inline keyboard button presses. */\n onCallbackQuery(handler: (data: string, chatId: number) => void): void {\n this.onCallback = handler;\n }\n\n /** Register handler for when the bot is added to a group. */\n onAddedToGroup(handler: (chatId: number, chatTitle?: string) => void): void {\n this.onBotAdded = handler;\n }\n\n /** Register handler for when the bot is removed from a group. */\n onRemovedFromGroup(handler: (chatId: number) => void): void {\n this.onBotRemoved = handler;\n }\n\n /** Start long polling. Blocks until stop() is called. */\n async start(): Promise<void> {\n this.running = true;\n\n // Verify bot token works\n const me = await this.apiCall(\"getMe\");\n if (!me.ok) {\n throw new Error(`Invalid bot token: ${JSON.stringify(me)}`);\n }\n\n while (this.running) {\n try {\n const updates = await this.getUpdates();\n for (const update of updates) {\n await this.handleUpdate(update);\n }\n } catch (err) {\n if (!this.running) break;\n console.error(`[telegram] Poll error: ${err instanceof Error ? err.message : err}`);\n await sleep(3000);\n }\n }\n }\n\n /** Stop long polling. */\n stop(): void {\n this.running = false;\n }\n\n /** Send a text message to a specific chat. Converts markdown and splits long messages. */\n async send(chatId: number, text: string, buttons?: InlineButton[][]): Promise<void> {\n const converted = toTelegramMarkdown(text);\n const chunks = splitMessage(converted);\n\n for (let i = 0; i < chunks.length; i++) {\n const isLast = i === chunks.length - 1;\n const replyMarkup =\n isLast && buttons\n ? {\n inline_keyboard: buttons.map((row) =>\n row.map((b) => ({ text: b.text, callback_data: b.callback_data })),\n ),\n }\n : undefined;\n\n await this.apiCall(\"sendMessage\", {\n chat_id: chatId,\n text: chunks[i],\n parse_mode: \"Markdown\",\n ...(replyMarkup ? { reply_markup: replyMarkup } : {}),\n });\n }\n }\n\n /** Send a plain text message (no markdown parsing) to a specific chat. */\n async sendPlain(chatId: number, text: string): Promise<void> {\n const chunks = splitMessage(text);\n for (const chunk of chunks) {\n await this.apiCall(\"sendMessage\", {\n chat_id: chatId,\n text: chunk,\n });\n }\n }\n\n /** Send a typing indicator to a specific chat. */\n async sendTyping(chatId: number): Promise<void> {\n await this.apiCall(\"sendChatAction\", {\n chat_id: chatId,\n action: \"typing\",\n });\n }\n\n /** Get a direct download URL for a Telegram file. */\n async getFileUrl(fileId: string): Promise<string> {\n const result = await this.apiCall(\"getFile\", { file_id: fileId });\n if (!result.ok) throw new Error(`Failed to get file: ${JSON.stringify(result)}`);\n const filePath = (result.result as { file_path: string }).file_path;\n return `${TELEGRAM_API}/file/bot${this.token}/${filePath}`;\n }\n\n // ── Private ───────────────────────────────────────────\n\n private async getUpdates(): Promise<TelegramUpdate[]> {\n const result = await this.apiCall(\"getUpdates\", {\n offset: this.offset,\n timeout: 30,\n allowed_updates: [\"message\", \"callback_query\", \"my_chat_member\"],\n });\n\n if (!result.ok || !Array.isArray(result.result)) return [];\n\n const updates = result.result as TelegramUpdate[];\n if (updates.length > 0) {\n this.offset = updates[updates.length - 1]!.update_id + 1;\n }\n return updates;\n }\n\n private async handleUpdate(update: TelegramUpdate): Promise<void> {\n if (update.message) {\n const msg = update.message;\n\n // Auth check\n if (msg.from.id !== this.allowedUserId) {\n return;\n }\n\n if (msg.text && this.onMessage) {\n this.onMessage({\n text: msg.text,\n chatId: msg.chat.id,\n chatType: msg.chat.type as TelegramMessage[\"chatType\"],\n chatTitle: msg.chat.title,\n });\n } else if (msg.voice && this.onVoiceMessage) {\n this.onVoiceMessage({\n fileId: msg.voice.file_id,\n duration: msg.voice.duration,\n chatId: msg.chat.id,\n chatType: msg.chat.type as TelegramMessage[\"chatType\"],\n chatTitle: msg.chat.title,\n });\n }\n }\n\n // Bot membership changed in a group\n if (update.my_chat_member) {\n const member = update.my_chat_member;\n const status = member.new_chat_member.status;\n if ((status === \"member\" || status === \"administrator\") && this.onBotAdded) {\n this.onBotAdded(member.chat.id, member.chat.title);\n } else if ((status === \"left\" || status === \"kicked\") && this.onBotRemoved) {\n this.onBotRemoved(member.chat.id);\n }\n }\n\n if (update.callback_query) {\n const cb = update.callback_query;\n\n if (cb.from.id !== this.allowedUserId) return;\n\n await this.apiCall(\"answerCallbackQuery\", { callback_query_id: cb.id });\n\n if (cb.data && this.onCallback) {\n this.onCallback(cb.data, cb.message.chat.id);\n }\n }\n }\n\n private async apiCall(\n method: string,\n body?: Record<string, unknown>,\n ): Promise<{ ok: boolean; result?: unknown }> {\n const url = `${TELEGRAM_API}/bot${this.token}/${method}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n return { ok: false };\n }\n\n return response.json() as Promise<{ ok: boolean; result?: unknown }>;\n }\n}\n\n// ── Markdown Conversion ──────────────────────────────────\n\n/**\n * Convert GitHub-flavored markdown to Telegram-compatible Markdown.\n *\n * Telegram supports: *bold*, _italic_, `code`, ```pre```, [link](url)\n * Does NOT support: headings, horizontal rules, tables, HTML tags, images\n */\nfunction toTelegramMarkdown(text: string): string {\n const lines = text.split(\"\\n\");\n const result: string[] = [];\n let inCodeBlock = false;\n\n for (const line of lines) {\n if (line.trimStart().startsWith(\"```\")) {\n inCodeBlock = !inCodeBlock;\n result.push(line);\n continue;\n }\n\n if (inCodeBlock) {\n result.push(line);\n continue;\n }\n\n let transformed = line;\n\n // Headings → bold text\n const headingMatch = transformed.match(/^(#{1,6})\\s+(.+)$/);\n if (headingMatch) {\n transformed = `*${headingMatch[2]}*`;\n result.push(transformed);\n continue;\n }\n\n // Horizontal rules → empty line\n if (/^(-{3,}|_{3,}|\\*{3,})$/.test(transformed.trim())) {\n result.push(\"\");\n continue;\n }\n\n // **bold** → *bold*\n transformed = transformed.replace(/\\*\\*(.+?)\\*\\*/g, \"*$1*\");\n\n result.push(transformed);\n }\n\n return result.join(\"\\n\");\n}\n\n// ── Helpers ───────────────────────────────────────────────\n\nfunction splitMessage(text: string): string[] {\n if (text.length <= MAX_MESSAGE_LENGTH) return [text];\n\n const chunks: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= MAX_MESSAGE_LENGTH) {\n chunks.push(remaining);\n break;\n }\n\n let splitAt = remaining.lastIndexOf(\"\\n\", MAX_MESSAGE_LENGTH);\n if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {\n splitAt = remaining.lastIndexOf(\" \", MAX_MESSAGE_LENGTH);\n }\n if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {\n splitAt = MAX_MESSAGE_LENGTH;\n }\n\n chunks.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt).trimStart();\n }\n\n return chunks;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","/**\n * Voice note transcription using local Whisper model.\n * Uses @huggingface/transformers (pure JS/WASM) — no native deps, no API keys.\n * Model (~75MB) is downloaded on first use and cached locally.\n */\n\nimport type { AutomaticSpeechRecognitionPipeline } from \"@huggingface/transformers\";\n\nconst TARGET_SAMPLE_RATE = 16000;\nconst MODEL_ID = \"Xenova/whisper-tiny.en\";\n\nlet transcriber: AutomaticSpeechRecognitionPipeline | null = null;\nlet loadPromise: Promise<AutomaticSpeechRecognitionPipeline> | null = null;\n\n/** Optional callback for model download progress. */\nexport type ProgressCallback = (info: { status: string; progress?: number; file?: string }) => void;\n\nlet onProgress: ProgressCallback | null = null;\n\n/** Set a callback to receive model download progress updates. */\nexport function setProgressCallback(cb: ProgressCallback | null): void {\n onProgress = cb;\n}\n\n/**\n * Resample audio from one sample rate to another using linear interpolation.\n */\nexport function resample(audio: Float32Array, fromRate: number, toRate: number): Float32Array {\n if (fromRate === toRate) return audio;\n const ratio = fromRate / toRate;\n const newLength = Math.round(audio.length / ratio);\n const result = new Float32Array(newLength);\n for (let i = 0; i < newLength; i++) {\n const srcIndex = i * ratio;\n const low = Math.floor(srcIndex);\n const high = Math.min(low + 1, audio.length - 1);\n const frac = srcIndex - low;\n result[i] = audio[low]! * (1 - frac) + audio[high]! * frac;\n }\n return result;\n}\n\n/**\n * Downmix multi-channel audio to mono by averaging all channels.\n */\nexport function downmixToMono(channelData: Float32Array[]): Float32Array {\n if (channelData.length === 0) return new Float32Array();\n if (channelData.length === 1) return channelData[0]!;\n\n const samples = channelData[0]!.length;\n const out = new Float32Array(samples);\n const scale = 1 / channelData.length;\n for (let i = 0; i < samples; i++) {\n let mixed = 0;\n for (const channel of channelData) mixed += channel[i] ?? 0;\n out[i] = mixed * scale;\n }\n return out;\n}\n\n/**\n * Decode OGG Opus audio buffer to 16kHz mono PCM Float32Array.\n */\nexport async function decodeOggOpus(buffer: Uint8Array): Promise<Float32Array> {\n const { OggOpusDecoder } = await import(\"ogg-opus-decoder\");\n const decoder = new OggOpusDecoder();\n await decoder.ready;\n try {\n const decoded = await decoder.decodeFile(buffer);\n\n if (!decoded.channelData?.length || !decoded.channelData[0]?.length) {\n throw new Error(\"Decoded audio is empty\");\n }\n\n const mono = downmixToMono(decoded.channelData);\n return resample(mono, decoded.sampleRate, TARGET_SAMPLE_RATE);\n } finally {\n decoder.free();\n }\n}\n\n/**\n * Get or initialize the Whisper transcription pipeline.\n * Model is downloaded on first use and cached by transformers.js.\n */\nasync function getTranscriber(): Promise<AutomaticSpeechRecognitionPipeline> {\n if (transcriber) return transcriber;\n\n if (!loadPromise) {\n loadPromise = (async () => {\n const { pipeline } = await import(\"@huggingface/transformers\");\n const instance = await pipeline(\"automatic-speech-recognition\", MODEL_ID, {\n dtype: \"fp32\",\n progress_callback: onProgress ?? undefined,\n });\n transcriber = instance;\n return instance;\n })();\n }\n\n return loadPromise;\n}\n\n/** Whether the model has been loaded already. */\nexport function isModelLoaded(): boolean {\n return transcriber !== null;\n}\n\n/**\n * Transcribe a voice message from its Telegram file URL.\n * Downloads the OGG Opus file, decodes to PCM, and runs Whisper locally.\n */\nexport async function transcribeVoice(fileUrl: string): Promise<string> {\n // Download the audio file\n const response = await fetch(fileUrl);\n if (!response.ok) throw new Error(`Failed to download voice file: ${response.status}`);\n const buffer = new Uint8Array(await response.arrayBuffer());\n\n // Decode OGG Opus → 16kHz mono PCM\n const pcm = await decodeOggOpus(buffer);\n\n // Transcribe with Whisper\n const asr = await getTranscriber();\n const result = await asr(pcm);\n\n const text = Array.isArray(result) ? result[0]?.text : (result as { text: string }).text;\n return (text ?? \"\").trim();\n}\n","import { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Provider-agnostic background self-updater. Each app composes its own instance\n * via `createAutoUpdater` with its npm package name and state-file path, so the\n * update logic (registry poll, version compare, detached install, throttling)\n * lives in exactly one place while branding stays in the apps.\n */\n\ninterface UpdateState {\n lastCheckedAt: number;\n latestVersion?: string;\n updatePending?: boolean;\n lastUpdateAttempt?: number;\n}\n\nenum PackageManager {\n NPM = \"npm\",\n PNPM = \"pnpm\",\n YARN = \"yarn\",\n UNKNOWN = \"unknown\",\n}\n\ninterface InstallInfo {\n packageManager: PackageManager;\n updateCommand: string | null;\n}\n\nexport interface AutoUpdateConfig {\n /** npm package to self-update, e.g. \"@kenkaiiii/ggcoder\". */\n packageName: string;\n /**\n * Absolute path to this app's update-state.json, or a thunk resolving it.\n * A thunk keeps path resolution lazy so callers can derive it from\n * `os.homedir()` without freezing the value at module-load time (which\n * breaks tests that mock the home directory after import).\n */\n stateFilePath: string | (() => string);\n /** Builds the in-session \"update available\" notification. */\n periodicMessage?: (args: {\n currentVersion: string;\n latestVersion: string;\n updateCommand: string;\n }) => string;\n}\n\nexport interface AutoUpdater {\n checkAndAutoUpdate(currentVersion: string): string | null;\n getPendingUpdate(currentVersion: string): { latestVersion: string } | null;\n startPeriodicUpdateCheck(currentVersion: string, onUpdate: (message: string) => void): void;\n stopPeriodicUpdateCheck(): void;\n}\n\nconst CHECK_INTERVAL_MS = 60 * 60 * 1000; // 1 hour\nconst FETCH_TIMEOUT_MS = 10_000; // 10s — npm can be slow\n\nfunction compareVersions(a: string, b: string): number {\n const pa = a.split(\".\").map(Number);\n const pb = b.split(\".\").map(Number);\n for (let i = 0; i < 3; i++) {\n const diff = (pa[i] ?? 0) - (pb[i] ?? 0);\n if (diff !== 0) return diff;\n }\n return 0;\n}\n\nfunction performUpdateInBackground(command: string): void {\n try {\n const parts = command.split(\" \");\n const child = spawn(parts[0]!, parts.slice(1), {\n detached: true,\n stdio: \"ignore\",\n env: { ...process.env, npm_config_loglevel: \"silent\" },\n });\n child.unref();\n } catch {\n // Non-fatal — will retry next startup\n }\n}\n\nexport function createAutoUpdater(config: AutoUpdateConfig): AutoUpdater {\n const REGISTRY_URL = `https://registry.npmjs.org/${config.packageName}/latest`;\n const periodicMessage =\n config.periodicMessage ??\n (({ currentVersion, latestVersion, updateCommand }) =>\n `Ken just pushed a fresh update — ${currentVersion} → ${latestVersion}! I'll grab it on next launch (or run ${updateCommand} if you can't wait).`);\n\n let periodicTimer: ReturnType<typeof setInterval> | null = null;\n\n function stateFilePath(): string {\n return typeof config.stateFilePath === \"function\"\n ? config.stateFilePath()\n : config.stateFilePath;\n }\n\n function readState(): UpdateState | null {\n try {\n const raw = fs.readFileSync(stateFilePath(), \"utf-8\");\n return JSON.parse(raw) as UpdateState;\n } catch {\n return null;\n }\n }\n\n function writeState(state: UpdateState): void {\n try {\n const filePath = stateFilePath();\n fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });\n fs.writeFileSync(filePath, JSON.stringify(state));\n } catch {\n // Non-fatal\n }\n }\n\n function detectInstallInfo(): InstallInfo {\n const scriptPath = (process.argv[1] ?? \"\").replace(/\\\\/g, \"/\");\n\n // npx — skip (ephemeral)\n if (scriptPath.includes(\"/_npx/\")) {\n return { packageManager: PackageManager.UNKNOWN, updateCommand: null };\n }\n\n // pnpm global\n if (scriptPath.includes(\"/.pnpm\") || scriptPath.includes(\"/pnpm/global\")) {\n return {\n packageManager: PackageManager.PNPM,\n updateCommand: `pnpm add -g ${config.packageName}@latest`,\n };\n }\n\n // yarn global\n if (scriptPath.includes(\"/.yarn/\") || scriptPath.includes(\"/yarn/global\")) {\n return {\n packageManager: PackageManager.YARN,\n updateCommand: `yarn global add ${config.packageName}@latest`,\n };\n }\n\n // npm global (default)\n return {\n packageManager: PackageManager.NPM,\n updateCommand: `npm install -g ${config.packageName}@latest`,\n };\n }\n\n async function fetchLatestVersion(): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n const response = await fetch(REGISTRY_URL, { signal: controller.signal });\n clearTimeout(timeout);\n const data = (await response.json()) as { version?: string };\n const version = data.version?.trim();\n return version && /^\\d+\\.\\d+\\.\\d+/.test(version) ? version : null;\n } catch {\n return null;\n }\n }\n\n function scheduleBackgroundCheck(currentVersion: string): void {\n fetchLatestVersion()\n .then((latestVersion) => {\n const newState: UpdateState = {\n lastCheckedAt: Date.now(),\n latestVersion: latestVersion ?? undefined,\n updatePending: false,\n };\n if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) {\n newState.updatePending = true;\n }\n writeState(newState);\n })\n .catch(() => {\n // Non-fatal — will retry next time\n });\n }\n\n function checkAndAutoUpdate(currentVersion: string): string | null {\n try {\n const state = readState();\n let message: string | null = null;\n\n // Phase 1: Apply pending update from previous check\n if (state?.updatePending && state.latestVersion) {\n if (compareVersions(state.latestVersion, currentVersion) > 0) {\n const info = detectInstallInfo();\n if (info.updateCommand) {\n performUpdateInBackground(info.updateCommand);\n message = `Ken just shipped ${state.latestVersion}! Installing in the background — takes effect next launch.`;\n writeState({\n ...state,\n lastCheckedAt: Date.now(),\n updatePending: false,\n lastUpdateAttempt: Date.now(),\n });\n }\n } else {\n // Already on latest (user may have updated manually)\n writeState({ ...state, updatePending: false });\n }\n }\n\n // Phase 2: Schedule background check for next startup\n const shouldCheck = !state || Date.now() - state.lastCheckedAt > CHECK_INTERVAL_MS;\n if (shouldCheck) scheduleBackgroundCheck(currentVersion);\n\n return message;\n } catch {\n return null;\n }\n }\n\n function getPendingUpdate(currentVersion: string): { latestVersion: string } | null {\n try {\n const state = readState();\n if (!state?.latestVersion) return null;\n if (compareVersions(state.latestVersion, currentVersion) <= 0) return null;\n return { latestVersion: state.latestVersion };\n } catch {\n return null;\n }\n }\n\n function startPeriodicUpdateCheck(\n currentVersion: string,\n onUpdate: (message: string) => void,\n ): void {\n if (periodicTimer) return; // Already running\n\n periodicTimer = setInterval(() => {\n fetchLatestVersion()\n .then((latestVersion) => {\n if (!latestVersion) return;\n if (compareVersions(latestVersion, currentVersion) <= 0) return;\n\n const info = detectInstallInfo();\n if (!info.updateCommand) return;\n\n writeState({ lastCheckedAt: Date.now(), latestVersion, updatePending: true });\n onUpdate(\n periodicMessage({ currentVersion, latestVersion, updateCommand: info.updateCommand }),\n );\n\n // Stop checking once we've notified\n stopPeriodicUpdateCheck();\n })\n .catch(() => {\n // Non-fatal\n });\n }, CHECK_INTERVAL_MS);\n\n // Don't keep the process alive just for update checks\n periodicTimer.unref();\n }\n\n function stopPeriodicUpdateCheck(): void {\n if (periodicTimer) {\n clearInterval(periodicTimer);\n periodicTimer = null;\n }\n }\n\n return {\n checkAndAutoUpdate,\n getPendingUpdate,\n startPeriodicUpdateCheck,\n stopPeriodicUpdateCheck,\n };\n}\n"],"mappings":"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","names":["maxIndex","fs","setTimeout","fs","path","path","fs","fs","crypto","crypto","crypto","crypto","CLIENT_ID","AUTHORIZE_URL","REDIRECT_URI","crypto","http","crypto","AUTHORIZE_URL","TOKEN_URL","SCOPE","crypto","loginWithServer","parseAuthorizationInput","postTokenRequest","http","project","path","CLIENT_ID","path","fs","crypto","sleep","fs","path","FETCH_TIMEOUT_MS","fs","path"]}
|