From 1ea8fc0db6bc539dfb6a60a95f8c98666f9d53b9 Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Mon, 16 Mar 2026 00:24:19 +0000 Subject: [PATCH] Extension host: organize foundation modules --- src/agents/.DS_Store | Bin 0 -> 8196 bytes src/agents/model-selection.ts | 19 +- src/agents/pi-embedded-runner/.DS_Store | Bin 0 -> 6148 bytes src/agents/skills/plugin-skills.ts | 2 +- src/auto-reply/.DS_Store | Bin 0 -> 6148 bytes src/auto-reply/reply/.DS_Store | Bin 0 -> 8196 bytes src/auto-reply/reply/commands-plugin.ts | 2 +- src/auto-reply/status.ts | 4 +- src/channels/.DS_Store | Bin 0 -> 6148 bytes src/channels/dock.ts | 4 +- src/channels/plugins/.DS_Store | Bin 0 -> 6148 bytes src/channels/plugins/catalog.ts | 2 +- src/channels/plugins/index.ts | 4 +- src/channels/plugins/plugins-core.test.ts | 2 +- src/channels/plugins/registry-loader.ts | 4 +- src/channels/registry.ts | 4 +- src/cli/.DS_Store | Bin 0 -> 8196 bytes src/cli/plugin-registry.ts | 2 +- src/commands/.DS_Store | Bin 0 -> 8196 bytes .../auth-choice.apply.plugin-provider.test.ts | 2 +- .../auth-choice.apply.plugin-provider.ts | 2 +- src/commands/model-picker.ts | 2 +- .../onboard-non-interactive/.DS_Store | Bin 0 -> 6148 bytes src/commands/provider-auth-helpers.ts | 2 +- src/config/.DS_Store | Bin 0 -> 6148 bytes src/config/doc-baseline.ts | 2 +- src/config/plugin-auto-enable.ts | 2 +- src/config/resolved-extension-validation.ts | 4 +- src/config/validation.ts | 2 +- src/extension-host/.DS_Store | Bin 0 -> 8196 bytes src/extension-host/activation.test.ts | 2 +- src/extension-host/activation.ts | 2 +- .../{ => activation}/loader-bootstrap.test.ts | 2 +- .../{ => activation}/loader-bootstrap.ts | 18 +- .../{ => activation}/loader-cache.test.ts | 2 +- .../{ => activation}/loader-cache.ts | 10 +- .../{ => activation}/loader-execution.test.ts | 0 .../{ => activation}/loader-execution.ts | 22 +- .../{ => activation}/loader-finalize.test.ts | 4 +- .../{ => activation}/loader-finalize.ts | 8 +- .../{ => activation}/loader-flow.test.ts | 8 +- .../{ => activation}/loader-flow.ts | 34 +- .../loader-host-state.test.ts | 0 .../{ => activation}/loader-host-state.ts | 0 .../{ => activation}/loader-import.test.ts | 0 .../{ => activation}/loader-import.ts | 4 +- .../loader-module-loader.test.ts | 0 .../{ => activation}/loader-module-loader.ts | 4 +- .../{ => activation}/loader-orchestrator.ts | 17 +- .../{ => activation}/loader-pipeline.test.ts | 0 .../{ => activation}/loader-pipeline.ts | 10 +- .../{ => activation}/loader-preflight.test.ts | 0 .../{ => activation}/loader-preflight.ts | 8 +- .../{ => activation}/loader-records.test.ts | 8 +- .../{ => activation}/loader-records.ts | 12 +- .../{ => activation}/loader-register.test.ts | 4 +- .../{ => activation}/loader-register.ts | 18 +- .../{ => activation}/loader-run.test.ts | 2 +- .../{ => activation}/loader-run.ts | 23 +- .../loader-runtime-proxy.test.ts | 0 .../{ => activation}/loader-runtime-proxy.ts | 2 +- .../{ => activation}/loader-runtime.test.ts | 2 +- .../{ => activation}/loader-runtime.ts | 14 +- .../{ => activation}/loader-session.test.ts | 6 +- .../{ => activation}/loader-session.ts | 29 +- .../{ => activation}/loader-state.test.ts | 4 +- .../{ => activation}/loader-state.ts | 2 +- .../{ => compat}/hook-compat.test.ts | 0 .../{ => compat}/hook-compat.ts | 6 +- .../{ => compat}/loader-compat.ts | 2 +- .../{ => compat}/plugin-api.test.ts | 2 +- src/extension-host/{ => compat}/plugin-api.ts | 14 +- .../plugin-registry-compat.test.ts | 4 +- .../{ => compat}/plugin-registry-compat.ts | 12 +- .../plugin-registry-registrations.test.ts | 2 +- .../plugin-registry-registrations.ts | 30 +- .../{ => compat}/plugin-registry.test.ts | 4 +- .../{ => compat}/plugin-registry.ts | 28 +- .../{ => contributions}/cli-lifecycle.test.ts | 4 +- .../{ => contributions}/cli-lifecycle.ts | 6 +- .../command-runtime.test.ts | 0 .../{ => contributions}/command-runtime.ts | 12 +- .../gateway-methods.test.ts | 2 +- .../{ => contributions}/gateway-methods.ts | 6 +- .../{ => contributions}/provider-auth-flow.ts | 26 +- .../{ => contributions}/provider-auth.test.ts | 2 +- .../{ => contributions}/provider-auth.ts | 6 +- .../provider-discovery.test.ts | 4 +- .../{ => contributions}/provider-discovery.ts | 6 +- .../provider-model-selection.ts | 12 +- .../provider-runtime.test.ts | 2 +- .../contributions/provider-runtime.ts | 22 + .../provider-wizard.test.ts | 2 +- .../{ => contributions}/provider-wizard.ts | 4 +- .../registry-writes.test.ts | 2 +- .../{ => contributions}/registry-writes.ts | 8 +- .../runtime-registrations.test.ts | 12 +- .../runtime-registrations.ts | 33 +- .../runtime-registry.test.ts | 2 +- .../{ => contributions}/runtime-registry.ts | 4 +- .../service-lifecycle.test.ts | 8 +- .../{ => contributions}/service-lifecycle.ts | 10 +- .../{ => contributions}/tool-runtime.test.ts | 4 +- .../{ => contributions}/tool-runtime.ts | 23 +- src/extension-host/cutover-inventory.md | 158 +-- .../{ => manifests}/manifest-registry.ts | 4 +- .../{ => manifests}/resolved-registry.ts | 6 +- .../{ => manifests}/schema.test.ts | 0 src/extension-host/{ => manifests}/schema.ts | 4 +- .../loader-activation-policy.test.ts | 8 +- .../{ => policy}/loader-activation-policy.ts | 31 +- .../loader-discovery-policy.test.ts | 0 .../{ => policy}/loader-discovery-policy.ts | 2 +- .../loader-finalization-policy.test.ts | 2 +- .../loader-finalization-policy.ts | 4 +- .../{ => policy}/loader-policy.test.ts | 2 +- .../{ => policy}/loader-policy.ts | 16 +- .../{ => policy}/loader-provenance.test.ts | 0 .../{ => policy}/loader-provenance.ts | 4 +- src/extension-host/provider-runtime.ts | 12 - .../{ => static}/active-registry.test.ts | 2 +- .../{ => static}/active-registry.ts | 2 +- src/gateway/.DS_Store | Bin 0 -> 6148 bytes src/gateway/protocol/.DS_Store | Bin 0 -> 6148 bytes src/gateway/server-plugins.ts | 2 +- src/gateway/server.impl.ts | 2 +- src/gateway/server/.DS_Store | Bin 0 -> 6148 bytes src/gateway/server/plugins-http.ts | 2 +- .../server/plugins-http/route-match.ts | 2 +- src/plugins/.DS_Store | Bin 0 -> 10244 bytes src/plugins/cli.ts | 2 +- src/plugins/discovery.ts | 11 +- src/plugins/http-registry.ts | 4 +- src/plugins/install.ts | 8 +- src/plugins/loader.ts | 920 +----------------- src/plugins/manifest-registry.ts | 35 +- src/plugins/provider-discovery.ts | 6 +- src/plugins/provider-wizard.ts | 4 +- src/plugins/providers.ts | 2 +- src/plugins/registry.ts | 557 +---------- src/plugins/runtime.ts | 2 +- src/plugins/services.ts | 5 +- src/plugins/tools.ts | 2 +- src/utils/message-channel.test.ts | 2 +- src/utils/message-channel.ts | 4 +- 145 files changed, 557 insertions(+), 1946 deletions(-) create mode 100644 src/agents/.DS_Store create mode 100644 src/agents/pi-embedded-runner/.DS_Store create mode 100644 src/auto-reply/.DS_Store create mode 100644 src/auto-reply/reply/.DS_Store create mode 100644 src/channels/.DS_Store create mode 100644 src/channels/plugins/.DS_Store create mode 100644 src/cli/.DS_Store create mode 100644 src/commands/.DS_Store create mode 100644 src/commands/onboard-non-interactive/.DS_Store create mode 100644 src/config/.DS_Store create mode 100644 src/extension-host/.DS_Store rename src/extension-host/{ => activation}/loader-bootstrap.test.ts (97%) rename src/extension-host/{ => activation}/loader-bootstrap.ts (85%) rename src/extension-host/{ => activation}/loader-cache.test.ts (97%) rename src/extension-host/{ => activation}/loader-cache.ts (86%) rename src/extension-host/{ => activation}/loader-execution.test.ts (100%) rename src/extension-host/{ => activation}/loader-execution.ts (83%) rename src/extension-host/{ => activation}/loader-finalize.test.ts (95%) rename src/extension-host/{ => activation}/loader-finalize.ts (79%) rename src/extension-host/{ => activation}/loader-flow.test.ts (95%) rename src/extension-host/{ => activation}/loader-flow.ts (90%) rename src/extension-host/{ => activation}/loader-host-state.test.ts (100%) rename src/extension-host/{ => activation}/loader-host-state.ts (100%) rename src/extension-host/{ => activation}/loader-import.test.ts (100%) rename src/extension-host/{ => activation}/loader-import.ts (90%) rename src/extension-host/{ => activation}/loader-module-loader.test.ts (100%) rename src/extension-host/{ => activation}/loader-module-loader.ts (93%) rename src/extension-host/{ => activation}/loader-orchestrator.ts (73%) rename src/extension-host/{ => activation}/loader-pipeline.test.ts (100%) rename src/extension-host/{ => activation}/loader-pipeline.ts (84%) rename src/extension-host/{ => activation}/loader-preflight.test.ts (100%) rename src/extension-host/{ => activation}/loader-preflight.ts (93%) rename src/extension-host/{ => activation}/loader-records.test.ts (93%) rename src/extension-host/{ => activation}/loader-records.ts (87%) rename src/extension-host/{ => activation}/loader-register.test.ts (96%) rename src/extension-host/{ => activation}/loader-register.ts (90%) rename src/extension-host/{ => activation}/loader-run.test.ts (95%) rename src/extension-host/{ => activation}/loader-run.ts (78%) rename src/extension-host/{ => activation}/loader-runtime-proxy.test.ts (100%) rename src/extension-host/{ => activation}/loader-runtime-proxy.ts (94%) rename src/extension-host/{ => activation}/loader-runtime.test.ts (97%) rename src/extension-host/{ => activation}/loader-runtime.ts (91%) rename src/extension-host/{ => activation}/loader-session.test.ts (94%) rename src/extension-host/{ => activation}/loader-session.ts (83%) rename src/extension-host/{ => activation}/loader-state.test.ts (96%) rename src/extension-host/{ => activation}/loader-state.ts (98%) rename src/extension-host/{ => compat}/hook-compat.test.ts (100%) rename src/extension-host/{ => compat}/hook-compat.ts (95%) rename src/extension-host/{ => compat}/loader-compat.ts (97%) rename src/extension-host/{ => compat}/plugin-api.test.ts (98%) rename src/extension-host/{ => compat}/plugin-api.ts (84%) rename src/extension-host/{ => compat}/plugin-registry-compat.test.ts (96%) rename src/extension-host/{ => compat}/plugin-registry-compat.ts (86%) rename src/extension-host/{ => compat}/plugin-registry-registrations.test.ts (98%) rename src/extension-host/{ => compat}/plugin-registry-registrations.ts (93%) rename src/extension-host/{ => compat}/plugin-registry.test.ts (96%) rename src/extension-host/{ => compat}/plugin-registry.ts (83%) rename src/extension-host/{ => contributions}/cli-lifecycle.test.ts (94%) rename src/extension-host/{ => contributions}/cli-lifecycle.ts (88%) rename src/extension-host/{ => contributions}/command-runtime.test.ts (100%) rename src/extension-host/{ => contributions}/command-runtime.ts (94%) rename src/extension-host/{ => contributions}/gateway-methods.test.ts (96%) rename src/extension-host/{ => contributions}/gateway-methods.ts (86%) rename src/extension-host/{ => contributions}/provider-auth-flow.ts (89%) rename src/extension-host/{ => contributions}/provider-auth.test.ts (98%) rename src/extension-host/{ => contributions}/provider-auth.ts (91%) rename src/extension-host/{ => contributions}/provider-discovery.test.ts (97%) rename src/extension-host/{ => contributions}/provider-discovery.ts (91%) rename src/extension-host/{ => contributions}/provider-model-selection.ts (69%) rename src/extension-host/{ => contributions}/provider-runtime.test.ts (92%) create mode 100644 src/extension-host/contributions/provider-runtime.ts rename src/extension-host/{ => contributions}/provider-wizard.test.ts (97%) rename src/extension-host/{ => contributions}/provider-wizard.ts (98%) rename src/extension-host/{ => contributions}/registry-writes.test.ts (99%) rename src/extension-host/{ => contributions}/registry-writes.ts (96%) rename src/extension-host/{ => contributions}/runtime-registrations.test.ts (97%) rename src/extension-host/{ => contributions}/runtime-registrations.ts (93%) rename src/extension-host/{ => contributions}/runtime-registry.test.ts (99%) rename src/extension-host/{ => contributions}/runtime-registry.ts (99%) rename src/extension-host/{ => contributions}/service-lifecycle.test.ts (94%) rename src/extension-host/{ => contributions}/service-lifecycle.ts (87%) rename src/extension-host/{ => contributions}/tool-runtime.test.ts (96%) rename src/extension-host/{ => contributions}/tool-runtime.ts (86%) rename src/extension-host/{ => manifests}/manifest-registry.ts (93%) rename src/extension-host/{ => manifests}/resolved-registry.ts (92%) rename src/extension-host/{ => manifests}/schema.test.ts (100%) rename src/extension-host/{ => manifests}/schema.ts (98%) rename src/extension-host/{ => policy}/loader-activation-policy.test.ts (92%) rename src/extension-host/{ => policy}/loader-activation-policy.ts (75%) rename src/extension-host/{ => policy}/loader-discovery-policy.test.ts (100%) rename src/extension-host/{ => policy}/loader-discovery-policy.ts (94%) rename src/extension-host/{ => policy}/loader-finalization-policy.test.ts (97%) rename src/extension-host/{ => policy}/loader-finalization-policy.ts (92%) rename src/extension-host/{ => policy}/loader-policy.test.ts (97%) rename src/extension-host/{ => policy}/loader-policy.ts (94%) rename src/extension-host/{ => policy}/loader-provenance.test.ts (100%) rename src/extension-host/{ => policy}/loader-provenance.ts (95%) delete mode 100644 src/extension-host/provider-runtime.ts rename src/extension-host/{ => static}/active-registry.test.ts (96%) rename src/extension-host/{ => static}/active-registry.ts (98%) create mode 100644 src/gateway/.DS_Store create mode 100644 src/gateway/protocol/.DS_Store create mode 100644 src/gateway/server/.DS_Store create mode 100644 src/plugins/.DS_Store diff --git a/src/agents/.DS_Store b/src/agents/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..17ebe4f6bd886f817b739b5670108e1694d3133a GIT binary patch literal 8196 zcmeHMJ!lj`6n=9_%n>~Z5hQ}eDi#)Ak&5U4>3DgmQ=8V{=Gf%TP(>PC~hp&@&62p$IuU{5)w+!dKF@jseF&F9V#rXDCli zYS5CEzn7^*_41X8*@d7|m5wRzQoMB~$mI&!U~oZ6I_`;J)&I%toNoWFPaakQ<4Q+>n^ z<938mmZ(Anv_(AJX2E<35meFEx;Pg{=7Bt+ry0xY?adbdiM>0~eY<<3v9~3oOXzLI zD?)&#vB-F%)@kJHm!y7Xtm}8yZoN=@Ezz9jI-aP{U6|j8uN7zJ8ONDv$GMERsD%Aj z$2tcrtzDQpwia(~#x!&DNo)OL#y2BL=3(Jatuy{%;LQVV5xX*=WefAb!*{(FCeGcR zHqNebOl;9s7M`Jy@f-l21^G@?C~u*mxk|U*#PVQxxwUJpF-#;U7vDVcH{{N?Y%CnK z+QM-SD_O>4ucXL+(m2|B6UY7S-SUpwQ#^-Z(|N-_G%T!b8w-bc#W)VhT~$XL_obkj zA91!OzO!Rnt-TdFw#iu%dmFdMxQBo^z|+lM=Hh!>Yhv3Tc-q2d_?u|@TUhgte&qRG ziDzIysmD40KNo%fA3uoGItCmA|1<+)FgKfX6Fx=pBmT- AVgLXD literal 0 HcmV?d00001 diff --git a/src/agents/model-selection.ts b/src/agents/model-selection.ts index 62233352bc9..b0ba0e4e437 100644 --- a/src/agents/model-selection.ts +++ b/src/agents/model-selection.ts @@ -14,8 +14,15 @@ import { } from "./agent-scope.js"; import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "./defaults.js"; import type { ModelCatalogEntry } from "./model-catalog.js"; -import { normalizeGoogleModelId } from "./model-id-normalization.js"; import { splitTrailingAuthProfile } from "./model-ref-profile.js"; +import { + legacyModelKey, + modelKey, + normalizeModelRef, + parseModelRef, + type ModelRef, +} from "./model-ref.js"; +import { normalizeProviderId, normalizeProviderIdForAuth } from "./provider-id.js"; const log = createSubsystemLogger("model-selection"); @@ -588,3 +595,13 @@ export function normalizeModelSelection(value: unknown): string | undefined { } return undefined; } + +export { + legacyModelKey, + modelKey, + normalizeModelRef, + normalizeProviderId, + normalizeProviderIdForAuth, + parseModelRef, +}; +export type { ModelRef }; diff --git a/src/agents/pi-embedded-runner/.DS_Store b/src/agents/pi-embedded-runner/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5a336d3ecf20a301b394912ff9557fefcb14136e GIT binary patch literal 6148 zcmeHKJ5Iwu5S>X}SfWXpf?_33kQ*$KbAntTGLb@&;0P(bI}St<) zc1+K7pr`GoTYtI#itL)Is<%xIPx*Ft`+j;o_oC}-wBC&BV=uaY?Ce^suti8P5DWwZ z!9XzZuNgqk7AbEG!v+JvKrnD+K>iO2DwrKxL;ZEY=m-FmXS@p5I!gePIDpx)HG~Jk zRtmII_7Q`v9RB2a*|9aWa$-Fh`}oQ16AJ6;@Fz_t&W2%wfncD|fY0a?>HiDp5A%P& zD87P$VBk+Nz(uvJ=D3pg*1_eZ*Cyx+`YFiObQo>LKyAhNkXAhHF`-Os2=xt)D!c%F0aRMiAyFa<0}?}Cf{BHVjRgsHV&%2? zY@bSxP+&rUY{~vEK0D`p`Eibj+~9KDC+ZPV24ze(U_KC@XYEK5JUr>-99QL8e|TC~ zO()hIzmoyJck6Uc6KbfW`2OuaUB|OkT@<6T9>JS!-``fxk1vPsBgS7uG}EOgWbY2? zv_%(Ke+IixQ;bT~GC@tV_-RURK8szhEuGH~jvu79mFKSNw@SYgAJr}I3zu$U3>X8( zz@KCQJ)0%lR5WW07z4(@f&u0v@6g|^K2vkLcLc4poFIXtJ>Ec<^U(i2b^U+qw^Tj3=#m)N#;!c-tTq$k} zmTufh>7Q_|yV8~7LeIT3q%$;0<3=prDKqC~=AJj_o(XR{F96*7erE+(1khj=yfx2e zOp$S^7s_1d5was6*uo=pFu*dete6AlfH`0em;>g(zvuw>Y$=Ti`@SEw)*LVg{!0hs z`H-;+<^d~@`siSzM*w1--CB6fbAWQPfO){mqf&WKe|m6%>cSDjc{;~42`Ac|hQY76TqkDjTw3x>Zx_lQg#30E5 zukXyti}QK4I?^}OoJDz_+rimf>(J*m6F12dr;=x#xjbcUr@1UViN|8SUqAo+c=lHP zA8}(%mu}3GDvCFnVFHuqZvM@O^)>OTCKK%YcHBGp0tnl*aL~mW6 z`q%K7tKXHHXvEebHAbVcuAA?xdrN+Ol8Eya93PR)k2jnEH|S57Z@R10Hhq%aAo3RS!0V|KvCH=Y!6K($&L#&ts zSIB{y*SaX@|BcD-|F2L+Ce<7;2maInS8r}M*U8ddeGFT6`Hb}es}zZ=JSv4v@{a&N dkA5)Zb;eNP>|wDN0cwLa=D=Td;5Q{`|FQr8 literal 0 HcmV?d00001 diff --git a/src/auto-reply/reply/commands-plugin.ts b/src/auto-reply/reply/commands-plugin.ts index e84c3b0875c..1c5f23a0c5f 100644 --- a/src/auto-reply/reply/commands-plugin.ts +++ b/src/auto-reply/reply/commands-plugin.ts @@ -8,7 +8,7 @@ import { executeExtensionHostPluginCommand, matchExtensionHostPluginCommand, -} from "../../extension-host/command-runtime.js"; +} from "../../extension-host/contributions/command-runtime.js"; import type { CommandHandler, CommandHandlerResult } from "./commands-types.js"; /** diff --git a/src/auto-reply/status.ts b/src/auto-reply/status.ts index 902d81d8f84..7f718e2ff19 100644 --- a/src/auto-reply/status.ts +++ b/src/auto-reply/status.ts @@ -20,7 +20,7 @@ import { type SessionEntry, type SessionScope, } from "../config/sessions.js"; -import { listExtensionHostPluginCommands } from "../extension-host/command-runtime.js"; +import { listExtensionHostPluginCommands } from "../extension-host/contributions/command-runtime.js"; import { formatTimeAgo } from "../infra/format-time/format-relative.ts"; import { resolveCommitHash } from "../infra/git-commit.js"; import type { MediaUnderstandingDecision } from "../media-understanding/types.js"; @@ -799,7 +799,7 @@ type CommandsListItem = { function buildCommandItems( commands: ChatCommandDefinition[], - pluginCommands: ReturnType, + pluginCommands: ReturnType, ): CommandsListItem[] { const grouped = groupCommandsByCategory(commands); const items: CommandsListItem[] = []; diff --git a/src/channels/.DS_Store b/src/channels/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..aacf86ec76eecc7794fa234a91beacca64022f66 GIT binary patch literal 6148 zcmeHKF)su`6n?{rJ0cVcg~%2(*9gC0ael$|!f`>eXD^(nB%3G{DurmY6eJo6QL6NE zzrhco{Y!XvbsNcic`#xZGwZ&w3tiG`BD7 zG~zBRDwI0+nNc2}QowwQIOpnMR0pGNXxQ)=(a>R5jLT{INZobLHK){CF01e2JYEzs zuM&7MA7}){V)R=+v*EYwD3{y9!P7-}rMYFS=dyc_$`hxTd67Q9fcf>}cUGsG&xzi< zGcJ$ullHCE$mY3wr)T~BxUPxiD1e&HRva`attcQ0hytGq@c9tH8AFSSL494war1Z{M$L_4`4Mo`#Uj;gx zRA^9IQ9u;%73ejOBV7L%^Y8zDl01n5qQJjWKou(0$~<1l*4EU^ajgyD%WyW1OAP81 jG`1Y;4wvFFxHilM+yRCb6N4Cm$sYkNgEXSRuPX2X8c@0| literal 0 HcmV?d00001 diff --git a/src/channels/dock.ts b/src/channels/dock.ts index 6d4e7a012ed..14c322790cf 100644 --- a/src/channels/dock.ts +++ b/src/channels/dock.ts @@ -8,8 +8,8 @@ import { resolveChannelGroupRequireMention, resolveChannelGroupToolsPolicy, } from "../config/group-policy.js"; -import { requireActiveExtensionHostRegistry } from "../extension-host/active-registry.js"; -import { listExtensionHostChannelRegistrations } from "../extension-host/runtime-registry.js"; +import { listExtensionHostChannelRegistrations } from "../extension-host/contributions/runtime-registry.js"; +import { requireActiveExtensionHostRegistry } from "../extension-host/static/active-registry.js"; import { formatAllowFromLowercase, formatNormalizedAllowFromEntries, diff --git a/src/channels/plugins/.DS_Store b/src/channels/plugins/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..c5debe5e0f2dfdf81bb9397fc28958014a25db26 GIT binary patch literal 6148 zcmeHLyH3L}6upK>lvYR`c`TXOI&?vdp((mX4V3C~>5CCAmCCcg+1Q(3NS7j*|L zeJ~u;z+fm2?~DA>96#UhZeG<|=Z=|Ha-FZiQ?xNXl1xA$)|;7z;OHA1>EbHSC(ZBj zBhfH3R+`%?Ka&^Jq8*xnRR<-+T@CupaE17W>RcDE^8shQ72avC&R4>9WyEsbe->fz zr#AC1GURNwQbnPytpZj7t3aXv?+-2tqo*-aD7Ow&@(2KQ&@2u2e3sxCSEHvfQivXy zP@zB-D)bRUsBpBq+RxJ%DOBMkOrw!ZWdbEmI$6i$VCLf{2~n|*$`8Tpb+pMkRE#w zFI7;fN)Yic@LIfi(z^)aNe`mmo0)EBva<@gC}aj^-m>$(x8HoTGn+RdBC)<%FB0X5 zD2vK=aRH5^a6i{XnbCJn!3y{j-KGZhX^CpoPN4k_uYgy;E8rFI3U~$n2Lg&&4*@FMP}`xha_c}NQvldm+?EB`$OEKLplzt_P+94Um@0b^+EwTj zLnwFj2MmV|wH+#}+({^R68gzPXDC8G9e#m?lL(ddtyjP+kW_$k_dHdRwMVpNng0oA^ZLZR z=BbVuYEVbck2-a+xy`IzOT(G`PHxBioH0#~f5TclGv}G-0yV*N0H#~8cbqDU;$Aw^ z3(k6-^vL5v4P0#J2 zP!P3{ig;4Ic=z0Yp!f&aW4|{uO=osDntBk$H(}=O&U|n7n{Q`!coQO0Oa1yH(F_q4 zkl9{5k0K*+JLgoIur+hA3jRdBc5`v17IoHBSg8;NL;+Di6c7bOfxklm?Ae?OBldmM zDy1kO3jCJ}@b@7=W*b@?8>>GZD0Bz_n@6=yxJDeHeFAGkYhz=zEBZ9igR-v5h8W7Y zqdj0aY-nw4tZ^r0+)3FdD;uFG{dD*R8cr%SR!UJo6i6$;vHLlyP?H+eO~&t!Z~CpB zs9dhLqbh0(FQ)dd&JMobNFwS(ME=c_*=w(pi1ju1gkTHqSot+t1BWht4QkV-cZ#5L z%UKwgOL0dXeKcHBeRZN!Mt81Ee_7boj8Zs{ms(|BQ&6QsJ#cym`-n=ki94?8CpgmW zd%wcFe82AxwfpHaT<+ugc;g^Fj!EiJMD+}9Cw4A@x7Y6S+?#xV@{SXjQ%y%fk6>%u6UJGO6w`Ge>0^t{gO(;dO9!c2L){ZHoUymntdD;JYN=Xt0##SI_ zkTV?rW2YZ={y%nq0u%*Afqzc{l`pT9m%!V`)~OM2tQ{b)B6DI~Y^-)c!4R(3;W+H@ b4?|oBwk@NauA?pkU|vrqY4}YzU(44 literal 0 HcmV?d00001 diff --git a/src/commands/auth-choice.apply.plugin-provider.test.ts b/src/commands/auth-choice.apply.plugin-provider.test.ts index c3709a6ce75..ea710971c9a 100644 --- a/src/commands/auth-choice.apply.plugin-provider.test.ts +++ b/src/commands/auth-choice.apply.plugin-provider.test.ts @@ -20,7 +20,7 @@ const runExtensionHostProviderModelSelectedHook = vi.hoisted(() => vi.fn(async ( vi.mock("../plugins/provider-wizard.js", () => ({ resolveProviderPluginChoice, })); -vi.mock("../extension-host/provider-model-selection.js", () => ({ +vi.mock("../extension-host/contributions/provider-model-selection.js", () => ({ runExtensionHostProviderModelSelectedHook, })); diff --git a/src/commands/auth-choice.apply.plugin-provider.ts b/src/commands/auth-choice.apply.plugin-provider.ts index e4b9b5b3dec..285adc28b69 100644 --- a/src/commands/auth-choice.apply.plugin-provider.ts +++ b/src/commands/auth-choice.apply.plugin-provider.ts @@ -3,7 +3,7 @@ import { applyExtensionHostPluginProvider, runExtensionHostProviderAuthMethod, type ExtensionHostPluginProviderAuthChoiceOptions, -} from "../extension-host/provider-auth-flow.js"; +} from "../extension-host/contributions/provider-auth-flow.js"; import type { ApplyAuthChoiceParams, ApplyAuthChoiceResult } from "./auth-choice.apply.js"; export type PluginProviderAuthChoiceOptions = ExtensionHostPluginProviderAuthChoiceOptions; diff --git a/src/commands/model-picker.ts b/src/commands/model-picker.ts index af7c0cee92b..64d9e533e1f 100644 --- a/src/commands/model-picker.ts +++ b/src/commands/model-picker.ts @@ -401,7 +401,7 @@ export async function promptDefaultModel( workspaceDir: params.workspaceDir, }); if (applied.defaultModel) { - await runExtensionHostProviderModelSelectedHook({ + await runProviderModelSelectedHook({ config: applied.config, model: applied.defaultModel, prompter: params.prompter, diff --git a/src/commands/onboard-non-interactive/.DS_Store b/src/commands/onboard-non-interactive/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5964b30b13029241ce0119e4817559237681cc09 GIT binary patch literal 6148 zcmeH~Jx&8L5QS$TNGs8#r1TYX0~0MhQZ4{VBq%o8H1w`>4^BXp6XYON+<=ldo&m98 zCAtWqHR$M*3XA-zR7jRZ)51W14c zPD%i0wpnxO%9;d7fCRn>*#3}EOmk>)ty>4GngT%W8eI)-%Oxx(h33%WiW!)CDAYqW zQVjKQjHmF+p~cn1MI-spc=BiRqV?%mKUH_p?8=%1NMK0d+`Cgd|8MZij3)WR5cWub z1pXNTowSQ~j*p77^~dMgS({MqP|VD)SObRk;1Yn2?ITxp(&v-4;g>^;tF2<=H5|%| MKn22z1WrKU1H@V_J5S>XDa?w)aVEdx(fv_nVezNkk1)kj1Eo3|Cz<4_*LS=eVVT?r7Xzw|!-zzc?g& zZ)l_|=t!UTe>v>-y5ZULTPr9u9vx`31OUo2S_QV$5|Wb~vtu!Y z2f~&Lv{d#IgDoB7$>XwPF|>4IFFx2;{wQ8pSI7KG!-=zDw820yFlAtF-KE_B=lEr+ zMgBA;dci<2@Xr|FMb~#Le3aj{twC T78%!cU_1nrkZ6K|Utr)Jt(P&2 literal 0 HcmV?d00001 diff --git a/src/config/doc-baseline.ts b/src/config/doc-baseline.ts index 58bff4269ae..e9d82bd7b5d 100644 --- a/src/config/doc-baseline.ts +++ b/src/config/doc-baseline.ts @@ -6,7 +6,7 @@ import type { ChannelPlugin } from "../channels/plugins/index.js"; import { loadResolvedExtensionRegistry, type ResolvedExtensionRegistry, -} from "../extension-host/resolved-registry.js"; +} from "../extension-host/manifests/resolved-registry.js"; import { resolveOpenClawPackageRootSync } from "../infra/openclaw-root.js"; import { FIELD_HELP } from "./schema.help.js"; import { buildConfigSchema, type ConfigSchemaResponse } from "./schema.js"; diff --git a/src/config/plugin-auto-enable.ts b/src/config/plugin-auto-enable.ts index cdcbdeace4a..58cce91c6f0 100644 --- a/src/config/plugin-auto-enable.ts +++ b/src/config/plugin-auto-enable.ts @@ -13,7 +13,7 @@ import { loadResolvedExtensionRegistry, resolvedExtensionRegistryFromPluginManifestRegistry, type ResolvedExtensionRegistry, -} from "../extension-host/resolved-registry.js"; +} from "../extension-host/manifests/resolved-registry.js"; import { type PluginManifestRegistry } from "../plugins/manifest-registry.js"; import { isRecord } from "../utils.js"; import type { OpenClawConfig } from "./config.js"; diff --git a/src/config/resolved-extension-validation.ts b/src/config/resolved-extension-validation.ts index 725f585a989..90ffa92b62a 100644 --- a/src/config/resolved-extension-validation.ts +++ b/src/config/resolved-extension-validation.ts @@ -1,8 +1,9 @@ -import type { ResolvedExtensionRegistry } from "../extension-host/resolved-registry.js"; +import type { ResolvedExtensionRegistry } from "../extension-host/manifests/resolved-registry.js"; export type ResolvedExtensionValidationEntry = { id: string; origin: "workspace" | "bundled" | "global" | "config"; + format?: "bundle" | "openclaw"; kind?: string; channels: string[]; configSchema?: Record; @@ -37,6 +38,7 @@ export function buildResolvedExtensionValidationIndex( return { id: extension.id, origin: extension.origin ?? "workspace", + format: record.manifestPath.endsWith("package.json") ? "openclaw" : "bundle", kind: extension.kind, channels, configSchema: extension.staticMetadata.configSchema, diff --git a/src/config/validation.ts b/src/config/validation.ts index b481c199b77..d0697522d69 100644 --- a/src/config/validation.ts +++ b/src/config/validation.ts @@ -1,7 +1,7 @@ import path from "node:path"; import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js"; import { CHANNEL_IDS, normalizeChatChannelId } from "../channels/registry.js"; -import { loadResolvedExtensionRegistry } from "../extension-host/resolved-registry.js"; +import { loadResolvedExtensionRegistry } from "../extension-host/manifests/resolved-registry.js"; import { normalizePluginsConfig, resolveEffectiveEnableState, diff --git a/src/extension-host/.DS_Store b/src/extension-host/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..96cd27f08b7c883df9cb46c6c2ebadce4d86b5c4 GIT binary patch literal 8196 zcmeHMJ!=$E6uoZ^Vf~0$rV4}hLjJ)R*2+dmXJvNQkA>O1)ir|MbXN9OVjo0B8!e*I zLaqD@f<>%Si3&EJ``&YNZ+2!71X=Jtc<&5zKjz#s!_3~dMC8`C2CGENMAXG(JarsP z&0ssvnbApSR)7xiM7L>!ZqblDZO(Yx2~)rnFa=BjQ@|9M2LQam0VmRy>y94ut zRm2!hE{2m!S9YmGapCHS%Yr+(Jff|pfGIGm0Qc_4(6tw#Zx{XhU{aKQ?@JD;bttc` zt`~kZ4msVuOHFMpaeG|JRecGDtmP{nw z7B@xS{dn4*RF<-RVgGk2E%{|(e-@$2?7ZeOkK!I|U<+tSSLq5(P^2oa#;nSsvv=#0 z$Z}qs@Vn{psL3bGX!lg~=_1o#!~^811pR{U$orxUn)0wZ94N_t{BmP2kySY)&FydH zPMwb?_#_f!P2*Nup$Q6uCb;xH5EOPv@XY(?`_qdnpM&T8?N32a_-KNeegF9u*)Rp> zU4bK!;4=6B=bQKc=e-Q$X9}1Cf1!X|=&kqoXK?DRXHs#monc1#;`y3_! literal 0 HcmV?d00001 diff --git a/src/extension-host/activation.test.ts b/src/extension-host/activation.test.ts index 99fb8d7fbf4..a71149eec7e 100644 --- a/src/extension-host/activation.test.ts +++ b/src/extension-host/activation.test.ts @@ -5,7 +5,7 @@ import { activateExtensionHostRegistry } from "./activation.js"; import { getActiveExtensionHostRegistry, getActiveExtensionHostRegistryKey, -} from "./active-registry.js"; +} from "./static/active-registry.js"; describe("extension host activation", () => { beforeEach(() => { diff --git a/src/extension-host/activation.ts b/src/extension-host/activation.ts index 9ef28146e4b..a76d506f03e 100644 --- a/src/extension-host/activation.ts +++ b/src/extension-host/activation.ts @@ -1,6 +1,6 @@ import { initializeGlobalHookRunner } from "../plugins/hook-runner-global.js"; import type { PluginRegistry } from "../plugins/registry.js"; -import { setActiveExtensionHostRegistry } from "./active-registry.js"; +import { setActiveExtensionHostRegistry } from "./static/active-registry.js"; export function activateExtensionHostRegistry(registry: PluginRegistry, cacheKey: string): void { setActiveExtensionHostRegistry(registry, cacheKey); diff --git a/src/extension-host/loader-bootstrap.test.ts b/src/extension-host/activation/loader-bootstrap.test.ts similarity index 97% rename from src/extension-host/loader-bootstrap.test.ts rename to src/extension-host/activation/loader-bootstrap.test.ts index a838b932640..57da529ce2f 100644 --- a/src/extension-host/loader-bootstrap.test.ts +++ b/src/extension-host/activation/loader-bootstrap.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { createEmptyPluginRegistry } from "../plugins/registry.js"; +import { createEmptyPluginRegistry } from "../../plugins/registry.js"; import { bootstrapExtensionHostPluginLoad } from "./loader-bootstrap.js"; describe("extension host loader bootstrap", () => { diff --git a/src/extension-host/loader-bootstrap.ts b/src/extension-host/activation/loader-bootstrap.ts similarity index 85% rename from src/extension-host/loader-bootstrap.ts rename to src/extension-host/activation/loader-bootstrap.ts index 6009e427b1b..0745230f6eb 100644 --- a/src/extension-host/loader-bootstrap.ts +++ b/src/extension-host/activation/loader-bootstrap.ts @@ -1,20 +1,20 @@ -import type { OpenClawConfig } from "../config/config.js"; -import type { NormalizedPluginsConfig } from "../plugins/config-state.js"; -import { discoverOpenClawPlugins, type PluginCandidate } from "../plugins/discovery.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import type { NormalizedPluginsConfig } from "../../plugins/config-state.js"; +import { discoverOpenClawPlugins, type PluginCandidate } from "../../plugins/discovery.js"; import { loadPluginManifestRegistry, type PluginManifestRecord, type PluginManifestRegistry, -} from "../plugins/manifest-registry.js"; -import type { PluginRegistry } from "../plugins/registry.js"; -import type { PluginLogger } from "../plugins/types.js"; -import { resolveExtensionHostDiscoveryPolicy } from "./loader-discovery-policy.js"; +} from "../../plugins/manifest-registry.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; +import type { PluginLogger } from "../../plugins/types.js"; +import { resolveExtensionHostDiscoveryPolicy } from "../policy/loader-discovery-policy.js"; import { buildExtensionHostProvenanceIndex, compareExtensionHostDuplicateCandidateOrder, pushExtensionHostDiagnostics, -} from "./loader-policy.js"; -import type { ExtensionHostProvenanceIndex } from "./loader-provenance.js"; +} from "../policy/loader-policy.js"; +import type { ExtensionHostProvenanceIndex } from "../policy/loader-provenance.js"; export function bootstrapExtensionHostPluginLoad(params: { config: OpenClawConfig; diff --git a/src/extension-host/loader-cache.test.ts b/src/extension-host/activation/loader-cache.test.ts similarity index 97% rename from src/extension-host/loader-cache.test.ts rename to src/extension-host/activation/loader-cache.test.ts index f9e103b6557..da1f8ced98d 100644 --- a/src/extension-host/loader-cache.test.ts +++ b/src/extension-host/activation/loader-cache.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import type { PluginRegistry } from "../plugins/registry.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; import { buildExtensionHostRegistryCacheKey, clearExtensionHostRegistryCache, diff --git a/src/extension-host/loader-cache.ts b/src/extension-host/activation/loader-cache.ts similarity index 86% rename from src/extension-host/loader-cache.ts rename to src/extension-host/activation/loader-cache.ts index 1649fbc8ff5..d046dd4bb1a 100644 --- a/src/extension-host/loader-cache.ts +++ b/src/extension-host/activation/loader-cache.ts @@ -1,8 +1,8 @@ -import type { PluginInstallRecord } from "../config/types.plugins.js"; -import type { NormalizedPluginsConfig } from "../plugins/config-state.js"; -import type { PluginRegistry } from "../plugins/registry.js"; -import { resolvePluginCacheInputs } from "../plugins/roots.js"; -import { resolveUserPath } from "../utils.js"; +import type { PluginInstallRecord } from "../../config/types.plugins.js"; +import type { NormalizedPluginsConfig } from "../../plugins/config-state.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; +import { resolvePluginCacheInputs } from "../../plugins/roots.js"; +import { resolveUserPath } from "../../utils.js"; export const MAX_EXTENSION_HOST_REGISTRY_CACHE_ENTRIES = 32; diff --git a/src/extension-host/loader-execution.test.ts b/src/extension-host/activation/loader-execution.test.ts similarity index 100% rename from src/extension-host/loader-execution.test.ts rename to src/extension-host/activation/loader-execution.test.ts diff --git a/src/extension-host/loader-execution.ts b/src/extension-host/activation/loader-execution.ts similarity index 83% rename from src/extension-host/loader-execution.ts rename to src/extension-host/activation/loader-execution.ts index ba6b6cc832b..88872fada73 100644 --- a/src/extension-host/loader-execution.ts +++ b/src/extension-host/activation/loader-execution.ts @@ -1,17 +1,17 @@ -import type { OpenClawConfig } from "../config/config.js"; -import type { NormalizedPluginsConfig } from "../plugins/config-state.js"; -import { createPluginRegistry, type PluginRegistry } from "../plugins/registry.js"; -import type { CreatePluginRuntimeOptions } from "../plugins/runtime/index.js"; -import type { PluginRuntime } from "../plugins/runtime/types.js"; -import type { PluginLogger } from "../plugins/types.js"; -import { bootstrapExtensionHostPluginLoad } from "./loader-bootstrap.js"; -import { resolveExtensionHostDiscoveryPolicy } from "./loader-discovery-policy.js"; -import { createExtensionHostModuleLoader } from "./loader-module-loader.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import type { NormalizedPluginsConfig } from "../../plugins/config-state.js"; +import { createPluginRegistry, type PluginRegistry } from "../../plugins/registry.js"; +import type { CreatePluginRuntimeOptions } from "../../plugins/runtime/index.js"; +import type { PluginRuntime } from "../../plugins/runtime/types.js"; +import type { PluginLogger } from "../../plugins/types.js"; +import { resolveExtensionHostDiscoveryPolicy } from "../policy/loader-discovery-policy.js"; import { buildExtensionHostProvenanceIndex, compareExtensionHostDuplicateCandidateOrder, pushExtensionHostDiagnostics, -} from "./loader-policy.js"; +} from "../policy/loader-policy.js"; +import { bootstrapExtensionHostPluginLoad } from "./loader-bootstrap.js"; +import { createExtensionHostModuleLoader } from "./loader-module-loader.js"; import { createExtensionHostLazyRuntime } from "./loader-runtime-proxy.js"; import { createExtensionHostLoaderSession, @@ -56,7 +56,7 @@ export function prepareExtensionHostLoaderExecution(params: { config: params.config, workspaceDir: params.workspaceDir, env: params.env, - warningCacheKey: params.cacheKey, + cacheKey: params.cacheKey, warningCache: params.warningCache, cache: params.cache, normalizedConfig: params.normalizedConfig, diff --git a/src/extension-host/loader-finalize.test.ts b/src/extension-host/activation/loader-finalize.test.ts similarity index 95% rename from src/extension-host/loader-finalize.test.ts rename to src/extension-host/activation/loader-finalize.test.ts index 7361db68019..7fb6944992b 100644 --- a/src/extension-host/loader-finalize.test.ts +++ b/src/extension-host/activation/loader-finalize.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from "vitest"; -import type { PluginRegistry } from "../plugins/registry.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; +import { createExtensionHostPluginRecord } from "../policy/loader-policy.js"; import { finalizeExtensionHostRegistryLoad } from "./loader-finalize.js"; -import { createExtensionHostPluginRecord } from "./loader-policy.js"; import { setExtensionHostPluginRecordLifecycleState } from "./loader-state.js"; function createRegistry(): PluginRegistry { diff --git a/src/extension-host/loader-finalize.ts b/src/extension-host/activation/loader-finalize.ts similarity index 79% rename from src/extension-host/loader-finalize.ts rename to src/extension-host/activation/loader-finalize.ts index a5c2c2ca1ce..6cac899414e 100644 --- a/src/extension-host/loader-finalize.ts +++ b/src/extension-host/activation/loader-finalize.ts @@ -1,7 +1,7 @@ -import type { PluginRegistry } from "../plugins/registry.js"; -import type { PluginLogger } from "../plugins/types.js"; -import { resolveExtensionHostFinalizationPolicy } from "./loader-finalization-policy.js"; -import type { ExtensionHostProvenanceIndex } from "./loader-policy.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; +import type { PluginLogger } from "../../plugins/types.js"; +import { resolveExtensionHostFinalizationPolicy } from "../policy/loader-finalization-policy.js"; +import type { ExtensionHostProvenanceIndex } from "../policy/loader-provenance.js"; import { markExtensionHostRegistryPluginsReady } from "./loader-state.js"; export function finalizeExtensionHostRegistryLoad(params: { diff --git a/src/extension-host/loader-flow.test.ts b/src/extension-host/activation/loader-flow.test.ts similarity index 95% rename from src/extension-host/loader-flow.test.ts rename to src/extension-host/activation/loader-flow.test.ts index 6aff6398d03..31c513be785 100644 --- a/src/extension-host/loader-flow.test.ts +++ b/src/extension-host/activation/loader-flow.test.ts @@ -2,10 +2,10 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import { normalizePluginsConfig } from "../plugins/config-state.js"; -import type { PluginCandidate } from "../plugins/discovery.js"; -import type { PluginManifestRecord } from "../plugins/manifest-registry.js"; -import type { PluginRegistry } from "../plugins/registry.js"; +import { normalizePluginsConfig } from "../../plugins/config-state.js"; +import type { PluginCandidate } from "../../plugins/discovery.js"; +import type { PluginManifestRecord } from "../../plugins/manifest-registry.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; import { processExtensionHostPluginCandidate } from "./loader-flow.js"; const tempDirs: string[] = []; diff --git a/src/extension-host/loader-flow.ts b/src/extension-host/activation/loader-flow.ts similarity index 90% rename from src/extension-host/loader-flow.ts rename to src/extension-host/activation/loader-flow.ts index 85bf3e410a9..e867ce38c99 100644 --- a/src/extension-host/loader-flow.ts +++ b/src/extension-host/activation/loader-flow.ts @@ -1,11 +1,12 @@ -import type { OpenClawConfig } from "../config/config.js"; -import type { PluginCandidate } from "../plugins/discovery.js"; -import type { PluginManifestRecord } from "../plugins/manifest-registry.js"; -import type { PluginRecord, PluginRegistry } from "../plugins/registry.js"; -import type { OpenClawPluginApi, OpenClawPluginModule, PluginLogger } from "../plugins/types.js"; -import { resolveExtensionHostActivationPolicy } from "./loader-activation-policy.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import type { NormalizedPluginsConfig } from "../../plugins/config-state.js"; +import type { PluginCandidate } from "../../plugins/discovery.js"; +import type { PluginManifestRecord } from "../../plugins/manifest-registry.js"; +import type { PluginRecord, PluginRegistry } from "../../plugins/registry.js"; +import type { OpenClawPluginApi, OpenClawPluginModule, PluginLogger } from "../../plugins/types.js"; +import { resolveExtensionHostActivationPolicy } from "../policy/loader-activation-policy.js"; +import { recordExtensionHostPluginError } from "../policy/loader-policy.js"; import { importExtensionHostPluginModule } from "./loader-import.js"; -import { recordExtensionHostPluginError } from "./loader-policy.js"; import { planExtensionHostLoadedPlugin, runExtensionHostPluginRegister, @@ -13,6 +14,7 @@ import { import { resolveExtensionHostModuleExport } from "./loader-runtime.js"; import { appendExtensionHostPluginRecord, + setExtensionHostPluginRecordDisabled, setExtensionHostPluginRecordLifecycleState, setExtensionHostPluginRecordError, } from "./loader-state.js"; @@ -20,21 +22,7 @@ import { export function processExtensionHostPluginCandidate(params: { candidate: PluginCandidate; manifestRecord: PluginManifestRecord; - normalizedConfig: { - entries: Record< - string, - { - enabled?: boolean; - hooks?: { - allowPromptInjection?: boolean; - }; - config?: unknown; - } - >; - slots: { - memory?: string | null; - }; - }; + normalizedConfig: NormalizedPluginsConfig; rootConfig: OpenClawConfig; validateOnly: boolean; logger: PluginLogger; @@ -85,7 +73,7 @@ export function processExtensionHostPluginCandidate(params: { level: "error", pluginId: record.id, source: record.source, - message: record.error, + message: record.error ?? message, }); }; diff --git a/src/extension-host/loader-host-state.test.ts b/src/extension-host/activation/loader-host-state.test.ts similarity index 100% rename from src/extension-host/loader-host-state.test.ts rename to src/extension-host/activation/loader-host-state.test.ts diff --git a/src/extension-host/loader-host-state.ts b/src/extension-host/activation/loader-host-state.ts similarity index 100% rename from src/extension-host/loader-host-state.ts rename to src/extension-host/activation/loader-host-state.ts diff --git a/src/extension-host/loader-import.test.ts b/src/extension-host/activation/loader-import.test.ts similarity index 100% rename from src/extension-host/loader-import.test.ts rename to src/extension-host/activation/loader-import.test.ts diff --git a/src/extension-host/loader-import.ts b/src/extension-host/activation/loader-import.ts similarity index 90% rename from src/extension-host/loader-import.ts rename to src/extension-host/activation/loader-import.ts index b4e6c44ef3a..629f8387f24 100644 --- a/src/extension-host/loader-import.ts +++ b/src/extension-host/activation/loader-import.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import path from "node:path"; -import { openBoundaryFileSync } from "../infra/boundary-file-read.js"; -import type { PluginRecord } from "../plugins/registry.js"; +import { openBoundaryFileSync } from "../../infra/boundary-file-read.js"; +import type { PluginRecord } from "../../plugins/registry.js"; export function importExtensionHostPluginModule(params: { rootDir: string; diff --git a/src/extension-host/loader-module-loader.test.ts b/src/extension-host/activation/loader-module-loader.test.ts similarity index 100% rename from src/extension-host/loader-module-loader.test.ts rename to src/extension-host/activation/loader-module-loader.test.ts diff --git a/src/extension-host/loader-module-loader.ts b/src/extension-host/activation/loader-module-loader.ts similarity index 93% rename from src/extension-host/loader-module-loader.ts rename to src/extension-host/activation/loader-module-loader.ts index 1df3523fcc0..9aa834a1378 100644 --- a/src/extension-host/loader-module-loader.ts +++ b/src/extension-host/activation/loader-module-loader.ts @@ -1,6 +1,6 @@ import { createJiti } from "jiti"; -import type { OpenClawPluginModule } from "../plugins/types.js"; -import { resolvePluginSdkAlias, resolvePluginSdkScopedAliasMap } from "./loader-compat.js"; +import type { OpenClawPluginModule } from "../../plugins/types.js"; +import { resolvePluginSdkAlias, resolvePluginSdkScopedAliasMap } from "../compat/loader-compat.js"; type JitiLoaderFactory = typeof createJiti; type JitiLoader = ReturnType; diff --git a/src/extension-host/loader-orchestrator.ts b/src/extension-host/activation/loader-orchestrator.ts similarity index 73% rename from src/extension-host/loader-orchestrator.ts rename to src/extension-host/activation/loader-orchestrator.ts index 0d7a820f5fc..a45f5988ee6 100644 --- a/src/extension-host/loader-orchestrator.ts +++ b/src/extension-host/activation/loader-orchestrator.ts @@ -1,9 +1,12 @@ -import type { OpenClawConfig } from "../config/config.js"; -import { createSubsystemLogger } from "../logging/subsystem.js"; -import type { PluginRegistry } from "../plugins/registry.js"; -import { createPluginRuntime, type CreatePluginRuntimeOptions } from "../plugins/runtime/index.js"; -import type { PluginLogger } from "../plugins/types.js"; -import { clearExtensionHostPluginCommands } from "./command-runtime.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import { createSubsystemLogger } from "../../logging/subsystem.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; +import { + createPluginRuntime, + type CreatePluginRuntimeOptions, +} from "../../plugins/runtime/index.js"; +import type { PluginLogger } from "../../plugins/types.js"; +import { clearExtensionHostPluginCommands } from "../contributions/command-runtime.js"; import { clearExtensionHostLoaderHostState, getExtensionHostDiscoveryWarningCache, @@ -18,7 +21,7 @@ export type ExtensionHostPluginLoadOptions = { logger?: PluginLogger; coreGatewayHandlers?: Record< string, - import("../gateway/server-methods/types.js").GatewayRequestHandler + import("../../gateway/server-methods/types.js").GatewayRequestHandler >; runtimeOptions?: CreatePluginRuntimeOptions; cache?: boolean; diff --git a/src/extension-host/loader-pipeline.test.ts b/src/extension-host/activation/loader-pipeline.test.ts similarity index 100% rename from src/extension-host/loader-pipeline.test.ts rename to src/extension-host/activation/loader-pipeline.test.ts diff --git a/src/extension-host/loader-pipeline.ts b/src/extension-host/activation/loader-pipeline.ts similarity index 84% rename from src/extension-host/loader-pipeline.ts rename to src/extension-host/activation/loader-pipeline.ts index 602d2684912..57a963b9029 100644 --- a/src/extension-host/loader-pipeline.ts +++ b/src/extension-host/activation/loader-pipeline.ts @@ -1,8 +1,8 @@ -import type { GatewayRequestHandler } from "../gateway/server-methods/types.js"; -import type { PluginRegistry } from "../plugins/registry.js"; -import type { CreatePluginRuntimeOptions } from "../plugins/runtime/index.js"; -import type { PluginRuntime } from "../plugins/runtime/types.js"; -import { activateExtensionHostRegistry } from "./activation.js"; +import type { GatewayRequestHandler } from "../../gateway/server-methods/types.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; +import type { CreatePluginRuntimeOptions } from "../../plugins/runtime/index.js"; +import type { PluginRuntime } from "../../plugins/runtime/types.js"; +import { activateExtensionHostRegistry } from "../activation.js"; import { setCachedExtensionHostRegistry } from "./loader-cache.js"; import { prepareExtensionHostLoaderExecution } from "./loader-execution.js"; import type { ExtensionHostLoaderPreflightReady } from "./loader-preflight.js"; diff --git a/src/extension-host/loader-preflight.test.ts b/src/extension-host/activation/loader-preflight.test.ts similarity index 100% rename from src/extension-host/loader-preflight.test.ts rename to src/extension-host/activation/loader-preflight.test.ts diff --git a/src/extension-host/loader-preflight.ts b/src/extension-host/activation/loader-preflight.ts similarity index 93% rename from src/extension-host/loader-preflight.ts rename to src/extension-host/activation/loader-preflight.ts index 3bb7049599f..6940100c571 100644 --- a/src/extension-host/loader-preflight.ts +++ b/src/extension-host/activation/loader-preflight.ts @@ -1,7 +1,7 @@ -import type { OpenClawConfig } from "../config/config.js"; -import { applyTestPluginDefaults, normalizePluginsConfig } from "../plugins/config-state.js"; -import type { PluginLogger } from "../plugins/types.js"; -import { activateExtensionHostRegistry } from "./activation.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import { applyTestPluginDefaults, normalizePluginsConfig } from "../../plugins/config-state.js"; +import type { PluginLogger } from "../../plugins/types.js"; +import { activateExtensionHostRegistry } from "../activation.js"; import { buildExtensionHostRegistryCacheKey, getCachedExtensionHostRegistry, diff --git a/src/extension-host/loader-records.test.ts b/src/extension-host/activation/loader-records.test.ts similarity index 93% rename from src/extension-host/loader-records.test.ts rename to src/extension-host/activation/loader-records.test.ts index ba0f423e241..3b2e4d8649e 100644 --- a/src/extension-host/loader-records.test.ts +++ b/src/extension-host/activation/loader-records.test.ts @@ -1,8 +1,8 @@ import { describe, expect, it } from "vitest"; -import type { OpenClawConfig } from "../config/config.js"; -import { normalizePluginsConfig } from "../plugins/config-state.js"; -import type { PluginCandidate } from "../plugins/discovery.js"; -import type { PluginManifestRecord } from "../plugins/manifest-registry.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import { normalizePluginsConfig } from "../../plugins/config-state.js"; +import type { PluginCandidate } from "../../plugins/discovery.js"; +import type { PluginManifestRecord } from "../../plugins/manifest-registry.js"; import { prepareExtensionHostPluginCandidate } from "./loader-records.js"; function createCandidate(overrides: Partial = {}): PluginCandidate { diff --git a/src/extension-host/loader-records.ts b/src/extension-host/activation/loader-records.ts similarity index 87% rename from src/extension-host/loader-records.ts rename to src/extension-host/activation/loader-records.ts index 46e7904dd4c..063a8285c3d 100644 --- a/src/extension-host/loader-records.ts +++ b/src/extension-host/activation/loader-records.ts @@ -1,12 +1,12 @@ -import type { OpenClawConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { resolveEffectiveEnableState, type NormalizedPluginsConfig, -} from "../plugins/config-state.js"; -import type { PluginCandidate } from "../plugins/discovery.js"; -import type { PluginManifestRecord } from "../plugins/manifest-registry.js"; -import type { PluginRecord } from "../plugins/registry.js"; -import { createExtensionHostPluginRecord } from "./loader-policy.js"; +} from "../../plugins/config-state.js"; +import type { PluginCandidate } from "../../plugins/discovery.js"; +import type { PluginManifestRecord } from "../../plugins/manifest-registry.js"; +import type { PluginRecord } from "../../plugins/registry.js"; +import { createExtensionHostPluginRecord } from "../policy/loader-policy.js"; import { setExtensionHostPluginRecordDisabled } from "./loader-state.js"; type CandidateEntry = NormalizedPluginsConfig["entries"][string]; diff --git a/src/extension-host/loader-register.test.ts b/src/extension-host/activation/loader-register.test.ts similarity index 96% rename from src/extension-host/loader-register.test.ts rename to src/extension-host/activation/loader-register.test.ts index 7139299bc4b..a02798b2afb 100644 --- a/src/extension-host/loader-register.test.ts +++ b/src/extension-host/activation/loader-register.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import type { PluginDiagnostic } from "../plugins/types.js"; -import { createExtensionHostPluginRecord } from "./loader-policy.js"; +import type { PluginDiagnostic } from "../../plugins/types.js"; +import { createExtensionHostPluginRecord } from "../policy/loader-policy.js"; import { planExtensionHostLoadedPlugin, runExtensionHostPluginRegister, diff --git a/src/extension-host/loader-register.ts b/src/extension-host/activation/loader-register.ts similarity index 90% rename from src/extension-host/loader-register.ts rename to src/extension-host/activation/loader-register.ts index 04596f3ff0f..049ab2ef960 100644 --- a/src/extension-host/loader-register.ts +++ b/src/extension-host/activation/loader-register.ts @@ -1,12 +1,11 @@ -import type { OpenClawConfig } from "../config/config.js"; -import type { PluginManifestRecord } from "../plugins/manifest-registry.js"; -import type { PluginRecord } from "../plugins/registry.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import type { PluginManifestRecord } from "../../plugins/manifest-registry.js"; +import type { PluginRecord } from "../../plugins/registry.js"; import type { OpenClawPluginApi, OpenClawPluginDefinition, - OpenClawPluginHookOptions, PluginDiagnostic, -} from "../plugins/types.js"; +} from "../../plugins/types.js"; import { applyExtensionHostDefinitionToRecord, resolveExtensionHostMemoryDecision, @@ -105,10 +104,11 @@ export function planExtensionHostLoadedPlugin(params: { value: params.entryConfig, }); if (!validatedConfig.ok) { + const errors = validatedConfig.errors ?? ["invalid config"]; return { kind: "invalid-config", - message: `invalid config: ${validatedConfig.errors.join(", ")}`, - errors: validatedConfig.errors, + message: `invalid config: ${errors.join(", ")}`, + errors, memorySlotMatched, selectedMemoryPluginId: nextSelectedMemoryPluginId, }; @@ -147,13 +147,13 @@ export function runExtensionHostPluginRegister(params: { options: { config: OpenClawConfig; pluginConfig?: Record; - hookPolicy?: OpenClawPluginHookOptions; + hookPolicy?: { allowPromptInjection?: boolean }; }, ) => OpenClawPluginApi; record: PluginRecord; config: OpenClawConfig; pluginConfig?: Record; - hookPolicy?: OpenClawPluginHookOptions; + hookPolicy?: { allowPromptInjection?: boolean }; diagnostics: PluginDiagnostic[]; }): | { diff --git a/src/extension-host/loader-run.test.ts b/src/extension-host/activation/loader-run.test.ts similarity index 95% rename from src/extension-host/loader-run.test.ts rename to src/extension-host/activation/loader-run.test.ts index a2af4a87c42..656ff501584 100644 --- a/src/extension-host/loader-run.test.ts +++ b/src/extension-host/activation/loader-run.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, vi } from "vitest"; -import type { PluginRegistry } from "../plugins/registry.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; import { runExtensionHostLoaderSession } from "./loader-run.js"; vi.mock("./loader-session.js", () => ({ diff --git a/src/extension-host/loader-run.ts b/src/extension-host/activation/loader-run.ts similarity index 78% rename from src/extension-host/loader-run.ts rename to src/extension-host/activation/loader-run.ts index 4af971ad143..14a51539eb5 100644 --- a/src/extension-host/loader-run.ts +++ b/src/extension-host/activation/loader-run.ts @@ -1,6 +1,7 @@ -import type { OpenClawConfig } from "../config/config.js"; -import type { PluginRecord } from "../plugins/registry.js"; -import type { OpenClawPluginApi, OpenClawPluginModule } from "../plugins/types.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import type { NormalizedPluginsConfig } from "../../plugins/config-state.js"; +import type { PluginRecord } from "../../plugins/registry.js"; +import type { OpenClawPluginApi, OpenClawPluginModule } from "../../plugins/types.js"; import type { ExtensionHostLoaderSession } from "./loader-session.js"; import { finalizeExtensionHostLoaderSession, @@ -13,21 +14,7 @@ export function runExtensionHostLoaderSession(params: { rootDir: string; }>; manifestByRoot: Map; - normalizedConfig: { - entries: Record< - string, - { - enabled?: boolean; - hooks?: { - allowPromptInjection?: boolean; - }; - config?: unknown; - } - >; - slots: { - memory?: string | null; - }; - }; + normalizedConfig: NormalizedPluginsConfig; rootConfig: OpenClawConfig; validateOnly: boolean; createApi: ( diff --git a/src/extension-host/loader-runtime-proxy.test.ts b/src/extension-host/activation/loader-runtime-proxy.test.ts similarity index 100% rename from src/extension-host/loader-runtime-proxy.test.ts rename to src/extension-host/activation/loader-runtime-proxy.test.ts diff --git a/src/extension-host/loader-runtime-proxy.ts b/src/extension-host/activation/loader-runtime-proxy.ts similarity index 94% rename from src/extension-host/loader-runtime-proxy.ts rename to src/extension-host/activation/loader-runtime-proxy.ts index 05036e4c22f..7fd6a498dbb 100644 --- a/src/extension-host/loader-runtime-proxy.ts +++ b/src/extension-host/activation/loader-runtime-proxy.ts @@ -1,4 +1,4 @@ -import type { PluginRuntime } from "../plugins/runtime/types.js"; +import type { PluginRuntime } from "../../plugins/runtime/types.js"; export function createExtensionHostLazyRuntime(params: { runtimeOptions?: TOptions; diff --git a/src/extension-host/loader-runtime.test.ts b/src/extension-host/activation/loader-runtime.test.ts similarity index 97% rename from src/extension-host/loader-runtime.test.ts rename to src/extension-host/activation/loader-runtime.test.ts index 74908641de8..9792a975a42 100644 --- a/src/extension-host/loader-runtime.test.ts +++ b/src/extension-host/activation/loader-runtime.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { createExtensionHostPluginRecord } from "./loader-policy.js"; +import { createExtensionHostPluginRecord } from "../policy/loader-policy.js"; import { applyExtensionHostDefinitionToRecord, resolveExtensionHostEarlyMemoryDecision, diff --git a/src/extension-host/loader-runtime.ts b/src/extension-host/activation/loader-runtime.ts similarity index 91% rename from src/extension-host/loader-runtime.ts rename to src/extension-host/activation/loader-runtime.ts index 799b97c59be..46de40878b6 100644 --- a/src/extension-host/loader-runtime.ts +++ b/src/extension-host/activation/loader-runtime.ts @@ -1,7 +1,7 @@ -import { resolveMemorySlotDecision } from "../plugins/config-state.js"; -import type { PluginRecord } from "../plugins/registry.js"; -import { validateJsonSchemaValue } from "../plugins/schema-validator.js"; -import type { OpenClawPluginDefinition, PluginDiagnostic } from "../plugins/types.js"; +import { resolveMemorySlotDecision } from "../../plugins/config-state.js"; +import type { PluginRecord } from "../../plugins/registry.js"; +import { validateJsonSchemaValue } from "../../plugins/schema-validator.js"; +import type { OpenClawPluginDefinition, PluginDiagnostic } from "../../plugins/types.js"; export function validateExtensionHostConfig(params: { schema?: Record; @@ -87,7 +87,7 @@ export function resolveExtensionHostEarlyMemoryDecision(params: { origin: PluginRecord["origin"]; manifestKind?: PluginRecord["kind"]; recordId: string; - memorySlot?: string; + memorySlot?: string | null; selectedMemoryPluginId: string | null; }): { enabled: boolean; reason?: string } { if (params.origin !== "bundled" || params.manifestKind !== "memory") { @@ -108,7 +108,7 @@ export function resolveExtensionHostEarlyMemoryDecision(params: { export function resolveExtensionHostMemoryDecision(params: { recordId: string; recordKind?: PluginRecord["kind"]; - memorySlot?: string; + memorySlot?: string | null; selectedMemoryPluginId: string | null; }): { enabled: boolean; selected: boolean; reason?: string } { const decision = resolveMemorySlotDecision({ @@ -119,7 +119,7 @@ export function resolveExtensionHostMemoryDecision(params: { }); return { enabled: decision.enabled, - selected: decision.selected, + selected: decision.selected === true, ...(decision.enabled ? {} : { reason: decision.reason }), }; } diff --git a/src/extension-host/loader-session.test.ts b/src/extension-host/activation/loader-session.test.ts similarity index 94% rename from src/extension-host/loader-session.test.ts rename to src/extension-host/activation/loader-session.test.ts index e4fe23830ca..f44d174a9ef 100644 --- a/src/extension-host/loader-session.test.ts +++ b/src/extension-host/activation/loader-session.test.ts @@ -2,9 +2,9 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import { normalizePluginsConfig } from "../plugins/config-state.js"; -import type { PluginManifestRecord } from "../plugins/manifest-registry.js"; -import type { PluginRegistry } from "../plugins/registry.js"; +import { normalizePluginsConfig } from "../../plugins/config-state.js"; +import type { PluginManifestRecord } from "../../plugins/manifest-registry.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; import { createExtensionHostLoaderSession, finalizeExtensionHostLoaderSession, diff --git a/src/extension-host/loader-session.ts b/src/extension-host/activation/loader-session.ts similarity index 83% rename from src/extension-host/loader-session.ts rename to src/extension-host/activation/loader-session.ts index e8eaec3ee4c..298085987b1 100644 --- a/src/extension-host/loader-session.ts +++ b/src/extension-host/activation/loader-session.ts @@ -1,11 +1,12 @@ -import type { OpenClawConfig } from "../config/config.js"; -import type { PluginCandidate } from "../plugins/discovery.js"; -import type { PluginManifestRecord } from "../plugins/manifest-registry.js"; -import type { PluginRecord, PluginRegistry } from "../plugins/registry.js"; -import type { OpenClawPluginApi, OpenClawPluginModule, PluginLogger } from "../plugins/types.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import type { NormalizedPluginsConfig } from "../../plugins/config-state.js"; +import type { PluginCandidate } from "../../plugins/discovery.js"; +import type { PluginManifestRecord } from "../../plugins/manifest-registry.js"; +import type { PluginRecord, PluginRegistry } from "../../plugins/registry.js"; +import type { OpenClawPluginApi, OpenClawPluginModule, PluginLogger } from "../../plugins/types.js"; +import type { ExtensionHostProvenanceIndex } from "../policy/loader-provenance.js"; import { finalizeExtensionHostRegistryLoad } from "./loader-finalize.js"; import { processExtensionHostPluginCandidate } from "./loader-flow.js"; -import type { ExtensionHostProvenanceIndex } from "./loader-policy.js"; export type ExtensionHostLoaderSession = { registry: PluginRegistry; @@ -53,21 +54,7 @@ export function processExtensionHostLoaderSessionCandidate(params: { session: ExtensionHostLoaderSession; candidate: PluginCandidate; manifestRecord: PluginManifestRecord; - normalizedConfig: { - entries: Record< - string, - { - enabled?: boolean; - hooks?: { - allowPromptInjection?: boolean; - }; - config?: unknown; - } - >; - slots: { - memory?: string | null; - }; - }; + normalizedConfig: NormalizedPluginsConfig; rootConfig: OpenClawConfig; validateOnly: boolean; createApi: ( diff --git a/src/extension-host/loader-state.test.ts b/src/extension-host/activation/loader-state.test.ts similarity index 96% rename from src/extension-host/loader-state.test.ts rename to src/extension-host/activation/loader-state.test.ts index 84c8383722a..eac602d1905 100644 --- a/src/extension-host/loader-state.test.ts +++ b/src/extension-host/activation/loader-state.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import type { PluginRegistry } from "../plugins/registry.js"; -import { createExtensionHostPluginRecord } from "./loader-policy.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; +import { createExtensionHostPluginRecord } from "../policy/loader-policy.js"; import { appendExtensionHostPluginRecord, markExtensionHostRegistryPluginsReady, diff --git a/src/extension-host/loader-state.ts b/src/extension-host/activation/loader-state.ts similarity index 98% rename from src/extension-host/loader-state.ts rename to src/extension-host/activation/loader-state.ts index 83b9c0856c9..348cae44508 100644 --- a/src/extension-host/loader-state.ts +++ b/src/extension-host/activation/loader-state.ts @@ -2,7 +2,7 @@ import type { PluginRecord, PluginRecordLifecycleState, PluginRegistry, -} from "../plugins/registry.js"; +} from "../../plugins/registry.js"; const EXTENSION_HOST_LIFECYCLE_STATUS_MAP: Record< PluginRecordLifecycleState, diff --git a/src/extension-host/hook-compat.test.ts b/src/extension-host/compat/hook-compat.test.ts similarity index 100% rename from src/extension-host/hook-compat.test.ts rename to src/extension-host/compat/hook-compat.test.ts diff --git a/src/extension-host/hook-compat.ts b/src/extension-host/compat/hook-compat.ts similarity index 95% rename from src/extension-host/hook-compat.ts rename to src/extension-host/compat/hook-compat.ts index 348e16aeaea..1dd66dc14e2 100644 --- a/src/extension-host/hook-compat.ts +++ b/src/extension-host/compat/hook-compat.ts @@ -1,13 +1,13 @@ -import { registerInternalHook, type InternalHookHandler } from "../hooks/internal-hooks.js"; +import { registerInternalHook, type InternalHookHandler } from "../../hooks/internal-hooks.js"; import type { PluginHookHandlerMap, PluginHookName, PluginHookRegistration as TypedPluginHookRegistration, -} from "../plugins/types.js"; +} from "../../plugins/types.js"; import { isPromptInjectionHookName, stripPromptMutationFieldsFromLegacyHookResult, -} from "../plugins/types.js"; +} from "../../plugins/types.js"; export function constrainExtensionHostPromptInjectionHook( handler: PluginHookHandlerMap["before_agent_start"], diff --git a/src/extension-host/loader-compat.ts b/src/extension-host/compat/loader-compat.ts similarity index 97% rename from src/extension-host/loader-compat.ts rename to src/extension-host/compat/loader-compat.ts index 60f750ed2f7..a03980b3e26 100644 --- a/src/extension-host/loader-compat.ts +++ b/src/extension-host/compat/loader-compat.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; -import { resolveOpenClawPackageRootSync } from "../infra/openclaw-root.js"; +import { resolveOpenClawPackageRootSync } from "../../infra/openclaw-root.js"; type PluginSdkAliasCandidateKind = "dist" | "src"; diff --git a/src/extension-host/plugin-api.test.ts b/src/extension-host/compat/plugin-api.test.ts similarity index 98% rename from src/extension-host/plugin-api.test.ts rename to src/extension-host/compat/plugin-api.test.ts index d05fbc1190d..c089f50a39a 100644 --- a/src/extension-host/plugin-api.test.ts +++ b/src/extension-host/compat/plugin-api.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, vi } from "vitest"; -import type { PluginRecord } from "../plugins/registry.js"; +import type { PluginRecord } from "../../plugins/registry.js"; import { createExtensionHostPluginApi, normalizeExtensionHostPluginLogger } from "./plugin-api.js"; function createRecord(): PluginRecord { diff --git a/src/extension-host/plugin-api.ts b/src/extension-host/compat/plugin-api.ts similarity index 84% rename from src/extension-host/plugin-api.ts rename to src/extension-host/compat/plugin-api.ts index dff59fd3cf6..7ea8488a035 100644 --- a/src/extension-host/plugin-api.ts +++ b/src/extension-host/compat/plugin-api.ts @@ -1,19 +1,21 @@ -import type { PluginRecord } from "../plugins/registry.js"; -import type { PluginRuntime } from "../plugins/runtime/types.js"; +import type { AnyAgentTool } from "../../agents/tools/common.js"; +import type { PluginRecord } from "../../plugins/registry.js"; +import type { PluginRuntime } from "../../plugins/runtime/types.js"; import type { OpenClawPluginApi, OpenClawPluginChannelRegistration, OpenClawPluginCliRegistrar, OpenClawPluginCommandDefinition, OpenClawPluginHttpRouteParams, + PluginInteractiveHandlerRegistration, OpenClawPluginService, OpenClawPluginToolFactory, PluginLogger, PluginHookName, PluginHookHandlerMap, ProviderPlugin, -} from "../plugins/types.js"; -import { resolveUserPath } from "../utils.js"; +} from "../../plugins/types.js"; +import { resolveUserPath } from "../../utils.js"; export function normalizeExtensionHostPluginLogger(logger: PluginLogger): PluginLogger { return { @@ -31,7 +33,7 @@ export function createExtensionHostPluginApi(params: { config: OpenClawPluginApi["config"]; pluginConfig?: Record; registerTool: ( - tool: OpenClawPluginToolFactory | { name: string }, + tool: OpenClawPluginToolFactory | AnyAgentTool, opts?: { name?: string; names?: string[]; optional?: boolean }, ) => void; registerHook: ( @@ -48,6 +50,7 @@ export function createExtensionHostPluginApi(params: { ? H : never, ) => void; + registerInteractiveHandler: (registration: PluginInteractiveHandlerRegistration) => void; registerCli: (registrar: OpenClawPluginCliRegistrar, opts?: { commands?: string[] }) => void; registerService: (service: OpenClawPluginService) => void; registerCommand: (command: OpenClawPluginCommandDefinition) => void; @@ -77,6 +80,7 @@ export function createExtensionHostPluginApi(params: { registerChannel: (registration) => params.registerChannel(registration), registerProvider: (provider) => params.registerProvider(provider), registerGatewayMethod: (method, handler) => params.registerGatewayMethod(method, handler), + registerInteractiveHandler: (registration) => params.registerInteractiveHandler(registration), registerCli: (registrar, opts) => params.registerCli(registrar, opts), registerService: (service) => params.registerService(service), registerCommand: (command) => params.registerCommand(command), diff --git a/src/extension-host/plugin-registry-compat.test.ts b/src/extension-host/compat/plugin-registry-compat.test.ts similarity index 96% rename from src/extension-host/plugin-registry-compat.test.ts rename to src/extension-host/compat/plugin-registry-compat.test.ts index c45313fb95f..d6d0a6a53a5 100644 --- a/src/extension-host/plugin-registry-compat.test.ts +++ b/src/extension-host/compat/plugin-registry-compat.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it, vi } from "vitest"; -import { clearPluginCommands } from "../plugins/commands.js"; -import { createEmptyPluginRegistry, type PluginRecord } from "../plugins/registry.js"; +import { clearPluginCommands } from "../../plugins/commands.js"; +import { createEmptyPluginRegistry, type PluginRecord } from "../../plugins/registry.js"; import { resolveExtensionHostCommandCompatibility, resolveExtensionHostProviderCompatibility, diff --git a/src/extension-host/plugin-registry-compat.ts b/src/extension-host/compat/plugin-registry-compat.ts similarity index 86% rename from src/extension-host/plugin-registry-compat.ts rename to src/extension-host/compat/plugin-registry-compat.ts index 0bb88c1c389..2eb0eaa6d2e 100644 --- a/src/extension-host/plugin-registry-compat.ts +++ b/src/extension-host/compat/plugin-registry-compat.ts @@ -1,18 +1,18 @@ -import { normalizeRegisteredProvider } from "../plugins/provider-validation.js"; -import type { PluginRecord, PluginRegistry } from "../plugins/registry.js"; +import { normalizeRegisteredProvider } from "../../plugins/provider-validation.js"; +import type { PluginRecord, PluginRegistry } from "../../plugins/registry.js"; import type { OpenClawPluginCommandDefinition, PluginDiagnostic, ProviderPlugin, -} from "../plugins/types.js"; -import { registerExtensionHostPluginCommand } from "./command-runtime.js"; +} from "../../plugins/types.js"; +import { registerExtensionHostPluginCommand } from "../contributions/command-runtime.js"; import { type ExtensionHostCommandRegistration, type ExtensionHostProviderRegistration, resolveExtensionCommandRegistration, resolveExtensionProviderRegistration, -} from "./runtime-registrations.js"; -import { listExtensionHostProviderRegistrations } from "./runtime-registry.js"; +} from "../contributions/runtime-registrations.js"; +import { listExtensionHostProviderRegistrations } from "../contributions/runtime-registry.js"; export function pushExtensionHostRegistryDiagnostic(params: { registry: PluginRegistry; diff --git a/src/extension-host/plugin-registry-registrations.test.ts b/src/extension-host/compat/plugin-registry-registrations.test.ts similarity index 98% rename from src/extension-host/plugin-registry-registrations.test.ts rename to src/extension-host/compat/plugin-registry-registrations.test.ts index 6604553d69e..837761fb2c2 100644 --- a/src/extension-host/plugin-registry-registrations.test.ts +++ b/src/extension-host/compat/plugin-registry-registrations.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { createEmptyPluginRegistry, type PluginRecord } from "../plugins/registry.js"; +import { createEmptyPluginRegistry, type PluginRecord } from "../../plugins/registry.js"; import { createExtensionHostPluginRegistrationActions } from "./plugin-registry-registrations.js"; function createRecord(): PluginRecord { diff --git a/src/extension-host/plugin-registry-registrations.ts b/src/extension-host/compat/plugin-registry-registrations.ts similarity index 93% rename from src/extension-host/plugin-registry-registrations.ts rename to src/extension-host/compat/plugin-registry-registrations.ts index 2f34c2de7c0..d98f45025d7 100644 --- a/src/extension-host/plugin-registry-registrations.ts +++ b/src/extension-host/compat/plugin-registry-registrations.ts @@ -1,9 +1,9 @@ -import type { AnyAgentTool } from "../agents/tools/common.js"; -import type { ChannelPlugin } from "../channels/plugins/types.js"; -import { registerContextEngine as registerLegacyContextEngine } from "../context-engine/registry.js"; -import type { GatewayRequestHandler } from "../gateway/server-methods/types.js"; -import { registerInternalHook } from "../hooks/internal-hooks.js"; -import type { PluginRecord, PluginRegistry } from "../plugins/registry.js"; +import type { AnyAgentTool } from "../../agents/tools/common.js"; +import type { ChannelPlugin } from "../../channels/plugins/types.js"; +import { registerContextEngine as registerLegacyContextEngine } from "../../context-engine/registry.js"; +import type { GatewayRequestHandler } from "../../gateway/server-methods/types.js"; +import { registerInternalHook } from "../../hooks/internal-hooks.js"; +import type { PluginRecord, PluginRegistry } from "../../plugins/registry.js"; import type { PluginHookHandlerMap, PluginHookName, @@ -15,12 +15,7 @@ import type { OpenClawPluginService, OpenClawPluginToolFactory, PluginHookRegistration as TypedPluginHookRegistration, -} from "../plugins/types.js"; -import { - applyExtensionHostTypedHookPolicy, - bridgeExtensionHostLegacyHooks, -} from "./hook-compat.js"; -import { pushExtensionHostRegistryDiagnostic } from "./plugin-registry-compat.js"; +} from "../../plugins/types.js"; import { addExtensionChannelRegistration, addExtensionCliRegistration, @@ -31,7 +26,7 @@ import { addExtensionServiceRegistration, addExtensionToolRegistration, addExtensionTypedHookRegistration, -} from "./registry-writes.js"; +} from "../contributions/registry-writes.js"; import { resolveExtensionChannelRegistration, resolveExtensionCliRegistration, @@ -42,12 +37,17 @@ import { resolveExtensionServiceRegistration, resolveExtensionToolRegistration, resolveExtensionTypedHookRegistration, -} from "./runtime-registrations.js"; +} from "../contributions/runtime-registrations.js"; import { listExtensionHostChannelRegistrations, getExtensionHostGatewayHandlers, listExtensionHostHttpRoutes, -} from "./runtime-registry.js"; +} from "../contributions/runtime-registry.js"; +import { + applyExtensionHostTypedHookPolicy, + bridgeExtensionHostLegacyHooks, +} from "./hook-compat.js"; +import { pushExtensionHostRegistryDiagnostic } from "./plugin-registry-compat.js"; export type PluginTypedHookPolicy = { allowPromptInjection?: boolean; diff --git a/src/extension-host/plugin-registry.test.ts b/src/extension-host/compat/plugin-registry.test.ts similarity index 96% rename from src/extension-host/plugin-registry.test.ts rename to src/extension-host/compat/plugin-registry.test.ts index 9130e020fe6..b36abad1fe7 100644 --- a/src/extension-host/plugin-registry.test.ts +++ b/src/extension-host/compat/plugin-registry.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it, vi } from "vitest"; -import { clearPluginCommands } from "../plugins/commands.js"; -import { createEmptyPluginRegistry, type PluginRecord } from "../plugins/registry.js"; +import { clearPluginCommands } from "../../plugins/commands.js"; +import { createEmptyPluginRegistry, type PluginRecord } from "../../plugins/registry.js"; import { createExtensionHostPluginRegistry } from "./plugin-registry.js"; function createRecord(): PluginRecord { diff --git a/src/extension-host/plugin-registry.ts b/src/extension-host/compat/plugin-registry.ts similarity index 83% rename from src/extension-host/plugin-registry.ts rename to src/extension-host/compat/plugin-registry.ts index b4d1b55e8f3..be2a8814574 100644 --- a/src/extension-host/plugin-registry.ts +++ b/src/extension-host/compat/plugin-registry.ts @@ -1,10 +1,16 @@ -import type { PluginRecord, PluginRegistry, PluginRegistryParams } from "../plugins/registry.js"; +import { registerPluginInteractiveHandler } from "../../plugins/interactive.js"; +import type { PluginRecord, PluginRegistry, PluginRegistryParams } from "../../plugins/registry.js"; import type { PluginDiagnostic, OpenClawPluginApi, OpenClawPluginCommandDefinition, + PluginInteractiveHandlerRegistration, ProviderPlugin, -} from "../plugins/types.js"; +} from "../../plugins/types.js"; +import { + addExtensionCommandRegistration, + addExtensionProviderRegistration, +} from "../contributions/registry-writes.js"; import { createExtensionHostPluginApi } from "./plugin-api.js"; import { resolveExtensionHostCommandCompatibility, @@ -14,10 +20,6 @@ import { createExtensionHostPluginRegistrationActions, type PluginTypedHookPolicy, } from "./plugin-registry-registrations.js"; -import { - addExtensionCommandRegistration, - addExtensionProviderRegistration, -} from "./registry-writes.js"; export function createExtensionHostPluginRegistry(params: { registry: PluginRegistry; @@ -85,6 +87,20 @@ export function createExtensionHostPluginRegistry(params: { registerProvider: (provider) => registerProvider(record, provider), registerGatewayMethod: (method, handler) => actions.registerGatewayMethod(record, method, handler), + registerInteractiveHandler: (registration: PluginInteractiveHandlerRegistration) => { + const result = registerPluginInteractiveHandler(record.id, registration, { + pluginName: record.name, + pluginRoot: record.rootDir, + }); + if (!result.ok) { + pushDiagnostic({ + level: "warn", + pluginId: record.id, + source: record.source, + message: result.error ?? "interactive handler registration failed", + }); + } + }, registerCli: (registrar, opts) => actions.registerCli(record, registrar, opts), registerService: (service) => actions.registerService(record, service), registerCommand: (command) => registerCommand(record, command), diff --git a/src/extension-host/cli-lifecycle.test.ts b/src/extension-host/contributions/cli-lifecycle.test.ts similarity index 94% rename from src/extension-host/cli-lifecycle.test.ts rename to src/extension-host/contributions/cli-lifecycle.test.ts index 465efd9d623..504a9bce6bc 100644 --- a/src/extension-host/cli-lifecycle.test.ts +++ b/src/extension-host/contributions/cli-lifecycle.test.ts @@ -1,7 +1,7 @@ import { Command } from "commander"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import { createEmptyPluginRegistry } from "../plugins/registry.js"; -import type { PluginLogger } from "../plugins/types.js"; +import { createEmptyPluginRegistry } from "../../plugins/registry.js"; +import type { PluginLogger } from "../../plugins/types.js"; import { registerExtensionHostCliCommands } from "./cli-lifecycle.js"; function createLogger(): PluginLogger { diff --git a/src/extension-host/cli-lifecycle.ts b/src/extension-host/contributions/cli-lifecycle.ts similarity index 88% rename from src/extension-host/cli-lifecycle.ts rename to src/extension-host/contributions/cli-lifecycle.ts index bac6a4f6ffd..665db1b2f2e 100644 --- a/src/extension-host/cli-lifecycle.ts +++ b/src/extension-host/contributions/cli-lifecycle.ts @@ -1,7 +1,7 @@ import type { Command } from "commander"; -import type { OpenClawConfig } from "../config/config.js"; -import type { PluginRegistry } from "../plugins/registry.js"; -import type { PluginLogger } from "../plugins/types.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; +import type { PluginLogger } from "../../plugins/types.js"; import { listExtensionHostCliRegistrations } from "./runtime-registry.js"; export function registerExtensionHostCliCommands(params: { diff --git a/src/extension-host/command-runtime.test.ts b/src/extension-host/contributions/command-runtime.test.ts similarity index 100% rename from src/extension-host/command-runtime.test.ts rename to src/extension-host/contributions/command-runtime.test.ts diff --git a/src/extension-host/command-runtime.ts b/src/extension-host/contributions/command-runtime.ts similarity index 94% rename from src/extension-host/command-runtime.ts rename to src/extension-host/contributions/command-runtime.ts index d57c988a4fc..afa666fc241 100644 --- a/src/extension-host/command-runtime.ts +++ b/src/extension-host/contributions/command-runtime.ts @@ -1,10 +1,10 @@ -import type { OpenClawConfig } from "../config/config.js"; -import { logVerbose } from "../globals.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import { logVerbose } from "../../globals.js"; import type { OpenClawPluginCommandDefinition, PluginCommandContext, PluginCommandResult, -} from "../plugins/types.js"; +} from "../../plugins/types.js"; export type RegisteredExtensionHostPluginCommand = OpenClawPluginCommandDefinition & { pluginId: string; @@ -210,6 +210,12 @@ export async function executeExtensionHostPluginCommand(params: { to: params.to, accountId: params.accountId, messageThreadId: params.messageThreadId, + requestConversationBinding: async () => ({ + status: "error" as const, + message: "Conversation binding is unavailable for this command surface.", + }), + detachConversationBinding: async () => ({ removed: false }), + getCurrentConversationBinding: async () => null, }; extensionHostCommandRegistryLocked = true; diff --git a/src/extension-host/gateway-methods.test.ts b/src/extension-host/contributions/gateway-methods.test.ts similarity index 96% rename from src/extension-host/gateway-methods.test.ts rename to src/extension-host/contributions/gateway-methods.test.ts index 5c9b0b0b57f..e1704749b17 100644 --- a/src/extension-host/gateway-methods.test.ts +++ b/src/extension-host/contributions/gateway-methods.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, vi } from "vitest"; -import { createEmptyPluginRegistry } from "../plugins/registry.js"; +import { createEmptyPluginRegistry } from "../../plugins/registry.js"; import { createExtensionHostGatewayExtraHandlers, logExtensionHostPluginDiagnostics, diff --git a/src/extension-host/gateway-methods.ts b/src/extension-host/contributions/gateway-methods.ts similarity index 86% rename from src/extension-host/gateway-methods.ts rename to src/extension-host/contributions/gateway-methods.ts index 0198227118c..5ab034e32c4 100644 --- a/src/extension-host/gateway-methods.ts +++ b/src/extension-host/contributions/gateway-methods.ts @@ -1,6 +1,6 @@ -import type { GatewayRequestHandlers } from "../gateway/server-methods/types.js"; -import type { PluginRegistry } from "../plugins/registry.js"; -import type { PluginDiagnostic } from "../plugins/types.js"; +import type { GatewayRequestHandlers } from "../../gateway/server-methods/types.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; +import type { PluginDiagnostic } from "../../plugins/types.js"; import { getExtensionHostGatewayHandlers } from "./runtime-registry.js"; export function resolveExtensionHostGatewayMethods(params: { diff --git a/src/extension-host/provider-auth-flow.ts b/src/extension-host/contributions/provider-auth-flow.ts similarity index 89% rename from src/extension-host/provider-auth-flow.ts rename to src/extension-host/contributions/provider-auth-flow.ts index 7cc80bc8854..a8262c41ab9 100644 --- a/src/extension-host/provider-auth-flow.ts +++ b/src/extension-host/contributions/provider-auth-flow.ts @@ -1,23 +1,23 @@ -import { resolveOpenClawAgentDir } from "../agents/agent-paths.js"; +import { resolveOpenClawAgentDir } from "../../agents/agent-paths.js"; import { resolveDefaultAgentId, resolveAgentDir, resolveAgentWorkspaceDir, -} from "../agents/agent-scope.js"; -import { upsertAuthProfile } from "../agents/auth-profiles.js"; -import { resolveDefaultAgentWorkspaceDir } from "../agents/workspace.js"; +} from "../../agents/agent-scope.js"; +import { upsertAuthProfile } from "../../agents/auth-profiles.js"; +import { resolveDefaultAgentWorkspaceDir } from "../../agents/workspace.js"; import type { ApplyAuthChoiceParams, ApplyAuthChoiceResult, -} from "../commands/auth-choice.apply.js"; -import { isRemoteEnvironment } from "../commands/oauth-env.js"; -import { createVpsAwareOAuthHandlers } from "../commands/oauth-flow.js"; -import { applyAuthProfileConfig } from "../commands/onboard-auth.js"; -import { openUrl } from "../commands/onboard-helpers.js"; -import { enablePluginInConfig } from "../plugins/enable.js"; -import { resolveProviderPluginChoice } from "../plugins/provider-wizard.js"; -import { resolvePluginProviders } from "../plugins/providers.js"; -import type { ProviderAuthMethod } from "../plugins/types.js"; +} from "../../commands/auth-choice.apply.js"; +import { isRemoteEnvironment } from "../../commands/oauth-env.js"; +import { createVpsAwareOAuthHandlers } from "../../commands/oauth-flow.js"; +import { applyAuthProfileConfig } from "../../commands/onboard-auth.js"; +import { openUrl } from "../../commands/onboard-helpers.js"; +import { enablePluginInConfig } from "../../plugins/enable.js"; +import { resolveProviderPluginChoice } from "../../plugins/provider-wizard.js"; +import { resolvePluginProviders } from "../../plugins/providers.js"; +import type { ProviderAuthMethod } from "../../plugins/types.js"; import { applyExtensionHostDefaultModel, mergeExtensionHostConfigPatch, diff --git a/src/extension-host/provider-auth.test.ts b/src/extension-host/contributions/provider-auth.test.ts similarity index 98% rename from src/extension-host/provider-auth.test.ts rename to src/extension-host/contributions/provider-auth.test.ts index 20844620745..e049d877812 100644 --- a/src/extension-host/provider-auth.test.ts +++ b/src/extension-host/contributions/provider-auth.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, vi } from "vitest"; -import type { ProviderPlugin } from "../plugins/types.js"; +import type { ProviderPlugin } from "../../plugins/types.js"; import { applyExtensionHostDefaultModel, mergeExtensionHostConfigPatch, diff --git a/src/extension-host/provider-auth.ts b/src/extension-host/contributions/provider-auth.ts similarity index 91% rename from src/extension-host/provider-auth.ts rename to src/extension-host/contributions/provider-auth.ts index 1d9a926d365..9ac2947f8de 100644 --- a/src/extension-host/provider-auth.ts +++ b/src/extension-host/contributions/provider-auth.ts @@ -1,6 +1,6 @@ -import { normalizeProviderId } from "../agents/provider-id.js"; -import type { OpenClawConfig } from "../config/config.js"; -import type { ProviderAuthMethod, ProviderPlugin } from "../plugins/types.js"; +import { normalizeProviderId } from "../../agents/provider-id.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import type { ProviderAuthMethod, ProviderPlugin } from "../../plugins/types.js"; export function resolveExtensionHostProviderMatch( providers: ProviderPlugin[], diff --git a/src/extension-host/provider-discovery.test.ts b/src/extension-host/contributions/provider-discovery.test.ts similarity index 97% rename from src/extension-host/provider-discovery.test.ts rename to src/extension-host/contributions/provider-discovery.test.ts index dec3d6a96d0..cde7c52b822 100644 --- a/src/extension-host/provider-discovery.test.ts +++ b/src/extension-host/contributions/provider-discovery.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import type { ModelProviderConfig } from "../config/types.js"; -import type { ProviderDiscoveryOrder, ProviderPlugin } from "../plugins/types.js"; +import type { ModelProviderConfig } from "../../config/types.js"; +import type { ProviderDiscoveryOrder, ProviderPlugin } from "../../plugins/types.js"; import { groupExtensionHostDiscoveryProvidersByOrder, normalizeExtensionHostDiscoveryResult, diff --git a/src/extension-host/provider-discovery.ts b/src/extension-host/contributions/provider-discovery.ts similarity index 91% rename from src/extension-host/provider-discovery.ts rename to src/extension-host/contributions/provider-discovery.ts index 0eb59b14d5a..9846e304015 100644 --- a/src/extension-host/provider-discovery.ts +++ b/src/extension-host/contributions/provider-discovery.ts @@ -1,6 +1,6 @@ -import { normalizeProviderId } from "../agents/provider-id.js"; -import type { ModelProviderConfig } from "../config/types.js"; -import type { ProviderDiscoveryOrder, ProviderPlugin } from "../plugins/types.js"; +import { normalizeProviderId } from "../../agents/provider-id.js"; +import type { ModelProviderConfig } from "../../config/types.js"; +import type { ProviderDiscoveryOrder, ProviderPlugin } from "../../plugins/types.js"; const DISCOVERY_ORDER: readonly ProviderDiscoveryOrder[] = ["simple", "profile", "paired", "late"]; diff --git a/src/extension-host/provider-model-selection.ts b/src/extension-host/contributions/provider-model-selection.ts similarity index 69% rename from src/extension-host/provider-model-selection.ts rename to src/extension-host/contributions/provider-model-selection.ts index 0f970fe4988..cf78b4ab545 100644 --- a/src/extension-host/provider-model-selection.ts +++ b/src/extension-host/contributions/provider-model-selection.ts @@ -1,9 +1,9 @@ -import { DEFAULT_PROVIDER } from "../agents/defaults.js"; -import { parseModelRef } from "../agents/model-ref.js"; -import { normalizeProviderId } from "../agents/provider-id.js"; -import type { OpenClawConfig } from "../config/config.js"; -import { resolvePluginProviders } from "../plugins/providers.js"; -import type { WizardPrompter } from "../wizard/prompts.js"; +import { DEFAULT_PROVIDER } from "../../agents/defaults.js"; +import { parseModelRef } from "../../agents/model-ref.js"; +import { normalizeProviderId } from "../../agents/provider-id.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import { resolvePluginProviders } from "../../plugins/providers.js"; +import type { WizardPrompter } from "../../wizard/prompts.js"; export async function runExtensionHostProviderModelSelectedHook(params: { config: OpenClawConfig; diff --git a/src/extension-host/provider-runtime.test.ts b/src/extension-host/contributions/provider-runtime.test.ts similarity index 92% rename from src/extension-host/provider-runtime.test.ts rename to src/extension-host/contributions/provider-runtime.test.ts index 1ad3f211efa..722375219e6 100644 --- a/src/extension-host/provider-runtime.test.ts +++ b/src/extension-host/contributions/provider-runtime.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { createEmptyPluginRegistry } from "../plugins/registry.js"; +import { createEmptyPluginRegistry } from "../../plugins/registry.js"; import { resolveExtensionHostProviders } from "./provider-runtime.js"; import { addExtensionHostProviderRegistration } from "./runtime-registry.js"; diff --git a/src/extension-host/contributions/provider-runtime.ts b/src/extension-host/contributions/provider-runtime.ts new file mode 100644 index 00000000000..ab45a16e05e --- /dev/null +++ b/src/extension-host/contributions/provider-runtime.ts @@ -0,0 +1,22 @@ +import type { PluginRegistry } from "../../plugins/registry.js"; +import type { ProviderPlugin } from "../../plugins/types.js"; +import { listExtensionHostProviderRegistrations } from "./runtime-registry.js"; + +export function resolveExtensionHostProviders(params: { + registry: Pick< + PluginRegistry, + | "channels" + | "tools" + | "providers" + | "cliRegistrars" + | "commands" + | "services" + | "httpRoutes" + | "gatewayHandlers" + >; +}): ProviderPlugin[] { + return listExtensionHostProviderRegistrations(params.registry).map((entry) => ({ + ...entry.provider, + pluginId: entry.pluginId, + })); +} diff --git a/src/extension-host/provider-wizard.test.ts b/src/extension-host/contributions/provider-wizard.test.ts similarity index 97% rename from src/extension-host/provider-wizard.test.ts rename to src/extension-host/contributions/provider-wizard.test.ts index 000e4b6af8a..aa6e499122d 100644 --- a/src/extension-host/provider-wizard.test.ts +++ b/src/extension-host/contributions/provider-wizard.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, vi } from "vitest"; -import type { ProviderPlugin } from "../plugins/types.js"; +import type { ProviderPlugin } from "../../plugins/types.js"; import { buildExtensionHostProviderMethodChoice, resolveExtensionHostProviderChoice, diff --git a/src/extension-host/provider-wizard.ts b/src/extension-host/contributions/provider-wizard.ts similarity index 98% rename from src/extension-host/provider-wizard.ts rename to src/extension-host/contributions/provider-wizard.ts index 4fc87576038..afb5fd9055c 100644 --- a/src/extension-host/provider-wizard.ts +++ b/src/extension-host/contributions/provider-wizard.ts @@ -1,10 +1,10 @@ -import { normalizeProviderId } from "../agents/provider-id.js"; +import { normalizeProviderId } from "../../agents/provider-id.js"; import type { ProviderAuthMethod, ProviderPlugin, ProviderPluginWizardModelPicker, ProviderPluginWizardOnboarding, -} from "../plugins/types.js"; +} from "../../plugins/types.js"; export const EXTENSION_HOST_PROVIDER_CHOICE_PREFIX = "provider-plugin:"; diff --git a/src/extension-host/registry-writes.test.ts b/src/extension-host/contributions/registry-writes.test.ts similarity index 99% rename from src/extension-host/registry-writes.test.ts rename to src/extension-host/contributions/registry-writes.test.ts index f7877504e52..7d96daa361a 100644 --- a/src/extension-host/registry-writes.test.ts +++ b/src/extension-host/contributions/registry-writes.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, vi } from "vitest"; -import { createEmptyPluginRegistry, type PluginRecord } from "../plugins/registry.js"; +import { createEmptyPluginRegistry, type PluginRecord } from "../../plugins/registry.js"; import { addExtensionChannelRegistration, addExtensionCliRegistration, diff --git a/src/extension-host/registry-writes.ts b/src/extension-host/contributions/registry-writes.ts similarity index 96% rename from src/extension-host/registry-writes.ts rename to src/extension-host/contributions/registry-writes.ts index 6cc37e0e5e3..3e7d4e35ced 100644 --- a/src/extension-host/registry-writes.ts +++ b/src/extension-host/contributions/registry-writes.ts @@ -1,5 +1,5 @@ -import { registerContextEngine, type ContextEngineFactory } from "../context-engine/registry.js"; -import type { GatewayRequestHandler } from "../gateway/server-methods/types.js"; +import { registerContextEngine, type ContextEngineFactory } from "../../context-engine/registry.js"; +import type { GatewayRequestHandler } from "../../gateway/server-methods/types.js"; import type { PluginChannelRegistration, PluginCliRegistration, @@ -11,8 +11,8 @@ import type { PluginProviderRegistration, PluginServiceRegistration, PluginToolRegistration, -} from "../plugins/registry.js"; -import type { PluginHookRegistration as TypedPluginHookRegistration } from "../plugins/types.js"; +} from "../../plugins/registry.js"; +import type { PluginHookRegistration as TypedPluginHookRegistration } from "../../plugins/types.js"; import type { ExtensionHostChannelRegistration, ExtensionHostCliRegistration, diff --git a/src/extension-host/runtime-registrations.test.ts b/src/extension-host/contributions/runtime-registrations.test.ts similarity index 97% rename from src/extension-host/runtime-registrations.test.ts rename to src/extension-host/contributions/runtime-registrations.test.ts index 9b75e2fdf09..6a81f95980c 100644 --- a/src/extension-host/runtime-registrations.test.ts +++ b/src/extension-host/contributions/runtime-registrations.test.ts @@ -1,9 +1,9 @@ import { describe, expect, it, vi } from "vitest"; -import type { AnyAgentTool } from "../agents/tools/common.js"; -import type { ChannelPlugin } from "../channels/plugins/types.js"; -import type { ContextEngineFactory } from "../context-engine/registry.js"; -import type { InternalHookHandler } from "../hooks/internal-hooks.js"; -import type { HookEntry } from "../hooks/types.js"; +import type { AnyAgentTool } from "../../agents/tools/common.js"; +import type { ChannelPlugin } from "../../channels/plugins/types.js"; +import type { ContextEngineFactory } from "../../context-engine/registry.js"; +import type { InternalHookHandler } from "../../hooks/internal-hooks.js"; +import type { HookEntry } from "../../hooks/types.js"; import type { OpenClawPluginCliContext, OpenClawPluginCommandDefinition, @@ -11,7 +11,7 @@ import type { OpenClawPluginService, PluginHookRegistration, ProviderPlugin, -} from "../plugins/types.js"; +} from "../../plugins/types.js"; import { resolveExtensionChannelRegistration, resolveExtensionCliRegistration, diff --git a/src/extension-host/runtime-registrations.ts b/src/extension-host/contributions/runtime-registrations.ts similarity index 93% rename from src/extension-host/runtime-registrations.ts rename to src/extension-host/contributions/runtime-registrations.ts index cd7342f4466..a1107ac3cb6 100644 --- a/src/extension-host/runtime-registrations.ts +++ b/src/extension-host/contributions/runtime-registrations.ts @@ -1,16 +1,16 @@ import path from "node:path"; -import type { AnyAgentTool } from "../agents/tools/common.js"; -import type { ChannelDock } from "../channels/dock.js"; -import type { ChannelPlugin } from "../channels/plugins/types.js"; -import type { ContextEngineFactory } from "../context-engine/registry.js"; +import type { AnyAgentTool } from "../../agents/tools/common.js"; +import type { ChannelDock } from "../../channels/dock.js"; +import type { ChannelPlugin } from "../../channels/plugins/types.js"; +import type { ContextEngineFactory } from "../../context-engine/registry.js"; import type { GatewayRequestHandler, GatewayRequestHandlers, -} from "../gateway/server-methods/types.js"; -import type { InternalHookHandler } from "../hooks/internal-hooks.js"; -import type { HookEntry } from "../hooks/types.js"; -import { normalizePluginHttpPath } from "../plugins/http-path.js"; -import { findOverlappingPluginHttpRoute } from "../plugins/http-route-overlap.js"; +} from "../../gateway/server-methods/types.js"; +import type { InternalHookHandler } from "../../hooks/internal-hooks.js"; +import type { HookEntry } from "../../hooks/types.js"; +import { normalizePluginHttpPath } from "../../plugins/http-path.js"; +import { findOverlappingPluginHttpRoute } from "../../plugins/http-route-overlap.js"; import type { OpenClawPluginCliRegistrar, OpenClawPluginCommandDefinition, @@ -27,8 +27,8 @@ import type { PluginHookName, PluginHookRegistration, ProviderPlugin, -} from "../plugins/types.js"; -import { isPluginHookName } from "../plugins/types.js"; +} from "../../plugins/types.js"; +import { isPluginHookName } from "../../plugins/types.js"; export type ExtensionHostChannelRegistration = { pluginId: string; @@ -110,10 +110,13 @@ export function resolveExtensionToolRegistration(params: { names.push(params.tool.name); } const normalizedNames = normalizeNameList(names); - const factory: OpenClawPluginToolFactory = - typeof params.tool === "function" - ? params.tool - : (_ctx: OpenClawPluginToolContext) => params.tool; + let factory: OpenClawPluginToolFactory; + if (typeof params.tool === "function") { + factory = params.tool; + } else { + const tool = params.tool; + factory = (_ctx: OpenClawPluginToolContext) => tool; + } return { names: normalizedNames, diff --git a/src/extension-host/runtime-registry.test.ts b/src/extension-host/contributions/runtime-registry.test.ts similarity index 99% rename from src/extension-host/runtime-registry.test.ts rename to src/extension-host/contributions/runtime-registry.test.ts index 0a7547bc9d3..2d1e982f7fe 100644 --- a/src/extension-host/runtime-registry.test.ts +++ b/src/extension-host/contributions/runtime-registry.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, vi } from "vitest"; -import { createEmptyPluginRegistry } from "../plugins/registry.js"; +import { createEmptyPluginRegistry } from "../../plugins/registry.js"; import { addExtensionHostChannelRegistration, addExtensionHostCliRegistration, diff --git a/src/extension-host/runtime-registry.ts b/src/extension-host/contributions/runtime-registry.ts similarity index 99% rename from src/extension-host/runtime-registry.ts rename to src/extension-host/contributions/runtime-registry.ts index 34601d7820d..919ab3823d9 100644 --- a/src/extension-host/runtime-registry.ts +++ b/src/extension-host/contributions/runtime-registry.ts @@ -1,4 +1,4 @@ -import type { GatewayRequestHandlers } from "../gateway/server-methods/types.js"; +import type { GatewayRequestHandlers } from "../../gateway/server-methods/types.js"; import type { PluginChannelRegistration, PluginCliRegistration, @@ -8,7 +8,7 @@ import type { PluginRegistry, PluginServiceRegistration, PluginToolRegistration, -} from "../plugins/registry.js"; +} from "../../plugins/registry.js"; const EMPTY_PROVIDERS: readonly PluginProviderRegistration[] = []; const EMPTY_TOOLS: readonly PluginToolRegistration[] = []; diff --git a/src/extension-host/service-lifecycle.test.ts b/src/extension-host/contributions/service-lifecycle.test.ts similarity index 94% rename from src/extension-host/service-lifecycle.test.ts rename to src/extension-host/contributions/service-lifecycle.test.ts index 647afc589d3..37b2da2f328 100644 --- a/src/extension-host/service-lifecycle.test.ts +++ b/src/extension-host/contributions/service-lifecycle.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import { createEmptyPluginRegistry } from "../plugins/registry.js"; -import type { OpenClawPluginService, OpenClawPluginServiceContext } from "../plugins/types.js"; +import { createEmptyPluginRegistry } from "../../plugins/registry.js"; +import type { OpenClawPluginService, OpenClawPluginServiceContext } from "../../plugins/types.js"; const mockedLogger = vi.hoisted(() => ({ info: vi.fn<(msg: string) => void>(), @@ -9,11 +9,11 @@ const mockedLogger = vi.hoisted(() => ({ debug: vi.fn<(msg: string) => void>(), })); -vi.mock("../logging/subsystem.js", () => ({ +vi.mock("../../logging/subsystem.js", () => ({ createSubsystemLogger: () => mockedLogger, })); -import { STATE_DIR } from "../config/paths.js"; +import { STATE_DIR } from "../../config/paths.js"; import { startExtensionHostServices } from "./service-lifecycle.js"; function createRegistry(services: OpenClawPluginService[]) { diff --git a/src/extension-host/service-lifecycle.ts b/src/extension-host/contributions/service-lifecycle.ts similarity index 87% rename from src/extension-host/service-lifecycle.ts rename to src/extension-host/contributions/service-lifecycle.ts index 2b59078d379..3c6d1ccf101 100644 --- a/src/extension-host/service-lifecycle.ts +++ b/src/extension-host/contributions/service-lifecycle.ts @@ -1,8 +1,8 @@ -import type { OpenClawConfig } from "../config/config.js"; -import { STATE_DIR } from "../config/paths.js"; -import { createSubsystemLogger } from "../logging/subsystem.js"; -import type { PluginRegistry } from "../plugins/registry.js"; -import type { OpenClawPluginServiceContext, PluginLogger } from "../plugins/types.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import { STATE_DIR } from "../../config/paths.js"; +import { createSubsystemLogger } from "../../logging/subsystem.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; +import type { OpenClawPluginServiceContext, PluginLogger } from "../../plugins/types.js"; import { listExtensionHostServiceRegistrations } from "./runtime-registry.js"; const log = createSubsystemLogger("plugins"); diff --git a/src/extension-host/tool-runtime.test.ts b/src/extension-host/contributions/tool-runtime.test.ts similarity index 96% rename from src/extension-host/tool-runtime.test.ts rename to src/extension-host/contributions/tool-runtime.test.ts index cd6af8eeb66..d16020a47f8 100644 --- a/src/extension-host/tool-runtime.test.ts +++ b/src/extension-host/contributions/tool-runtime.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it, vi } from "vitest"; -import type { AnyAgentTool } from "../agents/tools/common.js"; -import { createEmptyPluginRegistry } from "../plugins/registry.js"; +import type { AnyAgentTool } from "../../agents/tools/common.js"; +import { createEmptyPluginRegistry } from "../../plugins/registry.js"; import { addExtensionHostToolRegistration } from "./runtime-registry.js"; import { getExtensionHostPluginToolMeta, resolveExtensionHostPluginTools } from "./tool-runtime.js"; diff --git a/src/extension-host/tool-runtime.ts b/src/extension-host/contributions/tool-runtime.ts similarity index 86% rename from src/extension-host/tool-runtime.ts rename to src/extension-host/contributions/tool-runtime.ts index 226a6552ecb..2018be901f5 100644 --- a/src/extension-host/tool-runtime.ts +++ b/src/extension-host/contributions/tool-runtime.ts @@ -1,8 +1,8 @@ -import { normalizeToolName } from "../agents/tool-policy.js"; -import type { AnyAgentTool } from "../agents/tools/common.js"; -import { createSubsystemLogger } from "../logging/subsystem.js"; -import type { PluginRegistry } from "../plugins/registry.js"; -import type { OpenClawPluginToolContext } from "../plugins/types.js"; +import { normalizeToolName } from "../../agents/tool-policy.js"; +import type { AnyAgentTool } from "../../agents/tools/common.js"; +import { createSubsystemLogger } from "../../logging/subsystem.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; +import type { OpenClawPluginToolContext } from "../../plugins/types.js"; import { listExtensionHostToolRegistrations } from "./runtime-registry.js"; const log = createSubsystemLogger("plugins"); @@ -44,7 +44,18 @@ function isOptionalToolAllowed(params: { } export function resolveExtensionHostPluginTools(params: { - registry: Pick; + registry: Pick< + PluginRegistry, + | "channels" + | "tools" + | "providers" + | "cliRegistrars" + | "commands" + | "services" + | "httpRoutes" + | "gatewayHandlers" + | "diagnostics" + >; context: OpenClawPluginToolContext; existingToolNames?: Set; toolAllowlist?: string[]; diff --git a/src/extension-host/cutover-inventory.md b/src/extension-host/cutover-inventory.md index f51f9391f5a..76819fc44ec 100644 --- a/src/extension-host/cutover-inventory.md +++ b/src/extension-host/cutover-inventory.md @@ -25,85 +25,85 @@ This is an implementation checklist, not a future-design spec. ## Current Inventory -| Surface | Current implementation | Target owner | Status | How it has been handled so far | -| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Active runtime registry state | `src/plugins/runtime.ts` plus global plugin runtime state | `src/extension-host/active-registry.ts` | `moved` | Host-owned active registry exists; `src/plugins/runtime.ts` is now a compatibility facade. | -| Normalized extension descriptor model | plugin manifests and package metadata interpreted ad hoc across `src/plugins/manifest.ts`, `src/plugins/discovery.ts`, `src/plugins/install.ts` | `src/extension-host/schema.ts` | `partial` | `ResolvedExtension`, `ResolvedContribution`, and `ContributionPolicy` exist; current manifests project into them through compatibility adapters. | -| Resolved static registry | flat rows in `src/plugins/manifest-registry.ts` | `src/extension-host/resolved-registry.ts` | `partial` | Manifest records now carry `resolvedExtension`; a host-owned resolved registry view exists for static consumers. | -| Manifest/package metadata loading | `src/plugins/manifest.ts`, `src/plugins/discovery.ts`, `src/plugins/install.ts` | `src/extension-host/schema.ts` and `src/extension-host/manifest-registry.ts` | `partial` | Package metadata parsing is routed through host schema helpers; legacy loader flow still supplies the source manifests. | -| Loader SDK alias compatibility | `src/plugins/loader.ts` | `src/extension-host/loader-compat.ts` | `partial` | Plugin-SDK alias candidate ordering, alias-file resolution, and scoped alias-map construction now live in host-owned loader compatibility helpers. | -| Loader alias-wired module loader creation | `src/plugins/loader.ts` | `src/extension-host/loader-module-loader.ts` | `partial` | Lazy Jiti creation and SDK-alias-wired module loading now delegate through a host-owned loader-module-loader helper. | -| Loader cache key and registry cache control | `src/plugins/loader.ts` | `src/extension-host/loader-cache.ts` | `partial` | Cache-key construction, LRU registry cache reads and writes, and cache clearing now delegate through host-owned loader-cache helpers while preserving the current cache shape and cap. | -| Loader lazy runtime proxy creation | `src/plugins/loader.ts` | `src/extension-host/loader-runtime-proxy.ts` | `partial` | Lazy plugin runtime creation now delegates through a host-owned loader-runtime-proxy helper instead of remaining inline in the orchestrator. | -| Loader provenance and duplicate-order policy | `src/plugins/loader.ts` | `src/extension-host/loader-policy.ts` | `partial` | Plugin-record creation, duplicate precedence, and provenance indexing now live in host-owned loader-policy helpers. | -| Loader discovery policy results | mixed inside `src/extension-host/loader-policy.ts` and `src/extension-host/loader-orchestrator.ts` | `src/extension-host/loader-discovery-policy.ts` | `partial` | Open-allowlist discovery warnings now resolve through explicit host-owned discovery-policy results before the orchestrator logs them. | -| Loader initial candidate planning and record creation | `src/plugins/loader.ts` | `src/extension-host/loader-records.ts` | `partial` | Duplicate detection, initial record creation, manifest metadata attachment, and first-pass enable-state planning now delegate through host-owned loader-records helpers. | -| Loader entry-path opening and module import | `src/plugins/loader.ts` | `src/extension-host/loader-import.ts` | `partial` | Boundary-checked entry opening and module import now delegate through host-owned loader-import helpers while preserving the current trusted in-process loading model. | -| Loader module-export, config-validation, and memory-slot decisions | `src/plugins/loader.ts` | `src/extension-host/loader-runtime.ts` | `partial` | Module export resolution, export-metadata application, config validation, and early or final memory-slot decisions now delegate through host-owned loader-runtime helpers. | -| Loader post-import planning and register execution | `src/plugins/loader.ts` | `src/extension-host/loader-register.ts` | `partial` | Definition application, post-import validation planning, and `register(...)` execution now delegate through host-owned loader-register helpers while preserving current plugin behavior. | -| Loader per-candidate orchestration | `src/plugins/loader.ts` | `src/extension-host/loader-flow.ts` | `partial` | The per-candidate load flow now runs through a host-owned orchestrator that composes planning, import, runtime validation, register execution, and record-state helpers. | -| Loader top-level load orchestration | `src/plugins/loader.ts` | `src/extension-host/loader-orchestrator.ts` | `partial` | High-level load entry and compatibility facade behavior now route through a host-owned loader orchestrator while `src/plugins/loader.ts` remains the external compatibility surface. | -| Loader host process state | mixed inside `src/plugins/loader.ts` and `src/extension-host/loader-orchestrator.ts` | `src/extension-host/loader-host-state.ts` | `partial` | Shared discovery warning-cache state and loader reset behavior now delegate through a host-owned loader-host-state helper. | -| Loader preflight and cache-hit setup | mixed inside `src/plugins/loader.ts` and `src/extension-host/loader-orchestrator.ts` | `src/extension-host/loader-preflight.ts` | `partial` | Test-default application, config normalization, cache-key construction, cache-hit activation, and command-clear preflight now delegate through a host-owned loader-preflight helper. | -| Loader post-preflight pipeline composition | mixed inside `src/plugins/loader.ts` and `src/extension-host/loader-orchestrator.ts` | `src/extension-host/loader-pipeline.ts` | `partial` | Post-preflight execution setup and session-run composition now delegate through a host-owned loader-pipeline helper. | -| Loader execution setup composition | mixed inside `src/plugins/loader.ts` and `src/extension-host/loader-orchestrator.ts` | `src/extension-host/loader-execution.ts` | `partial` | Runtime creation, registry creation, bootstrap setup, module-loader creation, and session creation now delegate through a host-owned loader-execution helper. | -| Loader discovery and manifest bootstrap | mixed inside `src/plugins/loader.ts` and `src/extension-host/loader-orchestrator.ts` | `src/extension-host/loader-bootstrap.ts` | `partial` | Discovery, manifest loading, manifest diagnostics, discovery-policy logging, provenance building, and candidate ordering now delegate through a host-owned loader-bootstrap helper. | -| Loader mutable activation state session | local variables in `src/extension-host/loader-orchestrator.ts` | `src/extension-host/loader-session.ts` | `partial` | Seen-id tracking, memory-slot selection state, and finalization inputs now live in a host-owned loader session instead of being spread across top-level loader variables. | -| Loader session run and finalization composition | mixed inside `src/extension-host/loader-orchestrator.ts` and `src/extension-host/loader-session.ts` | `src/extension-host/loader-run.ts` | `partial` | Candidate iteration, manifest lookup, per-candidate session processing, and finalization handoff now delegate through a host-owned loader-run helper. | -| Loader activation policy outcomes | open-coded in `src/extension-host/loader-flow.ts` | `src/extension-host/loader-activation-policy.ts` | `partial` | Duplicate precedence, config enablement, and early memory-slot gating now resolve through explicit host-owned activation-policy outcomes instead of remaining as inline loader decisions. | -| Loader record-state transitions | `src/plugins/loader.ts` | `src/extension-host/loader-state.ts` | `partial` | The loader now enforces an explicit lifecycle transition model (`prepared -> imported -> validated -> registered -> ready`, plus terminal `disabled` and `error`) while still mapping back to compatibility `PluginRecord.status` values. | -| Loader finalization policy results | mixed inside `src/extension-host/loader-policy.ts` and `src/extension-host/loader-finalize.ts` | `src/extension-host/loader-finalization-policy.ts` | `partial` | Memory-slot finalization warnings and provenance-based untracked-extension warnings now resolve through explicit host-owned finalization-policy results before the finalizer applies them. | -| Loader final cache, readiness, and activation finalization | `src/plugins/loader.ts` | `src/extension-host/loader-finalize.ts` | `partial` | Cache writes, readiness promotion, and registry activation now delegate through a host-owned loader-finalize helper; broader host lifecycle and policy semantics are still pending. | -| Channel lookup | `src/channels/plugins/index.ts`, `src/channels/plugins/registry-loader.ts`, `src/channels/registry.ts` | extension-host-backed registries plus kernel channel contracts | `partial` | Readers now consume host-owned runtime-registry channel accessors, and channel registrations now also keep host-owned runtime-registry storage with mirrored legacy compatibility arrays. Writes still originate from plugin registration. | -| Dock lookup | `src/channels/dock.ts` | host-owned static descriptors | `partial` | Runtime lookup now uses the host boundary; dock ownership itself has not moved yet. | -| Message-channel normalization | `src/utils/message-channel.ts` | host-owned channel registry view | `partial` | Lookup path now reads through host-owned runtime-registry channel accessors instead of raw legacy channel arrays. | -| Default plugin HTTP route lookup | `src/plugins/http-registry.ts` | host-owned route registry | `partial` | Default route registration and lookup now use host-owned runtime-registry state with a mirrored legacy `registry.httpRoutes` compatibility view. The plugin API still remains the external call surface for static route registration. | -| Channel catalog static metadata | `src/channels/plugins/catalog.ts` | host-owned static descriptors | `partial` | Package metadata parsing now flows through host schema helpers; full canonical catalog migration has not started. | -| Plugin skill discovery | `src/agents/skills/plugin-skills.ts` | host-owned resolved registry | `moved` | Static consumer now reads only resolved-extension data for skill paths and enablement filtering. | -| Plugin auto-enable | `src/config/plugin-auto-enable.ts` | host-owned resolved registry | `partial` | Primary logic runs on resolved-extension data; old manifest-registry injection remains as a compatibility input for older callers and tests. | -| Config validation indexing | `src/config/validation.ts`, `src/config/resolved-extension-validation.ts` | host-owned resolved registry | `moved` | Validation indexing now builds from resolved-extension records instead of flat manifest rows. | -| Config doc baseline generation | `src/config/doc-baseline.ts` | host-owned resolved registry | `moved` | Bundled plugin and channel metadata now load through the resolved-extension registry. | -| Plugin tool resolution and metadata | `src/plugins/tools.ts` | `src/extension-host/tool-runtime.ts` | `partial` | Optional-tool gating, plugin-id and tool-name conflict handling, tool-factory resolution, and plugin-tool metadata tracking now delegate through a host-owned tool-runtime helper while tool registrations now also keep host-owned runtime-registry storage with a mirrored legacy compatibility view. `src/plugins/tools.ts` remains the loader and config-normalization facade. | -| Plugin provider resolution | `src/plugins/providers.ts` | `src/extension-host/provider-runtime.ts` | `partial` | Provider projection from registry entries into runtime provider objects now delegates through a host-owned provider-runtime helper while `src/plugins/providers.ts` remains the loader and config-normalization facade. | -| Plugin provider discovery | `src/plugins/provider-discovery.ts` | `src/extension-host/provider-discovery.ts` | `partial` | Discovery-capable provider filtering, order grouping, and result normalization now delegate through a host-owned provider-discovery helper while `src/plugins/provider-discovery.ts` remains the compatibility facade around the legacy provider loader path. | -| Plugin provider auth helpers | `src/commands/provider-auth-helpers.ts` | `src/extension-host/provider-auth.ts` | `partial` | Provider matching, auth-method selection, config-patch merging, and default-model application now delegate through a host-owned provider-auth helper while command and onboarding entry points remain compatibility surfaces. | -| Plugin provider wizard metadata and choice resolution | `src/plugins/provider-wizard.ts` | `src/extension-host/provider-wizard.ts` | `partial` | Onboarding option building, model-picker entry building, and provider-method choice resolution now delegate through a host-owned provider-wizard helper while `src/plugins/provider-wizard.ts` remains the compatibility facade around loader-backed provider access and post-selection hooks. | -| Plugin provider auth application flow | `src/commands/auth-choice.apply.plugin-provider.ts` | `src/extension-host/provider-auth-flow.ts` | `partial` | Loaded-provider auth application, plugin-enable gating, auth-method execution, and post-auth default-model handling now delegate through a host-owned provider-auth-flow helper while `src/commands/auth-choice.apply.plugin-provider.ts` remains the compatibility entry point. | -| Plugin provider post-selection hook execution | `src/plugins/provider-wizard.ts`, `src/commands/model-picker.ts` | `src/extension-host/provider-model-selection.ts` | `partial` | Provider post-selection hook lookup and invocation now delegate through a host-owned provider-model-selection helper while `src/plugins/provider-wizard.ts` remains a compatibility facade and existing command consumers continue migrating onto the host-owned surface. | -| Plugin loader activation | `src/plugins/loader.ts` | extension host lifecycle + compatibility loader | `partial` | Activation now routes through `src/extension-host/activation.ts`, but discovery, enablement, provenance, module loading, and policy still live in the legacy plugin loader. | -| Plugin API compatibility facade | `src/plugins/registry.ts` | `src/extension-host/plugin-api.ts` | `partial` | Compatibility `OpenClawPluginApi` composition and logger shaping now delegate through a host-owned helper; concrete registration callbacks now come from `src/extension-host/plugin-registry.ts` while `src/plugins/registry.ts` remains the external wrapper. | -| Plugin registry compatibility facade | `src/plugins/registry.ts` | `src/extension-host/plugin-registry.ts` | `partial` | The compatibility plugin-registry facade now delegates through a host-owned helper; `src/plugins/registry.ts` mainly defines shared types and forwards to the host-owned facade. | -| Plugin registry compatibility policy | mixed inside `src/extension-host/plugin-registry.ts` | `src/extension-host/plugin-registry-compat.ts` | `partial` | Provider normalization, command duplicate enforcement, and registry-local diagnostic shaping now delegate through a host-owned compatibility helper; the underlying provider-validation and plugin-command subsystems still remain legacy-owned. | -| Plugin registry registration actions | mixed inside `src/extension-host/plugin-registry.ts` | `src/extension-host/plugin-registry-registrations.ts` | `partial` | Low-risk registration actions for tools, hooks, gateway methods, HTTP routes, channels, CLI, services, typed hooks, and context engines now delegate through a host-owned helper; the compatibility facade still composes those actions with provider and command compatibility policy. | -| Runtime registry read surface | direct reads of `registry.channels`, `registry.providers`, `registry.tools`, `registry.services`, `registry.cliRegistrars`, `registry.commands`, `registry.gatewayHandlers`, and `registry.httpRoutes` across runtime consumers | `src/extension-host/runtime-registry.ts` | `partial` | Host-owned runtime-registry accessors now serve channel, provider, tool, service, CLI, command, gateway-method, and HTTP-route consumers. Channel registrations, provider registrations, tool registrations, command registrations, HTTP routes, gateway methods, CLI registrations, and service registrations now also have host-owned runtime-registry storage with mirrored legacy compatibility views, and the CLI pre-load fast path treats any pre-seeded runtime entry surface as already loaded. | -| Channel registration writes | `src/plugins/registry.ts` | host-owned channel registry | `partial` | Validation and normalization now delegate to `src/extension-host/runtime-registrations.ts`, and writes now land in host-owned runtime-registry channel state via `src/extension-host/registry-writes.ts` with mirrored legacy compatibility arrays. The legacy plugin API still remains the call surface. | -| Provider registration writes | `src/plugins/registry.ts` | host-owned provider registry | `partial` | Provider normalization and compatibility diagnostics now delegate through `src/extension-host/plugin-registry-compat.ts`, duplicate detection and normalized registration shape still delegate to `src/extension-host/runtime-registrations.ts`, and writes now land in host-owned runtime-registry provider state via `src/extension-host/registry-writes.ts` with mirrored legacy compatibility arrays. | -| HTTP route registration writes | `src/plugins/registry.ts` | host-owned route registry | `partial` | Route validation and normalization now delegate to `src/extension-host/runtime-registrations.ts`, and append or replace writes now land in host-owned runtime-registry route state via `src/extension-host/registry-writes.ts` with mirrored legacy compatibility arrays. | -| Gateway method registration writes | `src/plugins/registry.ts` | host-owned runtime contribution registry | `partial` | Duplicate detection and normalized method registration now delegate to `src/extension-host/runtime-registrations.ts`, and writes now land in host-owned runtime-registry gateway-handler state via `src/extension-host/registry-writes.ts` with a mirrored legacy compatibility map. | -| Tool registration writes | `src/plugins/registry.ts` | host-owned tool registry | `partial` | Tool-name normalization and tool-factory shaping delegate through `src/extension-host/runtime-registrations.ts`, and writes now land in host-owned runtime-registry tool state via `src/extension-host/registry-writes.ts` with mirrored legacy compatibility arrays. Duplicate handling still follows the legacy tool path. | -| CLI registration writes | `src/plugins/registry.ts` | host-owned CLI registry | `partial` | CLI command-name normalization delegates through `src/extension-host/runtime-registrations.ts`, and writes now land in host-owned runtime-registry CLI state via `src/extension-host/registry-writes.ts` with mirrored legacy compatibility arrays. The legacy plugin API still remains the call surface. | -| Service registration writes | `src/plugins/registry.ts` | host-owned service registry | `partial` | Service-id normalization delegates through `src/extension-host/runtime-registrations.ts`, writes now land in host-owned runtime-registry service state via `src/extension-host/registry-writes.ts` with mirrored legacy compatibility arrays, and broader lifecycle ownership now starts in `src/extension-host/service-lifecycle.ts`. | -| Command registration writes | `src/plugins/registry.ts` | host-owned command registry | `partial` | Command-name normalization and duplicate-enforcement diagnostics now delegate through `src/extension-host/plugin-registry-compat.ts`, and writes now land in host-owned runtime-registry command state via `src/extension-host/registry-writes.ts` with mirrored legacy compatibility arrays. | -| Plugin command runtime | `src/plugins/commands.ts`, `src/auto-reply/reply/commands-plugin.ts`, `src/auto-reply/status.ts`, `src/extension-host/loader-orchestrator.ts` | `src/extension-host/command-runtime.ts` | `partial` | Command registration, matching, execution, listing, native command-spec projection, and loader reload clearing now delegate through a host-owned command-runtime helper while `src/plugins/commands.ts` remains the compatibility facade. | -| Context-engine registration writes | `src/plugins/registry.ts` | host-owned context-engine registry | `partial` | Context-engine id normalization now delegates to `src/extension-host/runtime-registrations.ts`, and the compatibility write now routes through `src/extension-host/registry-writes.ts`; the actual context-engine registry remains legacy-owned. | -| Legacy hook registration writes | `src/plugins/registry.ts` | host-owned hook registry | `partial` | Hook-entry construction and event normalization now delegate to `src/extension-host/runtime-registrations.ts`, and the compatibility write now routes through `src/extension-host/registry-writes.ts`; internal-hook bridging still remains in the legacy plugin registry. | -| Typed-hook registration writes | `src/plugins/registry.ts` | host-owned typed-hook registry | `partial` | Typed-hook record construction and hook-name validation now delegate to `src/extension-host/runtime-registrations.ts`, and the compatibility write now routes through `src/extension-host/registry-writes.ts`; prompt-injection policy and execution semantics remain legacy-owned. | -| Hook compatibility policy and bridging | `src/plugins/registry.ts` | `src/extension-host/hook-compat.ts` | `partial` | Legacy internal-hook bridging and typed prompt-injection compatibility policy now delegate through a host-owned helper; actual hook execution ownership remains legacy-owned. | -| Hook execution and global runner | `src/plugins/hook-runner-global.ts`, `src/hooks/internal-hooks.ts`, plugin hook registration in `src/plugins/registry.ts` | canonical kernel event stages + host bridges | `not started` | No canonical event-stage migration has landed yet. | -| Service lifecycle | `src/plugins/services.ts` and plugin service registration | `src/extension-host/service-lifecycle.ts` | `partial` | Service startup, stop ordering, service-context creation, and failure logging now delegate through a host-owned service-lifecycle helper while `src/plugins/services.ts` remains the compatibility entry point. | -| CLI registration | plugin CLI registration in `src/plugins/registry.ts` and CLI loaders | `src/extension-host/cli-lifecycle.ts` plus static descriptors where possible | `partial` | CLI duplicate detection, registrar invocation, and async failure logging now delegate through a host-owned CLI-lifecycle helper while `src/plugins/cli.ts` remains the compatibility entry point. | -| Gateway/server methods | `src/plugins/registry.ts` gateway handler registration plus gateway runtime consumers | `src/extension-host/gateway-methods.ts` plus host-owned runtime contribution registry | `partial` | Gateway method-id aggregation, plugin diagnostic shaping, and extra-handler composition now delegate through a host-owned gateway-methods helper, and gateway handlers now live in host-owned runtime-registry state with a mirrored legacy compatibility map. Request dispatch semantics still live in the gateway server code. | -| Conversation binding ownership, approvals, and restore semantics | `src/plugins/conversation-binding.ts` plus `src/infra/outbound/session-binding-service.ts` | host-owned binding registry and approval policy surface | `not started` | This is a real missing migration surface. The host needs to own plugin-scoped conversation binding, approval persistence, restore-on-restart behavior, detached-binding cleanup, and legacy binding migration without making `src/plugins/conversation-binding.ts` the long-term public surface. | -| Interactive callback routing and namespace ownership | `src/plugins/interactive.ts` plus Telegram and Discord monitor-specific callback wiring | host-owned interaction router and namespace registry | `not started` | This needs to be explicit. The host should own namespace registration, dedupe, fallback rules, and callback dispatch. The first validated rollout may target Telegram and Discord, but the contract itself should stay generic and kernel-agnostic. | -| Ingress claim and bound-route short-circuit semantics | `src/plugins/hooks.ts` typed `inbound_claim` hook plus `src/auto-reply/reply/dispatch-from-config.ts` | canonical event-pipeline ingress claim stage | `not started` | The behavior is conceptually in-scope today, but it should land as a canonical ingress-stage contract with legacy hook bridging only as migration. The key parity rule is first-claim-wins for route ownership while passive observers still run through their own stages. | -| Interactive channel control verbs for bound agents | product-shaped runtime helpers added under `src/plugins/runtime/*` and direct channel-specific helpers in extension code | host-owned adapter runtime contracts and interaction capabilities | `not started` | The host needs a bounded first-cut set of control verbs for interactive agents, such as typing leases plus message or conversation actions. Those verbs should be expressed as generic host-owned adapter capabilities, even if the first validated rollout only exercises them through Telegram and Discord. | -| Slot arbitration | `src/plugins/slots.ts` | host-owned arbitration model | `not started` | Current slot selection remains plugin-era logic. | -| ACP backend registry | `src/acp/runtime/registry.ts` | host-owned runtime-backend registry | `not started` | ACP backends still mutate a global ACP runtime registry directly. | -| Embedding provider registry and fallback routing | `src/memory/embeddings.ts` plus plugin provider capability filtering through `src/plugins/runtime.ts` | host-owned embedding runtime registry for a typed backend family | `not started` | This is a real missing scope area. Embedding providers should be modeled as host-owned subsystem runtimes with explicit capability metadata, request envelopes, provider-id normalization, and fallback rules, not by widening legacy `registerProvider(...)` as the long-term architecture. | -| Media-understanding provider registry and fallback routing | `src/media-understanding/providers/index.ts` plus plugin provider capability filtering through `src/plugins/runtime.ts` | host-owned media runtime registry for a typed backend family | `not started` | Audio transcription, image understanding, and video understanding should be modeled as host-owned subsystem runtimes with capability routing, explicit request envelopes, and fallback behavior rather than as permanent extensions of the plugin-era provider API. | -| TTS provider registry and telephony override routing | `src/tts/providers.ts`, `src/tts/tts.ts`, and plugin provider capability filtering through `src/plugins/runtime.ts` | host-owned TTS runtime registry for a typed backend family | `not started` | TTS providers and telephony TTS overrides should move behind host-owned runtime registries with explicit capability and fallback policy rather than staying coupled to plugin-era provider capabilities and global active-registry reads. | -| Onboarding/install/setup surfaces | `src/plugins/install.ts`, package manifests, channel catalog, onboarding commands | host-owned static descriptors | `partial` | Static metadata normalization has started; full setup/install descriptor migration is not done. | -| Pilot migrations | `extensions/thread-ownership`, `extensions/telegram`, `extensions/acpx` | extension-host path with parity tracking | `not started` | No pilot runs through the host path yet. | +| Surface | Current implementation | Target owner | Status | How it has been handled so far | +| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Active runtime registry state | `src/plugins/runtime.ts` plus global plugin runtime state | `src/extension-host/static/active-registry.ts` | `moved` | Host-owned active registry exists; `src/plugins/runtime.ts` is now a compatibility facade. | +| Normalized extension descriptor model | plugin manifests and package metadata interpreted ad hoc across `src/plugins/manifest.ts`, `src/plugins/discovery.ts`, `src/plugins/install.ts` | `src/extension-host/manifests/schema.ts` | `partial` | `ResolvedExtension`, `ResolvedContribution`, and `ContributionPolicy` exist; current manifests project into them through compatibility adapters. | +| Resolved static registry | flat rows in `src/plugins/manifest-registry.ts` | `src/extension-host/manifests/resolved-registry.ts` | `partial` | Manifest records now carry `resolvedExtension`; a host-owned resolved registry view exists for static consumers. | +| Manifest/package metadata loading | `src/plugins/manifest.ts`, `src/plugins/discovery.ts`, `src/plugins/install.ts` | `src/extension-host/manifests/schema.ts` and `src/extension-host/manifests/manifest-registry.ts` | `partial` | Package metadata parsing is routed through host schema helpers; legacy loader flow still supplies the source manifests. | +| Loader SDK alias compatibility | `src/plugins/loader.ts` | `src/extension-host/compat/loader-compat.ts` | `partial` | Plugin-SDK alias candidate ordering, alias-file resolution, and scoped alias-map construction now live in host-owned loader compatibility helpers. | +| Loader alias-wired module loader creation | `src/plugins/loader.ts` | `src/extension-host/activation/loader-module-loader.ts` | `partial` | Lazy Jiti creation and SDK-alias-wired module loading now delegate through a host-owned loader-module-loader helper. | +| Loader cache key and registry cache control | `src/plugins/loader.ts` | `src/extension-host/activation/loader-cache.ts` | `partial` | Cache-key construction, LRU registry cache reads and writes, and cache clearing now delegate through host-owned loader-cache helpers while preserving the current cache shape and cap. | +| Loader lazy runtime proxy creation | `src/plugins/loader.ts` | `src/extension-host/activation/loader-runtime-proxy.ts` | `partial` | Lazy plugin runtime creation now delegates through a host-owned loader-runtime-proxy helper instead of remaining inline in the orchestrator. | +| Loader provenance and duplicate-order policy | `src/plugins/loader.ts` | `src/extension-host/policy/loader-policy.ts` | `partial` | Plugin-record creation, duplicate precedence, and provenance indexing now live in host-owned loader-policy helpers. | +| Loader discovery policy results | mixed inside `src/extension-host/policy/loader-policy.ts` and `src/extension-host/activation/loader-orchestrator.ts` | `src/extension-host/policy/loader-discovery-policy.ts` | `partial` | Open-allowlist discovery warnings now resolve through explicit host-owned discovery-policy results before the orchestrator logs them. | +| Loader initial candidate planning and record creation | `src/plugins/loader.ts` | `src/extension-host/activation/loader-records.ts` | `partial` | Duplicate detection, initial record creation, manifest metadata attachment, and first-pass enable-state planning now delegate through host-owned loader-records helpers. | +| Loader entry-path opening and module import | `src/plugins/loader.ts` | `src/extension-host/activation/loader-import.ts` | `partial` | Boundary-checked entry opening and module import now delegate through host-owned loader-import helpers while preserving the current trusted in-process loading model. | +| Loader module-export, config-validation, and memory-slot decisions | `src/plugins/loader.ts` | `src/extension-host/activation/loader-runtime.ts` | `partial` | Module export resolution, export-metadata application, config validation, and early or final memory-slot decisions now delegate through host-owned loader-runtime helpers. | +| Loader post-import planning and register execution | `src/plugins/loader.ts` | `src/extension-host/activation/loader-register.ts` | `partial` | Definition application, post-import validation planning, and `register(...)` execution now delegate through host-owned loader-register helpers while preserving current plugin behavior. | +| Loader per-candidate orchestration | `src/plugins/loader.ts` | `src/extension-host/activation/loader-flow.ts` | `partial` | The per-candidate load flow now runs through a host-owned orchestrator that composes planning, import, runtime validation, register execution, and record-state helpers. | +| Loader top-level load orchestration | `src/plugins/loader.ts` | `src/extension-host/activation/loader-orchestrator.ts` | `partial` | High-level load entry and compatibility facade behavior now route through a host-owned loader orchestrator while `src/plugins/loader.ts` remains the external compatibility surface. | +| Loader host process state | mixed inside `src/plugins/loader.ts` and `src/extension-host/activation/loader-orchestrator.ts` | `src/extension-host/activation/loader-host-state.ts` | `partial` | Shared discovery warning-cache state and loader reset behavior now delegate through a host-owned loader-host-state helper. | +| Loader preflight and cache-hit setup | mixed inside `src/plugins/loader.ts` and `src/extension-host/activation/loader-orchestrator.ts` | `src/extension-host/activation/loader-preflight.ts` | `partial` | Test-default application, config normalization, cache-key construction, cache-hit activation, and command-clear preflight now delegate through a host-owned loader-preflight helper. | +| Loader post-preflight pipeline composition | mixed inside `src/plugins/loader.ts` and `src/extension-host/activation/loader-orchestrator.ts` | `src/extension-host/activation/loader-pipeline.ts` | `partial` | Post-preflight execution setup and session-run composition now delegate through a host-owned loader-pipeline helper. | +| Loader execution setup composition | mixed inside `src/plugins/loader.ts` and `src/extension-host/activation/loader-orchestrator.ts` | `src/extension-host/activation/loader-execution.ts` | `partial` | Runtime creation, registry creation, bootstrap setup, module-loader creation, and session creation now delegate through a host-owned loader-execution helper. | +| Loader discovery and manifest bootstrap | mixed inside `src/plugins/loader.ts` and `src/extension-host/activation/loader-orchestrator.ts` | `src/extension-host/activation/loader-bootstrap.ts` | `partial` | Discovery, manifest loading, manifest diagnostics, discovery-policy logging, provenance building, and candidate ordering now delegate through a host-owned loader-bootstrap helper. | +| Loader mutable activation state session | local variables in `src/extension-host/activation/loader-orchestrator.ts` | `src/extension-host/activation/loader-session.ts` | `partial` | Seen-id tracking, memory-slot selection state, and finalization inputs now live in a host-owned loader session instead of being spread across top-level loader variables. | +| Loader session run and finalization composition | mixed inside `src/extension-host/activation/loader-orchestrator.ts` and `src/extension-host/activation/loader-session.ts` | `src/extension-host/activation/loader-run.ts` | `partial` | Candidate iteration, manifest lookup, per-candidate session processing, and finalization handoff now delegate through a host-owned loader-run helper. | +| Loader activation policy outcomes | open-coded in `src/extension-host/activation/loader-flow.ts` | `src/extension-host/policy/loader-activation-policy.ts` | `partial` | Duplicate precedence, config enablement, and early memory-slot gating now resolve through explicit host-owned activation-policy outcomes instead of remaining as inline loader decisions. | +| Loader record-state transitions | `src/plugins/loader.ts` | `src/extension-host/activation/loader-state.ts` | `partial` | The loader now enforces an explicit lifecycle transition model (`prepared -> imported -> validated -> registered -> ready`, plus terminal `disabled` and `error`) while still mapping back to compatibility `PluginRecord.status` values. | +| Loader finalization policy results | mixed inside `src/extension-host/policy/loader-policy.ts` and `src/extension-host/activation/loader-finalize.ts` | `src/extension-host/policy/loader-finalization-policy.ts` | `partial` | Memory-slot finalization warnings and provenance-based untracked-extension warnings now resolve through explicit host-owned finalization-policy results before the finalizer applies them. | +| Loader final cache, readiness, and activation finalization | `src/plugins/loader.ts` | `src/extension-host/activation/loader-finalize.ts` | `partial` | Cache writes, readiness promotion, and registry activation now delegate through a host-owned loader-finalize helper; broader host lifecycle and policy semantics are still pending. | +| Channel lookup | `src/channels/plugins/index.ts`, `src/channels/plugins/registry-loader.ts`, `src/channels/registry.ts` | extension-host-backed registries plus kernel channel contracts | `partial` | Readers now consume host-owned runtime-registry channel accessors, and channel registrations now also keep host-owned runtime-registry storage with mirrored legacy compatibility arrays. Writes still originate from plugin registration. | +| Dock lookup | `src/channels/dock.ts` | host-owned static descriptors | `partial` | Runtime lookup now uses the host boundary; dock ownership itself has not moved yet. | +| Message-channel normalization | `src/utils/message-channel.ts` | host-owned channel registry view | `partial` | Lookup path now reads through host-owned runtime-registry channel accessors instead of raw legacy channel arrays. | +| Default plugin HTTP route lookup | `src/plugins/http-registry.ts` | host-owned route registry | `partial` | Default route registration and lookup now use host-owned runtime-registry state with a mirrored legacy `registry.httpRoutes` compatibility view. The plugin API still remains the external call surface for static route registration. | +| Channel catalog static metadata | `src/channels/plugins/catalog.ts` | host-owned static descriptors | `partial` | Package metadata parsing now flows through host schema helpers; full canonical catalog migration has not started. | +| Plugin skill discovery | `src/agents/skills/plugin-skills.ts` | host-owned resolved registry | `moved` | Static consumer now reads only resolved-extension data for skill paths and enablement filtering. | +| Plugin auto-enable | `src/config/plugin-auto-enable.ts` | host-owned resolved registry | `partial` | Primary logic runs on resolved-extension data; old manifest-registry injection remains as a compatibility input for older callers and tests. | +| Config validation indexing | `src/config/validation.ts`, `src/config/resolved-extension-validation.ts` | host-owned resolved registry | `moved` | Validation indexing now builds from resolved-extension records instead of flat manifest rows. | +| Config doc baseline generation | `src/config/doc-baseline.ts` | host-owned resolved registry | `moved` | Bundled plugin and channel metadata now load through the resolved-extension registry. | +| Plugin tool resolution and metadata | `src/plugins/tools.ts` | `src/extension-host/contributions/tool-runtime.ts` | `partial` | Optional-tool gating, plugin-id and tool-name conflict handling, tool-factory resolution, and plugin-tool metadata tracking now delegate through a host-owned tool-runtime helper while tool registrations now also keep host-owned runtime-registry storage with a mirrored legacy compatibility view. `src/plugins/tools.ts` remains the loader and config-normalization facade. | +| Plugin provider resolution | `src/plugins/providers.ts` | `src/extension-host/contributions/provider-runtime.ts` | `partial` | Provider projection from registry entries into runtime provider objects now delegates through a host-owned provider-runtime helper while `src/plugins/providers.ts` remains the loader and config-normalization facade. | +| Plugin provider discovery | `src/plugins/provider-discovery.ts` | `src/extension-host/contributions/provider-discovery.ts` | `partial` | Discovery-capable provider filtering, order grouping, and result normalization now delegate through a host-owned provider-discovery helper while `src/plugins/provider-discovery.ts` remains the compatibility facade around the legacy provider loader path. | +| Plugin provider auth helpers | `src/commands/provider-auth-helpers.ts` | `src/extension-host/contributions/provider-auth.ts` | `partial` | Provider matching, auth-method selection, config-patch merging, and default-model application now delegate through a host-owned provider-auth helper while command and onboarding entry points remain compatibility surfaces. | +| Plugin provider wizard metadata and choice resolution | `src/plugins/provider-wizard.ts` | `src/extension-host/contributions/provider-wizard.ts` | `partial` | Onboarding option building, model-picker entry building, and provider-method choice resolution now delegate through a host-owned provider-wizard helper while `src/plugins/provider-wizard.ts` remains the compatibility facade around loader-backed provider access and post-selection hooks. | +| Plugin provider auth application flow | `src/commands/auth-choice.apply.plugin-provider.ts` | `src/extension-host/contributions/provider-auth-flow.ts` | `partial` | Loaded-provider auth application, plugin-enable gating, auth-method execution, and post-auth default-model handling now delegate through a host-owned provider-auth-flow helper while `src/commands/auth-choice.apply.plugin-provider.ts` remains the compatibility entry point. | +| Plugin provider post-selection hook execution | `src/plugins/provider-wizard.ts`, `src/commands/model-picker.ts` | `src/extension-host/contributions/provider-model-selection.ts` | `partial` | Provider post-selection hook lookup and invocation now delegate through a host-owned provider-model-selection helper while `src/plugins/provider-wizard.ts` remains a compatibility facade and existing command consumers continue migrating onto the host-owned surface. | +| Plugin loader activation | `src/plugins/loader.ts` | extension host lifecycle + compatibility loader | `partial` | Activation now routes through `src/extension-host/activation.ts`, but discovery, enablement, provenance, module loading, and policy still live in the legacy plugin loader. | +| Plugin API compatibility facade | `src/plugins/registry.ts` | `src/extension-host/compat/plugin-api.ts` | `partial` | Compatibility `OpenClawPluginApi` composition and logger shaping now delegate through a host-owned helper; concrete registration callbacks now come from `src/extension-host/compat/plugin-registry.ts` while `src/plugins/registry.ts` remains the external wrapper. | +| Plugin registry compatibility facade | `src/plugins/registry.ts` | `src/extension-host/compat/plugin-registry.ts` | `partial` | The compatibility plugin-registry facade now delegates through a host-owned helper; `src/plugins/registry.ts` mainly defines shared types and forwards to the host-owned facade. | +| Plugin registry compatibility policy | mixed inside `src/extension-host/compat/plugin-registry.ts` | `src/extension-host/compat/plugin-registry-compat.ts` | `partial` | Provider normalization, command duplicate enforcement, and registry-local diagnostic shaping now delegate through a host-owned compatibility helper; the underlying provider-validation and plugin-command subsystems still remain legacy-owned. | +| Plugin registry registration actions | mixed inside `src/extension-host/compat/plugin-registry.ts` | `src/extension-host/compat/plugin-registry-registrations.ts` | `partial` | Low-risk registration actions for tools, hooks, gateway methods, HTTP routes, channels, CLI, services, typed hooks, and context engines now delegate through a host-owned helper; the compatibility facade still composes those actions with provider and command compatibility policy. | +| Runtime registry read surface | direct reads of `registry.channels`, `registry.providers`, `registry.tools`, `registry.services`, `registry.cliRegistrars`, `registry.commands`, `registry.gatewayHandlers`, and `registry.httpRoutes` across runtime consumers | `src/extension-host/contributions/runtime-registry.ts` | `partial` | Host-owned runtime-registry accessors now serve channel, provider, tool, service, CLI, command, gateway-method, and HTTP-route consumers. Channel registrations, provider registrations, tool registrations, command registrations, HTTP routes, gateway methods, CLI registrations, and service registrations now also have host-owned runtime-registry storage with mirrored legacy compatibility views, and the CLI pre-load fast path treats any pre-seeded runtime entry surface as already loaded. | +| Channel registration writes | `src/plugins/registry.ts` | host-owned channel registry | `partial` | Validation and normalization now delegate to `src/extension-host/contributions/runtime-registrations.ts`, and writes now land in host-owned runtime-registry channel state via `src/extension-host/contributions/registry-writes.ts` with mirrored legacy compatibility arrays. The legacy plugin API still remains the call surface. | +| Provider registration writes | `src/plugins/registry.ts` | host-owned provider registry | `partial` | Provider normalization and compatibility diagnostics now delegate through `src/extension-host/compat/plugin-registry-compat.ts`, duplicate detection and normalized registration shape still delegate to `src/extension-host/contributions/runtime-registrations.ts`, and writes now land in host-owned runtime-registry provider state via `src/extension-host/contributions/registry-writes.ts` with mirrored legacy compatibility arrays. | +| HTTP route registration writes | `src/plugins/registry.ts` | host-owned route registry | `partial` | Route validation and normalization now delegate to `src/extension-host/contributions/runtime-registrations.ts`, and append or replace writes now land in host-owned runtime-registry route state via `src/extension-host/contributions/registry-writes.ts` with mirrored legacy compatibility arrays. | +| Gateway method registration writes | `src/plugins/registry.ts` | host-owned runtime contribution registry | `partial` | Duplicate detection and normalized method registration now delegate to `src/extension-host/contributions/runtime-registrations.ts`, and writes now land in host-owned runtime-registry gateway-handler state via `src/extension-host/contributions/registry-writes.ts` with a mirrored legacy compatibility map. | +| Tool registration writes | `src/plugins/registry.ts` | host-owned tool registry | `partial` | Tool-name normalization and tool-factory shaping delegate through `src/extension-host/contributions/runtime-registrations.ts`, and writes now land in host-owned runtime-registry tool state via `src/extension-host/contributions/registry-writes.ts` with mirrored legacy compatibility arrays. Duplicate handling still follows the legacy tool path. | +| CLI registration writes | `src/plugins/registry.ts` | host-owned CLI registry | `partial` | CLI command-name normalization delegates through `src/extension-host/contributions/runtime-registrations.ts`, and writes now land in host-owned runtime-registry CLI state via `src/extension-host/contributions/registry-writes.ts` with mirrored legacy compatibility arrays. The legacy plugin API still remains the call surface. | +| Service registration writes | `src/plugins/registry.ts` | host-owned service registry | `partial` | Service-id normalization delegates through `src/extension-host/contributions/runtime-registrations.ts`, writes now land in host-owned runtime-registry service state via `src/extension-host/contributions/registry-writes.ts` with mirrored legacy compatibility arrays, and broader lifecycle ownership now starts in `src/extension-host/contributions/service-lifecycle.ts`. | +| Command registration writes | `src/plugins/registry.ts` | host-owned command registry | `partial` | Command-name normalization and duplicate-enforcement diagnostics now delegate through `src/extension-host/compat/plugin-registry-compat.ts`, and writes now land in host-owned runtime-registry command state via `src/extension-host/contributions/registry-writes.ts` with mirrored legacy compatibility arrays. | +| Plugin command runtime | `src/plugins/commands.ts`, `src/auto-reply/reply/commands-plugin.ts`, `src/auto-reply/status.ts`, `src/extension-host/activation/loader-orchestrator.ts` | `src/extension-host/contributions/command-runtime.ts` | `partial` | Command registration, matching, execution, listing, native command-spec projection, and loader reload clearing now delegate through a host-owned command-runtime helper while `src/plugins/commands.ts` remains the compatibility facade. | +| Context-engine registration writes | `src/plugins/registry.ts` | host-owned context-engine registry | `partial` | Context-engine id normalization now delegates to `src/extension-host/contributions/runtime-registrations.ts`, and the compatibility write now routes through `src/extension-host/contributions/registry-writes.ts`; the actual context-engine registry remains legacy-owned. | +| Legacy hook registration writes | `src/plugins/registry.ts` | host-owned hook registry | `partial` | Hook-entry construction and event normalization now delegate to `src/extension-host/contributions/runtime-registrations.ts`, and the compatibility write now routes through `src/extension-host/contributions/registry-writes.ts`; internal-hook bridging still remains in the legacy plugin registry. | +| Typed-hook registration writes | `src/plugins/registry.ts` | host-owned typed-hook registry | `partial` | Typed-hook record construction and hook-name validation now delegate to `src/extension-host/contributions/runtime-registrations.ts`, and the compatibility write now routes through `src/extension-host/contributions/registry-writes.ts`; prompt-injection policy and execution semantics remain legacy-owned. | +| Hook compatibility policy and bridging | `src/plugins/registry.ts` | `src/extension-host/compat/hook-compat.ts` | `partial` | Legacy internal-hook bridging and typed prompt-injection compatibility policy now delegate through a host-owned helper; actual hook execution ownership remains legacy-owned. | +| Hook execution and global runner | `src/plugins/hook-runner-global.ts`, `src/hooks/internal-hooks.ts`, plugin hook registration in `src/plugins/registry.ts` | canonical kernel event stages + host bridges | `not started` | No canonical event-stage migration has landed yet. | +| Service lifecycle | `src/plugins/services.ts` and plugin service registration | `src/extension-host/contributions/service-lifecycle.ts` | `partial` | Service startup, stop ordering, service-context creation, and failure logging now delegate through a host-owned service-lifecycle helper while `src/plugins/services.ts` remains the compatibility entry point. | +| CLI registration | plugin CLI registration in `src/plugins/registry.ts` and CLI loaders | `src/extension-host/contributions/cli-lifecycle.ts` plus static descriptors where possible | `partial` | CLI duplicate detection, registrar invocation, and async failure logging now delegate through a host-owned CLI-lifecycle helper while `src/plugins/cli.ts` remains the compatibility entry point. | +| Gateway/server methods | `src/plugins/registry.ts` gateway handler registration plus gateway runtime consumers | `src/extension-host/contributions/gateway-methods.ts` plus host-owned runtime contribution registry | `partial` | Gateway method-id aggregation, plugin diagnostic shaping, and extra-handler composition now delegate through a host-owned gateway-methods helper, and gateway handlers now live in host-owned runtime-registry state with a mirrored legacy compatibility map. Request dispatch semantics still live in the gateway server code. | +| Conversation binding ownership, approvals, and restore semantics | `src/plugins/conversation-binding.ts` plus `src/infra/outbound/session-binding-service.ts` | host-owned binding registry and approval policy surface | `not started` | This is a real missing migration surface. The host needs to own plugin-scoped conversation binding, approval persistence, restore-on-restart behavior, detached-binding cleanup, and legacy binding migration without making `src/plugins/conversation-binding.ts` the long-term public surface. | +| Interactive callback routing and namespace ownership | `src/plugins/interactive.ts` plus Telegram and Discord monitor-specific callback wiring | host-owned interaction router and namespace registry | `not started` | This needs to be explicit. The host should own namespace registration, dedupe, fallback rules, and callback dispatch. The first validated rollout may target Telegram and Discord, but the contract itself should stay generic and kernel-agnostic. | +| Ingress claim and bound-route short-circuit semantics | `src/plugins/hooks.ts` typed `inbound_claim` hook plus `src/auto-reply/reply/dispatch-from-config.ts` | canonical event-pipeline ingress claim stage | `not started` | The behavior is conceptually in-scope today, but it should land as a canonical ingress-stage contract with legacy hook bridging only as migration. The key parity rule is first-claim-wins for route ownership while passive observers still run through their own stages. | +| Interactive channel control verbs for bound agents | product-shaped runtime helpers added under `src/plugins/runtime/*` and direct channel-specific helpers in extension code | host-owned adapter runtime contracts and interaction capabilities | `not started` | The host needs a bounded first-cut set of control verbs for interactive agents, such as typing leases plus message or conversation actions. Those verbs should be expressed as generic host-owned adapter capabilities, even if the first validated rollout only exercises them through Telegram and Discord. | +| Slot arbitration | `src/plugins/slots.ts` | host-owned arbitration model | `not started` | Current slot selection remains plugin-era logic. | +| ACP backend registry | `src/acp/runtime/registry.ts` | host-owned runtime-backend registry | `not started` | ACP backends still mutate a global ACP runtime registry directly. | +| Embedding provider registry and fallback routing | `src/memory/embeddings.ts` plus plugin provider capability filtering through `src/plugins/runtime.ts` | host-owned embedding runtime registry for a typed backend family | `not started` | This is a real missing scope area. Embedding providers should be modeled as host-owned subsystem runtimes with explicit capability metadata, request envelopes, provider-id normalization, and fallback rules, not by widening legacy `registerProvider(...)` as the long-term architecture. | +| Media-understanding provider registry and fallback routing | `src/media-understanding/providers/index.ts` plus plugin provider capability filtering through `src/plugins/runtime.ts` | host-owned media runtime registry for a typed backend family | `not started` | Audio transcription, image understanding, and video understanding should be modeled as host-owned subsystem runtimes with capability routing, explicit request envelopes, and fallback behavior rather than as permanent extensions of the plugin-era provider API. | +| TTS provider registry and telephony override routing | `src/tts/providers.ts`, `src/tts/tts.ts`, and plugin provider capability filtering through `src/plugins/runtime.ts` | host-owned TTS runtime registry for a typed backend family | `not started` | TTS providers and telephony TTS overrides should move behind host-owned runtime registries with explicit capability and fallback policy rather than staying coupled to plugin-era provider capabilities and global active-registry reads. | +| Onboarding/install/setup surfaces | `src/plugins/install.ts`, package manifests, channel catalog, onboarding commands | host-owned static descriptors | `partial` | Static metadata normalization has started; full setup/install descriptor migration is not done. | +| Pilot migrations | `extensions/thread-ownership`, `extensions/telegram`, `extensions/acpx` | extension-host path with parity tracking | `not started` | No pilot runs through the host path yet. | ## Completed Pattern So Far diff --git a/src/extension-host/manifest-registry.ts b/src/extension-host/manifests/manifest-registry.ts similarity index 93% rename from src/extension-host/manifest-registry.ts rename to src/extension-host/manifests/manifest-registry.ts index 462f218faaa..2e242fdf5c3 100644 --- a/src/extension-host/manifest-registry.ts +++ b/src/extension-host/manifests/manifest-registry.ts @@ -1,9 +1,9 @@ -import type { PluginCandidate } from "../plugins/discovery.js"; +import type { PluginCandidate } from "../../plugins/discovery.js"; import { loadPackageManifest, type PackageManifest, type PluginManifest, -} from "../plugins/manifest.js"; +} from "../../plugins/manifest.js"; import { resolveLegacyExtensionDescriptor, type ResolvedExtension } from "./schema.js"; export type ResolvedExtensionRecord = { diff --git a/src/extension-host/resolved-registry.ts b/src/extension-host/manifests/resolved-registry.ts similarity index 92% rename from src/extension-host/resolved-registry.ts rename to src/extension-host/manifests/resolved-registry.ts index e61b1e842fe..ccaaf92a557 100644 --- a/src/extension-host/resolved-registry.ts +++ b/src/extension-host/manifests/resolved-registry.ts @@ -1,9 +1,9 @@ -import type { OpenClawConfig } from "../config/config.js"; +import type { OpenClawConfig } from "../../config/config.js"; import { loadPluginManifestRegistry, type PluginManifestRegistry, -} from "../plugins/manifest-registry.js"; -import type { PluginDiagnostic } from "../plugins/types.js"; +} from "../../plugins/manifest-registry.js"; +import type { PluginDiagnostic } from "../../plugins/types.js"; import type { ResolvedExtension } from "./schema.js"; export type ResolvedExtensionRegistryEntry = { diff --git a/src/extension-host/schema.test.ts b/src/extension-host/manifests/schema.test.ts similarity index 100% rename from src/extension-host/schema.test.ts rename to src/extension-host/manifests/schema.test.ts diff --git a/src/extension-host/schema.ts b/src/extension-host/manifests/schema.ts similarity index 98% rename from src/extension-host/schema.ts rename to src/extension-host/manifests/schema.ts index 7472ed3f4da..35ca87ca847 100644 --- a/src/extension-host/schema.ts +++ b/src/extension-host/manifests/schema.ts @@ -6,8 +6,8 @@ import { type PackageExtensionResolution, type PackageManifest, type PluginManifest, -} from "../plugins/manifest.js"; -import type { PluginConfigUiHint, PluginKind, PluginOrigin } from "../plugins/types.js"; +} from "../../plugins/manifest.js"; +import type { PluginConfigUiHint, PluginKind, PluginOrigin } from "../../plugins/types.js"; export type { OpenClawPackageManifest, PackageExtensionResolution, PackageManifest }; diff --git a/src/extension-host/loader-activation-policy.test.ts b/src/extension-host/policy/loader-activation-policy.test.ts similarity index 92% rename from src/extension-host/loader-activation-policy.test.ts rename to src/extension-host/policy/loader-activation-policy.test.ts index 3ca49964f26..bd26c609fde 100644 --- a/src/extension-host/loader-activation-policy.test.ts +++ b/src/extension-host/policy/loader-activation-policy.test.ts @@ -1,8 +1,8 @@ import { describe, expect, it } from "vitest"; -import type { OpenClawConfig } from "../config/config.js"; -import { normalizePluginsConfig } from "../plugins/config-state.js"; -import type { PluginCandidate } from "../plugins/discovery.js"; -import type { PluginManifestRecord } from "../plugins/manifest-registry.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import { normalizePluginsConfig } from "../../plugins/config-state.js"; +import type { PluginCandidate } from "../../plugins/discovery.js"; +import type { PluginManifestRecord } from "../../plugins/manifest-registry.js"; import { resolveExtensionHostActivationPolicy } from "./loader-activation-policy.js"; function createCandidate(overrides: Partial = {}): PluginCandidate { diff --git a/src/extension-host/loader-activation-policy.ts b/src/extension-host/policy/loader-activation-policy.ts similarity index 75% rename from src/extension-host/loader-activation-policy.ts rename to src/extension-host/policy/loader-activation-policy.ts index 68d102108b1..f0bf717ac3f 100644 --- a/src/extension-host/loader-activation-policy.ts +++ b/src/extension-host/policy/loader-activation-policy.ts @@ -1,10 +1,11 @@ -import type { OpenClawConfig } from "../config/config.js"; -import type { PluginCandidate } from "../plugins/discovery.js"; -import type { PluginManifestRecord } from "../plugins/manifest-registry.js"; -import type { PluginRecord } from "../plugins/registry.js"; -import { prepareExtensionHostPluginCandidate } from "./loader-records.js"; -import { resolveExtensionHostEarlyMemoryDecision } from "./loader-runtime.js"; -import { setExtensionHostPluginRecordDisabled } from "./loader-state.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import type { NormalizedPluginsConfig } from "../../plugins/config-state.js"; +import type { PluginCandidate } from "../../plugins/discovery.js"; +import type { PluginManifestRecord } from "../../plugins/manifest-registry.js"; +import type { PluginRecord } from "../../plugins/registry.js"; +import { prepareExtensionHostPluginCandidate } from "../activation/loader-records.js"; +import { resolveExtensionHostEarlyMemoryDecision } from "../activation/loader-runtime.js"; +import { setExtensionHostPluginRecordDisabled } from "../activation/loader-state.js"; export type ExtensionHostActivationPolicyOutcome = | { @@ -45,21 +46,7 @@ export type ExtensionHostActivationPolicyOutcome = export function resolveExtensionHostActivationPolicy(params: { candidate: PluginCandidate; manifestRecord: PluginManifestRecord; - normalizedConfig: { - entries: Record< - string, - { - enabled?: boolean; - hooks?: { - allowPromptInjection?: boolean; - }; - config?: unknown; - } - >; - slots: { - memory?: string | null; - }; - }; + normalizedConfig: NormalizedPluginsConfig; rootConfig: OpenClawConfig; seenIds: Map; selectedMemoryPluginId: string | null; diff --git a/src/extension-host/loader-discovery-policy.test.ts b/src/extension-host/policy/loader-discovery-policy.test.ts similarity index 100% rename from src/extension-host/loader-discovery-policy.test.ts rename to src/extension-host/policy/loader-discovery-policy.test.ts diff --git a/src/extension-host/loader-discovery-policy.ts b/src/extension-host/policy/loader-discovery-policy.ts similarity index 94% rename from src/extension-host/loader-discovery-policy.ts rename to src/extension-host/policy/loader-discovery-policy.ts index fb245d27f13..c1b40e68c1f 100644 --- a/src/extension-host/loader-discovery-policy.ts +++ b/src/extension-host/policy/loader-discovery-policy.ts @@ -1,4 +1,4 @@ -import type { PluginRecord } from "../plugins/registry.js"; +import type { PluginRecord } from "../../plugins/registry.js"; export function resolveExtensionHostDiscoveryPolicy(params: { pluginsEnabled: boolean; diff --git a/src/extension-host/loader-finalization-policy.test.ts b/src/extension-host/policy/loader-finalization-policy.test.ts similarity index 97% rename from src/extension-host/loader-finalization-policy.test.ts rename to src/extension-host/policy/loader-finalization-policy.test.ts index 68ef023acad..d10c3360020 100644 --- a/src/extension-host/loader-finalization-policy.test.ts +++ b/src/extension-host/policy/loader-finalization-policy.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import type { PluginRegistry } from "../plugins/registry.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; import { resolveExtensionHostFinalizationPolicy } from "./loader-finalization-policy.js"; function createRegistry(): PluginRegistry { diff --git a/src/extension-host/loader-finalization-policy.ts b/src/extension-host/policy/loader-finalization-policy.ts similarity index 92% rename from src/extension-host/loader-finalization-policy.ts rename to src/extension-host/policy/loader-finalization-policy.ts index c16bf153a58..2c516022334 100644 --- a/src/extension-host/loader-finalization-policy.ts +++ b/src/extension-host/policy/loader-finalization-policy.ts @@ -1,5 +1,5 @@ -import type { PluginRegistry } from "../plugins/registry.js"; -import type { PluginDiagnostic } from "../plugins/types.js"; +import type { PluginRegistry } from "../../plugins/registry.js"; +import type { PluginDiagnostic } from "../../plugins/types.js"; import { isExtensionHostTrackedByProvenance, safeRealpathOrResolveExtensionHostPath, diff --git a/src/extension-host/loader-policy.test.ts b/src/extension-host/policy/loader-policy.test.ts similarity index 97% rename from src/extension-host/loader-policy.test.ts rename to src/extension-host/policy/loader-policy.test.ts index e894d8cd559..c71dfd001be 100644 --- a/src/extension-host/loader-policy.test.ts +++ b/src/extension-host/policy/loader-policy.test.ts @@ -2,7 +2,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import type { PluginCandidate } from "../plugins/discovery.js"; +import type { PluginCandidate } from "../../plugins/discovery.js"; import { buildExtensionHostProvenanceIndex, compareExtensionHostDuplicateCandidateOrder, diff --git a/src/extension-host/loader-policy.ts b/src/extension-host/policy/loader-policy.ts similarity index 94% rename from src/extension-host/loader-policy.ts rename to src/extension-host/policy/loader-policy.ts index d413fc735ad..6ff98e5c534 100644 --- a/src/extension-host/loader-policy.ts +++ b/src/extension-host/policy/loader-policy.ts @@ -1,7 +1,11 @@ -import type { OpenClawConfig } from "../config/config.js"; -import type { PluginCandidate } from "../plugins/discovery.js"; -import type { PluginRecord, PluginRegistry } from "../plugins/registry.js"; -import type { PluginDiagnostic, PluginLogger } from "../plugins/types.js"; +import type { OpenClawConfig } from "../../config/config.js"; +import type { PluginCandidate } from "../../plugins/discovery.js"; +import type { PluginRecord, PluginRegistry } from "../../plugins/registry.js"; +import type { PluginDiagnostic, PluginLogger } from "../../plugins/types.js"; +import { + appendExtensionHostPluginRecord, + setExtensionHostPluginRecordLifecycleState, +} from "../activation/loader-state.js"; import { addExtensionHostPathToMatcher, createExtensionHostPathMatcher, @@ -9,10 +13,6 @@ import { type ExtensionHostInstallTrackingRule, type ExtensionHostProvenanceIndex, } from "./loader-provenance.js"; -import { - appendExtensionHostPluginRecord, - setExtensionHostPluginRecordLifecycleState, -} from "./loader-state.js"; export function createExtensionHostPluginRecord(params: { id: string; diff --git a/src/extension-host/loader-provenance.test.ts b/src/extension-host/policy/loader-provenance.test.ts similarity index 100% rename from src/extension-host/loader-provenance.test.ts rename to src/extension-host/policy/loader-provenance.test.ts diff --git a/src/extension-host/loader-provenance.ts b/src/extension-host/policy/loader-provenance.ts similarity index 95% rename from src/extension-host/loader-provenance.ts rename to src/extension-host/policy/loader-provenance.ts index ab565303cc3..2ebc07d62bd 100644 --- a/src/extension-host/loader-provenance.ts +++ b/src/extension-host/policy/loader-provenance.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import path from "node:path"; -import { isPathInside, safeStatSync } from "../plugins/path-safety.js"; -import { resolveUserPath } from "../utils.js"; +import { isPathInside, safeStatSync } from "../../plugins/path-safety.js"; +import { resolveUserPath } from "../../utils.js"; export type ExtensionHostPathMatcher = { exact: Set; diff --git a/src/extension-host/provider-runtime.ts b/src/extension-host/provider-runtime.ts deleted file mode 100644 index 657765f3866..00000000000 --- a/src/extension-host/provider-runtime.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { PluginRegistry } from "../plugins/registry.js"; -import type { ProviderPlugin } from "../plugins/types.js"; -import { listExtensionHostProviderRegistrations } from "./runtime-registry.js"; - -export function resolveExtensionHostProviders(params: { - registry: Pick; -}): ProviderPlugin[] { - return listExtensionHostProviderRegistrations(params.registry).map((entry) => ({ - ...entry.provider, - pluginId: entry.pluginId, - })); -} diff --git a/src/extension-host/active-registry.test.ts b/src/extension-host/static/active-registry.test.ts similarity index 96% rename from src/extension-host/active-registry.test.ts rename to src/extension-host/static/active-registry.test.ts index 5b4c59c106c..679d5b3d7da 100644 --- a/src/extension-host/active-registry.test.ts +++ b/src/extension-host/static/active-registry.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { createEmptyPluginRegistry } from "../plugins/registry.js"; +import { createEmptyPluginRegistry } from "../../plugins/registry.js"; import { createEmptyExtensionHostRegistry, getActiveExtensionHostRegistry, diff --git a/src/extension-host/active-registry.ts b/src/extension-host/static/active-registry.ts similarity index 98% rename from src/extension-host/active-registry.ts rename to src/extension-host/static/active-registry.ts index 2385130c2e7..777ae393a78 100644 --- a/src/extension-host/active-registry.ts +++ b/src/extension-host/static/active-registry.ts @@ -1,4 +1,4 @@ -import { createEmptyPluginRegistry, type PluginRegistry } from "../plugins/registry.js"; +import { createEmptyPluginRegistry, type PluginRegistry } from "../../plugins/registry.js"; const EXTENSION_HOST_REGISTRY_STATE = Symbol.for("openclaw.extensionHostRegistryState"); diff --git a/src/gateway/.DS_Store b/src/gateway/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..506585a89415dfe9a5a785904ebe20d457822824 GIT binary patch literal 6148 zcmeHKPm9w)6n~S}-K@o>2Mg{k;7QoUR8UsD#M(W1Gos)hYSWZ$)+7^}bbBa;Ttx9Z z>|sBHi0e&HegXwQfnULk;CnOE+Sphh(B3s6fg$eO40XPLdpt@+vPR=s znNP&qZ7<{=*>;XkcDG)AxLNM!|B+uZXu9(;D;9PIYmh=8GdrY`&Xl>`;Fo^3FXr>E zcVxVm`4swy_>Wv3oP0cZQ{q$1Lr}1}m5Hy>Xf-9$tG%7^InPe_}?Z zdS-1MrMCXq9q_T6b+b|0>JA^$*Imv-Z&vSm_k#YoQ$K%;$5}Us`$G{B_qS#Dds>=T{EB=C})7q2Md+ZQJ6~TX?{9No1R>JwBF^2;TP5G>SnEGl#rUqBUt ZHj65Vj>23bwxH-A0YQTG=Km_U+i;c6B{lbu-v2+C4PQ`}gB%%;FGpz5V*UFT|{uzj)#glyGqd zoB?OR8E^*9!T`=}k?Ka#XJ^0}a0U(x$o>#81fyY6%v%Sh+yVgQ8l45Y^b(R245MLE zga^W!3e;4#7K1e%_F!?*Fez#}u{9rTPyT6MI6ocrLk=g7iat97&Oo1mOI;4-{GZ^L zDK`226kj<5&cHuofCu%o9^<3zY(4orIco#P6NZSyB~c*IdzSz#WFNW9PW1=T5f=@U UqEr!kP6zr$AQR$~GjIk5_J%kuUH||9 literal 0 HcmV?d00001 diff --git a/src/gateway/server-plugins.ts b/src/gateway/server-plugins.ts index 01e53626359..c19ec089a59 100644 --- a/src/gateway/server-plugins.ts +++ b/src/gateway/server-plugins.ts @@ -3,7 +3,7 @@ import type { loadConfig } from "../config/config.js"; import { logExtensionHostPluginDiagnostics, resolveExtensionHostGatewayMethods, -} from "../extension-host/gateway-methods.js"; +} from "../extension-host/contributions/gateway-methods.js"; import { loadOpenClawPlugins } from "../plugins/loader.js"; import { getPluginRuntimeGatewayRequestScope } from "../plugins/runtime/gateway-request-scope.js"; import type { PluginRuntime } from "../plugins/runtime/types.js"; diff --git a/src/gateway/server.impl.ts b/src/gateway/server.impl.ts index 19ca423d47b..ccb9f227509 100644 --- a/src/gateway/server.impl.ts +++ b/src/gateway/server.impl.ts @@ -21,7 +21,7 @@ import { import { formatConfigIssueLines } from "../config/issue-format.js"; import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js"; import { resolveMainSessionKey } from "../config/sessions.js"; -import { createExtensionHostGatewayExtraHandlers } from "../extension-host/gateway-methods.js"; +import { createExtensionHostGatewayExtraHandlers } from "../extension-host/contributions/gateway-methods.js"; import { clearAgentRunContext, onAgentEvent } from "../infra/agent-events.js"; import { ensureControlUiAssetsBuilt, diff --git a/src/gateway/server/.DS_Store b/src/gateway/server/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..d578602d3132d801dd50e116bc2b5811cbada05f GIT binary patch literal 6148 zcmeHK!AiqG5S^_-s#YinqPP5jVDBDciC@r*;Gxo1(n{I{+R|(A>@WBQUIY(>Y4!8# z{`lYhdIRRL8%6__i)-v=L!F>sh!lurjbxdH$^xWzD*nho^X0Sp{w z7U6*zn+mk4#$7RtO^4riae>3kqD?0wJ7XQUvvD^RBfG=zOE{UpqV}qQDo|8l%TDWD z|1Xx`|BFdFQw3CkjZ(mPVJmFnm0WEty&TtCAMF~AjpH(ll7h~aV;OKM<{PaTp7}fg V1`ace@WAv(KxEKP75GyHz5!!5h3)_V literal 0 HcmV?d00001 diff --git a/src/gateway/server/plugins-http.ts b/src/gateway/server/plugins-http.ts index bef2c9730a4..8e2ad7a355b 100644 --- a/src/gateway/server/plugins-http.ts +++ b/src/gateway/server/plugins-http.ts @@ -1,5 +1,5 @@ import type { IncomingMessage, ServerResponse } from "node:http"; -import { listExtensionHostHttpRoutes } from "../../extension-host/runtime-registry.js"; +import { listExtensionHostHttpRoutes } from "../../extension-host/contributions/runtime-registry.js"; import type { createSubsystemLogger } from "../../logging/subsystem.js"; import type { PluginRegistry } from "../../plugins/registry.js"; import { withPluginRuntimeGatewayRequestScope } from "../../plugins/runtime/gateway-request-scope.js"; diff --git a/src/gateway/server/plugins-http/route-match.ts b/src/gateway/server/plugins-http/route-match.ts index 43035cecb10..4c84f9b12cc 100644 --- a/src/gateway/server/plugins-http/route-match.ts +++ b/src/gateway/server/plugins-http/route-match.ts @@ -1,4 +1,4 @@ -import { listExtensionHostHttpRoutes } from "../../../extension-host/runtime-registry.js"; +import { listExtensionHostHttpRoutes } from "../../../extension-host/contributions/runtime-registry.js"; import type { PluginRegistry } from "../../../plugins/registry.js"; import { canonicalizePathVariant } from "../../security-path.js"; import { diff --git a/src/plugins/.DS_Store b/src/plugins/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a3f733297b5f59ba929a6312025a382ea54f7660 GIT binary patch literal 10244 zcmeHMYi!$86u!spR-4w;eQd1WvStf=bty~tKpT6dZ8|!(sne3SX*bA{*lW!kJH$>> zR!tP~*aQLrLLl*nm-q)04-JU{(s)Q91_F(0(m?QsAH4ZD1QG(y^>s#?wrD@L2_#?1 z_xPN9j*rjhbL^ZOLI`x_l@3Dugb*GNN~JoSW*Bsx9@7TrN~j&6Js}#&5H(e_vMGI< zwkPlq@DT72@DT72@DTVfAb{U&I`~>fz1c&+L%>7eA_DaN;Kzf~uuCTxbzU7fIV}Lv zY7{#I&#@11Z2T?_yL5t4#}u#0x(9Gg!EG^snd7>jsv`}%bb?W4PJo#ca6N>=PGFdYHfyVsB$$rFRv<^8*v!j+S$tgcyhD0B|Es_Hp&YjD)o+!`G< zi%~mi=dG?}Za?K>rm3e&=gHK7rWO-YbGK>ONzG7mj)A7AsB&OXGZeGfW#$dVa%`h) zLBNra=8cbsg8tCapntq$L&w^nf7AN)M~@2pyug~x`x1xsjA0&QQGojI_Xx5Oq<5uoLa!B2h*mW&lpxhYDg#bbY4%|YNxJKWt7!h>71$SdreETHPaYMNR8B} zFH1RVK+Rc5<96BAr|8FrEi-3#J09X1I%W4D^h>GNTF& z++xA8YLOSp@q9|VBd^(a@=}1GY-((f#8!EUAicuxSI}>FPQ_Vq)B|#>cz_D`mDw4tdxbP3F|TB4#BoeaPfHQSLlS zT%kriie{TRG;%}i6Zj!|!A?cN@TgGUC&zf{ET51h%_wMC3;5tzNeBUkJt57d6PH3c zN`Y|5eMb1@Yb9-D3yF|8xt-iaj+3Xz3*-cOhkQiNkT1wL|5ys#MjKjU~06Yi}!Nc$*JPpslbMQR8 z2q)oncmqzsdvF#$he`MfzJu@KNB9XYa5Wsy30x!B#5Hq^xfR?>u8mvGZR56cz1$F| zat6D3u2h8kr^d>e$XC2qbgO{-g0#fAQ?r#=@6Nj3TXy}gO6+{SQ&jWjU$bvmOp-{2Bs8u2^&Mtwz z6C~pBK41F|o|pK`o%3IlZ^_T(0s!WG6D$B91YrYgg_~gyL?MQm9*1E_gMzs};$*r7 zHWV=1?}mHeKDZx_!6Wb}JO+=$6HdlI>ty^(Z~|V2SK&=~3*Ls)@GhKzkKq&e6h4FV z@B{n`e^uo5o{GGtY(-vY%t(agHQ_e}-rv~r+6SF8X(^YWl^renP{HXLycME3LpO~P zT%xsChhJ@#SU9(nQ9RR07UvwXrhf9cKmJX(Jc72iixJFv?Tq;W=Fw00|9fWt|NpArm*>z!z(e5bApq5pXrv4Mm74iV*BlD` zcpSuo4yrf7sAGZ?RiSccJ02Oj9lz3*xf>nMdf1gsFzT42onwxa?dD(cKLal37Ms`q Xd;R|Q#$1<+W-FzC86tJ literal 0 HcmV?d00001 diff --git a/src/plugins/cli.ts b/src/plugins/cli.ts index 3ff27c864c2..c105319999b 100644 --- a/src/plugins/cli.ts +++ b/src/plugins/cli.ts @@ -2,7 +2,7 @@ import type { Command } from "commander"; import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js"; import type { OpenClawConfig } from "../config/config.js"; import { loadConfig } from "../config/config.js"; -import { registerExtensionHostCliCommands } from "../extension-host/cli-lifecycle.js"; +import { registerExtensionHostCliCommands } from "../extension-host/contributions/cli-lifecycle.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import { loadOpenClawPlugins } from "./loader.js"; import type { PluginLogger } from "./types.js"; diff --git a/src/plugins/discovery.ts b/src/plugins/discovery.ts index f6aa84dd350..6ea66a8b76f 100644 --- a/src/plugins/discovery.ts +++ b/src/plugins/discovery.ts @@ -1,22 +1,15 @@ import fs from "node:fs"; import path from "node:path"; import { - DEFAULT_EXTENSION_ENTRY_CANDIDATES, getExtensionPackageMetadata, resolveExtensionEntryCandidates, type PackageManifest, type OpenClawPackageManifest, -} from "../extension-host/schema.js"; +} from "../extension-host/manifests/schema.js"; import { openBoundaryFileSync } from "../infra/boundary-file-read.js"; import { resolveUserPath } from "../utils.js"; import { detectBundleManifestFormat, loadBundleManifest } from "./bundle-manifest.js"; -import { - DEFAULT_PLUGIN_ENTRY_CANDIDATES, - getPackageManifestMetadata, - resolvePackageExtensionEntries, - type OpenClawPackageManifest, - type PackageManifest, -} from "./manifest.js"; +import { DEFAULT_PLUGIN_ENTRY_CANDIDATES, loadPackageManifest } from "./manifest.js"; import { formatPosixMode, isPathInside, safeRealpathSync, safeStatSync } from "./path-safety.js"; import { resolvePluginCacheInputs, resolvePluginSourceRoots } from "./roots.js"; import type { PluginBundleFormat, PluginDiagnostic, PluginFormat, PluginOrigin } from "./types.js"; diff --git a/src/plugins/http-registry.ts b/src/plugins/http-registry.ts index 688e4a13284..2d70ef9f8f7 100644 --- a/src/plugins/http-registry.ts +++ b/src/plugins/http-registry.ts @@ -1,11 +1,11 @@ import type { IncomingMessage, ServerResponse } from "node:http"; -import { requireActiveExtensionHostRegistry } from "../extension-host/active-registry.js"; import { addExtensionHostHttpRoute, listExtensionHostHttpRoutes, removeExtensionHostHttpRoute, replaceExtensionHostHttpRoute, -} from "../extension-host/runtime-registry.js"; +} from "../extension-host/contributions/runtime-registry.js"; +import { requireActiveExtensionHostRegistry } from "../extension-host/static/active-registry.js"; import { normalizePluginHttpPath } from "./http-path.js"; import { findOverlappingPluginHttpRoute } from "./http-route-overlap.js"; import type { PluginHttpRouteRegistration, PluginRegistry } from "./registry.js"; diff --git a/src/plugins/install.ts b/src/plugins/install.ts index 5f6ef6612df..9c8ab9ab733 100644 --- a/src/plugins/install.ts +++ b/src/plugins/install.ts @@ -3,7 +3,7 @@ import path from "node:path"; import { resolveExtensionEntryCandidates, type PackageManifest as PluginPackageManifest, -} from "../extension-host/schema.js"; +} from "../extension-host/manifests/schema.js"; import { fileExists, readJsonFile, resolveArchiveKind } from "../infra/archive.js"; import { writeFileFromPathWithinRoot } from "../infra/fs-safe.js"; import { resolveExistingInstallPath, withExtractedArchiveRoot } from "../infra/install-flow.js"; @@ -36,11 +36,7 @@ import { extensionUsesSkippedScannerPath, isPathInside } from "../security/scan- import * as skillScanner from "../security/skill-scanner.js"; import { CONFIG_DIR, resolveUserPath } from "../utils.js"; import { detectBundleManifestFormat, loadBundleManifest } from "./bundle-manifest.js"; -import { - loadPluginManifest, - resolvePackageExtensionEntries, - type PackageManifest as PluginPackageManifest, -} from "./manifest.js"; +import { loadPluginManifest } from "./manifest.js"; type PluginInstallLogger = { info?: (message: string) => void; diff --git a/src/plugins/loader.ts b/src/plugins/loader.ts index 478f4365b4a..2d9040740e0 100644 --- a/src/plugins/loader.ts +++ b/src/plugins/loader.ts @@ -1,111 +1,34 @@ +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { MAX_EXTENSION_HOST_REGISTRY_CACHE_ENTRIES } from "../extension-host/activation/loader-cache.js"; +import { + clearExtensionHostLoaderState, + loadExtensionHostPluginRegistry, +} from "../extension-host/activation/loader-orchestrator.js"; import { listPluginSdkAliasCandidates, listPluginSdkExportedSubpaths, resolvePluginSdkAliasCandidateOrder, resolvePluginSdkAliasFile, -} from "../extension-host/loader-compat.js"; -import { - buildExtensionHostProvenanceIndex, - compareExtensionHostDuplicateCandidateOrder, - pushExtensionHostDiagnostics, - warnWhenExtensionAllowlistIsOpen, -} from "../extension-host/loader-policy.js"; -import type { GatewayRequestHandler } from "../gateway/server-methods/types.js"; -import { createSubsystemLogger } from "../logging/subsystem.js"; -import { clearPluginCommands } from "./commands.js"; -import { applyTestPluginDefaults, normalizePluginsConfig } from "./config-state.js"; -import { discoverOpenClawPlugins } from "./discovery.js"; -import { initializeGlobalHookRunner } from "./hook-runner-global.js"; -import { clearPluginInteractiveHandlers } from "./interactive.js"; -import { loadPluginManifestRegistry } from "./manifest-registry.js"; -import { createPluginRegistry, type PluginRecord, type PluginRegistry } from "./registry.js"; -import { createPluginRuntime, type CreatePluginRuntimeOptions } from "./runtime/index.js"; -import type { PluginRuntime } from "./runtime/types.js"; -import { validateJsonSchemaValue } from "./schema-validator.js"; -import type { - OpenClawPluginDefinition, - OpenClawPluginModule, - PluginDiagnostic, - PluginBundleFormat, - PluginFormat, - PluginLogger, -} from "./types.js"; +} from "../extension-host/compat/loader-compat.js"; +import { resolveOpenClawPackageRootSync } from "../infra/openclaw-root.js"; +import type { PluginRegistry } from "./registry.js"; export type PluginLoadResult = PluginRegistry; -export type PluginLoadOptions = ExtensionHostPluginLoadOptions; +export type PluginLoadOptions = + import("../extension-host/activation/loader-orchestrator.js").ExtensionHostPluginLoadOptions; export function clearPluginLoaderCache(): void { clearExtensionHostLoaderState(); } -const defaultLogger = () => createSubsystemLogger("plugins"); - -type PluginSdkAliasCandidateKind = "dist" | "src"; - -function resolvePluginSdkAliasCandidateOrder(params: { - modulePath: string; - isProduction: boolean; -}): PluginSdkAliasCandidateKind[] { - const normalizedModulePath = params.modulePath.replace(/\\/g, "/"); - const isDistRuntime = normalizedModulePath.includes("/dist/"); - return isDistRuntime || params.isProduction ? ["dist", "src"] : ["src", "dist"]; +export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegistry { + return loadExtensionHostPluginRegistry(options); } -function listPluginSdkAliasCandidates(params: { - srcFile: string; - distFile: string; - modulePath: string; -}) { - const orderedKinds = resolvePluginSdkAliasCandidateOrder({ - modulePath: params.modulePath, - isProduction: process.env.NODE_ENV === "production", - }); - let cursor = path.dirname(params.modulePath); - const candidates: string[] = []; - for (let i = 0; i < 6; i += 1) { - const candidateMap = { - src: path.join(cursor, "src", "plugin-sdk", params.srcFile), - dist: path.join(cursor, "dist", "plugin-sdk", params.distFile), - } as const; - for (const kind of orderedKinds) { - candidates.push(candidateMap[kind]); - } - const parent = path.dirname(cursor); - if (parent === cursor) { - break; - } - cursor = parent; - } - return candidates; -} - -const resolvePluginSdkAliasFile = (params: { - srcFile: string; - distFile: string; - modulePath?: string; -}): string | null => { - try { - const modulePath = params.modulePath ?? fileURLToPath(import.meta.url); - for (const candidate of listPluginSdkAliasCandidates({ - srcFile: params.srcFile, - distFile: params.distFile, - modulePath, - })) { - if (fs.existsSync(candidate)) { - return candidate; - } - } - } catch { - // ignore - } - return null; -}; - -const resolvePluginSdkAlias = (): string | null => - resolvePluginSdkAliasFile({ srcFile: "root-alias.cjs", distFile: "root-alias.cjs" }); - -const resolveExtensionApiAlias = (params: { modulePath?: string } = {}): string | null => { +function resolveExtensionApiAlias(params: { modulePath?: string } = {}): string | null { try { const modulePath = params.modulePath ?? fileURLToPath(import.meta.url); const packageRoot = resolveOpenClawPackageRootSync({ @@ -133,53 +56,8 @@ const resolveExtensionApiAlias = (params: { modulePath?: string } = {}): string // ignore } return null; -}; - -const cachedPluginSdkExportedSubpaths = new Map(); - -function listPluginSdkExportedSubpaths(params: { modulePath?: string } = {}): string[] { - const modulePath = params.modulePath ?? fileURLToPath(import.meta.url); - const packageRoot = resolveOpenClawPackageRootSync({ - cwd: path.dirname(modulePath), - }); - if (!packageRoot) { - return []; - } - const cached = cachedPluginSdkExportedSubpaths.get(packageRoot); - if (cached) { - return cached; - } - try { - const pkgRaw = fs.readFileSync(path.join(packageRoot, "package.json"), "utf-8"); - const pkg = JSON.parse(pkgRaw) as { - exports?: Record; - }; - const subpaths = Object.keys(pkg.exports ?? {}) - .filter((key) => key.startsWith("./plugin-sdk/")) - .map((key) => key.slice("./plugin-sdk/".length)) - .filter((subpath) => Boolean(subpath) && !subpath.includes("/")) - .toSorted(); - cachedPluginSdkExportedSubpaths.set(packageRoot, subpaths); - return subpaths; - } catch { - return []; - } } -const resolvePluginSdkScopedAliasMap = (): Record => { - const aliasMap: Record = {}; - for (const subpath of listPluginSdkExportedSubpaths()) { - const resolved = resolvePluginSdkAliasFile({ - srcFile: `${subpath}.ts`, - distFile: `${subpath}.js`, - }); - if (resolved) { - aliasMap[`openclaw/plugin-sdk/${subpath}`] = resolved; - } - } - return aliasMap; -}; - export const __testing = { listPluginSdkAliasCandidates, listPluginSdkExportedSubpaths, @@ -188,769 +66,3 @@ export const __testing = { resolvePluginSdkAliasFile, maxPluginRegistryCacheEntries: MAX_EXTENSION_HOST_REGISTRY_CACHE_ENTRIES, }; - -function getCachedPluginRegistry(cacheKey: string): PluginRegistry | undefined { - const cached = registryCache.get(cacheKey); - if (!cached) { - return undefined; - } - // Refresh insertion order so frequently reused registries survive eviction. - registryCache.delete(cacheKey); - registryCache.set(cacheKey, cached); - return cached; -} - -function setCachedPluginRegistry(cacheKey: string, registry: PluginRegistry): void { - if (registryCache.has(cacheKey)) { - registryCache.delete(cacheKey); - } - registryCache.set(cacheKey, registry); - while (registryCache.size > MAX_PLUGIN_REGISTRY_CACHE_ENTRIES) { - const oldestKey = registryCache.keys().next().value; - if (!oldestKey) { - break; - } - registryCache.delete(oldestKey); - } -} - -function buildCacheKey(params: { - workspaceDir?: string; - plugins: NormalizedPluginsConfig; - installs?: Record; - env: NodeJS.ProcessEnv; -}): string { - const { roots, loadPaths } = resolvePluginCacheInputs({ - workspaceDir: params.workspaceDir, - loadPaths: params.plugins.loadPaths, - env: params.env, - }); - const installs = Object.fromEntries( - Object.entries(params.installs ?? {}).map(([pluginId, install]) => [ - pluginId, - { - ...install, - installPath: - typeof install.installPath === "string" - ? resolveUserPath(install.installPath, params.env) - : install.installPath, - sourcePath: - typeof install.sourcePath === "string" - ? resolveUserPath(install.sourcePath, params.env) - : install.sourcePath, - }, - ]), - ); - return `${roots.workspace ?? ""}::${roots.global ?? ""}::${roots.stock ?? ""}::${JSON.stringify({ - ...params.plugins, - installs, - loadPaths, - })}`; -} - -function validatePluginConfig(params: { - schema?: Record; - cacheKey?: string; - value?: unknown; -}): { ok: boolean; value?: Record; errors?: string[] } { - const schema = params.schema; - if (!schema) { - return { ok: true, value: params.value as Record | undefined }; - } - const cacheKey = params.cacheKey ?? JSON.stringify(schema); - const result = validateJsonSchemaValue({ - schema, - cacheKey, - value: params.value ?? {}, - }); - if (result.ok) { - return { ok: true, value: params.value as Record | undefined }; - } - return { ok: false, errors: result.errors.map((error) => error.text) }; -} - -function resolvePluginModuleExport(moduleExport: unknown): { - definition?: OpenClawPluginDefinition; - register?: OpenClawPluginDefinition["register"]; -} { - const resolved = - moduleExport && - typeof moduleExport === "object" && - "default" in (moduleExport as Record) - ? (moduleExport as { default: unknown }).default - : moduleExport; - if (typeof resolved === "function") { - return { - register: resolved as OpenClawPluginDefinition["register"], - }; - } - if (resolved && typeof resolved === "object") { - const def = resolved as OpenClawPluginDefinition; - const register = def.register ?? def.activate; - return { definition: def, register }; - } - return {}; -} - -function createPluginRecord(params: { - id: string; - name?: string; - description?: string; - version?: string; - format?: PluginFormat; - bundleFormat?: PluginBundleFormat; - bundleCapabilities?: string[]; - source: string; - rootDir?: string; - origin: PluginRecord["origin"]; - workspaceDir?: string; - enabled: boolean; - configSchema: boolean; -}): PluginRecord { - return { - id: params.id, - name: params.name ?? params.id, - description: params.description, - version: params.version, - format: params.format ?? "openclaw", - bundleFormat: params.bundleFormat, - bundleCapabilities: params.bundleCapabilities, - source: params.source, - rootDir: params.rootDir, - origin: params.origin, - workspaceDir: params.workspaceDir, - enabled: params.enabled, - status: params.enabled ? "loaded" : "disabled", - toolNames: [], - hookNames: [], - channelIds: [], - providerIds: [], - gatewayMethods: [], - cliCommands: [], - services: [], - commands: [], - httpRoutes: 0, - hookCount: 0, - configSchema: params.configSchema, - configUiHints: undefined, - configJsonSchema: undefined, - }; -} - -function recordPluginError(params: { - logger: PluginLogger; - registry: PluginRegistry; - record: PluginRecord; - seenIds: Map; - pluginId: string; - origin: PluginRecord["origin"]; - error: unknown; - logPrefix: string; - diagnosticMessagePrefix: string; -}) { - const errorText = String(params.error); - const deprecatedApiHint = - errorText.includes("api.registerHttpHandler") && errorText.includes("is not a function") - ? "deprecated api.registerHttpHandler(...) was removed; use api.registerHttpRoute(...) for plugin-owned routes or registerPluginHttpRoute(...) for dynamic lifecycle routes" - : null; - const displayError = deprecatedApiHint ? `${deprecatedApiHint} (${errorText})` : errorText; - params.logger.error(`${params.logPrefix}${displayError}`); - params.record.status = "error"; - params.record.error = displayError; - params.registry.plugins.push(params.record); - params.seenIds.set(params.pluginId, params.origin); - params.registry.diagnostics.push({ - level: "error", - pluginId: params.record.id, - source: params.record.source, - message: `${params.diagnosticMessagePrefix}${displayError}`, - }); -} - -function pushDiagnostics(diagnostics: PluginDiagnostic[], append: PluginDiagnostic[]) { - diagnostics.push(...append); -} - -type PathMatcher = { - exact: Set; - dirs: string[]; -}; - -type InstallTrackingRule = { - trackedWithoutPaths: boolean; - matcher: PathMatcher; -}; - -type PluginProvenanceIndex = { - loadPathMatcher: PathMatcher; - installRules: Map; -}; - -function createPathMatcher(): PathMatcher { - return { exact: new Set(), dirs: [] }; -} - -function addPathToMatcher( - matcher: PathMatcher, - rawPath: string, - env: NodeJS.ProcessEnv = process.env, -): void { - const trimmed = rawPath.trim(); - if (!trimmed) { - return; - } - const resolved = resolveUserPath(trimmed, env); - if (!resolved) { - return; - } - if (matcher.exact.has(resolved) || matcher.dirs.includes(resolved)) { - return; - } - const stat = safeStatSync(resolved); - if (stat?.isDirectory()) { - matcher.dirs.push(resolved); - return; - } - matcher.exact.add(resolved); -} - -function matchesPathMatcher(matcher: PathMatcher, sourcePath: string): boolean { - if (matcher.exact.has(sourcePath)) { - return true; - } - return matcher.dirs.some((dirPath) => isPathInside(dirPath, sourcePath)); -} - -function buildProvenanceIndex(params: { - config: OpenClawConfig; - normalizedLoadPaths: string[]; - env: NodeJS.ProcessEnv; -}): PluginProvenanceIndex { - const loadPathMatcher = createPathMatcher(); - for (const loadPath of params.normalizedLoadPaths) { - addPathToMatcher(loadPathMatcher, loadPath, params.env); - } - - const installRules = new Map(); - const installs = params.config.plugins?.installs ?? {}; - for (const [pluginId, install] of Object.entries(installs)) { - const rule: InstallTrackingRule = { - trackedWithoutPaths: false, - matcher: createPathMatcher(), - }; - const trackedPaths = [install.installPath, install.sourcePath] - .map((entry) => (typeof entry === "string" ? entry.trim() : "")) - .filter(Boolean); - if (trackedPaths.length === 0) { - rule.trackedWithoutPaths = true; - } else { - for (const trackedPath of trackedPaths) { - addPathToMatcher(rule.matcher, trackedPath, params.env); - } - } - installRules.set(pluginId, rule); - } - - return { loadPathMatcher, installRules }; -} - -function isTrackedByProvenance(params: { - pluginId: string; - source: string; - index: PluginProvenanceIndex; - env: NodeJS.ProcessEnv; -}): boolean { - const sourcePath = resolveUserPath(params.source, params.env); - const installRule = params.index.installRules.get(params.pluginId); - if (installRule) { - if (installRule.trackedWithoutPaths) { - return true; - } - if (matchesPathMatcher(installRule.matcher, sourcePath)) { - return true; - } - } - return matchesPathMatcher(params.index.loadPathMatcher, sourcePath); -} - -function matchesExplicitInstallRule(params: { - pluginId: string; - source: string; - index: PluginProvenanceIndex; - env: NodeJS.ProcessEnv; -}): boolean { - const sourcePath = resolveUserPath(params.source, params.env); - const installRule = params.index.installRules.get(params.pluginId); - if (!installRule || installRule.trackedWithoutPaths) { - return false; - } - return matchesPathMatcher(installRule.matcher, sourcePath); -} - -function resolveCandidateDuplicateRank(params: { - candidate: ReturnType["candidates"][number]; - manifestByRoot: Map["plugins"][number]>; - provenance: PluginProvenanceIndex; - env: NodeJS.ProcessEnv; -}): number { - const manifestRecord = params.manifestByRoot.get(params.candidate.rootDir); - const pluginId = manifestRecord?.id; - const isExplicitInstall = - params.candidate.origin === "global" && - pluginId !== undefined && - matchesExplicitInstallRule({ - pluginId, - source: params.candidate.source, - index: params.provenance, - env: params.env, - }); - - if (params.candidate.origin === "config") { - return 0; - } - if (params.candidate.origin === "global" && isExplicitInstall) { - return 1; - } - if (params.candidate.origin === "bundled") { - // Bundled plugin ids stay reserved unless the operator configured an override. - return 2; - } - if (params.candidate.origin === "workspace") { - return 3; - } - return 4; -} - -function compareDuplicateCandidateOrder(params: { - left: ReturnType["candidates"][number]; - right: ReturnType["candidates"][number]; - manifestByRoot: Map["plugins"][number]>; - provenance: PluginProvenanceIndex; - env: NodeJS.ProcessEnv; -}): number { - const leftPluginId = params.manifestByRoot.get(params.left.rootDir)?.id; - const rightPluginId = params.manifestByRoot.get(params.right.rootDir)?.id; - if (!leftPluginId || leftPluginId !== rightPluginId) { - return 0; - } - return ( - resolveCandidateDuplicateRank({ - candidate: params.left, - manifestByRoot: params.manifestByRoot, - provenance: params.provenance, - env: params.env, - }) - - resolveCandidateDuplicateRank({ - candidate: params.right, - manifestByRoot: params.manifestByRoot, - provenance: params.provenance, - env: params.env, - }) - ); -} - -function warnWhenAllowlistIsOpen(params: { - logger: PluginLogger; - pluginsEnabled: boolean; - allow: string[]; - warningCacheKey: string; - discoverablePlugins: Array<{ id: string; source: string; origin: PluginRecord["origin"] }>; -}) { - if (!params.pluginsEnabled) { - return; - } - if (params.allow.length > 0) { - return; - } - const nonBundled = params.discoverablePlugins.filter((entry) => entry.origin !== "bundled"); - if (nonBundled.length === 0) { - return; - } - if (openAllowlistWarningCache.has(params.warningCacheKey)) { - return; - } - const preview = nonBundled - .slice(0, 6) - .map((entry) => `${entry.id} (${entry.source})`) - .join(", "); - const extra = nonBundled.length > 6 ? ` (+${nonBundled.length - 6} more)` : ""; - openAllowlistWarningCache.add(params.warningCacheKey); - params.logger.warn( - `[plugins] plugins.allow is empty; discovered non-bundled plugins may auto-load: ${preview}${extra}. Set plugins.allow to explicit trusted ids.`, - ); -} - -function warnAboutUntrackedLoadedPlugins(params: { - registry: PluginRegistry; - provenance: PluginProvenanceIndex; - logger: PluginLogger; - env: NodeJS.ProcessEnv; -}) { - for (const plugin of params.registry.plugins) { - if (plugin.status !== "loaded" || plugin.origin === "bundled") { - continue; - } - if ( - isTrackedByProvenance({ - pluginId: plugin.id, - source: plugin.source, - index: params.provenance, - env: params.env, - }) - ) { - continue; - } - const message = - "loaded without install/load-path provenance; treat as untracked local code and pin trust via plugins.allow or install records"; - params.registry.diagnostics.push({ - level: "warn", - pluginId: plugin.id, - source: plugin.source, - message, - }); - params.logger.warn(`[plugins] ${plugin.id}: ${message} (${plugin.source})`); - } -} - -function activatePluginRegistry(registry: PluginRegistry, cacheKey: string): void { - setActivePluginRegistry(registry, cacheKey); - initializeGlobalHookRunner(registry); -} - -export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegistry { - const env = options.env ?? process.env; - // Test env: default-disable plugins unless explicitly configured. - // This keeps unit/gateway suites fast and avoids loading heavyweight plugin deps by accident. - const cfg = applyTestPluginDefaults(options.config ?? {}, env); - const logger = options.logger ?? defaultLogger(); - const validateOnly = options.mode === "validate"; - const normalized = normalizePluginsConfig(cfg.plugins); - const cacheKey = buildExtensionHostRegistryCacheKey({ - workspaceDir: options.workspaceDir, - plugins: normalized, - installs: cfg.plugins?.installs, - env, - }); - const cacheEnabled = options.cache !== false; - if (cacheEnabled) { - const cached = getCachedExtensionHostRegistry(cacheKey); - if (cached) { - activateExtensionHostRegistry(cached, cacheKey); - return cached; - } - } - - // Clear previously registered plugin commands before reloading - clearPluginCommands(); - clearPluginInteractiveHandlers(); - - // Lazily initialize the runtime so startup paths that discover/skip plugins do - // not eagerly load every channel runtime dependency. - let resolvedRuntime: PluginRuntime | null = null; - const resolveRuntime = (): PluginRuntime => { - resolvedRuntime ??= createPluginRuntime(options.runtimeOptions); - return resolvedRuntime; - }; - const runtime = new Proxy({} as PluginRuntime, { - get(_target, prop, receiver) { - return Reflect.get(resolveRuntime(), prop, receiver); - }, - set(_target, prop, value, receiver) { - return Reflect.set(resolveRuntime(), prop, value, receiver); - }, - has(_target, prop) { - return Reflect.has(resolveRuntime(), prop); - }, - ownKeys() { - return Reflect.ownKeys(resolveRuntime() as object); - }, - getOwnPropertyDescriptor(_target, prop) { - return Reflect.getOwnPropertyDescriptor(resolveRuntime() as object, prop); - }, - defineProperty(_target, prop, attributes) { - return Reflect.defineProperty(resolveRuntime() as object, prop, attributes); - }, - deleteProperty(_target, prop) { - return Reflect.deleteProperty(resolveRuntime() as object, prop); - }, - getPrototypeOf() { - return Reflect.getPrototypeOf(resolveRuntime() as object); - }, - }); - const { registry, createApi } = createPluginRegistry({ - logger, - runtime, - coreGatewayHandlers: options.coreGatewayHandlers as Record, - }); - - const discovery = discoverOpenClawPlugins({ - workspaceDir: options.workspaceDir, - extraPaths: normalized.loadPaths, - cache: options.cache, - env, - }); - const manifestRegistry = loadPluginManifestRegistry({ - config: cfg, - workspaceDir: options.workspaceDir, - cache: options.cache, - env, - candidates: discovery.candidates, - diagnostics: discovery.diagnostics, - }); - pushExtensionHostDiagnostics(registry.diagnostics, manifestRegistry.diagnostics); - warnWhenExtensionAllowlistIsOpen({ - logger, - pluginsEnabled: normalized.enabled, - allow: normalized.allow, - warningCacheKey: cacheKey, - warningCache: openAllowlistWarningCache, - discoverablePlugins: manifestRegistry.plugins.map((plugin) => ({ - id: plugin.id, - source: plugin.source, - origin: plugin.origin, - })), - }); - const provenance = buildExtensionHostProvenanceIndex({ - config: cfg, - normalizedLoadPaths: normalized.loadPaths, - env, - }); - - // Lazy: avoid creating the Jiti loader when all plugins are disabled (common in unit tests). - let jitiLoader: ReturnType | null = null; - const getJiti = () => { - if (jitiLoader) { - return jitiLoader; - } - const pluginSdkAlias = resolvePluginSdkAlias(); - const extensionApiAlias = resolveExtensionApiAlias(); - const aliasMap = { - ...(extensionApiAlias ? { "openclaw/extension-api": extensionApiAlias } : {}), - ...(pluginSdkAlias ? { "openclaw/plugin-sdk": pluginSdkAlias } : {}), - ...resolvePluginSdkScopedAliasMap(), - }; - jitiLoader = createJiti(import.meta.url, { - interopDefault: true, - extensions: [".ts", ".tsx", ".mts", ".cts", ".mtsx", ".ctsx", ".js", ".mjs", ".cjs", ".json"], - ...(Object.keys(aliasMap).length > 0 - ? { - alias: aliasMap, - } - : {}), - }); - return jitiLoader; - }; - - const manifestByRoot = new Map( - manifestRegistry.plugins.map((record) => [record.rootDir, record]), - ); - const orderedCandidates = [...discovery.candidates].toSorted((left, right) => { - return compareExtensionHostDuplicateCandidateOrder({ - left, - right, - manifestByRoot, - provenance, - env, - }); - }); - - const seenIds = new Map(); - const memorySlot = normalized.slots.memory; - let selectedMemoryPluginId: string | null = null; - let memorySlotMatched = false; - - for (const candidate of orderedCandidates) { - const manifestRecord = manifestByRoot.get(candidate.rootDir); - if (!manifestRecord) { - continue; - } - const pluginId = manifestRecord.id; - const existingOrigin = seenIds.get(pluginId); - if (existingOrigin) { - const record = createExtensionHostPluginRecord({ - id: pluginId, - name: manifestRecord.name ?? pluginId, - description: manifestRecord.description, - version: manifestRecord.version, - format: manifestRecord.format, - bundleFormat: manifestRecord.bundleFormat, - bundleCapabilities: manifestRecord.bundleCapabilities, - source: candidate.source, - rootDir: candidate.rootDir, - origin: candidate.origin, - workspaceDir: candidate.workspaceDir, - enabled: false, - configSchema: Boolean(manifestRecord.configSchema), - }); - setExtensionHostPluginRecordDisabled(record, `overridden by ${existingOrigin} plugin`); - appendExtensionHostPluginRecord({ registry, record }); - continue; - } - - const enableState = resolveEffectiveEnableState({ - id: pluginId, - origin: candidate.origin, - config: normalized, - rootConfig: cfg, - }); - const entry = normalized.entries[pluginId]; - const record = createExtensionHostPluginRecord({ - id: pluginId, - name: manifestRecord.name ?? pluginId, - description: manifestRecord.description, - version: manifestRecord.version, - format: manifestRecord.format, - bundleFormat: manifestRecord.bundleFormat, - bundleCapabilities: manifestRecord.bundleCapabilities, - source: candidate.source, - rootDir: candidate.rootDir, - origin: candidate.origin, - workspaceDir: candidate.workspaceDir, - enabled: enableState.enabled, - configSchema: Boolean(manifestRecord.configSchema), - }); - record.kind = manifestRecord.kind; - record.configUiHints = manifestRecord.configUiHints; - record.configJsonSchema = manifestRecord.configSchema; - const pushPluginLoadError = (message: string) => { - setExtensionHostPluginRecordError(record, message); - appendExtensionHostPluginRecord({ - registry, - record, - seenIds, - pluginId, - origin: candidate.origin, - }); - registry.diagnostics.push({ - level: "error", - pluginId: record.id, - source: record.source, - message: record.error, - }); - }; - - if (!enableState.enabled) { - setExtensionHostPluginRecordDisabled(record, enableState.reason); - appendExtensionHostPluginRecord({ - registry, - record, - seenIds, - pluginId, - origin: candidate.origin, - }); - continue; - } - - if (record.format === "bundle") { - const unsupportedCapabilities = (record.bundleCapabilities ?? []).filter( - (capability) => - capability !== "skills" && - capability !== "settings" && - !( - capability === "commands" && - (record.bundleFormat === "claude" || record.bundleFormat === "cursor") - ) && - !(capability === "hooks" && record.bundleFormat === "codex"), - ); - for (const capability of unsupportedCapabilities) { - registry.diagnostics.push({ - level: "warn", - pluginId: record.id, - source: record.source, - message: `bundle capability detected but not wired into OpenClaw yet: ${capability}`, - }); - } - registry.plugins.push(record); - seenIds.set(pluginId, candidate.origin); - continue; - } - - // Fast-path bundled memory plugins that are guaranteed disabled by slot policy. - // This avoids opening/importing heavy memory plugin modules that will never register. - const earlyMemoryDecision = resolveExtensionHostEarlyMemoryDecision({ - origin: candidate.origin, - manifestKind: manifestRecord.kind, - recordId: record.id, - memorySlot, - selectedMemoryPluginId, - }); - if (!earlyMemoryDecision.enabled) { - setExtensionHostPluginRecordDisabled(record, earlyMemoryDecision.reason); - appendExtensionHostPluginRecord({ - registry, - record, - seenIds, - pluginId, - origin: candidate.origin, - }); - continue; - } - - if (!manifestRecord.configSchema) { - pushPluginLoadError("missing config schema"); - continue; - } - - const moduleImport = importExtensionHostPluginModule({ - rootDir: candidate.rootDir, - source: candidate.source, - origin: candidate.origin, - loadModule: (safeSource) => getJiti()(safeSource), - }); - if (!moduleImport.ok) { - if (moduleImport.message !== "failed to load plugin") { - pushPluginLoadError(moduleImport.message); - continue; - } - recordExtensionHostPluginError({ - logger, - registry, - record, - seenIds, - pluginId, - origin: candidate.origin, - error: moduleImport.error, - logPrefix: `[plugins] ${record.id} failed to load from ${record.source}: `, - diagnosticMessagePrefix: "failed to load plugin: ", - }); - continue; - } - - const resolved = resolveExtensionHostModuleExport(moduleImport.module as OpenClawPluginModule); - const definition = resolved.definition; - const register = resolved.register; - - const loadedPlan = planExtensionHostLoadedPlugin({ - record, - manifestRecord, - definition, - register, - diagnostics: registry.diagnostics, - memorySlot, - selectedMemoryPluginId, - entryConfig: entry?.config, - validateOnly, - logger, - registry, - seenIds, - selectedMemoryPluginId, - createApi, - loadModule: (safeSource) => getJiti()(safeSource) as OpenClawPluginModule, - }); - selectedMemoryPluginId = processed.selectedMemoryPluginId; - memorySlotMatched ||= processed.memorySlotMatched; - } - - return finalizeExtensionHostRegistryLoad({ - registry, - memorySlot, - memorySlotMatched, - provenance, - logger, - env, - cacheEnabled, - cacheKey, - setCachedRegistry: setCachedExtensionHostRegistry, - activateRegistry: activateExtensionHostRegistry, - }); -} diff --git a/src/plugins/manifest-registry.ts b/src/plugins/manifest-registry.ts index 2669fc98a32..75cfe659d4c 100644 --- a/src/plugins/manifest-registry.ts +++ b/src/plugins/manifest-registry.ts @@ -3,12 +3,13 @@ import type { OpenClawConfig } from "../config/config.js"; import { buildResolvedExtensionRecord, type ResolvedExtensionRecord, -} from "../extension-host/manifest-registry.js"; +} from "../extension-host/manifests/manifest-registry.js"; +import { resolveLegacyExtensionDescriptor } from "../extension-host/manifests/schema.js"; import { resolveUserPath } from "../utils.js"; import { loadBundleManifest } from "./bundle-manifest.js"; import { normalizePluginsConfig, type NormalizedPluginsConfig } from "./config-state.js"; import { discoverOpenClawPlugins, type PluginCandidate } from "./discovery.js"; -import { loadPluginManifest, type PluginManifest } from "./manifest.js"; +import { loadPluginManifest, type PackageManifest, type PluginManifest } from "./manifest.js"; import { isPathInside, safeRealpathSync } from "./path-safety.js"; import { resolvePluginCacheInputs } from "./roots.js"; import type { @@ -175,6 +176,35 @@ function buildBundleRecord(params: { candidate: PluginCandidate; manifestPath: string; }): PluginManifestRecord { + const packageManifest = + params.candidate.packageManifest || + params.candidate.packageName || + params.candidate.packageVersion || + params.candidate.packageDescription + ? ({ + openclaw: params.candidate.packageManifest, + name: params.candidate.packageName, + version: params.candidate.packageVersion, + description: params.candidate.packageDescription, + } as PackageManifest) + : undefined; + const resolvedExtension = resolveLegacyExtensionDescriptor({ + manifest: { + id: params.manifest.id, + configSchema: {}, + channels: [], + providers: [], + skills: params.manifest.skills ?? [], + name: params.manifest.name, + description: params.manifest.description, + version: params.manifest.version, + }, + packageManifest, + origin: params.candidate.origin, + rootDir: params.candidate.rootDir, + source: params.candidate.source, + workspaceDir: params.candidate.workspaceDir, + }); return { id: params.manifest.id, name: normalizeManifestLabel(params.manifest.name) ?? params.candidate.idHint, @@ -196,6 +226,7 @@ function buildBundleRecord(params: { schemaCacheKey: undefined, configSchema: undefined, configUiHints: undefined, + resolvedExtension, }; } diff --git a/src/plugins/provider-discovery.ts b/src/plugins/provider-discovery.ts index 1fb95d221a5..42d22a3e87c 100644 --- a/src/plugins/provider-discovery.ts +++ b/src/plugins/provider-discovery.ts @@ -1,10 +1,6 @@ import type { OpenClawConfig } from "../config/config.js"; import type { ModelProviderConfig } from "../config/types.js"; -import { - groupExtensionHostDiscoveryProvidersByOrder, - normalizeExtensionHostDiscoveryResult, - resolveExtensionHostDiscoveryProviders, -} from "../extension-host/provider-discovery.js"; +import { normalizeExtensionHostDiscoveryResult } from "../extension-host/contributions/provider-discovery.js"; import { resolvePluginProviders } from "./providers.js"; import type { ProviderDiscoveryOrder, ProviderPlugin } from "./types.js"; diff --git a/src/plugins/provider-wizard.ts b/src/plugins/provider-wizard.ts index 4f5efb64d95..557478793c0 100644 --- a/src/plugins/provider-wizard.ts +++ b/src/plugins/provider-wizard.ts @@ -1,11 +1,11 @@ import type { OpenClawConfig } from "../config/config.js"; -import { runExtensionHostProviderModelSelectedHook } from "../extension-host/provider-model-selection.js"; +import { runExtensionHostProviderModelSelectedHook } from "../extension-host/contributions/provider-model-selection.js"; import { buildExtensionHostProviderMethodChoice, resolveExtensionHostProviderChoice, resolveExtensionHostProviderModelPickerEntries, resolveExtensionHostProviderWizardOptions, -} from "../extension-host/provider-wizard.js"; +} from "../extension-host/contributions/provider-wizard.js"; import type { WizardPrompter } from "../wizard/prompts.js"; import { resolvePluginProviders } from "./providers.js"; import type { ProviderAuthMethod, ProviderPlugin } from "./types.js"; diff --git a/src/plugins/providers.ts b/src/plugins/providers.ts index 9827903240e..aa50c05fe9e 100644 --- a/src/plugins/providers.ts +++ b/src/plugins/providers.ts @@ -1,4 +1,4 @@ -import { resolveExtensionHostProviders } from "../extension-host/provider-runtime.js"; +import { resolveExtensionHostProviders } from "../extension-host/contributions/provider-runtime.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import { loadOpenClawPlugins, type PluginLoadOptions } from "./loader.js"; import { createPluginLoaderLogger } from "./logger.js"; diff --git a/src/plugins/registry.ts b/src/plugins/registry.ts index e36c9b10f76..4ec98ca768d 100644 --- a/src/plugins/registry.ts +++ b/src/plugins/registry.ts @@ -1,39 +1,26 @@ import type { ChannelDock } from "../channels/dock.js"; import type { ChannelPlugin } from "../channels/plugins/types.js"; -import { registerContextEngineForOwner } from "../context-engine/registry.js"; -import type { - GatewayRequestHandler, - GatewayRequestHandlers, -} from "../gateway/server-methods/types.js"; -import { registerInternalHook } from "../hooks/internal-hooks.js"; -import { registerPluginCommand } from "./commands.js"; -import { normalizePluginHttpPath } from "./http-path.js"; -import { findOverlappingPluginHttpRoute } from "./http-route-overlap.js"; -import { registerPluginInteractiveHandler } from "./interactive.js"; -import { normalizeRegisteredProvider } from "./provider-validation.js"; +import { createExtensionHostPluginRegistry } from "../extension-host/compat/plugin-registry.js"; +import type { GatewayRequestHandlers } from "../gateway/server-methods/types.js"; +import type { HookEntry } from "../hooks/types.js"; import type { PluginRuntime } from "./runtime/types.js"; -import { defaultSlotIdForKey } from "./slots.js"; -import { - isPromptInjectionHookName, - stripPromptMutationFieldsFromLegacyHookResult, -} from "./types.js"; import type { OpenClawPluginCliRegistrar, OpenClawPluginCommandDefinition, OpenClawPluginHttpRouteAuth, - OpenClawPluginHttpRouteMatch, OpenClawPluginHttpRouteHandler, - ProviderPlugin, + OpenClawPluginHttpRouteMatch, OpenClawPluginService, OpenClawPluginToolFactory, + PluginBundleFormat, PluginConfigUiHint, PluginDiagnostic, - PluginBundleFormat, PluginFormat, + PluginKind, PluginLogger, PluginOrigin, - PluginKind, PluginHookRegistration as TypedPluginHookRegistration, + ProviderPlugin, } from "./types.js"; export type PluginToolRegistration = { @@ -185,530 +172,8 @@ export function createEmptyPluginRegistry(): PluginRegistry { } export function createPluginRegistry(registryParams: PluginRegistryParams) { - const registry = createEmptyPluginRegistry(); - const coreGatewayMethods = new Set(Object.keys(registryParams.coreGatewayHandlers ?? {})); - - const pushDiagnostic = (diag: PluginDiagnostic) => { - registry.diagnostics.push(diag); - }; - - const registerTool = ( - record: PluginRecord, - tool: AnyAgentTool | OpenClawPluginToolFactory, - opts?: { name?: string; names?: string[]; optional?: boolean }, - ) => { - const names = opts?.names ?? (opts?.name ? [opts.name] : []); - const optional = opts?.optional === true; - const factory: OpenClawPluginToolFactory = - typeof tool === "function" ? tool : (_ctx: OpenClawPluginToolContext) => tool; - - if (typeof tool !== "function") { - names.push(tool.name); - } - - const normalized = names.map((name) => name.trim()).filter(Boolean); - if (normalized.length > 0) { - record.toolNames.push(...normalized); - } - registry.tools.push({ - pluginId: record.id, - pluginName: record.name, - factory, - names: normalized, - optional, - source: record.source, - rootDir: record.rootDir, - }); - addExtensionToolRegistration({ registry, record, names: result.names, entry: result.entry }); - }; - - const registerHook = ( - record: PluginRecord, - events: string | string[], - handler: Parameters[1], - opts: OpenClawPluginHookOptions | undefined, - config: OpenClawPluginApi["config"], - ) => { - const normalized = resolveExtensionLegacyHookRegistration({ - ownerPluginId: record.id, - ownerSource: record.source, - events, - handler, - opts, - }); - if (!normalized.ok) { - pushDiagnostic({ - level: "warn", - pluginId: record.id, - source: record.source, - message: normalized.message, - }); - return; - } - const existingHook = registry.hooks.find((entry) => entry.entry.hook.name === name); - if (existingHook) { - pushDiagnostic({ - level: "error", - pluginId: record.id, - source: record.source, - message: `hook already registered: ${name} (${existingHook.pluginId})`, - }); - return; - } - - const description = entry?.hook.description ?? opts?.description ?? ""; - const hookEntry: HookEntry = entry - ? { - ...entry, - hook: { - ...entry.hook, - name, - description, - source: "openclaw-plugin", - pluginId: record.id, - }, - metadata: { - ...entry.metadata, - events: normalizedEvents, - }, - } - : { - hook: { - name, - description, - source: "openclaw-plugin", - pluginId: record.id, - filePath: record.source, - baseDir: path.dirname(record.source), - handlerPath: record.source, - }, - frontmatter: {}, - metadata: { events: normalizedEvents }, - invocation: { enabled: true }, - }; - - record.hookNames.push(name); - registry.hooks.push({ - pluginId: normalized.entry.pluginId, - entry: normalized.entry.entry, - events: normalized.events, - }); - - bridgeExtensionHostLegacyHooks({ - events: normalized.events, - handler, - hookSystemEnabled: config?.hooks?.internal?.enabled === true, - register: opts?.register, - registerHook: registerInternalHook, - }); - }; - - const registerGatewayMethod = ( - record: PluginRecord, - method: string, - handler: GatewayRequestHandler, - ) => { - const result = resolveExtensionGatewayMethodRegistration({ - existing: registry.gatewayHandlers, - coreGatewayMethods, - method, - handler, - }); - if (!result.ok) { - pushDiagnostic({ - level: "error", - pluginId: record.id, - source: record.source, - message: result.message, - }); - return; - } - addExtensionGatewayMethodRegistration({ - registry, - record, - method: result.method, - handler: result.handler, - }); - }; - - const registerHttpRoute = (record: PluginRecord, params: OpenClawPluginHttpRouteParams) => { - const result = resolveExtensionHttpRouteRegistration({ - existing: registry.httpRoutes, - ownerPluginId: record.id, - ownerSource: record.source, - route: params, - }); - if (!result.ok) { - pushDiagnostic({ - level: result.message === "http route registration missing path" ? "warn" : "error", - pluginId: record.id, - source: record.source, - message: result.message, - }); - return; - } - if (result.action === "replace") { - addExtensionHttpRouteRegistration({ - registry, - record, - action: "replace", - existingIndex: result.existingIndex, - entry: result.entry, - }); - return; - } - addExtensionHttpRouteRegistration({ - registry, - record, - action: "append", - entry: result.entry, - }); - }; - - const registerChannel = ( - record: PluginRecord, - registration: OpenClawPluginChannelRegistration | ChannelPlugin, - ) => { - const normalized = - typeof (registration as OpenClawPluginChannelRegistration).plugin === "object" - ? (registration as OpenClawPluginChannelRegistration) - : { plugin: registration as ChannelPlugin }; - const plugin = normalized.plugin; - const id = typeof plugin?.id === "string" ? plugin.id.trim() : String(plugin?.id ?? "").trim(); - if (!id) { - pushDiagnostic({ - level: "error", - pluginId: record.id, - source: record.source, - message: "channel registration missing id", - }); - return; - } - const existing = registry.channels.find((entry) => entry.plugin.id === id); - if (existing) { - pushDiagnostic({ - level: "error", - pluginId: record.id, - source: record.source, - message: `channel already registered: ${id} (${existing.pluginId})`, - }); - return; - } - record.channelIds.push(id); - registry.channels.push({ - pluginId: record.id, - pluginName: record.name, - plugin, - dock: normalized.dock, - source: record.source, - rootDir: record.rootDir, - }); - if (!result.ok) { - pushDiagnostic({ - level: "error", - pluginId: record.id, - source: record.source, - message: result.message, - }); - return; - } - addExtensionChannelRegistration({ - registry, - record, - channelId: result.channelId, - entry: result.entry, - }); - }; - - const registerProvider = (record: PluginRecord, provider: ProviderPlugin) => { - const normalizedProvider = normalizeRegisteredProvider({ - pluginId: record.id, - source: record.source, - provider, - pushDiagnostic, - }); - if (!normalizedProvider) { - return; - } - const result = resolveExtensionProviderRegistration({ - existing: registry.providers, - ownerPluginId: record.id, - ownerSource: record.source, - provider: normalizedProvider, - }); - if (!result.ok) { - pushDiagnostic({ - level: "error", - pluginId: record.id, - source: record.source, - message: result.message, - }); - return; - } - record.providerIds.push(id); - registry.providers.push({ - pluginId: record.id, - pluginName: record.name, - provider: normalizedProvider, - source: record.source, - rootDir: record.rootDir, - }); - }; - - const registerCli = ( - record: PluginRecord, - registrar: OpenClawPluginCliRegistrar, - opts?: { commands?: string[] }, - ) => { - const commands = (opts?.commands ?? []).map((cmd) => cmd.trim()).filter(Boolean); - if (commands.length === 0) { - pushDiagnostic({ - level: "error", - pluginId: record.id, - source: record.source, - message: "cli registration missing explicit commands metadata", - }); - return; - } - const existing = registry.cliRegistrars.find((entry) => - entry.commands.some((command) => commands.includes(command)), - ); - if (existing) { - const overlap = commands.find((command) => existing.commands.includes(command)); - pushDiagnostic({ - level: "error", - pluginId: record.id, - source: record.source, - message: `cli command already registered: ${overlap ?? commands[0]} (${existing.pluginId})`, - }); - return; - } - record.cliCommands.push(...commands); - registry.cliRegistrars.push({ - pluginId: record.id, - pluginName: record.name, - register: registrar, - commands, - source: record.source, - rootDir: record.rootDir, - }); - addExtensionCliRegistration({ - registry, - record, - commands: result.commands, - entry: result.entry, - }); - }; - - const registerService = (record: PluginRecord, service: OpenClawPluginService) => { - const result = resolveExtensionServiceRegistration({ - ownerPluginId: record.id, - ownerSource: record.source, - service, - }); - if (!result.ok) { - return; - } - const existing = registry.services.find((entry) => entry.service.id === id); - if (existing) { - pushDiagnostic({ - level: "error", - pluginId: record.id, - source: record.source, - message: `service already registered: ${id} (${existing.pluginId})`, - }); - return; - } - record.services.push(id); - registry.services.push({ - pluginId: record.id, - pluginName: record.name, - service, - source: record.source, - rootDir: record.rootDir, - }); - }; - - const registerCommand = (record: PluginRecord, command: OpenClawPluginCommandDefinition) => { - const normalized = resolveExtensionCommandRegistration({ - ownerPluginId: record.id, - ownerSource: record.source, - command, - }); - if (!normalized.ok) { - pushDiagnostic({ - level: "error", - pluginId: record.id, - source: record.source, - message: normalized.message, - }); - return; - } - - // Register with the plugin command system (validates name and checks for duplicates) - const result = registerPluginCommand(record.id, command, { - pluginName: record.name, - pluginRoot: record.rootDir, - }); - if (!result.ok) { - pushDiagnostic({ - level: "error", - pluginId: record.id, - source: record.source, - message: `command registration failed: ${result.error}`, - }); - return; - } - - record.commands.push(name); - registry.commands.push({ - pluginId: record.id, - pluginName: record.name, - command, - source: record.source, - rootDir: record.rootDir, - }); - }; - - const registerTypedHook = ( - record: PluginRecord, - hookName: K, - handler: PluginHookHandlerMap[K], - opts?: { priority?: number }, - policy?: PluginTypedHookPolicy, - ) => { - const normalized = resolveExtensionTypedHookRegistration({ - ownerPluginId: record.id, - ownerSource: record.source, - hookName, - handler, - priority: opts?.priority, - }); - if (!normalized.ok) { - pushDiagnostic({ - level: "warn", - pluginId: record.id, - source: record.source, - message: normalized.message, - }); - return; - } - const policyResult = applyExtensionHostTypedHookPolicy({ - hookName: normalized.hookName, - handler, - policy, - blockedMessage: `typed hook "${normalized.hookName}" blocked by plugins.entries.${record.id}.hooks.allowPromptInjection=false`, - constrainedMessage: `typed hook "${normalized.hookName}" prompt fields constrained by plugins.entries.${record.id}.hooks.allowPromptInjection=false`, - }); - if (!policyResult.ok) { - pushDiagnostic({ - level: "warn", - pluginId: record.id, - source: record.source, - message: policyResult.message, - }); - return; - } - if (policyResult.warningMessage) { - pushDiagnostic({ - level: "warn", - pluginId: record.id, - source: record.source, - message: policyResult.warningMessage, - }); - } - addExtensionTypedHookRegistration({ - registry, - record, - entry: { - ...normalized.entry, - pluginId: record.id, - hookName: normalized.hookName, - handler: policyResult.entryHandler, - } as TypedPluginHookRegistration, - }); - }; - - const createApi = ( - record: PluginRecord, - params: { - config: OpenClawPluginApi["config"]; - pluginConfig?: Record; - hookPolicy?: PluginTypedHookPolicy; - }, - ): OpenClawPluginApi => { - return { - id: record.id, - name: record.name, - version: record.version, - description: record.description, - source: record.source, - rootDir: record.rootDir, - config: params.config, - pluginConfig: params.pluginConfig, - registerTool: (tool, opts) => registerTool(record, tool, opts), - registerHook: (events, handler, opts) => - registerHook(record, events, handler, opts, params.config), - registerHttpRoute: (routeParams) => registerHttpRoute(record, routeParams), - registerChannel: (registration) => registerChannel(record, registration as never), - registerProvider: (provider) => registerProvider(record, provider), - registerGatewayMethod: (method, handler) => registerGatewayMethod(record, method, handler), - registerCli: (registrar, opts) => registerCli(record, registrar, opts), - registerService: (service) => registerService(record, service), - registerInteractiveHandler: (registration) => { - const result = registerPluginInteractiveHandler(record.id, registration, { - pluginName: record.name, - pluginRoot: record.rootDir, - }); - if (!result.ok) { - pushDiagnostic({ - level: "warn", - pluginId: record.id, - source: record.source, - message: result.error ?? "interactive handler registration failed", - }); - } - }, - registerCommand: (command) => registerCommand(record, command), - registerContextEngine: (id, factory) => { - if (id === defaultSlotIdForKey("contextEngine")) { - pushDiagnostic({ - level: "error", - pluginId: record.id, - source: record.source, - message: `context engine id reserved by core: ${id}`, - }); - return; - } - const result = registerContextEngineForOwner(id, factory, `plugin:${record.id}`, { - allowSameOwnerRefresh: true, - }); - if (!result.ok) { - pushDiagnostic({ - level: "error", - pluginId: record.id, - source: record.source, - message: `context engine already registered: ${id} (${result.existingOwner})`, - }); - } - }, - on: (hookName, handler, opts) => - registerTypedHook(record, hookName, handler, opts, params.hookPolicy), - }); - }; - - return { - registry, - createApi, - pushDiagnostic, - registerTool, - registerChannel, - registerProvider, - registerGatewayMethod, - registerCli, - registerService, - registerCommand, - registerHook, - registerTypedHook, - }; + return createExtensionHostPluginRegistry({ + registry: createEmptyPluginRegistry(), + registryParams, + }); } diff --git a/src/plugins/runtime.ts b/src/plugins/runtime.ts index b10c7c9106d..fa3043a8b66 100644 --- a/src/plugins/runtime.ts +++ b/src/plugins/runtime.ts @@ -5,7 +5,7 @@ import { requireActiveExtensionHostRegistry, setActiveExtensionHostRegistry, type ExtensionHostRegistry, -} from "../extension-host/active-registry.js"; +} from "../extension-host/static/active-registry.js"; export type PluginRegistry = ExtensionHostRegistry; diff --git a/src/plugins/services.ts b/src/plugins/services.ts index ff3feaf9002..d0eeda11cb1 100644 --- a/src/plugins/services.ts +++ b/src/plugins/services.ts @@ -1,8 +1,5 @@ import type { OpenClawConfig } from "../config/config.js"; -import { - startExtensionHostServices, - type ExtensionHostServicesHandle, -} from "../extension-host/service-lifecycle.js"; +import type { ExtensionHostServicesHandle } from "../extension-host/contributions/service-lifecycle.js"; import type { PluginRegistry } from "./registry.js"; export type PluginServicesHandle = ExtensionHostServicesHandle; diff --git a/src/plugins/tools.ts b/src/plugins/tools.ts index 89841058017..805774af57f 100644 --- a/src/plugins/tools.ts +++ b/src/plugins/tools.ts @@ -3,7 +3,7 @@ import { getExtensionHostPluginToolMeta, resolveExtensionHostPluginTools, type ExtensionHostPluginToolMeta, -} from "../extension-host/tool-runtime.js"; +} from "../extension-host/contributions/tool-runtime.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import { applyTestPluginDefaults, normalizePluginsConfig } from "./config-state.js"; import { loadOpenClawPlugins } from "./loader.js"; diff --git a/src/utils/message-channel.test.ts b/src/utils/message-channel.test.ts index 218d4fedb5f..2513fc298a6 100644 --- a/src/utils/message-channel.test.ts +++ b/src/utils/message-channel.test.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest"; import type { ChannelPlugin } from "../channels/plugins/types.js"; -import { addExtensionHostChannelRegistration } from "../extension-host/runtime-registry.js"; +import { addExtensionHostChannelRegistration } from "../extension-host/contributions/runtime-registry.js"; import { setActivePluginRegistry } from "../plugins/runtime.js"; import { createMSTeamsTestPluginBase, createTestRegistry } from "../test-utils/channel-plugins.js"; import { resolveGatewayMessageChannel } from "./message-channel.js"; diff --git a/src/utils/message-channel.ts b/src/utils/message-channel.ts index adcd204975d..de4d9c3a71f 100644 --- a/src/utils/message-channel.ts +++ b/src/utils/message-channel.ts @@ -4,8 +4,8 @@ import { listChatChannelAliases, normalizeChatChannelId, } from "../channels/registry.js"; -import { getActiveExtensionHostRegistry } from "../extension-host/active-registry.js"; -import { listExtensionHostChannelRegistrations } from "../extension-host/runtime-registry.js"; +import { listExtensionHostChannelRegistrations } from "../extension-host/contributions/runtime-registry.js"; +import { getActiveExtensionHostRegistry } from "../extension-host/static/active-registry.js"; import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES,