diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 5d6deae..283211a 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -57,7 +57,7 @@ | Модуль | Ответственность | Зависит от | |---|---|---| -| `schema` | таблицы модуля: `wiki_project`, `wiki_page`, `wiki_page_fts` (FTS5), `wiki_attachment`, `wiki_sync_stage` | stdlib | +| `schema` | таблицы модуля: `wiki_project`, `wiki_page`, `wiki_attachment`, `wiki_sync_stage`; таблица FTS5 `wiki_page_fts` создаётся лениво при первой синхронизации (`search.ensure`), в `schema` её нет | stdlib | | `settings` | умолчания (`wiki_pacing`, `wiki_auto_sync_hours`, `wiki_min_agent_version`), ключи для агента, проверка значений | `core.settings` | | `paths` | каталог копий `<каталог базы>/wiki/<метка>/` | `core.db` | | `projects` | поле проекта `wiki_root` (изменяемое), `project_view` (`wiki_root`, `pages_count`, `synced_at`…), `on_project_created`/`on_project_updated` (постановка `wiki_sync`, отмена `queued`, сброс копии при смене корня) | `core.projects`, `core.queue`, `commands`, `paths` | @@ -136,7 +136,7 @@ golden-эталоны `__fixtures__/`), `issues/` (список, карточк - Ядро (`core/`) не импортирует модули (`jira_hub.modules.*`): исключения — `core/registry.py` (ленивый импорт внутри функции) и шаги истории миграций в `core/db.py` (ленивый импорт внутри шага). Проверяет `tests/test_registry.py::test_core_imports`. - Типы команд (`ensure_*`, `refresh`, `fetch_attachment`, `wiki_sync`, `wiki_fetch` и др.) и термины модулей (jira: `sync_run`, `issue_attachment`, `attachment_file`, `issue_comment`, `jql`, поля досок; wiki: `eva`, `wiki_`, `wiki/`, `DOC-`) живут только в модулях; ядро знает их лишь через `CommandHooks` и поля проекта. Проверяют `test_core_has_no_jira_terms` (исключение — `core/db.py`, история миграций) и `test_core_has_no_module_terms` (исключение — `core/registry.py`). Меток-исключений «долг» нет. - Новые имена в ядре — без названий модулей. Модуль не вызывается из ядра иначе как через `registry` и контракт `Module`. -- Копию вики (`wiki/<метка>/`, `wiki_page`, FTS) пишет только `sync.commit` в отчёте `wiki_sync`; MCP и API её читают. Модуль wiki не обращается к Eva и не хранит токен Eva. +- Копию вики (`wiki/<метка>/`, `wiki_page`, FTS) пишет только `sync.commit` в отчёте `wiki_sync` (и удаляет при сбросе корня `projects._drop_copy` в транзакции PATCH); MCP и API её читают. Модуль wiki не обращается к Eva и не хранит токен Eva. - Зеркало (включая `issue_attachment`) пишет только `mirror.apply_state` по запросу агента (и заметки через `PUT /issues/{key}/note`); из очереди и API задач напрямую не правят. - Журнал `issue_change` пишет только `history.record_changes` по `POST /agent/history`; API и MCP его только читают. - Хаб не знает пароль Jira и не обращается к Jira; `init` не переносит `auth`, `base_url`, `verify_ssl`, `ca_bundle`. @@ -145,6 +145,11 @@ golden-эталоны `__fixtures__/`), `issues/` (список, карточк - `commands`, `mirror`, `queue` не знают про HTTP; HTTP живёт только в `core/api`, `modules/*/api`, `client` и `relay` (реле — клиент своего же HTTP). - Веб-приложение (`web/`) ходит в хаб только через HTTP API (`web/src/api/client.ts`); словари `kind_labels`, `link_types` и набор закрытых статусов `closed_statuses` берёт из `GET /settings` и своих копий не держит. Модуль веба не импортирует другой модуль; общее — в `shell`, `ui`, `api`, `projects`. +## Выкатка и откат версии со схемой v7 +- Порядок: `git pull` → сразу `launchctl kickstart -k gui/$(id -u)/ru.aepif.jira-hub` (владелец) → `make web` → `/mcp` reconnect. Старый фронт с новым API работает (поля `board_id` и прочие на месте), поэтому сборку можно отложить. +- До kickstart не запускать MCP и CLI `jira-hub` (в том числе `tokens`): `HubClient.from_home()` и CLI открывают базу через `db.connect` и мигрируют её до v7, а хаб на прежнем коде (v6) с такой базой не работает (`agent_status`, токены). +- Откат на копию v6 из `backups/` (`*schema-v6*`): вместе с базой вернуть публикацию агента `release/jira/*` в `release/` (прежняя раскладка `release/agent.py`, `manifest.json`); иначе старый код увидит «публикации нет» и самообновление агента молчит. + ## Открытые вопросы - Правки из UI в Jira (спринт, срок, связи, исполнитель) — change `viewer-edit`; страницы очереди, агента и настроек — позже. - Автоподстройка темпа по фактам 429 не реализована: хаб только показывает их. diff --git a/README.md b/README.md index 9dc144e..ff090c1 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,10 @@ Python для хаба uv ставит свой (3.13, `.python-version`; сис `pyproject.toml`): в SQLite 3.51.0–3.51.1 есть взаимная блокировка, от которой хаб зависал под параллельными запросами. Первый `uv sync` или `uv run` после смены сам пересоздаёт `.venv`. -Код: ядро — `src/jira_hub/core/`, модуль jira — `src/jira_hub/modules/jira/`, веб — `web/src/` (модуль jira — `web/src/modules/jira/`); карта — `ARCHITECTURE.md`. +Код: ядро — `src/jira_hub/core/`, модуль jira — `src/jira_hub/modules/jira/`, модуль wiki — `src/jira_hub/modules/wiki/`, веб — `web/src/` (модуль jira — `web/src/modules/jira/`); карта — `ARCHITECTURE.md`. Данные лежат в `~/.local/share/jira-hub/` (каталог переопределяется переменной `JIRA_HUB_HOME`): -`hub.sqlite`, `backups/`, `release/<модуль>/` и `files/` (файлы вложений по sha256; каталоги — 0700). Пакет `mcp` закреплён версией `<2` (рулинг R-10): MCP SDK 2.x ломает API. +`hub.sqlite`, `backups/`, `release/<модуль>/`, `files/` (файлы вложений по sha256), `downloads/` (копии вложений для MCP) и `wiki/<метка>/` (Markdown-копия вики проекта); каталоги — 0700. Пакет `mcp` закреплён версией `<2` (рулинг R-10): MCP SDK 2.x ломает API. ## Первый запуск @@ -32,8 +32,8 @@ uv run jira-hub serve # 0.0.0.0:8790 `ca_bundle`) остаются у агента и в хаб не попадают. Повторный `init` отказывает ("уже инициализирован"); с `--force` настройки переписываются. Токены можно показать позже: `uv run jira-hub tokens`. -Передать агенту нужно адрес хаба и агентский токен: через общую папку виртуалки положить в `agent.json` -`"hub_url": "http://192.168.0.106:8790"` и `"hub_token": "<агентский токен>"`. Клиентский токен остаётся на этой машине: +Передать агенту jira нужно адрес хаба и токен агента jira (`uv run jira-hub tokens` → «агент jira»): через общую папку виртуалки положить в `agent.json` +`"hub_url": "http://192.168.0.106:8790"` и `"hub_token": "<токен агента jira>"`. Клиентский токен остаётся на этой машине: его использует MCP (читает из базы сам). Порт меняется ключом `--port` или настройкой `port`; адрес прослушивания — `--host`. @@ -241,10 +241,15 @@ curl -s -H "Authorization: Bearer $TOKEN" "http://127.0.0.1:8790/issues?sprint= ``` cd ~/projects/jira-bridge/jira-hub git pull -make web launchctl kickstart -k gui/$(id -u)/ru.aepif.jira-hub +make web ``` +Порядок важен для версии со схемой v7 (модуль wiki): сразу после `git pull` — kickstart, потом `make web`. До kickstart не +запускать MCP и CLI `jira-hub` (`tokens`, `mcp`, `import`): они открывают базу и переводят её в v7, а хаб на прежнем коде +с такой базой не работает. Старый фронт с новым API совместим, сборка может подождать. Откат на копию v6 из `backups/` — +вместе с возвратом `release/jira/*` в `release/` (прежняя раскладка), иначе старый код не найдёт публикацию агента. + Проект выбирается выпадающим списком «Проект» в верхней панели (метка и название); пункт «+ Новый проект…» открывает окно (метка, название, необязательно номер доски Jira): после создания приложение переходит в новый проект и показывает ход пакета обновления. Текущий проект — параметр `project` в адресе; без него приложение подставляет последний выбранный diff --git a/openspec/changes/wiki-module/specs/wiki/spec.md b/openspec/changes/wiki-module/specs/wiki/spec.md index 6ad79c9..b1ceceb 100644 --- a/openspec/changes/wiki-module/specs/wiki/spec.md +++ b/openspec/changes/wiki-module/specs/wiki/spec.md @@ -134,9 +134,9 @@ SHALL проверить, что файл есть в `files/` и размер Хаб SHALL предоставлять под клиентским токеном (проект — `project=<метка>`, неизвестный — 404, без корня — 409 `no_root`): - `GET /wiki/status?project=` — `{root, root_title, synced_at, pages, error, batch: {id, status} | null}`; -- `GET /wiki/tree?project=` — список `{code, title, depth, parent_code, size}` в порядке обхода; +- `GET /wiki/tree?project=` — `{"pages": [{code, title, depth, parent_code, size}]}` в порядке обхода; - `GET /wiki/pages/{code}?project=` — `{code, title, path, url, synced_at, markdown, attachments: [{id, name, state, - size}]}`; страницы нет в копии — 404; + size, error}]}`; страницы нет в копии — 404; - `GET /wiki/search?project=&q=&limit=` (`limit` 1–50, по умолчанию 10) — `{"results": [{code, title, path, snippet}]}` по убыванию релевантности; слова запроса ищутся по префиксу, пустой запрос — 422; - `POST /wiki/sync {project, author?}` → 201 `{batch_id}` (409 — см. «Синхронизация вики»);