Skip to content

Comments

Add sidePanel open mode#274

Merged
ujiro99 merged 30 commits intomainfrom
copilot/add-sidepanel-to-page-opening
Feb 21, 2026
Merged

Add sidePanel open mode#274
ujiro99 merged 30 commits intomainfrom
copilot/add-sidepanel-to-page-opening

Conversation

Copy link
Contributor

Copilot AI commented Feb 8, 2026

Adds OPEN_MODE.SIDE_PANEL to open URLs in Chrome's side panel API, enabling side-by-side viewing with the current page.

Core Implementation

  • New open mode: OPEN_MODE.SIDE_PANEL in shared constants and extension mappings
  • Side panel action: action/sidePanel.ts with IPC integration via BgCommand.openSidePanel
  • Chrome API integration: openSidePanel() in services/chrome.ts using chrome.sidePanel.setOptions() and chrome.sidePanel.open()

Permissions

  • Added "sidePanel" to manifest.json permissions array

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • www.google-analytics.com
    • Triggering command: /opt/hostedtoolcache/node/24.13.0/x64/bin/node /opt/hostedtoolcache/node/24.13.0/x64/bin/node --conditions node --conditions development /home/REDACTED/work/selection-command/selection-command/node_modules/tinypool/dist/entry/process.js +ujiro99@users.noreply.github.com> tnet/tools/git (dns block)
    • Triggering command: /opt/hostedtoolcache/node/24.13.0/x64/bin/node /opt/hostedtoolcache/node/24.13.0/x64/bin/node --conditions node --conditions development /home/REDACTED/work/selection-command/selection-command/node_modules/tinypool/dist/entry/process.js --global k/_temp/ghcca-node/node/bin/bash/var/lib/dpkg/info/libgpm2:amd64.list pull.rebase (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>ページの開き方へ'sidePanel'を追加する</issue_title>
<issue_description>リンクをsidePanelで表示可能にし、現在のページと並べて情報を閲覧できるようにする。

機能の要点

  • packages/extension/src/services/chrome.ts へ、指定したURLをsidePanelで表示できる機能を追加
  • packages/extension/src/action/ へ、sidePanelで表示するためのアクションを追加
  • sidePanelを表示後、もとのページにフォーカスが戻ったらsidePanelを自動で非表示にする。
    • この動作は、オプションにより有効・無効を切り替えられる</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 3 commits February 8, 2026 01:47
Co-authored-by: ujiro99 <677231+ujiro99@users.noreply.github.com>
Co-authored-by: ujiro99 <677231+ujiro99@users.noreply.github.com>
Co-authored-by: ujiro99 <677231+ujiro99@users.noreply.github.com>
Copilot AI changed the title [WIP] Add sidePanel functionality for page opening Add sidePanel open mode with focus-based auto-hide Feb 8, 2026
Copilot AI requested a review from ujiro99 February 8, 2026 01:56
@claude
Copy link

claude bot commented Feb 13, 2026

プルリクエストレビュー

このPRは、ChromeのサイドパネルAPIを使用してURLを開く新しい機能を追加しています。全体的な実装は良好ですが、いくつかの改善点とセキュリティ上の懸念があります。

✅ 良い点

  1. アーキテクチャ設計: 既存のアクションシステムに適切に統合されており、一貫性のあるコード構造になっています
  2. 型安全性: TypeScriptの型定義が適切に追加され、共有パッケージを通じて型の一貫性が保たれています
  3. 多言語対応: 11言語のlocalesファイルがすべて更新されています
  4. 設定の拡張性: sidePanelAutoHide設定がdefaultSettingsに適切に追加され、デフォルト値も妥当です

🔴 重大な問題

1. セキュリティ上の懸念: XSS脆弱性のリスク

// packages/extension/src/services/chrome.ts:611-614
chrome.sidePanel.setOptions({
  tabId: targetTabId,
  path: toUrl(url),  // ⚠️ ユーザー入力が直接pathに使用されている
  enabled: true,
})

問題点: toUrl()の結果が適切にサニタイズされているか確認が必要です。ユーザーが制御可能なsearchUrlselectionTextが含まれるため、悪意のあるスクリプトが注入される可能性があります。

推奨される修正:

  • chrome.sidePanel.setOptionsに渡す前にURLを検証
  • 許可されたスキーム(http/https)のみを受け入れる
  • javascript:data:スキームをブロック

2. リソースリークの可能性

// packages/extension/src/services/chrome.ts:630-653
export const closeSidePanel = async (tabId: number): Promise<void> => {
  const cleanup = async () => {
    try {
      await BgData.update((data) => ({
        sidePanelTabs: data.sidePanelTabs.filter((id) => id !== tabId),
      }))
      await chrome.sidePanel.setOptions({
        tabId: tabId,
        enabled: false,
      })
    } catch (e) {
      console.warn("Failed to cleanup side panel:", e)
    } finally {
      chrome.sidePanel.onClosed.removeListener(cleanup)  // ⚠️
    }
  }

  try {
    chrome.sidePanel.onClosed.addListener(cleanup)
    await chrome.sidePanel.close({ tabId: tabId })
  } catch (e) {
    console.warn("Failed to close side panel:", e)
  }
}

問題点:

  • chrome.sidePanel.close()が失敗した場合、リスナーが削除されずメモリリークの原因になります
  • エラーハンドリングが不十分で、例外が発生した場合にクリーンアップが実行されません

推奨される修正:

export const closeSidePanel = async (tabId: number): Promise<void> => {
  const cleanup = () => {
    chrome.sidePanel.onClosed.removeListener(cleanup)
    BgData.update((data) => ({
      sidePanelTabs: data.sidePanelTabs.filter((id) => id !== tabId),
    })).catch(console.error)
  }

  try {
    chrome.sidePanel.onClosed.addListener(cleanup)
    await chrome.sidePanel.close({ tabId: tabId })
  } catch (e) {
    chrome.sidePanel.onClosed.removeListener(cleanup)  // エラー時も確実に削除
    console.warn("Failed to close side panel:", e)
  }
}

⚠️ 改善が必要な点

3. 自動非表示機能のロジックの問題

// packages/extension/src/hooks/useSidePanelAutoClose.ts:20-28
const close = () => Ipc.send(BgCommand.closeSidePanel)

if (sidePanelVisible) {
  window.addEventListener("focus", close)
  window.addEventListener("click", close)  // ⚠️
  return () => {
    window.removeEventListener("focus", close)
    window.removeEventListener("click", close)
  }
}

問題点:

  • clickイベントでサイドパネルを閉じるのは予期しない動作になる可能性があります
  • ユーザーがページ内の任意の場所をクリックするたびにサイドパネルが閉じるのは使いにくい
  • issueの要件「もとのページにフォーカスが戻ったらsidePanelを自動で非表示にする」に対して、clickイベントは過剰です

推奨される修正: clickイベントリスナーを削除し、focusのみを使用する

4. background_script.tsでの自動非表示処理が存在しない

現在の実装では、useSidePanelAutoCloseフックがcontent scriptで使用されていますが、background scriptには対応するロジックがありません。issue要件の「もとのページにフォーカスが戻ったらsidePanelを自動で非表示にする」を実現するには、background scriptのchrome.windows.onFocusChangedリスナーにサイドパネル制御ロジックを追加する必要があります。

推奨される修正:

// packages/extension/src/background_script.ts
chrome.windows.onFocusChanged.addListener(async (windowId: number) => {
  // ... 既存のコード ...
  
  // Auto-hide side panel when focus returns to main window
  const settings = await enhancedSettings.get()
  if (settings.windowOption.sidePanelAutoHide) {
    const tabs = await chrome.tabs.query({ windowId })
    const bgData = BgData.get()
    for (const tab of tabs) {
      if (tab.id && bgData.sidePanelTabs.includes(tab.id)) {
        await closeSidePanel(tab.id)
      }
    }
  }
})

5. タブクリーンアップの欠落

// packages/extension/src/services/backgroundData.ts
export class BgData {
  // ...
  public sidePanelTabs: number[]
  // ...
}

サイドパネルが開かれているタブが閉じられたとき、sidePanelTabs配列から削除する処理がありません。これにより、閉じたタブのIDが配列に残り続けます。

推奨される修正:

// packages/extension/src/background_script.ts に追加
chrome.tabs.onRemoved.addListener((tabId: number) => {
  BgData.update((data) => ({
    sidePanelTabs: data.sidePanelTabs.filter((id) => id !== tabId),
  }))
})

6. エラーハンドリングの一貫性

// packages/extension/src/action/helper.ts:106-137
export const openSidePanel = (
  param: OpenSidePanelProps,
  sender: Sender,
): boolean => {
  const tabId = sender.tab?.id

  try {
    _openSidePanel({ ...param, tabId })
      .then(() => incrementCommandExecutionCount(tabId))
      .then(() => {
        if (tabId) {
          return BgData.update(...)
        }
      })
  } catch (error) {
    console.error("[ActionHelper.openSidePanel] Error:", error)
  }

  return false  // ⚠️ 常にfalseを返す
}

問題点:

  • try-catchブロック内でPromiseを返していますが、Promiseのrejectは捕捉されません
  • return falseは成功/失敗に関わらず返されます
  • コメントでは"tied to a user action"と述べていますが、非同期処理の結果を待たずにfalseを返しています

推奨される修正:

export const openSidePanel = (
  param: OpenSidePanelProps,
  sender: Sender,
): boolean => {
  const tabId = sender.tab?.id

  _openSidePanel({ ...param, tabId })
    .then(() => incrementCommandExecutionCount(tabId))
    .then(() => {
      if (tabId) {
        return BgData.update(...)
      }
    })
    .catch((error) => {
      console.error("[ActionHelper.openSidePanel] Error:", error)
    })

  return false  // Chrome API requires synchronous return for user gesture
}

📝 軽微な改善点

7. テストカバレッジの欠如

新機能に対する専用のテストファイルが見当たりません。以下のテストを追加することを推奨します:

  • sidePanel.test.ts: SidePanelアクションのユニットテスト
  • useSidePanelAutoClose.test.ts: フックのテスト
  • background scriptのサイドパネル関連ロジックのテスト

8. 型定義の曖昧性

// packages/extension/src/action/helper.ts:139
export const closeSidePanel = (_: any, sender: Sender) => {
  // ...
}

any型の使用は避けるべきです。適切な型を定義してください。

9. マジックナンバーの定数化

packages/extension/src/services/chrome.tsopenSidePanel関数で、タブIDの妥当性チェックがありません。undefinedチェックのみでは不十分で、無効なタブID(負の値など)もチェックすべきです。

📊 パフォーマンスに関する考察

特に重大なパフォーマンス上の懸念はありませんが、以下の点に注意:

  • BgData.updateの呼び出し頻度が増えるため、ストレージへの書き込みが頻繁に発生する可能性があります
  • sidePanelTabs配列の重複チェック(includes())は線形時間ですが、配列が小さいため問題ありません

🎯 総合評価

実装の品質: 6/10

この機能は有用で、既存のアーキテクチャに適切に統合されていますが、セキュリティ上の懸念、リソースリークの可能性、およびロジックの不完全性があります。特に、XSS脆弱性のリスクとメモリリークの可能性は、マージ前に必ず修正すべきです。

✅ マージ前に必須の修正

  1. セキュリティ: URLのサニタイズとバリデーションを追加
  2. リソース管理: closeSidePanelのリスナークリーンアップを修正
  3. 機能完全性: background scriptに自動非表示ロジックを追加
  4. クリーンアップ: タブ削除時のsidePanelTabs配列の更新

💡 推奨される追加修正

  1. useSidePanelAutoCloseからclickイベントを削除
  2. テストカバレッジの追加
  3. any型の置き換え

修正が完了したら、もう一度レビューさせていただきます。

@claude
Copy link

claude bot commented Feb 16, 2026

Pull Request Review: サイドパネル機能の追加

このPRでは、Chrome拡張機能にサイドパネル表示機能を追加し、自動非表示機能を実装しています。全体的に良好な実装ですが、いくつか改善すべき点を見つけました。


🟢 良い点

アーキテクチャ

  • 適切な責務分離: sidePanel.tschrome.tshelper.tsで機能が明確に分離されている
  • 型の一貫性: SharedパッケージでOPEN_MODEを拡張し、適切に型付けされている
  • IPC通信の活用: 既存のIPCパターンに従って実装されている

実装の堅牢性

  • エラーハンドリング: try-catchブロックで適切にエラーをキャッチし、ログ出力している (chrome.ts:598-654)
  • クリーンアップ処理: onClosedリスナーで適切にリソースを解放している (chrome.ts:632-646)
  • タブ追跡管理: BgDataでsidePanelTabsを管理し、重複チェックを実施 (helper.ts:126-128)

🔴 重大な問題

1. 競合状態のリスク (helper.ts:106-137)

openSidePanel関数がfalseを返していますが、非同期処理を実行しています。これにより、IPCの応答処理に不整合が発生する可能性があります。

現在のコード:

export const openSidePanel = (
  param: OpenSidePanelProps,
  sender: Sender,
): boolean => {
  // ...async operations...
  return false  // ❌ 非同期処理を開始しているのにfalseを返している
}

推奨される修正:

export const openSidePanel = (
  param: OpenSidePanelProps,
  sender: Sender,
  response: (res: boolean) => void,
): boolean => {
  const tabId = sender.tab?.id
  
  _openSidePanel({ ...param, tabId })
    .then(() => incrementCommandExecutionCount(tabId))
    .then(() => {
      if (tabId) {
        return BgData.update((data) => ({
          sidePanelTabs: data.sidePanelTabs.includes(tabId)
            ? data.sidePanelTabs
            : [...data.sidePanelTabs, tabId],
        }))
      }
    })
    .then(() => response(true))
    .catch((error) => {
      console.error('[ActionHelper.openSidePanel] Error:', error)
      response(false)
    })
  
  return true  // ✅ 非同期処理を示すためtrueを返す
}

2. useSidePanelAutoCloseの論理エラー (useSidePanelAutoClose.ts:6-31)

このフックには複数の問題があります:

a) イベントリスナーのタイミング問題

サイドパネルが表示された直後にfocus/clickイベントリスナーを追加していますが、これにより即座にサイドパネルが閉じられる可能性があります。

b) ウィンドウフォーカスイベントの誤解

window.addEventListener('focus')はサイドパネル内でのフォーカスを検知するため、メインページへのフォーカス変更を検知できません。

c) クリックイベントの不必要な使用

すべてのクリックでサイドパネルを閉じるのは、UX的に問題があります。

推奨される修正:
この機能はcontent script側ではなく、background script側で実装すべきです:

// background_script.tsに追加
chrome.windows.onFocusChanged.addListener(async (windowId: number) => {
  // 既存のコード...
  
  // Side panel auto-hide機能
  const settings = await enhancedSettings.get()
  if (settings.windowOption.sidePanelAutoHide) {
    const [currentTab] = await chrome.tabs.query({ 
      active: true, 
      windowId: windowId 
    })
    
    if (currentTab?.id) {
      const bgData = BgData.get()
      if (bgData.sidePanelTabs.includes(currentTab.id)) {
        await closeSidePanel(currentTab.id)
      }
    }
  }
})

そしてuseSidePanelAutoClose.tsは削除するか、単純な状態管理フックに変更すべきです。


🟡 中程度の問題

3. テストカバレッジの不足

新しく追加された機能に対する専用のテストがありません:

  • sidePanel.tsのテストなし
  • useSidePanelAutoClose.tsのテストなし
  • openSidePanel/closeSidePanelの統合テストなし

推奨アクション:
最低限、以下のテストを追加してください:

  • サイドパネルの開閉が正しく動作することを確認するユニットテスト
  • BgDataのsidePanelTabsが正しく更新されることを確認するテスト
  • 設定値sidePanelAutoHideに基づいて動作が変わることを確認するテスト

4. タブURLの変更時のクリーンアップ (background_script.ts)

chrome.tabs.onUpdatedでURL変更を検知してクリーンアップする処理が見当たりません。ユーザーが別のURLに遷移した場合、sidePanelTabsに古いタブIDが残る可能性があります。

推奨される修正:

chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
  if (changeInfo.url) {
    // URL変更時にsidePanelTabsからタブIDを削除
    BgData.update((data) => ({
      sidePanelTabs: data.sidePanelTabs.filter((id) => id \!== tabId),
    }))
  }
})

5. chrome.sidePanel.setOptions()のエラーハンドリング不足 (chrome.ts:612-616)

setOptionsの呼び出しにtry-catchがなく、失敗時の処理が不明確です。

推奨される修正:

try {
  await chrome.sidePanel.setOptions({
    tabId: targetTabId,
    path: toUrl(url),
    enabled: true,
  })
  await chrome.sidePanel.open({ tabId: targetTabId })
} catch (error) {
  console.error('Failed to open side panel:', error)
  throw error
}

🟢 軽微な改善提案

6. 型定義の改善

OpenSidePanelPropstabIdがオプショナルですが、実際には必須です (chrome.ts:603-609)。

推奨される修正:

export type OpenSidePanelProps = {
  url: string | UrlParam
  tabId: number  // オプショナルを削除
}

7. マジックナンバーの定数化

closeSidePanelの onClosed リスナーのクリーンアップパターンは良好ですが、コメントで意図を明確にすると良いでしょう。

8. 国際化メッセージの確認

多言語対応ファイルに追加されたメッセージが適切に翻訳されているか確認してください。特に自動翻訳を使用している場合は、ネイティブスピーカーによるレビューを推奨します。


🔒 セキュリティ考慮事項

問題なし: URLのサニタイズはtoUrl関数で適切に処理されています。


📊 パフォーマンス考慮事項

概ね良好: BgData.updateの使用頻度は適切で、不要なストレージ操作はありません。

⚠️ 注意点: useSidePanelAutoCloseがwindow.addEventListener('click')を使用している場合、すべてのクリックイベントを処理するためパフォーマンスに影響を与える可能性があります。


📝 まとめ

必須の修正:

  1. openSidePanelの戻り値と応答処理を修正
  2. useSidePanelAutoCloseの実装をbackground scriptに移動
  3. chrome.tabs.onUpdatedでのクリーンアップ処理を追加

強く推奨:

  1. テストカバレッジの追加
  2. エラーハンドリングの強化
  3. 型定義の改善

このPRは有用な機能追加ですが、上記の問題を修正してからマージすることを強く推奨します。特に1と2は競合状態やUX問題を引き起こす可能性があるため、優先的に対処してください。


レビューは packages/extension 内のコードを中心に実施しました。CLAUDE.mdの規約に従い、TypeScriptのベストプラクティスと Chrome 拡張機能の Manifest V3 の制約を考慮しています。

@claude
Copy link

claude bot commented Feb 18, 2026

PR #274 コードレビュー

サイドパネル機能の実装についてレビューしました。全体的に構造は適切ですが、いくつかの問題点と改善提案があります。


🔴 重要な問題点

1. openSidePanelsetOptions が await されていない

ファイル: packages/extension/src/services/chrome.ts

// 現在のコード(問題あり)
chrome.sidePanel.setOptions({
  tabId: targetTabId,
  path: toUrl(url),
  enabled: true,
})

// Open the side panel
await chrome.sidePanel.open({ tabId: targetTabId })

setOptions() は Promise を返すにも関わらず await していません。これにより、オプションが設定される前に open() が呼ばれる競合状態が発生する可能性があります。

// 修正案
await chrome.sidePanel.setOptions({
  tabId: targetTabId,
  path: toUrl(url),
  enabled: true,
})
await chrome.sidePanel.open({ tabId: targetTabId })

2. closeSidePanelonClosed イベントリスナーの重複登録問題

ファイル: packages/extension/src/services/chrome.ts

export const closeSidePanel = async (tabId: number): Promise<void> => {
  const cleanup = async () => { ... }
  
  try {
    chrome.sidePanel.onClosed.addListener(cleanup)  // ← 毎回新しいクロージャを登録
    await chrome.sidePanel.close({ tabId: tabId })
  } catch (e) { ... }
}

cleanup は毎回新しいクロージャとして生成されるため、removeListener が正常に機能しません(同じ参照でないと削除できない)。また、chrome.sidePanel.onClosed の存在自体が Chrome の公式 API にないため、実行時エラーになる可能性があります。


3. closeSidePanelsidePanelAutoHide 設定でのみ呼ばれ、フォーカス変更検知が未実装

ファイル: packages/extension/src/action/helper.ts

PR の説明では「ウィンドウのフォーカスが変わったらサイドパネルを自動非表示」とありますが、chrome.windows.onFocusChanged リスナーが background_script.ts に実装されていません。closeSidePanel は content script からの IPC 経由でのみ呼ばれる設計になっており、フォーカス変更時の自動非表示が機能しません。


4. getTabId の戻り値変更による既存動作への影響

ファイル: packages/extension/src/background_script.ts

// 変更前
const getTabId = (...) => {
  response(sender.tab?.id)
  return false  // 同期応答
}

// 変更後
  return true  // 非同期応答として扱われる

return true は「応答チャンネルを非同期に保持する」ことを意味します。getTabId は同期的に response() を呼んでいるため、return false が正しい動作です。この変更により既存の Ipc.getTabId() の挙動が変わる可能性があります。


🟡 中程度の問題点

5. sidePanelDetector.ts のロジックが不完全

ファイル: packages/extension/src/services/sidePanelDetector.ts

export const isSidePanel = (tabId, activeTabId): boolean => {
  if (tabId != null) return false // In sidePanel, tabId is null.
  if (!activeTabId) return false
  const bgData = BgData.get()
  if (!bgData.sidePanelTabs.includes(activeTabId)) return false
  return true
}

サービスワーカー再起動時に BgData が初期化されると sidePanelTabs が空になり、実際にサイドパネルが開いていても false を返す可能性があります。また、content script コンテキストから BgData.get() を呼ぶと、background script と共有されていないローカルインスタンスを参照してしまいます(BgData はシングルトンですが、プロセスが異なるため)。

6. defaultSettingssidePanelAutoHide デフォルト値の不一致

ファイル: packages/extension/src/services/option/defaultSettings.ts

// emptySettings ではデフォルト false
export const emptySettings = {
  windowOption: { sidePanelAutoHide: false },
}

// default export ではデフォルト false
export default {
  windowOption: { sidePanelAutoHide: false },
}

PR の説明では「デフォルト: enabled(true)」とありますが、コードでは false になっています。意図的であれば PR の説明を修正してください。

7. openSidePaneltoUrl() への型不整合

ファイル: packages/extension/src/services/chrome.ts

export type OpenSidePanelProps = {
  url: string | UrlParam  // UrlParam 型も受け付ける
  tabId?: number
}

// しかし sidePanel.setOptions の path には string が必要
chrome.sidePanel.setOptions({
  path: toUrl(url),  // toUrl が string を返すか確認が必要
})

chrome.sidePanel.setOptionspath は拡張機能内の相対パスを想定しており、外部 URL(https://...)を直接指定できません。外部 URL を表示するには <iframe> 経由か別の方法が必要です。

これは機能の根本的な制約です: Chrome の Side Panel API では、path に指定できるのは拡張機能内のリソース(例: sidepanel.html)のみです。外部 URL を直接サイドパネルに表示することはできません。


🟢 改善提案

8. useSidePanelNavigationactiveTabId 状態管理

ファイル: packages/extension/src/hooks/useSidePanelNavigation.ts

// isSidePanelPage の判定に activeTabId が必要だが、
// 2つの useEffect で依存関係が分離されている
useEffect(() => {
  Ipc.getActiveTabId().then((activeTabId) => {
    setIsSidePanelPage(isSidePanel(tabId, activeTabId))
    setActiveTabId(activeTabId)  // ← 先に isSidePanelPage が設定される
  })
}, [tabId])

setIsSidePanelPagesetActiveTabId を同時に設定しているにも関わらず、クリックハンドラが activeTabId を使うのに isSidePanelPage に依存しています。activeTabId を直接 isSidePanel の結果から分離して管理する方が明確です。

9. chrome.tabs.onUpdated でのサイドパネル URL 変更追跡が欠如

PR 説明には「URL 変更時のクリーンアップ」とありますが、chrome.tabs.onUpdated リスナーが background_script.ts に追加されていません。ユーザーがタブで別の URL に移動した際にサイドパネルが残留する可能性があります。

10. テストの setTimeout による非同期待機

ファイル: packages/extension/src/action/helper.test.ts

// NSP-06, NSP-07 などで使用
await new Promise((resolve) => setTimeout(resolve, 100))

setTimeout による待機はフレイキーテストの原因になります。vi.waitFor()flushPromises() などの確定的な待機手法を使用することを推奨します。


✅ 良い点

  • URL バリデーション: javascript:data: プロトコルを適切に拒否している
  • 型安全性: NavigateSidePanelProps など適切な型定義がある
  • マイグレーション: migrate0_14_3 で既存ユーザーの設定を適切に移行している
  • 多言語対応: 11言語すべてに翻訳が追加されている
  • i18nの修正: 複数の言語ファイルで誤ってネストされていたキーが正しい位置に修正されている

⚠️ 最重要の確認事項

Chrome の Side Panel API の制約について確認が必要です: chrome.sidePanel.setOptions({ path: externalUrl }) は外部 URL(https://example.com)を受け付けません。Extension の side panel は拡張機能内の HTML ファイルしか表示できません。もし外部 URL を表示したい場合は、拡張機能の HTML ファイル内に <iframe> を使用するアプローチが必要です。この設計の根本的な部分を確認・修正することを強く推奨します。

@claude
Copy link

claude bot commented Feb 19, 2026

PR レビュー: Add sidePanel open mode with focus-based auto-hide

Note: This is a DRAFT PR from an automated agent. The following feedback is intended to help finalize the implementation.


🐛 バグ / 潜在的な問題

1. openSidePanel 内で setOptions()await されていない

ファイル: packages/extension/src/services/chrome.ts

// 現在のコード(問題あり)
chrome.sidePanel.setOptions({
  tabId: targetTabId,
  path: toUrl(url),
  enabled: true,
})  // ← await なし
await chrome.sidePanel.open({ tabId: targetTabId })

setOptions() の完了を待たずに open() を呼び出しているため、パスが設定される前にパネルが開く可能性があります。await を追加してください。

// 修正案
await chrome.sidePanel.setOptions({
  tabId: targetTabId,
  path: toUrl(url),
  enabled: true,
})
await chrome.sidePanel.open({ tabId: targetTabId })

2. getTabId の return 値が不必要に変更されている

ファイル: packages/extension/src/background_script.ts

// 変更前
const getTabId = (...) => {
  response(sender.tab?.id)
  return false  // 同期レスポンスを示す
}

// 変更後
const getTabId = (...) => {
  response(sender.tab?.id)
  return true  // 非同期レスポンスを示す(だが response は同期的に呼ばれている)
}

Chrome の message passing では true を返すと「非同期でレスポンスを送る」ことを意味し、メッセージチャンネルをオープンのままにします。しかし getTabIdresponse() を同期的に呼び出しているため、return false のままにすべきです。この変更は getActiveTabId(本当に非同期)追加時の誤りと思われます。


3. Auto-hide トリガーのメカニズムが不明確

PR タイトルは "focus-based auto-hide" となっていますが、差分内に chrome.windows.onFocusChangedchrome.tabs.onActivated などのリスナーが見当たりません。

BgCommand.closeSidePanel はいつ、どこから送信されますか? action/helper.tscloseSidePanel は設定の sidePanelAutoHide をチェックしていますが、そのコマンドを送信するトリガーが実装されていないようです。フォーカス変更イベントの実装が欠けているか、説明が必要です。


⚠️ コード品質の問題

4. openSidePanel ヘルパー内のエラーハンドリング

ファイル: packages/extension/src/action/helper.ts

export const openSidePanel = (param, sender) => {
  try {
    _openSidePanel({ ...param, tabId })
      .then(() => incrementCommandExecutionCount(tabId))
      .then(() => { /* BgData.update */ })
    // ↑ Promise が return されず、.catch() もない
  } catch (error) {
    // try/catch は同期エラーしか捕捉できない
    console.error("[ActionHelper.openSidePanel] Error:", error)
  }
  return false
}

_openSidePanel() は Promise を返しますが、try/catch で囲っても非同期エラーは捕捉できません。.catch() を Promise チェーンに追加するか、async/await に書き換えてください。


5. sidePanelAutoHide のデフォルト値の不整合

ファイル: packages/extension/src/services/option/defaultSettings.ts

windowOption: {
  sidePanelAutoHide: false,  // デフォルト: 無効
}

PR 説明には "default: enabled" と記載されていますが、コードでは false(無効)になっています。意図を明確にし、ドキュメントかコードのどちらかを修正してください。


🔒 セキュリティ

6. URL プロトコルバリデーションの不完全性

ファイル: packages/extension/src/hooks/useSidePanelNavigation.ts

javascript:data: プロトコルはフィルタリングされていますが、vbscript: も同様に危険です(IE レガシーですが念のため)。また、Chrome 拡張機能のコンテキストでは file: プロトコルへのナビゲーションも制限されるべき場合があります。

許可リスト方式(http:https: のみ許可)の検討をお勧めします:

const ALLOWED_PROTOCOLS = ['http:', 'https:']
if (!ALLOWED_PROTOCOLS.includes(urlObj.protocol)) {
  console.warn("[navigateSidePanel] Blocked protocol:", urlObj.protocol)
  return
}

📝 その他の指摘

7. .gitignore への不要な変更

.git ディレクトリ自体は Git によって自動的に無視されるため、.gitignore に追加する必要はありません。エージェントによる誤った変更と思われます。削除してください。

8. ロケールファイルの修正がスコープ外

itkoms ロケールファイルの JSON 構造修正は本機能と無関係です。別 PR に分離するか、既存バグの修正として明示的に記載してください。

9. openSidePanel のテストカバレッジ不足

action/helper.tsopenSidePanel 関数に対するテストが追加されていません。少なくとも以下のケースをカバーしてください:

  • tabId が存在しない場合
  • _openSidePanel が失敗した場合
  • 正常ケース(sidePanelTabs に追加されること)

✅ 良い点

  • navigateSidePanel の URL バリデーションロジック(isSidePanel の判定が二段階になっているのは適切)
  • closeSidePanel でのクリーンアップ処理(onClosed リスナーを finally で解除している)
  • BgData への watch() メソッド追加(リアクティブな状態管理の改善)
  • タブ削除時のクリーンアップ(chrome.tabs.onRemoved リスナー)
  • 設定マイグレーション(migrate0_14_3)の実装
  • sidePanelDetector.test.tsuseSidePanelNavigation.test.ts のテスト追加

優先度まとめ

優先度 項目
🔴 高 setOptions()await 欠落(バグ)
🔴 高 Auto-hide トリガーの実装欠如または説明不足
🟡 中 getTabId の return 値(セマンティクス違反)
🟡 中 Promise チェーンのエラーハンドリング
🟡 中 sidePanelAutoHide デフォルト値の不整合
🟢 低 URL プロトコル許可リスト方式への変更
🟢 低 .gitignore/.git エントリ削除
🟢 低 テストカバレッジの追加

@ujiro99 ujiro99 changed the title Add sidePanel open mode with focus-based auto-hide Add sidePanel open mode Feb 19, 2026
@claude
Copy link

claude bot commented Feb 19, 2026

PR レビュー: Add sidePanel open mode

全体的な実装の方向性は良好です。Chrome Side Panel API との統合、IPC 通信の拡張、多言語対応が適切に行われています。ただし、いくつか重要な問題点があります。


クリティカルバグ

1. openSidePanel ヘルパーでの response(true) 未呼び出し問題

packages/extension/src/action/helper.ts

tabId が設定されている(通常ケース)場合、BgData.update() が成功しても response(true) が呼ばれません。IPC チャンネルが永遠に開いたままになります。

現在のコード:

.then(() => {
  if (tabId) {
    return BgData.update(...)  // BgData更新後、response(true) が呼ばれない
  }
  response(true)  // これは !tabId の場合のみ実行される
})

修正案:

.then(() => {
  if (tabId) {
    return BgData.update((data) => ({
      sidePanelTabs: data.sidePanelTabs.includes(tabId)
        ? data.sidePanelTabs
        : [...data.sidePanelTabs, tabId],
    }))
  }
})
.then(() => {
  response(true)  // 常にここで呼ぶ
})

2. chrome.sidePanel.setOptions のレースコンディション

packages/extension/src/services/chrome.ts

setOptions() を await しないまま open() を呼び出すため、パネルが開く前に path が設定されていない可能性があります。ユーザージェスチャーの制約で同期的に呼ぶ必要がある点は理解できますが、Promise が pending な状態で open() が先行する可能性があります。実際の Chrome API の挙動上、同一イベントループ内であれば問題ない可能性もありますが、理由を明示的にコメントで補足することを推奨します。


3. テストでの response コールバック未渡し

packages/extension/src/action/helper.test.ts

NSP-06, NSP-07, NSP-08 では navigateSidePanel(param, sender) を2引数で呼んでいますが、関数の定義は3引数 (param, sender, response) を要求しています。

非同期チェーン内で response(true) が呼ばれた際に TypeError: response is not a function が発生し、unhandled promise rejection となります。テスト自体は通過するかもしれませんが、これはバグを隠蔽しています。

修正案:

const response = vi.fn()
const result = navigateSidePanel(param, sender, response)
// ...
await new Promise((resolve) => setTimeout(resolve, 100))
expect(response).toHaveBeenCalledWith(true)

機能未実装

4. サイドパネルの自動非表示機能が実装されていない

Issue の要件:

sidePanelを表示後、もとのページにフォーカスが戻ったらsidePanelを自動で非表示にする。

現在の実装では BgCommand.closeSidePanel と sidePanelAutoHide 設定は存在しますが、コンテンツスクリプト側でフォーカス/visibility イベントを検知して closeSidePanel を送信するコードがありません。useSidePanelNavigation.ts にもこのロジックがありません。また、設定UIへの sidePanelAutoHide の追加も見当たりません。


設計上の懸念点

5. updateSidePanelUrl のナビゲーション動作

chrome.sidePanel.setOptions() はパネルが次に開くときの設定を変更するAPIです。既に開いているパネルの現在表示URLをこの方法でナビゲートできるか確認が必要です。もし機能しない場合、リンクのインターセプト機能が期待通りに動作しません。

6. PAGE_ACTION_OPEN_MODE への SIDE_PANEL 追加

packages/shared/src/constants/open-mode.ts

Page Action はブラウザ自動化シーケンスであり、URLを開くモードとは異なる概念です。SIDE_PANEL を Page Action のオープンモードとして使用するユースケースが明確でないため、意図的な追加かどうか確認が必要です。

7. BgData.watch が未使用

追加された BgData.watch メソッドはPR内で使用されていません。将来の実装のために追加された場合はコメントで補足するか、実際に使用するまで追加を保留することを推奨します。


軽微な指摘

  • packages/extension/src/services/chrome.ts のコメントアウトされたデバッグコード // console.debug("[updateSidePanelUrl] Updated:", { tabId, url }) は削除を推奨します。
  • .gitignore への .git 追加は不要です(git が自動的に除外します)。
  • イタリア語・韓国語・マレー語ロケールファイルの修正(既存の壊れた JSON 構造の修正)はPRの説明にも記載することを推奨します。

良い点

  • Chrome sidePanel パーミッションの追加が適切
  • URL バリデーション(javascript:, data: プロトコルのブロック)が実装されている
  • タブ削除時のクリーンアップ(chrome.tabs.onRemoved)が適切
  • 設定のマイグレーション(v0.14.3)が適切に実装されている
  • 11言語への翻訳追加
  • @types/chrome のバージョンアップ対応(TabChangeInfo → OnUpdatedInfo 等)
  • テストカバレッジが充実している(NSP-01〜08, SPN-01〜07, SPD-01〜04)

まとめ

優先度の高い修正事項:

  1. response(true) が成功時に呼ばれない — IPC が応答なしで止まる
  2. テストで response コールバックが渡されていない — unhandled rejection が発生
  3. 自動非表示機能が未実装 — Issueの主要要件を満たしていない
  4. updateSidePanelUrl の動作確認 — 既存の開いているパネルのナビゲーションが正しく機能するか検証が必要

@claude
Copy link

claude bot commented Feb 19, 2026

PR レビュー: Add sidePanel open mode (#274)

Chrome Side Panel APIを使ったサイドパネル開きモードの実装をレビューしました。全体的に設計は適切ですが、いくつか改善点があります。


🔴 重大な問題

1. AI設定ファイルがコミットされている

.claude/settings.local.json.serena/project.yml がこのPRに含まれています。これらはAIアシスタントのローカル設定ファイルであり、リポジトリにコミットすべきではありません。

対処: これらのファイルをコミットから除外し、.gitignore に追加してください。

# AI assistant local settings
.claude/settings.local.json
.serena/

🟡 重要な問題

2. Ipc.getActiveTabId() のエラーハンドリングが欠落

useSidePanelNavigation.ts の以下の箇所にエラーハンドリングがありません。

// 現状 (問題あり)
useEffect(() => {
  Ipc.getActiveTabId().then((id) => {
    setActiveTabId(id)
  })
}, [tabId])

// 修正案
useEffect(() => {
  Ipc.getActiveTabId()
    .then((id) => {
      setActiveTabId(id)
    })
    .catch((err) => {
      console.error("[useSidePanelNavigation] Failed to get active tab id:", err)
    })
}, [tabId])

3. isSidePanel() の呼び出しに冗長な null チェック

useSidePanelNavigation.ts の以下のチェックは冗長です。isSidePanel() 内で activeTabId の null/undefined チェックが既に行われています。

// 現状 (冗長)
const isSidePanelPage = activeTabId !== null && isSidePanel(tabId, activeTabId)

// 修正案
const isSidePanelPage = isSidePanel(tabId, activeTabId)

4. sidePanel.ts アクションのテストが不足

packages/extension/src/action/sidePanel.ts に対応するユニットテストが見当たりません。少なくとも以下のケースをカバーしてください:

  • searchUrl が無効な場合に早期リターンすること
  • 正常に Ipc.send(BgCommand.openSidePanel, ...) が呼ばれること
  • toUrl() が例外を投げた場合に re-throw されること

🟢 軽微な問題・改善提案

5. target="_top" の挙動について

useSidePanelNavigation.ts_top をインターセプトしていないのは意図的だと思いますが、サイドパネルには「最上位ブラウジングコンテキスト」が存在しないため、予期しない動作を招く可能性があります。コメントに意図を明記することを推奨します。

// _blank, _parent, _top: Let the browser handle these (open in new context)
if (target === "_blank" || target === "_parent" || target === "_top") {
  return
}

6. sidePanelDetector.ts のコメントを明確化

// 現状
if (tabId != null) return false // In sidePanel, tabId is null.

// 改善案
if (tabId != null) return false // Side panel context has no tabId (it's null/undefined)

7. NavigateSidePanelProps.tabIdnull ケースの処理確認

export type NavigateSidePanelProps = {
  url: string
  tabId: number | null  // ← null の場合の background handler での処理を確認
}

バックグラウンドスクリプトの navigateSidePanel ハンドラで tabIdnull の場合の処理が明示的に行われているか確認してください。


✅ 良い点

  • URL検証: isValidUrl()http:/https: プロトコルのみ許可しており、セキュリティ上適切
  • キャプチャフェーズ: クリックイベントをキャプチャフェーズで登録し、他のハンドラより先に処理できるようにしている
  • タブ削除時のクリーンアップ: chrome.tabs.onRemovedsidePanelTabs/sidePanelUrls を適切にクリーンアップしている
  • テストカバレッジ: sidePanelDetectoruseSidePanelNavigation に対して複数のエッジケースをカバーするテストが追加されている
  • 国際化: 全11言語へのメッセージ追加が行われている

まとめ

.claude/settings.local.json などのAIツール設定ファイルのコミットは必ず対処が必要です。その他の問題については、エラーハンドリングの追加と sidePanel.ts アクションのテスト追加を優先してください。

機能設計自体は適切で、Chrome Side Panel APIの正しい使い方に沿った実装になっています。

@claude
Copy link

claude bot commented Feb 21, 2026

コードレビュー: Add sidePanel open mode

全体として、Chrome Side Panel APIを活用した新しいオープンモードの追加は良い方向性です。IPC パターンの一貫した使用、セキュリティ検証(プロトコルフィルタリング)、テストカバレッジの追加なども評価できます。ただし、動作に影響する可能性があるいくつかの問題を指摘します。


🔴 Critical

1. sidePanelDetector.tsBgData.get() はコンテントスクリプトで機能しない

// src/services/sidePanelDetector.ts
export const isSidePanel = (...): boolean => {
  ...
  const bgData = BgData.get()  // ← 問題
  if (!bgData.sidePanelTabs.includes(activeTabId)) return false
  return true
}

BgData はインメモリシングルトンです。バックグラウンドスクリプト(service worker)でのみ sidePanelTabs が実際のデータで更新されます。コンテントスクリプト(useSidePanelNavigation が動作する環境)のJSコンテキストでは BgData.instance は初期化されておらず、BgData.get()BgData.init() により sidePanelTabs: [] の空インスタンスが返されます。

その結果、isSidePanel() は常に false を返し、useSidePanelNavigation のクリックリスナーは一切機能しません。

修正案: BgData のデータを chrome.storage.session から動的に取得するか、IPCでバックグラウンドに問い合わせる方式に変更する必要があります。


🟠 Important

2. chrome.sidePanel.setOptions({ path }) は外部URLを受け付けない可能性がある

// src/services/chrome.ts
chrome.sidePanel.setOptions({
  tabId: targetTabId,
  path: toUrl(url),  // 外部URLを渡している
  enabled: true,
})

Chrome SidePanel API の path パラメータは、拡張機能パッケージ内の相対パス(例: "panel.html")を期待しています。https://example.com/... のような外部URLを渡しても意図通りに動作しない可能性があります。外部URLをサイドパネルで表示するには、iframe でラップする拡張機能内のHTMLページが必要です。実装が期待通り動作することを実機で確認済みでしょうか?

3. setOptionsopen の実行順序の問題

// src/services/chrome.ts
// Do not await here because sidePanel.open() must be executed within a user gesture.
chrome.sidePanel.setOptions({  // await なし
  tabId: targetTabId,
  path: toUrl(url),
  enabled: true,
})
// Open the side panel
await chrome.sidePanel.open({ tabId: targetTabId })  // await あり

setOptions を await しないまま open を呼び出しているため、setOptions の完了前に open が実行されてパネルが間違ったURLで開く可能性があります。コメントに「user gesture のため await しない」とありますが、background script の message handler 内で両方 await しても user gesture の制約は維持されます。なぜなら、Chrome 拡張機能のメッセージパッシングはユーザージェスチャーをスレッドします。


🟡 Minor

4. .gitignore.git を追加している

+.git

.git ディレクトリはgitによって追跡されることは決してないため、.gitignore への追加は無意味です。AIエージェントが誤って追加したと思われます。削除してください。

5. background_script.ts のフォーマット崩れ

-;(async () => {
+  ; (async () => {

IIFE のインデントとセミコロンの位置が変更されていますが、これは意図的なものではなく、ファイル内の他のスタイルと一致していません。

6. テストの afterEach クリーンアップが機能していない

// src/hooks/useSidePanelNavigation.test.ts
afterEach(() => {
  // この除去は機能しない(関数参照が異なるため)
  document.removeEventListener("click", () => {}, { capture: true })
})

removeEventListener は同じ関数参照が必要です。毎回 () => {} を渡すと別の関数参照になるため、フックが追加したリスナーは削除されません。renderHook のアンマウントによる cleanup に依存する方が適切です。

7. helper.tscloseSidePanelany 型を使用

export const closeSidePanel = (
  _: any,  // ← 要改善
  sender: Sender,
  ...

他のハンドラーと同様に _: unknown を使用してください。

8. helper.tsopenSidePanelcloseSidePanel のテストが不足

helper.test.tsnavigateSidePanel のみをテストしています。openSidePanel(BgData 更新ロジックを含む)と closeSidePanelsidePanelAutoHide ロジック)のテストが必要です。


✅ 良い点

  • navigateSidePanel での javascript: / data: プロトコルのブロック(セキュリティ対応)
  • useSidePanelNavigation での http:/https: プロトコルのホワイトリスト方式
  • chrome.tabs.onRemoved での sidePanelTabs のクリーンアップ
  • settings.ts の migration 追加(windowOption の後方互換性確保)
  • chrome.tabs.TabChangeInfochrome.tabs.OnUpdatedInfo への型更新
  • it/messages.json 等の既存の壊れたロケールファイルの修正

補足

SearchCommand.openModeOPEN_MODE.BACKGROUND_TAB が追加されていますが(shared/types/command.ts)、これは以前から欠けていた既存バグの修正でしょうか?意図的な変更であれば問題ありません。

PR がドラフト状態のため、上記の問題(特に #1#2)を解決した上でのレビュー完了を推奨します。

@codecov
Copy link

codecov bot commented Feb 21, 2026

Codecov Report

❌ Patch coverage is 44.36090% with 222 lines in your changes missing coverage. Please review.
✅ Project coverage is 17.79%. Comparing base (8a45110) to head (47c21f7).
⚠️ Report is 151 commits behind head on main.

Files with missing lines Patch % Lines
packages/extension/src/services/chrome.ts 3.57% 81 Missing ⚠️
packages/extension/src/action/helper.ts 46.23% 50 Missing ⚠️
packages/extension/src/background_script.ts 35.55% 29 Missing ⚠️
packages/extension/src/action/sidePanel.ts 20.68% 23 Missing ⚠️
packages/extension/src/services/backgroundData.ts 14.28% 6 Missing ⚠️
...ages/extension/src/hooks/useSidePanelNavigation.ts 91.80% 5 Missing ⚠️
...rc/components/option/field/OpenModeToggleField.tsx 0.00% 4 Missing ⚠️
packages/extension/src/services/ipc.ts 62.50% 3 Missing ⚠️
packages/extension/src/action/index.ts 0.00% 2 Missing ⚠️
packages/extension/src/components/Popup.tsx 0.00% 2 Missing ⚠️
... and 17 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #274      +/-   ##
==========================================
+ Coverage   17.45%   17.79%   +0.34%     
==========================================
  Files         304      307       +3     
  Lines       28068    28408     +340     
  Branches     1147     1185      +38     
==========================================
+ Hits         4900     5056     +156     
- Misses      23168    23352     +184     

☔ View full report in Codecov by Sentry.
📢 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.

@ujiro99 ujiro99 marked this pull request as ready for review February 21, 2026 02:25
@claude
Copy link

claude bot commented Feb 21, 2026

コードレビュー

全体的に、Chrome Side Panel APIの統合として丁寧に実装されており、テストカバレッジも充実しています。ただし、いくつか対処が必要な点があります。


Critical: chrome.sidePanel.setOptions の path に外部URLを指定している可能性

packages/extension/src/services/chrome.ts

Chrome の sidePanel.setOptions の path フィールドは、拡張機能パッケージ内の相対パス(HTMLファイルへのパス)を期待しています。外部URL(例: https://google.com)を渡した場合、サイドパネルが空白になるか正常に機能しない可能性があります。

openSidePanel では path: toUrl(url) で、updateSidePanelUrl でも path: url で外部URLを設定しています。外部URLを表示するためには、拡張機能の side_panel.html 内でiframeを使うか、Chrome の最新APIを確認する必要があります。実装が意図通りに動作することを実際のブラウザで確認済みでしょうか?


Bug: setOptions を await せずに open() を呼んでいる

packages/extension/src/services/chrome.ts

chrome.sidePanel.setOptions() が await されていない状態で chrome.sidePanel.open() が呼ばれています。コメントには「ユーザージェスチャー内で実行する必要があるため await しない」とありますが、setOptions() はユーザージェスチャーを必要としないはずです。open() が呼ばれた時点で前の setOptions がまだ処理中の場合、古い設定で開かれるレースコンディションが生じます。


セキュリティ: URLバリデーションの不整合

useSidePanelNavigation.ts では許可リスト方式 (["http:", "https:"] のみ許可) を使用していますが、helper.ts の navigateSidePanel では拒否リスト方式 (javascript: と data: のみ拒否) を使用しています。

バックグラウンドスクリプト側では ftp:、blob: 等も許容してしまいます。防御の深さを保つため、バックグラウンド側も許可リスト方式に統一することを推奨します。


未使用コード: BgData.watch()

packages/extension/src/services/backgroundData.ts

追加された BgData.watch() メソッドがこのPRの変更のどこでも使用されていません。後で使う予定であれば、別PRで追加するか、使用箇所とセットで含めてください。


.gitignore の問題

.gitignore に .git が追加されています。.git ディレクトリはGitリポジトリのメタデータそのものであり、通常は .gitignore に記述すべきものではありません。誤ってコミットされたものではないでしょうか?


冗長なコード

packages/extension/src/services/chrome.ts で const targetTabId = tabId という単純なエイリアスが作られています。tabId を直接使用してください。


Promiseの未処理

packages/extension/src/action/sidePanel.ts

Ipc.send() の返すPromiseが await されておらず、エラーが無視されます。await するか .catch() でエラーハンドリングを追加してください。


良い点

  • ロケールファイルのバグ修正: イタリア語・韓国語・マレー語・ポルトガル語・ロシア語・中国語で Option_userVariables 系のキーが Option_openMode_backgroundTab_desc の中に誤ってネストされていた問題を修正しています。これは重要なバグ修正です。
  • テストカバレッジ: NSP-01〜08、SPN-01〜07、SPD-01〜04 と主要なケースが網羅されています。
  • マイグレーションの追加: 既存ユーザーへの影響を考慮した v0.14.3 マイグレーションが実装されています。
  • タブクローズ時のクリーンアップ: chrome.tabs.onRemoved で sidePanelTabs/sidePanelUrls を適切にクリアしています。
  • セキュリティ考慮: コンテントスクリプト側で target="_blank" や javascript: プロトコルのリンクをインターセプトしない設計は適切です。

@ujiro99 ujiro99 merged commit fb76ab1 into main Feb 21, 2026
5 checks passed
@ujiro99 ujiro99 deleted the copilot/add-sidepanel-to-page-opening branch February 21, 2026 02:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ページの開き方へ'sidePanel'を追加する

2 participants