v0.20 PR 1: entrypoint dashboard sync, / redirect, /health HTML#71
v0.20 PR 1: entrypoint dashboard sync, / redirect, /health HTML#71
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7f682decfd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| headers: { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" }, | ||
| }); |
There was a problem hiding this comment.
Add Vary header for negotiated /health responses
The /health handler now serves different representations (HTML vs JSON) based on Accept, but the response headers do not include Vary: Accept. In any deployment with an HTTP cache/proxy in front of the app, one representation can be cached and then incorrectly reused for clients with different Accept headers (for example, a browser getting cached JSON instead of HTML). Add Vary: Accept to both representations to keep content negotiation correct.
Useful? React with 👍 / 👎.
Match the error-handling pattern used by the sibling chat sync block. Without 2>/dev/null || true, an unexpected rm/cp/chown failure under set -e would crash the entrypoint and the container restart-loops on deploy.
Bumps the version to 0.20.0 in every place it's referenced: - package.json (1) - src/core/server.ts VERSION constant - src/mcp/server.ts MCP server identity - src/cli/index.ts phantom --version output - README.md version + tests badges - CLAUDE.md tagline + bun test count - CONTRIBUTING.md test count Tests: 1,799 pass / 10 skip / 0 fail. Typecheck and lint clean. No 0.19.1 or 1,584-tests references remain in source, docs, or badges. v0.20 shipped eight PRs on top of v0.19.1: #71 entrypoint dashboard sync + / redirect + /health HTML #72 Sessions dashboard tab #73 Cost dashboard tab #74 Scheduler tab + create-job + Sonnet describe-assist #75 Evolution Phase A + Memory explorer tabs #76 Settings page restructure (phantom.yaml, 6 sections) #77 Agent avatar upload across 14 identity surfaces #79 Landing page redesign (hero, starter tiles, live pages list)
Summary
Four quick fixes teed up for v0.20. The most important is fix 1: the v0.19.1 dashboard fix never reached production on existing VMs because the entrypoint only syncs a whitelist of files from the image into the
phantom_publicvolume. Five of seven dashboard JS files on cheeks are still dated Apr 14. Fix 1 unblocks all subsequent v0.20 dashboard work.The four fixes
public/dashboard.scripts/docker-entrypoint.shnow replaces the entiredashboard/directory frompublic-defaults/on every container start, followed bychown -R 999:999so the non-rootphantomuser retains write access.chat/,_examples/, and the named top-level files keep their existing behaviour. Agent-created HTML at the top level is still preserved (we do not touch paths outside the enumerated set).src/ui/serve.tsreturnsCache-Control: no-store, no-cache, must-revalidateplusPragma: no-cache/Expires: 0for*.jsunder/ui/dashboard/. Every other asset keeps the existingno-cachepolicy. Defense in depth so future dashboard deploys reach every browser without a hard refresh./redirect to/ui/.src/core/server.tsreturns a 302 redirect for bare root (/or empty pathname) before the 404 catch-all. 302 (not 301) so we can change the destination later if we want. Nothing in Phantom today probes/; Docker HEALTHCHECK and CF probes target/health./healthHTML page with content negotiation.src/core/health-page.tsexportsrenderHealthHtml(payload). The/healthhandler returns the HTML page when the request acceptstext/html(browsers) and JSON otherwise (curl, Docker healthcheck, MCP clients, jq).?format=jsonoverrides to JSON regardless of Accept so the embedded JS can re-fetch itself. Design matchespublic/index.html: warm cream tokens, Instrument Serif display, Inter body, JetBrains Mono numerics, status badge, memory dots, channel chips, evolution pill, scheduler stats, peers table. Auto-refresh every 10 seconds viasetInterval. Zero console errors in both light and dark themes.Why this lands now
public/dashboard/*.jschange silently fails to reach the browser on existing VMs.no-storecache header closes the long-tail "user's cached session keeps the stale JS after the deploy" hole./redirect replaces the current{"error":"Not found"}404 JSON that operators see when they type the bare domain./healthHTML page replaces the raw JSON operators land on when they click the Health quick-link from/ui/.Research
local/2026-04-16-v0.20-next-level/research/01-wave-1-quick-fixes.mdTest plan
Automated (all green locally)
bun run typecheckcleanbun run lintcleanbun test1610 pass, 10 skip, 0 failbash -n scripts/docker-entrypoint.shexits 0src/core/__tests__/server.test.tscovers/302 redirect,/healthJSON default,/healthHTML on text/html,/healthJSON on application/json,/healthbrowser-style Accept returns HTML,/health?format=jsonoverrides HTML Acceptsrc/ui/__tests__/serve.test.tsadds cache-control coverage: dashboard JS getsno-store, no-cache, must-revalidate, other assets keepno-cacheManual
curl -I http://localhost:3000/shows 302 with Location: /ui/curl -H "Accept: text/html" http://localhost:3000/healthreturns HTML with the agent name in the title and display headingcurl http://localhost:3000/healthreturns JSON (default Accept behaviour preserved for Docker HEALTHCHECK)curl -I http://localhost:3000/ui/dashboard/dashboard.jsshowsCache-Control: no-store, no-cache, must-revalidate/health, verify HTML renders with zero console errors in both light and dark themes, auto-refreshes every 10 sdocker exec phantom md5sum /app/public/dashboard/dashboard.js /app/public-defaults/dashboard/dashboard.jsreturns identical MD5s afterdocker compose up -d --force-recreate phantomNot in this PR