aicm 0.10.0 → 0.12.0
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 +37 -6
- package/dist/commands/install.js +22 -37
- package/dist/utils/glob-handler.d.ts +35 -0
- package/dist/utils/glob-handler.js +125 -0
- package/dist/utils/mcp-writer.d.ts +14 -0
- package/dist/utils/mcp-writer.js +69 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
> Agentic IDE Configuration Manager
|
|
4
4
|
|
|
5
|
-
A CLI tool for
|
|
5
|
+
A CLI tool for managing Agentic IDE configurations across projects
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+

|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Why
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
With the rise of Agentic IDEs, we have an opportunity to enforce best practices through rules. However, these rules are typically isolated within individual projects.
|
|
12
|
+
**aicm** is a CLI tool for distributing Agentic IDE configurations, rules, and MCPs across projects. It leverages node package managers, copy configurations from node_modules to the correct locations in your file system.
|
|
12
13
|
|
|
13
14
|
## Getting Started
|
|
14
15
|
|
|
@@ -33,6 +34,11 @@ In your project's `aicm.json`, reference the package and the specific rule:
|
|
|
33
34
|
"rules": {
|
|
34
35
|
"typescript": "@myteam/ai-tools/rules/typescript.mdc",
|
|
35
36
|
"react": "@myteam/ai-tools/rules/react.mdc"
|
|
37
|
+
},
|
|
38
|
+
"mcpServers": {
|
|
39
|
+
"my-mcp": {
|
|
40
|
+
"url": "https://example.com/sse"
|
|
41
|
+
}
|
|
36
42
|
}
|
|
37
43
|
}
|
|
38
44
|
```
|
|
@@ -47,7 +53,7 @@ In your project's `aicm.json`, reference the package and the specific rule:
|
|
|
47
53
|
}
|
|
48
54
|
```
|
|
49
55
|
|
|
50
|
-
Now the rules will be
|
|
56
|
+
Now, when you run `npm install`, the rules will be added to `.cursor/rules/aicm/` and the mcps to `.cursor/mcp.json`.
|
|
51
57
|
|
|
52
58
|
### Using Presets
|
|
53
59
|
|
|
@@ -219,7 +225,32 @@ Example `aicm.json`:
|
|
|
219
225
|
- **rules**: Object containing rule configurations
|
|
220
226
|
|
|
221
227
|
- **rule-name**: A unique identifier for the rule. Can include a directory path to install the rule to a specific directory.
|
|
222
|
-
- **source-location**: Location of the rule file (path within an npm package or local path)
|
|
228
|
+
- **source-location**: Location of the rule file (path within an npm package or local path). Supports glob patterns for automatic file discovery.
|
|
229
|
+
|
|
230
|
+
#### Glob Pattern Support
|
|
231
|
+
|
|
232
|
+
Rules support glob patterns for automatic discovery of multiple `.mdc` files. This is particularly useful when you have multiple related rules organized in directories.
|
|
233
|
+
|
|
234
|
+
```json
|
|
235
|
+
{
|
|
236
|
+
"rules": {
|
|
237
|
+
"typescript": "./rules/typescript/*.mdc",
|
|
238
|
+
"tests": "./rules/testing/**/*.mdc"
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
The key becomes the base namespace for discovered files:
|
|
244
|
+
|
|
245
|
+
- `./rules/typescript/strict.mdc` → installed as `typescript/strict`
|
|
246
|
+
- `./rules/typescript/interfaces.mdc` → installed as `typescript/interfaces`
|
|
247
|
+
- `./rules/testing/unit/setup.mdc` → installed as `tests/unit/setup`
|
|
248
|
+
|
|
249
|
+
**Installation Behavior:**
|
|
250
|
+
|
|
251
|
+
- Glob patterns are expanded during installation
|
|
252
|
+
- Only `.mdc` files are included
|
|
253
|
+
- Files are sorted alphabetically for consistent behavior
|
|
223
254
|
|
|
224
255
|
- **mcpServers**: Object containing MCP server configurations. Each key is a unique server name, and the value is an object with either:
|
|
225
256
|
|
package/dist/commands/install.js
CHANGED
|
@@ -10,11 +10,11 @@ const config_1 = require("../utils/config");
|
|
|
10
10
|
const rule_detector_1 = require("../utils/rule-detector");
|
|
11
11
|
const rule_collector_1 = require("../utils/rule-collector");
|
|
12
12
|
const rule_writer_1 = require("../utils/rule-writer");
|
|
13
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
14
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
15
13
|
const ci_info_1 = require("ci-info");
|
|
16
14
|
const discovery_1 = require("./workspaces/discovery");
|
|
17
15
|
const workspaces_install_1 = require("./workspaces/workspaces-install");
|
|
16
|
+
const mcp_writer_1 = require("../utils/mcp-writer");
|
|
17
|
+
const glob_handler_1 = require("../utils/glob-handler");
|
|
18
18
|
/**
|
|
19
19
|
* Helper function to execute a function within a specific working directory
|
|
20
20
|
* and ensure the original directory is always restored
|
|
@@ -33,27 +33,6 @@ async function withWorkingDirectory(targetDir, fn) {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
/**
|
|
37
|
-
* Write MCP servers configuration to IDE targets
|
|
38
|
-
* @param mcpServers The MCP servers configuration
|
|
39
|
-
* @param ides The IDEs to write to
|
|
40
|
-
* @param cwd The current working directory
|
|
41
|
-
*/
|
|
42
|
-
function writeMcpServersToTargets(mcpServers, ides, cwd) {
|
|
43
|
-
if (!mcpServers)
|
|
44
|
-
return;
|
|
45
|
-
for (const ide of ides) {
|
|
46
|
-
let mcpPath = null;
|
|
47
|
-
if (ide === "cursor") {
|
|
48
|
-
mcpPath = node_path_1.default.join(cwd, ".cursor", "mcp.json");
|
|
49
|
-
fs_extra_1.default.ensureDirSync(node_path_1.default.dirname(mcpPath));
|
|
50
|
-
}
|
|
51
|
-
// Windsurf does not support project mcpServers, so skip
|
|
52
|
-
if (mcpPath) {
|
|
53
|
-
fs_extra_1.default.writeJsonSync(mcpPath, { mcpServers }, { spaces: 2 });
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
36
|
/**
|
|
58
37
|
* Checks if the current environment is a CI environment
|
|
59
38
|
* This function respects any explicit settings in process.env.CI
|
|
@@ -168,20 +147,31 @@ async function install(options = {}) {
|
|
|
168
147
|
};
|
|
169
148
|
}
|
|
170
149
|
}
|
|
171
|
-
|
|
150
|
+
let expandedRules;
|
|
151
|
+
try {
|
|
152
|
+
const expansion = await (0, glob_handler_1.expandRulesGlobPatterns)(config.rules, cwd);
|
|
153
|
+
expandedRules = expansion.expandedRules;
|
|
154
|
+
if (options.verbose) {
|
|
155
|
+
for (const [expandedKey, originalPattern] of Object.entries(expansion.globSources)) {
|
|
156
|
+
console.log(chalk_1.default.gray(` Pattern "${originalPattern}" → ${expandedKey}`));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
return {
|
|
162
|
+
success: false,
|
|
163
|
+
error: `Error expanding glob patterns: ${error instanceof Error ? error.message : String(error)}`,
|
|
164
|
+
installedRuleCount: 0,
|
|
165
|
+
packagesCount: 0,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
172
168
|
let hasErrors = false;
|
|
173
169
|
const errorMessages = [];
|
|
174
170
|
let installedRuleCount = 0;
|
|
175
|
-
for (const [name, source] of Object.entries(
|
|
176
|
-
if (source === false)
|
|
177
|
-
continue; // skip canceled rules
|
|
178
|
-
// Detect rule type from the source string
|
|
171
|
+
for (const [name, source] of Object.entries(expandedRules)) {
|
|
179
172
|
const ruleType = (0, rule_detector_1.detectRuleType)(source);
|
|
180
|
-
// Get the base path of the preset file if this rule came from a preset
|
|
181
173
|
const ruleBasePath = (0, config_1.getRuleSource)(config, name);
|
|
182
|
-
// Get the original preset path for namespacing
|
|
183
174
|
const originalPresetPath = (0, config_1.getOriginalPresetPath)(config, name);
|
|
184
|
-
// Collect the rule based on its type
|
|
185
175
|
try {
|
|
186
176
|
let ruleContent;
|
|
187
177
|
switch (ruleType) {
|
|
@@ -195,7 +185,6 @@ async function install(options = {}) {
|
|
|
195
185
|
errorMessages.push(`Unknown rule type: ${ruleType}`);
|
|
196
186
|
continue;
|
|
197
187
|
}
|
|
198
|
-
// Add the preset path to the rule content for namespacing
|
|
199
188
|
if (originalPresetPath) {
|
|
200
189
|
ruleContent.presetPath = originalPresetPath;
|
|
201
190
|
}
|
|
@@ -208,7 +197,6 @@ async function install(options = {}) {
|
|
|
208
197
|
errorMessages.push(errorMessage);
|
|
209
198
|
}
|
|
210
199
|
}
|
|
211
|
-
// If there were errors, exit with error
|
|
212
200
|
if (hasErrors) {
|
|
213
201
|
return {
|
|
214
202
|
success: false,
|
|
@@ -217,13 +205,10 @@ async function install(options = {}) {
|
|
|
217
205
|
packagesCount: 0,
|
|
218
206
|
};
|
|
219
207
|
}
|
|
220
|
-
// Write all collected rules to their targets
|
|
221
208
|
(0, rule_writer_1.writeRulesToTargets)(ruleCollection);
|
|
222
|
-
// Write mcpServers config to IDE targets
|
|
223
209
|
if (config.mcpServers) {
|
|
224
|
-
// Filter out canceled servers
|
|
225
210
|
const filteredMcpServers = Object.fromEntries(Object.entries(config.mcpServers).filter(([, v]) => v !== false));
|
|
226
|
-
writeMcpServersToTargets(filteredMcpServers, config.ides, cwd);
|
|
211
|
+
(0, mcp_writer_1.writeMcpServersToTargets)(filteredMcpServers, config.ides, cwd);
|
|
227
212
|
}
|
|
228
213
|
return {
|
|
229
214
|
success: true,
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if a rule source string contains glob patterns
|
|
3
|
+
*/
|
|
4
|
+
export declare function isGlobPattern(source: string): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Expand a glob pattern to matching .mdc files
|
|
7
|
+
* @param pattern The glob pattern to expand
|
|
8
|
+
* @param basePath The base path to resolve relative patterns from
|
|
9
|
+
* @returns Array of file paths that match the pattern
|
|
10
|
+
*/
|
|
11
|
+
export declare function expandGlobPattern(pattern: string, basePath?: string): Promise<string[]>;
|
|
12
|
+
/**
|
|
13
|
+
* Generate a rule key from a file path and base key
|
|
14
|
+
* @param filePath The discovered file path
|
|
15
|
+
* @param baseKey The base key from the object notation
|
|
16
|
+
* @param patternBase The base directory of the glob pattern
|
|
17
|
+
* @returns Generated rule key with namespace
|
|
18
|
+
*/
|
|
19
|
+
export declare function generateGlobRuleKey(filePath: string, baseKey: string, patternBase: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Get the base directory from a glob pattern
|
|
22
|
+
* @param pattern The glob pattern
|
|
23
|
+
* @returns The base directory path without glob characters
|
|
24
|
+
*/
|
|
25
|
+
export declare function getGlobBase(pattern: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Expand glob patterns in rules object and return normalized rules
|
|
28
|
+
* @param rules The rules object that may contain glob patterns
|
|
29
|
+
* @param basePath The base path to resolve relative patterns from
|
|
30
|
+
* @returns Object with expanded rules and metadata about sources
|
|
31
|
+
*/
|
|
32
|
+
export declare function expandRulesGlobPatterns(rules: Record<string, string | false>, basePath?: string): Promise<{
|
|
33
|
+
expandedRules: Record<string, string>;
|
|
34
|
+
globSources: Record<string, string>;
|
|
35
|
+
}>;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.isGlobPattern = isGlobPattern;
|
|
7
|
+
exports.expandGlobPattern = expandGlobPattern;
|
|
8
|
+
exports.generateGlobRuleKey = generateGlobRuleKey;
|
|
9
|
+
exports.getGlobBase = getGlobBase;
|
|
10
|
+
exports.expandRulesGlobPatterns = expandRulesGlobPatterns;
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
+
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
13
|
+
/**
|
|
14
|
+
* Check if a rule source string contains glob patterns
|
|
15
|
+
*/
|
|
16
|
+
function isGlobPattern(source) {
|
|
17
|
+
return /[*?{}[\]]/.test(source);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Expand a glob pattern to matching .mdc files
|
|
21
|
+
* @param pattern The glob pattern to expand
|
|
22
|
+
* @param basePath The base path to resolve relative patterns from
|
|
23
|
+
* @returns Array of file paths that match the pattern
|
|
24
|
+
*/
|
|
25
|
+
async function expandGlobPattern(pattern, basePath) {
|
|
26
|
+
// Normalize the pattern to use forward slashes for consistent behavior
|
|
27
|
+
const normalizedPattern = pattern.replace(/\\/g, "/");
|
|
28
|
+
try {
|
|
29
|
+
const matches = await (0, fast_glob_1.default)(normalizedPattern, {
|
|
30
|
+
ignore: ["**/.*"], // Ignore hidden files
|
|
31
|
+
absolute: false,
|
|
32
|
+
onlyFiles: true,
|
|
33
|
+
// Set the working directory if basePath is provided
|
|
34
|
+
cwd: basePath,
|
|
35
|
+
});
|
|
36
|
+
// Filter to only .mdc files, normalize paths, and sort for deterministic behavior
|
|
37
|
+
return matches
|
|
38
|
+
.filter((file) => file.endsWith(".mdc"))
|
|
39
|
+
.map((file) => file.replace(/\\/g, "/")) // Normalize Windows backslashes to forward slashes
|
|
40
|
+
.sort((a, b) => a.localeCompare(b));
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
throw new Error(`Error expanding glob pattern "${pattern}": ${error instanceof Error ? error.message : String(error)}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Generate a rule key from a file path and base key
|
|
48
|
+
* @param filePath The discovered file path
|
|
49
|
+
* @param baseKey The base key from the object notation
|
|
50
|
+
* @param patternBase The base directory of the glob pattern
|
|
51
|
+
* @returns Generated rule key with namespace
|
|
52
|
+
*/
|
|
53
|
+
function generateGlobRuleKey(filePath, baseKey, patternBase) {
|
|
54
|
+
// Normalize paths to use forward slashes for consistent behavior
|
|
55
|
+
const normalizedFilePath = filePath.replace(/\\/g, "/");
|
|
56
|
+
const normalizedPatternBase = patternBase.replace(/\\/g, "/");
|
|
57
|
+
// Get the relative path from the pattern base to the file
|
|
58
|
+
const relativePath = node_path_1.default.posix.relative(normalizedPatternBase, normalizedFilePath);
|
|
59
|
+
// Remove .mdc extension
|
|
60
|
+
const withoutExtension = relativePath.replace(/\.mdc$/, "");
|
|
61
|
+
// Return the combined key
|
|
62
|
+
return `${baseKey}/${withoutExtension}`;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get the base directory from a glob pattern
|
|
66
|
+
* @param pattern The glob pattern
|
|
67
|
+
* @returns The base directory path without glob characters
|
|
68
|
+
*/
|
|
69
|
+
function getGlobBase(pattern) {
|
|
70
|
+
// Normalize path separators to forward slashes for consistent behavior
|
|
71
|
+
const normalizedPattern = pattern.replace(/\\/g, "/");
|
|
72
|
+
// Find the first occurrence of glob characters
|
|
73
|
+
const globIndex = normalizedPattern.search(/[*?{}[\]]/);
|
|
74
|
+
if (globIndex === -1) {
|
|
75
|
+
// No glob characters, return the directory
|
|
76
|
+
return node_path_1.default.dirname(normalizedPattern);
|
|
77
|
+
}
|
|
78
|
+
// Get the path up to the first glob character
|
|
79
|
+
const basePath = normalizedPattern.substring(0, globIndex);
|
|
80
|
+
// Find the last path separator before the glob
|
|
81
|
+
const lastSeparator = basePath.lastIndexOf("/");
|
|
82
|
+
if (lastSeparator === -1) {
|
|
83
|
+
return ".";
|
|
84
|
+
}
|
|
85
|
+
return basePath.substring(0, lastSeparator);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Expand glob patterns in rules object and return normalized rules
|
|
89
|
+
* @param rules The rules object that may contain glob patterns
|
|
90
|
+
* @param basePath The base path to resolve relative patterns from
|
|
91
|
+
* @returns Object with expanded rules and metadata about sources
|
|
92
|
+
*/
|
|
93
|
+
async function expandRulesGlobPatterns(rules, basePath) {
|
|
94
|
+
const expandedRules = {};
|
|
95
|
+
const globSources = {};
|
|
96
|
+
for (const [key, source] of Object.entries(rules)) {
|
|
97
|
+
if (source === false) {
|
|
98
|
+
continue; // Skip canceled rules
|
|
99
|
+
}
|
|
100
|
+
if (isGlobPattern(source)) {
|
|
101
|
+
// Expand glob pattern
|
|
102
|
+
try {
|
|
103
|
+
const matchedFiles = await expandGlobPattern(source, basePath);
|
|
104
|
+
if (matchedFiles.length === 0) {
|
|
105
|
+
console.warn(`Warning: Glob pattern "${source}" matched no files`);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const patternBase = getGlobBase(source);
|
|
109
|
+
for (const filePath of matchedFiles) {
|
|
110
|
+
const generatedKey = generateGlobRuleKey(filePath, key, patternBase);
|
|
111
|
+
expandedRules[generatedKey] = filePath;
|
|
112
|
+
globSources[generatedKey] = source;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
throw new Error(`Error processing glob pattern for key "${key}": ${error instanceof Error ? error.message : String(error)}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// Regular file path
|
|
121
|
+
expandedRules[key] = source;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return { expandedRules, globSources };
|
|
125
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Config } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Write MCP servers configuration to IDE targets
|
|
4
|
+
* @param mcpServers The MCP servers configuration
|
|
5
|
+
* @param ides The IDEs to write to
|
|
6
|
+
* @param cwd The current working directory
|
|
7
|
+
*/
|
|
8
|
+
export declare function writeMcpServersToTargets(mcpServers: Config["mcpServers"], ides: string[], cwd: string): void;
|
|
9
|
+
/**
|
|
10
|
+
* Write MCP servers configuration to a specific file
|
|
11
|
+
* @param mcpServers The MCP servers configuration
|
|
12
|
+
* @param mcpPath The path to the mcp.json file
|
|
13
|
+
*/
|
|
14
|
+
export declare function writeMcpServersToFile(mcpServers: Config["mcpServers"], mcpPath: string): void;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.writeMcpServersToTargets = writeMcpServersToTargets;
|
|
7
|
+
exports.writeMcpServersToFile = writeMcpServersToFile;
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
/**
|
|
11
|
+
* Write MCP servers configuration to IDE targets
|
|
12
|
+
* @param mcpServers The MCP servers configuration
|
|
13
|
+
* @param ides The IDEs to write to
|
|
14
|
+
* @param cwd The current working directory
|
|
15
|
+
*/
|
|
16
|
+
function writeMcpServersToTargets(mcpServers, ides, cwd) {
|
|
17
|
+
if (!mcpServers)
|
|
18
|
+
return;
|
|
19
|
+
for (const ide of ides) {
|
|
20
|
+
if (ide === "cursor") {
|
|
21
|
+
const mcpPath = node_path_1.default.join(cwd, ".cursor", "mcp.json");
|
|
22
|
+
writeMcpServersToFile(mcpServers, mcpPath);
|
|
23
|
+
}
|
|
24
|
+
// Windsurf does not support project mcpServers, so skip
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Write MCP servers configuration to a specific file
|
|
29
|
+
* @param mcpServers The MCP servers configuration
|
|
30
|
+
* @param mcpPath The path to the mcp.json file
|
|
31
|
+
*/
|
|
32
|
+
function writeMcpServersToFile(mcpServers, mcpPath) {
|
|
33
|
+
var _a;
|
|
34
|
+
if (!mcpServers)
|
|
35
|
+
return;
|
|
36
|
+
fs_extra_1.default.ensureDirSync(node_path_1.default.dirname(mcpPath));
|
|
37
|
+
const existingConfig = fs_extra_1.default.existsSync(mcpPath)
|
|
38
|
+
? fs_extra_1.default.readJsonSync(mcpPath)
|
|
39
|
+
: {};
|
|
40
|
+
const existingMcpServers = (_a = existingConfig === null || existingConfig === void 0 ? void 0 : existingConfig.mcpServers) !== null && _a !== void 0 ? _a : {};
|
|
41
|
+
// Filter out any existing aicm-managed servers (with aicm: true)
|
|
42
|
+
// This removes stale aicm servers that are no longer in the configuration
|
|
43
|
+
const userMcpServers = {};
|
|
44
|
+
for (const [key, value] of Object.entries(existingMcpServers)) {
|
|
45
|
+
if (typeof value === "object" && value !== null && value.aicm !== true) {
|
|
46
|
+
userMcpServers[key] = value;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Mark new aicm servers as managed and filter out canceled servers
|
|
50
|
+
const aicmMcpServers = {};
|
|
51
|
+
for (const [key, value] of Object.entries(mcpServers)) {
|
|
52
|
+
if (value !== false) {
|
|
53
|
+
aicmMcpServers[key] = {
|
|
54
|
+
...value,
|
|
55
|
+
aicm: true,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Merge user servers with aicm servers (aicm servers override user servers with same key)
|
|
60
|
+
const mergedMcpServers = {
|
|
61
|
+
...userMcpServers,
|
|
62
|
+
...aicmMcpServers,
|
|
63
|
+
};
|
|
64
|
+
const mergedConfig = {
|
|
65
|
+
...existingConfig,
|
|
66
|
+
mcpServers: mergedMcpServers,
|
|
67
|
+
};
|
|
68
|
+
fs_extra_1.default.writeJsonSync(mcpPath, mergedConfig, { spaces: 2 });
|
|
69
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aicm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "A TypeScript CLI tool for managing AI IDE rules across different projects and teams",
|
|
5
5
|
"main": "dist/api.js",
|
|
6
6
|
"types": "dist/api.d.ts",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"chalk": "^4.1.2",
|
|
44
44
|
"ci-info": "^4.2.0",
|
|
45
45
|
"cosmiconfig": "^9.0.0",
|
|
46
|
+
"fast-glob": "^3.3.3",
|
|
46
47
|
"fs-extra": "^11.1.1"
|
|
47
48
|
},
|
|
48
49
|
"devDependencies": {
|