openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
39 lines (38 loc) • 1.77 kB
JavaScript
import { c as normalizeOptionalLowercaseString } from "./string-coerce-1VuiLaaR.mjs";
import path from "node:path";
import fs from "node:fs/promises";
//#region src/security/installed-plugin-dirs.ts
const IGNORED_INSTALLED_PLUGIN_DIR_NAMES = /* @__PURE__ */ new Set(["node_modules", ".openclaw-install-backups"]);
/**
* Decide whether an installed-plugin directory should be skipped by security audits.
* This filters generated install debris while keeping real plugin roots visible to scans.
*/
function shouldIgnoreInstalledPluginDirName(name) {
const normalized = normalizeOptionalLowercaseString(name);
return !normalized || IGNORED_INSTALLED_PLUGIN_DIR_NAMES.has(normalized) || normalized.startsWith(".") || normalized.endsWith(".bak") || normalized.includes(".backup-") || normalized.includes(".disabled");
}
/**
* Lists installed plugin directories under the state extensions dir. Read
* failures surface through `onReadError` so audits can report scan problems,
* except a missing extensions dir, which is the normal no-plugins state.
*/
async function listInstalledPluginDirs(params) {
const extensionsDir = path.join(params.stateDir, "extensions");
if (!(await fs.stat(extensionsDir).catch((err) => {
const code = err?.code;
if (code !== "ENOENT" && code !== "ENOTDIR") params.onReadError?.(err);
return null;
}))?.isDirectory()) return {
extensionsDir,
pluginDirs: []
};
return {
extensionsDir,
pluginDirs: (await fs.readdir(extensionsDir, { withFileTypes: true }).catch((err) => {
params.onReadError?.(err);
return [];
})).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => !shouldIgnoreInstalledPluginDirName(name)).filter(Boolean)
};
}
//#endregion
export { listInstalledPluginDirs as t };