UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

747 lines (746 loc) 28.8 kB
import { y as uniqueStrings } from "./string-normalization-DsCfAx8q.js"; import { r as defaultRuntime } from "./runtime-CF2WjnNZ.js"; import { m as shortenHomePath } from "./utils-P__uGsPB.js"; import { t as formatCliCommand } from "./command-format-C7YfyMTd.js"; import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js"; import { c as tracePluginLifecyclePhaseAsync } from "./discovery-D_VDsZuY.js"; import { t as parseClawHubPluginSpec } from "./clawhub-spec-Er3Np6VI.js"; import { I as CLAWHUB_INSTALL_ERROR_CODE } from "./official-external-plugin-catalog-Dzu7dwBN.js"; import { t as PLUGIN_INSTALL_ERROR_CODE } from "./install-types-DY_kphq4.js"; import { n as assertConfigWriteAllowedInCurrentMode } from "./nix-mode-write-guard-uwcnAyQN.js"; import { r as replaceConfigFile } from "./mutate-ZNN4iFCn.js"; import "./config-Cs0XXL3x.js"; import { r as theme } from "./theme-vjDs9tao.js"; import { h as resolveArchiveKind } from "./archive-BfjFIxAJ.js"; import { t as buildNpmResolutionFields } from "./install-source-utils-DPJygB4h.js"; import { r as withClawPackageLifecycleLease } from "./claw-package-lifecycle-lease-CH70IHcU.js"; import { a as resolvePackageDirInstallTransaction, i as requestDeferredPackageDirInstall } from "./install-package-dir-kJK8m3kQ.js"; import { a as reportClawHubPluginInstallTelemetry } from "./clawhub-packages-DzRBkN2F.js"; import { t as markClawPackageIndependentlyOwned } from "./claw-package-adoption-Ba25vCgq.js"; import { t as findBundledPluginSource } from "./bundled-sources-CU4qjQGy.js"; import { n as formatNonClawHubInstallWarning, t as NON_CLAWHUB_INSTALL_FORCE_FLAG } from "./install-provenance-W0Pf0RSv.js"; import { t as withPluginLifecycleLease } from "./plugin-lifecycle-lease-BtAFH872.js"; import { r as promptYesNo } from "./prompt-BvBir9Yc.js"; import { n as resolvePluginCapabilityConsentCliOptions } from "./plugin-capability-consent-HWTOHYVK.js"; import "./install-BezM8CtS.js"; import { n as resolveBundledInstallPlanForNpmFailure, r as resolvePluginInstallSourcePlan } from "./plugin-install-plan-5wcyV5nl.js"; import { n as installHooksFromNpmSpec, r as installHooksFromPath } from "./install-7XIb3_ne.js"; import { i as formatPluginInstallWithHookFallbackError, n as createPluginInstallLogger, r as enableInternalHookEntries, t as createHookPackInstallLogger } from "./plugins-command-helpers-X8Lgc-nc.js"; import { t as installManagedPluginSource } from "./management-install-CPAJwGGP.js"; import "./clawhub-DgZbJqg3.js"; import { r as resolveMarketplaceInstallShortcut } from "./marketplace-ClbNhrdY.js"; import { r as resolvePluginInstallRequestContext } from "./plugin-install-config-policy-BKE_FN73.js"; import { t as resolveClawHubInstallConfirmation } from "./clawhub-install-confirmation-D-TCZ_VU.js"; import { t as resolveInstallPolicyWarningAcknowledgementCliOptions } from "./install-policy-warning-acknowledgement-DNm6cyVK.js"; import { n as resolveFullyBlockedConfigMutationReason, t as loadConfigForInstall } from "./plugins-install-config-_OMLBGf-.js"; import { t as stageHookInstall } from "./install-record-transaction-BSZea7FD.js"; import fs from "node:fs"; //#region src/cli/non-clawhub-install-acknowledgement.ts function canPromptForNonClawHubInstall() { return process.stdin.isTTY && process.stdout.isTTY; } async function confirmNonClawHubInstall(params) { const warning = formatNonClawHubInstallWarning({ sourceClass: params.sourceClass, spec: params.spec }); if (params.acknowledged) { params.runtime.log(theme.warn(warning)); return true; } if (canPromptForNonClawHubInstall()) { params.runtime.log(theme.warn(warning)); return await promptYesNo("Install this non-ClawHub plugin source?"); } params.runtime.error(`${warning}\nInstall cancelled; rerun with ${NON_CLAWHUB_INSTALL_FORCE_FLAG} after reviewing the source.`); return false; } //#endregion //#region src/cli/hook-install-persistence.ts async function persistHookPackInstall(params) { const runtime = params.runtime ?? defaultRuntime; return await withPluginLifecycleLease({}, async (lease) => { const assertPersistentApply = () => { lease.assertOwned(); params.snapshot.writeOptions.assertConfigPathForWrite?.(); params.beforePersistentApply?.(); }; const next = enableInternalHookEntries(params.snapshot.config, params.hooks); const transaction = await stageHookInstall({ update: { hookId: params.hookPackId, hooks: params.hooks, ...params.install }, payloadTransaction: params.payloadTransaction, lease, beforePersistentApply: assertPersistentApply }); try { await replaceConfigFile({ nextConfig: next, baseHash: params.snapshot.baseHash, writeOptions: { ...params.snapshot.writeOptions, assertConfigPathForWrite: assertPersistentApply } }); } catch (error) { try { await transaction.rollback(); } catch (rollbackError) { throw new AggregateError([error, rollbackError], "Hook install config rollback failed", { cause: rollbackError }); } throw error; } await transaction.commit(); runtime.log(params.successMessage ?? `Installed hook pack: ${params.hookPackId}`); runtime.log("Hook install/link config can activate immediately in hybrid mode; code-only updates and reload mode off need a Gateway restart."); return next; }); } //#endregion //#region src/cli/npm-resolution.ts /** Build the npm section of a plugin install record. */ function buildNpmInstallRecordFields(params) { return { source: "npm", spec: params.spec, installPath: params.installPath, version: params.version, ...buildNpmResolutionFields(params.resolution) }; } /** CLI adapter for npm install-record pinning with styled warning output. */ function resolvePinnedNpmInstallRecordForCli(rawSpec, pin, installPath, version, resolution, log, warnFormat) { const resolvedSpec = resolution?.resolvedSpec; const recordSpec = pin && resolvedSpec ? resolvedSpec : rawSpec; if (pin) { if (resolvedSpec) log(`Pinned npm install record to ${resolvedSpec}.`); else log(warnFormat("Could not resolve exact npm version for --pin; storing original npm spec.")); } return buildNpmInstallRecordFields({ spec: recordSpec, installPath, version, resolution }); } //#endregion //#region src/cli/plugins-install-hook-fallback.ts function resolveInstallSafetyOverrides(overrides) { return { config: overrides.config, dangerouslyForceUnsafeInstall: overrides.dangerouslyForceUnsafeInstall, onInstallPolicyWarning: overrides.onInstallPolicyWarning, trustedSourceLinkedOfficialInstall: overrides.trustedSourceLinkedOfficialInstall }; } async function probeHookPackFromNpmSpec(params) { try { return await installHooksFromNpmSpec(params); } catch (error) { return { ok: false, error: formatErrorMessage(error) }; } } async function probeHookPackFromPath(params) { try { return await installHooksFromPath(params); } catch (error) { return { ok: false, error: formatErrorMessage(error) }; } } 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.RELEASE_COHORT_UNAVAILABLE || code === PLUGIN_INSTALL_ERROR_CODE.UNSUPPORTED_PLAIN_FILE_PLUGIN; } async function tryInstallHookPackFromLocalPath(params) { if (params.snapshot.hookMutation.mode === "blocked") return { ok: false, error: params.snapshot.hookMutation.reason }; 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, ...params.expectedPackageKind ? { expectedPackageKind: params.expectedPackageKind } : {} }); if (!probe.ok) return probe; const existing = params.snapshot.config.hooks?.internal?.load?.extraDirs ?? []; const merged = uniqueStrings([...existing, params.resolvedPath]); await persistHookPackInstall({ snapshot: { ...params.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 } } } } }, 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, beforePersistentApply: params.beforePersistentApply }); return { ok: true }; } const result = await installHooksFromPath(requestDeferredPackageDirInstall({ ...resolveInstallSafetyOverrides(params.safetyOverrides ?? {}), path: params.resolvedPath, mode: params.installMode, ...params.expectedPackageKind ? { expectedPackageKind: params.expectedPackageKind } : {}, logger: createHookPackInstallLogger(params.runtime), beforePersistentApply: params.beforePersistentApply }, params.assertOwned)); 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, beforePersistentApply: params.beforePersistentApply, payloadTransaction: resolvePackageDirInstallTransaction(result) }); return { ok: true }; } async function tryInstallHookPackFromNpmSpec(params) { if (params.snapshot.hookMutation.mode === "blocked") return { ok: false, error: params.snapshot.hookMutation.reason }; const result = await installHooksFromNpmSpec(requestDeferredPackageDirInstall({ ...resolveInstallSafetyOverrides(params.safetyOverrides ?? {}), config: params.snapshot.config, spec: params.spec, mode: params.installMode, ...params.expectedIntegrity ? { expectedIntegrity: params.expectedIntegrity } : {}, ...params.expectedPackageKind ? { expectedPackageKind: params.expectedPackageKind } : {}, logger: createHookPackInstallLogger(params.runtime), beforePersistentApply: params.beforePersistentApply }, params.assertOwned)); if (!result.ok) return result; const pinMessages = []; const installRecord = resolvePinnedNpmInstallRecordForCli(params.spec, Boolean(params.pin), result.targetDir, result.version, result.npmResolution, (message) => pinMessages.push(message), theme.warn); await persistHookPackInstall({ snapshot: params.snapshot, hookPackId: result.hookPackId, hooks: result.hooks, install: installRecord, runtime: params.runtime, beforePersistentApply: params.beforePersistentApply, payloadTransaction: resolvePackageDirInstallTransaction(result) }); for (const message of pinMessages) (params.runtime ?? defaultRuntime).log(message); return { ok: true }; } /** Preserve npm plugin and hook ownership without executing a blocked mutation. */ async function tryInstallPluginOrHookPackFromNpmSpec(params) { const runtime = params.runtime ?? defaultRuntime; const installContext = { snapshot: params.snapshot, runtime, invalidateRuntimeCache: params.invalidateRuntimeCache, beforePersistentApply: params.beforePersistentApply, assertOwned: params.assertOwned }; const fullyBlockedReason = resolveFullyBlockedConfigMutationReason(params.snapshot); if (fullyBlockedReason) { runtime.error(fullyBlockedReason); return { ok: false }; } if (params.snapshot.pluginMutation.mode === "blocked" || params.snapshot.hookMutation.mode === "blocked") { const hookProbe = await probeHookPackFromNpmSpec({ ...resolveInstallSafetyOverrides(params.safetyOverrides), config: params.snapshot.config, spec: params.spec, mode: params.installMode, inspection: "package-kind", ...params.expectedIntegrity ? { expectedIntegrity: params.expectedIntegrity } : {}, logger: createHookPackInstallLogger(params.runtime) }); if (hookProbe.ok && hookProbe.packageKind === "hook-only") { if (params.snapshot.hookMutation.mode === "blocked") { runtime.error(params.snapshot.hookMutation.reason); return { ok: false }; } const hookFallback = await tryInstallHookPackFromNpmSpec({ ...installContext, installMode: params.installMode, spec: params.spec, safetyOverrides: params.safetyOverrides, pin: params.pin, expectedIntegrity: hookProbe.npmResolution?.integrity ?? params.expectedIntegrity, expectedPackageKind: "hook-only" }); if (hookFallback.ok) return { ok: true }; runtime.error(hookFallback.error); return { ok: false }; } if (params.snapshot.pluginMutation.mode === "blocked") { runtime.error(params.snapshot.pluginMutation.reason); return { ok: false }; } } const result = await installManagedPluginSource({ request: params.officialRequest ?? { source: "npm", spec: params.spec, mode: params.installMode, pin: params.pin, ...params.expectedPluginId ? { expectedPluginId: params.expectedPluginId } : {}, ...params.expectedIntegrity ? { expectedIntegrity: params.expectedIntegrity } : {}, ...params.trustedSourceLinkedOfficialInstall ? { trustedSourceLinkedOfficialInstall: true } : {} }, ...installContext, ...params.capabilityConsent, safetyOverrides: params.safetyOverrides, logger: createPluginInstallLogger(params.runtime) }); if (!result.ok) { if (result.installSource?.source === "clawhub" || params.officialRequest && result.code !== PLUGIN_INSTALL_ERROR_CODE.MISSING_OPENCLAW_EXTENSIONS || isTerminalPluginInstallFailure(result.code)) { runtime.error(result.error); return { ok: false }; } if (params.allowBundledFallback) { const bundledFallbackPlan = resolveBundledInstallPlanForNpmFailure({ rawSpec: params.spec, code: result.code, findBundledSource: (lookup) => findBundledPluginSource({ lookup }) }); if (bundledFallbackPlan) { const bundledResult = await installManagedPluginSource({ request: { source: "bundled", rawSpec: params.spec, bundledSource: bundledFallbackPlan.bundledSource, warning: bundledFallbackPlan.warning }, ...installContext }); if (!bundledResult.ok) { runtime.error(bundledResult.error); return { ok: false }; } return { ok: true }; } } const hookFallback = await tryInstallHookPackFromNpmSpec({ ...installContext, installMode: params.installMode, spec: params.spec, safetyOverrides: params.safetyOverrides, pin: params.pin, expectedIntegrity: params.expectedIntegrity }); if (hookFallback.ok) return { ok: true }; runtime.error(formatPluginInstallWithHookFallbackError(result.error, hookFallback)); return { ok: false }; } if (params.pin) { const resolvedSpec = result.npmResolution?.resolvedSpec; runtime.log(resolvedSpec ? `Pinned npm install record to ${resolvedSpec}.` : theme.warn("Could not resolve exact npm version for --pin; storing original npm spec.")); } return { ok: true }; } //#endregion //#region src/cli/plugins-install-preflight.ts function resolveMarketplaceOptionError(opts) { if (opts.link) return `--link is not supported with --marketplace. Remove --link, or install a local path with ${formatCliCommand(`openclaw plugins install --link <path> ${NON_CLAWHUB_INSTALL_FORCE_FLAG}`)}.`; if (opts.pin) return `--pin is not supported with --marketplace. Use ${formatCliCommand(`openclaw plugins install <plugin> --marketplace <name> ${NON_CLAWHUB_INSTALL_FORCE_FLAG}`)} without --pin.`; return null; } function resolveSourceOptionError(opts, sourcePlan) { if (sourcePlan.request.source === "git" && opts.link) return `--link is not supported with git: installs. Use ${formatCliCommand(`openclaw plugins install git:<repo>@<ref> ${NON_CLAWHUB_INSTALL_FORCE_FLAG}`)} for Git installs or ${formatCliCommand(`openclaw plugins install --link <path> ${NON_CLAWHUB_INSTALL_FORCE_FLAG}`)} for local paths.`; if (sourcePlan.request.source === "git" && opts.pin) return `--pin is not supported with git: installs. Pin the ref in the spec instead, for example ${formatCliCommand(`openclaw plugins install git:<repo>@<ref> ${NON_CLAWHUB_INSTALL_FORCE_FLAG}`)}.`; if (opts.pin && sourcePlan.request.source !== "npm" && sourcePlan.request.source !== "official" && sourcePlan.request.source !== "bundled") return "--pin is only supported with npm registry installs."; if (opts.link && sourcePlan.request.source !== "local") return `--link requires a local path. Run ${formatCliCommand(`openclaw plugins install --link <path> ${NON_CLAWHUB_INSTALL_FORCE_FLAG}`)}.`; return null; } /** Complete source and option validation before acquiring the persistent lifecycle lease. */ async function resolvePluginInstallPreflight(params) { if (!params.raw.trim()) return { ok: false, error: "Plugin install source must not be empty." }; if (params.opts.marketplace !== void 0 && !params.opts.marketplace.trim()) return { ok: false, error: "--marketplace requires a non-empty source." }; const installMode = params.opts.force && !params.opts.link ? "update" : "install"; let raw = params.raw; let marketplace = params.opts.marketplace; let sourcePlan = null; if (marketplace === void 0) { const shorthand = await tracePluginLifecyclePhaseAsync("marketplace shortcut resolution", () => resolveMarketplaceInstallShortcut(raw), { command: "install" }); if (shorthand?.ok === false) return { ok: false, error: shorthand.error }; if (shorthand?.ok) { raw = shorthand.plugin; marketplace = shorthand.marketplaceSource; } else { const planned = resolvePluginInstallSourcePlan({ raw, mode: installMode, link: params.opts.link, pin: params.opts.pin }); if (!planned.ok) return planned; sourcePlan = planned; } } const opts = { ...params.opts, marketplace }; const optionError = marketplace ? resolveMarketplaceOptionError(opts) : sourcePlan ? resolveSourceOptionError(opts, sourcePlan) : "Plugin install source could not be resolved."; if (optionError) return { ok: false, error: optionError }; const requestResolution = resolvePluginInstallRequestContext({ rawSpec: raw, marketplace }); if (!requestResolution.ok) return requestResolution; const source = sourcePlan?.request.source; const request = source && [ "npm-pack", "git", "clawhub", "bundled", "official" ].includes(source) ? { ...requestResolution.request, installKind: "plugin" } : requestResolution.request; if (marketplace) return { ok: true, raw, opts, installMode, request, marketplace, sourcePlan: null }; if (!sourcePlan) return { ok: false, error: "Plugin install source could not be resolved." }; return { ok: true, raw, opts, installMode, request, sourcePlan }; } //#endregion //#region src/cli/plugins-install-command.ts 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 isClawHubBlockedCliFailure(result) { return result.code === CLAWHUB_INSTALL_ERROR_CODE.CLAWHUB_DOWNLOAD_BLOCKED && typeof result.warning === "string" && result.warning.trim().length > 0; } /** Validate install intent before opening the SQLite-backed plugin lifecycle lease. */ async function runPluginInstallCommand(params) { assertConfigWriteAllowedInCurrentMode(); const runtime = params.runtime ?? defaultRuntime; const preflight = await resolvePluginInstallPreflight(params); if (!preflight.ok) { runtime.error(preflight.error); return runtime.exit(1); } return await withPluginLifecycleLease({}, async (lease) => await runPluginInstallCommandUnlocked({ ...params, beforePersistentApply: () => { lease.assertOwned(); params.beforePersistentApply?.(); } }, preflight, lease.assertOwned.bind(lease))); } async function runPluginInstallCommandUnlocked(params, preflight, assertOwned) { assertConfigWriteAllowedInCurrentMode(); const runtime = params.runtime ?? defaultRuntime; const { raw, opts, installMode, request } = preflight; if (opts.dangerouslyForceUnsafeInstall) runtime.log(theme.warn(DEPRECATED_DANGEROUS_FORCE_UNSAFE_INSTALL_WARNING)); const snapshot = await loadConfigForInstall(request).catch((error) => { runtime.error(formatErrorMessage(error)); return null; }); if (!snapshot) return runtime.exit(1); const installContext = { snapshot, runtime, invalidateRuntimeCache: params.invalidateRuntimeCache ?? true, beforePersistentApply: params.beforePersistentApply, assertOwned }; const safetyOverrides = resolveInstallSafetyOverrides({ ...opts, config: snapshot.config, ...resolveInstallPolicyWarningAcknowledgementCliOptions({ acknowledgeInstallPolicyWarning: opts.acknowledgeInstallPolicyWarning, allowPrompt: params.allowInstallPolicyWarningPrompt, dangerouslyForceUnsafeInstall: opts.dangerouslyForceUnsafeInstall }) }); const capabilityConsent = resolvePluginCapabilityConsentCliOptions({ acceptCapabilities: opts.acceptCapabilities, action: "install", runtime }); const acknowledgeNonClawHubSource = async (sourceClass, spec) => await confirmNonClawHubInstall({ acknowledged: opts.force, runtime, sourceClass, spec }); if (preflight.sourcePlan === null) { if (!await acknowledgeNonClawHubSource("marketplace", `${raw} from ${preflight.marketplace}`)) return runtime.exit(1); const result = await installManagedPluginSource({ request: { source: "marketplace", marketplace: preflight.marketplace, plugin: raw, mode: installMode }, ...installContext, ...capabilityConsent, safetyOverrides, logger: createPluginInstallLogger(runtime) }); if (!result.ok) { if (!isClawHubBlockedCliFailure(result)) runtime.error(result.error); return runtime.exit(1); } return; } const { sourcePlan } = preflight; if (sourcePlan.acknowledgement && !await acknowledgeNonClawHubSource(sourcePlan.acknowledgement.sourceClass, sourcePlan.acknowledgement.spec)) return runtime.exit(1); const sourceRequest = sourcePlan.request; switch (sourceRequest.source) { case "local": { const resolved = sourceRequest.path; if (sourceRequest.link) sourceRequest.successMessage = `Linked plugin path: ${shortenHomePath(resolved)}`; const fullyBlockedReason = resolveFullyBlockedConfigMutationReason(snapshot); if (fullyBlockedReason) { runtime.error(fullyBlockedReason); return runtime.exit(1); } if (snapshot.pluginMutation.mode === "blocked" || snapshot.hookMutation.mode === "blocked") { const hookProbe = await probeHookPackFromPath({ ...safetyOverrides, path: resolved, mode: installMode, inspection: "package-kind" }); if (hookProbe.ok && hookProbe.packageKind === "hook-only") { if (snapshot.hookMutation.mode === "blocked") { runtime.error(snapshot.hookMutation.reason); return runtime.exit(1); } const hookFallback = await tryInstallHookPackFromLocalPath({ ...installContext, installMode, resolvedPath: resolved, safetyOverrides, ...opts.link ? { link: true } : {}, expectedPackageKind: "hook-only" }); if (hookFallback.ok) return; runtime.error(hookFallback.error); return runtime.exit(1); } if (snapshot.pluginMutation.mode === "blocked") { runtime.error(snapshot.pluginMutation.reason); return runtime.exit(1); } } const result = await installManagedPluginSource({ request: sourceRequest, ...installContext, ...capabilityConsent, safetyOverrides, logger: createPluginInstallLogger(runtime) }); if (result.ok) return; if (isTerminalPluginInstallFailure(result.code)) { runtime.error(result.error); return runtime.exit(1); } const hookFallback = await tryInstallHookPackFromLocalPath({ ...installContext, installMode, resolvedPath: resolved, safetyOverrides, ...sourceRequest.link ? { link: true } : {} }); if (hookFallback.ok) return; runtime.error(formatPluginInstallWithHookFallbackError(result.error, hookFallback)); return runtime.exit(1); } case "marketplace": case "npm-pack": case "git": { const result = await installManagedPluginSource({ request: sourceRequest, ...installContext, ...capabilityConsent, safetyOverrides, logger: createPluginInstallLogger(runtime) }); if (!result.ok) { runtime.error(result.error); return runtime.exit(1); } return; } case "bundled": { const result = await tracePluginLifecyclePhaseAsync("install execution", () => installManagedPluginSource({ request: sourceRequest, ...installContext }), { command: "install", source: "bundled", pluginId: sourceRequest.bundledSource.pluginId }); if (!result.ok) { runtime.error(result.error); return runtime.exit(1); } return; } case "official": { const primary = sourceRequest.installSources?.[0]; if (primary?.source === "clawhub") { const result = await installManagedPluginSource({ request: sourceRequest, ...installContext, ...capabilityConsent, safetyOverrides, logger: createPluginInstallLogger(runtime) }); if (!result.ok) { runtime.error(result.error); return runtime.exit(1); } return; } if (!(await tryInstallPluginOrHookPackFromNpmSpec({ ...installContext, installMode, spec: sourceRequest.spec, pin: sourceRequest.pin, safetyOverrides, capabilityConsent, allowBundledFallback: false, expectedPluginId: sourceRequest.pluginId, expectedIntegrity: primary?.expectedIntegrity ?? sourceRequest.expectedIntegrity, trustedSourceLinkedOfficialInstall: true, officialRequest: sourceRequest })).ok) return runtime.exit(1); return; } case "clawhub": { const installFromClawHub = async (installSnapshot = snapshot, installSafetyOverrides = safetyOverrides) => { const result = await installManagedPluginSource({ ...installContext, request: { ...sourceRequest, ...opts.expectedIntegrity ? { expectedIntegrity: opts.expectedIntegrity } : {}, ...opts.expectedPluginId ? { expectedPluginId: opts.expectedPluginId } : {}, confirmInstall: resolveClawHubInstallConfirmation() }, snapshot: installSnapshot, ...capabilityConsent, safetyOverrides: installSafetyOverrides, logger: createPluginInstallLogger(runtime) }); if (!result.ok) { if (!isClawHubBlockedCliFailure(result)) runtime.error(result.error); return runtime.exit(1); } if (!result.clawhub) { runtime.error("ClawHub plugin install completed without source metadata."); return runtime.exit(1); } if (!params.clawManaged && result.clawhub.version) markClawPackageIndependentlyOwned({ kind: "plugin", source: "clawhub", ref: result.clawhub.clawhubPackage, version: result.clawhub.version }); await reportClawHubPluginInstallTelemetry({ baseUrl: result.clawhub.clawhubUrl, packageName: result.clawhub.clawhubPackage, version: result.clawhub.version }).catch(() => void 0); }; if (params.clawManaged) return await installFromClawHub(); return await withClawPackageLifecycleLease({ kind: "plugin", source: "clawhub", ref: parseClawHubPluginSpec(sourceRequest.spec)?.name ?? sourceRequest.spec }, async () => { const leasedSnapshot = await loadConfigForInstall(request).catch((error) => { runtime.error(formatErrorMessage(error)); return null; }); if (!leasedSnapshot) return runtime.exit(1); return await installFromClawHub(leasedSnapshot, resolveInstallSafetyOverrides({ ...safetyOverrides, config: leasedSnapshot.config })); }); } case "npm": if (!(await tryInstallPluginOrHookPackFromNpmSpec({ ...installContext, installMode, spec: sourceRequest.spec, pin: sourceRequest.pin, safetyOverrides, capabilityConsent, allowBundledFallback: sourceRequest.allowBundledFallback ?? false, expectedPluginId: sourceRequest.expectedPluginId, expectedIntegrity: sourceRequest.expectedIntegrity, trustedSourceLinkedOfficialInstall: sourceRequest.trustedSourceLinkedOfficialInstall })).ok) return runtime.exit(1); } } //#endregion export { runPluginInstallCommand as t };