aicm 0.12.2 → 0.13.1

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.
Files changed (37) hide show
  1. package/README.md +11 -10
  2. package/dist/api.d.ts +1 -1
  3. package/dist/bin/aicm.d.ts +2 -0
  4. package/dist/bin/aicm.js +5 -0
  5. package/dist/cli.d.ts +2 -0
  6. package/dist/cli.js +91 -0
  7. package/dist/commands/init.js +0 -3
  8. package/dist/commands/install/install-package.d.ts +53 -0
  9. package/dist/commands/install/install-package.js +122 -0
  10. package/dist/commands/install/install-single-package.d.ts +53 -0
  11. package/dist/commands/install/install-single-package.js +139 -0
  12. package/dist/commands/install/install-workspaces.d.ts +9 -0
  13. package/dist/commands/install/install-workspaces.js +172 -0
  14. package/dist/commands/install.d.ts +2 -48
  15. package/dist/commands/install.js +28 -202
  16. package/dist/commands/list.d.ts +1 -1
  17. package/dist/commands/list.js +2 -2
  18. package/dist/commands/workspaces/workspaces-install.js +2 -0
  19. package/dist/index.js +0 -0
  20. package/dist/types/index.d.ts +2 -1
  21. package/dist/utils/config.d.ts +3 -3
  22. package/dist/utils/config.js +17 -12
  23. package/dist/utils/working-directory.d.ts +5 -0
  24. package/dist/utils/working-directory.js +21 -0
  25. package/package.json +7 -4
  26. package/dist/commands/monorepo/discovery.d.ts +0 -7
  27. package/dist/commands/monorepo/discovery.js +0 -50
  28. package/dist/commands/monorepo/installer.d.ts +0 -9
  29. package/dist/commands/monorepo/installer.js +0 -70
  30. package/dist/commands/monorepo/monorepo-install.d.ts +0 -9
  31. package/dist/commands/monorepo/monorepo-install.js +0 -46
  32. package/dist/commands/monorepo/types.d.ts +0 -1
  33. package/dist/commands/monorepo/types.js +0 -17
  34. package/dist/utils/package-detector.d.ts +0 -6
  35. package/dist/utils/package-detector.js +0 -25
  36. package/dist/utils/windsurf-writer.d.ts +0 -15
  37. package/dist/utils/windsurf-writer.js +0 -137
package/README.md CHANGED
@@ -157,10 +157,12 @@ To prevent [prompt-injection](https://en.wikipedia.org/wiki/Prompt_injection), u
157
157
 
158
158
  aicm supports workspaces by automatically discovering and installing configurations across multiple packages in your repository.
159
159
 
160
- To enable workspaces mode, use the `--workspaces` flag:
160
+ To enable workspaces mode, set the `workspaces` property to `true` in your root `aicm.json`:
161
161
 
162
- ```bash
163
- npx aicm install --workspaces
162
+ ```json
163
+ {
164
+ "workspaces": true
165
+ }
164
166
  ```
165
167
 
166
168
  This will:
@@ -175,6 +177,7 @@ Each directory containing an `aicm.json` file is treated as a separate package w
175
177
  For example, in a workspace structure like:
176
178
 
177
179
  ```
180
+ ├── aicm.json (with "workspaces": true)
178
181
  ├── packages/
179
182
  │ ├── frontend/
180
183
  │ │ └── aicm.json
@@ -185,7 +188,7 @@ For example, in a workspace structure like:
185
188
  └── aicm.json
186
189
  ```
187
190
 
188
- Running `npx aicm install --workspaces` will install rules for each package in their respective directories:
191
+ Running `npx aicm install` will install rules for each package in their respective directories:
189
192
 
190
193
  - `packages/frontend/.cursor/rules/aicm/`
191
194
  - `packages/backend/.cursor/rules/aicm/`
@@ -270,8 +273,6 @@ The key becomes the base namespace for discovered files:
270
273
 
271
274
  - Preset files should contain a `rules` and `mcpServers` objects with the same structure as the main configuration.
272
275
 
273
- - **installOnCI**: Boolean flag (default: `false`) that controls whether installation should proceed in CI environments. When set to `true`, rules will be installed even in CI environments.
274
-
275
276
  ### MCP Server Installation
276
277
 
277
278
  - **Cursor**: MCP server configs are written to `.cursor/mcp.json` (see Cursor docs for latest path).
@@ -320,6 +321,8 @@ Initializes a new configuration file in your current directory.
320
321
  npx aicm init
321
322
  ```
322
323
 
324
+ Edit this file to add your rules, presets, or other settings.
325
+
323
326
  ### `install`
324
327
 
325
328
  Installs all rules and MCPs configured in your `aicm.json`.
@@ -331,8 +334,7 @@ npx aicm install
331
334
  Options:
332
335
 
333
336
  - `--ci`: run in CI environments (default: `false`)
334
- - `--workspaces`: enable workspaces mode to discover and install configurations across multiple packages
335
- - `--verbose`: show detailed output during installation
337
+ - `--verbose`: show detailed output and stack traces for debugging
336
338
 
337
339
  ## Node.js API
338
340
 
@@ -377,8 +379,7 @@ Installs rules and MCP servers based on configuration.
377
379
  - `cwd`: Base directory to use instead of `process.cwd()`
378
380
  - `config`: Custom config object to use instead of loading from file
379
381
  - `installOnCI`: Run installation on CI environments (default: `false`)
380
- - `workspaces`: Enable workspaces mode (default: `false`)
381
- - `verbose`: Show verbose output during installation (default: `false`)
382
+ - `verbose`: Show verbose output and stack traces for debugging (default: `false`)
382
383
 
383
384
  **Returns:**
384
385
 
package/dist/api.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { InstallOptions, InstallResult } from "./commands/install";
1
+ import { InstallOptions, InstallResult } from "./commands/install/install-package";
2
2
  /**
3
3
  * Install AICM rules based on configuration
4
4
  * @param options Installation options
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const cli_1 = require("../cli");
5
+ (0, cli_1.runCli)();
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export declare function runCli(): Promise<void>;
package/dist/cli.js ADDED
@@ -0,0 +1,91 @@
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.runCli = runCli;
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 runCli() {
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")} - A CLI tool for managing AI IDE configurations
63
+
64
+ ${chalk_1.default.bold("USAGE")}
65
+ $ aicm [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 init
80
+ $ aicm install
81
+ $ aicm list
82
+ `);
83
+ }
84
+ function logError(error, verbose = false) {
85
+ if (verbose && error instanceof Error && error.stack) {
86
+ console.error(chalk_1.default.red(error.stack));
87
+ }
88
+ else {
89
+ console.error(chalk_1.default.red(error instanceof Error ? error.message : String(error)));
90
+ }
91
+ }
@@ -8,10 +8,7 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const chalk_1 = __importDefault(require("chalk"));
10
10
  const defaultConfig = {
11
- ides: ["cursor"],
12
11
  rules: {},
13
- mcpServers: {},
14
- installOnCI: false,
15
12
  };
16
13
  function initCommand() {
17
14
  const configPath = path_1.default.join(process.cwd(), "aicm.json");
@@ -0,0 +1,53 @@
1
+ import { NormalizedConfig } from "../../types";
2
+ /**
3
+ * Options for the install functions
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?: NormalizedConfig;
14
+ /**
15
+ * allow installation on CI environments
16
+ */
17
+ installOnCI?: boolean;
18
+ /**
19
+ * Show verbose output during installation
20
+ */
21
+ verbose?: boolean;
22
+ }
23
+ /**
24
+ * Result of the install operation
25
+ */
26
+ export interface InstallResult {
27
+ /**
28
+ * Whether the operation was successful
29
+ */
30
+ success: boolean;
31
+ /**
32
+ * Error message if the operation failed
33
+ */
34
+ error?: string;
35
+ /**
36
+ * Error stack trace for debugging (when available)
37
+ */
38
+ errorStack?: string;
39
+ /**
40
+ * Number of rules installed
41
+ */
42
+ installedRuleCount: number;
43
+ /**
44
+ * Number of packages installed
45
+ */
46
+ packagesCount: number;
47
+ }
48
+ /**
49
+ * Install rules for a single package (used within workspaces and standalone installs)
50
+ * @param options Install options
51
+ * @returns Result of the install operation
52
+ */
53
+ export declare function installPackage(options?: InstallOptions): Promise<InstallResult>;
@@ -0,0 +1,122 @@
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.installPackage = installPackage;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const config_1 = require("../../utils/config");
9
+ const rule_detector_1 = require("../../utils/rule-detector");
10
+ const working_directory_1 = require("../../utils/working-directory");
11
+ const rule_collector_1 = require("../../utils/rule-collector");
12
+ const rule_writer_1 = require("../../utils/rule-writer");
13
+ const mcp_writer_1 = require("../../utils/mcp-writer");
14
+ const glob_handler_1 = require("../../utils/glob-handler");
15
+ /**
16
+ * Install rules for a single package (used within workspaces and standalone installs)
17
+ * @param options Install options
18
+ * @returns Result of the install operation
19
+ */
20
+ async function installPackage(options = {}) {
21
+ const cwd = options.cwd || process.cwd();
22
+ return (0, working_directory_1.withWorkingDirectory)(cwd, async () => {
23
+ const config = options.config || (await (0, config_1.getConfig)());
24
+ const ruleCollection = (0, rule_collector_1.initRuleCollection)();
25
+ if (!config) {
26
+ return {
27
+ success: false,
28
+ error: "Configuration file not found",
29
+ installedRuleCount: 0,
30
+ packagesCount: 0,
31
+ };
32
+ }
33
+ // Check if rules are defined (either directly or through presets)
34
+ if (!config.rules || Object.keys(config.rules).length === 0) {
35
+ // If there are no presets defined either, show a message
36
+ if (!config.presets || config.presets.length === 0) {
37
+ return {
38
+ success: false,
39
+ error: "No rules defined in configuration",
40
+ installedRuleCount: 0,
41
+ packagesCount: 0,
42
+ };
43
+ }
44
+ }
45
+ let expandedRules;
46
+ try {
47
+ const expansion = await (0, glob_handler_1.expandRulesGlobPatterns)(config.rules, cwd);
48
+ expandedRules = expansion.expandedRules;
49
+ if (options.verbose) {
50
+ for (const [expandedKey, originalPattern] of Object.entries(expansion.globSources)) {
51
+ console.log(chalk_1.default.gray(` Pattern "${originalPattern}" → ${expandedKey}`));
52
+ }
53
+ }
54
+ }
55
+ catch (error) {
56
+ const errorMessage = `Error expanding glob patterns: ${error instanceof Error ? error.message : String(error)}`;
57
+ return {
58
+ success: false,
59
+ error: errorMessage,
60
+ errorStack: error instanceof Error ? error.stack : undefined,
61
+ installedRuleCount: 0,
62
+ packagesCount: 0,
63
+ };
64
+ }
65
+ let hasErrors = false;
66
+ const errorMessages = [];
67
+ let firstErrorStack;
68
+ let installedRuleCount = 0;
69
+ for (const [name, source] of Object.entries(expandedRules)) {
70
+ const ruleType = (0, rule_detector_1.detectRuleType)(source);
71
+ const ruleBasePath = (0, config_1.getRuleSource)(config, name);
72
+ const originalPresetPath = (0, config_1.getOriginalPresetPath)(config, name);
73
+ try {
74
+ let ruleContent;
75
+ switch (ruleType) {
76
+ case "npm":
77
+ ruleContent = (0, rule_collector_1.collectNpmRule)(name, source);
78
+ break;
79
+ case "local":
80
+ ruleContent = (0, rule_collector_1.collectLocalRule)(name, source, ruleBasePath);
81
+ break;
82
+ default:
83
+ errorMessages.push(`Unknown rule type: ${ruleType}`);
84
+ continue;
85
+ }
86
+ if (originalPresetPath) {
87
+ ruleContent.presetPath = originalPresetPath;
88
+ }
89
+ (0, rule_collector_1.addRuleToCollection)(ruleCollection, ruleContent, config.ides);
90
+ installedRuleCount++;
91
+ }
92
+ catch (e) {
93
+ hasErrors = true;
94
+ const errorMessage = `Error processing rule ${name}: ${e instanceof Error ? e.message : String(e)}`;
95
+ errorMessages.push(errorMessage);
96
+ // Keep the first error stack trace
97
+ if (!firstErrorStack && e instanceof Error && e.stack) {
98
+ firstErrorStack = e.stack;
99
+ }
100
+ }
101
+ }
102
+ if (hasErrors) {
103
+ return {
104
+ success: false,
105
+ error: errorMessages.join("; "),
106
+ errorStack: firstErrorStack,
107
+ installedRuleCount,
108
+ packagesCount: 0,
109
+ };
110
+ }
111
+ (0, rule_writer_1.writeRulesToTargets)(ruleCollection);
112
+ if (config.mcpServers) {
113
+ const filteredMcpServers = Object.fromEntries(Object.entries(config.mcpServers).filter(([, v]) => v !== false));
114
+ (0, mcp_writer_1.writeMcpServersToTargets)(filteredMcpServers, config.ides, cwd);
115
+ }
116
+ return {
117
+ success: true,
118
+ installedRuleCount,
119
+ packagesCount: 1,
120
+ };
121
+ });
122
+ }
@@ -0,0 +1,53 @@
1
+ import { NormalizedConfig } from "../../types";
2
+ /**
3
+ * Options for the install functions
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?: NormalizedConfig;
14
+ /**
15
+ * allow installation on CI environments
16
+ */
17
+ installOnCI?: boolean;
18
+ /**
19
+ * Show verbose output during installation
20
+ */
21
+ verbose?: boolean;
22
+ }
23
+ /**
24
+ * Result of the install operation
25
+ */
26
+ export interface InstallResult {
27
+ /**
28
+ * Whether the operation was successful
29
+ */
30
+ success: boolean;
31
+ /**
32
+ * Error message if the operation failed
33
+ */
34
+ error?: string;
35
+ /**
36
+ * Error stack trace for debugging (when available)
37
+ */
38
+ errorStack?: string;
39
+ /**
40
+ * Number of rules installed
41
+ */
42
+ installedRuleCount: number;
43
+ /**
44
+ * Number of packages installed
45
+ */
46
+ packagesCount: number;
47
+ }
48
+ /**
49
+ * Core single package installation logic
50
+ * @param options Install options
51
+ * @returns Result of the install operation
52
+ */
53
+ export declare function installSinglePackage(options?: InstallOptions): Promise<InstallResult>;
@@ -0,0 +1,139 @@
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.installSinglePackage = installSinglePackage;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const config_1 = require("../../utils/config");
9
+ const rule_detector_1 = require("../../utils/rule-detector");
10
+ const rule_collector_1 = require("../../utils/rule-collector");
11
+ const rule_writer_1 = require("../../utils/rule-writer");
12
+ const mcp_writer_1 = require("../../utils/mcp-writer");
13
+ const glob_handler_1 = require("../../utils/glob-handler");
14
+ /**
15
+ * Helper function to execute a function within a specific working directory
16
+ * and ensure the original directory is always restored
17
+ */
18
+ async function withWorkingDirectory(targetDir, fn) {
19
+ const originalCwd = process.cwd();
20
+ if (targetDir !== originalCwd) {
21
+ process.chdir(targetDir);
22
+ }
23
+ try {
24
+ return await fn();
25
+ }
26
+ finally {
27
+ if (targetDir !== originalCwd) {
28
+ process.chdir(originalCwd);
29
+ }
30
+ }
31
+ }
32
+ /**
33
+ * Core single package installation logic
34
+ * @param options Install options
35
+ * @returns Result of the install operation
36
+ */
37
+ async function installSinglePackage(options = {}) {
38
+ const cwd = options.cwd || process.cwd();
39
+ return withWorkingDirectory(cwd, async () => {
40
+ const config = options.config || (0, config_1.getConfig)();
41
+ const ruleCollection = (0, rule_collector_1.initRuleCollection)();
42
+ if (!config) {
43
+ return {
44
+ success: false,
45
+ error: "Configuration file not found",
46
+ installedRuleCount: 0,
47
+ packagesCount: 0,
48
+ };
49
+ }
50
+ // Check if rules are defined (either directly or through presets)
51
+ if (!config.rules || Object.keys(config.rules).length === 0) {
52
+ // If there are no presets defined either, show a message
53
+ if (!config.presets || config.presets.length === 0) {
54
+ return {
55
+ success: false,
56
+ error: "No rules defined in configuration",
57
+ installedRuleCount: 0,
58
+ packagesCount: 0,
59
+ };
60
+ }
61
+ }
62
+ let expandedRules;
63
+ try {
64
+ const expansion = await (0, glob_handler_1.expandRulesGlobPatterns)(config.rules, cwd);
65
+ expandedRules = expansion.expandedRules;
66
+ if (options.verbose) {
67
+ for (const [expandedKey, originalPattern] of Object.entries(expansion.globSources)) {
68
+ console.log(chalk_1.default.gray(` Pattern "${originalPattern}" → ${expandedKey}`));
69
+ }
70
+ }
71
+ }
72
+ catch (error) {
73
+ const errorMessage = `Error expanding glob patterns: ${error instanceof Error ? error.message : String(error)}`;
74
+ return {
75
+ success: false,
76
+ error: errorMessage,
77
+ errorStack: error instanceof Error ? error.stack : undefined,
78
+ installedRuleCount: 0,
79
+ packagesCount: 0,
80
+ };
81
+ }
82
+ let hasErrors = false;
83
+ const errorMessages = [];
84
+ let firstErrorStack;
85
+ let installedRuleCount = 0;
86
+ for (const [name, source] of Object.entries(expandedRules)) {
87
+ const ruleType = (0, rule_detector_1.detectRuleType)(source);
88
+ const ruleBasePath = (0, config_1.getRuleSource)(config, name);
89
+ const originalPresetPath = (0, config_1.getOriginalPresetPath)(config, name);
90
+ try {
91
+ let ruleContent;
92
+ switch (ruleType) {
93
+ case "npm":
94
+ ruleContent = (0, rule_collector_1.collectNpmRule)(name, source);
95
+ break;
96
+ case "local":
97
+ ruleContent = (0, rule_collector_1.collectLocalRule)(name, source, ruleBasePath);
98
+ break;
99
+ default:
100
+ errorMessages.push(`Unknown rule type: ${ruleType}`);
101
+ continue;
102
+ }
103
+ if (originalPresetPath) {
104
+ ruleContent.presetPath = originalPresetPath;
105
+ }
106
+ (0, rule_collector_1.addRuleToCollection)(ruleCollection, ruleContent, config.ides);
107
+ installedRuleCount++;
108
+ }
109
+ catch (e) {
110
+ hasErrors = true;
111
+ const errorMessage = `Error processing rule ${name}: ${e instanceof Error ? e.message : String(e)}`;
112
+ errorMessages.push(errorMessage);
113
+ // Keep the first error stack trace
114
+ if (!firstErrorStack && e instanceof Error && e.stack) {
115
+ firstErrorStack = e.stack;
116
+ }
117
+ }
118
+ }
119
+ if (hasErrors) {
120
+ return {
121
+ success: false,
122
+ error: errorMessages.join("; "),
123
+ errorStack: firstErrorStack,
124
+ installedRuleCount,
125
+ packagesCount: 0,
126
+ };
127
+ }
128
+ (0, rule_writer_1.writeRulesToTargets)(ruleCollection);
129
+ if (config.mcpServers) {
130
+ const filteredMcpServers = Object.fromEntries(Object.entries(config.mcpServers).filter(([, v]) => v !== false));
131
+ (0, mcp_writer_1.writeMcpServersToTargets)(filteredMcpServers, config.ides, cwd);
132
+ }
133
+ return {
134
+ success: true,
135
+ installedRuleCount,
136
+ packagesCount: 1,
137
+ };
138
+ });
139
+ }
@@ -0,0 +1,9 @@
1
+ import { InstallResult } from "./install-package";
2
+ /**
3
+ * Install rules across multiple packages in a workspace
4
+ * @param cwd The current working directory
5
+ * @param installOnCI Whether to install on CI environments
6
+ * @param verbose Whether to show verbose output
7
+ * @returns Result of the install operation
8
+ */
9
+ export declare function installWorkspaces(cwd: string, installOnCI: boolean, verbose?: boolean): Promise<InstallResult>;