opencode-kimi-rotator 1.0.1 → 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
@@ -25,7 +25,19 @@ Automatically rotate between multiple Kimi API keys to handle rate limits and di
25
25
  <details open>
26
26
  <summary><b>For Humans</b></summary>
27
27
 
28
- **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**
29
41
 
30
42
  ```bash
31
43
  curl -fsSL https://raw.githubusercontent.com/deyndev/opencode-kimi-rotator/main/scripts/install.sh | bash
@@ -37,7 +49,7 @@ Or for Windows (PowerShell):
37
49
  irm https://raw.githubusercontent.com/deyndev/opencode-kimi-rotator/main/scripts/install.ps1 | iex
38
50
  ```
39
51
 
40
- **Option B: Manual setup**
52
+ **Option C: Manual setup**
41
53
 
42
54
  1. **Clone and build the plugin**:
43
55
 
@@ -65,15 +77,8 @@ irm https://raw.githubusercontent.com/deyndev/opencode-kimi-rotator/main/scripts
65
77
  "output": 32768
66
78
  },
67
79
  "modalities": {
68
- "input": [
69
- "text",
70
- "image",
71
- "video",
72
- "pdf"
73
- ],
74
- "output": [
75
- "text"
76
- ]
80
+ "input": ["text", "image", "video", "pdf"],
81
+ "output": ["text"]
77
82
  }
78
83
  }
79
84
  }
@@ -117,9 +122,7 @@ Add the plugin to your existing config. The plugin path must use the full absolu
117
122
 
118
123
  ```json
119
124
  {
120
- "plugin": [
121
- "file:///Users/YOUR_USERNAME/.config/opencode/plugins/kimi-rotator.js"
122
- ],
125
+ "plugin": ["file:///Users/YOUR_USERNAME/.config/opencode/plugins/kimi-rotator.js"],
123
126
  "provider": {
124
127
  "anthropic": {
125
128
  "name": "Anthropic",
@@ -132,15 +135,8 @@ Add the plugin to your existing config. The plugin path must use the full absolu
132
135
  "output": 32768
133
136
  },
134
137
  "modalities": {
135
- "input": [
136
- "text",
137
- "image",
138
- "video",
139
- "pdf"
140
- ],
141
- "output": [
142
- "text"
143
- ]
138
+ "input": ["text", "image", "video", "pdf"],
139
+ "output": ["text"]
144
140
  }
145
141
  }
146
142
  }
@@ -150,6 +146,7 @@ Add the plugin to your existing config. The plugin path must use the full absolu
150
146
  ```
151
147
 
152
148
  > **Important**: Replace `YOUR_USERNAME` with your actual username. Example paths:
149
+ >
153
150
  > - macOS: `file:///Users/john/.config/opencode/plugins/kimi-rotator.js`
154
151
  > - Linux: `file:///home/john/.config/opencode/plugins/kimi-rotator.js`
155
152
 
@@ -193,6 +190,7 @@ opencode-kimi list-keys
193
190
  ```
194
191
 
195
192
  ### What the plugin does automatically:
193
+
196
194
  - Sets `ANTHROPIC_BASE_URL` to Kimi's API endpoint
197
195
  - Intercepts fetch requests to `api.kimi.com`
198
196
  - Rotates API keys based on health scores
@@ -200,7 +198,6 @@ opencode-kimi list-keys
200
198
 
201
199
  </details>
202
200
 
203
-
204
201
  ---
205
202
 
206
203
  ## Models
@@ -209,13 +206,12 @@ opencode-kimi list-keys
209
206
 
210
207
  The Kimi Coding API provides a single flagship model:
211
208
 
212
- | Model ID | Name | Context | Output |
213
- |----------|------|---------|--------|
209
+ | Model ID | Name | Context | Output |
210
+ | ----------------- | --------- | ------- | ------ |
214
211
  | `kimi-for-coding` | Kimi K2.5 | 262,144 | 32,768 |
215
212
 
216
213
  Use it as: `anthropic/kimi-for-coding`
217
214
 
218
-
219
215
  <details>
220
216
  <summary><b>Full configuration (copy-paste ready)</b></summary>
221
217
 
@@ -224,9 +220,7 @@ Add this to your `~/.config/opencode/opencode.json`:
224
220
  ```json
225
221
  {
226
222
  "$schema": "https://opencode.ai/config.json",
227
- "plugin": [
228
- "file:///Users/YOUR_USERNAME/.config/opencode/plugins/kimi-rotator.js"
229
- ],
223
+ "plugin": ["file:///Users/YOUR_USERNAME/.config/opencode/plugins/kimi-rotator.js"],
230
224
  "provider": {
231
225
  "anthropic": {
232
226
  "name": "Anthropic",
@@ -239,15 +233,8 @@ Add this to your `~/.config/opencode/opencode.json`:
239
233
  "output": 32768
240
234
  },
241
235
  "modalities": {
242
- "input": [
243
- "text",
244
- "image",
245
- "video",
246
- "pdf"
247
- ],
248
- "output": [
249
- "text"
250
- ]
236
+ "input": ["text", "image", "video", "pdf"],
237
+ "output": ["text"]
251
238
  }
252
239
  }
253
240
  }
@@ -277,6 +264,7 @@ opencode-kimi list-keys
277
264
  ```
278
265
 
279
266
  Output:
267
+
280
268
  ```
281
269
  Kimi API Keys (2 total, strategy: health-based):
282
270
 
@@ -318,6 +306,64 @@ opencode-kimi set-strategy health-based
318
306
  opencode-kimi set-strategy sticky
319
307
  ```
320
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
+
321
367
  ---
322
368
 
323
369
  ## How It Works
@@ -325,6 +371,7 @@ opencode-kimi set-strategy sticky
325
371
  ### Health Score System
326
372
 
327
373
  Each API key has a health score (0-100):
374
+
328
375
  - **Initial**: 100
329
376
  - **Success**: +2 points
330
377
  - **Rate Limited**: -15 points
@@ -335,6 +382,7 @@ Keys with health score < 30 are temporarily skipped.
335
382
  ### Rate Limit Handling
336
383
 
337
384
  When a key is rate limited:
385
+
338
386
  1. Health score decreases
339
387
  2. Key is marked as rate limited with reset time
340
388
  3. Next request automatically uses next available key
@@ -343,6 +391,7 @@ When a key is rate limited:
343
391
  ### Data Storage
344
392
 
345
393
  Keys are stored in `~/.config/opencode/kimi-accounts.json`:
394
+
346
395
  ```json
347
396
  {
348
397
  "version": 1,
@@ -356,14 +405,55 @@ Keys are stored in `~/.config/opencode/kimi-accounts.json`:
356
405
  "healthScore": 100,
357
406
  "consecutiveFailures": 0,
358
407
  "totalRequests": 50,
359
- "successfulRequests": 45
408
+ "successfulRequests": 45,
409
+ "responseTimes": [245, 198, 210],
410
+ "dailyRequests": {
411
+ "2026-01-31": 12,
412
+ "2026-02-01": 5
413
+ }
360
414
  }
361
415
  ],
362
416
  "activeIndex": 0,
363
- "rotationStrategy": "health-based"
417
+ "rotationStrategy": "health-based",
418
+ "autoRefreshHealth": true,
419
+ "healthRefreshCooldownMinutes": 30
364
420
  }
365
421
  ```
366
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
+
367
457
  ---
368
458
 
369
459
  ## Configuration
@@ -372,10 +462,10 @@ Keys are stored in `~/.config/opencode/kimi-accounts.json`:
372
462
 
373
463
  OpenCode uses `~/.config/opencode/` on **all platforms** including Windows.
374
464
 
375
- | File | Path |
376
- |------|------|
377
- | Main config | `~/.config/opencode/opencode.json` |
378
- | Accounts | `~/.config/opencode/kimi-accounts.json` |
465
+ | File | Path |
466
+ | ----------- | --------------------------------------- |
467
+ | Main config | `~/.config/opencode/opencode.json` |
468
+ | Accounts | `~/.config/opencode/kimi-accounts.json` |
379
469
 
380
470
  > **Windows users**: `~` resolves to your user home directory (e.g., `C:\Users\YourName`). Do NOT use `%APPDATA%`.
381
471
 
@@ -411,6 +501,7 @@ To use Kimi models with Oh My OpenCode agents, update `~/.config/opencode/oh-my-
411
501
  ### "No Kimi API keys configured"
412
502
 
413
503
  Run:
504
+
414
505
  ```bash
415
506
  opencode-kimi add-key your-api-key
416
507
  ```
@@ -418,6 +509,7 @@ opencode-kimi add-key your-api-key
418
509
  ### All keys rate limited
419
510
 
420
511
  The plugin will wait for the soonest available key. You can:
512
+
421
513
  1. Wait for rate limits to reset
422
514
  2. Add more API keys
423
515
  3. Check status with `opencode-kimi list-keys`
@@ -431,6 +523,7 @@ The plugin will wait for the soonest available key. You can:
431
523
  ### Reset Everything
432
524
 
433
525
  If you need to start fresh:
526
+
434
527
  ```bash
435
528
  rm ~/.config/opencode/kimi-accounts.json
436
529
  opencode-kimi add-key your-new-api-key
@@ -446,10 +539,7 @@ Both plugins can work together. List them in your preferred order:
446
539
 
447
540
  ```json
448
541
  {
449
- "plugin": [
450
- "opencode-kimi-rotator@latest",
451
- "opencode-antigravity-auth@latest"
452
- ]
542
+ "plugin": ["opencode-kimi-rotator@latest", "opencode-antigravity-auth@latest"]
453
543
  }
454
544
  ```
455
545
 
@@ -492,23 +582,27 @@ irm https://raw.githubusercontent.com/deyndev/opencode-kimi-rotator/main/scripts
492
582
  ### Local Development Setup
493
583
 
494
584
  1. Clone the repository:
585
+
495
586
  ```bash
496
587
  git clone https://github.com/deyndev/opencode-kimi-rotator.git
497
588
  cd opencode-kimi-rotator
498
589
  ```
499
590
 
500
591
  2. Install dependencies and build:
592
+
501
593
  ```bash
502
594
  npm install
503
595
  npm run build
504
596
  ```
505
597
 
506
598
  3. Link for local testing:
599
+
507
600
  ```bash
508
601
  npm link
509
602
  ```
510
603
 
511
604
  4. Add to your OpenCode config:
605
+
512
606
  ```json
513
607
  {
514
608
  "plugin": ["opencode-kimi-rotator"]
@@ -517,6 +611,249 @@ npm link
517
611
 
518
612
  ---
519
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
+
520
857
  ## License
521
858
 
522
859
  MIT License. See [LICENSE](LICENSE) for details.
@@ -545,3 +882,13 @@ By using this plugin, you acknowledge:
545
882
  - "Kimi", "Moonshot", and "Moonshot AI" are trademarks of Moonshot AI.
546
883
 
547
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>