mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-12 07:00:44 +00:00
294 lines
8.8 KiB
TypeScript
294 lines
8.8 KiB
TypeScript
import { collectUniqueCommandDescriptors } from "../cli/program/command-descriptor-utils.js";
|
|
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
|
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
|
import { resolveManifestActivationPluginIds } from "./activation-planner.js";
|
|
import { createPluginCliGatewayNodesRuntime } from "./cli-gateway-nodes-runtime.js";
|
|
import type { PluginLoadOptions } from "./loader.js";
|
|
import { loadOpenClawPluginCliRegistry, loadOpenClawPlugins } from "./loader.js";
|
|
import { createEmptyPluginRegistry } from "./registry-empty.js";
|
|
import type { PluginRegistry } from "./registry.js";
|
|
import {
|
|
buildPluginRuntimeLoadOptions,
|
|
createPluginRuntimeLoaderLogger,
|
|
resolvePluginRuntimeLoadContext,
|
|
type PluginRuntimeLoadContext,
|
|
} from "./runtime/load-context.js";
|
|
import type {
|
|
OpenClawPluginCliCommandDescriptor,
|
|
OpenClawPluginCliContext,
|
|
PluginLogger,
|
|
} from "./types.js";
|
|
|
|
export type PluginCliLoaderOptions = Pick<PluginLoadOptions, "pluginSdkResolution">;
|
|
|
|
export type PluginCliPublicLoadParams = {
|
|
cfg?: OpenClawConfig;
|
|
env?: NodeJS.ProcessEnv;
|
|
loaderOptions?: PluginCliLoaderOptions;
|
|
logger?: PluginLogger;
|
|
primaryCommand?: string;
|
|
};
|
|
|
|
export type PluginCliLoadContext = PluginRuntimeLoadContext;
|
|
|
|
export type PluginCliRegistryLoadResult = PluginCliLoadContext & {
|
|
registry: PluginRegistry;
|
|
};
|
|
|
|
export type PluginCliCommandGroupEntry = {
|
|
pluginId: string;
|
|
parentPath: readonly string[];
|
|
placeholders: readonly OpenClawPluginCliCommandDescriptor[];
|
|
names: readonly string[];
|
|
register: (program: OpenClawPluginCliContext["program"]) => Promise<void>;
|
|
};
|
|
|
|
export function createPluginCliLogger(): PluginLogger {
|
|
return createPluginRuntimeLoaderLogger();
|
|
}
|
|
|
|
function resolvePluginCliLogger(logger?: PluginLogger): PluginLogger {
|
|
return logger ?? createPluginCliLogger();
|
|
}
|
|
|
|
function buildPluginCliLoaderParams(
|
|
context: PluginCliLoadContext,
|
|
params?: { primaryCommand?: string },
|
|
loaderOptions?: PluginCliLoaderOptions,
|
|
) {
|
|
const onlyPluginIds = resolvePrimaryCommandManifestPluginIds(context, params?.primaryCommand);
|
|
return buildPluginRuntimeLoadOptions(context, {
|
|
...loaderOptions,
|
|
...(onlyPluginIds && onlyPluginIds.length > 0 ? { onlyPluginIds } : {}),
|
|
});
|
|
}
|
|
|
|
function normalizePluginCliRootName(value: string | undefined): string {
|
|
return normalizeLowercaseStringOrEmpty(value);
|
|
}
|
|
|
|
function resolvePrimaryCommandManifestPluginIds(
|
|
context: PluginCliLoadContext,
|
|
primaryCommand: string | undefined,
|
|
): string[] | undefined {
|
|
const normalizedPrimary = normalizePluginCliRootName(primaryCommand);
|
|
if (!normalizedPrimary) {
|
|
return undefined;
|
|
}
|
|
return resolveManifestActivationPluginIds({
|
|
trigger: {
|
|
kind: "command",
|
|
command: normalizedPrimary,
|
|
},
|
|
config: context.activationSourceConfig,
|
|
workspaceDir: context.workspaceDir,
|
|
env: context.env,
|
|
});
|
|
}
|
|
|
|
function listPluginCliRootOwnerIds(registry: PluginRegistry, primaryCommand: string): string[] {
|
|
const normalizedPrimary = normalizePluginCliRootName(primaryCommand);
|
|
if (!normalizedPrimary) {
|
|
return [];
|
|
}
|
|
return [
|
|
...new Set(
|
|
registry.cliRegistrars
|
|
.filter((entry) => {
|
|
const parentPath = entry.parentPath ?? [];
|
|
const roots =
|
|
parentPath.length > 0
|
|
? [parentPath[0]]
|
|
: [...entry.commands, ...entry.descriptors.map((descriptor) => descriptor.name)];
|
|
return roots.includes(normalizedPrimary);
|
|
})
|
|
.map((entry) => entry.pluginId),
|
|
),
|
|
];
|
|
}
|
|
|
|
async function resolvePrimaryCommandPluginIds(
|
|
context: PluginCliLoadContext,
|
|
primaryCommand: string | undefined,
|
|
loaderOptions?: PluginCliLoaderOptions,
|
|
): Promise<string[] | undefined> {
|
|
const normalizedPrimary = normalizePluginCliRootName(primaryCommand);
|
|
if (!normalizedPrimary) {
|
|
return undefined;
|
|
}
|
|
const manifestPluginIds = resolvePrimaryCommandManifestPluginIds(context, normalizedPrimary);
|
|
if (manifestPluginIds && manifestPluginIds.length > 0) {
|
|
return manifestPluginIds;
|
|
}
|
|
const { registry } = await loadPluginCliMetadataRegistryWithContext(
|
|
context,
|
|
{ primaryCommand: normalizedPrimary },
|
|
loaderOptions,
|
|
);
|
|
return listPluginCliRootOwnerIds(registry, normalizedPrimary);
|
|
}
|
|
|
|
export function resolvePluginCliLoadContext(params: {
|
|
cfg?: OpenClawConfig;
|
|
env?: NodeJS.ProcessEnv;
|
|
logger: PluginLogger;
|
|
}): PluginCliLoadContext {
|
|
return resolvePluginRuntimeLoadContext({
|
|
config: params.cfg,
|
|
env: params.env,
|
|
logger: params.logger,
|
|
});
|
|
}
|
|
|
|
export async function loadPluginCliMetadataRegistryWithContext(
|
|
context: PluginCliLoadContext,
|
|
params?: { primaryCommand?: string },
|
|
loaderOptions?: PluginCliLoaderOptions,
|
|
): Promise<PluginCliRegistryLoadResult> {
|
|
return {
|
|
...context,
|
|
registry: await loadOpenClawPluginCliRegistry(
|
|
buildPluginCliLoaderParams(context, params, loaderOptions),
|
|
),
|
|
};
|
|
}
|
|
|
|
export async function loadPluginCliCommandRegistryWithContext(params: {
|
|
context: PluginCliLoadContext;
|
|
primaryCommand?: string;
|
|
loaderOptions?: PluginCliLoaderOptions;
|
|
}): Promise<PluginCliRegistryLoadResult> {
|
|
let onlyPluginIds: string[] | undefined;
|
|
try {
|
|
onlyPluginIds = await resolvePrimaryCommandPluginIds(
|
|
params.context,
|
|
params.primaryCommand,
|
|
params.loaderOptions,
|
|
);
|
|
} catch {
|
|
onlyPluginIds = resolvePrimaryCommandManifestPluginIds(params.context, params.primaryCommand);
|
|
}
|
|
if (onlyPluginIds && onlyPluginIds.length === 0) {
|
|
return {
|
|
...params.context,
|
|
registry: createEmptyPluginRegistry(),
|
|
};
|
|
}
|
|
return {
|
|
...params.context,
|
|
registry: loadOpenClawPlugins(
|
|
buildPluginRuntimeLoadOptions(params.context, {
|
|
...params.loaderOptions,
|
|
...(onlyPluginIds && onlyPluginIds.length > 0 ? { onlyPluginIds } : {}),
|
|
activate: false,
|
|
cache: false,
|
|
runtimeOptions: {
|
|
nodes: createPluginCliGatewayNodesRuntime(),
|
|
},
|
|
}),
|
|
),
|
|
};
|
|
}
|
|
|
|
function buildPluginCliCommandGroupEntries(params: {
|
|
registry: PluginRegistry;
|
|
config: OpenClawConfig;
|
|
workspaceDir: string | undefined;
|
|
logger: PluginLogger;
|
|
}): PluginCliCommandGroupEntry[] {
|
|
return params.registry.cliRegistrars.map((entry) => ({
|
|
pluginId: entry.pluginId,
|
|
parentPath: entry.parentPath ?? [],
|
|
placeholders: entry.descriptors,
|
|
names: entry.commands,
|
|
register: async (program) => {
|
|
await entry.register({
|
|
program,
|
|
parentPath: entry.parentPath ?? [],
|
|
config: params.config,
|
|
workspaceDir: params.workspaceDir,
|
|
logger: params.logger,
|
|
});
|
|
},
|
|
}));
|
|
}
|
|
|
|
export async function loadPluginCliDescriptors(
|
|
params: PluginCliPublicLoadParams,
|
|
): Promise<OpenClawPluginCliCommandDescriptor[]> {
|
|
try {
|
|
const logger = resolvePluginCliLogger(params.logger);
|
|
const context = resolvePluginCliLoadContext({
|
|
cfg: params.cfg,
|
|
env: params.env,
|
|
logger,
|
|
});
|
|
const { registry } = await loadPluginCliMetadataRegistryWithContext(
|
|
context,
|
|
{ primaryCommand: params.primaryCommand },
|
|
params.loaderOptions,
|
|
);
|
|
return collectUniqueCommandDescriptors(
|
|
registry.cliRegistrars
|
|
.filter((entry) => (entry.parentPath ?? []).length === 0)
|
|
.map((entry) => entry.descriptors),
|
|
);
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
export async function loadPluginCliRegistrationEntries(params: {
|
|
cfg?: OpenClawConfig;
|
|
env?: NodeJS.ProcessEnv;
|
|
loaderOptions?: PluginCliLoaderOptions;
|
|
logger?: PluginLogger;
|
|
primaryCommand?: string;
|
|
}): Promise<PluginCliCommandGroupEntry[]> {
|
|
const resolvedLogger = resolvePluginCliLogger(params.logger);
|
|
const context = resolvePluginCliLoadContext({
|
|
cfg: params.cfg,
|
|
env: params.env,
|
|
logger: resolvedLogger,
|
|
});
|
|
const { config, workspaceDir, logger, registry } = await loadPluginCliCommandRegistryWithContext({
|
|
context,
|
|
primaryCommand: params.primaryCommand,
|
|
loaderOptions: params.loaderOptions,
|
|
});
|
|
return buildPluginCliCommandGroupEntries({
|
|
registry,
|
|
config,
|
|
workspaceDir,
|
|
logger,
|
|
});
|
|
}
|
|
|
|
export async function resolvePluginCliRootOwnerIds(
|
|
params: PluginCliPublicLoadParams,
|
|
): Promise<string[] | null> {
|
|
const primaryCommand = normalizePluginCliRootName(params.primaryCommand);
|
|
if (!primaryCommand) {
|
|
return null;
|
|
}
|
|
const logger = resolvePluginCliLogger(params.logger);
|
|
const context = resolvePluginCliLoadContext({
|
|
cfg: params.cfg,
|
|
env: params.env,
|
|
logger,
|
|
});
|
|
return (
|
|
(await resolvePrimaryCommandPluginIds(context, primaryCommand, params.loaderOptions)) ?? null
|
|
);
|
|
}
|
|
|
|
export async function loadPluginCliRegistrationEntriesWithDefaults(
|
|
params: PluginCliPublicLoadParams,
|
|
): Promise<PluginCliCommandGroupEntry[]> {
|
|
const logger = resolvePluginCliLogger(params.logger);
|
|
return loadPluginCliRegistrationEntries({
|
|
...params,
|
|
logger,
|
|
});
|
|
}
|