How the Update Notice System Detects New Browser Versions in Ego Lite

The Ego Lite update notice system detects new browser versions by calling ego.getBrowserVersion() through an injected bridge, validating the returned BrowserVersionInfo, and emitting a formatted hint when updateAvailable equals true.

The update notice mechanism in citrolabs/ego-lite provides lightweight, stateless version detection that runs during every SDK command execution. Located in package/ego-browser/src/update-notice.ts, this system surfaces upgrade hints without persisting data or blocking command completion. This article breaks down the detection flow, suppression controls, and validation logic that powers the feature.

Entry Point: emitUpdateNotice and the Bridge Interface

The detection process begins at emitUpdateNotice in package/ego-browser/src/update-notice.ts (lines 36-39). This function receives two critical inputs:

  • The ego bridge object, which optionally exposes getBrowserVersion()
  • An emit callback that appends the notice to command output

When invoked, emitUpdateNotice passes a version source to updateNoticeLine. This source calls ego.getBrowserVersion() if the bridge method exists, otherwise resolving to null (lines 41-43).

// Simplified SDK usage pattern
import { emitUpdateNotice } from "./update-notice.js";

function runCommand(egoBridge, outputEmit) {
  // Command execution logic...

  // Attach update notice to output stream
  emitUpdateNotice(egoBridge, (line) => outputEmit(line));
}

Suppressing the Notice with Environment Variables

Before any bridge interaction, the system checks noticeSuppressed (lines 50-53). When either condition below is true, the entire notice pipeline exits silently:

  • EGO_BROWSER_NO_UPDATE_NOTIFIER is set
  • CI environment variable is present

This prevents update hints from appearing in automated pipelines or when explicitly disabled by the user.

Fetching the Version with Timeout Protection

The updateNoticeLine function executes the VersionSource within withTimeout (lines 44-45, 94-100). This races the bridge call against a 2-second timeout defined by NOTICE_PROBE_TIMEOUT_MS (2000 ms).

// Timeout-protected version probe
const NOTICE_PROBE_TIMEOUT_MS = 2000;

async function withTimeout<T>(
  promise: Promise<T>,
  ms: number
): Promise<T | null> {
  // Races bridge call against timeout
}

This guarantee prevents a stalled getBrowserVersion() from degrading command performance.

Validating and Formatting the Notice

Once the bridge returns data, composeNotice (lines 70-85) applies strict validation rules:

Field Requirement
updateAvailable Must be literal true
currentVersion Must be non-empty string
latestVersion Optional inclusion in output
mandatory Added to message when true

Valid notices receive the [ego-browser:notice] prefix from NOTICE_PREFIX (lines 40-41) before emission.

// Example formatted notice output
[ego-browser:notice] ego lite 1.3.0 is available (current 1.2.3) — run: ego-browser upgrade …

Emitting the Final Line

After updateNoticeLine resolves, emitUpdateNotice invokes the provided emit callback with the formatted line (lines 45-47). Errors at this stage are intentionally swallowed—wrapped in a catch block—to prevent unhandled rejections from disrupting command execution (lines 48-49).

Mocking for Testing

The modular design enables straightforward unit testing. Supply a fake VersionSource to updateNoticeLine to verify formatting logic without bridge dependencies:

import { updateNoticeLine } from "./update-notice.js";

const fakeSource = async () => ({
  currentVersion: "1.2.3",
  updateAvailable: true,
  latestVersion: "1.3.0",
  mandatory: false,
});

const line = await updateNoticeLine({ source: fakeSource });
console.log(line);
// → [ego-browser:notice] ego lite 1.3.0 is available (current 1.2.3) — run: ego-browser upgrade …

Supporting Files in the Detection Pipeline

File Responsibility
package/ego-browser/src/update-notice.ts Core detection, validation, and formatting
package/ego-browser/src/helpers.ts Registers emitUpdateNotice as output-sink trailer during SDK init
package/ego-browser/src/env.ts Resolves suppression environment variables
package/ego-browser/src/browser-runtime.ts Defines native ego bridge with getBrowserVersion

Summary

  • Bridge-dependent detection: The system relies on ego.getBrowserVersion() injected at runtime, falling back to null if unavailable
  • Zero persistence: No caching or state storage; checks run fresh on every command
  • 2-second timeout: NOTICE_PROBE_TIMEOUT_MS prevents blocking
  • Strict validation: Only updateAvailable: true with valid currentVersion triggers output
  • Environment controls: EGO_BROWSER_NO_UPDATE_NOTIFIER and CI provide opt-out mechanisms
  • Fail-silent emission: Errors in notice delivery never propagate to callers

Frequently Asked Questions

How does the update notice system detect new browser versions without network calls?

The system delegates detection to the native ego bridge via getBrowserVersion(). This local call returns BrowserVersionInfo without HTTP requests, keeping the check lightweight and private. The bridge implementation in browser-runtime.ts handles actual version comparison against available releases.

What happens if the bridge call hangs or responds slowly?

withTimeout enforces a 2000 ms ceiling on the VersionSource promise. If getBrowserVersion() exceeds this limit, the promise races to null resolution, and no notice appears. Commands continue normally regardless of bridge responsiveness.

Why does the notice appear on every command instead of rate-limited?

By design, emitUpdateNotice executes statelessly. No timestamp files, registry entries, or cache entries track last-check time. This eliminates filesystem dependencies and ensures users always see current availability status, accepting the minimal overhead of a 2-second-capped local call.

Can I disable update notices in CI environments?

Yes. Setting CI to any value automatically suppresses detection via noticeSuppressed. Alternatively, set EGO_BROWSER_NO_UPDATE_NOTIFIER for explicit opt-out in any environment. These variables are resolved in package/ego-browser/src/env.ts before any bridge interaction occurs.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →