fix(updates): report a plugin build installed beside the running one, never "up to date" on a failed check
A `claude plugin update` run from a terminal (or with only the Claude desktop
app open) unpacks the new build and starts nothing: no SessionStart fires, so
the dashboard kept running the old cache dir across reboots, and with the
forge unreachable the sidebar read "Up to date" (seen on a machine stuck at
1.8.10).
- pluginStatus asks supersededBy for its own root: a recorded sibling install
sets `installed_not_running: {root, version}` and `update_available`, with
no network needed
- the sidebar reads "<version> installed, not running"; the update modal keys
on it, so Update now is offered even with no release tag or sha
- plugin-update-helper hands over to the recorded install first, the newest
sibling dir only as a fallback
- a plugin install whose release lookup failed reads "Could not check for
updates" instead of "Up to date"
- docs/PLUGINS.md: the case and the manual hand-over command
This commit is contained in:
@@ -384,3 +384,39 @@ describe("fetchReleaseFromUrl", () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("a newer build installed beside the running one", () => {
|
||||
/** Record `installed` as Claude Code's install of agenthub@sg. */
|
||||
function recordInstall(home, installed) {
|
||||
fs.writeFileSync(
|
||||
path.join(home, "plugins", "installed_plugins.json"),
|
||||
JSON.stringify({ plugins: { "agenthub@sg": [{ scope: "user", installPath: installed }] } })
|
||||
);
|
||||
}
|
||||
|
||||
it("reports an update even when the release check fails", async () => {
|
||||
// `claude plugin update` from a terminal unpacks the new build and starts
|
||||
// nothing: the server keeps running the old directory, and with the forge
|
||||
// unreachable it used to answer "up to date" forever.
|
||||
const { root, home } = makePluginInstall("installed-newer", { version: "1.8.10" });
|
||||
const newer = path.join(path.dirname(root), "aaaaaaaaaaaa");
|
||||
fs.mkdirSync(newer, { recursive: true });
|
||||
fs.writeFileSync(path.join(newer, "package.json"), JSON.stringify({ version: "1.8.12" }));
|
||||
recordInstall(home, newer);
|
||||
|
||||
const s = await getUpdatesStatus(root, {
|
||||
latestRelease: { ok: false, reason: "unreachable" },
|
||||
});
|
||||
assert.equal(s.update_available, true);
|
||||
assert.deepEqual(s.installed_not_running, { root: newer, version: "1.8.12" });
|
||||
assert.match(s.message, /1\.8\.12 is installed but not running/);
|
||||
});
|
||||
|
||||
it("says nothing extra when the running build is the installed one", async () => {
|
||||
const { root, home } = makePluginInstall("installed-same", { version: "1.8.12" });
|
||||
recordInstall(home, root);
|
||||
const s = await getUpdatesStatus(root, { latestRelease: release("v1.8.12") });
|
||||
assert.equal(s.update_available, false);
|
||||
assert.equal(s.installed_not_running, null);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user