Verify Svelte Compatibility — 外部 Svelte リポジトリでの rsvelte 互換性検証
rsvelte が公式 Svelte コンパイラと 同じ出力・同じ挙動 を生成するかを、実際の Svelte エコシステムのリポジトリで検証するスキル。
このスキルは 3 つのことをやる:
- 新規リポジトリの取り込み — GitHub URL を受け取り、
compat/verify-svelte-compat/<name>/配下に git submodule として追加し、互換性を検証する - 既存サブモジュールの更新検証 —
vite-plugin-svelteやlanguage-toolsのような既存サブモジュールを最新化したうえで、互換性が保たれているか再検証する - 回帰の自動修正 — 検証中に検出された rsvelte 側のバグを、修正再検証ループで解消する
重要: 修正は rsvelte 側のみ。ターゲットリポジトリは「公式 Svelte 互換性のリファレンス」として扱い、原則として変更しない。
前提
- rsvelte リポジトリ内で実行する
cargo,pnpm,node(>=22),gitが使えるsvelte/サブモジュールが初期化されている(公式コンパイラのリファレンス)
用語
| 語 | 意味 |
|---|---|
| ターゲット | 検証対象の外部 Svelte リポジトリ |
| ツール型 | Svelte コンパイラを内部で呼び出すツール / ライブラリ(vite-plugin-svelte, language-tools 等)。自前のテストスイートを持つ |
| アプリ型 | エンドユーザー向けアプリ(immich, gradio, SvelteKit ベースの自社プロダクト等)。.svelte ファイルが多数ある |
| swap | ターゲット内部で読まれる svelte/compiler を、rsvelte の NAPI バインディングに置き換える操作 |
引数の解釈
/verify-svelte-compat <arg> の <arg> を以下のルールで解釈する:
<arg>が URL(http(s)://またはgit@) → Mode A(新規追加)<arg>が既存サブモジュールのパスまたは名前(.gitmodulesで確認)→ Mode B(更新検証)- 空 → ユーザーに確認
# 引数の検証ロジック
if [[ "$ARG" =~ ^(https?://|git@) ]]; then
MODE="add"
elif git config --file .gitmodules --get-regexp '\.path$' | awk '{print $2}' | grep -Fxq "$ARG"; then
MODE="update"
elif git config --file .gitmodules --get-regexp '\.path$' | awk '{print $2}' | grep -F "/$ARG\$"; then
MODE="update" # ベース名一致
else
# ユーザーに確認
fi
ディレクトリ規約
compat/verify-svelte-compat/ # このスキルが管理するサブモジュール置き場
<name>/ # 各ターゲット(git submodule)
.compat-meta.json # 検証メタ情報(型 / バージョン / 最終結果)— gitignored
.cache/ # 一時データ(baseline 出力など)— gitignored
.gitmodules # 追加した submodule はここに記録
既存の vite-plugin-svelte/、language-tools/ は ルート直下のレガシー配置。このスキルでも Mode B から扱えるが、新規追加は 必ず compat/verify-svelte-compat/<name>/ に配置する。
compat/verify-svelte-compat/ 自体は git に追加するが、compat/verify-svelte-compat/.cache/ および compat/verify-svelte-compat/*/.compat-meta.json は .gitignore 対象。
全体ワークフロー
Phase 0: 引数解釈 → Mode A (add) か Mode B (update) を決定
Phase 1: ターゲット取得 → submodule 追加 or 更新
Phase 2: ターゲット分析 → ツール型 / アプリ型を判定、ビルドシステム特定
Phase 3: rsvelte NAPI ビルド → ターゲットから読める形に配置
Phase 4: 互換性検証 → ツール型: 自前テスト実行 / アプリ型: 全 .svelte 比較
Phase 5: 失敗分析と自動修正 → rsvelte 側の根本原因を特定して修正
Phase 6: 再検証ループ → Phase 4 → Phase 5 を指摘ゼロまで反復
Phase 7: メタ情報保存とコミット → .compat-meta.json 更新、コミット
Phase 0: 引数解釈と Mode 決定
ARG="${1:-}"
# .gitmodules を読み込み
SUBMODULES=$(git config --file .gitmodules --get-regexp '\.path$' | awk '{print $2}')
if [ -z "$ARG" ]; then
echo "URL またはサブモジュール名を指定してください" >&2
echo "登録済みサブモジュール:" >&2
echo "$SUBMODULES" | sed 's/^/ - /' >&2
exit 64
elif [[ "$ARG" =~ ^(https?://|git@) ]]; then
MODE="add"
URL="$ARG"
elif echo "$SUBMODULES" | grep -Fxq "$ARG"; then
MODE="update"
TARGET_PATH="$ARG"
elif MATCH=$(echo "$SUBMODULES" | awk -v n="$ARG" -F/ '$NF == n {print; exit}') && [ -n "$MATCH" ]; then
MODE="update"
TARGET_PATH="$MATCH"
else
# ユーザーに確認
echo "「$ARG」は登録済みサブモジュール名でも URL でもありません。" >&2
exit 64
fi
# 報告
echo "Mode: $MODE"
echo "Target: ${TARGET_PATH:-(new) $URL}"
ユーザーへの最初の報告:
## Phase 0: 引数解釈
- Mode: [add / update]
- Target: [URL or submodule path]
- ターゲット名(推定): <name>
<name> の推定:
- Mode A: URL の最後のセグメントから
.gitを除去(例:https://github.com/sveltejs/kit.git→kit) - Mode B: パスの basename(例:
compat/verify-svelte-compat/kit→kit、vite-plugin-svelte→vite-plugin-svelte)
Phase 1: ターゲット取得
Mode A: 新規 submodule 追加
NAME=$(basename "$URL" .git)
TARGET_PATH="compat/verify-svelte-compat/$NAME"
if [ -e "$TARGET_PATH" ]; then
echo "Error: $TARGET_PATH が既に存在します" >&2
exit 1
fi
mkdir -p compat/verify-svelte-compat
git submodule add "$URL" "$TARGET_PATH"
git submodule update --init "$TARGET_PATH"
submodule 追加後、安定タグへ checkout を試みる:
cd "$TARGET_PATH"
git fetch --tags --quiet || true
LATEST_TAG=$(git tag -l --sort=-version:refname | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+$' | head -1 || true)
if [ -n "$LATEST_TAG" ]; then
git checkout "$LATEST_TAG" --quiet
fi
COMMIT=$(git rev-parse --short HEAD)
cd -
Mode B: 既存 submodule 更新
NAME=$(basename "$TARGET_PATH")
# 現状記録(ロールバック用)
cd "$TARGET_PATH"
PREV_COMMIT=$(git rev-parse HEAD)
cd -
# .gitmodules で branch 指定があるかチェック
BRANCH=$(git config --file .gitmodules --get "submodule.${TARGET_PATH}.branch" 2>/dev/null || true)
if [ -n "$BRANCH" ]; then
# branch 指定があるなら remote の最新へ
git submodule update --remote --merge "$TARGET_PATH"
else
# branch 指定がないなら最新の安定タグへ
cd "$TARGET_PATH"
git fetch --tags --quiet
LATEST_TAG=$(git tag -l --sort=-version:refname | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+$' | head -1 || true)
if [ -n "$LATEST_TAG" ]; then
git checkout "$LATEST_TAG" --quiet
else
git fetch origin --quiet
git checkout origin/HEAD --quiet 2>/dev/null || git pull --quiet
fi
cd -
fi
cd "$TARGET_PATH"
NEW_COMMIT=$(git rev-parse --short HEAD)
cd -
echo "Updated: $PREV_COMMIT → $NEW_COMMIT"
ユーザーへの報告:
## Phase 1: ターゲット取得
- パス: $TARGET_PATH
- コミット: <PREV> → <NEW>(または初回 <NEW>)
- バージョン: <tag があれば記載>
Phase 2: ターゲット分析(ツール型 vs アプリ型)
ターゲットがどう Svelte コンパイラを使っているかを分析する。
Step 2.1: 基本情報の収集
cd "$TARGET_PATH"
# package.json から情報を抽出
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
console.log('name:', pkg.name);
console.log('version:', pkg.version);
console.log('private:', pkg.private || false);
console.log('hasWorkspaces:', !!pkg.workspaces);
console.log('scripts:', Object.keys(pkg.scripts || {}).join(','));
console.log('depsKeys:', [
...Object.keys(pkg.dependencies||{}),
...Object.keys(pkg.devDependencies||{}),
...Object.keys(pkg.peerDependencies||{}),
].join(','));
"
# 各種ファイルの存在
for f in pnpm-workspace.yaml turbo.json nx.json lerna.json vite.config.ts vite.config.js svelte.config.js svelte.config.ts; do
[ -f "$f" ] && echo "has:$f"
done
# .svelte ファイル数
SVELTE_FILES=$(find . -name '*.svelte' -not -path './node_modules/*' -not -path './.git/*' | wc -l)
echo "svelteFiles:$SVELTE_FILES"
cd -
Step 2.2: タイプ判定
以下のルールで判定する:
| 兆候 | 判定 |
|---|---|
ソース が svelte/compiler または @rsvelte/compiler を import している |
ツール型(モノレポなら モノレポ型) |
| ワークスペース構成で複数パッケージを抱える | モノレポ型 — 必要に応じて代表的なサブパッケージを 1 つ選んで以降を実行(ユーザー確認) |
.svelte ファイル多数(>= 1)かつコンパイラ import なし |
アプリ型 |
alreadySwapped: trueが出た場合、そのリポジトリは既に rsvelte 用にフォーク済み(@rsvelte/compilerを import している)。Phase 4 では swap ステップをスキップ し、代わりに Phase 4-A-0 で@rsvelte/compilerをローカル供給する。
判定スクリプト(scripts/analyze-usage.mjs を呼ぶ):
node .claude/skills/verify-svelte-compat/scripts/analyze-usage.mjs "$TARGET_PATH"
このスクリプトは JSON を出力する:
{
"name": "vite-plugin-svelte",
"type": "tool", // "tool" | "app" | "monorepo"
"svelteVersion": "^5.0.0",
"buildSystem": "vite", // "vite" | "webpack" | "rollup" | "kit" | "other"
"compilerEntryPoints": [ // ターゲット内で svelte/compiler を import している箇所
"packages/vite-plugin-svelte/src/utils/compile.js"
],
"testCommands": [ // 検出したテストコマンド
"pnpm test",
"pnpm test:unit"
],
"buildCommands": [
"pnpm build"
],
"svelteFileCount": 0,
"monorepoPackages": [] // モノレポなら主要なサブパス
}
Step 2.3: ユーザーへの確認(モノレポなど曖昧な場合のみ)
明確に tool / app と判定できた場合は確認なしで Phase 3 へ。 モノレポや判定不能の場合のみ:
## Phase 2: ターゲット分析(要確認)
- 名前: $NAME
- 検出タイプ: [tool / app / monorepo / unknown]
- ビルドシステム: [vite / webpack / kit / ...]
- Svelte バージョン: ^X.Y.Z
- .svelte ファイル数: N
- 検出したテストコマンド: [...]
→ 検証範囲を確認させてください:
1. 全体(推奨ルート)
2. サブパッケージを限定(モノレポの場合: <候補>)
3. アプリ型として扱う / ツール型として扱う(判定が間違っている場合)
明確な場合の自動報告:
## Phase 2: ターゲット分析
- タイプ: tool / app
- ビルドシステム: ...
- Svelte バージョン: ...
- 検証戦略: [tool: 自前テストスイート実行 / app: .svelte 全件 semantic 比較]
Phase 3: rsvelte NAPI と canonicalizer のビルド + 配置
# rsvelte NAPI バインディング + canonicalize_js を同時にビルド
.claude/skills/verify-svelte-compat/scripts/build-rsvelte.sh "$TARGET_PATH"
cargo build --release --bin canonicalize_js
build-rsvelte.sh の挙動:
cargo build --release --features napi --lib- プラットフォームに応じた
.nodeファイル名を計算 svelte/${NODE_NAME}と${TARGET_PATH}/.rsvelte/${NODE_NAME}の両方にコピー
canonicalize_js は Phase 4-B での semantic 比較に必要。これがないと naive な whitespace canonicalizer に fallback し、formatting だけが違うケースを偽陽性で拾ってしまう(実測: vite-plugin-svelte で 25 件 → 9 件に減)。
rsvelte の公開 API は
compile、compileModule、svelte2tsxなどsvelte/compilerの主要 export と互換である(src/napi.rs参照)。
Phase 4: 互換性検証
タイプによって戦略を分岐する。
4-A: ツール型の検証
ツール型ターゲットは「自前のテストスイート」を持つ。これを 公式 Svelte で実行 → rsvelte で実行 → 結果を比較 する。
Step 4-A-0: rsvelte コンパイラの提供方法を決定
alreadySwapped の値で方針を決める:
alreadySwapped: true(ターゲットが既に@rsvelte/compilerを import) → ローカル wrapper パッケージを生成し pnpm overrides で上書きする:node .claude/skills/verify-svelte-compat/scripts/provide-rsvelte-compiler.mjs \ --target "$TARGET_PATH" \ --rsvelte-binding "$(pwd)/${TARGET_PATH}/.rsvelte/${NODE_NAME}"これは
compat/verify-svelte-compat/.cache/rsvelte-compiler-pkg/に最小 npm パッケージを作り、ターゲットpackage.jsonのpnpm.overrides['@rsvelte/compiler']を file: 参照に書き換える(ベースラインのため public 版が要る場合は事前にコピー保存)。alreadySwapped: false(ターゲットは公式svelte/compilerのみ) → Step 4-A-2 の loader hook で実行時にすり替える。
Step 4-A-1: 依存関係インストール & ベースライン確立
cd "$TARGET_PATH"
pnpm install --frozen-lockfile 2>/dev/null || pnpm install || npm install
INSTALL_EXIT=$?
cd -
# 公式 Svelte でテスト実行(baseline)
mkdir -p compat/verify-svelte-compat/.cache
BASELINE_LOG="compat/verify-svelte-compat/.cache/${NAME}-baseline.log"
if [ "$INSTALL_EXIT" -eq 0 ]; then
( cd "$TARGET_PATH" && pnpm test ) > "$BASELINE_LOG" 2>&1
BASELINE_EXIT=$?
else
BASELINE_EXIT=1
fi
Install ブロック時のフォールバック:
ターゲット側のフォーク不整合(例: vite-plugin-svelte の rsvelte ブランチで e2e-tests パッケージが @sveltejs/vite-plugin-svelte を workspace:^ で参照したまま改名漏れになっている)など、ターゲット由来の install 失敗が起こり得る。
その場合の方針:
--filterで問題パッケージを除外して再試行(例:pnpm install --filter '!@sveltejs/vite-plugin-svelte')- それでも失敗する場合は Phase 4-A をスキップして Phase 4-B にフォールバック。Phase 4-B は pnpm install を必要としない
- ユーザーに「ターゲット側の問題で Phase 4-A は実行不能、Phase 4-B のみで検証する」と明示
ターゲット側の修正は このスキルの責務外 — フォーク所有者にエスカレーションする。
Step 4-A-2: コンパイラ swap
ターゲット内部で svelte/compiler を import している箇所を、rsvelte の NAPI バインディングに置き換える。
最も低侵襲なのは Node.js の loader / require フック を使う方法:
# ターゲットの実行コマンドの先頭に NODE_OPTIONS で hook を仕込む
node .claude/skills/verify-svelte-compat/scripts/swap-compiler.mjs \
--target "$TARGET_PATH" \
--rsvelte-binding "$(pwd)/${TARGET_PATH}/.rsvelte/${NODE_NAME}"
swap-compiler.mjs の仕事:
- ターゲット直下に
.rsvelte/loader.mjsを生成(require フック) - ターゲットの
package.jsonのscripts.testをラップしてNODE_OPTIONS="--import ./.rsvelte/loader.mjs"を付与(一時的) - または、より確実な方法として
pnpmのオーバーライドを使う:// package.json patch (一時的に書き戻す) "pnpm": { "overrides": { "svelte": "file:../<wrapper-pkg>" // svelte/compiler を rsvelte に差し替えたラッパーパッケージ } }
既に
rsvelte用フォークになっている submodule(vite-plugin-svelteのrsvelteブランチ等)はこのステップをスキップ。.rsvelte/.swap-appliedのような sentinel ファイルで判定する。
Step 4-A-3: rsvelte でテスト実行
RSVELTE_LOG="compat/verify-svelte-compat/.cache/${NAME}-rsvelte.log"
( cd "$TARGET_PATH" && pnpm test ) > "$RSVELTE_LOG" 2>&1
RSVELTE_EXIT=$?
Step 4-A-4: 結果比較
# 終了コード一致 + ログのテスト結果セクション一致
diff "$BASELINE_LOG" "$RSVELTE_LOG" > "compat/verify-svelte-compat/.cache/${NAME}-diff.log" || true
判定:
- baseline と rsvelte の両方がパス & ログの差分が無視可能(タイムスタンプなどのみ)→ PASS
- baseline がパスで rsvelte が失敗 → REGRESSION(rsvelte バグ候補 → Phase 5 へ)
- baseline 自体が失敗 → ターゲット側の問題(Phase 5 で修正対象外、ユーザーに報告)
4-B: アプリ型の検証
アプリ型は「全 .svelte ファイルを公式 / rsvelte の両方でコンパイルし、出力を semantic に比較」する。既存の scripts/ecosystem/test-real-world-semantic.mjs のロジックを応用する。
Step 4-B-1: 全 .svelte ファイル列挙
node .claude/skills/verify-svelte-compat/scripts/compare-app.mjs \
--target "$TARGET_PATH" \
--rsvelte-binding "$(pwd)/${TARGET_PATH}/.rsvelte/${NODE_NAME}" \
--output "compat/verify-svelte-compat/.cache/${NAME}-app-report.json"
compare-app.mjs の仕事:
- ターゲット配下の
.svelteファイルを列挙(node_modules、.git、ビルド出力ディレクトリは除外) - 各ファイルを
client/serverの両モードで両コンパイラに通す - 結果を JSON で出力:
{ "totalFiles": 1234, "bothCompiled": 1230, "semanticEqual": 1225, "semanticDiff": 5, "rsvelteError": 4, "officialError": 0, "details": [ { "file": "src/Foo.svelte", "category": "semantic-diff", "snippet": "..." } ] }
semantic 比較は target/release/canonicalize_js(既存)または OXC の parse → codegen 経由で行う。なければビルドする:
cargo build --release --bin canonicalize_js 2>/dev/null || true
Step 4-B-2: 任意:ビルド検証
ターゲットがビルドコマンドを持っている場合(pnpm build が成功する場合)、rsvelte でも同じビルドが通るか確認する:
# baseline build
( cd "$TARGET_PATH" && pnpm build ) > "compat/verify-svelte-compat/.cache/${NAME}-build-baseline.log" 2>&1
# rsvelte build (compiler swap 適用)
( cd "$TARGET_PATH" && NODE_OPTIONS="--import ./.rsvelte/loader.mjs" pnpm build ) \
> "compat/verify-svelte-compat/.cache/${NAME}-build-rsvelte.log" 2>&1
両方が exit code 0 で、生成された JS の semantic 差分が無視可能なら PASS。
ビルド検証はオプションで、コストが高い場合(initial install + build に 数分以上かかる)はユーザーに確認する。
Phase 5: 失敗分析と自動修正
Phase 4 で検出した失敗を rsvelte 側の根本原因 に紐付け、修正する。
Step 5.1: 失敗のカテゴライズ
1. パースエラー(rsvelte だけ failure)
→ src/compiler/phases/1_parse/ の問題
2. 意味解析エラー(rsvelte だけ warning / error / 出力 NaN)
→ src/compiler/phases/2_analyze/ の問題
3. コード生成差分(両方コンパイル成功 / 出力が違う)
→ src/compiler/phases/3_transform/ の問題
4. CSS スコーピング差分
→ src/compiler/phases/3_transform/css/ の問題
5. ランタイム差分(compile は通るがテストが落ちる)
→ 多くは transform 問題、一部 analyze 問題
Step 5.2: 最小再現の作成
問題のあった .svelte ファイル / テストケースから、rsvelte 側の fixture テストに転記して再現させる:
tests/fixtures/{category}/<unique-name>/
input.svelte # 元ソースから抽出した最小ケース
_config.json # コンパイルオプション
expected/ # 公式 Svelte の出力(参照)
scripts/fixtures/generate-fixtures.mjs を活用して expected を生成する。
Step 5.3: 自動修正
公式実装(svelte/packages/svelte/src/compiler/)と rsvelte 実装(src/compiler/)を Agent で diff レビューさせ、原因箇所を特定して修正する。
Agent(subagent_type="general-purpose"):
prompt: |
rsvelte(公式 Svelte コンパイラの Rust ポート)で以下の互換性回帰が見つかった。
根本原因を特定し、rsvelte 側を修正してほしい。
## 失敗ケース
[問題のあった .svelte ファイル / テストケースの全文]
## 公式 Svelte の出力
[baseline 出力]
## rsvelte の出力(または失敗内容)
[rsvelte 出力 or エラー]
## 失敗カテゴリ
[parse / analyze / transform / css / runtime]
## 公式実装の対応箇所
[想定される svelte/packages/svelte/src/compiler/ 配下の関連ファイル]
## 手順
1. 公式実装と rsvelte 実装の該当ファイルを比較
2. 差分を特定
3. rsvelte 側を修正(公式実装をミラーする)
4. 該当 fixture テストで検証
5. 全 cargo test --release を実行して回帰がないことを確認
## 制約
- ターゲットリポジトリ自体は変更しない
- 公式実装にない独自抽象を新規導入しない
- 修正後 cargo fmt && cargo clippy --all-targets --all-features -- -D warnings がクリーンであること
Step 5.4: 修正の妥当性チェック
修正後、以下を確認する:
cargo fmt --all
cargo clippy --all-targets --all-features -- -D warnings
cargo test --release --test compatibility_report # 互換性レポート
cargo test --release # 全テスト
いずれかが失敗したら、その修正は採用しない(revert してユーザーに報告)。
Phase 6: 再検証ループ
Phase 4 → Phase 5 を反復する。
loop:
Phase 4 を再実行
失敗ゼロ → break
Phase 5 で修正
反復回数 += 1
反復回数 >= 5 → ユーザーに「残った失敗を別途 issue 化して進めますか?」と確認
各反復で以下を表示:
反復 N 回目:
- 失敗総数: X → Y(前回比 -Z)
- 残カテゴリ: parse=N, analyze=N, transform=N, css=N, runtime=N
- 直近の修正: <一行サマリ>
反復終了条件
- すべての Critical(テスト失敗 / コンパイル失敗)が解消
- Major(出力差分は出るが意味的に同等)以下の指摘について、ユーザー承認のもと「許容差分」として記録(
.compat-meta.jsonに書き込む)
Phase 7: メタ情報保存とコミット
Step 7.1: .compat-meta.json の更新
{
"name": "vite-plugin-svelte",
"type": "tool",
"lastVerifiedAt": "2026-05-02T12:34:56Z",
"targetCommit": "772fdf542b09",
"rsvelteCommit": "<HEAD>",
"result": "pass",
"summary": {
"tests": { "total": 234, "passed": 234, "failed": 0 },
"iterations": 1,
"fixesApplied": []
},
"knownDifferences": []
}
これは compat/verify-svelte-compat/<name>/.compat-meta.json に保存し、.gitignore 対象にする。
代わりにルートの compat/verify-svelte-compat/index.json に 要約のみ を git に含めて履歴にする:
[
{
"name": "vite-plugin-svelte",
"type": "tool",
"lastVerifiedAt": "2026-05-02",
"result": "pass",
"rsvelteCommit": "..."
}
]
Step 7.2: ターゲット側に注入した変更の cleanup
provide-rsvelte-compiler.mjs は ターゲットの package.json に pnpm.overrides['@rsvelte/compiler'] を注入する。検証完了後は 必ず revert する:
( cd "$TARGET_PATH" && git checkout package.json )
# pnpm-lock.yaml も install 後に書き換わるので revert
( cd "$TARGET_PATH" && git checkout pnpm-lock.yaml 2>/dev/null || true )
compat/verify-svelte-compat/<name>/.rsvelte/ と compat/verify-svelte-compat/.cache/ は .gitignore 対象なので残置 OK。
Step 7.3: コミット
修正が rsvelte 側に入っていれば、論理単位でコミット:
# 修正コミット(既に Phase 5 で個別にコミットされている想定)
# 最後に compat/verify-svelte-compat/ 関連の変更をまとめて:
git add compat/verify-svelte-compat/index.json .gitmodules compat/verify-svelte-compat/<name>
git commit -m "compat: verify <name> against rsvelte
- Mode: <add|update>
- Target commit: <SHA>
- Result: pass (X/X tests)
- Iterations: N
- Fixes: <一行サマリ>"
git push
ヘルパースクリプト
このスキルは以下のヘルパーを使う:
| パス | 役割 |
|---|---|
.claude/skills/verify-svelte-compat/scripts/analyze-usage.mjs |
ターゲットを分析して JSON を出力(Phase 2) |
.claude/skills/verify-svelte-compat/scripts/build-rsvelte.sh |
rsvelte NAPI をビルドして配置(Phase 3) |
.claude/skills/verify-svelte-compat/scripts/provide-rsvelte-compiler.mjs |
@rsvelte/compiler 用ローカル wrapper を作成 + pnpm overrides 注入(Phase 4-A-0) |
.claude/skills/verify-svelte-compat/scripts/swap-compiler.mjs |
ターゲットの Svelte コンパイラを rsvelte に差し替え(Phase 4-A-2) |
.claude/skills/verify-svelte-compat/scripts/compare-app.mjs |
全 .svelte ファイルを両コンパイラで比較(Phase 4-B) |
各スクリプトは単独でも実行可能(手動デバッグ用)。
クイックリファレンス
# 新規追加
/verify-svelte-compat https://github.com/sveltejs/kit
# 既存サブモジュール更新検証
/verify-svelte-compat vite-plugin-svelte
/verify-svelte-compat language-tools
# 任意: 個別ヘルパーの直接実行
node .claude/skills/verify-svelte-compat/scripts/analyze-usage.mjs <path>
.claude/skills/verify-svelte-compat/scripts/build-rsvelte.sh
node .claude/skills/verify-svelte-compat/scripts/compare-app.mjs --target <path> --output <json>
ワークフロー(実行時)
ユーザーが /verify-svelte-compat $ARGUMENTS を呼んだら:
- Phase 0: 引数を解釈し、Mode A / B を決定
- Phase 1: submodule を追加 / 更新
- Phase 2: ターゲット分析 → ツール型 / アプリ型を判定(モノレポ等の曖昧ケースのみユーザー確認)
- Phase 3: rsvelte NAPI ビルド → ターゲットに配置
- Phase 4: 互換性検証実行
- Phase 5: 失敗を rsvelte 側で自動修正
- Phase 6: 4 → 5 を反復(5 回まで自動、その後はユーザー確認)
- Phase 7:
.compat-meta.json更新 → コミット
各フェーズの結果は段階的に報告する。Phase 5 の修正コミットは個別に行い、最終 Phase 7 でメタ情報変更だけをまとめてコミットする。
心構え
- 公式 Svelte 出力が正: 差分が見つかったら原則 rsvelte 側を直す
- ターゲットには触らない: 例外は「公式 Svelte 自体のバグでターゲット側も追従済」のような明確なケースのみ。その場合もユーザー確認必須
- ベースラインが落ちる場合は別問題: Phase 4-A の baseline (公式 Svelte でも) がそもそも失敗している場合、それはこのスキルの対象外。「baseline 失敗のため検証不可」として報告し、ターゲット側の問題として切り分ける
- 修正は最小限: 1 つの失敗カテゴリにつき 1 つの修正コミット。リファクタリングや無関係な修正を混ぜない
- rsvelte 側の clippy / fmt / 全テスト pass を維持: Phase 5 の修正は必ず Step 5.4 のチェックを通してからコミット
Source: baseballyama/rsvelte — distributed by TomeVault.