Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ owo-colors = { version = "4.3.0", features = ["supports-colors"] }
rand = "0.9"
humantime = "2.1.0"
sha2 = "0.10"
# Release-asset pipeline behind `treehouse update` (crates/treehouse-core/src/updater.rs):
# gzip + tar for the unix assets the release workflow builds, zip for the Windows
# asset. Both are declared with default features OFF — the workflow produces
# plain DEFLATE tar.gz / zip, and the default feature sets drag in xattr (tar)
# and aes-crypto/zstd/xz/lzma/bzip2/ppmd (zip) that we never call. `zip` is NOT
# target-gated to Windows: gating it would leave the extraction path unbuildable
# and therefore untested on the Linux/macOS CI that actually runs the suite.
flate2 = "1.1.10"
tar = { version = "0.4.46", default-features = false }
zip = { version = "8.6.0", default-features = false, features = ["deflate"] }
# TOON encoder (toon_rust). Package name is `tru` (v0.2.2), lib name `toon` —
# imports use `use toon::...`. MSRV 1.88, edition 2024, license MIT +
# OpenAI/Anthropic Rider (NOT plain MIT — see docs/rust-port-plan.md §3/§5.4).
Expand Down
1,352 changes: 1,352 additions & 0 deletions MISSING.md

Large diffs are not rendered by default.

67 changes: 64 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,26 @@ treehouse is built for coding agents and the orchestrators that spawn them. If y
| `stderr` | 🌳 human banners, warnings, prompts |
| `exit 0` | Success (including declined cleanup prompts) |
| `exit 1` | Error — the message is printed once to `stderr` |
| `exit 3` | A dirty worktree was left unreturned — **only** when `TREEHOUSE_EXIT_STRICT=1` |

### Exit code 3 (opt-in)

When a worktree has uncommitted changes and you do not pass `--force`, treehouse
leaves it exactly as it found it. Go v3.0.0 made that case exit `3` instead of
`0`, as a **breaking change**: a caller reading `exit 0` as "the slot was
released" was reading a bug.

treehouse keeps `exit 0` as the default so existing scripts do not change
behaviour, and ships the strict exit code behind an environment variable:

```bash
TREEHOUSE_EXIT_STRICT=1 treehouse return "$PATH"
# exit 3 + "worktree not returned ... uncommitted changes were kept"
```

Turn it on in CI and in any orchestrator that branches on the result. The two
codes demand different responses: `1` is worth retrying, `3` means the tree stays
dirty until someone cleans it or passes `--force`.

```bash
# 1) Durable lease — path-only on stdout, nothing else
Expand Down Expand Up @@ -165,7 +185,9 @@ exit
| `treehouse get` | Acquire a worktree from the pool |
| `treehouse get --lease` | Durably lease a worktree without a subshell; print its path |
| `treehouse enter <name>` | Attach to an existing worktree by name (from `status`), even if in use |
| `treehouse return [path]` | Release a lease, terminate lingering processes, reset, return to pool |
| `treehouse return [path\|name]` | Release a lease, terminate lingering processes, reset, return to pool |
| `treehouse return --all` | Return every worktree this repository holds; slots nobody holds are left alone |
| `treehouse lease <name>` | Durably lease an existing worktree by name, without touching its contents |
| `treehouse status` | Show pool status (highlights leased and current worktrees) |
| `treehouse prune` | Dry-run removal of stale idle worktrees |
| `treehouse gc` | Reclaim stale, orphaned, and dead-owner worktrees (dry-run default) |
Expand All @@ -184,6 +206,8 @@ exit
| `--lease-holder <label>` | Record who holds the lease (defaults to `$TREEHOUSE_LEASE_HOLDER`) |
| `--ttl <duration>` | Make the lease expire (e.g. `30m`, `1h30m`, `24h`); requires `--lease` |
| `--json` | Print `path`, `lease_id`, `lease_holder`, `leased_at` (and `expires_at`) as JSON; requires `--lease` |
| `--base <branch>` | Cut from this branch instead of the repository default (does **not** create the branch) |
| `--no-fetch` | Skip the `git fetch origin` that normally runs before acquiring (offline / air-gapped) |

### `status`

Expand All @@ -193,12 +217,31 @@ exit

### `return`

The argument is read as a path first and then as a slot name, so `treehouse return 3`
does the obvious thing from inside the repo. It defaults to `$TREEHOUSE_DIR`.

| Flag | Description |
|------|-------------|
| `--force` | Clean, reset, and return without prompting |
| `--all` | Return every worktree held for this repository; slots nobody holds are left alone |
| `--if-lease-id <id>` | Return only if the current lease has this identity (ABA-safe) |
| `--if-lease-holder <holder>` | Return only if the current lease has this holder |

### `lease`

Durably lease a worktree **by name** without touching its contents — the counterpart
to `get --lease` for a slot that already exists.

| Flag | Description |
|------|-------------|
| `--lease-holder <label>` | Record who holds the lease (defaults to `$TREEHOUSE_LEASE_HOLDER`) |
| `--json` | Print the lease identity as JSON instead of the bare path |

```bash
treehouse lease 3 --lease-holder agent-42
treehouse lease 3 --lease-holder agent-42 --json
```

### `prune` / `gc`

| Flag | Description |
Expand All @@ -222,7 +265,25 @@ exit

| Flag | Description |
|------|-------------|
| `--env-path <DIR>` | Custom pool root (overrides `treehouse.toml` root and `~/.treehouse`); available on every command |
| `--root <DIR>` | Custom pool root; available on every command. Aliased as `--env-path`. |
| `TREEHOUSE_ROOT` | Same thing, from the environment |

Precedence, highest first:

```
--root <DIR> > TREEHOUSE_ROOT > treehouse.toml `root` > ~/.treehouse
```

> **`--root` and `--env-path` are the same flag**, and the directory you name is
> the **parent** of the pool, not the pool itself — Go's `--root` semantics. So
> `treehouse --root /tmp/pools get` puts the worktree in
> `/tmp/pools/.treehouse/<repo>-<hash>/`, not in `/tmp/pools/`. Use an absolute
> path; a relative one (including `.`) resolves from the repository root, which
> is how an in-project pool at `<repo>/.treehouse` is configured.
>
> This is a behaviour change from v0.1.2 and earlier, where `--env-path` was a
> silent no-op that always fell back to `~/.treehouse`. If you were relying on
> the old flag, it now works — and the pool it selects is the one above.

### `doctor`

Expand All @@ -241,7 +302,7 @@ Sweeps every pool under `~/.treehouse` — designed to run from your OS schedule
| `--interval <dur>` | Sweep interval for the foreground loop (e.g. `30s`, `5m`, `1h`). Default: `60s`. Ignored when `--once` is set |
| `--yes` | Execute instead of dry-run |
| `--prune-orphans` | Include backing-repository-missing orphans |
| `--env-path <DIR>` | Custom pool root (overrides `treehouse.toml` root and `~/.treehouse`) |
| `--root <DIR>` | Custom pool root (see [Global flag](#global-flag)); aliased as `--env-path` |

```bash
# One-shot — ideal for cron / systemd timer
Expand Down
4 changes: 4 additions & 0 deletions crates/treehouse-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ owo-colors = { workspace = true }
rand = { workspace = true }
humantime = { workspace = true }
sha2 = { workspace = true }
# Release-asset extraction for `treehouse update`; see updater.rs.
flate2 = { workspace = true }
tar = { workspace = true }
zip = { workspace = true }
# The `tru` package (Dicklesworthstone/toon_rust, lib name `toon`) is the TOON
# encoder, verified + pinned by the toon-verify bead. It is optional (the `toon`
# feature) so a checkout without network access to toon_rust still compiles.
Expand Down
Loading
Loading