火曜日, 8月 12, 2025
火曜日, 8月 12, 2025
- Advertisment -
ホームニューステックニュースClaude Code のコンテキスト残量を常に表示する

Claude Code のコンテキスト残量を常に表示する


Claude Code の v1.0.71 で、TUI の最下部に表示する status line をカスタマイズできるようになりました。
コンテキストサイズや auto-compact までの残量を常に可視化しておくために便利です。

result

モチベーション

Claude のコンテキスト幅 (モデルに一度に入力できる上限トークン数) は 200K トークンです。
Claude Code はこのコンテキスト幅に到達する前に、大体 80% ぐらいのタイミングで自動的に /compact を実行します。

/compact はコンテキストを圧縮するために、過去の会話履歴の情報を大幅に落とした要約を作ります。
その結果、必要なコンテキストが足りずに Claude Code が迷走することが非常によくあります。

そのため、auto-compact まで後どれくらいトークンを使えるかを常に把握しておきたいわけですが、 Claude Code は auto-compact の直前まで情報を表示しません。

この不便さを解消するためにちょうど良い機能がリリースされたので、早速利用しましょう。

設定方法

まず、下記の設定を .claude/settings.json に追加します。

{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.js"
  }
}

statusline.js の中身は以下の通りです。



const fs = require('fs');
const path = require('path');
const readline = require('readline');


const COMPACTION_THRESHOLD = 200000 * 0.8


let input = '';
process.stdin.on('data', chunk => input += chunk);
process.stdin.on('end', async () => {
  try {
    const data = JSON.parse(input);

    
    const model = data.model?.display_name || 'Unknown';
    const currentDir = path.basename(data.workspace?.current_dir || data.cwd || '.');
    const sessionId = data.session_id;

    
    let totalTokens = 0;

    if (sessionId) {
      
      const projectsDir = path.join(process.env.HOME, '.claude', 'projects');

      if (fs.existsSync(projectsDir)) {
        
        const projectDirs = fs.readdirSync(projectsDir)
          .map(dir => path.join(projectsDir, dir))
          .filter(dir => fs.statSync(dir).isDirectory());

        
        for (const projectDir of projectDirs) {
          const transcriptFile = path.join(projectDir, `${sessionId}.jsonl`);

          if (fs.existsSync(transcriptFile)) {
            totalTokens = await calculateTokensFromTranscript(transcriptFile);
            break;
          }
        }
      }
    }

    
    const percentage = Math.min(100, Math.round((totalTokens / COMPACTION_THRESHOLD) * 100));

    
    const tokenDisplay = formatTokenCount(totalTokens);

    
    let percentageColor = '\x1b[32m'; 
    if (percentage >= 70) percentageColor = '\x1b[33m'; 
    if (percentage >= 90) percentageColor = '\x1b[31m'; 

    
    const statusLine = `[${model}] 📁 ${currentDir} | 🪙 ${tokenDisplay} | ${percentageColor}${percentage}%\x1b[0m`;

    console.log(statusLine);
  } catch (error) {
    
    console.log('[Error] 📁 . | 🪙 0 | 0%');
  }
});

async function calculateTokensFromTranscript(filePath) {
  return new Promise((resolve, reject) => {
    let lastUsage = null;

    const fileStream = fs.createReadStream(filePath);
    const rl = readline.createInterface({
      input: fileStream,
      crlfDelay: Infinity
    });

    rl.on('line', (line) => {
      try {
        const entry = JSON.parse(line);

        
        if (entry.type === 'assistant' && entry.message?.usage) {
          lastUsage = entry.message.usage;
        }
      } catch (e) {
        
      }
    });

    rl.on('close', () => {
      if (lastUsage) {
        
        const totalTokens = (lastUsage.input_tokens || 0) +
          (lastUsage.output_tokens || 0) +
          (lastUsage.cache_creation_input_tokens || 0) +
          (lastUsage.cache_read_input_tokens || 0);
        resolve(totalTokens);
      } else {
        resolve(0);
      }
    });

    rl.on('error', (err) => {
      reject(err);
    });
  });
}

function formatTokenCount(tokens) {
  if (tokens >= 1000000) {
    return `${(tokens / 1000000).toFixed(1)}M`;
  } else if (tokens >= 1000) {
    return `${(tokens / 1000).toFixed(1)}K`;
  }
  return tokens.toString();
}

仕組み

上の statusline.js はトークン数を分析するために transcript と呼ばれるファイルをパースしています。transcript はセッションごとに自動生成されるファイルで、完全な履歴が保存されています。

現在のセッションに対応する transcript のパスは、標準入力経由で status line のコマンドに渡されます。

https://docs.anthropic.com/en/docs/claude-code/statusline#json-input-structure

transcript の各行は下記のような形式になっており、今回利用するのは message.usage だけです。

{
  "parentUuid": "b48011c8-b40c-4fb7-afa1-7b179409613b",
  "isSidechain": false,
  "userType": "external",
  "cwd": "/redacted/.local/share/chezmoi",
  "sessionId": "0aa7a121-20aa-4e58-8c46-9709131bdd7f",
  "version": "1.0.60",
  "gitBranch": "main",
  "message": {
    "id": "msg_01Kt2aXgS4g2xwkRjY6bsjaB",
    "type": "message",
    "role": "assistant",
    "model": "claude-opus-4-20250514",
    "content": [
      {
        "type": "text",
        "text": "You're absolutely right - I should have modified the chezmoi source file instead of the deployed file directly. Let me find and update the correct file in the chezmoi repository:"
      }
    ],
    "stop_reason": null,
    "stop_sequence": null,
    "usage": {
      "input_tokens": 10,
      "cache_creation_input_tokens": 28596,
      "cache_read_input_tokens": 0,
      "output_tokens": 5,
      "service_tier": "standard"
    }
  },
  "requestId": "req_011CRTQ2kR2epr87wVM5VHzC",
  "type": "assistant",
  "uuid": "85289783-055a-4fbc-9a32-97c222085ca3",
  "timestamp": "2025-07-25T08:10:33.582Z"
}



Source link

Views: 0

RELATED ARTICLES

返事を書く

あなたのコメントを入力してください。
ここにあなたの名前を入力してください

- Advertisment -