difitへのコントリビュート
2026-09-14
difit
difitは、ローカルのGit差分をGitHubのPR画面のようなUIで確認・レビューできるCLIツールだ レビューコメントをエージェント向けのプロンプトとしてコピーできるので、ローカルで差分を読み、そのままフィードバックを返せる
Zennに書いた開発フローの記事で、開発フローを支える3つのツールの一つとして紹介している pstackで事前設計し、herdrでエージェントを動かし、difitで出力をレビューする、という流れだ 自分はGitHubのside by side表示が一番diffを読みやすいと思っていて、difitはその見た目のままローカルで完結できる
レビュー中に見つけた違和感
当時subtreeを大量に引き込んで統合してあるリポジトリ上で作業をしていた
過去のコードをまずimportしており、徐々に新規コードにmigrationしていく作業をしていた
エージェントが書いた差分をdifitで確認していたときに、ファイルツリーの表示に気づいた
diffの中に、あるpathが単体のファイルとしてもディレクトリの接頭辞としても現れる場合がある
たとえば削除された vendor(シンボリックリンクなど)と、追加された vendor/lib.ts が同じdiffにあるようなケースだ
このとき、ツリーには vendor の下のファイルが表示されなかった
子ノードが静かに隠れてしまい、レビュー対象の差分に気づけない
コードを見ていくと考慮されていないパターンだったようなので、issue #452 として起票し、そのまま自分で直すことにした
原因
ファイルツリーは buildFileTree で組み立てている
ここで、最初に出会ったpathをleafノードとして作り、その後同じpathがディレクトリの接頭辞として現れても、leafをディレクトリに昇格させていなかった
結果として vendor はファイルのまま扱われ、vendor/lib.ts を入れる場所がなく子が消えていた
最初の修正とメンテナのレビュー
最初は素直に、leafだったノードをディレクトリに昇格させる実装を書いた テストも通ったのでPRを出したところ、メンテナのyoshiko-pgさんからレビューが返ってきた
昇格方式だと、昇格したノードはディレクトリとしてだけ描画されるため、削除された vendor のfile rowが消える
difitではfile rowをクリックするとその差分へスクロールし、reviewedチェックやコメント件数もそこに紐づく
つまり、ファイルの行そのものが失われると、レビューに必要な導線が落ちてしまう
テストが通っていたのは、getByTitle('vendor') がディレクトリのヘッダーにもマッチしていたからだった
代替として、fileノードとディレクトリノードを別々の兄弟ノードとして扱う方式を提案された lookupの条件にkindを足す、というシンプルなものだ
マージされた修正
提案に沿って、find条件を c.name === part && c.isDirectory === !isLast に変更し、同じpathのfileとディレクトリが兄弟として共存するようにした
promotionの分岐はまるごと削除した
Reactのkeyは両ノードが同じpathを持つため file:${file.path} に変更して衝突を避けた
テストは、vendor がディレクトリのヘッダーではなくクリック可能なfile rowとして存在し、クリックで onScrollToFile が呼ばれることまで確認するように強化した
無事マージされ、PR #453 としてmainに入っている
使っているツールに還元する
今回のコントリビュートは、Zennの記事に書いた開発フローの延長にある difitはエージェントの出力を読むための道具で、毎日使っている その道具の不具合を、使っている最中に見つけて直し、また使う、自然な流れだった
Nomad Karaokeのときは、自分の興味の外側にあるOSSを調べてコードを理解する、という動機が大きかった 今回は逆で、自分の開発フローの中核にあるツールを、自分のために直した
レビューも的確ですぐレスポンスを返してもらった 今回の変更はそんなに大きくないが、tree viewの根幹に関わる部分でコードはシンプルだが重要な部分だ UI実装の意図を理解するのにレビューは非常に重要だった
全行レビューをやめられるか、という問いに対してまだ答えは出ていない ただ、理解を同期するために毎日使う道具に少し貢献できてよかった
→ PR #453 → Issue #452 → GitHub: difit → Zenn: 全行レビューをやめられるか