diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 84fd40a..59be724 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,7 +1,7 @@ # Архитектура Агент — один файл `src/agent.py` и запускатель `src/run.py` (Python 3.9, только стандартная библиотека). Тесты в `tests/` работают на фейках -Jira и хаба. Спека: `../jira-hub/openspec/changes/bridge-core/`, план агента: `docs/superpowers/plans/2026-10-11-bridge-core-agent.md` (план хаба: `../jira-hub/docs/superpowers/plans/2026-10-11-bridge-core-hub.md`). +Jira и хаба. Спека: `../sdlc-hub/openspec/changes/bridge-core/`, план агента: `docs/superpowers/plans/2026-10-11-bridge-core-agent.md` (план хаба: `../sdlc-hub/docs/superpowers/plans/2026-10-11-bridge-core-hub.md`). ## Разделы файла `src/agent.py` @@ -9,7 +9,7 @@ Jira и хаба. Спека: `../jira-hub/openspec/changes/bridge-core/`, пл |---|---|---|---| | Настройки | `load_config` | читает `agent.json`, проверяет обязательные поля | — | | HTTP | `Http`, `HttpError`, `JiraClient`, `HubClient`, `multipart_file`, `wire_filename` | запросы; `Http.send` — запрос с готовым телом (JSON-вызов `call` идёт через него); `JiraClient` считает вызовы, повторяет 429/503 по `Retry-After` (до 5 запросов, не более 4 ожиданий), хранит время последнего вызова; `JiraClient.upload` — вложение `multipart/form-data` (таймаут не меньше 120 с); `JiraClient.download` (через `Http.fetch_bytes`) — содержимое вложения байтами, не больше предела (`TooBig`), перенаправление на другой адрес — `RedirectAway` без перехода (`_SameOriginRedirect`); `HubClient.file` — файл вложения у хаба (base64 в JSON), `HubClient.upload_file` — скачанный файл хабу (`POST /agent/files`) | `urllib` | -| Папка | `FolderTransport` | транспорт `folder:` к хабу через общую папку: `req/.json` → реле хаба → `resp/.json`; ошибки как у `Http`; `HubClient` делегирует ему `call` (спека `jira-hub/openspec/changes/folder-transport/`) | `os`, `uuid` | +| Папка | `FolderTransport` | транспорт `folder:` к хабу через общую папку: `req/.json` → реле хаба → `resp/.json`; ошибки как у `Http`; `HubClient` делегирует ему `call` (спека `sdlc-hub/openspec/changes/folder-transport/`) | `os`, `uuid` | | Журнал | `Journal`, `_parse_at` | дозапись `journal.jsonl`: `started` → `finished` → `acked`; восстановление; `prune` (из CLI — под блокировкой журнала) | файловая система | | Исполнитель | `Executor` и `do_<тип>` | по одному методу на тип команды: читает Jira, пишет только разницу; `refresh` читает и отправляет состояние в хаб, затем (v13, параметр `history`) журнал изменений Jira — `refresh_history`: изменившиеся с `history.since` задачи этого прогона и стартовая выборка `history.jql`, `search` с `expand=changelog`, `POST /agent/history` пачками по 500; ответ не 2xx Jira или хаба — `history.error`/`backfill_error`, `refresh` остаётся `done`; `ensure_attachment` берёт файл вложения у хаба (`hub_file`: sha256 и размер, повреждение — `HubError` с повтором); `fetch_attachment` (v14) читает вложение в Jira, качает содержимое по адресу из `base_url` (предел `MAX_ATTACHMENT`, 10 МБ) и отдаёт хабу; в состоянии `refresh` у задачи — `attachments` (список без содержимого, `attachments_of`); доски — из параметров команд (`ensure_sprint.board_id`, `refresh.boards`, тип доски — `board_type`), `board_id` настроек — запасной | `JiraClient`, `HubClient` (`refresh` и файл в `ensure_attachment`), настройки хаба | | Самообновление | `read_update_state`, `write_update_state`, `Updater`, `launcher_version` | `update.json`; после `claim` без команды — проверка `agent_release`, скачивание, sha256, компиляция, `selftest`, `staged`; подтверждение `ok` новой версией; без запускателя — только подсказка в лог | `HubClient`, `subprocess` | diff --git a/CLAUDE.md b/CLAUDE.md index 6385e21..c137687 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,11 +1,11 @@ # jira-agent ## Что это -Клиент моста Jira для виртуалки с доступом к Jira банка. Опрашивает хаб `jira-hub` (Mac mini), выполняет команды +Клиент моста Jira для виртуалки с доступом к Jira банка. Опрашивает хаб `sdlc-hub` (Mac mini), выполняет команды «желаемый результат» по правилу «проверь, потом сделай», ведёт журнал на диске и отдаёт хабу состояние задач. Главный сценарий: хаб ставит команду (например, создать задачу, перевести статус, перенести в спринт), агент читает задачу в Jira, записывает только разницу и возвращает результат; хаб синхронизирует зеркало через `refresh`. -Спека: `../jira-hub/openspec/specs/` (`agent/spec.md`, `commands/spec.md`). +Спека: `../sdlc-hub/openspec/specs/` (`agent/spec.md`, `commands/spec.md`). ## Стек и ограничения - Python 3.9.6 (как на виртуалке), только стандартная библиотека, без venv и зависимостей. @@ -15,7 +15,7 @@ Шаблон без секретов — `src/agent.example.json`. ## Архитектура -- `src/agent.py` — весь агент, один файл. Разделы в порядке файла: HTTP-клиенты (`Http`, `JiraClient`, `HubClient`; `FolderTransport` — транспорт `folder:` к хабу через общую папку, ошибки как у `Http`, спека `jira-hub/openspec/specs/agent/`), +- `src/agent.py` — весь агент, один файл. Разделы в порядке файла: HTTP-клиенты (`Http`, `JiraClient`, `HubClient`; `FolderTransport` — транспорт `folder:` к хабу через общую папку, ошибки как у `Http`, спека `sdlc-hub/openspec/specs/agent/`), `Journal`, `Executor` (по методу `do_<тип>` на каждый тип команды), `Runner` (цикл claim → пауза → журнал → выполнение → отчёт), `Updater` (самообновление: `update.json`, скачивание, `selftest`, выход 75), CLI (`cmd_check`, `cmd_selftest`, `cmd_run`, `cmd_prune`, `main`). @@ -48,12 +48,12 @@ ## Первая подсистема Исполнитель команд и цикл агента (спека `agent/spec.md`, `commands/spec.md`) — реализованы целиком: все типы команд, журнал, восстановление после перезапуска, CLI `run|check|selftest|prune`, самообновление через `run.py`. -Последний change — `../jira-hub/openspec/changes/attachment-fetch/` (агент v14: список вложений в `refresh`, команда `fetch_attachment`; решения агента — `openspec/changes/agent-v14-attachment-fetch/design.md`), план — `docs/superpowers/plans/2026-10-22-attachment-fetch-agent.md`. -План и спека живут в `jira-hub`: `openspec/changes/bridge-core/` и `docs/superpowers/plans/2026-10-11-bridge-core-hub.md`; план агента лежит здесь: `docs/superpowers/plans/2026-10-11-bridge-core-agent.md`. +Последний change — `../sdlc-hub/openspec/changes/attachment-fetch/` (агент v14: список вложений в `refresh`, команда `fetch_attachment`; решения агента — `openspec/changes/agent-v14-attachment-fetch/design.md`), план — `docs/superpowers/plans/2026-10-22-attachment-fetch-agent.md`. +План и спека живут в `sdlc-hub`: `openspec/changes/bridge-core/` и `docs/superpowers/plans/2026-10-11-bridge-core-hub.md`; план агента лежит здесь: `docs/superpowers/plans/2026-10-11-bridge-core-agent.md`. ## Выкатка новой версии Самообновление (с v5): после merge PR агента в main — поднять `AGENT_VERSION` (если не поднят в PR) и опубликовать: -`uv run --project ../jira-hub jira-hub agent publish src/agent.py` (из основного checkout `jira-agent` на main). +`uv run --project ../sdlc-hub sdlc-hub agent publish src/agent.py` (из основного checkout `jira-agent` на main). Через несколько минут MCP `agent_status` должен показать «обновление: ok v<старая> → v<новая>»; откат — «откат с v…» (причина — в логе агента на виртуалке). Это пункт чеклиста «закрывай» для PR агента. `run.py` публикацией не обновляется — только вручную через общую папку. diff --git a/README.md b/README.md index 87b5653..0b31747 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # jira-agent -Клиент моста Jira для виртуалки с доступом к Jira банка. Агент опрашивает хаб (`jira-hub` на Mac mini), +Клиент моста Jira для виртуалки с доступом к Jira банка. Агент опрашивает хаб (`sdlc-hub` на Mac mini), выполняет команды «желаемый результат» в Jira по правилу «проверь, потом сделай», ведёт журнал на диске и возвращает хабу состояние задач. Один файл `src/agent.py` и запускатель `src/run.py`, только стандартная библиотека, Python 3.9. -Спека: `../jira-hub/openspec/specs/agent/spec.md` (вместе с `commands/` и `hub-api/`). -Хаб, очередь команд и зеркало задач живут в репозитории `jira-hub`; агент с ним общается только по HTTP. +Спека: `../sdlc-hub/openspec/specs/agent/spec.md` (вместе с `commands/` и `hub-api/`). +Хаб, очередь команд и зеркало задач живут в репозитории `sdlc-hub`; агент с ним общается только по HTTP. ## Доставка на виртуалку @@ -14,7 +14,7 @@ виртуалке, например `~/jira-agent/`. Запускать из этого каталога, не из общей папки. 2. Переименовать `agent.example.json` в `agent.json` и заполнить: - `hub_url` — `http://<адрес Mac mini>:8790`, или, если сеть до Mac mini закрыта VPN (Континент), `folder:/Volumes/My Shared Files/RSHB/jira-bridge` — обмен через общую папку UTM (на хабе должна быть задана настройка `relay_dir`, см. README хаба); - - `hub_token` — агентский токен из `jira-hub tokens` на Mac mini; + - `hub_token` — агентский токен из `sdlc-hub tokens` на Mac mini; - `jira.base_url` — адрес Jira банка; - `jira.auth` — `{"type": "basic", "user": ..., "password": ...}` или `{"type": "bearer", "token": ...}`; - `verify_ssl`, `ca_bundle` — при корпоративном сертификате (см. ограничение 2 ниже); @@ -88,7 +88,7 @@ nohup python3 -u run.py > agent.log 2>&1 & ## Самообновление -С версии 5 агент обновляется сам. После `jira-hub agent publish` на Mac mini хаб сообщает новую версию в ответе на +С версии 5 агент обновляется сам. После `sdlc-hub agent publish` на Mac mini хаб сообщает новую версию в ответе на `claim`. Агент в паузе между командами (очередь пуста, отчёты подтверждены) скачивает файл по `GET /agent/release`, сверяет sha256, компилирует, проверяет `AGENT_VERSION`, кладёт рядом `agent.py.new`, запускает его `selftest` и выходит с кодом 75. `run.py` копирует текущий `agent.py` в `agent.py.prev`, ставит новый и запускает его в пробном режиме: diff --git a/src/agent.example.json b/src/agent.example.json index 20245eb..457d8f6 100644 --- a/src/agent.example.json +++ b/src/agent.example.json @@ -1,6 +1,6 @@ { "hub_url": "http://192.168.0.106:8790", - "hub_token": "агентский токен из `jira-hub tokens`", + "hub_token": "агентский токен из `sdlc-hub tokens`", "jira": { "base_url": "https://sdlc.go.rshbank.ru/jira", "auth": {"type": "basic", "user": "логин", "password": "пароль", "token": ""}