aicm 0.12.1 → 0.13.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.
Files changed (36) hide show
  1. package/README.md +26 -11
  2. package/dist/api.d.ts +2 -2
  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/workspaces/workspaces-install.js +2 -0
  17. package/dist/index.js +0 -0
  18. package/dist/types/index.d.ts +9 -4
  19. package/dist/utils/config.d.ts +7 -6
  20. package/dist/utils/config.js +20 -8
  21. package/dist/utils/mcp-writer.d.ts +3 -3
  22. package/dist/utils/working-directory.d.ts +5 -0
  23. package/dist/utils/working-directory.js +21 -0
  24. package/package.json +20 -19
  25. package/dist/commands/monorepo/discovery.d.ts +0 -7
  26. package/dist/commands/monorepo/discovery.js +0 -50
  27. package/dist/commands/monorepo/installer.d.ts +0 -9
  28. package/dist/commands/monorepo/installer.js +0 -70
  29. package/dist/commands/monorepo/monorepo-install.d.ts +0 -9
  30. package/dist/commands/monorepo/monorepo-install.js +0 -46
  31. package/dist/commands/monorepo/types.d.ts +0 -1
  32. package/dist/commands/monorepo/types.js +0 -17
  33. package/dist/utils/package-detector.d.ts +0 -6
  34. package/dist/utils/package-detector.js +0 -25
  35. package/dist/utils/windsurf-writer.d.ts +0 -15
  36. package/dist/utils/windsurf-writer.js +0 -137
@@ -0,0 +1,172 @@
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.installWorkspaces = installWorkspaces;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const node_child_process_1 = require("node:child_process");
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const config_1 = require("../../utils/config");
11
+ const working_directory_1 = require("../../utils/working-directory");
12
+ const install_package_1 = require("./install-package");
13
+ /**
14
+ * Discover aicm.json files using git ls-files
15
+ * @param rootDir The root directory to search from
16
+ * @returns Array of aicm.json file paths
17
+ */
18
+ function findAicmFiles(rootDir) {
19
+ const output = (0, node_child_process_1.execSync)("git ls-files --cached --others --exclude-standard aicm.json **/aicm.json", {
20
+ cwd: rootDir,
21
+ encoding: "utf8",
22
+ });
23
+ return output
24
+ .trim()
25
+ .split("\n")
26
+ .filter(Boolean)
27
+ .map((file) => node_path_1.default.resolve(rootDir, file));
28
+ }
29
+ /**
30
+ * Discover all packages with aicm configurations
31
+ * @param rootDir The root directory to search from
32
+ * @returns Array of discovered packages
33
+ */
34
+ async function discoverPackagesWithAicm(rootDir) {
35
+ const aicmFiles = findAicmFiles(rootDir);
36
+ const packages = [];
37
+ for (const aicmFile of aicmFiles) {
38
+ const packageDir = node_path_1.default.dirname(aicmFile);
39
+ const relativePath = node_path_1.default.relative(rootDir, packageDir);
40
+ // Normalize to forward slashes for cross-platform compatibility
41
+ const normalizedRelativePath = relativePath.replace(/\\/g, "/");
42
+ const config = (0, config_1.getConfig)(packageDir);
43
+ if (config) {
44
+ packages.push({
45
+ relativePath: normalizedRelativePath || ".",
46
+ absolutePath: packageDir,
47
+ config,
48
+ });
49
+ }
50
+ }
51
+ // Sort packages by relativePath for deterministic order
52
+ return packages.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
53
+ }
54
+ /**
55
+ * Install aicm configurations for all packages in a workspace
56
+ * @param packages The packages to install configurations for
57
+ * @param options Install options
58
+ * @returns Result of the workspace installation
59
+ */
60
+ async function installWorkspacesPackages(packages, options = {}) {
61
+ const results = [];
62
+ let totalRuleCount = 0;
63
+ // Install packages sequentially for now (can be parallelized later)
64
+ for (const pkg of packages) {
65
+ const packagePath = pkg.absolutePath;
66
+ try {
67
+ const result = await (0, install_package_1.installPackage)({
68
+ ...options,
69
+ cwd: packagePath,
70
+ });
71
+ totalRuleCount += result.installedRuleCount;
72
+ results.push({
73
+ path: pkg.relativePath,
74
+ success: result.success,
75
+ error: result.error,
76
+ errorStack: result.errorStack,
77
+ installedRuleCount: result.installedRuleCount,
78
+ });
79
+ }
80
+ catch (error) {
81
+ const errorMessage = error instanceof Error ? error.message : String(error);
82
+ results.push({
83
+ path: pkg.relativePath,
84
+ success: false,
85
+ error: errorMessage,
86
+ errorStack: error instanceof Error ? error.stack : undefined,
87
+ installedRuleCount: 0,
88
+ });
89
+ }
90
+ }
91
+ const failedPackages = results.filter((r) => !r.success);
92
+ return {
93
+ success: failedPackages.length === 0,
94
+ packages: results,
95
+ totalRuleCount,
96
+ };
97
+ }
98
+ /**
99
+ * Install rules across multiple packages in a workspace
100
+ * @param cwd The current working directory
101
+ * @param installOnCI Whether to install on CI environments
102
+ * @param verbose Whether to show verbose output
103
+ * @returns Result of the install operation
104
+ */
105
+ async function installWorkspaces(cwd, installOnCI, verbose = false) {
106
+ return (0, working_directory_1.withWorkingDirectory)(cwd, async () => {
107
+ if (verbose) {
108
+ console.log(chalk_1.default.blue("🔍 Discovering packages..."));
109
+ }
110
+ const allPackages = await discoverPackagesWithAicm(cwd);
111
+ const packages = allPackages.filter((pkg) => {
112
+ const isRoot = pkg.relativePath === ".";
113
+ if (!isRoot)
114
+ return true;
115
+ // For root directories, only keep if it has rules or presets
116
+ const hasRules = pkg.config.rules && Object.keys(pkg.config.rules).length > 0;
117
+ const hasPresets = pkg.config.presets && pkg.config.presets.length > 0;
118
+ return hasRules || hasPresets;
119
+ });
120
+ if (packages.length === 0) {
121
+ return {
122
+ success: false,
123
+ error: "No packages with aicm configurations found",
124
+ installedRuleCount: 0,
125
+ packagesCount: 0,
126
+ };
127
+ }
128
+ if (verbose) {
129
+ console.log(chalk_1.default.blue(`Found ${packages.length} packages with aicm configurations:`));
130
+ packages.forEach((pkg) => {
131
+ console.log(chalk_1.default.gray(` - ${pkg.relativePath}`));
132
+ });
133
+ console.log(chalk_1.default.blue(`📦 Installing configurations...`));
134
+ }
135
+ const result = await installWorkspacesPackages(packages, {
136
+ installOnCI,
137
+ });
138
+ if (verbose) {
139
+ result.packages.forEach((pkg) => {
140
+ if (pkg.success) {
141
+ console.log(chalk_1.default.green(`✅ ${pkg.path} (${pkg.installedRuleCount} rules)`));
142
+ }
143
+ else {
144
+ console.log(chalk_1.default.red(`❌ ${pkg.path}: ${pkg.error}`));
145
+ }
146
+ });
147
+ }
148
+ const failedPackages = result.packages.filter((r) => !r.success);
149
+ if (failedPackages.length > 0) {
150
+ console.log(chalk_1.default.yellow(`Installation completed with errors`));
151
+ if (verbose) {
152
+ console.log(chalk_1.default.green(`Successfully installed: ${result.packages.length - failedPackages.length}/${result.packages.length} packages (${result.totalRuleCount} rules total)`));
153
+ console.log(chalk_1.default.red(`Failed packages: ${failedPackages.map((p) => p.path).join(", ")}`));
154
+ }
155
+ const errorDetails = failedPackages
156
+ .map((p) => `${p.path}: ${p.error}`)
157
+ .join("; ");
158
+ return {
159
+ success: false,
160
+ error: `Package installation failed for ${failedPackages.length} package(s): ${errorDetails}`,
161
+ installedRuleCount: result.totalRuleCount,
162
+ packagesCount: result.packages.length,
163
+ };
164
+ }
165
+ console.log(`Successfully installed ${result.totalRuleCount} rules across ${result.packages.length} packages`);
166
+ return {
167
+ success: true,
168
+ installedRuleCount: result.totalRuleCount,
169
+ packagesCount: result.packages.length,
170
+ };
171
+ });
172
+ }
@@ -1,54 +1,8 @@
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
- * allow installation on CI environments
16
- */
17
- installOnCI?: boolean;
18
- /**
19
- * Enable workspaces mode
20
- */
21
- workspaces?: boolean;
22
- /**
23
- * Show verbose output during installation
24
- */
25
- verbose?: boolean;
26
- }
27
- /**
28
- * Result of the install operation
29
- */
30
- export interface InstallResult {
31
- /**
32
- * Whether the operation was successful
33
- */
34
- success: boolean;
35
- /**
36
- * Error message if the operation failed
37
- */
38
- error?: string;
39
- /**
40
- * Number of rules installed
41
- */
42
- installedRuleCount: number;
43
- /**
44
- * Number of packages installed
45
- */
46
- packagesCount: number;
47
- }
1
+ import { InstallOptions, InstallResult } from "./install/install-package";
48
2
  /**
49
3
  * Core implementation of the rule installation logic
50
4
  * @param options Install options
51
5
  * @returns Result of the install operation
52
6
  */
53
7
  export declare function install(options?: InstallOptions): Promise<InstallResult>;
54
- export declare function installCommand(installOnCI?: boolean, workspaces?: boolean, verbose?: boolean): Promise<void>;
8
+ export declare function installCommand(installOnCI?: boolean, verbose?: boolean): Promise<void>;
@@ -7,32 +7,10 @@ exports.install = install;
7
7
  exports.installCommand = installCommand;
8
8
  const chalk_1 = __importDefault(require("chalk"));
9
9
  const config_1 = require("../utils/config");
10
- const rule_detector_1 = require("../utils/rule-detector");
11
- const rule_collector_1 = require("../utils/rule-collector");
12
- const rule_writer_1 = require("../utils/rule-writer");
13
10
  const ci_info_1 = require("ci-info");
14
- const discovery_1 = require("./workspaces/discovery");
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
- /**
19
- * Helper function to execute a function within a specific working directory
20
- * and ensure the original directory is always restored
21
- */
22
- async function withWorkingDirectory(targetDir, fn) {
23
- const originalCwd = process.cwd();
24
- if (targetDir !== originalCwd) {
25
- process.chdir(targetDir);
26
- }
27
- try {
28
- return await fn();
29
- }
30
- finally {
31
- if (targetDir !== originalCwd) {
32
- process.chdir(originalCwd);
33
- }
34
- }
35
- }
11
+ const working_directory_1 = require("../utils/working-directory");
12
+ const install_package_1 = require("./install/install-package");
13
+ const install_workspaces_1 = require("./install/install-workspaces");
36
14
  /**
37
15
  * Checks if the current environment is a CI environment
38
16
  * This function respects any explicit settings in process.env.CI
@@ -46,64 +24,6 @@ function isInCIEnvironment() {
46
24
  // Fall back to ci-info's detection
47
25
  return ci_info_1.isCI;
48
26
  }
49
- async function handleWorkspacesInstallation(cwd, installOnCI, verbose = false) {
50
- return withWorkingDirectory(cwd, async () => {
51
- if (verbose) {
52
- console.log(chalk_1.default.blue("🔍 Discovering packages..."));
53
- }
54
- const packages = await (0, discovery_1.discoverPackagesWithAicm)(cwd);
55
- if (packages.length === 0) {
56
- return {
57
- success: false,
58
- error: "No packages with aicm configurations found",
59
- installedRuleCount: 0,
60
- packagesCount: 0,
61
- };
62
- }
63
- if (verbose) {
64
- console.log(chalk_1.default.blue(`Found ${packages.length} packages with aicm configurations:`));
65
- packages.forEach((pkg) => {
66
- console.log(chalk_1.default.gray(` - ${pkg.relativePath}`));
67
- });
68
- console.log(chalk_1.default.blue(`📦 Installing configurations...`));
69
- }
70
- const result = await (0, workspaces_install_1.installWorkspacesPackages)(packages, {
71
- installOnCI,
72
- });
73
- if (verbose) {
74
- result.packages.forEach((pkg) => {
75
- if (pkg.success) {
76
- console.log(chalk_1.default.green(`✅ ${pkg.path} (${pkg.installedRuleCount} rules)`));
77
- }
78
- else {
79
- console.log(chalk_1.default.red(`❌ ${pkg.path}: ${pkg.error}`));
80
- }
81
- });
82
- }
83
- const failedPackages = result.packages.filter((r) => !r.success);
84
- if (failedPackages.length > 0) {
85
- console.log(chalk_1.default.yellow(`Installation completed with errors`));
86
- if (verbose) {
87
- console.log(chalk_1.default.green(`Successfully installed: ${result.packages.length - failedPackages.length}/${result.packages.length} packages (${result.totalRuleCount} rules total)`));
88
- console.log(chalk_1.default.red(`Failed packages: ${failedPackages.map((p) => p.path).join(", ")}`));
89
- }
90
- const errorDetails = failedPackages
91
- .map((p) => `${p.path}: ${p.error}`)
92
- .join("; ");
93
- return {
94
- success: false,
95
- error: `Package installation failed for ${failedPackages.length} package(s): ${errorDetails}`,
96
- installedRuleCount: result.totalRuleCount,
97
- packagesCount: result.packages.length,
98
- };
99
- }
100
- return {
101
- success: true,
102
- installedRuleCount: result.totalRuleCount,
103
- packagesCount: result.packages.length,
104
- };
105
- });
106
- }
107
27
  /**
108
28
  * Core implementation of the rule installation logic
109
29
  * @param options Install options
@@ -112,132 +32,38 @@ async function handleWorkspacesInstallation(cwd, installOnCI, verbose = false) {
112
32
  async function install(options = {}) {
113
33
  const cwd = options.cwd || process.cwd();
114
34
  const installOnCI = options.installOnCI === true; // Default to false if not specified
115
- return withWorkingDirectory(cwd, async () => {
116
- if (options.workspaces) {
117
- return await handleWorkspacesInstallation(cwd, installOnCI, options.verbose);
118
- }
119
- const config = options.config || (0, config_1.getConfig)();
120
- const ruleCollection = (0, rule_collector_1.initRuleCollection)();
121
- if (!config) {
122
- return {
123
- success: false,
124
- error: "Configuration file not found",
125
- installedRuleCount: 0,
126
- packagesCount: 0,
127
- };
128
- }
129
- const inCI = isInCIEnvironment();
130
- if (inCI && !installOnCI && !config.installOnCI) {
131
- console.log(chalk_1.default.yellow("Detected CI environment, skipping install."));
132
- return {
133
- success: true,
134
- installedRuleCount: 0,
135
- packagesCount: 0,
136
- };
137
- }
138
- // Check if rules are defined (either directly or through presets)
139
- if (!config.rules || Object.keys(config.rules).length === 0) {
140
- // If there are no presets defined either, show a message
141
- if (!config.presets || config.presets.length === 0) {
142
- return {
143
- success: false,
144
- error: "No rules defined in configuration",
145
- installedRuleCount: 0,
146
- packagesCount: 0,
147
- };
148
- }
149
- }
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
- }
168
- let hasErrors = false;
169
- const errorMessages = [];
170
- let installedRuleCount = 0;
171
- for (const [name, source] of Object.entries(expandedRules)) {
172
- const ruleType = (0, rule_detector_1.detectRuleType)(source);
173
- const ruleBasePath = (0, config_1.getRuleSource)(config, name);
174
- const originalPresetPath = (0, config_1.getOriginalPresetPath)(config, name);
175
- try {
176
- let ruleContent;
177
- switch (ruleType) {
178
- case "npm":
179
- ruleContent = (0, rule_collector_1.collectNpmRule)(name, source);
180
- break;
181
- case "local":
182
- ruleContent = (0, rule_collector_1.collectLocalRule)(name, source, ruleBasePath);
183
- break;
184
- default:
185
- errorMessages.push(`Unknown rule type: ${ruleType}`);
186
- continue;
187
- }
188
- if (originalPresetPath) {
189
- ruleContent.presetPath = originalPresetPath;
190
- }
191
- (0, rule_collector_1.addRuleToCollection)(ruleCollection, ruleContent, config.ides);
192
- installedRuleCount++;
193
- }
194
- catch (e) {
195
- hasErrors = true;
196
- const errorMessage = `Error processing rule ${name}: ${e instanceof Error ? e.message : String(e)}`;
197
- errorMessages.push(errorMessage);
198
- }
199
- }
200
- if (hasErrors) {
201
- return {
202
- success: false,
203
- error: errorMessages.join("; "),
204
- installedRuleCount,
205
- packagesCount: 0,
206
- };
207
- }
208
- (0, rule_writer_1.writeRulesToTargets)(ruleCollection);
209
- if (config.mcpServers) {
210
- const filteredMcpServers = Object.fromEntries(Object.entries(config.mcpServers).filter(([, v]) => v !== false));
211
- (0, mcp_writer_1.writeMcpServersToTargets)(filteredMcpServers, config.ides, cwd);
212
- }
35
+ const inCI = isInCIEnvironment();
36
+ if (inCI && !installOnCI) {
37
+ console.log(chalk_1.default.yellow("Detected CI environment, skipping install."));
213
38
  return {
214
39
  success: true,
215
- installedRuleCount,
216
- packagesCount: 1,
40
+ installedRuleCount: 0,
41
+ packagesCount: 0,
217
42
  };
43
+ }
44
+ return (0, working_directory_1.withWorkingDirectory)(cwd, async () => {
45
+ const config = options.config || (0, config_1.getConfig)();
46
+ if (config === null || config === void 0 ? void 0 : config.workspaces) {
47
+ return await (0, install_workspaces_1.installWorkspaces)(cwd, installOnCI, options.verbose);
48
+ }
49
+ return (0, install_package_1.installPackage)(options);
218
50
  });
219
51
  }
220
- async function installCommand(installOnCI, workspaces, verbose) {
221
- try {
222
- const result = await install({ installOnCI, workspaces, verbose });
223
- if (!result.success) {
224
- console.error(chalk_1.default.red(result.error));
225
- process.exit(1);
52
+ async function installCommand(installOnCI, verbose) {
53
+ const result = await install({ installOnCI, verbose });
54
+ if (!result.success) {
55
+ const error = new Error(result.error);
56
+ if (result.errorStack) {
57
+ error.stack = result.errorStack;
58
+ }
59
+ throw error;
60
+ }
61
+ else {
62
+ if (result.packagesCount > 1) {
63
+ console.log(`Successfully installed ${result.installedRuleCount} rules across ${result.packagesCount} packages`);
226
64
  }
227
65
  else {
228
- if (result.packagesCount > 1) {
229
- console.log(`Successfully installed ${result.installedRuleCount} rules across ${result.packagesCount} packages`);
230
- }
231
- else if (workspaces) {
232
- console.log(`Successfully installed ${result.installedRuleCount} rules across ${result.packagesCount} packages`);
233
- }
234
- else {
235
- console.log("Rules installation completed");
236
- }
66
+ console.log("Rules installation completed");
237
67
  }
238
68
  }
239
- catch (error) {
240
- console.error(chalk_1.default.red(error instanceof Error ? error.message : String(error)));
241
- process.exit(1);
242
- }
243
69
  }
@@ -24,6 +24,7 @@ async function installWorkspacesPackages(packages, options = {}) {
24
24
  path: pkg.relativePath,
25
25
  success: result.success,
26
26
  error: result.error,
27
+ errorStack: result.errorStack,
27
28
  installedRuleCount: result.installedRuleCount,
28
29
  });
29
30
  }
@@ -33,6 +34,7 @@ async function installWorkspacesPackages(packages, options = {}) {
33
34
  path: pkg.relativePath,
34
35
  success: false,
35
36
  error: errorMessage,
37
+ errorStack: error instanceof Error ? error.stack : undefined,
36
38
  installedRuleCount: 0,
37
39
  });
38
40
  }
package/dist/index.js CHANGED
File without changes
@@ -17,11 +17,15 @@ export interface MCPServers {
17
17
  [serverName: string]: MCPServer;
18
18
  }
19
19
  export interface Config {
20
- ides: string[];
21
- rules: Rules;
20
+ ides?: string[];
21
+ rules?: Rules | string;
22
22
  presets?: string[];
23
23
  mcpServers?: MCPServers;
24
- installOnCI?: boolean;
24
+ workspaces?: boolean;
25
+ }
26
+ export interface NormalizedConfig extends Omit<Config, "rules"> {
27
+ ides: string[];
28
+ rules: Rules;
25
29
  }
26
30
  export interface RuleMetadata {
27
31
  type?: string;
@@ -45,7 +49,7 @@ export interface RuleCollection {
45
49
  export interface PackageInfo {
46
50
  relativePath: string;
47
51
  absolutePath: string;
48
- config: Config;
52
+ config: NormalizedConfig;
49
53
  }
50
54
  export interface WorkspacesInstallResult {
51
55
  success: boolean;
@@ -53,6 +57,7 @@ export interface WorkspacesInstallResult {
53
57
  path: string;
54
58
  success: boolean;
55
59
  error?: string;
60
+ errorStack?: string;
56
61
  installedRuleCount: number;
57
62
  }>;
58
63
  totalRuleCount: number;
@@ -1,12 +1,13 @@
1
- import { Config, Rules } from "../types";
1
+ import { Config, NormalizedConfig, Rules } from "../types";
2
2
  export interface RuleMetadata {
3
3
  ruleSources: Record<string, string>;
4
4
  originalPresetPaths: Record<string, string>;
5
5
  }
6
6
  export interface ConfigResult {
7
- config: Config;
7
+ config: NormalizedConfig;
8
8
  metadata: RuleMetadata;
9
9
  }
10
+ export declare function normalizeRules(rules: Rules | string | undefined): Rules;
10
11
  export interface PresetPathInfo {
11
12
  fullPath: string;
12
13
  originalPath: string;
@@ -24,19 +25,19 @@ export declare function loadPreset(presetPath: string, cwd?: string): {
24
25
  * Load the aicm config using cosmiconfigSync, supporting both aicm.json and package.json.
25
26
  * Returns the config object or null if not found.
26
27
  */
27
- export declare function loadAicmConfigCosmiconfig(searchFrom?: string): Config | null;
28
+ export declare function loadAicmConfigCosmiconfig(searchFrom?: string): NormalizedConfig | null;
28
29
  /**
29
30
  * Get the configuration from aicm.json or package.json (using cosmiconfigSync) and merge with any presets
30
31
  */
31
- export declare function getConfig(cwd?: string): Config | null;
32
+ export declare function getConfig(cwd?: string): NormalizedConfig | null;
32
33
  /**
33
34
  * Get the source preset path for a rule if it came from a preset
34
35
  */
35
- export declare function getRuleSource(config: Config, ruleName: string): string | undefined;
36
+ export declare function getRuleSource(config: NormalizedConfig, ruleName: string): string | undefined;
36
37
  /**
37
38
  * Get the original preset path for a rule if it came from a preset
38
39
  */
39
- export declare function getOriginalPresetPath(config: Config, ruleName: string): string | undefined;
40
+ export declare function getOriginalPresetPath(config: NormalizedConfig, ruleName: string): string | undefined;
40
41
  /**
41
42
  * Save the configuration to the aicm.json file
42
43
  */
@@ -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.normalizeRules = normalizeRules;
6
7
  exports.getFullPresetPath = getFullPresetPath;
7
8
  exports.loadPreset = loadPreset;
8
9
  exports.loadAicmConfigCosmiconfig = loadAicmConfigCosmiconfig;
@@ -14,6 +15,14 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
14
15
  const node_path_1 = __importDefault(require("node:path"));
15
16
  const cosmiconfig_1 = require("cosmiconfig");
16
17
  const CONFIG_FILE = "aicm.json";
18
+ function normalizeRules(rules) {
19
+ if (!rules)
20
+ return {};
21
+ if (typeof rules === "string") {
22
+ return { "/": rules };
23
+ }
24
+ return rules;
25
+ }
17
26
  function getFullPresetPath(presetPath, cwd) {
18
27
  const workingDir = cwd || process.cwd();
19
28
  // If it's a local file with .json extension, check relative to the working directory
@@ -82,11 +91,12 @@ function loadPreset(presetPath, cwd) {
82
91
  const parseError = error;
83
92
  throw new Error(`Error loading preset: Invalid JSON in ${presetPath}: ${parseError.message}`);
84
93
  }
85
- if (!preset.rules || typeof preset.rules !== "object") {
94
+ if (!preset.rules) {
86
95
  throw new Error(`Error loading preset: Invalid format in ${presetPath} - missing or invalid 'rules' object`);
87
96
  }
97
+ const normalizedRules = normalizeRules(preset.rules);
88
98
  return {
89
- rules: preset.rules,
99
+ rules: normalizedRules,
90
100
  mcpServers: preset.mcpServers,
91
101
  presets: preset.presets,
92
102
  };
@@ -123,7 +133,7 @@ function processPresetsInternal(config, metadata, cwd) {
123
133
  }
124
134
  // Skip if we've already processed this preset (prevents circular references)
125
135
  if (processedPresets.has(pathInfo.fullPath)) {
126
- console.warn(`Skipping already processed preset: ${presetPath}`);
136
+ // Skip duplicates to prevent circular references
127
137
  continue;
128
138
  }
129
139
  // Mark this preset as processed
@@ -214,11 +224,13 @@ function loadAicmConfigCosmiconfig(searchFrom) {
214
224
  const result = explorer.search(searchFrom);
215
225
  if (!result || !result.config)
216
226
  return null;
217
- const config = result.config;
218
- if (!config.rules)
219
- config.rules = {};
220
- if (!config.ides)
221
- config.ides = ["cursor"];
227
+ const rawConfig = result.config;
228
+ const normalizedRules = normalizeRules(rawConfig.rules);
229
+ const config = {
230
+ ...rawConfig,
231
+ ides: rawConfig.ides || ["cursor"],
232
+ rules: normalizedRules,
233
+ };
222
234
  return config;
223
235
  }
224
236
  catch (error) {
@@ -1,14 +1,14 @@
1
- import { Config } from "../types";
1
+ import { NormalizedConfig } from "../types";
2
2
  /**
3
3
  * Write MCP servers configuration to IDE targets
4
4
  * @param mcpServers The MCP servers configuration
5
5
  * @param ides The IDEs to write to
6
6
  * @param cwd The current working directory
7
7
  */
8
- export declare function writeMcpServersToTargets(mcpServers: Config["mcpServers"], ides: string[], cwd: string): void;
8
+ export declare function writeMcpServersToTargets(mcpServers: NormalizedConfig["mcpServers"], ides: string[], cwd: string): void;
9
9
  /**
10
10
  * Write MCP servers configuration to a specific file
11
11
  * @param mcpServers The MCP servers configuration
12
12
  * @param mcpPath The path to the mcp.json file
13
13
  */
14
- export declare function writeMcpServersToFile(mcpServers: Config["mcpServers"], mcpPath: string): void;
14
+ export declare function writeMcpServersToFile(mcpServers: NormalizedConfig["mcpServers"], mcpPath: string): void;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Helper function to execute a function within a specific working directory
3
+ * and ensure the original directory is always restored
4
+ */
5
+ export declare function withWorkingDirectory<T>(targetDir: string, fn: () => Promise<T>): Promise<T>;