mirror of
https://github.com/lemon07r/opencode-kimi-full.git
synced 2026-06-02 06:14:16 +02:00
Add constants and X-Msh-* header builder with persistent ~/.kimi/device_id
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
// Values mirror kimi-cli v1.35.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 what routes the issued JWT to K2.6.
|
||||
|
||||
export const KIMI_CLI_VERSION = "1.35.0"
|
||||
export const USER_AGENT = `KimiCodeCLI/${KIMI_CLI_VERSION}`
|
||||
|
||||
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"
|
||||
|
||||
export const API_BASE_URL = "https://api.kimi.com/coding/v1"
|
||||
export const MODEL_ID = "kimi-for-coding"
|
||||
|
||||
// Refresh a bit before the server-reported expiry so we never race it.
|
||||
export const REFRESH_SAFETY_WINDOW_MS = 60_000
|
||||
@@ -0,0 +1,47 @@
|
||||
import os from "node:os"
|
||||
import fs from "node:fs"
|
||||
import path from "node:path"
|
||||
import crypto from "node:crypto"
|
||||
import { KIMI_CLI_VERSION, USER_AGENT } from "./constants.ts"
|
||||
|
||||
// kimi-cli persists its device id at `~/.kimi/device_id` as a plain UUIDv4
|
||||
// hex string (no dashes). We intentionally share the same path so users who
|
||||
// also run the real kimi CLI keep a single stable fingerprint. See
|
||||
// research/kimi-cli/src/kimi_cli/auth/oauth.py (get_device_id).
|
||||
const DEVICE_ID_DIR = path.join(os.homedir(), ".kimi")
|
||||
const DEVICE_ID_PATH = path.join(DEVICE_ID_DIR, "device_id")
|
||||
|
||||
function ensureDir(dir: string) {
|
||||
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true, mode: 0o700 })
|
||||
}
|
||||
|
||||
export function getDeviceId(): string {
|
||||
ensureDir(DEVICE_ID_DIR)
|
||||
if (fs.existsSync(DEVICE_ID_PATH)) {
|
||||
const existing = fs.readFileSync(DEVICE_ID_PATH, "utf8").trim()
|
||||
if (existing) return existing
|
||||
}
|
||||
const id = crypto.randomUUID().replace(/-/g, "")
|
||||
fs.writeFileSync(DEVICE_ID_PATH, id, { mode: 0o600 })
|
||||
return id
|
||||
}
|
||||
|
||||
// Non-ASCII characters in HTTP headers will be rejected by Node's undici
|
||||
// fetch (`TypeError: Invalid character in header content`). kimi-cli does the
|
||||
// same sanitization in oauth._ascii_header_value.
|
||||
function ascii(value: string): string {
|
||||
return value.replace(/[^\x20-\x7e]/g, "?")
|
||||
}
|
||||
|
||||
/** Builds the 7 X-Msh-* / UA headers kimi-cli sends on every request. */
|
||||
export function kimiHeaders(): Record<string, string> {
|
||||
return {
|
||||
"User-Agent": USER_AGENT,
|
||||
"X-Msh-Platform": "kimi_cli",
|
||||
"X-Msh-Version": KIMI_CLI_VERSION,
|
||||
"X-Msh-Device-Name": ascii(os.hostname() || "unknown"),
|
||||
"X-Msh-Device-Model": ascii(os.machine?.() || os.arch()),
|
||||
"X-Msh-Device-Id": getDeviceId(),
|
||||
"X-Msh-Os-Version": ascii(`${os.type()} ${os.release()}`),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user