@intellectronica/ruler 0.3.42 → 0.3.43

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 (50) hide show
  1. package/README.md +97 -10
  2. package/dist/agents/AbstractAgent.js +3 -2
  3. package/dist/agents/AgentsMdAgent.js +3 -2
  4. package/dist/agents/AiderAgent.js +4 -3
  5. package/dist/agents/AmazonQCliAgent.js +6 -4
  6. package/dist/agents/AugmentCodeAgent.js +3 -2
  7. package/dist/agents/CodexCliAgent.js +1 -1
  8. package/dist/agents/CrushAgent.d.ts +1 -1
  9. package/dist/agents/CrushAgent.js +15 -6
  10. package/dist/agents/FirebenderAgent.js +5 -4
  11. package/dist/agents/GeminiCliAgent.d.ts +1 -0
  12. package/dist/agents/GeminiCliAgent.js +11 -5
  13. package/dist/agents/IAgent.d.ts +2 -0
  14. package/dist/agents/MistralVibeAgent.js +14 -3
  15. package/dist/agents/OpenCodeAgent.d.ts +1 -1
  16. package/dist/agents/OpenCodeAgent.js +10 -3
  17. package/dist/agents/QwenCodeAgent.d.ts +1 -0
  18. package/dist/agents/QwenCodeAgent.js +9 -3
  19. package/dist/agents/RooCodeAgent.js +3 -2
  20. package/dist/agents/ZedAgent.js +3 -3
  21. package/dist/constants.d.ts +1 -1
  22. package/dist/constants.js +1 -1
  23. package/dist/core/ConfigLoader.d.ts +2 -0
  24. package/dist/core/ConfigLoader.js +73 -6
  25. package/dist/core/FileSystemUtils.d.ts +4 -2
  26. package/dist/core/FileSystemUtils.js +120 -3
  27. package/dist/core/GitignoreUtils.d.ts +10 -0
  28. package/dist/core/GitignoreUtils.js +62 -31
  29. package/dist/core/SkillsProcessor.d.ts +2 -2
  30. package/dist/core/SkillsProcessor.js +46 -37
  31. package/dist/core/SubagentsProcessor.js +8 -5
  32. package/dist/core/UnifiedConfigLoader.js +54 -2
  33. package/dist/core/UnifiedConfigTypes.d.ts +3 -1
  34. package/dist/core/agent-selection.js +6 -4
  35. package/dist/core/apply-engine.d.ts +1 -0
  36. package/dist/core/apply-engine.js +38 -15
  37. package/dist/core/revert-engine.d.ts +2 -1
  38. package/dist/core/revert-engine.js +73 -26
  39. package/dist/lib.js +9 -6
  40. package/dist/mcp/merge.js +28 -26
  41. package/dist/mcp/propagateOpenCodeMcp.d.ts +1 -1
  42. package/dist/mcp/propagateOpenCodeMcp.js +10 -3
  43. package/dist/mcp/propagateOpenHandsMcp.d.ts +1 -1
  44. package/dist/mcp/propagateOpenHandsMcp.js +18 -7
  45. package/dist/paths/mcp.d.ts +1 -1
  46. package/dist/paths/mcp.js +11 -4
  47. package/dist/revert.js +27 -27
  48. package/dist/vscode/settings.d.ts +1 -1
  49. package/dist/vscode/settings.js +3 -3
  50. package/package.json +4 -3
package/dist/revert.js CHANGED
@@ -46,24 +46,23 @@ const agent_selection_1 = require("./core/agent-selection");
46
46
  const config_utils_1 = require("./core/config-utils");
47
47
  const GitignoreUtils_1 = require("./core/GitignoreUtils");
48
48
  const agents = agents_1.allAgents;
49
- const RULER_IGNORE_START_MARKER = '# START Ruler Generated Files';
50
- const RULER_IGNORE_END_MARKER = '# END Ruler Generated Files';
51
49
  const MANAGED_IGNORE_FILES = ['.gitignore', '.git/info/exclude'];
52
50
  /**
53
51
  * Reverts ruler configurations for selected AI agents.
54
52
  */
55
53
  async function revertAllAgentConfigs(projectRoot, includedAgents, configPath, keepBackups = false, verbose = false, dryRun = false, localOnly = false) {
56
- (0, constants_1.logVerbose)(`Loading configuration for revert from project root: ${projectRoot}`, verbose);
54
+ const rulerDir = await FileSystemUtils.findRulerDir(projectRoot, !localOnly);
55
+ if (!rulerDir) {
56
+ throw (0, constants_1.createRulerError)(`.ruler directory not found`, `Searched from: ${projectRoot}`);
57
+ }
58
+ const effectiveProjectRoot = FileSystemUtils.resolveProjectRootForRulerDir(projectRoot, rulerDir);
59
+ (0, constants_1.logVerbose)(`Loading configuration for revert from project root: ${effectiveProjectRoot}`, verbose);
57
60
  const config = await (0, ConfigLoader_1.loadConfig)({
58
- projectRoot,
61
+ projectRoot: effectiveProjectRoot,
59
62
  cliAgents: includedAgents,
60
63
  configPath,
61
64
  checkGlobal: !localOnly,
62
65
  });
63
- const rulerDir = await FileSystemUtils.findRulerDir(projectRoot, !localOnly);
64
- if (!rulerDir) {
65
- throw (0, constants_1.createRulerError)(`.ruler directory not found`, `Searched from: ${projectRoot}`);
66
- }
67
66
  (0, constants_1.logVerbose)(`Found .ruler directory at: ${rulerDir}`, verbose);
68
67
  // Normalize per-agent config keys to agent identifiers
69
68
  config.agentConfigs = (0, config_utils_1.mapRawAgentConfigs)(config.agentConfigs, agents);
@@ -105,27 +104,35 @@ async function revertAllAgentConfigs(projectRoot, includedAgents, configPath, ke
105
104
  }
106
105
  }
107
106
  (0, constants_1.logVerbose)(`Selected agents: ${selected.map((a) => a.getName()).join(', ')}`, verbose);
107
+ const isFullRevert = !config.cliAgents || config.cliAgents.length === 0;
108
108
  // Revert configurations for each agent
109
109
  let totalFilesProcessed = 0;
110
110
  let totalFilesRestored = 0;
111
111
  let totalFilesRemoved = 0;
112
112
  let totalBackupsRemoved = 0;
113
+ let totalDirectoriesRemoved = 0;
113
114
  for (const agent of selected) {
114
115
  const prefix = (0, constants_1.actionPrefix)(dryRun);
115
116
  console.log(`${prefix} Reverting ${agent.getName()}...`);
116
117
  const agentConfig = config.agentConfigs[agent.getIdentifier()];
117
- const result = await (0, revert_engine_1.revertAgentConfiguration)(agent, projectRoot, agentConfig, keepBackups, verbose, dryRun);
118
+ const result = await (0, revert_engine_1.revertAgentConfiguration)(agent, effectiveProjectRoot, agentConfig, keepBackups, verbose, dryRun);
118
119
  totalFilesProcessed += result.restored + result.removed;
119
120
  totalFilesRestored += result.restored;
120
121
  totalFilesRemoved += result.removed;
121
122
  totalBackupsRemoved += result.backupsRemoved;
123
+ if (!isFullRevert) {
124
+ totalDirectoriesRemoved += await (0, revert_engine_1.cleanUpAgentDirectories)(agent, effectiveProjectRoot, agentConfig, verbose, dryRun);
125
+ }
122
126
  }
123
- // Clean up auxiliary files and directories
124
- const cleanupResult = await (0, revert_engine_1.cleanUpAuxiliaryFiles)(projectRoot, verbose, dryRun);
127
+ // Clean up auxiliary files and directories only when reverting all agents.
128
+ const cleanupResult = isFullRevert
129
+ ? await (0, revert_engine_1.cleanUpAuxiliaryFiles)(effectiveProjectRoot, verbose, dryRun)
130
+ : { additionalFilesRemoved: 0, directoriesRemoved: 0 };
125
131
  totalFilesRemoved += cleanupResult.additionalFilesRemoved;
132
+ totalDirectoriesRemoved += cleanupResult.directoriesRemoved;
126
133
  // Clean managed ignore blocks if reverting all agents.
127
- const cleanedIgnoreFiles = !config.cliAgents || config.cliAgents.length === 0
128
- ? await cleanManagedIgnoreFiles(projectRoot, verbose, dryRun)
134
+ const cleanedIgnoreFiles = isFullRevert
135
+ ? await cleanManagedIgnoreFiles(effectiveProjectRoot, verbose, dryRun)
129
136
  : [];
130
137
  // Display summary
131
138
  const prefix = (0, constants_1.actionPrefix)(dryRun);
@@ -138,11 +145,9 @@ async function revertAllAgentConfigs(projectRoot, includedAgents, configPath, ke
138
145
  console.log(` Files processed: ${totalFilesProcessed}`);
139
146
  console.log(` Files restored from backup: ${totalFilesRestored}`);
140
147
  console.log(` Generated files removed: ${totalFilesRemoved}`);
141
- if (!keepBackups) {
142
- console.log(` Backup files removed: ${totalBackupsRemoved}`);
143
- }
144
- if (cleanupResult.directoriesRemoved > 0) {
145
- console.log(` Empty directories removed: ${cleanupResult.directoriesRemoved}`);
148
+ console.log(` Backup files removed: ${totalBackupsRemoved}`);
149
+ if (totalDirectoriesRemoved > 0) {
150
+ console.log(` Empty directories removed: ${totalDirectoriesRemoved}`);
146
151
  }
147
152
  for (const ignoreFile of cleanedIgnoreFiles) {
148
153
  console.log(` ${ignoreFile} cleaned: yes`);
@@ -170,9 +175,8 @@ async function cleanIgnoreFile(projectRoot, ignoreFile, verbose, dryRun) {
170
175
  return false;
171
176
  }
172
177
  const content = await fs_1.promises.readFile(ignorePath, 'utf8');
173
- const startIndex = content.indexOf(RULER_IGNORE_START_MARKER);
174
- const endIndex = content.indexOf(RULER_IGNORE_END_MARKER);
175
- if (startIndex === -1 || endIndex === -1) {
178
+ const cleaned = (0, GitignoreUtils_1.removeCompleteRulerBlocks)(content);
179
+ if (!cleaned.removed) {
176
180
  (0, constants_1.logVerbose)(`No ruler-managed block found in ${ignoreFile}`, verbose);
177
181
  return false;
178
182
  }
@@ -181,16 +185,12 @@ async function cleanIgnoreFile(projectRoot, ignoreFile, verbose, dryRun) {
181
185
  (0, constants_1.logVerbose)(`${prefix} Would remove ruler block from ${ignoreFile}`, verbose);
182
186
  }
183
187
  else {
184
- const beforeBlock = content.substring(0, startIndex);
185
- const afterBlock = content.substring(endIndex + RULER_IGNORE_END_MARKER.length);
186
- let newContent = beforeBlock + afterBlock;
187
- newContent = newContent.replace(/\n{3,}/g, '\n\n'); // Replace 3+ newlines with 2
188
- if (newContent.trim() === '') {
188
+ if (cleaned.content.trim() === '') {
189
189
  await fs_1.promises.unlink(ignorePath);
190
190
  (0, constants_1.logVerbose)(`${prefix} Removed empty ${ignoreFile} file`, verbose);
191
191
  }
192
192
  else {
193
- await fs_1.promises.writeFile(ignorePath, newContent);
193
+ await fs_1.promises.writeFile(ignorePath, cleaned.content);
194
194
  (0, constants_1.logVerbose)(`${prefix} Removed ruler block from ${ignoreFile}`, verbose);
195
195
  }
196
196
  }
@@ -25,7 +25,7 @@ export declare function readVSCodeSettings(settingsPath: string): Promise<VSCode
25
25
  /**
26
26
  * Write VSCode settings.json file
27
27
  */
28
- export declare function writeVSCodeSettings(settingsPath: string, settings: VSCodeSettings): Promise<void>;
28
+ export declare function writeVSCodeSettings(settingsPath: string, settings: VSCodeSettings, containmentRoot?: string): Promise<void>;
29
29
  /**
30
30
  * Transform ruler MCP config to Augment MCP server array format
31
31
  */
@@ -40,6 +40,7 @@ exports.mergeAugmentMcpServers = mergeAugmentMcpServers;
40
40
  exports.getVSCodeSettingsPath = getVSCodeSettingsPath;
41
41
  const fs_1 = require("fs");
42
42
  const path = __importStar(require("path"));
43
+ const FileSystemUtils_1 = require("../core/FileSystemUtils");
43
44
  /**
44
45
  * Read VSCode settings.json file
45
46
  */
@@ -58,9 +59,8 @@ async function readVSCodeSettings(settingsPath) {
58
59
  /**
59
60
  * Write VSCode settings.json file
60
61
  */
61
- async function writeVSCodeSettings(settingsPath, settings) {
62
- await fs_1.promises.mkdir(path.dirname(settingsPath), { recursive: true });
63
- await fs_1.promises.writeFile(settingsPath, JSON.stringify(settings, null, 4));
62
+ async function writeVSCodeSettings(settingsPath, settings, containmentRoot) {
63
+ await (0, FileSystemUtils_1.writeGeneratedFile)(settingsPath, JSON.stringify(settings, null, 4), containmentRoot);
64
64
  }
65
65
  /**
66
66
  * Transform ruler MCP config to Augment MCP server array format
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intellectronica/ruler",
3
- "version": "0.3.42",
3
+ "version": "0.3.43",
4
4
  "description": "Ruler — apply the same rules to all coding agents",
5
5
  "main": "dist/lib.js",
6
6
  "types": "dist/lib.d.ts",
@@ -13,7 +13,8 @@
13
13
  "test:coverage": "jest --coverage",
14
14
  "test:integration": "jest tests/e2e/ruler.integration.test.ts --verbose",
15
15
  "build": "tsc",
16
- "prepare": "npm run build"
16
+ "check:package-lock": "node -e \"const pkg=require('./package.json'); const lock=require('./package-lock.json'); const root=lock.packages?.['']; if (lock.version !== pkg.version || root?.version !== pkg.version) { console.error('package-lock.json version metadata must match package.json version'); process.exit(1); }\"",
17
+ "prepublishOnly": "npm run build"
17
18
  },
18
19
  "repository": {
19
20
  "type": "git",
@@ -68,7 +69,7 @@
68
69
  },
69
70
  "dependencies": {
70
71
  "@iarna/toml": "^2.2.5",
71
- "js-yaml": "^4.1.1",
72
+ "js-yaml": "^4.2.0",
72
73
  "yargs": "^18.0.0",
73
74
  "zod": "^4.1.12"
74
75
  }