const UNSAFE_SEGMENT = /^(\.{1,2}|\.git|git~\d+|gitmod~\d+)$|[. ]$|[\\\x00-\x1f\x7f]/i;
/** Rejects names git or common filesystems treat specially (CVE-2014-9390 style `.GIT`, `git~1`, trailing dots). */
export function isUnsafeSegment(segment: string): boolean {
const visible = segment.replace(/[\u200c-\u200f\u202a-\u202e\u206a-\u206f\ufeff]/g, "");
const odd = visible.toLowerCase() === ".gitmodules" && segment !== ".gitmodules";
return odd || UNSAFE_SEGMENT.test(segment) || UNSAFE_SEGMENT.test(visible);
}
const MAX_TREE_PATH = 4096;
/** The GIT-7 path rules as a predicate, for callers that validate before a commit (the editor room). */
export function isSafeTreePath(path: string): boolean {
if (path.length === 0 || path.length > MAX_TREE_PATH || path.startsWith("/") || path.endsWith("/")) return false;
const segments = path.split("/");
return segments.length > 0 && segments.every((segment) => segment !== "" && !isUnsafeSegment(segment));
}