READMESource: main@335993a9
dsh-schedule-panel
给 DeepSeek Harness Web 界面加一个**「日程」面板**:左侧栏日历 + 主面板月/周/概览视图,并注册一个同名的 schedule 工具,面板与模型工具共用同一份数据。
数据存在 DSH 自己的持久化存储域里(ctx.storageDomain,落在 $DSH_HOME/storages/storage_panel.json),重启后仍在,不受工具文件沙箱限制。
功能
| 功能 | 说明 |
|---|---|
| 月 / 周 / 概览视图 | 每天格子里直接显示日程标题(最多 4 条,超出显示"+N 项") |
| 新建 / 编辑 / 完成 / 删除 | 标题、时间(省略=全天)、分类、备注 |
| 到点提醒 | 每条日程可单独设置提前量(0/5/10/15/30/60/120/1440 分钟);到点弹系统通知,不可用时退化为面板顶部横幅 |
| 提醒总开关 | 工具栏一个手动开关,状态记在浏览器本地;关掉后不再轮询、不再弹任何提醒 |
| 补课机制 | 窗口最小化/后台时浏览器会降频定时器;恢复后按"上次检查时刻"把关闭期间到点的提醒补发(标题会写「错过的日程提醒」) |
| 收进托盘 | 桌面应用(Chromium --app 窗口)里多一个按钮,请常驻托盘宿主把窗口隐藏到系统托盘 |
schedule 工具 |
让我在会话里读写同一份日程:action=list/add/update/remove/clear,支持 remindBefore |
安装
# 从本地目录(link 方式,改源码即时生效)
dsh plugin --profile web add D:\path\to\dsh-schedule-panel-ts
# 或从 git
dsh plugin --profile web add https://github.com/MARIOMLY/dsh-schedule-panel.git
dsh plugin 会用 pnpm 把包装进 profile,并按包内 dsh.bundle 声明把本包追加到 dsh.profile.bundles,启动时合并 cordis.patch.yml 里的 insert——所以重启后自动加载,不需要手改 profile 文件。
仓库里提交了
lib/(构建产物),因此从 git 安装无需本地构建。
结构
lib/index.js 宿主半:普通 ESM。注册 Cordis 服务 schedulePanel(Typert Remote)
与模型工具 schedule;落盘走 ctx.storageDomain
lib/client/index.js 浏览器半:ModuleLoader 工厂格式(客户端产物必须是这个格式)
src/client/ 浏览器半源码(React + TSX)
src/client/contribution.ts 手写的 Remote 契约(描述符 + codec)
tools/ 构建后包装、离线校验脚本
cordis.patch.yml 本包的 bundle patch(composition insert 一行)
开发
pnpm install
pnpm exec tsc --noEmit
pnpm run build # tsdown(cjs) + tools/wrap-client.mjs 包成 ModuleLoader 工厂
node verify.mjs # 离线校验:产物格式/契约/接线/提醒逻辑,失败即 exit 1
verify.mjs 覆盖的都是实际踩过的坑,例如:
- 客户端产物必须是
window.__ModuleLoader__.load工厂格式(裸 ESM 会让整批客户端模块中止) - Remote 描述符每个 codec 必须有非空
typeSymbol(少了会报一句毫不相关的reading 'length') - 端点名不能撞 Cordis
Service原型成员(remove撞过,故改名drop) store必须是模块级/globalThis 单例;首次拉取不能依赖多个 effect 的相对顺序- 到点提醒的时间窗口、边界、每条各自的提前量、补课语义(20 项单测)
实现要点
- 宿主半是纯 JS:Node 24 不支持标准装饰器语法,且官方 codegen 依赖未发布的
@deepseek-ai/dsh-type-meta,所以走网关的 SRC 回退——它用Function.prototype.toString读方法形参名当 wire 字段,因此宿主形参名必须与src/client/contribution.ts里的wire逐字一致(verify.mjs会断言)。 - 客户端拿到的是
{ ok, value }信封:浏览器侧 Remote 方法返回信封,而直接打宿主 HTTP RPC 返回裸对象。所有调用统一走callSnapshot()拆信封。 - 通知权限必须由用户手势触发:所以页头放显式入口,并对
requestPermission()加超时(Chromium--app窗口可能既不弹询问也不返回)。 - 网页无法隐藏原生窗口:桌面应用的"收进托盘"是客户端写指令文件 → 常驻托盘宿主轮询后执行。
License
MIT
No comments yet. Be the first to write one.