-
Notifications
You must be signed in to change notification settings - Fork 62
feat: declarative skill sources with lockfile and curated directory #973
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Add support for declaring remote skill sources in rulesync.jsonc config.
Skills are fetched from GitHub repos and placed in .rulesync/skills/.curated/.
- Add 'sources' field to config schema (array of { source, skills? })
- Implement sources-lock.json for deterministic ref resolution
- Add resolveAndFetchSources pipeline integrated into generate command
- Extend SkillsProcessor to scan both local and .curated/ directories
- Local skills take precedence over curated; first-declared source wins
- Add --skip-sources and --update-sources CLI flags
- Add .rulesync/skills/.curated/ to gitignore entries
- Add resolveRefToSha to GitHubClient
- Add tests for sources-lock and sources modules
Replace prepare script that required pnpm with a no-op fallback. Add prepack script to build when installed from git source.
When a source URL includes a path (e.g. /tree/main/skills/.curated), treat it as the skills directory itself rather than prepending skills/ to it. This supports repos like openai/skills where skills are nested under skills/.curated/ rather than at the repo root.
Add comprehensive documentation for the new declarative sources feature: - README.md: Add 'Declarative Skill Sources' section with config, lockfile, precedence rules, CLI flags, and curated vs local skills table. Update Configuration section to show sources field. Update Quick Commands and Getting Started with source-related flags and alternatives. - skills/rulesync/declarative-sources.md: New skill reference doc covering configuration, how it works, CLI options, lockfile, curated vs local, and relationship to the fetch command. - skills/rulesync/SKILL.md: Add declarative-sources.md to table of contents. - skills/rulesync/configuration.md: Add sources field to config example. - skills/rulesync/getting-started.md: Mention sources as alternative to fetch. - skills/rulesync/official-skills.md: Add declarative sources config example. - skills/rulesync/quick-commands.md: Add --skip-sources and --update-sources.
- Security: validate skillDir.name for path traversal characters (../) before constructing file paths in sources.ts - Quality: replace mutable delete loop with immutable filter pattern for lockfile pruning in sources.ts - Design: validate --skip-sources and --update-sources mutual exclusivity in generate command, matching --dry-run/--check pattern - Testing: improve updateSources test with pre-populated lock to verify locked SHA is actually ignored when flag is set - Quality: use repos.getCommit() instead of listCommits(per_page:1) for resolveRefToSha — more direct and no null-access risk - Types: narrow ConfigResolverResolveParams to Omit<ConfigParams, 'sources'> since sources are config-file-only; remove unused SourceEntry import
|
Thank you for this well-thought-out PR! The lockfile mechanism, After reviewing the changes, here's my thinking: Concern: Complexity in the
|
|
@dyoshikawa I pushed an alternative version to #1032. |
|
duplicate #1032 |
Summary
Adds Declarative Skill Sources — a new feature allowing users to declare remote GitHub skill repositories in
rulesync.jsonc. Duringgenerate, these sources are automatically fetched, SHA-locked, and placed into.rulesync/skills/.curated/for use alongside local skills.Motivation
Currently, fetching skills from external repos requires manually running
rulesync fetchfor each source. This feature makes skill sourcing declarative and reproducible: declare once in config, andgeneratehandles the rest — with lockfile-based determinism and local-skill precedence.Changes
Core Implementation
src/lib/sources.ts— Main orchestrator: resolves source entries, fetches remote skill directories into.curated/, handles local-skill precedence, duplicate detection, and error recoverysrc/lib/sources-lock.ts— Lockfile operations: read/write.rulesync/sources-lock.jsonwith Zod schema validation, immutable set/get helperssrc/lib/github-client.ts— NewresolveRefToSha()method to resolve branch/tag/SHA to commit SHA viarepos.getCommit()Integration
src/lib/generate.ts— CallsresolveAndFetchSources()before skill generation whensourcesis configuredsrc/cli/commands/generate.ts— Wires--skip-sourcesand--update-sourcesCLI flags; validates mutual exclusivitysrc/cli/index.ts— Registers--skip-sourcesand--update-sourcesCLI optionssrc/config/config.ts— Addssourcesfield to config schema withSourceEntrytypesrc/config/config-resolver.ts— Resolvessourcesfrom config file (not CLI); type narrowed withOmit<ConfigParams, 'sources'>src/features/skills/skills-processor.ts—loadRulesyncDirs()now discovers curated skills in.curated/subdirectory with local-precedence filteringsrc/cli/commands/gitignore.ts— Adds.rulesync/skills/.curated/to gitignore entriessrc/constants/rulesync-paths.ts— New constants for curated skills dir and sources-lock pathSecurity
skillDir.name(rejects..,/,\characters)checkPathTraversal()MAX_FILE_SIZE(10MB)Tests (27 new tests)
src/lib/sources.test.ts(13 tests) — empty sources, skip, update, local precedence, skill filter, duplicates, 404 handling, error recovery, stale pruning, path traversal, GitLab graceful handlingsrc/lib/sources-lock.test.ts(12 tests) — empty lock, read/write, validation, immutabilitysrc/lib/generate.test.ts(4 tests) — sources integration with generatesrc/cli/commands/generate.test.ts(2 tests) — CLI flag wiring and mutual exclusivityDocumentation
README.md— Full "Declarative Skill Sources" section with config examples, CLI flags, lockfile format, authentication, precedence rulesskills/rulesync/declarative-skill-sources.md— Standalone skill docskills/rulesync/SKILL.md— Updated table of contentsconfig-schema.json— Addedsourcesproperty to JSON schemaConfig Example
{ "targets": ["copilot", "claudecode"], "features": ["rules", "skills"], "sources": [ { "source": "owner/skills-repo" }, { "source": "org/repo", "skills": ["specific-skill"] }, { "source": "org/repo@v1.0.0:custom/path" } ] }CLI
Verification