dsh-think-ux

DSH PLUGINUI 与外观

仓库 el16z3c/dsh-think-ux · npm dsh-think-ux

UI 与外观 未标注验证等级 安全审查:未标注 可信度:未标注 可安装插件
安装这个插件

为 DeepSeek Harness Web UI 提供顺滑的思考过程体验:推理时思考行自动展开并平滑跟随滚动,结束后以短动画收起,避免画面跳变。

一句话选型结论

按资料字段整理

dsh-think-ux 是UI 与外观类的 DSH 可安装插件,未做沙盒验证,暂无安全审查结论,列出 4 项功能,有可直接复制的安装命令。验证通过不等于安全:插件会读写文件、执行命令或联网,装前先到仓库确认它做了什么;涉及密钥或系统权限的,建议先在隔离环境试装。

分类UI 与外观 收录类型可安装插件 验证等级未标注验证等级 安全审查未标注
验证等级 UNKNOWN 未标注验证等级
GitHub 星标 0 复刻 0 · 未关闭 issue 0
最近更新 2026-09-18 创建于 2026-09-11
README 24.6 KB 正文体量,越大说明说明书写得越细

安装

可安装插件
在 DSH 里执行,装完用 dsh plugin list 确认已挂上;标了 L4 / L5 的命令已在沙盒里真实跑通
dsh plugin --profile web add dsh-think-ux
  1. 1
    确认版本与运行环境

    仓库没有标注兼容版本与 Node.js 要求,先确认你的 DSH 版本能装,再继续。

  2. 2
    执行安装命令

    在 DSH 里执行上面的命令;多包仓库要注意区分具体子包名,别装错包。

  3. 3
    确认已挂载

    用 dsh plugin list 查看列表里是否出现这个插件,出现即挂载成功。

  4. 4
    试跑并检查权限

    加载后跑一个最小用例,确认它能正常工作;同时看它申请了哪些文件、命令或网络权限。

兼容 DSH 版本未标注版本不匹配时安装会报错
Node.js 要求未标注来自仓库 package.json 的 engines 字段
前置依赖无需要同时安装的同级依赖
npm 包名dsh-think-ux可用 npm view 查看包信息

能做什么

4 项功能
字段来自项目仓库与公开索引,中文说明由本站标注

dsh-think-ux:为 DeepSeek Harness 打磨思考行滑动体验

  • 思考行流式自动展开
  • 预览平滑跟随滚动
  • 结束后动画收起
  • 主对话视图顺滑滚动

上游标签

dsh-plugin

验证等级与安全审查

未标注验证等级
自动化流程结论,不是人工审核
验证等级未标注验证等级上游未给出验证结论,安装前请自行确认
安全审查未标注静态分析结论,未标注不代表已通过审查
仓库健康度未标注按仓库活跃度与最近更新时间给出
可信度未标注综合仓库活跃度与验证结果

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。
  • 列出了 4 项功能,能直接看出它解决什么问题。

先想清楚的地方

  • 安全审查还没结论,装之前先看仓库改了什么、要什么权限。
  • 没有声明 Node.js 版本要求,版本不匹配可能装不上。
  • 验证通过不等于安全:插件会读写文件、执行命令或联网,装前先到仓库确认它做了什么。

更适合

  • 需要在UI 与外观场景里给 DSH 补能力的人。
  • 能接受在本地装依赖、愿意自己确认权限的人。

不太适合

  • 只使用 DSH 官方内置能力、不接受第三方插件的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
插件验证等级安全审查星标兼容版本安装命令
dsh-think-ux当前 未做沙盒验证 未标注 0 未标注 有
nuwa-skill 未做沙盒验证 未标注 3.8 万 未标注 有
awesome-dsh-plugin L4 · 沙盒安装通过 低风险 1.8 万 0.1.1-rc.2 有
deepseek-balance-whale-widget L4 · 沙盒安装通过 低风险 4,492 0.1.7-rc.2 等 2 个 有
dsh-better-sidebar L4 · 沙盒安装通过 低风险 4,112 0.1.7-rc.2 等 10 个 有
dsh-deep-whale L4 · 沙盒安装通过 低风险 2,470 未标注 有

仓库档案

UI 与外观
字段来自项目仓库与公开索引,中文说明由本站标注
作者 / 维护方el16z3c仓库 dsh-think-ux · 默认分支 main
分类UI 与外观ui
收录类型可安装插件声明了 dsh.bundle、可用 dsh plugin add 安装的条目
开发语言JavaScript仓库主语言
许可证MIT商用或二次分发前请确认条款原文
星标 / 复刻 / issue0 / 0 / 0收录时的数值,非实时
创建 / 更新2026-09-11 · 2026-09-18最后推送 2026-09-18
本站收录2026-09-17首次进入本站目录的时间

README 全文

24.6 KB
作者原文,中文版优先;只做安全转义,不改内容

dsh-think-ux

Smooth "thinking" experience for the DeepSeek Harness (dsh) Web UI: while a
model reasons, its think row expands as a capped 24-line preview that glides
to the bottom as text streams in; when reasoning settles, the preview
collapses with a short height animation instead of a one-frame ~490 px
jump. The main conversation view follows the same way — streamed output
glides up (long-session opens swoosh), and a scrollTop write trap makes
reader-vs-bundle scroll intent unambiguous, so the view glides instead of
snapping.

Pure DOM client plugin: no bundle changes, no services, no network calls,
no timers beyond one settle animation. Verified against DSH 0.1.5-rc.2.

Install

dsh plugin --profile web add dsh-think-ux

Then refresh the Web session (the profile layer picks it up on reload).
For another profile: dsh plugin --profile add dsh-think-ux.

Uninstall

dsh plugin --profile web remove dsh-think-ux

Refresh; the Web UI returns to stock behavior. Nothing to clean up.

Tunable constants (top of lib/client.js)

Constant Default Effect
CAP_LINES 24 think-preview line cap
CHASE_TAU_MS 70 glide exponential time constant (both chasers)
CHASE_MAX_PX 16 constant glide speed (px per 60 fps frame, ~960 px/s)
GAP_FAST_MIN 800 episode split: starting gap ≥ this = pure exponential swoosh, below = constant glide
COLLAPSE_MS 180 settle-collapse animation duration; 0 = instant unmount
MAIN_SMOOTH_FOLLOW true kill switch for the main-view glide + anchor override + method shadows
READER_INTENT_TTL_MS 700 reader-intent window (covers the bundle's 500 ms sample)

Any change is a one-line edit + reinstall of the local copy (see Local
development).

It is NOT upgrade-proof. It is verified against DSH 0.1.5-rc.2 and depends
on that version's DOM attributes and client load protocol. Behavioral
assumptions (the selectors, the click-to-toggle row, the bundle's plain
scrollTop write path) degrade quietly when broken — the plugin simply
stops doing its thing (see Residual risks). Registration/manifest
mismatches do NOT degrade quietly: the 0.1.0 release shipped a client
registration name that did not match the package name, and that made the
whole Web UI fail to load ("Failed to load plugins", not stock behavior).
If you see that page naming dsh-think-ux, you are on 0.1.0 — run
dsh plugin --profile web update dsh-think-ux (0.1.0 is deprecated on npm;
0.1.1 fixed it).

Behavior

  1. Think rows expand while reasoning streams. Any [data-variant="think"]
    row with data-state="running" is auto-expanded via a synthetic click on
    its [data-disclosure-row] element (React keeps owning the state). When the
    row settles (data-state="ok") the plugin auto-collapses it — unless the
    reader toggled that row themselves; a trusted click on the row hands it over
    permanently (plugin never touches it again for the row's lifetime). The
    collapse plays a short height animation on the capped body
    (COLLAPSE_MS, 180 ms) BEFORE the unmounting click: an instant body
    removal drops ~490 px of content in one frame and clamps a
    bottom-pinned reader down by the whole box in one visible jump, while the
    animation lets the browser clamp frame by frame (a smooth slide). The
    animation ENDS via the body's own transitionend (guarded by target +
    property); a COLLAPSE_MS + 300 ms safety timer — started at the
    animation's real start, not the settle — ends it early if the transition
    never completes (hidden tab, cancelled mid-flight, long main-thread
    stall; the early end just skips the tail of the slide). The finish
    clears the transition but KEEPS the inline height: 0 so the body
    unmounts with zero residue (clearing it first would flash the natural
    full height for a frame under load). A reader toggle during the
    animation cancels it (the body hands back to its natural height); a row
    REMOVED mid-animation (settle + unmount in the same frame) is cleaned up
    by the removal path (the record and listeners do not linger on the
    detached node); COLLAPSE_MS = 0 restores the instant unmount.
    History rows and rows under [data-turn-process-inline][hidden] are left
    alone.
    While auto-expanded, the body is a capped preview: at most 24 lines
    (line height taken from the bundle's own secondary-content token,
    calc(20px + var(--dsh-content-font-delta-secondary,0px))), with 24 px
    top/bottom fades. It is a hidden-scrollbar scroll box that a single rAF
    ticker chases to the bottom with the main view's smooth-episode
    step (70 ms time constant CHASE_TAU_MS, constant CHASE_MAX_PX
    speed ~960 px/s — the preview body is at most ~500 px, below the
    GAP_FAST_MIN threshold, so it always glides), so appended streaming
    text glides up smoothly instead of jumping in token chunks. A reader scroll up inside the preview
    pauses that row's follow (terminal style); returning within 25 px of
    the bottom resumes it. The cap applies only to plugin-managed rows: a
    reader toggle lifts it permanently for that row (their expansion is
    full-height and unscrollable), and settle auto-collapse removes it
    anyway.

  2. Reader scroll intent via a scrollTop write trap. Any reader-initiated
    upward movement (wheel up, touch finger-down drag, PageUp/Home/ArrowUp, or
    any upward scrollTop drift) arms a 700 ms intent window. A passive clamp
    is NOT reader intent: when content above the reader shrinks (a settled
    think row collapsing), the browser clamps scrollTop down — it reads as
    upward drift but ends at the floor, so it does not arm (otherwise every
    turn boundary would freeze the smooth follow for 700 ms and fast-catch-up).
    A real upward move leaves the at-bottom band within a few frames and arms
    there. The plugin then installs a defineProperty trap on the scroller's
    scrollTop.

The discriminator is structural, not heuristic: the bundle's follow re-pin
is a plain JS assignment (el.scrollTop = el.scrollHeight in
toBottom/followRef), while every reader input method — wheel, touch,
scrollbar thumb, track click — scrolls natively inside the browser and never
passes through the JS property setter. So the reader's return can never be
misclassified
(no event-shape heuristics, no thresholds to tune):

  • a write whose target is at or beyond floor-minus-25 while the reader sits
    more than 25 px above the floor (inside the window) is a re-pin (the
    bundle writes el.scrollHeight, which overshoots and is clamped to the
    floor): it is let land (the bundle's own bookkeeping stays consistent)
    and the reader's position is restored in the same tick — the yank never
    paints, and the resulting scroll event makes the bundle's 500 ms sample
    heal atBottomRef=false, so it stops re-pinning on its own;
  • a DOWNWARD arrival within 45 px of the floor (the re-follow zone) ends the
    intent and actively bottoms out: the pristine bundle only re-engages its
    follow at its own 25 px threshold, so a reader stopping in the 25–45 px
    band would otherwise strand (intent off, follow dead). The ≤45 px
    bottom-out nudge lands the bundle at 0 px, where its debounced sample
    flips atBottomRef back to true and native follow resumes (typically
    within the 500 ms sample debounce plus the next content chunk). A reader
    who PASSES through the band on the way up is armed, not nudged; a reader
    who stops there is left there.
  • exceptions (re-pin-shaped writes LET THROUGH, intent ends): a NEW
    reader-initiated element appeared since arming — a durable user flow row
    (data-chat-flow-kind="user"), a pending-steering bubble
    (data-pending-steering), or a submission echo
    (data-submission-echo) — i.e. the bundle's "show me my message" jump;
    or a trusted click on the scroller's back-to-bottom button (the only
    ` inside the conversation scroller and outside the[data-chat-flow]column), queued by a capture-phase click listener so the button's owntoBottom` write is never reverted even inside the
    intent window.

The 700 ms window covers the bundle's 500 ms scroll-sample debounce
(SCROLL_SAMPLE_INTERVAL_MS = 500), the only window in which the bundle can
yank.

  1. The main conversation view glides too. While the reader is at the
    bottom (follow mode), streamed agent output glides up instead of jumping in
    token chunks: the bundle's follow re-pin is intercepted and handed to an
    exponential chaser (same 70 ms CHASE_TAU_MS constant), and both the
    reader's return within the 45 px re-follow zone and the back-to-bottom
    button land with a glide rather than a snap. Turn-rail navigation glides
    too: a right-rail jump to a past turn lands through the bundle's
    landOnRow property write, which is identified by its caller stack (not
    its destination), swallowed, and chased to the row with the same episode
    machine; a re-land write while the glide is running (a chunk reflow while
    an unloaded turn loads) retargets it and keeps the episode speed. Any
    upward reader input stops
    follow mode immediately; a content-growth observer on the scroller re-arms
    a stopped chase while the reader is at the bottom, so a stale bundle
    atBottom sample cannot strand the view. Chase writes go through the
    original prototype setter (bypassing the re-pin trap) and land exactly at
    the floor, so the bundle's 500 ms at-bottom bookkeeping stays coherent.
    The chase speed is set per episode (chaseStep + st.episode,
    shared by both chasers): each chase episode — a gap created by one
    content event, closed to the tail — runs at ONE speed, chosen from the
    gap the episode STARTS with (a speed that tracks the shrinking gap
    decays a big swoosh into the slow flat speed in the last ~800 px and
    visibly crawls home — "fast to near the bottom, then slow"):
    - starting gap >= GAP_FAST_MIN (800 px): pure exponential (21 % of
    the gap per frame at 60 fps) for the WHOLE episode — opening a long
    session swooshes all the way to the bottom (~0.7 s for 30 000 px),
    no slow tail;
    - starting gap < 800 px: constant CHASE_MAX_PX px per 60 fps frame
    (~960 px/s) — a new tool-call row or body block (100–400 px in one
    commit) glides smoothly instead of swooshing.
    Episodes re-classify after each landing and upgrade smooth -> fast
    when a big insertion grows the gap past the threshold mid-episode
    (a large content block is a swoosh, not a crawl; no downgrade, so no
    oscillation).
    Browser scroll anchoring (overflow-anchor, default auto) is
    disabled on each bound scroller while MAIN_SMOOTH_FOLLOW is on:
    with the reader pinned at the bottom, an insertion of a large chunk
    (a tool row, a code block) makes the anchoring adjustment shift
    scrollTop by the WHOLE chunk in one frame — a native snap, visible
    as a stiff jump, and it fights the 16 px/frame chase. With anchoring
    off, every bottom tracking goes through the episode-speed chase
    (glide for small gaps, swoosh for large ones). The pre-override
    inline value is restored on unbind.
    Scroll methods are shadowed too: a scrollTo/scrollBy
    call on the scroller bypasses the property trap, so a bottom-targeted
    call made with no armed reader intent (e.g. the turn rail's follow) is
    swallowed and handed to the chaser (glide); every other call passes
    through untouched (rail centering, saved-position restore). The
    scrollTo(x, y) form reads the SECOND argument as the vertical
    coordinate (the first is horizontal; a single-number call is x-only),
    matching the DOM spec.
    Kill switch / rollback: the MAIN_SMOOTH_FOLLOW constant at the top of
    lib/client.js — false restores the bundle's current snap behavior for
    the main view (the think-row follower keeps working); see Rollback.

  2. One active instance per document (singleton takeover). The cordis
    runner registers this plugin per conversation surface: every in-page
    session switch invalidates + re-loads the module, creating a new plugin
    instance in the SAME document. Left alone, N live instances each run a
    document-wide MutationObserver and bind EVERY conversation scroller, so N
    chaser loops step on the same scroller — the source of the intermittent
    stiff follow (a fresh page has few live instances; after session switches
    it has many). The newest instance takes over the document: it publishes
    itself on globalThis.__DSH_THINK_UX_LIVE__ and releases its predecessor
    (observer, traps, rAF chasers, write probe, style tag). Teardown is
    idempotent, so the runner's effect cleanup of a superseded instance is a
    no-op.

Rollback

The git repo IS the rollback mechanism: every deployed state is a commit.

  • Revert to a previous state: git checkout then pwsh -File deploy.ps1 (e.g. git checkout 3e55717 restores the working
    smooth-think / snap-main state; then refresh the GUI).
  • In-place switch: MAIN_SMOOTH_FOLLOW = false in lib/client.js +
    redeploy turns off only the main-body glide (the chase, the method
    shadows, the re-pin intent system and the overflow-anchor: none
    override are all gated on it — with it off every scroll write passes
    through natively and the scroller's pre-override anchor value is
    restored on unbind).
  • Settle-collapse animation: COLLAPSE_MS = 0 in lib/client.js +
    redeploy = instant unmount on settle (the pre-animation behavior,
    whose one-frame ~490 px clamp jump at each turn boundary was the
    visible stiff snap); any small value is the animation duration.
  • Chase-speed states: GAP_FAST_MIN = 0 in lib/client.js + redeploy =
    pure exponential everywhere (fast swoosh for every gap, including
    streaming inserts); GAP_FAST_MIN = 9999999 = one flat 960 px/s speed
    for every gap (the all-capped state, whose slow tail on session open
    motivated the episode rule); the constant tunes which gaps swoosh vs
    glide.
  • Diagnostics: the final build ships with DIAGNOSTICS = false and
    TRACE_SINK_URL = null — no prototype probe, no console traces, no
    sink POSTs (the ~22k-line hunt log came from the on-state). To hunt a
    jank report: DIAGNOSTICS = true +
    TRACE_SINK_URL = &quot;http://127.0.0.1:3999/&quot; in lib/client.js +
    redeploy, start trace-sink.cjs (workspace cleanup-review) to
    collect the log as JSONL on disk, then reproduce. Traces cover intent
    arming, every episode start episode sc#N fast|smooth gap=Npx,
    chase fast frame step=Npx, fast upgrade gap=Npx, land ep=.. Nms,
    uncaught motion > 16 px with the isTrusted flag, native
    non-intercepted writes > 16 px with the caller stack; every line is
    mirrored via fire-and-forget POSTs (a missing sink is a silent no-op)
    and carries a 4-char per-instance id ([think-ux:XXXX]) so instances
    from different surfaces are separable in the shared log; the lifecycle
    lines instance up (doc title=...), takeover from instance XXXX and
    instance down (XXXX) show the singleton hand-off.
  • Last resort: uninstall (above) — the Web UI falls back to stock behavior.

Local development (file:// path)

For hacking on the plugin (or for installs that predate the npm package):
no build step (plain JS):

package.json   dsh.bundle.patch + dsh.client.platform=web, inject: []
lib/index.js   host half — marker only, apply() no-op
lib/client.js  browser half — all behavior
deploy.ps1     parameterized file:// deployer (SHA-verified, prints profile snippet)
trace-sink.cjs  local HTTP sink for the DIAGNOSTICS mirror (dev only)

One command, from the repo root:

pwsh -File deploy.ps1                      # derives root+version from $env:DSH_HOME
pwsh -File deploy.ps1 -DshRoot &#x27;C:\dsh&#x27; -Version &#x27;0.1.5-rc.2&#x27;  # explicit

It copies the plugin byte-for-byte into \plugins\dsh-think-ux\
(upgrade-surviving source of truth) and
\versions\\plugins\dsh-think-ux\ (the copy the profile loads),
verifies SHA256 parity, and prints the profile state. If the web profile
\home\\profiles\web\cordis.patch.yml lacks the insert row, add the
snippet it prints:

- insert:
- id: dsh-think-ux
name: file:////versions//plugins/dsh-think-ux/lib/index.js

Then refresh the GUI (the profile insert is picked up on reload; no other
restart needed). On a DSH version upgrade: rerun deploy.ps1 -Version and re-add the insert row for the new version dir (the top-level
plugins\ copy survives the upgrade untouched).

Constraints honored

  • No @deepseek-ai/* requires; inject: [] (pure DOM, no bundle services).
  • No bare fetch (the runner's closure trap shadows it with a throwing
    redirect on per-agent (re)loads — the trace mirror goes through
    window.fetch). Timer globals (setTimeout/clearTimeout) ARE
    available in the 0.1.5-rc.2 runner: the settle collapse (COLLAPSE_MS)
    uses them, verified at runtime; if a future runner withholds them the
    collapse self-degrades to the instant unmount (try/catch guard).
    Everything else runs on Date.now() + requestAnimationFrame +
    MutationObserver.
  • ctx.effect(callback, label) is a context verb and needs no service
    declaration; unload cascades the effect cleanup (observer, listeners, maps).
  • Selectors are stable attributes only (data-conversation-scroll,
    data-variant, data-state, data-expanded, data-disclosure-row,
    [hidden]) — never hashed CSS-module class names.

Residual risks (honest)

  • Selector stability. The behavior depends on the chat package keeping
    data-variant=&quot;think&quot; / data-state / data-expanded /
    data-disclosure-row. These are documented component-attribute names, not
    build hashes, but a future version could rename them. Failure mode is
    graceful: the plugin simply stops doing anything (no errors, no breakage of
    the host UI).
  • Click-to-toggle assumption. Expansion is driven by dispatching a click
    because the collapsed body unmounts (no keepContentWhenOpen); if a future
    build keeps content mounted and exposes a different toggle primitive, the
    synthetic click may double-toggle. Guard: the plugin re-reads data-expanded
    before every click and expects exactly the recorded result; an unexpected
    external toggle marks the row as user-controlled and stops touching it.
  • Row identity loss on remount. Row bookkeeping is keyed by element
    identity. If a row's element is re-created mid-run (parent swap), the new
    element loses userToggled history: a user-opened row that comes back
    already open is taken over as managed (no click needed) and auto-collapsed
    on settle — the plugin's default policy, not the user's choice. In
    0.1.5-rc.2 this is not reachable in normal operation: the bundle shares one
    keyed renderer instance across streaming/settled/interrupted, the
    in-page "container" change is a hidden-attribute toggle on the same
    wrapper, and any true remount starts collapsed (local useState(false)),
    which the plugin re-manages (re-expand while running, collapse on settle).
    The takeover branch makes the loss degrade to "default policy" instead of
    "stuck expanded".
  • Nested preview scroller. The capped body is a hidden-scrollbar scroller
    nested inside the main conversation scroller. A reader wheel/touch up
    inside the preview bubbles to the main scroller's listeners and can arm the
    700 ms intent window — the desired semantics (reading up anywhere pauses the
    main-view yank), but the two scroll layers share the intent system. The
    re-pin trap only watches the MAIN scroller's scrollTop; preview scrolling
    never passes through it and is unaffected by intent state. If a future
    bundle adds its own per-row scroll handling, the smooth follow degrades to
    plain (janky) auto-scroll or none — the row features are unaffected.
  • Capped preview line count. The 24-line cap is computed from the bundle's
    secondary-content line-height token; if a future version changes that token
    the cap drifts by a fraction of a line (cosmetic only — the box stays
    bounded either way). The fade mask is clamped (min/max stops) so short
    bodies (fewer than ~2 lines) degrade to a symmetric fade instead of an
    inverted gradient.
  • Write-path assumption. The re-pin trap sees JS property assignments
    (el.scrollTop = x); the scroll methods (scrollTo/scrollBy on the
    bound scroller) are shadowed, so a bottom-targeted call with no armed
    reader intent is also handed to the glide. Together they cover every
    programmatic scroll in 0.1.5-rc.2 (toBottom, followRef, land-on-row,
    saved-position restore, turn-rail scrollTo). If a future version
    switches the follow to scrollIntoView (or another API), re-pins bypass
    both layers and the yank becomes visible again (the row features are
    unaffected; with DIAGNOSTICS on, the uncaught motion is named in the
    console). Native reader scrolling is never affected either way.
  • Bottom-out nudge is a real (small) jump. A downward arrival in the
    25–45 px band pulls the view to the true bottom (≤45 px). That is the
    requested 45 px re-follow semantics — the bundle's own bookkeeping only
    accepts ≤25 px — but a reader who stops exactly in the band is pulled the
    last few pixels instead of being left there. With MAIN_SMOOTH_FOLLOW on
    (the default) this pull glides instead of jumping; the kill switch restores
    the snap.
  • Main-body smooth follow (newest feature, first to flip off). The
    conversation scroller's glide is a per-scroller rAF chaser that writes
    scrollTop through the original prototype setter, bypassing the re-pin
    trap — so chase writes are never misclassified and the bundle's 500 ms
    at-bottom sample stays coherent (the chase lands exactly at the floor, 0
    px). Mid-glide the bundle sees "not at bottom", which matches its own
    follow semantics (it stops re-pinning while the reader is technically
    above the floor). The chaser is self-terminating (one rAF chain, no
    timers). If the glide ever misbehaves, MAIN_SMOOTH_FOLLOW = false +
    redeploy restores the pre-feature behavior in effect — verified branch by
    branch: with the switch off, every trigger (growth observer, re-pin
    intercept, reader return, jump button) falls back to the original snap
    path, and the only residue is one inert content observer per scroller.
  • Back-to-bottom button identification. The button is recognized
    structurally (the only ` inside the conversation scroller, outside the[data-chat-flow]` column), not by a stable attribute. If a future
    build puts another button in that spot, that button's jump would also be
    let through while the intent window is open (harmless: it still lands the
    reader at the bottom where they can be).
  • Turn-rail jump near the floor. A rail/anchor jump that lands the view
    within 25 px of the bottom, made while the 700 ms intent window is open and
    no new reader-initiated element appeared since arming, is indistinguishable
    from a re-pin and gets reverted. Rare combination; jumping again works.
  • Row-glide writer identification. Turn-rail navigation is recognized by
    the writer's caller stack (landOnRow / realizePendingJump), captured at
    the write. If a future bundle renames these internals, rail jumps stop
    matching and fall back to the bundle's native snap — no breakage, and no
    other behavior is affected. The bundle's anchor-compensation corrections
    (which keep the reader's row stable across prepends) come from a different
    stack and stay instant by construction: gliding a correction would drift
    the view under a reader mid-page.
  • Cosmetic flicker. A reverted re-pin still runs the bundle's toBottom
    side effects (setAtBottom(true), active-turn update) before the restore, so
    the "jump to bottom" affordance can flicker once per revert; the bundle's own
    500 ms sample heals it.
  • Re-pin revert window. The 700 ms intent TTL covers the bundle's 500 ms
    scroll-sample debounce (the only window in which the bundle can yank). A
    re-pin arriving just after TTL expiry is not reverted (by design — the reader
    may have stopped moving and follow should resume).
  • Upgrade path. The bundle is pristine (verified by SHA against
    state-registry.txt); the plugin is the sole layer. On a DSH version
    upgrade: the top-level plugins\dsh-think-ux\ survives; recopy it into the
    new versions\\plugins\ dir and re-add the profile insert row pointing
    at the new version-dir copy. If the new version's scroller no longer uses
    plain scrollTop assignments, the scroll-intent half degrades to
    bundle-default behavior (rows unaffected).

常见问题

7 问
答案由本站依据条目字段整理,不引用上游原文
dsh-think-ux 怎么安装?

在 DSH 里执行 `dsh plugin --profile web add dsh-think-ux` 即可。对应的 npm 包名是 `dsh-think-ux`。

dsh-think-ux 的验证等级是什么意思?

未标注验证等级。上游未给出验证结论,安装前请自行确认

dsh-think-ux 安全吗?

未标注。

dsh-think-ux 装之前要先确认什么?

先看它会读写哪些文件、执行哪些命令、连接哪些网络地址;验证等级只说明装得上、跑得起来,不等于安全。涉及密钥或系统权限的,建议先在隔离环境试装。

dsh-think-ux 用的是什么许可证?

上游标注为 MIT。商用或二次分发前请到仓库确认许可证原文。

dsh-think-ux 有哪些功能?

思考行流式自动展开、预览平滑跟随滚动、结束后动画收起、主对话视图顺滑滚动。

这条记录的数据可靠吗?

本站按仓库名去重后合并整理,字段以作者仓库与 npm 元数据为准;安装命令、仓库地址与 README 保持原文,带 L4 / L5 标记的安装命令已在隔离沙盒里真实跑通。

UI 与外观
按星标排序,可作替代方案

nuwa-skill

nuwa-skill

女娲 DSH plugin 只需输入一个名字,就自动调研、提炼并验证任何人的心智模型、决策启发式与表达 DNA,生成可直接调用的思维视角 S

未标注验证等级 3.8 万 星

awesome-dsh-plugin

awesome-dsh-plugin

A curated list of plugins for DeepSeek Harness (dsh) · DeepSeek Harnes

L4 · 沙盒安装通过 1.8 万 星

deepseek-balance-whale-widget

DeepSeek-Balance-Whale-Widget

DSH 界面右下角的常驻小鲸鱼余额挂件,实时显示 DeepSeek 账户余额、今日已用与每轮对话消耗,支持拖拽吸附、Q 弹动画与音效,开箱即

L4 · 沙盒安装通过 4,492 星

dsh-better-sidebar

DSH-better-sidebar

面向 DeepSeek Harness 的服务化侧边栏工作台插件,把文件编辑、终端、Git 变更、子代理任务与侧边对话整合进右侧栏与底部面板

L4 · 沙盒安装通过 4,112 星

dsh-deep-whale

dsh-deep-whale

DSH Web 鲸鱼娘皮肤系列(深海女仆工坊 maid-atelier)。

L4 · 沙盒安装通过 2,470 星

deepseek-design

deepseek-design

可视化设计工作室,支持网站、App 原型、海报、信息卡、报告和杂志的模板创建、元素编辑、选区级 AI 草稿衔接与导出。

L4 · 沙盒安装通过 1,438 星

插件的元信息来自作者仓库;分类、验证等级与安全结论的中文说明为中文整理,最近核验 —。