- JavaScript 75.7%
- Shell 13.7%
- CSS 7.8%
- HTML 2.8%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| deploy | ||
| docs | ||
| public | ||
| src | ||
| test | ||
| .gitignore | ||
| package.json | ||
| README.md | ||
| web-monitor-prompt.md | ||
watcherenish
Web-интерфейс для мониторинга coding-агента pi
на этой машине: сессии, статистика (токены, стоимость, время tool-вызовов), полный
транскрипт любой сессии и хвост gate.log. Только чтение — сервис ничего не пишет
ни в ~/.pi/agent, ни в логи.
Возможности (этап 1, MVP)
- Дашборд: всего сессий / активных сейчас (mtime < TTL) / за сегодня, токены и стоимость за сегодня, последняя активность.
- Список сессий: поиск (имя / путь / модель / id), пагинация, сортировка по mtime.
- Детали сессии: транскрипт — user/assistant текстом, thinking свёрнут, каждый
tool-вызов — сворачиваемый блок (имя, длительность, аргументы, результат, ошибки
подсвечены красным); панель метрик (токены, cost, модели, длительность, ошибки,
compactions). Для обрезанных
toolResultсfullOutputPathподгружается полный вывод. - Лог gate: хвост
gate.log(N строк), поиск по подстроке, обновление кнопкой. Если файла нет — интерфейс сообщает об этом и не падает.
Сессии читаются из ~/.pi/agent/sessions/--<encoded-cwd>--/<timestamp>_<uuid>.jsonl
(формат v3). Битые/незавершённые строки JSONL пропускаются с warning — агент может
писать файл прямо сейчас.
Установка
Требуется Linux с systemd; Node.js ≥ 20 установщик поставит сам, если его нет. Зависимостей нет — только стандартная библиотека.
Одна команда — скачивание и установка (идемпотентно: повторный запуск обновляет код и рестартует сервис):
curl -fsSL http://10.10.1.7:3000/forgejo-admin/watcherenish/raw/branch/main/deploy/install.sh | sudo bash
Скрипт deploy/install.sh проверяет окружение, при необходимости ставит Node.js ≥ 20,
клонирует/обновляет код в /opt/watcherenish, гоняет npm test, генерирует
systemd-юнит и конфиг /etc/default/pi-web-monitor (при первой установке создаёт
AUTH_TOKEN и печатает его в итоговом статусе), запускает сервис и ждёт
GET /api/health. В конце — статус об успешной/неуспешной установке. Конфиг при
повторных установках не перетирается — ручные правки и токен сохраняются. Все пути
и параметры переопределяются переменными окружения (INSTALL_DIR, INSTALL_USER,
PORT, BIND, SESSIONS_DIR, GATE_LOG и др. — см. шапку deploy/install.sh).
Вручную (если хочется контролировать каждый шаг):
# на Linux-машине
git clone http://10.10.1.7:3000/forgejo-admin/watcherenish.git /opt/watcherenish
cd /opt/watcherenish
npm test # 33 теста: парсер, конфиг, API, logtail
npm start # запустить вручную: http://127.0.0.1:8787
Конфигурация (переменные окружения)
| Переменная | По умолчанию | Описание |
|---|---|---|
PORT |
8787 |
порт HTTP |
BIND |
127.0.0.1 |
адрес; 0.0.0.0/:: требует AUTH_TOKEN, иначе сервер откажется стартовать |
AUTH_TOKEN |
— | если задан — все /api/* требуют Authorization: Bearer <token> (страницы UI отдаются без токена, токен вводится в UI) |
SESSIONS_DIR |
~/.pi/agent/sessions |
каталог сессий |
GATE_LOG |
/var/log/pi-agent/gate.log |
лог gate-проверок |
GATE_LINE_REGEX |
— | регэксп для разбора строк лога (этап 3) |
ACTIVE_SESSION_TTL_MIN |
15 |
окно «активна сейчас» по mtime, минуты |
ALLOWED_ORIGINS |
— | список origin через запятую, которым разрешён CORS-доступ к /api/* (например http://win-pc:5173,https://hub.local); не задан — same-origin режим, CORS-заголовки не отдаются |
systemd
deploy/install.sh делает всё нижеперечисленное автоматически: юнит генерируется из
deploy/pi-web-monitor.service (подставляются User=, WorkingDirectory=, путь к
node), а все переменные окружения выносятся в EnvironmentFile=/etc/default/pi-web-monitor.
Вручную:
sudo cp deploy/pi-web-monitor.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now pi-web-monitor
systemctl status pi-web-monitor
Проверка живости (например, из мониторинга или UI-хаба):
curl -s -H "Authorization: Bearer $AUTH_TOKEN" http://127.0.0.1:8787/api/health
# {"status":"ok","sessionsDir":"/home/pi/.pi/agent/sessions","sessionsDirExists":true,"uptimeMs":...}
Юнит запускает сервис от пользователя pi (поправьте User=/WorkingDirectory=
под себя) с hardening: ProtectSystem=strict, ProtectHome=read-only — сервис
физически не может писать в ~/.pi.
API
GET /api/health— healthcheck (та же Bearer-авторизация):200{ status: ok|degraded, sessionsDir, sessionsDirExists, uptimeMs }; нужен для подключения удалённых агентов из UI-хаба.GET /api/summary— счётчики, токены/cost за сегодня, последняя активность.GET /api/sessions?limit=&offset=&search=— список с метриками, mtime desc.GET /api/sessions/:id— метаданные + все entries (id, parentId, type, timestamp, role, превью) — дерево в порядке следования.GET /api/sessions/:id/messages— линейный транскрипт для рендера (tool-вызовы связаны поtoolCallIdс длительностью и аргументами).GET /api/logs/gate?tail=500— строки лога (отдаётexists:false+ ошибку, если файл недоступен).
Безопасность
- По умолчанию слушает только
127.0.0.1; доступ снаружи — через SSH-туннель (ssh -L 8787:127.0.0.1:8787 user@host) или Tailscale. BIND=0.0.0.0безAUTH_TOKEN— ошибка запуска.- Транскрипты содержат содержимое файлов и вывод команд — не публикуйте UI в интернет.
- В файловую систему pi сервис не пишет (проверено hardening'ом юнита и кодом:
только
fs.readFile/createReadStream).
Структура
src/
server.js HTTP-сервер, роуты, статика (node:http, без зависимостей)
parser.js парсер JSONL-сессий, агрегация метрик, кэш по mtime
config.js env + дефолты + валидация
logtail.js хвост лог-файла (чтение с конца)
public/ UI: vanilla JS + CSS, без сборки и CDN
test/ фикстуры + node --test (parser, config, api, logtail)
deploy/ systemd unit + install.sh (идемпотентный установщик «одной командой»)
Дорожная карта (этапы 2–4 из web-monitor-prompt.md)
Этап 2 — live-обновления (fs.watch + SSE), этап 3 — метрики gate-проверок по
GATE_LINE_REGEX, этап 4 — RPC-мост/collector. Реализуются по отдельному указанию.