feat: M5 deployment-ready — Makefile, README (EN/RU), CI workflows, fixes
Some checks failed
CI / contracts (push) Failing after 42s
CI / bridge (push) Has been skipped
CI / frontend (push) Has been skipped

- Add Makefile with dev/build/test/docker/ci commands
- Rewrite README.md with architecture, quickstart, env vars (EN + RU)
- Add Forgejo CI workflow (.forgejo/workflows/test.yml)
- Update GitHub CI workflow for pnpm monorepo structure
- Fix unused imports in bridge test file (typecheck)
- Add test/ci scripts to root package.json
- Docker compose build verified (bridge + frontend images)
- Full local CI passes: typecheck → test (16/16) → build
This commit is contained in:
kisskin 2026-07-10 15:14:50 +03:00
parent ade88808fb
commit d405f71673
6 changed files with 370 additions and 139 deletions

View file

@ -0,0 +1,64 @@
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
contracts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install pnpm
run: corepack enable && corepack prepare pnpm@9.15.4 --activate
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build contracts
run: pnpm --filter @kanban/contracts build
- name: Typecheck contracts
run: pnpm --filter @kanban/contracts typecheck
bridge:
runs-on: ubuntu-latest
needs: contracts
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install pnpm
run: corepack enable && corepack prepare pnpm@9.15.4 --activate
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build contracts
run: pnpm --filter @kanban/contracts build
- name: Typecheck bridge
run: pnpm --filter @kanban/bridge typecheck
- name: Test bridge
run: pnpm --filter @kanban/bridge test
- name: Build bridge
run: pnpm --filter @kanban/bridge build
frontend:
runs-on: ubuntu-latest
needs: contracts
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install pnpm
run: corepack enable && corepack prepare pnpm@9.15.4 --activate
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build contracts
run: pnpm --filter @kanban/contracts build
- name: Typecheck frontend
run: pnpm --filter frontend typecheck
- name: Build frontend
run: pnpm --filter frontend build

View file

@ -7,35 +7,58 @@ on:
branches: [main] branches: [main]
jobs: jobs:
backend: contracts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install backend
run: |
python -m pip install -U pip
pip install -e backend[dev]
- name: Backend tests
run: pytest backend/tests -q
frontend:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: '22' node-version: '22'
cache: npm - name: Install pnpm
cache-dependency-path: frontend/package-lock.json run: corepack enable && corepack prepare pnpm@9.15.4 --activate
- name: Install frontend - name: Install dependencies
working-directory: frontend run: pnpm install --frozen-lockfile
run: npm ci - name: Build contracts
- name: Frontend tests run: pnpm --filter @kanban/contracts build
working-directory: frontend - name: Typecheck contracts
run: npm test run: pnpm --filter @kanban/contracts typecheck
- name: Frontend build
working-directory: frontend bridge:
run: npm run build runs-on: ubuntu-latest
needs: contracts
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install pnpm
run: corepack enable && corepack prepare pnpm@9.15.4 --activate
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build contracts
run: pnpm --filter @kanban/contracts build
- name: Typecheck bridge
run: pnpm --filter @kanban/bridge typecheck
- name: Test bridge
run: pnpm --filter @kanban/bridge test
- name: Build bridge
run: pnpm --filter @kanban/bridge build
frontend:
runs-on: ubuntu-latest
needs: contracts
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install pnpm
run: corepack enable && corepack prepare pnpm@9.15.4 --activate
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build contracts
run: pnpm --filter @kanban/contracts build
- name: Typecheck frontend
run: pnpm --filter frontend typecheck
- name: Build frontend
run: pnpm --filter frontend build

93
Makefile Normal file
View file

@ -0,0 +1,93 @@
# ─────────────────────────────────────────────────────────────
# Hermes Kanban Mini App — Makefile
# Common development and deployment commands
# ─────────────────────────────────────────────────────────────
.PHONY: dev dev-bridge dev-frontend build install typecheck test test-bridge clean up down logs
# ── Local development ───────────────────────────────────────
## Install all dependencies
install:
pnpm install
## Run bridge + frontend in dev mode (parallel)
dev:
@echo "Starting bridge (port 3456) and frontend (port 5173)..."
@pnpm --filter @kanban/bridge dev & \
pnpm --filter frontend dev & \
wait
## Run bridge only in dev mode (watch)
dev-bridge:
pnpm --filter @kanban/bridge dev
## Run frontend only in dev mode
dev-frontend:
pnpm --filter frontend dev
# ── Build ───────────────────────────────────────────────────
## Build all TypeScript packages
build:
pnpm -r build
## Build Docker images
docker-build:
docker compose build
## Build + tag production images
docker-build-prod:
docker compose -f docker-compose.yml build --no-cache
# ── Quality ─────────────────────────────────────────────────
## Run TypeScript type checking
typecheck:
pnpm typecheck
## Run all tests
test: test-bridge
## Run bridge tests
test-bridge:
pnpm --filter @kanban/bridge test
## Run frontend build (includes tsc)
test-frontend:
pnpm --filter frontend build
## Run full CI pipeline locally
ci: install typecheck test build
# ── Docker Compose ──────────────────────────────────────────
## Start services with docker compose
up:
docker compose up -d
## Stop services
down:
docker compose down
## View service logs
logs:
docker compose logs -f
## Rebuild and restart services
restart: down docker-build up
# ── Cleanup ─────────────────────────────────────────────────
## Remove build artifacts
clean:
pnpm -r clean
rm -rf frontend/dist
## Full clean (including node_modules)
clean-all: clean
rm -rf node_modules packages/*/node_modules frontend/node_modules
## Remove Docker images
docker-clean:
docker compose down --rmi local --volumes --remove-orphans

281
README.md
View file

@ -1,164 +1,213 @@
# Hermes Kanban Mini App # Hermes Kanban Mini App
A community-ready Telegram Mini App and browser dashboard for viewing and operating Hermes Agent Kanban boards from mobile or desktop. Telegram Mini App and web dashboard for [Hermes Agent](https://github.com/NousResearch/hermes-agent) Kanban boards. View, create, and manage tasks from mobile or desktop.
Status: local MVP. The repository is prepared for a future public GitHub push, but no remote is created by this task. > **[Русская версия](#hermes-kanban-mini-app--на-русском)**
## What it does ## What it does
- Shows Hermes Kanban columns: triage, todo, ready, running, blocked, done, archived. - **Board view**: Kanban columns — triage, todo, ready, running, blocked, done, archived
- Opens task details with body, events, runs and log tail. - **Task details**: body, events, runs, log tail, comments
- Creates tasks with assignee, priority, workspace kind, goal mode and runtime options. - **Task actions**: create, assign, promote, block/unblock, archive, dispatch, comment
- Adds comments and runs common actions: assign, promote, block, unblock, archive, dispatch. - **Telegram integration**: Mini App theme variables, `initData` auth, haptic feedback
- Supports Telegram Mini App theme variables and server-side Telegram `initData` validation. - **Secure bridge**: execFile with `shell: false`, command allowlist, token auth
## Architecture ## Architecture
```text ```
Telegram Mini App / Browser Telegram Mini App / Browser
|
| HTTPS in production, Vite proxy in dev │ HTTPS / Vite proxy in dev
v
React + TypeScript frontend React + TypeScript + Vite frontend (port 5173 dev / 80 nginx)
|
| /api/* with optional X-Telegram-Init-Data │ /bridge/v1/* (X-Bridge-Token or dev mode)
v
FastAPI backend Express Bridge (port 3456)
|
| fixed subprocess argv, shell=False │ hermes kanban ... --json (execFile, shell: false)
v
hermes kanban CLI Hermes Kanban board (SQLite)
|
v
Hermes Kanban board
``` ```
Screenshot placeholder: run the frontend locally and replace this section with screenshots before publishing the GitHub repository. **Monorepo structure** (pnpm workspace):
- `packages/contracts` — shared TypeScript types + Zod schemas
- `packages/bridge` — Express API server, CLI wrapper
- `frontend` — React + Vite SPA with Tailwind CSS
## Prerequisites ## Quick start
- Hermes Agent installed with Kanban enabled. ### Prerequisites
- Python 3.11+.
- Node.js 20+ (tested with Node 24).
- Telegram bot from BotFather for Mini App production mode.
- HTTPS public URL for Telegram Mini App production usage.
## Local development - Node.js ≥ 18
- pnpm 9.x (`corepack enable`)
- [Hermes Agent](https://github.com/NousResearch/hermes-agent) installed with Kanban enabled
### Local development
```bash ```bash
git clone <your-future-repo-url> hermes-kanban-miniapp git clone https://github.com/Kisskin-Mister/hermes-kanban-miniapp.git
cd hermes-kanban-miniapp cd hermes-kanban-miniapp
cp .env.example .env cp .env.example .env # edit as needed
pnpm install
make dev # starts bridge + frontend
``` ```
Backend: - Frontend: http://localhost:5173 (Vite dev server with hot reload)
- Bridge API: http://localhost:3456/bridge/v1/health
### Docker Compose
```bash ```bash
python3 -m venv .venv cp .env.example .env # edit HERMES_HOME, BRIDGE_TOKEN, etc.
. .venv/bin/activate make docker-build # or: docker compose build
pip install -e backend[dev] make up # or: docker compose up -d
uvicorn app.main:app --app-dir backend --reload --host 127.0.0.1 --port 8000
``` ```
Frontend: - Frontend: http://localhost:8080
- Bridge API: http://localhost:3456 (internal, proxied by nginx)
### Production
```bash ```bash
cd frontend make build # build TypeScript
npm install make docker-build # build images
npm run dev make up # start containers
``` ```
Open http://localhost:5173. In `KANBAN_UI_AUTH_MODE=dev` or `none`, the browser works without Telegram. The `docker-compose.yml` mounts `~/.hermes` read-only into the bridge container. Configure `HERMES_HOME` in `.env`.
## Environment variables ## Environment variables
See `.env.example`. ### Bridge (`.env`)
Important settings: | Variable | Default | Description |
|---|---|---|
| `BRIDGE_HOST` | `127.0.0.1` | Bridge bind address |
| `BRIDGE_PORT` | `8787` | Bridge port |
| `BRIDGE_TOKEN` | — | Auth token (`X-Bridge-Token` header) |
| `AUTH_MODE` | `token` | `token` (validate header) or `dev` (bypass auth) |
| `BRIDGE_ALLOWED_BOARDS` | `default` | Comma-separated board slugs or `*` |
| `COMMAND_TIMEOUT_SECONDS` | `30` | Per-command timeout |
| `LOG_TAIL_MAX_LINES` | `500` | Max log lines returned |
| `HERMES_BIN` | `hermes` | Path to hermes executable |
| `HERMES_HOME` | — | Hermes profile directory |
| `TELEGRAM_BOT_TOKEN` | — | For initData validation (optional) |
- `HERMES_BIN`: Hermes executable, default `hermes`. ### Docker Compose
- `HERMES_HOME`: Hermes home directory for the target profile.
- `HERMES_KANBAN_BOARD`: default board slug. | Variable | Default | Description |
- `KANBAN_UI_AUTH_MODE`: `telegram`, `dev` or `none`. |---|---|---|
- `TELEGRAM_BOT_TOKEN`: bot token used only by backend for `initData` validation. | `HERMES_HOME` | `/home/kisskin/.hermes` | Mounted into bridge container |
- `TELEGRAM_ALLOWED_USER_IDS`: optional comma-separated Telegram user id allowlist.
- `KANBAN_UI_ALLOWED_ORIGINS`: CORS allowlist. ## Makefile commands
- `KANBAN_UI_FRONTEND_DIST_DIR`: optional built frontend directory for single-container serving.
- `VITE_API_BASE_URL`: frontend API base URL for production builds. ```
make install — pnpm install
make dev — run bridge + frontend in dev mode
make build — build all TypeScript packages
make typecheck — run TypeScript type checking
make test — run bridge tests
make ci — install + typecheck + test + build
make docker-build — build Docker images
make up — docker compose up -d
make down — docker compose down
make logs — follow service logs
make clean — remove build artifacts
```
## Telegram Mini App setup ## Telegram Mini App setup
1. Open BotFather in Telegram. 1. Create a bot with [BotFather](https://t.me/BotFather)
2. Create or choose a bot. 2. Set the Mini App domain: `/setdomain` → your HTTPS domain
3. Use `/setdomain` and set the HTTPS domain that serves this app. 3. Configure `.env`:
4. Use `/setmenubutton` or create a Web App button and point it at your HTTPS frontend URL. ```bash
5. On the backend, set: AUTH_MODE=token
- `KANBAN_UI_AUTH_MODE=telegram` BRIDGE_TOKEN=<generate-a-strong-token>
- `TELEGRAM_BOT_TOKEN=<your bot token>` TELEGRAM_BOT_TOKEN=<your-bot-token>
- optionally `TELEGRAM_ALLOWED_USER_IDS=123,456`
6. Never put the bot token into frontend env vars or committed files.
## Production deployment notes
Telegram Mini Apps require HTTPS. Put the frontend and backend behind a reverse proxy such as Caddy, Nginx, Traefik or Cloudflare Tunnel. Configure CORS so the backend only accepts your frontend origin.
Systemd example:
```ini
[Unit]
Description=Hermes Kanban Mini App API
After=network.target
[Service]
WorkingDirectory=/opt/hermes-kanban-miniapp
EnvironmentFile=/opt/hermes-kanban-miniapp/.env
ExecStart=/opt/hermes-kanban-miniapp/.venv/bin/uvicorn app.main:app --app-dir backend --host 127.0.0.1 --port 8000
Restart=on-failure
[Install]
WantedBy=multi-user.target
``` ```
4. Deploy with HTTPS (Caddy, Nginx, Traefik, or Cloudflare Tunnel)
Build frontend for static hosting: ## CI
Forgejo CI workflow (`.forgejo/workflows/test.yml`) runs on push to `main`:
- Typecheck contracts, bridge, frontend
- Run bridge unit tests (vitest)
- Build frontend
## License
MIT — see [LICENSE](LICENSE).
---
# Hermes Kanban Mini App / На русском
Telegram Mini App и веб-панель для управления задачами [Hermes Agent](https://github.com/NousResearch/hermes-agent). Просматривайте, создавайте и управляйте задачами с мобильного или десктопа.
## Что это
- **Доска с колонками**: triage, todo, ready, running, blocked, done, archived
- **Детали задачи**: описание, события, запуски, логи, комментарии
- **Действия**: создание, назначение, продвижение, блокировка/разблокировка, архивация, диспетчеризация
- **Интеграция с Telegram**: темы Mini App, авторизация `initData`, тактильная обратная связь
## Быстрый старт
### Локальная разработка
```bash ```bash
cd frontend git clone https://github.com/Kisskin-Mister/hermes-kanban-miniapp.git
npm ci cd hermes-kanban-miniapp
npm run build cp .env.example .env
pnpm install
make dev
``` ```
The included Dockerfile builds the frontend and serves it from the FastAPI container on port `8000`. - Фронтенд: http://localhost:5173
For same-origin Docker deployment, leave `VITE_API_BASE_URL` empty at build time and expose only the backend container. - API моста: http://localhost:3456/bridge/v1/health
## Security model ### Docker Compose
- Backend accepts only fixed API actions mapped to fixed Hermes Kanban CLI subcommands.
- Subprocess calls use argv lists and `shell=False`.
- Telegram `initData` is validated according to Telegram WebApp signing rules in `telegram` auth mode.
- Optional Telegram user allowlist rejects unknown users.
- CORS is restrictive and configured by env.
- `.env` is ignored by git; `.env.example` contains placeholders only.
## Known limitations
- The adapter prefers Hermes CLI JSON output. If a local Hermes version lacks JSON for a command, parsing is conservative and may return raw text for some endpoints.
- No drag-and-drop yet; actions are button-based.
- No SSE yet; running boards auto-refresh every 2.5 seconds, otherwise every 5 seconds.
- No GitHub remote is created until the owner/name are confirmed and auth is configured.
## Tests
Backend:
```bash ```bash
. .venv/bin/activate cp .env.example .env
pytest backend/tests -q # Отредактируйте HERMES_HOME, BRIDGE_TOKEN и другие переменные
make docker-build
make up
``` ```
Frontend: - Фронтенд: http://localhost:8080
- Мост (внутренний): http://localhost:3456
```bash ### Предварительные требования
cd frontend
npm test - Node.js ≥ 18
npm run build - pnpm 9.x (`corepack enable`)
``` - [Hermes Agent](https://github.com/NousResearch/hermes-agent) с включённым Kanban
## Переменные окружения
Смотрите таблицу выше или файл `.env.example`.
## Команды Makefile
| Команда | Описание |
|---|---|
| `make dev` | Запуск bridge + frontend в режиме разработки |
| `make build` | Сборка всех TypeScript пакетов |
| `make test` | Запуск тестов bridge |
| `make docker-build` | Сборка Docker образов |
| `make up` | Запуск сервисов через docker compose |
| `make down` | Остановка сервисов |
| `make ci` | Полный CI-пайплайн локально |
## Установка Telegram Mini App
1. Создайте бота через [BotFather](https://t.me/BotFather)
2. Установите домен Mini App: `/setdomain` → ваш HTTPS домен
3. Настройте `.env` с `AUTH_MODE=token`, `BRIDGE_TOKEN` и `TELEGRAM_BOT_TOKEN`
4. Разверните с HTTPS (Caddy, Nginx, Traefik, Cloudflare Tunnel)
## Лицензия
MIT — см. [LICENSE](LICENSE).

View file

@ -8,6 +8,8 @@
"scripts": { "scripts": {
"build": "pnpm -r build", "build": "pnpm -r build",
"typecheck": "pnpm -r typecheck", "typecheck": "pnpm -r typecheck",
"clean": "pnpm -r clean" "test": "pnpm -r test",
"clean": "pnpm -r clean",
"ci": "pnpm install --frozen-lockfile && pnpm typecheck && pnpm test && pnpm build"
} }
} }

View file

@ -3,7 +3,7 @@
// Tests the Express app with mock Hermes CLI responses // Tests the Express app with mock Hermes CLI responses
// ───────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest'; import { describe, it, expect, vi } from 'vitest';
import request from 'supertest'; import request from 'supertest';
import { createApp, type BridgeConfig, VERSION } from '../index.js'; import { createApp, type BridgeConfig, VERSION } from '../index.js';
import type { Board, TaskSummary, TaskDetail } from '@kanban/contracts'; import type { Board, TaskSummary, TaskDetail } from '@kanban/contracts';