fix(eng): list nested skill assets instead of directory names 🤖🤖🤖 - #2765
Conversation
|
🔴 Contributor Reputation Check: HIGH risk
Maintainers: please review this contributor before merging. |
There was a problem hiding this comment.
Pull request overview
Fixes skill asset discovery by recursively listing bundled files.
Changes:
- Recurses through all skill subdirectories.
- Adds regression tests for nested assets.
- Regenerates skill documentation.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
eng/yaml-parser.mjs |
Recursively discovers skill assets. |
eng/yaml-parser.test.mjs |
Tests nested asset discovery. |
docs/README.skills.md |
Lists previously hidden asset files. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Good catch, fixed. Temp paths are now tracked and removed in an |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
eng/yaml-parser.mjs:152
statSync()follows directory symlinks, so unconditional recursion can now leave the skill root (for example, a trackedtemplates -> ../other-skilllink) or enter a cycle and makeparseSkillMetadata()fail. That causes the asset list and 5 MB validation to inspect files that are not actually contained in this skill. Please use directory-entry/lstat information and explicitly reject or avoid recursing through symlinks, with a regression test for the chosen policy. The equivalent hook traversal ateng/yaml-parser.mjs:226should follow the same policy.
if (fs.statSync(filePath).isDirectory()) {
arrayOfFiles = getAllFiles(filePath, arrayOfFiles);
|
Fair point, and you're right that this PR widened the exposure — before the change a symlinked non-spec directory was never traversed, so unconditional recursion made |
|
Good catch on the file case — fixed. I confirmed On the directory case, I checked and |
…directory-listing
|
Merged While re-syncing I noticed a fresh example of the bug this PR fixes, in a skill that landed yesterday. Simulating the pre-fix Seven real files hidden behind two entries that are not files at all. This also means That is the failure mode this PR removes, and it will keep recurring for any skill that organises bundled content under a directory name outside the three-entry allowlist. Checks are green and the diff is unchanged at three files. |
Description
parseSkillMetadata()ineng/yaml-parser.mjsonly recursed into three hard-codeddirectory names when listing a skill's bundled assets:
Any other directory fell into the
elsebranch and was pushed as if it were a file.Three consequences:
one level deep, so
references/skeletons/,scripts/lib/, andassets/templates/are never walked.
docs/README.skills.mdlistedqdrant-scalingas having four assets namedminimize-latency,scaling-data-volume,scaling-qps,scaling-query-volume—those are folders, and the 12
SKILL.mdfiles inside them were invisible.eng/validate-skills.mjsiterates this same list, so it called
statSyncon directories and never checkedanything inside a non-allowlisted folder. An oversized file in
skills/<name>/templates/passes validation today.23 skills are affected, hiding roughly 120 bundled files from the generated docs and
website data.
Fix
Recurse unconditionally and never emit a directory. This makes
parseSkillMetadata()match
parseHookMetadata()directly below it, which already walks all subdirectories,and matches
eng/materialize-plugins.mjs, which copies skill folders recursivelyregardless of directory name.
Verification
npm start— onlydocs/README.skills.mdchanged (regenerated, included here)npm run plugin:validate— passes (94 local + 43 external)npm run skill:validate— passes, no new size violationsnode --testacross all 8eng/**/*.test.mjsfiles — 55 tests, 0 failuresAdded
eng/yaml-parser.test.mjsas a regression guard: it fails 1/2 against theprevious implementation and passes 2/2 with the fix.
Notes
Related to #503 — this is a follow-up to a regression that fix introduced, not a
reopening of it.
This fix was developed with AI assistance; I have reviewed and verified the change
locally.