Skip to content

SkillStore.readEntry ignores symlinked directories #2104

@icexin

Description

@icexin

Problem

SkillStore.readEntry() in src/skills.ts uses entry.isDirectory() to detect skill directories inside a skill root. However, symlinks to directories are silently skipped because readdirSync with withFileTypes: true returns DT_LNK type, and Node.js Dirent.isDirectory() returns false for symlinks.

Reproduction

# Setup: create a symlinked skill
mkdir -p /tmp/test-skill
cat > /tmp/test-skill/SKILL.md << "EOF"
---
name: test-skill
description: A test skill
---

# Test
EOF

mkdir -p ~/.agents/skills
ln -s /tmp/test-skill ~/.agents/skills/test-skill

# Load reasonix — the skill does not appear

Verification

const { readdirSync } = require("fs");
const entries = readdirSync("/Users/bingxin.fan/.agents/skills/", { withFileTypes: true });
const sym = entries.find(e => e.name === "sra-fse");
console.log("isDirectory():", sym.isDirectory());        // false
console.log("isSymbolicLink():", sym.isSymbolicLink());  // true

In my case, 22 out of 22 skills under ~/.agents/skills/ are symlinks (pointing to a central ~/.sra/* skill repository) — all are silently ignored with no error or warning.

Impact

Users who maintain skills in a shared location and symlink them into ~/.agents/skills/ (a common pattern, also the default install method for skills.sh-style tooling) will have zero skills loaded. No error is shown — the skills simply don't appear in the Skills index.

Related

Suggested fix

In src/skills.ts, readEntry() should handle symlinks before the directory/file check:

// Before the isDirectory() branch, add:
if (entry.isSymbolicLink() && statSync(join(dir, entry.name)).isDirectory()) {
  // treat as directory
}

Or more compactly:

const isDir = entry.isDirectory() || (entry.isSymbolicLink() && statSync(join(dir, entry.name)).isDirectory());
if (isDir) { ... }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions