fix(plugin): restart a server left on a retired plugin root
A plugin update applied mid-session (/plugin followed by /reload-plugins) fires no SessionStart, so the bootstrap's version handover never runs and the dashboard server keeps executing a cache directory Claude Code has already discarded. /ccam-open then rebuilt the bundle from the new root against that old server, and the new bundle called routes the old server never had: /api/lanes/pipeline-stats fell through to /:id and rendered "lane not found", /api/workflows/skill-usage fell through to the SPA catch-all and broke JSON.parse on the returned HTML. Both Workflows panels showed an error while the code they needed was sitting on disk. plugin-open now re-runs bootstrap when the live server's recorded pluginRoot differs from the current one, or when no server is live at all. Bootstrap already owns the stop/start and the dependency install the new root may need, so this only restores the trigger that a mid-session update skips.
This commit is contained in:
+1
-1
@@ -149,7 +149,7 @@ output goes to `client-build.log` next to it; the server's own output goes to
|
||||
|---|---|
|
||||
| `/ccam-doctor` | Node version, bootstrap state, runtime deps, server liveness, duplicate hooks, CLI launcher + PATH, MCP build freshness, UI bundle |
|
||||
| `/ccam-update` | Pull the latest `ccam` release via `claude plugin marketplace update` + `claude plugin update ccam@<marketplace> -y`, then reinstall dependencies and restart the server (`plugin-bootstrap.js --force`). The plugin pull needs a manual `/reload-plugins` afterward to take effect in the current session — not scriptable from a command. |
|
||||
| `/ccam-open` | Build the UI bundle if missing, then print the dashboard URL |
|
||||
| `/ccam-open` | Rebuild the UI bundle and print the dashboard URL. Re-runs the bootstrap first when the server is down or still executing a plugin root that a mid-session `/plugin` update retired, so a fresh bundle never talks to an older server's routes |
|
||||
|
||||
### Where things live
|
||||
|
||||
|
||||
@@ -12,8 +12,12 @@ node "${CLAUDE_PLUGIN_ROOT}/scripts/plugin-open.js" --force
|
||||
```
|
||||
|
||||
Install + build takes a few minutes if the client toolchain isn't already
|
||||
installed; otherwise the rebuild itself takes ~10-15s. No server restart is
|
||||
needed — the server already serves from that directory.
|
||||
installed; otherwise the rebuild itself takes ~10-15s. The server serves from
|
||||
that directory, so it usually needs no restart — but if it is down, or still
|
||||
running from a plugin root a mid-session `/plugin` update retired, the command
|
||||
re-runs bootstrap first and prints `Server restarted on the current plugin
|
||||
version.` (without it, the fresh bundle would call routes that old server
|
||||
never had).
|
||||
|
||||
Then help the user open it:
|
||||
|
||||
|
||||
+13
-1
@@ -6,7 +6,10 @@
|
||||
* on session start, so client-only routes (e.g. `/run`) work the moment
|
||||
* `claude` is started, not just the API and MCP tools. `/ccam-open` re-runs
|
||||
* this standalone — a no-op when the bundle already matches — as a fallback
|
||||
* for `--force` rebuilds or a first build that failed during bootstrap.
|
||||
* for `--force` rebuilds or a first build that failed during bootstrap, and it
|
||||
* re-runs bootstrap first when the live server belongs to a retired plugin root
|
||||
* (a mid-session `/plugin` update) so the new bundle is not left calling routes
|
||||
* the running server never had.
|
||||
*
|
||||
* The client source is copied out of the (replaced-on-update) plugin cache into
|
||||
* the runtime dir before building, so neither the cache nor the checkout is
|
||||
@@ -74,12 +77,21 @@ function dashboardUrl() {
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
// A plugin update applied mid-session (/plugin + /reload-plugins) fires no
|
||||
// SessionStart, so the server keeps executing a cache dir Claude Code has
|
||||
// already retired: a bundle rebuilt from the new root then calls routes that
|
||||
// old server never had. Hand the version handover back to bootstrap, which
|
||||
// owns stop/start and the dependency install the new root may need.
|
||||
const stale = (boot.readState() || {}).pluginRoot !== PLUGIN_ROOT || !boot.serverIsLive();
|
||||
if (stale) boot.bootstrap();
|
||||
|
||||
const result = buildClient({ force: process.argv.includes("--force") });
|
||||
if (result === "failed") {
|
||||
console.error("Client build failed — the API and MCP tools still work.");
|
||||
process.exitCode = 1;
|
||||
} else {
|
||||
if (result === "built") console.log("Dashboard UI built.");
|
||||
if (stale) console.log("Server restarted on the current plugin version.");
|
||||
console.log(dashboardUrl());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user