@intellectronica/ruler 0.2.4 → 0.2.5
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 -0
- package/dist/agents/AiderAgent.js +2 -1
- package/dist/agents/ClaudeAgent.js +2 -1
- package/dist/agents/ClineAgent.js +2 -1
- package/dist/agents/CodexCliAgent.js +2 -1
- package/dist/agents/CopilotAgent.js +2 -1
- package/dist/agents/CursorAgent.js +2 -1
- package/dist/agents/FirebaseAgent.js +2 -1
- package/dist/agents/GeminiCliAgent.js +74 -0
- package/dist/agents/OpenHandsAgent.js +2 -1
- package/dist/agents/WindsurfAgent.js +2 -1
- package/dist/cli/commands.js +4 -1
- package/dist/lib.js +5 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -46,6 +46,7 @@ Ruler solves this by providing a **single source of truth** for all your AI agen
|
|
|
46
46
|
| Aider | `ruler_aider_instructions.md` and `.aider.conf.yml` |
|
|
47
47
|
| Firebase Studio | `.idx/airules.md` |
|
|
48
48
|
| Open Hands | `.openhands/microagents/repo.md` and `.openhands/config.toml` |
|
|
49
|
+
| Gemini CLI | `GEMINI.md` and `.gemini/settings.json` |
|
|
49
50
|
|
|
50
51
|
## Getting Started
|
|
51
52
|
|
|
@@ -222,6 +223,9 @@ output_path_config = ".aider.conf.yml"
|
|
|
222
223
|
enabled = true
|
|
223
224
|
output_path = ".idx/airules.md"
|
|
224
225
|
|
|
226
|
+
[agents.gemini-cli]
|
|
227
|
+
enabled = true
|
|
228
|
+
|
|
225
229
|
# Agent-specific MCP configuration
|
|
226
230
|
[agents.cursor.mcp]
|
|
227
231
|
enabled = true
|
|
@@ -48,7 +48,8 @@ class AiderAgent {
|
|
|
48
48
|
getName() {
|
|
49
49
|
return 'Aider';
|
|
50
50
|
}
|
|
51
|
-
async applyRulerConfig(concatenatedRules, projectRoot,
|
|
51
|
+
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
52
|
+
agentConfig) {
|
|
52
53
|
const mdPath = agentConfig?.outputPathInstructions ??
|
|
53
54
|
this.getDefaultOutputPath(projectRoot).instructions;
|
|
54
55
|
await (0, FileSystemUtils_1.backupFile)(mdPath);
|
|
@@ -46,7 +46,8 @@ class ClaudeAgent {
|
|
|
46
46
|
getName() {
|
|
47
47
|
return 'Claude Code';
|
|
48
48
|
}
|
|
49
|
-
async applyRulerConfig(concatenatedRules, projectRoot,
|
|
49
|
+
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
50
|
+
agentConfig) {
|
|
50
51
|
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
51
52
|
await (0, FileSystemUtils_1.backupFile)(output);
|
|
52
53
|
await (0, FileSystemUtils_1.writeGeneratedFile)(output, concatenatedRules);
|
|
@@ -46,7 +46,8 @@ class ClineAgent {
|
|
|
46
46
|
getName() {
|
|
47
47
|
return 'Cline';
|
|
48
48
|
}
|
|
49
|
-
async applyRulerConfig(concatenatedRules, projectRoot,
|
|
49
|
+
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
50
|
+
agentConfig) {
|
|
50
51
|
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
51
52
|
await (0, FileSystemUtils_1.backupFile)(output);
|
|
52
53
|
await (0, FileSystemUtils_1.writeGeneratedFile)(output, concatenatedRules);
|
|
@@ -46,7 +46,8 @@ class CodexCliAgent {
|
|
|
46
46
|
getName() {
|
|
47
47
|
return 'OpenAI Codex CLI';
|
|
48
48
|
}
|
|
49
|
-
async applyRulerConfig(concatenatedRules, projectRoot,
|
|
49
|
+
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
50
|
+
agentConfig) {
|
|
50
51
|
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
51
52
|
await (0, FileSystemUtils_1.backupFile)(output);
|
|
52
53
|
await (0, FileSystemUtils_1.writeGeneratedFile)(output, concatenatedRules);
|
|
@@ -46,7 +46,8 @@ class CopilotAgent {
|
|
|
46
46
|
getName() {
|
|
47
47
|
return 'GitHub Copilot';
|
|
48
48
|
}
|
|
49
|
-
async applyRulerConfig(concatenatedRules, projectRoot,
|
|
49
|
+
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
50
|
+
agentConfig) {
|
|
50
51
|
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
51
52
|
await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(output));
|
|
52
53
|
await (0, FileSystemUtils_1.backupFile)(output);
|
|
@@ -46,7 +46,8 @@ class CursorAgent {
|
|
|
46
46
|
getName() {
|
|
47
47
|
return 'Cursor';
|
|
48
48
|
}
|
|
49
|
-
async applyRulerConfig(concatenatedRules, projectRoot,
|
|
49
|
+
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
50
|
+
agentConfig) {
|
|
50
51
|
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
51
52
|
await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(output));
|
|
52
53
|
await (0, FileSystemUtils_1.backupFile)(output);
|
|
@@ -46,7 +46,8 @@ class FirebaseAgent {
|
|
|
46
46
|
getName() {
|
|
47
47
|
return 'Firebase Studio';
|
|
48
48
|
}
|
|
49
|
-
async applyRulerConfig(concatenatedRules, projectRoot,
|
|
49
|
+
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
50
|
+
agentConfig) {
|
|
50
51
|
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
51
52
|
await (0, FileSystemUtils_1.backupFile)(output);
|
|
52
53
|
await (0, FileSystemUtils_1.writeGeneratedFile)(output, concatenatedRules);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.GeminiCliAgent = void 0;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const fs_1 = require("fs");
|
|
39
|
+
const merge_1 = require("../mcp/merge");
|
|
40
|
+
class GeminiCliAgent {
|
|
41
|
+
getIdentifier() {
|
|
42
|
+
return 'gemini-cli';
|
|
43
|
+
}
|
|
44
|
+
getName() {
|
|
45
|
+
return 'Gemini CLI';
|
|
46
|
+
}
|
|
47
|
+
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, agentConfig) {
|
|
48
|
+
const outputPath = this.getDefaultOutputPath(projectRoot);
|
|
49
|
+
await fs_1.promises.writeFile(outputPath, concatenatedRules);
|
|
50
|
+
if (rulerMcpJson) {
|
|
51
|
+
const settingsPath = path.join(projectRoot, '.gemini', 'settings.json');
|
|
52
|
+
let existingSettings = {};
|
|
53
|
+
try {
|
|
54
|
+
const existingSettingsRaw = await fs_1.promises.readFile(settingsPath, 'utf8');
|
|
55
|
+
existingSettings = JSON.parse(existingSettingsRaw);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (error.code !== 'ENOENT') {
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const merged = (0, merge_1.mergeMcp)(existingSettings, rulerMcpJson, agentConfig?.mcp?.strategy ?? 'merge', this.getMcpServerKey());
|
|
63
|
+
await fs_1.promises.mkdir(path.dirname(settingsPath), { recursive: true });
|
|
64
|
+
await fs_1.promises.writeFile(settingsPath, JSON.stringify(merged, null, 2));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
getDefaultOutputPath(projectRoot) {
|
|
68
|
+
return path.join(projectRoot, 'GEMINI.md');
|
|
69
|
+
}
|
|
70
|
+
getMcpServerKey() {
|
|
71
|
+
return 'mcpServers';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.GeminiCliAgent = GeminiCliAgent;
|
|
@@ -43,7 +43,8 @@ class OpenHandsAgent {
|
|
|
43
43
|
getName() {
|
|
44
44
|
return 'Open Hands';
|
|
45
45
|
}
|
|
46
|
-
async applyRulerConfig(concatenatedRules, projectRoot,
|
|
46
|
+
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
47
|
+
agentConfig) {
|
|
47
48
|
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
48
49
|
await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(output));
|
|
49
50
|
await (0, FileSystemUtils_1.backupFile)(output);
|
|
@@ -46,7 +46,8 @@ class WindsurfAgent {
|
|
|
46
46
|
getName() {
|
|
47
47
|
return 'Windsurf';
|
|
48
48
|
}
|
|
49
|
-
async applyRulerConfig(concatenatedRules, projectRoot,
|
|
49
|
+
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
50
|
+
agentConfig) {
|
|
50
51
|
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
51
52
|
await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(output));
|
|
52
53
|
await (0, FileSystemUtils_1.backupFile)(output);
|
package/dist/cli/commands.js
CHANGED
|
@@ -58,7 +58,7 @@ function run() {
|
|
|
58
58
|
});
|
|
59
59
|
y.option('agents', {
|
|
60
60
|
type: 'string',
|
|
61
|
-
description: 'Comma-separated list of agent identifiers: copilot, claude, codex, cursor, windsurf, cline, aider, firebase',
|
|
61
|
+
description: 'Comma-separated list of agent identifiers: copilot, claude, codex, cursor, windsurf, cline, aider, firebase, gemini-cli',
|
|
62
62
|
});
|
|
63
63
|
y.option('config', {
|
|
64
64
|
type: 'string',
|
|
@@ -193,6 +193,9 @@ and apply them to your configured AI coding agents.
|
|
|
193
193
|
# [agents.firebase]
|
|
194
194
|
# enabled = true
|
|
195
195
|
# output_path = ".idx/airules.md"
|
|
196
|
+
|
|
197
|
+
# [agents.gemini-cli]
|
|
198
|
+
# enabled = true
|
|
196
199
|
`;
|
|
197
200
|
if (!(await exists(instructionsPath))) {
|
|
198
201
|
await fs_1.promises.writeFile(instructionsPath, DEFAULT_INSTRUCTIONS);
|
package/dist/lib.js
CHANGED
|
@@ -45,10 +45,11 @@ const ClaudeAgent_1 = require("./agents/ClaudeAgent");
|
|
|
45
45
|
const CodexCliAgent_1 = require("./agents/CodexCliAgent");
|
|
46
46
|
const CursorAgent_1 = require("./agents/CursorAgent");
|
|
47
47
|
const WindsurfAgent_1 = require("./agents/WindsurfAgent");
|
|
48
|
-
const
|
|
48
|
+
const ClineAgent = __importStar(require("./agents/ClineAgent"));
|
|
49
49
|
const AiderAgent_1 = require("./agents/AiderAgent");
|
|
50
50
|
const FirebaseAgent_1 = require("./agents/FirebaseAgent");
|
|
51
51
|
const OpenHandsAgent_1 = require("./agents/OpenHandsAgent");
|
|
52
|
+
const GeminiCliAgent_1 = require("./agents/GeminiCliAgent");
|
|
52
53
|
const merge_1 = require("./mcp/merge");
|
|
53
54
|
const validate_1 = require("./mcp/validate");
|
|
54
55
|
const mcp_1 = require("./paths/mcp");
|
|
@@ -94,10 +95,11 @@ const agents = [
|
|
|
94
95
|
new CodexCliAgent_1.CodexCliAgent(),
|
|
95
96
|
new CursorAgent_1.CursorAgent(),
|
|
96
97
|
new WindsurfAgent_1.WindsurfAgent(),
|
|
97
|
-
new
|
|
98
|
+
new ClineAgent.ClineAgent(),
|
|
98
99
|
new AiderAgent_1.AiderAgent(),
|
|
99
100
|
new FirebaseAgent_1.FirebaseAgent(),
|
|
100
101
|
new OpenHandsAgent_1.OpenHandsAgent(),
|
|
102
|
+
new GeminiCliAgent_1.GeminiCliAgent(),
|
|
101
103
|
];
|
|
102
104
|
/**
|
|
103
105
|
* Applies ruler configurations for all supported AI agents.
|
|
@@ -198,7 +200,7 @@ async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cli
|
|
|
198
200
|
(0, constants_1.logVerbose)(`DRY RUN: Would write rules to: ${outputPaths.join(', ')}`, verbose);
|
|
199
201
|
}
|
|
200
202
|
else {
|
|
201
|
-
await agent.applyRulerConfig(concatenated, projectRoot, agentConfig);
|
|
203
|
+
await agent.applyRulerConfig(concatenated, projectRoot, rulerMcpJson, agentConfig);
|
|
202
204
|
}
|
|
203
205
|
const dest = await (0, mcp_1.getNativeMcpPath)(agent.getName(), projectRoot);
|
|
204
206
|
const mcpEnabledForAgent = cliMcpEnabled &&
|