Back to home@qschen86

dsh-calendar-todo

DSH web plugin: per-folder calendar + todo app with iCal import and conversation tools

Stars
0
Language
JavaScript
Created
Aug 17, 2026
Updated
Aug 17, 2026
GitHub repo

Introduction

dsh-calendar-todo

日历 + 待办 插件(DSH Web)。

数据文件夹(应用数据根)

一个文件夹承载整个应用的数据:

  • 日历/待办数据:文件夹内的 dsh-calendar-todo.json
  • 对话(会话):该文件夹注册为 DSH workspace,新会话都创建在这个文件夹下, 会话内容随文件夹走(~/.dsh/sessions 下按文件夹路径归档)

对话与主界面解耦:日历应用里的对话有自己独立的会话域——会话目标始终是 绑定文件夹 workspace 下的会话(主界面当前打开哪个会话都不影响);进入日历 模式时对话列表自动过滤为该文件夹的会话,退出时恢复原过滤。

  • 首次进入:未设置时自动创建默认文件夹(~/.dsh/calendar-todo)并使用, 无需手动配置
  • 修改地址:⚙ 应用设置 →「文件夹地址」→ 修改(系统文件夹选择框 / 手动输入路径)。修改时会询问是否迁移旧文件夹的数据(日历待办 + 会话内容) 到新文件夹;选择「不迁移」则新文件夹从空白开始
  • 绑定记录:~/.dsh/dsh-calendar-todo-binding.json(可用 DSH_HOME 调整); 绑定文件夹被删除时自动恢复默认文件夹

布局(日历场景专属设计)

点击侧边栏 📅 图标进入日历待办模式(侧边栏图标名称后带「今日 X」标签, 统计今天接下来还剩的日程与带时间提醒——本地 + 外部日历的日程,以及今天到期、 文本以 "HH:mm " 开头且未到点的待办提醒,一并计算(服务端统一口径 todayRemaining,东八区),每分钟自动刷新、数据变更即时刷新):

  • 左侧:精简对话(320px)。该场景下对话只是 GUI 之外的另一种操作方式, 因此只保留最基本的对话功能——固定使用当前会话,消息列表 + 输入框 + 发送/停止 (发送/停止按钮在输入框内右下角)。助手消息按 Markdown 渲染 (标题、列表、代码块、加粗、引用、表格等,GFM)。 会话切换、模型切换、新增对话、轨迹、模式,以及对话列表/新建会话入口, 一律收进 ⚙ 应用设置,对话区只留对话本身。
  • 中间:时间轴列表(朋友圈风格)。待办与日程按时间合并排列,月份/日期 分组吸顶固定,每条带倒计时("3 天后 / 明天 / 今天 / 已过期 N 天")与过期标记; 进入日历应用时自动定位到今天(今天无日程时定位到最近的日子),之后 手动滚动/筛选不会被自动刷新打断;底部固定快速添加待办条 (内容 + 优先级 + 分类 + 日期)。
  • 顶部待办条(操作区最上方,横向滑动)。待办没有时间,但有优先级 (高/中/低)和分类标签(如 工作/学习/生活/家庭/健康/购物…,创建时由 模型或用户打上)。所有待办以卡片形式固定在时间轴列表上方横向排列:勾选 完成、内容、优先级徽标、彩色分类标签、到期日;未办在前(按优先级高→低、 到期日排序),已完成置灰排最后。点击可切换完成状态,悬停可删除。
  • 置顶待办(单独一行):每张待办卡片上有 📌 置顶按钮,时间轴条目上也有。 置顶的待办在待办条最上方单独一行横向排列(标签"置顶"),其余待办在 下一行;置顶/取消置顶即时生效(服务端排序:置顶在前)。对话里也可以说 "把 XX 置顶 / 取消置顶"。
  • 右上角:小日历。与时间轴双向联动——滚动列表时日历高亮当前日期并自动 切月;点击日历日期,列表滚动到对应日期置顶;下方卡片显示选中日条目与添加日程。
  • ⚙ 应用设置(面板头部):文件夹地址(修改/迁移)、外部日历(Google Calendar 等 iCal 源的管理与同步)、新建会话、对话列表、模型切换(可切换 provider/model)、轨迹/详情(打开右侧轨迹面板)。
  • 退出日历模式:点击侧边栏 📅 图标(或切到其他 workspace)。

对话方式

  • 面板里可以手动新增待办、标记已办/未办、删除;日历上可以查看/新增日程。
  • 对话里可以直接查询和新增待办、日程(agent 工具):
    • calendar_todo_query — 查询待办/日程(可按 source 筛选本地/外部;待办带 priority 与 category 字段)
    • calendar_todo_add — 新增待办(仅用于没有确定时间的事项)。每次创建待办 时模型都会根据内容判断并打上 priority(高/中/低)与 category(分类标签); 带确定时间的记录(inMinutes、文本 "HH:mm " 前缀、或带明确时段/日期词的 中文时间如"晚上 9 点半""明早 8 点")由应用自动转为日程并到点提醒,不会 写入待办;相对时间传 inMinutes,由应用代码换算东八区绝对时间
    • calendar_todo_add_event — 新增日程(“X 分钟后提醒我”用本工具 + inMinutes, 由代码算出日期与时间并自动跨天进位;只有日程(事件)会触发到点提醒, 待办不会。对话创建的日程属于本地日程,带本地标签徽标,默认 "kisen")
    • calendar_todo_update — 标记完成/修改(也可改优先级/分类、置顶/取消置顶)
    • calendar_todo_delete — 删除待办/日程
  • 日程 / 待办判定:对话中没有清晰说明是日程还是待办时,由模型先根据 内容判断——带明确时间/时段的是日程,纯事项是待办;模型判断不了时,会通过 ask_user_question 消息卡片让用户选择「日程 / 待办」,再按用户选择创建。 优先级/分类同样优先由模型判断,判断不了时也通过卡片询问用户。
  • 确认机制:明确的低风险请求(如"帮我记一条待办")由 agent 判断后直接执行, 不再弹确认卡片;仅当操作属于高风险(批量创建/删除大量条目、意图不明确、 破坏性改动等)时,agent 会传入 confirm: true,通过消息卡片请求确认后再执行。

外部日历(Google Calendar / 任意 iCal 源)

  • 配置入口:⚙ 应用设置 →「外部日历」。填写名称、ICS 地址(Google 日历的 「以 iCal 格式获取秘密地址」,webcal://.../basic.ics 直接可用)、筛选标签、 颜色、同步间隔(分钟,留空用默认值)、启用开关;保存后立即后台同步。 「测试获取」可先验证地址并预览日程数量。
  • 同步:按每个日历的间隔自动同步(默认 60 分钟,环境变量 DSH_CALENDAR_TODO_SYNC_INTERVAL 可改默认值);设置面板可「立即同步」单个 或全部。同步失败只记录错误(在日历行上显示),不会清除已导入的日程。
  • 导入行为:重复规则(RRULE:DAILY/WEEKLY/MONTHLY/YEARLY + INTERVAL/ COUNT/UNTIL/BYDAY)按 RFC 5545 模型只存储一次(series:母事件 + RRULE + EXDATE + RECURRENCE-ID 例外),不在磁盘上展开;查询某个窗口/某天时按需 展开(工具查询展开请求范围,GUI 时间轴展开默认窗口:过去 DSH_CALENDAR_TODO_LOOKBACK_DAYS 天(默认 90)到未来 DSH_CALENDAR_TODO_LOOKAHEAD_DAYS 天(默认 365))。跨天日程每天生成一条 (首日显示开始时间,末日显示结束时间);UTC 时间自动转东八区时间。 长期无发生的旧系列会在同步时自动清理。
  • 列表折叠:时间轴列表里同一重复系列只显示一行 —— 下一次未来发生 (系列已结束时保留最后一次),带「⟳ 每周/每天…」周期徽标;小日历圆点和 「选中日卡片」仍按天展示该天的全部发生,提醒照常按每次发生触发。
  • 来源筛选:时间轴顶部有筛选条 —— 全部 / 本地 / 外部 / 每个外部日历的 标签 chip(带颜色圆点)。选中后时间轴、右上角小日历的标记点和选中日卡片 一起联动;外部日程带来源徽标(标签 + 颜色),只读(不可删除,停用日历源 即可隐藏)。
  • 环境变量配置参数
    • DSH_CALENDAR_TODO_SYNC_INTERVAL —— 默认同步间隔(分钟,默认 60)
    • DSH_CALENDAR_TODO_LOOKBACK_DAYS / DSH_CALENDAR_TODO_LOOKAHEAD_DAYS —— 重复日程展开窗口(默认 90 / 365)
    • DSH_CALENDAR_TODO_CALENDARS —— 首次运行播种外部日历的 JSON 数组: [{"name":"...","url":"...","tag":"...","color":"#1a73e8","interval":60,"enabled":true}] (已有配置时不会重复播种)
    • DSH_CALENDAR_TODO_LOCAL_TAG —— 本地日程(含对话创建的日程)的标签文字, 默认 "kisen";DSH_CALENDAR_TODO_LOCAL_COLOR 可指定徽标颜色(#rrggbb)
    • DSH_CALENDAR_TODO_REMIND_MINUTES —— 日程开始前提前提醒的分钟数, 默认 5;设为 0 关闭提醒
  • 数据存于绑定文件夹的 dsh-calendar-todo.json(字段 calendars / externalEvents / reminded),随文件夹迁移一起走。

日程提醒(Telegram / 日历会话)

  • 触发:带时间的日程(本地与外部日历均可)开始前 DSH_CALENDAR_TODO_REMIND_MINUTES 分钟(默认 5,0 关闭)自动提醒,每 30 秒 检查一次;每个日程只提醒一次(提醒记录随数据文件持久化,重启不重复)。
  • 送达
    1. 日历应用自己的会话:提醒作为一条消息发进绑定文件夹工作区的会话 (agent 简短确认,对话里可见);
    2. Telegram 手机通知:通过 dsh-telegram-bridge 插件提供的 "telegramBridge" 服务发送到已授权 chat(/start 注册或 allowedChats 配置)。 未配置 bot token / 未授权 chat 时自动跳过,不影响会话内提醒。
  • 消息内容:日程标题、日期/时间、倒计时、来源标签(本地 kisen / 外部标签)、备注。

结构

  • lib/index.js — 宿主端:默认文件夹、绑定/迁移、数据读写、REST API、agent 工具 (每次数据写入经 SSE(/plugin/calendar-todo/events)向浏览器广播 refresh, 面板与侧边栏"今日 X"标签计数立即重新拉取,不等轮询;浏览器端用 EventSource 订阅该流)
  • lib/client.js — 浏览器端:rail 图标、日历待办面板、精简对话、设置菜单、布局联动 (模块加载时补丁 Intl.DateTimeFormat.prototype.resolvedOptions,让 DSH 的浏览器 时区采样返回 Asia/Shanghai——机器/浏览器在美国时区,但用户在东八区;否则模型 会被告知 "Browser time zone: America/Los_Angeles" 并按美国时间计算相对时间)

技术备注

  • 宿主端只依赖 node: 内置模块(out-of-tree 插件不能解析 @deepseek-ai 包; 会话迁移用 node:zlib 的 zstd 解压/重写 cwd;外部日历用全局 fetch 拉取 ICS 并自行解析/展开重复规则)
  • 数据文件夹通过 ctx.get("workspaceRegistry").create() 幂等注册为 workspace
  • 系统文件夹选择框通过 ctx.directoryPicker(directory-picker-auto -> native 后端) 懒加载调用;不可用时客户端回退到手动输入路径
  • 精简对话直接消费客户端 Session 对象(ctx.sessions.binding(id).session): prompt/cancel/notifier/events;消息文本从 user/message 与 assistant/message|chunk 事件提取,无全量 conversation UI
  • 布局联动补丁在 dsh-client-ui-layout(calendar.todo / calendar.chat 插槽、 收窄对话列、详情列支持)与 dsh-workspace-dock(sidebar.rail.apps 插槽)
  • 时区:应用固定使用东八区 (UTC+8) 作为展示/换算时区(中国无夏令时, 固定 +8h 偏移),与运行机器的系统时区(可能是美国时区)解耦——对话框、 时间轴、倒计时、今日定位、外部日历 UTC 转换、日程提醒一律按东八区计算; 对话工具返回的 summary 带有 timezone/today/now(东八区日期与当前时刻)提示; 工具描述中明确要求代理不得用系统时间(date 命令),必须先查 summary 再算时间
  • bash 时区守卫(服务端):仅提示模型"别用系统时间"并不可靠——模型仍会跑 bash date 取当前时间,而 bash 运行在机器系统时区(美国),会把"20:10 + 15 分钟"算成 05:25。宿主端在工具执行层(tools/execute)给每条 bash 命令前置 export TZ=Asia/Shanghai;,让 date 及其派生子进程一律输出东八区墙钟时间, 与客户端 Intl 补丁(浏览器时区采样上报 Asia/Shanghai)配套,覆盖模型用 date 算相对时间的路径;命令里已显式出现 TZ= 赋值的不再前置(尊重明确指定 的时区)。环境变量 DSH_CALENDAR_TODO_TZ_GUARD=0 可关闭该守卫

安装 / 卸载

# 安装(npm 包名 / GitHub Release tarball / git 链接均可)
dsh plugin --profile web add dsh-calendar-todo
# 或
dsh plugin --profile web add https://github.com/qschen86/dsh-calendar-todo/releases/download/v0.2.0/dsh-calendar-todo-0.2.0.tgz

# 验证条目后重启 dsh web(host 半生效),刷新页面(client 半生效)
dsh --profile web --dump-config

# 卸载
dsh plugin --profile web remove dsh-calendar-todo

兼容性:验证于 dsh 0.1.0-rc.6。数据保存在插件 data/ 目录与绑定文件夹,卸载不删除数据。