From 53c44876fa1b8452209e0cf60aad6c6400ed0d82 Mon Sep 17 00:00:00 2001 From: resq-sw Date: Sun, 10 May 2026 04:51:18 +0000 Subject: [PATCH] docs(rust): sync API reference for master --- docs.json | 19 +- sdks/rust/api/README.mdx | 19 + sdks/rust/api/_pages.json | 13 + sdks/rust/api/resq-ai.md | 10 + sdks/rust/api/resq-bin.md | 377 +++++++++++++++++++ sdks/rust/api/resq-clean.md | 172 +++++++++ sdks/rust/api/resq-cli.md | 586 ++++++++++++++++++++++++++++++ sdks/rust/api/resq-deploy.md | 225 ++++++++++++ sdks/rust/api/resq-dsa.md | 449 +++++++++++++++++++++++ sdks/rust/api/resq-flame.md | 183 ++++++++++ sdks/rust/api/resq-health.md | 274 ++++++++++++++ sdks/rust/api/resq-logs.md | 193 ++++++++++ sdks/rust/api/resq-perf.md | 228 ++++++++++++ sdks/rust/api/resq-tui.md | 687 +++++++++++++++++++++++++++++++++++ 14 files changed, 3434 insertions(+), 1 deletion(-) create mode 100644 sdks/rust/api/README.mdx create mode 100644 sdks/rust/api/_pages.json create mode 100644 sdks/rust/api/resq-ai.md create mode 100644 sdks/rust/api/resq-bin.md create mode 100644 sdks/rust/api/resq-clean.md create mode 100644 sdks/rust/api/resq-cli.md create mode 100644 sdks/rust/api/resq-deploy.md create mode 100644 sdks/rust/api/resq-dsa.md create mode 100644 sdks/rust/api/resq-flame.md create mode 100644 sdks/rust/api/resq-health.md create mode 100644 sdks/rust/api/resq-logs.md create mode 100644 sdks/rust/api/resq-perf.md create mode 100644 sdks/rust/api/resq-tui.md diff --git a/docs.json b/docs.json index 28896b04..f0ffd786 100644 --- a/docs.json +++ b/docs.json @@ -5282,6 +5282,23 @@ ] } ] + }, + { + "group": "Rust", + "pages": [ + "sdks/rust/api/README", + "sdks/rust/api/resq-ai", + "sdks/rust/api/resq-bin", + "sdks/rust/api/resq-clean", + "sdks/rust/api/resq-cli", + "sdks/rust/api/resq-deploy", + "sdks/rust/api/resq-dsa", + "sdks/rust/api/resq-flame", + "sdks/rust/api/resq-health", + "sdks/rust/api/resq-logs", + "sdks/rust/api/resq-perf", + "sdks/rust/api/resq-tui" + ] } ] } @@ -5585,4 +5602,4 @@ "website": "https://resq.software" } } -} +} \ No newline at end of file diff --git a/sdks/rust/api/README.mdx b/sdks/rust/api/README.mdx new file mode 100644 index 00000000..c50c4934 --- /dev/null +++ b/sdks/rust/api/README.mdx @@ -0,0 +1,19 @@ +# ResQ Rust SDK + +Auto-generated reference for [`resq-software/crates`](https://github.com/resq-software/crates) at ref `master`. + +Each entry below lists a crate published from the workspace. Click through for the README plus a link to the canonical [docs.rs](https://docs.rs) API reference. + +## Crates + +- `resq-ai` — `v0.1.0` +- `resq-bin` — `v0.1.16` +- `resq-clean` — `v0.1.16` +- `resq-cli` — `v0.3.0` +- `resq-deploy` — `v0.1.16` +- `resq-dsa` — `v0.1.3` +- `resq-flame` — `v0.1.16` +- `resq-health` — `v0.1.16` +- `resq-logs` — `v0.1.16` +- `resq-perf` — `v0.1.16` +- `resq-tui` — `v0.1.8` diff --git a/sdks/rust/api/_pages.json b/sdks/rust/api/_pages.json new file mode 100644 index 00000000..de70c342 --- /dev/null +++ b/sdks/rust/api/_pages.json @@ -0,0 +1,13 @@ +[ + "resq-ai", + "resq-bin", + "resq-clean", + "resq-cli", + "resq-deploy", + "resq-dsa", + "resq-flame", + "resq-health", + "resq-logs", + "resq-perf", + "resq-tui" +] diff --git a/sdks/rust/api/resq-ai.md b/sdks/rust/api/resq-ai.md new file mode 100644 index 00000000..2038ebc6 --- /dev/null +++ b/sdks/rust/api/resq-ai.md @@ -0,0 +1,10 @@ +# resq-ai + +> **Version:** `v0.1.0` · **License:** `Apache-2.0` · **Crate:** [crates.io](https://crates.io/crates/resq-ai) · **API docs:** [docs.rs](https://docs.rs/resq-ai/0.1.0) + +Multi-provider LLM abstraction for ResQ developer tools + +_No README.md in source repo._ + +See [docs.rs](https://docs.rs/resq-ai/0.1.0) for full API reference. + diff --git a/sdks/rust/api/resq-bin.md b/sdks/rust/api/resq-bin.md new file mode 100644 index 00000000..c4d75389 --- /dev/null +++ b/sdks/rust/api/resq-bin.md @@ -0,0 +1,377 @@ +# resq-bin + +> **Version:** `v0.1.16` · **License:** `Apache-2.0` · **Crate:** [crates.io](https://crates.io/crates/resq-bin) · **API docs:** [docs.rs](https://docs.rs/resq-bin/0.1.16) + +Binary and machine-code analyzer for ResQ binaries + +## Overview + +[![Crates.io](https://img.shields.io/crates/v/resq-bin.svg)](https://crates.io/crates/resq-bin) +[![License](https://img.shields.io/crates/l/resq-bin.svg)](LICENSE) + +Binary and machine-code analyzer for the ResQ platform. Provides deep inspection of ELF, Mach-O, and PE object files with interactive TUI exploration, Capstone-powered disassembly with objdump fallback, symbol and section analysis, and a persistent CRC32-based cache for fast repeated analysis of large binaries. + +## Capabilities + +- **Multi-format binary parsing** -- ELF, Mach-O, PE, and WASM via the `object` crate. +- **Dual disassembly backends** -- Capstone for high-quality instruction decoding (x86_64, AArch64), with automatic fallback to `llvm-objdump`/`objdump` for missing functions. +- **Interactive TUI** -- Three-pane terminal interface (Targets, Functions, Disassembly) with regex search, function filtering, and keyboard navigation. +- **CLI output modes** -- Human-readable plain text and structured JSON for CI pipelines and tooling integration. +- **Smart caching** -- Persistent analysis cache keyed on file path, size, modification time, and analysis options. Falls back to CRC32 content hashing when mtime is unavailable. +- **Batch analysis** -- Recursive directory scanning with extension filtering for analyzing entire build output trees. +- **Read-only operation** -- Never mutates inspected binaries. + +## Architecture + +```mermaid +flowchart TB + subgraph Input + A[Single File
--file] --> C[BinaryAnalyzer] + B[Directory
--dir --recursive] --> D[Directory Walker] + D --> C + end + + subgraph Parsing ["Parsing (object crate)"] + C --> E[Format Detection
ELF / Mach-O / PE / WASM] + E --> F[Section Extraction] + E --> G[Symbol Collection] + E --> H[Function Discovery
text section symbols] + end + + subgraph Disassembly + H --> I{Capstone
x86_64 / AArch64} + I -->|Success| J[Instruction Decode] + I -->|Failure or gaps| K{objdump Fallback
llvm-objdump / objdump} + K -->|Success| L[Parse objdump Output] + K -->|Failure| M[Warnings] + J --> N[Merge Results] + L --> N + end + + subgraph Cache ["Cache System (.cache/resq/bin-explorer)"] + C <-->|Check / Store| O[CRC32 Cache Key
path + size + mtime + options] + O <--> P[(JSON Cache Files)] + end + + subgraph Output + N --> Q[BinaryReport] + F --> Q + G --> Q + Q --> R{Output Mode} + R -->|--tui / default TTY| S[Interactive TUI
Ratatui + Crossterm] + R -->|--plain| T[Human-readable Text] + R -->|--json| U[Structured JSON] + end +``` + +## Installation + +```bash +# Build from the workspace root +cargo build --release -p resq-bin + +# Binary is placed at: +# target/release/resq-bin + +# Or install directly +cargo install --path resq-bin +``` + +### System Requirements + +- **Rust**: Latest stable toolchain. +- **Capstone**: The `capstone` crate bundles its own copy; no system library required. +- **objdump** (optional): `llvm-objdump` or `objdump` on `PATH` enables the fallback disassembly backend. Analysis works without it, but some functions may lack disassembly when Capstone cannot decode them. + +## CLI Reference + +### Arguments + +| Flag | Default | Description | +|------|---------|-------------| +| `--file ` | -- | Analyze a single binary file. Mutually exclusive with `--dir`. | +| `--dir ` | -- | Analyze all object-like files under a directory. Mutually exclusive with `--file`. | +| `--recursive` | `false` | Recurse into subdirectories when using `--dir`. | +| `--ext ` | -- | Filter files by suffix in `--dir` mode (e.g., `.so`, `.o`). | +| `--no-disasm` | `false` | Skip disassembly; collect only metadata (sections, symbols, entry point). | +| `--max-functions ` | `40` | Maximum number of functions to disassemble per binary. | +| `--config ` | `.resq-bin-explorer.toml` | Path to a TOML configuration file. | +| `--no-cache` | `false` | Disable the result cache entirely (no reads or writes). | +| `--rebuild-cache` | `false` | Ignore existing cache entries and re-analyze all targets. New results are still cached. | +| `--tui` | -- | Force interactive TUI mode. Mutually exclusive with `--json` and `--plain`. | +| `--plain` | `false` | Emit a human-readable non-interactive report. Mutually exclusive with `--json` and `--tui`. | +| `--json` | `false` | Emit a structured JSON report. Mutually exclusive with `--plain` and `--tui`. | + +When none of `--tui`, `--plain`, or `--json` is specified, the output mode is determined automatically: TUI if stdout is a terminal, plain text otherwise. + +## Usage Examples + +### Single file -- interactive TUI (default on a terminal) + +```bash +resq-bin --file target/release/resq +``` + +### Single file -- plain text report + +```bash +resq-bin --file target/release/resq --plain +``` + +Output: + +``` +scan: total=1 processed=1 failed=0 cache_hits=0 +== target/release/resq == +format=Elf arch=X86_64 endian=Little size=4521984B entry=0x5040 +sections=30 symbols=1842 functions=40 +disasm_backend=capstone attempts=capstone: ok +coverage: total=40 with_insn=40 capstone=40 objdump=0 missing=0 + + fn main @ 0x5040 size=128 insn=24 + fn _start @ 0x5000 size=47 insn=11 + ... +``` + +### Single file -- JSON output (for CI) + +```bash +resq-bin --file target/release/resq --json | jq '.stats' +``` + +```json +{ + "total": 1, + "processed": 1, + "failed": 0, + "cache_hits": 0 +} +``` + +### Directory scan -- recursive with extension filter + +```bash +resq-bin --dir target/release --recursive --ext .so --plain +``` + +### Batch analysis -- metadata only (fast) + +```bash +resq-bin --dir target/release --recursive --no-disasm --json > report.json +``` + +### Force TUI with a non-default config + +```bash +resq-bin --file my-service --tui --config my-config.toml +``` + +### Rebuild cache after recompilation + +```bash +resq-bin --dir target/release --recursive --rebuild-cache --plain +``` + +## TUI Mode + +The interactive TUI provides a three-pane layout for exploring binary analysis results. + +### Layout + +``` ++-- resq-bin -----------------------------------------------------------+ +| file: target/release/resq [ELF64 x86_64] | ++-----------------------------------------------------------------------+ +| TARGETS | FUNCTIONS | Summary | +| resq [Elf X86_64] | main [0x5040] insn=24 | file: target/release/.. | +| resq-bin [Elf ..] | _start [0x5000] insn=11| format=Elf arch=X86_64 | +| | +-------------------------+ +| | | Disassembly | +| | | 0x5040 push rbp | +| | | 0x5041 mov rbp, rsp | ++-----------------------------------------------------------------------+ +| Q Quit | Tab Focus | / Fn Filter | ? Regex | N Jump | H Help | Normal| ++-----------------------------------------------------------------------+ +``` + +### Keyboard Shortcuts + +| Key | Action | +|-----|--------| +| `q` / `Esc` | Quit the TUI | +| `Tab` | Cycle focus forward: Targets -> Functions -> Disassembly | +| `Shift+Tab` | Cycle focus backward | +| `Left` / `Right` | Switch focus between panes | +| `Up` / `k` | Navigate up in the focused pane | +| `Down` / `j` | Navigate down in the focused pane | +| `Page Up` | Scroll disassembly up by 12 lines | +| `Page Down` | Scroll disassembly down by 12 lines | +| `Home` | Scroll disassembly to top | +| `/` | Open function substring filter dialog | +| `?` | Open disassembly regex search dialog (case-insensitive) | +| `c` | Clear the active function filter | +| `n` | Jump to next match (function filter or disassembly regex) | +| `N` | Jump to previous match | +| `h` | Toggle help overlay | + +## Cache System + +resq-bin maintains a persistent cache of analysis results to avoid redundant heavy disassembly work on unchanged binaries. + +### Cache Location + +The default cache directory is `.cache/resq/bin-explorer` relative to the working directory. This can be overridden with the `cache_dir` key in the configuration file. + +### Cache Key Computation + +Each cache entry is keyed by a CRC32 hash of a fingerprint string that includes: + +1. **Protocol version** (`v5`) -- cache is automatically invalidated on schema changes. +2. **Canonical file path** -- absolute path to the binary. +3. **File size** -- byte length from filesystem metadata. +4. **Analysis options** -- disassembly enabled/disabled, max functions, max symbols, max instructions per function. +5. **Modification time** -- nanosecond-precision mtime when available. +6. **Content CRC32** -- full file content hash as a fallback when mtime is unavailable (e.g., some network filesystems). + +### Cache Behavior + +| Scenario | Behavior | +|----------|----------| +| Default | Read from cache on hit; write new entries after analysis. | +| `--no-cache` | Bypass cache entirely. No reads, no writes. | +| `--rebuild-cache` | Ignore existing entries but write fresh results. | +| Binary recompiled | Cache miss (mtime or size changed); automatic re-analysis. | +| Options changed | Cache miss (different max_functions, disasm toggle, etc.). | + +### Cache Storage Format + +Each entry is stored as a JSON file named `{crc32_hex}.json` containing the full `BinaryReport` structure. + +## Configuration File + +resq-bin reads an optional TOML configuration file. By default it looks for `.resq-bin-explorer.toml` in the current directory, or you can specify a path with `--config`. + +### Format + +```toml +# All fields are optional. CLI flags override config values. + +# Recurse into subdirectories in --dir mode +recursive = true + +# Filter files by extension +ext = ".so" + +# Disable disassembly (metadata only) +no_disasm = false + +# Maximum functions to disassemble per binary +max_functions = 60 + +# Output mode: "tui", "plain", or "json" +output = "tui" + +# Disable cache +no_cache = false + +# Force cache rebuild +rebuild_cache = false + +# Custom cache directory +cache_dir = "/tmp/resq-cache" +``` + +CLI flags always take precedence over configuration file values. + +## JSON Output Format + +The `--json` flag emits a single JSON object with three top-level fields: + +```json +{ + "stats": { + "total": 5, + "processed": 4, + "failed": 1, + "cache_hits": 2 + }, + "reports": [ + { + "path": "target/release/resq", + "format": "Elf", + "architecture": "X86_64", + "endianness": "Little", + "entry": 20544, + "size_bytes": 4521984, + "sections": [ + { "name": ".text", "address": 4096, "size": 1048576, "kind": "Text" } + ], + "symbols": [ + { "name": "main", "address": 20544, "size": 128, "kind": "Text", "is_global": true } + ], + "functions": [ + { + "name": "main", + "address": 20544, + "size": 128, + "instructions": [ + { "address": 20544, "text": "push rbp" }, + { "address": 20545, "text": "mov rbp, rsp" } + ] + } + ], + "disassembly_backend": "capstone", + "disassembly_attempts": ["capstone: ok"], + "disassembly_coverage": { + "total_functions": 40, + "functions_with_instructions": 40, + "capstone_functions": 40, + "objdump_functions": 0, + "missing_functions": 0 + }, + "function_backend_coverage": [ + { "name": "main", "backend": "capstone", "instruction_count": 24 } + ], + "warnings": [] + } + ], + "issues": [ + { "path": "target/release/build-script", "error": "failed to parse object file" } + ] +} +``` + +### Field Reference + +| Field | Type | Description | +|-------|------|-------------| +| `stats.total` | integer | Number of files considered for analysis. | +| `stats.processed` | integer | Number of files successfully analyzed. | +| `stats.failed` | integer | Number of files that produced errors. | +| `stats.cache_hits` | integer | Number of results served from cache. | +| `reports[].format` | string | Object file format (`Elf`, `Pe`, `MachO`, `Wasm`). | +| `reports[].architecture` | string | CPU architecture (`X86_64`, `Aarch64`, etc.). | +| `reports[].entry` | integer | Entrypoint virtual address. | +| `reports[].disassembly_backend` | string or null | Backend used: `capstone`, `objdump`, `capstone+objdump`, or null. | +| `reports[].disassembly_coverage` | object or null | Counts of functions decoded by each backend. | +| `issues[].path` | string | Path to the file that failed analysis. | +| `issues[].error` | string | Error message describing the failure. | + +## Source Layout + +``` +resq-bin/ + src/ + main.rs CLI entry point, argument parsing, mode selection + lib.rs Library root (re-exports analysis module) + tui.rs Interactive TUI (Ratatui + Crossterm) + cache.rs CRC32-based persistent cache system + analysis/ + mod.rs BinaryAnalyzer, Capstone/objdump backends, report types + Cargo.toml Crate manifest +``` + +## License + +Licensed under the Apache License, Version 2.0. See [LICENSE](http://www.apache.org/licenses/LICENSE-2.0) for details. + diff --git a/sdks/rust/api/resq-clean.md b/sdks/rust/api/resq-clean.md new file mode 100644 index 00000000..1c09e06f --- /dev/null +++ b/sdks/rust/api/resq-clean.md @@ -0,0 +1,172 @@ +# resq-clean + +> **Version:** `v0.1.16` · **License:** `Apache-2.0` · **Crate:** [crates.io](https://crates.io/crates/resq-clean) · **API docs:** [docs.rs](https://docs.rs/resq-clean/0.1.16) + +.gitignore-aware workspace cleaner for ResQ development + +## Overview + +[![Crates.io](https://img.shields.io/crates/v/resq-clean.svg)](https://crates.io/crates/resq-clean) +[![License](https://img.shields.io/crates/l/resq-clean.svg)](LICENSE) + +Interactive, `.gitignore`-aware workspace cleaner for ResQ development. Provides a TUI that scans for build artifacts and gitignored files, lets you select what to remove, and reclaims disk space safely. + +## Overview + +`resq-clean` walks the repository tree, applies `.gitignore` rules via the `ignore` crate (supporting negated patterns and nested `.gitignore` files), and presents every gitignored entry in an interactive list sorted by size. You can toggle individual items on or off before confirming deletion. + +## Cleanup Decision Tree + +```mermaid +flowchart TD + A[Launch resq-clean] --> B[Read .gitignore rules] + B --> C[Walk repository tree] + C --> D{For each path} + + D --> E{Is .git directory?} + E -->|Yes| F[Skip] + E -->|No| G{Matched by .gitignore?} + + G -->|No| F + G -->|Yes| H[Calculate size] + + H --> I[Add to entries list] + + I --> J[Sort entries by size descending] + J --> K[Display TUI] + + K --> L{User action} + L -->|Space| M[Toggle item selection] + M --> K + L -->|Up/Down| N[Navigate list] + N --> K + L -->|Enter| O{--dry-run?} + O -->|Yes| P[Exit without deleting] + O -->|No| Q[Delete selected items] + Q --> R[Re-scan workspace] + R --> K + L -->|q / Esc| S[Exit] +``` + +## Installation + +```bash +# From the workspace root +cargo build --release -p resq-clean + +# Binary location +target/release/resq-clean +``` + +## CLI Arguments + +| Flag | Default | Description | +|------|---------|-------------| +| `--dry-run` | `false` | Preview what would be deleted without removing anything. Pressing `Enter` in the TUI exits instead of deleting. | + +## Usage Examples + +### Interactive TUI (default) + +```bash +# Launch the cleanup TUI in the current directory +resq-clean +``` + +The TUI displays all gitignored files and directories sorted by size, with checkboxes. All items are selected by default. + +### Dry Run + +```bash +# Preview mode -- nothing is deleted +resq-clean --dry-run +``` + +In dry-run mode, pressing `Enter` exits the TUI without performing any deletions, letting you inspect what would be removed. + +### Targeted Cleanup + +```bash +# Run from a specific subdirectory +cd services/infrastructure-api && resq-clean +``` + +The scanner uses the current working directory as its root, so you can scope cleanup to a single service or library. + +## TUI Keybindings + +| Key | Action | +|-----|--------| +| `q` / `Esc` | Quit without deleting | +| `Space` | Toggle selection on the highlighted item | +| `Enter` | Delete all selected items (or exit in `--dry-run` mode) | +| `Up` / `k` | Move selection up | +| `Down` / `j` | Move selection down | + +## What Gets Deleted + +Anything matched by `.gitignore` rules, which typically includes: + +| Pattern | Description | +|---------|-------------| +| `target/` | Rust build output | +| `node_modules/` | npm/bun dependencies | +| `.next/` | Next.js build cache | +| `dist/` | TypeScript/Bun build output | +| `build/` | CMake build directories | +| `__pycache__/` | Python bytecode cache | +| `*.pyc` | Compiled Python files | +| `.pytest_cache/` | Pytest cache | +| `*.o`, `*.a`, `*.so` | C/C++ object files and libraries | +| `*.nettrace` | .NET profiling traces | +| `flamegraph.svg` | Generated flame graph profiles | + +Files matching negated gitignore entries (e.g., `!dist/keep-this.json`) are preserved automatically. + +## Environment Variables + +No environment variables are required. The tool operates entirely on the local filesystem using the current working directory as its root. + +## Output Format + +The TUI header displays the total size of all currently selected items (e.g., `PENDING: 2.4 GB`). Each entry in the list shows: + +``` +[x] +``` + +- `[x]` / `[ ]` -- selection checkbox +- Icon -- folder or file indicator +- Relative path -- path relative to the scan root +- Size -- human-readable size (B, KB, MB, GB) + +After deletion, the workspace is re-scanned and the list refreshes to reflect the current state. + +## Safety Notes + +- **Dry-run first**: Always use `--dry-run` on the first pass to review what will be removed. +- **Gitignore-only**: Only files and directories matched by `.gitignore` rules are candidates for deletion. Tracked files are never touched. +- **Negated patterns respected**: Entries matching negated patterns (e.g., `!important.log`) are excluded from the scan. +- **No .git deletion**: The `.git` directory and its contents are unconditionally skipped. +- **Interactive confirmation**: Nothing is deleted until you press `Enter` in the TUI. You can deselect individual items with `Space` before confirming. +- **Re-scan after deletion**: After deleting, the tool re-scans to show the updated state, so you can verify the results. +- **Directories removed recursively**: Selected directories are removed with `remove_dir_all`. Ensure you have deselected anything you want to keep. + +## When to Use + +- Before committing, to ensure no build artifacts slip through +- After switching branches, to avoid stale build caches +- Periodic deep clean when disk space is low + +For ecosystem-specific cleanup without the TUI: + +```bash +cargo clean # Rust only +rm -rf services/coordination-hce/node_modules # Node only +find . -type d -name __pycache__ -exec rm -rf {} + # Python only +``` + +## License + +Licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/resq-software/crates/blob/master/LICENSE) for details. + diff --git a/sdks/rust/api/resq-cli.md b/sdks/rust/api/resq-cli.md new file mode 100644 index 00000000..70e39b85 --- /dev/null +++ b/sdks/rust/api/resq-cli.md @@ -0,0 +1,586 @@ +# resq-cli + +> **Version:** `v0.3.0` · **License:** `Apache-2.0` · **Crate:** [crates.io](https://crates.io/crates/resq-cli) · **API docs:** [docs.rs](https://docs.rs/resq-cli/0.3.0) + +Developer CLI for the ResQ autonomous drone platform + +## Overview + +[![Crates.io](https://img.shields.io/crates/v/resq-cli.svg)](https://crates.io/crates/resq-cli) +[![License](https://img.shields.io/crates/l/resq-cli.svg)](LICENSE) + +Unified developer CLI for the ResQ platform. Provides commands for license header management, security auditing, secret scanning, dependency cost analysis, image placeholder generation, documentation export, monorepo versioning, and launching a suite of interactive TUI tools. + +## Overview + +`resq` is the single entry point for all ResQ developer tooling. It wraps standalone TUI applications (logs, health, deploy, perf, clean, asm) and provides built-in commands for CI workflows, pre-commit hooks, and repository maintenance. + +```mermaid +graph TD + resq["resq (CLI)"] + + resq --> copyright["copyright"] + resq --> lqip["lqip"] + resq --> audit["audit"] + resq --> cost["cost"] + resq --> secrets["secrets"] + resq --> tree_shake["tree-shake"] + resq --> pre_commit["pre-commit"] + + resq --> dev["dev"] + dev --> kill_ports["dev kill-ports"] + dev --> sync_env["dev sync-env"] + dev --> upgrade["dev upgrade"] + dev --> install_hooks["dev install-hooks"] + + resq --> version["version"] + version --> version_add["version add"] + version --> version_apply["version apply"] + version --> version_check["version check"] + + resq --> docs["docs"] + + resq --> explore["explore (resq-perf)"] + resq --> logs["logs (resq-logs)"] + resq --> health["health (resq-health)"] + resq --> deploy["deploy (resq-deploy)"] + resq --> clean["clean (resq-clean)"] + resq --> asm["asm (resq-bin)"] + + style resq fill:#2563eb,color:#fff + style dev fill:#7c3aed,color:#fff + style version fill:#7c3aed,color:#fff + style explore fill:#059669,color:#fff + style logs fill:#059669,color:#fff + style health fill:#059669,color:#fff + style deploy fill:#059669,color:#fff + style clean fill:#059669,color:#fff + style asm fill:#059669,color:#fff +``` + +**Legend:** Blue = entry point, Purple = commands with subcommands, Green = TUI launchers. + +## Installation + +```bash +# Build from the workspace root +cargo build --release -p resq-cli + +# Install globally +cargo install --path cli + +# Or use the cargo alias (defined in .cargo/config.toml) +cargo resq help +``` + +The binary is installed as `resq` at `target/release/resq`. + +### Cargo Aliases + +The following workspace aliases are defined in `.cargo/config.toml`: + +| Alias | Maps to | +| ----------------- | -------------------- | +| `cargo resq` | `resq` | +| `cargo health` | `resq health` | +| `cargo logs` | `resq logs` | +| `cargo perf` | `resq explore` | +| `cargo deploy` | `resq deploy` | +| `cargo cleanup` | `resq clean` | +| `cargo bin` | `resq asm` | +| `cargo check-all` | workspace check | +| `cargo t` | workspace test | +| `cargo c` | workspace clippy | +| `cargo flame` | `resq-flame` binary | + +--- + +## Commands + +### `copyright` -- License Header Management + +Adds or checks copyright/license headers across all source files in the repository. Supports multiple comment styles (C-style block, XML/HTML, hash-line, double-dash, Elisp, AsciiDoc). Shebangs (`#!/...`) are always preserved at line 0. + +#### Arguments + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `-l, --license ` | `String` | `apache-2.0` | License type: `apache-2.0`, `mit`, `gpl-3.0`, `bsd-3-clause` | +| `-a, --author ` | `String` | `ResQ` | Copyright holder name | +| `-y, --year ` | `String` | current year | Copyright year | +| `--force` | `bool` | `false` | Overwrite existing headers | +| `--dry-run` | `bool` | `false` | Preview changes without writing files | +| `--check` | `bool` | `false` | CI mode -- exits non-zero if any headers are missing | +| `-v, --verbose` | `bool` | `false` | Print detailed processing info | +| `--glob ...` | `Vec` | none | Glob patterns to match files (e.g. `src/**/*.rs`) | +| `--ext ` | `Vec` | none | Comma-separated file extensions to include (e.g. `rs,js,py`) | +| `-e, --exclude ...` | `Vec` | none | Patterns to exclude from processing | + +#### Examples + +```bash +# Check all tracked files (CI -- exits 1 if any missing) +resq copyright --check + +# Preview what would be added without writing +resq copyright --dry-run + +# Add headers to all files missing them +resq copyright + +# Overwrite existing headers with a different license and author +resq copyright --force --license apache-2.0 --author "Acme Corp" --year 2026 + +# Process only Rust and TypeScript files +resq copyright --ext rs,ts + +# Process files matching a glob pattern +resq copyright --glob "crates/**/*.rs" +``` + +--- + +### `lqip` -- Low-Quality Image Placeholders + +Generates tiny base64-encoded data URIs from images for use as blur-up placeholders in web applications. Supports JPEG, PNG, and WebP formats. + +#### Arguments + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `-t, --target ` | `String` | *required* | Directory or file to process | +| `--width ` | `u32` | `20` | Width of the generated LQIP in pixels | +| `--height ` | `u32` | `15` | Height of the generated LQIP in pixels | +| `-r, --recursive` | `bool` | `false` | Recursively search directories for images | +| `--format ` | `String` | `text` | Output format: `text` or `json` | + +#### Examples + +```bash +# Single image -- prints data URI +resq lqip --target hero.jpg + +# Directory of images -- text list +resq lqip --target public/images/ + +# Recursive with JSON output +resq lqip --target public/ --recursive --format json + +# Custom dimensions +resq lqip --target photo.png --width 32 --height 24 +``` + +--- + +### `audit` -- Security & Quality Audit + +Three-pass security and quality sweep covering all language ecosystems. Runs Google OSV Scanner (cross-ecosystem), npm audit-ci, and React Doctor. + +#### Arguments + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `--root ` | `PathBuf` | `.` | Root directory to start search from | +| `--level ` | `String` | `critical` | Minimum npm vulnerability severity to fail on (`critical`, `high`, `moderate`, `low`) | +| `--report-type ` | `String` | `important` | audit-ci report verbosity (`important`, `full`, `summary`) | +| `--skip-prepare` | `bool` | `false` | Skip the yarn.lock generation step required by audit-ci | +| `--skip-npm` | `bool` | `false` | Skip the npm audit-ci pass | +| `--skip-osv` | `bool` | `false` | Skip the Google OSV Scanner pass | +| `--osv-format ` | `String` | `table` | OSV Scanner output format (`table`, `json`, `sarif`, `gh-annotations`) | +| `--skip-react` | `bool` | `false` | Skip the react-doctor pass | +| `--react-target ` | `PathBuf` | `/services/web-dashboard` | Path to the React/Next.js project for react-doctor | +| `--react-diff ` | `String` | none | Only scan React files changed vs this base branch | +| `--react-min-score ` | `u8` | `75` | Minimum react-doctor health score to pass (0-100) | + +#### Examples + +```bash +# Full audit (all three passes) +resq audit + +# Run only the OSV Scanner pass +resq audit --skip-npm --skip-react + +# Strict npm audit (fail on moderate) +resq audit --skip-osv --skip-react --level moderate + +# OSV Scanner with JSON output +resq audit --skip-npm --skip-react --osv-format json + +# React Doctor with custom threshold and diff mode +resq audit --skip-osv --skip-npm --react-min-score 90 --react-diff main +``` + +--- + +### `cost` -- Dependency Size Analysis + +Fetches package sizes from registries (npm, crates.io, PyPI) and categorizes dependencies by download footprint into high (>10 MB), medium (1-10 MB), and low (<1 MB) buckets. Results are saved as JSON files. + +#### Arguments + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `--root ` | `PathBuf` | `.` | Root directory containing project manifest | +| `--output ` | `PathBuf` | `scripts/out` | Output directory for result JSON files | +| `--project-type ` | `String` | auto-detected | Force a specific project type: `node`, `rust`, `python` | + +#### Examples + +```bash +# Auto-detect project type and analyze +resq cost + +# Analyze a specific project directory +resq cost --root services/coordination-hce + +# Force Rust analysis and custom output +resq cost --project-type rust --output reports/deps +``` + +--- + +### `secrets` -- Secret Scanner + +Scans source files for hardcoded credentials, API keys, private keys, tokens, and high-entropy strings. Uses pattern matching with entropy analysis (Shannon entropy with charset-specific thresholds for hex, base64, and alphanumeric strings) and Aho-Corasick multi-pattern matching for performance. + +#### Arguments + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `--root ` | `PathBuf` | `.` | Root directory to scan | +| `--git-only` | `bool` | `true` | Only scan git-tracked files | +| `-v, --verbose` | `bool` | `false` | Show verbose output (print matched content) | +| `--allowlist ` | `PathBuf` | none | Path to allowlist file (one pattern per line) | +| `--staged` | `bool` | `false` | Scan only staged git changes (for pre-commit hook) | +| `--history` | `bool` | `false` | Also scan git history (all commits reachable from HEAD) | +| `--since ` | `String` | none | Limit history scan to commits after this rev/date (e.g. `"30 days ago"`, `"v1.0.0"`) | + +#### Examples + +```bash +# Scan all git-tracked files (default) +resq secrets + +# Only scan staged changes (pre-commit hook) +resq secrets --staged + +# Scan with history and allowlist +resq secrets --history --since "v1.0.0" --allowlist .secrets-allowlist + +# Verbose output showing matched content +resq secrets --verbose +``` + +--- + +### `tree-shake` -- TypeScript Dead Code Removal + +Runs [`tsr`](https://github.com/line/ts-remove-unused) to remove unused TypeScript exports from project entry points. Requires `bun` to be installed. + +#### Arguments + +This command takes no arguments. + +#### Examples + +```bash +resq tree-shake +``` + +--- + +### `dev` -- Development Utilities + +Unified entry point for repository-level development tasks. + +#### Subcommands + +##### `dev kill-ports` -- Kill Processes on Ports + +Finds and terminates processes listening on specified TCP ports. + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `...` | `Vec` | *required* | Ports or ranges (e.g. `8000` or `8000..8010`) | +| `-f, --force` | `bool` | `false` | Use SIGKILL instead of SIGTERM | +| `-y, --yes` | `bool` | `false` | Skip confirmation prompt | + +```bash +# Kill process on port 3000 +resq dev kill-ports 3000 + +# Kill range of ports without confirmation +resq dev kill-ports 8000..8010 --yes + +# Force kill +resq dev kill-ports 3000 --force +``` + +##### `dev sync-env` -- Sync Environment Variables to turbo.json + +Scans `.env.example` files across the monorepo and synchronizes discovered environment variable names into `turbo.json` task configurations. + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `-t, --tasks ` | `String` | `build,dev,start,test` | Comma-separated tasks to update in turbo.json | +| `-d, --dry-run` | `bool` | `false` | Preview changes without writing | +| `--max-depth ` | `usize` | `10` | Maximum directory depth to search | + +```bash +# Sync all environment variables +resq dev sync-env + +# Preview changes +resq dev sync-env --dry-run + +# Sync only for build and dev tasks +resq dev sync-env --tasks build,dev +``` + +##### `dev upgrade` -- Upgrade Dependencies + +Upgrades dependencies across all language silos in the monorepo (Python/uv, Rust/cargo, JS/bun, C++/Conan, C#/dotnet, Nix). + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `` | `String` | `all` | Silo to upgrade: `python`, `rust`, `js`, `cpp`, `csharp`, `nix`, or `all` | + +```bash +# Upgrade all ecosystems +resq dev upgrade + +# Upgrade only Rust dependencies +resq dev upgrade rust + +# Upgrade only JavaScript dependencies +resq dev upgrade js +``` + +##### `dev install-hooks` -- Install Git Hooks + +Configures `git core.hooksPath` to point at the `.git-hooks` directory and makes all hook scripts executable. + +```bash +resq dev install-hooks +``` + +--- + +### `pre-commit` -- Unified Pre-Commit Hook + +Runs a suite of checks suitable for a git pre-commit hook: copyright headers, secret scanning, formatting, audits, and versioning prompts. Includes an interactive TUI progress display. + +#### Arguments + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `--root ` | `PathBuf` | `.` | Project root (defaults to auto-detected) | +| `--skip-audit` | `bool` | `false` | Skip security audit (osv-scanner + npm audit-ci) | +| `--skip-format` | `bool` | `false` | Skip formatting step | +| `--skip-versioning` | `bool` | `false` | Skip changeset/versioning prompt | +| `--max-file-size ` | `u64` | `10485760` (10 MiB) | Maximum file size in bytes | +| `--no-tui` | `bool` | `false` | Disable TUI (plain output for CI or piped stderr) | + +#### Examples + +```bash +# Run all pre-commit checks +resq pre-commit + +# Skip audit and formatting (fast mode) +resq pre-commit --skip-audit --skip-format + +# CI-friendly plain output +resq pre-commit --no-tui +``` + +--- + +### `version` -- Monorepo Versioning + +Manages package versions and changesets across the monorepo using a changeset-based workflow. Supports Cargo.toml, package.json, pyproject.toml, and Directory.Build.props manifests. + +#### Subcommands + +##### `version add` -- Create a Changeset + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `-b, --bump ` | `String` | `patch` | Type of change: `patch`, `minor`, `major` | +| `-m, --message ` | `String` | *required* | Summary of what changed | + +```bash +resq version add --bump minor --message "Add new health check endpoint" +``` + +##### `version apply` -- Apply Version Bumps + +Consumes all pending changesets, determines the highest bump level, updates all manifests, and appends to CHANGELOG.md. + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `--dry-run` | `bool` | `false` | Preview what would change without modifying files | + +```bash +# Apply version bumps +resq version apply + +# Preview only +resq version apply --dry-run +``` + +##### `version check` -- Verify Version Sync + +Checks that all manifest files contain the same version string. + +```bash +resq version check +``` + +--- + +### `docs` -- Documentation Export + +Exports and publishes OpenAPI specifications from the Infrastructure API and Coordination HCE services. + +#### Arguments + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `-e, --export-only` | `bool` | `false` | Only export specs locally without publishing | +| `-p, --publish` | `bool` | `false` | Publish specifications to the documentation repository via GitHub API | +| `--dry-run` | `bool` | `false` | Show what would be done without executing | + +#### Examples + +```bash +# Export specs locally +resq docs --export-only + +# Export and publish to GitHub +resq docs --publish + +# Preview what would happen +resq docs --dry-run +``` + +--- + +### TUI Launchers + +These commands launch standalone TUI applications from the ResQ workspace. Each delegates to a separate binary via `cargo run -p `. + +#### `explore` -- Performance Monitor (resq-perf) + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `` | `String` | `http://localhost:3000/admin/status` | Service URL to monitor | +| `--refresh-ms ` | `u64` | `500` | Refresh rate in milliseconds | + +```bash +resq explore +resq explore http://localhost:8080/status --refresh-ms 1000 +``` + +#### `logs` -- Log Aggregator (resq-logs) + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `--source ` | `String` | `docker` | Log source: `docker` or `file` | +| `--service ` | `String` | none | Filter to a specific service name | + +```bash +resq logs +resq logs --source file --service edge-aeai +``` + +#### `health` -- Health Dashboard (resq-health) + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `-i, --interval ` | `u64` | `5` | Poll interval in seconds | + +```bash +resq health +resq health --interval 10 +``` + +#### `deploy` -- Deployment Manager (resq-deploy) + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `--env ` | `String` | `dev` | Target environment: `dev`, `staging`, `prod` | +| `--k8s` | `bool` | `false` | Use Kubernetes instead of Docker Compose | + +```bash +resq deploy +resq deploy --env staging --k8s +``` + +#### `clean` -- Workspace Cleaner (resq-clean) + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `--dry-run` | `bool` | `false` | Preview what would be deleted without removing anything | + +```bash +resq clean +resq clean --dry-run +``` + +#### `asm` -- Binary Analyzer (resq-bin) + +| Flag / Option | Type | Default | Description | +| --- | --- | --- | --- | +| `--file ` | `String` | none | Analyze a single binary (conflicts with `--dir`) | +| `--dir ` | `String` | none | Analyze binaries under a directory (conflicts with `--file`) | +| `--recursive` | `bool` | `false` | Recursively traverse directory in batch mode | +| `--ext ` | `String` | none | Suffix filter in batch mode (e.g. `.so`, `.o`) | +| `--config ` | `String` | none | Path to resq-bin config TOML | +| `--no-cache` | `bool` | `false` | Disable cache reads/writes | +| `--rebuild-cache` | `bool` | `false` | Force cache rebuild | +| `--no-disasm` | `bool` | `false` | Only collect metadata, skip disassembly | +| `--max-functions ` | `usize` | none | Maximum functions to disassemble per binary | +| `--tui` | `bool` | `false` | Force interactive TUI mode | +| `--plain` | `bool` | `false` | Use non-interactive plain output | +| `--json` | `bool` | `false` | Emit JSON report output | + +```bash +resq asm --file target/release/resq +resq asm --dir target/release/ --recursive --ext .so +resq asm --file mylib.o --plain --no-cache +resq asm --dir . --recursive --json --max-functions 100 +``` + +--- + +## Environment Variables + +| Variable | Used By | Description | +| --- | --- | --- | +| `RUST_LOG` | all commands | Controls `tracing-subscriber` log level (e.g. `debug`, `info`, `warn`) | +| `GH_TOKEN` / `GITHUB_TOKEN` | `docs --publish` | GitHub API authentication for publishing specs | + +The `pre-commit` and `audit` commands shell out to external tools (`osv-scanner`, `bun`, `npx`, `audit-ci`, `react-doctor`) which may read their own environment variables. + +## Configuration + +- **Project root detection**: The CLI walks up the directory tree looking for `resQ.sln`, `package.json`, `Cargo.toml`, `pyproject.toml`, or `.git` to locate the project root. +- **Gitignore integration**: The `secrets` and `copyright` commands parse `.gitignore` for directory exclusion. When `.gitignore` is missing, a built-in fallback list is used (`node_modules`, `.git`, `dist`, `build`, `.next`, `target`, `__pycache__`, `.venv`, `venv`, `vendor`, `.turbo`, `coverage`). +- **OSV Scanner config**: If `osv-scanner.toml` exists at the project root, it is passed automatically to the `audit` command. +- **Secrets allowlist**: Create a text file with one pattern per line and pass it via `--allowlist`. +- **Changesets**: Version changesets are stored as markdown files in `.changesets/` at the repository root. + +## Exit Codes + +| Code | Meaning | +| --- | --- | +| `0` | Success | +| `1` | Command failed (e.g. audit found vulnerabilities, copyright headers missing in `--check` mode, secrets detected, versions out of sync) | +| `2` | CLI argument parsing error | + +## License + +Licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/resq-software/crates/blob/master/LICENSE) for the full text. + diff --git a/sdks/rust/api/resq-deploy.md b/sdks/rust/api/resq-deploy.md new file mode 100644 index 00000000..d508057e --- /dev/null +++ b/sdks/rust/api/resq-deploy.md @@ -0,0 +1,225 @@ +# resq-deploy + +> **Version:** `v0.1.16` · **License:** `Apache-2.0` · **Crate:** [crates.io](https://crates.io/crates/resq-deploy) · **API docs:** [docs.rs](https://docs.rs/resq-deploy/0.1.16) + +Interactive deployment manager for ResQ environments — Docker Compose and Kubernetes TUI + +## Overview + +[![Crates.io](https://img.shields.io/crates/v/resq-deploy.svg)](https://crates.io/crates/resq-deploy) +[![License](https://img.shields.io/crates/l/resq-deploy.svg)](LICENSE) + +Interactive deployment manager for ResQ environments. Provides a three-panel Ratatui TUI for managing Docker Compose and Kubernetes deployments across dev, staging, and production, plus a non-interactive `--action` flag for CI/CD pipelines and scripting. + +## Overview + +`resq-deploy` wraps `docker compose` and `kubectl` behind a unified interface. Operators select a target environment and service, pick an action, and watch real-time execution output -- all without leaving the terminal. For automation, every action is accessible via a single CLI invocation that streams output to stdout and exits with the process status code. + +## Architecture + +```mermaid +graph TB + subgraph CLI["resq-deploy CLI"] + Parser["Clap Argument Parser"] + Router{"Interactive?"} + end + + subgraph TUI["Ratatui TUI"] + Header["Header (env + mode indicator)"] + Services["Services Panel"] + Actions["Actions Panel"] + Output["Execution Log Panel"] + Footer["Footer (keybindings)"] + end + + subgraph Backends + Docker["docker.rs
Docker Compose Backend"] + K8s["k8s.rs
Kubernetes Backend"] + end + + subgraph Infrastructure + Compose["docker compose"] + Kubectl["kubectl"] + end + + subgraph Environments + Dev["dev"] + Staging["staging"] + Prod["prod"] + end + + Parser --> Router + Router -->|"--action flag"| NI["Non-Interactive Runner
(stdout streaming)"] + Router -->|"no flag"| TUI + + Services --> Actions + Actions -->|Enter| Output + + TUI -->|"--k8s off"| Docker + TUI -->|"--k8s on"| K8s + NI -->|"--k8s off"| Docker + NI -->|"--k8s on"| K8s + + Docker --> Compose + K8s --> Kubectl + + Docker -->|"compose file selection"| Environments + K8s -->|"overlay / namespace"| Environments + + Docker -.->|"mpsc channel"| Output + K8s -.->|"mpsc channel"| Output +``` + +## Installation + +```bash +# From the workspace root +cargo install --path crates/resq-deploy + +# Or build locally +cargo build --release -p resq-deploy +# Binary: target/release/resq-deploy +``` + +## CLI Arguments + +| Flag | Short | Default | Description | +|------|-------|---------|-------------| +| `--env ` | | `dev` | Target environment: `dev`, `staging`, or `prod` | +| `--service ` | | all | Scope action to a single service | +| `--k8s` | | off | Use Kubernetes backend instead of Docker Compose | +| `--action ` | | -- | Run a single action non-interactively and exit | + +## Usage Examples + +### Interactive TUI (default) + +```bash +# Launch with defaults (dev environment, Docker Compose) +resq-deploy + +# Target staging environment +resq-deploy --env staging + +# Kubernetes mode against production +resq-deploy --k8s --env prod +``` + +### Non-Interactive / CI Mode + +```bash +# Bring up the dev stack +resq-deploy --env dev --action up + +# Deploy to production via Kubernetes +resq-deploy --env prod --k8s --action deploy + +# Restart a single service +resq-deploy --env dev --service infrastructure-api --action restart + +# Tear down staging +resq-deploy --env staging --action down + +# View logs for a specific service +resq-deploy --env dev --service coordination-hce --action logs +``` + +### CI Pipeline Example + +```bash +# Build, deploy, and gate on health +resq-deploy --env dev --action up +resq-health --check || { echo "Services not ready"; exit 1; } + +# Production Kubernetes deploy +resq-deploy --env prod --k8s --action deploy +``` + +## TUI Layout + +``` ++-- Services ----------+-- Actions ----------+-- Execution Log ----------------+ +| | | | +| > infrastructure-api | > status | [14:22:01] Starting up... | +| coordination-hce | build | [14:22:02] infra-api OK | +| intelligence-pdie | up | [14:22:03] coord-hce OK | +| web-dashboard | down | [14:22:04] All services up | +| | restart | | +| | logs | | ++----------------------+---------------------+---------------------------------+ +| ENV: DEV [E] cycle env [Tab] focus [Up/Down] select [Enter] run | +| [Q] quit | ++------------------------------------------------------------------------------+ +``` + +## Keyboard Shortcuts + +| Key | Action | +|-----|--------| +| `q` / `Esc` | Quit | +| `Tab` | Cycle focus between Services and Actions panels | +| `Up` / `k` | Move selection up in focused panel | +| `Down` / `j` | Move selection down in focused panel | +| `Enter` | Execute the selected action on the selected service | +| `e` | Cycle environment: dev -> staging -> prod -> dev | + +## Docker Compose Actions + +| Action | Description | Underlying Command | +|--------|-------------|--------------------| +| `status` | Show container status for all services | `docker compose ps --format json` | +| `build` | Build images for one or all services | `docker compose build [service]` | +| `up` | Start services in detached mode with build | `docker compose up -d --build [service]` | +| `down` | Stop and remove all containers | `docker compose down` | +| `restart` | Restart one or all services | `docker compose restart [service]` | +| `logs` | Tail last 100 log lines (streaming) | `docker compose logs -f --tail 100 [service]` | + +## Kubernetes Actions + +| Action | Description | Underlying Command | +|--------|-------------|--------------------| +| `status` | List pods in the environment namespace | `kubectl get pods -n resq- -o wide` | +| `deploy` | Apply Kustomize overlay for the environment | `kubectl apply -k infra/k8s/overlays/` | +| `destroy` | Delete resources from overlay (safe ignore) | `kubectl delete -k infra/k8s/overlays/ --ignore-not-found` | +| `logs` | Stream logs from a specific deployment | `kubectl logs -f deployment/ -n resq-` | + +## Managed Services + +The following services are tracked by default: + +| Service | Description | +|---------|-------------| +| `infrastructure-api` | Core platform API | +| `coordination-hce` | Coordination engine | +| `intelligence-pdie` | Intelligence/ML engine | +| `web-dashboard` | Frontend web application | + +## Environment Configuration + +| Environment | Docker Compose Files | K8s Overlay Path | +|-------------|---------------------|------------------| +| `dev` | `docker-compose.yml` + `docker-compose.dev.yml` | `infra/k8s/overlays/dev` | +| `staging` | `docker-compose.yml` (base only) | `infra/k8s/overlays/staging` | +| `prod` | `docker-compose.yml` + `docker-compose.prod.yml` | `infra/k8s/overlays/prod` | + +Docker Compose files are resolved relative to `/infra/docker/`. Kubernetes overlays are resolved relative to `/infra/k8s/overlays/`. The project root is auto-detected by ascending two directory levels from the current working directory. + +## Environment Variables + +`resq-deploy` does not currently read environment variables for configuration. All settings are controlled via CLI flags. Docker and kubectl inherit the calling shell's environment (e.g., `DOCKER_HOST`, `KUBECONFIG`). + +## Dependencies + +| Crate | Purpose | +|-------|---------| +| `resq-tui` | Shared TUI components, theme, header/footer widgets | +| `clap` | CLI argument parsing (derive mode) | +| `tokio` | Async runtime for background task management | +| `serde` / `serde_json` | JSON deserialization of `docker compose ps` output | +| `chrono` | Timestamp handling | +| `anyhow` | Error propagation | + +## License + +Licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/resq-software/crates/blob/master/LICENSE) for details. + diff --git a/sdks/rust/api/resq-dsa.md b/sdks/rust/api/resq-dsa.md new file mode 100644 index 00000000..824b241f --- /dev/null +++ b/sdks/rust/api/resq-dsa.md @@ -0,0 +1,449 @@ +# resq-dsa + +> **Version:** `v0.1.3` · **License:** `Apache-2.0` · **Crate:** [crates.io](https://crates.io/crates/resq-dsa) · **API docs:** [docs.rs](https://docs.rs/resq-dsa/0.1.3) + +Production-grade data structures and algorithms — zero external dependencies + +## Overview + +[![Crates.io](https://img.shields.io/crates/v/resq-dsa.svg)](https://crates.io/crates/resq-dsa) +[![docs.rs](https://img.shields.io/docsrs/resq-dsa)](https://docs.rs/resq-dsa) +[![License](https://img.shields.io/crates/l/resq-dsa.svg)](https://github.com/wombocombo/wrk/blob/master/LICENSE) + +Production-grade data structures and algorithms with **zero external dependencies**. Designed for `no_std` environments and embedded systems while remaining ergonomic in standard Rust applications. The crate provides space-efficient probabilistic data structures (Bloom filter, Count-Min sketch), graph algorithms (BFS, Dijkstra, A\*), a bounded heap for K-nearest-neighbor tracking, a trie for prefix-based search, and Rabin-Karp rolling-hash string matching. + +## Module Structure + +```mermaid +graph TD + A[resq-dsa] --> B[bloom] + A --> C[count_min] + A --> D[graph] + A --> E[heap] + A --> F[trie] + + B --> B1[BloomFilter] + C --> C1[CountMinSketch] + D --> D1["Graph<Id>"] + D1 --> D2[bfs] + D1 --> D3[dijkstra] + D1 --> D4[astar] + E --> E1["BoundedHeap<T, D>"] + F --> F1[Trie] + F --> F2[rabin_karp] + + style A fill:#2d333b,stroke:#539bf5,color:#adbac7 + style B fill:#2d333b,stroke:#57ab5a,color:#adbac7 + style C fill:#2d333b,stroke:#57ab5a,color:#adbac7 + style D fill:#2d333b,stroke:#57ab5a,color:#adbac7 + style E fill:#2d333b,stroke:#57ab5a,color:#adbac7 + style F fill:#2d333b,stroke:#57ab5a,color:#adbac7 +``` + +## Feature Flags + +| Feature | Default | Description | +|---------|---------|-------------| +| `std` | Yes | Enables standard library support. Disable for `no_std` environments (the crate uses `alloc` internally). | + +## Installation + +### With `std` (default) + +```toml +[dependencies] +resq-dsa = "0.1" +``` + +### `no_std` environments + +```toml +[dependencies] +resq-dsa = { version = "0.1", default-features = false } +``` + +When `std` is disabled the crate compiles with `#![no_std]` and relies only on `alloc`. You must provide a global allocator in your binary. + +--- + +## Data Structures + +### Bloom Filter + +A space-efficient probabilistic set-membership data structure. It can tell you if an element is **possibly** in the set or **definitely not** in the set. False positives are possible; false negatives are not. + +The filter uses `k` independent FNV-1a hash functions (seeded variants) to set bits in an `m`-bit array. Optimal values for `k` and `m` are computed automatically from the desired capacity and false-positive rate. + +#### Complexity + +| Operation | Time | Space | +|-----------|--------|-------| +| `new` | O(m) | O(m) | +| `add` | O(k) | -- | +| `has` | O(k) | -- | +| `len` | O(1) | -- | +| `is_empty`| O(1) | -- | +| `clear` | O(m) | -- | + +Where **m** is the bit-array size and **k** is the number of hash functions (both derived from `capacity` and `error_rate`). + +#### API Reference + +| Method | Signature | Description | +|--------|-----------|-------------| +| `new` | `fn new(capacity: usize, error_rate: f64) -> Self` | Creates a new Bloom filter sized for `capacity` elements at the given false-positive `error_rate` (must be in `(0, 1)`). Panics if `error_rate` is out of range or `capacity` is zero. | +| `add` | `fn add(&mut self, item: impl AsRef<[u8]>)` | Adds an element to the filter. Accepts `&str`, `String`, `&[u8]`, `Vec`, etc. | +| `has` | `fn has(&self, item: impl AsRef<[u8]>) -> bool` | Returns `true` if the element is possibly in the set, `false` if it is definitely absent. | +| `len` | `const fn len(&self) -> usize` | Returns the number of elements that have been added. | +| `is_empty` | `const fn is_empty(&self) -> bool` | Returns `true` if no elements have been added. | +| `clear` | `fn clear(&mut self)` | Resets the filter, removing all elements. | + +#### Example + +```rust +use resq_dsa::bloom::BloomFilter; + +// Create a filter for 10,000 items with a 1% false-positive rate +let mut bf = BloomFilter::new(10_000, 0.01); + +bf.add("drone-001"); +bf.add("drone-002"); +bf.add(b"raw-bytes" as &[u8]); + +assert!(bf.has("drone-001")); // definitely present +assert!(!bf.has("drone-999")); // definitely absent +assert_eq!(bf.len(), 3); + +bf.clear(); +assert!(bf.is_empty()); +assert!(!bf.has("drone-001")); // cleared +``` + +--- + +### Count-Min Sketch + +A space-efficient probabilistic data structure for **frequency estimation**. It may overcount but never undercounts. Estimates are within `epsilon * N` of the true count with probability `1 - delta`, where `N` is the total count of all increments. + +Uses `depth` independent FNV-1a hash functions mapping elements to `width` columns. The estimated count for a key is the **minimum** across all rows. + +#### Complexity + +| Operation | Time | Space | +|-------------|----------|----------------| +| `new` | O(w * d) | O(w * d) | +| `increment` | O(d) | -- | +| `estimate` | O(d) | -- | + +Where **w** = `ceil(e / epsilon)` (width) and **d** = `ceil(ln(1 / delta))` (depth). + +#### API Reference + +| Method | Signature | Description | +|--------|-----------|-------------| +| `new` | `fn new(epsilon: f64, delta: f64) -> Self` | Creates a new sketch. `epsilon` controls error magnitude, `delta` controls failure probability. Both must be in `(0, 1)`. | +| `increment` | `fn increment(&mut self, key: impl AsRef<[u8]>, count: u64)` | Increments the count for `key` by `count`. Counts are stored as `u64` and saturate on overflow. | +| `estimate` | `fn estimate(&self, key: impl AsRef<[u8]>) -> u64` | Returns the estimated count for `key`. Guaranteed to be >= the true count. | + +#### Example + +```rust +use resq_dsa::count_min::CountMinSketch; + +// Estimates within 1% of true count, 99% of the time +let mut cms = CountMinSketch::new(0.01, 0.01); + +cms.increment("sensor-temp-high", 5); +cms.increment("sensor-temp-high", 3); +cms.increment("sensor-humidity", 1); + +let temp_count = cms.estimate("sensor-temp-high"); +assert!(temp_count >= 8); // never undercounts + +// Works with byte slices +cms.increment(b"raw-key" as &[u8], 10); +assert!(cms.estimate(b"raw-key" as &[u8]) >= 10); + +// Unknown keys return 0 +assert_eq!(cms.estimate("never-seen"), 0); +``` + +--- + +### Graph (Weighted Directed) + +A weighted directed graph with three pathfinding algorithms: breadth-first search (BFS), Dijkstra's shortest path, and A\* with a user-provided heuristic. + +Node identifiers can be any type that implements `Eq + Hash + Clone` (and additionally `Ord` for Dijkstra and A\*). Edge weights are `u64`. + +```mermaid +graph LR + A["base"] -- "100" --> B["waypoint-1"] + B -- "50" --> C["waypoint-2"] + A -- "200" --> C + C -- "25" --> D["target"] + + style A fill:#2d333b,stroke:#539bf5,color:#adbac7 + style D fill:#2d333b,stroke:#e5534b,color:#adbac7 +``` + +#### Complexity + +| Operation | Time | Space | +|------------|-----------------------|--------------| +| `new` | O(1) | O(1) | +| `add_edge` | O(1) amortized | O(1) | +| `bfs` | O(V + E) | O(V) | +| `dijkstra` | O((V + E) log V) | O(V) | +| `astar` | O((V + E) log V) * | O(V) | + +\* A\* worst case matches Dijkstra; with a good heuristic it explores fewer nodes. + +#### API Reference + +| Method | Signature | Description | +|--------|-----------|-------------| +| `new` | `fn new() -> Self` | Creates a new empty directed graph. Also implements `Default`. | +| `add_edge` | `fn add_edge(&mut self, from: Id, to: Id, weight: u64)` | Adds a directed edge. For undirected graphs, call twice with reversed nodes. | +| `bfs` | `fn bfs(&self, start: &Id) -> Vec` | Returns all reachable nodes from `start` in breadth-first order. Requires `Id: Eq + Hash + Clone`. | +| `dijkstra` | `fn dijkstra(&self, start: &Id, end: &Id) -> Option<(Vec, u64)>` | Finds the shortest path and its cost. Returns `None` if `end` is unreachable. Requires `Id: Eq + Hash + Clone + Ord`. | +| `astar` | `fn astar u64>(&self, start: &Id, end: &Id, h: H) -> Option<(Vec, u64)>` | A\* shortest path with heuristic `h(node, goal)`. The heuristic must be admissible and consistent for correct results. Requires `Id: Eq + Hash + Clone + Ord`. | + +#### Examples + +```rust +use resq_dsa::graph::Graph; + +let mut g = Graph::<&str>::new(); + +// Build the graph +g.add_edge("base", "waypoint-1", 100); +g.add_edge("waypoint-1", "waypoint-2", 50); +g.add_edge("base", "waypoint-2", 200); +g.add_edge("waypoint-2", "target", 25); + +// BFS -- visit all reachable nodes +let visited = g.bfs(&"base"); +assert!(visited.contains(&"target")); + +// Dijkstra -- find shortest path +let (path, cost) = g.dijkstra(&"base", &"target").unwrap(); +assert_eq!(path, vec!["base", "waypoint-1", "waypoint-2", "target"]); +assert_eq!(cost, 175); + +// Unreachable nodes return None +assert!(g.dijkstra(&"target", &"base").is_none()); +``` + +**A\* with a heuristic:** + +```rust +use resq_dsa::graph::Graph; + +let mut g = Graph::::new(); +g.add_edge(0, 1, 1); +g.add_edge(1, 2, 1); +g.add_edge(0, 3, 10); +g.add_edge(3, 2, 1); + +// Use absolute difference as heuristic +let (path, cost) = g.astar(&0, &2, |a, b| a.abs_diff(*b)).unwrap(); +assert_eq!(path, vec![0, 1, 2]); +assert_eq!(cost, 2); +``` + +--- + +### Bounded Heap + +A bounded max-heap that retains only the **K entries with the smallest distance values**. Useful for K-nearest-neighbor search, top-K tracking, and streaming scenarios where you want to keep only the closest results. + +The root always holds the entry with the **largest** distance among the retained items. When the heap is full and a new entry has a smaller distance than the root, the root is evicted. + +#### Complexity + +| Operation | Time | Space | +|-------------|-----------|-------| +| `new` | O(1) | O(k) | +| `insert` | O(log k) | -- | +| `peek` | O(1) | -- | +| `to_sorted` | O(k log k)| O(k) | +| `len` | O(1) | -- | +| `is_empty` | O(1) | -- | + +Where **k** is the heap limit. + +#### API Reference + +| Method | Signature | Description | +|--------|-----------|-------------| +| `new` | `fn new(limit: usize, dist: D) -> Self` | Creates a heap that keeps at most `limit` items, ordered by the distance function `dist: Fn(&T) -> f64`. | +| `insert` | `fn insert(&mut self, entry: T)` | Inserts an entry. If full and the new entry's distance is less than the current max, the max is evicted. Otherwise the entry is rejected. | +| `peek` | `fn peek(&self) -> Option<&T>` | Returns a reference to the entry with the maximum distance (the root), or `None` if empty. | +| `to_sorted` | `fn to_sorted(&self) -> Vec<&T>` | Returns all entries sorted by distance ascending (nearest first). Allocates a new `Vec` on each call. | +| `len` | `const fn len(&self) -> usize` | Returns the current number of entries. | +| `is_empty` | `const fn is_empty(&self) -> bool` | Returns `true` if the heap is empty. | + +#### Example + +```rust +use resq_dsa::heap::BoundedHeap; + +#[derive(Debug)] +struct Waypoint { id: u32, distance: f64 } + +// Keep the 3 nearest waypoints +let mut h = BoundedHeap::new(3, |w: &Waypoint| w.distance); + +h.insert(Waypoint { id: 1, distance: 10.0 }); +h.insert(Waypoint { id: 2, distance: 2.0 }); +h.insert(Waypoint { id: 3, distance: 7.0 }); +h.insert(Waypoint { id: 4, distance: 1.0 }); // evicts id=1 (distance 10.0) +h.insert(Waypoint { id: 5, distance: 50.0 }); // rejected (too far) + +assert_eq!(h.len(), 3); + +// peek returns the current max (the eviction threshold) +assert_eq!(h.peek().unwrap().id, 3); // id=3 has distance 7.0 + +// Sorted nearest-first +let sorted: Vec = h.to_sorted().iter().map(|w| w.id).collect(); +assert_eq!(sorted, vec![4, 2, 3]); +``` + +**Works with closures:** + +```rust +use resq_dsa::heap::BoundedHeap; + +let offset = 1.0; +let mut h = BoundedHeap::new(5, move |x: &f64| *x + offset); +h.insert(3.0); +h.insert(1.0); +assert_eq!(h.len(), 2); +``` + +--- + +### Trie (Prefix Tree) + +A prefix tree for efficient string storage, exact lookup, and prefix-based autocomplete. All operations run in O(m) time where m is the length of the input string. + +Internally, each node stores a `HashMap`, making the trie Unicode-aware. + +#### Complexity + +| Operation | Time | Space | +|---------------|------|-----------------| +| `new` | O(1) | O(1) | +| `insert` | O(m) | O(m) worst case | +| `search` | O(m) | -- | +| `starts_with` | O(m + r) | O(r) | + +Where **m** is the string length and **r** is the total length of all matching results. + +#### API Reference + +| Method | Signature | Description | +|--------|-----------|-------------| +| `new` | `fn new() -> Self` | Creates a new empty trie. Also implements `Default`. | +| `insert` | `fn insert(&mut self, word: &str)` | Inserts a word into the trie. | +| `search` | `fn search(&self, word: &str) -> bool` | Returns `true` if the exact word exists in the trie. | +| `starts_with` | `fn starts_with(&self, prefix: &str) -> Vec` | Returns all words that start with the given prefix. Uses DFS with a shared buffer to minimize allocations. | + +#### Example + +```rust +use resq_dsa::trie::Trie; + +let mut t = Trie::new(); +t.insert("drone"); +t.insert("drone-001"); +t.insert("drone-002"); +t.insert("deploy"); + +// Exact search +assert!(t.search("drone")); +assert!(!t.search("dro")); // prefix alone is not a word + +// Autocomplete +let mut suggestions = t.starts_with("drone-"); +suggestions.sort(); +assert_eq!(suggestions, vec!["drone-001", "drone-002"]); + +// All words starting with "d" +let mut all_d = t.starts_with("d"); +all_d.sort(); +assert_eq!(all_d, vec!["deploy", "drone", "drone-001", "drone-002"]); +``` + +--- + +### Rabin-Karp String Search + +A rolling-hash string matching algorithm that finds all occurrences of a pattern in a text. Uses a polynomial rolling hash with modular arithmetic (base 31, mod 10^9 + 7). + +The algorithm is **Unicode-aware** -- it operates on `char` boundaries, so multi-byte characters are handled correctly. Indices in the result are character positions, not byte offsets. + +#### Complexity + +| Case | Time | Space | +|---------|------------|-------| +| Average | O(n + m) | O(m) | +| Worst | O(n * m) | O(m) | + +Where **n** is the text length and **m** is the pattern length (both in chars). + +#### API Reference + +| Function | Signature | Description | +|----------|-----------|-------------| +| `rabin_karp` | `fn rabin_karp(text: &str, pattern: &str) -> Vec` | Returns a vector of starting character indices where `pattern` occurs in `text`. Returns an empty vector if there are no matches or the pattern is empty. | + +#### Example + +```rust +use resq_dsa::trie::rabin_karp; + +// Multiple overlapping matches +let matches = rabin_karp("ababab", "ab"); +assert_eq!(matches, vec![0, 2, 4]); + +// Single match +let single = rabin_karp("hello world", "world"); +assert_eq!(single, vec![6]); + +// No match +let none = rabin_karp("hello", "xyz"); +assert!(none.is_empty()); + +// Unicode support +let unicode = rabin_karp("cafe\u{0301} cafe\u{0301}", "cafe\u{0301}"); +assert_eq!(unicode, vec![0, 6]); +``` + +--- + +## Quick Reference + +| Module | Primary Type | Key Methods | +|--------|-------------|-------------| +| `bloom` | `BloomFilter` | `new`, `add`, `has`, `len`, `is_empty`, `clear` | +| `count_min` | `CountMinSketch` | `new`, `increment`, `estimate` | +| `graph` | `Graph` | `new`, `add_edge`, `bfs`, `dijkstra`, `astar` | +| `heap` | `BoundedHeap` | `new`, `insert`, `peek`, `to_sorted`, `len`, `is_empty` | +| `trie` | `Trie` | `new`, `insert`, `search`, `starts_with` | +| `trie` | (free fn) `rabin_karp` | `rabin_karp(text, pattern)` | + +## Contributing + +1. Fork the repository and create a feature branch. +2. Run `cargo test` to ensure all tests pass. +3. All new source files must include the Apache-2.0 license header. +4. Keep binary names consistent with the `resq-` convention. +5. Open a pull request against `master`. + +## License + +Licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/resq-software/crates/blob/master/crates/LICENSE) for details. + diff --git a/sdks/rust/api/resq-flame.md b/sdks/rust/api/resq-flame.md new file mode 100644 index 00000000..d99a3b75 --- /dev/null +++ b/sdks/rust/api/resq-flame.md @@ -0,0 +1,183 @@ +# resq-flame + +> **Version:** `v0.1.16` · **License:** `Apache-2.0` · **Crate:** [crates.io](https://crates.io/crates/resq-flame) · **API docs:** [docs.rs](https://docs.rs/resq-flame/0.1.16) + +SVG CPU flame graph profiler for ResQ services + +## Overview + +[![Crates.io](https://img.shields.io/crates/v/resq-flame.svg)](https://crates.io/crates/resq-flame) +[![License](https://img.shields.io/crates/l/resq-flame.svg)](LICENSE) + +Interactive CPU profiler and SVG flame graph generator for ResQ services. Provides a TUI for selecting profiling targets and a subcommand interface for scripted profiling, piping output through `inferno-flamegraph`. + +## Overview + +`resq-flame` supports multiple profiling backends (V8 CPU profiles, pprof, py-spy, Linux perf) and converts their output into the folded-stack format consumed by `inferno`. The result is an interactive SVG flame graph you can open in any browser. + +## Profiling Pipeline + +```mermaid +flowchart LR + A[Launch resq-flame] --> B{Mode?} + B -->|Interactive| C[TUI: Select Target] + B -->|Subcommand| D[CLI: resq-flame hce ...] + + C --> E[Dispatch Profiling Engine] + D --> E + + E --> F{Engine} + F -->|HCE| G[V8 CPU Profile via HTTP] + F -->|API| H[Rust pprof] + F -->|PDIE| I[py-spy] + F -->|Perf| J[Linux perf record] + + G --> K[Parse to Folded Stacks] + H --> K + I --> K + J --> K + + K --> L[inferno-flamegraph] + L --> M[Output SVG] + M --> N{--open flag?} + N -->|Yes| O[Open in Browser] + N -->|No| P[Done] +``` + +## Installation + +```bash +# From the workspace root +cargo build --release -p resq-flame + +# Binary location +target/release/resq-flame +``` + +### Prerequisites + +| Tool | Required For | Install | +|------|-------------|---------| +| `inferno` | All SVG generation | `cargo install inferno` | +| `py-spy` | Python (PDIE) profiling | `pip install py-spy` | +| `perf` | Linux kernel profiling | `sudo apt install linux-perf` or `sudo pacman -S perf` | + +## CLI Arguments + +### Global Flags + +| Flag | Short | Default | Description | +|------|-------|---------|-------------| +| `--output ` | `-o` | `flamegraph.svg` | Output SVG file path | +| `--open` | | `false` | Open the SVG in the default browser after generation | + +### Subcommand: `hce` + +Fetch a V8 CPU profile from the Coordination HCE server. + +| Flag | Short | Default | Description | +|------|-------|---------|-------------| +| `--url ` | `-u` | `http://localhost:5000` | HCE server URL | +| `--duration ` | `-d` | `5000` | Profile duration in milliseconds | + +## Usage Examples + +### Interactive TUI (default) + +```bash +# Launch the target selection TUI +resq-flame +``` + +Use arrow keys or `j`/`k` to navigate, `Enter` to start profiling the selected target, and `q` or `Esc` to quit. + +### Subcommand Mode + +```bash +# Profile the HCE service for 5 seconds +resq-flame hce + +# Profile with custom URL and duration, output to custom path +resq-flame hce --url http://staging:5000 --duration 10000 --output hce-profile.svg + +# Profile and auto-open in browser +resq-flame --open hce --duration 3000 +``` + +## Profiling Targets (TUI) + +| Target | Engine | Description | +|--------|--------|-------------| +| Coordination HCE | `hce` | Node.js/Bun service via HTTP metrics | +| Infrastructure API | `api` | Rust backend via pprof | +| Intelligence PDIE | `python` | Python AI engine via py-spy | +| Linux Perf | `perf` | System-wide profiling via `perf record` | + +## TUI Keybindings + +| Key | Action | +|-----|--------| +| `q` / `Esc` | Quit | +| `Enter` | Profile the selected target | +| `Up` / `k` | Move selection up | +| `Down` / `j` | Move selection down | + +## Environment Variables + +| Variable | Description | +|----------|-------------| +| `RESQ_TOKEN` | Bearer token for HCE authentication | +| `RESQ_API_KEY` | API key for infrastructure-api and PDIE | + +## Output Format + +The tool generates interactive SVG flame graphs using the `inferno` crate: + +- **Folded stacks** are the intermediate format (`frame1;frame2;frameN count`). +- **SVG output** supports interactive features when opened in a browser: click to zoom, `Ctrl+F` to search. + +### Input Format Support + +| Format | Function | Description | +|--------|----------|-------------| +| V8 `.cpuprofile` | `cpuprofile_to_folded` | Chrome/Node.js CPU profiles with tree structure | +| bpftrace histogram | `parse_bpftrace_output` | `frame1, frame2: count` lines | +| Pre-folded stacks | `parse_folded_stacks` | Standard `stack count` lines | + +### Reading Flame Graphs + +- **Width** of a frame = proportion of total samples where that function was on the stack +- **Height** = call depth (bottom is root, top is leaf) +- **Wide frames at the top** = hot leaf functions (primary optimization targets) +- **Wide frames in the middle** = called frequently from many paths + +## Safety Notes + +- Profiling is **read-only** -- it does not modify the target service. +- External profiler binaries (`py-spy`, `perf`) are invoked as subprocesses; the tool handles missing binaries gracefully. +- Use reasonable durations when profiling production environments to minimize overhead. +- The HCE subcommand connects via HTTP and does not require kernel-level access. +- `perf` mode requires appropriate Linux capabilities (`CAP_SYS_ADMIN` or `perf_event_paranoid` settings). + +## Typical Workflow + +```bash +# 1. Start the target service +cargo run --manifest-path services/infrastructure-api/Cargo.toml + +# 2. Generate load +cd services/simulation-harness && dotnet run + +# 3. Profile while load is running +resq-flame --output before.svg hce --duration 30000 + +# 4. Make optimizations, restart, re-profile +resq-flame --output after.svg hce --duration 30000 + +# 5. Compare the two flame graphs visually +``` + +## License + +Licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/resq-software/crates/blob/master/LICENSE) for details. + diff --git a/sdks/rust/api/resq-health.md b/sdks/rust/api/resq-health.md new file mode 100644 index 00000000..a7a15c51 --- /dev/null +++ b/sdks/rust/api/resq-health.md @@ -0,0 +1,274 @@ +# resq-health + +> **Version:** `v0.1.16` · **License:** `Apache-2.0` · **Crate:** [crates.io](https://crates.io/crates/resq-health) · **API docs:** [docs.rs](https://docs.rs/resq-health/0.1.16) + +Service health diagnostic dashboard for ResQ platform + +## Overview + +[![Crates.io](https://img.shields.io/crates/v/resq-health.svg)](https://crates.io/crates/resq-health) +[![License](https://img.shields.io/crates/l/resq-health.svg)](LICENSE) + +Service health monitoring dashboard for the ResQ platform. Polls all service health endpoints concurrently and displays live status with latency in a Ratatui TUI. Also serves as a CI health gate via `--check` mode, and supports integration test execution via `--test`. + +## Overview + +`resq-health` monitors five core ResQ services by issuing HTTP health checks on a configurable interval. Standard services are probed with `GET /health`, while the Neo N3 RPC node uses a JSON-RPC `getversion` call. Results are displayed in a navigable table with color-coded status indicators, latency measurements, and error diagnostics. A non-interactive `--check` mode provides deterministic exit codes for CI pipelines. + +## Architecture + +```mermaid +graph TB + subgraph CLI["resq-health CLI"] + Parser["Clap Argument Parser"] + ModeRouter{"Mode?"} + end + + subgraph CIMode["CI Mode (--check)"] + SinglePoll["Single Poll"] + ExitCode["Exit Code
0 = all healthy
1 = degraded/unhealthy"] + end + + subgraph TestMode["Integration Test Mode (--test)"] + TestRunner["integration.rs
Script Runner"] + TestResults["Test Results
Pass / Fail / Skip"] + end + + subgraph TUIMode["TUI Mode (default)"] + EventLoop["Event Loop
(tokio::select)"] + KeyHandler["Key Handler"] + Renderer["Ratatui Renderer"] + + subgraph Views + TableView["Service Table View"] + DetailView["Service Detail View"] + HelpPopup["Help Popup"] + end + end + + subgraph Registry["services.rs - Service Registry"] + Client["reqwest HTTP Client
(5s timeout)"] + Services["Service Definitions"] + Poller["Concurrent Poller
(futures::join_all)"] + end + + subgraph Checks["Health Check Logic"] + HTTPCheck["Standard HTTP Check
GET /health"] + RPCCheck["Neo N3 JSON-RPC Check
POST getversion"] + end + + subgraph Endpoints["Monitored Services"] + HCE["coordination-hce
:5000/health"] + Infra["infrastructure-api
:8080/health"] + PDIE["intelligence-pdie
:8000/health"] + Neo["neo-n3-rpc
:20332 (JSON-RPC)"] + IPFS["ipfs-gateway
:8081/api/v0/version"] + end + + Parser --> ModeRouter + ModeRouter -->|"--check"| CIMode + ModeRouter -->|"--test"| TestMode + ModeRouter -->|"default"| TUIMode + + SinglePoll --> Registry + EventLoop -->|"poll interval"| Registry + Registry --> Poller + Poller --> Checks + + HTTPCheck --> HCE + HTTPCheck --> Infra + HTTPCheck --> PDIE + HTTPCheck --> IPFS + RPCCheck --> Neo + + Poller -->|"results"| EventLoop + Poller -->|"results"| SinglePoll + + EventLoop --> Renderer + Renderer --> Views + KeyHandler --> EventLoop + + SinglePoll --> ExitCode + TestRunner --> TestResults +``` + +## Installation + +```bash +# From the workspace root +cargo install --path crates/resq-health + +# Or build locally +cargo build --release -p resq-health +# Binary: target/release/resq-health +``` + +## CLI Arguments + +| Flag | Short | Default | Description | +|------|-------|---------|-------------| +| `--check` | `-c` | off | CI mode: run a single health check cycle, print results, and exit with a status code | +| `--interval ` | `-i` | `5` | Polling interval in seconds (TUI mode only) | +| `--test ` | `-t` | -- | Path to an integration test script or directory to execute | + +## Usage Examples + +### Interactive TUI (default) + +```bash +# Launch the health dashboard with default 5-second polling +resq-health + +# Increase polling interval to 10 seconds +resq-health --interval 10 + +# Short form +resq-health -i 10 +``` + +### CI / Health Gate Mode + +```bash +# Single check, exits with status code +resq-health --check + +# Use as a deployment gate +resq-health --check || { echo "Services not ready"; exit 1; } + +# Combine with deploy +resq-deploy --env dev --action up +resq-health --check +``` + +### Integration Tests + +```bash +# Run integration test scripts +resq-health --test tests/smoke.sh + +# Run tests from a directory +resq-health --test tests/integration/ +``` + +### Integration Test JSON Format + +```json +[ + { + "name": "infrastructure-api health", + "method": "GET", + "url": "http://localhost:5000/health", + "expect_status": 200 + }, + { + "name": "create incident", + "method": "POST", + "url": "http://localhost:5000/incidents", + "body": { "incident_type": "FLOOD", "severity": "HIGH" }, + "expect_status": 201 + } +] +``` + +## TUI Layout + +``` ++-----------------------------------------------------+ +| ResQ Health Monitor Up: 42s | +| 3/5 SERVICES HEALTHY | ++-----------------------------------------------------+ +| SERVICE STATUS LATENCY MESSAGE | +| | +| infrastructure-api Healthy 45ms - | +| coordination-hce Healthy 23ms - | +| intelligence-pdie Degraded 1250ms - | +| neo-n3-rpc Healthy 89ms - | +| web-dashboard Unhealthy 5000ms Timeout | ++-----------------------------------------------------+ +| [Q] Quit [Up/Down] Nav [Enter] Details | ++-----------------------------------------------------+ +``` + +### Detail View + +Pressing `Enter` on a service shows an expanded detail panel with the full URL, status, latency, and diagnostic error message. + +## Keyboard Shortcuts + +| Key | Action | +|-----|--------| +| `q` / `Esc` | Quit the application | +| `Down` / `j` | Move selection down | +| `Up` / `k` | Move selection up | +| `Enter` | Toggle detail view for selected service | +| `h` | Toggle help popup | + +## Health Status Levels + +| Status | Color | Description | +|--------|-------|-------------| +| `Healthy` | Green | Service responded successfully within timeout | +| `Degraded` | Yellow | Service responded but reported non-"ok" status or high latency | +| `Unhealthy` | Red | Service timed out, returned an error HTTP status, or is unreachable | +| `Unknown` | Gray | Service has not been checked yet (initial state) | + +## Exit Codes (--check mode) + +| Exit Code | Meaning | +|-----------|---------| +| `0` | All services report Healthy | +| `1` | One or more services are not Healthy | + +## Monitored Services + +| Service | Default URL | Health Endpoint | Protocol | +|---------|-------------|-----------------|----------| +| `coordination-hce` | `http://localhost:5000` | `/health` | HTTP GET | +| `infrastructure-api` | `http://localhost:8080` | `/health` | HTTP GET | +| `intelligence-pdie` | `http://localhost:8000` | `/health` | HTTP GET | +| `neo-n3-rpc` | `http://localhost:20332` | `/` | JSON-RPC POST (`getversion`) | +| `ipfs-gateway` | `http://localhost:8081` | `/api/v0/version` | HTTP GET | + +All requests use a 5-second timeout. Services that do not respond within the timeout are marked **Unhealthy**. + +## Environment Variables + +Service URLs can be overridden via environment variables: + +| Variable | Default | Description | +|----------|---------|-------------| +| `HCE_URL` | `http://localhost:5000` | Base URL for the coordination-hce service | +| `INFRA_API_URL` | `http://localhost:8080` | Base URL for the infrastructure-api service | +| `PDIE_URL` | `http://localhost:8000` | Base URL for the intelligence-pdie service | +| `NEO_RPC_URL` | `http://localhost:20332` | URL for the Neo N3 RPC node | +| `IPFS_URL` | `http://localhost:8081` | Base URL for the IPFS gateway | + +```bash +# Example: point at a remote staging cluster +HCE_URL=http://staging.internal:5000 \ +INFRA_API_URL=http://staging.internal:8080 \ +resq-health --check +``` + +## Configuration + +`resq-health` does not use configuration files. All configuration is handled through CLI flags and environment variables as described above. To add a new service to the monitoring list, add it to the `ServiceRegistry::new()` function in `src/services.rs`. + +## Dependencies + +| Crate | Purpose | +|-------|---------| +| `resq-tui` | Shared TUI components, theme, header/footer/popup widgets | +| `clap` | CLI argument parsing (derive mode) | +| `tokio` | Async runtime with timer support | +| `reqwest` | HTTP client for health check requests | +| `futures` | Concurrent polling via `join_all` | +| `serde` / `serde_json` | JSON deserialization of health responses | +| `chrono` | Timestamp handling | +| `walkdir` | Directory traversal for integration test discovery | +| `anyhow` | Error propagation | + +## License + +Licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/resq-software/crates/blob/master/LICENSE) for details. + diff --git a/sdks/rust/api/resq-logs.md b/sdks/rust/api/resq-logs.md new file mode 100644 index 00000000..becdd51d --- /dev/null +++ b/sdks/rust/api/resq-logs.md @@ -0,0 +1,193 @@ +# resq-logs + +> **Version:** `v0.1.16` · **License:** `Apache-2.0` · **Crate:** [crates.io](https://crates.io/crates/resq-logs) · **API docs:** [docs.rs](https://docs.rs/resq-logs/0.1.16) + +Multi-source log aggregator and viewer for ResQ services + +## Overview + +[![Crates.io](https://img.shields.io/crates/v/resq-logs.svg)](https://crates.io/crates/resq-logs) +[![License](https://img.shields.io/crates/l/resq-logs.svg)](LICENSE) + +Multi-source log aggregator and real-time stream viewer for ResQ services. Streams logs from Docker Compose containers or local files into a searchable, filterable Ratatui TUI with a 10,000-line ring buffer, color-coded log levels, and deterministic per-service coloring. + +## Architecture + +```mermaid +graph LR + subgraph Sources + D["Docker Compose
docker compose logs -f"] + F["Log File
tail -F"] + end + + subgraph Parser + P["parser.rs
Format Detection"] + P1["Docker Prefix
svc | msg"] + P2["JSON Structured
{level, msg, ts}"] + P3["RUST_LOG
TS LEVEL mod: msg"] + P4["Plain Text
keyword guessing"] + end + + subgraph TUI["TUI (main.rs)"] + RB["Ring Buffer
10,000 entries"] + FL["Filter Engine
level + service + search"] + R["Renderer
Ratatui"] + end + + D -->|"thread + BufReader"| P + F -->|"thread + BufReader"| P + P --> P1 & P2 & P3 & P4 + P1 & P2 & P3 & P4 -->|"mpsc channel"| RB + RB --> FL --> R +``` + +## Installation + +```bash +# From workspace root +cargo build --release -p resq-logs + +# Binary location +target/release/resq-logs +``` + +## CLI Arguments + +| Flag | Type | Default | Description | +|------|------|---------|-------------| +| `--source ` | `String` | `docker` | Log source: `docker` or `file` | +| `--path ` | `String` | `.` | File or directory path (required when `--source file`) | +| `--service ` | `String` | all | Filter to a specific Docker service name | +| `--level ` | `String` | all | Initial minimum log level: `error`, `warn`, `info`, `debug`, `trace` | + +## Usage Examples + +```bash +# Stream all Docker Compose service logs (default) +resq-logs + +# Stream logs from a specific service only +resq-logs --source docker --service infrastructure-api + +# Tail a local log file +resq-logs --source file --path services/infrastructure-api/logs/api.log + +# Start with error-level filter active +resq-logs --source docker --level error + +# Combine service and level filters +resq-logs --source docker --service coord-hce --level warn +``` + +## Log Format Support + +The parser (`parser.rs`) attempts each format in order and uses the first successful match: + +| Priority | Format | Example | Fields Extracted | +|----------|--------|---------|-----------------| +| 1 | Docker Compose prefix | `resq-api \| Server started` | service, message | +| 2 | JSON structured | `{"level":"error","msg":"timeout","ts":"2026-01-01T00:00:00Z"}` | level, message, timestamp, service | +| 3 | RUST_LOG | `2026-01-01T00:00:00Z INFO module::path: message` | timestamp, level, service (module), message | +| 4 | Plain text fallback | `Something happened with an ERROR` | message, level (keyword guess) | + +### JSON Field Aliases + +The JSON parser accepts multiple field names for interoperability: + +| Canonical | Aliases | +|-----------|---------| +| `level` | `lvl`, `severity` | +| `msg` | `message` | +| `timestamp` | `time`, `ts`, `@timestamp` | +| `service` | `component` | + +### Level Recognition + +The parser recognizes these level keywords (case-insensitive): + +| Level | Recognized Keywords | +|-------|-------------------| +| ERROR | `error`, `err`, `fatal`, `critical`, `panic` | +| WARN | `warn`, `warning` | +| INFO | `info` | +| DEBUG | `debug`, `dbg` | +| TRACE | `trace` | + +## Log Sources + +### Docker (`--source docker`) + +Runs `docker compose logs -f --no-color --tail 200` from the `infra/docker/` directory relative to the project root. A background thread reads stdout line-by-line through a `BufReader` and sends parsed entries over an unbounded `mpsc` channel. + +- Requires a running Docker Compose stack +- Strips `resq-` prefix from container names automatically +- Optional `--service` flag passes the service name to Docker for server-side filtering + +### File (`--source file`) + +Opens and reads a local log file to completion, parsing each line. A background thread handles the I/O. + +```bash +resq-logs --source file --path /var/log/resq/infrastructure-api.log +``` + +## Keybindings + +| Key | Mode | Action | +|-----|------|--------| +| `q` | Normal | Quit | +| `Esc` | Normal | Quit | +| `/` | Normal | Enter search mode | +| `Enter` | Search | Apply search query and return to normal mode | +| `Esc` | Search | Cancel search and return to normal mode | +| `Backspace` | Search | Delete last character | +| `f` | Normal | Cycle level filter: All > Error > Warn > Info > Debug > Trace > All | +| `c` | Normal | Clear all buffered log lines | +| `g` | Normal | Jump to bottom and enable follow (auto-scroll) mode | +| `Up` | Normal | Scroll up one line (disables auto-scroll) | +| `Down` | Normal | Scroll down one line (re-enables auto-scroll at bottom) | +| `PageUp` | Normal | Scroll up 20 lines | +| `PageDown` | Normal | Scroll down 20 lines | + +## TUI Layout + +``` ++-- Log-Explorer ---------- STATUS_LINE ----------------------+ +| | +| HH:MM:SS LEVEL SERVICE_NAME message text... | +| HH:MM:SS LEVEL SERVICE_NAME message text... | +| ... | +| | +| +-- SEARCH popup (when / is pressed) ---+ | +| | > search_query_here | | +| +---------------------------------------+ | +| | ++--------------------------------------------------------------+ +| Q Quit / Search F Filter C Clear G Follow Up/Down Scroll| ++--------------------------------------------------------------+ +``` + +## Configuration + +### Buffer Size + +The ring buffer holds a maximum of **10,000** log entries (`MAX_LOG_LINES`). When full, the oldest entry is dropped as each new entry arrives. Up to **256** entries are ingested per render frame (`MAX_INGEST_PER_FRAME`) to prevent UI stalls during high-throughput bursts. + +### Project Root Detection + +The Docker source resolves the project root by navigating two levels up from the current working directory (`ancestors().nth(2)`). The compose file is expected at `/infra/docker/docker-compose.yml`. + +## Environment Variables + +This tool does not currently read environment variables for configuration. All settings are passed via CLI flags. + +## Related Tools + +- [`resq-perf`](https://github.com/resq-software/crates/blob/master/crates/resq-perf/README.md) -- Real-time performance monitoring dashboard +- [`resq-health`](https://github.com/resq-software/crates/blob/master/crates/resq-health/README.md) -- Service health checker +- [`resq-flame`](https://github.com/resq-software/crates/blob/master/crates/resq-flame/README.md) -- CPU flame graph profiler + +## License + +Licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/resq-software/crates/blob/master/LICENSE) for details. + diff --git a/sdks/rust/api/resq-perf.md b/sdks/rust/api/resq-perf.md new file mode 100644 index 00000000..ca321bcc --- /dev/null +++ b/sdks/rust/api/resq-perf.md @@ -0,0 +1,228 @@ +# resq-perf + +> **Version:** `v0.1.16` · **License:** `Apache-2.0` · **Crate:** [crates.io](https://crates.io/crates/resq-perf) · **API docs:** [docs.rs](https://docs.rs/resq-perf/0.1.16) + +Real-time CPU and memory performance TUI for ResQ platform + +## Overview + +[![Crates.io](https://img.shields.io/crates/v/resq-perf.svg)](https://crates.io/crates/resq-perf) +[![License](https://img.shields.io/crates/l/resq-perf.svg)](LICENSE) + +Real-time performance monitoring dashboard for ResQ services. Polls a service's `/status` endpoint and displays live memory usage, response latency, and heap object breakdowns in a three-column Ratatui TUI with sparkline history charts. + +## Architecture + +```mermaid +graph TB + subgraph Service["Target Service"] + EP["/admin/status endpoint
JSON response"] + end + + subgraph Polling["HTTP Polling Loop"] + CL["reqwest::blocking::Client
Bearer token auth"] + T["Tick Timer
100ms - 5000ms configurable"] + end + + subgraph State["Application State"] + SR["StatusResponse
deserialized JSON"] + MH["Memory History
VecDeque<u64> (120 samples)"] + LH["Latency History
VecDeque<u64> (120 samples)"] + EH["Error History
VecDeque (10 entries)"] + ST["Stats Counters
success / error counts"] + end + + subgraph TUI["Three-Column TUI"] + MC["Memory Panel
Heap gauge + RSS +
sparkline chart"] + LC["Latency Panel
Current / Avg / Min /
Max / P95 + sparkline"] + HC["Heap Objects Panel
Object counts +
type breakdown table"] + end + + T -->|"tick interval"| CL + CL -->|"GET + Bearer"| EP + EP -->|"JSON"| SR + SR --> MH & LH & ST + CL -->|"on error"| EH + MH --> MC + LH --> LC + SR --> HC + EH -->|"waiting screen"| TUI +``` + +## Installation + +```bash +# From workspace root +cargo build --release -p resq-perf + +# Binary location +target/release/resq-perf +``` + +## CLI Arguments + +| Argument / Flag | Type | Default | Description | +|----------------|------|---------|-------------| +| `url` (positional) | `String` | `http://localhost:3000/admin/status` | Service status endpoint URL to monitor | +| `--refresh-ms ` | `u64` | `500` | Refresh interval in milliseconds (clamped to 100-5000) | +| `-t`, `--token ` | `String` | `$RESQ_TOKEN` | Bearer token for authenticated endpoints | + +## Usage Examples + +```bash +# Monitor default HCE service (localhost:3000) +resq-perf + +# Target a specific service status URL +resq-perf http://localhost:5000/admin/status + +# Authenticated service with explicit token +resq-perf --token + +# Use environment variable for authentication +export RESQ_TOKEN="" +resq-perf http://localhost:3000/admin/status + +# Slower refresh rate (1 second) for low-bandwidth environments +resq-perf --refresh-ms 1000 + +# Fast refresh for detailed monitoring +resq-perf --refresh-ms 100 +``` + +## Metrics Reference + +### Status Endpoint Schema + +The tool expects JSON from the `/admin/status` endpoint matching this structure (compatible with `coordination-hce`): + +```json +{ + "uptime": "2h 15m 30s", + "uptimeNanoseconds": 8130000000000, + "version": "1.2.3", + "environment": "production", + "memory": { + "process": { + "rss": 104857600, + "heapUsed": 52428800, + "heapTotal": 67108864, + "external": 1048576, + "arrayBuffers": 524288 + }, + "heap": { + "heapSize": 67108864, + "heapCapacity": 83886080, + "extraMemorySize": 2097152, + "objectCount": 45000, + "protectedObjectCount": 1200, + "globalObjectCount": 350, + "protectedGlobalObjectCount": 50, + "objectTypeCounts": { + "Object": 15000, + "Array": 8000, + "Function": 5000, + "String": 12000 + } + } + } +} +``` + +### Displayed Metrics + +| Panel | Metric | Source Field | Description | +|-------|--------|-------------|-------------| +| Memory | Heap Gauge | `memory.process.heapUsed / heapTotal` | Percentage bar with color coding (green < 50%, yellow < 80%, red >= 80%) | +| Memory | RSS | `memory.process.rss` | Resident set size of the process | +| Memory | External | `memory.process.external` | Memory used by C++ objects bound to JS | +| Memory | Uptime | `uptimeNanoseconds` | Formatted as `Xh Xm Xs` | +| Memory | Version | `version` | Service version string | +| Memory | Sparkline | heap_used history | Rolling 120-sample chart of heap usage | +| Latency | Current | measured round-trip | Last HTTP request latency in ms | +| Latency | Average | computed | Mean of all samples in history | +| Latency | Min / Max | computed | Range across history window | +| Latency | P95 | computed | 95th percentile latency | +| Latency | Success Rate | success / total | Percentage of successful polls | +| Latency | Sparkline | latency history | Rolling 120-sample chart of response times | +| Heap Objects | Object Count | `memory.heap.objectCount` | Total objects on the V8 heap | +| Heap Objects | Protected | `memory.heap.protectedObjectCount` | GC-protected object count | +| Heap Objects | Global | `memory.heap.globalObjectCount` | Global scope object count | +| Heap Objects | Heap Size | `memory.heap.heapSize` | Current heap allocation | +| Heap Objects | Capacity | `memory.heap.heapCapacity` | Total heap capacity | +| Heap Objects | Type Table | `memory.heap.objectTypeCounts` | Top 12 object types sorted by count | + +## Environment Variables + +| Variable | Description | +|----------|-------------| +| `RESQ_TOKEN` | Bearer token for service authentication. Used when `--token` is not provided. | + +## Keybindings + +| Key | Action | +|-----|--------| +| `q` / `Esc` | Quit | +| `Ctrl+C` | Force quit | +| `p` | Pause / resume polling | +| `r` | Reset all history, counters, and error log | +| `+` / `=` | Increase refresh rate by 100ms (faster polling) | +| `-` / `_` | Decrease refresh rate by 100ms (slower polling) | +| `h` | Toggle help overlay panel | + +## TUI Layout + +``` ++-- ResQ Performance Monitor -- STATUS -- LATENCY ------------+ +| | +| +-- Memory --------+ +-- Response Time -+ +-- Heap Objects -+| +| | [======= ] 70% | | Current: 45ms | | Objects: 45000 || +| | RSS: 100.0 MiB | | Average: 52ms | | Protected: 1200 || +| | External: 1.0 MiB| | Min: 12ms | | Global: 350 || +| | Uptime: 2h 15m | | Max: 350ms | | Heap: 64.0 MiB || +| | Version: 1.2.3 | | P95: 120ms | | Capacity: 80 MiB|| +| | | | Success: 99.2% | | || +| | History (max: 64M)| | | | Type Count %|| +| | ......######## | | Latency (max:350)| | Object 15000 || +| | ....########## | | ..####..####.. | | String 12000 || +| +-------------------+ +------------------+ | Array 8000 || +| | Function 5000 || +| +-----------------+| ++--------------------------------------------------------------+ +| q quit p pause r reset +/- speed h help | S:142 E:1 500ms| ++--------------------------------------------------------------+ +``` + +## Configuration + +### Refresh Rate Bounds + +The refresh interval is clamped to the range **100ms - 5000ms**. The `+` and `-` keys adjust in 100ms increments at runtime. The initial value is set via `--refresh-ms` (default: 500ms). + +### History Depth + +Both memory and latency sparklines retain the most recent **120 samples** (`MAX_HISTORY`). At the default 500ms refresh rate, this covers approximately 60 seconds of data. The error history retains the last **10 entries**. + +### HTTP Client + +The built-in `reqwest::blocking::Client` has a **5-second timeout** per request. Authentication uses the `Authorization: Bearer ` header when a token is provided via `--token` or `RESQ_TOKEN`. + +### Latency Color Coding + +Response time in the header is color-coded: +- **Green**: < 50ms +- **Yellow**: 50-200ms +- **Red**: > 200ms + +## Related Tools + +- [`resq-logs`](https://github.com/resq-software/crates/blob/master/crates/resq-logs/README.md) -- Log aggregator and stream viewer +- [`resq-flame`](https://github.com/resq-software/crates/blob/master/crates/resq-flame/README.md) -- CPU flame graph profiler +- [`resq-health`](https://github.com/resq-software/crates/blob/master/crates/resq-health/README.md) -- Service health checker + +For comprehensive profiling workflows see [`docs/PROFILING_FLAMEGRAPH_GUIDE.md`](https://github.com/resq-software/crates/blob/master/docs/PROFILING_FLAMEGRAPH_GUIDE.md). + +## License + +Licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/resq-software/crates/blob/master/LICENSE) for details. + diff --git a/sdks/rust/api/resq-tui.md b/sdks/rust/api/resq-tui.md new file mode 100644 index 00000000..9adb91b1 --- /dev/null +++ b/sdks/rust/api/resq-tui.md @@ -0,0 +1,687 @@ +# resq-tui + +> **Version:** `v0.1.8` · **License:** `Apache-2.0` · **Crate:** [crates.io](https://crates.io/crates/resq-tui) · **API docs:** [docs.rs](https://docs.rs/resq-tui/0.1.8) + +Shared TUI components and themes for ResQ developer tools + +## Overview + +[![Crates.io](https://img.shields.io/crates/v/resq-tui.svg)](https://crates.io/crates/resq-tui) +[![License](https://img.shields.io/crates/l/resq-tui.svg)](LICENSE) + +Shared TUI component library for all **ResQ** developer tools. Provides a unified theme system, console formatters, table rendering, progress bars, spinners, and terminal lifecycle management built on [Ratatui](https://ratatui.rs) and [Crossterm](https://docs.rs/crossterm). + +## Overview + +`resq-tui` ensures every ResQ tool (`resq-logs`, `resq-perf`, `resq-flame`, `resq-health`, etc.) shares a consistent visual identity and interaction model. It provides two tiers of output: + +- **Full-screen TUI** -- Ratatui-based widgets (header, footer, tabs, popups) with a standardized theme for interactive terminal applications. +- **Non-TUI CLI** -- Styled console formatters, tables, progress bars, and spinners for traditional command-line output that gracefully degrade when piped or redirected. + +All styling is gated through environment detection so ANSI codes never bleed into pipes, redirects, or screen-reader environments. + +## Architecture + +```mermaid +graph TD + subgraph resq-tui + LIB["lib.rs
Theme, Widgets, Utilities"] + THEME["theme.rs
AdaptiveColor, Palette"] + DETECT["detect.rs
TTY, Color Mode, Accessibility"] + CONSOLE["console.rs
Styled Message Formatters"] + TABLE["table.rs
CLI Table Renderer"] + PROGRESS["progress.rs
CLI Progress Bar"] + SPINNER["spinner.rs
Threaded CLI Spinner"] + TERMINAL["terminal.rs
Init, Restore, Event Loop"] + end + + THEME --> DETECT + CONSOLE --> DETECT + CONSOLE --> THEME + TABLE --> DETECT + TABLE --> THEME + PROGRESS --> DETECT + PROGRESS --> THEME + SPINNER --> DETECT + LIB --> THEME + + subgraph Consumers + LOGS["resq-logs"] + PERF["resq-perf"] + FLAME["resq-flame"] + HEALTH["resq-health"] + BIN["resq-bin"] + CLEAN["resq-clean"] + end + + LOGS --> LIB + PERF --> LIB + FLAME --> LIB + HEALTH --> LIB + BIN --> LIB + CLEAN --> LIB +``` + +### Module dependency flow + +```mermaid +flowchart LR + detect.rs -->|ColorMode| theme.rs + theme.rs -->|AdaptiveColor| console.rs + theme.rs -->|AdaptiveColor| table.rs + theme.rs -->|AdaptiveColor| progress.rs + detect.rs -->|should_style| console.rs + detect.rs -->|should_style| table.rs + detect.rs -->|should_style| progress.rs + detect.rs -->|should_style / is_tty| spinner.rs + lib.rs -->|re-exports| theme.rs + terminal.rs -->|crossterm + ratatui| lib.rs +``` + +## Installation + +Add to your `Cargo.toml`: + +```toml +[dependencies] +resq-tui = { workspace = true } +``` + +Or from crates.io: + +```toml +[dependencies] +resq-tui = "0.1.4" +``` + +## Module Reference + +### `lib.rs` -- Core Widgets and Utilities + +The root module re-exports `crossterm` and `ratatui` for convenience and provides the original `Theme` struct alongside shared TUI drawing functions. + +#### `Theme` (root) + +The original hardcoded dark-palette theme struct, retained for backward compatibility. For new code, prefer `theme::Theme::adaptive()` (see below). + +| Field | Type | Default | Description | +|-------------|---------|----------------|-------------------------------| +| `primary` | `Color` | `Cyan` | Primary brand color | +| `secondary` | `Color` | `Blue` | Secondary supporting color | +| `accent` | `Color` | `Magenta` | Metadata accent | +| `success` | `Color` | `Green` | Success state | +| `warning` | `Color` | `Yellow` | Warning / pending state | +| `error` | `Color` | `Red` | Error / critical state | +| `bg` | `Color` | `Black` | Background | +| `fg` | `Color` | `White` | Foreground text | +| `highlight` | `Color` | `Rgb(50,50,50)`| Selection highlight | +| `inactive` | `Color` | `DarkGray` | Muted / inactive elements | + +#### Widget Functions + +##### `draw_header` + +Renders a standardized header bar with service name, status badge, PID, and URL. + +```rust +use resq_tui::{self as tui, Theme}; + +fn draw(f: &mut ratatui::Frame, area: ratatui::layout::Rect) { + let theme = Theme::default(); + tui::draw_header( + f, + area, + "My-Explorer", + "READY", + theme.success, + Some(1234), // PID (or None) + "http://localhost:3000", + &theme, + ); +} +``` + +**Signature:** +```rust +pub fn draw_header( + frame: &mut Frame, + area: Rect, + title: &str, + status: &str, + status_color: Color, + pid: Option, + url: &str, + theme: &Theme, +) +``` + +##### `draw_footer` + +Renders a keyboard-shortcut footer bar. + +```rust +tui::draw_footer( + f, + area, + &[("Q", "Quit"), ("Tab", "Focus"), ("Up/Down", "Navigate")], + &theme, +); +``` + +**Signature:** +```rust +pub fn draw_footer(frame: &mut Frame, area: Rect, keys: &[(&str, &str)], theme: &Theme) +``` + +##### `draw_tabs` + +Renders a tab bar with selection highlight. Uses the default theme internally. + +```rust +tui::draw_tabs(f, area, vec!["Overview", "Details", "Logs"], 0); +``` + +**Signature:** +```rust +pub fn draw_tabs(frame: &mut Frame, area: Rect, titles: Vec<&str>, selected: usize) +``` + +##### `draw_popup` + +Renders a centered modal overlay for help dialogs or error messages. + +```rust +use ratatui::text::Line; + +tui::draw_popup( + f, + area, + "Help", + &[Line::raw("Press Q to quit"), Line::raw("Press ? for help")], + 60, // percent_x + 40, // percent_y + &theme, +); +``` + +**Signature:** +```rust +pub fn draw_popup( + frame: &mut Frame, + area: Rect, + title: &str, + lines: &[Line], + percent_x: u16, + percent_y: u16, + theme: &Theme, +) +``` + +##### `centered_rect` + +Helper that computes a centered `Rect` given percentage dimensions. Used internally by `draw_popup`. + +```rust +let popup_area = tui::centered_rect(60, 40, area); +``` + +#### Utility Functions + +##### `format_bytes` + +Converts a byte count to a human-readable string using binary units (KiB, MiB, GiB). + +```rust +use resq_tui::format_bytes; + +assert_eq!(format_bytes(0), "0 B"); +assert_eq!(format_bytes(1024), "1.0 KiB"); +assert_eq!(format_bytes(5242880), "5.0 MiB"); +assert_eq!(format_bytes(1073741824), "1.00 GiB"); +``` + +##### `format_duration` + +Converts seconds to a human-readable duration string. + +```rust +use resq_tui::format_duration; + +assert_eq!(format_duration(45), "45s"); +assert_eq!(format_duration(125), "2m 5s"); +assert_eq!(format_duration(3661), "1h 1m 1s"); +assert_eq!(format_duration(90061), "1d 1h 1m"); +``` + +##### `SPINNER_FRAMES` + +Braille animation frames for TUI spinner widgets: + +```rust +pub const SPINNER_FRAMES: &[&str] = &["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; +``` + +--- + +### `theme` -- Adaptive Color System + +The theme module provides a Dracula-inspired adaptive color palette that switches between light and dark variants based on terminal environment detection. + +#### `AdaptiveColor` + +A color pair with `light` and `dark` variants that resolves at runtime via `detect_color_mode()`. + +```rust +use resq_tui::theme::{AdaptiveColor, COLOR_PRIMARY}; +use ratatui::style::Color; + +let resolved: Color = COLOR_PRIMARY.resolve(); +``` + +| Method | Returns | Description | +|-------------|---------|--------------------------------------------------| +| `resolve()` | `Color` | Returns the appropriate variant for the terminal | + +#### Palette Constants + +| Constant | Dark (Dracula) | Light | Usage | +|------------------------|-------------------------|-------------------------|-------------------------| +| `COLOR_PRIMARY` | `Rgb(139, 233, 253)` | `Rgb(0, 139, 139)` | Brand / primary accent | +| `COLOR_SECONDARY` | `Rgb(189, 147, 249)` | `Rgb(68, 71, 144)` | Supporting elements | +| `COLOR_ACCENT` | `Rgb(255, 121, 198)` | `Rgb(163, 55, 136)` | Metadata / PID | +| `COLOR_SUCCESS` | `Rgb(80, 250, 123)` | `Rgb(40, 130, 40)` | Success states | +| `COLOR_WARNING` | `Rgb(241, 250, 140)` | `Rgb(180, 120, 0)` | Warning states | +| `COLOR_ERROR` | `Rgb(255, 85, 85)` | `Rgb(215, 55, 55)` | Error states | +| `COLOR_FG` | `Rgb(248, 248, 242)` | `Rgb(40, 42, 54)` | Foreground text | +| `COLOR_BG` | `Rgb(40, 42, 54)` | `Rgb(248, 248, 242)` | Background | +| `COLOR_INACTIVE` | `Rgb(98, 114, 164)` | `Rgb(140, 140, 140)` | Muted / comments | +| `COLOR_HIGHLIGHT` | `Rgb(68, 71, 90)` | `Rgb(230, 230, 230)` | Selection background | +| `COLOR_PROGRESS_START` | `Rgb(189, 147, 249)` | `Rgb(100, 60, 180)` | Progress bar fill start | +| `COLOR_PROGRESS_END` | `Rgb(139, 233, 253)` | `Rgb(0, 139, 139)` | Progress bar fill end | +| `COLOR_PROGRESS_EMPTY` | `Rgb(98, 114, 164)` | `Rgb(200, 200, 200)` | Progress bar empty | + +#### `Theme` (theme module) + +Extended theme struct with adaptive color support. + +| Constructor | Description | +|-----------------|-------------------------------------------------------------------| +| `Theme::adaptive()` | Resolves all colors via `AdaptiveColor::resolve()` (recommended) | +| `Theme::default()` | Hardcoded dark palette for backward compatibility | + +```rust +use resq_tui::theme::Theme; + +// Recommended: adapts to terminal background +let theme = Theme::adaptive(); + +// Legacy: always dark +let theme = Theme::default(); +``` + +--- + +### `detect` -- Terminal Environment Detection + +Detects TTY status, color support, and accessibility mode. All detection is cached per-process via `OnceLock`. + +#### Environment Variables + +| Variable | Effect when set | +|--------------|--------------------------------------------------| +| `NO_COLOR` | Disables all ANSI styling ([no-color.org](https://no-color.org)) | +| `TERM=dumb` | Disables all ANSI styling | +| `ACCESSIBLE` | Enables screen-reader / accessible mode | +| `COLORFGBG` | Used to detect light vs dark terminal background | + +#### `ColorMode` + +```rust +pub enum ColorMode { + Dark, // Dark terminal background (default assumption) + Light, // Light terminal background + None, // No color support +} +``` + +#### Public Functions + +| Function | Returns | Description | +|-----------------------|-------------|--------------------------------------------------------| +| `is_tty_stdout()` | `bool` | Whether stdout is a TTY | +| `is_tty_stderr()` | `bool` | Whether stderr is a TTY | +| `is_accessible_mode()`| `bool` | Whether accessible / plain output is requested | +| `should_style()` | `bool` | Master gate -- all console formatters check this | +| `detect_color_mode()`| `ColorMode` | Resolved color mode for adaptive color selection | + +--- + +### `console` -- Styled Message Formatters + +TTY-gated console formatters for non-TUI CLI output. Diagnostics go to stderr, structured data to stdout. All styling respects `detect::should_style()`. + +#### Format Functions (return `String`) + +| Function | Prefix | Color | Usage | +|---------------------------|--------|-----------|------------------------------| +| `format_success(msg)` | `✅` | Success | Completion messages | +| `format_error(msg)` | `❌` | Error | Error messages (bold) | +| `format_warning(msg)` | `⚠️` | Warning | Warning messages | +| `format_info(msg)` | `ℹ️` | Primary | Informational messages | +| `format_command(cmd)` | `▶` | Secondary | Command references (bold) | +| `format_progress(msg)` | `⏳` | Warning | In-flight operations | +| `format_prompt(msg)` | `?` | Primary | Interactive prompts (bold) | +| `format_verbose(msg)` | -- | Dim | Debug / verbose output | +| `format_list_item(msg)` | ` •` | -- | Indented list items | +| `format_section_header(h)`| `━━━` | Primary | Section dividers with rule | +| `format_count(msg)` | `📊` | Accent | Metrics / counts | +| `format_location(msg)` | `📁` | Secondary | File paths / locations | +| `format_list_header(h)` | -- | FG (bold) | List / section headers | +| `format_search(msg)` | `🔍` | Primary | Search / scan operations | + +#### Print Functions (write to stderr) + +Convenience wrappers that call the corresponding `format_*` function and print to stderr: + +```rust +use resq_tui::console; + +console::success("Deployment complete"); +console::error("Connection refused"); +console::warning("Certificate expires soon"); +console::info("Scanning 42 services"); +console::progress("Uploading artifacts..."); +console::verbose("Retry attempt 3/5"); +console::section("Results"); +``` + +--- + +### `table` -- CLI Table Renderer + +Renders styled tables to stderr with zebra-striped rows, auto-computed column widths, and adaptive colors. Falls back to plain aligned text when styling is disabled. + +#### `Align` + +```rust +pub enum Align { + Left, // Default alignment + Right, // Right-aligned (for numeric columns) +} +``` + +#### `Column` + +Builder for table column definitions. + +| Method | Description | +|-----------------------|---------------------------------------| +| `Column::new(header)` | Left-aligned column | +| `Column::right(header)`| Right-aligned column | +| `.width(w)` | Sets minimum column width | + +#### `render_table` + +Renders a complete table to stderr. + +```rust +use resq_tui::table::{Column, render_table}; + +let columns = vec![ + Column::new("Service"), + Column::right("Latency"), + Column::new("Status").width(10), +]; + +let rows = vec![ + vec!["api".into(), "12ms".into(), "healthy".into()], + vec!["worker".into(), "340ms".into(), "degraded".into()], + vec!["cache".into(), "2ms".into(), "healthy".into()], +]; + +render_table(&columns, &rows); +``` + +Output (styled): +``` + Service Latency Status + ─────── ─────── ────────── + api 12ms healthy + worker 340ms degraded ← dimmed (zebra stripe) + cache 2ms healthy +``` + +--- + +### `progress` -- CLI Progress Bar + +Non-TUI progress bar rendered to stderr with adaptive gradient colors. Falls back to plain ASCII in non-TTY mode. + +#### `ProgressBar` + +| Method | Description | +|--------------------------------|---------------------------------------------------| +| `ProgressBar::new(msg, width)` | Creates a progress bar with message and width | +| `.render(fraction)` | Renders at the given fraction (0.0 to 1.0) | +| `.finish()` | Ends the bar with a newline | +| `.finish_with_message(msg)` | Clears the bar and prints a final message | + +```rust +use resq_tui::progress::ProgressBar; + +let pb = ProgressBar::new("Downloading", 40); +for i in 0..=100 { + pb.render(i as f64 / 100.0); +} +pb.finish_with_message("✅ Download complete"); +``` + +TTY output: `Downloading ████████████████░░░░░░░░░░░░░░░░░░░░░░░░ 40%` + +Non-TTY output: `Downloading [################------------------------] 40%` + +--- + +### `spinner` -- Threaded CLI Spinner + +Thread-safe stderr spinner that respects TTY and accessibility settings. Uses braille animation by default with a plain-dots fallback. + +#### `SPINNER_FRAMES` + +Braille frames used by both the TUI spinner constant and the non-TUI `Spinner`: + +```rust +pub const SPINNER_FRAMES: &[&str] = &["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; +``` + +#### `Spinner` + +| Method | Description | +|-------------------------------|-------------------------------------------------| +| `Spinner::start(msg)` | Starts the spinner in a background thread | +| `.stop_with_message(msg)` | Stops and prints a final message | +| `.stop()` | Stops without a final message | + +The spinner is also stopped automatically on `Drop`. + +```rust +use resq_tui::spinner::Spinner; + +let spinner = Spinner::start("Fetching service health"); +// ... long-running operation ... +spinner.stop_with_message("✅ Health check complete"); +``` + +In non-TTY mode, `start()` prints `"Fetching service health..."` once and returns immediately. + +--- + +### `terminal` -- Terminal Lifecycle Management + +Manages raw mode, alternate screen, and provides a standard event loop for Ratatui applications. + +#### Type Alias + +```rust +pub type Term = Terminal>; +``` + +#### `init() -> anyhow::Result` + +Enables raw mode, enters the alternate screen, and returns an initialized `Term`. + +#### `restore()` + +Leaves the alternate screen and disables raw mode. Safe to call even in a partially-initialized state. + +#### `TuiApp` Trait + +Implement this trait on your application state to use `run_loop`. + +```rust +pub trait TuiApp { + fn draw(&mut self, frame: &mut ratatui::Frame); + fn handle_key(&mut self, key: crossterm::event::KeyEvent) -> anyhow::Result; +} +``` + +Return `false` from `handle_key` to exit the event loop. `Ctrl+C` always exits. + +#### `run_loop` + +Runs a standard TUI event loop. `poll_ms` controls input polling frequency. + +```rust +pub fn run_loop( + terminal: &mut Term, + poll_ms: u64, + app: &mut dyn TuiApp, +) -> anyhow::Result<()> +``` + +--- + +## Integration Guide + +### Building a new ResQ TUI tool + +1. **Add the dependency** to your crate's `Cargo.toml`: + +```toml +[dependencies] +resq-tui = { workspace = true } +``` + +2. **Implement `TuiApp`** on your application state: + +```rust +use resq_tui::terminal::TuiApp; +use resq_tui::theme::Theme; +use resq_tui::{draw_header, draw_footer}; +use ratatui::layout::{Constraint, Layout}; + +struct MyApp { + theme: Theme, +} + +impl TuiApp for MyApp { + fn draw(&mut self, frame: &mut ratatui::Frame) { + let area = frame.area(); + let chunks = Layout::vertical([ + Constraint::Length(3), // header + Constraint::Min(1), // body + Constraint::Length(3), // footer + ]) + .split(area); + + draw_header( + frame, chunks[0], + "My-Tool", "RUNNING", self.theme.success, + None, "localhost:8080", &self.theme, + ); + + // ... render your body content in chunks[1] ... + + draw_footer( + frame, chunks[2], + &[("Q", "Quit"), ("Tab", "Switch"), ("?", "Help")], + &self.theme, + ); + } + + fn handle_key( + &mut self, + key: crossterm::event::KeyEvent, + ) -> anyhow::Result { + use crossterm::event::KeyCode; + match key.code { + KeyCode::Char('q') => Ok(false), + _ => Ok(true), + } + } +} +``` + +3. **Run the event loop** in `main`: + +```rust +fn main() -> anyhow::Result<()> { + let mut terminal = resq_tui::terminal::init()?; + let mut app = MyApp { + theme: Theme::adaptive(), + }; + + let result = resq_tui::terminal::run_loop(&mut terminal, 100, &mut app); + resq_tui::terminal::restore(); + result +} +``` + +### Using non-TUI console output + +For CLI tools that do not need a full-screen TUI: + +```rust +use resq_tui::console; +use resq_tui::table::{Column, render_table}; +use resq_tui::progress::ProgressBar; +use resq_tui::spinner::Spinner; + +fn main() { + console::section("Service Health"); + + let spinner = Spinner::start("Checking services"); + // ... check services ... + spinner.stop_with_message("✅ All services checked"); + + let columns = vec![ + Column::new("Service"), + Column::right("Latency"), + Column::new("Status"), + ]; + let rows = vec![ + vec!["api".into(), "12ms".into(), "healthy".into()], + ]; + render_table(&columns, &rows); + + let pb = ProgressBar::new("Deploying", 30); + for i in 0..=100 { + pb.render(i as f64 / 100.0); + } + pb.finish_with_message(&console::format_success("Deployed")); +} +``` + +## Accessibility + +`resq-tui` respects the following standards: + +- **`NO_COLOR`** ([no-color.org](https://no-color.org)) -- disables all ANSI color codes +- **`TERM=dumb`** -- plain text output only +- **`ACCESSIBLE`** -- activates screen-reader-friendly output (plain dot spinners, no animation) +- Non-TTY pipes and redirects receive unstyled output automatically + +## License + +Licensed under the Apache License, Version 2.0. See [LICENSE](https://github.com/resq-software/crates/blob/master/crates/LICENSE) for details. +