@intellectronica/ruler 0.3.41 → 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.
- package/README.md +135 -36
- package/dist/agents/AbstractAgent.d.ts +53 -0
- package/dist/agents/AbstractAgent.js +3 -2
- package/dist/agents/AgentsMdAgent.d.ts +14 -0
- package/dist/agents/AgentsMdAgent.js +3 -2
- package/dist/agents/AiderAgent.d.ts +14 -0
- package/dist/agents/AiderAgent.js +7 -4
- package/dist/agents/AmazonQCliAgent.d.ts +13 -0
- package/dist/agents/AmazonQCliAgent.js +6 -4
- 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/AugmentCodeAgent.js +3 -2
- 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/CodexCliAgent.js +1 -1
- package/dist/agents/CopilotAgent.d.ts +20 -0
- package/dist/agents/CrushAgent.d.ts +14 -0
- package/dist/agents/CrushAgent.js +18 -6
- 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/FirebenderAgent.js +5 -4
- package/dist/agents/GeminiCliAgent.d.ts +12 -0
- package/dist/agents/GeminiCliAgent.js +13 -7
- package/dist/agents/GooseAgent.d.ts +12 -0
- package/dist/agents/IAgent.d.ts +74 -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/MistralVibeAgent.js +14 -3
- package/dist/agents/OpenCodeAgent.d.ts +11 -0
- package/dist/agents/OpenCodeAgent.js +24 -12
- package/dist/agents/OpenHandsAgent.d.ts +8 -0
- package/dist/agents/PiAgent.d.ts +9 -0
- package/dist/agents/QwenCodeAgent.d.ts +11 -0
- package/dist/agents/QwenCodeAgent.js +11 -5
- package/dist/agents/RooCodeAgent.d.ts +16 -0
- package/dist/agents/RooCodeAgent.js +3 -2
- 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 +8 -5
- 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 +1 -2
- package/dist/cli/handlers.d.ts +41 -0
- package/dist/cli/handlers.js +75 -59
- package/dist/cli/index.d.ts +2 -0
- package/dist/constants.d.ts +35 -0
- package/dist/constants.js +1 -1
- package/dist/core/ConfigLoader.d.ts +59 -0
- package/dist/core/ConfigLoader.js +178 -44
- package/dist/core/FileSystemUtils.d.ts +53 -0
- package/dist/core/FileSystemUtils.js +157 -20
- package/dist/core/GitignoreUtils.d.ts +25 -0
- package/dist/core/GitignoreUtils.js +94 -32
- package/dist/core/RuleProcessor.d.ts +8 -0
- package/dist/core/SkillsProcessor.d.ts +127 -0
- package/dist/core/SkillsProcessor.js +118 -223
- package/dist/core/SkillsUtils.d.ts +26 -0
- package/dist/core/SubagentsProcessor.d.ts +38 -0
- package/dist/core/SubagentsProcessor.js +8 -5
- package/dist/core/SubagentsUtils.d.ts +34 -0
- package/dist/core/UnifiedConfigLoader.d.ts +10 -0
- package/dist/core/UnifiedConfigLoader.js +115 -33
- package/dist/core/UnifiedConfigTypes.d.ts +97 -0
- package/dist/core/agent-selection.d.ts +12 -0
- package/dist/core/agent-selection.js +17 -7
- package/dist/core/apply-engine.d.ts +70 -0
- package/dist/core/apply-engine.js +88 -58
- 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 +37 -0
- package/dist/core/revert-engine.js +142 -34
- package/dist/lib.d.ts +13 -0
- package/dist/lib.js +24 -8
- package/dist/mcp/capabilities.d.ts +20 -0
- package/dist/mcp/merge.d.ts +10 -0
- package/dist/mcp/merge.js +36 -16
- package/dist/mcp/propagateOpenCodeMcp.d.ts +2 -0
- package/dist/mcp/propagateOpenCodeMcp.js +30 -11
- package/dist/mcp/propagateOpenHandsMcp.d.ts +2 -0
- package/dist/mcp/propagateOpenHandsMcp.js +48 -21
- 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 +44 -8
- package/dist/revert.d.ts +6 -0
- package/dist/revert.js +58 -46
- package/dist/types.d.ts +87 -0
- package/dist/vscode/settings.d.ts +40 -0
- package/dist/vscode/settings.js +3 -3
- package/package.json +8 -5
|
@@ -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) {
|
|
@@ -103,9 +105,10 @@ async function createHierarchicalConfiguration(rulerDir, files, config, cliConfi
|
|
|
103
105
|
config,
|
|
104
106
|
concatenatedRules,
|
|
105
107
|
rulerMcpJson,
|
|
108
|
+
projectRoot: directoryRoot,
|
|
106
109
|
};
|
|
107
110
|
}
|
|
108
|
-
async function loadConfigForRulerDir(rulerDir, cliConfigPath, resolvedNested) {
|
|
111
|
+
async function loadConfigForRulerDir(rulerDir, cliConfigPath, resolvedNested, localOnly) {
|
|
109
112
|
const directoryRoot = path.dirname(rulerDir);
|
|
110
113
|
const localConfigPath = path.join(rulerDir, 'ruler.toml');
|
|
111
114
|
let hasLocalConfig = false;
|
|
@@ -119,6 +122,7 @@ async function loadConfigForRulerDir(rulerDir, cliConfigPath, resolvedNested) {
|
|
|
119
122
|
const loaded = await (0, ConfigLoader_1.loadConfig)({
|
|
120
123
|
projectRoot: directoryRoot,
|
|
121
124
|
configPath: hasLocalConfig ? localConfigPath : cliConfigPath,
|
|
125
|
+
checkGlobal: !localOnly,
|
|
122
126
|
});
|
|
123
127
|
const cloned = cloneLoadedConfig(loaded);
|
|
124
128
|
if (resolvedNested) {
|
|
@@ -136,6 +140,12 @@ function cloneLoadedConfig(config) {
|
|
|
136
140
|
clonedAgentConfigs[agent] = {
|
|
137
141
|
...agentConfig,
|
|
138
142
|
mcp: agentConfig.mcp ? { ...agentConfig.mcp } : undefined,
|
|
143
|
+
mcpServers: agentConfig.mcpServers
|
|
144
|
+
? Object.fromEntries(Object.entries(agentConfig.mcpServers).map(([name, server]) => [
|
|
145
|
+
name,
|
|
146
|
+
{ ...server },
|
|
147
|
+
]))
|
|
148
|
+
: undefined,
|
|
139
149
|
};
|
|
140
150
|
}
|
|
141
151
|
return {
|
|
@@ -144,6 +154,7 @@ function cloneLoadedConfig(config) {
|
|
|
144
154
|
cliAgents: config.cliAgents ? [...config.cliAgents] : undefined,
|
|
145
155
|
mcp: config.mcp ? { ...config.mcp } : undefined,
|
|
146
156
|
gitignore: config.gitignore ? { ...config.gitignore } : undefined,
|
|
157
|
+
backup: config.backup ? { ...config.backup } : undefined,
|
|
147
158
|
skills: config.skills ? { ...config.skills } : undefined,
|
|
148
159
|
subagents: config.subagents ? { ...config.subagents } : undefined,
|
|
149
160
|
nested: config.nested,
|
|
@@ -156,18 +167,10 @@ function cloneLoadedConfig(config) {
|
|
|
156
167
|
async function findRulerDirectories(projectRoot, localOnly, hierarchical) {
|
|
157
168
|
if (hierarchical) {
|
|
158
169
|
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) {
|
|
170
|
+
if (dirs.length === 0) {
|
|
168
171
|
throw (0, constants_1.createRulerError)(`.ruler directory not found`, `Searched from: ${projectRoot}`);
|
|
169
172
|
}
|
|
170
|
-
return { dirs
|
|
173
|
+
return { dirs, primaryDir: dirs[0] };
|
|
171
174
|
}
|
|
172
175
|
else {
|
|
173
176
|
const dir = await FileSystemUtils.findRulerDir(projectRoot, !localOnly);
|
|
@@ -198,10 +201,12 @@ async function loadSingleConfiguration(projectRoot, configPath, localOnly) {
|
|
|
198
201
|
const { dirs: rulerDirs, primaryDir } = await findRulerDirectories(projectRoot, localOnly, false);
|
|
199
202
|
// Warn about legacy mcp.json
|
|
200
203
|
await warnAboutLegacyMcpJson(primaryDir);
|
|
204
|
+
const effectiveProjectRoot = FileSystemUtils.resolveProjectRootForRulerDir(projectRoot, primaryDir);
|
|
201
205
|
// Load the ruler.toml configuration
|
|
202
206
|
const config = await (0, ConfigLoader_1.loadConfig)({
|
|
203
|
-
projectRoot,
|
|
207
|
+
projectRoot: effectiveProjectRoot,
|
|
204
208
|
configPath,
|
|
209
|
+
checkGlobal: !localOnly,
|
|
205
210
|
});
|
|
206
211
|
// Read rule files. `.ruler/agents/` is only included when
|
|
207
212
|
// `[agents] include_in_rules = true`.
|
|
@@ -212,7 +217,11 @@ async function loadSingleConfiguration(projectRoot, configPath, localOnly) {
|
|
|
212
217
|
const concatenatedRules = (0, RuleProcessor_1.concatenateRules)(files, path.dirname(primaryDir));
|
|
213
218
|
// Load unified config to get merged MCP configuration
|
|
214
219
|
const { loadUnifiedConfig } = await Promise.resolve().then(() => __importStar(require('./UnifiedConfigLoader')));
|
|
215
|
-
const unifiedConfig = await loadUnifiedConfig({
|
|
220
|
+
const unifiedConfig = await loadUnifiedConfig({
|
|
221
|
+
projectRoot: effectiveProjectRoot,
|
|
222
|
+
configPath,
|
|
223
|
+
checkGlobal: !localOnly,
|
|
224
|
+
});
|
|
216
225
|
// Synthesize rulerMcpJson from unified MCP bundle for backward compatibility
|
|
217
226
|
let rulerMcpJson = null;
|
|
218
227
|
if (unifiedConfig.mcp && Object.keys(unifiedConfig.mcp.servers).length > 0) {
|
|
@@ -224,6 +233,7 @@ async function loadSingleConfiguration(projectRoot, configPath, localOnly) {
|
|
|
224
233
|
config,
|
|
225
234
|
concatenatedRules,
|
|
226
235
|
rulerMcpJson,
|
|
236
|
+
projectRoot: effectiveProjectRoot,
|
|
227
237
|
};
|
|
228
238
|
}
|
|
229
239
|
/**
|
|
@@ -281,7 +291,7 @@ async function applyConfigurationsToAgents(agents, concatenatedRules, rulerMcpJs
|
|
|
281
291
|
(0, constants_1.logInfo)(`Applying rules for ${agent.getName()}...`, dryRun);
|
|
282
292
|
(0, constants_1.logVerbose)(`Processing agent: ${agent.getName()}`, verbose);
|
|
283
293
|
const agentConfig = config.agentConfigs[agent.getIdentifier()];
|
|
284
|
-
const agentRulerMcpJson = rulerMcpJson;
|
|
294
|
+
const agentRulerMcpJson = mergeAgentMcpServers(rulerMcpJson, agentConfig);
|
|
285
295
|
// Collect output paths for .gitignore
|
|
286
296
|
const outputPaths = (0, agent_utils_1.getAgentOutputPaths)(agent, projectRoot, agentConfig);
|
|
287
297
|
(0, constants_1.logVerbose)(`Agent ${agent.getName()} output paths: ${outputPaths.join(', ')}`, verbose);
|
|
@@ -306,22 +316,27 @@ async function applyConfigurationsToAgents(agents, concatenatedRules, rulerMcpJs
|
|
|
306
316
|
agentsMdWritten = true;
|
|
307
317
|
}
|
|
308
318
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
322
|
-
}
|
|
319
|
+
const effectiveMcpEnabled = cliMcpEnabled &&
|
|
320
|
+
(agentConfig?.mcp?.enabled ?? config.mcp?.enabled ?? true);
|
|
321
|
+
const effectiveMcpStrategy = cliMcpStrategy ??
|
|
322
|
+
agentConfig?.mcp?.strategy ??
|
|
323
|
+
config.mcp?.strategy ??
|
|
324
|
+
'merge';
|
|
325
|
+
const finalAgentConfig = {
|
|
326
|
+
...agentConfig,
|
|
327
|
+
mcp: {
|
|
328
|
+
...agentConfig?.mcp,
|
|
329
|
+
enabled: effectiveMcpEnabled,
|
|
330
|
+
strategy: effectiveMcpStrategy,
|
|
331
|
+
},
|
|
332
|
+
};
|
|
333
|
+
const mcpForAgentApply = shouldUseEngineManagedMcp(agent)
|
|
334
|
+
? null
|
|
335
|
+
: effectiveMcpEnabled
|
|
336
|
+
? agentRulerMcpJson
|
|
337
|
+
: null;
|
|
323
338
|
if (!skipApplyForThisAgent) {
|
|
324
|
-
await agent.applyRulerConfig(concatenatedRules, projectRoot,
|
|
339
|
+
await agent.applyRulerConfig(concatenatedRules, projectRoot, mcpForAgentApply, finalAgentConfig, backup);
|
|
325
340
|
}
|
|
326
341
|
}
|
|
327
342
|
// Handle MCP configuration
|
|
@@ -334,7 +349,7 @@ async function handleMcpConfiguration(agent, agentConfig, config, rulerMcpJson,
|
|
|
334
349
|
(0, constants_1.logVerbose)(`Agent ${agent.getName()} does not support MCP - skipping MCP configuration`, verbose);
|
|
335
350
|
return;
|
|
336
351
|
}
|
|
337
|
-
const dest = await (
|
|
352
|
+
const dest = await resolveMcpDestination(agent, agentConfig, projectRoot);
|
|
338
353
|
const mcpEnabledForAgent = cliMcpEnabled && (agentConfig?.mcp?.enabled ?? config.mcp?.enabled ?? true);
|
|
339
354
|
if (!dest || !mcpEnabledForAgent) {
|
|
340
355
|
return;
|
|
@@ -349,8 +364,30 @@ async function handleMcpConfiguration(agent, agentConfig, config, rulerMcpJson,
|
|
|
349
364
|
await updateGitignoreForMcpFile(dest, projectRoot, generatedPaths, backup);
|
|
350
365
|
await applyMcpConfiguration(agent, filteredMcpJson, dest, agentConfig, config, projectRoot, cliMcpStrategy, dryRun, verbose, backup);
|
|
351
366
|
}
|
|
367
|
+
function shouldUseEngineManagedMcp(agent) {
|
|
368
|
+
return (agent.getIdentifier() === 'codex' || agent.getIdentifier() === 'opencode');
|
|
369
|
+
}
|
|
370
|
+
function mergeAgentMcpServers(rulerMcpJson, agentConfig) {
|
|
371
|
+
const baseServers = rulerMcpJson?.mcpServers && typeof rulerMcpJson.mcpServers === 'object'
|
|
372
|
+
? rulerMcpJson.mcpServers
|
|
373
|
+
: {};
|
|
374
|
+
const agentServers = agentConfig?.mcpServers ?? {};
|
|
375
|
+
const mergedServers = {
|
|
376
|
+
...baseServers,
|
|
377
|
+
...agentServers,
|
|
378
|
+
};
|
|
379
|
+
return Object.keys(mergedServers).length > 0
|
|
380
|
+
? { mcpServers: mergedServers }
|
|
381
|
+
: null;
|
|
382
|
+
}
|
|
383
|
+
async function resolveMcpDestination(agent, agentConfig, projectRoot) {
|
|
384
|
+
if (agentConfig?.outputPathConfig) {
|
|
385
|
+
return path.resolve(projectRoot, agentConfig.outputPathConfig);
|
|
386
|
+
}
|
|
387
|
+
return await (0, mcp_1.getNativeMcpPath)(agent.getName(), projectRoot);
|
|
388
|
+
}
|
|
352
389
|
async function updateGitignoreForMcpFile(dest, projectRoot, generatedPaths, backup = true) {
|
|
353
|
-
if (
|
|
390
|
+
if ((0, path_utils_1.isPathInsideOrEqual)(projectRoot, dest)) {
|
|
354
391
|
const relativeDest = path.relative(projectRoot, dest);
|
|
355
392
|
generatedPaths.push(relativeDest);
|
|
356
393
|
if (backup) {
|
|
@@ -391,16 +428,16 @@ function sanitizeMcpTimeoutsForAgent(agent, mcpJson, dryRun) {
|
|
|
391
428
|
}
|
|
392
429
|
async function applyMcpConfiguration(agent, filteredMcpJson, dest, agentConfig, config, projectRoot, cliMcpStrategy, dryRun, verbose, backup = true) {
|
|
393
430
|
// Prevent writing MCP configs outside the project root (e.g., legacy home-directory targets)
|
|
394
|
-
if (!
|
|
431
|
+
if (!(0, path_utils_1.isPathInsideOrEqual)(projectRoot, dest)) {
|
|
395
432
|
(0, constants_1.logVerbose)(`Skipping MCP config for ${agent.getName()} because target path is outside project: ${dest}`, verbose);
|
|
396
433
|
return;
|
|
397
434
|
}
|
|
398
435
|
const agentMcpJson = sanitizeMcpTimeoutsForAgent(agent, filteredMcpJson, dryRun);
|
|
399
436
|
if (agent.getIdentifier() === 'openhands') {
|
|
400
|
-
return await applyOpenHandsMcpConfiguration(agentMcpJson, dest, dryRun, verbose, backup);
|
|
437
|
+
return await applyOpenHandsMcpConfiguration(agentMcpJson, dest, projectRoot, cliMcpStrategy ?? agentConfig?.mcp?.strategy ?? config.mcp?.strategy, dryRun, verbose, backup);
|
|
401
438
|
}
|
|
402
439
|
if (agent.getIdentifier() === 'opencode') {
|
|
403
|
-
return await applyOpenCodeMcpConfiguration(agentMcpJson, dest, dryRun, verbose, backup);
|
|
440
|
+
return await applyOpenCodeMcpConfiguration(agentMcpJson, dest, projectRoot, cliMcpStrategy ?? agentConfig?.mcp?.strategy ?? config.mcp?.strategy, dryRun, verbose, backup);
|
|
404
441
|
}
|
|
405
442
|
// Agents that handle MCP configuration internally should not have external MCP handling
|
|
406
443
|
if (agent.getIdentifier() === 'zed' ||
|
|
@@ -410,22 +447,22 @@ async function applyMcpConfiguration(agent, filteredMcpJson, dest, agentConfig,
|
|
|
410
447
|
(0, constants_1.logVerbose)(`Skipping external MCP config for ${agent.getName()} - handled internally by agent`, verbose);
|
|
411
448
|
return;
|
|
412
449
|
}
|
|
413
|
-
return await applyStandardMcpConfiguration(agent, agentMcpJson, dest, agentConfig, config, cliMcpStrategy, dryRun, verbose, backup);
|
|
450
|
+
return await applyStandardMcpConfiguration(agent, agentMcpJson, dest, agentConfig, config, projectRoot, cliMcpStrategy, dryRun, verbose, backup);
|
|
414
451
|
}
|
|
415
|
-
async function applyOpenHandsMcpConfiguration(filteredMcpJson, dest, dryRun, verbose, backup = true) {
|
|
452
|
+
async function applyOpenHandsMcpConfiguration(filteredMcpJson, dest, projectRoot, strategy, dryRun, verbose, backup = true) {
|
|
416
453
|
if (dryRun) {
|
|
417
454
|
(0, constants_1.logVerbose)(`DRY RUN: Would apply MCP config by updating TOML file: ${dest}`, verbose);
|
|
418
455
|
}
|
|
419
456
|
else {
|
|
420
|
-
await (0, propagateOpenHandsMcp_1.propagateMcpToOpenHands)(filteredMcpJson, dest, backup);
|
|
457
|
+
await (0, propagateOpenHandsMcp_1.propagateMcpToOpenHands)(filteredMcpJson, dest, backup, strategy, projectRoot);
|
|
421
458
|
}
|
|
422
459
|
}
|
|
423
|
-
async function applyOpenCodeMcpConfiguration(filteredMcpJson, dest, dryRun, verbose, backup = true) {
|
|
460
|
+
async function applyOpenCodeMcpConfiguration(filteredMcpJson, dest, projectRoot, strategy, dryRun, verbose, backup = true) {
|
|
424
461
|
if (dryRun) {
|
|
425
462
|
(0, constants_1.logVerbose)(`DRY RUN: Would apply MCP config by updating OpenCode config file: ${dest}`, verbose);
|
|
426
463
|
}
|
|
427
464
|
else {
|
|
428
|
-
await (0, propagateOpenCodeMcp_1.propagateMcpToOpenCode)(filteredMcpJson, dest, backup);
|
|
465
|
+
await (0, propagateOpenCodeMcp_1.propagateMcpToOpenCode)(filteredMcpJson, dest, backup, strategy, projectRoot);
|
|
429
466
|
}
|
|
430
467
|
}
|
|
431
468
|
/**
|
|
@@ -521,7 +558,7 @@ function transformMcpForFactoryDroid(mcpJson) {
|
|
|
521
558
|
transformedMcp.mcpServers = transformedServers;
|
|
522
559
|
return transformedMcp;
|
|
523
560
|
}
|
|
524
|
-
async function applyStandardMcpConfiguration(agent, filteredMcpJson, dest, agentConfig, config, cliMcpStrategy, dryRun, verbose, backup = true) {
|
|
561
|
+
async function applyStandardMcpConfiguration(agent, filteredMcpJson, dest, agentConfig, config, projectRoot, cliMcpStrategy, dryRun, verbose, backup = true) {
|
|
525
562
|
const strategy = cliMcpStrategy ??
|
|
526
563
|
agentConfig?.mcp?.strategy ??
|
|
527
564
|
config.mcp?.strategy ??
|
|
@@ -539,7 +576,8 @@ async function applyStandardMcpConfiguration(agent, filteredMcpJson, dest, agent
|
|
|
539
576
|
else {
|
|
540
577
|
// Transform MCP config for agent-specific compatibility
|
|
541
578
|
let mcpToMerge = filteredMcpJson;
|
|
542
|
-
if (agent.getIdentifier() === 'claude'
|
|
579
|
+
if (agent.getIdentifier() === 'claude' ||
|
|
580
|
+
agent.getIdentifier() === 'aider') {
|
|
543
581
|
mcpToMerge = transformMcpForClaude(filteredMcpJson);
|
|
544
582
|
}
|
|
545
583
|
else if (agent.getIdentifier() === 'kilocode') {
|
|
@@ -550,17 +588,9 @@ async function applyStandardMcpConfiguration(agent, filteredMcpJson, dest, agent
|
|
|
550
588
|
}
|
|
551
589
|
const CODEX_AGENT_ID = 'codex';
|
|
552
590
|
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
|
-
}
|
|
591
|
+
const existing = isCodexToml
|
|
592
|
+
? await (0, mcp_1.readNativeMcpToml)(dest, (text) => (0, toml_1.parse)(text))
|
|
593
|
+
: await (0, mcp_1.readNativeMcp)(dest);
|
|
564
594
|
let merged = (0, merge_1.mergeMcp)(existing, mcpToMerge, strategy, serverKey);
|
|
565
595
|
if (isCodexToml) {
|
|
566
596
|
const { [serverKey]: servers, ...rest } = merged;
|
|
@@ -626,13 +656,13 @@ async function applyStandardMcpConfiguration(agent, filteredMcpJson, dest, agent
|
|
|
626
656
|
if (currentContent !== newContent) {
|
|
627
657
|
if (backup) {
|
|
628
658
|
const { backupFile } = await Promise.resolve().then(() => __importStar(require('../core/FileSystemUtils')));
|
|
629
|
-
await backupFile(dest);
|
|
659
|
+
await backupFile(dest, projectRoot);
|
|
630
660
|
}
|
|
631
661
|
if (isCodexToml) {
|
|
632
|
-
await FileSystemUtils.writeGeneratedFile(dest, (0, toml_1.stringify)(toWrite));
|
|
662
|
+
await FileSystemUtils.writeGeneratedFile(dest, (0, toml_1.stringify)(toWrite), projectRoot);
|
|
633
663
|
}
|
|
634
664
|
else {
|
|
635
|
-
await (0, mcp_1.writeNativeMcp)(dest, toWrite);
|
|
665
|
+
await (0, mcp_1.writeNativeMcp)(dest, toWrite, projectRoot);
|
|
636
666
|
}
|
|
637
667
|
}
|
|
638
668
|
else {
|
|
@@ -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,37 @@
|
|
|
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 restored backup files should be preserved
|
|
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>;
|
|
37
|
+
export declare function cleanUpAgentDirectories(agent: IAgent, projectRoot: string, agentConfig: IAgentConfig | undefined, verbose: boolean, dryRun: boolean): Promise<number>;
|