# Shutdown Guard · Выключение после завершения задач [中文](README.md) · [English](README.en.md) · **Русский**

Shutdown Guard — автоматическое выключение после завершения задач, ночная карточка на боковой панели

[![version](https://img.shields.io/badge/version-1.5.1-2ea44f)](CHANGELOG.md) [![demo](https://img.shields.io/badge/%E2%96%B6-%D0%94%D0%95%D0%9C%D0%9E-d97757)](https://ltayshark0637.github.io/dsh-Shutdown-Guard/demo.html) [![DSH](https://img.shields.io/badge/DSH-%E2%89%A50.1.5--rc.1-4a90d9)](https://github.com/deepseek-ai) [![platform](https://img.shields.io/badge/platform-Windows-0078d4)](#ограничения) [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE) Добавляет в боковую панель DeepSeek Harness карточку «выключить компьютер после завершения всех задач» — с более разнообразным и качественным оформлением, логикой принятия решения и настройкой под себя. Карточка расположена под «Центром навыков» и над списком сессий и обновляется в реальном времени вместе с состоянием задач. **▶ [Интерактивная демонстрация](https://ltayshark0637.github.io/dsh-Shutdown-Guard/demo.html)** — подключать плагин не нужно: сначала посмотрите, как он выглядит и как принимает решения. Две страницы: **«Понять»** (правила, внешний вид, состояния) и **«Попробовать»** (случайный сценарий: вручную включите охрану, отмените её, снимите — и проследите до самого выключения или блокировки). Все данные генерируются локально случайным образом, сеть не используется. ## Зачем это нужно У тех, кто запускает долгие задачи, сценарий обычно такой: вечером вы поручаете агенту пачку работы и хотите, чтобы по её завершении компьютер выключился, — а вас рядом нет. Но «задачи завершены» не означает «можно выключать»: фоновые задачи ещё выполняются, в сессии произошла ошибка, агент ждёт вашего ответа, вы сами прервали его на полпути. Выключение в любом из этих случаев — авария. Плагин отсекает каждую такую ситуацию и выключает компьютер, только когда это действительно безопасно. ## Правила: когда происходит выключение В заблокированном состоянии (см. ниже) команда не отправляется вовсе; в остальных случаях должны одновременно выполниться пять условий, и только тогда отправляется `shutdown /s`: 1. **Охрана включена** — вы включили её вручную 2. **Обратный отсчёт уже не идёт** — чтобы не отправить команду повторно 3. **Все корневые сессии простаивают** — ни один агент ещё не работает 4. **Нет выполняющихся или останавливающихся фоновых задач** — `blockOnJobs`, включено по умолчанию 5. **В этой партии нет ошибок сессий** — `onlyOnSuccess`, включено по умолчанию Если не выполнено хотя бы одно условие, выключения не будет, а причина будет указана на карточке и на странице настроек. ## Три варианта оформления | A · Предупреждающая лента | B · Радар | C · Терминал | |:----------------------------------------------------------------------:|:---------------------------------------------------------------:|:------------------------------------------------------------------------------------:| | | | | | Крупный статус + бегущая красно-жёлтая штриховка внизу | Концентрические круги + сканирующий луч, сессии и фоновые задачи показаны точками | Сводка в стиле командной строки + шесть индикаторов условий | Точки на радаре только добавляются и удаляются, но не переставляются: при изменении количества те точки, на которые вы смотрите, не прыгают на другие места.

Сканирование радара

Переключается в настройках, действует сразу, перезапуск не нужен. ## Шесть состояний работы | Выключено | Ожидание | Ожидание фоновых задач | |:---------------------------------------------------:|:-----------------------------------------------------:|:----------------------------------------------------------------------:| | | | | | Обратный отсчёт | Команда отправлена | Блокировка | |:----------------------------------------------------:|:-----------------------------------------------------------------------:|:------------------------------------------------------------------------:| | | | | `Выключено` → `Ожидание` → `Ожидание фоновых задач` → `Обратный отсчёт` → `Команда отправлена`; на любом этапе блокирующая ошибка переводит карточку в `Блокировка`. Во время обратного отсчёта можно отменить в любой момент; **после отмены охрана остаётся включённой** — следующая партия задач всё равно приведёт к выключению. Хотите пересмотреть все шесть состояний? В демонстрации, в разделе 04 страницы «Понять», в правом верхнем углу есть три «капсулы» `A` `B` `C` — они переключают оформление предпросмотра. ## Заблокированные состояния | halted · нужно вмешательство человека | waiting · автоматические повторы | |:--------------------------------------------------------------:|:---------------------------------------------------------------------------------:| | | | При ошибках, которые нельзя обработать как обычный сбой, плагин **не снимает охрану**, меняет цвет карточки и пишет причину: - **`halted`** (серо-синий) — нехватка квоты, недействительные учётные данные, превышение контекста, неподдерживаемая возможность, переполнен диск. Справиться может только человек: нажмите «Снять и повторить». - **`waiting`** (серо-зелёный, точка «дышит») — ограничение частоты, 5xx, обрыв сети, пустой ответ, тайм-аут, выгрузка изображений. Повторяется автоматически по политике; в нужный момент внедряется инструкция «продолжить по исходному плану».

Ожидание восстановления, точка состояния «дышит»

Ритм повторов настраивается отдельно для каждого типа сбоя, см. [Политики повторов](#политики-повторов). ## Автопилот AFK Когда вас нет рядом, плагин берёт на себя три вещи: - **Автоматические ответы на вопросы** (включено по умолчанию): когда агент что-то спрашивает, плагин отвечает: «Пользователь в AFK. Сначала выполните уже поставленные задачи, сведите отчёт и сохраните его на диск, не трогайте ветки, которые не были поручены». Возвращается `selected: []` плюс пользовательский текст, поэтому **ни один вариант за вас не выбирается**; если выключить, вопросы снова будут приходить вам. - **Восстановление после ошибок**: при ошибке сессии агенту сначала предлагается разобраться и продолжить по исходному плану; при повторной ошибке в той же сессии — «прекратить повторы и завершить отчётом». - **Защита от прерывания**: если вы сами остановили задачу на полпути, выключение не сработает. ## Где он находится | Охрана включена: под «Центром навыков», над списком сессий | Обратный отсчёт: там же, вся полоса краснеет | |:-------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------:| | | | Сейчас карточка закреплена именно в этом месте боковой панели. В дальнейшем планируется сделать её самостоятельной формой (с переключателем в настройках); тогда здесь появится пояснение. ## Прочее - **Вертикальное сворачивание**: в свёрнутом виде остаются только заголовок и статус; нажмите на заголовок, чтобы развернуть. Свёрнутое состояние - **Адаптация к теме**: у карточки собственная палитра `--dsp-*`, светлые и тёмные цвета выбираются автоматически по яркости поверхности хоста; можно также принудительно задать тёмную / светлую / Claude Style. - **Журнал событий**: на странице настроек видны последние события и «почему в прошлый раз не выключилось»; полный поток — в `data/events.log`.
## Страница настроек | Тёмная | Светлая | |:---------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------:| | | | Три группы: Оформление / Когда выключать / Состояние. Все переключатели действуют сразу. - **Профиль по умолчанию** зафиксирован на 60 секундах и не меняется; есть ещё 8 пользовательских профилей, которые можно свободно настраивать. - «Все сессии остановились» — базовое условие, включено всегда и не отключается. - «Фоновые задачи завершены» блокирует фоновые задачи, «пропустить этот раунд при ошибке в сессии» блокирует партии с ошибками. - «Автоответ в AFK» управляет тем, отвечает ли плагин на вопросы за вас, пока включена охрана; в описании сказано: «ответы не выбирают за вас ни один вариант; после отключения вопросы снова приходят вам». ## Светлая тема и сторонние темы | Светлая карточка | Claude Style | |:-----------------------------------------------------:|:------------------------------------------------------:| | | | Карточка не наследует палитру хоста, у неё своя; страница настроек следует теме хоста. У сторонней темы Claude Style тоже есть соответствующая палитра. ## Установка Опубликовано в npm, рекомендуется: ```bash dsh plugin --profile web add dsh-shutdown-guard ``` Или установить напрямую с GitHub: ```bash dsh plugin --profile web add github:ltayshark0637/dsh-Shutdown-Guard ``` После установки **перезапустите DSH**. > ⚠️ **Клиентский бандл попадает в граф модулей только при запуске DSH**: после изменения `lib/client.js` обязателен перезапуск, обновление страницы не поможет. С серверной частью то же самое. **При ограниченной сети**: команда с GitHub по сути представляет собой `pnpm add github:...` и требует клонирования. Если клонировать не получается, используйте в первую очередь команду из npm (она идёт через registry); если не работает и она, установите по локальному пути — DSH Настройки → Плагины → Добавить, укажите **абсолютный путь** к этому каталогу → Установить → перезапустить. **Ручной резервный вариант**: создайте в `profiles\web` символическую ссылку `node_modules\dsh-shutdown-guard` на этот каталог, затем: - в `profiles\web\package.json` добавьте `link:<абсолютный путь к этому каталогу>` в `dependencies` и `pnpm.overrides` - в `dsh.profile.bundles` добавьте `dsh-shutdown-guard` ## Права и влияние После установки плагин делает следующее: | Область | Конкретное поведение | | --- | --- | | **Выполнение команд** | Через `subprocess` вызывает Windows `shutdown.exe`: `/s /t <секунды>` планирует выключение, `/a` отменяет. **Вызывается только при включённой охране и выполнении всех пяти условий** | | **Файлы** | Только `data/` в каталоге плагина: `config.json` (настройки) и `events.log` (журнал событий) | | **События** | `agent/status`, `agent/error`, `session/event`, `user-questions/request` | | **HTTP-маршруты** | В локальном веб-сервере DSH: `/api/dsh-shutdown-guard/` — `GET /state`, `GET /events`, `POST /arm`, `POST /disarm`, `POST /cancel`, `POST /config`; для POST проверяется, что Origin равен `127.0.0.1` или `localhost` | | **Сеть** | **Никаких внешних запросов**, данные не собираются | | **Платформа** | **Только Windows**. На платформах, отличных от `win32`, плагин молча не загружается | Когда автопилот AFK включён, плагин во время охраны отвечает на вопросы агента и внедряет инструкции восстановления в сессии с ошибками; этот переключатель можно в любой момент отключить в настройках. ## Настройка Записывается в `cordis.patch.yml` (патч внутри пакета плагина) или меняется во время работы через `POST /config`. | Ключ | Диапазон | По умолчанию | Описание | | --------------- | ------ | ------ | ----------------------------------------- | | `countdownSec` | 10–600 | 60 | Секунды обратного отсчёта перед выключением (в профиле по умолчанию фиксировано 60, не меняется) | | `marginSec` | 0–60 | 5 | Дополнительный запас, передаваемый в `shutdown /t` | | `onlyOnSuccess` | bool | `true` | Пропускать выключение при ошибке в любой сессии этой партии | | `blockOnJobs` | bool | `true` | Пропускать выключение, пока выполняются фоновые задачи | | `afkAutoAnswer` | bool | `true` | Отвечать на вопросы за пользователя и выполнять восстановление после ошибок во время охраны | | `language` | список | `auto` | Язык интерфейса; `auto` следует языку системы, можно закрепить `zh` / `en` / `ru` | ### Политики повторов Каждому коду ошибки назначается имя политики; сами политики настраиваются: | Политика | Ритм по умолчанию | Назначена | | ------------ | -------------------------------------- | ---------------------------------- | | `rate-limit` | backoff 30 → 60 → 120 → 240 → 300, с потолком | `RATE_LIMIT` | | `transient` | фиксировано 20 секунд | `SERVER` / `TRANSPORT` / `TIMEOUT` | | `empty` | фиксировано 30 секунд | `EMPTY_RESPONSE` | | `offload` | фиксировано 5 секунд | `IMAGE_OFFLOAD_REQUIRED` | Для ограничения частоты используется backoff, а не фиксированный интервал: частые повторы к сервису, ограничивающему частоту, **продлевают** период ограничения, а не просто тратят запросы. Сбои 5xx и сетевые ошибки восстанавливаются за предсказуемое время, поэтому фиксированный интервал оказывается быстрее. Выгрузка изображений — локальная операция с диском, повтор возможен почти сразу, отсюда 5 секунд. Переопределение отдельного кода ошибки: ```yaml retryAssign: RATE_LIMIT: slow-limit retryPolicies: slow-limit: { mode: backoff, base: 60, max: 900 } ``` Неизвестный `code` откатывается к `transient`; политики с неверной структурой отбрасываются, а значения по умолчанию сохраняются. Действующие назначения можно прочитать из `retryAssign` и `retryPolicies` в `/state`. Настройки интерфейса хранятся в браузерном `localStorage`: `dsh-shutdown-guard.variant` / `.theme` / `.folded`. ## HTTP-интерфейс Префикс `/api/dsh-shutdown-guard`, используется для опроса самой карточкой с того же источника: | Метод | Путь | Описание | | ---- | -------------------------- | -------------------------------------------------------------------------------- | | GET | `/state?since=` | Полное состояние + инкрементальные события | | POST | `/arm` `/disarm` `/cancel` | Включить охрану / снять / отменить текущий обратный отсчёт | | POST | `/config` | Изменить настройки: `customEnabled`, `activeProfileId`, `profileId`+`patch`, `afkAutoAnswer`, `language` | | GET | `/events?since=&limit=` | Поток событий | POST с Origin не с этого компьютера возвращает 403; запрос не методом POST — 405. ## Журналы - `<каталог плагина>\data\events.log` — читаемый человеком поток событий (категории `config` / `afk` / `skip`), его же читает «Журнал событий» на странице настроек - `\dsh-shutdown-guard.log` — журнал уровня процесса (дописывается) ## Разработка ```bash node test/host.test.mjs # сервер: 26 проверок, mock ctx, реального выключения нет node test/client.test.cjs # smoke-тест клиентского бандла node scripts/gen-gallery.cjs # генерация страницы скриншотов из настоящего CSS в lib/client.js powershell -NoProfile -ExecutionPolicy Bypass -File scripts/screenshot.ps1 # headless Edge рендерит PNG (прозрачный фон + автообрезка) node scripts/gen-gif.cjs # генерация трёх анимированных GIF для README node scripts/gen-banner.cjs # генерация социального превью 1280x640 node scripts/gen-demo.cjs # генерация docs/demo.html (интерактивная демонстрация) ``` Все скриншоты генерируются из настоящего CSS в `lib/client.js`, поэтому не расходятся с продуктом. С анимациями так же: CSS-анимации замораживаются через `animation-delay` в нескольких моментах времени, снимаются покадрово и собираются встроенным кодировщиком GIF89a — ffmpeg или ImageMagick на машине не нужны. Раздел «Понять» на странице демонстрации тоже рендерится в реальном времени: шесть состояний создаются на месте той же разметкой `card()`, что и в продукте, а не берутся со скриншотов. ## Частые вопросы **В: Почему изменение настройки ни на что не влияет?** О: И сервер, и клиент загружают новый код только после перезапуска DSH. Локальный HMR для локально подключённых плагинов не работает. **В: Почему после включения охраны компьютер не выключился?** О: Посмотрите на странице настроек «почему в прошлый раз не выключилось» — там указана конкретная причина (фоновые задачи, ошибка, охрана не включена и т. п.). **В: Можно ли передумать во время обратного отсчёта?** О: Да. «Отменить выключение» на карточке или просто `shutdown /a`; после отмены охрана остаётся включённой и действует для следующей партии. **В: Бывает ли ошибочное выключение?** О: При настройках по умолчанию плагин действует, только когда одновременно выполнены четыре условия: все сессии простаивают, фоновых задач нет, ошибок нет, охрана включена вручную. Нарушение любого из них отменяет или пропускает выключение. Ручное прерывание задачи также распознаётся и исключается. **В: Работает ли не на Windows?** О: Пока нет, это запланировано на будущее. ## Ограничения - Только Windows: на платформах, отличных от `win32`, происходит ранний выход, ничего не монтируется. - Нулевые зависимости времени выполнения: сервер использует только `node:fs` / `node:path` / `node:crypto`, браузер — только `require('react')`. - Не изменяет `app.asar` и исходный код DSH. ## Лицензия [MIT](LICENSE)