cursor-lint 0.3.1 → 0.4.1

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,7 +1,12 @@
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
 
8
+ ![cursor-lint demo](demo.png)
9
+
5
10
  ```bash
6
11
  npx cursor-lint
7
12
  ```
@@ -92,3 +97,11 @@ MIT
92
97
  ---
93
98
 
94
99
  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)
100
+
101
+ ---
102
+
103
+ ## Related
104
+
105
+ - [cursorrules-collection](https://github.com/cursorrulespacks/cursorrules-collection) — 77+ free .mdc rules
106
+ - [Cursor Setup Audit](https://cursorrulespacks.gumroad.com/l/cursor-setup-audit) — Professional review of your rules setup ($50)
107
+ - [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.1",
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.1';
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
 
@@ -209,6 +246,8 @@ async function main() {
209
246
  if (totalErrors > 0) {
210
247
  console.log(`${DIM}Need help fixing these? Get a full setup review:${RESET}`);
211
248
  console.log(`${CYAN}https://cursorrulespacks.gumroad.com/l/cursor-setup-audit${RESET}\n`);
249
+ } else if (totalPassed > 0) {
250
+ console.log(`${DIM}If cursor-lint saved you time: ${CYAN}https://github.com/cursorrulespacks/cursor-lint${RESET} ${DIM}(⭐ helps others find it)${RESET}\n`);
212
251
  }
213
252
 
214
253
  process.exit(totalErrors > 0 ? 1 : 0);
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 };