Plugins: extract loader execution setup
This commit is contained in:
parent
6fb5324f73
commit
977610fbde
@ -43,6 +43,7 @@ This is an implementation checklist, not a future-design spec.
|
||||
| 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` | Cache hits, runtime creation, discovery, manifest loading, candidate ordering, candidate processing, and finalization now route through a host-owned loader orchestrator while `src/plugins/loader.ts` remains the compatibility facade. |
|
||||
| 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. |
|
||||
|
||||
49
src/extension-host/loader-execution.test.ts
Normal file
49
src/extension-host/loader-execution.test.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { prepareExtensionHostLoaderExecution } from "./loader-execution.js";
|
||||
|
||||
describe("extension host loader execution", () => {
|
||||
it("composes runtime, registry, bootstrap, module loader, and session setup", () => {
|
||||
const runtime = {} as never;
|
||||
const registry = { plugins: [], diagnostics: [] } as never;
|
||||
const createApi = vi.fn() as never;
|
||||
const loadModule = vi.fn() as never;
|
||||
const session = { registry } as never;
|
||||
|
||||
const result = prepareExtensionHostLoaderExecution({
|
||||
config: {},
|
||||
env: process.env,
|
||||
cacheKey: "cache-key",
|
||||
normalizedConfig: {
|
||||
enabled: true,
|
||||
allow: [],
|
||||
loadPaths: [],
|
||||
entries: {},
|
||||
slots: {},
|
||||
},
|
||||
logger: {
|
||||
info: () => {},
|
||||
warn: () => {},
|
||||
error: () => {},
|
||||
},
|
||||
warningCache: new Set<string>(),
|
||||
setCachedRegistry: vi.fn(),
|
||||
activateRegistry: vi.fn(),
|
||||
createRuntime: vi.fn(() => runtime) as never,
|
||||
createRegistry: vi.fn(() => ({ registry, createApi })) as never,
|
||||
bootstrapLoad: vi.fn(() => ({
|
||||
provenance: { loadPathMatcher: { exact: new Set(), dirs: [] }, installRules: new Map() },
|
||||
orderedCandidates: [{ rootDir: "/plugins/a" }],
|
||||
manifestByRoot: new Map([["/plugins/a", { rootDir: "/plugins/a" }]]),
|
||||
})) as never,
|
||||
createModuleLoader: vi.fn(() => loadModule) as never,
|
||||
createSession: vi.fn(() => session) as never,
|
||||
});
|
||||
|
||||
expect(result.registry).toBe(registry);
|
||||
expect(result.createApi).toBe(createApi);
|
||||
expect(result.loadModule).toBe(loadModule);
|
||||
expect(result.session).toBe(session);
|
||||
expect(result.orderedCandidates).toEqual([{ rootDir: "/plugins/a" }]);
|
||||
expect(result.manifestByRoot.get("/plugins/a")?.rootDir).toBe("/plugins/a");
|
||||
});
|
||||
});
|
||||
92
src/extension-host/loader-execution.ts
Normal file
92
src/extension-host/loader-execution.ts
Normal file
@ -0,0 +1,92 @@
|
||||
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 {
|
||||
buildExtensionHostProvenanceIndex,
|
||||
compareExtensionHostDuplicateCandidateOrder,
|
||||
pushExtensionHostDiagnostics,
|
||||
} from "./loader-policy.js";
|
||||
import { createExtensionHostLazyRuntime } from "./loader-runtime-proxy.js";
|
||||
import {
|
||||
createExtensionHostLoaderSession,
|
||||
type ExtensionHostLoaderSession,
|
||||
} from "./loader-session.js";
|
||||
|
||||
export function prepareExtensionHostLoaderExecution(params: {
|
||||
config: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
env: NodeJS.ProcessEnv;
|
||||
cache?: boolean;
|
||||
cacheKey: string;
|
||||
normalizedConfig: NormalizedPluginsConfig;
|
||||
logger: PluginLogger;
|
||||
coreGatewayHandlers?: Record<string, unknown>;
|
||||
runtimeOptions?: CreatePluginRuntimeOptions;
|
||||
warningCache: Set<string>;
|
||||
setCachedRegistry: (cacheKey: string, registry: PluginRegistry) => void;
|
||||
activateRegistry: (registry: PluginRegistry, cacheKey: string) => void;
|
||||
createRuntime: (runtimeOptions?: CreatePluginRuntimeOptions) => PluginRuntime;
|
||||
createRegistry?: typeof createPluginRegistry;
|
||||
bootstrapLoad?: typeof bootstrapExtensionHostPluginLoad;
|
||||
createModuleLoader?: typeof createExtensionHostModuleLoader;
|
||||
createSession?: typeof createExtensionHostLoaderSession;
|
||||
}) {
|
||||
const createRegistry = params.createRegistry ?? createPluginRegistry;
|
||||
const bootstrapLoad = params.bootstrapLoad ?? bootstrapExtensionHostPluginLoad;
|
||||
const createModuleLoader = params.createModuleLoader ?? createExtensionHostModuleLoader;
|
||||
const createSession = params.createSession ?? createExtensionHostLoaderSession;
|
||||
|
||||
const runtime = createExtensionHostLazyRuntime({
|
||||
runtimeOptions: params.runtimeOptions,
|
||||
createRuntime: params.createRuntime,
|
||||
});
|
||||
const { registry, createApi } = createRegistry({
|
||||
logger: params.logger,
|
||||
runtime,
|
||||
coreGatewayHandlers: params.coreGatewayHandlers as never,
|
||||
});
|
||||
|
||||
const bootstrap = bootstrapLoad({
|
||||
config: params.config,
|
||||
workspaceDir: params.workspaceDir,
|
||||
env: params.env,
|
||||
warningCacheKey: params.cacheKey,
|
||||
warningCache: params.warningCache,
|
||||
cache: params.cache,
|
||||
normalizedConfig: params.normalizedConfig,
|
||||
logger: params.logger,
|
||||
registry,
|
||||
pushDiagnostics: pushExtensionHostDiagnostics,
|
||||
resolveDiscoveryPolicy: resolveExtensionHostDiscoveryPolicy,
|
||||
buildProvenanceIndex: buildExtensionHostProvenanceIndex,
|
||||
compareDuplicateCandidateOrder: compareExtensionHostDuplicateCandidateOrder,
|
||||
});
|
||||
|
||||
const loadModule = createModuleLoader();
|
||||
const session: ExtensionHostLoaderSession = createSession({
|
||||
registry,
|
||||
logger: params.logger,
|
||||
env: params.env,
|
||||
provenance: bootstrap.provenance,
|
||||
cacheEnabled: params.cache !== false,
|
||||
cacheKey: params.cacheKey,
|
||||
memorySlot: params.normalizedConfig.slots.memory,
|
||||
setCachedRegistry: params.setCachedRegistry,
|
||||
activateRegistry: params.activateRegistry,
|
||||
});
|
||||
|
||||
return {
|
||||
registry,
|
||||
createApi,
|
||||
loadModule,
|
||||
session,
|
||||
orderedCandidates: bootstrap.orderedCandidates,
|
||||
manifestByRoot: bootstrap.manifestByRoot,
|
||||
};
|
||||
}
|
||||
@ -6,24 +6,15 @@ import {
|
||||
getCachedExtensionHostRegistry,
|
||||
setCachedExtensionHostRegistry,
|
||||
} from "../extension-host/loader-cache.js";
|
||||
import {
|
||||
buildExtensionHostProvenanceIndex,
|
||||
compareExtensionHostDuplicateCandidateOrder,
|
||||
pushExtensionHostDiagnostics,
|
||||
} from "../extension-host/loader-policy.js";
|
||||
import type { GatewayRequestHandler } from "../gateway/server-methods/types.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { clearPluginCommands } from "../plugins/commands.js";
|
||||
import { applyTestPluginDefaults, normalizePluginsConfig } from "../plugins/config-state.js";
|
||||
import { createPluginRegistry, type PluginRegistry } from "../plugins/registry.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 { bootstrapExtensionHostPluginLoad } from "./loader-bootstrap.js";
|
||||
import { resolveExtensionHostDiscoveryPolicy } from "./loader-discovery-policy.js";
|
||||
import { createExtensionHostModuleLoader } from "./loader-module-loader.js";
|
||||
import { prepareExtensionHostLoaderExecution } from "./loader-execution.js";
|
||||
import { runExtensionHostLoaderSession } from "./loader-run.js";
|
||||
import { createExtensionHostLazyRuntime } from "./loader-runtime-proxy.js";
|
||||
import { createExtensionHostLoaderSession } from "./loader-session.js";
|
||||
|
||||
export type ExtensionHostPluginLoadOptions = {
|
||||
config?: OpenClawConfig;
|
||||
@ -73,54 +64,30 @@ export function loadExtensionHostPluginRegistry(
|
||||
// Clear previously registered plugin commands before reloading.
|
||||
clearPluginCommands();
|
||||
|
||||
const runtime = createExtensionHostLazyRuntime({
|
||||
runtimeOptions: options.runtimeOptions,
|
||||
createRuntime: createPluginRuntime,
|
||||
});
|
||||
const { registry, createApi } = createPluginRegistry({
|
||||
logger,
|
||||
runtime,
|
||||
coreGatewayHandlers: options.coreGatewayHandlers as Record<string, GatewayRequestHandler>,
|
||||
});
|
||||
|
||||
const bootstrap = bootstrapExtensionHostPluginLoad({
|
||||
const execution = prepareExtensionHostLoaderExecution({
|
||||
config: cfg,
|
||||
workspaceDir: options.workspaceDir,
|
||||
env,
|
||||
warningCacheKey: cacheKey,
|
||||
warningCache: openAllowlistWarningCache,
|
||||
cache: options.cache,
|
||||
cacheKey,
|
||||
normalizedConfig: normalized,
|
||||
logger,
|
||||
registry,
|
||||
pushDiagnostics: pushExtensionHostDiagnostics,
|
||||
resolveDiscoveryPolicy: resolveExtensionHostDiscoveryPolicy,
|
||||
buildProvenanceIndex: buildExtensionHostProvenanceIndex,
|
||||
compareDuplicateCandidateOrder: compareExtensionHostDuplicateCandidateOrder,
|
||||
});
|
||||
|
||||
const loadModule = createExtensionHostModuleLoader();
|
||||
|
||||
const session = createExtensionHostLoaderSession({
|
||||
registry,
|
||||
logger,
|
||||
env,
|
||||
provenance: bootstrap.provenance,
|
||||
cacheEnabled,
|
||||
cacheKey,
|
||||
memorySlot: normalized.slots.memory,
|
||||
coreGatewayHandlers: options.coreGatewayHandlers as Record<string, GatewayRequestHandler>,
|
||||
runtimeOptions: options.runtimeOptions,
|
||||
warningCache: openAllowlistWarningCache,
|
||||
setCachedRegistry: setCachedExtensionHostRegistry,
|
||||
activateRegistry: activateExtensionHostRegistry,
|
||||
createRuntime: createPluginRuntime,
|
||||
});
|
||||
|
||||
return runExtensionHostLoaderSession({
|
||||
session,
|
||||
orderedCandidates: bootstrap.orderedCandidates,
|
||||
manifestByRoot: bootstrap.manifestByRoot,
|
||||
session: execution.session,
|
||||
orderedCandidates: execution.orderedCandidates,
|
||||
manifestByRoot: execution.manifestByRoot,
|
||||
normalizedConfig: normalized,
|
||||
rootConfig: cfg,
|
||||
validateOnly,
|
||||
createApi,
|
||||
loadModule,
|
||||
createApi: execution.createApi,
|
||||
loadModule: execution.loadModule,
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user