fix: stabilize browser extension tab group recovery#51
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1efb3eed9b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
This PR stabilizes Nine1Bot browser extension tab-group recovery across reconnects/service worker restarts by making tab-group binding window-scoped, introducing authoritative resync/diagnostics from the extension, and improving server-side self-healing and startup error reporting.
Changes:
- Browser extension: migrate active tab-group binding from a single global ID to per-window bindings with recovery heuristics + diagnostics payloads.
- Relay/bridge server: prefer authoritative
tabs_context_mcpscans, rebuild targets when relay cache is empty, exposetabListSource+ runtime diagnostics/issues. - OpenCode server: improve listen/start failure messaging and add regression tests.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/nine1bot/src/launcher/server.ts | Best-effort cleanup of browser bridge if main server fails to start. |
| packages/browser-mcp-server/test/bridge-server.test.ts | Adds regression tests for authoritative target rebuild and relay-cache fallback. |
| packages/browser-mcp-server/src/core/types.ts | Extends browser status/runtime types with tab list source + diagnostics payload. |
| packages/browser-mcp-server/src/bridge/server.ts | Implements authoritative tab scan refresh, relay-cache fallback, and runtime issue propagation. |
| packages/browser-mcp-server/src/bridge/relay-routes.ts | Adds stable session IDs + target upsert helper + exposes extension diagnostics via relay health. |
| packages/browser-extension/test/tab-group-manager.test.ts | Adds recovery/migration regression tests for window-scoped bindings. |
| packages/browser-extension/src/tools/tabs.ts | Enhances tabs_context_mcp output with scan status + diagnostics and clearer reason codes. |
| packages/browser-extension/src/sidepanel/index.ts | Avoids unconditional re-binding; ensures group only if missing; reacts to new storage key. |
| packages/browser-extension/src/shared/tab-group.ts | Introduces window-scoped binding types and diagnostics schemas. |
| packages/browser-extension/src/background/tab-group-manager.ts | Core refactor: per-window bindings, recovery strategy, persistence + diagnostics APIs. |
| packages/browser-extension/src/background/relay-client.ts | Stabilizes session IDs, adds authoritative resync mechanism + diagnostics emission. |
| packages/browser-extension/src/background/index.ts | Propagates open nonce and supports “onlyIfMissing” tab-group ensure semantics. |
| opencode/packages/opencode/test/server/listen-errors.test.ts | Adds regression tests for improved listen error formatting. |
| opencode/packages/opencode/src/tool/browser.ts | Displays user tab list source in browser_status output. |
| opencode/packages/opencode/src/server/server.ts | Adds formatListenError() and uses it when Bun serve fails. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| for (const [windowKey, candidate] of Object.entries(value as Record<string, unknown>)) { | ||
| if (!candidate || typeof candidate !== 'object') continue | ||
| const record = candidate as Partial<ActiveNine1TabGroupBinding> | ||
| if ( | ||
| typeof record.groupId !== 'number' |
| } | ||
|
|
||
| export function __resetTabGroupManagerStateForTests(): void { | ||
| cleanupInstalled = false |
描述 / Summary
修复浏览器扩展在
Nine1Bot标签组场景下的稳定性问题,重点解决“标签组仍存在,但 runtime/bridge 识别不到标签页”的问题。这次改动把标签组绑定从全局单例改成按窗口恢复,补上扩展侧 target/session 的权威重同步,以及 server 侧基于权威扫描结果的自愈与诊断信息,降低 sidepanel 重开、扩展重连、service worker 重启后的失联概率。
类型 / Type of change
关联的 issue(如果有)/ Related issues
/ 暂无 /
变更点 / What changed
activeNine1TabGroupId升级为按windowId存储的activeNine1TabGroups,并保留旧存储键迁移逻辑。Nine1Bot*标签组,并优先选择当前活动 tab 所在组,其次单一匹配组。tab_<tabId>,避免断连/重连后 target 身份漂移。tabs_context_mcp增强返回结果,补充tabScanStatus、group diagnostics、reason code,显式区分no_active_group、group_binding_stale、no_automatable_tabs等状态。browser_status优先使用扩展权威扫描结果;当 relay cache 为空但权威 tab 列表可用时,自动重建 targets。runtime.issues暴露tab_scan_failed/relay_cache_fallback等诊断码。BrowserStatus.user新增tabListSource,模型侧browser_status输出会显示 tab 列表来源。如何测试 / How to test
bun test opencode/packages/opencode/test/server/listen-errors.test.ts packages/browser-extension/test/tab-group-manager.test.ts packages/browser-mcp-server/test/bridge-server.test.ts packages/browser-mcp-server/test/relay-routes.test.ts packages/browser-extension/test/server-config.test.tscd packages/browser-extension && bun run typecheckcd packages/browser-mcp-server && bun run typecheck打开带有
Nine1Bot标签组的窗口,反复打开 sidepanel、重连扩展或触发 service worker 恢复,确认browser_status仍能识别已有 tabs,且不会因为 sidepanel 重开丢失当前窗口绑定。browser_status能稳定返回用户浏览器 tabs;group 存在时可自动恢复;无有效 group / 无可自动化 tab 时返回明确诊断;端口占用时启动报错更明确。截图(UI 变更时提供)/ Screenshots for UI changed
无重大 UI 改动。
Checklist(合并前请确认) / Checklist
备注 / Notes for reviewers
建议重点看这几块:
packages/browser-extension/src/background/tab-group-manager.ts这里是标签组绑定模型和恢复策略的核心改动。
packages/browser-extension/src/background/relay-client.ts这里实现了稳定 sessionId 和权威 resync,是本次稳定性修复的关键路径。
packages/browser-mcp-server/src/bridge/server.ts这里补了 authoritative scan 优先、relay cache fallback、自愈重建和 runtime issue 输出。
packages/browser-mcp-server/src/bridge/relay-routes.ts这里补了 target 重建与 diagnostics 透传逻辑。
另外有一个和本次修复无关但在本地验证中暴露的问题:如果
127.0.0.1:4096已被其他进程占用,dev:test仍会启动失败;这次已把错误信息补得更明确,但没有改成自动切换端口策略。fix issue:
[Bug] 浏览器插件页面识别不稳定问题 #50