Refactor extractProjectName to accept cwdHint for improved project name extraction. Update ErrorTriggerChecker to utilize new parameter, ensuring accurate project name retrieval in various contexts. Enhance tests to cover new functionality and edge cases.

This commit is contained in:
matt 2026-02-11 20:12:25 +09:00
parent 96fab90c37
commit 5a0e4c474f
4 changed files with 26 additions and 5 deletions

View file

@ -185,7 +185,7 @@ export function checkToolResultTrigger(
sessionId,
projectId,
filePath,
projectName: extractProjectName(projectId),
projectName: extractProjectName(projectId, message.cwd),
lineNumber,
source: result.toolName ?? 'tool_result',
message: errorMessage,
@ -220,7 +220,7 @@ export function checkToolResultTrigger(
sessionId,
projectId,
filePath,
projectName: extractProjectName(projectId),
projectName: extractProjectName(projectId, message.cwd),
lineNumber,
source: trigger.toolName,
message: `Tool result matched: ${content.slice(0, 200)}`,
@ -296,7 +296,7 @@ export function checkToolUseTrigger(
sessionId,
projectId,
filePath,
projectName: extractProjectName(projectId),
projectName: extractProjectName(projectId, message.cwd),
lineNumber,
source: toolUse.name,
message: `${trigger.matchField ?? 'tool_use'}: ${fieldValue.slice(0, 200)}`,
@ -443,7 +443,7 @@ export function checkTokenThresholdTrigger(
sessionId,
projectId,
filePath,
projectName: extractProjectName(projectId),
projectName: extractProjectName(projectId, message.cwd),
lineNumber,
source: toolUse.name,
message: tokenMessage,

View file

@ -68,7 +68,14 @@ export function decodePath(encodedName: string): string {
* @param encodedName - The encoded directory name
* @returns The project name
*/
export function extractProjectName(encodedName: string): string {
export function extractProjectName(encodedName: string, cwdHint?: string): string {
// Prefer cwdHint (actual filesystem path) since decodePath is lossy for
// paths containing dashes (e.g., "claude-code-context" → "claude/code/context").
if (cwdHint) {
const segments = cwdHint.split(/[/\\]/).filter(Boolean);
const last = segments[segments.length - 1];
if (last) return last;
}
const decoded = decodePath(encodedName);
const segments = decoded.split('/').filter(Boolean);
return segments[segments.length - 1] || encodedName;

View file

@ -74,6 +74,7 @@ export const NotificationRow = ({
style={{
borderColor: 'var(--color-border)',
backgroundColor: isHovered ? 'var(--color-surface-raised)' : undefined,
opacity: isUnread ? 1 : 0.5,
}}
>
{/* Color Dot — always visible, opacity indicates read state */}

View file

@ -96,6 +96,19 @@ describe('pathDecoder', () => {
it('should handle path with underscore in project name', () => {
expect(extractProjectName('-Users-username-my_cool_projectname')).toBe('my_cool_projectname');
});
it('should prefer cwdHint over lossy decode for dashed project names', () => {
// Without cwdHint, dashes are decoded as slashes (lossy)
expect(extractProjectName('-Users-name-claude-code-context')).toBe('context');
// With cwdHint, the actual project name is preserved
expect(
extractProjectName('-Users-name-claude-code-context', '/Users/name/claude-code-context')
).toBe('claude-code-context');
});
it('should fall back to decoded name when cwdHint is undefined', () => {
expect(extractProjectName('-Users-username-projectname', undefined)).toBe('projectname');
});
});
describe('isValidEncodedPath', () => {