aicm 0.1.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.
@@ -0,0 +1,21 @@
1
+ import { Config, Rules } from "../types";
2
+ /**
3
+ * Get the full path to a preset file
4
+ */
5
+ export declare function getFullPresetPath(presetPath: string): string | null;
6
+ /**
7
+ * Load a preset file and return its rules
8
+ */
9
+ export declare function loadPreset(presetPath: string): Rules | null;
10
+ /**
11
+ * Get the configuration from the rules.json file and merge with any presets
12
+ */
13
+ export declare function getConfig(): Config | null;
14
+ /**
15
+ * Get the source preset path for a rule if it came from a preset
16
+ */
17
+ export declare function getRuleSource(config: Config, ruleName: string): string | undefined;
18
+ /**
19
+ * Save the configuration to the rules.json file
20
+ */
21
+ export declare function saveConfig(config: Config): boolean;
@@ -0,0 +1,155 @@
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.getFullPresetPath = getFullPresetPath;
7
+ exports.loadPreset = loadPreset;
8
+ exports.getConfig = getConfig;
9
+ exports.getRuleSource = getRuleSource;
10
+ exports.saveConfig = saveConfig;
11
+ const fs_extra_1 = __importDefault(require("fs-extra"));
12
+ const node_path_1 = __importDefault(require("node:path"));
13
+ const rule_detector_1 = require("./rule-detector");
14
+ const CONFIG_FILE = "rules.json";
15
+ /**
16
+ * Get the full path to a preset file
17
+ */
18
+ function getFullPresetPath(presetPath) {
19
+ try {
20
+ const ruleType = (0, rule_detector_1.detectRuleType)(presetPath);
21
+ let fullPresetPath = presetPath;
22
+ if (ruleType === "npm") {
23
+ try {
24
+ fullPresetPath = require.resolve(presetPath, {
25
+ paths: [process.cwd()],
26
+ });
27
+ }
28
+ catch (_a) {
29
+ const directPath = node_path_1.default.join(process.cwd(), "node_modules", presetPath);
30
+ if (fs_extra_1.default.existsSync(directPath)) {
31
+ fullPresetPath = directPath;
32
+ }
33
+ else {
34
+ return null;
35
+ }
36
+ }
37
+ }
38
+ else {
39
+ // For local files, resolve from current directory
40
+ fullPresetPath = node_path_1.default.resolve(process.cwd(), presetPath);
41
+ }
42
+ return fs_extra_1.default.existsSync(fullPresetPath) ? fullPresetPath : null;
43
+ }
44
+ catch (_b) {
45
+ return null;
46
+ }
47
+ }
48
+ /**
49
+ * Load a preset file and return its rules
50
+ */
51
+ function loadPreset(presetPath) {
52
+ const fullPresetPath = getFullPresetPath(presetPath);
53
+ if (!fullPresetPath) {
54
+ throw new Error(`Error loading preset: File not found: ${presetPath}. Make sure the package is installed in your project.`);
55
+ }
56
+ const presetContent = fs_extra_1.default.readFileSync(fullPresetPath, "utf8");
57
+ let preset;
58
+ try {
59
+ preset = JSON.parse(presetContent);
60
+ }
61
+ catch (error) {
62
+ const parseError = error;
63
+ throw new Error(`Error loading preset: Invalid JSON in ${presetPath}: ${parseError.message}`);
64
+ }
65
+ if (!preset.rules || typeof preset.rules !== "object") {
66
+ throw new Error(`Error loading preset: Invalid format in ${presetPath} - missing or invalid 'rules' object`);
67
+ }
68
+ return preset.rules;
69
+ }
70
+ /**
71
+ * Read the raw configuration file without processing presets
72
+ */
73
+ function readConfigFile() {
74
+ const configPath = node_path_1.default.join(process.cwd(), CONFIG_FILE);
75
+ if (!fs_extra_1.default.existsSync(configPath)) {
76
+ return null;
77
+ }
78
+ try {
79
+ const configContent = fs_extra_1.default.readFileSync(configPath, "utf8");
80
+ const config = JSON.parse(configContent);
81
+ // Initialize rules object if it doesn't exist
82
+ if (!config.rules) {
83
+ config.rules = {};
84
+ }
85
+ return config;
86
+ }
87
+ catch (error) {
88
+ console.error("Error reading configuration file:", error);
89
+ return null;
90
+ }
91
+ }
92
+ /**
93
+ * Process presets and merge their rules into the config
94
+ */
95
+ function processPresets(config) {
96
+ if (!config.presets || !Array.isArray(config.presets)) {
97
+ return;
98
+ }
99
+ for (const presetPath of config.presets) {
100
+ const presetRules = loadPreset(presetPath);
101
+ if (!presetRules)
102
+ continue;
103
+ const fullPresetPath = getFullPresetPath(presetPath);
104
+ if (!fullPresetPath)
105
+ continue;
106
+ mergePresetRules(config, presetRules, fullPresetPath);
107
+ }
108
+ }
109
+ /**
110
+ * Merge preset rules into the config
111
+ */
112
+ function mergePresetRules(config, presetRules, presetPath) {
113
+ // Add preset rules, but don't override existing rules
114
+ for (const [ruleName, rulePath] of Object.entries(presetRules)) {
115
+ // Only add if not already defined in config
116
+ if (!config.rules[ruleName]) {
117
+ config.rules[ruleName] = rulePath;
118
+ // Store the source preset path in metadata
119
+ config.__ruleSources = config.__ruleSources || {};
120
+ config.__ruleSources[ruleName] = presetPath;
121
+ }
122
+ }
123
+ }
124
+ /**
125
+ * Get the configuration from the rules.json file and merge with any presets
126
+ */
127
+ function getConfig() {
128
+ const config = readConfigFile();
129
+ if (!config) {
130
+ return null;
131
+ }
132
+ processPresets(config);
133
+ return config;
134
+ }
135
+ /**
136
+ * Get the source preset path for a rule if it came from a preset
137
+ */
138
+ function getRuleSource(config, ruleName) {
139
+ var _a;
140
+ return (_a = config.__ruleSources) === null || _a === void 0 ? void 0 : _a[ruleName];
141
+ }
142
+ /**
143
+ * Save the configuration to the rules.json file
144
+ */
145
+ function saveConfig(config) {
146
+ const configPath = node_path_1.default.join(process.cwd(), CONFIG_FILE);
147
+ try {
148
+ fs_extra_1.default.writeJsonSync(configPath, config, { spaces: 2 });
149
+ return true;
150
+ }
151
+ catch (error) {
152
+ console.error("Error writing configuration file:", error);
153
+ return false;
154
+ }
155
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Parse an MDC file and extract its content
3
+ * MDC files are Markdown files with metadata
4
+ * https://docs.cursor.com/context/rules
5
+ */
6
+ export declare function parseMdcFile(filePath: string): {
7
+ metadata: Record<string, boolean | string | string[]>;
8
+ content: string;
9
+ };
@@ -0,0 +1,59 @@
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.parseMdcFile = parseMdcFile;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ /**
9
+ * Parse an MDC file and extract its content
10
+ * MDC files are Markdown files with metadata
11
+ * https://docs.cursor.com/context/rules
12
+ */
13
+ function parseMdcFile(filePath) {
14
+ const fileContent = fs_extra_1.default.readFileSync(filePath, "utf8");
15
+ if (!fileContent.startsWith("---")) {
16
+ return {
17
+ metadata: {},
18
+ content: fileContent,
19
+ };
20
+ }
21
+ const endOfMetadata = fileContent.indexOf("---", 3);
22
+ if (endOfMetadata === -1) {
23
+ return {
24
+ metadata: {},
25
+ content: fileContent,
26
+ };
27
+ }
28
+ const metadataStr = fileContent.substring(3, endOfMetadata).trim();
29
+ const content = fileContent.substring(endOfMetadata + 3).trim();
30
+ const metadata = {};
31
+ metadataStr.split("\n").forEach((line) => {
32
+ const colonIndex = line.indexOf(":");
33
+ if (colonIndex !== -1) {
34
+ const key = line.substring(0, colonIndex).trim();
35
+ const valueStr = line.substring(colonIndex + 1).trim();
36
+ // Handle different value types
37
+ let value = "";
38
+ if (valueStr === "true") {
39
+ value = true;
40
+ }
41
+ else if (valueStr === "false") {
42
+ value = false;
43
+ }
44
+ else if (valueStr.startsWith('"') && valueStr.endsWith('"')) {
45
+ // Remove quotes from string values
46
+ value = valueStr.substring(1, valueStr.length - 1);
47
+ }
48
+ else {
49
+ // Default to using the string value as is
50
+ value = valueStr;
51
+ }
52
+ metadata[key] = value;
53
+ }
54
+ });
55
+ return {
56
+ metadata,
57
+ content,
58
+ };
59
+ }
@@ -0,0 +1,33 @@
1
+ import { RuleCollection, RuleContent } from "../types";
2
+ /**
3
+ * Find the root directory of a package by name
4
+ * @param packageName The name of the package
5
+ * @returns The absolute path to the package's root directory
6
+ */
7
+ export declare function findPackageRoot(packageName: string): string;
8
+ /**
9
+ * Initialize an empty rule collection
10
+ */
11
+ export declare function initRuleCollection(): RuleCollection;
12
+ /**
13
+ * Add a rule to the collection
14
+ * @param collection The rule collection to add to
15
+ * @param rule The rule content to add
16
+ * @param ides The IDEs to add the rule for
17
+ */
18
+ export declare function addRuleToCollection(collection: RuleCollection, rule: RuleContent, ides: string[]): void;
19
+ /**
20
+ * Collect a rule from a local file source
21
+ * @param ruleName The name of the rule
22
+ * @param source The source path (relative or absolute)
23
+ * @param ruleBasePath Optional base path for resolving relative paths
24
+ * @returns The rule content
25
+ */
26
+ export declare function collectLocalRule(ruleName: string, source: string, ruleBasePath?: string): RuleContent;
27
+ /**
28
+ * Collect a rule from an npm package
29
+ * @param ruleName The name of the rule
30
+ * @param source The npm package source (can include path)
31
+ * @returns The rule content
32
+ */
33
+ export declare function collectNpmRule(ruleName: string, source: string): RuleContent;
@@ -0,0 +1,160 @@
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.findPackageRoot = findPackageRoot;
7
+ exports.initRuleCollection = initRuleCollection;
8
+ exports.addRuleToCollection = addRuleToCollection;
9
+ exports.collectLocalRule = collectLocalRule;
10
+ exports.collectNpmRule = collectNpmRule;
11
+ const fs_extra_1 = __importDefault(require("fs-extra"));
12
+ const node_path_1 = __importDefault(require("node:path"));
13
+ const mdc_parser_1 = require("./mdc-parser");
14
+ /**
15
+ * Find the root directory of a package by name
16
+ * @param packageName The name of the package
17
+ * @returns The absolute path to the package's root directory
18
+ */
19
+ function findPackageRoot(packageName) {
20
+ try {
21
+ // Method 1: Try to use require.resolve
22
+ const packageEntry = require.resolve(packageName, {
23
+ paths: [process.cwd()],
24
+ });
25
+ // Navigate up until we find a package.json or reach a reasonable limit
26
+ let currentDir = node_path_1.default.dirname(packageEntry);
27
+ let iterations = 0;
28
+ const maxIterations = 3; // Prevent infinite loops
29
+ while (iterations < maxIterations) {
30
+ // If we found the package.json, this is likely the package root
31
+ if (fs_extra_1.default.existsSync(node_path_1.default.join(currentDir, "package.json"))) {
32
+ return currentDir;
33
+ }
34
+ // Move up one directory
35
+ const parentDir = node_path_1.default.dirname(currentDir);
36
+ // If we've reached the root or haven't changed directory, stop
37
+ if (parentDir === currentDir) {
38
+ break;
39
+ }
40
+ currentDir = parentDir;
41
+ iterations++;
42
+ }
43
+ // If we couldn't find package.json, use the directory of the entry point
44
+ return node_path_1.default.dirname(packageEntry);
45
+ }
46
+ catch (_a) {
47
+ // Method 2: Fall back to direct node_modules resolution
48
+ const nodeModulesPath = node_path_1.default.resolve(process.cwd(), "node_modules", packageName);
49
+ if (!fs_extra_1.default.existsSync(nodeModulesPath)) {
50
+ throw new Error(`Package '${packageName}' not found in node_modules.`);
51
+ }
52
+ return nodeModulesPath;
53
+ }
54
+ }
55
+ /**
56
+ * Initialize an empty rule collection
57
+ */
58
+ function initRuleCollection() {
59
+ return {
60
+ cursor: [],
61
+ windsurf: [],
62
+ };
63
+ }
64
+ /**
65
+ * Add a rule to the collection
66
+ * @param collection The rule collection to add to
67
+ * @param rule The rule content to add
68
+ * @param ides The IDEs to add the rule for
69
+ */
70
+ function addRuleToCollection(collection, rule, ides) {
71
+ for (const ide of ides) {
72
+ if (ide === "cursor" &&
73
+ !collection.cursor.some((r) => r.name === rule.name)) {
74
+ collection.cursor.push(rule);
75
+ }
76
+ else if (ide === "windsurf" &&
77
+ !collection.windsurf.some((r) => r.name === rule.name)) {
78
+ collection.windsurf.push(rule);
79
+ }
80
+ }
81
+ }
82
+ /**
83
+ * Collect a rule from a local file source
84
+ * @param ruleName The name of the rule
85
+ * @param source The source path (relative or absolute)
86
+ * @param ruleBasePath Optional base path for resolving relative paths
87
+ * @returns The rule content
88
+ */
89
+ function collectLocalRule(ruleName, source, ruleBasePath) {
90
+ // Resolve path relative to base path or current directory
91
+ let sourcePath = source;
92
+ if (!node_path_1.default.isAbsolute(source)) {
93
+ if (ruleBasePath) {
94
+ // If a base path is provided (e.g., for presets), resolve relative to that
95
+ sourcePath = node_path_1.default.resolve(node_path_1.default.dirname(ruleBasePath), source);
96
+ }
97
+ else {
98
+ // Otherwise resolve relative to current directory
99
+ sourcePath = node_path_1.default.resolve(process.cwd(), source);
100
+ }
101
+ }
102
+ if (!fs_extra_1.default.existsSync(sourcePath)) {
103
+ throw new Error(`Source file ${sourcePath} not found.`);
104
+ }
105
+ // Parse the MDC file to extract metadata and content
106
+ const { metadata, content } = (0, mdc_parser_1.parseMdcFile)(sourcePath);
107
+ return {
108
+ name: ruleName,
109
+ content,
110
+ metadata,
111
+ sourcePath,
112
+ };
113
+ }
114
+ /**
115
+ * Collect a rule from an npm package
116
+ * @param ruleName The name of the rule
117
+ * @param source The npm package source (can include path)
118
+ * @returns The rule content
119
+ */
120
+ function collectNpmRule(ruleName, source) {
121
+ // Parse source into package and file path
122
+ let packageName;
123
+ let packagePath;
124
+ if (source.includes("/") && !source.startsWith("@")) {
125
+ // Format: "package-name/path/to/file.mdc"
126
+ const firstSlash = source.indexOf("/");
127
+ packageName = source.substring(0, firstSlash);
128
+ packagePath = source.substring(firstSlash + 1);
129
+ }
130
+ else if (source.startsWith("@")) {
131
+ // Format: "@scope/package/path/to/file.mdc"
132
+ const parts = source.split("/");
133
+ // @scope/package
134
+ packageName = `${parts[0]}/${parts[1]}`;
135
+ // Remaining path, if any
136
+ packagePath = parts.slice(2).join("/");
137
+ }
138
+ else {
139
+ // Format: "package-name" (whole package)
140
+ packageName = source;
141
+ packagePath = "";
142
+ }
143
+ // Try to find the package and get its root directory
144
+ const packageRoot = findPackageRoot(packageName);
145
+ // Resolve the full path to the rule file
146
+ const ruleFile = packagePath
147
+ ? node_path_1.default.join(packageRoot, packagePath)
148
+ : packageRoot;
149
+ if (!fs_extra_1.default.existsSync(ruleFile)) {
150
+ throw new Error(`Rule file not found in package: ${ruleFile}`);
151
+ }
152
+ // Parse the MDC file to extract metadata and content
153
+ const { metadata, content } = (0, mdc_parser_1.parseMdcFile)(ruleFile);
154
+ return {
155
+ name: ruleName,
156
+ content,
157
+ metadata,
158
+ sourcePath: ruleFile,
159
+ };
160
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Detects the rule type from the source string
3
+ */
4
+ export declare function detectRuleType(source: string): "npm" | "local";
@@ -0,0 +1,42 @@
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.detectRuleType = detectRuleType;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ /**
10
+ * Detects the rule type from the source string
11
+ */
12
+ function detectRuleType(source) {
13
+ if (source.startsWith("http://") || source.startsWith("https://")) {
14
+ throw new Error("URL-based rules are not supported due to security concerns. Please use npm packages or local files instead.");
15
+ }
16
+ // Check if it's a local file path
17
+ if (source.startsWith("/") ||
18
+ source.startsWith("./") ||
19
+ source.startsWith("../") ||
20
+ source.startsWith("\\") ||
21
+ source.startsWith(".\\") ||
22
+ (source.includes(":\\") && source.includes("\\")) || // Windows absolute path with backslash
23
+ (source.includes(":") &&
24
+ (source.startsWith("file:") || source.includes(":\\"))) // Path with protocol or Windows drive letter
25
+ ) {
26
+ return "local";
27
+ }
28
+ // Check if it's an npm package with a direct node_modules reference
29
+ const packageName = source.split(/[/\\]/)[0]; // Support both slash types
30
+ if (fs_extra_1.default.existsSync(node_path_1.default.resolve(process.cwd(), "node_modules", packageName))) {
31
+ return "npm";
32
+ }
33
+ // Try to interpret as npm package
34
+ try {
35
+ require.resolve(packageName, { paths: [process.cwd()] });
36
+ return "npm";
37
+ }
38
+ catch (_a) {
39
+ // If we couldn't resolve it as an npm package, assume it's a local path
40
+ return "local";
41
+ }
42
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Get the IDE-specific rule installation paths
3
+ */
4
+ export declare function getIdePaths(): Record<string, string>;
5
+ /**
6
+ * Check if a rule is installed in the specified IDEs
7
+ */
8
+ export declare function checkRuleStatus(ruleName: string, ruleType: string, ides: string[]): boolean;
@@ -0,0 +1,47 @@
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.getIdePaths = getIdePaths;
7
+ exports.checkRuleStatus = checkRuleStatus;
8
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ /**
11
+ * Get the IDE-specific rule installation paths
12
+ */
13
+ function getIdePaths() {
14
+ const projectDir = process.cwd(); // Get current working directory (project root)
15
+ return {
16
+ cursor: node_path_1.default.join(projectDir, ".cursor", "rules"),
17
+ windsurf: node_path_1.default.join(projectDir, ".rules"),
18
+ };
19
+ }
20
+ /**
21
+ * Check if a rule is installed in the specified IDEs
22
+ */
23
+ function checkRuleStatus(ruleName, ruleType, ides) {
24
+ const idePaths = getIdePaths();
25
+ // Check if rule is installed in all specified IDEs
26
+ return ides.every((ide) => {
27
+ if (!idePaths[ide]) {
28
+ return false;
29
+ }
30
+ if (ide === "cursor") {
31
+ return fs_extra_1.default.existsSync(node_path_1.default.join(idePaths[ide], `${ruleName}.mdc`));
32
+ }
33
+ if (ide === "windsurf") {
34
+ // For Windsurf, check if the rule exists in .rules directory
35
+ // and if it's referenced in .windsurfrules
36
+ const ruleExists = fs_extra_1.default.existsSync(node_path_1.default.join(idePaths[ide], `${ruleName}.md`));
37
+ // Check if .windsurfrules exists and contains a reference to this rule
38
+ const windsurfRulesPath = node_path_1.default.join(process.cwd(), ".windsurfrules");
39
+ if (fs_extra_1.default.existsSync(windsurfRulesPath)) {
40
+ const windsurfRulesContent = fs_extra_1.default.readFileSync(windsurfRulesPath, "utf8");
41
+ return (ruleExists && windsurfRulesContent.includes(`.rules/${ruleName}.md`));
42
+ }
43
+ return false;
44
+ }
45
+ return false;
46
+ });
47
+ }
@@ -0,0 +1,6 @@
1
+ import { RuleCollection } from "../types";
2
+ /**
3
+ * Write all collected rules to their respective IDE targets
4
+ * @param collection The collection of rules to write
5
+ */
6
+ export declare function writeRulesToTargets(collection: RuleCollection): void;
@@ -0,0 +1,68 @@
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.writeRulesToTargets = writeRulesToTargets;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const rule_status_1 = require("./rule-status");
10
+ const windsurf_writer_1 = require("./windsurf-writer");
11
+ /**
12
+ * Write all collected rules to their respective IDE targets
13
+ * @param collection The collection of rules to write
14
+ */
15
+ function writeRulesToTargets(collection) {
16
+ const idePaths = (0, rule_status_1.getIdePaths)();
17
+ // Write Cursor rules
18
+ if (collection.cursor.length > 0) {
19
+ writeCursorRules(collection.cursor, idePaths.cursor);
20
+ }
21
+ // Write Windsurf rules
22
+ if (collection.windsurf.length > 0) {
23
+ writeWindsurfRulesFromCollection(collection.windsurf);
24
+ }
25
+ }
26
+ /**
27
+ * Write rules to Cursor's rules directory
28
+ * @param rules The rules to write
29
+ * @param cursorRulesDir The path to Cursor's rules directory
30
+ */
31
+ function writeCursorRules(rules, cursorRulesDir) {
32
+ fs_extra_1.default.ensureDirSync(cursorRulesDir);
33
+ for (const rule of rules) {
34
+ const ruleFile = node_path_1.default.join(cursorRulesDir, `${rule.name}.mdc`);
35
+ // For Cursor, we either copy the file or create a symlink to the original
36
+ if (fs_extra_1.default.existsSync(rule.sourcePath)) {
37
+ // Copy the file (safer than symlink)
38
+ fs_extra_1.default.copyFileSync(rule.sourcePath, ruleFile);
39
+ }
40
+ else {
41
+ // If source path doesn't exist (shouldn't happen), write content directly
42
+ const mdcContent = `---\n${JSON.stringify(rule.metadata, null, 2)}\n---\n\n${rule.content}`;
43
+ fs_extra_1.default.writeFileSync(ruleFile, mdcContent);
44
+ }
45
+ }
46
+ }
47
+ /**
48
+ * Write rules to Windsurf's rules directory and update .windsurfrules file
49
+ * @param rules The rules to write
50
+ */
51
+ function writeWindsurfRulesFromCollection(rules) {
52
+ const idePaths = (0, rule_status_1.getIdePaths)();
53
+ const ruleDir = idePaths.windsurf;
54
+ fs_extra_1.default.ensureDirSync(ruleDir);
55
+ // First write individual rule files
56
+ const ruleFiles = rules.map((rule) => {
57
+ const ruleFile = node_path_1.default.join(ruleDir, `${rule.name}.md`);
58
+ fs_extra_1.default.writeFileSync(ruleFile, rule.content);
59
+ return {
60
+ name: rule.name,
61
+ path: `.rules/${rule.name}.md`,
62
+ metadata: rule.metadata,
63
+ };
64
+ });
65
+ // Then generate and write the .windsurfrules file
66
+ const windsurfRulesContent = (0, windsurf_writer_1.generateWindsurfRulesContent)(ruleFiles);
67
+ (0, windsurf_writer_1.writeWindsurfRules)(windsurfRulesContent);
68
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Write rules to the .windsurfrules file
3
+ * This will update the content between the RULES_BEGIN and RULES_END markers
4
+ * If the file doesn't exist, it will create it
5
+ * If the markers don't exist, it will append them to the existing content
6
+ */
7
+ export declare function writeWindsurfRules(rulesContent: string, rulesFilePath?: string): void;
8
+ /**
9
+ * Generate the Windsurf rules content based on rule files
10
+ */
11
+ export declare function generateWindsurfRulesContent(ruleFiles: {
12
+ name: string;
13
+ path: string;
14
+ metadata: Record<string, string | boolean | string[]>;
15
+ }[]): string;