Claude CodeでFlutterのpub依存衝突を直す — analyzeをhookで回す
flutter pub getが依存を解決できないとき、Claude Codeに原因の切り分けを任せ、pubspec.yamlの編集後にPostToolUse hookでpub getとanalyzeを回して直す手順です。
Flutterでflutter pub getが依存を解決できないとき、Claude Codeに「直して」とだけ頼むと、dependency_overridesで黙らせて終わることがあります。エラーは消えますが、衝突の原因は残ります。
この記事では、衝突を「読む → 候補を絞る → 直す → 検証する」の順で進めさせる型を作ります。検証には、pubspec.yamlの編集直後にflutter pub getとflutter analyzeを走らせるPostToolUse hookを使います。CLAUDE.mdとhooksの初期設定はClaude CodeでFlutterアプリを開発する手順にあるので、ここでは依存の解決に絞ります。
依存衝突は「共有された依存のバージョンが合わない」状態
pubは、アプリが使うパッケージを1バージョンだけに決めます。npmのように同じパッケージの複数バージョンを同居させる方式は採りません。Dartではcollection 2.3.5とcollection 2.3.7のクラスが別物の型として扱われ、片方で作ったインスタンスをもう片方へ渡すと型注釈に合わないからです。
そのため、widgetsがcollection 2.3.5を、templatesが2.3.7を要求すると、解決はエラーで止まります。Flutterの例では、some_packageとanother_packageが異なるバージョンのurl_launcherに依存する場合が同じ型です。
衝突の直し方は、突き詰めると次の3通りです。
衝突の直し方の3系統
制約を広げる・上げる
自分の
pubspec.yamlの制約を見直し、依存するパッケージを新しい版に上げます。最も根本的な直し方です。片方の依存を変える
最新版でも衝突が残るなら、別のパッケージに置き換えるか、古い側の更新を待ちます。
dependency_overridesで固定する
衝突しているパッケージ同士が実際には互換に使えるときだけの、最後の手段です。
Claude Codeに任せるときは、上から順に試させ、3つ目を選ぶときは理由を報告させます。
原因の切り分けにはpub outdatedとpub depsを使う
エラーメッセージを読む前に、事実を2つ集めさせます。
flutter pub outdated
dart pub depspub outdatedは、依存ごとにCurrent・Upgradable・Resolvable・Latestの4列を出します。見るのはResolvableです。この列は、pub upgradeが解決できる最新版を示します。Upgradableより新しいResolvableがあるなら、pubspec.yamlの制約が古い版に縛っています。逆にResolvableがLatestより古いときは、別のパッケージが古いメジャーバージョンしか許さないせいで上げられません。
直接の依存は最新なのに、間接依存だけが古いままのこともあります。その場合はdart pub depsの出力で、古いパッケージの名前を探します。誰がそのパッケージを要求しているかが分かります。
Claude Codeには、この2つの出力を読ませたうえで、次の形で報告させるのが扱いやすいです。
- 衝突しているパッケージ名と、それを要求している側
ResolvableがLatestに届かない依存とその理由- 試す順番(制約を上げる → 置き換える → override)
CLAUDE.mdに依存解決の手順と禁止事項を書く
毎回の依頼文に手順を書くのは面倒なので、CLAUDE.mdに入れておきます。例えば次のような形です。
## 依存の衝突を直すとき
1. エラー全文を読み、衝突しているパッケージと要求元を挙げる
2. `flutter pub outdated` と `dart pub deps` で、古いままの依存と要求元を調べる
3. 直す順番は「制約を上げる → 別パッケージに置き換える → override」
4. `dependency_overrides` を足すときは、理由をコメントに残して報告する
5. `pubspec.yaml` を編集したら `flutter pub get` と `flutter analyze` が通るまで繰り返す
6. `dart pub upgrade --major-versions` の前は、`pubspec.yaml` をコミットしておく最後の項目には根拠があります。--major-versionsは、pub outdatedでResolvableと出る版まで、pubspec.yamlの上限制約を無視して上げ、pubspec.yamlも書き換えます。pubの案内でも、元に戻せるよう事前のコミットが勧められています。何が上がるかはdart pub upgrade --major-versions --dry-runで先に確認できます。
コマンドの許可はsettings.jsonに書いておくと、依存調査のたびに確認が出なくなります。
{
"permissions": {
"allow": [
"Bash(flutter pub get)",
"Bash(flutter pub outdated)",
"Bash(dart pub deps)",
"Bash(flutter analyze)"
]
}
}pub upgrade --major-versionsはpubspec.yamlを書き換えるので、許可リストには入れず、毎回確認が出る状態に残す構成が堅実です。
pubspec.yamlの編集後にpub getとanalyzeを走らせるhook
依存を直したつもりでも、pub getが通ったあとにanalyzeでエラーが出ることがあります。メジャーバージョンを上げれば、APIの変更に由来するエラーが出るのが普通です。これをClaude Codeが自分で見つけて直す流れを、PostToolUse hookで作ります。
PostToolUseは、ツールの実行が成功した直後に走るイベントです。hookが終了コード2で終わり、標準エラー出力にメッセージを書くと、その内容がClaudeに渡されます。ツールはすでに実行済みなので取り消しはできませんが、「次に何を直すか」のフィードバックには使えます。
次のスクリプトを.claude/hooks/flutter-deps-check.shとして作り、実行権限を付けます。pubspec.yaml以外のファイルでは何もせず終わります。
#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
case "$FILE" in
*/pubspec.yaml) ;;
*) exit 0 ;;
esac
cd "$(dirname "$FILE")" || exit 0
if ! OUT=$(flutter pub get 2>&1); then
echo "flutter pub get が失敗しました。依存の衝突を読み、制約を直してください。" >&2
echo "$OUT" | tail -n 40 >&2
exit 2
fi
if ! OUT=$(flutter analyze 2>&1); then
echo "flutter analyze が問題を報告しました。pubspec.yaml の変更に伴う修正が必要です。" >&2
echo "$OUT" | tail -n 60 >&2
exit 2
fi
exit 0flutter analyzeが問題を見つけたときに非ゼロで終わるかどうかは、手元のSDKで一度確かめてください。0で終わる環境では、ifの判定が働かず、analyzeの結果がClaudeに届きません。
.claude/settings.jsonには、Edit|Writeのmatcherで登録します。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/flutter-deps-check.sh",
"timeout": 300
}
]
}
]
}
}commandタイプのhookの既定タイムアウトは10分で、timeoutには秒数を書きます。依存の取得とanalyzeが重い環境では、上の値のように短めの上限を置くと、固まったときに気づけます。
hookの失敗はトランスクリプトにhook errorとして出ます。動いたかどうかは、Ctrl+Oで開くトランスクリプトか、claude --debugのログで確認できます。
衝突を読ませて直させる依頼文
hookとCLAUDE.mdが揃ったら、依頼文は短くて足ります。
flutter pub get が解決に失敗します。エラー全文を貼ります。
CLAUDE.md の「依存の衝突を直すとき」の順番で進めてください。
dependency_overrides を足す場合は、先に理由を報告してください。
(ここにエラー全文)エラー全文を貼るのがコツです。要約して渡すと、どのパッケージが何を要求しているかという情報が落ち、切り分けの手がかりが減ります。
Claudeがpubspec.yamlを編集すると、hookがpub getとanalyzeを回します。失敗すればその出力がClaudeに返り、同じ会話の中で次の修正に進みます。成功すれば何も表示されません。
pubspec.lockが固めた版と、間接依存を動かす方法
解決が通らない原因は、制約だけではありません。アプリではpubspec.lockが、直接・間接の全パッケージの版を記録しています。pubは一度作ったロックファイルを、指示があるまで書き換えません。意図せず新しい版へ移らないための仕組みですが、裏返すと、間接依存の古い版がロックされたまま残ります。
アプリの場合、このファイルはバージョン管理に入れる扱いです。チーム全員と本番ビルドで、同じ版の組み合わせを使うためです。Claude Codeに依存を直させた結果は、pubspec.yamlとpubspec.lockの両方の差分としてレビューします。片方だけを見ると、実際に何が上がったかを見落とします。
間接依存だけを動かしたいときは、dart pub upgrade --unlock-transitiveにパッケージ名を渡します。指定したパッケージと、その依存を最新に上げる指定です。
dart pub upgrade --unlock-transitive test args全体を上げるpub upgradeより影響範囲が狭いので、「間接依存が原因で上がらない」と分かったあとの一手として向いています。CLAUDE.mdには、全体のpub upgradeの前にまずpub outdatedのResolvable列を見ると書き添えておくと、無関係なパッケージまで動く事態を避けられます。
CIでは、ロックファイルを前提に取得する--enforce-lockfileが使えます。pubspec.yamlがロックを満たし、pubspec.lockが存在し、パッケージの内容ハッシュが一致するときだけ、新しい依存の解決が進みます。ロックの更新し忘れを検知する網として置けます。
落とし穴とhookの限界
落とし穴
dependency_overridesは自分のpubspecでしか効かない
overrideが有効なのは、そのアプリ自身のpubspec.yamlに書いたものだけです。依存先のパッケージが持つoverrideは無視されます。パッケージとして公開する側が、overrideで衝突を隠しても、利用者の環境では衝突が再現します。
overrideでpub getが通っても、衝突が解けたわけではありません。pubのドキュメントにあるとおり、パッケージが対応を宣言した範囲の外を指定すると、アプリが壊れる危険があります。analyzeが通っても、実行時に壊れる可能性は残ります。overrideを足した変更は、テストまで通してから採用するのが安全です。
hookにも限界があります。
Edit|Writeのmatcherは、Bashツールには反応しません。Claudeがflutter pub addをBashで実行してpubspec.yamlが変わった場合、このhookは走りません。ファイルの変更そのものを契機にするなら、FileChangedイベントのhookが選択肢です- PostToolUseは編集後に走るため、壊れた状態は一度できます。
pubspec.yamlの変更を自動で戻す仕組みではありません - CocoaPodsにはoverrideに相当する機能がありません。iOS側のPodの衝突は、
pubspec.yamlの直し方では解けません。AndroidのGradle側の衝突は、android/app/build.gradleのresolutionStrategyで版を固定する書き方がFlutterの説明にあります
依存を上げたあとの回帰確認
制約を上げてpub getとanalyzeが通ったら、テストも流させます。flutter testをPostToolUseに足す手もありますが、実行のたびに時間がかかります。Stopで走らせる設計との使い分けはClaude Code hooksでテストを自動実行するにまとめています。
パッケージを公開する側なら、dart pub downgradeのあとにdart analyzeとdart testを回す確認も使えます。制約の下限が、実際に使うAPIに追いついているかを調べられます。下限を実態に合わせるときはdart pub upgrade --tightenが使えます。
言語ごとのlint自動修正の書き方はPostToolUse hookのLint自動修正に、hookイベント全体の整理はClaude Code Hooks完全ガイドにあります。Dart用のスキルやツールを足したいなら、Dart and Flutterプラグインの記事が次の一歩です。
まとめ
依存衝突の直し方は、制約を上げる、依存を替える、overrideで固定する、の順に試すのが筋です。overrideは、衝突しているパッケージ同士が実際に互換に使えるときの最後の手段にとどめます。
CLAUDE.mdに手順と「overrideは理由を報告」の一行を入れておけば、Claude Codeは勝手に黙らせる方向へ流れにくくなります。pubspec.yamlの編集直後にpub getとanalyzeが走るhookがあれば、修正の成否はClaude自身が確認できます。残るのは、Bash経由の変更が拾えない点と、実行時の互換性です。後者はテストで確かめます。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。