@intellectronica/ruler 0.3.1 → 0.3.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/dist/agents/AbstractAgent.js +4 -2
- package/dist/agents/AgentsMdAgent.js +5 -3
- package/dist/agents/AiderAgent.js +5 -3
- package/dist/agents/AugmentCodeAgent.js +4 -2
- package/dist/agents/CursorAgent.js +4 -2
- package/dist/agents/WindsurfAgent.js +4 -2
- package/dist/cli/commands.js +5 -0
- package/dist/cli/handlers.js +2 -1
- package/dist/core/apply-engine.js +37 -27
- package/dist/lib.js +4 -4
- package/dist/mcp/propagateOpenCodeMcp.js +5 -1
- package/dist/mcp/propagateOpenHandsMcp.js +5 -1
- package/package.json +1 -1
|
@@ -50,11 +50,13 @@ class AbstractAgent {
|
|
|
50
50
|
* 4. Writing the new content
|
|
51
51
|
*/
|
|
52
52
|
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
53
|
-
agentConfig) {
|
|
53
|
+
agentConfig, backup = true) {
|
|
54
54
|
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
55
55
|
const absolutePath = path.resolve(projectRoot, output);
|
|
56
56
|
await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(absolutePath));
|
|
57
|
-
|
|
57
|
+
if (backup) {
|
|
58
|
+
await (0, FileSystemUtils_1.backupFile)(absolutePath);
|
|
59
|
+
}
|
|
58
60
|
await (0, FileSystemUtils_1.writeGeneratedFile)(absolutePath, concatenatedRules);
|
|
59
61
|
}
|
|
60
62
|
/**
|
|
@@ -54,7 +54,7 @@ class AgentsMdAgent extends AbstractAgent_1.AbstractAgent {
|
|
|
54
54
|
return path.join(projectRoot, 'AGENTS.md');
|
|
55
55
|
}
|
|
56
56
|
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
57
|
-
agentConfig) {
|
|
57
|
+
agentConfig, backup = true) {
|
|
58
58
|
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
59
59
|
const absolutePath = path.resolve(projectRoot, output);
|
|
60
60
|
await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(absolutePath));
|
|
@@ -72,8 +72,10 @@ class AgentsMdAgent extends AbstractAgent_1.AbstractAgent {
|
|
|
72
72
|
// No change; skip backup/write for idempotency
|
|
73
73
|
return;
|
|
74
74
|
}
|
|
75
|
-
// Backup (only if file existed) then write new content
|
|
76
|
-
|
|
75
|
+
// Backup (only if file existed and backup is enabled) then write new content
|
|
76
|
+
if (backup) {
|
|
77
|
+
await (0, FileSystemUtils_1.backupFile)(absolutePath);
|
|
78
|
+
}
|
|
77
79
|
await (0, FileSystemUtils_1.writeGeneratedFile)(absolutePath, contentWithMarker);
|
|
78
80
|
}
|
|
79
81
|
getMcpServerKey() {
|
|
@@ -52,21 +52,23 @@ class AiderAgent {
|
|
|
52
52
|
getName() {
|
|
53
53
|
return 'Aider';
|
|
54
54
|
}
|
|
55
|
-
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, agentConfig) {
|
|
55
|
+
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, agentConfig, backup = true) {
|
|
56
56
|
// First perform idempotent AGENTS.md write via composed AgentsMdAgent
|
|
57
57
|
await this.agentsMdAgent.applyRulerConfig(concatenatedRules, projectRoot, null, {
|
|
58
58
|
// Preserve explicit outputPath precedence semantics if provided.
|
|
59
59
|
outputPath: agentConfig?.outputPath ||
|
|
60
60
|
agentConfig?.outputPathInstructions ||
|
|
61
61
|
undefined,
|
|
62
|
-
});
|
|
62
|
+
}, backup);
|
|
63
63
|
// Now handle .aider.conf.yml configuration
|
|
64
64
|
const cfgPath = agentConfig?.outputPathConfig ??
|
|
65
65
|
this.getDefaultOutputPath(projectRoot).config;
|
|
66
66
|
let doc = {};
|
|
67
67
|
try {
|
|
68
68
|
await fs.access(cfgPath);
|
|
69
|
-
|
|
69
|
+
if (backup) {
|
|
70
|
+
await (0, FileSystemUtils_1.backupFile)(cfgPath);
|
|
71
|
+
}
|
|
70
72
|
const raw = await fs.readFile(cfgPath, 'utf8');
|
|
71
73
|
doc = (yaml.load(raw) || {});
|
|
72
74
|
}
|
|
@@ -48,9 +48,11 @@ class AugmentCodeAgent {
|
|
|
48
48
|
return 'AugmentCode';
|
|
49
49
|
}
|
|
50
50
|
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
51
|
-
agentConfig) {
|
|
51
|
+
agentConfig, backup = true) {
|
|
52
52
|
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
53
|
-
|
|
53
|
+
if (backup) {
|
|
54
|
+
await (0, FileSystemUtils_1.backupFile)(output);
|
|
55
|
+
}
|
|
54
56
|
await (0, FileSystemUtils_1.writeGeneratedFile)(output, concatenatedRules);
|
|
55
57
|
// AugmentCode does not support MCP servers
|
|
56
58
|
// MCP configuration is ignored for this agent
|
|
@@ -48,7 +48,7 @@ class CursorAgent extends AbstractAgent_1.AbstractAgent {
|
|
|
48
48
|
return 'Cursor';
|
|
49
49
|
}
|
|
50
50
|
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
51
|
-
agentConfig) {
|
|
51
|
+
agentConfig, backup = true) {
|
|
52
52
|
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
53
53
|
const absolutePath = path.resolve(projectRoot, output);
|
|
54
54
|
// Cursor expects a YAML front-matter block with an `alwaysApply` flag.
|
|
@@ -56,7 +56,9 @@ class CursorAgent extends AbstractAgent_1.AbstractAgent {
|
|
|
56
56
|
const frontMatter = ['---', 'alwaysApply: true', '---', ''].join('\n');
|
|
57
57
|
const content = `${frontMatter}${concatenatedRules.trimStart()}`;
|
|
58
58
|
await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(absolutePath));
|
|
59
|
-
|
|
59
|
+
if (backup) {
|
|
60
|
+
await (0, FileSystemUtils_1.backupFile)(absolutePath);
|
|
61
|
+
}
|
|
60
62
|
await (0, FileSystemUtils_1.writeGeneratedFile)(absolutePath, content);
|
|
61
63
|
}
|
|
62
64
|
getDefaultOutputPath(projectRoot) {
|
|
@@ -48,14 +48,16 @@ class WindsurfAgent extends AbstractAgent_1.AbstractAgent {
|
|
|
48
48
|
return 'Windsurf';
|
|
49
49
|
}
|
|
50
50
|
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
51
|
-
agentConfig) {
|
|
51
|
+
agentConfig, backup = true) {
|
|
52
52
|
const output = agentConfig?.outputPath ?? this.getDefaultOutputPath(projectRoot);
|
|
53
53
|
const absolutePath = path.resolve(projectRoot, output);
|
|
54
54
|
// Windsurf expects a YAML front-matter block with a `trigger` flag.
|
|
55
55
|
const frontMatter = ['---', 'trigger: always_on', '---', ''].join('\n');
|
|
56
56
|
const content = `${frontMatter}${concatenatedRules.trimStart()}`;
|
|
57
57
|
await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(absolutePath));
|
|
58
|
-
|
|
58
|
+
if (backup) {
|
|
59
|
+
await (0, FileSystemUtils_1.backupFile)(absolutePath);
|
|
60
|
+
}
|
|
59
61
|
await (0, FileSystemUtils_1.writeGeneratedFile)(absolutePath, content);
|
|
60
62
|
}
|
|
61
63
|
getDefaultOutputPath(projectRoot) {
|
package/dist/cli/commands.js
CHANGED
|
@@ -64,6 +64,11 @@ function run() {
|
|
|
64
64
|
type: 'boolean',
|
|
65
65
|
description: 'Enable nested rule loading from nested .ruler directories (default: disabled)',
|
|
66
66
|
default: false,
|
|
67
|
+
})
|
|
68
|
+
.option('backup', {
|
|
69
|
+
type: 'boolean',
|
|
70
|
+
description: 'Enable/disable creation of .bak backup files (default: enabled)',
|
|
71
|
+
default: true,
|
|
67
72
|
});
|
|
68
73
|
}, handlers_1.applyHandler)
|
|
69
74
|
.command('init', 'Scaffold a .ruler directory with default files', (y) => {
|
package/dist/cli/handlers.js
CHANGED
|
@@ -59,6 +59,7 @@ async function applyHandler(argv) {
|
|
|
59
59
|
const dryRun = argv['dry-run'];
|
|
60
60
|
const localOnly = argv['local-only'];
|
|
61
61
|
const nested = argv.nested;
|
|
62
|
+
const backup = argv.backup;
|
|
62
63
|
// Determine gitignore preference: CLI > TOML > Default (enabled)
|
|
63
64
|
// yargs handles --no-gitignore by setting gitignore to false
|
|
64
65
|
let gitignorePreference;
|
|
@@ -69,7 +70,7 @@ async function applyHandler(argv) {
|
|
|
69
70
|
gitignorePreference = undefined; // Let TOML/default decide
|
|
70
71
|
}
|
|
71
72
|
try {
|
|
72
|
-
await (0, lib_1.applyAllAgentConfigs)(projectRoot, agents, configPath, mcpEnabled, mcpStrategy, gitignorePreference, verbose, dryRun, localOnly, nested);
|
|
73
|
+
await (0, lib_1.applyAllAgentConfigs)(projectRoot, agents, configPath, mcpEnabled, mcpStrategy, gitignorePreference, verbose, dryRun, localOnly, nested, backup);
|
|
73
74
|
console.log('Ruler apply completed successfully.');
|
|
74
75
|
}
|
|
75
76
|
catch (err) {
|
|
@@ -218,12 +218,12 @@ function selectAgentsToRun(allAgents, config) {
|
|
|
218
218
|
* @param cliMcpStrategy MCP strategy from CLI
|
|
219
219
|
* @returns Promise resolving to array of generated file paths
|
|
220
220
|
*/
|
|
221
|
-
async function processHierarchicalConfigurations(agents, configurations, verbose, dryRun, cliMcpEnabled, cliMcpStrategy) {
|
|
221
|
+
async function processHierarchicalConfigurations(agents, configurations, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup = true) {
|
|
222
222
|
const allGeneratedPaths = [];
|
|
223
223
|
for (const config of configurations) {
|
|
224
224
|
console.log(`[ruler] Processing .ruler directory: ${config.rulerDir}`);
|
|
225
225
|
const rulerRoot = path.dirname(config.rulerDir);
|
|
226
|
-
const paths = await applyConfigurationsToAgents(agents, config.concatenatedRules, config.rulerMcpJson, config.config, rulerRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy);
|
|
226
|
+
const paths = await applyConfigurationsToAgents(agents, config.concatenatedRules, config.rulerMcpJson, config.config, rulerRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
|
|
227
227
|
allGeneratedPaths.push(...paths);
|
|
228
228
|
}
|
|
229
229
|
return allGeneratedPaths;
|
|
@@ -240,8 +240,8 @@ async function processHierarchicalConfigurations(agents, configurations, verbose
|
|
|
240
240
|
* @param cliMcpStrategy MCP strategy from CLI
|
|
241
241
|
* @returns Promise resolving to array of generated file paths
|
|
242
242
|
*/
|
|
243
|
-
async function processSingleConfiguration(agents, configuration, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy) {
|
|
244
|
-
return await applyConfigurationsToAgents(agents, configuration.concatenatedRules, configuration.rulerMcpJson, configuration.config, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy);
|
|
243
|
+
async function processSingleConfiguration(agents, configuration, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup = true) {
|
|
244
|
+
return await applyConfigurationsToAgents(agents, configuration.concatenatedRules, configuration.rulerMcpJson, configuration.config, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
|
|
245
245
|
}
|
|
246
246
|
/**
|
|
247
247
|
* Applies configurations to the selected agents (internal function).
|
|
@@ -254,7 +254,7 @@ async function processSingleConfiguration(agents, configuration, projectRoot, ve
|
|
|
254
254
|
* @param dryRun Whether to perform a dry run
|
|
255
255
|
* @returns Promise resolving to array of generated file paths
|
|
256
256
|
*/
|
|
257
|
-
async function applyConfigurationsToAgents(agents, concatenatedRules, rulerMcpJson, config, projectRoot, verbose, dryRun, cliMcpEnabled = true, cliMcpStrategy) {
|
|
257
|
+
async function applyConfigurationsToAgents(agents, concatenatedRules, rulerMcpJson, config, projectRoot, verbose, dryRun, cliMcpEnabled = true, cliMcpStrategy, backup = true) {
|
|
258
258
|
const generatedPaths = [];
|
|
259
259
|
let agentsMdWritten = false;
|
|
260
260
|
for (const agent of agents) {
|
|
@@ -266,9 +266,11 @@ async function applyConfigurationsToAgents(agents, concatenatedRules, rulerMcpJs
|
|
|
266
266
|
const outputPaths = (0, agent_utils_1.getAgentOutputPaths)(agent, projectRoot, agentConfig);
|
|
267
267
|
(0, constants_1.logVerbose)(`Agent ${agent.getName()} output paths: ${outputPaths.join(', ')}`, verbose);
|
|
268
268
|
generatedPaths.push(...outputPaths);
|
|
269
|
-
//
|
|
270
|
-
|
|
271
|
-
|
|
269
|
+
// Only add the backup file paths to the gitignore list if backups are enabled
|
|
270
|
+
if (backup) {
|
|
271
|
+
const backupPaths = outputPaths.map((p) => `${p}.bak`);
|
|
272
|
+
generatedPaths.push(...backupPaths);
|
|
273
|
+
}
|
|
272
274
|
if (dryRun) {
|
|
273
275
|
(0, constants_1.logVerbose)(`DRY RUN: Would write rules to: ${outputPaths.join(', ')}`, verbose);
|
|
274
276
|
}
|
|
@@ -299,15 +301,15 @@ async function applyConfigurationsToAgents(agents, concatenatedRules, rulerMcpJs
|
|
|
299
301
|
};
|
|
300
302
|
}
|
|
301
303
|
if (!skipApplyForThisAgent) {
|
|
302
|
-
await agent.applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, finalAgentConfig);
|
|
304
|
+
await agent.applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, finalAgentConfig, backup);
|
|
303
305
|
}
|
|
304
306
|
}
|
|
305
307
|
// Handle MCP configuration
|
|
306
|
-
await handleMcpConfiguration(agent, agentConfig, config, rulerMcpJson, projectRoot, generatedPaths, verbose, dryRun, cliMcpEnabled, cliMcpStrategy);
|
|
308
|
+
await handleMcpConfiguration(agent, agentConfig, config, rulerMcpJson, projectRoot, generatedPaths, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
|
|
307
309
|
}
|
|
308
310
|
return generatedPaths;
|
|
309
311
|
}
|
|
310
|
-
async function handleMcpConfiguration(agent, agentConfig, config, rulerMcpJson, projectRoot, generatedPaths, verbose, dryRun, cliMcpEnabled = true, cliMcpStrategy) {
|
|
312
|
+
async function handleMcpConfiguration(agent, agentConfig, config, rulerMcpJson, projectRoot, generatedPaths, verbose, dryRun, cliMcpEnabled = true, cliMcpStrategy, backup = true) {
|
|
311
313
|
if (!(0, capabilities_1.agentSupportsMcp)(agent)) {
|
|
312
314
|
(0, constants_1.logVerbose)(`Agent ${agent.getName()} does not support MCP - skipping MCP configuration`, verbose);
|
|
313
315
|
return;
|
|
@@ -322,47 +324,49 @@ async function handleMcpConfiguration(agent, agentConfig, config, rulerMcpJson,
|
|
|
322
324
|
(0, constants_1.logVerbose)(`No compatible MCP servers found for ${agent.getName()} - skipping MCP configuration`, verbose);
|
|
323
325
|
return;
|
|
324
326
|
}
|
|
325
|
-
await updateGitignoreForMcpFile(dest, projectRoot, generatedPaths);
|
|
326
|
-
await applyMcpConfiguration(agent, filteredMcpJson, dest, agentConfig, config, projectRoot, cliMcpStrategy, dryRun, verbose);
|
|
327
|
+
await updateGitignoreForMcpFile(dest, projectRoot, generatedPaths, backup);
|
|
328
|
+
await applyMcpConfiguration(agent, filteredMcpJson, dest, agentConfig, config, projectRoot, cliMcpStrategy, dryRun, verbose, backup);
|
|
327
329
|
}
|
|
328
|
-
async function updateGitignoreForMcpFile(dest, projectRoot, generatedPaths) {
|
|
330
|
+
async function updateGitignoreForMcpFile(dest, projectRoot, generatedPaths, backup = true) {
|
|
329
331
|
if (dest.startsWith(projectRoot)) {
|
|
330
332
|
const relativeDest = path.relative(projectRoot, dest);
|
|
331
333
|
generatedPaths.push(relativeDest);
|
|
332
|
-
|
|
334
|
+
if (backup) {
|
|
335
|
+
generatedPaths.push(`${relativeDest}.bak`);
|
|
336
|
+
}
|
|
333
337
|
}
|
|
334
338
|
}
|
|
335
|
-
async function applyMcpConfiguration(agent, filteredMcpJson, dest, agentConfig, config, projectRoot, cliMcpStrategy, dryRun, verbose) {
|
|
339
|
+
async function applyMcpConfiguration(agent, filteredMcpJson, dest, agentConfig, config, projectRoot, cliMcpStrategy, dryRun, verbose, backup = true) {
|
|
336
340
|
// Prevent writing MCP configs outside the project root (e.g., legacy home-directory targets)
|
|
337
341
|
if (!dest.startsWith(projectRoot)) {
|
|
338
342
|
(0, constants_1.logVerbose)(`Skipping MCP config for ${agent.getName()} because target path is outside project: ${dest}`, verbose);
|
|
339
343
|
return;
|
|
340
344
|
}
|
|
341
345
|
if (agent.getIdentifier() === 'openhands') {
|
|
342
|
-
return await applyOpenHandsMcpConfiguration(filteredMcpJson, dest, dryRun, verbose);
|
|
346
|
+
return await applyOpenHandsMcpConfiguration(filteredMcpJson, dest, dryRun, verbose, backup);
|
|
343
347
|
}
|
|
344
348
|
if (agent.getIdentifier() === 'opencode') {
|
|
345
|
-
return await applyOpenCodeMcpConfiguration(filteredMcpJson, dest, dryRun, verbose);
|
|
349
|
+
return await applyOpenCodeMcpConfiguration(filteredMcpJson, dest, dryRun, verbose, backup);
|
|
346
350
|
}
|
|
347
|
-
return await applyStandardMcpConfiguration(agent, filteredMcpJson, dest, agentConfig, config, cliMcpStrategy, dryRun, verbose);
|
|
351
|
+
return await applyStandardMcpConfiguration(agent, filteredMcpJson, dest, agentConfig, config, cliMcpStrategy, dryRun, verbose, backup);
|
|
348
352
|
}
|
|
349
|
-
async function applyOpenHandsMcpConfiguration(filteredMcpJson, dest, dryRun, verbose) {
|
|
353
|
+
async function applyOpenHandsMcpConfiguration(filteredMcpJson, dest, dryRun, verbose, backup = true) {
|
|
350
354
|
if (dryRun) {
|
|
351
355
|
(0, constants_1.logVerbose)(`DRY RUN: Would apply MCP config by updating TOML file: ${dest}`, verbose);
|
|
352
356
|
}
|
|
353
357
|
else {
|
|
354
|
-
await (0, propagateOpenHandsMcp_1.propagateMcpToOpenHands)(filteredMcpJson, dest);
|
|
358
|
+
await (0, propagateOpenHandsMcp_1.propagateMcpToOpenHands)(filteredMcpJson, dest, backup);
|
|
355
359
|
}
|
|
356
360
|
}
|
|
357
|
-
async function applyOpenCodeMcpConfiguration(filteredMcpJson, dest, dryRun, verbose) {
|
|
361
|
+
async function applyOpenCodeMcpConfiguration(filteredMcpJson, dest, dryRun, verbose, backup = true) {
|
|
358
362
|
if (dryRun) {
|
|
359
363
|
(0, constants_1.logVerbose)(`DRY RUN: Would apply MCP config by updating OpenCode config file: ${dest}`, verbose);
|
|
360
364
|
}
|
|
361
365
|
else {
|
|
362
|
-
await (0, propagateOpenCodeMcp_1.propagateMcpToOpenCode)(filteredMcpJson, dest);
|
|
366
|
+
await (0, propagateOpenCodeMcp_1.propagateMcpToOpenCode)(filteredMcpJson, dest, backup);
|
|
363
367
|
}
|
|
364
368
|
}
|
|
365
|
-
async function applyStandardMcpConfiguration(agent, filteredMcpJson, dest, agentConfig, config, cliMcpStrategy, dryRun, verbose) {
|
|
369
|
+
async function applyStandardMcpConfiguration(agent, filteredMcpJson, dest, agentConfig, config, cliMcpStrategy, dryRun, verbose, backup = true) {
|
|
366
370
|
const strategy = cliMcpStrategy ??
|
|
367
371
|
agentConfig?.mcp?.strategy ??
|
|
368
372
|
config.mcp?.strategy ??
|
|
@@ -373,6 +377,10 @@ async function applyStandardMcpConfiguration(agent, filteredMcpJson, dest, agent
|
|
|
373
377
|
(0, constants_1.logVerbose)(`DRY RUN: Would apply MCP config to: ${dest}`, verbose);
|
|
374
378
|
}
|
|
375
379
|
else {
|
|
380
|
+
if (backup) {
|
|
381
|
+
const { backupFile } = await Promise.resolve().then(() => __importStar(require('../core/FileSystemUtils')));
|
|
382
|
+
await backupFile(dest);
|
|
383
|
+
}
|
|
376
384
|
const existing = await (0, mcp_1.readNativeMcp)(dest);
|
|
377
385
|
const merged = (0, merge_1.mergeMcp)(existing, filteredMcpJson, strategy, serverKey);
|
|
378
386
|
await (0, mcp_1.writeNativeMcp)(dest, merged);
|
|
@@ -386,7 +394,7 @@ async function applyStandardMcpConfiguration(agent, filteredMcpJson, dest, agent
|
|
|
386
394
|
* @param cliGitignoreEnabled CLI gitignore setting
|
|
387
395
|
* @param dryRun Whether to perform a dry run
|
|
388
396
|
*/
|
|
389
|
-
async function updateGitignore(projectRoot, generatedPaths, config, cliGitignoreEnabled, dryRun) {
|
|
397
|
+
async function updateGitignore(projectRoot, generatedPaths, config, cliGitignoreEnabled, dryRun, backup = true) {
|
|
390
398
|
// Configuration precedence: CLI > TOML > Default (enabled)
|
|
391
399
|
let gitignoreEnabled;
|
|
392
400
|
if (cliGitignoreEnabled !== undefined) {
|
|
@@ -400,8 +408,10 @@ async function updateGitignore(projectRoot, generatedPaths, config, cliGitignore
|
|
|
400
408
|
}
|
|
401
409
|
if (gitignoreEnabled && generatedPaths.length > 0) {
|
|
402
410
|
const uniquePaths = [...new Set(generatedPaths)];
|
|
403
|
-
// Add wildcard pattern for backup files
|
|
404
|
-
|
|
411
|
+
// Add wildcard pattern for backup files only if backup is enabled
|
|
412
|
+
if (backup) {
|
|
413
|
+
uniquePaths.push('*.bak');
|
|
414
|
+
}
|
|
405
415
|
if (uniquePaths.length > 0) {
|
|
406
416
|
const prefix = (0, constants_1.actionPrefix)(dryRun);
|
|
407
417
|
if (dryRun) {
|
package/dist/lib.js
CHANGED
|
@@ -17,7 +17,7 @@ const agents = agents_1.allAgents;
|
|
|
17
17
|
* @param projectRoot Root directory of the project
|
|
18
18
|
* @param includedAgents Optional list of agent name filters (case-insensitive substrings)
|
|
19
19
|
*/
|
|
20
|
-
async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cliMcpEnabled = true, cliMcpStrategy, cliGitignoreEnabled, verbose = false, dryRun = false, localOnly = false, nested = false) {
|
|
20
|
+
async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cliMcpEnabled = true, cliMcpStrategy, cliGitignoreEnabled, verbose = false, dryRun = false, localOnly = false, nested = false, backup = true) {
|
|
21
21
|
// Load configuration and rules
|
|
22
22
|
(0, constants_1.logVerbose)(`Loading configuration from project root: ${projectRoot}`, verbose);
|
|
23
23
|
if (configPath) {
|
|
@@ -40,7 +40,7 @@ async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cli
|
|
|
40
40
|
normalizeAgentConfigs(rootConfig, agents);
|
|
41
41
|
selectedAgents = (0, apply_engine_1.selectAgentsToRun)(agents, rootConfig);
|
|
42
42
|
(0, constants_1.logVerbose)(`Selected ${selectedAgents.length} agents: ${selectedAgents.map((a) => a.getName()).join(', ')}`, verbose);
|
|
43
|
-
generatedPaths = await (0, apply_engine_1.processHierarchicalConfigurations)(selectedAgents, hierarchicalConfigs, verbose, dryRun, cliMcpEnabled, cliMcpStrategy);
|
|
43
|
+
generatedPaths = await (0, apply_engine_1.processHierarchicalConfigurations)(selectedAgents, hierarchicalConfigs, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
|
|
44
44
|
}
|
|
45
45
|
else {
|
|
46
46
|
const singleConfig = await (0, apply_engine_1.loadSingleConfiguration)(projectRoot, configPath, localOnly);
|
|
@@ -51,9 +51,9 @@ async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cli
|
|
|
51
51
|
normalizeAgentConfigs(singleConfig.config, agents);
|
|
52
52
|
selectedAgents = (0, apply_engine_1.selectAgentsToRun)(agents, singleConfig.config);
|
|
53
53
|
(0, constants_1.logVerbose)(`Selected ${selectedAgents.length} agents: ${selectedAgents.map((a) => a.getName()).join(', ')}`, verbose);
|
|
54
|
-
generatedPaths = await (0, apply_engine_1.processSingleConfiguration)(selectedAgents, singleConfig, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy);
|
|
54
|
+
generatedPaths = await (0, apply_engine_1.processSingleConfiguration)(selectedAgents, singleConfig, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backup);
|
|
55
55
|
}
|
|
56
|
-
await (0, apply_engine_1.updateGitignore)(projectRoot, generatedPaths, loadedConfig, cliGitignoreEnabled, dryRun);
|
|
56
|
+
await (0, apply_engine_1.updateGitignore)(projectRoot, generatedPaths, loadedConfig, cliGitignoreEnabled, dryRun, backup);
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
59
|
* Normalizes per-agent config keys to agent identifiers for consistent lookup.
|
|
@@ -85,7 +85,7 @@ function transformToOpenCodeFormat(rulerMcp) {
|
|
|
85
85
|
mcp: openCodeServers,
|
|
86
86
|
};
|
|
87
87
|
}
|
|
88
|
-
async function propagateMcpToOpenCode(rulerMcpData, openCodeConfigPath) {
|
|
88
|
+
async function propagateMcpToOpenCode(rulerMcpData, openCodeConfigPath, backup = true) {
|
|
89
89
|
const rulerMcp = rulerMcpData || {};
|
|
90
90
|
// Read existing OpenCode config if it exists
|
|
91
91
|
let existingConfig = {};
|
|
@@ -108,5 +108,9 @@ async function propagateMcpToOpenCode(rulerMcpData, openCodeConfigPath) {
|
|
|
108
108
|
},
|
|
109
109
|
};
|
|
110
110
|
await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(openCodeConfigPath));
|
|
111
|
+
if (backup) {
|
|
112
|
+
const { backupFile } = await Promise.resolve().then(() => __importStar(require('../core/FileSystemUtils')));
|
|
113
|
+
await backupFile(openCodeConfigPath);
|
|
114
|
+
}
|
|
111
115
|
await fs.writeFile(openCodeConfigPath, JSON.stringify(finalConfig, null, 2) + '\n');
|
|
112
116
|
}
|
|
@@ -90,7 +90,7 @@ function normalizeRemoteServerArray(entries) {
|
|
|
90
90
|
// All entries are strings, keep as is
|
|
91
91
|
return entries;
|
|
92
92
|
}
|
|
93
|
-
async function propagateMcpToOpenHands(rulerMcpData, openHandsConfigPath) {
|
|
93
|
+
async function propagateMcpToOpenHands(rulerMcpData, openHandsConfigPath, backup = true) {
|
|
94
94
|
const rulerMcp = rulerMcpData || {};
|
|
95
95
|
// Always use the legacy Ruler MCP config format as input (top-level "mcpServers" key)
|
|
96
96
|
const rulerServers = rulerMcp.mcpServers || {};
|
|
@@ -162,5 +162,9 @@ async function propagateMcpToOpenHands(rulerMcpData, openHandsConfigPath) {
|
|
|
162
162
|
config.mcp.sse_servers = normalizeRemoteServerArray(Array.from(existingSseServers.values()));
|
|
163
163
|
config.mcp.shttp_servers = normalizeRemoteServerArray(Array.from(existingShttpServers.values()));
|
|
164
164
|
await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(openHandsConfigPath));
|
|
165
|
+
if (backup) {
|
|
166
|
+
const { backupFile } = await Promise.resolve().then(() => __importStar(require('../core/FileSystemUtils')));
|
|
167
|
+
await backupFile(openHandsConfigPath);
|
|
168
|
+
}
|
|
165
169
|
await fs.writeFile(openHandsConfigPath, (0, toml_1.stringify)(config));
|
|
166
170
|
}
|