@dreb/ai 2.8.0 → 2.10.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/models.generated.d.ts +47 -35
- package/dist/models.generated.d.ts.map +1 -1
- package/dist/models.generated.js +44 -40
- package/dist/models.generated.js.map +1 -1
- package/dist/providers/openai-completions.d.ts.map +1 -1
- package/dist/providers/openai-completions.js +19 -0
- package/dist/providers/openai-completions.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/oauth/index.d.ts +2 -0
- package/dist/utils/oauth/index.d.ts.map +1 -1
- package/dist/utils/oauth/index.js +4 -0
- package/dist/utils/oauth/index.js.map +1 -1
- package/dist/utils/oauth/kimi-coding.d.ts +35 -0
- package/dist/utils/oauth/kimi-coding.d.ts.map +1 -0
- package/dist/utils/oauth/kimi-coding.js +416 -0
- package/dist/utils/oauth/kimi-coding.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kimi For Coding OAuth flow (device code)
|
|
3
|
+
*
|
|
4
|
+
* Authenticates against Moonshot's Kimi API (auth.kimi.com) with scope "kimi-code".
|
|
5
|
+
* Uses the device authorization grant flow to obtain access/refresh tokens,
|
|
6
|
+
* then discovers the user's model entitlement via the /models endpoint.
|
|
7
|
+
*/
|
|
8
|
+
import { execFileSync } from "node:child_process";
|
|
9
|
+
import * as fs from "node:fs";
|
|
10
|
+
import * as os from "node:os";
|
|
11
|
+
import * as path from "node:path";
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Constants
|
|
14
|
+
// ============================================================================
|
|
15
|
+
const KIMI_CLI_VERSION = "1.35.0";
|
|
16
|
+
const USER_AGENT = `KimiCLI/${KIMI_CLI_VERSION}`;
|
|
17
|
+
const OAUTH_HOST = "https://auth.kimi.com";
|
|
18
|
+
const OAUTH_DEVICE_AUTH_URL = `${OAUTH_HOST}/api/oauth/device_authorization`;
|
|
19
|
+
const OAUTH_TOKEN_URL = `${OAUTH_HOST}/api/oauth/token`;
|
|
20
|
+
const OAUTH_CLIENT_ID = "17e5f671-d194-4dfb-9706-5516cb48c098";
|
|
21
|
+
const OAUTH_SCOPE = "kimi-code";
|
|
22
|
+
const OAUTH_DEVICE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
|
|
23
|
+
const OAUTH_REFRESH_GRANT = "refresh_token";
|
|
24
|
+
const API_BASE_URL = "https://api.kimi.com/coding/v1";
|
|
25
|
+
const DEVICE_ID_PATH = path.join(os.homedir(), ".kimi", "device_id");
|
|
26
|
+
const MAX_REFRESH_RETRIES = 3;
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// Device ID
|
|
29
|
+
// ============================================================================
|
|
30
|
+
function generateDeviceId() {
|
|
31
|
+
// UUID v4 without dashes (hex only, 32 chars)
|
|
32
|
+
return "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".replace(/x/g, () => Math.floor(Math.random() * 16).toString(16));
|
|
33
|
+
}
|
|
34
|
+
function getDeviceId() {
|
|
35
|
+
try {
|
|
36
|
+
if (fs.existsSync(DEVICE_ID_PATH)) {
|
|
37
|
+
const id = fs.readFileSync(DEVICE_ID_PATH, "utf-8").trim();
|
|
38
|
+
if (/^[0-9a-f]{32}$/i.test(id)) {
|
|
39
|
+
return id;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Fall through to generate
|
|
45
|
+
}
|
|
46
|
+
const id = generateDeviceId();
|
|
47
|
+
try {
|
|
48
|
+
fs.mkdirSync(path.dirname(DEVICE_ID_PATH), { recursive: true });
|
|
49
|
+
fs.writeFileSync(DEVICE_ID_PATH, id, "utf-8");
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// If we can't persist, just use the generated ID for this session
|
|
53
|
+
}
|
|
54
|
+
return id;
|
|
55
|
+
}
|
|
56
|
+
// ============================================================================
|
|
57
|
+
// Header helpers
|
|
58
|
+
// ============================================================================
|
|
59
|
+
/**
|
|
60
|
+
* Strip non-ASCII characters from a string for use in HTTP header values.
|
|
61
|
+
*/
|
|
62
|
+
function asciiHeaderValue(value) {
|
|
63
|
+
return value.replace(/[^\x20-\x7E]/g, "");
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Determine the device model string, mirroring kimi-cli logic.
|
|
67
|
+
*/
|
|
68
|
+
function kimiDeviceModel() {
|
|
69
|
+
const platform = os.platform();
|
|
70
|
+
const machine = os.machine?.() || process.arch;
|
|
71
|
+
if (platform === "darwin") {
|
|
72
|
+
let version;
|
|
73
|
+
try {
|
|
74
|
+
version = execFileSync("sw_vers", ["-productVersion"], { encoding: "utf-8", timeout: 3000 }).trim();
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
version = os.release();
|
|
78
|
+
}
|
|
79
|
+
return `macOS ${version} ${machine}`;
|
|
80
|
+
}
|
|
81
|
+
if (platform === "win32") {
|
|
82
|
+
const release = os.release();
|
|
83
|
+
const buildNumber = Number.parseInt(release.split(".").pop() || "0", 10);
|
|
84
|
+
const label = buildNumber >= 22000 ? "11" : "10";
|
|
85
|
+
return `Windows ${label} ${machine}`;
|
|
86
|
+
}
|
|
87
|
+
// Linux and other
|
|
88
|
+
return `${os.type()} ${os.release()} ${machine}`;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Build the standard set of headers required on every Kimi API request.
|
|
92
|
+
*/
|
|
93
|
+
export function buildKimiHeaders() {
|
|
94
|
+
return {
|
|
95
|
+
"User-Agent": USER_AGENT,
|
|
96
|
+
"X-Msh-Platform": "kimi_cli",
|
|
97
|
+
"X-Msh-Version": KIMI_CLI_VERSION,
|
|
98
|
+
"X-Msh-Device-Name": asciiHeaderValue(os.hostname()),
|
|
99
|
+
"X-Msh-Device-Model": asciiHeaderValue(kimiDeviceModel()),
|
|
100
|
+
"X-Msh-Device-Id": getDeviceId(),
|
|
101
|
+
"X-Msh-Os-Version": asciiHeaderValue(os.version?.() || `${os.type()} ${os.release()}`),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
// ============================================================================
|
|
105
|
+
// Network helpers
|
|
106
|
+
// ============================================================================
|
|
107
|
+
async function fetchJson(url, init) {
|
|
108
|
+
const response = await fetch(url, init);
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
const text = await response.text();
|
|
111
|
+
throw new Error(`${response.status} ${response.statusText}: ${text}`);
|
|
112
|
+
}
|
|
113
|
+
return response.json();
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Sleep that can be interrupted by an AbortSignal.
|
|
117
|
+
*/
|
|
118
|
+
function abortableSleep(ms, signal) {
|
|
119
|
+
return new Promise((resolve, reject) => {
|
|
120
|
+
if (signal?.aborted) {
|
|
121
|
+
reject(new Error("Login cancelled"));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const timeout = setTimeout(resolve, ms);
|
|
125
|
+
signal?.addEventListener("abort", () => {
|
|
126
|
+
clearTimeout(timeout);
|
|
127
|
+
reject(new Error("Login cancelled"));
|
|
128
|
+
}, { once: true });
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
// ============================================================================
|
|
132
|
+
// Model discovery
|
|
133
|
+
// ============================================================================
|
|
134
|
+
/**
|
|
135
|
+
* List available models from the Kimi API.
|
|
136
|
+
* Returns the model info array from the response's `data` field.
|
|
137
|
+
*/
|
|
138
|
+
export async function listModels(accessToken) {
|
|
139
|
+
const raw = await fetchJson(`${API_BASE_URL}/models`, {
|
|
140
|
+
headers: {
|
|
141
|
+
Authorization: `Bearer ${accessToken}`,
|
|
142
|
+
...buildKimiHeaders(),
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
if (!raw || typeof raw !== "object") {
|
|
146
|
+
throw new Error("Invalid models response");
|
|
147
|
+
}
|
|
148
|
+
const data = raw.data;
|
|
149
|
+
if (!Array.isArray(data)) {
|
|
150
|
+
throw new Error("Invalid models response: expected data array");
|
|
151
|
+
}
|
|
152
|
+
return data;
|
|
153
|
+
}
|
|
154
|
+
// ============================================================================
|
|
155
|
+
// Device flow
|
|
156
|
+
// ============================================================================
|
|
157
|
+
async function startDeviceFlow() {
|
|
158
|
+
const data = await fetchJson(OAUTH_DEVICE_AUTH_URL, {
|
|
159
|
+
method: "POST",
|
|
160
|
+
headers: {
|
|
161
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
162
|
+
...buildKimiHeaders(),
|
|
163
|
+
},
|
|
164
|
+
body: new URLSearchParams({
|
|
165
|
+
client_id: OAUTH_CLIENT_ID,
|
|
166
|
+
scope: OAUTH_SCOPE,
|
|
167
|
+
}),
|
|
168
|
+
});
|
|
169
|
+
if (!data || typeof data !== "object") {
|
|
170
|
+
throw new Error("Invalid device code response");
|
|
171
|
+
}
|
|
172
|
+
const d = data;
|
|
173
|
+
const device_code = d.device_code;
|
|
174
|
+
const user_code = d.user_code;
|
|
175
|
+
const verification_uri = d.verification_uri;
|
|
176
|
+
const interval = d.interval;
|
|
177
|
+
const expires_in = d.expires_in;
|
|
178
|
+
if (typeof device_code !== "string" ||
|
|
179
|
+
typeof user_code !== "string" ||
|
|
180
|
+
typeof verification_uri !== "string" ||
|
|
181
|
+
typeof interval !== "number" ||
|
|
182
|
+
typeof expires_in !== "number") {
|
|
183
|
+
throw new Error("Invalid device code response fields");
|
|
184
|
+
}
|
|
185
|
+
return { device_code, user_code, verification_uri, interval, expires_in };
|
|
186
|
+
}
|
|
187
|
+
async function pollForAccessToken(deviceCode, intervalSeconds, expiresIn, signal) {
|
|
188
|
+
const deadline = Date.now() + expiresIn * 1000;
|
|
189
|
+
let intervalMs = Math.max(1000, Math.floor(intervalSeconds * 1000));
|
|
190
|
+
while (Date.now() < deadline) {
|
|
191
|
+
if (signal?.aborted) {
|
|
192
|
+
throw new Error("Login cancelled");
|
|
193
|
+
}
|
|
194
|
+
const remainingMs = deadline - Date.now();
|
|
195
|
+
const waitMs = Math.min(intervalMs, remainingMs);
|
|
196
|
+
await abortableSleep(waitMs, signal);
|
|
197
|
+
const tokenResponse = await fetch(OAUTH_TOKEN_URL, {
|
|
198
|
+
method: "POST",
|
|
199
|
+
headers: {
|
|
200
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
201
|
+
...buildKimiHeaders(),
|
|
202
|
+
},
|
|
203
|
+
body: new URLSearchParams({
|
|
204
|
+
client_id: OAUTH_CLIENT_ID,
|
|
205
|
+
device_code: deviceCode,
|
|
206
|
+
grant_type: OAUTH_DEVICE_GRANT,
|
|
207
|
+
}),
|
|
208
|
+
});
|
|
209
|
+
// The token endpoint returns 400 for authorization_pending / slow_down / expired_token.
|
|
210
|
+
// We must read the body regardless of status to handle the OAuth error codes.
|
|
211
|
+
const resp = (await tokenResponse.json());
|
|
212
|
+
// Success: has access_token
|
|
213
|
+
if (typeof resp.access_token === "string") {
|
|
214
|
+
return resp;
|
|
215
|
+
}
|
|
216
|
+
// Error response (RFC 8628 §3.5)
|
|
217
|
+
if (typeof resp.error === "string") {
|
|
218
|
+
const error = resp.error;
|
|
219
|
+
const description = resp.error_description;
|
|
220
|
+
const newInterval = resp.interval;
|
|
221
|
+
if (error === "authorization_pending") {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
if (error === "slow_down") {
|
|
225
|
+
intervalMs =
|
|
226
|
+
typeof newInterval === "number" && newInterval > 0
|
|
227
|
+
? newInterval * 1000
|
|
228
|
+
: Math.max(1000, intervalMs + 5000);
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (error === "expired_token") {
|
|
232
|
+
throw new Error("Device code expired. Please try logging in again.");
|
|
233
|
+
}
|
|
234
|
+
const descriptionSuffix = description ? `: ${description}` : "";
|
|
235
|
+
throw new Error(`Device flow failed: ${error}${descriptionSuffix}`);
|
|
236
|
+
}
|
|
237
|
+
// Unexpected response: valid object but no access_token or error field
|
|
238
|
+
throw new Error(`Unexpected token response: ${JSON.stringify(resp)}`);
|
|
239
|
+
}
|
|
240
|
+
throw new Error("Device flow timed out");
|
|
241
|
+
}
|
|
242
|
+
// ============================================================================
|
|
243
|
+
// Refresh with retry
|
|
244
|
+
// ============================================================================
|
|
245
|
+
const RETRYABLE_STATUS_CODES = [429, 500, 502, 503, 504];
|
|
246
|
+
class RetriableError extends Error {
|
|
247
|
+
constructor(message) {
|
|
248
|
+
super(message);
|
|
249
|
+
this.name = "RetriableError";
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Heuristic to detect network-level errors that should be retried.
|
|
254
|
+
* Fetch throws TypeError on network failures; some runtimes include
|
|
255
|
+
* recognizable substrings in the message.
|
|
256
|
+
*/
|
|
257
|
+
function isNetworkError(error) {
|
|
258
|
+
if (error instanceof TypeError)
|
|
259
|
+
return true;
|
|
260
|
+
const msg = error.message.toLowerCase();
|
|
261
|
+
return ["fetch failed", "econnrefused", "etimedout", "enotfound", "econnreset", "socket hang up"].some((s) => msg.includes(s));
|
|
262
|
+
}
|
|
263
|
+
async function refreshWithRetry(refreshToken, signal) {
|
|
264
|
+
let lastError;
|
|
265
|
+
for (let attempt = 0; attempt < MAX_REFRESH_RETRIES; attempt++) {
|
|
266
|
+
if (signal?.aborted) {
|
|
267
|
+
throw new Error("Refresh cancelled");
|
|
268
|
+
}
|
|
269
|
+
try {
|
|
270
|
+
const response = await fetch(OAUTH_TOKEN_URL, {
|
|
271
|
+
method: "POST",
|
|
272
|
+
headers: {
|
|
273
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
274
|
+
...buildKimiHeaders(),
|
|
275
|
+
},
|
|
276
|
+
body: new URLSearchParams({
|
|
277
|
+
client_id: OAUTH_CLIENT_ID,
|
|
278
|
+
refresh_token: refreshToken,
|
|
279
|
+
grant_type: OAUTH_REFRESH_GRANT,
|
|
280
|
+
}),
|
|
281
|
+
});
|
|
282
|
+
// Retry on retriable status codes
|
|
283
|
+
if (RETRYABLE_STATUS_CODES.includes(response.status)) {
|
|
284
|
+
throw new RetriableError(`Token refresh failed with status ${response.status}`);
|
|
285
|
+
}
|
|
286
|
+
if (!response.ok) {
|
|
287
|
+
const text = await response.text();
|
|
288
|
+
throw new Error(`Token refresh failed: ${response.status} ${response.statusText}: ${text}`);
|
|
289
|
+
}
|
|
290
|
+
const raw = await response.json();
|
|
291
|
+
if (!raw || typeof raw !== "object" || typeof raw.access_token !== "string") {
|
|
292
|
+
throw new Error("Invalid token refresh response");
|
|
293
|
+
}
|
|
294
|
+
return raw;
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
298
|
+
// Wrap network errors (TypeError from fetch, or common network failure indicators) as retriable
|
|
299
|
+
if (!(lastError instanceof RetriableError) && isNetworkError(lastError)) {
|
|
300
|
+
lastError = new RetriableError(lastError.message);
|
|
301
|
+
}
|
|
302
|
+
// Retry on retriable errors (network failures or retriable HTTP status codes)
|
|
303
|
+
if (lastError instanceof RetriableError && attempt < MAX_REFRESH_RETRIES - 1) {
|
|
304
|
+
const backoffMs = Math.min(1000 * 2 ** attempt, 10000);
|
|
305
|
+
await abortableSleep(backoffMs, signal);
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
throw lastError;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
throw lastError ?? new Error("Token refresh failed after retries");
|
|
312
|
+
}
|
|
313
|
+
// ============================================================================
|
|
314
|
+
// Login flow
|
|
315
|
+
// ============================================================================
|
|
316
|
+
export async function loginKimiCoding(options) {
|
|
317
|
+
const device = await startDeviceFlow();
|
|
318
|
+
// Kimi's device page expects user_code as a query parameter
|
|
319
|
+
const authUrl = new URL(device.verification_uri);
|
|
320
|
+
authUrl.searchParams.set("user_code", device.user_code);
|
|
321
|
+
options.onAuth({
|
|
322
|
+
url: authUrl.toString(),
|
|
323
|
+
instructions: `Enter code: ${device.user_code}`,
|
|
324
|
+
});
|
|
325
|
+
const tokenResp = await pollForAccessToken(device.device_code, device.interval, device.expires_in, options.signal);
|
|
326
|
+
// Discover model entitlement
|
|
327
|
+
options.onProgress?.("Discovering available models...");
|
|
328
|
+
let models = [];
|
|
329
|
+
try {
|
|
330
|
+
models = await listModels(tokenResp.access_token);
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
// Proceed without model enrichment if the models endpoint fails
|
|
334
|
+
}
|
|
335
|
+
const credentials = {
|
|
336
|
+
refresh: tokenResp.refresh_token,
|
|
337
|
+
access: tokenResp.access_token,
|
|
338
|
+
expires: Date.now() + tokenResp.expires_in * 1000,
|
|
339
|
+
};
|
|
340
|
+
if (models.length > 0) {
|
|
341
|
+
const primary = models[0];
|
|
342
|
+
credentials.modelId = primary.id;
|
|
343
|
+
credentials.contextLength = primary.context_length;
|
|
344
|
+
credentials.modelDisplay = primary.display_name;
|
|
345
|
+
}
|
|
346
|
+
return credentials;
|
|
347
|
+
}
|
|
348
|
+
// ============================================================================
|
|
349
|
+
// Refresh
|
|
350
|
+
// ============================================================================
|
|
351
|
+
export async function refreshKimiCodingToken(credentials, signal) {
|
|
352
|
+
const tokenResp = await refreshWithRetry(credentials.refresh, signal);
|
|
353
|
+
// Re-discover model entitlement
|
|
354
|
+
let models = [];
|
|
355
|
+
try {
|
|
356
|
+
models = await listModels(tokenResp.access_token);
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
// Proceed without model enrichment if the models endpoint fails
|
|
360
|
+
}
|
|
361
|
+
const fresh = {
|
|
362
|
+
refresh: tokenResp.refresh_token ?? credentials.refresh,
|
|
363
|
+
access: tokenResp.access_token,
|
|
364
|
+
expires: Date.now() + tokenResp.expires_in * 1000,
|
|
365
|
+
modelId: credentials.modelId,
|
|
366
|
+
contextLength: credentials.contextLength,
|
|
367
|
+
modelDisplay: credentials.modelDisplay,
|
|
368
|
+
};
|
|
369
|
+
if (models.length > 0) {
|
|
370
|
+
const primary = models[0];
|
|
371
|
+
fresh.modelId = primary.id;
|
|
372
|
+
fresh.contextLength = primary.context_length;
|
|
373
|
+
fresh.modelDisplay = primary.display_name;
|
|
374
|
+
}
|
|
375
|
+
return fresh;
|
|
376
|
+
}
|
|
377
|
+
// ============================================================================
|
|
378
|
+
// Provider
|
|
379
|
+
// ============================================================================
|
|
380
|
+
export const kimiCodingOAuthProvider = {
|
|
381
|
+
id: "kimi-coding-oauth",
|
|
382
|
+
name: "Kimi For Coding",
|
|
383
|
+
async login(callbacks) {
|
|
384
|
+
return loginKimiCoding({
|
|
385
|
+
onAuth: callbacks.onAuth,
|
|
386
|
+
onProgress: callbacks.onProgress,
|
|
387
|
+
signal: callbacks.signal,
|
|
388
|
+
});
|
|
389
|
+
},
|
|
390
|
+
async refreshToken(credentials) {
|
|
391
|
+
return refreshKimiCodingToken(credentials);
|
|
392
|
+
},
|
|
393
|
+
getApiKey(credentials) {
|
|
394
|
+
return credentials.access;
|
|
395
|
+
},
|
|
396
|
+
modifyModels(models, credentials) {
|
|
397
|
+
const creds = credentials;
|
|
398
|
+
const headers = buildKimiHeaders();
|
|
399
|
+
return models.map((m) => {
|
|
400
|
+
if (m.provider !== "kimi-coding-oauth")
|
|
401
|
+
return m;
|
|
402
|
+
const updated = {
|
|
403
|
+
...m,
|
|
404
|
+
headers: { ...headers, ...(m.headers || {}) },
|
|
405
|
+
};
|
|
406
|
+
if (creds.modelId) {
|
|
407
|
+
updated.id = creds.modelId;
|
|
408
|
+
}
|
|
409
|
+
if (creds.contextLength) {
|
|
410
|
+
updated.contextWindow = creds.contextLength;
|
|
411
|
+
}
|
|
412
|
+
return updated;
|
|
413
|
+
});
|
|
414
|
+
},
|
|
415
|
+
};
|
|
416
|
+
//# sourceMappingURL=kimi-coding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kimi-coding.js","sourceRoot":"","sources":["../../../src/utils/oauth/kimi-coding.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAIlC,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,MAAM,gBAAgB,GAAG,QAAQ,CAAC;AAClC,MAAM,UAAU,GAAG,WAAW,gBAAgB,EAAE,CAAC;AACjD,MAAM,UAAU,GAAG,uBAAuB,CAAC;AAC3C,MAAM,qBAAqB,GAAG,GAAG,UAAU,iCAAiC,CAAC;AAC7E,MAAM,eAAe,GAAG,GAAG,UAAU,kBAAkB,CAAC;AACxD,MAAM,eAAe,GAAG,sCAAsC,CAAC;AAC/D,MAAM,WAAW,GAAG,WAAW,CAAC;AAChC,MAAM,kBAAkB,GAAG,8CAA8C,CAAC;AAC1E,MAAM,mBAAmB,GAAG,eAAe,CAAC;AAC5C,MAAM,YAAY,GAAG,gCAAgC,CAAC;AAEtD,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;AAErE,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,SAAS,gBAAgB,GAAW;IACnC,8CAA8C;IAC9C,OAAO,kCAAkC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;AAAA,CAC3G;AAED,SAAS,WAAW,GAAW;IAC9B,IAAI,CAAC;QACJ,IAAI,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YACnC,MAAM,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;YAC3D,IAAI,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;gBAChC,OAAO,EAAE,CAAC;YACX,CAAC;QACF,CAAC;IACF,CAAC;IAAC,MAAM,CAAC;QACR,2BAA2B;IAC5B,CAAC;IAED,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAC9B,IAAI,CAAC;QACJ,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,EAAE,CAAC,aAAa,CAAC,cAAc,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACR,kEAAkE;IACnE,CAAC;IACD,OAAO,EAAE,CAAC;AAAA,CACV;AAED,+EAA+E;AAC/E,iBAAiB;AACjB,+EAA+E;AAE/E;;GAEG;AACH,SAAS,gBAAgB,CAAC,KAAa,EAAU;IAChD,OAAO,KAAK,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;AAAA,CAC1C;AAED;;GAEG;AACH,SAAS,eAAe,GAAW;IAClC,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IAE/C,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC3B,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACJ,OAAO,GAAG,YAAY,CAAC,SAAS,EAAE,CAAC,iBAAiB,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACrG,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QACxB,CAAC;QACD,OAAO,SAAS,OAAO,IAAI,OAAO,EAAE,CAAC;IACtC,CAAC;IAED,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QAC7B,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;QACzE,MAAM,KAAK,GAAG,WAAW,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACjD,OAAO,WAAW,KAAK,IAAI,OAAO,EAAE,CAAC;IACtC,CAAC;IAED,kBAAkB;IAClB,OAAO,GAAG,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,IAAI,OAAO,EAAE,CAAC;AAAA,CACjD;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,GAA2B;IAC1D,OAAO;QACN,YAAY,EAAE,UAAU;QACxB,gBAAgB,EAAE,UAAU;QAC5B,eAAe,EAAE,gBAAgB;QACjC,mBAAmB,EAAE,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC;QACpD,oBAAoB,EAAE,gBAAgB,CAAC,eAAe,EAAE,CAAC;QACzD,iBAAiB,EAAE,WAAW,EAAE;QAChC,kBAAkB,EAAE,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,IAAI,GAAG,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC;KACtF,CAAC;AAAA,CACF;AAkCD,+EAA+E;AAC/E,kBAAkB;AAClB,+EAA+E;AAE/E,KAAK,UAAU,SAAS,CAAC,GAAW,EAAE,IAAiB,EAAoB;IAC1E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QAClB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,GAAG,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AAAA,CACvB;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,EAAU,EAAE,MAAoB,EAAiB;IACxE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;QACvC,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC;YACrC,OAAO;QACR,CAAC;QAED,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAExC,MAAM,EAAE,gBAAgB,CACvB,OAAO,EACP,GAAG,EAAE,CAAC;YACL,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,MAAM,CAAC,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC;QAAA,CACrC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACd,CAAC;IAAA,CACF,CAAC,CAAC;AAAA,CACH;AAED,+EAA+E;AAC/E,kBAAkB;AAClB,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,WAAmB,EAA4B;IAC/E,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,YAAY,SAAS,EAAE;QACrD,OAAO,EAAE;YACR,aAAa,EAAE,UAAU,WAAW,EAAE;YACtC,GAAG,gBAAgB,EAAE;SACrB;KACD,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,IAAI,GAAI,GAA+B,CAAC,IAAI,CAAC;IACnD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,IAAuB,CAAC;AAAA,CAC/B;AAED,+EAA+E;AAC/E,cAAc;AACd,+EAA+E;AAE/E,KAAK,UAAU,eAAe,GAAgC;IAC7D,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,qBAAqB,EAAE;QACnD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACR,cAAc,EAAE,mCAAmC;YACnD,GAAG,gBAAgB,EAAE;SACrB;QACD,IAAI,EAAE,IAAI,eAAe,CAAC;YACzB,SAAS,EAAE,eAAe;YAC1B,KAAK,EAAE,WAAW;SAClB,CAAC;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,MAAM,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC;IAClC,MAAM,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC;IAC9B,MAAM,gBAAgB,GAAG,CAAC,CAAC,gBAAgB,CAAC;IAC5C,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;IAC5B,MAAM,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC;IAEhC,IACC,OAAO,WAAW,KAAK,QAAQ;QAC/B,OAAO,SAAS,KAAK,QAAQ;QAC7B,OAAO,gBAAgB,KAAK,QAAQ;QACpC,OAAO,QAAQ,KAAK,QAAQ;QAC5B,OAAO,UAAU,KAAK,QAAQ,EAC7B,CAAC;QACF,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;AAAA,CAC1E;AAED,KAAK,UAAU,kBAAkB,CAChC,UAAkB,EAClB,eAAuB,EACvB,SAAiB,EACjB,MAAoB,EACY;IAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC;IAC/C,IAAI,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC;IAEpE,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC9B,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;QACpC,CAAC;QAED,MAAM,WAAW,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QACjD,MAAM,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAErC,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,eAAe,EAAE;YAClD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACR,cAAc,EAAE,mCAAmC;gBACnD,GAAG,gBAAgB,EAAE;aACrB;YACD,IAAI,EAAE,IAAI,eAAe,CAAC;gBACzB,SAAS,EAAE,eAAe;gBAC1B,WAAW,EAAE,UAAU;gBACvB,UAAU,EAAE,kBAAkB;aAC9B,CAAC;SACF,CAAC,CAAC;QAEH,wFAAwF;QACxF,8EAA8E;QAC9E,MAAM,IAAI,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,CAA4B,CAAC;QAErE,4BAA4B;QAC5B,IAAI,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;YAC3C,OAAO,IAAuC,CAAC;QAChD,CAAC;QAED,kCAAiC;QACjC,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YACpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;YACzB,MAAM,WAAW,GAAG,IAAI,CAAC,iBAAuC,CAAC;YACjE,MAAM,WAAW,GAAG,IAAI,CAAC,QAA8B,CAAC;YAExD,IAAI,KAAK,KAAK,uBAAuB,EAAE,CAAC;gBACvC,SAAS;YACV,CAAC;YAED,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;gBAC3B,UAAU;oBACT,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,GAAG,CAAC;wBACjD,CAAC,CAAC,WAAW,GAAG,IAAI;wBACpB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC,CAAC;gBACtC,SAAS;YACV,CAAC;YAED,IAAI,KAAK,KAAK,eAAe,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;YACtE,CAAC;YAED,MAAM,iBAAiB,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,MAAM,IAAI,KAAK,CAAC,uBAAuB,KAAK,GAAG,iBAAiB,EAAE,CAAC,CAAC;QACrE,CAAC;QAED,uEAAuE;QACvE,MAAM,IAAI,KAAK,CAAC,8BAA8B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;AAAA,CACzC;AAED,+EAA+E;AAC/E,qBAAqB;AACrB,+EAA+E;AAE/E,MAAM,sBAAsB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAEzD,MAAM,cAAe,SAAQ,KAAK;IACjC,YAAY,OAAe,EAAE;QAC5B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAAA,CAC7B;CACD;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,KAAY,EAAW;IAC9C,IAAI,KAAK,YAAY,SAAS;QAAE,OAAO,IAAI,CAAC;IAC5C,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;IACxC,OAAO,CAAC,cAAc,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAC5G,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CACf,CAAC;AAAA,CACF;AAED,KAAK,UAAU,gBAAgB,CAAC,YAAoB,EAAE,MAAoB,EAAiC;IAC1G,IAAI,SAA4B,CAAC;IAEjC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,mBAAmB,EAAE,OAAO,EAAE,EAAE,CAAC;QAChE,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACtC,CAAC;QAED,IAAI,CAAC;YACJ,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,eAAe,EAAE;gBAC7C,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACR,cAAc,EAAE,mCAAmC;oBACnD,GAAG,gBAAgB,EAAE;iBACrB;gBACD,IAAI,EAAE,IAAI,eAAe,CAAC;oBACzB,SAAS,EAAE,eAAe;oBAC1B,aAAa,EAAE,YAAY;oBAC3B,UAAU,EAAE,mBAAmB;iBAC/B,CAAC;aACF,CAAC,CAAC;YAEH,kCAAkC;YAClC,IAAI,sBAAsB,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtD,MAAM,IAAI,cAAc,CAAC,oCAAoC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YACjF,CAAC;YAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBAClB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnC,MAAM,IAAI,KAAK,CAAC,yBAAyB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC,CAAC;YAC7F,CAAC;YAED,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YAClC,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAQ,GAA+B,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;gBAC1G,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;YACnD,CAAC;YAED,OAAO,GAAsC,CAAC;QAC/C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,SAAS,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAEtE,gGAAgG;YAChG,IAAI,CAAC,CAAC,SAAS,YAAY,cAAc,CAAC,IAAI,cAAc,CAAC,SAAS,CAAC,EAAE,CAAC;gBACzE,SAAS,GAAG,IAAI,cAAc,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YACnD,CAAC;YAED,8EAA8E;YAC9E,IAAI,SAAS,YAAY,cAAc,IAAI,OAAO,GAAG,mBAAmB,GAAG,CAAC,EAAE,CAAC;gBAC9E,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,OAAO,EAAE,KAAK,CAAC,CAAC;gBACvD,MAAM,cAAc,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;gBACxC,SAAS;YACV,CAAC;YAED,MAAM,SAAS,CAAC;QACjB,CAAC;IACF,CAAC;IAED,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;AAAA,CACnE;AAED,+EAA+E;AAC/E,aAAa;AACb,+EAA+E;AAE/E,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAIrC,EAA6B;IAC7B,MAAM,MAAM,GAAG,MAAM,eAAe,EAAE,CAAC;IACvC,4DAA4D;IAC5D,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACjD,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACxD,OAAO,CAAC,MAAM,CAAC;QACd,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE;QACvB,YAAY,EAAE,eAAe,MAAM,CAAC,SAAS,EAAE;KAC/C,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnH,6BAA6B;IAC7B,OAAO,CAAC,UAAU,EAAE,CAAC,iCAAiC,CAAC,CAAC;IACxD,IAAI,MAAM,GAAoB,EAAE,CAAC;IACjC,IAAI,CAAC;QACJ,MAAM,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACR,gEAAgE;IACjE,CAAC;IAED,MAAM,WAAW,GAAoB;QACpC,OAAO,EAAE,SAAS,CAAC,aAAa;QAChC,MAAM,EAAE,SAAS,CAAC,YAAY;QAC9B,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,UAAU,GAAG,IAAI;KACjD,CAAC;IAEF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1B,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC,EAAE,CAAC;QACjC,WAAW,CAAC,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;QACnD,WAAW,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IACjD,CAAC;IAED,OAAO,WAAW,CAAC;AAAA,CACnB;AAED,+EAA+E;AAC/E,UAAU;AACV,+EAA+E;AAE/E,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC3C,WAA6B,EAC7B,MAAoB,EACQ;IAC5B,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAEtE,gCAAgC;IAChC,IAAI,MAAM,GAAoB,EAAE,CAAC;IACjC,IAAI,CAAC;QACJ,MAAM,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACR,gEAAgE;IACjE,CAAC;IAED,MAAM,KAAK,GAAoB;QAC9B,OAAO,EAAE,SAAS,CAAC,aAAa,IAAI,WAAW,CAAC,OAAO;QACvD,MAAM,EAAE,SAAS,CAAC,YAAY;QAC9B,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,UAAU,GAAG,IAAI;QACjD,OAAO,EAAG,WAA+B,CAAC,OAAO;QACjD,aAAa,EAAG,WAA+B,CAAC,aAAa;QAC7D,YAAY,EAAG,WAA+B,CAAC,YAAY;KAC3D,CAAC;IAEF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1B,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC,EAAE,CAAC;QAC3B,KAAK,CAAC,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;QAC7C,KAAK,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAC3C,CAAC;IAED,OAAO,KAAK,CAAC;AAAA,CACb;AAED,+EAA+E;AAC/E,WAAW;AACX,+EAA+E;AAE/E,MAAM,CAAC,MAAM,uBAAuB,GAA2B;IAC9D,EAAE,EAAE,mBAAmB;IACvB,IAAI,EAAE,iBAAiB;IAEvB,KAAK,CAAC,KAAK,CAAC,SAA8B,EAA6B;QACtE,OAAO,eAAe,CAAC;YACtB,MAAM,EAAE,SAAS,CAAC,MAAM;YACxB,UAAU,EAAE,SAAS,CAAC,UAAU;YAChC,MAAM,EAAE,SAAS,CAAC,MAAM;SACxB,CAAC,CAAC;IAAA,CACH;IAED,KAAK,CAAC,YAAY,CAAC,WAA6B,EAA6B;QAC5E,OAAO,sBAAsB,CAAC,WAAW,CAAC,CAAC;IAAA,CAC3C;IAED,SAAS,CAAC,WAA6B,EAAU;QAChD,OAAO,WAAW,CAAC,MAAM,CAAC;IAAA,CAC1B;IAED,YAAY,CAAC,MAAoB,EAAE,WAA6B,EAAgB;QAC/E,MAAM,KAAK,GAAG,WAA8B,CAAC;QAC7C,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;QAEnC,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACxB,IAAI,CAAC,CAAC,QAAQ,KAAK,mBAAmB;gBAAE,OAAO,CAAC,CAAC;YAEjD,MAAM,OAAO,GAAG;gBACf,GAAG,CAAC;gBACJ,OAAO,EAAE,EAAE,GAAG,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE;aAC7C,CAAC;YAEF,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBACnB,OAAO,CAAC,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC;YAC5B,CAAC;YAED,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;gBACzB,OAAO,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC;YAC7C,CAAC;YAED,OAAO,OAAO,CAAC;QAAA,CACf,CAAC,CAAC;IAAA,CACH;CACD,CAAC","sourcesContent":["/**\n * Kimi For Coding OAuth flow (device code)\n *\n * Authenticates against Moonshot's Kimi API (auth.kimi.com) with scope \"kimi-code\".\n * Uses the device authorization grant flow to obtain access/refresh tokens,\n * then discovers the user's model entitlement via the /models endpoint.\n */\n\nimport { execFileSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { Api, Model } from \"../../types.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.js\";\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst KIMI_CLI_VERSION = \"1.35.0\";\nconst USER_AGENT = `KimiCLI/${KIMI_CLI_VERSION}`;\nconst OAUTH_HOST = \"https://auth.kimi.com\";\nconst OAUTH_DEVICE_AUTH_URL = `${OAUTH_HOST}/api/oauth/device_authorization`;\nconst OAUTH_TOKEN_URL = `${OAUTH_HOST}/api/oauth/token`;\nconst OAUTH_CLIENT_ID = \"17e5f671-d194-4dfb-9706-5516cb48c098\";\nconst OAUTH_SCOPE = \"kimi-code\";\nconst OAUTH_DEVICE_GRANT = \"urn:ietf:params:oauth:grant-type:device_code\";\nconst OAUTH_REFRESH_GRANT = \"refresh_token\";\nconst API_BASE_URL = \"https://api.kimi.com/coding/v1\";\n\nconst DEVICE_ID_PATH = path.join(os.homedir(), \".kimi\", \"device_id\");\n\nconst MAX_REFRESH_RETRIES = 3;\n\n// ============================================================================\n// Device ID\n// ============================================================================\n\nfunction generateDeviceId(): string {\n\t// UUID v4 without dashes (hex only, 32 chars)\n\treturn \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\".replace(/x/g, () => Math.floor(Math.random() * 16).toString(16));\n}\n\nfunction getDeviceId(): string {\n\ttry {\n\t\tif (fs.existsSync(DEVICE_ID_PATH)) {\n\t\t\tconst id = fs.readFileSync(DEVICE_ID_PATH, \"utf-8\").trim();\n\t\t\tif (/^[0-9a-f]{32}$/i.test(id)) {\n\t\t\t\treturn id;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Fall through to generate\n\t}\n\n\tconst id = generateDeviceId();\n\ttry {\n\t\tfs.mkdirSync(path.dirname(DEVICE_ID_PATH), { recursive: true });\n\t\tfs.writeFileSync(DEVICE_ID_PATH, id, \"utf-8\");\n\t} catch {\n\t\t// If we can't persist, just use the generated ID for this session\n\t}\n\treturn id;\n}\n\n// ============================================================================\n// Header helpers\n// ============================================================================\n\n/**\n * Strip non-ASCII characters from a string for use in HTTP header values.\n */\nfunction asciiHeaderValue(value: string): string {\n\treturn value.replace(/[^\\x20-\\x7E]/g, \"\");\n}\n\n/**\n * Determine the device model string, mirroring kimi-cli logic.\n */\nfunction kimiDeviceModel(): string {\n\tconst platform = os.platform();\n\tconst machine = os.machine?.() || process.arch;\n\n\tif (platform === \"darwin\") {\n\t\tlet version: string;\n\t\ttry {\n\t\t\tversion = execFileSync(\"sw_vers\", [\"-productVersion\"], { encoding: \"utf-8\", timeout: 3000 }).trim();\n\t\t} catch {\n\t\t\tversion = os.release();\n\t\t}\n\t\treturn `macOS ${version} ${machine}`;\n\t}\n\n\tif (platform === \"win32\") {\n\t\tconst release = os.release();\n\t\tconst buildNumber = Number.parseInt(release.split(\".\").pop() || \"0\", 10);\n\t\tconst label = buildNumber >= 22000 ? \"11\" : \"10\";\n\t\treturn `Windows ${label} ${machine}`;\n\t}\n\n\t// Linux and other\n\treturn `${os.type()} ${os.release()} ${machine}`;\n}\n\n/**\n * Build the standard set of headers required on every Kimi API request.\n */\nexport function buildKimiHeaders(): Record<string, string> {\n\treturn {\n\t\t\"User-Agent\": USER_AGENT,\n\t\t\"X-Msh-Platform\": \"kimi_cli\",\n\t\t\"X-Msh-Version\": KIMI_CLI_VERSION,\n\t\t\"X-Msh-Device-Name\": asciiHeaderValue(os.hostname()),\n\t\t\"X-Msh-Device-Model\": asciiHeaderValue(kimiDeviceModel()),\n\t\t\"X-Msh-Device-Id\": getDeviceId(),\n\t\t\"X-Msh-Os-Version\": asciiHeaderValue(os.version?.() || `${os.type()} ${os.release()}`),\n\t};\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype DeviceCodeResponse = {\n\tdevice_code: string;\n\tuser_code: string;\n\tverification_uri: string;\n\tinterval: number;\n\texpires_in: number;\n};\n\ntype TokenSuccessResponse = {\n\taccess_token: string;\n\trefresh_token: string;\n\texpires_in: number;\n};\n\nexport type KimiModelInfo = {\n\tid: string;\n\tdisplay_name: string;\n\tcontext_length: number;\n\tsupports_reasoning?: boolean;\n\t[key: string]: unknown;\n};\n\ntype KimiCredentials = OAuthCredentials & {\n\tmodelId?: string;\n\tcontextLength?: number;\n\tmodelDisplay?: string;\n};\n\n// ============================================================================\n// Network helpers\n// ============================================================================\n\nasync function fetchJson(url: string, init: RequestInit): Promise<unknown> {\n\tconst response = await fetch(url, init);\n\tif (!response.ok) {\n\t\tconst text = await response.text();\n\t\tthrow new Error(`${response.status} ${response.statusText}: ${text}`);\n\t}\n\treturn response.json();\n}\n\n/**\n * Sleep that can be interrupted by an AbortSignal.\n */\nfunction abortableSleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new Error(\"Login cancelled\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst timeout = setTimeout(resolve, ms);\n\n\t\tsignal?.addEventListener(\n\t\t\t\"abort\",\n\t\t\t() => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\treject(new Error(\"Login cancelled\"));\n\t\t\t},\n\t\t\t{ once: true },\n\t\t);\n\t});\n}\n\n// ============================================================================\n// Model discovery\n// ============================================================================\n\n/**\n * List available models from the Kimi API.\n * Returns the model info array from the response's `data` field.\n */\nexport async function listModels(accessToken: string): Promise<KimiModelInfo[]> {\n\tconst raw = await fetchJson(`${API_BASE_URL}/models`, {\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${accessToken}`,\n\t\t\t...buildKimiHeaders(),\n\t\t},\n\t});\n\n\tif (!raw || typeof raw !== \"object\") {\n\t\tthrow new Error(\"Invalid models response\");\n\t}\n\n\tconst data = (raw as Record<string, unknown>).data;\n\tif (!Array.isArray(data)) {\n\t\tthrow new Error(\"Invalid models response: expected data array\");\n\t}\n\n\treturn data as KimiModelInfo[];\n}\n\n// ============================================================================\n// Device flow\n// ============================================================================\n\nasync function startDeviceFlow(): Promise<DeviceCodeResponse> {\n\tconst data = await fetchJson(OAUTH_DEVICE_AUTH_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t...buildKimiHeaders(),\n\t\t},\n\t\tbody: new URLSearchParams({\n\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\tscope: OAUTH_SCOPE,\n\t\t}),\n\t});\n\n\tif (!data || typeof data !== \"object\") {\n\t\tthrow new Error(\"Invalid device code response\");\n\t}\n\n\tconst d = data as Record<string, unknown>;\n\tconst device_code = d.device_code;\n\tconst user_code = d.user_code;\n\tconst verification_uri = d.verification_uri;\n\tconst interval = d.interval;\n\tconst expires_in = d.expires_in;\n\n\tif (\n\t\ttypeof device_code !== \"string\" ||\n\t\ttypeof user_code !== \"string\" ||\n\t\ttypeof verification_uri !== \"string\" ||\n\t\ttypeof interval !== \"number\" ||\n\t\ttypeof expires_in !== \"number\"\n\t) {\n\t\tthrow new Error(\"Invalid device code response fields\");\n\t}\n\n\treturn { device_code, user_code, verification_uri, interval, expires_in };\n}\n\nasync function pollForAccessToken(\n\tdeviceCode: string,\n\tintervalSeconds: number,\n\texpiresIn: number,\n\tsignal?: AbortSignal,\n): Promise<TokenSuccessResponse> {\n\tconst deadline = Date.now() + expiresIn * 1000;\n\tlet intervalMs = Math.max(1000, Math.floor(intervalSeconds * 1000));\n\n\twhile (Date.now() < deadline) {\n\t\tif (signal?.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\n\t\tconst remainingMs = deadline - Date.now();\n\t\tconst waitMs = Math.min(intervalMs, remainingMs);\n\t\tawait abortableSleep(waitMs, signal);\n\n\t\tconst tokenResponse = await fetch(OAUTH_TOKEN_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t...buildKimiHeaders(),\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\t\tdevice_code: deviceCode,\n\t\t\t\tgrant_type: OAUTH_DEVICE_GRANT,\n\t\t\t}),\n\t\t});\n\n\t\t// The token endpoint returns 400 for authorization_pending / slow_down / expired_token.\n\t\t// We must read the body regardless of status to handle the OAuth error codes.\n\t\tconst resp = (await tokenResponse.json()) as Record<string, unknown>;\n\n\t\t// Success: has access_token\n\t\tif (typeof resp.access_token === \"string\") {\n\t\t\treturn resp as unknown as TokenSuccessResponse;\n\t\t}\n\n\t\t// Error response (RFC 8628 §3.5)\n\t\tif (typeof resp.error === \"string\") {\n\t\t\tconst error = resp.error;\n\t\t\tconst description = resp.error_description as string | undefined;\n\t\t\tconst newInterval = resp.interval as number | undefined;\n\n\t\t\tif (error === \"authorization_pending\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (error === \"slow_down\") {\n\t\t\t\tintervalMs =\n\t\t\t\t\ttypeof newInterval === \"number\" && newInterval > 0\n\t\t\t\t\t\t? newInterval * 1000\n\t\t\t\t\t\t: Math.max(1000, intervalMs + 5000);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (error === \"expired_token\") {\n\t\t\t\tthrow new Error(\"Device code expired. Please try logging in again.\");\n\t\t\t}\n\n\t\t\tconst descriptionSuffix = description ? `: ${description}` : \"\";\n\t\t\tthrow new Error(`Device flow failed: ${error}${descriptionSuffix}`);\n\t\t}\n\n\t\t// Unexpected response: valid object but no access_token or error field\n\t\tthrow new Error(`Unexpected token response: ${JSON.stringify(resp)}`);\n\t}\n\n\tthrow new Error(\"Device flow timed out\");\n}\n\n// ============================================================================\n// Refresh with retry\n// ============================================================================\n\nconst RETRYABLE_STATUS_CODES = [429, 500, 502, 503, 504];\n\nclass RetriableError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"RetriableError\";\n\t}\n}\n\n/**\n * Heuristic to detect network-level errors that should be retried.\n * Fetch throws TypeError on network failures; some runtimes include\n * recognizable substrings in the message.\n */\nfunction isNetworkError(error: Error): boolean {\n\tif (error instanceof TypeError) return true;\n\tconst msg = error.message.toLowerCase();\n\treturn [\"fetch failed\", \"econnrefused\", \"etimedout\", \"enotfound\", \"econnreset\", \"socket hang up\"].some((s) =>\n\t\tmsg.includes(s),\n\t);\n}\n\nasync function refreshWithRetry(refreshToken: string, signal?: AbortSignal): Promise<TokenSuccessResponse> {\n\tlet lastError: Error | undefined;\n\n\tfor (let attempt = 0; attempt < MAX_REFRESH_RETRIES; attempt++) {\n\t\tif (signal?.aborted) {\n\t\t\tthrow new Error(\"Refresh cancelled\");\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(OAUTH_TOKEN_URL, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\t...buildKimiHeaders(),\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams({\n\t\t\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\t\t\trefresh_token: refreshToken,\n\t\t\t\t\tgrant_type: OAUTH_REFRESH_GRANT,\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\t// Retry on retriable status codes\n\t\t\tif (RETRYABLE_STATUS_CODES.includes(response.status)) {\n\t\t\t\tthrow new RetriableError(`Token refresh failed with status ${response.status}`);\n\t\t\t}\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst text = await response.text();\n\t\t\t\tthrow new Error(`Token refresh failed: ${response.status} ${response.statusText}: ${text}`);\n\t\t\t}\n\n\t\t\tconst raw = await response.json();\n\t\t\tif (!raw || typeof raw !== \"object\" || typeof (raw as Record<string, unknown>).access_token !== \"string\") {\n\t\t\t\tthrow new Error(\"Invalid token refresh response\");\n\t\t\t}\n\n\t\t\treturn raw as unknown as TokenSuccessResponse;\n\t\t} catch (error) {\n\t\t\tlastError = error instanceof Error ? error : new Error(String(error));\n\n\t\t\t// Wrap network errors (TypeError from fetch, or common network failure indicators) as retriable\n\t\t\tif (!(lastError instanceof RetriableError) && isNetworkError(lastError)) {\n\t\t\t\tlastError = new RetriableError(lastError.message);\n\t\t\t}\n\n\t\t\t// Retry on retriable errors (network failures or retriable HTTP status codes)\n\t\t\tif (lastError instanceof RetriableError && attempt < MAX_REFRESH_RETRIES - 1) {\n\t\t\t\tconst backoffMs = Math.min(1000 * 2 ** attempt, 10000);\n\t\t\t\tawait abortableSleep(backoffMs, signal);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthrow lastError;\n\t\t}\n\t}\n\n\tthrow lastError ?? new Error(\"Token refresh failed after retries\");\n}\n\n// ============================================================================\n// Login flow\n// ============================================================================\n\nexport async function loginKimiCoding(options: {\n\tonAuth: (info: { url: string; instructions?: string }) => void;\n\tonProgress?: (message: string) => void;\n\tsignal?: AbortSignal;\n}): Promise<OAuthCredentials> {\n\tconst device = await startDeviceFlow();\n\t// Kimi's device page expects user_code as a query parameter\n\tconst authUrl = new URL(device.verification_uri);\n\tauthUrl.searchParams.set(\"user_code\", device.user_code);\n\toptions.onAuth({\n\t\turl: authUrl.toString(),\n\t\tinstructions: `Enter code: ${device.user_code}`,\n\t});\n\n\tconst tokenResp = await pollForAccessToken(device.device_code, device.interval, device.expires_in, options.signal);\n\n\t// Discover model entitlement\n\toptions.onProgress?.(\"Discovering available models...\");\n\tlet models: KimiModelInfo[] = [];\n\ttry {\n\t\tmodels = await listModels(tokenResp.access_token);\n\t} catch {\n\t\t// Proceed without model enrichment if the models endpoint fails\n\t}\n\n\tconst credentials: KimiCredentials = {\n\t\trefresh: tokenResp.refresh_token,\n\t\taccess: tokenResp.access_token,\n\t\texpires: Date.now() + tokenResp.expires_in * 1000,\n\t};\n\n\tif (models.length > 0) {\n\t\tconst primary = models[0];\n\t\tcredentials.modelId = primary.id;\n\t\tcredentials.contextLength = primary.context_length;\n\t\tcredentials.modelDisplay = primary.display_name;\n\t}\n\n\treturn credentials;\n}\n\n// ============================================================================\n// Refresh\n// ============================================================================\n\nexport async function refreshKimiCodingToken(\n\tcredentials: OAuthCredentials,\n\tsignal?: AbortSignal,\n): Promise<OAuthCredentials> {\n\tconst tokenResp = await refreshWithRetry(credentials.refresh, signal);\n\n\t// Re-discover model entitlement\n\tlet models: KimiModelInfo[] = [];\n\ttry {\n\t\tmodels = await listModels(tokenResp.access_token);\n\t} catch {\n\t\t// Proceed without model enrichment if the models endpoint fails\n\t}\n\n\tconst fresh: KimiCredentials = {\n\t\trefresh: tokenResp.refresh_token ?? credentials.refresh,\n\t\taccess: tokenResp.access_token,\n\t\texpires: Date.now() + tokenResp.expires_in * 1000,\n\t\tmodelId: (credentials as KimiCredentials).modelId,\n\t\tcontextLength: (credentials as KimiCredentials).contextLength,\n\t\tmodelDisplay: (credentials as KimiCredentials).modelDisplay,\n\t};\n\n\tif (models.length > 0) {\n\t\tconst primary = models[0];\n\t\tfresh.modelId = primary.id;\n\t\tfresh.contextLength = primary.context_length;\n\t\tfresh.modelDisplay = primary.display_name;\n\t}\n\n\treturn fresh;\n}\n\n// ============================================================================\n// Provider\n// ============================================================================\n\nexport const kimiCodingOAuthProvider: OAuthProviderInterface = {\n\tid: \"kimi-coding-oauth\",\n\tname: \"Kimi For Coding\",\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginKimiCoding({\n\t\t\tonAuth: callbacks.onAuth,\n\t\t\tonProgress: callbacks.onProgress,\n\t\t\tsignal: callbacks.signal,\n\t\t});\n\t},\n\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\treturn refreshKimiCodingToken(credentials);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n\n\tmodifyModels(models: Model<Api>[], credentials: OAuthCredentials): Model<Api>[] {\n\t\tconst creds = credentials as KimiCredentials;\n\t\tconst headers = buildKimiHeaders();\n\n\t\treturn models.map((m) => {\n\t\t\tif (m.provider !== \"kimi-coding-oauth\") return m;\n\n\t\t\tconst updated = {\n\t\t\t\t...m,\n\t\t\t\theaders: { ...headers, ...(m.headers || {}) },\n\t\t\t};\n\n\t\t\tif (creds.modelId) {\n\t\t\t\tupdated.id = creds.modelId;\n\t\t\t}\n\n\t\t\tif (creds.contextLength) {\n\t\t\t\tupdated.contextWindow = creds.contextLength;\n\t\t\t}\n\n\t\t\treturn updated;\n\t\t});\n\t},\n};\n"]}
|