dsh-subagent-workspace-ui 1.9.0 → 1.9.1
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.md +106 -87
- package/README.zh.md +103 -222
- package/cordis.patch.yml +11 -6
- package/lib/client.js +7 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,28 +1,91 @@
|
|
|
1
1
|
# DSH Subagent Workspace UI
|
|
2
2
|
|
|
3
|
+
**English** | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
<p align="center"> <img src="https://raw.githubusercontent.com/miuzel/dsh-subagent-ui/main/docs/banner.png" alt="DSH Subagent Workspace UI —— a subagent manager panel with a live floating panel" width="100%"> </p>
|
|
6
|
+
<p align="center"> <a href="https://www.npmjs.com/package/dsh-subagent-workspace-ui"><img src="https://img.shields.io/npm/v/dsh-subagent-workspace-ui?style=flat-square&label=npm&color=cb3837" alt="npm version"></a> <a href="https://www.npmjs.com/package/dsh-subagent-workspace-ui"><img src="https://img.shields.io/npm/dm/dsh-subagent-workspace-ui?style=flat-square&label=downloads&color=cb3837" alt="npm downloads"></a> <a href="LICENSE"><img src="https://img.shields.io/npm/l/dsh-subagent-workspace-ui?style=flat-square&label=license&color=green" alt="license"></a> <a href="https://awesome-dsh-plugin.com"><img src="https://img.shields.io/badge/awesome--dsh--plugin-listed-2f6feb?style=flat-square" alt="listed in awesome-dsh-plugin (an aggregated index, not an official curated list)"></a> <a href="#compatibility"><img src="https://img.shields.io/badge/DSH-%3E%3D0.1.5--rc.3-2f6feb?style=flat-square" alt="dsh host range: 0.1.5-rc.3 and later"></a> </p>
|
|
7
|
+
|
|
3
8
|
A Web client plugin that adds a **子代理管理** button to the conversation-header action row. It opens a searchable panel for the subagents currently discovered by the DSH client runtime.
|
|
4
9
|
|
|
10
|
+
Current release: **v1.9.1** — full history in [`CHANGELOG.md`](https://github.com/miuzel/dsh-subagent-ui/blob/HEAD/CHANGELOG.md) (English) and [`CHANGELOG.zh.md`](https://github.com/miuzel/dsh-subagent-ui/blob/HEAD/CHANGELOG.zh.md) (中文).
|
|
11
|
+
|
|
12
|
+
## Install in the Web profile
|
|
13
|
+
|
|
14
|
+
Install the published package from npm into your DSH Web profile:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
dsh plugin --profile web add dsh-subagent-workspace-ui
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Upgrade to the latest published version:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
dsh plugin --profile web add dsh-subagent-workspace-ui@latest
|
|
24
|
+
# or, equivalently:
|
|
25
|
+
dsh plugin --profile web update dsh-subagent-workspace-ui
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Uninstall:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
dsh plugin --profile web remove dsh-subagent-workspace-ui
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`dsh plugin --profile <name> <args…>` forwards its arguments to pnpm inside that profile, so the usual `add` / `update` / `remove` subcommands apply. No `--allow-build` flag is needed: the published tarball already ships a prebuilt `lib/`, and the package declares no install-time lifecycle scripts.
|
|
35
|
+
|
|
36
|
+
The bundle includes [`cordis.patch.yml`](cordis.patch.yml), which inserts the manager and shadows exactly one stock slot: `conversation.session.header.lineage` is claimed by a `priority: -1` title-only shadow so DSH's stock `ui-subagent` lineage dropdown stays invisible while this package is installed. The stock `ui-subagent` plugin itself is **left enabled** — this package no longer disables it wholesale, because the sidebar tab it provides is the navigation target of the new "open in the sidebar" button. The shadow renders the session title instead of an empty entry, so the subagent session header keeps its title. Removing the package removes this bundle layer, and the host's `ui-subagent` setting is untouched, so your own configuration is restored as it was. Restart the existing `dsh web` process, then refresh `http://127.0.0.1:3080` after the plugin is available.
|
|
37
|
+
|
|
38
|
+
If you previously disabled `ui-subagent` manually in `$DSH_HOME/profiles/web/cordis.patch.yml`, you can keep that stanza: it is user-owned and intentionally preserved. The plugin no longer needs (or writes) such a stanza.
|
|
39
|
+
|
|
40
|
+
Working on a checkout instead of the npm release? See [Local checkout (contributors)](#local-checkout-contributors).
|
|
41
|
+
|
|
5
42
|
## Features
|
|
6
43
|
|
|
44
|
+
### Scope: entry, workspace and session
|
|
45
|
+
|
|
7
46
|
- Compact title-bar trigger shows the active-child count and animated activity dot without opening the panel.
|
|
8
47
|
- Defaults to the main session's current workspace and current session, even when the user is viewing a child session.
|
|
9
48
|
- Workspace and session selectors support current workspace, all workspaces, named workspaces, current session, and named sessions.
|
|
49
|
+
- Show session IDs beside names, compact metadata, token totals, and creation time in the relative-time tooltip.
|
|
50
|
+
- Ordinary search matches names, titles and workspace names; the `id:` prefix searches Session IDs only (`id: graph:g-a92e1406`).
|
|
51
|
+
|
|
52
|
+
### Search, sorting and grouping
|
|
53
|
+
|
|
10
54
|
- Sort by recent activity, name, or type; recently running children remain near the top after they finish.
|
|
11
55
|
- Group by session, workspace, category, type, or no grouping. Session headers show the workspace and parent session name.
|
|
56
|
+
|
|
57
|
+
### Categories
|
|
58
|
+
|
|
12
59
|
- Browser-local classification tabs support custom regular expressions. Built-ins include all, other, review, test, implementation, and planning.
|
|
13
60
|
- One-shot children carry a compact `⚡ 一次性` badge; continuable children remain visually uncluttered.
|
|
14
|
-
|
|
15
|
-
|
|
61
|
+
|
|
62
|
+
### Filtering and hiding
|
|
63
|
+
|
|
64
|
+
- The filter block (category tabs, scope/session selectors, sorting, grouping, options) opens **collapsed by default**, showing one summary line (`Current workspace · Current session … · All`, then `Sort · recent activity` and `Group · by session`). That summary line is itself the disclosure control — click it, or press Enter/Space (`role=button` / `aria-expanded`) — and the preference is still persisted.
|
|
65
|
+
- Filtering and hiding are plugin-local: a hidden child simply leaves the list, no DSH session or workspace file is deleted, and the header counts subtract it. The options row offers hide one-shot, hide long-inactive, show hidden, the show-active-float toggle, a separately configurable subagent background colour for the dark and light themes, and reset filters.
|
|
66
|
+
|
|
67
|
+
### Pause, continue and one-click pause
|
|
68
|
+
|
|
69
|
+
- A running continuable child can be paused from its own row, from the active-subagent group header (`⏸ Pause all`, with a confirmation), or from the floating panel.
|
|
70
|
+
- An ended continuable row offers **`▶ Continue`** next to pause/hide/delete and sends one **localized** continue instruction into the child (Chinese UI `继续`, English UI `continue`) through the session face the host really exposes: `sessions.retain(…)` → `binding.session.prompt([…], 'queue')` where `retain` exists (0.1.6-alpha.2 on, including 0.1.7-rc.1), and the borrowed `sessions.binding` face on 0.1.5-rc.3, which has no `retain`. Pure capability probing, never a version check: a host without such a face renders no button at all, and running and one-shot rows never show it.
|
|
71
|
+
|
|
72
|
+
### Batch operations and permanent deletion
|
|
73
|
+
|
|
16
74
|
- Archive state is local and never deletes a DSH session. Single-row archive actions and a batch mode support shift-selection, select-all, time-based selection (up to 1,000 rows), batch archive, restore, and archive-all.
|
|
17
|
-
- Load catalogs in pages of 40 with an independent wheel-scroll container; batch time selection expands loading up to 1,000 children.
|
|
18
75
|
- Batch mode changes cards into selection targets and hides individual archive/restore actions. The highlighted 完成 button exits batch mode.
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
76
|
+
- Load catalogs in pages of 40 with an independent wheel-scroll container; batch time selection expands loading up to 1,000 children.
|
|
77
|
+
|
|
78
|
+
### Live activity and streaming output
|
|
79
|
+
|
|
22
80
|
- Active children are grouped at the top in a collapsible section. The panel shows the latest two lines of live output, recent tool calls, context injection, command status, and a gray final snapshot after completion — for **every** running row, not only the selected child, because the plugin retains its own session binding instead of borrowing whatever the main view happens to hold.
|
|
23
81
|
- Ended rows mark how the last turn finished, from the child's own public read-only `subagentTiming.lastTurnCompleted` projection: a normal end is a **hollow green ring**, an abnormal one (stopped/aborted, error, blocked, a token ceiling …) a **solid red dot**, each with a zh/en hover label. A host that does not publish the projection keeps exactly the previous dot — an unknown end is never shown as a normal one — and a running row keeps its original green dot.
|
|
24
|
-
|
|
25
|
-
|
|
82
|
+
|
|
83
|
+
### Opening and inspecting a child
|
|
84
|
+
|
|
85
|
+
- Open a loaded child at its exact `{ parentSessionId, childSessionId, mode }` address. In normal mode the whole card opens the child; archive controls do not. The navigation tiers are documented under [Compatibility](#compatibility).
|
|
86
|
+
- Every row also carries a dedicated **open in the sidebar** button (`◫`) that opens the child as a right-sidebar tab, so the main conversation stays where it is. The button stops propagation (it never triggers the row's default navigation and never toggles batch selection), and it is rendered only when the runtime exposes the sidebar capability: without `ctx.sidebarRight` plus a type that claims the address, the button is hidden entirely; for a single row whose subagent address cannot be resolved it stays visible but disabled with a readable reason. The same button is on the active-subagent floating panel.
|
|
87
|
+
- Show each child's current **type and model provider/id** (`provider/model`, plus the reasoning effort when the host publishes one) from the host's public projections only — no new RPC, no model-switch UI. See [Type and model](#type-and-model-read-only-projections).
|
|
88
|
+
- Show each child's usage inline, computed with the host's own definitions: `↑ 131.3k (未缓存 39.1k) / ↓ 12.7k · 命中 70% · 104 tps · 3 轮 · 9 步` (English UI: `miss` / `Hit` / `rnds` / `stps`). The `↑` figure is the **billed input** (`uncachedInputTokens + cacheReadTokens + cacheWriteTokens`) and that billed input alone is the cache-hit denominator — exactly what DSH's own composer footer does, so the plugin and the host agree instead of disagreeing by six points. `tps` is `decodeTokens / (decodeMs / 1000)` from the same public `sessionStats` projection. Hovering the row or the floating panel reveals the complete breakdown — total, every bucket, the share, the speed, and the session's LLM / tool / TTFT timings — in the native `title` tooltip.
|
|
26
89
|
|
|
27
90
|
## Screenshot guide
|
|
28
91
|
|
|
@@ -32,6 +95,8 @@ Both screenshots were taken on the `1.7.0-dev` line (commit `79d9d0f`) against a
|
|
|
32
95
|
|
|
33
96
|

|
|
34
97
|
|
|
98
|
+
### Legend
|
|
99
|
+
|
|
35
100
|
1. **Header** — panel title, `Current session n · Current workspace n · Active n`, the show-active-float toggle, and the close action.
|
|
36
101
|
2. **Search and scope row** — ordinary name/title/workspace search, with `id: xxx` reserved for Session ID search; workspace, session, sorting, and grouping selectors stay on one compact row.
|
|
37
102
|
3. **Classification row** (once the filter block is expanded) — built-in and custom categories with live counts, custom-category creation and deletion inside the same tab frame.
|
|
@@ -41,24 +106,14 @@ Both screenshots were taken on the `1.7.0-dev` line (commit `79d9d0f`) against a
|
|
|
41
106
|
7. **Detail block** — `Type: … · Model: …` straight from the host's read-only projections, then the official usage line `↑ billed (miss …) / ↓ output · Hit n% · n tps · n rnds · n stps`; a running child also shows its latest live-output lines, while a finished child keeps its final snapshot.
|
|
42
107
|
8. **Floating panel** — the running children of the current session in a compact always-on-top card, each with its live output, usage line and stop button; it appears whenever at least one child is running and the manager panel is closed. While it is shown it keeps every running child it lists live, independently of which child the main view has selected.
|
|
43
108
|
|
|
44
|
-
## Install in the Web profile
|
|
45
|
-
|
|
46
|
-
From this directory:
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
dsh plugin --profile web add file:.
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
The bundle includes [`cordis.patch.yml`](cordis.patch.yml), which inserts the manager and shadows exactly one stock slot: `conversation.session.header.lineage` is claimed by a `priority: -1` title-only shadow so DSH's stock `ui-subagent` lineage dropdown stays invisible while this package is installed. The stock `ui-subagent` plugin itself is **left enabled** — this package no longer disables it wholesale, because the sidebar tab it provides is the navigation target of the new "open in the sidebar" button. The shadow renders the session title instead of an empty entry, so the subagent session header keeps its title. Removing the package removes this bundle layer, and the host's `ui-subagent` setting is untouched, so your own configuration is restored as it was. Restart the existing `dsh web` process, then refresh `http://127.0.0.1:3080` after the plugin is available.
|
|
53
|
-
|
|
54
|
-
If you previously disabled `ui-subagent` manually in `$DSH_HOME/profiles/web/cordis.patch.yml`, you can keep that stanza: it is user-owned and intentionally preserved. The plugin no longer needs (or writes) such a stanza.
|
|
55
|
-
|
|
56
109
|
## Runtime data boundary
|
|
57
110
|
|
|
58
111
|
The public DSH Web session store exposes subagent summaries that have been discovered in the current browser runtime. It deliberately does not expose a global historical subagent index or a mode for every unvisited child. Therefore this first plugin version manages the discovered catalog; rows whose type is not yet loaded remain visible and searchable and fall back to DSH's retained session navigation. Exact catalog navigation is used automatically as soon as DSH supplies the address and mode.
|
|
59
112
|
|
|
60
113
|
A full persistent workspace-wide archive view requires a host-side catalog RPC (or an upstream DSH API) that enumerates every child address and its mode. The public `SessionSummary` does not expose the original prompt, so prompts are neither queried nor displayed; **type and model** come from the public projections documented in [Type and model](#type-and-model-read-only-projections). Live output and tool/context activity are read from a bound session automatically: on dsh **0.1.2-alpha.2** they are derived from the raw `binding.eventSource` event stream (showing the tool description or target filename), while older hosts (e.g. **0.1.1-rc.2**) fall back to `session.getSnapshot().chat.legacy`. On hosts with the retain contract (**0.1.6-alpha.2** and on) the plugin first **retains** each running child itself — `sessions.binding(id)` merely borrows a binding somebody else retained, so without retaining, only the child the main view had selected ever streamed. Retention is bounded to 8 children (the float first, then the panel's rendered running rows, most recently active first) and is released as soon as a row stops rendering or stops running, when a surface closes, or when the plugin is disposed; a child beyond the cap, and any host without `retain`, falls back to the borrowed binding and then to the durable summary. Capability detection selects the path (never a version check), so the plugin stays forward compatible. The UI is isolated in [`lib/client.js`](lib/client.js), so it can switch to a richer source without changing the panel interaction model.
|
|
61
114
|
|
|
115
|
+
Archive, category and recent-use order are kept in browser `localStorage`; nothing is ever written into the DSH session log.
|
|
116
|
+
|
|
62
117
|
### Type and model (read-only projections)
|
|
63
118
|
|
|
64
119
|
A child's type and model come from public host projections. The plugin adds no RPC and writes no state:
|
|
@@ -95,10 +150,18 @@ The display rules are identical on all three surfaces and differ only in density
|
|
|
95
150
|
|
|
96
151
|
## Compatibility
|
|
97
152
|
|
|
98
|
-
v1.8.0 and later support dsh **0.1.5-rc.3**, **0.1.6-alpha.2**
|
|
153
|
+
v1.8.0 and later support dsh **0.1.5-rc.3**, **0.1.6-alpha.2**, **0.1.7-rc.1**, **0.1.7-rc.2** and **0.2.0-rc.1** and stay backward compatible with all DeepSeek Harness versions. Those hosts span two API tiers — 0.1.5-rc.3 and 0.1.6-alpha.2 still publish `subagentsByParent`, `refreshSubagents` and `setSubagentCatalogOpen`, while 0.1.7-rc.1 **removed** `sessions.setSubagentCatalogOpen`, **renamed** `refreshSubagents(parentSessionId)` to `refreshProjections(sessionId)`, and **replaced** `SessionListState.subagentsByParent` with the parent session's own `subagentCatalog` projection. Every call site probes for the capability it needs, so both generations work and no version number is ever compared.
|
|
154
|
+
|
|
155
|
+
**0.2.0-rc.1** was checked the same way — package by package against **0.1.7-rc.1** (23 host packages plus the CLI, app boot and the web frontend), not against its release notes — and it needs **no adaptation** either: no host face this plugin reads changed structurally. The two slot declarations it registers, the module-loader shell and its seeded `require` keys, the `subagentCatalog` / `subagent` / `subagentTiming` projections (including the generational `lastTurnCompleted` field), `subagentAddress` / `openResource` / `candidates`, the `dsh plugin --profile web add` flow and all 21 `--dsw-*` tokens this plugin uses are unchanged or purely additive; the only contract addition is an optional `fork(onCreated)` the plugin never calls, and the stock web graph dropping its `ui-schedule` row does not touch this plugin or its slot shadow. Two differences are visible but not breaking: one dark-theme token the panel and the floating card use for their glass surface changed value, and the sidebar services appear **even later** than on 0.1.7-rc.1 (see “Open in the sidebar” below).
|
|
156
|
+
|
|
157
|
+
A smoke run on **0.2.0-rc.1** renders the same panel: on a parent session with six catalog children the manager lists all six rows with their catalog labels, `Type: continuable` on every row and an enabled `◫` on every row, and each child session that gets mounted shows its ended row as the hollow green ring with its own model and usage figures — line for line the same as the **0.1.7-rc.1** run over the same session data, and a click on `◫` opens that child as a right-sidebar tab on both.
|
|
99
158
|
|
|
100
159
|
A smoke run on **0.1.5-rc.3** shows no degradation on that line: on a fresh instance with one running child the manager opens on the live session with the child's catalog label, `Type: continuable`, the concrete model id, `◫` on the row, the pause/hide/delete actions, the live-output section rendering that child's running `bash` tool, and the usage figures — with no error from this plugin in the console.
|
|
101
160
|
|
|
161
|
+
**0.1.7-rc.2** needs no adaptation either, and it exposed one thing the earlier matrix had missed: the stock `ui-subagent` plugin registers **two** header entries, not one. Besides the `conversation.session.header.lineage` dropdown, **0.1.7-rc.1** added a second registration in `conversation.session.header.actions` (`id: "subagent-catalog"`, `order: -30`) that draws the official “N subagents” count dropdown as soon as the current session's `subagentCatalog` projection is loaded. Because that slot is a `list` slot whose cells are keyed by `id`, the manager's own `subagent-workspace-manager` cell never competed with it, so both entries could show side by side — the plugin now shadows that cell too (`priority: -1`, rendering `null`), exactly as it shadows the lineage slot, and either shadow degrades to “official entry visible” if a host ever occupies the same cell at that priority. Verified on **0.1.7-rc.1**, **0.1.7-rc.2** and **0.2.0-rc.1** against the same six-child fixture: the header shows only `🧩 Subagents 0/6`, the six-row panel opens, and each row's `◫` still opens that child as the stock `subagentchat` right-sidebar tab. On **0.1.5-rc.3** and **0.1.6-alpha.2** — which have no such stock registration — the extra shadow cell adds no element to the header and raises no error.
|
|
162
|
+
|
|
163
|
+
### Session navigation (three capability tiers)
|
|
164
|
+
|
|
102
165
|
```text
|
|
103
166
|
# dsh 0.1.2-alpha.5 .. 0.1.6-alpha.1: the session controller entry points
|
|
104
167
|
ctx.sessions.openSubagent(address) # exact child address
|
|
@@ -112,6 +175,8 @@ ctx.get('uiWorkspace').openSession({ parentSessionId, childSessionId, mode } | s
|
|
|
112
175
|
|
|
113
176
|
`uiWorkspace` is read through `ctx.get('uiWorkspace')`, never through a required injection, so hosts that do not register the service (everything before **0.1.2-alpha.5**) still load and keep using the session-controller path, while hosts that removed `openSubagent`/`open` (**0.1.6-alpha.2**) use the workspace service. **The probe order follows the argument shape, not the version**: `sessions.openSubagent` accepts an address object on every host that has it, whereas `uiWorkspace.openSession` only accepts a `SessionTarget` from **0.1.6-alpha.2** on — on **0.1.5-alpha.2 … 0.1.6-alpha.1** it is `openSession(sessionId)` and routes through `sessions.open(id)`, which throws on an address. The session-controller tier is therefore tried first and the workspace service is the fallback. Within the controller tier the exact `{ parentSessionId, childSessionId, mode }` address is used first and only a missing mode/child falls back to plain session navigation, because `openSubagent` rejects addresses that are not healthy catalog children. The 0.1.2-series capability paths (live output via `binding.eventSource`, chat-tab switch via slot `actions`) remain the primary branches, and the **0.1.1-rc.2** legacy fallbacks (`chat.legacy` snapshot) are unchanged.
|
|
114
177
|
|
|
178
|
+
### Open in the sidebar (◫ button)
|
|
179
|
+
|
|
115
180
|
The **open in the sidebar** button follows the same rule — capability detection, never a version check:
|
|
116
181
|
|
|
117
182
|
```text
|
|
@@ -127,75 +192,13 @@ ctx.sessions.subagentAddress → typeof function (per-row address lookup)
|
|
|
127
192
|
# with a readable reason instead of throwing.
|
|
128
193
|
```
|
|
129
194
|
|
|
130
|
-
Both faces are resolved **per row and per click, never once at activation**: dsh **0.1.7-rc.1** registers `sidebarRight`/`sidebarRightTabs` only *after* a plugin's `apply` has run — on **0.1.6-alpha.2** they are already present when `apply` runs — so a probe performed once at activation hides the whole `◫` column on the newer host while leaving the older one untouched.
|
|
195
|
+
Both faces are resolved **per row and per click, never once at activation**: dsh **0.1.7-rc.1** registers `sidebarRight`/`sidebarRightTabs` only *after* a plugin's `apply` has run — on **0.1.6-alpha.2** they are already present when `apply` runs — so a probe performed once at activation hides the whole `◫` column on the newer host while leaving the older one untouched. dsh **0.2.0-rc.1** pushes that window further out still: its `ui-sidebar-right` now also injects `shortcuts`, so it waits for one more service before it publishes those two faces. The per-row, per-click resolution is what keeps the `◫` column rendered on all of these hosts.
|
|
131
196
|
|
|
132
197
|
Adding the sidebar capability does not change the navigation probe above: the row's default click still walks the same three tiers, and the new button never touches them.
|
|
133
198
|
|
|
134
199
|
Opening a subagent in the right sidebar uses DSH's own `subagentchat` right-sidebar tab, so the pane is a *session view*: the subagent session's composer there is DSH's official read-only composer (`一次性子代理记录` / "one-shot subagent record") rather than this plugin's UI. That is expected, and it is the only official way to read a child session without leaving the main conversation.
|
|
135
|
-
## v1.9.0
|
|
136
|
-
|
|
137
|
-
- **Feature**: an ended subagent can be **continued from its own row**. The row action group (`⏸ Pause` / `⊘ Hide` / `🗑 Delete`) gains `▶ Continue`, which sends one **localized** continue instruction into that child (Chinese UI `继续`, English UI `continue`) so it runs again. The implementation is pure capability probing and **never compares a version**: a host with `retain` (0.1.6-alpha.2 on, including 0.1.7-rc.1) goes `sessions.retain(…)` → `binding.session.prompt([{ type: 'text', text: '继续' }], 'queue')` (the English UI passes `'continue'`), while **0.1.5-rc.3** has no `retain` and uses the same face obtained by borrowing `sessions.binding`, which works just as well. A host without that capability **renders no button**; running rows and one-shot rows never show it either; the manager panel itself lives in the parent session's header, so "the parent agent must be alive" is satisfied by construction in normal use (an unavailable parent only logs a console warning instead of becoming an uncaught rejection).
|
|
138
|
-
- **Feature**: the **filter block opens collapsed**. On first open the manager shows a single summary line (`Current workspace · Current session … · All`, plus `Sort · recent activity` and `Group · by session`); clicking that summary line expands or collapses the block, and Enter/Space do the same (`role=button` / `aria-expanded`). The preference is still persisted. A bug falls out with it: with the preference unset the toggle could only collapse and never expand, because `!undefined === true`.
|
|
139
|
-
- **Feature**: an **ended row separates a normal end from an abnormal one**. A normal end is a hollow green ring, an abnormal one (⏸ stopped/aborted, error, blocked, max-tokens …) a solid red dot, each with a zh/en hover label (`正常结束` / `异常结束`). The verdict comes only from the child's own public read-only `subagentTiming.lastTurnCompleted` projection (the host writes it on `turn/end` and removes it on `turn/start`); a host that does not publish the projection **keeps the previous dot**, so an unknown end is never rendered as a normal one. The verdict field itself is projected by the host only from **dsh 0.1.7-alpha.1**: **0.1.5-rc.3** and **0.1.6-alpha.2** publish `{ settledMs, active? }` only, so on those two hosts an ended row keeps the neutral dot and does not distinguish how it ended. Running rows keep their original green dot.
|
|
140
|
-
- **Compatibility**: all three changes are capability-probed and **never version-checked**; v1.9.0 supports dsh **0.1.5-rc.3** / **0.1.6-alpha.2** / **0.1.7-rc.1** exactly as v1.8.0 does (verified on all three hosts; the terminal indicator stays a neutral dot on 0.1.5-rc.3 and 0.1.6-alpha.2 per the boundary above). The only code changes are the row-action alignment (`src/client/styles.ts`) and one corrected comment (`src/client/format.ts`); the rest is the version bump and docs, and `pnpm run check` is green with the bundle freshness in sync.
|
|
141
|
-
|
|
142
|
-
## v1.8.0
|
|
143
|
-
|
|
144
|
-
- **Fix**: live output only updated for the **currently selected** subagent. `sessions.binding(id)` only *borrows* a binding somebody else retained, and the stock view retains just the session the main view has selected — so every other child had no live region at all. The plugin now **retains** each running child it is showing itself: the float keeps every running child it displays, the panel keeps the running rows it renders, both share a cap of 8 (float first, most recently active first), and each row that stops rendering or stops running, every closed surface and the plugin's disposal releases in pairs. A host without `retain`, and any child beyond the cap, still falls back to the borrowed binding and then to the durable summary. Landing with it: **Pause now works on a row that is not selected** — it previously called into a binding that did not exist and silently did nothing.
|
|
145
|
-
- **Compatibility with dsh 0.1.7-rc.1**: that host **removed** `sessions.setSubagentCatalogOpen`, **renamed** `refreshSubagents(parentSessionId)` to `refreshProjections(sessionId)`, and **replaced** `SessionListState.subagentsByParent[parent]` with the parent session's own `projectionValues.subagentCatalog` projection (the same direct children in catalog event order; entries lost their `kind` discriminator and gained a third `mode: 'unknown'` arm). Un-guarded, the removed method threw out of the manager panel's open effect and the error boundary took the whole header slot down — **opening the manager crashed the title bar**. Every host call is now capability-probed and never version-checked: one reader resolves the catalog from the parent's `subagentCatalog` on 0.1.7-rc.1+ and from `subagentsByParent` up to 0.1.6-alpha.2 (the legacy source wins when a host publishes both, so older hosts read exactly what they read before), `refresh` prefers `refreshProjections` and falls back to `refreshSubagents`, and a missing `setSubagentCatalogOpen` is skipped. An entry whose `mode` is `unknown` keeps its label and yields the mode to the child's own identity projection instead of trusting that arm.
|
|
146
|
-
- **Fix**: on 0.1.7-rc.1 the per-row **open in the sidebar** action (`◫`) disappeared from every row. That host registers `sidebarRight`/`sidebarRightTabs` *after* this plugin's `apply` runs, so the one-time probe at activation judged both absent for good. Both faces are now resolved per row and per click: a host that never publishes them still renders no button (byte-for-byte the previous surface), while an available face whose row address does not validate keeps the existing disabled button and its readable reason.
|
|
147
|
-
- **Docs**: the type/model ladder documents both catalog generations, and the compatibility section records the 0.1.7-rc.1 API changes above.
|
|
148
|
-
- **Tweak**: the active float pins its background at **exactly 95% opacity**. dsh **0.1.7-rc.1** redefined `--dsw-specific-menu` as a translucent glass colour — `#30313680` in the dark theme (alpha `0x80` = 50%) and `#f8f9fa94` in the light one (58%) — where 0.1.6 pointed that same token at the opaque `--dsw-alias-bg-layer-3`, so the float turned see-through on the newer host. It now composites the host's **opaque** surface token at 95% (`color-mix`, with the previous declaration kept ahead of it as the fallback for a host without `color-mix`), which also makes the float's density identical on 0.1.6 and 0.1.7 — no version check, and the tone still comes from the host's own theme tokens.
|
|
149
|
-
|
|
150
|
-
Verified on dsh **0.1.6-alpha.2** and **0.1.7-rc.1**: `pnpm run check` green (bundle freshness in sync, 98,439 bytes). On 0.1.7-rc.1 the panel opens on a live session with all 7 of its subagents, rows carrying their catalog labels, `Type: continuable`, model and usage figures, `◫` on every row, and **no console error after the click**. On 0.1.6-alpha.2 the panel object is byte-for-byte identical to the pre-change build, and the same batch of data shows the same unknowns it showed before (a child whose projections the host never published stays `model unknown`, exactly as it does on 0.1.6). The float's background was then measured on a live 0.1.7-rc.1 instance with a running child: it renders `rgb(51,52,54)`, the exact value `#353638` at 95% predicts over the `rgb(21,21,23)` header backdrop behind it, where the previous 50% glass would have rendered `rgb(34,35,38)`; sampling the same float over a backdrop 22 levels lighter (`rgb(43,43,45)`) moved it by at most one level, which is what a 95% surface does and a 50% one cannot (it would have moved 11 levels). The host's own `dsh-client-ui-open-in-app` logs a load-time `inactive context` error on 0.1.7-rc.1; it is unrelated to this plugin and deliberately left alone.
|
|
151
|
-
|
|
152
|
-
## v1.7.0
|
|
153
|
-
|
|
154
|
-
- **Fix**: the **open in the sidebar** button (`◫`) — on a panel row and on the active float — was a far smaller target than the 24×24 CSS px minimum: 18.03×16 and 17.14×17, i.e. only the glyph itself was clickable. Both now measure **24.03×24** and **24.14×25**, while the layout box, the glyph position, the row heights and every neighbouring button's coordinates stay **pixel-identical**: the padding growth is cancelled by negative margins, and the hover pill moved into an `::after` pseudo-element whose insets reproduce the previous border box exactly (18.03×16 / 17.14×17). The one rendering difference is compositing order — the hover overlay now paints over the glyph instead of under it (≲1.3/255 per channel in the dark theme, ≲0.7/255 in the light one), which is imperceptible. Disabled rows keep their opacity and `not-allowed` cursor, and the larger area cannot turn a row press into a float drag: `closest('button,input,label')` is DOM ancestry, not geometry.
|
|
155
|
-
- **Docs**: the dshmarket screenshots were re-shot on a real dsh **0.1.6-alpha.2** instance of the `1.7.0-dev` line (commit `79d9d0f`) — the manager panel and the active-subagents float, each in Chinese and in English (`*.en.png`, the host locale actually switched), dark theme, 1280×900 CSS at DPR 1.75. The captured session ran four background subagents at once (three running, one finished), so every row carries its real type, model and the official usage line instead of fallback text, with the `◫`, pause, hide and delete actions visible. `screenshots.json` now lists all four paths (dshmarket's carousel cap is 6), each README points at its own language pair instead of both sharing one, and the screenshot guide was rewritten — it still described controls (`show archived`, `→ archive`) that no longer exist.
|
|
156
200
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
## v1.6.0
|
|
160
|
-
|
|
161
|
-
- **Feature**: every row and the active-subagent floating panel now carry an **open in the sidebar** button (`◫`) that opens the child as DSH's own `subagentchat` right-sidebar tab, so the main conversation stays where it is. It is capability-detected and never version-checked: the button is hidden entirely when the runtime exposes no `sidebarRight` / `sidebarRightTabs` capability or no tab type claims the row's address, and a single row whose address cannot be resolved stays visible but disabled with a readable reason. Clicking it never triggers the row's default navigation and never toggles batch selection. Because that sidebar tab *is* stock `ui-subagent`'s, the bundle patch no longer disables that plugin wholesale — it now only shadows `conversation.session.header.lineage` at `priority: -1` (a **title-only** shadow, so a subagent session's header title survives) and `ui-subagent` itself stays enabled. Your own `cordis.patch.yml` stanza is still preserved on removal.
|
|
162
|
-
- **Feature**: the manager shows each child's **type and model** (`provider/model`, plus the reasoning effort when the host publishes one) purely from public read-only projections, with the type and the model degrading independently (`类型待加载` / `模型未知`). No new RPC, no model-switch UI.
|
|
163
|
-
- **Fix**: a child's type could read `类型待加载` (*type loading*) until the manager panel had been opened once, even though the host had already published the mode — and opening the panel then flipped that same row to `一次性`. The mode was read only from the lazily pulled subagent catalog, and only the panel pulls it. It now resolves through one reader with one fallback order: ① the discovered catalog entry → ② the child's own `subagent` identity projection (pushed on the live-control stream and on every session-added summary, so a freshly loaded page already has it) → ③ the existing fallback text. A freshly spawned child's sidebar button can stay briefly disabled until that child is discovered; that is the documented capability probe, not a defect.
|
|
164
|
-
- **Fix**: the inline usage figures disagreed with DSH's own composer footer for the same child (`in 39.1k / out 12.7k · cache hit 64%` versus `143K tok · Cache hit 70%`). The line showed the *uncached input* bucket labelled as "input", and it divided the cache-hit share by the four-bucket **total**, which counts output tokens in a prompt-side ratio. Both now follow the host's definitions: `↑ billed input (uncached) / ↓ output · 命中 n% · tps · turns · steps`, with the billed input alone as the denominator, and `tps = decodeTokens / (decodeMs / 1000)` from the same public `sessionStats` projection. The complete breakdown — total, every bucket, the share, the speed and the session's LLM / tool / TTFT timings — moved into the native `title` tooltip on both the row and the float. The host's cache-hit formatter is ported expression-for-expression, so a partial hit can never round up to 100%.
|
|
165
|
-
- **Docs**: the lineage slot shadow is now described as what it is — a *title-only* shadow. The host's conversation module replaces the caller fallback once an entry exists in that single slot, so a literally empty entry would delete a subagent session's header title.
|
|
166
|
-
|
|
167
|
-
Verified on dsh **0.1.6-alpha.2**: `pnpm run check` green, and the usage figures cross-checked against the official composer footer for the same child in a single screenshot (`132 tok/s` / `缓存命中 98%` / `29.8M tok` against `132 tps` / `命中 98%` / `↑ 29.7m + ↓ 119.6k` = `29.8M`). The cache-hit formatter is covered by a differential test that slices the three official helper functions out of the installed host client at run time and asserts identical output over 80,980 `(read, billed)` pairs — 0 mismatches, with 425 cases where the previous implementation differed.
|
|
168
|
-
|
|
169
|
-
## v1.5.0
|
|
170
|
-
|
|
171
|
-
- **Fix**: on DeepSeek Harness **0.1.6-alpha.2** clicking a subagent row failed with `TypeError: ctx.sessions.openSubagent is not a function` (the click was silently swallowed by the row's `try`/`catch`, so the panel just looked dead). 0.1.6-alpha.2 removed `sessions.openSubagent(address)` and `sessions.open(id)`; the plugin now detects the navigation capability at runtime in three tiers (`sessions.openSubagent` → `sessions.open` → `uiWorkspace.openSession`) instead of hard-switching, so the same bundle keeps working on both sides of that upstream change, and the failure is surfaced in the UI when no navigation API exists at all.
|
|
172
|
-
- **Fix**: the tier order above is argument-shape driven, because **0.1.5-alpha.2 … 0.1.6-alpha.1** ships a `uiWorkspace.openSession(sessionId)` that only accepts a string id and throws `sessions.select: unknown session [object Object]` for an address, while `sessions.openSubagent(address)` is still present and does accept one on those hosts. Trying the workspace service first there swallowed that throw and showed the "unsupported version" notice, so the address now goes to the object-capable controller entry point first and `uiWorkspace` remains the fallback for 0.1.6-alpha.2+. Verified live on both sides of the band: on **0.1.5-alpha.1** (client packages 0.1.5-rc.2) the reordered bundle switches session in ~142 ms with no alert and no navigation error, and on **0.1.6-alpha.2** the served bundle still resolves to `uiWorkspace.openSession` and opens the child session.
|
|
173
|
-
- **Fix**: 0.1.6-alpha.2 also dropped the `current` field from the session list snapshot, which the current-session resolution and the Chat-tab fallback relied on. Both now degrade gracefully: the fallback recognizes a missing `current`, tries the host's own Chat tab immediately, and gives up quietly after 2 s instead of polling for 8 s.
|
|
174
|
-
|
|
175
|
-
## v1.4.0
|
|
176
|
-
|
|
177
|
-
- **Compatibility**: supports DeepSeek Harness **0.1.5-rc.2**, backward compatible with all dsh versions. 0.1.5-rc.2 changed the conversation view structure (the slot renderer no longer injects store `actions` into entries that do not declare a store, and the selected view is now persisted per session, with new tabs such as Trajectory) — clicking a subagent lands back on the Chat tab again (when `actions` is unavailable the plugin clicks the host's own Chat tab, preserving the host's activation and persistence semantics). The 0.1.2 capability-detection path remains the untouched primary branch and the 0.1.1 legacy fallback is unchanged.
|
|
178
|
-
- **TypeScript migration**: `src/client/*.ts` is now the single source of truth and `lib/client.js` is generated by `pnpm run build` (sucrase type erasure + deterministic linker) instead of being hand-written. New tooling: `verify-build` (token/line-level diff against the v1.3.4 hand-written golden — migration equivalence proof and delta viewer for intentional changes) and `verify-fresh` (stale-bundle gate); `pnpm run check` runs build + typecheck + syntax + freshness in one shot.
|
|
179
|
-
- **Fix**: a latent `scopeKey` ReferenceError in the collapsed filter summary (found during the TypeScript migration) is corrected to `workspaceKey`.
|
|
180
|
-
|
|
181
|
-
## v1.3.4
|
|
182
|
-
|
|
183
|
-
- **Feature**: the whole UI is localized through DSH client-locale (zh/en, AI-assisted English strings). Labels, buttons, stats, live output (context injection / thinking / tool details) and confirm dialogs now use translation keys and follow the host language. Contributed by [@Marcuss2](https://github.com/Marcuss2) in [PR #1](https://github.com/miuzel/dsh-subagent-ui/pull/1) — thank you!
|
|
184
|
-
|
|
185
|
-
## v1.3.3
|
|
186
|
-
|
|
187
|
-
- **Fix**: batch delete no longer errors on large selections (host request-body limit raised to 8 MiB).
|
|
188
|
-
- **Feature**: with details hidden, hovering a row/name shows the stats (`输入/输出 · 缓存命中 · 轮数 · 步数`) via the title tooltip.
|
|
189
|
-
- **Fix**: live output now shows context injection (`上下文注入 · <form>`) and the thinking state.
|
|
190
|
-
- **Feature**: while thinking, a rotating "思考中…" spinner indicates the state instead of the low-priority reasoning text.
|
|
191
|
-
|
|
192
|
-
## v1.3.2
|
|
193
|
-
|
|
194
|
-
- **Performance**: the manager now does one base scan (`subagentRows`) and derives `allRows`/`activeRows`/`tabCounts` from it (no repeated full scans or `modeMap` merges), `tabCounts` is computed from a deferred value and is skipped while the panel is closed, and `useSessions` subscribes only the fields the manager reads. Live output is capped to a few simultaneous subagents (`liveCap`, default 3, `0` = unlimited) and fully releases its subscriptions when live display is off or the float/panel is closed.
|
|
195
|
-
- **UX**: opening a subagent now auto-switches the session to the Chat tab.
|
|
196
|
-
- **Fix**: the batch "select N hours ago" now selects the truly-old subagents in the current view (accurate count) and no longer overwrites or re-selects your manual changes.
|
|
197
|
-
|
|
198
|
-
## Validation
|
|
201
|
+
## Development and validation
|
|
199
202
|
|
|
200
203
|
The client bundle `lib/client.js` is **generated from the TypeScript sources** in [`src/client/`](src/client/) — edit those, never the bundle, then rebuild:
|
|
201
204
|
|
|
@@ -207,7 +210,17 @@ pnpm run check # build + tsc --noEmit + node --check lib/index.js + bundle fr
|
|
|
207
210
|
|
|
208
211
|
`pnpm run verify:build` compares the generated bundle with the hand-written pre-refactor bundle (git ref `v1.3.4`) up to insignificant whitespace, using token-level and line-level comparison. After the migration it doubles as a delta viewer that prints the exact differences of any intentional change.
|
|
209
212
|
|
|
210
|
-
|
|
213
|
+
### Local checkout (contributors)
|
|
214
|
+
|
|
215
|
+
To iterate on a clone instead of the npm release, install the working tree into the Web profile from the repository root:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
dsh plugin --profile web add file:.
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Profile installs are store copies, so after editing `src/client/*.ts` you must run `pnpm run build` and re-add the plugin (or run `./test.sh`) before the Web UI can pick the change up. The host-entry (`lib/index.js`) path always needs a `dsh web` restart. The same contributor loop is documented in [`AGENTS.md`](AGENTS.md).
|
|
222
|
+
|
|
223
|
+
### Smoke test (any dsh version)
|
|
211
224
|
|
|
212
225
|
```bash
|
|
213
226
|
./test.sh # local dsh, port 8084
|
|
@@ -219,8 +232,14 @@ DSH_PLUGIN_DIR=.worktrees/x ./test.sh # smoke another checkout's bundle
|
|
|
219
232
|
|
|
220
233
|
The script always uses an isolated `DSH_HOME` (`$HOME/tmp/dsh-test`, override with `DSH_SMOKE_HOME=…`) and refuses to touch the real `~/.dsh` profile. With `DSH_VERSION` set it runs `pnpx @deepseek-ai/dsh@<version>`; pnpm 12 ignores dependency lifecycle scripts by default, so the script passes `--allow-build=<pkg>` for dsh's native dependencies (`DSH_ALLOW_BUILDS=…` overrides the list).
|
|
221
234
|
|
|
235
|
+
## Release notes
|
|
236
|
+
|
|
237
|
+
Full release notes — every version, newest first — live in the changelog:
|
|
238
|
+
|
|
239
|
+
- [`CHANGELOG.md`](https://github.com/miuzel/dsh-subagent-ui/blob/HEAD/CHANGELOG.md) — English, back to v1.3.2.
|
|
240
|
+
- [`CHANGELOG.zh.md`](https://github.com/miuzel/dsh-subagent-ui/blob/HEAD/CHANGELOG.zh.md) — 中文完整版, back to v1.0.1.
|
|
241
|
+
|
|
222
242
|
## Acknowledgements
|
|
223
243
|
|
|
224
244
|
- UI localization (zh/en) contributed by [@Marcuss2](https://github.com/Marcuss2) via [PR #1](https://github.com/miuzel/dsh-subagent-ui/pull/1) — many thanks!
|
|
225
245
|
- Subagent permanent deletion and session cleanup design inspired by and referencing [@heiheiha798/dsh-plugin-subagent-delete](https://github.com/heiheiha798/dsh-plugin-subagent-delete).
|
|
226
|
-
|
package/README.zh.md
CHANGED
|
@@ -1,13 +1,53 @@
|
|
|
1
1
|
# DSH 子代理工作区管理器
|
|
2
2
|
|
|
3
|
+
[English](README.md) | **中文**
|
|
4
|
+
|
|
5
|
+
<p align="center"> <img src="https://raw.githubusercontent.com/miuzel/dsh-subagent-ui/main/docs/banner.png" alt="DSH 子代理工作区管理器 —— 子代理管理器与实时浮窗" width="100%"> </p>
|
|
6
|
+
<p align="center"> <a href="https://www.npmjs.com/package/dsh-subagent-workspace-ui"><img src="https://img.shields.io/npm/v/dsh-subagent-workspace-ui?style=flat-square&label=npm&color=cb3837" alt="npm 版本"></a> <a href="https://www.npmjs.com/package/dsh-subagent-workspace-ui"><img src="https://img.shields.io/npm/dm/dsh-subagent-workspace-ui?style=flat-square&label=downloads&color=cb3837" alt="npm 下载量"></a> <a href="LICENSE"><img src="https://img.shields.io/npm/l/dsh-subagent-workspace-ui?style=flat-square&label=license&color=green" alt="许可证"></a> <a href="https://awesome-dsh-plugin.com"><img src="https://img.shields.io/badge/awesome--dsh--plugin-listed-2f6feb?style=flat-square" alt="已收录于 awesome-dsh-plugin(聚合索引,非官方 curated 列表)"></a> <a href="#兼容性"><img src="https://img.shields.io/badge/DSH-%3E%3D0.1.5--rc.3-2f6feb?style=flat-square" alt="dsh 宿主版本范围:0.1.5-rc.3 起"></a> </p>
|
|
7
|
+
|
|
3
8
|
面向 DeepSeek Harness Web 的子代理管理插件。插件在会话标题栏提供一个紧凑的 `🧩 子代理 active/total` 入口,用于搜索、筛选、分组、排序、查看和批量归档当前运行时已发现的子代理。
|
|
4
9
|
|
|
5
|
-
当前发布版本:**v1.9.0
|
|
10
|
+
当前发布版本:**v1.9.1** —— 完整历史见 [`CHANGELOG.zh.md`](https://github.com/miuzel/dsh-subagent-ui/blob/HEAD/CHANGELOG.zh.md)(中文,回溯至 v1.0.1)与 [`CHANGELOG.md`](https://github.com/miuzel/dsh-subagent-ui/blob/HEAD/CHANGELOG.md)(English)。
|
|
11
|
+
|
|
12
|
+
## 安装
|
|
13
|
+
|
|
14
|
+
从 npm 安装已发布的包到 DSH Web profile:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
dsh plugin --profile web add dsh-subagent-workspace-ui
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
升级到最新发布版本:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
dsh plugin --profile web add dsh-subagent-workspace-ui@latest
|
|
24
|
+
# 或者等价地:
|
|
25
|
+
dsh plugin --profile web update dsh-subagent-workspace-ui
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
卸载:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
dsh plugin --profile web remove dsh-subagent-workspace-ui
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`dsh plugin --profile <name> <参数…>` 会把参数转发给该 profile 内的 pnpm,因此 `add` / `update` / `remove` 等子命令按常规语义生效。**不需要 `--allow-build`**:发布 tarball 内含预构建的 `lib/`,且本包没有安装期生命周期脚本。
|
|
35
|
+
|
|
36
|
+
插件 bundle 会自动加载 [`cordis.patch.yml`](cordis.patch.yml):安装期间插入管理器,并且**只遮蔽一个 slot**——用 `priority: -1` 的**标题位遮蔽**占用 `conversation.session.header.lineage`,从而让 DSH 自带的 `ui-subagent` 血统下拉保持不可见。自带 `ui-subagent` 插件本身**保持启用**(本插件不再整体禁用它),因为新版「在侧边栏打开」按钮正是复用它提供的 `subagentchat` 右侧栏标签页。该遮蔽渲染的是会话标题而不是空内容,所以子代理会话标题不会消失。卸载插件后,这层 bundle patch 会被移除,宿主的 `ui-subagent` 设置从未被改动,恢复如初。请重启现有的 `dsh web` 进程,然后刷新:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
http://127.0.0.1:3080
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
如果之前在 `$DSH_HOME/profiles/web/cordis.patch.yml` 中手动禁用了 `ui-subagent`,那条配置属于用户所有,插件不会覆盖、也不会依赖它——可以保留。
|
|
43
|
+
|
|
44
|
+
要在本地 checkout 上开发而不是用 npm 发布版?见[本地 checkout(贡献者)](#本地-checkout贡献者)。
|
|
6
45
|
|
|
7
46
|
## 主要功能
|
|
8
47
|
|
|
9
|
-
###
|
|
48
|
+
### 范围:标题栏入口、工作区与会话
|
|
10
49
|
|
|
50
|
+
- 标题栏入口显示活跃数 / 总数与活动动画点,不打开面板也能看到运行状态。
|
|
11
51
|
- 默认选择当前工作区。
|
|
12
52
|
- 默认选择当前主会话;即使当前页面已经进入某个子代理,会话管理器仍然以最上层主会话为基准。
|
|
13
53
|
- 工作区下拉框支持:
|
|
@@ -44,25 +84,6 @@
|
|
|
44
84
|
- 按会话分组时,分组标题显示“工作区 · 会话名称”,卡片中不再重复显示相同的归属信息。
|
|
45
85
|
- 活跃子代理单独置顶,并可折叠。
|
|
46
86
|
|
|
47
|
-
## 界面截图
|
|
48
|
-
|
|
49
|
-
两张截图拍摄于 `1.7.0-dev` 分支(commit `79d9d0f`)上真实运行的 dsh **0.1.6-alpha.2** 实例,深色主题。拍摄时同一个会话里并存 4 个后台子代理——3 个仍在运行、1 个已完成,因此每行都能展示真实的类型、模型与用量数字。这里是中文界面;英文界面两张见 [`README.md`](README.md)。
|
|
50
|
-
|
|
51
|
-

|
|
52
|
-
|
|
53
|
-

|
|
54
|
-
|
|
55
|
-
管理面板自上而下依次是:
|
|
56
|
-
|
|
57
|
-
1. **标题栏** —— 面板标题、`当前会话 n 个 · 当前工作区 n 个 · 活跃 n 个`、活跃浮窗开关与关闭按钮。
|
|
58
|
-
2. **搜索与范围行** —— 名称/标题/工作区搜索,`id: xxx` 专用于 Session ID 搜索;工作区、会话、排序、分组四个选择器同处一行。
|
|
59
|
-
3. **分类行**(展开筛选块后)—— 内置分类与自定义分类(带实时数量),自定义分类的新建与删除都在同一标签框内。
|
|
60
|
-
4. **筛选块** —— 默认折叠,只显示一行摘要(`当前工作区 · 当前会话 … · 全部` + `排序 · 最近活跃 分组 · 按会话`);点击该摘要行即可展开/收起,键盘 Enter/Space 同样有效(摘要行带 `role=button` / `aria-expanded`)。展开后才是上面的分类行、范围/会话/排序/分组选择器,以及选项行(隐藏一次性、隐藏长期未活跃、子代理背景色(浅色/深色)、重置筛选);折叠偏好仍然持久化。
|
|
61
|
-
5. **汇总行** —— `显示 n/m 个`、显示详情、显示已隐藏,以及批量操作入口。
|
|
62
|
-
6. **活跃子代理分组** —— 置顶且可折叠,带「一键暂停」;每行包含状态点(运行中为绿点,已结束按结束方式显示空心绿环或实心红点)、名称、Session ID、相对活动时间,以及 `◫` 在侧边栏打开、`⏸ 暂停`、`▶ 继续`、`⊘ 隐藏`、`🗑 删除`。
|
|
63
|
-
7. **详情区** —— 直接来自宿主只读投影的 `类型:… · 模型:…`,以及官方口径的用量行 `↑ 计费输入 (未缓存…) / ↓ 输出 · 命中 n% · n tps · n 轮 · n 步`;运行中的子代理都会显示最新的实时输出(不只当前选中的那一个),已完成的保留最终快照。
|
|
64
|
-
8. **活跃浮窗** —— 当前会话里运行中的子代理以紧凑浮窗常驻,每行带实时输出、用量行与暂停按钮;面板关闭且存在运行中子代理时自动出现。浮窗显示期间会为其中每个运行中的子代理各自保留实时会话,与主视图当前选中哪一个无关。
|
|
65
|
-
|
|
66
87
|
### 分类标签
|
|
67
88
|
|
|
68
89
|
内置分类包括:
|
|
@@ -102,14 +123,6 @@
|
|
|
102
123
|
- **子代理背景色自定义**:可开启/关闭子代理会话的独立背景色,支持分别配置深色主题与浅色主题下的背景色,进入子代理时一目了然。
|
|
103
124
|
- 重置筛选
|
|
104
125
|
|
|
105
|
-
### 暂停与一键暂停
|
|
106
|
-
|
|
107
|
-
- **浮窗一键暂停**:活跃子代理浮窗头部提供“⏸ 一键暂停”按钮,点击并二次确认后批量暂停所有活跃的可继续子代理。
|
|
108
|
-
- **浮窗单项暂停**:浮窗内每个正在运行的可继续子代理卡片均有“⏸ 暂停”按钮,点击确认后暂停该子代理。
|
|
109
|
-
- **管理面板单项暂停**:列表和活跃分组中的每个运行中可继续子代理均有“⏸ 暂停”按钮。
|
|
110
|
-
- **管理面板一键暂停**:“活跃子代理”折叠分组头部右侧提供“⏸ 一键暂停”按钮,支持一键暂停全部活跃子代理。
|
|
111
|
-
- **继续已结束的子代理**:已结束(非运行中)的可继续子代理行在操作区显示“▶ 继续”,点击后向该子代理发送一条**本地化**的继续指令(中文界面「继续」、英文界面 “continue”),让它接着跑。运行中与一次性子代理的行不显示该按钮;宿主没有该能力时**按钮不渲染**(纯能力探测,从不比较版本号)。管理器面板本身就在父会话 header 里,所以“父会话 agent 必须存活”这一前提在正常使用下天然满足;父会话不可用时只在控制台告警,不会把异常抛给用户。
|
|
112
|
-
|
|
113
126
|
隐藏是插件本地状态,只在列表不显示子代理,不会删除 DSH 会话或工作区文件。默认情况下:
|
|
114
127
|
|
|
115
128
|
- 列表不显示已隐藏子代理。
|
|
@@ -117,6 +130,14 @@
|
|
|
117
130
|
- 勾选“隐藏一次性”后,入口按钮统计也会扣除一次性子代理。
|
|
118
131
|
- 卡片右侧提供 **👁 隐藏** / **🙈 取消隐藏** 按钮。
|
|
119
132
|
|
|
133
|
+
### 暂停、继续与一键暂停
|
|
134
|
+
|
|
135
|
+
- **浮窗一键暂停**:活跃子代理浮窗头部提供“⏸ 一键暂停”按钮,点击并二次确认后批量暂停所有活跃的可继续子代理。
|
|
136
|
+
- **浮窗单项暂停**:浮窗内每个正在运行的可继续子代理卡片均有“⏸ 暂停”按钮,点击确认后暂停该子代理。
|
|
137
|
+
- **管理面板单项暂停**:列表和活跃分组中的每个运行中可继续子代理均有“⏸ 暂停”按钮。
|
|
138
|
+
- **管理面板一键暂停**:“活跃子代理”折叠分组头部右侧提供“⏸ 一键暂停”按钮,支持一键暂停全部活跃子代理。
|
|
139
|
+
- **继续已结束的子代理**:已结束(非运行中)的可继续子代理行在操作区显示“▶ 继续”,点击后向该子代理发送一条**本地化**的继续指令(中文界面「继续」、英文界面 “continue”),让它接着跑。运行中与一次性子代理的行不显示该按钮;宿主没有该能力时**按钮不渲染**(纯能力探测,从不比较版本号)。管理器面板本身就在父会话 header 里,所以“父会话 agent 必须存活”这一前提在正常使用下天然满足;父会话不可用时只在控制台告警,不会把异常抛给用户。
|
|
140
|
+
|
|
120
141
|
### 批量操作与永久删除
|
|
121
142
|
|
|
122
143
|
点击结果统计右侧的“批量操作”进入批量模式。批量模式下:
|
|
@@ -171,50 +192,37 @@
|
|
|
171
192
|
|
|
172
193
|
已结束的行还会用状态点区分结束方式:**正常结束为空心绿环,异常结束(⏸ 停止/aborted、error、blocked、max-tokens 等)为实心红点**,hover 显示「正常结束 / 异常结束」文字(zh+en)。判定只读子代理自身的公共只读投影 `subagentTiming.lastTurnCompleted`(宿主仅在 `turn/end` 写入、`turn/start` 删除);宿主不提供该投影时**保持原样**,绝不把“未知”显示成“正常”,运行中的行保持原绿点。
|
|
173
194
|
|
|
174
|
-
|
|
195
|
+
### 打开与查看子代理
|
|
175
196
|
|
|
176
|
-
|
|
197
|
+
- **精确地址打开**:点击卡片把子代理打开到主对话区,地址为 `{ parentSessionId, childSessionId, mode }`;批量模式下卡片整体变为选择区域,归档控件不会触发跳转。降级顺序见「打开子代理会话的三级能力探测」。
|
|
198
|
+
- **`◫` 在右侧边栏打开**:不离开主对话即可把子代理开成 DSH 自带的 `subagentchat` 标签页;纯能力探测,且按行、按次解析。详见「在右侧边栏打开子代理(`◫` 按钮)」。
|
|
199
|
+
- **类型与模型**:`provider/model`(宿主发布时附推理档位)只读宿主公开投影,类型与模型各自独立降级;不新增任何 RPC,也不提供模型切换入口。详见「类型与模型(只读投影)」。
|
|
200
|
+
- **行内用量**:卡片详情行与浮窗共用同一行 `↑ 计费输入 (未缓存…) / ↓ 输出 · 命中 n% · tps · 轮数 · 步数`,口径与官方 composer 页脚一致;完整信息(总量、各分桶、命中率、速度、模型/工具/首字耗时)在原生 `title` tooltip 中。
|
|
177
201
|
|
|
178
|
-
|
|
179
|
-
2. **搜索框**:普通文本搜索;使用 `id: xxx` 查询 Session ID。
|
|
180
|
-
3. **范围和排序行**:工作区、会话、排序、分组四个紧凑控件。
|
|
181
|
-
4. **分类标签行**:分类名称和数量。
|
|
182
|
-
5. **筛选块**:默认折叠为一行摘要(范围 · 会话 · 分类 | 排序 · 分组),点击摘要行或按 Enter/Space 展开;展开后包含分类标签、筛选选项(隐藏一次性、隐藏长期未活跃、子代理背景色、重置筛选)。
|
|
183
|
-
6. **结果统计**:显示当前结果数量和批量操作入口。
|
|
184
|
-
7. **结果列表**:活跃分组、会话/工作区分组、子代理卡片和实时状态。
|
|
185
|
-
8. **行内 `◫` 按钮**:在右侧边栏打开该子代理,主对话不跳转(见「在右侧边栏打开子代理」一节)。
|
|
186
|
-
9. **行内用量与统计**:卡片详情行与浮窗显示同一行 `↑ 计费输入 (未缓存…) / ↓ 输出 · 命中 n% · tps · 轮数 · 步数`,口径与官方 composer 页脚一致;完整信息(总量、各分桶、命中率、速度、模型/工具/首字耗时)在原生 `title` tooltip 中。
|
|
187
|
-
|
|
188
|
-
插件不在左侧全局菜单增加入口按钮;入口仅位于会话标题栏。
|
|
189
|
-
|
|
190
|
-
## 安装
|
|
191
|
-
|
|
192
|
-
在插件目录执行:
|
|
193
|
-
|
|
194
|
-
```bash
|
|
195
|
-
dsh plugin --profile web add file:.
|
|
196
|
-
```
|
|
202
|
+
## 界面截图
|
|
197
203
|
|
|
198
|
-
|
|
204
|
+
两张截图拍摄于 `1.7.0-dev` 分支(commit `79d9d0f`)上真实运行的 dsh **0.1.6-alpha.2** 实例,深色主题。拍摄时同一个会话里并存 4 个后台子代理——3 个仍在运行、1 个已完成,因此每行都能展示真实的类型、模型与用量数字。这里是中文界面;英文界面两张见 [`README.md`](README.md)。
|
|
199
205
|
|
|
200
|
-
|
|
201
|
-
dsh plugin --profile web remove dsh-subagent-workspace-ui
|
|
202
|
-
dsh plugin --profile web add file:.
|
|
203
|
-
```
|
|
206
|
+

|
|
204
207
|
|
|
205
|
-
|
|
208
|
+

|
|
206
209
|
|
|
207
|
-
|
|
208
|
-
http://127.0.0.1:3080
|
|
209
|
-
```
|
|
210
|
+
### 图注
|
|
210
211
|
|
|
211
|
-
|
|
212
|
+
管理面板自上而下依次是:
|
|
212
213
|
|
|
213
|
-
|
|
214
|
+
1. **标题栏** —— 面板标题、`当前会话 n 个 · 当前工作区 n 个 · 活跃 n 个`、活跃浮窗开关与关闭按钮。
|
|
215
|
+
2. **搜索与范围行** —— 名称/标题/工作区搜索,`id: xxx` 专用于 Session ID 搜索;工作区、会话、排序、分组四个选择器同处一行。
|
|
216
|
+
3. **分类行**(展开筛选块后)—— 内置分类与自定义分类(带实时数量),自定义分类的新建与删除都在同一标签框内。
|
|
217
|
+
4. **筛选块** —— 默认折叠,只显示一行摘要(`当前工作区 · 当前会话 … · 全部` + `排序 · 最近活跃 分组 · 按会话`);点击该摘要行即可展开/收起,键盘 Enter/Space 同样有效(摘要行带 `role=button` / `aria-expanded`)。展开后才是上面的分类行、范围/会话/排序/分组选择器,以及选项行(隐藏一次性、隐藏长期未活跃、子代理背景色(浅色/深色)、重置筛选);折叠偏好仍然持久化。
|
|
218
|
+
5. **汇总行** —— `显示 n/m 个`、显示详情、显示已隐藏,以及批量操作入口。
|
|
219
|
+
6. **活跃子代理分组** —— 置顶且可折叠,带「一键暂停」;每行包含状态点(运行中为绿点,已结束按结束方式显示空心绿环或实心红点)、名称、Session ID、相对活动时间,以及 `◫` 在侧边栏打开、`⏸ 暂停`、`▶ 继续`、`⊘ 隐藏`、`🗑 删除`。
|
|
220
|
+
7. **详情区** —— 直接来自宿主只读投影的 `类型:… · 模型:…`,以及官方口径的用量行 `↑ 计费输入 (未缓存…) / ↓ 输出 · 命中 n% · n tps · n 轮 · n 步`;运行中的子代理都会显示最新的实时输出(不只当前选中的那一个),已完成的保留最终快照。
|
|
221
|
+
8. **活跃浮窗** —— 当前会话里运行中的子代理以紧凑浮窗常驻,每行带实时输出、用量行与暂停按钮;面板关闭且存在运行中子代理时自动出现。浮窗显示期间会为其中每个运行中的子代理各自保留实时会话,与主视图当前选中哪一个无关。
|
|
214
222
|
|
|
215
|
-
|
|
223
|
+
插件不在左侧全局菜单增加入口按钮;入口仅位于会话标题栏。
|
|
216
224
|
|
|
217
|
-
|
|
225
|
+
## 数据边界
|
|
218
226
|
|
|
219
227
|
插件只管理当前 DSH Web 客户端运行时已经发现的子代理目录,不伪造不存在的历史数据。首次加载以 40 条为一页;普通分页可以继续加载,批量时间选择最多扩展到 1000 条。
|
|
220
228
|
|
|
@@ -274,6 +282,20 @@ ctx.sessions.list.getSnapshot().byId[childId].projectionValues.modelSelection
|
|
|
274
282
|
- 宿主未提供该投影(例如 **0.1.1-rc.2**)、投影值为空或 provider/model 为空串时,统一显示兜底文案 **模型未知**(英文界面 `model unknown`),不会出现空白或 `null/null`。该兜底使用独立 i18n 键 `modelUnknown`,不复用 `typeLoading`:老版本宿主上类型与模型各自独立降级(实测同行为 `类型:类型加载中… · 模型未知`)。
|
|
275
283
|
- **只读、无切换入口**:插件不调用 `selectedModel` 等任何模型写入 API,也不提供模型切换 UI;官方 SDK 对子代理地址的模型选择明确不可用(`model selection is unavailable for addressed subagent sessions`)。
|
|
276
284
|
|
|
285
|
+
归档、分类和最近使用顺序保存在浏览器本地 `localStorage` 中,不会写入 DSH 会话日志。
|
|
286
|
+
|
|
287
|
+
## 兼容性
|
|
288
|
+
|
|
289
|
+
v1.8.0 及以后版本支持 dsh **0.1.5-rc.3**、**0.1.6-alpha.2**、**0.1.7-rc.1**、**0.1.7-rc.2** 与 **0.2.0-rc.1**,并对所有 DeepSeek Harness 版本保持向后兼容。这些宿主分属两代接口——0.1.5-rc.3 与 0.1.6-alpha.2 仍发布 `subagentsByParent`、`refreshSubagents` 与 `setSubagentCatalogOpen`,而 0.1.7-rc.1 删除了 `sessions.setSubagentCatalogOpen`、把 `refreshSubagents(parentSessionId)` 改名为 `refreshProjections(sessionId)`、并把 `SessionListState.subagentsByParent` 换成父会话自身的 `subagentCatalog` 投影。插件对每一项都做能力探测,因此两代宿主各自走可用路径,**从不比较版本号**。
|
|
290
|
+
|
|
291
|
+
**0.2.0-rc.1** 用同一套方法核对——以 **0.1.7-rc.1** 为基线逐包比对(23 个宿主包,外加 CLI、app-boot 与 web 前端),**不把 release note 当接口变更清单**——结论同样是**无需适配**:本插件读取的宿主面没有任何结构性变化。它注册的两个 slot 声明、模块加载壳及其种子 `require` 键、`subagentCatalog` / `subagent` / `subagentTiming` 三个投影(含世代性字段 `lastTurnCompleted`)、`subagentAddress` / `openResource` / `candidates`、`dsh plugin --profile web add` 流程,以及本插件用到的全部 21 个 `--dsw-*` token,都未变或仅纯增量;契约上唯一的新增是可选参数 `fork(onCreated)`(本插件不调用),而宿主 web graph 移除 `ui-schedule` 行既不触及本插件,也不影响它的 slot 屏蔽。两处差异可见但不构成破坏:面板与浮窗玻璃材质用到的暗色 token 改了取值;右侧栏服务的注册时刻比 0.1.7-rc.1 **更晚**(见下文「在右侧边栏打开子代理」)。
|
|
292
|
+
|
|
293
|
+
**0.2.0-rc.1** 上实测面板渲染一致:父会话带 6 个目录子代理时,管理器列出全部 6 行及其目录标签、每行 `类型:可继续`、每行 `◫` 均可用;被挂载过的子会话,其已结束行显示空心绿环,并带该子代理自己的模型与用量数字——与同一份会话数据上的 **0.1.7-rc.1** 运行结果逐行一致;两版上点击 `◫` 都能把该子代理打开为右侧栏标签页。
|
|
294
|
+
|
|
295
|
+
**0.1.5-rc.3** 上实测无降级:全新实例 + 一个运行中子代理时,管理器在实时会话上正常打开,行显示目录标签、`类型:可继续`、具体模型 id、`◫`、暂停/隐藏/删除、渲染该子代理正在运行的 `bash` 工具的实时输出区,以及用量数字——控制台没有来自本插件的错误。
|
|
296
|
+
|
|
297
|
+
**0.1.7-rc.2** 同样无需适配;它暴露出此前兼容矩阵的一处**漏检**:stock `ui-subagent` 注册的是**两个** header 单元,而不是一个。除了 `conversation.session.header.lineage` 的 lineage 下拉,**0.1.7-rc.1** 还在 `conversation.session.header.actions` 里新增了第二个注册(`id: "subagent-catalog"`、`order: -30`),只要当前会话的 `subagentCatalog` 投影已加载,它就渲染官方的「N 个子智能体」计数下拉。该槽是 `list` 槽、cell 按 `id` 划分,管理器自己的 `subagent-workspace-manager` cell 与它从不相争,因此两个入口会并存——本插件现在也遮蔽这个 cell(`priority: -1`,渲染 `null`),与遮蔽 lineage 槽完全同形;若未来宿主在同一 cell 占用同一优先级,两处遮蔽都会降级为「官方入口可见」而不会让插件失效。已在 **0.1.7-rc.1**、**0.1.7-rc.2** 与 **0.2.0-rc.1** 上用同一份「父会话 + 6 个子代理」数据实测:header 只剩 `🧩 Subagents 0/6`,面板仍列出 6 行,行上的 `◫` 仍能把该子代理打开为官方 `subagentchat` 右侧栏标签页。而在 **0.1.5-rc.3** 与 **0.1.6-alpha.2** 上——它们的 stock 包**没有**这个注册——多出的遮蔽 cell 不会在 header 里产生任何元素,也不抛错。
|
|
298
|
+
|
|
277
299
|
### 打开子代理会话的三级能力探测
|
|
278
300
|
|
|
279
301
|
```text
|
|
@@ -289,8 +311,6 @@ ctx.get('uiWorkspace').openSession({ parentSessionId, childSessionId, mode } | s
|
|
|
289
311
|
|
|
290
312
|
`uiWorkspace` 通过 `ctx.get('uiWorkspace')` 读取,而不是必填注入,因此未注册该服务的宿主(**0.1.2-alpha.5** 之前的全部版本)仍能正常加载并继续走会话控制器路径;而移除了 `openSubagent`/`open` 的 **0.1.6-alpha.2** 则走工作区服务。**探测顺序按「参数形态」而不是版本号决定**:`sessions.openSubagent` 在所有带它的宿主上都吃 address 对象,而 `uiWorkspace.openSession` 直到 **0.1.6-alpha.2** 才接受 `SessionTarget`——在 **0.1.5-alpha.2 … 0.1.6-alpha.1** 上它是 `openSession(sessionId)`,内部走 `sessions.open(id)`,传入对象会抛错。因此先试会话控制器一级、把工作区服务作为兜底。控制器路径下优先使用 `{ parentSessionId, childSessionId, mode }` 精确地址,仅在缺少 mode/child 时才降级为普通会话导航,因为 `openSubagent` 会拒绝非健康目录子项的地址。0.1.2 系列能力探测路径(实时输出走 `binding.eventSource`、对话标签切换走 slot `actions`)仍为首选分支,**0.1.1-rc.2** legacy 回退路径保持不变。本版本与 **v1.8.0** 一样支持 dsh **0.1.5-rc.3**、**0.1.6-alpha.2** 与 **0.1.7-rc.1**,并向下兼容所有 DeepSeek Harness 版本。
|
|
291
313
|
|
|
292
|
-
归档、分类和最近使用顺序保存在浏览器本地 `localStorage` 中,不会写入 DSH 会话日志。
|
|
293
|
-
|
|
294
314
|
### 在右侧边栏打开子代理(`◫` 按钮)
|
|
295
315
|
|
|
296
316
|
管理面板的每个子代理条目、以及活跃子代理浮窗的每一行,都带一个 `◫` 图标按钮:点击后**不离开当前主对话**,直接把这个子代理作为 DSH 右侧栏的 `subagentchat` 标签页打开,标签标题就是子代理的名称/label。两处行为完全一致(浮窗只是紧凑样式),并遵循同一套降级规则:
|
|
@@ -307,7 +327,7 @@ ctx.sessions.subagentAddress → 是函数(按行取地址)
|
|
|
307
327
|
# 验证为空 → 该行按钮渲染为禁用态并给出可读说明,绝不抛异常给用户。
|
|
308
328
|
```
|
|
309
329
|
|
|
310
|
-
两个能力面**按行、按次解析,绝不在激活时只探测一次**:dsh **0.1.7-rc.1** 在本插件 `apply` **之后**才注册 `sidebarRight`/`sidebarRightTabs`(**0.1.6-alpha.2** 在 `apply` 时已就绪),因此激活时的一次性探测会让新宿主上的整列 `◫` 消失,而旧宿主毫无异样。
|
|
330
|
+
两个能力面**按行、按次解析,绝不在激活时只探测一次**:dsh **0.1.7-rc.1** 在本插件 `apply` **之后**才注册 `sidebarRight`/`sidebarRightTabs`(**0.1.6-alpha.2** 在 `apply` 时已就绪),因此激活时的一次性探测会让新宿主上的整列 `◫` 消失,而旧宿主毫无异样。dsh **0.2.0-rc.1** 把这个窗口推得更晚:它的 `ui-sidebar-right` 现在还要注入 `shortcuts`,即发布这两个能力面之前要多等一个服务。正是「按行、按次解析」让 `◫` 列在这些宿主上都能正常渲染。
|
|
311
331
|
|
|
312
332
|
要点:
|
|
313
333
|
|
|
@@ -329,6 +349,16 @@ pnpm run check # 构建 + tsc --noEmit + node --check lib/index.js + 产物
|
|
|
329
349
|
|
|
330
350
|
`pnpm run verify:build` 会对生成的 `lib/client.js` 与改造前的手写版本(git 引用 `v1.3.4`)做 token 级与行级比对;迁移完成后它同时充当差异查看器,可精确显示任何有意改动引入的 token/行差异。
|
|
331
351
|
|
|
352
|
+
### 本地 checkout(贡献者)
|
|
353
|
+
|
|
354
|
+
要在克隆出来的工作区上迭代(而不是用 npm 发布版),在仓库根执行:
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
dsh plugin --profile web add file:.
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
profile 安装是 store 拷贝,因此改动 `src/client/*.ts` 后必须 `pnpm run build` 并重新 add 插件(或直接跑 `./test.sh`),Web UI 才会生效;宿主入口(`lib/index.js`)的改动一律需要重启 `dsh web`。同一条贡献者回路也记录在 [`AGENTS.md`](AGENTS.md) 中。
|
|
361
|
+
|
|
332
362
|
### 冒烟测试(可指定 dsh 版本)
|
|
333
363
|
|
|
334
364
|
```bash
|
|
@@ -341,163 +371,14 @@ DSH_PLUGIN_DIR=.worktrees/x ./test.sh # 冒烟其它 checkout 的产物
|
|
|
341
371
|
|
|
342
372
|
`DSH_HOME` 固定用隔离目录(`$HOME/tmp/dsh-test`,可用 `DSH_SMOKE_HOME=/path` 覆盖),并在启动前拒绝把真实 `~/.dsh` 当冒烟目录。`DSH_VERSION` 非空时用 `pnpx @deepseek-ai/dsh@<version>` 运行,可用于冒烟任意 dsh 版本(如 0.1.6-alpha.2、legacy 的 0.1.1-rc.2)。pnpm 12 默认忽略依赖的生命周期脚本,脚本会为 dsh 的原生依赖逐个传 `--allow-build=<pkg>`(清单可用 `DSH_ALLOW_BUILDS=…` 覆盖)。
|
|
343
373
|
|
|
344
|
-
##
|
|
345
|
-
|
|
346
|
-
- UI 本地化(zh/en)由 [@Marcuss2](https://github.com/Marcuss2) 在 [PR #1](https://github.com/miuzel/dsh-subagent-ui/pull/1) 中贡献,特此致谢!
|
|
347
|
-
- 子代理永久删除、会话生命周期清理及快照刷新机制的设计参考并致谢开源项目:[@heiheiha798/dsh-plugin-subagent-delete](https://github.com/heiheiha798/dsh-plugin-subagent-delete)。
|
|
348
|
-
|
|
349
|
-
## v1.9.0 发布说明
|
|
350
|
-
|
|
351
|
-
- **特性:在管理器中让已结束的子代理继续运行**。行的操作区(`⏸ 暂停` / `⊘ 隐藏` / `🗑 删除` 一组)新增“▶ 继续”,点击后向该子代理发送一条**本地化**的继续指令(中文界面「继续」、英文界面 “continue”),让它接着跑。实现是纯能力探测、**从不比较版本号**:有 `retain` 的宿主(0.1.6-alpha.2 起,含 0.1.7-rc.1)走 `sessions.retain(...)` → `binding.session.prompt([{ type: 'text', text: '继续' }], 'queue')`(英文界面传入 `'continue'`),**0.1.5-rc.3** 没有 `retain`,走借用 `sessions.binding` 得到的同一个 face,同样可用。宿主没有该能力时**按钮不渲染**;运行中与一次性子代理的行也不显示该按钮;管理器面板本身就在父会话 header 里,因此“父会话 agent 必须存活”在正常使用下天然满足(父会话不可用时只在控制台告警,不会变成未捕获的异常)。
|
|
352
|
-
- **特性:筛选块默认折叠**。管理器筛选块首次打开即为折叠态,只显示一行摘要(`当前工作区 · 当前会话 … · 全部` + `排序 · 最近活跃 分组 · 按会话`);点击该摘要行即可展开/收起,键盘 Enter/Space 同样有效(摘要行带 `role=button` / `aria-expanded`)。折叠偏好仍持久化。顺带修掉一个 bug:此前在偏好未设置时,切换按钮因 `!undefined === true` 只能折叠、无法展开。
|
|
353
|
-
- **特性:已结束子代理区分正常/异常结束**。正常结束显示**空心绿环**,异常结束(⏸ 停止/aborted、error、blocked、max-tokens 等)显示**实心红点**,hover 显示「正常结束 / 异常结束」文字(zh+en)。数据只来自子代理自身的公共只读投影 `subagentTiming.lastTurnCompleted`(宿主仅在 `turn/end` 写入、`turn/start` 删除);宿主不提供该投影时**保持原样**,绝不把“未知”显示成“正常”。该判定字段自 **dsh 0.1.7-alpha.1** 起才由宿主投影:**0.1.5-rc.3** 与 **0.1.6-alpha.2** 只发布 `{ settledMs, active? }`,因此那两台宿主上已结束行保持中性状态点、不区分结束方式(有据才下结论,绝不伪造判据)。运行中的行保持原绿点。
|
|
354
|
-
- **兼容性**:以上三项都只依赖能力探测、**从不比较版本号**;v1.9.0 与 v1.8.0 一样支持 dsh **0.1.5-rc.3** / **0.1.6-alpha.2** / **0.1.7-rc.1**(已在三台上实测;终态标记在 0.1.5-rc.3 / 0.1.6-alpha.2 上按上述边界保持中性点)。本版代码改动只有两处——行操作按钮对齐(`src/client/styles.ts`)与一处失实注释订正(`src/client/format.ts`)——其余为版本号与文档:`pnpm run check` 全绿(bundle 新鲜度一致)。
|
|
355
|
-
|
|
356
|
-
## v1.8.0 发布说明
|
|
357
|
-
|
|
358
|
-
- **修复:只有当前被选中的子代理才更新实时输出**。`sessions.binding(id)` 只是**借用**别人已经保留的绑定,而官方视图只保留主视图当前选中的那一个会话——于是其余子代理根本没有实时区域。现改为插件**自己成为保留者**:浮窗保留它显示的每个运行中子代理、面板保留它渲染的运行中行,两者共用上限 8(浮窗优先、最近活跃优先),行停止渲染或停止运行、界面关闭、插件卸载时成对释放;宿主没有 `retain`、以及超出上限的行,仍回落到借用式绑定、再回落到持久化摘要。随之落地的一项修复:**未选中行的「暂停」现在真正生效**——此前它调用的是一个并不存在的绑定,属于静默空操作。
|
|
359
|
-
- **兼容 dsh 0.1.7-rc.1**:该宿主**删除**了 `sessions.setSubagentCatalogOpen`、把 `refreshSubagents(parentSessionId)` **改名**为 `refreshProjections(sessionId)`、并把 `SessionListState.subagentsByParent[parent]` **换成**父会话自身的 `projectionValues.subagentCatalog` 投影(同一批直接子代理,目录事件顺序;条目去掉了 `kind` 判别字段,并多出一个 `mode: 'unknown'` 取值)。在缺少防护的旧实现里,被删除的方法从管理器面板的打开副作用里抛出,错误边界随即带走整个标题栏 slot——**点开管理器会让标题栏直接崩掉**。现在所有宿主调用一律能力探测、**从不比较版本号**:同一个取值函数在 0.1.7-rc.1 及以上读父会话的 `subagentCatalog`、在 0.1.6-alpha.2 及以前读 `subagentsByParent`(宿主两者都发布时旧来源优先,因此旧宿主读到的与改动前逐字相同),刷新优先 `refreshProjections`、回落 `refreshSubagents`,`setSubagentCatalogOpen` 缺失则跳过;`mode` 为 `unknown` 的条目保留 label,并把类型让给子会话自身的身份投影,而不是直接采信该取值。
|
|
360
|
-
- **修复:0.1.7-rc.1 上每行的 `◫`「在侧边栏打开」整列消失**。该宿主在本插件 `apply` **之后**才注册 `sidebarRight`/`sidebarRightTabs`,激活时的一次性探测便把两者永久判为不存在。现改为**按行、按次**解析:从不发布这两个能力的宿主依旧完全不渲染按钮(与改动前逐字相同),而能力可用但该行地址校验不通过时,仍保留既有的禁用按钮与可读原因。
|
|
361
|
-
- **文档**:类型/模型阶梯补上两代目录来源;兼容性小节记录上述 0.1.7-rc.1 接口变化。
|
|
362
|
-
- **微调:活跃浮窗背景固定为 95% 不透明度**。dsh **0.1.7-rc.1** 把 `--dsw-specific-menu` 改成了带透明度的「玻璃」色——深色主题 `#30313680`(alpha `0x80` = 50%)、浅色 `#f8f9fa94`(58%)——而 0.1.6 把同一个令牌指向不透明的 `--dsw-alias-bg-layer-3`,于是浮窗在新宿主上变得半透明。现在浮窗改用宿主**不透明**的表面色令牌按**恰好 95%** 合成(`color-mix`,并把旧声明保留在其前,作为不具备 `color-mix` 的宿主的回落),顺带让浮窗在 0.1.6 与 0.1.7 上的观感一致——不判断版本号,色调仍来自宿主自己的主题令牌。
|
|
363
|
-
|
|
364
|
-
已在 dsh **0.1.6-alpha.2** 与 **0.1.7-rc.1** 上验证:`pnpm run check` 全绿(bundle 新鲜度一致,98,439 字节)。0.1.7-rc.1 上打开一个真实运行中的会话,面板列出全部 7 个子代理,行名回到目录标签、`Type: continuable`、模型与用量齐全、每行都有 `◫`,且**点击后控制台没有任何错误**;0.1.6-alpha.2 上面板对象与改动前逐字节相同,同一批数据仍显示与改动前相同的未知项(宿主从未发布过投影的子代理依旧是 `model unknown`,与 0.1.6 上的表现完全一致)。浮窗背景随后在一个真实运行中的 0.1.7-rc.1 实例上做了像素测量:它渲染为 `rgb(51,52,54)`,正是 `#353638` 按 95% 合成、叠在其身后的 `rgb(21,21,23)` 标题栏背景上的精确预测值,而此前的 50% 玻璃色在该处应渲染成 `rgb(34,35,38)`;把同一个浮窗放到亮 22 级的背景(`rgb(43,43,45)`)上,它最多只变化 1 级——这正是 95% 表面的行为,50% 表面不可能如此(它会变化 11 级)。0.1.7-rc.1 宿主自带的 `dsh-client-ui-open-in-app` 会在加载期报一条 `inactive context`,与本插件无关,本次刻意不动。
|
|
365
|
-
|
|
366
|
-
## v1.7.0 发布说明
|
|
367
|
-
|
|
368
|
-
- **修复:`◫`「在侧边栏打开」按钮的点击面积远小于 24×24 CSS px 下限**:面板行实测 18.03×16、活跃浮窗 17.14×17,等于只有字形本身可点。现分别为 **24.03×24** 与 **24.14×25**,而**布局盒、字形位置、行高与相邻按钮坐标逐像素不变**——padding 的增量被等量负 margin 抵消,hover 药丸改由 `::after` 伪元素承载、其 inset 恰好还原原边框盒(18.03×16 / 17.14×17)。唯一的渲染差异是合成顺序:hover 叠加层现在画在字形**之上**而非之下(深色主题每通道 ≲1.3/255、浅色 ≲0.7/255,肉眼不可分辨)。禁用行仍保持透明度与 `not-allowed` 光标;扩大后的区域不会把「按行」变成「拖浮窗」——`closest('button,input,label')` 判定的是 DOM 祖先而非几何。
|
|
369
|
-
- **文档:dshmarket 截图重拍**:在 `1.7.0-dev` 分支(commit `79d9d0f`)上真实运行的 dsh **0.1.6-alpha.2** 实例拍摄,管理器面板与活跃浮窗各出中英两张(`*.en.png`,**真正切换宿主语言**而非给中文图配英文题注),深色主题、1280×900 CSS @ DPR 1.75。拍摄时同一会话并存 4 个后台子代理(3 个运行中、1 个已完成),因此每行都带**真实**类型、模型与官方口径用量行(不再是兜底文案),`◫`、暂停、隐藏、删除四个动作齐全。`screenshots.json` 现列出全部四条路径(dshmarket 轮播上限 6),两个 README 各自引用对应语言的图(不再共用同一对),且「界面截图」导览已按新 UI 重写——旧导览仍在描述本版已不存在的控件(「显示已归档」「→ 归档」等)。
|
|
370
|
-
|
|
371
|
-
已在 dsh **0.1.6-alpha.2** 上实机验证:`pnpm run check` 全绿——本版产物只有命中区这一处 CSS 改动,截图工作未触碰任何源码(只改 4 张 PNG + `screenshots.json` + 两个 README)。命中区另经几何核算(padding / margin / `::after` inset 与原边框盒的算式)与按钮列改造前后的像素剖面对照;并用隔离 `DSH_HOME` 跑 `./test.sh` 冒烟:在面板行与浮窗上点击**新增的边缘**内侧都能打开侧边栏、孤儿禁用行行为正确,且 A/B 验证了按按钮不会变成拖浮窗、也不会误触邻居的暂停按钮。
|
|
374
|
+
## 发布说明
|
|
372
375
|
|
|
373
|
-
|
|
376
|
+
完整发布说明——每个版本、新版本在前——都在更新日志中:
|
|
374
377
|
|
|
375
|
-
-
|
|
376
|
-
-
|
|
377
|
-
- **修复:类型在打开过一次管理面板前显示「类型待加载」**:此前 mode 只从「惰性拉取的子代理目录」读取,而该目录只有管理面板会拉,于是宿主明明已发布 mode、界面却落兜底,且打开一次面板后同一条目会突然「变对」。现改为同一个取值函数、同一回退顺序:① 已发现的目录条目 → ② 子会话自身的 `subagent` 身份投影(随实时控制流与每次 session-added 摘要下发,刷新页面即已具备)→ ③ 既有兜底文案;因此**不打开面板**、首屏即正确。刚派生的子代理在被发现前,其侧边栏按钮可能短暂禁用——这是既有的能力探测行为,不是缺陷。
|
|
378
|
-
- **修复:行内用量与官方 composer 页脚对不上**:同一子代理,插件显示 `in 39.1k / out 12.7k · cache hit 64%`,官方页脚显示 `143K tok · Cache hit 70%`。原因有二:行内「输入」实为**未缓存输入**这一桶,且命中率分母取了**四项总和**(把输出 token 也算进提示词侧比例)。现全部改为官方口径:`↑ 计费输入 (未缓存…) / ↓ 输出 · 命中 n% · tps · 轮数 · 步数`,命中率分母只取计费输入,`tps = decodeTokens / (decodeMs / 1000)`(取自同一个公开 `sessionStats` 投影);完整信息——总量、各分桶、命中率、速度、以及模型/工具/首字耗时——移入行与浮窗的原生 `title` tooltip。官方命中率格式化函数已逐表达式移植,**部分命中永远不会被凑成 100%**。
|
|
379
|
-
- **文档**:把血统 slot 遮蔽如实描述为**标题位遮蔽**。宿主会话模块在该 slot 一旦存在条目就会替换调用方 fallback,因此字面上的「空占位」会删掉子代理会话的标题。
|
|
378
|
+
- [`CHANGELOG.zh.md`](https://github.com/miuzel/dsh-subagent-ui/blob/HEAD/CHANGELOG.zh.md) —— 中文完整版,回溯至 v1.0.1。
|
|
379
|
+
- [`CHANGELOG.md`](https://github.com/miuzel/dsh-subagent-ui/blob/HEAD/CHANGELOG.md) —— English, back to v1.3.2。
|
|
380
380
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
## v1.5.0 发布说明
|
|
384
|
-
|
|
385
|
-
- **修复:dsh 0.1.6-alpha.2 点击子代理行无法打开会话**:报错 `TypeError: ctx.sessions.openSubagent is not a function`,且该错误被行点击的 `try`/`catch` 吞掉,界面表现为「点了没反应」。0.1.6-alpha.2 删除了 `sessions.openSubagent(address)` 与 `sessions.open(id)`;插件改为运行时三级能力探测(`sessions.openSubagent` → `sessions.open` → `uiWorkspace.openSession`),不再硬切调用,同一份产物在上下游变更两侧都能工作;三级都不可用时在界面上提示当前版本不支持。
|
|
386
|
-
- **修复:三级探测的顺序按参数形态决定**:**0.1.5-alpha.2 … 0.1.6-alpha.1** 这一带同时存在两级 API,但其中的 `uiWorkspace.openSession(sessionId)` 只接受字符串,传入 address 会走 `sessions.open(id)` 并抛 `sessions.select: unknown session [object Object]`;而 `sessions.openSubagent(address)` 在这些宿主上仍然存在且吃对象。若优先试工作区服务,该异常会被吞掉并误报「当前版本不支持」,因此改为 address 先走会话控制器一级、`uiWorkspace` 作为 0.1.6-alpha.2+ 的兜底。已在危险带两侧实机验证:**0.1.5-alpha.1**(客户端包 0.1.5-rc.2)上顺序修正后的产物约 142 ms 完成会话切换、无告警、无导航报错;**0.1.6-alpha.2** 上服务端实际下发的产物仍命中 `uiWorkspace.openSession` 并正常打开子代理会话。
|
|
387
|
-
- **修复:dsh 0.1.6-alpha.2 的 `current` 字段缺失**:会话列表快照不再提供 `current`,而当前会话解析与「对话」标签页兜底依赖它。两处均已优雅退化——兜底逻辑识别 `current` 缺失后立即尝试点击宿主自身的「对话」标签,并在 2 秒内安静放弃,不再空转 8 秒。
|
|
388
|
-
|
|
389
|
-
## v1.4.0 发布说明
|
|
390
|
-
|
|
391
|
-
- **支持 DeepSeek Harness 0.1.5-rc.2,向下兼容所有 dsh 版本**:适配 0.1.5-rc.2 的对话页视图结构变化(slot 渲染器不再向未声明 store 的注册项注入 `actions`;视图选择改为按会话持久化,新增「轨迹」等标签页)——点击子代理重新正确落回「对话」标签页(`actions` 缺失时改为点击宿主自身的「对话」标签完成切换,激活与持久化语义完整)。0.1.2 系列能力探测路径保留为首选分支、调用方式不变,0.1.1 legacy 回退路径零改动,旧版本行为完全一致。
|
|
392
|
-
- **客户端迁移至 TypeScript**:`src/client/*.ts` 成为唯一源码,`lib/client.js` 由 `pnpm run build`(sucrase 逐字类型擦除 + 确定性链接)生成,不再手写。新增 `verify-build`(与 v1.3.4 手写 golden 做 token/行级比对——迁移等价证明兼有意改动差异查看器)与 `verify-fresh`(过期 bundle 门禁);`pnpm run check` 一键完成构建 + 类型检查 + 语法检查 + 新鲜度校验。
|
|
393
|
-
- **修复:筛选摘要潜伏 ReferenceError**:折叠筛选区且选中具体工作区时,`scopeKey` 未定义变量导致报错,已修正为 `workspaceKey`(TS 迁移期间发现)。
|
|
394
|
-
|
|
395
|
-
## v1.3.4 发布说明
|
|
396
|
-
|
|
397
|
-
- **特性:UI 本地化(zh/en)**:通过 DSH client-locale 将插件全部 UI 文案本地化,支持中文/英文(英文为 AI 辅助翻译)。标签、按钮、统计、实时输出(上下文注入 / 思考中 / 工具说明)、确认弹窗等均改为走翻译键;跟随宿主语言切换。由 [@Marcuss2](https://github.com/Marcuss2) 在 [PR #1](https://github.com/miuzel/dsh-subagent-ui/pull/1) 中贡献,感谢!
|
|
398
|
-
|
|
399
|
-
## v1.3.3 发布说明
|
|
400
|
-
|
|
401
|
-
- **修复:批量删除大数量不再报错**:服务端请求体上限从 64 KiB 提升到 8 MiB,批量删除选中数百上千个子代理时不再触发「body too large」导致「删除请求失败」。
|
|
402
|
-
- **特性:隐藏详情时 tooltip 查看统计**:关闭「显示详情」后,行/名字的悬停 tooltip 显示 `输入/输出 · 缓存命中 · 轮数 · 步数` 统计。
|
|
403
|
-
- **修复:实时输出显示上下文注入与思考**:新 API 实时推导此前漏掉了 `user/message` 上下文注入;已补齐 `上下文注入 · <form>` 行,并修复思考被活动行掩盖的问题。
|
|
404
|
-
- **特性:思考中用动画图标标示**:运行中思考阶段显示旋转的「思考中…」,不再依赖低优先级的思考文本。
|
|
405
|
-
|
|
406
|
-
## v1.3.2 发布说明
|
|
407
|
-
|
|
408
|
-
- **性能优化(显著降低卡顿)**:
|
|
409
|
-
- 子代理管理器改为单次基础扫描(`subagentRows`),`allRows`/`activeRows`/`tabCounts` 不再各自全表扫描并重复合并 `modeMap`;`tabCounts` 用延迟值计算、面板关闭时不计算。
|
|
410
|
-
- `useSessions` 细粒度订阅(只订阅 `byId`/`subagentsByParent`/`current` 三字段并浅比较),无关的会话帧不再触发整组重渲染。
|
|
411
|
-
- 活跃浮窗/面板**限制同时实时订阅的子代理数**(`liveCap`,默认 3,`0`=不设限);关闭实时显示或关闭浮窗/面板时**完全停止 live 订阅并释放资源**,而非仅隐藏。
|
|
412
|
-
- **点击子代理自动切换到「对话」选项卡**:进入子代理时自动落到对话视图。
|
|
413
|
-
- **修复:批量「选择 N 小时前」**:按当前视图一次性选中真正超过 N 小时的子代理(数量准确),可正常增减,取消后不会自动勾回。
|
|
414
|
-
|
|
415
|
-
## v1.3.1 发布说明
|
|
416
|
-
|
|
417
|
-
- **兼容 dsh 0.1.2-alpha.2 与 0.1.1-rc.2**:实时输出按能力探测自动切换两条链路——新版本(0.1.2-alpha.2)走 `binding.eventSource` 原始事件流推导;旧版本(0.1.1-rc.2 及更早)回退 `chat.legacy` 对话快照。老版本行为不变,向前兼容。
|
|
418
|
-
- **实时工具调用显示说明/文件名**:进行中与已完成的工具调用现在优先显示工具 `description` 或目标 `path/file_path`(例如 `bash · Print current working directory`、`write · subagent-AJ.txt`),不再只有工具名。工具参数跨分片累积,参数完整后才渲染详情,避免流式过程中显示残缺 JSON。
|
|
419
|
-
- **清理**:移除已不存在的 `dsh-client-runtime` 客户端注入引用。
|
|
420
|
-
- **测试脚本支持指定版本**:`DSH_VERSION=0.1.1-rc.2 ./test.sh` 可冒烟测试旧版本兼容性。
|
|
421
|
-
|
|
422
|
-
## v1.2.4 发布说明
|
|
423
|
-
|
|
424
|
-
- **批量选择优化**:修复批量模式下直接点击 checkbox 偶现无响应的问题;支持 Shift 连选与连续批量取消选中(跟随上一次点击意图)。
|
|
425
|
-
|
|
426
|
-
## v1.2.3 发布说明
|
|
427
|
-
|
|
428
|
-
- **按需加载优化**:列表默认仅自动加载最近 10 个子代理的历史最新消息;更早的历史子代理默认不建立会话绑定,改为显示「📥 加载最新消息」按钮,大幅降低大列表初始加载时的资源开销。
|
|
429
|
-
- **运行中不受限制**:正在运行中的子代理始终保持自动连接与实时输出流更新。
|
|
430
|
-
- **单项按需加载**:点击任意历史子代理的「📥 加载最新消息」按钮后即时打开会话并保持显示,不触发整行跳转。
|
|
431
|
-
|
|
432
|
-
## v1.2.2 发布说明
|
|
433
|
-
|
|
434
|
-
- **自适应相对时间**:子代理卡片的时间显示优化为自适应相对时间(`x 秒前`、`x 分钟前`、`x 小时 x 分钟前`、`x 天前`),提升可读性。
|
|
435
|
-
- **提示信息重命名**:悬停时间的 Tooltip 标签统一优化为「最近活动:」。
|
|
436
|
-
|
|
437
|
-
## v1.2.1 发布说明
|
|
438
|
-
|
|
439
|
-
- 修复活跃浮窗中点击子代理的实时输出区域时,第一下无法打开子代理、需要点击第二下的问题(流式输出高频重渲染导致点击事件丢失)。
|
|
440
|
-
|
|
441
|
-
## v1.2.0 发布说明
|
|
442
|
-
|
|
443
|
-
### 永久删除
|
|
444
|
-
|
|
445
|
-
- 增加子代理永久删除功能(支持“带备份删除”与“不备份直接删除”)。
|
|
446
|
-
- 批量模式增加“批量删除(带备份/不备份)”以及“一键删除全部”操作。
|
|
447
|
-
- 备份目录保存于 `$DSH_HOME/subagent-backups/`。
|
|
448
|
-
- 彻底清理会话磁盘目录、投影缓存、工作区索引与内存注册表,并支持实时同步刷新。
|
|
449
|
-
|
|
450
|
-
### 隐藏与视觉
|
|
451
|
-
|
|
452
|
-
- 归档重构为「隐藏」:以 🙈/👁 眼睛图标一键隐藏或取消隐藏子代理,隐藏仅在列表不显示、不删除会话。
|
|
453
|
-
- 已隐藏子代理整行暗化,深浅主题自适应,与正常子代理形成强烈视觉对比。
|
|
454
|
-
|
|
455
|
-
### 浏览密度与筛选
|
|
456
|
-
|
|
457
|
-
- 新增「显示详情」开关(默认开启):取消勾选后卡片收拢为单行,token 统计、提示词预览与实时流式输出不再展开,提升单屏浏览密度。
|
|
458
|
-
- 搜索框新增 × 清空按钮,关闭抽屉后保留搜索关键词。
|
|
459
|
-
- 搜索框右侧 ⚙ 按钮可折叠/展开筛选区(分类标签、范围/会话/分组/排序下拉、选项行),折叠状态自动持久化。
|
|
460
|
-
- 筛选区折叠后在统计行上方显示当前筛选摘要(分类/工作区/会话/排序/分组)。
|
|
461
|
-
|
|
462
|
-
### 布局与交互
|
|
463
|
-
|
|
464
|
-
- 「显示活跃浮窗」开关固定到标题栏统计行(当前会话/工作区/活跃数)右侧。
|
|
465
|
-
- 「显示已隐藏」开关固定到列表统计行(显示 M/N 个)右侧。
|
|
466
|
-
- 详情区域宽度对齐整张卡片,左右不再截断。
|
|
467
|
-
- 子代理行内状态点与隐藏标记垂直居中。
|
|
468
|
-
- 筛选折叠按钮(⚙)点击热区加大,更易点中。
|
|
469
|
-
|
|
470
|
-
## v1.1.4 发布说明
|
|
471
|
-
|
|
472
|
-
- 适配深浅两种主题色。
|
|
473
|
-
- 子代理会话专属背景色支持自定义与深浅色独立配置。
|
|
474
|
-
- 实时浮窗与管理清单支持单个子代理「⏸ 暂停」与「⏸ 一键暂停」全部活跃子代理(带二次确认)。
|
|
475
|
-
|
|
476
|
-
## v1.1.2 发布说明
|
|
477
|
-
|
|
478
|
-
- 修复当无活跃子代理时,短路求值导致标题栏按钮左侧意外渲染出数字 `0` 的问题。
|
|
479
|
-
|
|
480
|
-
## v1.1.1 发布说明
|
|
481
|
-
|
|
482
|
-
- 测试脚本不再强制要求预先设置 API Key。
|
|
483
|
-
- 测试脚本根据自身位置定位项目目录,可从任意工作目录运行。
|
|
484
|
-
|
|
485
|
-
## v1.1.0 发布说明
|
|
486
|
-
|
|
487
|
-
- 增加右上角活跃子代理浮窗,显示运行时长、实时输出和统计信息。
|
|
488
|
-
- 支持在浮窗和管理抽屉中直接打断可取消的运行中子代理。
|
|
489
|
-
- 增加浮窗实时输出开关,关闭后可在有限空间显示更多子代理。
|
|
490
|
-
- 实时输出按 100ms 节流,并区分最新活动与已完成活动。
|
|
491
|
-
- 优先显示工具 description,长文件路径自动缩略。
|
|
492
|
-
- 增加 dsh-graph 工作流产生的大量子代理会话管理说明。
|
|
493
|
-
|
|
494
|
-
## v1.0.1 发布说明
|
|
381
|
+
## 致谢与参考
|
|
495
382
|
|
|
496
|
-
-
|
|
497
|
-
-
|
|
498
|
-
- 增加规划分类和分类数量徽章。
|
|
499
|
-
- 增加批量选择、Shift 连选、时间范围选择和批量归档。
|
|
500
|
-
- 改进批量模式下的卡片交互和完成按钮视觉反馈。
|
|
501
|
-
- 增加活跃子代理置顶、实时工具调用、上下文注入和结束快照。
|
|
502
|
-
- 移除 provider/model 查询和显示。
|
|
503
|
-
- 移除左侧全局菜单中的子代理入口。
|
|
383
|
+
- UI 本地化(zh/en)由 [@Marcuss2](https://github.com/Marcuss2) 在 [PR #1](https://github.com/miuzel/dsh-subagent-ui/pull/1) 中贡献,特此致谢!
|
|
384
|
+
- 子代理永久删除、会话生命周期清理及快照刷新机制的设计参考并致谢开源项目:[@heiheiha798/dsh-plugin-subagent-delete](https://github.com/heiheiha798/dsh-plugin-subagent-delete)。
|
package/cordis.patch.yml
CHANGED
|
@@ -4,11 +4,16 @@
|
|
|
4
4
|
name: 'dsh-subagent-workspace-ui'
|
|
5
5
|
|
|
6
6
|
# The stock ui-subagent plugin is deliberately left ENABLED: the manager reuses
|
|
7
|
-
# its right-sidebar chat tab for the new "open in the sidebar" button. Its
|
|
8
|
-
# session-header
|
|
9
|
-
# bundle, which
|
|
10
|
-
# conversation.session.header.lineage (a
|
|
11
|
-
# priority winner,
|
|
12
|
-
#
|
|
7
|
+
# its right-sidebar chat tab for the new "open in the sidebar" button. Its two
|
|
8
|
+
# session-header subagent entries are hidden instead by this plugin's own client
|
|
9
|
+
# bundle, which shadows each slot at a lower priority than the stock default 0:
|
|
10
|
+
# a title-only cell at priority -1 in conversation.session.header.lineage (a
|
|
11
|
+
# `single` slot renders its lowest priority winner), and a null cell at
|
|
12
|
+
# priority -1 in conversation.session.header.actions under the stock
|
|
13
|
+
# `subagent-catalog` id (that slot gives every id its own cell, so only the one
|
|
14
|
+
# stock cell is taken and the manager keeps its own). Each shadow swallows its
|
|
15
|
+
# own registration error, so a future host that ships a rival entry at the same
|
|
16
|
+
# (id, priority) pair costs the shadow, not the plugin.
|
|
17
|
+
# Removing this package removes those registrations with it, and this file no
|
|
13
18
|
# longer touches ui-subagent at all — a manual ui-subagent stanza a user wrote in
|
|
14
19
|
# the profile patch is intentionally preserved and keeps working.
|
package/lib/client.js
CHANGED
|
@@ -304,6 +304,11 @@ const LineageShadow=({displayTitle,lineageSessionId,useSessions,openTitle})=>{
|
|
|
304
304
|
const open=typeof openTitle==='function'?openTitle:null
|
|
305
305
|
return jsx('button',{type:'button',className:open?'dsh-sam-lineage-title':'dsh-sam-lineage-title dsh-sam-lineage-current',disabled:!open,title:displayTitle,onClick:open||undefined,children:displayTitle})
|
|
306
306
|
}
|
|
307
|
+
const CatalogShadow=()=>null
|
|
308
|
+
const registerShadow=(ctx,slot,options,component)=>ctx.slots.inject(slot,()=>{
|
|
309
|
+
try{return ctx.slots.register(options,component)}
|
|
310
|
+
catch(error){console.warn('subagent-workspace-ui: unable to shadow',options.id??slot,error);return()=>{}}
|
|
311
|
+
})
|
|
307
312
|
const SUBAGENT_CHAT_PREFIX='dsh-resource://subagentchat/session/'
|
|
308
313
|
const subagentChatAddressOf=address=>`${SUBAGENT_CHAT_PREFIX}${encodeURIComponent(address.childSessionId)}?${new URLSearchParams({parent:address.parentSessionId,mode:address.mode})}`
|
|
309
314
|
function apply(ctx){
|
|
@@ -332,7 +337,8 @@ function apply(ctx){
|
|
|
332
337
|
},
|
|
333
338
|
face=()=>({...actions,asideAddressOf,openAside})
|
|
334
339
|
ctx.slots.inject('conversation.session.header.actions',()=>ctx.slots.register({name:'conversation.session.header.actions',id:'subagent-workspace-manager',order:100,locale:NS,inject:face},Manager))
|
|
335
|
-
ctx
|
|
340
|
+
registerShadow(ctx,'conversation.session.header.actions',{name:'conversation.session.header.actions',id:'subagent-catalog',priority:-1},CatalogShadow)
|
|
341
|
+
registerShadow(ctx,'conversation.session.header.lineage',{name:'conversation.session.header.lineage',priority:-1},LineageShadow)
|
|
336
342
|
}
|
|
337
343
|
return {inject:['sessions','slots','locale'],apply}
|
|
338
344
|
}
|