opencode-kimi-rotator 1.0.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/LICENSE +21 -0
- package/README.md +488 -0
- package/bin/cli.js +264 -0
- package/dist/accounts.d.ts +36 -0
- package/dist/accounts.d.ts.map +1 -0
- package/dist/accounts.js +205 -0
- package/dist/accounts.js.map +1 -0
- package/dist/plugin.bundle.js +6168 -0
- package/dist/plugin.d.ts +6 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +142 -0
- package/dist/plugin.js.map +1 -0
- package/dist/storage.d.ts +18 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +137 -0
- package/dist/storage.js.map +1 -0
- package/dist/types.d.ts +103 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +31 -0
- package/dist/types.js.map +1 -0
- package/package.json +66 -0
- package/src/plugin.ts +176 -0
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAqE9C,eAAO,MAAM,iBAAiB,EAAE,MAqG/B,CAAC;AAEF,eAAe,iBAAiB,CAAC;AACjC,YAAY,EAAE,WAAW,EAAE,CAAC"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { KimiAccountManager } from './accounts.js';
|
|
2
|
+
let accountManager = null;
|
|
3
|
+
let currentAccountIndex = 0;
|
|
4
|
+
let originalFetch = null;
|
|
5
|
+
async function getAccountManager() {
|
|
6
|
+
if (!accountManager) {
|
|
7
|
+
accountManager = new KimiAccountManager();
|
|
8
|
+
await accountManager.init();
|
|
9
|
+
}
|
|
10
|
+
return accountManager;
|
|
11
|
+
}
|
|
12
|
+
async function getAuth() {
|
|
13
|
+
const manager = await getAccountManager();
|
|
14
|
+
const result = await manager.getNextAccount();
|
|
15
|
+
if (!result) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
currentAccountIndex = result.index;
|
|
19
|
+
return {
|
|
20
|
+
type: 'api',
|
|
21
|
+
key: result.account.key,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
let openCodeClient = null;
|
|
25
|
+
let toastQueue = [];
|
|
26
|
+
async function showToast(message, variant = 'info') {
|
|
27
|
+
if (!openCodeClient?.tui?.showToast) {
|
|
28
|
+
toastQueue.push({ message, variant });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
await openCodeClient.tui.showToast({ body: { message, variant } });
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function flushToastQueue() {
|
|
39
|
+
if (!openCodeClient?.tui?.showToast)
|
|
40
|
+
return;
|
|
41
|
+
while (toastQueue.length > 0) {
|
|
42
|
+
const toast = toastQueue.shift();
|
|
43
|
+
if (toast) {
|
|
44
|
+
try {
|
|
45
|
+
await openCodeClient.tui.showToast({ body: { message: toast.message, variant: toast.variant } });
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export const KimiRotatorPlugin = async ({ client }) => {
|
|
54
|
+
openCodeClient = client;
|
|
55
|
+
accountManager = await getAccountManager();
|
|
56
|
+
const result = await accountManager.getNextAccount();
|
|
57
|
+
if (result) {
|
|
58
|
+
const kimiBaseUrl = 'https://api.kimi.com/coding/v1';
|
|
59
|
+
process.env.ANTHROPIC_BASE_URL = kimiBaseUrl;
|
|
60
|
+
process.env.ANTHROPIC_API_KEY = result.account.key;
|
|
61
|
+
}
|
|
62
|
+
originalFetch = globalThis.fetch;
|
|
63
|
+
globalThis.fetch = async (input, init) => {
|
|
64
|
+
const url = typeof input === 'string' ? input : input.toString();
|
|
65
|
+
if (url.includes('api.kimi.com')) {
|
|
66
|
+
const nextAccount = await accountManager.getNextAccount();
|
|
67
|
+
if (nextAccount) {
|
|
68
|
+
currentAccountIndex = nextAccount.index;
|
|
69
|
+
const keyLabel = nextAccount.account.key.substring(0, 18) + '...';
|
|
70
|
+
const position = nextAccount.index + 1;
|
|
71
|
+
const allKeysNow = await accountManager.listKeys();
|
|
72
|
+
const total = allKeysNow.length;
|
|
73
|
+
await showToast(`🔄 Using key: ${keyLabel} (${position}/${total})`, 'info');
|
|
74
|
+
const headers = new Headers(init?.headers);
|
|
75
|
+
headers.set('x-api-key', nextAccount.account.key);
|
|
76
|
+
headers.delete('Authorization');
|
|
77
|
+
try {
|
|
78
|
+
const response = await originalFetch(input, { ...init, headers });
|
|
79
|
+
if (response.status === 429) {
|
|
80
|
+
const retryAfter = response.headers.get('retry-after');
|
|
81
|
+
const retryAfterMs = retryAfter ? parseInt(retryAfter, 10) * 1000 : 60000;
|
|
82
|
+
await accountManager.markAccountRateLimited(currentAccountIndex, retryAfterMs);
|
|
83
|
+
await showToast(`⚠️ Key ${position} rate limited`, 'warning');
|
|
84
|
+
}
|
|
85
|
+
else if (response.ok) {
|
|
86
|
+
await accountManager.markAccountSuccess(currentAccountIndex);
|
|
87
|
+
}
|
|
88
|
+
else if (response.status >= 500) {
|
|
89
|
+
await accountManager.markAccountFailure(currentAccountIndex);
|
|
90
|
+
}
|
|
91
|
+
return response;
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
await accountManager.markAccountFailure(currentAccountIndex);
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return originalFetch(input, init);
|
|
100
|
+
};
|
|
101
|
+
const showInitialToast = async () => {
|
|
102
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
103
|
+
await flushToastQueue();
|
|
104
|
+
await showToast("🎉 Kimi Rotator Plugin loaded!", 'info');
|
|
105
|
+
};
|
|
106
|
+
showInitialToast().catch(() => { });
|
|
107
|
+
const pluginReturn = {
|
|
108
|
+
auth: {
|
|
109
|
+
provider: 'kimi-rotator',
|
|
110
|
+
methods: [{
|
|
111
|
+
type: 'api',
|
|
112
|
+
label: 'Kimi API Key',
|
|
113
|
+
}],
|
|
114
|
+
loader: async () => {
|
|
115
|
+
const auth = await getAuth();
|
|
116
|
+
if (!auth) {
|
|
117
|
+
throw new Error('No Kimi API keys configured. Run: opencode-kimi add-key');
|
|
118
|
+
}
|
|
119
|
+
const kimiBaseUrl = 'https://api.kimi.com/coding/v1';
|
|
120
|
+
return {
|
|
121
|
+
apiKey: auth.key,
|
|
122
|
+
baseURL: kimiBaseUrl,
|
|
123
|
+
async fetch(input, init) {
|
|
124
|
+
return globalThis.fetch(input, init);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
cleanup: () => {
|
|
130
|
+
if (originalFetch) {
|
|
131
|
+
globalThis.fetch = originalFetch;
|
|
132
|
+
originalFetch = null;
|
|
133
|
+
}
|
|
134
|
+
openCodeClient = null;
|
|
135
|
+
accountManager = null;
|
|
136
|
+
toastQueue = [];
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
return pluginReturn;
|
|
140
|
+
};
|
|
141
|
+
export default KimiRotatorPlugin;
|
|
142
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { KimiAccountsConfig, KimiAccount } from './types.js';
|
|
2
|
+
export declare class KimiStorage {
|
|
3
|
+
private configDir;
|
|
4
|
+
private accountsFilePath;
|
|
5
|
+
private lockOptions;
|
|
6
|
+
constructor();
|
|
7
|
+
init(): Promise<void>;
|
|
8
|
+
loadConfig(): Promise<KimiAccountsConfig>;
|
|
9
|
+
saveConfig(config: KimiAccountsConfig): Promise<void>;
|
|
10
|
+
addAccount(key: string, name?: string): Promise<KimiAccount>;
|
|
11
|
+
removeAccount(index: number): Promise<void>;
|
|
12
|
+
listAccounts(): Promise<KimiAccount[]>;
|
|
13
|
+
getActiveAccount(): Promise<KimiAccount | null>;
|
|
14
|
+
setActiveIndex(index: number): Promise<void>;
|
|
15
|
+
updateAccount(index: number, updates: Partial<KimiAccount>): Promise<void>;
|
|
16
|
+
private acquireLock;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,kBAAkB,EAElB,WAAW,EAGZ,MAAM,YAAY,CAAC;AAOpB,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,WAAW,CAGjB;;IAOI,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBrB,UAAU,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAkBzC,UAAU,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAcrD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAuB5D,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB3C,YAAY,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAKtC,gBAAgB,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAQ/C,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW5C,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAWlE,WAAW;CAgB1B"}
|
package/dist/storage.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import lockfile from 'proper-lockfile';
|
|
5
|
+
import { KimiAccountsConfigSchema, DEFAULT_CONFIG, DEFAULT_ACCOUNT, } from './types.js';
|
|
6
|
+
const ACCOUNTS_FILE_NAME = 'kimi-accounts.json';
|
|
7
|
+
const GITIGNORE_CONTENT = '# Kimi Rotator\nkimi-accounts.json\n';
|
|
8
|
+
const LOCK_STALE_MS = 5000;
|
|
9
|
+
const LOCK_RETRIES = 3;
|
|
10
|
+
export class KimiStorage {
|
|
11
|
+
configDir;
|
|
12
|
+
accountsFilePath;
|
|
13
|
+
lockOptions = {
|
|
14
|
+
stale: LOCK_STALE_MS,
|
|
15
|
+
retries: LOCK_RETRIES,
|
|
16
|
+
};
|
|
17
|
+
constructor() {
|
|
18
|
+
this.configDir = path.join(os.homedir(), '.config', 'opencode');
|
|
19
|
+
this.accountsFilePath = path.join(this.configDir, ACCOUNTS_FILE_NAME);
|
|
20
|
+
}
|
|
21
|
+
async init() {
|
|
22
|
+
await fs.mkdir(this.configDir, { recursive: true });
|
|
23
|
+
const gitignorePath = path.join(this.configDir, '.gitignore');
|
|
24
|
+
try {
|
|
25
|
+
await fs.access(gitignorePath);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
await fs.appendFile(gitignorePath, GITIGNORE_CONTENT, 'utf-8');
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
await fs.access(this.accountsFilePath);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
await this.saveConfig({
|
|
35
|
+
...DEFAULT_CONFIG,
|
|
36
|
+
accounts: [],
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async loadConfig() {
|
|
41
|
+
const release = await this.acquireLock();
|
|
42
|
+
try {
|
|
43
|
+
const data = await fs.readFile(this.accountsFilePath, 'utf-8');
|
|
44
|
+
const parsed = JSON.parse(data);
|
|
45
|
+
return KimiAccountsConfigSchema.parse(parsed);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (error.code === 'ENOENT') {
|
|
49
|
+
const config = { ...DEFAULT_CONFIG, accounts: [] };
|
|
50
|
+
await this.saveConfig(config);
|
|
51
|
+
return config;
|
|
52
|
+
}
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
await release();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async saveConfig(config) {
|
|
60
|
+
const release = await this.acquireLock();
|
|
61
|
+
try {
|
|
62
|
+
const validated = KimiAccountsConfigSchema.parse(config);
|
|
63
|
+
await fs.writeFile(this.accountsFilePath, JSON.stringify(validated, null, 2), 'utf-8');
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
await release();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async addAccount(key, name) {
|
|
70
|
+
const config = await this.loadConfig();
|
|
71
|
+
const existingIndex = config.accounts.findIndex(a => a.key === key);
|
|
72
|
+
if (existingIndex !== -1) {
|
|
73
|
+
throw new Error('This API key already exists');
|
|
74
|
+
}
|
|
75
|
+
const now = Date.now();
|
|
76
|
+
const newAccount = {
|
|
77
|
+
key,
|
|
78
|
+
name: name || `Account ${config.accounts.length + 1}`,
|
|
79
|
+
addedAt: now,
|
|
80
|
+
lastUsed: now,
|
|
81
|
+
...DEFAULT_ACCOUNT,
|
|
82
|
+
};
|
|
83
|
+
config.accounts.push(newAccount);
|
|
84
|
+
await this.saveConfig(config);
|
|
85
|
+
return newAccount;
|
|
86
|
+
}
|
|
87
|
+
async removeAccount(index) {
|
|
88
|
+
const config = await this.loadConfig();
|
|
89
|
+
if (index < 0 || index >= config.accounts.length) {
|
|
90
|
+
throw new Error(`Invalid account index: ${index}`);
|
|
91
|
+
}
|
|
92
|
+
config.accounts.splice(index, 1);
|
|
93
|
+
if (config.activeIndex >= config.accounts.length) {
|
|
94
|
+
config.activeIndex = Math.max(0, config.accounts.length - 1);
|
|
95
|
+
}
|
|
96
|
+
await this.saveConfig(config);
|
|
97
|
+
}
|
|
98
|
+
async listAccounts() {
|
|
99
|
+
const config = await this.loadConfig();
|
|
100
|
+
return config.accounts;
|
|
101
|
+
}
|
|
102
|
+
async getActiveAccount() {
|
|
103
|
+
const config = await this.loadConfig();
|
|
104
|
+
if (config.accounts.length === 0) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
return config.accounts[config.activeIndex];
|
|
108
|
+
}
|
|
109
|
+
async setActiveIndex(index) {
|
|
110
|
+
const config = await this.loadConfig();
|
|
111
|
+
if (index < 0 || index >= config.accounts.length) {
|
|
112
|
+
throw new Error(`Invalid account index: ${index}`);
|
|
113
|
+
}
|
|
114
|
+
config.activeIndex = index;
|
|
115
|
+
await this.saveConfig(config);
|
|
116
|
+
}
|
|
117
|
+
async updateAccount(index, updates) {
|
|
118
|
+
const config = await this.loadConfig();
|
|
119
|
+
if (index < 0 || index >= config.accounts.length) {
|
|
120
|
+
throw new Error(`Invalid account index: ${index}`);
|
|
121
|
+
}
|
|
122
|
+
config.accounts[index] = { ...config.accounts[index], ...updates };
|
|
123
|
+
await this.saveConfig(config);
|
|
124
|
+
}
|
|
125
|
+
async acquireLock() {
|
|
126
|
+
await fs.mkdir(path.dirname(this.accountsFilePath), { recursive: true });
|
|
127
|
+
try {
|
|
128
|
+
await fs.access(this.accountsFilePath);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
await fs.writeFile(this.accountsFilePath, JSON.stringify({ ...DEFAULT_CONFIG, accounts: [] }), { flag: 'wx' });
|
|
132
|
+
}
|
|
133
|
+
const release = await lockfile.lock(this.accountsFilePath, this.lockOptions);
|
|
134
|
+
return release;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const KimiAccountSchema: z.ZodObject<{
|
|
3
|
+
key: z.ZodString;
|
|
4
|
+
name: z.ZodOptional<z.ZodString>;
|
|
5
|
+
addedAt: z.ZodNumber;
|
|
6
|
+
lastUsed: z.ZodNumber;
|
|
7
|
+
rateLimitResetTime: z.ZodDefault<z.ZodNumber>;
|
|
8
|
+
healthScore: z.ZodDefault<z.ZodNumber>;
|
|
9
|
+
consecutiveFailures: z.ZodDefault<z.ZodNumber>;
|
|
10
|
+
totalRequests: z.ZodDefault<z.ZodNumber>;
|
|
11
|
+
successfulRequests: z.ZodDefault<z.ZodNumber>;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
key: string;
|
|
14
|
+
addedAt: number;
|
|
15
|
+
lastUsed: number;
|
|
16
|
+
rateLimitResetTime: number;
|
|
17
|
+
healthScore: number;
|
|
18
|
+
consecutiveFailures: number;
|
|
19
|
+
totalRequests: number;
|
|
20
|
+
successfulRequests: number;
|
|
21
|
+
name?: string | undefined;
|
|
22
|
+
}, {
|
|
23
|
+
key: string;
|
|
24
|
+
addedAt: number;
|
|
25
|
+
lastUsed: number;
|
|
26
|
+
name?: string | undefined;
|
|
27
|
+
rateLimitResetTime?: number | undefined;
|
|
28
|
+
healthScore?: number | undefined;
|
|
29
|
+
consecutiveFailures?: number | undefined;
|
|
30
|
+
totalRequests?: number | undefined;
|
|
31
|
+
successfulRequests?: number | undefined;
|
|
32
|
+
}>;
|
|
33
|
+
export declare const KimiAccountsConfigSchema: z.ZodObject<{
|
|
34
|
+
version: z.ZodDefault<z.ZodNumber>;
|
|
35
|
+
accounts: z.ZodArray<z.ZodObject<{
|
|
36
|
+
key: z.ZodString;
|
|
37
|
+
name: z.ZodOptional<z.ZodString>;
|
|
38
|
+
addedAt: z.ZodNumber;
|
|
39
|
+
lastUsed: z.ZodNumber;
|
|
40
|
+
rateLimitResetTime: z.ZodDefault<z.ZodNumber>;
|
|
41
|
+
healthScore: z.ZodDefault<z.ZodNumber>;
|
|
42
|
+
consecutiveFailures: z.ZodDefault<z.ZodNumber>;
|
|
43
|
+
totalRequests: z.ZodDefault<z.ZodNumber>;
|
|
44
|
+
successfulRequests: z.ZodDefault<z.ZodNumber>;
|
|
45
|
+
}, "strip", z.ZodTypeAny, {
|
|
46
|
+
key: string;
|
|
47
|
+
addedAt: number;
|
|
48
|
+
lastUsed: number;
|
|
49
|
+
rateLimitResetTime: number;
|
|
50
|
+
healthScore: number;
|
|
51
|
+
consecutiveFailures: number;
|
|
52
|
+
totalRequests: number;
|
|
53
|
+
successfulRequests: number;
|
|
54
|
+
name?: string | undefined;
|
|
55
|
+
}, {
|
|
56
|
+
key: string;
|
|
57
|
+
addedAt: number;
|
|
58
|
+
lastUsed: number;
|
|
59
|
+
name?: string | undefined;
|
|
60
|
+
rateLimitResetTime?: number | undefined;
|
|
61
|
+
healthScore?: number | undefined;
|
|
62
|
+
consecutiveFailures?: number | undefined;
|
|
63
|
+
totalRequests?: number | undefined;
|
|
64
|
+
successfulRequests?: number | undefined;
|
|
65
|
+
}>, "many">;
|
|
66
|
+
activeIndex: z.ZodDefault<z.ZodNumber>;
|
|
67
|
+
rotationStrategy: z.ZodDefault<z.ZodEnum<["round-robin", "health-based", "sticky"]>>;
|
|
68
|
+
}, "strip", z.ZodTypeAny, {
|
|
69
|
+
version: number;
|
|
70
|
+
accounts: {
|
|
71
|
+
key: string;
|
|
72
|
+
addedAt: number;
|
|
73
|
+
lastUsed: number;
|
|
74
|
+
rateLimitResetTime: number;
|
|
75
|
+
healthScore: number;
|
|
76
|
+
consecutiveFailures: number;
|
|
77
|
+
totalRequests: number;
|
|
78
|
+
successfulRequests: number;
|
|
79
|
+
name?: string | undefined;
|
|
80
|
+
}[];
|
|
81
|
+
activeIndex: number;
|
|
82
|
+
rotationStrategy: "round-robin" | "health-based" | "sticky";
|
|
83
|
+
}, {
|
|
84
|
+
accounts: {
|
|
85
|
+
key: string;
|
|
86
|
+
addedAt: number;
|
|
87
|
+
lastUsed: number;
|
|
88
|
+
name?: string | undefined;
|
|
89
|
+
rateLimitResetTime?: number | undefined;
|
|
90
|
+
healthScore?: number | undefined;
|
|
91
|
+
consecutiveFailures?: number | undefined;
|
|
92
|
+
totalRequests?: number | undefined;
|
|
93
|
+
successfulRequests?: number | undefined;
|
|
94
|
+
}[];
|
|
95
|
+
version?: number | undefined;
|
|
96
|
+
activeIndex?: number | undefined;
|
|
97
|
+
rotationStrategy?: "round-robin" | "health-based" | "sticky" | undefined;
|
|
98
|
+
}>;
|
|
99
|
+
export type KimiAccount = z.infer<typeof KimiAccountSchema>;
|
|
100
|
+
export type KimiAccountsConfig = z.infer<typeof KimiAccountsConfigSchema>;
|
|
101
|
+
export declare const DEFAULT_ACCOUNT: Omit<KimiAccount, 'key' | 'addedAt' | 'lastUsed'>;
|
|
102
|
+
export declare const DEFAULT_CONFIG: Omit<KimiAccountsConfig, 'accounts'>;
|
|
103
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU5B,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKnC,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,eAAe,EAAE,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,SAAS,GAAG,UAAU,CAM7E,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAI/D,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const KimiAccountSchema = z.object({
|
|
3
|
+
key: z.string().min(1),
|
|
4
|
+
name: z.string().optional(),
|
|
5
|
+
addedAt: z.number(),
|
|
6
|
+
lastUsed: z.number(),
|
|
7
|
+
rateLimitResetTime: z.number().default(0),
|
|
8
|
+
healthScore: z.number().min(0).max(100).default(100),
|
|
9
|
+
consecutiveFailures: z.number().default(0),
|
|
10
|
+
totalRequests: z.number().default(0),
|
|
11
|
+
successfulRequests: z.number().default(0),
|
|
12
|
+
});
|
|
13
|
+
export const KimiAccountsConfigSchema = z.object({
|
|
14
|
+
version: z.number().default(1),
|
|
15
|
+
accounts: z.array(KimiAccountSchema),
|
|
16
|
+
activeIndex: z.number().default(0),
|
|
17
|
+
rotationStrategy: z.enum(['round-robin', 'health-based', 'sticky']).default('health-based'),
|
|
18
|
+
});
|
|
19
|
+
export const DEFAULT_ACCOUNT = {
|
|
20
|
+
rateLimitResetTime: 0,
|
|
21
|
+
healthScore: 100,
|
|
22
|
+
consecutiveFailures: 0,
|
|
23
|
+
totalRequests: 0,
|
|
24
|
+
successfulRequests: 0,
|
|
25
|
+
};
|
|
26
|
+
export const DEFAULT_CONFIG = {
|
|
27
|
+
version: 1,
|
|
28
|
+
activeIndex: 0,
|
|
29
|
+
rotationStrategy: 'health-based',
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACzC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;IACpD,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1C,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACpC,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;CAC1C,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9B,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC;IACpC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAClC,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,cAAc,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC;CAC5F,CAAC,CAAC;AAKH,MAAM,CAAC,MAAM,eAAe,GAAsD;IAChF,kBAAkB,EAAE,CAAC;IACrB,WAAW,EAAE,GAAG;IAChB,mBAAmB,EAAE,CAAC;IACtB,aAAa,EAAE,CAAC;IAChB,kBAAkB,EAAE,CAAC;CACtB,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAyC;IAClE,OAAO,EAAE,CAAC;IACV,WAAW,EAAE,CAAC;IACd,gBAAgB,EAAE,cAAc;CACjC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencode-kimi-rotator",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Kimi API Key Rotator for OpenCode - Automatically rotate between multiple Kimi API keys to handle rate limits",
|
|
5
|
+
"main": "./dist/plugin.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"opencode-kimi": "bin/cli.js",
|
|
10
|
+
"kimi-rotator": "bin/cli.js"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"bundle": "esbuild src/plugin.ts --bundle --platform=node --format=esm --outfile=dist/plugin.bundle.js --external:@opencode-ai/plugin --packages=bundle",
|
|
15
|
+
"dev": "tsc --watch",
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"clean": "rm -rf dist",
|
|
18
|
+
"install:plugin": "npm run bundle && mkdir -p ~/.config/opencode/plugins && cp dist/plugin.bundle.js ~/.config/opencode/plugins/kimi-rotator.js",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"opencode",
|
|
23
|
+
"plugin",
|
|
24
|
+
"kimi",
|
|
25
|
+
"moonshot",
|
|
26
|
+
"api-key",
|
|
27
|
+
"rotation",
|
|
28
|
+
"rate-limit",
|
|
29
|
+
"load-balancer",
|
|
30
|
+
"multi-account"
|
|
31
|
+
],
|
|
32
|
+
"author": "OpenCode User",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/deyndev/opencode-kimi-rotator.git"
|
|
37
|
+
},
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/deyndev/opencode-kimi-rotator/issues"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/deyndev/opencode-kimi-rotator#readme",
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@opencode-ai/plugin": "^0.15.30",
|
|
44
|
+
"proper-lockfile": "^4.1.2",
|
|
45
|
+
"zod": "^3.22.4"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^20.10.0",
|
|
49
|
+
"@types/proper-lockfile": "^4.1.4",
|
|
50
|
+
"esbuild": "^0.27.2",
|
|
51
|
+
"typescript": "^5.3.0"
|
|
52
|
+
},
|
|
53
|
+
"files": [
|
|
54
|
+
"dist",
|
|
55
|
+
"bin",
|
|
56
|
+
"src/plugin.ts",
|
|
57
|
+
"README.md",
|
|
58
|
+
"LICENSE"
|
|
59
|
+
],
|
|
60
|
+
"engines": {
|
|
61
|
+
"node": ">=18.0.0"
|
|
62
|
+
},
|
|
63
|
+
"publishConfig": {
|
|
64
|
+
"access": "public"
|
|
65
|
+
}
|
|
66
|
+
}
|