Sync kimi-cli 1.41.0 parity: bump version, drop OAuth scope

This commit is contained in:
lemon07r
2026-05-09 06:31:58 -04:00
parent 86e697a53a
commit 76f58b429e
6 changed files with 16 additions and 15 deletions
+6 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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,
})
}
+2 -3
View File
@@ -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
View File
@@ -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,
})
})