rhai-process 0.1.1

Expose safe process-execution helpers to Rhai scripts.
Documentation
# rhai-process

## Overview
`rhai-process` is a Rust crate that lets Rhai scripts execute external processes in an OS-agnostic and safe way. It focuses on structured array-based commands so CLI/DSL apps can expose a consistent execution interface.

## Rhai Script
```rhai
let result = cmd(["ls"])
                .pipe(cmd(["grep", "Cargo.toml"]))
                .build()
                .run();

if result.success {
    print(result.stdout);
}
```

## Rust Source
```rust
use rhai::packages::Package;
use rhai::{Engine, EvalAltResult};
use rhai_process::{Config, ProcessPackage};

fn main() -> Result<(), Box<EvalAltResult>> {
    let mut engine = Engine::new();

    let package = ProcessPackage::new(Config::default());
    package.register_into_engine(&mut engine);

    let contents = engine.eval::<String>(r#"
        let result = cmd(["ls"])
                        .pipe(cmd(["grep", "Cargo.toml"]))
                        .build()
                        .run();

        if result.success {
            result.stdout
        }
    "#)?;
    println!("{}", contents);
    Ok(())
}
```

## Config
Host applications use `Config` to control what Rhai scripts may execute.

| Option | Description |
| ------ | ----------- |
| `allow_commands([...])` / `deny_commands([...])` | Whitelist or blacklist executable names (mutually exclusive). When unspecified, all commands are allowed. |
| `allow_env_vars([...])` / `deny_env_vars([...])` | Restrict which environment-variable keys scripts may override (mutually exclusive). Unset means all keys are allowed. |
| `default_timeout_ms(ms)` | Default timeout in milliseconds. Zero or negative values are rejected. Call `Executor::timeout(ms)` to override per pipeline. |

> Every `CommandBuilder` consults this policy before launching. Violations raise an immediate Rhai error and the external process is never started.

## CommandBuilder
```rhai
  let run = cmd(["cargo", "build"])
                .env(#{ "RUSTFLAGS": "-Dwarnings" })
                .build()
                .cwd(repo_dir);
```
| Method | Description |
| ------ | ----------- |
| `cmd([cmd, opt, ...])` | Create a builder by passing the program name and arguments as an array. |
| `env(map)` / `env_var(key, value)` | Inject environment variables (collectively or individually). Keys must be allowed by `Config`. |
| `pipe(other_builder)` | Append another `CommandBuilder` via a pipe and return a `PipeBuilder`. |
| `build()` | Turn this single command into an `Executor`, which exposes timeout/exit-code controls and `run()`. |

## PipeBuilder
| Method | Description |
| ------ | ----------- |
| `pipe(other_builder)` | Attach another command to the current pipeline. |
| `build()` | Convert the pipeline into an `Executor`. |

## Executor
| Method | Description |
| ------ | ----------- |
| `timeout(ms)` | Override the pipeline-wide timeout in milliseconds (`Config::default_timeout_ms` is used otherwise). |
| `cwd(path)` | Set the working directory for the entire pipeline. |
| `allow_exit_codes(array)` | Treat the listed exit codes as successes. |
| `run()` | Execute the pipeline and return `#{ success, status, stdout, stderr, duration_ms }`. |
| `run_stream(stdout_fn?, stderr_fn?)` | Stream stdout/stderr in real time (defaults to printing directly) and return the same result map. `stdout` / `stderr` in the result are empty strings. |

## Handling results
- `run()` (or `run_stream()`) is the terminal API. Both return `#{ success, status, stdout, stderr, duration_ms }`; check `success` (or inspect `stderr`) and raise your own error if needed. `run_stream()` streams stdout/stderr directly, so the `stdout`/`stderr` fields in the result are empty strings.

## License
Dual-licensed under MIT or Apache-2.0.