dsh-brief-sidebar
v0.7.0
Published
DSH web plugin (dsh-better-sidebar consumer): render the session brief — the todo list (the `todos` projection board) plus the artifact list (a live produced-files feed, codeplan artifacts marked) — as a summary tab in the right sidebar, and shadow the of
Maintainers
Readme
dsh-brief-sidebar
简体中文 | Français | Deutsch | Italiano | Русский | Español
Веб-плагин DSH (потребитель dsh-better-sidebar), имя репозитория/пакета dsh-brief-sidebar (боковая панель брифов сессии).
Он рендерит бриф сессии в виде вкладки «Обзор» в правой боковой панели; бриф состоит из двух списков:
- список todo — доска прогресса проекции
todos, показывающая три состояния и сводку прогресса задач текущей сессии; - список результатов — раздел результатов (deliverables) проекции
dshSummaryDeliverables, в реальном времени, по ходу хода, показывающий успешно записанные/изменённые файлы; результаты планирования codeplan помечаются строчной меткой (pill) «Планирование».
Одновременно он перекрывает официальную todo-панель DSH над composer, делая доску единственным видимым носителем todo.
Только чтение: без редактирования, без записи обратно, без агрегации нескольких сессий, без копирования какого-либо стороннего слоя рендеринга.
Диапазон совместимости: эта линия (ветка main, повышена из compat/0.2.0) нацелена на линию DSH 0.2.0 — engines.dsh равен >=0.2.0-rc.1 <0.2.1-0, проверенная база — DSH 0.2.0-rc.1, публикации через npm dist-тег dsh-0.2.0. 0.2.0 чисто аддитивен для всех API хоста, которые использует этот плагин (потребляемая поверхность — только чистые вызовы ctx.get(...), ноль удалений экспортов), поэтому линия поддержки целиком сдвигается вперёд — ветка совместимости на уровне рантайма не нужна. Версию плагина выбирайте строго по версии DSH (не используйте latest вслепую на старых хостах: engines старого хоста перестают выполняться, и плагин молча отключается стартовой предпроверкой; caret-диапазоны также не переходят через minor хоста):
| Хост DSH | Последняя версия плагина | dist-тег для установки |
|---|---|---|
| 0.2.0 | 0.4.0 (latest) | dsh-0.2.0 |
| 0.1.7 | 0.3.1 | dsh-0.1.7 |
| 0.1.5 | 0.3.1 | dsh-0.1.5 |
| 0.1.2 и старше | не поддерживается (у линии 0.1.x нижняя граница — 0.1.5-rc.1; на npm нет соответствующего dist-тега) | — |
(по состоянию на 2026-09-30; линия 0.1.x продолжает обслуживаться замороженными ветками compat/0.1.7 / compat/0.1.5 (≤0.3.1).)

Границы именования: идентичность этого плагина (имя пакета / plugin id / cordis bundle id / namespace локали / DOM-хук
data-dsh-brief-sidebar) повсюду использует brief; тогда как проекция todos, инструмент todo_write, официальная dock-ячейка { id: 'todo' } и dsh-tool-todo относятся к вышестоящей домену DSH: оригинальное слово todo сохраняется, этот плагин ничего не переименовывает.
Система памяти: третий раздел брифа (вызов памяти) пока является лишь зарезервированным слотом макета, находится в планировании и в этом выпуске не рендерится — см. R11 / K4.
Соответствие требований
| № | Требование | Место реализации |
|---|---|---|
| R1 | Во время монтирования плагина официальная todo-полоса вообще не рендерится | src/client/brief/dock-shadow.tsx |
| R2 | Отдельный самостоятельный плагин, регистрирующий вкладку «Обзор» в better-sidebar | src/client/index.tsx |
| R3 | Данные берутся только из вычисляемой хостом проекции todos; без клиентского схлопывания, без записи обратно | src/client/brief/use-todos.ts + board.ts |
| R4 | Обычный React + токены --dsw-alias-*; нулевая связь кода/именования с плагином Canvas | src/client/TodoBoardTab.tsx (TodoSection) + BriefIcon.tsx |
| R5 | Обратимость: после отключения/удаления плагина официальный dock восстанавливается автоматически | Все регистрации идут через ctx.effect, disposer-ы утилизируются вместе с fiber |
| R6 | Неагрессивность: без изменения DSH checkout / better-sidebar / плагина canvas | Пакет самодостаточен, ни один из названных репозиториев не затронут |
| R7 | Вкладка становится «Обзор», TAB_ID не меняется (замена на месте, уже открытые вкладки не теряют связь) | src/client/SummaryTab.tsx + index.tsx |
| R8 | Раздел 1 «Прогресс»: контракт трёх состояний todos опущен до уровня раздела | src/client/TodoBoardTab.tsx |
| R9 | Раздел 2 «Результаты»: список в реальном времени последнего хода + накопление за сессию, хостовая половина регистрирует проекцию | src/projection/* + src/client/summary/* |
| R10 | Результаты codeplan — это аннотированное подмножество раздела результатов (строчная метка «Планирование»), а не отдельный раздел | src/client/summary/deliverables.ts + DeliverablesSection.tsx |
| R11 | Вызов памяти: только зарезервированный слот макета (в самом низу последовательности разделов), в планировании, в этом выпуске не рендерится | Комментарий слота в src/client/SummaryTab.tsx / K4 |
| R12 | Сохранение поведения: перекрытие, badge, пауза через visible, контракт высоты, адаптация 0.1.5 | В разных местах, см. ниже |
| R13 | Хостовая половина не делает синхронный ввод-вывод; проекция — опциональный вклад (ожидание через ctx.inject) | src/index.ts + src/projection/register.ts |
Установка
# выбирайте dist-тег по версии хоста DSH (рекомендуется, не используйте latest вслепую)
dsh plugin --profile web add [email protected] # линия DSH 0.2.0 (0.4.0)
dsh plugin --profile web add [email protected] # линия DSH 0.1.7 (0.3.1)
dsh plugin --profile web add [email protected] # линия DSH 0.1.5 (0.3.1)
# Вариант 1: локальный tarball (эта линия: dsh-brief-sidebar-0.4.0.tgz)
dsh plugin --profile web add <dsh-brief-sidebar-0.4.0.tgz>
# Вариант 2: прямая установка с GitHub (сборка своими силами)
dsh plugin --profile web add github:drscrewdriver/dsh-brief-sidebar#main--profile должен идти сразу после plugin. После установки обновите http://127.0.0.1:3080.
Ключевые решения
Цепочка данных: разбор грани проекций напрямую, вместо useProjection из фреймворка
Тело вкладки better-sidebar не находится в дереве слотов DSH и не получает стандартные props со scope сессии, поэтому:
ctx.get('sessions') // безопасное получение (без прямого чтения Proxy)
?.binding(scope.sessionId)?.session.projections // SessionBinding.session = SessionFace
?.faceOf(key) // ProjectionsFace
=> useSyncExternalStore(...) // без локального зеркала, без схлопыванияЭта цепочка используется обеими проекциями (src/client/use-projection.ts — универсальный разбор, не зависящий от key):
todos— регистрируетсяdsh-tool-todo, хост — единственная точка вычисления,TodoItem[] | null.dshSummaryDeliverables— регистрируется хостовой половиной этого плагина (см. следующий раздел),DeliverablesView.
Три состояния раздела прогресса должны оставаться различимыми (контракт readTodos, закреплён тестами):
| Значение | Смысл | Рендер |
|---|---|---|
| undefined | возможность отсутствует (нет сессии / хостовый unit не смонтирован / baseline ещё нет) | «Задачи временно недоступны» |
| null → [] | проекция есть и пуста | пустое состояние |
| массив | реальные записи | список + сводка прогресса |
Смешать первые два — значит заявить читателю «в этой сессии нет задач», тогда как на самом деле «данные недоступны».
Раздел результатов устроен иначе: это опциональная расширяющая возможность; при отсутствии проекции (хостовая половина не зарегистрировала этот unit) раздел целиком скрывается, без рендера шума «недоступно»; когда проекция есть, latest: null и sessionTotal: 0 — его пустое состояние (unit публикуется сразу при регистрации).
Цепочка данных результатов: хостовая половина регистрирует unit проекции
Данные официальной строки «результаты хода» (ui-deliverables) накапливаются уже по ходу хода, запись за записью, при каждом успешном tool/result; просто официальная UI висит на conversation.chat.turnTail и рендерится только в конце хода, а боковая вкладка не имеет доступа к данным хода движка conversation (SessionFace не открывает окно событий, IConversation не открывает данные хода). Поэтому хостовая половина плагина вносит собственный unit через ctx.sessionProjections.register():
- критерий fold в точности совпадает с официальным
turn-deliverables.ts: учитываются только пути успешныхwrite/edit/str_replace_editor(варианты create/str_replace/insert), с дедупликацией, неудачи не считаются, операции чтения не считаются; запись и последующее изменение в одном ходу считаются одной записью (src/projection/deliverables-fold.ts, чистая функция, закреплено тестами). - реальное время внутри хода: каждое событие коммита реестра приводит в действие
applyвсех unit; каждое успешно зафиксированное изменение файла сразу выталкивает кадр. - опциональный вклад:
ctx.inject(['sessionProjections'], …)ожидает сервис; развёртывание без реестра загружает этот плагин как обычно (раздел результатов тихо скрывается); регистрация — это effect, при удалении key исчезает, и клиент читает «возможность отсутствует». - вместимость: пути последнего хода с лимитом 50, накопление за сессию с лимитом 100 (сохраняются самые свежие);
sessionTotalбез ограничений, строка накопления «всего N файлов за эту сессию» всегда соответствует действительности. - key с пространством имён (
dshSummaryDeliverables): реестр отказывает в совместном использовании одного key с разнымstateVersion, чтобы избежать лобового столкновения с возможной будущей официальной хостовой проекцией.
Результаты codeplan: аннотированное подмножество раздела результатов
Критерий метки «Планирование» — чисто правило по путям: если путь созданного файла после нормализации разделителей попадает на сегмент .agents/plans/ (прямой или обратный слэш), ставится метка «Планирование», а первый сегмент после .agents/plans/ (имя задачи) кладётся в title.
Плагин не читает содержимое файлов и не проверяет, что пишет именно skill codeplan — любой файл, записанный в этот каталог, получает метку;
плюс такого критерия — нулевая дополнительная цепочка данных, цена — сама договорённость о путях является единственным источником истины (см. пробел K5).
Skill codeplan пишет spec.md / findings.md / checklist.md / tasks.md через write в
$workspace\.agents\plans\<任务名>\ — эти файлы естественно появляются в fold результатов, без дополнительного сбора.
У результатов планирования нет отдельного раздела: они по своей природе часть результатов.
Открытие по клику: тот же канал предпросмотра Sidebar, что и поток диалога
В разделе результатов каждая строка пути — это кнопка; клик идёт через ctx.sidebarRight.openResource(<address>) — ровно тот же канал, что чипы «результаты хода» в диалоге и строчные упоминания code (приём ui-chat openFile). Адрес строит инлайн-перенесённый fileAddressFor (источник @deepseek-ai/dsh-util-workspace-path): относительный путь или абсолютный путь внутри рабочего пространства сессии адресуется по dsh-resource://file/session/<id>/<相对路径> (префикс рабочего пространства срезается); абсолютный путь вне рабочего пространства сохраняет абсолютное написание в том же адресе сессии. cwd сессии читается из снимка sessions.list, заново при каждом клике.
Когда сервис sidebarRight отсутствует, строка деградирует до чистого текста (та же дисциплина деградации, что и при отсутствии проекции результатов).
Перекрытие официального dock: конкуренция ячеек в слоте list
conversation.input.dock — это слот list, ячейки идентифицируются по id записи. Поведение SlotCore таково:
- ключ дедупликации
register()— это(id, priority)— тот жеidс другойpriority— легальная регистрация; - записи сортируются по возрастанию
priority(затем поorder), текст ошибки сам несёт семантику "lowest renders"; entriesOfSlot()для слота list берёт ячейки поoptions.id, оставляя для одной ячейки только первую после сортировки запись.
Официальная запись регистрирует { id: 'todo', order: 0 } (priority по умолчанию = 0); этот плагин выигрывает с **{ id: 'todo', priority: -1 }**.
Регистрация идёт через ctx.slots.inject('conversation.input.dock', …)(ожидает объявления слота и переустанавливается при его пересборке),
а не через голыйregister(который состязался бы с таблицей объявления children родительской записи). Тот же приём — уже работающий прецедент вdsh-input-trafficв отношении соседней ячейкиqueue`.
Перекрывать только при доступном betterSidebar, иначе панель будет скрыта, а задачи не видны нигде.
Несущая поверхность: нативная правая боковая панель DSH
С 0.1.5 правая боковая панель принадлежит DSH нативно; openTab better-sidebar с дефолтным target: 'right' регистрирует содержимое как нативный тип вкладки,
меню + — это нативная страница guide (description рендерится только когда на странице guide ≤4 записей). Тело вкладки по-прежнему получает
TabComponentProps = { ctx, store, scope, tab, visible, … }; плагин использует из этого только ctx / scope / visible.
При visible === false вся карточка (включая оболочку) не рендерится, чтобы скрытая вкладка не перерендеривалась на каждый кадр проекции.
Риски связанности и самопроверка
| Риск | Последствие | Метод самопроверки |
|---|---|---|
| Вышестоящий код переименовывает id ячейки todo | Перекрытие тихо перестаёт работать, официальная панель появляется снова (fail-open: данные не теряются, просто показываются дважды) | Выполнить в консоли ctx.slots.entriesOfSlot('conversation.input.dock').filter(e => e.options.id === 'todo'); должна остаться только запись этого плагина (registrant: 'dsh-brief-sidebar', priority: -1) |
| Панель/боковая панель better-sidebar закрыты | Задачи невидимы | Badge вкладки показывает число незавершённых задач как подсказку |
| Вышестоящий код меняет key или поля проекции todos | Доска показывает «недоступно» или отбрасывает недопустимые записи | SessionProjectionMap.todos в types.d.ts у dsh-tool-todo остаётся единственным источником истины |
| Дрейф API better-sidebar | Поверхность регистрации выходит из строя | Использовать только базовые поля registerTab (id/title/description/icon/order/single/badge/component); peerDependencies ослаблен до >=0.18.1, devDependencies закреплён на текущей исполняемой версии |
| Дрейф официального критерия fold (в список допускаются новые инструменты мутации и т.п.) | Список результатов плагина постепенно расходится с официальными «результатами хода» | Критерий выравнивается по mutationPath из ui-deliverables/turn-deliverables.ts; при каждом обновении сверять diff-ом |
| Вышестоящий код меняет форму событий tool/call / tool/result | fold результатов теряет данные (защита в духе readTodos сужается, без падения) | Записи 'tool/call' / 'tool/result' в SessionEventMap у dsh-session — источник истины |
Известные пробелы
- K1 Если пользователь отключает этот тип вкладки в карточке Side, dock остаётся скрытым → задачи не видны нигде.
Впоследствии можно сделать gate on
prefs.tabsEnabled; в этот раз не сделано (пользователь выбрал «скрывать полностью»). - K2 При закрытой панели/боковой панели better-sidebar задачи невидимы (подтверждено как принятое).
- K3 Вышестоящий код переименовывает ячейку
todo→ перекрытие тихо перестаёт работать (fail-open, см. таблицу выше). - K4 Раздел вызова памяти имеет только слот макета (в планировании): в системе нет памяти по умолчанию; цепочка данных будет подключена, когда плагин памяти зарегистрирует key проекции.
- K5 Метка «Планирование» — чистая проверка префикса пути (сегмент
.agents/plans/), без проверки автора записи: файлы, записанные в этот каталог источниками кроме codeplan, тоже получают метку; если codeplan сменит договорённость о каталоге результатов, нужно синхронно обновить константу вsummary/deliverables.ts. - K6 Открытие строк путей по клику зависит от хостового сервиса
sidebarRight(опциональное потребление); на развёртываниях без него строки результатов некликабельны и показываются как чистый текст.
Разработка
pnpm install # зависимости: react / @deepseek-ai/cordis / zod как devDep, в рантайме предоставляются таблицей модулей хоста или собираются с пакетом
pnpm typecheck # tsc -p tsconfig.json && tsc -p tsconfig.client.json
pnpm test # vitest (jsdom)
pnpm build # tsc создаёт lib/types + tsdown создаёт lib/index.mjs / lib/client.js (zod упакован в host-пакет, самодостаточно)
npm pack # создаёт tarball (в этом каталоге есть pnpm-workspace.yaml, но без поля packages, pnpm pack неприменим)lib/ должен храниться в репозитории: при установке profile по GitHub ref шага сборки нет.
Совместимость
Поштучные записи натурных проверок линии 0.1.x смотрите в README веток compat/0.1.7 / compat/0.1.5 (≤0.3.1); эта линия (main) нацелена на линию DSH 0.2.0, проверенная база — DSH 0.2.0-rc.1 + dsh-better-sidebar 0.19.1.
0.2.0-rc.1 полностью совместим с plugin API 0.1.7 (manifest/settings/HMR/slot/сессии V4 не тронуты); вся потребляемая поверхность плагина — чистые вызовы ctx.get(...) (slots / locale / betterSidebar / sidebarRight / sessions, с собственными локальными определениями интерфейсов), без override хостовых контрактов, поэтому эта линия — чисто метаданная адаптация без изменения кода.
engines.dsh равен >=0.2.0-rc.1 <0.2.1-0, и три места — engines.dsh в package.json, диапазон клиентского пакета DSH в peerDependencies и engines.dsh в dsh.plugin.json — должны совпадать (сейчас совпадают).
Последняя версия плагина по каждой линии хоста и dist-тег для установки — в таблице раздела «Диапазон совместимости» в начале файла (0.2.0 → 0.4.0 / 0.1.7 → 0.3.1 / 0.1.5 → 0.3.1; 0.1.2 и старше не поддерживаются).
Хостовые линии начиная с 0.2.1 не входят в покрытие этой линии: дисциплина фиксации на rc-окне; с 0.2.1 адаптацию придётся переоценивать (тогда будет открыта новая линия версий).
Примечание о языках / Sprachen / Langues / Языки / Idiomas / Lingue
Оригинальный README написан на китайском; этот документ — его перевод на русский. Кратко об установке и совместимости (эта линия требует DSH 0.2.0: >=0.2.0-rc.1 <0.2.1-0; dist-тег по линии хоста: 0.2.0 → dsh-0.2.0 (0.4.0) / 0.1.7 → dsh-0.1.7 (0.3.1) / 0.1.5 → dsh-0.1.5 (0.3.1); DSH 0.1.2 и старше не поддерживаются, не используйте latest вслепую на старых хостах):
- Deutsch — benötigt DSH 0.2.0 (
>=0.2.0-rc.1 <0.2.1-0), getestet gegen DSH 0.2.0-rc.1. dist-tag je nach Host-Linie:dsh plugin --profile web add [email protected](0.2.0 → 0.4.0),…@dsh-0.1.7(0.1.7 → 0.3.1),…@dsh-0.1.5(0.1.5 → 0.3.1); DSH 0.1.2 und früher werden nicht unterstützt. Kein blindeslatestauf alten Hosts (die Start-Vorprüfung deaktiviert das Plugin still). Tabelle: Abschnitt „Kompatibilitätsbereich". - Français — nécessite DSH 0.2.0 (
>=0.2.0-rc.1 <0.2.1-0), testé avec DSH 0.2.0-rc.1. dist-tag selon la ligne d'hôte :dsh plugin --profile web add [email protected](0.2.0 → 0.4.0),…@dsh-0.1.7(0.1.7 → 0.3.1),…@dsh-0.1.5(0.1.5 → 0.3.1) ; DSH 0.1.2 et antérieurs ne sont pas pris en charge. Pas delatestaveugle sur un hôte ancien (la prévérification de démarrage le désactive en silence). Tableau : section « Périmètre de compatibilité ». - Русский — требуется DSH 0.2.0 (
>=0.2.0-rc.1 <0.2.1-0), протестировано на DSH 0.2.0-rc.1. dist-tag по линии хоста:dsh plugin --profile web add [email protected](0.2.0 → 0.4.0),…@dsh-0.1.7(0.1.7 → 0.3.1),…@dsh-0.1.5(0.1.5 → 0.3.1); DSH 0.1.2 и ранее не поддерживаются. Не используйтеlatestвслепую на старых хостах (плагин молча отключается стартовой предпроверкой). Таблица: раздел «Диапазон совместимости». - Español — requiere DSH 0.2.0 (
>=0.2.0-rc.1 <0.2.1-0), probado con DSH 0.2.0-rc.1. dist-tag según la línea del host:dsh plugin --profile web add [email protected](0.2.0 → 0.4.0),…@dsh-0.1.7(0.1.7 → 0.3.1),…@dsh-0.1.5(0.1.5 → 0.3.1); DSH 0.1.2 y anteriores no están soportados. No uselatesta ciegas en hosts antiguos (la preverificación de arranque lo desactiva en silencio). Tabla: sección «Alcance de compatibilidad». - Italiano — richiede DSH 0.2.0 (
>=0.2.0-rc.1 <0.2.1-0), testato su DSH 0.2.0-rc.1. dist-tag in base alla linea dell'host:dsh plugin --profile web add [email protected](0.2.0 → 0.4.0),…@dsh-0.1.7(0.1.7 → 0.3.1),…@dsh-0.1.5(0.1.5 → 0.3.1); DSH 0.1.2 e precedenti non sono supportati. Nientelatestalla cieca su host vecchi (la preverifica di avvio lo disattiva in silenzio). Tabella: sezione «Perimetro di compatibilità».
