dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
DSH (DeepSeek Harness) conversation rewind plugin - rewind to any user message, interrupt a running turn, hide the tail from chat view and model context, cancel freely before sending.
English | 简体中文
A conversation-rewind plugin for DSH (DeepSeek Harness). A permanent bundle plugin with a host half and a web client half — zero dependencies, zero build steps.
snapshotEvents() /
eventAt() and falls back to session.events on older hosts.user / steering renderers of
conversation.chat.node, so only those rows ever carried a data-xsj-seq
stamp. The model's assistant-step output, tool calls and context rows
render through the shipped renderer and were never stamped. The hiding
pass treated an unstamped row as "no evidence" and therefore visible, so a
committed range hid the prompt while the answer stayed on screen.test/hiding.test.mjs.display untouched./state answered, and the two were indistinguishable, so every
load flashed the rewound tail back into view; if the read failed it stayed
visible for good, leaving the UI showing messages the model cannot see.
Sessions now track fetched / fetchFailed: while no answer has arrived the
current verdicts are held and a retry is scheduled, and a locally recorded
mark still applies immediately.agent/disposed no longer strands the patch: ensurePatched
installs a deriveMessages override on the session instance closing over
st.ranges, and disposal used to drop the state record outright, leaving
that override with no record to unwind it — the session kept filtering its
model context permanently, surviving a plugin reload. Disposal now
follows the same rule as evictIfNeeded: unwind first, then drop.ensurePatched is self-healing: it no longer trusts the st.patched
flag alone but compares the installed method against the recorded wrapper
and re-installs when they diverge (idempotent), so a flag that drifts out of
sync cannot silently stop hiding the tail from the model./image answer 404 for an id the log does reference — surfaced as
an image silently dropped on rewind./api/xsj-rewind/image to read a message's durable image bytes by
attachmentId, and the client rebuilds File objects and feeds them back
through the composer's hidden file input, inheriting the shipped image
count/size validation.@deepseek-ai/dsh-client-ui-attachment exports only apply/inject in
0.1.5-rc.2 (no ImageGallery component), so referencing it threw inside
any image-bearing user row and the React error boundary widened the damage
to the surrounding rows — the rewind button vanished across a whole span of
messages. Images now render through the shipped renderMessageImages prop
(routed to the conversation.message.images slot).slots service is resolved
defensively and each seat registers under its own try/catch. A single
registration conflict (e.g. a client HMR rebuild race) previously aborted
apply(), leaving the stylesheet injected with every renderer lost.attachments at call time (ctx.get), so a missing
attachment provider no longer blocks the mount; the image endpoint alone
degrades to a 501.primitives.MessageText was removed; the user
bubble now renders text through the same projectUserText() helper the
shipped bubble uses (reference/session chips included);@deepseek-ai/dsh-client-runtime;mark / cancel / state / image) register on the dsh
web server and therefore follow dsh's own local-trust model: dsh web
listens on 127.0.0.1 by default, so they are reachable from this machine
only and do not pass through dsh's API authentication layer. If you bind dsh
web to a routable address (e.g. 0.0.0.0), these endpoints become reachable
too — restrict them at the network layer (firewall or an authenticating
reverse proxy) in that case./image endpoint is scoped by the session log: it returns bytes only for
attachments that session actually references (matched by attachmentId
against the event stream). There is no path-based or arbitrary-id read. The
bytes come from dsh's attachments.readImage, which verifies integrity.hook/invoked event with payload
{ source: 'xsj.rewind', phase: 'mark' | 'cancel' | 'commit', targetSeq, hiddenFrom?, hiddenTo?, preview? }.
The type is a known-but-unused reserved entry in this build, so the records
are reload-safe.# from anywhere; the path points at your clone of this repo:
dsh plugin --profile web add <absolute path to this repo>
# restart the DSH process, then refresh the browser page
The command registers the package into the profile
(~/.dsh/profiles/<name>/package.json: dependencies + dsh.profile.bundles).
At boot the profile merges this package's cordis.patch.yml, inserting the
host plugin row; the web client scan then serves lib/client.js automatically.
dsh plugin --profile web remove @xsj/dsh-rewind
# restart DSH. Rewind records in session logs are harmless (hook/invoked is a
# known event type).
Session object's
deriveMessages() to skip hidden surface ranges (memoized by a signature of
surface size / range count / replace generation). The request builder, the
llm/stream reconstruction invariant, and the image check all share this
one method, so every reader stays consistent. No message event is ever
added, removed, or rewritten.agent.cancel({ kind: 'user' }, { keepInbox: true }); queued messages
survive and continue from the rewind point.agent/pre-step waterfall, the first step that
claims a real input message seals the hidden range
[targetSeq, current log end]; the new message is appended afterwards and
stays visible.data-chat-flow-key; the
client stamps each row with its seq and a MutationObserver applies inline
display:none to hidden rows. Nothing depends on the host store's internal
shape; cancelling or switching sessions restores everything without touching
any shipped renderer.user/steering cells of
conversation.chat.node at priority -1 (the slot system's native
shadowing), replicating the native bubble (projectUserText / ImageGallery /
Tooltip / writeClipboard) plus the ↺ button.The plugin has no npm dependencies: the host half uses only Node builtins and
injected services; the client half pulls react,
@deepseek-ai/dsh-client-ui-primitives, and
@deepseek-ai/dsh-client-ui-attachment from the shell's frozen module table
via window.__ModuleLoader__. Clone this repo on any machine and follow
"Install".