mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
1471881af7
* fix(plugins): canonicalize install record persistence Preserve canonical fields, passthrough metadata, untouched record identity, and deterministic serialized ordering across SQLite and post-core handoff. Punchcard-Session: amber-workshop-workshop-36 Co-authored-by: Galin Iliev <5711535+galiniliev@users.noreply.github.com> * fix(doctor): block invalid plugin record mutations Preflight persisted and legacy install-record state before registry repair, package cleanup, generation retirement, archival, or state-directory moves. Punchcard-Session: amber-workshop-workshop-36 Co-authored-by: Galin Iliev <5711535+galiniliev@users.noreply.github.com> * fix(plugins): harden install record map ownership Punchcard-Session: amber-workshop-workshop-36 Co-authored-by: Galin Iliev <5711535+galiniliev@users.noreply.github.com> * fix(update): preserve special plugin ids in payload checks Punchcard-Session: amber-workshop-workshop-36 Co-authored-by: Galin Iliev <5711535+galiniliev@users.noreply.github.com> * test(doctor): assert canonical install record maps Punchcard-Session: amber-workshop-workshop-36 Co-authored-by: Galin Iliev <5711535+galiniliev@users.noreply.github.com> * test(doctor): preserve invalid plugin index fixtures Punchcard-Session: amber-workshop-workshop-36 Co-authored-by: Galin Iliev <5711535+galiniliev@users.noreply.github.com> --------- Co-authored-by: Galin Iliev <5711535+galiniliev@users.noreply.github.com>
56 lines
1.8 KiB
TypeScript
56 lines
1.8 KiB
TypeScript
import fs from "node:fs";
|
|
import { safeParseJson } from "@openclaw/normalization-core";
|
|
import {
|
|
inspectPluginInstallRecordMap,
|
|
type PluginInstallRecordMapState,
|
|
} from "../config/plugin-install-record-map.js";
|
|
import { withOpenClawStateDatabaseReadOnly } from "../state/openclaw-state-db-readonly.js";
|
|
import {
|
|
resolveInstalledPluginIndexStateDatabaseOptions,
|
|
resolveInstalledPluginIndexStorePath,
|
|
type InstalledPluginIndexStoreOptions,
|
|
} from "./installed-plugin-index-store-path.js";
|
|
|
|
type InstalledPluginIndexRecordRow = {
|
|
install_records_json: string;
|
|
};
|
|
|
|
export function inspectPersistedInstalledPluginIndexInstallRecordsSync(
|
|
options: InstalledPluginIndexStoreOptions = {},
|
|
): PluginInstallRecordMapState {
|
|
const storePath = resolveInstalledPluginIndexStorePath(options);
|
|
if (!fs.existsSync(storePath) || options.filePath?.endsWith(".json")) {
|
|
return { status: "missing" };
|
|
}
|
|
try {
|
|
return withOpenClawStateDatabaseReadOnly(({ db }) => {
|
|
const hasTable = db
|
|
.prepare(
|
|
`SELECT 1
|
|
FROM sqlite_master
|
|
WHERE type = 'table' AND name = 'installed_plugin_index'`,
|
|
)
|
|
.get();
|
|
if (!hasTable) {
|
|
return { status: "missing" };
|
|
}
|
|
const row = db
|
|
.prepare(
|
|
`
|
|
SELECT install_records_json
|
|
FROM installed_plugin_index
|
|
WHERE index_key = ?
|
|
`,
|
|
)
|
|
.get("installed-plugin-index") as InstalledPluginIndexRecordRow | undefined;
|
|
if (!row) {
|
|
return { status: "missing" };
|
|
}
|
|
const parsed = safeParseJson(row.install_records_json);
|
|
return parsed === undefined ? { status: "invalid" } : inspectPluginInstallRecordMap(parsed);
|
|
}, resolveInstalledPluginIndexStateDatabaseOptions(options));
|
|
} catch {
|
|
return { status: "invalid" };
|
|
}
|
|
}
|