dsh-shutdown-guard 1.5.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/LICENSE +20 -20
- package/README.en.md +263 -0
- package/README.md +263 -253
- package/README.ru.md +263 -0
- package/cordis.patch.yml +21 -19
- package/lib/client.js +372 -60
- package/lib/i18n.mjs +425 -0
- package/lib/index.mjs +1078 -1000
- package/package.json +70 -68
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.5.1 — 2026-11-04
|
|
4
|
+
|
|
5
|
+
- 三语界面:中文 / English / Русский。宿主侧文案目录 78 键、侧边栏卡片 74 键,三语键集齐平、零缺失;日志与提示全部改走 `t(lang, key)`,`lib/index.mjs` 内已无硬编码中文串。
|
|
6
|
+
- 新增语言选择器:设置 → 插件 → 任务完成后关机 → 「语言」,切换即时生效——经 `POST /api/dsh-shutdown-guard/config` 的 `language` 字段落盘,卡片强制重绘,不需要重启 DSH。
|
|
7
|
+
- 新增 `language` 配置项:取值 `auto` | `zh` | `en` | `ru`,默认 `auto`(跟随系统语言)。它由 `loadStore`(`lib/index.mjs:283`)读取、经 `POST /config` 在运行时写入;**不是** `normalizeProfile` 字段,三份 README 的配置表已单独为它补一行。
|
|
8
|
+
- 语言偏好同时写入宿主配置(`data/config.json`)与浏览器 `localStorage`:前者是权威值,后者让卡片在首帧就按所选语言渲染,重启后不再闪一下中文。
|
|
9
|
+
- 文档:新增 `README.en.md`、`README.ru.md`,三份 README 的配置表统一补 `language` 行;演示页改成三语(`scripts/demo/i18n.js`,157 键)。
|
|
10
|
+
- 修复:切换语言后,事件日志里切换前的旧行会永久停留在旧语言;现在切换时整环重取(`lib/client.js` `setSnapshot`)。
|
|
11
|
+
- 修复:`saveStore()` 在 `apply()` 外引用越界变量,写 `data/config.json` 失败时会抛 `ReferenceError`、`log.configWriteFailed` 提示永远打不出来(`lib/index.mjs:292-295`、`:1039`)。
|
|
12
|
+
- 可访问性:设置里 5 个开关补 `aria-label`,屏幕阅读器可读出开关名称(未新增文案键)。
|
|
13
|
+
- 测试:新增 i18n 目录断言——`LANGS` 固定为三语、`catalogCoverage().missing` 为空、每语键数与基准一致。
|
|
14
|
+
- ⚠️ 升级注意:**已有配置无需任何改动或迁移**。`language` 缺省即 `auto`,与 v1.5.0 的行为一致;升级后若想固定语言,在设置里选一次即可。
|
|
15
|
+
|
|
3
16
|
## v1.5.0 — 2026-11-02
|
|
4
17
|
|
|
5
18
|
- 改名:`dsh-shutdown-panel` → **`dsh-shutdown-guard`**(Shutdown Guard)。原名只描述了界面,没表达它真正的特长——关机前逐条排除。`shutdown` 仍在包名第二位,市场按关键词搜索时排序不受影响。
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 ltayshark0637
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ltayshark0637
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
SOFTWARE.
|
package/README.en.md
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# Shutdown Guard · Shut down when tasks finish
|
|
2
|
+
[中文](README.md) · **English** · [Русский](README.ru.md)
|
|
3
|
+
|
|
4
|
+
<p align="center"><img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/banner.png" width="880" alt="Shutdown Guard — automatic shutdown when tasks finish, a night-watch card in the sidebar"></p>
|
|
5
|
+
|
|
6
|
+
[](CHANGELOG.md)
|
|
7
|
+
[](https://ltayshark0637.github.io/dsh-Shutdown-Guard/demo.html)
|
|
8
|
+
[](https://github.com/deepseek-ai)
|
|
9
|
+
[](#constraints)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
|
|
12
|
+
Adds a "shut down automatically when all tasks finish" card to the DeepSeek Harness sidebar, with a more varied and polished visual treatment, decision logic, and customization. It sits below Skill Center and above the session list, and updates in real time with task state.
|
|
13
|
+
|
|
14
|
+
**▶ [Interactive demo](https://ltayshark0637.github.io/dsh-Shutdown-Guard/demo.html)** — no installation needed; see what it looks like and how it decides. Two panes: **Learn** (rules, appearance, states) and **Try** (a random scenario where you arm the guard, cancel it, and release it yourself, all the way to a shutdown or a block). All data is generated locally at random; nothing is sent over the network.
|
|
15
|
+
|
|
16
|
+
## Why you need it
|
|
17
|
+
|
|
18
|
+
People who run long tasks know this scene: you hand the agent a batch of work in the evening, want the machine to shut down when it is done, and you are not at the desk.
|
|
19
|
+
|
|
20
|
+
But "task finished" does not mean "safe to shut down" — background jobs may still be running, a session may have errored, the agent may be waiting for your answer, or you may have stopped it halfway. Shutting down in any of those cases is an incident. The plugin blocks each of these situations and shuts down only when it is genuinely safe.
|
|
21
|
+
|
|
22
|
+
## Rules: when it actually shuts down
|
|
23
|
+
|
|
24
|
+
In a blocked state (see below) nothing is sent at all; otherwise all five gates must pass before `shutdown /s` is issued:
|
|
25
|
+
|
|
26
|
+
1. **Armed** — you turned it on manually
|
|
27
|
+
2. **No countdown already running** — avoids duplicate issuance
|
|
28
|
+
3. **All root sessions idle** — no agent is still working
|
|
29
|
+
4. **No running or stopping background jobs** — `blockOnJobs`, on by default
|
|
30
|
+
5. **No session error in this batch** — `onlyOnSuccess`, on by default
|
|
31
|
+
|
|
32
|
+
If any one is missing, it does not shut down and writes the reason on the card and in the settings page.
|
|
33
|
+
|
|
34
|
+
## Three looks
|
|
35
|
+
|
|
36
|
+
| A · Hazard tape | B · Radar | C · Terminal |
|
|
37
|
+
|:----------------------------------------------------------------------:|:---------------------------------------------------------------:|:------------------------------------------------------------------------------------:|
|
|
38
|
+
| <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/02-armed.png" width="250"> | <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/06-variant-b-radar.png" width="250"> | <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/07-variant-c-terminal.png" width="250"> |
|
|
39
|
+
| Large status text + scrolling red-and-yellow stripes at the bottom | Concentric rings + a scanning beam, sessions and background jobs shown as dots | Command-line summary + six indicator lights for the gate conditions |
|
|
40
|
+
|
|
41
|
+
Dots in the radar are added and removed, never reordered: when the count changes, the dots you are looking at do not jump.
|
|
42
|
+
|
|
43
|
+
<p align="center"><img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/anim-radar.gif" width="330" alt="Radar sweep"></p>
|
|
44
|
+
|
|
45
|
+
Switch in settings; takes effect immediately, no restart needed.
|
|
46
|
+
|
|
47
|
+
## Six runtime states
|
|
48
|
+
|
|
49
|
+
| Off | Standby | Waiting on background jobs |
|
|
50
|
+
|:---------------------------------------------------:|:-----------------------------------------------------:|:----------------------------------------------------------------------:|
|
|
51
|
+
| <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/01-off.png" width="250"> | <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/02-armed.png" width="250"> | <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/03-hold.png" width="250"> |
|
|
52
|
+
|
|
53
|
+
| Countdown | Issued | Blocked |
|
|
54
|
+
|:----------------------------------------------------:|:-----------------------------------------------------------------------:|:------------------------------------------------------------------------:|
|
|
55
|
+
| <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/04-fire.png" width="250"> | <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/05-fired.png" width="250"> | <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/08-blocked-halted.png" width="250"> |
|
|
56
|
+
|
|
57
|
+
`Off` → `Standby` → `Waiting on background jobs` → `Countdown` → `Issued`; a blocking error at any stage moves it to `Blocked`. You can cancel at any point during the countdown; **cancelling leaves it armed** — the next batch will still shut down.
|
|
58
|
+
|
|
59
|
+
Want to flip through all six states? In section 04 of the demo's Learn pane, the three capsules `A` `B` `C` at the top right switch which look the preview uses.
|
|
60
|
+
|
|
61
|
+
## Blocked states
|
|
62
|
+
|
|
63
|
+
| halted · needs manual action | waiting · retries automatically |
|
|
64
|
+
|:--------------------------------------------------------------:|:---------------------------------------------------------------------------------:|
|
|
65
|
+
| <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/08-blocked-halted.png" width="250"> | <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/09-blocked-waiting.png" width="250"> |
|
|
66
|
+
|
|
67
|
+
For errors that cannot be handled as ordinary failures, the plugin **stays armed**, changes the card's colour, and writes out the reason:
|
|
68
|
+
|
|
69
|
+
- **`halted`** (slate blue) — insufficient quota, invalid credentials, context overrun, unsupported capability, disk full. Only a human can resolve it; click "disarm and retry".
|
|
70
|
+
- **`waiting`** (slate green, a breathing dot) — rate limiting, 5xx, network interruption, empty response, timeout, image offload. Retried automatically according to policy; at the right moment a "continue the original plan" instruction is injected.
|
|
71
|
+
|
|
72
|
+
<p align="center"><img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/anim-blocked.gif" width="380" alt="Waiting for recovery, the status dot breathing"></p>
|
|
73
|
+
|
|
74
|
+
Retry cadence is configured per failure type; see [Retry policies](#retry-policies).
|
|
75
|
+
|
|
76
|
+
## AFK auto-pilot
|
|
77
|
+
|
|
78
|
+
When nobody is at the desk, the plugin covers three things for you:
|
|
79
|
+
|
|
80
|
+
- **Auto-answer questions** (on by default): when the agent asks something, it replies "The user is AFK. Finish the tasks already assigned, write up a summary report to disk, and do not touch branches that were not assigned." It returns `selected: []` plus custom text, so **it never selects an option for you**; turn this off and questions come to you as usual.
|
|
81
|
+
- **Error recovery**: when a session errors, the agent is first asked to investigate and continue the original plan; a second failure in the same session switches to "stop retrying and write up a report".
|
|
82
|
+
- **Interruption protection**: if you stop a task yourself midway, that does not trigger a shutdown.
|
|
83
|
+
|
|
84
|
+
## Where it lives
|
|
85
|
+
|
|
86
|
+
| Armed: below Skill Center, above the session list | Countdown: same spot, the whole strip turns red |
|
|
87
|
+
|:-------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------:|
|
|
88
|
+
| <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/10-sidebar-hold.png" width="250"> | <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/11-sidebar-fire.png" width="250"> |
|
|
89
|
+
|
|
90
|
+
The card is currently pinned to this sidebar slot. A future version plans to make it available as a standalone widget (with a switch in settings); this section will be updated then.
|
|
91
|
+
|
|
92
|
+
## Other details
|
|
93
|
+
|
|
94
|
+
- **Vertical collapse**: collapsed it keeps only the title and status; click the title to expand.
|
|
95
|
+
|
|
96
|
+
<img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/16-folded.png" width="250" align="right" alt="Collapsed state">
|
|
97
|
+
|
|
98
|
+
- **Theme adaptation**: the card carries its own `--dsp-*` palette and picks light or dark automatically from the host surface's brightness; you can also force dark / light / Claude Style.
|
|
99
|
+
|
|
100
|
+
- **Event log**: the settings page shows recent events and "why it did not shut down last time"; the full stream is in `data/events.log`.
|
|
101
|
+
|
|
102
|
+
<br clear="all">
|
|
103
|
+
|
|
104
|
+
## Settings page
|
|
105
|
+
|
|
106
|
+
| Dark | Light |
|
|
107
|
+
|:---------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------:|
|
|
108
|
+
| <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/12-settings-dark.png" width="380"> | <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/13-settings-light.png" width="380"> |
|
|
109
|
+
|
|
110
|
+
Three groups: Appearance / When to shut down / Status. Every switch takes effect immediately.
|
|
111
|
+
|
|
112
|
+
- **Default profile** is locked at 60 seconds and cannot be changed; there are 8 custom slots you can tune freely.
|
|
113
|
+
- "All sessions idle" is the floor condition, always on and not switchable.
|
|
114
|
+
- "Background jobs finished" blocks background jobs; "skip this round if any session errored" blocks erroring batches.
|
|
115
|
+
- "AFK auto-answer" controls whether questions are answered for you while armed; the description states "replies never select an option for you; turn this off and questions come to you as usual."
|
|
116
|
+
|
|
117
|
+
## Light and third-party themes
|
|
118
|
+
|
|
119
|
+
| Light card | Claude Style |
|
|
120
|
+
|:-----------------------------------------------------:|:------------------------------------------------------:|
|
|
121
|
+
| <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/14-light.png" width="250"> | <img src="https://cdn.jsdelivr.net/gh/ltayshark0637/dsh-Shutdown-Guard@main/docs/screenshots/15-claude.png" width="250"> |
|
|
122
|
+
|
|
123
|
+
The card does not inherit the host palette; it brings its own, while the settings page follows the host theme. The third-party Claude Style theme has a matching palette too.
|
|
124
|
+
|
|
125
|
+
## Installation
|
|
126
|
+
|
|
127
|
+
Published on npm; recommended:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
dsh plugin --profile web add dsh-shutdown-guard
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Or install straight from GitHub:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
dsh plugin --profile web add github:ltayshark0637/dsh-Shutdown-Guard
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Then **restart DSH**.
|
|
140
|
+
|
|
141
|
+
> ⚠️ **The client bundle is only wired into the module graph at DSH startup**: after editing `lib/client.js` you must restart; refreshing the page does nothing. The same applies to the server side.
|
|
142
|
+
|
|
143
|
+
**On a restricted network**: the GitHub command is essentially `pnpm add github:...` and needs a clone. If cloning fails, prefer the npm command (it goes through the registry); if neither works, install from a local path — DSH Settings → Plugins → Add, enter the **absolute path** of this directory → Install → restart.
|
|
144
|
+
|
|
145
|
+
**Manual fallback**: create a symlink `node_modules\dsh-shutdown-guard` under `profiles\web` pointing at this directory, then:
|
|
146
|
+
|
|
147
|
+
- add `link:<absolute path of this directory>` to `dependencies` and `pnpm.overrides` in `profiles\web\package.json`
|
|
148
|
+
- append `dsh-shutdown-guard` to `dsh.profile.bundles`
|
|
149
|
+
|
|
150
|
+
## Permissions and impact
|
|
151
|
+
|
|
152
|
+
Once installed, the plugin does the following:
|
|
153
|
+
|
|
154
|
+
| Area | Concrete behaviour |
|
|
155
|
+
| --- | --- |
|
|
156
|
+
| **Command execution** | Calls Windows `shutdown.exe` through `subprocess`: `/s /t <seconds>` schedules the shutdown, `/a` cancels it. **Only invoked when armed and all five gates pass** |
|
|
157
|
+
| **File access** | Only `data/` inside the plugin directory: `config.json` (configuration) and `events.log` (event log) |
|
|
158
|
+
| **Events** | `agent/status`, `agent/error`, `session/event`, `user-questions/request` |
|
|
159
|
+
| **HTTP routes** | Under the local DSH Web server, `/api/dsh-shutdown-guard/`: `GET /state`, `GET /events`, `POST /arm`, `POST /disarm`, `POST /cancel`, `POST /config`; POST validates that Origin is `127.0.0.1` or `localhost` |
|
|
160
|
+
| **Network** | **No external requests at all**, no data collection |
|
|
161
|
+
| **Platform** | **Windows only**. On anything other than `win32` the plugin silently does not load |
|
|
162
|
+
|
|
163
|
+
While AFK auto-pilot is on, the plugin answers the agent's questions and injects recovery instructions into erroring sessions during armed periods; you can switch this off at any time in settings.
|
|
164
|
+
|
|
165
|
+
## Configuration
|
|
166
|
+
|
|
167
|
+
Written in `cordis.patch.yml` (the patch inside the plugin package), or changed at runtime via `POST /config`.
|
|
168
|
+
|
|
169
|
+
| Key | Range | Default | Description |
|
|
170
|
+
| --------------- | ------ | ------ | ----------------------------------------- |
|
|
171
|
+
| `countdownSec` | 10–600 | 60 | Seconds of countdown before shutdown (fixed at 60 in the default profile, not editable) |
|
|
172
|
+
| `marginSec` | 0–60 | 5 | Extra margin passed to `shutdown /t` |
|
|
173
|
+
| `onlyOnSuccess` | bool | `true` | Skip the shutdown when any session in this batch errored |
|
|
174
|
+
| `blockOnJobs` | bool | `true` | Skip the shutdown while background jobs are running |
|
|
175
|
+
| `afkAutoAnswer` | bool | `true` | Answer questions and perform error recovery for the user while armed |
|
|
176
|
+
| `language` | enum | `auto` | UI language; `auto` follows the system language, or pin it to `zh` / `en` / `ru` |
|
|
177
|
+
|
|
178
|
+
### Retry policies
|
|
179
|
+
|
|
180
|
+
Each error code is assigned a policy name; the policies themselves are configurable:
|
|
181
|
+
|
|
182
|
+
| Policy | Default cadence | Assigned to |
|
|
183
|
+
| ------------ | -------------------------------------- | ---------------------------------- |
|
|
184
|
+
| `rate-limit` | backoff 30 → 60 → 120 → 240 → 300, capped | `RATE_LIMIT` |
|
|
185
|
+
| `transient` | fixed 20 seconds | `SERVER` / `TRANSPORT` / `TIMEOUT` |
|
|
186
|
+
| `empty` | fixed 30 seconds | `EMPTY_RESPONSE` |
|
|
187
|
+
| `offload` | fixed 5 seconds | `IMAGE_OFFLOAD_REQUIRED` |
|
|
188
|
+
|
|
189
|
+
Rate limiting uses backoff rather than a fixed interval because hammering a rate-limited service **extends** the limit rather than just wasting requests. 5xx and network failures recover on a predictable timescale, so a fixed interval is simply faster. Image offload is a local disk operation and is almost immediately retryable, hence 5 seconds.
|
|
190
|
+
|
|
191
|
+
Override a single error code:
|
|
192
|
+
|
|
193
|
+
```yaml
|
|
194
|
+
retryAssign:
|
|
195
|
+
RATE_LIMIT: slow-limit
|
|
196
|
+
retryPolicies:
|
|
197
|
+
slow-limit: { mode: backoff, base: 60, max: 900 }
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
An unknown `code` falls back to `transient`; malformed policies are dropped and the defaults are kept. The currently effective assignments are available from `retryAssign` and `retryPolicies` in `/state`.
|
|
201
|
+
|
|
202
|
+
UI preferences live in the browser's `localStorage`: `dsh-shutdown-guard.variant` / `.theme` / `.folded`.
|
|
203
|
+
|
|
204
|
+
## HTTP API
|
|
205
|
+
|
|
206
|
+
Prefix `/api/dsh-shutdown-guard`, used by the card's own same-origin polling:
|
|
207
|
+
|
|
208
|
+
| Method | Path | Description |
|
|
209
|
+
| ---- | -------------------------- | -------------------------------------------------------------------------------- |
|
|
210
|
+
| GET | `/state?since=<ms>` | Full state plus incremental events |
|
|
211
|
+
| POST | `/arm` `/disarm` `/cancel` | Arm / disarm / cancel this countdown |
|
|
212
|
+
| POST | `/config` | Change configuration: `customEnabled`, `activeProfileId`, `profileId`+`patch`, `afkAutoAnswer`, `language` |
|
|
213
|
+
| GET | `/events?since=&limit=` | Event stream |
|
|
214
|
+
|
|
215
|
+
POSTs from a non-local Origin return 403; non-POST returns 405.
|
|
216
|
+
|
|
217
|
+
## Logs
|
|
218
|
+
|
|
219
|
+
- `<plugin directory>\data\events.log` — human-readable event stream (categories `config` / `afk` / `skip`); the settings page's "Event log" reads it
|
|
220
|
+
- `<DSH_HOME>\dsh-shutdown-guard.log` — process-level append log
|
|
221
|
+
|
|
222
|
+
## Development
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
node test/host.test.mjs # server: 26 assertions, mock ctx, never actually shuts down
|
|
226
|
+
node test/client.test.cjs # client bundle smoke test
|
|
227
|
+
node scripts/gen-gallery.cjs # generate the screenshot page from the real CSS in lib/client.js
|
|
228
|
+
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/screenshot.ps1 # headless Edge renders PNGs (transparent background + auto crop)
|
|
229
|
+
node scripts/gen-gif.cjs # generate the three animated GIFs used in the README
|
|
230
|
+
node scripts/gen-banner.cjs # generate the 1280x640 social preview image
|
|
231
|
+
node scripts/gen-demo.cjs # generate docs/demo.html (the interactive demo)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
All screenshots are generated from the real CSS in `lib/client.js`, so they cannot drift from the product. The animations work the same way: CSS animations are frozen at several points in time via `animation-delay`, captured frame by frame, and assembled with a built-in GIF89a encoder — no ffmpeg or ImageMagick needed on the machine.
|
|
235
|
+
|
|
236
|
+
The Learn section of the demo page is rendered live too: the six states are generated on the spot with the same `card()` markup as the product, not captured as screenshots.
|
|
237
|
+
|
|
238
|
+
## FAQ
|
|
239
|
+
|
|
240
|
+
**Q: Why does changing a setting do nothing?**
|
|
241
|
+
A: Both the server and the client need DSH restarted to load new code. Local HMR does not apply to locally linked plugins.
|
|
242
|
+
|
|
243
|
+
**Q: Why didn't it shut down after arming?**
|
|
244
|
+
A: Check "why it did not shut down last time" in settings; it names the specific reason (background jobs, errors, not armed, etc.).
|
|
245
|
+
|
|
246
|
+
**Q: Can I change my mind during the countdown?**
|
|
247
|
+
A: Yes. Use "Cancel shutdown" on the card or just run `shutdown /a`; cancelling keeps it armed, so the next batch still applies.
|
|
248
|
+
|
|
249
|
+
**Q: Can it shut down by mistake?**
|
|
250
|
+
A: With the default configuration, the plugin acts only when all four hold — all sessions idle, no background jobs, no errors, and you armed it manually. Breaking any one of them cancels or skips the shutdown. Manual task termination is also detected and excluded.
|
|
251
|
+
|
|
252
|
+
**Q: Does it work outside Windows?**
|
|
253
|
+
A: Not yet; that is planned for later.
|
|
254
|
+
|
|
255
|
+
## Constraints
|
|
256
|
+
|
|
257
|
+
- Windows only: exits early on anything other than `win32` and mounts nothing.
|
|
258
|
+
- Zero runtime dependencies: the server uses only `node:fs` / `node:path` / `node:crypto`, the browser only `require('react')`.
|
|
259
|
+
- Does not modify `app.asar` or DSH source.
|
|
260
|
+
|
|
261
|
+
## License
|
|
262
|
+
|
|
263
|
+
[MIT](LICENSE)
|