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.
- package/LICENSE +21 -0
- package/README.md +232 -0
- package/dist/commands/check-updates.d.ts +6 -0
- package/dist/commands/check-updates.js +84 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +31 -0
- package/dist/commands/install.d.ts +1 -0
- package/dist/commands/install.js +152 -0
- package/dist/commands/list.d.ts +1 -0
- package/dist/commands/list.js +37 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +69 -0
- package/dist/types/index.d.ts +26 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/config.d.ts +21 -0
- package/dist/utils/config.js +155 -0
- package/dist/utils/mdc-parser.d.ts +9 -0
- package/dist/utils/mdc-parser.js +59 -0
- package/dist/utils/rule-collector.d.ts +33 -0
- package/dist/utils/rule-collector.js +160 -0
- package/dist/utils/rule-detector.d.ts +4 -0
- package/dist/utils/rule-detector.js +42 -0
- package/dist/utils/rule-status.d.ts +8 -0
- package/dist/utils/rule-status.js +47 -0
- package/dist/utils/rule-writer.d.ts +6 -0
- package/dist/utils/rule-writer.js +68 -0
- package/dist/utils/windsurf-writer.d.ts +15 -0
- package/dist/utils/windsurf-writer.js +137 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# 📜 rules-manager
|
|
2
|
+
|
|
3
|
+
A CLI tool for syncing AI IDE rules across projects
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
Development teams struggle with:
|
|
8
|
+
|
|
9
|
+
- **Inconsistent Practices**: Developers apply varying standards across projects
|
|
10
|
+
- **Knowledge Silos**: Best practices remain trapped in individual projects
|
|
11
|
+
- **Change Management**: No efficient way to update and distribute new standards
|
|
12
|
+
|
|
13
|
+
As developers increasingly adopt AI-powered IDEs like Cursor and Windsurf, we have an opportunity to enforce best practices through "rules." However, these rules are typically isolated within individual developers or projects.
|
|
14
|
+
|
|
15
|
+
**rules-manager** is a CLI tool that helps streamline rule management:
|
|
16
|
+
|
|
17
|
+
- 🏛️ **Single Source of Truth**: Define, maintain and version-control all AI IDE rules in one central repository
|
|
18
|
+
- 📦 **Seamless Distribution**: Automatically synchronize the latest rules to developers' local projects using npm packages
|
|
19
|
+
- 🌐 **Cross-IDE Support**: Supports multiple AI-powered IDEs (Cursor, Windsurf)
|
|
20
|
+
|
|
21
|
+
## Getting Started
|
|
22
|
+
|
|
23
|
+
To get automatic rule updates from NPM Packages, you can create, publish, and use dedicated npm packages to distribute AI rules across multiple projects.
|
|
24
|
+
|
|
25
|
+
Considering the following npm package:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
@myteam/ai-tools
|
|
29
|
+
├── package.json
|
|
30
|
+
└── rules/
|
|
31
|
+
├── typescript.mdc
|
|
32
|
+
├── react.mdc
|
|
33
|
+
└── general.mdc
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
1. **Point to the path within the npm package**
|
|
37
|
+
|
|
38
|
+
In your project's `rules.json`, reference the package and the specific rule:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"ides": ["cursor"],
|
|
43
|
+
"rules": {
|
|
44
|
+
"typescript": "@myteam/ai-tools/rules/typescript.mdc",
|
|
45
|
+
"react": "@myteam/ai-tools/rules/react.mdc",
|
|
46
|
+
"general": "@myteam/ai-tools/rules/general.mdc"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
2. **Add a postinstall script** to your `package.json`:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"scripts": {
|
|
56
|
+
"postinstall": "npx -y rules-manager install"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Now the rules will be linked to `.cursor/rules/` when you run `npm install`.
|
|
62
|
+
|
|
63
|
+
### Using Presets
|
|
64
|
+
|
|
65
|
+
Presets allow you to bundle multiple rules into a single configuration that can be shared across projects.
|
|
66
|
+
|
|
67
|
+
1. **Create a preset file**
|
|
68
|
+
|
|
69
|
+
Create a JSON file with your rule definitions:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"rules": {
|
|
74
|
+
"typescript": "./rules/typescript.mdc",
|
|
75
|
+
"react": "./rules/react.mdc"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
2. **Reference the preset in your project**
|
|
81
|
+
|
|
82
|
+
In your project's `rules.json`, reference the preset:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"ides": ["cursor"],
|
|
87
|
+
"presets": ["@myteam/ai-tools/my-rule.json"]
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
When you run `npx rules-manager install`, all rules from the preset will be installed to `.cursor/rules/`.
|
|
92
|
+
|
|
93
|
+
### Demo
|
|
94
|
+
|
|
95
|
+
Here is a package to demonstrate how rules manager works:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Install a package containing a rule
|
|
99
|
+
npm install --save-dev pirate-coding-rule
|
|
100
|
+
|
|
101
|
+
# Install the rule via the rules-manager CLI
|
|
102
|
+
npx -y rules-manager install pirate-coding pirate-coding-rule/rule.mdc
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
This command will:
|
|
106
|
+
|
|
107
|
+
1. Create a `rules.json` file if it doesn't exist
|
|
108
|
+
2. Add the rule to the configuration
|
|
109
|
+
3. Install the rule to `.cursor/rules/`
|
|
110
|
+
|
|
111
|
+
After installation, open Cursor and ask it to do something. Your AI assistant will respond with pirate-themed coding advice.
|
|
112
|
+
|
|
113
|
+
## Security Note
|
|
114
|
+
|
|
115
|
+
To prevent [prompt-injection](https://en.wikipedia.org/wiki/Prompt_injection), use only packages from trusted sources.
|
|
116
|
+
|
|
117
|
+
## Configuration
|
|
118
|
+
|
|
119
|
+
rules-manager uses a JSON configuration file (`rules.json`) in your project root directory.
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"ides": ["cursor"],
|
|
124
|
+
"presets": ["@my-team/ai-tools/my-rules.json"],
|
|
125
|
+
"rules": {
|
|
126
|
+
"team-standards": "@my-team/ai-tools/rules/team-standards.mdc"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
- **ides**: Array of IDE names where rules should be installed. Currently supported values:
|
|
132
|
+
|
|
133
|
+
- `"cursor"`: For the Cursor IDE
|
|
134
|
+
|
|
135
|
+
- **rules**: Object containing rule configurations
|
|
136
|
+
|
|
137
|
+
- **rule-name**: A unique identifier for the rule
|
|
138
|
+
- **source-location**: Location of the rule file (path within an npm package or local path)
|
|
139
|
+
|
|
140
|
+
- **presets**: Array of preset configurations to include. Each preset is a path to a JSON file (npm package or local path) that contains additional rules.
|
|
141
|
+
- Presets allow organizations to bundle a set of rules that can be easily shared across projects
|
|
142
|
+
- Preset files should contain a `rules` object with the same structure as the main configuration
|
|
143
|
+
|
|
144
|
+
### Rule Source Types
|
|
145
|
+
|
|
146
|
+
The type of rule is automatically detected based on the source format:
|
|
147
|
+
|
|
148
|
+
#### NPM Source
|
|
149
|
+
|
|
150
|
+
Rules provided by NPM packages. The package must be installed either globally or in your project's `node_modules`. Sources that start with `@` or don't contain start with path separators are detected as NPM packages.
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
"react-best-practices": "@my-team/ai-tools/rules-manager-react"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### Local Source
|
|
157
|
+
|
|
158
|
+
Rules stored locally in your project or filesystem. Any path containing slashes or backslashes is detected as a local file path.
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
"personal-rules": "./rules/custom.mdc"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Supported IDEs
|
|
165
|
+
|
|
166
|
+
- **Cursor**: Rules are installed as individual `.mdc` files in the Cursor rules directory (`.cursor/rules/`)
|
|
167
|
+
- **Windsurf**: Rules are installed in the `.rules` directory which should be added to your `.gitignore` file. Our approach for Windsurf is to create links from the `.windsurfrules` file to the respective rules in the `.rules` directory.
|
|
168
|
+
|
|
169
|
+
## Commands
|
|
170
|
+
|
|
171
|
+
### Global Options
|
|
172
|
+
|
|
173
|
+
These options are available for all commands:
|
|
174
|
+
|
|
175
|
+
- `--help`, `-h`: Show help information
|
|
176
|
+
- `--version`, `-v`: Show version information
|
|
177
|
+
|
|
178
|
+
### `init`
|
|
179
|
+
|
|
180
|
+
Initializes a new configuration file in your current directory.
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
npx rules-manager init
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### `install`
|
|
187
|
+
|
|
188
|
+
Installs rules from your configuration to the appropriate IDE locations.
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
npx rules-manager install [rule-name] [rule-source]
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Options:**
|
|
195
|
+
|
|
196
|
+
- `[rule-name]`: Optional - Name of a specific rule to install instead of all rules
|
|
197
|
+
- `[rule-source]`: Optional - Source of the rule (npm package or local path)
|
|
198
|
+
|
|
199
|
+
**Examples:**
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# Install all configured rules
|
|
203
|
+
npx -y rules-manager install
|
|
204
|
+
|
|
205
|
+
# Install a rule from an npm package and update configuration
|
|
206
|
+
npx -y rules-manager install react-best-practices @my-team/ai-tools/react-best-practices.mdc
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Contributing
|
|
210
|
+
|
|
211
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
212
|
+
|
|
213
|
+
## Development
|
|
214
|
+
|
|
215
|
+
### Testing
|
|
216
|
+
|
|
217
|
+
The project includes both unit tests and end-to-end (E2E) tests:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# Run all tests
|
|
221
|
+
npm test
|
|
222
|
+
|
|
223
|
+
# Run only unit tests
|
|
224
|
+
npm run test:unit
|
|
225
|
+
|
|
226
|
+
# Run only E2E tests
|
|
227
|
+
npm run test:e2e
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## License
|
|
231
|
+
|
|
232
|
+
MIT
|
|
@@ -0,0 +1,84 @@
|
|
|
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.checkUpdates = void 0;
|
|
7
|
+
exports.checkNpmPackageUpdates = checkNpmPackageUpdates;
|
|
8
|
+
const commander_1 = require("commander");
|
|
9
|
+
const config_1 = require("../utils/config");
|
|
10
|
+
const rule_detector_1 = require("../utils/rule-detector");
|
|
11
|
+
const semver_1 = __importDefault(require("semver"));
|
|
12
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
13
|
+
const child_process_1 = require("child_process");
|
|
14
|
+
const fs_1 = require("fs");
|
|
15
|
+
const path_1 = require("path");
|
|
16
|
+
exports.checkUpdates = new commander_1.Command("check-updates")
|
|
17
|
+
.description("Check for updates to installed rules")
|
|
18
|
+
.option("-a, --auto-sync", "Automatically sync updates if available")
|
|
19
|
+
.action(async (options) => {
|
|
20
|
+
const config = await (0, config_1.getConfig)();
|
|
21
|
+
if (!config) {
|
|
22
|
+
console.error("No configuration file found. Run 'rules-manager init' first.");
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
const updates = [];
|
|
26
|
+
const errors = [];
|
|
27
|
+
// Check each rule for updates
|
|
28
|
+
for (const [ruleName, source] of Object.entries(config.rules)) {
|
|
29
|
+
try {
|
|
30
|
+
const ruleType = (0, rule_detector_1.detectRuleType)(source);
|
|
31
|
+
if (ruleType === "npm") {
|
|
32
|
+
const { currentVersion, latestVersion } = await checkNpmPackageUpdates(source.split("/")[0] // Get package name from source
|
|
33
|
+
);
|
|
34
|
+
if (latestVersion && semver_1.default.gt(latestVersion, currentVersion)) {
|
|
35
|
+
updates.push({
|
|
36
|
+
name: ruleName,
|
|
37
|
+
current: currentVersion,
|
|
38
|
+
latest: latestVersion,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
45
|
+
errors.push(`Error checking updates for ${ruleName}: ${errorMessage}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Display results
|
|
49
|
+
if (updates.length > 0) {
|
|
50
|
+
console.log(chalk_1.default.yellow("\nUpdates available:"));
|
|
51
|
+
updates.forEach((update) => {
|
|
52
|
+
console.log(chalk_1.default.yellow(` ${update.name}: ${update.current} → ${update.latest}`));
|
|
53
|
+
});
|
|
54
|
+
if (options.autoSync) {
|
|
55
|
+
console.log(chalk_1.default.blue("\nAuto-syncing updates..."));
|
|
56
|
+
// Trigger install command with updated versions
|
|
57
|
+
// This will be implemented in the install command
|
|
58
|
+
process.exit(0);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
console.log(chalk_1.default.blue("\nRun 'rules-manager install --update' to install updates"));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
console.log(chalk_1.default.green("All rules are up to date!"));
|
|
66
|
+
}
|
|
67
|
+
if (errors.length > 0) {
|
|
68
|
+
console.error(chalk_1.default.red("\nErrors:"));
|
|
69
|
+
errors.forEach((error) => console.error(chalk_1.default.red(` ${error}`)));
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
async function checkNpmPackageUpdates(packageName) {
|
|
74
|
+
// Get current version from package.json
|
|
75
|
+
const packageJsonPath = (0, path_1.join)(process.cwd(), "node_modules", packageName, "package.json");
|
|
76
|
+
const packageJson = JSON.parse((0, fs_1.readFileSync)(packageJsonPath, "utf-8"));
|
|
77
|
+
const currentVersion = packageJson.version;
|
|
78
|
+
// Get latest version from npm registry
|
|
79
|
+
const stdout = (0, child_process_1.execSync)(`npm view ${packageName} version`, {
|
|
80
|
+
encoding: "utf-8",
|
|
81
|
+
});
|
|
82
|
+
const latestVersion = stdout.trim();
|
|
83
|
+
return { currentVersion, latestVersion };
|
|
84
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function initCommand(): void;
|
|
@@ -0,0 +1,31 @@
|
|
|
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.initCommand = initCommand;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const defaultConfig = {
|
|
11
|
+
ides: ["cursor"],
|
|
12
|
+
rules: {},
|
|
13
|
+
};
|
|
14
|
+
function initCommand() {
|
|
15
|
+
const configPath = path_1.default.join(process.cwd(), "rules.json");
|
|
16
|
+
if (fs_extra_1.default.existsSync(configPath)) {
|
|
17
|
+
console.log(chalk_1.default.yellow("Configuration file already exists!"));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
fs_extra_1.default.writeJsonSync(configPath, defaultConfig, { spaces: 2 });
|
|
22
|
+
console.log(chalk_1.default.green("Configuration file created successfully!"));
|
|
23
|
+
console.log(`Configuration file location: ${chalk_1.default.blue(configPath)}`);
|
|
24
|
+
console.log(`\nNext steps:`);
|
|
25
|
+
console.log(` 1. Edit ${chalk_1.default.blue("rules.json")} to configure your rules`);
|
|
26
|
+
console.log(` 2. Run ${chalk_1.default.blue("npx rules-manager install")} to install rules`);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error(chalk_1.default.red("Error creating configuration file:"), error);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function installCommand(): Promise<void>;
|
|
@@ -0,0 +1,152 @@
|
|
|
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.installCommand = installCommand;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const arg_1 = __importDefault(require("arg"));
|
|
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
|
+
// Default configuration
|
|
14
|
+
const defaultConfig = {
|
|
15
|
+
ides: ["cursor", "windsurf"],
|
|
16
|
+
rules: {},
|
|
17
|
+
presets: [],
|
|
18
|
+
};
|
|
19
|
+
async function installCommand() {
|
|
20
|
+
// Parse command-specific arguments
|
|
21
|
+
const args = (0, arg_1.default)({
|
|
22
|
+
// Removed flags as we'll infer the type from the source
|
|
23
|
+
}, {
|
|
24
|
+
permissive: true,
|
|
25
|
+
argv: process.argv.slice(3), // Skip the first two args and the command name
|
|
26
|
+
});
|
|
27
|
+
// Get rule name and source if provided
|
|
28
|
+
const ruleName = args._.length > 0 ? args._[0] : null;
|
|
29
|
+
const ruleSource = args._.length > 1 ? args._[1] : null;
|
|
30
|
+
try {
|
|
31
|
+
// Initialize rule collection
|
|
32
|
+
const ruleCollection = (0, rule_collector_1.initRuleCollection)();
|
|
33
|
+
// If a rule name and source are provided, install directly
|
|
34
|
+
if (ruleName && ruleSource) {
|
|
35
|
+
// Detect rule type from the source string
|
|
36
|
+
const ruleType = (0, rule_detector_1.detectRuleType)(ruleSource);
|
|
37
|
+
// Create config file if it doesn't exist
|
|
38
|
+
let config = (0, config_1.getConfig)();
|
|
39
|
+
if (!config) {
|
|
40
|
+
config = { ...defaultConfig };
|
|
41
|
+
console.log(chalk_1.default.blue("Configuration file not found. Creating a new one..."));
|
|
42
|
+
}
|
|
43
|
+
// Add the rule to the config
|
|
44
|
+
config.rules[ruleName] = ruleSource;
|
|
45
|
+
// Save the updated config
|
|
46
|
+
(0, config_1.saveConfig)(config);
|
|
47
|
+
console.log(chalk_1.default.green("Configuration updated successfully!"));
|
|
48
|
+
// Collect the rule based on its type
|
|
49
|
+
let ruleContent;
|
|
50
|
+
switch (ruleType) {
|
|
51
|
+
case "npm":
|
|
52
|
+
ruleContent = (0, rule_collector_1.collectNpmRule)(ruleName, ruleSource);
|
|
53
|
+
break;
|
|
54
|
+
case "local":
|
|
55
|
+
ruleContent = (0, rule_collector_1.collectLocalRule)(ruleName, ruleSource);
|
|
56
|
+
break;
|
|
57
|
+
default:
|
|
58
|
+
console.log(chalk_1.default.yellow(`Unknown rule type: ${ruleType}`));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// Add rule to collection
|
|
62
|
+
(0, rule_collector_1.addRuleToCollection)(ruleCollection, ruleContent, config.ides);
|
|
63
|
+
// Write rules to targets
|
|
64
|
+
(0, rule_writer_1.writeRulesToTargets)(ruleCollection);
|
|
65
|
+
console.log(chalk_1.default.green("\nRules installation completed!"));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Load configuration
|
|
69
|
+
let config = (0, config_1.getConfig)();
|
|
70
|
+
// If config doesn't exist, create a new one
|
|
71
|
+
if (!config) {
|
|
72
|
+
config = { ...defaultConfig };
|
|
73
|
+
console.log(chalk_1.default.blue("Configuration file not found. Creating a new one..."));
|
|
74
|
+
(0, config_1.saveConfig)(config);
|
|
75
|
+
console.log(chalk_1.default.green("Empty configuration file created successfully!"));
|
|
76
|
+
console.log(chalk_1.default.yellow("No rules defined in configuration."));
|
|
77
|
+
console.log(`Edit your ${chalk_1.default.blue("rules.json")} file to add rules or use the direct install command: npx rules-manager install <rule-name> <rule-source>`);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// Check if rules are defined (either directly or through presets)
|
|
81
|
+
if (!config.rules || Object.keys(config.rules).length === 0) {
|
|
82
|
+
// If there are no presets defined either, show a message
|
|
83
|
+
if (!config.presets || config.presets.length === 0) {
|
|
84
|
+
console.log(chalk_1.default.yellow("No rules defined in configuration."));
|
|
85
|
+
console.log(`Edit your ${chalk_1.default.blue("rules.json")} file to add rules or use the direct install command: npx rules-manager install <rule-name> <rule-source>`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (config.presets && config.presets.length > 0) {
|
|
90
|
+
const hasValidPresets = true;
|
|
91
|
+
// If no valid presets and no direct rules, exit
|
|
92
|
+
if (!hasValidPresets &&
|
|
93
|
+
(!config.rules || Object.keys(config.rules).length === 0)) {
|
|
94
|
+
console.log(chalk_1.default.yellow("\nNo valid rules found in configuration or presets."));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Process each rule (or just the specific one if provided)
|
|
99
|
+
let hasErrors = false;
|
|
100
|
+
for (const [name, source] of Object.entries(config.rules)) {
|
|
101
|
+
// Skip if a specific rule was requested and this isn't it
|
|
102
|
+
if (ruleName && name !== ruleName) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
// Detect rule type from the source string
|
|
106
|
+
const ruleType = (0, rule_detector_1.detectRuleType)(source);
|
|
107
|
+
// Get the base path of the preset file if this rule came from a preset
|
|
108
|
+
const ruleBasePath = (0, config_1.getRuleSource)(config, name);
|
|
109
|
+
// Collect the rule based on its type
|
|
110
|
+
try {
|
|
111
|
+
let ruleContent;
|
|
112
|
+
switch (ruleType) {
|
|
113
|
+
case "npm":
|
|
114
|
+
ruleContent = (0, rule_collector_1.collectNpmRule)(name, source);
|
|
115
|
+
break;
|
|
116
|
+
case "local":
|
|
117
|
+
ruleContent = (0, rule_collector_1.collectLocalRule)(name, source, ruleBasePath);
|
|
118
|
+
break;
|
|
119
|
+
default:
|
|
120
|
+
console.log(chalk_1.default.yellow(`Unknown rule type: ${ruleType}`));
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
// Add rule to collection
|
|
124
|
+
(0, rule_collector_1.addRuleToCollection)(ruleCollection, ruleContent, config.ides);
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
hasErrors = true;
|
|
128
|
+
console.error(chalk_1.default.red(`Error processing rule ${name}: ${error instanceof Error ? error.message : String(error)}`));
|
|
129
|
+
// If a specific rule was requested and it failed, exit immediately
|
|
130
|
+
if (ruleName) {
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// If there were errors and we're not processing a specific rule, exit with error
|
|
136
|
+
if (hasErrors && !ruleName) {
|
|
137
|
+
throw new Error("One or more rules failed to process");
|
|
138
|
+
}
|
|
139
|
+
// If a specific rule was requested but not found
|
|
140
|
+
if (ruleName && !Object.keys(config.rules).includes(ruleName)) {
|
|
141
|
+
console.log(chalk_1.default.yellow(`Rule "${ruleName}" not found in configuration.`));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
// Write all collected rules to their targets
|
|
145
|
+
(0, rule_writer_1.writeRulesToTargets)(ruleCollection);
|
|
146
|
+
console.log(chalk_1.default.green("\nRules installation completed!"));
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
console.error(chalk_1.default.red(`Error during rule installation: ${error instanceof Error ? error.message : String(error)}`));
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function listCommand(): void;
|
|
@@ -0,0 +1,37 @@
|
|
|
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.listCommand = listCommand;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const config_1 = require("../utils/config");
|
|
9
|
+
const rule_status_1 = require("../utils/rule-status");
|
|
10
|
+
const rule_detector_1 = require("../utils/rule-detector");
|
|
11
|
+
function listCommand() {
|
|
12
|
+
const config = (0, config_1.getConfig)();
|
|
13
|
+
if (!config) {
|
|
14
|
+
console.log(chalk_1.default.red("Configuration file not found!"));
|
|
15
|
+
console.log(`Run ${chalk_1.default.blue("npx rules-manager init")} to create one.`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (!config.rules || Object.keys(config.rules).length === 0) {
|
|
19
|
+
console.log(chalk_1.default.yellow("No rules defined in configuration."));
|
|
20
|
+
console.log(`Edit your ${chalk_1.default.blue("rules.json")} file to add rules.`);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
console.log(chalk_1.default.blue("Configured Rules:"));
|
|
24
|
+
console.log(chalk_1.default.dim("─".repeat(50)));
|
|
25
|
+
for (const [ruleName, source] of Object.entries(config.rules)) {
|
|
26
|
+
const ruleType = (0, rule_detector_1.detectRuleType)(source);
|
|
27
|
+
const status = (0, rule_status_1.checkRuleStatus)(ruleName, ruleType, config.ides);
|
|
28
|
+
const statusColor = status
|
|
29
|
+
? chalk_1.default.green("Installed")
|
|
30
|
+
: chalk_1.default.yellow("Not installed");
|
|
31
|
+
console.log(`${chalk_1.default.bold(ruleName)}`);
|
|
32
|
+
console.log(` Source: ${source}`);
|
|
33
|
+
console.log(` Type: ${ruleType} (auto-detected)`);
|
|
34
|
+
console.log(` Status: ${statusColor}`);
|
|
35
|
+
console.log(chalk_1.default.dim("─".repeat(50)));
|
|
36
|
+
}
|
|
37
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const arg_1 = __importDefault(require("arg"));
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const init_1 = require("./commands/init");
|
|
10
|
+
const install_1 = require("./commands/install");
|
|
11
|
+
const list_1 = require("./commands/list");
|
|
12
|
+
// Define version from package.json
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
14
|
+
const pkg = require("../package.json");
|
|
15
|
+
// Parse arguments
|
|
16
|
+
const args = (0, arg_1.default)({
|
|
17
|
+
"--help": Boolean,
|
|
18
|
+
"--version": Boolean,
|
|
19
|
+
"-h": "--help",
|
|
20
|
+
"-v": "--version",
|
|
21
|
+
}, {
|
|
22
|
+
permissive: true,
|
|
23
|
+
argv: process.argv.slice(2),
|
|
24
|
+
});
|
|
25
|
+
// Show version
|
|
26
|
+
if (args["--version"]) {
|
|
27
|
+
console.log(pkg.version);
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
// Get the command (first non-flag argument)
|
|
31
|
+
const command = args._.length > 0 ? args._[0] : null;
|
|
32
|
+
// Execute the appropriate command
|
|
33
|
+
switch (command) {
|
|
34
|
+
case "init":
|
|
35
|
+
(0, init_1.initCommand)();
|
|
36
|
+
break;
|
|
37
|
+
case "install":
|
|
38
|
+
(0, install_1.installCommand)();
|
|
39
|
+
break;
|
|
40
|
+
case "list":
|
|
41
|
+
(0, list_1.listCommand)();
|
|
42
|
+
break;
|
|
43
|
+
default:
|
|
44
|
+
// Show help
|
|
45
|
+
showHelp();
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
function showHelp() {
|
|
49
|
+
console.log(`
|
|
50
|
+
${chalk_1.default.bold("rules-manager")} - A CLI tool for managing AI IDE rules
|
|
51
|
+
|
|
52
|
+
${chalk_1.default.bold("USAGE")}
|
|
53
|
+
$ rules-manager [command] [options]
|
|
54
|
+
|
|
55
|
+
${chalk_1.default.bold("COMMANDS")}
|
|
56
|
+
init Initialize a new rules-manager configuration file
|
|
57
|
+
install Install rules from configured sources
|
|
58
|
+
list List all configured rules and their status
|
|
59
|
+
|
|
60
|
+
${chalk_1.default.bold("OPTIONS")}
|
|
61
|
+
-h, --help Show this help message
|
|
62
|
+
-v, --version Show version number
|
|
63
|
+
|
|
64
|
+
${chalk_1.default.bold("EXAMPLES")}
|
|
65
|
+
$ rules-manager init
|
|
66
|
+
$ rules-manager install
|
|
67
|
+
$ rules-manager list
|
|
68
|
+
`);
|
|
69
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type Rule = string;
|
|
2
|
+
export interface Rules {
|
|
3
|
+
[ruleName: string]: Rule;
|
|
4
|
+
}
|
|
5
|
+
export interface Config {
|
|
6
|
+
ides: string[];
|
|
7
|
+
rules: Rules;
|
|
8
|
+
presets?: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface RuleMetadata {
|
|
11
|
+
type?: string;
|
|
12
|
+
alwaysApply?: boolean | string;
|
|
13
|
+
globs?: string[] | string;
|
|
14
|
+
description?: string;
|
|
15
|
+
[key: string]: any;
|
|
16
|
+
}
|
|
17
|
+
export interface RuleContent {
|
|
18
|
+
name: string;
|
|
19
|
+
content: string;
|
|
20
|
+
metadata: RuleMetadata;
|
|
21
|
+
sourcePath: string;
|
|
22
|
+
}
|
|
23
|
+
export interface RuleCollection {
|
|
24
|
+
cursor: RuleContent[];
|
|
25
|
+
windsurf: RuleContent[];
|
|
26
|
+
}
|