
The `fs` module provides capability-typed filesystem access with `Result` returns:

```vary
import fs

def example() -> Result[None, FsError] {
    let wp = fs.write_path("/tmp/demo.txt")?
    let _w = fs.write_text(wp, "hello")?
    let rp = fs.read_path("/tmp/demo.txt")?
    let content = fs.read_text(rp)?
    return Ok(None)
}
```

## Path Constructors

Create typed paths before performing operations. Each constructor validates capabilities at construction time:

| **Constructor** | **Returns** | **Validation** |
|----------|-----------|-----------|
| `fs.path(s)` | `Path` | None (neutral type) |
| `fs.read_path(s)` | `Result[ReadPath, FsError]` | Must exist and be readable |
| `fs.write_path(s)` | `Result[WritePath, FsError]` | Parent must be writable |
| `fs.dir_path(s)` | `Result[DirPath, FsError]` | Must exist and be a directory |
| `fs.root(s)` | `Result[RootDir, FsError]` | Must exist and be a directory |

Operations require matching path types - `fs.read_text()` takes a `ReadPath`, `fs.write_text()` takes a `WritePath`, `fs.list_dir()` takes a `DirPath`, and so on.

## Operations

| **Function** | **Signature** | **Description** |
|----------|-----------|-----------|
| `fs.read_text(p)` | `(ReadPath) -> Result[Str, FsError]` | Read file as string |
| `fs.write_text(p, s)` | `(WritePath, Str) -> Result[None, FsError]` | Write string to file |
| `fs.append_text(p, s)` | `(AppendPath, Str) -> Result[None, FsError]` | Append string to file |
| `fs.read_lines(p)` | `(ReadPath) -> Result[List[Str], FsError]` | Read file as list of lines |
| `fs.mkdir(p)` | `(Path) -> Result[DirPath, FsError]` | Create directory |
| `fs.makedirs(p)` | `(Path) -> Result[DirPath, FsError]` | Create directory tree |
| `fs.remove(p)` | `(WritePath) -> Result[None, FsError]` | Delete file |
| `fs.copy(src, dst)` | `(ReadPath, WritePath) -> Result[None, FsError]` | Copy file |
| `fs.move(src, dst)` | `(WritePath, WritePath) -> Result[None, FsError]` | Move file |
| `fs.list_dir(p)` | `(DirPath) -> Result[List[Str], FsError]` | List directory contents |
| `fs.walk(p)` | `(DirPath) -> Result[List[Str], FsError]` | Recursive directory listing |
| `fs.exists(p)` | `(Path) -> Bool` | Check if path exists |
| `fs.copy_dir(src, dst)` | `(Path, Path) -> Result[None, FsError]` | Recursively copy directory tree |
| `fs.remove_dir(p)` | `(Path) -> Result[None, FsError]` | Recursively delete directory and contents |
| `fs.ensure_dir(p)` | `(Path) -> Result[DirPath, FsError]` | Create directory if it does not exist |
| `fs.glob(pattern, base)` | `(Str, Str) -> Result[List[Str], FsError]` | Find files matching glob pattern |
| `fs.metadata(p)` | `(Path) -> Result[FsMetadata, FsError]` | Get file metadata (size, timestamps, type) |
| `fs.permissions(p)` | `(Path) -> Result[FsPermissions, FsError]` | Get file permissions |
| `fs.is_file(p)` | `(Path) -> Bool` | Check if path is a regular file |
| `fs.is_dir(p)` | `(Path) -> Bool` | Check if path is a directory |
| `fs.is_symlink(p)` | `(Path) -> Bool` | Check if path is a symbolic link |
| `fs.file_size(p)` | `(Path) -> Result[Int, FsError]` | Get file size in bytes |
| `fs.modified_time(p)` | `(Path) -> Result[Int, FsError]` | Get last modified time as epoch ms |
| `fs.walk_dir(p)` | `(DirPath) -> Result[List[Str], FsError]` | Recursively list all paths in directory |
| `fs.walk_files(p, ext)` | `(DirPath, Str) -> Result[List[Str], FsError]` | Recursively find files with given extension |

## FsMetadata

`fs.metadata(p)` returns an `FsMetadata` object with the following methods:

| **Method** | **Returns** | **Description** |
|----------|-----------|-----------|
| `.size()` | `Int` | File size in bytes |
| `.is_file()` | `Bool` | True if path is a regular file |
| `.is_dir()` | `Bool` | True if path is a directory |
| `.is_symlink()` | `Bool` | True if path is a symbolic link |
| `.modified_millis()` | `Int` | Last modified time as epoch milliseconds |

## FsPermissions

`fs.permissions(p)` returns an `FsPermissions` object with the following methods:

| **Method** | **Returns** | **Description** |
|----------|-----------|-----------|
| `.readable()` | `Bool` | True if path is readable |
| `.writable()` | `Bool` | True if path is writable |
| `.executable()` | `Bool` | True if path is executable |

## Quick-start example

```vary
import fs

let rp = fs.read_path("input.txt").unwrap()
let content = fs.read_text(rp).unwrap()

let wp = fs.write_path("output.txt").unwrap()
fs.write_text(wp, content).unwrap()

if fs.exists(fs.path("output.txt")) {
    print("written")
}
```
