dsh-session-guard 0.1.0 → 0.1.2
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.ja.md +29 -0
- package/CHANGELOG.ko.md +29 -0
- package/CHANGELOG.md +29 -0
- package/INSTALL.ja.md +42 -0
- package/INSTALL.ko.md +42 -0
- package/INSTALL.md +44 -0
- package/INSTALL.zh.md +42 -0
- package/README.en.md +170 -0
- package/README.ja.md +106 -0
- package/README.ko.md +106 -0
- package/README.md +171 -128
- package/package.json +79 -67
- package/src/client/locales.ts +95 -0
- package/src/index.js +8 -4
- package/src/time.js +23 -7
package/README.md
CHANGED
|
@@ -1,128 +1,171 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<strong>高峰自动会话门:周末模式 + 高峰自动暂停 + 会话级冻结 + 后端自动重试</strong>
|
|
3
|
-
</p>
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<
|
|
8
|
-
</p>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
-
|
|
76
|
-
-
|
|
77
|
-
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
{
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<strong>高峰自动会话门:周末模式 + 高峰自动暂停 + 会话级冻结 + 后端自动重试</strong>
|
|
3
|
+
</p>
|
|
4
|
+
<img width="832" height="182" alt="00c4b89a-b026-4bf1-a358-a068e80d2da7" src="https://github.com/user-attachments/assets/31a8836f-0fe0-4043-948a-f0865bb1b3bb" />
|
|
5
|
+
|
|
6
|
+
<p align="center">
|
|
7
|
+
<a href="README.en.md">English</a> · <strong>中文</strong> · <a href="README.ja.md">日本語</a> · <a href="README.ko.md">한국어</a>
|
|
8
|
+
</p>
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="LICENSE"><img alt="MIT License" src="https://img.shields.io/badge/license-MIT-263146?style=flat-square"></a>
|
|
11
|
+
<img src="https://camo.githubusercontent.com/2c11fb2e0e14bb9985c5acbe61123a7441c5ee63aa27fa6e04e2a707ebfd6022/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6473682d2d706c7567696e2d72656164792d3437384342463f6c6f676f3d646565707365656b266c6f676f436f6c6f723d7768697465" alt="dsh-plugin" data-canonical-src="https://img.shields.io/badge/dsh--plugin-ready-478CBF?logo=deepseek&logoColor=white" style="max-width: 100%;">
|
|
12
|
+
<img alt="Public beta" src="https://img.shields.io/badge/status-public%20beta-7da1de?style=flat-square">
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
# dsh-session-guard
|
|
16
|
+
|
|
17
|
+
- [English README](./README.en.md)
|
|
18
|
+
- [中文 README](./README.md)
|
|
19
|
+
- [日本語 README](./README.ja.md)
|
|
20
|
+
- [한국어 README](./README.ko.md)
|
|
21
|
+
- [Installation guide](./INSTALL.md)
|
|
22
|
+
- [中文安装指南](./INSTALL.zh.md)
|
|
23
|
+
- [日本語インストールガイド](./INSTALL.ja.md)
|
|
24
|
+
- [한국어 설치 안내](./INSTALL.ko.md)
|
|
25
|
+
- [Changelog](./CHANGELOG.md)
|
|
26
|
+
- [日本語 changelog](./CHANGELOG.ja.md)
|
|
27
|
+
- [한국어 changelog](./CHANGELOG.ko.md)
|
|
28
|
+
|
|
29
|
+
> **兼容性说明:** v0.1.1 已包含日语(`ja`)和韩语(`ko`)字典,但当前官方 DSH 只通过 `LocaleRuntime` 提供 `zh` 和 `en`。在原版 DSH 中选择 `ja` 或 `ko` 会失败,并提示 `locale "<id>" is not registered`。需要等待官方 DSH 增加对应 locale ID 后才能正常使用。高级用户可以维护 DSH fork 进行扩展。
|
|
30
|
+
|
|
31
|
+
> 高峰时段自动暂停运行中的会话、低峰/周末自动续跑;配合 input-traffic 的冻结按钮做到**会话级**锁定;后端**自动重试**在冻结/门控期间让路。核心基于**自研会话门**(`agent.cancel keepInbox + goals.pause + session/event 安全边界 + followup 续跑`),不再依赖 dsh-task-control。
|
|
32
|
+
|
|
33
|
+
无需修改 dsh 源码、无需提 PR:`dsh plugin` 命令组装 + bundle patch 装配的 cordis 插件。
|
|
34
|
+
|
|
35
|
+
> 💡 **为什么推荐**:DeepSeek 已于 2026-08-17 实行**峰谷计费**——高峰时段(北京时间 9:00-12:00、14:00-18:00)单价为闲时(含午间、夜间、周末与节假日)的 **2 倍**。本插件在高峰自动停住运行会话、退峰自动续跑,错峰长跑最多可省 **50%**;手动冻结(配 input-traffic 按钮)可进一步按会话精确控停。
|
|
36
|
+
|
|
37
|
+
## 功能一览
|
|
38
|
+
|
|
39
|
+
- **周末模式**:识别周末(基于配置时区 `Intl.DateTimeFormat`,不踩裸 `getUTCDay()` 的北京边界 8 小时 bug)→ 周末无视峰谷、畅快跑。
|
|
40
|
+
- **高峰自动暂停(全局)**:进入高峰(且非周末)时,对所有 running root session 自动暂停;退峰自动恢复全部——**全局开关,无需手动**。
|
|
41
|
+
- **会话级冻结 / 恢复**:`sessionGuard` 冗余端口 + `POST /session-guard/rpc`,input-traffic 冻结按钮逐会话透传接入;也提供 `/pause /resume /cancel` 手动命令。
|
|
42
|
+
- **后端自动重试(D9)**:turn/end 瞬时失败(error/429/max-tokens)自适应退避自动续跑;永久失败停止;**冻结/门控期间让路**,绝不绕过会话门。
|
|
43
|
+
- **fail-open**:自研会话门不可用、session-guard 未装、设置服务缺失——均静默降级,绝不因依赖而崩。
|
|
44
|
+
|
|
45
|
+
## 安装
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
dsh plugin --profile web add github:<owner>/dsh-session-guard
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
装后重启 dsh web 并刷新页面。
|
|
52
|
+
|
|
53
|
+
## 设置(设置 → 插件 → session-guard,简单开关)
|
|
54
|
+
|
|
55
|
+
| 开关 | 默认 | 说明 |
|
|
56
|
+
|---|---|---|
|
|
57
|
+
| `enabled` | on | **高峰自动暂停冻结会话**:高峰时段自动暂停运行会话 |
|
|
58
|
+
| `offPeakAutoResume` | on | **低谷自动恢复**:低峰时段自动恢复被暂停的会话;关掉则退峰不自动恢复(需手动) |
|
|
59
|
+
| `weekendMode` | on | **周末模式**:识别周末 → 周末不自动暂停(周末本无高峰,畅快跑) |
|
|
60
|
+
| `queueFallback` | on | 自研会话门不可用时回退锁等待队列(fail-open) |
|
|
61
|
+
| `retryEnabled` | off | **自动重试(后端)**:瞬时失败自动续跑(默认关,保守) |
|
|
62
|
+
|
|
63
|
+
附属配置:
|
|
64
|
+
|
|
65
|
+
- `timezone`(默认 Asia/Shanghai)——**周末判定**和徽标显示用的时区;**不影响峰谷判定**(峰谷固定按北京时间);
|
|
66
|
+
- `peakWindows`(默认 09:00–12:00 / 14:00–18:00)——按北京时间(UTC+8)的峰谷窗口,与 DeepSeek 官方计费一致;
|
|
67
|
+
- `pauseMode`(`safe`/`force`)、`pauseReason`(`wait`/`stop`)——暂停推进方式;
|
|
68
|
+
- 重试参数:`retryText`、`retryGraceMs`、`retryCooldownMs`、`retryBackoffFactor`、`retryBackoffMaxMs`、`retryMaxConsecutive`。
|
|
69
|
+
|
|
70
|
+
## 行为
|
|
71
|
+
|
|
72
|
+
### 高峰自动门(全局)
|
|
73
|
+
|
|
74
|
+
- **入峰**(且非周末):对所有 running root session 调 `gate.stopNextTurn`——自研会话门真暂停(不打断推理,推理完成/工具派发前落在安全边界暂停),或按 `queueFallback` 回退锁等待队列;
|
|
75
|
+
- **退峰 / 周末**:`gate.resume` **全部**会话(自动续跑,无需手动)——受 `offPeakAutoResume` 开关控制,关掉则退峰不自动恢复;
|
|
76
|
+
- **峰谷时区**:固定使用北京时间(`Asia/Shanghai`),与 DeepSeek 官方计费基准一致,不受 `timezone` 配置影响;
|
|
77
|
+
- 状态机:单实例 `NORMAL ↔ PAUSED_PEAK`(`scheduler.js`),由单一 30s tick 驱动。
|
|
78
|
+
|
|
79
|
+
### 会话锁定(冻结)
|
|
80
|
+
|
|
81
|
+
- **冗余端口**:`ctx.provide('sessionGuard', service)`——`stopNextTurn(sessionId)` / `resume(sessionId)` / `lockQueue(sessionId)` / `unlockQueue(sessionId)` / `state(sessionId)`;
|
|
82
|
+
- **RPC 桥**:`POST /session-guard/rpc { action, sessionId }`——input-traffic 冻结按钮按 `sessionId` **逐会话**调用 `stopNextTurn` / `resume`;本插件未装则静默跳过(D8 fail-open);
|
|
83
|
+
- **手动命令**:`/pause [force|safe] [stop|wait]`、`/resume [confirm] [rerun|skip]`、`/cancel`——作用于调用它的会话(取 `invocation.agent.id`)。
|
|
84
|
+
|
|
85
|
+
### 后端自动重试(D9)
|
|
86
|
+
|
|
87
|
+
监听 `turn/end`,将失败分类:
|
|
88
|
+
|
|
89
|
+
- **瞬时失败**(error/429/max-tokens 等)→ 自适应退避自动 `followup(retryText)` 续跑;
|
|
90
|
+
- **永久失败**(鉴权/余额/模型/上下文超限)→ 停止;
|
|
91
|
+
- **冻结/门控期间让路**:`isFrozen(sessionId)` 为真(queueLocked / paused / taskControl paused)时不重试;
|
|
92
|
+
- 用户介入或成功回合重置连续失败计数。
|
|
93
|
+
|
|
94
|
+
### 状态徽标(前端展示)
|
|
95
|
+
|
|
96
|
+
输入区右侧显示一个**纯展示**状态徽标,实时反映当前所处阶段:
|
|
97
|
+
|
|
98
|
+
| 阶段 | 徽标文案 | CSS 类 | 含义 |
|
|
99
|
+
|---|---|---|---|
|
|
100
|
+
| `peak` | 高峰 | `sg-peak` | 工作日高峰时段,会话已被自动暂停 |
|
|
101
|
+
| `off-peak` | 谷时 | `sg-off` | 非高峰时段,会话正常运行 |
|
|
102
|
+
| `weekend` | 周末 | `sg-weekend` | 周末(周末模式开启时),无视峰谷畅快跑 |
|
|
103
|
+
|
|
104
|
+
- **轮询**:每 15 秒请求 `GET /session-guard/status`,获取全局 `phase`;
|
|
105
|
+
- **fail-open**:路由不可达、网络错误、或 `enabled` 关闭时→ 徽标静默隐藏,不影响任何会话;
|
|
106
|
+
- **独立于 input-traffic**:徽标由 session-guard 客户端独立渲染,**不需要安装 input-traffic 插件**即可显示。input-traffic 只负责冻结按钮,与徽标无依赖关系;
|
|
107
|
+
- **tooltip**:悬停显示 `阶段 · 时区 · 周末模式`(如 `周末 · Asia/Shanghai · 周末模式`)。
|
|
108
|
+
|
|
109
|
+
### 时区处理与校验
|
|
110
|
+
|
|
111
|
+
- 时区判定基于 **IANA 时区名**(如 `Asia/Shanghai`、`Asia/Tokyo`、`Asia/Seoul`),通过 `Intl.DateTimeFormat` 投影为配置时区的墙钟,**不依赖裸 `getUTCDay()`**——避免北京时区 UTC+8 边界错 8 小时的经典 bug(周六 00:30 北京时间,UTC 还是周五);
|
|
112
|
+
- `Intl.DateTimeFormat` 本身即为校验层:传入无效时区名(如 `Foo/Bar`)会抛 `RangeError`,被外层 try-catch 静默降级为默认时区 `Asia/Shanghai`(fail-open);
|
|
113
|
+
- 峰谷窗口为**左闭右开** `[start, end)`,支持跨午夜窗口(如 `22:00–06:00`);
|
|
114
|
+
- `timezone` 配置项对所有语言(中/英/日/韩)通用——`Intl.DateTimeFormat` 的 IANA 时区名不依赖 locale,日文/韩文界面下时区行为与中文完全一致。
|
|
115
|
+
|
|
116
|
+
### 与 input-traffic 协作
|
|
117
|
+
|
|
118
|
+
- input-traffic 的**冻结按钮**触发时经 `sessionGuard.stopNextTurn`(RPC,会话级)透传服务端;
|
|
119
|
+
- input-traffic **只做冻结增强**(队列冻结/解冻 + composer block),重试归本插件后端;
|
|
120
|
+
- 两者共享「会话隔离」语义:input-traffic 冻结队列按 sessionId 隔离,session-guard RPC 同样按 sessionId 锁。
|
|
121
|
+
|
|
122
|
+
## 冗余端口 `sessionGuard`
|
|
123
|
+
|
|
124
|
+
```js
|
|
125
|
+
{
|
|
126
|
+
stopNextTurn(sessionId, opts), // 停掉 session 下一回合(自研会话门 / 回退锁队列)
|
|
127
|
+
resume(sessionId, opts), // 恢复(confirm + choice: rerun|skip)
|
|
128
|
+
lockQueue(sessionId, reason), // 显式锁队列
|
|
129
|
+
unlockQueue(sessionId), // 显式解锁
|
|
130
|
+
state(sessionId), // { queueLocked, lockReason, paused, taskControlAvailable, taskControl }
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## HTTP 路由
|
|
135
|
+
|
|
136
|
+
- `GET /session-guard/state?session=<id>` — 会话状态
|
|
137
|
+
- `GET /session-guard/settings` — 设置 + taskControl 可用性
|
|
138
|
+
- `GET /session-guard/status` — 全局当前阶段(状态徽标轮询)
|
|
139
|
+
- `GET /session-guard/diag` — 运行时诊断
|
|
140
|
+
- `POST /session-guard/rpc` — `{ action: stopNextTurn|resume|lockQueue|unlockQueue|state, sessionId }`
|
|
141
|
+
|
|
142
|
+
## 状态存储
|
|
143
|
+
|
|
144
|
+
每会话 JSON:`$DSH_HOME/.dsh/session-guard/<sessionId>.json`(原子写;`DSH_SESSION_GUARD_STATE_DIR` 可覆盖)。
|
|
145
|
+
|
|
146
|
+
## 测试
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
npm test # node --test tests/*.test.mjs(时区/周末/状态机/会话门/桥接/重试)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## 模块
|
|
153
|
+
|
|
154
|
+
| 文件 | 职责 |
|
|
155
|
+
|---|---|
|
|
156
|
+
| `src/time.js` | 高峰/周末判定(时区正确) |
|
|
157
|
+
| `src/scheduler.js` | 纯状态机 NORMAL ↔ PAUSED_PEAK |
|
|
158
|
+
| `src/pause-gate.js` | 自研会话门引擎(agent.cancel keepInbox + goals.pause + 安全边界 + followup 续跑) |
|
|
159
|
+
| `src/pause-store.js` | 自研暂停状态持久化 |
|
|
160
|
+
| `src/gate.js` | 会话门驱动(自研真暂停 / 回退锁队列,fail-open) |
|
|
161
|
+
| `src/bridge.js` | `sessionGuard` 冗余端口 |
|
|
162
|
+
| `src/retry.js` | 后端自动重试(失败分类/退避/冻结让路) |
|
|
163
|
+
| `src/detect.js` | 自动检测(host taskControl / client input-traffic 桥) |
|
|
164
|
+
| `src/store.js` | 每会话持久化状态 |
|
|
165
|
+
| `src/settings.js` | 设置子板块(schemastery schema + fail-open 注册) |
|
|
166
|
+
| `src/index.js` | host apply(设置/路由/tick/提供服务/重试接线) |
|
|
167
|
+
| `src/client/` | 浏览器 half(状态徽标 + 设置卡片) |
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
MIT — 见 [LICENSE](LICENSE)。
|
package/package.json
CHANGED
|
@@ -1,67 +1,79 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
1
|
+
{
|
|
2
|
+
"peerDependencies": {
|
|
3
|
+
"@deepseek-ai/dsh-llm": "0.1.1-rc.2"
|
|
4
|
+
},
|
|
5
|
+
"version": "0.1.2",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"files": [
|
|
8
|
+
"src/",
|
|
9
|
+
"lib/",
|
|
10
|
+
"cordis.patch.yml",
|
|
11
|
+
"README.md",
|
|
12
|
+
"README.en.md",
|
|
13
|
+
"README.ja.md",
|
|
14
|
+
"README.ko.md",
|
|
15
|
+
"INSTALL.md",
|
|
16
|
+
"INSTALL.zh.md",
|
|
17
|
+
"INSTALL.ja.md",
|
|
18
|
+
"INSTALL.ko.md",
|
|
19
|
+
"CHANGELOG.md",
|
|
20
|
+
"CHANGELOG.ja.md",
|
|
21
|
+
"CHANGELOG.ko.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@deepseek-ai/schemastery": "^3.18.1"
|
|
26
|
+
},
|
|
27
|
+
"name": "dsh-session-guard",
|
|
28
|
+
"type": "module",
|
|
29
|
+
"exports": {
|
|
30
|
+
"./client": "./lib/client.js",
|
|
31
|
+
"./package.json": "./package.json",
|
|
32
|
+
".": "./src/index.js"
|
|
33
|
+
},
|
|
34
|
+
"description": "Peak auto session gate: weekend mode + peak auto-pause + session-level freeze + backend auto-retry",
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": "\u003e=20"
|
|
37
|
+
},
|
|
38
|
+
"dsh": {
|
|
39
|
+
"client": {
|
|
40
|
+
"inject": [
|
|
41
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
42
|
+
"@deepseek-ai/dsh-client-locale",
|
|
43
|
+
"@deepseek-ai/dsh-client-ui-slots",
|
|
44
|
+
"@deepseek-ai/dsh-client-ui-settings"
|
|
45
|
+
],
|
|
46
|
+
"platform": "web"
|
|
47
|
+
},
|
|
48
|
+
"bundle": {
|
|
49
|
+
"patch": "./cordis.patch.yml"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"keywords": [
|
|
53
|
+
"deepseek-harness",
|
|
54
|
+
"dsh",
|
|
55
|
+
"plugin",
|
|
56
|
+
"peak",
|
|
57
|
+
"off-peak",
|
|
58
|
+
"weekend",
|
|
59
|
+
"pause",
|
|
60
|
+
"freeze",
|
|
61
|
+
"retry",
|
|
62
|
+
"session-gate"
|
|
63
|
+
],
|
|
64
|
+
"scripts": {
|
|
65
|
+
"test": "node --test \"tests/*.test.mjs\"",
|
|
66
|
+
"build": "tsdown",
|
|
67
|
+
"lint": "eslint src tests"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"tsdown": "^0.22.2",
|
|
71
|
+
"eslint": "^10.8.1",
|
|
72
|
+
"typescript": "^5.6.0",
|
|
73
|
+
"@types/react": "~18.3.1",
|
|
74
|
+
"typescript-eslint": "^8.67.0",
|
|
75
|
+
"react": "^18.2.0",
|
|
76
|
+
"@eslint/js": "^10.0.1"
|
|
77
|
+
},
|
|
78
|
+
"main": "src/index.js"
|
|
79
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/** `session-guard` client dictionaries (zh / en / ja / ko). */
|
|
2
|
+
|
|
3
|
+
/** Dictionary namespace owned by this plugin. */
|
|
4
|
+
export const NS = 'session-guard'
|
|
5
|
+
|
|
6
|
+
/** Simplified Chinese dictionary (the key-set source of truth). */
|
|
7
|
+
export const zh = {
|
|
8
|
+
'badge.normal': '正常',
|
|
9
|
+
'badge.paused': '已暂停(峰值)',
|
|
10
|
+
'badge_paused_peak': '峰值暂停中',
|
|
11
|
+
'settings.enabled': '高峰自动暂停',
|
|
12
|
+
'settings.enabled.desc': '高峰时段自动暂停运行中的会话',
|
|
13
|
+
'settings.offPeakAutoResume': '低谷自动恢复',
|
|
14
|
+
'settings.offPeakAutoResume.desc': '低峰时段自动恢复被暂停的会话',
|
|
15
|
+
'settings.weekendMode': '周末模式',
|
|
16
|
+
'settings.weekendMode.desc': '识别周末 → 周末不自动暂停',
|
|
17
|
+
'settings.queueFallback': '回退锁等待队列',
|
|
18
|
+
'settings.queueFallback.desc': '自研会话门不可用时回退锁等待队列(fail-open)',
|
|
19
|
+
'settings.retryEnabled': '自动重试',
|
|
20
|
+
'settings.retryEnabled.desc': '瞬时失败自动续跑(默认关,保守)',
|
|
21
|
+
'settings.timezone': '时区',
|
|
22
|
+
'settings.peakWindows': '高峰时间窗口',
|
|
23
|
+
'settings.unavailable': '设置不可用:请确认 dsh-session-guard 已装配进 profile。',
|
|
24
|
+
'status.normal': '正常运行',
|
|
25
|
+
'status.paused_peak': '峰值暂停中',
|
|
26
|
+
} satisfies Record<string, string>
|
|
27
|
+
|
|
28
|
+
/** English dictionary (keys mirror zh). */
|
|
29
|
+
export const en: Record<keyof typeof zh, string> = {
|
|
30
|
+
'badge.normal': 'Normal',
|
|
31
|
+
'badge.paused': 'Paused (peak)',
|
|
32
|
+
'badge_paused_peak': 'Peak paused',
|
|
33
|
+
'settings.enabled': 'Peak auto-pause',
|
|
34
|
+
'settings.enabled.desc': 'Auto-pause running sessions during peak hours',
|
|
35
|
+
'settings.offPeakAutoResume': 'Off-peak auto-resume',
|
|
36
|
+
'settings.offPeakAutoResume.desc': 'Auto-resume paused sessions during off-peak hours',
|
|
37
|
+
'settings.weekendMode': 'Weekend mode',
|
|
38
|
+
'settings.weekendMode.desc': 'Detect weekends → no auto-pause on weekends',
|
|
39
|
+
'settings.queueFallback': 'Fallback lock-wait queue',
|
|
40
|
+
'settings.queueFallback.desc': 'Fallback to lock-wait queue when custom session gate is unavailable (fail-open)',
|
|
41
|
+
'settings.retryEnabled': 'Auto-retry',
|
|
42
|
+
'settings.retryEnabled.desc': 'Transient failure auto-resume (off by default, conservative)',
|
|
43
|
+
'settings.timezone': 'Timezone',
|
|
44
|
+
'settings.peakWindows': 'Peak time windows',
|
|
45
|
+
'settings.unavailable': 'Settings unavailable: make sure dsh-session-guard is assembled into this profile.',
|
|
46
|
+
'status.normal': 'Running normally',
|
|
47
|
+
'status.paused_peak': 'Peak paused',
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Japanese dictionary (keys mirror zh). */
|
|
51
|
+
export const ja: Record<keyof typeof zh, string> = {
|
|
52
|
+
'badge.normal': '通常',
|
|
53
|
+
'badge.paused': '一時停止(ピーク)',
|
|
54
|
+
'badge_paused_peak': 'ピーク一時停止中',
|
|
55
|
+
'settings.enabled': 'ピーク自動一時停止',
|
|
56
|
+
'settings.enabled.desc': 'ピーク時間帯に実行中セッションを自動一時停止',
|
|
57
|
+
'settings.offPeakAutoResume': 'オフピーク自動再開',
|
|
58
|
+
'settings.offPeakAutoResume.desc': 'オフピーク時に一時停止セッションを自動再開',
|
|
59
|
+
'settings.weekendMode': '週末モード',
|
|
60
|
+
'settings.weekendMode.desc': '週末を認識→週末は自動一時停止しない',
|
|
61
|
+
'settings.queueFallback': 'フォールバックロック待機キュー',
|
|
62
|
+
'settings.queueFallback.desc': 'カスタムセッションゲート利用不可時にロック待機キューにフォールバック(fail-open)',
|
|
63
|
+
'settings.retryEnabled': '自動リトライ',
|
|
64
|
+
'settings.retryEnabled.desc': '瞬時失敗自動再試行(デフォルトオフ、保守的)',
|
|
65
|
+
'settings.timezone': 'タイムゾーン',
|
|
66
|
+
'settings.peakWindows': 'ピーク時間ウィンドウ',
|
|
67
|
+
'settings.unavailable': '設定利用不可:dsh-session-guard が profile に組み込まれているか確認してください。',
|
|
68
|
+
'status.normal': '通常実行中',
|
|
69
|
+
'status.paused_peak': 'ピーク一時停止中',
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Korean dictionary (keys mirror zh). */
|
|
73
|
+
export const ko: Record<keyof typeof zh, string> = {
|
|
74
|
+
'badge.normal': '정상',
|
|
75
|
+
'badge.paused': '일시정지(피크)',
|
|
76
|
+
'badge_paused_peak': '피크 일시정지 중',
|
|
77
|
+
'settings.enabled': '피크 자동 일시정지',
|
|
78
|
+
'settings.enabled.desc': '피크 시간대에 실행 중인 세션을 자동 일시정지',
|
|
79
|
+
'settings.offPeakAutoResume': '오피크 자동 재개',
|
|
80
|
+
'settings.offPeakAutoResume.desc': '오피크 시간대에 일시정지된 세션을 자동 재개',
|
|
81
|
+
'settings.weekendMode': '주말 모드',
|
|
82
|
+
'settings.weekendMode.desc': '주말 감지 → 주말에는 자동 일시정지 안 함',
|
|
83
|
+
'settings.queueFallback': '폴백 잠금 대기 큐',
|
|
84
|
+
'settings.queueFallback.desc': '커스텀 세션 게이트 사용 불가 시 잠금 대기 큐로 폴백(fail-open)',
|
|
85
|
+
'settings.retryEnabled': '자동 재시도',
|
|
86
|
+
'settings.retryEnabled.desc': '일시적 실패 자동 재개(기본값 꺼짐, 보수적)',
|
|
87
|
+
'settings.timezone': '타임존',
|
|
88
|
+
'settings.peakWindows': '피크 시간대',
|
|
89
|
+
'settings.unavailable': '설정 사용 불가: dsh-session-guard가 이 profile에 조립되었는지 확인하세요.',
|
|
90
|
+
'status.normal': '정상 실행 중',
|
|
91
|
+
'status.paused_peak': '피크 일시정지 중',
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Dictionary key union. */
|
|
95
|
+
export type SessionGuardKey = keyof typeof zh
|
package/src/index.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* 对齐 dsh-thinking-levels;不 value-import dsh-settings);设置服务缺失时 fail-open 用默认配置照常运行。
|
|
13
13
|
*/
|
|
14
14
|
import { computeState, transition } from './scheduler.js'
|
|
15
|
-
import { wallClock, isWeekend, isInPeak } from './time.js'
|
|
15
|
+
import { wallClock, isWeekend, isInPeak, BILLING_TIMEZONE } from './time.js'
|
|
16
16
|
import { createStore } from './store.js'
|
|
17
17
|
import { createGate } from './gate.js'
|
|
18
18
|
import { createBridge } from './bridge.js'
|
|
@@ -207,12 +207,15 @@ export function apply(ctx) {
|
|
|
207
207
|
return json(200, { ok: true, settings: cfg, taskControlAvailable: detectTaskControl(ctx) })
|
|
208
208
|
}
|
|
209
209
|
// GET /session-guard/status —— 全局当前阶段(状态徽标轮询用)
|
|
210
|
+
// 峰谷判定:固定北京时间(BILLING_TIMEZONE),与 DeepSeek 官方计费一致
|
|
211
|
+
// 周末判定:用配置时区(用户本地的周末)
|
|
210
212
|
if (method === 'GET' && url.pathname === '/session-guard/status') {
|
|
211
213
|
const cfg = readCfg()
|
|
212
214
|
const now = new Date()
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
const
|
|
215
|
+
const wcUser = wallClock(cfg.timezone, now)
|
|
216
|
+
const wcBilling = wallClock(BILLING_TIMEZONE, now)
|
|
217
|
+
const weekend = isWeekend(wcUser.weekday)
|
|
218
|
+
const peak = cfg.enabled && !weekend && isInPeak(wcBilling, cfg.peakWindows || [])
|
|
216
219
|
return json(200, {
|
|
217
220
|
ok: true,
|
|
218
221
|
status: {
|
|
@@ -223,6 +226,7 @@ export function apply(ctx) {
|
|
|
223
226
|
enabled: cfg.enabled,
|
|
224
227
|
weekendMode: cfg.weekendMode,
|
|
225
228
|
timezone: cfg.timezone,
|
|
229
|
+
billingTimezone: BILLING_TIMEZONE,
|
|
226
230
|
now: now.toISOString(),
|
|
227
231
|
},
|
|
228
232
|
})
|