a0dd516cd5
Systematic cleanup of every error handling anti-pattern detected by the automated scanner. 289 issues fixed via code changes, 12 approved with specific technical justifications. Changes across 90 files: - GENERIC_CATCH (141): Added instanceof Error type discrimination - LARGE_TRY_BLOCK (82): Extracted helper methods to narrow try scope to ≤10 lines - NO_LOGGING_IN_CATCH (65): Added logger/console calls for error visibility - CATCH_AND_CONTINUE_CRITICAL_PATH (10): Added throw/return or approved overrides - ERROR_STRING_MATCHING (2): Approved with rationale (no typed error classes) - ERROR_MESSAGE_GUESSING (1): Replaced chained .includes() with documented pattern array - PROMISE_CATCH_NO_LOGGING (1): Added logging to .catch() handler Also fixes a detector bug where nested try/catch inside a catch block corrupted brace-depth tracking, causing false positives. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
89 lines
2.5 KiB
TypeScript
89 lines
2.5 KiB
TypeScript
/**
|
|
* Worktree Detection Utility
|
|
*
|
|
* Detects if the current working directory is a git worktree and extracts
|
|
* information about the parent repository.
|
|
*
|
|
* Git worktrees have a `.git` file (not directory) containing:
|
|
* gitdir: /path/to/parent/.git/worktrees/<name>
|
|
*/
|
|
|
|
import { statSync, readFileSync } from 'fs';
|
|
import path from 'path';
|
|
|
|
export interface WorktreeInfo {
|
|
isWorktree: boolean;
|
|
worktreeName: string | null; // e.g., "yokohama"
|
|
parentRepoPath: string | null; // e.g., "/Users/alex/main"
|
|
parentProjectName: string | null; // e.g., "main"
|
|
}
|
|
|
|
const NOT_A_WORKTREE: WorktreeInfo = {
|
|
isWorktree: false,
|
|
worktreeName: null,
|
|
parentRepoPath: null,
|
|
parentProjectName: null
|
|
};
|
|
|
|
/**
|
|
* Detect if a directory is a git worktree and extract parent info.
|
|
*
|
|
* @param cwd - Current working directory (absolute path)
|
|
* @returns WorktreeInfo with parent details if worktree, otherwise isWorktree=false
|
|
*/
|
|
export function detectWorktree(cwd: string): WorktreeInfo {
|
|
const gitPath = path.join(cwd, '.git');
|
|
|
|
// Check if .git is a file (worktree) or directory (main repo)
|
|
let stat;
|
|
try {
|
|
stat = statSync(gitPath);
|
|
} catch (error: unknown) {
|
|
// No .git at all - not a git repo (ENOENT is expected, other errors are noteworthy)
|
|
if (error instanceof Error && (error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
|
console.warn(`[worktree] Unexpected error checking .git:`, error);
|
|
}
|
|
return NOT_A_WORKTREE;
|
|
}
|
|
|
|
if (!stat.isFile()) {
|
|
// .git is a directory = main repo, not a worktree
|
|
return NOT_A_WORKTREE;
|
|
}
|
|
|
|
// Parse .git file to find parent repo
|
|
let content: string;
|
|
try {
|
|
content = readFileSync(gitPath, 'utf-8').trim();
|
|
} catch (error: unknown) {
|
|
console.warn(`[worktree] Failed to read .git file:`, error instanceof Error ? error.message : String(error));
|
|
return NOT_A_WORKTREE;
|
|
}
|
|
|
|
// Format: gitdir: /path/to/parent/.git/worktrees/<name>
|
|
const match = content.match(/^gitdir:\s*(.+)$/);
|
|
if (!match) {
|
|
return NOT_A_WORKTREE;
|
|
}
|
|
|
|
const gitdirPath = match[1];
|
|
|
|
// Extract: /path/to/parent from /path/to/parent/.git/worktrees/name
|
|
// Handle both Unix and Windows paths
|
|
const worktreesMatch = gitdirPath.match(/^(.+)[/\\]\.git[/\\]worktrees[/\\]([^/\\]+)$/);
|
|
if (!worktreesMatch) {
|
|
return NOT_A_WORKTREE;
|
|
}
|
|
|
|
const parentRepoPath = worktreesMatch[1];
|
|
const worktreeName = path.basename(cwd);
|
|
const parentProjectName = path.basename(parentRepoPath);
|
|
|
|
return {
|
|
isWorktree: true,
|
|
worktreeName,
|
|
parentRepoPath,
|
|
parentProjectName
|
|
};
|
|
}
|