Модуль wiki, агенты модулей, поля проектов (#91) #92

Merged
aep merged 46 commits from feat/91-wiki into main 2026-10-24 09:05:09 +03:00
Owner

Closes #91

Второй шаг к sdlc-hub. Он даёт:

  • модуль wiki: Markdown-копию дерева EVA Wiki по проекту, поиск, вложения по запросу, MCP jira-hub-wiki и страницу «Вики»;
  • агентов по модулям (jira, wiki) в ядре;
  • поля проекта от модулей: доски Jira уехали из ядра в модуль jira, долга hub-modules больше нет.

Спека: openspec/changes/wiki-module/. План: docs/superpowers/plans/2026-10-24-wiki-module.md.

eva-agent — отдельный репозиторий aep/eva-agent, отдельный PR.

Что сделано

  • Миграция v7 (одним шагом, копия базы перед ней):
    • tokens = {client, agents: {jira, wiki}}, прежний агентский токен стал токеном jira;
    • agent_status хранит строку на каждого агента;
    • доски переехали в jira_project.
  • Агенты.
    • claim, релиз (release/<модуль>/), самообновление и /agent/settings у каждого агента свои.
    • Агенты работают параллельно.
    • Маршруты модуля доступны только агенту этого модуля, чужая команда — 404.
    • Новые точки: GET /agents, GET /agent?module=, jira-hub agent publish --module.
  • Проекты.
    • ProjectField и project_view у модулей.
    • Новый PATCH /projects/{label}.
    • В окне «Новый проект» поля собираются из модулей.
  • Модуль wiki:
    • корень проекта wiki_root;
    • команды wiki_sync и wiki_fetch;
    • приём пачек страниц POST /agent/wiki/pages;
    • перевод HTML в Markdown (markdownify, ссылки attachment:/page:);
    • сборка копии с атомарной подменой каталога;
    • FTS5;
    • маршруты /wiki/*;
    • синхронизация раз в сутки;
    • MCP jira-hub-wiki (9 инструментов);
    • страница «Вики».
  • Документация: ARCHITECTURE, CLAUDE.md, README.

Совместимость

  • jira-agent v14 работает без обновления. Это проверяет сквозной HTTP-тест на базе v6: прежний токен, claim, релиз v14, /agent/settings без board_id.
  • tests/fixtures/baseline/mcp_tools.expected.json (сервер jira-hub) не изменился ни на байт.
  • Изменения эталонов:
    • schema: v7, agent_status, jira_project, таблицы wiki;
    • settings: ключи wiki, min_agent_version переехал в jira, board_id удалён;
    • routes: только новые маршруты.

Проверка

  • make check: pytest 957 passed, vitest 52 files / 485 tests passed, tsc и eslint чистые.
  • npm run e2e: 39 passed, 44 skipped (screens-тесты).
  • openspec validate wiki-module --strict: valid.

⚠️ Выкатка — порядок важен (I-2)

Порядок: git pull → сразу launchctl kickstart -k gui/$(id -u)/ru.aepif.jira-hub → make web → /mcp reconnect.

Между pull и kickstart нельзя запускать jira-hub mcp, jira-hub tokens и переподключать MCP. Новый код мигрирует живую базу в v7, а старый процесс хаба с ней уже не работает.

Откат: предыдущий коммит, копия базы backups/*schema-v6* и возврат release/jira/* в release/.

Rulings I made

Полный список с ценой ошибки — design.md, раздел «Decisions made without discussion», #1–#79. Основные:

  • R-1 (#18). INSERT OR IGNORE строк agent_status для агентов модулей при каждом migrate.
    Цена ошибки: правка одного места.
  • R-2 (#19). POST /projects отдаёт {project, batch_id}, как в спеке, без batch_ids.
    Цена ошибки: второй пакет виден только через GET /batches.
  • R-3 (#20). Тест границы ядра ищет (?i:\beva\b|wiki_|wiki/)|DOC-.
    Цена ошибки: правка регэкспа.
  • R-4 (#21). Очистка FTS при сбросе корня идёт, только если таблица есть.
    Цена ошибки: закрыто в Task 7.
  • R-5 (#47). Имя каталога копии — paths.dir_name(label) с экранированием.
    Цена ошибки: экзотические метки получают экранированное имя.
  • R-6 (#57). Новые необязательные хуки ядра CommandHooks.before_result/abort_result: копия собирается вне блокировки базы.
    Цена ошибки: правка контракта модуля.
  • R-7 (#63). GET /wiki/search → {"results": [...]}, спека поправлена.
    Цена ошибки: формат ответа.
  • R-8 (#76). Финальная волна закрыла I-1, I-3, M-1…M-6, M-8…M-15. I-2 и M-13 закрыты документацией, M-7 и T8.3 ушли в follow-up.
    Цена ошибки: два известных недочёта.
  • Решения исполнителей, которые стоит перечитать:
    • ProjectField.validate_edit (#78);
    • проверка «изменяемое поле без on_project_updated» в registry.check (#42);
    • миграция через DROP COLUMN, нужен SQLite ≥ 3.35 (#36);
    • FTS-таблица создаётся лениво (#61);
    • первая автосинхронизация ставится сразу (#50);
    • копия готовится в .<метка>.new.<id> под замком метки (#59);
    • внешние Markdown-картинки не загружаются (#73).

Отложено (уйдёт в follow-up issue при закрытии)

  • Главное:
    • M-7 — замерить переиндексацию FTS под блокировкой записи;
    • T8.3 — command_retry даёт второй живой wiki_sync;
    • T9.4 — /wiki/attachments/{id} не привязан к проекту сессии.
  • Остальное:
    • T1.4, T1.5;
    • T2.1–T2.4;
    • T3.5, T3.6;
    • T4.1, T4.2, T4.4, T4.5;
    • T6.1–T6.5;
    • T7.1–T7.8;
    • T8.1, T8.2, T8.4–T8.9;
    • T9.1–T9.3, T9.6, T9.7;
    • T10.1–T10.8, из них T10.8 — ручной просмотр тем и ширины 390 px;
    • T11.4.
  • Наблюдение: O-1.

🤖 Generated with Claude Code

Closes #91 Второй шаг к sdlc-hub. Он даёт: - **модуль `wiki`:** Markdown-копию дерева EVA Wiki по проекту, поиск, вложения по запросу, MCP `jira-hub-wiki` и страницу «Вики»; - **агентов по модулям** (`jira`, `wiki`) в ядре; - **поля проекта от модулей:** доски Jira уехали из ядра в модуль jira, долга `hub-modules` больше нет. Спека: `openspec/changes/wiki-module/`. План: `docs/superpowers/plans/2026-10-24-wiki-module.md`. eva-agent — отдельный репозиторий `aep/eva-agent`, отдельный PR. ## Что сделано - **Миграция v7** (одним шагом, копия базы перед ней): - `tokens` = `{client, agents: {jira, wiki}}`, прежний агентский токен стал токеном `jira`; - `agent_status` хранит строку на каждого агента; - доски переехали в `jira_project`. - **Агенты.** - `claim`, релиз (`release/<модуль>/`), самообновление и `/agent/settings` у каждого агента свои. - Агенты работают параллельно. - Маршруты модуля доступны только агенту этого модуля, чужая команда — 404. - Новые точки: `GET /agents`, `GET /agent?module=`, `jira-hub agent publish --module`. - **Проекты.** - `ProjectField` и `project_view` у модулей. - Новый `PATCH /projects/{label}`. - В окне «Новый проект» поля собираются из модулей. - **Модуль wiki:** - корень проекта `wiki_root`; - команды `wiki_sync` и `wiki_fetch`; - приём пачек страниц `POST /agent/wiki/pages`; - перевод HTML в Markdown (`markdownify`, ссылки `attachment:`/`page:`); - сборка копии с атомарной подменой каталога; - FTS5; - маршруты `/wiki/*`; - синхронизация раз в сутки; - MCP `jira-hub-wiki` (9 инструментов); - страница «Вики». - **Документация:** ARCHITECTURE, CLAUDE.md, README. ## Совместимость - jira-agent v14 работает без обновления. Это проверяет сквозной HTTP-тест на базе v6: прежний токен, `claim`, релиз v14, `/agent/settings` без `board_id`. - `tests/fixtures/baseline/mcp_tools.expected.json` (сервер `jira-hub`) не изменился ни на байт. - Изменения эталонов: - `schema`: v7, `agent_status`, `jira_project`, таблицы wiki; - `settings`: ключи wiki, `min_agent_version` переехал в jira, `board_id` удалён; - `routes`: только новые маршруты. ## Проверка - `make check`: pytest `957 passed`, vitest `52 files / 485 tests passed`, tsc и eslint чистые. - `npm run e2e`: `39 passed`, `44 skipped` (screens-тесты). - `openspec validate wiki-module --strict`: valid. ## ⚠️ Выкатка — порядок важен (I-2) Порядок: `git pull` → **сразу** `launchctl kickstart -k gui/$(id -u)/ru.aepif.jira-hub` → `make web` → `/mcp` reconnect. Между pull и kickstart нельзя запускать `jira-hub mcp`, `jira-hub tokens` и переподключать MCP. Новый код мигрирует живую базу в v7, а старый процесс хаба с ней уже не работает. Откат: предыдущий коммит, копия базы `backups/*schema-v6*` и возврат `release/jira/*` в `release/`. ## Rulings I made Полный список с ценой ошибки — `design.md`, раздел «Decisions made without discussion», #1–#79. Основные: - **R-1 (#18).** `INSERT OR IGNORE` строк `agent_status` для агентов модулей при каждом `migrate`. Цена ошибки: правка одного места. - **R-2 (#19).** `POST /projects` отдаёт `{project, batch_id}`, как в спеке, без `batch_ids`. Цена ошибки: второй пакет виден только через `GET /batches`. - **R-3 (#20).** Тест границы ядра ищет `(?i:\beva\b|wiki_|wiki/)|DOC-`. Цена ошибки: правка регэкспа. - **R-4 (#21).** Очистка FTS при сбросе корня идёт, только если таблица есть. Цена ошибки: закрыто в Task 7. - **R-5 (#47).** Имя каталога копии — `paths.dir_name(label)` с экранированием. Цена ошибки: экзотические метки получают экранированное имя. - **R-6 (#57).** Новые необязательные хуки ядра `CommandHooks.before_result`/`abort_result`: копия собирается вне блокировки базы. Цена ошибки: правка контракта модуля. - **R-7 (#63).** `GET /wiki/search` → `{"results": [...]}`, спека поправлена. Цена ошибки: формат ответа. - **R-8 (#76).** Финальная волна закрыла I-1, I-3, M-1…M-6, M-8…M-15. I-2 и M-13 закрыты документацией, M-7 и T8.3 ушли в follow-up. Цена ошибки: два известных недочёта. - **Решения исполнителей**, которые стоит перечитать: - `ProjectField.validate_edit` (#78); - проверка «изменяемое поле без `on_project_updated`» в `registry.check` (#42); - миграция через `DROP COLUMN`, нужен SQLite ≥ 3.35 (#36); - FTS-таблица создаётся лениво (#61); - первая автосинхронизация ставится сразу (#50); - копия готовится в `.<метка>.new.<id>` под замком метки (#59); - внешние Markdown-картинки не загружаются (#73). ## Отложено (уйдёт в follow-up issue при закрытии) - **Главное:** - M-7 — замерить переиндексацию FTS под блокировкой записи; - T8.3 — `command_retry` даёт второй живой `wiki_sync`; - T9.4 — `/wiki/attachments/{id}` не привязан к проекту сессии. - **Остальное:** - T1.4, T1.5; - T2.1–T2.4; - T3.5, T3.6; - T4.1, T4.2, T4.4, T4.5; - T6.1–T6.5; - T7.1–T7.8; - T8.1, T8.2, T8.4–T8.9; - T9.1–T9.3, T9.6, T9.7; - T10.1–T10.8, из них T10.8 — ручной просмотр тем и ширины 390 px; - T11.4. - **Наблюдение:** O-1. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
aep added 46 commits 2026-10-24 03:26:58 +03:00
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tokens -> {client, agents: {модуль: токен}}, agent_status по агентам
(ключ agent, last_call_at), настройки агента и маршруты agent-scope по
модулю токена, min_agent_version переехал в модуль jira.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Окно «Новый проект» собирает поля из MODULES[].projectFields; Project — ядро плюс поля модулей;
useUpdateProject (PATCH /projects/{label}); метка «долг hub-modules» снята; e2e читают токен агента из tokens.agents.jira.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Каркас модуля wiki: схема (wiki_project, wiki_page, wiki_attachment, wiki_sync_stage), настройки,
поле проекта wiki_root с хуками создания и правки, команды wiki_sync и wiki_fetch,
фоновая синхронизация. Зависимость markdownify>=1.2.3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
convert.to_markdown: вложения по ref (картинка и миниатюра+файл — одна ссылка),
ссылки на страницы DOC-… → page:<код>, static/ удаляются, сырого HTML нет.
convert.fill_ids подставляет id вложений вместо attachment:@<n>.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Схемы javascript:/data:/vbscript: в ссылках не выводятся; имя вложения и текст
ссылки экранируются (скобки, @, переводы строк); fill_ids меняет только
](attachment:@N) и поднимает ValueError вне диапазона; «<» в тексте — &lt;;
attachments/links = None трактуются как пустые списки.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Двойное экранирование текста ссылки на страницу убрано; «@» больше не
экранируется. Ссылку на вложение выдаёт только конвертер (внутренний маркер),
авторское «attachment:@» в тексте, атрибутах, коде и именах нейтрализуется,
схема attachment: у ссылок и картинок автора не выводится.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fmt_agent, safe_name и store_copy вынесены в core/mcp.py; сервер jira их переэкспортирует, тексты вывода не менялись.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Модуль wiki: дерево страниц, страница с Markdown (react-markdown, remark-gfm, без сырого HTML),
поиск, форма привязки корня, ход синхронизации в боковой панели, скачивание вложений,
поле «Корень вики» в окне нового проекта. Сид копии вики и e2e.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Дерево не раскрывает предков повторно после ручного сворачивания, предел опроса вложения,
//host не ссылка, регистр схем page:/attachment:, тесты дерева, загрузки, плашки панели, 422/404.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Эффект раскрытия предков зависит только от selected; тест с новым массивом nodes;
заглушки URL.createObjectURL в тесте загрузки через spyOn.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Тест границы test_core_has_no_module_terms; ARCHITECTURE/CLAUDE/README; дельта-спека о хуках before_result/abort_result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- root_set кодирует метку; parse_root вынесен в wiki/roots.py; PATCH wiki_root "" -> 422
- суррогаты в пачке страниц заменяются; dir_name экранирует ведущую точку; error у вложений
- beautifulsoup4 и markdownify<2 объявлены; убраны неиспользуемые импорты и дубль _has_table

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
aep merged commit 3b88b8be2a into main 2026-10-24 09:05:09 +03:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: aep/sdlc-hub#92
No description provided.