@intellectronica/ruler 0.2.18 → 0.3.0

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.
Files changed (47) hide show
  1. package/README.md +190 -30
  2. package/dist/agents/AbstractAgent.js +82 -0
  3. package/dist/agents/AgentsMdAgent.js +82 -0
  4. package/dist/agents/AiderAgent.js +29 -9
  5. package/dist/agents/AmpAgent.js +13 -0
  6. package/dist/agents/AugmentCodeAgent.js +10 -12
  7. package/dist/agents/ClaudeAgent.js +9 -9
  8. package/dist/agents/ClineAgent.js +3 -9
  9. package/dist/agents/CodexCliAgent.js +27 -21
  10. package/dist/agents/CopilotAgent.js +9 -10
  11. package/dist/agents/CrushAgent.js +6 -0
  12. package/dist/agents/CursorAgent.js +13 -5
  13. package/dist/agents/FirebaseAgent.js +2 -8
  14. package/dist/agents/GeminiCliAgent.js +31 -22
  15. package/dist/agents/GooseAgent.js +2 -10
  16. package/dist/agents/JulesAgent.js +3 -44
  17. package/dist/agents/JunieAgent.js +2 -9
  18. package/dist/agents/KiloCodeAgent.js +8 -9
  19. package/dist/agents/KiroAgent.js +50 -0
  20. package/dist/agents/OpenCodeAgent.js +50 -11
  21. package/dist/agents/OpenHandsAgent.js +8 -9
  22. package/dist/agents/QwenCodeAgent.js +83 -0
  23. package/dist/agents/WarpAgent.js +61 -0
  24. package/dist/agents/WindsurfAgent.js +9 -10
  25. package/dist/agents/ZedAgent.js +132 -0
  26. package/dist/agents/agent-utils.js +37 -0
  27. package/dist/agents/index.js +53 -0
  28. package/dist/cli/commands.js +48 -242
  29. package/dist/cli/handlers.js +176 -0
  30. package/dist/constants.js +9 -2
  31. package/dist/core/ConfigLoader.js +1 -1
  32. package/dist/core/FileSystemUtils.js +51 -4
  33. package/dist/core/RuleProcessor.js +15 -3
  34. package/dist/core/UnifiedConfigLoader.js +357 -0
  35. package/dist/core/UnifiedConfigTypes.js +2 -0
  36. package/dist/core/agent-selection.js +52 -0
  37. package/dist/core/apply-engine.js +302 -0
  38. package/dist/core/config-utils.js +30 -0
  39. package/dist/core/hash.js +24 -0
  40. package/dist/core/revert-engine.js +413 -0
  41. package/dist/lib.js +20 -312
  42. package/dist/mcp/capabilities.js +51 -0
  43. package/dist/mcp/propagateOpenCodeMcp.js +30 -31
  44. package/dist/mcp/propagateOpenHandsMcp.js +101 -17
  45. package/dist/paths/mcp.js +7 -3
  46. package/dist/revert.js +96 -479
  47. package/package.json +2 -1
package/README.md CHANGED
@@ -1,11 +1,27 @@
1
1
  # Ruler: Centralise Your AI Coding Assistant Instructions
2
2
 
3
- [![CI](https://github.com/intellectronica/ruler/actions/workflows/ci.yml/badge.svg)](https://github.com/intellectronica/ruler/actions/workflows/ci.yml)
4
- [![npm version](https://badge.fury.io/js/%40intellectronica%2Fruler.svg)](https://badge.fury.io/js/%40intellectronica%2Fruler)
5
- ![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)
6
-
7
- - **GitHub**: [intellectronica/ruler](https://github.com/intellectronica/ruler)
8
- - **NPM**: [@intellectronica/ruler](https://www.npmjs.com/package/@intellectronica/ruler)
3
+ <table style="width:100%">
4
+ <tr>
5
+ <td style="vertical-align: top;">
6
+ <p>
7
+ <a href="https://github.com/intellectronica/ruler/actions/workflows/ci.yml"><img src="https://github.com/intellectronica/ruler/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
8
+ <a href="https://www.npmjs.com/package/@intellectronica/ruler"><img src="https://badge.fury.io/js/%40intellectronica%2Fruler.svg" alt="npm version"></a>
9
+ <img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT">
10
+ </p>
11
+ <ul>
12
+ <li><strong>GitHub</strong>: <a href="https://github.com/intellectronica/ruler">intellectronica/ruler</a></li>
13
+ <li><strong>NPM</strong>: <a href="https://www.npmjs.com/package/@intellectronica/ruler">@intellectronica/ruler</a></li>
14
+ </ul>
15
+ <hr />
16
+ <p>
17
+ <em>Animation by <a href="https://isaacflath.com/">Isaac Flath</a> of <strong><a href="https://elite-ai-assisted-coding.dev/">Elite AI-Assisted Coding</a></strong></em> ➡︎
18
+ </p>
19
+ </td>
20
+ <td style="vertical-align: top; width:33%;">
21
+ <img src="img/ruler-short.gif" alt="Ruler demo" style="width:300px; height:auto; display:block;" />
22
+ </td>
23
+ </tr>
24
+ </table>
9
25
 
10
26
  ---
11
27
 
@@ -36,24 +52,30 @@ Ruler solves this by providing a **single source of truth** for all your AI agen
36
52
 
37
53
  ## Supported AI Agents
38
54
 
39
- | Agent | Rules File(s) | MCP Configuration |
55
+ | Agent | Rules File(s) | MCP Configuration / Notes |
40
56
  | ---------------- | ------------------------------------------------ | --------------------------------------------------- |
57
+ | AGENTS.md | `AGENTS.md` | (pseudo-agent ensuring root `AGENTS.md` exists) |
41
58
  | GitHub Copilot | `.github/copilot-instructions.md` | `.vscode/mcp.json` |
42
59
  | Claude Code | `CLAUDE.md` | `.mcp.json` |
43
- | OpenAI Codex CLI | `AGENTS.md` | `.codex/config.toml`, `~/.codex/config.json` |
60
+ | OpenAI Codex CLI | `AGENTS.md` | `.codex/config.toml` |
44
61
  | Jules | `AGENTS.md` | - |
45
- | Cursor | `.cursor/rules/ruler_cursor_instructions.mdc` | `.cursor/mcp.json`, `~/.cursor/mcp.json` |
46
- | Windsurf | `.windsurf/rules/ruler_windsurf_instructions.md` | `~/.codeium/windsurf/mcp_config.json` |
62
+ | Cursor | `.cursor/rules/ruler_cursor_instructions.mdc` | `.cursor/mcp.json` |
63
+ | Windsurf | `.windsurf/rules/ruler_windsurf_instructions.md` | - |
47
64
  | Cline | `.clinerules` | - |
48
- | Aider | `ruler_aider_instructions.md`, `.aider.conf.yml` | `.mcp.json` |
65
+ | Amp | `AGENTS.md` | - |
66
+ | Aider | `AGENTS.md`, `.aider.conf.yml` | `.mcp.json` |
49
67
  | Firebase Studio | `.idx/airules.md` | - |
50
- | Open Hands | `.openhands/microagents/repo.md` | `.openhands/config.toml` |
51
- | Gemini CLI | `GEMINI.md` | `.gemini/settings.json` |
68
+ | Open Hands | `.openhands/microagents/repo.md` | `.openhands/config.toml` |
69
+ | Gemini CLI | `AGENTS.md` | `.gemini/settings.json` |
52
70
  | Junie | `.junie/guidelines.md` | - |
53
71
  | AugmentCode | `.augment/rules/ruler_augment_instructions.md` | `.vscode/settings.json` |
54
72
  | Kilo Code | `.kilocode/rules/ruler_kilocode_instructions.md` | `.kilocode/mcp.json` |
55
- | OpenCode | `AGENTS.md` | `opencode.json`, `~/.config/opencode/opencode.json` |
73
+ | opencode | `AGENTS.md` | `opencode.json` |
56
74
  | Goose | `.goosehints` | - |
75
+ | Qwen Code | `AGENTS.md` | `.qwen/settings.json` |
76
+ | Zed | `AGENTS.md` | `.zed/settings.json` (project root, never $HOME) |
77
+ | Warp | `WARP.md` | - |
78
+ | Kiro | `.kiro/steering/ruler_kiro_instructions.md` | - |
57
79
 
58
80
  ## Getting Started
59
81
 
@@ -80,10 +102,10 @@ npx @intellectronica/ruler apply
80
102
  1. Navigate to your project's root directory
81
103
  2. Run `ruler init`
82
104
  3. This creates:
83
- - `.ruler/` directory
84
- - `.ruler/instructions.md`: A starter Markdown file for your rules
85
- - `.ruler/ruler.toml`: The main configuration file for Ruler
86
- - `.ruler/mcp.json`: An example MCP server configuration
105
+ - `.ruler/` directory
106
+ - `.ruler/AGENTS.md`: The primary starter Markdown file for your rules
107
+ - `.ruler/ruler.toml`: The main configuration file for Ruler (now contains sample MCP server sections; legacy `.ruler/mcp.json` no longer scaffolded)
108
+ - (Optional legacy fallback) If you previously used `.ruler/instructions.md`, it is still respected when `AGENTS.md` is absent. (The prior runtime warning was removed.)
87
109
 
88
110
  Additionally, you can create a global configuration to use when no local `.ruler/` directory is found:
89
111
 
@@ -99,11 +121,18 @@ The global configuration will be created to `$XDG_CONFIG_HOME/ruler` (default: `
99
121
 
100
122
  This is your central hub for all AI agent instructions:
101
123
 
102
- - **Rule Files (`*.md`)**: Discovered recursively from `.ruler/` or `$XDG_CONFIG_HOME/ruler` and alphabetically concatenated
124
+ - **Primary File Order & Precedence**:
125
+ 1. A repository root `AGENTS.md` (outside `.ruler/`) if present (highest precedence, prepended)
126
+ 2. `.ruler/AGENTS.md` (new default starter file)
127
+ 3. Legacy `.ruler/instructions.md` (only if `.ruler/AGENTS.md` absent; no longer emits a deprecation warning)
128
+ 4. Remaining discovered `.md` files under `.ruler/` (and subdirectories) in sorted order
129
+ - **Rule Files (`*.md`)**: Discovered recursively from `.ruler/` or `$XDG_CONFIG_HOME/ruler` and concatenated in the order above
103
130
  - **Concatenation Marker**: Each file's content is prepended with `--- Source: <relative_path_to_md_file> ---` for traceability
104
131
  - **`ruler.toml`**: Master configuration for Ruler's behavior, agent selection, and output paths
105
132
  - **`mcp.json`**: Shared MCP server settings
106
133
 
134
+ This ordering lets you keep a short, high-impact root `AGENTS.md` (e.g. executive project summary) while housing detailed guidance inside `.ruler/`.
135
+
107
136
  ### Best Practices for Rule Files
108
137
 
109
138
  **Granularity**: Break down complex instructions into focused `.md` files:
@@ -150,7 +179,7 @@ The `apply` command looks for `.ruler/` in the current directory tree, reading t
150
179
  | Option | Description |
151
180
  | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
152
181
  | `--project-root <path>` | Path to your project's root (default: current directory) |
153
- | `--agents <agent1,agent2,...>` | Comma-separated list of agent names to target (copilot, claude, codex, cursor, windsurf, cline, aider, firebase, gemini-cli, junie, augmentcode, kilocode) |
182
+ | `--agents <agent1,agent2,...>` | Comma-separated list of agent names to target (agentsmd, amp, copilot, claude, codex, cursor, windsurf, cline, aider, firebase, gemini-cli, junie, augmentcode, kilocode, warp) |
154
183
  | `--config <path>` | Path to a custom `ruler.toml` configuration file |
155
184
  | `--mcp` / `--with-mcp` | Enable applying MCP server configurations (default: true) |
156
185
  | `--no-mcp` | Disable applying MCP server configurations |
@@ -180,6 +209,12 @@ ruler apply --agents copilot,claude
180
209
  ruler apply --agents firebase
181
210
  ```
182
211
 
212
+ **Apply rules only to Warp:**
213
+
214
+ ```bash
215
+ ruler apply --agents warp
216
+ ```
217
+
183
218
  **Use a specific configuration file:**
184
219
 
185
220
  ```bash
@@ -222,7 +257,7 @@ ruler revert [options]
222
257
  | Option | Description |
223
258
  | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
224
259
  | `--project-root <path>` | Path to your project's root (default: current directory) |
225
- | `--agents <agent1,agent2,...>` | Comma-separated list of agent names to revert (copilot, claude, codex, cursor, windsurf, cline, aider, firebase, gemini-cli, junie, kilocode, opencode) |
260
+ | `--agents <agent1,agent2,...>` | Comma-separated list of agent names to revert (agentsmd, amp, copilot, claude, codex, cursor, windsurf, cline, aider, firebase, gemini-cli, junie, kilocode, opencode, warp) |
226
261
  | `--config <path>` | Path to a custom `ruler.toml` configuration file |
227
262
  | `--keep-backups` | Keep backup files (.bak) after restoration (default: false) |
228
263
  | `--dry-run` | Preview changes without actually reverting files |
@@ -281,6 +316,21 @@ enabled = true
281
316
  # Global merge strategy: 'merge' or 'overwrite' (default: 'merge')
282
317
  merge_strategy = "merge"
283
318
 
319
+ # --- MCP Server Definitions ---
320
+ [mcp_servers.filesystem]
321
+ command = "npx"
322
+ args = ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/project"]
323
+
324
+ [mcp_servers.git]
325
+ command = "npx"
326
+ args = ["-y", "@modelcontextprotocol/server-git", "--repository", "."]
327
+
328
+ [mcp_servers.remote_api]
329
+ url = "https://api.example.com"
330
+
331
+ [mcp_servers.remote_api.headers]
332
+ Authorization = "Bearer your-token"
333
+
284
334
  # --- Global .gitignore Configuration ---
285
335
  [gitignore]
286
336
  # Enable/disable automatic .gitignore updates (default: true)
@@ -297,7 +347,7 @@ output_path = "CLAUDE.md"
297
347
 
298
348
  [agents.aider]
299
349
  enabled = true
300
- output_path_instructions = "ruler_aider_instructions.md"
350
+ output_path_instructions = "AGENTS.md"
301
351
  output_path_config = ".aider.conf.yml"
302
352
 
303
353
  # OpenAI Codex CLI agent and MCP config
@@ -337,6 +387,10 @@ enabled = false
337
387
  [agents.kilocode]
338
388
  enabled = true
339
389
  output_path = ".kilocode/rules/ruler_kilocode_instructions.md"
390
+
391
+ [agents.warp]
392
+ enabled = true
393
+ output_path = "WARP.md"
340
394
  ```
341
395
 
342
396
  ### Configuration Precedence
@@ -349,9 +403,36 @@ output_path = ".kilocode/rules/ruler_kilocode_instructions.md"
349
403
 
350
404
  MCP provides broader context to AI models through server configurations. Ruler can manage and distribute these settings across compatible agents.
351
405
 
352
- ### `.ruler/mcp.json`
406
+ ### TOML Configuration (Recommended)
407
+
408
+ You can now define MCP servers directly in `ruler.toml` using the `[mcp_servers.<name>]` syntax:
409
+
410
+ ```toml
411
+ # Global MCP behavior
412
+ [mcp]
413
+ enabled = true
414
+ merge_strategy = "merge" # or "overwrite"
415
+
416
+ # Local (stdio) server
417
+ [mcp_servers.filesystem]
418
+ command = "npx"
419
+ args = ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/project"]
420
+
421
+ [mcp_servers.filesystem.env]
422
+ API_KEY = "your-api-key"
423
+
424
+ # Remote server
425
+ [mcp_servers.search]
426
+ url = "https://mcp.example.com"
427
+
428
+ [mcp_servers.search.headers]
429
+ Authorization = "Bearer your-token"
430
+ "X-API-Version" = "v1"
431
+ ```
432
+
433
+ ### Legacy `.ruler/mcp.json` (Deprecated)
353
434
 
354
- Define your project's MCP servers:
435
+ For backward compatibility, you can still use the JSON format; a warning is issued encouraging migration to TOML. The file is no longer created during `ruler init`.
355
436
 
356
437
  ```json
357
438
  {
@@ -372,8 +453,37 @@ Define your project's MCP servers:
372
453
  }
373
454
  ```
374
455
 
456
+ ### Configuration Precedence
457
+
458
+ When both TOML and JSON configurations are present:
459
+ 1. **TOML servers take precedence** over JSON servers with the same name
460
+ 2. **Servers are merged** from both sources (unless using overwrite strategy)
461
+ 3. **Deprecation warning** is shown encouraging migration to TOML (warning shown once per run)
462
+
463
+ ### Server Types
464
+
465
+ **Local/stdio servers** require a `command` field:
466
+ ```toml
467
+ [mcp_servers.local_server]
468
+ command = "node"
469
+ args = ["server.js"]
470
+
471
+ [mcp_servers.local_server.env]
472
+ DEBUG = "1"
473
+ ```
474
+
475
+ **Remote servers** require a `url` field (headers optional; bearer Authorization token auto-extracted for OpenHands when possible):
476
+ ```toml
477
+ [mcp_servers.remote_server]
478
+ url = "https://api.example.com"
479
+
480
+ [mcp_servers.remote_server.headers]
481
+ Authorization = "Bearer token"
482
+ ```
483
+
484
+ Ruler uses this configuration with the `merge` (default) or `overwrite` strategy, controlled by `ruler.toml` or CLI flags.
375
485
 
376
- Ruler uses this file with the `merge` (default) or `overwrite` strategy, controlled by `ruler.toml` or CLI flags.
486
+ **Home Directory Safety:** Ruler never writes MCP configuration files outside your project root. Any historical references to user home directories (e.g. `~/.codeium/windsurf/mcp_config.json` or `~/.zed/settings.json`) have been removed; only project-local paths are targeted.
377
487
 
378
488
  **Note for OpenAI Codex CLI:** To apply the local Codex CLI MCP configuration, set the `CODEX_HOME` environment variable to your project’s `.codex` directory:
379
489
  ```bash
@@ -391,7 +501,7 @@ Ruler automatically manages your `.gitignore` file to keep generated agent confi
391
501
  - Preserves existing content outside this block
392
502
  - Sorts paths alphabetically and uses relative POSIX-style paths
393
503
 
394
- ### Example `.gitignore` Section
504
+ ### Example `.gitignore` Section (sample - actual list depends on enabled agents)
395
505
 
396
506
  ```gitignore
397
507
  # Your existing rules
@@ -406,7 +516,7 @@ node_modules/
406
516
  .windsurf/rules/ruler_windsurf_instructions.md
407
517
  AGENTS.md
408
518
  CLAUDE.md
409
- ruler_aider_instructions.md
519
+ AGENTS.md
410
520
  # END Ruler Generated Files
411
521
 
412
522
  dist/
@@ -428,7 +538,7 @@ cd your-project
428
538
  ruler init
429
539
 
430
540
  # Edit the generated files
431
- # - Add your coding guidelines to .ruler/instructions.md
541
+ # - Add your coding guidelines to .ruler/AGENTS.md (or keep adding additional .md files)
432
542
  # - Customize .ruler/ruler.toml if needed
433
543
 
434
544
  # Apply rules to all AI agents
@@ -546,8 +656,20 @@ A: Ruler creates backups with `.bak` extension before overwriting any existing f
546
656
  **Q: Can I run Ruler in CI/CD pipelines?**
547
657
  A: Yes! Use `ruler apply --no-gitignore` in CI to avoid modifying `.gitignore`. See the GitHub Actions example above.
548
658
 
549
- **Q: How do I migrate from version 0.1.x to 0.2.0?**
550
- A: Version 0.2.0 is backward compatible. Your existing `.ruler/` directory and `ruler.toml` will continue to work. New features like verbose logging and improved error messages are opt-in.
659
+ **Q: How do I migrate from older versions using `instructions.md`?**
660
+ A: Simply rename `.ruler/instructions.md` to `.ruler/AGENTS.md` (recommended). If you keep the legacy file and omit `AGENTS.md`, Ruler will still use it (without emitting the old deprecation warning). Having both causes `AGENTS.md` to take precedence; the legacy file is still concatenated afterward.
661
+
662
+ **Q: How does OpenHands MCP propagation classify servers?**
663
+ A: Local stdio servers become `stdio_servers`. Remote URLs containing `/sse` are classified as `sse_servers`; others become `shttp_servers`. Bearer tokens in an `Authorization` header are extracted into `api_key` where possible.
664
+
665
+ **Q: Where is Zed configuration written now?**
666
+ A: Ruler writes a `settings.json` in the project root (not the user home dir) and transforms MCP server definitions to Zed's `context_servers` format including `source: "custom"`.
667
+
668
+ **Q: What changed about MCP initialization?**
669
+ A: `ruler init` now only adds example MCP server sections to `ruler.toml` instead of creating `.ruler/mcp.json`. The JSON file is still consumed if present, but TOML servers win on name conflicts.
670
+
671
+ **Q: Is Kiro supported?**
672
+ A: Yes. Kiro receives concatenated rules at `.kiro/steering/ruler_kiro_instructions.md`.
551
673
 
552
674
  ## Development
553
675
 
@@ -602,5 +724,43 @@ MIT
602
724
 
603
725
  ---
604
726
 
727
+ ## Development and Testing
728
+
729
+ ### Running Tests
730
+
731
+ The project includes comprehensive test coverage with unit, integration, and end-to-end tests:
732
+
733
+ ```bash
734
+ # Run all tests
735
+ npm test
736
+
737
+ # Run with coverage
738
+ npm run test:coverage
739
+
740
+ # Run integration tests specifically
741
+ npm run test:integration
742
+
743
+ # Run tests in watch mode
744
+ npm run test:watch
745
+ ```
746
+
747
+ ### Integration Testing
748
+
749
+ The project includes comprehensive integration tests that validate the complete CLI workflow:
750
+
751
+ - **`npm run test:integration`**: Runs a full end-to-end integration test that:
752
+ 1. Creates a temporary test directory
753
+ 2. Runs `ruler init` to set up the initial structure
754
+ 3. Creates custom `ruler.toml` with MCP servers (both stdio and remote)
755
+ 4. Creates sample `AGENTS.md` and additional markdown files for concatenation
756
+ 5. Runs `ruler apply` to generate all agent configuration files
757
+ 6. Inspects and validates all generated files contain expected content
758
+ 7. Outputs the content of all generated files for manual verification
759
+ 8. Validates MCP server configurations were properly applied
760
+
761
+ This integration test ensures the entire CLI workflow functions correctly and can be used for manual testing or CI validation.
762
+
763
+ ---
764
+
605
765
  © Eleanor Berger
606
766
  [ai.intellectronica.net](https://ai.intellectronica.net/)
@@ -0,0 +1,82 @@
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.AbstractAgent = void 0;
37
+ const path = __importStar(require("path"));
38
+ const FileSystemUtils_1 = require("../core/FileSystemUtils");
39
+ /**
40
+ * Abstract base class for agents that write to a single configuration file.
41
+ * Implements common logic for applying ruler configuration.
42
+ */
43
+ class AbstractAgent {
44
+ /**
45
+ * Applies the concatenated ruler rules to the agent's configuration.
46
+ * This implementation handles the common pattern of:
47
+ * 1. Determining the output path
48
+ * 2. Ensuring the parent directory exists
49
+ * 3. Backing up the existing file
50
+ * 4. Writing the new content
51
+ */
52
+ async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
53
+ agentConfig) {
54
+ const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
55
+ const absolutePath = path.resolve(projectRoot, output);
56
+ await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(absolutePath));
57
+ await (0, FileSystemUtils_1.backupFile)(absolutePath);
58
+ await (0, FileSystemUtils_1.writeGeneratedFile)(absolutePath, concatenatedRules);
59
+ }
60
+ /**
61
+ * Returns the specific key to be used for the server object in MCP JSON.
62
+ * Defaults to 'mcpServers' if not overridden.
63
+ */
64
+ getMcpServerKey() {
65
+ return 'mcpServers';
66
+ }
67
+ /**
68
+ * Returns whether this agent supports MCP STDIO servers.
69
+ * Defaults to false if not overridden.
70
+ */
71
+ supportsMcpStdio() {
72
+ return false;
73
+ }
74
+ /**
75
+ * Returns whether this agent supports MCP remote servers.
76
+ * Defaults to false if not overridden.
77
+ */
78
+ supportsMcpRemote() {
79
+ return false;
80
+ }
81
+ }
82
+ exports.AbstractAgent = AbstractAgent;
@@ -0,0 +1,82 @@
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.AgentsMdAgent = void 0;
37
+ const path = __importStar(require("path"));
38
+ const fs_1 = require("fs");
39
+ const AbstractAgent_1 = require("./AbstractAgent");
40
+ const FileSystemUtils_1 = require("../core/FileSystemUtils");
41
+ /**
42
+ * Pseudo-agent that ensures the concatenated rules are written to root-level `AGENTS.md`.
43
+ * Does not participate in MCP propagation. Idempotent: only writes (and creates a backup)
44
+ * when content differs from existing file.
45
+ */
46
+ class AgentsMdAgent extends AbstractAgent_1.AbstractAgent {
47
+ getIdentifier() {
48
+ return 'agentsmd';
49
+ }
50
+ getName() {
51
+ return 'AgentsMd';
52
+ }
53
+ getDefaultOutputPath(projectRoot) {
54
+ return path.join(projectRoot, 'AGENTS.md');
55
+ }
56
+ async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
57
+ agentConfig) {
58
+ const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
59
+ const absolutePath = path.resolve(projectRoot, output);
60
+ await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(absolutePath));
61
+ // Read existing content if present and skip write if identical
62
+ let existing = null;
63
+ try {
64
+ existing = await fs_1.promises.readFile(absolutePath, 'utf8');
65
+ }
66
+ catch {
67
+ existing = null;
68
+ }
69
+ if (existing !== null && existing === concatenatedRules) {
70
+ // No change; skip backup/write for idempotency
71
+ return;
72
+ }
73
+ // Backup (only if file existed) then write new content
74
+ await (0, FileSystemUtils_1.backupFile)(absolutePath);
75
+ await (0, FileSystemUtils_1.writeGeneratedFile)(absolutePath, concatenatedRules);
76
+ }
77
+ getMcpServerKey() {
78
+ // No MCP configuration for this pseudo-agent
79
+ return '';
80
+ }
81
+ }
82
+ exports.AgentsMdAgent = AgentsMdAgent;
@@ -35,25 +35,32 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.AiderAgent = void 0;
37
37
  const path = __importStar(require("path"));
38
+ const AgentsMdAgent_1 = require("./AgentsMdAgent");
38
39
  const FileSystemUtils_1 = require("../core/FileSystemUtils");
39
40
  const fs = __importStar(require("fs/promises"));
40
41
  const yaml = __importStar(require("js-yaml"));
41
42
  /**
42
- * Aider agent adapter (stub implementation).
43
+ * Aider agent adapter that uses AGENTS.md for instructions and .aider.conf.yml for configuration.
43
44
  */
44
45
  class AiderAgent {
46
+ constructor() {
47
+ this.agentsMdAgent = new AgentsMdAgent_1.AgentsMdAgent();
48
+ }
45
49
  getIdentifier() {
46
50
  return 'aider';
47
51
  }
48
52
  getName() {
49
53
  return 'Aider';
50
54
  }
51
- async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
52
- agentConfig) {
53
- const mdPath = agentConfig?.outputPathInstructions ??
54
- this.getDefaultOutputPath(projectRoot).instructions;
55
- await (0, FileSystemUtils_1.backupFile)(mdPath);
56
- await (0, FileSystemUtils_1.writeGeneratedFile)(mdPath, concatenatedRules);
55
+ async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, agentConfig) {
56
+ // First perform idempotent AGENTS.md write via composed AgentsMdAgent
57
+ await this.agentsMdAgent.applyRulerConfig(concatenatedRules, projectRoot, null, {
58
+ // Preserve explicit outputPath precedence semantics if provided.
59
+ outputPath: agentConfig?.outputPath ||
60
+ agentConfig?.outputPathInstructions ||
61
+ undefined,
62
+ });
63
+ // Now handle .aider.conf.yml configuration
57
64
  const cfgPath = agentConfig?.outputPathConfig ??
58
65
  this.getDefaultOutputPath(projectRoot).config;
59
66
  let doc = {};
@@ -69,7 +76,11 @@ class AiderAgent {
69
76
  if (!Array.isArray(doc.read)) {
70
77
  doc.read = [];
71
78
  }
72
- const name = path.basename(mdPath);
79
+ // Determine the actual agents file path (AGENTS.md by default, or custom path)
80
+ const agentsPath = agentConfig?.outputPath ||
81
+ agentConfig?.outputPathInstructions ||
82
+ this.getDefaultOutputPath(projectRoot).instructions;
83
+ const name = path.basename(agentsPath);
73
84
  if (!doc.read.includes(name)) {
74
85
  doc.read.push(name);
75
86
  }
@@ -78,9 +89,18 @@ class AiderAgent {
78
89
  }
79
90
  getDefaultOutputPath(projectRoot) {
80
91
  return {
81
- instructions: path.join(projectRoot, 'ruler_aider_instructions.md'),
92
+ instructions: path.join(projectRoot, 'AGENTS.md'),
82
93
  config: path.join(projectRoot, '.aider.conf.yml'),
83
94
  };
84
95
  }
96
+ getMcpServerKey() {
97
+ return this.agentsMdAgent.getMcpServerKey();
98
+ }
99
+ supportsMcpStdio() {
100
+ return true;
101
+ }
102
+ supportsMcpRemote() {
103
+ return true;
104
+ }
85
105
  }
86
106
  exports.AiderAgent = AiderAgent;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AmpAgent = void 0;
4
+ const AgentsMdAgent_1 = require("./AgentsMdAgent");
5
+ class AmpAgent extends AgentsMdAgent_1.AgentsMdAgent {
6
+ getIdentifier() {
7
+ return 'amp';
8
+ }
9
+ getName() {
10
+ return 'Amp';
11
+ }
12
+ }
13
+ exports.AmpAgent = AmpAgent;
@@ -36,7 +36,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.AugmentCodeAgent = void 0;
37
37
  const path = __importStar(require("path"));
38
38
  const FileSystemUtils_1 = require("../core/FileSystemUtils");
39
- const settings_1 = require("../vscode/settings");
40
39
  /**
41
40
  * AugmentCode agent adapter.
42
41
  * Generates ruler_augment_instructions.md configuration file and updates VSCode settings.json with MCP server configuration.
@@ -48,24 +47,23 @@ class AugmentCodeAgent {
48
47
  getName() {
49
48
  return 'AugmentCode';
50
49
  }
51
- async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, agentConfig) {
50
+ async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
51
+ agentConfig) {
52
52
  const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
53
53
  await (0, FileSystemUtils_1.backupFile)(output);
54
54
  await (0, FileSystemUtils_1.writeGeneratedFile)(output, concatenatedRules);
55
- if (rulerMcpJson) {
56
- const settingsPath = (0, settings_1.getVSCodeSettingsPath)(projectRoot);
57
- await (0, FileSystemUtils_1.backupFile)(settingsPath);
58
- const existingSettings = await (0, settings_1.readVSCodeSettings)(settingsPath);
59
- const augmentServers = (0, settings_1.transformRulerToAugmentMcp)(rulerMcpJson);
60
- const mergedSettings = (0, settings_1.mergeAugmentMcpServers)(existingSettings, augmentServers, agentConfig?.mcp?.strategy ?? 'merge');
61
- await (0, settings_1.writeVSCodeSettings)(settingsPath, mergedSettings);
62
- }
55
+ // AugmentCode does not support MCP servers
56
+ // MCP configuration is ignored for this agent
63
57
  }
64
58
  getDefaultOutputPath(projectRoot) {
65
59
  return path.join(projectRoot, '.augment', 'rules', 'ruler_augment_instructions.md');
66
60
  }
67
- getMcpServerKey() {
68
- return 'mcpServers';
61
+ // AugmentCode does not support MCP servers
62
+ supportsMcpStdio() {
63
+ return false;
64
+ }
65
+ supportsMcpRemote() {
66
+ return false;
69
67
  }
70
68
  }
71
69
  exports.AugmentCodeAgent = AugmentCodeAgent;