DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

Peak Hours — DeepSeek Harness 插件(DSH Plugin)
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
P

dsh-peak-hours

Peak Hours

DeepSeek Harness 的运行时段开关:始终运行,或仅在非高峰时段运行——每项任务(包括已在运行的任务)都会在中国高价时段开始时暂停,并在结束时恢复。

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:lion231226/dsh-peak-hours#2764dcf75dcbdf62e77ea0c3f731e1546b156026
README兼容性版本

兼容性与来源证明

Peak Hours 以 dsh-peak-hours 发布,当前版本为 0.2.1。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/10/14

版本

0.2.1stable
2026/10/14
0.1.1stable
2026/10/9
0.1.0stable
2026/10/9

相关插件

正在加载相关插件…

最新版
0.2.1
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 1
周下载
0
最近提交
2026/10/14
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 models-usage 分类下经过校验的插件。

Whale Widgetdsh-whale-widgetDSH Web 界面右下角的 DeepSeek 余额小鲸鱼挂件:余额/今日已用/峰谷定价、自定义泡泡点击序列(文本/余额/今日/峰谷/图片/随机语句与并列加权选择)、逐行样式与字体、悬浮快捷编辑、音效与每轮消耗、自定义角色/动图/音效、吸附与翻转自定义Usage@linxin666/dsh-usage用于 dsh Web GUI 的使用统计插件:检测各提供商的余额和编程套餐配额,并实时记录令牌使用情况;侧边栏 Settings 行上方显示紧凑的价格概览卡片Client Ui Model Capabilities@linxin666/dsh-client-ui-model-capabilities为自定义 pi-ai 提供商声明每个模型的能力(图像输入和推理力度),可直接在 Models 设置卡片中编辑;写入官方 llm-pi-ai 设置命名空间,不更改 DSH 源代码。Cost Meterdsh-cost-meterDeepSeek Harness 会话费用统计插件:本会话成本、当日费用、历史记录与官方价格同步,支持多厂商多模型价格计费(内置 170+ 模型 ID 价格目录与自动匹配)、主流 Coding Plan 订阅额度查询与显示(13 家,含 OpenDesign 工作区查询、含小米 MiMo Token Plan 控制台 Cookie 查询、SCNet Token Plan 本地 Credits 计量与火山方舟 Volcano Ark Coding Plan AK/SK 签名查询)、自定义 Provider

README

dsh-peak-hours

A run-window switch for DeepSeek Harness (dsh).

It adds a control to the right of the composer's mode buttons that chooses between running always and running only in off-peak hours. In the second mode every dsh task — including one that is already running — is paused when a peak-price window starts and resumed automatically when it ends.

Available in English (this file) and 中文.

Run windows

Off-peak is the half-price window. Peak, in Beijing time (UTC+8), is:

WhenPhase
Monday–Friday, 09:00–12:00 and 14:00–18:00, excluding Chinese statutory holidayspeak
Everything else — 00:00–09:00, 12:00–14:00, 18:00–24:00, all weekend, all statutory holidaysidle

Make-up workdays (weekends that are worked to offset a holiday) stay idle: the rule only looks at the weekday and whether the date is a statutory holiday.

Install

From the dsh CLI:

dsh plugin --profile web add github:lion231226/dsh-peak-hours

The plugin is pure JavaScript with no build step and no runtime dependencies, so a source install is enough.

For a desktop profile that is currently running, this repository also ships install.ps1, which copies the package into %DSH_HOME%\profiles\<profile>\node_modules\ and maintains one managed row in the profile's cordis.patch.yml. It validates the patch file with js-yaml before writing (a malformed patch file stops the Loader from reconciling the whole profile), waits for the plugin to answer, and re-activates the entry with a fresh row id if a previous attempt left it failed. No restart is required.

Do not mix the two install paths. dsh plugin add registers the package as a profile bundle, and the bundle layer then contributes the patch row from the package's own cordis.patch.yml. install.ps1 writes that row by hand instead; running it against a profile that already has the bundle would leave two entries with the same id, and nothing downstream de-duplicates them (the patch applier pushes inserted rows as-is and the cordis Loader has no duplicate check). The script now refuses to run in that case.

powershell -ExecutionPolicy Bypass -File .\install.ps1
powershell -ExecutionPolicy Bypass -File .\install.ps1 -Uninstall

Using it

The button sits in the composer tool row, immediately to the right of the mode buttons (the permission and plan selectors). It has three states:

StateLabelDot
Run always全天运行 / Run alwaysneutral
Off-peak only, currently idle空闲时段 · 运行中 / Off-peak · runninggreen
Off-peak only, currently peak空闲时段 · 已暂停 / Off-peak · pausedamber

Clicking it opens a panel with the two modes, the current Beijing time, the next switch and a per-second countdown, today's holiday (when there is one), a warning when the holiday calendar has no data for the year, and a note while a clock override is active.

While a peak window is in force, a banner above the composer card states that submitted tasks will start automatically at the end of the window, with a live countdown.

How the pause works

The host half hooks two waterfalls and only acts in idle-only mode:

  1. agent/pre-step — before every model call. An abort during the wait is re-thrown, which is the control flow the agent loop already expects (signal.throwIfAborted() follows the waterfall).
  2. tools/pre-execute — before every tool body is dispatched, covering a step that runs into a peak window. On abort it returns the runtime's designed { kind: 'cancel' } instead of throwing, because a throwing listener is classified as a scheduler failure and fails the whole step.

The gate releases immediately when the phase is idle, and while a peak window is in force it registers a waiter and arms a single timer at the exact next transition instant — no polling, no busy loop. When the timer fires, the phase is re-evaluated and every waiter is released, so the work continues on its own.

llm/stream is deliberately not gated: it returns an AsyncIterable rather than a promise, and the agent loop has a call path that bypasses it, so the primary gate already covers every model call.

Nothing is lost while waiting: messages and tool calls stay in the session log, no model request is made, and the wait is abortable (pressing stop cancels it).

HTTP API

Registered on the host's loopback web server; no GUI token is required on loopback.

The mode is per session: every session carries its own choice, and a task is judged by the session that owns it. A session with no explicit choice follows default.

MethodPathBody / result
GET/api/peak-hours/health{ ok, plugin, version }
GET/api/peak-hours/state?session=<id>the state envelope below; without ?session= it reports default
POST/api/peak-hours/mode{ "mode": "always" | "idle-only" | null, "session"?: "<id>", "scope"?: "session" | "default" } — mode: null with a session clears that override; neither field writes default. Requires Content-Type: application/json
POST/api/peak-hours/clock{ "offsetMs": <int|null>, "ttlMs"?: <int> }; ttlMs is capped at 30 minutes
{ "ok": true, "state": {
  "mode": "always", "defaultMode": "always", "modeSource": "session",
  "sessionId": "session-abc", "phase": "idle", "reason": "off-hours",
  "now": 1791541815888, "nowText": "2026-10-09 18:30:15",
  "nextTransitionAt": 1791766800000, "nextTransitionText": "2026-10-12 09:00:00", "nextPhase": "peak",
  "msUntilTransition": 224984112, "paused": false,
  "waitingTasks": 0, "waitingTasksTotal": 0, "waitingTasksUnresolved": 0,
  "holidayToday": null, "holidayCoverage": "known", "unknownHolidayYear": null,
  "timeZone": "Asia/Shanghai (UTC+8)", "peakWindows": ["09:00-12:00", "14:00-18:00"],
  "clockOverride": null, "config": { "allowClockOverride": true } } }

waitingTasks counts the session named by ?session=, and the whole host when the parameter is absent — which is why the older session-less curl examples keep their meaning. waitingTasksTotal is always host-wide. waitingTasksUnresolved counts waiters whose session could not be resolved; those follow default, and the count exists so a resolution failure is visible instead of looking like "nothing is waiting".

clockOverride shifts the host's notion of "now" so a peak window can be simulated without waiting for one. It always carries a TTL (10 minutes by default) and clears itself: without that, a session that is held by the window it created has nothing left to release it. Set DSH_PEAK_HOURS_ALLOW_CLOCK=0 to disable the endpoint.

Holiday data

The built-in calendar lists every statutory day off in 2025 (28 days) and 2026 (33 days), taken from the State Council holiday notices. Make-up workdays are not part of the set. Each entry keeps its source titles and URLs in HOLIDAY_SOURCE_DETAIL inside lib/core/holidays.js.

The 2027 notice has not been published yet, so that year reports holidayCoverage: "unknown" with unknownHolidayYear: 2027 and treats the date as a non-holiday (a weekday inside a window is peak); the UI surfaces the warning. Adding a year is one data entry.

Callers can overlay their own dates with createCalendar({ extra: { '2027-01-01': '元旦' } }); extra wins and is not restricted by years.

Configuration

KeyDefaultMeaning
allowClockOverridetrueWhether POST /api/peak-hours/clock is accepted
versionfrom package.jsonVersion reported by /health

Per-session choices live in %DSH_HOME%\peak-hours-state.json as { "version": 2, "default": "always", "sessions": { "<sessionId>": "idle-only" } }, written with serialized atomic writes. An older { "mode": ... } file is migrated on first read — default takes that value and sessions starts empty — and a corrupt file falls back to always with an empty table, logging once. The table is capped at 500 entries and evicts the least recently written one, logging each eviction. Disposing the plugin releases every listener, timer and route.

Known limits

  • A model call that has already been issued is not interrupted; the task pauses at its next safe boundary.
  • Background processes in a terminal, and background shells started as jobs, are not agent steps and are not gated.
  • A message submitted during a peak window is not dropped — it waits and continues when the window ends.
  • Each session with a mounted client keeps its own poll (15 s, 3 s near a boundary), so request volume grows with the number of open sessions.
  • Writing default changes every session that has no override of its own; the composer states that scope before the change is made.

Upgrading from 0.1.x

The mode used to be one host-wide value. It now lives per session, and the old value becomes default, so every session without its own entry keeps behaving exactly as before after the upgrade. Two things to know:

  • Refresh the window after installing. A page still running the 0.1.x client sends a bare {mode} write, which the new host correctly reads as "write default" — i.e. the old bundle would reproduce the very bug this release fixes.
  • Downgrading loses sessions. An 0.1.x build ignores the sessions table and rewrites the file in the old shape, so back up or delete %DSH_HOME%\peak-hours-state.json before going back.

Tests

node --test                          # author suites + the independent verification suite
node --test "test/**/*.test.mjs"     # author suites only
node --test "verify/**/*.test.mjs"   # independent verification only
node tools/smoke-host.mjs            # host half against a fake context, over real HTTP
node tools/show-monday.mjs           # print one day's phase segments

test/ holds the author suites (core schedule, host gate/routes/store, client). verify/ holds an independent suite written against the same contracts: a day-by-day check of the holiday calendar against the official notices, a boundary matrix at one-second resolution, property tests over the transition function, gate semantics under a fake clock, adversarial cases, client bundle checks, and a harness that mounts the plugin under the real cordis runtime. verify/EVIDENCE.md records each command with its raw output.

Node 24 rejects a directory argument for node --test, hence the glob patterns above.

Field test (real clock, no simulation)

On Monday 2026-10-12, with the plugin in off-peak mode, a message submitted at 09:01:58 Beijing time — inside the morning peak window — was held for 178 minutes. The session log for that run shows the message entering the inbox at 09:01:58.530, the turn opening two milliseconds later, then no event of any kind until step/start at 12:00:03.051 — three seconds after the boundary at 12:00:00 — followed by the model request at 12:00:03.054. Nothing was dropped and no interval was skipped: the work simply waited for the window to end.

License

MIT