mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 12:56:01 -06:00
fix(update): adopt post-core plugin payloads
This commit is contained in:
@@ -2886,6 +2886,11 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
const postCoreHostVersion = await readPackageVersion(root);
|
||||
if (postCoreHostVersion) {
|
||||
process.env.OPENCLAW_COMPATIBILITY_HOST_VERSION = postCoreHostVersion;
|
||||
}
|
||||
|
||||
let postCoreConfigSnapshot = await readConfigFileSnapshot({ skipPluginValidation: true });
|
||||
const preUpdateSourceConfig = await readPostCorePreUpdateSourceConfig({
|
||||
sourceConfigPath: process.env[POST_CORE_UPDATE_SOURCE_CONFIG_PATH_ENV],
|
||||
|
||||
@@ -1143,6 +1143,10 @@ describe("repairMissingConfiguredPluginInstalls", () => {
|
||||
const npmRoot = makeTempDir();
|
||||
const packageDir = path.join(npmRoot, "node_modules", "@openclaw", "matrix");
|
||||
fs.mkdirSync(packageDir, { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.join(packageDir, "package.json"),
|
||||
JSON.stringify({ name: "@openclaw/matrix", version: "1.2.3" }),
|
||||
);
|
||||
mocks.resolveDefaultPluginNpmDir.mockReturnValue(npmRoot);
|
||||
mocks.listChannelPluginCatalogEntries.mockReturnValue([
|
||||
{
|
||||
@@ -1192,13 +1196,17 @@ describe("repairMissingConfiguredPluginInstalls", () => {
|
||||
});
|
||||
|
||||
expect(mocks.installPluginFromClawHub).not.toHaveBeenCalled();
|
||||
expectRecordFields(mockCallArg(mocks.installPluginFromNpmSpec), {
|
||||
spec: expectedNpmInstallSpec("@openclaw/matrix"),
|
||||
npmDir: npmRoot,
|
||||
mode: "update",
|
||||
});
|
||||
expect(mocks.installPluginFromNpmSpec).not.toHaveBeenCalled();
|
||||
expect(result.warnings).toEqual([]);
|
||||
expect(result.records.matrix?.installPath).toBe(packageDir);
|
||||
expectRecordFields(result.records.matrix, {
|
||||
source: "npm",
|
||||
spec: "@openclaw/matrix",
|
||||
installPath: packageDir,
|
||||
version: "1.2.3",
|
||||
resolvedName: "@openclaw/matrix",
|
||||
resolvedVersion: "1.2.3",
|
||||
resolvedSpec: "@openclaw/matrix@1.2.3",
|
||||
});
|
||||
});
|
||||
|
||||
it("repairs missing external payload during post-core convergence even with OPENCLAW_UPDATE_IN_PROGRESS=1", async () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { existsSync } from "node:fs";
|
||||
import { rm } from "node:fs/promises";
|
||||
import { readFile, rm } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import {
|
||||
listExplicitlyDisabledChannelIdsForConfig,
|
||||
@@ -54,6 +54,7 @@ import {
|
||||
} from "./configured-runtime-plugin-installs.js";
|
||||
import { asObjectRecord } from "./object.js";
|
||||
import {
|
||||
isPostCoreConvergencePass,
|
||||
isLegacyPackageUpdateDoctorPass,
|
||||
shouldDeferConfiguredPluginInstallRepair,
|
||||
} from "./update-phase.js";
|
||||
@@ -786,6 +787,21 @@ async function installCandidate(params: {
|
||||
const existingNpmPackagePath = npmInstallSpec
|
||||
? resolveExistingCandidateNpmPackagePath({ candidate, npmDir })
|
||||
: null;
|
||||
if (
|
||||
existingNpmPackagePath &&
|
||||
npmInstallSpec &&
|
||||
clawhubInstallSpec &&
|
||||
params.mode !== "update" &&
|
||||
isPostCoreConvergencePass(params.env)
|
||||
) {
|
||||
return await adoptExistingNpmPackage({
|
||||
candidate,
|
||||
records: params.records,
|
||||
npmInstallSpec,
|
||||
npmRecordSpec: npmSpecs?.recordSpec ?? npmInstallSpec,
|
||||
packagePath: existingNpmPackagePath,
|
||||
});
|
||||
}
|
||||
const shouldTryClawHub =
|
||||
clawhubInstallSpec &&
|
||||
!existingNpmPackagePath &&
|
||||
@@ -930,6 +946,52 @@ function resolveExistingCandidateClawHubPackagePath(params: {
|
||||
}
|
||||
}
|
||||
|
||||
async function readNpmPackageVersion(packagePath: string): Promise<string | undefined> {
|
||||
try {
|
||||
const parsed = JSON.parse(await readFile(path.join(packagePath, "package.json"), "utf-8")) as {
|
||||
version?: unknown;
|
||||
};
|
||||
return typeof parsed.version === "string" && parsed.version.trim()
|
||||
? parsed.version.trim()
|
||||
: undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async function adoptExistingNpmPackage(params: {
|
||||
candidate: DownloadableInstallCandidate;
|
||||
records: Record<string, PluginInstallRecord>;
|
||||
npmInstallSpec: string;
|
||||
npmRecordSpec: string;
|
||||
packagePath: string;
|
||||
}): Promise<{
|
||||
records: Record<string, PluginInstallRecord>;
|
||||
changes: string[];
|
||||
warnings: string[];
|
||||
}> {
|
||||
const version = await readNpmPackageVersion(params.packagePath);
|
||||
const npmName = parseRegistryNpmSpec(params.npmInstallSpec)?.name;
|
||||
return {
|
||||
records: {
|
||||
...params.records,
|
||||
[params.candidate.pluginId]: {
|
||||
source: "npm",
|
||||
spec: params.npmRecordSpec,
|
||||
installPath: params.packagePath,
|
||||
installedAt: new Date().toISOString(),
|
||||
...(version ? { version, resolvedVersion: version } : {}),
|
||||
...(npmName ? { resolvedName: npmName } : {}),
|
||||
...(npmName && version ? { resolvedSpec: `${npmName}@${version}` } : {}),
|
||||
},
|
||||
},
|
||||
changes: [
|
||||
`Repaired missing configured plugin "${params.candidate.pluginId}" from existing npm payload ${params.npmInstallSpec}.`,
|
||||
],
|
||||
warnings: [],
|
||||
};
|
||||
}
|
||||
|
||||
export type RepairMissingPluginInstallsResult = {
|
||||
changes: string[];
|
||||
warnings: string[];
|
||||
|
||||
Reference in New Issue
Block a user