@@ -112,6 +112,7 @@ import {
112112 getCachedPluginSourceModuleLoader ,
113113 type PluginModuleLoaderCache ,
114114} from "./plugin-module-loader-cache.js" ;
115+ import type { PluginOrigin } from "./plugin-origin.types.js" ;
115116import {
116117 createPluginIdScopeSet ,
117118 hasExplicitPluginIdScope ,
@@ -180,6 +181,11 @@ export type PluginLoadOptions = {
180181 * via package metadata because their setup entry covers the pre-listen startup surface.
181182 */
182183 preferSetupRuntimeForChannelPlugins ?: boolean ;
184+ /**
185+ * For hot startup paths, prefer bundled plugin JS artifacts over source TS
186+ * entrypoints when both are present in a source checkout.
187+ */
188+ preferBuiltPluginArtifacts ?: boolean ;
183189 toolDiscovery ?: boolean ;
184190 activate ?: boolean ;
185191 loadModules ?: boolean ;
@@ -275,6 +281,7 @@ function createPluginCandidatesFromManifestRegistry(
275281 idHint : record . id ,
276282 rootDir : record . rootDir ,
277283 source : record . source ,
284+ ...( record . setupSource !== undefined ? { setupSource : record . setupSource } : { } ) ,
278285 origin : record . origin ,
279286 ...( record . workspaceDir !== undefined ? { workspaceDir : record . workspaceDir } : { } ) ,
280287 ...( record . format !== undefined ? { format : record . format } : { } ) ,
@@ -517,6 +524,52 @@ function resolveCanonicalDistRuntimeSource(source: string): string {
517524 return fs . existsSync ( candidate ) ? candidate : source ;
518525}
519526
527+ function rewriteBundledRuntimeArtifactRelativePath ( relativePath : string ) : string {
528+ return relativePath . replace ( / \. [ ^ . ] + $ / u, ".js" ) ;
529+ }
530+
531+ function resolvePreferredBuiltBundledRuntimeArtifact ( params : {
532+ source : string ;
533+ rootDir : string ;
534+ origin : PluginOrigin ;
535+ preferBuiltPluginArtifacts : boolean ;
536+ } ) : { source : string ; rootDir : string } {
537+ const rootDir = safeRealpathOrResolve ( params . rootDir ) ;
538+ const source = safeRealpathOrResolve ( params . source ) ;
539+ if ( ! params . preferBuiltPluginArtifacts || params . origin !== "bundled" ) {
540+ return { source, rootDir } ;
541+ }
542+ const extensionsDir = path . dirname ( rootDir ) ;
543+ if ( path . basename ( extensionsDir ) !== "extensions" ) {
544+ return { source, rootDir } ;
545+ }
546+ const packageRoot = path . dirname ( extensionsDir ) ;
547+ if ( path . basename ( packageRoot ) === "dist" || path . basename ( packageRoot ) === "dist-runtime" ) {
548+ return { source, rootDir } ;
549+ }
550+ const relativeSource = path . relative ( rootDir , source ) ;
551+ if ( relativeSource === "" || relativeSource . startsWith ( ".." ) || path . isAbsolute ( relativeSource ) ) {
552+ return { source, rootDir } ;
553+ }
554+ const artifactRelativePath = rewriteBundledRuntimeArtifactRelativePath ( relativeSource ) ;
555+ for ( const artifactRootName of [ "dist-runtime" , "dist" ] as const ) {
556+ const artifactRoot = path . join (
557+ packageRoot ,
558+ artifactRootName ,
559+ "extensions" ,
560+ path . basename ( rootDir ) ,
561+ ) ;
562+ const artifactSource = path . join ( artifactRoot , artifactRelativePath ) ;
563+ if ( fs . existsSync ( artifactSource ) ) {
564+ return {
565+ source : safeRealpathOrResolve ( artifactSource ) ,
566+ rootDir : safeRealpathOrResolve ( artifactRoot ) ,
567+ } ;
568+ }
569+ }
570+ return { source, rootDir } ;
571+ }
572+
520573export const __testing = {
521574 buildPluginLoaderJitiOptions,
522575 buildPluginLoaderAliasMap,
@@ -682,6 +735,7 @@ function buildCacheKey(params: {
682735 forceSetupOnlyChannelPlugins ?: boolean ;
683736 requireSetupEntryForSetupOnlyChannelPlugins ?: boolean ;
684737 preferSetupRuntimeForChannelPlugins ?: boolean ;
738+ preferBuiltPluginArtifacts ?: boolean ;
685739 toolDiscovery ?: boolean ;
686740 loadModules ?: boolean ;
687741 runtimeSubagentMode ?: "default" | "explicit" | "gateway-bindable" ;
@@ -722,6 +776,8 @@ function buildCacheKey(params: {
722776 : "allow-full-fallback" ;
723777 const startupChannelMode =
724778 params . preferSetupRuntimeForChannelPlugins === true ? "prefer-setup" : "full" ;
779+ const bundledArtifactMode =
780+ params . preferBuiltPluginArtifacts === true ? "prefer-built-artifacts" : "source-default" ;
725781 const moduleLoadMode = params . loadModules === false ? "manifest-only" : "load-modules" ;
726782 const discoveryMode = params . toolDiscovery === true ? "tool-discovery" : "default-discovery" ;
727783 const runtimeSubagentMode = params . runtimeSubagentMode ?? "default" ;
@@ -734,7 +790,7 @@ function buildCacheKey(params: {
734790 installs,
735791 loadPaths,
736792 activationMetadataKey : params . activationMetadataKey ?? "" ,
737- } ) } ::${ scopeKey } ::${ setupOnlyKey } ::${ setupOnlyModeKey } ::${ setupOnlyRequirementKey } ::${ startupChannelMode } ::${ moduleLoadMode } ::${ discoveryMode } ::${ runtimeSubagentMode } ::${ params . pluginSdkResolution ?? "auto" } ::${ gatewayMethodsKey } ::${ activationMode } `;
793+ } ) } ::${ scopeKey } ::${ setupOnlyKey } ::${ setupOnlyModeKey } ::${ setupOnlyRequirementKey } ::${ startupChannelMode } ::${ bundledArtifactMode } :: ${ moduleLoadMode } ::${ discoveryMode } ::${ runtimeSubagentMode } ::${ params . pluginSdkResolution ?? "auto" } ::${ gatewayMethodsKey } ::${ activationMode } `;
738794}
739795
740796function matchesScopedPluginRequest ( params : {
@@ -812,6 +868,7 @@ function hasExplicitCompatibilityInputs(options: PluginLoadOptions): boolean {
812868 options . forceSetupOnlyChannelPlugins === true ||
813869 options . requireSetupEntryForSetupOnlyChannelPlugins === true ||
814870 options . preferSetupRuntimeForChannelPlugins === true ||
871+ options . preferBuiltPluginArtifacts === true ||
815872 options . loadModules === false
816873 ) ;
817874}
@@ -1011,6 +1068,7 @@ function resolvePluginLoadCacheContext(options: PluginLoadOptions = {}) {
10111068 const requireSetupEntryForSetupOnlyChannelPlugins =
10121069 options . requireSetupEntryForSetupOnlyChannelPlugins === true ;
10131070 const preferSetupRuntimeForChannelPlugins = options . preferSetupRuntimeForChannelPlugins === true ;
1071+ const preferBuiltPluginArtifacts = options . preferBuiltPluginArtifacts === true ;
10141072 const runtimeSubagentMode = resolveRuntimeSubagentMode ( options . runtimeOptions ) ;
10151073 const coreGatewayMethodNames = resolveCoreGatewayMethodNames ( options ) ;
10161074 const installRecords = {
@@ -1031,6 +1089,7 @@ function resolvePluginLoadCacheContext(options: PluginLoadOptions = {}) {
10311089 forceSetupOnlyChannelPlugins,
10321090 requireSetupEntryForSetupOnlyChannelPlugins,
10331091 preferSetupRuntimeForChannelPlugins,
1092+ preferBuiltPluginArtifacts,
10341093 toolDiscovery : options . toolDiscovery ,
10351094 loadModules : options . loadModules ,
10361095 runtimeSubagentMode,
@@ -1050,6 +1109,7 @@ function resolvePluginLoadCacheContext(options: PluginLoadOptions = {}) {
10501109 forceSetupOnlyChannelPlugins,
10511110 requireSetupEntryForSetupOnlyChannelPlugins,
10521111 preferSetupRuntimeForChannelPlugins,
1112+ preferBuiltPluginArtifacts,
10531113 shouldActivate : options . activate !== false ,
10541114 shouldLoadModules : options . loadModules !== false ,
10551115 runtimeSubagentMode,
@@ -1375,6 +1435,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
13751435 forceSetupOnlyChannelPlugins,
13761436 requireSetupEntryForSetupOnlyChannelPlugins,
13771437 preferSetupRuntimeForChannelPlugins,
1438+ preferBuiltPluginArtifacts,
13781439 shouldActivate,
13791440 shouldLoadModules,
13801441 cacheKey,
@@ -1697,13 +1758,20 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
16971758 } ) ;
16981759 } ;
16991760 const pluginRoot = safeRealpathOrResolve ( candidate . rootDir ) ;
1700- let runtimePluginRoot = pluginRoot ;
1701- let runtimeCandidateSource =
1702- candidate . origin === "bundled" ? safeRealpathOrResolve ( candidate . source ) : candidate . source ;
1703- let runtimeSetupSource =
1704- candidate . origin === "bundled" && manifestRecord . setupSource
1705- ? safeRealpathOrResolve ( manifestRecord . setupSource )
1706- : manifestRecord . setupSource ;
1761+ const runtimeCandidateEntry = resolvePreferredBuiltBundledRuntimeArtifact ( {
1762+ source : candidate . source ,
1763+ rootDir : pluginRoot ,
1764+ origin : candidate . origin ,
1765+ preferBuiltPluginArtifacts,
1766+ } ) ;
1767+ const runtimeSetupEntry = manifestRecord . setupSource
1768+ ? resolvePreferredBuiltBundledRuntimeArtifact ( {
1769+ source : manifestRecord . setupSource ,
1770+ rootDir : pluginRoot ,
1771+ origin : candidate . origin ,
1772+ preferBuiltPluginArtifacts,
1773+ } )
1774+ : undefined ;
17071775
17081776 const scopedSetupOnlyChannelPluginRequested =
17091777 includeSetupOnlyChannelPlugins &&
@@ -1883,12 +1951,12 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
18831951 continue ;
18841952 }
18851953
1886- const loadSource =
1887- registrationPlan . loadSetupEntry && runtimeSetupSource
1888- ? runtimeSetupSource
1889- : runtimeCandidateSource ;
1890- const moduleLoadSource = resolveCanonicalDistRuntimeSource ( loadSource ) ;
1891- const moduleRoot = resolveCanonicalDistRuntimeSource ( runtimePluginRoot ) ;
1954+ const loadEntry =
1955+ registrationPlan . loadSetupEntry && runtimeSetupEntry
1956+ ? runtimeSetupEntry
1957+ : runtimeCandidateEntry ;
1958+ const moduleLoadSource = resolveCanonicalDistRuntimeSource ( loadEntry . source ) ;
1959+ const moduleRoot = resolveCanonicalDistRuntimeSource ( loadEntry . rootDir ) ;
18921960 const opened = openBoundaryFileSync ( {
18931961 absolutePath : moduleLoadSource ,
18941962 rootPath : moduleRoot ,
@@ -1972,11 +2040,17 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
19722040 if (
19732041 registrationPlan . loadSetupRuntimeEntry &&
19742042 setupRegistration . usesBundledSetupContract &&
1975- runtimeCandidateSource !== safeSource
2043+ resolveCanonicalDistRuntimeSource ( runtimeCandidateEntry . source ) !== safeSource
19762044 ) {
2045+ const runtimeModuleSource = resolveCanonicalDistRuntimeSource (
2046+ runtimeCandidateEntry . source ,
2047+ ) ;
2048+ const runtimeModuleRoot = resolveCanonicalDistRuntimeSource (
2049+ runtimeCandidateEntry . rootDir ,
2050+ ) ;
19772051 const runtimeOpened = openBoundaryFileSync ( {
1978- absolutePath : runtimeCandidateSource ,
1979- rootPath : runtimePluginRoot ,
2052+ absolutePath : runtimeModuleSource ,
2053+ rootPath : runtimeModuleRoot ,
19802054 boundaryLabel : "plugin root" ,
19812055 rejectHardlinks : candidate . origin !== "bundled" ,
19822056 skipLexicalRootCheck : true ,
0 commit comments