@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/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/auth-storage.ts
89
- var import_promises4 = __toESM(require("fs/promises"), 1);
90
- var import_node_crypto6 = __toESM(require("crypto"), 1);
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 import_node_crypto2 = __toESM(require("crypto"), 1);
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 import_node_path3 = __toESM(require("path"), 1);
363
+ var import_node_path4 = __toESM(require("path"), 1);
141
364
 
142
365
  // src/logger.ts
143
- var import_node_fs = __toESM(require("fs"), 1);
144
- var import_node_path2 = __toESM(require("path"), 1);
145
- var import_node_crypto = require("crypto");
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 = import_node_fs.default.statSync(filePath);
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
- import_node_fs.default.unlinkSync(rotated);
384
+ import_node_fs2.default.unlinkSync(rotated);
160
385
  } catch {
161
386
  }
162
- import_node_fs.default.renameSync(filePath, rotated);
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
- import_node_fs.default.mkdirSync(import_node_path2.default.dirname(filePath), { recursive: true, mode: 448 });
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 = import_node_fs.default.openSync(filePath, "a");
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
- import_node_fs.default.writeSync(fd, "\n");
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
- import_node_fs.default.writeSync(fd, line);
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 === null) return;
218
- if (opts?.shutdownLine !== false) log("INFO", "shutdown", `${appName} shutting down`);
219
- try {
220
- import_node_fs.default.closeSync(fd);
221
- } catch {
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 import_node_path3.default.join(getAppPaths().agentDir, "claude-code-version.json");
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 CLIENT_ID = atob("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
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 = import_node_crypto2.default.randomBytes(16).toString("hex");
621
+ const state = import_node_crypto3.default.randomBytes(16).toString("hex");
364
622
  const params = new URLSearchParams({
365
623
  code: "true",
366
- client_id: 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: 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: 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 import_node_crypto3 = __toESM(require("crypto"), 1);
412
- var CLIENT_ID2 = "app_EMoamEEZ73f0CkXaXp7hrann";
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 = import_node_crypto3.default.randomBytes(16).toString("hex");
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", CLIENT_ID2);
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: CLIENT_ID2,
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: CLIENT_ID2
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 import_node_crypto4 = __toESM(require("crypto"), 1);
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 = import_node_crypto4.default.randomBytes(32).toString("hex");
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
- return {
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 requestDeviceAuthorization() {
1079
- const { status, data } = await postForm("/api/oauth/device_authorization", {
1080
- client_id: CLIENT_ID3
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 pollDeviceToken(deviceCode) {
1100
- const { status, data } = await postForm("/api/oauth/token", {
1101
- client_id: CLIENT_ID3,
1102
- device_code: deviceCode,
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 (status === 200 && typeof data.access_token === "string") {
1106
- return { kind: "success", creds: credsFromTokenResponse(data) };
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 sleep(ms) {
1126
- return new Promise((resolve) => {
1127
- setTimeout(resolve, ms);
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
- async function loginKimi(callbacks) {
1131
- const auth = await requestDeviceAuthorization();
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
- async function refreshKimiToken(refreshToken) {
1156
- const { status, data } = await postForm("/api/oauth/token", {
1157
- client_id: CLIENT_ID3,
1158
- grant_type: "refresh_token",
1159
- refresh_token: refreshToken
1160
- });
1161
- if (status === 200 && typeof data.access_token === "string") {
1162
- return credsFromTokenResponse(data, { fallbackRefreshToken: refreshToken });
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
- const errorCode = typeof data.error === "string" ? data.error : "";
1165
- throw new Error(`Kimi token refresh failed (${status}): ${errorCode || errorDetail(data)}`);
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
- return false;
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 (Rust → ~/.ezcoder/auth.json) without going through
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.ensureLoaded();
1349
- this.data[provider] = creds;
1350
- await this.save();
1442
+ await this.mutateLatest((latest) => {
1443
+ latest[provider] = creds;
1444
+ });
1351
1445
  }
1352
1446
  async clearCredentials(provider) {
1353
- await this.ensureLoaded();
1354
- delete this.data[provider];
1355
- await this.save();
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.data = {};
1359
- await this.save();
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, opts);
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
- try {
1405
- const content = await import_promises4.default.readFile(this.filePath, "utf-8");
1406
- const freshData = JSON.parse(content);
1407
- const freshCreds = freshData[provider];
1408
- if (freshCreds && !opts?.forceRefresh && Date.now() < freshCreds.expiresAt - REFRESH_SKEW_MS) {
1409
- this.data[provider] = freshCreds;
1410
- return freshCreds;
1411
- }
1412
- } catch {
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(creds.refreshToken);
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 this.data[provider];
1423
- await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));
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 && creds.accountId) {
1429
- refreshed.accountId = creds.accountId;
1569
+ if (!refreshed.accountId && latestCreds.accountId) {
1570
+ refreshed.accountId = latestCreds.accountId;
1430
1571
  }
1431
- if (!refreshed.projectId && creds.projectId) {
1432
- refreshed.projectId = creds.projectId;
1572
+ if (!refreshed.projectId && latestCreds.projectId) {
1573
+ refreshed.projectId = latestCreds.projectId;
1433
1574
  }
1434
- if (!refreshed.baseUrl && creds.baseUrl) {
1435
- refreshed.baseUrl = creds.baseUrl;
1575
+ if (!refreshed.baseUrl && latestCreds.baseUrl) {
1576
+ refreshed.baseUrl = latestCreds.baseUrl;
1436
1577
  }
1437
- this.data[provider] = refreshed;
1438
- await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));
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 372K on the ChatGPT OAuth route. All three take
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: 372e3,
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: 372e3,
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: 372e3,
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-k2.7-code");
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
- async function readUsageResponse(response) {
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 import_node_fs3 = __toESM(require("fs"), 1);
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 = import_node_fs3.default.readFileSync(stateFilePath(), "utf-8");
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
- import_node_fs3.default.mkdirSync(import_node_path5.default.dirname(filePath), { recursive: true, mode: 448 });
2490
- import_node_fs3.default.writeFileSync(filePath, JSON.stringify(state));
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,