cursor-lint 0.3.1 → 0.4.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/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # cursor-lint
2
2
 
3
+ [![npm](https://img.shields.io/npm/dw/cursor-lint)](https://www.npmjs.com/package/cursor-lint)
4
+ [![npm version](https://img.shields.io/npm/v/cursor-lint)](https://www.npmjs.com/package/cursor-lint)
5
+
3
6
  Lint your [Cursor](https://cursor.com) rules. Catch common mistakes before they silently break your workflow.
4
7
 
5
8
  ```bash
@@ -92,3 +95,11 @@ MIT
92
95
  ---
93
96
 
94
97
  Made by [nedcodes](https://dev.to/nedcodes) · [Free rules collection](https://github.com/cursorrulespacks/cursorrules-collection) · [Setup audits](https://cursorrulespacks.gumroad.com/l/cursor-setup-audit)
98
+
99
+ ---
100
+
101
+ ## Related
102
+
103
+ - [cursorrules-collection](https://github.com/cursorrulespacks/cursorrules-collection) — 77+ free .mdc rules
104
+ - [Cursor Setup Audit](https://cursorrulespacks.gumroad.com/l/cursor-setup-audit) — Professional review of your rules setup ($50)
105
+ - [Articles on Dev.to](https://dev.to/nedcodes) — Guides on writing effective Cursor rules
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cursor-lint",
3
- "version": "0.3.1",
4
- "description": "Lint your Cursor rules catch common mistakes before they break your workflow",
3
+ "version": "0.4.0",
4
+ "description": "Lint your Cursor rules \u2014 catch common mistakes before they break your workflow",
5
5
  "main": "src/index.js",
6
6
  "bin": {
7
7
  "cursor-lint": "src/cli.js"
@@ -12,7 +12,12 @@
12
12
  "cursorrules",
13
13
  "mdc",
14
14
  "linter",
15
- "developer-tools"
15
+ "developer-tools",
16
+ "cursor-rules",
17
+ "lint",
18
+ "validate",
19
+ "ai-coding",
20
+ "code-quality"
16
21
  ],
17
22
  "author": "nedcodes",
18
23
  "license": "MIT",
@@ -26,4 +31,4 @@
26
31
  "files": [
27
32
  "src/"
28
33
  ]
29
- }
34
+ }
package/src/cli.js CHANGED
@@ -4,8 +4,9 @@ const path = require('path');
4
4
  const { lintProject } = require('./index');
5
5
  const { verifyProject } = require('./verify');
6
6
  const { initProject } = require('./init');
7
+ const { fixProject } = require('./fix');
7
8
 
8
- const VERSION = '0.3.1';
9
+ const VERSION = '0.4.0';
9
10
 
10
11
  const RED = '\x1b[31m';
11
12
  const YELLOW = '\x1b[33m';
@@ -28,6 +29,7 @@ ${YELLOW}Options:${RESET}
28
29
  --version, -v Show version number
29
30
  --verify Check if code follows rules with verify: blocks
30
31
  --init Generate starter .mdc rules (auto-detects your stack)
32
+ --fix Auto-fix common issues (missing frontmatter, alwaysApply)
31
33
 
32
34
  ${YELLOW}What it checks (default):${RESET}
33
35
  • .cursorrules files (warns about agent mode compatibility)
@@ -81,8 +83,43 @@ async function main() {
81
83
  const cwd = process.cwd();
82
84
  const isVerify = args.includes('--verify');
83
85
  const isInit = args.includes('--init');
86
+ const isFix = args.includes('--fix');
84
87
 
85
- if (isInit) {
88
+ if (isFix) {
89
+ console.log(`\n🔧 cursor-lint v${VERSION} --fix\n`);
90
+ console.log(`Scanning ${cwd} for fixable issues...\n`);
91
+
92
+ const results = await fixProject(cwd);
93
+
94
+ if (results.length === 0) {
95
+ console.log(`${YELLOW}No .mdc files found in .cursor/rules/${RESET}\n`);
96
+ process.exit(0);
97
+ }
98
+
99
+ let totalFixed = 0;
100
+ for (const result of results) {
101
+ const relPath = path.relative(cwd, result.file) || result.file;
102
+ if (result.changes.length > 0) {
103
+ console.log(`${GREEN}✓${RESET} ${relPath}`);
104
+ for (const change of result.changes) {
105
+ console.log(` ${DIM}→ ${change}${RESET}`);
106
+ }
107
+ totalFixed++;
108
+ } else {
109
+ console.log(`${DIM} ${relPath} — nothing to fix${RESET}`);
110
+ }
111
+ }
112
+
113
+ console.log();
114
+ console.log('─'.repeat(50));
115
+ if (totalFixed > 0) {
116
+ console.log(`${GREEN}Fixed ${totalFixed} file(s)${RESET}. Run cursor-lint to verify.\n`);
117
+ } else {
118
+ console.log(`${GREEN}All files look good — nothing to fix${RESET}\n`);
119
+ }
120
+ process.exit(0);
121
+
122
+ } else if (isInit) {
86
123
  console.log(`\n🔍 cursor-lint v${VERSION} --init\n`);
87
124
  console.log(`Detecting stack in ${cwd}...\n`);
88
125
 
package/src/fix.js ADDED
@@ -0,0 +1,89 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ function addFrontmatter(content, filePath) {
5
+ const name = path.basename(filePath, '.mdc');
6
+ const frontmatter = `---
7
+ description: ${name} rules
8
+ alwaysApply: true
9
+ ---
10
+ `;
11
+ return { fixed: frontmatter + content, changes: ['Added YAML frontmatter with alwaysApply: true'] };
12
+ }
13
+
14
+ function addAlwaysApply(content) {
15
+ // Insert alwaysApply: true after the first ---
16
+ const match = content.match(/^(---\n)([\s\S]*?)(---)/);
17
+ if (!match) return { fixed: content, changes: [] };
18
+
19
+ const frontmatterBody = match[2];
20
+ if (frontmatterBody.includes('alwaysApply')) return { fixed: content, changes: [] };
21
+
22
+ const newFm = match[1] + 'alwaysApply: true\n' + frontmatterBody + match[3];
23
+ const rest = content.slice(match[0].length);
24
+ return { fixed: newFm + rest, changes: ['Added alwaysApply: true to frontmatter'] };
25
+ }
26
+
27
+ function addDescription(content, filePath) {
28
+ const match = content.match(/^(---\n)([\s\S]*?)(---)/);
29
+ if (!match) return { fixed: content, changes: [] };
30
+
31
+ const frontmatterBody = match[2];
32
+ if (frontmatterBody.includes('description')) return { fixed: content, changes: [] };
33
+
34
+ const name = path.basename(filePath, '.mdc');
35
+ const newFm = match[1] + `description: ${name} rules\n` + frontmatterBody + match[3];
36
+ const rest = content.slice(match[0].length);
37
+ return { fixed: newFm + rest, changes: [`Added description: "${name} rules" to frontmatter`] };
38
+ }
39
+
40
+ async function fixFile(filePath) {
41
+ let content = fs.readFileSync(filePath, 'utf-8');
42
+ const allChanges = [];
43
+
44
+ // Check if frontmatter exists
45
+ const hasFm = content.match(/^---\n[\s\S]*?\n---/);
46
+
47
+ if (!hasFm) {
48
+ const result = addFrontmatter(content, filePath);
49
+ content = result.fixed;
50
+ allChanges.push(...result.changes);
51
+ } else {
52
+ // Fix missing alwaysApply
53
+ const r1 = addAlwaysApply(content);
54
+ if (r1.changes.length) {
55
+ content = r1.fixed;
56
+ allChanges.push(...r1.changes);
57
+ }
58
+
59
+ // Fix missing description
60
+ const r2 = addDescription(content, filePath);
61
+ if (r2.changes.length) {
62
+ content = r2.fixed;
63
+ allChanges.push(...r2.changes);
64
+ }
65
+ }
66
+
67
+ if (allChanges.length > 0) {
68
+ fs.writeFileSync(filePath, content, 'utf-8');
69
+ }
70
+
71
+ return { file: filePath, changes: allChanges };
72
+ }
73
+
74
+ async function fixProject(dir) {
75
+ const results = [];
76
+ const rulesDir = path.join(dir, '.cursor', 'rules');
77
+
78
+ if (fs.existsSync(rulesDir) && fs.statSync(rulesDir).isDirectory()) {
79
+ for (const entry of fs.readdirSync(rulesDir)) {
80
+ if (entry.endsWith('.mdc')) {
81
+ results.push(await fixFile(path.join(rulesDir, entry)));
82
+ }
83
+ }
84
+ }
85
+
86
+ return results;
87
+ }
88
+
89
+ module.exports = { fixProject, fixFile };