0.134.51

Changed

  • Рефакторинг дублирующего функционала между /settings/ и /agents/{id}/. Анализ выявил четыре класса пересечений: (A) явный дубль (Cron/Heartbeat продублированы в settings без добавленной ценности — агрегация по всем агентам реализовалась циклом по per-agent эндпоинтам, т.е. settings-страницы не имели собственного бэкенда); (B2) смешение уровней управления (Skills: матрица «навык × агент» жила и в settings, и в агенте); (C) спрятанный UX (MCP-активация для агента была вложена в permissions → mcp вместо отдельного пункта навигации); (D1) дубль редактирования полей агента (settings/agents vs /agents/{id}). Рефакторинг только frontend — backend (Go handlers/services/store) не тронут, т.к. все эндпоинты переиспользуются оставшимися разделами; специфичных admin-агрегирующих эндпоинтов для cron/heartbeat не существует (проверено grep’ом /api/v1/admin/(cron|heartbeat) → 0). Netto: −717 строк.
  • Категория A — убран дубль из settings. Удалены web/src/routes/settings/cron/ (3 файла) и web/src/routes/settings/heartbeat/ (3 файла). Пункты cron, heartbeat убраны из SettingsSidebar.svelte. Управление cron/heartbeat осталось только в /agents/{id}/cron и /agents/{id}/heartbeat (как и должно быть — сущности привязаны к агенту).
  • Категория B2 — Skills: разделение уровней. settings/skills/+page.svelte упрощён: убрана матрица «навык × агент» (привязка управляется только из агента); оставлен CRUD глобального каталога. В /agents/{id}/skills/+page.svelte иконка «Редактировать» убрана для глобальных и встроенных навыков (рендерится только для индивидуальных skill_owner_agent_id === agentId). Страница /agents/{id}/skills/{skillId} для глобальных/builtin навыков теперь показывает read-only превью (имя, описание, метаданные, триггеры, контент в <pre>) вместо формы редактирования.
  • Баг ownership-check (найден ocr review, критичный): isEditableInAgent/confirmRemoveSkill/removeSkill проверяли skill_owner_agent_id !== null без сверки с agentId. Навык, принадлежащий другому агенту, ошибочно классифицировался как «редактируемый здесь» и при удалении хард-делетился через api.skills.delete. Исправлено: проверка skill_owner_agent_id === agentId во всех трёх точках; убрана unreachable-ветка !== undefined (тип поля — number | null).
  • Прочее из review: вынесен единый parseSkillMetadata helper (устранено дублирование JSON-парсинга между initialData и parsedMeta), guard !isNaN(date.getTime()) против «Invalid Date», aria-label на back-link, убран избыточный && initialData в read-only ветке. В settings/skills: пустой catch {} в loadSkills теперь показывает ошибку; error сбрасывается перед повторным delete.
  • Категория C — MCP: отдельный пункт навигации агента. Создан новый маршрут /agents/{id}/mcp/+page.svelte — обёртка над переиспользуемым McpPermissionsCard (loading через PermissionsStore, своя кнопка save). Пункт mcp добавлен в навигацию агента (+layout.svelte, группа «Агент», рядом с webhooks). Вкладка mcp убрана из /agents/{id}/permissions: 'mcp' удалён из PermSectionKey и SECTIONS (usePermissionTab.svelte.ts), import и ветка {:#else if tab.active === 'mcp'} удалены из permissions/+page.svelte. Подключение серверов (stdio/SSE/HTTP, OAuth) осталось в settings/mcp (как и должно быть по модели «подключение в settings, активация у агента»).
  • Категория D1 — settings/agents → только каталог. Модалка редактирования существующего агента удалена (редактирование — в /agents/{id}). Форма создания упрощена до name + description (убраны context_max_tokens и realtime_extraction). Блок участников удален (управление — в /agents/{id}/members).
  • Функциональные регрессии (найдены ocr review, исправлены): (1) context_max_tokens/realtime_extraction после удаления из settings нигде не редактировались — добавлена секция «Настройки контекста» в Профиль агента (/agents/{id}/+page.svelte, только для canEditAgent), сохранение через api.agents.update. (2) Удаление агента нигде не было доступно — добавлена секция «Опасная зона» в Профиль с ConfirmModal и редиректом на /agents после api.agents.delete.
  • Прочее из review: error-баннер при ошибке создания был скрыт за fixed inset-0 оверлеем модалки — теперь дублируется внутри модалки рядом с кнопками; name/description триммятся перед api.agents.create.
  • Что НЕ менялось: audit в settings и в агенте (по решению — разные срезы); backend (Go); все остальные разделы settings и агента. 309 a11y-warnings в svelte-check — pre-existing паттерны проекта (div+onclick-модалки, <label> без for), не связанные с рефакторингом.