aicm 0.13.1 → 0.14.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 CHANGED
@@ -8,117 +8,105 @@ A CLI tool for managing Agentic IDE configurations across projects
8
8
 
9
9
  ## Why
10
10
 
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.
11
+ Agentic IDEs like Cursor enable AI-driven development through custom rules and configurations. However, sharing these configurations across projects and teams is challenging.
12
+
13
+ **aicm** solves this by distributing AI rules and MCP servers through npm packages, automatically installing them to the correct IDE locations.
13
14
 
14
15
  ## Getting Started
15
16
 
16
- Since aicm is not a package manager, begin by creating an npm package that contains your rules and MCP configurations.
17
+ The easiest way to get started with aicm is by using **presets** - npm packages containing rules and MCP configurations that you can install in any project.
17
18
 
18
- Consider the following npm package structure:
19
+ ### Using a preset
19
20
 
20
- ```
21
- @myteam/ai-tools
22
- ├── package.json
23
- └── rules/
24
- ├── typescript.mdc
25
- └── react.mdc
26
- ```
21
+ 1. **Install a preset npm package**:
27
22
 
28
- 1. **Point to the path within the npm package**
23
+ ```bash
24
+ npm install --save-dev @yourteam/ai-preset
25
+ ```
29
26
 
30
- In your project's `aicm.json`, reference the package and the specific rule:
27
+ 2. **Create an `aicm.json` file** in your project:
31
28
 
32
29
  ```json
33
- {
34
- "rules": {
35
- "typescript": "@myteam/ai-tools/rules/typescript.mdc",
36
- "react": "@myteam/ai-tools/rules/react.mdc"
37
- },
38
- "mcpServers": {
39
- "my-mcp": {
40
- "url": "https://example.com/sse"
41
- }
42
- }
43
- }
30
+ { "presets": ["@yourteam/ai-preset"] }
31
+ ```
32
+
33
+ 3. **Install the rules and MCPs**:
34
+
35
+ ```bash
36
+ npx -y aicm install
44
37
  ```
45
38
 
46
- 2. **Add a prepare script** to your `package.json`:
39
+ 4. **Add a prepare script** to your `package.json` for automatic installation:
47
40
 
48
41
  ```json
49
42
  {
50
43
  "scripts": {
51
- "prepare": "npx -y aicm install"
44
+ "prepare": "npx aicm install"
52
45
  }
53
46
  }
54
47
  ```
55
48
 
56
- Now, when you run `npm install`, the rules will be added to `.cursor/rules/aicm/` and the mcps to `.cursor/mcp.json`.
49
+ The rules are now installed in `.cursor/rules/aicm/` and any MCP servers are configured in `.cursor/mcp.json`.
57
50
 
58
- ### Using Presets
51
+ ### Creating a Preset
59
52
 
60
- Presets allow you to bundle multiple rules & mcps into a single configuration that can be shared across projects.
53
+ To create a reusable preset for your team:
61
54
 
62
- 1. **Create a preset package or directory**
55
+ 1. **Create an npm package** with the following structure:
63
56
 
64
- Create an npm package with your rule definitions in an `aicm.json` file:
57
+ ```
58
+ @myteam/ai-tools
59
+ ├── package.json
60
+ ├── aicm.json
61
+ └── rules/
62
+ ├── typescript.mdc
63
+ └── react.mdc
64
+ ```
65
65
 
66
- > `@myteam/ai-tools/aicm.json`
66
+ 2. **Configure the preset's `aicm.json`**:
67
67
 
68
68
  ```json
69
69
  {
70
- "rules": {
71
- "typescript": "./rules/typescript.mdc",
72
- "react": "./rules/react.mdc"
73
- },
70
+ "rulesDir": "./rules",
74
71
  "mcpServers": {
75
- "my-mcp": {
76
- "url": "https://example.com/sse"
77
- }
72
+ "my-mcp": { "url": "https://example.com/sse" }
78
73
  }
79
74
  }
80
75
  ```
81
76
 
82
- 2. **Reference the preset in your project**
77
+ 3. **Publish the package** and reference it in your projects:
78
+
79
+ ```json
80
+ { "presets": ["@myteam/ai-tools"] }
81
+ ```
82
+
83
+ > **Note:** This is syntactic sugar for `@myteam/ai-tools/aicm.json`. Both forms are equivalent.
84
+
85
+ ### Using Local Rules
83
86
 
84
- In your project's `aicm.json`, reference the preset by its npm package or directory name:
87
+ For project-specific rules, you can specify `rulesDir` in your `aicm.json` config. This approach allows you to write rules once and automatically generate them for all configured targets:
85
88
 
86
89
  ```json
87
90
  {
88
- "presets": ["@myteam/ai-tools"]
91
+ "rulesDir": "./rules"
89
92
  }
90
93
  ```
91
94
 
92
- When you run `npx aicm install`, all rules from the preset will be installed to `.cursor/rules/aicm/` and all mcps from the preset will be installed to `.cursor/mcp.json`.
93
-
94
95
  ### Notes
95
96
 
96
97
  - Generated rules are always placed in a subdirectory for deterministic cleanup and easy gitignore.
97
- - Users may add `.cursor/rules/aicm/` and `.aicm/` (for Windsurf/Codex) to their `.gitignore` if they do not want to track generated rules.
98
-
99
- ### Overriding and Disabling Rules and MCP Servers from Presets
100
-
101
- When you use a preset, you can override or disable any rule or mcpServer from the preset in your own `aicm.json` configuration:
98
+ - Users may add `.cursor/rules/aicm/` and `.aicm/` (for Windsurf/Codex) to `.gitignore` if they do not want to track generated rules.
102
99
 
103
- - **Override**: To override a rule or mcpServer, specify the same key in your config with a new value. The value in your config will take precedence over the preset.
104
- - **Disable**: To disable a rule or mcpServer from a preset, set its value to `false` in your config.
100
+ ### Overrides
105
101
 
106
- **Example:**
102
+ You can disable or replace specific rules provided by presets using the `overrides` field:
107
103
 
108
104
  ```json
109
105
  {
110
- "ides": ["cursor"],
111
- "presets": ["@company/ai-rules/aicm.json"],
112
- "rules": {
106
+ "presets": ["@company/ai-rules"],
107
+ "overrides": {
113
108
  "rule-from-preset-a": "./rules/override-rule.mdc",
114
109
  "rule-from-preset-b": false
115
- },
116
- "mcpServers": {
117
- "mcp-from-preset-a": {
118
- "command": "./scripts/override-mcp.sh",
119
- "env": { "MCP_TOKEN": "override" }
120
- },
121
- "mcp-from-preset-b": false
122
110
  }
123
111
  }
124
112
  ```
@@ -127,27 +115,27 @@ When you use a preset, you can override or disable any rule or mcpServer from th
127
115
 
128
116
  We'll install [an npm package](https://github.com/ranyitz/pirate-coding) containing a simple preset to demonstrate how aicm works.
129
117
 
130
- 1. Install an npm package containing a preset
118
+ 1. **Install the demo preset package**:
131
119
 
132
120
  ```bash
133
121
  npm install --save-dev pirate-coding
134
122
  ```
135
123
 
136
- 2. Create an `aicm.json` file in your project
124
+ 2. **Create an `aicm.json` file** in your project:
137
125
 
138
126
  ```bash
139
127
  echo '{ "presets": ["pirate-coding"] }' > aicm.json
140
128
  ```
141
129
 
142
- 3. Install all rules & mcps from your configuration
130
+ 3. **Install all rules & MCPs from your configuration**:
143
131
 
144
132
  ```bash
145
- npx -y aicm install
133
+ npx aicm install
146
134
  ```
147
135
 
148
136
  This command installs all configured rules and MCPs to their IDE-specific locations.
149
137
 
150
- After installation, open Cursor and ask it to do something. Your AI assistant will respond with pirate-themed coding advice. You can also ask it about the aicm library which uses https://gitmcp.io/ to give you advise based on the latest documentation.
138
+ After installation, open Cursor and ask it to do something. Your AI assistant will respond with pirate-themed coding advice. You can also ask it about the aicm library which uses https://gitmcp.io/ to give you advice based on the latest documentation.
151
139
 
152
140
  ## Security Note
153
141
 
@@ -157,7 +145,7 @@ To prevent [prompt-injection](https://en.wikipedia.org/wiki/Prompt_injection), u
157
145
 
158
146
  aicm supports workspaces by automatically discovering and installing configurations across multiple packages in your repository.
159
147
 
160
- To enable workspaces mode, set the `workspaces` property to `true` in your root `aicm.json`:
148
+ You can enable workspaces mode by setting the `workspaces` property to `true` in your root `aicm.json`:
161
149
 
162
150
  ```json
163
151
  {
@@ -165,7 +153,9 @@ To enable workspaces mode, set the `workspaces` property to `true` in your root
165
153
  }
166
154
  ```
167
155
 
168
- This will:
156
+ aicm automatically detects workspaces if your `package.json` contains a `workspaces` configuration:
157
+
158
+ ### How It Works
169
159
 
170
160
  1. **Discover packages**: Automatically find all directories containing `aicm.json` files in your repository
171
161
  2. **Install per package**: Install rules and MCPs for each package individually in their respective directories
@@ -196,113 +186,34 @@ Running `npx aicm install` will install rules for each package in their respecti
196
186
 
197
187
  ## Configuration
198
188
 
199
- To configure aicm, use either:
200
-
201
- - a root-level `aicm.json` file, **or**
202
- - an `aicm` key in your project's `package.json`.
203
-
204
- Example `aicm.json`:
205
-
206
- ```json
207
- {
208
- "ides": ["cursor"],
209
- "presets": ["@my-team/ai-tools/my-aicm.json"],
210
- "rules": {
211
- "team-rules/team-standards": "@my-team/ai-tools/rules/team-standards.mdc"
212
- },
213
- "mcpServers": {
214
- "remote-mcp": {
215
- "url": "https://example.com/sse"
216
- }
217
- }
218
- }
219
- ```
220
-
221
- - **ides**: Array of IDE names where rules should be installed. Currently supported values:
222
-
223
- - `"cursor"`: For the Cursor IDE
224
- - `"windsurf"`: For the Windsurf IDE
225
- - `"codex"`: For the Codex Agent
226
-
227
- > **Note:** The 'ides' field is default to `["cursor"]` if not specified.
228
-
229
- - **rules**: Object containing rule configurations.
230
- If you want to install every rule from a single directory, you can also use a
231
- string as a shortcut:
232
-
233
- ```json
234
- {
235
- "rules": "./rules/*"
236
- }
237
- ```
238
-
239
- - **rule-name**: A unique identifier for the rule. Can include a directory path to install the rule to a specific directory.
240
- - **source-location**: Location of the rule file (path within an npm package or local path). Supports glob patterns for automatic file discovery.
241
-
242
- #### Glob Pattern Support
243
-
244
- Rules support glob patterns for automatic discovery of multiple `.mdc` files. This is particularly useful when you have multiple related rules organized in directories.
189
+ Create an `aicm.json` file in your project root, or an `aicm` key in your project's `package.json`.
245
190
 
246
191
  ```json
247
192
  {
248
- "rules": {
249
- "typescript": "./rules/typescript/*.mdc",
250
- "tests": "./rules/testing/**/*.mdc"
251
- }
193
+ "rulesDir": "./rules",
194
+ "targets": ["cursor"],
195
+ "presets": [],
196
+ "overrides": {},
197
+ "mcpServers": {}
252
198
  }
253
199
  ```
254
200
 
255
- The key becomes the base namespace for discovered files:
256
-
257
- - `./rules/typescript/strict.mdc` installed as `typescript/strict`
258
- - `./rules/typescript/interfaces.mdc` installed as `typescript/interfaces`
259
- - `./rules/testing/unit/setup.mdc` installed as `tests/unit/setup`
260
-
261
- **Installation Behavior:**
262
-
263
- - Glob patterns are expanded during installation
264
- - Only `.mdc` files are included
265
- - Files are sorted alphabetically for consistent behavior
266
-
267
- - **mcpServers**: Object containing MCP server configurations. Each key is a unique server name, and the value is an object with either:
268
-
269
- - **command**: The command or script to run (with optional **args** and **env**), or
270
- - **url**: The URL to fetch the MCP config from (with optional **env**)
271
-
272
- - **presets**: Array of preset configurations to include. Each preset is a path to a JSON file (npm package or local path) that contains additional rules and mcpServers.
273
-
274
- - Preset files should contain a `rules` and `mcpServers` objects with the same structure as the main configuration.
201
+ - **rulesDir**: Directory containing all rule files.
202
+ - **targets**: IDEs/Agent targets where rules should be installed. Defaults to `["cursor"]`.
203
+ - **presets**: List of preset packages or paths to include.
204
+ - **overrides**: Map of rule names to `false` (disable) or a replacement file path.
205
+ - **mcpServers**: MCP server configurations.
206
+ - **workspaces**: Set to `true` to enable workspace mode. If not specified, aicm will automatically detect workspaces from your `package.json`.
275
207
 
276
208
  ### MCP Server Installation
277
209
 
278
- - **Cursor**: MCP server configs are written to `.cursor/mcp.json` (see Cursor docs for latest path).
279
- - **Windsurf**: Windsurf does not support project mcpServers. MCP server configuration is not installed for Windsurf projects.
280
-
281
- ### Rule Source Types
282
-
283
- The type of rule is automatically detected based on the source format:
284
-
285
- #### NPM Source
286
-
287
- Rules provided by NPM packages. The package must be installed either globally or in your project's `node_modules`. Sources that start with `@` or don't contain start with path separators are detected as NPM packages.
288
-
289
- ```json
290
- "react-best-practices": "@my-team/ai-tools/aicm-react"
291
- ```
292
-
293
- #### Local Source
294
-
295
- Rules stored locally in your project or filesystem. Any path containing slashes or backslashes is detected as a local file path.
296
-
297
- ```json
298
- "personal-rules": "./rules/custom.mdc"
299
- ```
210
+ - **Cursor**: MCP server configs are written to `.cursor/mcp.json`.
300
211
 
301
- ## Supported IDEs
212
+ ## Supported Targets
302
213
 
303
214
  - **Cursor**: Rules are installed as individual `.mdc` files in the Cursor rules directory (`.cursor/rules/aicm/`), mcp servers are installed to `.cursor/mcp.json`
304
215
  - **Windsurf**: Rules are installed in the `.aicm` directory which should be added to your `.gitignore` file. Our approach for Windsurf is to create links from the `.windsurfrules` file to the respective rules in the `.aicm` directory. There is no support for local mcp servers at the moment.
305
- - **Codex**: Rules are installed in the `.aicm` directory and referenced from `AGENTS.md` using the same markers as Windsurf.
216
+ - **Codex**: Rules are installed in the `.aicm` directory and referenced from `AGENTS.md`.
306
217
 
307
218
  ## Commands
308
219
 
@@ -356,7 +267,7 @@ const customConfig = {
356
267
  ides: ["cursor"],
357
268
  rules: {
358
269
  typescript: "./rules/typescript.mdc",
359
- react: "@org/rules/react.mdc",
270
+ react: "./rules/react.mdc",
360
271
  },
361
272
  };
362
273
 
package/dist/api.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- import { InstallOptions, InstallResult } from "./commands/install/install-package";
1
+ import { InstallOptions, InstallResult } from "./commands/install";
2
2
  /**
3
3
  * Install AICM rules based on configuration
4
4
  * @param options Installation options
5
5
  * @returns Result of the install operation
6
6
  */
7
7
  export declare function install(options?: InstallOptions): Promise<InstallResult>;
8
- export { Config, NormalizedConfig, Rule, Rules, RuleMetadata, RuleContent, RuleCollection, } from "./types";
8
+ export type { InstallOptions, InstallResult } from "./commands/install";
9
+ export type { ResolvedConfig, Config, RuleFile, MCPServers, } from "./utils/config";
@@ -0,0 +1,9 @@
1
+ import { InstallOptions, InstallResult } from "./commands/install";
2
+ /**
3
+ * Install AICM rules based on configuration (v2)
4
+ * @param options Installation options
5
+ * @returns Result of the install operation
6
+ */
7
+ export declare function install(options?: InstallOptions): Promise<InstallResult>;
8
+ export type { InstallOptions, InstallResult } from "./commands/install";
9
+ export type { ResolvedConfig, Config, RuleFile, MCPServers, } from "./utils/config";
package/dist/api_v2.js ADDED
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.install = install;
4
+ const install_1 = require("./commands/install");
5
+ /**
6
+ * Install AICM rules based on configuration (v2)
7
+ * @param options Installation options
8
+ * @returns Result of the install operation
9
+ */
10
+ async function install(options = {}) {
11
+ return (0, install_1.install)(options);
12
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const cli_v2_1 = require("../cli_v2");
5
+ (0, cli_v2_1.runCliV2)().catch((error) => {
6
+ console.error(error);
7
+ process.exit(1);
8
+ });
package/dist/cli.js CHANGED
@@ -81,11 +81,14 @@ ${chalk_1.default.bold("EXAMPLES")}
81
81
  $ aicm list
82
82
  `);
83
83
  }
84
- function logError(error, verbose = false) {
85
- if (verbose && error instanceof Error && error.stack) {
86
- console.error(chalk_1.default.red(error.stack));
84
+ function logError(error, verbose) {
85
+ if (error instanceof Error) {
86
+ console.error(chalk_1.default.red(`Error: ${error.message}`));
87
+ if (verbose && error.stack) {
88
+ console.error(chalk_1.default.gray(error.stack));
89
+ }
87
90
  }
88
91
  else {
89
- console.error(chalk_1.default.red(error instanceof Error ? error.message : String(error)));
92
+ console.error(chalk_1.default.red(`Error: ${String(error)}`));
90
93
  }
91
94
  }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export declare function runCliV2(): Promise<void>;
package/dist/cli_v2.js ADDED
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.runCliV2 = runCliV2;
8
+ const arg_1 = __importDefault(require("arg"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const init_1 = require("./commands/init");
11
+ const install_1 = require("./commands/install");
12
+ const list_1 = require("./commands/list");
13
+ // Define version from package.json
14
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
15
+ const pkg = require("../package.json");
16
+ async function runCliV2() {
17
+ const args = (0, arg_1.default)({
18
+ "--help": Boolean,
19
+ "--version": Boolean,
20
+ "--ci": Boolean,
21
+ "--verbose": Boolean,
22
+ "-h": "--help",
23
+ "-v": "--version",
24
+ }, {
25
+ permissive: true,
26
+ argv: process.argv.slice(2),
27
+ });
28
+ // Show version
29
+ if (args["--version"]) {
30
+ console.log(pkg.version);
31
+ process.exit(0);
32
+ }
33
+ // Show help
34
+ if (args["--help"]) {
35
+ showHelp();
36
+ process.exit(0);
37
+ }
38
+ const command = args._.length > 0 ? args._[0] : null;
39
+ try {
40
+ switch (command) {
41
+ case "init":
42
+ (0, init_1.initCommand)();
43
+ break;
44
+ case "install":
45
+ await (0, install_1.installCommand)(args["--ci"], args["--verbose"]);
46
+ break;
47
+ case "list":
48
+ await (0, list_1.listCommand)();
49
+ break;
50
+ default:
51
+ showHelp();
52
+ break;
53
+ }
54
+ }
55
+ catch (error) {
56
+ logError(error, args["--verbose"]);
57
+ process.exit(1);
58
+ }
59
+ }
60
+ function showHelp() {
61
+ console.log(`
62
+ ${chalk_1.default.bold("aicm v2")} - A CLI tool for managing AI IDE configurations (v2)
63
+
64
+ ${chalk_1.default.bold("USAGE")}
65
+ $ aicm-v2 [command] [options]
66
+
67
+ ${chalk_1.default.bold("COMMANDS")}
68
+ init Initialize a new aicm configuration file
69
+ install Install rules from configured sources
70
+ list List all configured rules and their status
71
+
72
+ ${chalk_1.default.bold("OPTIONS")}
73
+ -h, --help Show this help message
74
+ -v, --version Show version number
75
+ --ci Run in CI environments (default: \`false\`)
76
+ --verbose Show detailed output and stack traces for debugging
77
+
78
+ ${chalk_1.default.bold("EXAMPLES")}
79
+ $ aicm-v2 init
80
+ $ aicm-v2 install
81
+ $ aicm-v2 list
82
+ `);
83
+ }
84
+ function logError(error, verbose) {
85
+ if (error instanceof Error) {
86
+ console.error(chalk_1.default.red(`Error: ${error.message}`));
87
+ if (verbose && error.stack) {
88
+ console.error(chalk_1.default.gray(error.stack));
89
+ }
90
+ }
91
+ else {
92
+ console.error(chalk_1.default.red(`Error: ${String(error)}`));
93
+ }
94
+ }
@@ -1,8 +1,52 @@
1
- import { InstallOptions, InstallResult } from "./install/install-package";
1
+ import { ResolvedConfig } from "../utils/config";
2
+ export interface InstallOptions {
3
+ /**
4
+ * Base directory to use instead of process.cwd()
5
+ */
6
+ cwd?: string;
7
+ /**
8
+ * Custom config object to use instead of loading from file
9
+ */
10
+ config?: ResolvedConfig;
11
+ /**
12
+ * allow installation on CI environments
13
+ */
14
+ installOnCI?: boolean;
15
+ /**
16
+ * Show verbose output during installation
17
+ */
18
+ verbose?: boolean;
19
+ }
20
+ /**
21
+ * Result of the install operation
22
+ */
23
+ export interface InstallResult {
24
+ /**
25
+ * Whether the operation was successful
26
+ */
27
+ success: boolean;
28
+ /**
29
+ * Error object if the operation failed
30
+ */
31
+ error?: Error;
32
+ /**
33
+ * Number of rules installed
34
+ */
35
+ installedRuleCount: number;
36
+ /**
37
+ * Number of packages installed
38
+ */
39
+ packagesCount: number;
40
+ }
41
+ /**
42
+ * Install rules for a single package (used within workspaces and standalone installs)
43
+ */
44
+ export declare function installPackage(options?: InstallOptions): Promise<InstallResult>;
2
45
  /**
3
46
  * Core implementation of the rule installation logic
4
- * @param options Install options
5
- * @returns Result of the install operation
6
47
  */
7
48
  export declare function install(options?: InstallOptions): Promise<InstallResult>;
49
+ /**
50
+ * CLI command wrapper for install
51
+ */
8
52
  export declare function installCommand(installOnCI?: boolean, verbose?: boolean): Promise<void>;