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.
- package/README.md +26 -11
- package/dist/api.d.ts +2 -2
- package/dist/bin/aicm.d.ts +2 -0
- package/dist/bin/aicm.js +5 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +91 -0
- package/dist/commands/init.js +0 -3
- package/dist/commands/install/install-package.d.ts +53 -0
- package/dist/commands/install/install-package.js +122 -0
- package/dist/commands/install/install-single-package.d.ts +53 -0
- package/dist/commands/install/install-single-package.js +139 -0
- package/dist/commands/install/install-workspaces.d.ts +9 -0
- package/dist/commands/install/install-workspaces.js +172 -0
- package/dist/commands/install.d.ts +2 -48
- package/dist/commands/install.js +28 -202
- package/dist/commands/workspaces/workspaces-install.js +2 -0
- package/dist/index.js +0 -0
- package/dist/types/index.d.ts +9 -4
- package/dist/utils/config.d.ts +7 -6
- package/dist/utils/config.js +20 -8
- package/dist/utils/mcp-writer.d.ts +3 -3
- package/dist/utils/working-directory.d.ts +5 -0
- package/dist/utils/working-directory.js +21 -0
- package/package.json +20 -19
- package/dist/commands/monorepo/discovery.d.ts +0 -7
- package/dist/commands/monorepo/discovery.js +0 -50
- package/dist/commands/monorepo/installer.d.ts +0 -9
- package/dist/commands/monorepo/installer.js +0 -70
- package/dist/commands/monorepo/monorepo-install.d.ts +0 -9
- package/dist/commands/monorepo/monorepo-install.js +0 -46
- package/dist/commands/monorepo/types.d.ts +0 -1
- package/dist/commands/monorepo/types.js +0 -17
- package/dist/utils/package-detector.d.ts +0 -6
- package/dist/utils/package-detector.js +0 -25
- package/dist/utils/windsurf-writer.d.ts +0 -15
- package/dist/utils/windsurf-writer.js +0 -137
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withWorkingDirectory = withWorkingDirectory;
|
|
4
|
+
/**
|
|
5
|
+
* Helper function to execute a function within a specific working directory
|
|
6
|
+
* and ensure the original directory is always restored
|
|
7
|
+
*/
|
|
8
|
+
async function withWorkingDirectory(targetDir, fn) {
|
|
9
|
+
const originalCwd = process.cwd();
|
|
10
|
+
if (targetDir !== originalCwd) {
|
|
11
|
+
process.chdir(targetDir);
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
return await fn();
|
|
15
|
+
}
|
|
16
|
+
finally {
|
|
17
|
+
if (targetDir !== originalCwd) {
|
|
18
|
+
process.chdir(originalCwd);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,33 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aicm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "A TypeScript CLI tool for managing AI IDE rules across different projects and teams",
|
|
5
5
|
"main": "dist/api.js",
|
|
6
6
|
"types": "dist/api.d.ts",
|
|
7
7
|
"bin": {
|
|
8
|
-
"aicm": "./dist/
|
|
8
|
+
"aicm": "./dist/bin/aicm.js"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
12
12
|
"README.md",
|
|
13
13
|
"LICENSE"
|
|
14
14
|
],
|
|
15
|
-
"scripts": {
|
|
16
|
-
"build": "tsc",
|
|
17
|
-
"watch": "tsc --watch",
|
|
18
|
-
"start": "node dist/index.js",
|
|
19
|
-
"dev": "ts-node src/index.ts",
|
|
20
|
-
"test": "jest",
|
|
21
|
-
"test:watch": "jest --watch",
|
|
22
|
-
"test:all": "npm run build && npm run test",
|
|
23
|
-
"test:unit": "jest --config jest.unit.config.js",
|
|
24
|
-
"test:e2e": "jest tests/e2e",
|
|
25
|
-
"format": "prettier --write .",
|
|
26
|
-
"format:check": "prettier --check .",
|
|
27
|
-
"lint": "eslint",
|
|
28
|
-
"prepare": "husky install && npx ts-node src/index.ts install",
|
|
29
|
-
"version": "auto-changelog -p && git add CHANGELOG.md"
|
|
30
|
-
},
|
|
31
15
|
"keywords": [
|
|
32
16
|
"ai",
|
|
33
17
|
"ide",
|
|
@@ -58,6 +42,7 @@
|
|
|
58
42
|
"lint-staged": "^15.2.0",
|
|
59
43
|
"mock-fs": "^5.2.0",
|
|
60
44
|
"nock": "^13.3.8",
|
|
45
|
+
"np": "^10.2.0",
|
|
61
46
|
"prettier": "^3.1.0",
|
|
62
47
|
"rimraf": "^5.0.5",
|
|
63
48
|
"ts-jest": "^29.1.1",
|
|
@@ -68,5 +53,21 @@
|
|
|
68
53
|
"lint-staged": {
|
|
69
54
|
"*.{js,ts,json,md,mjs}": "prettier --write",
|
|
70
55
|
"*.ts": "eslint"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsc",
|
|
59
|
+
"watch": "tsc --watch",
|
|
60
|
+
"start": "node dist/bin/aicm.js",
|
|
61
|
+
"dev": "ts-node src/bin/aicm.ts",
|
|
62
|
+
"test": "jest",
|
|
63
|
+
"test:watch": "jest --watch",
|
|
64
|
+
"test:all": "npm run build && npm run test",
|
|
65
|
+
"test:unit": "jest --config jest.unit.config.js",
|
|
66
|
+
"test:e2e": "jest tests/e2e",
|
|
67
|
+
"format": "prettier --write .",
|
|
68
|
+
"format:check": "prettier --check .",
|
|
69
|
+
"lint": "eslint",
|
|
70
|
+
"version": "auto-changelog -p && git add CHANGELOG.md",
|
|
71
|
+
"release": "np"
|
|
71
72
|
}
|
|
72
|
-
}
|
|
73
|
+
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { PackageInfo } from "../../types";
|
|
2
|
-
/**
|
|
3
|
-
* Discover all packages with aicm configurations in a monorepo
|
|
4
|
-
* @param rootDir The root directory to search from
|
|
5
|
-
* @returns Array of discovered packages
|
|
6
|
-
*/
|
|
7
|
-
export declare function discoverPackagesWithAicm(rootDir: string): Promise<PackageInfo[]>;
|
|
@@ -1,50 +0,0 @@
|
|
|
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.discoverPackagesWithAicm = discoverPackagesWithAicm;
|
|
7
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
-
const node_child_process_1 = require("node:child_process");
|
|
9
|
-
const config_1 = require("../../utils/config");
|
|
10
|
-
/**
|
|
11
|
-
* Discover aicm.json files using git ls-files
|
|
12
|
-
* @param rootDir The root directory to search from
|
|
13
|
-
* @returns Array of aicm.json file paths
|
|
14
|
-
*/
|
|
15
|
-
function findAicmFiles(rootDir) {
|
|
16
|
-
const output = (0, node_child_process_1.execSync)("git ls-files --cached --others --exclude-standard aicm.json **/aicm.json", {
|
|
17
|
-
cwd: rootDir,
|
|
18
|
-
encoding: "utf8",
|
|
19
|
-
});
|
|
20
|
-
return output
|
|
21
|
-
.trim()
|
|
22
|
-
.split("\n")
|
|
23
|
-
.filter(Boolean)
|
|
24
|
-
.map((file) => node_path_1.default.resolve(rootDir, file));
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Discover all packages with aicm configurations in a monorepo
|
|
28
|
-
* @param rootDir The root directory to search from
|
|
29
|
-
* @returns Array of discovered packages
|
|
30
|
-
*/
|
|
31
|
-
async function discoverPackagesWithAicm(rootDir) {
|
|
32
|
-
const aicmFiles = findAicmFiles(rootDir);
|
|
33
|
-
const packages = [];
|
|
34
|
-
for (const aicmFile of aicmFiles) {
|
|
35
|
-
const packageDir = node_path_1.default.dirname(aicmFile);
|
|
36
|
-
const relativePath = node_path_1.default.relative(rootDir, packageDir);
|
|
37
|
-
// Normalize to forward slashes for cross-platform compatibility
|
|
38
|
-
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
39
|
-
const config = (0, config_1.getConfig)(packageDir);
|
|
40
|
-
if (config) {
|
|
41
|
-
packages.push({
|
|
42
|
-
relativePath: normalizedRelativePath || ".",
|
|
43
|
-
absolutePath: packageDir,
|
|
44
|
-
config,
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
// Sort packages by relativePath for deterministic order
|
|
49
|
-
return packages.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
50
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { PackageInfo, MonorepoInstallResult } from "./types";
|
|
2
|
-
import { InstallOptions } from "../install";
|
|
3
|
-
/**
|
|
4
|
-
* Install aicm configurations for all packages in a monorepo
|
|
5
|
-
* @param packages The packages to install configurations for
|
|
6
|
-
* @param options Install options
|
|
7
|
-
* @returns Result of the monorepo installation
|
|
8
|
-
*/
|
|
9
|
-
export declare function installMonorepoPackages(packages: PackageInfo[], options?: InstallOptions): Promise<MonorepoInstallResult>;
|
|
@@ -1,70 +0,0 @@
|
|
|
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.installMonorepoPackages = installMonorepoPackages;
|
|
7
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
-
const install_1 = require("../install");
|
|
10
|
-
/**
|
|
11
|
-
* Install aicm configurations for all packages in a monorepo
|
|
12
|
-
* @param packages The packages to install configurations for
|
|
13
|
-
* @param options Install options
|
|
14
|
-
* @returns Result of the monorepo installation
|
|
15
|
-
*/
|
|
16
|
-
async function installMonorepoPackages(packages, options = {}) {
|
|
17
|
-
console.log(chalk_1.default.blue(`📦 Installing configurations...`));
|
|
18
|
-
const results = [];
|
|
19
|
-
let totalRuleCount = 0;
|
|
20
|
-
// Install packages sequentially for now (can be parallelized later)
|
|
21
|
-
for (const pkg of packages) {
|
|
22
|
-
const packagePath = node_path_1.default.resolve(process.cwd(), pkg.path);
|
|
23
|
-
try {
|
|
24
|
-
console.log(chalk_1.default.gray(` Installing ${pkg.path}...`));
|
|
25
|
-
const result = await (0, install_1.install)({
|
|
26
|
-
...options,
|
|
27
|
-
cwd: packagePath,
|
|
28
|
-
});
|
|
29
|
-
if (result.success) {
|
|
30
|
-
console.log(chalk_1.default.green(`✅ ${pkg.path} (${result.installedRuleCount} rules)`));
|
|
31
|
-
totalRuleCount += result.installedRuleCount;
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
console.log(chalk_1.default.red(`❌ ${pkg.path}: ${result.error}`));
|
|
35
|
-
}
|
|
36
|
-
results.push({
|
|
37
|
-
path: pkg.path,
|
|
38
|
-
success: result.success,
|
|
39
|
-
error: result.error,
|
|
40
|
-
installedRuleCount: result.installedRuleCount,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
catch (error) {
|
|
44
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
45
|
-
console.log(chalk_1.default.red(`❌ ${pkg.path}: ${errorMessage}`));
|
|
46
|
-
results.push({
|
|
47
|
-
path: pkg.path,
|
|
48
|
-
success: false,
|
|
49
|
-
error: errorMessage,
|
|
50
|
-
installedRuleCount: 0,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
const successfulPackages = results.filter((r) => r.success);
|
|
55
|
-
const failedPackages = results.filter((r) => !r.success);
|
|
56
|
-
// Print summary
|
|
57
|
-
if (failedPackages.length > 0) {
|
|
58
|
-
console.log(chalk_1.default.yellow(`\n⚠️ Installation completed with errors`));
|
|
59
|
-
console.log(chalk_1.default.green(`Successfully installed: ${successfulPackages.length}/${packages.length} packages (${totalRuleCount} rules total)`));
|
|
60
|
-
console.log(chalk_1.default.red(`Failed packages: ${failedPackages.map((p) => p.path).join(", ")}`));
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
console.log(chalk_1.default.green(`\n🎉 Successfully installed ${totalRuleCount} rules across ${packages.length} packages`));
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
success: failedPackages.length === 0,
|
|
67
|
-
packages: results,
|
|
68
|
-
totalRuleCount,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { PackageInfo, MonorepoInstallResult } from "../../types";
|
|
2
|
-
import { InstallOptions } from "../install";
|
|
3
|
-
/**
|
|
4
|
-
* Install aicm configurations for all packages in a monorepo
|
|
5
|
-
* @param packages The packages to install configurations for
|
|
6
|
-
* @param options Install options
|
|
7
|
-
* @returns Result of the monorepo installation
|
|
8
|
-
*/
|
|
9
|
-
export declare function installMonorepoPackages(packages: PackageInfo[], options?: InstallOptions): Promise<MonorepoInstallResult>;
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.installMonorepoPackages = installMonorepoPackages;
|
|
4
|
-
const install_1 = require("../install");
|
|
5
|
-
/**
|
|
6
|
-
* Install aicm configurations for all packages in a monorepo
|
|
7
|
-
* @param packages The packages to install configurations for
|
|
8
|
-
* @param options Install options
|
|
9
|
-
* @returns Result of the monorepo installation
|
|
10
|
-
*/
|
|
11
|
-
async function installMonorepoPackages(packages, options = {}) {
|
|
12
|
-
const results = [];
|
|
13
|
-
let totalRuleCount = 0;
|
|
14
|
-
// Install packages sequentially for now (can be parallelized later)
|
|
15
|
-
for (const pkg of packages) {
|
|
16
|
-
const packagePath = pkg.absolutePath;
|
|
17
|
-
try {
|
|
18
|
-
const result = await (0, install_1.install)({
|
|
19
|
-
...options,
|
|
20
|
-
cwd: packagePath,
|
|
21
|
-
});
|
|
22
|
-
totalRuleCount += result.installedRuleCount;
|
|
23
|
-
results.push({
|
|
24
|
-
path: pkg.relativePath,
|
|
25
|
-
success: result.success,
|
|
26
|
-
error: result.error,
|
|
27
|
-
installedRuleCount: result.installedRuleCount,
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
catch (error) {
|
|
31
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
32
|
-
results.push({
|
|
33
|
-
path: pkg.relativePath,
|
|
34
|
-
success: false,
|
|
35
|
-
error: errorMessage,
|
|
36
|
-
installedRuleCount: 0,
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
const failedPackages = results.filter((r) => !r.success);
|
|
41
|
-
return {
|
|
42
|
-
success: failedPackages.length === 0,
|
|
43
|
-
packages: results,
|
|
44
|
-
totalRuleCount,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "../../types";
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("../../types"), exports);
|
|
@@ -1,25 +0,0 @@
|
|
|
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.detectPackageType = detectPackageType;
|
|
7
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
-
/**
|
|
10
|
-
* Detect the type of package based on files present in the directory
|
|
11
|
-
* @param packageDir The directory to check
|
|
12
|
-
* @returns The detected package type
|
|
13
|
-
*/
|
|
14
|
-
function detectPackageType(packageDir) {
|
|
15
|
-
// Check for npm package
|
|
16
|
-
if (fs_extra_1.default.existsSync(node_path_1.default.join(packageDir, "package.json"))) {
|
|
17
|
-
return "npm";
|
|
18
|
-
}
|
|
19
|
-
// Check for Bazel package
|
|
20
|
-
if (fs_extra_1.default.existsSync(node_path_1.default.join(packageDir, "BUILD")) ||
|
|
21
|
-
fs_extra_1.default.existsSync(node_path_1.default.join(packageDir, "BUILD.bazel"))) {
|
|
22
|
-
return "bazel";
|
|
23
|
-
}
|
|
24
|
-
return "unknown";
|
|
25
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
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;
|
|
@@ -1,137 +0,0 @@
|
|
|
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.writeWindsurfRules = writeWindsurfRules;
|
|
7
|
-
exports.generateWindsurfRulesContent = generateWindsurfRulesContent;
|
|
8
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
-
const path_1 = __importDefault(require("path"));
|
|
10
|
-
const RULES_BEGIN = "<!-- AICM:BEGIN -->";
|
|
11
|
-
const RULES_END = "<!-- AICM:END -->";
|
|
12
|
-
const WARNING = "<!-- WARNING: Everything between these markers will be overwritten during installation -->";
|
|
13
|
-
/**
|
|
14
|
-
* Create a formatted block of content with rules markers
|
|
15
|
-
*/
|
|
16
|
-
function createRulesBlock(rulesContent) {
|
|
17
|
-
return `${RULES_BEGIN}
|
|
18
|
-
${WARNING}
|
|
19
|
-
|
|
20
|
-
${rulesContent}
|
|
21
|
-
|
|
22
|
-
${RULES_END}`;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Write rules to the .windsurfrules file
|
|
26
|
-
* This will update the content between the RULES_BEGIN and RULES_END markers
|
|
27
|
-
* If the file doesn't exist, it will create it
|
|
28
|
-
* If the markers don't exist, it will append them to the existing content
|
|
29
|
-
*/
|
|
30
|
-
function writeWindsurfRules(rulesContent, rulesFilePath = path_1.default.join(process.cwd(), ".windsurfrules")) {
|
|
31
|
-
let fileContent;
|
|
32
|
-
const formattedRulesBlock = createRulesBlock(rulesContent);
|
|
33
|
-
// Check if file exists
|
|
34
|
-
if (fs_extra_1.default.existsSync(rulesFilePath)) {
|
|
35
|
-
const existingContent = fs_extra_1.default.readFileSync(rulesFilePath, "utf8");
|
|
36
|
-
// Check if our markers exist
|
|
37
|
-
if (existingContent.includes(RULES_BEGIN) &&
|
|
38
|
-
existingContent.includes(RULES_END)) {
|
|
39
|
-
// Replace content between markers
|
|
40
|
-
const beforeMarker = existingContent.split(RULES_BEGIN)[0];
|
|
41
|
-
const afterMarker = existingContent.split(RULES_END)[1];
|
|
42
|
-
fileContent = beforeMarker + formattedRulesBlock + afterMarker;
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
// Preserve the existing content and append markers
|
|
46
|
-
// Ensure there's proper spacing between existing content and markers
|
|
47
|
-
let separator = "";
|
|
48
|
-
if (!existingContent.endsWith("\n")) {
|
|
49
|
-
separator += "\n";
|
|
50
|
-
}
|
|
51
|
-
// Add an extra line if the file doesn't already end with multiple newlines
|
|
52
|
-
if (!existingContent.endsWith("\n\n")) {
|
|
53
|
-
separator += "\n";
|
|
54
|
-
}
|
|
55
|
-
// Create the new file content with preserved original content
|
|
56
|
-
fileContent = existingContent + separator + formattedRulesBlock;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
// Create new file with markers and content
|
|
61
|
-
fileContent = formattedRulesBlock;
|
|
62
|
-
}
|
|
63
|
-
fs_extra_1.default.writeFileSync(rulesFilePath, fileContent);
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Generate the Windsurf rules content based on rule files
|
|
67
|
-
*/
|
|
68
|
-
function generateWindsurfRulesContent(ruleFiles) {
|
|
69
|
-
const alwaysRules = [];
|
|
70
|
-
const autoAttachedRules = [];
|
|
71
|
-
const agentRequestedRules = [];
|
|
72
|
-
const manualRules = [];
|
|
73
|
-
ruleFiles.forEach(({ path, metadata }) => {
|
|
74
|
-
// Determine rule type based on metadata
|
|
75
|
-
if (metadata.type === "always" ||
|
|
76
|
-
metadata.alwaysApply === true ||
|
|
77
|
-
metadata.alwaysApply === "true") {
|
|
78
|
-
alwaysRules.push(path);
|
|
79
|
-
}
|
|
80
|
-
else if (metadata.type === "auto-attached" || metadata.globs) {
|
|
81
|
-
const globPattern = typeof metadata.globs === "string" || Array.isArray(metadata.globs)
|
|
82
|
-
? Array.isArray(metadata.globs)
|
|
83
|
-
? metadata.globs.join(", ")
|
|
84
|
-
: metadata.globs
|
|
85
|
-
: undefined;
|
|
86
|
-
if (globPattern !== undefined) {
|
|
87
|
-
autoAttachedRules.push({ path, glob: globPattern });
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
else if (metadata.type === "agent-requested" || metadata.description) {
|
|
91
|
-
agentRequestedRules.push(path);
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
// Default to manual inclusion
|
|
95
|
-
manualRules.push(path);
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
// Generate the content
|
|
99
|
-
let content = "";
|
|
100
|
-
// Always rules
|
|
101
|
-
if (alwaysRules.length > 0) {
|
|
102
|
-
content +=
|
|
103
|
-
"The following rules always apply to all files in the project:\n";
|
|
104
|
-
alwaysRules.forEach((rule) => {
|
|
105
|
-
content += `- ${rule}\n`;
|
|
106
|
-
});
|
|
107
|
-
content += "\n";
|
|
108
|
-
}
|
|
109
|
-
// Auto Attached rules
|
|
110
|
-
if (autoAttachedRules.length > 0) {
|
|
111
|
-
content +=
|
|
112
|
-
"The following rules are automatically attached to matching glob patterns:\n";
|
|
113
|
-
autoAttachedRules.forEach((rule) => {
|
|
114
|
-
content += `- [${rule.glob}] ${rule.path}\n`;
|
|
115
|
-
});
|
|
116
|
-
content += "\n";
|
|
117
|
-
}
|
|
118
|
-
// Agent Requested rules
|
|
119
|
-
if (agentRequestedRules.length > 0) {
|
|
120
|
-
content +=
|
|
121
|
-
"The following rules are available for the AI to include when needed:\n";
|
|
122
|
-
agentRequestedRules.forEach((rule) => {
|
|
123
|
-
content += `- ${rule}\n`;
|
|
124
|
-
});
|
|
125
|
-
content += "\n";
|
|
126
|
-
}
|
|
127
|
-
// Manual rules
|
|
128
|
-
if (manualRules.length > 0) {
|
|
129
|
-
content +=
|
|
130
|
-
"The following rules are only included when explicitly referenced:\n";
|
|
131
|
-
manualRules.forEach((rule) => {
|
|
132
|
-
content += `- ${rule}\n`;
|
|
133
|
-
});
|
|
134
|
-
content += "\n";
|
|
135
|
-
}
|
|
136
|
-
return content.trim();
|
|
137
|
-
}
|