Skip to content

Add: Option to keep the selection menu open on tab/window change#431

Merged
ujiro99 merged 15 commits into
mainfrom
feat/keep-menu-open-on-tab-change
Jul 15, 2026
Merged

Add: Option to keep the selection menu open on tab/window change#431
ujiro99 merged 15 commits into
mainfrom
feat/keep-menu-open-on-tab-change

Conversation

@ujiro99

@ujiro99 ujiro99 commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

  • 選択メニューからコマンドを実行して別タブ/ウィンドウに移動した場合でも、startupMethod.keepMenuOpenOnTabChange オプション(デフォルトOFF)を有効にすると、選択メニューと選択テキストを維持するようにしました。
  • chrome.tabs.onActivated / chrome.windows.onFocusChanged でのメニュー強制クローズ・選択テキストクリアを、オプション有効時はスキップします。
  • 設定画面の「起動方法」セクションにトグルを追加し、全14言語のロケールファイルを更新しました。
  • 既存ユーザー設定向けにマイグレーション処理を追加しています。

Closes #365

Test plan

  • yarn test:run src/test/locales.test.ts — ロケールキーの整合性・順序を確認
  • yarn tsc --noEmit — 型エラーなし
  • yarn lint — 新規エラーなし
  • yarn test:run(全体) — 882 passed。失敗14件は @supabase/supabase-js 未インストール等の既存事象で、git stash により変更前から存在することを確認済み

Adds startupMethod.keepMenuOpenOnTabChange, letting users keep the
selection menu and selected text visible after running a command
opens a new tab/window, so they can return and run another command
on the same selection.

Closes #365
@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 52.99539% with 204 lines in your changes missing coverage. Please review.
✅ Project coverage is 39.57%. Comparing base (a963e1b) to head (7c83d4f).
⚠️ Report is 33 commits behind head on main.

Files with missing lines Patch % Lines
...sion/src/components/option/editor/ShortcutList.tsx 0.00% 47 Missing ⚠️
packages/hub/src/app/page.tsx 0.00% 32 Missing ⚠️
packages/hub/src/app/not-found.tsx 0.00% 27 Missing ⚠️
packages/extension/src/background_script.ts 39.02% 25 Missing ⚠️
...es/extension/src/components/option/SettingForm.tsx 0.00% 25 Missing ⚠️
...kages/extension/src/services/windowStackManager.ts 86.56% 9 Missing ⚠️
packages/hub/src/app/[lang]/layout.tsx 0.00% 8 Missing ⚠️
...ckages/extension/src/services/settings/settings.ts 73.07% 7 Missing ⚠️
packages/hub/src/components/layout/Header.tsx 0.00% 4 Missing ⚠️
packages/extension/src/action/pageAction.ts 0.00% 3 Missing ⚠️
... and 11 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #431      +/-   ##
==========================================
+ Coverage   29.93%   39.57%   +9.63%     
==========================================
  Files         322      237      -85     
  Lines       33274    25349    -7925     
  Branches     1943     1886      -57     
==========================================
+ Hits         9962    10031      +69     
+ Misses      23312    15318    -7994     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@claude

claude Bot commented Jul 13, 2026

Copy link
Copy Markdown

レビュー結果

タブ/ウィンドウ切り替え時に選択メニューを維持するオプション追加、全体的に実装方針は明確で、既存のマイグレーションパターンや14言語ロケール更新もきちんと踏襲されています。以下、気になった点です。

1. (nit/確認) マイグレーションのバージョン閾値が未リリースのバージョンを指している

  • packages/extension/src/services/settings/settings.ts:265, settings.ts:388-399
  • migrate1_1_1versionDiff(currentVersion, "1.1.1") を閾値にしていますが、packages/extension/package.jsonpackages/extension/manifest.jsonversion は現状 1.1.0 のままです。
  • このままリリースすると VERSION(__APP_VERSION__)は "1.1.0" になるため、data.settingVersion は常に "1.1.0" に設定され、versionDiff(currentVersion, "1.1.1") が毎回 Old 判定になり migrate1_1_1 が呼ばれ続けます。keepMenuOpenOnTabChange == null チェックにより実害はありませんが、意図通り動かすには本PR(または別PR)で package.json / manifest.json の version を 1.1.1 以上に上げる必要があります。リリースフローで別途バージョンを上げる運用であれば問題ありませんが、念のため確認をお願いします。

2. (テストカバレッジ) 新規ロジックに対するテストが不足

  • packages/extension/src/background_script.ts:349-408chrome.windows.onFocusChanged / chrome.tabs.onActivated に追加された keepMenuOpenOnTabChange 分岐について、background_script.test.ts に有効/無効それぞれのケースを検証するテストが見当たりませんでした(既存のPAC-01〜PAC-03は popupAutoCloseDelay 周りのテストで、この分岐はカバーしていません)。
  • 同様に packages/extension/src/services/settings/settings.ts:388migrate1_1_1 にも専用のユニットテストが settings.test.ts に追加されていません(既存の migrate0_14_3 等は ST-33 で個別にテストされています)。
  • 挙動を切り替えるトグルという性質上、keepMenuOpenOnTabChange: true 時にメニューがクローズされない/選択テキストがクリアされないことを検証するテストの追加をおすすめします。

3. (パフォーマンス・軽微) enhancedSettings.get() はフル取得で若干過剰

  • packages/extension/src/background_script.ts:350, 399
  • どちらのリスナーも startupMethod.keepMenuOpenOnTabChange の1フィールドしか使っていませんが、enhancedSettings.get() はCOMMANDS/USER_SETTINGS/STARS/SHORTCUTS/USER_STATSの5セクションを毎回並行取得します。chrome.tabs.onActivated はタブ切り替えのたびに高頻度で発火するため、enhancedSettings.getSection(CACHE_SECTIONS.USER_SETTINGS)(本ファイル内の PopupAutoClose 関連処理でも使われているパターン)に絞った方が無駄が少ないと思います。キャッシュ層があるため実害は小さいですが、頻度が高いイベントなので検討の余地があります。

4. 良い点

  • SettingForm.tsx のトグルは既存の SwitchField パターン(tooltip prop含む)に沿っており、t() のキー命名(Option_ prefix)も一貫しています。
  • 14言語すべてのロケールファイルが更新されており、抜けはありません。
  • defaultSettings.tsemptySettings / デフォルト設定の両方に keepMenuOpenOnTabChange: false が追加されており、既存ユーザー・新規ユーザーどちらでも一貫したデフォルト値になっています。
  • SettingForm.tsx 内の leftClickHoldParam 周りのインデント差分はロジック変更を伴わない整形のみで、意図しない挙動変更はなさそうです。

セキュリティ

  • 今回の変更はローカルのChrome Storage設定値の読み書きとUI表示のみで、外部通信や権限拡大は伴わないため、セキュリティ上の大きな懸念は見当たりませんでした。

以上、大きなブロッカーはありませんが、特に1点目(バージョン閾値)は次回リリースで意図通りマイグレーションが走るか確認いただけると安心です。


🤖 Generated with Claude Code

ujiro99 and others added 8 commits July 13, 2026 20:58
…page

The Selection Command Hub app has migrated to a new repository
(selection-command-hub) with a new architecture. packages/hub now only
needs to host public/data/ai-services.json for the AiPrompt command and
serve the e2e test page used by packages/extension's Playwright suite,
so all other pages, components, features, and data have been removed.

The extension's MyCommands widget (command_hub.tsx) only worked by
injecting into hub pages that are now deleted, so it has been removed
along with its manifest.json content_script entry and build config
references. AGENTS.md and README.md have been updated to reflect the
reduced scope.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fix the Header logo linking to a now-deleted route (404), trim locale
dictionaries down to the keys actually consumed by the reduced hub app,
drop dead code from useLocale and const.ts left over from the feature
removal, and stop showing a Footer "Last Updated" date that was frozen
to a stub value after GA integration was removed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
# Conflicts:
#	packages/extension/src/services/settings/settings.ts
Root causes were in BgData, not the onFocusChanged guard itself:
- BgData.init() populated instance only via a fire-and-forget
  Storage.get().then(...), so any read/write before it resolved saw
  (or persisted) an incomplete state, silently dropping windowStack.
- BgData.update()/set() read-then-wrote non-atomically, so a
  concurrent update (e.g. activeTabId tracking) could overwrite a
  just-added popup before it was ever read back.
- The chrome.storage.onChanged echo listener could replay a stale
  write (including this context's own) after a newer local update,
  rolling back windowStack right after a popup was added.

Fixes: synchronous default instance + ready() gate, atomic
BgData.update()-based read-modify-write in WindowStackManager, and a
revision counter so stale onChanged echoes are ignored. Also reorders
onFocusChanged so popup-close scheduling isn't gated behind the
settings fetch, and adds backgroundData.test.ts covering the fixed
races.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@claude

claude Bot commented Jul 14, 2026

Copy link
Copy Markdown

レビュー概要

startupMethod.keepMenuOpenOnTabChange オプションの追加、および BgData/WindowStackManager の競合状態修正を中心にレビューしました。なお本PRには packages/hub の大規模な削除・整理(PR番号434 由来のマージ内容、既にレビュー済みと思われます)が大量に含まれていますが、そちらは対象外とし、機能追加・バグ修正に関わるファイルに絞ってレビューしています。

良い点

  • BgData.init() が同期的にデフォルトインスタンスを用意するようになり、BgData.get()undefined を返す既存のバグ要因を解消している点(packages/extension/src/services/backgroundData.ts:52-57)。
  • WindowStackManager の各操作が BgData.update() の read-modify-write をアトミックに行うようになり、activeTabId 更新など並行更新との競合を避ける設計に改善されている点(packages/extension/src/services/windowStackManager.ts:76-132)。
  • 14言語すべてのロケールファイルにキーの過不足なく翻訳が追加されている点を確認しました(Option_keepMenuOpenOnTabChange / Option_keepMenuOpenOnTabChange_desc)。
  • backgroundData.test.tsrevision によるstale echo拒否など、修正した競合状態に対するテストが新規追加されている点。

気になる点

  1. BgData.init() の初期ロードが、より新しい onChanged echo を上書きしてしまう可能性 (バグ・優先度高)

packages/extension/src/services/backgroundData.ts:59-64

BgData.readyPromise = Storage.get<BgData>(SESSION_STORAGE_KEY.BG).then(
  (val: BgData) => {
    BgData.currentRevision = val?.revision ?? 0
    BgData.instance = new BgData(val)
  },
)

Storage.addListener 側のコールバック(65-74行目)は revision を見て古いechoを弾いていますが、この初期ロードの .then() は無条件に BgData.instance / currentRevision を上書きしています。Service Worker起動直後など、Storage.get() が解決する前に(別コンテキストからの書き込みによる)より新しい onChanged イベントが先に届き BgData.instance が更新された場合、その後で初期ロードの .then() が解決すると、読み込み開始時点の古い値で BgData.instancecurrentRevision を上書きしてしまいます。これはこのPRの最後のコミット(Fix: Popup auto-close broken by keepMenuOpenOnTabChange changes)がまさに修正しようとした「stale echoによるwindowStackのロールバック」と同種の問題を再度作り込んでしまう可能性があります。

init().then() 側でも onChanged と同様に revision を比較し、より新しい状態が既に適用されている場合はスキップするようにした方が安全だと思います。backgroundData.test.ts にもこのシナリオ(初期ロード解決前に onChanged が発火するケース)のテストが無いため、追加を検討ください。

  1. マイグレーションのバージョン管理の不整合 (バグの可能性・優先度中)

packages/extension/src/services/settings/settings.ts:266-271 / packages/extension/package.json:3

if (versionDiff(currentVersion, "1.1.1") === VersionDiff.Old) {
  data = migrate1_1_1(data)
}

migrate1_1_1 が追加されましたが、packages/extension/package.jsonversion"1.1.0" のまま更新されていません(VERSION はこの値から生成されます)。migrate() の最後で data.settingVersion = VERSION と設定されるため、マイグレーション後も settingVersion は常に "1.1.0" に留まり、次回読み込み時も versionDiff("1.1.0", "1.1.1")Old のままとなり、このマイグレーションが毎回の設定読み込みのたびに実行され続けます。migrate1_1_1 内部で keepMenuOpenOnTabChange == null をチェックしているため実害(データ破壊)はなさそうですが、1回限りのマイグレーションという設計意図から外れており、settingVersion が実際には "1.1.1" に到達しない点は将来のマイグレーション追加時に混乱を招きそうです。既存の migrate1_1_0 追加時にバージョンが 1.1.0 に上げられているパターンに倣い、package.json のバージョンも 1.1.1 以上に上げる必要があるのではないでしょうか。

  1. background_script.ts の新規分岐に対するテストが無い (テストカバレッジ)

packages/extension/src/background_script.ts:344-353, 409-421, 622-641

clearSelectionTextUnlessKeepOpenchrome.tabs.onActivated でのメニュー強制クローズのスキップ、chrome.sidePanel.onOpened でのスキップなど、本PRの主機能である keepMenuOpenOnTabChange に関する分岐について、background_script.test.ts を確認した限りテストが見当たりませんでした(既存の onFocusChanged テストは Popup Auto-Close Delay 用のもので、選択テキストのクリア可否やメニュークローズの可否は検証していません)。オプションON/OFFそれぞれで「選択テキストがクリアされない/される」「closeMenu が送信されない/される」ことを確認するテストの追加を推奨します。

  1. WindowStackManager の変更なし操作でも常時ストレージ書き込みが発生するようになった (パフォーマンス・情報共有)

packages/extension/src/services/windowStackManager.ts:110-132, 171-179

removeWindow / cleanupEmptyLayers は、BgData.update() に切り替えたことで、実質的に変更が無い場合(該当ウィンドウが見つからない、空レイヤーが無い等)でも常に Storage.set が呼ばれ revision がインクリメントされるようになりました(windowStackManager.test.ts のテスト期待値変更でも確認できます)。アトミック性を担保するためのトレードオフとして妥当ではありますが、chrome.storage への書き込み・onChanged 通知の頻度が増える点は意図した変更か念のため確認をお願いします(removeWindowsender.tab?.windowId に対して都度呼ばれるため、書き込み回数が増加します)。

その他

  • packages/extension/src/services/option/defaultSettings.tsemptySettings / デフォルトエクスポート双方に keepMenuOpenOnTabChange: false が追加されており、整合性は取れています。
  • SettingForm.tsxt("keepMenuOpenOnTabChange") は、ファイル内のローカル t ラッパー(Option_ プレフィックス付与)経由で Option_keepMenuOpenOnTabChange に解決されるため、ロケールキーとの不整合はありませんでした。

セキュリティ面で懸念となる変更(外部入力の扱いなど)は見当たりませんでした。上記1・2は動作に影響し得るため、特にご確認いただけると幸いです。

ujiro99 added 4 commits July 15, 2026 08:41
The flag now gates menu-close behavior on both tab switches and side
panel opens, not just tab changes, so rename it to reflect the broader
focus-change scope. Updated all 14 locale messages to also mention the
side panel.
@claude

claude Bot commented Jul 15, 2026

Copy link
Copy Markdown

レビュー結果

PR #431feat/keep-menu-open-on-tab-change)を確認しました。GitHub上の差分には feat/tidy-up-hub ブランチのマージに伴う packages/hub の大規模な削除(約1.4万行)が含まれていますが、これは別PR(#434等)で既にレビュー済みの内容と思われるため、本レビューは今回のPR本来の目的である 拡張機能側の「タブ/ウィンドウ切替時にメニューを維持するオプション」 に関わる差分に絞ってコメントします。

良い点

  • packages/extension/src/services/backgroundData.tsrevision ベースの排他制御は、chrome.storage.onChanged の古いエコーによって新しいローカル状態が巻き戻される問題に対する丁寧な対策になっています。readyPromise による同期的な空デフォルト値の提供も含め、設計として妥当です。
  • packages/extension/src/services/windowStackManager.tsaddWindow/removeWindow 等を BgData.update() 経由のatomicな読み書きに統一した点は、並行更新によるロスト・アップデートを防ぐ良いリファクタリングです。
  • 14言語すべてのロケールファイルが機械的に揃えられており、Option_ プレフィックス経由の t() 呼び出しとキー名も整合しています。
  • 既存ユーザー向けの migrate1_1_0 マイグレーションも一貫した形で追加されています。

指摘事項

1. 新機能の中核ロジックに対するユニットテストが見当たりません(テストカバレッジ)

packages/extension/src/background_script.tschrome.windows.onFocusChanged(361-379行目)、chrome.tabs.onActivated(409-428行目)、chrome.sidePanel.onOpened(623-636行目)に startupMethod.keepMenuOpenOnFocusChange の分岐が追加されていますが、packages/extension/src/background_script.test.ts を確認したところ keepMenuOpenOnFocusChange を検証するテストが見つかりませんでした。このオプションはPRの主目的そのものであり、ON/OFF双方でメニュークローズ・選択テキストクリアがスキップ/実行されることを検証するテストを追加することを推奨します。

2. 「メニューを強制的に閉じる」ロジックの重複(コード品質)

background_script.tschrome.tabs.onActivated(409-421行目)と chrome.sidePanel.onOpened(623-636行目)で、以下のブロックがほぼ同一のまま重複しています。

const settings = await enhancedSettings.getSection(CACHE_SECTIONS.USER_SETTINGS)
if (!settings.startupMethod?.keepMenuOpenOnFocusChange) {
  try {
    const ret = await Ipc.sendAllTab(TabCommand.closeMenu)
    ret.filter((v) => v).forEach((v) => console.debug(v))
  } catch (error) {
    console.error("Failed to close menu:", error)
  }
}

同ファイル内で追加された clearSelectionTextUnlessKeepOpen(344-353行目)と同様に、closeMenuUnlessKeepOpen() のような共通関数へ切り出すと保守性が上がります。

3. PR概要とコード上のオプション名の不一致(軽微)

PR descriptionでは startupMethod.keepMenuOpenOnTabChange と記載されていますが、最終コミット(Rename: keepMenuOpenOnTabChange to keepMenuOpenOnFocusChange)でコード上は keepMenuOpenOnFocusChange にリネームされています(packages/extension/src/types/index.ts:1816background_script.ts 全体)。実害はありませんが、PR descriptionの更新漏れです。

4. BgDatarevision カウンタはコンテキストごとに独立している点の注意(設計メモ)

packages/extension/src/services/backgroundData.ts:19-20currentRevision はstaticなモジュールスコープの値であり、BgData を利用する複数の実行コンテキスト(background service worker、options page、side panelなど、App.tsxipc.ts からもimportされています)がそれぞれ独自にカウンタを持ちます。chrome.storage.onChanged の伝播により通常は収束しますが、複数コンテキストがほぼ同時に書き込むと理論上は同一revision番号の競合が発生し得ます。現状のユースケース(単一backgroundからの書き込みが主)であれば実害は小さいと思われますが、コメントで前提を明記しておくと今後の変更時に安全です。

その他(軽微・任意)

  • packages/extension/src/components/option/SettingForm.tsx の588-611行目付近で、leftClickHoldParamInputField のインデントのみが変更されています。機能追加とは無関係な整形差分なので、可能であれば分離してレビューしやすくすると良いです。
  • packages/extension/src/services/settings/settings.tsmigrate1_1_0(389-413行目)で、従来あった await Storage.setCommands(data.commands) の即時書き込みが削除されていますが、他の migrateX_Y_Z 関数群と同様に「呼び出し時に都度in-memoryで適用される」挙動へ統一されており、これは意図的な一貫性向上と判断しました(問題ありません)。

セキュリティ

今回の差分範囲では、外部入力の扱いやXSS/インジェクションに繋がるような変更は見当たりませんでした。

以上、よろしくお願いします。

migrate() runs while Storage.get is still in flight, so it must not
trigger a write like Storage.setCommands mid-read. The migrated
command added to data.commands is persisted by the caller once the
read completes, so drop the incorrect expectation instead of adding
back a write inside migrate1_1_0.
@claude

claude Bot commented Jul 15, 2026

Copy link
Copy Markdown

コードレビュー結果

コマンド実行後にタブ/ウィンドウを切り替えても選択メニューを維持できるオプション追加、興味深い機能追加です。実装を確認しました。

レビュー範囲についての注意

gh pr diff 431 の出力には packages/hub/*AGENTS.md / README.md / package.json / manifest.json の hub 機能縮小に関する大量の差分(166ファイル中の大部分、-14350行)が含まれていますが、これは本ブランチが hub 縮小コミットとは別系統の古い main から分岐したまま rebase されていないために生じている diff アーティファクトのようです(マージ結果には既にこれらのファイルは存在しないため、マージ自体は正しく解決されると見られます)。以下のレビューは実際の機能変更(packages/extension 内の該当ファイル)に絞っています。マージ前に main を取り込んで diff をクリーンにしておくと、後続のレビューアーが混乱せずに済むと思います。

気になった点

  1. migrate1_1_0 でのコマンド永続化省略が既存の兄弟マイグレーションと矛盾している可能性
    packages/extension/src/services/settings/settings.ts:281migrate0_10_0)は今も migrate 中に await Storage.setCommands(data.commands) を呼んでいますが、同ファイル settings.ts:389-411migrate1_1_0)ではこの PR で「Search Commands on Hub」コマンド追加時の Storage.setCommands 呼び出しが削除されました。理由はテストのコメント(settings.test.ts:687-689)に「migrate() は Storage.get 中に走るため書き込みは unsafe。移行後のコマンドは呼び出し元が読み込み完了後に永続化する」とありますが、Settings.get()settings.ts:51-82)を見る限り、migrate() 実行後に Storage.setCommands を呼んでいる呼び出し元は見当たりませんでした(setCommands の呼び出し箇所を grep して確認)。

    • もし本当に「呼び出し元が永続化する」のであれば、その箇所を明示していただけると安心です。
    • もし永続化されないのが正しい挙動になったのであれば、migrate0_10_0 側の同種の書き込み(settings.ts:281)も同じ理由で不要/危険なはずで、整合性のため合わせて修正すべきです。
    • このままだと、Settings.get() を呼ぶたびに Search Commands コマンドがメモリ上には追加されるものの chrome.storage には保存されない、という状態になり、Storage.getCommands() を直接参照する箇所(例: hub/background.ts 等)との間で状態の食い違いが起きる可能性があります。今回の PR 本来のスコープ(keepMenuOpenOnFocusChange)とは無関係な変更なので、意図を明確にするか別 PR に切り出すことをおすすめします。
  2. 新しいマイグレーション分岐にテストがない
    settings.ts:401-410keepMenuOpenOnFocusChange デフォルト値付与処理には、隣接する Search Command 追加処理(ST-34 / ST-34-asettings.test.ts:675-711)のような専用テストが見当たりません。既存ユーザー設定のマイグレーションは本 PR の重要な要素なので、migrate(oldData) に対して keepMenuOpenOnFocusChange が正しくデフォルト付与されることを検証するテストの追加を検討してください。

  3. 機能本体のゲーティングロジックにテストがない
    background_script.ts に追加された clearSelectionTextUnlessKeepOpen(344-353行目)、chrome.tabs.onActivated 内の keepMenuOpenOnFocusChange によるメニュークローズのスキップ(409-421行目)、chrome.sidePanel.onOpened 内の同様のガード(621行目付近)について、background_script.test.ts 側にオプション ON/OFF それぞれの挙動を検証するテストが追加されていないようです。本 PR の中核機能なので、最低限「ON のとき選択テキスト/メニューが維持される」「OFF のとき従来通りクリアされる」ケースのテストを追加すると安心です。

  4. PR 説明とコードのオプション名の不一致
    PR タイトル/概要では startupMethod.keepMenuOpenOnTabChange と記載されていますが、実装されているフィールド名は keepMenuOpenOnFocusChangetypes/index.ts:1831, defaultSettings.ts, SettingForm.tsx 等)です。動作的には window focus 変更・tab activation・side panel open をまとめて「focus change」として扱っているため命名自体は妥当に見えますが、PR 説明文と実装名が食い違っていると将来コードを検索する際に混乱の元になります。念のため PR 説明を実装に合わせて更新しておくとよいと思います。

  5. (軽微) WindowStackManager.cleanupEmptyLayers が変更なしでも常に書き込みを行うようになった
    windowStackManager.ts:171-179 で、以前は「空レイヤーがあった場合のみ」saveStack していたのに対し、リファクタ後は BgData.update() を常に呼ぶようになりました。BgData.updatebackgroundData.ts)は partial が {} でも無条件に Storage.set を呼び revision をインクリメントするため、実質的に「変化がなくても毎回 chrome.storage.session に書き込む」形になっています。現状 cleanupEmptyLayers は本体コードから呼び出されておらずテストのみで使われているため実害はなさそうですが、将来呼び出し箇所が増えた場合に無駄な書き込みが発生する点は留意しておくとよいでしょう(stack.length !== cleanedStack.length のときだけ BgData.update を呼ぶようガードすれば従来通りの挙動になります)。

  6. (スコープについての所感) BgData への revision / readyPromise 導入(backgroundData.ts)と WindowStackManager のアトミック更新化は、それ自体は理にかなった競合状態対策に見えますが、PR の主目的(メニュー維持オプションの追加)からするとやや大きめの構造変更です。「メニューを維持したまま複数タブ/ウィンドウにまたがる操作が増えることで、既存の read-modify-write 競合が顕在化しやすくなったための対策」であれば、その旨を PR 説明に一言加えていただけると、レビューアーが変更の必要性を判断しやすくなります。

良い点

  • chrome.sidePanel.onOpened が存在しない Chrome バージョンでも安全に動作するよう try/catch でガードしている点(background_script.ts 620行目付近)は丁寧です。
  • BgDatarevision によるスタール echo 対策や、init() 完了前の同期的デフォルト値提供(BgData.get()undefined を返さないようにする対応)は、backgroundData.test.ts で新規ケースがきちんとテストされています。
  • 全14言語のロケールファイルが揃っており、Option_keepMenuOpenOnFocusChange / _desc のキーも一貫した命名で追加されています。
  • settings.ts のマイグレーション処理により、既存ユーザーの設定にも安全にデフォルト値が付与される設計になっています(テスト不足の点は上記コメント参照)。

以上、よろしくお願いします。

@ujiro99
ujiro99 merged commit 0e02fcc into main Jul 15, 2026
2 of 4 checks passed
@ujiro99
ujiro99 deleted the feat/keep-menu-open-on-tab-change branch July 15, 2026 05:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant