@kenkaiiii/gg-core 5.20.5 → 5.22.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-QNR6SNB2.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,11 +247,11 @@ 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 "@kenkaiiii/gg-ai";
39
257
  var MAX_BYTES = 10 * 1024 * 1024;
@@ -62,7 +280,7 @@ function openLog(filePath, name) {
62
280
  appName = name;
63
281
  exactSecrets = environmentSecrets(process.env);
64
282
  try {
65
- fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 448 });
283
+ fs.mkdirSync(path2.dirname(filePath), { recursive: true, mode: 448 });
66
284
  } catch {
67
285
  }
68
286
  rotateIfNeeded(filePath);
@@ -161,7 +379,7 @@ var FALLBACK_VERSION = "2.1.88";
161
379
  var memoryCache = null;
162
380
  var inflight = null;
163
381
  function cachePath() {
164
- return path2.join(getAppPaths().agentDir, "claude-code-version.json");
382
+ return path3.join(getAppPaths().agentDir, "claude-code-version.json");
165
383
  }
166
384
  async function readDiskCache() {
167
385
  try {
@@ -243,7 +461,7 @@ async function getClaudeCliUserAgent() {
243
461
  }
244
462
 
245
463
  // src/oauth/anthropic.ts
246
- var CLIENT_ID = atob("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
464
+ var CLIENT_ID2 = atob("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
247
465
  var AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
248
466
  var TOKEN_URLS = [
249
467
  "https://platform.claude.com/v1/oauth/token",
@@ -290,7 +508,7 @@ async function loginAnthropic(callbacks) {
290
508
  const state = crypto2.randomBytes(16).toString("hex");
291
509
  const params = new URLSearchParams({
292
510
  code: "true",
293
- client_id: CLIENT_ID,
511
+ client_id: CLIENT_ID2,
294
512
  response_type: "code",
295
513
  redirect_uri: REDIRECT_URI,
296
514
  scope: SCOPES,
@@ -311,7 +529,7 @@ async function exchangeAnthropicCode(code, state, verifier) {
311
529
  const data = await postTokenRequest(
312
530
  {
313
531
  grant_type: "authorization_code",
314
- client_id: CLIENT_ID,
532
+ client_id: CLIENT_ID2,
315
533
  code,
316
534
  state,
317
535
  redirect_uri: REDIRECT_URI,
@@ -325,7 +543,7 @@ async function refreshAnthropicToken(refreshToken) {
325
543
  const data = await postTokenRequest(
326
544
  {
327
545
  grant_type: "refresh_token",
328
- client_id: CLIENT_ID,
546
+ client_id: CLIENT_ID2,
329
547
  refresh_token: refreshToken
330
548
  },
331
549
  "token refresh"
@@ -336,7 +554,7 @@ async function refreshAnthropicToken(refreshToken) {
336
554
  // src/oauth/openai.ts
337
555
  import http from "http";
338
556
  import crypto3 from "crypto";
339
- var CLIENT_ID2 = "app_EMoamEEZ73f0CkXaXp7hrann";
557
+ var CLIENT_ID3 = "app_EMoamEEZ73f0CkXaXp7hrann";
340
558
  var AUTHORIZE_URL2 = "https://auth.openai.com/oauth/authorize";
341
559
  var TOKEN_URL = "https://auth.openai.com/oauth/token";
342
560
  var REDIRECT_URI2 = "http://localhost:1455/auth/callback";
@@ -347,7 +565,7 @@ async function loginOpenAI(callbacks) {
347
565
  const state = crypto3.randomBytes(16).toString("hex");
348
566
  const url = new URL(AUTHORIZE_URL2);
349
567
  url.searchParams.set("response_type", "code");
350
- url.searchParams.set("client_id", CLIENT_ID2);
568
+ url.searchParams.set("client_id", CLIENT_ID3);
351
569
  url.searchParams.set("redirect_uri", REDIRECT_URI2);
352
570
  url.searchParams.set("scope", SCOPE);
353
571
  url.searchParams.set("code_challenge", challenge);
@@ -468,7 +686,7 @@ async function exchangeOpenAICode(code, verifier) {
468
686
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
469
687
  body: new URLSearchParams({
470
688
  grant_type: "authorization_code",
471
- client_id: CLIENT_ID2,
689
+ client_id: CLIENT_ID3,
472
690
  code,
473
691
  redirect_uri: REDIRECT_URI2,
474
692
  code_verifier: verifier
@@ -492,7 +710,7 @@ async function refreshOpenAIToken(refreshToken) {
492
710
  body: new URLSearchParams({
493
711
  grant_type: "refresh_token",
494
712
  refresh_token: refreshToken,
495
- client_id: CLIENT_ID2
713
+ client_id: CLIENT_ID3
496
714
  })
497
715
  });
498
716
  if (!response.ok) {
@@ -875,223 +1093,6 @@ function codeAssistHeaders(accessToken) {
875
1093
  };
876
1094
  }
877
1095
 
878
- // src/oauth/kimi.ts
879
- import { execFileSync } from "child_process";
880
- import { randomUUID } from "crypto";
881
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
882
- import { arch, hostname, release, type } from "os";
883
- import path3 from "path";
884
- var CLIENT_ID3 = "17e5f671-d194-4dfb-9706-5516cb48c098";
885
- var DEFAULT_OAUTH_HOST = "https://auth.kimi.com";
886
- var DEFAULT_CODING_BASE_URL = "https://api.kimi.com/coding/v1";
887
- var KIMI_PLATFORM = "kimi_code_cli";
888
- var DEFAULT_KIMI_VERSION = "1.0.11";
889
- var DEVICE_TIMEOUT_MS = 15 * 60 * 1e3;
890
- function oauthHost() {
891
- const host = process.env.KIMI_CODE_OAUTH_HOST ?? process.env.KIMI_OAUTH_HOST ?? DEFAULT_OAUTH_HOST;
892
- return host.replace(/\/+$/, "");
893
- }
894
- function kimiCodeBaseUrl() {
895
- return (process.env.KIMI_CODE_BASE_URL ?? DEFAULT_CODING_BASE_URL).replace(/\/+$/, "");
896
- }
897
- function kimiVersion() {
898
- const v = process.env.KIMI_CODE_VERSION ?? DEFAULT_KIMI_VERSION;
899
- return asciiHeader(v, DEFAULT_KIMI_VERSION);
900
- }
901
- function asciiHeader(value, fallback = "unknown") {
902
- const cleaned = value.replace(/[^\u0020-\u007E]/g, "").trim();
903
- return cleaned.length > 0 ? cleaned : fallback;
904
- }
905
- function macOsProductVersion() {
906
- try {
907
- const version = execFileSync("/usr/bin/sw_vers", ["-productVersion"], {
908
- encoding: "utf-8",
909
- timeout: 1e3
910
- }).trim();
911
- return version.length > 0 ? version : void 0;
912
- } catch {
913
- return void 0;
914
- }
915
- }
916
- function deviceModel() {
917
- const os = type();
918
- const version = release();
919
- const osArch = arch();
920
- if (os === "Darwin") return `macOS ${macOsProductVersion() ?? version} ${osArch}`;
921
- if (os === "Windows_NT") return `Windows ${version} ${osArch}`;
922
- return `${os} ${version} ${osArch}`.trim();
923
- }
924
- function deviceId() {
925
- const idPath = path3.join(getAppPaths().agentDir, "kimi_device_id");
926
- if (existsSync(idPath)) {
927
- try {
928
- const text = readFileSync(idPath, "utf-8").trim();
929
- if (text.length > 0) return text;
930
- } catch {
931
- }
932
- }
933
- const id = randomUUID();
934
- try {
935
- mkdirSync(getAppPaths().agentDir, { recursive: true, mode: 448 });
936
- writeFileSync(idPath, id, { encoding: "utf-8", mode: 384 });
937
- } catch {
938
- }
939
- return id;
940
- }
941
- function deviceHeaders() {
942
- return {
943
- "X-Msh-Platform": KIMI_PLATFORM,
944
- "X-Msh-Version": kimiVersion(),
945
- "X-Msh-Device-Name": asciiHeader(hostname()),
946
- "X-Msh-Device-Model": asciiHeader(deviceModel()),
947
- "X-Msh-Os-Version": asciiHeader(release()),
948
- "X-Msh-Device-Id": deviceId()
949
- };
950
- }
951
- function kimiCodingHeaders() {
952
- return {
953
- "User-Agent": `kimi-code-cli/${kimiVersion()}`,
954
- ...deviceHeaders()
955
- };
956
- }
957
- function isKimiCodingEndpoint(baseUrl) {
958
- if (typeof baseUrl !== "string" || baseUrl.length === 0) return false;
959
- const normalized = baseUrl.replace(/\/+$/, "");
960
- return normalized === kimiCodeBaseUrl() || /(^|\.)kimi\.com/i.test(normalized);
961
- }
962
- async function postForm(endpoint, params) {
963
- const response = await fetch(`${oauthHost()}${endpoint}`, {
964
- method: "POST",
965
- headers: {
966
- ...deviceHeaders(),
967
- "Content-Type": "application/x-www-form-urlencoded",
968
- Accept: "application/json"
969
- },
970
- body: new URLSearchParams(params).toString()
971
- });
972
- let data = {};
973
- try {
974
- const parsed = await response.json();
975
- if (parsed && typeof parsed === "object") data = parsed;
976
- } catch {
977
- }
978
- return { status: response.status, data };
979
- }
980
- function errorDetail(data) {
981
- const desc = data.error_description ?? data.message ?? data.error;
982
- return typeof desc === "string" && desc.length > 0 ? desc : "unknown error";
983
- }
984
- function credsFromTokenResponse(data, opts) {
985
- const accessToken = data.access_token;
986
- const responseRefreshToken = data.refresh_token;
987
- const expiresIn = Number(data.expires_in);
988
- if (typeof accessToken !== "string" || accessToken.length === 0) {
989
- throw new Error("Kimi OAuth response missing access_token.");
990
- }
991
- const refreshToken = typeof responseRefreshToken === "string" && responseRefreshToken.length > 0 ? responseRefreshToken : opts?.fallbackRefreshToken ?? "";
992
- if (refreshToken.length === 0) {
993
- throw new Error("Kimi OAuth response missing refresh_token.");
994
- }
995
- if (!Number.isFinite(expiresIn) || expiresIn <= 0) {
996
- throw new Error("Kimi OAuth response missing or invalid expires_in.");
997
- }
998
- return {
999
- accessToken,
1000
- refreshToken,
1001
- expiresAt: Date.now() + expiresIn * 1e3,
1002
- baseUrl: kimiCodeBaseUrl()
1003
- };
1004
- }
1005
- async function requestDeviceAuthorization() {
1006
- const { status, data } = await postForm("/api/oauth/device_authorization", {
1007
- client_id: CLIENT_ID3
1008
- });
1009
- if (status !== 200) {
1010
- throw new Error(`Kimi device authorization failed (${status}): ${errorDetail(data)}`);
1011
- }
1012
- const userCode = data.user_code;
1013
- const deviceCode = data.device_code;
1014
- const verificationUriComplete = data.verification_uri_complete;
1015
- if (typeof userCode !== "string" || typeof deviceCode !== "string") {
1016
- throw new Error("Kimi device authorization response missing user_code/device_code.");
1017
- }
1018
- return {
1019
- userCode,
1020
- deviceCode,
1021
- verificationUri: typeof data.verification_uri === "string" ? data.verification_uri : "",
1022
- verificationUriComplete: typeof verificationUriComplete === "string" ? verificationUriComplete : "",
1023
- interval: Number(data.interval ?? 5) || 5
1024
- };
1025
- }
1026
- async function pollDeviceToken(deviceCode) {
1027
- const { status, data } = await postForm("/api/oauth/token", {
1028
- client_id: CLIENT_ID3,
1029
- device_code: deviceCode,
1030
- grant_type: "urn:ietf:params:oauth:grant-type:device_code"
1031
- });
1032
- if (status === 200 && typeof data.access_token === "string") {
1033
- return { kind: "success", creds: credsFromTokenResponse(data) };
1034
- }
1035
- if (status >= 500) {
1036
- throw new Error(`Kimi token polling server error (${status}): ${errorDetail(data)}`);
1037
- }
1038
- const errorCode = typeof data.error === "string" ? data.error : "unknown_error";
1039
- switch (errorCode) {
1040
- case "authorization_pending":
1041
- return { kind: "pending" };
1042
- case "slow_down":
1043
- return { kind: "slow_down" };
1044
- case "expired_token":
1045
- return { kind: "expired" };
1046
- case "access_denied":
1047
- return { kind: "denied" };
1048
- default:
1049
- throw new Error(`Kimi token polling failed (${status}): ${errorDetail(data)}`);
1050
- }
1051
- }
1052
- function sleep(ms) {
1053
- return new Promise((resolve) => {
1054
- setTimeout(resolve, ms);
1055
- });
1056
- }
1057
- async function loginKimi(callbacks) {
1058
- const auth = await requestDeviceAuthorization();
1059
- callbacks.onStatus(
1060
- `Visit ${auth.verificationUri || auth.verificationUriComplete} and enter code: ${auth.userCode}`
1061
- );
1062
- callbacks.onOpenUrl(auth.verificationUriComplete || auth.verificationUri);
1063
- callbacks.onStatus("Waiting for you to authorize in the browser...");
1064
- const deadline = Date.now() + DEVICE_TIMEOUT_MS;
1065
- let interval = Math.max(auth.interval, 1);
1066
- while (Date.now() < deadline) {
1067
- await sleep(interval * 1e3);
1068
- const result = await pollDeviceToken(auth.deviceCode);
1069
- if (result.kind === "success") return result.creds;
1070
- if (result.kind === "denied") {
1071
- throw new Error("Kimi authorization was denied.");
1072
- }
1073
- if (result.kind === "expired") {
1074
- throw new Error("Kimi device code expired. Please run login again.");
1075
- }
1076
- if (result.kind === "slow_down") {
1077
- interval += 5;
1078
- }
1079
- }
1080
- throw new Error("Kimi login timed out. Please run login again.");
1081
- }
1082
- async function refreshKimiToken(refreshToken) {
1083
- const { status, data } = await postForm("/api/oauth/token", {
1084
- client_id: CLIENT_ID3,
1085
- grant_type: "refresh_token",
1086
- refresh_token: refreshToken
1087
- });
1088
- if (status === 200 && typeof data.access_token === "string") {
1089
- return credsFromTokenResponse(data, { fallbackRefreshToken: refreshToken });
1090
- }
1091
- const errorCode = typeof data.error === "string" ? data.error : "";
1092
- throw new Error(`Kimi token refresh failed (${status}): ${errorCode || errorDetail(data)}`);
1093
- }
1094
-
1095
1096
  // src/file-lock.ts
1096
1097
  import fs3 from "fs/promises";
1097
1098
  import { setTimeout as setTimeout2 } from "timers/promises";
@@ -1157,6 +1158,26 @@ function isAlive(pid) {
1157
1158
  // src/auth-storage.ts
1158
1159
  var MOONSHOT_OAUTH_KEY = "moonshot-oauth";
1159
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
+ }
1160
1181
  var REFRESH_SKEW_MS = 6e4;
1161
1182
  var USAGE_EXHAUSTED_DEFAULT_MS = 15 * 60 * 1e3;
1162
1183
  var STATIC_API_KEY_PROVIDERS = /* @__PURE__ */ new Set([
@@ -1232,6 +1253,16 @@ var AuthStorage = class {
1232
1253
  }
1233
1254
  return STATIC_API_KEY_PROVIDERS.has(provider);
1234
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
+ }
1235
1266
  async load() {
1236
1267
  await withFileLock(this.filePath, async () => {
1237
1268
  try {
@@ -1260,19 +1291,40 @@ var AuthStorage = class {
1260
1291
  async ensureLoaded() {
1261
1292
  if (!this.loaded) await this.load();
1262
1293
  }
1294
+ /**
1295
+ * Apply one provider-scoped mutation to the latest on-disk snapshot.
1296
+ * AuthStorage instances live in every app session/process, so writing this
1297
+ * instance's cached snapshot can erase credentials another instance just
1298
+ * added. The file lock only serializes writers; the re-read prevents stale
1299
+ * full-file overwrites.
1300
+ */
1301
+ async mutateLatest(mutator) {
1302
+ await this.ensureLoaded();
1303
+ await withFileLock(this.filePath, async () => {
1304
+ const latest = await readAuthData(this.filePath);
1305
+ mutator(latest);
1306
+ await atomicWriteFile(this.filePath, JSON.stringify(latest, null, 2));
1307
+ this.data = latest;
1308
+ });
1309
+ }
1310
+ async reloadLatest() {
1311
+ await withFileLock(this.filePath, async () => {
1312
+ this.data = await readAuthData(this.filePath);
1313
+ });
1314
+ }
1263
1315
  async getCredentials(provider) {
1264
1316
  await this.ensureLoaded();
1265
1317
  return this.data[provider];
1266
1318
  }
1267
1319
  async setCredentials(provider, creds) {
1268
- await this.ensureLoaded();
1269
- this.data[provider] = creds;
1270
- await this.save();
1320
+ await this.mutateLatest((latest) => {
1321
+ latest[provider] = creds;
1322
+ });
1271
1323
  }
1272
1324
  async clearCredentials(provider) {
1273
- await this.ensureLoaded();
1274
- delete this.data[provider];
1275
- await this.save();
1325
+ await this.mutateLatest((latest) => {
1326
+ delete latest[provider];
1327
+ });
1276
1328
  }
1277
1329
  /**
1278
1330
  * Mark the credential stored under `storageKey` as usage-exhausted until
@@ -1286,12 +1338,15 @@ var AuthStorage = class {
1286
1338
  * nothing is stored under `storageKey`.
1287
1339
  */
1288
1340
  async markUsageExhausted(storageKey, resetsAt) {
1289
- await this.ensureLoaded();
1290
- const creds = this.data[storageKey];
1291
- if (!creds) return;
1292
1341
  const until = resetsAt !== void 0 && resetsAt * 1e3 > Date.now() ? resetsAt * 1e3 : Date.now() + USAGE_EXHAUSTED_DEFAULT_MS;
1293
- creds.usageExhaustedUntil = until;
1294
- await this.save();
1342
+ let marked = false;
1343
+ await this.mutateLatest((latest) => {
1344
+ const creds = latest[storageKey];
1345
+ if (!creds) return;
1346
+ creds.usageExhaustedUntil = until;
1347
+ marked = true;
1348
+ });
1349
+ if (!marked) return;
1295
1350
  log(
1296
1351
  "WARN",
1297
1352
  "auth",
@@ -1299,8 +1354,11 @@ var AuthStorage = class {
1299
1354
  );
1300
1355
  }
1301
1356
  async clearAll() {
1302
- this.data = {};
1303
- await this.save();
1357
+ await this.ensureLoaded();
1358
+ await withFileLock(this.filePath, async () => {
1359
+ this.data = {};
1360
+ await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));
1361
+ });
1304
1362
  }
1305
1363
  /**
1306
1364
  * Returns valid credentials, auto-refreshing if expired.
@@ -1310,6 +1368,10 @@ var AuthStorage = class {
1310
1368
  */
1311
1369
  async resolveCredentials(provider, opts) {
1312
1370
  await this.ensureLoaded();
1371
+ const directStorageKeys = opts?.storageKeys && !(opts.storageKeys.length === 1 && opts.storageKeys[0] === provider) ? opts.storageKeys : provider === "moonshot" ? [MOONSHOT_OAUTH_KEY, "moonshot"] : [provider];
1372
+ if (!directStorageKeys.some((key) => Boolean(this.data[key]))) {
1373
+ await this.reloadLatest();
1374
+ }
1313
1375
  if (opts?.storageKeys && !(opts.storageKeys.length === 1 && opts.storageKeys[0] === provider)) {
1314
1376
  for (const key of opts.storageKeys) {
1315
1377
  const creds2 = this.data[key];
@@ -1356,41 +1418,44 @@ var AuthStorage = class {
1356
1418
  const existing = this.refreshLocks.get(provider);
1357
1419
  if (existing) return existing;
1358
1420
  const refreshPromise = withFileLock(this.filePath, async () => {
1359
- try {
1360
- const content = await fs4.readFile(this.filePath, "utf-8");
1361
- const freshData = JSON.parse(content);
1362
- const freshCreds = freshData[provider];
1363
- if (freshCreds && !opts?.forceRefresh && Date.now() < freshCreds.expiresAt - REFRESH_SKEW_MS) {
1364
- this.data[provider] = freshCreds;
1365
- return freshCreds;
1366
- }
1367
- } catch {
1421
+ const latest = await readAuthData(this.filePath);
1422
+ const latestCreds = latest[provider];
1423
+ if (!latestCreds) {
1424
+ this.data = latest;
1425
+ throw new NotLoggedInError(provider);
1426
+ }
1427
+ const credentialWasReplaced = latestCreds.accessToken !== creds.accessToken || latestCreds.refreshToken !== creds.refreshToken || latestCreds.expiresAt !== creds.expiresAt;
1428
+ if (credentialWasReplaced || !opts?.forceRefresh && Date.now() < latestCreds.expiresAt - REFRESH_SKEW_MS) {
1429
+ this.data = latest;
1430
+ return latestCreds;
1368
1431
  }
1369
1432
  const refreshFn = provider === "anthropic" ? refreshAnthropicToken : provider === "gemini" ? refreshGeminiToken : provider === MOONSHOT_OAUTH_KEY ? refreshKimiToken : refreshOpenAIToken;
1370
1433
  let refreshed;
1371
1434
  try {
1372
- refreshed = await refreshFn(creds.refreshToken);
1435
+ refreshed = await refreshFn(latestCreds.refreshToken);
1373
1436
  } catch (err) {
1374
1437
  const msg = err instanceof Error ? err.message : String(err);
1375
1438
  const isAuthFailure = /\((401|400)\)/.test(msg) || /invalid_grant|invalid_token|invalid.*refresh/i.test(msg) || /unauthorized/i.test(msg);
1376
1439
  if (isAuthFailure) {
1377
- delete this.data[provider];
1378
- await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));
1440
+ delete latest[provider];
1441
+ this.data = latest;
1442
+ await atomicWriteFile(this.filePath, JSON.stringify(latest, null, 2));
1379
1443
  throw new NotLoggedInError(provider);
1380
1444
  }
1381
1445
  throw err;
1382
1446
  }
1383
- if (!refreshed.accountId && creds.accountId) {
1384
- refreshed.accountId = creds.accountId;
1447
+ if (!refreshed.accountId && latestCreds.accountId) {
1448
+ refreshed.accountId = latestCreds.accountId;
1385
1449
  }
1386
- if (!refreshed.projectId && creds.projectId) {
1387
- refreshed.projectId = creds.projectId;
1450
+ if (!refreshed.projectId && latestCreds.projectId) {
1451
+ refreshed.projectId = latestCreds.projectId;
1388
1452
  }
1389
- if (!refreshed.baseUrl && creds.baseUrl) {
1390
- refreshed.baseUrl = creds.baseUrl;
1453
+ if (!refreshed.baseUrl && latestCreds.baseUrl) {
1454
+ refreshed.baseUrl = latestCreds.baseUrl;
1391
1455
  }
1392
- this.data[provider] = refreshed;
1393
- await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));
1456
+ latest[provider] = refreshed;
1457
+ this.data = latest;
1458
+ await atomicWriteFile(this.filePath, JSON.stringify(latest, null, 2));
1394
1459
  return refreshed;
1395
1460
  });
1396
1461
  this.refreshLocks.set(provider, refreshPromise);
@@ -1408,12 +1473,16 @@ var AuthStorage = class {
1408
1473
  const creds = await this.resolveCredentials(provider);
1409
1474
  return creds.accessToken;
1410
1475
  }
1411
- async save() {
1412
- await withFileLock(this.filePath, async () => {
1413
- await atomicWriteFile(this.filePath, JSON.stringify(this.data, null, 2));
1414
- });
1415
- }
1416
1476
  };
1477
+ async function readAuthData(filePath) {
1478
+ try {
1479
+ const content = await fs4.readFile(filePath, "utf-8");
1480
+ return JSON.parse(content);
1481
+ } catch (error) {
1482
+ if (error.code === "ENOENT") return {};
1483
+ throw error;
1484
+ }
1485
+ }
1417
1486
  async function atomicWriteFile(filePath, content) {
1418
1487
  const tmpPath = `${filePath}.${process.pid}.${Date.now()}.${crypto5.randomUUID().slice(0, 8)}.tmp`;
1419
1488
  try {
@@ -1668,8 +1737,9 @@ var MODELS = [
1668
1737
  },
1669
1738
  // ── Moonshot (Kimi) ────────────────────────────────────
1670
1739
  // K3 is Kimi's 2.8T-parameter flagship for long-horizon coding, knowledge
1671
- // work, and deep reasoning. It always reasons at the `max` effort; the public
1672
- // API uses `reasoning_effort`, while Kimi Code OAuth keeps its managed wire shape.
1740
+ // work, and deep reasoning. Its effort ladder is server-declared as
1741
+ // low/high/max on both the public API (default max) and the Kimi For Coding
1742
+ // OAuth endpoint (default high); thinking can also be fully disabled.
1673
1743
  {
1674
1744
  id: "kimi-k3",
1675
1745
  name: "Kimi K3",
@@ -1903,6 +1973,11 @@ function getContextWindow(modelId, options) {
1903
1973
  function getMaxThinkingLevel(modelId) {
1904
1974
  return getModel(modelId)?.maxThinkingLevel ?? "high";
1905
1975
  }
1976
+ function getDefaultThinkingLevel(modelId, options) {
1977
+ const model = getModel(modelId);
1978
+ if (model?.id === "kimi-k3" && isKimiCodingEndpoint(options?.baseUrl)) return "high";
1979
+ return model?.maxThinkingLevel ?? "high";
1980
+ }
1906
1981
  function getSummaryModel(provider, currentModelId) {
1907
1982
  if (provider === "anthropic") {
1908
1983
  return MODELS.find((m) => m.id === "claude-sonnet-5");
@@ -1919,6 +1994,11 @@ function getFastModel(provider, currentModelId) {
1919
1994
  }
1920
1995
 
1921
1996
  export {
1997
+ kimiCodeBaseUrl,
1998
+ kimiCodingHeaders,
1999
+ isKimiCodingEndpoint,
2000
+ loginKimi,
2001
+ refreshKimiToken,
1922
2002
  generatePKCE,
1923
2003
  openLog,
1924
2004
  getSessionId,
@@ -1934,14 +2014,10 @@ export {
1934
2014
  refreshOpenAIToken,
1935
2015
  loginGemini,
1936
2016
  refreshGeminiToken,
1937
- kimiCodeBaseUrl,
1938
- kimiCodingHeaders,
1939
- isKimiCodingEndpoint,
1940
- loginKimi,
1941
- refreshKimiToken,
1942
2017
  withFileLock,
1943
2018
  MOONSHOT_OAUTH_KEY,
1944
2019
  XIAOMI_CREDITS_KEY,
2020
+ readStoredBaseUrlSync,
1945
2021
  AuthStorage,
1946
2022
  NotLoggedInError,
1947
2023
  MODELS,
@@ -1956,7 +2032,8 @@ export {
1956
2032
  getToolResultCharLimit,
1957
2033
  getContextWindow,
1958
2034
  getMaxThinkingLevel,
2035
+ getDefaultThinkingLevel,
1959
2036
  getSummaryModel,
1960
2037
  getFastModel
1961
2038
  };
1962
- //# sourceMappingURL=chunk-GMBEO4JX.js.map
2039
+ //# sourceMappingURL=chunk-TST5LJWL.js.map