UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

716 lines (715 loc) 27.6 kB
import { o as isRecord } from "./record-coerce-DHZ4bFlT.js"; import { i as formatErrorMessage } from "./errors-BXgSefBE.js"; import { t as formatCliCommand } from "./command-format-CKGmlpAQ.js"; import { r as theme } from "./theme-vjDs9tao.js"; import { _ as uniqueStrings } from "./string-normalization-WNUDCpXX.js"; import { a as tracePluginLifecyclePhaseAsync } from "./discovery-BDSfxwT6.js"; import { g as shortenHomePath } from "./utils-CCC-BEJH.js"; import { n as defaultRuntime } from "./runtime-B4lgFmsS.js"; import { t as parseClawHubPluginSpec } from "./clawhub-spec-BilWxjDF.js"; import "./clawhub-CzBrlwb2.js"; import { r as parseGitPluginSpec, t as installPluginFromGitSpec } from "./git-install-BdZ_4rl0.js"; import { r as resolveDefaultPluginExtensionsDir } from "./install-paths-D-sCLR1I.js"; import { c as resolveOfficialExternalPluginInstall, n as getOfficialExternalPluginCatalogEntryForPackage, s as resolveOfficialExternalPluginId, t as getOfficialExternalPluginCatalogEntry } from "./official-external-plugin-catalog-h7dZZiYs.js"; import { u as readConfigFileSnapshot } from "./io-Gi7-pyU-.js"; import { t as validateJsonSchemaValue } from "./schema-validator-CHU-4IBb.js"; import { s as resolveArchiveKind } from "./archive-Dcpo6Wva.js"; import "./archive-CBe_wA_B.js"; import { n as assertConfigWriteAllowedInCurrentMode } from "./nix-mode-write-guard-DMwPAosm.js"; import "./config-C9RxTsn1.js"; import { t as findBundledPluginSource } from "./bundled-sources-C3sNzxQs.js"; import { i as resolvePinnedNpmInstallRecordForCli, n as persistPluginInstall, t as persistHookPackInstall } from "./plugins-install-persist-CogTPCuA.js"; import { a as installPluginFromNpmSpec, i as installPluginFromNpmPackArchive, o as installPluginFromPath, t as PLUGIN_INSTALL_ERROR_CODE } from "./install-DzhyqmuT.js"; import { a as resolveOfficialExternalNpmPackageTrust, i as resolveOfficialExternalInstallPlanBeforeNpm, r as resolveBundledInstallPlanForNpmFailure, t as resolveBundledInstallPlanBeforeNpm } from "./plugin-install-plan-BuLcDN4V.js"; import { a as formatPluginInstallWithHookFallbackError, c as parseNpmPackPrefixPath, l as parseNpmPrefixSpec, n as createHookPackInstallLogger, r as createPluginInstallLogger } from "./plugins-command-helpers-BMTwD7oF.js"; import { n as installPluginFromClawHub } from "./clawhub-bGaJF9si.js"; import { t as buildClawHubPluginInstallRecordFields } from "./clawhub-install-records-DgujSxf8.js"; import { o as collectChannelDoctorStaleConfigMutations } from "./channel-doctor-BpjhUDUf.js"; import { n as installHooksFromPath, t as installHooksFromNpmSpec } from "./install-BYbeO-DA.js"; import { r as resolveMarketplaceInstallShortcut, t as installPluginFromMarketplace } from "./marketplace-CA-MtHLs.js"; import { r as resolvePluginInstallRequestContext, t as resolvePluginInstallInvalidConfigPolicy } from "./plugin-install-config-policy-D3Y5X8Ex.js"; import fs from "node:fs"; import path from "node:path"; //#region src/cli/install-spec.ts /** Detect specs that should be interpreted as local file/path installs. */ function looksLikeLocalInstallSpec(spec, knownSuffixes) { return spec.startsWith(".") || spec.startsWith("~") || path.isAbsolute(spec) || knownSuffixes.some((suffix) => spec.endsWith(suffix)); } //#endregion //#region src/cli/plugins-install-command.ts function resolveInstallMode(force) { return force ? "update" : "install"; } function resolveInstallSafetyOverrides(overrides) { return { config: overrides.config, dangerouslyForceUnsafeInstall: overrides.dangerouslyForceUnsafeInstall, trustedSourceLinkedOfficialInstall: overrides.trustedSourceLinkedOfficialInstall }; } const DEPRECATED_DANGEROUS_FORCE_UNSAFE_INSTALL_WARNING = "--dangerously-force-unsafe-install is deprecated and no longer affects plugin installs because built-in install-time dangerous-code scanning has been removed. Configure security.installPolicy for operator-owned install decisions."; function findTrustedCatalogPackageInstall(packageName) { const entry = getOfficialExternalPluginCatalogEntryForPackage(packageName); if (!entry) return; const pluginId = resolveOfficialExternalPluginId(entry); if (!pluginId) return; const install = resolveOfficialExternalPluginInstall(entry); return { pluginId, ...install?.npmSpec ? { npmSpec: install.npmSpec } : {}, ...install?.expectedIntegrity ? { expectedIntegrity: install.expectedIntegrity } : {} }; } function isEmptyRecord(value) { return Object.keys(value).length === 0; } function hasValidBundledPluginConfig(params) { if (!params.bundledSource.requiresConfig) return true; if (!isRecord(params.existingEntry)) return false; const config = params.existingEntry.config; if (!isRecord(config)) return false; if (!params.bundledSource.configSchema) return !isEmptyRecord(config); return validateJsonSchemaValue({ schema: params.bundledSource.configSchema, cacheKey: `bundled-install:${params.bundledSource.pluginId}`, value: config, applyDefaults: true }).ok; } function prepareConfigForDisabledBundledInstall(config, pluginId) { const { [pluginId]: _removedEntry, ...nextEntries } = config.plugins?.entries ?? {}; return { ...config, plugins: { ...config.plugins, entries: nextEntries } }; } async function installBundledPluginSource(params) { const existingEntry = params.snapshot.config.plugins?.entries?.[params.bundledSource.pluginId]; const shouldEnable = hasValidBundledPluginConfig({ bundledSource: params.bundledSource, existingEntry }); const configBase = shouldEnable ? params.snapshot.config : prepareConfigForDisabledBundledInstall(params.snapshot.config, params.bundledSource.pluginId); const configWarning = shouldEnable ? "" : `Installed bundled plugin "${params.bundledSource.pluginId}" without enabling it because it requires configuration first. Configure it, then run \`openclaw plugins enable ${params.bundledSource.pluginId}\`.`; await persistPluginInstall({ snapshot: { config: configBase, baseHash: params.snapshot.baseHash }, pluginId: params.bundledSource.pluginId, install: { source: "path", spec: params.rawSpec, sourcePath: params.bundledSource.localPath, installPath: params.bundledSource.localPath }, enable: shouldEnable, invalidateRuntimeCache: params.invalidateRuntimeCache, warningMessage: [params.warning, configWarning].filter(Boolean).join("\n"), runtime: params.runtime }); } async function tryInstallHookPackFromLocalPath(params) { if (params.link) { if (!fs.statSync(params.resolvedPath).isDirectory()) return { ok: false, error: "Linked hook pack paths must be directories." }; const probe = await installHooksFromPath({ ...resolveInstallSafetyOverrides(params.safetyOverrides ?? {}), path: params.resolvedPath, dryRun: true }); if (!probe.ok) return probe; const merged = uniqueStrings([...params.snapshot.config.hooks?.internal?.load?.extraDirs ?? [], params.resolvedPath]); await persistHookPackInstall({ snapshot: { config: { ...params.snapshot.config, hooks: { ...params.snapshot.config.hooks, internal: { ...params.snapshot.config.hooks?.internal, enabled: true, load: { ...params.snapshot.config.hooks?.internal?.load, extraDirs: merged } } } }, baseHash: params.snapshot.baseHash }, hookPackId: probe.hookPackId, hooks: probe.hooks, install: { source: "path", sourcePath: params.resolvedPath, installPath: params.resolvedPath, version: probe.version }, successMessage: `Linked hook pack path: ${shortenHomePath(params.resolvedPath)}`, runtime: params.runtime }); return { ok: true }; } const result = await installHooksFromPath({ ...resolveInstallSafetyOverrides(params.safetyOverrides ?? {}), path: params.resolvedPath, mode: params.installMode, logger: createHookPackInstallLogger(params.runtime) }); if (!result.ok) return result; const source = resolveArchiveKind(params.resolvedPath) ? "archive" : "path"; await persistHookPackInstall({ snapshot: params.snapshot, hookPackId: result.hookPackId, hooks: result.hooks, install: { source, sourcePath: params.resolvedPath, installPath: result.targetDir, version: result.version }, runtime: params.runtime }); return { ok: true }; } async function tryInstallHookPackFromNpmSpec(params) { const result = await installHooksFromNpmSpec({ spec: params.spec, mode: params.installMode, ...params.expectedIntegrity ? { expectedIntegrity: params.expectedIntegrity } : {}, logger: createHookPackInstallLogger(params.runtime) }); if (!result.ok) return result; const installRecord = resolvePinnedNpmInstallRecordForCli(params.spec, Boolean(params.pin), result.targetDir, result.version, result.npmResolution, params.runtime?.log ?? defaultRuntime.log, theme.warn); await persistHookPackInstall({ snapshot: params.snapshot, hookPackId: result.hookPackId, hooks: result.hooks, install: installRecord, runtime: params.runtime }); return { ok: true }; } async function tryInstallPluginOrHookPackFromNpmSpec(params) { const result = await installPluginFromNpmSpec({ ...params.safetyOverrides, mode: params.installMode, spec: params.spec, ...params.expectedPluginId ? { expectedPluginId: params.expectedPluginId } : {}, ...params.expectedIntegrity ? { expectedIntegrity: params.expectedIntegrity } : {}, ...params.trustedSourceLinkedOfficialInstall ? { trustedSourceLinkedOfficialInstall: true } : {}, extensionsDir: params.extensionsDir, logger: createPluginInstallLogger(params.runtime) }); if (!result.ok) { if (isTerminalPluginInstallFailure(result.code)) { (params.runtime ?? defaultRuntime).error(result.error); return { ok: false }; } if (params.allowBundledFallback) { const bundledFallbackPlan = resolveBundledInstallPlanForNpmFailure({ rawSpec: params.spec, code: result.code, findBundledSource: (lookup) => findBundledPluginSource({ lookup }) }); if (bundledFallbackPlan) { await installBundledPluginSource({ snapshot: params.snapshot, rawSpec: params.spec, bundledSource: bundledFallbackPlan.bundledSource, warning: bundledFallbackPlan.warning, invalidateRuntimeCache: params.invalidateRuntimeCache, runtime: params.runtime }); return { ok: true }; } } const hookFallback = await tryInstallHookPackFromNpmSpec({ snapshot: params.snapshot, installMode: params.installMode, spec: params.spec, pin: params.pin, expectedIntegrity: params.expectedIntegrity, runtime: params.runtime }); if (hookFallback.ok) return { ok: true }; (params.runtime ?? defaultRuntime).error(formatPluginInstallWithHookFallbackError(result.error, hookFallback.error)); return { ok: false }; } const installRecord = resolvePinnedNpmInstallRecordForCli(params.spec, Boolean(params.pin), result.targetDir, result.version, result.npmResolution, params.runtime?.log ?? defaultRuntime.log, theme.warn); await persistPluginInstall({ snapshot: params.snapshot, pluginId: result.pluginId, install: installRecord, invalidateRuntimeCache: params.invalidateRuntimeCache, runtime: params.runtime }); return { ok: true }; } async function tryInstallPluginFromNpmPackArchive(params) { const result = await installPluginFromNpmPackArchive({ ...params.safetyOverrides, mode: params.installMode, archivePath: params.archivePath, extensionsDir: params.extensionsDir, logger: createPluginInstallLogger(params.runtime) }); if (!result.ok) { (params.runtime ?? defaultRuntime).error(result.error); return { ok: false }; } await persistPluginInstall({ snapshot: params.snapshot, pluginId: result.pluginId, install: { source: "npm", spec: result.npmResolution?.resolvedSpec ?? result.manifestName ?? result.pluginId, sourcePath: params.archivePath, installPath: result.targetDir, ...result.version ? { version: result.version } : {}, ...result.npmResolution?.name ? { resolvedName: result.npmResolution.name } : {}, ...result.npmResolution?.version ? { resolvedVersion: result.npmResolution.version } : {}, ...result.npmResolution?.resolvedSpec ? { resolvedSpec: result.npmResolution.resolvedSpec } : {}, ...result.npmResolution?.integrity ? { integrity: result.npmResolution.integrity } : {}, ...result.npmResolution?.shasum ? { shasum: result.npmResolution.shasum } : {}, ...result.npmResolution?.resolvedAt ? { resolvedAt: result.npmResolution.resolvedAt } : {}, artifactKind: "npm-pack", artifactFormat: "tgz", ...result.npmResolution?.integrity ? { npmIntegrity: result.npmResolution.integrity } : {}, ...result.npmResolution?.shasum ? { npmShasum: result.npmResolution.shasum } : {}, ...result.npmTarballName ? { npmTarballName: result.npmTarballName } : {} }, invalidateRuntimeCache: params.invalidateRuntimeCache, runtime: params.runtime }); return { ok: true }; } async function tryInstallPluginFromGitSpec(params) { const result = await installPluginFromGitSpec({ ...params.safetyOverrides, mode: params.installMode, spec: params.spec, extensionsDir: params.extensionsDir, logger: createPluginInstallLogger(params.runtime) }); if (!result.ok) { (params.runtime ?? defaultRuntime).error(result.error); return { ok: false }; } await persistPluginInstall({ snapshot: params.snapshot, pluginId: result.pluginId, install: { source: "git", spec: params.spec, installPath: result.targetDir, version: result.version, resolvedAt: result.git.resolvedAt, gitUrl: result.git.url, gitRef: result.git.ref, gitCommit: result.git.commit }, invalidateRuntimeCache: params.invalidateRuntimeCache, runtime: params.runtime }); return { ok: true }; } function isTerminalPluginInstallFailure(code) { return code === PLUGIN_INSTALL_ERROR_CODE.SECURITY_SCAN_BLOCKED || code === PLUGIN_INSTALL_ERROR_CODE.SECURITY_SCAN_FAILED || code === PLUGIN_INSTALL_ERROR_CODE.UNSUPPORTED_PLAIN_FILE_PLUGIN; } function isAllowedPluginRecoveryIssue(issue, request) { const pluginId = request.bundledPluginId?.trim(); if (!pluginId) return false; return issue.path === `channels.${pluginId}` && issue.message === `unknown channel id: ${pluginId}` || issue.path === "plugins.load.paths" && typeof issue.message === "string" && issue.message.includes("plugin path not found") || issue.path === "plugins" && typeof issue.message === "string" && issue.message.includes("requires compiled runtime output") || issue.path === `plugins.entries.${pluginId}` && typeof issue.message === "string" && issue.message.includes("requires compiled runtime output") || issue.path === "tools.web.search.provider" && typeof issue.message === "string" && issue.message.includes(`plugin "${pluginId}"`); } function buildInvalidPluginInstallConfigError(message) { const error = new Error(message); error.code = "INVALID_CONFIG"; return error; } async function loadConfigFromSnapshotForInstall(request, snapshot) { if (resolvePluginInstallInvalidConfigPolicy(request) !== "allow-plugin-recovery") throw buildInvalidPluginInstallConfigError("Config invalid; run `openclaw doctor --fix` before installing plugins."); const parsed = snapshot.parsed ?? {}; if (!snapshot.exists || Object.keys(parsed).length === 0) throw buildInvalidPluginInstallConfigError("Config file could not be parsed; run `openclaw doctor` to repair it."); if (snapshot.legacyIssues.length > 0 || snapshot.issues.length === 0 || snapshot.issues.some((issue) => !isAllowedPluginRecoveryIssue(issue, request))) throw buildInvalidPluginInstallConfigError(`Config invalid outside the plugin recovery path for ${request.bundledPluginId ?? "the requested plugin"}; run \`openclaw doctor --fix\` before reinstalling it.`); let nextConfig = snapshot.config; for (const mutation of await collectChannelDoctorStaleConfigMutations(snapshot.config, { env: process.env })) nextConfig = mutation.config; return { config: nextConfig, baseHash: snapshot.hash }; } async function loadConfigForInstall(request) { const snapshot = await tracePluginLifecyclePhaseAsync("config read", () => readConfigFileSnapshot(), { command: "install" }); if (snapshot.valid) return { config: snapshot.sourceConfig, baseHash: snapshot.hash }; return loadConfigFromSnapshotForInstall(request, snapshot); } async function runPluginInstallCommand(params) { assertConfigWriteAllowedInCurrentMode(); const runtime = params.runtime ?? defaultRuntime; const invalidateRuntimeCache = params.invalidateRuntimeCache ?? true; const shorthand = !params.opts.marketplace ? await tracePluginLifecyclePhaseAsync("marketplace shortcut resolution", () => resolveMarketplaceInstallShortcut(params.raw), { command: "install" }) : null; if (shorthand?.ok === false) { runtime.error(shorthand.error); return runtime.exit(1); } const raw = shorthand?.ok ? shorthand.plugin : params.raw; const opts = { ...params.opts, marketplace: params.opts.marketplace ?? (shorthand?.ok ? shorthand.marketplaceSource : void 0) }; if (opts.dangerouslyForceUnsafeInstall) runtime.log(theme.warn(DEPRECATED_DANGEROUS_FORCE_UNSAFE_INSTALL_WARNING)); if (opts.marketplace) { if (opts.link) { runtime.error(`--link is not supported with --marketplace. Remove --link, or install a local path with ${formatCliCommand("openclaw plugins install --link <path>")}.`); return runtime.exit(1); } if (opts.pin) { runtime.error(`--pin is not supported with --marketplace. Use ${formatCliCommand("openclaw plugins install <plugin> --marketplace <name>")} without --pin.`); return runtime.exit(1); } } const gitPrefix = raw.trim().toLowerCase().startsWith("git:"); const gitSpec = parseGitPluginSpec(raw); if (gitPrefix && !gitSpec) { runtime.error(`Unsupported git plugin spec: ${raw}. Use ${formatCliCommand("openclaw plugins install git:<repo>@<ref>")}.`); return runtime.exit(1); } if (gitSpec && opts.link) { runtime.error(`--link is not supported with git: installs. Use ${formatCliCommand("openclaw plugins install git:<repo>@<ref>")} for Git installs or ${formatCliCommand("openclaw plugins install --link <path>")} for local paths.`); return runtime.exit(1); } if (gitSpec && opts.pin) { runtime.error(`--pin is not supported with git: installs. Pin the ref in the spec instead, for example ${formatCliCommand("openclaw plugins install git:<repo>@<ref>")}.`); return runtime.exit(1); } if (opts.link && opts.force) { runtime.error(`--force is not supported with --link. Linked plugins point at the source path directly; remove --force and re-run ${formatCliCommand("openclaw plugins install --link <path>")}.`); return runtime.exit(1); } const requestResolution = resolvePluginInstallRequestContext({ rawSpec: raw, marketplace: opts.marketplace }); if (!requestResolution.ok) { runtime.error(requestResolution.error); return runtime.exit(1); } const request = requestResolution.request; const snapshot = await loadConfigForInstall(request).catch((error) => { runtime.error(formatErrorMessage(error)); return null; }); if (!snapshot) return runtime.exit(1); const cfg = snapshot.config; const installMode = resolveInstallMode(opts.force); const safetyOverrides = resolveInstallSafetyOverrides({ ...opts, config: cfg }); const extensionsDir = resolveDefaultPluginExtensionsDir(); if (opts.marketplace) { const result = await installPluginFromMarketplace({ ...safetyOverrides, marketplace: opts.marketplace, mode: installMode, plugin: raw, extensionsDir, logger: createPluginInstallLogger(runtime) }); if (!result.ok) { runtime.error(result.error); return runtime.exit(1); } await persistPluginInstall({ snapshot, pluginId: result.pluginId, install: { source: "marketplace", installPath: result.targetDir, version: result.version, marketplaceName: result.marketplaceName, marketplaceSource: result.marketplaceSource, marketplacePlugin: result.marketplacePlugin }, invalidateRuntimeCache, runtime }); return; } const resolved = request.resolvedPath ?? request.normalizedSpec; if (fs.existsSync(resolved)) { if (opts.link) { const merged = uniqueStrings([...cfg.plugins?.load?.paths ?? [], resolved]); const probe = await installPluginFromPath({ ...safetyOverrides, mode: installMode, path: resolved, dryRun: true, allowSourceTypeScriptEntries: true, extensionsDir, logger: createPluginInstallLogger(runtime) }); if (!probe.ok) { if (isTerminalPluginInstallFailure(probe.code)) { runtime.error(probe.error); return runtime.exit(1); } const hookFallback = await tryInstallHookPackFromLocalPath({ snapshot, installMode, resolvedPath: resolved, safetyOverrides, link: true, runtime }); if (hookFallback.ok) return; runtime.error(formatPluginInstallWithHookFallbackError(probe.error, hookFallback.error)); return runtime.exit(1); } await persistPluginInstall({ snapshot: { config: { ...cfg, plugins: { ...cfg.plugins, load: { ...cfg.plugins?.load, paths: merged } } }, baseHash: snapshot.baseHash }, pluginId: probe.pluginId, install: { source: "path", sourcePath: resolved, installPath: resolved, version: probe.version }, invalidateRuntimeCache, successMessage: `Linked plugin path: ${shortenHomePath(resolved)}`, runtime }); return; } const result = await installPluginFromPath({ ...safetyOverrides, mode: installMode, path: resolved, extensionsDir, logger: createPluginInstallLogger(runtime) }); if (!result.ok) { if (isTerminalPluginInstallFailure(result.code)) { runtime.error(result.error); return runtime.exit(1); } const hookFallback = await tryInstallHookPackFromLocalPath({ snapshot, installMode, resolvedPath: resolved, safetyOverrides, runtime }); if (hookFallback.ok) return; runtime.error(formatPluginInstallWithHookFallbackError(result.error, hookFallback.error)); return runtime.exit(1); } const source = resolveArchiveKind(resolved) ? "archive" : "path"; await persistPluginInstall({ snapshot, pluginId: result.pluginId, install: { source, sourcePath: resolved, installPath: result.targetDir, version: result.version }, invalidateRuntimeCache, runtime }); return; } if (opts.link) { runtime.error(`--link requires a local path. Run ${formatCliCommand("openclaw plugins install --link <path>")}.`); return runtime.exit(1); } const npmPrefixSpec = parseNpmPrefixSpec(raw); if (npmPrefixSpec !== null) { if (!npmPrefixSpec) { runtime.error(`Unsupported npm plugin spec: missing package. Use ${formatCliCommand("openclaw plugins install npm:<package>")}.`); return runtime.exit(1); } const officialNpmTrust = resolveOfficialExternalNpmPackageTrust({ npmSpec: npmPrefixSpec, findOfficialExternalPackage: findTrustedCatalogPackageInstall }); if (!(await tryInstallPluginOrHookPackFromNpmSpec({ snapshot, installMode, spec: npmPrefixSpec, pin: opts.pin, safetyOverrides, allowBundledFallback: false, extensionsDir, invalidateRuntimeCache, ...officialNpmTrust ? { expectedPluginId: officialNpmTrust.pluginId, ...officialNpmTrust.expectedIntegrity ? { expectedIntegrity: officialNpmTrust.expectedIntegrity } : {}, trustedSourceLinkedOfficialInstall: true } : {}, runtime })).ok) return runtime.exit(1); return; } const npmPackPath = parseNpmPackPrefixPath(raw); if (npmPackPath !== null) { if (!npmPackPath) { runtime.error(`Unsupported npm-pack plugin spec: missing archive path. Use ${formatCliCommand("openclaw plugins install npm-pack:<path-to.tgz>")}.`); return runtime.exit(1); } if (!(await tryInstallPluginFromNpmPackArchive({ snapshot, installMode, archivePath: npmPackPath, safetyOverrides, extensionsDir, invalidateRuntimeCache, runtime })).ok) return runtime.exit(1); return; } if (gitSpec) { if (!(await tryInstallPluginFromGitSpec({ snapshot, installMode, spec: raw, safetyOverrides, extensionsDir, invalidateRuntimeCache, runtime })).ok) return runtime.exit(1); return; } if (looksLikeLocalInstallSpec(raw, [ ".ts", ".js", ".mjs", ".cjs", ".tgz", ".tar.gz", ".tar", ".zip" ])) { runtime.error(`Plugin path not found: ${resolved}. Check the path, or install from npm with ${formatCliCommand("openclaw plugins install npm:<package>")}.`); return runtime.exit(1); } const bundledPreNpmPlan = resolveBundledInstallPlanBeforeNpm({ rawSpec: raw, findBundledSource: (lookup) => findBundledPluginSource({ lookup }) }); if (bundledPreNpmPlan) { await tracePluginLifecyclePhaseAsync("install execution", () => installBundledPluginSource({ snapshot, rawSpec: raw, bundledSource: bundledPreNpmPlan.bundledSource, warning: bundledPreNpmPlan.warning, invalidateRuntimeCache, runtime }), { command: "install", source: "bundled", pluginId: bundledPreNpmPlan.bundledSource.pluginId }); return; } const officialExternalPlan = resolveOfficialExternalInstallPlanBeforeNpm({ rawSpec: raw, findOfficialExternalPlugin: (pluginId) => { const entry = getOfficialExternalPluginCatalogEntry(pluginId); const resolvedPluginId = entry ? resolveOfficialExternalPluginId(entry) : void 0; const install = entry ? resolveOfficialExternalPluginInstall(entry) : null; const npmSpec = install?.npmSpec; return resolvedPluginId && npmSpec ? { pluginId: resolvedPluginId, npmSpec, ...install.expectedIntegrity ? { expectedIntegrity: install.expectedIntegrity } : {} } : void 0; } }); if (officialExternalPlan) { if (!(await tryInstallPluginOrHookPackFromNpmSpec({ snapshot, installMode, spec: officialExternalPlan.npmSpec, pin: opts.pin, safetyOverrides, allowBundledFallback: false, extensionsDir, expectedPluginId: officialExternalPlan.pluginId, expectedIntegrity: officialExternalPlan.expectedIntegrity, trustedSourceLinkedOfficialInstall: true, invalidateRuntimeCache, runtime })).ok) return runtime.exit(1); return; } if (parseClawHubPluginSpec(raw)) { const result = await installPluginFromClawHub({ ...safetyOverrides, mode: installMode, spec: raw, extensionsDir, logger: createPluginInstallLogger(runtime) }); if (!result.ok) { runtime.error(result.error); return runtime.exit(1); } await persistPluginInstall({ snapshot, pluginId: result.pluginId, install: { ...buildClawHubPluginInstallRecordFields(result.clawhub), spec: raw, installPath: result.targetDir }, invalidateRuntimeCache, runtime }); return; } const officialNpmTrust = resolveOfficialExternalNpmPackageTrust({ npmSpec: raw, findOfficialExternalPackage: findTrustedCatalogPackageInstall }); if (!(await tryInstallPluginOrHookPackFromNpmSpec({ snapshot, installMode, spec: raw, pin: opts.pin, safetyOverrides, allowBundledFallback: true, extensionsDir, invalidateRuntimeCache, ...officialNpmTrust ? { expectedPluginId: officialNpmTrust.pluginId, ...officialNpmTrust.expectedIntegrity ? { expectedIntegrity: officialNpmTrust.expectedIntegrity } : {}, trustedSourceLinkedOfficialInstall: true } : {}, runtime })).ok) return runtime.exit(1); } //#endregion export { runPluginInstallCommand as n, loadConfigForInstall as t };