Merge nucleic/vivid-harbor-tapir-5aci into dev
This commit is contained in:
@@ -1,204 +1,136 @@
|
||||
<div align="center">
|
||||
<img src="https://github.com/user-attachments/assets/266b83a6-bacb-408c-afb7-2a2ddf37b272"/>
|
||||
</div>
|
||||
# nucleic-brush
|
||||
|
||||
<br/>
|
||||
A fork of [**brush**](https://github.com/reubeno/brush) — the Bo(u)rn(e) RUsty SHell by
|
||||
reuben olinsky — carrying the patches Nucleic needs to build **nash**, its agent shell.
|
||||
|
||||
<!-- Primary badges -->
|
||||
<p align="center">
|
||||
<!-- crates.io version badge -->
|
||||
<a href="https://crates.io/crates/brush-shell"><img src="https://img.shields.io/crates/v/brush-shell?style=flat-square"/></a>
|
||||
<!-- msrv badge -->
|
||||
<img src="https://img.shields.io/crates/msrv/brush-shell"/>
|
||||
<!-- license badge -->
|
||||
<img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square"/>
|
||||
<br/>
|
||||
<!-- crates.io download badge -->
|
||||
<a href="https://crates.io/crates/brush-shell"><img src="https://img.shields.io/crates/d/brush-shell?style=flat-square"/></a>
|
||||
<!-- compat tests badge -->
|
||||
<img src="https://img.shields.io/badge/compat_tests-1389-brightgreen?style=flat-square" alt="1389 compatibility tests"/>
|
||||
<!-- Packaging badges -->
|
||||
<a href="https://repology.org/project/brush/versions">
|
||||
<img src="https://repology.org/badge/tiny-repos/brush.svg" alt="Packaging status"/>
|
||||
</a>
|
||||
<!-- Social badges -->
|
||||
<a href="https://discord.gg/kPRgC9j3Tj">
|
||||
<img src="https://dcbadge.limes.pink/api/server/https://discord.gg/kPRgC9j3Tj?compact=true&style=flat" alt="Discord invite"/>
|
||||
</a>
|
||||
</p>
|
||||
Pinned at upstream tag **`brush-shell-v0.4.0`** (commit `96a26d0`).
|
||||
|
||||
<a href="https://repology.org/project/brush/versions">
|
||||
</a>
|
||||
> **Looking for the shell itself?** Go [upstream](https://github.com/reubeno/brush).
|
||||
> This repository is not a distribution of brush and publishes no binaries or crates —
|
||||
> it is a vendored fork whose only consumer is Nucleic's `shell/` workspace. Everything
|
||||
> here that isn't marked as a fork change is upstream's work, under upstream's
|
||||
> [MIT license](LICENSE).
|
||||
|
||||
</p>
|
||||
## What the fork adds
|
||||
|
||||
<hr/>
|
||||
Nucleic runs agent-authored shell commands and needs to *see* what they do — the
|
||||
commands, their exits, and the data crossing pipes and redirections — from inside the
|
||||
shell rather than by wrapping it. That is what these patches provide. Everything else
|
||||
is upstream brush, unmodified.
|
||||
|
||||
`brush` (**B**o(u)rn(e) **RU**sty **SH**ell) is a modern [bash-](https://www.gnu.org/software/bash/) and [POSIX-](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html) compatible shell written in Rust. Run your existing scripts and `.bashrc` unchanged -- with syntax highlighting and auto-suggestions built in.
|
||||
|
||||
## At a glance
|
||||
|
||||
✅ Your existing `.bashrc` just works—aliases, functions, completions, all of it.<br/>
|
||||
✨ Syntax highlighting and auto-suggestions built in.<br/>
|
||||
🧪 Validated against bash with [~1700 compatibility tests](brush-shell/tests/cases).<br/>
|
||||
🧩 Easily embeddable in your Rust apps using `brush_core::Shell`.<br/>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://github.com/user-attachments/assets/0e64d1b9-7e4e-43be-8593-6c1b9607ac52" width="80%"/>
|
||||
</p>
|
||||
|
||||
> ⚠️ **Not everything works yet:** `select` and some edge cases aren't supported. See the [Compatibility Reference](docs/reference/compatibility.md) for details.
|
||||
|
||||
### Quick start:
|
||||
Every divergence carries a `// nash:` comment, so the complete diff against upstream is
|
||||
one grep away:
|
||||
|
||||
```console
|
||||
$ cargo binstall brush-shell # using cargo-binstall
|
||||
$ brew install brush # using Homebrew
|
||||
$ pacman -S brush # Arch Linux
|
||||
$ cargo install --locked brush-shell # Build from sources
|
||||
$ grep -rn "nash:" --include="*.rs" --include="*.yaml" .
|
||||
```
|
||||
|
||||
`brush` is ready for use as a daily driver. We test every change against `bash` to keep it that way.
|
||||
### 1. The observation gate
|
||||
|
||||
More detailed installation instructions are available below.
|
||||
A process-global, verdict-shaped hook at the shell's command choke point
|
||||
(`brush-core/src/gate.rs`). The default implementation allows everything and observes
|
||||
nothing, so **an unconfigured shell behaves exactly like upstream brush** — including
|
||||
the fast paths: pipe teeing is only wired up when a real gate is installed.
|
||||
|
||||
## ✨ Features
|
||||
| Surface | What it reports |
|
||||
| --- | --- |
|
||||
| `Gate::on_exec` / `on_exit` | every simple command (builtin, function, external): argv, cwd, redirections, pipeline slot; then its exit code (128+signal for signal deaths) |
|
||||
| `Gate::on_pipe` | the bytes crossing each `a \| b` link once it drains, with both stages rendered from their *pre-expansion* AST text |
|
||||
| `Gate::on_cmdsub` | the trimmed output of `$(…)` / backtick substitutions |
|
||||
|
||||
### 🐚 `bash` Compatibility
|
||||
`on_exec` returns a `Verdict`, so the same seam supports enforcement (`Deny`) later
|
||||
without further changes to this crate. Today Nucleic only observes.
|
||||
|
||||
| | Feature | Description |
|
||||
|--|---------|-------------|
|
||||
| ✅ | **50+ builtins** | `echo`, `declare`, `read`, `complete`, `trap`, `ulimit`, ... |
|
||||
| ✅ | **Full expansions** | brace, parameter, arithmetic, command/process substitution, globs, `extglob`, `globstar` |
|
||||
| ✅ | **Control flow** | `if`/`for`/`while`/`until`/`case`, `&&`/`\|\|`, subshells, pipelines, etc. |
|
||||
| ✅ | **Redirection** | here docs, here strings, fd duplication, process substitution redirects |
|
||||
| ✅ | **Arrays & variables** | indexed/associative arrays, dynamic variables, standard well-known variables, etc. |
|
||||
| ✅ | **Programmable completion** | Works with [bash-completion](https://github.com/scop/bash-completion) out of the box |
|
||||
| ✅ | **Job control** | background jobs, suspend/resume, `fg`/`bg`/`jobs` |
|
||||
| 🔷 | **Traps & options** | `DEBUG`/`ERR`/`EXIT` traps work; signal traps and options in progress |
|
||||
The plumbing behind those hooks:
|
||||
|
||||
### ⌨️ User Experience
|
||||
| File | Change |
|
||||
| --- | --- |
|
||||
| `brush-core/src/gate.rs` (new), `lib.rs` | the `Gate` trait, event types, and process-global install/allow-all default |
|
||||
| `brush-core/src/commands.rs` | `SimpleCommand::execute` split into a gate wrapper + `execute_inner`; `on_exec` runs before dispatch and correlates completion across all three spawn-result variants |
|
||||
| `brush-core/src/processes.rs` | `ChildProcess.gate_token` and `on_exit` reporting from both `wait()` and `poll()`, exactly once |
|
||||
| `brush-core/src/interp.rs` | redirection recording (`>`, `>>`, `<`, `2>`, `&>`, `<>`, heredocs, here-strings) for post-run read-back; a tee interposed on each pipe link when observation is active — a pooled copier thread mirrors a bounded prefix while preserving backpressure and SIGPIPE, with a `splice` passthrough after the cap |
|
||||
| `brush-core/src/expansion.rs` | command-substitution arm reports its output to the gate |
|
||||
| `brush-shell/src/entry.rs` | `set_exit_hook` seam so an embedder can flush buffered events before `process::exit` |
|
||||
|
||||
| | Feature | Description |
|
||||
|--|---------|-------------|
|
||||
| ✅ | **Syntax highlighting** | Real-time as you type ([reedline](https://github.com/nushell/reedline)) |
|
||||
| ✅ | **Auto-suggestions** | History-based hints as you type ([reedline](https://github.com/nushell/reedline)) |
|
||||
| ✅ | **Rich prompts** | `PS1`/`PROMPT_COMMAND`, right prompts, [starship](https://starship.rs) compatible |
|
||||
| ✅ | **TOML config** | `~/.config/brush/config.toml` for persistent settings |
|
||||
| 🧪 | **Extras** | `fzf`/`atuin` support, zsh-style `precmd`/`preexec` hooks (experimental), VS Code terminal integration |
|
||||
### 2. Upstream-candidate fixes
|
||||
|
||||
## Installation
|
||||
Bugs found by running real-world scripts through brush. These aren't Nucleic-specific
|
||||
and belong upstream:
|
||||
|
||||
_When you run `brush`, it should look exactly as `bash` does on your system: it processes your `.bashrc` and
|
||||
other standard configuration. If you'd like to distinguish the look of `brush` from the other shells
|
||||
on your system, you may author a `~/.brushrc` file._
|
||||
| File | Fix |
|
||||
| --- | --- |
|
||||
| `brush-core/src/expansion.rs` | literal unquoted word text is no longer field-split (bash splits only the *results* of expansions) while keeping its glob characters active. Parameter-expansion substitutions convert back to splittable at the expansion boundary; `ExpanderOptions.field_split_literal_text` lets data-string callers opt in. Repairs 3 previously `known_failure` IFS tests. |
|
||||
| `brush-core/src/completion.rs` | `compgen -W` opts into `field_split_literal_text` — the `-W` string is data, not source text |
|
||||
| `brush-builtins/src/dot.rs` | `.` / `source` searches `PATH` for slashless operands when `sourcepath` is set, as bash and POSIX require. Fixes `git-subtree`, which sources `git-sh-setup` this way. |
|
||||
|
||||
<details>
|
||||
<summary>🍺 <b>Installing using Homebrew</b> (macOS/Linux)</summary>
|
||||
### 3. Branding
|
||||
|
||||
Homebrew users can install using [the `brush` formula](https://formulae.brew.sh/formula/brush):
|
||||
The binary this workspace builds is still named `brush`, but identifies itself as nash
|
||||
so an agent-facing shell doesn't misrepresent what it is:
|
||||
|
||||
```bash
|
||||
brew install brush
|
||||
| File | Change |
|
||||
| --- | --- |
|
||||
| `brush-shell/src/productinfo.rs` | `PRODUCT_NAME` → `nash`; display string reads `nash (Nucleic agent shell, brush fork) …` |
|
||||
| `brush-shell/src/args.rs` | usage and version strings rebranded |
|
||||
| `brush-core/src/prompt.rs` | `\$` renders the atom sign `⚛` (U+269B) for non-root; root still shows `#` |
|
||||
|
||||
[`NUCLEIC_FORK.md`](NUCLEIC_FORK.md) tracks the same list at file granularity, with the
|
||||
current verification status.
|
||||
|
||||
## How it's consumed
|
||||
|
||||
Nucleic's `shell/` workspace depends on `brush-shell` and `brush-parser` by path. The
|
||||
`nash` binary is a thin wrapper that loads a root-owned operator policy, installs its
|
||||
`Gate` implementation (`nash-observe`), flushes events at exit, and otherwise defers
|
||||
entirely to brush's bash-compatible CLI. None of the fork's crates are published; the
|
||||
`brush` binary built from here is a development artifact.
|
||||
|
||||
## Building and testing
|
||||
|
||||
Standard upstream workflow — a recent Rust toolchain (see `rust-version` in
|
||||
[`Cargo.toml`](Cargo.toml)), then:
|
||||
|
||||
```console
|
||||
$ cargo build --release
|
||||
$ cargo test --workspace
|
||||
$ cargo test -p brush-shell --test brush-compat-tests # the bash-oracle compat suite
|
||||
```
|
||||
|
||||
</details>
|
||||
The compat suite is the fork's regression gate: it must stay level with a pristine
|
||||
build of the pinned upstream tag. As last recorded in
|
||||
[`NUCLEIC_FORK.md`](NUCLEIC_FORK.md), it does — the only failures are environmental
|
||||
ones a baseline run reproduces, plus the 3 IFS tests the expansion fix repairs.
|
||||
|
||||
<details>
|
||||
<summary>🐧 <b>Installing on Arch Linux</b></summary>
|
||||
## Staying in sync with upstream
|
||||
|
||||
Arch Linux users can install `brush` from the official [extra repository](https://archlinux.org/packages/extra/x86_64/brush/):
|
||||
1. Diff this tree against the pinned upstream tag.
|
||||
2. Re-vendor the new tag.
|
||||
3. Re-apply the fork patches — `grep -rn "nash:"` on the old tree enumerates all of
|
||||
them.
|
||||
4. Re-run the brush compat suite and Nucleic's transcript-replay corpus.
|
||||
5. Update the pin and the patch table in [`NUCLEIC_FORK.md`](NUCLEIC_FORK.md).
|
||||
|
||||
```bash
|
||||
pacman -S brush
|
||||
```
|
||||
Fixes that aren't Nucleic-specific should go to
|
||||
[upstream](https://github.com/reubeno/brush/issues) rather than accumulate here — a
|
||||
smaller diff is a cheaper rebase.
|
||||
|
||||
</details>
|
||||
## Upstream documentation
|
||||
|
||||
<details>
|
||||
<summary>🚀 <b>Installing prebuilt binaries via `cargo binstall`</b></summary>
|
||||
Retained as vendored, and still accurate for everything the fork doesn't touch:
|
||||
|
||||
You may use [cargo binstall](https://github.com/cargo-bins/cargo-binstall) to install pre-built `brush` binaries. Once you've installed `cargo-binstall` you can run:
|
||||
* [Compatibility reference](docs/reference/compatibility.md) — what does and doesn't work versus bash
|
||||
* [Configuration](docs/reference/configuration.md)
|
||||
* [Building from source](docs/how-to/build.md) · [Running tests](docs/how-to/run-tests.md)
|
||||
* [Full docs index](docs/README.md)
|
||||
|
||||
```bash
|
||||
cargo binstall brush-shell
|
||||
```
|
||||
## Credits and license
|
||||
|
||||
</details>
|
||||
brush is written by **reuben olinsky** and its contributors:
|
||||
<https://github.com/reubeno/brush>. It is an excellent piece of work, and the reason
|
||||
Nucleic could get an observable shell by patching rather than by writing one.
|
||||
|
||||
<details>
|
||||
<summary>🚀 <b>Installing prebuilt binaries from GitHub</b></summary>
|
||||
|
||||
We publish prebuilt binaries of `brush` for Linux (x86_64, aarch64) and macOS (aarch64) to GitHub for official [releases](https://github.com/reubeno/brush/releases). You can manually download and extract the `brush` binary from one of the archives published there, or otherwise use the GitHub CLI to download it, e.g.:
|
||||
|
||||
```bash
|
||||
gh release download --repo reubeno/brush --pattern "brush-x86_64-unknown-linux-gnu.*"
|
||||
```
|
||||
|
||||
After downloading the archive for your platform, you may verify its authenticity using the [GitHub CLI](https://cli.github.com/), e.g.:
|
||||
|
||||
```bash
|
||||
gh attestation verify brush-x86_64-unknown-linux-gnu.tar.gz --repo reubeno/brush
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>🐧 <b>Installing using Nix</b></summary>
|
||||
|
||||
If you are a Nix user, you can use the registered version:
|
||||
|
||||
```bash
|
||||
nix run 'github:NixOS/nixpkgs/nixpkgs-unstable#brush' -- --version
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary> 🔨 <b>Building from sources</b></summary>
|
||||
|
||||
To build from sources, first install a working (and recent) `rust` toolchain; we recommend installing it via [`rustup`](https://rustup.rs/). Then run:
|
||||
|
||||
```bash
|
||||
cargo install --locked brush-shell
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Community & Contributing
|
||||
|
||||
This project started out of curiosity and a desire to learn—we're keeping that attitude. If something doesn't work the way you'd expect, [let us know](https://github.com/reubeno/brush/issues)!
|
||||
|
||||
* [Discord server](https://discord.gg/kPRgC9j3Tj) — chat with the community
|
||||
* [Building from source](docs/how-to/build.md) — development workflow
|
||||
* [Contribution guidelines](CONTRIBUTING.md) — how to submit changes
|
||||
* [Technical docs](docs/README.md) — architecture and reference
|
||||
|
||||
## Related Projects
|
||||
|
||||
Other POSIX-ish shells implemented in non-C/C++ languages:
|
||||
|
||||
* [`nushell`](https://www.nushell.sh/) — modern Rust shell (provides `reedline`)
|
||||
* [`fish`](https://fishshell.com) — user-friendly shell ([Rust port in 4.0](https://fishshell.com/blog/rustport/))
|
||||
* [`Oils`](https://github.com/oils-for-unix/oils) — bash-compatible with new Oil language
|
||||
* [`mvdan/sh`](https://github.com/mvdan/sh) — Go implementation
|
||||
* [`rusty_bash`](https://github.com/shellgei/rusty_bash) — another Rust bash-like shell
|
||||
|
||||
<details>
|
||||
<summary><b>🙏 Credits</b></summary>
|
||||
|
||||
This project relies on many excellent OSS crates:
|
||||
|
||||
* [`reedline`](https://github.com/nushell/reedline) — readline-like input and interactive features
|
||||
* [`clap`](https://github.com/clap-rs/clap) — command-line parsing
|
||||
* [`fancy-regex`](https://github.com/fancy-regex/fancy-regex) — regex support
|
||||
* [`tokio`](https://github.com/tokio-rs/tokio) — async runtime
|
||||
* [`nix`](https://github.com/nix-rust/nix) — Unix/POSIX APIs
|
||||
* [`criterion.rs`](https://github.com/bheisler/criterion.rs) — benchmarking
|
||||
* [`bash-completion`](https://github.com/scop/bash-completion) — completion test suite
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
Licensed under the [MIT license](LICENSE).
|
||||
This fork is distributed under the same [MIT license](LICENSE) as upstream; the
|
||||
copyright notice is unchanged. Upstream's [community
|
||||
guidelines](CODE_OF_CONDUCT.md) and [contribution
|
||||
guidelines](CONTRIBUTING.md) are vendored here and describe *upstream's* process —
|
||||
follow them there, not in this repository.
|
||||
|
||||
Reference in New Issue
Block a user