cursor-lint 0.10.0 → 0.11.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
@@ -121,7 +121,7 @@ Every check in cursor-lint comes from [actual experiments](https://dev.to/nedcod
121
121
 
122
122
  ## Need a deeper review?
123
123
 
124
- cursor-lint catches structural issues. For a full review of your rules, project structure, and model settings, I offer [$50 async setup audits](https://cursorrulespacks.gumroad.com/l/cursor-setup-audit). You get a written report with specific fixes, not generic advice.
124
+ cursor-lint catches structural issues. For a full review of your rules, project structure, and model settings, I offer [$50 async setup audits](https://nedcodes.gumroad.com/l/cursor-setup-audit). You get a written report with specific fixes, not generic advice.
125
125
 
126
126
  ## License
127
127
 
@@ -129,12 +129,12 @@ MIT
129
129
 
130
130
  ---
131
131
 
132
- 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)
132
+ Made by [nedcodes](https://dev.to/nedcodes) · [Free rules collection](https://github.com/nedcodes-ok/cursorrules-collection) · [Setup audits](https://nedcodes.gumroad.com/l/cursor-setup-audit)
133
133
 
134
134
  ---
135
135
 
136
136
  ## Related
137
137
 
138
- - [cursorrules-collection](https://github.com/cursorrulespacks/cursorrules-collection) — 104 free .mdc rules
139
- - [Cursor Setup Audit](https://cursorrulespacks.gumroad.com/l/cursor-setup-audit) — Professional review of your rules setup ($50)
138
+ - [cursorrules-collection](https://github.com/nedcodes-ok/cursorrules-collection) — 104 free .mdc rules
139
+ - [Cursor Setup Audit](https://nedcodes.gumroad.com/l/cursor-setup-audit) — Professional review of your rules setup ($50)
140
140
  - [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.10.0",
4
- "description": "Lint your Cursor rules \u2014 catch common mistakes before they break your workflow",
3
+ "version": "0.11.1",
4
+ "description": "Lint your Cursor rules catch common mistakes before they break your workflow",
5
5
  "main": "src/index.js",
6
6
  "bin": {
7
7
  "cursor-lint": "src/cli.js"
@@ -21,9 +21,10 @@
21
21
  ],
22
22
  "author": "nedcodes",
23
23
  "license": "MIT",
24
+ "homepage": "https://github.com/nedcodes-ok/cursor-lint",
24
25
  "repository": {
25
26
  "type": "git",
26
- "url": "https://github.com/cursorrulespacks/cursor-lint.git"
27
+ "url": "https://github.com/nedcodes-ok/cursor-lint.git"
27
28
  },
28
29
  "engines": {
29
30
  "node": ">=16"
@@ -31,4 +32,4 @@
31
32
  "files": [
32
33
  "src/"
33
34
  ]
34
- }
35
+ }
package/src/cli.js CHANGED
@@ -8,7 +8,7 @@ const { fixProject } = require('./fix');
8
8
  const { generateRules, suggestSkills } = require('./generate');
9
9
  const { checkVersions, checkRuleVersionMismatches } = require('./versions');
10
10
 
11
- const VERSION = '0.10.0';
11
+ const VERSION = '0.11.0';
12
12
 
13
13
  const RED = '\x1b[31m';
14
14
  const YELLOW = '\x1b[33m';
@@ -39,6 +39,7 @@ ${YELLOW}Options:${RESET}
39
39
  ${YELLOW}What it checks (default):${RESET}
40
40
  • .cursorrules files (warns about agent mode compatibility)
41
41
  • .cursor/rules/*.mdc files (frontmatter, alwaysApply, etc.)
42
+ • Agent skill files (SKILL.md in .claude/skills/, skills/)
42
43
  • Vague rules that won't change AI behavior
43
44
  • YAML syntax errors
44
45
 
@@ -69,7 +70,7 @@ ${YELLOW}Examples:${RESET}
69
70
  npx cursor-lint --generate # Download community rules for your stack
70
71
 
71
72
  ${YELLOW}More info:${RESET}
72
- https://github.com/cursorrulespacks/cursor-lint
73
+ https://github.com/nedcodes-ok/cursor-lint
73
74
  `);
74
75
  }
75
76
 
@@ -431,10 +432,10 @@ async function main() {
431
432
  console.log(parts.join(', ') + '\n');
432
433
 
433
434
  if (totalErrors > 0) {
434
- console.log(`${DIM}Need help fixing these? Get a full setup review:${RESET}`);
435
- console.log(`${CYAN}https://cursorrulespacks.gumroad.com/l/cursor-setup-audit${RESET}\n`);
435
+ console.log(`${DIM}Try ${CYAN}cursor-lint --fix${RESET}${DIM} to auto-repair frontmatter issues.${RESET}`);
436
+ console.log(`${DIM}Run ${CYAN}cursor-lint --order${RESET}${DIM} to check which rules are actually loading.${RESET}\n`);
436
437
  } else if (totalPassed > 0) {
437
- console.log(`${DIM}If cursor-lint saved you time: ${CYAN}https://github.com/cursorrulespacks/cursor-lint${RESET} ${DIM}(⭐ helps others find it)${RESET}\n`);
438
+ console.log(`${DIM}If cursor-lint saved you time: ${CYAN}https://github.com/nedcodes-ok/cursor-lint${RESET} ${DIM}(⭐ helps others find it)${RESET}\n`);
438
439
  }
439
440
 
440
441
  process.exit(totalErrors > 0 ? 1 : 0);
package/src/generate.js CHANGED
@@ -2,7 +2,7 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const https = require('https');
4
4
 
5
- const BASE_URL = 'https://raw.githubusercontent.com/cursorrulespacks/cursorrules-collection/main/rules-mdc/';
5
+ const BASE_URL = 'https://raw.githubusercontent.com/nedcodes-ok/cursorrules-collection/main/rules-mdc/';
6
6
 
7
7
  // package.json dependencies → rule files
8
8
  const PKG_DEP_MAP = {
package/src/index.js CHANGED
@@ -94,6 +94,98 @@ async function lintMdcFile(filePath) {
94
94
  return { file: filePath, issues };
95
95
  }
96
96
 
97
+ async function lintSkillFile(filePath) {
98
+ const content = fs.readFileSync(filePath, 'utf-8');
99
+ const issues = [];
100
+
101
+ const fm = parseFrontmatter(content);
102
+
103
+ if (!fm.found) {
104
+ issues.push({ severity: 'error', message: 'Missing YAML frontmatter', hint: 'Add --- block with name and description fields' });
105
+ } else if (fm.error) {
106
+ issues.push({ severity: 'error', message: `YAML frontmatter error: ${fm.error}`, hint: 'Fix frontmatter syntax' });
107
+ } else {
108
+ if (!fm.data.name) {
109
+ issues.push({ severity: 'error', message: 'Missing name in frontmatter', hint: 'Add name: your-skill-name to frontmatter' });
110
+ }
111
+ if (!fm.data.description) {
112
+ issues.push({ severity: 'error', message: 'Missing description in frontmatter', hint: 'Add a description so the agent knows when to use this skill' });
113
+ }
114
+ if (fm.data.description && fm.data.description.length < 20) {
115
+ issues.push({ severity: 'warning', message: 'Description is very short', hint: 'A longer description helps agents understand when to invoke this skill' });
116
+ }
117
+ }
118
+
119
+ // Check body content
120
+ const body = fm.found ? content.replace(/^---\n[\s\S]*?\n---\n?/, '') : content;
121
+
122
+ if (body.trim().length === 0) {
123
+ issues.push({ severity: 'error', message: 'Skill file has no body content', hint: 'Add instructions for the agent after the frontmatter' });
124
+ } else if (body.trim().length < 50) {
125
+ issues.push({ severity: 'warning', message: 'Skill body is very short (< 50 chars)', hint: 'Skills with more detail produce better agent behavior' });
126
+ }
127
+
128
+ // Check for headings (structure)
129
+ const headings = body.match(/^#{1,3}\s+.+/gm);
130
+ if (body.trim().length > 500 && (!headings || headings.length === 0)) {
131
+ issues.push({ severity: 'warning', message: 'Long skill with no headings', hint: 'Add ## sections to organize instructions for better agent comprehension' });
132
+ }
133
+
134
+ // Vague rules (same as .mdc)
135
+ const contentLower = content.toLowerCase();
136
+ for (const pattern of VAGUE_PATTERNS) {
137
+ const idx = contentLower.indexOf(pattern);
138
+ if (idx !== -1) {
139
+ const lineNum = content.slice(0, idx).split('\n').length;
140
+ issues.push({ severity: 'warning', message: `Vague instruction: "${pattern}"`, line: lineNum });
141
+ }
142
+ }
143
+
144
+ return { file: filePath, issues };
145
+ }
146
+
147
+ function findSkillDirs(dir) {
148
+ const skillDirs = [];
149
+ // .claude/skills/ (Claude Code)
150
+ const claudeSkills = path.join(dir, '.claude', 'skills');
151
+ if (fs.existsSync(claudeSkills)) skillDirs.push(claudeSkills);
152
+ // .cursor/skills/ (Cursor agent skills - future)
153
+ const cursorSkills = path.join(dir, '.cursor', 'skills');
154
+ if (fs.existsSync(cursorSkills)) skillDirs.push(cursorSkills);
155
+ // skills/ at project root (skills.sh convention)
156
+ const rootSkills = path.join(dir, 'skills');
157
+ if (fs.existsSync(rootSkills) && fs.statSync(rootSkills).isDirectory()) {
158
+ // Only if it looks like agent skills (has SKILL.md files in subdirs)
159
+ try {
160
+ const entries = fs.readdirSync(rootSkills);
161
+ const hasSkillMd = entries.some(e => {
162
+ const sub = path.join(rootSkills, e);
163
+ return fs.statSync(sub).isDirectory() && fs.existsSync(path.join(sub, 'SKILL.md'));
164
+ });
165
+ if (hasSkillMd) skillDirs.push(rootSkills);
166
+ } catch {}
167
+ }
168
+ return skillDirs;
169
+ }
170
+
171
+ function collectSkillFiles(skillDirs) {
172
+ const files = [];
173
+ for (const dir of skillDirs) {
174
+ try {
175
+ for (const entry of fs.readdirSync(dir)) {
176
+ const sub = path.join(dir, entry);
177
+ if (fs.statSync(sub).isDirectory()) {
178
+ const skillMd = path.join(sub, 'SKILL.md');
179
+ if (fs.existsSync(skillMd)) files.push(skillMd);
180
+ }
181
+ // Also handle flat SKILL.md files
182
+ if (entry === 'SKILL.md') files.push(path.join(dir, entry));
183
+ }
184
+ } catch {}
185
+ }
186
+ return files;
187
+ }
188
+
97
189
  async function lintCursorrules(filePath) {
98
190
  const content = fs.readFileSync(filePath, 'utf-8');
99
191
  const issues = [];
@@ -134,10 +226,17 @@ async function lintProject(dir) {
134
226
  }
135
227
  }
136
228
 
229
+ // Skill files (.claude/skills/, skills/, etc.)
230
+ const skillDirs = findSkillDirs(dir);
231
+ const skillFiles = collectSkillFiles(skillDirs);
232
+ for (const sf of skillFiles) {
233
+ results.push(await lintSkillFile(sf));
234
+ }
235
+
137
236
  if (results.length === 0) {
138
237
  results.push({
139
238
  file: dir,
140
- issues: [{ severity: 'warning', message: 'No Cursor rules found in this directory' }],
239
+ issues: [{ severity: 'warning', message: 'No Cursor rules or agent skills found in this directory' }],
141
240
  });
142
241
  }
143
242