@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.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ContextWindowOptions, MODELS, ModelInfo, getContextWindow, getDefaultModel, getMaxThinkingLevel, getModel, getModelsForProvider, getSummaryModel, usesOpenAICodexTransport } from './model-registry.cjs';
|
|
1
|
+
export { ContextWindowOptions, DEFAULT_MAX_VIDEO_BYTES, MODELS, ModelInfo, getContextWindow, getDefaultModel, getMaxThinkingLevel, getModel, getModelsForProvider, getSummaryModel, getVideoByteLimit, usesOpenAICodexTransport } from './model-registry.cjs';
|
|
2
2
|
import { Provider, ThinkingLevel } from '@kenkaiiii/gg-ai';
|
|
3
3
|
export { AppPaths, getAppPaths } from './paths.cjs';
|
|
4
4
|
|
|
@@ -65,6 +65,12 @@ interface OAuthLoginCallbacks {
|
|
|
65
65
|
onStatus: (message: string) => void;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Storage key for Kimi Code OAuth credentials. Kept distinct from the
|
|
70
|
+
* `moonshot` API-key entry so a user can configure BOTH and we always
|
|
71
|
+
* prefer OAuth for the logical `moonshot` provider.
|
|
72
|
+
*/
|
|
73
|
+
declare const MOONSHOT_OAUTH_KEY = "moonshot-oauth";
|
|
68
74
|
declare class AuthStorage {
|
|
69
75
|
private data;
|
|
70
76
|
private filePath;
|
|
@@ -78,6 +84,18 @@ declare class AuthStorage {
|
|
|
78
84
|
listProviders(): Promise<string[]>;
|
|
79
85
|
/** True if credentials exist for `provider`. */
|
|
80
86
|
hasCredentials(provider: string): Promise<boolean>;
|
|
87
|
+
/**
|
|
88
|
+
* True if the user has any usable auth for the logical provider. For
|
|
89
|
+
* `moonshot` this is satisfied by either the Kimi OAuth credential or the
|
|
90
|
+
* Moonshot API key.
|
|
91
|
+
*/
|
|
92
|
+
hasProviderAuth(provider: string): Promise<boolean>;
|
|
93
|
+
/**
|
|
94
|
+
* True if the active credential for `provider` is a static API key with no
|
|
95
|
+
* refresh mechanism. For `moonshot` this is only true when the Kimi OAuth
|
|
96
|
+
* credential is absent (a present OAuth credential is refreshable).
|
|
97
|
+
*/
|
|
98
|
+
isStaticApiKey(provider: string): Promise<boolean>;
|
|
81
99
|
load(): Promise<void>;
|
|
82
100
|
private ensureLoaded;
|
|
83
101
|
getCredentials(provider: string): Promise<OAuthCredentials | undefined>;
|
|
@@ -119,6 +137,52 @@ declare function refreshOpenAIToken(refreshToken: string): Promise<OAuthCredenti
|
|
|
119
137
|
declare function loginGemini(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;
|
|
120
138
|
declare function refreshGeminiToken(refreshToken: string): Promise<OAuthCredentials>;
|
|
121
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Kimi Code OAuth — Device Authorization Grant (RFC 8628).
|
|
142
|
+
*
|
|
143
|
+
* Mirrors MoonshotAI/kimi-code's managed-auth flow. Three form-encoded
|
|
144
|
+
* POST endpoints against the OAuth host (default `https://auth.kimi.com`):
|
|
145
|
+
*
|
|
146
|
+
* - `/api/oauth/device_authorization` (client_id) → device + user code
|
|
147
|
+
* - `/api/oauth/token` (grant_type=device_code) → poll until authorized
|
|
148
|
+
* - `/api/oauth/token` (grant_type=refresh_token) → refresh access token
|
|
149
|
+
*
|
|
150
|
+
* Unlike Anthropic/OpenAI/Gemini (browser-redirect PKCE), this is a
|
|
151
|
+
* device-code/poll flow: we show the user a URL + code, they authorize in a
|
|
152
|
+
* browser on any device, and we poll for the token.
|
|
153
|
+
*
|
|
154
|
+
* After login the issued token is used against the managed coding API
|
|
155
|
+
* (`https://api.kimi.com/coding/v1`, distinct from the `api.moonshot.ai`
|
|
156
|
+
* API-key endpoint) via `Authorization: Bearer <access_token>`. We persist
|
|
157
|
+
* that base URL on the credential so the runtime routes there automatically.
|
|
158
|
+
*/
|
|
159
|
+
|
|
160
|
+
/** Managed coding API base URL the issued OAuth token is used against. */
|
|
161
|
+
declare function kimiCodeBaseUrl(): string;
|
|
162
|
+
/**
|
|
163
|
+
* Headers the Kimi For Coding API requires on every model request. The
|
|
164
|
+
* managed endpoint gates access to recognized coding agents: requests must
|
|
165
|
+
* carry a `kimi_code_cli` platform identity and matching `User-Agent`, or the
|
|
166
|
+
* server rejects with "only available for Coding Agents". Attach these to the
|
|
167
|
+
* inference client's default headers whenever the Kimi OAuth token is used.
|
|
168
|
+
*/
|
|
169
|
+
declare function kimiCodingHeaders(): Record<string, string>;
|
|
170
|
+
/**
|
|
171
|
+
* True if `baseUrl` targets the Kimi For Coding managed endpoint (the URL
|
|
172
|
+
* persisted on Kimi OAuth credentials). Callers use this to decide whether to
|
|
173
|
+
* attach `kimiCodingHeaders()` — the Moonshot API-key path uses a different
|
|
174
|
+
* host and must NOT receive the coding-agent identity headers.
|
|
175
|
+
*/
|
|
176
|
+
declare function isKimiCodingEndpoint(baseUrl: string | undefined): boolean;
|
|
177
|
+
/**
|
|
178
|
+
* Drive the Kimi device-code flow end-to-end. Shows the verification URL +
|
|
179
|
+
* user code via callbacks, opens the browser, and polls until the user
|
|
180
|
+
* authorizes (or a 15-minute local timeout elapses).
|
|
181
|
+
*/
|
|
182
|
+
declare function loginKimi(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;
|
|
183
|
+
/** Exchange a refresh token for a fresh Kimi access token. */
|
|
184
|
+
declare function refreshKimiToken(refreshToken: string): Promise<OAuthCredentials>;
|
|
185
|
+
|
|
122
186
|
/**
|
|
123
187
|
* Minimal Telegram Bot API client using raw fetch().
|
|
124
188
|
* Supports long polling, markdown messages, inline keyboards, and message splitting.
|
|
@@ -292,4 +356,4 @@ interface AutoUpdater {
|
|
|
292
356
|
}
|
|
293
357
|
declare function createAutoUpdater(config: AutoUpdateConfig): AutoUpdater;
|
|
294
358
|
|
|
295
|
-
export { AuthStorage, type AutoUpdateConfig, type AutoUpdater, type InlineButton, type LogLevel, NotLoggedInError, type OAuthCredentials, type OAuthLoginCallbacks, type ProgressCallback, TelegramBot, type TelegramConfig, type TelegramMessage, type TelegramUpdate, type TelegramVoiceMessage, closeLogger, createAutoUpdater, decodeOggOpus, downmixToMono, generatePKCE, getClaudeCliUserAgent, getClaudeCodeVersion, getNextThinkingLevel, getSessionId, getSupportedThinkingLevels, isLoggerOpen, isModelLoaded, isThinkingLevelSupported, log, loginAnthropic, loginGemini, loginOpenAI, openLog, refreshAnthropicToken, refreshGeminiToken, refreshOpenAIToken, registerLogCleanup, resample, setProgressCallback, transcribeVoice, withFileLock };
|
|
359
|
+
export { AuthStorage, type AutoUpdateConfig, type AutoUpdater, type InlineButton, type LogLevel, MOONSHOT_OAUTH_KEY, NotLoggedInError, type OAuthCredentials, type OAuthLoginCallbacks, type ProgressCallback, TelegramBot, type TelegramConfig, type TelegramMessage, type TelegramUpdate, type TelegramVoiceMessage, closeLogger, createAutoUpdater, decodeOggOpus, downmixToMono, generatePKCE, getClaudeCliUserAgent, getClaudeCodeVersion, getNextThinkingLevel, getSessionId, getSupportedThinkingLevels, isKimiCodingEndpoint, isLoggerOpen, isModelLoaded, isThinkingLevelSupported, kimiCodeBaseUrl, kimiCodingHeaders, log, loginAnthropic, loginGemini, loginKimi, loginOpenAI, openLog, refreshAnthropicToken, refreshGeminiToken, refreshKimiToken, refreshOpenAIToken, registerLogCleanup, resample, setProgressCallback, transcribeVoice, withFileLock };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ContextWindowOptions, MODELS, ModelInfo, getContextWindow, getDefaultModel, getMaxThinkingLevel, getModel, getModelsForProvider, getSummaryModel, usesOpenAICodexTransport } from './model-registry.js';
|
|
1
|
+
export { ContextWindowOptions, DEFAULT_MAX_VIDEO_BYTES, MODELS, ModelInfo, getContextWindow, getDefaultModel, getMaxThinkingLevel, getModel, getModelsForProvider, getSummaryModel, getVideoByteLimit, usesOpenAICodexTransport } from './model-registry.js';
|
|
2
2
|
import { Provider, ThinkingLevel } from '@kenkaiiii/gg-ai';
|
|
3
3
|
export { AppPaths, getAppPaths } from './paths.js';
|
|
4
4
|
|
|
@@ -65,6 +65,12 @@ interface OAuthLoginCallbacks {
|
|
|
65
65
|
onStatus: (message: string) => void;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Storage key for Kimi Code OAuth credentials. Kept distinct from the
|
|
70
|
+
* `moonshot` API-key entry so a user can configure BOTH and we always
|
|
71
|
+
* prefer OAuth for the logical `moonshot` provider.
|
|
72
|
+
*/
|
|
73
|
+
declare const MOONSHOT_OAUTH_KEY = "moonshot-oauth";
|
|
68
74
|
declare class AuthStorage {
|
|
69
75
|
private data;
|
|
70
76
|
private filePath;
|
|
@@ -78,6 +84,18 @@ declare class AuthStorage {
|
|
|
78
84
|
listProviders(): Promise<string[]>;
|
|
79
85
|
/** True if credentials exist for `provider`. */
|
|
80
86
|
hasCredentials(provider: string): Promise<boolean>;
|
|
87
|
+
/**
|
|
88
|
+
* True if the user has any usable auth for the logical provider. For
|
|
89
|
+
* `moonshot` this is satisfied by either the Kimi OAuth credential or the
|
|
90
|
+
* Moonshot API key.
|
|
91
|
+
*/
|
|
92
|
+
hasProviderAuth(provider: string): Promise<boolean>;
|
|
93
|
+
/**
|
|
94
|
+
* True if the active credential for `provider` is a static API key with no
|
|
95
|
+
* refresh mechanism. For `moonshot` this is only true when the Kimi OAuth
|
|
96
|
+
* credential is absent (a present OAuth credential is refreshable).
|
|
97
|
+
*/
|
|
98
|
+
isStaticApiKey(provider: string): Promise<boolean>;
|
|
81
99
|
load(): Promise<void>;
|
|
82
100
|
private ensureLoaded;
|
|
83
101
|
getCredentials(provider: string): Promise<OAuthCredentials | undefined>;
|
|
@@ -119,6 +137,52 @@ declare function refreshOpenAIToken(refreshToken: string): Promise<OAuthCredenti
|
|
|
119
137
|
declare function loginGemini(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;
|
|
120
138
|
declare function refreshGeminiToken(refreshToken: string): Promise<OAuthCredentials>;
|
|
121
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Kimi Code OAuth — Device Authorization Grant (RFC 8628).
|
|
142
|
+
*
|
|
143
|
+
* Mirrors MoonshotAI/kimi-code's managed-auth flow. Three form-encoded
|
|
144
|
+
* POST endpoints against the OAuth host (default `https://auth.kimi.com`):
|
|
145
|
+
*
|
|
146
|
+
* - `/api/oauth/device_authorization` (client_id) → device + user code
|
|
147
|
+
* - `/api/oauth/token` (grant_type=device_code) → poll until authorized
|
|
148
|
+
* - `/api/oauth/token` (grant_type=refresh_token) → refresh access token
|
|
149
|
+
*
|
|
150
|
+
* Unlike Anthropic/OpenAI/Gemini (browser-redirect PKCE), this is a
|
|
151
|
+
* device-code/poll flow: we show the user a URL + code, they authorize in a
|
|
152
|
+
* browser on any device, and we poll for the token.
|
|
153
|
+
*
|
|
154
|
+
* After login the issued token is used against the managed coding API
|
|
155
|
+
* (`https://api.kimi.com/coding/v1`, distinct from the `api.moonshot.ai`
|
|
156
|
+
* API-key endpoint) via `Authorization: Bearer <access_token>`. We persist
|
|
157
|
+
* that base URL on the credential so the runtime routes there automatically.
|
|
158
|
+
*/
|
|
159
|
+
|
|
160
|
+
/** Managed coding API base URL the issued OAuth token is used against. */
|
|
161
|
+
declare function kimiCodeBaseUrl(): string;
|
|
162
|
+
/**
|
|
163
|
+
* Headers the Kimi For Coding API requires on every model request. The
|
|
164
|
+
* managed endpoint gates access to recognized coding agents: requests must
|
|
165
|
+
* carry a `kimi_code_cli` platform identity and matching `User-Agent`, or the
|
|
166
|
+
* server rejects with "only available for Coding Agents". Attach these to the
|
|
167
|
+
* inference client's default headers whenever the Kimi OAuth token is used.
|
|
168
|
+
*/
|
|
169
|
+
declare function kimiCodingHeaders(): Record<string, string>;
|
|
170
|
+
/**
|
|
171
|
+
* True if `baseUrl` targets the Kimi For Coding managed endpoint (the URL
|
|
172
|
+
* persisted on Kimi OAuth credentials). Callers use this to decide whether to
|
|
173
|
+
* attach `kimiCodingHeaders()` — the Moonshot API-key path uses a different
|
|
174
|
+
* host and must NOT receive the coding-agent identity headers.
|
|
175
|
+
*/
|
|
176
|
+
declare function isKimiCodingEndpoint(baseUrl: string | undefined): boolean;
|
|
177
|
+
/**
|
|
178
|
+
* Drive the Kimi device-code flow end-to-end. Shows the verification URL +
|
|
179
|
+
* user code via callbacks, opens the browser, and polls until the user
|
|
180
|
+
* authorizes (or a 15-minute local timeout elapses).
|
|
181
|
+
*/
|
|
182
|
+
declare function loginKimi(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;
|
|
183
|
+
/** Exchange a refresh token for a fresh Kimi access token. */
|
|
184
|
+
declare function refreshKimiToken(refreshToken: string): Promise<OAuthCredentials>;
|
|
185
|
+
|
|
122
186
|
/**
|
|
123
187
|
* Minimal Telegram Bot API client using raw fetch().
|
|
124
188
|
* Supports long polling, markdown messages, inline keyboards, and message splitting.
|
|
@@ -292,4 +356,4 @@ interface AutoUpdater {
|
|
|
292
356
|
}
|
|
293
357
|
declare function createAutoUpdater(config: AutoUpdateConfig): AutoUpdater;
|
|
294
358
|
|
|
295
|
-
export { AuthStorage, type AutoUpdateConfig, type AutoUpdater, type InlineButton, type LogLevel, NotLoggedInError, type OAuthCredentials, type OAuthLoginCallbacks, type ProgressCallback, TelegramBot, type TelegramConfig, type TelegramMessage, type TelegramUpdate, type TelegramVoiceMessage, closeLogger, createAutoUpdater, decodeOggOpus, downmixToMono, generatePKCE, getClaudeCliUserAgent, getClaudeCodeVersion, getNextThinkingLevel, getSessionId, getSupportedThinkingLevels, isLoggerOpen, isModelLoaded, isThinkingLevelSupported, log, loginAnthropic, loginGemini, loginOpenAI, openLog, refreshAnthropicToken, refreshGeminiToken, refreshOpenAIToken, registerLogCleanup, resample, setProgressCallback, transcribeVoice, withFileLock };
|
|
359
|
+
export { AuthStorage, type AutoUpdateConfig, type AutoUpdater, type InlineButton, type LogLevel, MOONSHOT_OAUTH_KEY, NotLoggedInError, type OAuthCredentials, type OAuthLoginCallbacks, type ProgressCallback, TelegramBot, type TelegramConfig, type TelegramMessage, type TelegramUpdate, type TelegramVoiceMessage, closeLogger, createAutoUpdater, decodeOggOpus, downmixToMono, generatePKCE, getClaudeCliUserAgent, getClaudeCodeVersion, getNextThinkingLevel, getSessionId, getSupportedThinkingLevels, isKimiCodingEndpoint, isLoggerOpen, isModelLoaded, isThinkingLevelSupported, kimiCodeBaseUrl, kimiCodingHeaders, log, loginAnthropic, loginGemini, loginKimi, loginOpenAI, openLog, refreshAnthropicToken, refreshGeminiToken, refreshKimiToken, refreshOpenAIToken, registerLogCleanup, resample, setProgressCallback, transcribeVoice, withFileLock };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
DEFAULT_MAX_VIDEO_BYTES,
|
|
2
3
|
MODELS,
|
|
3
4
|
getContextWindow,
|
|
4
5
|
getDefaultModel,
|
|
@@ -6,8 +7,9 @@ import {
|
|
|
6
7
|
getModel,
|
|
7
8
|
getModelsForProvider,
|
|
8
9
|
getSummaryModel,
|
|
10
|
+
getVideoByteLimit,
|
|
9
11
|
usesOpenAICodexTransport
|
|
10
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-74Z6I5V7.js";
|
|
11
13
|
import {
|
|
12
14
|
getAppPaths
|
|
13
15
|
} from "./chunk-TZNVRILI.js";
|
|
@@ -951,7 +953,232 @@ function codeAssistHeaders(accessToken) {
|
|
|
951
953
|
};
|
|
952
954
|
}
|
|
953
955
|
|
|
956
|
+
// src/oauth/kimi.ts
|
|
957
|
+
import { execFileSync } from "child_process";
|
|
958
|
+
import { randomUUID } from "crypto";
|
|
959
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
960
|
+
import { arch, hostname, release, type } from "os";
|
|
961
|
+
import path3 from "path";
|
|
962
|
+
var CLIENT_ID3 = "17e5f671-d194-4dfb-9706-5516cb48c098";
|
|
963
|
+
var DEFAULT_OAUTH_HOST = "https://auth.kimi.com";
|
|
964
|
+
var DEFAULT_CODING_BASE_URL = "https://api.kimi.com/coding/v1";
|
|
965
|
+
var KIMI_PLATFORM = "kimi_code_cli";
|
|
966
|
+
var DEFAULT_KIMI_VERSION = "1.0.11";
|
|
967
|
+
var DEVICE_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
968
|
+
function oauthHost() {
|
|
969
|
+
const host = process.env.KIMI_CODE_OAUTH_HOST ?? process.env.KIMI_OAUTH_HOST ?? DEFAULT_OAUTH_HOST;
|
|
970
|
+
return host.replace(/\/+$/, "");
|
|
971
|
+
}
|
|
972
|
+
function kimiCodeBaseUrl() {
|
|
973
|
+
return (process.env.KIMI_CODE_BASE_URL ?? DEFAULT_CODING_BASE_URL).replace(/\/+$/, "");
|
|
974
|
+
}
|
|
975
|
+
function kimiVersion() {
|
|
976
|
+
const v = process.env.KIMI_CODE_VERSION ?? DEFAULT_KIMI_VERSION;
|
|
977
|
+
return asciiHeader(v, DEFAULT_KIMI_VERSION);
|
|
978
|
+
}
|
|
979
|
+
function asciiHeader(value, fallback = "unknown") {
|
|
980
|
+
const cleaned = value.replace(/[^\u0020-\u007E]/g, "").trim();
|
|
981
|
+
return cleaned.length > 0 ? cleaned : fallback;
|
|
982
|
+
}
|
|
983
|
+
function macOsProductVersion() {
|
|
984
|
+
try {
|
|
985
|
+
const version = execFileSync("/usr/bin/sw_vers", ["-productVersion"], {
|
|
986
|
+
encoding: "utf-8",
|
|
987
|
+
timeout: 1e3
|
|
988
|
+
}).trim();
|
|
989
|
+
return version.length > 0 ? version : void 0;
|
|
990
|
+
} catch {
|
|
991
|
+
return void 0;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
function deviceModel() {
|
|
995
|
+
const os = type();
|
|
996
|
+
const version = release();
|
|
997
|
+
const osArch = arch();
|
|
998
|
+
if (os === "Darwin") return `macOS ${macOsProductVersion() ?? version} ${osArch}`;
|
|
999
|
+
if (os === "Windows_NT") return `Windows ${version} ${osArch}`;
|
|
1000
|
+
return `${os} ${version} ${osArch}`.trim();
|
|
1001
|
+
}
|
|
1002
|
+
function deviceId() {
|
|
1003
|
+
const idPath = path3.join(getAppPaths().agentDir, "kimi_device_id");
|
|
1004
|
+
if (existsSync(idPath)) {
|
|
1005
|
+
try {
|
|
1006
|
+
const text = readFileSync(idPath, "utf-8").trim();
|
|
1007
|
+
if (text.length > 0) return text;
|
|
1008
|
+
} catch {
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
const id = randomUUID();
|
|
1012
|
+
try {
|
|
1013
|
+
mkdirSync(getAppPaths().agentDir, { recursive: true, mode: 448 });
|
|
1014
|
+
writeFileSync(idPath, id, { encoding: "utf-8", mode: 384 });
|
|
1015
|
+
} catch {
|
|
1016
|
+
}
|
|
1017
|
+
return id;
|
|
1018
|
+
}
|
|
1019
|
+
function deviceHeaders() {
|
|
1020
|
+
return {
|
|
1021
|
+
"X-Msh-Platform": KIMI_PLATFORM,
|
|
1022
|
+
"X-Msh-Version": kimiVersion(),
|
|
1023
|
+
"X-Msh-Device-Name": asciiHeader(hostname()),
|
|
1024
|
+
"X-Msh-Device-Model": asciiHeader(deviceModel()),
|
|
1025
|
+
"X-Msh-Os-Version": asciiHeader(release()),
|
|
1026
|
+
"X-Msh-Device-Id": deviceId()
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
function kimiCodingHeaders() {
|
|
1030
|
+
return {
|
|
1031
|
+
"User-Agent": `kimi-code-cli/${kimiVersion()}`,
|
|
1032
|
+
...deviceHeaders()
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
1035
|
+
function isKimiCodingEndpoint(baseUrl) {
|
|
1036
|
+
if (typeof baseUrl !== "string" || baseUrl.length === 0) return false;
|
|
1037
|
+
const normalized = baseUrl.replace(/\/+$/, "");
|
|
1038
|
+
return normalized === kimiCodeBaseUrl() || /(^|\.)kimi\.com/i.test(normalized);
|
|
1039
|
+
}
|
|
1040
|
+
async function postForm(endpoint, params) {
|
|
1041
|
+
const response = await fetch(`${oauthHost()}${endpoint}`, {
|
|
1042
|
+
method: "POST",
|
|
1043
|
+
headers: {
|
|
1044
|
+
...deviceHeaders(),
|
|
1045
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
1046
|
+
Accept: "application/json"
|
|
1047
|
+
},
|
|
1048
|
+
body: new URLSearchParams(params).toString()
|
|
1049
|
+
});
|
|
1050
|
+
let data = {};
|
|
1051
|
+
try {
|
|
1052
|
+
const parsed = await response.json();
|
|
1053
|
+
if (parsed && typeof parsed === "object") data = parsed;
|
|
1054
|
+
} catch {
|
|
1055
|
+
}
|
|
1056
|
+
return { status: response.status, data };
|
|
1057
|
+
}
|
|
1058
|
+
function errorDetail(data) {
|
|
1059
|
+
const desc = data.error_description ?? data.message ?? data.error;
|
|
1060
|
+
return typeof desc === "string" && desc.length > 0 ? desc : "unknown error";
|
|
1061
|
+
}
|
|
1062
|
+
function credsFromTokenResponse(data) {
|
|
1063
|
+
const accessToken = data.access_token;
|
|
1064
|
+
const refreshToken = data.refresh_token;
|
|
1065
|
+
const expiresIn = Number(data.expires_in);
|
|
1066
|
+
if (typeof accessToken !== "string" || accessToken.length === 0) {
|
|
1067
|
+
throw new Error("Kimi OAuth response missing access_token.");
|
|
1068
|
+
}
|
|
1069
|
+
if (typeof refreshToken !== "string" || refreshToken.length === 0) {
|
|
1070
|
+
throw new Error("Kimi OAuth response missing refresh_token.");
|
|
1071
|
+
}
|
|
1072
|
+
if (!Number.isFinite(expiresIn) || expiresIn <= 0) {
|
|
1073
|
+
throw new Error("Kimi OAuth response missing or invalid expires_in.");
|
|
1074
|
+
}
|
|
1075
|
+
return {
|
|
1076
|
+
accessToken,
|
|
1077
|
+
refreshToken,
|
|
1078
|
+
expiresAt: Date.now() + expiresIn * 1e3,
|
|
1079
|
+
baseUrl: kimiCodeBaseUrl()
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
async function requestDeviceAuthorization() {
|
|
1083
|
+
const { status, data } = await postForm("/api/oauth/device_authorization", {
|
|
1084
|
+
client_id: CLIENT_ID3
|
|
1085
|
+
});
|
|
1086
|
+
if (status !== 200) {
|
|
1087
|
+
throw new Error(`Kimi device authorization failed (${status}): ${errorDetail(data)}`);
|
|
1088
|
+
}
|
|
1089
|
+
const userCode = data.user_code;
|
|
1090
|
+
const deviceCode = data.device_code;
|
|
1091
|
+
const verificationUriComplete = data.verification_uri_complete;
|
|
1092
|
+
if (typeof userCode !== "string" || typeof deviceCode !== "string") {
|
|
1093
|
+
throw new Error("Kimi device authorization response missing user_code/device_code.");
|
|
1094
|
+
}
|
|
1095
|
+
return {
|
|
1096
|
+
userCode,
|
|
1097
|
+
deviceCode,
|
|
1098
|
+
verificationUri: typeof data.verification_uri === "string" ? data.verification_uri : "",
|
|
1099
|
+
verificationUriComplete: typeof verificationUriComplete === "string" ? verificationUriComplete : "",
|
|
1100
|
+
interval: Number(data.interval ?? 5) || 5
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
async function pollDeviceToken(deviceCode) {
|
|
1104
|
+
const { status, data } = await postForm("/api/oauth/token", {
|
|
1105
|
+
client_id: CLIENT_ID3,
|
|
1106
|
+
device_code: deviceCode,
|
|
1107
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code"
|
|
1108
|
+
});
|
|
1109
|
+
if (status === 200 && typeof data.access_token === "string") {
|
|
1110
|
+
return { kind: "success", creds: credsFromTokenResponse(data) };
|
|
1111
|
+
}
|
|
1112
|
+
if (status >= 500) {
|
|
1113
|
+
throw new Error(`Kimi token polling server error (${status}): ${errorDetail(data)}`);
|
|
1114
|
+
}
|
|
1115
|
+
const errorCode = typeof data.error === "string" ? data.error : "unknown_error";
|
|
1116
|
+
switch (errorCode) {
|
|
1117
|
+
case "authorization_pending":
|
|
1118
|
+
return { kind: "pending" };
|
|
1119
|
+
case "slow_down":
|
|
1120
|
+
return { kind: "slow_down" };
|
|
1121
|
+
case "expired_token":
|
|
1122
|
+
return { kind: "expired" };
|
|
1123
|
+
case "access_denied":
|
|
1124
|
+
return { kind: "denied" };
|
|
1125
|
+
default:
|
|
1126
|
+
throw new Error(`Kimi token polling failed (${status}): ${errorDetail(data)}`);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
function sleep(ms) {
|
|
1130
|
+
return new Promise((resolve) => {
|
|
1131
|
+
setTimeout(resolve, ms);
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
async function loginKimi(callbacks) {
|
|
1135
|
+
const auth = await requestDeviceAuthorization();
|
|
1136
|
+
callbacks.onStatus(
|
|
1137
|
+
`Visit ${auth.verificationUri || auth.verificationUriComplete} and enter code: ${auth.userCode}`
|
|
1138
|
+
);
|
|
1139
|
+
callbacks.onOpenUrl(auth.verificationUriComplete || auth.verificationUri);
|
|
1140
|
+
callbacks.onStatus("Waiting for you to authorize in the browser...");
|
|
1141
|
+
const deadline = Date.now() + DEVICE_TIMEOUT_MS;
|
|
1142
|
+
let interval = Math.max(auth.interval, 1);
|
|
1143
|
+
while (Date.now() < deadline) {
|
|
1144
|
+
await sleep(interval * 1e3);
|
|
1145
|
+
const result = await pollDeviceToken(auth.deviceCode);
|
|
1146
|
+
if (result.kind === "success") return result.creds;
|
|
1147
|
+
if (result.kind === "denied") {
|
|
1148
|
+
throw new Error("Kimi authorization was denied.");
|
|
1149
|
+
}
|
|
1150
|
+
if (result.kind === "expired") {
|
|
1151
|
+
throw new Error("Kimi device code expired. Please run login again.");
|
|
1152
|
+
}
|
|
1153
|
+
if (result.kind === "slow_down") {
|
|
1154
|
+
interval += 5;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
throw new Error("Kimi login timed out. Please run login again.");
|
|
1158
|
+
}
|
|
1159
|
+
async function refreshKimiToken(refreshToken) {
|
|
1160
|
+
const { status, data } = await postForm("/api/oauth/token", {
|
|
1161
|
+
client_id: CLIENT_ID3,
|
|
1162
|
+
grant_type: "refresh_token",
|
|
1163
|
+
refresh_token: refreshToken
|
|
1164
|
+
});
|
|
1165
|
+
if (status === 200 && typeof data.access_token === "string") {
|
|
1166
|
+
return credsFromTokenResponse(data);
|
|
1167
|
+
}
|
|
1168
|
+
const errorCode = typeof data.error === "string" ? data.error : "";
|
|
1169
|
+
throw new Error(`Kimi token refresh failed (${status}): ${errorCode || errorDetail(data)}`);
|
|
1170
|
+
}
|
|
1171
|
+
|
|
954
1172
|
// src/auth-storage.ts
|
|
1173
|
+
var MOONSHOT_OAUTH_KEY = "moonshot-oauth";
|
|
1174
|
+
var STATIC_API_KEY_PROVIDERS = /* @__PURE__ */ new Set([
|
|
1175
|
+
"glm",
|
|
1176
|
+
"moonshot",
|
|
1177
|
+
"xiaomi",
|
|
1178
|
+
"minimax",
|
|
1179
|
+
"deepseek",
|
|
1180
|
+
"openrouter"
|
|
1181
|
+
]);
|
|
955
1182
|
var AuthStorage = class {
|
|
956
1183
|
data = {};
|
|
957
1184
|
filePath;
|
|
@@ -975,6 +1202,30 @@ var AuthStorage = class {
|
|
|
975
1202
|
await this.ensureLoaded();
|
|
976
1203
|
return Boolean(this.data[provider]);
|
|
977
1204
|
}
|
|
1205
|
+
/**
|
|
1206
|
+
* True if the user has any usable auth for the logical provider. For
|
|
1207
|
+
* `moonshot` this is satisfied by either the Kimi OAuth credential or the
|
|
1208
|
+
* Moonshot API key.
|
|
1209
|
+
*/
|
|
1210
|
+
async hasProviderAuth(provider) {
|
|
1211
|
+
await this.ensureLoaded();
|
|
1212
|
+
if (provider === "moonshot") {
|
|
1213
|
+
return Boolean(this.data[MOONSHOT_OAUTH_KEY] || this.data["moonshot"]);
|
|
1214
|
+
}
|
|
1215
|
+
return Boolean(this.data[provider]);
|
|
1216
|
+
}
|
|
1217
|
+
/**
|
|
1218
|
+
* True if the active credential for `provider` is a static API key with no
|
|
1219
|
+
* refresh mechanism. For `moonshot` this is only true when the Kimi OAuth
|
|
1220
|
+
* credential is absent (a present OAuth credential is refreshable).
|
|
1221
|
+
*/
|
|
1222
|
+
async isStaticApiKey(provider) {
|
|
1223
|
+
await this.ensureLoaded();
|
|
1224
|
+
if (provider === "moonshot" && this.data[MOONSHOT_OAUTH_KEY]) {
|
|
1225
|
+
return false;
|
|
1226
|
+
}
|
|
1227
|
+
return STATIC_API_KEY_PROVIDERS.has(provider);
|
|
1228
|
+
}
|
|
978
1229
|
async load() {
|
|
979
1230
|
await withFileLock(this.filePath, async () => {
|
|
980
1231
|
try {
|
|
@@ -1029,11 +1280,21 @@ var AuthStorage = class {
|
|
|
1029
1280
|
*/
|
|
1030
1281
|
async resolveCredentials(provider, opts) {
|
|
1031
1282
|
await this.ensureLoaded();
|
|
1283
|
+
if (provider === "moonshot" && this.data[MOONSHOT_OAUTH_KEY]) {
|
|
1284
|
+
try {
|
|
1285
|
+
return await this.resolveCredentials(MOONSHOT_OAUTH_KEY, opts);
|
|
1286
|
+
} catch (err) {
|
|
1287
|
+
if (err instanceof NotLoggedInError && this.data["moonshot"]) {
|
|
1288
|
+
return this.data["moonshot"];
|
|
1289
|
+
}
|
|
1290
|
+
throw err;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1032
1293
|
const creds = this.data[provider];
|
|
1033
1294
|
if (!creds) {
|
|
1034
1295
|
throw new NotLoggedInError(provider);
|
|
1035
1296
|
}
|
|
1036
|
-
if (provider
|
|
1297
|
+
if (STATIC_API_KEY_PROVIDERS.has(provider)) {
|
|
1037
1298
|
return creds;
|
|
1038
1299
|
}
|
|
1039
1300
|
if (!opts?.forceRefresh && Date.now() < creds.expiresAt) {
|
|
@@ -1052,7 +1313,7 @@ var AuthStorage = class {
|
|
|
1052
1313
|
}
|
|
1053
1314
|
} catch {
|
|
1054
1315
|
}
|
|
1055
|
-
const refreshFn = provider === "anthropic" ? refreshAnthropicToken : provider === "gemini" ? refreshGeminiToken : refreshOpenAIToken;
|
|
1316
|
+
const refreshFn = provider === "anthropic" ? refreshAnthropicToken : provider === "gemini" ? refreshGeminiToken : provider === MOONSHOT_OAUTH_KEY ? refreshKimiToken : refreshOpenAIToken;
|
|
1056
1317
|
let refreshed;
|
|
1057
1318
|
try {
|
|
1058
1319
|
refreshed = await refreshFn(creds.refreshToken);
|
|
@@ -1170,7 +1431,7 @@ var TelegramBot = class {
|
|
|
1170
1431
|
} catch (err) {
|
|
1171
1432
|
if (!this.running) break;
|
|
1172
1433
|
console.error(`[telegram] Poll error: ${err instanceof Error ? err.message : err}`);
|
|
1173
|
-
await
|
|
1434
|
+
await sleep2(3e3);
|
|
1174
1435
|
}
|
|
1175
1436
|
}
|
|
1176
1437
|
}
|
|
@@ -1340,7 +1601,7 @@ function splitMessage(text) {
|
|
|
1340
1601
|
}
|
|
1341
1602
|
return chunks;
|
|
1342
1603
|
}
|
|
1343
|
-
function
|
|
1604
|
+
function sleep2(ms) {
|
|
1344
1605
|
return new Promise((r) => setTimeout(r, ms));
|
|
1345
1606
|
}
|
|
1346
1607
|
|
|
@@ -1427,7 +1688,7 @@ async function transcribeVoice(fileUrl) {
|
|
|
1427
1688
|
// src/auto-update.ts
|
|
1428
1689
|
import { spawn } from "child_process";
|
|
1429
1690
|
import fs5 from "fs";
|
|
1430
|
-
import
|
|
1691
|
+
import path4 from "path";
|
|
1431
1692
|
var CHECK_INTERVAL_MS = 60 * 60 * 1e3;
|
|
1432
1693
|
var FETCH_TIMEOUT_MS2 = 1e4;
|
|
1433
1694
|
function compareVersions(a, b) {
|
|
@@ -1469,7 +1730,7 @@ function createAutoUpdater(config) {
|
|
|
1469
1730
|
function writeState(state) {
|
|
1470
1731
|
try {
|
|
1471
1732
|
const filePath = stateFilePath();
|
|
1472
|
-
fs5.mkdirSync(
|
|
1733
|
+
fs5.mkdirSync(path4.dirname(filePath), { recursive: true, mode: 448 });
|
|
1473
1734
|
fs5.writeFileSync(filePath, JSON.stringify(state));
|
|
1474
1735
|
} catch {
|
|
1475
1736
|
}
|
|
@@ -1594,7 +1855,9 @@ function createAutoUpdater(config) {
|
|
|
1594
1855
|
}
|
|
1595
1856
|
export {
|
|
1596
1857
|
AuthStorage,
|
|
1858
|
+
DEFAULT_MAX_VIDEO_BYTES,
|
|
1597
1859
|
MODELS,
|
|
1860
|
+
MOONSHOT_OAUTH_KEY,
|
|
1598
1861
|
NotLoggedInError,
|
|
1599
1862
|
TelegramBot,
|
|
1600
1863
|
closeLogger,
|
|
@@ -1614,16 +1877,22 @@ export {
|
|
|
1614
1877
|
getSessionId,
|
|
1615
1878
|
getSummaryModel,
|
|
1616
1879
|
getSupportedThinkingLevels,
|
|
1880
|
+
getVideoByteLimit,
|
|
1881
|
+
isKimiCodingEndpoint,
|
|
1617
1882
|
isLoggerOpen,
|
|
1618
1883
|
isModelLoaded,
|
|
1619
1884
|
isThinkingLevelSupported,
|
|
1885
|
+
kimiCodeBaseUrl,
|
|
1886
|
+
kimiCodingHeaders,
|
|
1620
1887
|
log,
|
|
1621
1888
|
loginAnthropic,
|
|
1622
1889
|
loginGemini,
|
|
1890
|
+
loginKimi,
|
|
1623
1891
|
loginOpenAI,
|
|
1624
1892
|
openLog,
|
|
1625
1893
|
refreshAnthropicToken,
|
|
1626
1894
|
refreshGeminiToken,
|
|
1895
|
+
refreshKimiToken,
|
|
1627
1896
|
refreshOpenAIToken,
|
|
1628
1897
|
registerLogCleanup,
|
|
1629
1898
|
resample,
|