openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
670 lines (669 loc) • 29.3 kB
JavaScript
import { t as isTruthyEnvValue } from "./env-Di49gJwo.js";
import { o as isRecord } from "./record-coerce-DHZ4bFlT.js";
import { p as resolveIsNixMode } from "./paths-mvMm5bYV.js";
import { n as appendRegularFileSync } from "./regular-file-BD2zl6_l.js";
import { p as resolveUserPath } from "./utils-CCC-BEJH.js";
import { o as resolveCompatibilityHostVersion } from "./version-Crcn9X9T.js";
import "./logger-Brhy0cvC.js";
import { i as normalizeProviderId } from "./provider-id-Dq06Bcx6.js";
import { t as loadPluginManifestRegistry } from "./manifest-registry-BywZIeAq.js";
import { a as resolveDefaultPluginNpmDir, l as resolvePluginNpmProjectsDir } from "./install-paths-D-sCLR1I.js";
import { d as serializePluginIdScope, p as resolvePluginControlPlaneFingerprint, r as getCurrentPluginMetadataSnapshot, u as normalizePluginIdScope } from "./current-plugin-metadata-snapshot-CfA_n2Nc.js";
import { n as registerPluginMetadataProcessMemoLifecycleClear } from "./plugin-metadata-lifecycle-C3dWg4tn.js";
import { g as hashJson, m as resolveInstalledPluginIndexPolicyHash } from "./installed-plugin-index-BSYm7o5l.js";
import { n as resolveInstalledManifestRegistryIndexFingerprint, t as loadPluginManifestRegistryForInstalledIndex } from "./manifest-registry-installed-DSyeeqEt.js";
import { g as createPluginRegistryIdNormalizer, m as loadPluginRegistrySnapshotWithMetadata } from "./plugin-registry-ChcJPHWl.js";
import { i as readPersistedInstalledPluginIndexSync } from "./installed-plugin-index-store-DyTBte5L.js";
import { t as isDiagnosticFlagEnabled } from "./diagnostic-flags-4mY6zjJI.js";
import fs, { mkdirSync } from "node:fs";
import path, { dirname } from "node:path";
import { randomUUID } from "node:crypto";
import { AsyncLocalStorage } from "node:async_hooks";
import { performance as performance$1 } from "node:perf_hooks";
//#region src/infra/diagnostics-timeline.ts
const OPENCLAW_DIAGNOSTICS_TIMELINE_SCHEMA_VERSION = "openclaw.diagnostics.v1";
let warnedAboutTimelineWrite = false;
const createdTimelineDirs = /* @__PURE__ */ new Set();
const activeDiagnosticsTimelineSpan = new AsyncLocalStorage();
function resolveDiagnosticsTimelineOptions(options = {}) {
return {
env: options.env ?? process.env,
...options.config ? { config: options.config } : {}
};
}
/** Returns true when diagnostics flags and a JSONL output path both allow timeline writes. */
function isDiagnosticsTimelineEnabled(options = {}) {
const { config, env } = resolveDiagnosticsTimelineOptions(options);
return (isDiagnosticFlagEnabled("timeline", config, env) || isDiagnosticFlagEnabled("diagnostics.timeline", config, env) || isTruthyEnvValue(env.OPENCLAW_DIAGNOSTICS)) && typeof env.OPENCLAW_DIAGNOSTICS_TIMELINE_PATH === "string" && env.OPENCLAW_DIAGNOSTICS_TIMELINE_PATH.trim().length > 0;
}
function normalizeNumber(value) {
if (typeof value !== "number" || !Number.isFinite(value)) return;
return Math.max(0, Math.round(value * 1e3) / 1e3);
}
function normalizeAttributes(attributes) {
if (!attributes) return;
const normalized = {};
for (const [key, value] of Object.entries(attributes)) {
if (typeof value === "number") {
if (Number.isFinite(value)) normalized[key] = normalizeNumber(value) ?? 0;
continue;
}
if (typeof value === "string" || typeof value === "boolean" || value === null) normalized[key] = value;
}
return Object.keys(normalized).length > 0 ? normalized : void 0;
}
function serializeTimelineEvent(event, env) {
const normalized = {
schemaVersion: OPENCLAW_DIAGNOSTICS_TIMELINE_SCHEMA_VERSION,
type: event.type,
timestamp: event.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
name: event.name,
...env.OPENCLAW_DIAGNOSTICS_RUN_ID ? { runId: env.OPENCLAW_DIAGNOSTICS_RUN_ID } : {},
...env.OPENCLAW_DIAGNOSTICS_ENV ? { envName: env.OPENCLAW_DIAGNOSTICS_ENV } : {},
pid: process.pid,
...event.runId ? { runId: event.runId } : {},
...event.envName ? { envName: event.envName } : {},
...typeof event.pid === "number" ? { pid: event.pid } : {},
...event.phase ? { phase: event.phase } : {},
...event.spanId ? { spanId: event.spanId } : {},
...event.parentSpanId ? { parentSpanId: event.parentSpanId } : {},
...typeof event.durationMs === "number" ? { durationMs: normalizeNumber(event.durationMs) } : {},
...event.errorName ? { errorName: event.errorName } : {},
...event.errorMessage ? { errorMessage: event.errorMessage } : {},
...typeof event.p50Ms === "number" ? { p50Ms: normalizeNumber(event.p50Ms) } : {},
...typeof event.p95Ms === "number" ? { p95Ms: normalizeNumber(event.p95Ms) } : {},
...typeof event.p99Ms === "number" ? { p99Ms: normalizeNumber(event.p99Ms) } : {},
...typeof event.maxMs === "number" ? { maxMs: normalizeNumber(event.maxMs) } : {},
...event.activeSpanName ? { activeSpanName: event.activeSpanName } : {},
...event.provider ? { provider: event.provider } : {},
...event.operation ? { operation: event.operation } : {},
...typeof event.ok === "boolean" ? { ok: event.ok } : {},
...event.command ? { command: event.command } : {},
...event.exitCode !== void 0 ? { exitCode: event.exitCode } : {},
...event.signal !== void 0 ? { signal: event.signal } : {},
...normalizeAttributes(event.attributes) ? { attributes: normalizeAttributes(event.attributes) } : {}
};
return `${JSON.stringify(normalized)}\n`;
}
/** Appends one normalized diagnostics timeline event to the configured JSONL file. */
function emitDiagnosticsTimelineEvent(event, options = {}) {
const { env } = resolveDiagnosticsTimelineOptions(options);
if (!isDiagnosticsTimelineEnabled(options)) return;
const path = env.OPENCLAW_DIAGNOSTICS_TIMELINE_PATH?.trim();
if (!path) return;
const line = serializeTimelineEvent(event, env);
try {
const dir = dirname(path);
if (!createdTimelineDirs.has(dir)) {
mkdirSync(dir, { recursive: true });
createdTimelineDirs.add(dir);
}
appendRegularFileSync({
filePath: path,
content: line
});
} catch (error) {
if (!warnedAboutTimelineWrite) {
warnedAboutTimelineWrite = true;
process.stderr.write(`[diagnostics] failed to write timeline event: ${String(error)}\n`);
}
}
}
/** Returns the currently active span so callers can preserve parentage across memoized work. */
function getActiveDiagnosticsTimelineSpan() {
return activeDiagnosticsTimelineSpan.getStore();
}
function startDiagnosticsTimelineSpan(name, options) {
const env = options.env ?? process.env;
if (!isDiagnosticsTimelineEnabled({
config: options.config,
env
})) return;
const activeSpan = getActiveDiagnosticsTimelineSpan();
const phase = options.phase ?? activeSpan?.phase;
const parentSpanId = options.parentSpanId ?? activeSpan?.spanId;
const span = {
name,
env,
...options.config ? { config: options.config } : {},
spanId: randomUUID(),
startedAt: performance$1.now(),
...phase ? { phase } : {},
...parentSpanId ? { parentSpanId } : {},
...options.attributes ? { attributes: options.attributes } : {},
...options.omitErrorMessage ? { omitErrorMessage: true } : {}
};
emitDiagnosticsTimelineEvent({
type: "span.start",
name: span.name,
phase: span.phase,
spanId: span.spanId,
parentSpanId: span.parentSpanId,
attributes: span.attributes
}, {
config: span.config,
env: span.env
});
return span;
}
function runInDiagnosticsTimelineSpan(span, run) {
return activeDiagnosticsTimelineSpan.run({
name: span.name,
...span.phase ? { phase: span.phase } : {},
spanId: span.spanId,
...span.parentSpanId ? { parentSpanId: span.parentSpanId } : {},
...span.attributes ? { attributes: span.attributes } : {}
}, run);
}
function emitFinishedDiagnosticsTimelineSpan(span) {
emitDiagnosticsTimelineEvent({
type: "span.end",
name: span.name,
phase: span.phase,
spanId: span.spanId,
parentSpanId: span.parentSpanId,
durationMs: performance$1.now() - span.startedAt,
attributes: span.attributes
}, {
config: span.config,
env: span.env
});
}
function emitFailedDiagnosticsTimelineSpan(span, error) {
emitDiagnosticsTimelineEvent({
type: "span.error",
name: span.name,
phase: span.phase,
spanId: span.spanId,
parentSpanId: span.parentSpanId,
durationMs: performance$1.now() - span.startedAt,
attributes: span.attributes,
errorName: error instanceof Error ? error.name : typeof error,
...span.omitErrorMessage ? {} : { errorMessage: error instanceof Error ? error.message : String(error) }
}, {
config: span.config,
env: span.env
});
}
/** Measures async work as a start/end timeline span, emitting an error span before rethrowing. */
async function measureDiagnosticsTimelineSpan(name, run, options = {}) {
const span = startDiagnosticsTimelineSpan(name, options);
if (!span) return await run();
try {
const result = await runInDiagnosticsTimelineSpan(span, () => run());
emitFinishedDiagnosticsTimelineSpan(span);
return result;
} catch (error) {
emitFailedDiagnosticsTimelineSpan(span, error);
throw error;
}
}
/** Measures sync work as a start/end timeline span, emitting an error span before rethrowing. */
function measureDiagnosticsTimelineSpanSync(name, run, options = {}) {
const span = startDiagnosticsTimelineSpan(name, options);
if (!span) return run();
try {
const result = runInDiagnosticsTimelineSpan(span, run);
emitFinishedDiagnosticsTimelineSpan(span);
return result;
} catch (error) {
emitFailedDiagnosticsTimelineSpan(span, error);
throw error;
}
}
//#endregion
//#region src/plugins/plugin-metadata-snapshot.ts
const MAX_PLUGIN_METADATA_SNAPSHOT_MEMOS = 8;
let pluginMetadataSnapshotMemos = [];
function clearLoadPluginMetadataSnapshotMemo() {
pluginMetadataSnapshotMemos = [];
}
registerPluginMetadataProcessMemoLifecycleClear(clearLoadPluginMetadataSnapshotMemo);
const MEMO_RELEVANT_ENV_KEYS = [
"APPDATA",
"HOME",
"OPENCLAW_BUNDLED_PLUGINS_DIR",
"OPENCLAW_COMPATIBILITY_HOST_VERSION",
"OPENCLAW_CONFIG_PATH",
"OPENCLAW_DISABLE_BUNDLED_PLUGINS",
"OPENCLAW_DISABLE_BUNDLED_SOURCE_OVERLAYS",
"OPENCLAW_DISABLE_PERSISTED_PLUGIN_REGISTRY",
"OPENCLAW_HOME",
"OPENCLAW_NIX_MODE",
"OPENCLAW_STATE_DIR",
"USERPROFILE",
"XDG_CONFIG_HOME"
];
function fileFingerprint(filePath) {
try {
const stat = fs.statSync(filePath, { bigint: true });
return [
filePath,
stat.isFile() ? "file" : stat.isDirectory() ? "dir" : "other",
stat.size.toString(),
stat.mtimeNs.toString(),
stat.ctimeNs.toString()
];
} catch {
return [filePath, "missing"];
}
}
function directoryChildPackageJsonFingerprint(directoryPath) {
let entries;
try {
entries = fs.readdirSync(directoryPath, { withFileTypes: true });
} catch {
return [directoryPath, "missing"];
}
return [directoryPath, ...entries.filter((entry) => entry.isDirectory()).toSorted((a, b) => a.name.localeCompare(b.name)).map((entry) => fileFingerprint(path.join(directoryPath, entry.name, "package.json")))];
}
function stableMemoValue(value) {
if (Array.isArray(value)) return value.map(stableMemoValue);
if (!isRecord(value)) return value;
return Object.fromEntries(Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, stableMemoValue(entry)]));
}
function pickMemoRelevantEnv(env) {
return Object.fromEntries(MEMO_RELEVANT_ENV_KEYS.flatMap((key) => {
const value = env[key];
return value === void 0 ? [] : [[key, value]];
}));
}
function resolvePluginMetadataSnapshotMemoEnvFingerprint(env) {
return hashJson(pickMemoRelevantEnv(env));
}
function throwReadonlyPluginMetadataMutation() {
throw new TypeError("Plugin metadata snapshots are immutable");
}
function freezeSnapshotValue(value, seen = /* @__PURE__ */ new WeakSet()) {
if (!value || typeof value !== "object") return value;
if (seen.has(value)) return value;
seen.add(value);
if (value instanceof Map) {
for (const [key, entry] of value) {
freezeSnapshotValue(key, seen);
freezeSnapshotValue(entry, seen);
}
Object.defineProperties(value, {
clear: { value: throwReadonlyPluginMetadataMutation },
delete: { value: throwReadonlyPluginMetadataMutation },
set: { value: throwReadonlyPluginMetadataMutation }
});
return Object.freeze(value);
}
if (value instanceof Set) {
for (const entry of value) freezeSnapshotValue(entry, seen);
Object.defineProperties(value, {
add: { value: throwReadonlyPluginMetadataMutation },
clear: { value: throwReadonlyPluginMetadataMutation },
delete: { value: throwReadonlyPluginMetadataMutation }
});
return Object.freeze(value);
}
for (const entry of Object.values(value)) freezeSnapshotValue(entry, seen);
return Object.freeze(value);
}
function freezePluginMetadataSnapshot(snapshot) {
return freezeSnapshotValue(snapshot);
}
function resolvePersistedRegistryFastMemoFingerprint(params) {
const disabledByEnv = params.env.OPENCLAW_DISABLE_PERSISTED_PLUGIN_REGISTRY?.trim().toLowerCase();
if (params.preferPersisted === false || Boolean(disabledByEnv) && disabledByEnv !== "0" && disabledByEnv !== "false" && disabledByEnv !== "no") return { disabled: true };
const npmRoot = params.stateDir ? path.join(params.stateDir, "npm") : resolveDefaultPluginNpmDir(params.env);
return {
index: hashJson(stableMemoValue(readPersistedInstalledPluginIndexSync({
env: params.env,
...params.stateDir ? { stateDir: params.stateDir } : {}
})) ?? null),
npmPackageJson: fileFingerprint(path.join(npmRoot, "package.json")),
npmProjectPackageJsons: directoryChildPackageJsonFingerprint(resolvePluginNpmProjectsDir(npmRoot))
};
}
function resolvePersistedRegistryMemoContextHash(params) {
return hashJson({
env: pickMemoRelevantEnv(params.env),
fastFingerprint: params.fastFingerprint,
preferPersisted: params.preferPersisted ?? null,
stateDir: params.stateDir ?? null
});
}
function resolvePersistedRegistryMemoLookupContextHash(params) {
return hashJson({
env: pickMemoRelevantEnv(params.env),
preferPersisted: params.preferPersisted ?? null,
stateDir: params.stateDir ?? null
});
}
function resolvePersistedRegistryMemoState(params) {
const fastFingerprint = resolvePersistedRegistryFastMemoFingerprint(params);
const fastHash = hashJson(fastFingerprint);
const contextHash = resolvePersistedRegistryMemoContextHash({
...params,
fastFingerprint
});
if (isRecord(fastFingerprint) && fastFingerprint.disabled === true) return {
contextHash,
fastHash,
fingerprint: fastFingerprint
};
const index = readPersistedInstalledPluginIndexSync({
env: params.env,
...params.stateDir ? { stateDir: params.stateDir } : {}
});
return {
contextHash,
fastHash,
fingerprint: {
...fastFingerprint,
indexHash: hashJson(stableMemoValue(index) ?? null)
}
};
}
function resolvePersistedRegistryMemoStateForLookup(params, memos) {
const lookupContextHash = resolvePersistedRegistryMemoLookupContextHash(params);
for (const memo of memos) if (memo.lookupContextHash === lookupContextHash && memo.registryState) return memo.registryState;
const fastFingerprint = resolvePersistedRegistryFastMemoFingerprint(params);
const fastHash = hashJson(fastFingerprint);
const contextHash = resolvePersistedRegistryMemoContextHash({
...params,
fastFingerprint
});
for (const memo of memos) {
const registryState = memo.registryState;
if (registryState && registryState.contextHash === contextHash && registryState.fastHash === fastHash) return registryState;
}
return resolvePersistedRegistryMemoState(params);
}
function resolveProvidedIndexMemoState(index) {
const fingerprint = { providedIndex: resolveInstalledManifestRegistryIndexFingerprint(index) };
const fingerprintHash = hashJson(fingerprint);
return {
contextHash: fingerprintHash,
fastHash: fingerprintHash,
fingerprint
};
}
function findPluginMetadataSnapshotMemo(key) {
const index = pluginMetadataSnapshotMemos.findIndex((memo) => memo.key === key);
if (index === -1) return;
const [memo] = pluginMetadataSnapshotMemos.splice(index, 1);
if (!memo) return;
pluginMetadataSnapshotMemos.unshift(memo);
return memo;
}
function rememberPluginMetadataSnapshotMemo(memo) {
pluginMetadataSnapshotMemos = [memo, ...pluginMetadataSnapshotMemos.filter((existing) => existing.key !== memo.key)].slice(0, MAX_PLUGIN_METADATA_SNAPSHOT_MEMOS);
}
function computePluginMetadataSnapshotMemoKey(params) {
const { params: snapshotParams, registryState } = params;
const env = snapshotParams.env ?? process.env;
const indexFingerprint = snapshotParams.index ? resolveInstalledManifestRegistryIndexFingerprint(snapshotParams.index) : void 0;
return hashJson({
controlPlane: resolvePluginControlPlaneFingerprint({
config: snapshotParams.config,
env,
workspaceDir: snapshotParams.workspaceDir,
policyHash: resolveInstalledPluginIndexPolicyHash(snapshotParams.config),
...indexFingerprint ? { inventoryFingerprint: indexFingerprint } : {}
}),
cwd: process.cwd(),
env: pickMemoRelevantEnv(env),
index: indexFingerprint ?? null,
pathPolicy: {
compatibilityHostVersion: resolveCompatibilityHostVersion(env),
nixMode: resolveIsNixMode(env)
},
pluginIds: serializePluginIdScope(normalizePluginIdScope(snapshotParams.pluginIds)),
pluginIdScopeKey: snapshotParams.pluginIdScope?.key ?? null,
preferPersisted: snapshotParams.preferPersisted ?? null,
registry: registryState.fingerprint,
stateDir: snapshotParams.stateDir ? resolveUserPath(snapshotParams.stateDir, env) : null,
workspaceDir: snapshotParams.workspaceDir ?? null
});
}
function resolvePluginMetadataControlPlaneFingerprint(params) {
return resolvePluginControlPlaneFingerprint(params);
}
function indexesMatch(left, right) {
if (!left || !right) return true;
return resolveInstalledManifestRegistryIndexFingerprint(left) === resolveInstalledManifestRegistryIndexFingerprint(right);
}
function cloneSnapshotInput(value) {
return value && typeof value === "object" ? structuredClone(value) : value;
}
function normalizeInstalledPluginIndex(index) {
return {
version: index.version ?? 1,
hostContractVersion: index.hostContractVersion ?? "",
compatRegistryVersion: index.compatRegistryVersion ?? "",
migrationVersion: index.migrationVersion ?? 1,
policyHash: index.policyHash ?? "",
generatedAtMs: index.generatedAtMs ?? 0,
installRecords: cloneSnapshotInput(index.installRecords ?? {}),
plugins: (index.plugins ?? []).map(cloneSnapshotInput),
diagnostics: (index.diagnostics ?? []).map(cloneSnapshotInput),
...index.warning ? { warning: index.warning } : {},
...index.refreshReason ? { refreshReason: index.refreshReason } : {}
};
}
function resolvePluginMetadataSnapshotPluginIds(params) {
const direct = normalizePluginIdScope(params.params.pluginIds);
if (direct !== void 0) return direct;
return normalizePluginIdScope(params.params.pluginIdScope?.resolve({ index: params.index }));
}
function isPluginMetadataSnapshotCompatible(params) {
const env = params.env ?? process.env;
const requestedPluginIds = normalizePluginIdScope(params.pluginIds);
const snapshotPluginIds = normalizePluginIdScope(params.snapshot.pluginIds);
return (snapshotPluginIds === void 0 || params.allowScopedSnapshot === true || requestedPluginIds !== void 0 && serializePluginIdScope(snapshotPluginIds) === serializePluginIdScope(requestedPluginIds)) && params.snapshot.policyHash === resolveInstalledPluginIndexPolicyHash(params.config) && (!params.snapshot.configFingerprint || params.snapshot.configFingerprint === resolvePluginMetadataControlPlaneFingerprint({
config: params.config,
env,
index: params.index ?? params.snapshot.index,
policyHash: params.snapshot.policyHash,
workspaceDir: params.workspaceDir
})) && (params.snapshot.workspaceDir ?? "") === (params.workspaceDir ?? "") && indexesMatch(params.snapshot.index, params.index);
}
function appendOwner(owners, ownedId, pluginId) {
const existing = owners.get(ownedId);
if (existing) {
if (existing.includes(pluginId)) return;
existing.push(pluginId);
return;
}
owners.set(ownedId, [pluginId]);
}
function freezeOwnerMap(owners) {
return new Map([...owners.entries()].map(([ownedId, pluginIds]) => [ownedId, Object.freeze([...pluginIds])]));
}
function buildPluginMetadataOwnerMaps(plugins) {
const channels = /* @__PURE__ */ new Map();
const channelConfigs = /* @__PURE__ */ new Map();
const providers = /* @__PURE__ */ new Map();
const modelCatalogProviders = /* @__PURE__ */ new Map();
const cliBackends = /* @__PURE__ */ new Map();
const setupProviders = /* @__PURE__ */ new Map();
const commandAliases = /* @__PURE__ */ new Map();
const contracts = /* @__PURE__ */ new Map();
for (const plugin of plugins) {
for (const channelId of plugin.channels ?? []) appendOwner(channels, channelId, plugin.id);
for (const channelId of Object.keys(plugin.channelConfigs ?? {})) appendOwner(channelConfigs, channelId, plugin.id);
for (const providerId of plugin.providers ?? []) appendOwner(providers, providerId, plugin.id);
for (const [rawAlias, target] of Object.entries(plugin.providerAuthAliases ?? {})) {
const alias = normalizeProviderId(rawAlias);
const targetProvider = normalizeProviderId(target);
if (alias && targetProvider && (plugin.providers ?? []).some((providerId) => normalizeProviderId(providerId) === targetProvider)) appendOwner(providers, alias, plugin.id);
}
for (const providerId of Object.keys(plugin.modelCatalog?.providers ?? {})) appendOwner(modelCatalogProviders, providerId, plugin.id);
for (const providerId of Object.keys(plugin.modelCatalog?.aliases ?? {})) appendOwner(modelCatalogProviders, providerId, plugin.id);
for (const cliBackendId of plugin.cliBackends ?? []) appendOwner(cliBackends, cliBackendId, plugin.id);
for (const cliBackendId of plugin.setup?.cliBackends ?? []) appendOwner(cliBackends, cliBackendId, plugin.id);
for (const setupProvider of plugin.setup?.providers ?? []) appendOwner(setupProviders, setupProvider.id, plugin.id);
for (const commandAlias of plugin.commandAliases ?? []) appendOwner(commandAliases, commandAlias.name, plugin.id);
for (const [contract, values] of Object.entries(plugin.contracts ?? {})) if (Array.isArray(values) && values.length > 0) appendOwner(contracts, contract, plugin.id);
}
return {
channels: freezeOwnerMap(channels),
channelConfigs: freezeOwnerMap(channelConfigs),
providers: freezeOwnerMap(providers),
modelCatalogProviders: freezeOwnerMap(modelCatalogProviders),
cliBackends: freezeOwnerMap(cliBackends),
setupProviders: freezeOwnerMap(setupProviders),
commandAliases: freezeOwnerMap(commandAliases),
contracts: freezeOwnerMap(contracts)
};
}
function listPluginOriginsFromMetadataSnapshot(snapshot) {
return new Map(snapshot.plugins.map((record) => [record.id, record.origin]));
}
function loadPluginMetadataSnapshot(params) {
const activeTimelineSpan = getActiveDiagnosticsTimelineSpan();
const env = params.env ?? process.env;
const registryState = params.index ? resolveProvidedIndexMemoState(params.index) : resolvePersistedRegistryMemoStateForLookup({
env,
...params.stateDir ? { stateDir: resolveUserPath(params.stateDir, env) } : {},
...params.preferPersisted !== void 0 ? { preferPersisted: params.preferPersisted } : {}
}, pluginMetadataSnapshotMemos);
const memoKey = computePluginMetadataSnapshotMemoKey({
params,
registryState
});
const memo = findPluginMetadataSnapshotMemo(memoKey);
if (memo?.key === memoKey) return measureDiagnosticsTimelineSpanSync("plugins.metadata.scan", () => memo.snapshot, {
phase: activeTimelineSpan?.phase ?? "startup",
config: params.config,
env: params.env,
attributes: {
cacheHit: true,
hasWorkspaceDir: params.workspaceDir !== void 0,
hasInstalledIndex: params.index !== void 0
}
});
const result = measureDiagnosticsTimelineSpanSync("plugins.metadata.scan", () => loadPluginMetadataSnapshotImpl(params), {
phase: activeTimelineSpan?.phase ?? "startup",
config: params.config,
env: params.env,
attributes: {
hasWorkspaceDir: params.workspaceDir !== void 0,
hasInstalledIndex: params.index !== void 0
}
});
const snapshot = freezePluginMetadataSnapshot(result.snapshot);
if (canMemoizePluginMetadataSnapshotResult(result)) rememberPluginMetadataSnapshotMemo({
key: memoKey,
lookupContextHash: resolvePersistedRegistryMemoLookupContextHash({
env,
...params.stateDir ? { stateDir: resolveUserPath(params.stateDir, env) } : {},
...params.preferPersisted !== void 0 ? { preferPersisted: params.preferPersisted } : {}
}),
registryState,
snapshot
});
return snapshot;
}
function canMemoizePluginMetadataSnapshotResult(result) {
const snapshot = result.snapshot;
const hasCompleteSnapshotShape = Array.isArray(snapshot.plugins) && Array.isArray(snapshot.diagnostics) && Array.isArray(snapshot.registryDiagnostics) && Array.isArray(snapshot.manifestRegistry.plugins) && Array.isArray(snapshot.manifestRegistry.diagnostics) && Array.isArray(snapshot.index.plugins) && Array.isArray(snapshot.index.diagnostics);
const hasPluginMetadata = snapshot.plugins.length > 0 || snapshot.index.plugins.length > 0;
return hasCompleteSnapshotShape && hasPluginMetadata;
}
function resolvePluginMetadataSnapshot(params) {
if (params.allowCurrent !== false && params.stateDir === void 0 && params.preferPersisted !== false) {
const current = getCurrentPluginMetadataSnapshot({
config: params.config,
env: params.env,
...params.pluginIds !== void 0 ? { pluginIds: params.pluginIds } : {},
...params.pluginIdScope !== void 0 ? { pluginIdScope: params.pluginIdScope } : {},
...params.workspaceDir !== void 0 ? { workspaceDir: params.workspaceDir } : {},
...params.allowWorkspaceScopedCurrent === true ? { allowWorkspaceScopedSnapshot: true } : {}
});
if (!current) return loadPluginMetadataSnapshot(params);
if (!params.index) return current;
if (isPluginMetadataSnapshotCompatible({
snapshot: current,
config: params.config,
env: params.env,
allowScopedSnapshot: params.pluginIds !== void 0 || params.pluginIdScope !== void 0,
workspaceDir: params.workspaceDir ?? (params.allowWorkspaceScopedCurrent === true ? current.workspaceDir : void 0),
index: params.index
})) return current;
}
return loadPluginMetadataSnapshot(params);
}
function loadPluginMetadataSnapshotImpl(params) {
const totalStartedAt = performance.now();
const registryStartedAt = performance.now();
const registryResult = loadPluginRegistrySnapshotWithMetadata({
config: params.config,
workspaceDir: params.workspaceDir,
...params.stateDir ? { stateDir: params.stateDir } : {},
env: params.env,
...params.preferPersisted !== void 0 ? { preferPersisted: params.preferPersisted } : {},
...params.index ? { index: params.index } : {}
}) ?? {
source: "derived",
snapshot: { plugins: [] },
diagnostics: []
};
const registrySnapshotMs = performance.now() - registryStartedAt;
const index = normalizeInstalledPluginIndex(registryResult.snapshot);
const pluginIds = resolvePluginMetadataSnapshotPluginIds({
params,
index
});
const manifestStartedAt = performance.now();
const manifestRegistry = index.plugins.length === 0 ? loadPluginManifestRegistry({
config: params.config,
workspaceDir: params.workspaceDir,
env: params.env,
diagnostics: [...index.diagnostics],
installRecords: index.installRecords
}) : loadPluginManifestRegistryForInstalledIndex({
index,
config: params.config,
workspaceDir: params.workspaceDir,
env: params.env,
...pluginIds !== void 0 ? { pluginIds } : {},
includeDisabled: true
});
const manifestRegistryMs = performance.now() - manifestStartedAt;
const normalizePluginId = createPluginRegistryIdNormalizer(index, { manifestRegistry });
const byPluginId = new Map(manifestRegistry.plugins.map((plugin) => [plugin.id, plugin]));
const ownerMapsStartedAt = performance.now();
const owners = buildPluginMetadataOwnerMaps(manifestRegistry.plugins);
const ownerMapsMs = performance.now() - ownerMapsStartedAt;
const totalMs = performance.now() - totalStartedAt;
return {
registrySource: registryResult.source,
snapshot: {
policyHash: index.policyHash,
registrySource: registryResult.source,
configFingerprint: resolvePluginMetadataControlPlaneFingerprint({
config: params.config,
env: params.env,
index,
policyHash: index.policyHash,
workspaceDir: params.workspaceDir
}),
...pluginIds !== void 0 ? { pluginIds } : {},
...params.workspaceDir ? { workspaceDir: params.workspaceDir } : {},
index,
registryDiagnostics: registryResult.diagnostics,
manifestRegistry,
plugins: manifestRegistry.plugins,
diagnostics: manifestRegistry.diagnostics,
byPluginId,
normalizePluginId,
owners,
metrics: {
registrySnapshotMs,
manifestRegistryMs,
ownerMapsMs,
totalMs,
indexPluginCount: index.plugins.length,
manifestPluginCount: manifestRegistry.plugins.length
},
discovery: registryResult.discovery
}
};
}
//#endregion
export { resolvePluginMetadataSnapshot as a, isDiagnosticsTimelineEnabled as c, loadPluginMetadataSnapshot as i, measureDiagnosticsTimelineSpan as l, isPluginMetadataSnapshotCompatible as n, resolvePluginMetadataSnapshotMemoEnvFingerprint as o, listPluginOriginsFromMetadataSnapshot as r, emitDiagnosticsTimelineEvent as s, clearLoadPluginMetadataSnapshotMemo as t, measureDiagnosticsTimelineSpanSync as u };