🦀

Claude Code の Status Line に PR リンクを置く方法

に公開

皆様 Claude Code で日々 PR 作成に取り組まれていると思います。Claude Code を複数ウィンドウで並行運用していると、「このセッションはどのブランチか」「PR は作成済みか」が一瞬で分からなくなり、レビュー漏れや作業ミスの原因になります。

そこで本記事では、Status Line に ブランチ名 + Dirty + PR リンク を表示し、PR 番号をクリックすると GitHub の該当 PR を開けるようにする方法を紹介します。

~/src/my-project | main* [PR#42] | Opus 4.5 | 03:45 | ↑12.3k ↓5.6k (17.9k)
                        ^^^^^^^ クリックでGitHub PRページへ

npm パッケージにしちゃうと便利

自分は複数の開発マシンで同じ statusline を使いたいので、Script を GitHub リポジトリで管理し、npm パッケージとして配布して使っています。

https://github.com/him0/claude-code-statusline

これにより ~/.claude/settings.json に npx や bunx で、同じ statusline を複数環境で使うことができます。

"statusLine": {
  "type": "command",
  "command": "npx him0/claude-code-statusline"
}

または

"statusLine": {
  "type": "command",
  "command": "bunx him0/claude-code-statusline"
}

出力はこんな感じになります。これで十分って人は、同じように設定していただければ同じ出力が得られるかと思います。また、カスタムしたい人は、fork したり、手元に js のファイルを編集しちゃうといいかなと思います。

ここから続きは、もっとカスタムしたい人、仕組みを知りたい人向けです

1. クリック可能なリンクを Terminal で作成 (OSC8)

iTerm2, Ghostty などの最近の Terminal Emulator は、OSC8 という仕様があり Terminal でハイパーリンクを表現することができます。Claude Code のネイティブ機能でも時々利用されていますが、これを覚えておくと、自分で追加機能を作るときにも強力な選択肢になります。

function createClickableLink(text, url) {
  // OSC 8 hyperlink escape sequence (using BEL terminator for better compatibility)
  return `\x1b]8;;${url}\x07${text}\x1b]8;;\x07`;
}

2. gh CLI で PR 情報を取得

gh コマンドは GitHub の多彩な情報を効率よく取得できます。gh pr view で現在のブランチに紐づくPRを検出し、stateOPEN を取得し、利用しています。

function getPrInfo(repoPath, branch) {
  try {
    const result = execSync("gh pr view --json url,number,state", {
      cwd: repoPath,
      encoding: "utf8",
      stdio: "pipe",
      timeout: 5000,
    });
    const prData = JSON.parse(result);
    // Only show PR link for open PRs
    if (prData.state !== "OPEN") {
      return null;
    }
    return { url: prData.url, number: prData.number };
  } catch {
    // No PR or gh CLI error
    return null;
  }
}

3. status line への組み込み

ブランチ名は git rev-parse --abbrev-ref HEAD で取得し、git status --porcelain で差分を検知、差分があれば * を付与します。さらに PR が存在する場合は [PR#42] の形式で表示し、その部分を OSC8 ハイパーリンクを用いてターミナル上でクリック可能にします。

// Git branch + PR link
let gitInfo = "";
try {
  let branch = execSync("git rev-parse --abbrev-ref HEAD", {
    encoding: "utf8",
    stdio: "pipe",
    cwd: dirFull,
  }).trim();

  // Check for dirty (including untracked)
  const status = execSync(
    "git --no-optional-locks status --porcelain -unormal --ignore-submodules=dirty",
    { encoding: "utf8", stdio: "pipe", cwd: dirFull },
  );
  if (status.trim()) {
    branch += "*";
  }
  gitInfo = branch;

  // Add PR number if available
  const prInfo = getPrInfo(dirFull, branch.replace(/\*$/, ""));
  if (prInfo) {
    const prLink = createClickableLink(`PR#${prInfo.number}`, prInfo.url);
    gitInfo = `${branch} [${prLink}]`;
  }
} catch {
  // Not a git repo
}

4. キャッシュ機構

gh pr view は API 呼び出しのため毎回実行すると遅くなるため、リポジトリ×ブランチ単位で結果をキャッシュし、有効期限を 5 分に設定しています。ブランチ切り替え時はキャッシュを無効化して新規 PR を検出し、PR が存在しない場合はキャッシュせず、常に即時検出を優先します。

const CACHE_FILE = path.join(process.env.HOME, ".claude", "cache", "statusline-pr-cache.json");
const DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes

function getFromCache(repoPath, branch) {
  const cache = loadCache();
  const entry = cache[repoPath];
  if (!entry || entry.branch !== branch) {
    return null;
  }
  if (Date.now() - entry.fetchedAt > DEFAULT_CACHE_TTL_MS) {
    return null;
  }
  return entry;
}

function saveToCache(repoPath, branch, prUrl, prNumber) {
  const cache = loadCache();
  cache[repoPath] = { branch, prUrl, prNumber, fetchedAt: Date.now() };
  saveCache(cache);
}

おわりに

本記事で紹介した statusline は、以下のリポジトリで管理しています。
改善案や不具合報告、機能追加の提案などがあれば、Issue や PR をいただけると嬉しいです。

https://github.com/him0/claude-code-statusline

Discussion