Skip to content

feat: add /usage slash command for DeepSeek API balance#216

Open
al4xdev wants to merge 2 commits into
lessweb:mainfrom
al4xdev:feat/usage-command
Open

feat: add /usage slash command for DeepSeek API balance#216
al4xdev wants to merge 2 commits into
lessweb:mainfrom
al4xdev:feat/usage-command

Conversation

@al4xdev

@al4xdev al4xdev commented Jul 1, 2026

Copy link
Copy Markdown

Summary

Add a /usage slash command that queries the DeepSeek API (GET /user/balance) and displays the user's credit balance and availability status in a dedicated bordered view.

Motivation

DeepSeek API users with prepaid credits have to visit the DeepSeek website to check their balance. This command brings that information directly into the CLI.

Design

The command opens a bordered view (same pattern as /mcp status). Press Esc to return to chat.

Provider detection

  • baseURL.includes("api.deepseek.com") → calls GET https://api.deepseek.com/user/balance
  • Any other provider → shows error with current base URL

Error handling

Scenario Behavior
Non-DeepSeek provider setErrorLine with base URL
No API key configured setErrorLine
HTTP error from API setErrorLine with status
Network error setErrorLine with message

Files Changed

File Description
packages/cli/src/ui/views/UsageView.tsx New -- bordered view component (+59)
packages/cli/src/ui/core/slash-commands.ts +7 -- "usage" kind + built-in entry
packages/cli/src/ui/views/App.tsx +49/-2 -- handleUsage callback + view routing
packages/cli/src/ui/views/PromptInput.tsx +6/-1 -- command union type + handler
packages/cli/src/tests/slash-commands.test.ts +1 -- built-in names assertion

Verification

npm run check     -- typecheck 0 errors, lint 0 errors, format clean
npm test          -- all tests pass
npm run build     -- successful

al4xdev added 2 commits June 30, 2026 21:27
- Add 'usage' to SlashCommandKind type and BUILTIN_SLASH_COMMANDS
- Handle /usage in PromptInput (command type + handleSlashSelection)
- Create handleUsage callback in App: detects DeepSeek via baseURL,
  fetches GET /user/balance, displays result as system message
- Detect slash commands in -p/--prompt startup path
- Show provider mismatch error when baseURL is not api.deepseek.com
…m message

Replace inline system message with a UsageView component (bordered box,
Esc to close), matching the MCP status pattern. This avoids render issues
with addSessionSystemMessage and provides a cleaner UX.
@dengmik-commits

Copy link
Copy Markdown
Contributor
image 如上图。 这个效果,可以通过 statusline 插件得到的。

@dengmik-commits

dengmik-commits commented Jul 1, 2026

Copy link
Copy Markdown
Contributor
      {
        "type": "module",
        "id": "deepseek-balance",
        "path": "C:/Users/xxxxx/.deepcode/plugins/deepseek-balance.mjs",
        "color": "green",
        "timeoutMs": 10000,
        "maxLength": 20
      },
  在 .deepcode/settings.json 的 statusline  加上这段配置。
import * as fs from "fs";
import * as os from "os";
import * as path from "path";

const BALANCE_API = "https://api.deepseek.com/user/balance";
const MIN_INTERVAL_MS = 10000; // 最少间隔 10 秒才真正请求一次

let lastBalance = ""; // 上次成功值,不含格式
let lastText = ""; // 上次显示文本
let lastFetchTime = 0;
let pendingPromise = null; // 正在进行的请求不重复发

function getApiKey() {
  const settingsPath = path.join(os.homedir(), ".deepcode", "settings.json");
  try {
    const raw = fs.readFileSync(settingsPath, "utf8");
    const settings = JSON.parse(raw);
    if (settings.env?.API_KEY) {
      return settings.env.API_KEY;
    }
  } catch {
    // ignore
  }
  return process.env.DEEPCODE_API_KEY || process.env.API_KEY || "";
}

async function doFetch(apiKey) {
  const res = await fetch(BALANCE_API, {
    headers: {
      Authorization: `Bearer ${apiKey}`,
      Accept: "application/json",
    },
    signal: AbortSignal.timeout(8000),
  });
  if (!res.ok) return null;
  const data = await res.json();
  const b = data.balance_infos?.[0];
  if (!b) return null;
  return parseFloat(b.total_balance).toFixed(2);
}

export default async function deepseekBalanceProvider() {
  const apiKey = getApiKey();
  if (!apiKey) return lastText;

  const now = Date.now();

  // 间隔不够且已有上次值 → 直接返回
  if (now - lastFetchTime < MIN_INTERVAL_MS && lastText) {
    return lastText;
  }

  // 有正在进行中的请求 → 复用
  if (pendingPromise) {
    try {
      await pendingPromise;
    } catch {
      // ignore
    }
    return lastText;
  }

  // 真正发请求
  pendingPromise = doFetch(apiKey);
  lastFetchTime = now;

  try {
    const total = await pendingPromise;
    if (total !== null) {
      if (total !== lastBalance) {
        lastBalance = total;
        lastText = `余额: ¥${total}`;
      }
    }
    return lastText;
  } catch {
    return lastText;
  } finally {
    pendingPromise = null;
  }
}

上面是 /.deepcode/plugins/deepseek-balance.mjs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants