mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-05 14:52:09 +03:00
feat(kimi-coding): add Kimi Coding plan quota display (#279)
- Add getKimiUsage() with X-Msh-* device headers for Kimi API - Parse weekly quota + rate-limit breakdown from /v1/usages endpoint - Fix X-Msh-* headers in refreshKimiCodingToken (was missing) - Wire kimi-coding into getUsageForProvider switch - Add quota capability flag to providers.ts - Remove console.warn/error (production-safe silent returns) Co-authored-by: nyatoru <nyarutoru0002@outlook.co.th>
This commit is contained in:
@@ -20,6 +20,7 @@ const PROVIDER_CONFIG = {
|
||||
kiro: { label: "Kiro AI", color: "#FF6B35" },
|
||||
codex: { label: "OpenAI Codex", color: "#10A37F" },
|
||||
claude: { label: "Claude Code", color: "#D97757" },
|
||||
"kimi-coding": { label: "Kimi Coding", color: "#1E3A8A" },
|
||||
};
|
||||
|
||||
const TIER_FILTERS = [
|
||||
@@ -236,7 +237,7 @@ export default function ProviderLimits() {
|
||||
);
|
||||
|
||||
const sortedConnections = useMemo(() => {
|
||||
const priority = { antigravity: 1, github: 2, codex: 3, claude: 4, kiro: 5 };
|
||||
const priority = { antigravity: 1, github: 2, codex: 3, claude: 4, kiro: 5, "kimi-coding": 6 };
|
||||
return [...filteredConnections].sort(
|
||||
(a, b) => (priority[a.provider] || 9) - (priority[b.provider] || 9)
|
||||
);
|
||||
|
||||
@@ -1,4 +1,26 @@
|
||||
import { KIMI_CODING_CONFIG } from "../constants/oauth";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { hostname } from "node:os";
|
||||
|
||||
// Generate device ID (persistent per installation)
|
||||
const DEVICE_ID = randomUUID();
|
||||
const PLATFORM = "omniroute";
|
||||
const VERSION = "2.1.2";
|
||||
const DEVICE_NAME = hostname();
|
||||
const DEVICE_MODEL = `${process.platform} ${process.arch}`;
|
||||
|
||||
// Custom headers required by Kimi OAuth
|
||||
function getKimiOAuthHeaders() {
|
||||
return {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
Accept: "application/json",
|
||||
"X-Msh-Platform": PLATFORM,
|
||||
"X-Msh-Version": VERSION,
|
||||
"X-Msh-Device-Name": DEVICE_NAME,
|
||||
"X-Msh-Device-Model": DEVICE_MODEL,
|
||||
"X-Msh-Device-Id": DEVICE_ID,
|
||||
};
|
||||
}
|
||||
|
||||
export const kimiCoding = {
|
||||
config: KIMI_CODING_CONFIG,
|
||||
@@ -6,10 +28,7 @@ export const kimiCoding = {
|
||||
requestDeviceCode: async (config) => {
|
||||
const response = await fetch(config.deviceCodeUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
Accept: "application/json",
|
||||
},
|
||||
headers: getKimiOAuthHeaders(),
|
||||
body: new URLSearchParams({
|
||||
client_id: config.clientId,
|
||||
}),
|
||||
@@ -24,10 +43,10 @@ export const kimiCoding = {
|
||||
return {
|
||||
device_code: data.device_code,
|
||||
user_code: data.user_code,
|
||||
verification_uri: data.verification_uri || `https://www.kimi.com/code/authorize_device`,
|
||||
verification_uri: data.verification_uri || `https://auth.kimi.com/activate`,
|
||||
verification_uri_complete:
|
||||
data.verification_uri_complete ||
|
||||
`https://www.kimi.com/code/authorize_device?user_code=${data.user_code}`,
|
||||
`https://auth.kimi.com/activate?user_code=${data.user_code}`,
|
||||
expires_in: data.expires_in,
|
||||
interval: data.interval || 5,
|
||||
};
|
||||
@@ -35,14 +54,11 @@ export const kimiCoding = {
|
||||
pollToken: async (config, deviceCode) => {
|
||||
const response = await fetch(config.tokenUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
Accept: "application/json",
|
||||
},
|
||||
headers: getKimiOAuthHeaders(),
|
||||
body: new URLSearchParams({
|
||||
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
||||
client_id: config.clientId,
|
||||
device_code: deviceCode,
|
||||
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -63,5 +79,7 @@ export const kimiCoding = {
|
||||
accessToken: tokens.access_token,
|
||||
refreshToken: tokens.refresh_token,
|
||||
expiresIn: tokens.expires_in,
|
||||
tokenType: tokens.token_type,
|
||||
scope: tokens.scope,
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -400,7 +400,14 @@ export const ID_TO_ALIAS = Object.values(AI_PROVIDERS).reduce((acc, p) => {
|
||||
}, {});
|
||||
|
||||
// Providers that support usage/quota API
|
||||
export const USAGE_SUPPORTED_PROVIDERS = ["antigravity", "kiro", "github", "codex", "claude"];
|
||||
export const USAGE_SUPPORTED_PROVIDERS = [
|
||||
"antigravity",
|
||||
"kiro",
|
||||
"github",
|
||||
"codex",
|
||||
"claude",
|
||||
"kimi-coding",
|
||||
];
|
||||
|
||||
// ── Zod validation at module load (Phase 7.2) ──
|
||||
import { validateProviders } from "../validation/providerSchema";
|
||||
|
||||
Reference in New Issue
Block a user