Problem Description
When running ccexp from a subdirectory within a project, the project's CLAUDE.md and CLAUDE.local.md files are not discovered and displayed in the UI.
Steps to Reproduce
- Navigate to a project directory that contains
CLAUDE.md and/or CLAUDE.local.md files
- Create a subdirectory:
mkdir test-dir && cd test-dir
- Run ccexp:
../dist/index.js or ccexp (if installed globally)
- Observe that the project's CLAUDE.md files are not shown in the file list
Expected Behavior
Project-level CLAUDE.md and CLAUDE.local.md files should be discovered and displayed regardless of which subdirectory ccexp is executed from within the project.
Actual Behavior
Only user-level files from ~/.claude/ are displayed. The project's memory files are missing.
Root Cause Analysis
Current Implementation (AS-IS)
-
Working Directory Dependency (src/index.tsx:24)
.option('-p, --path <path>', 'specify directory to scan', process.cwd())
-
Limited Scan Scope (src/claude-md-scanner.ts)
- Scans from
process.cwd() downward
- Scans
~/.claude/
- Scans first-level subdirectories in home
- Does NOT scan parent directories
-
Environment-Specific Hardcoding
const projectDirectories = new Set([
'my_programs', // Specific to certain environments
'projects',
'dev',
// ...
]);
Proposed Solution (TO-BE)
Scan from HOME directory with intelligent filtering
export const scanClaudeFiles = async (options: ScanOptions = {}): Promise<ClaudeFileInfo[]> => {
const { homedir } = await import('node:os');
const homeDir = homedir();
const files: string[] = [];
// 1. Scan ~/.claude directory
const globalClaudeDir = join(homeDir, '.claude');
if (existsSync(globalClaudeDir)) {
const globalFiles = await findClaudeFiles({
path: globalClaudeDir,
recursive: true,
});
files.push(...globalFiles);
}
// 2. Scan all directories under HOME with smart filtering
const homeContents = await readdir(homeDir, { withFileTypes: true });
for (const entry of homeContents) {
if (!entry.isDirectory() || shouldExcludeDirectory(entry.name)) continue;
const dirPath = join(homeDir, entry.name);
// Prioritize likely project directories
if (await isLikelyProjectDirectory(dirPath, entry.name)) {
const projectFiles = await findClaudeFiles({
path: dirPath,
recursive: true,
});
files.push(...projectFiles);
}
}
// Remove duplicates and process
const uniqueFiles = uniq(files);
// ... process files
};
Improved Directory Detection
// Remove environment-specific hardcoding
async function isLikelyProjectDirectory(dirPath: string, dirName: string): boolean {
// 1. Pattern-based detection
const namePatterns = [
/^(dev|develop|development)$/i,
/^(proj|project|projects)$/i,
/^(work|workspace|code|src|source)$/i,
/^(repo|repos|repositories)$/i,
/^(git|github|gitlab)$/i,
];
if (namePatterns.some(pattern => pattern.test(dirName))) {
return true;
}
// 2. Marker file detection
const markers = [
'.git', 'package.json', 'Cargo.toml', 'go.mod',
'requirements.txt', '.claude', 'CLAUDE.md'
];
for (const marker of markers) {
if (existsSync(join(dirPath, marker))) {
return true;
}
}
return false;
}
// Comprehensive exclusion patterns
function shouldExcludeDirectory(name: string): boolean {
const excludePatterns = [
// System/Cache
/^\.cache$/, /^\.npm$/, /^\.yarn$/, /^node_modules$/,
// OS-specific
/^Library$/, /^Applications$/, /^\.Trash$/, // macOS
/^AppData$/, /^LocalAppData$/, // Windows
// Large media directories
/^Downloads$/, /^Pictures$/, /^Movies$/, /^Music$/,
// Hidden config
/^\.local$/, /^\.config$/, /^\.vscode$/, /^\.idea$/,
];
return excludePatterns.some(pattern => pattern.test(name));
}
Benefits
- Reliability: Scanning from HOME ensures all CLAUDE.md files are found regardless of execution location
- Performance: Smart filtering and pattern matching reduce unnecessary scans
- Security: Clear exclusion patterns avoid system directories
- Portability: No environment-specific hardcoding
Implementation Notes
- Maintain backward compatibility with existing API
- Add depth limits to prevent excessive scanning
- Consider adding a progress indicator for large file systems
- Cache results for improved performance on repeated runs
This change will significantly improve the user experience by ensuring ccexp behaves consistently regardless of where it's executed.
Problem Description
When running
ccexpfrom a subdirectory within a project, the project'sCLAUDE.mdandCLAUDE.local.mdfiles are not discovered and displayed in the UI.Steps to Reproduce
CLAUDE.mdand/orCLAUDE.local.mdfilesmkdir test-dir && cd test-dir../dist/index.jsorccexp(if installed globally)Expected Behavior
Project-level
CLAUDE.mdandCLAUDE.local.mdfiles should be discovered and displayed regardless of which subdirectory ccexp is executed from within the project.Actual Behavior
Only user-level files from
~/.claude/are displayed. The project's memory files are missing.Root Cause Analysis
Current Implementation (AS-IS)
Working Directory Dependency (
src/index.tsx:24)Limited Scan Scope (
src/claude-md-scanner.ts)process.cwd()downward~/.claude/Environment-Specific Hardcoding
Proposed Solution (TO-BE)
Scan from HOME directory with intelligent filtering
Improved Directory Detection
Benefits
Implementation Notes
This change will significantly improve the user experience by ensuring ccexp behaves consistently regardless of where it's executed.