zinit 0.3.9

Process supervisor with dependency management
Documentation
# ADR-005: Enable Xinet Socket Activation Proxy

## Status

Implemented (2026-01-08)

## Context

Xinet is a socket activation proxy similar to xinetd/systemd socket activation. It:
- Listens on frontend sockets (TCP and/or Unix)
- On first connection, starts the backend service if not running
- Forwards traffic bidirectionally to the backend socket
- Can auto-stop the service after an idle timeout

The xinet implementation already exists in zinit-server but is not enabled:
- `zinit-server/src/xinet/` - Full proxy implementation (~600 lines)
- `zinit-common/src/xinet.rs` - Shared types (XinetConfig, ProxyStatus)
- `zinit-server/src/ipc.rs` - RPC handlers exist but return "xinet not enabled"

The server currently sets `xinet_manager = None` in main.rs, disabling all functionality.

## Decision

Enable xinet and expose it through all client interfaces (CLI, REPL, Rhai).

## Implementation

### Phase 1: Enable XinetManager in Server

**File: `zinit-server/src/main.rs`**

Create service callbacks and wire up XinetManager:

```rust
use zinit_server::xinet::{XinetManager, StartServiceFn, StopServiceFn, IsRunningFn};

// Clone graph for xinet is_running callback
let xinet_graph = Arc::clone(&graph);

// Create command senders for xinet callbacks
let xinet_start_tx = command_tx.clone();
let xinet_stop_tx = command_tx.clone();

// Start service callback
let start_service: StartServiceFn = Arc::new(move |name: &str| {
    xinet_start_tx
        .blocking_send(IpcCommand::StartService { name: name.to_string() })
        .is_ok()
});

// Stop service callback
let stop_service: StopServiceFn = Arc::new(move |name: &str| {
    xinet_stop_tx
        .blocking_send(IpcCommand::StopService { name: name.to_string() })
        .is_ok()
});

// Check if service is running
let is_running: IsRunningFn = Arc::new(move |name: &str| {
    // Check graph state for Running status
    ...
});

let xinet_manager = Some(Arc::new(XinetManager::new(start_service, stop_service, is_running)));
```

### Phase 2: Add Client Methods

**Blocking Client (`zinit-common/src/client.rs`):**
- `xinet_register(config: &XinetConfig)` - Register proxy
- `xinet_unregister(name: &str)` - Unregister proxy
- `xinet_list()` - List proxy names
- `xinet_status(name: &str)` - Get proxy status
- `xinet_status_all()` - Get all proxy statuses

**Async Client (`zinit-common/src/async_client.rs`):**
- Same methods with async signatures

### Phase 3: Add CLI Commands

**New subcommand: `zinit xinet`**

```bash
# Register a proxy
zinit xinet register myproxy \
  --listen unix:/tmp/frontend.sock \
  --listen tcp:127.0.0.1:8080 \
  --backend tcp:127.0.0.1:5432 \
  --service postgres \
  --idle-timeout 300

# Unregister
zinit xinet unregister myproxy

# List all proxies
zinit xinet list

# Show status
zinit xinet status myproxy
zinit xinet status  # all proxies
```

### Phase 4: Add REPL Support

Add to command completions:
- `xinet register`, `xinet unregister`, `xinet list`, `xinet status`

Add to Rhai function completions:
- `zinit_xinet_register`, `zinit_xinet_unregister`, `zinit_xinet_list`, `zinit_xinet_status`, `zinit_xinet_status_all`

### Phase 5: Add Rhai Functions

```rhai
// List all proxies
let proxies = zinit_xinet_list();

// Register a proxy
zinit_xinet_register("myproxy", "tcp:8080", "tcp:5432", "postgres");

// Get status
let status = zinit_xinet_status("myproxy");
print(`Active connections: ${status.active_connections}`);

// Unregister
zinit_xinet_unregister("myproxy");
```

## Files Modified

| File | Changes |
|------|---------|
| zinit-server/src/main.rs | Enable XinetManager with callbacks |
| zinit-common/src/client.rs | Add 5 xinet methods |
| zinit-common/src/async_client.rs | Add 5 async xinet methods |
| zinit-client/src/cli/args.rs | Add Xinet command + XinetCommands enum |
| zinit-client/src/cli/commands.rs | Add 4 handlers + helpers |
| zinit-client/src/cli/mod.rs | Export XinetCommands |
| zinit-client/src/main.rs | Add Xinet dispatch |
| zinit-client/src/repl.rs | Add completions |
| zinit-client/src/rhai/engine.rs | Add 5 Rhai functions |

## Implementation Checklist

### Server
- [x] Import XinetManager types in zinit-server/src/main.rs
- [x] Create start_service callback function
- [x] Create stop_service callback function
- [x] Create is_running callback function
- [x] Create XinetManager with callbacks
- [x] Pass XinetManager to IPC server

### Blocking Client (zinit-common/src/client.rs)
- [x] Add xinet imports
- [x] Add xinet_register method
- [x] Add xinet_unregister method
- [x] Add xinet_list method
- [x] Add xinet_status method
- [x] Add xinet_status_all method

### Async Client (zinit-common/src/async_client.rs)
- [x] Add xinet imports
- [x] Add async xinet_register method
- [x] Add async xinet_unregister method
- [x] Add async xinet_list method
- [x] Add async xinet_status method
- [x] Add async xinet_status_all method

### CLI Args (zinit-client/src/cli/args.rs)
- [x] Add Xinet variant to Commands enum
- [x] Create XinetCommands enum with Register, Unregister, List, Status
- [x] Add all register arguments (name, listen, backend, service, timeouts, single)

### CLI Commands (zinit-client/src/cli/commands.rs)
- [x] Add xinet imports
- [x] Add parse_socket_addr helper
- [x] Add cmd_xinet_register handler
- [x] Add cmd_xinet_unregister handler
- [x] Add cmd_xinet_list handler
- [x] Add cmd_xinet_status handler
- [x] Add print_proxy_status helper

### CLI Module (zinit-client/src/cli/mod.rs)
- [x] Export XinetCommands

### Main Dispatch (zinit-client/src/main.rs)
- [x] Import XinetCommands
- [x] Add Commands::Xinet match arm with all subcommands

### REPL (zinit-client/src/repl.rs)
- [x] Add xinet commands to COMMANDS array
- [x] Add xinet command handling in execute_command

### Rhai Engine (zinit-client/src/rhai/engine.rs)
- [x] Add xinet imports
- [x] Add proxy_status_to_map helper function
- [x] Add parse_xinet_addr helper function
- [x] Register zinit_xinet_list function
- [x] Register zinit_xinet_status function
- [x] Register zinit_xinet_status_all function
- [x] Register zinit_xinet_register function
- [x] Register zinit_xinet_unregister function

### Verification
- [x] Build workspace: `cargo build --workspace`
- [x] Build client with features: `cargo build -p zinit-client --features full`
- [x] Test CLI help: `./target/debug/zinit xinet --help`
- [ ] Test with running server (manual)

## Consequences

### Positive
- Socket activation enables on-demand service startup
- Reduces resource usage for rarely-used services
- Idle timeout allows automatic cleanup
- Full integration with TUI, REPL, and Rhai scripting

### Negative
- Additional complexity in service management
- Proxy overhead for connections

### Use Cases
- Database connections (start postgres on first query)
- Development servers (start on HTTP request)
- Backup services (start on schedule trigger)
- Any service that should only run when needed