fix: resolve path format mismatch in folder CLAUDE.md generation (#794) (#813)

The isDirectChild() function failed to match files when the API used
absolute paths (/Users/x/project/app/api) but the database stored
relative paths (app/api/router.py). This caused all folder CLAUDE.md
files to incorrectly show "No recent activity".

Changes:
- Create shared path-utils module with proper path normalization
- Implement suffix matching strategy for mixed path formats
- Update SessionSearch.ts to use shared utilities
- Update regenerate-claude-md.ts to use shared utilities (was using
  outdated broken logic)
- Prevent spurious directory creation from malformed paths
- Add comprehensive test coverage for path matching edge cases

This is the proper fix for #794, replacing PR #809 which only masked
the bug by skipping file creation when "no activity" was shown.

Co-authored-by: bigphoot <bigphoot@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Alexander Knigge
2026-01-26 12:48:31 -08:00
committed by GitHub
parent 0b7ecedcd7
commit 182097ef1c
6 changed files with 257 additions and 57 deletions
+3 -11
View File
@@ -2,6 +2,7 @@ import { Database } from 'bun:sqlite';
import { TableNameRow } from '../../types/database.js';
import { DATA_DIR, DB_PATH, ensureDir } from '../../shared/paths.js';
import { logger } from '../../utils/logger.js';
import { isDirectChild } from '../../shared/path-utils.js';
import {
ObservationSearchResult,
SessionSummarySearchResult,
@@ -336,15 +337,6 @@ export class SessionSearch {
return this.db.prepare(sql).all(...params) as ObservationSearchResult[];
}
/**
* Check if a file is a direct child of a folder (not in a subfolder)
*/
private isDirectChild(filePath: string, folderPath: string): boolean {
if (!filePath.startsWith(folderPath + '/')) return false;
const remainder = filePath.slice(folderPath.length + 1);
return !remainder.includes('/');
}
/**
* Check if an observation has any files that are direct children of the folder
*/
@@ -354,7 +346,7 @@ export class SessionSearch {
try {
const files = JSON.parse(filesJson);
if (Array.isArray(files)) {
return files.some(f => this.isDirectChild(f, folderPath));
return files.some(f => isDirectChild(f, folderPath));
}
} catch {}
return false;
@@ -372,7 +364,7 @@ export class SessionSearch {
try {
const files = JSON.parse(filesJson);
if (Array.isArray(files)) {
return files.some(f => this.isDirectChild(f, folderPath));
return files.some(f => isDirectChild(f, folderPath));
}
} catch {}
return false;