@intellectronica/ruler 0.3.20 → 0.3.21
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/GeminiCliAgent.js +20 -2
- package/dist/cli/handlers.js +10 -0
- package/dist/core/apply-engine.js +25 -1
- package/package.json +1 -1
|
@@ -69,17 +69,35 @@ class GeminiCliAgent extends AgentsMdAgent_1.AgentsMdAgent {
|
|
|
69
69
|
const mcpEnabled = agentConfig?.mcp?.enabled ?? true;
|
|
70
70
|
if (mcpEnabled && rulerMcpJson) {
|
|
71
71
|
const strategy = agentConfig?.mcp?.strategy ?? 'merge';
|
|
72
|
+
// Gemini CLI (since v0.21.0) no longer accepts the "type" field in MCP server entries.
|
|
73
|
+
// Following the MCP spec update from Nov 25, 2025, the transport type is now inferred
|
|
74
|
+
// from the presence of specific keys (command/args -> stdio, url -> sse/http).
|
|
75
|
+
// Strip 'type' field from all incoming servers before merging.
|
|
76
|
+
const stripTypeField = (servers) => {
|
|
77
|
+
const cleaned = {};
|
|
78
|
+
for (const [name, def] of Object.entries(servers)) {
|
|
79
|
+
if (def && typeof def === 'object') {
|
|
80
|
+
const copy = { ...def };
|
|
81
|
+
delete copy.type;
|
|
82
|
+
cleaned[name] = copy;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
cleaned[name] = def;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return cleaned;
|
|
89
|
+
};
|
|
72
90
|
if (strategy === 'overwrite') {
|
|
73
91
|
// For overwrite, preserve existing settings except MCP servers
|
|
74
92
|
const incomingServers = rulerMcpJson.mcpServers || {};
|
|
75
|
-
updated[this.getMcpServerKey()] = incomingServers;
|
|
93
|
+
updated[this.getMcpServerKey()] = stripTypeField(incomingServers);
|
|
76
94
|
}
|
|
77
95
|
else {
|
|
78
96
|
// For merge strategy, merge with existing MCP servers
|
|
79
97
|
const baseServers = existingSettings[this.getMcpServerKey()] || {};
|
|
80
98
|
const incomingServers = rulerMcpJson.mcpServers || {};
|
|
81
99
|
const mergedServers = { ...baseServers, ...incomingServers };
|
|
82
|
-
updated[this.getMcpServerKey()] = mergedServers;
|
|
100
|
+
updated[this.getMcpServerKey()] = stripTypeField(mergedServers);
|
|
83
101
|
}
|
|
84
102
|
}
|
|
85
103
|
await fs_1.promises.mkdir(path.dirname(settingsPath), { recursive: true });
|
package/dist/cli/handlers.js
CHANGED
|
@@ -43,11 +43,20 @@ const os = __importStar(require("os"));
|
|
|
43
43
|
const fs = __importStar(require("fs/promises"));
|
|
44
44
|
const constants_1 = require("../constants");
|
|
45
45
|
const ConfigLoader_1 = require("../core/ConfigLoader");
|
|
46
|
+
function assertNotInsideRulerDir(projectRoot) {
|
|
47
|
+
const normalized = path.resolve(projectRoot);
|
|
48
|
+
const segments = normalized.split(path.sep);
|
|
49
|
+
if (segments.includes('.ruler')) {
|
|
50
|
+
console.error(`${constants_1.ERROR_PREFIX} Cannot run from inside a .ruler directory. Please run from your project root.`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
46
54
|
/**
|
|
47
55
|
* Handler for the 'apply' command.
|
|
48
56
|
*/
|
|
49
57
|
async function applyHandler(argv) {
|
|
50
58
|
const projectRoot = argv['project-root'];
|
|
59
|
+
assertNotInsideRulerDir(projectRoot);
|
|
51
60
|
const agents = argv.agents
|
|
52
61
|
? argv.agents.split(',').map((a) => a.trim())
|
|
53
62
|
: undefined;
|
|
@@ -192,6 +201,7 @@ async function initHandler(argv) {
|
|
|
192
201
|
*/
|
|
193
202
|
async function revertHandler(argv) {
|
|
194
203
|
const projectRoot = argv['project-root'];
|
|
204
|
+
assertNotInsideRulerDir(projectRoot);
|
|
195
205
|
const agents = argv.agents
|
|
196
206
|
? argv.agents.split(',').map((a) => a.trim())
|
|
197
207
|
: undefined;
|
|
@@ -577,7 +577,31 @@ async function applyStandardMcpConfiguration(agent, filteredMcpJson, dest, agent
|
|
|
577
577
|
out[serverKey] = cleanedServers;
|
|
578
578
|
return out;
|
|
579
579
|
};
|
|
580
|
-
|
|
580
|
+
// Gemini CLI (since v0.21.0) no longer accepts the "type" field in MCP server entries.
|
|
581
|
+
// Following the MCP spec update from Nov 25, 2025, the transport type is now inferred
|
|
582
|
+
// from the presence of specific keys (command/args -> stdio, url -> sse/http).
|
|
583
|
+
// Sanitize merged config by stripping 'type' from each server when targeting Gemini.
|
|
584
|
+
const sanitizeForGemini = (obj) => {
|
|
585
|
+
if (agent.getIdentifier() !== 'gemini-cli')
|
|
586
|
+
return obj;
|
|
587
|
+
const out = { ...obj };
|
|
588
|
+
const servers = out[serverKey] || {};
|
|
589
|
+
const cleanedServers = {};
|
|
590
|
+
for (const [name, def] of Object.entries(servers)) {
|
|
591
|
+
if (def && typeof def === 'object') {
|
|
592
|
+
const copy = { ...def };
|
|
593
|
+
delete copy.type;
|
|
594
|
+
cleanedServers[name] = copy;
|
|
595
|
+
}
|
|
596
|
+
else {
|
|
597
|
+
cleanedServers[name] = def;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
out[serverKey] = cleanedServers;
|
|
601
|
+
return out;
|
|
602
|
+
};
|
|
603
|
+
let toWrite = sanitizeForFirebase(merged);
|
|
604
|
+
toWrite = sanitizeForGemini(toWrite);
|
|
581
605
|
// Only backup and write if content would actually change (idempotent)
|
|
582
606
|
const currentContent = JSON.stringify(existing, null, 2);
|
|
583
607
|
const newContent = JSON.stringify(toWrite, null, 2);
|