Как работает плагин
Плагин — это npm-пакет, в котором бывает до трёх точек входа, по одной на процесс bb. Серверная точка входа обязательна и работает внутри сервера. Клиентская точка входа (необязательная) работает в окне приложения, а хостовая (тоже необязательная) — на машине агента. Точки входа не делят память. Они общаются через RPC, push-канал реального времени и хостовый RPC, а всё долговременное состояние живёт в серверной точке входа. bb загружает каждую точку входа с полным доверием. Если вы ещё не знакомы с этими тремя процессами, сначала прочитайте Как работает bb.
Три точки входа
Заголовок раздела «Три точки входа»Манифест — это package.json плагина. Блок bb в нём перечисляет точки входа:
"bb": { "name": "Hello", "server": "./server.ts", // required "app": "./app.tsx", // optional: UI in the app window "host": "./host.ts" // optional: code on the agent's machine}| Точка входа | Работает в | Для чего нужна | Формат |
|---|---|---|---|
серверная точка входа, bb.server | процессе сервера bb | хранилища, RPC- и HTTP-маршруты, CLI-команды, инструменты агента, провайдеры, расписания | экспортируемая по умолчанию фабрика (bb: BbPluginApi) => … |
клиентская точка входа, bb.app | окне приложения, в том же JS-контексте, что и собственный интерфейс bb | панели, контролы и рендереры в окне, дополнения в композере, команды палитры | definePluginApp((app) => …) |
хостовая точка входа, bb.host | процессе хост-воркера, который демон хоста запускает на своей машине | файлы, процессы и мост агента на машине агента | experimental_defineHostEntry({ contract, handlers }) |
Серверная точка входа обязательна, даже если плагин добавляет только интерфейс: в файле plugins/scheduled-send/server.ts лежит намеренная заглушка. Все поля манифеста описаны в Анатомии пакета.
Ни серверная, ни клиентская точка входа не запускают главный цикл. Серверная точка входа — это функция, которую bb вызывает один раз за загрузку и передаёт ей свежий объект bb. Эта функция регистрирует всё, что предоставляет плагин (RPC-метод, CLI-команду, настройку, инструмент агента), и возвращает управление. Клиентская точка входа делает то же самое через объект app: регистрирует панель, компонент слота или команду, а bb монтирует этот компонент там, где в окне находится нужный слот. С этого момента bb вызывает код плагина, когда он нужен человеку, агенту или другому процессу. Вызовы регистрации перечислены в Неймспейсах бэкенда и Слотах фронтенда.
Как общаются точки входа
Заголовок раздела «Как общаются точки входа»app.tsx
useRpc<typeof rpcContract>()
rpc.call("listIssues", { … })
import type — the backend is erased from the bundle
1↓ rpc.call(…) → POST /plugins/<id>/rpc/<method>
POST /plugins/<id>/rpc/<method>
input schema → handler → output schema
2↓ validation → server.ts — the factory, in the server process
server.ts — the factory, in the server process
bb.rpc.register(…)
bb.http.route(…)
bb.cli.register({ name, run })
bb.agents.registerTool(…)
bb.realtime.publish(…)
the result is strict JSON
3↓ bb.realtime.publish → WebSocket /ws — one shared socket (signal back)
8↓ host RPC → host.ts, on the agent’s machine
↓ read and write → state and the outside world
useRealtime("issues:changed", fn)
the same component refetches its data
WebSocket /ws — one shared socket
{ type, pluginId, channel, payload }
broadcast to all; the client filters
4↓ useRealtime → refetch → useRealtime("issues:changed", fn) (signal back)
bb CLI
bb <command> … · argv without the command name
5↓ POST /cli → POST /plugins/<id>/cli
POST /plugins/<id>/cli
run() executes on the server
↓ server.ts — the factory, in the server process
agent tool
the tool set is frozen at session start
6↓ execute(…) → called inside the server process
called inside the server process
errors come back as text
↓ server.ts — the factory, in the server process
external service · webhook
POST with the signature in the request body
7↓ signature in the body → ALL /plugins/<id>/http/<path>
ALL /plugins/<id>/http/<path>
your own route, exact path match
↓ server.ts — the factory, in the server process
state and the outside world
bb.storage.kv · bb.storage.database()
fetch · fs · child_process
host.ts, on the agent’s machine
called through bb.hosts.experimental_client(…)
signals back with experimental_emitSignal(…)
Серверная точка входа служит хабом. Все клиенты обращаются к плагину через неё, и у каждого есть ровно один канал:
| Канал | Откуда → куда | Для чего нужен | Справочник |
|---|---|---|---|
| RPC | клиентская точка входа → серверная точка входа | чтение и изменение данных из интерфейса; контракт определяется один раз в серверной точке входа, а клиентская импортирует только его тип | bb.rpc |
| realtime | серверная точка входа → каждое открытое окно | уведомление страниц об изменении данных, чтобы они запросили их заново; ничего не сохраняется и не воспроизводится | bb.realtime |
| CLI | CLI bb → серверная точка входа | команда bb <command> для людей и агента; выполняется на сервере, а не в CLI | bb.cli |
| инструмент агента | агент → серверная точка входа | нативный инструмент в сессии агента, вызываемый внутри процесса сервера | bb.agents |
| HTTP | внешний сервис → серверная точка входа | вебхуки и другие вызывающие стороны за пределами bb | bb.http |
| хостовый RPC | серверная точка входа ⇄ хостовая точка входа | работа на машине агента с отправкой сигналов обратно | bb.hosts |
Двух каналов намеренно нет. Клиентская точка входа не может напрямую вызывать хостовую: она вызывает серверную точку входа по RPC, а та уже обращается к хостовой. Также ни одна точка входа не может напрямую обратиться к другому плагину.
Скилл завершает картину для агента. Плагин поставляет файл skills/<name>/SKILL.md, bb внедряет его в треды агента, и скилл говорит агенту, какую команду bb выполнить. Затем агент проходит через CLI-канал так же, как человек, вместо того чтобы напрямую обращаться к хранилищу плагина. В Первом плагине разобран шаблон плагина, который использует RPC, realtime, CLI и скилл для работы с единым хранилищем.
Состояние живёт в серверной точке входа
Заголовок раздела «Состояние живёт в серверной точке входа»Серверная точка входа владеет всем долговременным состоянием: значениями в bb.storage.kv, собственной базой данных SQLite из bb.storage.database() и настройками, объявленными через bb.settings.define. Клиентская точка входа хранит только то, что рендерит. Она запрашивает данные по RPC и запрашивает их заново при получении realtime-сигнала, поэтому каждое открытое окно показывает одни и те же данные. Хостовая точка входа держит собственные файлы на своей машине в каталоге, который ей выдаёт bb.
Это позволяет плагину оставаться компактным по мере роста. Страница, CLI-команда и инструмент агента — три клиента одних и тех же функций в серверной точке входа, поэтому добавление поверхности в готовый плагин обычно требует лишь написать ещё один вызов существующего кода.
Загрузка, перезагрузка и dispose
Заголовок раздела «Загрузка, перезагрузка и dispose»bb запускает фабрику серверной точки входа при каждой загрузке плагина: при старте сервера, после установки, по команде bb plugin reload и после каждого сохранения, пока работает bb plugin dev. Из этого следуют четыре правила:
- Работа фабрики ограничена 30 секундами. То, что длится дольше или выполняется бесконечно, помещайте в фоновый сервис через
bb.background.service. - Объект
bbвалиден ровно одну загрузку. После перезагрузки сохранённая ссылка на него выбрасывает ошибкуPluginContextStaleError, поэтому никогда не сохраняйтеbbв переменную на уровне модуля. - При перезагрузке bb сначала загружает новый экземпляр, а затем вызывает dispose для старого. Если новая фабрика падает с ошибкой, старый экземпляр продолжает работать, а его статус остаётся
runningс пометкой «reload failed: …». - Помещайте код очистки в
bb.onDispose. bb вызывает эти хуки в обратном порядке регистрации, когда плагин перезагружается, отключается или когда сервер останавливается.
В окне приложения bb заново вызывает фабрику клиентской точки входа при каждом изменении бандла. Если компонент слота выбрасывает ошибку, её ловит внутренний error boundary: bb показывает fallback, остальная часть окна продолжает работать, а слот остаётся отключённым до перезагрузки плагина. Точные шаги загрузки и dispose, восемь статусов и цикл горячей перезагрузки описаны в Рантайме и жизненном цикле.
Полное доверие
Заголовок раздела «Полное доверие»bb не прячет плагины в песочницу. Серверная точка входа работает внутри процесса сервера и имеет неограниченный доступ к fs, net, child_process и fetch. Клиентская точка входа — это код страницы с тем же источником (same-origin) в собственном окне bb. Хостовая точка входа работает от имени того же пользователя ОС, что и агент. Граница безопасности — это решение человека установить плагин. В Модели доверия перечислено, к чему может получить доступ код плагина, и описаны правила проектирования, которые из этого следуют.