opencode-kimi-rotator 1.0.0 → 1.1.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/README.md CHANGED
@@ -1,8 +1,7 @@
1
1
  # Kimi API Key Rotator for OpenCode
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/opencode-kimi-rotator.svg)](https://www.npmjs.com/package/opencode-kimi-rotator)
4
- [![npm beta](https://img.shields.io/npm/v/opencode-kimi-rotator/beta.svg?label=beta)](https://www.npmjs.com/package/opencode-kimi-rotator)
5
- [![npm downloads](https://img.shields.io/npm/dw/opencode-kimi-rotator.svg)](https://www.npmjs.com/package/opencode-kimi-rotator)
4
+ [![npm downloads](https://img.shields.io/npm/dm/opencode-kimi-rotator.svg)](https://www.npmjs.com/package/opencode-kimi-rotator)
6
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
6
 
8
7
  Automatically rotate between multiple Kimi API keys to handle rate limits and distribute load across accounts.
@@ -26,7 +25,19 @@ Automatically rotate between multiple Kimi API keys to handle rate limits and di
26
25
  <details open>
27
26
  <summary><b>For Humans</b></summary>
28
27
 
29
- **Option A: Automatic (Recommended)**
28
+ **Option A: NPM (One-line installation)**
29
+
30
+ ```bash
31
+ npm install -g opencode-kimi-rotator
32
+ ```
33
+
34
+ That's it! The plugin is automatically built and installed. Now add your API keys:
35
+
36
+ ```bash
37
+ opencode-kimi add-key sk-kimi-your-key-here "My Account"
38
+ ```
39
+
40
+ **Option B: Automatic Install Script**
30
41
 
31
42
  ```bash
32
43
  curl -fsSL https://raw.githubusercontent.com/deyndev/opencode-kimi-rotator/main/scripts/install.sh | bash
@@ -38,7 +49,7 @@ Or for Windows (PowerShell):
38
49
  irm https://raw.githubusercontent.com/deyndev/opencode-kimi-rotator/main/scripts/install.ps1 | iex
39
50
  ```
40
51
 
41
- **Option B: Manual setup**
52
+ **Option C: Manual setup**
42
53
 
43
54
  1. **Clone and build the plugin**:
44
55
 
@@ -60,9 +71,14 @@ irm https://raw.githubusercontent.com/deyndev/opencode-kimi-rotator/main/scripts
60
71
  "models": {
61
72
  "kimi-for-coding": {
62
73
  "name": "Kimi K2.5 (via Kimi API)",
74
+ "attachment": true,
63
75
  "limit": {
64
76
  "context": 262144,
65
77
  "output": 32768
78
+ },
79
+ "modalities": {
80
+ "input": ["text", "image", "video", "pdf"],
81
+ "output": ["text"]
66
82
  }
67
83
  }
68
84
  }
@@ -106,16 +122,22 @@ Add the plugin to your existing config. The plugin path must use the full absolu
106
122
 
107
123
  ```json
108
124
  {
109
- "plugin": [
110
- "file:///Users/YOUR_USERNAME/.config/opencode/plugins/kimi-rotator.js"
111
- ],
125
+ "plugin": ["file:///Users/YOUR_USERNAME/.config/opencode/plugins/kimi-rotator.js"],
112
126
  "provider": {
113
127
  "anthropic": {
114
128
  "name": "Anthropic",
115
129
  "models": {
116
130
  "kimi-for-coding": {
117
131
  "name": "Kimi K2.5 (via Kimi API)",
118
- "limit": { "context": 262144, "output": 32768 }
132
+ "attachment": true,
133
+ "limit": {
134
+ "context": 262144,
135
+ "output": 32768
136
+ },
137
+ "modalities": {
138
+ "input": ["text", "image", "video", "pdf"],
139
+ "output": ["text"]
140
+ }
119
141
  }
120
142
  }
121
143
  }
@@ -124,6 +146,7 @@ Add the plugin to your existing config. The plugin path must use the full absolu
124
146
  ```
125
147
 
126
148
  > **Important**: Replace `YOUR_USERNAME` with your actual username. Example paths:
149
+ >
127
150
  > - macOS: `file:///Users/john/.config/opencode/plugins/kimi-rotator.js`
128
151
  > - Linux: `file:///home/john/.config/opencode/plugins/kimi-rotator.js`
129
152
 
@@ -167,6 +190,7 @@ opencode-kimi list-keys
167
190
  ```
168
191
 
169
192
  ### What the plugin does automatically:
193
+
170
194
  - Sets `ANTHROPIC_BASE_URL` to Kimi's API endpoint
171
195
  - Intercepts fetch requests to `api.kimi.com`
172
196
  - Rotates API keys based on health scores
@@ -174,7 +198,6 @@ opencode-kimi list-keys
174
198
 
175
199
  </details>
176
200
 
177
-
178
201
  ---
179
202
 
180
203
  ## Models
@@ -183,13 +206,12 @@ opencode-kimi list-keys
183
206
 
184
207
  The Kimi Coding API provides a single flagship model:
185
208
 
186
- | Model ID | Name | Context | Output |
187
- |----------|------|---------|--------|
209
+ | Model ID | Name | Context | Output |
210
+ | ----------------- | --------- | ------- | ------ |
188
211
  | `kimi-for-coding` | Kimi K2.5 | 262,144 | 32,768 |
189
212
 
190
213
  Use it as: `anthropic/kimi-for-coding`
191
214
 
192
-
193
215
  <details>
194
216
  <summary><b>Full configuration (copy-paste ready)</b></summary>
195
217
 
@@ -198,21 +220,20 @@ Add this to your `~/.config/opencode/opencode.json`:
198
220
  ```json
199
221
  {
200
222
  "$schema": "https://opencode.ai/config.json",
201
- "plugin": [
202
- "file:///Users/YOUR_USERNAME/.config/opencode/plugins/kimi-rotator.js"
203
- ],
223
+ "plugin": ["file:///Users/YOUR_USERNAME/.config/opencode/plugins/kimi-rotator.js"],
204
224
  "provider": {
205
225
  "anthropic": {
206
226
  "name": "Anthropic",
207
227
  "models": {
208
228
  "kimi-for-coding": {
209
229
  "name": "Kimi K2.5 (via Kimi API)",
230
+ "attachment": true,
210
231
  "limit": {
211
232
  "context": 262144,
212
233
  "output": 32768
213
234
  },
214
235
  "modalities": {
215
- "input": ["text", "image", "video"],
236
+ "input": ["text", "image", "video", "pdf"],
216
237
  "output": ["text"]
217
238
  }
218
239
  }
@@ -243,6 +264,7 @@ opencode-kimi list-keys
243
264
  ```
244
265
 
245
266
  Output:
267
+
246
268
  ```
247
269
  Kimi API Keys (2 total, strategy: health-based):
248
270
 
@@ -284,6 +306,64 @@ opencode-kimi set-strategy health-based
284
306
  opencode-kimi set-strategy sticky
285
307
  ```
286
308
 
309
+ ### View Usage Statistics
310
+
311
+ ```bash
312
+ opencode-kimi stats
313
+ ```
314
+
315
+ Output:
316
+
317
+ ```
318
+ 📊 Usage Statistics
319
+
320
+ [0] My Account 1
321
+ Total Requests: 1425
322
+ Successful: 1227
323
+ Failed: 198
324
+ Success Rate: 86.1%
325
+ Avg Response Time: 245ms
326
+ Requests Today: 12
327
+ Requests Last 7 Days: 89
328
+
329
+ [1] My Account 2
330
+ Total Requests: 811
331
+ Successful: 793
332
+ Failed: 18
333
+ Success Rate: 97.8%
334
+ Avg Response Time: 198ms
335
+ Requests Today: 5
336
+ Requests Last 7 Days: 42
337
+
338
+ ──────────────────────────────────────────────────
339
+ 📈 Aggregate Statistics
340
+ Total Requests (All Keys): 2236
341
+ Total Successful: 2020
342
+ Overall Success Rate: 90.3%
343
+ Overall Avg Response Time: 221ms
344
+ ```
345
+
346
+ ### Health Auto-Refresh
347
+
348
+ Automatically restore health scores for rate-limited keys after a cooldown period.
349
+
350
+ ```bash
351
+ # Check current auto-refresh settings
352
+ opencode-kimi list-keys
353
+
354
+ # Enable/disable auto-refresh (default: enabled)
355
+ opencode-kimi set-auto-refresh true
356
+ opencode-kimi set-auto-refresh false
357
+
358
+ # Set cooldown period in minutes (default: 30, range: 1-1440)
359
+ opencode-kimi set-cooldown 30
360
+ opencode-kimi set-cooldown 60 # 1 hour
361
+ opencode-kimi set-cooldown 180 # 3 hours
362
+
363
+ # Manually trigger health refresh
364
+ opencode-kimi refresh-health
365
+ ```
366
+
287
367
  ---
288
368
 
289
369
  ## How It Works
@@ -291,6 +371,7 @@ opencode-kimi set-strategy sticky
291
371
  ### Health Score System
292
372
 
293
373
  Each API key has a health score (0-100):
374
+
294
375
  - **Initial**: 100
295
376
  - **Success**: +2 points
296
377
  - **Rate Limited**: -15 points
@@ -301,6 +382,7 @@ Keys with health score < 30 are temporarily skipped.
301
382
  ### Rate Limit Handling
302
383
 
303
384
  When a key is rate limited:
385
+
304
386
  1. Health score decreases
305
387
  2. Key is marked as rate limited with reset time
306
388
  3. Next request automatically uses next available key
@@ -309,6 +391,7 @@ When a key is rate limited:
309
391
  ### Data Storage
310
392
 
311
393
  Keys are stored in `~/.config/opencode/kimi-accounts.json`:
394
+
312
395
  ```json
313
396
  {
314
397
  "version": 1,
@@ -322,14 +405,55 @@ Keys are stored in `~/.config/opencode/kimi-accounts.json`:
322
405
  "healthScore": 100,
323
406
  "consecutiveFailures": 0,
324
407
  "totalRequests": 50,
325
- "successfulRequests": 45
408
+ "successfulRequests": 45,
409
+ "responseTimes": [245, 198, 210],
410
+ "dailyRequests": {
411
+ "2026-01-31": 12,
412
+ "2026-02-01": 5
413
+ }
326
414
  }
327
415
  ],
328
416
  "activeIndex": 0,
329
- "rotationStrategy": "health-based"
417
+ "rotationStrategy": "health-based",
418
+ "autoRefreshHealth": true,
419
+ "healthRefreshCooldownMinutes": 30
330
420
  }
331
421
  ```
332
422
 
423
+ ### Account Tracking
424
+
425
+ Each account tracks additional metrics for health-based rotation:
426
+
427
+ - **responseTimes** — Array of the last 100 response times (in milliseconds)
428
+ - **dailyRequests** — Record of request counts by date (YYYY-MM-DD format)
429
+
430
+ ### Health Auto-Refresh Settings
431
+
432
+ - **autoRefreshHealth** — Whether to automatically refresh health scores after cooldown (default: `true`)
433
+ - **healthRefreshCooldownMinutes** — Minutes to wait before health can be refreshed (default: `30`, range: 1-1440)
434
+
435
+ When enabled, keys that were rate-limited will have their health score gradually restored (+10 points) after the cooldown period passes, making them available for rotation again.
436
+
437
+ ### Export/Import Keys
438
+
439
+ Backup and migrate your API keys between machines using encrypted files.
440
+
441
+ ```bash
442
+ # Export all keys to an encrypted file
443
+ opencode-kimi export-keys
444
+ opencode-kimi export-keys my-backup.json.enc
445
+
446
+ # Import keys from an encrypted file
447
+ opencode-kimi import-keys my-backup.json.enc
448
+ ```
449
+
450
+ **Features:**
451
+
452
+ - AES-256-GCM encryption with password protection
453
+ - Exports all keys, settings, and statistics
454
+ - Duplicate keys are skipped during import
455
+ - Rotation strategy and auto-refresh settings are preserved
456
+
333
457
  ---
334
458
 
335
459
  ## Configuration
@@ -338,10 +462,10 @@ Keys are stored in `~/.config/opencode/kimi-accounts.json`:
338
462
 
339
463
  OpenCode uses `~/.config/opencode/` on **all platforms** including Windows.
340
464
 
341
- | File | Path |
342
- |------|------|
343
- | Main config | `~/.config/opencode/opencode.json` |
344
- | Accounts | `~/.config/opencode/kimi-accounts.json` |
465
+ | File | Path |
466
+ | ----------- | --------------------------------------- |
467
+ | Main config | `~/.config/opencode/opencode.json` |
468
+ | Accounts | `~/.config/opencode/kimi-accounts.json` |
345
469
 
346
470
  > **Windows users**: `~` resolves to your user home directory (e.g., `C:\Users\YourName`). Do NOT use `%APPDATA%`.
347
471
 
@@ -377,6 +501,7 @@ To use Kimi models with Oh My OpenCode agents, update `~/.config/opencode/oh-my-
377
501
  ### "No Kimi API keys configured"
378
502
 
379
503
  Run:
504
+
380
505
  ```bash
381
506
  opencode-kimi add-key your-api-key
382
507
  ```
@@ -384,6 +509,7 @@ opencode-kimi add-key your-api-key
384
509
  ### All keys rate limited
385
510
 
386
511
  The plugin will wait for the soonest available key. You can:
512
+
387
513
  1. Wait for rate limits to reset
388
514
  2. Add more API keys
389
515
  3. Check status with `opencode-kimi list-keys`
@@ -397,6 +523,7 @@ The plugin will wait for the soonest available key. You can:
397
523
  ### Reset Everything
398
524
 
399
525
  If you need to start fresh:
526
+
400
527
  ```bash
401
528
  rm ~/.config/opencode/kimi-accounts.json
402
529
  opencode-kimi add-key your-new-api-key
@@ -412,10 +539,7 @@ Both plugins can work together. List them in your preferred order:
412
539
 
413
540
  ```json
414
541
  {
415
- "plugin": [
416
- "opencode-kimi-rotator@latest",
417
- "opencode-antigravity-auth@latest"
418
- ]
542
+ "plugin": ["opencode-kimi-rotator@latest", "opencode-antigravity-auth@latest"]
419
543
  }
420
544
  ```
421
545
 
@@ -458,23 +582,27 @@ irm https://raw.githubusercontent.com/deyndev/opencode-kimi-rotator/main/scripts
458
582
  ### Local Development Setup
459
583
 
460
584
  1. Clone the repository:
585
+
461
586
  ```bash
462
587
  git clone https://github.com/deyndev/opencode-kimi-rotator.git
463
588
  cd opencode-kimi-rotator
464
589
  ```
465
590
 
466
591
  2. Install dependencies and build:
592
+
467
593
  ```bash
468
594
  npm install
469
595
  npm run build
470
596
  ```
471
597
 
472
598
  3. Link for local testing:
599
+
473
600
  ```bash
474
601
  npm link
475
602
  ```
476
603
 
477
604
  4. Add to your OpenCode config:
605
+
478
606
  ```json
479
607
  {
480
608
  "plugin": ["opencode-kimi-rotator"]
@@ -483,6 +611,284 @@ npm link
483
611
 
484
612
  ---
485
613
 
614
+ ## Public API
615
+
616
+ ### `KimiAccountManager`
617
+
618
+ Main class for managing Kimi API key rotation.
619
+
620
+ #### Methods
621
+
622
+ ##### `markAccountSuccess(index, responseTime?, date?)`
623
+
624
+ Marks an account as successfully used and updates health metrics.
625
+
626
+ ```typescript
627
+ async markAccountSuccess(
628
+ index: number,
629
+ responseTime?: number,
630
+ date?: string
631
+ ): Promise<void>
632
+ ```
633
+
634
+ - **index** — Account index in the accounts array
635
+ - **responseTime** — Optional response time in milliseconds (tracked in rolling window of 100)
636
+ - **date** — Optional date string (YYYY-MM-DD) for daily request tracking
637
+
638
+ ##### `setAutoRefreshHealth(enabled)`
639
+
640
+ Enables or disables automatic health score refresh.
641
+
642
+ ```typescript
643
+ async setAutoRefreshHealth(enabled: boolean): Promise<void>
644
+ ```
645
+
646
+ ##### `setHealthRefreshCooldown(minutes)`
647
+
648
+ Sets the cooldown period for health refresh.
649
+
650
+ ```typescript
651
+ async setHealthRefreshCooldown(minutes: number): Promise<void>
652
+ ```
653
+
654
+ - **minutes** — Cooldown duration (1-1440, default: 30)
655
+ - **Throws** — Error if minutes is outside valid range
656
+
657
+ ##### `refreshHealthScores()`
658
+
659
+ Manually triggers health score refresh for eligible accounts.
660
+
661
+ ```typescript
662
+ async refreshHealthScores(): Promise<{
663
+ refreshed: number;
664
+ details: string[];
665
+ }>
666
+ ```
667
+
668
+ Returns the number of accounts refreshed and detailed change log.
669
+
670
+ ### `KimiStorage`
671
+
672
+ Handles persistent storage of account configuration with file locking.
673
+
674
+ #### Constructor
675
+
676
+ ```typescript
677
+ constructor();
678
+ ```
679
+
680
+ Creates a new storage instance. The config directory is automatically set to `~/.config/opencode/`.
681
+
682
+ #### Methods
683
+
684
+ ##### `init()`
685
+
686
+ Initializes the storage directory and files.
687
+
688
+ ```typescript
689
+ async init(): Promise<void>
690
+ ```
691
+
692
+ Creates the config directory if it doesn't exist and initializes an empty accounts file.
693
+
694
+ ##### `loadConfig()`
695
+
696
+ Loads and validates the accounts configuration.
697
+
698
+ ```typescript
699
+ async loadConfig(): Promise<KimiAccountsConfig>
700
+ ```
701
+
702
+ - **Returns** — Parsed and validated configuration
703
+ - **Throws** — Error if file cannot be read or parsed
704
+
705
+ ##### `saveConfig(config)`
706
+
707
+ Saves the configuration to disk with file locking.
708
+
709
+ ```typescript
710
+ async saveConfig(config: KimiAccountsConfig): Promise<void>
711
+ ```
712
+
713
+ - **config** — Configuration object to save
714
+ - **Throws** — Error if validation fails or file cannot be written
715
+
716
+ ##### `addAccount(key, name?)`
717
+
718
+ Adds a new API key account.
719
+
720
+ ```typescript
721
+ async addAccount(key: string, name?: string): Promise<KimiAccount>
722
+ ```
723
+
724
+ - **key** — The API key to store
725
+ - **name** — Optional display name for the account
726
+ - **Returns** — The created account object
727
+ - **Throws** — Error if the key already exists
728
+
729
+ ##### `removeAccount(index)`
730
+
731
+ Removes an account by index.
732
+
733
+ ```typescript
734
+ async removeAccount(index: number): Promise<void>
735
+ ```
736
+
737
+ - **index** — Account index to remove
738
+ - **Throws** — Error if index is invalid
739
+
740
+ ##### `listAccounts()`
741
+
742
+ Returns all stored accounts.
743
+
744
+ ```typescript
745
+ async listAccounts(): Promise<KimiAccount[]>
746
+ ```
747
+
748
+ ##### `getActiveAccount()`
749
+
750
+ Returns the currently active account.
751
+
752
+ ```typescript
753
+ async getActiveAccount(): Promise<KimiAccount | null>
754
+ ```
755
+
756
+ - **Returns** — The active account or `null` if no accounts exist
757
+
758
+ ##### `setActiveIndex(index)`
759
+
760
+ Sets the active account index.
761
+
762
+ ```typescript
763
+ async setActiveIndex(index: number): Promise<void>
764
+ ```
765
+
766
+ - **index** — Account index to set as active
767
+ - **Throws** — Error if index is invalid
768
+
769
+ ##### `updateAccount(index, updates)`
770
+
771
+ Updates specific fields of an account.
772
+
773
+ ```typescript
774
+ async updateAccount(index: number, updates: Partial<KimiAccount>): Promise<void>
775
+ ```
776
+
777
+ - **index** — Account index to update
778
+ - **updates** — Partial account object with fields to update
779
+ - **Throws** — Error if index is invalid
780
+
781
+ ### Schemas
782
+
783
+ #### `KimiAccountSchema`
784
+
785
+ Zod schema for validating Kimi account objects:
786
+
787
+ ```javascript
788
+ {
789
+ key: string, // API key (required)
790
+ name: string, // Optional account name
791
+ addedAt: number, // Timestamp when added
792
+ lastUsed: number, // Timestamp of last use
793
+ rateLimitResetTime: number, // Default: 0
794
+ healthScore: number, // 0-100, default: 100
795
+ consecutiveFailures: number, // Default: 0
796
+ totalRequests: number, // Default: 0
797
+ successfulRequests: number, // Default: 0
798
+ responseTimes: number[], // Array of response times (ms)
799
+ dailyRequests: Record<string, number> // Requests per day
800
+ }
801
+ ```
802
+
803
+ #### `KimiAccountsConfigSchema`
804
+
805
+ Zod schema for the accounts configuration:
806
+
807
+ ```javascript
808
+ {
809
+ version: number, // Default: 1
810
+ accounts: KimiAccount[], // Array of accounts
811
+ activeIndex: number, // Default: 0
812
+ rotationStrategy: 'round-robin' | 'health-based' | 'sticky',
813
+ autoRefreshHealth: boolean, // Default: true
814
+ healthRefreshCooldownMinutes: number // Default: 30, range: 1-1440
815
+ }
816
+ ```
817
+
818
+ ### Types
819
+
820
+ - `KimiAccount` — Inferred type from `KimiAccountSchema`
821
+ - `KimiAccountsConfig` — Inferred type from `KimiAccountsConfigSchema`
822
+
823
+ ### Constants
824
+
825
+ #### `DEFAULT_ACCOUNT`
826
+
827
+ Default values for new accounts (excludes `key`, `addedAt`, `lastUsed`):
828
+
829
+ ```javascript
830
+ {
831
+ rateLimitResetTime: 0,
832
+ healthScore: 100,
833
+ consecutiveFailures: 0,
834
+ totalRequests: 0,
835
+ successfulRequests: 0,
836
+ responseTimes: [],
837
+ dailyRequests: {}
838
+ }
839
+ ```
840
+
841
+ #### `DEFAULT_CONFIG`
842
+
843
+ Default configuration values (excludes `accounts`):
844
+
845
+ ```javascript
846
+ {
847
+ version: 1,
848
+ activeIndex: 0,
849
+ rotationStrategy: 'health-based',
850
+ autoRefreshHealth: true,
851
+ healthRefreshCooldownMinutes: 30
852
+ }
853
+ ```
854
+
855
+ ---
856
+
486
857
  ## License
487
858
 
488
859
  MIT License. See [LICENSE](LICENSE) for details.
860
+
861
+ <details>
862
+ <summary><b>Legal</b></summary>
863
+
864
+ ### Intended Use
865
+
866
+ - Personal / internal development only
867
+ - Respect internal quotas and data handling policies
868
+ - Not for production services or bypassing intended limits
869
+
870
+ ### Warning
871
+
872
+ By using this plugin, you acknowledge:
873
+
874
+ - **Terms of Service risk** — This approach may violate ToS of AI model providers
875
+ - **Account risk** — Providers may suspend or ban accounts
876
+ - **No guarantees** — APIs may change without notice
877
+ - **Assumption of risk** — You assume all legal, financial, and technical risks
878
+
879
+ ### Disclaimer
880
+
881
+ - Not affiliated with Moonshot AI. This is an independent open-source project.
882
+ - "Kimi", "Moonshot", and "Moonshot AI" are trademarks of Moonshot AI.
883
+
884
+ </details>
885
+
886
+ ---
887
+
888
+ ## Contributors
889
+
890
+ Thanks to all the people who already contributed!
891
+
892
+ <a href="https://github.com/deyndev/opencode-kimi-rotator/graphs/contributors">
893
+ <img src="https://contributors-img.web.app/image?repo=deyndev/opencode-kimi-rotator&max=750&columns=20" />
894
+ </a>