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.
@@ -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
- }
@@ -1 +0,0 @@
1
- export declare function listCommand(): Promise<void>;
@@ -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
- }