UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

210 lines (209 loc) 8.35 kB
import { c as resolveUserPath } from "./home-dir-BPhrG-aM.js"; import { m as shortenHomePath } from "./utils-P__uGsPB.js"; import { o as parseRegistryNpmSpec } from "./npm-registry-spec-CM_p1_uq.js"; import { t as parseClawHubPluginSpec } from "./clawhub-spec-Er3Np6VI.js"; import { t as PLUGIN_INSTALL_ERROR_CODE } from "./install-types-DY_kphq4.js"; import { h as resolveArchiveKind } from "./archive-BfjFIxAJ.js"; import { t as findBundledPluginSource } from "./bundled-sources-CU4qjQGy.js"; import { a as resolveCatalogOfficialExternalInstallPlan, i as resolveOpenClawTrustedNpmPackageInstall } from "./install-provenance-W0Pf0RSv.js"; import "./install-BezM8CtS.js"; import { r as parseGitPluginSpec } from "./git-install-BNE75LQq.js"; import { c as resolveFileNpmSpecToLocalPath, o as parseNpmPackPrefixPath, s as parseNpmPrefixSpec } from "./plugins-command-helpers-X8Lgc-nc.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/plugin-install-plan.ts function sourcePlan(request, raw, sourceClass) { return { ok: true, request, ...sourceClass ? { acknowledgement: { sourceClass, spec: raw } } : {} }; } function resolvePluginInstallSourcePlan(params) { const fileSpec = resolveFileNpmSpecToLocalPath(params.raw); if (fileSpec && !fileSpec.ok) return fileSpec; const normalized = fileSpec?.ok ? fileSpec.path : params.raw; const resolved = resolveUserPath(normalized); if (fs.existsSync(resolved)) { const recordSource = resolveArchiveKind(resolved) ? "archive" : "path"; const bundled = recordSource === "path" ? findBundledPluginSource({ lookup: { kind: "localPath", value: resolved } }) : void 0; return sourcePlan({ source: "local", path: resolved, recordSource, mode: params.mode, ...bundled ? { bundledOrigin: true } : {}, ...params.link ? { link: true } : {} }, params.raw, bundled ? void 0 : recordSource === "archive" ? "local-archive" : "local-path"); } const npmPackPath = parseNpmPackPrefixPath(params.raw); if (npmPackPath !== null) return npmPackPath ? sourcePlan({ source: "npm-pack", archivePath: npmPackPath, mode: params.mode }, params.raw, "npm-pack") : { ok: false, error: "Unsupported npm-pack plugin spec: missing archive path." }; const gitPrefix = params.raw.trim().toLowerCase().startsWith("git:"); const git = parseGitPluginSpec(params.raw); if (gitPrefix) return git ? sourcePlan({ source: "git", spec: params.raw, mode: params.mode }, params.raw, "git") : { ok: false, error: `unsupported git: plugin spec: ${params.raw}` }; const clawhubPrefix = params.raw.trim().toLowerCase().startsWith("clawhub:"); const clawhub = parseClawHubPluginSpec(params.raw); if (clawhubPrefix) return clawhub ? sourcePlan({ source: "clawhub", spec: params.raw, mode: params.mode }, params.raw) : { ok: false, error: `Unsupported ClawHub plugin spec: ${params.raw}` }; const explicitNpm = parseNpmPrefixSpec(params.raw); if (explicitNpm !== null && !explicitNpm) return { ok: false, error: "Unsupported npm plugin spec: missing package." }; if (explicitNpm === null && looksLikeLocalInstallSpec(params.raw, [ ".ts", ".js", ".mjs", ".cjs", ".tgz", ".tar.gz", ".tar", ".zip" ])) return { ok: false, error: `Plugin path not found: ${resolved}` }; const npmSpec = explicitNpm ?? params.raw; const bundledPlan = explicitNpm === null ? resolveBundledInstallPlanBeforeNpm({ rawSpec: params.raw, findBundledSource: (lookup) => findBundledPluginSource({ lookup }) }) : null; if (bundledPlan) return sourcePlan({ source: "bundled", rawSpec: params.raw, bundledSource: bundledPlan.bundledSource, warning: bundledPlan.warning }, params.raw); const official = explicitNpm === null ? resolveCatalogOfficialExternalInstallPlan(params.raw) : null; if (official) return sourcePlan({ source: "official", spec: official.spec, installSources: official.installSources, expectedPluginId: official.pluginId, pluginId: official.pluginId, mode: params.mode, ...params.pin ? { pin: true } : {} }, params.raw); const trusted = resolveOpenClawTrustedNpmPackageInstall(npmSpec); return sourcePlan({ source: "npm", spec: npmSpec, mode: params.mode, ...params.pin ? { pin: true } : {}, ...explicitNpm === null ? { allowBundledFallback: true } : {}, ...trusted ? { expectedPluginId: trusted.pluginId, ...trusted.expectedIntegrity ? { expectedIntegrity: trusted.expectedIntegrity } : {}, trustedSourceLinkedOfficialInstall: true } : {} }, params.raw, trusted ? void 0 : "npm"); } function isBareNpmPackageName(spec) { const trimmed = spec.trim(); return /^[a-z0-9][a-z0-9-._~]*$/.test(trimmed); } function isSourceCheckoutBundledPath(localPath) { const extensionsDir = path.dirname(path.resolve(localPath)); if (path.basename(extensionsDir) !== "extensions") return false; const extensionsParent = path.dirname(extensionsDir); const packageRoot = ["dist", "dist-runtime"].includes(path.basename(extensionsParent)) ? path.dirname(extensionsParent) : extensionsParent; try { return JSON.parse(fs.readFileSync(path.join(packageRoot, "package.json"), "utf8")).name === "openclaw" && fs.existsSync(path.join(packageRoot, ".git")) && fs.existsSync(path.join(packageRoot, "pnpm-workspace.yaml")) && fs.existsSync(path.join(packageRoot, "src")) && fs.existsSync(path.join(packageRoot, "extensions")); } catch { return false; } } function resolveBundledInstallPlanForCatalogEntry(params) { const pluginId = params.pluginId.trim(); const npmSpec = params.npmSpec.trim(); if (!pluginId || !npmSpec) return null; const bundledBySpec = params.findBundledSource({ kind: "npmSpec", value: npmSpec }); if (bundledBySpec?.pluginId === pluginId) return { bundledSource: bundledBySpec }; const bundledById = params.findBundledSource({ kind: "pluginId", value: pluginId }); if (bundledById?.pluginId !== pluginId) return null; if (bundledById.npmSpec && bundledById.npmSpec !== npmSpec) return null; return { bundledSource: bundledById }; } function resolveBundledInstallPlanBeforeNpm(params) { const rawSpec = params.rawSpec.trim(); if (!rawSpec) return null; if (isBareNpmPackageName(rawSpec)) { const bundledSource = params.findBundledSource({ kind: "pluginId", value: rawSpec }); if (!bundledSource) return null; return { bundledSource, warning: `Using bundled plugin "${bundledSource.pluginId}" from ${shortenHomePath(bundledSource.localPath)} for bare install spec "${rawSpec}". To install an npm package with the same name, use a scoped package name (for example @scope/${rawSpec}).` }; } const parsedNpmSpec = parseRegistryNpmSpec(rawSpec); if (!parsedNpmSpec) return null; const bundledSource = params.findBundledSource({ kind: "npmSpec", value: rawSpec }) ?? params.findBundledSource({ kind: "npmSpec", value: parsedNpmSpec.name }); if (!bundledSource) return null; if (!isBareNpmPackageName(params.rawSpec) && isSourceCheckoutBundledPath(bundledSource.localPath)) return null; return { bundledSource, warning: `Using bundled plugin "${bundledSource.pluginId}" from ${shortenHomePath(bundledSource.localPath)} for npm install spec "${rawSpec}" because this plugin ships with the current OpenClaw build. To force an external npm override, use npm:${rawSpec}.` }; } function resolveBundledInstallPlanForNpmFailure(params) { if (params.code !== PLUGIN_INSTALL_ERROR_CODE.NPM_PACKAGE_NOT_FOUND) return null; const bundledSource = params.findBundledSource({ kind: "npmSpec", value: params.rawSpec }); if (!bundledSource) return null; if (!isBareNpmPackageName(params.rawSpec) && isSourceCheckoutBundledPath(bundledSource.localPath)) return null; return { bundledSource, warning: `npm package unavailable for ${params.rawSpec}; using bundled plugin at ${shortenHomePath(bundledSource.localPath)}.` }; } //#endregion export { resolveBundledInstallPlanForNpmFailure as n, resolvePluginInstallSourcePlan as r, resolveBundledInstallPlanForCatalogEntry as t };