@intellectronica/ruler 0.3.23 → 0.3.24
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.
|
@@ -79,6 +79,13 @@ class AbstractAgent {
|
|
|
79
79
|
supportsMcpRemote() {
|
|
80
80
|
return false;
|
|
81
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Returns whether this agent supports MCP server timeout configuration.
|
|
84
|
+
* Defaults to false if not overridden.
|
|
85
|
+
*/
|
|
86
|
+
supportsMcpTimeout() {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
82
89
|
/**
|
|
83
90
|
* Returns whether this agent has native skills support.
|
|
84
91
|
* Defaults to false if not overridden.
|
|
@@ -182,6 +182,9 @@ async function loadUnifiedConfig(options) {
|
|
|
182
182
|
if (serverDef.headers && typeof serverDef.headers === 'object') {
|
|
183
183
|
server.headers = Object.fromEntries(Object.entries(serverDef.headers).filter(([, v]) => typeof v === 'string'));
|
|
184
184
|
}
|
|
185
|
+
if (typeof serverDef.timeout === 'number') {
|
|
186
|
+
server.timeout = serverDef.timeout;
|
|
187
|
+
}
|
|
185
188
|
// Validate server configuration
|
|
186
189
|
const hasCommand = !!server.command;
|
|
187
190
|
const hasUrl = !!server.url;
|
|
@@ -301,6 +304,9 @@ async function loadUnifiedConfig(options) {
|
|
|
301
304
|
if (def.headers && typeof def.headers === 'object') {
|
|
302
305
|
server.headers = Object.fromEntries(Object.entries(def.headers).filter(([, v]) => typeof v === 'string'));
|
|
303
306
|
}
|
|
307
|
+
if (typeof def.timeout === 'number') {
|
|
308
|
+
server.timeout = def.timeout;
|
|
309
|
+
}
|
|
304
310
|
// Derive type
|
|
305
311
|
if (server.url)
|
|
306
312
|
server.type = 'remote';
|
|
@@ -427,17 +427,49 @@ async function updateGitignoreForMcpFile(dest, projectRoot, generatedPaths, back
|
|
|
427
427
|
}
|
|
428
428
|
}
|
|
429
429
|
}
|
|
430
|
+
function sanitizeMcpTimeoutsForAgent(agent, mcpJson, dryRun) {
|
|
431
|
+
if (agent.supportsMcpTimeout?.()) {
|
|
432
|
+
return mcpJson;
|
|
433
|
+
}
|
|
434
|
+
if (!mcpJson.mcpServers || typeof mcpJson.mcpServers !== 'object') {
|
|
435
|
+
return mcpJson;
|
|
436
|
+
}
|
|
437
|
+
const servers = mcpJson.mcpServers;
|
|
438
|
+
const sanitizedServers = {};
|
|
439
|
+
const strippedTimeouts = [];
|
|
440
|
+
for (const [name, serverDef] of Object.entries(servers)) {
|
|
441
|
+
if (serverDef && typeof serverDef === 'object') {
|
|
442
|
+
const copy = { ...serverDef };
|
|
443
|
+
if ('timeout' in copy) {
|
|
444
|
+
delete copy.timeout;
|
|
445
|
+
strippedTimeouts.push(name);
|
|
446
|
+
}
|
|
447
|
+
sanitizedServers[name] = copy;
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
sanitizedServers[name] = serverDef;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (strippedTimeouts.length > 0) {
|
|
454
|
+
(0, constants_1.logWarn)(`${agent.getName()} does not support MCP server timeout configuration; ignoring timeout for: ${strippedTimeouts.join(', ')}`, dryRun);
|
|
455
|
+
}
|
|
456
|
+
return {
|
|
457
|
+
...mcpJson,
|
|
458
|
+
mcpServers: sanitizedServers,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
430
461
|
async function applyMcpConfiguration(agent, filteredMcpJson, dest, agentConfig, config, projectRoot, cliMcpStrategy, dryRun, verbose, backup = true) {
|
|
431
462
|
// Prevent writing MCP configs outside the project root (e.g., legacy home-directory targets)
|
|
432
463
|
if (!dest.startsWith(projectRoot)) {
|
|
433
464
|
(0, constants_1.logVerbose)(`Skipping MCP config for ${agent.getName()} because target path is outside project: ${dest}`, verbose);
|
|
434
465
|
return;
|
|
435
466
|
}
|
|
467
|
+
const agentMcpJson = sanitizeMcpTimeoutsForAgent(agent, filteredMcpJson, dryRun);
|
|
436
468
|
if (agent.getIdentifier() === 'openhands') {
|
|
437
|
-
return await applyOpenHandsMcpConfiguration(
|
|
469
|
+
return await applyOpenHandsMcpConfiguration(agentMcpJson, dest, dryRun, verbose, backup);
|
|
438
470
|
}
|
|
439
471
|
if (agent.getIdentifier() === 'opencode') {
|
|
440
|
-
return await applyOpenCodeMcpConfiguration(
|
|
472
|
+
return await applyOpenCodeMcpConfiguration(agentMcpJson, dest, dryRun, verbose, backup);
|
|
441
473
|
}
|
|
442
474
|
// Agents that handle MCP configuration internally should not have external MCP handling
|
|
443
475
|
if (agent.getIdentifier() === 'zed' ||
|
|
@@ -447,7 +479,7 @@ async function applyMcpConfiguration(agent, filteredMcpJson, dest, agentConfig,
|
|
|
447
479
|
(0, constants_1.logVerbose)(`Skipping external MCP config for ${agent.getName()} - handled internally by agent`, verbose);
|
|
448
480
|
return;
|
|
449
481
|
}
|
|
450
|
-
return await applyStandardMcpConfiguration(agent,
|
|
482
|
+
return await applyStandardMcpConfiguration(agent, agentMcpJson, dest, agentConfig, config, cliMcpStrategy, dryRun, verbose, backup);
|
|
451
483
|
}
|
|
452
484
|
async function applyOpenHandsMcpConfiguration(filteredMcpJson, dest, dryRun, verbose, backup = true) {
|
|
453
485
|
if (dryRun) {
|
|
@@ -63,6 +63,9 @@ function transformToOpenCodeFormat(rulerMcp) {
|
|
|
63
63
|
if (serverDef.headers) {
|
|
64
64
|
openCodeServer.headers = serverDef.headers;
|
|
65
65
|
}
|
|
66
|
+
if (typeof serverDef.timeout === 'number') {
|
|
67
|
+
openCodeServer.timeout = serverDef.timeout;
|
|
68
|
+
}
|
|
66
69
|
}
|
|
67
70
|
else if (isLocalServer(serverDef)) {
|
|
68
71
|
openCodeServer.type = 'local';
|
|
@@ -74,6 +77,9 @@ function transformToOpenCodeFormat(rulerMcp) {
|
|
|
74
77
|
if (serverDef.env) {
|
|
75
78
|
openCodeServer.environment = serverDef.env;
|
|
76
79
|
}
|
|
80
|
+
if (typeof serverDef.timeout === 'number') {
|
|
81
|
+
openCodeServer.timeout = serverDef.timeout;
|
|
82
|
+
}
|
|
77
83
|
}
|
|
78
84
|
else {
|
|
79
85
|
continue;
|