mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-16 19:21:40 +00:00
* fix(cli): harden official plugin recovery * fix(config): preserve include write context * fix(config): reject external include mutations * fix(config): bind snapshots to config paths * fix(config): preserve write ownership * fix(cli): preflight plugin config mutations * chore(plugin-sdk): refresh api baseline * test(config): prove install env policy mutations * fix(cli): preflight plugin updates * fix(cli): preflight non-npm id migrations * chore(plugin-sdk): refresh api baseline * fix(cli): satisfy plugin recovery checks
127 lines
4.4 KiB
TypeScript
127 lines
4.4 KiB
TypeScript
/** Builds and compares installed plugin index records for refresh decisions. */
|
|
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
|
import type { PluginInstallRecord } from "../config/types.plugins.js";
|
|
import {
|
|
clearLoadInstalledPluginIndexInstallRecordsCache,
|
|
loadInstalledPluginIndexInstallRecords,
|
|
loadInstalledPluginIndexInstallRecordsSync,
|
|
readPersistedInstalledPluginIndexInstallRecords,
|
|
readPersistedInstalledPluginIndexInstallRecordsSync,
|
|
} from "./installed-plugin-index-record-reader.js";
|
|
import { resolveInstalledPluginIndexStorePath } from "./installed-plugin-index-store-path.js";
|
|
import {
|
|
refreshPersistedInstalledPluginIndex,
|
|
refreshPersistedInstalledPluginIndexSync,
|
|
} from "./installed-plugin-index-store.js";
|
|
import type { RefreshInstalledPluginIndexParams } from "./installed-plugin-index.js";
|
|
import { recordPluginInstall, type PluginInstallUpdate } from "./installs.js";
|
|
|
|
export {
|
|
clearLoadInstalledPluginIndexInstallRecordsCache,
|
|
loadInstalledPluginIndexInstallRecords,
|
|
loadInstalledPluginIndexInstallRecordsSync,
|
|
readPersistedInstalledPluginIndexInstallRecords,
|
|
readPersistedInstalledPluginIndexInstallRecordsSync,
|
|
};
|
|
|
|
/** Config path for legacy plugin install records kept for migration/doctor flows. */
|
|
export const PLUGIN_INSTALLS_CONFIG_PATH = ["plugins", "installs"] as const;
|
|
|
|
/** Options shared by installed plugin index record storage helpers. */
|
|
export type InstalledPluginIndexRecordStoreOptions = {
|
|
env?: NodeJS.ProcessEnv;
|
|
stateDir?: string;
|
|
filePath?: string;
|
|
};
|
|
|
|
type InstalledPluginIndexRecordRefreshOptions = InstalledPluginIndexRecordStoreOptions &
|
|
Partial<Omit<RefreshInstalledPluginIndexParams, "reason" | "installRecords">> & {
|
|
now?: () => Date;
|
|
};
|
|
|
|
/** Resolves the installed plugin index record store path. */
|
|
export function resolveInstalledPluginIndexRecordsStorePath(
|
|
options: InstalledPluginIndexRecordStoreOptions = {},
|
|
): string {
|
|
return resolveInstalledPluginIndexStorePath(options);
|
|
}
|
|
|
|
/** Refreshes persisted installed plugin index records asynchronously. */
|
|
export async function writePersistedInstalledPluginIndexInstallRecords(
|
|
records: Record<string, PluginInstallRecord>,
|
|
options: InstalledPluginIndexRecordRefreshOptions = {},
|
|
): Promise<string> {
|
|
await refreshPersistedInstalledPluginIndex({
|
|
...options,
|
|
reason: "source-changed",
|
|
installRecords: records,
|
|
});
|
|
return resolveInstalledPluginIndexRecordsStorePath(options);
|
|
}
|
|
|
|
/** Refreshes persisted installed plugin index records synchronously. */
|
|
export function writePersistedInstalledPluginIndexInstallRecordsSync(
|
|
records: Record<string, PluginInstallRecord>,
|
|
options: InstalledPluginIndexRecordRefreshOptions = {},
|
|
): string {
|
|
refreshPersistedInstalledPluginIndexSync({
|
|
...options,
|
|
reason: "source-changed",
|
|
installRecords: records,
|
|
});
|
|
return resolveInstalledPluginIndexRecordsStorePath(options);
|
|
}
|
|
|
|
/** Returns config with plugin install records attached at the canonical config path. */
|
|
export function withPluginInstallRecords(
|
|
config: OpenClawConfig,
|
|
records: Record<string, PluginInstallRecord>,
|
|
): OpenClawConfig {
|
|
return {
|
|
...config,
|
|
plugins: {
|
|
...config.plugins,
|
|
installs: records,
|
|
},
|
|
};
|
|
}
|
|
|
|
/** Returns config with legacy plugin install records removed. */
|
|
export function withoutPluginInstallRecords(
|
|
config: OpenClawConfig,
|
|
options: { preserveEmptyPlugins?: boolean } = {},
|
|
): OpenClawConfig {
|
|
if (!config.plugins?.installs) {
|
|
return config;
|
|
}
|
|
const { installs: _installs, ...plugins } = config.plugins;
|
|
if (Object.keys(plugins).length === 0) {
|
|
if (options.preserveEmptyPlugins) {
|
|
return { ...config, plugins: {} };
|
|
}
|
|
const { plugins: _plugins, ...rest } = config;
|
|
return rest;
|
|
}
|
|
return {
|
|
...config,
|
|
plugins,
|
|
};
|
|
}
|
|
|
|
/** Applies one install update to an in-memory install record map. */
|
|
export function recordPluginInstallInRecords(
|
|
records: Record<string, PluginInstallRecord>,
|
|
update: PluginInstallUpdate,
|
|
): Record<string, PluginInstallRecord> {
|
|
return recordPluginInstall({ plugins: { installs: records } }, update).plugins?.installs ?? {};
|
|
}
|
|
|
|
/** Removes one plugin install record from an in-memory record map. */
|
|
export function removePluginInstallRecordFromRecords(
|
|
records: Record<string, PluginInstallRecord>,
|
|
pluginId: string,
|
|
): Record<string, PluginInstallRecord> {
|
|
const { [pluginId]: _removed, ...rest } = records;
|
|
return rest;
|
|
}
|