@prestyj/core 5.7.0 → 5.9.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-RQADK6HE.js → chunk-JXPW4JKV.js} +482 -288
- package/dist/chunk-JXPW4JKV.js.map +1 -0
- package/dist/index.cjs +672 -365
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -8
- package/dist/index.d.ts +48 -8
- package/dist/index.js +122 -8
- package/dist/index.js.map +1 -1
- package/dist/model-registry.cjs +91 -24
- package/dist/model-registry.cjs.map +1 -1
- package/dist/model-registry.d.cts +24 -2
- package/dist/model-registry.d.ts +24 -2
- package/dist/model-registry.js +5 -1
- package/package.json +2 -2
- package/dist/chunk-RQADK6HE.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -51,6 +51,7 @@ __export(index_exports, {
|
|
|
51
51
|
getClaudeCodeVersion: () => getClaudeCodeVersion,
|
|
52
52
|
getContextWindow: () => getContextWindow,
|
|
53
53
|
getDefaultModel: () => getDefaultModel,
|
|
54
|
+
getDefaultThinkingLevel: () => getDefaultThinkingLevel,
|
|
54
55
|
getFastModel: () => getFastModel,
|
|
55
56
|
getMaxThinkingLevel: () => getMaxThinkingLevel,
|
|
56
57
|
getModel: () => getModel,
|
|
@@ -59,6 +60,7 @@ __export(index_exports, {
|
|
|
59
60
|
getSessionId: () => getSessionId,
|
|
60
61
|
getSummaryModel: () => getSummaryModel,
|
|
61
62
|
getSupportedThinkingLevels: () => getSupportedThinkingLevels,
|
|
63
|
+
getToolResultCharLimit: () => getToolResultCharLimit,
|
|
62
64
|
getVideoByteLimit: () => getVideoByteLimit,
|
|
63
65
|
isKimiCodingEndpoint: () => isKimiCodingEndpoint,
|
|
64
66
|
isLoggerOpen: () => isLoggerOpen,
|
|
@@ -72,6 +74,7 @@ __export(index_exports, {
|
|
|
72
74
|
loginKimi: () => loginKimi,
|
|
73
75
|
loginOpenAI: () => loginOpenAI,
|
|
74
76
|
openLog: () => openLog,
|
|
77
|
+
readStoredBaseUrlSync: () => readStoredBaseUrlSync,
|
|
75
78
|
refreshAnthropicToken: () => refreshAnthropicToken,
|
|
76
79
|
refreshGeminiToken: () => refreshGeminiToken,
|
|
77
80
|
refreshKimiToken: () => refreshKimiToken,
|
|
@@ -85,9 +88,12 @@ __export(index_exports, {
|
|
|
85
88
|
});
|
|
86
89
|
module.exports = __toCommonJS(index_exports);
|
|
87
90
|
|
|
88
|
-
// src/
|
|
89
|
-
var
|
|
90
|
-
var
|
|
91
|
+
// src/oauth/kimi.ts
|
|
92
|
+
var import_node_child_process = require("child_process");
|
|
93
|
+
var import_node_crypto = require("crypto");
|
|
94
|
+
var import_node_fs = require("fs");
|
|
95
|
+
var import_node_os2 = require("os");
|
|
96
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
91
97
|
|
|
92
98
|
// src/paths.ts
|
|
93
99
|
var import_node_path = __toESM(require("path"), 1);
|
|
@@ -114,8 +120,225 @@ function getAppPaths() {
|
|
|
114
120
|
};
|
|
115
121
|
}
|
|
116
122
|
|
|
123
|
+
// src/oauth/kimi.ts
|
|
124
|
+
var CLIENT_ID = "17e5f671-d194-4dfb-9706-5516cb48c098";
|
|
125
|
+
var DEFAULT_OAUTH_HOST = "https://auth.kimi.com";
|
|
126
|
+
var DEFAULT_CODING_BASE_URL = "https://api.kimi.com/coding/v1";
|
|
127
|
+
var KIMI_PLATFORM = "kimi_code_cli";
|
|
128
|
+
var DEFAULT_KIMI_VERSION = "1.0.11";
|
|
129
|
+
var DEVICE_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
130
|
+
function oauthHost() {
|
|
131
|
+
const host = process.env.KIMI_CODE_OAUTH_HOST ?? process.env.KIMI_OAUTH_HOST ?? DEFAULT_OAUTH_HOST;
|
|
132
|
+
return host.replace(/\/+$/, "");
|
|
133
|
+
}
|
|
134
|
+
function kimiCodeBaseUrl() {
|
|
135
|
+
return (process.env.KIMI_CODE_BASE_URL ?? DEFAULT_CODING_BASE_URL).replace(/\/+$/, "");
|
|
136
|
+
}
|
|
137
|
+
function kimiVersion() {
|
|
138
|
+
const v = process.env.KIMI_CODE_VERSION ?? DEFAULT_KIMI_VERSION;
|
|
139
|
+
return asciiHeader(v, DEFAULT_KIMI_VERSION);
|
|
140
|
+
}
|
|
141
|
+
function asciiHeader(value, fallback = "unknown") {
|
|
142
|
+
const cleaned = value.replace(/[^\u0020-\u007E]/g, "").trim();
|
|
143
|
+
return cleaned.length > 0 ? cleaned : fallback;
|
|
144
|
+
}
|
|
145
|
+
function macOsProductVersion() {
|
|
146
|
+
try {
|
|
147
|
+
const version = (0, import_node_child_process.execFileSync)("/usr/bin/sw_vers", ["-productVersion"], {
|
|
148
|
+
encoding: "utf-8",
|
|
149
|
+
timeout: 1e3
|
|
150
|
+
}).trim();
|
|
151
|
+
return version.length > 0 ? version : void 0;
|
|
152
|
+
} catch {
|
|
153
|
+
return void 0;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function deviceModel() {
|
|
157
|
+
const os2 = (0, import_node_os2.type)();
|
|
158
|
+
const version = (0, import_node_os2.release)();
|
|
159
|
+
const osArch = (0, import_node_os2.arch)();
|
|
160
|
+
if (os2 === "Darwin") return `macOS ${macOsProductVersion() ?? version} ${osArch}`;
|
|
161
|
+
if (os2 === "Windows_NT") return `Windows ${version} ${osArch}`;
|
|
162
|
+
return `${os2} ${version} ${osArch}`.trim();
|
|
163
|
+
}
|
|
164
|
+
function deviceId() {
|
|
165
|
+
const idPath = import_node_path2.default.join(getAppPaths().agentDir, "kimi_device_id");
|
|
166
|
+
if ((0, import_node_fs.existsSync)(idPath)) {
|
|
167
|
+
try {
|
|
168
|
+
const text = (0, import_node_fs.readFileSync)(idPath, "utf-8").trim();
|
|
169
|
+
if (text.length > 0) return text;
|
|
170
|
+
} catch {
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const id = (0, import_node_crypto.randomUUID)();
|
|
174
|
+
try {
|
|
175
|
+
(0, import_node_fs.mkdirSync)(getAppPaths().agentDir, { recursive: true, mode: 448 });
|
|
176
|
+
(0, import_node_fs.writeFileSync)(idPath, id, { encoding: "utf-8", mode: 384 });
|
|
177
|
+
} catch {
|
|
178
|
+
}
|
|
179
|
+
return id;
|
|
180
|
+
}
|
|
181
|
+
function deviceHeaders() {
|
|
182
|
+
return {
|
|
183
|
+
"X-Msh-Platform": KIMI_PLATFORM,
|
|
184
|
+
"X-Msh-Version": kimiVersion(),
|
|
185
|
+
"X-Msh-Device-Name": asciiHeader((0, import_node_os2.hostname)()),
|
|
186
|
+
"X-Msh-Device-Model": asciiHeader(deviceModel()),
|
|
187
|
+
"X-Msh-Os-Version": asciiHeader((0, import_node_os2.release)()),
|
|
188
|
+
"X-Msh-Device-Id": deviceId()
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function kimiCodingHeaders() {
|
|
192
|
+
return {
|
|
193
|
+
"User-Agent": `kimi-code-cli/${kimiVersion()}`,
|
|
194
|
+
...deviceHeaders()
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function isKimiCodingEndpoint(baseUrl) {
|
|
198
|
+
if (typeof baseUrl !== "string" || baseUrl.length === 0) return false;
|
|
199
|
+
const normalized = baseUrl.replace(/\/+$/, "");
|
|
200
|
+
return normalized === kimiCodeBaseUrl() || /(^|\.)kimi\.com/i.test(normalized);
|
|
201
|
+
}
|
|
202
|
+
async function postForm(endpoint, params) {
|
|
203
|
+
const response = await fetch(`${oauthHost()}${endpoint}`, {
|
|
204
|
+
method: "POST",
|
|
205
|
+
headers: {
|
|
206
|
+
...deviceHeaders(),
|
|
207
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
208
|
+
Accept: "application/json"
|
|
209
|
+
},
|
|
210
|
+
body: new URLSearchParams(params).toString()
|
|
211
|
+
});
|
|
212
|
+
let data = {};
|
|
213
|
+
try {
|
|
214
|
+
const parsed = await response.json();
|
|
215
|
+
if (parsed && typeof parsed === "object") data = parsed;
|
|
216
|
+
} catch {
|
|
217
|
+
}
|
|
218
|
+
return { status: response.status, data };
|
|
219
|
+
}
|
|
220
|
+
function errorDetail(data) {
|
|
221
|
+
const desc = data.error_description ?? data.message ?? data.error;
|
|
222
|
+
return typeof desc === "string" && desc.length > 0 ? desc : "unknown error";
|
|
223
|
+
}
|
|
224
|
+
function credsFromTokenResponse(data, opts) {
|
|
225
|
+
const accessToken = data.access_token;
|
|
226
|
+
const responseRefreshToken = data.refresh_token;
|
|
227
|
+
const expiresIn = Number(data.expires_in);
|
|
228
|
+
if (typeof accessToken !== "string" || accessToken.length === 0) {
|
|
229
|
+
throw new Error("Kimi OAuth response missing access_token.");
|
|
230
|
+
}
|
|
231
|
+
const refreshToken = typeof responseRefreshToken === "string" && responseRefreshToken.length > 0 ? responseRefreshToken : opts?.fallbackRefreshToken ?? "";
|
|
232
|
+
if (refreshToken.length === 0) {
|
|
233
|
+
throw new Error("Kimi OAuth response missing refresh_token.");
|
|
234
|
+
}
|
|
235
|
+
if (!Number.isFinite(expiresIn) || expiresIn <= 0) {
|
|
236
|
+
throw new Error("Kimi OAuth response missing or invalid expires_in.");
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
accessToken,
|
|
240
|
+
refreshToken,
|
|
241
|
+
expiresAt: Date.now() + expiresIn * 1e3,
|
|
242
|
+
baseUrl: kimiCodeBaseUrl()
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
async function requestDeviceAuthorization() {
|
|
246
|
+
const { status, data } = await postForm("/api/oauth/device_authorization", {
|
|
247
|
+
client_id: CLIENT_ID
|
|
248
|
+
});
|
|
249
|
+
if (status !== 200) {
|
|
250
|
+
throw new Error(`Kimi device authorization failed (${status}): ${errorDetail(data)}`);
|
|
251
|
+
}
|
|
252
|
+
const userCode = data.user_code;
|
|
253
|
+
const deviceCode = data.device_code;
|
|
254
|
+
const verificationUriComplete = data.verification_uri_complete;
|
|
255
|
+
if (typeof userCode !== "string" || typeof deviceCode !== "string") {
|
|
256
|
+
throw new Error("Kimi device authorization response missing user_code/device_code.");
|
|
257
|
+
}
|
|
258
|
+
return {
|
|
259
|
+
userCode,
|
|
260
|
+
deviceCode,
|
|
261
|
+
verificationUri: typeof data.verification_uri === "string" ? data.verification_uri : "",
|
|
262
|
+
verificationUriComplete: typeof verificationUriComplete === "string" ? verificationUriComplete : "",
|
|
263
|
+
interval: Number(data.interval ?? 5) || 5
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
async function pollDeviceToken(deviceCode) {
|
|
267
|
+
const { status, data } = await postForm("/api/oauth/token", {
|
|
268
|
+
client_id: CLIENT_ID,
|
|
269
|
+
device_code: deviceCode,
|
|
270
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code"
|
|
271
|
+
});
|
|
272
|
+
if (status === 200 && typeof data.access_token === "string") {
|
|
273
|
+
return { kind: "success", creds: credsFromTokenResponse(data) };
|
|
274
|
+
}
|
|
275
|
+
if (status >= 500) {
|
|
276
|
+
throw new Error(`Kimi token polling server error (${status}): ${errorDetail(data)}`);
|
|
277
|
+
}
|
|
278
|
+
const errorCode = typeof data.error === "string" ? data.error : "unknown_error";
|
|
279
|
+
switch (errorCode) {
|
|
280
|
+
case "authorization_pending":
|
|
281
|
+
return { kind: "pending" };
|
|
282
|
+
case "slow_down":
|
|
283
|
+
return { kind: "slow_down" };
|
|
284
|
+
case "expired_token":
|
|
285
|
+
return { kind: "expired" };
|
|
286
|
+
case "access_denied":
|
|
287
|
+
return { kind: "denied" };
|
|
288
|
+
default:
|
|
289
|
+
throw new Error(`Kimi token polling failed (${status}): ${errorDetail(data)}`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function sleep(ms) {
|
|
293
|
+
return new Promise((resolve) => {
|
|
294
|
+
setTimeout(resolve, ms);
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
async function loginKimi(callbacks) {
|
|
298
|
+
const auth = await requestDeviceAuthorization();
|
|
299
|
+
callbacks.onStatus(
|
|
300
|
+
`Visit ${auth.verificationUri || auth.verificationUriComplete} and enter code: ${auth.userCode}`
|
|
301
|
+
);
|
|
302
|
+
callbacks.onOpenUrl(auth.verificationUriComplete || auth.verificationUri);
|
|
303
|
+
callbacks.onStatus("Waiting for you to authorize in the browser...");
|
|
304
|
+
const deadline = Date.now() + DEVICE_TIMEOUT_MS;
|
|
305
|
+
let interval = Math.max(auth.interval, 1);
|
|
306
|
+
while (Date.now() < deadline) {
|
|
307
|
+
await sleep(interval * 1e3);
|
|
308
|
+
const result = await pollDeviceToken(auth.deviceCode);
|
|
309
|
+
if (result.kind === "success") return result.creds;
|
|
310
|
+
if (result.kind === "denied") {
|
|
311
|
+
throw new Error("Kimi authorization was denied.");
|
|
312
|
+
}
|
|
313
|
+
if (result.kind === "expired") {
|
|
314
|
+
throw new Error("Kimi device code expired. Please run login again.");
|
|
315
|
+
}
|
|
316
|
+
if (result.kind === "slow_down") {
|
|
317
|
+
interval += 5;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
throw new Error("Kimi login timed out. Please run login again.");
|
|
321
|
+
}
|
|
322
|
+
async function refreshKimiToken(refreshToken) {
|
|
323
|
+
const { status, data } = await postForm("/api/oauth/token", {
|
|
324
|
+
client_id: CLIENT_ID,
|
|
325
|
+
grant_type: "refresh_token",
|
|
326
|
+
refresh_token: refreshToken
|
|
327
|
+
});
|
|
328
|
+
if (status === 200 && typeof data.access_token === "string") {
|
|
329
|
+
return credsFromTokenResponse(data, { fallbackRefreshToken: refreshToken });
|
|
330
|
+
}
|
|
331
|
+
const errorCode = typeof data.error === "string" ? data.error : "";
|
|
332
|
+
throw new Error(`Kimi token refresh failed (${status}): ${errorCode || errorDetail(data)}`);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// src/auth-storage.ts
|
|
336
|
+
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
337
|
+
var import_node_fs3 = require("fs");
|
|
338
|
+
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
339
|
+
|
|
117
340
|
// src/oauth/anthropic.ts
|
|
118
|
-
var
|
|
341
|
+
var import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
119
342
|
|
|
120
343
|
// src/oauth/pkce.ts
|
|
121
344
|
function base64urlEncode(bytes) {
|
|
@@ -137,49 +360,66 @@ async function generatePKCE() {
|
|
|
137
360
|
|
|
138
361
|
// src/claude-code-version.ts
|
|
139
362
|
var import_promises = __toESM(require("fs/promises"), 1);
|
|
140
|
-
var
|
|
363
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
141
364
|
|
|
142
365
|
// src/logger.ts
|
|
143
|
-
var
|
|
144
|
-
var
|
|
145
|
-
var
|
|
366
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
367
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
368
|
+
var import_node_crypto2 = require("crypto");
|
|
146
369
|
var import_ai = require("@prestyj/ai");
|
|
147
370
|
var MAX_BYTES = 10 * 1024 * 1024;
|
|
148
371
|
var fd = null;
|
|
372
|
+
var bytesWritten = 0;
|
|
373
|
+
var capped = false;
|
|
149
374
|
var sessionId = "";
|
|
150
375
|
var appName = "app";
|
|
151
376
|
var cleanups = [];
|
|
152
377
|
var exactSecrets = [];
|
|
153
378
|
function rotateIfNeeded(filePath) {
|
|
154
379
|
try {
|
|
155
|
-
const st =
|
|
380
|
+
const st = import_node_fs2.default.statSync(filePath);
|
|
156
381
|
if (st.size < MAX_BYTES) return;
|
|
157
382
|
const rotated = `${filePath}.1`;
|
|
158
383
|
try {
|
|
159
|
-
|
|
384
|
+
import_node_fs2.default.unlinkSync(rotated);
|
|
160
385
|
} catch {
|
|
161
386
|
}
|
|
162
|
-
|
|
387
|
+
import_node_fs2.default.renameSync(filePath, rotated);
|
|
163
388
|
} catch {
|
|
164
389
|
}
|
|
165
390
|
}
|
|
166
391
|
function openLog(filePath, name) {
|
|
167
|
-
if (fd !== null) return false;
|
|
392
|
+
if (fd !== null || capped) return false;
|
|
168
393
|
appName = name;
|
|
169
394
|
exactSecrets = (0, import_ai.environmentSecrets)(process.env);
|
|
170
395
|
try {
|
|
171
|
-
|
|
396
|
+
import_node_fs2.default.mkdirSync(import_node_path3.default.dirname(filePath), { recursive: true, mode: 448 });
|
|
172
397
|
} catch {
|
|
173
398
|
}
|
|
174
399
|
rotateIfNeeded(filePath);
|
|
175
400
|
try {
|
|
176
|
-
fd =
|
|
401
|
+
fd = import_node_fs2.default.openSync(filePath, "a");
|
|
177
402
|
} catch {
|
|
403
|
+
fd = null;
|
|
404
|
+
bytesWritten = 0;
|
|
178
405
|
return false;
|
|
179
406
|
}
|
|
180
|
-
sessionId = (0, import_node_crypto.randomBytes)(4).toString("hex");
|
|
181
407
|
try {
|
|
182
|
-
|
|
408
|
+
bytesWritten = import_node_fs2.default.fstatSync(fd).size;
|
|
409
|
+
} catch {
|
|
410
|
+
try {
|
|
411
|
+
import_node_fs2.default.closeSync(fd);
|
|
412
|
+
} catch {
|
|
413
|
+
}
|
|
414
|
+
fd = null;
|
|
415
|
+
bytesWritten = 0;
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
sessionId = (0, import_node_crypto2.randomBytes)(4).toString("hex");
|
|
419
|
+
try {
|
|
420
|
+
if (bytesWritten < MAX_BYTES) {
|
|
421
|
+
bytesWritten += import_node_fs2.default.writeSync(fd, "\n");
|
|
422
|
+
}
|
|
183
423
|
} catch {
|
|
184
424
|
}
|
|
185
425
|
return true;
|
|
@@ -205,8 +445,23 @@ function log(level, category, message, data) {
|
|
|
205
445
|
if (pairs) line += ` ${pairs}`;
|
|
206
446
|
}
|
|
207
447
|
line += "\n";
|
|
448
|
+
const lineBytes = Buffer.byteLength(line);
|
|
449
|
+
if (bytesWritten + lineBytes > MAX_BYTES) {
|
|
450
|
+
const capLine = `[${ts}] [sid=${sessionId}] [WARN] [logger] Log cap reached; file logging disabled until restart
|
|
451
|
+
`;
|
|
452
|
+
try {
|
|
453
|
+
if (bytesWritten + Buffer.byteLength(capLine) <= MAX_BYTES) {
|
|
454
|
+
bytesWritten += import_node_fs2.default.writeSync(fd, capLine);
|
|
455
|
+
}
|
|
456
|
+
import_node_fs2.default.closeSync(fd);
|
|
457
|
+
} catch {
|
|
458
|
+
}
|
|
459
|
+
fd = null;
|
|
460
|
+
capped = true;
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
208
463
|
try {
|
|
209
|
-
|
|
464
|
+
bytesWritten += import_node_fs2.default.writeSync(fd, line);
|
|
210
465
|
} catch {
|
|
211
466
|
}
|
|
212
467
|
}
|
|
@@ -214,13 +469,16 @@ function registerLogCleanup(fn) {
|
|
|
214
469
|
cleanups.push(fn);
|
|
215
470
|
}
|
|
216
471
|
function closeLogger(opts) {
|
|
217
|
-
if (fd
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
472
|
+
if (fd !== null) {
|
|
473
|
+
if (opts?.shutdownLine !== false) log("INFO", "shutdown", `${appName} shutting down`);
|
|
474
|
+
try {
|
|
475
|
+
if (fd !== null) import_node_fs2.default.closeSync(fd);
|
|
476
|
+
} catch {
|
|
477
|
+
}
|
|
222
478
|
}
|
|
223
479
|
fd = null;
|
|
480
|
+
bytesWritten = 0;
|
|
481
|
+
capped = false;
|
|
224
482
|
exactSecrets = [];
|
|
225
483
|
for (const unsub of cleanups) unsub();
|
|
226
484
|
cleanups = [];
|
|
@@ -234,7 +492,7 @@ var FALLBACK_VERSION = "2.1.88";
|
|
|
234
492
|
var memoryCache = null;
|
|
235
493
|
var inflight = null;
|
|
236
494
|
function cachePath() {
|
|
237
|
-
return
|
|
495
|
+
return import_node_path4.default.join(getAppPaths().agentDir, "claude-code-version.json");
|
|
238
496
|
}
|
|
239
497
|
async function readDiskCache() {
|
|
240
498
|
try {
|
|
@@ -316,7 +574,7 @@ async function getClaudeCliUserAgent() {
|
|
|
316
574
|
}
|
|
317
575
|
|
|
318
576
|
// src/oauth/anthropic.ts
|
|
319
|
-
var
|
|
577
|
+
var CLIENT_ID2 = atob("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
|
|
320
578
|
var AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
|
|
321
579
|
var TOKEN_URLS = [
|
|
322
580
|
"https://platform.claude.com/v1/oauth/token",
|
|
@@ -360,10 +618,10 @@ function toCredentials(data) {
|
|
|
360
618
|
}
|
|
361
619
|
async function loginAnthropic(callbacks) {
|
|
362
620
|
const { verifier, challenge } = await generatePKCE();
|
|
363
|
-
const state =
|
|
621
|
+
const state = import_node_crypto3.default.randomBytes(16).toString("hex");
|
|
364
622
|
const params = new URLSearchParams({
|
|
365
623
|
code: "true",
|
|
366
|
-
client_id:
|
|
624
|
+
client_id: CLIENT_ID2,
|
|
367
625
|
response_type: "code",
|
|
368
626
|
redirect_uri: REDIRECT_URI,
|
|
369
627
|
scope: SCOPES,
|
|
@@ -384,7 +642,7 @@ async function exchangeAnthropicCode(code, state, verifier) {
|
|
|
384
642
|
const data = await postTokenRequest(
|
|
385
643
|
{
|
|
386
644
|
grant_type: "authorization_code",
|
|
387
|
-
client_id:
|
|
645
|
+
client_id: CLIENT_ID2,
|
|
388
646
|
code,
|
|
389
647
|
state,
|
|
390
648
|
redirect_uri: REDIRECT_URI,
|
|
@@ -398,7 +656,7 @@ async function refreshAnthropicToken(refreshToken) {
|
|
|
398
656
|
const data = await postTokenRequest(
|
|
399
657
|
{
|
|
400
658
|
grant_type: "refresh_token",
|
|
401
|
-
client_id:
|
|
659
|
+
client_id: CLIENT_ID2,
|
|
402
660
|
refresh_token: refreshToken
|
|
403
661
|
},
|
|
404
662
|
"token refresh"
|
|
@@ -408,8 +666,8 @@ async function refreshAnthropicToken(refreshToken) {
|
|
|
408
666
|
|
|
409
667
|
// src/oauth/openai.ts
|
|
410
668
|
var import_node_http = __toESM(require("http"), 1);
|
|
411
|
-
var
|
|
412
|
-
var
|
|
669
|
+
var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
670
|
+
var CLIENT_ID3 = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
413
671
|
var AUTHORIZE_URL2 = "https://auth.openai.com/oauth/authorize";
|
|
414
672
|
var TOKEN_URL = "https://auth.openai.com/oauth/token";
|
|
415
673
|
var REDIRECT_URI2 = "http://localhost:1455/auth/callback";
|
|
@@ -417,10 +675,10 @@ var SCOPE = "openid profile email offline_access api.connectors.read api.connect
|
|
|
417
675
|
var JWT_CLAIM_PATH = "https://api.openai.com/auth";
|
|
418
676
|
async function loginOpenAI(callbacks) {
|
|
419
677
|
const { verifier, challenge } = await generatePKCE();
|
|
420
|
-
const state =
|
|
678
|
+
const state = import_node_crypto4.default.randomBytes(16).toString("hex");
|
|
421
679
|
const url = new URL(AUTHORIZE_URL2);
|
|
422
680
|
url.searchParams.set("response_type", "code");
|
|
423
|
-
url.searchParams.set("client_id",
|
|
681
|
+
url.searchParams.set("client_id", CLIENT_ID3);
|
|
424
682
|
url.searchParams.set("redirect_uri", REDIRECT_URI2);
|
|
425
683
|
url.searchParams.set("scope", SCOPE);
|
|
426
684
|
url.searchParams.set("code_challenge", challenge);
|
|
@@ -541,7 +799,7 @@ async function exchangeOpenAICode(code, verifier) {
|
|
|
541
799
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
542
800
|
body: new URLSearchParams({
|
|
543
801
|
grant_type: "authorization_code",
|
|
544
|
-
client_id:
|
|
802
|
+
client_id: CLIENT_ID3,
|
|
545
803
|
code,
|
|
546
804
|
redirect_uri: REDIRECT_URI2,
|
|
547
805
|
code_verifier: verifier
|
|
@@ -565,7 +823,7 @@ async function refreshOpenAIToken(refreshToken) {
|
|
|
565
823
|
body: new URLSearchParams({
|
|
566
824
|
grant_type: "refresh_token",
|
|
567
825
|
refresh_token: refreshToken,
|
|
568
|
-
client_id:
|
|
826
|
+
client_id: CLIENT_ID3
|
|
569
827
|
})
|
|
570
828
|
});
|
|
571
829
|
if (!response.ok) {
|
|
@@ -587,7 +845,7 @@ async function refreshOpenAIToken(refreshToken) {
|
|
|
587
845
|
|
|
588
846
|
// src/oauth/gemini.ts
|
|
589
847
|
var import_node_http2 = __toESM(require("http"), 1);
|
|
590
|
-
var
|
|
848
|
+
var import_node_crypto5 = __toESM(require("crypto"), 1);
|
|
591
849
|
var CLIENT_ID_ENV = "GGCODER_GEMINI_OAUTH_CLIENT_ID";
|
|
592
850
|
var CLIENT_SECRET_ENV = "GGCODER_GEMINI_OAUTH_CLIENT_SECRET";
|
|
593
851
|
var DEFAULT_CLIENT_ID = "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com";
|
|
@@ -621,7 +879,7 @@ var CodeAssistHttpError = class extends Error {
|
|
|
621
879
|
async function loginGemini(callbacks) {
|
|
622
880
|
const { clientId, clientSecret } = getGeminiOAuthClientCredentials();
|
|
623
881
|
const { verifier, challenge } = await generatePKCE();
|
|
624
|
-
const state =
|
|
882
|
+
const state = import_node_crypto5.default.randomBytes(32).toString("hex");
|
|
625
883
|
const redirectUri = await getLoopbackRedirectUri();
|
|
626
884
|
const url = new URL(AUTHORIZE_URL3);
|
|
627
885
|
url.searchParams.set("response_type", "code");
|
|
@@ -880,289 +1138,72 @@ function throwProjectError(response) {
|
|
|
880
1138
|
);
|
|
881
1139
|
}
|
|
882
1140
|
async function codeAssistPost(accessToken, method, body) {
|
|
883
|
-
let lastError;
|
|
884
|
-
for (let attempt = 0; attempt <= CODE_ASSIST_POST_RETRIES; attempt++) {
|
|
885
|
-
try {
|
|
886
|
-
return await codeAssistRequest(getCodeAssistMethodUrl(method), accessToken, method, {
|
|
887
|
-
method: "POST",
|
|
888
|
-
body: JSON.stringify(body)
|
|
889
|
-
});
|
|
890
|
-
} catch (err) {
|
|
891
|
-
if (!(err instanceof CodeAssistHttpError) || attempt === CODE_ASSIST_POST_RETRIES || !shouldRetryCodeAssistStatus(err.status)) {
|
|
892
|
-
throw err;
|
|
893
|
-
}
|
|
894
|
-
lastError = err;
|
|
895
|
-
}
|
|
896
|
-
await new Promise((resolve) => setTimeout(resolve, CODE_ASSIST_POST_RETRY_DELAY_MS));
|
|
897
|
-
}
|
|
898
|
-
throw lastError ?? new Error(`Gemini Code Assist ${method} failed.`);
|
|
899
|
-
}
|
|
900
|
-
async function codeAssistGet(accessToken, operationName) {
|
|
901
|
-
return codeAssistRequest(getCodeAssistOperationUrl(operationName), accessToken, "operation", {
|
|
902
|
-
method: "GET"
|
|
903
|
-
});
|
|
904
|
-
}
|
|
905
|
-
async function codeAssistRequest(url, accessToken, label, init) {
|
|
906
|
-
const response = await fetch(url, {
|
|
907
|
-
...init,
|
|
908
|
-
headers: codeAssistHeaders(accessToken)
|
|
909
|
-
});
|
|
910
|
-
if (!response.ok) {
|
|
911
|
-
const text = await response.text();
|
|
912
|
-
throw new CodeAssistHttpError(label, response.status, text);
|
|
913
|
-
}
|
|
914
|
-
return await response.json();
|
|
915
|
-
}
|
|
916
|
-
function getCodeAssistBaseUrl() {
|
|
917
|
-
const endpoint = process.env.CODE_ASSIST_ENDPOINT ?? CODE_ASSIST_BASE_URL;
|
|
918
|
-
const version = process.env.CODE_ASSIST_API_VERSION || CODE_ASSIST_API_VERSION;
|
|
919
|
-
return `${endpoint}/${version}`;
|
|
920
|
-
}
|
|
921
|
-
function getCodeAssistMethodUrl(method) {
|
|
922
|
-
return `${getCodeAssistBaseUrl()}:${method}`;
|
|
923
|
-
}
|
|
924
|
-
function getCodeAssistOperationUrl(operationName) {
|
|
925
|
-
return `${getCodeAssistBaseUrl()}/${operationName}`;
|
|
926
|
-
}
|
|
927
|
-
function shouldRetryCodeAssistStatus(status) {
|
|
928
|
-
return status === 429 || status === 499 || status >= 500 && status <= 599;
|
|
929
|
-
}
|
|
930
|
-
function isVpcScAffectedError(error) {
|
|
931
|
-
try {
|
|
932
|
-
const parsed = JSON.parse(error.body);
|
|
933
|
-
if (!parsed || typeof parsed !== "object" || !("error" in parsed)) return false;
|
|
934
|
-
const details = parsed.error?.details;
|
|
935
|
-
return Array.isArray(details) ? details.some(
|
|
936
|
-
(detail) => detail != null && typeof detail === "object" && "reason" in detail && detail.reason === VPC_SC_REASON
|
|
937
|
-
) : false;
|
|
938
|
-
} catch {
|
|
939
|
-
return false;
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
function codeAssistHeaders(accessToken) {
|
|
943
|
-
return {
|
|
944
|
-
Authorization: `Bearer ${accessToken}`,
|
|
945
|
-
"Content-Type": "application/json",
|
|
946
|
-
"User-Agent": "google-gemini-cli",
|
|
947
|
-
"X-Goog-Api-Client": "gemini-cli/0.0.0"
|
|
948
|
-
};
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
// src/oauth/kimi.ts
|
|
952
|
-
var import_node_child_process = require("child_process");
|
|
953
|
-
var import_node_crypto5 = require("crypto");
|
|
954
|
-
var import_node_fs2 = require("fs");
|
|
955
|
-
var import_node_os2 = require("os");
|
|
956
|
-
var import_node_path4 = __toESM(require("path"), 1);
|
|
957
|
-
var CLIENT_ID3 = "17e5f671-d194-4dfb-9706-5516cb48c098";
|
|
958
|
-
var DEFAULT_OAUTH_HOST = "https://auth.kimi.com";
|
|
959
|
-
var DEFAULT_CODING_BASE_URL = "https://api.kimi.com/coding/v1";
|
|
960
|
-
var KIMI_PLATFORM = "kimi_code_cli";
|
|
961
|
-
var DEFAULT_KIMI_VERSION = "1.0.11";
|
|
962
|
-
var DEVICE_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
963
|
-
function oauthHost() {
|
|
964
|
-
const host = process.env.KIMI_CODE_OAUTH_HOST ?? process.env.KIMI_OAUTH_HOST ?? DEFAULT_OAUTH_HOST;
|
|
965
|
-
return host.replace(/\/+$/, "");
|
|
966
|
-
}
|
|
967
|
-
function kimiCodeBaseUrl() {
|
|
968
|
-
return (process.env.KIMI_CODE_BASE_URL ?? DEFAULT_CODING_BASE_URL).replace(/\/+$/, "");
|
|
969
|
-
}
|
|
970
|
-
function kimiVersion() {
|
|
971
|
-
const v = process.env.KIMI_CODE_VERSION ?? DEFAULT_KIMI_VERSION;
|
|
972
|
-
return asciiHeader(v, DEFAULT_KIMI_VERSION);
|
|
973
|
-
}
|
|
974
|
-
function asciiHeader(value, fallback = "unknown") {
|
|
975
|
-
const cleaned = value.replace(/[^\u0020-\u007E]/g, "").trim();
|
|
976
|
-
return cleaned.length > 0 ? cleaned : fallback;
|
|
977
|
-
}
|
|
978
|
-
function macOsProductVersion() {
|
|
979
|
-
try {
|
|
980
|
-
const version = (0, import_node_child_process.execFileSync)("/usr/bin/sw_vers", ["-productVersion"], {
|
|
981
|
-
encoding: "utf-8",
|
|
982
|
-
timeout: 1e3
|
|
983
|
-
}).trim();
|
|
984
|
-
return version.length > 0 ? version : void 0;
|
|
985
|
-
} catch {
|
|
986
|
-
return void 0;
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
function deviceModel() {
|
|
990
|
-
const os2 = (0, import_node_os2.type)();
|
|
991
|
-
const version = (0, import_node_os2.release)();
|
|
992
|
-
const osArch = (0, import_node_os2.arch)();
|
|
993
|
-
if (os2 === "Darwin") return `macOS ${macOsProductVersion() ?? version} ${osArch}`;
|
|
994
|
-
if (os2 === "Windows_NT") return `Windows ${version} ${osArch}`;
|
|
995
|
-
return `${os2} ${version} ${osArch}`.trim();
|
|
996
|
-
}
|
|
997
|
-
function deviceId() {
|
|
998
|
-
const idPath = import_node_path4.default.join(getAppPaths().agentDir, "kimi_device_id");
|
|
999
|
-
if ((0, import_node_fs2.existsSync)(idPath)) {
|
|
1000
|
-
try {
|
|
1001
|
-
const text = (0, import_node_fs2.readFileSync)(idPath, "utf-8").trim();
|
|
1002
|
-
if (text.length > 0) return text;
|
|
1003
|
-
} catch {
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
const id = (0, import_node_crypto5.randomUUID)();
|
|
1007
|
-
try {
|
|
1008
|
-
(0, import_node_fs2.mkdirSync)(getAppPaths().agentDir, { recursive: true, mode: 448 });
|
|
1009
|
-
(0, import_node_fs2.writeFileSync)(idPath, id, { encoding: "utf-8", mode: 384 });
|
|
1010
|
-
} catch {
|
|
1011
|
-
}
|
|
1012
|
-
return id;
|
|
1013
|
-
}
|
|
1014
|
-
function deviceHeaders() {
|
|
1015
|
-
return {
|
|
1016
|
-
"X-Msh-Platform": KIMI_PLATFORM,
|
|
1017
|
-
"X-Msh-Version": kimiVersion(),
|
|
1018
|
-
"X-Msh-Device-Name": asciiHeader((0, import_node_os2.hostname)()),
|
|
1019
|
-
"X-Msh-Device-Model": asciiHeader(deviceModel()),
|
|
1020
|
-
"X-Msh-Os-Version": asciiHeader((0, import_node_os2.release)()),
|
|
1021
|
-
"X-Msh-Device-Id": deviceId()
|
|
1022
|
-
};
|
|
1023
|
-
}
|
|
1024
|
-
function kimiCodingHeaders() {
|
|
1025
|
-
return {
|
|
1026
|
-
"User-Agent": `kimi-code-cli/${kimiVersion()}`,
|
|
1027
|
-
...deviceHeaders()
|
|
1028
|
-
};
|
|
1029
|
-
}
|
|
1030
|
-
function isKimiCodingEndpoint(baseUrl) {
|
|
1031
|
-
if (typeof baseUrl !== "string" || baseUrl.length === 0) return false;
|
|
1032
|
-
const normalized = baseUrl.replace(/\/+$/, "");
|
|
1033
|
-
return normalized === kimiCodeBaseUrl() || /(^|\.)kimi\.com/i.test(normalized);
|
|
1034
|
-
}
|
|
1035
|
-
async function postForm(endpoint, params) {
|
|
1036
|
-
const response = await fetch(`${oauthHost()}${endpoint}`, {
|
|
1037
|
-
method: "POST",
|
|
1038
|
-
headers: {
|
|
1039
|
-
...deviceHeaders(),
|
|
1040
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
1041
|
-
Accept: "application/json"
|
|
1042
|
-
},
|
|
1043
|
-
body: new URLSearchParams(params).toString()
|
|
1044
|
-
});
|
|
1045
|
-
let data = {};
|
|
1046
|
-
try {
|
|
1047
|
-
const parsed = await response.json();
|
|
1048
|
-
if (parsed && typeof parsed === "object") data = parsed;
|
|
1049
|
-
} catch {
|
|
1050
|
-
}
|
|
1051
|
-
return { status: response.status, data };
|
|
1052
|
-
}
|
|
1053
|
-
function errorDetail(data) {
|
|
1054
|
-
const desc = data.error_description ?? data.message ?? data.error;
|
|
1055
|
-
return typeof desc === "string" && desc.length > 0 ? desc : "unknown error";
|
|
1056
|
-
}
|
|
1057
|
-
function credsFromTokenResponse(data, opts) {
|
|
1058
|
-
const accessToken = data.access_token;
|
|
1059
|
-
const responseRefreshToken = data.refresh_token;
|
|
1060
|
-
const expiresIn = Number(data.expires_in);
|
|
1061
|
-
if (typeof accessToken !== "string" || accessToken.length === 0) {
|
|
1062
|
-
throw new Error("Kimi OAuth response missing access_token.");
|
|
1063
|
-
}
|
|
1064
|
-
const refreshToken = typeof responseRefreshToken === "string" && responseRefreshToken.length > 0 ? responseRefreshToken : opts?.fallbackRefreshToken ?? "";
|
|
1065
|
-
if (refreshToken.length === 0) {
|
|
1066
|
-
throw new Error("Kimi OAuth response missing refresh_token.");
|
|
1067
|
-
}
|
|
1068
|
-
if (!Number.isFinite(expiresIn) || expiresIn <= 0) {
|
|
1069
|
-
throw new Error("Kimi OAuth response missing or invalid expires_in.");
|
|
1141
|
+
let lastError;
|
|
1142
|
+
for (let attempt = 0; attempt <= CODE_ASSIST_POST_RETRIES; attempt++) {
|
|
1143
|
+
try {
|
|
1144
|
+
return await codeAssistRequest(getCodeAssistMethodUrl(method), accessToken, method, {
|
|
1145
|
+
method: "POST",
|
|
1146
|
+
body: JSON.stringify(body)
|
|
1147
|
+
});
|
|
1148
|
+
} catch (err) {
|
|
1149
|
+
if (!(err instanceof CodeAssistHttpError) || attempt === CODE_ASSIST_POST_RETRIES || !shouldRetryCodeAssistStatus(err.status)) {
|
|
1150
|
+
throw err;
|
|
1151
|
+
}
|
|
1152
|
+
lastError = err;
|
|
1153
|
+
}
|
|
1154
|
+
await new Promise((resolve) => setTimeout(resolve, CODE_ASSIST_POST_RETRY_DELAY_MS));
|
|
1070
1155
|
}
|
|
1071
|
-
|
|
1072
|
-
accessToken,
|
|
1073
|
-
refreshToken,
|
|
1074
|
-
expiresAt: Date.now() + expiresIn * 1e3,
|
|
1075
|
-
baseUrl: kimiCodeBaseUrl()
|
|
1076
|
-
};
|
|
1156
|
+
throw lastError ?? new Error(`Gemini Code Assist ${method} failed.`);
|
|
1077
1157
|
}
|
|
1078
|
-
async function
|
|
1079
|
-
|
|
1080
|
-
|
|
1158
|
+
async function codeAssistGet(accessToken, operationName) {
|
|
1159
|
+
return codeAssistRequest(getCodeAssistOperationUrl(operationName), accessToken, "operation", {
|
|
1160
|
+
method: "GET"
|
|
1081
1161
|
});
|
|
1082
|
-
if (status !== 200) {
|
|
1083
|
-
throw new Error(`Kimi device authorization failed (${status}): ${errorDetail(data)}`);
|
|
1084
|
-
}
|
|
1085
|
-
const userCode = data.user_code;
|
|
1086
|
-
const deviceCode = data.device_code;
|
|
1087
|
-
const verificationUriComplete = data.verification_uri_complete;
|
|
1088
|
-
if (typeof userCode !== "string" || typeof deviceCode !== "string") {
|
|
1089
|
-
throw new Error("Kimi device authorization response missing user_code/device_code.");
|
|
1090
|
-
}
|
|
1091
|
-
return {
|
|
1092
|
-
userCode,
|
|
1093
|
-
deviceCode,
|
|
1094
|
-
verificationUri: typeof data.verification_uri === "string" ? data.verification_uri : "",
|
|
1095
|
-
verificationUriComplete: typeof verificationUriComplete === "string" ? verificationUriComplete : "",
|
|
1096
|
-
interval: Number(data.interval ?? 5) || 5
|
|
1097
|
-
};
|
|
1098
1162
|
}
|
|
1099
|
-
async function
|
|
1100
|
-
const
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
grant_type: "urn:ietf:params:oauth:grant-type:device_code"
|
|
1163
|
+
async function codeAssistRequest(url, accessToken, label, init) {
|
|
1164
|
+
const response = await fetch(url, {
|
|
1165
|
+
...init,
|
|
1166
|
+
headers: codeAssistHeaders(accessToken)
|
|
1104
1167
|
});
|
|
1105
|
-
if (
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
if (status >= 500) {
|
|
1109
|
-
throw new Error(`Kimi token polling server error (${status}): ${errorDetail(data)}`);
|
|
1110
|
-
}
|
|
1111
|
-
const errorCode = typeof data.error === "string" ? data.error : "unknown_error";
|
|
1112
|
-
switch (errorCode) {
|
|
1113
|
-
case "authorization_pending":
|
|
1114
|
-
return { kind: "pending" };
|
|
1115
|
-
case "slow_down":
|
|
1116
|
-
return { kind: "slow_down" };
|
|
1117
|
-
case "expired_token":
|
|
1118
|
-
return { kind: "expired" };
|
|
1119
|
-
case "access_denied":
|
|
1120
|
-
return { kind: "denied" };
|
|
1121
|
-
default:
|
|
1122
|
-
throw new Error(`Kimi token polling failed (${status}): ${errorDetail(data)}`);
|
|
1168
|
+
if (!response.ok) {
|
|
1169
|
+
const text = await response.text();
|
|
1170
|
+
throw new CodeAssistHttpError(label, response.status, text);
|
|
1123
1171
|
}
|
|
1172
|
+
return await response.json();
|
|
1124
1173
|
}
|
|
1125
|
-
function
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
}
|
|
1174
|
+
function getCodeAssistBaseUrl() {
|
|
1175
|
+
const endpoint = process.env.CODE_ASSIST_ENDPOINT ?? CODE_ASSIST_BASE_URL;
|
|
1176
|
+
const version = process.env.CODE_ASSIST_API_VERSION || CODE_ASSIST_API_VERSION;
|
|
1177
|
+
return `${endpoint}/${version}`;
|
|
1129
1178
|
}
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
callbacks.onStatus(
|
|
1133
|
-
`Visit ${auth.verificationUri || auth.verificationUriComplete} and enter code: ${auth.userCode}`
|
|
1134
|
-
);
|
|
1135
|
-
callbacks.onOpenUrl(auth.verificationUriComplete || auth.verificationUri);
|
|
1136
|
-
callbacks.onStatus("Waiting for you to authorize in the browser...");
|
|
1137
|
-
const deadline = Date.now() + DEVICE_TIMEOUT_MS;
|
|
1138
|
-
let interval = Math.max(auth.interval, 1);
|
|
1139
|
-
while (Date.now() < deadline) {
|
|
1140
|
-
await sleep(interval * 1e3);
|
|
1141
|
-
const result = await pollDeviceToken(auth.deviceCode);
|
|
1142
|
-
if (result.kind === "success") return result.creds;
|
|
1143
|
-
if (result.kind === "denied") {
|
|
1144
|
-
throw new Error("Kimi authorization was denied.");
|
|
1145
|
-
}
|
|
1146
|
-
if (result.kind === "expired") {
|
|
1147
|
-
throw new Error("Kimi device code expired. Please run login again.");
|
|
1148
|
-
}
|
|
1149
|
-
if (result.kind === "slow_down") {
|
|
1150
|
-
interval += 5;
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
throw new Error("Kimi login timed out. Please run login again.");
|
|
1179
|
+
function getCodeAssistMethodUrl(method) {
|
|
1180
|
+
return `${getCodeAssistBaseUrl()}:${method}`;
|
|
1154
1181
|
}
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1182
|
+
function getCodeAssistOperationUrl(operationName) {
|
|
1183
|
+
return `${getCodeAssistBaseUrl()}/${operationName}`;
|
|
1184
|
+
}
|
|
1185
|
+
function shouldRetryCodeAssistStatus(status) {
|
|
1186
|
+
return status === 429 || status === 499 || status >= 500 && status <= 599;
|
|
1187
|
+
}
|
|
1188
|
+
function isVpcScAffectedError(error) {
|
|
1189
|
+
try {
|
|
1190
|
+
const parsed = JSON.parse(error.body);
|
|
1191
|
+
if (!parsed || typeof parsed !== "object" || !("error" in parsed)) return false;
|
|
1192
|
+
const details = parsed.error?.details;
|
|
1193
|
+
return Array.isArray(details) ? details.some(
|
|
1194
|
+
(detail) => detail != null && typeof detail === "object" && "reason" in detail && detail.reason === VPC_SC_REASON
|
|
1195
|
+
) : false;
|
|
1196
|
+
} catch {
|
|
1197
|
+
return false;
|
|
1163
1198
|
}
|
|
1164
|
-
|
|
1165
|
-
|
|
1199
|
+
}
|
|
1200
|
+
function codeAssistHeaders(accessToken) {
|
|
1201
|
+
return {
|
|
1202
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1203
|
+
"Content-Type": "application/json",
|
|
1204
|
+
"User-Agent": "google-gemini-cli",
|
|
1205
|
+
"X-Goog-Api-Client": "gemini-cli/0.0.0"
|
|
1206
|
+
};
|
|
1166
1207
|
}
|
|
1167
1208
|
|
|
1168
1209
|
// src/file-lock.ts
|
|
@@ -1230,7 +1271,28 @@ function isAlive(pid) {
|
|
|
1230
1271
|
// src/auth-storage.ts
|
|
1231
1272
|
var MOONSHOT_OAUTH_KEY = "moonshot-oauth";
|
|
1232
1273
|
var XIAOMI_CREDITS_KEY = "xiaomi-credits";
|
|
1274
|
+
function activeBaseUrlEntry(data, provider) {
|
|
1275
|
+
if (provider === "moonshot") {
|
|
1276
|
+
const oauth = data[MOONSHOT_OAUTH_KEY];
|
|
1277
|
+
if (oauth) {
|
|
1278
|
+
const exhaustedUntil = oauth.usageExhaustedUntil ?? 0;
|
|
1279
|
+
if (Date.now() < exhaustedUntil && data["moonshot"]) return data["moonshot"];
|
|
1280
|
+
return oauth;
|
|
1281
|
+
}
|
|
1282
|
+
return data["moonshot"];
|
|
1283
|
+
}
|
|
1284
|
+
return data[provider];
|
|
1285
|
+
}
|
|
1286
|
+
function readStoredBaseUrlSync(authFile, provider) {
|
|
1287
|
+
try {
|
|
1288
|
+
const data = JSON.parse((0, import_node_fs3.readFileSync)(authFile, "utf-8"));
|
|
1289
|
+
return activeBaseUrlEntry(data, provider)?.baseUrl;
|
|
1290
|
+
} catch {
|
|
1291
|
+
return void 0;
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1233
1294
|
var REFRESH_SKEW_MS = 6e4;
|
|
1295
|
+
var USAGE_EXHAUSTED_DEFAULT_MS = 15 * 60 * 1e3;
|
|
1234
1296
|
var STATIC_API_KEY_PROVIDERS = /* @__PURE__ */ new Set([
|
|
1235
1297
|
"glm",
|
|
1236
1298
|
"moonshot",
|
|
@@ -1238,7 +1300,8 @@ var STATIC_API_KEY_PROVIDERS = /* @__PURE__ */ new Set([
|
|
|
1238
1300
|
"minimax",
|
|
1239
1301
|
"deepseek",
|
|
1240
1302
|
"openrouter",
|
|
1241
|
-
"sakana"
|
|
1303
|
+
"sakana",
|
|
1304
|
+
"xai"
|
|
1242
1305
|
]);
|
|
1243
1306
|
var AuthStorage = class {
|
|
1244
1307
|
data = {};
|
|
@@ -1297,10 +1360,22 @@ var AuthStorage = class {
|
|
|
1297
1360
|
async isStaticApiKey(provider) {
|
|
1298
1361
|
await this.ensureLoaded();
|
|
1299
1362
|
if (provider === "moonshot" && this.data[MOONSHOT_OAUTH_KEY]) {
|
|
1300
|
-
|
|
1363
|
+
const exhaustedUntil = this.data[MOONSHOT_OAUTH_KEY].usageExhaustedUntil ?? 0;
|
|
1364
|
+
const apiKeyActive = Date.now() < exhaustedUntil && Boolean(this.data["moonshot"]);
|
|
1365
|
+
if (!apiKeyActive) return false;
|
|
1301
1366
|
}
|
|
1302
1367
|
return STATIC_API_KEY_PROVIDERS.has(provider);
|
|
1303
1368
|
}
|
|
1369
|
+
/**
|
|
1370
|
+
* The base URL on the credential that is active right now, if any.
|
|
1371
|
+
* Synchronous — call only after load()/resolveCredentials() populated the
|
|
1372
|
+
* snapshot. For `moonshot` this is the Kimi For Coding URL whenever the
|
|
1373
|
+
* OAuth entry is the one resolveCredentials would serve (i.e. not currently
|
|
1374
|
+
* usage-exhausted with an API key configured).
|
|
1375
|
+
*/
|
|
1376
|
+
getStoredBaseUrl(provider) {
|
|
1377
|
+
return activeBaseUrlEntry(this.data, provider)?.baseUrl;
|
|
1378
|
+
}
|
|
1304
1379
|
async load() {
|
|
1305
1380
|
await withFileLock(this.filePath, async () => {
|
|
1306
1381
|
try {
|
|
@@ -1332,31 +1407,80 @@ var AuthStorage = class {
|
|
|
1332
1407
|
/**
|
|
1333
1408
|
* Force a re-read from disk, discarding the in-memory cache. Needed when
|
|
1334
1409
|
* another process mutates the auth file out-of-band — e.g. the desktop app
|
|
1335
|
-
* writes API keys natively
|
|
1336
|
-
* this instance, so a long-lived daemon's cache would otherwise stay stale and
|
|
1337
|
-
* never see a newly added provider key.
|
|
1410
|
+
* writes API keys natively without going through this instance.
|
|
1338
1411
|
*/
|
|
1339
1412
|
async reload() {
|
|
1340
1413
|
this.loaded = false;
|
|
1341
1414
|
await this.load();
|
|
1342
1415
|
}
|
|
1416
|
+
/**
|
|
1417
|
+
* Apply one provider-scoped mutation to the latest on-disk snapshot.
|
|
1418
|
+
* AuthStorage instances live in every app session/process, so writing this
|
|
1419
|
+
* instance's cached snapshot can erase credentials another instance just
|
|
1420
|
+
* added. The file lock only serializes writers; the re-read prevents stale
|
|
1421
|
+
* full-file overwrites.
|
|
1422
|
+
*/
|
|
1423
|
+
async mutateLatest(mutator) {
|
|
1424
|
+
await this.ensureLoaded();
|
|
1425
|
+
await withFileLock(this.filePath, async () => {
|
|
1426
|
+
const latest = await readAuthData(this.filePath);
|
|
1427
|
+
mutator(latest);
|
|
1428
|
+
await atomicWriteFile(this.filePath, JSON.stringify(latest, null, 2));
|
|
1429
|
+
this.data = latest;
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
async reloadLatest() {
|
|
1433
|
+
await withFileLock(this.filePath, async () => {
|
|
1434
|
+
this.data = await readAuthData(this.filePath);
|
|
1435
|
+
});
|
|
1436
|
+
}
|
|
1343
1437
|
async getCredentials(provider) {
|
|
1344
1438
|
await this.ensureLoaded();
|
|
1345
1439
|
return this.data[provider];
|
|
1346
1440
|
}
|
|
1347
1441
|
async setCredentials(provider, creds) {
|
|
1348
|
-
await this.
|
|
1349
|
-
|
|
1350
|
-
|
|
1442
|
+
await this.mutateLatest((latest) => {
|
|
1443
|
+
latest[provider] = creds;
|
|
1444
|
+
});
|
|
1351
1445
|
}
|
|
1352
1446
|
async clearCredentials(provider) {
|
|
1353
|
-
await this.
|
|
1354
|
-
|
|
1355
|
-
|
|
1447
|
+
await this.mutateLatest((latest) => {
|
|
1448
|
+
delete latest[provider];
|
|
1449
|
+
});
|
|
1450
|
+
}
|
|
1451
|
+
/**
|
|
1452
|
+
* Mark the credential stored under `storageKey` as usage-exhausted until
|
|
1453
|
+
* `resetsAt` (unix SECONDS, from the provider's rate-limit response) or a
|
|
1454
|
+
* 15-minute default when no reset time is known. While the mark is in the
|
|
1455
|
+
* future, `resolveCredentials("moonshot")` serves the Moonshot API key
|
|
1456
|
+
* instead of the Kimi OAuth credential (when both are configured) — OAuth
|
|
1457
|
+
* stays the preferred credential and is retried automatically once the mark
|
|
1458
|
+
* lapses. Persisted to auth.json so a restart (or another ezcoder-app window)
|
|
1459
|
+
* doesn't burn a request rediscovering the same exhausted window. No-op if
|
|
1460
|
+
* nothing is stored under `storageKey`.
|
|
1461
|
+
*/
|
|
1462
|
+
async markUsageExhausted(storageKey, resetsAt) {
|
|
1463
|
+
const until = resetsAt !== void 0 && resetsAt * 1e3 > Date.now() ? resetsAt * 1e3 : Date.now() + USAGE_EXHAUSTED_DEFAULT_MS;
|
|
1464
|
+
let marked = false;
|
|
1465
|
+
await this.mutateLatest((latest) => {
|
|
1466
|
+
const creds = latest[storageKey];
|
|
1467
|
+
if (!creds) return;
|
|
1468
|
+
creds.usageExhaustedUntil = until;
|
|
1469
|
+
marked = true;
|
|
1470
|
+
});
|
|
1471
|
+
if (!marked) return;
|
|
1472
|
+
log(
|
|
1473
|
+
"WARN",
|
|
1474
|
+
"auth",
|
|
1475
|
+
`Marked ${storageKey} usage-exhausted until ${new Date(until).toISOString()}`
|
|
1476
|
+
);
|
|
1356
1477
|
}
|
|
1357
1478
|
async clearAll() {
|
|
1358
|
-
this.
|
|
1359
|
-
await this.
|
|
1479
|
+
await this.ensureLoaded();
|
|
1480
|
+
await withFileLock(this.filePath, async () => {
|
|
1481
|
+
this.data = {};
|
|
1482
|
+
await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));
|
|
1483
|
+
});
|
|
1360
1484
|
}
|
|
1361
1485
|
/**
|
|
1362
1486
|
* Returns valid credentials, auto-refreshing if expired.
|
|
@@ -1366,6 +1490,10 @@ var AuthStorage = class {
|
|
|
1366
1490
|
*/
|
|
1367
1491
|
async resolveCredentials(provider, opts) {
|
|
1368
1492
|
await this.ensureLoaded();
|
|
1493
|
+
const directStorageKeys = opts?.storageKeys && !(opts.storageKeys.length === 1 && opts.storageKeys[0] === provider) ? opts.storageKeys : provider === "moonshot" ? [MOONSHOT_OAUTH_KEY, "moonshot"] : [provider];
|
|
1494
|
+
if (!directStorageKeys.some((key) => Boolean(this.data[key]))) {
|
|
1495
|
+
await this.reloadLatest();
|
|
1496
|
+
}
|
|
1369
1497
|
if (opts?.storageKeys && !(opts.storageKeys.length === 1 && opts.storageKeys[0] === provider)) {
|
|
1370
1498
|
for (const key of opts.storageKeys) {
|
|
1371
1499
|
const creds2 = this.data[key];
|
|
@@ -1374,8 +1502,19 @@ var AuthStorage = class {
|
|
|
1374
1502
|
throw new NotLoggedInError(provider);
|
|
1375
1503
|
}
|
|
1376
1504
|
if (provider === "moonshot" && this.data[MOONSHOT_OAUTH_KEY]) {
|
|
1505
|
+
const exhaustedUntil = this.data[MOONSHOT_OAUTH_KEY].usageExhaustedUntil ?? 0;
|
|
1506
|
+
if (Date.now() < exhaustedUntil && this.data["moonshot"]) {
|
|
1507
|
+
log(
|
|
1508
|
+
"WARN",
|
|
1509
|
+
"auth",
|
|
1510
|
+
`Kimi OAuth usage window is exhausted \u2014 using the Moonshot API key until ${new Date(exhaustedUntil).toISOString()} (OAuth resumes automatically).`
|
|
1511
|
+
);
|
|
1512
|
+
return this.data["moonshot"];
|
|
1513
|
+
}
|
|
1377
1514
|
try {
|
|
1378
|
-
return await this.resolveCredentials(MOONSHOT_OAUTH_KEY,
|
|
1515
|
+
return await this.resolveCredentials(MOONSHOT_OAUTH_KEY, {
|
|
1516
|
+
...opts?.forceRefresh ? { forceRefresh: true } : {}
|
|
1517
|
+
});
|
|
1379
1518
|
} catch (err) {
|
|
1380
1519
|
if (err instanceof NotLoggedInError && this.data["moonshot"]) {
|
|
1381
1520
|
log(
|
|
@@ -1401,41 +1540,44 @@ var AuthStorage = class {
|
|
|
1401
1540
|
const existing = this.refreshLocks.get(provider);
|
|
1402
1541
|
if (existing) return existing;
|
|
1403
1542
|
const refreshPromise = withFileLock(this.filePath, async () => {
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1543
|
+
const latest = await readAuthData(this.filePath);
|
|
1544
|
+
const latestCreds = latest[provider];
|
|
1545
|
+
if (!latestCreds) {
|
|
1546
|
+
this.data = latest;
|
|
1547
|
+
throw new NotLoggedInError(provider);
|
|
1548
|
+
}
|
|
1549
|
+
const credentialWasReplaced = latestCreds.accessToken !== creds.accessToken || latestCreds.refreshToken !== creds.refreshToken || latestCreds.expiresAt !== creds.expiresAt;
|
|
1550
|
+
if (credentialWasReplaced || !opts?.forceRefresh && Date.now() < latestCreds.expiresAt - REFRESH_SKEW_MS) {
|
|
1551
|
+
this.data = latest;
|
|
1552
|
+
return latestCreds;
|
|
1413
1553
|
}
|
|
1414
1554
|
const refreshFn = provider === "anthropic" ? refreshAnthropicToken : provider === "gemini" ? refreshGeminiToken : provider === MOONSHOT_OAUTH_KEY ? refreshKimiToken : refreshOpenAIToken;
|
|
1415
1555
|
let refreshed;
|
|
1416
1556
|
try {
|
|
1417
|
-
refreshed = await refreshFn(
|
|
1557
|
+
refreshed = await refreshFn(latestCreds.refreshToken);
|
|
1418
1558
|
} catch (err) {
|
|
1419
1559
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1420
1560
|
const isAuthFailure = /\((401|400)\)/.test(msg) || /invalid_grant|invalid_token|invalid.*refresh/i.test(msg) || /unauthorized/i.test(msg);
|
|
1421
1561
|
if (isAuthFailure) {
|
|
1422
|
-
delete
|
|
1423
|
-
|
|
1562
|
+
delete latest[provider];
|
|
1563
|
+
this.data = latest;
|
|
1564
|
+
await atomicWriteFile(this.filePath, JSON.stringify(latest, null, 2));
|
|
1424
1565
|
throw new NotLoggedInError(provider);
|
|
1425
1566
|
}
|
|
1426
1567
|
throw err;
|
|
1427
1568
|
}
|
|
1428
|
-
if (!refreshed.accountId &&
|
|
1429
|
-
refreshed.accountId =
|
|
1569
|
+
if (!refreshed.accountId && latestCreds.accountId) {
|
|
1570
|
+
refreshed.accountId = latestCreds.accountId;
|
|
1430
1571
|
}
|
|
1431
|
-
if (!refreshed.projectId &&
|
|
1432
|
-
refreshed.projectId =
|
|
1572
|
+
if (!refreshed.projectId && latestCreds.projectId) {
|
|
1573
|
+
refreshed.projectId = latestCreds.projectId;
|
|
1433
1574
|
}
|
|
1434
|
-
if (!refreshed.baseUrl &&
|
|
1435
|
-
refreshed.baseUrl =
|
|
1575
|
+
if (!refreshed.baseUrl && latestCreds.baseUrl) {
|
|
1576
|
+
refreshed.baseUrl = latestCreds.baseUrl;
|
|
1436
1577
|
}
|
|
1437
|
-
|
|
1438
|
-
|
|
1578
|
+
latest[provider] = refreshed;
|
|
1579
|
+
this.data = latest;
|
|
1580
|
+
await atomicWriteFile(this.filePath, JSON.stringify(latest, null, 2));
|
|
1439
1581
|
return refreshed;
|
|
1440
1582
|
});
|
|
1441
1583
|
this.refreshLocks.set(provider, refreshPromise);
|
|
@@ -1453,12 +1595,16 @@ var AuthStorage = class {
|
|
|
1453
1595
|
const creds = await this.resolveCredentials(provider);
|
|
1454
1596
|
return creds.accessToken;
|
|
1455
1597
|
}
|
|
1456
|
-
async save() {
|
|
1457
|
-
await withFileLock(this.filePath, async () => {
|
|
1458
|
-
await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));
|
|
1459
|
-
});
|
|
1460
|
-
}
|
|
1461
1598
|
};
|
|
1599
|
+
async function readAuthData(filePath) {
|
|
1600
|
+
try {
|
|
1601
|
+
const content = await import_promises4.default.readFile(filePath, "utf-8");
|
|
1602
|
+
return JSON.parse(content);
|
|
1603
|
+
} catch (error) {
|
|
1604
|
+
if (error.code === "ENOENT") return {};
|
|
1605
|
+
throw error;
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1462
1608
|
async function atomicWriteFile(filePath, content) {
|
|
1463
1609
|
const tmpPath = `${filePath}.${process.pid}.${Date.now()}.${import_node_crypto6.default.randomUUID().slice(0, 8)}.tmp`;
|
|
1464
1610
|
try {
|
|
@@ -1551,7 +1697,8 @@ var MODELS = [
|
|
|
1551
1697
|
// ── OpenAI (Codex) ─────────────────────────────────────
|
|
1552
1698
|
// GPT-5.6 family — three agentic coding tiers launched July 2026. The public
|
|
1553
1699
|
// Responses API advertises a 1.05M context window; OpenAI's Codex product
|
|
1554
|
-
// catalog advertises
|
|
1700
|
+
// catalog advertises 272K on the ChatGPT OAuth route (corrected from the
|
|
1701
|
+
// initially advertised 372K — openai/codex PR #33972, Jul 18 2026 hotfix). All three take
|
|
1555
1702
|
// text+image input, freeform apply_patch, text+image web search, and parallel
|
|
1556
1703
|
// tool calls.
|
|
1557
1704
|
{
|
|
@@ -1563,7 +1710,7 @@ var MODELS = [
|
|
|
1563
1710
|
name: "GPT-5.6 Sol",
|
|
1564
1711
|
provider: "openai",
|
|
1565
1712
|
contextWindow: 105e4,
|
|
1566
|
-
codexContextWindow:
|
|
1713
|
+
codexContextWindow: 272e3,
|
|
1567
1714
|
maxOutputTokens: 128e3,
|
|
1568
1715
|
supportsThinking: true,
|
|
1569
1716
|
supportsImages: true,
|
|
@@ -1578,7 +1725,7 @@ var MODELS = [
|
|
|
1578
1725
|
name: "GPT-5.6 Terra",
|
|
1579
1726
|
provider: "openai",
|
|
1580
1727
|
contextWindow: 105e4,
|
|
1581
|
-
codexContextWindow:
|
|
1728
|
+
codexContextWindow: 272e3,
|
|
1582
1729
|
maxOutputTokens: 128e3,
|
|
1583
1730
|
supportsThinking: true,
|
|
1584
1731
|
supportsImages: true,
|
|
@@ -1593,7 +1740,7 @@ var MODELS = [
|
|
|
1593
1740
|
name: "GPT-5.6 Luna",
|
|
1594
1741
|
provider: "openai",
|
|
1595
1742
|
contextWindow: 105e4,
|
|
1596
|
-
codexContextWindow:
|
|
1743
|
+
codexContextWindow: 272e3,
|
|
1597
1744
|
maxOutputTokens: 128e3,
|
|
1598
1745
|
supportsThinking: true,
|
|
1599
1746
|
supportsImages: true,
|
|
@@ -1644,6 +1791,26 @@ var MODELS = [
|
|
|
1644
1791
|
costTier: "high",
|
|
1645
1792
|
maxThinkingLevel: "xhigh"
|
|
1646
1793
|
},
|
|
1794
|
+
// ── xAI (Grok) ─────────────────────────────────────────
|
|
1795
|
+
// Grok 4.5 (released 2026-07-08) is xAI's flagship for coding, agentic
|
|
1796
|
+
// tasks, and knowledge work — 500K context, text+image input, configurable
|
|
1797
|
+
// `reasoning_effort` (low/medium/high, server default high; reasoning can't
|
|
1798
|
+
// be fully disabled). Served over the OpenAI-compatible API at
|
|
1799
|
+
// https://api.x.ai/v1 (API key from console.x.ai). xAI hasn't published an
|
|
1800
|
+
// official max-output cap for 4.5; 131K matches the Grok Responses ceiling
|
|
1801
|
+
// third-party integrations use.
|
|
1802
|
+
{
|
|
1803
|
+
id: "grok-4.5",
|
|
1804
|
+
name: "Grok 4.5",
|
|
1805
|
+
provider: "xai",
|
|
1806
|
+
contextWindow: 5e5,
|
|
1807
|
+
maxOutputTokens: 131072,
|
|
1808
|
+
supportsThinking: true,
|
|
1809
|
+
supportsImages: true,
|
|
1810
|
+
supportsVideo: false,
|
|
1811
|
+
costTier: "medium",
|
|
1812
|
+
maxThinkingLevel: "high"
|
|
1813
|
+
},
|
|
1647
1814
|
// ── Gemini ─────────────────────────────────────────────
|
|
1648
1815
|
{
|
|
1649
1816
|
id: "gemini-3.1-flash-lite",
|
|
@@ -1691,9 +1858,29 @@ var MODELS = [
|
|
|
1691
1858
|
maxThinkingLevel: "high"
|
|
1692
1859
|
},
|
|
1693
1860
|
// ── Moonshot (Kimi) ────────────────────────────────────
|
|
1861
|
+
// K3 is Kimi's 2.8T-parameter flagship for long-horizon coding, knowledge
|
|
1862
|
+
// work, and deep reasoning. Its effort ladder is server-declared as
|
|
1863
|
+
// low/high/max on both the public API (default max) and the Kimi For Coding
|
|
1864
|
+
// OAuth endpoint (default high); thinking can also be fully disabled.
|
|
1865
|
+
{
|
|
1866
|
+
id: "kimi-k3",
|
|
1867
|
+
name: "Kimi K3",
|
|
1868
|
+
provider: "moonshot",
|
|
1869
|
+
contextWindow: 1048576,
|
|
1870
|
+
// The API can be raised as high as the full context window, but 131K is the
|
|
1871
|
+
// documented default and keeps room for input in AgentSession's fixed cap.
|
|
1872
|
+
maxOutputTokens: 131072,
|
|
1873
|
+
supportsThinking: true,
|
|
1874
|
+
supportsImages: true,
|
|
1875
|
+
supportsVideo: true,
|
|
1876
|
+
maxVideoBytes: 100 * 1024 * 1024,
|
|
1877
|
+
costTier: "high",
|
|
1878
|
+
maxThinkingLevel: "max"
|
|
1879
|
+
},
|
|
1880
|
+
// Retain the cheaper dedicated coding model as an explicit alternative.
|
|
1694
1881
|
{
|
|
1695
1882
|
id: "kimi-k2.7-code",
|
|
1696
|
-
name: "Kimi K2.7",
|
|
1883
|
+
name: "Kimi K2.7 Code",
|
|
1697
1884
|
provider: "moonshot",
|
|
1698
1885
|
contextWindow: 262144,
|
|
1699
1886
|
maxOutputTokens: 262144,
|
|
@@ -1883,16 +2070,20 @@ function getDefaultModel(provider) {
|
|
|
1883
2070
|
if (provider === "openai") return MODELS.find((m) => m.id === "gpt-5.6-sol");
|
|
1884
2071
|
if (provider === "gemini") return MODELS.find((m) => m.id === "gemini-3.1-flash-lite");
|
|
1885
2072
|
if (provider === "glm") return MODELS.find((m) => m.id === "glm-5.2");
|
|
1886
|
-
if (provider === "moonshot") return MODELS.find((m) => m.id === "kimi-
|
|
2073
|
+
if (provider === "moonshot") return MODELS.find((m) => m.id === "kimi-k3");
|
|
1887
2074
|
if (provider === "minimax") return MODELS.find((m) => m.id === "MiniMax-M3");
|
|
1888
2075
|
if (provider === "deepseek") return MODELS.find((m) => m.id === "deepseek-v4-pro");
|
|
1889
2076
|
if (provider === "openrouter") return MODELS.find((m) => m.id === "qwen/qwen3.6-plus");
|
|
1890
2077
|
if (provider === "sakana") return MODELS.find((m) => m.id === "fugu");
|
|
2078
|
+
if (provider === "xai") return MODELS.find((m) => m.id === "grok-4.5");
|
|
1891
2079
|
return MODELS.find((m) => m.id === "claude-sonnet-5");
|
|
1892
2080
|
}
|
|
1893
2081
|
function usesOpenAICodexTransport(options) {
|
|
1894
2082
|
return options?.provider === "openai" && Boolean(options.accountId);
|
|
1895
2083
|
}
|
|
2084
|
+
function getToolResultCharLimit(_modelId, options) {
|
|
2085
|
+
return usesOpenAICodexTransport(options) ? 1e4 * 4 : void 0;
|
|
2086
|
+
}
|
|
1896
2087
|
function getContextWindow(modelId, options) {
|
|
1897
2088
|
const model = getModel(modelId);
|
|
1898
2089
|
if (!model) return 2e5;
|
|
@@ -1904,6 +2095,11 @@ function getContextWindow(modelId, options) {
|
|
|
1904
2095
|
function getMaxThinkingLevel(modelId) {
|
|
1905
2096
|
return getModel(modelId)?.maxThinkingLevel ?? "high";
|
|
1906
2097
|
}
|
|
2098
|
+
function getDefaultThinkingLevel(modelId, options) {
|
|
2099
|
+
const model = getModel(modelId);
|
|
2100
|
+
if (model?.id === "kimi-k3" && isKimiCodingEndpoint(options?.baseUrl)) return "high";
|
|
2101
|
+
return model?.maxThinkingLevel ?? "high";
|
|
2102
|
+
}
|
|
1907
2103
|
function getSummaryModel(provider, currentModelId) {
|
|
1908
2104
|
if (provider === "anthropic") {
|
|
1909
2105
|
return MODELS.find((m) => m.id === "claude-sonnet-5");
|
|
@@ -1930,6 +2126,7 @@ var OPENAI_GPT_56_THINKING_LEVELS = [
|
|
|
1930
2126
|
"ultra"
|
|
1931
2127
|
];
|
|
1932
2128
|
var SAKANA_THINKING_LEVELS = ["high", "xhigh"];
|
|
2129
|
+
var XAI_THINKING_LEVELS = ["low", "medium", "high"];
|
|
1933
2130
|
var ANTHROPIC_OPUS_48_47_THINKING_LEVELS = [
|
|
1934
2131
|
"low",
|
|
1935
2132
|
"medium",
|
|
@@ -1943,12 +2140,19 @@ var ANTHROPIC_ADAPTIVE_THINKING_LEVELS = [
|
|
|
1943
2140
|
"high",
|
|
1944
2141
|
"max"
|
|
1945
2142
|
];
|
|
2143
|
+
var MOONSHOT_K3_THINKING_LEVELS = ["low", "high", "max"];
|
|
1946
2144
|
function isOpenAIGptModel(provider, model) {
|
|
1947
2145
|
return provider === "openai" && model.startsWith("gpt-");
|
|
1948
2146
|
}
|
|
1949
2147
|
function isSakanaModel(provider) {
|
|
1950
2148
|
return provider === "sakana";
|
|
1951
2149
|
}
|
|
2150
|
+
function isXaiModel(provider) {
|
|
2151
|
+
return provider === "xai";
|
|
2152
|
+
}
|
|
2153
|
+
function isMoonshotK3Model(provider, model) {
|
|
2154
|
+
return provider === "moonshot" && model === "kimi-k3";
|
|
2155
|
+
}
|
|
1952
2156
|
function isAnthropicOpus48Or47Model(provider, model) {
|
|
1953
2157
|
return provider === "anthropic" && /opus-4-8|opus-4-7/.test(model);
|
|
1954
2158
|
}
|
|
@@ -1968,6 +2172,12 @@ function getSupportedThinkingLevels(provider, model) {
|
|
|
1968
2172
|
if (maxIndex2 === -1) return SAKANA_THINKING_LEVELS;
|
|
1969
2173
|
return SAKANA_THINKING_LEVELS.slice(0, maxIndex2 + 1);
|
|
1970
2174
|
}
|
|
2175
|
+
if (isXaiModel(provider)) {
|
|
2176
|
+
const maxIndex2 = XAI_THINKING_LEVELS.indexOf(maxLevel);
|
|
2177
|
+
if (maxIndex2 === -1) return XAI_THINKING_LEVELS;
|
|
2178
|
+
return XAI_THINKING_LEVELS.slice(0, maxIndex2 + 1);
|
|
2179
|
+
}
|
|
2180
|
+
if (isMoonshotK3Model(provider, model)) return MOONSHOT_K3_THINKING_LEVELS;
|
|
1971
2181
|
if (!isOpenAIGptModel(provider, model)) return [maxLevel];
|
|
1972
2182
|
const levels = model.startsWith("gpt-5.6-") ? OPENAI_GPT_56_THINKING_LEVELS : OPENAI_GPT_THINKING_LEVELS;
|
|
1973
2183
|
const maxIndex = levels.indexOf(maxLevel);
|
|
@@ -1979,7 +2189,7 @@ function isThinkingLevelSupported(provider, model, level) {
|
|
|
1979
2189
|
}
|
|
1980
2190
|
function getNextThinkingLevel(provider, model, current) {
|
|
1981
2191
|
const supportedLevels = getSupportedThinkingLevels(provider, model);
|
|
1982
|
-
const shouldCycleLevels = isOpenAIGptModel(provider, model) || isAnthropicAdaptiveModel(provider, model) || isSakanaModel(provider);
|
|
2192
|
+
const shouldCycleLevels = isOpenAIGptModel(provider, model) || isAnthropicAdaptiveModel(provider, model) || isSakanaModel(provider) || isXaiModel(provider) || isMoonshotK3Model(provider, model);
|
|
1983
2193
|
if (!shouldCycleLevels) {
|
|
1984
2194
|
return current ? void 0 : supportedLevels[0];
|
|
1985
2195
|
}
|
|
@@ -1991,9 +2201,10 @@ function getNextThinkingLevel(provider, model, current) {
|
|
|
1991
2201
|
|
|
1992
2202
|
// src/provider-usage.ts
|
|
1993
2203
|
var SubscriptionUsageError = class extends Error {
|
|
1994
|
-
constructor(message, status) {
|
|
2204
|
+
constructor(message, status, retryAfterMs2) {
|
|
1995
2205
|
super(message);
|
|
1996
2206
|
this.status = status;
|
|
2207
|
+
this.retryAfterMs = retryAfterMs2;
|
|
1997
2208
|
this.name = "SubscriptionUsageError";
|
|
1998
2209
|
}
|
|
1999
2210
|
};
|
|
@@ -2043,12 +2254,20 @@ function normalizedCodexWindow(window, fallbackKind, now) {
|
|
|
2043
2254
|
resetsAt: codexResetAt(window, now)
|
|
2044
2255
|
};
|
|
2045
2256
|
}
|
|
2046
|
-
|
|
2257
|
+
function retryAfterMs(response, now) {
|
|
2258
|
+
const value = response.headers.get("retry-after")?.trim();
|
|
2259
|
+
if (!value) return void 0;
|
|
2260
|
+
if (/^\d+(?:\.\d+)?$/.test(value)) return Math.ceil(Number(value) * 1e3);
|
|
2261
|
+
const retryAt = Date.parse(value);
|
|
2262
|
+
return Number.isFinite(retryAt) ? Math.max(0, retryAt - now) : void 0;
|
|
2263
|
+
}
|
|
2264
|
+
async function readUsageResponse(response, now) {
|
|
2047
2265
|
const text = await response.text();
|
|
2048
2266
|
if (!response.ok) {
|
|
2049
2267
|
throw new SubscriptionUsageError(
|
|
2050
2268
|
`Subscription usage request failed with HTTP ${response.status}`,
|
|
2051
|
-
response.status
|
|
2269
|
+
response.status,
|
|
2270
|
+
retryAfterMs(response, now)
|
|
2052
2271
|
);
|
|
2053
2272
|
}
|
|
2054
2273
|
try {
|
|
@@ -2069,7 +2288,7 @@ async function fetchAnthropicUsage(credentials, fetchFn, signal, now) {
|
|
|
2069
2288
|
"User-Agent": "ezcoder"
|
|
2070
2289
|
}
|
|
2071
2290
|
});
|
|
2072
|
-
const data = await readUsageResponse(response);
|
|
2291
|
+
const data = await readUsageResponse(response, now());
|
|
2073
2292
|
const windows = [];
|
|
2074
2293
|
const currentPercent = clampPercent(data.five_hour?.utilization);
|
|
2075
2294
|
if (currentPercent !== void 0) {
|
|
@@ -2105,7 +2324,7 @@ async function fetchCodexUsage(credentials, fetchFn, signal, now) {
|
|
|
2105
2324
|
};
|
|
2106
2325
|
if (credentials.accountId) headers["ChatGPT-Account-Id"] = credentials.accountId;
|
|
2107
2326
|
const response = await fetchFn(CODEX_USAGE_URL, { method: "GET", signal, headers });
|
|
2108
|
-
const data = await readUsageResponse(response);
|
|
2327
|
+
const data = await readUsageResponse(response, now());
|
|
2109
2328
|
const windows = [
|
|
2110
2329
|
normalizedCodexWindow(data.rate_limit?.primary_window, "current", now()),
|
|
2111
2330
|
normalizedCodexWindow(data.rate_limit?.secondary_window, "weekly", now())
|
|
@@ -2121,12 +2340,97 @@ async function fetchCodexUsage(credentials, fetchFn, signal, now) {
|
|
|
2121
2340
|
fetchedAt: now()
|
|
2122
2341
|
};
|
|
2123
2342
|
}
|
|
2343
|
+
function kimiNumber(value) {
|
|
2344
|
+
if (typeof value === "string" && value.trim()) {
|
|
2345
|
+
const parsed = Number(value);
|
|
2346
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
2347
|
+
}
|
|
2348
|
+
return finiteNumber(value);
|
|
2349
|
+
}
|
|
2350
|
+
function kimiUsagePercent(detail) {
|
|
2351
|
+
const used = kimiNumber(detail?.used);
|
|
2352
|
+
const limit = kimiNumber(detail?.limit);
|
|
2353
|
+
if (used === void 0 || limit === void 0 || limit <= 0) return void 0;
|
|
2354
|
+
return Math.min(100, Math.max(0, used / limit * 100));
|
|
2355
|
+
}
|
|
2356
|
+
function kimiWindowMinutes(window) {
|
|
2357
|
+
const duration = kimiNumber(window?.duration);
|
|
2358
|
+
if (duration === void 0 || duration <= 0) return void 0;
|
|
2359
|
+
switch (window?.timeUnit) {
|
|
2360
|
+
case "TIME_UNIT_SECOND":
|
|
2361
|
+
return duration / 60;
|
|
2362
|
+
case "TIME_UNIT_MINUTE":
|
|
2363
|
+
return duration;
|
|
2364
|
+
case "TIME_UNIT_HOUR":
|
|
2365
|
+
return duration * 60;
|
|
2366
|
+
case "TIME_UNIT_DAY":
|
|
2367
|
+
return duration * 24 * 60;
|
|
2368
|
+
default:
|
|
2369
|
+
return void 0;
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
async function fetchKimiUsage(credentials, fetchFn, signal, now) {
|
|
2373
|
+
const response = await fetchFn(`${kimiCodeBaseUrl()}/usages`, {
|
|
2374
|
+
method: "GET",
|
|
2375
|
+
signal,
|
|
2376
|
+
headers: {
|
|
2377
|
+
Authorization: "Bearer " + credentials.accessToken,
|
|
2378
|
+
Accept: "application/json",
|
|
2379
|
+
// The managed coding endpoint gates on the kimi-code-cli client identity,
|
|
2380
|
+
// same as model requests.
|
|
2381
|
+
...kimiCodingHeaders()
|
|
2382
|
+
}
|
|
2383
|
+
});
|
|
2384
|
+
const data = await readUsageResponse(response, now());
|
|
2385
|
+
const windows = [];
|
|
2386
|
+
const weeklyPercent = kimiUsagePercent(data.usage);
|
|
2387
|
+
if (weeklyPercent !== void 0) {
|
|
2388
|
+
windows.push({
|
|
2389
|
+
kind: "weekly",
|
|
2390
|
+
label: "Weekly",
|
|
2391
|
+
usedPercent: weeklyPercent,
|
|
2392
|
+
resetsAt: isoTimestamp(data.usage?.resetTime)
|
|
2393
|
+
});
|
|
2394
|
+
}
|
|
2395
|
+
for (const limit of data.limits ?? []) {
|
|
2396
|
+
const minutes = kimiWindowMinutes(limit?.window);
|
|
2397
|
+
const percent = kimiUsagePercent(limit?.detail);
|
|
2398
|
+
if (minutes === void 0 || percent === void 0) continue;
|
|
2399
|
+
if (minutes >= 6 * 24 * 60) {
|
|
2400
|
+
if (!windows.some((window) => window.kind === "weekly")) {
|
|
2401
|
+
windows.push({
|
|
2402
|
+
kind: "weekly",
|
|
2403
|
+
label: "Weekly",
|
|
2404
|
+
usedPercent: percent,
|
|
2405
|
+
resetsAt: isoTimestamp(limit?.detail?.resetTime)
|
|
2406
|
+
});
|
|
2407
|
+
}
|
|
2408
|
+
continue;
|
|
2409
|
+
}
|
|
2410
|
+
windows.push({
|
|
2411
|
+
kind: "current",
|
|
2412
|
+
label: `${Math.max(1, Math.round(minutes / 60))}-hour`,
|
|
2413
|
+
usedPercent: percent,
|
|
2414
|
+
resetsAt: isoTimestamp(limit?.detail?.resetTime)
|
|
2415
|
+
});
|
|
2416
|
+
}
|
|
2417
|
+
windows.sort((left, right) => {
|
|
2418
|
+
if (left.kind === right.kind) return 0;
|
|
2419
|
+
return left.kind === "current" ? -1 : 1;
|
|
2420
|
+
});
|
|
2421
|
+
return {
|
|
2422
|
+
provider: "moonshot",
|
|
2423
|
+
displayName: "Kimi",
|
|
2424
|
+
windows,
|
|
2425
|
+
fetchedAt: now()
|
|
2426
|
+
};
|
|
2427
|
+
}
|
|
2124
2428
|
async function fetchSubscriptionUsage(provider, credentials, options = {}) {
|
|
2125
2429
|
const fetchFn = options.fetchFn ?? fetch;
|
|
2126
2430
|
const now = options.now ?? Date.now;
|
|
2127
2431
|
const signal = AbortSignal.timeout(options.timeoutMs ?? 8e3);
|
|
2128
2432
|
try {
|
|
2129
|
-
return provider === "anthropic" ? await fetchAnthropicUsage(credentials, fetchFn, signal, now) : await fetchCodexUsage(credentials, fetchFn, signal, now);
|
|
2433
|
+
return provider === "anthropic" ? await fetchAnthropicUsage(credentials, fetchFn, signal, now) : provider === "openai" ? await fetchCodexUsage(credentials, fetchFn, signal, now) : await fetchKimiUsage(credentials, fetchFn, signal, now);
|
|
2130
2434
|
} catch (error) {
|
|
2131
2435
|
if (error instanceof SubscriptionUsageError) throw error;
|
|
2132
2436
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -2443,7 +2747,7 @@ async function transcribeVoice(fileUrl) {
|
|
|
2443
2747
|
|
|
2444
2748
|
// src/auto-update.ts
|
|
2445
2749
|
var import_node_child_process2 = require("child_process");
|
|
2446
|
-
var
|
|
2750
|
+
var import_node_fs4 = __toESM(require("fs"), 1);
|
|
2447
2751
|
var import_node_path5 = __toESM(require("path"), 1);
|
|
2448
2752
|
var CHECK_INTERVAL_MS = 60 * 60 * 1e3;
|
|
2449
2753
|
var FETCH_TIMEOUT_MS2 = 1e4;
|
|
@@ -2477,7 +2781,7 @@ function createAutoUpdater(config) {
|
|
|
2477
2781
|
}
|
|
2478
2782
|
function readState() {
|
|
2479
2783
|
try {
|
|
2480
|
-
const raw =
|
|
2784
|
+
const raw = import_node_fs4.default.readFileSync(stateFilePath(), "utf-8");
|
|
2481
2785
|
return JSON.parse(raw);
|
|
2482
2786
|
} catch {
|
|
2483
2787
|
return null;
|
|
@@ -2486,8 +2790,8 @@ function createAutoUpdater(config) {
|
|
|
2486
2790
|
function writeState(state) {
|
|
2487
2791
|
try {
|
|
2488
2792
|
const filePath = stateFilePath();
|
|
2489
|
-
|
|
2490
|
-
|
|
2793
|
+
import_node_fs4.default.mkdirSync(import_node_path5.default.dirname(filePath), { recursive: true, mode: 448 });
|
|
2794
|
+
import_node_fs4.default.writeFileSync(filePath, JSON.stringify(state));
|
|
2491
2795
|
} catch {
|
|
2492
2796
|
}
|
|
2493
2797
|
}
|
|
@@ -2632,6 +2936,7 @@ function createAutoUpdater(config) {
|
|
|
2632
2936
|
getClaudeCodeVersion,
|
|
2633
2937
|
getContextWindow,
|
|
2634
2938
|
getDefaultModel,
|
|
2939
|
+
getDefaultThinkingLevel,
|
|
2635
2940
|
getFastModel,
|
|
2636
2941
|
getMaxThinkingLevel,
|
|
2637
2942
|
getModel,
|
|
@@ -2640,6 +2945,7 @@ function createAutoUpdater(config) {
|
|
|
2640
2945
|
getSessionId,
|
|
2641
2946
|
getSummaryModel,
|
|
2642
2947
|
getSupportedThinkingLevels,
|
|
2948
|
+
getToolResultCharLimit,
|
|
2643
2949
|
getVideoByteLimit,
|
|
2644
2950
|
isKimiCodingEndpoint,
|
|
2645
2951
|
isLoggerOpen,
|
|
@@ -2653,6 +2959,7 @@ function createAutoUpdater(config) {
|
|
|
2653
2959
|
loginKimi,
|
|
2654
2960
|
loginOpenAI,
|
|
2655
2961
|
openLog,
|
|
2962
|
+
readStoredBaseUrlSync,
|
|
2656
2963
|
refreshAnthropicToken,
|
|
2657
2964
|
refreshGeminiToken,
|
|
2658
2965
|
refreshKimiToken,
|