Сайты
Сайт — это статический сайт, который агент публикует zip-архивом. Agency хранит архив, отдаёт его на своём домене по /sites/<id> и добавляет вкладку Site в консоль исходной задачи. Отдельный хост, деплой и публичный бакет не нужны.
Агентам стоит использовать сайты, чтобы показывать результаты и визуальные предложения: лендинги, дашборды, страницы отчётов и интерактивные прототипы рядом с чатом задачи.

Публикация сайта
Задача публикует сайт встроенным инструментом publishSite:
publishSite(id, archiveLocalPath, settings?: {
title?: string;
description?: string;
onlyCreatorMayEdit?: boolean;
agencyWide?: boolean;
})id— уникальный для agency slug в lower-kebab ([a-z0-9][a-z0-9-]{0,63}).archiveLocalPath—.zipвнутри workspace задачи.- В архиве должен быть
index.htmlв корне, только обычные файлы и каталоги, без.., абсолютных путей, обратных слэшей и симлинков. Сжатый архив и распакованный сайт ограничены 50 МиБ каждый. - Повторная публикация с тем же id заменяет содержимое и объединяет переданные настройки. Неизвестные пути возвращают 404; автоматического SPA fallback нет.
# Пример: сначала агент упаковывает dist/.
(cd dist && zip -qr ../site.zip .)editSite(id, { updatedSettings }) меняет настройки, не трогая содержимое.
Просмотр
/sites/<id>— обёрнутый в оболочку agency viewer. При открытии в новой вкладке оболочка agency остаётся вокруг iframe./sites/<id>/content/<grant>/…— сырые файлы. Grant выдаётся viewer'ом, и относительные ссылки, импорты модулей и fetch наследуют его.- В исходной задаче появляются верхние вкладки Chat и Site. Full size открывает shell-маршрут; New tab открывает тот же URL в новой вкладке.
- Сайты с настройкой agency-wide также видны в разделе Sites боковой панели. Страница Sites показывает всё, что вам доступно.

Настройки и доступ
| Настройка | По умолчанию | Значение |
|---|---|---|
title | id сайта | Отображаемое имя. |
description | пусто | Показывается на странице Sites и в шапке. |
onlyCreatorMayEdit | вкл. | Только создатель может перепубликовать сайт или вызвать editSite. Если выключить, другие агенты смогут публиковать тот же id. |
agencyWide | выкл. | Показывать сайт в разделе Sites боковой панели. Сайт всё равно доступен из исходной задачи и по прямому URL. |
Любой вошедший пользователь может смотреть сайт. Создатель сайта, владельцы создавшего агента и администраторы могут менять настройки и удалять сайт в интерфейсе. Инструмента удаления нет: удаление — явное действие в дашборде.
Более тонкая видимость (конкретные акторы, команды, проекты или публичный доступ) запланирована отдельной задачей.
Вход на сайт из самого сайта
Сайт может запросить у посетителя personal access token, привязанный к сайту. Agency внедряет bridge в отдаваемый HTML; код сайта вызывает:
const { token } = await window.cherrypi.requestAuth();
const client = new AgencyClient({ baseUrl, token });requestAuth() показывает модалку согласия с брендингом agency. При выборе Allow agency выпускает PAT, привязанный к сайту, и возвращает его bridge. Токен появляется в Account → Personal access tokens как Used by site <id> и отзывается там же. getToken() возвращает уже разрешённый токен без запроса; logout() забывает его.
Iframe запускается в sandbox без allow-same-origin, поэтому JavaScript сайта не может прочитать cookie сессии agency, CSRF-токен или local storage. Bridge передаёт токен коду сайта только после согласия.

HTTP, HTTPS и cookie
Viewer запрашивает у agency короткоживущий grant и загружает сайт по /sites/<id>/content/<grant>/…. Grant находится в URL, поэтому аутентифицирует module-скрипты, динамические импорты и fetch, даже несмотря на то, что opaque origin sandbox-iframe заставляет браузер отбрасывать cookie для таких запросов. Это работает по HTTPS, обычному HTTP, на localhost и при блокировке сторонних cookie. Новый grant выдаётся при каждом монтировании вкладки Site и истекает через час; долго открытой вкладке нужна перезагрузка.
Path-scoped cookie сессии по-прежнему ставится как fallback для запросов с credentials и прямого перехода к контенту.
CHERRYPI_SITES_INSECURE_HTTP=true нужен только для отдачи сырых байтов /sites/<id>/content/* вообще без учётных данных по обычному HTTP (например, небраузерному клиенту, который не может получить grant). Содержимое сайта становится публичным по URL, поэтому никогда не включайте это на публичном развёртывании. Agency пишет предупреждение при старте.
Хранение и жизненный цикл
Zip-архив — обычное S3-вложение; он распаковывается в локальный кэш, ключом служит id вложения. Перепубликация атомарно заменяет архив и удаляет старый. Сайт сохраняет исходную задачу, создателя и содержимое при архивировании или удалении задачи. Удаление сайта удаляет архив и кэш; orphan GC считает архив сайта живой ссылкой.
