Paths
AbstractPath
Section titled “AbstractPath”ActiveCli.Path.AbstractPath — a filesystem location, as some concrete flavour of path.
abstract class AbstractPath { toString(): string; abstract toWslPath(): string; abstract isSpawnableAsCwd(): boolean;}Paths arrive at our boundaries as bare strings — from a caller’s options, from an IDE handing us a project root, from a CLI’s JSON output. A string cannot answer “are you a Windows drive path or a Linux one?”, so every caller that needs to know re-derives it, and the derivations drift apart. Here the answer is the class.
| Member | Description |
|---|---|
toString() |
The path exactly as it was given, separators and all. |
toWslPath() |
This location as the path a process running inside a WSL distro would see. Named for the destination rather than the source, because that is what the caller is choosing: “render yourself for a Linux child”. A path already native to that world answers with itself. |
isSpawnableAsCwd() |
Whether spawning a child with this path as cwd is safe on the current host. |
PathParser
Section titled “PathParser”ActiveCli.Path.PathParser — turns a path string into the flavour it actually is. The boundary where a bare string stops being allowed to travel: call it the moment a path arrives, and pass the instance everywhere after.
class PathParser { parse(raw: string): AbstractPath;}| Input | Result | 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 (relative) |
PosixPath |
src/core |
Anything not absolute in any flavour is treated as POSIX, which normalises separators on the way out and stays spawnable — the honest answer for a relative cwd.
PathParser is a separate class rather than a static on AbstractPath so the base does not have to import its own subclasses.
PosixPath
Section titled “PosixPath”ActiveCli.Path.PosixPath — a Linux/macOS path (/home/user/proj), and the fallback for anything not absolute in another flavour.
class PosixPath extends AbstractPath { constructor(raw: string); toWslPath(): string; // separators normalised isSpawnableAsCwd(): boolean; // always true}Already native to a POSIX child, so it is always safe as a spawn cwd. A relative path may still reach us with back-slashes (src\core), and separators are converted in toWslPath() rather than at construction — which keeps toString() honest about what we were given.
WindowsPath
Section titled “WindowsPath”ActiveCli.Path.WindowsPath — a Windows drive path (C:\Users\foo, or the separator-less C:Users\foo).
class WindowsPath extends AbstractPath { constructor(raw: string); static matches(raw: string): boolean; // second character is ':' toWslPath(): string; isSpawnableAsCwd(): boolean; // always true}Inside a WSL distro the Windows drives are mounted under /mnt/<letter>, so that is what a Linux child must be handed.
parser.parse('D:\\Projects').toWslPath(); // '/mnt/d/Projects'parser.parse('C:\\').toWslPath(); // '/mnt/c' — not '/mnt/c/'parser.parse('C:Users\\foo').toWslPath(); // '/mnt/c/Users/foo'The drive letter is lower-cased because the mount point is /mnt/c, not /mnt/C. A trailing slash is stripped because /mnt/c/ reads as a different location than the mount point itself.
WslUncPath
Section titled “WslUncPath”ActiveCli.Path.WslUncPath — a WSL UNC path: \\wsl.localhost\Ubuntu\home\user\proj, or the legacy \\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; // the inner Linux path isSpawnableAsCwd(): boolean; // always false}This is the path that breaks spawning, from both sides. isSpawnableAsCwd() is therefore always false: cmd.exe refuses a UNC cwd outright, and a process running inside the distro has no such location either.
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 — a UNC path, but not a WSL oneWslUncPath.parse('/home/user'); // nullThe distro id keeps its original casing, because wsl -d is case-sensitive about it. Only the \\wsl.localhost\ / \\wsl$\ host prefix is matched case-insensitively.
Forward-slashed input counts as a match: //wsl.localhost/Ubuntu/... is the exact form an IDE hands a backend, and it must not be mistaken for a POSIX path just because it starts with a slash.
Where this matters at spawn time
Section titled “Where this matters at spawn time”SpawnOptions converts workingDirectory on the way in — the shortest place to turn a string into something that knows whether it can be a spawn cwd at all.
const options = new SpawnOptions({ workingDirectory: '//wsl.localhost/Ubuntu/home/me' });options.workingDirectory?.isSpawnableAsCwd(); // falseoptions.workingDirectory?.toWslPath(); // '/home/me'ClaudeAdapter omits an unspawnable cwd entirely rather than handing it over, because handing it over fails the spawn with ENOENT naming the directory rather than the binary — see Spawning failures.