packages/dsh-task-board
zhu1090093659/dsh-web侧边栏多列任务看板:卡片交给真实 DSH 智能体会话执行,支持 cron 定时(Host 侧到点执行,关浏览器也生效)。
在对话右侧轮次导航条上右键收藏某一轮:该短横线变为导航条满宽并换成强调色,便于之后一眼找到,再次右键取消。收藏按对话隔离(取当前选中会话 id)并持久保存,刷新后仍在;不引起布局跳动,导航条保持固定间距。
Bookmark turns from the conversation's right-edge turn rail — the column of short dashes where each dash marks one turn and jumps back to it when clicked. A bookmarked dash grows to the rail's full length and takes the accent colour, so a specific turn stays easy to find in a long conversation.
Right-click a dash to bookmark it; right-click again to unbookmark.
A long conversation gives you a rail of identical dashes. The shipped rail already distinguishes the active turn, but nothing lets you mark the turns you care about — the decision, the diff, the answer you keep scrolling back to. This plugin adds exactly that one bit per turn, and makes it visible at a glance by reusing the rail's own "full length" geometry.
scaleX 0.4 for turns not loaded into the transcript, 0.6 for loaded ones) to the rail's full width (scaleX 1), and switches from the neutral border colour to the accent colour.scaleX changes.dsh plugin add dsh-starred-turns
Or add it to a profile's cordis.patch.yml by hand:
- insert:
- id: starred-turns
name: dsh-starred-turns
Restart the app (or let HMR rescan) after installing: the Host only scans plugin packages at startup.
The rail is drawn by @deepseek-ai/dsh-client-ui-chat and is not slot-extended, so the plugin decorates it from the outside rather than forking the package. Each dash is:
<button data-index="18" class="…_mark …_markActive" aria-label="Jump to turn 19"></button>
with the visible dash supplied by a ::before pseudo-element:
.…_mark:before { width: 20px; height: 2px; transform: translateY(-50%) scaleX(.6); }
.…_markActive:before { transform: translateY(-50%) scaleX(1); }
.…_markUnloaded:before { transform: translateY(-50%) scaleX(.4); }
So the plugin does three things, all from the outside:
contextmenu listener on document toggles the bookmark for the dash under the pointer;MutationObserver (watching data-index and child insertion) plus a store subscription keep a data-dsh-starred-turn attribute painted on the right dashes;scaleX(1) in the accent colour.Bookmarking deliberately reuses the dash's own scaleX geometry instead of changing width or height, which is what keeps the rail's pitch intact.
The observer never watches the plugin's own attribute — it writes that attribute, so an unguarded observer would retrigger itself forever. Paints are also guarded by a read of the current attribute for the same reason.
Bookmarks live in a client store named dsh.starred-turns.v1, keyed by conversation:
{ "byConversation": { "session-…": ["1", "7"] } }
The shell backs persist with localStorage. On the Desktop build the page origin is the stable dsh-app://app scheme, so bookmarks survive app restarts there. On a plain browser the Host picks a new loopback port per launch and browsers scope localStorage by origin including the port, so bookmarks do not carry across restarts in that mode.
npm install
npm run build # src -> lib (client bundle in the shell's closure-factory format)
npm test # bundle shape, exported surface, selector targets
src/client.js — store, rail painting, right-click gesture, stylesheetsrc/index.js — node half (host-side no-op; exists so the Loader has an entry module)scripts/build.mjs — copies the node half and bundles the browser half with esbuildMIT