Консольный клиент с текстовым интерфейсом (TUI) на Rust. Загружает иерархическое меню с сервера и позволяет запускать bash-скрипты, скачивать файлы и выполнять HTTP-запросы прямо из терминала. Все диалоги (выбор из списка, подтверждение, ввод текста) реализованы внутри интерфейса — никаких сырых `read -p` в терминале.
Консольный клиент с текстовым интерфейсом (TUI) на Rust. Загружает иерархическое меню с сервера и позволяет запускать bash-скрипты, скачивать файлы и выполнять HTTP-запросы прямо из терминале. Все диалоги (выбор из списка, подтверждение, ввод текста) реализованы внутри интерфейса — никаких сырых `read -p` в терминале.
---
## Навигация
### Главное меню
| Клавиша | Действие |
|---|---|
| `↑` / `↓` | Перемещение по списку |
| `Enter` | Войти в категорию / запустить действие |
| `Esc` | Выйти из категории / закрыть popup / отменить скрипт |
| `↑` / `↓` или `k` / `j` | Перемещение по списку |
| `Enter` или `l` | Войти в категорию / запустить действие |
| `Esc` или `h` | Выйти из категории |
| `q` | Выйти из приложения |
| `R` | Перезагрузить меню с сервера |
В попапе запущенного скрипта:
### Popup запущенного скрипта
| Клавиша | Действие |
|---|---|
| `↑` / `↓` | Прокрутка лога (если нет активного запроса) / навигация по селектору |
| `timeout_sec` | Таймаут HTTP-запросов в секундах |
| `update_api` | Базовый URL Gitea API для проверки обновлений (опционально) |
---
## Автообновление
Если задан `update_api`, при каждом запуске клиент в фоне проверяет наличие нового релиза в Gitea. Если найдена новая стабильная версия — показывает диалог:
```
Доступно обновление
1.0.0 → 1.1.0
Размер: 4.2 МБ
[Y / l] Обновить [N / h / Esc] Пропустить
```
При подтверждении скачивает бинарник, атомарно заменяет текущий исполняемый файл и перезапускает приложение через `execv` (процесс не пересоздаётся, PID остаётся тем же).
### Naming convention ассетов в Gitea
Файлы релиза должны называться по шаблону `{name}-{os}-{arch}`:
| Файл | Платформа |
|---|---|
| `ostiary-linux-x86_64` | Linux 64-bit |
| `ostiary-linux-aarch64` | Linux ARM64 |
| `ostiary-macos-aarch64` | macOS Apple Silicon |
| `ostiary-macos-x86_64` | macOS Intel |
---
## Формат меню (JSON)
Сервер должен отдавать`GET /api/menu`с`Content-Type: application/json`.
| `confirm_message` | строка | Кастомный текст диалога подтверждения |
**`interaction: "terminal"`** — скрипт запускается как дочерний процесс, вывод игнорируется клиентом. Подходит для простых неинтерактивных команд.
**`interaction: "terminal"`** — скрипт запускается дочерним процессом без захвата вывода.
**`interaction: "structured"`** — скрипт общается с клиентом через протокол команд (см. раздел ниже). Весь вывод отображается в прокручиваемом логе с поддержкой ANSI-цветов. Поддерживает интерактивные элементы: селекторы, поля ввода, подтверждения.
**`interaction: "structured"`** — весь вывод отображается в прокручиваемом логе с ANSI-цветами, скрипт может запрашивать ввод через протокол команд.
### `download` — скачивание файла
@@ -156,12 +194,6 @@ selected_bg = "blue"
}
```
| Параметр | Описание |
|---|---|
| `url` | Адрес файла |
| `filename` | Имя сохраняемого файла (по умолчанию — из URL) |
| `target_dir` | Директория сохранения (по умолчанию — текущая) |
### `download_and_run` — скачать и выполнить
```json
@@ -174,11 +206,6 @@ selected_bg = "blue"
}
```
| Параметр | Описание |
|---|---|
| `run_args` | Аргументы командной строки |
| `keep_file` | Оставить файл после выполнения (по умолчанию `false`) |
### `http_request` — HTTP-запрос
```json
@@ -186,10 +213,7 @@ selected_bg = "blue"
"type":"http_request",
"method":"POST",
"url":"https://api.example.com/deploy",
"headers":{
"Authorization":"Bearer token123",
"Content-Type":"application/json"
},
"headers":{"Authorization":"Bearer token123"},
"body":"{\"env\": \"production\"}",
"confirm":true
}
@@ -199,12 +223,10 @@ selected_bg = "blue"
## Интерактивные скрипты (structured)
При `interaction: "structured"` скрипт может запрашивать у пользователя данные через специальный протокол. Клиент показывает соответствующий элемент интерфейса ratatui и ждёт ответа.
При `interaction: "structured"` скрипт общается с клиентом через протокол команд. Команды отправляются в **stderr** (`>&2`), ответы приходят в **stdin**.
### Базовые хелперы
Добавьте эти функции в начало каждого интерактивного скрипта:
```bash
#!/bin/bash
@@ -215,21 +237,16 @@ ask() {
printf'%s'"$_response"
}
# Отправить уведомление (не ждёт ответа)
# Отправить уведомление (не ждёт ответа, не блокирует скрипт)
notify(){
printf'CMD:%s\n'"$1" >&2
}
```
Команды отправляются в **stderr** (`>&2`), ответы приходят в **stdin** через `read`. Это позволяет использовать `$(ask '...')` для захвата результата.
---
### Ввод текста (`input`)
Показывает текстовое поле с заголовком. Поддерживает маскировку для паролей.
**Команда:**
```json
{"type":"input","prompt":"Введите имя пользователя:","default":"admin","secret":false}
```
@@ -240,20 +257,17 @@ notify() {
| `default` | Значение по умолчанию (опционально) |
| `secret` | Если `true` — символы заменяются на `•` |
Временно **передаёт терминал** внешней программе (mysql, vim, htop и т.д.). Клиент скрывает ratatui, программа работает на полном экране, после завершения TUI восстанавливается. Возвращает код завершения.
Временно **передаёт терминал** внешней программе (mysql, vim, htop и др.). Клиент скрывает TUI, программа работает на полном экране, после завершения TUI восстанавливается. Возвращает код завершения.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.