fix(onboard): preserve rerun config migrations

Fix non-interactive and wizard onboarding reruns so existing agent lists and bindings are preserved unless the user explicitly resets config.

Isolate legacy `plugins.installs` migration into its own write so the config size-drop allowance cannot mask unrelated config loss, while preserving new or repaired install records for the final plugin-index commit. Also keep shrinkwrap generation pinned to pnpm-locked transitive patch versions only when the dependency edge still allows that version, and isolate the tooling Vitest shard that mutates process state.

Fixes #84692.
Replaces #84748.

Co-authored-by: yetval <yetvald@gmail.com>
This commit is contained in:
Peter Steinberger
2026-05-27 18:05:07 +01:00
committed by GitHub
parent 11dfef201f
commit de5971eedc
19 changed files with 693 additions and 38 deletions

View File

@@ -26,6 +26,8 @@ vi.mock("../plugins/installed-plugin-index-records.js", async (importOriginal) =
import {
commitConfigWithPendingPluginInstalls,
commitConfigWriteWithPendingPluginInstalls,
stripPendingPluginInstallRecords,
unchangedPendingPluginInstallRecordIds,
} from "./plugins-install-record-commit.js";
describe("commitConfigWithPendingPluginInstalls", () => {
@@ -107,6 +109,47 @@ describe("commitConfigWithPendingPluginInstalls", () => {
});
});
it("strips only selected pending plugin install records", () => {
const config: OpenClawConfig = {
plugins: {
installs: {
legacy: { source: "npm", spec: "legacy@1.0.0" },
fresh: { source: "npm", spec: "fresh@1.0.0" },
},
},
};
expect(stripPendingPluginInstallRecords(config, ["legacy"])).toEqual({
plugins: {
installs: {
fresh: { source: "npm", spec: "fresh@1.0.0" },
},
},
});
});
it("selects only unchanged pending plugin install records for migration stripping", () => {
const baseConfig: OpenClawConfig = {
plugins: {
installs: {
legacy: { source: "npm", spec: "legacy@1.0.0" },
repaired: { source: "npm", spec: "repaired@1.0.0" },
},
},
};
const nextConfig: OpenClawConfig = {
plugins: {
installs: {
legacy: { source: "npm", spec: "legacy@1.0.0" },
repaired: { source: "npm", spec: "repaired@2.0.0" },
fresh: { source: "npm", spec: "fresh@1.0.0" },
},
},
};
expect(unchangedPendingPluginInstallRecordIds(nextConfig, baseConfig)).toEqual(["legacy"]);
});
it("does not add restart intent when pending records match the plugin index", async () => {
const existingRecords: Record<string, PluginInstallRecord> = {
demo: {