@prestyj/core 5.8.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-GMAX7TES.js → chunk-JXPW4JKV.js} +401 -290
- package/dist/chunk-JXPW4JKV.js.map +1 -0
- package/dist/index.cjs +596 -382
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -8
- package/dist/index.d.ts +31 -8
- package/dist/index.js +111 -8
- package/dist/index.js.map +1 -1
- package/dist/model-registry.cjs +45 -24
- package/dist/model-registry.cjs.map +1 -1
- package/dist/model-registry.d.cts +14 -1
- package/dist/model-registry.d.ts +14 -1
- package/dist/model-registry.js +3 -1
- package/package.json +2 -2
- package/dist/chunk-GMAX7TES.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,
|
|
@@ -73,6 +74,7 @@ __export(index_exports, {
|
|
|
73
74
|
loginKimi: () => loginKimi,
|
|
74
75
|
loginOpenAI: () => loginOpenAI,
|
|
75
76
|
openLog: () => openLog,
|
|
77
|
+
readStoredBaseUrlSync: () => readStoredBaseUrlSync,
|
|
76
78
|
refreshAnthropicToken: () => refreshAnthropicToken,
|
|
77
79
|
refreshGeminiToken: () => refreshGeminiToken,
|
|
78
80
|
refreshKimiToken: () => refreshKimiToken,
|
|
@@ -86,9 +88,12 @@ __export(index_exports, {
|
|
|
86
88
|
});
|
|
87
89
|
module.exports = __toCommonJS(index_exports);
|
|
88
90
|
|
|
89
|
-
// src/
|
|
90
|
-
var
|
|
91
|
-
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);
|
|
92
97
|
|
|
93
98
|
// src/paths.ts
|
|
94
99
|
var import_node_path = __toESM(require("path"), 1);
|
|
@@ -115,8 +120,225 @@ function getAppPaths() {
|
|
|
115
120
|
};
|
|
116
121
|
}
|
|
117
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
|
+
|
|
118
340
|
// src/oauth/anthropic.ts
|
|
119
|
-
var
|
|
341
|
+
var import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
120
342
|
|
|
121
343
|
// src/oauth/pkce.ts
|
|
122
344
|
function base64urlEncode(bytes) {
|
|
@@ -138,49 +360,66 @@ async function generatePKCE() {
|
|
|
138
360
|
|
|
139
361
|
// src/claude-code-version.ts
|
|
140
362
|
var import_promises = __toESM(require("fs/promises"), 1);
|
|
141
|
-
var
|
|
363
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
142
364
|
|
|
143
365
|
// src/logger.ts
|
|
144
|
-
var
|
|
145
|
-
var
|
|
146
|
-
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");
|
|
147
369
|
var import_ai = require("@prestyj/ai");
|
|
148
370
|
var MAX_BYTES = 10 * 1024 * 1024;
|
|
149
371
|
var fd = null;
|
|
372
|
+
var bytesWritten = 0;
|
|
373
|
+
var capped = false;
|
|
150
374
|
var sessionId = "";
|
|
151
375
|
var appName = "app";
|
|
152
376
|
var cleanups = [];
|
|
153
377
|
var exactSecrets = [];
|
|
154
378
|
function rotateIfNeeded(filePath) {
|
|
155
379
|
try {
|
|
156
|
-
const st =
|
|
380
|
+
const st = import_node_fs2.default.statSync(filePath);
|
|
157
381
|
if (st.size < MAX_BYTES) return;
|
|
158
382
|
const rotated = `${filePath}.1`;
|
|
159
383
|
try {
|
|
160
|
-
|
|
384
|
+
import_node_fs2.default.unlinkSync(rotated);
|
|
161
385
|
} catch {
|
|
162
386
|
}
|
|
163
|
-
|
|
387
|
+
import_node_fs2.default.renameSync(filePath, rotated);
|
|
164
388
|
} catch {
|
|
165
389
|
}
|
|
166
390
|
}
|
|
167
391
|
function openLog(filePath, name) {
|
|
168
|
-
if (fd !== null) return false;
|
|
392
|
+
if (fd !== null || capped) return false;
|
|
169
393
|
appName = name;
|
|
170
394
|
exactSecrets = (0, import_ai.environmentSecrets)(process.env);
|
|
171
395
|
try {
|
|
172
|
-
|
|
396
|
+
import_node_fs2.default.mkdirSync(import_node_path3.default.dirname(filePath), { recursive: true, mode: 448 });
|
|
173
397
|
} catch {
|
|
174
398
|
}
|
|
175
399
|
rotateIfNeeded(filePath);
|
|
176
400
|
try {
|
|
177
|
-
fd =
|
|
401
|
+
fd = import_node_fs2.default.openSync(filePath, "a");
|
|
178
402
|
} catch {
|
|
403
|
+
fd = null;
|
|
404
|
+
bytesWritten = 0;
|
|
179
405
|
return false;
|
|
180
406
|
}
|
|
181
|
-
sessionId = (0, import_node_crypto.randomBytes)(4).toString("hex");
|
|
182
407
|
try {
|
|
183
|
-
|
|
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
|
+
}
|
|
184
423
|
} catch {
|
|
185
424
|
}
|
|
186
425
|
return true;
|
|
@@ -206,8 +445,23 @@ function log(level, category, message, data) {
|
|
|
206
445
|
if (pairs) line += ` ${pairs}`;
|
|
207
446
|
}
|
|
208
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
|
+
}
|
|
209
463
|
try {
|
|
210
|
-
|
|
464
|
+
bytesWritten += import_node_fs2.default.writeSync(fd, line);
|
|
211
465
|
} catch {
|
|
212
466
|
}
|
|
213
467
|
}
|
|
@@ -215,13 +469,16 @@ function registerLogCleanup(fn) {
|
|
|
215
469
|
cleanups.push(fn);
|
|
216
470
|
}
|
|
217
471
|
function closeLogger(opts) {
|
|
218
|
-
if (fd
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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
|
+
}
|
|
223
478
|
}
|
|
224
479
|
fd = null;
|
|
480
|
+
bytesWritten = 0;
|
|
481
|
+
capped = false;
|
|
225
482
|
exactSecrets = [];
|
|
226
483
|
for (const unsub of cleanups) unsub();
|
|
227
484
|
cleanups = [];
|
|
@@ -235,7 +492,7 @@ var FALLBACK_VERSION = "2.1.88";
|
|
|
235
492
|
var memoryCache = null;
|
|
236
493
|
var inflight = null;
|
|
237
494
|
function cachePath() {
|
|
238
|
-
return
|
|
495
|
+
return import_node_path4.default.join(getAppPaths().agentDir, "claude-code-version.json");
|
|
239
496
|
}
|
|
240
497
|
async function readDiskCache() {
|
|
241
498
|
try {
|
|
@@ -317,7 +574,7 @@ async function getClaudeCliUserAgent() {
|
|
|
317
574
|
}
|
|
318
575
|
|
|
319
576
|
// src/oauth/anthropic.ts
|
|
320
|
-
var
|
|
577
|
+
var CLIENT_ID2 = atob("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
|
|
321
578
|
var AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
|
|
322
579
|
var TOKEN_URLS = [
|
|
323
580
|
"https://platform.claude.com/v1/oauth/token",
|
|
@@ -361,10 +618,10 @@ function toCredentials(data) {
|
|
|
361
618
|
}
|
|
362
619
|
async function loginAnthropic(callbacks) {
|
|
363
620
|
const { verifier, challenge } = await generatePKCE();
|
|
364
|
-
const state =
|
|
621
|
+
const state = import_node_crypto3.default.randomBytes(16).toString("hex");
|
|
365
622
|
const params = new URLSearchParams({
|
|
366
623
|
code: "true",
|
|
367
|
-
client_id:
|
|
624
|
+
client_id: CLIENT_ID2,
|
|
368
625
|
response_type: "code",
|
|
369
626
|
redirect_uri: REDIRECT_URI,
|
|
370
627
|
scope: SCOPES,
|
|
@@ -385,7 +642,7 @@ async function exchangeAnthropicCode(code, state, verifier) {
|
|
|
385
642
|
const data = await postTokenRequest(
|
|
386
643
|
{
|
|
387
644
|
grant_type: "authorization_code",
|
|
388
|
-
client_id:
|
|
645
|
+
client_id: CLIENT_ID2,
|
|
389
646
|
code,
|
|
390
647
|
state,
|
|
391
648
|
redirect_uri: REDIRECT_URI,
|
|
@@ -399,7 +656,7 @@ async function refreshAnthropicToken(refreshToken) {
|
|
|
399
656
|
const data = await postTokenRequest(
|
|
400
657
|
{
|
|
401
658
|
grant_type: "refresh_token",
|
|
402
|
-
client_id:
|
|
659
|
+
client_id: CLIENT_ID2,
|
|
403
660
|
refresh_token: refreshToken
|
|
404
661
|
},
|
|
405
662
|
"token refresh"
|
|
@@ -409,8 +666,8 @@ async function refreshAnthropicToken(refreshToken) {
|
|
|
409
666
|
|
|
410
667
|
// src/oauth/openai.ts
|
|
411
668
|
var import_node_http = __toESM(require("http"), 1);
|
|
412
|
-
var
|
|
413
|
-
var
|
|
669
|
+
var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
670
|
+
var CLIENT_ID3 = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
414
671
|
var AUTHORIZE_URL2 = "https://auth.openai.com/oauth/authorize";
|
|
415
672
|
var TOKEN_URL = "https://auth.openai.com/oauth/token";
|
|
416
673
|
var REDIRECT_URI2 = "http://localhost:1455/auth/callback";
|
|
@@ -418,10 +675,10 @@ var SCOPE = "openid profile email offline_access api.connectors.read api.connect
|
|
|
418
675
|
var JWT_CLAIM_PATH = "https://api.openai.com/auth";
|
|
419
676
|
async function loginOpenAI(callbacks) {
|
|
420
677
|
const { verifier, challenge } = await generatePKCE();
|
|
421
|
-
const state =
|
|
678
|
+
const state = import_node_crypto4.default.randomBytes(16).toString("hex");
|
|
422
679
|
const url = new URL(AUTHORIZE_URL2);
|
|
423
680
|
url.searchParams.set("response_type", "code");
|
|
424
|
-
url.searchParams.set("client_id",
|
|
681
|
+
url.searchParams.set("client_id", CLIENT_ID3);
|
|
425
682
|
url.searchParams.set("redirect_uri", REDIRECT_URI2);
|
|
426
683
|
url.searchParams.set("scope", SCOPE);
|
|
427
684
|
url.searchParams.set("code_challenge", challenge);
|
|
@@ -542,7 +799,7 @@ async function exchangeOpenAICode(code, verifier) {
|
|
|
542
799
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
543
800
|
body: new URLSearchParams({
|
|
544
801
|
grant_type: "authorization_code",
|
|
545
|
-
client_id:
|
|
802
|
+
client_id: CLIENT_ID3,
|
|
546
803
|
code,
|
|
547
804
|
redirect_uri: REDIRECT_URI2,
|
|
548
805
|
code_verifier: verifier
|
|
@@ -566,7 +823,7 @@ async function refreshOpenAIToken(refreshToken) {
|
|
|
566
823
|
body: new URLSearchParams({
|
|
567
824
|
grant_type: "refresh_token",
|
|
568
825
|
refresh_token: refreshToken,
|
|
569
|
-
client_id:
|
|
826
|
+
client_id: CLIENT_ID3
|
|
570
827
|
})
|
|
571
828
|
});
|
|
572
829
|
if (!response.ok) {
|
|
@@ -588,7 +845,7 @@ async function refreshOpenAIToken(refreshToken) {
|
|
|
588
845
|
|
|
589
846
|
// src/oauth/gemini.ts
|
|
590
847
|
var import_node_http2 = __toESM(require("http"), 1);
|
|
591
|
-
var
|
|
848
|
+
var import_node_crypto5 = __toESM(require("crypto"), 1);
|
|
592
849
|
var CLIENT_ID_ENV = "GGCODER_GEMINI_OAUTH_CLIENT_ID";
|
|
593
850
|
var CLIENT_SECRET_ENV = "GGCODER_GEMINI_OAUTH_CLIENT_SECRET";
|
|
594
851
|
var DEFAULT_CLIENT_ID = "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com";
|
|
@@ -622,7 +879,7 @@ var CodeAssistHttpError = class extends Error {
|
|
|
622
879
|
async function loginGemini(callbacks) {
|
|
623
880
|
const { clientId, clientSecret } = getGeminiOAuthClientCredentials();
|
|
624
881
|
const { verifier, challenge } = await generatePKCE();
|
|
625
|
-
const state =
|
|
882
|
+
const state = import_node_crypto5.default.randomBytes(32).toString("hex");
|
|
626
883
|
const redirectUri = await getLoopbackRedirectUri();
|
|
627
884
|
const url = new URL(AUTHORIZE_URL3);
|
|
628
885
|
url.searchParams.set("response_type", "code");
|
|
@@ -863,307 +1120,90 @@ async function loadCodeAssist(accessToken, envProject, metadata) {
|
|
|
863
1120
|
}
|
|
864
1121
|
}
|
|
865
1122
|
function getValidationRequiredTier(response) {
|
|
866
|
-
return response.ineligibleTiers?.find(
|
|
867
|
-
(tier) => tier.reasonCode === VALIDATION_REQUIRED_REASON && typeof tier.validationUrl === "string"
|
|
868
|
-
);
|
|
869
|
-
}
|
|
870
|
-
function getOnboardTier(response) {
|
|
871
|
-
const defaultTier = response.allowedTiers?.find((tier) => tier.isDefault);
|
|
872
|
-
return defaultTier ?? { id: USER_TIER_LEGACY, name: "" };
|
|
873
|
-
}
|
|
874
|
-
function throwProjectError(response) {
|
|
875
|
-
const reasons = response.ineligibleTiers?.map((tier) => tier.reasonMessage ?? tier.tierName).filter((reason) => Boolean(reason));
|
|
876
|
-
if (reasons && reasons.length > 0) {
|
|
877
|
-
throw new Error(`Gemini Code Assist setup failed: ${reasons.join(", ")}`);
|
|
878
|
-
}
|
|
879
|
-
throw new Error(
|
|
880
|
-
"Gemini requires a Google Cloud project for this account. Set GOOGLE_CLOUD_PROJECT and try again."
|
|
881
|
-
);
|
|
882
|
-
}
|
|
883
|
-
async function codeAssistPost(accessToken, method, body) {
|
|
884
|
-
let lastError;
|
|
885
|
-
for (let attempt = 0; attempt <= CODE_ASSIST_POST_RETRIES; attempt++) {
|
|
886
|
-
try {
|
|
887
|
-
return await codeAssistRequest(getCodeAssistMethodUrl(method), accessToken, method, {
|
|
888
|
-
method: "POST",
|
|
889
|
-
body: JSON.stringify(body)
|
|
890
|
-
});
|
|
891
|
-
} catch (err) {
|
|
892
|
-
if (!(err instanceof CodeAssistHttpError) || attempt === CODE_ASSIST_POST_RETRIES || !shouldRetryCodeAssistStatus(err.status)) {
|
|
893
|
-
throw err;
|
|
894
|
-
}
|
|
895
|
-
lastError = err;
|
|
896
|
-
}
|
|
897
|
-
await new Promise((resolve) => setTimeout(resolve, CODE_ASSIST_POST_RETRY_DELAY_MS));
|
|
898
|
-
}
|
|
899
|
-
throw lastError ?? new Error(`Gemini Code Assist ${method} failed.`);
|
|
900
|
-
}
|
|
901
|
-
async function codeAssistGet(accessToken, operationName) {
|
|
902
|
-
return codeAssistRequest(getCodeAssistOperationUrl(operationName), accessToken, "operation", {
|
|
903
|
-
method: "GET"
|
|
904
|
-
});
|
|
905
|
-
}
|
|
906
|
-
async function codeAssistRequest(url, accessToken, label, init) {
|
|
907
|
-
const response = await fetch(url, {
|
|
908
|
-
...init,
|
|
909
|
-
headers: codeAssistHeaders(accessToken)
|
|
910
|
-
});
|
|
911
|
-
if (!response.ok) {
|
|
912
|
-
const text = await response.text();
|
|
913
|
-
throw new CodeAssistHttpError(label, response.status, text);
|
|
914
|
-
}
|
|
915
|
-
return await response.json();
|
|
916
|
-
}
|
|
917
|
-
function getCodeAssistBaseUrl() {
|
|
918
|
-
const endpoint = process.env.CODE_ASSIST_ENDPOINT ?? CODE_ASSIST_BASE_URL;
|
|
919
|
-
const version = process.env.CODE_ASSIST_API_VERSION || CODE_ASSIST_API_VERSION;
|
|
920
|
-
return `${endpoint}/${version}`;
|
|
921
|
-
}
|
|
922
|
-
function getCodeAssistMethodUrl(method) {
|
|
923
|
-
return `${getCodeAssistBaseUrl()}:${method}`;
|
|
924
|
-
}
|
|
925
|
-
function getCodeAssistOperationUrl(operationName) {
|
|
926
|
-
return `${getCodeAssistBaseUrl()}/${operationName}`;
|
|
927
|
-
}
|
|
928
|
-
function shouldRetryCodeAssistStatus(status) {
|
|
929
|
-
return status === 429 || status === 499 || status >= 500 && status <= 599;
|
|
930
|
-
}
|
|
931
|
-
function isVpcScAffectedError(error) {
|
|
932
|
-
try {
|
|
933
|
-
const parsed = JSON.parse(error.body);
|
|
934
|
-
if (!parsed || typeof parsed !== "object" || !("error" in parsed)) return false;
|
|
935
|
-
const details = parsed.error?.details;
|
|
936
|
-
return Array.isArray(details) ? details.some(
|
|
937
|
-
(detail) => detail != null && typeof detail === "object" && "reason" in detail && detail.reason === VPC_SC_REASON
|
|
938
|
-
) : false;
|
|
939
|
-
} catch {
|
|
940
|
-
return false;
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
function codeAssistHeaders(accessToken) {
|
|
944
|
-
return {
|
|
945
|
-
Authorization: `Bearer ${accessToken}`,
|
|
946
|
-
"Content-Type": "application/json",
|
|
947
|
-
"User-Agent": "google-gemini-cli",
|
|
948
|
-
"X-Goog-Api-Client": "gemini-cli/0.0.0"
|
|
949
|
-
};
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
// src/oauth/kimi.ts
|
|
953
|
-
var import_node_child_process = require("child_process");
|
|
954
|
-
var import_node_crypto5 = require("crypto");
|
|
955
|
-
var import_node_fs2 = require("fs");
|
|
956
|
-
var import_node_os2 = require("os");
|
|
957
|
-
var import_node_path4 = __toESM(require("path"), 1);
|
|
958
|
-
var CLIENT_ID3 = "17e5f671-d194-4dfb-9706-5516cb48c098";
|
|
959
|
-
var DEFAULT_OAUTH_HOST = "https://auth.kimi.com";
|
|
960
|
-
var DEFAULT_CODING_BASE_URL = "https://api.kimi.com/coding/v1";
|
|
961
|
-
var KIMI_PLATFORM = "kimi_code_cli";
|
|
962
|
-
var DEFAULT_KIMI_VERSION = "1.0.11";
|
|
963
|
-
var DEVICE_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
964
|
-
function oauthHost() {
|
|
965
|
-
const host = process.env.KIMI_CODE_OAUTH_HOST ?? process.env.KIMI_OAUTH_HOST ?? DEFAULT_OAUTH_HOST;
|
|
966
|
-
return host.replace(/\/+$/, "");
|
|
967
|
-
}
|
|
968
|
-
function kimiCodeBaseUrl() {
|
|
969
|
-
return (process.env.KIMI_CODE_BASE_URL ?? DEFAULT_CODING_BASE_URL).replace(/\/+$/, "");
|
|
970
|
-
}
|
|
971
|
-
function kimiVersion() {
|
|
972
|
-
const v = process.env.KIMI_CODE_VERSION ?? DEFAULT_KIMI_VERSION;
|
|
973
|
-
return asciiHeader(v, DEFAULT_KIMI_VERSION);
|
|
974
|
-
}
|
|
975
|
-
function asciiHeader(value, fallback = "unknown") {
|
|
976
|
-
const cleaned = value.replace(/[^\u0020-\u007E]/g, "").trim();
|
|
977
|
-
return cleaned.length > 0 ? cleaned : fallback;
|
|
978
|
-
}
|
|
979
|
-
function macOsProductVersion() {
|
|
980
|
-
try {
|
|
981
|
-
const version = (0, import_node_child_process.execFileSync)("/usr/bin/sw_vers", ["-productVersion"], {
|
|
982
|
-
encoding: "utf-8",
|
|
983
|
-
timeout: 1e3
|
|
984
|
-
}).trim();
|
|
985
|
-
return version.length > 0 ? version : void 0;
|
|
986
|
-
} catch {
|
|
987
|
-
return void 0;
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
function deviceModel() {
|
|
991
|
-
const os2 = (0, import_node_os2.type)();
|
|
992
|
-
const version = (0, import_node_os2.release)();
|
|
993
|
-
const osArch = (0, import_node_os2.arch)();
|
|
994
|
-
if (os2 === "Darwin") return `macOS ${macOsProductVersion() ?? version} ${osArch}`;
|
|
995
|
-
if (os2 === "Windows_NT") return `Windows ${version} ${osArch}`;
|
|
996
|
-
return `${os2} ${version} ${osArch}`.trim();
|
|
997
|
-
}
|
|
998
|
-
function deviceId() {
|
|
999
|
-
const idPath = import_node_path4.default.join(getAppPaths().agentDir, "kimi_device_id");
|
|
1000
|
-
if ((0, import_node_fs2.existsSync)(idPath)) {
|
|
1001
|
-
try {
|
|
1002
|
-
const text = (0, import_node_fs2.readFileSync)(idPath, "utf-8").trim();
|
|
1003
|
-
if (text.length > 0) return text;
|
|
1004
|
-
} catch {
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
const id = (0, import_node_crypto5.randomUUID)();
|
|
1008
|
-
try {
|
|
1009
|
-
(0, import_node_fs2.mkdirSync)(getAppPaths().agentDir, { recursive: true, mode: 448 });
|
|
1010
|
-
(0, import_node_fs2.writeFileSync)(idPath, id, { encoding: "utf-8", mode: 384 });
|
|
1011
|
-
} catch {
|
|
1012
|
-
}
|
|
1013
|
-
return id;
|
|
1014
|
-
}
|
|
1015
|
-
function deviceHeaders() {
|
|
1016
|
-
return {
|
|
1017
|
-
"X-Msh-Platform": KIMI_PLATFORM,
|
|
1018
|
-
"X-Msh-Version": kimiVersion(),
|
|
1019
|
-
"X-Msh-Device-Name": asciiHeader((0, import_node_os2.hostname)()),
|
|
1020
|
-
"X-Msh-Device-Model": asciiHeader(deviceModel()),
|
|
1021
|
-
"X-Msh-Os-Version": asciiHeader((0, import_node_os2.release)()),
|
|
1022
|
-
"X-Msh-Device-Id": deviceId()
|
|
1023
|
-
};
|
|
1024
|
-
}
|
|
1025
|
-
function kimiCodingHeaders() {
|
|
1026
|
-
return {
|
|
1027
|
-
"User-Agent": `kimi-code-cli/${kimiVersion()}`,
|
|
1028
|
-
...deviceHeaders()
|
|
1029
|
-
};
|
|
1030
|
-
}
|
|
1031
|
-
function isKimiCodingEndpoint(baseUrl) {
|
|
1032
|
-
if (typeof baseUrl !== "string" || baseUrl.length === 0) return false;
|
|
1033
|
-
const normalized = baseUrl.replace(/\/+$/, "");
|
|
1034
|
-
return normalized === kimiCodeBaseUrl() || /(^|\.)kimi\.com/i.test(normalized);
|
|
1035
|
-
}
|
|
1036
|
-
async function postForm(endpoint, params) {
|
|
1037
|
-
const response = await fetch(`${oauthHost()}${endpoint}`, {
|
|
1038
|
-
method: "POST",
|
|
1039
|
-
headers: {
|
|
1040
|
-
...deviceHeaders(),
|
|
1041
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
1042
|
-
Accept: "application/json"
|
|
1043
|
-
},
|
|
1044
|
-
body: new URLSearchParams(params).toString()
|
|
1045
|
-
});
|
|
1046
|
-
let data = {};
|
|
1047
|
-
try {
|
|
1048
|
-
const parsed = await response.json();
|
|
1049
|
-
if (parsed && typeof parsed === "object") data = parsed;
|
|
1050
|
-
} catch {
|
|
1051
|
-
}
|
|
1052
|
-
return { status: response.status, data };
|
|
1123
|
+
return response.ineligibleTiers?.find(
|
|
1124
|
+
(tier) => tier.reasonCode === VALIDATION_REQUIRED_REASON && typeof tier.validationUrl === "string"
|
|
1125
|
+
);
|
|
1053
1126
|
}
|
|
1054
|
-
function
|
|
1055
|
-
const
|
|
1056
|
-
return
|
|
1127
|
+
function getOnboardTier(response) {
|
|
1128
|
+
const defaultTier = response.allowedTiers?.find((tier) => tier.isDefault);
|
|
1129
|
+
return defaultTier ?? { id: USER_TIER_LEGACY, name: "" };
|
|
1057
1130
|
}
|
|
1058
|
-
function
|
|
1059
|
-
const
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
if (typeof accessToken !== "string" || accessToken.length === 0) {
|
|
1063
|
-
throw new Error("Kimi OAuth response missing access_token.");
|
|
1064
|
-
}
|
|
1065
|
-
const refreshToken = typeof responseRefreshToken === "string" && responseRefreshToken.length > 0 ? responseRefreshToken : opts?.fallbackRefreshToken ?? "";
|
|
1066
|
-
if (refreshToken.length === 0) {
|
|
1067
|
-
throw new Error("Kimi OAuth response missing refresh_token.");
|
|
1131
|
+
function throwProjectError(response) {
|
|
1132
|
+
const reasons = response.ineligibleTiers?.map((tier) => tier.reasonMessage ?? tier.tierName).filter((reason) => Boolean(reason));
|
|
1133
|
+
if (reasons && reasons.length > 0) {
|
|
1134
|
+
throw new Error(`Gemini Code Assist setup failed: ${reasons.join(", ")}`);
|
|
1068
1135
|
}
|
|
1069
|
-
|
|
1070
|
-
|
|
1136
|
+
throw new Error(
|
|
1137
|
+
"Gemini requires a Google Cloud project for this account. Set GOOGLE_CLOUD_PROJECT and try again."
|
|
1138
|
+
);
|
|
1139
|
+
}
|
|
1140
|
+
async function codeAssistPost(accessToken, method, body) {
|
|
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));
|
|
1071
1155
|
}
|
|
1072
|
-
|
|
1073
|
-
accessToken,
|
|
1074
|
-
refreshToken,
|
|
1075
|
-
expiresAt: Date.now() + expiresIn * 1e3,
|
|
1076
|
-
baseUrl: kimiCodeBaseUrl()
|
|
1077
|
-
};
|
|
1156
|
+
throw lastError ?? new Error(`Gemini Code Assist ${method} failed.`);
|
|
1078
1157
|
}
|
|
1079
|
-
async function
|
|
1080
|
-
|
|
1081
|
-
|
|
1158
|
+
async function codeAssistGet(accessToken, operationName) {
|
|
1159
|
+
return codeAssistRequest(getCodeAssistOperationUrl(operationName), accessToken, "operation", {
|
|
1160
|
+
method: "GET"
|
|
1082
1161
|
});
|
|
1083
|
-
if (status !== 200) {
|
|
1084
|
-
throw new Error(`Kimi device authorization failed (${status}): ${errorDetail(data)}`);
|
|
1085
|
-
}
|
|
1086
|
-
const userCode = data.user_code;
|
|
1087
|
-
const deviceCode = data.device_code;
|
|
1088
|
-
const verificationUriComplete = data.verification_uri_complete;
|
|
1089
|
-
if (typeof userCode !== "string" || typeof deviceCode !== "string") {
|
|
1090
|
-
throw new Error("Kimi device authorization response missing user_code/device_code.");
|
|
1091
|
-
}
|
|
1092
|
-
return {
|
|
1093
|
-
userCode,
|
|
1094
|
-
deviceCode,
|
|
1095
|
-
verificationUri: typeof data.verification_uri === "string" ? data.verification_uri : "",
|
|
1096
|
-
verificationUriComplete: typeof verificationUriComplete === "string" ? verificationUriComplete : "",
|
|
1097
|
-
interval: Number(data.interval ?? 5) || 5
|
|
1098
|
-
};
|
|
1099
1162
|
}
|
|
1100
|
-
async function
|
|
1101
|
-
const
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
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)
|
|
1105
1167
|
});
|
|
1106
|
-
if (
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
if (status >= 500) {
|
|
1110
|
-
throw new Error(`Kimi token polling server error (${status}): ${errorDetail(data)}`);
|
|
1111
|
-
}
|
|
1112
|
-
const errorCode = typeof data.error === "string" ? data.error : "unknown_error";
|
|
1113
|
-
switch (errorCode) {
|
|
1114
|
-
case "authorization_pending":
|
|
1115
|
-
return { kind: "pending" };
|
|
1116
|
-
case "slow_down":
|
|
1117
|
-
return { kind: "slow_down" };
|
|
1118
|
-
case "expired_token":
|
|
1119
|
-
return { kind: "expired" };
|
|
1120
|
-
case "access_denied":
|
|
1121
|
-
return { kind: "denied" };
|
|
1122
|
-
default:
|
|
1123
|
-
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);
|
|
1124
1171
|
}
|
|
1172
|
+
return await response.json();
|
|
1125
1173
|
}
|
|
1126
|
-
function
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
}
|
|
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}`;
|
|
1130
1178
|
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
callbacks.onStatus(
|
|
1134
|
-
`Visit ${auth.verificationUri || auth.verificationUriComplete} and enter code: ${auth.userCode}`
|
|
1135
|
-
);
|
|
1136
|
-
callbacks.onOpenUrl(auth.verificationUriComplete || auth.verificationUri);
|
|
1137
|
-
callbacks.onStatus("Waiting for you to authorize in the browser...");
|
|
1138
|
-
const deadline = Date.now() + DEVICE_TIMEOUT_MS;
|
|
1139
|
-
let interval = Math.max(auth.interval, 1);
|
|
1140
|
-
while (Date.now() < deadline) {
|
|
1141
|
-
await sleep(interval * 1e3);
|
|
1142
|
-
const result = await pollDeviceToken(auth.deviceCode);
|
|
1143
|
-
if (result.kind === "success") return result.creds;
|
|
1144
|
-
if (result.kind === "denied") {
|
|
1145
|
-
throw new Error("Kimi authorization was denied.");
|
|
1146
|
-
}
|
|
1147
|
-
if (result.kind === "expired") {
|
|
1148
|
-
throw new Error("Kimi device code expired. Please run login again.");
|
|
1149
|
-
}
|
|
1150
|
-
if (result.kind === "slow_down") {
|
|
1151
|
-
interval += 5;
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
throw new Error("Kimi login timed out. Please run login again.");
|
|
1179
|
+
function getCodeAssistMethodUrl(method) {
|
|
1180
|
+
return `${getCodeAssistBaseUrl()}:${method}`;
|
|
1155
1181
|
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
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;
|
|
1164
1198
|
}
|
|
1165
|
-
|
|
1166
|
-
|
|
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
|
+
};
|
|
1167
1207
|
}
|
|
1168
1208
|
|
|
1169
1209
|
// src/file-lock.ts
|
|
@@ -1231,6 +1271,26 @@ function isAlive(pid) {
|
|
|
1231
1271
|
// src/auth-storage.ts
|
|
1232
1272
|
var MOONSHOT_OAUTH_KEY = "moonshot-oauth";
|
|
1233
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
|
+
}
|
|
1234
1294
|
var REFRESH_SKEW_MS = 6e4;
|
|
1235
1295
|
var USAGE_EXHAUSTED_DEFAULT_MS = 15 * 60 * 1e3;
|
|
1236
1296
|
var STATIC_API_KEY_PROVIDERS = /* @__PURE__ */ new Set([
|
|
@@ -1306,6 +1366,16 @@ var AuthStorage = class {
|
|
|
1306
1366
|
}
|
|
1307
1367
|
return STATIC_API_KEY_PROVIDERS.has(provider);
|
|
1308
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
|
+
}
|
|
1309
1379
|
async load() {
|
|
1310
1380
|
await withFileLock(this.filePath, async () => {
|
|
1311
1381
|
try {
|
|
@@ -1337,27 +1407,46 @@ var AuthStorage = class {
|
|
|
1337
1407
|
/**
|
|
1338
1408
|
* Force a re-read from disk, discarding the in-memory cache. Needed when
|
|
1339
1409
|
* another process mutates the auth file out-of-band — e.g. the desktop app
|
|
1340
|
-
* writes API keys natively
|
|
1341
|
-
* this instance, so a long-lived daemon's cache would otherwise stay stale and
|
|
1342
|
-
* never see a newly added provider key.
|
|
1410
|
+
* writes API keys natively without going through this instance.
|
|
1343
1411
|
*/
|
|
1344
1412
|
async reload() {
|
|
1345
1413
|
this.loaded = false;
|
|
1346
1414
|
await this.load();
|
|
1347
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
|
+
}
|
|
1348
1437
|
async getCredentials(provider) {
|
|
1349
1438
|
await this.ensureLoaded();
|
|
1350
1439
|
return this.data[provider];
|
|
1351
1440
|
}
|
|
1352
1441
|
async setCredentials(provider, creds) {
|
|
1353
|
-
await this.
|
|
1354
|
-
|
|
1355
|
-
|
|
1442
|
+
await this.mutateLatest((latest) => {
|
|
1443
|
+
latest[provider] = creds;
|
|
1444
|
+
});
|
|
1356
1445
|
}
|
|
1357
1446
|
async clearCredentials(provider) {
|
|
1358
|
-
await this.
|
|
1359
|
-
|
|
1360
|
-
|
|
1447
|
+
await this.mutateLatest((latest) => {
|
|
1448
|
+
delete latest[provider];
|
|
1449
|
+
});
|
|
1361
1450
|
}
|
|
1362
1451
|
/**
|
|
1363
1452
|
* Mark the credential stored under `storageKey` as usage-exhausted until
|
|
@@ -1371,12 +1460,15 @@ var AuthStorage = class {
|
|
|
1371
1460
|
* nothing is stored under `storageKey`.
|
|
1372
1461
|
*/
|
|
1373
1462
|
async markUsageExhausted(storageKey, resetsAt) {
|
|
1374
|
-
await this.ensureLoaded();
|
|
1375
|
-
const creds = this.data[storageKey];
|
|
1376
|
-
if (!creds) return;
|
|
1377
1463
|
const until = resetsAt !== void 0 && resetsAt * 1e3 > Date.now() ? resetsAt * 1e3 : Date.now() + USAGE_EXHAUSTED_DEFAULT_MS;
|
|
1378
|
-
|
|
1379
|
-
await this.
|
|
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;
|
|
1380
1472
|
log(
|
|
1381
1473
|
"WARN",
|
|
1382
1474
|
"auth",
|
|
@@ -1384,8 +1476,11 @@ var AuthStorage = class {
|
|
|
1384
1476
|
);
|
|
1385
1477
|
}
|
|
1386
1478
|
async clearAll() {
|
|
1387
|
-
this.
|
|
1388
|
-
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
|
+
});
|
|
1389
1484
|
}
|
|
1390
1485
|
/**
|
|
1391
1486
|
* Returns valid credentials, auto-refreshing if expired.
|
|
@@ -1395,6 +1490,10 @@ var AuthStorage = class {
|
|
|
1395
1490
|
*/
|
|
1396
1491
|
async resolveCredentials(provider, opts) {
|
|
1397
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
|
+
}
|
|
1398
1497
|
if (opts?.storageKeys && !(opts.storageKeys.length === 1 && opts.storageKeys[0] === provider)) {
|
|
1399
1498
|
for (const key of opts.storageKeys) {
|
|
1400
1499
|
const creds2 = this.data[key];
|
|
@@ -1441,41 +1540,44 @@ var AuthStorage = class {
|
|
|
1441
1540
|
const existing = this.refreshLocks.get(provider);
|
|
1442
1541
|
if (existing) return existing;
|
|
1443
1542
|
const refreshPromise = withFileLock(this.filePath, async () => {
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
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;
|
|
1453
1553
|
}
|
|
1454
1554
|
const refreshFn = provider === "anthropic" ? refreshAnthropicToken : provider === "gemini" ? refreshGeminiToken : provider === MOONSHOT_OAUTH_KEY ? refreshKimiToken : refreshOpenAIToken;
|
|
1455
1555
|
let refreshed;
|
|
1456
1556
|
try {
|
|
1457
|
-
refreshed = await refreshFn(
|
|
1557
|
+
refreshed = await refreshFn(latestCreds.refreshToken);
|
|
1458
1558
|
} catch (err) {
|
|
1459
1559
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1460
1560
|
const isAuthFailure = /\((401|400)\)/.test(msg) || /invalid_grant|invalid_token|invalid.*refresh/i.test(msg) || /unauthorized/i.test(msg);
|
|
1461
1561
|
if (isAuthFailure) {
|
|
1462
|
-
delete
|
|
1463
|
-
|
|
1562
|
+
delete latest[provider];
|
|
1563
|
+
this.data = latest;
|
|
1564
|
+
await atomicWriteFile(this.filePath, JSON.stringify(latest, null, 2));
|
|
1464
1565
|
throw new NotLoggedInError(provider);
|
|
1465
1566
|
}
|
|
1466
1567
|
throw err;
|
|
1467
1568
|
}
|
|
1468
|
-
if (!refreshed.accountId &&
|
|
1469
|
-
refreshed.accountId =
|
|
1569
|
+
if (!refreshed.accountId && latestCreds.accountId) {
|
|
1570
|
+
refreshed.accountId = latestCreds.accountId;
|
|
1470
1571
|
}
|
|
1471
|
-
if (!refreshed.projectId &&
|
|
1472
|
-
refreshed.projectId =
|
|
1572
|
+
if (!refreshed.projectId && latestCreds.projectId) {
|
|
1573
|
+
refreshed.projectId = latestCreds.projectId;
|
|
1473
1574
|
}
|
|
1474
|
-
if (!refreshed.baseUrl &&
|
|
1475
|
-
refreshed.baseUrl =
|
|
1575
|
+
if (!refreshed.baseUrl && latestCreds.baseUrl) {
|
|
1576
|
+
refreshed.baseUrl = latestCreds.baseUrl;
|
|
1476
1577
|
}
|
|
1477
|
-
|
|
1478
|
-
|
|
1578
|
+
latest[provider] = refreshed;
|
|
1579
|
+
this.data = latest;
|
|
1580
|
+
await atomicWriteFile(this.filePath, JSON.stringify(latest, null, 2));
|
|
1479
1581
|
return refreshed;
|
|
1480
1582
|
});
|
|
1481
1583
|
this.refreshLocks.set(provider, refreshPromise);
|
|
@@ -1493,12 +1595,16 @@ var AuthStorage = class {
|
|
|
1493
1595
|
const creds = await this.resolveCredentials(provider);
|
|
1494
1596
|
return creds.accessToken;
|
|
1495
1597
|
}
|
|
1496
|
-
async save() {
|
|
1497
|
-
await withFileLock(this.filePath, async () => {
|
|
1498
|
-
await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));
|
|
1499
|
-
});
|
|
1500
|
-
}
|
|
1501
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
|
+
}
|
|
1502
1608
|
async function atomicWriteFile(filePath, content) {
|
|
1503
1609
|
const tmpPath = `${filePath}.${process.pid}.${Date.now()}.${import_node_crypto6.default.randomUUID().slice(0, 8)}.tmp`;
|
|
1504
1610
|
try {
|
|
@@ -1591,7 +1697,8 @@ var MODELS = [
|
|
|
1591
1697
|
// ── OpenAI (Codex) ─────────────────────────────────────
|
|
1592
1698
|
// GPT-5.6 family — three agentic coding tiers launched July 2026. The public
|
|
1593
1699
|
// Responses API advertises a 1.05M context window; OpenAI's Codex product
|
|
1594
|
-
// 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
|
|
1595
1702
|
// text+image input, freeform apply_patch, text+image web search, and parallel
|
|
1596
1703
|
// tool calls.
|
|
1597
1704
|
{
|
|
@@ -1603,7 +1710,7 @@ var MODELS = [
|
|
|
1603
1710
|
name: "GPT-5.6 Sol",
|
|
1604
1711
|
provider: "openai",
|
|
1605
1712
|
contextWindow: 105e4,
|
|
1606
|
-
codexContextWindow:
|
|
1713
|
+
codexContextWindow: 272e3,
|
|
1607
1714
|
maxOutputTokens: 128e3,
|
|
1608
1715
|
supportsThinking: true,
|
|
1609
1716
|
supportsImages: true,
|
|
@@ -1618,7 +1725,7 @@ var MODELS = [
|
|
|
1618
1725
|
name: "GPT-5.6 Terra",
|
|
1619
1726
|
provider: "openai",
|
|
1620
1727
|
contextWindow: 105e4,
|
|
1621
|
-
codexContextWindow:
|
|
1728
|
+
codexContextWindow: 272e3,
|
|
1622
1729
|
maxOutputTokens: 128e3,
|
|
1623
1730
|
supportsThinking: true,
|
|
1624
1731
|
supportsImages: true,
|
|
@@ -1633,7 +1740,7 @@ var MODELS = [
|
|
|
1633
1740
|
name: "GPT-5.6 Luna",
|
|
1634
1741
|
provider: "openai",
|
|
1635
1742
|
contextWindow: 105e4,
|
|
1636
|
-
codexContextWindow:
|
|
1743
|
+
codexContextWindow: 272e3,
|
|
1637
1744
|
maxOutputTokens: 128e3,
|
|
1638
1745
|
supportsThinking: true,
|
|
1639
1746
|
supportsImages: true,
|
|
@@ -1752,8 +1859,9 @@ var MODELS = [
|
|
|
1752
1859
|
},
|
|
1753
1860
|
// ── Moonshot (Kimi) ────────────────────────────────────
|
|
1754
1861
|
// K3 is Kimi's 2.8T-parameter flagship for long-horizon coding, knowledge
|
|
1755
|
-
// work, and deep reasoning.
|
|
1756
|
-
//
|
|
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.
|
|
1757
1865
|
{
|
|
1758
1866
|
id: "kimi-k3",
|
|
1759
1867
|
name: "Kimi K3",
|
|
@@ -1987,6 +2095,11 @@ function getContextWindow(modelId, options) {
|
|
|
1987
2095
|
function getMaxThinkingLevel(modelId) {
|
|
1988
2096
|
return getModel(modelId)?.maxThinkingLevel ?? "high";
|
|
1989
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
|
+
}
|
|
1990
2103
|
function getSummaryModel(provider, currentModelId) {
|
|
1991
2104
|
if (provider === "anthropic") {
|
|
1992
2105
|
return MODELS.find((m) => m.id === "claude-sonnet-5");
|
|
@@ -2027,6 +2140,7 @@ var ANTHROPIC_ADAPTIVE_THINKING_LEVELS = [
|
|
|
2027
2140
|
"high",
|
|
2028
2141
|
"max"
|
|
2029
2142
|
];
|
|
2143
|
+
var MOONSHOT_K3_THINKING_LEVELS = ["low", "high", "max"];
|
|
2030
2144
|
function isOpenAIGptModel(provider, model) {
|
|
2031
2145
|
return provider === "openai" && model.startsWith("gpt-");
|
|
2032
2146
|
}
|
|
@@ -2036,6 +2150,9 @@ function isSakanaModel(provider) {
|
|
|
2036
2150
|
function isXaiModel(provider) {
|
|
2037
2151
|
return provider === "xai";
|
|
2038
2152
|
}
|
|
2153
|
+
function isMoonshotK3Model(provider, model) {
|
|
2154
|
+
return provider === "moonshot" && model === "kimi-k3";
|
|
2155
|
+
}
|
|
2039
2156
|
function isAnthropicOpus48Or47Model(provider, model) {
|
|
2040
2157
|
return provider === "anthropic" && /opus-4-8|opus-4-7/.test(model);
|
|
2041
2158
|
}
|
|
@@ -2060,6 +2177,7 @@ function getSupportedThinkingLevels(provider, model) {
|
|
|
2060
2177
|
if (maxIndex2 === -1) return XAI_THINKING_LEVELS;
|
|
2061
2178
|
return XAI_THINKING_LEVELS.slice(0, maxIndex2 + 1);
|
|
2062
2179
|
}
|
|
2180
|
+
if (isMoonshotK3Model(provider, model)) return MOONSHOT_K3_THINKING_LEVELS;
|
|
2063
2181
|
if (!isOpenAIGptModel(provider, model)) return [maxLevel];
|
|
2064
2182
|
const levels = model.startsWith("gpt-5.6-") ? OPENAI_GPT_56_THINKING_LEVELS : OPENAI_GPT_THINKING_LEVELS;
|
|
2065
2183
|
const maxIndex = levels.indexOf(maxLevel);
|
|
@@ -2071,7 +2189,7 @@ function isThinkingLevelSupported(provider, model, level) {
|
|
|
2071
2189
|
}
|
|
2072
2190
|
function getNextThinkingLevel(provider, model, current) {
|
|
2073
2191
|
const supportedLevels = getSupportedThinkingLevels(provider, model);
|
|
2074
|
-
const shouldCycleLevels = isOpenAIGptModel(provider, model) || isAnthropicAdaptiveModel(provider, model) || isSakanaModel(provider) || isXaiModel(provider);
|
|
2192
|
+
const shouldCycleLevels = isOpenAIGptModel(provider, model) || isAnthropicAdaptiveModel(provider, model) || isSakanaModel(provider) || isXaiModel(provider) || isMoonshotK3Model(provider, model);
|
|
2075
2193
|
if (!shouldCycleLevels) {
|
|
2076
2194
|
return current ? void 0 : supportedLevels[0];
|
|
2077
2195
|
}
|
|
@@ -2083,9 +2201,10 @@ function getNextThinkingLevel(provider, model, current) {
|
|
|
2083
2201
|
|
|
2084
2202
|
// src/provider-usage.ts
|
|
2085
2203
|
var SubscriptionUsageError = class extends Error {
|
|
2086
|
-
constructor(message, status) {
|
|
2204
|
+
constructor(message, status, retryAfterMs2) {
|
|
2087
2205
|
super(message);
|
|
2088
2206
|
this.status = status;
|
|
2207
|
+
this.retryAfterMs = retryAfterMs2;
|
|
2089
2208
|
this.name = "SubscriptionUsageError";
|
|
2090
2209
|
}
|
|
2091
2210
|
};
|
|
@@ -2135,12 +2254,20 @@ function normalizedCodexWindow(window, fallbackKind, now) {
|
|
|
2135
2254
|
resetsAt: codexResetAt(window, now)
|
|
2136
2255
|
};
|
|
2137
2256
|
}
|
|
2138
|
-
|
|
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) {
|
|
2139
2265
|
const text = await response.text();
|
|
2140
2266
|
if (!response.ok) {
|
|
2141
2267
|
throw new SubscriptionUsageError(
|
|
2142
2268
|
`Subscription usage request failed with HTTP ${response.status}`,
|
|
2143
|
-
response.status
|
|
2269
|
+
response.status,
|
|
2270
|
+
retryAfterMs(response, now)
|
|
2144
2271
|
);
|
|
2145
2272
|
}
|
|
2146
2273
|
try {
|
|
@@ -2161,7 +2288,7 @@ async function fetchAnthropicUsage(credentials, fetchFn, signal, now) {
|
|
|
2161
2288
|
"User-Agent": "ezcoder"
|
|
2162
2289
|
}
|
|
2163
2290
|
});
|
|
2164
|
-
const data = await readUsageResponse(response);
|
|
2291
|
+
const data = await readUsageResponse(response, now());
|
|
2165
2292
|
const windows = [];
|
|
2166
2293
|
const currentPercent = clampPercent(data.five_hour?.utilization);
|
|
2167
2294
|
if (currentPercent !== void 0) {
|
|
@@ -2197,7 +2324,7 @@ async function fetchCodexUsage(credentials, fetchFn, signal, now) {
|
|
|
2197
2324
|
};
|
|
2198
2325
|
if (credentials.accountId) headers["ChatGPT-Account-Id"] = credentials.accountId;
|
|
2199
2326
|
const response = await fetchFn(CODEX_USAGE_URL, { method: "GET", signal, headers });
|
|
2200
|
-
const data = await readUsageResponse(response);
|
|
2327
|
+
const data = await readUsageResponse(response, now());
|
|
2201
2328
|
const windows = [
|
|
2202
2329
|
normalizedCodexWindow(data.rate_limit?.primary_window, "current", now()),
|
|
2203
2330
|
normalizedCodexWindow(data.rate_limit?.secondary_window, "weekly", now())
|
|
@@ -2213,12 +2340,97 @@ async function fetchCodexUsage(credentials, fetchFn, signal, now) {
|
|
|
2213
2340
|
fetchedAt: now()
|
|
2214
2341
|
};
|
|
2215
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
|
+
}
|
|
2216
2428
|
async function fetchSubscriptionUsage(provider, credentials, options = {}) {
|
|
2217
2429
|
const fetchFn = options.fetchFn ?? fetch;
|
|
2218
2430
|
const now = options.now ?? Date.now;
|
|
2219
2431
|
const signal = AbortSignal.timeout(options.timeoutMs ?? 8e3);
|
|
2220
2432
|
try {
|
|
2221
|
-
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);
|
|
2222
2434
|
} catch (error) {
|
|
2223
2435
|
if (error instanceof SubscriptionUsageError) throw error;
|
|
2224
2436
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -2535,7 +2747,7 @@ async function transcribeVoice(fileUrl) {
|
|
|
2535
2747
|
|
|
2536
2748
|
// src/auto-update.ts
|
|
2537
2749
|
var import_node_child_process2 = require("child_process");
|
|
2538
|
-
var
|
|
2750
|
+
var import_node_fs4 = __toESM(require("fs"), 1);
|
|
2539
2751
|
var import_node_path5 = __toESM(require("path"), 1);
|
|
2540
2752
|
var CHECK_INTERVAL_MS = 60 * 60 * 1e3;
|
|
2541
2753
|
var FETCH_TIMEOUT_MS2 = 1e4;
|
|
@@ -2569,7 +2781,7 @@ function createAutoUpdater(config) {
|
|
|
2569
2781
|
}
|
|
2570
2782
|
function readState() {
|
|
2571
2783
|
try {
|
|
2572
|
-
const raw =
|
|
2784
|
+
const raw = import_node_fs4.default.readFileSync(stateFilePath(), "utf-8");
|
|
2573
2785
|
return JSON.parse(raw);
|
|
2574
2786
|
} catch {
|
|
2575
2787
|
return null;
|
|
@@ -2578,8 +2790,8 @@ function createAutoUpdater(config) {
|
|
|
2578
2790
|
function writeState(state) {
|
|
2579
2791
|
try {
|
|
2580
2792
|
const filePath = stateFilePath();
|
|
2581
|
-
|
|
2582
|
-
|
|
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));
|
|
2583
2795
|
} catch {
|
|
2584
2796
|
}
|
|
2585
2797
|
}
|
|
@@ -2724,6 +2936,7 @@ function createAutoUpdater(config) {
|
|
|
2724
2936
|
getClaudeCodeVersion,
|
|
2725
2937
|
getContextWindow,
|
|
2726
2938
|
getDefaultModel,
|
|
2939
|
+
getDefaultThinkingLevel,
|
|
2727
2940
|
getFastModel,
|
|
2728
2941
|
getMaxThinkingLevel,
|
|
2729
2942
|
getModel,
|
|
@@ -2746,6 +2959,7 @@ function createAutoUpdater(config) {
|
|
|
2746
2959
|
loginKimi,
|
|
2747
2960
|
loginOpenAI,
|
|
2748
2961
|
openLog,
|
|
2962
|
+
readStoredBaseUrlSync,
|
|
2749
2963
|
refreshAnthropicToken,
|
|
2750
2964
|
refreshGeminiToken,
|
|
2751
2965
|
refreshKimiToken,
|