deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:YMRYMR/deepseek-peak
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
A drop-in dsh-plugin for the
deepseek-ai/deepseek-harness
web UI that shows the DeepSeek V4 API's current peak / off-peak pricing
state, lets you pause the LLM during peak hours with a queue that drains
on its own, watches your account balance, and warns you when the
balance drops below a threshold you set.

The PEAK pill in the session header, the BALANCE row with the
REFRESH and TOP UP actions, and the per-model 30-day peak/off-peak
bar charts (v4-pro and v4-flash). The pill is amber when the
balance drops below the configured lowBalanceWarningUsd
threshold.
Pill (always visible, in the session header next to the Session log button). Reads the current phase from the browser clock against a baked-in UTC schedule:
PRE-CUTOVER badge while the new schedule is being previewed→ live target arrow while pre-cutover, or a → next phase HH:MM
arrow after the cutoverlowBalanceWarningUsd threshold (default $1.00).
Overrides the phase color so a low balance is visible at a glance.Tooltip (on hover, while the pill is open). Expands under the pill:
/api/peak-hours/balance so the API key never
leaves the harness process). Two action pills on the right:https://platform.deepseek.com/top_up in a
new tab.Settings (registered on the existing peak-hours namespace in
the host's settings plane, exposed through Settings → Plugins → Plugin configuration → Peak hours):
paused — boolean, the same value the pill toggle writes. Two
write paths into the same field; last write wins.lowBalanceWarningUsd — number, the threshold below which the
pill switches to amber. Default $1.00. Zero is allowed (always
warn); negatives are rejected by the schema.Background refresh:
usePeakHoursState
hook), so toggle / threshold / queue / balance changes propagate
in under two ticks./api/peak-hours/usage route, which walks the session persistence
log. The in-browser trajectory walk is a fallback for the
harness-not-running case.Source of truth:
api-docs.deepseek.com/quick_start/pricing/. The schedule windows and the cutover date are baked in as constants insrc/client/domain.ts. ThePRE-CUTOVERwindow is the period between "the new schedule is announced" and "the new schedule is enforced"; the pill shows it for the duration and the gate is engaged wheneverpaused && peakregardless of cutover state.
This repo ships two things:
harness-plugin/ — a dsh-plugin Cordis client package for the
harness web UI. This is the real integration.
widget.html + serve.js — a self-contained browser widget
you can pin as a tab in any browser, no harness required. Useful as a
fallback for users who don't run the harness. It does NOT include the
pause / queue / balance features; it's a phase + countdown display
only.
The harness plugin is the rich one. The standalone widget is a "schedule on a second monitor" display.
Requires:
deepseek-harness working tree (any recent commit)node ≥ 22.19pnpm ≥ 11 (install once with npm i -g pnpm)# Clone this repo
git clone https://github.com/YMRYMR/deepseek-peak.git
cd deepseek-peak
# One-liner installer: takes your harness clone as the argument
./install.sh /path/to/deepseek-harness
What the installer does (each step is idempotent and skipped if already done):
harness-plugin/ → <harness>/packages/client/ui-peak-hours/ui-peak-hours row to packages/bundle/web-app/cordis.patch.ymlpackages/bundle/web-app/package.jsontsconfig.client.jsontsconfig.base.jsonpnpm install in the harnesspnpm run build:lib:host (required for the generated Typert contracts)pnpm --filter @deepseek-ai/dsh-client-ui-peak-hours run bundleThen start the harness:
cd /path/to/deepseek-harness
pnpm dsh web
Open http://127.0.0.1:3080/. The pill appears in the top-right of the
session header, left of the Session log button.
Hard-refresh the browser (Ctrl+Shift+R) the first time so the new
__DSH_BOOT__ roster loads.
A compact pill, ~180 px wide, with this shape (left to right):
[●] PEAK PRE-CUTOVER 08h 11m → live [pause-switch]
[●] is the colored dot — green for off-peak, red for peak, amber
when the balance is below the configured threshold (overrides the
phase color)PRE-CUTOVER badge (only during the
pre-cutover window)→ live while pre-cutover, → next phase HH:MM
after the cutoverThe card expands under the pill:
Open Settings → Plugins → Plugin configuration → Peak hours and set
lowBalanceWarningUsd to your preferred floor (default 1.00). The
pill switches to amber the moment the live account balance drops below
the value. Override the same field directly in ~/.dsh/settings.yaml:
peak-hours:
paused: false
lowBalanceWarningUsd: 1.5
The next 2 s state poll picks up the new value automatically.
./uninstall.sh /path/to/deepseek-harness
The script removes the plugin directory and prints the four small
wire-up entries you need to delete by hand (one line each in
cordis.patch.yml, package.json, and the two tsconfig files).
No harness needed. Just a Node server that serves a static HTML page.
cd deepseek-peak
node serve.js
Opens http://127.0.0.1:3737/ in your default browser. Pin the tab.
Press Ctrl+C in the terminal to stop.
The standalone widget includes a 24-hour timeline of peak windows, a V4-Flash / V4-Pro model selector, and the actual $/1M-token rate for each tier. Useful on a screen that doesn't have the harness open. Pause / queue / balance features are NOT in the standalone widget — they live in the harness plugin only.
The harness pill is the right answer inside the harness. The standalone is the right answer everywhere else (a second monitor, a tablet, a phone browser). Both compute the same numbers from the same authoritative schedule, so they never disagree.
| Route | Method | Purpose |
|---|---|---|
/api/peak-hours/state |
GET |
Current pause / phase / queue / balance / threshold (2 s polled by the browser) |
/api/peak-hours/state |
POST |
Toggle the global pause (writes through the host's settings service) |
/api/peak-hours/balance |
GET |
Live DeepSeek account balance (5 min host cache) |
/api/peak-hours/balance?fresh=1 |
GET |
Force a fresh upstream fetch (bypasses both the host and the browser cache; the in-tooltip REFRESH button calls this) |
/api/peak-hours/usage?rangeDays=N |
GET |
Per-day, per-model token / cost buckets for the trailing N days (default 30, max 365; 5 min host cache) |
/api/peak-hours/usage?fresh=1&rangeDays=N |
GET |
Force a fresh host walk of the session persistence log |
/api/peak-hours/queue/dispatch |
POST |
Manually dispatch the front queued item (the per-row send arrow in the queue card calls this) |
The API key is held by the host's credentials seam and never reaches
the browser — the host routes read the key, fetch from
api.deepseek.com, and return the parsed JSON envelope.
The plugin passes every harness gate I could run on a Windows dev tree:
| Check | Result |
|---|---|
pnpm run constraints |
220/220 packages conform |
pnpm run verify-cordis-config |
120/120 config files passed |
pnpm run verify-package-invariants |
220/220 hand-owned companions conform |
tsc -b tsconfig.client.json |
clean |
pnpm --filter ... run bundle |
~78 kB client.js |
pnpm run build (host + client + web) |
clean |
Live runtime smoke (curl /plugins/.../client.js) |
200, ~78 kB, slot registered |
deepseek-peak/
├── README.md # this file
├── LICENSE # MIT
├── .gitignore
├── install.sh # one-line installer for the harness plugin
├── uninstall.sh # rollback helper
├── package.json # standalone-widget package
├── serve.js # standalone-widget Node server
├── smoke.js # standalone-widget self-test (5/5 passes)
├── widget.html # the standalone widget
├── docs/
│ └── pill-preview.png # the screenshot at the top of this README
└── harness-plugin/ # the in-harness plugin (copied to a harness
# clone by install.sh)
├── package.json
├── tsconfig.json
├── tsdown.config.ts
├── README.md
└── src/
├── index.ts # host face — routes, settings,
│ # LLM gate, 1 Hz phase ticker
├── invariant.ts
├── css-modules.d.ts
└── client/
├── index.ts # browser apply() — registers the pill
├── domain.ts # pure peak/off-peak math, schedule,
│ # pre-cutover computation
├── phase.ts # phase types, currentPhase(), labels
├── peakHoursState.ts # state hook — 2 s poll, paused toggle
├── balance.ts # balance fetch + 5 min cache, REFRESH support
├── usage.ts # host usage fetch with host-side fallback
├── pricing.ts # model display names
├── PeakHoursPill.tsx # the always-visible React component
├── PeakHoursPill.module.css
├── PeakHoursHost.tsx # hover-state host; renders the tooltip + queue
├── PeakHoursHost.module.css
├── UsageTooltip.tsx # the tooltip card (balance + chart + queue)
├── UsageTooltip.module.css
├── QueueCard.tsx # per-row dispatch card
├── QueueCard.module.css
├── PauseSwitch.tsx # the pill's right-edge toggle
├── PauseSwitch.module.css
├── PeakHoursDock.tsx # legacy input.dock variant, kept for
│ # reference; the current pill lives
│ # in the session header instead
└── PeakHoursDock.module.css
src/client/domain.ts. If DeepSeek changes the windows or the
cutover date, edit the constants there and re-bundle.worldtimeapi.org.paused field in the
Plugin configuration page are two write paths into the same
persisted setting. The 2 s state poll reconciles whichever wrote
last.?fresh=1 (so the host bypasses its own 5 min cache and re-fetches
from api.deepseek.com). Both must be running the latest code for
REFRESH to work end-to-end; the host change requires a dsh web
restart.MIT. See LICENSE.
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。