mirror of
https://github.com/lemon07r/opencode-kimi-full.git
synced 2026-06-02 06:14:16 +02:00
Sync kimi-cli 1.41.0 parity: bump version, drop OAuth scope
This commit is contained in:
@@ -26,14 +26,18 @@ Every design decision here follows from that: we do device-flow OAuth to mirror
|
||||
|
||||
### Architecture
|
||||
|
||||
Three files, 1 job each. Do not add a fourth unless the existing three genuinely can't hold a new concern.
|
||||
Each source file has one job. Do not add new files unless the existing ones genuinely can't hold a new concern.
|
||||
|
||||
| File | Responsibility |
|
||||
|--------------------|--------------------------------------------------------------------------------|
|
||||
| `src/constants.ts` | Pinned strings that must mirror upstream kimi-cli (version, endpoints, client id, scope). |
|
||||
| `src/constants.ts` | Pinned strings that must mirror upstream kimi-cli (version, endpoints, client id). |
|
||||
| `src/headers.ts` | The seven `X-Msh-*` / UA headers + the persistent `~/.kimi/device_id` file. |
|
||||
| `src/oauth.ts` | Device-code start, device-code poll, refresh-token exchange, and `GET /coding/v1/models` discovery. |
|
||||
| `src/auth-store.ts`| Read/write opencode's `auth.json` entries for this provider. |
|
||||
| `src/auth-refresh.ts`| Lock-based token refresh with cross-instance coordination, `ensureFreshStoredAuth` for standalone callers. |
|
||||
| `src/index.ts` | Plugin entry (v1 `PluginModule` format). Wires `auth` (login + loader) plus the Kimi chat hooks/body rewrite. |
|
||||
| `src/usage.ts` | Fetch and parse Kimi subscription usage (`/coding/v1/usages`). |
|
||||
| `src/tui.tsx` | TUI slash command `/kimi:usage` — renders usage in an opencode dialog. |
|
||||
|
||||
Data flow on a chat request:
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "opencode-kimi-full",
|
||||
"version": "1.2.9",
|
||||
"version": "1.3.0",
|
||||
"description": "OpenCode plugin that brings the official Kimi OAuth device flow and Kimi-specific coding request fields to opencode, matching upstream kimi-cli.",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
||||
+3
-4
@@ -1,13 +1,13 @@
|
||||
// Values mirror kimi-cli v1.37.0 1:1. When upstream bumps, update here and
|
||||
// Values mirror kimi-cli v1.41.0 1:1. When upstream bumps, update here and
|
||||
// nothing else in the codebase should hard-code these strings.
|
||||
//
|
||||
// Source of truth: research/kimi-cli/src/kimi_cli/constant.py,
|
||||
// research/kimi-cli/src/kimi_cli/auth/oauth.py
|
||||
//
|
||||
// NOTE: client_id is a public constant shipped inside the official CLI, not a
|
||||
// secret. scope `kimi-code` is the upstream coding-agent OAuth scope.
|
||||
// secret.
|
||||
|
||||
export const KIMI_CLI_VERSION = "1.37.0"
|
||||
export const KIMI_CLI_VERSION = "1.41.0"
|
||||
// Upstream: research/kimi-cli/src/kimi_cli/constant.py get_user_agent() →
|
||||
// f"KimiCLI/{get_version()}". This must match verbatim — Moonshot's
|
||||
// `kimi-for-coding` backend 403s on any other UA prefix
|
||||
@@ -18,7 +18,6 @@ export const OAUTH_HOST = "https://auth.kimi.com"
|
||||
export const OAUTH_DEVICE_AUTH_URL = `${OAUTH_HOST}/api/oauth/device_authorization`
|
||||
export const OAUTH_TOKEN_URL = `${OAUTH_HOST}/api/oauth/token`
|
||||
export const OAUTH_CLIENT_ID = "17e5f671-d194-4dfb-9706-5516cb48c098"
|
||||
export const OAUTH_SCOPE = "kimi-code"
|
||||
export const OAUTH_DEVICE_GRANT = "urn:ietf:params:oauth:grant-type:device_code"
|
||||
export const OAUTH_REFRESH_GRANT = "refresh_token"
|
||||
|
||||
|
||||
+3
-2
@@ -4,7 +4,6 @@ import {
|
||||
OAUTH_DEVICE_AUTH_URL,
|
||||
OAUTH_DEVICE_GRANT,
|
||||
OAUTH_REFRESH_GRANT,
|
||||
OAUTH_SCOPE,
|
||||
OAUTH_TOKEN_URL,
|
||||
} from "./constants.ts"
|
||||
import { kimiHeaders } from "./headers.ts"
|
||||
@@ -65,9 +64,11 @@ async function postForm<T>(url: string, params: Record<string, string>): Promise
|
||||
}
|
||||
|
||||
export async function startDeviceAuth(): Promise<DeviceAuth> {
|
||||
// kimi-cli v1.41.0 dropped the `scope` parameter from the device
|
||||
// authorization request (research/kimi-cli/src/kimi_cli/auth/oauth.py,
|
||||
// request_device_authorization). Only `client_id` is sent now.
|
||||
return postForm<DeviceAuth>(OAUTH_DEVICE_AUTH_URL, {
|
||||
client_id: OAUTH_CLIENT_ID,
|
||||
scope: OAUTH_SCOPE,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -18,13 +18,12 @@ test("USER_AGENT embeds KIMI_CLI_VERSION", () => {
|
||||
|
||||
test("OAuth constants match upstream kimi-cli exactly", () => {
|
||||
// Pinned values from research/kimi-cli/src/kimi_cli/auth/oauth.py. If these
|
||||
// drift from upstream, tokens are issued against the wrong scope/client and
|
||||
// the plugin no longer mirrors official kimi-cli auth.
|
||||
// drift from upstream, tokens are issued against the wrong client and the
|
||||
// plugin no longer mirrors official kimi-cli auth.
|
||||
expect(C.OAUTH_HOST).toBe("https://auth.kimi.com")
|
||||
expect(C.OAUTH_DEVICE_AUTH_URL).toBe("https://auth.kimi.com/api/oauth/device_authorization")
|
||||
expect(C.OAUTH_TOKEN_URL).toBe("https://auth.kimi.com/api/oauth/token")
|
||||
expect(C.OAUTH_CLIENT_ID).toBe("17e5f671-d194-4dfb-9706-5516cb48c098")
|
||||
expect(C.OAUTH_SCOPE).toBe("kimi-code")
|
||||
expect(C.OAUTH_DEVICE_GRANT).toBe("urn:ietf:params:oauth:grant-type:device_code")
|
||||
expect(C.OAUTH_REFRESH_GRANT).toBe("refresh_token")
|
||||
})
|
||||
|
||||
+1
-3
@@ -4,7 +4,6 @@ import {
|
||||
OAUTH_DEVICE_AUTH_URL,
|
||||
OAUTH_DEVICE_GRANT,
|
||||
OAUTH_REFRESH_GRANT,
|
||||
OAUTH_SCOPE,
|
||||
OAUTH_TOKEN_URL,
|
||||
} from "../src/constants.ts"
|
||||
import { pollDeviceToken, refreshToken, startDeviceAuth } from "../src/oauth.ts"
|
||||
@@ -20,7 +19,7 @@ afterEach(() => {
|
||||
mock = undefined
|
||||
})
|
||||
|
||||
test("startDeviceAuth posts client_id+scope as form-encoded to the device endpoint", async () => {
|
||||
test("startDeviceAuth posts client_id as form-encoded to the device endpoint", async () => {
|
||||
mock = installFetchMock(() => ({
|
||||
body: {
|
||||
device_code: "dc",
|
||||
@@ -44,7 +43,6 @@ test("startDeviceAuth posts client_id+scope as form-encoded to the device endpoi
|
||||
expect(call.headers["x-msh-device-id"]).toMatch(/^[0-9a-f]{32}$/)
|
||||
expect(parseForm(call.body)).toEqual({
|
||||
client_id: OAUTH_CLIENT_ID,
|
||||
scope: OAUTH_SCOPE,
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user