dsh-plugin-node-time
Hover timestamps for DSH web. Hovering a chat node row — Think, Bash, Read/Edit/Write, Search, commands, compaction markers, sub-calls — pops a compact card with that node's start time → end time and how long it took.
- Stars
- 1
- Language
- JavaScript
- Created
- Aug 29, 2026
- Updated
- Aug 29, 2026
Introduction
dsh-plugin-node-time
Hover timestamps for DSH web. Hovering a chat node row — Think, Bash, Read/Edit/Write, Search, commands, compaction markers, sub-calls — pops a compact card with that node's start time → end time and how long it took.
English | 中文
The card
11:30:05.123 → 11:30:09.123
4.00s
- Range line — start → end in your local timezone; the date prefix appears when the node didn't happen today (and the year when it wasn't this year). A still-running node shows
start → …with the elapsed time ticking every second; the line flips to the final range the moment the call settles. - Duration line — humanized:
830ms/4.33s/1m 23s/1h 02m 30s. - Extra line — assistant steps also show
TTFT(time to first token) when the step has recorded one. - Styling rides the host's
--dsw-alias-*design tokens, so it follows your theme; the card ispointer-events: noneand never intercepts the mouse.
What gets a card
| Row | Start | End |
|---|---|---|
| Tool rows (Bash, Read, Edit, Search, …) and every nested sub-call | tool/call time | tool/result time |
| Think rows and assistant steps | step/start time | assistant/message time |
| Commands, compaction, turn errors, retries, context rows | — | event time (single line) |
Rows whose times the host already shows on hover (user messages, the turn tail) are left untouched, and a node whose call event fell outside the loaded history window simply shows what exists — or nothing.
How it works
- Trigger — one delegated
mouseover/mouseoutpair ondocument(capture). A hit on a row header —[data-disclosure-row](generic tool rows, Think, commands) or[data-sample](the Bash/Pwsh sample card, whose expanded output lives outside the row root, so sweeping output never pops the card) — resolves throughdata-chat-call-id(exact tool-call/sub-call attribution) ordata-chat-anchor-key(chat node), then reads the timing out of the current session snapshot — read at hover time, so it is always fresh. - Data — the
sessionsservice:ToolChatData.rootlifecycle (callTime/time),AssistantChatData.finalNode.timing(stepStartTime/firstTokenTime/completedTime),node.location.stepboundary events for running steps, anddata.timefor single-time nodes. - Zero host DOM writes — the card is a
position: fixedelement appended todocument.body; React re-renders can never wipe it, and no host component is replaced or patched. - Style contract — the injected
<style>arrives pre-tagged withdata-plugin="dsh-plugin-node-time": the client module system'sclaimStylesre-assigns every untagged head style to whichever plugin materializes next (HMR bookkeeping), so an untagged style gets claimed — and possibly cleaned up — by a neighbour. (This exact race is why v0.1.0 cards sometimes never appeared.) - Silent by design — missing
sessionsservice, changed contracts, or truncated windows degrade to "no card"; the plugin can never break the host.
Install
dsh plugin --profile web add dsh-plugin-node-time
Restart dsh web to take effect.
From source (local development)
pnpm install
pnpm run build
pnpm test
Then add this package to ~/.dsh/profiles/web/package.json as a link: dependency, register it in dsh.profile.bundles, and restart dsh web.
Keywords
dsh · deepseek harness · dsh plugin · web plugin · client plugin · chat ui · tooltip · hover · timestamp · start time · end time · duration · elapsed · node timing · tool timing · think · bash · subcalls · assistant step · 时间 · 开始时间 · 结束时间 · 用时 · 悬浮 · 节点时间 · 工具耗时