aicm 0.20.0 → 0.20.5
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 +79 -3
- package/package.json +6 -2
- package/dist/api.d.ts +0 -16
- package/dist/api.js +0 -22
- package/dist/bin/aicm.d.ts +0 -2
- package/dist/bin/aicm.js +0 -5
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -102
- package/dist/commands/clean.d.ts +0 -19
- package/dist/commands/clean.js +0 -325
- package/dist/commands/init.d.ts +0 -1
- package/dist/commands/init.js +0 -49
- package/dist/commands/install-workspaces.d.ts +0 -5
- package/dist/commands/install-workspaces.js +0 -349
- package/dist/commands/install.d.ts +0 -92
- package/dist/commands/install.js +0 -607
- package/dist/commands/list.d.ts +0 -1
- package/dist/commands/list.js +0 -40
- package/dist/utils/config.d.ts +0 -109
- package/dist/utils/config.js +0 -476
- package/dist/utils/hooks.d.ts +0 -50
- package/dist/utils/hooks.js +0 -346
- package/dist/utils/is-ci.d.ts +0 -1
- package/dist/utils/is-ci.js +0 -8
- package/dist/utils/rules-file-writer.d.ts +0 -24
- package/dist/utils/rules-file-writer.js +0 -197
- package/dist/utils/working-directory.d.ts +0 -5
- package/dist/utils/working-directory.js +0 -21
- package/dist/utils/workspace-discovery.d.ts +0 -13
- package/dist/utils/workspace-discovery.js +0 -53
package/dist/commands/install.js
DELETED
|
@@ -1,607 +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.writeAssetsToTargets = writeAssetsToTargets;
|
|
7
|
-
exports.writeCommandsToTargets = writeCommandsToTargets;
|
|
8
|
-
exports.writeSkillsToTargets = writeSkillsToTargets;
|
|
9
|
-
exports.warnPresetSkillCollisions = warnPresetSkillCollisions;
|
|
10
|
-
exports.dedupeSkillsForInstall = dedupeSkillsForInstall;
|
|
11
|
-
exports.warnPresetCommandCollisions = warnPresetCommandCollisions;
|
|
12
|
-
exports.dedupeCommandsForInstall = dedupeCommandsForInstall;
|
|
13
|
-
exports.writeMcpServersToFile = writeMcpServersToFile;
|
|
14
|
-
exports.installPackage = installPackage;
|
|
15
|
-
exports.install = install;
|
|
16
|
-
exports.installCommand = installCommand;
|
|
17
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
18
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
19
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
20
|
-
const config_1 = require("../utils/config");
|
|
21
|
-
const hooks_1 = require("../utils/hooks");
|
|
22
|
-
const working_directory_1 = require("../utils/working-directory");
|
|
23
|
-
const is_ci_1 = require("../utils/is-ci");
|
|
24
|
-
const rules_file_writer_1 = require("../utils/rules-file-writer");
|
|
25
|
-
const install_workspaces_1 = require("./install-workspaces");
|
|
26
|
-
/**
|
|
27
|
-
* Rewrite asset references from source paths to installation paths
|
|
28
|
-
* Only rewrites the ../assets/ pattern - everything else is preserved
|
|
29
|
-
*
|
|
30
|
-
* @param content - The file content to rewrite
|
|
31
|
-
* @param presetName - The preset name if this file is from a preset
|
|
32
|
-
* @param fileInstallDepth - The depth of the file's installation directory relative to .cursor/
|
|
33
|
-
* For example: .cursor/commands/aicm/file.md has depth 2 (commands, aicm)
|
|
34
|
-
* .cursor/rules/aicm/preset/file.mdc has depth 3 (rules, aicm, preset)
|
|
35
|
-
*/
|
|
36
|
-
function rewriteAssetReferences(content, presetName, fileInstallDepth = 2) {
|
|
37
|
-
// Calculate the relative path from the file to .cursor/assets/aicm/
|
|
38
|
-
// We need to go up fileInstallDepth levels to reach .cursor/, then down to assets/aicm/
|
|
39
|
-
const upLevels = "../".repeat(fileInstallDepth);
|
|
40
|
-
// If this is from a preset, include the preset namespace in the asset path
|
|
41
|
-
let assetBasePath = "assets/aicm/";
|
|
42
|
-
if (presetName) {
|
|
43
|
-
const namespace = (0, config_1.extractNamespaceFromPresetPath)(presetName);
|
|
44
|
-
assetBasePath = node_path_1.default.posix.join("assets", "aicm", ...namespace) + "/";
|
|
45
|
-
}
|
|
46
|
-
const targetPath = upLevels + assetBasePath;
|
|
47
|
-
// Replace ../assets/ with the calculated target path
|
|
48
|
-
// Handles both forward slashes and backslashes for cross-platform compatibility
|
|
49
|
-
return content.replace(/\.\.[\\/]assets[\\/]/g, targetPath);
|
|
50
|
-
}
|
|
51
|
-
function getTargetPaths() {
|
|
52
|
-
const projectDir = process.cwd();
|
|
53
|
-
return {
|
|
54
|
-
cursor: node_path_1.default.join(projectDir, ".cursor", "rules", "aicm"),
|
|
55
|
-
assetsAicm: node_path_1.default.join(projectDir, ".cursor", "assets", "aicm"),
|
|
56
|
-
aicm: node_path_1.default.join(projectDir, ".aicm"),
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
function writeCursorRules(rules, cursorRulesDir) {
|
|
60
|
-
fs_extra_1.default.emptyDirSync(cursorRulesDir);
|
|
61
|
-
for (const rule of rules) {
|
|
62
|
-
let rulePath;
|
|
63
|
-
const ruleNameParts = rule.name.split(node_path_1.default.sep).filter(Boolean);
|
|
64
|
-
if (rule.presetName) {
|
|
65
|
-
// For rules from presets, create a namespaced directory structure
|
|
66
|
-
const namespace = (0, config_1.extractNamespaceFromPresetPath)(rule.presetName);
|
|
67
|
-
// Path will be: cursorRulesDir/namespace/rule-name.mdc
|
|
68
|
-
rulePath = node_path_1.default.join(cursorRulesDir, ...namespace, ...ruleNameParts);
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
// For local rules, maintain the original flat structure
|
|
72
|
-
rulePath = node_path_1.default.join(cursorRulesDir, ...ruleNameParts);
|
|
73
|
-
}
|
|
74
|
-
const ruleFile = rulePath + ".mdc";
|
|
75
|
-
fs_extra_1.default.ensureDirSync(node_path_1.default.dirname(ruleFile));
|
|
76
|
-
// Calculate the depth for asset path rewriting
|
|
77
|
-
// cursorRulesDir is .cursor/rules/aicm (depth 2 from .cursor)
|
|
78
|
-
// Add namespace depth if present
|
|
79
|
-
let fileInstallDepth = 2; // rules, aicm
|
|
80
|
-
if (rule.presetName) {
|
|
81
|
-
const namespace = (0, config_1.extractNamespaceFromPresetPath)(rule.presetName);
|
|
82
|
-
fileInstallDepth += namespace.length;
|
|
83
|
-
}
|
|
84
|
-
// Add any subdirectories in the rule name
|
|
85
|
-
fileInstallDepth += ruleNameParts.length - 1; // -1 because the last part is the filename
|
|
86
|
-
// Rewrite asset references before writing
|
|
87
|
-
const content = rewriteAssetReferences(rule.content, rule.presetName, fileInstallDepth);
|
|
88
|
-
fs_extra_1.default.writeFileSync(ruleFile, content);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
function writeCursorCommands(commands, cursorCommandsDir) {
|
|
92
|
-
fs_extra_1.default.removeSync(cursorCommandsDir);
|
|
93
|
-
for (const command of commands) {
|
|
94
|
-
const commandNameParts = command.name
|
|
95
|
-
.replace(/\\/g, "/")
|
|
96
|
-
.split("/")
|
|
97
|
-
.filter(Boolean);
|
|
98
|
-
const commandPath = node_path_1.default.join(cursorCommandsDir, ...commandNameParts);
|
|
99
|
-
const commandFile = commandPath + ".md";
|
|
100
|
-
fs_extra_1.default.ensureDirSync(node_path_1.default.dirname(commandFile));
|
|
101
|
-
// Calculate the depth for asset path rewriting
|
|
102
|
-
// cursorCommandsDir is .cursor/commands/aicm (depth 2 from .cursor)
|
|
103
|
-
// Commands are NOT namespaced by preset, but we still need to account for subdirectories
|
|
104
|
-
let fileInstallDepth = 2; // commands, aicm
|
|
105
|
-
// Add any subdirectories in the command name
|
|
106
|
-
fileInstallDepth += commandNameParts.length - 1; // -1 because the last part is the filename
|
|
107
|
-
// Rewrite asset references before writing
|
|
108
|
-
const content = rewriteAssetReferences(command.content, command.presetName, fileInstallDepth);
|
|
109
|
-
fs_extra_1.default.writeFileSync(commandFile, content);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Write rules to a shared directory and update the given rules file
|
|
114
|
-
*/
|
|
115
|
-
function writeRulesForFile(rules, assets, ruleDir, rulesFile) {
|
|
116
|
-
fs_extra_1.default.emptyDirSync(ruleDir);
|
|
117
|
-
const ruleFiles = rules.map((rule) => {
|
|
118
|
-
let rulePath;
|
|
119
|
-
const ruleNameParts = rule.name.split(node_path_1.default.sep).filter(Boolean);
|
|
120
|
-
if (rule.presetName) {
|
|
121
|
-
// For rules from presets, create a namespaced directory structure
|
|
122
|
-
const namespace = (0, config_1.extractNamespaceFromPresetPath)(rule.presetName);
|
|
123
|
-
// Path will be: ruleDir/namespace/rule-name.md
|
|
124
|
-
rulePath = node_path_1.default.join(ruleDir, ...namespace, ...ruleNameParts);
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
// For local rules, maintain the original flat structure
|
|
128
|
-
rulePath = node_path_1.default.join(ruleDir, ...ruleNameParts);
|
|
129
|
-
}
|
|
130
|
-
// For windsurf/codex/claude, assets are installed at the same namespace level as rules
|
|
131
|
-
// Example: .aicm/my-preset/rule.md and .aicm/my-preset/asset.json
|
|
132
|
-
// So we need to remove the 'assets/' part from the path
|
|
133
|
-
// ../assets/file.json -> ../file.json
|
|
134
|
-
// ../../assets/file.json -> ../../file.json
|
|
135
|
-
const content = rule.content.replace(/(\.\.[/\\])assets[/\\]/g, "$1");
|
|
136
|
-
const physicalRulePath = rulePath + ".md";
|
|
137
|
-
fs_extra_1.default.ensureDirSync(node_path_1.default.dirname(physicalRulePath));
|
|
138
|
-
fs_extra_1.default.writeFileSync(physicalRulePath, content);
|
|
139
|
-
const relativeRuleDir = node_path_1.default.basename(ruleDir);
|
|
140
|
-
// For the rules file, maintain the same structure
|
|
141
|
-
let windsurfPath;
|
|
142
|
-
if (rule.presetName) {
|
|
143
|
-
const namespace = (0, config_1.extractNamespaceFromPresetPath)(rule.presetName);
|
|
144
|
-
windsurfPath =
|
|
145
|
-
node_path_1.default.join(relativeRuleDir, ...namespace, ...ruleNameParts) + ".md";
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
windsurfPath = node_path_1.default.join(relativeRuleDir, ...ruleNameParts) + ".md";
|
|
149
|
-
}
|
|
150
|
-
// Normalize to POSIX style for cross-platform compatibility
|
|
151
|
-
const windsurfPathPosix = windsurfPath.replace(/\\/g, "/");
|
|
152
|
-
return {
|
|
153
|
-
name: rule.name,
|
|
154
|
-
path: windsurfPathPosix,
|
|
155
|
-
metadata: (0, rules_file_writer_1.parseRuleFrontmatter)(content),
|
|
156
|
-
};
|
|
157
|
-
});
|
|
158
|
-
const rulesContent = (0, rules_file_writer_1.generateRulesFileContent)(ruleFiles);
|
|
159
|
-
(0, rules_file_writer_1.writeRulesFile)(rulesContent, node_path_1.default.join(process.cwd(), rulesFile));
|
|
160
|
-
}
|
|
161
|
-
function writeAssetsToTargets(assets, targets) {
|
|
162
|
-
const targetPaths = getTargetPaths();
|
|
163
|
-
for (const target of targets) {
|
|
164
|
-
let targetDir;
|
|
165
|
-
switch (target) {
|
|
166
|
-
case "cursor":
|
|
167
|
-
targetDir = targetPaths.assetsAicm;
|
|
168
|
-
break;
|
|
169
|
-
case "windsurf":
|
|
170
|
-
case "codex":
|
|
171
|
-
case "claude":
|
|
172
|
-
targetDir = targetPaths.aicm;
|
|
173
|
-
break;
|
|
174
|
-
default:
|
|
175
|
-
continue;
|
|
176
|
-
}
|
|
177
|
-
for (const asset of assets) {
|
|
178
|
-
let assetPath;
|
|
179
|
-
if (asset.presetName) {
|
|
180
|
-
const namespace = (0, config_1.extractNamespaceFromPresetPath)(asset.presetName);
|
|
181
|
-
assetPath = node_path_1.default.join(targetDir, ...namespace, asset.name);
|
|
182
|
-
}
|
|
183
|
-
else {
|
|
184
|
-
assetPath = node_path_1.default.join(targetDir, asset.name);
|
|
185
|
-
}
|
|
186
|
-
fs_extra_1.default.ensureDirSync(node_path_1.default.dirname(assetPath));
|
|
187
|
-
fs_extra_1.default.writeFileSync(assetPath, asset.content);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Write all collected rules to their respective IDE targets
|
|
193
|
-
*/
|
|
194
|
-
function writeRulesToTargets(rules, assets, targets) {
|
|
195
|
-
const targetPaths = getTargetPaths();
|
|
196
|
-
for (const target of targets) {
|
|
197
|
-
switch (target) {
|
|
198
|
-
case "cursor":
|
|
199
|
-
if (rules.length > 0) {
|
|
200
|
-
writeCursorRules(rules, targetPaths.cursor);
|
|
201
|
-
}
|
|
202
|
-
break;
|
|
203
|
-
case "windsurf":
|
|
204
|
-
if (rules.length > 0) {
|
|
205
|
-
writeRulesForFile(rules, assets, targetPaths.aicm, ".windsurfrules");
|
|
206
|
-
}
|
|
207
|
-
break;
|
|
208
|
-
case "codex":
|
|
209
|
-
if (rules.length > 0) {
|
|
210
|
-
writeRulesForFile(rules, assets, targetPaths.aicm, "AGENTS.md");
|
|
211
|
-
}
|
|
212
|
-
break;
|
|
213
|
-
case "claude":
|
|
214
|
-
if (rules.length > 0) {
|
|
215
|
-
writeRulesForFile(rules, assets, targetPaths.aicm, "CLAUDE.md");
|
|
216
|
-
}
|
|
217
|
-
break;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
// Write assets after rules so they don't get wiped by emptyDirSync
|
|
221
|
-
writeAssetsToTargets(assets, targets);
|
|
222
|
-
}
|
|
223
|
-
function writeCommandsToTargets(commands, targets) {
|
|
224
|
-
const projectDir = process.cwd();
|
|
225
|
-
const cursorRoot = node_path_1.default.join(projectDir, ".cursor");
|
|
226
|
-
for (const target of targets) {
|
|
227
|
-
if (target === "cursor") {
|
|
228
|
-
const commandsDir = node_path_1.default.join(cursorRoot, "commands", "aicm");
|
|
229
|
-
writeCursorCommands(commands, commandsDir);
|
|
230
|
-
}
|
|
231
|
-
// Other targets do not support commands yet
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Get the skills installation path for a target
|
|
236
|
-
* Returns null for targets that don't support skills
|
|
237
|
-
*/
|
|
238
|
-
function getSkillsTargetPath(target) {
|
|
239
|
-
const projectDir = process.cwd();
|
|
240
|
-
switch (target) {
|
|
241
|
-
case "cursor":
|
|
242
|
-
return node_path_1.default.join(projectDir, ".cursor", "skills");
|
|
243
|
-
case "claude":
|
|
244
|
-
return node_path_1.default.join(projectDir, ".claude", "skills");
|
|
245
|
-
case "codex":
|
|
246
|
-
return node_path_1.default.join(projectDir, ".codex", "skills");
|
|
247
|
-
case "windsurf":
|
|
248
|
-
// Windsurf does not support skills
|
|
249
|
-
return null;
|
|
250
|
-
default:
|
|
251
|
-
return null;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
/**
|
|
255
|
-
* Write a single skill to the target directory
|
|
256
|
-
* Copies the entire skill directory and writes .aicm.json metadata
|
|
257
|
-
*/
|
|
258
|
-
function writeSkillToTarget(skill, targetSkillsDir) {
|
|
259
|
-
const skillTargetPath = node_path_1.default.join(targetSkillsDir, skill.name);
|
|
260
|
-
// Remove existing skill directory if it exists (to ensure clean install)
|
|
261
|
-
if (fs_extra_1.default.existsSync(skillTargetPath)) {
|
|
262
|
-
fs_extra_1.default.removeSync(skillTargetPath);
|
|
263
|
-
}
|
|
264
|
-
// Copy the entire skill directory
|
|
265
|
-
fs_extra_1.default.copySync(skill.sourcePath, skillTargetPath);
|
|
266
|
-
// Write .aicm.json metadata file
|
|
267
|
-
// The presence of this file indicates the skill is managed by aicm
|
|
268
|
-
const metadata = {
|
|
269
|
-
source: skill.source,
|
|
270
|
-
};
|
|
271
|
-
if (skill.presetName) {
|
|
272
|
-
metadata.presetName = skill.presetName;
|
|
273
|
-
}
|
|
274
|
-
const metadataPath = node_path_1.default.join(skillTargetPath, ".aicm.json");
|
|
275
|
-
fs_extra_1.default.writeJsonSync(metadataPath, metadata, { spaces: 2 });
|
|
276
|
-
}
|
|
277
|
-
/**
|
|
278
|
-
* Write skills to all supported target directories
|
|
279
|
-
*/
|
|
280
|
-
function writeSkillsToTargets(skills, targets) {
|
|
281
|
-
if (skills.length === 0)
|
|
282
|
-
return;
|
|
283
|
-
for (const target of targets) {
|
|
284
|
-
const targetSkillsDir = getSkillsTargetPath(target);
|
|
285
|
-
if (!targetSkillsDir) {
|
|
286
|
-
// Target doesn't support skills
|
|
287
|
-
continue;
|
|
288
|
-
}
|
|
289
|
-
// Ensure the skills directory exists
|
|
290
|
-
fs_extra_1.default.ensureDirSync(targetSkillsDir);
|
|
291
|
-
for (const skill of skills) {
|
|
292
|
-
writeSkillToTarget(skill, targetSkillsDir);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* Warn about skill name collisions from different presets
|
|
298
|
-
*/
|
|
299
|
-
function warnPresetSkillCollisions(skills) {
|
|
300
|
-
const collisions = new Map();
|
|
301
|
-
for (const skill of skills) {
|
|
302
|
-
if (!skill.presetName)
|
|
303
|
-
continue;
|
|
304
|
-
const entry = collisions.get(skill.name);
|
|
305
|
-
if (entry) {
|
|
306
|
-
entry.presets.add(skill.presetName);
|
|
307
|
-
entry.lastPreset = skill.presetName;
|
|
308
|
-
}
|
|
309
|
-
else {
|
|
310
|
-
collisions.set(skill.name, {
|
|
311
|
-
presets: new Set([skill.presetName]),
|
|
312
|
-
lastPreset: skill.presetName,
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
for (const [skillName, { presets, lastPreset }] of collisions) {
|
|
317
|
-
if (presets.size > 1) {
|
|
318
|
-
const presetList = Array.from(presets).sort().join(", ");
|
|
319
|
-
console.warn(chalk_1.default.yellow(`Warning: multiple presets provide the "${skillName}" skill (${presetList}). Using definition from ${lastPreset}.`));
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
/**
|
|
324
|
-
* Dedupe skills by name (last one wins)
|
|
325
|
-
*/
|
|
326
|
-
function dedupeSkillsForInstall(skills) {
|
|
327
|
-
const unique = new Map();
|
|
328
|
-
for (const skill of skills) {
|
|
329
|
-
unique.set(skill.name, skill);
|
|
330
|
-
}
|
|
331
|
-
return Array.from(unique.values());
|
|
332
|
-
}
|
|
333
|
-
function warnPresetCommandCollisions(commands) {
|
|
334
|
-
const collisions = new Map();
|
|
335
|
-
for (const command of commands) {
|
|
336
|
-
if (!command.presetName)
|
|
337
|
-
continue;
|
|
338
|
-
const entry = collisions.get(command.name);
|
|
339
|
-
if (entry) {
|
|
340
|
-
entry.presets.add(command.presetName);
|
|
341
|
-
entry.lastPreset = command.presetName;
|
|
342
|
-
}
|
|
343
|
-
else {
|
|
344
|
-
collisions.set(command.name, {
|
|
345
|
-
presets: new Set([command.presetName]),
|
|
346
|
-
lastPreset: command.presetName,
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
for (const [commandName, { presets, lastPreset }] of collisions) {
|
|
351
|
-
if (presets.size > 1) {
|
|
352
|
-
const presetList = Array.from(presets).sort().join(", ");
|
|
353
|
-
console.warn(chalk_1.default.yellow(`Warning: multiple presets provide the "${commandName}" command (${presetList}). Using definition from ${lastPreset}.`));
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
function dedupeCommandsForInstall(commands) {
|
|
358
|
-
const unique = new Map();
|
|
359
|
-
for (const command of commands) {
|
|
360
|
-
unique.set(command.name, command);
|
|
361
|
-
}
|
|
362
|
-
return Array.from(unique.values());
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* Write MCP servers configuration to IDE targets
|
|
366
|
-
*/
|
|
367
|
-
function writeMcpServersToTargets(mcpServers, targets, cwd) {
|
|
368
|
-
if (!mcpServers || Object.keys(mcpServers).length === 0)
|
|
369
|
-
return;
|
|
370
|
-
for (const target of targets) {
|
|
371
|
-
if (target === "cursor") {
|
|
372
|
-
const mcpPath = node_path_1.default.join(cwd, ".cursor", "mcp.json");
|
|
373
|
-
writeMcpServersToFile(mcpServers, mcpPath);
|
|
374
|
-
}
|
|
375
|
-
// Windsurf and Codex do not support project mcpServers, so skip
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
/**
|
|
379
|
-
* Write hooks to IDE targets
|
|
380
|
-
*/
|
|
381
|
-
function writeHooksToTargets(hooksConfig, hookFiles, targets, cwd) {
|
|
382
|
-
const hasHooks = hooksConfig.hooks && Object.keys(hooksConfig.hooks).length > 0;
|
|
383
|
-
if (!hasHooks && hookFiles.length === 0) {
|
|
384
|
-
return;
|
|
385
|
-
}
|
|
386
|
-
for (const target of targets) {
|
|
387
|
-
if (target === "cursor") {
|
|
388
|
-
(0, hooks_1.writeHooksToCursor)(hooksConfig, hookFiles, cwd);
|
|
389
|
-
}
|
|
390
|
-
// Other targets do not support hooks yet
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
/**
|
|
394
|
-
* Write MCP servers configuration to a specific file
|
|
395
|
-
*/
|
|
396
|
-
function writeMcpServersToFile(mcpServers, mcpPath) {
|
|
397
|
-
var _a;
|
|
398
|
-
fs_extra_1.default.ensureDirSync(node_path_1.default.dirname(mcpPath));
|
|
399
|
-
const existingConfig = fs_extra_1.default.existsSync(mcpPath)
|
|
400
|
-
? fs_extra_1.default.readJsonSync(mcpPath)
|
|
401
|
-
: {};
|
|
402
|
-
const existingMcpServers = (_a = existingConfig === null || existingConfig === void 0 ? void 0 : existingConfig.mcpServers) !== null && _a !== void 0 ? _a : {};
|
|
403
|
-
// Filter out any existing aicm-managed servers (with aicm: true)
|
|
404
|
-
// This removes stale aicm servers that are no longer in the configuration
|
|
405
|
-
const userMcpServers = {};
|
|
406
|
-
for (const [key, value] of Object.entries(existingMcpServers)) {
|
|
407
|
-
if (typeof value === "object" && value !== null && value.aicm !== true) {
|
|
408
|
-
userMcpServers[key] = value;
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
// Mark new aicm servers as managed and filter out canceled servers
|
|
412
|
-
const aicmMcpServers = {};
|
|
413
|
-
for (const [key, value] of Object.entries(mcpServers)) {
|
|
414
|
-
if (value !== false) {
|
|
415
|
-
aicmMcpServers[key] = {
|
|
416
|
-
...value,
|
|
417
|
-
aicm: true,
|
|
418
|
-
};
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
// Merge user servers with aicm servers (aicm servers override user servers with same key)
|
|
422
|
-
const mergedMcpServers = {
|
|
423
|
-
...userMcpServers,
|
|
424
|
-
...aicmMcpServers,
|
|
425
|
-
};
|
|
426
|
-
const mergedConfig = {
|
|
427
|
-
...existingConfig,
|
|
428
|
-
mcpServers: mergedMcpServers,
|
|
429
|
-
};
|
|
430
|
-
fs_extra_1.default.writeJsonSync(mcpPath, mergedConfig, { spaces: 2 });
|
|
431
|
-
}
|
|
432
|
-
/**
|
|
433
|
-
* Install rules for a single package (used within workspaces and standalone installs)
|
|
434
|
-
*/
|
|
435
|
-
async function installPackage(options = {}) {
|
|
436
|
-
const cwd = options.cwd || process.cwd();
|
|
437
|
-
return (0, working_directory_1.withWorkingDirectory)(cwd, async () => {
|
|
438
|
-
let resolvedConfig;
|
|
439
|
-
if (options.config) {
|
|
440
|
-
resolvedConfig = options.config;
|
|
441
|
-
}
|
|
442
|
-
else {
|
|
443
|
-
resolvedConfig = await (0, config_1.loadConfig)(cwd);
|
|
444
|
-
}
|
|
445
|
-
if (!resolvedConfig) {
|
|
446
|
-
return {
|
|
447
|
-
success: false,
|
|
448
|
-
error: new Error("Configuration file not found"),
|
|
449
|
-
installedRuleCount: 0,
|
|
450
|
-
installedCommandCount: 0,
|
|
451
|
-
installedAssetCount: 0,
|
|
452
|
-
installedHookCount: 0,
|
|
453
|
-
installedSkillCount: 0,
|
|
454
|
-
packagesCount: 0,
|
|
455
|
-
};
|
|
456
|
-
}
|
|
457
|
-
const { config, rules, commands, assets, skills, mcpServers, hooks, hookFiles, } = resolvedConfig;
|
|
458
|
-
if (config.skipInstall === true) {
|
|
459
|
-
return {
|
|
460
|
-
success: true,
|
|
461
|
-
installedRuleCount: 0,
|
|
462
|
-
installedCommandCount: 0,
|
|
463
|
-
installedAssetCount: 0,
|
|
464
|
-
installedHookCount: 0,
|
|
465
|
-
installedSkillCount: 0,
|
|
466
|
-
packagesCount: 0,
|
|
467
|
-
};
|
|
468
|
-
}
|
|
469
|
-
warnPresetCommandCollisions(commands);
|
|
470
|
-
const commandsToInstall = dedupeCommandsForInstall(commands);
|
|
471
|
-
warnPresetSkillCollisions(skills);
|
|
472
|
-
const skillsToInstall = dedupeSkillsForInstall(skills);
|
|
473
|
-
try {
|
|
474
|
-
if (!options.dryRun) {
|
|
475
|
-
writeRulesToTargets(rules, assets, config.targets);
|
|
476
|
-
writeCommandsToTargets(commandsToInstall, config.targets);
|
|
477
|
-
writeSkillsToTargets(skillsToInstall, config.targets);
|
|
478
|
-
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
479
|
-
writeMcpServersToTargets(mcpServers, config.targets, cwd);
|
|
480
|
-
}
|
|
481
|
-
if (hooks && ((0, hooks_1.countHooks)(hooks) > 0 || hookFiles.length > 0)) {
|
|
482
|
-
writeHooksToTargets(hooks, hookFiles, config.targets, cwd);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
const uniqueRuleCount = new Set(rules.map((rule) => rule.name)).size;
|
|
486
|
-
const uniqueCommandCount = new Set(commandsToInstall.map((command) => command.name)).size;
|
|
487
|
-
const uniqueHookCount = (0, hooks_1.countHooks)(hooks);
|
|
488
|
-
const uniqueSkillCount = skillsToInstall.length;
|
|
489
|
-
return {
|
|
490
|
-
success: true,
|
|
491
|
-
installedRuleCount: uniqueRuleCount,
|
|
492
|
-
installedCommandCount: uniqueCommandCount,
|
|
493
|
-
installedAssetCount: assets.length,
|
|
494
|
-
installedHookCount: uniqueHookCount,
|
|
495
|
-
installedSkillCount: uniqueSkillCount,
|
|
496
|
-
packagesCount: 1,
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
catch (error) {
|
|
500
|
-
return {
|
|
501
|
-
success: false,
|
|
502
|
-
error: error instanceof Error ? error : new Error(String(error)),
|
|
503
|
-
installedRuleCount: 0,
|
|
504
|
-
installedCommandCount: 0,
|
|
505
|
-
installedAssetCount: 0,
|
|
506
|
-
installedHookCount: 0,
|
|
507
|
-
installedSkillCount: 0,
|
|
508
|
-
packagesCount: 0,
|
|
509
|
-
};
|
|
510
|
-
}
|
|
511
|
-
});
|
|
512
|
-
}
|
|
513
|
-
/**
|
|
514
|
-
* Core implementation of the rule installation logic
|
|
515
|
-
*/
|
|
516
|
-
async function install(options = {}) {
|
|
517
|
-
const cwd = options.cwd || process.cwd();
|
|
518
|
-
const installOnCI = options.installOnCI === true; // Default to false if not specified
|
|
519
|
-
const inCI = (0, is_ci_1.isCIEnvironment)();
|
|
520
|
-
if (inCI && !installOnCI) {
|
|
521
|
-
console.log(chalk_1.default.yellow("Detected CI environment, skipping install."));
|
|
522
|
-
return {
|
|
523
|
-
success: true,
|
|
524
|
-
installedRuleCount: 0,
|
|
525
|
-
installedCommandCount: 0,
|
|
526
|
-
installedAssetCount: 0,
|
|
527
|
-
installedHookCount: 0,
|
|
528
|
-
installedSkillCount: 0,
|
|
529
|
-
packagesCount: 0,
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
return (0, working_directory_1.withWorkingDirectory)(cwd, async () => {
|
|
533
|
-
let resolvedConfig;
|
|
534
|
-
if (options.config) {
|
|
535
|
-
resolvedConfig = options.config;
|
|
536
|
-
}
|
|
537
|
-
else {
|
|
538
|
-
resolvedConfig = await (0, config_1.loadConfig)(cwd);
|
|
539
|
-
}
|
|
540
|
-
const shouldUseWorkspaces = (resolvedConfig === null || resolvedConfig === void 0 ? void 0 : resolvedConfig.config.workspaces) ||
|
|
541
|
-
(!resolvedConfig && (0, config_1.detectWorkspacesFromPackageJson)(cwd));
|
|
542
|
-
if (shouldUseWorkspaces) {
|
|
543
|
-
return await (0, install_workspaces_1.installWorkspaces)(cwd, installOnCI, options.verbose, options.dryRun);
|
|
544
|
-
}
|
|
545
|
-
return installPackage(options);
|
|
546
|
-
});
|
|
547
|
-
}
|
|
548
|
-
/**
|
|
549
|
-
* CLI command wrapper for install
|
|
550
|
-
*/
|
|
551
|
-
async function installCommand(installOnCI, verbose, dryRun) {
|
|
552
|
-
var _a;
|
|
553
|
-
const result = await install({ installOnCI, verbose, dryRun });
|
|
554
|
-
if (!result.success) {
|
|
555
|
-
throw (_a = result.error) !== null && _a !== void 0 ? _a : new Error("Installation failed with unknown error");
|
|
556
|
-
}
|
|
557
|
-
else {
|
|
558
|
-
const ruleCount = result.installedRuleCount;
|
|
559
|
-
const commandCount = result.installedCommandCount;
|
|
560
|
-
const hookCount = result.installedHookCount;
|
|
561
|
-
const skillCount = result.installedSkillCount;
|
|
562
|
-
const ruleMessage = ruleCount > 0 ? `${ruleCount} rule${ruleCount === 1 ? "" : "s"}` : null;
|
|
563
|
-
const commandMessage = commandCount > 0
|
|
564
|
-
? `${commandCount} command${commandCount === 1 ? "" : "s"}`
|
|
565
|
-
: null;
|
|
566
|
-
const hookMessage = hookCount > 0 ? `${hookCount} hook${hookCount === 1 ? "" : "s"}` : null;
|
|
567
|
-
const skillMessage = skillCount > 0
|
|
568
|
-
? `${skillCount} skill${skillCount === 1 ? "" : "s"}`
|
|
569
|
-
: null;
|
|
570
|
-
const countsParts = [];
|
|
571
|
-
if (ruleMessage) {
|
|
572
|
-
countsParts.push(ruleMessage);
|
|
573
|
-
}
|
|
574
|
-
if (commandMessage) {
|
|
575
|
-
countsParts.push(commandMessage);
|
|
576
|
-
}
|
|
577
|
-
if (hookMessage) {
|
|
578
|
-
countsParts.push(hookMessage);
|
|
579
|
-
}
|
|
580
|
-
if (skillMessage) {
|
|
581
|
-
countsParts.push(skillMessage);
|
|
582
|
-
}
|
|
583
|
-
const countsMessage = countsParts.length > 0
|
|
584
|
-
? countsParts.join(", ").replace(/, ([^,]*)$/, " and $1")
|
|
585
|
-
: "0 rules";
|
|
586
|
-
if (dryRun) {
|
|
587
|
-
if (result.packagesCount > 1) {
|
|
588
|
-
console.log(`Dry run: validated ${countsMessage} across ${result.packagesCount} packages`);
|
|
589
|
-
}
|
|
590
|
-
else {
|
|
591
|
-
console.log(`Dry run: validated ${countsMessage}`);
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
else if (ruleCount === 0 &&
|
|
595
|
-
commandCount === 0 &&
|
|
596
|
-
hookCount === 0 &&
|
|
597
|
-
skillCount === 0) {
|
|
598
|
-
console.log("No rules, commands, hooks, or skills installed");
|
|
599
|
-
}
|
|
600
|
-
else if (result.packagesCount > 1) {
|
|
601
|
-
console.log(`Successfully installed ${countsMessage} across ${result.packagesCount} packages`);
|
|
602
|
-
}
|
|
603
|
-
else {
|
|
604
|
-
console.log(`Successfully installed ${countsMessage}`);
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
}
|
package/dist/commands/list.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function listCommand(): Promise<void>;
|
package/dist/commands/list.js
DELETED
|
@@ -1,40 +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.listCommand = listCommand;
|
|
7
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
-
const config_1 = require("../utils/config");
|
|
9
|
-
async function listCommand() {
|
|
10
|
-
const config = await (0, config_1.loadConfig)();
|
|
11
|
-
if (!config) {
|
|
12
|
-
console.log(chalk_1.default.red("Configuration file not found!"));
|
|
13
|
-
console.log(`Run ${chalk_1.default.blue("npx aicm init")} to create one.`);
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
const hasRules = config.rules && config.rules.length > 0;
|
|
17
|
-
const hasCommands = config.commands && config.commands.length > 0;
|
|
18
|
-
if (!hasRules && !hasCommands) {
|
|
19
|
-
console.log(chalk_1.default.yellow("No rules or commands defined in configuration."));
|
|
20
|
-
console.log(`Edit your ${chalk_1.default.blue("aicm.json")} file to add rules or commands.`);
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
if (hasRules) {
|
|
24
|
-
console.log(chalk_1.default.blue("Configured Rules:"));
|
|
25
|
-
console.log(chalk_1.default.dim("─".repeat(50)));
|
|
26
|
-
for (const rule of config.rules) {
|
|
27
|
-
console.log(`${chalk_1.default.bold(rule.name)} - ${rule.sourcePath} ${rule.presetName ? `[${rule.presetName}]` : ""}`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
if (hasCommands) {
|
|
31
|
-
if (hasRules) {
|
|
32
|
-
console.log();
|
|
33
|
-
}
|
|
34
|
-
console.log(chalk_1.default.blue("Configured Commands:"));
|
|
35
|
-
console.log(chalk_1.default.dim("─".repeat(50)));
|
|
36
|
-
for (const command of config.commands) {
|
|
37
|
-
console.log(`${chalk_1.default.bold(command.name)} - ${command.sourcePath} ${command.presetName ? `[${command.presetName}]` : ""}`);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|