packer-commander
v0.4.1
Published
TUI-раннер npm-скриптов монорепозитория: живые статусы задач, логи, поиск и пайплайны GitLab
Maintainers
Readme
packer-commander
TUI-раннер npm-скриптов монорепозитория — в духе mc: две колонки, живые статусы задач, логи рядом со списком, поиск по логу и пайплайны GitLab.
┌ Задачи ──────────────────────┬ build • режим: Watch • /core • 15 ──────────┐
│ ▶ Команды │ apps/core/analytics (ssmm-core-analytics) │
│ build │ apps/core/auth (ssmm-core-auth) │
│ serve │ apps/core/payment (ssmm-core-payment) │
│ ● Запущено (2) │ │
│ ● apps/api build 0:12 │ │
│ ✓ Завершено (1) │ │
│ ✗ libs/core test exit 1 │ │
│ ⚙ Пайплайны master (2) │ │
│ ● #5 running │ │
└──────────────────────────────┴─────────────────────────────────────────────┘
Запущено: 2 Готово: 0 Ошибок: 1 │ Tab/←→ колонки Enter выбрать ? помощьЗапуск
Без установки:
npx packer-commanderГлобально:
npm i -g packer-commanderДальше packer-commander или короткое pc в любой папке репозитория.
Что делает
- Находит корень проекта сам. Поднимается от текущей папки: монорепо с
workspacesважнее ближайшегоpackage.json, дальше.gitне уходит. Запуск изapps/apiвидит весь репозиторий. - Папки воркспейсов берёт из
workspaces—apps/*→apps. Нетworkspaces— пробуетapps,libs,packages,services; нет и их — работает с одиночным пакетом (запуск без--workspace). - Показывает статусы живыми. Таймеры и статусы обновляются сами, вывод не смешивается с интерфейсом.
- Держит лог рядом. Курсор на команде — справа её сервисы, курсор на задаче — её лог, курсор на пайплайне — его джобы.
- Ищет по логу —
/, дальшеnиNпо совпадениям, с подсветкой. Работает и по трассе джобы GitLab. - Никаких новых зависимостей, кроме
blessed.
Клавиши
| Клавиша | Что делает |
|---|---|
| Tab, ←, → | переключить колонку |
| ↑, ↓ | курсор в списке или скролл лога |
| Enter | команда → её сервисы, сервис → запуск, задача → лог, пайплайн → джобы, джоба → трасса |
| Пробел | режим запуска: Обычный → Watch → В терминале |
| s, S | остановить выбранную задачу / все; на пайплайне — отменить его |
| d | забыть завершённую задачу |
| i | детали задачи |
| t | показать или скрыть таймстемпы |
| y | скопировать лог или трассу в буфер обмена (без разметки) |
| z | лог на весь экран без рамок — чтобы выделять мышью только его |
| / | поиск по логу, Escape — снять |
| p | запустить пайплайн на текущей ветке (спросит подтверждение) |
| r | пересканировать воркспейсы и обновить пайплайны |
| Backspace | назад |
| ? | все клавиши |
| q, Ctrl+C | выход; при живых задачах спросит подтверждение |
Как скопировать часть лога
Терминал выделяет мышью прямоугольник поперёк всего экрана, поэтому в двух колонках в выделение неизбежно попадает левое меню. Два способа обойти:
z— лог разворачивается на весь экран без рамок и меню. Выделяется только текст лога. Повторноеzвозвращает две колонки, состояние прокрутки и поиска сохраняется.y— весь лог (или трасса джобы) уходит в буфер обмена без разметки: сначала пробуется системная утилита (clip,pbcopy,xclip), затем OSC 52, который работает и через ssh. Если включены таймстемпы поt, они попадут в копию.
Полезно и то, что в обычном режиме между рамкой и текстом есть отступ — Ctrl+click
по src/app.ts:12:5 в VS Code открывает файл, а не тащит │ внутрь ссылки.
Каталог проектов
Если в текущей папке лежат несколько проектов — как /opt на сервере, — слева
появляется секция 📦 Проекты: первая строка сам корень, дальше подпапки, в которых
есть compose-файл, makefile, *.sh или package.json со скриптами. Курсор на проекте
— справа плоский список запускаемого, отсортированный по типу:
▸ контейнеры 12/14
make up
make down
sh check.sh
sh checkmig.sh
npm buildБуквы фильтруют весь список сразу: che находит check.sh и checkmig.sh. Enter
на строке контейнеров уводит в список контейнеров этого проекта, Esc возвращает.
Enter на make, скрипте или npm открывает меню:
- Запустить (задачей, с логом) — обычная задача: лог рядом, поиск по
/, стоп поsс убийством дерева процессов. - Запустить в терминале — TUI сворачивается, команда получает настоящий терминал.
Нужно для всего интерактивного: задачи идут со
stdin: ignore, и скрипт с вопросомContinue? [y/N]в задаче просто повиснет.
Перед запуском показывается точная команда и рабочая папка, и спрашивается
подтверждение — всегда, без списка «безопасных» имён: отличить check.sh от
clear-docker.sh по имени нельзя.
Сканируется один уровень вниз: рекурсия по /opt уперлась бы в тома docker и
логи. Цели make читаются из файла, make -qp не вызывается — он разбирает всё
окружение. Скрипты запускаются как bash <файл>: бита +x может не быть, а sh не
понимает bash-измов.
Состояние контейнеров опрашивается только для проекта под курсором — 35 проектов не
превращаются в 35 вызовов docker compose ps. r пересканирует проекты и перечитает
состояние.
Docker Compose
Если рядом с проектом есть docker-compose.yml, слева появляется секция 🐳 Compose
со строкой проекта, а справа — его контейнеры: состояние, статус, пометка про откат.
Буквы фильтруют список, Enter открывает меню действий:
- Логи —
docker compose logs -f --tail=200 <сервис>как обычная задача: поиск по/, копирование поy, режим на весь экран поz. - Обновить —
pullиup -dодной задачей с одним логом. Ненулевой код на первом шаге отменяет второй, и в логе видно, где встало. - Образы и откат — список образов из локального кеша и текущий digest тега из
реестра GitLab. Выбор → подтверждение → при необходимости
pullнужного digest, локальный ретег иup -d --no-deps. Compose-файл не меняется. - Рестарт, Стоп — то же с подтверждением.
Первая строка списка — весь проект: обновление всего сразу и логи всех сервисов.
Всё, что меняет состояние docker, показывает точные команды и спрашивает
подтверждение. Читаются ps, images, inspect и реестр — без спроса, раз в 5
секунд, пока курсор стоит на секции; r перечитывает немедленно.
Про откат честно. Compose ссылается на изменяемый тег, поэтому откат делается
локальным ретегом: после него тег указывает не на то, что в реестре, и сервис
помечается ⇤ локально переопределён. Следующее «Обновить» осознанно уедет вперёд на
свежий образ, и пометка снимется. Постоянного закрепления digest в compose-файле нет.
Откуда берутся образы для отката. Из локального кеша docker: после нового пуша
прежний образ остаётся лежать с тегом <none>, и именно он нужен для возврата. Реестр
GitLab историю тега не хранит — он отдаёт только текущий digest, поэтому в списке он
справочный. Практический вывод: docker image prune -a на проде стирает возможность
откатиться.
Как работает стоп
Раннер запускает npm run ..., а npm запускает уже свой процесс — node, nest,
vite, — и порт держит именно он. Поэтому убить один pid недостаточно: npm умрёт,
а внук останется слушать порт, и следующий запуск упадёт с EADDRINUSE.
s снимает всё дерево:
- POSIX — задача стартует лидером своей группы процессов (
detached), стоп посылаетSIGTERMвсей группе по отрицательному pid, через 5 секунд —SIGKILL. - Windows — сигналов нет, поэтому
taskkill /PID <pid> /T, а через 5 секунд то же с/F.
S останавливает все живые задачи, выход по q предлагает сделать это же. Если TUI
умрёт аварийно (не через q), задачи на POSIX останутся жить как осиротевшие — они в
своей группе процессов; ищи их по lsof -i :порт.
Пайплайны GitLab
Секция включается, если в окружении есть токен:
export GITLAB_TOKEN=glpat-...Scope read_api хватает для просмотра пайплайнов, джоб и трасс. Для запуска (p) и отмены (s) нужен api. Хост и путь проекта берутся из git remote get-url origin, ветка — из текущего HEAD. Токен читается только из окружения, никуда не пишется и не логируется. Нет токена — секция объясняет, чего не хватает, остальное работает как обычно.
Опции
packer-commander [опции]
--cwd <путь> откуда искать корень проекта (по умолчанию текущая папка)
--roots a,b папки воркспейсов вручную вместо чтения "workspaces"
--self-check напечатать корень, папки и число пакетов, не поднимая TUI
-v, --version версия
-h, --help справка--self-check удобен, когда непонятно, что раннер вообще нашёл:
$ npx packer-commander --self-check
root=/repo roots=apps,libs packages=43 commands=4Требования
Node.js 20 и новее. Нужен интерактивный терминал не меньше 80×24 — под пайпом или в CI раннер честно откажется работать с кодом 1.
Публикация
Публикует GitHub Actions по тегу — вручную npm publish запускать не нужно:
npm version patch -m "chore: версия %s"
git push --follow-tagsWorkflow .github/workflows/publish.yml прогоняет тесты, сверяет тег с версией в
package.json и публикует через trusted publishing (OIDC): токен в секретах не
хранится, пакет получает provenance-подпись.
Однократная настройка на стороне npm: в настройках пакета на npmjs.com →
Trusted publishers → добавить GitHub Actions с владельцем Slowmoney,
репозиторием packer-commander и файлом workflow publish.yml.
Если trusted publishing по каким-то причинам не подходит, альтернатива — granular
automation token в секрете NPM_TOKEN и NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
на шаге npm publish; тогда id-token: write и npm install -g npm@latest не нужны.
Разработка
npm test53 теста на node:test: ядро (индекс воркспейсов, сборка команд npm, конвертер ANSI → теги blessed, кольцевой буфер лога, автомат статусов задач, клиент GitLab) и CLI. Интерфейс проверяется дымовым прогоном на заглушке blessed.
Лицензия
MIT
