mcpField
S
starter-kit-upgrade

starter-kit-upgrade

github.com/laravel開発731480 回インストール2 週間前に更新
リポジトリ

starter-kit-upgrade について

Laravel Starter Kit Upgrade は、Laravel スターターキットを使うプロジェクト向けのアップグレードスキルで、上流の機能変更を個別に選んで取り込めます。専用ブランチ、機能ごとのコミット、動作確認でカスタマイズを保護し、競合の自動解決やマニフェスト・ロックファイルの上書きは行いません。

主な機能

  1. 01Vue、React、Svelte、Livewire の kit を判別
  2. 02上流の機能一覧から選択
  3. 03ファイルを比較しカスタム変更を提示
  4. 04専用ブランチで機能ごとにコミット
  5. 05適用後にテストとビルドを再実行

活用シーン

  1. 01カスタマイズ済みプロジェクトに上流の通知機能を導入
  2. 02上流変更が独自ファイルに与える影響を確認
  3. 03スターターキットの機能を個別に採用
  4. 04更新後もテストとビルドが通ることを検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/laravel/agent-skills --skill starter-kit-upgrade

インストール後、Claude Code で/starter-kit-upgradeを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

scripts/
apply_new_files.sh
classify_feature.sh
fetch_kit.sh
later_edits.sh
preflight.sh
reconcile_manifests.sh
run_tests.sh
scan_transitive_imports.sh

詳細

Laravel Starter Kit のアップグレード

  • ユーザーは laravel/vue-starter-kit、react-starter-kit、svelte-starter-kit、または livewire-starter-kit からプロジェクトを作成し、その後カスタマイズします。コードの所有者はユーザーです。
  • 上流から取り込むのは「トースト通知」「2FA のオートフォーカス修正」などの特定の機能であり、「バージョンのアップグレード」ではありません。
  • ユーザーの Git 履歴とキットの Git 履歴に関連性はありません。共通の祖先もありません。ユーザーの現在の状態と上流の現在の状態を、バイト単位で比較します。
  • カスタマイズされたファイルを自動マージすることはありません。カスタマイズ箇所を提示し、判断はユーザーに委ねます。
  • 動作の維持が契約です。現在パスしているユーザーのテスト、型チェック、ビルドは、適用後もすべてパスする必要があります。

安全上の契約:妥協不可

副作用が発生する操作の前に、以下をユーザーに伝え、その後も常に遵守してください。

  1. 作業ツリーはクリーンでなければなりません。git status --porcelain の出力が空でない場合は拒否し、コミットまたはスタッシュするようユーザーに伝えてください。「ユーザーに代わってスタッシュ」してはいけません。
  2. すべての作業は専用ブランチ(starter-kit-upgrade/<short-id>)で行います。ユーザーの現在のブランチは変更しません。
  3. 適用する機能ごとに、個別のコミットを作成します。これにより、変更を取り消せます。
  4. コンフリクトを自動解決してはいけません。カスタマイズされたコードに触れる変更は提示し、デフォルトではそのファイルをスキップします。
  5. マニフェストやロックファイル(composer.json、package.json、*-lock.*)をユーザーに知らせず上書きしてはいけません。差分を表示し、判断はユーザーに委ねます。
  6. 動作が維持されていることを検証します。適用後にユーザーのテスト、型チェック、ビルドを再実行してください。以前パスしていたチェックが失敗した場合はリグレッションです。停止して状況を提示し、変更の取り消しを推奨してください。
  7. 曖昧さのない根拠から判定し、曖昧な場合は確認してください。(config/fortify.php が存在するなどの)具体的な根拠は問題ありません。シグナルが混在している、または存在しない場合に、可能性の高そうな答えを選んではいけません。

これらのいずれかに違反した場合は、問題の内容と復旧方法を明確に伝えて中止してください。

必須ツール

  • git(ユーザーのプロジェクト内)
  • gh(認証済みであること。gh auth status が OK を返す)
  • jq(run_tests.sh で使用)
  • bash(同梱スクリプト用)

不足しているツールがある場合は、フェーズ 4 で停止し、インストール方法をユーザーに伝えてください。

注意点

事前に伝えられていない場合、エージェントが誤った判断をする環境固有の挙動です。ワークフローを始める前に読み、全体を通して適用してください。

  • 並行実装。 機能に new ファイルがあり、呼び出し箇所が differs となっている場合、ユーザーがすでに社内で同等の実装(独自のトーストヘルパー、バリデーションルールなど)を用意している可能性があります。機能全体を提示してください。「安全」な変更として new ファイルだけを個別に適用してはいけません。デフォルトでは機能全体をスキップします。ユーザーは後からアップストリーム版を採用し、独自の実装を削除できます。

  • 名前が変更されたパス。 new パスのベース名またはクラス名がユーザーのリポジトリ内の別の場所にすでに存在する場合、ユーザーが名前を変更したか、移動した可能性があります。自動適用せず、該当箇所を提示してください。そうしないと重複が作られてしまいます。アップストリームの変更内容を示し、ユーザーが名前を変更したファイルに手動で適用するか、ユーザーの確認を待ってください。

  • その後のアップストリーム編集。 アップストリームの HEAD をコピーすると、機能が導入されたコミットだけでなく、その後のすべてのコミットも取り込まれます。適用前に、必ず Phase 5 の手順 2 の確認を実行してください。その後の編集がある場合は、HEAD:<path> ではなく <sha>:<path> の範囲に絞ってください。

  • 間接的なインポート。 新規ファイルは、その機能のコミットに含まれていないヘルパーを import していることがよくあります(Vue/React/Svelte:@/lib/...、@/components/...、Livewire:@include、<x-...>、<livewire:...>)。Phase 5 の手順 4 でこの確認を行います。確認せずに機能の適用完了を宣言してはいけません。見落としたインポートは、実行時またはコンパイル時のエラーにつながります。

  • ロックファイルの差分。 マニフェストはユーザーが管理しています。上書きしてはいけません。アップストリームとの差分をユーザーに説明し、マージしてもらってから、パッケージマネージャーでロックファイルを再生成してください(Phase 6)。

  • メジャーアップデート後の古い node_modules。 Vite v7 から v8、React 18 から 19 などの更新後は、npm install が ERESOLVE で失敗することがよくあります。クリーンアップして再インストールしてください(Phase 6)。

  • 新しいマイグレーション。 アップストリームでマイグレーションが追加された場合(例:「Skeleton に合わせてマイグレーションを追いつかせる」)、別途提示してください。まず php artisan migrate:status の実行を推奨します。データが入った DB に新しいマイグレーションを適用すると、明確なエラーが発生する可能性があります。

  • 機能として扱うフレームワークのメジャーアップデート。 Laravel 12 から 13、Livewire 3 から 4、Inertia v2 から v3 などの変更は規模が大きく、機能ごとに進めるフローでは対応できません。このスキルを使って実行しようとしないでください。代わりに、ユーザーに対応する Laravel Boost MCP スラッシュコマンドを先に実行するよう案内し、アップグレード後の(クリーンな作業ツリーの)リポジトリでこのスキルを再実行してもらいます。Boost がまだインストールされていない場合:composer require laravel/boost --dev && php artisan boost:install(Boost ^2.0 が必要です)。スラッシュコマンド:

    • Laravel 12 → 13:/upgrade-laravel-v13
    • Livewire 3 → 4:/upgrade-livewire-v4
    • Inertia v2 → v3:/upgrade-inertia-v3
  • すでに存在する機能。 Phase 2 の事前フィルターで見落とされ、Phase 5 の分類で全ファイルが already-present と報告された場合は、「すべてのファイルがアップストリームの現行版と一致しています。次に進みます。」と記して、その機能をスキップしてください。空のコミットを作成してはいけません。

  • differs が約 50 件を超える場合。 ファイルごとに確認する進め方では、その規模に対応するのは手間がかかりすぎて有益ではありません。中断し、その機能は手動でアップグレードするよう推奨してください。

ワークフロー

順番に進める 8 つのフェーズです。各フェーズで、次のフェーズが前提とする条件を確立します。

フェーズ 1:キットとブランチの種類を特定する

ユーザーのプロジェクトを調べます。

vuereactsveltelivewire
手掛かりresources/js/components/ui/ 内の .vue ファイルresources/js/components/ui/ 内の .tsx ファイルresources/js/components/ui/ 内の .svelte ファイルresources/js/components/ui/ ディレクトリがない
package.json にあるもの"vue" + "@inertiajs/vue3""react" + "@inertiajs/react""svelte" + "@inertiajs/svelte"該当なし
composer.json にあるもの該当なし該当なし該当なし"livewire/livewire" + "livewire/flux"

検出したキットを明示します。一致する列が 1 つだけなら、そのまま進めます。2 つの列が部分的に一致する場合(例:.vue と .tsx の両方がある、または package.json に vue と react の両方が記載されている場合)は、停止して質問します。

次に、ブランチの種類を判定します。キットごとに、独立した 2 つの軸で決まる 4 つのブランチがあります。

  • 認証軸(composer.json を読み取ります):
    • composer.json に laravel/fortify がある、または config/fortify.php が存在する、または app/Actions/Fortify/ が存在する、または app/Providers/FortifyServiceProvider.php が存在する場合は Fortify です。
    • composer.json に laravel/workos があり、Fortify の目印がどれも存在しない場合は WorkOS です。
  • チーム軸(チーム用のスキャフォールディングがあるか確認します):
    • app/Models/Team.php が存在する場合は Teams です(通常は Membership.php、TeamInvitation.php、および ..._create_teams_table.php というマイグレーションもあります)。
    • それ以外は Non-teams です。

2 つの軸を組み合わせてブランチ名を決定します。

AuthTeamsBranch
Fortifyいいえmain
Fortifyはいteams
WorkOSいいえworkos
WorkOSはいworkos-teams

検出したブランチを明示します。シグナルが矛盾している場合(例:Fortify の目印があり、かつ composer に laravel/workos が記載されている、または Team.php モデルがあるのにチーム用マイグレーションがない場合)に限り、質問します。これはユーザーによるカスタマイズを示しており、安全に推測できないためです。

フェーズ 2:利用可能なアップストリーム機能を列挙する

ユーザーは「使用しているバージョン」を確実に伝えられないため(また、こちらもその確認はしません)、現時点のアップストリームを調べて、機能カタログを提示します。

生データを取得します。デフォルトの対象範囲は直近 100 件のコミット/マージ済み PRです。これより古い機能はカタログに表示されないことをユーザーが把握できるよう、最初にその旨を伝えます。対象範囲よりかなり前にブートストラップしていた場合は、&page=2、&page=3 などで遡るか、--limit を増やします。

gh api "repos/laravel/<kit>/commits?sha=<branch>&per_page=100" \
  -q '.[] | {sha: .sha[0:7], date: .commit.author.date[0:10], msg: .commit.message | split("\n")[0]}'

gh pr list --repo "laravel/<kit>" --state merged --base "<branch>" --limit 100 \
  --json number,title,mergeCommit,mergedAt

コミット/PR をユーザー向けの機能にまとめます。ユーザーが認識しやすい例を示します。

  • 「すべてのキットにトースト通知を追加」(1 コミット、複数ファイル)
  • 「認証フォームにパスワード表示切り替えを追加」(1 コミット、3 ファイル)
  • 「2FA のオートフォーカスを修正」(1 コミット、1 ファイル)
  • 「チームのサポート」(1 PR、多数のファイル。大規模と表示)
  • 「Inertia 3 へのアップグレード」(ロックファイル中心。レビューが必要と表示)
  • 「メンテナンス:フォーマット/Lint 設定」(小さなコミットをまとめたもの)

内部処理やリファクタリングのコミットは、1 件の「メンテナンス」にまとめます。通常、ユーザーはこれをスキップします。

事前フィルタリング:機能候補ごとに、そのコミットに対して scripts/classify_feature.sh を実行します。すべてのファイルが already-present の場合は、[!] すでに存在します と表示し、デフォルトではスキップします。

フェーズ 3:カタログを提示し、明示的な選択を得る
Available upstream features (vue-starter-kit, branch: main):

[ ] Toast notifications              · PR #142, 4 files, 1 lockfile
[ ] Password visibility toggle       · PR #131, 3 files
[ ] 2FA autofocus fix                · commit 78fda0c, 1 file
[ ] Teams support                    · PR #98, 23 files (LARGE)
[~] Inertia 3 upgrade                · PR #110, lockfile-heavy (review carefully)
[!] Already present: Vite font plugin

Which would you like to pull in?

選択を待ちます。選択内容と、影響を受けるファイル数をまとめて確認します。副作用が発生する前に、最後にもう一度確認します。

フェーズ 4:事前確認、ベースライン、ワークスペースのセットアップ

事前確認を実行します。

scripts/preflight.sh <user_repo>

リポジトリが Git リポジトリであること、作業ツリーがクリーンであること、認証済みの gh と jq が利用できることを確認します。ゼロ以外の終了コードが返された場合は、メッセージをそのまま提示して処理を停止します。

フェーズ 7 で回帰と既存の失敗を区別できるように、検証ベースラインを記録します。並行実行によって互いの結果が上書きされないよう、mktemp を使用します。

baseline=$(mktemp -t skup-baseline.XXXXXX.json)
scripts/run_tests.sh <user_repo> --baseline "$baseline"

$baseline を保持してください。フェーズ 7 で必要になります。

上流キットを取得し、そのパスを保存します。

kit_dir=$(scripts/fetch_kit.sh <kit> <branch>)

$kit_dir を保持してください。フェーズ 5 で必要になります。このスクリプトは冪等です。同じ引数で再実行すると、再クローンではなく最新のブランチ先端を取得します。

アップグレードブランチを作成します。

git -C <user_repo> checkout -b "starter-kit-upgrade/$(date +%Y%m%d-%H%M)-<first-slug>"

ユーザーがすでに starter-kit-upgrade/... ブランチにいる場合(前回の実行後にクリーンアップされていない場合)、新しい名前が既存の名前と重なると checkout -b は拒否されます。自動で解決しないでください。そのブランチで再開する(checkout -b をスキップし、現在の状態から続行する)、新しく開始する(新しいタイムスタンプ付きの名前は分単位で異なるため、そのまま再試行する。同じ分の場合は +%Y%m%d-%H%M%S に変更する)、または手動でクリーンアップできるよう中止するのいずれにするか、ユーザーに確認してください。ユーザーに代わって既存のブランチを削除してはいけません。

以降の書き込みはすべて、このブランチに対して行います。

フェーズ 5: 選択した各機能を適用する

選択した各機能について、順に:

  1. 分類します。scripts/classify_feature.sh <kit_dir> <sha> <user_repo> を実行します。ステータス:
  • new: ファイルがユーザーリポジトリに存在せず、upstream HEAD には存在します。追加しても安全です。
  • already-present: ユーザーのファイルが upstream HEAD とバイト単位で同一です。スキップします。
  • differs: ユーザーがファイルを持っており、バイトが upstream HEAD と異なります。表面化します。
  • deleted-upstream: upstream HEAD にファイルがありませんが、ユーザーは持っています。表面化します。デフォルトはユーザーのものを保持します。
  • lockfile: マニフェストまたはロックファイルです。表面化します。自動マージは決して行いません。

分類器は upstream HEAD とのみ比較します。ユーザーの git 履歴はキットの履歴まで遡れないため、マージの基準となる「ビフォアイメージ」はありません。そこは試みません。機能コミットは、どのパスを確認すべきかを列挙するだけです。

  1. later-edits チェック。どの機能パスが 後の upstream コミットでも変更されたかを見つけます:
scripts/later_edits.sh <kit_dir> <sha> <user_repo>

スクリプトが出力する各パスは、upstream HEAD の内容をコピーすると 後の 変更も一緒に取り込まれてしまうパスです。<sha>:<path> を HEAD:<path> と diff します。空白以外のハンクが異なる場合は、機能コミットにスコープを絞り(git -C <kit_dir> show <sha>:<path>)、レポートに記録します。

3. new ファイルを適用します。 スクリプトは各 new パスについて upstream HEAD の内容を書き込み、ステージします。それ以外はすべてステップ 4〜5 に残します:

scripts/apply_new_files.sh <kit_dir> <sha> <user_repo>

書き込んだ各ファイルについて applied <path> を出力するので、機能のコミットメッセージとレポート用にリストを収集できます。

スクリプトを実行させる前に、リネームの落とし穴を確認します(落とし穴 →「リネームされたパス」を参照)。new パスのベース名がユーザーリポジトリの別の場所にすでに存在する場合は、適用する前にユーザーに表面化します。

4. 推移的インポートチェック。 新しいファイルは、同じ機能コミットに含まれないヘルパーをインポートすることがよくあります。スクリプトはキットに適した正規表現を選びます(Vue/React/Svelte は TS/JS インポートを処理し、Livewire は Blade インクルード / x- コンポーネント / livewire: タグを処理します):

scripts/scan_transitive_imports.sh <kit> <new_files...>

出力はインポートごとに <file>:<line>:<match> です。各マッチについて、対応するヘルパーファイルがユーザーリポジトリに存在するか確認します。存在しない場合、新しいファイルはコンパイル/レンダリングされません。不足しているターゲットを、ユーザーが取得する必要があるフォローアップ依存関係としてフラグを立てます(differs と同じウォークスルー)。

5. differs、deleted-upstream、lockfile についてユーザーをガイドします。 一度に 1 ファイルずつ:

  • upstream が持っているものを表示します: git -C <kit_dir> show HEAD:<path>(later_edits.sh がこのパスにフラグを立てた場合は <sha>:<path>)。
  • ユーザーの現在のファイルを表示します。
  • 両者の diff を表示します。
  • ユーザーに選択を求めます: upstream を丸ごと採用する(非可逆。先に確認する)、ユーザーのものを保持する、または手動でマージする(参考用に unified diff を生成し、ユーザーが結果を書きます)。
  • 迷っている場合は、目の前に diff を置いてもう一度尋ねます。それでも迷っているなら → ユーザーのものを保持して先に進みます。黙って選ばないでください。
  • ユーザーが選んだものをステージします: git -C <user_repo> add <path>。

lockfile の場合: マニフェストを決して上書きしないでください。composer.json / package.json の upstream diff を表示し、関連する変更を案内し、ユーザーにマニフェストを編集させます。ロックファイルの再生成はフェーズ 6 で行います。

6. 機能を 1 つのリバート可能な単位としてコミットします:

git -C <user_repo> commit -m "starter-kit-upgrade: <feature name>

Upstream: laravel/<kit>@<sha>
Files added: <list>
Files updated (took upstream): <list>
Files updated (manual merge): <list>
Files kept as-is: <list>"

ユーザーがいつでも中止したい場合は、ブランチをそのままにしておきます。git branch -D で削除できます。

フェーズ 6: 必要に応じてマニフェストを調整する

いずれかの機能がマニフェストに触れた場合、ロックファイルは同期が取れていません。ユーザーが同意した後、次を実行します:

scripts/reconcile_manifests.sh <user_repo>

スクリプトは composer install を実行し(composer.json と composer.lock が両方存在する場合)、既存のロックファイルから JS パッケージマネージャーを自動検出して <pm> install を実行し、失敗した場合(通常は Vite v7 → v8 や React 18 → 19 のようなメジャーアップグレード後の ERESOLVE)は node_modules とロックファイルを消去して一度だけ再試行します。

ロックファイルの更新は、独立してリバートできるよう、別の starter-kit-upgrade: dependency lockfiles コミットとしてコミットします。

フェーズ 7:動作が維持されていることを確認する

ベースラインと比較します。

scripts/run_tests.sh <user_repo> --compare "$baseline"

比較モードでは、存在する PHP テスト、JS の型チェック、JS のビルドを実行し、ベースラインでは成功していたものの、現在失敗するようになったチェックのみを報告します。既存の失敗はアップグレードが原因ではないため、処理を妨げません。

リグレッションが報告された場合:

  • スクリプトが示すチェックごとのログファイルから、失敗時の出力を提示します。
  • まず git revert HEAD を推奨します。それで解決しない場合は、もう一度リバートします。
  • 複数の機能が関係して原因が不明な場合は、git bisect start <upgrade-branch> <previous-branch> を提案します。
  • 失敗したチェックに合格させるためにコードを編集してはいけません。これは動作に関する契約に反します。

プロジェクトで検出可能な検証コマンドが見つからない場合は、レポートにその旨を明記します。検証を実施したかのように装ってはいけません。

フェーズ 8:レポートを作成する

まず /tmp/starter-kit-upgrade-report-<id>.md に書き込みます(<id> はアップグレードブランチの starter-kit-upgrade/<id> と一致します)。ユーザーのリポジトリに黙って書き込んではいけません。ID を付けることで、同時実行や再実行による上書きを防ぎます。パスを提示し、STARTER_KIT_UPGRADE.md としてリポジトリに追加するか、リポジトリの外に置いておくかを尋ねます。

# Starter Kit Upgrade Report

- Date: <date>
- Kit: laravel/<kit>
- Branch tracked: <branch>
- Upgrade branch: starter-kit-upgrade/<id>

## Features applied

- <feature name> · laravel/<kit>@<sha> · <N files>
  - Applied: <list>
  - Skipped: <list with reasons>
  - Manual decisions: <if any, with reasoning>
  - Later-edit drift avoided: <if any, with paths scoped manually>

## Lockfile updates

<which lock files were regenerated and how>

## Verification

- Baseline: <path or summary>
- Result: <PASS / REGRESSED:<list> / NO-CHECKS>
- Output: <relevant snippet>

## How to revert

- Drop a single feature: `git revert <commit-sha>`
- Discard everything: `git checkout <previous-branch> && git branch -D starter-kit-upgrade/<id>`

対象外

  • ユーザーがどの「バージョン」のキットから始めたかの検出。確実な方法はないため、検出できるとは装いません。
  • 依存関係のバージョン制約の自動調整。内容を提示し、判断はユーザーに委ねます。
  • スターターキットのフォーク。リポジトリの構成が公式キット 3 種のいずれとも認識できない場合は、拒否して理由を説明します。
  • キット間の移行(例:Vue → React)。
  • 適用したファイルに対するリンター/フォーマッターの実行。ユーザー自身のツールで実行してもらいます。

コメント