@intellectronica/ruler 0.3.24 → 0.3.26
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 +48 -67
- package/dist/agents/AntigravityAgent.js +3 -0
- package/dist/constants.js +2 -3
- package/dist/core/SkillsProcessor.js +34 -45
- package/dist/core/apply-engine.js +11 -84
- package/dist/lib.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -54,38 +54,38 @@ Ruler solves this by providing a **single source of truth** for all your AI agen
|
|
|
54
54
|
|
|
55
55
|
## Supported AI Agents
|
|
56
56
|
|
|
57
|
-
| Agent | Rules File(s) | MCP Configuration / Notes |
|
|
58
|
-
| ---------------- | ------------------------------------------------ | ------------------------------------------------ |
|
|
59
|
-
| AGENTS.md | `AGENTS.md` | (pseudo-agent ensuring root `AGENTS.md` exists) |
|
|
60
|
-
| GitHub Copilot | `AGENTS.md` | `.vscode/mcp.json` |
|
|
61
|
-
| Claude Code | `CLAUDE.md` | `.mcp.json` |
|
|
62
|
-
| OpenAI Codex CLI | `AGENTS.md` | `.codex/config.toml` |
|
|
63
|
-
| Pi Coding Agent | `AGENTS.md` | - |
|
|
64
|
-
| Jules | `AGENTS.md` | - |
|
|
65
|
-
| Cursor | `AGENTS.md` | `.cursor/mcp.json` |
|
|
66
|
-
| Windsurf | `AGENTS.md` | `.windsurf/mcp_config.json` |
|
|
67
|
-
| Cline | `.clinerules` | - |
|
|
68
|
-
| Crush | `CRUSH.md` | `.crush.json` |
|
|
69
|
-
| Amp | `AGENTS.md` | - |
|
|
70
|
-
| Antigravity | `.agent/rules/ruler.md` | - |
|
|
71
|
-
| Amazon Q CLI | `.amazonq/rules/ruler_q_rules.md` | `.amazonq/mcp.json` |
|
|
72
|
-
| Aider | `AGENTS.md`, `.aider.conf.yml` | `.mcp.json` |
|
|
73
|
-
| Firebase Studio | `.idx/airules.md` | `.idx/mcp.json` |
|
|
74
|
-
| Open Hands | `.openhands/microagents/repo.md` | `config.toml` |
|
|
75
|
-
| Gemini CLI | `AGENTS.md` | `.gemini/settings.json` |
|
|
76
|
-
| Junie | `.junie/guidelines.md` | - |
|
|
77
|
-
| AugmentCode | `.augment/rules/ruler_augment_instructions.md` | - |
|
|
78
|
-
| Kilo Code | `.kilocode/rules/ruler_kilocode_instructions.md` | `.kilocode/mcp.json` |
|
|
79
|
-
| OpenCode | `AGENTS.md` | `opencode.json` |
|
|
80
|
-
| Goose | `.goosehints` | - |
|
|
81
|
-
| Qwen Code | `AGENTS.md` | `.qwen/settings.json` |
|
|
82
|
-
| RooCode | `AGENTS.md` | `.roo/mcp.json` |
|
|
83
|
-
| Zed | `AGENTS.md` | `.zed/settings.json` (project root, never $HOME) |
|
|
84
|
-
| Trae AI | `.trae/rules/project_rules.md` | - |
|
|
85
|
-
| Warp | `WARP.md` | - |
|
|
86
|
-
| Kiro | `.kiro/steering/ruler_kiro_instructions.md` | `.kiro/settings/mcp.json` |
|
|
87
|
-
| Firebender | `firebender.json` | `firebender.json` (rules and MCP in same file) |
|
|
88
|
-
| Mistral Vibe | `AGENTS.md` | `.vibe/config.toml` |
|
|
57
|
+
| Agent | Rules File(s) | MCP Configuration / Notes | Skills Support / Location |
|
|
58
|
+
| ---------------- | ------------------------------------------------ | ------------------------------------------------ | ------------------------------------------------- |
|
|
59
|
+
| AGENTS.md | `AGENTS.md` | (pseudo-agent ensuring root `AGENTS.md` exists) | - |
|
|
60
|
+
| GitHub Copilot | `AGENTS.md` | `.vscode/mcp.json` | `.claude/skills/` |
|
|
61
|
+
| Claude Code | `CLAUDE.md` | `.mcp.json` | `.claude/skills/` |
|
|
62
|
+
| OpenAI Codex CLI | `AGENTS.md` | `.codex/config.toml` | `.codex/skills/` |
|
|
63
|
+
| Pi Coding Agent | `AGENTS.md` | - | `.pi/skills/` |
|
|
64
|
+
| Jules | `AGENTS.md` | - | - |
|
|
65
|
+
| Cursor | `AGENTS.md` | `.cursor/mcp.json` | `.cursor/skills/` |
|
|
66
|
+
| Windsurf | `AGENTS.md` | `.windsurf/mcp_config.json` | - |
|
|
67
|
+
| Cline | `.clinerules` | - | - |
|
|
68
|
+
| Crush | `CRUSH.md` | `.crush.json` | - |
|
|
69
|
+
| Amp | `AGENTS.md` | - | `.agents/skills/` |
|
|
70
|
+
| Antigravity | `.agent/rules/ruler.md` | - | `.agent/skills/` |
|
|
71
|
+
| Amazon Q CLI | `.amazonq/rules/ruler_q_rules.md` | `.amazonq/mcp.json` | - |
|
|
72
|
+
| Aider | `AGENTS.md`, `.aider.conf.yml` | `.mcp.json` | - |
|
|
73
|
+
| Firebase Studio | `.idx/airules.md` | `.idx/mcp.json` | - |
|
|
74
|
+
| Open Hands | `.openhands/microagents/repo.md` | `config.toml` | - |
|
|
75
|
+
| Gemini CLI | `AGENTS.md` | `.gemini/settings.json` | `.gemini/skills/` |
|
|
76
|
+
| Junie | `.junie/guidelines.md` | - | - |
|
|
77
|
+
| AugmentCode | `.augment/rules/ruler_augment_instructions.md` | - | - |
|
|
78
|
+
| Kilo Code | `.kilocode/rules/ruler_kilocode_instructions.md` | `.kilocode/mcp.json` | `.claude/skills/` |
|
|
79
|
+
| OpenCode | `AGENTS.md` | `opencode.json` | `.opencode/skill/` |
|
|
80
|
+
| Goose | `.goosehints` | - | `.agents/skills/` |
|
|
81
|
+
| Qwen Code | `AGENTS.md` | `.qwen/settings.json` | - |
|
|
82
|
+
| RooCode | `AGENTS.md` | `.roo/mcp.json` | `.roo/skills/` |
|
|
83
|
+
| Zed | `AGENTS.md` | `.zed/settings.json` (project root, never $HOME) | - |
|
|
84
|
+
| Trae AI | `.trae/rules/project_rules.md` | - | - |
|
|
85
|
+
| Warp | `WARP.md` | - | - |
|
|
86
|
+
| Kiro | `.kiro/steering/ruler_kiro_instructions.md` | `.kiro/settings/mcp.json` | - |
|
|
87
|
+
| Firebender | `firebender.json` | `firebender.json` (rules and MCP in same file) | - |
|
|
88
|
+
| Mistral Vibe | `AGENTS.md` | `.vibe/config.toml` | `.vibe/skills/` |
|
|
89
89
|
|
|
90
90
|
## Getting Started
|
|
91
91
|
|
|
@@ -318,15 +318,15 @@ ruler revert [options]
|
|
|
318
318
|
|
|
319
319
|
### Options
|
|
320
320
|
|
|
321
|
-
| Option | Description
|
|
322
|
-
| ------------------------------ |
|
|
323
|
-
| `--project-root <path>` | Path to your project's root (default: current directory)
|
|
321
|
+
| Option | Description |
|
|
322
|
+
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
323
|
+
| `--project-root <path>` | Path to your project's root (default: current directory) |
|
|
324
324
|
| `--agents <agent1,agent2,...>` | Comma-separated list of agent names to revert (agentsmd, aider, amazonqcli, amp, antigravity, augmentcode, claude, cline, codex, copilot, crush, cursor, firebase, firebender, gemini-cli, goose, jules, junie, kilocode, kiro, mistral, opencode, openhands, pi, qwen, roo, trae, warp, windsurf, zed) |
|
|
325
|
-
| `--config <path>` | Path to a custom `ruler.toml` configuration file
|
|
326
|
-
| `--keep-backups` | Keep backup files (.bak) after restoration (default: false)
|
|
327
|
-
| `--dry-run` | Preview changes without actually reverting files
|
|
328
|
-
| `--verbose` / `-v` | Display detailed output during execution
|
|
329
|
-
| `--local-only` | Only search for local .ruler directories, ignore global config
|
|
325
|
+
| `--config <path>` | Path to a custom `ruler.toml` configuration file |
|
|
326
|
+
| `--keep-backups` | Keep backup files (.bak) after restoration (default: false) |
|
|
327
|
+
| `--dry-run` | Preview changes without actually reverting files |
|
|
328
|
+
| `--verbose` / `-v` | Display detailed output during execution |
|
|
329
|
+
| `--local-only` | Only search for local .ruler directories, ignore global config |
|
|
330
330
|
|
|
331
331
|
### Common Examples
|
|
332
332
|
|
|
@@ -559,7 +559,7 @@ export CODEX_HOME="$(pwd)/.codex"
|
|
|
559
559
|
|
|
560
560
|
## Skills Support (Experimental)
|
|
561
561
|
|
|
562
|
-
**⚠️ Experimental Feature**: Skills support is currently experimental
|
|
562
|
+
**⚠️ Experimental Feature**: Skills support is currently experimental. Skills are only propagated to agents with native skills support; other agents are skipped with a warning.
|
|
563
563
|
|
|
564
564
|
Ruler can manage and propagate skills to supported AI agents. Skills are stored in `.ruler/skills/` and are automatically distributed to compatible agents when you run `ruler apply`.
|
|
565
565
|
|
|
@@ -576,11 +576,11 @@ Skills are specialized knowledge packages that extend AI agent capabilities with
|
|
|
576
576
|
- **Pi Coding Agent**: `.pi/skills/`
|
|
577
577
|
- **Goose**: `.agents/skills/`
|
|
578
578
|
- **Amp**: `.agents/skills/` (shared with Goose)
|
|
579
|
+
- **Antigravity**: `.agent/skills/`
|
|
579
580
|
- **Mistral Vibe**: `.vibe/skills/`
|
|
580
581
|
- **Roo Code**: `.roo/skills/`
|
|
581
582
|
- **Gemini CLI**: `.gemini/skills/`
|
|
582
583
|
- **Cursor**: `.cursor/skills/`
|
|
583
|
-
- **Other MCP-compatible agents**: Skills are copied to `.skillz/` and a Skillz MCP server is automatically configured via `uvx`
|
|
584
584
|
|
|
585
585
|
### Skills Directory Structure
|
|
586
586
|
|
|
@@ -627,23 +627,9 @@ ruler apply --no-skills
|
|
|
627
627
|
enabled = true # or false to disable
|
|
628
628
|
```
|
|
629
629
|
|
|
630
|
-
###
|
|
630
|
+
### Non-native Agents
|
|
631
631
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
1. Copies skills to `.skillz/` directory
|
|
635
|
-
2. Configures a Skillz MCP server in the agent's configuration
|
|
636
|
-
3. Uses `uvx` to launch the server with the absolute path to `.skillz`
|
|
637
|
-
|
|
638
|
-
Agents using native skills support (Claude Code, GitHub Copilot, Kilo Code, OpenAI Codex CLI, OpenCode, Pi Coding Agent, Goose, Amp, Mistral Vibe, Roo Code, Gemini CLI, and Cursor) **do not** use the Skillz MCP server and instead use their own native skills directories.
|
|
639
|
-
|
|
640
|
-
Example auto-generated MCP server configuration:
|
|
641
|
-
|
|
642
|
-
```toml
|
|
643
|
-
[mcp_servers.skillz]
|
|
644
|
-
command = "uvx"
|
|
645
|
-
args = ["skillz@latest", "/absolute/path/to/project/.skillz"]
|
|
646
|
-
```
|
|
632
|
+
If you run Ruler for agents that do not support native skills, Ruler logs a warning and skips skills propagation for those agents.
|
|
647
633
|
|
|
648
634
|
### `.gitignore` Integration
|
|
649
635
|
|
|
@@ -654,22 +640,17 @@ When skills support is enabled and gitignore integration is active, Ruler automa
|
|
|
654
640
|
- `.opencode/skill/` (for OpenCode)
|
|
655
641
|
- `.pi/skills/` (for Pi Coding Agent)
|
|
656
642
|
- `.agents/skills/` (for Goose and Amp)
|
|
643
|
+
- `.agent/skills/` (for Antigravity)
|
|
657
644
|
- `.vibe/skills/` (for Mistral Vibe)
|
|
658
645
|
- `.roo/skills/` (for Roo Code)
|
|
659
646
|
- `.gemini/skills/` (for Gemini CLI)
|
|
660
647
|
- `.cursor/skills/` (for Cursor)
|
|
661
|
-
- `.skillz/` (for other MCP-based agents)
|
|
662
648
|
|
|
663
649
|
to your `.gitignore` file within the managed Ruler block.
|
|
664
650
|
|
|
665
651
|
### Requirements
|
|
666
652
|
|
|
667
|
-
- **For agents with native skills support** (Claude Code, GitHub Copilot, Kilo Code, OpenAI Codex CLI, OpenCode, Pi Coding Agent, Goose, Amp, Mistral Vibe, Roo Code, Gemini CLI, Cursor): No additional requirements
|
|
668
|
-
- **For other MCP agents**: `uv` must be installed and available in your PATH
|
|
669
|
-
```bash
|
|
670
|
-
# Install uv if needed
|
|
671
|
-
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
672
|
-
```
|
|
653
|
+
- **For agents with native skills support** (Claude Code, GitHub Copilot, Kilo Code, OpenAI Codex CLI, OpenCode, Pi Coding Agent, Goose, Amp, Antigravity, Mistral Vibe, Roo Code, Gemini CLI, Cursor): No additional requirements.
|
|
673
654
|
|
|
674
655
|
### Validation
|
|
675
656
|
|
|
@@ -688,7 +669,7 @@ Test skills propagation without making changes:
|
|
|
688
669
|
ruler apply --dry-run
|
|
689
670
|
```
|
|
690
671
|
|
|
691
|
-
This shows which skills would be copied
|
|
672
|
+
This shows which skills would be copied.
|
|
692
673
|
|
|
693
674
|
### Example Workflow
|
|
694
675
|
|
|
@@ -717,11 +698,11 @@ ruler apply
|
|
|
717
698
|
# - OpenCode: .opencode/skill/my-skill/
|
|
718
699
|
# - Pi Coding Agent: .pi/skills/my-skill/
|
|
719
700
|
# - Goose & Amp: .agents/skills/my-skill/
|
|
701
|
+
# - Antigravity: .agent/skills/my-skill/
|
|
720
702
|
# - Mistral Vibe: .vibe/skills/my-skill/
|
|
721
703
|
# - Roo Code: .roo/skills/my-skill/
|
|
722
704
|
# - Gemini CLI: .gemini/skills/my-skill/
|
|
723
705
|
# - Cursor: .cursor/skills/my-skill/
|
|
724
|
-
# - Other MCP agents: .skillz/my-skill/ + Skillz MCP server configured
|
|
725
706
|
```
|
|
726
707
|
|
|
727
708
|
## `.gitignore` Integration
|
|
@@ -49,5 +49,8 @@ class AntigravityAgent extends AbstractAgent_1.AbstractAgent {
|
|
|
49
49
|
getDefaultOutputPath(projectRoot) {
|
|
50
50
|
return path.join(projectRoot, '.agent', 'rules', 'ruler.md');
|
|
51
51
|
}
|
|
52
|
+
supportsNativeSkills() {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
52
55
|
}
|
|
53
56
|
exports.AntigravityAgent = AntigravityAgent;
|
package/dist/constants.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.SKILL_MD_FILENAME = exports.ANTIGRAVITY_SKILLS_PATH = exports.CURSOR_SKILLS_PATH = exports.GEMINI_SKILLS_PATH = exports.ROO_SKILLS_PATH = exports.VIBE_SKILLS_PATH = exports.GOOSE_SKILLS_PATH = exports.PI_SKILLS_PATH = exports.OPENCODE_SKILLS_PATH = exports.CODEX_SKILLS_PATH = exports.CLAUDE_SKILLS_PATH = exports.RULER_SKILLS_PATH = exports.SKILLS_DIR = exports.DEFAULT_RULES_FILENAME = exports.ERROR_PREFIX = void 0;
|
|
4
4
|
exports.actionPrefix = actionPrefix;
|
|
5
5
|
exports.createRulerError = createRulerError;
|
|
6
6
|
exports.logVerbose = logVerbose;
|
|
@@ -61,6 +61,5 @@ exports.VIBE_SKILLS_PATH = '.vibe/skills';
|
|
|
61
61
|
exports.ROO_SKILLS_PATH = '.roo/skills';
|
|
62
62
|
exports.GEMINI_SKILLS_PATH = '.gemini/skills';
|
|
63
63
|
exports.CURSOR_SKILLS_PATH = '.cursor/skills';
|
|
64
|
-
exports.
|
|
64
|
+
exports.ANTIGRAVITY_SKILLS_PATH = '.agent/skills';
|
|
65
65
|
exports.SKILL_MD_FILENAME = 'SKILL.md';
|
|
66
|
-
exports.SKILLZ_MCP_SERVER_NAME = 'skillz';
|
|
@@ -45,8 +45,7 @@ exports.propagateSkillsForVibe = propagateSkillsForVibe;
|
|
|
45
45
|
exports.propagateSkillsForRoo = propagateSkillsForRoo;
|
|
46
46
|
exports.propagateSkillsForGemini = propagateSkillsForGemini;
|
|
47
47
|
exports.propagateSkillsForCursor = propagateSkillsForCursor;
|
|
48
|
-
exports.
|
|
49
|
-
exports.buildSkillzMcpConfig = buildSkillzMcpConfig;
|
|
48
|
+
exports.propagateSkillsForAntigravity = propagateSkillsForAntigravity;
|
|
50
49
|
const path = __importStar(require("path"));
|
|
51
50
|
const fs = __importStar(require("fs/promises"));
|
|
52
51
|
const constants_1 = require("../constants");
|
|
@@ -82,7 +81,7 @@ async function getSkillsGitignorePaths(projectRoot) {
|
|
|
82
81
|
return [];
|
|
83
82
|
}
|
|
84
83
|
// Import here to avoid circular dependency
|
|
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,
|
|
84
|
+
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, ANTIGRAVITY_SKILLS_PATH, } = await Promise.resolve().then(() => __importStar(require('../constants')));
|
|
86
85
|
return [
|
|
87
86
|
path.join(projectRoot, CLAUDE_SKILLS_PATH),
|
|
88
87
|
path.join(projectRoot, CODEX_SKILLS_PATH),
|
|
@@ -93,7 +92,7 @@ async function getSkillsGitignorePaths(projectRoot) {
|
|
|
93
92
|
path.join(projectRoot, ROO_SKILLS_PATH),
|
|
94
93
|
path.join(projectRoot, GEMINI_SKILLS_PATH),
|
|
95
94
|
path.join(projectRoot, CURSOR_SKILLS_PATH),
|
|
96
|
-
path.join(projectRoot,
|
|
95
|
+
path.join(projectRoot, ANTIGRAVITY_SKILLS_PATH),
|
|
97
96
|
];
|
|
98
97
|
}
|
|
99
98
|
/**
|
|
@@ -104,16 +103,15 @@ async function getSkillsGitignorePaths(projectRoot) {
|
|
|
104
103
|
*/
|
|
105
104
|
let hasWarnedExperimental = false;
|
|
106
105
|
/**
|
|
107
|
-
* Warns once per process about experimental skills
|
|
106
|
+
* Warns once per process about experimental skills support.
|
|
108
107
|
* Uses module-level state to prevent duplicate warnings within the same process.
|
|
109
108
|
*/
|
|
110
|
-
function
|
|
109
|
+
function warnOnceExperimental(verbose, dryRun) {
|
|
111
110
|
if (hasWarnedExperimental) {
|
|
112
111
|
return;
|
|
113
112
|
}
|
|
114
113
|
hasWarnedExperimental = true;
|
|
115
114
|
(0, constants_1.logWarn)('Skills support is experimental and behavior may change in future releases.', dryRun);
|
|
116
|
-
(0, constants_1.logWarn)('Skills MCP server (Skillz) requires uv. Install: https://github.com/astral-sh/uv', dryRun);
|
|
117
115
|
}
|
|
118
116
|
/**
|
|
119
117
|
* Cleans up skills directories when skills are disabled.
|
|
@@ -129,7 +127,7 @@ async function cleanupSkillsDirectories(projectRoot, dryRun, verbose) {
|
|
|
129
127
|
const rooSkillsPath = path.join(projectRoot, constants_1.ROO_SKILLS_PATH);
|
|
130
128
|
const geminiSkillsPath = path.join(projectRoot, constants_1.GEMINI_SKILLS_PATH);
|
|
131
129
|
const cursorSkillsPath = path.join(projectRoot, constants_1.CURSOR_SKILLS_PATH);
|
|
132
|
-
const
|
|
130
|
+
const antigravitySkillsPath = path.join(projectRoot, constants_1.ANTIGRAVITY_SKILLS_PATH);
|
|
133
131
|
// Clean up .claude/skills
|
|
134
132
|
try {
|
|
135
133
|
await fs.access(claudeSkillsPath);
|
|
@@ -256,15 +254,15 @@ async function cleanupSkillsDirectories(projectRoot, dryRun, verbose) {
|
|
|
256
254
|
catch {
|
|
257
255
|
// Directory doesn't exist, nothing to clean
|
|
258
256
|
}
|
|
259
|
-
// Clean up .
|
|
257
|
+
// Clean up .agent/skills
|
|
260
258
|
try {
|
|
261
|
-
await fs.access(
|
|
259
|
+
await fs.access(antigravitySkillsPath);
|
|
262
260
|
if (dryRun) {
|
|
263
|
-
(0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.
|
|
261
|
+
(0, constants_1.logVerboseInfo)(`DRY RUN: Would remove ${constants_1.ANTIGRAVITY_SKILLS_PATH}`, verbose, dryRun);
|
|
264
262
|
}
|
|
265
263
|
else {
|
|
266
|
-
await fs.rm(
|
|
267
|
-
(0, constants_1.logVerboseInfo)(`Removed ${constants_1.
|
|
264
|
+
await fs.rm(antigravitySkillsPath, { recursive: true, force: true });
|
|
265
|
+
(0, constants_1.logVerboseInfo)(`Removed ${constants_1.ANTIGRAVITY_SKILLS_PATH} (skills disabled)`, verbose, dryRun);
|
|
268
266
|
}
|
|
269
267
|
}
|
|
270
268
|
catch {
|
|
@@ -301,17 +299,20 @@ async function propagateSkills(projectRoot, agents, skillsEnabled, verbose, dryR
|
|
|
301
299
|
return;
|
|
302
300
|
}
|
|
303
301
|
(0, constants_1.logVerboseInfo)(`Discovered ${skills.length} skill(s)`, verbose, dryRun);
|
|
304
|
-
// Check if any agents need skills
|
|
305
302
|
const hasNativeSkillsAgent = agents.some((a) => a.supportsNativeSkills?.());
|
|
306
|
-
const
|
|
307
|
-
if (
|
|
308
|
-
|
|
303
|
+
const nonNativeAgents = agents.filter((agent) => !agent.supportsNativeSkills?.());
|
|
304
|
+
if (nonNativeAgents.length > 0) {
|
|
305
|
+
const agentList = nonNativeAgents
|
|
306
|
+
.map((agent) => agent.getName())
|
|
307
|
+
.join(', ');
|
|
308
|
+
(0, constants_1.logWarn)(`Skills are configured, but the following agents do not support native skills and will be skipped: ${agentList}`, dryRun);
|
|
309
|
+
}
|
|
310
|
+
if (!hasNativeSkillsAgent) {
|
|
311
|
+
(0, constants_1.logVerboseInfo)('No agents support native skills, skipping skills propagation', verbose, dryRun);
|
|
309
312
|
return;
|
|
310
313
|
}
|
|
311
314
|
// Warn about experimental features
|
|
312
|
-
|
|
313
|
-
warnOnceExperimentalAndUv(verbose, dryRun);
|
|
314
|
-
}
|
|
315
|
+
warnOnceExperimental(verbose, dryRun);
|
|
315
316
|
// Copy to Claude skills directory if needed
|
|
316
317
|
if (hasNativeSkillsAgent) {
|
|
317
318
|
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.CLAUDE_SKILLS_PATH} for Claude Code, GitHub Copilot, and Kilo Code`, verbose, dryRun);
|
|
@@ -332,12 +333,10 @@ async function propagateSkills(projectRoot, agents, skillsEnabled, verbose, dryR
|
|
|
332
333
|
await propagateSkillsForGemini(projectRoot, { dryRun });
|
|
333
334
|
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.CURSOR_SKILLS_PATH} for Cursor`, verbose, dryRun);
|
|
334
335
|
await propagateSkillsForCursor(projectRoot, { dryRun });
|
|
336
|
+
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.ANTIGRAVITY_SKILLS_PATH} for Antigravity`, verbose, dryRun);
|
|
337
|
+
await propagateSkillsForAntigravity(projectRoot, { dryRun });
|
|
335
338
|
}
|
|
336
|
-
//
|
|
337
|
-
if (hasMcpAgent) {
|
|
338
|
-
(0, constants_1.logVerboseInfo)(`Copying skills to ${constants_1.SKILLZ_DIR} for MCP agents`, verbose, dryRun);
|
|
339
|
-
await propagateSkillsForSkillz(projectRoot, { dryRun });
|
|
340
|
-
}
|
|
339
|
+
// No MCP-based propagation; only native skills are supported.
|
|
341
340
|
}
|
|
342
341
|
/**
|
|
343
342
|
* Propagates skills for Claude Code by copying .ruler/skills to .claude/skills.
|
|
@@ -790,13 +789,14 @@ async function propagateSkillsForCursor(projectRoot, options) {
|
|
|
790
789
|
return [];
|
|
791
790
|
}
|
|
792
791
|
/**
|
|
793
|
-
* Propagates skills for
|
|
792
|
+
* Propagates skills for Antigravity by copying .ruler/skills to .agent/skills.
|
|
794
793
|
* Uses atomic replace to ensure safe overwriting of existing skills.
|
|
795
794
|
* Returns dry-run steps if dryRun is true, otherwise returns empty array.
|
|
796
795
|
*/
|
|
797
|
-
async function
|
|
796
|
+
async function propagateSkillsForAntigravity(projectRoot, options) {
|
|
798
797
|
const skillsDir = path.join(projectRoot, constants_1.RULER_SKILLS_PATH);
|
|
799
|
-
const
|
|
798
|
+
const antigravitySkillsPath = path.join(projectRoot, constants_1.ANTIGRAVITY_SKILLS_PATH);
|
|
799
|
+
const antigravityDir = path.dirname(antigravitySkillsPath);
|
|
800
800
|
// Check if source skills directory exists
|
|
801
801
|
try {
|
|
802
802
|
await fs.access(skillsDir);
|
|
@@ -807,25 +807,26 @@ async function propagateSkillsForSkillz(projectRoot, options) {
|
|
|
807
807
|
}
|
|
808
808
|
if (options.dryRun) {
|
|
809
809
|
return [
|
|
810
|
-
`Copy skills from ${constants_1.RULER_SKILLS_PATH} to ${constants_1.
|
|
811
|
-
`Configure Skillz MCP server with absolute path to ${constants_1.SKILLZ_DIR}`,
|
|
810
|
+
`Copy skills from ${constants_1.RULER_SKILLS_PATH} to ${constants_1.ANTIGRAVITY_SKILLS_PATH}`,
|
|
812
811
|
];
|
|
813
812
|
}
|
|
813
|
+
// Ensure .agent directory exists
|
|
814
|
+
await fs.mkdir(antigravityDir, { recursive: true });
|
|
814
815
|
// Use atomic replace: copy to temp, then rename
|
|
815
|
-
const tempDir = path.join(
|
|
816
|
+
const tempDir = path.join(antigravityDir, `skills.tmp-${Date.now()}`);
|
|
816
817
|
try {
|
|
817
818
|
// Copy to temp directory
|
|
818
819
|
await (0, SkillsUtils_1.copySkillsDirectory)(skillsDir, tempDir);
|
|
819
820
|
// Atomically replace the target
|
|
820
821
|
// First, remove existing target if it exists
|
|
821
822
|
try {
|
|
822
|
-
await fs.rm(
|
|
823
|
+
await fs.rm(antigravitySkillsPath, { recursive: true, force: true });
|
|
823
824
|
}
|
|
824
825
|
catch {
|
|
825
826
|
// Target didn't exist, that's fine
|
|
826
827
|
}
|
|
827
828
|
// Rename temp to target
|
|
828
|
-
await fs.rename(tempDir,
|
|
829
|
+
await fs.rename(tempDir, antigravitySkillsPath);
|
|
829
830
|
}
|
|
830
831
|
catch (error) {
|
|
831
832
|
// Clean up temp directory on error
|
|
@@ -839,15 +840,3 @@ async function propagateSkillsForSkillz(projectRoot, options) {
|
|
|
839
840
|
}
|
|
840
841
|
return [];
|
|
841
842
|
}
|
|
842
|
-
/**
|
|
843
|
-
* Builds MCP config for Skillz server.
|
|
844
|
-
*/
|
|
845
|
-
function buildSkillzMcpConfig(projectRoot) {
|
|
846
|
-
const skillzAbsPath = path.resolve(projectRoot, constants_1.SKILLZ_DIR);
|
|
847
|
-
return {
|
|
848
|
-
[constants_1.SKILLZ_MCP_SERVER_NAME]: {
|
|
849
|
-
command: 'uvx',
|
|
850
|
-
args: ['skillz@latest', skillzAbsPath],
|
|
851
|
-
},
|
|
852
|
-
};
|
|
853
|
-
}
|
|
@@ -233,12 +233,12 @@ async function loadSingleConfiguration(projectRoot, configPath, localOnly) {
|
|
|
233
233
|
* @param cliMcpStrategy MCP strategy from CLI
|
|
234
234
|
* @returns Promise resolving to array of generated file paths
|
|
235
235
|
*/
|
|
236
|
-
async function processHierarchicalConfigurations(agents, configurations, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup = true
|
|
236
|
+
async function processHierarchicalConfigurations(agents, configurations, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup = true) {
|
|
237
237
|
const allGeneratedPaths = [];
|
|
238
238
|
for (const config of configurations) {
|
|
239
239
|
(0, constants_1.logVerboseInfo)(`Processing .ruler directory: ${config.rulerDir}`, verbose, dryRun);
|
|
240
240
|
const rulerRoot = path.dirname(config.rulerDir);
|
|
241
|
-
const paths = await applyConfigurationsToAgents(agents, config.concatenatedRules, config.rulerMcpJson, config.config, rulerRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup
|
|
241
|
+
const paths = await applyConfigurationsToAgents(agents, config.concatenatedRules, config.rulerMcpJson, config.config, rulerRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
|
|
242
242
|
const normalizedPaths = paths.map((p) => path.isAbsolute(p) ? p : path.join(rulerRoot, p));
|
|
243
243
|
allGeneratedPaths.push(...normalizedPaths);
|
|
244
244
|
}
|
|
@@ -256,43 +256,8 @@ async function processHierarchicalConfigurations(agents, configurations, verbose
|
|
|
256
256
|
* @param cliMcpStrategy MCP strategy from CLI
|
|
257
257
|
* @returns Promise resolving to array of generated file paths
|
|
258
258
|
*/
|
|
259
|
-
async function processSingleConfiguration(agents, configuration, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup = true
|
|
260
|
-
return await applyConfigurationsToAgents(agents, configuration.concatenatedRules, configuration.rulerMcpJson, configuration.config, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Adds Skillz MCP server to rulerMcpJson if skills exist and any agent needs it.
|
|
264
|
-
* Returns augmented MCP config or original if no changes needed.
|
|
265
|
-
*/
|
|
266
|
-
async function addSkillzMcpServerIfNeeded(rulerMcpJson, projectRoot, agents, verbose) {
|
|
267
|
-
// Check if any agent supports MCP stdio but not native skills
|
|
268
|
-
const hasAgentNeedingSkillz = agents.some((agent) => agent.supportsMcpStdio?.() && !agent.supportsNativeSkills?.());
|
|
269
|
-
if (!hasAgentNeedingSkillz) {
|
|
270
|
-
return rulerMcpJson;
|
|
271
|
-
}
|
|
272
|
-
// Check if .skillz directory exists
|
|
273
|
-
try {
|
|
274
|
-
const { SKILLZ_DIR } = await Promise.resolve().then(() => __importStar(require('../constants')));
|
|
275
|
-
const skillzPath = path.join(projectRoot, SKILLZ_DIR);
|
|
276
|
-
await fs_1.promises.access(skillzPath);
|
|
277
|
-
// Skills exist, add Skillz MCP server
|
|
278
|
-
const { buildSkillzMcpConfig } = await Promise.resolve().then(() => __importStar(require('./SkillsProcessor')));
|
|
279
|
-
const skillzMcp = buildSkillzMcpConfig(projectRoot);
|
|
280
|
-
// Initialize empty config if null
|
|
281
|
-
const baseConfig = rulerMcpJson || { mcpServers: {} };
|
|
282
|
-
const mcpServers = baseConfig.mcpServers || {};
|
|
283
|
-
(0, constants_1.logVerbose)('Adding Skillz MCP server to configuration for agents that need it', verbose);
|
|
284
|
-
return {
|
|
285
|
-
...baseConfig,
|
|
286
|
-
mcpServers: {
|
|
287
|
-
...mcpServers,
|
|
288
|
-
...skillzMcp,
|
|
289
|
-
},
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
catch {
|
|
293
|
-
// No .skillz directory, return original config
|
|
294
|
-
return rulerMcpJson;
|
|
295
|
-
}
|
|
259
|
+
async function processSingleConfiguration(agents, configuration, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup = true) {
|
|
260
|
+
return await applyConfigurationsToAgents(agents, configuration.concatenatedRules, configuration.rulerMcpJson, configuration.config, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
|
|
296
261
|
}
|
|
297
262
|
/**
|
|
298
263
|
* Applies configurations to the selected agents (internal function).
|
|
@@ -305,20 +270,14 @@ async function addSkillzMcpServerIfNeeded(rulerMcpJson, projectRoot, agents, ver
|
|
|
305
270
|
* @param dryRun Whether to perform a dry run
|
|
306
271
|
* @returns Promise resolving to array of generated file paths
|
|
307
272
|
*/
|
|
308
|
-
async function applyConfigurationsToAgents(agents, concatenatedRules, rulerMcpJson, config, projectRoot, verbose, dryRun, cliMcpEnabled = true, cliMcpStrategy, backup = true
|
|
273
|
+
async function applyConfigurationsToAgents(agents, concatenatedRules, rulerMcpJson, config, projectRoot, verbose, dryRun, cliMcpEnabled = true, cliMcpStrategy, backup = true) {
|
|
309
274
|
const generatedPaths = [];
|
|
310
275
|
let agentsMdWritten = false;
|
|
311
|
-
// Add Skillz MCP server to rulerMcpJson if skills are enabled
|
|
312
|
-
// This must happen before calling agent.applyRulerConfig() so that agents
|
|
313
|
-
// that handle MCP internally (e.g. Codex, Gemini) receive the Skillz server
|
|
314
|
-
let augmentedRulerMcpJson = rulerMcpJson;
|
|
315
|
-
if (skillsEnabled && !dryRun) {
|
|
316
|
-
augmentedRulerMcpJson = await addSkillzMcpServerIfNeeded(rulerMcpJson, projectRoot, agents, verbose);
|
|
317
|
-
}
|
|
318
276
|
for (const agent of agents) {
|
|
319
277
|
(0, constants_1.logInfo)(`Applying rules for ${agent.getName()}...`, dryRun);
|
|
320
278
|
(0, constants_1.logVerbose)(`Processing agent: ${agent.getName()}`, verbose);
|
|
321
279
|
const agentConfig = config.agentConfigs[agent.getIdentifier()];
|
|
280
|
+
const agentRulerMcpJson = rulerMcpJson;
|
|
322
281
|
// Collect output paths for .gitignore
|
|
323
282
|
const outputPaths = (0, agent_utils_1.getAgentOutputPaths)(agent, projectRoot, agentConfig);
|
|
324
283
|
(0, constants_1.logVerbose)(`Agent ${agent.getName()} output paths: ${outputPaths.join(', ')}`, verbose);
|
|
@@ -344,7 +303,7 @@ async function applyConfigurationsToAgents(agents, concatenatedRules, rulerMcpJs
|
|
|
344
303
|
}
|
|
345
304
|
}
|
|
346
305
|
let finalAgentConfig = agentConfig;
|
|
347
|
-
if (agent.getIdentifier() === 'augmentcode' &&
|
|
306
|
+
if (agent.getIdentifier() === 'augmentcode' && agentRulerMcpJson) {
|
|
348
307
|
const resolvedStrategy = cliMcpStrategy ??
|
|
349
308
|
agentConfig?.mcp?.strategy ??
|
|
350
309
|
config.mcp?.strategy ??
|
|
@@ -358,15 +317,15 @@ async function applyConfigurationsToAgents(agents, concatenatedRules, rulerMcpJs
|
|
|
358
317
|
};
|
|
359
318
|
}
|
|
360
319
|
if (!skipApplyForThisAgent) {
|
|
361
|
-
await agent.applyRulerConfig(concatenatedRules, projectRoot,
|
|
320
|
+
await agent.applyRulerConfig(concatenatedRules, projectRoot, agentRulerMcpJson, finalAgentConfig, backup);
|
|
362
321
|
}
|
|
363
322
|
}
|
|
364
323
|
// Handle MCP configuration
|
|
365
|
-
await handleMcpConfiguration(agent, agentConfig, config,
|
|
324
|
+
await handleMcpConfiguration(agent, agentConfig, config, agentRulerMcpJson, projectRoot, generatedPaths, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
|
|
366
325
|
}
|
|
367
326
|
return generatedPaths;
|
|
368
327
|
}
|
|
369
|
-
async function handleMcpConfiguration(agent, agentConfig, config, rulerMcpJson, projectRoot, generatedPaths, verbose, dryRun, cliMcpEnabled = true, cliMcpStrategy, backup = true
|
|
328
|
+
async function handleMcpConfiguration(agent, agentConfig, config, rulerMcpJson, projectRoot, generatedPaths, verbose, dryRun, cliMcpEnabled = true, cliMcpStrategy, backup = true) {
|
|
370
329
|
if (!(0, capabilities_1.agentSupportsMcp)(agent)) {
|
|
371
330
|
(0, constants_1.logVerbose)(`Agent ${agent.getName()} does not support MCP - skipping MCP configuration`, verbose);
|
|
372
331
|
return;
|
|
@@ -376,41 +335,9 @@ async function handleMcpConfiguration(agent, agentConfig, config, rulerMcpJson,
|
|
|
376
335
|
if (!dest || !mcpEnabledForAgent) {
|
|
377
336
|
return;
|
|
378
337
|
}
|
|
379
|
-
|
|
338
|
+
const filteredMcpJson = rulerMcpJson
|
|
380
339
|
? (0, capabilities_1.filterMcpConfigForAgent)(rulerMcpJson, agent)
|
|
381
340
|
: null;
|
|
382
|
-
// Add Skillz MCP server for agents that support stdio but not native skills
|
|
383
|
-
// Only add if skills are enabled
|
|
384
|
-
if (skillsEnabled &&
|
|
385
|
-
agent.supportsMcpStdio?.() &&
|
|
386
|
-
!agent.supportsNativeSkills?.()) {
|
|
387
|
-
// Check if .skillz directory exists
|
|
388
|
-
try {
|
|
389
|
-
const { SKILLZ_DIR } = await Promise.resolve().then(() => __importStar(require('../constants')));
|
|
390
|
-
const skillzPath = path.join(projectRoot, SKILLZ_DIR);
|
|
391
|
-
await fs_1.promises.access(skillzPath);
|
|
392
|
-
// Skills exist, add Skillz MCP server
|
|
393
|
-
const { buildSkillzMcpConfig } = await Promise.resolve().then(() => __importStar(require('./SkillsProcessor')));
|
|
394
|
-
const skillzMcp = buildSkillzMcpConfig(projectRoot);
|
|
395
|
-
// Merge Skillz server into MCP config
|
|
396
|
-
// Initialize empty config if null
|
|
397
|
-
if (!filteredMcpJson) {
|
|
398
|
-
filteredMcpJson = { mcpServers: {} };
|
|
399
|
-
}
|
|
400
|
-
const mcpServers = filteredMcpJson.mcpServers || {};
|
|
401
|
-
filteredMcpJson = {
|
|
402
|
-
...filteredMcpJson,
|
|
403
|
-
mcpServers: {
|
|
404
|
-
...mcpServers,
|
|
405
|
-
...skillzMcp,
|
|
406
|
-
},
|
|
407
|
-
};
|
|
408
|
-
(0, constants_1.logVerboseInfo)(`Added Skillz MCP server for ${agent.getName()}`, verbose, dryRun);
|
|
409
|
-
}
|
|
410
|
-
catch {
|
|
411
|
-
// No .skillz directory, skip adding Skillz server
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
341
|
if (!filteredMcpJson) {
|
|
415
342
|
(0, constants_1.logVerbose)(`No compatible MCP servers found for ${agent.getName()} - skipping MCP configuration`, verbose);
|
|
416
343
|
return;
|
package/dist/lib.js
CHANGED
|
@@ -100,7 +100,7 @@ async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cli
|
|
|
100
100
|
await propagateSkills(nestedRoot, selectedAgents, skillsEnabledResolved, verbose, dryRun);
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
-
generatedPaths = await (0, apply_engine_1.processHierarchicalConfigurations)(selectedAgents, hierarchicalConfigs, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup
|
|
103
|
+
generatedPaths = await (0, apply_engine_1.processHierarchicalConfigurations)(selectedAgents, hierarchicalConfigs, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
|
|
104
104
|
}
|
|
105
105
|
else {
|
|
106
106
|
const singleConfig = await (0, apply_engine_1.loadSingleConfiguration)(projectRoot, configPath, localOnly);
|
|
@@ -117,7 +117,7 @@ async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cli
|
|
|
117
117
|
const { propagateSkills } = await Promise.resolve().then(() => __importStar(require('./core/SkillsProcessor')));
|
|
118
118
|
await propagateSkills(projectRoot, selectedAgents, skillsEnabledResolved, verbose, dryRun);
|
|
119
119
|
}
|
|
120
|
-
generatedPaths = await (0, apply_engine_1.processSingleConfiguration)(selectedAgents, singleConfig, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup
|
|
120
|
+
generatedPaths = await (0, apply_engine_1.processSingleConfiguration)(selectedAgents, singleConfig, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
|
|
121
121
|
}
|
|
122
122
|
// Add skills-generated paths to gitignore if skills are enabled
|
|
123
123
|
let allGeneratedPaths = generatedPaths;
|