feat: support dsh (DeepSeek harness) as a usage + presence source - #81
Merged
Conversation
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>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
- 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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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-presenceappends to a local usage log. Theusagecommand 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 usageview 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 inagent-presence— no transcript scraping.How
src/installers.tsbuildDshPluginSource): a single-file Cordis plugin that bridgesagent/session-start→ running,agent/pre-step/tools/*→ heartbeat,agent/turn-stopping→ finished (sync, so headless one-shot runs deliver Stop before exit), and reports eachassistant/messageusage alongside the heartbeat. Waterfall events correctly delegate tonext().src/usage-events.ts): append-only~/.agent-presence/usage-events.log, size-bounded by the existingappendRetainedLogLineutility (5 MB cap, 1 MB tail).usageEventFromPayloadextracts{model, usage}from any hook payload — generic, so future plugin sources can reuse it.src/usage/scan-dsh.ts): reads the log forsource=dsh, window-filters, returnsUsageRecord[]withcostUsd: null→ cost derived from the pricing table by actual model (listed models priced, private modelsn/a).src/hooks/dsh.ts): accepts the plugin's{session_id, cwd, model, usage}payload and dsh'sdsh-hooks-claude-codedialect (hook_event_name,session_id,cwd).scripts/install-dsh-plugin.ts/uninstall-dsh-plugin.ts): writes the plugin to~/.dsh/plugins/agent-presence.mjsand 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.src/cli/commands/setup.ts): prompts to install when~/.dshis detected and the terminal is interactive; non-interactive skips.pnpm run install:dsh-plugin/uninstall:dsh-pluginfor manual use.dshadded toBUILTIN_SOURCE_PLUGINSandsources.default.json.Validation
pnpm test— 328 tests pass (40 files), including newusage-events.test.ts,usage-scan-dsh.test.ts,dsh-plugin-install.test.ts, and updatedhooks.test.ts/sources.test.ts.pnpm run typecheck,pnpm run build,pnpm pack --dry-run— clean; dsh files included in the tarball.DSH_HOME/AGENT_PRESENCE_HOME):cordis.patch.yml;node --checkon the plugin passes.echo '{...usage...}' | agent-presence hook --source dsh→usage-events.logappended, presence staterunning.agent-presence usage --days 1shows adshrow; listed model (deepseek-v4-pro) priced, private model (auto_model/alwaysday1)n/a.Follow-up risks
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).agent.session.header.id/event.data.usage/message.source.modelfrom dsh's current API. A future dsh release that changes these shapes would silently stop reporting (the plugin is regenerated onsetuprerun, so updatingagent-presence+ rerunning setup fixes it).agent/pre-stepas start: presence activates on the first step (user prompt submitted), matching the Pi extension's "active on prompt, not on open" semantics. If dsh'sagent/session-startfires before any prompt in TUI mode, it may briefly show active until TTL.🤖 Generated with Claude Code