@kenkaiiii/gg-core 5.20.4 → 5.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-GMBEO4JX.js → chunk-TST5LJWL.js} +352 -275
- package/dist/chunk-TST5LJWL.js.map +1 -0
- package/dist/index.cjs +383 -297
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -3
- package/dist/index.d.ts +27 -3
- package/dist/index.js +11 -2
- package/dist/index.js.map +1 -1
- package/dist/model-registry.cjs +40 -20
- package/dist/model-registry.cjs.map +1 -1
- package/dist/model-registry.d.cts +14 -1
- package/dist/model-registry.d.ts +14 -1
- package/dist/model-registry.js +3 -1
- package/package.json +2 -2
- package/dist/chunk-GMBEO4JX.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ContextWindowOptions, DEFAULT_MAX_VIDEO_BYTES, MODELS, ModelInfo, getAuthStorageKey, getAuthStorageKeys, getContextWindow, getDefaultModel, getFastModel, getMaxThinkingLevel, getModel, getModelsForProvider, getSummaryModel, getToolResultCharLimit, getVideoByteLimit, usesOpenAICodexTransport } from './model-registry.cjs';
|
|
1
|
+
export { ContextWindowOptions, DEFAULT_MAX_VIDEO_BYTES, MODELS, ModelInfo, getAuthStorageKey, getAuthStorageKeys, getContextWindow, getDefaultModel, getDefaultThinkingLevel, getFastModel, getMaxThinkingLevel, getModel, getModelsForProvider, getSummaryModel, getToolResultCharLimit, getVideoByteLimit, usesOpenAICodexTransport } from './model-registry.cjs';
|
|
2
2
|
import { Provider, ThinkingLevel } from '@kenkaiiii/gg-ai';
|
|
3
3
|
export { AppPaths, getAppPaths } from './paths.cjs';
|
|
4
4
|
|
|
@@ -85,6 +85,14 @@ declare const MOONSHOT_OAUTH_KEY = "moonshot-oauth";
|
|
|
85
85
|
* order, is decided per-model via `getAuthStorageKeys()` in model-registry.ts.
|
|
86
86
|
*/
|
|
87
87
|
declare const XIAOMI_CREDITS_KEY = "xiaomi-credits";
|
|
88
|
+
/**
|
|
89
|
+
* Synchronous baseUrl read straight from the auth file, for boot paths that
|
|
90
|
+
* need the active endpoint before an AuthStorage instance exists (e.g. the
|
|
91
|
+
* CLI's sync main()). Missing/corrupt files yield undefined — callers treat
|
|
92
|
+
* that as the provider's public endpoint. Read-only: safe without the file
|
|
93
|
+
* lock (a torn mid-write read just falls back to undefined).
|
|
94
|
+
*/
|
|
95
|
+
declare function readStoredBaseUrlSync(authFile: string, provider: string): string | undefined;
|
|
88
96
|
declare class AuthStorage {
|
|
89
97
|
private data;
|
|
90
98
|
private filePath;
|
|
@@ -118,8 +126,25 @@ declare class AuthStorage {
|
|
|
118
126
|
* credential is absent (a present OAuth credential is refreshable).
|
|
119
127
|
*/
|
|
120
128
|
isStaticApiKey(provider: string): Promise<boolean>;
|
|
129
|
+
/**
|
|
130
|
+
* The base URL on the credential that is active right now, if any.
|
|
131
|
+
* Synchronous — call only after load()/resolveCredentials() populated the
|
|
132
|
+
* snapshot. For `moonshot` this is the Kimi For Coding URL whenever the
|
|
133
|
+
* OAuth entry is the one resolveCredentials would serve (i.e. not currently
|
|
134
|
+
* usage-exhausted with an API key configured).
|
|
135
|
+
*/
|
|
136
|
+
getStoredBaseUrl(provider: string): string | undefined;
|
|
121
137
|
load(): Promise<void>;
|
|
122
138
|
private ensureLoaded;
|
|
139
|
+
/**
|
|
140
|
+
* Apply one provider-scoped mutation to the latest on-disk snapshot.
|
|
141
|
+
* AuthStorage instances live in every app session/process, so writing this
|
|
142
|
+
* instance's cached snapshot can erase credentials another instance just
|
|
143
|
+
* added. The file lock only serializes writers; the re-read prevents stale
|
|
144
|
+
* full-file overwrites.
|
|
145
|
+
*/
|
|
146
|
+
private mutateLatest;
|
|
147
|
+
private reloadLatest;
|
|
123
148
|
getCredentials(provider: string): Promise<OAuthCredentials | undefined>;
|
|
124
149
|
setCredentials(provider: string, creds: OAuthCredentials): Promise<void>;
|
|
125
150
|
clearCredentials(provider: string): Promise<void>;
|
|
@@ -151,7 +176,6 @@ declare class AuthStorage {
|
|
|
151
176
|
* Throws if not logged in.
|
|
152
177
|
*/
|
|
153
178
|
resolveToken(provider: string): Promise<string>;
|
|
154
|
-
private save;
|
|
155
179
|
}
|
|
156
180
|
declare class NotLoggedInError extends Error {
|
|
157
181
|
provider: string;
|
|
@@ -422,4 +446,4 @@ interface AutoUpdater {
|
|
|
422
446
|
}
|
|
423
447
|
declare function createAutoUpdater(config: AutoUpdateConfig): AutoUpdater;
|
|
424
448
|
|
|
425
|
-
export { AuthStorage, type AutoUpdateConfig, type AutoUpdater, type InlineButton, type LogLevel, MOONSHOT_OAUTH_KEY, NotLoggedInError, type OAuthCredentials, type OAuthLoginCallbacks, type ProgressCallback, SubscriptionUsageError, type SubscriptionUsageProvider, type SubscriptionUsageSnapshot, type SubscriptionUsageWindow, TelegramBot, type TelegramConfig, type TelegramMessage, type TelegramUpdate, type TelegramVoiceMessage, XIAOMI_CREDITS_KEY, closeLogger, createAutoUpdater, decodeOggOpus, downmixToMono, fetchSubscriptionUsage, generatePKCE, getClaudeCliUserAgent, getClaudeCodeVersion, getNextThinkingLevel, getSessionId, getSupportedThinkingLevels, isKimiCodingEndpoint, isLoggerOpen, isModelLoaded, isThinkingLevelSupported, kimiCodeBaseUrl, kimiCodingHeaders, log, loginAnthropic, loginGemini, loginKimi, loginOpenAI, openLog, refreshAnthropicToken, refreshGeminiToken, refreshKimiToken, refreshOpenAIToken, registerLogCleanup, resample, setProgressCallback, transcribeVoice, withFileLock };
|
|
449
|
+
export { AuthStorage, type AutoUpdateConfig, type AutoUpdater, type InlineButton, type LogLevel, MOONSHOT_OAUTH_KEY, NotLoggedInError, type OAuthCredentials, type OAuthLoginCallbacks, type ProgressCallback, SubscriptionUsageError, type SubscriptionUsageProvider, type SubscriptionUsageSnapshot, type SubscriptionUsageWindow, TelegramBot, type TelegramConfig, type TelegramMessage, type TelegramUpdate, type TelegramVoiceMessage, XIAOMI_CREDITS_KEY, closeLogger, createAutoUpdater, decodeOggOpus, downmixToMono, fetchSubscriptionUsage, generatePKCE, getClaudeCliUserAgent, getClaudeCodeVersion, getNextThinkingLevel, getSessionId, getSupportedThinkingLevels, isKimiCodingEndpoint, isLoggerOpen, isModelLoaded, isThinkingLevelSupported, kimiCodeBaseUrl, kimiCodingHeaders, log, loginAnthropic, loginGemini, loginKimi, loginOpenAI, openLog, readStoredBaseUrlSync, refreshAnthropicToken, refreshGeminiToken, refreshKimiToken, refreshOpenAIToken, registerLogCleanup, resample, setProgressCallback, transcribeVoice, withFileLock };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ContextWindowOptions, DEFAULT_MAX_VIDEO_BYTES, MODELS, ModelInfo, getAuthStorageKey, getAuthStorageKeys, getContextWindow, getDefaultModel, getFastModel, getMaxThinkingLevel, getModel, getModelsForProvider, getSummaryModel, getToolResultCharLimit, getVideoByteLimit, usesOpenAICodexTransport } from './model-registry.js';
|
|
1
|
+
export { ContextWindowOptions, DEFAULT_MAX_VIDEO_BYTES, MODELS, ModelInfo, getAuthStorageKey, getAuthStorageKeys, getContextWindow, getDefaultModel, getDefaultThinkingLevel, getFastModel, getMaxThinkingLevel, getModel, getModelsForProvider, getSummaryModel, getToolResultCharLimit, getVideoByteLimit, usesOpenAICodexTransport } from './model-registry.js';
|
|
2
2
|
import { Provider, ThinkingLevel } from '@kenkaiiii/gg-ai';
|
|
3
3
|
export { AppPaths, getAppPaths } from './paths.js';
|
|
4
4
|
|
|
@@ -85,6 +85,14 @@ declare const MOONSHOT_OAUTH_KEY = "moonshot-oauth";
|
|
|
85
85
|
* order, is decided per-model via `getAuthStorageKeys()` in model-registry.ts.
|
|
86
86
|
*/
|
|
87
87
|
declare const XIAOMI_CREDITS_KEY = "xiaomi-credits";
|
|
88
|
+
/**
|
|
89
|
+
* Synchronous baseUrl read straight from the auth file, for boot paths that
|
|
90
|
+
* need the active endpoint before an AuthStorage instance exists (e.g. the
|
|
91
|
+
* CLI's sync main()). Missing/corrupt files yield undefined — callers treat
|
|
92
|
+
* that as the provider's public endpoint. Read-only: safe without the file
|
|
93
|
+
* lock (a torn mid-write read just falls back to undefined).
|
|
94
|
+
*/
|
|
95
|
+
declare function readStoredBaseUrlSync(authFile: string, provider: string): string | undefined;
|
|
88
96
|
declare class AuthStorage {
|
|
89
97
|
private data;
|
|
90
98
|
private filePath;
|
|
@@ -118,8 +126,25 @@ declare class AuthStorage {
|
|
|
118
126
|
* credential is absent (a present OAuth credential is refreshable).
|
|
119
127
|
*/
|
|
120
128
|
isStaticApiKey(provider: string): Promise<boolean>;
|
|
129
|
+
/**
|
|
130
|
+
* The base URL on the credential that is active right now, if any.
|
|
131
|
+
* Synchronous — call only after load()/resolveCredentials() populated the
|
|
132
|
+
* snapshot. For `moonshot` this is the Kimi For Coding URL whenever the
|
|
133
|
+
* OAuth entry is the one resolveCredentials would serve (i.e. not currently
|
|
134
|
+
* usage-exhausted with an API key configured).
|
|
135
|
+
*/
|
|
136
|
+
getStoredBaseUrl(provider: string): string | undefined;
|
|
121
137
|
load(): Promise<void>;
|
|
122
138
|
private ensureLoaded;
|
|
139
|
+
/**
|
|
140
|
+
* Apply one provider-scoped mutation to the latest on-disk snapshot.
|
|
141
|
+
* AuthStorage instances live in every app session/process, so writing this
|
|
142
|
+
* instance's cached snapshot can erase credentials another instance just
|
|
143
|
+
* added. The file lock only serializes writers; the re-read prevents stale
|
|
144
|
+
* full-file overwrites.
|
|
145
|
+
*/
|
|
146
|
+
private mutateLatest;
|
|
147
|
+
private reloadLatest;
|
|
123
148
|
getCredentials(provider: string): Promise<OAuthCredentials | undefined>;
|
|
124
149
|
setCredentials(provider: string, creds: OAuthCredentials): Promise<void>;
|
|
125
150
|
clearCredentials(provider: string): Promise<void>;
|
|
@@ -151,7 +176,6 @@ declare class AuthStorage {
|
|
|
151
176
|
* Throws if not logged in.
|
|
152
177
|
*/
|
|
153
178
|
resolveToken(provider: string): Promise<string>;
|
|
154
|
-
private save;
|
|
155
179
|
}
|
|
156
180
|
declare class NotLoggedInError extends Error {
|
|
157
181
|
provider: string;
|
|
@@ -422,4 +446,4 @@ interface AutoUpdater {
|
|
|
422
446
|
}
|
|
423
447
|
declare function createAutoUpdater(config: AutoUpdateConfig): AutoUpdater;
|
|
424
448
|
|
|
425
|
-
export { AuthStorage, type AutoUpdateConfig, type AutoUpdater, type InlineButton, type LogLevel, MOONSHOT_OAUTH_KEY, NotLoggedInError, type OAuthCredentials, type OAuthLoginCallbacks, type ProgressCallback, SubscriptionUsageError, type SubscriptionUsageProvider, type SubscriptionUsageSnapshot, type SubscriptionUsageWindow, TelegramBot, type TelegramConfig, type TelegramMessage, type TelegramUpdate, type TelegramVoiceMessage, XIAOMI_CREDITS_KEY, closeLogger, createAutoUpdater, decodeOggOpus, downmixToMono, fetchSubscriptionUsage, generatePKCE, getClaudeCliUserAgent, getClaudeCodeVersion, getNextThinkingLevel, getSessionId, getSupportedThinkingLevels, isKimiCodingEndpoint, isLoggerOpen, isModelLoaded, isThinkingLevelSupported, kimiCodeBaseUrl, kimiCodingHeaders, log, loginAnthropic, loginGemini, loginKimi, loginOpenAI, openLog, refreshAnthropicToken, refreshGeminiToken, refreshKimiToken, refreshOpenAIToken, registerLogCleanup, resample, setProgressCallback, transcribeVoice, withFileLock };
|
|
449
|
+
export { AuthStorage, type AutoUpdateConfig, type AutoUpdater, type InlineButton, type LogLevel, MOONSHOT_OAUTH_KEY, NotLoggedInError, type OAuthCredentials, type OAuthLoginCallbacks, type ProgressCallback, SubscriptionUsageError, type SubscriptionUsageProvider, type SubscriptionUsageSnapshot, type SubscriptionUsageWindow, TelegramBot, type TelegramConfig, type TelegramMessage, type TelegramUpdate, type TelegramVoiceMessage, XIAOMI_CREDITS_KEY, closeLogger, createAutoUpdater, decodeOggOpus, downmixToMono, fetchSubscriptionUsage, generatePKCE, getClaudeCliUserAgent, getClaudeCodeVersion, getNextThinkingLevel, getSessionId, getSupportedThinkingLevels, isKimiCodingEndpoint, isLoggerOpen, isModelLoaded, isThinkingLevelSupported, kimiCodeBaseUrl, kimiCodingHeaders, log, loginAnthropic, loginGemini, loginKimi, loginOpenAI, openLog, readStoredBaseUrlSync, refreshAnthropicToken, refreshGeminiToken, refreshKimiToken, refreshOpenAIToken, registerLogCleanup, resample, setProgressCallback, transcribeVoice, withFileLock };
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
getClaudeCodeVersion,
|
|
14
14
|
getContextWindow,
|
|
15
15
|
getDefaultModel,
|
|
16
|
+
getDefaultThinkingLevel,
|
|
16
17
|
getFastModel,
|
|
17
18
|
getMaxThinkingLevel,
|
|
18
19
|
getModel,
|
|
@@ -31,6 +32,7 @@ import {
|
|
|
31
32
|
loginKimi,
|
|
32
33
|
loginOpenAI,
|
|
33
34
|
openLog,
|
|
35
|
+
readStoredBaseUrlSync,
|
|
34
36
|
refreshAnthropicToken,
|
|
35
37
|
refreshGeminiToken,
|
|
36
38
|
refreshKimiToken,
|
|
@@ -38,7 +40,7 @@ import {
|
|
|
38
40
|
registerLogCleanup,
|
|
39
41
|
usesOpenAICodexTransport,
|
|
40
42
|
withFileLock
|
|
41
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-TST5LJWL.js";
|
|
42
44
|
import {
|
|
43
45
|
getAppPaths
|
|
44
46
|
} from "./chunk-QNR6SNB2.js";
|
|
@@ -68,6 +70,7 @@ var ANTHROPIC_ADAPTIVE_THINKING_LEVELS = [
|
|
|
68
70
|
"high",
|
|
69
71
|
"max"
|
|
70
72
|
];
|
|
73
|
+
var MOONSHOT_K3_THINKING_LEVELS = ["low", "high", "max"];
|
|
71
74
|
function isOpenAIGptModel(provider, model) {
|
|
72
75
|
return provider === "openai" && model.startsWith("gpt-");
|
|
73
76
|
}
|
|
@@ -77,6 +80,9 @@ function isSakanaModel(provider) {
|
|
|
77
80
|
function isXaiModel(provider) {
|
|
78
81
|
return provider === "xai";
|
|
79
82
|
}
|
|
83
|
+
function isMoonshotK3Model(provider, model) {
|
|
84
|
+
return provider === "moonshot" && model === "kimi-k3";
|
|
85
|
+
}
|
|
80
86
|
function isAnthropicOpus48Or47Model(provider, model) {
|
|
81
87
|
return provider === "anthropic" && /opus-4-8|opus-4-7/.test(model);
|
|
82
88
|
}
|
|
@@ -101,6 +107,7 @@ function getSupportedThinkingLevels(provider, model) {
|
|
|
101
107
|
if (maxIndex2 === -1) return XAI_THINKING_LEVELS;
|
|
102
108
|
return XAI_THINKING_LEVELS.slice(0, maxIndex2 + 1);
|
|
103
109
|
}
|
|
110
|
+
if (isMoonshotK3Model(provider, model)) return MOONSHOT_K3_THINKING_LEVELS;
|
|
104
111
|
if (!isOpenAIGptModel(provider, model)) return [maxLevel];
|
|
105
112
|
const levels = model.startsWith("gpt-5.6-") ? OPENAI_GPT_56_THINKING_LEVELS : OPENAI_GPT_THINKING_LEVELS;
|
|
106
113
|
const maxIndex = levels.indexOf(maxLevel);
|
|
@@ -112,7 +119,7 @@ function isThinkingLevelSupported(provider, model, level) {
|
|
|
112
119
|
}
|
|
113
120
|
function getNextThinkingLevel(provider, model, current) {
|
|
114
121
|
const supportedLevels = getSupportedThinkingLevels(provider, model);
|
|
115
|
-
const shouldCycleLevels = isOpenAIGptModel(provider, model) || isAnthropicAdaptiveModel(provider, model) || isSakanaModel(provider) || isXaiModel(provider);
|
|
122
|
+
const shouldCycleLevels = isOpenAIGptModel(provider, model) || isAnthropicAdaptiveModel(provider, model) || isSakanaModel(provider) || isXaiModel(provider) || isMoonshotK3Model(provider, model);
|
|
116
123
|
if (!shouldCycleLevels) {
|
|
117
124
|
return current ? void 0 : supportedLevels[0];
|
|
118
125
|
}
|
|
@@ -764,6 +771,7 @@ export {
|
|
|
764
771
|
getClaudeCodeVersion,
|
|
765
772
|
getContextWindow,
|
|
766
773
|
getDefaultModel,
|
|
774
|
+
getDefaultThinkingLevel,
|
|
767
775
|
getFastModel,
|
|
768
776
|
getMaxThinkingLevel,
|
|
769
777
|
getModel,
|
|
@@ -786,6 +794,7 @@ export {
|
|
|
786
794
|
loginKimi,
|
|
787
795
|
loginOpenAI,
|
|
788
796
|
openLog,
|
|
797
|
+
readStoredBaseUrlSync,
|
|
789
798
|
refreshAnthropicToken,
|
|
790
799
|
refreshGeminiToken,
|
|
791
800
|
refreshKimiToken,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/thinking-level.ts","../src/provider-usage.ts","../src/telegram.ts","../src/voice-transcriber.ts","../src/auto-update.ts"],"sourcesContent":["import type { Provider, ThinkingLevel } from \"@kenkaiiii/gg-ai\";\nimport { getMaxThinkingLevel } from \"./model-registry.js\";\n\nconst OPENAI_GPT_THINKING_LEVELS: readonly ThinkingLevel[] = [\"medium\", \"high\", \"xhigh\"];\nconst OPENAI_GPT_56_THINKING_LEVELS: readonly ThinkingLevel[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\",\n \"max\",\n \"ultra\",\n];\n// Sakana Fugu accepts exactly two reasoning efforts — \"high\" and \"xhigh\" — and\n// rejects anything else. Expose both so users can pick the lighter tier instead\n// of being forced into all-or-nothing xhigh.\nconst SAKANA_THINKING_LEVELS: readonly ThinkingLevel[] = [\"high\", \"xhigh\"];\n// Grok reasoning models take reasoning_effort low/medium/high (server default\n// high; reasoning can't be fully disabled — \"off\" just omits the param).\nconst XAI_THINKING_LEVELS: readonly ThinkingLevel[] = [\"low\", \"medium\", \"high\"];\nconst ANTHROPIC_OPUS_48_47_THINKING_LEVELS: readonly ThinkingLevel[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\",\n \"max\",\n];\nconst ANTHROPIC_ADAPTIVE_THINKING_LEVELS: readonly ThinkingLevel[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"max\",\n];\n\nfunction isOpenAIGptModel(provider: Provider, model: string): boolean {\n return provider === \"openai\" && model.startsWith(\"gpt-\");\n}\n\nfunction isSakanaModel(provider: Provider): boolean {\n return provider === \"sakana\";\n}\n\nfunction isXaiModel(provider: Provider): boolean {\n return provider === \"xai\";\n}\n\nfunction isAnthropicOpus48Or47Model(provider: Provider, model: string): boolean {\n return provider === \"anthropic\" && /opus-4-8|opus-4-7/.test(model);\n}\n\nfunction isAnthropicAdaptiveModel(provider: Provider, model: string): boolean {\n return (\n provider === \"anthropic\" && /opus-4-8|opus-4-7|opus-4-6|sonnet-5|fable-5|mythos-5/.test(model)\n );\n}\n\nexport function getSupportedThinkingLevels(\n provider: Provider,\n model: string,\n): readonly ThinkingLevel[] {\n const maxLevel = getMaxThinkingLevel(model);\n if (isAnthropicAdaptiveModel(provider, model)) {\n const levels = isAnthropicOpus48Or47Model(provider, model)\n ? ANTHROPIC_OPUS_48_47_THINKING_LEVELS\n : ANTHROPIC_ADAPTIVE_THINKING_LEVELS;\n const maxIndex = levels.indexOf(maxLevel);\n if (maxIndex === -1) return [\"low\", \"medium\", \"high\"];\n return levels.slice(0, maxIndex + 1);\n }\n\n if (isSakanaModel(provider)) {\n const maxIndex = SAKANA_THINKING_LEVELS.indexOf(maxLevel);\n if (maxIndex === -1) return SAKANA_THINKING_LEVELS;\n return SAKANA_THINKING_LEVELS.slice(0, maxIndex + 1);\n }\n\n if (isXaiModel(provider)) {\n const maxIndex = XAI_THINKING_LEVELS.indexOf(maxLevel);\n if (maxIndex === -1) return XAI_THINKING_LEVELS;\n return XAI_THINKING_LEVELS.slice(0, maxIndex + 1);\n }\n\n if (!isOpenAIGptModel(provider, model)) return [maxLevel];\n\n const levels = model.startsWith(\"gpt-5.6-\")\n ? OPENAI_GPT_56_THINKING_LEVELS\n : OPENAI_GPT_THINKING_LEVELS;\n const maxIndex = levels.indexOf(maxLevel);\n if (maxIndex === -1) return [\"medium\"];\n return levels.slice(0, maxIndex + 1);\n}\n\nexport function isThinkingLevelSupported(\n provider: Provider,\n model: string,\n level: ThinkingLevel,\n): boolean {\n return getSupportedThinkingLevels(provider, model).includes(level);\n}\n\nexport function getNextThinkingLevel(\n provider: Provider,\n model: string,\n current: ThinkingLevel | undefined,\n): ThinkingLevel | undefined {\n const supportedLevels = getSupportedThinkingLevels(provider, model);\n const shouldCycleLevels =\n isOpenAIGptModel(provider, model) ||\n isAnthropicAdaptiveModel(provider, model) ||\n isSakanaModel(provider) ||\n isXaiModel(provider);\n if (!shouldCycleLevels) {\n return current ? undefined : supportedLevels[0];\n }\n\n if (!current) return supportedLevels[0];\n const index = supportedLevels.indexOf(current);\n if (index === -1) return supportedLevels[0];\n return supportedLevels[index + 1];\n}\n","import type { OAuthCredentials } from \"./oauth/types.js\";\n\nexport type SubscriptionUsageProvider = \"anthropic\" | \"openai\";\n\nexport interface SubscriptionUsageWindow {\n kind: \"current\" | \"weekly\";\n label: string;\n usedPercent: number;\n /** Unix epoch milliseconds. */\n resetsAt?: number;\n}\n\nexport interface SubscriptionUsageSnapshot {\n provider: SubscriptionUsageProvider;\n displayName: string;\n windows: SubscriptionUsageWindow[];\n fetchedAt: number;\n}\n\nexport class SubscriptionUsageError extends Error {\n constructor(\n message: string,\n readonly status?: number,\n ) {\n super(message);\n this.name = \"SubscriptionUsageError\";\n }\n}\n\ntype FetchFn = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;\n\ninterface FetchSubscriptionUsageOptions {\n fetchFn?: FetchFn;\n timeoutMs?: number;\n now?: () => number;\n}\n\ninterface AnthropicWindow {\n utilization?: unknown;\n resets_at?: unknown;\n}\n\ninterface AnthropicUsageResponse {\n five_hour?: AnthropicWindow | null;\n seven_day?: AnthropicWindow | null;\n}\n\ninterface CodexWindow {\n limit_window_seconds?: unknown;\n used_percent?: unknown;\n reset_at?: unknown;\n reset_after_seconds?: unknown;\n}\n\ninterface CodexUsageResponse {\n rate_limit?: {\n primary_window?: CodexWindow | null;\n secondary_window?: CodexWindow | null;\n } | null;\n}\n\nconst ANTHROPIC_USAGE_URL = \"https://api.anthropic.com/api/oauth/usage\";\nconst CODEX_USAGE_URL = \"https://chatgpt.com/backend-api/wham/usage\";\n\nfunction finiteNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction clampPercent(value: unknown): number | undefined {\n const number = finiteNumber(value);\n return number === undefined ? undefined : Math.min(100, Math.max(0, number));\n}\n\nfunction isoTimestamp(value: unknown): number | undefined {\n if (typeof value !== \"string\" || !value.trim()) return undefined;\n const timestamp = Date.parse(value);\n return Number.isFinite(timestamp) ? timestamp : undefined;\n}\n\nfunction unixTimestamp(value: unknown): number | undefined {\n const seconds = finiteNumber(value);\n return seconds === undefined ? undefined : seconds * 1000;\n}\n\nfunction codexResetAt(window: CodexWindow, now: number): number | undefined {\n const absolute = unixTimestamp(window.reset_at);\n if (absolute !== undefined) return absolute;\n const afterSeconds = finiteNumber(window.reset_after_seconds);\n return afterSeconds === undefined ? undefined : now + afterSeconds * 1000;\n}\n\nfunction currentWindowLabel(seconds: unknown, fallbackHours: number): string {\n const duration = finiteNumber(seconds);\n const hours = Math.max(1, Math.round((duration ?? fallbackHours * 3600) / 3600));\n return `${hours}-hour`;\n}\n\nfunction codexWindowKind(\n window: CodexWindow,\n fallback: \"current\" | \"weekly\",\n): \"current\" | \"weekly\" {\n const duration = finiteNumber(window.limit_window_seconds);\n if (duration === undefined) return fallback;\n // The API can put its seven-day limit in either primary or secondary.\n // Classify by duration without mislabeling a future 24-hour window as weekly.\n return duration >= 6 * 24 * 60 * 60 ? \"weekly\" : \"current\";\n}\n\nfunction normalizedCodexWindow(\n window: CodexWindow | null | undefined,\n fallbackKind: \"current\" | \"weekly\",\n now: number,\n): SubscriptionUsageWindow | null {\n if (!window) return null;\n const usedPercent = clampPercent(window.used_percent);\n if (usedPercent === undefined) return null;\n const kind = codexWindowKind(window, fallbackKind);\n return {\n kind,\n label: kind === \"weekly\" ? \"Weekly\" : currentWindowLabel(window.limit_window_seconds, 5),\n usedPercent,\n resetsAt: codexResetAt(window, now),\n };\n}\n\nasync function readUsageResponse(response: Response): Promise<unknown> {\n const text = await response.text();\n if (!response.ok) {\n throw new SubscriptionUsageError(\n `Subscription usage request failed with HTTP ${response.status}`,\n response.status,\n );\n }\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw new SubscriptionUsageError(\"Subscription usage response was not valid JSON\");\n }\n}\n\nasync function fetchAnthropicUsage(\n credentials: Pick<OAuthCredentials, \"accessToken\">,\n fetchFn: FetchFn,\n signal: AbortSignal,\n now: () => number,\n): Promise<SubscriptionUsageSnapshot> {\n const response = await fetchFn(ANTHROPIC_USAGE_URL, {\n method: \"GET\",\n signal,\n headers: {\n Authorization: `Bearer ${credentials.accessToken}`,\n Accept: \"application/json\",\n \"anthropic-version\": \"2023-06-01\",\n \"anthropic-beta\": \"oauth-2025-04-20\",\n \"User-Agent\": \"ggcoder\",\n },\n });\n const data = (await readUsageResponse(response)) as AnthropicUsageResponse;\n const windows: SubscriptionUsageWindow[] = [];\n const currentPercent = clampPercent(data.five_hour?.utilization);\n if (currentPercent !== undefined) {\n windows.push({\n kind: \"current\",\n label: \"5-hour\",\n usedPercent: currentPercent,\n resetsAt: isoTimestamp(data.five_hour?.resets_at),\n });\n }\n const weeklyPercent = clampPercent(data.seven_day?.utilization);\n if (weeklyPercent !== undefined) {\n windows.push({\n kind: \"weekly\",\n label: \"Weekly\",\n usedPercent: weeklyPercent,\n resetsAt: isoTimestamp(data.seven_day?.resets_at),\n });\n }\n return {\n provider: \"anthropic\",\n displayName: \"Anthropic\",\n windows,\n fetchedAt: now(),\n };\n}\n\nasync function fetchCodexUsage(\n credentials: Pick<OAuthCredentials, \"accessToken\" | \"accountId\">,\n fetchFn: FetchFn,\n signal: AbortSignal,\n now: () => number,\n): Promise<SubscriptionUsageSnapshot> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${credentials.accessToken}`,\n Accept: \"application/json\",\n originator: \"ggcoder\",\n \"User-Agent\": \"ggcoder\",\n };\n if (credentials.accountId) headers[\"ChatGPT-Account-Id\"] = credentials.accountId;\n const response = await fetchFn(CODEX_USAGE_URL, { method: \"GET\", signal, headers });\n const data = (await readUsageResponse(response)) as CodexUsageResponse;\n const windows = [\n normalizedCodexWindow(data.rate_limit?.primary_window, \"current\", now()),\n normalizedCodexWindow(data.rate_limit?.secondary_window, \"weekly\", now()),\n ].filter((window): window is SubscriptionUsageWindow => window !== null);\n windows.sort((left, right) => {\n if (left.kind === right.kind) return 0;\n return left.kind === \"current\" ? -1 : 1;\n });\n return {\n provider: \"openai\",\n displayName: \"Codex\",\n windows,\n fetchedAt: now(),\n };\n}\n\n/**\n * Fetch subscription quota windows with an already-resolved OAuth credential.\n * Tokens stay server-side: callers expose only the normalized percentages and\n * reset timestamps to their UI.\n */\nexport async function fetchSubscriptionUsage(\n provider: SubscriptionUsageProvider,\n credentials: Pick<OAuthCredentials, \"accessToken\" | \"accountId\">,\n options: FetchSubscriptionUsageOptions = {},\n): Promise<SubscriptionUsageSnapshot> {\n const fetchFn = options.fetchFn ?? fetch;\n const now = options.now ?? Date.now;\n const signal = AbortSignal.timeout(options.timeoutMs ?? 8_000);\n try {\n return provider === \"anthropic\"\n ? await fetchAnthropicUsage(credentials, fetchFn, signal, now)\n : await fetchCodexUsage(credentials, fetchFn, signal, now);\n } catch (error) {\n if (error instanceof SubscriptionUsageError) throw error;\n const message = error instanceof Error ? error.message : String(error);\n throw new SubscriptionUsageError(message);\n }\n}\n","/**\n * Minimal Telegram Bot API client using raw fetch().\n * Supports long polling, markdown messages, inline keyboards, and message splitting.\n */\n\nconst TELEGRAM_API = \"https://api.telegram.org\";\nconst MAX_MESSAGE_LENGTH = 4096;\n\nexport interface TelegramConfig {\n botToken: string;\n /** Only accept messages from this Telegram user ID. */\n allowedUserId: number;\n}\n\nexport interface TelegramUpdate {\n update_id: number;\n message?: {\n message_id: number;\n from: { id: number; first_name: string };\n chat: { id: number; type: string; title?: string };\n text?: string;\n voice?: { file_id: string; duration: number; mime_type?: string; file_size?: number };\n };\n callback_query?: {\n id: string;\n from: { id: number };\n message: { chat: { id: number } };\n data: string;\n };\n my_chat_member?: {\n chat: { id: number; type: string; title?: string };\n from: { id: number };\n new_chat_member: { status: string };\n };\n}\n\nexport interface InlineButton {\n text: string;\n callback_data: string;\n}\n\n/** Incoming message with chat context. */\nexport interface TelegramMessage {\n text: string;\n chatId: number;\n chatType: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n chatTitle?: string;\n}\n\n/** Incoming voice note with chat context. */\nexport interface TelegramVoiceMessage {\n fileId: string;\n duration: number;\n chatId: number;\n chatType: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n chatTitle?: string;\n}\n\nexport class TelegramBot {\n private token: string;\n private allowedUserId: number;\n private offset = 0;\n private running = false;\n\n private onMessage: ((msg: TelegramMessage) => void) | null = null;\n private onVoiceMessage: ((msg: TelegramVoiceMessage) => void) | null = null;\n private onCallback: ((data: string, chatId: number) => void) | null = null;\n private onBotAdded: ((chatId: number, chatTitle?: string) => void) | null = null;\n private onBotRemoved: ((chatId: number) => void) | null = null;\n\n constructor(config: TelegramConfig) {\n this.token = config.botToken;\n this.allowedUserId = config.allowedUserId;\n }\n\n /** Register handler for incoming text messages. */\n onText(handler: (msg: TelegramMessage) => void): void {\n this.onMessage = handler;\n }\n\n /** Register handler for incoming voice notes. */\n onVoice(handler: (msg: TelegramVoiceMessage) => void): void {\n this.onVoiceMessage = handler;\n }\n\n /** Register handler for inline keyboard button presses. */\n onCallbackQuery(handler: (data: string, chatId: number) => void): void {\n this.onCallback = handler;\n }\n\n /** Register handler for when the bot is added to a group. */\n onAddedToGroup(handler: (chatId: number, chatTitle?: string) => void): void {\n this.onBotAdded = handler;\n }\n\n /** Register handler for when the bot is removed from a group. */\n onRemovedFromGroup(handler: (chatId: number) => void): void {\n this.onBotRemoved = handler;\n }\n\n /** Start long polling. Blocks until stop() is called. */\n async start(): Promise<void> {\n this.running = true;\n\n // Verify bot token works\n const me = await this.apiCall(\"getMe\");\n if (!me.ok) {\n throw new Error(`Invalid bot token: ${JSON.stringify(me)}`);\n }\n\n while (this.running) {\n try {\n const updates = await this.getUpdates();\n for (const update of updates) {\n await this.handleUpdate(update);\n }\n } catch (err) {\n if (!this.running) break;\n console.error(`[telegram] Poll error: ${err instanceof Error ? err.message : err}`);\n await sleep(3000);\n }\n }\n }\n\n /** Stop long polling. */\n stop(): void {\n this.running = false;\n }\n\n /** Send a text message to a specific chat. Converts markdown and splits long messages. */\n async send(chatId: number, text: string, buttons?: InlineButton[][]): Promise<void> {\n const converted = toTelegramMarkdown(text);\n const chunks = splitMessage(converted);\n\n for (let i = 0; i < chunks.length; i++) {\n const isLast = i === chunks.length - 1;\n const replyMarkup =\n isLast && buttons\n ? {\n inline_keyboard: buttons.map((row) =>\n row.map((b) => ({ text: b.text, callback_data: b.callback_data })),\n ),\n }\n : undefined;\n\n await this.apiCall(\"sendMessage\", {\n chat_id: chatId,\n text: chunks[i],\n parse_mode: \"Markdown\",\n ...(replyMarkup ? { reply_markup: replyMarkup } : {}),\n });\n }\n }\n\n /** Send a plain text message (no markdown parsing) to a specific chat. */\n async sendPlain(chatId: number, text: string): Promise<void> {\n const chunks = splitMessage(text);\n for (const chunk of chunks) {\n await this.apiCall(\"sendMessage\", {\n chat_id: chatId,\n text: chunk,\n });\n }\n }\n\n /** Send a typing indicator to a specific chat. */\n async sendTyping(chatId: number): Promise<void> {\n await this.apiCall(\"sendChatAction\", {\n chat_id: chatId,\n action: \"typing\",\n });\n }\n\n /** Get a direct download URL for a Telegram file. */\n async getFileUrl(fileId: string): Promise<string> {\n const result = await this.apiCall(\"getFile\", { file_id: fileId });\n if (!result.ok) throw new Error(`Failed to get file: ${JSON.stringify(result)}`);\n const filePath = (result.result as { file_path: string }).file_path;\n return `${TELEGRAM_API}/file/bot${this.token}/${filePath}`;\n }\n\n // ── Private ───────────────────────────────────────────\n\n private async getUpdates(): Promise<TelegramUpdate[]> {\n const result = await this.apiCall(\"getUpdates\", {\n offset: this.offset,\n timeout: 30,\n allowed_updates: [\"message\", \"callback_query\", \"my_chat_member\"],\n });\n\n if (!result.ok || !Array.isArray(result.result)) return [];\n\n const updates = result.result as TelegramUpdate[];\n if (updates.length > 0) {\n this.offset = updates[updates.length - 1]!.update_id + 1;\n }\n return updates;\n }\n\n private async handleUpdate(update: TelegramUpdate): Promise<void> {\n if (update.message) {\n const msg = update.message;\n\n // Auth check\n if (msg.from.id !== this.allowedUserId) {\n return;\n }\n\n if (msg.text && this.onMessage) {\n this.onMessage({\n text: msg.text,\n chatId: msg.chat.id,\n chatType: msg.chat.type as TelegramMessage[\"chatType\"],\n chatTitle: msg.chat.title,\n });\n } else if (msg.voice && this.onVoiceMessage) {\n this.onVoiceMessage({\n fileId: msg.voice.file_id,\n duration: msg.voice.duration,\n chatId: msg.chat.id,\n chatType: msg.chat.type as TelegramMessage[\"chatType\"],\n chatTitle: msg.chat.title,\n });\n }\n }\n\n // Bot membership changed in a group\n if (update.my_chat_member) {\n const member = update.my_chat_member;\n const status = member.new_chat_member.status;\n if ((status === \"member\" || status === \"administrator\") && this.onBotAdded) {\n this.onBotAdded(member.chat.id, member.chat.title);\n } else if ((status === \"left\" || status === \"kicked\") && this.onBotRemoved) {\n this.onBotRemoved(member.chat.id);\n }\n }\n\n if (update.callback_query) {\n const cb = update.callback_query;\n\n if (cb.from.id !== this.allowedUserId) return;\n\n await this.apiCall(\"answerCallbackQuery\", { callback_query_id: cb.id });\n\n if (cb.data && this.onCallback) {\n this.onCallback(cb.data, cb.message.chat.id);\n }\n }\n }\n\n private async apiCall(\n method: string,\n body?: Record<string, unknown>,\n ): Promise<{ ok: boolean; result?: unknown }> {\n const url = `${TELEGRAM_API}/bot${this.token}/${method}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n return { ok: false };\n }\n\n return response.json() as Promise<{ ok: boolean; result?: unknown }>;\n }\n}\n\n// ── Markdown Conversion ──────────────────────────────────\n\n/**\n * Convert GitHub-flavored markdown to Telegram-compatible Markdown.\n *\n * Telegram supports: *bold*, _italic_, `code`, ```pre```, [link](url)\n * Does NOT support: headings, horizontal rules, tables, HTML tags, images\n */\nfunction toTelegramMarkdown(text: string): string {\n const lines = text.split(\"\\n\");\n const result: string[] = [];\n let inCodeBlock = false;\n\n for (const line of lines) {\n if (line.trimStart().startsWith(\"```\")) {\n inCodeBlock = !inCodeBlock;\n result.push(line);\n continue;\n }\n\n if (inCodeBlock) {\n result.push(line);\n continue;\n }\n\n let transformed = line;\n\n // Headings → bold text\n const headingMatch = transformed.match(/^(#{1,6})\\s+(.+)$/);\n if (headingMatch) {\n transformed = `*${headingMatch[2]}*`;\n result.push(transformed);\n continue;\n }\n\n // Horizontal rules → empty line\n if (/^(-{3,}|_{3,}|\\*{3,})$/.test(transformed.trim())) {\n result.push(\"\");\n continue;\n }\n\n // **bold** → *bold*\n transformed = transformed.replace(/\\*\\*(.+?)\\*\\*/g, \"*$1*\");\n\n result.push(transformed);\n }\n\n return result.join(\"\\n\");\n}\n\n// ── Helpers ───────────────────────────────────────────────\n\nfunction splitMessage(text: string): string[] {\n if (text.length <= MAX_MESSAGE_LENGTH) return [text];\n\n const chunks: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= MAX_MESSAGE_LENGTH) {\n chunks.push(remaining);\n break;\n }\n\n let splitAt = remaining.lastIndexOf(\"\\n\", MAX_MESSAGE_LENGTH);\n if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {\n splitAt = remaining.lastIndexOf(\" \", MAX_MESSAGE_LENGTH);\n }\n if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {\n splitAt = MAX_MESSAGE_LENGTH;\n }\n\n chunks.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt).trimStart();\n }\n\n return chunks;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","/**\n * Voice note transcription using local Whisper model.\n * Uses @huggingface/transformers (pure JS/WASM) — no native deps, no API keys.\n * Model (~75MB) is downloaded on first use and cached locally.\n */\n\nimport type { AutomaticSpeechRecognitionPipeline } from \"@huggingface/transformers\";\n\nconst TARGET_SAMPLE_RATE = 16000;\nconst MODEL_ID = \"Xenova/whisper-tiny.en\";\n\nlet transcriber: AutomaticSpeechRecognitionPipeline | null = null;\nlet loadPromise: Promise<AutomaticSpeechRecognitionPipeline> | null = null;\n\n/** Optional callback for model download progress. */\nexport type ProgressCallback = (info: { status: string; progress?: number; file?: string }) => void;\n\nlet onProgress: ProgressCallback | null = null;\n\n/** Set a callback to receive model download progress updates. */\nexport function setProgressCallback(cb: ProgressCallback | null): void {\n onProgress = cb;\n}\n\n/**\n * Resample audio from one sample rate to another using linear interpolation.\n */\nexport function resample(audio: Float32Array, fromRate: number, toRate: number): Float32Array {\n if (fromRate === toRate) return audio;\n const ratio = fromRate / toRate;\n const newLength = Math.round(audio.length / ratio);\n const result = new Float32Array(newLength);\n for (let i = 0; i < newLength; i++) {\n const srcIndex = i * ratio;\n const low = Math.floor(srcIndex);\n const high = Math.min(low + 1, audio.length - 1);\n const frac = srcIndex - low;\n result[i] = audio[low]! * (1 - frac) + audio[high]! * frac;\n }\n return result;\n}\n\n/**\n * Downmix multi-channel audio to mono by averaging all channels.\n */\nexport function downmixToMono(channelData: Float32Array[]): Float32Array {\n if (channelData.length === 0) return new Float32Array();\n if (channelData.length === 1) return channelData[0]!;\n\n const samples = channelData[0]!.length;\n const out = new Float32Array(samples);\n const scale = 1 / channelData.length;\n for (let i = 0; i < samples; i++) {\n let mixed = 0;\n for (const channel of channelData) mixed += channel[i] ?? 0;\n out[i] = mixed * scale;\n }\n return out;\n}\n\n/**\n * Decode OGG Opus audio buffer to 16kHz mono PCM Float32Array.\n */\nexport async function decodeOggOpus(buffer: Uint8Array): Promise<Float32Array> {\n const { OggOpusDecoder } = await import(\"ogg-opus-decoder\");\n const decoder = new OggOpusDecoder();\n await decoder.ready;\n try {\n const decoded = await decoder.decodeFile(buffer);\n\n if (!decoded.channelData?.length || !decoded.channelData[0]?.length) {\n throw new Error(\"Decoded audio is empty\");\n }\n\n const mono = downmixToMono(decoded.channelData);\n return resample(mono, decoded.sampleRate, TARGET_SAMPLE_RATE);\n } finally {\n decoder.free();\n }\n}\n\n/**\n * Get or initialize the Whisper transcription pipeline.\n * Model is downloaded on first use and cached by transformers.js.\n */\nasync function getTranscriber(): Promise<AutomaticSpeechRecognitionPipeline> {\n if (transcriber) return transcriber;\n\n if (!loadPromise) {\n loadPromise = (async () => {\n const { pipeline } = await import(\"@huggingface/transformers\");\n const instance = await pipeline(\"automatic-speech-recognition\", MODEL_ID, {\n dtype: \"fp32\",\n progress_callback: onProgress ?? undefined,\n });\n transcriber = instance;\n return instance;\n })();\n }\n\n return loadPromise;\n}\n\n/** Whether the model has been loaded already. */\nexport function isModelLoaded(): boolean {\n return transcriber !== null;\n}\n\n/**\n * Transcribe a voice message from its Telegram file URL.\n * Downloads the OGG Opus file, decodes to PCM, and runs Whisper locally.\n */\nexport async function transcribeVoice(fileUrl: string): Promise<string> {\n // Download the audio file\n const response = await fetch(fileUrl);\n if (!response.ok) throw new Error(`Failed to download voice file: ${response.status}`);\n const buffer = new Uint8Array(await response.arrayBuffer());\n\n // Decode OGG Opus → 16kHz mono PCM\n const pcm = await decodeOggOpus(buffer);\n\n // Transcribe with Whisper\n const asr = await getTranscriber();\n const result = await asr(pcm);\n\n const text = Array.isArray(result) ? result[0]?.text : (result as { text: string }).text;\n return (text ?? \"\").trim();\n}\n","import { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Provider-agnostic background self-updater. Each app composes its own instance\n * via `createAutoUpdater` with its npm package name and state-file path, so the\n * update logic (registry poll, version compare, detached install, throttling)\n * lives in exactly one place while branding stays in the apps.\n */\n\ninterface UpdateState {\n lastCheckedAt: number;\n latestVersion?: string;\n updatePending?: boolean;\n lastUpdateAttempt?: number;\n}\n\nenum PackageManager {\n NPM = \"npm\",\n PNPM = \"pnpm\",\n YARN = \"yarn\",\n UNKNOWN = \"unknown\",\n}\n\ninterface InstallInfo {\n packageManager: PackageManager;\n updateCommand: string | null;\n}\n\nexport interface AutoUpdateConfig {\n /** npm package to self-update, e.g. \"@kenkaiiii/ggcoder\". */\n packageName: string;\n /**\n * Absolute path to this app's update-state.json, or a thunk resolving it.\n * A thunk keeps path resolution lazy so callers can derive it from\n * `os.homedir()` without freezing the value at module-load time (which\n * breaks tests that mock the home directory after import).\n */\n stateFilePath: string | (() => string);\n /** Builds the in-session \"update available\" notification. */\n periodicMessage?: (args: {\n currentVersion: string;\n latestVersion: string;\n updateCommand: string;\n }) => string;\n}\n\nexport interface AutoUpdater {\n checkAndAutoUpdate(currentVersion: string): string | null;\n getPendingUpdate(currentVersion: string): { latestVersion: string } | null;\n startPeriodicUpdateCheck(currentVersion: string, onUpdate: (message: string) => void): void;\n stopPeriodicUpdateCheck(): void;\n}\n\nconst CHECK_INTERVAL_MS = 60 * 60 * 1000; // 1 hour\nconst FETCH_TIMEOUT_MS = 10_000; // 10s — npm can be slow\n\nfunction compareVersions(a: string, b: string): number {\n const pa = a.split(\".\").map(Number);\n const pb = b.split(\".\").map(Number);\n for (let i = 0; i < 3; i++) {\n const diff = (pa[i] ?? 0) - (pb[i] ?? 0);\n if (diff !== 0) return diff;\n }\n return 0;\n}\n\nfunction performUpdateInBackground(command: string): void {\n try {\n const parts = command.split(\" \");\n const child = spawn(parts[0]!, parts.slice(1), {\n detached: true,\n stdio: \"ignore\",\n env: { ...process.env, npm_config_loglevel: \"silent\" },\n });\n child.unref();\n } catch {\n // Non-fatal — will retry next startup\n }\n}\n\nexport function createAutoUpdater(config: AutoUpdateConfig): AutoUpdater {\n const REGISTRY_URL = `https://registry.npmjs.org/${config.packageName}/latest`;\n const periodicMessage =\n config.periodicMessage ??\n (({ currentVersion, latestVersion, updateCommand }) =>\n `Ken just pushed a fresh update — ${currentVersion} → ${latestVersion}! I'll grab it on next launch (or run ${updateCommand} if you can't wait).`);\n\n let periodicTimer: ReturnType<typeof setInterval> | null = null;\n\n function stateFilePath(): string {\n return typeof config.stateFilePath === \"function\"\n ? config.stateFilePath()\n : config.stateFilePath;\n }\n\n function readState(): UpdateState | null {\n try {\n const raw = fs.readFileSync(stateFilePath(), \"utf-8\");\n return JSON.parse(raw) as UpdateState;\n } catch {\n return null;\n }\n }\n\n function writeState(state: UpdateState): void {\n try {\n const filePath = stateFilePath();\n fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });\n fs.writeFileSync(filePath, JSON.stringify(state));\n } catch {\n // Non-fatal\n }\n }\n\n function detectInstallInfo(): InstallInfo {\n const scriptPath = (process.argv[1] ?? \"\").replace(/\\\\/g, \"/\");\n\n // npx — skip (ephemeral)\n if (scriptPath.includes(\"/_npx/\")) {\n return { packageManager: PackageManager.UNKNOWN, updateCommand: null };\n }\n\n // pnpm global\n if (scriptPath.includes(\"/.pnpm\") || scriptPath.includes(\"/pnpm/global\")) {\n return {\n packageManager: PackageManager.PNPM,\n updateCommand: `pnpm add -g ${config.packageName}@latest`,\n };\n }\n\n // yarn global\n if (scriptPath.includes(\"/.yarn/\") || scriptPath.includes(\"/yarn/global\")) {\n return {\n packageManager: PackageManager.YARN,\n updateCommand: `yarn global add ${config.packageName}@latest`,\n };\n }\n\n // npm global (default)\n return {\n packageManager: PackageManager.NPM,\n updateCommand: `npm install -g ${config.packageName}@latest`,\n };\n }\n\n async function fetchLatestVersion(): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n const response = await fetch(REGISTRY_URL, { signal: controller.signal });\n clearTimeout(timeout);\n const data = (await response.json()) as { version?: string };\n const version = data.version?.trim();\n return version && /^\\d+\\.\\d+\\.\\d+/.test(version) ? version : null;\n } catch {\n return null;\n }\n }\n\n function scheduleBackgroundCheck(currentVersion: string): void {\n fetchLatestVersion()\n .then((latestVersion) => {\n const newState: UpdateState = {\n lastCheckedAt: Date.now(),\n latestVersion: latestVersion ?? undefined,\n updatePending: false,\n };\n if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) {\n newState.updatePending = true;\n }\n writeState(newState);\n })\n .catch(() => {\n // Non-fatal — will retry next time\n });\n }\n\n function checkAndAutoUpdate(currentVersion: string): string | null {\n try {\n const state = readState();\n let message: string | null = null;\n\n // Phase 1: Apply pending update from previous check\n if (state?.updatePending && state.latestVersion) {\n if (compareVersions(state.latestVersion, currentVersion) > 0) {\n const info = detectInstallInfo();\n if (info.updateCommand) {\n performUpdateInBackground(info.updateCommand);\n message = `Ken just shipped ${state.latestVersion}! Installing in the background — takes effect next launch.`;\n writeState({\n ...state,\n lastCheckedAt: Date.now(),\n updatePending: false,\n lastUpdateAttempt: Date.now(),\n });\n }\n } else {\n // Already on latest (user may have updated manually)\n writeState({ ...state, updatePending: false });\n }\n }\n\n // Phase 2: Schedule background check for next startup\n const shouldCheck = !state || Date.now() - state.lastCheckedAt > CHECK_INTERVAL_MS;\n if (shouldCheck) scheduleBackgroundCheck(currentVersion);\n\n return message;\n } catch {\n return null;\n }\n }\n\n function getPendingUpdate(currentVersion: string): { latestVersion: string } | null {\n try {\n const state = readState();\n if (!state?.latestVersion) return null;\n if (compareVersions(state.latestVersion, currentVersion) <= 0) return null;\n return { latestVersion: state.latestVersion };\n } catch {\n return null;\n }\n }\n\n function startPeriodicUpdateCheck(\n currentVersion: string,\n onUpdate: (message: string) => void,\n ): void {\n if (periodicTimer) return; // Already running\n\n periodicTimer = setInterval(() => {\n fetchLatestVersion()\n .then((latestVersion) => {\n if (!latestVersion) return;\n if (compareVersions(latestVersion, currentVersion) <= 0) return;\n\n const info = detectInstallInfo();\n if (!info.updateCommand) return;\n\n writeState({ lastCheckedAt: Date.now(), latestVersion, updatePending: true });\n onUpdate(\n periodicMessage({ currentVersion, latestVersion, updateCommand: info.updateCommand }),\n );\n\n // Stop checking once we've notified\n stopPeriodicUpdateCheck();\n })\n .catch(() => {\n // Non-fatal\n });\n }, CHECK_INTERVAL_MS);\n\n // Don't keep the process alive just for update checks\n periodicTimer.unref();\n }\n\n function stopPeriodicUpdateCheck(): void {\n if (periodicTimer) {\n clearInterval(periodicTimer);\n periodicTimer = null;\n }\n }\n\n return {\n checkAndAutoUpdate,\n getPendingUpdate,\n startPeriodicUpdateCheck,\n stopPeriodicUpdateCheck,\n };\n}\n"],"mappings":"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","names":["levels","maxIndex"]}
|
|
1
|
+
{"version":3,"sources":["../src/thinking-level.ts","../src/provider-usage.ts","../src/telegram.ts","../src/voice-transcriber.ts","../src/auto-update.ts"],"sourcesContent":["import type { Provider, ThinkingLevel } from \"@kenkaiiii/gg-ai\";\nimport { getMaxThinkingLevel } from \"./model-registry.js\";\n\nconst OPENAI_GPT_THINKING_LEVELS: readonly ThinkingLevel[] = [\"medium\", \"high\", \"xhigh\"];\nconst OPENAI_GPT_56_THINKING_LEVELS: readonly ThinkingLevel[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\",\n \"max\",\n \"ultra\",\n];\n// Sakana Fugu accepts exactly two reasoning efforts — \"high\" and \"xhigh\" — and\n// rejects anything else. Expose both so users can pick the lighter tier instead\n// of being forced into all-or-nothing xhigh.\nconst SAKANA_THINKING_LEVELS: readonly ThinkingLevel[] = [\"high\", \"xhigh\"];\n// Grok reasoning models take reasoning_effort low/medium/high (server default\n// high; reasoning can't be fully disabled — \"off\" just omits the param).\nconst XAI_THINKING_LEVELS: readonly ThinkingLevel[] = [\"low\", \"medium\", \"high\"];\nconst ANTHROPIC_OPUS_48_47_THINKING_LEVELS: readonly ThinkingLevel[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\",\n \"max\",\n];\nconst ANTHROPIC_ADAPTIVE_THINKING_LEVELS: readonly ThinkingLevel[] = [\n \"low\",\n \"medium\",\n \"high\",\n \"max\",\n];\n// Kimi K3's effort ladder is declared server-side via /models think_efforts:\n// [\"low\",\"high\",\"max\"] on both the public API (default max) and the Kimi For\n// Coding OAuth endpoint (default high) — verified live 2026-07-21. Unlisted\n// efforts are rejected with a 400, so expose exactly the declared rungs.\nconst MOONSHOT_K3_THINKING_LEVELS: readonly ThinkingLevel[] = [\"low\", \"high\", \"max\"];\n\nfunction isOpenAIGptModel(provider: Provider, model: string): boolean {\n return provider === \"openai\" && model.startsWith(\"gpt-\");\n}\n\nfunction isSakanaModel(provider: Provider): boolean {\n return provider === \"sakana\";\n}\n\nfunction isXaiModel(provider: Provider): boolean {\n return provider === \"xai\";\n}\n\nfunction isMoonshotK3Model(provider: Provider, model: string): boolean {\n return provider === \"moonshot\" && model === \"kimi-k3\";\n}\n\nfunction isAnthropicOpus48Or47Model(provider: Provider, model: string): boolean {\n return provider === \"anthropic\" && /opus-4-8|opus-4-7/.test(model);\n}\n\nfunction isAnthropicAdaptiveModel(provider: Provider, model: string): boolean {\n return (\n provider === \"anthropic\" && /opus-4-8|opus-4-7|opus-4-6|sonnet-5|fable-5|mythos-5/.test(model)\n );\n}\n\nexport function getSupportedThinkingLevels(\n provider: Provider,\n model: string,\n): readonly ThinkingLevel[] {\n const maxLevel = getMaxThinkingLevel(model);\n if (isAnthropicAdaptiveModel(provider, model)) {\n const levels = isAnthropicOpus48Or47Model(provider, model)\n ? ANTHROPIC_OPUS_48_47_THINKING_LEVELS\n : ANTHROPIC_ADAPTIVE_THINKING_LEVELS;\n const maxIndex = levels.indexOf(maxLevel);\n if (maxIndex === -1) return [\"low\", \"medium\", \"high\"];\n return levels.slice(0, maxIndex + 1);\n }\n\n if (isSakanaModel(provider)) {\n const maxIndex = SAKANA_THINKING_LEVELS.indexOf(maxLevel);\n if (maxIndex === -1) return SAKANA_THINKING_LEVELS;\n return SAKANA_THINKING_LEVELS.slice(0, maxIndex + 1);\n }\n\n if (isXaiModel(provider)) {\n const maxIndex = XAI_THINKING_LEVELS.indexOf(maxLevel);\n if (maxIndex === -1) return XAI_THINKING_LEVELS;\n return XAI_THINKING_LEVELS.slice(0, maxIndex + 1);\n }\n\n if (isMoonshotK3Model(provider, model)) return MOONSHOT_K3_THINKING_LEVELS;\n\n if (!isOpenAIGptModel(provider, model)) return [maxLevel];\n\n const levels = model.startsWith(\"gpt-5.6-\")\n ? OPENAI_GPT_56_THINKING_LEVELS\n : OPENAI_GPT_THINKING_LEVELS;\n const maxIndex = levels.indexOf(maxLevel);\n if (maxIndex === -1) return [\"medium\"];\n return levels.slice(0, maxIndex + 1);\n}\n\nexport function isThinkingLevelSupported(\n provider: Provider,\n model: string,\n level: ThinkingLevel,\n): boolean {\n return getSupportedThinkingLevels(provider, model).includes(level);\n}\n\nexport function getNextThinkingLevel(\n provider: Provider,\n model: string,\n current: ThinkingLevel | undefined,\n): ThinkingLevel | undefined {\n const supportedLevels = getSupportedThinkingLevels(provider, model);\n const shouldCycleLevels =\n isOpenAIGptModel(provider, model) ||\n isAnthropicAdaptiveModel(provider, model) ||\n isSakanaModel(provider) ||\n isXaiModel(provider) ||\n isMoonshotK3Model(provider, model);\n if (!shouldCycleLevels) {\n return current ? undefined : supportedLevels[0];\n }\n\n if (!current) return supportedLevels[0];\n const index = supportedLevels.indexOf(current);\n if (index === -1) return supportedLevels[0];\n return supportedLevels[index + 1];\n}\n","import type { OAuthCredentials } from \"./oauth/types.js\";\n\nexport type SubscriptionUsageProvider = \"anthropic\" | \"openai\";\n\nexport interface SubscriptionUsageWindow {\n kind: \"current\" | \"weekly\";\n label: string;\n usedPercent: number;\n /** Unix epoch milliseconds. */\n resetsAt?: number;\n}\n\nexport interface SubscriptionUsageSnapshot {\n provider: SubscriptionUsageProvider;\n displayName: string;\n windows: SubscriptionUsageWindow[];\n fetchedAt: number;\n}\n\nexport class SubscriptionUsageError extends Error {\n constructor(\n message: string,\n readonly status?: number,\n ) {\n super(message);\n this.name = \"SubscriptionUsageError\";\n }\n}\n\ntype FetchFn = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;\n\ninterface FetchSubscriptionUsageOptions {\n fetchFn?: FetchFn;\n timeoutMs?: number;\n now?: () => number;\n}\n\ninterface AnthropicWindow {\n utilization?: unknown;\n resets_at?: unknown;\n}\n\ninterface AnthropicUsageResponse {\n five_hour?: AnthropicWindow | null;\n seven_day?: AnthropicWindow | null;\n}\n\ninterface CodexWindow {\n limit_window_seconds?: unknown;\n used_percent?: unknown;\n reset_at?: unknown;\n reset_after_seconds?: unknown;\n}\n\ninterface CodexUsageResponse {\n rate_limit?: {\n primary_window?: CodexWindow | null;\n secondary_window?: CodexWindow | null;\n } | null;\n}\n\nconst ANTHROPIC_USAGE_URL = \"https://api.anthropic.com/api/oauth/usage\";\nconst CODEX_USAGE_URL = \"https://chatgpt.com/backend-api/wham/usage\";\n\nfunction finiteNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction clampPercent(value: unknown): number | undefined {\n const number = finiteNumber(value);\n return number === undefined ? undefined : Math.min(100, Math.max(0, number));\n}\n\nfunction isoTimestamp(value: unknown): number | undefined {\n if (typeof value !== \"string\" || !value.trim()) return undefined;\n const timestamp = Date.parse(value);\n return Number.isFinite(timestamp) ? timestamp : undefined;\n}\n\nfunction unixTimestamp(value: unknown): number | undefined {\n const seconds = finiteNumber(value);\n return seconds === undefined ? undefined : seconds * 1000;\n}\n\nfunction codexResetAt(window: CodexWindow, now: number): number | undefined {\n const absolute = unixTimestamp(window.reset_at);\n if (absolute !== undefined) return absolute;\n const afterSeconds = finiteNumber(window.reset_after_seconds);\n return afterSeconds === undefined ? undefined : now + afterSeconds * 1000;\n}\n\nfunction currentWindowLabel(seconds: unknown, fallbackHours: number): string {\n const duration = finiteNumber(seconds);\n const hours = Math.max(1, Math.round((duration ?? fallbackHours * 3600) / 3600));\n return `${hours}-hour`;\n}\n\nfunction codexWindowKind(\n window: CodexWindow,\n fallback: \"current\" | \"weekly\",\n): \"current\" | \"weekly\" {\n const duration = finiteNumber(window.limit_window_seconds);\n if (duration === undefined) return fallback;\n // The API can put its seven-day limit in either primary or secondary.\n // Classify by duration without mislabeling a future 24-hour window as weekly.\n return duration >= 6 * 24 * 60 * 60 ? \"weekly\" : \"current\";\n}\n\nfunction normalizedCodexWindow(\n window: CodexWindow | null | undefined,\n fallbackKind: \"current\" | \"weekly\",\n now: number,\n): SubscriptionUsageWindow | null {\n if (!window) return null;\n const usedPercent = clampPercent(window.used_percent);\n if (usedPercent === undefined) return null;\n const kind = codexWindowKind(window, fallbackKind);\n return {\n kind,\n label: kind === \"weekly\" ? \"Weekly\" : currentWindowLabel(window.limit_window_seconds, 5),\n usedPercent,\n resetsAt: codexResetAt(window, now),\n };\n}\n\nasync function readUsageResponse(response: Response): Promise<unknown> {\n const text = await response.text();\n if (!response.ok) {\n throw new SubscriptionUsageError(\n `Subscription usage request failed with HTTP ${response.status}`,\n response.status,\n );\n }\n try {\n return JSON.parse(text) as unknown;\n } catch {\n throw new SubscriptionUsageError(\"Subscription usage response was not valid JSON\");\n }\n}\n\nasync function fetchAnthropicUsage(\n credentials: Pick<OAuthCredentials, \"accessToken\">,\n fetchFn: FetchFn,\n signal: AbortSignal,\n now: () => number,\n): Promise<SubscriptionUsageSnapshot> {\n const response = await fetchFn(ANTHROPIC_USAGE_URL, {\n method: \"GET\",\n signal,\n headers: {\n Authorization: `Bearer ${credentials.accessToken}`,\n Accept: \"application/json\",\n \"anthropic-version\": \"2023-06-01\",\n \"anthropic-beta\": \"oauth-2025-04-20\",\n \"User-Agent\": \"ggcoder\",\n },\n });\n const data = (await readUsageResponse(response)) as AnthropicUsageResponse;\n const windows: SubscriptionUsageWindow[] = [];\n const currentPercent = clampPercent(data.five_hour?.utilization);\n if (currentPercent !== undefined) {\n windows.push({\n kind: \"current\",\n label: \"5-hour\",\n usedPercent: currentPercent,\n resetsAt: isoTimestamp(data.five_hour?.resets_at),\n });\n }\n const weeklyPercent = clampPercent(data.seven_day?.utilization);\n if (weeklyPercent !== undefined) {\n windows.push({\n kind: \"weekly\",\n label: \"Weekly\",\n usedPercent: weeklyPercent,\n resetsAt: isoTimestamp(data.seven_day?.resets_at),\n });\n }\n return {\n provider: \"anthropic\",\n displayName: \"Anthropic\",\n windows,\n fetchedAt: now(),\n };\n}\n\nasync function fetchCodexUsage(\n credentials: Pick<OAuthCredentials, \"accessToken\" | \"accountId\">,\n fetchFn: FetchFn,\n signal: AbortSignal,\n now: () => number,\n): Promise<SubscriptionUsageSnapshot> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${credentials.accessToken}`,\n Accept: \"application/json\",\n originator: \"ggcoder\",\n \"User-Agent\": \"ggcoder\",\n };\n if (credentials.accountId) headers[\"ChatGPT-Account-Id\"] = credentials.accountId;\n const response = await fetchFn(CODEX_USAGE_URL, { method: \"GET\", signal, headers });\n const data = (await readUsageResponse(response)) as CodexUsageResponse;\n const windows = [\n normalizedCodexWindow(data.rate_limit?.primary_window, \"current\", now()),\n normalizedCodexWindow(data.rate_limit?.secondary_window, \"weekly\", now()),\n ].filter((window): window is SubscriptionUsageWindow => window !== null);\n windows.sort((left, right) => {\n if (left.kind === right.kind) return 0;\n return left.kind === \"current\" ? -1 : 1;\n });\n return {\n provider: \"openai\",\n displayName: \"Codex\",\n windows,\n fetchedAt: now(),\n };\n}\n\n/**\n * Fetch subscription quota windows with an already-resolved OAuth credential.\n * Tokens stay server-side: callers expose only the normalized percentages and\n * reset timestamps to their UI.\n */\nexport async function fetchSubscriptionUsage(\n provider: SubscriptionUsageProvider,\n credentials: Pick<OAuthCredentials, \"accessToken\" | \"accountId\">,\n options: FetchSubscriptionUsageOptions = {},\n): Promise<SubscriptionUsageSnapshot> {\n const fetchFn = options.fetchFn ?? fetch;\n const now = options.now ?? Date.now;\n const signal = AbortSignal.timeout(options.timeoutMs ?? 8_000);\n try {\n return provider === \"anthropic\"\n ? await fetchAnthropicUsage(credentials, fetchFn, signal, now)\n : await fetchCodexUsage(credentials, fetchFn, signal, now);\n } catch (error) {\n if (error instanceof SubscriptionUsageError) throw error;\n const message = error instanceof Error ? error.message : String(error);\n throw new SubscriptionUsageError(message);\n }\n}\n","/**\n * Minimal Telegram Bot API client using raw fetch().\n * Supports long polling, markdown messages, inline keyboards, and message splitting.\n */\n\nconst TELEGRAM_API = \"https://api.telegram.org\";\nconst MAX_MESSAGE_LENGTH = 4096;\n\nexport interface TelegramConfig {\n botToken: string;\n /** Only accept messages from this Telegram user ID. */\n allowedUserId: number;\n}\n\nexport interface TelegramUpdate {\n update_id: number;\n message?: {\n message_id: number;\n from: { id: number; first_name: string };\n chat: { id: number; type: string; title?: string };\n text?: string;\n voice?: { file_id: string; duration: number; mime_type?: string; file_size?: number };\n };\n callback_query?: {\n id: string;\n from: { id: number };\n message: { chat: { id: number } };\n data: string;\n };\n my_chat_member?: {\n chat: { id: number; type: string; title?: string };\n from: { id: number };\n new_chat_member: { status: string };\n };\n}\n\nexport interface InlineButton {\n text: string;\n callback_data: string;\n}\n\n/** Incoming message with chat context. */\nexport interface TelegramMessage {\n text: string;\n chatId: number;\n chatType: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n chatTitle?: string;\n}\n\n/** Incoming voice note with chat context. */\nexport interface TelegramVoiceMessage {\n fileId: string;\n duration: number;\n chatId: number;\n chatType: \"private\" | \"group\" | \"supergroup\" | \"channel\";\n chatTitle?: string;\n}\n\nexport class TelegramBot {\n private token: string;\n private allowedUserId: number;\n private offset = 0;\n private running = false;\n\n private onMessage: ((msg: TelegramMessage) => void) | null = null;\n private onVoiceMessage: ((msg: TelegramVoiceMessage) => void) | null = null;\n private onCallback: ((data: string, chatId: number) => void) | null = null;\n private onBotAdded: ((chatId: number, chatTitle?: string) => void) | null = null;\n private onBotRemoved: ((chatId: number) => void) | null = null;\n\n constructor(config: TelegramConfig) {\n this.token = config.botToken;\n this.allowedUserId = config.allowedUserId;\n }\n\n /** Register handler for incoming text messages. */\n onText(handler: (msg: TelegramMessage) => void): void {\n this.onMessage = handler;\n }\n\n /** Register handler for incoming voice notes. */\n onVoice(handler: (msg: TelegramVoiceMessage) => void): void {\n this.onVoiceMessage = handler;\n }\n\n /** Register handler for inline keyboard button presses. */\n onCallbackQuery(handler: (data: string, chatId: number) => void): void {\n this.onCallback = handler;\n }\n\n /** Register handler for when the bot is added to a group. */\n onAddedToGroup(handler: (chatId: number, chatTitle?: string) => void): void {\n this.onBotAdded = handler;\n }\n\n /** Register handler for when the bot is removed from a group. */\n onRemovedFromGroup(handler: (chatId: number) => void): void {\n this.onBotRemoved = handler;\n }\n\n /** Start long polling. Blocks until stop() is called. */\n async start(): Promise<void> {\n this.running = true;\n\n // Verify bot token works\n const me = await this.apiCall(\"getMe\");\n if (!me.ok) {\n throw new Error(`Invalid bot token: ${JSON.stringify(me)}`);\n }\n\n while (this.running) {\n try {\n const updates = await this.getUpdates();\n for (const update of updates) {\n await this.handleUpdate(update);\n }\n } catch (err) {\n if (!this.running) break;\n console.error(`[telegram] Poll error: ${err instanceof Error ? err.message : err}`);\n await sleep(3000);\n }\n }\n }\n\n /** Stop long polling. */\n stop(): void {\n this.running = false;\n }\n\n /** Send a text message to a specific chat. Converts markdown and splits long messages. */\n async send(chatId: number, text: string, buttons?: InlineButton[][]): Promise<void> {\n const converted = toTelegramMarkdown(text);\n const chunks = splitMessage(converted);\n\n for (let i = 0; i < chunks.length; i++) {\n const isLast = i === chunks.length - 1;\n const replyMarkup =\n isLast && buttons\n ? {\n inline_keyboard: buttons.map((row) =>\n row.map((b) => ({ text: b.text, callback_data: b.callback_data })),\n ),\n }\n : undefined;\n\n await this.apiCall(\"sendMessage\", {\n chat_id: chatId,\n text: chunks[i],\n parse_mode: \"Markdown\",\n ...(replyMarkup ? { reply_markup: replyMarkup } : {}),\n });\n }\n }\n\n /** Send a plain text message (no markdown parsing) to a specific chat. */\n async sendPlain(chatId: number, text: string): Promise<void> {\n const chunks = splitMessage(text);\n for (const chunk of chunks) {\n await this.apiCall(\"sendMessage\", {\n chat_id: chatId,\n text: chunk,\n });\n }\n }\n\n /** Send a typing indicator to a specific chat. */\n async sendTyping(chatId: number): Promise<void> {\n await this.apiCall(\"sendChatAction\", {\n chat_id: chatId,\n action: \"typing\",\n });\n }\n\n /** Get a direct download URL for a Telegram file. */\n async getFileUrl(fileId: string): Promise<string> {\n const result = await this.apiCall(\"getFile\", { file_id: fileId });\n if (!result.ok) throw new Error(`Failed to get file: ${JSON.stringify(result)}`);\n const filePath = (result.result as { file_path: string }).file_path;\n return `${TELEGRAM_API}/file/bot${this.token}/${filePath}`;\n }\n\n // ── Private ───────────────────────────────────────────\n\n private async getUpdates(): Promise<TelegramUpdate[]> {\n const result = await this.apiCall(\"getUpdates\", {\n offset: this.offset,\n timeout: 30,\n allowed_updates: [\"message\", \"callback_query\", \"my_chat_member\"],\n });\n\n if (!result.ok || !Array.isArray(result.result)) return [];\n\n const updates = result.result as TelegramUpdate[];\n if (updates.length > 0) {\n this.offset = updates[updates.length - 1]!.update_id + 1;\n }\n return updates;\n }\n\n private async handleUpdate(update: TelegramUpdate): Promise<void> {\n if (update.message) {\n const msg = update.message;\n\n // Auth check\n if (msg.from.id !== this.allowedUserId) {\n return;\n }\n\n if (msg.text && this.onMessage) {\n this.onMessage({\n text: msg.text,\n chatId: msg.chat.id,\n chatType: msg.chat.type as TelegramMessage[\"chatType\"],\n chatTitle: msg.chat.title,\n });\n } else if (msg.voice && this.onVoiceMessage) {\n this.onVoiceMessage({\n fileId: msg.voice.file_id,\n duration: msg.voice.duration,\n chatId: msg.chat.id,\n chatType: msg.chat.type as TelegramMessage[\"chatType\"],\n chatTitle: msg.chat.title,\n });\n }\n }\n\n // Bot membership changed in a group\n if (update.my_chat_member) {\n const member = update.my_chat_member;\n const status = member.new_chat_member.status;\n if ((status === \"member\" || status === \"administrator\") && this.onBotAdded) {\n this.onBotAdded(member.chat.id, member.chat.title);\n } else if ((status === \"left\" || status === \"kicked\") && this.onBotRemoved) {\n this.onBotRemoved(member.chat.id);\n }\n }\n\n if (update.callback_query) {\n const cb = update.callback_query;\n\n if (cb.from.id !== this.allowedUserId) return;\n\n await this.apiCall(\"answerCallbackQuery\", { callback_query_id: cb.id });\n\n if (cb.data && this.onCallback) {\n this.onCallback(cb.data, cb.message.chat.id);\n }\n }\n }\n\n private async apiCall(\n method: string,\n body?: Record<string, unknown>,\n ): Promise<{ ok: boolean; result?: unknown }> {\n const url = `${TELEGRAM_API}/bot${this.token}/${method}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n return { ok: false };\n }\n\n return response.json() as Promise<{ ok: boolean; result?: unknown }>;\n }\n}\n\n// ── Markdown Conversion ──────────────────────────────────\n\n/**\n * Convert GitHub-flavored markdown to Telegram-compatible Markdown.\n *\n * Telegram supports: *bold*, _italic_, `code`, ```pre```, [link](url)\n * Does NOT support: headings, horizontal rules, tables, HTML tags, images\n */\nfunction toTelegramMarkdown(text: string): string {\n const lines = text.split(\"\\n\");\n const result: string[] = [];\n let inCodeBlock = false;\n\n for (const line of lines) {\n if (line.trimStart().startsWith(\"```\")) {\n inCodeBlock = !inCodeBlock;\n result.push(line);\n continue;\n }\n\n if (inCodeBlock) {\n result.push(line);\n continue;\n }\n\n let transformed = line;\n\n // Headings → bold text\n const headingMatch = transformed.match(/^(#{1,6})\\s+(.+)$/);\n if (headingMatch) {\n transformed = `*${headingMatch[2]}*`;\n result.push(transformed);\n continue;\n }\n\n // Horizontal rules → empty line\n if (/^(-{3,}|_{3,}|\\*{3,})$/.test(transformed.trim())) {\n result.push(\"\");\n continue;\n }\n\n // **bold** → *bold*\n transformed = transformed.replace(/\\*\\*(.+?)\\*\\*/g, \"*$1*\");\n\n result.push(transformed);\n }\n\n return result.join(\"\\n\");\n}\n\n// ── Helpers ───────────────────────────────────────────────\n\nfunction splitMessage(text: string): string[] {\n if (text.length <= MAX_MESSAGE_LENGTH) return [text];\n\n const chunks: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= MAX_MESSAGE_LENGTH) {\n chunks.push(remaining);\n break;\n }\n\n let splitAt = remaining.lastIndexOf(\"\\n\", MAX_MESSAGE_LENGTH);\n if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {\n splitAt = remaining.lastIndexOf(\" \", MAX_MESSAGE_LENGTH);\n }\n if (splitAt === -1 || splitAt < MAX_MESSAGE_LENGTH * 0.5) {\n splitAt = MAX_MESSAGE_LENGTH;\n }\n\n chunks.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt).trimStart();\n }\n\n return chunks;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n","/**\n * Voice note transcription using local Whisper model.\n * Uses @huggingface/transformers (pure JS/WASM) — no native deps, no API keys.\n * Model (~75MB) is downloaded on first use and cached locally.\n */\n\nimport type { AutomaticSpeechRecognitionPipeline } from \"@huggingface/transformers\";\n\nconst TARGET_SAMPLE_RATE = 16000;\nconst MODEL_ID = \"Xenova/whisper-tiny.en\";\n\nlet transcriber: AutomaticSpeechRecognitionPipeline | null = null;\nlet loadPromise: Promise<AutomaticSpeechRecognitionPipeline> | null = null;\n\n/** Optional callback for model download progress. */\nexport type ProgressCallback = (info: { status: string; progress?: number; file?: string }) => void;\n\nlet onProgress: ProgressCallback | null = null;\n\n/** Set a callback to receive model download progress updates. */\nexport function setProgressCallback(cb: ProgressCallback | null): void {\n onProgress = cb;\n}\n\n/**\n * Resample audio from one sample rate to another using linear interpolation.\n */\nexport function resample(audio: Float32Array, fromRate: number, toRate: number): Float32Array {\n if (fromRate === toRate) return audio;\n const ratio = fromRate / toRate;\n const newLength = Math.round(audio.length / ratio);\n const result = new Float32Array(newLength);\n for (let i = 0; i < newLength; i++) {\n const srcIndex = i * ratio;\n const low = Math.floor(srcIndex);\n const high = Math.min(low + 1, audio.length - 1);\n const frac = srcIndex - low;\n result[i] = audio[low]! * (1 - frac) + audio[high]! * frac;\n }\n return result;\n}\n\n/**\n * Downmix multi-channel audio to mono by averaging all channels.\n */\nexport function downmixToMono(channelData: Float32Array[]): Float32Array {\n if (channelData.length === 0) return new Float32Array();\n if (channelData.length === 1) return channelData[0]!;\n\n const samples = channelData[0]!.length;\n const out = new Float32Array(samples);\n const scale = 1 / channelData.length;\n for (let i = 0; i < samples; i++) {\n let mixed = 0;\n for (const channel of channelData) mixed += channel[i] ?? 0;\n out[i] = mixed * scale;\n }\n return out;\n}\n\n/**\n * Decode OGG Opus audio buffer to 16kHz mono PCM Float32Array.\n */\nexport async function decodeOggOpus(buffer: Uint8Array): Promise<Float32Array> {\n const { OggOpusDecoder } = await import(\"ogg-opus-decoder\");\n const decoder = new OggOpusDecoder();\n await decoder.ready;\n try {\n const decoded = await decoder.decodeFile(buffer);\n\n if (!decoded.channelData?.length || !decoded.channelData[0]?.length) {\n throw new Error(\"Decoded audio is empty\");\n }\n\n const mono = downmixToMono(decoded.channelData);\n return resample(mono, decoded.sampleRate, TARGET_SAMPLE_RATE);\n } finally {\n decoder.free();\n }\n}\n\n/**\n * Get or initialize the Whisper transcription pipeline.\n * Model is downloaded on first use and cached by transformers.js.\n */\nasync function getTranscriber(): Promise<AutomaticSpeechRecognitionPipeline> {\n if (transcriber) return transcriber;\n\n if (!loadPromise) {\n loadPromise = (async () => {\n const { pipeline } = await import(\"@huggingface/transformers\");\n const instance = await pipeline(\"automatic-speech-recognition\", MODEL_ID, {\n dtype: \"fp32\",\n progress_callback: onProgress ?? undefined,\n });\n transcriber = instance;\n return instance;\n })();\n }\n\n return loadPromise;\n}\n\n/** Whether the model has been loaded already. */\nexport function isModelLoaded(): boolean {\n return transcriber !== null;\n}\n\n/**\n * Transcribe a voice message from its Telegram file URL.\n * Downloads the OGG Opus file, decodes to PCM, and runs Whisper locally.\n */\nexport async function transcribeVoice(fileUrl: string): Promise<string> {\n // Download the audio file\n const response = await fetch(fileUrl);\n if (!response.ok) throw new Error(`Failed to download voice file: ${response.status}`);\n const buffer = new Uint8Array(await response.arrayBuffer());\n\n // Decode OGG Opus → 16kHz mono PCM\n const pcm = await decodeOggOpus(buffer);\n\n // Transcribe with Whisper\n const asr = await getTranscriber();\n const result = await asr(pcm);\n\n const text = Array.isArray(result) ? result[0]?.text : (result as { text: string }).text;\n return (text ?? \"\").trim();\n}\n","import { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Provider-agnostic background self-updater. Each app composes its own instance\n * via `createAutoUpdater` with its npm package name and state-file path, so the\n * update logic (registry poll, version compare, detached install, throttling)\n * lives in exactly one place while branding stays in the apps.\n */\n\ninterface UpdateState {\n lastCheckedAt: number;\n latestVersion?: string;\n updatePending?: boolean;\n lastUpdateAttempt?: number;\n}\n\nenum PackageManager {\n NPM = \"npm\",\n PNPM = \"pnpm\",\n YARN = \"yarn\",\n UNKNOWN = \"unknown\",\n}\n\ninterface InstallInfo {\n packageManager: PackageManager;\n updateCommand: string | null;\n}\n\nexport interface AutoUpdateConfig {\n /** npm package to self-update, e.g. \"@kenkaiiii/ggcoder\". */\n packageName: string;\n /**\n * Absolute path to this app's update-state.json, or a thunk resolving it.\n * A thunk keeps path resolution lazy so callers can derive it from\n * `os.homedir()` without freezing the value at module-load time (which\n * breaks tests that mock the home directory after import).\n */\n stateFilePath: string | (() => string);\n /** Builds the in-session \"update available\" notification. */\n periodicMessage?: (args: {\n currentVersion: string;\n latestVersion: string;\n updateCommand: string;\n }) => string;\n}\n\nexport interface AutoUpdater {\n checkAndAutoUpdate(currentVersion: string): string | null;\n getPendingUpdate(currentVersion: string): { latestVersion: string } | null;\n startPeriodicUpdateCheck(currentVersion: string, onUpdate: (message: string) => void): void;\n stopPeriodicUpdateCheck(): void;\n}\n\nconst CHECK_INTERVAL_MS = 60 * 60 * 1000; // 1 hour\nconst FETCH_TIMEOUT_MS = 10_000; // 10s — npm can be slow\n\nfunction compareVersions(a: string, b: string): number {\n const pa = a.split(\".\").map(Number);\n const pb = b.split(\".\").map(Number);\n for (let i = 0; i < 3; i++) {\n const diff = (pa[i] ?? 0) - (pb[i] ?? 0);\n if (diff !== 0) return diff;\n }\n return 0;\n}\n\nfunction performUpdateInBackground(command: string): void {\n try {\n const parts = command.split(\" \");\n const child = spawn(parts[0]!, parts.slice(1), {\n detached: true,\n stdio: \"ignore\",\n env: { ...process.env, npm_config_loglevel: \"silent\" },\n });\n child.unref();\n } catch {\n // Non-fatal — will retry next startup\n }\n}\n\nexport function createAutoUpdater(config: AutoUpdateConfig): AutoUpdater {\n const REGISTRY_URL = `https://registry.npmjs.org/${config.packageName}/latest`;\n const periodicMessage =\n config.periodicMessage ??\n (({ currentVersion, latestVersion, updateCommand }) =>\n `Ken just pushed a fresh update — ${currentVersion} → ${latestVersion}! I'll grab it on next launch (or run ${updateCommand} if you can't wait).`);\n\n let periodicTimer: ReturnType<typeof setInterval> | null = null;\n\n function stateFilePath(): string {\n return typeof config.stateFilePath === \"function\"\n ? config.stateFilePath()\n : config.stateFilePath;\n }\n\n function readState(): UpdateState | null {\n try {\n const raw = fs.readFileSync(stateFilePath(), \"utf-8\");\n return JSON.parse(raw) as UpdateState;\n } catch {\n return null;\n }\n }\n\n function writeState(state: UpdateState): void {\n try {\n const filePath = stateFilePath();\n fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });\n fs.writeFileSync(filePath, JSON.stringify(state));\n } catch {\n // Non-fatal\n }\n }\n\n function detectInstallInfo(): InstallInfo {\n const scriptPath = (process.argv[1] ?? \"\").replace(/\\\\/g, \"/\");\n\n // npx — skip (ephemeral)\n if (scriptPath.includes(\"/_npx/\")) {\n return { packageManager: PackageManager.UNKNOWN, updateCommand: null };\n }\n\n // pnpm global\n if (scriptPath.includes(\"/.pnpm\") || scriptPath.includes(\"/pnpm/global\")) {\n return {\n packageManager: PackageManager.PNPM,\n updateCommand: `pnpm add -g ${config.packageName}@latest`,\n };\n }\n\n // yarn global\n if (scriptPath.includes(\"/.yarn/\") || scriptPath.includes(\"/yarn/global\")) {\n return {\n packageManager: PackageManager.YARN,\n updateCommand: `yarn global add ${config.packageName}@latest`,\n };\n }\n\n // npm global (default)\n return {\n packageManager: PackageManager.NPM,\n updateCommand: `npm install -g ${config.packageName}@latest`,\n };\n }\n\n async function fetchLatestVersion(): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n const response = await fetch(REGISTRY_URL, { signal: controller.signal });\n clearTimeout(timeout);\n const data = (await response.json()) as { version?: string };\n const version = data.version?.trim();\n return version && /^\\d+\\.\\d+\\.\\d+/.test(version) ? version : null;\n } catch {\n return null;\n }\n }\n\n function scheduleBackgroundCheck(currentVersion: string): void {\n fetchLatestVersion()\n .then((latestVersion) => {\n const newState: UpdateState = {\n lastCheckedAt: Date.now(),\n latestVersion: latestVersion ?? undefined,\n updatePending: false,\n };\n if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) {\n newState.updatePending = true;\n }\n writeState(newState);\n })\n .catch(() => {\n // Non-fatal — will retry next time\n });\n }\n\n function checkAndAutoUpdate(currentVersion: string): string | null {\n try {\n const state = readState();\n let message: string | null = null;\n\n // Phase 1: Apply pending update from previous check\n if (state?.updatePending && state.latestVersion) {\n if (compareVersions(state.latestVersion, currentVersion) > 0) {\n const info = detectInstallInfo();\n if (info.updateCommand) {\n performUpdateInBackground(info.updateCommand);\n message = `Ken just shipped ${state.latestVersion}! Installing in the background — takes effect next launch.`;\n writeState({\n ...state,\n lastCheckedAt: Date.now(),\n updatePending: false,\n lastUpdateAttempt: Date.now(),\n });\n }\n } else {\n // Already on latest (user may have updated manually)\n writeState({ ...state, updatePending: false });\n }\n }\n\n // Phase 2: Schedule background check for next startup\n const shouldCheck = !state || Date.now() - state.lastCheckedAt > CHECK_INTERVAL_MS;\n if (shouldCheck) scheduleBackgroundCheck(currentVersion);\n\n return message;\n } catch {\n return null;\n }\n }\n\n function getPendingUpdate(currentVersion: string): { latestVersion: string } | null {\n try {\n const state = readState();\n if (!state?.latestVersion) return null;\n if (compareVersions(state.latestVersion, currentVersion) <= 0) return null;\n return { latestVersion: state.latestVersion };\n } catch {\n return null;\n }\n }\n\n function startPeriodicUpdateCheck(\n currentVersion: string,\n onUpdate: (message: string) => void,\n ): void {\n if (periodicTimer) return; // Already running\n\n periodicTimer = setInterval(() => {\n fetchLatestVersion()\n .then((latestVersion) => {\n if (!latestVersion) return;\n if (compareVersions(latestVersion, currentVersion) <= 0) return;\n\n const info = detectInstallInfo();\n if (!info.updateCommand) return;\n\n writeState({ lastCheckedAt: Date.now(), latestVersion, updatePending: true });\n onUpdate(\n periodicMessage({ currentVersion, latestVersion, updateCommand: info.updateCommand }),\n );\n\n // Stop checking once we've notified\n stopPeriodicUpdateCheck();\n })\n .catch(() => {\n // Non-fatal\n });\n }, CHECK_INTERVAL_MS);\n\n // Don't keep the process alive just for update checks\n periodicTimer.unref();\n }\n\n function stopPeriodicUpdateCheck(): void {\n if (periodicTimer) {\n clearInterval(periodicTimer);\n periodicTimer = null;\n }\n }\n\n return {\n checkAndAutoUpdate,\n getPendingUpdate,\n startPeriodicUpdateCheck,\n stopPeriodicUpdateCheck,\n };\n}\n"],"mappings":"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","names":["levels","maxIndex"]}
|
package/dist/model-registry.cjs
CHANGED
|
@@ -36,6 +36,7 @@ __export(model_registry_exports, {
|
|
|
36
36
|
getAuthStorageKeys: () => getAuthStorageKeys,
|
|
37
37
|
getContextWindow: () => getContextWindow,
|
|
38
38
|
getDefaultModel: () => getDefaultModel,
|
|
39
|
+
getDefaultThinkingLevel: () => getDefaultThinkingLevel,
|
|
39
40
|
getFastModel: () => getFastModel,
|
|
40
41
|
getMaxThinkingLevel: () => getMaxThinkingLevel,
|
|
41
42
|
getModel: () => getModel,
|
|
@@ -47,25 +48,45 @@ __export(model_registry_exports, {
|
|
|
47
48
|
});
|
|
48
49
|
module.exports = __toCommonJS(model_registry_exports);
|
|
49
50
|
|
|
50
|
-
// src/
|
|
51
|
-
var
|
|
52
|
-
var
|
|
51
|
+
// src/oauth/kimi.ts
|
|
52
|
+
var import_node_child_process = require("child_process");
|
|
53
|
+
var import_node_crypto = require("crypto");
|
|
54
|
+
var import_node_fs = require("fs");
|
|
55
|
+
var import_node_os2 = require("os");
|
|
56
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
53
57
|
|
|
54
58
|
// src/paths.ts
|
|
55
59
|
var import_node_path = __toESM(require("path"), 1);
|
|
56
60
|
var import_node_os = __toESM(require("os"), 1);
|
|
57
61
|
|
|
62
|
+
// src/oauth/kimi.ts
|
|
63
|
+
var DEFAULT_CODING_BASE_URL = "https://api.kimi.com/coding/v1";
|
|
64
|
+
var DEVICE_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
65
|
+
function kimiCodeBaseUrl() {
|
|
66
|
+
return (process.env.KIMI_CODE_BASE_URL ?? DEFAULT_CODING_BASE_URL).replace(/\/+$/, "");
|
|
67
|
+
}
|
|
68
|
+
function isKimiCodingEndpoint(baseUrl) {
|
|
69
|
+
if (typeof baseUrl !== "string" || baseUrl.length === 0) return false;
|
|
70
|
+
const normalized = baseUrl.replace(/\/+$/, "");
|
|
71
|
+
return normalized === kimiCodeBaseUrl() || /(^|\.)kimi\.com/i.test(normalized);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/auth-storage.ts
|
|
75
|
+
var import_promises4 = __toESM(require("fs/promises"), 1);
|
|
76
|
+
var import_node_fs3 = require("fs");
|
|
77
|
+
var import_node_crypto6 = __toESM(require("crypto"), 1);
|
|
78
|
+
|
|
58
79
|
// src/oauth/anthropic.ts
|
|
59
|
-
var
|
|
80
|
+
var import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
60
81
|
|
|
61
82
|
// src/claude-code-version.ts
|
|
62
83
|
var import_promises = __toESM(require("fs/promises"), 1);
|
|
63
|
-
var
|
|
84
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
64
85
|
|
|
65
86
|
// src/logger.ts
|
|
66
|
-
var
|
|
67
|
-
var
|
|
68
|
-
var
|
|
87
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
88
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
89
|
+
var import_node_crypto2 = require("crypto");
|
|
69
90
|
var import_gg_ai = require("@kenkaiiii/gg-ai");
|
|
70
91
|
var MAX_BYTES = 10 * 1024 * 1024;
|
|
71
92
|
|
|
@@ -77,25 +98,17 @@ var CLIENT_ID = atob("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
|
|
|
77
98
|
|
|
78
99
|
// src/oauth/openai.ts
|
|
79
100
|
var import_node_http = __toESM(require("http"), 1);
|
|
80
|
-
var
|
|
101
|
+
var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
81
102
|
|
|
82
103
|
// src/oauth/gemini.ts
|
|
83
104
|
var import_node_http2 = __toESM(require("http"), 1);
|
|
84
|
-
var
|
|
105
|
+
var import_node_crypto5 = __toESM(require("crypto"), 1);
|
|
85
106
|
var SCOPE = [
|
|
86
107
|
"https://www.googleapis.com/auth/cloud-platform",
|
|
87
108
|
"https://www.googleapis.com/auth/userinfo.email",
|
|
88
109
|
"https://www.googleapis.com/auth/userinfo.profile"
|
|
89
110
|
].join(" ");
|
|
90
111
|
|
|
91
|
-
// src/oauth/kimi.ts
|
|
92
|
-
var import_node_child_process = require("child_process");
|
|
93
|
-
var import_node_crypto5 = require("crypto");
|
|
94
|
-
var import_node_fs2 = require("fs");
|
|
95
|
-
var import_node_os2 = require("os");
|
|
96
|
-
var import_node_path4 = __toESM(require("path"), 1);
|
|
97
|
-
var DEVICE_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
98
|
-
|
|
99
112
|
// src/file-lock.ts
|
|
100
113
|
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
101
114
|
var import_promises3 = require("timers/promises");
|
|
@@ -338,8 +351,9 @@ var MODELS = [
|
|
|
338
351
|
},
|
|
339
352
|
// ── Moonshot (Kimi) ────────────────────────────────────
|
|
340
353
|
// K3 is Kimi's 2.8T-parameter flagship for long-horizon coding, knowledge
|
|
341
|
-
// work, and deep reasoning.
|
|
342
|
-
//
|
|
354
|
+
// work, and deep reasoning. Its effort ladder is server-declared as
|
|
355
|
+
// low/high/max on both the public API (default max) and the Kimi For Coding
|
|
356
|
+
// OAuth endpoint (default high); thinking can also be fully disabled.
|
|
343
357
|
{
|
|
344
358
|
id: "kimi-k3",
|
|
345
359
|
name: "Kimi K3",
|
|
@@ -573,6 +587,11 @@ function getContextWindow(modelId, options) {
|
|
|
573
587
|
function getMaxThinkingLevel(modelId) {
|
|
574
588
|
return getModel(modelId)?.maxThinkingLevel ?? "high";
|
|
575
589
|
}
|
|
590
|
+
function getDefaultThinkingLevel(modelId, options) {
|
|
591
|
+
const model = getModel(modelId);
|
|
592
|
+
if (model?.id === "kimi-k3" && isKimiCodingEndpoint(options?.baseUrl)) return "high";
|
|
593
|
+
return model?.maxThinkingLevel ?? "high";
|
|
594
|
+
}
|
|
576
595
|
function getSummaryModel(provider, currentModelId) {
|
|
577
596
|
if (provider === "anthropic") {
|
|
578
597
|
return MODELS.find((m) => m.id === "claude-sonnet-5");
|
|
@@ -595,6 +614,7 @@ function getFastModel(provider, currentModelId) {
|
|
|
595
614
|
getAuthStorageKeys,
|
|
596
615
|
getContextWindow,
|
|
597
616
|
getDefaultModel,
|
|
617
|
+
getDefaultThinkingLevel,
|
|
598
618
|
getFastModel,
|
|
599
619
|
getMaxThinkingLevel,
|
|
600
620
|
getModel,
|