콘텐츠로 이동

경로

ActiveCli.Path.AbstractPath — 파일시스템 위치를, 어떤 구체적인 종류의 경로로서.

abstract class AbstractPath {
toString(): string;
abstract toWslPath(): string;
abstract isSpawnableAsCwd(): boolean;
}

경로는 우리 경계에 맨 문자열로 도착합니다 — 호출자의 옵션에서, 프로젝트 루트를 건네는 IDE에서, CLI의 JSON 출력에서. 문자열은 “너는 Windows 드라이브 경로냐 Linux 경로냐”에 답할 수 없으므로, 그것을 알아야 하는 모든 호출자가 각자 다시 도출하고, 그 도출들은 서로 어긋납니다. 여기서는 클래스가 곧 답입니다.

멤버 설명
toString() 주어진 그대로의 경로. 구분자까지 포함해서.
toWslPath() WSL 배포판 안에서 도는 프로세스가 보게 될 경로로서의 이 위치. 출발지가 아니라 목적지를 기준으로 이름 붙인 것은, 호출자가 고르는 것이 그것이기 때문입니다: “Linux 자식을 위해 자신을 렌더링하라”. 이미 그 세계에 속한 경로는 자기 자신으로 답합니다.
isSpawnableAsCwd() 현재 호스트에서 이 경로를 cwd로 삼아 자식을 spawn하는 것이 안전한지 여부.

ActiveCli.Path.PathParser — 경로 문자열을 그것이 실제로 속한 종류로 바꿉니다. 맨 문자열이 더 이상 여행하도록 허용되지 않는 경계입니다. 경로가 도착하는 순간 이것을 호출하고, 그 뒤로는 인스턴스를 전달하십시오.

class PathParser {
parse(raw: string): AbstractPath;
}
입력 결과 toWslPath()
//wsl.localhost/Ubuntu/home/user/proj WslUncPath /home/user/proj
/home/user/proj PosixPath /home/user/proj
C:\Users\foo WindowsPath /mnt/c/Users/foo
src\core (상대 경로) PosixPath src/core

어떤 종류로도 절대 경로가 아닌 것은 POSIX로 취급되며, 나가는 길에 구분자를 정규화하고 spawn 가능한 상태로 남습니다 — 상대 cwd에 대한 정직한 답입니다.

PathParserAbstractPath의 static이 아니라 별도 클래스인 것은, 베이스가 자신의 하위 클래스를 import하지 않아도 되게 하기 위함입니다.

ActiveCli.Path.PosixPath — Linux/macOS 경로(/home/user/proj), 그리고 다른 종류의 절대 경로가 아닌 모든 것에 대한 폴백.

class PosixPath extends AbstractPath {
constructor(raw: string);
toWslPath(): string; // 구분자 정규화
isSpawnableAsCwd(): boolean; // 언제나 true
}

이미 POSIX 자식에게 네이티브이므로 spawn cwd로 언제나 안전합니다. 상대 경로는 여전히 역슬래시(src\core)를 달고 올 수 있으며, 구분자는 생성 시점이 아니라 toWslPath()에서 변환됩니다 — 그래야 toString()이 우리가 받은 것에 대해 정직하게 남습니다.

ActiveCli.Path.WindowsPath — Windows 드라이브 경로(C:\Users\foo, 또는 구분자가 없는 C:Users\foo).

class WindowsPath extends AbstractPath {
constructor(raw: string);
static matches(raw: string): boolean; // 두 번째 문자가 ':'
toWslPath(): string;
isSpawnableAsCwd(): boolean; // 언제나 true
}

WSL 배포판 안에서 Windows 드라이브는 /mnt/<letter> 아래에 마운트되므로, Linux 자식에게 건네야 하는 것은 그 형태입니다.

parser.parse('D:\\Projects').toWslPath(); // '/mnt/d/Projects'
parser.parse('C:\\').toWslPath(); // '/mnt/c' — '/mnt/c/'가 아님
parser.parse('C:Users\\foo').toWslPath(); // '/mnt/c/Users/foo'

드라이브 문자를 소문자로 바꾸는 것은 마운트 지점이 /mnt/C가 아니라 /mnt/c이기 때문입니다. 끝의 슬래시를 떼는 것은 /mnt/c/가 마운트 지점 자체와 다른 위치로 읽히기 때문입니다.

ActiveCli.Path.WslUncPath — WSL UNC 경로: \\wsl.localhost\Ubuntu\home\user\proj, 또는 구형인 \\wsl$\NixOS\home\maicol07.

class WslUncPath extends AbstractPath {
static matches(raw: string): boolean;
static parse(raw: string): WslUncPath | null;
readonly distro: string;
readonly linuxPath: string;
toWslPath(): string; // 안쪽의 Linux 경로
isSpawnableAsCwd(): boolean; // 언제나 false
}

이것이 양쪽 모두에서 spawn을 깨뜨리는 경로입니다. 그래서 isSpawnableAsCwd()는 언제나 false입니다. cmd.exe는 UNC cwd를 아예 거부하고, 배포판 안에서 도는 프로세스에는 그런 위치가 존재하지 않습니다.

WslUncPath.parse('\\\\wsl.localhost\\Ubuntu\\home\\user\\proj');
// distro 'Ubuntu', linuxPath '/home/user/proj'
WslUncPath.parse('\\\\wsl$\\NixOS\\home\\maicol07');
// distro 'NixOS', linuxPath '/home/maicol07'
WslUncPath.parse('\\\\wsl.localhost\\Ubuntu');
// distro 'Ubuntu', linuxPath '/'
WslUncPath.parse('\\\\server\\share\\file'); // null — UNC 경로이지만 WSL의 것은 아님
WslUncPath.parse('/home/user'); // null

distro id는 원래의 대소문자를 유지합니다. wsl -d가 그에 대해 대소문자를 가리기 때문입니다. \\wsl.localhost\ / \\wsl$\ 호스트 접두사만 대소문자 구분 없이 매칭됩니다.

슬래시로 된 입력도 일치로 칩니다. //wsl.localhost/Ubuntu/...는 IDE가 백엔드에 건네는 바로 그 형태이며, 슬래시로 시작한다는 이유만으로 POSIX 경로로 오인되어서는 안 됩니다.

이것이 spawn 시점에 중요해지는 지점

섹션 제목: “이것이 spawn 시점에 중요해지는 지점”

SpawnOptionsworkingDirectory를 들어오는 길에 변환합니다 — 문자열을, 자신이 spawn cwd가 될 수 있는지를 아는 무언가로 바꾸기에 가장 짧은 자리입니다.

const options = new SpawnOptions({ workingDirectory: '//wsl.localhost/Ubuntu/home/me' });
options.workingDirectory?.isSpawnableAsCwd(); // false
options.workingDirectory?.toWslPath(); // '/home/me'

ClaudeAdapter는 spawn 불가능한 cwd를 넘기는 대신 아예 생략합니다. 그것을 넘기면 바이너리가 아니라 디렉토리를 지목하는 ENOENT로 spawn이 실패하기 때문입니다 — 프로세스 실행 실패를 보십시오.