@intellectronica/ruler 0.2.16 → 0.2.18

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 CHANGED
@@ -39,7 +39,7 @@ Ruler solves this by providing a **single source of truth** for all your AI agen
39
39
  | Agent | Rules File(s) | MCP Configuration |
40
40
  | ---------------- | ------------------------------------------------ | --------------------------------------------------- |
41
41
  | GitHub Copilot | `.github/copilot-instructions.md` | `.vscode/mcp.json` |
42
- | Claude Code | `CLAUDE.md` | `claude_desktop_config.json` |
42
+ | Claude Code | `CLAUDE.md` | `.mcp.json` |
43
43
  | OpenAI Codex CLI | `AGENTS.md` | `.codex/config.toml`, `~/.codex/config.json` |
44
44
  | Jules | `AGENTS.md` | - |
45
45
  | Cursor | `.cursor/rules/ruler_cursor_instructions.mdc` | `.cursor/mcp.json`, `~/.cursor/mcp.json` |
@@ -0,0 +1,88 @@
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.CrushAgent = void 0;
37
+ const fs = __importStar(require("fs/promises"));
38
+ const path = __importStar(require("path"));
39
+ class CrushAgent {
40
+ getIdentifier() {
41
+ return 'crush';
42
+ }
43
+ getName() {
44
+ return 'Crush';
45
+ }
46
+ getDefaultOutputPath(projectRoot) {
47
+ return {
48
+ instructions: path.join(projectRoot, 'CRUSH.md'),
49
+ mcp: path.join(projectRoot, '.crush.json'),
50
+ };
51
+ }
52
+ async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, agentConfig) {
53
+ const outputPaths = this.getDefaultOutputPath(projectRoot);
54
+ const instructionsPath = agentConfig?.outputPathInstructions ?? outputPaths['instructions'];
55
+ const mcpPath = agentConfig?.outputPathConfig ?? outputPaths['mcp'];
56
+ await fs.writeFile(instructionsPath, concatenatedRules);
57
+ // Always transform from mcpServers ({ mcpServers: ... }) to { mcp: ... } for Crush
58
+ let finalMcpConfig = { mcp: {} };
59
+ try {
60
+ const existingMcpConfig = JSON.parse(await fs.readFile(mcpPath, 'utf-8'));
61
+ if (existingMcpConfig && typeof existingMcpConfig === 'object') {
62
+ finalMcpConfig = {
63
+ ...existingMcpConfig,
64
+ mcp: {
65
+ ...(existingMcpConfig.mcp || {}),
66
+ ...(rulerMcpJson?.mcpServers ?? {}),
67
+ },
68
+ };
69
+ }
70
+ else if (rulerMcpJson) {
71
+ finalMcpConfig = {
72
+ mcp: (rulerMcpJson?.mcpServers ?? {}),
73
+ };
74
+ }
75
+ }
76
+ catch {
77
+ if (rulerMcpJson) {
78
+ finalMcpConfig = {
79
+ mcp: (rulerMcpJson?.mcpServers ?? {}),
80
+ };
81
+ }
82
+ }
83
+ if (Object.keys(finalMcpConfig.mcp).length > 0) {
84
+ await fs.writeFile(mcpPath, JSON.stringify(finalMcpConfig, null, 2));
85
+ }
86
+ }
87
+ }
88
+ exports.CrushAgent = CrushAgent;
@@ -60,7 +60,7 @@ function run() {
60
60
  });
61
61
  y.option('agents', {
62
62
  type: 'string',
63
- description: 'Comma-separated list of agent identifiers: copilot, claude, codex, cursor, windsurf, cline, aider, firebase, gemini-cli, junie, kilocode, opencode',
63
+ description: 'Comma-separated list of agent identifiers: copilot, claude, codex, cursor, windsurf, cline, aider, firebase, gemini-cli, junie, kilocode, opencode, crush',
64
64
  });
65
65
  y.option('config', {
66
66
  type: 'string',
@@ -234,10 +234,15 @@ and apply them to your configured AI coding agents.
234
234
  const DEFAULT_MCP_JSON = `{
235
235
  "mcpServers": {
236
236
  "example": {
237
- "url": "https://mcp.example.com"
237
+ "type": "stdio",
238
+ "command": "node",
239
+ "args": ["/path/to/mcp-server.js"],
240
+ "env": {
241
+ "NODE_ENV": "production"
242
+ }
238
243
  }
239
244
  }
240
- }`;
245
+ }\n`;
241
246
  if (!(await exists(mcpPath))) {
242
247
  await fs_1.promises.writeFile(mcpPath, DEFAULT_MCP_JSON);
243
248
  console.log(`[ruler] Created ${mcpPath}`);
@@ -254,7 +259,7 @@ and apply them to your configured AI coding agents.
254
259
  });
255
260
  y.option('agents', {
256
261
  type: 'string',
257
- description: 'Comma-separated list of agent identifiers: copilot, claude, codex, cursor, windsurf, cline, aider, firebase, gemini-cli, junie, kilocode, opencode',
262
+ description: 'Comma-separated list of agent identifiers: copilot, claude, codex, cursor, windsurf, cline, aider, firebase, gemini-cli, junie, kilocode, opencode, crush',
258
263
  });
259
264
  y.option('config', {
260
265
  type: 'string',
package/dist/lib.js CHANGED
@@ -45,7 +45,7 @@ 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 ClineAgent = __importStar(require("./agents/ClineAgent"));
48
+ const ClineAgent_1 = 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");
@@ -55,6 +55,7 @@ const JunieAgent_1 = require("./agents/JunieAgent");
55
55
  const AugmentCodeAgent_1 = require("./agents/AugmentCodeAgent");
56
56
  const KiloCodeAgent_1 = require("./agents/KiloCodeAgent");
57
57
  const OpenCodeAgent_1 = require("./agents/OpenCodeAgent");
58
+ const CrushAgent_1 = require("./agents/CrushAgent");
58
59
  const GooseAgent_1 = require("./agents/GooseAgent");
59
60
  const merge_1 = require("./mcp/merge");
60
61
  const validate_1 = require("./mcp/validate");
@@ -102,7 +103,7 @@ const agents = [
102
103
  new CodexCliAgent_1.CodexCliAgent(),
103
104
  new CursorAgent_1.CursorAgent(),
104
105
  new WindsurfAgent_1.WindsurfAgent(),
105
- new ClineAgent.ClineAgent(),
106
+ new ClineAgent_1.ClineAgent(),
106
107
  new AiderAgent_1.AiderAgent(),
107
108
  new FirebaseAgent_1.FirebaseAgent(),
108
109
  new OpenHandsAgent_1.OpenHandsAgent(),
@@ -113,6 +114,7 @@ const agents = [
113
114
  new KiloCodeAgent_1.KiloCodeAgent(),
114
115
  new OpenCodeAgent_1.OpenCodeAgent(),
115
116
  new GooseAgent_1.GooseAgent(),
117
+ new CrushAgent_1.CrushAgent(),
116
118
  ];
117
119
  /**
118
120
  * Applies ruler configurations for all supported AI agents.
package/dist/mcp/merge.js CHANGED
@@ -12,15 +12,23 @@ exports.mergeMcp = mergeMcp;
12
12
  function mergeMcp(base, incoming, strategy, serverKey) {
13
13
  if (strategy === 'overwrite') {
14
14
  // Ensure the incoming object uses the correct server key.
15
- const incomingServers = incoming.mcpServers || {};
15
+ // Transform from the standard (Crush) MCP config format
16
+ const incomingServers = incoming[serverKey] ||
17
+ incoming.mcpServers ||
18
+ incoming.mcp ||
19
+ {};
16
20
  return {
17
21
  [serverKey]: incomingServers,
18
22
  };
19
23
  }
20
24
  const baseServers = base[serverKey] ||
21
25
  base.mcpServers ||
22
- {}; // Handle legacy key in existing files
23
- const incomingServers = incoming.mcpServers || {};
26
+ base.mcp ||
27
+ {};
28
+ const incomingServers = incoming[serverKey] ||
29
+ incoming.mcpServers ||
30
+ incoming.mcp ||
31
+ {};
24
32
  const mergedServers = { ...baseServers, ...incomingServers };
25
33
  const newBase = { ...base };
26
34
  delete newBase.mcpServers; // Remove old key if present
@@ -48,6 +48,7 @@ async function propagateMcpToOpenHands(rulerMcpPath, openHandsConfigPath) {
48
48
  catch {
49
49
  return;
50
50
  }
51
+ // Always use the legacy Ruler MCP config format as input (top-level "mcpServers" key)
51
52
  const rulerServers = rulerMcp.mcpServers || {};
52
53
  let config = {};
53
54
  try {
@@ -12,6 +12,6 @@ function validateMcp(data) {
12
12
  typeof data !== 'object' ||
13
13
  !('mcpServers' in data) ||
14
14
  typeof data.mcpServers !== 'object') {
15
- throw new Error('[ruler] Invalid .ruler/mcp.json: must contain an object property "mcpServers"');
15
+ throw new Error('[ruler] Invalid MCP config: must contain an object property "mcpServers" (Ruler style)');
16
16
  }
17
17
  }
package/dist/paths/mcp.js CHANGED
@@ -59,7 +59,7 @@ async function getNativeMcpPath(adapterName, projectRoot) {
59
59
  candidates.push(path.join(home, '.codeium', 'windsurf', 'mcp_config.json'));
60
60
  break;
61
61
  case 'Claude Code':
62
- candidates.push(path.join(projectRoot, 'claude_desktop_config.json'));
62
+ candidates.push(path.join(projectRoot, '.mcp.json'));
63
63
  break;
64
64
  case 'OpenAI Codex CLI':
65
65
  candidates.push(path.join(home, '.codex', 'config.json'));
package/dist/revert.js CHANGED
@@ -307,7 +307,6 @@ async function removeEmptyDirectories(projectRoot, verbose, dryRun) {
307
307
  async function removeAdditionalAgentFiles(projectRoot, verbose, dryRun) {
308
308
  const additionalFiles = [
309
309
  '.gemini/settings.json',
310
- 'claude_desktop_config.json',
311
310
  '.mcp.json',
312
311
  '.vscode/mcp.json',
313
312
  '.cursor/mcp.json',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intellectronica/ruler",
3
- "version": "0.2.16",
3
+ "version": "0.2.18",
4
4
  "description": "Ruler — apply the same rules to all coding agents",
5
5
  "main": "dist/lib.js",
6
6
  "scripts": {