mirror of
https://github.com/github/awesome-copilot.git
synced 2026-08-26 18:45:12 +00:00
fix(eng): list nested skill assets instead of directory names 🤖🤖🤖 (#2765)
* fix(eng): list nested skill assets instead of directory names * test(eng): clean up temp dirs and cover nested SKILL.md assets * fix(eng): do not follow symlinks when listing bundled assets * fix(eng): keep file symlinks in bundled asset lists
This commit is contained in:
+32
-13
@@ -14,6 +14,24 @@ function safeFileOperation(operation, filePath, defaultValue = null) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decide whether a symlinked entry should be left out of a bundled asset list.
|
||||
*
|
||||
* Directory symlinks are skipped because following one can walk outside the
|
||||
* folder or form a cycle. Broken links are skipped too. File symlinks are kept:
|
||||
* plugin materialization dereferences them, so they really are bundled content.
|
||||
*
|
||||
* @param {string} filePath - Path to the symlinked entry
|
||||
* @returns {boolean} True when the entry should be skipped
|
||||
*/
|
||||
function skipsAsBundledAsset(filePath) {
|
||||
try {
|
||||
return fs.statSync(filePath).isDirectory();
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse frontmatter from a markdown file using vfile-matter
|
||||
* Works with any markdown file that has YAML frontmatter (agents, prompts, instructions)
|
||||
@@ -142,16 +160,16 @@ function parseSkillMetadata(skillPath) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// List bundled assets (all files except SKILL.md), recursing through subdirectories
|
||||
// List bundled assets (all files except SKILL.md), recursing through subdirectories.
|
||||
// Directory symlinks are skipped: following one can escape the skill folder.
|
||||
const getAllFiles = (dirPath, arrayOfFiles = []) => {
|
||||
const files = fs.readdirSync(dirPath);
|
||||
const assetPaths = ['references', 'assets', 'scripts'];
|
||||
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
||||
|
||||
files.forEach((file) => {
|
||||
const filePath = path.join(dirPath, file);
|
||||
if (fs.statSync(filePath).isDirectory() && assetPaths.includes(file)) {
|
||||
entries.forEach((entry) => {
|
||||
const filePath = path.join(dirPath, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
arrayOfFiles = getAllFiles(filePath, arrayOfFiles);
|
||||
} else {
|
||||
} else if (!entry.isSymbolicLink() || !skipsAsBundledAsset(filePath)) {
|
||||
const relativePath = path.relative(skillPath, filePath);
|
||||
if (relativePath !== "SKILL.md") {
|
||||
// Normalize path separators to forward slashes for cross-platform consistency
|
||||
@@ -218,15 +236,16 @@ function parseHookMetadata(hookPath) {
|
||||
}
|
||||
}
|
||||
|
||||
// List bundled assets (all files except README.md), recursing through subdirectories
|
||||
// List bundled assets (all files except README.md), recursing through subdirectories.
|
||||
// Directory symlinks are skipped: following one can escape the hook folder.
|
||||
const getAllFiles = (dirPath, arrayOfFiles = []) => {
|
||||
const files = fs.readdirSync(dirPath);
|
||||
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
||||
|
||||
files.forEach((file) => {
|
||||
const filePath = path.join(dirPath, file);
|
||||
if (fs.statSync(filePath).isDirectory()) {
|
||||
entries.forEach((entry) => {
|
||||
const filePath = path.join(dirPath, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
arrayOfFiles = getAllFiles(filePath, arrayOfFiles);
|
||||
} else {
|
||||
} else if (!entry.isSymbolicLink() || !skipsAsBundledAsset(filePath)) {
|
||||
const relativePath = path.relative(hookPath, filePath);
|
||||
if (relativePath !== "README.md") {
|
||||
// Normalize path separators to forward slashes for cross-platform consistency
|
||||
|
||||
Reference in New Issue
Block a user