🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

提示悬浮球 systemsssx/dsh-hint-ball

DeepSeek Harness
systemsssx27 天前有提交已提供中文文档扫描:无法判定

在右下角悬浮球里接收并管理智能体提示

36.2/100
综合分
2
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/10 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

该插件未发布到 npm,按作者文档从 GitHub 源安装即可(静态检查只覆盖 npm 路径,不代表插件不可用)。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add systemsssx/dsh-hint-ball
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · other
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 27 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

仓库 package.json 标记 private,未发布到 npm,需从源码安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包dsh-hint-ball(未发布到 npm,仅可源码安装)
✓Node 引擎要求 >=18 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/24 19:31:42

安全扫描自动 · 静态分析源码
v2.7.0
⚪ 扫描:无法判定尚无人工评估
展开查看扫描说明与证据 ↓

已尝试扫描但取不到可分析的源码:仓库或包不存在、已删除,或为非 JS/TS 实现、未随包发布源码。无法判定,不代表安全。

  • · 取源不可用(Error: github tarball HTTP 404 @ https:
  • · api.github.com
  • · repos
  • · systemsssx
  • · dsh-hint-ball
  • · tarball)
扫描于 2026/11/3(0 天前)

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 右下角可拖动悬浮球
  • 位置记忆与折叠
  • 提示列表与交接面板

README

由 DeepSeek 最新模型翻译生成
dsh-hint-ball · 提示悬浮球 给 DeepSeek Harness(DSH)的提示(hint / 通知)悬浮球:右下角一个可拖动的游戏风格悬浮球,折叠起来是带未读角标的迷你球,展开是「提示 / 交接」双标签面板。 一句话定位:智能体与本地进程都能往球里推提示,你在右下角一眼看到,不必打断正在读的对话。 - 宿主半(lib/index.js + lib/hint-store.js):持有提示列表,开 5 条同源 JSON 路由,注册 post_hint 工具与 hint-ball 设置命名空间。 - 前端半(lib/client.js):手写的 window.__ModuleLoader__.load bundle,零构建,注册到 shell.overlay 插槽,并 portal 到 document.body。 - 零依赖、零构建脚本:纯 ESM JavaScript,package.json 里没有 dependencies,也没有 prepare / postinstall。
展开完整文档(README 剩余 1 节)
dsh-hint-ball · 提示悬浮球

给 DeepSeek Harness(DSH)的提示(hint / 通知)悬浮球:右下角一个可拖动的游戏风格悬浮球,折叠起来是带未读角标的迷你球,展开是「提示 / 交接」双标签面板。

一句话定位:智能体与本地进程都能往球里推提示,你在右下角一眼看到,不必打断正在读的对话。

- 宿主半(lib/index.js + lib/hint-store.js):持有提示列表,开 5 条同源 JSON 路由,注册 post_hint 工具与 hint-ball 设置命名空间。
- 前端半(lib/client.js):手写的 window.__ModuleLoader__.load bundle,零构建,注册到 shell.overlay 插槽,并 portal 到 document.body。
- 零依赖、零构建脚本:纯 ESM JavaScript,package.json 里没有 dependencies,也没有 prepare / postinstall。

目录

- 1. 这是什么
- 2. 功能
- 3. 面板:两个标签页
- 3.1 提示
- 3.2 交接
- 4. 推送提示的两个入口
- 4.1 宿主工具 post_hint
- 4.2 HTTP 路由
- 5. 安装
- 5.1 安装前须知
- 5.2 方式一:DSH 插件管理器(推荐)
- 5.3 方式二:CLI
- 5.4 安装后必做:重启 DSH
- 6. 配置
- 7. 验证
- 8. 卸载 / 回滚
- 9. 文件结构
- 10. 开发与自测
- 11. 兼容性
- 12. 已知限制 / 未验证假设
- 13. License

1. 这是什么

DSH 里的提示(hint)本来无处安放:智能体想说一句「跑完了」「这个决定要你看一眼」,只能写进对话流里,你得往下翻。

这个插件把它变成一枚悬浮球:

- 宿主半持有提示列表(内存,可选落盘),并通过同源 HTTP 路由把列表交给前端;
- 前端半在 DSH 窗口右下角渲染这枚球,折叠时只剩一个迷你球 + 未读角标;
- 提示的来源有两个:宿主工具 post_hint(智能体自己就能推)与 HTTP 路由(任何本地进程、脚本、CI 都能推)。

面板上还有一个「交接」页:它复用 dsh-auto-handoff 的宿主半,把「交接给新会话」这件事从原来的悬浮窗搬到了这枚球里(dsh-auto-handoff 自己的前端半在这台机器上无法渲染)。

提示是全局的:换会话、开新会话,球里的提示都还在,不绑定任何 session。

2. 功能

| 功能 | 说明 |
| 右下角可拖动 | 拖标题栏或迷你球即可移动。拖动范围是整个 web view(四边各留 8px),越界会被钳制;窗口缩放时重新钳制 |
| 位置与状态记忆 | 位置、折叠状态、当前标签页都存在 window.localStorage(dsh-hint-ball:pos / dsh-hint-ball:mini / dsh-hint-ball:tab),下次打开还在原处、还在原来的页 |
| 可折叠成迷你球 | 点标题栏的 — 收成 46px 的迷你球;迷你球右上角是未读角标(未读数) |
| 未读 error 闪红光 | 迷你球上有未读的 error 级提示时,球体呼吸式闪红光 |
| 展开成提示面板 | 点迷你球展开 320×380 的面板,两个标签页,「提示」页的页签上直接显示未读数 |
| 两个标签页 | 提示(列表 + 已读/清空/测试)与交接(压缩状态 + 交接按钮 + 交接结果),见 §3 |
| 三色级别 | info / warn / error 三色描边 + 标签,未知级别一律降级为 info,不报错 |
| 相对时间 | 「刚刚」→「N 分钟前」→「N 小时前」→ 绝对日期(本地时区),30 秒一跳 |
| 已读 / 未读 | 单条点击即已读,顶部有未读计数与「未读 N / 已读」状态片 |
| 一键操作 | 「全部已读」、「清空」(两次点击确认:第一次变成「确认清空?」)、「测试」(自己 POST /hint/push 一条 info 提示,验证通路) |
| 可选落盘 | persistPath 指向一个 JSON 文件,提示(含已读状态)随写随存、下次启动恢复 |
| 可选种子 | seedFile 指向 hints.json / HINTS.md,启动时读一次作为初始提示(有落盘内容时跳过) |
| 零依赖零构建 | 没有 dependencies、没有构建步骤,装的时候不会触发 pnpm 的 allowBuilds 拦截 |

视觉:沿用 dsh-game-hud 的悬浮窗语言(霓虹描边、发光、扫描线、等宽字体、圆角),但内容换成提示列表。

3. 面板:两个标签页

3.1 提示

- 列表新的在最上面;每条是 { id, title, body, level, ts, source, read }。
- 每条显示 标题 / 正文 / 级别标签 / 相对时间 / 已读圆点,点一下即标记已读(本地立刻变,再 POST /hint/read 落库)。
- 标题右侧有级别标签:提示(info)/ 警告(warn)/ 错误(error);边框颜色跟着级别走。
- 空状态写的是:「暂无提示 · 用 post_hint 工具或 POST /hint/push 推送」。
- 底部一行状态:已连接宿主 · 每 Ns 刷新 · 共 M 条;连不上时显示错误,插件被关掉时显示「插件已关闭(enabled: false)」。
- 底部三个按钮:全部已读(无未读时禁用)、清空(两次点击确认,按钮文字先变成「确认清空?」)、测试(推一条 info 测试提示)。

3.2 交接

这一页调的是 dsh-auto-handoff 的宿主半(未改动),路由是:

GET /handoff/state?sessionId=<当前屏幕上的会话> POST /handoff/prepare { sessionId, force: true, instruction? }

页面上依次是:

| 行 | 内容 |
| 「将交接:<会话>」 | 第一行,也是最显眼的一行。显示即将被交接的会话短号(完整 id 在 tooltip 里),并在推之前就写清楚——避免「明明在看 A 会话,却把 B 会话交接出去」 |
| 自动压缩轮数 | 当前累计的自动压缩轮数 / 阈值,压缩进行中显示「· 压缩中」 |
| 工作目录 | 当前会话所在的 cwd |
| 安全状态 | 「处于安全时刻,可以交接」或具体的阻塞原因(如「压缩轮数未到阈值 N」) |
| 指令输入框 | placeholder:「交接指令(可选):新会话要做的第一件事;留空则用宿主生成的默认指令。」 |
| 「强制交接」 | POST /handoff/prepare { sessionId, force: true, instruction? },无视安全闸门立即交接;进行中变「交接中…」 |
| 「实际交接」对照 | 交接完成后显示「交接文件:…」「新会话:…」「实际交接:<短号>」;若与「将交接」不一致,用 error 色写明「实际交接的是另一个会话:将交接 X / 实际 Y」 |
| 脚注 | 「已连接交接服务 · 每 N 秒刷新」或「交接记录保存在工作目录下的 .dsh-handoff 文件夹里。」 |

降级:GET /handoff/state 连不上或返回 ok:false 时,这一页只显示「交接插件未就绪」(带上具体原因,如 /handoff/state → HTTP 404),其它什么都不变——「提示」页、轮询、球本身照常工作。

会话是怎么认出来的:「将交接」的 id 按顺序取 ① slot 的 useSessions 钩子 → ② 客户端 sessions 服务 → ③ 都没有就不带参数,并用 warn 色写「将交接:未识别(宿主将回退到最近活跃会话)」。判定"屏幕上的会话"用的是 DSH 自己的规则 retainedBy.mainView > 0(DocumentTitle / CordisPanel 用的同一条)。两者都只在 try/catch 里机会性读取,拿不到不影响其它功能。

4. 推送提示的两个入口

4.1 宿主工具 post_hint

agent 自己就能推。工具签名:

{
"name": "post_hint",
"parameters": {
"title": "一句话标题(必填)", "body": "可选正文", "level": "info | warn | error(可选,默认 info)" } }

返回 { ok, id, level, unread, total };插件关闭时返回 { ok: false, error: 'disabled' }。

用法示例(在会话里直接说):

用 post_hint 推一条 warn 级别的提示:构建完成

4.2 HTTP 路由

全部同源 JSON,响应带 Cache-Control: no-store。默认端口以你实际打开 DSH 的地址为准(本机 GUI 是 http://127.0.0.1:19387)。

| 方法 | 路径 | 请求体 | 响应 |
| GET | /hint/list | ?since=<ms>&limit=<n>(可选) | { ok, enabled, version, ts, unread, unreadError, total, stats, config, hints } |
| POST | /hint/push | { title, body?, level?, source?, ts?, id? } 或 { hints: [...] } | { ok, added, hint, hints, unread, total } |
| POST | /hint/read | { ids: [...] } 或 { id } 或 { all: true } | { ok, changed, unread, total } |
| POST | /hint/clear | {} 或 { onlyRead: true }(只清已读) | { ok, removed, unread, total } |
| POST | /hint/config | 见 §6 | { ok, applied, needsReload, config } |

推一条 curl.exe -X POST http://127.0.0.1:19387/hint/push -H "Content-Type: application/json" -d "" 读列表 curl.exe http://127.0.0.1:19387/hint/list title 缺失时用正文第一行顶上;title / body 都没有 → 400 title-or-body-required;插件关闭时 /hint/push 返回 409 { ok:false, error:'disabled' }。

5. 安装

5.1 安装前须知

- 零依赖、零构建:package.json 没有 dependencies,没有 prepare / postinstall 脚本,因此不会触发 pnpm 的 allowBuilds 拦截,也不需要编译工具链。
- 安装会写什么:把包装进目标 profile 的 node_modules,并把本包加进该 profile 的 dsh.profile.bundles;本包自带的 cordis.patch.yml 会被应用到该 profile 的层叠配置里(- insert: 一行 id: hint-ball)。它不改动 profile 里任何既有文件。
- 插件以你的权限运行:和所有 DSH 插件一样,宿主半在你的用户权限下执行、能开 HTTP 路由、能读你让它读的文件(seedFile / persistPath)。只从你信任的来源安装插件。

5.2 方式一:DSH 插件管理器(推荐)

官方推荐的就是这条:让插件管理器替你处理 profile 写入、bundle 注册与 patch 应用,不要用 shell 命令去复现安装步骤。

1. 打开 DSH 桌面版,进入 插件 → 添加插件;
2. 粘贴仓库地址:

https://github.com/systemsssx/dsh-hint-ball

3. 确认安装;
4. 重启 DSH(见 5.4)。

运行时这一步走的是 plugin_manager.install_bundle,与你手敲命令装出来的结果是同一件事,但由管理器负责,出错信息也更清楚。

5.3 方式二:CLI

dsh plugin --profile <你的 profile 名> add github:systemsssx/dsh-hint-ball

- --profile 是必填的,把 <你的 profile 名> 换成你自己的 profile(桌面版常见的名字是 desktop);
- 也可以用完整仓库 URL:

dsh plugin --profile <你的 profile 名> add https://github.com/systemsssx/dsh-hint-ball

- 装完包会出现在 $DSH_HOME/profiles/<profile>/node_modules/dsh-hint-ball;
- ⚠️ desktop 这类由 Electron 应用自身管理的 profile 有限制:不要拿它去跑 dsh plugin --profile desktop --dump-config 之类的诊断命令,那些命令只对你自己维护的 profile 有意义;
- 装完要重启 DSH(见下)。

5.4 安装后必做:重启 DSH

换掉已安装包的 JS 模块、或让客户端半生效,都需要重启 DSH。

原因很具体:这个插件的客户端半只在启动时加载。刷新页面不一定让内核重新读取 lib/client.js,于是会出现「GET /hint/list 正常返回 200、球却不显示」的现象——宿主半是热加载的,前端半不是。

重启后确认:

- 宿主半:GET /hint/list 返回 200 且 ok:true(响应里的 version 字段应等于 package.json 的版本号);
- 前端半:右下角出现悬浮球。

6. 配置

优先级:cordis.patch.yml(启动基线) < hint-ball settings 命名空间(宿主挂载 settings 服务时) < 运行时覆盖层(Settings → Hint Ball 通过 POST /hint/config 写入)。

| 配置 | 默认 | 说明 |
| enabled | true | 总开关。false 时 /hint/push 与 post_hint 返回 { ok:false, error:'disabled' }(HTTP 状态 409),面板显示「插件已关闭」 |
| maxHints | 50 | 最多保留多少条(1–500),新的挤掉旧的;改小会立即裁剪 |
| pollMs | 4000 | 前端轮询 GET /hint/list 的间隔,毫秒(1000–60000) |
| autoOpenOnError | false | 出现未读 error 时迷你球自动展开成面板 |
| seedFile | '' | 可选:启动时读一次的 hints.json / HINTS.md。绝对路径,或相对宿主进程 cwd。空 = 关闭 |
| persistPath | '' | 可选:把提示(含已读状态)落到这个 JSON 文件,下次启动恢复。空 = 只存内存 |

- 启动基线写在自带 cordis.patch.yml 的 config: 块里,也可以在目标 profile 的层叠配置里覆盖。
- POST /hint/config 支持 { enabled?, maxHints?, pollMs?, autoOpenOnError?, seedFile?, persistPath? } 或 { reset: true },返回 { ok, applied, needsReload, config }。
- 运行时覆盖层只存在宿主内存里:除 seedFile / persistPath(标记在 needsReload 里,需重载插件或重启)外都立即生效,但重启 DSH 后回到 cordis.patch.yml 的值。这是刻意取舍:本机 0.2.0-rc.2 的内核里没有客户端设置服务(settingsScope 不存在),与其编造一个写配置的 API,不如走插件自己的路由,行为完全可见、可测。
- 设置 → 提示球(settings.section 插槽)就是这套路由的 UI:读 GET /hint/list → config,写 POST /hint/config,非法值会被钳制或拒绝。

种子文件格式(seedFile):

[ { "title": "磁盘将满", "body": "剩余 5GB", "level": "warn" } ]

也接受 { "hints": [ ... ] } 或单个对象。HINTS.md 支持标题写法(# [warn] 标题 + 正文)与列表写法(- [info] 标题 | 正文),级别标记兼容 [warn] (警告) 【error】 等中英写法。文件里的第一条显示在面板最上方。 persistPath 成功恢复了内容时跳过 seedFile(避免重复)。

7. 验证

装好、重启之后,按顺序走一遍(<你的地址> 一般为 http://127.0.0.1:19387):

1. 球出现了吗:打开 DSH 主窗口,右下角应有悬浮球;点一下展开面板,「提示」页标签上带未读数。
2. 路由通不通:

curl.exe <你的地址>/hint/list

期望 HTTP 200,且 JSON 里有 "ok":true、"version":"0.1.0"、hints / unread / config 字段。

3. 推一条测试提示:在会话里说「用 post_hint 推一条 warn 级别的提示:构建完成」,工具应返回 { ok: true, id, level: "warn", unread, total },球上角标 +1、面板里出现该条。
(也可以点面板里的「测试」按钮,它会自己 POST /hint/push 一条 info 提示并立刻显示。)
4. 记忆生效吗:把球拖到别处、收成迷你球,刷新页面——位置与折叠状态不变。
5. 交接页:切到「交接」页,第一行「将交接:<短号>」应当就是你现在看的那个会话;没装 dsh-auto-handoff 时这里显示「交接插件未就绪」,不影响提示页。

8. 卸载 / 回滚

插件管理器:在「插件」里移除 dsh-hint-ball,然后重启 DSH。

命令行:

dsh plugin --profile <你的 profile 名> remove dsh-hint-ball

只禁用、不卸载(任选一种,都无需卸载包):

- 在目标 profile 的 cordis.patch.yml 里,给 id: hint-ball 那一行加 disabled: true;
- 或把 config.enabled 设为 false——球会变暗、推送被拒(409),路由仍然应答,便于排查;
- 或运行时 POST /hint/config { "enabled": false }(重启后失效)。

回滚到安装前的状态:本插件不改动任何既有文件,唯一的外部写入是可选落盘的 persistPath 文件(默认关闭)。若你为 persistPath 指了路径,删掉那个 JSON 文件即可清空历史。

9. 文件结构

dsh-hint-ball/
├─ package.json # 零依赖、零构建;dsh.bundle.patch + dsh.client ├─ cordis.patch.yml # - insert: 一行 id: hint-ball / name: 'dsh-hint-ball'(附全部配置项注释) ├─ LICENSE # MIT ├─ README.md # 本文件 ├─ lib/ │ ├─ index.js # 宿主半:提示仓库 + 5 条路由 + post_hint 工具 + settings 命名空间 │ ├─ hint-store.js # 纯数据层:归一化、环形缓冲、未读计数、已读/清空、种子与持久化格式 │ └─ client.js # 前端半:window.__ModuleLoader__.load 手写 bundle(无构建步骤) ├─ locale/ │ ├─ zh.json # 中文标题 / 描述 │ └─ en.json # 英文标题 / 描述 └─ test/ ├─ run.mjs # 零依赖自测(480 项断言) └─ _scan.mjs # 辅助脚本:对已安装的 DSH 运行时做字符串扫描(开发用)

10. 开发与自测

零依赖、零构建。在插件目录里:

cd C:\Users\syste\.dsh\plugins\dsh-hint-ball
node --check lib/index.js
node --check lib/hint-store.js
node --check lib/client.js
node --check test/run.mjs
node test/run.mjs

test/run.mjs 用假 cordis ctx 驱动真实的 apply(),并且用假的 window.__ModuleLoader__ / react / fetch 真正加载并渲染 lib/client.js,覆盖:

| 分组 | 覆盖内容 |
| [1] hint-store | 归一化、环形缓冲、未读计数、已读/清空、序列化格式 |
| [2] host routes through apply() | 五条路由的注册、状态码、请求体与响应体 |
| [2b] post_hint tool + live settings | 工具成功/拒绝/禁用三条路径;设置命名空间 |
| [2c] POST /hint/config | 写入、裁剪、钳制、reset,以及三层配置优先级 |
| [3] seed file + persistence | HINTS.md / hints.json 解析、落盘、重载恢复(含已读状态)、坏文件降级 |
| [4] client bundle | 渲染、级别三色、相对时间、已读/清空/测试按钮、拖动与 localStorage 记忆、折叠与未读角标 |
| [4b] no top safe band | 四边各 8px 钳制、四个角、无顶部安全带 |
| [4c] 交接 tab | GET /handoff/state 的每条降级路径 |
| [4d] 交接 targets the session ON SCREEN | 「将交接」取的是屏幕上的会话、短号渲染、「实际交接」对照与不一致告警 |
| [5] verified contract strings | window.__ModuleLoader__.load、slots.inject('shell.overlay')、slots.inject('settings.section')、ctx.inject(['webServer'])、settings.register('hint-ball', …)、dsh.client.inject 的取值等 |

实际执行结果(2026-10-07,node v24.19.0,win32/x64):

$ node test/run.mjs
[1] hint-store …
[2] host routes through apply() …
[2b] post_hint tool + live settings …
[2c] POST /hint/config (settings.section backend) …
[3] seed file + persistence …
[4] client bundle (draggable ball) …
[4b] no top safe band — 8px edge clamping, four corners …
[4c] 交接 tab (id-less fallback + every degradation path) …
[4d] 交接 targets the session that is ON SCREEN …
[5] verified contract strings …

480 passed, 0 failed

自测零依赖、不联网、不碰 profile:只读写系统临时目录。

11. 兼容性

| 项 | 值 |
| DSH 桌面版 | 0.2.0-rc.2(2026-09-29 内核),本机实测 |
| Node.js | ≥ 18(package.json 的 engines) |
| 操作系统 | win32/x64 实测通过;macOS / Linux 未验证(代码里没有平台相关分支) |
| 依赖 | 0 个运行时依赖,0 个构建步骤 |
| 前端插槽 | shell.overlay、settings.section |
| 客户端契约 | window.__ModuleLoader__.load({ id, factory }),exports.inject = ['slots'] |
| 交接页依赖 | 可选:dsh-auto-handoff 的宿主半(未安装时该页降级为「交接插件未就绪」) |

12. 已知限制 / 未验证假设

已在本机验证(自测覆盖):lib/hint-store.js 全部逻辑;lib/index.js 的五条路由、post_hint 工具、三层配置优先级、种子与持久化;lib/client.js 的组件渲染、拖动、localStorage 记忆、折叠/展开、已读/清空/测试按钮、settings.section 设置区(走路由读写)、「交接」页各条降级路径与会话短号渲染。

前端插槽与注入契约:已由本机字节扫描实测确定(目标:…\DeepSeek Harness\resources\app.asar,0.2.0-rc.2,121 MB):

| 标识符 | 出现次数 |
| shell.overlay | 46 ✅ |
| settings.section | 39 ✅ |
| settings.plugin.item | 0 ❌ 未使用 |
| settingsScope | 0 ❌ 未使用 |

cordis 把 exports.inject 里的每个名字都当成硬依赖:服务不出现,apply() 就永远不被调用。所以 exports.inject 只保留确定存在的 ['slots'];轮询改用 window.setInterval / window.clearInterval(不依赖 timer 服务);设置区改成走插件自己的路由(不依赖 settingsScope)。

宿主侧已实测:装上后 GET /hint/list 实测返回 200,post_hint 已出现在工具表里。

照抄参考插件、但未经真实内核运行验证的部分:

- ctx.slots.inject('settings.section', () => ctx.slots.register({ name, id, order, label: () => '…', inject: () => ({}) }, Component)) 的形状照抄 dsh-orb(本机已装、实测可用);
- ctx.slots.inject('shell.overlay', () => ctx.slots.register({ name, id, order }, Component)) 的插槽名实测存在,注册形状与 dsh-game-hud / dsh-auto-handoff 相同;
- package.json 的 dsh.client = { platform: 'web', inject: ['@deepseek-ai/dsh-client-ui-settings', '@deepseek-ai/dsh-client-ui-conversation'] }:两个包名都在 app.asar 里出现(分别 431 / 107 次),前者正是 dsh-orb 声明的那一个。不要写 @deepseek-ai/dsh-client-runtime(在 app.asar 里只有 2 次偶发出现,参考插件都没用它)。

其它已知限制:

- 没有客户端设置服务:运行时覆盖层只存在宿主内存,重启 DSH 后回到 cordis.patch.yml 的值(设置区里已注明)。
- 轮询而非推送:前端每 pollMs 拉一次 /hint/list,没有 SSE / WebSocket,所以外部推的提示最坏有约一个 pollMs 的显示延迟。
- 顶部安全带被刻意移除:球可以停在窗口最顶端(四边都只留 8px),此时可能盖住 DSH 顶栏的按钮,得自己拖开。这是换取「整个 web view 自由移动」的代价——对比 dsh-orb:它的球是独立的 Electron 窗口,能跑到 DSH 窗口之外;本插件的球是 web view 里的 DOM 元素(position: fixed),不可能超出窗口,也不会创建任何原生窗口。
- 提示是全局的,不绑定会话:换会话、开新会话,球里的提示都还在。
- 「交接」页的会话识别是机会性的:props.useSessions 与客户端 sessions 服务都只在 try/catch 里读,拿不到就不带 sessionId 并显著提示「未识别」,绝不硬编码一个 id。
- 未验证、因此没有使用:settingsScope、settings.plugin.item、客户端 timer 服务、任何「从宿主直接调用前端」的接口、以及上述之外的所有 cordis 服务。
- 自测是假 ctx / 假 window 的单元与渲染测试,不能替代真实内核里的一次人工走查(尤其是前端半的渲染)。

13. License

MIT © 2026 systemsssx
预览分享卡片长什么样 ↓systemsssx/dsh-hint-ball
分享 · DeepSeek Harness Hub
systemsssx/dsh-hint-ball

在右下角悬浮球里接收并管理智能体提示

回到顶部