@dreb/ai 2.25.1 → 2.25.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"kimi-coding.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/kimi-coding.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,KAAK,EAAE,gBAAgB,EAAuB,sBAAsB,EAAE,MAAM,YAAY,CAAC;AA2FhG;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUzD;AAoBD,MAAM,MAAM,aAAa,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB,CAAC;AAgDF;;;GAGG;AACH,wBAAsB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAkB9E;AA8MD,wBAAsB,eAAe,CAAC,OAAO,EAAE;IAC9C,MAAM,EAAE,CAAC,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC/D,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAmC5B;AAMD,wBAAsB,sBAAsB,CAC3C,WAAW,EAAE,gBAAgB,EAC7B,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,gBAAgB,CAAC,CA4B3B;AAMD,eAAO,MAAM,uBAAuB,EAAE,sBA2CrC,CAAC","sourcesContent":["/**\n * Kimi For Coding OAuth flow (device code)\n *\n * Authenticates against Moonshot's Kimi API (auth.kimi.com) with scope \"kimi-code\".\n * Uses the device authorization grant flow to obtain access/refresh tokens,\n * then discovers the user's model entitlement via the /models endpoint.\n */\n\nimport { execFileSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { Api, Model } from \"../../types.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.js\";\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst KIMI_CLI_VERSION = \"1.35.0\";\nconst USER_AGENT = `KimiCLI/${KIMI_CLI_VERSION}`;\nconst OAUTH_HOST = \"https://auth.kimi.com\";\nconst OAUTH_DEVICE_AUTH_URL = `${OAUTH_HOST}/api/oauth/device_authorization`;\nconst OAUTH_TOKEN_URL = `${OAUTH_HOST}/api/oauth/token`;\nconst OAUTH_CLIENT_ID = \"17e5f671-d194-4dfb-9706-5516cb48c098\";\nconst OAUTH_SCOPE = \"kimi-code\";\nconst OAUTH_DEVICE_GRANT = \"urn:ietf:params:oauth:grant-type:device_code\";\nconst OAUTH_REFRESH_GRANT = \"refresh_token\";\nconst API_BASE_URL = \"https://api.kimi.com/coding/v1\";\n\nconst DEVICE_ID_PATH = path.join(os.homedir(), \".kimi\", \"device_id\");\n\nconst MAX_REFRESH_RETRIES = 3;\n\n// ============================================================================\n// Device ID\n// ============================================================================\n\nfunction generateDeviceId(): string {\n\t// UUID v4 without dashes (hex only, 32 chars)\n\treturn \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\".replace(/x/g, () => Math.floor(Math.random() * 16).toString(16));\n}\n\nfunction getDeviceId(): string {\n\ttry {\n\t\tif (fs.existsSync(DEVICE_ID_PATH)) {\n\t\t\tconst id = fs.readFileSync(DEVICE_ID_PATH, \"utf-8\").trim();\n\t\t\tif (/^[0-9a-f]{32}$/i.test(id)) {\n\t\t\t\treturn id;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Fall through to generate\n\t}\n\n\tconst id = generateDeviceId();\n\ttry {\n\t\tfs.mkdirSync(path.dirname(DEVICE_ID_PATH), { recursive: true });\n\t\tfs.writeFileSync(DEVICE_ID_PATH, id, \"utf-8\");\n\t} catch {\n\t\t// If we can't persist, just use the generated ID for this session\n\t}\n\treturn id;\n}\n\n// ============================================================================\n// Header helpers\n// ============================================================================\n\n/**\n * Strip non-ASCII characters from a string for use in HTTP header values.\n */\nfunction asciiHeaderValue(value: string): string {\n\treturn value.replace(/[^\\x20-\\x7E]/g, \"\");\n}\n\n/**\n * Determine the device model string, mirroring kimi-cli logic.\n */\nfunction kimiDeviceModel(): string {\n\tconst platform = os.platform();\n\tconst machine = os.machine?.() || process.arch;\n\n\tif (platform === \"darwin\") {\n\t\tlet version: string;\n\t\ttry {\n\t\t\tversion = execFileSync(\"sw_vers\", [\"-productVersion\"], { encoding: \"utf-8\", timeout: 3000 }).trim();\n\t\t} catch {\n\t\t\tversion = os.release();\n\t\t}\n\t\treturn `macOS ${version} ${machine}`;\n\t}\n\n\tif (platform === \"win32\") {\n\t\tconst release = os.release();\n\t\tconst buildNumber = Number.parseInt(release.split(\".\").pop() || \"0\", 10);\n\t\tconst label = buildNumber >= 22000 ? \"11\" : \"10\";\n\t\treturn `Windows ${label} ${machine}`;\n\t}\n\n\t// Linux and other\n\treturn `${os.type()} ${os.release()} ${machine}`;\n}\n\n/**\n * Build the standard set of headers required on every Kimi API request.\n */\nexport function buildKimiHeaders(): Record<string, string> {\n\treturn {\n\t\t\"User-Agent\": USER_AGENT,\n\t\t\"X-Msh-Platform\": \"kimi_cli\",\n\t\t\"X-Msh-Version\": KIMI_CLI_VERSION,\n\t\t\"X-Msh-Device-Name\": asciiHeaderValue(os.hostname()),\n\t\t\"X-Msh-Device-Model\": asciiHeaderValue(kimiDeviceModel()),\n\t\t\"X-Msh-Device-Id\": getDeviceId(),\n\t\t\"X-Msh-Os-Version\": asciiHeaderValue(os.version?.() || `${os.type()} ${os.release()}`),\n\t};\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype DeviceCodeResponse = {\n\tdevice_code: string;\n\tuser_code: string;\n\tverification_uri: string;\n\tinterval: number;\n\texpires_in: number;\n};\n\ntype TokenSuccessResponse = {\n\taccess_token: string;\n\trefresh_token: string;\n\texpires_in: number;\n};\n\nexport type KimiModelInfo = {\n\tid: string;\n\tdisplay_name: string;\n\tcontext_length: number;\n\tsupports_reasoning?: boolean;\n\t[key: string]: unknown;\n};\n\ntype KimiCredentials = OAuthCredentials & {\n\tmodelId?: string;\n\tcontextLength?: number;\n\tmodelDisplay?: string;\n};\n\n// ============================================================================\n// Network helpers\n// ============================================================================\n\nasync function fetchJson(url: string, init: RequestInit): Promise<unknown> {\n\tconst response = await fetch(url, init);\n\tif (!response.ok) {\n\t\tconst text = await response.text();\n\t\tthrow new Error(`${response.status} ${response.statusText}: ${text}`);\n\t}\n\treturn response.json();\n}\n\n/**\n * Sleep that can be interrupted by an AbortSignal.\n */\nfunction abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new Error(\"Login cancelled\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst timeout = setTimeout(resolve, ms);\n\n\t\tsignal?.addEventListener(\n\t\t\t\"abort\",\n\t\t\t() => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\treject(new Error(\"Login cancelled\"));\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t});\n}\n\n// ============================================================================\n// Model discovery\n// ============================================================================\n\n/**\n * List available models from the Kimi API.\n * Returns the model info array from the response's `data` field.\n */\nexport async function listModels(accessToken: string): Promise<KimiModelInfo[]> {\n\tconst raw = await fetchJson(`${API_BASE_URL}/models`, {\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\t...buildKimiHeaders(),\n\t\t},\n\t});\n\n\tif (!raw || typeof raw !== \"object\") {\n\t\tthrow new Error(\"Invalid models response\");\n\t}\n\n\tconst data = (raw as Record<string, unknown>).data;\n\tif (!Array.isArray(data)) {\n\t\tthrow new Error(\"Invalid models response: expected data array\");\n\t}\n\n\treturn data as KimiModelInfo[];\n}\n\n// ============================================================================\n// Device flow\n// ============================================================================\n\nasync function startDeviceFlow(): Promise<DeviceCodeResponse> {\n\tconst data = await fetchJson(OAUTH_DEVICE_AUTH_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t...buildKimiHeaders(),\n\t\t},\n\t\tbody: new URLSearchParams({\n\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\tscope: OAUTH_SCOPE,\n\t\t}),\n\t});\n\n\tif (!data || typeof data !== \"object\") {\n\t\tthrow new Error(\"Invalid device code response\");\n\t}\n\n\tconst d = data as Record<string, unknown>;\n\tconst device_code = d.device_code;\n\tconst user_code = d.user_code;\n\tconst verification_uri = d.verification_uri;\n\tconst interval = d.interval;\n\tconst expires_in = d.expires_in;\n\n\tif (\n\t\ttypeof device_code !== \"string\" ||\n\t\ttypeof user_code !== \"string\" ||\n\t\ttypeof verification_uri !== \"string\" ||\n\t\ttypeof interval !== \"number\" ||\n\t\ttypeof expires_in !== \"number\"\n\t) {\n\t\tthrow new Error(\"Invalid device code response fields\");\n\t}\n\n\treturn { device_code, user_code, verification_uri, interval, expires_in };\n}\n\nasync function pollForAccessToken(\n\tdeviceCode: string,\n\tintervalSeconds: number,\n\texpiresIn: number,\n\tsignal?: AbortSignal,\n): Promise<TokenSuccessResponse> {\n\tconst deadline = Date.now() + expiresIn * 1000;\n\tlet intervalMs = Math.max(1000, Math.floor(intervalSeconds * 1000));\n\n\twhile (Date.now() < deadline) {\n\t\tif (signal?.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\n\t\tconst remainingMs = deadline - Date.now();\n\t\tconst waitMs = Math.min(intervalMs, remainingMs);\n\t\tawait abortableSleep(waitMs, signal);\n\n\t\tconst tokenResponse = await fetch(OAUTH_TOKEN_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t...buildKimiHeaders(),\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\t\tdevice_code: deviceCode,\n\t\t\t\tgrant_type: OAUTH_DEVICE_GRANT,\n\t\t\t}),\n\t\t});\n\n\t\t// The token endpoint returns 400 for authorization_pending / slow_down / expired_token.\n\t\t// We must read the body regardless of status to handle the OAuth error codes.\n\t\tconst resp = (await tokenResponse.json()) as Record<string, unknown>;\n\n\t\t// Success: has access_token\n\t\tif (typeof resp.access_token === \"string\") {\n\t\t\treturn resp as unknown as TokenSuccessResponse;\n\t\t}\n\n\t\t// Error response (RFC 8628 §3.5)\n\t\tif (typeof resp.error === \"string\") {\n\t\t\tconst error = resp.error;\n\t\t\tconst description = resp.error_description as string | undefined;\n\t\t\tconst newInterval = resp.interval as number | undefined;\n\n\t\t\tif (error === \"authorization_pending\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (error === \"slow_down\") {\n\t\t\t\tintervalMs =\n\t\t\t\t\ttypeof newInterval === \"number\" && newInterval > 0\n\t\t\t\t\t\t? newInterval * 1000\n\t\t\t\t\t\t: Math.max(1000, intervalMs + 5000);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (error === \"expired_token\") {\n\t\t\t\tthrow new Error(\"Device code expired. Please try logging in again.\");\n\t\t\t}\n\n\t\t\tconst descriptionSuffix = description ? `: ${description}` : \"\";\n\t\t\tthrow new Error(`Device flow failed: ${error}${descriptionSuffix}`);\n\t\t}\n\n\t\t// Unexpected response: valid object but no access_token or error field\n\t\tthrow new Error(`Unexpected token response: ${JSON.stringify(resp)}`);\n\t}\n\n\tthrow new Error(\"Device flow timed out\");\n}\n\n// ============================================================================\n// Refresh with retry\n// ============================================================================\n\nconst RETRYABLE_STATUS_CODES = [429, 500, 502, 503, 504];\n\nclass RetriableError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"RetriableError\";\n\t}\n}\n\n/**\n * Heuristic to detect network-level errors that should be retried.\n * Fetch throws TypeError on network failures; some runtimes include\n * recognizable substrings in the message.\n */\nfunction isNetworkError(error: Error): boolean {\n\tif (error instanceof TypeError) return true;\n\tconst msg = error.message.toLowerCase();\n\treturn [\"fetch failed\", \"econnrefused\", \"etimedout\", \"enotfound\", \"econnreset\", \"socket hang up\"].some((s) =>\n\t\tmsg.includes(s),\n\t);\n}\n\nasync function refreshWithRetry(refreshToken: string, signal?: AbortSignal): Promise<TokenSuccessResponse> {\n\tlet lastError: Error | undefined;\n\n\tfor (let attempt = 0; attempt < MAX_REFRESH_RETRIES; attempt++) {\n\t\tif (signal?.aborted) {\n\t\t\tthrow new Error(\"Refresh cancelled\");\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(OAUTH_TOKEN_URL, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\t...buildKimiHeaders(),\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams({\n\t\t\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\t\t\trefresh_token: refreshToken,\n\t\t\t\t\tgrant_type: OAUTH_REFRESH_GRANT,\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\t// Retry on retriable status codes\n\t\t\tif (RETRYABLE_STATUS_CODES.includes(response.status)) {\n\t\t\t\tthrow new RetriableError(`Token refresh failed with status ${response.status}`);\n\t\t\t}\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst text = await response.text();\n\t\t\t\tthrow new Error(`Token refresh failed: ${response.status} ${response.statusText}: ${text}`);\n\t\t\t}\n\n\t\t\tconst raw = await response.json();\n\t\t\tif (!raw || typeof raw !== \"object\" || typeof (raw as Record<string, unknown>).access_token !== \"string\") {\n\t\t\t\tthrow new Error(\"Invalid token refresh response\");\n\t\t\t}\n\n\t\t\treturn raw as unknown as TokenSuccessResponse;\n\t\t} catch (error) {\n\t\t\tlastError = error instanceof Error ? error : new Error(String(error));\n\n\t\t\t// Wrap network errors (TypeError from fetch, or common network failure indicators) as retriable\n\t\t\tif (!(lastError instanceof RetriableError) && isNetworkError(lastError)) {\n\t\t\t\tlastError = new RetriableError(lastError.message);\n\t\t\t}\n\n\t\t\t// Retry on retriable errors (network failures or retriable HTTP status codes)\n\t\t\tif (lastError instanceof RetriableError && attempt < MAX_REFRESH_RETRIES - 1) {\n\t\t\t\tconst backoffMs = Math.min(1000 * 2 ** attempt, 10000);\n\t\t\t\tawait abortableSleep(backoffMs, signal);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthrow lastError;\n\t\t}\n\t}\n\n\tthrow lastError ?? new Error(\"Token refresh failed after retries\");\n}\n\n// ============================================================================\n// Login flow\n// ============================================================================\n\nexport async function loginKimiCoding(options: {\n\tonAuth: (info: { url: string; instructions?: string }) => void;\n\tonProgress?: (message: string) => void;\n\tsignal?: AbortSignal;\n}): Promise<OAuthCredentials> {\n\tconst device = await startDeviceFlow();\n\t// Kimi's device page expects user_code as a query parameter\n\tconst authUrl = new URL(device.verification_uri);\n\tauthUrl.searchParams.set(\"user_code\", device.user_code);\n\toptions.onAuth({\n\t\turl: authUrl.toString(),\n\t\tinstructions: `Enter code: ${device.user_code}`,\n\t});\n\n\tconst tokenResp = await pollForAccessToken(device.device_code, device.interval, device.expires_in, options.signal);\n\n\t// Discover model entitlement\n\toptions.onProgress?.(\"Discovering available models...\");\n\tlet models: KimiModelInfo[] = [];\n\ttry {\n\t\tmodels = await listModels(tokenResp.access_token);\n\t} catch {\n\t\t// Proceed without model enrichment if the models endpoint fails\n\t}\n\n\tconst credentials: KimiCredentials = {\n\t\trefresh: tokenResp.refresh_token,\n\t\taccess: tokenResp.access_token,\n\t\texpires: Date.now() + tokenResp.expires_in * 1000,\n\t};\n\n\tif (models.length > 0) {\n\t\tconst primary = models[0];\n\t\tcredentials.modelId = primary.id;\n\t\tcredentials.contextLength = primary.context_length;\n\t\tcredentials.modelDisplay = primary.display_name;\n\t}\n\n\treturn credentials;\n}\n\n// ============================================================================\n// Refresh\n// ============================================================================\n\nexport async function refreshKimiCodingToken(\n\tcredentials: OAuthCredentials,\n\tsignal?: AbortSignal,\n): Promise<OAuthCredentials> {\n\tconst tokenResp = await refreshWithRetry(credentials.refresh, signal);\n\n\t// Re-discover model entitlement\n\tlet models: KimiModelInfo[] = [];\n\ttry {\n\t\tmodels = await listModels(tokenResp.access_token);\n\t} catch {\n\t\t// Proceed without model enrichment if the models endpoint fails\n\t}\n\n\tconst fresh: KimiCredentials = {\n\t\trefresh: tokenResp.refresh_token ?? credentials.refresh,\n\t\taccess: tokenResp.access_token,\n\t\texpires: Date.now() + tokenResp.expires_in * 1000,\n\t\tmodelId: (credentials as KimiCredentials).modelId,\n\t\tcontextLength: (credentials as KimiCredentials).contextLength,\n\t\tmodelDisplay: (credentials as KimiCredentials).modelDisplay,\n\t};\n\n\tif (models.length > 0) {\n\t\tconst primary = models[0];\n\t\tfresh.modelId = primary.id;\n\t\tfresh.contextLength = primary.context_length;\n\t\tfresh.modelDisplay = primary.display_name;\n\t}\n\n\treturn fresh;\n}\n\n// ============================================================================\n// Provider\n// ============================================================================\n\nexport const kimiCodingOAuthProvider: OAuthProviderInterface = {\n\tid: \"kimi-coding-oauth\",\n\tname: \"Kimi For Coding\",\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginKimiCoding({\n\t\t\tonAuth: callbacks.onAuth,\n\t\t\tonProgress: callbacks.onProgress,\n\t\t\tsignal: callbacks.signal,\n\t\t});\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\treturn refreshKimiCodingToken(credentials);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n\n\tmodifyModels(models: Model<Api>[], credentials: OAuthCredentials): Model<Api>[] {\n\t\tconst creds = credentials as KimiCredentials;\n\t\tconst headers = buildKimiHeaders();\n\n\t\treturn models.map((m) => {\n\t\t\tif (m.provider !== \"kimi-coding-oauth\") return m;\n\n\t\t\tconst updated = {\n\t\t\t\t...m,\n\t\t\t\theaders: { ...headers, ...(m.headers || {}) },\n\t\t\t};\n\n\t\t\tif (creds.modelId) {\n\t\t\t\tupdated.id = creds.modelId;\n\t\t\t}\n\n\t\t\tif (creds.contextLength) {\n\t\t\t\tupdated.contextWindow = creds.contextLength;\n\t\t\t}\n\n\t\t\treturn updated;\n\t\t});\n\t},\n};\n"]}
1
+ {"version":3,"file":"kimi-coding.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/kimi-coding.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,KAAK,EAAE,gBAAgB,EAAuB,sBAAsB,EAAE,MAAM,YAAY,CAAC;AA2FhG;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUzD;AAoBD,MAAM,MAAM,aAAa,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB,CAAC;AAgDF;;;GAGG;AACH,wBAAsB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAkB9E;AA8MD,wBAAsB,eAAe,CAAC,OAAO,EAAE;IAC9C,MAAM,EAAE,CAAC,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC/D,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAmC5B;AAMD,wBAAsB,sBAAsB,CAC3C,WAAW,EAAE,gBAAgB,EAC7B,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,gBAAgB,CAAC,CA4B3B;AAMD,eAAO,MAAM,uBAAuB,EAAE,sBA8CrC,CAAC","sourcesContent":["/**\n * Kimi For Coding OAuth flow (device code)\n *\n * Authenticates against Moonshot's Kimi API (auth.kimi.com) with scope \"kimi-code\".\n * Uses the device authorization grant flow to obtain access/refresh tokens,\n * then discovers the user's model entitlement via the /models endpoint.\n */\n\nimport { execFileSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { Api, Model } from \"../../types.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.js\";\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst KIMI_CLI_VERSION = \"1.35.0\";\nconst USER_AGENT = `KimiCLI/${KIMI_CLI_VERSION}`;\nconst OAUTH_HOST = \"https://auth.kimi.com\";\nconst OAUTH_DEVICE_AUTH_URL = `${OAUTH_HOST}/api/oauth/device_authorization`;\nconst OAUTH_TOKEN_URL = `${OAUTH_HOST}/api/oauth/token`;\nconst OAUTH_CLIENT_ID = \"17e5f671-d194-4dfb-9706-5516cb48c098\";\nconst OAUTH_SCOPE = \"kimi-code\";\nconst OAUTH_DEVICE_GRANT = \"urn:ietf:params:oauth:grant-type:device_code\";\nconst OAUTH_REFRESH_GRANT = \"refresh_token\";\nconst API_BASE_URL = \"https://api.kimi.com/coding/v1\";\n\nconst DEVICE_ID_PATH = path.join(os.homedir(), \".kimi\", \"device_id\");\n\nconst MAX_REFRESH_RETRIES = 3;\n\n// ============================================================================\n// Device ID\n// ============================================================================\n\nfunction generateDeviceId(): string {\n\t// UUID v4 without dashes (hex only, 32 chars)\n\treturn \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\".replace(/x/g, () => Math.floor(Math.random() * 16).toString(16));\n}\n\nfunction getDeviceId(): string {\n\ttry {\n\t\tif (fs.existsSync(DEVICE_ID_PATH)) {\n\t\t\tconst id = fs.readFileSync(DEVICE_ID_PATH, \"utf-8\").trim();\n\t\t\tif (/^[0-9a-f]{32}$/i.test(id)) {\n\t\t\t\treturn id;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Fall through to generate\n\t}\n\n\tconst id = generateDeviceId();\n\ttry {\n\t\tfs.mkdirSync(path.dirname(DEVICE_ID_PATH), { recursive: true });\n\t\tfs.writeFileSync(DEVICE_ID_PATH, id, \"utf-8\");\n\t} catch {\n\t\t// If we can't persist, just use the generated ID for this session\n\t}\n\treturn id;\n}\n\n// ============================================================================\n// Header helpers\n// ============================================================================\n\n/**\n * Strip non-ASCII characters from a string for use in HTTP header values.\n */\nfunction asciiHeaderValue(value: string): string {\n\treturn value.replace(/[^\\x20-\\x7E]/g, \"\");\n}\n\n/**\n * Determine the device model string, mirroring kimi-cli logic.\n */\nfunction kimiDeviceModel(): string {\n\tconst platform = os.platform();\n\tconst machine = os.machine?.() || process.arch;\n\n\tif (platform === \"darwin\") {\n\t\tlet version: string;\n\t\ttry {\n\t\t\tversion = execFileSync(\"sw_vers\", [\"-productVersion\"], { encoding: \"utf-8\", timeout: 3000 }).trim();\n\t\t} catch {\n\t\t\tversion = os.release();\n\t\t}\n\t\treturn `macOS ${version} ${machine}`;\n\t}\n\n\tif (platform === \"win32\") {\n\t\tconst release = os.release();\n\t\tconst buildNumber = Number.parseInt(release.split(\".\").pop() || \"0\", 10);\n\t\tconst label = buildNumber >= 22000 ? \"11\" : \"10\";\n\t\treturn `Windows ${label} ${machine}`;\n\t}\n\n\t// Linux and other\n\treturn `${os.type()} ${os.release()} ${machine}`;\n}\n\n/**\n * Build the standard set of headers required on every Kimi API request.\n */\nexport function buildKimiHeaders(): Record<string, string> {\n\treturn {\n\t\t\"User-Agent\": USER_AGENT,\n\t\t\"X-Msh-Platform\": \"kimi_cli\",\n\t\t\"X-Msh-Version\": KIMI_CLI_VERSION,\n\t\t\"X-Msh-Device-Name\": asciiHeaderValue(os.hostname()),\n\t\t\"X-Msh-Device-Model\": asciiHeaderValue(kimiDeviceModel()),\n\t\t\"X-Msh-Device-Id\": getDeviceId(),\n\t\t\"X-Msh-Os-Version\": asciiHeaderValue(os.version?.() || `${os.type()} ${os.release()}`),\n\t};\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype DeviceCodeResponse = {\n\tdevice_code: string;\n\tuser_code: string;\n\tverification_uri: string;\n\tinterval: number;\n\texpires_in: number;\n};\n\ntype TokenSuccessResponse = {\n\taccess_token: string;\n\trefresh_token: string;\n\texpires_in: number;\n};\n\nexport type KimiModelInfo = {\n\tid: string;\n\tdisplay_name: string;\n\tcontext_length: number;\n\tsupports_reasoning?: boolean;\n\t[key: string]: unknown;\n};\n\ntype KimiCredentials = OAuthCredentials & {\n\tmodelId?: string;\n\tcontextLength?: number;\n\tmodelDisplay?: string;\n};\n\n// ============================================================================\n// Network helpers\n// ============================================================================\n\nasync function fetchJson(url: string, init: RequestInit): Promise<unknown> {\n\tconst response = await fetch(url, init);\n\tif (!response.ok) {\n\t\tconst text = await response.text();\n\t\tthrow new Error(`${response.status} ${response.statusText}: ${text}`);\n\t}\n\treturn response.json();\n}\n\n/**\n * Sleep that can be interrupted by an AbortSignal.\n */\nfunction abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new Error(\"Login cancelled\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst timeout = setTimeout(resolve, ms);\n\n\t\tsignal?.addEventListener(\n\t\t\t\"abort\",\n\t\t\t() => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\treject(new Error(\"Login cancelled\"));\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t});\n}\n\n// ============================================================================\n// Model discovery\n// ============================================================================\n\n/**\n * List available models from the Kimi API.\n * Returns the model info array from the response's `data` field.\n */\nexport async function listModels(accessToken: string): Promise<KimiModelInfo[]> {\n\tconst raw = await fetchJson(`${API_BASE_URL}/models`, {\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\t...buildKimiHeaders(),\n\t\t},\n\t});\n\n\tif (!raw || typeof raw !== \"object\") {\n\t\tthrow new Error(\"Invalid models response\");\n\t}\n\n\tconst data = (raw as Record<string, unknown>).data;\n\tif (!Array.isArray(data)) {\n\t\tthrow new Error(\"Invalid models response: expected data array\");\n\t}\n\n\treturn data as KimiModelInfo[];\n}\n\n// ============================================================================\n// Device flow\n// ============================================================================\n\nasync function startDeviceFlow(): Promise<DeviceCodeResponse> {\n\tconst data = await fetchJson(OAUTH_DEVICE_AUTH_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t...buildKimiHeaders(),\n\t\t},\n\t\tbody: new URLSearchParams({\n\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\tscope: OAUTH_SCOPE,\n\t\t}),\n\t});\n\n\tif (!data || typeof data !== \"object\") {\n\t\tthrow new Error(\"Invalid device code response\");\n\t}\n\n\tconst d = data as Record<string, unknown>;\n\tconst device_code = d.device_code;\n\tconst user_code = d.user_code;\n\tconst verification_uri = d.verification_uri;\n\tconst interval = d.interval;\n\tconst expires_in = d.expires_in;\n\n\tif (\n\t\ttypeof device_code !== \"string\" ||\n\t\ttypeof user_code !== \"string\" ||\n\t\ttypeof verification_uri !== \"string\" ||\n\t\ttypeof interval !== \"number\" ||\n\t\ttypeof expires_in !== \"number\"\n\t) {\n\t\tthrow new Error(\"Invalid device code response fields\");\n\t}\n\n\treturn { device_code, user_code, verification_uri, interval, expires_in };\n}\n\nasync function pollForAccessToken(\n\tdeviceCode: string,\n\tintervalSeconds: number,\n\texpiresIn: number,\n\tsignal?: AbortSignal,\n): Promise<TokenSuccessResponse> {\n\tconst deadline = Date.now() + expiresIn * 1000;\n\tlet intervalMs = Math.max(1000, Math.floor(intervalSeconds * 1000));\n\n\twhile (Date.now() < deadline) {\n\t\tif (signal?.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\n\t\tconst remainingMs = deadline - Date.now();\n\t\tconst waitMs = Math.min(intervalMs, remainingMs);\n\t\tawait abortableSleep(waitMs, signal);\n\n\t\tconst tokenResponse = await fetch(OAUTH_TOKEN_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t...buildKimiHeaders(),\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\t\tdevice_code: deviceCode,\n\t\t\t\tgrant_type: OAUTH_DEVICE_GRANT,\n\t\t\t}),\n\t\t});\n\n\t\t// The token endpoint returns 400 for authorization_pending / slow_down / expired_token.\n\t\t// We must read the body regardless of status to handle the OAuth error codes.\n\t\tconst resp = (await tokenResponse.json()) as Record<string, unknown>;\n\n\t\t// Success: has access_token\n\t\tif (typeof resp.access_token === \"string\") {\n\t\t\treturn resp as unknown as TokenSuccessResponse;\n\t\t}\n\n\t\t// Error response (RFC 8628 §3.5)\n\t\tif (typeof resp.error === \"string\") {\n\t\t\tconst error = resp.error;\n\t\t\tconst description = resp.error_description as string | undefined;\n\t\t\tconst newInterval = resp.interval as number | undefined;\n\n\t\t\tif (error === \"authorization_pending\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (error === \"slow_down\") {\n\t\t\t\tintervalMs =\n\t\t\t\t\ttypeof newInterval === \"number\" && newInterval > 0\n\t\t\t\t\t\t? newInterval * 1000\n\t\t\t\t\t\t: Math.max(1000, intervalMs + 5000);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (error === \"expired_token\") {\n\t\t\t\tthrow new Error(\"Device code expired. Please try logging in again.\");\n\t\t\t}\n\n\t\t\tconst descriptionSuffix = description ? `: ${description}` : \"\";\n\t\t\tthrow new Error(`Device flow failed: ${error}${descriptionSuffix}`);\n\t\t}\n\n\t\t// Unexpected response: valid object but no access_token or error field\n\t\tthrow new Error(`Unexpected token response: ${JSON.stringify(resp)}`);\n\t}\n\n\tthrow new Error(\"Device flow timed out\");\n}\n\n// ============================================================================\n// Refresh with retry\n// ============================================================================\n\nconst RETRYABLE_STATUS_CODES = [429, 500, 502, 503, 504];\n\nclass RetriableError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"RetriableError\";\n\t}\n}\n\n/**\n * Heuristic to detect network-level errors that should be retried.\n * Fetch throws TypeError on network failures; some runtimes include\n * recognizable substrings in the message.\n */\nfunction isNetworkError(error: Error): boolean {\n\tif (error instanceof TypeError) return true;\n\tconst msg = error.message.toLowerCase();\n\treturn [\"fetch failed\", \"econnrefused\", \"etimedout\", \"enotfound\", \"econnreset\", \"socket hang up\"].some((s) =>\n\t\tmsg.includes(s),\n\t);\n}\n\nasync function refreshWithRetry(refreshToken: string, signal?: AbortSignal): Promise<TokenSuccessResponse> {\n\tlet lastError: Error | undefined;\n\n\tfor (let attempt = 0; attempt < MAX_REFRESH_RETRIES; attempt++) {\n\t\tif (signal?.aborted) {\n\t\t\tthrow new Error(\"Refresh cancelled\");\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(OAUTH_TOKEN_URL, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\t...buildKimiHeaders(),\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams({\n\t\t\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\t\t\trefresh_token: refreshToken,\n\t\t\t\t\tgrant_type: OAUTH_REFRESH_GRANT,\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\t// Retry on retriable status codes\n\t\t\tif (RETRYABLE_STATUS_CODES.includes(response.status)) {\n\t\t\t\tthrow new RetriableError(`Token refresh failed with status ${response.status}`);\n\t\t\t}\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst text = await response.text();\n\t\t\t\tthrow new Error(`Token refresh failed: ${response.status} ${response.statusText}: ${text}`);\n\t\t\t}\n\n\t\t\tconst raw = await response.json();\n\t\t\tif (!raw || typeof raw !== \"object\" || typeof (raw as Record<string, unknown>).access_token !== \"string\") {\n\t\t\t\tthrow new Error(\"Invalid token refresh response\");\n\t\t\t}\n\n\t\t\treturn raw as unknown as TokenSuccessResponse;\n\t\t} catch (error) {\n\t\t\tlastError = error instanceof Error ? error : new Error(String(error));\n\n\t\t\t// Wrap network errors (TypeError from fetch, or common network failure indicators) as retriable\n\t\t\tif (!(lastError instanceof RetriableError) && isNetworkError(lastError)) {\n\t\t\t\tlastError = new RetriableError(lastError.message);\n\t\t\t}\n\n\t\t\t// Retry on retriable errors (network failures or retriable HTTP status codes)\n\t\t\tif (lastError instanceof RetriableError && attempt < MAX_REFRESH_RETRIES - 1) {\n\t\t\t\tconst backoffMs = Math.min(1000 * 2 ** attempt, 10000);\n\t\t\t\tawait abortableSleep(backoffMs, signal);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthrow lastError;\n\t\t}\n\t}\n\n\tthrow lastError ?? new Error(\"Token refresh failed after retries\");\n}\n\n// ============================================================================\n// Login flow\n// ============================================================================\n\nexport async function loginKimiCoding(options: {\n\tonAuth: (info: { url: string; instructions?: string }) => void;\n\tonProgress?: (message: string) => void;\n\tsignal?: AbortSignal;\n}): Promise<OAuthCredentials> {\n\tconst device = await startDeviceFlow();\n\t// Kimi's device page expects user_code as a query parameter\n\tconst authUrl = new URL(device.verification_uri);\n\tauthUrl.searchParams.set(\"user_code\", device.user_code);\n\toptions.onAuth({\n\t\turl: authUrl.toString(),\n\t\tinstructions: `Enter code: ${device.user_code}`,\n\t});\n\n\tconst tokenResp = await pollForAccessToken(device.device_code, device.interval, device.expires_in, options.signal);\n\n\t// Discover model entitlement\n\toptions.onProgress?.(\"Discovering available models...\");\n\tlet models: KimiModelInfo[] = [];\n\ttry {\n\t\tmodels = await listModels(tokenResp.access_token);\n\t} catch {\n\t\t// Proceed without model enrichment if the models endpoint fails\n\t}\n\n\tconst credentials: KimiCredentials = {\n\t\trefresh: tokenResp.refresh_token,\n\t\taccess: tokenResp.access_token,\n\t\texpires: Date.now() + tokenResp.expires_in * 1000,\n\t};\n\n\tif (models.length > 0) {\n\t\tconst primary = models[0];\n\t\tcredentials.modelId = primary.id;\n\t\tcredentials.contextLength = primary.context_length;\n\t\tcredentials.modelDisplay = primary.display_name;\n\t}\n\n\treturn credentials;\n}\n\n// ============================================================================\n// Refresh\n// ============================================================================\n\nexport async function refreshKimiCodingToken(\n\tcredentials: OAuthCredentials,\n\tsignal?: AbortSignal,\n): Promise<OAuthCredentials> {\n\tconst tokenResp = await refreshWithRetry(credentials.refresh, signal);\n\n\t// Re-discover model entitlement\n\tlet models: KimiModelInfo[] = [];\n\ttry {\n\t\tmodels = await listModels(tokenResp.access_token);\n\t} catch {\n\t\t// Proceed without model enrichment if the models endpoint fails\n\t}\n\n\tconst fresh: KimiCredentials = {\n\t\trefresh: tokenResp.refresh_token ?? credentials.refresh,\n\t\taccess: tokenResp.access_token,\n\t\texpires: Date.now() + tokenResp.expires_in * 1000,\n\t\tmodelId: (credentials as KimiCredentials).modelId,\n\t\tcontextLength: (credentials as KimiCredentials).contextLength,\n\t\tmodelDisplay: (credentials as KimiCredentials).modelDisplay,\n\t};\n\n\tif (models.length > 0) {\n\t\tconst primary = models[0];\n\t\tfresh.modelId = primary.id;\n\t\tfresh.contextLength = primary.context_length;\n\t\tfresh.modelDisplay = primary.display_name;\n\t}\n\n\treturn fresh;\n}\n\n// ============================================================================\n// Provider\n// ============================================================================\n\nexport const kimiCodingOAuthProvider: OAuthProviderInterface = {\n\tid: \"kimi-coding-oauth\",\n\tname: \"Kimi For Coding\",\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginKimiCoding({\n\t\t\tonAuth: callbacks.onAuth,\n\t\t\tonProgress: callbacks.onProgress,\n\t\t\tsignal: callbacks.signal,\n\t\t});\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\treturn refreshKimiCodingToken(credentials);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n\n\tmodifyModels(models: Model<Api>[], credentials: OAuthCredentials): Model<Api>[] {\n\t\tconst creds = credentials as KimiCredentials;\n\t\tconst headers = buildKimiHeaders();\n\n\t\treturn models.map((m) => {\n\t\t\tif (m.provider !== \"kimi-coding-oauth\") return m;\n\n\t\t\tconst updated = {\n\t\t\t\t...m,\n\t\t\t\t// The OAuth coding endpoint accepts OpenAI-style image_url data URLs for\n\t\t\t\t// kimi-for-coding; keep this capability even if static metadata is stale.\n\t\t\t\tinput: Array.from(new Set([...m.input, \"image\" as const])),\n\t\t\t\theaders: { ...headers, ...(m.headers || {}) },\n\t\t\t};\n\n\t\t\tif (creds.modelId) {\n\t\t\t\tupdated.id = creds.modelId;\n\t\t\t}\n\n\t\t\tif (creds.contextLength) {\n\t\t\t\tupdated.contextWindow = creds.contextLength;\n\t\t\t}\n\n\t\t\treturn updated;\n\t\t});\n\t},\n};\n"]}
@@ -401,6 +401,9 @@ export const kimiCodingOAuthProvider = {
401
401
  return m;
402
402
  const updated = {
403
403
  ...m,
404
+ // The OAuth coding endpoint accepts OpenAI-style image_url data URLs for
405
+ // kimi-for-coding; keep this capability even if static metadata is stale.
406
+ input: Array.from(new Set([...m.input, "image"])),
404
407
  headers: { ...headers, ...(m.headers || {}) },
405
408
  };
406
409
  if (creds.modelId) {
@@ -1 +1 @@
1
- {"version":3,"file":"kimi-coding.js","sourceRoot":"","sources":["../../../src/utils/oauth/kimi-coding.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Kimi For Coding OAuth flow (device code)\n *\n * Authenticates against Moonshot's Kimi API (auth.kimi.com) with scope \"kimi-code\".\n * Uses the device authorization grant flow to obtain access/refresh tokens,\n * then discovers the user's model entitlement via the /models endpoint.\n */\n\nimport { execFileSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { Api, Model } from \"../../types.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.js\";\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst KIMI_CLI_VERSION = \"1.35.0\";\nconst USER_AGENT = `KimiCLI/${KIMI_CLI_VERSION}`;\nconst OAUTH_HOST = \"https://auth.kimi.com\";\nconst OAUTH_DEVICE_AUTH_URL = `${OAUTH_HOST}/api/oauth/device_authorization`;\nconst OAUTH_TOKEN_URL = `${OAUTH_HOST}/api/oauth/token`;\nconst OAUTH_CLIENT_ID = \"17e5f671-d194-4dfb-9706-5516cb48c098\";\nconst OAUTH_SCOPE = \"kimi-code\";\nconst OAUTH_DEVICE_GRANT = \"urn:ietf:params:oauth:grant-type:device_code\";\nconst OAUTH_REFRESH_GRANT = \"refresh_token\";\nconst API_BASE_URL = \"https://api.kimi.com/coding/v1\";\n\nconst DEVICE_ID_PATH = path.join(os.homedir(), \".kimi\", \"device_id\");\n\nconst MAX_REFRESH_RETRIES = 3;\n\n// ============================================================================\n// Device ID\n// ============================================================================\n\nfunction generateDeviceId(): string {\n\t// UUID v4 without dashes (hex only, 32 chars)\n\treturn \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\".replace(/x/g, () => Math.floor(Math.random() * 16).toString(16));\n}\n\nfunction getDeviceId(): string {\n\ttry {\n\t\tif (fs.existsSync(DEVICE_ID_PATH)) {\n\t\t\tconst id = fs.readFileSync(DEVICE_ID_PATH, \"utf-8\").trim();\n\t\t\tif (/^[0-9a-f]{32}$/i.test(id)) {\n\t\t\t\treturn id;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Fall through to generate\n\t}\n\n\tconst id = generateDeviceId();\n\ttry {\n\t\tfs.mkdirSync(path.dirname(DEVICE_ID_PATH), { recursive: true });\n\t\tfs.writeFileSync(DEVICE_ID_PATH, id, \"utf-8\");\n\t} catch {\n\t\t// If we can't persist, just use the generated ID for this session\n\t}\n\treturn id;\n}\n\n// ============================================================================\n// Header helpers\n// ============================================================================\n\n/**\n * Strip non-ASCII characters from a string for use in HTTP header values.\n */\nfunction asciiHeaderValue(value: string): string {\n\treturn value.replace(/[^\\x20-\\x7E]/g, \"\");\n}\n\n/**\n * Determine the device model string, mirroring kimi-cli logic.\n */\nfunction kimiDeviceModel(): string {\n\tconst platform = os.platform();\n\tconst machine = os.machine?.() || process.arch;\n\n\tif (platform === \"darwin\") {\n\t\tlet version: string;\n\t\ttry {\n\t\t\tversion = execFileSync(\"sw_vers\", [\"-productVersion\"], { encoding: \"utf-8\", timeout: 3000 }).trim();\n\t\t} catch {\n\t\t\tversion = os.release();\n\t\t}\n\t\treturn `macOS ${version} ${machine}`;\n\t}\n\n\tif (platform === \"win32\") {\n\t\tconst release = os.release();\n\t\tconst buildNumber = Number.parseInt(release.split(\".\").pop() || \"0\", 10);\n\t\tconst label = buildNumber >= 22000 ? \"11\" : \"10\";\n\t\treturn `Windows ${label} ${machine}`;\n\t}\n\n\t// Linux and other\n\treturn `${os.type()} ${os.release()} ${machine}`;\n}\n\n/**\n * Build the standard set of headers required on every Kimi API request.\n */\nexport function buildKimiHeaders(): Record<string, string> {\n\treturn {\n\t\t\"User-Agent\": USER_AGENT,\n\t\t\"X-Msh-Platform\": \"kimi_cli\",\n\t\t\"X-Msh-Version\": KIMI_CLI_VERSION,\n\t\t\"X-Msh-Device-Name\": asciiHeaderValue(os.hostname()),\n\t\t\"X-Msh-Device-Model\": asciiHeaderValue(kimiDeviceModel()),\n\t\t\"X-Msh-Device-Id\": getDeviceId(),\n\t\t\"X-Msh-Os-Version\": asciiHeaderValue(os.version?.() || `${os.type()} ${os.release()}`),\n\t};\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype DeviceCodeResponse = {\n\tdevice_code: string;\n\tuser_code: string;\n\tverification_uri: string;\n\tinterval: number;\n\texpires_in: number;\n};\n\ntype TokenSuccessResponse = {\n\taccess_token: string;\n\trefresh_token: string;\n\texpires_in: number;\n};\n\nexport type KimiModelInfo = {\n\tid: string;\n\tdisplay_name: string;\n\tcontext_length: number;\n\tsupports_reasoning?: boolean;\n\t[key: string]: unknown;\n};\n\ntype KimiCredentials = OAuthCredentials & {\n\tmodelId?: string;\n\tcontextLength?: number;\n\tmodelDisplay?: string;\n};\n\n// ============================================================================\n// Network helpers\n// ============================================================================\n\nasync function fetchJson(url: string, init: RequestInit): Promise<unknown> {\n\tconst response = await fetch(url, init);\n\tif (!response.ok) {\n\t\tconst text = await response.text();\n\t\tthrow new Error(`${response.status} ${response.statusText}: ${text}`);\n\t}\n\treturn response.json();\n}\n\n/**\n * Sleep that can be interrupted by an AbortSignal.\n */\nfunction abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new Error(\"Login cancelled\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst timeout = setTimeout(resolve, ms);\n\n\t\tsignal?.addEventListener(\n\t\t\t\"abort\",\n\t\t\t() => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\treject(new Error(\"Login cancelled\"));\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t});\n}\n\n// ============================================================================\n// Model discovery\n// ============================================================================\n\n/**\n * List available models from the Kimi API.\n * Returns the model info array from the response's `data` field.\n */\nexport async function listModels(accessToken: string): Promise<KimiModelInfo[]> {\n\tconst raw = await fetchJson(`${API_BASE_URL}/models`, {\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\t...buildKimiHeaders(),\n\t\t},\n\t});\n\n\tif (!raw || typeof raw !== \"object\") {\n\t\tthrow new Error(\"Invalid models response\");\n\t}\n\n\tconst data = (raw as Record<string, unknown>).data;\n\tif (!Array.isArray(data)) {\n\t\tthrow new Error(\"Invalid models response: expected data array\");\n\t}\n\n\treturn data as KimiModelInfo[];\n}\n\n// ============================================================================\n// Device flow\n// ============================================================================\n\nasync function startDeviceFlow(): Promise<DeviceCodeResponse> {\n\tconst data = await fetchJson(OAUTH_DEVICE_AUTH_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t...buildKimiHeaders(),\n\t\t},\n\t\tbody: new URLSearchParams({\n\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\tscope: OAUTH_SCOPE,\n\t\t}),\n\t});\n\n\tif (!data || typeof data !== \"object\") {\n\t\tthrow new Error(\"Invalid device code response\");\n\t}\n\n\tconst d = data as Record<string, unknown>;\n\tconst device_code = d.device_code;\n\tconst user_code = d.user_code;\n\tconst verification_uri = d.verification_uri;\n\tconst interval = d.interval;\n\tconst expires_in = d.expires_in;\n\n\tif (\n\t\ttypeof device_code !== \"string\" ||\n\t\ttypeof user_code !== \"string\" ||\n\t\ttypeof verification_uri !== \"string\" ||\n\t\ttypeof interval !== \"number\" ||\n\t\ttypeof expires_in !== \"number\"\n\t) {\n\t\tthrow new Error(\"Invalid device code response fields\");\n\t}\n\n\treturn { device_code, user_code, verification_uri, interval, expires_in };\n}\n\nasync function pollForAccessToken(\n\tdeviceCode: string,\n\tintervalSeconds: number,\n\texpiresIn: number,\n\tsignal?: AbortSignal,\n): Promise<TokenSuccessResponse> {\n\tconst deadline = Date.now() + expiresIn * 1000;\n\tlet intervalMs = Math.max(1000, Math.floor(intervalSeconds * 1000));\n\n\twhile (Date.now() < deadline) {\n\t\tif (signal?.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\n\t\tconst remainingMs = deadline - Date.now();\n\t\tconst waitMs = Math.min(intervalMs, remainingMs);\n\t\tawait abortableSleep(waitMs, signal);\n\n\t\tconst tokenResponse = await fetch(OAUTH_TOKEN_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t...buildKimiHeaders(),\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\t\tdevice_code: deviceCode,\n\t\t\t\tgrant_type: OAUTH_DEVICE_GRANT,\n\t\t\t}),\n\t\t});\n\n\t\t// The token endpoint returns 400 for authorization_pending / slow_down / expired_token.\n\t\t// We must read the body regardless of status to handle the OAuth error codes.\n\t\tconst resp = (await tokenResponse.json()) as Record<string, unknown>;\n\n\t\t// Success: has access_token\n\t\tif (typeof resp.access_token === \"string\") {\n\t\t\treturn resp as unknown as TokenSuccessResponse;\n\t\t}\n\n\t\t// Error response (RFC 8628 §3.5)\n\t\tif (typeof resp.error === \"string\") {\n\t\t\tconst error = resp.error;\n\t\t\tconst description = resp.error_description as string | undefined;\n\t\t\tconst newInterval = resp.interval as number | undefined;\n\n\t\t\tif (error === \"authorization_pending\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (error === \"slow_down\") {\n\t\t\t\tintervalMs =\n\t\t\t\t\ttypeof newInterval === \"number\" && newInterval > 0\n\t\t\t\t\t\t? newInterval * 1000\n\t\t\t\t\t\t: Math.max(1000, intervalMs + 5000);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (error === \"expired_token\") {\n\t\t\t\tthrow new Error(\"Device code expired. Please try logging in again.\");\n\t\t\t}\n\n\t\t\tconst descriptionSuffix = description ? `: ${description}` : \"\";\n\t\t\tthrow new Error(`Device flow failed: ${error}${descriptionSuffix}`);\n\t\t}\n\n\t\t// Unexpected response: valid object but no access_token or error field\n\t\tthrow new Error(`Unexpected token response: ${JSON.stringify(resp)}`);\n\t}\n\n\tthrow new Error(\"Device flow timed out\");\n}\n\n// ============================================================================\n// Refresh with retry\n// ============================================================================\n\nconst RETRYABLE_STATUS_CODES = [429, 500, 502, 503, 504];\n\nclass RetriableError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"RetriableError\";\n\t}\n}\n\n/**\n * Heuristic to detect network-level errors that should be retried.\n * Fetch throws TypeError on network failures; some runtimes include\n * recognizable substrings in the message.\n */\nfunction isNetworkError(error: Error): boolean {\n\tif (error instanceof TypeError) return true;\n\tconst msg = error.message.toLowerCase();\n\treturn [\"fetch failed\", \"econnrefused\", \"etimedout\", \"enotfound\", \"econnreset\", \"socket hang up\"].some((s) =>\n\t\tmsg.includes(s),\n\t);\n}\n\nasync function refreshWithRetry(refreshToken: string, signal?: AbortSignal): Promise<TokenSuccessResponse> {\n\tlet lastError: Error | undefined;\n\n\tfor (let attempt = 0; attempt < MAX_REFRESH_RETRIES; attempt++) {\n\t\tif (signal?.aborted) {\n\t\t\tthrow new Error(\"Refresh cancelled\");\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(OAUTH_TOKEN_URL, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\t...buildKimiHeaders(),\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams({\n\t\t\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\t\t\trefresh_token: refreshToken,\n\t\t\t\t\tgrant_type: OAUTH_REFRESH_GRANT,\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\t// Retry on retriable status codes\n\t\t\tif (RETRYABLE_STATUS_CODES.includes(response.status)) {\n\t\t\t\tthrow new RetriableError(`Token refresh failed with status ${response.status}`);\n\t\t\t}\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst text = await response.text();\n\t\t\t\tthrow new Error(`Token refresh failed: ${response.status} ${response.statusText}: ${text}`);\n\t\t\t}\n\n\t\t\tconst raw = await response.json();\n\t\t\tif (!raw || typeof raw !== \"object\" || typeof (raw as Record<string, unknown>).access_token !== \"string\") {\n\t\t\t\tthrow new Error(\"Invalid token refresh response\");\n\t\t\t}\n\n\t\t\treturn raw as unknown as TokenSuccessResponse;\n\t\t} catch (error) {\n\t\t\tlastError = error instanceof Error ? error : new Error(String(error));\n\n\t\t\t// Wrap network errors (TypeError from fetch, or common network failure indicators) as retriable\n\t\t\tif (!(lastError instanceof RetriableError) && isNetworkError(lastError)) {\n\t\t\t\tlastError = new RetriableError(lastError.message);\n\t\t\t}\n\n\t\t\t// Retry on retriable errors (network failures or retriable HTTP status codes)\n\t\t\tif (lastError instanceof RetriableError && attempt < MAX_REFRESH_RETRIES - 1) {\n\t\t\t\tconst backoffMs = Math.min(1000 * 2 ** attempt, 10000);\n\t\t\t\tawait abortableSleep(backoffMs, signal);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthrow lastError;\n\t\t}\n\t}\n\n\tthrow lastError ?? new Error(\"Token refresh failed after retries\");\n}\n\n// ============================================================================\n// Login flow\n// ============================================================================\n\nexport async function loginKimiCoding(options: {\n\tonAuth: (info: { url: string; instructions?: string }) => void;\n\tonProgress?: (message: string) => void;\n\tsignal?: AbortSignal;\n}): Promise<OAuthCredentials> {\n\tconst device = await startDeviceFlow();\n\t// Kimi's device page expects user_code as a query parameter\n\tconst authUrl = new URL(device.verification_uri);\n\tauthUrl.searchParams.set(\"user_code\", device.user_code);\n\toptions.onAuth({\n\t\turl: authUrl.toString(),\n\t\tinstructions: `Enter code: ${device.user_code}`,\n\t});\n\n\tconst tokenResp = await pollForAccessToken(device.device_code, device.interval, device.expires_in, options.signal);\n\n\t// Discover model entitlement\n\toptions.onProgress?.(\"Discovering available models...\");\n\tlet models: KimiModelInfo[] = [];\n\ttry {\n\t\tmodels = await listModels(tokenResp.access_token);\n\t} catch {\n\t\t// Proceed without model enrichment if the models endpoint fails\n\t}\n\n\tconst credentials: KimiCredentials = {\n\t\trefresh: tokenResp.refresh_token,\n\t\taccess: tokenResp.access_token,\n\t\texpires: Date.now() + tokenResp.expires_in * 1000,\n\t};\n\n\tif (models.length > 0) {\n\t\tconst primary = models[0];\n\t\tcredentials.modelId = primary.id;\n\t\tcredentials.contextLength = primary.context_length;\n\t\tcredentials.modelDisplay = primary.display_name;\n\t}\n\n\treturn credentials;\n}\n\n// ============================================================================\n// Refresh\n// ============================================================================\n\nexport async function refreshKimiCodingToken(\n\tcredentials: OAuthCredentials,\n\tsignal?: AbortSignal,\n): Promise<OAuthCredentials> {\n\tconst tokenResp = await refreshWithRetry(credentials.refresh, signal);\n\n\t// Re-discover model entitlement\n\tlet models: KimiModelInfo[] = [];\n\ttry {\n\t\tmodels = await listModels(tokenResp.access_token);\n\t} catch {\n\t\t// Proceed without model enrichment if the models endpoint fails\n\t}\n\n\tconst fresh: KimiCredentials = {\n\t\trefresh: tokenResp.refresh_token ?? credentials.refresh,\n\t\taccess: tokenResp.access_token,\n\t\texpires: Date.now() + tokenResp.expires_in * 1000,\n\t\tmodelId: (credentials as KimiCredentials).modelId,\n\t\tcontextLength: (credentials as KimiCredentials).contextLength,\n\t\tmodelDisplay: (credentials as KimiCredentials).modelDisplay,\n\t};\n\n\tif (models.length > 0) {\n\t\tconst primary = models[0];\n\t\tfresh.modelId = primary.id;\n\t\tfresh.contextLength = primary.context_length;\n\t\tfresh.modelDisplay = primary.display_name;\n\t}\n\n\treturn fresh;\n}\n\n// ============================================================================\n// Provider\n// ============================================================================\n\nexport const kimiCodingOAuthProvider: OAuthProviderInterface = {\n\tid: \"kimi-coding-oauth\",\n\tname: \"Kimi For Coding\",\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginKimiCoding({\n\t\t\tonAuth: callbacks.onAuth,\n\t\t\tonProgress: callbacks.onProgress,\n\t\t\tsignal: callbacks.signal,\n\t\t});\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\treturn refreshKimiCodingToken(credentials);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n\n\tmodifyModels(models: Model<Api>[], credentials: OAuthCredentials): Model<Api>[] {\n\t\tconst creds = credentials as KimiCredentials;\n\t\tconst headers = buildKimiHeaders();\n\n\t\treturn models.map((m) => {\n\t\t\tif (m.provider !== \"kimi-coding-oauth\") return m;\n\n\t\t\tconst updated = {\n\t\t\t\t...m,\n\t\t\t\theaders: { ...headers, ...(m.headers || {}) },\n\t\t\t};\n\n\t\t\tif (creds.modelId) {\n\t\t\t\tupdated.id = creds.modelId;\n\t\t\t}\n\n\t\t\tif (creds.contextLength) {\n\t\t\t\tupdated.contextWindow = creds.contextLength;\n\t\t\t}\n\n\t\t\treturn updated;\n\t\t});\n\t},\n};\n"]}
1
+ {"version":3,"file":"kimi-coding.js","sourceRoot":"","sources":["../../../src/utils/oauth/kimi-coding.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Kimi For Coding OAuth flow (device code)\n *\n * Authenticates against Moonshot's Kimi API (auth.kimi.com) with scope \"kimi-code\".\n * Uses the device authorization grant flow to obtain access/refresh tokens,\n * then discovers the user's model entitlement via the /models endpoint.\n */\n\nimport { execFileSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { Api, Model } from \"../../types.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.js\";\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst KIMI_CLI_VERSION = \"1.35.0\";\nconst USER_AGENT = `KimiCLI/${KIMI_CLI_VERSION}`;\nconst OAUTH_HOST = \"https://auth.kimi.com\";\nconst OAUTH_DEVICE_AUTH_URL = `${OAUTH_HOST}/api/oauth/device_authorization`;\nconst OAUTH_TOKEN_URL = `${OAUTH_HOST}/api/oauth/token`;\nconst OAUTH_CLIENT_ID = \"17e5f671-d194-4dfb-9706-5516cb48c098\";\nconst OAUTH_SCOPE = \"kimi-code\";\nconst OAUTH_DEVICE_GRANT = \"urn:ietf:params:oauth:grant-type:device_code\";\nconst OAUTH_REFRESH_GRANT = \"refresh_token\";\nconst API_BASE_URL = \"https://api.kimi.com/coding/v1\";\n\nconst DEVICE_ID_PATH = path.join(os.homedir(), \".kimi\", \"device_id\");\n\nconst MAX_REFRESH_RETRIES = 3;\n\n// ============================================================================\n// Device ID\n// ============================================================================\n\nfunction generateDeviceId(): string {\n\t// UUID v4 without dashes (hex only, 32 chars)\n\treturn \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\".replace(/x/g, () => Math.floor(Math.random() * 16).toString(16));\n}\n\nfunction getDeviceId(): string {\n\ttry {\n\t\tif (fs.existsSync(DEVICE_ID_PATH)) {\n\t\t\tconst id = fs.readFileSync(DEVICE_ID_PATH, \"utf-8\").trim();\n\t\t\tif (/^[0-9a-f]{32}$/i.test(id)) {\n\t\t\t\treturn id;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Fall through to generate\n\t}\n\n\tconst id = generateDeviceId();\n\ttry {\n\t\tfs.mkdirSync(path.dirname(DEVICE_ID_PATH), { recursive: true });\n\t\tfs.writeFileSync(DEVICE_ID_PATH, id, \"utf-8\");\n\t} catch {\n\t\t// If we can't persist, just use the generated ID for this session\n\t}\n\treturn id;\n}\n\n// ============================================================================\n// Header helpers\n// ============================================================================\n\n/**\n * Strip non-ASCII characters from a string for use in HTTP header values.\n */\nfunction asciiHeaderValue(value: string): string {\n\treturn value.replace(/[^\\x20-\\x7E]/g, \"\");\n}\n\n/**\n * Determine the device model string, mirroring kimi-cli logic.\n */\nfunction kimiDeviceModel(): string {\n\tconst platform = os.platform();\n\tconst machine = os.machine?.() || process.arch;\n\n\tif (platform === \"darwin\") {\n\t\tlet version: string;\n\t\ttry {\n\t\t\tversion = execFileSync(\"sw_vers\", [\"-productVersion\"], { encoding: \"utf-8\", timeout: 3000 }).trim();\n\t\t} catch {\n\t\t\tversion = os.release();\n\t\t}\n\t\treturn `macOS ${version} ${machine}`;\n\t}\n\n\tif (platform === \"win32\") {\n\t\tconst release = os.release();\n\t\tconst buildNumber = Number.parseInt(release.split(\".\").pop() || \"0\", 10);\n\t\tconst label = buildNumber >= 22000 ? \"11\" : \"10\";\n\t\treturn `Windows ${label} ${machine}`;\n\t}\n\n\t// Linux and other\n\treturn `${os.type()} ${os.release()} ${machine}`;\n}\n\n/**\n * Build the standard set of headers required on every Kimi API request.\n */\nexport function buildKimiHeaders(): Record<string, string> {\n\treturn {\n\t\t\"User-Agent\": USER_AGENT,\n\t\t\"X-Msh-Platform\": \"kimi_cli\",\n\t\t\"X-Msh-Version\": KIMI_CLI_VERSION,\n\t\t\"X-Msh-Device-Name\": asciiHeaderValue(os.hostname()),\n\t\t\"X-Msh-Device-Model\": asciiHeaderValue(kimiDeviceModel()),\n\t\t\"X-Msh-Device-Id\": getDeviceId(),\n\t\t\"X-Msh-Os-Version\": asciiHeaderValue(os.version?.() || `${os.type()} ${os.release()}`),\n\t};\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype DeviceCodeResponse = {\n\tdevice_code: string;\n\tuser_code: string;\n\tverification_uri: string;\n\tinterval: number;\n\texpires_in: number;\n};\n\ntype TokenSuccessResponse = {\n\taccess_token: string;\n\trefresh_token: string;\n\texpires_in: number;\n};\n\nexport type KimiModelInfo = {\n\tid: string;\n\tdisplay_name: string;\n\tcontext_length: number;\n\tsupports_reasoning?: boolean;\n\t[key: string]: unknown;\n};\n\ntype KimiCredentials = OAuthCredentials & {\n\tmodelId?: string;\n\tcontextLength?: number;\n\tmodelDisplay?: string;\n};\n\n// ============================================================================\n// Network helpers\n// ============================================================================\n\nasync function fetchJson(url: string, init: RequestInit): Promise<unknown> {\n\tconst response = await fetch(url, init);\n\tif (!response.ok) {\n\t\tconst text = await response.text();\n\t\tthrow new Error(`${response.status} ${response.statusText}: ${text}`);\n\t}\n\treturn response.json();\n}\n\n/**\n * Sleep that can be interrupted by an AbortSignal.\n */\nfunction abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new Error(\"Login cancelled\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst timeout = setTimeout(resolve, ms);\n\n\t\tsignal?.addEventListener(\n\t\t\t\"abort\",\n\t\t\t() => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\treject(new Error(\"Login cancelled\"));\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t});\n}\n\n// ============================================================================\n// Model discovery\n// ============================================================================\n\n/**\n * List available models from the Kimi API.\n * Returns the model info array from the response's `data` field.\n */\nexport async function listModels(accessToken: string): Promise<KimiModelInfo[]> {\n\tconst raw = await fetchJson(`${API_BASE_URL}/models`, {\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\t...buildKimiHeaders(),\n\t\t},\n\t});\n\n\tif (!raw || typeof raw !== \"object\") {\n\t\tthrow new Error(\"Invalid models response\");\n\t}\n\n\tconst data = (raw as Record<string, unknown>).data;\n\tif (!Array.isArray(data)) {\n\t\tthrow new Error(\"Invalid models response: expected data array\");\n\t}\n\n\treturn data as KimiModelInfo[];\n}\n\n// ============================================================================\n// Device flow\n// ============================================================================\n\nasync function startDeviceFlow(): Promise<DeviceCodeResponse> {\n\tconst data = await fetchJson(OAUTH_DEVICE_AUTH_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t...buildKimiHeaders(),\n\t\t},\n\t\tbody: new URLSearchParams({\n\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\tscope: OAUTH_SCOPE,\n\t\t}),\n\t});\n\n\tif (!data || typeof data !== \"object\") {\n\t\tthrow new Error(\"Invalid device code response\");\n\t}\n\n\tconst d = data as Record<string, unknown>;\n\tconst device_code = d.device_code;\n\tconst user_code = d.user_code;\n\tconst verification_uri = d.verification_uri;\n\tconst interval = d.interval;\n\tconst expires_in = d.expires_in;\n\n\tif (\n\t\ttypeof device_code !== \"string\" ||\n\t\ttypeof user_code !== \"string\" ||\n\t\ttypeof verification_uri !== \"string\" ||\n\t\ttypeof interval !== \"number\" ||\n\t\ttypeof expires_in !== \"number\"\n\t) {\n\t\tthrow new Error(\"Invalid device code response fields\");\n\t}\n\n\treturn { device_code, user_code, verification_uri, interval, expires_in };\n}\n\nasync function pollForAccessToken(\n\tdeviceCode: string,\n\tintervalSeconds: number,\n\texpiresIn: number,\n\tsignal?: AbortSignal,\n): Promise<TokenSuccessResponse> {\n\tconst deadline = Date.now() + expiresIn * 1000;\n\tlet intervalMs = Math.max(1000, Math.floor(intervalSeconds * 1000));\n\n\twhile (Date.now() < deadline) {\n\t\tif (signal?.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\n\t\tconst remainingMs = deadline - Date.now();\n\t\tconst waitMs = Math.min(intervalMs, remainingMs);\n\t\tawait abortableSleep(waitMs, signal);\n\n\t\tconst tokenResponse = await fetch(OAUTH_TOKEN_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t...buildKimiHeaders(),\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\t\tdevice_code: deviceCode,\n\t\t\t\tgrant_type: OAUTH_DEVICE_GRANT,\n\t\t\t}),\n\t\t});\n\n\t\t// The token endpoint returns 400 for authorization_pending / slow_down / expired_token.\n\t\t// We must read the body regardless of status to handle the OAuth error codes.\n\t\tconst resp = (await tokenResponse.json()) as Record<string, unknown>;\n\n\t\t// Success: has access_token\n\t\tif (typeof resp.access_token === \"string\") {\n\t\t\treturn resp as unknown as TokenSuccessResponse;\n\t\t}\n\n\t\t// Error response (RFC 8628 §3.5)\n\t\tif (typeof resp.error === \"string\") {\n\t\t\tconst error = resp.error;\n\t\t\tconst description = resp.error_description as string | undefined;\n\t\t\tconst newInterval = resp.interval as number | undefined;\n\n\t\t\tif (error === \"authorization_pending\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (error === \"slow_down\") {\n\t\t\t\tintervalMs =\n\t\t\t\t\ttypeof newInterval === \"number\" && newInterval > 0\n\t\t\t\t\t\t? newInterval * 1000\n\t\t\t\t\t\t: Math.max(1000, intervalMs + 5000);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (error === \"expired_token\") {\n\t\t\t\tthrow new Error(\"Device code expired. Please try logging in again.\");\n\t\t\t}\n\n\t\t\tconst descriptionSuffix = description ? `: ${description}` : \"\";\n\t\t\tthrow new Error(`Device flow failed: ${error}${descriptionSuffix}`);\n\t\t}\n\n\t\t// Unexpected response: valid object but no access_token or error field\n\t\tthrow new Error(`Unexpected token response: ${JSON.stringify(resp)}`);\n\t}\n\n\tthrow new Error(\"Device flow timed out\");\n}\n\n// ============================================================================\n// Refresh with retry\n// ============================================================================\n\nconst RETRYABLE_STATUS_CODES = [429, 500, 502, 503, 504];\n\nclass RetriableError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"RetriableError\";\n\t}\n}\n\n/**\n * Heuristic to detect network-level errors that should be retried.\n * Fetch throws TypeError on network failures; some runtimes include\n * recognizable substrings in the message.\n */\nfunction isNetworkError(error: Error): boolean {\n\tif (error instanceof TypeError) return true;\n\tconst msg = error.message.toLowerCase();\n\treturn [\"fetch failed\", \"econnrefused\", \"etimedout\", \"enotfound\", \"econnreset\", \"socket hang up\"].some((s) =>\n\t\tmsg.includes(s),\n\t);\n}\n\nasync function refreshWithRetry(refreshToken: string, signal?: AbortSignal): Promise<TokenSuccessResponse> {\n\tlet lastError: Error | undefined;\n\n\tfor (let attempt = 0; attempt < MAX_REFRESH_RETRIES; attempt++) {\n\t\tif (signal?.aborted) {\n\t\t\tthrow new Error(\"Refresh cancelled\");\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(OAUTH_TOKEN_URL, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\t...buildKimiHeaders(),\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams({\n\t\t\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\t\t\trefresh_token: refreshToken,\n\t\t\t\t\tgrant_type: OAUTH_REFRESH_GRANT,\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\t// Retry on retriable status codes\n\t\t\tif (RETRYABLE_STATUS_CODES.includes(response.status)) {\n\t\t\t\tthrow new RetriableError(`Token refresh failed with status ${response.status}`);\n\t\t\t}\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst text = await response.text();\n\t\t\t\tthrow new Error(`Token refresh failed: ${response.status} ${response.statusText}: ${text}`);\n\t\t\t}\n\n\t\t\tconst raw = await response.json();\n\t\t\tif (!raw || typeof raw !== \"object\" || typeof (raw as Record<string, unknown>).access_token !== \"string\") {\n\t\t\t\tthrow new Error(\"Invalid token refresh response\");\n\t\t\t}\n\n\t\t\treturn raw as unknown as TokenSuccessResponse;\n\t\t} catch (error) {\n\t\t\tlastError = error instanceof Error ? error : new Error(String(error));\n\n\t\t\t// Wrap network errors (TypeError from fetch, or common network failure indicators) as retriable\n\t\t\tif (!(lastError instanceof RetriableError) && isNetworkError(lastError)) {\n\t\t\t\tlastError = new RetriableError(lastError.message);\n\t\t\t}\n\n\t\t\t// Retry on retriable errors (network failures or retriable HTTP status codes)\n\t\t\tif (lastError instanceof RetriableError && attempt < MAX_REFRESH_RETRIES - 1) {\n\t\t\t\tconst backoffMs = Math.min(1000 * 2 ** attempt, 10000);\n\t\t\t\tawait abortableSleep(backoffMs, signal);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthrow lastError;\n\t\t}\n\t}\n\n\tthrow lastError ?? new Error(\"Token refresh failed after retries\");\n}\n\n// ============================================================================\n// Login flow\n// ============================================================================\n\nexport async function loginKimiCoding(options: {\n\tonAuth: (info: { url: string; instructions?: string }) => void;\n\tonProgress?: (message: string) => void;\n\tsignal?: AbortSignal;\n}): Promise<OAuthCredentials> {\n\tconst device = await startDeviceFlow();\n\t// Kimi's device page expects user_code as a query parameter\n\tconst authUrl = new URL(device.verification_uri);\n\tauthUrl.searchParams.set(\"user_code\", device.user_code);\n\toptions.onAuth({\n\t\turl: authUrl.toString(),\n\t\tinstructions: `Enter code: ${device.user_code}`,\n\t});\n\n\tconst tokenResp = await pollForAccessToken(device.device_code, device.interval, device.expires_in, options.signal);\n\n\t// Discover model entitlement\n\toptions.onProgress?.(\"Discovering available models...\");\n\tlet models: KimiModelInfo[] = [];\n\ttry {\n\t\tmodels = await listModels(tokenResp.access_token);\n\t} catch {\n\t\t// Proceed without model enrichment if the models endpoint fails\n\t}\n\n\tconst credentials: KimiCredentials = {\n\t\trefresh: tokenResp.refresh_token,\n\t\taccess: tokenResp.access_token,\n\t\texpires: Date.now() + tokenResp.expires_in * 1000,\n\t};\n\n\tif (models.length > 0) {\n\t\tconst primary = models[0];\n\t\tcredentials.modelId = primary.id;\n\t\tcredentials.contextLength = primary.context_length;\n\t\tcredentials.modelDisplay = primary.display_name;\n\t}\n\n\treturn credentials;\n}\n\n// ============================================================================\n// Refresh\n// ============================================================================\n\nexport async function refreshKimiCodingToken(\n\tcredentials: OAuthCredentials,\n\tsignal?: AbortSignal,\n): Promise<OAuthCredentials> {\n\tconst tokenResp = await refreshWithRetry(credentials.refresh, signal);\n\n\t// Re-discover model entitlement\n\tlet models: KimiModelInfo[] = [];\n\ttry {\n\t\tmodels = await listModels(tokenResp.access_token);\n\t} catch {\n\t\t// Proceed without model enrichment if the models endpoint fails\n\t}\n\n\tconst fresh: KimiCredentials = {\n\t\trefresh: tokenResp.refresh_token ?? credentials.refresh,\n\t\taccess: tokenResp.access_token,\n\t\texpires: Date.now() + tokenResp.expires_in * 1000,\n\t\tmodelId: (credentials as KimiCredentials).modelId,\n\t\tcontextLength: (credentials as KimiCredentials).contextLength,\n\t\tmodelDisplay: (credentials as KimiCredentials).modelDisplay,\n\t};\n\n\tif (models.length > 0) {\n\t\tconst primary = models[0];\n\t\tfresh.modelId = primary.id;\n\t\tfresh.contextLength = primary.context_length;\n\t\tfresh.modelDisplay = primary.display_name;\n\t}\n\n\treturn fresh;\n}\n\n// ============================================================================\n// Provider\n// ============================================================================\n\nexport const kimiCodingOAuthProvider: OAuthProviderInterface = {\n\tid: \"kimi-coding-oauth\",\n\tname: \"Kimi For Coding\",\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginKimiCoding({\n\t\t\tonAuth: callbacks.onAuth,\n\t\t\tonProgress: callbacks.onProgress,\n\t\t\tsignal: callbacks.signal,\n\t\t});\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\treturn refreshKimiCodingToken(credentials);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n\n\tmodifyModels(models: Model<Api>[], credentials: OAuthCredentials): Model<Api>[] {\n\t\tconst creds = credentials as KimiCredentials;\n\t\tconst headers = buildKimiHeaders();\n\n\t\treturn models.map((m) => {\n\t\t\tif (m.provider !== \"kimi-coding-oauth\") return m;\n\n\t\t\tconst updated = {\n\t\t\t\t...m,\n\t\t\t\t// The OAuth coding endpoint accepts OpenAI-style image_url data URLs for\n\t\t\t\t// kimi-for-coding; keep this capability even if static metadata is stale.\n\t\t\t\tinput: Array.from(new Set([...m.input, \"image\" as const])),\n\t\t\t\theaders: { ...headers, ...(m.headers || {}) },\n\t\t\t};\n\n\t\t\tif (creds.modelId) {\n\t\t\t\tupdated.id = creds.modelId;\n\t\t\t}\n\n\t\t\tif (creds.contextLength) {\n\t\t\t\tupdated.contextWindow = creds.contextLength;\n\t\t\t}\n\n\t\t\treturn updated;\n\t\t});\n\t},\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dreb/ai",
3
- "version": "2.25.1",
3
+ "version": "2.25.3",
4
4
  "description": "Unified LLM API with automatic model discovery and provider configuration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",