dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Read-only Agent Team console for the DeepSeek Harness Web UI: live roster, shared task board, and collaboration activity.
Read-only Agent Teams dashboard for the DeepSeek Harness Web UI (dsh-agent-team-console): a
project-scoped, card-grid view of every team, with a top-down pixel-art agent flow graph and rounds /
token / working-time statistics in one first-class main panel.
English | 中文
Repository: https://github.com/kkomia/dsh-agent-team-console
Unofficial community plugin. This repository is not part of the DeepSeek official packages, is not published or endorsed by DeepSeek, and is not a replacement for the official experimental Agent Teams bundle. It is a read-only viewer: it never creates, changes, or completes a team member or a task.
The official experimental Agent Teams Web UI (@deepseek-ai/dsh-experimental-client-ui-agent-team)
adds a compact roster and task-board action to the conversation header. That is convenient for a
quick check while you are inside the Lead conversation, but it is not a page of its own.
Agent Team Console keeps the same read-only contract and adds a sidebar entry plus a full main panel for people who keep a team running for a long stretch:
It is a plain DeepSeek Harness (DSH) Web plugin: no build step for users, no npm dependencies, and no external services.
ready === false is blocked, and in-progress tasks are never shown as
blocked.--dsw-* theme tokens, so
the panel follows dark and light themes. Graph nodes and cards are keyboard accessible and every
animation (including the hand-off dash flow) is disabled under reduced motion.uiWorkspace.openSession, clicking a graph node
opens that member's session. When it does not, the panel stays a read-only page.0.2.1-rc.2; package.json declares engines.dsh as >=0.2.1-rc.2 <0.3.0-0, which also excludes
0.3.0 prereleases.sessionStats and tokenUsage projections. They are optional: without them the panel still
renders the graph and shows dashes for statistics.desktop profile; replace desktop
with your own Web profile name (web, and so on) if it differs.The examples below use dsh plugin --profile desktop add <spec>. Replace desktop with your profile
name if you use a different Web profile.
github:kkomia/dsh-agent-team-console (or dsh-agent-team-console once the package is
published on npm), then confirm the install.GitHub repository (works today):
dsh plugin --profile desktop add github:kkomia/dsh-agent-team-console
npm registry (once the package is published on npm):
dsh plugin --profile desktop add dsh-agent-team-console
GitHub installs are resolved through the network and need Git (and pnpm, which DSH's plugin manager already uses). The repository has no build step, so the install is a plain copy of the package files.
The host half registers an HTTP route when the DSH host process starts, so restart the desktop app after installing or upgrading; then refresh the Web UI page if it is already open. If only client assets changed and the host is unchanged, a page refresh is enough.
Select Team console in the sidebar. The panel loads the current snapshot immediately and then keeps polling every 2 seconds while it is visible.
The header shows the page title and subtitle (a one-line description of the live graph), the project filter when it applies, a live indicator (pulsing while any member is running), the time of the last successful update, and a refresh button that spins while a manual refresh is in flight.
When the snapshot lists more than one project (workspace), a project select appears in the header. It starts at "All projects"; choosing a project narrows the status strip, its token total, and the workspace cards to that project's teams; each card shows its workspace name. The filter is client-side only: it is not saved, and remounting the panel resets it to "All projects". Projects with duplicate titles get a short path tail in their option label so they stay distinguishable. Teams whose project cannot be resolved appear under "All projects" only.
The status strip is a compact row of five chips for the current selection: in-progress tasks, running
members (running / total), token usage summed across the filtered teams (shown compactly, such as
1.2M tok), blocked tasks, and pending tasks. The blocked chip counts pending tasks that are not
ready; in-progress and completed tasks are never counted as blocked. A chip with a value of zero stays
visible but is muted. Completed tasks are not counted in the strip; they appear only in the per-team
task summary.
Teams are ordered active first, then by most recent activity, and shown as a responsive grid of block cards. A collapsed card shows the status dot, workspace/project name, an in-progress badge when non-zero, the Lead name, the working-vs-idle donut with team rounds and token totals, and a muted work-vs-idle caption. At most one team is expanded at a time: clicking a collapsed card expands it and collapses the previous one, and clicking the expanded card's header collapses it. The default expanded card is the first active team; an explicit collapse sticks across the 2-second polls (and a card that disappears from the filtered list falls back to the default). An expanded card spans the full grid row and shows the full header, the flow graph, and the task summary.
Each expanded card contains an SVG data-flow graph. The Lead/root sits at the top centre, and the other members are placed in balanced rows below it: a single row for up to 5 teammates, otherwise two balanced rows with the larger row first; up to 8 members are drawn and a "+N" node stands in for any overflow. A small legend above the graph labels the two edge kinds when they are present:
agent-message deliveries in each member's session log, plus legacy team/message/queued
records when present, observed within bounded per-member scans. Thicker arcs mean more messages in
the observed window, brighter arcs are more recent, and same-row arcs bend upward so they stay clear
of the member names.Members are drawn as deterministic pixel-art characters made of SVG rectangles (no external images): the Lead gets a brand-colored outfit and marker, and each teammate's hair, outfit accent, and accessory vary deterministically from their identity. Node radius grows with token usage (log-scaled against the team's busiest member), an outer arc shows the working ratio, and a tiny "N rounds · X tok" line sits under each node. Status motion: running bobs with a working spark, provisioning spins a dashed ring and blinks softly, idle is muted and static, and failed keeps a static error ring. If the payload has no edge data, the graph falls back to a structural hand-off graph from the root member. Animations respect the host's reduced-motion preference.
Hovering or focusing a node opens a detail card below the graph: model, rounds, steps, the token breakdown (uncached input, cache read, cache write, output, total), working and idle time, and the member's message summary (received and sent counts). The card closes when the pointer or focus leaves the node.
Each expanded team card ends with a single summary line: in-progress, pending, and blocked counts plus a small expand toggle. Expanding it shows only the in-progress tasks as compact one-line rows with the subject and owner; pending and completed tasks stay as counts. Readiness is derived by the host: a pending task is ready when all of its blockers are completed, and only a pending task that is not ready is counted and shown as blocked. In-progress tasks are claimed work and never show a blocked warning.
Click a graph node (or focus it and press Enter or Space) to open that member's session when the host provides workspace navigation. This is an optional convenience: when the service is not available, nodes are not clickable.
The refresh button in the header requests one snapshot immediately. The regular 2-second polling continues as usual.
Agent Team Console is deliberately conservative:
GET /api/team-console/snapshot; for admitted
requests, any other path returns a JSON 404. No POST, PUT, PATCH, or DELETE route exists, and the
handler never reads the request body.react from the host module
system; it imports no @deepseek-ai/* package and no third-party bundle.connection service, the route asks
it to admit every request before running any route logic: a request that fails the Host/Origin fence
or the browser-session check receives a JSON 401 (unauthorized) or 403 (forbidden) response
and is rejected exactly like any other Web UI request. An authenticated same-origin browser fetch is
admitted. If a host does not mount that service, the route leaves admission to the deployment's own
access control.flowchart LR
subgraph Browser["DSH Web UI (browser)"]
P["client.js<br/>sidebar entry + main panel"]
end
subgraph Host["DSH host process"]
R["GET /api/team-console/snapshot"]
S["agentTeams / agents / sessions services"]
W["workspaceRegistry (optional)"]
J["sessionProjections (optional)"]
R --> S
R --> W
R --> J
end
P -- "fetch snapshot, every 2s, same origin" --> R
index.js)index.js has zero import statements so a plain Node test can load it. It exports
inject = ['webServer'] and apply(ctx), which registers a prefix route under
/api/team-console inside ctx.effect(...), so unloading the plugin disposes the route.
On every request the handler first applies the optional DSH connection service's admission check;
a request that fails the Host/Origin fence or browser-session admission gets a JSON 401/403 before any
route logic. It then resolves the optional agentTeams, agents, sessions, workspaceRegistry, and
sessionProjections services through ctx.get(...). If Agent Teams is missing it returns a valid
snapshot with an unsupported reason. Otherwise it enumerates live agents, keeps the ones with a Lead
role, reads the roster and task board for each team, enriches members from a bounded session tail,
resolves each team's project, and reads each member's session statistics from the optional session
projections (sessionStats and tokenUsage): two bounded projection reads per member, never a
session-log scan for stats. It computes turns, steps, token buckets, working / idle / wall time, and a
working ratio, aggregates them per team, and builds each team's interaction graph: structural Lead
edges plus message edges aggregated from two bounded sources — live agent-message deliveries in
each member's session log (the newest 1000 events per listed member, Lead included) and legacy
team/message/queued records in the newest 2000 Lead-session events; weights add, message counts are
capped at 99, and the newest timestamp is kept. It returns one JSON-safe snapshot with contract
version 4. Teams are ordered active first, then by most recent activity. Unexpected aggregation
failures become a valid JSON 500 body; unknown routes become a JSON 404 body.
client.js)client.js is a self-registering browser bundle loaded through window.__ModuleLoader__.load, with
an id equal to the package name. Its factory requires only react. apply(ctx) registers the
Chinese and English locale dictionaries under the agent-team-console namespace inside
ctx.effect(...), then registers a sidebar.panellist entry (id team-console, order 20) and a
main panel (key team-console).
The panel keeps the project selection, the single expanded-team key (plus whether the user explicitly
collapsed or chose a card), and the per-team task-summary state in local React state (no storage). It
renders the project filter, the five-chip status strip, and a responsive grid of workspace block cards
in which at most one card is expanded at a time: the default expanded card is the first active team
until an explicit choice is made, clicking a collapsed card switches the expansion, and clicking the
expanded header collapses it. The expanded card contains the full header, the top-down SVG flow graph
with deterministic pixel-art characters, and the task summary; the wire contract still carries the
activity list but the panel does not render it. All styles, graph art, and animations come from one
<style> element that uses only --dsw-* tokens, animations are disabled under reduced motion, and
polling keeps the same 2-second, visibility-aware, cleanup-safe behavior as before.
Requirements: Node.js 22.19 or newer for the test tooling. There are no npm dependencies and no build
step; client.js is a hand-written, committed browser bundle.
node --check index.js
node --check client.js
node --test test/snapshot.test.mjs
node scripts/ci-guard.mjs
node scripts/client-check.mjs
npm run check runs the syntax checks and the test suite, and npm test runs the tests alone. The
suite currently has 50 tests that use only Node built-ins and fake Cordis services; they cover the
snapshot contract (version 4, project resolution, active ordering, session stats and their optional
degradation, and the interaction-graph edges from both live and legacy sources), unknown event shapes,
JSON safety, and the 200/404/500 route behavior. scripts/ci-guard.mjs runs 32 checks over the
cross-file DSH wiring (manifest, patch, exports, client registration, locale metadata, and the embedded
client dictionary key parity), which is the part that can break without any unit test failing.
scripts/client-check.mjs extracts the self-contained @atc-layout-begin / @atc-layout-end pure
layout block from client.js, evaluates it with Node, and runs 26 checks on it: the frozen layout
constants, the root topmost and centred, the single-row boundary at 5 teammates, balanced 3+3 / 4+3 /
4+4 rows with the half-slot stagger for equal rows, overflow placement in the last slot, finite
geometry for empty and degenerate inputs, hand-off edge control points between the rows, upward-bending
same-row message arcs, and the static wiring (the graph component uses the pure layout functions, the
lead dash flow exists and respects reduced motion, and no ring-layout remnants remain). CI runs it after
the syntax checks.
To try a local change in a live app, install the package into a DSH profile (an absolute local path
is accepted as an install spec), restart the app, and open the panel. Host log lines are prefixed
[agent-team-console].
To check a running instance's snapshot route from the command line, run
TEAM_CONSOLE_URL=http://127.0.0.1:10100 node scripts/verify-live.mjs. It exits 0 when the route
is reachable and the v4 contract matches, 1 when the route is unreachable or the contract is
violated, and 2 when admission rejects the request as unauthenticated. A 2 is expected against a
running DSH desktop app: the route enforces DSH connection admission, so an anonymous command-line
probe is answered with a JSON 401 before any snapshot logic, while the authenticated browser UI
works. The script is useful only where you can pass admission, such as an authenticated setup you
control.
| Path | What it is |
|---|---|
index.js | Host half: route registration and snapshot aggregation (no imports) |
client.js | Client half: self-registering browser bundle (slots, locale, panel, polling) |
cordis.patch.yml | Bundle patch that inserts the plugin into the profile's loader |
package.json | Package manifest: DSH bundle/client metadata, exports, scripts |
locale/en.json, |