Winix.TreeX 0.3.0

Prefix Reserved
dotnet tool install --global Winix.TreeX --version 0.3.0
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local Winix.TreeX --version 0.3.0
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=Winix.TreeX&version=0.3.0
                    
nuke :add-package Winix.TreeX --version 0.3.0
                    

treex

Enhanced directory tree with colour, filtering, size rollups, gitignore, and clickable hyperlinks. Cross-platform tree replacement.

tree replacement (and works on Linux/macOS too).

Install

Scoop (Windows)

scoop bucket add winix https://github.com/Yortw/winix
scoop install winix/treex

Winget (Windows, stable releases)

winget install Winix.TreeX

.NET Tool (cross-platform)

dotnet tool install -g Winix.TreeX

Direct Download

Download native binaries from GitHub Releases.

Usage

treex [options] [paths...]

Walks one or more directories (default: .) and renders a tree-formatted listing to stdout. Filters, sizes, and sort order are all configurable.

Examples

# Basic tree of current directory
treex

# Show only C# files with their ancestor directories
treex src --ext cs

# Clean tree with sizes, skipping hidden and gitignored
treex --size --gitignore --no-hidden

# Sort by size to find the largest files
treex --size --sort size

# Limit to 2 levels deep
treex -d 2

# Multiple roots
treex src tests

# Structured output (NDJSON to stdout)
treex --ndjson | jq '.name'

# AI agent metadata
treex --describe

Options

Option Description
-g, --glob PATTERN Match filenames against glob pattern (repeatable)
-e, --regex PATTERN Match filenames against regex (repeatable)
--ext EXT Match file extension, e.g. cs, log (repeatable)
-t, --type TYPE Filter by type: f (file), d (directory), l (symlink)
--min-size SIZE Minimum file size (e.g. 100k, 10M, 1G)
--max-size SIZE Maximum file size (e.g. 100k, 10M)
--newer DURATION Modified within duration (e.g. 1h, 30m, 7d)
--older DURATION Not modified within duration (e.g. 1h, 7d)
-d, --max-depth N Maximum directory depth (0-based; 0 = root only, 1 = root + immediate children, N = root + N levels of children)
--no-hidden Skip hidden files and directories
--gitignore Respect .gitignore rules
-i, --ignore-case Case-insensitive matching
--case-sensitive Case-sensitive matching
-s, --size Show file sizes
--date Show last-modified dates
--sort MODE Sort: name (default), size, modified
-D, --dirs-only Show only directories
--no-links Disable clickable terminal hyperlinks
--ndjson Streaming NDJSON to stdout (one JSON object per node)
--json JSON envelope to stdout on exit (suite convention; pipe-friendly for jq)
--describe Print machine-readable metadata (flags, examples, composability) and exit
--no-color Disable colored output
--color Force colored output
--version Show version
-h, --help Show help

Size Units

--min-size and --max-size accept values with optional unit suffix: b (bytes), k (kilobytes, 1024), M (megabytes), G (gigabytes). No suffix = bytes. Examples: 500, 10k, 2M, 1G.

Duration Units

--newer and --older accept a duration: a number followed by s (seconds), m (minutes), h (hours), d (days), w (weeks). Examples: 30m, 1h, 7d.

Differences from tree

Behaviour tree treex
Windows availability Yes (DOS-era, limited) Yes
Linux/macOS Varies by distro Yes
Colour No (Windows) / Basic (Linux) Full ANSI
Clickable hyperlinks No Yes (when terminal supports)
Filter by name/ext No --glob, --ext, --regex
Filter by size No --min-size / --max-size
Filter by date No --newer / --older
Respect .gitignore No --gitignore
Skip hidden No --no-hidden
Size rollups No --size
JSON output No --ndjson / --json
Sort order name only by default (most builds) name, size, modified

Exit Codes

Code Meaning
0 Success
1 Runtime error (permission denied, invalid path, or partial walk where one or more directories could not be enumerated)
125 Usage error (bad arguments)

When a walk encounters unreadable directories (e.g. a chmod-denied subdirectory), each unreadable path is reported on stderr (treex: <path>: <reason>), the rendered tree marks the directory with [error opening dir], and the process exits 1 with exit_reason: walk_error_partial in the --json envelope. This matches tree(1) behaviour.

Structured Output

treex supports two machine-readable output modes, both on stdout per suite convention:

NDJSON (--ndjson) — one JSON object per tree node, suitable for streaming consumers and jq:

Field Type Description
path string File path relative to the search root (forward-slash separated)
name string Filename only
type string file, dir, or link
size_bytes int | null File size in bytes; null for directories without --size rollup
modified string ISO 8601 timestamp
depth int Depth relative to root (0 = root, 1 = immediate child)

JSON envelope (--json) — single summary object emitted after the walk completes:

Field Type Description
tool string "treex"
version string Tool version
exit_code int Process exit code
exit_reason string Machine-readable reason (success, walk_error_partial, path_not_found, not_a_directory, usage_error, runtime_error)
directories int Number of directories walked (excluding root)
files int Number of files walked
total_size_bytes int Sum of file sizes (only present when --size is on)
walk_errors array Paths that could not be read during the walk; each entry has path and reason. Always present (empty array on success).
error string Human-readable failure reason (only present on pre-walk error envelopes — path_not_found, not_a_directory)

Colour

  • Automatic: colour when outputting to a terminal, plain when piped
  • --color forces colour on (overrides NO_COLOR)
  • --no-color forces colour off
  • Respects the NO_COLOR environment variable (no-color.org)
  • Clickable hyperlinks are disabled when colour is off (e.g. --no-color, piped output) or when --no-links is passed

Part of Winix

treex is part of the Winix CLI toolkit.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
0.3.0 90 5/26/2026
0.3.0-rc2 92 5/10/2026
0.2.0 112 4/16/2026
0.2.0-test4 98 4/15/2026
0.1.0 118 4/2/2026

## [0.3.0] - 2026-05-09

### Changed (BREAKING)
- `--max-depth N` semantics: now `depth ≤ N` with the search root at depth 0. `--max-depth 0` shows only the root; `--max-depth 1` shows root + immediate children. Previously `--max-depth 0` showed root + immediate children, contradicting the documented contract. Migration: subtract 1 from any existing `--max-depth` values.

### Changed
- `--ndjson` records no longer include envelope fields (`tool`, `version`, `exit_code`, `exit_reason`). Stream-level metadata is now emitted only via `--json`. Each NDJSON line carries only per-record fields (`path`, `name`, `type`, `size_bytes`, `modified`, `depth`) — ~35% bandwidth reduction on small trees, line-record convention compliance.
- `size_bytes` field now emits JSON `null` for directories without `--size` rollup (was the sentinel `-1`).
- `--json` output now goes to **stdout** (was stderr) per suite convention. Pipe-friendly for `jq` and matches `man`, `winix`, `whoholds`.
- `--older DURATION` description updated from "Modified before duration" to "Not modified within duration" — same behaviour, clearer phrasing.

### Fixed
- `--size --ndjson` now reports correct `total_size_bytes` in the summary envelope. Previously the NDJSON branch never accumulated sizes, so the summary always reported `0` regardless of actual file sizes.
- Walk errors (permission denied, vanishing directories, I/O failures) are now surfaced to stderr and the process exits 1 with `exit_reason: walk_error_partial`. Previously these were silently swallowed and the partial tree shipped with exit 0, contradicting the documented exit-1 contract.
- Directories that cannot be enumerated are now annotated with `[error opening dir]` in the rendered tree, matching `tree(1)` precedent.
- `--describe` JSON field schema for `size_bytes` updated from `int` to `int|null` to match the post-fix emitter.
- Path that exists but is a regular file (not a directory) now reports "not a directory" instead of the misleading "path not found", and surfaces `exit_reason: not_a_directory` in the `--json` envelope.
- `--version` output no longer carries the `+gitsha` SourceLink suffix. Users see plain `treex 0.3.0`, matching the suite-wide convention.

### Added
- Library seam `Winix.TreeX.Cli.Run` for orchestration testing without process spawning.
- `--json` pre-walk error envelopes (path_not_found, not_a_directory) now carry an `error` field with the human-readable failure detail (in addition to the machine-readable `exit_reason`).
- `--json` summary envelope now includes a `walk_errors` array enumerating directories and files that could not be read during the walk. Each entry is `{"path": "...", "reason": "..."}`. Always present (empty array on success); non-empty when `exit_reason: "walk_error_partial"`. Closes the JSON-consumer blind spot where the prior envelope reported `exit_reason: walk_error_partial` but didn't enumerate which paths failed.

See full changelog at https://github.com/Yortw/winix/blob/main/src/treex/CHANGELOG.md