zinit 0.3.9

Process supervisor with dependency management
Documentation
# Zinit Rhai Scripting Guide

Zinit supports Rhai scripting for service automation. You can use Rhai scripts to programmatically manage services, automate deployment workflows, and orchestrate complex service dependencies.

## Quick Start

### 1. Using Shebang (Executable Scripts)

Create a script with the shebang header:

```bash
#!/usr/bin/env zinit
// Your Rhai script here
let factory = new ZinitFactory();
let z = factory.connect();
let services = z.list();
print("Services: " + services);
```

Make it executable and run it directly:

```bash
chmod +x script.rhai
./script.rhai
```

### 2. Using zinit Command

Run a single script:

```bash
zinit rhai script.rhai
```

Run all `.rhai` scripts in a directory (sorted alphabetically):

```bash
zinit rhai ./scripts/
```

This will execute all `.rhai` files in the directory in lexicographic order, useful for multi-step deployments.

## API Reference

### ZinitFactory

The factory creates connections to the zinit daemon.

```rhai
// Create a factory
let factory = new ZinitFactory();

// Configure and connect (fluent API)
let z = factory
    .socket("/custom/path.sock")  // Optional: custom socket path
    .log_level(2)                  // Optional: 0-3 (Silent, Minimal, Normal, Verbose)
    .connect();                    // Connect to daemon
```

### ZinitHandle

Once connected, you have a handle with these methods:

#### Service Management

```rhai
// List all services
let services = z.list();
for name in services {
    print(name);
}

// Get service status
let status = z.status("service-name");
print("State: " + status.state);      // inactive, blocked, starting, running, stopping, exited, failed
print("PID: " + status.pid);
print("Uptime: " + status.uptime);

// Control services
z.start("service-name");
z.stop("service-name");
z.restart("service-name");

// Signal service
z.kill("service-name", "SIGTERM");

// Create/delete services
let config = new ServiceConfig();
config.name = "my-service";
config.exec = "/usr/bin/my-app";
z.service_set(config);
z.service_delete("my-service");
```

#### Information Queries

```rhai
// Show dependency tree
let tree = z.tree();
print(tree);

// Explain why service is blocked
let why = z.why("blocked-service");
print("Blocked by: " + why);

// Get logs
let logs = z.logs(Some("service-name"), Some(100));
for log in logs {
    print(log);
}

// Get debug state
let debug = z.debug_state();
print(debug);
```

#### Xinet (Socket Activation)

```rhai
// Register proxy
let xinet_config = new XinetConfig();
xinet_config.name = "web-proxy";
xinet_config.listen = ["unix:/tmp/web.sock"];
xinet_config.backend = "tcp:127.0.0.1:8080";
xinet_config.service = "web-app";
z.xinet_set(xinet_config);

// Check proxy status
let status = z.xinet_status(Some("web-proxy"));
print("Proxy status: " + status);

// Delete proxy
z.xinet_delete("web-proxy");
```

## Examples

### Example 1: Simple Health Check

```bash
#!/usr/bin/env zinit
let z = new ZinitFactory().connect();
let services = z.list();

for service in services {
    let status = z.status(service);
    if status.state != "running" {
        print("WARNING: " + service + " is not running!");
    }
}
```

### Example 2: Deployment Pipeline

Scripts in a directory are executed in order (alphabetically sorted):

```
scripts/
  01-backup.rhai       # Backup current state
  02-stop-services.rhai # Stop services
  03-deploy.rhai        # Deploy new code
  04-start-services.rhai # Start services
  05-verify.rhai        # Verify deployment
```

Run with:

```bash
zinit rhai scripts/
```

### Example 3: Conditional Service Management

```bash
#!/usr/bin/env zinit
let z = new ZinitFactory().log_level(2).connect();

// Only start services if they're not already running
let services = z.list();
for service in services {
    let status = z.status(service);
    if status.state == "inactive" {
        print("Starting " + service);
        z.start(service);
    }
}
```

### Example 4: Service Configuration Builder

```bash
#!/usr/bin/env zinit
let z = new ZinitFactory().connect();

// Create a new service
let config = new ServiceConfig();
config.name = "database";
config.exec = "/usr/bin/postgres -D /var/lib/postgres";
config.dir = "/var/lib/postgres";
config.restart = "on-failure";
config.restart_delay_ms = 5000;

z.service_set(config);
print("Created service: database");

// Verify
let status = z.status("database");
print("Service state: " + status.state);
```

## Features

- **Shebang Support**: Use `#!/usr/bin/env zinit` in scripts
-**Directory Execution**: Run all `.rhai` files in a directory, sorted
-**Shebang Stripping**: Shebang lines are automatically removed before execution
-**Error Handling**: Failed scripts report errors with file paths
-**Fluent API**: Chain method calls for configuration
-**Type Safety**: Full Rhai type system with zinit types
-**Logging Levels**: 4 levels of logging control (Silent to Verbose)

## Technical Details

### Script Execution Model

1. Scripts are loaded from file or directory
2. Shebang line (`#!/usr/bin/env zinit`) is stripped if present
3. Each script creates its own ZinitFactory and connects independently
4. Scripts are executed in alphabetical order when a directory is provided
5. Errors in one script stop execution of subsequent scripts

### Type System

All Rhai scripts use zinit SDK types:
- `State` - enum: Inactive, Blocked, Starting, Running, Stopping, Exited, Failed
- `Status` - enum: Start, Stop, Ignore
- `ServiceClass` - enum: User, System
- `RestartPolicy` - enum: Always, OnFailure, Never
- `ServiceConfig`, `ServiceDef`, `DependencyDef`, etc.

### Socket Configuration

By default, zinit looks for the socket at:
- Linux: `/run/zinit/zinit.sock`
- macOS/Darwin: `$HOME/.zinit/socket`

Override with `socket()` method on ZinitFactory.

## Troubleshooting

### Script won't execute as shebang

Ensure the file is executable:

```bash
chmod +x script.rhai
```

And the shebang line is exact:

```bash
#!/usr/bin/env zinit
```

### Connection fails

Check that:
1. zinit-server is running: `pgrep zinit-server`
2. Socket path is correct: `ls -la /run/zinit/socket`
3. User has permission to socket file

### Script errors

Use the verbose logging flag to debug:

```rhai
let z = new ZinitFactory()
    .log_level(3)  // Maximum verbosity
    .connect();
```

## Performance

- Scripts that list all services: O(n) where n is number of services
- Status queries are fast (single RPC call)
- Log retrieval depends on log size
- Directory execution processes files sequentially