DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

Pinned Sessions — DeepSeek Harness 插件(DSH Plugin)
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
P

@vfvrpq/dsh-pinned-sessions

Pinned Sessions

DeepSeek Harness 的置顶会话:侧边栏中的一个「置顶」分组——为所有工作区中的每个置顶会话提供原生样式的会话行,位于 Workspace 浏览器正上方,并支持就地搜索。

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:439436269-ctrl/dsh-pinned-sessions#c687fdea1ae7ab9db3c092f0ddf2c38973269cf6
README兼容性版本

兼容性与来源证明

Pinned Sessions 以 @vfvrpq/dsh-pinned-sessions 发布,当前版本为 0.4.0。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/10/7

版本

0.4.0stable
2026/10/7
0.3.1stable
2026/10/7
0.3.0stable
2026/10/6

相关插件

正在加载相关插件…

最新版
0.4.0
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 0
周下载
0
最近提交
2026/10/7
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 productivity-workflow 分类下经过校验的插件。

Deepseek Ipptdeepseek-ipptiPolloWork PPT Studio 及其精选幻灯片模板,作为原生 DeepSeek Harness 对话视图。Codex Ui@michengai/dsh-codex-uiDSH Codex UI — 为 DeepSeek Harness Web 提供 Codex 风格侧栏、工作区会话树、全局搜索和轮次导航Remotedsh-remoteDeepSeek Harness 的远程工作助手:连接 SSH(密码/密钥/代理/键盘交互/代理跳转),选择远程工作区,使用 22 个 rw_* 工具操作该工作区(包括 rw_edit/rw_stat/rw_mkdir/rw_remove/rw_move/rw_forward),具备冲突感知的镜像 syAi Novel Writer@ethanyoq/dsh-ai-novel-writer面向 DeepSeek Harness 的本地优先小说项目插件

README

dsh-pinned-sessions

npm package: @vfvrpq/dsh-pinned-sessions · repo: dsh-pinned-sessions

A pinned-session group in the sidebar for DeepSeek Harness: 「置顶」 sits where a Workspace group sits — a 34px header with an outline pin glyph, a count and a search button, and 32px session rows under it for every pinned session, across all workspaces. Pin enough of them and you can search right there.

English | 中文

What it does

DSH already pins sessions (hover a row → pin glyph, or right-click → 「置顶会话」), but the result is only a re-order inside that session's own workspace group: a pinned session still scrolls away when you switch workspaces, collapse groups, or drown in a long list.

This plugin gives the pinned set its own group, above the Workspace browser:

插件
自动化任务
工作区                        ← the native section header
置顶  1  dsh-pinned-sessions v0.4.0  🔍   ← this plugin, inside the list
   插件笔记:dsh-cost-…   默认工作区   4 小时前
默认工作区
   新会话
   …

With the search open (the count becomes matched/total):

置顶  1/3  dsh-pinned-sessions v0.4.0  ✕
   [ 搜索置顶会话              ]
   插件笔记:dsh-cost-…   4 小时前
  • rows are drawn with the native session-row metrics (32px rows, 14px titles, 10px meta, the same hover wash and hover-revealed actions), so the group is visually indistinguishable from a workspace group;
  • the group is mounted inside the native list's own scroll container, as its first item: it sits under the 「工作区」 header with the same scrollbar as the groups below, never squeezes them, and steps aside while the list shows search results;
  • each row shows which workspace it belongs to (默认工作区) and carries the session's own status dot — running (blue) or finished-but-unopened (green) — from the real session-status hook; title, workspace and time also ride the row tooltip;
  • Settings → 通用 has a 「置顶会话区」 switch, so the group can be turned off without editing anything;
  • the header carries the plugin's npm identity — dsh-pinned-sessions v0.4.0 — as a muted chip that links to @vfvrpq/dsh-pinned-sessions on npm (target="_blank"; the desktop shell turns that into shell.openExternal, so it opens in your browser instead of inside the app). The chip shows the unscoped name because the sidebar is 256px wide; its tooltip/aria-label carry the full scoped name, and clicking it never toggles the group;
  • the header's outline pin matches the line-icon style of the sidebar entries above it (插件 / 自动化任务); a row's own pin marker stays filled, keeping "state" distinct from "navigation";
  • clicking a row opens that session; hovering one reveals 「取消置顶」;
  • the header's 🔍 filters this group in place: title match, case-insensitive, surrounding whitespace ignored; opening the search expands the group, and Esc or a second click closes it and clears the query; a query with no match gets its own line, distinct from the "nothing pinned yet" hint;
  • the header is a disclosure control — click to collapse, and the choice survives reloads. When nothing is pinned the group shows a one-line hint instead of rows;
  • running sessions keep the native state dot; archived pins are hidden with a count note; subagent sessions never appear.

It owns no new state: pinning is the Host capability the native Workspace browser already ships (dsh-api-workspace-controller → workspaces.pinSession / unpinSession, persisted in the workspace storage unit), so the sidebar and the group always agree — pin with either one and the other updates immediately.

How it is mounted

The sidebar's browsing region between the global panel rows and the foot is declared as one single slot (sidebar.workspaces) owned by @deepseek-ai/dsh-client-ui-workspace, and it exposes no "extra group" seat:

seatownerwhat it holds
sidebar.panellist (list)ui-sidebarthe global panel rows (插件, 自动化任务, …) — a row is a button, not a group
sidebar.workspaces (single)ui-workspacethe whole browsing region: header, search, tree, menus

Shadowing sidebar.workspaces would mean reimplementing the entire browser (search, flat/grouped views, drag ordering, menus, hover cards, archive flow), so instead this plugin mounts next to the renderer's own outlet anchor (div[data-slot="sidebar.workspaces"], display: contents) as its previous sibling inside the region, and portals the group into that host node:

  • nothing is ever inserted into the native component's DOM subtree;
  • the host node is flex: none, so the native browser keeps flex: 1 and simply gets a little less height — the pinned group stays put while the list scrolls;
  • the anchor is re-resolved through a throttled MutationObserver, so the group survives re-renders and sidebar collapse/expand;
  • if the anchor ever disappears (a future DSH changes the sidebar), the plugin renders nothing instead of breaking anything.

Feedback

Bugs and ideas: Issues.

Install

dsh plugin --profile <your-profile> add @vfvrpq/dsh-pinned-sessions

The package is dual-face (dsh.bundle.patch + dsh.client): the Loader row brings up the no-op Host half, and the browser half arrives through exports["./client"].

Local development (this checkout)

cd ~/.dsh/profiles/desktop
# 1) make the package resolvable (pnpm hard-links a directory dependency, so a
#    symlink keeps edits live). The install name comes from the package's own
#    package.json, so a scoped package lands under node_modules/@vfvrpq/:
pnpm add file:/path/to/dsh-pinned-sessions     # or hand-edit package.json
ln -sfn /path/to/dsh-pinned-sessions node_modules/@vfvrpq/dsh-pinned-sessions
# 2) activate the row in your own patch layer (hot: the loader watches it)
cat >> cordis.patch.yml <<'YAML'
- insert:
    - id: dsh-pinned-sessions
      name: '@vfvrpq/dsh-pinned-sessions'
YAML

Then reload the Web UI (⌘R / F5). The boot graph is rebuilt per page load, so an edited lib/client.js shows up on the next reload — no application restart. Do not also add @vfvrpq/dsh-pinned-sessions to dsh.profile.bundles at the same time: insert is append-only and never de-duplicates ids, so the plugin would be mounted twice and its slot registrations would collide. (Appending that row to a patch file that still holds the template's bare [] produces invalid YAML and is silently ignored — [] plus a sequence is two documents in one file.)

Develop

lib/client.js is the browser bundle, written by hand in the same window.__ModuleLoader__.load({ id, factory }) shape the build emits — plain JS with react.createElement, no build step, no JSX. apply(ctx) registers exactly one entry:

registrationslotid
sidebar group (portals into the sidebar)shell.overlay (list)pinned-sessions-section

Client services it injects: slots, sessions, workspaces, uiWorkspace, locale. It reads the two stores (sessions.list, workspaces.list) through useSyncExternalStore and never writes to them directly.

Checks

<bundled node> test/bundle-check.mjs

Registers the bundle against a fake window.__ModuleLoader__, materializes the factory with stub require, runs apply() against a fake Client Context and renders the group with a hook shim — asserting the entry id, the dictionaries' key parity, the anchor selector, pin order, the count, the running dot, the unpin toggle (and that it does not also open the row), collapse, the empty hint, the archived note, subagent filtering, the English copy, and the npm chip (its text, its href, target/rel, and that clicking it does not toggle the group).

Because a client bundle cannot read its own manifest, lib/client.js repeats the package name and version (PACKAGE_NAME / PACKAGE_VERSION). The chip checks compare them against package.json, so a version bump that forgets the bundle fails the suite instead of shipping a stale chip.

The DOM-mounting half needs a real sidebar, so it is covered by the Playwright pass recorded in VERIFY.md.

Layout

lib/index.js      Host half — no-op; exists so the Loader row resolves and the
                  client-modules scan can find the package
lib/client.js     Browser half — the whole feature
cordis.patch.yml  Bundle patch: one row, id === package name
test/bundle-check.mjs

Known boundaries

  • The group lists pinned, non-archived sessions; archived pins are summarised in a note instead of listed (matching the native archive filter).
  • Subagent sessions (origin: "subagent") never appear.
  • Order is the native pin order (newest pin first); this plugin adds no custom sorting, and the group is a flat list rather than one sub-group per workspace.
  • Mounting is anchor-based, not a slot: a future sidebar rewrite that removes div[data-slot="sidebar.workspaces"] would hide the group.