# Установка на другое устройство Плагин — один файл: `dist/dsh-session-cost-0.1.0.tgz`. Перенесите его на другую машину любым способом (флешка, облако, `scp`). ## Что нужно на той машине - DeepSeek Harness **0.2.x** (проверено на `0.2.1-rc.3`). Точную версию печатает `runtime.json`, поле `desktopVersion` — файл лежит в одном из двух мест, смотря как установлен харнесс: ```powershell $runtimeJson = @( "$env:USERPROFILE\.dsh\dsh-runtimes\dsh-primary-runtime\runtime.json", "$env:LOCALAPPDATA\Programs\DeepSeek Harness\resources\runtime\primary-runtime\runtime.json" ) | Where-Object { Test-Path $_ } | Select-Object -First 1 (Get-Content $runtimeJson -Raw | ConvertFrom-Json).desktopVersion ``` Первый путь — рантайм, скачанный харнессом отдельно; второй — рантайм, вложенный в установленное приложение (так на машине, где плагин писался). Второй путь ищется от `$env:LOCALAPPDATA`, поэтому при установке в другое место подставьте свой. - Модель должна идти через **routerai**: стоимость приходит в ответе провайдера, другие провайдеры её не отдают, и ячейка просто молчит. - Ничего больше: ключ `ROUTERAI_API_KEY` плагину не нужен. Он читает стоимость из ответа, который харнесс и так получает, и сам никуда не ходит. ## Установка Ставим **в профиль `desktop`** — это профиль, который поднимает приложение. Самый короткий путь — одна команда `dsh plugin`: она и ставит пакет, и дописывает его в список бандлов профиля (проверено: после неё `dsh-session-cost` уже в `dsh.profile.bundles`). ```powershell # dsh.cmd лежит рядом с установленным приложением; ищем, не угадывая путь $dsh = @( "$env:LOCALAPPDATA\Programs\DeepSeek Harness\resources\runtime\cli\bin\dsh.cmd", "C:\Program Files\DeepSeek Harness\resources\runtime\cli\bin\dsh.cmd" ) | Where-Object { Test-Path $_ } | Select-Object -First 1 $tgz = "C:\путь\к\dsh-session-cost-0.1.0.tgz" & $dsh plugin --profile desktop add "file:$tgz" ``` Оба пути — рядом с `DeepSeek Harness.exe`: установщик кладёт приложение либо в `%LOCALAPPDATA%\Programs`, либо в `C:\Program Files`, смотря как ставили. Профиль `desktop` принадлежит приложению, поэтому обычный запуск и дамп конфигурации по нему закрыты: `dsh --profile desktop --dump-config` отвечает `error: profile "desktop" is managed exclusively by the Electron application`. Это ограничение на **запуск**, а не на управление пакетами: `dsh plugin --profile desktop ...` в поставке десктопа разрешён и работает. ### Если ставите pnpm напрямую Штатный `dsh plugin` — обёртка над pnpm, и разница только в одном: **он же ведёт список бандлов**. Голый pnpm список не трогает, поэтому после него шаг со списком обязателен. ```powershell $node = "$env:LOCALAPPDATA\Programs\DeepSeek Harness\resources\runtime\primary-runtime\dependencies\node\bin\node.exe" $pnpm = "$env:LOCALAPPDATA\Programs\DeepSeek Harness\resources\runtime\primary-runtime\dependencies\pnpm\bin\pnpm.mjs" $profile = "$env:USERPROFILE\.dsh\profiles\desktop" $tgz = "C:\путь\к\dsh-session-cost-0.1.0.tgz" # 1. поставить пакет в профиль & $node $pnpm add "file:$tgz" --dir $profile # 2. дописать плагин в список бандлов (голый pnpm этого не делает) $manifestPath = Join-Path $profile 'package.json' $m = Get-Content $manifestPath -Raw | ConvertFrom-Json if ($m.dsh.profile.bundles -notcontains 'dsh-session-cost') { $m.dsh.profile.bundles += 'dsh-session-cost' } $m | ConvertTo-Json -Depth 10 | Set-Content $manifestPath -Encoding utf8 ``` Без шага 2 пакет лежит в профиле и не загружается. Ровно в таком состоянии на машине, где плагин писался, оказался `dsh-bottom-info-bar`: установлен, но не активен. Тумблером это тоже делается: **Plugins** в боковой панели → `dsh-session-cost` → включить. Страница правит тот же список бандлов (её host-половина `plugin-manager` на десктопе включена, потому что он передаёт `profileContext`). ## `file:` и `link:` — чем отличаются на Windows Формат записи в `package.json` профиля решает, как пакет попадёт в `node_modules`, и от этого зависит, что будет при правке исходника. - **`file:`** (так ставится `.tgz` и так стояло на машине-источнике изначально). pnpm кладёт содержимое в свой store и делает **хардлинки** в `node_modules` профиля. Это не копия: у файлов один и тот же File ID, поэтому правка **на месте** видна в профиле сразу, без переустановки. Но атомарная замена файла (сохранение через временный файл и `rename` — так делают многие редакторы, `pnpm pack` и инструменты вроде нашего) **рвёт хардлинк**: в профиле остаётся старая версия, и нужна переустановка. Проверить, жив ли ещё линк: ```powershell fsutil hardlink list "$env:USERPROFILE\.dsh\profiles\desktop\node_modules\dsh-session-cost\lib\index.js" ``` Два пути в выводе — линк цел; один — в профиле уже отдельная копия. - **`link:`** — junction на папку с исходником. Правки видны всегда, чем бы их ни делали, переустановка не нужна вовсе. Цена: pnpm предупреждает, что `peerDependencies` (у плагина это `react`) из целевой папки не разрешатся, — для клиентской половины это неважно, `react` подставляет модульная система браузера. Плагин в профиле `desktop` стоит именно так, чтобы правки `lib/` доезжали до харнесса без переустановки. Живой линк ставится так (именно так плагин стоит на машине-источнике сейчас): ```powershell & $node $pnpm add "link:C:\Users\anton\src\dsh-cost-plugin" --dir $profile ``` ## Нужен ли перезапуск На десктопе — **нет**. Базовый бандл включает `hmr`, когда приложение передаёт `profileContext`, а `dsh-hmr` следит за манифестом профиля и обоими файлами патчей: правка `dsh.profile.bundles` пересобирает дерево на ходу, и клиентская половина подхватывается открытой страницей через HMR-транспорт. Проверено: приложение стартовало в 16:36, пакет встал в 16:41, ячейка появилась в том же процессе. Перезапуск нужен, если HMR выключен — в бандлах `headless`, `sdk` и `acp` он погашен в YAML, и там же, где профиль правили руками без пересборки. Перезагрузки одной страницы в этом случае недостаточно: плагины собираются при старте хоста. ## Проверка Открыть любой диалог, отправить сообщение. В нижнем ряду, сразу после родных ячеек, должна появиться сумма вида `₽ 0,1234`. Если пусто, открыть консоль (F12) и посмотреть строки `[dsh-session-cost]`: - `session id: ...` — какой id определился; - `cannot read ...` — не дошёл запрос до хостовой половины. Оба сообщения печатаются один раз на каждую новую причину, а не на каждый опрос. ## Что переносится, а что нет **Переносится:** сам плагин — код, страница состояния, расчёт. **Не переносится:** накопленный реестр. Стоимость хранится на каждой машине отдельно, в `~/.dsh/dsh-session-cost/state.json`. Это сделано намеренно: суммы относятся к сессиям конкретной установки, и чужие сессии в новом реестре всё равно не к чему привязать. Если всё же нужно перенести историю — скопируйте этот файл в ту же папку на новой машине. Формат переносимый, идентификаторы генераций глобально уникальны. ## Как обновить плагин Собрать новый архив здесь (`pnpm pack --pack-destination dist`), перенести, повторить установку. Если плагин стоит **ссылкой** (`link:`), обновление не нужно: правится исходник, и после ближайшей пересборки дерева подхватывается новое. Если он стоит через `file:`, правка исходника доедет только при записи на месте — после атомарной замены файла переустановите пакет. ## Как удалить ```powershell & $dsh plugin --profile desktop remove dsh-session-cost ``` Штатная команда убирает и пакет, и запись из `dsh.profile.bundles` (проверено). Если ставили голым pnpm — уберите `dsh-session-cost` из списка вручную или выключите тумблером в Plugins. Реестр `~/.dsh/dsh-session-cost/` при удалении остаётся, как и у `dsh-bottom-info-bar`; удалите папку вручную, если хотите чистый лист.