
























@@ -1,7 +1,6 @@
11import fs from "node:fs";
22import path from "node:path";
3-import { matchBoundaryFileOpenFailure, openBoundaryFileSync } from "../infra/boundary-file-read.js";
4-import { resolveBoundaryPathSync } from "../infra/boundary-path.js";
3+import { openBoundaryFileSync } from "../infra/boundary-file-read.js";
54import {
65normalizeLowercaseStringOrEmpty,
76normalizeOptionalString,
@@ -19,7 +18,10 @@ import {
1918type OpenClawPackageManifest,
2019type PackageManifest,
2120} from "./manifest.js";
22-import { listBuiltRuntimeEntryCandidates } from "./package-entrypoints.js";
21+import {
22+resolvePackageRuntimeExtensionSources,
23+resolvePackageSetupSource,
24+} from "./package-entry-resolution.js";
2325import { formatPosixMode, isPathInside, safeRealpathSync, safeStatSync } from "./path-safety.js";
2426import type { PluginOrigin } from "./plugin-origin.types.js";
2527import { resolvePluginCacheInputs, resolvePluginSourceRoots } from "./roots.js";
@@ -555,245 +557,6 @@ function discoverBundleInRoot(params: {
555557return "added";
556558}
557559558-function resolvePackageEntrySource(params: {
559-packageDir: string;
560-entryPath: string;
561-sourceLabel: string;
562-diagnostics: PluginDiagnostic[];
563-rejectHardlinks?: boolean;
564-}): string | null {
565-const source = path.resolve(params.packageDir, params.entryPath);
566-const rejectHardlinks = params.rejectHardlinks ?? true;
567-const candidates = [source];
568-const openCandidate = (absolutePath: string): string | null => {
569-const opened = openBoundaryFileSync({
570- absolutePath,
571-rootPath: params.packageDir,
572-boundaryLabel: "plugin package directory",
573- rejectHardlinks,
574-});
575-if (!opened.ok) {
576-return matchBoundaryFileOpenFailure(opened, {
577-path: () => null,
578-io: () => {
579-params.diagnostics.push({
580-level: "warn",
581-message: `extension entry unreadable (I/O error): ${params.entryPath}`,
582-source: params.sourceLabel,
583-});
584-return null;
585-},
586-fallback: () => {
587-params.diagnostics.push({
588-level: "error",
589-message: `extension entry escapes package directory: ${params.entryPath}`,
590-source: params.sourceLabel,
591-});
592-return null;
593-},
594-});
595-}
596-const safeSource = opened.path;
597-fs.closeSync(opened.fd);
598-return safeSource;
599-};
600-if (!rejectHardlinks) {
601-const builtCandidate = source.replace(/\.[^.]+$/u, ".js");
602-if (builtCandidate !== source) {
603-candidates.push(builtCandidate);
604-}
605-}
606-607-for (const candidate of new Set(candidates)) {
608-if (!fs.existsSync(candidate)) {
609-continue;
610-}
611-return openCandidate(candidate);
612-}
613-614-return openCandidate(source);
615-}
616-617-function shouldInferBuiltRuntimeEntry(origin: PluginOrigin): boolean {
618-return origin === "config" || origin === "global";
619-}
620-621-function resolveSafePackageEntry(params: {
622-packageDir: string;
623-entryPath: string;
624-sourceLabel: string;
625-diagnostics: PluginDiagnostic[];
626-rejectHardlinks?: boolean;
627-}): { relativePath: string; existingSource?: string } | null {
628-const absolutePath = path.resolve(params.packageDir, params.entryPath);
629-if (fs.existsSync(absolutePath)) {
630-const existingSource = resolvePackageEntrySource({
631-packageDir: params.packageDir,
632-entryPath: params.entryPath,
633-sourceLabel: params.sourceLabel,
634-diagnostics: params.diagnostics,
635-rejectHardlinks: params.rejectHardlinks,
636-});
637-if (!existingSource) {
638-return null;
639-}
640-return {
641-relativePath: path.relative(params.packageDir, absolutePath).replace(/\\/g, "/"),
642- existingSource,
643-};
644-}
645-646-try {
647-resolveBoundaryPathSync({
648- absolutePath,
649-rootPath: params.packageDir,
650-boundaryLabel: "plugin package directory",
651-});
652-} catch {
653-params.diagnostics.push({
654-level: "error",
655-message: `extension entry escapes package directory: ${params.entryPath}`,
656-source: params.sourceLabel,
657-});
658-return null;
659-}
660-return { relativePath: path.relative(params.packageDir, absolutePath).replace(/\\/g, "/") };
661-}
662-663-function resolveExistingPackageEntrySource(params: {
664-packageDir: string;
665-entryPath: string;
666-sourceLabel: string;
667-diagnostics: PluginDiagnostic[];
668-rejectHardlinks?: boolean;
669-}): string | null {
670-const source = path.resolve(params.packageDir, params.entryPath);
671-if (!fs.existsSync(source)) {
672-return null;
673-}
674-return resolvePackageEntrySource(params);
675-}
676-677-function normalizePackageManifestStringList(value: unknown): string[] {
678-if (!Array.isArray(value)) {
679-return [];
680-}
681-return value.map((entry) => normalizeOptionalString(entry) ?? "").filter(Boolean);
682-}
683-684-function resolvePackageRuntimeEntrySource(params: {
685-packageDir: string;
686-entryPath: string;
687-runtimeEntryPath?: string;
688-origin: PluginOrigin;
689-sourceLabel: string;
690-diagnostics: PluginDiagnostic[];
691-rejectHardlinks?: boolean;
692-}): string | null {
693-const safeEntry = resolveSafePackageEntry({
694-packageDir: params.packageDir,
695-entryPath: params.entryPath,
696-sourceLabel: params.sourceLabel,
697-diagnostics: params.diagnostics,
698-rejectHardlinks: params.rejectHardlinks,
699-});
700-if (!safeEntry) {
701-return null;
702-}
703-704-if (params.runtimeEntryPath) {
705-const runtimeSource = resolvePackageEntrySource({
706-packageDir: params.packageDir,
707-entryPath: params.runtimeEntryPath,
708-sourceLabel: params.sourceLabel,
709-diagnostics: params.diagnostics,
710-rejectHardlinks: params.rejectHardlinks,
711-});
712-if (runtimeSource) {
713-return runtimeSource;
714-}
715-}
716-717-if (shouldInferBuiltRuntimeEntry(params.origin)) {
718-for (const candidate of listBuiltRuntimeEntryCandidates(safeEntry.relativePath)) {
719-const runtimeSource = resolveExistingPackageEntrySource({
720-packageDir: params.packageDir,
721-entryPath: candidate,
722-sourceLabel: params.sourceLabel,
723-diagnostics: params.diagnostics,
724-rejectHardlinks: params.rejectHardlinks,
725-});
726-if (runtimeSource) {
727-return runtimeSource;
728-}
729-}
730-}
731-732-if (safeEntry.existingSource) {
733-return safeEntry.existingSource;
734-}
735-736-return resolvePackageEntrySource({
737-packageDir: params.packageDir,
738-entryPath: params.entryPath,
739-sourceLabel: params.sourceLabel,
740-diagnostics: params.diagnostics,
741-rejectHardlinks: params.rejectHardlinks,
742-});
743-}
744-745-function resolvePackageSetupSource(params: {
746-packageDir: string;
747-manifest: PackageManifest | null;
748-origin: PluginOrigin;
749-sourceLabel: string;
750-diagnostics: PluginDiagnostic[];
751-rejectHardlinks?: boolean;
752-}): string | null {
753-const packageManifest = getPackageManifestMetadata(params.manifest ?? undefined);
754-const setupEntryPath = normalizeOptionalString(packageManifest?.setupEntry);
755-if (!setupEntryPath) {
756-return null;
757-}
758-return resolvePackageRuntimeEntrySource({
759-packageDir: params.packageDir,
760-entryPath: setupEntryPath,
761-runtimeEntryPath: normalizeOptionalString(packageManifest?.runtimeSetupEntry),
762-origin: params.origin,
763-sourceLabel: params.sourceLabel,
764-diagnostics: params.diagnostics,
765-rejectHardlinks: params.rejectHardlinks,
766-});
767-}
768-769-function resolvePackageRuntimeExtensionEntries(params: {
770-packageDir: string;
771-manifest: PackageManifest | null;
772-extensions: readonly string[];
773-origin: PluginOrigin;
774-sourceLabel: string;
775-diagnostics: PluginDiagnostic[];
776-rejectHardlinks?: boolean;
777-}): string[] {
778-const packageManifest = getPackageManifestMetadata(params.manifest ?? undefined);
779-const runtimeExtensions = normalizePackageManifestStringList(packageManifest?.runtimeExtensions);
780-return params.extensions.flatMap((entryPath, index) => {
781-const source = resolvePackageRuntimeEntrySource({
782-packageDir: params.packageDir,
783- entryPath,
784-runtimeEntryPath:
785-runtimeExtensions.length === params.extensions.length
786- ? runtimeExtensions[index]
787- : undefined,
788-origin: params.origin,
789-sourceLabel: params.sourceLabel,
790-diagnostics: params.diagnostics,
791-rejectHardlinks: params.rejectHardlinks,
792-});
793-return source ? [source] : [];
794-});
795-}
796-797560function discoverInDirectory(params: {
798561dir: string;
799562origin: PluginOrigin;
@@ -871,7 +634,7 @@ function discoverInDirectory(params: {
871634});
872635873636if (extensions.length > 0) {
874-const resolvedRuntimeSources = resolvePackageRuntimeExtensionEntries({
637+const resolvedRuntimeSources = resolvePackageRuntimeExtensionSources({
875638packageDir: fullPath,
876639 manifest,
877640 extensions,
@@ -1007,7 +770,7 @@ function discoverFromPath(params: {
1007770});
10087711009772if (extensions.length > 0) {
1010-const resolvedRuntimeSources = resolvePackageRuntimeExtensionEntries({
773+const resolvedRuntimeSources = resolvePackageRuntimeExtensionSources({
1011774packageDir: resolved,
1012775 manifest,
1013776 extensions,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。