Files
openclaw/src/plugins/plugin-metadata-snapshot.runtime.ts
T
Peter Steinberger 499d81cdbd perf(plugins): make every plugin closure statically kysely-free and guard it transitively (#120876)
* perf(plugins): close the last kysely closure chains and guard reachability transitively

Follow-up to #120698/#120811/#120882: the closure guard's enumerated barrel
bans cannot catch new heavy edges, and two closures still statically reached
kysely on main.

- guard: add a transitive kysely-reachability test that walks static value
  imports from every doctor-contract and legacy-setup closure through plugin,
  plugin-sdk, and relative core graphs, failing with the full import chain;
  type-only and lazy dynamic imports stay allowed
- llm-task/model refs: manifest-model-id-normalization reads snapshots
  through a registration-slot runtime bridge (snapshot modules register at
  eval; require fallback covers cold processes) and
  current-plugin-metadata-state moves its process-scoped facts onto a
  globalThis singleton so dual module instances share published state
- telegram: split thread-bindings-store.ts (pure record shapes + legacy-file
  readers) out of the acp-runtime-heavy manager, delete the consumer-less
  testing export, move the pure bot-user-id token parse to
  token-fingerprint.ts, and lazy-import token.js in the async update-offset
  detector

llm-task enumeration drops to ~0.8s/157 modules cold; every closure is now
statically kysely-free and stays that way by construction.

* fix(telegram): repoint the native-command menu state at the token-fingerprint parser
2026-08-09 00:39:45 -07:00

96 lines
3.4 KiB
TypeScript

/**
* Lazy bridge for plugin metadata snapshot reads. The snapshot modules pull
* the control-plane context (installed-plugin index/kysely), which light
* shared modules and doctor closures must not cold-load at import time.
*
* The snapshot module registers its reader here at eval time, so any process
* that published or scoped a snapshot serves reads through the registered
* instance. The require fallback only covers cold processes that never loaded
* the metadata system (built code loads .js; source/jiti paths resolve .ts).
*/
import { createRequire } from "node:module";
import { resolveGlobalSingleton } from "../shared/global-singleton.js";
type CurrentSnapshotModule = Pick<
typeof import("./current-plugin-metadata-snapshot.js"),
"getCurrentPluginMetadataSnapshot"
>;
type SnapshotLoaderModule = Pick<
typeof import("./plugin-metadata-snapshot.js"),
"resolvePluginMetadataSnapshot"
>;
type SnapshotReaderSlot = {
getCurrentPluginMetadataSnapshot?: CurrentSnapshotModule["getCurrentPluginMetadataSnapshot"];
resolvePluginMetadataSnapshot?: SnapshotLoaderModule["resolvePluginMetadataSnapshot"];
};
// globalThis-keyed so a require-loaded second module instance shares the slot.
const snapshotReaderSlot = resolveGlobalSingleton<SnapshotReaderSlot>(
Symbol.for("openclaw.pluginMetadataSnapshotReaders"),
() => ({}),
);
/** Called by the snapshot modules at eval time; last registration wins. */
export function registerPluginMetadataSnapshotReaders(readers: SnapshotReaderSlot): void {
Object.assign(snapshotReaderSlot, readers);
}
const require = createRequire(import.meta.url);
function createModuleLoader(candidates: readonly string[]): () => unknown {
let loaded: unknown;
let attempted = false;
return () => {
if (loaded) {
return loaded;
}
if (attempted) {
return null;
}
attempted = true;
for (const candidate of candidates) {
try {
loaded = require(candidate);
return loaded;
} catch {
// Try source/runtime candidates in order.
}
}
return null;
};
}
const loadCurrentSnapshotModule = createModuleLoader([
"./current-plugin-metadata-snapshot.js",
"./current-plugin-metadata-snapshot.ts",
]) as () => CurrentSnapshotModule | null;
const loadSnapshotLoaderModule = createModuleLoader([
"./plugin-metadata-snapshot.js",
"./plugin-metadata-snapshot.ts",
]) as () => SnapshotLoaderModule | null;
/** Reads the current plugin metadata snapshot, loading the snapshot graph lazily. */
export function getCurrentPluginMetadataSnapshotRuntime(
params: Parameters<CurrentSnapshotModule["getCurrentPluginMetadataSnapshot"]>[0],
): ReturnType<CurrentSnapshotModule["getCurrentPluginMetadataSnapshot"]> {
const reader =
snapshotReaderSlot.getCurrentPluginMetadataSnapshot ??
loadCurrentSnapshotModule()?.getCurrentPluginMetadataSnapshot;
return reader?.(params) ?? undefined;
}
/**
* Resolves a plugin metadata snapshot, or undefined when the metadata system
* is unavailable (cold test workers without a CJS TS hook); callers treat that
* as "no manifest policies exist".
*/
export function resolvePluginMetadataSnapshotRuntime(
params: Parameters<SnapshotLoaderModule["resolvePluginMetadataSnapshot"]>[0],
): ReturnType<SnapshotLoaderModule["resolvePluginMetadataSnapshot"]> | undefined {
const resolver =
snapshotReaderSlot.resolvePluginMetadataSnapshot ??
loadSnapshotLoaderModule()?.resolvePluginMetadataSnapshot;
return resolver?.(params);
}