fix(chrome-extension): add start/stop controls for bridge mode#2177
fix(chrome-extension): add start/stop controls for bridge mode#2177
Conversation
The bridge mode UI was missing start/stop controls, making it impossible for users to stop listening or change the remote server URL. The bridge auto-started on extension load and the URL input was always disabled. Closes #2119 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Deploying midscene with
|
| Latest commit: |
14fe38c
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://726c7ec8.midscene.pages.dev |
| Branch Preview URL: | https://fix-chrome-extension-bridge.midscene.pages.dev |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a11b50a525
ℹ️ 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".
| const isBridgeActive = | ||
| bridgeStatus === 'listening' || bridgeStatus === 'connected'; |
There was a problem hiding this comment.
Keep the toggle in Stop mode while reconnecting
When a bridge session drops, BridgeConnector moves to disconnected and keeps retrying inside connect() instead of stopping (apps/chrome-extension/src/utils/bridgeConnector.ts:54-102). Because isBridgeActive only treats listening and connected as active, the new control flips to Start during that reconnect window even though the bridge is still running and the URL field stays disabled. In that state the user cannot actually stop the retry loop without first restarting the bridge, so the new start/stop control is incorrect whenever a connection is lost.
Useful? React with 👍 / 👎.
| chrome.runtime.sendMessage( | ||
| { type: workerMessageTypes.BRIDGE_STOP }, |
There was a problem hiding this comment.
Persist the stopped state before advertising a Stop control
This handler makes Stop look permanent, but BRIDGE_STOP only tears down the current worker instance. The extension is declared as an MV3 background.service_worker (apps/chrome-extension/static/manifest.json:5-17), and worker.ts still unconditionally runs initBackgroundBridge() plus safeSetupKeepalive({ shouldEnable: true }) at module load (apps/chrome-extension/src/scripts/worker.ts:352-379). After any normal service-worker restart, the bridge starts listening again, so users who stopped bridge mode can be silently re-exposed to incoming connections.
Useful? React with 👍 / 👎.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous run failed because `npx nx test chrome-extension` ran all tests including an unrelated flaky timeout in event-memory-stress.test.ts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
--testPathPattern is a Jest option, not vitest. Pass the file path directly to vitest run instead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add junit reporter for bridge unit tests and upload as separate artifact. Also check both unit and e2e test results in the final step. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add e2e test case that verifies: - Bridge mode shows Stop button when listening - Clicking Stop changes status to "Stopped" and button to "Start" - Server URL input becomes editable after stopping - Typing a new server URL works - Clicking Start restarts bridge with "Listening" status Remove standalone unit test step from CI, keep e2e only. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ve prompts The previous run failed because the dropdown menu click didn't register, leaving the panel in Playground mode. Added retry logic (same pattern as existing test case 5) and improved AI prompts for more reliable element targeting. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reduce the bridge mode e2e test to just stop/start lifecycle verification. The previous version had too many AI steps (URL change, expand config, etc.) causing timeout at 360s. Focus on core stop→start flow only. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move bridge mode start/stop e2e test out of chrome-extension.test.ts into its own file chrome-extension-bridge.test.ts with a dedicated CI job (chrome-extension-bridge) and separate report artifact. The test covers: - Open side panel and switch to Bridge Mode - Stop bridge listening → verify "Stopped" + "Start" button - Edit server URL when stopped - Restart bridge → verify "Listening" + "Stop" button Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extend bridge e2e test to verify actual WebSocket connections: - Start a real bridge server → extension connects → UI shows "Connected" - Click Stop → disconnects → UI shows "Stopped" - Start another server while stopped → no connection received - Click Start → extension reconnects → UI shows "Connected" again Uses a child process running bridge-test-server.mjs (Socket.IO server) to simulate the CLI-side bridge server. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The bridge e2e test failed because the extension shows a connection confirm dialog when a server connects. Add injectBridgePermission() helper that sets chrome.storage.local alwaysAllow via CDP, bypassing the confirm popup in automated tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous approach injected permission on the page target but the service worker had already started connecting before the permission was set. Now targets the service worker directly and restarts the bridge after setting alwaysAllow, ensuring the permission takes effect. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a connection drops, BridgeConnector moves to 'disconnected' but keeps retrying in connectLoop(). The toggle button incorrectly showed "Start" during reconnection because isBridgeActive did not include 'disconnected'. Now the Stop button stays visible while reconnecting, allowing users to actually stop the retry loop. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The service worker unconditionally called initBackgroundBridge() on startup, silently re-enabling bridge listening after the user had explicitly stopped it. Now the stopped intent is persisted to chrome.storage.local and checked before auto-starting. - stopBackgroundBridge() sets BRIDGE_STOPPED_KEY - startBackgroundBridge() clears BRIDGE_STOPPED_KEY - initBackgroundBridge() skips auto-start if flag is present Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
closed), enabling users to change the remote server URLCloses #2119
Changes
apps/chrome-extension/src/extension/bridge/index.tsx: AddedhandleToggleBridgefunction that sendsBRIDGE_START/BRIDGE_STOPmessages to the service worker, and a toggle button in the status barapps/chrome-extension/src/extension/bridge/index.less: Added.bridge-toggle-btnstylesapps/chrome-extension/tests/bridge-start-stop.test.ts: Added unit tests for bridge connector state machine, worker message handling, and UI state logicValidation
pnpm run lint✅npx nx build chrome-extension✅vitest run apps/chrome-extension/tests/bridge-start-stop.test.ts✅ (15 tests passed)Test plan
🤖 Generated with Claude Code