Skip to content

feat: support dsh (DeepSeek harness) as a usage + presence source - #81

Merged
PerfectPan merged 2 commits into
mainfrom
feat/dsh-source
Aug 18, 2026
Merged

feat: support dsh (DeepSeek harness) as a usage + presence source#81
PerfectPan merged 2 commits into
mainfrom
feat/dsh-source

Conversation

@PerfectPan

Copy link
Copy Markdown
Owner

What changed

Add dsh (DeepSeek harness) as a built-in source. Instead of scraping dsh's zstd transcripts, a managed Cordis plugin reports each model call's token usage in real time via the hook payload, which agent-presence appends to a local usage log. The usage command and signature badge read that log back, so dsh contributes to the same calendar-day windows and totals as the transcript-scraping sources.

Why

dsh is now released and users want its token consumption in the same agent-presence usage view and signature badge as the other five sources. dsh's supported extension surface is its Cordis plugin system (not a hook settings file), so the integration is a plugin that dsh loads, plus a real-time ingestion path in agent-presence — no transcript scraping.

How

  • dsh plugin (src/installers.ts buildDshPluginSource): a single-file Cordis plugin that bridges agent/session-start → running, agent/pre-step / tools/* → heartbeat, agent/turn-stopping → finished (sync, so headless one-shot runs deliver Stop before exit), and reports each assistant/message usage alongside the heartbeat. Waterfall events correctly delegate to next().
  • Usage ingestion (src/usage-events.ts): append-only ~/.agent-presence/usage-events.log, size-bounded by the existing appendRetainedLogLine utility (5 MB cap, 1 MB tail). usageEventFromPayload extracts {model, usage} from any hook payload — generic, so future plugin sources can reuse it.
  • Scanner (src/usage/scan-dsh.ts): reads the log for source=dsh, window-filters, returns UsageRecord[] with costUsd: null → cost derived from the pricing table by actual model (listed models priced, private models n/a).
  • Presence resolver (src/hooks/dsh.ts): accepts the plugin's {session_id, cwd, model, usage} payload and dsh's dsh-hooks-claude-code dialect (hook_event_name, session_id, cwd).
  • Installer (scripts/install-dsh-plugin.ts / uninstall-dsh-plugin.ts): writes the plugin to ~/.dsh/plugins/agent-presence.mjs and registers it in the home-level ~/.dsh/cordis.patch.yml (applies to every profile) via a marker-delimited YAML text merge — no new dependency. Refuses to overwrite a non-managed file.
  • Setup (src/cli/commands/setup.ts): prompts to install when ~/.dsh is detected and the terminal is interactive; non-interactive skips. pnpm run install:dsh-plugin / uninstall:dsh-plugin for manual use.
  • Registration: dsh added to BUILTIN_SOURCE_PLUGINS and sources.default.json.

Validation

  • pnpm test — 328 tests pass (40 files), including new usage-events.test.ts, usage-scan-dsh.test.ts, dsh-plugin-install.test.ts, and updated hooks.test.ts / sources.test.ts.
  • pnpm run typecheck, pnpm run build, pnpm pack --dry-run — clean; dsh files included in the tarball.
  • Hygiene scan on changed files — no private tokens/hostnames/paths.
  • E2E (temp DSH_HOME / AGENT_PRESENCE_HOME):
    • Installer writes the plugin + cordis.patch.yml; node --check on the plugin passes.
    • echo '{...usage...}' | agent-presence hook --source dshusage-events.log appended, presence state running.
    • agent-presence usage --days 1 shows a dsh row; listed model (deepseek-v4-pro) priced, private model (auto_model/alwaysday1) n/a.

Follow-up risks

  • Subagent usage not counted: the plugin skips sessions with origin: 'subagent' to avoid mixing subagent turns into the main aggregate. If subagent accounting is wanted later, it needs a dedup decision (subagent usage is not in the main session's events).
  • Plugin event-shape drift: the plugin reads agent.session.header.id / event.data.usage / message.source.model from dsh's current API. A future dsh release that changes these shapes would silently stop reporting (the plugin is regenerated on setup rerun, so updating agent-presence + rerunning setup fixes it).
  • agent/pre-step as start: presence activates on the first step (user prompt submitted), matching the Pi extension's "active on prompt, not on open" semantics. If dsh's agent/session-start fires before any prompt in TUI mode, it may briefly show active until TTL.

🤖 Generated with Claude Code

Add dsh as a built-in source. A managed Cordis plugin (installed by `setup`,
opt-in via prompt when ~/.dsh is detected) bridges dsh lifecycle events to
presence and reports each model call's token usage in real time via the hook
payload, which agent-presence appends to a local usage log. The `usage`
command and signature badge read that log back, so dsh contributes to the
same calendar-day windows and totals as the transcript-scraping sources —
without scraping dsh's zstd transcripts.

- src/usage-events.ts: append-only usage event log, size-bounded via the
  existing log-retention utility
- src/usage/scan-dsh.ts: reads the log for the dsh source; cost derived
  from the pricing table by actual model (listed models priced, private
  models n/a)
- src/hooks/dsh.ts: presence resolver (plugin payload + CC-dialect fallback)
- src/installers.ts: plugin source generator + marker-delimited YAML patch
  merge for ~/.dsh/cordis.patch.yml (no new dependency)
- scripts/install-dsh-plugin.ts / uninstall-dsh-plugin.ts
- setup: prompt to install when ~/.dsh is detected
- docs: README, architecture, presence/token-usage guides (en + zh), RFC,
  changeset

Co-Authored-By: Claude <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agent-presence Ready Ready Preview Aug 17, 2026 12:56pm

- Generalize readManagedExtension with a marker param; delete the duplicate
  readManagedFile (Pi and dsh now share one helper)
- Export resolveDshPluginPaths() and use it in setup.ts + both install
  scripts, removing the triplicated DSH_HOME/path resolution
- maybeInstallDshPlugin calls installDshPlugin directly instead of spawning
  a child process, surfacing patchError
- readUsageEvents reuses forEachJsonl + adds an mtime pre-filter
- Drop the redundant tools/pre-execute heartbeat (tools/result alone proves
  activity; halves per-tool process spawns)
- Handle the orphaned-start-marker case in withDshAgentPresencePatch;
  withoutDshAgentPresencePatch only normalizes the removed block's gap
- Add uninstall-dsh-plugin.js to DEFAULT_UNINSTALL_SCRIPT_NAMES so
  `agent-presence uninstall` removes the dsh plugin
- Use a static mkdir import in the dsh install test

Co-Authored-By: Claude <noreply@anthropic.com>
@PerfectPan
PerfectPan merged commit f7e868a into main Aug 18, 2026
4 checks passed
@PerfectPan
PerfectPan deleted the feat/dsh-source branch August 18, 2026 03:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant