aicm 0.6.0 → 0.6.2

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
@@ -121,32 +121,24 @@ When you use a preset, you can override or disable any rule or mcpServer from th
121
121
 
122
122
  ### Demo
123
123
 
124
- We'll install an npm package containing a simple rule to demonstrate how aicm works.
124
+ We'll install [an npm package](https://github.com/ranyitz/pirate-coding) containing a simple preset to demonstrate how aicm works.
125
125
 
126
- 1. Install an npm package containing a rule
126
+ 1. Install an npm package containing a preset
127
127
 
128
128
  ```bash
129
- npm install --save-dev pirate-coding-rule
129
+ npm install --save-dev pirate-coding
130
130
  ```
131
131
 
132
- 2. Initialize aicm config
132
+ 2. Create an `aicm.json` file in your project
133
133
 
134
134
  ```bash
135
- npx -y aicm init
136
- ```
137
-
138
- 3. Add the rule to your config file: `aicm.json`
139
-
140
- ```json
141
- {
135
+ echo '{
142
136
  "ides": ["cursor"],
143
- "rules": {
144
- "pirate-coding": "pirate-coding-rule/rule.mdc"
145
- }
146
- }
137
+ "presets": ["pirate-coding"]
138
+ }' > aicm.json
147
139
  ```
148
140
 
149
- 4. Install all rules from your configuration
141
+ 3. Install all rules & mcps from your configuration
150
142
 
151
143
  ```bash
152
144
  npx -y aicm install
@@ -154,7 +146,7 @@ npx -y aicm install
154
146
 
155
147
  This command installs all configured rules and MCPs to their IDE-specific locations.
156
148
 
157
- After installation, open Cursor and ask it to do something. Your AI assistant will respond with pirate-themed coding advice.
149
+ 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.
158
150
 
159
151
  ## Security Note
160
152
 
@@ -251,12 +243,65 @@ npx aicm init
251
243
 
252
244
  ### `install`
253
245
 
254
- Installs rules from your configuration to the appropriate IDE locations.
246
+ Installs all rules and MCPs configured in your `aicm.json`.
255
247
 
256
248
  ```bash
257
249
  npx aicm install
258
250
  ```
259
251
 
252
+ ## Node.js API
253
+
254
+ In addition to the CLI, aicm can be used programmatically in Node.js applications:
255
+
256
+ ```javascript
257
+ const { install, Config } = require("aicm");
258
+
259
+ install().then((result) => {
260
+ if (result.success) {
261
+ console.log(`Successfully installed ${result.installedRuleCount} rules`);
262
+ } else {
263
+ console.error(`Error: ${result.error}`);
264
+ }
265
+ });
266
+
267
+ // Install with custom options
268
+ const customConfig = {
269
+ ides: ["cursor"],
270
+ rules: {
271
+ typescript: "./rules/typescript.mdc",
272
+ react: "@org/rules/react.mdc",
273
+ },
274
+ };
275
+
276
+ install({
277
+ config: customConfig,
278
+ cwd: "/path/to/project",
279
+ silent: true,
280
+ }).then((result) => {
281
+ // Handle result
282
+ });
283
+ ```
284
+
285
+ ### API Reference
286
+
287
+ #### `install(options?: InstallOptions): Promise<InstallResult>`
288
+
289
+ Installs rules and MCP servers based on configuration.
290
+
291
+ **Options:**
292
+
293
+ - `cwd`: Base directory to use instead of `process.cwd()`
294
+ - `config`: Custom config object to use instead of loading from file
295
+ - `silent`: Whether to suppress console output
296
+
297
+ **Returns:**
298
+
299
+ A Promise that resolves to an object with:
300
+
301
+ - `success`: Whether the operation was successful
302
+ - `error`: Error message if the operation failed
303
+ - `installedRuleCount`: Number of rules installed
304
+
260
305
  ## Contributing
261
306
 
262
307
  Contributions are welcome! Please feel free to submit a Pull Request.
package/dist/api.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { InstallOptions, InstallResult } from "./commands/install";
2
+ /**
3
+ * Install AICM rules based on configuration
4
+ * @param options Install options
5
+ * @returns Result of the install operation
6
+ */
7
+ export declare function install(options?: InstallOptions): Promise<InstallResult>;
8
+ export { Config, Rule, Rules, RuleMetadata, RuleContent, RuleCollection, } from "./types";
package/dist/api.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
7
+ * @param options Install options
8
+ * @returns Result of the install operation
9
+ */
10
+ async function install(options = {}) {
11
+ return (0, install_1.install)(options);
12
+ }
@@ -20,11 +20,10 @@ function initCommand() {
20
20
  }
21
21
  try {
22
22
  fs_extra_1.default.writeJsonSync(configPath, defaultConfig, { spaces: 2 });
23
- console.log(chalk_1.default.green("Configuration file created successfully!"));
24
23
  console.log(`Configuration file location: ${chalk_1.default.blue(configPath)}`);
25
24
  console.log(`\nNext steps:`);
26
- console.log(` 1. Edit ${chalk_1.default.blue("aicm.json")} to configure your rules`);
27
- console.log(` 2. Run ${chalk_1.default.blue("npx aicm install")} to install rules`);
25
+ console.log(` 1. Edit ${chalk_1.default.blue("aicm.json")} to configure your rules & presets`);
26
+ console.log(` 2. Run ${chalk_1.default.blue("npx aicm install")} to install rules & mcps`);
28
27
  }
29
28
  catch (error) {
30
29
  console.error(chalk_1.default.red("Error creating configuration file:"), error);
@@ -1 +1,42 @@
1
+ import { Config } from "../types";
2
+ /**
3
+ * Options for the installCore function
4
+ */
5
+ export interface InstallOptions {
6
+ /**
7
+ * Base directory to use instead of process.cwd()
8
+ */
9
+ cwd?: string;
10
+ /**
11
+ * Custom config object to use instead of loading from file
12
+ */
13
+ config?: Config;
14
+ /**
15
+ * Whether to log progress to console
16
+ */
17
+ silent?: boolean;
18
+ }
19
+ /**
20
+ * Result of the install operation
21
+ */
22
+ export interface InstallResult {
23
+ /**
24
+ * Whether the operation was successful
25
+ */
26
+ success: boolean;
27
+ /**
28
+ * Error message if the operation failed
29
+ */
30
+ error?: string;
31
+ /**
32
+ * Number of rules installed
33
+ */
34
+ installedRuleCount: number;
35
+ }
36
+ /**
37
+ * Core implementation of the rule installation logic
38
+ * @param options Install options
39
+ * @returns Result of the install operation
40
+ */
41
+ export declare function install(options?: InstallOptions): Promise<InstallResult>;
1
42
  export declare function installCommand(): Promise<void>;
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.install = install;
6
7
  exports.installCommand = installCommand;
7
8
  const chalk_1 = __importDefault(require("chalk"));
8
9
  const config_1 = require("../utils/config");
@@ -11,13 +12,19 @@ const rule_collector_1 = require("../utils/rule-collector");
11
12
  const rule_writer_1 = require("../utils/rule-writer");
12
13
  const fs_extra_1 = __importDefault(require("fs-extra"));
13
14
  const node_path_1 = __importDefault(require("node:path"));
14
- function writeMcpServersToTargets(mcpServers, ides) {
15
+ /**
16
+ * Write MCP servers configuration to IDE targets
17
+ * @param mcpServers The MCP servers configuration
18
+ * @param ides The IDEs to write to
19
+ * @param cwd The current working directory
20
+ */
21
+ function writeMcpServersToTargets(mcpServers, ides, cwd) {
15
22
  if (!mcpServers)
16
23
  return;
17
24
  for (const ide of ides) {
18
25
  let mcpPath = null;
19
26
  if (ide === "cursor") {
20
- mcpPath = node_path_1.default.join(process.cwd(), ".cursor", "mcp.json");
27
+ mcpPath = node_path_1.default.join(cwd, ".cursor", "mcp.json");
21
28
  fs_extra_1.default.ensureDirSync(node_path_1.default.dirname(mcpPath));
22
29
  }
23
30
  // Windsurf does not support project mcpServers, so skip
@@ -26,37 +33,59 @@ function writeMcpServersToTargets(mcpServers, ides) {
26
33
  }
27
34
  }
28
35
  }
29
- async function installCommand() {
36
+ /**
37
+ * Core implementation of the rule installation logic
38
+ * @param options Install options
39
+ * @returns Result of the install operation
40
+ */
41
+ async function install(options = {}) {
42
+ const cwd = options.cwd || process.cwd();
43
+ const silent = options.silent || false;
44
+ const log = silent ? () => { } : console.log;
45
+ const error = silent ? () => { } : console.error;
30
46
  try {
47
+ // Save original process.cwd() and change to the specified cwd
48
+ const originalCwd = process.cwd();
49
+ if (cwd !== originalCwd) {
50
+ process.chdir(cwd);
51
+ }
31
52
  // Initialize rule collection
32
53
  const ruleCollection = (0, rule_collector_1.initRuleCollection)();
33
- // Load configuration
34
- const config = (0, config_1.getConfig)();
35
- // If config doesn't exist, print error and exit
54
+ // Use provided config or load from file
55
+ const config = options.config || (0, config_1.getConfig)();
56
+ // If config doesn't exist, return error
36
57
  if (!config) {
37
- console.error(chalk_1.default.red("Configuration file not found! Please run 'npx aicm init' to create one."));
38
- process.exit(1);
58
+ error("Configuration file not found!");
59
+ // Restore original cwd
60
+ if (cwd !== originalCwd) {
61
+ process.chdir(originalCwd);
62
+ }
63
+ return {
64
+ success: false,
65
+ error: "Configuration file not found!",
66
+ installedRuleCount: 0,
67
+ };
39
68
  }
40
69
  // Check if rules are defined (either directly or through presets)
41
70
  if (!config.rules || Object.keys(config.rules).length === 0) {
42
71
  // If there are no presets defined either, show a message
43
72
  if (!config.presets || config.presets.length === 0) {
44
- console.log(chalk_1.default.yellow("No rules defined in configuration."));
45
- console.log(`Edit your ${chalk_1.default.blue("aicm.json")} file to add rules.`);
46
- return;
47
- }
48
- }
49
- if (config.presets && config.presets.length > 0) {
50
- const hasValidPresets = true;
51
- // If no valid presets and no direct rules, exit
52
- if (!hasValidPresets &&
53
- (!config.rules || Object.keys(config.rules).length === 0)) {
54
- console.log(chalk_1.default.yellow("\nNo valid rules found in configuration or presets."));
55
- return;
73
+ error("No rules defined in configuration.");
74
+ // Restore original cwd
75
+ if (cwd !== originalCwd) {
76
+ process.chdir(originalCwd);
77
+ }
78
+ return {
79
+ success: false,
80
+ error: "No rules defined in configuration.",
81
+ installedRuleCount: 0,
82
+ };
56
83
  }
57
84
  }
58
85
  // Process each rule
59
86
  let hasErrors = false;
87
+ const errorMessages = [];
88
+ let installedRuleCount = 0;
60
89
  for (const [name, source] of Object.entries(config.rules)) {
61
90
  if (source === false)
62
91
  continue; // skip canceled rules
@@ -75,20 +104,32 @@ async function installCommand() {
75
104
  ruleContent = (0, rule_collector_1.collectLocalRule)(name, source, ruleBasePath);
76
105
  break;
77
106
  default:
78
- console.log(chalk_1.default.yellow(`Unknown rule type: ${ruleType}`));
107
+ error(`Unknown rule type: ${ruleType}`);
108
+ errorMessages.push(`Unknown rule type: ${ruleType}`);
79
109
  continue;
80
110
  }
81
111
  // Add rule to collection
82
112
  (0, rule_collector_1.addRuleToCollection)(ruleCollection, ruleContent, config.ides);
113
+ installedRuleCount++;
83
114
  }
84
- catch (error) {
115
+ catch (e) {
85
116
  hasErrors = true;
86
- console.error(chalk_1.default.red(`Error processing rule ${name}: ${error instanceof Error ? error.message : String(error)}`));
117
+ const errorMessage = `Error processing rule ${name}: ${e instanceof Error ? e.message : String(e)}`;
118
+ error(errorMessage);
119
+ errorMessages.push(errorMessage);
87
120
  }
88
121
  }
89
122
  // If there were errors, exit with error
90
123
  if (hasErrors) {
91
- throw new Error("One or more rules failed to process");
124
+ // Restore original cwd
125
+ if (cwd !== originalCwd) {
126
+ process.chdir(originalCwd);
127
+ }
128
+ return {
129
+ success: false,
130
+ error: errorMessages.join("; "),
131
+ installedRuleCount,
132
+ };
92
133
  }
93
134
  // Write all collected rules to their targets
94
135
  (0, rule_writer_1.writeRulesToTargets)(ruleCollection);
@@ -96,9 +137,39 @@ async function installCommand() {
96
137
  if (config.mcpServers) {
97
138
  // Filter out canceled servers
98
139
  const filteredMcpServers = Object.fromEntries(Object.entries(config.mcpServers).filter(([, v]) => v !== false));
99
- writeMcpServersToTargets(filteredMcpServers, config.ides);
140
+ writeMcpServersToTargets(filteredMcpServers, config.ides, cwd);
141
+ }
142
+ log("Rules installation completed");
143
+ // Restore original cwd
144
+ if (cwd !== originalCwd) {
145
+ process.chdir(originalCwd);
146
+ }
147
+ return {
148
+ success: true,
149
+ installedRuleCount,
150
+ };
151
+ }
152
+ catch (e) {
153
+ const errorMessage = `Error during rule installation: ${e instanceof Error ? e.message : String(e)}`;
154
+ error(errorMessage);
155
+ // If cwd was changed, restore it
156
+ if (cwd !== process.cwd()) {
157
+ process.chdir(cwd);
158
+ }
159
+ return {
160
+ success: false,
161
+ error: errorMessage,
162
+ installedRuleCount: 0,
163
+ };
164
+ }
165
+ }
166
+ async function installCommand() {
167
+ try {
168
+ const result = await install({ silent: false });
169
+ if (!result.success) {
170
+ console.error(chalk_1.default.red(result.error));
171
+ process.exit(1);
100
172
  }
101
- console.log(chalk_1.default.green("\nRules installation completed!"));
102
173
  }
103
174
  catch (error) {
104
175
  console.error(chalk_1.default.red(`Error during rule installation: ${error instanceof Error ? error.message : String(error)}`));
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "aicm",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "A TypeScript CLI tool for managing AI IDE rules across different projects and teams",
5
- "main": "dist/index.js",
5
+ "main": "dist/api.js",
6
+ "types": "dist/api.d.ts",
6
7
  "bin": {
7
8
  "aicm": "./dist/index.js"
8
9
  },