DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Url Router — DSH Plugin for DeepSeek Harness
← Plugins
U

dsh-url-router

Url Router

DSH Web GUI address bar routing plugin: each interface has its own link (sessions / main dashboard / plugin pages and component pages / task board); the entire line is the actual link, using only a fragment.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:DDDMUC/dsh-url-router#cbcb8f3c9530d59f4b5c6b7bfdbdc1179d51c608
READMECompatibilityVersions

Compatibility and provenance

Url Router is published as dsh-url-router and currently resolves to version 0.3.1. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
github
Registry updated
10/11/2026

Versions

0.3.1stable
10/11/2026
0.3.0stable
10/11/2026
0.2.0stable
10/9/2026
Show 2 more versionsCollapse versions
0.1.2stable
10/9/2026
0.1.0stable
10/8/2026

Related plugins

Loading related plugins…

Latest
0.3.1
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
web
License
MIT
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
10/13/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in

Related plugins

More verified plugins in ui-customization.

Client Ui Skill Explorer@linxin666/dsh-client-ui-skill-explorerDSH skill center: browse loaded skills by source (bundled / project / user / custom / runtime), enable or disable, create and delete, in a web GUI panel.Remote Web Ui@linxin666/dsh-remote-web-uiScan-to-pair remote access for the dsh web GUI that shares one official interface: a QR beside the settings button pairs phones and PCs into the same Web GUI (a portrait-touch adaptation layer for phones, full desktop on PCs) through one-time tokens and rClient Ui Task Board@linxin666/dsh-client-ui-task-boardHost-authoritative task board for the DSH Web GUI with real session execution, Host cron scheduling, and optional cross-platform idle-sleep protection; mounted without DSH source changes.Client Ui Git Graph@linxin666/dsh-client-ui-git-graphExternal dsh web GUI plugin: a blank-session git branch selector + Git graph, with real host-side git operations and guards, as a dsh profile bundle

README

dsh-url-router

DSH Web GUI 地址栏路由插件 —— 每个界面都有自己的链接:地址栏写着屏幕上的东西,链接点开就是那个界面。 给 DeepSeek Harness (dsh) Web GUI 补上"可寻址":点侧栏会话,地址栏变成 #/session/<id>;点插件面板,变成 #/panel/plugins;点进某个插件、某个组件、某个任务,地址栏跟着一起走。把这条链接贴到新标签页、或者对着侧栏任意一行右键,就是浏览器自己的行为——无需复制按钮、无需自定义菜单。

它是地址栏的唯一写者:只改 URL 的 fragment,路径与查询串(例如启动时的 ?token=…)原样保留;只用 replaceState,浏览面板不会往后退栈里塞历史。只有浏览器半区——零依赖、无宿主路由、无遥测。

中文 · English


中文

安装

# 通过插件管理器(推荐)
dsh plugin --profile web add dsh-url-router

# 重启 dsh web,之后硬刷新浏览器

开发时也可以直接挂工作树:

dsh plugin --profile web add "link:/path/to/dsh-url-router"

路由表

地址界面由谁打开
#/session/<id>主视图里的那个会话uiWorkspace.openSession(id)
#/panel/<panelId>主面板(plugins、task-board、skill-explorer、ssh …)layout.selectPanel(id)
#/panel/plugins/<包名>某个已安装插件的页面面板自己的列表行控件
#/panel/plugins/<官方项 id>某个官方内置插件的页面(shell、agent-loop、subagent、web-search)面板自己的列表行控件
#/panel/plugins/<包名>/<组件 id>插件页面里的某个组件页面板自己的组件行控件
#/panel/task-board/task/<任务 id>任务看板里某个任务的详情任务看板自己的 dsh-taskboard-open-task 窗口事件
#/panel/task-board/new任务看板的新建任务表单任务看板自己的 dsh-taskboard-new-task 窗口事件

输入侧宽容:sessions/panels 复数、百分号编码都接受,一律规范化成上面的形式。不认识的段位不碰,只留一条诊断(留给以后的路由器,或者别的插件写的深链形态 ✓ —— 一个 fragment 只能有一个写者 ✓,所以读到不属于本插件的形态时会明确说一句,而不是静默 ✗)。

面板内部页是面板自己的词汇表,本插件不发明:插件管理器发布 data-plugin-detail / data-plugin-item-detail / data-plugin-row-detail,任务看板发布 data-dsh-taskboard-open-task / data-dsh-taskboard-new-task,并接受同名窗口事件。

每一行都是真链接

侧栏的会话行、插件面板的列表行(已安装组与官方组)都是整行覆盖的透明真锚点:

  • 右键 → 浏览器原生菜单(在新标签页中打开 / 复制链接 / 另存为)
  • 中键、Cmd/Ctrl + 单击 → 原生新标签页
  • 左键单击 → 在本页打开(preventDefault 后调官方导航,不新增历史记录)

它守的规矩

  • 只动 fragment:路径与查询串从不改写(启动 ?token=… 能活下来)。
  • 唯一写者:本插件拥有 fragment,请不要和别的写 fragment 的插件同时启用(例如 dsh-session-url),两者会互相覆盖。
  • 只用 replaceState:浏览面板不污染后退栈。
  • 轮次信息:能证明才写 ✓。助手行自己的身份里就带轮次(row/assistant/80/32 = 第 80 轮第 32 项 ✓);工具行不带 ✗(只有调用 id ✓)→ 于是我从视图的轮次边界 [data-turn-start] 反推 ✓,但只在行夹在两个已渲染边界之间时才写 ✓(turn/82/row/tool/call/… ✓)。视图是虚拟化的 ✓,边界可能只渲染了一侧 ✗ → 那时宁可不写轮次 ✓,也绝不猜一个错的轮次 ✗。
  • 轨迹里的每一行都有自己的链接 ✓:#/session/<id>/row/<类>/<作用域>/<id>(例:row/tool/call/call_ce3a…、row/assistant/80/32 = 第 80 轮第 32 项 ✓;有工作区时跟在会话 id 之后 ✓)。身份来自视图自己发的 data-trajectory-row-key ✓(值是 <类>%00<作用域>%00<id> ✓,我把它拆成可读路径 ✓);你家 Trajectory Plus 发的是 data-dshts-turn(轮号 ✓)→ 那种行按轮次写(turn/<n> ✓)。点一行就反映进地址栏 ✓(纯被动:不 preventDefault ✓)。粘贴行链接会打开那个对话并尽力滚到那一行 ✓ —— 视图是虚拟化的 ✓,没渲染出来的行不会被假装滚到 ✗(不会骗你 ✓)。
  • 会话视图(对话 / 轨迹 / 轨迹plus …)也进地址栏 ✓:#/session/<id>/view/<viewId>(有工作区时是 #/workspace/<名>/session/<id>/view/<viewId> ✓)。视图 id 是真的 id ✓(来自槽位 conversation.view 的 id 字段 ✓,按 order 排序后与头部页签一一对应 ✓):实测本机是 chat / trajectory / surface(Trajectory Plus ✓)/ plus2(Trajectory Plus 2 ✓)。默认视图(第一个 ✓)不写进链接 ✓,所以普通对话链接保持短 ✓。粘贴视图链接会真的切过去 ✓(与其它覆盖层不同:这是链接存在的意义 ✓)。
  • 工作区是"它住在哪",所以写在链接最前面 ✓:#/workspace/<工作区名>/session/<会话id>(侧栏本身就是这个形状 ✓)。工作区名是给眼睛看的 ✓ —— 决定打开哪个会话的永远是会话 id ✓,所以名字过期/写错也照样打开对的会话 ✓(地址栏随后自己纠正成真实工作区 ✓)。读不到工作区行(没有侧栏 / 树里没有)就不猜 ✓,退回 #/session/<id> ✓。
  • 作用域由视图决定,不靠猜:主面板是应用级界面(列的是本机插件,不是某个对话),所以它的链接不带会话 id。
  • 链接落地即交权:视图一旦变成链接描述的那个界面,链接立刻失去权威——这样你在面板里继续点进去时,地址栏不会被拽回上一层。
  • 绝不抛错:官方 selectPanel 对未注册的面板 id 是抛异常的;所有宿主面调用都被容纳,失败只留一条诊断并回落到屏幕上真实的视图。

已知限制

  • 轮次链接是"位置",而且现在真能跳 ✓:点某一轮,地址栏记下 #/session/<id>/turn/<n> ✓;粘贴它会打开那个对话、把历史翻页回那一轮、再滚到它 ✓(真机实测:贴 /turn/118 → 窗口变成 118→121、目标在视口 true、最顶可见正是 118 ✓)。用的是官方已有公开契约 ✓:sessions.retainScope(id, source) 拿到会话控制器 ✓ → session.projections.faceOf('turnOutline') 读到那一轮的 seq ✓ → session.loadThrough(seq) 翻页回去 ✓(完事 reference.release() ✓)→ 再按官方视口同款选择器 [data-chat-turn]:not([hidden]) 滚到它 ✓。座位高度/相交都读不到时不算到位 ✓,宁可继续重试也不假报 ✗。
  • 右栏 pane 已闭环 ✓:#/session/<id>/pane/<kind> 与 #/panel/<面板>/pane/<kind> ✓(真机验证:贴链接开出对应页签 ✓、地址栏跟着切换 ✓)。页签种类由右栏自己注册 ✓(实测 7 种:guide / subagentchat / changes-review / plan / files / text / terminal ✓)。
  • 设置面板已纳入:#/settings ✓、#/settings/<分区> ✓、#/settings/<分区>/<页签> ✓(页签靠标准 role="tab" + aria-selected ✓,分区内任何页签都吃这一套 ✓)。分区没有稳定 id ✗(实测:导航项上只有 aria-current="true" ✓,父链是 nav ✓,右侧内容区一个 data-* 都没有 ✗;官方内部的 openSection(id) 也不对外 ✗)→ 所以分区的身份就是它的显示名 ✓:反映读「aria-current="true" 且属于 nav」的那个按钮的标签文字 ✓,驱动按标签点 ✓。含义:换语言或官方改文案后,旧的分区链接会失效 ✗(但你重新点一次,地址栏就会写出新链接 ✓ —— 自洽、不过期 ✓)。裸 #/settings 只要面板开着就算落地 ✓,随后地址栏自动升级为具体分区 ✓。
  • 设置页分区暂未纳入(旧描述):设置包没有"打开某个分区"的接缝(它们是 keyed list slot),只能等它自己发布类似契约。
  • 会话内的轮次与行锚点已纳入 ✓:#/session/<id>/turn/<n> ✓(反映 + 翻页 + 滚动 ✓ 全链路已闭环)、#/session/<id>/row/<类>/<作用域>/<id> ✓(反映 + 尽力滚动 ✓,含可证明时的轮次归属 ✓)。轮次跳转用的是官方公开 API ✓,没有等待任何新接缝 ✓(uiChat.scrollToTurn 那条请求已降级为锦上添花 ✓,讨论见 https://github.com/deepseek-ai/deepseek-harness/discussions/9339 ✓)。
  • 技能中心 / SSH 的内部页:需要它们各自发布"当前实体 id + 按 id 打开"的契约(任务看板就是这么做的)。
  • 和别的 fragment 写者互斥(例如写 #msg= 的"跳到消息"插件):一个 URL 只有一个 fragment ✓,两个写者只能轮流拥有 ✗。本插件不假装合并 ✓ —— 它认出外来 fragment ✓、绝不覆盖 ✓,并明确说"只能启用一个写者" ✓(而不是互相静默擦掉对方的链接 ✗)。

开发

手写 JS 直接进 lib/(无构建步骤),npm test 直接跑交付产物(35→45 条用例,node --test)。改之前请读 AGENTS.md 里的路由与行链接契约。

排障

浏览器 Console 里调用 window.__dshUrlRouter.report() ✓,它会列出:当前地址栏 ✓、本插件认为屏幕在哪个界面 ✓、正在落地的链接与重试次数 ✓、每一层读到了多少个钩子 ✓、右栏 pane 的真实 kind 列表 ✓、以及它拒绝认领的段位 ✓。它绝不出错、也不写任何东西 ✓。

English

A URL router for the DSH Web GUI — every surface gets its own link. Click a conversation and the address bar becomes #/session/<id>; click a panel (Plugins, Task Board, …) and it becomes #/panel/<panelId>; walk into a plugin, a component, or a task and the bar follows. Paste the link into another tab, or right-click any sidebar row for the browser's own "open in new tab / copy link".

It is the single writer of the fragment: path and query string (a launch ?token=…) are never touched, and it only ever calls replaceState. Browser half only — no dependencies, no host route, no telemetry.

Install

dsh plugin --profile web add dsh-url-router
# restart `dsh web`, then hard-refresh the browser

Routes

RouteSurface
#/session/<id>the conversation the main view shows
#/panel/<panelId>a main-column panel
#/panel/plugins/<package>an installed plugin's page
#/panel/plugins/<item>a built-in plugin's page (shell, agent-loop, subagent, web-search)
#/panel/plugins/<package>/<component>one component page inside that plugin's page
#/panel/task-board/task/<taskId>one task's detail on the task board
#/panel/task-board/newthe task board's new-task form

A kind it does not know is left alone with a single diagnostic (a fragment has exactly one writer, so a foreign shape is named rather than silently ignored). Panel inner pages are the panel's own vocabulary: the plugin manager publishes data-plugin-detail / data-plugin-item-detail / data-plugin-row-detail, the task board publishes data-dsh-taskboard-open-task / data-dsh-taskboard-new-task.

Every row is a real link

Conversation rows and both plugin-list groups carry a transparent full-row anchor: right-click gives the native menu, middle/Cmd-click opens a native new tab, and a plain left click navigates in place without adding a history entry.

Rules it keeps

  • Fragment only. Path and query are never rewritten.
  • One writer. Do not run another fragment writer (dsh-session-url) beside it.
  • replaceState only, so panels never fill the Back stack.
  • Scopes are declared, not guessed. A panel is application-level and carries no session id.
  • A link stays authoritative until it lands, then hands the address bar back.
  • Never throws. Refused navigations are contained with one diagnostic.

Limits

Still open: Skill Center / SSH inner pages, which need their own "publish the current id + accept an open request" contract the way the task board did. Session links are meaningful on the same machine and DSH_HOME only.

  • 链接同名不跨机:会话 id 只在同一台机器、同一个 DSH_HOME 下有意义。