dsh-canvas-tsx-sidebar
v0.7.0
Published
DSH web plugin (dsh-better-sidebar consumer) for the DSH 0.2.0 line: render Qoder Canvas `*.canvas.tsx` reports as a structured page in the right sidebar. Static parse only — no code execution.
Maintainers
Readme
dsh-canvas-tsx-sidebar
简体中文 | Français | Deutsch | Italiano | Русский | Español
Веб-плагин DSH (DeepSeek Harness) — плагин-потребитель dsh-better-sidebar.
Статически разбирает файлы *.canvas.tsx из Qoder Canvas в рабочей области в структурированные страницы и отображает их в правой боковой панели DSH.
Полностью статический конвейер: исходники canvas не выполняются. Без
eval, безnew Function, без бандлера, без sandbox-iframe. Разбор выполняется на стороне браузера собственным легковесным рекурсивным парсером (ноль зависимостей парсера).
В репозитории также есть Skill: skills/writing-qoder-canvas/, который учит LLM писать этот формат. См. Интеграция Skill.

Диапазон совместимости: линия DSH 0.2.0 (эта линия) — engines.dsh равен >=0.2.0-rc.1 <0.2.1-0, проверенная база — dsh-client-locale 0.2.0-rc.1, публикация через npm dist-tag dsh-0.2.0. 0.2.0 чисто аддитивен для всех API хоста, которые использует этот плагин (он потребляет только register(ns, locale, dict) / bind(ns) из dsh-client-locale; поверхность клиентских экспортов идентична 0.1.7-rc.2), поэтому линия поддержки целиком сдвигается вперёд — ветка совместимости на уровне рантайма не нужна. Версию плагина выбирайте строго по версии DSH (не используйте latest вслепую на старых хостах: engines старого хоста перестают выполняться, и плагин молча отключается стартовой предпроверкой; caret-диапазоны также не переходят через minor хоста):
| Хост DSH | Последняя версия плагина | dist-tag для установки |
|---|---|---|
| 0.2.0 | 0.5.0 (latest) | dsh-0.2.0 |
| 0.1.7 | 0.4.0 | dsh-0.1.7 |
| 0.1.5 | 0.3.2 | dsh-0.1.5 |
| 0.1.2 | 0.2.2 | dsh-0.1.2 |
| 0.1.1 и ранее | не поддерживается (у линии 0.1.2 нижняя граница — 0.1.2-rc.1) | — |
(по состоянию на 2026-09-30; старые линии обслуживают compat/0.1.7, а также замороженные ветки compat/0.1.5 и archive/release/0.1.2.)
Предварительные требования
- DSH
dsh webнормально запускается - Установлен dsh-better-sidebar (
>=0.19.1)
Без better-sidebar плагин полностью пассивен: обе регистрации молча пропускаются и не затрагивают остальные функции DSH.
Установка
Способ A (рекомендуется, официальный CLI)
# выбирайте dist-tag по версии хоста DSH (рекомендуется, не используйте latest вслепую)
dsh plugin --profile <profile> add [email protected] # линия DSH 0.2.0 (0.5.0)
dsh plugin --profile <profile> add [email protected] # линия DSH 0.1.7 (0.4.0)
dsh plugin --profile <profile> add [email protected] # линия DSH 0.1.5 (0.3.2)
dsh plugin --profile <profile> add [email protected] # линия DSH 0.1.2 (0.2.2)
# альтернатива: локальный tarball (эта линия: dsh-canvas-tsx-sidebar-0.5.0.tgz)
dsh plugin --profile <profile> add <dsh-canvas-tsx-sidebar-0.5.0.tgz>dsh добавляет этот пакет в dsh.profile.bundles; при запуске входящий в пакет cordis.patch.yml вставляет запись загрузчика, и клиентский бандл регистрируется и доставляется согласно entry.name.
Способ B (вручную, альтернативный)
Скопировать пакет в
~/.dsh/profiles/<profile>/node_modules/dsh-canvas-tsx-sidebar(либо добавить"dsh-canvas-tsx-sidebar": "link:<путь-к-плагину>"вdependenciesфайлаpackage.jsonпрофиля);дописать следующую строку в
~/.dsh/profiles/<profile>/cordis.patch.yml:- insert: - id: dsh-canvas-tsx-sidebar name: dsh-canvas-tsx-sidebarвыполнить
pnpm installв каталоге профиля.
⚠️ Выберите способ A или способ B — не регистрируйте дважды.
Активация
- Перезапустите
dsh web— добавление бандла требует перезагрузки на стороне хоста (hot reload работает только для изменений клиента уже подключённого плагина); - жёсткое обновление страницы в браузере (Ctrl+Shift+R).
Состояние подключения можно перепроверить через pwsh -NoProfile -File ./scripts/mount-check.ps1.
Использование
Две точки входа:
| Точка входа | Как вызывается | Поведение |
|---|---|---|
| Просмотрщик файлов (перехват) | Открыть любой .tsx в дереве файлов | .canvas.tsx → структурированная страница + переключатель Просмотр/Код; остальные .tsx → просмотр исходника |
| Вкладка | меню + правой панели → Отчёт Canvas | ввести путь вручную и посмотреть, не открывая файл в редакторе |
Просмотрщик файлов можно отключить в настройках карточки Side; после отключения такие файлы возвращаются к встроенному просмотрщику кода.
Открытие одного файла рендерит именно этот файл — плагин не сканирует рабочую область.
Почему просмотрщик файлов обязан перехватывать все .tsx
exts: ['tsx'] — единственный работоспособный способ перехвата; цена в том, что перехватываются и .tsx вне canvas. Все доказательства взяты из исходников better-sidebar и практических проверок в экосистеме:
| # | Ограничение | Доказательство |
|---|---|---|
| L1 | extOf() берёт только последний сегмент расширения → extOf('a.canvas.tsx') === 'tsx' | src/client/paths.ts:80-85 |
| L2 | exts: ['tsx'] перехватывает все .tsx рабочей области, а priority 0 перекрывает CodeMirror встроенного code (-100) | service.ts:847-875 |
| L3 | detect вызывается только при доступных байтах head, а head приходит только из бинарного fs.read — текстовый .tsx до этой ветки никогда не доходит | service.ts:860 |
| L4 | после перехвата дескриптором component обязан отрисоваться, API делегирования/отката нет | EditorHost.tsx:349,486 |
| L5 | экосистемный плагин dsh-code-nav уже содержит tsx в своём LANG_EXT и перехватывает с priority: 10 | dsh-code-nav/src/lang-registry.js |
→ Определение .canvas.tsx возможно только внутри собственного компонента. Поэтому: просмотрщик перехватывает все .tsx (canvas идёт на страницу, остальное — на исходник), а вкладка сохранена как второй вход, минующий перехват файлов.
Интеграция Skill: научить LLM писать .canvas.tsx
skills/writing-qoder-canvas/ — самодостаточный, полностью переносимый Skill:
skills/writing-qoder-canvas/
SKILL.md # условия срабатывания, скелет файла, пять железных правил, список красных флагов
references/components.md # 38 реально отрисовываемых тегов + prop каждого (машинная проверка)
references/expressions.md # замкнутые правила статического парсера: какие значения выживают
references/layout.md # писать под боковую панель ~400px (а не под превью 960px)
examples/status-report.canvas.tsx # рендеримый образец, тесты гарантируют ноль деградацийПочему он не лжёт
Документация дрейфует, поэтому каждое утверждение здесь привязано к исходникам (tests/skill.spec.ts):
- список поддерживаемого в
components.mdдолжен поэлементно совпадать с тегамиcaseвrender.tsx(38 штук, включая порядок); - ни одно имя из списка «не поддерживается» не должно встречаться в рендерере;
examples/status-report.canvas.tsxдолжен отрисовываться без единой деградации — без пометокunsupported, без пунктирных рамок неизвестных компонентов.
Если документация расходится с реальными возможностями, pnpm test падает.
Как установить его в DSH
DSH обнаруживает Skill в фиксированном наборе корней, причём Skill должен лежать ровно на один уровень в глубину: <root>/<name>/SKILL.md.
Вложенные **/SKILL.md не находятся (провайдер следит за каждым корнем через chokidar, depth: 1).
| rank | Источник | Путь |
|---|---|---|
| 100 | project-dsh | <projectRoot>/.dsh/skills |
| 200 | project-agents | <projectRoot>/.agents/skills |
| 300 | custom | customSkillDirs из конфигурации DSH |
| 400 | user-dsh | ~/.dsh/skills |
| 500 | user-agents | ~/.agents/skills |
| 600 | bundled | $DSH_BUNDLED_SKILL_DIR |
# по умолчанию: установка в ~/.agents/skills через junction (без копий, без дрейфа)
pwsh -NoProfile -File ./scripts/install-skill.ps1
# установка в другое место; -Copy делает настоящую независимую копию (дрейфует, после правок запускать заново)
pwsh -NoProfile -File ./scripts/install-skill.ps1 -Target UserDsh
pwsh -NoProfile -File ./scripts/install-skill.ps1 -Path D:\some\skills -Copy
# удаление
pwsh -NoProfile -File ./scripts/install-skill.ps1 -UninstallПровайдер следит за корнями, перезапускать dsh web не нужно: после установки Skill появится в каталоге skill'ов следующей сессии.
По умолчанию junction, а не копия, потому что копии дрейфуют — эта рабочая область уже обжигалась на memport с «тремя копиями, ни одна не синхронна». Junction делает копию в репозитории единственным авторитетным источником.
skills/не входит вfiles[]вpackage.json— это актив репозитория, а не публикуемый npm-артефакт.
Ограничения версий
На [email protected] / 0.19.1 path seed у openTab({ path }) перенаправляется в редактор файлов, и вкладка-компонент не монтируется (upstream #632, исправлено с 0.19.2). Поэтому плагин не полагается на path seed, а сам разрешает целевой файл через /sidebar/api (session.cwd → fs.tree → fs.read) — этот подход одинаково работает и на 0.19.2+.
Скины и темы
Оболочка плагина (вкладки, карточка настроек, кнопки) потребляет только токены --dsw-alias-* от DSH и автоматически следует всем скинам и светлой/тёмной теме.
Поддерево документов canvas — исключение, и намеренное: .canvas.tsx описывает лист с фиксированной вёрсткой, цвета выбирает автор; перекраска по скину изменила бы сам вид отчёта. Поэтому styles.ts использует буквальные значения цветов, и каждый селектор ограничен .dsh-canvas-doc, без протечек в UI хоста (tests/render.spec.tsx сторожит область действия, tests/purity.spec.ts — поверхность регистрации).
Известные ограничения
Разбор ведёт легковесный собственный парсер, а не компиляторная точность. Дженерики, декораторы и произвольные вызовы не моделируются и всегда деградируют, но ошибка никогда не бросается.
Разбор значений — замкнутый набор правил (подробности в
skills/writing-qoder-canvas/references/expressions.md). Поддерживается: литералы, утвержденияas const/as T, литеральныеconstна уровне модуля и в начале тела функции, проекцииARR.map(x => литерал)по статическим массивам,canvasImage('литерал'). Не поддерживается (не вычисляется): условные выражения, вызовы функций, цепочки членов, шаблонная интерполяция, арифметика,new,await,constвнутри вложенных блоков, данные из межмодульныхimport.- не-литеральный дочерний узел → отрисовывается как встроенная полоса деградации, исходный фрагмент остаётся видимым;
- не-литеральное свойство → свойство отбрасывается, имя попадает в
unresolvedIR, остальные свойства отрисовываются как обычно.
Теги в нижнем регистре всегда прозрачно проходят как нативный HTML; только заглавные и не отображённые компоненты рисуются пунктирной рамкой с именем.
Вкладки отрисовываются только для чтения.
Парсер терпимее компилятора: Qoder SDK требует, чтобы авторы правили диагностику через «Canvas TypeScript check» в IDE, но реальные файлы не всегда чисты. На нелегальном TSX этот плагин не падает и не прерывается, деградирует только проблемный узел. Авторитетную диагностику можно посмотреть через
node scripts/syntax-oracle.cjs <file.canvas.tsx>.Проверено на практике: строка 46 входящего в репозиторий образца
cmp-cloud-sdk-report.canvas.tsx,{'created': ...}, — нелегальный TSX (TypeScript выдаёт TS1005 + TS1381 — «голый» оператор разворота). Плагин деградирует это место во встроенную пометку, остальные 147 строк рендерит как обычно.
Семантика пробелов в JSX
Текстовые дочерние узлы сворачиваются строго по семантике cleanJSXElementLiteralChild из React:
- ведущий отступ на всех строках, кроме первой, безусловно срезается;
- концевые пробелы последней строки сохраняются — этот пробел несущий: он отделяет текст от идущего следом контейнера выражения
(пример: пробел в
…сложение (0 + {'created': ...})…; уберите его — и два куска слипнутся).
Разработка
pnpm install
pnpm typecheck # tsc (включая проверку «ноль зависимостей от Node» в клиентской части)
pnpm test # vitest
pnpm build # tsc dts + tsdown (хостовая половина + клиентский бандл)
pnpm run audit:bundle # аудит реальных артефактов сборкиСкрипты разработки
| Скрипт | Назначение |
|---|---|
| scripts/dump-ir.ts | Экспорт IR-структуры / JSON / эталонных фикстур файла (--write) |
| scripts/syntax-oracle.cjs | Определяет настоящим компилятором TypeScript, является ли исходник корректным TSX (typescript остаётся devDependency и в бандл не попадает) |
| scripts/audit-bundle.cjs | Аудит реальных артефактов сборки: утечки встроенных модулей, повторные парсеры, eval, регистрации вне зоны ответственности |
| scripts/mount-check.ps1 | Проверка/исправление подключения профиля (чистый ASCII, совместим с Windows PowerShell 5.1) |
| scripts/install-skill.ps1 | Устанавливает skills/writing-qoder-canvas в корень skill'ов DSH (по умолчанию junction) |
| scripts/component-census.cjs | Автономная перепись компонентов (без жёстко зашитой таблицы компонентов, с учётом многострочности) |
| scripts/corpus-stats.ts / format-economics.ts / audit-corpus.ts / corpus-gaps.ts | Статистика корпуса и практические замеры экономики формата (источник цифр для docs/canvas-format-rules.md) |
