Problem
When an agent (Claude Code, etc.) needs to invalidate cached state inside a running daemon — most commonly the playwright-server module cache after editing a non-spec .ts file (UI model, fixture helper) — the only tool available today is shutdown + re-serve. That works, but it has a nasty side effect when the user is running davstack start (the TUI):
- The TUI launches the daemons and adopts their PIDs.
- The agent runs
playwright-server shutdown → the TUI's child dies.
- The agent runs
playwright-server serve → a new daemon starts, owned by the agent's shell, not the TUI.
- The TUI's panel now shows "not running" until the user manually restarts it, and stdout/stderr is going to the agent's terminal instead of the TUI's log panel.
In other words: an agent doing routine cache-busting silently steals the daemon out of the user's TUI session. The user has to notice and re-claim.
Concrete cases
- playwright-server: spec files get cache-busted via
?t=${Date.now()} (see session.ts:323), but any module a spec imports (*.ui.ts, fixtures/*.ts) is held in the worker's ESM cache forever. After editing a UI model, the daemon serves stale code until someone restarts.
- vitest-server: similar story for non-test code edits the vitest daemon doesn't pick up.
- logs-server: less impacted by code reload, but config edits or schema migrations to the per-session SQLite still need a clean way to flush without killing the process.
Proposal
Add a refresh verb to each of the three servers that does in-place reinitialisation without exiting:
playwright-server refresh # flushes spec-module ESM cache; re-reads config; reseats warm context if storageStatePath changed
vitest-server refresh # restarts the vitest worker pool / clears transform cache; re-reads config
logs-server refresh # re-reads config (cors, ports), reopens DB handles, flushes per-session SQLite cache
HTTP shape (mirrors existing shutdown / refresh-auth):
POST /refresh
→ { ok: true, refreshedAt: <iso> }
CLI shape:
playwright-server refresh # exits 0 on success
playwright-server refresh --hard # equivalent to today's shutdown + serve, for the rare case it's actually wanted
Implementation notes (playwright-server, by way of example)
- The cache problem is mostly the Node ESM loader. Two viable strategies:
- Re-register the loader hook with a new revision so subsequent dynamic imports get a fresh URL —
?t=${Date.now()} applied to ALL imports under the spec, not just the spec itself. Simplest; doesn't free memory but kills the stale-module problem.
- Spawn a fresh worker to host the spec module evaluation and discard the old one. Cleaner; more moving parts.
- Either way the warm Chromium context, persistent profile, and HTTP socket stay alive across the refresh. That's the whole value prop: the TUI's adopted PID never changes, the chromium window doesn't flash, and any in-flight
goto/runFile requests either complete or get a clean 503.
check should learn a refreshedAt field so the TUI can surface "last refreshed 12s ago" in its status panel.
Why this matters
Agentic loops over playwright-server land somewhere around 10-30 edit-rerun cycles for a feature. Today every cache-stale rerun forces either a noisy diagnostic ("why is my test still failing?") or a shutdown+serve that breaks the user's TUI session. A refresh verb closes that gap without making the agent and the human fight over daemon ownership.
Related
packages/playwright-server/src/session.ts:323 — current spec-only cache bust
packages/playwright-server/src/spec-runner.ts — registration-intercept module loader
packages/playwright-server/src/http.ts — existing /refresh-auth + /shutdown endpoints
packages/vitest-server/src/http.ts — same shape
packages/logs-server/src/server.ts — server entry; would need a refresh hook into config + db-cache
Problem
When an agent (Claude Code, etc.) needs to invalidate cached state inside a running daemon — most commonly the playwright-server module cache after editing a non-spec
.tsfile (UI model, fixture helper) — the only tool available today isshutdown+ re-serve. That works, but it has a nasty side effect when the user is runningdavstack start(the TUI):playwright-server shutdown→ the TUI's child dies.playwright-server serve→ a new daemon starts, owned by the agent's shell, not the TUI.In other words: an agent doing routine cache-busting silently steals the daemon out of the user's TUI session. The user has to notice and re-claim.
Concrete cases
?t=${Date.now()}(seesession.ts:323), but any module a spec imports (*.ui.ts,fixtures/*.ts) is held in the worker's ESM cache forever. After editing a UI model, the daemon serves stale code until someone restarts.Proposal
Add a
refreshverb to each of the three servers that does in-place reinitialisation without exiting:HTTP shape (mirrors existing
shutdown/refresh-auth):CLI shape:
Implementation notes (playwright-server, by way of example)
?t=${Date.now()}applied to ALL imports under the spec, not just the spec itself. Simplest; doesn't free memory but kills the stale-module problem.goto/runFilerequests either complete or get a clean 503.checkshould learn arefreshedAtfield so the TUI can surface "last refreshed 12s ago" in its status panel.Why this matters
Agentic loops over playwright-server land somewhere around 10-30 edit-rerun cycles for a feature. Today every cache-stale rerun forces either a noisy diagnostic ("why is my test still failing?") or a
shutdown+servethat breaks the user's TUI session. Arefreshverb closes that gap without making the agent and the human fight over daemon ownership.Related
packages/playwright-server/src/session.ts:323— current spec-only cache bustpackages/playwright-server/src/spec-runner.ts— registration-intercept module loaderpackages/playwright-server/src/http.ts— existing/refresh-auth+/shutdownendpointspackages/vitest-server/src/http.ts— same shapepackages/logs-server/src/server.ts— server entry; would need a refresh hook into config + db-cache