Skip to content

feat(linux): fully functional optimized Linux port - #291

Open
nosliwhtes wants to merge 6 commits into
citrolabs:mainfrom
nosliwhtes:feat/linux-port
Open

feat(linux): fully functional optimized Linux port#291
nosliwhtes wants to merge 6 commits into
citrolabs:mainfrom
nosliwhtes:feat/linux-port

Conversation

@nosliwhtes

Copy link
Copy Markdown

Fully functional Linux port — ego-browser now works on Linux with same or better features than macOS.

  • Cross-platform install.sh: Darwin DMG + Linux apt/dnf/pacman/zypper, auto-detects google-chrome/chromium, builds CLI, creates ~/.local/bin/ego-browser shim, Wayland-aware
  • Linux runtime (src/linux/): launcher (ephemeral --remote-debugging-port, daemon cache at ~/.cache/ego-lite/), bridge via ws, task-spaces (BrowserContext isolation, EGO_* codes), snapshot-ax (AXTree + DOM fallback)
  • Wiring: EGO_LINUX=1 opt-in, lazy bridge (no chrome spawn during cdpOverride tests)
  • doctor-linux.mjs diagnostics (--json), Build/CI ws dep + linux-headless job, Docs install.md + README platform table

Verification: npm run build OK, typecheck OK, 302 tests pass, doctor-linux OK.

- Cross-platform install.sh (Darwin DMG + Linux apt/dnf/pacman/zypper,
  auto-detects google-chrome/chromium, builds CLI, creates
  ~/.local/bin/ego-browser shim, Wayland-aware)
- Linux runtime: launcher (ephemeral --remote-debugging-port, Ozone
  auto, --no-sandbox for CI, per-TaskSpace BrowserContext, daemon
  cache at ~/.cache/ego-lite/), CDP bridge via ws, task-spaces
  (Target.createBrowserContext isolation, ownership semantics,
  EGO_* error codes), snapshot-ax (Accessibility.getFullAXTree +
  DOM fallback, backendNodeId refs)
- Wiring: EGO_LINUX=1 opt-in (auto-detect on Linux when chrome
  present, suppressed in CI to keep unit tests green), lazy bridge
  (no chrome spawn during cdpOverride tests), circular-dep fixed
  via dynamic import in snapshot-ax
- doctor-linux.mjs diagnostics (chrome version, devtools port,
  cache, display server, ws, node; --json)
- Build/CI: ws ^8.21.3 dep, build.mjs external ws, linux-headless
  job in ci.yml, release now needs both jobs
- Docs: install.md (Linux quickstart + troubleshooting), README
  platform table + Linux snippet

Co-Authored-By: internal-model
- index.ts: listTabs/createTab now hit Chrome HTTP /json (not stub []),
  Promise<string> type fix for tsc
- bridge.test.mjs: randomized PORT + proper wss close + beforeEach to avoid
  socket hang up port-reuse flake (302/302 now)
…cleanup (Claude review)

- bridge.ts: route WS messages to ego.onCDPMessage via onMessage, clear
  stale bridge on close/error so ensureBridge respawns instead of
  leaking dead socket
- index.ts: onBridgeMessage/onBridgeClose helpers, stale-bridge reset,
  proper EGO_CDP_SEND_FAILED forwarding
- launcher.ts: remove unused createBrowserContext (used non-existent
  fetch), remove BrowserContext type, drop ephemeralPort wrapper
- task-spaces.ts: honest EgoError union types instead of as unknown
  casts
- install.sh: chrome --version preflight, Ubuntu chromium-stub guard,
  EGO_BROWSER_ASSUME_YES, CI path now exercises install.sh
…napshot truncation

- index.ts: add bridgePromise lock to ensureBridge (prevents double
  launch when parallel callers both see bridge===null; onBridgeClose
  now also clears bridgePromise; stale promise cleared on failure)
- install.sh: rebuild when src or package.json -nt dist/out/index.js
  (was only when missing — git pull left stale artifact)
- snapshot-ax.ts: honor maxResultLength on both AX and DOM fallback
  (was silently ignored via void opts)
- task-spaces.ts: document deferred BrowserContext (shares profile,
  same as macOS helpers in-memory behavior)
- audit: deleg_00fec6b1 TASK-BEST-PRACTICES (max reasoning)
… ws leak, dir-mtime, state loadEnv

- snapshot-ax.ts: Accessibility.enable before getFullAXTree (refs never
  populated without it, was falling through to DOM fallback with refs:[])
  + remove dead getBridge ctor param + fix double truncation (hardcoded
  4000 → use maxResultLength as single budget, default 250k)
- index.ts: CI guard now if (process.env.CI) not CI===1 (GHA is CI=true)
- index.ts: hasChrome now covers google-chrome-stable (.deb name) and
  EGO_CHROME_BIN correctly (was missing, blocked auto-activate)
- bridge.ts: ws.readyState !== 1 not ws.OPEN (static, not instance)
- install.sh: find -newer not src dir -nt (content edits missed)
- index.ts: shutdownCleanup + onBridgeClose removeListener (was leaking
  process.once per respawn)
- state.ts: loadEnv() before linux/index.js import (was after, .env
  EGO_LINUX invisible)
Prism Full @d1ea3fd + 656d1679 P1/P2; reasoning max
Distinguish no-daemon (ECONNREFUSED) from empty tab list;
still returns {tabs:[]} but stderr aids doctor-linux triage.
Prism ff90cc0 Low FIXABLE auto-approve polish
@Hotragn

Hotragn commented Aug 19, 2026

Copy link
Copy Markdown

Coordination note from the Windows side, since this lands very close to #228.

I built the same thing for Windows (#228, proposal in #227) and independently arrived at almost your exact decomposition — bridge, launcher, AX-tree snapshot, task-space registry, doctor. That convergence is probably worth taking as a signal about the shape rather than two people's taste.

Two differences where I think yours is the better call, and I'd rather align than have the repo carry two shapes:

  • Placement. You put it in-tree at package/ego-browser/src/linux/; I used a sibling package (package/ego-windows-host) to keep the runtime's dependency surface untouched. In-tree is simpler for users and keeps one build. If maintainers prefer that, I'll restructure feat(ego-windows-host): run the ego-browser runtime on stock Edge/Chrome (Windows preview) #228 to src/windows/ to match — say so and I'll do the move rather than argue for mine.
  • Shared surface. The AX snapshot renderer, the task-space registry, and the ownership/handoff state machine are platform-neutral in both implementations. If the layout settles, most of that could be one module with a thin per-platform launcher + browser-locator. Happy to do that extraction on top of whichever version lands first — yours, since it is further along.

One thing that may save you a rebase: this targets main, while CONTRIBUTING says dev. dev has not moved since 2026-08-06 (8216641), and the active line is sprint-1.3.0 (currently c1b1184), which is a fairly deep rearchitecture — it adds playwright-core as a runtime dependency and removes src/driver/ entirely. If your bridge touches anything under src/driver/, it will conflict there. I asked which branch external PRs should target in #227 and have not had an answer yet.

For what it's worth, I verified the part that matters for both of us: browser-runtime.ts on sprint-1.3.0 still uses globalThis.ego / sendCDPMessage, so the contract both hosts implement survives the rewrite.

@nosliwhtes

Copy link
Copy Markdown
Author

Thanks for the coordination note. Good to know #228 landed so close in shape, and I agree the convergence is a signal about where the repo is going.

Placement: in-tree was deliberate. The whole port lives in package/ego-browser/src/linux/ with small wiring in state.ts and the build script, so runtime users get the Linux host from the same install with no extra dependency surface. If #228 moves to src/windows/ we end up with a clean mirror on both sides, and that's the outcome I'd prefer over a sibling package.

Shared surface: I reached the same conclusion. The AX snapshot renderer, task-space registry, and handoff state machine are all platform-neutral in my version too. Extraction feels like the right end state, but I'd wait until one of the two lands rather than refactor across two open PRs at once.

Branches, current numbers for anyone picking this up: main got a docs merge today (5ca3c36), dev last moved 2026-08-20 (ca74689, #296), sprint-1.3.0 still sits at c1b1184. This PR targets main and merges clean against it right now. Nothing in the diff touches src/driver/, so I don't expect conflicts with the sprint rewrite either way. Your question in #227 is still the blocker for both of us, so I'll hold here until a maintainer answers and move the base wherever they point.

Happy to take the neutral-module extraction on top of whichever PR lands first.

@nosliwhtes

nosliwhtes commented Aug 25, 2026

Copy link
Copy Markdown
Author

Current status checked today:

  • The branch is mergeable.
  • The six main commits since its base only touch star-history files, docs workflows, .gitignore, and README.
  • None overlap the Linux runtime files.
  • All three Actions runs are action_required with zero jobs. They are waiting for maintainer approval to run fork workflows; no check has failed.
  • Fresh local verification is green: build and typecheck pass, all 302 tests pass, and doctor-linux reports Chrome 151, DevTools on 127.0.0.1:9222, X11, and ws 8.21.3 healthy.

I have not merged unrelated docs commits just to change the up-to-date badge, since that would churn the head and reset workflow approval without changing the code under review.

@section9-lab @WUXM5, could one of you confirm whether this should stay on main or move to dev/sprint-1.3.0, and approve the workflows? Once the target is settled, I will update it once and handle review feedback in the same pass. Hotragn's #227 is waiting on the same branch decision.

@NagyVikt

NagyVikt commented Aug 27, 2026

Copy link
Copy Markdown

Hi — I updated the clean dev-based production Chromium host proposal for Linux and Windows.

Compare / ready-to-open draft:
https://github.com/citrolabs/ego-lite/compare/dev...opencue:agenticbrowser:feat/production-linux-port-upstream?expand=1

Current head: 545b28c

The update adds:

  • background focus restoration for X11 and Wayland;
  • atomic cross-process state replacement;
  • Windows installer and CI hardening;
  • platform-neutral test-state paths.

Fresh local verification:

  • ego-browser: 314/314 tests;
  • host runtime: 231/231 tests;
  • agent-style validation: 31 files;
  • site-skill validation.

The branch still excludes fork-only learnings, evals, experimental sibling host packages, the Collaboration Inbox, and unrelated cleanup. Windows-specific paths are covered by tests and the added CI jobs; I did not run this update on a physical Windows host locally.

I retried draft creation after pushing the update, but GitHub still rejects it with CreatePullRequest permission denied for this account. A collaborator can open the draft directly from the compare page.

@citrolabs citrolabs deleted a comment from chatgpt-codex-connector Bot Aug 28, 2026
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.

3 participants