Skip to content

Fix self-host/Cloudflare update card always showing; show version in the dashboard#1204

Merged
RhysSullivan merged 1 commit into
mainfrom
fix/selfhost-update-card-version
Jun 29, 2026
Merged

Fix self-host/Cloudflare update card always showing; show version in the dashboard#1204
RhysSullivan merged 1 commit into
mainfrom
fix/selfhost-update-card-version

Conversation

@RhysSullivan

Copy link
Copy Markdown
Owner

Fixes a user report: on a Docker (Railway) self-host, the sidebar "update available" card showed even when running the latest version. Same report asked to surface the version in the dashboard. Both come from one root cause.

Root cause

The self-host and Cloudflare builds baked a placeholder VITE_APP_VERSION (0.0.0-selfhost / 0.0.0-cloudflare) into the web shell. The update card compares that against the published executor dist-tags, so compareVersions("0.0.0-selfhost", "1.5.23") was always -1 — permanently "behind", regardless of the deployed version. (The npm CLI and desktop builds already bake the real version, so they were fine.)

Fix

  • apps/host-selfhost and apps/host-cloudflare vite builds now read the real release version from the CLI package, exactly as apps/local does. The Docker image and Worker are built at the release tag, so this matches the published version.
  • The multiplayer shell sidebar footer now shows v<version> (it showed no version before), so self-hosters can see what they are on. Hidden on builds that do not inject a version (e.g. cloud).

After the fix: a build that is current shows no card and displays its version; when a newer version is published, the card returns.

no card when current, version in footer

Testing

  • e2e selfhost|cloudflare/update-card-render.test.ts now has two scenarios each, both green on the real self-host and Cloudflare UIs:
    • behind -> the card shows (existing), and
    • current -> NO card, and the footer shows the running version (new regression test). With the old placeholder this test fails because the card would show even against an older published version.
  • Format, lint, typecheck pass.

Note: deployed instances pick this up on their next image pull / redeploy (the version is baked at build time).

…dashboard

The self-host and Cloudflare builds baked a placeholder VITE_APP_VERSION
(0.0.0-selfhost / 0.0.0-cloudflare), so the update check always compared as
"behind" and the card showed even on the latest version. Bake the real release
version from the CLI package the same way apps/local does. Also surface the
running version in the multiplayer shell sidebar footer so self-hosters can see
what they are on. Adds a regression e2e: current build -> no card + version shown.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
executor-marketing 81c1880 Commit Preview URL

Branch Preview URL
Jun 29 2026, 04:31 AM

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
executor-cloud 81c1880 Jun 29 2026, 04:32 AM

@greptile-apps

greptile-apps Bot commented Jun 29, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes the self-host and Cloudflare web shells always showing an "update available" card by replacing baked-in placeholder versions (0.0.0-selfhost / 0.0.0-cloudflare) with the real CLI package version read at build time, matching the pattern already used by apps/local. It also adds a sidebar footer version display for self-hosters.

  • Both apps/host-cloudflare/vite.config.ts and apps/host-selfhost/vite.config.ts now read the version from ../cli/package.json via readFileSync at Vite build time, exactly mirroring apps/local.
  • packages/react/src/multiplayer/shell.tsx adds a VITE_APP_VERSION-gated footer line that is hidden when the env var is not injected (e.g. cloud).
  • New e2e regression scenarios in e2e/src/update-card-render.ts cover the "card absent when build is current" path for both selfhost and Cloudflare hosts.

Confidence Score: 4/5

The production fix is straightforward and correct — baking the real CLI version at build time is exactly how apps/local already works. The only rough edge is in the new regression test, which uses a fixed sleep to guard the negative assertion instead of waiting on a condition.

The vite config changes and shell.tsx addition are clean and low-risk. The one issue is a page.waitForTimeout(750) sleep in the new e2e scenario, which could be flaky under load and contradicts the project's explicit no-sleeps testing guideline.

e2e/src/update-card-render.ts — the registerUpdateCardCurrentScenario function uses a fixed sleep before its negative assertion.

Important Files Changed

Filename Overview
e2e/src/update-card-render.ts Adds registerUpdateCardCurrentScenario; uses a fixed 750 ms sleep (page.waitForTimeout) to settle state before the negative assertion, violating the e2e no-sleeps guideline.
apps/host-cloudflare/vite.config.ts Now reads the real CLI version from package.json at build time; fallback "0.0.0" is a safe improvement over the old placeholder; matches apps/local pattern.
apps/host-selfhost/vite.config.ts Same version-reading change as host-cloudflare; consistent with apps/local and the established pattern.
packages/react/src/multiplayer/shell.tsx Adds APP_VERSION module-level constant and a conditionally rendered footer paragraph; the optional-chaining type cast is correct for both Vite and non-Vite environments.
e2e/selfhost/update-card-render.test.ts Registers the new current-build scenario for the selfhost target; straightforward delegation.
e2e/cloudflare/update-card-render.test.ts Registers the new current-build scenario for the Cloudflare target; straightforward delegation.
.changeset/selfhost-update-card-version.md Changeset correctly marks patch bumps for host-selfhost, host-cloudflare, and react packages.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Build as Vite Build
    participant CLI as apps/cli/package.json
    participant Define as import.meta.env.VITE_APP_VERSION
    participant Shell as shell.tsx (runtime)
    participant API as /v1/app/npm/dist-tags
    participant Card as SidebarUpdateCard

    Build->>CLI: readFileSync("../cli/package.json")
    CLI-->>Build: "{ version: "1.5.23" }"
    Build->>Define: JSON.stringify("1.5.23")
    Note over Define: Statically baked into the bundle

    Shell->>Define: read APP_VERSION at module init
    Define-->>Shell: "1.5.23"
    Shell->>Shell: Render footer v1.5.23 (if APP_VERSION defined)

    Shell->>API: fetch dist-tags on mount
    API-->>Shell: "{ latest: "1.5.23" }"
    Shell->>Card: "compareVersions("1.5.23", "1.5.23") == 0"
    Card-->>Shell: hidden (no update needed)
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 Build as Vite Build
    participant CLI as apps/cli/package.json
    participant Define as import.meta.env.VITE_APP_VERSION
    participant Shell as shell.tsx (runtime)
    participant API as /v1/app/npm/dist-tags
    participant Card as SidebarUpdateCard

    Build->>CLI: readFileSync("../cli/package.json")
    CLI-->>Build: "{ version: "1.5.23" }"
    Build->>Define: JSON.stringify("1.5.23")
    Note over Define: Statically baked into the bundle

    Shell->>Define: read APP_VERSION at module init
    Define-->>Shell: "1.5.23"
    Shell->>Shell: Render footer v1.5.23 (if APP_VERSION defined)

    Shell->>API: fetch dist-tags on mount
    API-->>Shell: "{ latest: "1.5.23" }"
    Shell->>Card: "compareVersions("1.5.23", "1.5.23") == 0"
    Card-->>Shell: hidden (no update needed)
Loading

Reviews (1): Last reviewed commit: "Fix self-host/Cloudflare update card alw..." | Re-trigger Greptile

Comment on lines +97 to +103
// The mocked update check resolves on mount; give the state a beat to
// settle, then assert the card stayed hidden.
await page.waitForTimeout(750);
expect(
await page.getByText("Update available").count(),
"no update card when the build is current",
).toBe(0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Fixed sleep in negative assertion. The e2e/AGENTS.md guide says "no sleeps; wait on conditions," but page.waitForTimeout(750) is an unconditional 750 ms pause. For the negative case ("card must NOT appear"), Playwright's built-in waitFor({ state: "hidden" }) polls until the element is absent or a timeout fires, giving a deterministic wait without a magic constant that may be too short under load.

Suggested change
// The mocked update check resolves on mount; give the state a beat to
// settle, then assert the card stayed hidden.
await page.waitForTimeout(750);
expect(
await page.getByText("Update available").count(),
"no update card when the build is current",
).toBe(0);
// The mocked update check resolves on mount; wait for the card to be
// absent rather than sleeping a fixed duration.
const updateCard = page.getByText("Update available");
await updateCard.waitFor({ state: "hidden", timeout: 5_000 });
expect(
await updateCard.count(),
"no update card when the build is current",
).toBe(0);

Context Used: e2e/AGENTS.md (source)

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!

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Cloudflare preview

Torn down — the PR is closed.

@pkg-pr-new

pkg-pr-new Bot commented Jun 29, 2026

Copy link
Copy Markdown

Open in StackBlitz

@executor-js/cli

npm i https://pkg.pr.new/@executor-js/cli@1204

@executor-js/config

npm i https://pkg.pr.new/@executor-js/config@1204

@executor-js/execution

npm i https://pkg.pr.new/@executor-js/execution@1204

@executor-js/sdk

npm i https://pkg.pr.new/@executor-js/sdk@1204

@executor-js/codemode-core

npm i https://pkg.pr.new/@executor-js/codemode-core@1204

@executor-js/runtime-quickjs

npm i https://pkg.pr.new/@executor-js/runtime-quickjs@1204

@executor-js/plugin-file-secrets

npm i https://pkg.pr.new/@executor-js/plugin-file-secrets@1204

@executor-js/plugin-graphql

npm i https://pkg.pr.new/@executor-js/plugin-graphql@1204

@executor-js/plugin-keychain

npm i https://pkg.pr.new/@executor-js/plugin-keychain@1204

@executor-js/plugin-mcp

npm i https://pkg.pr.new/@executor-js/plugin-mcp@1204

@executor-js/plugin-onepassword

npm i https://pkg.pr.new/@executor-js/plugin-onepassword@1204

@executor-js/plugin-openapi

npm i https://pkg.pr.new/@executor-js/plugin-openapi@1204

executor

npm i https://pkg.pr.new/executor@1204

commit: 81c1880

@RhysSullivan

Copy link
Copy Markdown
Owner Author

Verified against the production build (prod serve.ts over the vite build dist, the exact artifact the Docker image serves). The dist bakes the real version (grep finds 1.5.23, no 0.0.0-selfhost placeholder), and the e2e card-render scenarios pass on the selfhost-docker target attached to it: current build shows no card and the footer shows the version.

docker prod build: no card, v1.5.23 in footer

(A real container wraps this same build; the web bundle and version injection are identical.)

@RhysSullivan RhysSullivan merged commit 9394217 into main Jun 29, 2026
27 of 30 checks passed
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.

1 participant