18
8
生成AIに関する記事を書こう!
Qiita Engineer Festa20242024年7月17日まで開催中!

ClaudeやChatGPTにリポジトリを丸ごと読み込ませるコマンドを作りました!

Last updated at Posted at 2024-07-15

Claude を使ったコーディング体験が素晴らしかったので、より簡単に Claude と一緒にコーディングするための Node.js コマンドを作りました。

リポジトリの直下で以下を叩くと repopack-output.txt というファイルが出来上がります。

$ npx repopack

そのまま Claude に次のようなプロンプトと一緒に送ると、

このファイルはリポジトリのファイルを1つにしたものです。コードのリファクタをしたいのでまずコードを確認してください。

全体の内容を理解した上で、リファクタリングなどを進めることができます。
image.png

具体的な内容を提案すると、それに従って良い感じのコードを生成してくれます。Claude だと Artifacts 機能で複数のファイルが出力できるため、依存関係にある複数のコードも一緒に生成できます。

image.png

特徴

指定したフォルダ配下のファイル郡を1ファイルにまとめてくれるツールです。

.gitignore 対象やバイナリ系のファイルを無視したり、AIに理解させるための文言を入れたりなど細かいことはやっていますが、以下のようなファイルを出力するだけでやっていることは単純です。

================================================================
REPOPACK OUTPUT FILE
================================================================
// AIに理解してもらうための文言

================
File: src/index.js
================
// ファイルの内容

================
File: src/utils.js
================
// ファイルの内容

Claude 3.5 Sonnet だと、こういった雑な構造でもきちんと理解してくれるので、複数ファイルに跨るリファクタなども難なく対応してくれます。

生成AIのサービスごとに処理できるコンテキスト長は限られているので、小規模なプロジェクトに限られますが、個人開発レベルであれば十分使えるかと思います。(仕事のコードでは使わないでください)

設定ファイルでignore対象を調整できたりするので、詳細は GitHub をご覧いただけると幸いです。

経緯

最近個人で Claude Pro を色々と試しており、Projects の機能で複数ファイル読み込ませてコードを改修させたりしていたのですが、60%~95% ぐらいの精度のコードを生成してくれるので、それを参考にコードを書き換えると割と効率が良いと感じています。

ただ、Projects にフォルダやzipごとアップロードするような機能がなく、Cursor を使うことも考えましたがAPIが従量課金だったりと面倒で躊躇していました。

そんなときにこの記事を見て、丸ごと1ファイルでも十分に理解してくれることに気づき、ツールの作成・公開に至ります。

開発について

大したことをしているわけではないですが、なにかのお役に立てれば幸いです :bow_tone1:

出力ファイルの内容

出力ファイルの先頭に、このファイルをどう取り扱うかの文章が入っています。

最初はファイルパスと内容だけのシンプルな構造だったのですが、うまく理解してくれないことがあったため、先頭に「ファイルの目的」「フォーマット」「取り扱い方法」「その他の補足」を入れることで、より精度良く理解してくれるようになりました。

また、ファイルごとの区切り線に関しては、ChatGPT の Tokenizer を参考に、トークン数が1になる = の16個と64個区切るようにしています。

image.png

image.png

ChatGPT-4o や Claude だとまたトークン数が違ってくるとは思いますが、近しいものにあわせておこうという意図でこうしています。

CLIの実装

コマンドラインツールの作成にはcommanderライブラリを使用しました。
yargsでも良かったのですが、構文がシンプルで、自動でヘルプを作成してくれる機能が気に入っています。

また、自身のバージョンを取得するのに package.json を見ています。Node.js の古いバージョンでも package.json を適切に読み込ませないといけないので、 import などは使わず fs で直接取っています。そして、ES module だと __dirname が使えず import.meta.dirname を使えないバージョンがあったりもするので、少しトリッキーな取り方をしたりもしています。

import * as url from 'url';

const dirName = url.fileURLToPath(new URL('.', import.meta.url));

npmパッケージとしての公開

npmへの公開に関しては、楽に新バージョンを公開できるように以下のscriptをpackage.jsonに入れています。
npm version <major|minor|patch> が地味に便利ですね。

package.json
    "npm-publish": "npm run lint && npm run test-coverage && npm run build && npm publish",
    "npm-release-patch": "npm version patch && npm run npm-publish",
    "npm-release-minor": "npm version minor && npm run npm-publish",
    "npm-release-prerelease": "npm version prerelease && npm run npm-publish"

ファイルエンコーディング

このツールではバイナリファイルなどは読み込みたくないので、is-binary-path などでバイナリを無視しつつ、 jschardet, iconv-lite でエンコーディングを適切に処理しています。

ファイルのignore

特定ファイルのignoreに関しては ignore が便利でした。

.gitignore ライクなパターンのフィルタを簡単に実装できます。

function createIgnoreFilter(patterns: string[]): (path: string) => boolean {
  const ig = ignore.add(patterns);
  return (filePath: string) => !ig.ignores(filePath);
}

まとめ

単純に自分が欲しかっただけのシンプルなツールで、待っていればClaudeにもフォルダやzipのアップロード機能が実装されそうですが、今後も増えていくであろう生成AIサービスで汎用的に使えるものにはなっていると思います。

ぜひ試してフィードバックをいただけると嬉しいです!

18
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
8