Skip to content

refactor: remove unused controller extension#505

Open
shadowfax92 wants to merge 4 commits intomainfrom
fix/mar19-clean-up-dead-code
Open

refactor: remove unused controller extension#505
shadowfax92 wants to merge 4 commits intomainfrom
fix/mar19-clean-up-dead-code

Conversation

@shadowfax92
Copy link
Contributor

@shadowfax92 shadowfax92 commented Mar 20, 2026

Summary

  • Remove the unused apps/controller-ext Chrome extension workspace and the server-side ControllerBackend WebSocket bridge end-to-end
  • Simplify the server to CDP-only architecture: remove extension port config, controller startup, extension connectivity status
  • Update dev/eval/test helpers to stop building, loading, or waiting on the deleted extension
  • Clean up eval scripts (test-lifecycle.ts, test-failure-scenarios.ts) to use CDP health checks instead of extension status
  • Add mkdir calls in page-actions for PDF/screenshot/download paths
  • Fix test ordering in Go dev CLI: browser+CDP start before server

Rework

After rebasing on main (which added 9 new commits including credits tracking, Qwen OAuth, voice input, and build smoke tests), cleaned up remaining controller-ext references in eval scripts that the rebase missed. All extension port/status references are now fully removed.

Test plan

  • bun run typecheck — all packages pass
  • bun run lint — only pre-existing cognitive complexity warnings
  • No remaining references to controller-ext, extensionPort, extension-status, or --extension-port
  • Greptile review items addressed:
    • Silent windowId fall-through now throws instead of dropping the constraint
    • Health route test covers both connected and disconnected CDP states

🤖 Generated with Claude Code

@shadowfax92
Copy link
Contributor Author

@greptileai review

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 20, 2026

Greptile Summary

This PR removes the apps/controller-ext Chrome extension workspace and the ControllerBackend WebSocket bridge end-to-end, simplifying the server to a CDP-only architecture. The change is broadly well-executed across 140 files — config, server startup, browser abstraction, Go dev tooling, eval scripts, and test helpers all consistently remove every extensionPort/extensionConnected/controller reference.

Key highlights:

  • Browser class no longer accepts a ControllerBackend constructor arg; a new isCdpConnected() method wraps CdpBackend.isConnected().
  • page-actions.ts gains mkdir calls before writing PDFs, screenshots, and downloads — fixing a latent "directory not found" failure.
  • Go test.go corrects the startup order: browser+CDP now start before the server, ensuring CDP is available when the server connects.
  • lsof in test helpers is tightened to -sTCP:LISTEN to avoid accidentally killing client connections.
  • A temporary LLM workspace file (.llm/tmp_review_feedback.md) was committed accidentally and should be removed.
  • The health route's cdpConnected defaults to true when no browser is provided, which could produce a false-positive signal if the route is ever instantiated without a browser dependency.
  • /status and /health now return identical { status, cdpConnected } payloads; any external consumers that previously read extensionConnected from /status will silently receive undefined.

Confidence Score: 4/5

  • Safe to merge after removing the accidentally committed .llm/tmp_review_feedback.md file and fixing the cdpConnected ?? true default in the health route.
  • The refactor is thorough and consistent — all extension port/status references are removed across TypeScript and Go. The two minor issues (false-positive health default and stray temp file) do not affect core functionality, but the health default is a correctness concern for monitoring setups. The /status API change is intentional but potentially breaking for external consumers.
  • packages/browseros-agent/.llm/tmp_review_feedback.md (stray file) and packages/browseros-agent/apps/server/src/api/routes/health.ts (false-positive default).

Important Files Changed

Filename Overview
packages/browseros-agent/apps/server/src/api/routes/health.ts Now accepts an optional Browser dependency and reports cdpConnected in the response; defaults to true when no browser is provided, which could produce a false-positive health signal.
packages/browseros-agent/apps/server/src/api/routes/status.ts Switched dependency from ControllerBackend to Browser; now reports cdpConnected instead of extensionConnected. This is a breaking change for any external consumers of the /status endpoint.
packages/browseros-agent/apps/server/src/api/services/sdk/browser.ts Adds getFallbackPage and getPageInfo helpers; refactors navigateTo to attempt window-scoped page creation with graceful fallback. The windowId-scoped failure now re-throws correctly when no fallback page exists (previously flagged concern addressed).
packages/browseros-agent/apps/server/src/tools/page-actions.ts Adds mkdir calls before writing PDFs, screenshots, and downloads so missing parent directories are created automatically — a clean bug fix.
packages/browseros-agent/apps/server/src/browser/browser.ts Removes ControllerBackend dependency from the constructor; adds isCdpConnected() public method delegating to CdpBackend.isConnected().
packages/browseros-agent/apps/server/src/main.ts Removes ControllerBackend startup, error handling, and extension port logging; logStartupSummary now logs CDP endpoint instead.
packages/browseros-agent/tools/dev/cmd/test.go Fixes test startup order: browser+CDP now start before the server (previously server started first), ensuring CDP is available when the server connects. Removes --cdp-only flag and extension wait logic.
packages/browseros-agent/apps/eval/src/runner/browseros-app-manager.ts Removes loadExtensions flag, buildExtensions static method, and all --load-extension/--browseros-extension-port Chrome args referencing controller-ext; overall cleanup is thorough.
packages/browseros-agent/apps/server/tests/helpers/setup.ts Removes extensionPort from test config, removes waitForExtensionConnection polling, and simplifies environment setup to server + browser only.
packages/browseros-agent/.llm/tmp_review_feedback.md Temporary LLM workspace file accidentally committed to the repository; should be removed and gitignored.

Sequence Diagram

sequenceDiagram
    participant CLI as Go CLI (dev/test)
    participant Chrome as Chrome/BrowserOS
    participant CDP as CDP Backend
    participant Server as HTTP Server
    participant Client as SDK / Eval Client

    Note over CLI,Client: Before this PR (controller-ext architecture)
    CLI->>Server: Start server (with --extension-port)
    CLI->>Chrome: Launch with --load-extension=controller-ext
    Chrome-->>Server: WebSocket connect (ControllerBackend)
    CLI->>Server: WaitForExtension (/status?extensionConnected)
    Client->>Server: API calls → forwarded via WebSocket → Chrome ext

    Note over CLI,Client: After this PR (CDP-only architecture)
    CLI->>Chrome: Launch Chrome
    Chrome-->>CDP: CDP available on --remote-debugging-port
    CLI->>Server: Start server (after CDP ready)
    Server->>CDP: Connect directly
    Client->>Server: API calls → forwarded via CDP → Browser
    Client->>Server: GET /health → { status: ok, cdpConnected: bool }
Loading

Comments Outside Diff (1)

  1. packages/browseros-agent/apps/server/src/api/routes/health.ts, line 16 (link)

    P2 False-positive cdpConnected: true when no browser is wired up

    deps.browser?.isCdpConnected() ?? true returns true whenever createHealthRoute() is called without a browser instance (i.e., deps.browser is undefined). A caller that is not yet connected to CDP — or a future test that omits the browser — would receive { status: 'ok', cdpConnected: true }, masking an unconnected state.

    Defaulting to false is safer: an absent browser means connectivity cannot be confirmed.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: packages/browseros-agent/apps/server/src/api/routes/health.ts
    Line: 16
    
    Comment:
    **False-positive `cdpConnected: true` when no browser is wired up**
    
    `deps.browser?.isCdpConnected() ?? true` returns `true` whenever `createHealthRoute()` is called without a `browser` instance (i.e., `deps.browser` is `undefined`). A caller that is not yet connected to CDP — or a future test that omits the browser — would receive `{ status: 'ok', cdpConnected: true }`, masking an unconnected state.
    
    Defaulting to `false` is safer: an absent browser means connectivity cannot be confirmed.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: packages/browseros-agent/.llm/tmp_review_feedback.md
Line: 1-13

Comment:
**Temporary LLM workspace file accidentally committed**

This file (`tmp_review_feedback.md`) is a transient AI workspace artifact — it is not source code, documentation, or a test. It should be removed from the repository before merging and added to `.gitignore` to prevent future accidents.

**Rule Used:** Remove unused/dead code rather than leaving it in ... ([source](https://app.greptile.com/review/custom-context?memory=9b045db4-2630-428c-95b7-ccf048d34547))

**Learnt From**
[browseros-ai/BrowserOS-agent#126](https://github.com/browseros-ai/BrowserOS-agent/pull/126)

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: packages/browseros-agent/apps/server/src/api/routes/health.ts
Line: 16

Comment:
**False-positive `cdpConnected: true` when no browser is wired up**

`deps.browser?.isCdpConnected() ?? true` returns `true` whenever `createHealthRoute()` is called without a `browser` instance (i.e., `deps.browser` is `undefined`). A caller that is not yet connected to CDP — or a future test that omits the browser — would receive `{ status: 'ok', cdpConnected: true }`, masking an unconnected state.

Defaulting to `false` is safer: an absent browser means connectivity cannot be confirmed.

```suggestion
    const cdpConnected = deps.browser?.isCdpConnected() ?? false
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: packages/browseros-agent/apps/server/src/api/routes/status.ts
Line: 15-22

Comment:
**`/status` and `/health` now return identical payloads**

Both `/status` (`{ status: 'ok', cdpConnected }`) and `/health` (`{ status: 'ok', cdpConnected }`) now expose the same fields. Before this PR, `/status` returned `extensionConnected` and `/health` returned only `{ status: 'ok' }` — they served different purposes. Now the two routes are functionally identical.

Consider either consolidating to a single endpoint or differentiating their payloads (e.g., `/health` for liveness, `/status` for richer operational detail). At minimum, any external callers that read `extensionConnected` from `/status` will now receive `undefined` for that field; a migration note or versioned field might be warranted if this API is consumed externally.

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: "fix: remove .llm/ fr..."

Comment on lines 128 to 138
} catch {
const fallbackPage = await this.getFallbackPage()
if (fallbackPage) {
await this.browser.goto(fallbackPage.pageId, url)
return {
tabId: fallbackPage.tabId,
windowId: fallbackPage.windowId ?? 0,
}
}
}
await this.browser.goto(page.pageId, url)
return { tabId: page.tabId, windowId }
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Silent fall-through when windowId navigation fails completely

When windowId !== undefined, the active tab in that window is missing, newPage(url, { windowId }) throws, and getFallbackPage() returns null (e.g. browser has zero open pages), execution silently falls out of the if (windowId !== undefined) block. The code then calls this.browser.newPage(url) at line 149 without the windowId, creating a page in an arbitrary window and returning it as if the requested window constraint was satisfied.

The previous behaviour threw SdkError('No active tab in specified window'), which was safer. Consider re-throwing (or at least logging) when both fallbacks are exhausted while a caller-specified window was targeted:

Suggested change
} catch {
const fallbackPage = await this.getFallbackPage()
if (fallbackPage) {
await this.browser.goto(fallbackPage.pageId, url)
return {
tabId: fallbackPage.tabId,
windowId: fallbackPage.windowId ?? 0,
}
}
}
await this.browser.goto(page.pageId, url)
return { tabId: page.tabId, windowId }
}
} catch {
const fallbackPage = await this.getFallbackPage()
if (fallbackPage) {
await this.browser.goto(fallbackPage.pageId, url)
return {
tabId: fallbackPage.tabId,
windowId: fallbackPage.windowId ?? 0,
}
}
throw new SdkError(`Window ${windowId} not found and no fallback page available`)
}
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/browseros-agent/apps/server/src/api/services/sdk/browser.ts
Line: 128-138

Comment:
**Silent fall-through when `windowId` navigation fails completely**

When `windowId !== undefined`, the active tab in that window is missing, `newPage(url, { windowId })` throws, *and* `getFallbackPage()` returns `null` (e.g. browser has zero open pages), execution silently falls out of the `if (windowId !== undefined)` block. The code then calls `this.browser.newPage(url)` at line 149 **without** the `windowId`, creating a page in an arbitrary window and returning it as if the requested window constraint was satisfied.

The previous behaviour threw `SdkError('No active tab in specified window')`, which was safer. Consider re-throwing (or at least logging) when both fallbacks are exhausted while a caller-specified window was targeted:

```suggestion
      } catch {
        const fallbackPage = await this.getFallbackPage()
        if (fallbackPage) {
          await this.browser.goto(fallbackPage.pageId, url)
          return {
            tabId: fallbackPage.tabId,
            windowId: fallbackPage.windowId ?? 0,
          }
        }
        throw new SdkError(`Window ${windowId} not found and no fallback page available`)
      }
    }
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in ecc8ede. The window-targeted navigation path now rethrows the original window-scoped failure when it cannot create a page and there is no fallback page available, so it no longer falls through to the generic new-page path and silently drops the requested windowId. I also added a focused unit test for that case and tightened the health route test coverage in the same follow-up.

shadowfax92 added a commit that referenced this pull request Mar 20, 2026
shadowfax92 added a commit that referenced this pull request Mar 20, 2026
@shadowfax92 shadowfax92 force-pushed the fix/mar19-clean-up-dead-code branch from ecc8ede to 1e33dd9 Compare March 20, 2026 18:58
@shadowfax92
Copy link
Contributor Author

@greptileai review

@shadowfax92
Copy link
Contributor Author

@claude review

@claude
Copy link

claude bot commented Mar 20, 2026

Claude encountered an error —— View job


I'll analyze this and get back to you.

shadowfax92 and others added 4 commits March 21, 2026 09:49
Rebase on main missed updating eval scripts that still referenced
extension ports, --extension-port args, and /extension-status endpoint.
Updated to use CDP-only architecture via /health endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The .llm/ directory is in .gitignore but was accidentally committed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@shadowfax92 shadowfax92 force-pushed the fix/mar19-clean-up-dead-code branch from 32b16b6 to 87506af Compare March 21, 2026 16:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant