@gehennawu/dsh-service 2.0.8 → 2.0.9
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/README.en.md +80 -113
- package/README.md +80 -113
- package/client.js +1 -1
- package/index.js +53 -2
- package/model-config-routes.js +8 -0
- package/package.json +2 -2
- package/quota-adapters.js +55 -0
- package/screenshots/README.md +4 -3
- package/screenshots/configuration.png +0 -0
- package/screenshots/configuration_en.png +0 -0
- package/screenshots/health-diagnostics.png +0 -0
- package/screenshots/health-diagnostics_en.png +0 -0
- package/screenshots/model-configuration.png +0 -0
- package/screenshots/model-configuration_en.png +0 -0
- package/screenshots/overview.png +0 -0
- package/screenshots/overview_en.png +0 -0
- package/subagent-routes.js +59 -1
package/README.en.md
CHANGED
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
<em>DeepSeek Harness (DSH) Web 服务控制与运维插件。</em>
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
|
-
[](package.json)
|
|
13
13
|
[](LICENSE)
|
|
14
|
-
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
15
15
|
[](https://cordis.moe/)
|
|
16
16
|
[](https://github.com/gehennawu/dsh-service)
|
|
17
17
|
[](https://github.com/gehennawu/dsh-service/issues)
|
|
@@ -57,8 +57,8 @@ Under **Plugins → Plugin configuration**, thirteen host-level switches: **Heal
|
|
|
57
57
|
|
|
58
58
|
### Overview
|
|
59
59
|
|
|
60
|
-
-
|
|
61
|
-
-
|
|
60
|
+
- View service status, actionable issues, DSH / plugin versions, runtime and recent errors.
|
|
61
|
+
- Health, backup, statistics and quota failures surface as alerts; available updates and missing backups are informational.
|
|
62
62
|
|
|
63
63
|
### Maintenance and Configuration pages
|
|
64
64
|
|
|
@@ -66,15 +66,15 @@ Under **Plugins → Plugin configuration**, thirteen host-level switches: **Heal
|
|
|
66
66
|
|
|
67
67
|

|
|
68
68
|
|
|
69
|
-
- Maintenance groups Sessions, Skills, Backups
|
|
70
|
-
- Configuration groups feature switches,
|
|
71
|
-
-
|
|
69
|
+
- Maintenance groups Sessions, Skills, Backups and Restart, remembering the latest subpage.
|
|
70
|
+
- Configuration groups feature switches, notifications and settings-navigation tabs, with drag / arrow ordering and visibility controls. Service Control always remains visible.
|
|
71
|
+
- Navigation and quota-card preferences sync across devices through `$DSH_HOME/dsh-service-config.json`; feature sections do not affect one another.
|
|
72
72
|
|
|
73
73
|
### Version and updates
|
|
74
74
|
|
|
75
75
|
- Shows the current DSH and plugin versions, linking to GitHub Releases
|
|
76
76
|
- Automatically checks npm **stable + preview** (latest / next dist-tags)
|
|
77
|
-
- "What's new"
|
|
77
|
+
- "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.
|
|
78
78
|
- One-click upgrade with automatic restart; when no process manager is detected, it confirms the consequences first, keeps running, and shows manual-restart instructions
|
|
79
79
|
- 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
|
|
80
80
|
|
|
@@ -92,28 +92,25 @@ Under **Plugins → Plugin configuration**, thirteen host-level switches: **Heal
|
|
|
92
92
|
|
|
93
93
|

|
|
94
94
|
|
|
95
|
-
-
|
|
96
|
-
-
|
|
97
|
-
- **Usage index
|
|
98
|
-
- **Notification permission
|
|
99
|
-
- **Plugin health checks
|
|
100
|
-
-
|
|
101
|
-
- Suspected manual
|
|
95
|
+
- View uptime, memory, sessions, active agents, background jobs, platform, architecture and Node version.
|
|
96
|
+
- Check session storage, workspace registry, backups, tar, file permissions, runtime and the usage index.
|
|
97
|
+
- **Usage index** reports indexed / failed sessions and update time. Partial failures do not block other sessions; disabling model statistics omits this check.
|
|
98
|
+
- **Notification permission** reports blocked or missing browser permission with recovery guidance; it does not affect overview status and is omitted when notifications are disabled.
|
|
99
|
+
- **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.
|
|
100
|
+
- Permissions & repair provides deep scans and two-step permission repairs.
|
|
101
|
+
- Suspected manual launches warn of no restart assurance; missing backups are informational.
|
|
102
102
|
|
|
103
103
|
### Model statistics
|
|
104
104
|
|
|
105
105
|

|
|
106
106
|
|
|
107
|
-
-
|
|
108
|
-
- Per-model
|
|
109
|
-
- A **daily usage heatmap
|
|
110
|
-
-
|
|
111
|
-
-
|
|
112
|
-
-
|
|
113
|
-
-
|
|
114
|
-
- **Opening the panel syncs automatically — no manual refresh needed**: the mount sync always runs once (it renders the persisted cache first, then folds the delta in the background); after that it only syncs on **real edges** — crossing local midnight (the "Today" card lands on the new day), returning from a background tab, and each time you enter the usage page. Idling on the page arms no polling at all, and other pages pay none of that cost. The refresh button reads "Refreshing…" during a sync (about 0.3 s when idle, but tens of seconds when historical-format sessions exist and the corpus is changing)
|
|
115
|
-
- Steps whose provider reports no token usage are excluded
|
|
116
|
-
- A session that cannot be read, migrated, or parsed no longer blocks other sessions. An all-projects warning shows successful/skipped counts and expandable session IDs, error categories, and safe summaries. Previously indexed data is retained and marked stale; first-time failures contribute nothing and are retried on the next refresh. Only global errors, such as an unavailable service, failed session listing, or failed index write, fail the entire refresh. The warning can be dismissed (remembered locally), and silencing it mutes only that same failure set: a newly skipped session or a changed error category brings it back, so dismissing once never hides a new problem for good
|
|
107
|
+
- Seven-day input / output / cache token trends, filtered by project. Hover for totals, successful model steps and cache hit rates.
|
|
108
|
+
- Per-model breakdowns switch between Today, Last 7 days and All time.
|
|
109
|
+
- A **daily usage heatmap** covers up to 20 weeks, with a weekday × hour view; both follow the project filter.
|
|
110
|
+
- **Indexed history is permanent**: deleting sessions or projects never subtracts usage. Deleted projects leave the filter but remain in overall totals.
|
|
111
|
+
- View model / tool errors from the last 48 hours; omitted when empty.
|
|
112
|
+
- Sync automatically on panel opening, page entry, local midnight and return to the foreground, or refresh manually. No idle polling.
|
|
113
|
+
- 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.
|
|
117
114
|
|
|
118
115
|
### Quota lookup
|
|
119
116
|
|
|
@@ -131,6 +128,9 @@ Under **Plugins → Plugin configuration**, thirteen host-level switches: **Heal
|
|
|
131
128
|
| OpenCode Go | `{baseURL}/usage` (built-in channel without an explicit baseURL uses the registry default `https://opencode.ai/zen/go/v1`) |
|
|
132
129
|
| OpenRouter | Credits used % |
|
|
133
130
|
| Kimi / SiliconFlow | CNY balance |
|
|
131
|
+
| Vercel AI Gateway | Official `GET /v1/credits` for the team's remaining USD balance (Gateway API key; lifetime spend is not a quota limit) |
|
|
132
|
+
| Poe | API-key query for remaining points (non-monetary; no currency gauge) |
|
|
133
|
+
| ClinePass | API-key query for 5-hour / weekly / monthly plan usage and reset times |
|
|
134
134
|
| StepFun Balance | Official `GET /v1/accounts` (API key, com/ai dual domains) |
|
|
135
135
|
| StepFun Step Plan | Console BFF subscription quota (Oasis-Token console session; 5-hour/weekly windows vs Credit pool auto-detected) |
|
|
136
136
|
| Xiaomi MiMo Token Plan | Console-origin plan quota (web session cookie) |
|
|
@@ -149,7 +149,6 @@ Under **Plugins → Plugin configuration**, thirteen host-level switches: **Heal
|
|
|
149
149
|
|
|
150
150
|

|
|
151
151
|
|
|
152
|
-
- Backup records use light two-line rows (name on the first line, size · time on the second, separator layout; same style as the session list)
|
|
153
152
|
|
|
154
153
|
- 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)
|
|
155
154
|
- **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
|
|
@@ -165,64 +164,46 @@ Under **Plugins → Plugin configuration**, thirteen host-level switches: **Heal
|
|
|
165
164
|

|
|
166
165
|
|
|
167
166
|
- Lists local skills in three sections — **auto-loaded / manual-only / fully disabled**; same-name shadowing marks both copies, bundled directories are read-only
|
|
168
|
-
- Entries start collapsed into one row (name plus source / read-only / annotated badges); the top button expands or collapses every visible entry at once, and clicking an entry's name row toggles that entry alone; an invalid entry keeps its ⚠ and one-click fix visible while collapsed
|
|
169
167
|
- Two switches edit the SKILL.md frontmatter directly (`disable-model-invocation` / `user-invocable`); changes go live within ~200 ms
|
|
170
168
|
- Entries with legacy camelCase keys are dropped by the official parser: ⚠ warning + one-click canonical fix
|
|
171
169
|
- ✨ Fill with AI: pick a model to draft a description (follows the UI language), saved to a plugin sidecar index — **SKILL.md is never modified**; one-click batch fill runs in the host background and can be cancelled. Already-annotated skills are listed separately in the plan and are only overwritten after a "Confirm forced refill" second confirmation (annotating no longer blocks future batch fills forever); completion-log timestamps use your local timezone
|
|
172
170
|
|
|
173
171
|
### Model configuration
|
|
174
172
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
-
|
|
178
|
-
- **
|
|
179
|
-
- **
|
|
180
|
-
- **
|
|
181
|
-
- **
|
|
182
|
-
- **
|
|
183
|
-
- **
|
|
184
|
-
- **
|
|
185
|
-
- **
|
|
186
|
-
- **
|
|
187
|
-
- **
|
|
188
|
-
- **
|
|
189
|
-
- **
|
|
190
|
-
- **Deletion keeps the credential and is restorable**: deleting a channel removes only the route from settings and keeps the credential reference (other channels sharing it are unaffected). The full pre-deletion configuration goes into a snapshot first, and the **restore entry stays at the bottom of the list** instead of disappearing with the row. Restore writes the reference back but **never the old key value**
|
|
191
|
-
- **Configuration is not a call-time selection**: effort checkboxes declare selectable levels, not the level selected for every call. Unconfigured levels inherit existing values or leave behavior to the API default; they do not automatically disable reasoning. Smart fill retains mappings explicitly declared by metadata. Manually checking a non-off level currently uses its English name as the wire value, whose suitability must be checked. Saving requires at least one non-off mapping
|
|
192
|
-
- **Drafts stay on the page**: a failed save or a concurrent conflict never clears the draft, and a conflict asks you to re-confirm against the latest values; leaving with unsaved edits warns first; drafts are never persisted across refreshes (so keys never reach browser storage)
|
|
193
|
-
- **Built-in and custom catalogs are handled separately**: built-in providers show the resolved protocol and allow adding out-of-catalog models or editing current Profile model entries. Catalog defaults are displayed as inherited values rather than copied wholesale when unchanged. Unknown overrides and advanced fields are retained; the entire dynamic catalog is not frozen
|
|
194
|
-
- **Zero external network on the overview**: reads the current Profile, pi-ai catalog, runtime providers and sidecar, with saved / loaded / basic-call status shown separately. Opening the provider list does not query external metadata
|
|
195
|
-
- **Per-model smart fill**: OFF whenever the detail opens. ON queries the local pi-ai index and fixed modelparams.dev / OpenRouter sources, **never provider discovery, inference or automatic save**. **This round is model-ID-scoped filling: it binds no current-provider or protocol source**, and the UI has no source picker or binding action (candidates are evidence only and are never written into configuration)
|
|
196
|
-
- **Suggestions shown per parameter**: display name, context capacity, maximum output, input modalities and reasoning levels are shown separately. Modalities are compared as sets, so ordering is not a difference. Suggestions use a stable source order; reasoning prefers explicitly declared mappings without filtering by the current provider, and missing mappings never fabricate levels. modelparams request ranges are not model output limits. Metadata is reference information, not a real API capability test
|
|
197
|
-
- **One confirmation to fill**: "Fill all" first lists which draft fields it will replace; confirming **only updates the draft**, writes no configuration and still requires Save. There is no source binding or per-field ✓ / ✕. Hovering the switch explains the sources and operation boundaries
|
|
198
|
-
- **The two reasoning notices are distinct**: when the model metadata declares reasoning support but no concrete level suggestions were found, the panel says reasoning is supported yet the level values are unavailable and the API default is unknown; when there is no reasoning metadata at all it says no reasoning level suggestions were found and to configure them manually. **Absent metadata is not "unsupported"**; only `reasoningEfforts: false` declares that explicitly
|
|
199
|
-
- **Effort badges use English level names**: current and suggested levels render as `minimal / low / medium / high / xhigh / max` badges regardless of the UI language (the `models.smart.effort.*` Chinese dictionary is retained but not used here); the "Current levels / Suggested levels" labels themselves still follow the UI language
|
|
200
|
-
- **Snapshot before mutation**: ordinary save is one click; delete / credential replacement / restore preview consequences before confirmation. Snapshot failure prevents configuration writes. Creation, edits and restore capture owner / full fingerprint / revision and reject concurrent overwrite; subsequent external edits block undo. Ordinary snapshots exclude sensitive headers; deletion is refused if sensitive values cannot be restored in full safely
|
|
201
|
-
- **Online verification**: looks a model up in the OpenRouter model directory by id (fixed domain, redirects not followed); results are shown for reference only and never change your config
|
|
173
|
+

|
|
174
|
+
|
|
175
|
+
- Model configuration contains **Providers & models** and **Subagent routing**, separating built-in and custom providers.
|
|
176
|
+
- **Add custom providers** with an ID, display name, protocol, address, API key and model IDs. Creation never probes the endpoint automatically.
|
|
177
|
+
- **Mixed-protocol notice**: when a catalog mixes protocols (such as pi-ai's `azure` since 0.2.1-alpha.3), the template picker and provider editor explain that a route-level protocol overrides every model on the route, preventing Chat Completions models from being pinned to the Responses protocol.
|
|
178
|
+
- **Provider editing** covers display name, address and credentials. Custom protocols are editable; built-in protocols are read-only. Unshown headers, timeouts, cache settings and advanced parameters remain unchanged.
|
|
179
|
+
- **Model discovery** supports manual IDs or explicit Fetch online, with search and batch selection for OpenAI-compatible and Anthropic model lists. Discovery failure never blocks manual entry; a returned list does not prove calls work.
|
|
180
|
+
- **Model editing** covers ID, display name, context window, max output, image input and reasoning levels. Capacity accepts `256K` / `1M`; blank inherits catalog defaults. IDs must be unique per provider, and disabled models must be enabled before renaming.
|
|
181
|
+
- **Immediate toggles** block new main-chat and subagent calls while retaining configuration and keys; running calls are not cancelled. Unloading the plugin removes this policy.
|
|
182
|
+
- **Basic call tests may incur charges**. They send short text through saved models and report elapsed time and sanitized errors; they do not verify images, capacity or every reasoning level, and failures never roll back configuration.
|
|
183
|
+
- **Smart fill starts disabled**. It queries local pi-ai, modelparams.dev and OpenRouter metadata by model ID, without provider discovery, inference or automatic saving. Suggestions are per parameter; confirming Fill all changes only the draft and still requires Save.
|
|
184
|
+
- **Check reasoning levels against the API**: selectable levels differ from the effort selected for a call. Missing metadata does not mean unsupported; unconfigured values inherit or use API defaults. Manually supplied mappings require verification.
|
|
185
|
+
- **Deletion checks references** to the main-chat default, subagent primary and fallback models, blocking deletion when referenced. A custom provider cannot lose its final model.
|
|
186
|
+
- **Restore and credentials**: provider deletion snapshots configuration and keeps credential references. Restore recovers configuration, never old key values. Replacement defaults to an independent reference; shared replacement first lists users.
|
|
187
|
+
- **Draft and concurrency protection**: failed saves retain drafts, leaving unsaved edits warns, and external changes prevent overwrite until reviewed again. Drafts do not persist across reloads.
|
|
202
188
|
|
|
203
189
|
#### URL and credential safety
|
|
204
190
|
|
|
205
|
-
-
|
|
206
|
-
-
|
|
207
|
-
-
|
|
208
|
-
- **Short-lived host handles**: editing baselines, deletion, restore and credential consequences bind to `sessionId` / `planId`; submission re-checks the complete baseline and revision. Unknown, expired or replayed handles are rejected. Manual parameters pass a closed schema vocabulary
|
|
209
|
-
- **Structural write protection**: writes use `settings.mutate(entryId, ops, expectedRevision)` with the current pi-ai owner's dynamically resolved entry ID; only legacy hosts use `llm-pi-ai`. Complete official validation, atomic persistence and live reconciliation are retained; no direct writes to real configuration YAML
|
|
210
|
-
- **Loopback only**: every endpoint is exposed through the single-segment `/dsh-service` channel with `loopback` authority
|
|
191
|
+
- Hosts without trackable configuration revisions remain view-only and refuse writes; configuration changes retain official DSH validation and atomic saving.
|
|
192
|
+
- Entering or saving an address never fetches it. Discovery uses the saved current-Profile address and requires public HTTPS on port 443, rejecting private addresses, IP literals and redirects, with timeout / size limits. Local or HTTP providers can still be saved with manual IDs.
|
|
193
|
+
- Keys pass over loopback into the DSH credential store, never echoed, logged or snapshotted. They go only to the corresponding provider, never metadata sites.
|
|
211
194
|
|
|
212
195
|
### Subagent model
|
|
213
196
|
|
|
214
197
|

|
|
215
198
|
|
|
216
|
-
- Three modes: **Default** (no override)
|
|
217
|
-
-
|
|
218
|
-
- Custom
|
|
219
|
-
-
|
|
220
|
-
- **
|
|
221
|
-
- **
|
|
222
|
-
-
|
|
223
|
-
-
|
|
224
|
-
- **Conversation-page visibility** — a session-level line sits under the composer listing the models your subagents actually ran on, e.g. `Subagents: cpa/gpt-5.6-luna (xhigh) · opencode-go/deepseek-v4-flash (max)` — covering fallback hits, explicit routes, and inherited sources, so you can verify the custom route at a glance. The line is mounted on the official `conversation.composer.dock` slot, occupying its own line right below the official stats instead of sharing their row; 20s refresh, independent of turn data (it keeps showing even when compaction folds the delegation tool calls), covered from the host dispatch records and visible in any view; switch it off independently from Model configuration → Subagent routing. Records live in host memory (survive page reloads, cleared on process restart). Works regardless of the official "assign subagent models" switch
|
|
225
|
-
- Config stored in `$DSH_HOME/dsh-service-subagent-route.json` (atomic writes, `0600`); one-click reset
|
|
199
|
+
- Three modes: **Default** (no override), **Follow main model** (the latest model actually used by the main chat), and **Custom**. Entry: Model configuration → Subagent routing.
|
|
200
|
+
- Explicit provider/model values in a delegation always take priority.
|
|
201
|
+
- Custom models with declared reasoning levels offer an effort selection; blank uses the target default. Models without declarations explain that selection is unavailable.
|
|
202
|
+
- **Mode switching preserves configuration**: custom model, effort and fallback list remain saved when switching away and back.
|
|
203
|
+
- **Ordered fallbacks** in Follow and Custom modes handle unavailable channels or quota. If all routes are unavailable, use native inheritance.
|
|
204
|
+
- **Independent Agent preset** (0.2.1-alpha.3+ hosts): give every spawned subagent one independent preset (role and tools together); leave empty to follow the parent, explicit presets win, and only backends that support independent presets are affected.
|
|
205
|
+
- An optional composer line shows the models actually used by the session's subagents, including fallback and explicit routes. Records survive page reloads, not process restarts.
|
|
206
|
+
- Configuration lives at `$DSH_HOME/dsh-service-subagent-route.json`, with one-click reset.
|
|
226
207
|
|
|
227
208
|
### Task notifications
|
|
228
209
|
|
|
@@ -237,49 +218,36 @@ Under **Plugins → Plugin configuration**, thirteen host-level switches: **Heal
|
|
|
237
218
|
|
|
238
219
|

|
|
239
220
|
|
|
240
|
-
- Off by default;
|
|
241
|
-
-
|
|
242
|
-
-
|
|
243
|
-
-
|
|
244
|
-
-
|
|
245
|
-
-
|
|
246
|
-
- The Agent Team panel stays on screen on phones (<1024 px): the official panel is left-anchored (`left:0`), so sitting in the header's right-hand action slot pushes it off the right edge (measured 112–352 px past the viewport at 320–1023 px). On mobile the session header becomes the positioning context and the panel is re-anchored to the **right with a 16 px inset** and capped at `100vw − 32px`, leaving 16 px on each side; desktop ≥1024 px keeps the official geometry byte-for-byte
|
|
247
|
-
- Scroll immersion: inside a conversation, swiping down auto-hides the header, the top-left drawer icon, and composer for full-screen reading (the top-left drawer icon slides up and fades out in sync with the top-right sidebar button, and the composer yields its layout space so the transcript really fills the screen; on reveal, if you are still at the end of the conversation it re-aligns to the bottom). Swipe up, tapping the official "Back to bottom" button, or focusing the composer brings them back (no extra floating button); already sitting at the end of the conversation, a single small backward nudge reveals it right away (no full threshold needed), and after a back-to-bottom tap the resting position gets one extra bottom snap. Programmatic scrolling (streaming pinning, anchor jumps) never triggers it
|
|
248
|
-
- Swipeable drawers: with both drawers closed, a horizontally dominant swipe rightward anywhere opens the sidebar drawer and a swipe leftward anywhere opens the official right sidebar (DSH 0.1.5+; stays inert when unavailable); once open, a swipe in the reverse direction anywhere closes them. Swipes starting at the screen edge additionally benefit from stolen-gesture completion for browser edge navigation, and horizontal scrolling inside editors never misfires
|
|
249
|
-
- The "Back to bottom" button is shifted flush right on mobile (no more large empty strip); a matching circular up-arrow now sits above it on all platforms, jumping to the previous user message on each click for step-by-step back navigation. Targets outside the loaded history auto-trigger the official "load earlier" action; the button hides once you reach the very top and reappears when you scroll back down
|
|
250
|
-
- Transparent large-JSON compression (≥4KB auto gzip/brotli per `Accept-Encoding`) speeds up long session histories
|
|
251
|
-
- Adds `viewport-fit=cover` with safe-area avoidance, disables double-tap zoom, keeps inputs ≥16px against iOS focus zoom
|
|
252
|
-
- `?dshsvc-mobile-debug=1` shows a floating diagnostics chip (debugging only)
|
|
221
|
+
- Off by default; enabled behavior applies only below a 1024px viewport, leaving desktop unaffected.
|
|
222
|
+
- Supports sidebar drawers, narrow-screen settings navigation and full-screen panels, with model selection, task menus and Agent Team dialogs adapted for phones.
|
|
223
|
+
- **Scroll immersion** hides the header and composer when scrolling down; scroll up, go to bottom or focus the composer to restore them. Streaming updates never trigger it.
|
|
224
|
+
- **Drawer gestures**: swipe right to open the sidebar, left to open the right sidebar, and reverse to close. Editor horizontal scrolling is unaffected.
|
|
225
|
+
- An up-arrow jumps through previous user messages, automatically loading earlier history as needed.
|
|
226
|
+
- Large conversation JSON responses are compressed, with safe-area and mobile input zoom handling.
|
|
253
227
|
|
|
254
228
|
### Session manager
|
|
255
229
|
|
|
256
230
|

|
|
257
231
|
|
|
258
|
-
- **
|
|
259
|
-
- **
|
|
260
|
-
- **
|
|
261
|
-
- **
|
|
262
|
-
- **
|
|
263
|
-
- **
|
|
264
|
-
-
|
|
265
|
-
-
|
|
232
|
+
- **Browse** running, cold and archived sessions with workspace, event count and size. Sort by time / title or group by project; Archived is the default view.
|
|
233
|
+
- **Details** offer paged Markdown transcripts and collapsible system / tool events; returning preserves list scroll position.
|
|
234
|
+
- **Subagents** can be filtered or selected in bulk; plain forks are not misclassified as subagents.
|
|
235
|
+
- **Export** complete official ZIPs individually or in batches, including subagents and attachments.
|
|
236
|
+
- **Archive and unarchive** non-running sessions individually or in batches; unarchiving requires DSH ≥0.1.6, with older hosts remaining archive-only.
|
|
237
|
+
- **Content search** spans sessions with case-insensitive, whitespace-flexible matching; optionally restrict to archived sessions, jump into match context and navigate previous / next hits.
|
|
238
|
+
- **Delete**: Only archived sessions can be deleted. Running sessions are checked again and refused; two-step confirmation lists ID, title, workspace and size, then updates the official sidebar.
|
|
239
|
+
- **Deleted records** can be viewed and cleared individually or in bulk. They contain title / time only, no transcript, and cannot restore a session.
|
|
240
|
+
- Entry: Maintenance → Sessions; the optional settings-sidebar shortcut is off by default.
|
|
266
241
|
|
|
267
242
|
### Model provider icons
|
|
268
243
|
|
|
269
|
-
-
|
|
270
|
-
-
|
|
271
|
-
-
|
|
272
|
-
-
|
|
273
|
-
-
|
|
274
|
-
-
|
|
275
|
-
-
|
|
276
|
-
- **The model picker's group headings carry them too**: open the model button → the "Model" list, and each **provider/channel group heading gets the same mark in front of it** (13px, matching the 12px heading scale). Same resolution and fallback rules: unrecognised groups keep the official heading untouched, with no icon added
|
|
277
|
-
- **Legible in both light and dark themes**: a brand colour is kept only when its contrast is adequate against **both** a light and a dark background; otherwise the icon automatically switches to a monochrome variant that follows the theme's text colour — so you never get a black logo on a dark background, or a nearly invisible one in light mode
|
|
278
|
-
- **Zero runtime network requests**: icons are inlined into the client bundle at build time, so it works offline, needs no CSP exceptions, and never leaks your provider names to a third party
|
|
279
|
-
- The icon is sized to match the **quota ring** beside the composer (each mark's viewBox is tightened to its real drawn extent and squared at build time, so every brand reads at the same visual size instead of some filling the box and others shrinking)
|
|
280
|
-
- Toggle under Plugins → Plugin configuration → Interaction (on by default, applied live)
|
|
281
|
-
- Icons come from the MIT-licensed [LobeHub Icons](https://github.com/lobehub/lobe-icons) (pinned to `@1.95.0`); the Xiaomi icon uses the plain "mi" mark from CC0 [Simple Icons](https://github.com/simple-icons/simple-icons) (LobeHub's version is a two-line "Xiaomi / MIMO" wordmark that turns to mush at 15px). **Brand marks remain the property of their owners**, so review each vendor's brand guidelines before public-facing use
|
|
282
|
-
- **Every icon is browsable in one page**: [icon catalog](docs/model-icons.html) — 62 marks, 76 provider mappings, the matching rules, and a light/dark comparison; a single offline file, generated from the very data inlined into the client bundle
|
|
244
|
+
- Provider marks appear in model buttons, model lists and quota cards; unknown providers retain the official default icon.
|
|
245
|
+
- Covers common built-in pi-ai providers plus Ollama, vLLM, LM Studio, Perplexity, Cohere, Volcengine, Doubao, Hunyuan, StepFun, Cline and others.
|
|
246
|
+
- Custom names are recognized by prefixes / aliases such as `openrouter-f`, `zai-coding-cn`, `command-goat` and `cline-official`.
|
|
247
|
+
- Unknown names can use the adapter type **manually chosen** on the quota page. Name matches take priority; CLIProxyAPI icons require manual adaptation.
|
|
248
|
+
- Icons are bundled, work offline and never send provider names to third parties. Toggle under Plugin configuration → Interaction, on by default.
|
|
249
|
+
- Sources: [LobeHub Icons](https://github.com/lobehub/lobe-icons) (MIT) and [Simple Icons](https://github.com/simple-icons/simple-icons) (CC0). Brand marks belong to their owners.
|
|
250
|
+
- See the [icon catalog](docs/model-icons.html) for all marks and provider matching rules.
|
|
283
251
|
|
|
284
252
|
### Right-Sidebar file editing
|
|
285
253
|
|
|
@@ -349,7 +317,7 @@ Key contracts:
|
|
|
349
317
|
1. Open the **Plugins** page in the left sidebar.
|
|
350
318
|
2. Click the **+ Add plugin** button in the top-right corner.
|
|
351
319
|
3. In the dialog, fill in **one of the three** source forms (the same field accepts all three, and the hint below it follows what you type):
|
|
352
|
-
- **npm package name (recommended)**: `@gehennawu/dsh-service@2.0.
|
|
320
|
+
- **npm package name (recommended)**: `@gehennawu/dsh-service@2.0.9` — **include the exact version** (written as `package@version`);
|
|
353
321
|
- **GitHub repository URL**: `https://github.com/gehennawu/dsh-service` (public repository, no token needed; the shorthand `github:gehennawu/dsh-service` works too);
|
|
354
322
|
- **Local plugin directory**: an absolute path on this machine, e.g. `/path/to/dsh-service` (for your own or pre-downloaded plugins).
|
|
355
323
|
4. Pick the **install source** for your network: the default **official npm registry**, or the **China mainland mirror** if fetching from npm is restricted there (it affects package-name installs only; GitHub URLs and local directories are unaffected).
|
|
@@ -360,17 +328,17 @@ Key contracts:
|
|
|
360
328
|
|
|
361
329
|
> Tip: all three forms go through the official installation path — no manual profile edits; entering a GitHub URL in the dialog is equivalent to the `github:` prefix on the command line.
|
|
362
330
|
|
|
363
|
-
> **Why the npm form wants a version**: pnpm 11 enables a supply-chain release cooldown by default (`minimumReleaseAge`, 1440 minutes). **Without a version** (including `@latest`), a release published less than the cooldown period ago is not installed automatically, so the package manager falls back to the newest version that has cleared it — which is why the plugin page may report that it installed x.y.z instead of the latest a.b.c. Writing an **exact version** (e.g. `@gehennawu/dsh-service@2.0.
|
|
331
|
+
> **Why the npm form wants a version**: pnpm 11 enables a supply-chain release cooldown by default (`minimumReleaseAge`, 1440 minutes). **Without a version** (including `@latest`), a release published less than the cooldown period ago is not installed automatically, so the package manager falls back to the newest version that has cleared it — which is why the plugin page may report that it installed x.y.z instead of the latest a.b.c. Writing an **exact version** (e.g. `@gehennawu/dsh-service@2.0.9`) installs exactly the release you name. The cooldown is a supply-chain safety policy, not a sign that the new release is broken; if you are not in a hurry, installing without a version after the 24 hours have passed also reaches the new release.
|
|
364
332
|
|
|
365
333
|
### Option 2: Command line
|
|
366
334
|
|
|
367
335
|
| Method | Command |
|
|
368
336
|
| --- | --- |
|
|
369
|
-
| npm (recommended) | `dsh plugin --profile web add @gehennawu/dsh-service@2.0.
|
|
337
|
+
| npm (recommended) | `dsh plugin --profile web add @gehennawu/dsh-service@2.0.9` |
|
|
370
338
|
| GitHub | `dsh plugin --profile web add github:gehennawu/dsh-service` |
|
|
371
339
|
| Local development | `dsh plugin --profile web add link:/path/to/dsh-service` |
|
|
372
340
|
|
|
373
|
-
The command line uses the default npm / pnpm registry; if you need a mirror, point npm / pnpm's registry at one the usual way first, then run the command above. The npm method is subject to the same pnpm release cooldown: without a version it installs the newest release that has cleared the cooldown, while an exact version (`@gehennawu/dsh-service@2.0.
|
|
341
|
+
The command line uses the default npm / pnpm registry; if you need a mirror, point npm / pnpm's registry at one the usual way first, then run the command above. The npm method is subject to the same pnpm release cooldown: without a version it installs the newest release that has cleared the cooldown, while an exact version (`@gehennawu/dsh-service@2.0.9`) installs that release (see the note under Option 1).
|
|
374
342
|
|
|
375
343
|
Restart DSH Web after installing or updating:
|
|
376
344
|
|
|
@@ -422,11 +390,10 @@ pm2 start "dsh web --host 127.0.0.1" --name dsh-web
|
|
|
422
390
|
|
|
423
391
|
Requirements: Node.js `>=22`, and a DSH Web installation capable of loading both Host and Client plugin halves. Update checks require access to `registry.npmjs.org`; network failures do not affect other features.
|
|
424
392
|
|
|
425
|
-
**DSH compatibility
|
|
393
|
+
**DSH compatibility**: `>=0.1.1-rc.2 <0.2.1-alpha.4`, adapted through `0.2.1-alpha.3`. Older DSH cannot read newer session formats; **backups cannot be restored across a downgrade**.
|
|
426
394
|
|
|
427
|
-
**DSH 0.2.1-alpha.2 compatibility update**: the supported range now includes `0.2.1-alpha.2` (`engines.dsh`: `>=0.1.1-rc.2 <0.2.1-alpha.3`). Subagent startup supports both the new `startActivation(spec)` and older `start` / `startContinuable` methods. Mobile task-chip CSS handles the removal of `.QsffPG_root` and the switch to a body-portaled task menu. On the current alpha.2 Web host, the plugin RPC, `available:true` subagent seam, real `subagent` and `subagent_fork` executions and their routed dispatch records were verified; legacy and new API tests pass. With an actual background task on alpha.2, the mobile chip geometry was checked at 320/360/390/560px, its in-flow fallback at 561px, and the portaled menu was opened twice at 390px without crossing the viewport. At 320px the task-count text is fully elided, but the icons and complete `aria-label` remain. **A real older-host UI comparison and other tab counts remain unverified.**
|
|
428
395
|
|
|
429
|
-
**DSH Desktop
|
|
396
|
+
**DSH Desktop**: restart and post-restore restart require quitting and reopening the app; upgrade through its own plugin manager. Notifications require system permission, and clicking one may not restore a hidden window—use the tray. Other platforms are best-effort, without compatibility guarantees.
|
|
430
397
|
|
|
431
398
|
## 🔒 Security design
|
|
432
399
|
|
|
@@ -516,7 +483,7 @@ Concurrency protection kicked in: SKILL.md was just modified by an external edit
|
|
|
516
483
|
<details>
|
|
517
484
|
<summary><strong>The plugin page installed the plugin, but the version is an older one?</strong></summary>
|
|
518
485
|
|
|
519
|
-
pnpm 11 enables a supply-chain release cooldown by default (`minimumReleaseAge`, 1440 minutes): **installing without a version** (including `@latest`) only selects the newest release that has already cleared the cooldown, so a freshly published release is skipped and the official plugin page reports that it installed x.y.z instead of the latest a.b.c. To get the new version right away: uninstall it in the plugin page and reinstall with `package@version` (e.g. `@gehennawu/dsh-service@2.0.
|
|
486
|
+
pnpm 11 enables a supply-chain release cooldown by default (`minimumReleaseAge`, 1440 minutes): **installing without a version** (including `@latest`) only selects the newest release that has already cleared the cooldown, so a freshly published release is skipped and the official plugin page reports that it installed x.y.z instead of the latest a.b.c. To get the new version right away: uninstall it in the plugin page and reinstall with `package@version` (e.g. `@gehennawu/dsh-service@2.0.9`), or use this plugin's **Service Control → Upgrade** — it installs an exact version and is not subject to the cooldown. The cooldown is a supply-chain policy (a fresh release may contain defects that are not known yet); after the 24 hours have passed, installing without a version also reaches the new release.
|
|
520
487
|
</details>
|
|
521
488
|
|
|
522
489
|
<details>
|