🦈

claude --resumeをもっと使いやすくするCLIツール、「ccresume」を作った

に公開2

はじめに

Claude Codeで会話を再開するときに使えるコマンドで、claude --resumeというのがあります。

このコマンド、実際に使ってみるとわかるんですが、微妙に使いにくいなぁと不満でした。

これが実際の画面なんですが、どれがなんのsessionか、全然わからないんですよね。

で、そんな不満がある最中で、先日開催された #claude_code_deep_dive のイベントで、@hiragramさんが紹介されていた、"ccraw"という会話ログビューワを見て、なるほどデータ的に会話ログが見えるのかと。

https://github.com/hiragram/ccraw

それなら、ログの簡易確認ができるresumeが作れるのではないかと思い、作成に至りました。


なお、作成にあたっては、先述のhiragramさんに加えて、@ryoppippiさんのccusageと、

https://zenn.dev/ryoppippi/articles/6c9a8fe6629cd6

@mizchiさんのReact Ink紹介記事に、多分に影響を受けています。

https://zenn.dev/mizchi/articles/react-ink-renderer-for-ai-age

作ったもの

ccresume - Claude Codeの会話を簡単に再開できるCUI(TUI)ツールです。

https://github.com/sasazame/ccresume

主な機能

  • 過去の全プロジェクトのClaude Code会話履歴を一覧表示
  • 会話の詳細(チャット履歴)を簡易プレビュー
  • Enterキーで選択した会話を即座に再開
  • セッションIDをクリップボードにコピー
  • 起動時に与えられたオプションはすべてclaudeコマンドの実行時引数に引き渡し。

インストール・使い方

# npxで実行(インストール不要)
npx @sasazame/ccresume@latest

# またはグローバルインストール
npm install -g @sasazame/ccresume

本当はnpx ccresume@latestのみにしたかったんですが、似た名前のプロジェクトがあるとかで弾かれてしまい(claude code関係なさそうなもの)、なくなくユーザーネーム入れています……。

開発の経緯

1. バイブス高まってます

TS・React初学者のため、コーディングはほぼほぼclaude codeにお願いしています。

有効性とか実現性のところはclaudeのPlanモードで壁打ちして確認。使用技術の部分は先述の記事を拝見して、React Inkを使ってみようと決めていたので、それと付随するライブラリだけ提示して、あとはほぼお任せでした。

2. データ構造

hiragramさんの発表で得た知識ですが、claudeは仕組み的に以下のようなディレクトリ構造で会話ログを保持しています:

~/.claude/projects/
├── -home-user-project1/
│   ├── session-id-1.jsonl
│   └── session-id-2.jsonl
└── -home-user-project2/
    └── session-id-3.jsonl

各JSONLファイルには、以下のような形式でメッセージが記録されています:

{"type":"user","message":{"role":"user","content":"Hello"},"timestamp":"2024-01-01T00:00:00.000Z","sessionId":"xxx","cwd":"/home/user/project1"}
{"type":"assistant","message":{"role":"assistant","content":"Hi!"},"timestamp":"2024-01-01T00:00:01.000Z","sessionId":"xxx"}

簡単に言えば、これを1ファイルずつparseして、最新データから順にソートして出力。会話ログの中身も1行ずつ解釈して出力しているというだけになります。

3. CLIオプションの引き渡し

claudeコマンドのオプションをそのまま使えるように、一部の例外(--help, --version, .)を除き引数をすべて透過的に引き渡す仕組みを実装しています。

最初は、有効なコマンドだけにバリデーションするとか、起動後にコマンド書いて実行できるようにしようかとか色々考えたんですが、結局claude側が受け付けてくれるかとか、そのあたり諸々不安だったので、もう全部投げつけてしまえばいいじゃないかと。

# これらのオプションがそのままclaudeに渡される
ccresume --dangerously-skip-permissions
ccresume --model claude-3-opus

--resumeなど一部のオプションはおそらくおかしい動作になるとおもうので、使わないようにという注意書きだけヘルプに入れていたりします。

4. 起動ディレクトリは気にせず実行可能

本家のclaude --resumeは、今自分がいるパスで起動したセッションの分しか表示されません。

あれやこれやと書き散らしていると、前回どこで立ち上げたんだっけ、となりがちな私。LLMにコンテキスト広く持たせたくて、バックエンドとフロントエンドのソースを一つのディレクトリにまとめて、そこでclaude呼ぶ、とかをやったりしています。

そんなことしていると、resumeしようにもどこで実行すればいいかがわからなくなったりしてたので、今回の仕様になっています。

実行にあたっては子プロセスを立ち上げて、そっちでclaudeを実際に読んでいます。そのときはちゃんと対象のディレクトリ上で実行。子プロセスでやらせているので、親の方はディレクトリ移動は発生しないため、元の位置のままというわけです。

5. 詰まりポイント

表示範囲固定のアプリ、めっちゃむずい

今回、React Inkを使用しているわけですが、表示が崩れる問題が発生しまくりでした。

日本語とか、あとclaudeが使いがちな絵文字とか、なんとなくマルチバイト文字が悪さをしているのではないか、というあたりを付けて、claudeに色々と注文をつけて直してもらっていたのですがなかなか解決せず。

チャット履歴の部分は、どうしても実際のテキストが持つ改行と、現在のターミナル幅から計算した1行内の文字数を超過したときのwrapが存在して、何回やってもうまくいかずでした。

そのため、最終的には、テキストの改行は全部取っ払って、1会話をワンライナーで表示。表示しきれない範囲についてはhiddenにするという力技で対応しています。

まあこの機能はあくまでresumeするのが目的で、会話ログビューワとしての目的は優先度が低いよね、という判断でした。

CUIならWeb画面と比べたら圧倒的に開発負荷が低いというのは事実ではありつつ、こっちはこっちで意外と難しいのだな、という気づきがありました。

操作方法問題

本当は、マウススクロールをサポートして、下の会話ログの方はスクロールで確認できるようにしたいなぁと思っていました。

claudeさんにも依頼しては見たのですが、コードを書いたり消したりを繰り返してしまっているのを見て慌てて停止。どうも現状、マウススクロールで部分的にスクロールみたいなことは難しそうでした。

まあ確かに、そもそもターミナル自体をスクロールするときの動作ともかぶるだろうし、難しい気がします。

そんなわけでこの機能は諦めました。まあ翌々考えたら、キーボード操作だけで別に困らないですね。

まとめ

自分が感じた不満から、アイデアさえ固まってしまえば、シュッと実装にまでこぎつけました。

実は、個人開発としてオープンなツールを作ったのもこれがほぼ初めて。気になるポイントは色々ありつつも、まずは動くところまで、という感じで取捨選択をしながら開発を進めました。

このスピード感でリリースまで行けるのは、CUIの強みですね。あと、npxで一発で実行できちゃうのもやっぱデカイ。ccusageがあんなに簡単に使えちゃったのも、今回これを作ったきっかけになりました。

もっと良いツールや、公式のresumeが使いやすくなるまではメンテしたいと思います。ぜひ使ってみて、フィードバックをいただければ幸いです!

https://github.com/sasazame/ccresume


宣伝

はてなブログさんの方で、ささざめブログという雑記ブログを基本毎日更新しています。よかったら遊びに来てね。

Discussion

鹿野 壮鹿野 壮

めちゃくちゃ便利で最高です、ありがとうございます!
-rは毎日使っているのですが、とにかく見づらくて辛かったです。
公式で取り入れてほしいくらいの神機能です。

ささざめささざめ

ご感想ありがとうございます! お役に立てたようで嬉しいです!
公式の-r、使うたびにどれ選べばいいかわかんなくて困っていて、みんな使いこなせるのかなぁと心配してたんですが、今回頂いた反応見るに皆さん困ってるんだろうなぁと思いました(笑)