import { C as hashStableJson } from "./discovery-DUKpMd1M.js";
import { c as resolveUserPath } from "./home-dir-BFvskzn8.js";
import { o as isGatewayPluginMetadataSnapshotActive } from "./current-plugin-metadata-state-C9do4nKP.js";
import { t as clearPluginMetadataLifecycleCaches } from "./plugin-metadata-lifecycle-C-Fgq33W.js";
import { d as extractPluginInstallRecordsFromInstalledPluginIndex, f as resolveCompatRegistryVersion, n as hasInstalledPluginIndexWorkspaceScopeMismatch, o as refreshInstalledPluginIndex, p as resolveInstalledPluginIndexPolicyHash, s as INSTALLED_PLUGIN_INDEX_WARNING } from "./installed-plugin-index-eRMeMKev.js";
import { c as resolveEffectiveEnableState, s as normalizePluginsConfig } from "./config-state-BtLgAen1.js";
import { r as resolveInstalledPluginIndexInstallOwner, t as isInstalledPluginIndexInstallOwnerAmbiguous } from "./installed-plugin-index-install-owner-Bd-Byre8.js";
import { o as resolveCompatibilityHostVersion } from "./version-CyS-R7WB.js";
import { t as isPluginEnabledByDefaultForPlatform } from "./default-enablement-CEIbpabL.js";
import { a as inspectPluginInstallRecordMap, c as serializePluginInstallRecordMap, l as setPluginInstallRecordMapEntry, o as parsePluginInstallRecord, r as createPluginInstallRecordMap } from "./plugin-install-record-map-BGcwGvXL.js";
import { l as resolveInstalledPluginIndexStateDatabaseOptions, o as clearLoadInstalledPluginIndexInstallRecordsCache, u as resolveInstalledPluginIndexStorePath } from "./installed-plugin-index-record-reader-veV-zWXU.js";
import { r as hasMissingConfigPathActivationMetadata } from "./installed-plugin-index-config-path-scope-BAeCI-f_.js";
import { i as readInstalledPluginIndexRow, o as readPersistedInstalledPluginIndexSync, r as parseInstalledPluginIndexSqliteRow, t as INSTALLED_PLUGIN_INDEX_STATE_KEY } from "./installed-plugin-index-store-CSRUh_M4.js";
import { t as hasMissingInstalledPluginOwnerMetadata } from "./installed-plugin-package-ownership-B8f8deQc.js";
import { s as runOpenClawStateWriteTransaction } from "./openclaw-state-db-Cb4e1jdd.js";
import { existsSync } from "node:fs";
//#region src/plugins/installed-plugin-index-store-write.ts
/** Writes, restores, and refreshes the installed plugin index in the state database. */
function assertWritableInstalledPluginIndexStoreOptions(options) {
	if (options.filePath?.endsWith(".json")) throw new Error("Explicit JSON installed plugin index paths are retired. Use the shared SQLite state DB or run openclaw doctor --fix to migrate legacy plugins/installs.json.");
}
function preparePersistedInstalledPluginIndex(index) {
	const installRecords = createPluginInstallRecordMap();
	for (const [pluginId, rawRecord] of Object.entries(index.installRecords)) {
		const record = parsePluginInstallRecord(rawRecord);
		if (!record) throw new Error("Invalid plugin install record");
		setPluginInstallRecordMapEntry(installRecords, pluginId, record);
	}
	return {
		...index,
		warning: INSTALLED_PLUGIN_INDEX_WARNING,
		installRecords
	};
}
function resolveNextInstalledPluginIndexRevision(current) {
	return Math.max(Date.now(), (current ?? 0) + 1);
}
function writePersistedInstalledPluginIndexRow(database, index, revision) {
	const persistedIndex = {
		version: index.version,
		warning: index.warning ?? "DO NOT EDIT. This file is generated by OpenClaw from plugin manifests, install records, and config policy. Use `openclaw plugins registry --refresh`, `openclaw plugins install/update/uninstall`, or `openclaw plugins enable/disable` instead.",
		hostContractVersion: index.hostContractVersion,
		compatRegistryVersion: index.compatRegistryVersion,
		migrationVersion: index.migrationVersion,
		policyHash: index.policyHash,
		generatedAtMs: index.generatedAtMs,
		...index.workspaceDir !== void 0 ? { workspaceDir: index.workspaceDir } : {},
		...index.refreshReason ? { refreshReason: index.refreshReason } : {},
		installRecords: JSON.parse(serializePluginInstallRecordMap(index.installRecords)),
		plugins: index.plugins.map((plugin) => {
			const installOwner = resolveInstalledPluginIndexInstallOwner(plugin);
			return {
				...plugin,
				...installOwner ? { installOwner } : {},
				...isInstalledPluginIndexInstallOwnerAmbiguous(plugin) ? { installOwnerAmbiguous: true } : {}
			};
		}),
		diagnostics: index.diagnostics
	};
	const valueJson = JSON.stringify({
		revision,
		index: persistedIndex
	});
	database.prepare(`
        INSERT INTO config_machine_state (state_key, value_json, updated_at_ms)
        VALUES (?, ?, ?)
        ON CONFLICT(state_key) DO UPDATE SET
          value_json = excluded.value_json,
          updated_at_ms = excluded.updated_at_ms
      `).run(INSTALLED_PLUGIN_INDEX_STATE_KEY, valueJson, revision);
}
function writePersistedInstalledPluginIndexToSqlite(index, options = {}, lease) {
	assertWritableInstalledPluginIndexStoreOptions(options);
	const persisted = preparePersistedInstalledPluginIndex(index);
	return runOpenClawStateWriteTransaction(({ db }) => {
		const previousRow = readInstalledPluginIndexRow(db);
		if (previousRow) {
			const previousInstallRecords = previousRow.index?.installRecords;
			if (previousInstallRecords === void 0 || inspectPluginInstallRecordMap(previousInstallRecords).status === "invalid") throw new Error("Persisted plugin install records are invalid. Repair the state before writing plugin installation metadata.");
		}
		lease?.assertOwnedInTransaction(db);
		const revision = resolveNextInstalledPluginIndexRevision(previousRow ? previousRow.revision : null);
		writePersistedInstalledPluginIndexRow(db, persisted, revision);
		return {
			previous: parseInstalledPluginIndexSqliteRow(previousRow),
			revision
		};
	}, resolveInstalledPluginIndexStateDatabaseOptions(options));
}
function clearPersistedInstalledPluginIndexCaches() {
	if (!isGatewayPluginMetadataSnapshotActive()) clearPluginMetadataLifecycleCaches();
	clearLoadInstalledPluginIndexInstallRecordsCache();
}
async function writePersistedInstalledPluginIndex(index, options = {}) {
	return writePersistedInstalledPluginIndexSync(index, options);
}
/** Restore a snapshot only while the caller's tentative write is still current. */
async function restorePersistedInstalledPluginIndexIfCurrent(index, expectedRevision, options) {
	const { lease, ...storeOptions } = options;
	assertWritableInstalledPluginIndexStoreOptions(storeOptions);
	if (!existsSync(resolveInstalledPluginIndexStorePath(storeOptions))) return false;
	const restored = runOpenClawStateWriteTransaction(({ db }) => {
		lease.assertOwnedInTransaction(db);
		const currentRow = readInstalledPluginIndexRow(db);
		const currentRevision = currentRow ? currentRow.revision : null;
		if (currentRevision !== expectedRevision) return false;
		if (index) writePersistedInstalledPluginIndexRow(db, preparePersistedInstalledPluginIndex(index), resolveNextInstalledPluginIndexRevision(currentRevision));
		else db.prepare("DELETE FROM config_machine_state WHERE state_key = ?").run(INSTALLED_PLUGIN_INDEX_STATE_KEY);
		return true;
	}, resolveInstalledPluginIndexStateDatabaseOptions(storeOptions));
	clearPersistedInstalledPluginIndexCaches();
	return restored;
}
function writePersistedInstalledPluginIndexSync(index, options = {}) {
	const filePath = resolveInstalledPluginIndexStorePath(options);
	writePersistedInstalledPluginIndexToSqlite(index, options);
	clearPersistedInstalledPluginIndexCaches();
	return filePath;
}
function writePersistedInstalledPluginIndexWithLeaseSync(index, options) {
	const { lease, ...storeOptions } = options;
	const filePath = resolveInstalledPluginIndexStorePath(storeOptions);
	writePersistedInstalledPluginIndexToSqlite(index, storeOptions, lease);
	clearPersistedInstalledPluginIndexCaches();
	return filePath;
}
function hasCompletePolicyRefreshProjection(persisted, policyPluginIds, env) {
	const pluginIds = new Set(persisted.plugins.map((plugin) => plugin.pluginId));
	if (policyPluginIds?.some((pluginId) => !pluginIds.has(pluginId))) return false;
	const installOwners = new Set(persisted.plugins.map(resolveInstalledPluginIndexInstallOwner));
	return Object.entries(persisted.installRecords).every(([installOwner, record]) => {
		if (installOwners.has(installOwner)) return true;
		const installedPath = record.installPath?.trim() || record.sourcePath?.trim();
		return !installedPath || !existsSync(resolveUserPath(installedPath, env));
	});
}
function canRefreshPersistedPolicyState(persisted, params) {
	if (!persisted || params.reason !== "policy-changed") return false;
	if ((params.diagnostics?.length ?? 0) > 0 || persisted.diagnostics.some((diagnostic) => diagnostic.code === "workspace-scope-omitted") || hasInstalledPluginIndexWorkspaceScopeMismatch(persisted, params.workspaceDir)) return false;
	const env = params.env ?? process.env;
	if (persisted.version !== 1 || persisted.hostContractVersion !== resolveCompatibilityHostVersion(env) || persisted.compatRegistryVersion !== resolveCompatRegistryVersion() || persisted.migrationVersion !== 1 || hasMissingConfigPathActivationMetadata(persisted) || hasMissingInstalledPluginOwnerMetadata(persisted, env)) return false;
	if (params.installRecords && hashStableJson(params.installRecords) !== hashStableJson(persisted.installRecords ?? {})) return false;
	return hasCompletePolicyRefreshProjection(persisted, params.policyPluginIds, env);
}
function refreshPersistedPolicyState(persisted, params) {
	const normalizedConfig = normalizePluginsConfig(params.config?.plugins);
	return {
		...persisted,
		policyHash: resolveInstalledPluginIndexPolicyHash(params.config),
		generatedAtMs: (params.now?.() ?? /* @__PURE__ */ new Date()).getTime(),
		refreshReason: params.reason,
		plugins: persisted.plugins.map((plugin) => ({
			...plugin,
			enabled: resolveEffectiveEnableState({
				id: plugin.pluginId,
				origin: plugin.origin,
				config: normalizedConfig,
				rootConfig: params.config,
				enabledByDefault: isPluginEnabledByDefaultForPlatform(plugin)
			}).enabled
		}))
	};
}
async function refreshPersistedInstalledPluginIndex(params) {
	return refreshPersistedInstalledPluginIndexSync(params);
}
function resolveRefreshedPersistedInstalledPluginIndex(params) {
	const persisted = params.reason === "policy-changed" || !params.installRecords ? readPersistedInstalledPluginIndexSync(params) : null;
	if (canRefreshPersistedPolicyState(persisted, params)) return refreshPersistedPolicyState(persisted, params);
	return refreshInstalledPluginIndex({
		...params,
		installRecords: params.installRecords ?? extractPluginInstallRecordsFromInstalledPluginIndex(persisted)
	});
}
function refreshPersistedInstalledPluginIndexSync(params) {
	const index = resolveRefreshedPersistedInstalledPluginIndex(params);
	writePersistedInstalledPluginIndexSync(index, params);
	return index;
}
function refreshPersistedInstalledPluginIndexWithLeaseSync(params) {
	const { lease, ...storeParams } = params;
	const receipt = writePersistedInstalledPluginIndexToSqlite(resolveRefreshedPersistedInstalledPluginIndex(storeParams), storeParams, lease);
	clearPersistedInstalledPluginIndexCaches();
	return receipt;
}
//#endregion
export { writePersistedInstalledPluginIndex as a, restorePersistedInstalledPluginIndexIfCurrent as i, refreshPersistedInstalledPluginIndexSync as n, writePersistedInstalledPluginIndexSync as o, refreshPersistedInstalledPluginIndexWithLeaseSync as r, writePersistedInstalledPluginIndexWithLeaseSync as s, refreshPersistedInstalledPluginIndex as t };
