10 KiB
sdlc-hub
Что это
SDLC-хаб с модулями jira и wiki. Мост Jira для АРМ КА: единственный источник истины по задачам проектов-меток Jira-проекта AURORA на Mac mini (192.168.0.106) и Markdown-копии вики Eva по проектам (модуль wiki). Хранит зеркало задач, служебные заметки и очередь команд в 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/sdlc_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/sdlc-hub/(SDLC_HUB_HOME):hub.sqlite(зеркало, очередь, журнал измененийissue_change),backups/,release/<модуль>/(опубликованная версия агента модуля),files/(файлы вложений по sha256, уборка через 30 дней),downloads/(копии вложений для MCP<id>/<имя>, у wikiwiki-<id>/<имя>, уборка 30 дней),wiki/<метка>/(Markdown-копия вики проекта:index.mdв каталоге страницы,_tree.json); каталог данных,backups/,release/<модуль>/,files/,downloads/иwiki/— права 0700. Порт по умолчанию 8790. - Статические токены (в таблице
setting): клиентский — всё, кроме/agent/*; по одному токену агента на модуль (jira,wiki) — только/agent/*и только маршруты своего модуля. Токен Eva в хабе не хранится.
Архитектура
src/sdlc_hub/core/— ядро:db,settings,projects,queue(механика очереди),files,api(HTTP,CORE_ROUTES+ маршруты модулей вROUTES, фоновыйtick),relay,release,client,mcp(каркас MCP),cli; контракт модуляModule/CommandHooks—core/modules.py, реестр —core/registry.py.src/sdlc_hub/modules/jira/— модуль jira:schema,mirror,history,attachments,fetch,commands,refresh,projects,hooks(смысл типов команд для очереди),api,mcp,settings,importer/cli. Входная точка —MODULEвmodules/jira/__init__.py.src/sdlc_hub/modules/wiki/— модуль wiki:schema,settings,paths,projects(полеwiki_root),commands(wiki_sync,wiki_fetchи хуки очереди),convert(HTML → Markdown),stage,sync,search(FTS5),attachments,tick,api,mcp. Входная точка —MODULEвmodules/wiki/__init__.py.- Граница: ядро не импортирует модули (кроме ленивого импорта в
registry.pyи шагах миграцийdb.py), типы команд и термины модулей (jira, wiki, eva) живут в модуле, новые имена в ядре — без названий модулей; проверяютtest_core_imports,test_core_has_no_jira_terms,test_core_has_no_module_termsвtests/test_registry.py. Меток-исключений нет. - Цепочка ядра:
db←settings,projects←queue←api←cli;files←queue,api; релеrelay— поток вserve;backupвызывается изapiи изdb. Модуль jira:hooks → commands/mirror/history/refresh/attachments/fetch → core. - Веб: оболочка и общее —
web/src/{shell,ui,api,projects,auth,styles}, модули —web/src/modules/<имя>/(контрактHubModuleвmodules/types.ts, список —modules/index.ts); модуль jira — страницы доски, задач и ленты; модуль wiki (web/src/modules/wiki/) — страница «Вики» (/app/wiki?project=<метка>). - Подробная карта модулей и границ —
ARCHITECTURE.md.
Команды
uv run pytest— весь набор тестов. Зелёным считается только весь набор.uv sync— установка окружения.uv run sdlc-hub init --config PATH [--force]— настройки проекта изconfig.example.json, создание токенов.uv run sdlc-hub serve [--host] [--port]— локальный запуск хаба.- Веб-приложение —
http://127.0.0.1:8790/app/(доска —/app/board?project=<метка>, задачи —/app/issues?project=<метка>, лента изменений —/app/feed?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 sdlc-hub import FOLDER— импорт CSV-пакетаadmin/jira-sync;uv run sdlc-hub mcp <модуль> [--project <метка>]— MCP модуля по stdio (модуль обязателен:jira— серверsdlc-jira,wiki— серверsdlc-wiki; с привязкой сессии к проекту);uv run sdlc-hub tokens— показать токены (клиентский и по агенту на модуль).uv run sdlc-hub agent publish [--module jira|wiki] PATH— опубликовать версию агента модуля для самообновления (только вверх; по умолчаниюjira; публикация лежит вrelease/<модуль>/).
Тесты
- Golden-тесты:
tests/fixtures/<name>.*+ эталон<name>.expected.*. Внешние сервисы в тестах мокаются. - SQLite в памяти или во временном
SDLC_HUB_HOME(tmp_path); API поднимается на порту 0 в отдельном потоке. Jira и агент в тестах не участвуют. - Соединение SQLite в тесте — через фикстуру
open_db(tests/conftest.py) или фикстуруconnмодуля, иначе с явнымclose():pyproject.toml(filterwarnings) делает незакрытое соединение ошибкой набора. - Фронт: golden-эталоны доски —
web/src/modules/jira/board/__fixtures__/*.expected.json(их пишетweb/scripts/golden-from-links.tsиз старой страницы); тесты рядом с кодом*.test.ts(x); e2e —web/e2e/на тестовом хабе.
Первая подсистема
Очередь команд (core/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.