fix(plugins): discover symlinked extension and hook directories

readdir entries report isDirectory()=false for symlinks, causing
plugin discovery, hook discovery, and security audits to skip
symlinked directories. Adding isSymbolicLink() checks lets
symlinked packages be found correctly.

Affected files:
- src/plugins/discovery.ts (plugin/extension discovery)
- src/hooks/workspace.ts (hook discovery)
- src/security/audit-extra.ts (extension security audit)

Useful when extensions or hooks are managed outside the workspace
and symlinked in (e.g. from a shared development directory).
This commit is contained in:
Molly Wires 2026-01-28 11:58:40 -08:00
parent 109ac1c549
commit 1be67406e2
3 changed files with 3 additions and 3 deletions

View File

@ -112,7 +112,7 @@ function loadHooksFromDir(params: { dir: string; source: HookSource; pluginId?:
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
if (!entry.isDirectory()) continue;
if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
const hookDir = path.join(dir, entry.name);
const manifest = readHookPackageManifest(hookDir);

View File

@ -136,7 +136,7 @@ function discoverInDirectory(params: {
workspaceDir: params.workspaceDir,
});
}
if (!entry.isDirectory()) continue;
if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
const manifest = readPackageManifest(fullPath);
const extensions = manifest ? resolvePackageExtensions(manifest) : [];

View File

@ -527,7 +527,7 @@ export async function collectPluginsTrustFindings(params: {
const entries = await fs.readdir(extensionsDir, { withFileTypes: true }).catch(() => []);
const pluginDirs = entries
.filter((e) => e.isDirectory())
.filter((e) => e.isDirectory() || e.isSymbolicLink())
.map((e) => e.name)
.filter(Boolean);
if (pluginDirs.length === 0) return findings;