diff --git a/.claude/commands/upstream-merge.md b/.claude/commands/upstream-merge.md deleted file mode 100644 index b8f04b64f75..00000000000 --- a/.claude/commands/upstream-merge.md +++ /dev/null @@ -1,521 +0,0 @@ -# /upstream:merge - Interactive Upstream Merge Workflow - -半自動化されたupstream scratch-editor mergeワークフローを提供します。 - -## 使い方 - -``` -/upstream:merge -``` - -対話型で段階的にmerge作業を進めます。 - ---- - -## Workflow - -### Phase 1: Prerequisites Check - -1. **Git状態確認** - - Working directoryがcleanか確認 - - Current branchが`develop`か確認 - - Upstream remoteが設定されているか確認 - -2. **Merge履歴読み込み** - - `.upstream-merge-history.json`を読み込み - - 前回mergeのcommit IDを取得 - - ファイルが存在しない場合はエラー - -3. **Upstream差分確認** - ```bash - git fetch -p upstream develop - git log ..upstream/develop --oneline --format="%h %s" - ``` - - 新しいcommit数を表示 - - 最新10件のcommit messageを表示 - -4. **ユーザー確認** - - "X commits を merge します。続行しますか?" - - Yes/No/View all commits の選択肢 - -5. **ドキュメント保存先確認** - - デフォルト: `notes/upstream/merge-YYYY-MM/` - - ユーザーにパスを確認・変更可能 - - ディレクトリ作成 - ---- - -### Phase 2: Merge Branch Creation - -1. **ブランチ作成** - ```bash - DATE=$(date +%Y-%m) - git checkout -b feat/upstream-merge-$DATE - ``` - -2. **進捗管理ファイル初期化** - - `/progress.md` 作成 - - Timestamp, commit count, branch nameを記録 - ---- - -### Phase 3: Merge Execution - -1. **Merge実行** - ```bash - git merge upstream/develop --no-commit --no-ff - ``` - -2. **Conflict検出** - ```bash - git status --porcelain - ``` - - `UU` で始まる行 = unmerged conflicts - -3. **Known Conflicts ガイダンス表示** - - **gui.ts conflict検出時:** - ``` - ✓ gui.ts conflict detected (EXPECTED) - - Resolution guide: - 1. Open: packages/scratch-gui/src/reducers/gui.ts - 2. Look for these markers: - // === Smalruby: Start of Redux state registry === - import {smalrubyReducers, smalrubyInitialState} from './smalruby-registry'; - // === Smalruby: End of Redux state registry === - - 3. In buildInitialState(), keep: - // === Smalruby: Start of initial state === - ...smalrubyInitialState, - // === Smalruby: End of initial state === - - 4. In combineReducers(), keep: - // === Smalruby: Start of reducers === - ...smalrubyReducers, - // === Smalruby: End of reducers === - - 5. Accept all other upstream changes - - Reference: packages/scratch-gui/src/reducers/smalruby-registry.ts - ``` - - **extension-manager.js conflict検出時:** - ``` - ✓ extension-manager.js conflict detected (EXPECTED) - - Resolution guide: - 1. Open: packages/scratch-vm/src/extension-support/extension-manager.js - 2. Look for these markers: - // === Smalruby: Start of extension registration === - const registerSmalrubyExtensions = require('./smalruby-extensions'); - registerSmalrubyExtensions(builtinExtensions); - // === Smalruby: End of extension registration === - - 3. Keep the Smalruby registration block - 4. Accept upstream changes for builtinExtensions object - - Reference: packages/scratch-vm/src/extension-support/smalruby-extensions.js - ``` - - **package-lock.json conflict検出時:** - ``` - ✓ package-lock.json conflict detected (EXPECTED) - - Resolution: - 1. Accept upstream package.json completely - 2. Regenerate lock file: - docker compose run --rm app npm install - - This will merge dependency trees correctly. - ``` - -4. **Unexpected Conflicts警告** - - Known conflicts以外が見つかった場合、**WARNING**表示 - - ファイルリストを表示 - - ユーザーに手動解決を促す - -5. **Conflict解決待機** - ``` - Conflicts to resolve: - - [EXPECTED] packages/scratch-gui/src/reducers/gui.ts - - [EXPECTED] packages/scratch-vm/src/extension-support/extension-manager.js - - [WARNING] packages/scratch-gui/src/components/unknown-file.jsx - - Resolve conflicts manually, then press Enter to continue... - ``` - -6. **解決確認** - - Enterキー押下後、`git status`で確認 - - まだconflictが残っている場合は警告 - ---- - -### Phase 4: Post-Merge Validation - -#### Step 1: Commit Merge - -1. **Merge commit作成** - ```bash - git add . - git commit -m "feat: merge upstream scratch-editor changes (X commits) - - Merged X commits from upstream develop branch. - - Co-Authored-By: Claude Sonnet 4.5 " - ``` - -2. **Merge commit hash取得** - - 後で`.upstream-merge-history.json`更新に使用 - -#### Step 2: Lint Check - -1. **実行** - ```bash - docker compose run --rm app npm run lint - ``` - -2. **結果判定** - - **Pass**: 次へ進む - - **Fail**: エラー内容表示 → ユーザーに修正を促す → 修正後Enter - -3. **Lint通過後、Push推奨** - ``` - ✓ Linting passed - - 💡 Recommended: Push now to start CI in parallel - - Suggested command: - git push -u origin feat/upstream-merge-YYYY-MM - - Push now? [Y/n] - ``` - - - Yesの場合: git pushを実行 - - Noの場合: 次へ進む(後でpush可能) - -#### Step 3: Build Check - -1. **実行** - ```bash - docker compose run --rm app npm run build:dev - ``` - -2. **結果判定** - - **Pass**: 次へ進む - - **Fail**: エラー表示 → 修正待機 - -#### Step 4: Unit Tests - -1. **実行確認** - ``` - Run unit tests? (This may take 1-2 minutes) - [Y/n/skip] - ``` - -2. **実行** - ```bash - docker compose run --rm app npm run test:unit - ``` - -3. **結果記録** - - Pass/failをprogress.mdに記録 - - Failの場合は詳細をtest-results.mdに記録 - -#### Step 5: Integration Tests - -1. **テスト選択** - ``` - Run integration tests? - [1] Smalruby-specific only (fast, ~30 sec) - RECOMMENDED - [2] All tests (slow, ~5-10 min) - [3] Skip (rely on CI) - - Choice: - ``` - -2. **Smalruby-specific tests (option 1)** - ```bash - cd packages/scratch-gui - npm exec jest test/integration/smalruby-tutorials.test.js - npm exec jest test/integration/block-display-modal.test.js - ``` - -3. **All tests (option 2)** - ```bash - docker compose run --rm app npm run test:integration - ``` - -4. **結果記録** - - progress.mdとtest-results.mdに記録 - -#### Step 6: CI Status Check - -1. **CI URL表示** - ``` - Check CI status: - https://github.com/smalruby/smalruby3-editor/actions - - Are all CI checks passing? [Y/n/pending] - ``` - -2. **選択肢** - - **Y**: 次へ進む - - **n**: CI failの詳細を記録、修正が必要 - - **pending**: 待機中、後で確認 - ---- - -### Phase 5: Documentation Generation - -1. **conflict-resolutions.md 生成** - ```markdown - # Conflict Resolutions - YYYY-MM Upstream Merge - - ## Files with Conflicts - - ### Known Conflicts (Resolved) - - [x] packages/scratch-gui/src/reducers/gui.ts - - Resolution: Kept Smalruby registry pattern - - [x] packages/scratch-vm/src/extension-support/extension-manager.js - - Resolution: Kept Smalruby extension registration - - ### Unexpected Conflicts (Manual Resolution Required) - - [x] packages/scratch-gui/src/components/unknown-file.jsx - - Resolution: [User will describe] - ``` - - **ユーザーに確認:** - - Unexpected conflictがあった場合、解決方法を入力してもらう - -2. **test-results.md 生成** - ```markdown - # Test Results - YYYY-MM Upstream Merge - - ## Lint - ✅ Passed - - ## Build - ✅ Passed - - ## Unit Tests - ✅ Passed (X tests, Y warnings) - - Warnings: - - smalrubot_s1: unused variable 'e' (pre-existing) - - ## Integration Tests - ✅ Passed (Smalruby-specific: 3/3) - - - smalruby-tutorials.test.js: 3/3 ✅ - - block-display-modal.test.js: 7/7 ✅ - - ## CI Status - ✅ All checks passed - ``` - -3. **progress.md 更新** - - 各ステップの完了時刻を記録 - - 最終status = "Completed" - ---- - -### Phase 6: Merge History Update - -1. **`.upstream-merge-history.json` 更新** - ```json - { - "lastMerge": { - "date": "2026-02-XX", - "upstreamCommit": "", - "smalrubyCommit": "", - "mergeCommit": "", - "notes": "X commits merged from upstream develop" - }, - "previousMerges": [ - { - "date": "2026-02-14", - "upstreamCommit": "5f063605b67927f01647f56a8abf28b972a292bd", - ... - } - ] - } - ``` - -2. **Commit and push** - ```bash - git add .upstream-merge-history.json - git commit -m "chore: update upstream merge history" - git push - ``` - ---- - -### Phase 7: PR Creation - -1. **PR body自動生成** - ```markdown - ## Summary - - Merged X commits from upstream scratch-editor `develop` branch. - - **Upstream Commit Range**: .. - - ## Major Upstream Changes - - [Top 10 commit messages from git log] - - ## Conflicts Resolved - - ### Known Conflicts - - ✅ gui.ts - Kept Smalruby registry pattern - - ✅ extension-manager.js - Kept Smalruby extension registration - - ✅ package-lock.json - Regenerated with npm install - - ### Unexpected Conflicts - [List if any] - - ## Test Results - - - ✅ Linting passed - - ✅ Build succeeded - - ✅ Unit tests: X/Y passed - - ✅ Integration tests: Smalruby-specific (3/3 passed) - - ✅ CI: All checks passing - - ## Documentation - - Merge documentation: `notes/upstream/merge-YYYY-MM/` - - ## Manual Testing Checklist - - Before merging this PR, verify: - - [ ] Ruby code editor loads correctly - - [ ] Ruby-to-blocks conversion works - - [ ] Google Drive integration works - - [ ] Custom extensions load (microbitMore, Koshien) - - [ ] Block Display modal filters correctly - - [ ] No console errors or warnings - - --- - - 🤖 Generated with `/upstream:merge` command - ``` - -2. **PR作成確認** - ``` - Create PR now? [Y/n] - - Title: feat: upstream merge YYYY-MM (X commits) - Base: develop - Head: feat/upstream-merge-YYYY-MM - ``` - -3. **PR作成** - ```bash - gh pr create \ - --repo smalruby/smalruby3-editor \ - --base develop \ - --head feat/upstream-merge-YYYY-MM \ - --title "feat: upstream merge YYYY-MM (X commits)" \ - --body-file /tmp/pr-body.md - ``` - -4. **完了メッセージ** - ``` - ✅ Upstream merge completed successfully! - - PR created: https://github.com/smalruby/smalruby3-editor/pull/XXX - - Next steps: - 1. Monitor CI: https://github.com/smalruby/smalruby3-editor/actions - 2. Review changes in PR - 3. Complete manual testing checklist - 4. Merge when ready - - Documentation: notes/upstream/merge-YYYY-MM/ - - progress.md - - conflict-resolutions.md - - test-results.md - - Merge history updated: .upstream-merge-history.json - ``` - ---- - -## Error Handling - -### Prerequisites Failure - -``` -✗ Prerequisites check failed - -Issues: -- Working directory is not clean (3 modified files) -- Current branch is 'feature-branch' (expected: develop) - -Fix these issues and run /upstream:merge again. -``` - -### Unresolved Conflicts - -``` -⚠ Conflicts still exist after resolution attempt - -Files with unresolved conflicts: -- packages/scratch-gui/src/components/new-file.jsx - -Run `git status` to see details. -Resolve manually, then run: - git add . - /upstream:merge --continue - -(Note: --continue not implemented yet, just continue the workflow) -``` - -### Test Failure - -``` -✗ Integration tests failed - -Failed tests: -- block-display-modal.test.js: "should filter blocks correctly" (timeout) - -Options: -[1] View test output -[2] Skip and document (not recommended) -[3] Fix and re-run - -Choice: -``` - -### CI Failure - -``` -⚠ CI checks are failing - -Failed checks: -- Integration Tests (chromium): 2 tests failed -- Build (production): Webpack error - -View logs: https://github.com/smalruby/smalruby3-editor/actions/runs/XXXXX - -Continue with PR creation anyway? [y/N] -``` - ---- - -## Important Notes - -- **Half-automated**: User intervention required for conflict resolution -- **Progress tracking**: All actions logged in notes/upstream/merge-YYYY-MM/ -- **CI-parallel**: Recommended to push after lint to run CI in parallel -- **No auto-resolve**: Conflicts must be resolved manually following guidance -- **Revert-friendly**: All steps can be reverted with `git reset` or `git revert` - ---- - -## Command Implementation - -This command guides the user through the entire upstream merge workflow interactively, -providing clear instructions at each step and automatically generating documentation. diff --git a/.claude/rules/code-style.md b/.claude/rules/code-style.md index 4b0a06a19d0..b4f96735d6c 100644 --- a/.claude/rules/code-style.md +++ b/.claude/rules/code-style.md @@ -57,6 +57,25 @@ export default MyComponent; - Follow existing reducer/action patterns for consistency - Keep state shape flat when possible +## Smalruby Marker Comments + +upstream のファイルに Smalruby 固有のコードを追加する際は、必ず **マーカーコメント** で囲む。 + +```javascript +// === Smalruby: Start of <機能名> === +// ... Smalruby 固有のコード ... +// === Smalruby: End of <機能名> === +``` + +- Start と End は必ずペアにする +- `<機能名>` は英語で、何の機能かわかる名前にする +- ファイル全体が Smalruby 固有の場合はファイル冒頭に `// === Smalruby: This file is Smalruby-specific (<説明>) ===` +- マーカーを追加・削除したら、該当パッケージの `development.md` のマーカー一覧を更新する + +詳細は各パッケージの development.md を参照: +- `.claude/rules/scratch-gui/development.md` — scratch-gui のマーカー一覧 +- `.claude/rules/scratch-vm/development.md` — scratch-vm のマーカー一覧 + ## Documentation ### JSDoc Comments diff --git a/.claude/rules/scratch-gui/development.md b/.claude/rules/scratch-gui/development.md index d63659bc519..f491bafff6f 100644 --- a/.claude/rules/scratch-gui/development.md +++ b/.claude/rules/scratch-gui/development.md @@ -221,6 +221,61 @@ The GUI is built as a PWA. Assets and manifest are generated by: - `webpack-pwa-manifest` plugin (build) - `workbox-webpack-plugin` (build) +## Smalruby Marker Blocks + +Smalruby のカスタムコードは upstream ファイルの中に **マーカーコメント** で囲んで配置する。 +upstream merge 時にコンフリクトを解決しやすくするための仕組み。 + +### マーカーの書式 + +```javascript +// === Smalruby: Start of <機能名> === +// ... Smalruby 固有のコード ... +// === Smalruby: End of <機能名> === +``` + +ファイル全体が Smalruby 固有の場合: +```javascript +// === Smalruby: This file is Smalruby-specific (<説明>) === +``` + +### ルール + +1. **upstream ファイルに Smalruby コードを追加するときは必ずマーカーで囲む** +2. **マーカー内のコードだけを変更する** — マーカー外は upstream の管轄 +3. **新しいマーカーを追加したら、このセクションに記載する** +4. **マーカーを削除する場合は、このセクションからも削除する** + +### 現在のマーカー一覧 + +| ファイル | 機能名 | 説明 | +|----------|--------|------| +| `src/reducers/gui.ts` | Redux state registry | Smalruby reducer の import | +| `src/reducers/gui.ts` | initial state | Smalruby 初期 state の展開 | +| `src/reducers/gui.ts` | reducers | Smalruby reducer の登録 | +| `src/containers/cards.jsx` | tutorial glow animation | チュートリアルのハイライトアニメーション | +| `src/containers/connection-modal.jsx` | meshV2 initial step feature | Mesh v2 接続初期ステップ | +| `src/containers/connection-modal.jsx` | meshV2 connected message feature | Mesh v2 接続済みメッセージ | +| `src/containers/connection-modal.jsx` | meshV2 back button feature | Mesh v2 戻るボタン | +| `src/components/cards/cards.jsx` | tutorial glow animation | チュートリアル UI のハイライト | +| `src/components/connection-modal/connection-modal.jsx` | network filter detection feature | ネットワークフィルター検出 | +| `src/components/connection-modal/connection-modal.jsx` | meshV2 initial step feature | Mesh v2 初期ステップ UI | +| `src/components/connection-modal/connected-step.jsx` | meshV2 connected message feature | Mesh v2 接続済みステップ UI | +| `src/components/gui/gui.jsx` | Redux action props prevention | Redux action props の伝播防止 | + +### Smalruby 固有ファイル(ファイル全体がマーカー) + +| ファイル | 説明 | +|----------|------| +| `src/components/connection-modal/mesh-v2-initial-step.jsx` | Mesh v2 初期接続ステップコンポーネント | +| `src/components/connection-modal/mesh-v2-network-filtered-step.jsx` | Mesh v2 ネットワークフィルター検出コンポーネント | +| `src/reducers/smalruby-registry.ts` | Smalruby reducer/state の一括エクスポート | + +### 関連ファイル + +マーカーで囲まれたコードが参照するファイル: +- `src/reducers/smalruby-registry.ts` — gui.ts のマーカーから参照 + ## Development Notes - The webpack config loads environment variables from monorepo root `.env` file diff --git a/.claude/rules/scratch-vm/development.md b/.claude/rules/scratch-vm/development.md index 59acda62a35..03cc0500ed1 100644 --- a/.claude/rules/scratch-vm/development.md +++ b/.claude/rules/scratch-vm/development.md @@ -194,6 +194,37 @@ The mesh v2 extension uses AWS AppSync for real-time collaboration: 5. **Only after all tests pass and lint is clean**, commit and push. +## Smalruby Marker Blocks + +Smalruby のカスタムコードは upstream ファイルの中に **マーカーコメント** で囲んで配置する。 +upstream merge 時にコンフリクトを解決しやすくするための仕組み。 + +### マーカーの書式 + +```javascript +// === Smalruby: Start of <機能名> === +// ... Smalruby 固有のコード ... +// === Smalruby: End of <機能名> === +``` + +### ルール + +1. **upstream ファイルに Smalruby コードを追加するときは必ずマーカーで囲む** +2. **マーカー内のコードだけを変更する** — マーカー外は upstream の管轄 +3. **新しいマーカーを追加したら、このセクションに記載する** +4. **マーカーを削除する場合は、このセクションからも削除する** + +### 現在のマーカー一覧 + +| ファイル | 機能名 | 説明 | +|----------|--------|------| +| `src/extension-support/extension-manager.js` | extension registration | Smalruby 拡張機能の登録 | + +### 関連ファイル + +マーカーで囲まれたコードが参照するファイル: +- `src/extension-support/smalruby-extensions.js` — extension-manager.js のマーカーから参照 + ## Development Notes - The VM exports both Node.js and browser builds diff --git a/.claude/skills/upstream-merge/SKILL.md b/.claude/skills/upstream-merge/SKILL.md new file mode 100644 index 00000000000..3118cb2f0dc --- /dev/null +++ b/.claude/skills/upstream-merge/SKILL.md @@ -0,0 +1,47 @@ +--- +name: upstream-merge +description: "/upstream:merge - Interactive Upstream Merge Workflow. upstream scratch-editor の変更を Smalruby に取り込む半自動ワークフロー。" +--- + +# /upstream:merge - Interactive Upstream Merge Workflow + +upstream scratch-editor の変更を Smalruby fork に取り込む半自動ワークフロー。 + +## ワークフロー全体像 + +| Phase | ファイル | 内容 | +|-------|----------|------| +| 1 | `phase1-prepare.md` | Prerequisites確認 → ブランチ作成 → マージ実行 | +| 2 | `phase2-conflicts.md` | コンフリクト解決ガイド(既知パターン + ガイダンス) | +| 3 | `phase3-validation.md` | コミット → lint → build → テスト → CI | +| 4 | `phase4-finalize.md` | merge history更新 → PR作成 → 手動テスト | + +リファレンス(必要時に読み込む): + +| ファイル | 内容 | +|----------|------| +| `reference-api-migration.md` | ScratchBlocks API 変更一覧 | +| `reference-test-patterns.md` | テスト修正の既知パターン集 | + +## 進め方 + +1. Phase 1 から順番に実行する +2. 各フェーズの開始時に該当ファイルを読み込む +3. コンフリクト解決やテスト修正で詰まったら、リファレンスファイルを読み込む +4. 各フェーズが完了したら次のフェーズに進む + +## 絶対に守るルール + +- **`git add .` は使わない** — `git add -u` (tracked files のみ) を使う +- **`notes/` は絶対にコミットしない** — `.gitignore` で除外済みだが、明示パス指定や `-f` で追加されうる +- **ファイル指定で add** — merge history 更新時は `git add .upstream-merge-history.json` のみ +- **PR マージは `--merge`** — squash merge は禁止。`gh pr merge --merge --delete-branch` +- **ドキュメントはPRの説明文に記載** — リポジトリにファイルとしてコミットしない + +## 開始 + +Phase 1 のファイルを読み込んで開始: + +``` +.claude/skills/upstream-merge/phase1-prepare.md +``` diff --git a/.claude/skills/upstream-merge/phase1-prepare.md b/.claude/skills/upstream-merge/phase1-prepare.md new file mode 100644 index 00000000000..7c006833dab --- /dev/null +++ b/.claude/skills/upstream-merge/phase1-prepare.md @@ -0,0 +1,76 @@ +# Phase 1: Prepare — Prerequisites + Branch Creation + Merge Execution + +## Step 1: Prerequisites Check + +### 1.1 Git状態確認 + +```bash +git status +git branch --show-current +git remote -v | grep upstream +``` + +- Working directory が clean であること +- Current branch が `develop` であること +- Upstream remote が設定されていること + +未設定の場合: +```bash +git remote add upstream https://github.com/scratchfoundation/scratch-editor.git +``` + +### 1.2 Merge履歴読み込み + +`.upstream-merge-history.json` を読み込み、前回 merge の commit ID を取得する。 +ファイルが存在しない場合はエラー。 + +### 1.3 Upstream差分確認 + +**重要**: `git fetch upstream` は絶対に使わない(gh-pages を含む全ブランチを取得してしまう)。 + +```bash +git fetch -p upstream develop +git log ..upstream/develop --oneline --format="%h %s" +``` + +- 新しい commit 数を表示 +- 最新10件の commit message を表示 + +### 1.4 ユーザー確認 + +- "X commits を merge します。続行しますか?" +- Yes / No / View all commits の選択肢 + +--- + +## Step 2: Merge Branch Creation + +```bash +DATE=$(date +%Y-%m) +git checkout -b feat/upstream-merge-$DATE +``` + +--- + +## Step 3: Merge Execution + +```bash +git merge upstream/develop --no-commit --no-ff +``` + +### Conflict検出 + +```bash +git status --porcelain +``` + +- `UU` で始まる行 = unmerged conflicts +- conflict がある場合は **Phase 2** (`phase2-conflicts.md`) を読み込んで解決する +- conflict がない場合は **Phase 3** (`phase3-validation.md`) に進む + +--- + +## 次のフェーズ + +- コンフリクトあり → `phase2-conflicts.md` を読み込む +- コンフリクトなし → `phase3-validation.md` を読み込む diff --git a/.claude/skills/upstream-merge/phase2-conflicts.md b/.claude/skills/upstream-merge/phase2-conflicts.md new file mode 100644 index 00000000000..90b64792c8e --- /dev/null +++ b/.claude/skills/upstream-merge/phase2-conflicts.md @@ -0,0 +1,153 @@ +# Phase 2: Conflict Resolution + +コンフリクトを検出し、既知パターンに従って解決する。 + +## Known Conflicts 一覧 + +以下のファイルは upstream merge 時にほぼ毎回コンフリクトが発生する。 + +### gui.ts + +``` +✓ gui.ts conflict detected (EXPECTED) +``` + +**ファイル**: `packages/scratch-gui/src/reducers/gui.ts` + +**解決方法**: +1. 以下のマーカーブロックを保持: + ``` + // === Smalruby: Start of Redux state registry === + import {smalrubyReducers, smalrubyInitialState} from './smalruby-registry'; + // === Smalruby: End of Redux state registry === + ``` +2. `buildInitialState()` 内で保持: + ``` + // === Smalruby: Start of initial state === + ...smalrubyInitialState, + // === Smalruby: End of initial state === + ``` +3. `combineReducers()` 内で保持: + ``` + // === Smalruby: Start of reducers === + ...smalrubyReducers, + // === Smalruby: End of reducers === + ``` +4. それ以外は upstream の変更を受け入れる + +**参考**: `packages/scratch-gui/src/reducers/smalruby-registry.ts` + +--- + +### extension-manager.js + +``` +✓ extension-manager.js conflict detected (EXPECTED) +``` + +**ファイル**: `packages/scratch-vm/src/extension-support/extension-manager.js` + +**解決方法**: +1. 以下のマーカーブロックを保持: + ``` + // === Smalruby: Start of extension registration === + const registerSmalrubyExtensions = require('./smalruby-extensions'); + registerSmalrubyExtensions(builtinExtensions); + // === Smalruby: End of extension registration === + ``` +2. `builtinExtensions` オブジェクトは upstream の変更を受け入れる + +**参考**: `packages/scratch-vm/src/extension-support/smalruby-extensions.js` + +--- + +### blocks.jsx + +``` +✓ blocks.jsx conflict detected (EXPECTED) +``` + +**ファイル**: `packages/scratch-gui/src/containers/blocks.jsx` + +**解決方法**: +1. Smalruby 固有の追加を全て保持: + - Ruby tab logic (`handleActivateRubyTab` 等) + - Smalruby extension integration + - Block display modal integration +2. upstream の ScratchBlocks API 変更を Smalruby コードにも適用 + → `reference-api-migration.md` を参照 +3. 新しい props/state destructuring パターンがあれば取り込む + +--- + +### eslint.config.mjs + +``` +✓ eslint.config.mjs conflict detected (EXPECTED) +``` + +**ファイル**: `packages/scratch-gui/eslint.config.mjs` (またはルート) + +**解決方法**: +1. Smalruby 固有の lint ルールとオーバーライドを保持 +2. upstream のプラグインマイグレーションを受け入れ + - 例: `eslint-plugin-import` → `import-x` +3. Smalruby ルールで名前変更されたプラグインを参照している箇所を更新 + - 例: `"import/core-modules"` → `"import-x/core-modules"` + +--- + +### package.json (複数) + +``` +✓ package.json conflict detected (EXPECTED) +``` + +**解決方法**: +1. `@smalruby` パッケージ名を保持 (例: `@smalruby/scratch-vm`) +2. Smalruby 固有の dependencies を保持 +3. upstream のバージョンアップを受け入れ +4. Smalruby パッケージのバージョンを upstream メジャーバージョンに合わせる +5. upstream が peer deps として追加したものが Smalruby では direct deps として必要か確認 + - 例: `react`, `react-dom`, `redux` が direct dependency として必要な場合がある + +--- + +### package-lock.json + +``` +✓ package-lock.json conflict detected (EXPECTED) +``` + +**解決方法**: +1. upstream の package.json 変更を先に受け入れる +2. lock file を再生成: + ```bash + docker compose run --rm app npm install + ``` + +--- + +## Unexpected Conflicts + +上記以外のファイルでコンフリクトが発生した場合: + +1. **WARNING** として表示 +2. ファイルリストを表示 +3. ユーザーに手動解決を促す +4. API 変更が原因の場合は `reference-api-migration.md` を参照 + +## コンフリクト解決後の確認 + +```bash +git status --porcelain | grep "^UU" +``` + +- 出力がなければ全てのコンフリクトが解決済み +- まだ残っている場合は警告して続行を待つ + +--- + +## 次のフェーズ + +コンフリクト解決完了 → `phase3-validation.md` を読み込む diff --git a/.claude/skills/upstream-merge/phase3-validation.md b/.claude/skills/upstream-merge/phase3-validation.md new file mode 100644 index 00000000000..a40c796f518 --- /dev/null +++ b/.claude/skills/upstream-merge/phase3-validation.md @@ -0,0 +1,118 @@ +# Phase 3: Validation — Commit + Lint + Build + Tests + CI + +## Step 1: Merge Commit + +**重要**: `git add .` は絶対に使わない。 + +```bash +# tracked files のみをステージング(.gitignore を尊重) +git add -u + +# notes/ がステージングされていないことを確認 +git status + +# merge commit 作成 +git commit -m "$(cat <<'EOF' +feat: merge upstream scratch-editor changes (X commits) + +Merged X commits from upstream develop branch. + +Co-Authored-By: Claude +EOF +)" +``` + +merge commit の hash を記録しておく(Phase 4 で使用)。 + +--- + +## Step 2: Lint + +```bash +docker compose run --rm app npm run lint +``` + +- **Pass**: 次へ進む +- **Fail**: エラー内容を確認して修正 → 再度 lint → 修正コミット + +### Lint 通過後: Push 推奨 + +CI を並行実行するため、早めに push する: + +```bash +git push -u origin feat/upstream-merge-YYYY-MM +``` + +PR も早めに作成すると CI が走る(Phase 4 の PR 作成を先にやってもよい)。 + +--- + +## Step 3: Build + +```bash +docker compose run --rm app npm run build:dev +``` + +- **Pass**: 次へ進む +- **Fail**: エラー内容を確認して修正 + +--- + +## Step 4: Unit Tests + +```bash +docker compose run --rm app npm run test:unit +``` + +- **Pass**: 次へ進む +- **Fail**: `reference-test-patterns.md` を参照して修正 + +--- + +## Step 5: Integration Tests + +統合テストはタイムアウト回避のためバッチ実行する(5-6ファイルずつ): + +```bash +docker compose run --rm app bash -c "cd packages/scratch-gui && npm exec jest --no-coverage \ + test/integration/A.test.js \ + test/integration/B.test.js \ + test/integration/C.test.js" +``` + +全テストファイルを確認: +```bash +ls packages/scratch-gui/test/integration/*.test.js +ls packages/scratch-vm/test/integration/*.js +``` + +- **Pass**: 次へ進む +- **Fail**: `reference-test-patterns.md` を参照して修正 + +--- + +## Step 6: CI Status Check + +push 済みなら CI の状態を確認: + +```bash +gh run list --repo smalruby/smalruby3-editor --branch feat/upstream-merge-YYYY-MM +``` + +または: https://github.com/smalruby/smalruby3-editor/actions + +- **All passing**: 次へ進む +- **Failing**: ログを確認して修正、push、再確認 +- **Pending**: 待機中。次のフェーズに進んでもよい + +### 既知の CI 注意点 + +- **"Lint commit messages" workflow**: upstream の commit message が 100 文字超えの場合に失敗する。 + これは想定内であり、ブロッカーではない。 + +--- + +## 次のフェーズ + +全てのテストが通過 → `phase4-finalize.md` を読み込む +テスト修正が必要 → `reference-test-patterns.md` を読み込む diff --git a/.claude/skills/upstream-merge/phase4-finalize.md b/.claude/skills/upstream-merge/phase4-finalize.md new file mode 100644 index 00000000000..b1422d63160 --- /dev/null +++ b/.claude/skills/upstream-merge/phase4-finalize.md @@ -0,0 +1,165 @@ +# Phase 4: Finalize — Merge History + PR Creation + Manual Testing + +## Step 1: Merge History Update + +### `.upstream-merge-history.json` 更新 + +```json +{ + "lastMerge": { + "date": "YYYY-MM-DD", + "upstreamCommit": "", + "smalrubyCommit": "", + "mergeCommit": "", + "notes": "X commits merged from upstream develop" + }, + "previousMerges": [ + { "(前回の lastMerge をここに移動)" } + ] +} +``` + +### Commit and Push + +**重要**: `.upstream-merge-history.json` のみを明示的に add する。 + +```bash +git add .upstream-merge-history.json +git commit -m "$(cat <<'EOF' +chore: update upstream merge history + +Co-Authored-By: Claude +EOF +)" +git push +``` + +--- + +## Step 2: PR Creation + +### PR Body 作成 + +`/tmp/pr-body.md` に Write tool で書き出す: + +```markdown +## Summary + +Merged X commits from upstream scratch-editor `develop` branch. + +**Upstream Commit Range**: ``..`` + +## Major Upstream Changes + +[git log から主要な commit message を10件程度] + +## Conflicts Resolved + +### Known Conflicts +- ✅ gui.ts - Kept Smalruby registry pattern +- ✅ extension-manager.js - Kept Smalruby extension registration +- ✅ package-lock.json - Regenerated with npm install +[他の conflict も記載] + +### Unexpected Conflicts +[あれば記載] + +### Post-Merge Fixes +[テスト修正、lint 修正などがあれば記載] + +## Test Results + +- ✅ Linting passed +- ✅ Build succeeded +- ✅ Unit tests passed +- ✅ Integration tests passed +- ✅ CI: All checks passing + +## Manual Testing Checklist + +Before merging this PR, verify: +- [ ] Ruby code editor loads correctly +- [ ] Ruby-to-blocks conversion works +- [ ] Google Drive integration works +- [ ] Custom extensions load (microbitMore, Koshien, Mesh v2) +- [ ] Gemini modal works +- [ ] Block Display modal filters correctly +- [ ] No console errors or warnings + +--- + +🤖 Generated with `/upstream:merge` command +``` + +### PR 作成 + +```bash +gh pr create \ + --repo smalruby/smalruby3-editor \ + --base develop \ + --head feat/upstream-merge-YYYY-MM \ + --title "feat: upstream merge YYYY-MM (X commits)" \ + --body-file /tmp/pr-body.md + +rm /tmp/pr-body.md +``` + +--- + +## Step 3: Manual Testing (Playwright MCP) + +PR の preview URL を使って手動確認する。 +Playwright MCP を使うと効率的。 + +### Preview URL + +PR にコメントされる URL、または: +``` +https://smalruby.jp/smalruby3-editor// +``` + +### 確認項目 + +| Feature | 確認方法 | +|---------|----------| +| ページ読み込み | console errors が 0 であること | +| ブロックカテゴリ | 日本語で全カテゴリ表示 | +| 設定メニュー | 言語、カラーモード、ルビー、ブロック表示 | +| ファイルメニュー | Google Drive 項目(読み込む、保存、コピーを保存) | +| ルビータブ | Monaco editor、ツールバー、ふりがなボタン | +| Gemini モーダル | 「スモウルビー先生」ボタン → モーダル表示 | +| 拡張機能 | 「拡張機能を追加」→ 全拡張機能(Mesh v2 含む)表示 | + +### 確認完了後 + +PR の Manual Testing Checklist にチェックを入れ、PR 説明を更新。 + +--- + +## Step 4: Merge + +全ての確認が完了したら: + +```bash +gh pr merge \ + --repo smalruby/smalruby3-editor \ + --merge \ + --delete-branch +``` + +**注意**: `--merge` フラグ必須。squash merge は禁止。 + +```bash +git checkout develop && git pull origin develop +``` + +--- + +## 完了 + +``` +✅ Upstream merge completed successfully! + +PR merged: https://github.com/smalruby/smalruby3-editor/pull/XXX +Merge history updated: .upstream-merge-history.json +``` diff --git a/.claude/skills/upstream-merge/reference-api-migration.md b/.claude/skills/upstream-merge/reference-api-migration.md new file mode 100644 index 00000000000..1fc931919fd --- /dev/null +++ b/.claude/skills/upstream-merge/reference-api-migration.md @@ -0,0 +1,61 @@ +# Reference: ScratchBlocks API Migration Guide + +upstream が scratch-blocks のメジャーバージョンを上げた場合に参照する。 +Smalruby のカスタムコード (`blocks.jsx` 等) にも同じ変更を適用すること。 + +## scratch-blocks v2.0.0 (spork) での変更 + +### JavaScript API + +| Before | After | +|--------|-------| +| `ScratchBlocks.prompt` | `ScratchBlocks.dialog.setPrompt()` | +| `ScratchBlocks.statusButtonCallback` | `ScratchBlocks.StatusIndicatorLabel.statusButtonCallback` | +| `ScratchBlocks.Xml.textToDom` | `ScratchBlocks.utils.xml.textToDom` | +| `ScratchBlocks.Xml.clearWorkspaceAndLoadFromXml` | `ScratchBlocks.clearWorkspaceAndLoadFromXml` | +| `this.workspace.reportValue()` | `this.ScratchBlocks.reportValue()` | + +### CSS クラス名 + +| Before | After | +|--------|-------| +| `.blocklyToolboxDiv` | `.blocklyToolbox` | + +テストで CSS セレクタを使っている場合は更新が必要。 + +### DOM 構造 + +scratch-blocks v2 ではブロックカテゴリのクリックターゲットが変わる場合がある。 + +- テストで `clickText('カテゴリ名')` が失敗する場合は `clickBlocksCategory('カテゴリ名')` を使用 +- `clickBlocksCategory` は `packages/scratch-gui/test/helpers/selenium-helper.js` で定義 + +### ESM モジュール (.mjs) + +scratch-blocks v2 は `.mjs` ファイルで ESM モジュールを使用する場合がある。 +デフォルトエクスポートがない場合は named import を使用: + +```javascript +// Before (CJS) +const ScratchBlocks = require('scratch-blocks'); + +// After (ESM, if applicable) +import {ScratchBlocks} from 'scratch-blocks'; +``` + +### blocks.jsx での主な影響箇所 + +`packages/scratch-gui/src/containers/blocks.jsx` で特に注意が必要な箇所: + +1. **ScratchBlocks の初期化コード** — API 名が変わっている可能性 +2. **toolbox 関連** — DOM クラス名変更の影響 +3. **ワークスペース操作** — `Xml` 名前空間の移動 +4. **ステータスボタン** — callback の設定方法の変更 +5. **プロンプト/ダイアログ** — prompt の設定方法の変更 + +### lib/blocks.js での主な影響箇所 + +`packages/scratch-gui/src/lib/blocks.js` でも API 変更の影響を受ける: + +1. **XML 操作** — `ScratchBlocks.Xml.*` → `ScratchBlocks.utils.xml.*` または直接メソッド +2. **ワークスペース操作** — `clearWorkspaceAndLoadFromXml` の移動 diff --git a/.claude/skills/upstream-merge/reference-test-patterns.md b/.claude/skills/upstream-merge/reference-test-patterns.md new file mode 100644 index 00000000000..9b49b4af95a --- /dev/null +++ b/.claude/skills/upstream-merge/reference-test-patterns.md @@ -0,0 +1,178 @@ +# Reference: Known Test Fix Patterns + +upstream merge 後に頻出するテスト修正パターン。 + +--- + +## Integration Tests (scratch-gui) + +### 1. カテゴリクリックの失敗 (element click intercepted) + +**症状**: テストが `clickText('カテゴリ名')` で失敗、"element click intercepted" エラー + +**原因**: scratch-blocks v2 の DOM 構造変更により、カテゴリラベルのクリックが +親コンテナに遮られる。 + +**修正**: +```javascript +// Before +await clickText('Looks'); +await clickText('調べる'); + +// After +await clickBlocksCategory('Looks'); +await clickBlocksCategory('調べる'); +``` + +`clickBlocksCategory` は `test/helpers/selenium-helper.js` で定義。 +import が必要: +```javascript +const {clickBlocksCategory, ...} = require('../helpers/selenium-helper'); +``` + +### 2. CSS セレクタの不一致 + +**症状**: `document.querySelector('.blocklyToolboxDiv')` が `null` を返す + +**原因**: scratch-blocks v2 でクラス名が変更された。 + +**修正**: +```javascript +// Before +document.querySelector('.blocklyToolboxDiv') + +// After +document.querySelector('.blocklyToolbox') +``` + +### 3. 新しいヘルパー関数の import 不足 + +**症状**: `ReferenceError: scopeForFlyoutBlock is not defined` 等 + +**原因**: upstream が `selenium-helper.js` に新しい関数を追加し、テストファイルで使用。 + +**修正**: テストファイルの import 文を更新して新しい関数を含める。 + +```javascript +// 例: scopeForFlyoutBlock が追加された場合 +const { + clickText, + clickBlocksCategory, + scopeForFlyoutBlock, // 追加 + ... +} = require('../helpers/selenium-helper'); +``` + +--- + +## Unit Tests (scratch-vm) + +### 1. タイミング依存テストの flakiness + +**症状**: CI で断続的に失敗。ローカルでは通る。 +`not ok - should be equal` のような曖昧なエラー。 + +**原因**: `setTimeout` や `Date.now()` に依存するテストが CI 環境の遅延で不安定。 + +**修正**: `Date.now` と `Date` コンストラクタの両方をモックして決定的にする。 + +**重要**: `new Date().toISOString()` を使うコードでは `Date.now` だけでなく +`Date` コンストラクタ自体もモックが必要。 + +```javascript +// Mock both Date.now and Date constructor +const realDateNow = Date.now; +const RealDate = Date; +const startTime = realDateNow(); +let currentTime = startTime; +Date.now = () => currentTime; +// eslint-disable-next-line no-global-assign +Date = class extends RealDate { + constructor (...args) { + if (args.length === 0) { + super(currentTime); + } else { + super(...args); + } + } + static now () { + return currentTime; + } +}; + +try { + // テストコード: currentTime を操作して時間を制御 + service.fireEvent('e1'); + currentTime = startTime + 100; + service.fireEvent('e2'); + currentTime = startTime + 200; + service.fireEvent('e3'); + + await service.processBatchEvents(); + + // アサーション... +} finally { + // eslint-disable-next-line no-global-assign + Date = RealDate; + Date.now = realDateNow; +} +``` + +--- + +## CI-Specific Issues + +### 1. "Lint commit messages" workflow failure + +**症状**: "Lint commit messages" CI ジョブが失敗 + +**原因**: upstream の commit message が commitlint の 100 文字制限を超えている。 + +**対応**: ブロッカーではない。無視してよい。 + +### 2. カバレッジ閾値エラー + +**症状**: テスト自体は通るが、CI がカバレッジ不足で失敗 + +**原因**: `tap` の `allow-incomplete-coverage` 設定、またはカバレッジ閾値の設定 + +**対応**: `package.json` の `tap` セクションを確認: +```json +{ + "tap": { + "allow-incomplete-coverage": true + } +} +``` + +--- + +## テスト実行のベストプラクティス + +### バッチ実行 + +統合テストはタイムアウト回避のため 5-6 ファイルずつ実行: + +```bash +docker compose run --rm app bash -c "cd packages/scratch-gui && npm exec jest --no-coverage \ + test/integration/blocks.test.js \ + test/integration/blocks-standalone.test.js \ + test/integration/localization.test.js" +``` + +### scratch-vm のテスト + +```bash +# 単体テスト全体 +docker compose run --rm app bash -c "cd packages/scratch-vm && npm exec tap test/unit/*.js" + +# 特定のファイル +docker compose run --rm app bash -c "cd packages/scratch-vm && npm exec tap test/unit/specific-file.js" +``` + +### テスト失敗時の調査 + +1. まずエラーメッセージを確認 +2. 上記の既知パターンに当てはまるか確認 +3. 当てはまらない場合は、upstream の diff を確認して原因を特定 +4. API 変更が原因の場合は `reference-api-migration.md` を参照 diff --git a/CLAUDE.md b/CLAUDE.md index 139ff4d41a9..19e96b5d0e9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -323,4 +323,4 @@ This command provides: **Manual merge is NOT recommended** - use the slash command to ensure consistent process and complete documentation. -See `.claude/commands/upstream-merge.md` for detailed workflow documentation. +See `.claude/skills/upstream-merge/SKILL.md` for detailed workflow documentation. diff --git a/notes/upstream/merge-2026-03/conflict-resolutions.md b/notes/upstream/merge-2026-03/conflict-resolutions.md deleted file mode 100644 index 76c1639cc3c..00000000000 --- a/notes/upstream/merge-2026-03/conflict-resolutions.md +++ /dev/null @@ -1,34 +0,0 @@ -# Conflict Resolutions - 2026-03 Upstream Merge - -## Files with Conflicts - -### Known Conflicts (Resolved) -- [x] `package-lock.json` - Regenerated with `npm install --legacy-peer-deps` -- [x] `packages/scratch-gui/package.json` - Kept @smalruby naming, merged deps -- [x] `packages/scratch-render/package.json` - Kept @smalruby naming, bumped version -- [x] `packages/scratch-svg-renderer/package.json` - Kept @smalruby naming, bumped version -- [x] `packages/scratch-vm/package.json` - Kept @smalruby naming, bumped version -- [x] `packages/task-herder/package.json` - Kept @smalruby naming, bumped version - -### Unexpected Conflicts (Manual Resolution) -- [x] `.github/workflows/ci.yml` (DU) - Kept deletion (Smalruby uses own CI) -- [x] `packages/scratch-gui/src/lib/settings/color-mode/dark/__mocks__/index.js` (DU) - Accepted upstream -- [x] `packages/scratch-gui/src/lib/settings/color-mode/default/__mocks__/index.js` (DU) - Accepted upstream -- [x] `packages/scratch-gui/eslint.config.mjs` - Kept Smalruby additions + upstream globalIgnores, updated import/core-modules to import-x/core-modules -- [x] `packages/scratch-gui/src/containers/blocks.jsx` - Kept Smalruby logic (Ruby tab guard, fromRuby cleanup), updated ScratchBlocks API calls to v2.0.0 -- [x] `packages/scratch-gui/test/integration/blocks-standalone.test.js` - Imported both `until` and `scopeForFlyoutBlock` -- [x] `packages/scratch-gui/test/integration/blocks.test.js` - Imported both `until` and `scopeForFlyoutBlock` -- [x] `packages/scratch-gui/test/integration/localization.test.js` - Kept Smalruby version (Japanese locale test) - -## Post-Merge Fixes -- Added `blockDisplayInitialState` export alias to `block-display.js` reducer -- Added `redux` to `import-x/no-unresolved` ignore in eslint config -- Fixed `colorMode` destructuring in blocks.jsx (needed by CustomProcedures) -- Added `react`, `react-dom`, `redux` as direct dependencies (were peer deps only) - -## ScratchBlocks v2.0.0 API Changes Applied -- `ScratchBlocks.prompt` → `ScratchBlocks.dialog.setPrompt()` -- `ScratchBlocks.statusButtonCallback` → `ScratchBlocks.StatusIndicatorLabel.statusButtonCallback` -- `ScratchBlocks.Xml.textToDom` → `ScratchBlocks.utils.xml.textToDom` -- `ScratchBlocks.Xml.clearWorkspaceAndLoadFromXml` → `ScratchBlocks.clearWorkspaceAndLoadFromXml` -- `this.workspace.reportValue()` → `this.ScratchBlocks.reportValue()` diff --git a/notes/upstream/merge-2026-03/progress.md b/notes/upstream/merge-2026-03/progress.md deleted file mode 100644 index 7752d1aae55..00000000000 --- a/notes/upstream/merge-2026-03/progress.md +++ /dev/null @@ -1,23 +0,0 @@ -# Upstream Merge Progress - 2026-03 - -## Info -- **Date**: 2026-03-08 -- **Branch**: feat/upstream-merge-2026-03 -- **Upstream commits**: 146 -- **Previous merge commit**: 5f063605b67927f01647f56a8abf28b972a292bd - -## Steps - -| Step | Status | Time | -|------|--------|------| -| Prerequisites | ✅ | 2026-03-08 | -| Branch creation | ✅ | 2026-03-08 | -| Merge execution | ✅ | 2026-03-08 | -| Conflict resolution | ✅ | 2026-03-08 | -| Lint | ✅ | 2026-03-08 | -| Build | ✅ | 2026-03-08 | -| Unit tests | ✅ | 2026-03-08 | -| Integration tests | ✅ | 2026-03-08 | -| CI check | ⏳ Running | | -| Documentation | ✅ | 2026-03-08 | -| PR creation | ✅ | PR #238 | diff --git a/notes/upstream/merge-2026-03/test-results.md b/notes/upstream/merge-2026-03/test-results.md deleted file mode 100644 index 4e253256e86..00000000000 --- a/notes/upstream/merge-2026-03/test-results.md +++ /dev/null @@ -1,40 +0,0 @@ -# Test Results - 2026-03 Upstream Merge - -## Lint -✅ Passed (3 pre-existing warnings) - -## Build -✅ Passed (dev build, warnings only) - -## Unit Tests -✅ Passed (183 suites, 1582/1583 passed, 1 skipped) - -## Integration Tests -✅ Passed (local) - -- smalruby-tutorials.test.js: 3/3 ✅ -- block-display-modal.test.js: 7/7 ✅ -- gemini-modal.test.js: 1/1 ✅ -- ruby-tab-completion-and-indent.test.js: ✅ (skipped: 12) -- tutorial-block-restriction.test.js: 3/3 ✅ -- palette-toggle.test.js: 4/4 ✅ -- backpack.test.js: ✅ -- ruby-tab.test.js: ✅ -- menu-bar.test.js: ✅ -- project-loading.test.js: ✅ -- sprites.test.js: ✅ -- blocks.test.js: ✅ -- localization.test.js: 4/4 ✅ - -### Fixes Required for scratch-blocks v2 -- `clickText` → `clickBlocksCategory` for toolbox category clicks (DOM structure changed) -- `.blocklyToolboxDiv` → `.blocklyToolbox` CSS selector (class name changed) -- `import Blockly from 'scratch-blocks'` → `import * as Blockly from 'scratch-blocks'` (no default export) -- `Blockly.utils.genUid()` → `Blockly.utils.idGenerator.genUid()` (API changed) -- `Blockly.NAME_TYPE` → `Blockly.Names.NameType` (API changed) - -## CI Status -⏳ Running - https://github.com/smalruby/smalruby3-editor/actions/runs/22818709584 - -### Known CI Issue -- "Lint commit messages" workflow fails due to upstream commits with headers >100 characters. This is expected for merge branches and not a blocking issue.