@intellectronica/ruler 0.3.40 → 0.3.42
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 +59 -46
- package/dist/agents/AbstractAgent.d.ts +53 -0
- package/dist/agents/AgentsMdAgent.d.ts +14 -0
- package/dist/agents/AiderAgent.d.ts +14 -0
- package/dist/agents/AiderAgent.js +3 -1
- package/dist/agents/AmazonQCliAgent.d.ts +13 -0
- package/dist/agents/AmpAgent.d.ts +6 -0
- package/dist/agents/AntigravityAgent.d.ts +10 -0
- package/dist/agents/AugmentCodeAgent.d.ts +13 -0
- package/dist/agents/ClaudeAgent.d.ts +13 -0
- package/dist/agents/ClineAgent.d.ts +9 -0
- package/dist/agents/CodexCliAgent.d.ts +31 -0
- package/dist/agents/CopilotAgent.d.ts +20 -0
- package/dist/agents/CrushAgent.d.ts +14 -0
- package/dist/agents/CrushAgent.js +5 -2
- package/dist/agents/CursorAgent.d.ts +17 -0
- package/dist/agents/FactoryDroidAgent.d.ts +13 -0
- package/dist/agents/FirebaseAgent.d.ts +11 -0
- package/dist/agents/FirebenderAgent.d.ts +36 -0
- package/dist/agents/GeminiCliAgent.d.ts +11 -0
- package/dist/agents/GeminiCliAgent.js +2 -2
- package/dist/agents/GooseAgent.d.ts +12 -0
- package/dist/agents/IAgent.d.ts +72 -0
- package/dist/agents/JetBrainsAiAssistantAgent.d.ts +10 -0
- package/dist/agents/JulesAgent.d.ts +5 -0
- package/dist/agents/JunieAgent.d.ts +12 -0
- package/dist/agents/KiloCodeAgent.d.ts +14 -0
- package/dist/agents/KiroAgent.d.ts +8 -0
- package/dist/agents/MistralVibeAgent.d.ts +31 -0
- package/dist/agents/OpenCodeAgent.d.ts +11 -0
- package/dist/agents/OpenCodeAgent.js +14 -9
- package/dist/agents/OpenHandsAgent.d.ts +8 -0
- package/dist/agents/PiAgent.d.ts +9 -0
- package/dist/agents/QwenCodeAgent.d.ts +10 -0
- package/dist/agents/QwenCodeAgent.js +2 -2
- package/dist/agents/RooCodeAgent.d.ts +16 -0
- package/dist/agents/TraeAgent.d.ts +10 -0
- package/dist/agents/WarpAgent.d.ts +12 -0
- package/dist/agents/WindsurfAgent.d.ts +13 -0
- package/dist/agents/ZedAgent.d.ts +21 -0
- package/dist/agents/ZedAgent.js +5 -2
- package/dist/agents/agent-utils.d.ts +5 -0
- package/dist/agents/agent-utils.js +8 -5
- package/dist/agents/index.d.ts +9 -0
- package/dist/cli/commands.d.ts +4 -0
- package/dist/cli/commands.js +2 -3
- package/dist/cli/handlers.d.ts +41 -0
- package/dist/cli/handlers.js +76 -60
- package/dist/cli/index.d.ts +2 -0
- package/dist/constants.d.ts +35 -0
- package/dist/core/ConfigLoader.d.ts +57 -0
- package/dist/core/ConfigLoader.js +123 -41
- package/dist/core/FileSystemUtils.d.ts +51 -0
- package/dist/core/FileSystemUtils.js +37 -17
- package/dist/core/GitignoreUtils.d.ts +15 -0
- package/dist/core/GitignoreUtils.js +32 -1
- package/dist/core/RuleProcessor.d.ts +8 -0
- package/dist/core/SkillsProcessor.d.ts +127 -0
- package/dist/core/SkillsProcessor.js +104 -218
- package/dist/core/SkillsUtils.d.ts +26 -0
- package/dist/core/SubagentsProcessor.d.ts +38 -0
- package/dist/core/SubagentsProcessor.js +68 -22
- package/dist/core/SubagentsUtils.d.ts +34 -0
- package/dist/core/UnifiedConfigLoader.d.ts +10 -0
- package/dist/core/UnifiedConfigLoader.js +61 -31
- package/dist/core/UnifiedConfigTypes.d.ts +95 -0
- package/dist/core/agent-selection.d.ts +12 -0
- package/dist/core/agent-selection.js +11 -3
- package/dist/core/apply-engine.d.ts +69 -0
- package/dist/core/apply-engine.js +57 -50
- package/dist/core/config-utils.d.ts +14 -0
- package/dist/core/config-utils.js +9 -3
- package/dist/core/hash.d.ts +2 -0
- package/dist/core/path-utils.d.ts +1 -0
- package/dist/core/path-utils.js +42 -0
- package/dist/core/revert-engine.d.ts +36 -0
- package/dist/core/revert-engine.js +70 -9
- package/dist/lib.d.ts +13 -0
- package/dist/lib.js +23 -5
- package/dist/mcp/capabilities.d.ts +20 -0
- package/dist/mcp/merge.d.ts +10 -0
- package/dist/mcp/merge.js +19 -1
- package/dist/mcp/propagateOpenCodeMcp.d.ts +2 -0
- package/dist/mcp/propagateOpenCodeMcp.js +21 -9
- package/dist/mcp/propagateOpenHandsMcp.d.ts +2 -0
- package/dist/mcp/propagateOpenHandsMcp.js +31 -15
- package/dist/mcp/validate.d.ts +7 -0
- package/dist/mcp/validate.js +6 -1
- package/dist/paths/mcp.d.ts +8 -0
- package/dist/paths/mcp.js +33 -4
- package/dist/revert.d.ts +6 -0
- package/dist/revert.js +39 -27
- package/dist/types.d.ts +87 -0
- package/dist/vscode/settings.d.ts +40 -0
- package/package.json +7 -4
|
@@ -52,6 +52,7 @@ const propagateOpenHandsMcp_1 = require("../mcp/propagateOpenHandsMcp");
|
|
|
52
52
|
const propagateOpenCodeMcp_1 = require("../mcp/propagateOpenCodeMcp");
|
|
53
53
|
const agent_utils_1 = require("../agents/agent-utils");
|
|
54
54
|
const capabilities_1 = require("../mcp/capabilities");
|
|
55
|
+
const path_utils_1 = require("./path-utils");
|
|
55
56
|
const constants_1 = require("../constants");
|
|
56
57
|
async function loadNestedConfigurations(projectRoot, configPath, localOnly, resolvedNested) {
|
|
57
58
|
const { dirs: rulerDirs } = await findRulerDirectories(projectRoot, localOnly, true);
|
|
@@ -59,11 +60,11 @@ async function loadNestedConfigurations(projectRoot, configPath, localOnly, reso
|
|
|
59
60
|
// Load config first so we know whether `.ruler/agents/` should be included
|
|
60
61
|
// in the rule concatenation for each directory.
|
|
61
62
|
for (const rulerDir of rulerDirs) {
|
|
62
|
-
const config = await loadConfigForRulerDir(rulerDir, configPath, resolvedNested);
|
|
63
|
+
const config = await loadConfigForRulerDir(rulerDir, configPath, resolvedNested, localOnly);
|
|
63
64
|
const files = await FileSystemUtils.readMarkdownFiles(rulerDir, {
|
|
64
65
|
includeAgents: shouldIncludeAgentsInRules(config),
|
|
65
66
|
});
|
|
66
|
-
results.push(await createHierarchicalConfiguration(rulerDir, files, config, configPath));
|
|
67
|
+
results.push(await createHierarchicalConfiguration(rulerDir, files, config, configPath, localOnly));
|
|
67
68
|
}
|
|
68
69
|
return results;
|
|
69
70
|
}
|
|
@@ -74,7 +75,7 @@ async function loadNestedConfigurations(projectRoot, configPath, localOnly, reso
|
|
|
74
75
|
function shouldIncludeAgentsInRules(config) {
|
|
75
76
|
return config.subagents?.include_in_rules === true;
|
|
76
77
|
}
|
|
77
|
-
async function createHierarchicalConfiguration(rulerDir, files, config, cliConfigPath) {
|
|
78
|
+
async function createHierarchicalConfiguration(rulerDir, files, config, cliConfigPath, localOnly) {
|
|
78
79
|
await warnAboutLegacyMcpJson(rulerDir);
|
|
79
80
|
const concatenatedRules = (0, RuleProcessor_1.concatenateRules)(files, path.dirname(rulerDir));
|
|
80
81
|
const directoryRoot = path.dirname(rulerDir);
|
|
@@ -91,6 +92,7 @@ async function createHierarchicalConfiguration(rulerDir, files, config, cliConfi
|
|
|
91
92
|
const unifiedConfig = await loadUnifiedConfig({
|
|
92
93
|
projectRoot: directoryRoot,
|
|
93
94
|
configPath: configPathToUse,
|
|
95
|
+
checkGlobal: !localOnly,
|
|
94
96
|
});
|
|
95
97
|
let rulerMcpJson = null;
|
|
96
98
|
if (unifiedConfig.mcp && Object.keys(unifiedConfig.mcp.servers).length > 0) {
|
|
@@ -105,7 +107,7 @@ async function createHierarchicalConfiguration(rulerDir, files, config, cliConfi
|
|
|
105
107
|
rulerMcpJson,
|
|
106
108
|
};
|
|
107
109
|
}
|
|
108
|
-
async function loadConfigForRulerDir(rulerDir, cliConfigPath, resolvedNested) {
|
|
110
|
+
async function loadConfigForRulerDir(rulerDir, cliConfigPath, resolvedNested, localOnly) {
|
|
109
111
|
const directoryRoot = path.dirname(rulerDir);
|
|
110
112
|
const localConfigPath = path.join(rulerDir, 'ruler.toml');
|
|
111
113
|
let hasLocalConfig = false;
|
|
@@ -119,6 +121,7 @@ async function loadConfigForRulerDir(rulerDir, cliConfigPath, resolvedNested) {
|
|
|
119
121
|
const loaded = await (0, ConfigLoader_1.loadConfig)({
|
|
120
122
|
projectRoot: directoryRoot,
|
|
121
123
|
configPath: hasLocalConfig ? localConfigPath : cliConfigPath,
|
|
124
|
+
checkGlobal: !localOnly,
|
|
122
125
|
});
|
|
123
126
|
const cloned = cloneLoadedConfig(loaded);
|
|
124
127
|
if (resolvedNested) {
|
|
@@ -144,6 +147,7 @@ function cloneLoadedConfig(config) {
|
|
|
144
147
|
cliAgents: config.cliAgents ? [...config.cliAgents] : undefined,
|
|
145
148
|
mcp: config.mcp ? { ...config.mcp } : undefined,
|
|
146
149
|
gitignore: config.gitignore ? { ...config.gitignore } : undefined,
|
|
150
|
+
backup: config.backup ? { ...config.backup } : undefined,
|
|
147
151
|
skills: config.skills ? { ...config.skills } : undefined,
|
|
148
152
|
subagents: config.subagents ? { ...config.subagents } : undefined,
|
|
149
153
|
nested: config.nested,
|
|
@@ -156,18 +160,10 @@ function cloneLoadedConfig(config) {
|
|
|
156
160
|
async function findRulerDirectories(projectRoot, localOnly, hierarchical) {
|
|
157
161
|
if (hierarchical) {
|
|
158
162
|
const dirs = await FileSystemUtils.findAllRulerDirs(projectRoot);
|
|
159
|
-
|
|
160
|
-
// Add global config if not local-only
|
|
161
|
-
if (!localOnly) {
|
|
162
|
-
const globalDir = await FileSystemUtils.findGlobalRulerDir();
|
|
163
|
-
if (globalDir) {
|
|
164
|
-
allDirs.push(globalDir);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
if (allDirs.length === 0) {
|
|
163
|
+
if (dirs.length === 0) {
|
|
168
164
|
throw (0, constants_1.createRulerError)(`.ruler directory not found`, `Searched from: ${projectRoot}`);
|
|
169
165
|
}
|
|
170
|
-
return { dirs
|
|
166
|
+
return { dirs, primaryDir: dirs[0] };
|
|
171
167
|
}
|
|
172
168
|
else {
|
|
173
169
|
const dir = await FileSystemUtils.findRulerDir(projectRoot, !localOnly);
|
|
@@ -202,6 +198,7 @@ async function loadSingleConfiguration(projectRoot, configPath, localOnly) {
|
|
|
202
198
|
const config = await (0, ConfigLoader_1.loadConfig)({
|
|
203
199
|
projectRoot,
|
|
204
200
|
configPath,
|
|
201
|
+
checkGlobal: !localOnly,
|
|
205
202
|
});
|
|
206
203
|
// Read rule files. `.ruler/agents/` is only included when
|
|
207
204
|
// `[agents] include_in_rules = true`.
|
|
@@ -212,7 +209,11 @@ async function loadSingleConfiguration(projectRoot, configPath, localOnly) {
|
|
|
212
209
|
const concatenatedRules = (0, RuleProcessor_1.concatenateRules)(files, path.dirname(primaryDir));
|
|
213
210
|
// Load unified config to get merged MCP configuration
|
|
214
211
|
const { loadUnifiedConfig } = await Promise.resolve().then(() => __importStar(require('./UnifiedConfigLoader')));
|
|
215
|
-
const unifiedConfig = await loadUnifiedConfig({
|
|
212
|
+
const unifiedConfig = await loadUnifiedConfig({
|
|
213
|
+
projectRoot,
|
|
214
|
+
configPath,
|
|
215
|
+
checkGlobal: !localOnly,
|
|
216
|
+
});
|
|
216
217
|
// Synthesize rulerMcpJson from unified MCP bundle for backward compatibility
|
|
217
218
|
let rulerMcpJson = null;
|
|
218
219
|
if (unifiedConfig.mcp && Object.keys(unifiedConfig.mcp.servers).length > 0) {
|
|
@@ -306,22 +307,27 @@ async function applyConfigurationsToAgents(agents, concatenatedRules, rulerMcpJs
|
|
|
306
307
|
agentsMdWritten = true;
|
|
307
308
|
}
|
|
308
309
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
322
|
-
}
|
|
310
|
+
const effectiveMcpEnabled = cliMcpEnabled &&
|
|
311
|
+
(agentConfig?.mcp?.enabled ?? config.mcp?.enabled ?? true);
|
|
312
|
+
const effectiveMcpStrategy = cliMcpStrategy ??
|
|
313
|
+
agentConfig?.mcp?.strategy ??
|
|
314
|
+
config.mcp?.strategy ??
|
|
315
|
+
'merge';
|
|
316
|
+
const finalAgentConfig = {
|
|
317
|
+
...agentConfig,
|
|
318
|
+
mcp: {
|
|
319
|
+
...agentConfig?.mcp,
|
|
320
|
+
enabled: effectiveMcpEnabled,
|
|
321
|
+
strategy: effectiveMcpStrategy,
|
|
322
|
+
},
|
|
323
|
+
};
|
|
324
|
+
const mcpForAgentApply = shouldUseEngineManagedMcp(agent)
|
|
325
|
+
? null
|
|
326
|
+
: effectiveMcpEnabled
|
|
327
|
+
? agentRulerMcpJson
|
|
328
|
+
: null;
|
|
323
329
|
if (!skipApplyForThisAgent) {
|
|
324
|
-
await agent.applyRulerConfig(concatenatedRules, projectRoot,
|
|
330
|
+
await agent.applyRulerConfig(concatenatedRules, projectRoot, mcpForAgentApply, finalAgentConfig, backup);
|
|
325
331
|
}
|
|
326
332
|
}
|
|
327
333
|
// Handle MCP configuration
|
|
@@ -334,7 +340,7 @@ async function handleMcpConfiguration(agent, agentConfig, config, rulerMcpJson,
|
|
|
334
340
|
(0, constants_1.logVerbose)(`Agent ${agent.getName()} does not support MCP - skipping MCP configuration`, verbose);
|
|
335
341
|
return;
|
|
336
342
|
}
|
|
337
|
-
const dest = await (
|
|
343
|
+
const dest = await resolveMcpDestination(agent, agentConfig, projectRoot);
|
|
338
344
|
const mcpEnabledForAgent = cliMcpEnabled && (agentConfig?.mcp?.enabled ?? config.mcp?.enabled ?? true);
|
|
339
345
|
if (!dest || !mcpEnabledForAgent) {
|
|
340
346
|
return;
|
|
@@ -349,8 +355,17 @@ async function handleMcpConfiguration(agent, agentConfig, config, rulerMcpJson,
|
|
|
349
355
|
await updateGitignoreForMcpFile(dest, projectRoot, generatedPaths, backup);
|
|
350
356
|
await applyMcpConfiguration(agent, filteredMcpJson, dest, agentConfig, config, projectRoot, cliMcpStrategy, dryRun, verbose, backup);
|
|
351
357
|
}
|
|
358
|
+
function shouldUseEngineManagedMcp(agent) {
|
|
359
|
+
return (agent.getIdentifier() === 'codex' || agent.getIdentifier() === 'opencode');
|
|
360
|
+
}
|
|
361
|
+
async function resolveMcpDestination(agent, agentConfig, projectRoot) {
|
|
362
|
+
if (agentConfig?.outputPathConfig) {
|
|
363
|
+
return path.resolve(projectRoot, agentConfig.outputPathConfig);
|
|
364
|
+
}
|
|
365
|
+
return await (0, mcp_1.getNativeMcpPath)(agent.getName(), projectRoot);
|
|
366
|
+
}
|
|
352
367
|
async function updateGitignoreForMcpFile(dest, projectRoot, generatedPaths, backup = true) {
|
|
353
|
-
if (
|
|
368
|
+
if ((0, path_utils_1.isPathInsideOrEqual)(projectRoot, dest)) {
|
|
354
369
|
const relativeDest = path.relative(projectRoot, dest);
|
|
355
370
|
generatedPaths.push(relativeDest);
|
|
356
371
|
if (backup) {
|
|
@@ -391,16 +406,16 @@ function sanitizeMcpTimeoutsForAgent(agent, mcpJson, dryRun) {
|
|
|
391
406
|
}
|
|
392
407
|
async function applyMcpConfiguration(agent, filteredMcpJson, dest, agentConfig, config, projectRoot, cliMcpStrategy, dryRun, verbose, backup = true) {
|
|
393
408
|
// Prevent writing MCP configs outside the project root (e.g., legacy home-directory targets)
|
|
394
|
-
if (!
|
|
409
|
+
if (!(0, path_utils_1.isPathInsideOrEqual)(projectRoot, dest)) {
|
|
395
410
|
(0, constants_1.logVerbose)(`Skipping MCP config for ${agent.getName()} because target path is outside project: ${dest}`, verbose);
|
|
396
411
|
return;
|
|
397
412
|
}
|
|
398
413
|
const agentMcpJson = sanitizeMcpTimeoutsForAgent(agent, filteredMcpJson, dryRun);
|
|
399
414
|
if (agent.getIdentifier() === 'openhands') {
|
|
400
|
-
return await applyOpenHandsMcpConfiguration(agentMcpJson, dest, dryRun, verbose, backup);
|
|
415
|
+
return await applyOpenHandsMcpConfiguration(agentMcpJson, dest, cliMcpStrategy ?? agentConfig?.mcp?.strategy ?? config.mcp?.strategy, dryRun, verbose, backup);
|
|
401
416
|
}
|
|
402
417
|
if (agent.getIdentifier() === 'opencode') {
|
|
403
|
-
return await applyOpenCodeMcpConfiguration(agentMcpJson, dest, dryRun, verbose, backup);
|
|
418
|
+
return await applyOpenCodeMcpConfiguration(agentMcpJson, dest, cliMcpStrategy ?? agentConfig?.mcp?.strategy ?? config.mcp?.strategy, dryRun, verbose, backup);
|
|
404
419
|
}
|
|
405
420
|
// Agents that handle MCP configuration internally should not have external MCP handling
|
|
406
421
|
if (agent.getIdentifier() === 'zed' ||
|
|
@@ -412,20 +427,20 @@ async function applyMcpConfiguration(agent, filteredMcpJson, dest, agentConfig,
|
|
|
412
427
|
}
|
|
413
428
|
return await applyStandardMcpConfiguration(agent, agentMcpJson, dest, agentConfig, config, cliMcpStrategy, dryRun, verbose, backup);
|
|
414
429
|
}
|
|
415
|
-
async function applyOpenHandsMcpConfiguration(filteredMcpJson, dest, dryRun, verbose, backup = true) {
|
|
430
|
+
async function applyOpenHandsMcpConfiguration(filteredMcpJson, dest, strategy, dryRun, verbose, backup = true) {
|
|
416
431
|
if (dryRun) {
|
|
417
432
|
(0, constants_1.logVerbose)(`DRY RUN: Would apply MCP config by updating TOML file: ${dest}`, verbose);
|
|
418
433
|
}
|
|
419
434
|
else {
|
|
420
|
-
await (0, propagateOpenHandsMcp_1.propagateMcpToOpenHands)(filteredMcpJson, dest, backup);
|
|
435
|
+
await (0, propagateOpenHandsMcp_1.propagateMcpToOpenHands)(filteredMcpJson, dest, backup, strategy);
|
|
421
436
|
}
|
|
422
437
|
}
|
|
423
|
-
async function applyOpenCodeMcpConfiguration(filteredMcpJson, dest, dryRun, verbose, backup = true) {
|
|
438
|
+
async function applyOpenCodeMcpConfiguration(filteredMcpJson, dest, strategy, dryRun, verbose, backup = true) {
|
|
424
439
|
if (dryRun) {
|
|
425
440
|
(0, constants_1.logVerbose)(`DRY RUN: Would apply MCP config by updating OpenCode config file: ${dest}`, verbose);
|
|
426
441
|
}
|
|
427
442
|
else {
|
|
428
|
-
await (0, propagateOpenCodeMcp_1.propagateMcpToOpenCode)(filteredMcpJson, dest, backup);
|
|
443
|
+
await (0, propagateOpenCodeMcp_1.propagateMcpToOpenCode)(filteredMcpJson, dest, backup, strategy);
|
|
429
444
|
}
|
|
430
445
|
}
|
|
431
446
|
/**
|
|
@@ -550,17 +565,9 @@ async function applyStandardMcpConfiguration(agent, filteredMcpJson, dest, agent
|
|
|
550
565
|
}
|
|
551
566
|
const CODEX_AGENT_ID = 'codex';
|
|
552
567
|
const isCodexToml = agent.getIdentifier() === CODEX_AGENT_ID && dest.endsWith('.toml');
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
const tomlContent = await fs_1.promises.readFile(dest, 'utf8');
|
|
557
|
-
existing = (0, toml_1.parse)(tomlContent);
|
|
558
|
-
}
|
|
559
|
-
catch (error) {
|
|
560
|
-
(0, constants_1.logVerbose)(`Failed to read Codex MCP TOML at ${dest}: ${error.message}`, verbose);
|
|
561
|
-
// ignore missing or invalid TOML, fall back to previously read value
|
|
562
|
-
}
|
|
563
|
-
}
|
|
568
|
+
const existing = isCodexToml
|
|
569
|
+
? await (0, mcp_1.readNativeMcpToml)(dest, (text) => (0, toml_1.parse)(text))
|
|
570
|
+
: await (0, mcp_1.readNativeMcp)(dest);
|
|
564
571
|
let merged = (0, merge_1.mergeMcp)(existing, mcpToMerge, strategy, serverKey);
|
|
565
572
|
if (isCodexToml) {
|
|
566
573
|
const { [serverKey]: servers, ...rest } = merged;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { IAgent, IAgentConfig } from '../agents/IAgent';
|
|
2
|
+
/**
|
|
3
|
+
* Maps raw agent configuration keys to their corresponding agent identifiers.
|
|
4
|
+
*
|
|
5
|
+
* This function normalizes configuration keys by matching them against agent identifiers
|
|
6
|
+
* and display names. It performs both exact matching (case-insensitive) with agent
|
|
7
|
+
* identifiers and substring matching (case-insensitive) with agent display names
|
|
8
|
+
* for backwards compatibility.
|
|
9
|
+
*
|
|
10
|
+
* @param raw Raw agent configurations with user-provided keys
|
|
11
|
+
* @param agents Array of all available agents
|
|
12
|
+
* @returns Record with agent identifiers as keys and their configurations as values
|
|
13
|
+
*/
|
|
14
|
+
export declare function mapRawAgentConfigs(raw: Record<string, IAgentConfig>, agents: IAgent[]): Record<string, IAgentConfig>;
|
|
@@ -17,11 +17,17 @@ function mapRawAgentConfigs(raw, agents) {
|
|
|
17
17
|
const mappedConfigs = {};
|
|
18
18
|
for (const [key, cfg] of Object.entries(raw)) {
|
|
19
19
|
const lowerKey = key.toLowerCase();
|
|
20
|
+
const exactMatches = agents.filter((agent) => agent.getIdentifier().toLowerCase() === lowerKey);
|
|
21
|
+
// Exact identifier matches take precedence over fuzzy display-name matching.
|
|
22
|
+
if (exactMatches.length > 0) {
|
|
23
|
+
for (const agent of exactMatches) {
|
|
24
|
+
mappedConfigs[agent.getIdentifier()] = cfg;
|
|
25
|
+
}
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
20
28
|
for (const agent of agents) {
|
|
21
29
|
const identifier = agent.getIdentifier();
|
|
22
|
-
|
|
23
|
-
if (identifier === lowerKey ||
|
|
24
|
-
agent.getName().toLowerCase().includes(lowerKey)) {
|
|
30
|
+
if (agent.getName().toLowerCase().includes(lowerKey)) {
|
|
25
31
|
mappedConfigs[identifier] = cfg;
|
|
26
32
|
}
|
|
27
33
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isPathInsideOrEqual(parentPath: string, targetPath: string): boolean;
|
|
@@ -0,0 +1,42 @@
|
|
|
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.isPathInsideOrEqual = isPathInsideOrEqual;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
function isPathInsideOrEqual(parentPath, targetPath) {
|
|
39
|
+
const relative = path.relative(path.resolve(parentPath), path.resolve(targetPath));
|
|
40
|
+
return (relative === '' ||
|
|
41
|
+
(!relative.startsWith('..') && !path.isAbsolute(relative)));
|
|
42
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { IAgent } from '../agents/IAgent';
|
|
2
|
+
import { IAgentConfig } from './ConfigLoader';
|
|
3
|
+
/**
|
|
4
|
+
* Result of reverting an agent configuration
|
|
5
|
+
*/
|
|
6
|
+
export interface RevertAgentResult {
|
|
7
|
+
restored: number;
|
|
8
|
+
removed: number;
|
|
9
|
+
backupsRemoved: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Result of cleaning up auxiliary files
|
|
13
|
+
*/
|
|
14
|
+
export interface CleanUpResult {
|
|
15
|
+
additionalFilesRemoved: number;
|
|
16
|
+
directoriesRemoved: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Reverts configuration for a single agent.
|
|
20
|
+
* @param agent The agent to revert
|
|
21
|
+
* @param projectRoot Root directory of the project
|
|
22
|
+
* @param agentConfig Agent-specific configuration
|
|
23
|
+
* @param keepBackups Whether to keep backup files
|
|
24
|
+
* @param verbose Whether to enable verbose logging
|
|
25
|
+
* @param dryRun Whether to perform a dry run
|
|
26
|
+
* @returns Promise resolving to revert statistics
|
|
27
|
+
*/
|
|
28
|
+
export declare function revertAgentConfiguration(agent: IAgent, projectRoot: string, agentConfig: IAgentConfig | undefined, keepBackups: boolean, verbose: boolean, dryRun: boolean): Promise<RevertAgentResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Cleans up auxiliary files and directories.
|
|
31
|
+
* @param projectRoot Root directory of the project
|
|
32
|
+
* @param verbose Whether to enable verbose logging
|
|
33
|
+
* @param dryRun Whether to perform a dry run
|
|
34
|
+
* @returns Promise resolving to cleanup statistics
|
|
35
|
+
*/
|
|
36
|
+
export declare function cleanUpAuxiliaryFiles(projectRoot: string, verbose: boolean, dryRun: boolean): Promise<CleanUpResult>;
|
|
@@ -40,7 +40,12 @@ const fs_1 = require("fs");
|
|
|
40
40
|
const agent_utils_1 = require("../agents/agent-utils");
|
|
41
41
|
const mcp_1 = require("../paths/mcp");
|
|
42
42
|
const constants_1 = require("../constants");
|
|
43
|
+
const GitignoreUtils_1 = require("./GitignoreUtils");
|
|
43
44
|
const settings_1 = require("../vscode/settings");
|
|
45
|
+
const path_utils_1 = require("./path-utils");
|
|
46
|
+
const RULER_START_MARKER = '# START Ruler Generated Files';
|
|
47
|
+
const RULER_END_MARKER = '# END Ruler Generated Files';
|
|
48
|
+
const RULER_GENERATED_MARKER = '<!-- Generated by Ruler -->';
|
|
44
49
|
/**
|
|
45
50
|
* Checks if a file exists.
|
|
46
51
|
*/
|
|
@@ -53,6 +58,54 @@ async function fileExists(filePath) {
|
|
|
53
58
|
return false;
|
|
54
59
|
}
|
|
55
60
|
}
|
|
61
|
+
async function ignoreFileHasRulerGeneratedPath(ignoreFilePath, generatedPath) {
|
|
62
|
+
try {
|
|
63
|
+
const content = await fs_1.promises.readFile(ignoreFilePath, 'utf8');
|
|
64
|
+
const lines = content.split('\n');
|
|
65
|
+
let inRulerBlock = false;
|
|
66
|
+
for (const line of lines) {
|
|
67
|
+
const trimmed = line.trim();
|
|
68
|
+
if (trimmed === RULER_START_MARKER) {
|
|
69
|
+
inRulerBlock = true;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (trimmed === RULER_END_MARKER) {
|
|
73
|
+
inRulerBlock = false;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (inRulerBlock &&
|
|
77
|
+
(trimmed === generatedPath || trimmed === generatedPath.slice(1))) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
async function hasRulerGeneratedProvenance(filePath, projectRoot) {
|
|
88
|
+
try {
|
|
89
|
+
const content = await fs_1.promises.readFile(filePath, 'utf8');
|
|
90
|
+
if (content.startsWith(RULER_GENERATED_MARKER)) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
const relativePath = `/${path.relative(projectRoot, filePath).replace(/\\/g, '/')}`;
|
|
98
|
+
const ignoreFiles = [
|
|
99
|
+
await (0, GitignoreUtils_1.resolveIgnoreFilePath)(projectRoot, '.gitignore'),
|
|
100
|
+
await (0, GitignoreUtils_1.resolveIgnoreFilePath)(projectRoot, '.git/info/exclude'),
|
|
101
|
+
];
|
|
102
|
+
for (const ignoreFile of ignoreFiles) {
|
|
103
|
+
if (await ignoreFileHasRulerGeneratedPath(ignoreFile, relativePath)) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
56
109
|
/**
|
|
57
110
|
* Restores a file from its backup if the backup exists.
|
|
58
111
|
*/
|
|
@@ -76,7 +129,7 @@ async function restoreFromBackup(filePath, verbose, dryRun) {
|
|
|
76
129
|
/**
|
|
77
130
|
* Removes a file if it exists and has no backup (meaning it was generated by ruler).
|
|
78
131
|
*/
|
|
79
|
-
async function removeGeneratedFile(filePath, verbose, dryRun) {
|
|
132
|
+
async function removeGeneratedFile(filePath, verbose, dryRun, projectRoot) {
|
|
80
133
|
const fileExistsFlag = await fileExists(filePath);
|
|
81
134
|
const backupExists = await fileExists(`${filePath}.bak`);
|
|
82
135
|
if (!fileExistsFlag) {
|
|
@@ -87,6 +140,11 @@ async function removeGeneratedFile(filePath, verbose, dryRun) {
|
|
|
87
140
|
(0, constants_1.logVerbose)(`File has backup, skipping removal: ${filePath}`, verbose);
|
|
88
141
|
return false;
|
|
89
142
|
}
|
|
143
|
+
if (projectRoot &&
|
|
144
|
+
!(await hasRulerGeneratedProvenance(filePath, projectRoot))) {
|
|
145
|
+
(0, constants_1.logVerbose)(`Preserving file without backup or Ruler provenance: ${filePath}`, verbose);
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
90
148
|
const prefix = (0, constants_1.actionPrefix)(dryRun);
|
|
91
149
|
if (dryRun) {
|
|
92
150
|
(0, constants_1.logVerbose)(`${prefix} Would remove generated file: ${filePath}`, verbose);
|
|
@@ -267,6 +325,9 @@ async function removeAdditionalAgentFiles(projectRoot, verbose, dryRun) {
|
|
|
267
325
|
filesRemoved++;
|
|
268
326
|
}
|
|
269
327
|
}
|
|
328
|
+
else if (!(await hasRulerGeneratedProvenance(fullPath, projectRoot))) {
|
|
329
|
+
(0, constants_1.logVerbose)(`Preserving additional file without backup or Ruler provenance: ${fullPath}`, verbose);
|
|
330
|
+
}
|
|
270
331
|
else {
|
|
271
332
|
if (dryRun) {
|
|
272
333
|
(0, constants_1.logVerbose)(`${prefix} Would remove additional file: ${fullPath}`, verbose);
|
|
@@ -288,7 +349,7 @@ async function removeAdditionalAgentFiles(projectRoot, verbose, dryRun) {
|
|
|
288
349
|
const restored = await restoreFromBackup(settingsPath, verbose, dryRun);
|
|
289
350
|
if (restored) {
|
|
290
351
|
filesRemoved++;
|
|
291
|
-
(0, constants_1.logVerbose)(`${
|
|
352
|
+
(0, constants_1.logVerbose)(`${prefix} Restored VSCode settings from backup`, verbose);
|
|
292
353
|
}
|
|
293
354
|
}
|
|
294
355
|
else if (await fileExists(settingsPath)) {
|
|
@@ -299,10 +360,10 @@ async function removeAdditionalAgentFiles(projectRoot, verbose, dryRun) {
|
|
|
299
360
|
delete settings['augment.advanced'];
|
|
300
361
|
const remainingKeys = Object.keys(settings);
|
|
301
362
|
if (remainingKeys.length === 0) {
|
|
302
|
-
(0, constants_1.logVerbose)(`${
|
|
363
|
+
(0, constants_1.logVerbose)(`${prefix} Would remove empty VSCode settings file`, verbose);
|
|
303
364
|
}
|
|
304
365
|
else {
|
|
305
|
-
(0, constants_1.logVerbose)(`${
|
|
366
|
+
(0, constants_1.logVerbose)(`${prefix} Would remove augment.advanced section from ${settingsPath}`, verbose);
|
|
306
367
|
}
|
|
307
368
|
filesRemoved++;
|
|
308
369
|
}
|
|
@@ -314,11 +375,11 @@ async function removeAdditionalAgentFiles(projectRoot, verbose, dryRun) {
|
|
|
314
375
|
const remainingKeys = Object.keys(settings);
|
|
315
376
|
if (remainingKeys.length === 0) {
|
|
316
377
|
await fs_1.promises.unlink(settingsPath);
|
|
317
|
-
(0, constants_1.logVerbose)(`${
|
|
378
|
+
(0, constants_1.logVerbose)(`${prefix} Removed empty VSCode settings file`, verbose);
|
|
318
379
|
}
|
|
319
380
|
else {
|
|
320
381
|
await (0, settings_1.writeVSCodeSettings)(settingsPath, settings);
|
|
321
|
-
(0, constants_1.logVerbose)(`${
|
|
382
|
+
(0, constants_1.logVerbose)(`${prefix} Removed augment.advanced section from VSCode settings`, verbose);
|
|
322
383
|
}
|
|
323
384
|
filesRemoved++;
|
|
324
385
|
}
|
|
@@ -363,7 +424,7 @@ async function revertAgentConfiguration(agent, projectRoot, agentConfig, keepBac
|
|
|
363
424
|
}
|
|
364
425
|
}
|
|
365
426
|
else {
|
|
366
|
-
const removed = await removeGeneratedFile(outputPath, verbose, dryRun);
|
|
427
|
+
const removed = await removeGeneratedFile(outputPath, verbose, dryRun, projectRoot);
|
|
367
428
|
if (removed) {
|
|
368
429
|
result.removed++;
|
|
369
430
|
}
|
|
@@ -371,7 +432,7 @@ async function revertAgentConfiguration(agent, projectRoot, agentConfig, keepBac
|
|
|
371
432
|
}
|
|
372
433
|
// Handle MCP files
|
|
373
434
|
const mcpPath = await (0, mcp_1.getNativeMcpPath)(agent.getName(), projectRoot);
|
|
374
|
-
if (mcpPath &&
|
|
435
|
+
if (mcpPath && (0, path_utils_1.isPathInsideOrEqual)(projectRoot, mcpPath)) {
|
|
375
436
|
if (agent.getName() === 'AugmentCode' &&
|
|
376
437
|
mcpPath.endsWith('.vscode/settings.json')) {
|
|
377
438
|
(0, constants_1.logVerbose)(`Skipping MCP handling for AugmentCode settings.json - handled separately`, verbose);
|
|
@@ -388,7 +449,7 @@ async function revertAgentConfiguration(agent, projectRoot, agentConfig, keepBac
|
|
|
388
449
|
}
|
|
389
450
|
}
|
|
390
451
|
else {
|
|
391
|
-
const mcpRemoved = await removeGeneratedFile(mcpPath, verbose, dryRun);
|
|
452
|
+
const mcpRemoved = await removeGeneratedFile(mcpPath, verbose, dryRun, projectRoot);
|
|
392
453
|
if (mcpRemoved) {
|
|
393
454
|
result.removed++;
|
|
394
455
|
}
|
package/dist/lib.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { allAgents } from './agents';
|
|
2
|
+
import { McpStrategy } from './types';
|
|
3
|
+
export { allAgents };
|
|
4
|
+
/**
|
|
5
|
+
* Applies ruler configurations for all supported AI agents.
|
|
6
|
+
* @param projectRoot Root directory of the project
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Applies ruler configurations for selected AI agents.
|
|
10
|
+
* @param projectRoot Root directory of the project
|
|
11
|
+
* @param includedAgents Optional list of agent name filters (case-insensitive substrings)
|
|
12
|
+
*/
|
|
13
|
+
export declare function applyAllAgentConfigs(projectRoot: string, includedAgents?: string[], configPath?: string, cliMcpEnabled?: boolean, cliMcpStrategy?: McpStrategy, cliGitignoreEnabled?: boolean, verbose?: boolean, dryRun?: boolean, localOnly?: boolean, nested?: boolean, backup?: boolean, skillsEnabled?: boolean, cliGitignoreLocal?: boolean, subagentsEnabled?: boolean): Promise<void>;
|
package/dist/lib.js
CHANGED
|
@@ -53,6 +53,17 @@ function resolveSkillsEnabled(cliFlag, configSetting) {
|
|
|
53
53
|
? configSetting
|
|
54
54
|
: true; // default to enabled
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Resolves backup enabled state based on precedence:
|
|
58
|
+
* CLI flag > ruler.toml > default (enabled).
|
|
59
|
+
*/
|
|
60
|
+
function resolveBackupEnabled(cliFlag, configSetting) {
|
|
61
|
+
return cliFlag !== undefined
|
|
62
|
+
? cliFlag
|
|
63
|
+
: configSetting !== undefined
|
|
64
|
+
? configSetting
|
|
65
|
+
: true; // default to enabled
|
|
66
|
+
}
|
|
56
67
|
/**
|
|
57
68
|
* Resolves subagents enabled state based on precedence:
|
|
58
69
|
* CLI flag > ruler.toml > default (disabled).
|
|
@@ -70,6 +81,9 @@ function resolveSubagentsEnabled(cliFlag, configSetting) {
|
|
|
70
81
|
? configSetting
|
|
71
82
|
: false; // default to disabled — see spec: subagents must opt in
|
|
72
83
|
}
|
|
84
|
+
function resolveSubagentsCleanupOrphaned(configSetting) {
|
|
85
|
+
return configSetting === true;
|
|
86
|
+
}
|
|
73
87
|
/**
|
|
74
88
|
* Applies ruler configurations for all supported AI agents.
|
|
75
89
|
* @param projectRoot Root directory of the project
|
|
@@ -79,7 +93,7 @@ function resolveSubagentsEnabled(cliFlag, configSetting) {
|
|
|
79
93
|
* @param projectRoot Root directory of the project
|
|
80
94
|
* @param includedAgents Optional list of agent name filters (case-insensitive substrings)
|
|
81
95
|
*/
|
|
82
|
-
async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cliMcpEnabled = true, cliMcpStrategy, cliGitignoreEnabled, verbose = false, dryRun = false, localOnly = false, nested = false, backup
|
|
96
|
+
async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cliMcpEnabled = true, cliMcpStrategy, cliGitignoreEnabled, verbose = false, dryRun = false, localOnly = false, nested = false, backup, skillsEnabled, cliGitignoreLocal, subagentsEnabled) {
|
|
83
97
|
// Load configuration and rules
|
|
84
98
|
(0, constants_1.logVerbose)(`Loading configuration from project root: ${projectRoot}`, verbose);
|
|
85
99
|
if (configPath) {
|
|
@@ -119,15 +133,17 @@ async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cli
|
|
|
119
133
|
}
|
|
120
134
|
// Propagate subagents (mirrors skills handling for nested mode).
|
|
121
135
|
const subagentsEnabledResolved = resolveSubagentsEnabled(subagentsEnabled, rootConfig.subagents?.enabled);
|
|
136
|
+
const subagentsCleanupOrphaned = resolveSubagentsCleanupOrphaned(rootConfig.subagents?.cleanup_orphaned);
|
|
137
|
+
const backupEnabledResolved = resolveBackupEnabled(backup, rootConfig.backup?.enabled);
|
|
122
138
|
{
|
|
123
139
|
const { propagateSubagents } = await Promise.resolve().then(() => __importStar(require('./core/SubagentsProcessor')));
|
|
124
140
|
for (const configEntry of hierarchicalConfigs) {
|
|
125
141
|
const nestedRoot = path.dirname(configEntry.rulerDir);
|
|
126
142
|
(0, constants_1.logVerbose)(`Propagating subagents for nested directory: ${nestedRoot}`, verbose);
|
|
127
|
-
await propagateSubagents(nestedRoot, selectedAgents, subagentsEnabledResolved, verbose, dryRun);
|
|
143
|
+
await propagateSubagents(nestedRoot, selectedAgents, subagentsEnabledResolved, subagentsCleanupOrphaned, verbose, dryRun);
|
|
128
144
|
}
|
|
129
145
|
}
|
|
130
|
-
generatedPaths = await (0, apply_engine_1.processHierarchicalConfigurations)(selectedAgents, hierarchicalConfigs, verbose, dryRun, cliMcpEnabled, cliMcpStrategy,
|
|
146
|
+
generatedPaths = await (0, apply_engine_1.processHierarchicalConfigurations)(selectedAgents, hierarchicalConfigs, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backupEnabledResolved);
|
|
131
147
|
}
|
|
132
148
|
else {
|
|
133
149
|
const singleConfig = await (0, apply_engine_1.loadSingleConfiguration)(projectRoot, configPath, localOnly);
|
|
@@ -146,11 +162,13 @@ async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cli
|
|
|
146
162
|
}
|
|
147
163
|
// Propagate subagents (mirrors skills handling).
|
|
148
164
|
const subagentsEnabledResolvedSingle = resolveSubagentsEnabled(subagentsEnabled, singleConfig.config.subagents?.enabled);
|
|
165
|
+
const subagentsCleanupOrphanedSingle = resolveSubagentsCleanupOrphaned(singleConfig.config.subagents?.cleanup_orphaned);
|
|
166
|
+
const backupEnabledResolvedSingle = resolveBackupEnabled(backup, singleConfig.config.backup?.enabled);
|
|
149
167
|
{
|
|
150
168
|
const { propagateSubagents } = await Promise.resolve().then(() => __importStar(require('./core/SubagentsProcessor')));
|
|
151
|
-
await propagateSubagents(projectRoot, selectedAgents, subagentsEnabledResolvedSingle, verbose, dryRun);
|
|
169
|
+
await propagateSubagents(projectRoot, selectedAgents, subagentsEnabledResolvedSingle, subagentsCleanupOrphanedSingle, verbose, dryRun);
|
|
152
170
|
}
|
|
153
|
-
generatedPaths = await (0, apply_engine_1.processSingleConfiguration)(selectedAgents, singleConfig, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy,
|
|
171
|
+
generatedPaths = await (0, apply_engine_1.processSingleConfiguration)(selectedAgents, singleConfig, projectRoot, verbose, dryRun, cliMcpEnabled, cliMcpStrategy, backupEnabledResolvedSingle);
|
|
154
172
|
}
|
|
155
173
|
// Add skills-generated paths to gitignore if skills are enabled
|
|
156
174
|
let allGeneratedPaths = generatedPaths;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { IAgent } from '../agents/IAgent';
|
|
2
|
+
/**
|
|
3
|
+
* MCP capability types for agents
|
|
4
|
+
*/
|
|
5
|
+
export interface McpCapabilities {
|
|
6
|
+
supportsStdio: boolean;
|
|
7
|
+
supportsRemote: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Derives MCP capabilities for an agent
|
|
11
|
+
*/
|
|
12
|
+
export declare function getAgentMcpCapabilities(agent: IAgent): McpCapabilities;
|
|
13
|
+
/**
|
|
14
|
+
* Checks if an agent supports any MCP functionality
|
|
15
|
+
*/
|
|
16
|
+
export declare function agentSupportsMcp(agent: IAgent): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Filters MCP configuration based on agent capabilities
|
|
19
|
+
*/
|
|
20
|
+
export declare function filterMcpConfigForAgent(mcpConfig: Record<string, unknown>, agent: IAgent): Record<string, unknown> | null;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { McpStrategy } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Merge native and incoming MCP server configurations according to strategy.
|
|
4
|
+
* @param base Existing native MCP config object.
|
|
5
|
+
* @param incoming Ruler MCP config object.
|
|
6
|
+
* @param strategy Merge strategy: 'merge' to union servers, 'overwrite' to replace.
|
|
7
|
+
* @param serverKey The key to use for servers in the output (e.g., 'servers' for Copilot, 'mcpServers' for others).
|
|
8
|
+
* @returns Merged MCP config object.
|
|
9
|
+
*/
|
|
10
|
+
export declare function mergeMcp(base: Record<string, unknown>, incoming: Record<string, unknown>, strategy: McpStrategy, serverKey: string): Record<string, unknown>;
|