DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

wangtheme-coder /

wangtheme-coder/dsh-greeting

Verified

给 DSH 主页 / 新会话界面加一行按时段变化的问候语(傲娇鲸鱼娘口吻,可自定义台词)

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@36616dbf

dsh-greeting

给 DSH 的主页 / 新会话界面加一行按时段变化的问候语(像 ZCode 那句「夜深啦,别忘了照顾好自己哦」), 位置在 hero 区「探索未至之境」标题正下方、工作区选择器上方。

  • 纯插件实现:不碰 DSH 本体、不改 React 节点、不动任何官方 CSS 类名之外的样式。
  • 台词按本地时间分 7 个时段随机抽一句,跨时段自动换(每 30s 检查一次,无需刷新)。
  • 只在 hero(空白新会话)出现;一旦进入真正的会话就消失。
  • 停用插件 / 删掉目录即彻底消失,没有任何残留。
  • 桌面版窗口只认 dsh.client 客户端模块(tapIndex 注入进不了 asar 里的静态首页), 详见下面「两条下发通道」。

安装(推荐)

插件市场:在 DSH 的插件市场里搜索 dsh-greeting,一键安装。

手动按 tarball 安装:

dsh plugin --profile desktop add "https://github.com/wangtheme-coder/dsh-greeting/releases/download/v0.2.0/dsh-greeting-0.2.0.tgz"

(把 desktop 换成你在用的 profile 名,web 版用 web。)

装好后重启一次 DSH(宿主进程启动时才会扫描 dsh.client 声明并写进模块图), 问候语就会出现在主页;之后改配置、改台词都不用再重启。

本地开发安装

源码就在 $DSH_HOME/plugins/dsh-greeting,profile 侧只需三样东西:

  1. profiles/<profile>/package.json → dependencies 里加 "dsh-greeting": "link:C:/Users/ASUS/.dsh/plugins/dsh-greeting";
  2. 同一个 package.json → dsh.profile.bundles 里加 "dsh-greeting";
  3. profiles/<profile>/node_modules/dsh-greeting 建 junction 指向源码目录 (New-Item -ItemType Junction -Path <link> -Target <src>)。

装好之后要重启一次(只有一次):宿主进程启动时才扫描 dsh.client 声明并把它写进 模块图,而模块图(pkgMeta 判定 + index.js 的 ESM 缓存)在进程内不会重扫 —— 热挂载 只会把宿主侧半边挂上去,客户端半边必须等宿主换进程。重启后 GET /dsh-greeting/config.json 返回 200、模块图里出现 dsh-greeting 行,问候语就出来了。

此后改代码不用重启:assets/greeting.js、client.js 都是每次请求现读文件; client.js 还挂在 dsh-client-hmr 的 500ms 轮询上,改完自动热替换正在开着的页面。 改 greeting.json 更是立刻生效。

两条下发通道(重要)

通道 到哪儿 桌面版窗口 浏览器打开 127.0.0.1:19387
dsh.client 模块(client.js,走 /plugins 组合路由 + 模块图) 所有 web 前端 ✅ 唯一可达 ✅
webServer.tapIndex 注入 + /dsh-greeting/greeting.js 只注入宿主 HTTP 首页 ❌ 到不了 ✅

原因:桌面版窗口的文档不是宿主首页,而是 Electron 私有协议 dsh-app://app/ 直接从 app.asar 里读的静态 dist/index.html(lib/main.js 的 protocol.handle:/、 /index.html、/assets/*、favicon 走 serveWebDocument(<asar>/.../dsh-web-frontend/dist)), 所以 tapIndex 注入的 <script> 永远进不了用户真正看的那个窗口。两条通道共用同一套 DOM 标记(data-dsh-greeting)、同一个 data-slot 记账和同一份配置,谁先到谁写, 另一份看到「当前文本仍在本期台词池里」就自动让位,不会抢也不会闪。

配置

配置文件:$DSH_HOME/greeting.json(首次运行自动生成,改完刷新页面即可生效,不用重启)。

{
  "enabled": true,
  "fontSize": 14,
  "reloadShortcut": true,
  "phrases": {
    "lateNight": ["这句会替换掉内置的凌晨时段台词"],
    "evening": ["晚上好。今天也算辛苦了…只有一点点。", "第二句也可以"]
  }
}
字段 说明
enabled false = 前端不显示问候语(插件本身仍在,可随时改回来)
fontSize 字号(px),默认 14
reloadShortcut 默认 true:把 Ctrl+R / F5 接回页面刷新(见下节);设 false 关掉
phrases 按时段覆盖台词数组;没写的时段用内置默认

关于「刷新页面」:这个应用本来刷不了

DSH 桌面版(Windows 打包版)的应用菜单只挂了两个 visible:false 的 toggleDevTools (其中一条带 accelerator: "F12"),生产环境没有 role: "reload" 菜单项, lib/main.js 里连 webContents.reload 都没有 —— 所以 Ctrl+R、 F5 全都没人处理,页面刷新不了。

  • 第一次让脚本生效(或客户端还没起来的时候): F12 打开开发者工具 → 在 Console 里敲 location.reload() 回车 (DevTools 面板是焦点时 Ctrl+R 也能重载页面);或者退出应用重开。
  • 装好本插件之后:页面里的 keydown 监听会把 Ctrl+R / F5 接回来调 location.reload(),从此肌肉记忆可用(reloadShortcut:false 可关)。 它不干扰输入框;Ctrl+Shift+R 也一并接成普通刷新 (页面全 no-store,强刷本来就没区别)。实测(隔离宿主 + 无头 Chrome,把 greeting.js 兜底脚本整个掐掉、只用 client.js):Ctrl+R / F5 都真的换了文档(哨兵变量随之消失), 刷新后问候语自己回来;reloadShortcut:false 时按键原样放行。 注意 Ctrl+R 只重载页面,宿主侧代码(新路由、新 dsh.client 声明)仍然要重启应用才生效。

时段划分(本地时间,改边界要同时改 client.js 与 assets/greeting.js 的 SLOTS)

key 时间 内置台词示例
lateNight 00:00–04:59 夜深啦,别忘了照顾好自己哦——才、才不是学别人说话。
dawn 05:00–06:59 天刚亮就来了?…我才没有在等你。
morning 07:00–11:59 上午好。今天的活,我勉强帮你分担一点。
noon 12:00–13:59 中午了,去吃饭。饿着的脑袋我可懒得替你转。
afternoon 14:00–17:59 下午了,别发呆。…要发呆也得先把手上的事做完。
evening 18:00–22:59 天黑啦。今天也算辛苦了…只有一点点。
night 23:00–23:59 快十二点了,收个尾就去睡。…我只是嫌你明天没精神。

关掉 / 卸载

# profiles/<profile>/cordis.patch.yml —— 临时关掉(可逆,需重启)
- id: dsh-greeting
  disabled: true

彻底卸载:从 profile 的 package.json 移除依赖与 dsh.profile.bundles 里的 dsh-greeting, 再删掉 node_modules/dsh-greeting 链接与 $DSH_HOME/plugins/dsh-greeting 目录。

实现要点(给未来的自己)

  • 客户端半边 client.js(主通道):package.json 里 dsh.client = {platform:"web"} + exports["./client"],宿主 @deepseek-ai/dsh-client-modules 扫描后把它作为模块图里的一行 (plugins/??dsh-greeting/client.js&rev=…),前端 window.__ModuleLoader__.load({id, factory}) 注册;id 必须等于 loader entry 名(dsh-greeting),否则报 loaded without registering。 声明与文件必须同时存在:声明了 dsh.client 却没有 exports["./client"] 会在组合期 直接抛 ClientPackageCompositionError(fiber FAILED),所以两个改动永远一起做。
  • 宿主半边 index.js:注册 GET /dsh-greeting/config.json(JSON,no-store,每次请求现读 greeting.json)与 GET /dsh-greeting/greeting.js(prelude 拼 window.__DSH_GREETING__ + 兜底脚本), 再用 webServer.tapIndex 往宿主首页注入 <script defer>。台词默认值(PHRASES)只存在于这里。
  • 页面侧锚点:[data-conversation-region="chat"][data-content-phase="hero"] 里的 [class*="_headline"](CSS Module 只换前缀哈希,_headline 后缀跨构建稳定)。找不到锚点就安静地 不显示,绝不报错、绝不猜别的元素。
  • 只往 headline 的父容器里 insertBefore 一个自己的 div(data-dsh-greeting), 用 MutationObserver + 30s 定时器兜住 React 的重建;hero 消失时自行移除。
  • 颜色用主题变量 --dsw-alias-label-secondary,深浅色主题都自动适配。
  • 两个坑(都已在隔离宿主里复现并修掉):①picked 用 const 声明又整体赋值 → 静默抛错、 一句都不显示;②data-slot 相同就早退 → 配置后到时新台词顶不上来,只剩内置兜底句。 判定改成「当前文本仍在本期台词池里才让位」。CSS 也不要写 animation-fill-mode: both: 动画被节流时元素会永远停在 opacity: 0。
—/ 5

No ratings yet

Verified DSH bundle

Commit 36616dbfdd78

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout