Files
openclaw/src/plugins/installed-plugin-index-types.ts
Dallin Romney 88d8d6af93 perf(plugins): extend discovery threading to loader, manifest registry, installed-index, and config contracts (#84283)
* perf(plugins): extend discovery threading to loader, manifest registry, installed-index, and config contracts

Follow-up to #75451. Threads optional discovery?: PluginDiscoveryResult
through the remaining helpers that still call discoverOpenClawPlugins
internally during startup:

- loadOpenClawPlugins / loadOpenClawPluginCliRegistry (src/plugins/loader.ts):
  add discovery? to PluginLoadOptions and consult it before falling back to
  an internal scan at both call sites.

- loadPluginManifestRegistry (src/plugins/manifest-registry.ts): accept
  discovery? as a more ergonomic alternative to the existing candidates? /
  diagnostics? pair; candidates? still wins when both are supplied.

- resolveInstalledPluginIndexRegistry (src/plugins/installed-plugin-index-registry.ts):
  add discovery? to LoadInstalledPluginIndexParams and use it when
  candidates aren't supplied.

- resolvePluginConfigContractsById (src/plugins/config-contracts.ts): add
  discovery? and thread it into the bundled-fallback discovery call.

Add discovery-threading.test.ts asserting each entry point skips its
internal discoverOpenClawPlugins call when discovery is supplied, calls it
when nothing is supplied, and prefers explicit candidates over discovery
when both are present (6 tests, all pass).

discoverOpenClawPlugins remains stateless; sharing is function-scoped per
src/plugins/CLAUDE.md guidance. Backward compatible: every change is
additive (new optional param).

* perf(plugins): drop verbose JSDoc from discovery? params
2026-05-19 16:22:30 -07:00

141 lines
4.5 KiB
TypeScript

import type { OpenClawConfig } from "../config/types.js";
import type { PluginInstallRecord } from "../config/types.plugins.js";
import type { PluginCompatCode } from "./compat/registry.js";
import type { PluginCandidate, PluginDiscoveryResult } from "./discovery.js";
import type { PluginInstallSourceInfo } from "./install-source-info.js";
import type { InstalledPluginFileSignature } from "./installed-plugin-index-hash.js";
import type { PluginManifestRecord } from "./manifest-registry.js";
import type { PluginDiagnostic } from "./manifest-types.js";
import type { PluginPackageChannel } from "./manifest.js";
export const INSTALLED_PLUGIN_INDEX_VERSION = 1;
export const INSTALLED_PLUGIN_INDEX_MIGRATION_VERSION = 1;
export const INSTALLED_PLUGIN_INDEX_WARNING =
"DO NOT EDIT. This file is generated by OpenClaw from plugin manifests, install records, and config policy. Use `openclaw plugins registry --refresh`, `openclaw plugins install/update/uninstall`, or `openclaw plugins enable/disable` instead.";
export type InstalledPluginIndexRefreshReason =
| "missing"
| "stale-manifest"
| "stale-package"
| "source-changed"
| "policy-changed"
| "migration"
| "host-contract-changed"
| "compat-registry-changed"
| "manual";
export type InstalledPluginStartupInfo = {
sidecar: boolean;
memory: boolean;
deferConfiguredChannelFullLoadUntilAfterListen: boolean;
agentHarnesses: readonly string[];
};
export type InstalledPluginInstallRecordInfo = Pick<
PluginInstallRecord,
| "source"
| "spec"
| "sourcePath"
| "installPath"
| "version"
| "resolvedName"
| "resolvedVersion"
| "resolvedSpec"
| "integrity"
| "shasum"
| "resolvedAt"
| "installedAt"
| "clawhubUrl"
| "clawhubPackage"
| "clawhubFamily"
| "clawhubChannel"
| "artifactKind"
| "artifactFormat"
| "npmIntegrity"
| "npmShasum"
| "npmTarballName"
| "clawpackSha256"
| "clawpackSpecVersion"
| "clawpackManifestSha256"
| "clawpackSize"
| "gitUrl"
| "gitRef"
| "gitCommit"
| "marketplaceName"
| "marketplaceSource"
| "marketplacePlugin"
>;
export type InstalledPluginPackageChannelInfo = PluginPackageChannel;
export type InstalledPluginIndexRecord = {
pluginId: string;
packageName?: string;
packageVersion?: string;
/**
* Legacy embedded install record accepted when reading earlier index files.
* New index writes keep install records in InstalledPluginIndex.installRecords.
*/
installRecord?: InstalledPluginInstallRecordInfo;
/** Hash of the top-level installRecords entry; used to detect source-changed invalidation. */
installRecordHash?: string;
/**
* Package-authored openclaw.install metadata. This describes catalog/package
* install intent and must not be treated as the durable install record.
*/
packageInstall?: PluginInstallSourceInfo;
packageChannel?: InstalledPluginPackageChannelInfo;
manifestPath: string;
manifestHash: string;
manifestFile?: InstalledPluginFileSignature;
format?: PluginManifestRecord["format"];
bundleFormat?: PluginManifestRecord["bundleFormat"];
source?: string;
setupSource?: string;
packageJson?: {
path: string;
hash: string;
fileSignature?: InstalledPluginFileSignature;
};
rootDir: string;
origin: PluginManifestRecord["origin"];
enabled: boolean;
enabledByDefault?: boolean;
enabledByDefaultOnPlatforms?: readonly string[];
syntheticAuthRefs?: readonly string[];
startup: InstalledPluginStartupInfo;
compat: readonly PluginCompatCode[];
};
export type InstalledPluginIndex = {
version: typeof INSTALLED_PLUGIN_INDEX_VERSION;
warning?: string;
hostContractVersion: string;
compatRegistryVersion: string;
migrationVersion: typeof INSTALLED_PLUGIN_INDEX_MIGRATION_VERSION;
policyHash: string;
generatedAtMs: number;
refreshReason?: InstalledPluginIndexRefreshReason;
installRecords: Readonly<Record<string, InstalledPluginInstallRecordInfo>>;
plugins: readonly InstalledPluginIndexRecord[];
diagnostics: readonly PluginDiagnostic[];
};
export type LoadInstalledPluginIndexParams = {
config?: OpenClawConfig;
workspaceDir?: string;
env?: NodeJS.ProcessEnv;
stateDir?: string;
pluginIndexFilePath?: string;
installRecords?: Record<string, PluginInstallRecord>;
candidates?: PluginCandidate[];
diagnostics?: PluginDiagnostic[];
discovery?: PluginDiscoveryResult;
now?: () => Date;
};
export type RefreshInstalledPluginIndexParams = LoadInstalledPluginIndexParams & {
reason: InstalledPluginIndexRefreshReason;
policyPluginIds?: readonly string[];
};