From d405f7167379984ff9967782245404dfb9fd7b3e Mon Sep 17 00:00:00 2001 From: kisskin Date: Fri, 10 Jul 2026 15:14:50 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20M5=20deployment-ready=20=E2=80=94=20Mak?= =?UTF-8?q?efile,=20README=20(EN/RU),=20CI=20workflows,=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- .forgejo/workflows/test.yml | 64 +++++ .github/workflows/ci.yml | 75 +++-- Makefile | 93 +++++++ README.md | 271 +++++++++++-------- package.json | 4 +- packages/bridge/src/__tests__/routes.test.ts | 2 +- 6 files changed, 370 insertions(+), 139 deletions(-) create mode 100644 .forgejo/workflows/test.yml create mode 100644 Makefile diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml new file mode 100644 index 0000000..b020272 --- /dev/null +++ b/.forgejo/workflows/test.yml @@ -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 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e86ab78..b020272 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7ecfcfe --- /dev/null +++ b/Makefile @@ -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 diff --git a/README.md b/README.md index 01ecbe3..fbcf07b 100644 --- a/README.md +++ b/README.md @@ -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 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=` - - 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= + TELEGRAM_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). diff --git a/package.json b/package.json index a9fee95..430d47d 100644 --- a/package.json +++ b/package.json @@ -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" } } diff --git a/packages/bridge/src/__tests__/routes.test.ts b/packages/bridge/src/__tests__/routes.test.ts index 19c16c6..21bfcd3 100644 --- a/packages/bridge/src/__tests__/routes.test.ts +++ b/packages/bridge/src/__tests__/routes.test.ts @@ -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';