@intellectronica/ruler 0.3.33 → 0.3.35
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 +9 -6
- package/dist/cli/commands.js +4 -0
- package/dist/cli/handlers.js +12 -1
- package/dist/constants.js +1 -1
- package/dist/core/ConfigLoader.js +4 -0
- package/dist/core/GitignoreUtils.js +7 -5
- package/dist/core/SkillsProcessor.js +2 -2
- package/dist/core/apply-engine.js +12 -4
- package/dist/lib.js +2 -2
- 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/` |
|
|
@@ -238,6 +238,7 @@ The `apply` command looks for `.ruler/` in the current directory tree, reading t
|
|
|
238
238
|
| `--mcp-overwrite` | Overwrite native MCP config instead of merging. |
|
|
239
239
|
| `--gitignore` | Enable automatic .gitignore updates (default: true). |
|
|
240
240
|
| `--no-gitignore` | Disable automatic .gitignore updates. |
|
|
241
|
+
| `--gitignore-local` | Write managed ignore entries to `.git/info/exclude` instead. |
|
|
241
242
|
| `--nested` | Enable nested rule loading (default: inherit from config or disabled). |
|
|
242
243
|
| `--no-nested` | Disable nested rule loading even if `nested = true` in config. |
|
|
243
244
|
| `--backup` | Toggle creation of `.bak` backup files (default: enabled). |
|
|
@@ -405,6 +406,8 @@ Authorization = "Bearer your-token"
|
|
|
405
406
|
[gitignore]
|
|
406
407
|
# Enable/disable automatic .gitignore updates (default: true)
|
|
407
408
|
enabled = true
|
|
409
|
+
# Write managed entries to .git/info/exclude instead of .gitignore (default: false)
|
|
410
|
+
local = false
|
|
408
411
|
|
|
409
412
|
# --- Agent-Specific Configurations ---
|
|
410
413
|
[agents.copilot]
|
|
@@ -578,7 +581,7 @@ Skills are specialized knowledge packages that extend AI agent capabilities with
|
|
|
578
581
|
- **GitHub Copilot**: `.claude/skills/` (shared with Claude Code)
|
|
579
582
|
- **Kilo Code**: `.claude/skills/` (shared with Claude Code)
|
|
580
583
|
- **OpenAI Codex CLI**: `.codex/skills/`
|
|
581
|
-
- **OpenCode**: `.opencode/
|
|
584
|
+
- **OpenCode**: `.opencode/skills/`
|
|
582
585
|
- **Pi Coding Agent**: `.pi/skills/`
|
|
583
586
|
- **Goose**: `.agents/skills/`
|
|
584
587
|
- **Amp**: `.agents/skills/` (shared with Goose)
|
|
@@ -644,7 +647,7 @@ When skills support is enabled and gitignore integration is active, Ruler automa
|
|
|
644
647
|
|
|
645
648
|
- `.claude/skills/` (for Claude Code, GitHub Copilot, and Kilo Code)
|
|
646
649
|
- `.codex/skills/` (for OpenAI Codex CLI)
|
|
647
|
-
- `.opencode/
|
|
650
|
+
- `.opencode/skills/` (for OpenCode)
|
|
648
651
|
- `.pi/skills/` (for Pi Coding Agent)
|
|
649
652
|
- `.agents/skills/` (for Goose and Amp)
|
|
650
653
|
- `.agent/skills/` (for Antigravity)
|
|
@@ -703,7 +706,7 @@ ruler apply
|
|
|
703
706
|
# 3. Skills are now available to compatible agents:
|
|
704
707
|
# - Claude Code, GitHub Copilot & Kilo Code: .claude/skills/my-skill/
|
|
705
708
|
# - OpenAI Codex CLI: .codex/skills/my-skill/
|
|
706
|
-
# - OpenCode: .opencode/
|
|
709
|
+
# - OpenCode: .opencode/skills/my-skill/
|
|
707
710
|
# - Pi Coding Agent: .pi/skills/my-skill/
|
|
708
711
|
# - Goose & Amp: .agents/skills/my-skill/
|
|
709
712
|
# - Antigravity: .agent/skills/my-skill/
|
|
@@ -744,8 +747,8 @@ dist/
|
|
|
744
747
|
|
|
745
748
|
### Control Options
|
|
746
749
|
|
|
747
|
-
- **CLI flags**: `--gitignore
|
|
748
|
-
- **Configuration**: `[gitignore].enabled` in `ruler.toml`
|
|
750
|
+
- **CLI flags**: `--gitignore`, `--no-gitignore`, `--gitignore-local`, `--no-gitignore-local`
|
|
751
|
+
- **Configuration**: `[gitignore].enabled` and `[gitignore].local` in `ruler.toml`
|
|
749
752
|
- **Default**: enabled
|
|
750
753
|
|
|
751
754
|
## Practical Usage Scenarios
|
package/dist/cli/commands.js
CHANGED
|
@@ -44,6 +44,10 @@ function run() {
|
|
|
44
44
|
.option('gitignore', {
|
|
45
45
|
type: 'boolean',
|
|
46
46
|
description: 'Enable/disable automatic .gitignore updates (default: enabled)',
|
|
47
|
+
})
|
|
48
|
+
.option('gitignore-local', {
|
|
49
|
+
type: 'boolean',
|
|
50
|
+
description: 'Write generated ignore entries to .git/info/exclude instead of .gitignore',
|
|
47
51
|
})
|
|
48
52
|
.option('verbose', {
|
|
49
53
|
type: 'boolean',
|
package/dist/cli/handlers.js
CHANGED
|
@@ -78,6 +78,13 @@ async function applyHandler(argv) {
|
|
|
78
78
|
else {
|
|
79
79
|
gitignorePreference = undefined; // Let TOML/default decide
|
|
80
80
|
}
|
|
81
|
+
let gitignoreLocalPreference;
|
|
82
|
+
if (argv['gitignore-local'] !== undefined) {
|
|
83
|
+
gitignoreLocalPreference = argv['gitignore-local'];
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
gitignoreLocalPreference = undefined; // Let TOML/default decide
|
|
87
|
+
}
|
|
81
88
|
// Determine nested preference: CLI > TOML > Default (false)
|
|
82
89
|
let nested;
|
|
83
90
|
if (argv.nested !== undefined) {
|
|
@@ -108,7 +115,7 @@ async function applyHandler(argv) {
|
|
|
108
115
|
skillsEnabled = undefined; // Let config/default decide
|
|
109
116
|
}
|
|
110
117
|
try {
|
|
111
|
-
await (0, lib_1.applyAllAgentConfigs)(projectRoot, agents, configPath, mcpEnabled, mcpStrategy, gitignorePreference, verbose, dryRun, localOnly, nested, backup, skillsEnabled);
|
|
118
|
+
await (0, lib_1.applyAllAgentConfigs)(projectRoot, agents, configPath, mcpEnabled, mcpStrategy, gitignorePreference, verbose, dryRun, localOnly, nested, backup, skillsEnabled, gitignoreLocalPreference);
|
|
112
119
|
console.log('Ruler apply completed successfully.');
|
|
113
120
|
}
|
|
114
121
|
catch (err) {
|
|
@@ -150,6 +157,10 @@ async function initHandler(argv) {
|
|
|
150
157
|
# When enabled, ruler will search for and process .ruler directories throughout the project hierarchy
|
|
151
158
|
# nested = false
|
|
152
159
|
|
|
160
|
+
# [gitignore]
|
|
161
|
+
# enabled = true
|
|
162
|
+
# local = false # set true to write generated ignores to .git/info/exclude instead
|
|
163
|
+
|
|
153
164
|
# --- Agent Specific Configurations ---
|
|
154
165
|
# You can enable/disable agents and override their default output paths here.
|
|
155
166
|
# Use lowercase agent identifiers: aider, amp, claude, cline, codex, copilot, cursor, jetbrains-ai, kilocode, pi, windsurf
|
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';
|
|
@@ -67,6 +67,7 @@ const rulerConfigSchema = zod_1.z.object({
|
|
|
67
67
|
gitignore: zod_1.z
|
|
68
68
|
.object({
|
|
69
69
|
enabled: zod_1.z.boolean().optional(),
|
|
70
|
+
local: zod_1.z.boolean().optional(),
|
|
70
71
|
})
|
|
71
72
|
.optional(),
|
|
72
73
|
skills: zod_1.z
|
|
@@ -203,6 +204,9 @@ async function loadConfig(options) {
|
|
|
203
204
|
if (typeof rawGitignoreSection.enabled === 'boolean') {
|
|
204
205
|
gitignoreConfig.enabled = rawGitignoreSection.enabled;
|
|
205
206
|
}
|
|
207
|
+
if (typeof rawGitignoreSection.local === 'boolean') {
|
|
208
|
+
gitignoreConfig.local = rawGitignoreSection.local;
|
|
209
|
+
}
|
|
206
210
|
const rawSkillsSection = raw.skills && typeof raw.skills === 'object' && !Array.isArray(raw.skills)
|
|
207
211
|
? raw.skills
|
|
208
212
|
: {};
|
|
@@ -39,14 +39,15 @@ const path = __importStar(require("path"));
|
|
|
39
39
|
const RULER_START_MARKER = '# START Ruler Generated Files';
|
|
40
40
|
const RULER_END_MARKER = '# END Ruler Generated Files';
|
|
41
41
|
/**
|
|
42
|
-
* Updates
|
|
42
|
+
* Updates an ignore file in the project root with paths in a managed Ruler block.
|
|
43
43
|
* Creates the file if it doesn't exist, and creates or updates the Ruler-managed block.
|
|
44
44
|
*
|
|
45
|
-
* @param projectRoot The project root directory
|
|
46
|
-
* @param paths Array of file paths to add to
|
|
45
|
+
* @param projectRoot The project root directory
|
|
46
|
+
* @param paths Array of file paths to add to the ignore file (can be absolute or relative)
|
|
47
|
+
* @param ignoreFile Relative path to the ignore file from project root (defaults to .gitignore)
|
|
47
48
|
*/
|
|
48
|
-
async function updateGitignore(projectRoot, paths) {
|
|
49
|
-
const gitignorePath = path.join(projectRoot,
|
|
49
|
+
async function updateGitignore(projectRoot, paths, ignoreFile = '.gitignore') {
|
|
50
|
+
const gitignorePath = path.join(projectRoot, ignoreFile);
|
|
50
51
|
// Read existing .gitignore or start with empty content
|
|
51
52
|
let existingContent = '';
|
|
52
53
|
try {
|
|
@@ -97,6 +98,7 @@ async function updateGitignore(projectRoot, paths) {
|
|
|
97
98
|
// Create new content
|
|
98
99
|
const newContent = updateGitignoreContent(existingContent, allRulerPaths);
|
|
99
100
|
// Write the updated content
|
|
101
|
+
await fs_1.promises.mkdir(path.dirname(gitignorePath), { recursive: true });
|
|
100
102
|
await fs_1.promises.writeFile(gitignorePath, newContent);
|
|
101
103
|
}
|
|
102
104
|
/**
|
|
@@ -186,7 +186,7 @@ async function cleanupSkillsDirectories(projectRoot, dryRun, verbose) {
|
|
|
186
186
|
catch {
|
|
187
187
|
// Directory doesn't exist, nothing to clean
|
|
188
188
|
}
|
|
189
|
-
// Clean up .opencode/
|
|
189
|
+
// Clean up .opencode/skills
|
|
190
190
|
try {
|
|
191
191
|
await fs.access(opencodeSkillsPath);
|
|
192
192
|
if (dryRun) {
|
|
@@ -510,7 +510,7 @@ async function propagateSkillsForCodex(projectRoot, options) {
|
|
|
510
510
|
return [];
|
|
511
511
|
}
|
|
512
512
|
/**
|
|
513
|
-
* Propagates skills for OpenCode by copying .ruler/skills to .opencode/
|
|
513
|
+
* Propagates skills for OpenCode by copying .ruler/skills to .opencode/skills.
|
|
514
514
|
* Uses atomic replace to ensure safe overwriting of existing skills.
|
|
515
515
|
* Returns dry-run steps if dryRun is true, otherwise returns empty array.
|
|
516
516
|
*/
|
|
@@ -644,8 +644,9 @@ async function applyStandardMcpConfiguration(agent, filteredMcpJson, dest, agent
|
|
|
644
644
|
* @param config Loaded configuration
|
|
645
645
|
* @param cliGitignoreEnabled CLI gitignore setting
|
|
646
646
|
* @param dryRun Whether to perform a dry run
|
|
647
|
+
* @param cliGitignoreLocal CLI toggle for .git/info/exclude usage
|
|
647
648
|
*/
|
|
648
|
-
async function updateGitignore(projectRoot, generatedPaths, config, cliGitignoreEnabled, dryRun) {
|
|
649
|
+
async function updateGitignore(projectRoot, generatedPaths, config, cliGitignoreEnabled, dryRun, cliGitignoreLocal) {
|
|
649
650
|
// Configuration precedence: CLI > TOML > Default (enabled)
|
|
650
651
|
let gitignoreEnabled;
|
|
651
652
|
if (cliGitignoreEnabled !== undefined) {
|
|
@@ -657,17 +658,24 @@ async function updateGitignore(projectRoot, generatedPaths, config, cliGitignore
|
|
|
657
658
|
else {
|
|
658
659
|
gitignoreEnabled = true; // Default enabled
|
|
659
660
|
}
|
|
661
|
+
const gitignoreTarget = cliGitignoreLocal !== undefined
|
|
662
|
+
? cliGitignoreLocal
|
|
663
|
+
? '.git/info/exclude'
|
|
664
|
+
: '.gitignore'
|
|
665
|
+
: config.gitignore?.local
|
|
666
|
+
? '.git/info/exclude'
|
|
667
|
+
: '.gitignore';
|
|
660
668
|
if (gitignoreEnabled && generatedPaths.length > 0) {
|
|
661
669
|
const uniquePaths = [...new Set(generatedPaths)];
|
|
662
670
|
// Note: Individual backup patterns are added per-file in the collection phase
|
|
663
671
|
// No need to add a broad *.bak pattern here
|
|
664
672
|
if (uniquePaths.length > 0) {
|
|
665
673
|
if (dryRun) {
|
|
666
|
-
(0, constants_1.logInfo)(`Would update
|
|
674
|
+
(0, constants_1.logInfo)(`Would update ${gitignoreTarget} with ${uniquePaths.length} unique path(s): ${uniquePaths.join(', ')}`, dryRun);
|
|
667
675
|
}
|
|
668
676
|
else {
|
|
669
|
-
await (0, GitignoreUtils_1.updateGitignore)(projectRoot, uniquePaths);
|
|
670
|
-
(0, constants_1.logInfo)(`Updated
|
|
677
|
+
await (0, GitignoreUtils_1.updateGitignore)(projectRoot, uniquePaths, gitignoreTarget);
|
|
678
|
+
(0, constants_1.logInfo)(`Updated ${gitignoreTarget} with ${uniquePaths.length} unique path(s) in the Ruler block.`, dryRun);
|
|
671
679
|
}
|
|
672
680
|
}
|
|
673
681
|
}
|
package/dist/lib.js
CHANGED
|
@@ -62,7 +62,7 @@ function resolveSkillsEnabled(cliFlag, configSetting) {
|
|
|
62
62
|
* @param projectRoot Root directory of the project
|
|
63
63
|
* @param includedAgents Optional list of agent name filters (case-insensitive substrings)
|
|
64
64
|
*/
|
|
65
|
-
async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cliMcpEnabled = true, cliMcpStrategy, cliGitignoreEnabled, verbose = false, dryRun = false, localOnly = false, nested = false, backup = true, skillsEnabled) {
|
|
65
|
+
async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cliMcpEnabled = true, cliMcpStrategy, cliGitignoreEnabled, verbose = false, dryRun = false, localOnly = false, nested = false, backup = true, skillsEnabled, cliGitignoreLocal) {
|
|
66
66
|
// Load configuration and rules
|
|
67
67
|
(0, constants_1.logVerbose)(`Loading configuration from project root: ${projectRoot}`, verbose);
|
|
68
68
|
if (configPath) {
|
|
@@ -128,7 +128,7 @@ async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cli
|
|
|
128
128
|
const skillsPaths = await getSkillsGitignorePaths(projectRoot, selectedAgents);
|
|
129
129
|
allGeneratedPaths = [...generatedPaths, ...skillsPaths];
|
|
130
130
|
}
|
|
131
|
-
await (0, apply_engine_1.updateGitignore)(projectRoot, allGeneratedPaths, loadedConfig, cliGitignoreEnabled, dryRun);
|
|
131
|
+
await (0, apply_engine_1.updateGitignore)(projectRoot, allGeneratedPaths, loadedConfig, cliGitignoreEnabled, dryRun, cliGitignoreLocal);
|
|
132
132
|
}
|
|
133
133
|
/**
|
|
134
134
|
* Normalizes per-agent config keys to agent identifiers for consistent lookup.
|