Skip to content

fix: restore server version flag#1322

Merged
Nikhil (shadowfax92) merged 4 commits into
mainfrom
fix/0622-1520-cheetah
Jun 22, 2026
Merged

fix: restore server version flag#1322
Nikhil (shadowfax92) merged 4 commits into
mainfrom
fix/0622-1520-cheetah

Conversation

@shadowfax92

Copy link
Copy Markdown
Contributor

Summary

  • restore bare browseros_server --version handling for compiled production binaries
  • replace Bun embedded runtime argv with a compiled bootstrap that installs the native addon guard before loading the server
  • add build tests covering the native addon policy and the updater-facing version command

Test plan

  • bun test scripts/build/server/native-addon-policy.test.ts
  • bun test apps/server/tests/build.test.ts
  • bun run build:server:test
  • ./dist/prod/server/darwin-arm64/resources/bin/browseros_server --version
  • ./dist/prod/server/darwin-arm64/resources/bin/browseros_server
  • ./dist/prod/server/darwin-arm64/resources/bin/browseros_server --help
  • bun run check
  • bun run test:main
  • bun run test

@shadowfax92

Copy link
Copy Markdown
Contributor Author

Claude (@claude) review

@shadowfax92

Copy link
Copy Markdown
Contributor Author

Greptile (@greptileai) review

@github-actions github-actions Bot added the fix label Jun 22, 2026
@claude

claude Bot commented Jun 22, 2026

Copy link
Copy Markdown

Claude finished Nikhil (@shadowfax92)'s task in 1m 52s —— View job


Code Review

  • Read changed files
  • Analyze for bugs, security issues, and best practices
  • Post review feedback

Overall: Clean architectural improvement. Replacing --compile-exec-argv=--no-addons (a Bun-specific runtime flag) with an in-process dlopen guard makes the policy explicit, testable, and portable. The bootstrap separation is the right structure. A few issues worth fixing before merging.


Issues

process.cwd() path in native-addon-policy.test.ts — fragile

native-addon-policy.test.ts:8-11

const nativeAddonGuardPath = join(
  process.cwd(),
  'apps/server/src/lib/native-addon-guard.ts',
)

This assumes the test runner's working directory is the monorepo root. If bun test is ever invoked from a subdirectory (e.g., packages/browseros-agent/ or the scripts/build/server/ directory directly), the path breaks and both tests that reference nativeAddonGuardPath will fail at spawn time. Use import.meta.dir to anchor to the file's location instead:

import { resolve } from 'node:path'

const nativeAddonGuardPath = resolve(
  import.meta.dir,
  '../../../apps/server/src/lib/native-addon-guard.ts',
)

Fix this →


Low-value constant test in native-addon-policy.test.ts

native-addon-policy.test.ts:23-27

it('bundles the compiled bootstrap entrypoint', () => {
  expect(SERVER_BUNDLE_ENTRYPOINT).toBe(
    'apps/server/src/compiled-bootstrap.ts',
  )
})

This test just asserts that a string constant equals a string literal — it adds no behavioral coverage and will always pass unless someone renames the constant. If the goal is to guard the compile step's entry selection, consider verifying via a build artifact or at least documenting what this catches that a type or lint check wouldn't.


Positives

  • Guard timing is correct. installNativeAddonGuard() runs synchronously before await import('./index'), so dlopen is locked before any module with a native dep can be loaded.

  • Idempotency pattern is sound. The __browserosNativeAddonGuardInstalled sentinel prevents double-installation without relying on module cache assumptions. The test verifying process.dlopen === guarded after a second call is a nice tight assertion.

  • assert.notStrictEqual(actualVersion, Bun.version) — excellent defensive assertion. This directly guards the regression described in the commit history where the embedded Bun runtime's version leaked into --version output.

  • Removing --compile-exec-argv removes a Bun-specific escape hatch in favor of something that TypeScript can typecheck, test authors can unit-test, and future maintainers can read without knowing Bun compile internals.

  • .fallowrc.json update registers the new bootstrap as a dead-code entry point, keeping Fallow accurate.


@github-actions

Copy link
Copy Markdown
Contributor

✅ Tests passed — 1393/1397

Suite Passed Failed Skipped
agent 271/271 0 0
build 26/26 0 0
eval 91/91 0 0
server-agent 301/301 0 0
server-api 138/138 0 0
server-browser 10/10 0 0
server-integration 10/10 0 0
server-lib 251/252 0 1
server-root 47/50 0 3
server-tools 248/248 0 0

View workflow run

@shadowfax92 Nikhil (shadowfax92) merged commit 33ee634 into main Jun 22, 2026
19 checks passed
@greptile-apps

greptile-apps Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes browseros_server --version in compiled production binaries by switching from Bun's --compile-exec-argv=--no-addons runtime flag to a JS-level native-addon guard installed at startup. The old approach caused Bun to intercept bare --version, requiring the awkward -- --version workaround; the new bootstrap entrypoint patches process.dlopen before loading the server, letting commander handle --version normally.

  • New compiled-bootstrap.ts entrypoint: installs installNativeAddonGuard() synchronously, then dynamically imports index.ts; replaces the previous --compile-exec-argv=--no-addons bun compile flag.
  • New native-addon-guard.ts: overwrites process.dlopen with a throwing stub and uses an idempotency marker on the process object to prevent double-installation.
  • Test updates: build.test.ts now invokes [binary, '--version'] directly and asserts the output is not Bun's own version string; native-addon-policy.test.ts adds an idempotency test and verifies no .node files are extracted to the temp directory.

Confidence Score: 4/5

The change is focused and well-tested; the main risk is the shift from a Bun runtime-enforced addon block to a JS-level dlopen patch, but the new test suite explicitly verifies both the guard and the absence of extracted .node files.

The bootstrap approach is clean and the tests cover the two critical properties (idempotency and no temp-file extraction). The one weak spot is the tautological constant test in native-addon-policy.test.ts, which would not catch the compile step silently using a different entrypoint.

packages/browseros-agent/scripts/build/server/native-addon-policy.test.ts — the first test is a constant-equality check that provides little coverage of the actual bundling behaviour.

Important Files Changed

Filename Overview
packages/browseros-agent/apps/server/src/compiled-bootstrap.ts New 4-line compiled entrypoint that installs the native-addon guard before dynamically importing index.ts; replaces the old --compile-exec-argv=--no-addons approach cleanly.
packages/browseros-agent/apps/server/src/lib/native-addon-guard.ts New module that patches process.dlopen to throw a descriptive error; includes idempotency guard via a property on the process object.
packages/browseros-agent/apps/server/src/index.ts Removes the isCompiledVersionRequest workaround and VERSION import; --version is now handled normally by commander since Bun no longer consumes the flag via --compile-exec-argv.
packages/browseros-agent/scripts/build/server/compile.ts Switches entrypoint from index.ts to compiled-bootstrap.ts, drops --compile-exec-argv=--no-addons from the bun build command, and renames the exported constant accordingly.
packages/browseros-agent/apps/server/tests/build.test.ts Updates --version invocation from [binary, '--', '--version'] to [binary, '--version'], and adds an assert that the output is not Bun's own version string.
packages/browseros-agent/scripts/build/server/native-addon-policy.test.ts Rewrites policy tests to use the JS-level guard; adds an idempotency test and a temp-dir contents assertion; the first test is a tautological constant check that adds minimal assurance.
packages/browseros-agent/.fallowrc.json Adds compiled-bootstrap.ts as an additional fallow entry point so the dependency graph analysis covers the new file.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph OLD["Old boot path (--compile-exec-argv=--no-addons)"]
        A1["bun build --compile index.ts\n--compile-exec-argv=--no-addons"] --> B1["Compiled binary"]
        B1 -->|"argv: binary -- --version"| C1["isCompiledVersionRequest() → true\nprint VERSION, exit 0"]
        B1 -->|"argv: binary"| D1["loadServerConfig() → Application.start()"]
        B1 -.->|"argv: binary --version\n(consumed by Bun runtime)"| E1["Bun prints its own version ❌"]
    end

    subgraph NEW["New boot path (JS-level guard)"]
        A2["bun build --compile compiled-bootstrap.ts"] --> B2["Compiled binary"]
        B2 -->|"any argv"| C2["installNativeAddonGuard()\npatches process.dlopen"]
        C2 --> D2["await import('./index')"]
        D2 -->|"argv: binary --version"| E2["commander handles --version ✅"]
        D2 -->|"argv: binary"| F2["loadServerConfig() → Application.start()"]
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    subgraph OLD["Old boot path (--compile-exec-argv=--no-addons)"]
        A1["bun build --compile index.ts\n--compile-exec-argv=--no-addons"] --> B1["Compiled binary"]
        B1 -->|"argv: binary -- --version"| C1["isCompiledVersionRequest() → true\nprint VERSION, exit 0"]
        B1 -->|"argv: binary"| D1["loadServerConfig() → Application.start()"]
        B1 -.->|"argv: binary --version\n(consumed by Bun runtime)"| E1["Bun prints its own version ❌"]
    end

    subgraph NEW["New boot path (JS-level guard)"]
        A2["bun build --compile compiled-bootstrap.ts"] --> B2["Compiled binary"]
        B2 -->|"any argv"| C2["installNativeAddonGuard()\npatches process.dlopen"]
        C2 --> D2["await import('./index')"]
        D2 -->|"argv: binary --version"| E2["commander handles --version ✅"]
        D2 -->|"argv: binary"| F2["loadServerConfig() → Application.start()"]
    end
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
packages/browseros-agent/scripts/build/server/native-addon-policy.test.ts:23-27
**Tautological constant test**

This test asserts that `SERVER_BUNDLE_ENTRYPOINT` equals the literal string `'apps/server/src/compiled-bootstrap.ts'`, but that value is the constant itself — the test can only fail if someone changes the constant and then edits this assertion to match. A more meaningful check would verify that the file referenced by the constant actually exists on disk, or that the bundle step picks it up as an entry point.

Reviews (1): Last reviewed commit: "chore: register compiled server entrypoi..." | Re-trigger Greptile

@greptile-apps

greptile-apps Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR replaces Bun's --compile-exec-argv=--no-addons flag with a JavaScript-level process.dlopen guard installed by a new compiled-bootstrap.ts entrypoint, restoring the ability to run browseros_server --version without the -- separator that Bun's embedded runtime previously required.

  • New bootstrap entrypoint (compiled-bootstrap.ts): installs the native-addon guard synchronously before dynamically importing index.ts, so the guard is always in place before any server code can trigger a require() of a .node file.
  • native-addon-guard.ts: idempotent process.dlopen patcher with a clear error message; replaces the now-removed --no-addons compile flag.
  • index.ts cleanup: removes the isCompiledVersionRequest workaround and unused VERSION import; --version now falls through naturally to Commander's .version() handler.

Confidence Score: 4/5

Safe to merge; the core logic change is small, well-tested, and the only finding is a test-path robustness issue.

The approach of patching process.dlopen is verified end-to-end by the updated test suite, and the --version restoration is confirmed by both the build test and Commander's own .version() handler. The one rough edge is that native-addon-policy.test.ts constructs the guard's file path with process.cwd() rather than import.meta.dir, which would silently produce wrong paths if the test runner's working directory is not packages/browseros-agent.

packages/browseros-agent/scripts/build/server/native-addon-policy.test.ts — the process.cwd()-based path construction.

Important Files Changed

Filename Overview
packages/browseros-agent/apps/server/src/compiled-bootstrap.ts New 4-line bootstrap that installs the native-addon guard synchronously then dynamically imports index.ts, ensuring the guard is in place before any server code executes.
packages/browseros-agent/apps/server/src/lib/native-addon-guard.ts New module that patches process.dlopen with an idempotent guard, replacing the removed --no-addons compile flag; guard check prevents double-installation and the approach is verified by the updated test suite.
packages/browseros-agent/apps/server/src/index.ts Removes the isCompiledVersionRequest workaround that parsed Bun's embedded-runtime argv separator (-- --version); --version is now handled naturally by Commander's .version(VERSION) in config.ts.
packages/browseros-agent/scripts/build/server/compile.ts Switches build entrypoint from index.ts to compiled-bootstrap.ts and drops the --compile-exec-argv=--no-addons flag; the bundle entry filename is updated correspondingly.
packages/browseros-agent/apps/server/tests/build.test.ts Updates the build smoke test to invoke --version directly (without the -- separator) and adds an assertion that the version output does not equal Bun.version.
packages/browseros-agent/scripts/build/server/native-addon-policy.test.ts Replaces the COMPILED_SERVER_EXEC_ARGV constant check with real behavioral tests (idempotency and addon-blocking); uses process.cwd() for the guard path which is fragile if tests are run outside packages/browseros-agent.
packages/browseros-agent/.fallowrc.json Adds compiled-bootstrap.ts as a second entry point so the fallow bundler tracks it alongside index.ts.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant OS as OS / Updater
    participant Boot as compiled-bootstrap.ts
    participant Guard as native-addon-guard.ts
    participant Index as index.ts
    participant Config as config.ts (Commander)

    OS->>Boot: "execve browseros_server [--version | --help | (none)]"
    Boot->>Guard: installNativeAddonGuard()
    Guard-->>Boot: process.dlopen patched (throws on call)
    Boot->>Index: await import('./index')
    Index->>Config: loadServerConfig() → parseCliArgs(argv)
    alt --version flag
        Config-->>OS: print VERSION, exit 0
    else normal start
        Config-->>Index: ConfigResult OK
        Index->>Index: new Application(config).start()
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant OS as OS / Updater
    participant Boot as compiled-bootstrap.ts
    participant Guard as native-addon-guard.ts
    participant Index as index.ts
    participant Config as config.ts (Commander)

    OS->>Boot: "execve browseros_server [--version | --help | (none)]"
    Boot->>Guard: installNativeAddonGuard()
    Guard-->>Boot: process.dlopen patched (throws on call)
    Boot->>Index: await import('./index')
    Index->>Config: loadServerConfig() → parseCliArgs(argv)
    alt --version flag
        Config-->>OS: print VERSION, exit 0
    else normal start
        Config-->>Index: ConfigResult OK
        Index->>Index: new Application(config).start()
    end
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
packages/browseros-agent/scripts/build/server/native-addon-policy.test.ts:8-11
Prefer `import.meta.dir` over `process.cwd()` so the path resolves correctly regardless of which working directory the test runner is launched from. If `bun test` is invoked from the repo root, `process.cwd()` won't point to `packages/browseros-agent` and every subprocess-spawning test in this file will fail with a module-not-found error.

```suggestion
const nativeAddonGuardPath = join(
  import.meta.dir,
  '../../../apps/server/src/lib/native-addon-guard.ts',
)
```

Reviews (2): Last reviewed commit: "chore: register compiled server entrypoi..." | Re-trigger Greptile

Comment on lines +8 to +11
const nativeAddonGuardPath = join(
process.cwd(),
'apps/server/src/lib/native-addon-guard.ts',
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Prefer import.meta.dir over process.cwd() so the path resolves correctly regardless of which working directory the test runner is launched from. If bun test is invoked from the repo root, process.cwd() won't point to packages/browseros-agent and every subprocess-spawning test in this file will fail with a module-not-found error.

Suggested change
const nativeAddonGuardPath = join(
process.cwd(),
'apps/server/src/lib/native-addon-guard.ts',
)
const nativeAddonGuardPath = join(
import.meta.dir,
'../../../apps/server/src/lib/native-addon-guard.ts',
)
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/browseros-agent/scripts/build/server/native-addon-policy.test.ts
Line: 8-11

Comment:
Prefer `import.meta.dir` over `process.cwd()` so the path resolves correctly regardless of which working directory the test runner is launched from. If `bun test` is invoked from the repo root, `process.cwd()` won't point to `packages/browseros-agent` and every subprocess-spawning test in this file will fail with a module-not-found error.

```suggestion
const nativeAddonGuardPath = join(
  import.meta.dir,
  '../../../apps/server/src/lib/native-addon-guard.ts',
)
```

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

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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