@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
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.CrushAgent = void 0;
|
|
37
37
|
const fs = __importStar(require("fs/promises"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
|
+
const FileSystemUtils_1 = require("../core/FileSystemUtils");
|
|
39
40
|
class CrushAgent {
|
|
40
41
|
getIdentifier() {
|
|
41
42
|
return 'crush';
|
|
@@ -80,13 +81,20 @@ class CrushAgent {
|
|
|
80
81
|
}
|
|
81
82
|
return transformedServers;
|
|
82
83
|
}
|
|
83
|
-
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, agentConfig) {
|
|
84
|
+
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, agentConfig, backup = true) {
|
|
84
85
|
const outputPaths = this.getDefaultOutputPath(projectRoot);
|
|
85
|
-
const instructionsPath = agentConfig?.
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
const instructionsPath = path.resolve(projectRoot, agentConfig?.outputPath ??
|
|
87
|
+
agentConfig?.outputPathInstructions ??
|
|
88
|
+
outputPaths['instructions']);
|
|
89
|
+
const mcpPath = path.resolve(projectRoot, agentConfig?.outputPathConfig ?? outputPaths['mcp']);
|
|
90
|
+
await fs.mkdir(path.dirname(instructionsPath), { recursive: true });
|
|
91
|
+
if (backup) {
|
|
92
|
+
await (0, FileSystemUtils_1.backupFile)(instructionsPath, projectRoot);
|
|
93
|
+
}
|
|
94
|
+
await (0, FileSystemUtils_1.writeGeneratedFile)(instructionsPath, concatenatedRules, projectRoot);
|
|
88
95
|
// Always transform from mcpServers ({ mcpServers: ... }) to { mcp: ... } for Crush
|
|
89
96
|
let finalMcpConfig = { mcp: {} };
|
|
97
|
+
const strategy = agentConfig?.mcp?.strategy ?? 'merge';
|
|
90
98
|
try {
|
|
91
99
|
const existingMcpConfig = JSON.parse(await fs.readFile(mcpPath, 'utf-8'));
|
|
92
100
|
if (existingMcpConfig && typeof existingMcpConfig === 'object') {
|
|
@@ -94,7 +102,7 @@ class CrushAgent {
|
|
|
94
102
|
finalMcpConfig = {
|
|
95
103
|
...existingMcpConfig,
|
|
96
104
|
mcp: {
|
|
97
|
-
...(existingMcpConfig.mcp || {}),
|
|
105
|
+
...(strategy === 'merge' ? existingMcpConfig.mcp || {} : {}),
|
|
98
106
|
...transformedServers,
|
|
99
107
|
},
|
|
100
108
|
};
|
|
@@ -115,7 +123,11 @@ class CrushAgent {
|
|
|
115
123
|
}
|
|
116
124
|
}
|
|
117
125
|
if (Object.keys(finalMcpConfig.mcp).length > 0) {
|
|
118
|
-
await fs.
|
|
126
|
+
await fs.mkdir(path.dirname(mcpPath), { recursive: true });
|
|
127
|
+
if (backup) {
|
|
128
|
+
await (0, FileSystemUtils_1.backupFile)(mcpPath, projectRoot);
|
|
129
|
+
}
|
|
130
|
+
await (0, FileSystemUtils_1.writeGeneratedFile)(mcpPath, JSON.stringify(finalMcpConfig, null, 2), projectRoot);
|
|
119
131
|
}
|
|
120
132
|
}
|
|
121
133
|
supportsMcpStdio() {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { IAgentConfig } from './IAgent';
|
|
2
|
+
import { AgentsMdAgent } from './AgentsMdAgent';
|
|
3
|
+
/**
|
|
4
|
+
* Cursor agent adapter.
|
|
5
|
+
* Leverages the standardized AGENTS.md approach supported natively by Cursor.
|
|
6
|
+
* See: https://docs.cursor.com/en/cli/using
|
|
7
|
+
*/
|
|
8
|
+
export declare class CursorAgent extends AgentsMdAgent {
|
|
9
|
+
getIdentifier(): string;
|
|
10
|
+
getName(): string;
|
|
11
|
+
applyRulerConfig(concatenatedRules: string, projectRoot: string, _rulerMcpJson: Record<string, unknown> | null, agentConfig?: IAgentConfig, backup?: boolean): Promise<void>;
|
|
12
|
+
getMcpServerKey(): string;
|
|
13
|
+
supportsMcpStdio(): boolean;
|
|
14
|
+
supportsMcpRemote(): boolean;
|
|
15
|
+
supportsNativeSkills(): boolean;
|
|
16
|
+
supportsNativeSubagents(): boolean;
|
|
17
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AgentsMdAgent } from './AgentsMdAgent';
|
|
2
|
+
/**
|
|
3
|
+
* Factory Droid agent adapter.
|
|
4
|
+
* Uses the root-level AGENTS.md for instructions.
|
|
5
|
+
*/
|
|
6
|
+
export declare class FactoryDroidAgent extends AgentsMdAgent {
|
|
7
|
+
getIdentifier(): string;
|
|
8
|
+
getName(): string;
|
|
9
|
+
getMcpServerKey(): string;
|
|
10
|
+
supportsMcpStdio(): boolean;
|
|
11
|
+
supportsMcpRemote(): boolean;
|
|
12
|
+
supportsNativeSkills(): boolean;
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AbstractAgent } from './AbstractAgent';
|
|
2
|
+
/**
|
|
3
|
+
* Firebase Studio agent adapter.
|
|
4
|
+
*/
|
|
5
|
+
export declare class FirebaseAgent extends AbstractAgent {
|
|
6
|
+
getIdentifier(): string;
|
|
7
|
+
getName(): string;
|
|
8
|
+
getDefaultOutputPath(projectRoot: string): string;
|
|
9
|
+
supportsMcpStdio(): boolean;
|
|
10
|
+
supportsMcpRemote(): boolean;
|
|
11
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { IAgent, IAgentConfig } from './IAgent';
|
|
2
|
+
/**
|
|
3
|
+
* Firebender agent adapter.
|
|
4
|
+
*/
|
|
5
|
+
export declare class FirebenderAgent implements IAgent {
|
|
6
|
+
/**
|
|
7
|
+
* Type guard function to safely check if an object is a FirebenderRule.
|
|
8
|
+
*/
|
|
9
|
+
private isFirebenderRule;
|
|
10
|
+
getIdentifier(): string;
|
|
11
|
+
getName(): string;
|
|
12
|
+
applyRulerConfig(concatenatedRules: string, projectRoot: string, rulerMcpJson: Record<string, unknown> | null, agentConfig?: IAgentConfig, backup?: boolean): Promise<void>;
|
|
13
|
+
private resolveOutputPath;
|
|
14
|
+
private loadExistingConfig;
|
|
15
|
+
private createRulesFromConcatenatedRules;
|
|
16
|
+
private createRuleObjectsFromFilePaths;
|
|
17
|
+
private createRulesFromPlainText;
|
|
18
|
+
private removeDuplicateRules;
|
|
19
|
+
private saveConfig;
|
|
20
|
+
/**
|
|
21
|
+
* Handle MCP server configuration for Firebender.
|
|
22
|
+
* Merges or overwrites MCP servers in the firebender.json configuration based on strategy.
|
|
23
|
+
*/
|
|
24
|
+
private handleMcpConfiguration;
|
|
25
|
+
getDefaultOutputPath(projectRoot: string): Record<string, string>;
|
|
26
|
+
getMcpServerKey(): string;
|
|
27
|
+
supportsMcpStdio(): boolean;
|
|
28
|
+
supportsMcpRemote(): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Extracts file paths from concatenated rules by parsing HTML source comments.
|
|
31
|
+
* @param concatenatedRules The concatenated rules string with HTML comments
|
|
32
|
+
* @param projectRoot The project root directory
|
|
33
|
+
* @returns Array of file paths relative to project root
|
|
34
|
+
*/
|
|
35
|
+
private extractFilePathsFromRules;
|
|
36
|
+
}
|
|
@@ -60,6 +60,7 @@ class FirebenderAgent {
|
|
|
60
60
|
}
|
|
61
61
|
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, agentConfig, backup = true) {
|
|
62
62
|
const rulesPath = this.resolveOutputPath(projectRoot, agentConfig);
|
|
63
|
+
await (0, FileSystemUtils_1.assertManagedPathInsideRoot)(rulesPath, projectRoot, 'Refusing to write generated file outside project');
|
|
63
64
|
await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(rulesPath));
|
|
64
65
|
const firebenderConfig = await this.loadExistingConfig(rulesPath);
|
|
65
66
|
const newRules = this.createRulesFromConcatenatedRules(concatenatedRules, projectRoot);
|
|
@@ -69,7 +70,7 @@ class FirebenderAgent {
|
|
|
69
70
|
if (mcpEnabled && rulerMcpJson) {
|
|
70
71
|
await this.handleMcpConfiguration(firebenderConfig, rulerMcpJson, agentConfig);
|
|
71
72
|
}
|
|
72
|
-
await this.saveConfig(rulesPath, firebenderConfig, backup);
|
|
73
|
+
await this.saveConfig(rulesPath, firebenderConfig, backup, projectRoot);
|
|
73
74
|
}
|
|
74
75
|
resolveOutputPath(projectRoot, agentConfig) {
|
|
75
76
|
const outputPaths = this.getDefaultOutputPath(projectRoot);
|
|
@@ -135,12 +136,12 @@ class FirebenderAgent {
|
|
|
135
136
|
return true;
|
|
136
137
|
});
|
|
137
138
|
}
|
|
138
|
-
async saveConfig(rulesPath, config, backup) {
|
|
139
|
+
async saveConfig(rulesPath, config, backup, projectRoot) {
|
|
139
140
|
const updatedContent = JSON.stringify(config, null, 2);
|
|
140
141
|
if (backup) {
|
|
141
|
-
await (0, FileSystemUtils_1.backupFile)(rulesPath);
|
|
142
|
+
await (0, FileSystemUtils_1.backupFile)(rulesPath, projectRoot);
|
|
142
143
|
}
|
|
143
|
-
await (0, FileSystemUtils_1.writeGeneratedFile)(rulesPath, updatedContent);
|
|
144
|
+
await (0, FileSystemUtils_1.writeGeneratedFile)(rulesPath, updatedContent, projectRoot);
|
|
144
145
|
}
|
|
145
146
|
/**
|
|
146
147
|
* Handle MCP server configuration for Firebender.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { IAgentConfig } from './IAgent';
|
|
2
|
+
import { AgentsMdAgent } from './AgentsMdAgent';
|
|
3
|
+
export declare class GeminiCliAgent extends AgentsMdAgent {
|
|
4
|
+
getIdentifier(): string;
|
|
5
|
+
getName(): string;
|
|
6
|
+
private getContextFileName;
|
|
7
|
+
applyRulerConfig(concatenatedRules: string, projectRoot: string, rulerMcpJson: Record<string, unknown> | null, agentConfig?: IAgentConfig, backup?: boolean): Promise<void>;
|
|
8
|
+
getMcpServerKey(): string;
|
|
9
|
+
supportsMcpStdio(): boolean;
|
|
10
|
+
supportsMcpRemote(): boolean;
|
|
11
|
+
supportsNativeSkills(): boolean;
|
|
12
|
+
}
|
|
@@ -37,6 +37,7 @@ exports.GeminiCliAgent = void 0;
|
|
|
37
37
|
const path = __importStar(require("path"));
|
|
38
38
|
const fs_1 = require("fs");
|
|
39
39
|
const AgentsMdAgent_1 = require("./AgentsMdAgent");
|
|
40
|
+
const FileSystemUtils_1 = require("../core/FileSystemUtils");
|
|
40
41
|
class GeminiCliAgent extends AgentsMdAgent_1.AgentsMdAgent {
|
|
41
42
|
getIdentifier() {
|
|
42
43
|
return 'gemini-cli';
|
|
@@ -44,13 +45,19 @@ class GeminiCliAgent extends AgentsMdAgent_1.AgentsMdAgent {
|
|
|
44
45
|
getName() {
|
|
45
46
|
return 'Gemini CLI';
|
|
46
47
|
}
|
|
47
|
-
|
|
48
|
+
getContextFileName(projectRoot, agentConfig) {
|
|
49
|
+
const outputPath = agentConfig?.outputPath ?? 'AGENTS.md';
|
|
50
|
+
return path
|
|
51
|
+
.relative(projectRoot, path.resolve(projectRoot, outputPath))
|
|
52
|
+
.replace(/\\/g, '/');
|
|
53
|
+
}
|
|
54
|
+
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, agentConfig, backup = true) {
|
|
48
55
|
// First, perform idempotent write of AGENTS.md via base class
|
|
49
56
|
await super.applyRulerConfig(concatenatedRules, projectRoot, null, {
|
|
50
57
|
outputPath: agentConfig?.outputPath,
|
|
51
|
-
});
|
|
52
|
-
// Prepare
|
|
53
|
-
const settingsPath = path.
|
|
58
|
+
}, backup);
|
|
59
|
+
// Prepare settings with contextFileName and MCP configuration
|
|
60
|
+
const settingsPath = path.resolve(projectRoot, agentConfig?.outputPathConfig ?? path.join('.gemini', 'settings.json'));
|
|
54
61
|
let existingSettings = {};
|
|
55
62
|
try {
|
|
56
63
|
const raw = await fs_1.promises.readFile(settingsPath, 'utf8');
|
|
@@ -63,7 +70,7 @@ class GeminiCliAgent extends AgentsMdAgent_1.AgentsMdAgent {
|
|
|
63
70
|
}
|
|
64
71
|
const updated = {
|
|
65
72
|
...existingSettings,
|
|
66
|
-
contextFileName:
|
|
73
|
+
contextFileName: this.getContextFileName(projectRoot, agentConfig),
|
|
67
74
|
};
|
|
68
75
|
// Handle MCP server configuration if provided
|
|
69
76
|
const mcpEnabled = agentConfig?.mcp?.enabled ?? true;
|
|
@@ -100,8 +107,7 @@ class GeminiCliAgent extends AgentsMdAgent_1.AgentsMdAgent {
|
|
|
100
107
|
updated[this.getMcpServerKey()] = stripTypeField(mergedServers);
|
|
101
108
|
}
|
|
102
109
|
}
|
|
103
|
-
await
|
|
104
|
-
await fs_1.promises.writeFile(settingsPath, JSON.stringify(updated, null, 2));
|
|
110
|
+
await (0, FileSystemUtils_1.writeGeneratedFile)(settingsPath, JSON.stringify(updated, null, 2), projectRoot);
|
|
105
111
|
}
|
|
106
112
|
// Ensure MCP merging uses the correct key for Gemini (.gemini/settings.json)
|
|
107
113
|
getMcpServerKey() {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AbstractAgent } from './AbstractAgent';
|
|
2
|
+
/**
|
|
3
|
+
* Goose agent adapter for Block's Goose AI assistant.
|
|
4
|
+
* Propagates rules to .goosehints file.
|
|
5
|
+
*/
|
|
6
|
+
export declare class GooseAgent extends AbstractAgent {
|
|
7
|
+
getIdentifier(): string;
|
|
8
|
+
getName(): string;
|
|
9
|
+
getDefaultOutputPath(projectRoot: string): string;
|
|
10
|
+
getMcpServerKey(): string;
|
|
11
|
+
supportsNativeSkills(): boolean;
|
|
12
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface defining an AI agent configuration adapter.
|
|
3
|
+
*/
|
|
4
|
+
import { McpConfig } from '../types';
|
|
5
|
+
/**
|
|
6
|
+
* Configuration overrides for a specific agent.
|
|
7
|
+
*/
|
|
8
|
+
export interface IAgentConfig {
|
|
9
|
+
/** Explicit enable/disable agent */
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
/** Override for primary output path */
|
|
12
|
+
outputPath?: string;
|
|
13
|
+
/** Override for Aider instruction file path */
|
|
14
|
+
outputPathInstructions?: string;
|
|
15
|
+
/** Override for Aider config file path */
|
|
16
|
+
outputPathConfig?: string;
|
|
17
|
+
/** MCP propagation config for this agent. */
|
|
18
|
+
mcp?: McpConfig;
|
|
19
|
+
/** Agent-scoped MCP server definitions. */
|
|
20
|
+
mcpServers?: Record<string, Record<string, unknown>>;
|
|
21
|
+
}
|
|
22
|
+
export interface IAgent {
|
|
23
|
+
/**
|
|
24
|
+
* Returns the lowercase identifier of the agent (e.g., "copilot", "claude", "aider").
|
|
25
|
+
*/
|
|
26
|
+
getIdentifier(): string;
|
|
27
|
+
/**
|
|
28
|
+
* Returns the display name of the agent.
|
|
29
|
+
*/
|
|
30
|
+
getName(): string;
|
|
31
|
+
/**
|
|
32
|
+
* Applies the concatenated ruler rules to the agent's configuration.
|
|
33
|
+
* @param concatenatedRules The combined rules text
|
|
34
|
+
* @param projectRoot The root directory of the project
|
|
35
|
+
*/
|
|
36
|
+
applyRulerConfig(concatenatedRules: string, projectRoot: string, rulerMcpJson: Record<string, unknown> | null, agentConfig?: IAgentConfig, backup?: boolean): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Returns the default output path(s) for this agent given the project root.
|
|
39
|
+
*/
|
|
40
|
+
getDefaultOutputPath(projectRoot: string): string | Record<string, string>;
|
|
41
|
+
/**
|
|
42
|
+
* Returns the specific key to be used for the server object in MCP JSON.
|
|
43
|
+
* Defaults to 'mcpServers' if not implemented.
|
|
44
|
+
*/
|
|
45
|
+
getMcpServerKey?(): string;
|
|
46
|
+
/**
|
|
47
|
+
* Returns whether this agent supports MCP STDIO servers.
|
|
48
|
+
* Defaults to false if not implemented.
|
|
49
|
+
*/
|
|
50
|
+
supportsMcpStdio?(): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Returns whether this agent supports MCP remote servers.
|
|
53
|
+
* Defaults to false if not implemented.
|
|
54
|
+
*/
|
|
55
|
+
supportsMcpRemote?(): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Returns whether this agent supports MCP server timeout configuration.
|
|
58
|
+
* Defaults to false if not implemented.
|
|
59
|
+
*/
|
|
60
|
+
supportsMcpTimeout?(): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Returns whether this agent has native skills support (like Claude Code).
|
|
63
|
+
* When true, skills are copied directly to the agent's skills directory.
|
|
64
|
+
* Defaults to false if not implemented.
|
|
65
|
+
*/
|
|
66
|
+
supportsNativeSkills?(): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Returns whether this agent has native subagent support (like Claude Code,
|
|
69
|
+
* Cursor, Codex CLI, GitHub Copilot). When true, subagent definitions from
|
|
70
|
+
* `.ruler/agents/` are propagated to the agent's native subagent location.
|
|
71
|
+
* Defaults to false if not implemented.
|
|
72
|
+
*/
|
|
73
|
+
supportsNativeSubagents?(): boolean;
|
|
74
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AbstractAgent } from './AbstractAgent';
|
|
2
|
+
/**
|
|
3
|
+
* JetBrains AI Assistant agent adapter.
|
|
4
|
+
* Writes rules to .aiassistant/rules/AGENTS.md.
|
|
5
|
+
*/
|
|
6
|
+
export declare class JetBrainsAiAssistantAgent extends AbstractAgent {
|
|
7
|
+
getIdentifier(): string;
|
|
8
|
+
getName(): string;
|
|
9
|
+
getDefaultOutputPath(projectRoot: string): string;
|
|
10
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AbstractAgent } from './AbstractAgent';
|
|
2
|
+
/**
|
|
3
|
+
* JetBrains Junie agent adapter.
|
|
4
|
+
*/
|
|
5
|
+
export declare class JunieAgent extends AbstractAgent {
|
|
6
|
+
getIdentifier(): string;
|
|
7
|
+
getName(): string;
|
|
8
|
+
getDefaultOutputPath(projectRoot: string): string;
|
|
9
|
+
supportsMcpStdio(): boolean;
|
|
10
|
+
supportsMcpRemote(): boolean;
|
|
11
|
+
supportsNativeSkills(): boolean;
|
|
12
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AgentsMdAgent } from './AgentsMdAgent';
|
|
2
|
+
/**
|
|
3
|
+
* Kilo Code agent adapter.
|
|
4
|
+
* Uses AGENTS.md for instructions and .kilocode/mcp.json for MCP configuration.
|
|
5
|
+
*/
|
|
6
|
+
export declare class KiloCodeAgent extends AgentsMdAgent {
|
|
7
|
+
getIdentifier(): string;
|
|
8
|
+
getName(): string;
|
|
9
|
+
getDefaultOutputPath(projectRoot: string): string;
|
|
10
|
+
getMcpServerKey(): string;
|
|
11
|
+
supportsMcpStdio(): boolean;
|
|
12
|
+
supportsMcpRemote(): boolean;
|
|
13
|
+
supportsNativeSkills(): boolean;
|
|
14
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AbstractAgent } from './AbstractAgent';
|
|
2
|
+
export declare class KiroAgent extends AbstractAgent {
|
|
3
|
+
getIdentifier(): string;
|
|
4
|
+
getName(): string;
|
|
5
|
+
getDefaultOutputPath(projectRoot: string): string;
|
|
6
|
+
supportsMcpStdio(): boolean;
|
|
7
|
+
supportsMcpRemote(): boolean;
|
|
8
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { IAgent, IAgentConfig } from './IAgent';
|
|
2
|
+
interface RulerMcpServer {
|
|
3
|
+
command?: string;
|
|
4
|
+
args?: string[];
|
|
5
|
+
url?: string;
|
|
6
|
+
headers?: Record<string, string>;
|
|
7
|
+
env?: Record<string, string>;
|
|
8
|
+
timeout?: number;
|
|
9
|
+
}
|
|
10
|
+
interface RulerMcp {
|
|
11
|
+
mcpServers?: Record<string, RulerMcpServer>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Mistral Vibe CLI agent adapter.
|
|
15
|
+
* Propagates rules to AGENTS.md and MCP servers to .vibe/config.toml.
|
|
16
|
+
*/
|
|
17
|
+
export declare class MistralVibeAgent implements IAgent {
|
|
18
|
+
private agentsMdAgent;
|
|
19
|
+
getIdentifier(): string;
|
|
20
|
+
getName(): string;
|
|
21
|
+
applyRulerConfig(concatenatedRules: string, projectRoot: string, rulerMcpJson: RulerMcp | null, agentConfig?: IAgentConfig, backup?: boolean): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Determines the transport type based on server configuration.
|
|
24
|
+
*/
|
|
25
|
+
private determineTransport;
|
|
26
|
+
getDefaultOutputPath(projectRoot: string): Record<string, string>;
|
|
27
|
+
supportsMcpStdio(): boolean;
|
|
28
|
+
supportsMcpRemote(): boolean;
|
|
29
|
+
supportsNativeSkills(): boolean;
|
|
30
|
+
}
|
|
31
|
+
export {};
|
|
@@ -109,12 +109,20 @@ class MistralVibeAgent {
|
|
|
109
109
|
}
|
|
110
110
|
// Read existing TOML config if it exists
|
|
111
111
|
let existingConfig = {};
|
|
112
|
+
let configExists = false;
|
|
112
113
|
try {
|
|
113
114
|
const existingContent = await fs_1.promises.readFile(configPath, 'utf8');
|
|
115
|
+
configExists = true;
|
|
114
116
|
existingConfig = (0, toml_1.parse)(existingContent);
|
|
115
117
|
}
|
|
116
|
-
catch {
|
|
117
|
-
|
|
118
|
+
catch (error) {
|
|
119
|
+
if (error.code === 'ENOENT') {
|
|
120
|
+
// Missing config starts from an empty config.
|
|
121
|
+
existingConfig = {};
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
throw new Error(`Invalid Mistral config at ${configPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
125
|
+
}
|
|
118
126
|
}
|
|
119
127
|
// Create the updated config
|
|
120
128
|
const updatedConfig = { ...existingConfig };
|
|
@@ -134,7 +142,10 @@ class MistralVibeAgent {
|
|
|
134
142
|
// Convert to TOML and write
|
|
135
143
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
136
144
|
const tomlContent = (0, toml_1.stringify)(updatedConfig);
|
|
137
|
-
|
|
145
|
+
if (configExists && backup) {
|
|
146
|
+
await (0, FileSystemUtils_1.backupFile)(configPath, projectRoot);
|
|
147
|
+
}
|
|
148
|
+
await (0, FileSystemUtils_1.writeGeneratedFile)(configPath, tomlContent, projectRoot);
|
|
138
149
|
}
|
|
139
150
|
}
|
|
140
151
|
/**
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IAgent, IAgentConfig } from './IAgent';
|
|
2
|
+
export declare class OpenCodeAgent implements IAgent {
|
|
3
|
+
getIdentifier(): string;
|
|
4
|
+
getName(): string;
|
|
5
|
+
getDefaultOutputPath(projectRoot: string): Record<string, string>;
|
|
6
|
+
applyRulerConfig(concatenatedRules: string, projectRoot: string, rulerMcpJson: Record<string, unknown> | null, agentConfig?: IAgentConfig, backup?: boolean): Promise<void>;
|
|
7
|
+
supportsMcpStdio(): boolean;
|
|
8
|
+
supportsMcpRemote(): boolean;
|
|
9
|
+
supportsMcpTimeout(): boolean;
|
|
10
|
+
supportsNativeSkills(): boolean;
|
|
11
|
+
}
|
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.OpenCodeAgent = void 0;
|
|
37
37
|
const fs = __importStar(require("fs/promises"));
|
|
38
38
|
const path = __importStar(require("path"));
|
|
39
|
+
const FileSystemUtils_1 = require("../core/FileSystemUtils");
|
|
39
40
|
class OpenCodeAgent {
|
|
40
41
|
getIdentifier() {
|
|
41
42
|
return 'opencode';
|
|
@@ -49,11 +50,20 @@ class OpenCodeAgent {
|
|
|
49
50
|
mcp: path.join(projectRoot, 'opencode.json'),
|
|
50
51
|
};
|
|
51
52
|
}
|
|
52
|
-
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, agentConfig) {
|
|
53
|
+
async applyRulerConfig(concatenatedRules, projectRoot, rulerMcpJson, agentConfig, backup = true) {
|
|
53
54
|
const outputPaths = this.getDefaultOutputPath(projectRoot);
|
|
54
|
-
const instructionsPath = path.resolve(projectRoot, agentConfig?.
|
|
55
|
+
const instructionsPath = path.resolve(projectRoot, agentConfig?.outputPath ??
|
|
56
|
+
agentConfig?.outputPathInstructions ??
|
|
57
|
+
outputPaths['instructions']);
|
|
55
58
|
const mcpPath = path.resolve(projectRoot, agentConfig?.outputPathConfig ?? outputPaths['mcp']);
|
|
56
|
-
await fs.
|
|
59
|
+
await fs.mkdir(path.dirname(instructionsPath), { recursive: true });
|
|
60
|
+
if (backup) {
|
|
61
|
+
await (0, FileSystemUtils_1.backupFile)(instructionsPath, projectRoot);
|
|
62
|
+
}
|
|
63
|
+
await (0, FileSystemUtils_1.writeGeneratedFile)(instructionsPath, concatenatedRules, projectRoot);
|
|
64
|
+
if (!rulerMcpJson) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
57
67
|
// Create OpenCode config with schema and MCP configuration
|
|
58
68
|
let finalMcpConfig = {
|
|
59
69
|
$schema: 'https://opencode.ai/config.json',
|
|
@@ -71,23 +81,25 @@ class OpenCodeAgent {
|
|
|
71
81
|
},
|
|
72
82
|
};
|
|
73
83
|
}
|
|
74
|
-
else
|
|
84
|
+
else {
|
|
75
85
|
finalMcpConfig = {
|
|
76
86
|
$schema: 'https://opencode.ai/config.json',
|
|
77
|
-
mcp: (rulerMcpJson
|
|
87
|
+
mcp: (rulerMcpJson.mcpServers ?? {}),
|
|
78
88
|
};
|
|
79
89
|
}
|
|
80
90
|
}
|
|
81
91
|
catch {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
};
|
|
87
|
-
}
|
|
92
|
+
finalMcpConfig = {
|
|
93
|
+
$schema: 'https://opencode.ai/config.json',
|
|
94
|
+
mcp: (rulerMcpJson.mcpServers ?? {}),
|
|
95
|
+
};
|
|
88
96
|
}
|
|
89
97
|
// Always write the config file, even if MCP is empty
|
|
90
|
-
await fs.
|
|
98
|
+
await fs.mkdir(path.dirname(mcpPath), { recursive: true });
|
|
99
|
+
if (backup) {
|
|
100
|
+
await (0, FileSystemUtils_1.backupFile)(mcpPath, projectRoot);
|
|
101
|
+
}
|
|
102
|
+
await (0, FileSystemUtils_1.writeGeneratedFile)(mcpPath, JSON.stringify(finalMcpConfig, null, 2), projectRoot);
|
|
91
103
|
}
|
|
92
104
|
supportsMcpStdio() {
|
|
93
105
|
return true;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AbstractAgent } from './AbstractAgent';
|
|
2
|
+
export declare class OpenHandsAgent extends AbstractAgent {
|
|
3
|
+
getIdentifier(): string;
|
|
4
|
+
getName(): string;
|
|
5
|
+
getDefaultOutputPath(projectRoot: string): string;
|
|
6
|
+
supportsMcpStdio(): boolean;
|
|
7
|
+
supportsMcpRemote(): boolean;
|
|
8
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IAgentConfig } from './IAgent';
|
|
2
|
+
import { AgentsMdAgent } from './AgentsMdAgent';
|
|
3
|
+
export declare class QwenCodeAgent extends AgentsMdAgent {
|
|
4
|
+
getIdentifier(): string;
|
|
5
|
+
getName(): string;
|
|
6
|
+
private getContextFileName;
|
|
7
|
+
applyRulerConfig(concatenatedRules: string, projectRoot: string, _rulerMcpJson: Record<string, unknown> | null, agentConfig?: IAgentConfig, backup?: boolean): Promise<void>;
|
|
8
|
+
getMcpServerKey(): string;
|
|
9
|
+
supportsMcpStdio(): boolean;
|
|
10
|
+
supportsMcpRemote(): boolean;
|
|
11
|
+
}
|
|
@@ -37,6 +37,7 @@ exports.QwenCodeAgent = void 0;
|
|
|
37
37
|
const path = __importStar(require("path"));
|
|
38
38
|
const fs_1 = require("fs");
|
|
39
39
|
const AgentsMdAgent_1 = require("./AgentsMdAgent");
|
|
40
|
+
const FileSystemUtils_1 = require("../core/FileSystemUtils");
|
|
40
41
|
class QwenCodeAgent extends AgentsMdAgent_1.AgentsMdAgent {
|
|
41
42
|
getIdentifier() {
|
|
42
43
|
return 'qwen';
|
|
@@ -44,11 +45,17 @@ class QwenCodeAgent extends AgentsMdAgent_1.AgentsMdAgent {
|
|
|
44
45
|
getName() {
|
|
45
46
|
return 'Qwen Code';
|
|
46
47
|
}
|
|
47
|
-
|
|
48
|
+
getContextFileName(projectRoot, agentConfig) {
|
|
49
|
+
const outputPath = agentConfig?.outputPath ?? 'AGENTS.md';
|
|
50
|
+
return path
|
|
51
|
+
.relative(projectRoot, path.resolve(projectRoot, outputPath))
|
|
52
|
+
.replace(/\\/g, '/');
|
|
53
|
+
}
|
|
54
|
+
async applyRulerConfig(concatenatedRules, projectRoot, _rulerMcpJson, agentConfig, backup = true) {
|
|
48
55
|
// First, perform idempotent write of AGENTS.md via base class
|
|
49
56
|
await super.applyRulerConfig(concatenatedRules, projectRoot, null, {
|
|
50
57
|
outputPath: agentConfig?.outputPath,
|
|
51
|
-
});
|
|
58
|
+
}, backup);
|
|
52
59
|
// Ensure .qwen/settings.json has contextFileName set to AGENTS.md
|
|
53
60
|
const settingsPath = path.join(projectRoot, '.qwen', 'settings.json');
|
|
54
61
|
let existingSettings = {};
|
|
@@ -63,10 +70,9 @@ class QwenCodeAgent extends AgentsMdAgent_1.AgentsMdAgent {
|
|
|
63
70
|
}
|
|
64
71
|
const updated = {
|
|
65
72
|
...existingSettings,
|
|
66
|
-
contextFileName:
|
|
73
|
+
contextFileName: this.getContextFileName(projectRoot, agentConfig),
|
|
67
74
|
};
|
|
68
|
-
await
|
|
69
|
-
await fs_1.promises.writeFile(settingsPath, JSON.stringify(updated, null, 2));
|
|
75
|
+
await (0, FileSystemUtils_1.writeGeneratedFile)(settingsPath, JSON.stringify(updated, null, 2), projectRoot);
|
|
70
76
|
}
|
|
71
77
|
// Ensure MCP merging uses the correct key for Qwen Code (.qwen/settings.json)
|
|
72
78
|
getMcpServerKey() {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { IAgent, IAgentConfig } from './IAgent';
|
|
2
|
+
/**
|
|
3
|
+
* Agent for RooCode that writes to AGENTS.md and generates .roo/mcp.json
|
|
4
|
+
* with project-level MCP server configuration.
|
|
5
|
+
*/
|
|
6
|
+
export declare class RooCodeAgent implements IAgent {
|
|
7
|
+
private agentsMdAgent;
|
|
8
|
+
getIdentifier(): string;
|
|
9
|
+
getName(): string;
|
|
10
|
+
getDefaultOutputPath(projectRoot: string): Record<string, string>;
|
|
11
|
+
applyRulerConfig(concatenatedRules: string, projectRoot: string, rulerMcpJson: Record<string, unknown> | null, agentConfig?: IAgentConfig, backup?: boolean): Promise<void>;
|
|
12
|
+
supportsMcpStdio(): boolean;
|
|
13
|
+
supportsMcpRemote(): boolean;
|
|
14
|
+
getMcpServerKey(): string;
|
|
15
|
+
supportsNativeSkills(): boolean;
|
|
16
|
+
}
|
|
@@ -69,6 +69,7 @@ class RooCodeAgent {
|
|
|
69
69
|
// Now handle .roo/mcp.json configuration
|
|
70
70
|
const outputPaths = this.getDefaultOutputPath(projectRoot);
|
|
71
71
|
const mcpPath = path.resolve(projectRoot, agentConfig?.outputPathConfig ?? outputPaths['mcp']);
|
|
72
|
+
await (0, FileSystemUtils_1.assertManagedPathInsideRoot)(mcpPath, projectRoot, 'Refusing to write generated file outside project');
|
|
72
73
|
await (0, FileSystemUtils_1.ensureDirExists)(path.dirname(mcpPath));
|
|
73
74
|
// Create base structure with mcpServers
|
|
74
75
|
let finalMcpConfig = {
|
|
@@ -122,9 +123,9 @@ class RooCodeAgent {
|
|
|
122
123
|
}
|
|
123
124
|
// Backup (only if file existed and backup is enabled) then write new content
|
|
124
125
|
if (backup) {
|
|
125
|
-
await (0, FileSystemUtils_1.backupFile)(mcpPath);
|
|
126
|
+
await (0, FileSystemUtils_1.backupFile)(mcpPath, projectRoot);
|
|
126
127
|
}
|
|
127
|
-
await (0, FileSystemUtils_1.writeGeneratedFile)(mcpPath, newContent);
|
|
128
|
+
await (0, FileSystemUtils_1.writeGeneratedFile)(mcpPath, newContent, projectRoot);
|
|
128
129
|
}
|
|
129
130
|
supportsMcpStdio() {
|
|
130
131
|
return true;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AbstractAgent } from './AbstractAgent';
|
|
2
|
+
/**
|
|
3
|
+
* Trae AI agent adapter.
|
|
4
|
+
* Generates project_rules.md configuration file.
|
|
5
|
+
*/
|
|
6
|
+
export declare class TraeAgent extends AbstractAgent {
|
|
7
|
+
getIdentifier(): string;
|
|
8
|
+
getName(): string;
|
|
9
|
+
getDefaultOutputPath(projectRoot: string): string;
|
|
10
|
+
}
|