[中文](./README.md)
# 🛠️ dsh-service
A service-control & operations plugin for DeepSeek Harness (DSH) Web.
DeepSeek Harness (DSH) Web 服务控制与运维插件。
[](package.json)
[](LICENSE)
[](https://github.com/deepseek-ai/deepseek-harness)
[](https://cordis.moe/)
[](https://github.com/gehennawu/dsh-service)
[](https://github.com/gehennawu/dsh-service/issues)
[](https://awesome-dsh-plugin.com)
Features •
Architecture •
Installation •
Automatic restart •
Platform support •
Security design •
FAQ •
Contributing •
License
---
A service-control and operations plugin for DSH Web: safe restart, version management and one-click upgrade, health diagnostics, model-usage statistics, quota lookup, backup management, task notifications, skills management, session management, and Linux file-permission maintenance.

## 📑 Contents
- [🚀 Features](#-features)
- [Version and updates](#version-and-updates) · [Safe restart](#safe-restart) · [Health diagnostics](#health-diagnostics) · [Model statistics](#model-statistics)
- [Quota lookup](#quota-lookup) · [Model configuration](#model-configuration) · [Backup management](#backup-management) · [Skills management](#skills-management) · [Subagent model](#subagent-model)
- [Task notifications](#task-notifications) · [Session manager](#session-manager) · [Mobile adaptation](#mobile-adaptation) · [Sidebar settings entry](#sidebar-settings-entry) · [Model provider icons](#model-provider-icons) · [Right-Sidebar file editing](#right-sidebar-file-editing) · [External liveness probe](#external-liveness-probe)
- [🏗️ Architecture](#-architecture)
- [⚡ Installation](#-installation) · [🔄 Automatic restart](#-automatic-restart) · [🖥️ Platform support](#-platform-support)
- [🔒 Security design](#-security-design) · [❓ FAQ](#-faq) · [🤝 Contributing](#-contributing) · [📄 License](#-license)
## 🚀 Features
The Settings "Service Control" panel has a seven-page navigation: **Overview · Model stats · Quota lookup · Model configuration · Health · Maintenance · Configuration**; "Model configuration" contains Providers & models / Subagent routing, "Maintenance" aggregates four subpages — Sessions · Skills · Backups · Restart — and "Configuration" aggregates Features · Task notifications · Settings Nav. Restart, Quota lookup, and Sessions can each enable a **quick entry in the settings left navigation** (off by default; the Skills and Subagents sidebar entries were removed).
Under **Plugins → Plugin configuration**, thirteen host-level switches: **Health diagnostics, Model statistics, Quota lookup, Model configuration, Backup maintenance, Task notifications, Skill manager, Subagent model, Session manager, Mobile adaptation, Model provider icons, Right-Sidebar file editing, `/healthz` liveness endpoint** (all on by default except Mobile adaptation). All are live settings: disabling hides the UI, stops polling/subscriptions, and makes the host reject that capability; Overview and Restart stay available.

### Overview
- View service status, actionable issues, DSH / plugin versions, runtime and recent errors.
- Health, backup, statistics and quota failures surface as alerts; available updates and missing backups are informational.
### Maintenance and Configuration pages


- Maintenance groups Sessions, Skills, Backups and Restart, remembering the latest subpage.
- Configuration groups feature switches, notifications and settings-navigation tabs, with drag / arrow ordering and visibility controls. Service Control always remains visible.
- Navigation and quota-card preferences sync across devices through `$DSH_HOME/dsh-service-config.json`; feature sections do not affect one another.
### Version and updates
- Shows the current DSH and plugin versions, linking to GitHub Releases
- Automatically checks npm **stable + preview** (latest / next dist-tags)
- "What's new" opens release notes for the running version; an available-update link opens the new release notes in place. Press Escape to close.
- One-click upgrade with automatic restart; when no process manager is detected, it confirms the consequences first, keeps running, and shows manual-restart instructions
- Between the upgrade landing and the process restart (common in a manual-launch environment) the version row reads "Installed X — restart to take effect" and the upgrade button is withdrawn; reopening the panel or refreshing the page keeps that state until the process is restarted
### Safe restart

- Detects active agents, background jobs, and terminals before restart; lists them and requires explicit confirmation
- `/restart` also works in conversations; automatically refuses while work is running
- Probes the new process after restart and reloads the page; manual reload offered after 60 seconds. A restart triggered by `/restart` in a conversation reloads the same way: the page records the process identity at load time and compares `instanceId` on reconnect, reloading as soon as the new process is up
- Optional "Restart" entry in the settings left navigation (off by default), sharing the same confirmation flow as the "Maintenance → Restart" subpage
- A suspected manual terminal launch warns that nothing will bring the process back and gets a yellow caution in Health
### Health diagnostics

- View uptime, memory, sessions, active agents, background jobs, platform, architecture and Node version.
- Check session storage, workspace registry, backups, tar, file permissions, runtime and the usage index.
- **Usage index** reports indexed / failed sessions and update time. Partial failures do not block other sessions; disabling model statistics omits this check.
- **Notification permission** reports blocked or missing browser permission with recovery guidance; it does not affect overview status and is omitted when notifications are disabled.
- **Plugin health checks** list failures and missing dependencies; failed plugins can be reloaded after confirmation. Manually disabled plugins are not anomalies; disposed or unknown states are informational only.
- Permissions & repair provides deep scans and two-step permission repairs.
- Suspected manual launches warn of no restart assurance; missing backups are informational.
### Model statistics

- Seven-day input / output / cache token trends, filtered by project. Hover for totals, successful model steps and cache hit rates.
- Per-model breakdowns switch between Today, Last 7 days and All time.
- A **daily usage heatmap** covers up to 20 weeks, with a weekday × hour view; both follow the project filter.
- **Indexed history is permanent**: deleting sessions or projects never subtracts usage. Deleted projects leave the filter but remain in overall totals.
- View model / tool errors from the last 48 hours; omitted when empty.
- Sync automatically on panel opening, page entry, local midnight and return to the foreground, or refresh manually. No idle polling.
- Steps without provider-reported tokens are excluded. Unreadable sessions retain stale cached data and are retried while other sessions continue; expand failure details, with new failures bringing the notice back.
### Quota lookup

- Provider cards keep the existing window presentation (label + percent / independent bar / reset countdown); **configuration** (credentials, kind switching, manual reset entries) is collapsed per card by default
- Card **order and visibility**: "Reorder & visibility" on the quota page expands a management list where cards can be dragged or nudged with ↑/↓, and a toggle hides cards you rarely need (hiding only affects display, not querying); the config shares one backend with the Settings Nav tabs, stored in the `quotaCards` section of the unified server-side config `$DSH_HOME/dsh-service-config.json` (cross-device sync with a local-cache fallback, sections never affect each other)
- A **quota ring** in the conversation composer follows the current session's model provider and shows the tightest budget window (<80% green, ≥80% amber); clicking opens a detail panel that becomes a centered overlay on narrow screens
- Built-in adaptations:
| Provider | Data source |
| --- | --- |
| DeepSeek Platform | Official balance + peak/off-peak ribbon and countdown (peak = Mon–Fri 09:00–12:00 and 14:00–18:00 UTC+8, **excluding Chinese public holidays**; weekends and public holidays are off-peak all day) |
| Zhipu GLM Coding Plan | Official endpoint: 5-hour rolling / weekly / monthly MCP windows + peak/off-peak ribbon and countdown (peak = Mon–Fri 14:00–18:00 UTC+8) |
| OpenCode Go | `{baseURL}/usage` (built-in channel without an explicit baseURL uses the registry default `https://opencode.ai/zen/go/v1`) |
| OpenRouter | Credits used % |
| Kimi / SiliconFlow | CNY balance |
| Vercel AI Gateway | Official `GET /v1/credits` for the team's remaining USD balance (Gateway API key; lifetime spend is not a quota limit) |
| Poe | API-key query for remaining points (non-monetary; no currency gauge) |
| ClinePass | API-key query for 5-hour / weekly / monthly plan usage and reset times |
| StepFun Balance | Official `GET /v1/accounts` (API key, com/ai dual domains) |
| StepFun Step Plan | Console BFF subscription quota (Oasis-Token console session; 5-hour/weekly windows vs Credit pool auto-detected) |
| Xiaomi MiMo Token Plan | Console-origin plan quota (web session cookie) |
| Command Code (command-goat) | Official account quota plane `api.commandcode.ai/alpha/*` (same key reused: balance + period spend + plan + 5-hour/weekly windows) |
| CLIProxyAPI deployment | Official remaining quota of each OAuth upstream account |
- Credentials go into the DSH credential store (`$DSH_HOME/.credentials.yaml`, hot-effective): an API key, the CPA management key, the Xiaomi console cookie, or the StepFun Step Plan console token (Oasis-Token; the `Oasis-Webid` is derived from the token automatically — no manual entry); the Command Code quota plane reuses the inference key, so no extra credential is needed
- **Credentials can be changed at any time**: every adapted card keeps a credential entry in its **Config** area — unconfigured rows show the per-channel wording, configured rows show "Edit credential (configured)", where the stored value can be overwritten (key rotation, another account, a typo) or cleared; the value is only ever sent with the save request and is never echoed back
- Anti-rate-limit pacing: 60 s result cache, exponential backoff for transient network errors (30 s doubling, capped at 15 min); **deterministic failures switch to manual** — credential errors, 4xx, expired plans, management API disabled, unexpected response shapes and anything else only a config change can fix stop the automatic retries (the error line then reads "Auto-retry paused — retry manually"), and only a successful manual reconnect via the refresh button (5 s cooldown) returns the channel to automatic mode; querying is fully manual — a snapshot is fetched when you open the quota page, expand the ring, or hit refresh, and the client never arms a periodic poll (upstream throttling still lives entirely in the host)
- **CLIProxyAPI management-plane bans get their own notice**: five consecutive auth failures from one IP ban that IP for 30 minutes on the management plane; while banned the card reads "Temporarily banned by CLIProxyAPI" plus the upstream message (including the remaining time). That state offers no credential form (the key is fine) — wait for the ban to expire, or change the host's egress IP, then hit "Retry connection". The ban covers the management plane only; model inference through that CPA is unaffected
- CLIProxyAPI: when an account's live query fails, its last cached snapshot windows are shown with a "cached" badge; snapshot windows whose reset time has already passed (the window they described has ended) are dropped, avoiding the illusion of quota stuck on yesterday
- Failures state their real reason: cards and the ring show "error copy (HTTP status · failing endpoint · failing account · upstream message) · next automatic retry" — a wrong key, an unpaid balance, rate limiting, and a moved endpoint each read differently instead of one generic notice; an upstream 401/403 is classified as "credential rejected by upstream" and the card keeps its credential form available, and business error codes inside an HTTP 200 envelope are classified the same way (auth failure → credential rejected, expired plan → no active subscription, vendor-side failure → upstream service error) instead of being reported as "unexpected response format"; rows switched to manual mode end with "Auto-retry paused — retry manually" instead of a retry time
- API keys are resolved only inside the host process; the browser receives normalized window data only; unadapted providers are never requested
### Backup management

- Creates `.tar.gz` archives of sessions, configuration, and plugin-profile manifests; sessions are snapshotted through the persistence layer's stable-read seam (active-agent writes no longer fail creation), and creation shows one continuous phase progress bar (copy / pack / verify / publish, step counter 1/4–4/4, real percentage during copy)
- **DSH version at backup time**: the archive filename carries the DSH version running when the backup was taken (`dsh-backup-YYYYMMDD-HHmmss-dsh0.1.7-rc.1.tar.gz`), and `meta/backup.json` inside the archive records the DSH version, plugin version, and creation time; both the panel row and the restore preflight show it, so you can tell which version a snapshot came from (restoring across a downgrade cannot read newer session formats). Archives written by older plugin versions have no version segment: they still list and restore normally, they simply show no version line, and import accepts filenames both with and without the segment
- Export download / import upload / delete (two-step confirmation); unlimited, never auto-pruned; imported archives must pass the same integrity inspection used by restore
- **Integrity inspection** validates gzip/tar structure, paths, and entry types. Only `sessions`, the three allowlisted config files, `profiles/