dgy970516/dsh-status-turbo ↗★ 0
dsh-status-turbo
DSH 插件:把「现在到底卡在哪」变成 composer 上方一行会跳的状态条。支柱 A1 —— 阶段 / 本阶段已耗时 / 本步 token / 缓存命中率 / 无进展告警。纯日志投影驱动,不读宿主内存、不轮询、不注入 DOM。 适合需要直观监控推理阶段、耗时及缓存命中率的用户
Install
$
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:dgy970516/dsh-status-turboREADME
Read the full README ↗Configuration
| Key | Default | Description |
|---|---|---|
statusBar | true | Mount switch for the status bar. The host projects it into the wire field mountStatus ('enabled' / 'disabled'); the client has three states: enabled → normal bar; disabled → renders nothing; field absent (an older host that does not send it) → a red cell 状态条开关缺失:配置未送达 instead of a silent no-op. Off means "no bar", not "silently dead switch" |
noProgressMs | 90000 | No-progress threshold in milliseconds |
downgrade | true | See the section above |
downgradeFloor | low | See the section above |
minQuietSteps | 2 | See the section above |
readOnlyTools | 10 tool names | 0.9.2 (P1-4): the B1 read-only allowlist — only explicitly read-only tools count as "pure read / list / search"; anything not listed (bash / edit / write / sql_exec / univer_execute…) counts as "may write", and one such call breaks the consecutive run (deliberately conservative). Elements must be non-empty strings and invalid ones are filtered; an empty result falls back to this table ([] means "not configured", not "no read-only tools"). Defaults: read / read_image / glob / grep / list_dir / search_context / web_search / web_fetch / cordis_inspect_list / cordis_inspect_query |
spillThresholdBytes | 32768 | B3: a result body this many UTF-8 bytes or larger may be spilled (AND-ed with the harness tool-result pruner) |
localTrimHeadChars | 4096 | 0.6.5: characters of the head kept by the local trimmer used when the host pruner is unavailable (spillThresholdBytes decides whether to spill; these three keys decide how much the model sees) |
localTrimTailChars | 1024 | 0.6.5: characters of the tail kept; the elided middle becomes one line saying how many characters were dropped |
localTrimMinChars | 8192 | 0.6.5: a longest-text block shorter than this is not trimmed (characters, unrelated to spillThresholdBytes); a trim no shorter than the original is skipped too |
bulkInjectionBytes | 32768 | B4: one tool/result payload at or above this counts as a "bulk injection" that invalidates the cache prefix |
evidenceWhitelist | 3 regex sources | C1: 3 complete regex literals as strings (delimiters + flags included); matching any one counts as verifiable evidence |
stuckAction | warn | D: warn (default, zero side effect) / nudge / stop |
stuckRounds | 3 | D: consecutive turn/end without a new tool name. Currently has no consumer (known gap) |
stuckRepeats | 3 | D: how many repeats of the same aggregate key count as stuck |
mojibakeMinRuns | 2 | C3-a: longest run of consecutive U+FFFD before the encoding warning fires |
activityLimit | 24 | 0.6.0: how many activity entries the ring buffer keeps (drops from the head past this) |
activityBytes | 8192 | 0.6.0: total UTF-8 byte cap for the activity ring buffer (drops from the head past this) |
reasoningChars | 400 | 0.6.0: characters a single reasoning excerpt is truncated to |
resultHeadLines | 6 | 0.6.0: head lines kept from a tool result / error |
redactKeys | 11 keys | 0.6.0: argument-redaction keys (case-insensitive substring match): key / token / secret / password / passwd / pwd / authorization / cookie / dsn / apikey / credential |
subagentWaitTools | ['wait_agent'] | 0.6.1: waiting tool names (waiting on a subagent); they skip "slowest tools" and are listed as their own wait kind |
humanWaitTools | ['ask_user_question'] | 0.6.1: waiting tool names (waiting on the user), classified human |
jobWaitTools | ['job_output','job_wait'] | 0.6.3: waiting tool names (waiting on a background job) — the fourth kind. Only a call whose arguments carry wait: true counts as job; a snapshot without wait counts as real execution |
slowMs | 60000 | 0.6.3: slow-call threshold in milliseconds; a tool whose maxMs reaches it carries slow: true on the wire, and the client adds ⚠ plus a pointer to the background-tasks plugin |
handoffExport | true | Master switch for the 0.7.0 handoff export. On by default; an explicit false really does nothing (no probing, no process, no directory) |
handoffExportTokens | 240000 | Export is considered once the step's input tokens reach this (lowered from 400000 in 0.8.1 — the measured hard stop on this machine was 341421) |
handoffExportMinDeltaTokens | 60000 | Re-export only after the session grew by this much (lowered from 100000 in 0.8.1) |
handoffExportDir | 'handoff' | Export directory, relative to the session cwd |
handoffExportFull | false | Whether to pass --full (attaches every block's raw messages; a much larger document) |
handoffExportBiliBin | '' | Path to the bili executable; the empty string selects the probing chain described below |
handoffExportTimeoutMs | 120000 | 0.9.2 (P1-4): hard timeout for one bili export (and for the lane-list read), in milliseconds. On timeout it kills first, destroys both pipes and only then escalates to SIGKILL (lib/handoff.js · runBili). One key shared by both call sites (runExport / listLanes); an invalid value falls back to 120000 |
handoffExportWindowPercent | 25 | Threshold as a percentage of the model window when the window is known. One knob shared by the token and byte criteria (lowered from 40 in 0.8.1: the old 40% × 1M equalled the old token knob, so it never bound) |
handoffExportMaxPerProcess | 64 | Most exports started per process; exhausting it records failed plus one warning (raised from a hardcoded 8 in 0.7.5) |
handoffExportSubLanes | false | Whether to export the session's sub-lanes (|) as well. Off by default since 0.7.8 (one over-threshold lane used to cost one export per lane) |
handoffExportBytes | 1800000 | Byte criterion: fires when the model-visible volume reaches it (OR-ed with the token criterion); lowered from 3000000 in 0.8.1 = 240000 × 7.5 |
handoffExportMinDeltaBytes | 450000 | Throttle for the byte criterion (lowered from 8000000 in 0.8.1 — the old value was above the threshold, making a second byte-triggered export a dead end) |
handoffExportFreshMs | 300000 | Only fresh events trigger: an event folded from further back than this many milliseconds does nothing (blocks the cold-start replay burst) |
handoffExportRefreshBytes | 0 | Whether one lane may be exported repeatedly. 0 = at most one document per lane (default since 0.7.8); setting a byte delta restores "refresh per watermark bucket" |
rotation | 'auto' | Rotation mode: off / manual (one clickable panel row) / auto. auto by default since 0.9.1 |
rotationCooldownMs | 600000 | Minimum interval between two rotations (process-wide, to break rotation chains) |
rotationOpenChild | true | 0.9.0: whether the client switches to the child session the host created (in auto mode it switches automatically) |
rotationFreshMs | 300000 | 0.8.1: rotation is judged only on fresh events (same purpose as handoffExportFreshMs) |
rotationRequireIdle | false | 0.9.2: whether rotation requires the session to have no open round. Default false — creating a blank session does not interrupt a running turn; true restores the 0.8.0 behaviour (measured: a session that is never idle never rotates) |
rotationArchiveOld | false | Whether to archive the old session after switching (false since 0.8.1: archiving drops it from the same list projection the @ picker reads, so the @{old} lead would break, and the UI has no un-archive entry) |
rotationIncreaseTitle | true | 0.20.0: whether a rotation child is renamed after the parent's persisted title with the official (N) convention (the parent's title is read through ctx.sessionTitle.get, the child written through rename; an absent service, a missing title or a failed rename only downgrade) |
rotationCreate | false | 0.20.0: whether a threshold crossing actually creates a new session. false (the default) only records remind — shouldRotate still recognises "at threshold", but nothing is created and the client shows a suggestion; set true to restore the 0.19.x automatic child session |
rotationSeedMessage | '继续旧会话 {old}(工作目录 {cwd})。…' | 0.9.0: the opening-script template ({old} = old session id, {cwd} = working directory). Since 0.21.1 it is no longer written into the new session — it only renders the text you copy from the status bar button or the settings page; that copy is now the only route that puts the old session id into the context |
Restart DSH after changing configuration.
Note: the per-key behaviour of the handoffExport* and rotation* families (0.7.0 handoff export, 0.8.0+ rotation) is
described in Chinese in README.zh.md §「交接文档自动导出」/§「到量轮换」; the defaults above are the
same values.