@intellectronica/ruler 0.3.32 → 0.3.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/constants.js +1 -1
- package/dist/core/SkillsProcessor.js +70 -18
- package/dist/lib.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -76,7 +76,7 @@ Ruler solves this by providing a **single source of truth** for all your AI agen
|
|
|
76
76
|
| Junie | `.junie/guidelines.md` | - | - |
|
|
77
77
|
| AugmentCode | `.augment/rules/ruler_augment_instructions.md` | - | - |
|
|
78
78
|
| Kilo Code | `AGENTS.md` | `.kilocode/mcp.json` | `.claude/skills/` |
|
|
79
|
-
| OpenCode | `AGENTS.md` | `opencode.json` | `.opencode/
|
|
79
|
+
| OpenCode | `AGENTS.md` | `opencode.json` | `.opencode/skills/` |
|
|
80
80
|
| Goose | `.goosehints` | - | `.agents/skills/` |
|
|
81
81
|
| Qwen Code | `AGENTS.md` | `.qwen/settings.json` | - |
|
|
82
82
|
| RooCode | `AGENTS.md` | `.roo/mcp.json` | `.roo/skills/` |
|
|
@@ -578,7 +578,7 @@ Skills are specialized knowledge packages that extend AI agent capabilities with
|
|
|
578
578
|
- **GitHub Copilot**: `.claude/skills/` (shared with Claude Code)
|
|
579
579
|
- **Kilo Code**: `.claude/skills/` (shared with Claude Code)
|
|
580
580
|
- **OpenAI Codex CLI**: `.codex/skills/`
|
|
581
|
-
- **OpenCode**: `.opencode/
|
|
581
|
+
- **OpenCode**: `.opencode/skills/`
|
|
582
582
|
- **Pi Coding Agent**: `.pi/skills/`
|
|
583
583
|
- **Goose**: `.agents/skills/`
|
|
584
584
|
- **Amp**: `.agents/skills/` (shared with Goose)
|
|
@@ -644,7 +644,7 @@ When skills support is enabled and gitignore integration is active, Ruler automa
|
|
|
644
644
|
|
|
645
645
|
- `.claude/skills/` (for Claude Code, GitHub Copilot, and Kilo Code)
|
|
646
646
|
- `.codex/skills/` (for OpenAI Codex CLI)
|
|
647
|
-
- `.opencode/
|
|
647
|
+
- `.opencode/skills/` (for OpenCode)
|
|
648
648
|
- `.pi/skills/` (for Pi Coding Agent)
|
|
649
649
|
- `.agents/skills/` (for Goose and Amp)
|
|
650
650
|
- `.agent/skills/` (for Antigravity)
|
|
@@ -703,7 +703,7 @@ ruler apply
|
|
|
703
703
|
# 3. Skills are now available to compatible agents:
|
|
704
704
|
# - Claude Code, GitHub Copilot & Kilo Code: .claude/skills/my-skill/
|
|
705
705
|
# - OpenAI Codex CLI: .codex/skills/my-skill/
|
|
706
|
-
# - OpenCode: .opencode/
|
|
706
|
+
# - OpenCode: .opencode/skills/my-skill/
|
|
707
707
|
# - Pi Coding Agent: .pi/skills/my-skill/
|
|
708
708
|
# - Goose & Amp: .agents/skills/my-skill/
|
|
709
709
|
# - Antigravity: .agent/skills/my-skill/
|
package/dist/constants.js
CHANGED
|
@@ -54,7 +54,7 @@ exports.SKILLS_DIR = 'skills';
|
|
|
54
54
|
exports.RULER_SKILLS_PATH = '.ruler/skills';
|
|
55
55
|
exports.CLAUDE_SKILLS_PATH = '.claude/skills';
|
|
56
56
|
exports.CODEX_SKILLS_PATH = '.codex/skills';
|
|
57
|
-
exports.OPENCODE_SKILLS_PATH = '.opencode/
|
|
57
|
+
exports.OPENCODE_SKILLS_PATH = '.opencode/skills';
|
|
58
58
|
exports.PI_SKILLS_PATH = '.pi/skills';
|
|
59
59
|
exports.GOOSE_SKILLS_PATH = '.agents/skills';
|
|
60
60
|
exports.VIBE_SKILLS_PATH = '.vibe/skills';
|
|
@@ -72,7 +72,7 @@ async function discoverSkills(projectRoot) {
|
|
|
72
72
|
* Gets the paths that skills will generate, for gitignore purposes.
|
|
73
73
|
* Returns empty array if skills directory doesn't exist.
|
|
74
74
|
*/
|
|
75
|
-
async function getSkillsGitignorePaths(projectRoot) {
|
|
75
|
+
async function getSkillsGitignorePaths(projectRoot, agents) {
|
|
76
76
|
const skillsDir = path.join(projectRoot, constants_1.RULER_SKILLS_PATH);
|
|
77
77
|
// Check if skills directory exists
|
|
78
78
|
try {
|
|
@@ -83,19 +83,21 @@ async function getSkillsGitignorePaths(projectRoot) {
|
|
|
83
83
|
}
|
|
84
84
|
// Import here to avoid circular dependency
|
|
85
85
|
const { CLAUDE_SKILLS_PATH, CODEX_SKILLS_PATH, OPENCODE_SKILLS_PATH, PI_SKILLS_PATH, GOOSE_SKILLS_PATH, VIBE_SKILLS_PATH, ROO_SKILLS_PATH, GEMINI_SKILLS_PATH, CURSOR_SKILLS_PATH, FACTORY_SKILLS_PATH, ANTIGRAVITY_SKILLS_PATH, } = await Promise.resolve().then(() => __importStar(require('../constants')));
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
86
|
+
const selectedTargets = getSelectedSkillTargets(agents);
|
|
87
|
+
const targetPaths = {
|
|
88
|
+
claude: CLAUDE_SKILLS_PATH,
|
|
89
|
+
codex: CODEX_SKILLS_PATH,
|
|
90
|
+
opencode: OPENCODE_SKILLS_PATH,
|
|
91
|
+
pi: PI_SKILLS_PATH,
|
|
92
|
+
goose: GOOSE_SKILLS_PATH,
|
|
93
|
+
vibe: VIBE_SKILLS_PATH,
|
|
94
|
+
roo: ROO_SKILLS_PATH,
|
|
95
|
+
gemini: GEMINI_SKILLS_PATH,
|
|
96
|
+
cursor: CURSOR_SKILLS_PATH,
|
|
97
|
+
factory: FACTORY_SKILLS_PATH,
|
|
98
|
+
antigravity: ANTIGRAVITY_SKILLS_PATH,
|
|
99
|
+
};
|
|
100
|
+
return Array.from(selectedTargets).map((target) => path.join(projectRoot, targetPaths[target]));
|
|
99
101
|
}
|
|
100
102
|
/**
|
|
101
103
|
* Module-level state to track if experimental warning has been shown.
|
|
@@ -115,6 +117,31 @@ function warnOnceExperimental(verbose, dryRun) {
|
|
|
115
117
|
hasWarnedExperimental = true;
|
|
116
118
|
(0, constants_1.logWarn)('Skills support is experimental and behavior may change in future releases.', dryRun);
|
|
117
119
|
}
|
|
120
|
+
const SKILL_TARGET_TO_IDENTIFIERS = new Map([
|
|
121
|
+
['claude', ['claude', 'copilot', 'kilocode']],
|
|
122
|
+
['codex', ['codex']],
|
|
123
|
+
['opencode', ['opencode']],
|
|
124
|
+
['pi', ['pi']],
|
|
125
|
+
['goose', ['goose', 'amp']],
|
|
126
|
+
['vibe', ['mistral']],
|
|
127
|
+
['roo', ['roo']],
|
|
128
|
+
['gemini', ['gemini-cli']],
|
|
129
|
+
['cursor', ['cursor']],
|
|
130
|
+
['factory', ['factory']],
|
|
131
|
+
['antigravity', ['antigravity']],
|
|
132
|
+
]);
|
|
133
|
+
function getSelectedSkillTargets(agents) {
|
|
134
|
+
const selectedIdentifiers = new Set(agents
|
|
135
|
+
.filter((agent) => agent.supportsNativeSkills?.())
|
|
136
|
+
.map((agent) => agent.getIdentifier()));
|
|
137
|
+
const targets = new Set();
|
|
138
|
+
for (const [target, identifiers] of SKILL_TARGET_TO_IDENTIFIERS) {
|
|
139
|
+
if (identifiers.some((id) => selectedIdentifiers.has(id))) {
|
|
140
|
+
targets.add(target);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return targets;
|
|
144
|
+
}
|
|
118
145
|
/**
|
|
119
146
|
* Cleans up skills directories when skills are disabled.
|
|
120
147
|
* This ensures that stale skills from previous runs don't persist when skills are turned off.
|
|
@@ -159,7 +186,7 @@ async function cleanupSkillsDirectories(projectRoot, dryRun, verbose) {
|
|
|
159
186
|
catch {
|
|
160
187
|
// Directory doesn't exist, nothing to clean
|
|
161
188
|
}
|
|
162
|
-
// Clean up .opencode/
|
|
189
|
+
// Clean up .opencode/skills
|
|
163
190
|
try {
|
|
164
191
|
await fs.access(opencodeSkillsPath);
|
|
165
192
|
if (dryRun) {
|
|
@@ -330,28 +357,53 @@ async function propagateSkills(projectRoot, agents, skillsEnabled, verbose, dryR
|
|
|
330
357
|
}
|
|
331
358
|
// Warn about experimental features
|
|
332
359
|
warnOnceExperimental(verbose, dryRun);
|
|
360
|
+
const selectedTargets = getSelectedSkillTargets(agents);
|
|
361
|
+
if (selectedTargets.size === 0) {
|
|
362
|
+
(0, constants_1.logVerboseInfo)('No selected agents require skills propagation, skipping skills propagation', verbose, dryRun);
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
333
365
|
// Copy to Claude skills directory if needed
|
|
334
|
-
if (
|
|
335
|
-
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.CLAUDE_SKILLS_PATH} for Claude Code, GitHub Copilot, and
|
|
366
|
+
if (selectedTargets.has('claude')) {
|
|
367
|
+
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.CLAUDE_SKILLS_PATH} for Claude Code, GitHub Copilot, and KiloCode`, verbose, dryRun);
|
|
336
368
|
await propagateSkillsForClaude(projectRoot, { dryRun });
|
|
369
|
+
}
|
|
370
|
+
if (selectedTargets.has('codex')) {
|
|
337
371
|
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.CODEX_SKILLS_PATH} for OpenAI Codex CLI`, verbose, dryRun);
|
|
338
372
|
await propagateSkillsForCodex(projectRoot, { dryRun });
|
|
373
|
+
}
|
|
374
|
+
if (selectedTargets.has('opencode')) {
|
|
339
375
|
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.OPENCODE_SKILLS_PATH} for OpenCode`, verbose, dryRun);
|
|
340
376
|
await propagateSkillsForOpenCode(projectRoot, { dryRun });
|
|
377
|
+
}
|
|
378
|
+
if (selectedTargets.has('pi')) {
|
|
341
379
|
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.PI_SKILLS_PATH} for Pi Coding Agent`, verbose, dryRun);
|
|
342
380
|
await propagateSkillsForPi(projectRoot, { dryRun });
|
|
381
|
+
}
|
|
382
|
+
if (selectedTargets.has('goose')) {
|
|
343
383
|
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.GOOSE_SKILLS_PATH} for Goose and Amp`, verbose, dryRun);
|
|
344
384
|
await propagateSkillsForGoose(projectRoot, { dryRun });
|
|
385
|
+
}
|
|
386
|
+
if (selectedTargets.has('vibe')) {
|
|
345
387
|
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.VIBE_SKILLS_PATH} for Mistral Vibe`, verbose, dryRun);
|
|
346
388
|
await propagateSkillsForVibe(projectRoot, { dryRun });
|
|
389
|
+
}
|
|
390
|
+
if (selectedTargets.has('roo')) {
|
|
347
391
|
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.ROO_SKILLS_PATH} for Roo Code`, verbose, dryRun);
|
|
348
392
|
await propagateSkillsForRoo(projectRoot, { dryRun });
|
|
393
|
+
}
|
|
394
|
+
if (selectedTargets.has('gemini')) {
|
|
349
395
|
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.GEMINI_SKILLS_PATH} for Gemini CLI`, verbose, dryRun);
|
|
350
396
|
await propagateSkillsForGemini(projectRoot, { dryRun });
|
|
397
|
+
}
|
|
398
|
+
if (selectedTargets.has('cursor')) {
|
|
351
399
|
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.CURSOR_SKILLS_PATH} for Cursor`, verbose, dryRun);
|
|
352
400
|
await propagateSkillsForCursor(projectRoot, { dryRun });
|
|
401
|
+
}
|
|
402
|
+
if (selectedTargets.has('factory')) {
|
|
353
403
|
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.FACTORY_SKILLS_PATH} for Factory Droid`, verbose, dryRun);
|
|
354
404
|
await propagateSkillsForFactory(projectRoot, { dryRun });
|
|
405
|
+
}
|
|
406
|
+
if (selectedTargets.has('antigravity')) {
|
|
355
407
|
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.ANTIGRAVITY_SKILLS_PATH} for Antigravity`, verbose, dryRun);
|
|
356
408
|
await propagateSkillsForAntigravity(projectRoot, { dryRun });
|
|
357
409
|
}
|
|
@@ -458,7 +510,7 @@ async function propagateSkillsForCodex(projectRoot, options) {
|
|
|
458
510
|
return [];
|
|
459
511
|
}
|
|
460
512
|
/**
|
|
461
|
-
* Propagates skills for OpenCode by copying .ruler/skills to .opencode/
|
|
513
|
+
* Propagates skills for OpenCode by copying .ruler/skills to .opencode/skills.
|
|
462
514
|
* Uses atomic replace to ensure safe overwriting of existing skills.
|
|
463
515
|
* Returns dry-run steps if dryRun is true, otherwise returns empty array.
|
|
464
516
|
*/
|
package/dist/lib.js
CHANGED
|
@@ -125,7 +125,7 @@ async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cli
|
|
|
125
125
|
if (skillsEnabledForGitignore) {
|
|
126
126
|
// Skills enabled by default or explicitly
|
|
127
127
|
const { getSkillsGitignorePaths } = await Promise.resolve().then(() => __importStar(require('./core/SkillsProcessor')));
|
|
128
|
-
const skillsPaths = await getSkillsGitignorePaths(projectRoot);
|
|
128
|
+
const skillsPaths = await getSkillsGitignorePaths(projectRoot, selectedAgents);
|
|
129
129
|
allGeneratedPaths = [...generatedPaths, ...skillsPaths];
|
|
130
130
|
}
|
|
131
131
|
await (0, apply_engine_1.updateGitignore)(projectRoot, allGeneratedPaths, loadedConfig, cliGitignoreEnabled, dryRun);
|