Tracks DSH's file reads, image views, and code edits in WakaTime, including exact counts of lines added and deleted by AI. Keeps activity tracking running while DSH responds, batches updates across files, and coordinates per-project reporting limits across parallel DSH processes. Automatically installs and updates wakatime-cli.
Install
# from npm (prebuilt)
dsh plugin --profile web add @dingyi222666/dsh-wakatime
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:dingyi222666/dsh-wakatime
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
English | 中文
WakaTime plugin for DeepSeek Harness (dsh) — track your AI coding activity, lines of code, and time spent. Adapted from opencode-wakatime to dsh's plugin model.
Install
# Install from npm (requires dsh >= 0.1.3-alpha.2 <0.3.0-0, declared as engines.dsh)
dsh plugin --profile web add @dingyi222666/dsh-wakatime
# Restart dsh web for it to take effect
dsh web
The plugin works in any profile that runs the agent loop — web, headless, acp, sdk, and the Desktop app's desktop profile — install it into each profile you use:
dsh plugin --profile headless add @dingyi222666/dsh-wakatime
Desktop app
The DeepSeek Harness Desktop application is an Electron shell around the same Web
host, but it exclusively owns a separate profile ($DSH_HOME/profiles/desktop)
and its own package state. Install the plugin there with the CLI bundled inside
the app — an npm-installed dsh cannot mutate the Desktop profile:
# 1. Launch Desktop once so it initializes profiles/desktop, then fully quit it.
# 2. Run the bundled CLI (macOS path shown; Windows uses resources\runtime\cli\bin\dsh.cmd):
"/Applications/DeepSeek Harness.app/Contents/Resources/runtime/cli/bin/dsh" \
plugin --profile desktop add @dingyi222666/dsh-wakatime
# 3. Reopen Desktop; the bundle patch applies on the next boot.
The same command manages updates (add @dingyi222666/dsh-wakatime@latest),
list, and remove <package>, and it keeps the shared Desktop profile lock and
compatibility checks intact. Because both the Desktop host and its plugins run in
the same Electron Node process, the tracked events and heartbeats are identical to
the Web profile.
From source (GitHub)
git clone https://github.com/dingyi222666/dsh-wakatime
cd dsh-wakatime
pnpm install && pnpm run build
dsh plugin --profile web add .
dsh web
Notes:
dsh pluginbehaves like adding a dependency to your profile. A bundle plugin is loaded once its full package name appears in the profile'sdsh.profile.bundleslist (added automatically); the bundle patch (cordis.patch.yml) applies on the next boot.- The bundle declares
engines.dsh(>=0.1.3-alpha.2 <0.3.0-0): dsh installation and profile startup refuse a host outside that range (this replaced the peer-range check in dsh 0.2.1-alpha.3 — whenengines.dshis present, the@deepseek-ai/dsh*peers are ignored for compatibility; the<0.3.0-0bound also excludes 0.3 prereleases). - To update, run the same command again.
- With the repo source-launched CLI, run the args through the bin directly (
node --import tsx/esm apps/cli/src/bin.ts plugin --profile web add @dingyi222666/dsh-wakatime).
Configuration
The plugin works out of the box. To override behavior, add a row with the
same id (wakatime) in your profile's user patch layer
($DSH_HOME/profiles/<name>/cordis.patch.yml) or via --patch:
- id: wakatime
config:
heartbeatIntervalMs: 120000 # rate limit per project (default 60000)
debug: true # force DEBUG logging (default: ~/.wakatime.cfg debug=true)
client: web # client qualifier in the --plugin string (default "dsh")
timeoutMs: 45000 # heartbeat CLI timeout (default 30000)
All fields are optional and validated by a schemastery schema at load.
Features
- Automatic CLI management — downloads and updates
wakatime-cliautomatically, or uses a global install (brew install wakatime-cli) - Detailed file tracking — tracks file operations the agent performs:
edit,write,read,read_image, andstr_replace_editor(view/create/str_replace/insert) - Resolved-path accuracy (dsh 0.1.3-alpha.1) — reads the fs tools' durable
tool/resultmeta: resolved (sandbox-aware) entity paths and exact diff hunks win over raw call arguments when present - Exact write outcomes (dsh 0.1.7-alpha.1) — the
writeresult'soperationstamp (create/update) distinguishes a created file (content lines charged) from an unchanged overwrite (zero line changes, heartbeat only) - Working-directory aware (dsh 0.2.1-alpha.2) — follows the session's committed
working-directory/changerecords, so heartbeats,--project-folder, relative-path resolution, and the per-project rate limit retarget when the agent changes its working directory - AI coding metrics — sends
--ai-line-changesfor WakaTime's AI coding analytics, computed exactly from the fs tools' diff hunks (context lines excluded) - Live activity heartbeats (dsh 0.1.3-alpha.1) —
agent/statustransitions and theagent/assistant-streamfirehose heartbeat the current file in near real time while a long turn streams, instead of waiting for the durable settlement - Rate-limited heartbeats — 1 per minute per project, persisted to disk so parallel dsh processes share the budget (durable changes and live activity draw from the same budget)
- Session lifecycle — force-flushes pending heartbeats when a session is disposed and when the plugin tree tears down, so one-shot
dsh --profile headlessruns still report their activity - Batch tool support — multiple files in one edit are sent in a single
wakatime-cliinvocation via--extra-heartbeats - Zero runtime dependencies — the built plugin imports only Node builtins plus the
@deepseek-ai/*peers the host already provides
Prerequisites
WakaTime API Key
Ensure you have a WakaTime API key configured in ~/.wakatime.cfg
(or $WAKATIME_HOME/.wakatime.cfg when WAKATIME_HOME is set):
[settings]
api_key = waka_your_api_key_here
Get your API key from WakaTime Settings.
WakaTime CLI (Optional)
The plugin downloads wakatime-cli automatically when missing. To install it yourself:
brew install wakatime-cli
or download from WakaTime releases.
How It Works
The plugin subscribes to dsh's session event firehose (session/event):
flowchart TB
subgraph dsh["DeepSeek Harness"]
A[Agent Loop] --> B[tool/call + tool/result events<br/>(meta: resolved path + diff hunks)]
C[Live agent events<br/>agent/status, agent/assistant-stream] --> D[Activity]
C2[Chat Activity<br/>user/message, assistant/message, assistant/attempt] --> D
B --> D
D --> E[Session Events<br/>turn/end, session/disposed]
end
subgraph Plugin["dsh-wakatime"]
B --> F[Join callId: extract file<br/>path + line changes from<br/>meta and fs diff hunks]
F --> G[Per-project pending<br/>changes + last entity]
C --> H[Rate-limited<br/>heartbeat batch]
G --> H
E --> I[Final force flush]
H --> J[wakatime-cli<br/>--ai-line-changes<br/>--extra-heartbeats]
I --> J
end
tool/callrecords the tool name and parsed arguments bycallId;tool/resultmatches it back and reads the fs tools' durablemetapayload — resolved entity paths (read,read_image), diff hunks (edit,write), and thewriteoutcome stamp (dsh 0.1.7-alpha.1) — for exact per-hunk line counts, falling back to the call arguments when a host attaches no meta (writecontent,str_replace_editorstrings). Awriteupdate with an empty hunk list is charged zero lines; a create is charged its content lines. Failed results — including the synthetic recovery closers agent-loop records for skipped calls when a step fails (dsh 0.2.0) — are never charged.- Heartbeats are sent at most once per minute per project (state file under
~/.wakatime/dsh-wakatime/), on chat activity, tool results, committed model settlements (including message-lessassistant/attemptrecords in dsh 0.1.3-alpha.1), live agent activity (agent/status,agent/assistant-stream), turn boundaries, session disposal, and plugin teardown. - The project folder starts at the session header cwd and follows committed
working-directory/changerecords (dsh 0.2.1-alpha.2), matching the directory the fs tools resolve against; each folder keeps its own rate-limit budget. - The
--plugintag reportsDeepseek Harness[-<client>]/<dsh version> dsh-wakatime/<version>.
Development
pnpm install
pnpm run typecheck # tsc --noEmit
pnpm run build # declarations into lib/types + tsdown bundle lib/index.js
pnpm test # vitest: changes, state, heartbeat, plugin wiring
Layout:
src/index.ts— plugin entry (name/Config/apply) and event wiringsrc/config.ts— schemasteryConfigschema, defaults,--plugintagsrc/changes.ts— tool events → file changes, diff line countingsrc/state.ts— per-project rate limitingsrc/heartbeat.ts—wakatime-cliinvocation, batching, flushingsrc/cli.ts—wakatime-clidiscovery/download/updatesrc/paths.ts,src/logger.ts— WakaTime paths and file loggingtests/— unit tests plus an integration test that drives the plugin over a real cordisContext
Known Limitations
- Tool calls executed inside sandboxed/remote filesystems are tracked by their
model-visible
file_patharguments unless the tool/resultmetacarries a resolved absolute path (dsh 0.1.3-alpha.1 fs tools do); paths the sandbox resolves differently may land as project-relative entities. bashcommands are not attributed to files (they can touch anything).- The dsh host version in the
--plugintag isunknownwhen the@deepseek-ai/dshpackage cannot be resolved from the plugin's location (e.g. an npm install without the dev dependency present). - The
@deepseek-ai/dsh-session/@deepseek-ai/dsh-agentpeer ranges start at0.1.3-alpha.1; older hosts run the tracking paths but get no live agent activity heartbeats.
License
MIT — ported logic from opencode-wakatime (MIT).
Links
More in this category
bowenliang123/dsh-context★ 3724
DSH context insight panel: Context dashboard + /context command + Context browser — one-stop context lifecycle management with categorized composition, content details, evolution trends, compaction/injection events, and stats.
Han-1413141/dsh-cost-meter★ 556
Per-session and daily API cost, budget with usage %, official balance, history dashboard, and one-click official price sync with peak/off-peak pricing.
wssfk12138/dsh-damage-pulse★ 276
Tracks DeepSeek token usage, per-call and session costs, and account balance with cache-aware charge animations in the DSH Web UI.
zh667/TokenLedger★ 199
Sidebar usage panel that attributes tokens to the relay site that served each request, read from your existing provider config: today/month/all-time totals, per-site and per-model breakdowns, a year activity heatmap, and New API / Sub2API / DeepSeek balances.
Ychris12138/dsh-usage-stats★ 186
Multi-provider usage dashboard with provider/model token breakdowns, calendar drill-downs, account balances, and OpenCode Go / Z.ai subscription quota tracking.
PolinniZhong/dsh-personal-center★ 114
Personal center for DeepSeek Harness: cross-session usage statistics, per-model cost estimation, global custom instructions, a global font-size adjuster, a data-driven desktop pet with bitmap & vector skins, and a conversation status overview, all local and offline.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.