mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-04-28 06:59:37 +00:00
docs(optimize): remove references to non-existent .claudeignore
Claude Code does not document or implement a .claudeignore feature. The junk-reads detector's fix is now a CLAUDE.md instruction asking Claude to avoid generated/dependency directories. The separate detectMissingClaudeignore finding and its tests are removed; checking for the presence of a non-existent file has no signal. Closes #61.
This commit is contained in:
parent
f2d1753d3a
commit
bd71377fdd
3 changed files with 10 additions and 106 deletions
|
|
@ -32,7 +32,6 @@ const TOKENS_PER_SKILL_DEF = 80
|
|||
const TOKENS_PER_COMMAND_DEF = 60
|
||||
const CLAUDEMD_TOKENS_PER_LINE = 13
|
||||
const BASH_TOKENS_PER_CHAR = 0.25
|
||||
const ESTIMATED_READS_PER_MISSING_IGNORE = 10
|
||||
|
||||
// ============================================================================
|
||||
// Detector thresholds
|
||||
|
|
@ -52,7 +51,6 @@ const LOW_RATIO_HIGH_THRESHOLD = 2
|
|||
const LOW_RATIO_MEDIUM_THRESHOLD = 3
|
||||
const MIN_API_CALLS_FOR_CACHE = 10
|
||||
const CACHE_EXCESS_HIGH_THRESHOLD = 15000
|
||||
const MISSING_IGNORE_HIGH_THRESHOLD = 3
|
||||
const UNUSED_MCP_HIGH_THRESHOLD = 3
|
||||
const GHOST_AGENTS_HIGH_THRESHOLD = 5
|
||||
const GHOST_AGENTS_MEDIUM_THRESHOLD = 2
|
||||
|
|
@ -97,8 +95,6 @@ const JUNK_PATTERN = new RegExp(`/(?:${JUNK_DIRS.join('|')})/`)
|
|||
const SHELL_PROFILES = ['.zshrc', '.bashrc', '.bash_profile', '.profile']
|
||||
|
||||
const TOP_ITEMS_PREVIEW = 3
|
||||
const MISSING_IGNORE_PATHS_PREVIEW = 2
|
||||
const JUNK_DIRS_IGNORE_PREVIEW = 8
|
||||
const GHOST_NAMES_PREVIEW = 5
|
||||
const GHOST_CLEANUP_COMMANDS_LIMIT = 10
|
||||
|
||||
|
|
@ -408,18 +404,17 @@ export function detectJunkReads(calls: ToolCall[], dateRange?: DateRange): Waste
|
|||
const detected = sorted.map(([d]) => d)
|
||||
const commonDefaults = ['node_modules', '.git', 'dist', '__pycache__']
|
||||
const extras = commonDefaults.filter(d => !dirCounts.has(d)).slice(0, Math.max(0, 6 - detected.length))
|
||||
const ignoreContent = [...detected, ...extras].join('\n')
|
||||
const dirsToAvoid = [...detected, ...extras].join(', ')
|
||||
|
||||
return {
|
||||
title: 'Claude is reading build/dependency folders',
|
||||
explanation: `Claude read into ${dirList} (${totalJunkReads} reads). These are generated or dependency directories, not your code. A .claudeignore tells Claude to skip them.`,
|
||||
explanation: `Claude read into ${dirList} (${totalJunkReads} reads). These are generated or dependency directories, not your code. Tell Claude in CLAUDE.md to avoid them.`,
|
||||
impact: totalJunkReads > JUNK_READS_HIGH_THRESHOLD ? 'high' : totalJunkReads > JUNK_READS_MEDIUM_THRESHOLD ? 'medium' : 'low',
|
||||
tokensSaved,
|
||||
fix: {
|
||||
type: 'file-content',
|
||||
label: 'Create .claudeignore in your project root:',
|
||||
path: '.claudeignore',
|
||||
content: ignoreContent,
|
||||
type: 'paste',
|
||||
label: 'Append to your project CLAUDE.md:',
|
||||
text: `Do not read or search files under these directories unless I explicitly ask: ${dirsToAvoid}.`,
|
||||
},
|
||||
trend,
|
||||
}
|
||||
|
|
@ -531,43 +526,6 @@ export function detectUnusedMcp(
|
|||
}
|
||||
}
|
||||
|
||||
export function detectMissingClaudeignore(projectCwds: Set<string>): WasteFinding | null {
|
||||
const missing: string[] = []
|
||||
|
||||
for (const cwd of projectCwds) {
|
||||
if (!existsSync(cwd)) continue
|
||||
if (existsSync(join(cwd, '.claudeignore'))) continue
|
||||
for (const dir of JUNK_DIRS) {
|
||||
if (existsSync(join(cwd, dir))) {
|
||||
missing.push(cwd)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (missing.length === 0) return null
|
||||
|
||||
const shortPaths = missing.map(shortHomePath)
|
||||
const display = shortPaths.length <= MISSING_IGNORE_PATHS_PREVIEW + 1
|
||||
? shortPaths.join(', ')
|
||||
: `${shortPaths.slice(0, MISSING_IGNORE_PATHS_PREVIEW).join(', ')} + ${shortPaths.length - MISSING_IGNORE_PATHS_PREVIEW} more`
|
||||
|
||||
const tokensSaved = missing.length * ESTIMATED_READS_PER_MISSING_IGNORE * AVG_TOKENS_PER_READ
|
||||
|
||||
return {
|
||||
title: `Add .claudeignore to ${missing.length} project${missing.length > 1 ? 's' : ''}`,
|
||||
explanation: `${missing.length} project${missing.length > 1 ? 's have' : ' has'} build/dependency folders (node_modules, .git, etc.) but no .claudeignore: ${display}. Without it, Claude can wander into them.`,
|
||||
impact: missing.length >= MISSING_IGNORE_HIGH_THRESHOLD ? 'high' : 'medium',
|
||||
tokensSaved,
|
||||
fix: {
|
||||
type: 'file-content',
|
||||
label: 'Create .claudeignore in each project root:',
|
||||
path: '.claudeignore',
|
||||
content: JUNK_DIRS.slice(0, JUNK_DIRS_IGNORE_PREVIEW).join('\n'),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function expandImports(filePath: string, seen: Set<string>, depth: number): { totalLines: number; importedFiles: number } {
|
||||
if (depth > MAX_IMPORT_DEPTH || seen.has(filePath)) return { totalLines: 0, importedFiles: 0 }
|
||||
seen.add(filePath)
|
||||
|
|
@ -1018,7 +976,6 @@ export async function scanAndDetect(
|
|||
() => detectJunkReads(toolCalls, dateRange),
|
||||
() => detectDuplicateReads(toolCalls, dateRange),
|
||||
() => detectUnusedMcp(toolCalls, projects, projectCwds),
|
||||
() => detectMissingClaudeignore(projectCwds),
|
||||
() => detectBloatedClaudeMd(projectCwds),
|
||||
() => detectBashBloat(),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ vi.mock('os', async () => {
|
|||
const FAKE_HOME_FOR_MOCK = process.env['CODEBURN_TEST_FAKE_HOME']!
|
||||
|
||||
import {
|
||||
detectMissingClaudeignore,
|
||||
detectBloatedClaudeMd,
|
||||
detectUnusedMcp,
|
||||
detectBashBloat,
|
||||
|
|
@ -60,48 +59,6 @@ afterAll(() => {
|
|||
}
|
||||
})
|
||||
|
||||
// ============================================================================
|
||||
// detectMissingClaudeignore
|
||||
// ============================================================================
|
||||
|
||||
describe('detectMissingClaudeignore', () => {
|
||||
it('flags a project with node_modules but no .claudeignore', () => {
|
||||
const root = makeFixtureRoot()
|
||||
const projectDir = join(root, 'myapp')
|
||||
mkdirSync(join(projectDir, 'node_modules'), { recursive: true })
|
||||
const finding = detectMissingClaudeignore(new Set([projectDir]))
|
||||
expect(finding).not.toBeNull()
|
||||
expect(finding!.impact).toBe('medium')
|
||||
})
|
||||
|
||||
it('does not flag when .claudeignore exists', () => {
|
||||
const root = makeFixtureRoot()
|
||||
const projectDir = join(root, 'myapp')
|
||||
mkdirSync(join(projectDir, 'node_modules'), { recursive: true })
|
||||
writeFile(join(projectDir, '.claudeignore'), 'node_modules\n')
|
||||
expect(detectMissingClaudeignore(new Set([projectDir]))).toBeNull()
|
||||
})
|
||||
|
||||
it('does not flag project without junk dirs', () => {
|
||||
const root = makeFixtureRoot()
|
||||
const projectDir = join(root, 'myapp')
|
||||
mkdirSync(join(projectDir, 'src'), { recursive: true })
|
||||
expect(detectMissingClaudeignore(new Set([projectDir]))).toBeNull()
|
||||
})
|
||||
|
||||
it('escalates to high when three or more projects need it', () => {
|
||||
const root = makeFixtureRoot()
|
||||
const cwds = new Set<string>()
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const p = join(root, `proj-${i}`)
|
||||
mkdirSync(join(p, 'node_modules'), { recursive: true })
|
||||
cwds.add(p)
|
||||
}
|
||||
const finding = detectMissingClaudeignore(cwds)
|
||||
expect(finding!.impact).toBe('high')
|
||||
})
|
||||
})
|
||||
|
||||
// ============================================================================
|
||||
// detectBloatedClaudeMd (including @-import expansion)
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import {
|
|||
detectLowReadEditRatio,
|
||||
detectCacheBloat,
|
||||
detectBloatedClaudeMd,
|
||||
detectMissingClaudeignore,
|
||||
computeHealth,
|
||||
computeTrend,
|
||||
type ToolCall,
|
||||
|
|
@ -77,13 +76,14 @@ describe('detectJunkReads', () => {
|
|||
expect(detectJunkReads(calls)).toBeNull()
|
||||
})
|
||||
|
||||
it('builds .claudeignore content from detected + common extras', () => {
|
||||
it('suggests CLAUDE.md advice listing detected and common junk dirs', () => {
|
||||
const calls = Array.from({ length: 5 }, () => call('Read', { file_path: '/x/node_modules/a.js' }))
|
||||
const finding = detectJunkReads(calls)!
|
||||
expect(finding.fix.type).toBe('file-content')
|
||||
if (finding.fix.type === 'file-content') {
|
||||
expect(finding.fix.content).toContain('node_modules')
|
||||
expect(finding.fix.type).toBe('paste')
|
||||
if (finding.fix.type === 'paste') {
|
||||
expect(finding.fix.text).toContain('node_modules')
|
||||
}
|
||||
expect(finding.fix.label).toContain('CLAUDE.md')
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -207,16 +207,6 @@ describe('detectBloatedClaudeMd', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('detectMissingClaudeignore', () => {
|
||||
it('returns null for empty set', () => {
|
||||
expect(detectMissingClaudeignore(new Set())).toBeNull()
|
||||
})
|
||||
|
||||
it('returns null for non-existent cwds', () => {
|
||||
expect(detectMissingClaudeignore(new Set(['/does/not/exist']))).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('computeHealth', () => {
|
||||
it('returns A with 100 for no findings', () => {
|
||||
const { score, grade } = computeHealth([])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue