aicm 0.14.4 → 0.14.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.
Files changed (46) hide show
  1. package/dist/commands/install.js +5 -5
  2. package/package.json +1 -1
  3. package/dist/api_v2.d.ts +0 -9
  4. package/dist/api_v2.js +0 -12
  5. package/dist/bin/aicm_v2.d.ts +0 -2
  6. package/dist/bin/aicm_v2.js +0 -8
  7. package/dist/cli_v2.d.ts +0 -2
  8. package/dist/cli_v2.js +0 -94
  9. package/dist/commands/install/install-package.d.ts +0 -53
  10. package/dist/commands/install/install-package.js +0 -122
  11. package/dist/commands/install/install-single-package.d.ts +0 -53
  12. package/dist/commands/install/install-single-package.js +0 -139
  13. package/dist/commands/install/install-workspaces.d.ts +0 -9
  14. package/dist/commands/install/install-workspaces.js +0 -172
  15. package/dist/commands/install_new.d.ts +0 -17
  16. package/dist/commands/install_new.js +0 -457
  17. package/dist/commands/install_v2.d.ts +0 -52
  18. package/dist/commands/install_v2.js +0 -505
  19. package/dist/commands/install_/327/2242.d.ts +0 -59
  20. package/dist/commands/install_/327/2242.js +0 -546
  21. package/dist/commands/workspaces/discovery.d.ts +0 -7
  22. package/dist/commands/workspaces/discovery.js +0 -50
  23. package/dist/commands/workspaces/workspaces-install.d.ts +0 -9
  24. package/dist/commands/workspaces/workspaces-install.js +0 -48
  25. package/dist/index.d.ts +0 -2
  26. package/dist/index.js +0 -76
  27. package/dist/types/index.d.ts +0 -64
  28. package/dist/types/index.js +0 -2
  29. package/dist/utils/config_new.d.ts +0 -64
  30. package/dist/utils/config_new.js +0 -228
  31. package/dist/utils/config_v2.d.ts +0 -64
  32. package/dist/utils/config_v2.js +0 -250
  33. package/dist/utils/glob-handler.d.ts +0 -35
  34. package/dist/utils/glob-handler.js +0 -125
  35. package/dist/utils/mcp-writer.d.ts +0 -14
  36. package/dist/utils/mcp-writer.js +0 -69
  37. package/dist/utils/mdc-parser.d.ts +0 -9
  38. package/dist/utils/mdc-parser.js +0 -59
  39. package/dist/utils/rule-collector.d.ts +0 -33
  40. package/dist/utils/rule-collector.js +0 -169
  41. package/dist/utils/rule-detector.d.ts +0 -4
  42. package/dist/utils/rule-detector.js +0 -31
  43. package/dist/utils/rule-status.d.ts +0 -8
  44. package/dist/utils/rule-status.js +0 -53
  45. package/dist/utils/rule-writer.d.ts +0 -6
  46. package/dist/utils/rule-writer.js +0 -118
@@ -1,505 +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.installPackage = installPackage;
7
- exports.install = install;
8
- exports.installCommand = installCommand;
9
- const chalk_1 = __importDefault(require("chalk"));
10
- const fs_extra_1 = __importDefault(require("fs-extra"));
11
- const node_path_1 = __importDefault(require("node:path"));
12
- const child_process_1 = require("child_process");
13
- const config_v2_1 = require("../utils/config_v2");
14
- const working_directory_1 = require("../utils/working-directory");
15
- const is_ci_1 = require("../utils/is-ci");
16
- function getTargetPaths() {
17
- const projectDir = process.cwd();
18
- return {
19
- cursor: node_path_1.default.join(projectDir, ".cursor", "rules", "aicm"),
20
- windsurf: node_path_1.default.join(projectDir, ".aicm"),
21
- codex: node_path_1.default.join(projectDir, ".aicm"),
22
- };
23
- }
24
- function writeCursorRules(rules, cursorRulesDir) {
25
- fs_extra_1.default.emptyDirSync(cursorRulesDir);
26
- for (const rule of rules) {
27
- let rulePath;
28
- const ruleNameParts = rule.name.split(node_path_1.default.sep).filter(Boolean);
29
- if (rule.presetName) {
30
- // For rules from presets, create a namespaced directory structure
31
- const namespace = extractNamespaceFromPresetPath(rule.presetName);
32
- // Path will be: cursorRulesDir/namespace/rule-name.mdc
33
- rulePath = node_path_1.default.join(cursorRulesDir, ...namespace, ...ruleNameParts);
34
- }
35
- else {
36
- // For local rules, maintain the original flat structure
37
- rulePath = node_path_1.default.join(cursorRulesDir, ...ruleNameParts);
38
- }
39
- const ruleFile = rulePath + ".mdc";
40
- fs_extra_1.default.ensureDirSync(node_path_1.default.dirname(ruleFile));
41
- fs_extra_1.default.writeFileSync(ruleFile, rule.content);
42
- }
43
- }
44
- function extractNamespaceFromPresetPath(presetPath) {
45
- // Special case: npm package names always use forward slashes, regardless of platform
46
- if (presetPath.startsWith("@")) {
47
- // For scoped packages like @scope/package/subdir, create nested directories
48
- return presetPath.split("/");
49
- }
50
- const parts = presetPath.split(node_path_1.default.sep);
51
- return parts.filter((part) => part.length > 0); // Filter out empty segments
52
- }
53
- function generateRulesFileContent(ruleFiles) {
54
- const alwaysApplyRules = [];
55
- const optInRules = [];
56
- for (const rule of ruleFiles) {
57
- // Parse metadata to determine rule type
58
- const metadata = rule.content.match(/^---\n([\s\S]*?)\n---/);
59
- let alwaysApply = false;
60
- if (metadata) {
61
- try {
62
- const frontmatter = metadata[1];
63
- // Simple YAML parsing for alwaysApply field
64
- const alwaysApplyMatch = frontmatter.match(/alwaysApply:\s*(true|false)/);
65
- if (alwaysApplyMatch) {
66
- alwaysApply = alwaysApplyMatch[1] === "true";
67
- }
68
- }
69
- catch (_a) {
70
- // If parsing fails, default to false
71
- }
72
- }
73
- if (alwaysApply) {
74
- alwaysApplyRules.push(`- ${rule.path}`);
75
- }
76
- else {
77
- optInRules.push(`- ${rule.path}`);
78
- }
79
- }
80
- let content = "<!-- AICM:BEGIN -->\n";
81
- if (alwaysApplyRules.length > 0) {
82
- content +=
83
- "The following rules always apply to all files in the project:\n";
84
- content += alwaysApplyRules.join("\n") + "\n\n";
85
- }
86
- if (optInRules.length > 0) {
87
- content +=
88
- "The following rules are available for the AI to include when needed:\n";
89
- content += optInRules.join("\n") + "\n\n";
90
- }
91
- content += "<!-- AICM:END -->\n";
92
- return content;
93
- }
94
- /**
95
- * Write rules file content to a file, preserving existing content outside markers
96
- */
97
- function writeRulesFile(rulesContent, rulesFilePath) {
98
- const RULES_BEGIN = "<!-- AICM:BEGIN -->";
99
- const RULES_END = "<!-- AICM:END -->";
100
- let fileContent;
101
- if (fs_extra_1.default.existsSync(rulesFilePath)) {
102
- const existingContent = fs_extra_1.default.readFileSync(rulesFilePath, "utf8");
103
- if (existingContent.includes(RULES_BEGIN) &&
104
- existingContent.includes(RULES_END)) {
105
- const beforeMarker = existingContent.split(RULES_BEGIN)[0];
106
- const afterMarker = existingContent.split(RULES_END)[1];
107
- fileContent = beforeMarker + rulesContent + afterMarker;
108
- }
109
- else {
110
- // Preserve the existing content and append markers
111
- let separator = "";
112
- if (!existingContent.endsWith("\n")) {
113
- separator += "\n";
114
- }
115
- if (!existingContent.endsWith("\n\n")) {
116
- separator += "\n";
117
- }
118
- fileContent = existingContent + separator + rulesContent;
119
- }
120
- }
121
- else {
122
- // Create new file with markers and content
123
- fileContent = rulesContent;
124
- }
125
- fs_extra_1.default.writeFileSync(rulesFilePath, fileContent);
126
- }
127
- /**
128
- * Write rules to a shared directory and update the given rules file
129
- */
130
- function writeRulesForFile(rules, ruleDir, rulesFile) {
131
- fs_extra_1.default.emptyDirSync(ruleDir);
132
- const ruleFiles = rules.map((rule) => {
133
- let rulePath;
134
- const ruleNameParts = rule.name.split(node_path_1.default.sep).filter(Boolean);
135
- if (rule.presetName) {
136
- // For rules from presets, create a namespaced directory structure
137
- const namespace = extractNamespaceFromPresetPath(rule.presetName);
138
- // Path will be: ruleDir/namespace/rule-name.md
139
- rulePath = node_path_1.default.join(ruleDir, ...namespace, ...ruleNameParts);
140
- }
141
- else {
142
- // For local rules, maintain the original flat structure
143
- rulePath = node_path_1.default.join(ruleDir, ...ruleNameParts);
144
- }
145
- const physicalRulePath = rulePath + ".md";
146
- fs_extra_1.default.ensureDirSync(node_path_1.default.dirname(physicalRulePath));
147
- fs_extra_1.default.writeFileSync(physicalRulePath, rule.content);
148
- const relativeRuleDir = node_path_1.default.basename(ruleDir);
149
- // For the rules file, maintain the same structure
150
- let windsurfPath;
151
- if (rule.presetName) {
152
- const namespace = extractNamespaceFromPresetPath(rule.presetName);
153
- windsurfPath =
154
- node_path_1.default.join(relativeRuleDir, ...namespace, ...ruleNameParts) + ".md";
155
- }
156
- else {
157
- windsurfPath = node_path_1.default.join(relativeRuleDir, ...ruleNameParts) + ".md";
158
- }
159
- // Normalize to POSIX style for cross-platform compatibility
160
- const windsurfPathPosix = windsurfPath.replace(/\\/g, "/");
161
- return {
162
- name: rule.name,
163
- path: windsurfPathPosix,
164
- content: rule.content,
165
- };
166
- });
167
- const rulesContent = generateRulesFileContent(ruleFiles);
168
- writeRulesFile(rulesContent, node_path_1.default.join(process.cwd(), rulesFile));
169
- }
170
- /**
171
- * Write all collected rules to their respective IDE targets
172
- */
173
- function writeRulesToTargets(rules, targets) {
174
- const targetPaths = getTargetPaths();
175
- for (const target of targets) {
176
- switch (target) {
177
- case "cursor":
178
- if (rules.length > 0) {
179
- writeCursorRules(rules, targetPaths.cursor);
180
- }
181
- break;
182
- case "windsurf":
183
- if (rules.length > 0) {
184
- writeRulesForFile(rules, targetPaths.windsurf, ".windsurfrules");
185
- }
186
- break;
187
- case "codex":
188
- if (rules.length > 0) {
189
- writeRulesForFile(rules, targetPaths.codex, "AGENTS.md");
190
- }
191
- break;
192
- }
193
- }
194
- }
195
- /**
196
- * Write MCP servers configuration to IDE targets
197
- */
198
- function writeMcpServersToTargets(mcpServers, targets, cwd) {
199
- if (!mcpServers || Object.keys(mcpServers).length === 0)
200
- return;
201
- for (const target of targets) {
202
- if (target === "cursor") {
203
- const mcpPath = node_path_1.default.join(cwd, ".cursor", "mcp.json");
204
- writeMcpServersToFile(mcpServers, mcpPath);
205
- }
206
- // Windsurf and Codex do not support project mcpServers, so skip
207
- }
208
- }
209
- /**
210
- * Write MCP servers configuration to a specific file
211
- */
212
- function writeMcpServersToFile(mcpServers, mcpPath) {
213
- var _a;
214
- fs_extra_1.default.ensureDirSync(node_path_1.default.dirname(mcpPath));
215
- const existingConfig = fs_extra_1.default.existsSync(mcpPath)
216
- ? fs_extra_1.default.readJsonSync(mcpPath)
217
- : {};
218
- const existingMcpServers = (_a = existingConfig === null || existingConfig === void 0 ? void 0 : existingConfig.mcpServers) !== null && _a !== void 0 ? _a : {};
219
- // Filter out any existing aicm-managed servers (with aicm: true)
220
- // This removes stale aicm servers that are no longer in the configuration
221
- const userMcpServers = {};
222
- for (const [key, value] of Object.entries(existingMcpServers)) {
223
- if (typeof value === "object" && value !== null && value.aicm !== true) {
224
- userMcpServers[key] = value;
225
- }
226
- }
227
- // Mark new aicm servers as managed and filter out canceled servers
228
- const aicmMcpServers = {};
229
- for (const [key, value] of Object.entries(mcpServers)) {
230
- if (value !== false) {
231
- aicmMcpServers[key] = {
232
- ...value,
233
- aicm: true,
234
- };
235
- }
236
- }
237
- // Merge user servers with aicm servers (aicm servers override user servers with same key)
238
- const mergedMcpServers = {
239
- ...userMcpServers,
240
- ...aicmMcpServers,
241
- };
242
- const mergedConfig = {
243
- ...existingConfig,
244
- mcpServers: mergedMcpServers,
245
- };
246
- fs_extra_1.default.writeJsonSync(mcpPath, mergedConfig, { spaces: 2 });
247
- }
248
- /**
249
- * Discover all packages with aicm configurations using git ls-files
250
- */
251
- function findAicmFiles(rootDir) {
252
- try {
253
- const output = (0, child_process_1.execSync)("git ls-files --cached --others --exclude-standard aicm.json **/aicm.json", {
254
- cwd: rootDir,
255
- encoding: "utf8",
256
- });
257
- return output
258
- .trim()
259
- .split("\n")
260
- .filter(Boolean)
261
- .map((file) => node_path_1.default.resolve(rootDir, file));
262
- }
263
- catch (_a) {
264
- // Fallback to manual search if git is not available
265
- return [];
266
- }
267
- }
268
- /**
269
- * Discover all packages with aicm configurations
270
- */
271
- async function discoverPackagesWithAicm(rootDir) {
272
- const aicmFiles = findAicmFiles(rootDir);
273
- const packages = [];
274
- for (const aicmFile of aicmFiles) {
275
- const packageDir = node_path_1.default.dirname(aicmFile);
276
- const relativePath = node_path_1.default.relative(rootDir, packageDir);
277
- // Normalize to forward slashes for cross-platform compatibility
278
- const normalizedRelativePath = relativePath.replace(/\\/g, "/");
279
- const config = await (0, config_v2_1.loadConfig)(packageDir);
280
- if (config) {
281
- packages.push({
282
- relativePath: normalizedRelativePath || ".",
283
- absolutePath: packageDir,
284
- config,
285
- });
286
- }
287
- }
288
- // Sort packages by relativePath for deterministic order
289
- return packages.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
290
- }
291
- /**
292
- * Install rules for a single package (used within workspaces and standalone installs)
293
- */
294
- async function installPackage(options = {}) {
295
- const cwd = options.cwd || process.cwd();
296
- return (0, working_directory_1.withWorkingDirectory)(cwd, async () => {
297
- let resolvedConfig;
298
- if (options.config) {
299
- resolvedConfig = options.config;
300
- }
301
- else {
302
- resolvedConfig = await (0, config_v2_1.loadConfig)(cwd);
303
- }
304
- if (!resolvedConfig) {
305
- return {
306
- success: false,
307
- error: new Error("Configuration file not found"),
308
- installedRuleCount: 0,
309
- packagesCount: 0,
310
- };
311
- }
312
- const { config, rules, mcpServers } = resolvedConfig;
313
- // Check if rules are defined (either directly or through presets)
314
- if (!rules || rules.length === 0) {
315
- // If there are no presets defined either, show a message
316
- if (!config.presets || config.presets.length === 0) {
317
- return {
318
- success: false,
319
- error: new Error("No rules defined in configuration"),
320
- installedRuleCount: 0,
321
- packagesCount: 0,
322
- };
323
- }
324
- }
325
- try {
326
- // Write rules to targets
327
- writeRulesToTargets(rules, config.targets);
328
- // Write MCP servers
329
- if (mcpServers && Object.keys(mcpServers).length > 0) {
330
- writeMcpServersToTargets(mcpServers, config.targets, cwd);
331
- }
332
- return {
333
- success: true,
334
- installedRuleCount: rules.length,
335
- packagesCount: 1,
336
- };
337
- }
338
- catch (error) {
339
- return {
340
- success: false,
341
- error: error instanceof Error ? error : new Error(String(error)),
342
- installedRuleCount: 0,
343
- packagesCount: 0,
344
- };
345
- }
346
- });
347
- }
348
- /**
349
- * Install aicm configurations for all packages in a workspace
350
- */
351
- async function installWorkspacesPackages(packages, options = {}) {
352
- const results = [];
353
- let totalRuleCount = 0;
354
- // Install packages sequentially for now (can be parallelized later)
355
- for (const pkg of packages) {
356
- const packagePath = pkg.absolutePath;
357
- try {
358
- const result = await installPackage({
359
- ...options,
360
- cwd: packagePath,
361
- config: pkg.config,
362
- });
363
- totalRuleCount += result.installedRuleCount;
364
- results.push({
365
- path: pkg.relativePath,
366
- success: result.success,
367
- error: result.error,
368
- installedRuleCount: result.installedRuleCount,
369
- });
370
- }
371
- catch (error) {
372
- results.push({
373
- path: pkg.relativePath,
374
- success: false,
375
- error: error instanceof Error ? error : new Error(String(error)),
376
- installedRuleCount: 0,
377
- });
378
- }
379
- }
380
- const failedPackages = results.filter((r) => !r.success);
381
- return {
382
- success: failedPackages.length === 0,
383
- packages: results,
384
- totalRuleCount,
385
- };
386
- }
387
- /**
388
- * Install rules across multiple packages in a workspace
389
- */
390
- async function installWorkspaces(cwd, installOnCI, verbose = false) {
391
- return (0, working_directory_1.withWorkingDirectory)(cwd, async () => {
392
- if (verbose) {
393
- console.log(chalk_1.default.blue("🔍 Discovering packages..."));
394
- }
395
- const allPackages = await discoverPackagesWithAicm(cwd);
396
- const packages = allPackages.filter((pkg) => {
397
- const isRoot = pkg.relativePath === ".";
398
- if (!isRoot)
399
- return true;
400
- // For root directories, only keep if it has rules or presets
401
- const hasRules = pkg.config.rules && pkg.config.rules.length > 0;
402
- const hasPresets = pkg.config.config.presets && pkg.config.config.presets.length > 0;
403
- return hasRules || hasPresets;
404
- });
405
- if (packages.length === 0) {
406
- return {
407
- success: false,
408
- error: new Error("No packages with aicm configurations found"),
409
- installedRuleCount: 0,
410
- packagesCount: 0,
411
- };
412
- }
413
- if (verbose) {
414
- console.log(chalk_1.default.blue(`Found ${packages.length} packages with aicm configurations:`));
415
- packages.forEach((pkg) => {
416
- console.log(chalk_1.default.gray(` - ${pkg.relativePath}`));
417
- });
418
- console.log(chalk_1.default.blue(`📦 Installing configurations...`));
419
- }
420
- const result = await installWorkspacesPackages(packages, {
421
- installOnCI,
422
- verbose,
423
- });
424
- if (verbose) {
425
- result.packages.forEach((pkg) => {
426
- if (pkg.success) {
427
- console.log(chalk_1.default.green(`✅ ${pkg.path} (${pkg.installedRuleCount} rules)`));
428
- }
429
- else {
430
- console.log(chalk_1.default.red(`❌ ${pkg.path}: ${pkg.error}`));
431
- }
432
- });
433
- }
434
- const failedPackages = result.packages.filter((r) => !r.success);
435
- if (failedPackages.length > 0) {
436
- console.log(chalk_1.default.yellow(`Installation completed with errors`));
437
- if (verbose) {
438
- console.log(chalk_1.default.green(`Successfully installed: ${result.packages.length - failedPackages.length}/${result.packages.length} packages (${result.totalRuleCount} rules total)`));
439
- console.log(chalk_1.default.red(`Failed packages: ${failedPackages.map((p) => p.path).join(", ")}`));
440
- }
441
- const errorDetails = failedPackages
442
- .map((p) => `${p.path}: ${p.error}`)
443
- .join("; ");
444
- return {
445
- success: false,
446
- error: new Error(`Package installation failed for ${failedPackages.length} package(s): ${errorDetails}`),
447
- installedRuleCount: result.totalRuleCount,
448
- packagesCount: result.packages.length,
449
- };
450
- }
451
- console.log(`Successfully installed ${result.totalRuleCount} rules across ${result.packages.length} packages`);
452
- return {
453
- success: true,
454
- installedRuleCount: result.totalRuleCount,
455
- packagesCount: result.packages.length,
456
- };
457
- });
458
- }
459
- /**
460
- * Core implementation of the rule installation logic
461
- */
462
- async function install(options = {}) {
463
- const cwd = options.cwd || process.cwd();
464
- const installOnCI = options.installOnCI === true; // Default to false if not specified
465
- const inCI = (0, is_ci_1.isCIEnvironment)();
466
- if (inCI && !installOnCI) {
467
- console.log(chalk_1.default.yellow("Detected CI environment, skipping install."));
468
- return {
469
- success: true,
470
- installedRuleCount: 0,
471
- packagesCount: 0,
472
- };
473
- }
474
- return (0, working_directory_1.withWorkingDirectory)(cwd, async () => {
475
- let resolvedConfig;
476
- if (options.config) {
477
- resolvedConfig = options.config;
478
- }
479
- else {
480
- resolvedConfig = await (0, config_v2_1.loadConfig)(cwd);
481
- }
482
- if (resolvedConfig === null || resolvedConfig === void 0 ? void 0 : resolvedConfig.config.workspaces) {
483
- return await installWorkspaces(cwd, installOnCI, options.verbose);
484
- }
485
- return installPackage(options);
486
- });
487
- }
488
- /**
489
- * CLI command wrapper for install
490
- */
491
- async function installCommand(installOnCI, verbose) {
492
- var _a;
493
- const result = await install({ installOnCI, verbose });
494
- if (!result.success) {
495
- throw (_a = result.error) !== null && _a !== void 0 ? _a : new Error("Installation failed with unknown error");
496
- }
497
- else {
498
- if (result.packagesCount > 1) {
499
- console.log(`Successfully installed ${result.installedRuleCount} rules across ${result.packagesCount} packages`);
500
- }
501
- else {
502
- console.log("Rules installation completed");
503
- }
504
- }
505
- }
@@ -1,59 +0,0 @@
1
- import { ResolvedConfig } from "../utils/config_new";
2
- /**
3
- * Options for the install functions
4
- */
5
- export interface InstallOptions {
6
- /**
7
- * Base directory to use instead of process.cwd()
8
- */
9
- cwd?: string;
10
- /**
11
- * Custom config object to use instead of loading from file
12
- */
13
- config?: ResolvedConfig;
14
- /**
15
- * allow installation on CI environments
16
- */
17
- installOnCI?: boolean;
18
- /**
19
- * Show verbose output during installation
20
- */
21
- verbose?: boolean;
22
- }
23
- /**
24
- * Result of the install operation
25
- */
26
- export interface InstallResult {
27
- /**
28
- * Whether the operation was successful
29
- */
30
- success: boolean;
31
- /**
32
- * Error message if the operation failed
33
- */
34
- error?: string;
35
- /**
36
- * Error stack trace for debugging (when available)
37
- */
38
- errorStack?: string;
39
- /**
40
- * Number of rules installed
41
- */
42
- installedRuleCount: number;
43
- /**
44
- * Number of packages installed
45
- */
46
- packagesCount: number;
47
- }
48
- /**
49
- * Install rules for a single package (used within workspaces and standalone installs)
50
- */
51
- export declare function installPackage(options?: InstallOptions): Promise<InstallResult>;
52
- /**
53
- * Core implementation of the rule installation logic
54
- */
55
- export declare function install(options?: InstallOptions): Promise<InstallResult>;
56
- /**
57
- * CLI command wrapper for install
58
- */
59
- export declare function installCommand(installOnCI?: boolean, verbose?: boolean): Promise<void>;