diff --git a/dist/index.js b/dist/index.js index c26440a..ce0d613 100644 --- a/dist/index.js +++ b/dist/index.js @@ -38,6 +38,11 @@ const CONFIG = { apiKey: process.env.MINIMAX_API_KEY || 'sk-cp-XC8cbgbVBuv1g8mMcao0ABeZu_rGEN_S22EhBUqo4lJbY_UJVqUVO5XF8hVobp8gE_39JbgQggr00TQwNdV9vP458Y_MBC_8GstvzmwhuukEGY4a2I5_L6A', baseUrl: 'api.minimax.io', endpoint: '/v1/api/openplatform/coding_plan/remains' + }, + kimi: { + apiKey: process.env.KIMI_API_KEY || 'sk-kimi-dr5bfb3Gz8yOQOJVbLd2iY3kdDPf5MPBp1Ay467FlpAhvKMcTVOyiMH8zuQz1gb2', + baseUrl: 'api.kimi.com', + endpoint: '/coding/v1/usages' } }; @@ -141,6 +146,74 @@ async function getMinimaxUsage() { } } +// Fetch Kimi usage +async function getKimiUsage() { + if (!CONFIG.kimi.apiKey) { + return { error: 'No Kimi API key configured' }; + } + + try { + const response = await makeRequest({ + hostname: CONFIG.kimi.baseUrl, + path: CONFIG.kimi.endpoint, + method: 'GET', + headers: { + 'Authorization': `Bearer ${CONFIG.kimi.apiKey}`, + 'Content-Type': 'application/json' + } + }); + + const usage = response?.usage; + const limits = response?.limits || []; + + if (!usage) { + return { pct: 0, remainingMinutes: 0, error: 'No data' }; + } + + const pct = parseInt(usage.used) / parseInt(usage.limit) * 100; + let remainingMinutes = 0; + let weeklyReset = null; + + if (usage.resetTime) { + const resetDate = new Date(usage.resetTime); + const now = new Date(); + remainingMinutes = (resetDate - now) / 1000 / 60; + weeklyReset = resetDate; + } + + const limitInfos = []; + for (const l of limits) { + if (l.detail?.resetTime) { + const resetDate = new Date(l.detail.resetTime); + const now = new Date(); + const limitMins = (resetDate - now) / 1000 / 60; + + if (limitMins > 0) { + const limitUsed = parseInt(l.detail.limit) - parseInt(l.detail.remaining); + const limitPct = limitUsed / parseInt(l.detail.limit) * 100; + const windowDur = l.window?.duration || 0; + const windowUnit = l.window?.timeUnit || ''; + + let label = '5h'; + if (windowUnit === 'TIME_UNIT_MINUTE' && windowDur >= 60) { + label = `${windowDur / 60}h`; + } + + limitInfos.push({ + pct: limitPct, + remainingMinutes: limitMins, + label: label + }); + } + } + } + + return { pct, remainingMinutes, weeklyReset, limitInfos, error: null }; + } catch (e) { + return { pct: 0, remainingMinutes: 0, error: e.message }; + } +} + // Get color based on percentage function getColor(pct) { if (pct > 90) return colors.red; @@ -174,35 +247,62 @@ function formatMinimaxStatus(minimax) { return `${colors.purple}MiniMax${colors.reset} ${getColor(minimax.pct)}${minimax.pct.toFixed(0)}%${colors.reset}${timeStr ? ` ${timeStr}` : ''}`; } +// Format Kimi status +function formatKimiStatus(kimi) { + if (kimi.error) { + return `${colors.orange}Kimi${colors.reset} ${colors.red}offline${colors.reset}`; + } + + let status = `${colors.orange}Kimi${colors.reset} ${getColor(kimi.pct)}${kimi.pct.toFixed(0)}%${colors.reset}`; + + if (kimi.remainingMinutes > 0) { + status += ` ${formatTime(kimi.remainingMinutes)}`; + } + + if (kimi.limitInfos && kimi.limitInfos.length > 0) { + for (const lim of kimi.limitInfos) { + status += ` ${colors.orange}${lim.label}${colors.reset}${getColor(lim.pct)}${lim.pct.toFixed(0)}%${colors.reset}`; + } + } + + return status; +} + // Main function async function main() { const args = process.argv.slice(2); const showJson = args.includes('--json'); const showOnlyGlm = args.includes('--glm'); const showOnlyMinimax = args.includes('--minimax'); + const showOnlyKimi = args.includes('--kimi'); try { - const [glm, minimax] = await Promise.all([ - showOnlyMinimax ? Promise.resolve({ error: 'disabled' }) : getGlmUsage(), - showOnlyGlm ? Promise.resolve({ error: 'disabled' }) : getMinimaxUsage() + const [glm, minimax, kimi] = await Promise.all([ + getGlmUsage(), + getMinimaxUsage(), + getKimiUsage() ]); if (showJson) { - console.log(JSON.stringify({ glm, minimax }, null, 2)); + console.log(JSON.stringify({ glm, minimax, kimi }, null, 2)); return; } - // Statusline output + // Statusline output - always show all 3 let parts = []; - if (!showOnlyMinimax && !glm.error) { + if (!showOnlyMinimax && !showOnlyKimi) { parts.push(formatGlmStatus(glm)); } - if (!showOnlyGlm && !minimax.error) { + if (!showOnlyGlm && !showOnlyKimi) { parts.push(formatMinimaxStatus(minimax)); } + if (!showOnlyGlm && !showOnlyMinimax) { + parts.push(formatKimiStatus(kimi)); + } + if (parts.length === 0) { console.log(`${colors.red}No API configured${colors.reset}`); return;