Metadata-Version: 2.4
Name: bgo-cli
Version: 0.2.0
Summary: Lightweight, zero-dependency background process manager (pm2-style) with watch mode and auto-restart.
Project-URL: Homepage, https://github.com/tcsenpai/bgo
Project-URL: Repository, https://github.com/tcsenpai/bgo
Project-URL: Issues, https://github.com/tcsenpai/bgo/issues
Project-URL: Changelog, https://github.com/tcsenpai/bgo/commits/main
Author-email: tcsenpai <tcsenpai@discus.sh>
License-Expression: MIT
License-File: LICENSE
Keywords: background,cli,daemon,pm2,process-manager,supervisor,watchdog
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: twine>=4.0; extra == 'dev'
Description-Content-Type: text/markdown

# bgo - Background Go

Lightweight, zero-dep background process manager inspired by pm2.
Detach any binary or script from your shell with one command.

## Features

- 🚀 **Simple syntax** — `bgo <name> -- <command>`
- 🐧 **Unix-style aliases** — `bgo open` / `kill` / `rm` / `ls`
- 📊 **Status monitoring** — CPU, memory, uptime in plain / normal / fancy tables (auto-detect)
- 📝 **Log management** — stdout / stderr / watcher logs with follow mode
- 🔄 **Lifecycle** — start, stop, restart, restart-stopped, restart-last, resurrect
- 👁 **Watch mode** — auto-restart crashed processes with fast-crash backoff
- 🧹 **Auto-cleanup** — clean stopped procs; keep logs on delete if desired
- 🤖 **Scriptable** — `--json` output for any pipeline
- ⚡ **Zero runtime dependencies** — pure Python 3.9+

## Installation

```bash
# Via PyPI
pip install bgo-cli
# or
pipx install bgo-cli
# or
uv tool install bgo-cli

# Via the install script (system-wide, needs sudo)
./install.sh

# User-local (~/.local/bin, no sudo)
./install.sh --local

# Or manually — bgo is a single file
cp bgo ~/.local/bin/   # or /usr/local/bin/
ln -s "$(pwd)/bgo" ~/.local/bin/bgo
```

Run `./install.sh --help` for `--force` and `--uninstall` options.

## Quick Start

```bash
# Start a process
bgo myserver -- python3 -m http.server 8080
bgo open myserver -- python3 -m http.server 8080   # alias

# Check status
bgo status        # full alias chain: status / ls / list
bgo ls

# Status detail for one proc (or: bgo <registered-name>)
bgo myserver

# View logs
bgo logs myserver
bgo logs myserver -f        # follow (tail -f)
bgo follow myserver         # alias for logs -f

# Stop / restart / delete
bgo stop myserver           # or: bgo kill myserver
bgo restart myserver
bgo delete myserver         # or: bgo rm myserver
bgo rm myserver --keep-logs # preserve log files

# Bare `bgo` prints help; `bgo <unknown>` errors out (never silently spawns)
bgo
```

## Commands

### Lifecycle

| Command | Description |
|---|---|
| `bgo start <name> -- <cmd>` | Start a process (alias: `open`) |
| `bgo <name> -- <cmd>` | Shorthand for start |
| `bgo stop <name>` | Stop (SIGTERM, alias: `kill`) |
| `bgo stop <name> -f` | Force kill (SIGKILL) |
| `bgo restart <name>` | Restart; preserves watch state and counters |
| `bgo restart <name> --reset-counters` | Also zero `watch.restarts` |
| `bgo restart-stopped` | Pick stopped procs to restart (interactive) |
| `bgo restart-stopped --all` | Restart every stopped proc |
| `bgo restart-stopped <name>...` | Restart named stopped procs |
| `bgo restart-last` | Menu sorted most-recent-first |
| `bgo restart-last --all` | Restart all not-running procs in recent order |
| `bgo resurrect` | Restart all procs that were running before shutdown |
| `bgo delete <name>` | Remove proc + logs (alias: `rm`) |
| `bgo delete <name> --keep-logs` | Remove proc, keep logs |
| `bgo clean` | Drop all stopped procs from the list |

### Inspection

| Command | Description |
|---|---|
| `bgo status` | Process table (alias: `ls`, `list`) |
| `bgo status <name>` | Detail view for one proc |
| `bgo status -w` | Watch mode (auto-refresh every 2s) |
| `bgo status -w --interval N` | Custom refresh interval |
| `bgo status --json` | Machine-readable output |
| `bgo status --plain` | ASCII-only output (no color, no glyphs) |
| `bgo status --fancy` | Force Unicode box-drawing rendering |
| `bgo <registered-name>` | Shorthand for `bgo status <name>` |
| `bgo logs <name>` | Last 50 lines |
| `bgo logs <name> -f` | Follow logs |
| `bgo logs <name> -n 100` | Last 100 lines |
| `bgo logs <name> --stderr` | Only stderr |
| `bgo logs <name> --watcher` | Watcher event log |
| `bgo follow <name>` | Alias for `logs -f` (also: `tail`) |

### Watch mode

| Command | Description |
|---|---|
| `bgo start -w <name> -- <cmd>` | Start with watcher attached |
| `bgo -w <name> <cmd>` | Direct mode with watcher |
| `bgo watch <name>` | Attach watcher to a running proc |
| `bgo watch <name> --interval N --min-uptime N --on-fast-crash MODE` | Tune |
| `bgo unwatch <name>` | Detach watcher, keep proc |

## Examples

```bash
# Python HTTP server
bgo web -- python3 -m http.server 8080

# Node.js app with watcher
bgo -w api -- npm start

# Custom binary with working directory
bgo start dashboard --cwd /opt/app -- node server.js

# Inspect one proc
bgo web

# Scripted: stop every online proc via JSON
bgo status --json | python3 -c '
import json, sys, subprocess
for p in json.load(sys.stdin):
    if p["status"] == "online":
        subprocess.run(["bgo", "stop", p["name"]])
'
```

## Status Table

The table auto-detects terminal capabilities and picks the best rendering:

| Level | Trigger | What you get |
|---|---|---|
| `plain` | non-TTY (pipes, CI logs), `TERM=dumb`, or `--plain` | ASCII only, no color, no glyphs |
| `normal` | TTY without UTF-8 locale | ANSI color + ASCII rules |
| `fancy` | TTY + UTF-8 locale (default) | ANSI color + Unicode box-drawing |

Override with `--plain` / `--fancy` or `BGO_TABLE=plain|normal|fancy`.

Sample (fancy):
```
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ NAME         STATUS     PID      CPU    MEM    UPTIME    WATCH      COMMAND                    ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ web          ● online   12345    2.5    0.1    00:05     ✓ 0        python3 -m http.server 8080 ┃
┃ api          ● online   12346    0.0    0.0    01:23     ✓ 3        node server.js              ┃
┃ worker       ○ stopped  -        -      -      -         ⚠ errored  python3 worker.py           ┃
┃ batch        ● online   12347    0.0    0.0    02:11     ·          ./batch                     ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
Total: 4 | ● online: 3 | ○ stopped: 1

⚠ 1 errored:
   worker — 4 consecutive fast-crashes
     bgo logs worker --watcher   |   bgo restart worker
```

CPU / MEM / uptime are pulled in a single batched `ps` call regardless of how many procs are running.

## Watch Mode

Watch mode runs a sidecar process per watched proc that polls the
target and restarts it on crash. State (restart count, error reason,
last stderr tail) is recorded in the proc JSON and surfaced via
`bgo status`.

### Quick start

```bash
bgo start -w myapi -- node server.js          # start with watcher
bgo -w myapi node server.js                   # direct-mode variant
bgo watch myapi                               # attach to a running proc
bgo watch myapi --interval 5 --min-uptime 3 --on-fast-crash backoff
bgo unwatch myapi                             # detach, keep proc
bgo logs myapi --watcher                      # inspect events
```

### Fast-crash policy

If a process dies before `--min-uptime` (default 2s) it's a *fast crash*. Reaction depends on `--on-fast-crash`:

| Mode | Behavior |
|---|---|
| `backoff` (default) | Wait 2s, retry. Then 4s, then 8s. After 4 consecutive fast-crashes, mark `errored` and exit watcher. |
| `stop` | Mark `errored` on the first fast-crash. |
| `retry` | Retry indefinitely, capped at 8s backoff. |

When a proc enters `errored`:
- WATCH column shows `⚠ errored` (or `[!] errored` in plain).
- Status footer summarizes errored procs and hints at the recovery commands.
- `bgo status <name>` detail shows the error reason and last stderr tail.
- `bgo restart <name>` clears the errored flag and re-spawns the watcher. Restart counter is **preserved** by default — use `--reset-counters` to zero it.

### Tunables

| Flag | Default | Notes |
|---|---|---|
| `--interval N` | 3 | Poll interval after the initial uptime window |
| `--min-uptime N` | 2 | Crash threshold; sub-window polled at high frequency |
| `--on-fast-crash MODE` | `backoff` | One of `backoff`, `stop`, `retry` |
| `--reset` | off | `bgo watch` only — reset prior watch config to defaults |

## Storage

- State: `~/.bgo/procs/<name>.json` — one file per process, written atomically (tmp + `os.replace`)
- Logs: `~/.bgo/logs/<name>.out.log`, `<name>.err.log`, `<name>.watcher.log`

## Testing

```bash
python3 -m pytest tests/ -v
```

54 tests covering state I/O, atomic writes, command-shape detection, name derivation, liveness + zombie filtering, watch-config inheritance, and table rendering across all three levels.

## Requirements

- Python 3.9+
- Linux or macOS (zombie detection is platform-aware: `/proc` on Linux, `ps -o stat=` on macOS)

## License

MIT
