@intellectronica/ruler 0.3.8 → 0.3.9
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 +5 -7
- package/dist/agents/CopilotAgent.js +4 -64
- package/dist/agents/FirebaseAgent.js +8 -0
- package/dist/core/apply-engine.js +24 -2
- package/dist/paths/mcp.js +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ Ruler solves this by providing a **single source of truth** for all your AI agen
|
|
|
57
57
|
| Agent | Rules File(s) | MCP Configuration / Notes |
|
|
58
58
|
| ---------------- | ------------------------------------------------ | ------------------------------------------------ |
|
|
59
59
|
| AGENTS.md | `AGENTS.md` | (pseudo-agent ensuring root `AGENTS.md` exists) |
|
|
60
|
-
| GitHub Copilot | `AGENTS.md
|
|
60
|
+
| GitHub Copilot | `AGENTS.md` | `.vscode/mcp.json` |
|
|
61
61
|
| Claude Code | `CLAUDE.md` | `.mcp.json` |
|
|
62
62
|
| OpenAI Codex CLI | `AGENTS.md` | `.codex/config.toml` |
|
|
63
63
|
| Jules | `AGENTS.md` | - |
|
|
@@ -68,11 +68,11 @@ Ruler solves this by providing a **single source of truth** for all your AI agen
|
|
|
68
68
|
| Amp | `AGENTS.md` | - |
|
|
69
69
|
| Amazon Q CLI | `.amazonq/rules/ruler_q_rules.md` | `.amazonq/mcp.json` |
|
|
70
70
|
| Aider | `AGENTS.md`, `.aider.conf.yml` | `.mcp.json` |
|
|
71
|
-
| Firebase Studio | `.idx/airules.md` |
|
|
71
|
+
| Firebase Studio | `.idx/airules.md` | `.idx/mcp.json` |
|
|
72
72
|
| Open Hands | `.openhands/microagents/repo.md` | `config.toml` |
|
|
73
73
|
| Gemini CLI | `AGENTS.md` | `.gemini/settings.json` |
|
|
74
74
|
| Junie | `.junie/guidelines.md` | - |
|
|
75
|
-
| AugmentCode | `.augment/rules/ruler_augment_instructions.md` |
|
|
75
|
+
| AugmentCode | `.augment/rules/ruler_augment_instructions.md` | - |
|
|
76
76
|
| Kilo Code | `.kilocode/rules/ruler_kilocode_instructions.md` | `.kilocode/mcp.json` |
|
|
77
77
|
| opencode | `AGENTS.md` | `opencode.json` |
|
|
78
78
|
| Goose | `.goosehints` | - |
|
|
@@ -214,7 +214,7 @@ The `apply` command looks for `.ruler/` in the current directory tree, reading t
|
|
|
214
214
|
| Option | Description |
|
|
215
215
|
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
216
216
|
| `--project-root <path>` | Path to your project's root (default: current directory) |
|
|
217
|
-
| `--agents <agent1,agent2,...>` | Comma-separated list of agent names to target (agentsmd, amazonqcli, amp,
|
|
217
|
+
| `--agents <agent1,agent2,...>` | Comma-separated list of agent names to target (agentsmd, aider, amazonqcli, amp, augmentcode, claude, cline, codex, copilot, crush, cursor, firebase, gemini-cli, goose, jules, junie, kilocode, kiro, opencode, openhands, qwen, roo, trae, warp, windsurf, zed) |
|
|
218
218
|
| `--config <path>` | Path to a custom `ruler.toml` configuration file |
|
|
219
219
|
| `--mcp` / `--with-mcp` | Enable applying MCP server configurations (default: true) |
|
|
220
220
|
| `--no-mcp` | Disable applying MCP server configurations |
|
|
@@ -307,7 +307,7 @@ ruler revert [options]
|
|
|
307
307
|
| Option | Description |
|
|
308
308
|
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
309
309
|
| `--project-root <path>` | Path to your project's root (default: current directory) |
|
|
310
|
-
| `--agents <agent1,agent2,...>` | Comma-separated list of agent names to revert (agentsmd, amazonqcli, amp,
|
|
310
|
+
| `--agents <agent1,agent2,...>` | Comma-separated list of agent names to revert (agentsmd, aider, amazonqcli, amp, augmentcode, claude, cline, codex, copilot, crush, cursor, firebase, gemini-cli, goose, jules, junie, kilocode, kiro, opencode, openhands, qwen, roo, trae, warp, windsurf, zed) |
|
|
311
311
|
| `--config <path>` | Path to a custom `ruler.toml` configuration file |
|
|
312
312
|
| `--keep-backups` | Keep backup files (.bak) after restoration (default: false) |
|
|
313
313
|
| `--dry-run` | Preview changes without actually reverting files |
|
|
@@ -389,7 +389,6 @@ enabled = true
|
|
|
389
389
|
# --- Agent-Specific Configurations ---
|
|
390
390
|
[agents.copilot]
|
|
391
391
|
enabled = true
|
|
392
|
-
output_path = ".github/copilot-instructions.md"
|
|
393
392
|
|
|
394
393
|
[agents.claude]
|
|
395
394
|
enabled = true
|
|
@@ -565,7 +564,6 @@ node_modules/
|
|
|
565
564
|
.aider.conf.yml
|
|
566
565
|
.clinerules
|
|
567
566
|
.cursor/rules/ruler_cursor_instructions.mdc
|
|
568
|
-
.github/copilot-instructions.md
|
|
569
567
|
.windsurf/rules/ruler_windsurf_instructions.md
|
|
570
568
|
AGENTS.md
|
|
571
569
|
CLAUDE.md
|
|
@@ -1,47 +1,10 @@
|
|
|
1
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
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
3
|
exports.CopilotAgent = void 0;
|
|
37
|
-
const path = __importStar(require("path"));
|
|
38
4
|
const AgentsMdAgent_1 = require("./AgentsMdAgent");
|
|
39
|
-
const FileSystemUtils_1 = require("../core/FileSystemUtils");
|
|
40
|
-
const fs_1 = require("fs");
|
|
41
5
|
/**
|
|
42
6
|
* GitHub Copilot agent adapter.
|
|
43
|
-
* Writes to
|
|
44
|
-
* .github/copilot-instructions.md (for VS Code extension compatibility).
|
|
7
|
+
* Writes to AGENTS.md for both web-based GitHub Copilot and VS Code extension.
|
|
45
8
|
*/
|
|
46
9
|
class CopilotAgent {
|
|
47
10
|
constructor() {
|
|
@@ -54,41 +17,18 @@ class CopilotAgent {
|
|
|
54
17
|
return 'GitHub Copilot';
|
|
55
18
|
}
|
|
56
19
|
/**
|
|
57
|
-
* Returns
|
|
20
|
+
* Returns the default output path for AGENTS.md.
|
|
58
21
|
*/
|
|
59
22
|
getDefaultOutputPath(projectRoot) {
|
|
60
|
-
return
|
|
61
|
-
instructions: path.join(projectRoot, 'AGENTS.md'),
|
|
62
|
-
legacy: path.join(projectRoot, '.github', 'copilot-instructions.md'),
|
|
63
|
-
};
|
|
23
|
+
return this.agentsMdAgent.getDefaultOutputPath(projectRoot);
|
|
64
24
|
}
|
|
65
25
|
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, agentConfig, backup = true) {
|
|
66
|
-
//
|
|
26
|
+
// Write to AGENTS.md using the existing AgentsMdAgent infrastructure
|
|
67
27
|
await this.agentsMdAgent.applyRulerConfig(concatenatedRules, projectRoot, null, // No MCP config needed for the instructions file
|
|
68
28
|
{
|
|
69
29
|
// Preserve explicit outputPath precedence semantics if provided
|
|
70
30
|
outputPath: agentConfig?.outputPath || agentConfig?.outputPathInstructions,
|
|
71
31
|
}, backup);
|
|
72
|
-
// Additionally write to .github/copilot-instructions.md for VS Code extension compatibility
|
|
73
|
-
const outputPaths = this.getDefaultOutputPath(projectRoot);
|
|
74
|
-
const legacyPath = path.resolve(projectRoot, outputPaths.legacy);
|
|
75
|
-
// Add marker comment to the content to identify it as generated
|
|
76
|
-
const contentWithMarker = `<!-- Generated by Ruler -->\n${concatenatedRules}`;
|
|
77
|
-
await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(legacyPath));
|
|
78
|
-
// Check if content has changed (idempotency)
|
|
79
|
-
let existingLegacy = null;
|
|
80
|
-
try {
|
|
81
|
-
existingLegacy = await fs_1.promises.readFile(legacyPath, 'utf8');
|
|
82
|
-
}
|
|
83
|
-
catch {
|
|
84
|
-
existingLegacy = null;
|
|
85
|
-
}
|
|
86
|
-
if (existingLegacy === null || existingLegacy !== contentWithMarker) {
|
|
87
|
-
if (backup) {
|
|
88
|
-
await (0, FileSystemUtils_1.backupFile)(legacyPath);
|
|
89
|
-
}
|
|
90
|
-
await (0, FileSystemUtils_1.writeGeneratedFile)(legacyPath, contentWithMarker);
|
|
91
|
-
}
|
|
92
32
|
}
|
|
93
33
|
getMcpServerKey() {
|
|
94
34
|
return 'servers';
|
|
@@ -49,5 +49,13 @@ class FirebaseAgent extends AbstractAgent_1.AbstractAgent {
|
|
|
49
49
|
getDefaultOutputPath(projectRoot) {
|
|
50
50
|
return path.join(projectRoot, '.idx', 'airules.md');
|
|
51
51
|
}
|
|
52
|
+
// Firebase Studio (IDX) supports stdio MCP servers via .idx/mcp.json
|
|
53
|
+
supportsMcpStdio() {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
// Remote MCP over HTTP/SSE is not documented for Firebase Studio yet
|
|
57
|
+
supportsMcpRemote() {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
52
60
|
}
|
|
53
61
|
exports.FirebaseAgent = FirebaseAgent;
|
|
@@ -392,15 +392,37 @@ async function applyStandardMcpConfiguration(agent, filteredMcpJson, dest, agent
|
|
|
392
392
|
}
|
|
393
393
|
const existing = await (0, mcp_1.readNativeMcp)(dest);
|
|
394
394
|
const merged = (0, merge_1.mergeMcp)(existing, mcpToMerge, strategy, serverKey);
|
|
395
|
+
// Firebase Studio (IDX) expects no "type" fields in .idx/mcp.json server entries.
|
|
396
|
+
// Sanitize merged config by stripping 'type' from each server when targeting Firebase.
|
|
397
|
+
const sanitizeForFirebase = (obj) => {
|
|
398
|
+
if (agent.getIdentifier() !== 'firebase')
|
|
399
|
+
return obj;
|
|
400
|
+
const out = { ...obj };
|
|
401
|
+
const servers = out[serverKey] || {};
|
|
402
|
+
const cleanedServers = {};
|
|
403
|
+
for (const [name, def] of Object.entries(servers)) {
|
|
404
|
+
if (def && typeof def === 'object') {
|
|
405
|
+
const copy = { ...def };
|
|
406
|
+
delete copy.type;
|
|
407
|
+
cleanedServers[name] = copy;
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
cleanedServers[name] = def;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
out[serverKey] = cleanedServers;
|
|
414
|
+
return out;
|
|
415
|
+
};
|
|
416
|
+
const toWrite = sanitizeForFirebase(merged);
|
|
395
417
|
// Only backup and write if content would actually change (idempotent)
|
|
396
418
|
const currentContent = JSON.stringify(existing, null, 2);
|
|
397
|
-
const newContent = JSON.stringify(
|
|
419
|
+
const newContent = JSON.stringify(toWrite, null, 2);
|
|
398
420
|
if (currentContent !== newContent) {
|
|
399
421
|
if (backup) {
|
|
400
422
|
const { backupFile } = await Promise.resolve().then(() => __importStar(require('../core/FileSystemUtils')));
|
|
401
423
|
await backupFile(dest);
|
|
402
424
|
}
|
|
403
|
-
await (0, mcp_1.writeNativeMcp)(dest,
|
|
425
|
+
await (0, mcp_1.writeNativeMcp)(dest, toWrite);
|
|
404
426
|
}
|
|
405
427
|
else {
|
|
406
428
|
(0, constants_1.logVerbose)(`MCP config for ${agent.getName()} is already up to date - skipping backup and write`, verbose);
|
package/dist/paths/mcp.js
CHANGED
|
@@ -80,6 +80,9 @@ async function getNativeMcpPath(adapterName, projectRoot) {
|
|
|
80
80
|
case 'OpenCode':
|
|
81
81
|
candidates.push(path.join(projectRoot, 'opencode.json'));
|
|
82
82
|
break;
|
|
83
|
+
case 'Firebase Studio':
|
|
84
|
+
candidates.push(path.join(projectRoot, '.idx', 'mcp.json'));
|
|
85
|
+
break;
|
|
83
86
|
case 'Zed':
|
|
84
87
|
// Only consider project-local Zed settings (avoid writing to user home directory)
|
|
85
88
|
candidates.push(path.join(projectRoot, '.zed', 'settings.json'));
|