I-1: boards() отдаёт type=null, если тип неизвестен у любого проекта доски. M-2: labels_add ensure_fields нормализуется к метке проекта. M-3: light_list вместо list_projects в _assign_boards. M-4/T5.4: пустой project — 422. M-1, M-5, T10.1-T10.7: README, ARCHITECTURE, CLAUDE.md, design.md (49-51), e2e. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7.8 KiB
jira-hub
Что это
Хаб моста Jira для АРМ КА: единственный источник истины по задачам проектов-меток Jira-проекта AURORA на Mac mini (192.168.0.106). Хранит зеркало задач, служебные заметки и очередь команд в SQLite, отдаёт HTTP API в локальной сети (агенту на виртуалке jira-agent и интерфейсам) и MCP-сервер для Claude. Главный сценарий: из чата поставить пакет команд, агент на виртуалке выполняет их в Jira по правилу «проверь, потом сделай» и возвращает состояние задач в зеркало. Спеки: openspec/specs/; активные change — openspec/changes/ (кроме archive/).
Стек и ограничения
- Веб-приложение —
web/(React 19 + TypeScript + Vite, TanStack Query, Vitest, Playwright; Node 24, npm); сборка вsrc/jira_hub/web/app/не в git. - Python 3.13 от uv (
.python-version,tool.uv.python-preference = "only-managed": системный Python miniconda несёт SQLite 3.51.1 с взаимной блокировкой, O-14 #29), uv, hatchling, pytest; HTTP на stdlib (http.server), БД — SQLite (stdlib), MCP — пакетmcp(закреплён<2, рулинг R-10). - Хаб не знает пароль Jira и не ходит в Jira: учётные данные и сеть до Jira только у агента.
- Зеркало задач пишет только
mirror.apply_stateпо загрузке состояния от агента (POST /agent/state); правки идут командами через очередь. - Хаб не создаёт команды сам: повтор после failed — новая команда по запросу человека/интерфейса. Команду, выданную агенту и оставшуюся без отчёта, хаб довыдаёт при следующем claim (до 3 выдач, затем failed).
- Данные:
~/.local/share/jira-hub/(JIRA_HUB_HOME):hub.sqlite,backups/,release/(опубликованная версия агента),files/(файлы вложений по sha256, уборка через 30 дней); каталог данных,backups/,release/иfiles/— права 0700. Порт по умолчанию 8790. - Два статических токена (в таблице
setting): агентский открывает только/agent/*, клиентский — остальное.
Архитектура
src/jira_hub/— весь код пакета, без разделения на ядро и адаптеры; чистая логика (commands,mirror,queue,settings) принимает соединение SQLite параметром.db(схема, миграции) ←settings,mirror,commands,projects←queue←api(HTTP, маршруты вROUTES, фоновыйtick, реле общей папкиrelay(поток вserve, настройкаrelay_dir)) ←cli.files(хранилище вложенийfiles/<sha256>, каталог — параметрHub.files_dir) ←queue,api;mcp_serverберёт из него только пределMAX_SIZE.client(HTTP-клиент хаба) ←mcp_server(stdio, инструменты MCP);importer→mirror/settings;backupвызывается изapiи изdb(копия перед миграцией схемы).- Подробная карта модулей и границ —
ARCHITECTURE.md.
Команды
uv run pytest— весь набор тестов. Зелёным считается только весь набор.uv sync— установка окружения.uv run jira-hub init --config PATH [--force]— настройки проекта изconfig.example.json, создание токенов.uv run jira-hub serve [--host] [--port]— локальный запуск хаба.- Веб-приложение —
http://127.0.0.1:8790/app/(доска —/app/board?project=<метка>, задачи —/app/issues?project=<метка>; вход по клиентскому токену);/и/linksперенаправляют на доску. make web— сборка приложения (послеgit pullна Mac mini, до перезапуска хаба);make check— pytest + lint и тесты фронта;cd web && npm run dev— разработка с прокси на тестовый хабbash web/scripts/test-hub.sh(:8791);cd web && npm run e2e— Playwright;cd web && npm run golden— перегенерировать эталоны доски изlinks.html@3931a88(только при смене фикстур).uv run jira-hub import FOLDER— импорт CSV-пакетаadmin/jira-sync;uv run jira-hub mcp [--project <метка>]— MCP по stdio (с привязкой сессии к проекту);uv run jira-hub tokens— показать токены.uv run jira-hub agent publish PATH— опубликовать версию агента для самообновления (только вверх).
Тесты
- Golden-тесты:
tests/fixtures/<name>.*+ эталон<name>.expected.*. Внешние сервисы в тестах мокаются. - SQLite в памяти или во временном
JIRA_HUB_HOME(tmp_path); API поднимается на порту 0 в отдельном потоке. Jira и агент в тестах не участвуют. - Соединение SQLite в тесте — через фикстуру
open_db(tests/conftest.py) или фикстуруconnмодуля, иначе с явнымclose():pyproject.toml(filterwarnings) делает незакрытое соединение ошибкой набора. - Фронт: golden-эталоны доски —
web/src/board/__fixtures__/*.expected.json(их пишетweb/scripts/golden-from-links.tsиз старой страницы); тесты рядом с кодом*.test.ts(x); e2e —web/e2e/на тестовом хабе.
Первая подсистема
Очередь команд (queue.py, Task 5): пакеты, порядок (batch.created_at, seq), одна команда в полёте, временные ключи new:<n>, подтверждение по состоянию зеркала. Остальное (API, MCP, импорт) надстраивается над ней.
OpenSpec и superpowers
- Вход в любую задачу — superpowers:brainstorming. Skills openspec-propose и openspec-explore сами по себе не запускать.
- Когда brainstorming классифицировал задачу как architectural, структуру change создать через
openspec new change <id>(или/opsx:propose <id>), а содержимое proposal.md, specs/ и design.md написать по итогам brainstorming. tasks.md из OpenSpec не заполнять — задачи живут в плане superpowers. /opsx:applyне использовать: исполнение идёт через writing-plans и SDD/executing-plans.openspec archive <id>— после merge PR, как часть чеклиста закрытия.- Хук require-plan защищает любой каталог
src/на любой глубине. Если код лежит иначе — перечислить каталоги (префиксы от корня, по одному в строке) в.claude/code-paths.