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,137 @@
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 = "<!-- RULES-MANAGER:BEGIN -->";
11
+ const RULES_END = "<!-- RULES-MANAGER: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
+ }
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "aicm",
3
+ "version": "0.1.0",
4
+ "description": "A TypeScript CLI tool for managing AI IDE rules across different projects and teams",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "rules-manager": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "watch": "tsc --watch",
17
+ "start": "node dist/index.js",
18
+ "dev": "ts-node src/index.ts",
19
+ "test": "jest",
20
+ "test:watch": "jest --watch",
21
+ "test:all": "npm run build && npm run test",
22
+ "test:unit": "jest --config jest.unit.config.js",
23
+ "test:e2e": "jest tests/e2e",
24
+ "format": "prettier --write .",
25
+ "format:check": "prettier --check .",
26
+ "lint": "eslint",
27
+ "prepare": "husky && npx ts-node src/index.ts install",
28
+ "version": "auto-changelog -p && git add CHANGELOG.md"
29
+ },
30
+ "keywords": [
31
+ "ai",
32
+ "ide",
33
+ "rules",
34
+ "cursor",
35
+ "cli"
36
+ ],
37
+ "author": "Ran Yitzhaki <ranyitz@gmail.com>",
38
+ "license": "MIT",
39
+ "dependencies": {
40
+ "arg": "^5.0.2",
41
+ "args": "^5.0.3",
42
+ "chalk": "^4.1.2",
43
+ "fs-extra": "^11.1.1"
44
+ },
45
+ "devDependencies": {
46
+ "@eslint/js": "^9.26.0",
47
+ "@types/fs-extra": "^11.0.4",
48
+ "@types/jest": "^29.5.8",
49
+ "@types/node": "^20.9.0",
50
+ "auto-changelog": "^2.5.0",
51
+ "eslint": "^9.26.0",
52
+ "husky": "^8.0.3",
53
+ "jest": "^29.7.0",
54
+ "lint-staged": "^15.2.0",
55
+ "mock-fs": "^5.2.0",
56
+ "nock": "^13.3.8",
57
+ "prettier": "^3.1.0",
58
+ "rimraf": "^5.0.5",
59
+ "ts-jest": "^29.1.1",
60
+ "ts-node": "^10.9.1",
61
+ "typescript": "^5.8.3",
62
+ "typescript-eslint": "^8.31.1"
63
+ },
64
+ "lint-staged": {
65
+ "*.{js,ts,json,md,mjs}": "prettier --write",
66
+ "*.ts": "eslint"
67
+ }
68
+ }