@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.
@@ -2,8 +2,226 @@ import {
2
2
  getAppPaths
3
3
  } from "./chunk-WCIV25KV.js";
4
4
 
5
+ // src/oauth/kimi.ts
6
+ import { execFileSync } from "child_process";
7
+ import { randomUUID } from "crypto";
8
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
9
+ import { arch, hostname, release, type } from "os";
10
+ import path from "path";
11
+ var CLIENT_ID = "17e5f671-d194-4dfb-9706-5516cb48c098";
12
+ var DEFAULT_OAUTH_HOST = "https://auth.kimi.com";
13
+ var DEFAULT_CODING_BASE_URL = "https://api.kimi.com/coding/v1";
14
+ var KIMI_PLATFORM = "kimi_code_cli";
15
+ var DEFAULT_KIMI_VERSION = "1.0.11";
16
+ var DEVICE_TIMEOUT_MS = 15 * 60 * 1e3;
17
+ function oauthHost() {
18
+ const host = process.env.KIMI_CODE_OAUTH_HOST ?? process.env.KIMI_OAUTH_HOST ?? DEFAULT_OAUTH_HOST;
19
+ return host.replace(/\/+$/, "");
20
+ }
21
+ function kimiCodeBaseUrl() {
22
+ return (process.env.KIMI_CODE_BASE_URL ?? DEFAULT_CODING_BASE_URL).replace(/\/+$/, "");
23
+ }
24
+ function kimiVersion() {
25
+ const v = process.env.KIMI_CODE_VERSION ?? DEFAULT_KIMI_VERSION;
26
+ return asciiHeader(v, DEFAULT_KIMI_VERSION);
27
+ }
28
+ function asciiHeader(value, fallback = "unknown") {
29
+ const cleaned = value.replace(/[^\u0020-\u007E]/g, "").trim();
30
+ return cleaned.length > 0 ? cleaned : fallback;
31
+ }
32
+ function macOsProductVersion() {
33
+ try {
34
+ const version = execFileSync("/usr/bin/sw_vers", ["-productVersion"], {
35
+ encoding: "utf-8",
36
+ timeout: 1e3
37
+ }).trim();
38
+ return version.length > 0 ? version : void 0;
39
+ } catch {
40
+ return void 0;
41
+ }
42
+ }
43
+ function deviceModel() {
44
+ const os = type();
45
+ const version = release();
46
+ const osArch = arch();
47
+ if (os === "Darwin") return `macOS ${macOsProductVersion() ?? version} ${osArch}`;
48
+ if (os === "Windows_NT") return `Windows ${version} ${osArch}`;
49
+ return `${os} ${version} ${osArch}`.trim();
50
+ }
51
+ function deviceId() {
52
+ const idPath = path.join(getAppPaths().agentDir, "kimi_device_id");
53
+ if (existsSync(idPath)) {
54
+ try {
55
+ const text = readFileSync(idPath, "utf-8").trim();
56
+ if (text.length > 0) return text;
57
+ } catch {
58
+ }
59
+ }
60
+ const id = randomUUID();
61
+ try {
62
+ mkdirSync(getAppPaths().agentDir, { recursive: true, mode: 448 });
63
+ writeFileSync(idPath, id, { encoding: "utf-8", mode: 384 });
64
+ } catch {
65
+ }
66
+ return id;
67
+ }
68
+ function deviceHeaders() {
69
+ return {
70
+ "X-Msh-Platform": KIMI_PLATFORM,
71
+ "X-Msh-Version": kimiVersion(),
72
+ "X-Msh-Device-Name": asciiHeader(hostname()),
73
+ "X-Msh-Device-Model": asciiHeader(deviceModel()),
74
+ "X-Msh-Os-Version": asciiHeader(release()),
75
+ "X-Msh-Device-Id": deviceId()
76
+ };
77
+ }
78
+ function kimiCodingHeaders() {
79
+ return {
80
+ "User-Agent": `kimi-code-cli/${kimiVersion()}`,
81
+ ...deviceHeaders()
82
+ };
83
+ }
84
+ function isKimiCodingEndpoint(baseUrl) {
85
+ if (typeof baseUrl !== "string" || baseUrl.length === 0) return false;
86
+ const normalized = baseUrl.replace(/\/+$/, "");
87
+ return normalized === kimiCodeBaseUrl() || /(^|\.)kimi\.com/i.test(normalized);
88
+ }
89
+ async function postForm(endpoint, params) {
90
+ const response = await fetch(`${oauthHost()}${endpoint}`, {
91
+ method: "POST",
92
+ headers: {
93
+ ...deviceHeaders(),
94
+ "Content-Type": "application/x-www-form-urlencoded",
95
+ Accept: "application/json"
96
+ },
97
+ body: new URLSearchParams(params).toString()
98
+ });
99
+ let data = {};
100
+ try {
101
+ const parsed = await response.json();
102
+ if (parsed && typeof parsed === "object") data = parsed;
103
+ } catch {
104
+ }
105
+ return { status: response.status, data };
106
+ }
107
+ function errorDetail(data) {
108
+ const desc = data.error_description ?? data.message ?? data.error;
109
+ return typeof desc === "string" && desc.length > 0 ? desc : "unknown error";
110
+ }
111
+ function credsFromTokenResponse(data, opts) {
112
+ const accessToken = data.access_token;
113
+ const responseRefreshToken = data.refresh_token;
114
+ const expiresIn = Number(data.expires_in);
115
+ if (typeof accessToken !== "string" || accessToken.length === 0) {
116
+ throw new Error("Kimi OAuth response missing access_token.");
117
+ }
118
+ const refreshToken = typeof responseRefreshToken === "string" && responseRefreshToken.length > 0 ? responseRefreshToken : opts?.fallbackRefreshToken ?? "";
119
+ if (refreshToken.length === 0) {
120
+ throw new Error("Kimi OAuth response missing refresh_token.");
121
+ }
122
+ if (!Number.isFinite(expiresIn) || expiresIn <= 0) {
123
+ throw new Error("Kimi OAuth response missing or invalid expires_in.");
124
+ }
125
+ return {
126
+ accessToken,
127
+ refreshToken,
128
+ expiresAt: Date.now() + expiresIn * 1e3,
129
+ baseUrl: kimiCodeBaseUrl()
130
+ };
131
+ }
132
+ async function requestDeviceAuthorization() {
133
+ const { status, data } = await postForm("/api/oauth/device_authorization", {
134
+ client_id: CLIENT_ID
135
+ });
136
+ if (status !== 200) {
137
+ throw new Error(`Kimi device authorization failed (${status}): ${errorDetail(data)}`);
138
+ }
139
+ const userCode = data.user_code;
140
+ const deviceCode = data.device_code;
141
+ const verificationUriComplete = data.verification_uri_complete;
142
+ if (typeof userCode !== "string" || typeof deviceCode !== "string") {
143
+ throw new Error("Kimi device authorization response missing user_code/device_code.");
144
+ }
145
+ return {
146
+ userCode,
147
+ deviceCode,
148
+ verificationUri: typeof data.verification_uri === "string" ? data.verification_uri : "",
149
+ verificationUriComplete: typeof verificationUriComplete === "string" ? verificationUriComplete : "",
150
+ interval: Number(data.interval ?? 5) || 5
151
+ };
152
+ }
153
+ async function pollDeviceToken(deviceCode) {
154
+ const { status, data } = await postForm("/api/oauth/token", {
155
+ client_id: CLIENT_ID,
156
+ device_code: deviceCode,
157
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code"
158
+ });
159
+ if (status === 200 && typeof data.access_token === "string") {
160
+ return { kind: "success", creds: credsFromTokenResponse(data) };
161
+ }
162
+ if (status >= 500) {
163
+ throw new Error(`Kimi token polling server error (${status}): ${errorDetail(data)}`);
164
+ }
165
+ const errorCode = typeof data.error === "string" ? data.error : "unknown_error";
166
+ switch (errorCode) {
167
+ case "authorization_pending":
168
+ return { kind: "pending" };
169
+ case "slow_down":
170
+ return { kind: "slow_down" };
171
+ case "expired_token":
172
+ return { kind: "expired" };
173
+ case "access_denied":
174
+ return { kind: "denied" };
175
+ default:
176
+ throw new Error(`Kimi token polling failed (${status}): ${errorDetail(data)}`);
177
+ }
178
+ }
179
+ function sleep(ms) {
180
+ return new Promise((resolve) => {
181
+ setTimeout(resolve, ms);
182
+ });
183
+ }
184
+ async function loginKimi(callbacks) {
185
+ const auth = await requestDeviceAuthorization();
186
+ callbacks.onStatus(
187
+ `Visit ${auth.verificationUri || auth.verificationUriComplete} and enter code: ${auth.userCode}`
188
+ );
189
+ callbacks.onOpenUrl(auth.verificationUriComplete || auth.verificationUri);
190
+ callbacks.onStatus("Waiting for you to authorize in the browser...");
191
+ const deadline = Date.now() + DEVICE_TIMEOUT_MS;
192
+ let interval = Math.max(auth.interval, 1);
193
+ while (Date.now() < deadline) {
194
+ await sleep(interval * 1e3);
195
+ const result = await pollDeviceToken(auth.deviceCode);
196
+ if (result.kind === "success") return result.creds;
197
+ if (result.kind === "denied") {
198
+ throw new Error("Kimi authorization was denied.");
199
+ }
200
+ if (result.kind === "expired") {
201
+ throw new Error("Kimi device code expired. Please run login again.");
202
+ }
203
+ if (result.kind === "slow_down") {
204
+ interval += 5;
205
+ }
206
+ }
207
+ throw new Error("Kimi login timed out. Please run login again.");
208
+ }
209
+ async function refreshKimiToken(refreshToken) {
210
+ const { status, data } = await postForm("/api/oauth/token", {
211
+ client_id: CLIENT_ID,
212
+ grant_type: "refresh_token",
213
+ refresh_token: refreshToken
214
+ });
215
+ if (status === 200 && typeof data.access_token === "string") {
216
+ return credsFromTokenResponse(data, { fallbackRefreshToken: refreshToken });
217
+ }
218
+ const errorCode = typeof data.error === "string" ? data.error : "";
219
+ throw new Error(`Kimi token refresh failed (${status}): ${errorCode || errorDetail(data)}`);
220
+ }
221
+
5
222
  // src/auth-storage.ts
6
223
  import fs4 from "fs/promises";
224
+ import { readFileSync as readFileSync2 } from "fs";
7
225
  import crypto5 from "crypto";
8
226
 
9
227
  // src/oauth/anthropic.ts
@@ -29,15 +247,17 @@ async function generatePKCE() {
29
247
 
30
248
  // src/claude-code-version.ts
31
249
  import fs2 from "fs/promises";
32
- import path2 from "path";
250
+ import path3 from "path";
33
251
 
34
252
  // src/logger.ts
35
253
  import fs from "fs";
36
- import path from "path";
254
+ import path2 from "path";
37
255
  import { randomBytes } from "crypto";
38
256
  import { environmentSecrets, redactText, redactValue } from "@prestyj/ai";
39
257
  var MAX_BYTES = 10 * 1024 * 1024;
40
258
  var fd = null;
259
+ var bytesWritten = 0;
260
+ var capped = false;
41
261
  var sessionId = "";
42
262
  var appName = "app";
43
263
  var cleanups = [];
@@ -56,22 +276,37 @@ function rotateIfNeeded(filePath) {
56
276
  }
57
277
  }
58
278
  function openLog(filePath, name) {
59
- if (fd !== null) return false;
279
+ if (fd !== null || capped) return false;
60
280
  appName = name;
61
281
  exactSecrets = environmentSecrets(process.env);
62
282
  try {
63
- fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 448 });
283
+ fs.mkdirSync(path2.dirname(filePath), { recursive: true, mode: 448 });
64
284
  } catch {
65
285
  }
66
286
  rotateIfNeeded(filePath);
67
287
  try {
68
288
  fd = fs.openSync(filePath, "a");
69
289
  } catch {
290
+ fd = null;
291
+ bytesWritten = 0;
292
+ return false;
293
+ }
294
+ try {
295
+ bytesWritten = fs.fstatSync(fd).size;
296
+ } catch {
297
+ try {
298
+ fs.closeSync(fd);
299
+ } catch {
300
+ }
301
+ fd = null;
302
+ bytesWritten = 0;
70
303
  return false;
71
304
  }
72
305
  sessionId = randomBytes(4).toString("hex");
73
306
  try {
74
- fs.writeSync(fd, "\n");
307
+ if (bytesWritten < MAX_BYTES) {
308
+ bytesWritten += fs.writeSync(fd, "\n");
309
+ }
75
310
  } catch {
76
311
  }
77
312
  return true;
@@ -97,8 +332,23 @@ function log(level, category, message, data) {
97
332
  if (pairs) line += ` ${pairs}`;
98
333
  }
99
334
  line += "\n";
335
+ const lineBytes = Buffer.byteLength(line);
336
+ if (bytesWritten + lineBytes > MAX_BYTES) {
337
+ const capLine = `[${ts}] [sid=${sessionId}] [WARN] [logger] Log cap reached; file logging disabled until restart
338
+ `;
339
+ try {
340
+ if (bytesWritten + Buffer.byteLength(capLine) <= MAX_BYTES) {
341
+ bytesWritten += fs.writeSync(fd, capLine);
342
+ }
343
+ fs.closeSync(fd);
344
+ } catch {
345
+ }
346
+ fd = null;
347
+ capped = true;
348
+ return;
349
+ }
100
350
  try {
101
- fs.writeSync(fd, line);
351
+ bytesWritten += fs.writeSync(fd, line);
102
352
  } catch {
103
353
  }
104
354
  }
@@ -106,13 +356,16 @@ function registerLogCleanup(fn) {
106
356
  cleanups.push(fn);
107
357
  }
108
358
  function closeLogger(opts) {
109
- if (fd === null) return;
110
- if (opts?.shutdownLine !== false) log("INFO", "shutdown", `${appName} shutting down`);
111
- try {
112
- fs.closeSync(fd);
113
- } catch {
359
+ if (fd !== null) {
360
+ if (opts?.shutdownLine !== false) log("INFO", "shutdown", `${appName} shutting down`);
361
+ try {
362
+ if (fd !== null) fs.closeSync(fd);
363
+ } catch {
364
+ }
114
365
  }
115
366
  fd = null;
367
+ bytesWritten = 0;
368
+ capped = false;
116
369
  exactSecrets = [];
117
370
  for (const unsub of cleanups) unsub();
118
371
  cleanups = [];
@@ -126,7 +379,7 @@ var FALLBACK_VERSION = "2.1.88";
126
379
  var memoryCache = null;
127
380
  var inflight = null;
128
381
  function cachePath() {
129
- return path2.join(getAppPaths().agentDir, "claude-code-version.json");
382
+ return path3.join(getAppPaths().agentDir, "claude-code-version.json");
130
383
  }
131
384
  async function readDiskCache() {
132
385
  try {
@@ -208,7 +461,7 @@ async function getClaudeCliUserAgent() {
208
461
  }
209
462
 
210
463
  // src/oauth/anthropic.ts
211
- var CLIENT_ID = atob("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
464
+ var CLIENT_ID2 = atob("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
212
465
  var AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
213
466
  var TOKEN_URLS = [
214
467
  "https://platform.claude.com/v1/oauth/token",
@@ -255,7 +508,7 @@ async function loginAnthropic(callbacks) {
255
508
  const state = crypto2.randomBytes(16).toString("hex");
256
509
  const params = new URLSearchParams({
257
510
  code: "true",
258
- client_id: CLIENT_ID,
511
+ client_id: CLIENT_ID2,
259
512
  response_type: "code",
260
513
  redirect_uri: REDIRECT_URI,
261
514
  scope: SCOPES,
@@ -276,7 +529,7 @@ async function exchangeAnthropicCode(code, state, verifier) {
276
529
  const data = await postTokenRequest(
277
530
  {
278
531
  grant_type: "authorization_code",
279
- client_id: CLIENT_ID,
532
+ client_id: CLIENT_ID2,
280
533
  code,
281
534
  state,
282
535
  redirect_uri: REDIRECT_URI,
@@ -290,7 +543,7 @@ async function refreshAnthropicToken(refreshToken) {
290
543
  const data = await postTokenRequest(
291
544
  {
292
545
  grant_type: "refresh_token",
293
- client_id: CLIENT_ID,
546
+ client_id: CLIENT_ID2,
294
547
  refresh_token: refreshToken
295
548
  },
296
549
  "token refresh"
@@ -301,7 +554,7 @@ async function refreshAnthropicToken(refreshToken) {
301
554
  // src/oauth/openai.ts
302
555
  import http from "http";
303
556
  import crypto3 from "crypto";
304
- var CLIENT_ID2 = "app_EMoamEEZ73f0CkXaXp7hrann";
557
+ var CLIENT_ID3 = "app_EMoamEEZ73f0CkXaXp7hrann";
305
558
  var AUTHORIZE_URL2 = "https://auth.openai.com/oauth/authorize";
306
559
  var TOKEN_URL = "https://auth.openai.com/oauth/token";
307
560
  var REDIRECT_URI2 = "http://localhost:1455/auth/callback";
@@ -312,7 +565,7 @@ async function loginOpenAI(callbacks) {
312
565
  const state = crypto3.randomBytes(16).toString("hex");
313
566
  const url = new URL(AUTHORIZE_URL2);
314
567
  url.searchParams.set("response_type", "code");
315
- url.searchParams.set("client_id", CLIENT_ID2);
568
+ url.searchParams.set("client_id", CLIENT_ID3);
316
569
  url.searchParams.set("redirect_uri", REDIRECT_URI2);
317
570
  url.searchParams.set("scope", SCOPE);
318
571
  url.searchParams.set("code_challenge", challenge);
@@ -433,7 +686,7 @@ async function exchangeOpenAICode(code, verifier) {
433
686
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
434
687
  body: new URLSearchParams({
435
688
  grant_type: "authorization_code",
436
- client_id: CLIENT_ID2,
689
+ client_id: CLIENT_ID3,
437
690
  code,
438
691
  redirect_uri: REDIRECT_URI2,
439
692
  code_verifier: verifier
@@ -457,7 +710,7 @@ async function refreshOpenAIToken(refreshToken) {
457
710
  body: new URLSearchParams({
458
711
  grant_type: "refresh_token",
459
712
  refresh_token: refreshToken,
460
- client_id: CLIENT_ID2
713
+ client_id: CLIENT_ID3
461
714
  })
462
715
  });
463
716
  if (!response.ok) {
@@ -840,223 +1093,6 @@ function codeAssistHeaders(accessToken) {
840
1093
  };
841
1094
  }
842
1095
 
843
- // src/oauth/kimi.ts
844
- import { execFileSync } from "child_process";
845
- import { randomUUID } from "crypto";
846
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
847
- import { arch, hostname, release, type } from "os";
848
- import path3 from "path";
849
- var CLIENT_ID3 = "17e5f671-d194-4dfb-9706-5516cb48c098";
850
- var DEFAULT_OAUTH_HOST = "https://auth.kimi.com";
851
- var DEFAULT_CODING_BASE_URL = "https://api.kimi.com/coding/v1";
852
- var KIMI_PLATFORM = "kimi_code_cli";
853
- var DEFAULT_KIMI_VERSION = "1.0.11";
854
- var DEVICE_TIMEOUT_MS = 15 * 60 * 1e3;
855
- function oauthHost() {
856
- const host = process.env.KIMI_CODE_OAUTH_HOST ?? process.env.KIMI_OAUTH_HOST ?? DEFAULT_OAUTH_HOST;
857
- return host.replace(/\/+$/, "");
858
- }
859
- function kimiCodeBaseUrl() {
860
- return (process.env.KIMI_CODE_BASE_URL ?? DEFAULT_CODING_BASE_URL).replace(/\/+$/, "");
861
- }
862
- function kimiVersion() {
863
- const v = process.env.KIMI_CODE_VERSION ?? DEFAULT_KIMI_VERSION;
864
- return asciiHeader(v, DEFAULT_KIMI_VERSION);
865
- }
866
- function asciiHeader(value, fallback = "unknown") {
867
- const cleaned = value.replace(/[^\u0020-\u007E]/g, "").trim();
868
- return cleaned.length > 0 ? cleaned : fallback;
869
- }
870
- function macOsProductVersion() {
871
- try {
872
- const version = execFileSync("/usr/bin/sw_vers", ["-productVersion"], {
873
- encoding: "utf-8",
874
- timeout: 1e3
875
- }).trim();
876
- return version.length > 0 ? version : void 0;
877
- } catch {
878
- return void 0;
879
- }
880
- }
881
- function deviceModel() {
882
- const os = type();
883
- const version = release();
884
- const osArch = arch();
885
- if (os === "Darwin") return `macOS ${macOsProductVersion() ?? version} ${osArch}`;
886
- if (os === "Windows_NT") return `Windows ${version} ${osArch}`;
887
- return `${os} ${version} ${osArch}`.trim();
888
- }
889
- function deviceId() {
890
- const idPath = path3.join(getAppPaths().agentDir, "kimi_device_id");
891
- if (existsSync(idPath)) {
892
- try {
893
- const text = readFileSync(idPath, "utf-8").trim();
894
- if (text.length > 0) return text;
895
- } catch {
896
- }
897
- }
898
- const id = randomUUID();
899
- try {
900
- mkdirSync(getAppPaths().agentDir, { recursive: true, mode: 448 });
901
- writeFileSync(idPath, id, { encoding: "utf-8", mode: 384 });
902
- } catch {
903
- }
904
- return id;
905
- }
906
- function deviceHeaders() {
907
- return {
908
- "X-Msh-Platform": KIMI_PLATFORM,
909
- "X-Msh-Version": kimiVersion(),
910
- "X-Msh-Device-Name": asciiHeader(hostname()),
911
- "X-Msh-Device-Model": asciiHeader(deviceModel()),
912
- "X-Msh-Os-Version": asciiHeader(release()),
913
- "X-Msh-Device-Id": deviceId()
914
- };
915
- }
916
- function kimiCodingHeaders() {
917
- return {
918
- "User-Agent": `kimi-code-cli/${kimiVersion()}`,
919
- ...deviceHeaders()
920
- };
921
- }
922
- function isKimiCodingEndpoint(baseUrl) {
923
- if (typeof baseUrl !== "string" || baseUrl.length === 0) return false;
924
- const normalized = baseUrl.replace(/\/+$/, "");
925
- return normalized === kimiCodeBaseUrl() || /(^|\.)kimi\.com/i.test(normalized);
926
- }
927
- async function postForm(endpoint, params) {
928
- const response = await fetch(`${oauthHost()}${endpoint}`, {
929
- method: "POST",
930
- headers: {
931
- ...deviceHeaders(),
932
- "Content-Type": "application/x-www-form-urlencoded",
933
- Accept: "application/json"
934
- },
935
- body: new URLSearchParams(params).toString()
936
- });
937
- let data = {};
938
- try {
939
- const parsed = await response.json();
940
- if (parsed && typeof parsed === "object") data = parsed;
941
- } catch {
942
- }
943
- return { status: response.status, data };
944
- }
945
- function errorDetail(data) {
946
- const desc = data.error_description ?? data.message ?? data.error;
947
- return typeof desc === "string" && desc.length > 0 ? desc : "unknown error";
948
- }
949
- function credsFromTokenResponse(data, opts) {
950
- const accessToken = data.access_token;
951
- const responseRefreshToken = data.refresh_token;
952
- const expiresIn = Number(data.expires_in);
953
- if (typeof accessToken !== "string" || accessToken.length === 0) {
954
- throw new Error("Kimi OAuth response missing access_token.");
955
- }
956
- const refreshToken = typeof responseRefreshToken === "string" && responseRefreshToken.length > 0 ? responseRefreshToken : opts?.fallbackRefreshToken ?? "";
957
- if (refreshToken.length === 0) {
958
- throw new Error("Kimi OAuth response missing refresh_token.");
959
- }
960
- if (!Number.isFinite(expiresIn) || expiresIn <= 0) {
961
- throw new Error("Kimi OAuth response missing or invalid expires_in.");
962
- }
963
- return {
964
- accessToken,
965
- refreshToken,
966
- expiresAt: Date.now() + expiresIn * 1e3,
967
- baseUrl: kimiCodeBaseUrl()
968
- };
969
- }
970
- async function requestDeviceAuthorization() {
971
- const { status, data } = await postForm("/api/oauth/device_authorization", {
972
- client_id: CLIENT_ID3
973
- });
974
- if (status !== 200) {
975
- throw new Error(`Kimi device authorization failed (${status}): ${errorDetail(data)}`);
976
- }
977
- const userCode = data.user_code;
978
- const deviceCode = data.device_code;
979
- const verificationUriComplete = data.verification_uri_complete;
980
- if (typeof userCode !== "string" || typeof deviceCode !== "string") {
981
- throw new Error("Kimi device authorization response missing user_code/device_code.");
982
- }
983
- return {
984
- userCode,
985
- deviceCode,
986
- verificationUri: typeof data.verification_uri === "string" ? data.verification_uri : "",
987
- verificationUriComplete: typeof verificationUriComplete === "string" ? verificationUriComplete : "",
988
- interval: Number(data.interval ?? 5) || 5
989
- };
990
- }
991
- async function pollDeviceToken(deviceCode) {
992
- const { status, data } = await postForm("/api/oauth/token", {
993
- client_id: CLIENT_ID3,
994
- device_code: deviceCode,
995
- grant_type: "urn:ietf:params:oauth:grant-type:device_code"
996
- });
997
- if (status === 200 && typeof data.access_token === "string") {
998
- return { kind: "success", creds: credsFromTokenResponse(data) };
999
- }
1000
- if (status >= 500) {
1001
- throw new Error(`Kimi token polling server error (${status}): ${errorDetail(data)}`);
1002
- }
1003
- const errorCode = typeof data.error === "string" ? data.error : "unknown_error";
1004
- switch (errorCode) {
1005
- case "authorization_pending":
1006
- return { kind: "pending" };
1007
- case "slow_down":
1008
- return { kind: "slow_down" };
1009
- case "expired_token":
1010
- return { kind: "expired" };
1011
- case "access_denied":
1012
- return { kind: "denied" };
1013
- default:
1014
- throw new Error(`Kimi token polling failed (${status}): ${errorDetail(data)}`);
1015
- }
1016
- }
1017
- function sleep(ms) {
1018
- return new Promise((resolve) => {
1019
- setTimeout(resolve, ms);
1020
- });
1021
- }
1022
- async function loginKimi(callbacks) {
1023
- const auth = await requestDeviceAuthorization();
1024
- callbacks.onStatus(
1025
- `Visit ${auth.verificationUri || auth.verificationUriComplete} and enter code: ${auth.userCode}`
1026
- );
1027
- callbacks.onOpenUrl(auth.verificationUriComplete || auth.verificationUri);
1028
- callbacks.onStatus("Waiting for you to authorize in the browser...");
1029
- const deadline = Date.now() + DEVICE_TIMEOUT_MS;
1030
- let interval = Math.max(auth.interval, 1);
1031
- while (Date.now() < deadline) {
1032
- await sleep(interval * 1e3);
1033
- const result = await pollDeviceToken(auth.deviceCode);
1034
- if (result.kind === "success") return result.creds;
1035
- if (result.kind === "denied") {
1036
- throw new Error("Kimi authorization was denied.");
1037
- }
1038
- if (result.kind === "expired") {
1039
- throw new Error("Kimi device code expired. Please run login again.");
1040
- }
1041
- if (result.kind === "slow_down") {
1042
- interval += 5;
1043
- }
1044
- }
1045
- throw new Error("Kimi login timed out. Please run login again.");
1046
- }
1047
- async function refreshKimiToken(refreshToken) {
1048
- const { status, data } = await postForm("/api/oauth/token", {
1049
- client_id: CLIENT_ID3,
1050
- grant_type: "refresh_token",
1051
- refresh_token: refreshToken
1052
- });
1053
- if (status === 200 && typeof data.access_token === "string") {
1054
- return credsFromTokenResponse(data, { fallbackRefreshToken: refreshToken });
1055
- }
1056
- const errorCode = typeof data.error === "string" ? data.error : "";
1057
- throw new Error(`Kimi token refresh failed (${status}): ${errorCode || errorDetail(data)}`);
1058
- }
1059
-
1060
1096
  // src/file-lock.ts
1061
1097
  import fs3 from "fs/promises";
1062
1098
  import { setTimeout as setTimeout2 } from "timers/promises";
@@ -1122,7 +1158,28 @@ function isAlive(pid) {
1122
1158
  // src/auth-storage.ts
1123
1159
  var MOONSHOT_OAUTH_KEY = "moonshot-oauth";
1124
1160
  var XIAOMI_CREDITS_KEY = "xiaomi-credits";
1161
+ function activeBaseUrlEntry(data, provider) {
1162
+ if (provider === "moonshot") {
1163
+ const oauth = data[MOONSHOT_OAUTH_KEY];
1164
+ if (oauth) {
1165
+ const exhaustedUntil = oauth.usageExhaustedUntil ?? 0;
1166
+ if (Date.now() < exhaustedUntil && data["moonshot"]) return data["moonshot"];
1167
+ return oauth;
1168
+ }
1169
+ return data["moonshot"];
1170
+ }
1171
+ return data[provider];
1172
+ }
1173
+ function readStoredBaseUrlSync(authFile, provider) {
1174
+ try {
1175
+ const data = JSON.parse(readFileSync2(authFile, "utf-8"));
1176
+ return activeBaseUrlEntry(data, provider)?.baseUrl;
1177
+ } catch {
1178
+ return void 0;
1179
+ }
1180
+ }
1125
1181
  var REFRESH_SKEW_MS = 6e4;
1182
+ var USAGE_EXHAUSTED_DEFAULT_MS = 15 * 60 * 1e3;
1126
1183
  var STATIC_API_KEY_PROVIDERS = /* @__PURE__ */ new Set([
1127
1184
  "glm",
1128
1185
  "moonshot",
@@ -1130,7 +1187,8 @@ var STATIC_API_KEY_PROVIDERS = /* @__PURE__ */ new Set([
1130
1187
  "minimax",
1131
1188
  "deepseek",
1132
1189
  "openrouter",
1133
- "sakana"
1190
+ "sakana",
1191
+ "xai"
1134
1192
  ]);
1135
1193
  var AuthStorage = class {
1136
1194
  data = {};
@@ -1189,10 +1247,22 @@ var AuthStorage = class {
1189
1247
  async isStaticApiKey(provider) {
1190
1248
  await this.ensureLoaded();
1191
1249
  if (provider === "moonshot" && this.data[MOONSHOT_OAUTH_KEY]) {
1192
- return false;
1250
+ const exhaustedUntil = this.data[MOONSHOT_OAUTH_KEY].usageExhaustedUntil ?? 0;
1251
+ const apiKeyActive = Date.now() < exhaustedUntil && Boolean(this.data["moonshot"]);
1252
+ if (!apiKeyActive) return false;
1193
1253
  }
1194
1254
  return STATIC_API_KEY_PROVIDERS.has(provider);
1195
1255
  }
1256
+ /**
1257
+ * The base URL on the credential that is active right now, if any.
1258
+ * Synchronous — call only after load()/resolveCredentials() populated the
1259
+ * snapshot. For `moonshot` this is the Kimi For Coding URL whenever the
1260
+ * OAuth entry is the one resolveCredentials would serve (i.e. not currently
1261
+ * usage-exhausted with an API key configured).
1262
+ */
1263
+ getStoredBaseUrl(provider) {
1264
+ return activeBaseUrlEntry(this.data, provider)?.baseUrl;
1265
+ }
1196
1266
  async load() {
1197
1267
  await withFileLock(this.filePath, async () => {
1198
1268
  try {
@@ -1224,31 +1294,80 @@ var AuthStorage = class {
1224
1294
  /**
1225
1295
  * Force a re-read from disk, discarding the in-memory cache. Needed when
1226
1296
  * another process mutates the auth file out-of-band — e.g. the desktop app
1227
- * writes API keys natively (Rust → ~/.ezcoder/auth.json) without going through
1228
- * this instance, so a long-lived daemon's cache would otherwise stay stale and
1229
- * never see a newly added provider key.
1297
+ * writes API keys natively without going through this instance.
1230
1298
  */
1231
1299
  async reload() {
1232
1300
  this.loaded = false;
1233
1301
  await this.load();
1234
1302
  }
1303
+ /**
1304
+ * Apply one provider-scoped mutation to the latest on-disk snapshot.
1305
+ * AuthStorage instances live in every app session/process, so writing this
1306
+ * instance's cached snapshot can erase credentials another instance just
1307
+ * added. The file lock only serializes writers; the re-read prevents stale
1308
+ * full-file overwrites.
1309
+ */
1310
+ async mutateLatest(mutator) {
1311
+ await this.ensureLoaded();
1312
+ await withFileLock(this.filePath, async () => {
1313
+ const latest = await readAuthData(this.filePath);
1314
+ mutator(latest);
1315
+ await atomicWriteFile(this.filePath, JSON.stringify(latest, null, 2));
1316
+ this.data = latest;
1317
+ });
1318
+ }
1319
+ async reloadLatest() {
1320
+ await withFileLock(this.filePath, async () => {
1321
+ this.data = await readAuthData(this.filePath);
1322
+ });
1323
+ }
1235
1324
  async getCredentials(provider) {
1236
1325
  await this.ensureLoaded();
1237
1326
  return this.data[provider];
1238
1327
  }
1239
1328
  async setCredentials(provider, creds) {
1240
- await this.ensureLoaded();
1241
- this.data[provider] = creds;
1242
- await this.save();
1329
+ await this.mutateLatest((latest) => {
1330
+ latest[provider] = creds;
1331
+ });
1243
1332
  }
1244
1333
  async clearCredentials(provider) {
1245
- await this.ensureLoaded();
1246
- delete this.data[provider];
1247
- await this.save();
1334
+ await this.mutateLatest((latest) => {
1335
+ delete latest[provider];
1336
+ });
1337
+ }
1338
+ /**
1339
+ * Mark the credential stored under `storageKey` as usage-exhausted until
1340
+ * `resetsAt` (unix SECONDS, from the provider's rate-limit response) or a
1341
+ * 15-minute default when no reset time is known. While the mark is in the
1342
+ * future, `resolveCredentials("moonshot")` serves the Moonshot API key
1343
+ * instead of the Kimi OAuth credential (when both are configured) — OAuth
1344
+ * stays the preferred credential and is retried automatically once the mark
1345
+ * lapses. Persisted to auth.json so a restart (or another ezcoder-app window)
1346
+ * doesn't burn a request rediscovering the same exhausted window. No-op if
1347
+ * nothing is stored under `storageKey`.
1348
+ */
1349
+ async markUsageExhausted(storageKey, resetsAt) {
1350
+ const until = resetsAt !== void 0 && resetsAt * 1e3 > Date.now() ? resetsAt * 1e3 : Date.now() + USAGE_EXHAUSTED_DEFAULT_MS;
1351
+ let marked = false;
1352
+ await this.mutateLatest((latest) => {
1353
+ const creds = latest[storageKey];
1354
+ if (!creds) return;
1355
+ creds.usageExhaustedUntil = until;
1356
+ marked = true;
1357
+ });
1358
+ if (!marked) return;
1359
+ log(
1360
+ "WARN",
1361
+ "auth",
1362
+ `Marked ${storageKey} usage-exhausted until ${new Date(until).toISOString()}`
1363
+ );
1248
1364
  }
1249
1365
  async clearAll() {
1250
- this.data = {};
1251
- await this.save();
1366
+ await this.ensureLoaded();
1367
+ await withFileLock(this.filePath, async () => {
1368
+ this.data = {};
1369
+ await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));
1370
+ });
1252
1371
  }
1253
1372
  /**
1254
1373
  * Returns valid credentials, auto-refreshing if expired.
@@ -1258,6 +1377,10 @@ var AuthStorage = class {
1258
1377
  */
1259
1378
  async resolveCredentials(provider, opts) {
1260
1379
  await this.ensureLoaded();
1380
+ const directStorageKeys = opts?.storageKeys && !(opts.storageKeys.length === 1 && opts.storageKeys[0] === provider) ? opts.storageKeys : provider === "moonshot" ? [MOONSHOT_OAUTH_KEY, "moonshot"] : [provider];
1381
+ if (!directStorageKeys.some((key) => Boolean(this.data[key]))) {
1382
+ await this.reloadLatest();
1383
+ }
1261
1384
  if (opts?.storageKeys && !(opts.storageKeys.length === 1 && opts.storageKeys[0] === provider)) {
1262
1385
  for (const key of opts.storageKeys) {
1263
1386
  const creds2 = this.data[key];
@@ -1266,8 +1389,19 @@ var AuthStorage = class {
1266
1389
  throw new NotLoggedInError(provider);
1267
1390
  }
1268
1391
  if (provider === "moonshot" && this.data[MOONSHOT_OAUTH_KEY]) {
1392
+ const exhaustedUntil = this.data[MOONSHOT_OAUTH_KEY].usageExhaustedUntil ?? 0;
1393
+ if (Date.now() < exhaustedUntil && this.data["moonshot"]) {
1394
+ log(
1395
+ "WARN",
1396
+ "auth",
1397
+ `Kimi OAuth usage window is exhausted \u2014 using the Moonshot API key until ${new Date(exhaustedUntil).toISOString()} (OAuth resumes automatically).`
1398
+ );
1399
+ return this.data["moonshot"];
1400
+ }
1269
1401
  try {
1270
- return await this.resolveCredentials(MOONSHOT_OAUTH_KEY, opts);
1402
+ return await this.resolveCredentials(MOONSHOT_OAUTH_KEY, {
1403
+ ...opts?.forceRefresh ? { forceRefresh: true } : {}
1404
+ });
1271
1405
  } catch (err) {
1272
1406
  if (err instanceof NotLoggedInError && this.data["moonshot"]) {
1273
1407
  log(
@@ -1293,41 +1427,44 @@ var AuthStorage = class {
1293
1427
  const existing = this.refreshLocks.get(provider);
1294
1428
  if (existing) return existing;
1295
1429
  const refreshPromise = withFileLock(this.filePath, async () => {
1296
- try {
1297
- const content = await fs4.readFile(this.filePath, "utf-8");
1298
- const freshData = JSON.parse(content);
1299
- const freshCreds = freshData[provider];
1300
- if (freshCreds && !opts?.forceRefresh && Date.now() < freshCreds.expiresAt - REFRESH_SKEW_MS) {
1301
- this.data[provider] = freshCreds;
1302
- return freshCreds;
1303
- }
1304
- } catch {
1430
+ const latest = await readAuthData(this.filePath);
1431
+ const latestCreds = latest[provider];
1432
+ if (!latestCreds) {
1433
+ this.data = latest;
1434
+ throw new NotLoggedInError(provider);
1435
+ }
1436
+ const credentialWasReplaced = latestCreds.accessToken !== creds.accessToken || latestCreds.refreshToken !== creds.refreshToken || latestCreds.expiresAt !== creds.expiresAt;
1437
+ if (credentialWasReplaced || !opts?.forceRefresh && Date.now() < latestCreds.expiresAt - REFRESH_SKEW_MS) {
1438
+ this.data = latest;
1439
+ return latestCreds;
1305
1440
  }
1306
1441
  const refreshFn = provider === "anthropic" ? refreshAnthropicToken : provider === "gemini" ? refreshGeminiToken : provider === MOONSHOT_OAUTH_KEY ? refreshKimiToken : refreshOpenAIToken;
1307
1442
  let refreshed;
1308
1443
  try {
1309
- refreshed = await refreshFn(creds.refreshToken);
1444
+ refreshed = await refreshFn(latestCreds.refreshToken);
1310
1445
  } catch (err) {
1311
1446
  const msg = err instanceof Error ? err.message : String(err);
1312
1447
  const isAuthFailure = /\((401|400)\)/.test(msg) || /invalid_grant|invalid_token|invalid.*refresh/i.test(msg) || /unauthorized/i.test(msg);
1313
1448
  if (isAuthFailure) {
1314
- delete this.data[provider];
1315
- await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));
1449
+ delete latest[provider];
1450
+ this.data = latest;
1451
+ await atomicWriteFile(this.filePath, JSON.stringify(latest, null, 2));
1316
1452
  throw new NotLoggedInError(provider);
1317
1453
  }
1318
1454
  throw err;
1319
1455
  }
1320
- if (!refreshed.accountId && creds.accountId) {
1321
- refreshed.accountId = creds.accountId;
1456
+ if (!refreshed.accountId && latestCreds.accountId) {
1457
+ refreshed.accountId = latestCreds.accountId;
1322
1458
  }
1323
- if (!refreshed.projectId && creds.projectId) {
1324
- refreshed.projectId = creds.projectId;
1459
+ if (!refreshed.projectId && latestCreds.projectId) {
1460
+ refreshed.projectId = latestCreds.projectId;
1325
1461
  }
1326
- if (!refreshed.baseUrl && creds.baseUrl) {
1327
- refreshed.baseUrl = creds.baseUrl;
1462
+ if (!refreshed.baseUrl && latestCreds.baseUrl) {
1463
+ refreshed.baseUrl = latestCreds.baseUrl;
1328
1464
  }
1329
- this.data[provider] = refreshed;
1330
- await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));
1465
+ latest[provider] = refreshed;
1466
+ this.data = latest;
1467
+ await atomicWriteFile(this.filePath, JSON.stringify(latest, null, 2));
1331
1468
  return refreshed;
1332
1469
  });
1333
1470
  this.refreshLocks.set(provider, refreshPromise);
@@ -1345,12 +1482,16 @@ var AuthStorage = class {
1345
1482
  const creds = await this.resolveCredentials(provider);
1346
1483
  return creds.accessToken;
1347
1484
  }
1348
- async save() {
1349
- await withFileLock(this.filePath, async () => {
1350
- await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));
1351
- });
1352
- }
1353
1485
  };
1486
+ async function readAuthData(filePath) {
1487
+ try {
1488
+ const content = await fs4.readFile(filePath, "utf-8");
1489
+ return JSON.parse(content);
1490
+ } catch (error) {
1491
+ if (error.code === "ENOENT") return {};
1492
+ throw error;
1493
+ }
1494
+ }
1354
1495
  async function atomicWriteFile(filePath, content) {
1355
1496
  const tmpPath = `${filePath}.${process.pid}.${Date.now()}.${crypto5.randomUUID().slice(0, 8)}.tmp`;
1356
1497
  try {
@@ -1443,7 +1584,8 @@ var MODELS = [
1443
1584
  // ── OpenAI (Codex) ─────────────────────────────────────
1444
1585
  // GPT-5.6 family — three agentic coding tiers launched July 2026. The public
1445
1586
  // Responses API advertises a 1.05M context window; OpenAI's Codex product
1446
- // catalog advertises 372K on the ChatGPT OAuth route. All three take
1587
+ // catalog advertises 272K on the ChatGPT OAuth route (corrected from the
1588
+ // initially advertised 372K — openai/codex PR #33972, Jul 18 2026 hotfix). All three take
1447
1589
  // text+image input, freeform apply_patch, text+image web search, and parallel
1448
1590
  // tool calls.
1449
1591
  {
@@ -1455,7 +1597,7 @@ var MODELS = [
1455
1597
  name: "GPT-5.6 Sol",
1456
1598
  provider: "openai",
1457
1599
  contextWindow: 105e4,
1458
- codexContextWindow: 372e3,
1600
+ codexContextWindow: 272e3,
1459
1601
  maxOutputTokens: 128e3,
1460
1602
  supportsThinking: true,
1461
1603
  supportsImages: true,
@@ -1470,7 +1612,7 @@ var MODELS = [
1470
1612
  name: "GPT-5.6 Terra",
1471
1613
  provider: "openai",
1472
1614
  contextWindow: 105e4,
1473
- codexContextWindow: 372e3,
1615
+ codexContextWindow: 272e3,
1474
1616
  maxOutputTokens: 128e3,
1475
1617
  supportsThinking: true,
1476
1618
  supportsImages: true,
@@ -1485,7 +1627,7 @@ var MODELS = [
1485
1627
  name: "GPT-5.6 Luna",
1486
1628
  provider: "openai",
1487
1629
  contextWindow: 105e4,
1488
- codexContextWindow: 372e3,
1630
+ codexContextWindow: 272e3,
1489
1631
  maxOutputTokens: 128e3,
1490
1632
  supportsThinking: true,
1491
1633
  supportsImages: true,
@@ -1536,6 +1678,26 @@ var MODELS = [
1536
1678
  costTier: "high",
1537
1679
  maxThinkingLevel: "xhigh"
1538
1680
  },
1681
+ // ── xAI (Grok) ─────────────────────────────────────────
1682
+ // Grok 4.5 (released 2026-07-08) is xAI's flagship for coding, agentic
1683
+ // tasks, and knowledge work — 500K context, text+image input, configurable
1684
+ // `reasoning_effort` (low/medium/high, server default high; reasoning can't
1685
+ // be fully disabled). Served over the OpenAI-compatible API at
1686
+ // https://api.x.ai/v1 (API key from console.x.ai). xAI hasn't published an
1687
+ // official max-output cap for 4.5; 131K matches the Grok Responses ceiling
1688
+ // third-party integrations use.
1689
+ {
1690
+ id: "grok-4.5",
1691
+ name: "Grok 4.5",
1692
+ provider: "xai",
1693
+ contextWindow: 5e5,
1694
+ maxOutputTokens: 131072,
1695
+ supportsThinking: true,
1696
+ supportsImages: true,
1697
+ supportsVideo: false,
1698
+ costTier: "medium",
1699
+ maxThinkingLevel: "high"
1700
+ },
1539
1701
  // ── Gemini ─────────────────────────────────────────────
1540
1702
  {
1541
1703
  id: "gemini-3.1-flash-lite",
@@ -1583,9 +1745,29 @@ var MODELS = [
1583
1745
  maxThinkingLevel: "high"
1584
1746
  },
1585
1747
  // ── Moonshot (Kimi) ────────────────────────────────────
1748
+ // K3 is Kimi's 2.8T-parameter flagship for long-horizon coding, knowledge
1749
+ // work, and deep reasoning. Its effort ladder is server-declared as
1750
+ // low/high/max on both the public API (default max) and the Kimi For Coding
1751
+ // OAuth endpoint (default high); thinking can also be fully disabled.
1752
+ {
1753
+ id: "kimi-k3",
1754
+ name: "Kimi K3",
1755
+ provider: "moonshot",
1756
+ contextWindow: 1048576,
1757
+ // The API can be raised as high as the full context window, but 131K is the
1758
+ // documented default and keeps room for input in AgentSession's fixed cap.
1759
+ maxOutputTokens: 131072,
1760
+ supportsThinking: true,
1761
+ supportsImages: true,
1762
+ supportsVideo: true,
1763
+ maxVideoBytes: 100 * 1024 * 1024,
1764
+ costTier: "high",
1765
+ maxThinkingLevel: "max"
1766
+ },
1767
+ // Retain the cheaper dedicated coding model as an explicit alternative.
1586
1768
  {
1587
1769
  id: "kimi-k2.7-code",
1588
- name: "Kimi K2.7",
1770
+ name: "Kimi K2.7 Code",
1589
1771
  provider: "moonshot",
1590
1772
  contextWindow: 262144,
1591
1773
  maxOutputTokens: 262144,
@@ -1775,16 +1957,20 @@ function getDefaultModel(provider) {
1775
1957
  if (provider === "openai") return MODELS.find((m) => m.id === "gpt-5.6-sol");
1776
1958
  if (provider === "gemini") return MODELS.find((m) => m.id === "gemini-3.1-flash-lite");
1777
1959
  if (provider === "glm") return MODELS.find((m) => m.id === "glm-5.2");
1778
- if (provider === "moonshot") return MODELS.find((m) => m.id === "kimi-k2.7-code");
1960
+ if (provider === "moonshot") return MODELS.find((m) => m.id === "kimi-k3");
1779
1961
  if (provider === "minimax") return MODELS.find((m) => m.id === "MiniMax-M3");
1780
1962
  if (provider === "deepseek") return MODELS.find((m) => m.id === "deepseek-v4-pro");
1781
1963
  if (provider === "openrouter") return MODELS.find((m) => m.id === "qwen/qwen3.6-plus");
1782
1964
  if (provider === "sakana") return MODELS.find((m) => m.id === "fugu");
1965
+ if (provider === "xai") return MODELS.find((m) => m.id === "grok-4.5");
1783
1966
  return MODELS.find((m) => m.id === "claude-sonnet-5");
1784
1967
  }
1785
1968
  function usesOpenAICodexTransport(options) {
1786
1969
  return options?.provider === "openai" && Boolean(options.accountId);
1787
1970
  }
1971
+ function getToolResultCharLimit(_modelId, options) {
1972
+ return usesOpenAICodexTransport(options) ? 1e4 * 4 : void 0;
1973
+ }
1788
1974
  function getContextWindow(modelId, options) {
1789
1975
  const model = getModel(modelId);
1790
1976
  if (!model) return 2e5;
@@ -1796,6 +1982,11 @@ function getContextWindow(modelId, options) {
1796
1982
  function getMaxThinkingLevel(modelId) {
1797
1983
  return getModel(modelId)?.maxThinkingLevel ?? "high";
1798
1984
  }
1985
+ function getDefaultThinkingLevel(modelId, options) {
1986
+ const model = getModel(modelId);
1987
+ if (model?.id === "kimi-k3" && isKimiCodingEndpoint(options?.baseUrl)) return "high";
1988
+ return model?.maxThinkingLevel ?? "high";
1989
+ }
1799
1990
  function getSummaryModel(provider, currentModelId) {
1800
1991
  if (provider === "anthropic") {
1801
1992
  return MODELS.find((m) => m.id === "claude-sonnet-5");
@@ -1812,6 +2003,11 @@ function getFastModel(provider, currentModelId) {
1812
2003
  }
1813
2004
 
1814
2005
  export {
2006
+ kimiCodeBaseUrl,
2007
+ kimiCodingHeaders,
2008
+ isKimiCodingEndpoint,
2009
+ loginKimi,
2010
+ refreshKimiToken,
1815
2011
  generatePKCE,
1816
2012
  openLog,
1817
2013
  getSessionId,
@@ -1827,14 +2023,10 @@ export {
1827
2023
  refreshOpenAIToken,
1828
2024
  loginGemini,
1829
2025
  refreshGeminiToken,
1830
- kimiCodeBaseUrl,
1831
- kimiCodingHeaders,
1832
- isKimiCodingEndpoint,
1833
- loginKimi,
1834
- refreshKimiToken,
1835
2026
  withFileLock,
1836
2027
  MOONSHOT_OAUTH_KEY,
1837
2028
  XIAOMI_CREDITS_KEY,
2029
+ readStoredBaseUrlSync,
1838
2030
  AuthStorage,
1839
2031
  NotLoggedInError,
1840
2032
  MODELS,
@@ -1846,9 +2038,11 @@ export {
1846
2038
  getVideoByteLimit,
1847
2039
  getDefaultModel,
1848
2040
  usesOpenAICodexTransport,
2041
+ getToolResultCharLimit,
1849
2042
  getContextWindow,
1850
2043
  getMaxThinkingLevel,
2044
+ getDefaultThinkingLevel,
1851
2045
  getSummaryModel,
1852
2046
  getFastModel
1853
2047
  };
1854
- //# sourceMappingURL=chunk-RQADK6HE.js.map
2048
+ //# sourceMappingURL=chunk-JXPW4JKV.js.map