@nerviq/cli 0.9.0-beta.2 → 0.9.2
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 +103 -406
- package/package.json +1 -1
- package/src/codex/setup.js +2 -14
- package/src/codex/techniques.js +630 -25
- package/src/techniques.js +127 -35
package/src/techniques.js
CHANGED
|
@@ -55,15 +55,16 @@ const TECHNIQUES = {
|
|
|
55
55
|
|
|
56
56
|
importSyntax: {
|
|
57
57
|
id: 763,
|
|
58
|
-
name: 'CLAUDE.md uses @
|
|
58
|
+
name: 'CLAUDE.md uses @path imports for modularity',
|
|
59
59
|
check: (ctx) => {
|
|
60
60
|
const md = ctx.claudeMdContent() || '';
|
|
61
|
-
|
|
61
|
+
// Current syntax is @path/to/file (no "import" keyword)
|
|
62
|
+
return /@\S+\.(md|txt|json|yml|yaml|toml)/i.test(md) || /@\w+\//.test(md);
|
|
62
63
|
},
|
|
63
64
|
impact: 'medium',
|
|
64
65
|
rating: 4,
|
|
65
66
|
category: 'memory',
|
|
66
|
-
fix: 'Use @
|
|
67
|
+
fix: 'Use @path syntax in CLAUDE.md to split instructions into focused modules (e.g. @docs/coding-style.md). You can also use .claude/rules/ for path-specific rules.',
|
|
67
68
|
template: null
|
|
68
69
|
},
|
|
69
70
|
|
|
@@ -271,22 +272,35 @@ const TECHNIQUES = {
|
|
|
271
272
|
skills: {
|
|
272
273
|
id: 21,
|
|
273
274
|
name: 'Custom skills',
|
|
274
|
-
check: (ctx) =>
|
|
275
|
+
check: (ctx) => {
|
|
276
|
+
// Skills use directory-per-skill structure: .claude/skills/<name>/SKILL.md
|
|
277
|
+
if (!ctx.hasDir('.claude/skills')) return false;
|
|
278
|
+
const dirs = ctx.dirFiles('.claude/skills');
|
|
279
|
+
// Check for SKILL.md inside skill directories
|
|
280
|
+
for (const d of dirs) {
|
|
281
|
+
if (ctx.fileContent(`.claude/skills/${d}/SKILL.md`)) return true;
|
|
282
|
+
}
|
|
283
|
+
// Fallback: any files in skills dir (legacy .claude/commands/ also works)
|
|
284
|
+
return dirs.length > 0;
|
|
285
|
+
},
|
|
275
286
|
impact: 'medium',
|
|
276
287
|
rating: 4,
|
|
277
288
|
category: 'workflow',
|
|
278
|
-
fix: '
|
|
289
|
+
fix: 'Create skills at .claude/skills/<name>/SKILL.md with YAML frontmatter (name, description). Each skill is a directory with a SKILL.md file.',
|
|
279
290
|
template: 'skills'
|
|
280
291
|
},
|
|
281
292
|
|
|
282
293
|
multipleSkills: {
|
|
283
294
|
id: 2101,
|
|
284
295
|
name: '2+ skills for specialization',
|
|
285
|
-
check: (ctx) =>
|
|
296
|
+
check: (ctx) => {
|
|
297
|
+
if (!ctx.hasDir('.claude/skills')) return false;
|
|
298
|
+
return ctx.dirFiles('.claude/skills').length >= 2;
|
|
299
|
+
},
|
|
286
300
|
impact: 'medium',
|
|
287
301
|
rating: 4,
|
|
288
302
|
category: 'workflow',
|
|
289
|
-
fix: 'Add at least 2 skills
|
|
303
|
+
fix: 'Add at least 2 skills covering different workflows (e.g. code-review, test-writer).',
|
|
290
304
|
template: 'skills'
|
|
291
305
|
},
|
|
292
306
|
|
|
@@ -418,7 +432,7 @@ const TECHNIQUES = {
|
|
|
418
432
|
id: 19,
|
|
419
433
|
name: 'Hooks for automation',
|
|
420
434
|
check: (ctx) => {
|
|
421
|
-
|
|
435
|
+
// Hooks are configured in settings.json (not .claude/hooks/ directory)
|
|
422
436
|
const shared = ctx.jsonFile('.claude/settings.json') || {};
|
|
423
437
|
const local = ctx.jsonFile('.claude/settings.local.json') || {};
|
|
424
438
|
return !!(shared.hooks && Object.keys(shared.hooks).length > 0) || !!(local.hooks && Object.keys(local.hooks).length > 0);
|
|
@@ -426,7 +440,7 @@ const TECHNIQUES = {
|
|
|
426
440
|
impact: 'high',
|
|
427
441
|
rating: 4,
|
|
428
442
|
category: 'automation',
|
|
429
|
-
fix: 'Add hooks
|
|
443
|
+
fix: 'Add hooks in .claude/settings.json under the "hooks" key. Supported events: PreToolUse, PostToolUse, Notification, Stop, StopFailure, SubagentStop, and more.',
|
|
430
444
|
template: 'hooks'
|
|
431
445
|
},
|
|
432
446
|
|
|
@@ -696,13 +710,17 @@ const TECHNIQUES = {
|
|
|
696
710
|
id: 18,
|
|
697
711
|
name: 'MCP servers configured',
|
|
698
712
|
check: (ctx) => {
|
|
713
|
+
// MCP now lives in .mcp.json (project) and ~/.claude.json (user), NOT settings.json
|
|
714
|
+
const mcpJson = ctx.jsonFile('.mcp.json');
|
|
715
|
+
if (mcpJson && mcpJson.mcpServers && Object.keys(mcpJson.mcpServers).length > 0) return true;
|
|
716
|
+
// Fallback: check settings for legacy format
|
|
699
717
|
const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
|
|
700
718
|
return !!(settings && settings.mcpServers && Object.keys(settings.mcpServers).length > 0);
|
|
701
719
|
},
|
|
702
720
|
impact: 'medium',
|
|
703
721
|
rating: 3,
|
|
704
722
|
category: 'tools',
|
|
705
|
-
fix: 'Configure MCP servers
|
|
723
|
+
fix: 'Configure MCP servers in .mcp.json at project root. Use `claude mcp add` to add servers. Project-level MCP is committed to git for team sharing.',
|
|
706
724
|
template: null
|
|
707
725
|
},
|
|
708
726
|
|
|
@@ -711,10 +729,10 @@ const TECHNIQUES = {
|
|
|
711
729
|
name: '2+ MCP servers for rich tooling',
|
|
712
730
|
check: (ctx) => {
|
|
713
731
|
let count = 0;
|
|
714
|
-
const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
|
|
715
|
-
if (settings && settings.mcpServers) count += Object.keys(settings.mcpServers).length;
|
|
716
732
|
const mcpJson = ctx.jsonFile('.mcp.json');
|
|
717
733
|
if (mcpJson && mcpJson.mcpServers) count += Object.keys(mcpJson.mcpServers).length;
|
|
734
|
+
const settings = ctx.jsonFile('.claude/settings.local.json') || ctx.jsonFile('.claude/settings.json');
|
|
735
|
+
if (settings && settings.mcpServers) count += Object.keys(settings.mcpServers).length;
|
|
718
736
|
return count >= 2;
|
|
719
737
|
},
|
|
720
738
|
impact: 'medium',
|
|
@@ -853,17 +871,17 @@ const TECHNIQUES = {
|
|
|
853
871
|
|
|
854
872
|
// claudeMdNotOverlong removed — duplicate of underlines200 (id 681)
|
|
855
873
|
|
|
856
|
-
|
|
874
|
+
claudeLocalMd: {
|
|
857
875
|
id: 2002,
|
|
858
|
-
name: 'CLAUDE.md
|
|
876
|
+
name: 'CLAUDE.local.md for personal overrides',
|
|
859
877
|
check: (ctx) => {
|
|
860
|
-
//
|
|
861
|
-
return
|
|
878
|
+
// CLAUDE.local.md is for personal, non-committed overrides
|
|
879
|
+
return ctx.files.includes('CLAUDE.local.md') || ctx.files.includes('.claude/CLAUDE.local.md');
|
|
862
880
|
},
|
|
863
|
-
impact: '
|
|
864
|
-
rating:
|
|
865
|
-
category: '
|
|
866
|
-
fix: 'CLAUDE.md
|
|
881
|
+
impact: 'low',
|
|
882
|
+
rating: 2,
|
|
883
|
+
category: 'memory',
|
|
884
|
+
fix: 'Create CLAUDE.local.md for personal preferences that should not be committed (add to .gitignore).',
|
|
867
885
|
template: null
|
|
868
886
|
},
|
|
869
887
|
|
|
@@ -935,21 +953,22 @@ const TECHNIQUES = {
|
|
|
935
953
|
|
|
936
954
|
agentsHaveMaxTurns: {
|
|
937
955
|
id: 2007,
|
|
938
|
-
name: '
|
|
956
|
+
name: 'Subagents have max-turns limit',
|
|
939
957
|
check: (ctx) => {
|
|
940
958
|
if (!ctx.hasDir('.claude/agents')) return null;
|
|
941
959
|
const files = ctx.dirFiles('.claude/agents');
|
|
942
960
|
if (files.length === 0) return null;
|
|
943
961
|
for (const f of files) {
|
|
944
962
|
const content = ctx.fileContent(`.claude/agents/${f}`) || '';
|
|
945
|
-
|
|
963
|
+
// Current frontmatter uses kebab-case: max-turns (also accept legacy maxTurns)
|
|
964
|
+
if (!content.includes('max-turns') && !content.includes('maxTurns')) return false;
|
|
946
965
|
}
|
|
947
966
|
return true;
|
|
948
967
|
},
|
|
949
968
|
impact: 'medium',
|
|
950
969
|
rating: 3,
|
|
951
970
|
category: 'quality-deep',
|
|
952
|
-
fix: '
|
|
971
|
+
fix: 'Subagents without max-turns can run indefinitely. Add "max-turns: 50" to subagent YAML frontmatter.',
|
|
953
972
|
template: null
|
|
954
973
|
},
|
|
955
974
|
|
|
@@ -986,19 +1005,20 @@ const TECHNIQUES = {
|
|
|
986
1005
|
// --- New checks: agent depth ---
|
|
987
1006
|
agentHasAllowedTools: {
|
|
988
1007
|
id: 2011,
|
|
989
|
-
name: 'At least one
|
|
1008
|
+
name: 'At least one subagent restricts tools',
|
|
990
1009
|
check: (ctx) => {
|
|
991
1010
|
if (!ctx.hasDir('.claude/agents')) return null;
|
|
992
1011
|
const files = ctx.dirFiles('.claude/agents');
|
|
993
1012
|
if (files.length === 0) return null;
|
|
994
1013
|
for (const f of files) {
|
|
995
1014
|
const content = ctx.fileContent(`.claude/agents/${f}`) || '';
|
|
996
|
-
|
|
1015
|
+
// Current frontmatter uses allowed-tools (also accept legacy tools:)
|
|
1016
|
+
if (/allowed-tools:/i.test(content) || /tools:\s*\[/.test(content)) return true;
|
|
997
1017
|
}
|
|
998
1018
|
return false;
|
|
999
1019
|
},
|
|
1000
1020
|
impact: 'medium', rating: 3, category: 'workflow',
|
|
1001
|
-
fix: 'Add
|
|
1021
|
+
fix: 'Add allowed-tools to subagent frontmatter (e.g. allowed-tools: Read Grep Bash) for safer delegation.',
|
|
1002
1022
|
template: null
|
|
1003
1023
|
},
|
|
1004
1024
|
|
|
@@ -1179,14 +1199,15 @@ const TECHNIQUES = {
|
|
|
1179
1199
|
|
|
1180
1200
|
stopFailureHook: {
|
|
1181
1201
|
id: 2025,
|
|
1182
|
-
name: 'StopFailure
|
|
1202
|
+
name: 'StopFailure hook for error tracking',
|
|
1183
1203
|
check: (ctx) => {
|
|
1184
1204
|
const shared = ctx.jsonFile('.claude/settings.json') || {};
|
|
1185
1205
|
const local = ctx.jsonFile('.claude/settings.local.json') || {};
|
|
1186
|
-
|
|
1206
|
+
// StopFailure = error stop (API errors), Stop = normal completion — both useful but different
|
|
1207
|
+
return !!(shared.hooks?.StopFailure || local.hooks?.StopFailure);
|
|
1187
1208
|
},
|
|
1188
1209
|
impact: 'low', rating: 3, category: 'automation',
|
|
1189
|
-
fix: 'Add a StopFailure hook to log errors
|
|
1210
|
+
fix: 'Add a StopFailure hook to log API errors and unexpected stops. Note: StopFailure (errors) is different from Stop (normal completion).',
|
|
1190
1211
|
template: null
|
|
1191
1212
|
},
|
|
1192
1213
|
|
|
@@ -1282,19 +1303,19 @@ const TECHNIQUES = {
|
|
|
1282
1303
|
name: 'No deprecated patterns detected',
|
|
1283
1304
|
check: (ctx) => {
|
|
1284
1305
|
const md = ctx.claudeMdContent();
|
|
1285
|
-
if (!md) return false;
|
|
1286
|
-
//
|
|
1306
|
+
if (!md) return false;
|
|
1307
|
+
// Only flag truly deprecated patterns, not valid aliases
|
|
1287
1308
|
const deprecatedPatterns = [
|
|
1288
|
-
/\
|
|
1289
|
-
/\
|
|
1290
|
-
/\
|
|
1309
|
+
/\bhuman_prompt\b/i, /\bassistant_prompt\b/i, // old completions API format (not Messages API)
|
|
1310
|
+
/\buse model claude-3-opus\b/i, // explicit recommendation to use old name as --model
|
|
1311
|
+
/\buse model claude-3-sonnet\b/i,
|
|
1291
1312
|
];
|
|
1292
1313
|
return !deprecatedPatterns.some(p => p.test(md));
|
|
1293
1314
|
},
|
|
1294
1315
|
impact: 'medium',
|
|
1295
1316
|
rating: 3,
|
|
1296
1317
|
category: 'quality-deep',
|
|
1297
|
-
fix: 'CLAUDE.md references deprecated patterns (
|
|
1318
|
+
fix: 'CLAUDE.md references deprecated API patterns (human_prompt/assistant_prompt). Update to current Messages API conventions.',
|
|
1298
1319
|
template: null
|
|
1299
1320
|
},
|
|
1300
1321
|
|
|
@@ -1315,6 +1336,77 @@ const TECHNIQUES = {
|
|
|
1315
1336
|
fix: 'CLAUDE.md exists but lacks substance. Add at least 2 sections (## headings) and include your test/build/lint commands.',
|
|
1316
1337
|
template: null
|
|
1317
1338
|
},
|
|
1339
|
+
|
|
1340
|
+
// ============================================================
|
|
1341
|
+
// === NEW CHECKS: Uncovered features (2026-04-05) ============
|
|
1342
|
+
// ============================================================
|
|
1343
|
+
|
|
1344
|
+
mcpJsonProject: {
|
|
1345
|
+
id: 2032,
|
|
1346
|
+
name: 'Project-level .mcp.json exists',
|
|
1347
|
+
check: (ctx) => ctx.files.includes('.mcp.json'),
|
|
1348
|
+
impact: 'medium',
|
|
1349
|
+
rating: 3,
|
|
1350
|
+
category: 'tools',
|
|
1351
|
+
fix: 'Create .mcp.json at project root for team-shared MCP servers. Use `claude mcp add --project` to add servers.',
|
|
1352
|
+
template: null
|
|
1353
|
+
},
|
|
1354
|
+
|
|
1355
|
+
hooksNotificationEvent: {
|
|
1356
|
+
id: 2033,
|
|
1357
|
+
name: 'Notification hook for alerts',
|
|
1358
|
+
check: (ctx) => {
|
|
1359
|
+
const shared = ctx.jsonFile('.claude/settings.json') || {};
|
|
1360
|
+
const local = ctx.jsonFile('.claude/settings.local.json') || {};
|
|
1361
|
+
return !!(shared.hooks?.Notification || local.hooks?.Notification);
|
|
1362
|
+
},
|
|
1363
|
+
impact: 'low',
|
|
1364
|
+
rating: 2,
|
|
1365
|
+
category: 'automation',
|
|
1366
|
+
fix: 'Add a Notification hook to capture alerts and status updates from Claude during long tasks.',
|
|
1367
|
+
template: null
|
|
1368
|
+
},
|
|
1369
|
+
|
|
1370
|
+
subagentStopHook: {
|
|
1371
|
+
id: 2034,
|
|
1372
|
+
name: 'SubagentStop hook for delegation tracking',
|
|
1373
|
+
check: (ctx) => {
|
|
1374
|
+
const shared = ctx.jsonFile('.claude/settings.json') || {};
|
|
1375
|
+
const local = ctx.jsonFile('.claude/settings.local.json') || {};
|
|
1376
|
+
return !!(shared.hooks?.SubagentStop || local.hooks?.SubagentStop);
|
|
1377
|
+
},
|
|
1378
|
+
impact: 'low',
|
|
1379
|
+
rating: 2,
|
|
1380
|
+
category: 'automation',
|
|
1381
|
+
fix: 'Add a SubagentStop hook to track when delegated subagent tasks complete.',
|
|
1382
|
+
template: null
|
|
1383
|
+
},
|
|
1384
|
+
|
|
1385
|
+
rulesDirectory: {
|
|
1386
|
+
id: 2035,
|
|
1387
|
+
name: 'Path-specific rules in .claude/rules/',
|
|
1388
|
+
check: (ctx) => ctx.hasDir('.claude/rules') && ctx.dirFiles('.claude/rules').length > 0,
|
|
1389
|
+
impact: 'medium',
|
|
1390
|
+
rating: 3,
|
|
1391
|
+
category: 'workflow',
|
|
1392
|
+
fix: 'Create .claude/rules/ with path-specific rules for different parts of your codebase (e.g. frontend.md, backend.md).',
|
|
1393
|
+
template: null
|
|
1394
|
+
},
|
|
1395
|
+
|
|
1396
|
+
gitignoreClaudeLocal: {
|
|
1397
|
+
id: 2036,
|
|
1398
|
+
name: 'CLAUDE.local.md in .gitignore',
|
|
1399
|
+
check: (ctx) => {
|
|
1400
|
+
const gitignore = ctx.fileContent('.gitignore') || '';
|
|
1401
|
+
return /CLAUDE\.local\.md/i.test(gitignore);
|
|
1402
|
+
},
|
|
1403
|
+
impact: 'medium',
|
|
1404
|
+
rating: 3,
|
|
1405
|
+
category: 'git',
|
|
1406
|
+
fix: 'Add CLAUDE.local.md to .gitignore — it contains personal overrides that should not be committed.',
|
|
1407
|
+
template: null
|
|
1408
|
+
},
|
|
1409
|
+
|
|
1318
1410
|
};
|
|
1319
1411
|
|
|
1320
1412
|
// Stack detection
|