k.denisov 1eef73ec22 README со скриншотом панели
Что показывает вкладка «Токены», как устроен прокси внутри OpenCode, установка
без обёртки, переменные окружения, запуск server.mjs отдельно под Node.
2026-10-29 21:28:30 -07:00

context-panel

Панель «Токены» для веб-интерфейса OpenCode 2: что сейчас лежит в контексте сессии, как он рос и сколько токенов ушло за сессию, за день и за всё время. Работает как плагин OpenCode и поднимается в его же процессе.

Вкладка «Токены» в боковой панели OpenCode

Что на вкладке

В шапке сессии появляется кнопка с кружком и % заполнения контекста. Она открывает боковую панель на вкладке «Токены» рядом с Review и Context; вкладку можно выбрать и вручную. Кнопка и вкладка повторяют разметку OpenCode, поэтому стили у них родные. Если OpenCode перерисует интерфейс, panel.js вставит их заново.

  • Состав контекста. Сколько токенов было в последнем запросе к модели (как в самом OpenCode) из лимита модели. Разбивка по категориям: сообщения, ответы, reasoning, вывод каждого тула (MCP отдельно, gitlab: …, jira: …; для Code Mode — какие MCP вызывал скрипт), сводка compaction. Учитывается только то, что сейчас в контексте, — его отдаёт сам OpenCode (/api/session/{id}/context). Категории считаются как символы/4, так же оценивает сам OpenCode. «Остаток» — это разница между реальным числом токенов и суммой оценок: системный промпт, AGENTS.md, схемы тулов и MCP, плюс погрешность.
  • Рост контекста по шагам. Токенов в каждом запросе к модели за всю сессию, линия лимита модели и отметки compaction. Под графиком — список compaction: когда, авто или вручную, контекст до и после, размер сводки, сколько заняло. Провал на графике без отметки compaction — это чистка вывода тулов (prune / DCP).
  • Самые тяжёлые вызовы в контексте. Топ-10 вызовов тулов в текущем контексте: тул, что вызывали (файл, команда, описание), токены входа и вывода.
  • Расход за сессию. Input, cache read/write, output, reasoning, число шагов модели. Если были сабагенты, рядом показан итог вместе с ними.
  • Скорость модели в сессии. Генерация (output + reasoning за время потока, ток/с), среднее ожидание первого токена, prefill (input без кэша за это время, ток/с) и среднее время модели на шаг. Начало потока — первая часть ответа, конец — time.streamed сообщения. Выполнение тулов не считается.
  • Расход за сегодня / 7 дней / 30 дней / всё время, по проекту или по всем проектам, плюс топ моделей (со скоростью генерации и временем на шаг). Над таблицей — график с выбором периода: сегодня по часам, 7 и 30 дней по дням, всё время по дням или по неделям, если история длиннее 90 дней. Столбики разбиты по типу токенов (Cache / Input / Output) или по моделям (топ-4 + «другие»).

Каждый раздел сворачивается кликом по заголовку; какие свёрнуты — запоминается в браузере (localStorage). Данные обновляются раз в 3 секунды, пока вкладка выбрана, % на кнопке — раз в 10 секунд.

Как устроено

У веб-интерфейса OpenCode нет точек расширения: он зашит в бинарник, слоты для плагинов есть только в TUI, а своих HTTP-маршрутов серверный плагин добавить не может. Поэтому плагин context-panel.v2.ts поднимает внутри процесса OpenCode прокси (server.mjs) на отдельном порту. Прокси пропускает HTTP, SSE и WebSocket как есть, а в HTML-страницы вставляет <script src="/__ctx/panel.js">. CSP страницы (script-src 'self') скрипт пропускает: он с того же origin. Service worker веб-интерфейса прокси подменяет «гасящим», иначе тот отдавал бы страницу из кэша без панели.

браузер → :4196 server.mjs (в процессе OpenCode) ─┬─ /__ctx/panel.js, /__ctx/api/* → opencode.db (только чтение) + API OpenCode
                                                  └─ всё остальное → :4197 opencode serve

/__ctx/* закрыт тем же паролем, что и сам OpenCode: прокси сверяет заголовок Authorization с OpenCode и с ним же берёт из API лимит модели и текущий контекст сессии. Зависимостей нет: в OpenCode база читается через bun:sqlite, под Node ≥ 22.5 — через node:sqlite.

Особенности плагинов OpenCode 2 (проверено на 2.1.3):

  • Плагин грузится лениво — при первом запросе к API проекта, а не при старте opencode serve. Пока такого запроса не было, порт панели пуст. Поэтому после старта нужно один раз дёрнуть API (см. «Установка»).
  • Модуль импортируется заново для каждого проекта. Прокси один на процесс (флаг в globalThis).
  • При выгрузке проекта прокси не закрывается. Браузер ходит через него, и без прокси OpenCode не получил бы запрос, который загрузит плагин снова. Живёт, пока жив процесс.

Установка

  1. Положить ссылку на плагин в plugins/ конфига OpenCode (в "plugin" в opencode.jsonc не добавлять: имя там считается npm-пакетом). server.mjs и panel.js плагин ищет рядом с настоящим файлом:

    ln -sfn "$PWD/context-panel.v2.ts" "${XDG_CONFIG_HOME:-$HOME/.config}/opencode/plugins/"
    
  2. Запустить OpenCode на соседнем порту и сказать плагину, где слушать:

    CTX_PANEL_LISTEN=4196 CTX_PANEL_TARGET=4197 opencode serve --hostname 127.0.0.1 --port 4197
    
  3. Загрузить плагин первым запросом к API и открыть http://127.0.0.1:4196/ (на 4197 панели нет):

    curl -s -o /dev/null -u opencode:"$OPENCODE_SERVER_PASSWORD" http://127.0.0.1:4197/api/plugin
    

Переменные окружения плагина:

Переменная По умолчанию Что
CTX_PANEL_LISTEN 4196 порт прокси с панелью
CTX_PANEL_TARGET 4197 порт самого opencode serve
CTX_PANEL_DB $XDG_DATA_HOME/opencode/opencode.db база OpenCode
OPENCODE_CONTEXT_PANEL — 0 — не запускать

Журнал плагина: $XDG_DATA_HOME/opencode/log/context-panel.log (на каком порту поднялся или почему нет).

В mms-challenge всё это делает обёртка egress-filter/bin/opencode-web (make opencode): кладёт ссылку, передаёт порты, после старта дёргает API, ждёт порт 4196 и только потом открывает браузер. Выключить панель: OPENCODE_CONTEXT_PANEL=0 make opencode.

Без плагина

Тот же server.mjs можно запустить отдельным процессом под Node перед уже запущенным OpenCode:

node --disable-warning=ExperimentalWarning server.mjs --listen 4196 --target 4197 \
  --db "${XDG_DATA_HOME:-$HOME/.local/share}/opencode/opencode.db"

Проверка

curl -s -u opencode:"$OPENCODE_SERVER_PASSWORD" http://127.0.0.1:4196/ -H 'accept: text/html' | grep -c __ctx/panel.js

Должно вывести 1. Если панели нет — смотреть context-panel.log и консоль браузера. Если открыта старая вкладка, её нужно перезагрузить.

Разработка

  • Правки в panel.js применяются после перезагрузки страницы, правки в server.mjs и context-panel.v2.ts — после перезапуска OpenCode.
  • Панель читает внутреннюю схему opencode.db (таблицы session_v2, session_message). Если после обновления OpenCode она перестанет показывать данные, смотреть надо в sessionStatsV2 / globalRowsV2 в server.mjs.
S
Description
No description provided
Readme
556 KiB
Languages
JavaScript 95.4%
TypeScript 4.6%