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]
jobs:
backend:
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:
contracts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Install frontend
working-directory: frontend
run: npm ci
- name: Frontend tests
working-directory: frontend
run: npm test
- name: Frontend build
working-directory: frontend
run: npm run build
- 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

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

271
README.md
View file

@ -1,164 +1,213 @@
# 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
- Shows Hermes Kanban columns: triage, todo, ready, running, blocked, done, archived.
- Opens task details with body, events, runs and log tail.
- Creates tasks with assignee, priority, workspace kind, goal mode and runtime options.
- Adds comments and runs common actions: assign, promote, block, unblock, archive, dispatch.
- Supports Telegram Mini App theme variables and server-side Telegram `initData` validation.
- **Board view**: Kanban columns — triage, todo, ready, running, blocked, done, archived
- **Task details**: body, events, runs, log tail, comments
- **Task actions**: create, assign, promote, block/unblock, archive, dispatch, comment
- **Telegram integration**: Mini App theme variables, `initData` auth, haptic feedback
- **Secure bridge**: execFile with `shell: false`, command allowlist, token auth
## Architecture
```text
```
Telegram Mini App / Browser
|
| HTTPS in production, Vite proxy in dev
v
React + TypeScript frontend
|
| /api/* with optional X-Telegram-Init-Data
v
FastAPI backend
|
| fixed subprocess argv, shell=False
v
hermes kanban CLI
|
v
Hermes Kanban board
│ HTTPS / Vite proxy in dev
React + TypeScript + Vite frontend (port 5173 dev / 80 nginx)
│ /bridge/v1/* (X-Bridge-Token or dev mode)
Express Bridge (port 3456)
│ hermes kanban ... --json (execFile, shell: false)
Hermes Kanban board (SQLite)
```
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.
- 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.
### Prerequisites
## 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
git clone <your-future-repo-url> hermes-kanban-miniapp
git clone https://github.com/Kisskin-Mister/hermes-kanban-miniapp.git
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
python3 -m venv .venv
. .venv/bin/activate
pip install -e backend[dev]
uvicorn app.main:app --app-dir backend --reload --host 127.0.0.1 --port 8000
cp .env.example .env # edit HERMES_HOME, BRIDGE_TOKEN, etc.
make docker-build # or: docker compose build
make up # or: docker compose up -d
```
Frontend:
- Frontend: http://localhost:8080
- Bridge API: http://localhost:3456 (internal, proxied by nginx)
### Production
```bash
cd frontend
npm install
npm run dev
make build # build TypeScript
make docker-build # build images
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
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`.
- `HERMES_HOME`: Hermes home directory for the target profile.
- `HERMES_KANBAN_BOARD`: default board slug.
- `KANBAN_UI_AUTH_MODE`: `telegram`, `dev` or `none`.
- `TELEGRAM_BOT_TOKEN`: bot token used only by backend for `initData` validation.
- `TELEGRAM_ALLOWED_USER_IDS`: optional comma-separated Telegram user id allowlist.
- `KANBAN_UI_ALLOWED_ORIGINS`: CORS allowlist.
- `KANBAN_UI_FRONTEND_DIST_DIR`: optional built frontend directory for single-container serving.
- `VITE_API_BASE_URL`: frontend API base URL for production builds.
### Docker Compose
| Variable | Default | Description |
|---|---|---|
| `HERMES_HOME` | `/home/kisskin/.hermes` | Mounted into bridge container |
## Makefile commands
```
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
1. Open BotFather in Telegram.
2. Create or choose a bot.
3. Use `/setdomain` and set the HTTPS domain that serves this app.
4. Use `/setmenubutton` or create a Web App button and point it at your HTTPS frontend URL.
5. On the backend, set:
- `KANBAN_UI_AUTH_MODE=telegram`
- `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.
1. Create a bot with [BotFather](https://t.me/BotFather)
2. Set the Mini App domain: `/setdomain` → your HTTPS domain
3. Configure `.env`:
```bash
AUTH_MODE=token
BRIDGE_TOKEN=<generate-a-strong-token>
TELEGRAM_BOT_TOKEN=<your-bot-token>
```
4. Deploy with HTTPS (Caddy, Nginx, Traefik, or Cloudflare Tunnel)
## Production deployment notes
## CI
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.
Forgejo CI workflow (`.forgejo/workflows/test.yml`) runs on push to `main`:
- Typecheck contracts, bridge, frontend
- Run bridge unit tests (vitest)
- Build frontend
Systemd example:
## License
```ini
[Unit]
Description=Hermes Kanban Mini App API
After=network.target
MIT — see [LICENSE](LICENSE).
[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
```
# Hermes Kanban Mini App / На русском
Build frontend for static hosting:
Telegram Mini App и веб-панель для управления задачами [Hermes Agent](https://github.com/NousResearch/hermes-agent). Просматривайте, создавайте и управляйте задачами с мобильного или десктопа.
## Что это
- **Доска с колонками**: triage, todo, ready, running, blocked, done, archived
- **Детали задачи**: описание, события, запуски, логи, комментарии
- **Действия**: создание, назначение, продвижение, блокировка/разблокировка, архивация, диспетчеризация
- **Интеграция с Telegram**: темы Mini App, авторизация `initData`, тактильная обратная связь
## Быстрый старт
### Локальная разработка
```bash
cd frontend
npm ci
npm run build
git clone https://github.com/Kisskin-Mister/hermes-kanban-miniapp.git
cd hermes-kanban-miniapp
cp .env.example .env
pnpm install
make dev
```
The included Dockerfile builds the frontend and serves it from the FastAPI container on port `8000`.
For same-origin Docker deployment, leave `VITE_API_BASE_URL` empty at build time and expose only the backend container.
- Фронтенд: http://localhost:5173
- API моста: http://localhost:3456/bridge/v1/health
## Security model
- 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:
### Docker Compose
```bash
. .venv/bin/activate
pytest backend/tests -q
cp .env.example .env
# Отредактируйте HERMES_HOME, BRIDGE_TOKEN и другие переменные
make docker-build
make up
```
Frontend:
- Фронтенд: http://localhost:8080
- Мост (внутренний): http://localhost:3456
```bash
cd frontend
npm test
npm run build
```
### Предварительные требования
- Node.js ≥ 18
- 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": {
"build": "pnpm -r build",
"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
// ─────────────────────────────────────────────────────────────
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest';
import { describe, it, expect, vi } from 'vitest';
import request from 'supertest';
import { createApp, type BridgeConfig, VERSION } from '../index.js';
import type { Board, TaskSummary, TaskDetail } from '@kanban/contracts';