import { c as normalizeOptionalString } from "./string-coerce-DyL154ka.js";
import { t as createLazyImportLoader } from "./lazy-promise-Djskx0qC.js";
import { t as packageNameMatchesId } from "./install-safe-path-CLz5STbR.js";
import { p as resolveUserPath } from "./utils-CNnMhEDp.js";
import { a as resolveDefaultPluginNpmDir, c as validatePluginId, n as matchesExpectedPluginId, r as resolveDefaultPluginExtensionsDir, s as safePluginInstallFileName, t as encodePluginInstallDirName } from "./install-paths-wshgrJTh.js";
import { a as isPrereleaseResolutionAllowed, c as validateRegistryNpmSpec, i as isExactSemverVersion, n as formatPrereleaseResolutionError, o as isPrereleaseSemverVersion, s as parseRegistryNpmSpec, t as compareDaoCoreReleaseVersions } from "./npm-registry-spec-D1a7Iic0.js";
import { o as resolvePackageExtensionEntries } from "./manifest-DbwIPpku.js";
import { r as validatePackageExtensionEntriesForInstall } from "./package-entry-resolution-ZpftJNrs.js";
import { r as runCommandWithTimeout } from "./exec-PI-gh7wQ.js";
import { a as resolveNpmPackArchiveMetadata, n as createNpmMetadataEnv, o as resolveNpmSpecMetadata } from "./install-source-utils-V8Nsm9Fz.js";
import { i as parseComparableSemver, t as compareComparableSemver } from "./semver-compare-BoMHoO1q.js";
import { n as createSafeNpmInstallEnv, t as createSafeNpmInstallArgs } from "./safe-package-install-CZ0VYBja.js";
import { a as repairManagedNpmRootDaoCorePeer, c as syncManagedNpmRootPeerDependencies, i as removeManagedNpmRootDependency, l as upsertManagedNpmRootDependency, n as readManagedNpmRootInstalledDependency, o as resolveManagedNpmRootDependencySpec, r as readManagedNpmRootPeerDependencySnapshot, s as restoreManagedNpmRootPeerDependencySnapshot, t as readDaoCoreManagedNpmRootOverrides } from "./npm-managed-root-CvrIsrYr.js";
import { i as relinkDaoCorePeerDependenciesInManagedNpmRoot, r as linkDaoCorePeerDependencies } from "./plugin-peer-link-Bbj9bZaK.js";
import { t as resolveNpmIntegrityDriftWithDefaultMessage } from "./npm-integrity-DsZIWZKw.js";
import { n as installedPackageNeedsDaoCorePeerLinkRepair } from "./package-update-utils-CCdczg9U.js";
import path from "node:path";
import fs from "node:fs/promises";
import { createHash } from "node:crypto";
//#region src/plugins/install.ts
const pluginInstallRuntimeLoader = createLazyImportLoader(() => import("./install.runtime.js"));
async function loadPluginInstallRuntime() {
	return await pluginInstallRuntimeLoader.load();
}
function formatUnresolvedDaoCorePeerLinkError(packageName) {
	return `Installed plugin ${packageName} declares daocore as a peer dependency, but DaoCore could not create a plugin-local node_modules/daocore link. Run from a packaged DaoCore install or reinstall DaoCore, then retry.`;
}
function isNpmAliasOverrideComparatorError(result) {
	return `${result.stderr}\n${result.stdout}`.includes("Invalid comparator: npm:");
}
const MISSING_EXTENSIONS_ERROR = "package.json missing daocore.extensions; update the plugin package to include daocore.extensions (for example [\"./dist/index.js\"]). See https://docs.openclaw.ai/help/troubleshooting#plugin-install-fails-with-missing-daocore-extensions";
const PLUGIN_ARCHIVE_ROOT_MARKERS = [
	"package.json",
	"daocore.plugin.json",
	".codex-plugin/plugin.json",
	".claude-plugin/plugin.json",
	".cursor-plugin/plugin.json"
];
const MANAGED_NPM_PACK_ARCHIVE_DIR = "_daocore-pack-archives";
const PLUGIN_INSTALL_ERROR_CODE = {
	INVALID_NPM_SPEC: "invalid_npm_spec",
	INVALID_MIN_HOST_VERSION: "invalid_min_host_version",
	UNKNOWN_HOST_VERSION: "unknown_host_version",
	INCOMPATIBLE_HOST_VERSION: "incompatible_host_version",
	MISSING_DAOCORE_EXTENSIONS: "missing_daocore_extensions",
	MISSING_PLUGIN_MANIFEST: "missing_plugin_manifest",
	EMPTY_DAOCORE_EXTENSIONS: "empty_daocore_extensions",
	INVALID_DAOCORE_EXTENSIONS: "invalid_daocore_extensions",
	NPM_PACKAGE_NOT_FOUND: "npm_package_not_found",
	PLUGIN_ID_MISMATCH: "plugin_id_mismatch",
	SECURITY_SCAN_BLOCKED: "security_scan_blocked",
	SECURITY_SCAN_FAILED: "security_scan_failed"
};
const defaultLogger = {};
function ensureDaoCoreExtensions(params) {
	const resolved = resolvePackageExtensionEntries(params.manifest);
	if (resolved.status === "missing") return {
		ok: false,
		error: MISSING_EXTENSIONS_ERROR,
		code: PLUGIN_INSTALL_ERROR_CODE.MISSING_DAOCORE_EXTENSIONS
	};
	if (resolved.status === "empty") return {
		ok: false,
		error: "package.json daocore.extensions is empty",
		code: PLUGIN_INSTALL_ERROR_CODE.EMPTY_DAOCORE_EXTENSIONS
	};
	if (resolved.status === "invalid") return {
		ok: false,
		error: resolved.error,
		code: PLUGIN_INSTALL_ERROR_CODE.INVALID_DAOCORE_EXTENSIONS
	};
	return {
		ok: true,
		entries: resolved.entries
	};
}
function isNpmPackageNotFoundMessage(error) {
	const normalized = error.trim();
	if (normalized.startsWith("Package not found on npm:")) return true;
	return /E404|404 not found|not in this registry/i.test(normalized);
}
function compareNpmSemver(a, b) {
	const releaseCmp = compareDaoCoreReleaseVersions(a, b);
	if (releaseCmp !== null) return releaseCmp;
	return compareComparableSemver(parseComparableSemver(a), parseComparableSemver(b)) ?? 0;
}
async function resolveTrustedOfficialPrereleaseResolution(params) {
	if (!params.spec.name.startsWith("@daocore/")) return null;
	const versions = await runCommandWithTimeout([
		"npm",
		"view",
		params.spec.name,
		"versions",
		"--json"
	], {
		timeoutMs: Math.max(params.timeoutMs, 6e4),
		env: createNpmMetadataEnv()
	});
	if (versions.code !== 0) return null;
	let parsed;
	try {
		parsed = JSON.parse(versions.stdout.trim());
	} catch {
		return null;
	}
	const semverVersions = (Array.isArray(parsed) ? parsed : [parsed]).filter((value) => typeof value === "string" && isExactSemverVersion(value));
	const stableVersion = semverVersions.filter((value) => !isPrereleaseSemverVersion(value)).toSorted(compareNpmSemver).at(-1);
	if (!stableVersion) {
		const prereleaseVersion = semverVersions.filter(isPrereleaseSemverVersion).toSorted(compareNpmSemver).at(-1);
		if (prereleaseVersion && semverVersions.every(isPrereleaseSemverVersion)) {
			if (prereleaseVersion !== params.resolvedPrereleaseVersion) {
				const prereleaseSpec = `${params.spec.name}@${prereleaseVersion}`;
				const metadataResult = await resolveNpmSpecMetadata({
					spec: prereleaseSpec,
					timeoutMs: params.timeoutMs
				});
				if (!metadataResult.ok) return null;
				params.logger.warn?.(`Resolved ${params.spec.raw} to prerelease version ${params.resolvedPrereleaseVersion}; using newest prerelease ${prereleaseSpec} because this trusted official DaoCore package has no stable npm versions yet.`);
				return {
					kind: "prerelease-only",
					resolution: metadataResult.metadata
				};
			}
			params.logger.warn?.(`Resolved ${params.spec.raw} to prerelease version ${params.resolvedPrereleaseVersion}; allowing it because this trusted official DaoCore package has no stable npm versions yet.`);
			return { kind: "allow-prerelease-only" };
		}
		return null;
	}
	const stableSpec = `${params.spec.name}@${stableVersion}`;
	const metadataResult = await resolveNpmSpecMetadata({
		spec: stableSpec,
		timeoutMs: params.timeoutMs
	});
	if (!metadataResult.ok) return null;
	params.logger.warn?.(`Resolved ${params.spec.raw} to prerelease version ${params.resolvedPrereleaseVersion}; falling back to stable ${stableSpec} for this trusted official DaoCore install.`);
	return {
		kind: "stable",
		resolution: metadataResult.metadata
	};
}
function buildFileInstallResult(pluginId, targetFile) {
	return {
		ok: true,
		pluginId,
		targetDir: targetFile,
		manifestName: void 0,
		version: void 0,
		extensions: [path.basename(targetFile)]
	};
}
function buildDirectoryInstallResult(params) {
	return {
		ok: true,
		pluginId: params.pluginId,
		targetDir: params.targetDir,
		manifestName: params.manifestName,
		version: params.version,
		extensions: params.extensions
	};
}
function hasPackageRuntimeDependencies(manifest) {
	return Object.keys(manifest.dependencies ?? {}).length > 0 || Object.keys(manifest.optionalDependencies ?? {}).length > 0;
}
function buildBlockedInstallResult(params) {
	return {
		ok: false,
		error: params.blocked.reason,
		...params.blocked.code === "security_scan_failed" ? { code: PLUGIN_INSTALL_ERROR_CODE.SECURITY_SCAN_FAILED } : params.blocked.code === "security_scan_blocked" ? { code: PLUGIN_INSTALL_ERROR_CODE.SECURITY_SCAN_BLOCKED } : {}
	};
}
async function rollbackManagedNpmPluginInstall(params) {
	try {
		await runCommandWithTimeout([
			"npm",
			"uninstall",
			"--loglevel=error",
			"--legacy-peer-deps",
			"--ignore-scripts",
			"--no-audit",
			"--no-fund",
			params.packageName
		], {
			cwd: params.npmRoot,
			timeoutMs: Math.max(params.timeoutMs, 3e5),
			env: createSafeNpmInstallEnv(process.env, {
				legacyPeerDeps: true,
				npmConfigCwd: params.npmRoot,
				packageLock: true,
				quiet: true
			})
		});
	} catch (error) {
		params.logger.warn?.(`Failed to run npm uninstall rollback for ${params.packageName}: ${String(error)}`);
	}
	try {
		await fs.rm(params.targetDir, {
			recursive: true,
			force: true
		});
	} catch (error) {
		params.logger.warn?.(`Failed to remove failed plugin install directory ${params.targetDir}: ${String(error)}`);
	}
	try {
		await removeManagedNpmRootDependency({
			npmRoot: params.npmRoot,
			packageName: params.packageName
		});
	} catch (error) {
		params.logger.warn?.(`Failed to remove managed npm dependency ${params.packageName}: ${String(error)}`);
	}
	if (params.peerDependencySnapshot) try {
		const preRestorePeerDependencySnapshot = await readManagedNpmRootPeerDependencySnapshot({ npmRoot: params.npmRoot });
		const restoredPeerDependencyNames = new Set(params.peerDependencySnapshot.managedPeerDependencies);
		const addedPeerDependencyNames = preRestorePeerDependencySnapshot.managedPeerDependencies.filter((packageName) => !restoredPeerDependencyNames.has(packageName));
		await restoreManagedNpmRootPeerDependencySnapshot({
			npmRoot: params.npmRoot,
			snapshot: params.peerDependencySnapshot
		});
		const cleanupResult = await runCommandWithTimeout([
			"npm",
			"install",
			"--omit=dev",
			"--omit=peer",
			"--loglevel=error",
			"--legacy-peer-deps",
			"--ignore-scripts",
			"--no-audit",
			"--no-fund"
		], {
			cwd: params.npmRoot,
			timeoutMs: Math.max(params.timeoutMs, 3e5),
			env: createSafeNpmInstallEnv(process.env, {
				legacyPeerDeps: true,
				npmConfigCwd: params.npmRoot,
				packageLock: true,
				quiet: true
			})
		});
		if (cleanupResult.code !== 0) {
			params.logger.warn?.(`npm install cleanup after rollback for ${params.packageName} exited ${cleanupResult.code}: ${cleanupResult.stderr.trim() || cleanupResult.stdout.trim()}`);
			await Promise.all(addedPeerDependencyNames.map(async (packageName) => {
				try {
					await fs.rm(resolveManagedNpmRootPackageDir(params.npmRoot, packageName), {
						recursive: true,
						force: true
					});
				} catch (error) {
					params.logger.warn?.(`Failed to remove rolled-back managed peer dependency ${packageName}: ${String(error)}`);
				}
			}));
		}
	} catch (error) {
		params.logger.warn?.(`Failed to restore managed npm peer dependencies after rollback for ${params.packageName}: ${String(error)}`);
	}
	if (params.packageName !== "daocore") try {
		await repairManagedNpmRootDaoCorePeer({
			npmRoot: params.npmRoot,
			timeoutMs: params.timeoutMs,
			logger: params.logger
		});
	} catch (error) {
		params.logger.warn?.(`Failed to repair managed npm daocore peer after rollback: ${String(error)}`);
	}
	try {
		await relinkDaoCorePeerDependenciesInManagedNpmRoot({
			npmRoot: params.npmRoot,
			logger: params.logger
		});
	} catch (error) {
		params.logger.warn?.(`Failed to repair managed npm peer links after rollback for ${params.packageName}: ${String(error)}`);
	}
}
function resolveInstalledNpmResolutionMismatch(params) {
	if (!params.installed) return `npm install did not record package-lock metadata for ${params.packageName}`;
	if (params.expected.version && params.installed.version !== params.expected.version) return `npm install resolved ${params.packageName} to version ${params.installed.version ?? "unknown"}, expected ${params.expected.version}`;
	if (params.expected.integrity && params.installed.integrity !== params.expected.integrity) return `npm install resolved ${params.packageName} with integrity ${params.installed.integrity ?? "unknown"}, expected ${params.expected.integrity}`;
	return null;
}
async function listManagedNpmRootPackageNames(npmRoot) {
	const nodeModulesDir = path.join(npmRoot, "node_modules");
	let entries;
	try {
		entries = await fs.readdir(nodeModulesDir, { withFileTypes: true });
	} catch (error) {
		if (error.code === "ENOENT") return /* @__PURE__ */ new Set();
		throw error;
	}
	const packageNames = /* @__PURE__ */ new Set();
	for (const entry of entries.toSorted((left, right) => left.name.localeCompare(right.name))) {
		if (entry.name === ".bin" || entry.name === "daocore") continue;
		if (entry.name.startsWith("@")) {
			const scopeDir = path.join(nodeModulesDir, entry.name);
			let scopedEntries;
			try {
				scopedEntries = await fs.readdir(scopeDir, { withFileTypes: true });
			} catch (error) {
				if (error.code === "ENOENT") continue;
				throw error;
			}
			for (const scopedEntry of scopedEntries.toSorted((left, right) => left.name.localeCompare(right.name))) if (scopedEntry.isDirectory() || scopedEntry.isSymbolicLink()) packageNames.add(`${entry.name}/${scopedEntry.name}`);
			continue;
		}
		if (entry.isDirectory() || entry.isSymbolicLink()) packageNames.add(entry.name);
	}
	return packageNames;
}
function resolveManagedNpmRootPackageDir(npmRoot, packageName) {
	return path.join(npmRoot, "node_modules", ...packageName.split("/"));
}
async function listNewManagedNpmRootPackageDirs(params) {
	return [...await listManagedNpmRootPackageNames(params.npmRoot)].filter((packageName) => !params.beforeInstallPackageNames.has(packageName)).map((packageName) => resolveManagedNpmRootPackageDir(params.npmRoot, packageName)).toSorted((left, right) => left.localeCompare(right));
}
function resolveTrustedNpmPackPackageName(packageName) {
	if (!packageName) return {
		ok: false,
		error: "npm pack metadata missing package name",
		code: PLUGIN_INSTALL_ERROR_CODE.INVALID_NPM_SPEC
	};
	const specError = validateRegistryNpmSpec(packageName);
	const parsedSpec = parseRegistryNpmSpec(packageName);
	if (specError || !parsedSpec || parsedSpec.selectorKind !== "none") return {
		ok: false,
		error: `unsupported npm pack package name: ${packageName}`,
		code: PLUGIN_INSTALL_ERROR_CODE.INVALID_NPM_SPEC
	};
	return {
		ok: true,
		packageName: parsedSpec.name
	};
}
async function installPluginFromManagedNpmRoot(params) {
	const runtime = await loadPluginInstallRuntime();
	const { logger, timeoutMs, mode, dryRun } = runtime.resolveTimedInstallModeOptions(params, defaultLogger);
	const expectedPluginId = params.expectedPluginId;
	const npmRoot = params.npmDir ? resolveUserPath(params.npmDir) : resolveDefaultPluginNpmDir();
	const installRoot = path.join(npmRoot, "node_modules", params.packageName);
	const effectiveMode = await resolveEffectiveInstallMode({
		runtime,
		requestedMode: mode,
		targetPath: installRoot
	});
	const availability = await ensureInstallTargetAvailableForMode({
		runtime,
		targetPath: installRoot,
		mode: effectiveMode
	});
	if (!availability.ok) return availability;
	if (dryRun) return {
		ok: true,
		pluginId: expectedPluginId ?? params.packageName,
		targetDir: installRoot,
		extensions: [],
		npmResolution: params.npmResolution,
		...params.integrityDrift ? { integrityDrift: params.integrityDrift } : {}
	};
	logger.info?.(`Installing ${params.displaySpec} into ${npmRoot}…`);
	if (params.packageName !== "daocore") {
		if (await repairManagedNpmRootDaoCorePeer({
			npmRoot,
			timeoutMs,
			logger
		})) logger.info?.(`Repaired stale daocore peer dependency in ${npmRoot}`);
	}
	const preInstallRootPackageNames = await listManagedNpmRootPackageNames(npmRoot);
	const managedOverrides = await readDaoCoreManagedNpmRootOverrides();
	const rollbackPeerDependencySnapshot = await readManagedNpmRootPeerDependencySnapshot({ npmRoot });
	const rollbackFailedManagedNpmInstall = async (error) => {
		await rollbackManagedNpmPluginInstall({
			npmRoot,
			packageName: params.packageName,
			targetDir: installRoot,
			timeoutMs,
			logger,
			peerDependencySnapshot: rollbackPeerDependencySnapshot
		});
		return {
			ok: false,
			error
		};
	};
	const syncManagedPeerDependenciesForInstall = async (options) => {
		try {
			return {
				ok: true,
				changed: await syncManagedNpmRootPeerDependencies({
					npmRoot,
					managedOverrides,
					omitUnsupportedManagedOverrides: options?.omitUnsupportedManagedOverrides,
					timeoutMs
				})
			};
		} catch (error) {
			return {
				ok: false,
				error: `npm peer dependency planning failed: ${error instanceof Error ? error.message : String(error)}`
			};
		}
	};
	await upsertManagedNpmRootDependency({
		npmRoot,
		packageName: params.packageName,
		dependencySpec: params.dependencySpec,
		managedOverrides
	});
	const initialPeerSync = await syncManagedPeerDependenciesForInstall();
	if (!initialPeerSync.ok) return await rollbackFailedManagedNpmInstall(initialPeerSync.error);
	const npmInstallArgs = ["npm", ...createSafeNpmInstallArgs({
		omitDev: true,
		omitPeer: true,
		loglevel: "error",
		legacyPeerDeps: true,
		noAudit: true,
		noFund: true
	})];
	const npmInstallOptions = {
		cwd: npmRoot,
		timeoutMs: Math.max(timeoutMs, 3e5),
		env: createSafeNpmInstallEnv(process.env, {
			legacyPeerDeps: true,
			npmConfigCwd: npmRoot,
			packageLock: true,
			quiet: true
		})
	};
	let install = await runCommandWithTimeout(npmInstallArgs, npmInstallOptions);
	let omitUnsupportedManagedOverrides = false;
	if (install.code !== 0 && isNpmAliasOverrideComparatorError(install)) {
		logger.warn?.("npm rejected managed npm alias overrides; retrying plugin install without alias overrides for this npm version.");
		omitUnsupportedManagedOverrides = true;
		await upsertManagedNpmRootDependency({
			npmRoot,
			packageName: params.packageName,
			dependencySpec: params.dependencySpec,
			managedOverrides,
			omitUnsupportedManagedOverrides: true
		});
		const aliasRetryPeerSync = await syncManagedPeerDependenciesForInstall({ omitUnsupportedManagedOverrides: true });
		if (!aliasRetryPeerSync.ok) return await rollbackFailedManagedNpmInstall(aliasRetryPeerSync.error);
		install = await runCommandWithTimeout(npmInstallArgs, npmInstallOptions);
	}
	if (install.code !== 0) {
		await rollbackManagedNpmPluginInstall({
			npmRoot,
			packageName: params.packageName,
			targetDir: installRoot,
			timeoutMs,
			logger,
			peerDependencySnapshot: rollbackPeerDependencySnapshot
		});
		return {
			ok: false,
			error: `npm install failed: ${install.stderr.trim() || install.stdout.trim()}`
		};
	}
	let settledManagedPeerDependencies = false;
	for (let peerSyncPass = 0; peerSyncPass < 10; peerSyncPass += 1) {
		const peerSync = await syncManagedPeerDependenciesForInstall({ omitUnsupportedManagedOverrides });
		if (!peerSync.ok) return await rollbackFailedManagedNpmInstall(peerSync.error);
		if (!peerSync.changed) {
			settledManagedPeerDependencies = true;
			break;
		}
		install = await runCommandWithTimeout(npmInstallArgs, npmInstallOptions);
		if (install.code !== 0) {
			await rollbackManagedNpmPluginInstall({
				npmRoot,
				packageName: params.packageName,
				targetDir: installRoot,
				timeoutMs,
				logger,
				peerDependencySnapshot: rollbackPeerDependencySnapshot
			});
			return {
				ok: false,
				error: `npm install failed after syncing managed peer dependencies: ${install.stderr.trim() || install.stdout.trim()}`
			};
		}
	}
	if (!settledManagedPeerDependencies) {
		const peerSync = await syncManagedPeerDependenciesForInstall({ omitUnsupportedManagedOverrides });
		if (!peerSync.ok) return await rollbackFailedManagedNpmInstall(peerSync.error);
		settledManagedPeerDependencies = !peerSync.changed;
	}
	if (!settledManagedPeerDependencies) {
		await rollbackManagedNpmPluginInstall({
			npmRoot,
			packageName: params.packageName,
			targetDir: installRoot,
			timeoutMs,
			logger,
			peerDependencySnapshot: rollbackPeerDependencySnapshot
		});
		return {
			ok: false,
			error: "npm install could not settle managed peer dependencies after 10 sync passes; refusing to leave a partially reconciled plugin dependency tree."
		};
	}
	if (params.packageName !== "daocore") {
		if (await repairManagedNpmRootDaoCorePeer({
			npmRoot,
			timeoutMs,
			logger
		})) logger.info?.(`Repaired stale daocore peer dependency in ${npmRoot} after npm install`);
	}
	try {
		await relinkDaoCorePeerDependenciesInManagedNpmRoot({
			npmRoot,
			logger
		});
	} catch (error) {
		await rollbackManagedNpmPluginInstall({
			npmRoot,
			packageName: params.packageName,
			targetDir: installRoot,
			timeoutMs,
			logger,
			peerDependencySnapshot: rollbackPeerDependencySnapshot
		});
		return {
			ok: false,
			error: `Failed to repair daocore peer links after npm install: ${String(error)}`
		};
	}
	if (installedPackageNeedsDaoCorePeerLinkRepair(installRoot)) {
		await rollbackManagedNpmPluginInstall({
			npmRoot,
			packageName: params.packageName,
			targetDir: installRoot,
			timeoutMs,
			logger,
			peerDependencySnapshot: rollbackPeerDependencySnapshot
		});
		return {
			ok: false,
			error: formatUnresolvedDaoCorePeerLinkError(params.packageName)
		};
	}
	let installedDependency;
	try {
		installedDependency = await readManagedNpmRootInstalledDependency({
			npmRoot,
			packageName: params.packageName
		});
	} catch (error) {
		await rollbackManagedNpmPluginInstall({
			npmRoot,
			packageName: params.packageName,
			targetDir: installRoot,
			timeoutMs,
			logger,
			peerDependencySnapshot: rollbackPeerDependencySnapshot
		});
		return {
			ok: false,
			error: `Failed to verify npm install metadata for ${params.packageName}: ${String(error)}`
		};
	}
	const resolutionMismatch = resolveInstalledNpmResolutionMismatch({
		packageName: params.packageName,
		expected: params.npmResolution,
		installed: installedDependency
	});
	if (resolutionMismatch) {
		await rollbackManagedNpmPluginInstall({
			npmRoot,
			packageName: params.packageName,
			targetDir: installRoot,
			timeoutMs,
			logger,
			peerDependencySnapshot: rollbackPeerDependencySnapshot
		});
		return {
			ok: false,
			error: resolutionMismatch
		};
	}
	const newRootPackageDirs = await listNewManagedNpmRootPackageDirs({
		beforeInstallPackageNames: preInstallRootPackageNames,
		npmRoot
	});
	const result = await installPluginFromInstalledPackageDir({
		dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
		additionalDependencyPackageDirs: newRootPackageDirs,
		packageDir: installRoot,
		dependencyScanRootDir: npmRoot,
		logger,
		expectedPluginId,
		trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
		mode: effectiveMode,
		installPolicyRequest: params.installPolicyRequest
	});
	if (!result.ok) {
		await rollbackManagedNpmPluginInstall({
			npmRoot,
			packageName: params.packageName,
			targetDir: installRoot,
			timeoutMs,
			logger,
			peerDependencySnapshot: rollbackPeerDependencySnapshot
		});
		return result;
	}
	return {
		...result,
		npmResolution: params.npmResolution,
		...params.integrityDrift ? { integrityDrift: params.integrityDrift } : {}
	};
}
async function stageNpmPackArchiveInManagedRoot(params) {
	const archiveStoreDir = path.join(params.npmRoot, MANAGED_NPM_PACK_ARCHIVE_DIR);
	const identity = params.integrity ?? params.shasum ?? params.tarballName;
	const identitySlug = createHash("sha256").update(identity).digest("hex").slice(0, 16);
	const archiveFileName = `${safePluginInstallFileName(params.packageName) || "plugin"}-${safePluginInstallFileName(params.version ?? "pack") || "pack"}-${identitySlug}.tgz`;
	const stableArchivePath = path.join(archiveStoreDir, archiveFileName);
	await fs.mkdir(archiveStoreDir, { recursive: true });
	await fs.copyFile(params.archivePath, stableArchivePath);
	return {
		stableArchivePath,
		dependencySpec: `file:./${path.posix.join(MANAGED_NPM_PACK_ARCHIVE_DIR, archiveFileName)}`
	};
}
function pickPackageInstallCommonParams(params) {
	return {
		dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
		trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
		extensionsDir: params.extensionsDir,
		npmDir: params.npmDir,
		timeoutMs: params.timeoutMs,
		logger: params.logger,
		mode: params.mode,
		dryRun: params.dryRun,
		expectedPluginId: params.expectedPluginId,
		requirePluginManifest: params.requirePluginManifest,
		installPolicyRequest: params.installPolicyRequest
	};
}
function pickFileInstallCommonParams(params) {
	return {
		dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
		extensionsDir: params.extensionsDir,
		logger: params.logger,
		mode: params.mode,
		dryRun: params.dryRun,
		installPolicyRequest: params.installPolicyRequest
	};
}
async function ensureInstallTargetAvailableForMode(params) {
	return await params.runtime.ensureInstallTargetAvailable({
		mode: params.mode,
		targetDir: params.targetPath,
		alreadyExistsError: `plugin already exists: ${params.targetPath} (delete it first)`
	});
}
async function resolvePreparedDirectoryInstallTarget(params) {
	const targetDirResult = await resolvePluginInstallTarget({
		runtime: params.runtime,
		pluginId: params.pluginId,
		extensionsDir: params.extensionsDir,
		nameEncoder: params.nameEncoder
	});
	if (!targetDirResult.ok) return targetDirResult;
	return {
		ok: true,
		target: {
			targetPath: targetDirResult.targetDir,
			effectiveMode: await resolveEffectiveInstallMode({
				runtime: params.runtime,
				requestedMode: params.requestedMode,
				targetPath: targetDirResult.targetDir
			})
		}
	};
}
async function runInstallSourceScan(params) {
	try {
		const scanResult = await params.scan();
		if (scanResult?.blocked) return buildBlockedInstallResult({ blocked: scanResult.blocked });
		return null;
	} catch (err) {
		return {
			ok: false,
			error: `${params.subject} installation blocked: code safety scan failed (${String(err)}). Run "daocore security audit --deep" for details.`,
			code: PLUGIN_INSTALL_ERROR_CODE.SECURITY_SCAN_FAILED
		};
	}
}
async function installPluginDirectoryIntoExtensions(params) {
	const runtime = await loadPluginInstallRuntime();
	let targetDir = params.targetDir;
	if (!targetDir) {
		const targetDirResult = await resolvePluginInstallTarget({
			runtime,
			pluginId: params.pluginId,
			extensionsDir: params.extensionsDir,
			nameEncoder: params.nameEncoder
		});
		if (!targetDirResult.ok) return {
			ok: false,
			error: targetDirResult.error
		};
		targetDir = targetDirResult.targetDir;
	}
	const availability = await ensureInstallTargetAvailableForMode({
		runtime,
		targetPath: targetDir,
		mode: params.mode
	});
	if (!availability.ok) return availability;
	if (params.dryRun) return buildDirectoryInstallResult({
		pluginId: params.pluginId,
		targetDir,
		manifestName: params.manifestName,
		version: params.version,
		extensions: params.extensions
	});
	const installRes = await runtime.installPackageDir({
		sourceDir: params.sourceDir,
		targetDir,
		mode: params.mode,
		timeoutMs: params.timeoutMs,
		logger: params.logger,
		copyErrorPrefix: params.copyErrorPrefix,
		hasDeps: params.hasDeps,
		depsLogMessage: params.depsLogMessage,
		afterCopy: params.afterCopy,
		afterInstall: async (installedDir) => {
			const postInstallResult = await params.afterInstall?.(installedDir);
			if (!postInstallResult) return { ok: true };
			return {
				ok: false,
				error: postInstallResult.error,
				...postInstallResult.code ? { code: postInstallResult.code } : {}
			};
		}
	});
	if (!installRes.ok) return {
		ok: false,
		error: installRes.error,
		...installRes.code ? { code: installRes.code } : {}
	};
	return buildDirectoryInstallResult({
		pluginId: params.pluginId,
		targetDir,
		manifestName: params.manifestName,
		version: params.version,
		extensions: params.extensions
	});
}
async function resolvePluginInstallTarget(params) {
	const extensionsDir = params.extensionsDir ? resolveUserPath(params.extensionsDir) : resolveDefaultPluginExtensionsDir();
	return await params.runtime.resolveCanonicalInstallTarget({
		baseDir: extensionsDir,
		id: params.pluginId,
		invalidNameMessage: "invalid plugin name: path traversal detected",
		boundaryLabel: "extensions directory",
		nameEncoder: params.nameEncoder
	});
}
async function resolveEffectiveInstallMode(params) {
	if (params.requestedMode !== "update") return "install";
	return await params.runtime.fileExists(params.targetPath) ? "update" : "install";
}
async function installBundleFromSourceDir(params) {
	const runtime = await loadPluginInstallRuntime();
	const bundleFormat = runtime.detectBundleManifestFormat(params.sourceDir);
	if (!bundleFormat) return null;
	const { logger, timeoutMs, mode, dryRun } = runtime.resolveTimedInstallModeOptions(params, defaultLogger);
	const manifestRes = runtime.loadBundleManifest({
		rootDir: params.sourceDir,
		bundleFormat,
		rejectHardlinks: true
	});
	if (!manifestRes.ok) return {
		ok: false,
		error: manifestRes.error
	};
	const pluginId = manifestRes.manifest.id;
	const pluginIdError = validatePluginId(pluginId);
	if (pluginIdError) return {
		ok: false,
		error: pluginIdError
	};
	if (params.expectedPluginId && params.expectedPluginId !== pluginId) return {
		ok: false,
		error: `plugin id mismatch: expected ${params.expectedPluginId}, got ${pluginId}`,
		code: PLUGIN_INSTALL_ERROR_CODE.PLUGIN_ID_MISMATCH
	};
	const targetResult = await resolvePreparedDirectoryInstallTarget({
		runtime,
		pluginId,
		extensionsDir: params.extensionsDir,
		requestedMode: mode
	});
	if (!targetResult.ok) return {
		ok: false,
		error: targetResult.error
	};
	const scanResult = await runInstallSourceScan({
		subject: `Bundle "${pluginId}"`,
		scan: async () => await runtime.scanBundleInstallSource({
			dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
			sourceDir: params.sourceDir,
			pluginId,
			logger,
			requestKind: params.installPolicyRequest?.kind,
			requestedSpecifier: params.installPolicyRequest?.requestedSpecifier,
			mode: targetResult.target.effectiveMode,
			version: manifestRes.manifest.version
		})
	});
	if (scanResult) return scanResult;
	return await installPluginDirectoryIntoExtensions({
		sourceDir: params.sourceDir,
		pluginId,
		manifestName: manifestRes.manifest.name,
		version: manifestRes.manifest.version,
		extensions: [],
		targetDir: targetResult.target.targetPath,
		extensionsDir: params.extensionsDir,
		logger,
		timeoutMs,
		mode: targetResult.target.effectiveMode,
		dryRun,
		copyErrorPrefix: "failed to copy plugin bundle",
		hasDeps: false,
		depsLogMessage: ""
	});
}
async function installPluginFromSourceDir(params) {
	if (await detectNativePackageInstallSource(params.sourceDir)) return await installPluginFromPackageDir({
		packageDir: params.sourceDir,
		...pickPackageInstallCommonParams(params)
	});
	const bundleResult = await installBundleFromSourceDir({
		sourceDir: params.sourceDir,
		...pickPackageInstallCommonParams(params)
	});
	if (bundleResult) return bundleResult;
	return await installPluginFromPackageDir({
		packageDir: params.sourceDir,
		...pickPackageInstallCommonParams(params)
	});
}
async function detectNativePackageInstallSource(packageDir) {
	const runtime = await loadPluginInstallRuntime();
	const manifestPath = path.join(packageDir, "package.json");
	if (!await runtime.fileExists(manifestPath)) return false;
	try {
		return ensureDaoCoreExtensions({ manifest: await runtime.readJsonFile(manifestPath) }).ok;
	} catch {
		return false;
	}
}
async function validatePackagePluginInstallSource(params) {
	const manifestPath = path.join(params.packageDir, "package.json");
	if (!await params.runtime.fileExists(manifestPath)) return {
		ok: false,
		error: "extracted package missing package.json"
	};
	let manifest;
	try {
		manifest = await params.runtime.readJsonFile(manifestPath);
	} catch (err) {
		return {
			ok: false,
			error: `invalid package.json: ${String(err)}`
		};
	}
	const extensionsResult = ensureDaoCoreExtensions({ manifest });
	if (!extensionsResult.ok) return {
		ok: false,
		error: extensionsResult.error,
		code: extensionsResult.code
	};
	const extensions = extensionsResult.entries;
	const pkgName = normalizeOptionalString(manifest.name) ?? "";
	const npmPluginId = pkgName || "plugin";
	const ocManifestResult = params.runtime.loadPluginManifest(params.packageDir);
	if (!ocManifestResult.ok && params.requirePluginManifest) return {
		ok: false,
		error: `package missing valid daocore.plugin.json: ${ocManifestResult.error}`,
		code: PLUGIN_INSTALL_ERROR_CODE.MISSING_PLUGIN_MANIFEST
	};
	const manifestPluginId = ocManifestResult.ok && ocManifestResult.manifest.id ? ocManifestResult.manifest.id.trim() : void 0;
	const pluginId = manifestPluginId ?? npmPluginId;
	const pluginIdError = validatePluginId(pluginId);
	if (pluginIdError) return {
		ok: false,
		error: pluginIdError
	};
	if (!matchesExpectedPluginId({
		expectedPluginId: params.expectedPluginId,
		pluginId,
		manifestPluginId,
		npmPluginId
	})) return {
		ok: false,
		error: `plugin id mismatch: expected ${params.expectedPluginId}, got ${pluginId}`,
		code: PLUGIN_INSTALL_ERROR_CODE.PLUGIN_ID_MISMATCH
	};
	if (manifestPluginId && !packageNameMatchesId(npmPluginId, manifestPluginId)) params.logger.info?.(`Plugin manifest id "${manifestPluginId}" differs from npm package name "${npmPluginId}"; using manifest id as the config key.`);
	const packageMetadata = params.runtime.getPackageManifestMetadata(manifest);
	const minHostVersionCheck = params.runtime.checkMinHostVersion({
		currentVersion: params.runtime.resolveCompatibilityHostVersion(),
		minHostVersion: packageMetadata?.install?.minHostVersion
	});
	if (!minHostVersionCheck.ok) {
		if (minHostVersionCheck.kind === "invalid") return {
			ok: false,
			error: `invalid package.json daocore.install.minHostVersion: ${minHostVersionCheck.error}`,
			code: PLUGIN_INSTALL_ERROR_CODE.INVALID_MIN_HOST_VERSION
		};
		if (minHostVersionCheck.kind === "unknown_host_version") return {
			ok: false,
			error: `plugin "${pluginId}" requires DaoCore >=${minHostVersionCheck.requirement.minimumLabel}, but this host version could not be determined. Re-run from a released build or set DAOCORE_VERSION and retry.`,
			code: PLUGIN_INSTALL_ERROR_CODE.UNKNOWN_HOST_VERSION
		};
		return {
			ok: false,
			error: `plugin "${pluginId}" requires DaoCore >=${minHostVersionCheck.requirement.minimumLabel}, but this host is ${minHostVersionCheck.currentVersion}. Upgrade DaoCore and retry.`,
			code: PLUGIN_INSTALL_ERROR_CODE.INCOMPATIBLE_HOST_VERSION
		};
	}
	const extensionValidation = await validatePackageExtensionEntriesForInstall({
		packageDir: params.packageDir,
		extensions,
		manifest
	});
	if (!extensionValidation.ok) return {
		ok: false,
		error: extensionValidation.error,
		code: PLUGIN_INSTALL_ERROR_CODE.INVALID_DAOCORE_EXTENSIONS
	};
	const scanMode = params.resolveEffectiveMode ? await params.resolveEffectiveMode(pluginId) : params.mode;
	const scanResult = await runInstallSourceScan({
		subject: `Plugin "${pluginId}"`,
		scan: async () => await params.runtime.scanPackageInstallSource({
			dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
			trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
			packageDir: params.packageDir,
			pluginId,
			logger: params.logger,
			extensions,
			...packageMetadata ? { packageMetadata } : {},
			requestKind: params.installPolicyRequest?.kind,
			requestedSpecifier: params.installPolicyRequest?.requestedSpecifier,
			mode: scanMode,
			packageName: pkgName || void 0,
			manifestId: manifestPluginId,
			version: typeof manifest.version === "string" ? manifest.version : void 0
		})
	});
	if (scanResult) return scanResult;
	return {
		ok: true,
		plugin: {
			manifest,
			pluginId,
			manifestName: pkgName || void 0,
			version: typeof manifest.version === "string" ? manifest.version : void 0,
			extensions,
			hasRuntimeDependencies: hasPackageRuntimeDependencies(manifest),
			peerDependencies: manifest.peerDependencies ?? {}
		}
	};
}
async function scanAndLinkInstalledPackage(params) {
	const scanResult = await runInstallSourceScan({
		subject: `Plugin "${params.pluginId}"`,
		scan: async () => await params.runtime.scanInstalledPackageDependencyTree({
			...params.additionalDependencyPackageDirs ? { additionalPackageDirs: params.additionalDependencyPackageDirs } : {},
			allowManagedNpmRootPackagePeerSymlinks: params.dependencyScanRootDir !== void 0 && path.resolve(params.dependencyScanRootDir) !== path.resolve(params.installedDir),
			dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
			dependencyScanRootDir: params.dependencyScanRootDir,
			logger: params.logger,
			packageDir: params.installedDir,
			pluginId: params.pluginId,
			trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall
		})
	});
	if (scanResult) return scanResult;
	if ((await linkDaoCorePeerDependencies({
		installedDir: params.installedDir,
		peerDependencies: params.peerDependencies,
		logger: params.logger
	})).skipped > 0) return {
		ok: false,
		error: formatUnresolvedDaoCorePeerLinkError(params.pluginId)
	};
	return null;
}
async function installPluginFromInstalledPackageDir(params) {
	const runtime = await loadPluginInstallRuntime();
	const { logger } = runtime.resolveTimedInstallModeOptions(params, defaultLogger);
	const validated = await validatePackagePluginInstallSource({
		runtime,
		packageDir: params.packageDir,
		expectedPluginId: params.expectedPluginId,
		requirePluginManifest: params.requirePluginManifest,
		dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
		trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
		installPolicyRequest: params.installPolicyRequest,
		logger,
		mode: params.mode ?? "install"
	});
	if (!validated.ok) return validated;
	const postInstallError = await scanAndLinkInstalledPackage({
		runtime,
		installedDir: params.packageDir,
		...params.additionalDependencyPackageDirs ? { additionalDependencyPackageDirs: params.additionalDependencyPackageDirs } : {},
		dependencyScanRootDir: params.dependencyScanRootDir,
		pluginId: validated.plugin.pluginId,
		peerDependencies: validated.plugin.peerDependencies,
		dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
		trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
		logger
	});
	if (postInstallError) return postInstallError;
	return buildDirectoryInstallResult({
		pluginId: validated.plugin.pluginId,
		targetDir: params.packageDir,
		manifestName: validated.plugin.manifestName,
		version: validated.plugin.version,
		extensions: validated.plugin.extensions
	});
}
async function installPluginFromPackageDir(params) {
	const runtime = await loadPluginInstallRuntime();
	const { logger, timeoutMs, mode, dryRun } = runtime.resolveTimedInstallModeOptions(params, defaultLogger);
	let preparedTarget;
	const resolvePreparedTargetForPluginId = async (pluginId) => {
		if (!preparedTarget) {
			const targetResult = await resolvePreparedDirectoryInstallTarget({
				runtime,
				pluginId,
				extensionsDir: params.extensionsDir,
				requestedMode: mode,
				nameEncoder: encodePluginInstallDirName
			});
			if (!targetResult.ok) throw new Error(targetResult.error);
			preparedTarget = targetResult.target;
		}
		return preparedTarget;
	};
	const validated = await validatePackagePluginInstallSource({
		runtime,
		packageDir: params.packageDir,
		expectedPluginId: params.expectedPluginId,
		requirePluginManifest: params.requirePluginManifest,
		dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
		trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
		installPolicyRequest: params.installPolicyRequest,
		logger,
		mode,
		resolveEffectiveMode: async (pluginId) => (await resolvePreparedTargetForPluginId(pluginId)).effectiveMode
	});
	if (!validated.ok) return validated;
	const { plugin } = validated;
	preparedTarget = await resolvePreparedTargetForPluginId(plugin.pluginId);
	const hasBundleManifest = Boolean(runtime.detectBundleManifestFormat(params.packageDir));
	return await installPluginDirectoryIntoExtensions({
		sourceDir: params.packageDir,
		pluginId: plugin.pluginId,
		manifestName: plugin.manifestName,
		version: plugin.version,
		extensions: plugin.extensions,
		targetDir: preparedTarget.targetPath,
		extensionsDir: params.extensionsDir,
		logger,
		timeoutMs,
		mode: preparedTarget.effectiveMode,
		dryRun,
		copyErrorPrefix: "failed to copy plugin",
		hasDeps: plugin.hasRuntimeDependencies && !hasBundleManifest && params.installPolicyRequest?.kind === "plugin-archive",
		depsLogMessage: "Installing plugin dependencies…",
		nameEncoder: encodePluginInstallDirName,
		afterInstall: async (installedDir) => {
			return await scanAndLinkInstalledPackage({
				runtime,
				installedDir,
				pluginId: plugin.pluginId,
				peerDependencies: plugin.peerDependencies,
				dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
				trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
				logger
			});
		}
	});
}
async function installPluginFromArchive(params) {
	const runtime = await loadPluginInstallRuntime();
	const logger = params.logger ?? defaultLogger;
	const timeoutMs = params.timeoutMs ?? 12e4;
	const mode = params.mode ?? "install";
	const installPolicyRequest = params.installPolicyRequest ?? {
		kind: "plugin-archive",
		requestedSpecifier: params.archivePath
	};
	const archivePathResult = await runtime.resolveArchiveSourcePath(params.archivePath);
	if (!archivePathResult.ok) return archivePathResult;
	const archivePath = archivePathResult.path;
	return await runtime.withExtractedArchiveRoot({
		archivePath,
		tempDirPrefix: "daocore-plugin-",
		timeoutMs,
		logger,
		rootMarkers: PLUGIN_ARCHIVE_ROOT_MARKERS,
		onExtracted: async (sourceDir) => await installPluginFromSourceDir({
			sourceDir,
			...pickPackageInstallCommonParams({
				dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
				extensionsDir: params.extensionsDir,
				timeoutMs,
				logger,
				mode,
				dryRun: params.dryRun,
				expectedPluginId: params.expectedPluginId,
				trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
				requirePluginManifest: true,
				installPolicyRequest
			})
		})
	});
}
async function installPluginFromDir(params) {
	const runtime = await loadPluginInstallRuntime();
	const dirPath = resolveUserPath(params.dirPath);
	const installPolicyRequest = params.installPolicyRequest ?? {
		kind: "plugin-dir",
		requestedSpecifier: params.dirPath
	};
	if (!await runtime.fileExists(dirPath)) return {
		ok: false,
		error: `directory not found: ${dirPath}`
	};
	if (!(await fs.stat(dirPath)).isDirectory()) return {
		ok: false,
		error: `not a directory: ${dirPath}`
	};
	return await installPluginFromSourceDir({
		sourceDir: dirPath,
		...pickPackageInstallCommonParams({
			...params,
			installPolicyRequest
		})
	});
}
async function installPluginFromFile(params) {
	const runtime = await loadPluginInstallRuntime();
	const { logger, mode, dryRun } = runtime.resolveInstallModeOptions(params, defaultLogger);
	const filePath = resolveUserPath(params.filePath);
	const installPolicyRequest = params.installPolicyRequest ?? {
		kind: "plugin-file",
		requestedSpecifier: params.filePath
	};
	if (!await runtime.fileExists(filePath)) return {
		ok: false,
		error: `file not found: ${filePath}`
	};
	const extensionsDir = params.extensionsDir ? resolveUserPath(params.extensionsDir) : resolveDefaultPluginExtensionsDir();
	await fs.mkdir(extensionsDir, { recursive: true });
	const pluginId = path.basename(filePath, path.extname(filePath)) || "plugin";
	const pluginIdError = validatePluginId(pluginId);
	if (pluginIdError) return {
		ok: false,
		error: pluginIdError
	};
	const targetFile = path.join(extensionsDir, `${safePluginInstallFileName(pluginId)}${path.extname(filePath)}`);
	const preparedTarget = {
		targetPath: targetFile,
		effectiveMode: await resolveEffectiveInstallMode({
			runtime,
			requestedMode: mode,
			targetPath: targetFile
		})
	};
	const availability = await ensureInstallTargetAvailableForMode({
		runtime,
		targetPath: preparedTarget.targetPath,
		mode: preparedTarget.effectiveMode
	});
	if (!availability.ok) return availability;
	if (dryRun) return buildFileInstallResult(pluginId, preparedTarget.targetPath);
	const scanResult = await runInstallSourceScan({
		subject: `Plugin file "${pluginId}"`,
		scan: async () => await runtime.scanFileInstallSource({
			dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
			filePath,
			logger,
			mode: preparedTarget.effectiveMode,
			pluginId,
			requestedSpecifier: installPolicyRequest.requestedSpecifier
		})
	});
	if (scanResult) return scanResult;
	logger.info?.(`Installing to ${preparedTarget.targetPath}…`);
	try {
		await (await runtime.root(extensionsDir)).copyIn(path.basename(preparedTarget.targetPath), filePath);
	} catch (err) {
		return {
			ok: false,
			error: String(err)
		};
	}
	return buildFileInstallResult(pluginId, preparedTarget.targetPath);
}
async function installPluginFromNpmSpec(params) {
	const runtime = await loadPluginInstallRuntime();
	const { logger, timeoutMs, mode, dryRun } = runtime.resolveTimedInstallModeOptions(params, defaultLogger);
	const expectedPluginId = params.expectedPluginId;
	const spec = params.spec.trim();
	const specError = runtime.validateRegistryNpmSpec(spec);
	if (specError) return {
		ok: false,
		error: specError,
		code: PLUGIN_INSTALL_ERROR_CODE.INVALID_NPM_SPEC
	};
	const parsedSpec = parseRegistryNpmSpec(spec);
	if (!parsedSpec) return {
		ok: false,
		error: "unsupported npm spec",
		code: PLUGIN_INSTALL_ERROR_CODE.INVALID_NPM_SPEC
	};
	const metadataResult = await resolveNpmSpecMetadata({
		spec,
		timeoutMs
	});
	if (!metadataResult.ok) return {
		ok: false,
		error: metadataResult.error,
		...isNpmPackageNotFoundMessage(metadataResult.error) ? { code: PLUGIN_INSTALL_ERROR_CODE.NPM_PACKAGE_NOT_FOUND } : {}
	};
	const npmResolution = {
		...metadataResult.metadata,
		resolvedAt: (/* @__PURE__ */ new Date()).toISOString()
	};
	if (npmResolution.version && !isPrereleaseResolutionAllowed({
		spec: parsedSpec,
		resolvedVersion: npmResolution.version
	})) {
		const trustedResolution = params.trustedSourceLinkedOfficialInstall ? await resolveTrustedOfficialPrereleaseResolution({
			spec: parsedSpec,
			resolvedPrereleaseVersion: npmResolution.version,
			timeoutMs,
			logger
		}) : null;
		if (trustedResolution?.kind === "stable" || trustedResolution?.kind === "prerelease-only") Object.assign(npmResolution, trustedResolution.resolution, { resolvedAt: npmResolution.resolvedAt });
		else if (trustedResolution?.kind === "allow-prerelease-only") {} else return {
			ok: false,
			error: formatPrereleaseResolutionError({
				spec: parsedSpec,
				resolvedVersion: npmResolution.version
			})
		};
	}
	const driftResult = await resolveNpmIntegrityDriftWithDefaultMessage({
		spec,
		expectedIntegrity: params.expectedIntegrity,
		resolution: npmResolution,
		onIntegrityDrift: params.onIntegrityDrift,
		warn: (message) => logger.warn?.(message)
	});
	if (driftResult.error) return {
		ok: false,
		error: driftResult.error
	};
	return await installPluginFromManagedNpmRoot({
		dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
		trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
		packageName: parsedSpec.name,
		dependencySpec: resolveManagedNpmRootDependencySpec({
			parsedSpec,
			resolution: npmResolution
		}),
		displaySpec: spec,
		installPolicyRequest: {
			kind: "plugin-npm",
			requestedSpecifier: spec
		},
		extensionsDir: params.extensionsDir,
		npmDir: params.npmDir,
		timeoutMs,
		logger,
		mode,
		dryRun,
		expectedPluginId,
		npmResolution,
		...driftResult.integrityDrift ? { integrityDrift: driftResult.integrityDrift } : {}
	});
}
async function installPluginFromNpmPackArchive(params) {
	const { logger, timeoutMs, mode, dryRun } = (await loadPluginInstallRuntime()).resolveTimedInstallModeOptions(params, defaultLogger);
	const metadataResult = await resolveNpmPackArchiveMetadata({
		archivePath: params.archivePath,
		timeoutMs
	});
	if (!metadataResult.ok) return metadataResult;
	const npmResolution = {
		...metadataResult.metadata,
		resolvedAt: (/* @__PURE__ */ new Date()).toISOString()
	};
	const driftResult = await resolveNpmIntegrityDriftWithDefaultMessage({
		spec: metadataResult.archivePath,
		expectedIntegrity: params.expectedIntegrity,
		resolution: npmResolution,
		onIntegrityDrift: params.onIntegrityDrift,
		warn: (message) => logger.warn?.(message)
	});
	if (driftResult.error) return {
		ok: false,
		error: driftResult.error
	};
	const packageNameResult = resolveTrustedNpmPackPackageName(metadataResult.metadata.name);
	if (!packageNameResult.ok) return packageNameResult;
	const packageName = packageNameResult.packageName;
	const npmRoot = params.npmDir ? resolveUserPath(params.npmDir) : resolveDefaultPluginNpmDir();
	let dependencySpec = "";
	if (!dryRun) try {
		dependencySpec = (await stageNpmPackArchiveInManagedRoot({
			archivePath: metadataResult.archivePath,
			npmRoot,
			packageName,
			version: metadataResult.metadata.version,
			integrity: metadataResult.metadata.integrity,
			shasum: metadataResult.metadata.shasum,
			tarballName: metadataResult.tarballName
		})).dependencySpec;
	} catch (error) {
		return {
			ok: false,
			error: `Failed to stage npm pack archive in managed npm root: ${String(error)}`
		};
	}
	const result = await installPluginFromManagedNpmRoot({
		dangerouslyForceUnsafeInstall: params.dangerouslyForceUnsafeInstall,
		trustedSourceLinkedOfficialInstall: params.trustedSourceLinkedOfficialInstall,
		packageName,
		dependencySpec,
		displaySpec: metadataResult.archivePath,
		installPolicyRequest: {
			kind: "plugin-npm",
			requestedSpecifier: `npm-pack:${metadataResult.archivePath}`
		},
		extensionsDir: params.extensionsDir,
		npmDir: npmRoot,
		timeoutMs,
		logger,
		mode,
		dryRun,
		expectedPluginId: params.expectedPluginId,
		npmResolution,
		...driftResult.integrityDrift ? { integrityDrift: driftResult.integrityDrift } : {}
	});
	return {
		...result,
		...result.ok ? { npmTarballName: metadataResult.tarballName } : {}
	};
}
async function installPluginFromPath(params) {
	const runtime = await loadPluginInstallRuntime();
	const pathResult = await runtime.resolveExistingInstallPath(params.path);
	if (!pathResult.ok) return pathResult;
	const { resolvedPath: resolved, stat } = pathResult;
	const packageInstallOptions = pickPackageInstallCommonParams(params);
	if (stat.isDirectory()) return await installPluginFromDir({
		dirPath: resolved,
		...packageInstallOptions,
		installPolicyRequest: {
			kind: "plugin-dir",
			requestedSpecifier: params.path
		}
	});
	if (runtime.resolveArchiveKind(resolved)) return await installPluginFromArchive({
		archivePath: resolved,
		...packageInstallOptions,
		installPolicyRequest: {
			kind: "plugin-archive",
			requestedSpecifier: params.path
		}
	});
	return await installPluginFromFile({
		filePath: resolved,
		...pickFileInstallCommonParams({
			...params,
			installPolicyRequest: {
				kind: "plugin-file",
				requestedSpecifier: params.path
			}
		})
	});
}
//#endregion
export { installPluginFromNpmSpec as a, installPluginFromNpmPackArchive as i, installPluginFromArchive as n, installPluginFromPath as o, installPluginFromInstalledPackageDir as r, PLUGIN_INSTALL_ERROR_CODE as t };
