Skip to content

fix(server): serve the desktop bundle's dashboard from an ocx the app did not start - #6722

Merged
lidge-jun merged 2 commits into
lidge-jun:devfrom
sungyongcho:fix/gui-dist-packaged-layout
Oct 8, 2026
Merged

lidge-jun merged 2 commits into
lidge-jun:devfrom
sungyongcho:fix/gui-dist-packaged-layout

Conversation

@sungyongcho

@sungyongcho sungyongcho commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary

When the desktop shell did not start a desktop-bundled ocx itself, that proxy served no dashboard. The shell passes OPENCODEX_GUI_DIST only to the sidecar it spawns. ocx ensure from the Codex autostart shim and the login service run the same /usr/bin/ocx without the variable. findGuiDist() then checked only /usr/bin/gui/dist and source-tree paths, while the .deb installs the dashboard at /usr/lib/OpenCodex/gui/dist. The proxy answered GET / with the "GUI build not found" JSON, and a desktop app reopened afterwards attached to it as a guest and showed that JSON in its window.

For a standalone binary, findGuiDist() now also tries the desktop bundle's resource directory. The rule mirrors Tauri's resource_dir in tauri-utils 2.9.3, the version locked in desktop/src-tauri/Cargo.lock:

  • Linux: <exe dir>/../lib/OpenCodex/gui/dist. This covers the .deb (/usr/bin), /usr/local/bin, a custom prefix, and an AppImage's $APPDIR/usr/bin.
  • macOS: <exe dir>/../Resources/gui/dist, for OpenCodex.app/Contents/MacOS/ocx.
  • Windows: unchanged. Tauri keeps resources beside the executable, and the existing candidate already covers that. A Windows binary does not consult the Linux or macOS directories.

The lookup order is otherwise unchanged:

  1. OPENCODEX_GUI_DIST
  2. beside the binary
  3. the bundle directory
  4. the source checkout

Discovery only checks whether index.html exists. It creates, copies and builds nothing, does not change the environment, and does not start or stop anything. findGuiDist() now takes an optional lookup object (standaloneDir, platform, moduleDir) so tests can drive synthetic layouts; production callers pass nothing. The served-index path is untouched: serveGuiFile() and the session-bootstrap injection work as before.

The desktop's guest-attach behavior does not change. A reopened app still attaches to a runtime that is already listening, but that runtime now serves the dashboard.

Closes #6720

Verification

Run on Ubuntu 26.04 (x86_64) at head d73bd2b230, which sits on the current dev tip bbab02ab27.

Path-fixture tests (synthetic layouts, tests/gui/gui-static.test.ts)

19 pass / 0 fail on Ubuntu. With the Linux and macOS bundle candidates disabled, 9 of them fail. The remaining cases guard behavior this PR must not change, so they pass both ways. On the M1 MacBook below, the file at 609bc8d923 (its first 9 tests, before the second commit added the rest) ran 9 pass / 0 fail.

Case Covered by
Linux .deb /usr/bin → /usr/lib/OpenCodex packaged-layout table
AppImage $APPDIR/usr/bin → $APPDIR/usr/lib/OpenCodex, /usr/local and /opt prefixes packaged-layout table
macOS Contents/MacOS → Contents/Resources packaged-layout table
Windows: resources beside ocx.exe; Linux and macOS directories not consulted packaged-layout table, plus a dedicated Windows test
OPENCODEX_GUI_DIST wins over every packaged layout env-override test
Beside-the-binary gui/dist wins over a bundle layout precedence test
Source checkout serves its own gui/dist and never consults a bundle layout; a packaged layout comes before the checkout fallback two fallback tests
No resources anywhere → null, so GET / keeps the JSON fallback absent-resources test
A discovered bundle serves index.html (and an SPA route) with no-store and the session-bootstrap meta tags session test
Discovery creates no files and leaves process.env unchanged read-only test
DESKTOP_PRODUCT_NAME matches productName in tauri.conf.json, and the bundle maps a resource to gui/dist source-oracle test

Packaged artifacts actually tested

For each artifact I compiled two probe binaries with bun build --compile. One imports this branch's findGuiDist (and, on Linux, serveGuiFile); the other imports dev's src/server/gui-static.ts. I placed both in the artifact's executable directory and ran them without OPENCODEX_GUI_DIST.

  • On Linux, HOME, OPENCODEX_HOME and CODEX_HOME pointed at empty temporary directories, which stayed empty.
  • On macOS, snapshots of ~/.codex and ~/.opencodex were identical before and after each run.
  • No proxy was started anywhere.
Artifact How This branch dev
open-codex 2.80.0 .deb, installed (/usr/bin/ocx, /usr/lib/OpenCodex/gui/dist/index.html, no /usr/bin/gui) probes in <tmp>/usr/bin, with <tmp>/usr/lib/OpenCodex a symlink to the installed /usr/lib/OpenCodex resolves the packaged gui/dist; GET / returns text/html, no-store, with session meta null
OpenCodex-2.80.0-linux-x86_64.AppImage (SHA-256 matches the release asset digest; not executed) squashfs listed and usr/lib/OpenCodex/gui extracted with unsquashfs; the payload has usr/bin/ocx and no usr/bin/gui; probes placed in the extracted usr/bin same as above null
OpenCodex-2.80.0-macos.dmg on an M1 MacBook Pro, macOS 27.0.1 arm64 (SHA-256 matches the release .sha256; mounted read-only, nothing installed). The bundle has Contents/MacOS/ocx, Contents/Resources/gui/dist/index.html, and no Contents/MacOS/gui probes in <tmp>/OpenCodex.app/Contents/MacOS, with Contents/Resources a symlink to the mounted bundle's; run at 609bc8d923 resolves the packaged Contents/Resources/gui/dist null
The live bug, before this change the installed 2.80.0 /usr/bin/ocx, started by ocx ensure from the Codex shim — GET / returned the "GUI build not found" JSON (see #6720)

The macOS run used 609bc8d923. d73bd2b230 only adds findGuiDist()'s optional lookup object and tests. A call without arguments, which is what every production caller makes, resolves exactly as before. The platform-macos CI leg does not run for this path, so this M1 run is the macOS hardware evidence.

A side note from that run, unrelated to this PR: on macOS 27.0.1, Bun 1.4.0's bun build --compile left the probes' ad-hoc signature invalid. The first run of each probe was SIGKILLed (exit 137), and re-signing with codesign --force --sign - fixed it. The shipped 2.80.0 ocx is Developer ID signed and verifies. This only matters to someone building ocx locally on macOS.

Not tested on hardware:

  • Windows: I have no Windows machine. Its layout is the existing one, and the fixture tests run on the Windows CI shards once CI is approved.
  • End to end: I did not start a proxy from a branch-built ocx against a packaged layout, to avoid touching the proxy already running on this machine. The served-index path is covered by the probes and the session test above.

Other checks

  • bun run test:changed (merge base bbab02ab27): 3007 pass / 31 skip / 0 fail across 146 files.
  • Full bun run test at 609bc8d923 (the fix commit; the second commit only adds tests and the lookup object): run in two parts.
    • A 10 GB memory-capped run had one worker SIGKILLed (tests/storage/storage-restore-job-responsive.test.ts). The runner stopped with 371 files not started.
    • The first part covered about 1,730 files. Its only failures are the host-specific tests listed below.
    • The second part ran the remaining, interrupted and crashed 375 files: 6471 pass / 75 skip / 0 fail.
  • bun run typecheck, bun run structure:check, bun run privacy:scan: pass.

Unrelated test failures on this host (the test cases need an update)

These fail identically with and without this change. I ran each file on its own against both this branch and dev's src/server/gui-static.ts, with the same pass and fail counts. They come from the test machine, not from this PR, and should be fixed in the tests:

  • tests/clients/link-ssh-argv.test.ts (2 tests: "the remote prelude appends ~/.bun/bin after the remote PATH and keeps every argument" and "the constructed remote command preserves POSIX argument bytes").
    • Both use PATH: "/usr/bin:/bin" as the fake remote PATH. On a host where the Linux desktop package has installed /usr/bin/ocx, that real binary resolves first, which is what the prelude intends ("an ocx the remote PATH already resolves wins"). The stub in ~/.bun/bin therefore never runs.
    • Fixed separately in test(link): isolate the remote-prelude tests from a host-installed ocx #6726, which gives the fixture a remote PATH holding only an sh symlink to /bin/sh (remoteOcxArgv runs sh -c).
  • tests/config/serving-runtimes.test.ts (2), tests/codex-integration/codex-runtime.test.ts (1), tests/cli/cli-connect-readiness.test.ts (1).
    • These also fail on unchanged dev on this machine, which has the .deb ocx and the Codex App runtime installed. For example, resolveCodexRuntime with PATH: "" returns source: "installed" where the test expects "fallback".
    • I have not root-caused them. They look like the same class of problem: the tests read installed binaries from the host.
  • tests/cli/cli-access-audio-live.test.ts timed out under full-suite load and passes on its own (36 / 0).

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
    • structure/dashboard-and-usage.md states the new lookup order.
    • structure/ops/service-and-sidecars.md is still accurate as written.
    • No docs-site page describes where a desktop install keeps the dashboard.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.
    • The change only adds existence checks on fixed paths next to the executable.
    • The served directory still goes through the path containment in resolveGuiFilePath.
    • On Linux the new directory is root-owned for a packaged install. For a user-installed ocx, it is no more writable than the existing beside-the-binary candidate or the binary itself.

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • Required local validation passed; commands, results, and any full-suite exception are documented.

  • I pushed my PR to a recent dev commit (at most 10 behind; a maintainer may still ask for the exact tip before merge).

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

Summary by CodeRabbit

  • New Features
    • Standalone desktop apps can now locate their dashboard in the executable’s nearby folder or the platform’s packaged resource directory, with source-checkout locations as a fallback.
    • The existing OPENCODEX_GUI_DIST override retains priority.
  • Documentation
    • Updated dashboard setup guidance to describe standalone app directory lookup.

@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: lidge-jun/opencodex/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 746ae643-f42f-43f6-9e7b-f0136568aecf
📥 Commits

Reviewing files that changed from the base of the PR and between bbab02a and d73bd2b.

📒 Files selected for processing (3)
  • src/server/gui-static.ts
  • structure/dashboard-and-usage.md
  • tests/gui/gui-static.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

Standalone GUI discovery now checks platform-specific desktop bundle paths, in addition to the executable-adjacent path. The environment override and source-checkout fallbacks retain their existing precedence. Tests cover packaged layouts and dashboard responses.

Changes

Standalone GUI discovery

Layer / File(s) Summary
Resolve packaged dashboard candidates
src/server/gui-static.ts, tests/gui/gui-static.test.ts, structure/dashboard-and-usage.md
findGuiDist now checks executable-adjacent and platform-specific bundle paths. Tests cover platform layouts, lookup precedence, source-checkout fallback, and missing dashboards. The documentation describes the bundle resource paths.
Serve the discovered dashboard
tests/gui/gui-static.test.ts
Tests verify that discovered dashboards serve / and /models with session bootstrap metadata, and that discovery does not change files or environment variables.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: lidge-jun

Merge Risk: ⚪ Minimal · up to d73bd

This change lets a standalone ocx binary find the desktop bundle's dashboard on Linux and macOS. No concrete merge-blocking risk was identified.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Issue #6720 is an active direct link. The implementation meets its coding requirements. In src/server/gui-static.ts:29-33, standaloneGuiDistCandidates() keeps the beside-binary candidate and adds …
Out of Scope Changes check ✅ Passed The changes stay within issue #6720. The production change is limited to dashboard discovery in src/server/gui-static.ts. The additions in tests/gui/gui-static.test.ts verify the required platform…
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 2 files. (1 skipped: 1 u…
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: serving the desktop bundle dashboard when an ocx process did not start the app. It is specific, concise, and directly related to the updated standalone …
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

✅ Deterministic PR hygiene checks passed.

@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

✅ READY

  • all PR quality gates passed; the review readiness checklist is complete.

Review readiness checklist

  • ✅ Required local validation passed; commands, results, and any full-suite exception are documented.
  • ✅ I pushed my PR to a recent dev commit (at most 10 behind; a maintainer may still ask for the exact tip before merge).
  • ✅ I resolved all correct Codex and CodeRabbit findings.
  • ✅ My PR is ready for review.

✅ 4/4 boxes ticked.

This pull request is already Ready for Review.
The review-ready label marks this PR as ready; review automation runs independently.
Maintainers: @lidge-jun @Ingwannu

@github-actions github-actions Bot added the bug Something isn't working label Oct 8, 2026
@sungyongcho

Copy link
Copy Markdown
Contributor Author

@codex review

@sungyongcho

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@lidge-jun
lidge-jun marked this pull request as ready for review October 8, 2026 01:16
@lidge-jun
lidge-jun merged commit ab53742 into lidge-jun:dev Oct 8, 2026
118 of 127 checks passed
@lidge-jun lidge-jun mentioned this pull request Oct 8, 2026
3 tasks done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working review-ready

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants