@intellectronica/ruler 0.1.0 → 0.1.2
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 +84 -1
- package/dist/agents/AiderAgent.js +16 -7
- package/dist/agents/ClaudeAgent.js +7 -4
- package/dist/agents/ClineAgent.js +7 -4
- package/dist/agents/CodexCliAgent.js +7 -4
- package/dist/agents/CopilotAgent.js +8 -6
- package/dist/agents/CursorAgent.js +8 -6
- package/dist/agents/WindsurfAgent.js +8 -6
- package/dist/cli/commands.js +154 -1
- package/dist/core/ConfigLoader.js +117 -0
- package/dist/lib.js +72 -8
- package/dist/mcp/merge.js +21 -0
- package/dist/mcp/validate.js +17 -0
- package/dist/paths/mcp.js +100 -0
- package/dist/types.js +2 -0
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -35,7 +35,14 @@ Create a `.ruler/` directory at your project root and add Markdown files definin
|
|
|
35
35
|
Run the apply command:
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
ruler apply [--project-root <path>] [--agents <agent1,agent2,...>]
|
|
38
|
+
ruler apply [--project-root <path>] [--agents <agent1,agent2,...>] [--config <path>]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
Run the init command to scaffold a basic `.ruler/` setup:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
ruler init [--project-root <path>]
|
|
39
46
|
```
|
|
40
47
|
|
|
41
48
|
Use `--agents` to specify a comma-separated list of agent names (case-insensitive substrings) to limit which agents the rules are applied to.
|
|
@@ -52,6 +59,82 @@ The command will read all `.md` files under `.ruler/`, concatenate their content
|
|
|
52
59
|
| Cline | `.clinerules` |
|
|
53
60
|
| Aider | `ruler_aider_instructions.md` <br>and updates `.aider.conf.yml` |
|
|
54
61
|
|
|
62
|
+
## Configuration
|
|
63
|
+
|
|
64
|
+
Ruler uses a TOML configuration file located at `.ruler/ruler.toml` by default. You can override its location with the `--config <path>` option in the `apply` command.
|
|
65
|
+
|
|
66
|
+
### Configuration structure
|
|
67
|
+
|
|
68
|
+
```toml
|
|
69
|
+
# Run only these agents by default (omit to use all agents)
|
|
70
|
+
# default_agents = ["GitHub Copilot", "Claude Code", "Aider"]
|
|
71
|
+
|
|
72
|
+
[agents.Copilot]
|
|
73
|
+
enabled = true
|
|
74
|
+
output_path = ".github/copilot-instructions.md"
|
|
75
|
+
|
|
76
|
+
[agents.Claude]
|
|
77
|
+
enabled = true
|
|
78
|
+
# output_path = "CLAUDE.md"
|
|
79
|
+
|
|
80
|
+
[agents.Aider]
|
|
81
|
+
enabled = false
|
|
82
|
+
# output_path_instructions = "ruler_aider_instructions.md"
|
|
83
|
+
# output_path_config = ".aider.conf.yml"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- `default_agents`: array of agent names (case-insensitive substrings) to run by default.
|
|
87
|
+
- `[agents.<AgentName>]`: per-agent settings:
|
|
88
|
+
- `enabled` (boolean): enable or disable this agent.
|
|
89
|
+
- `output_path` (string): custom path for agents that produce a single file.
|
|
90
|
+
- `output_path_instructions`/`output_path_config`: custom paths for Aider's instruction and config files.
|
|
91
|
+
|
|
92
|
+
### Precedence
|
|
93
|
+
|
|
94
|
+
1. CLI `--agents` option (substring filters)
|
|
95
|
+
2. Config file `default_agents` and `[agents]` overrides
|
|
96
|
+
3. Built-in defaults (all agents enabled, standard output paths)
|
|
97
|
+
|
|
98
|
+
## MCP servers
|
|
99
|
+
|
|
100
|
+
Ruler can propagate a project-level `.ruler/mcp.json` file to native MCP configurations of supported agents, merging (or overwriting) each agent’s existing MCP server settings.
|
|
101
|
+
|
|
102
|
+
### `.ruler/mcp.json`
|
|
103
|
+
|
|
104
|
+
Place your MCP servers config in a file at `.ruler/mcp.json`:
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"mcpServers": {
|
|
109
|
+
"example": {
|
|
110
|
+
"url": "https://mcp.example.com"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### CLI flags
|
|
117
|
+
|
|
118
|
+
| Flag | Effect |
|
|
119
|
+
|-------------------|--------------------------------------------------------------|
|
|
120
|
+
| `--with-mcp` | Enable writing MCP configs for all agents (default) |
|
|
121
|
+
| `--no-mcp` | Disable writing MCP configs |
|
|
122
|
+
| `--mcp-overwrite` | Overwrite native MCP configs instead of merging |
|
|
123
|
+
|
|
124
|
+
### Configuration (`ruler.toml`)
|
|
125
|
+
|
|
126
|
+
Configure default behavior in your `ruler.toml`:
|
|
127
|
+
|
|
128
|
+
```toml
|
|
129
|
+
[mcp]
|
|
130
|
+
enabled = true
|
|
131
|
+
merge_strategy = "merge" # or "overwrite"
|
|
132
|
+
|
|
133
|
+
[agents.Cursor.mcp]
|
|
134
|
+
enabled = false
|
|
135
|
+
merge_strategy = "overwrite"
|
|
136
|
+
```
|
|
137
|
+
|
|
55
138
|
## Development
|
|
56
139
|
|
|
57
140
|
Clone the repository and install dependencies:
|
|
@@ -45,11 +45,13 @@ class AiderAgent {
|
|
|
45
45
|
getName() {
|
|
46
46
|
return 'Aider';
|
|
47
47
|
}
|
|
48
|
-
async applyRulerConfig(concatenatedRules, projectRoot) {
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
await (0, FileSystemUtils_1.
|
|
52
|
-
|
|
48
|
+
async applyRulerConfig(concatenatedRules, projectRoot, agentConfig) {
|
|
49
|
+
const mdPath = agentConfig?.outputPathInstructions ??
|
|
50
|
+
this.getDefaultOutputPath(projectRoot).instructions;
|
|
51
|
+
await (0, FileSystemUtils_1.backupFile)(mdPath);
|
|
52
|
+
await (0, FileSystemUtils_1.writeGeneratedFile)(mdPath, concatenatedRules);
|
|
53
|
+
const cfgPath = agentConfig?.outputPathConfig ??
|
|
54
|
+
this.getDefaultOutputPath(projectRoot).config;
|
|
53
55
|
let doc = {};
|
|
54
56
|
try {
|
|
55
57
|
await fs.access(cfgPath);
|
|
@@ -63,11 +65,18 @@ class AiderAgent {
|
|
|
63
65
|
if (!Array.isArray(doc.read)) {
|
|
64
66
|
doc.read = [];
|
|
65
67
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
const name = path.basename(mdPath);
|
|
69
|
+
if (!doc.read.includes(name)) {
|
|
70
|
+
doc.read.push(name);
|
|
68
71
|
}
|
|
69
72
|
const yamlStr = yaml.dump(doc);
|
|
70
73
|
await (0, FileSystemUtils_1.writeGeneratedFile)(cfgPath, yamlStr);
|
|
71
74
|
}
|
|
75
|
+
getDefaultOutputPath(projectRoot) {
|
|
76
|
+
return {
|
|
77
|
+
instructions: path.join(projectRoot, 'ruler_aider_instructions.md'),
|
|
78
|
+
config: path.join(projectRoot, '.aider.conf.yml'),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
72
81
|
}
|
|
73
82
|
exports.AiderAgent = AiderAgent;
|
|
@@ -43,10 +43,13 @@ class ClaudeAgent {
|
|
|
43
43
|
getName() {
|
|
44
44
|
return 'Claude Code';
|
|
45
45
|
}
|
|
46
|
-
async applyRulerConfig(concatenatedRules, projectRoot) {
|
|
47
|
-
const
|
|
48
|
-
await (0, FileSystemUtils_1.backupFile)(
|
|
49
|
-
await (0, FileSystemUtils_1.writeGeneratedFile)(
|
|
46
|
+
async applyRulerConfig(concatenatedRules, projectRoot, agentConfig) {
|
|
47
|
+
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
48
|
+
await (0, FileSystemUtils_1.backupFile)(output);
|
|
49
|
+
await (0, FileSystemUtils_1.writeGeneratedFile)(output, concatenatedRules);
|
|
50
|
+
}
|
|
51
|
+
getDefaultOutputPath(projectRoot) {
|
|
52
|
+
return path.join(projectRoot, 'CLAUDE.md');
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
55
|
exports.ClaudeAgent = ClaudeAgent;
|
|
@@ -43,10 +43,13 @@ class ClineAgent {
|
|
|
43
43
|
getName() {
|
|
44
44
|
return 'Cline';
|
|
45
45
|
}
|
|
46
|
-
async applyRulerConfig(concatenatedRules, projectRoot) {
|
|
47
|
-
const
|
|
48
|
-
await (0, FileSystemUtils_1.backupFile)(
|
|
49
|
-
await (0, FileSystemUtils_1.writeGeneratedFile)(
|
|
46
|
+
async applyRulerConfig(concatenatedRules, projectRoot, agentConfig) {
|
|
47
|
+
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
48
|
+
await (0, FileSystemUtils_1.backupFile)(output);
|
|
49
|
+
await (0, FileSystemUtils_1.writeGeneratedFile)(output, concatenatedRules);
|
|
50
|
+
}
|
|
51
|
+
getDefaultOutputPath(projectRoot) {
|
|
52
|
+
return path.join(projectRoot, '.clinerules');
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
55
|
exports.ClineAgent = ClineAgent;
|
|
@@ -43,10 +43,13 @@ class CodexCliAgent {
|
|
|
43
43
|
getName() {
|
|
44
44
|
return 'OpenAI Codex CLI';
|
|
45
45
|
}
|
|
46
|
-
async applyRulerConfig(concatenatedRules, projectRoot) {
|
|
47
|
-
const
|
|
48
|
-
await (0, FileSystemUtils_1.backupFile)(
|
|
49
|
-
await (0, FileSystemUtils_1.writeGeneratedFile)(
|
|
46
|
+
async applyRulerConfig(concatenatedRules, projectRoot, agentConfig) {
|
|
47
|
+
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
48
|
+
await (0, FileSystemUtils_1.backupFile)(output);
|
|
49
|
+
await (0, FileSystemUtils_1.writeGeneratedFile)(output, concatenatedRules);
|
|
50
|
+
}
|
|
51
|
+
getDefaultOutputPath(projectRoot) {
|
|
52
|
+
return path.join(projectRoot, 'AGENTS.md');
|
|
50
53
|
}
|
|
51
54
|
}
|
|
52
55
|
exports.CodexCliAgent = CodexCliAgent;
|
|
@@ -43,12 +43,14 @@ class CopilotAgent {
|
|
|
43
43
|
getName() {
|
|
44
44
|
return 'GitHub Copilot';
|
|
45
45
|
}
|
|
46
|
-
async applyRulerConfig(concatenatedRules, projectRoot) {
|
|
47
|
-
const
|
|
48
|
-
await (0, FileSystemUtils_1.ensureDirExists)(
|
|
49
|
-
|
|
50
|
-
await (0, FileSystemUtils_1.
|
|
51
|
-
|
|
46
|
+
async applyRulerConfig(concatenatedRules, projectRoot, agentConfig) {
|
|
47
|
+
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
48
|
+
await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(output));
|
|
49
|
+
await (0, FileSystemUtils_1.backupFile)(output);
|
|
50
|
+
await (0, FileSystemUtils_1.writeGeneratedFile)(output, concatenatedRules);
|
|
51
|
+
}
|
|
52
|
+
getDefaultOutputPath(projectRoot) {
|
|
53
|
+
return path.join(projectRoot, '.github', 'copilot-instructions.md');
|
|
52
54
|
}
|
|
53
55
|
}
|
|
54
56
|
exports.CopilotAgent = CopilotAgent;
|
|
@@ -43,12 +43,14 @@ class CursorAgent {
|
|
|
43
43
|
getName() {
|
|
44
44
|
return 'Cursor';
|
|
45
45
|
}
|
|
46
|
-
async applyRulerConfig(concatenatedRules, projectRoot) {
|
|
47
|
-
const
|
|
48
|
-
await (0, FileSystemUtils_1.ensureDirExists)(
|
|
49
|
-
|
|
50
|
-
await (0, FileSystemUtils_1.
|
|
51
|
-
|
|
46
|
+
async applyRulerConfig(concatenatedRules, projectRoot, agentConfig) {
|
|
47
|
+
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
48
|
+
await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(output));
|
|
49
|
+
await (0, FileSystemUtils_1.backupFile)(output);
|
|
50
|
+
await (0, FileSystemUtils_1.writeGeneratedFile)(output, concatenatedRules);
|
|
51
|
+
}
|
|
52
|
+
getDefaultOutputPath(projectRoot) {
|
|
53
|
+
return path.join(projectRoot, '.cursor', 'rules', 'ruler_cursor_instructions.md');
|
|
52
54
|
}
|
|
53
55
|
}
|
|
54
56
|
exports.CursorAgent = CursorAgent;
|
|
@@ -43,12 +43,14 @@ class WindsurfAgent {
|
|
|
43
43
|
getName() {
|
|
44
44
|
return 'Windsurf';
|
|
45
45
|
}
|
|
46
|
-
async applyRulerConfig(concatenatedRules, projectRoot) {
|
|
47
|
-
const
|
|
48
|
-
await (0, FileSystemUtils_1.ensureDirExists)(
|
|
49
|
-
|
|
50
|
-
await (0, FileSystemUtils_1.
|
|
51
|
-
|
|
46
|
+
async applyRulerConfig(concatenatedRules, projectRoot, agentConfig) {
|
|
47
|
+
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
48
|
+
await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(output));
|
|
49
|
+
await (0, FileSystemUtils_1.backupFile)(output);
|
|
50
|
+
await (0, FileSystemUtils_1.writeGeneratedFile)(output, concatenatedRules);
|
|
51
|
+
}
|
|
52
|
+
getDefaultOutputPath(projectRoot) {
|
|
53
|
+
return path.join(projectRoot, '.windsurf', 'rules', 'ruler_windsurf_instructions.md');
|
|
52
54
|
}
|
|
53
55
|
}
|
|
54
56
|
exports.WindsurfAgent = WindsurfAgent;
|
package/dist/cli/commands.js
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
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
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
@@ -7,6 +40,8 @@ exports.run = run;
|
|
|
7
40
|
const yargs_1 = __importDefault(require("yargs"));
|
|
8
41
|
const helpers_1 = require("yargs/helpers");
|
|
9
42
|
const lib_1 = require("../lib");
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const fs_1 = require("fs");
|
|
10
45
|
/**
|
|
11
46
|
* Sets up and parses CLI commands.
|
|
12
47
|
*/
|
|
@@ -24,13 +59,33 @@ function run() {
|
|
|
24
59
|
type: 'string',
|
|
25
60
|
description: 'Comma-separated list of agent names to include (e.g. "copilot,claude")',
|
|
26
61
|
});
|
|
62
|
+
y.option('config', {
|
|
63
|
+
type: 'string',
|
|
64
|
+
description: 'Path to TOML configuration file',
|
|
65
|
+
});
|
|
66
|
+
y.option('mcp', {
|
|
67
|
+
type: 'boolean',
|
|
68
|
+
description: 'Enable or disable applying MCP server config',
|
|
69
|
+
default: true,
|
|
70
|
+
});
|
|
71
|
+
y.alias('mcp', 'with-mcp');
|
|
72
|
+
y.option('mcp-overwrite', {
|
|
73
|
+
type: 'boolean',
|
|
74
|
+
description: 'Replace (not merge) the native MCP config(s)',
|
|
75
|
+
default: false,
|
|
76
|
+
});
|
|
27
77
|
}, async (argv) => {
|
|
28
78
|
const projectRoot = argv['project-root'];
|
|
29
79
|
const agents = argv.agents
|
|
30
80
|
? argv.agents.split(',').map((a) => a.trim())
|
|
31
81
|
: undefined;
|
|
82
|
+
const configPath = argv.config;
|
|
83
|
+
const mcpEnabled = argv.mcp;
|
|
84
|
+
const mcpStrategy = argv['mcp-overwrite']
|
|
85
|
+
? 'overwrite'
|
|
86
|
+
: undefined;
|
|
32
87
|
try {
|
|
33
|
-
await (0, lib_1.applyAllAgentConfigs)(projectRoot, agents);
|
|
88
|
+
await (0, lib_1.applyAllAgentConfigs)(projectRoot, agents, configPath, mcpEnabled, mcpStrategy);
|
|
34
89
|
console.log('Ruler apply completed successfully.');
|
|
35
90
|
}
|
|
36
91
|
catch (err) {
|
|
@@ -38,6 +93,104 @@ function run() {
|
|
|
38
93
|
console.error('Error applying ruler configurations:', message);
|
|
39
94
|
process.exit(1);
|
|
40
95
|
}
|
|
96
|
+
})
|
|
97
|
+
.command('init', 'Scaffold a .ruler directory with default files', (y) => {
|
|
98
|
+
y.option('project-root', {
|
|
99
|
+
type: 'string',
|
|
100
|
+
description: 'Project root directory',
|
|
101
|
+
default: process.cwd(),
|
|
102
|
+
});
|
|
103
|
+
}, async (argv) => {
|
|
104
|
+
const projectRoot = argv['project-root'];
|
|
105
|
+
const rulerDir = path.join(projectRoot, '.ruler');
|
|
106
|
+
await fs_1.promises.mkdir(rulerDir, { recursive: true });
|
|
107
|
+
const instructionsPath = path.join(rulerDir, 'instructions.md');
|
|
108
|
+
const tomlPath = path.join(rulerDir, 'ruler.toml');
|
|
109
|
+
const exists = async (p) => {
|
|
110
|
+
try {
|
|
111
|
+
await fs_1.promises.access(p);
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
const DEFAULT_INSTRUCTIONS = `# Ruler Instructions
|
|
119
|
+
|
|
120
|
+
These are your centralised AI agent instructions.
|
|
121
|
+
Add your coding guidelines, style guides, and other project-specific context here.
|
|
122
|
+
|
|
123
|
+
Ruler will concatenate all .md files in this directory (and its subdirectories)
|
|
124
|
+
and apply them to your configured AI coding agents.
|
|
125
|
+
`;
|
|
126
|
+
const DEFAULT_TOML = `# Ruler Configuration File
|
|
127
|
+
# See https://ai.intellectronica.net/ruler for documentation.
|
|
128
|
+
|
|
129
|
+
# To specify which agents are active by default when --agents is not used,
|
|
130
|
+
# uncomment and populate the following line. If omitted, all agents are active.
|
|
131
|
+
# default_agents = ["Copilot", "Claude"]
|
|
132
|
+
|
|
133
|
+
# --- Agent Specific Configurations ---
|
|
134
|
+
# You can enable/disable agents and override their default output paths here.
|
|
135
|
+
|
|
136
|
+
# [agents.GitHubCopilot]
|
|
137
|
+
# enabled = true
|
|
138
|
+
# output_path = ".github/copilot-instructions.md"
|
|
139
|
+
|
|
140
|
+
# [agents.ClaudeCode]
|
|
141
|
+
# enabled = true
|
|
142
|
+
# output_path = "CLAUDE.md"
|
|
143
|
+
|
|
144
|
+
# [agents.OpenAICodexCLI]
|
|
145
|
+
# enabled = true
|
|
146
|
+
# output_path = "AGENTS.md"
|
|
147
|
+
|
|
148
|
+
# [agents.Cursor]
|
|
149
|
+
# enabled = true
|
|
150
|
+
# output_path = ".cursor/rules/ruler_cursor_instructions.md"
|
|
151
|
+
|
|
152
|
+
# [agents.Windsurf]
|
|
153
|
+
# enabled = true
|
|
154
|
+
# output_path = ".windsurf/rules/ruler_windsurf_instructions.md"
|
|
155
|
+
|
|
156
|
+
# [agents.Cline]
|
|
157
|
+
# enabled = true
|
|
158
|
+
# output_path = ".clinerules"
|
|
159
|
+
|
|
160
|
+
# [agents.Aider]
|
|
161
|
+
# enabled = true
|
|
162
|
+
# output_path_instructions = "ruler_aider_instructions.md"
|
|
163
|
+
# output_path_config = ".aider.conf.yml"
|
|
164
|
+
`;
|
|
165
|
+
if (!(await exists(instructionsPath))) {
|
|
166
|
+
await fs_1.promises.writeFile(instructionsPath, DEFAULT_INSTRUCTIONS);
|
|
167
|
+
console.log(`[ruler] Created ${instructionsPath}`);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
console.log(`[ruler] instructions.md already exists, skipping`);
|
|
171
|
+
}
|
|
172
|
+
if (!(await exists(tomlPath))) {
|
|
173
|
+
await fs_1.promises.writeFile(tomlPath, DEFAULT_TOML);
|
|
174
|
+
console.log(`[ruler] Created ${tomlPath}`);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
console.log(`[ruler] ruler.toml already exists, skipping`);
|
|
178
|
+
}
|
|
179
|
+
const mcpPath = path.join(rulerDir, 'mcp.json');
|
|
180
|
+
const DEFAULT_MCP_JSON = `{
|
|
181
|
+
"mcpServers": {
|
|
182
|
+
"example": {
|
|
183
|
+
"url": "https://mcp.example.com"
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}`;
|
|
187
|
+
if (!(await exists(mcpPath))) {
|
|
188
|
+
await fs_1.promises.writeFile(mcpPath, DEFAULT_MCP_JSON);
|
|
189
|
+
console.log(`[ruler] Created ${mcpPath}`);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
console.log(`[ruler] mcp.json already exists, skipping`);
|
|
193
|
+
}
|
|
41
194
|
})
|
|
42
195
|
.demandCommand(1, 'You need to specify a command')
|
|
43
196
|
.help()
|
|
@@ -0,0 +1,117 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.loadConfig = loadConfig;
|
|
40
|
+
const fs_1 = require("fs");
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const toml_1 = __importDefault(require("toml"));
|
|
43
|
+
/**
|
|
44
|
+
* Loads and parses the ruler TOML configuration file, applying defaults.
|
|
45
|
+
* If the file is missing or invalid, returns empty/default config.
|
|
46
|
+
*/
|
|
47
|
+
async function loadConfig(options) {
|
|
48
|
+
const { projectRoot, configPath, cliAgents } = options;
|
|
49
|
+
const configFile = configPath
|
|
50
|
+
? path.resolve(configPath)
|
|
51
|
+
: path.join(projectRoot, '.ruler', 'ruler.toml');
|
|
52
|
+
let raw = {};
|
|
53
|
+
try {
|
|
54
|
+
const text = await fs_1.promises.readFile(configFile, 'utf8');
|
|
55
|
+
raw = text.trim() ? toml_1.default.parse(text) : {};
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
if (err instanceof Error && err.code !== 'ENOENT') {
|
|
59
|
+
console.warn(`[ruler] Warning: could not read config file at ${configFile}: ${err.message}`);
|
|
60
|
+
}
|
|
61
|
+
raw = {};
|
|
62
|
+
}
|
|
63
|
+
const defaultAgents = Array.isArray(raw.default_agents)
|
|
64
|
+
? raw.default_agents.map((a) => String(a))
|
|
65
|
+
: undefined;
|
|
66
|
+
const agentsSection = raw.agents && typeof raw.agents === 'object' && !Array.isArray(raw.agents)
|
|
67
|
+
? raw.agents
|
|
68
|
+
: {};
|
|
69
|
+
const agentConfigs = {};
|
|
70
|
+
for (const [name, section] of Object.entries(agentsSection)) {
|
|
71
|
+
if (section && typeof section === 'object') {
|
|
72
|
+
const sectionObj = section;
|
|
73
|
+
const cfg = {};
|
|
74
|
+
if (typeof sectionObj.enabled === 'boolean') {
|
|
75
|
+
cfg.enabled = sectionObj.enabled;
|
|
76
|
+
}
|
|
77
|
+
if (typeof sectionObj.output_path === 'string') {
|
|
78
|
+
cfg.outputPath = path.resolve(projectRoot, sectionObj.output_path);
|
|
79
|
+
}
|
|
80
|
+
if (typeof sectionObj.output_path_instructions === 'string') {
|
|
81
|
+
cfg.outputPathInstructions = path.resolve(projectRoot, sectionObj.output_path_instructions);
|
|
82
|
+
}
|
|
83
|
+
if (typeof sectionObj.output_path_config === 'string') {
|
|
84
|
+
cfg.outputPathConfig = path.resolve(projectRoot, sectionObj.output_path_config);
|
|
85
|
+
}
|
|
86
|
+
if (sectionObj.mcp && typeof sectionObj.mcp === 'object') {
|
|
87
|
+
const m = sectionObj.mcp;
|
|
88
|
+
const mcpCfg = {};
|
|
89
|
+
if (typeof m.enabled === 'boolean') {
|
|
90
|
+
mcpCfg.enabled = m.enabled;
|
|
91
|
+
}
|
|
92
|
+
if (typeof m.merge_strategy === 'string') {
|
|
93
|
+
const ms = m.merge_strategy;
|
|
94
|
+
if (ms === 'merge' || ms === 'overwrite') {
|
|
95
|
+
mcpCfg.strategy = ms;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
cfg.mcp = mcpCfg;
|
|
99
|
+
}
|
|
100
|
+
agentConfigs[name] = cfg;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const rawMcpSection = raw.mcp && typeof raw.mcp === 'object' && !Array.isArray(raw.mcp)
|
|
104
|
+
? raw.mcp
|
|
105
|
+
: {};
|
|
106
|
+
const globalMcpConfig = {};
|
|
107
|
+
if (typeof rawMcpSection.enabled === 'boolean') {
|
|
108
|
+
globalMcpConfig.enabled = rawMcpSection.enabled;
|
|
109
|
+
}
|
|
110
|
+
if (typeof rawMcpSection.merge_strategy === 'string') {
|
|
111
|
+
const strat = rawMcpSection.merge_strategy;
|
|
112
|
+
if (strat === 'merge' || strat === 'overwrite') {
|
|
113
|
+
globalMcpConfig.strategy = strat;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return { defaultAgents, agentConfigs, cliAgents, mcp: globalMcpConfig };
|
|
117
|
+
}
|
package/dist/lib.js
CHANGED
|
@@ -35,8 +35,10 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.applyAllAgentConfigs = applyAllAgentConfigs;
|
|
37
37
|
const path = __importStar(require("path"));
|
|
38
|
-
const
|
|
38
|
+
const fs_1 = require("fs");
|
|
39
|
+
const FileSystemUtils = __importStar(require("./core/FileSystemUtils"));
|
|
39
40
|
const RuleProcessor_1 = require("./core/RuleProcessor");
|
|
41
|
+
const ConfigLoader_1 = require("./core/ConfigLoader");
|
|
40
42
|
const CopilotAgent_1 = require("./agents/CopilotAgent");
|
|
41
43
|
const ClaudeAgent_1 = require("./agents/ClaudeAgent");
|
|
42
44
|
const CodexCliAgent_1 = require("./agents/CodexCliAgent");
|
|
@@ -44,6 +46,9 @@ const CursorAgent_1 = require("./agents/CursorAgent");
|
|
|
44
46
|
const WindsurfAgent_1 = require("./agents/WindsurfAgent");
|
|
45
47
|
const ClineAgent_1 = require("./agents/ClineAgent");
|
|
46
48
|
const AiderAgent_1 = require("./agents/AiderAgent");
|
|
49
|
+
const merge_1 = require("./mcp/merge");
|
|
50
|
+
const validate_1 = require("./mcp/validate");
|
|
51
|
+
const mcp_1 = require("./paths/mcp");
|
|
47
52
|
const agents = [
|
|
48
53
|
new CopilotAgent_1.CopilotAgent(),
|
|
49
54
|
new ClaudeAgent_1.ClaudeAgent(),
|
|
@@ -62,21 +67,80 @@ const agents = [
|
|
|
62
67
|
* @param projectRoot Root directory of the project
|
|
63
68
|
* @param includedAgents Optional list of agent name filters (case-insensitive substrings)
|
|
64
69
|
*/
|
|
65
|
-
async function applyAllAgentConfigs(projectRoot, includedAgents) {
|
|
66
|
-
|
|
70
|
+
async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cliMcpEnabled = true, cliMcpStrategy) {
|
|
71
|
+
// Load configuration (default_agents, per-agent overrides, CLI filters)
|
|
72
|
+
const config = await (0, ConfigLoader_1.loadConfig)({
|
|
73
|
+
projectRoot,
|
|
74
|
+
cliAgents: includedAgents,
|
|
75
|
+
configPath,
|
|
76
|
+
});
|
|
77
|
+
// Normalize per-agent config keys to actual agent names (substring match)
|
|
78
|
+
const rawConfigs = config.agentConfigs;
|
|
79
|
+
const mappedConfigs = {};
|
|
80
|
+
for (const [key, cfg] of Object.entries(rawConfigs)) {
|
|
81
|
+
const lowerKey = key.toLowerCase();
|
|
82
|
+
for (const agent of agents) {
|
|
83
|
+
if (agent.getName().toLowerCase().includes(lowerKey)) {
|
|
84
|
+
mappedConfigs[agent.getName()] = cfg;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
config.agentConfigs = mappedConfigs;
|
|
89
|
+
const rulerDir = await FileSystemUtils.findRulerDir(projectRoot);
|
|
67
90
|
if (!rulerDir) {
|
|
68
91
|
throw new Error(`.ruler directory not found from ${projectRoot}`);
|
|
69
92
|
}
|
|
70
|
-
await
|
|
71
|
-
const files = await
|
|
93
|
+
await FileSystemUtils.ensureDirExists(path.join(rulerDir, 'generated'));
|
|
94
|
+
const files = await FileSystemUtils.readMarkdownFiles(rulerDir);
|
|
72
95
|
const concatenated = (0, RuleProcessor_1.concatenateRules)(files);
|
|
96
|
+
const mcpFile = path.join(rulerDir, 'mcp.json');
|
|
97
|
+
let rulerMcpJson = null;
|
|
98
|
+
try {
|
|
99
|
+
const raw = await fs_1.promises.readFile(mcpFile, 'utf8');
|
|
100
|
+
rulerMcpJson = JSON.parse(raw);
|
|
101
|
+
(0, validate_1.validateMcp)(rulerMcpJson);
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
if (err.code !== 'ENOENT') {
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Determine which agents to run:
|
|
109
|
+
// CLI --agents > config.default_agents > per-agent.enabled flags > default all
|
|
73
110
|
let selected = agents;
|
|
74
|
-
if (
|
|
75
|
-
const filters =
|
|
111
|
+
if (config.cliAgents && config.cliAgents.length > 0) {
|
|
112
|
+
const filters = config.cliAgents.map((n) => n.toLowerCase());
|
|
76
113
|
selected = agents.filter((agent) => filters.some((f) => agent.getName().toLowerCase().includes(f)));
|
|
77
114
|
}
|
|
115
|
+
else if (config.defaultAgents && config.defaultAgents.length > 0) {
|
|
116
|
+
const defaults = config.defaultAgents.map((n) => n.toLowerCase());
|
|
117
|
+
selected = agents.filter((agent) => {
|
|
118
|
+
const key = agent.getName();
|
|
119
|
+
const override = config.agentConfigs[key]?.enabled;
|
|
120
|
+
if (override !== undefined) {
|
|
121
|
+
return override;
|
|
122
|
+
}
|
|
123
|
+
return defaults.includes(key.toLowerCase());
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
selected = agents.filter((agent) => config.agentConfigs[agent.getName()]?.enabled !== false);
|
|
128
|
+
}
|
|
78
129
|
for (const agent of selected) {
|
|
79
130
|
console.log(`[ruler] Applying rules for ${agent.getName()}...`);
|
|
80
|
-
|
|
131
|
+
const agentConfig = config.agentConfigs[agent.getName()];
|
|
132
|
+
await agent.applyRulerConfig(concatenated, projectRoot, agentConfig);
|
|
133
|
+
const dest = await (0, mcp_1.getNativeMcpPath)(agent.getName(), projectRoot);
|
|
134
|
+
const enabled = cliMcpEnabled &&
|
|
135
|
+
(agentConfig?.mcp?.enabled ?? config.mcp?.enabled ?? true);
|
|
136
|
+
if (dest && rulerMcpJson != null && enabled) {
|
|
137
|
+
const strategy = cliMcpStrategy ??
|
|
138
|
+
agentConfig?.mcp?.strategy ??
|
|
139
|
+
config.mcp?.strategy ??
|
|
140
|
+
'merge';
|
|
141
|
+
const existing = await (0, mcp_1.readNativeMcp)(dest);
|
|
142
|
+
const merged = (0, merge_1.mergeMcp)(existing, rulerMcpJson, strategy);
|
|
143
|
+
await (0, mcp_1.writeNativeMcp)(dest, merged);
|
|
144
|
+
}
|
|
81
145
|
}
|
|
82
146
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergeMcp = mergeMcp;
|
|
4
|
+
/**
|
|
5
|
+
* Merge native and incoming MCP server configurations according to strategy.
|
|
6
|
+
* @param base Existing native MCP config object.
|
|
7
|
+
* @param incoming Ruler MCP config object.
|
|
8
|
+
* @param strategy Merge strategy: 'merge' to union servers, 'overwrite' to replace.
|
|
9
|
+
* @returns Merged MCP config object.
|
|
10
|
+
*/
|
|
11
|
+
function mergeMcp(base, incoming, strategy) {
|
|
12
|
+
if (strategy === 'overwrite') {
|
|
13
|
+
return incoming;
|
|
14
|
+
}
|
|
15
|
+
const baseServers = base.mcpServers || {};
|
|
16
|
+
const incomingServers = incoming.mcpServers || {};
|
|
17
|
+
return {
|
|
18
|
+
...base,
|
|
19
|
+
mcpServers: { ...baseServers, ...incomingServers },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateMcp = validateMcp;
|
|
4
|
+
/**
|
|
5
|
+
* Validate the structure of the Ruler MCP JSON config.
|
|
6
|
+
* Minimal validation: ensure 'mcpServers' property exists and is an object.
|
|
7
|
+
* @param data Parsed JSON object from .ruler/mcp.json.
|
|
8
|
+
* @throws Error if validation fails.
|
|
9
|
+
*/
|
|
10
|
+
function validateMcp(data) {
|
|
11
|
+
if (!data ||
|
|
12
|
+
typeof data !== 'object' ||
|
|
13
|
+
!('mcpServers' in data) ||
|
|
14
|
+
typeof data.mcpServers !== 'object') {
|
|
15
|
+
throw new Error('[ruler] Invalid .ruler/mcp.json: must contain an object property "mcpServers"');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
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.getNativeMcpPath = getNativeMcpPath;
|
|
37
|
+
exports.readNativeMcp = readNativeMcp;
|
|
38
|
+
exports.writeNativeMcp = writeNativeMcp;
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const fs_1 = require("fs");
|
|
42
|
+
/** Determine the native MCP config path for a given agent. */
|
|
43
|
+
async function getNativeMcpPath(adapterName, projectRoot) {
|
|
44
|
+
const home = os.homedir();
|
|
45
|
+
const candidates = [];
|
|
46
|
+
switch (adapterName) {
|
|
47
|
+
case 'GitHub Copilot':
|
|
48
|
+
candidates.push(path.join(projectRoot, '.vscode', 'mcp.json'));
|
|
49
|
+
break;
|
|
50
|
+
case 'Visual Studio':
|
|
51
|
+
candidates.push(path.join(projectRoot, '.mcp.json'));
|
|
52
|
+
candidates.push(path.join(projectRoot, '.vs', 'mcp.json'));
|
|
53
|
+
break;
|
|
54
|
+
case 'Cursor':
|
|
55
|
+
candidates.push(path.join(projectRoot, '.cursor', 'mcp.json'));
|
|
56
|
+
candidates.push(path.join(home, '.cursor', 'mcp.json'));
|
|
57
|
+
break;
|
|
58
|
+
case 'Windsurf':
|
|
59
|
+
candidates.push(path.join(home, '.codeium', 'windsurf', 'mcp_config.json'));
|
|
60
|
+
break;
|
|
61
|
+
case 'Claude Code':
|
|
62
|
+
candidates.push(path.join(projectRoot, 'claude_desktop_config.json'));
|
|
63
|
+
break;
|
|
64
|
+
case 'OpenAI Codex CLI':
|
|
65
|
+
candidates.push(path.join(home, '.codex', 'config.json'));
|
|
66
|
+
break;
|
|
67
|
+
case 'Aider':
|
|
68
|
+
candidates.push(path.join(projectRoot, '.mcp.json'));
|
|
69
|
+
break;
|
|
70
|
+
default:
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
for (const p of candidates) {
|
|
74
|
+
try {
|
|
75
|
+
await fs_1.promises.access(p);
|
|
76
|
+
return p;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// continue
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// default to first candidate if none exist
|
|
83
|
+
return candidates.length > 0 ? candidates[0] : null;
|
|
84
|
+
}
|
|
85
|
+
/** Read native MCP config from disk, or return empty object if missing/invalid. */
|
|
86
|
+
async function readNativeMcp(filePath) {
|
|
87
|
+
try {
|
|
88
|
+
const text = await fs_1.promises.readFile(filePath, 'utf8');
|
|
89
|
+
return JSON.parse(text);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return {};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** Write native MCP config to disk, creating parent directories as needed. */
|
|
96
|
+
async function writeNativeMcp(filePath, data) {
|
|
97
|
+
await fs_1.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
98
|
+
const text = JSON.stringify(data, null, 2) + '\n';
|
|
99
|
+
await fs_1.promises.writeFile(filePath, text, 'utf8');
|
|
100
|
+
}
|
package/dist/types.js
ADDED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intellectronica/ruler",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Ruler — apply the same rules to all coding agents",
|
|
5
5
|
"main": "dist/lib.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"lint": "eslint \"src/**/*.{ts,tsx}\"",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"bugs": {
|
|
33
33
|
"url": "https://github.com/intellectronica/ruler/issues"
|
|
34
34
|
},
|
|
35
|
-
"homepage": "https://
|
|
35
|
+
"homepage": "https://ai.intellectronica.net/ruler",
|
|
36
36
|
"files": [
|
|
37
37
|
"dist",
|
|
38
38
|
"README.md",
|
|
@@ -53,10 +53,11 @@
|
|
|
53
53
|
"jest": "^29.7.0",
|
|
54
54
|
"prettier": "^3.5.3",
|
|
55
55
|
"ts-jest": "^29.3.4",
|
|
56
|
-
"typescript": "^5.8.3"
|
|
57
|
-
"yargs": "^17.7.2"
|
|
56
|
+
"typescript": "^5.8.3"
|
|
58
57
|
},
|
|
59
58
|
"dependencies": {
|
|
60
|
-
"js-yaml": "^4.1.0"
|
|
59
|
+
"js-yaml": "^4.1.0",
|
|
60
|
+
"toml": "^3.0.0",
|
|
61
|
+
"yargs": "^17.7.2"
|
|
61
62
|
}
|
|
62
63
|
}
|