@itssimplereally/opencode-kimicode-auth 0.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/LICENSE +22 -0
- package/README.md +87 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/src/constants.d.ts +69 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +207 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/kimi/oauth.d.ts +64 -0
- package/dist/src/kimi/oauth.d.ts.map +1 -0
- package/dist/src/kimi/oauth.js +130 -0
- package/dist/src/kimi/oauth.js.map +1 -0
- package/dist/src/plugin/accounts.d.ts +167 -0
- package/dist/src/plugin/accounts.d.ts.map +1 -0
- package/dist/src/plugin/accounts.js +843 -0
- package/dist/src/plugin/accounts.js.map +1 -0
- package/dist/src/plugin/auth.d.ts +13 -0
- package/dist/src/plugin/auth.d.ts.map +1 -0
- package/dist/src/plugin/auth.js +26 -0
- package/dist/src/plugin/auth.js.map +1 -0
- package/dist/src/plugin/cache.d.ts +14 -0
- package/dist/src/plugin/cache.d.ts.map +1 -0
- package/dist/src/plugin/cache.js +56 -0
- package/dist/src/plugin/cache.js.map +1 -0
- package/dist/src/plugin/cli.d.ts +21 -0
- package/dist/src/plugin/cli.d.ts.map +1 -0
- package/dist/src/plugin/cli.js +98 -0
- package/dist/src/plugin/cli.js.map +1 -0
- package/dist/src/plugin/config/index.d.ts +16 -0
- package/dist/src/plugin/config/index.d.ts.map +1 -0
- package/dist/src/plugin/config/index.js +16 -0
- package/dist/src/plugin/config/index.js.map +1 -0
- package/dist/src/plugin/config/loader.d.ts +36 -0
- package/dist/src/plugin/config/loader.d.ts.map +1 -0
- package/dist/src/plugin/config/loader.js +182 -0
- package/dist/src/plugin/config/loader.js.map +1 -0
- package/dist/src/plugin/config/models.d.ts +18 -0
- package/dist/src/plugin/config/models.d.ts.map +1 -0
- package/dist/src/plugin/config/models.js +26 -0
- package/dist/src/plugin/config/models.js.map +1 -0
- package/dist/src/plugin/config/schema.d.ts +107 -0
- package/dist/src/plugin/config/schema.d.ts.map +1 -0
- package/dist/src/plugin/config/schema.js +282 -0
- package/dist/src/plugin/config/schema.js.map +1 -0
- package/dist/src/plugin/config/updater.d.ts +55 -0
- package/dist/src/plugin/config/updater.d.ts.map +1 -0
- package/dist/src/plugin/config/updater.js +154 -0
- package/dist/src/plugin/config/updater.js.map +1 -0
- package/dist/src/plugin/debug.d.ts +92 -0
- package/dist/src/plugin/debug.d.ts.map +1 -0
- package/dist/src/plugin/debug.js +406 -0
- package/dist/src/plugin/debug.js.map +1 -0
- package/dist/src/plugin/errors.d.ts +28 -0
- package/dist/src/plugin/errors.d.ts.map +1 -0
- package/dist/src/plugin/errors.js +42 -0
- package/dist/src/plugin/errors.js.map +1 -0
- package/dist/src/plugin/fingerprint.d.ts +41 -0
- package/dist/src/plugin/fingerprint.d.ts.map +1 -0
- package/dist/src/plugin/fingerprint.js +94 -0
- package/dist/src/plugin/fingerprint.js.map +1 -0
- package/dist/src/plugin/logger.d.ts +54 -0
- package/dist/src/plugin/logger.d.ts.map +1 -0
- package/dist/src/plugin/logger.js +120 -0
- package/dist/src/plugin/logger.js.map +1 -0
- package/dist/src/plugin/recovery/constants.d.ts +26 -0
- package/dist/src/plugin/recovery/constants.d.ts.map +1 -0
- package/dist/src/plugin/recovery/constants.js +47 -0
- package/dist/src/plugin/recovery/constants.js.map +1 -0
- package/dist/src/plugin/recovery/index.d.ts +16 -0
- package/dist/src/plugin/recovery/index.d.ts.map +1 -0
- package/dist/src/plugin/recovery/index.js +16 -0
- package/dist/src/plugin/recovery/index.js.map +1 -0
- package/dist/src/plugin/recovery/storage.d.ts +24 -0
- package/dist/src/plugin/recovery/storage.d.ts.map +1 -0
- package/dist/src/plugin/recovery/storage.js +354 -0
- package/dist/src/plugin/recovery/storage.js.map +1 -0
- package/dist/src/plugin/recovery/types.d.ts +116 -0
- package/dist/src/plugin/recovery/types.d.ts.map +1 -0
- package/dist/src/plugin/recovery/types.js +6 -0
- package/dist/src/plugin/recovery/types.js.map +1 -0
- package/dist/src/plugin/recovery.d.ts +63 -0
- package/dist/src/plugin/recovery.d.ts.map +1 -0
- package/dist/src/plugin/recovery.js +331 -0
- package/dist/src/plugin/recovery.js.map +1 -0
- package/dist/src/plugin/refresh-queue.d.ts +101 -0
- package/dist/src/plugin/refresh-queue.d.ts.map +1 -0
- package/dist/src/plugin/refresh-queue.js +248 -0
- package/dist/src/plugin/refresh-queue.js.map +1 -0
- package/dist/src/plugin/rotation.d.ts +169 -0
- package/dist/src/plugin/rotation.d.ts.map +1 -0
- package/dist/src/plugin/rotation.js +328 -0
- package/dist/src/plugin/rotation.js.map +1 -0
- package/dist/src/plugin/storage.d.ts +90 -0
- package/dist/src/plugin/storage.d.ts.map +1 -0
- package/dist/src/plugin/storage.js +450 -0
- package/dist/src/plugin/storage.js.map +1 -0
- package/dist/src/plugin/token.d.ts +19 -0
- package/dist/src/plugin/token.d.ts.map +1 -0
- package/dist/src/plugin/token.js +112 -0
- package/dist/src/plugin/token.js.map +1 -0
- package/dist/src/plugin/types.d.ts +97 -0
- package/dist/src/plugin/types.d.ts.map +1 -0
- package/dist/src/plugin/types.js +1 -0
- package/dist/src/plugin/types.js.map +1 -0
- package/dist/src/plugin/version.d.ts +14 -0
- package/dist/src/plugin/version.d.ts.map +1 -0
- package/dist/src/plugin/version.js +20 -0
- package/dist/src/plugin/version.js.map +1 -0
- package/dist/src/plugin.d.ts +5 -0
- package/dist/src/plugin.d.ts.map +1 -0
- package/dist/src/plugin.js +1077 -0
- package/dist/src/plugin.js.map +1 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 opencode-kimicode-auth contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# OpenCode Kimi Code Auth
|
|
2
|
+
|
|
3
|
+
OpenCode plugin for **Kimi Code OAuth** under the **Moonshot AI** provider.
|
|
4
|
+
|
|
5
|
+
Authenticates via device-code OAuth (same flow as kimi-cli), manages multi-account rotation, and routes requests to the Kimi Code API.
|
|
6
|
+
|
|
7
|
+
## Models
|
|
8
|
+
|
|
9
|
+
| OpenCode model | Mode | Kimi API model |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `moonshotai/kimicode-kimi-k2.5` | Thinking off | `kimi-for-coding` |
|
|
12
|
+
| `moonshotai/kimicode-kimi-k2.5-thinking` | Thinking on | `kimi-for-coding` |
|
|
13
|
+
|
|
14
|
+
Both models use 262k context and 32k output. Existing `moonshotai/*` API-key models are unaffected.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
Add the plugin to `~/.config/opencode/opencode.json`:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"$schema": "https://opencode.ai/config.json",
|
|
23
|
+
"plugin": [
|
|
24
|
+
"@itssimplereally/opencode-kimicode-auth@latest"
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Then authenticate:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
opencode auth login
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
In the picker, select **Moonshot AI** → **OAuth (Kimi Code / kimi-cli)**.
|
|
36
|
+
|
|
37
|
+
A browser window opens for Kimi device authorization. After approval, the plugin stores your tokens locally. You can add multiple accounts for rotation.
|
|
38
|
+
|
|
39
|
+
Verify:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
opencode models moonshotai
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Troubleshooting
|
|
46
|
+
|
|
47
|
+
- **Only seeing "Enter your API key"** — Ensure `"@itssimplereally/opencode-kimicode-auth@latest"` is in your plugin array, then re-run `opencode auth login`.
|
|
48
|
+
- **Auth errors after working setup** — Your refresh token may have expired. Re-run `opencode auth login`.
|
|
49
|
+
|
|
50
|
+
## For LLMs
|
|
51
|
+
|
|
52
|
+
Copy this prompt into your coding agent to set up the plugin:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
Configure OpenCode on this machine to use Kimi Code OAuth via the published plugin.
|
|
56
|
+
|
|
57
|
+
Goal:
|
|
58
|
+
- Use Kimi Code OAuth in OpenCode for moonshotai/kimicode-* models.
|
|
59
|
+
|
|
60
|
+
Rules:
|
|
61
|
+
- Never print credential values.
|
|
62
|
+
- Only modify config fields required for this setup.
|
|
63
|
+
|
|
64
|
+
Steps:
|
|
65
|
+
1. Validate tools:
|
|
66
|
+
- Run: opencode --version
|
|
67
|
+
2. Update OpenCode config:
|
|
68
|
+
- File: ~/.config/opencode/opencode.json
|
|
69
|
+
- Ensure the plugin array includes: "@itssimplereally/opencode-kimicode-auth@latest"
|
|
70
|
+
- Preserve all other existing plugin entries.
|
|
71
|
+
3. Verify OpenCode starts cleanly:
|
|
72
|
+
- Run: opencode auth list
|
|
73
|
+
- If plugin install/import errors occur, fix the plugin entry first.
|
|
74
|
+
4. **Do not attempt interactive auth in this session.**
|
|
75
|
+
- Ask the human to run: opencode auth login
|
|
76
|
+
- Ask the human to choose provider "Moonshot AI" and method "OAuth (Kimi Code / kimi-cli)".
|
|
77
|
+
- Wait for the human to confirm they completed authorization.
|
|
78
|
+
5. After human confirmation, verify:
|
|
79
|
+
- Run: opencode auth list
|
|
80
|
+
- Run: opencode models moonshotai
|
|
81
|
+
- Confirm output includes moonshotai/kimicode-kimi-k2.5 and moonshotai/kimicode-kimi-k2.5-thinking.
|
|
82
|
+
6. Return a concise report of changes and verification results.
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,YAAY,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants for Kimi Code OAuth flows and API integration.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* OAuth client ID for Kimi Code (from kimi-cli).
|
|
6
|
+
*/
|
|
7
|
+
export declare const KIMI_CLIENT_ID = "17e5f671-d194-4dfb-9706-5516cb48c098";
|
|
8
|
+
/**
|
|
9
|
+
* OAuth host for Kimi authentication.
|
|
10
|
+
* Env override: KIMI_CODE_OAUTH_HOST
|
|
11
|
+
*/
|
|
12
|
+
export declare const KIMI_OAUTH_HOST: string;
|
|
13
|
+
/**
|
|
14
|
+
* Device authorization endpoint.
|
|
15
|
+
*/
|
|
16
|
+
export declare const KIMI_DEVICE_AUTH_ENDPOINT: string;
|
|
17
|
+
/**
|
|
18
|
+
* Token endpoint (for both device code exchange and refresh).
|
|
19
|
+
*/
|
|
20
|
+
export declare const KIMI_TOKEN_ENDPOINT: string;
|
|
21
|
+
/**
|
|
22
|
+
* Base URL for Kimi Code API.
|
|
23
|
+
* Env override: KIMI_CODE_BASE_URL
|
|
24
|
+
*/
|
|
25
|
+
export declare const KIMI_API_BASE_URL: string;
|
|
26
|
+
/**
|
|
27
|
+
* Chat completions endpoint (OpenAI-compatible).
|
|
28
|
+
*/
|
|
29
|
+
export declare const KIMI_CHAT_COMPLETIONS_ENDPOINT: string;
|
|
30
|
+
/**
|
|
31
|
+
* Models listing endpoint.
|
|
32
|
+
*/
|
|
33
|
+
export declare const KIMI_MODELS_ENDPOINT: string;
|
|
34
|
+
/**
|
|
35
|
+
* Grant type for device code token exchange.
|
|
36
|
+
*/
|
|
37
|
+
export declare const KIMI_DEVICE_CODE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
38
|
+
/**
|
|
39
|
+
* Grant type for token refresh.
|
|
40
|
+
*/
|
|
41
|
+
export declare const KIMI_REFRESH_GRANT_TYPE = "refresh_token";
|
|
42
|
+
/**
|
|
43
|
+
* Token refresh threshold in seconds (refresh when < 300s remaining).
|
|
44
|
+
*/
|
|
45
|
+
export declare const KIMI_REFRESH_THRESHOLD_SECONDS = 300;
|
|
46
|
+
/**
|
|
47
|
+
* Background token refresh interval in seconds.
|
|
48
|
+
*/
|
|
49
|
+
export declare const KIMI_REFRESH_INTERVAL_SECONDS = 60;
|
|
50
|
+
/**
|
|
51
|
+
* Provider identifier shared between the plugin loader and credential store.
|
|
52
|
+
*/
|
|
53
|
+
export declare const KIMI_PROVIDER_ID = "kimi";
|
|
54
|
+
export declare function getKimiPluginVersion(): string;
|
|
55
|
+
export declare function setKimiPluginVersion(version: string): void;
|
|
56
|
+
export declare function getKimiUserAgent(): string;
|
|
57
|
+
/**
|
|
58
|
+
* X-Msh-* device headers for Kimi API requests.
|
|
59
|
+
* These mimic the headers sent by the official kimi-cli.
|
|
60
|
+
*/
|
|
61
|
+
export declare function getKimiDeviceHeaders(deviceId: string): Record<string, string>;
|
|
62
|
+
/**
|
|
63
|
+
* X-Msh-* headers for OAuth requests (device auth, token exchange, refresh).
|
|
64
|
+
* Matches kimi-cli's _common_headers() which sends these on every OAuth call.
|
|
65
|
+
* Uses a session-stable device ID generated at module load.
|
|
66
|
+
*/
|
|
67
|
+
export declare function getKimiOAuthHeaders(): Record<string, string>;
|
|
68
|
+
export declare function setOAuthDeviceId(id: string): void;
|
|
69
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH;;GAEG;AACH,eAAO,MAAM,cAAc,yCAAyC,CAAA;AAEpE;;;GAGG;AACH,eAAO,MAAM,eAAe,QAA8D,CAAA;AAE1F;;GAEG;AACH,eAAO,MAAM,yBAAyB,QAAsD,CAAA;AAE5F;;GAEG;AACH,eAAO,MAAM,mBAAmB,QAAuC,CAAA;AAEvE;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAAqE,CAAA;AAEnG;;GAEG;AACH,eAAO,MAAM,8BAA8B,QAA0C,CAAA;AAErF;;GAEG;AACH,eAAO,MAAM,oBAAoB,QAAgC,CAAA;AAEjE;;GAEG;AACH,eAAO,MAAM,2BAA2B,iDAAiD,CAAA;AAEzF;;GAEG;AACH,eAAO,MAAM,uBAAuB,kBAAkB,CAAA;AAEtD;;GAEG;AACH,eAAO,MAAM,8BAA8B,MAAM,CAAA;AAEjD;;GAEG;AACH,eAAO,MAAM,6BAA6B,KAAK,CAAA;AAE/C;;GAEG;AACH,eAAO,MAAM,gBAAgB,SAAS,CAAA;AAWtC,wBAAgB,oBAAoB,IAAI,MAAM,CAA6B;AAE3E,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAI1D;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAIzC;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAS7E;AAsED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAS5D;AAiBD,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEjD"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants for Kimi Code OAuth flows and API integration.
|
|
3
|
+
*/
|
|
4
|
+
import { execSync } from "node:child_process";
|
|
5
|
+
import { randomBytes } from "node:crypto";
|
|
6
|
+
import { arch, hostname, platform, release, version as osVersion, } from "node:os";
|
|
7
|
+
/**
|
|
8
|
+
* OAuth client ID for Kimi Code (from kimi-cli).
|
|
9
|
+
*/
|
|
10
|
+
export const KIMI_CLIENT_ID = "17e5f671-d194-4dfb-9706-5516cb48c098";
|
|
11
|
+
/**
|
|
12
|
+
* OAuth host for Kimi authentication.
|
|
13
|
+
* Env override: KIMI_CODE_OAUTH_HOST
|
|
14
|
+
*/
|
|
15
|
+
export const KIMI_OAUTH_HOST = process.env.KIMI_CODE_OAUTH_HOST || "https://auth.kimi.com";
|
|
16
|
+
/**
|
|
17
|
+
* Device authorization endpoint.
|
|
18
|
+
*/
|
|
19
|
+
export const KIMI_DEVICE_AUTH_ENDPOINT = `${KIMI_OAUTH_HOST}/api/oauth/device_authorization`;
|
|
20
|
+
/**
|
|
21
|
+
* Token endpoint (for both device code exchange and refresh).
|
|
22
|
+
*/
|
|
23
|
+
export const KIMI_TOKEN_ENDPOINT = `${KIMI_OAUTH_HOST}/api/oauth/token`;
|
|
24
|
+
/**
|
|
25
|
+
* Base URL for Kimi Code API.
|
|
26
|
+
* Env override: KIMI_CODE_BASE_URL
|
|
27
|
+
*/
|
|
28
|
+
export const KIMI_API_BASE_URL = process.env.KIMI_CODE_BASE_URL || "https://api.kimi.com/coding/v1";
|
|
29
|
+
/**
|
|
30
|
+
* Chat completions endpoint (OpenAI-compatible).
|
|
31
|
+
*/
|
|
32
|
+
export const KIMI_CHAT_COMPLETIONS_ENDPOINT = `${KIMI_API_BASE_URL}/chat/completions`;
|
|
33
|
+
/**
|
|
34
|
+
* Models listing endpoint.
|
|
35
|
+
*/
|
|
36
|
+
export const KIMI_MODELS_ENDPOINT = `${KIMI_API_BASE_URL}/models`;
|
|
37
|
+
/**
|
|
38
|
+
* Grant type for device code token exchange.
|
|
39
|
+
*/
|
|
40
|
+
export const KIMI_DEVICE_CODE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
41
|
+
/**
|
|
42
|
+
* Grant type for token refresh.
|
|
43
|
+
*/
|
|
44
|
+
export const KIMI_REFRESH_GRANT_TYPE = "refresh_token";
|
|
45
|
+
/**
|
|
46
|
+
* Token refresh threshold in seconds (refresh when < 300s remaining).
|
|
47
|
+
*/
|
|
48
|
+
export const KIMI_REFRESH_THRESHOLD_SECONDS = 300;
|
|
49
|
+
/**
|
|
50
|
+
* Background token refresh interval in seconds.
|
|
51
|
+
*/
|
|
52
|
+
export const KIMI_REFRESH_INTERVAL_SECONDS = 60;
|
|
53
|
+
/**
|
|
54
|
+
* Provider identifier shared between the plugin loader and credential store.
|
|
55
|
+
*/
|
|
56
|
+
export const KIMI_PROVIDER_ID = "kimi";
|
|
57
|
+
/**
|
|
58
|
+
* Emulated kimi-cli version for User-Agent and X-Msh-Version headers.
|
|
59
|
+
* This should track a recent kimi-cli release to avoid server-side
|
|
60
|
+
* version gating. Override with KIMI_CODE_CLI_VERSION env var.
|
|
61
|
+
*/
|
|
62
|
+
const KIMI_CLI_COMPAT_VERSION = "1.12.0";
|
|
63
|
+
let kimiPluginVersion = process.env.KIMI_CODE_CLI_VERSION || KIMI_CLI_COMPAT_VERSION;
|
|
64
|
+
let versionLocked = !!process.env.KIMI_CODE_CLI_VERSION;
|
|
65
|
+
export function getKimiPluginVersion() { return kimiPluginVersion; }
|
|
66
|
+
export function setKimiPluginVersion(version) {
|
|
67
|
+
if (versionLocked)
|
|
68
|
+
return;
|
|
69
|
+
kimiPluginVersion = version;
|
|
70
|
+
versionLocked = true;
|
|
71
|
+
}
|
|
72
|
+
export function getKimiUserAgent() {
|
|
73
|
+
// Kimi For Coding access is gated on known coding-agent user agents.
|
|
74
|
+
// Mimic kimi-cli by default, but allow an escape hatch.
|
|
75
|
+
return process.env.OPENCODE_KIMICODE_USER_AGENT || `KimiCLI/${getKimiPluginVersion()}`;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* X-Msh-* device headers for Kimi API requests.
|
|
79
|
+
* These mimic the headers sent by the official kimi-cli.
|
|
80
|
+
*/
|
|
81
|
+
export function getKimiDeviceHeaders(deviceId) {
|
|
82
|
+
return {
|
|
83
|
+
"X-Msh-Platform": "kimi_cli",
|
|
84
|
+
"X-Msh-Version": getKimiPluginVersion(),
|
|
85
|
+
"X-Msh-Device-Name": asciiHeaderValue(getDeviceName()),
|
|
86
|
+
"X-Msh-Device-Model": asciiHeaderValue(getDeviceModel()),
|
|
87
|
+
"X-Msh-Os-Version": asciiHeaderValue(getOsVersion()),
|
|
88
|
+
"X-Msh-Device-Id": deviceId,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function getDeviceName() {
|
|
92
|
+
try {
|
|
93
|
+
return hostname();
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return "unknown";
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function getMacOsVersion() {
|
|
100
|
+
try {
|
|
101
|
+
return execSync("sw_vers -productVersion", { encoding: "utf8" }).trim();
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Fallback: derive from Darwin kernel version (e.g. 23.x → 14.x)
|
|
105
|
+
try {
|
|
106
|
+
return release();
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return "";
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function getWindowsRelease() {
|
|
114
|
+
try {
|
|
115
|
+
// os.release() returns e.g. "10.0.22621" on Windows
|
|
116
|
+
const rel = release();
|
|
117
|
+
const major = rel.split(".")[0];
|
|
118
|
+
// Windows 11 is still NT 10.0 but with build >= 22000
|
|
119
|
+
if (major === "10") {
|
|
120
|
+
const build = parseInt(rel.split(".")[2] ?? "0", 10);
|
|
121
|
+
if (build >= 22000)
|
|
122
|
+
return "11";
|
|
123
|
+
}
|
|
124
|
+
return major ?? rel;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return "";
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function getDeviceModel() {
|
|
131
|
+
const sys = platform();
|
|
132
|
+
const a = arch();
|
|
133
|
+
if (sys === "darwin") {
|
|
134
|
+
const ver = getMacOsVersion();
|
|
135
|
+
if (ver && a)
|
|
136
|
+
return `macOS ${ver} ${a}`;
|
|
137
|
+
if (ver)
|
|
138
|
+
return `macOS ${ver}`;
|
|
139
|
+
return `macOS ${a}`.trim();
|
|
140
|
+
}
|
|
141
|
+
if (sys === "win32") {
|
|
142
|
+
const rel = getWindowsRelease();
|
|
143
|
+
if (rel && a)
|
|
144
|
+
return `Windows ${rel} ${a}`;
|
|
145
|
+
if (rel)
|
|
146
|
+
return `Windows ${rel}`;
|
|
147
|
+
return `Windows ${a}`.trim();
|
|
148
|
+
}
|
|
149
|
+
if (sys)
|
|
150
|
+
return `${sys} ${release()} ${a}`.trim();
|
|
151
|
+
return "Unknown";
|
|
152
|
+
}
|
|
153
|
+
function getOsVersion() {
|
|
154
|
+
try {
|
|
155
|
+
return osVersion();
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
try {
|
|
159
|
+
return release();
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return "unknown";
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* X-Msh-* headers for OAuth requests (device auth, token exchange, refresh).
|
|
168
|
+
* Matches kimi-cli's _common_headers() which sends these on every OAuth call.
|
|
169
|
+
* Uses a session-stable device ID generated at module load.
|
|
170
|
+
*/
|
|
171
|
+
export function getKimiOAuthHeaders() {
|
|
172
|
+
return {
|
|
173
|
+
"X-Msh-Platform": "kimi_cli",
|
|
174
|
+
"X-Msh-Version": getKimiPluginVersion(),
|
|
175
|
+
"X-Msh-Device-Name": asciiHeaderValue(getDeviceName()),
|
|
176
|
+
"X-Msh-Device-Model": asciiHeaderValue(getDeviceModel()),
|
|
177
|
+
"X-Msh-Os-Version": asciiHeaderValue(getOsVersion()),
|
|
178
|
+
"X-Msh-Device-Id": getOrCreateOAuthDeviceId(),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Lazily-generated device ID for OAuth requests.
|
|
183
|
+
* In kimi-cli this is persisted to ~/.kimi/device_id; here we generate once
|
|
184
|
+
* per process and also allow the fingerprint module to override it later.
|
|
185
|
+
*/
|
|
186
|
+
let oauthDeviceId = null;
|
|
187
|
+
function getOrCreateOAuthDeviceId() {
|
|
188
|
+
if (!oauthDeviceId) {
|
|
189
|
+
// Generate a 32-char lowercase hex string matching kimi-cli's uuid4().hex format
|
|
190
|
+
oauthDeviceId = randomBytes(16).toString("hex");
|
|
191
|
+
}
|
|
192
|
+
return oauthDeviceId;
|
|
193
|
+
}
|
|
194
|
+
export function setOAuthDeviceId(id) {
|
|
195
|
+
oauthDeviceId = id;
|
|
196
|
+
}
|
|
197
|
+
function asciiHeaderValue(value, fallback = "unknown") {
|
|
198
|
+
if (/^[\x00-\x7F]*$/.test(value))
|
|
199
|
+
return value;
|
|
200
|
+
const sanitized = value
|
|
201
|
+
.split("")
|
|
202
|
+
.filter((ch) => ch.charCodeAt(0) < 128)
|
|
203
|
+
.join("")
|
|
204
|
+
.trim();
|
|
205
|
+
return sanitized || fallback;
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kimi Device Authorization Grant (RFC 8628)
|
|
3
|
+
*
|
|
4
|
+
* Implements the device code flow used by kimi-cli:
|
|
5
|
+
* 1. Request device code from auth.kimi.com
|
|
6
|
+
* 2. User visits verification URL and enters code
|
|
7
|
+
* 3. Plugin polls token endpoint until user completes auth
|
|
8
|
+
*/
|
|
9
|
+
export interface DeviceAuthorizationResponse {
|
|
10
|
+
device_code: string;
|
|
11
|
+
user_code: string;
|
|
12
|
+
verification_uri: string;
|
|
13
|
+
verification_uri_complete?: string;
|
|
14
|
+
expires_in: number;
|
|
15
|
+
interval: number;
|
|
16
|
+
}
|
|
17
|
+
export interface KimiTokenExchangeResult {
|
|
18
|
+
access_token: string;
|
|
19
|
+
refresh_token: string;
|
|
20
|
+
expires_in: number;
|
|
21
|
+
scope?: string;
|
|
22
|
+
token_type: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Request a device code from Kimi's OAuth server.
|
|
26
|
+
* Returns device_code, user_code, and verification_uri for the user.
|
|
27
|
+
*/
|
|
28
|
+
export declare function requestDeviceAuthorization(): Promise<DeviceAuthorizationResponse>;
|
|
29
|
+
export type PollResult = {
|
|
30
|
+
status: "success";
|
|
31
|
+
tokens: KimiTokenExchangeResult;
|
|
32
|
+
} | {
|
|
33
|
+
status: "pending";
|
|
34
|
+
} | {
|
|
35
|
+
status: "slow_down";
|
|
36
|
+
interval: number;
|
|
37
|
+
} | {
|
|
38
|
+
status: "expired";
|
|
39
|
+
} | {
|
|
40
|
+
status: "error";
|
|
41
|
+
message: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Poll the token endpoint until the user completes authorization.
|
|
45
|
+
* Implements backoff on slow_down responses and respects expiration.
|
|
46
|
+
*
|
|
47
|
+
* @param deviceCode The device code from requestDeviceAuthorization
|
|
48
|
+
* @param intervalSeconds Initial polling interval in seconds
|
|
49
|
+
* @param expiresInSeconds Time until the device code expires
|
|
50
|
+
* @param signal Optional AbortSignal to cancel polling
|
|
51
|
+
*/
|
|
52
|
+
export declare function pollForToken(deviceCode: string, intervalSeconds: number, expiresInSeconds: number, signal?: AbortSignal): Promise<KimiTokenExchangeResult>;
|
|
53
|
+
export interface KimiAuthorization {
|
|
54
|
+
verificationUri: string;
|
|
55
|
+
userCode: string;
|
|
56
|
+
poll: (signal?: AbortSignal) => Promise<KimiTokenExchangeResult>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Start the Kimi device authorization flow.
|
|
60
|
+
* Returns the verification URL/code for the user, and a poll function
|
|
61
|
+
* to await completion.
|
|
62
|
+
*/
|
|
63
|
+
export declare function authorizeKimi(): Promise<KimiAuthorization>;
|
|
64
|
+
//# sourceMappingURL=oauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../../src/kimi/oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAcH,MAAM,WAAW,2BAA2B;IAC1C,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,MAAM,CAAA;IACxB,yBAAyB,CAAC,EAAE,MAAM,CAAA;IAClC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;CACnB;AAMD;;;GAGG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,2BAA2B,CAAC,CAoBvF;AAMD,MAAM,MAAM,UAAU,GAClB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,uBAAuB,CAAA;CAAE,GACtD;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AA8CxC;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,EACvB,gBAAgB,EAAE,MAAM,EACxB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,uBAAuB,CAAC,CAiClC;AAMD,MAAM,WAAW,iBAAiB;IAChC,eAAe,EAAE,MAAM,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAA;CACjE;AAED;;;;GAIG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAchE"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kimi Device Authorization Grant (RFC 8628)
|
|
3
|
+
*
|
|
4
|
+
* Implements the device code flow used by kimi-cli:
|
|
5
|
+
* 1. Request device code from auth.kimi.com
|
|
6
|
+
* 2. User visits verification URL and enters code
|
|
7
|
+
* 3. Plugin polls token endpoint until user completes auth
|
|
8
|
+
*/
|
|
9
|
+
import { KIMI_CLIENT_ID, KIMI_DEVICE_AUTH_ENDPOINT, KIMI_TOKEN_ENDPOINT, KIMI_DEVICE_CODE_GRANT_TYPE, getKimiOAuthHeaders, } from "../constants";
|
|
10
|
+
// =============================================================================
|
|
11
|
+
// Device Authorization
|
|
12
|
+
// =============================================================================
|
|
13
|
+
/**
|
|
14
|
+
* Request a device code from Kimi's OAuth server.
|
|
15
|
+
* Returns device_code, user_code, and verification_uri for the user.
|
|
16
|
+
*/
|
|
17
|
+
export async function requestDeviceAuthorization() {
|
|
18
|
+
const response = await fetch(KIMI_DEVICE_AUTH_ENDPOINT, {
|
|
19
|
+
method: "POST",
|
|
20
|
+
headers: {
|
|
21
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
22
|
+
...getKimiOAuthHeaders(),
|
|
23
|
+
},
|
|
24
|
+
body: new URLSearchParams({
|
|
25
|
+
client_id: KIMI_CLIENT_ID,
|
|
26
|
+
}),
|
|
27
|
+
});
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
const text = await response.text().catch(() => "");
|
|
30
|
+
throw new Error(`Device authorization failed (${response.status}): ${text}`);
|
|
31
|
+
}
|
|
32
|
+
return (await response.json());
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Poll the token endpoint once for a device code exchange result.
|
|
36
|
+
*/
|
|
37
|
+
async function pollTokenEndpointOnce(deviceCode) {
|
|
38
|
+
const response = await fetch(KIMI_TOKEN_ENDPOINT, {
|
|
39
|
+
method: "POST",
|
|
40
|
+
headers: {
|
|
41
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
42
|
+
...getKimiOAuthHeaders(),
|
|
43
|
+
},
|
|
44
|
+
body: new URLSearchParams({
|
|
45
|
+
grant_type: KIMI_DEVICE_CODE_GRANT_TYPE,
|
|
46
|
+
client_id: KIMI_CLIENT_ID,
|
|
47
|
+
device_code: deviceCode,
|
|
48
|
+
}),
|
|
49
|
+
});
|
|
50
|
+
if (response.ok) {
|
|
51
|
+
const tokens = (await response.json());
|
|
52
|
+
return { status: "success", tokens };
|
|
53
|
+
}
|
|
54
|
+
const body = await response.text().catch(() => "");
|
|
55
|
+
let errorCode = "";
|
|
56
|
+
try {
|
|
57
|
+
const parsed = JSON.parse(body);
|
|
58
|
+
errorCode = parsed.error ?? "";
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// not JSON
|
|
62
|
+
}
|
|
63
|
+
if (errorCode === "authorization_pending") {
|
|
64
|
+
return { status: "pending" };
|
|
65
|
+
}
|
|
66
|
+
if (errorCode === "slow_down") {
|
|
67
|
+
return { status: "slow_down", interval: 10 };
|
|
68
|
+
}
|
|
69
|
+
if (errorCode === "expired_token") {
|
|
70
|
+
return { status: "expired" };
|
|
71
|
+
}
|
|
72
|
+
return { status: "error", message: `Token exchange failed (${response.status}): ${body}` };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Poll the token endpoint until the user completes authorization.
|
|
76
|
+
* Implements backoff on slow_down responses and respects expiration.
|
|
77
|
+
*
|
|
78
|
+
* @param deviceCode The device code from requestDeviceAuthorization
|
|
79
|
+
* @param intervalSeconds Initial polling interval in seconds
|
|
80
|
+
* @param expiresInSeconds Time until the device code expires
|
|
81
|
+
* @param signal Optional AbortSignal to cancel polling
|
|
82
|
+
*/
|
|
83
|
+
export async function pollForToken(deviceCode, intervalSeconds, expiresInSeconds, signal) {
|
|
84
|
+
const deadline = Date.now() + expiresInSeconds * 1000;
|
|
85
|
+
let interval = intervalSeconds;
|
|
86
|
+
while (Date.now() < deadline) {
|
|
87
|
+
if (signal?.aborted) {
|
|
88
|
+
throw new Error("Device authorization cancelled");
|
|
89
|
+
}
|
|
90
|
+
await sleep(interval * 1000);
|
|
91
|
+
if (signal?.aborted) {
|
|
92
|
+
throw new Error("Device authorization cancelled");
|
|
93
|
+
}
|
|
94
|
+
const result = await pollTokenEndpointOnce(deviceCode);
|
|
95
|
+
switch (result.status) {
|
|
96
|
+
case "success":
|
|
97
|
+
return result.tokens;
|
|
98
|
+
case "pending":
|
|
99
|
+
continue;
|
|
100
|
+
case "slow_down":
|
|
101
|
+
interval = Math.max(interval + 5, result.interval);
|
|
102
|
+
continue;
|
|
103
|
+
case "expired":
|
|
104
|
+
throw new Error("Device code expired. Please restart the login flow.");
|
|
105
|
+
case "error":
|
|
106
|
+
throw new Error(result.message);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
throw new Error("Device code expired (timeout). Please restart the login flow.");
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Start the Kimi device authorization flow.
|
|
113
|
+
* Returns the verification URL/code for the user, and a poll function
|
|
114
|
+
* to await completion.
|
|
115
|
+
*/
|
|
116
|
+
export async function authorizeKimi() {
|
|
117
|
+
const deviceAuth = await requestDeviceAuthorization();
|
|
118
|
+
return {
|
|
119
|
+
verificationUri: deviceAuth.verification_uri_complete ?? deviceAuth.verification_uri,
|
|
120
|
+
userCode: deviceAuth.user_code,
|
|
121
|
+
poll: (signal) => pollForToken(deviceAuth.device_code, deviceAuth.interval, deviceAuth.expires_in, signal),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// =============================================================================
|
|
125
|
+
// Helpers
|
|
126
|
+
// =============================================================================
|
|
127
|
+
function sleep(ms) {
|
|
128
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../../src/kimi/oauth.ts"],"names":[],"mappings":"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"}
|