aicm 0.13.1 → 0.14.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.
@@ -3,203 +3,224 @@ 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;
7
- exports.getFullPresetPath = getFullPresetPath;
6
+ exports.SUPPORTED_TARGETS = void 0;
7
+ exports.detectWorkspacesFromPackageJson = detectWorkspacesFromPackageJson;
8
+ exports.applyDefaults = applyDefaults;
9
+ exports.validateConfig = validateConfig;
10
+ exports.loadRulesFromDirectory = loadRulesFromDirectory;
11
+ exports.resolvePresetPath = resolvePresetPath;
8
12
  exports.loadPreset = loadPreset;
9
- exports.loadAicmConfigCosmiconfig = loadAicmConfigCosmiconfig;
10
- exports.getConfig = getConfig;
11
- exports.getRuleSource = getRuleSource;
12
- exports.getOriginalPresetPath = getOriginalPresetPath;
13
+ exports.loadAllRules = loadAllRules;
14
+ exports.applyOverrides = applyOverrides;
15
+ exports.loadConfigFile = loadConfigFile;
16
+ exports.loadConfig = loadConfig;
13
17
  exports.saveConfig = saveConfig;
14
18
  const fs_extra_1 = __importDefault(require("fs-extra"));
15
19
  const node_path_1 = __importDefault(require("node:path"));
16
20
  const cosmiconfig_1 = require("cosmiconfig");
17
- const glob_handler_1 = require("./glob-handler");
18
- const CONFIG_FILE = "aicm.json";
19
- function normalizeRules(rules) {
20
- if (!rules)
21
- return {};
22
- if (typeof rules === "string") {
23
- return { "/": rules };
21
+ const fast_glob_1 = __importDefault(require("fast-glob"));
22
+ exports.SUPPORTED_TARGETS = ["cursor", "windsurf", "codex"];
23
+ function detectWorkspacesFromPackageJson(cwd) {
24
+ try {
25
+ const packageJsonPath = node_path_1.default.join(cwd, "package.json");
26
+ if (!fs_extra_1.default.existsSync(packageJsonPath)) {
27
+ return false;
28
+ }
29
+ const packageJson = JSON.parse(fs_extra_1.default.readFileSync(packageJsonPath, "utf8"));
30
+ return Boolean(packageJson.workspaces);
31
+ }
32
+ catch (_a) {
33
+ return false;
24
34
  }
25
- return rules;
26
35
  }
27
- function getFullPresetPath(presetPath, cwd) {
36
+ function applyDefaults(config, cwd) {
28
37
  const workingDir = cwd || process.cwd();
29
- // If it's a local file with .json extension, check relative to the working directory
30
- if (presetPath.endsWith(".json")) {
31
- const absolutePath = node_path_1.default.isAbsolute(presetPath)
32
- ? presetPath
33
- : node_path_1.default.resolve(workingDir, presetPath);
34
- if (fs_extra_1.default.pathExistsSync(absolutePath)) {
35
- return { fullPath: absolutePath, originalPath: presetPath };
38
+ // Auto-detect workspaces if not explicitly set
39
+ const workspaces = config.workspaces !== undefined
40
+ ? config.workspaces
41
+ : detectWorkspacesFromPackageJson(workingDir);
42
+ return {
43
+ rulesDir: config.rulesDir,
44
+ targets: config.targets || ["cursor"],
45
+ presets: config.presets || [],
46
+ overrides: config.overrides || {},
47
+ mcpServers: config.mcpServers || {},
48
+ workspaces,
49
+ };
50
+ }
51
+ function validateConfig(config, configFilePath, cwd, isWorkspaceMode = false) {
52
+ if (typeof config !== "object" || config === null) {
53
+ throw new Error(`Config is not an object at ${configFilePath}`);
54
+ }
55
+ // Validate that either rulesDir or presets is provided
56
+ const hasRulesDir = "rulesDir" in config && typeof config.rulesDir === "string";
57
+ const hasPresets = "presets" in config &&
58
+ Array.isArray(config.presets) &&
59
+ config.presets.length > 0;
60
+ // In workspace mode, root config doesn't need rulesDir or presets
61
+ // since packages will have their own configurations
62
+ if (!isWorkspaceMode && !hasRulesDir && !hasPresets) {
63
+ throw new Error(`Either rulesDir or presets must be specified in config at ${configFilePath}`);
64
+ }
65
+ // Validate rulesDir if provided
66
+ if (hasRulesDir) {
67
+ const rulesPath = node_path_1.default.resolve(cwd, config.rulesDir);
68
+ if (!fs_extra_1.default.existsSync(rulesPath)) {
69
+ throw new Error(`Rules directory does not exist: ${rulesPath}`);
70
+ }
71
+ if (!fs_extra_1.default.statSync(rulesPath).isDirectory()) {
72
+ throw new Error(`Rules path is not a directory: ${rulesPath}`);
36
73
  }
37
74
  }
38
- try {
39
- let absolutePresetPath;
40
- // Handle npm package with explicit JSON path
41
- if (presetPath.endsWith(".json")) {
42
- absolutePresetPath = require.resolve(presetPath, {
43
- paths: [__dirname, workingDir],
44
- });
75
+ if ("targets" in config) {
76
+ if (!Array.isArray(config.targets)) {
77
+ throw new Error(`targets must be an array in config at ${configFilePath}`);
45
78
  }
46
- // Handle npm package without explicit JSON path (add aicm.json)
47
- else {
48
- // For npm packages, ensure we properly handle scoped packages (@org/pkg)
49
- const presetPathWithConfig = node_path_1.default.join(presetPath, "aicm.json");
50
- try {
51
- absolutePresetPath = require.resolve(presetPathWithConfig, {
52
- paths: [__dirname, workingDir],
53
- });
54
- }
55
- catch (_a) {
56
- // If direct resolution fails, try as a package name
57
- absolutePresetPath = require.resolve(presetPath, {
58
- paths: [__dirname, workingDir],
59
- });
60
- // If we found the package but not the config file, look for aicm.json
61
- if (fs_extra_1.default.existsSync(absolutePresetPath)) {
62
- const packageDir = node_path_1.default.dirname(absolutePresetPath);
63
- const configPath = node_path_1.default.join(packageDir, "aicm.json");
64
- if (fs_extra_1.default.existsSync(configPath)) {
65
- absolutePresetPath = configPath;
66
- }
67
- }
79
+ if (config.targets.length === 0) {
80
+ throw new Error(`targets must not be empty in config at ${configFilePath}`);
81
+ }
82
+ for (const target of config.targets) {
83
+ if (!exports.SUPPORTED_TARGETS.includes(target)) {
84
+ throw new Error(`Unsupported target: ${target}. Supported targets: ${exports.SUPPORTED_TARGETS.join(", ")}`);
68
85
  }
69
86
  }
70
- return fs_extra_1.default.existsSync(absolutePresetPath)
71
- ? { fullPath: absolutePresetPath, originalPath: presetPath }
72
- : null;
73
87
  }
74
- catch (_b) {
88
+ // Validate override rule names will be checked after rule resolution
89
+ }
90
+ async function loadRulesFromDirectory(rulesDir, source, presetName) {
91
+ const rules = [];
92
+ if (!fs_extra_1.default.existsSync(rulesDir)) {
93
+ return rules;
94
+ }
95
+ const pattern = node_path_1.default.join(rulesDir, "**/*.mdc").replace(/\\/g, "/");
96
+ const filePaths = await (0, fast_glob_1.default)(pattern, {
97
+ onlyFiles: true,
98
+ absolute: true,
99
+ });
100
+ for (const filePath of filePaths) {
101
+ const content = await fs_extra_1.default.readFile(filePath, "utf8");
102
+ // Preserve directory structure by using relative path from rulesDir
103
+ const relativePath = node_path_1.default.relative(rulesDir, filePath);
104
+ const ruleName = relativePath.replace(/\.mdc$/, "").replace(/\\/g, "/");
105
+ rules.push({
106
+ name: ruleName,
107
+ content,
108
+ sourcePath: filePath,
109
+ source,
110
+ presetName,
111
+ });
112
+ }
113
+ return rules;
114
+ }
115
+ function resolvePresetPath(presetPath, cwd) {
116
+ // Support specifying aicm.json directory and load the config from it
117
+ if (!presetPath.endsWith(".json")) {
118
+ presetPath = node_path_1.default.join(presetPath, "aicm.json");
119
+ }
120
+ // Support local or absolute paths
121
+ const absolutePath = node_path_1.default.isAbsolute(presetPath)
122
+ ? presetPath
123
+ : node_path_1.default.resolve(cwd, presetPath);
124
+ if (fs_extra_1.default.existsSync(absolutePath)) {
125
+ return absolutePath;
126
+ }
127
+ try {
128
+ // Support npm packages
129
+ const resolvedPath = require.resolve(presetPath, {
130
+ paths: [cwd, __dirname],
131
+ });
132
+ return fs_extra_1.default.existsSync(resolvedPath) ? resolvedPath : null;
133
+ }
134
+ catch (_a) {
75
135
  return null;
76
136
  }
77
137
  }
78
- /**
79
- * Load a preset file and return its contents
80
- */
81
- function loadPreset(presetPath, cwd) {
82
- const pathInfo = getFullPresetPath(presetPath, cwd);
83
- if (!pathInfo) {
84
- throw new Error(`Error loading preset: "${presetPath}". Make sure the package is installed in your project.`);
138
+ async function loadPreset(presetPath, cwd) {
139
+ const resolvedPresetPath = resolvePresetPath(presetPath, cwd);
140
+ if (!resolvedPresetPath) {
141
+ throw new Error(`Preset not found: "${presetPath}". Make sure the package is installed or the path is correct.`);
85
142
  }
86
- const presetContent = fs_extra_1.default.readFileSync(pathInfo.fullPath, "utf8");
87
- let preset;
143
+ let presetConfig;
88
144
  try {
89
- preset = JSON.parse(presetContent);
145
+ const content = await fs_extra_1.default.readFile(resolvedPresetPath, "utf8");
146
+ presetConfig = JSON.parse(content);
90
147
  }
91
148
  catch (error) {
92
- const parseError = error;
93
- throw new Error(`Error loading preset: Invalid JSON in ${presetPath}: ${parseError.message}`);
149
+ throw new Error(`Failed to load preset "${presetPath}": ${error instanceof Error ? error.message : "Unknown error"}`);
94
150
  }
95
- if (!preset.rules) {
96
- throw new Error(`Error loading preset: Invalid format in ${presetPath} - missing or invalid 'rules' object`);
151
+ // Validate that preset has rulesDir
152
+ if (!presetConfig.rulesDir) {
153
+ throw new Error(`Preset "${presetPath}" must have a rulesDir specified`);
97
154
  }
98
- const normalizedRules = normalizeRules(preset.rules);
155
+ // Resolve preset's rules directory relative to the preset file
156
+ const presetDir = node_path_1.default.dirname(resolvedPresetPath);
157
+ const presetRulesDir = node_path_1.default.resolve(presetDir, presetConfig.rulesDir);
99
158
  return {
100
- rules: normalizedRules,
101
- mcpServers: preset.mcpServers,
102
- presets: preset.presets,
159
+ config: presetConfig,
160
+ rulesDir: presetRulesDir,
103
161
  };
104
162
  }
105
- // Global metadata storage
106
- let currentMetadata = null;
107
- // Track processed presets to avoid circular references
108
- const processedPresets = new Set();
109
- /**
110
- * Process presets and return a new config with merged rules and metadata
111
- */
112
- async function processPresets(config, cwd) {
113
- // Create a deep copy of the config to avoid mutations
114
- const newConfig = JSON.parse(JSON.stringify(config));
115
- const metadata = {
116
- ruleSources: {},
117
- originalPresetPaths: {},
118
- };
119
- // Clear processed presets tracking set when starting from the top level
120
- processedPresets.clear();
121
- return await processPresetsInternal(newConfig, metadata, cwd);
122
- }
123
- /**
124
- * Internal function to process presets recursively
125
- */
126
- async function processPresetsInternal(config, metadata, cwd) {
127
- if (!config.presets || !Array.isArray(config.presets)) {
128
- return { config, metadata };
163
+ async function loadAllRules(config, cwd) {
164
+ const allRules = [];
165
+ let mergedMcpServers = { ...config.mcpServers };
166
+ // Load local rules only if rulesDir is provided
167
+ if (config.rulesDir) {
168
+ const localRulesPath = node_path_1.default.resolve(cwd, config.rulesDir);
169
+ const localRules = await loadRulesFromDirectory(localRulesPath, "local");
170
+ allRules.push(...localRules);
129
171
  }
130
- for (const presetPath of config.presets) {
131
- const pathInfo = getFullPresetPath(presetPath, cwd);
132
- if (!pathInfo) {
133
- throw new Error(`Error loading preset: "${presetPath}". Make sure the package is installed in your project.`);
134
- }
135
- // Skip if we've already processed this preset (prevents circular references)
136
- if (processedPresets.has(pathInfo.fullPath)) {
137
- // Skip duplicates to prevent circular references
138
- continue;
139
- }
140
- // Mark this preset as processed
141
- processedPresets.add(pathInfo.fullPath);
142
- const preset = loadPreset(presetPath, cwd);
143
- if (!preset)
144
- continue;
145
- // Expand glob patterns within the preset using its base directory
146
- const presetDir = node_path_1.default.dirname(pathInfo.fullPath);
147
- const expansion = await (0, glob_handler_1.expandRulesGlobPatterns)(preset.rules, presetDir);
148
- preset.rules = expansion.expandedRules;
149
- // Process nested presets first (depth-first)
150
- if (preset.presets && preset.presets.length > 0) {
151
- // Create a temporary config with just the presets from this preset
152
- const presetConfig = {
153
- rules: {},
154
- presets: preset.presets,
155
- ides: [],
156
- };
157
- // Recursively process the nested presets
158
- const { config: nestedConfig } = await processPresetsInternal(presetConfig, metadata, cwd);
159
- Object.assign(preset.rules, nestedConfig.rules);
160
- }
161
- const { updatedConfig, updatedMetadata } = mergePresetRules(config, preset.rules, pathInfo, metadata);
162
- Object.assign(config.rules, updatedConfig.rules);
163
- Object.assign(metadata.ruleSources, updatedMetadata.ruleSources);
164
- Object.assign(metadata.originalPresetPaths, updatedMetadata.originalPresetPaths);
165
- if (preset.mcpServers) {
166
- config.mcpServers = mergePresetMcpServers(config.mcpServers || {}, preset.mcpServers);
172
+ if (config.presets) {
173
+ for (const presetPath of config.presets) {
174
+ const preset = await loadPreset(presetPath, cwd);
175
+ const presetRules = await loadRulesFromDirectory(preset.rulesDir, "preset", presetPath);
176
+ allRules.push(...presetRules);
177
+ // Merge MCP servers from preset
178
+ if (preset.config.mcpServers) {
179
+ mergedMcpServers = mergePresetMcpServers(mergedMcpServers, preset.config.mcpServers);
180
+ }
167
181
  }
168
182
  }
169
- return { config, metadata };
170
- }
171
- /**
172
- * Merge preset rules into the config without mutation
173
- */
174
- function mergePresetRules(config, presetRules, pathInfo, metadata) {
175
- const updatedRules = { ...config.rules };
176
- const updatedMetadata = {
177
- ruleSources: { ...metadata.ruleSources },
178
- originalPresetPaths: { ...metadata.originalPresetPaths },
183
+ return {
184
+ rules: allRules,
185
+ mcpServers: mergedMcpServers,
179
186
  };
180
- for (const [ruleName, rulePath] of Object.entries(presetRules)) {
181
- // Cancel if set to false in config
182
- if (Object.prototype.hasOwnProperty.call(config.rules, ruleName) &&
183
- config.rules[ruleName] === false) {
184
- delete updatedRules[ruleName];
185
- delete updatedMetadata.ruleSources[ruleName];
186
- delete updatedMetadata.originalPresetPaths[ruleName];
187
- continue;
187
+ }
188
+ function applyOverrides(rules, overrides, cwd) {
189
+ // Validate that all override rule names exist in the resolved rules
190
+ for (const ruleName of Object.keys(overrides)) {
191
+ // TODO: support better error messages with edit distance, helping the user in case of a typo
192
+ // TODO: or shows a list of potential rules to override
193
+ if (!rules.some((rule) => rule.name === ruleName)) {
194
+ throw new Error(`Override rule "${ruleName}" does not exist in resolved rules`);
188
195
  }
189
- // Only add if not already defined in config (override handled by config)
190
- if (!Object.prototype.hasOwnProperty.call(config.rules, ruleName)) {
191
- updatedRules[ruleName] = rulePath;
192
- updatedMetadata.ruleSources[ruleName] = pathInfo.fullPath;
193
- updatedMetadata.originalPresetPaths[ruleName] = pathInfo.originalPath;
196
+ }
197
+ const ruleMap = new Map();
198
+ for (const rule of rules) {
199
+ ruleMap.set(rule.name, rule);
200
+ }
201
+ for (const [ruleName, override] of Object.entries(overrides)) {
202
+ if (override === false) {
203
+ ruleMap.delete(ruleName);
204
+ }
205
+ else if (typeof override === "string") {
206
+ const overridePath = node_path_1.default.resolve(cwd, override);
207
+ if (!fs_extra_1.default.existsSync(overridePath)) {
208
+ throw new Error(`Override rule file not found: ${override} in ${cwd}`);
209
+ }
210
+ const content = fs_extra_1.default.readFileSync(overridePath, "utf8");
211
+ ruleMap.set(ruleName, {
212
+ name: ruleName,
213
+ content,
214
+ sourcePath: overridePath,
215
+ source: "local",
216
+ });
194
217
  }
195
218
  }
196
- return {
197
- updatedConfig: { ...config, rules: updatedRules },
198
- updatedMetadata,
199
- };
219
+ return Array.from(ruleMap.values());
200
220
  }
201
221
  /**
202
- * Merge preset mcpServers without mutation
222
+ * Merge preset MCP servers with local config MCP servers
223
+ * Local config takes precedence over preset config
203
224
  */
204
225
  function mergePresetMcpServers(configMcpServers, presetMcpServers) {
205
226
  const newMcpServers = { ...configMcpServers };
@@ -217,71 +238,46 @@ function mergePresetMcpServers(configMcpServers, presetMcpServers) {
217
238
  }
218
239
  return newMcpServers;
219
240
  }
220
- /**
221
- * Load the aicm config using cosmiconfig, supporting both aicm.json and package.json.
222
- * Returns the config object or null if not found.
223
- */
224
- async function loadAicmConfigCosmiconfig(searchFrom) {
241
+ async function loadConfigFile(searchFrom) {
225
242
  const explorer = (0, cosmiconfig_1.cosmiconfig)("aicm", {
226
- searchPlaces: ["package.json", "aicm.json"],
243
+ searchPlaces: ["aicm.json", "package.json"],
227
244
  });
228
245
  try {
229
246
  const result = await explorer.search(searchFrom);
230
- if (!result || !result.config)
231
- return null;
232
- const rawConfig = result.config;
233
- const normalizedRules = normalizeRules(rawConfig.rules);
234
- const config = {
235
- ...rawConfig,
236
- ides: rawConfig.ides || ["cursor"],
237
- rules: normalizedRules,
238
- };
239
- return config;
247
+ return result;
240
248
  }
241
249
  catch (error) {
242
- throw new Error(`Error loading aicm config: ${error instanceof Error ? error.message : String(error)}`);
250
+ throw new Error(`Failed to load configuration: ${error instanceof Error ? error.message : "Unknown error"}`);
243
251
  }
244
252
  }
245
- /**
246
- * Get the configuration from aicm.json or package.json (using cosmiconfigSync) and merge with any presets
247
- */
248
- async function getConfig(cwd) {
253
+ async function loadConfig(cwd) {
249
254
  const workingDir = cwd || process.cwd();
250
- const config = await loadAicmConfigCosmiconfig(workingDir);
251
- if (!config) {
252
- throw new Error(`No config found in ${workingDir}, create one using "aicm init"`);
255
+ const configResult = await loadConfigFile(workingDir);
256
+ if (!(configResult === null || configResult === void 0 ? void 0 : configResult.config)) {
257
+ return null;
253
258
  }
254
- const { config: processedConfig, metadata } = await processPresets(config, workingDir);
255
- // Store metadata for later access
256
- currentMetadata = metadata;
257
- return processedConfig;
258
- }
259
- /**
260
- * Get the source preset path for a rule if it came from a preset
261
- */
262
- function getRuleSource(config, ruleName) {
263
- var _a;
264
- return (_a = currentMetadata === null || currentMetadata === void 0 ? void 0 : currentMetadata.ruleSources) === null || _a === void 0 ? void 0 : _a[ruleName];
265
- }
266
- /**
267
- * Get the original preset path for a rule if it came from a preset
268
- */
269
- function getOriginalPresetPath(config, ruleName) {
270
- var _a;
271
- return (_a = currentMetadata === null || currentMetadata === void 0 ? void 0 : currentMetadata.originalPresetPaths) === null || _a === void 0 ? void 0 : _a[ruleName];
259
+ const configWithDefaults = applyDefaults(configResult.config, workingDir);
260
+ const isWorkspaceMode = configWithDefaults.workspaces;
261
+ validateConfig(configResult.config, configResult.filepath, workingDir, isWorkspaceMode);
262
+ const { rules, mcpServers } = await loadAllRules(configWithDefaults, workingDir);
263
+ let rulesWithOverrides = rules;
264
+ if (configWithDefaults.overrides) {
265
+ rulesWithOverrides = applyOverrides(rules, configWithDefaults.overrides, workingDir);
266
+ }
267
+ return {
268
+ config: configWithDefaults,
269
+ rules: rulesWithOverrides,
270
+ mcpServers,
271
+ };
272
272
  }
273
- /**
274
- * Save the configuration to the aicm.json file
275
- */
276
273
  function saveConfig(config, cwd) {
277
274
  const workingDir = cwd || process.cwd();
278
- const configPath = node_path_1.default.join(workingDir, CONFIG_FILE);
275
+ const configPath = node_path_1.default.join(workingDir, "aicm.json");
279
276
  try {
280
- fs_extra_1.default.writeJsonSync(configPath, config, { spaces: 2 });
277
+ fs_extra_1.default.writeFileSync(configPath, JSON.stringify(config, null, 2));
281
278
  return true;
282
279
  }
283
- catch (error) {
284
- console.error("Error writing configuration file:", error);
280
+ catch (_a) {
285
281
  return false;
286
282
  }
287
283
  }
@@ -0,0 +1,64 @@
1
+ import { CosmiconfigResult } from "cosmiconfig";
2
+ export interface RawConfig {
3
+ rulesDir: string;
4
+ targets?: string[];
5
+ presets?: string[];
6
+ overrides?: Record<string, string | false>;
7
+ mcpServers?: MCPServers;
8
+ workspaces?: boolean;
9
+ }
10
+ export interface Config {
11
+ rulesDir: string;
12
+ targets: string[];
13
+ presets?: string[];
14
+ overrides?: Record<string, string | false>;
15
+ mcpServers?: MCPServers;
16
+ workspaces?: boolean;
17
+ }
18
+ export type MCPServer = {
19
+ command: string;
20
+ args?: string[];
21
+ env?: Record<string, string>;
22
+ url?: never;
23
+ } | {
24
+ url: string;
25
+ env?: Record<string, string>;
26
+ command?: never;
27
+ args?: never;
28
+ } | false;
29
+ export interface MCPServers {
30
+ [serverName: string]: MCPServer;
31
+ }
32
+ export interface RuleFile {
33
+ name: string;
34
+ content: string;
35
+ sourcePath: string;
36
+ source: "local" | "preset";
37
+ presetName?: string;
38
+ }
39
+ export interface RuleCollection {
40
+ [target: string]: RuleFile[];
41
+ }
42
+ export interface ResolvedConfig {
43
+ config: Config;
44
+ rules: RuleFile[];
45
+ mcpServers: MCPServers;
46
+ }
47
+ export declare const SUPPORTED_TARGETS: readonly ["cursor", "windsurf", "codex"];
48
+ export type SupportedTarget = (typeof SUPPORTED_TARGETS)[number];
49
+ export declare function applyDefaults(config: RawConfig): Config;
50
+ export declare function validateConfig(config: unknown, configFilePath: string, cwd: string): asserts config is Config;
51
+ export declare function loadRulesFromDirectory(rulesDir: string, source: "local" | "preset", presetName?: string): Promise<RuleFile[]>;
52
+ export declare function resolvePresetPath(presetPath: string, cwd: string): string | null;
53
+ export declare function loadPreset(presetPath: string, cwd: string): Promise<{
54
+ config: Config;
55
+ rulesDir: string;
56
+ }>;
57
+ export declare function loadAllRules(config: Config, cwd: string): Promise<{
58
+ rules: RuleFile[];
59
+ mcpServers: MCPServers;
60
+ }>;
61
+ export declare function applyOverrides(rules: RuleFile[], overrides: Record<string, string | false>, cwd: string): RuleFile[];
62
+ export declare function loadConfigFile(searchFrom?: string): Promise<CosmiconfigResult>;
63
+ export declare function loadConfig(cwd?: string): Promise<ResolvedConfig | null>;
64
+ export declare function saveConfig(config: Config, cwd?: string): boolean;