89cde16ddc
The notes described a machine that no longer matches: the runtime paths they hardcoded do not exist on this one, and three of their claims turned out to be wrong when the plugin was actually installed. What was wrong, and what is true: 1. Runtime paths. `~/.dsh/dsh-runtimes/...` is only where a downloaded runtime lives; this install carries it in the application. The notes now probe both locations and take the one that exists. 2. "You cannot install into the desktop profile from the CLI". The launcher refuses `desktop` only for booting and for --dump-config; `dsh plugin --profile desktop ...` is allowed because the Desktop carrier passes manageDesktopProfile. Verified: install, list, remove all work, and each one keeps dsh.profile.bundles in sync by itself. 3. "An application restart is required". Not on Desktop. The base bundle enables hmr whenever profileContext is supplied, and the application supplies it, so editing the profile manifest recomposes the tree live and the client half reaches an open page over the HMR transport. The application had started at 16:36 and the pill appeared in that same process after the 16:41 install. Also documented, because it decides whether an edit reaches the harness: `file:` on Windows produces hardlinks out of the pnpm store, so an in-place write is visible immediately but an atomic replace silently breaks the link; `link:` is a junction and always sees edits. The plugin is now installed as `link:` for that reason. The design note keeps its original text and carries dated corrections plus a table of what was actually verified, so the next install does not repeat the probing.
129 lines
11 KiB
Markdown
129 lines
11 KiB
Markdown
# Установка на другое устройство
|
||
|
||
Плагин — один файл: `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`; удалите папку вручную, если хотите чистый лист.
|