claude --resumeをもっと使いやすくするCLIツール、「ccresume」を作った
はじめに
Claude Codeで会話を再開するときに使えるコマンドで、claude --resume
というのがあります。
このコマンド、実際に使ってみるとわかるんですが、微妙に使いにくいなぁと不満でした。
これが実際の画面なんですが、どれがなんのsessionか、全然わからないんですよね。
で、そんな不満がある最中で、先日開催された #claude_code_deep_dive のイベントで、@hiragramさんが紹介されていた、"ccraw"という会話ログビューワを見て、なるほどデータ的に会話ログが見えるのかと。
それなら、ログの簡易確認ができるresumeが作れるのではないかと思い、作成に至りました。
なお、作成にあたっては、先述のhiragramさんに加えて、@ryoppippiさんのccusageと、
@mizchiさんのReact Ink紹介記事に、多分に影響を受けています。
作ったもの
ccresume
- Claude Codeの会話を簡単に再開できるCUI(TUI)ツールです。
主な機能
- 過去の全プロジェクトの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が使いやすくなるまではメンテしたいと思います。ぜひ使ってみて、フィードバックをいただければ幸いです!
宣伝
はてなブログさんの方で、ささざめブログという雑記ブログを基本毎日更新しています。よかったら遊びに来てね。
Discussion
めちゃくちゃ便利で最高です、ありがとうございます!
-rは毎日使っているのですが、とにかく見づらくて辛かったです。
公式で取り入れてほしいくらいの神機能です。
ご感想ありがとうございます! お役に立てたようで嬉しいです!
公式の-r、使うたびにどれ選べばいいかわかんなくて困っていて、みんな使いこなせるのかなぁと心配してたんですが、今回頂いた反応見るに皆さん困ってるんだろうなぁと思いました(笑)