dsh-calendar 0.8.3 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,92 +1,92 @@
1
- # Changelog
2
-
3
- ## 0.8.3(2026-09-21)
4
-
5
- - 已知事件的修改、删除及创建后回读改为直接 CalDAV multiget,省掉整集合索引查询;每次仍读取最新 ETag,保留条件写入。
6
- - 限定事件地址属于当前日历;无 calendar-data 的响应不会触发写入或删除。
7
- - 新增真实 tsdav 请求回归,覆盖请求次数、ETag、取消与缺失事件;全量 161 项测试通过。更新中英文介绍,补齐已有的可视化面板与连接设置说明。
8
-
9
- ## 0.8.2(2026-09-20)
10
-
11
- - **修主题色误用**:此前把宿主遮罩 token `--dsw-alias-bg-mask-3` 当淡色 hover/底纹用;DSH 0.1.6-alpha.2 里它实测亮/暗主题都是 `rgba(0,0,0,.48)`,导致周视图「今天」整列、月视图格子 hover、加载骨架屏、详情 tag 全部发深灰(浏览器视觉验收抓到,视觉上像一块无字灰板)。现改为 `color-mix`(label-primary 5%~7% / business-primary 7%),mask-3 只保留在 `.dshc-overlay` / `.dshc-modalwrap` 两处真正的遮罩上。
12
- - **修 Esc 关错层**:详情抽屉/新建表单打开时按 Esc 会连整个日历浮层面板一起关掉。现在 Esc 只关最上面一层,第二次才关面板;焦点在上层宿主 `PRIM.Modal` 里时让行给宿主;输入法组合状态(`isComposing`)不误关;设置页与对话页两个面板并存时一次也只关一层,并按实际打开顺序关。
13
- - **测试**:render 测试 7 → 15 条(新增抽屉/宿主 Modal 真假路径/宿主高层浮层让行/普通宿主元素兜底/层序/IME 等用例),全量 154 pass。该版经两位独立评审:首轮抓到「宿主 Portal 抢 Esc」「双面板一次连关两层」「IME 误关」,二轮抓到「宿主高层 Modal 盖上来时关错下面那层」,均已修。
14
-
15
- ## 0.8.1(2026-09-19)
16
-
17
- - **新增真 DOM 行为测试层**(`test/render.test.mjs`,devDependencies 里加 `react` / `react-dom` / `jsdom`,不进发布包):用 jsdom + 真 React 渲染周视图,然后真派发 `pointerdown/move/up`、`click`、`keydown`。7 条覆盖:渲染不抛、点事件不会顺手弹「新建」、拖动只提交一次且按视口坐标换算、拖动中 Esc 零请求、卸载后不留监听器且之后的 pointerup 不提交、拖到边缘 rAF 持续滚动、重复日程被面板挡住。
18
- - **它的第一批产出就是三个真问题**:
19
- ① **同一批次内拖动不提交**:提交前的「有没有落点」判断读的是 React state(`ghost`),而 `pointermove` 与 `pointerup` 落在同一批次时 state 还没刷新 → 明明拖了却不落盘。改为在 `dragRef` 上记同步标记。
20
- ② `requestAnimationFrame` / `cancelAnimationFrame` 按全局调用:浏览器里有,但模块作用域下应当显式走 `window.*`。
21
- ③ 三处 React key 警告(日期头、事件块、幽灵块、日列的子节点用了数组却没给 key)——dev 模式控制台一直在吵。
22
-
23
- ## 0.8.0(2026-09-19)
24
-
25
- - **新增:周视图拖拽改期**。拖动事件块上下改时间、左右换天(15 分钟吸附);拖块底部 6px 改时长;拖动中显示幽灵落点,与已有日程重叠时描成黄色(允许重叠,只是提醒);拖到容器上下边缘自动滚动,长会议不用先滚再拖。
26
- - **新增:键盘改期**。Tab 聚焦后 ↑/↓ 挪 15 分钟、Shift+↑/↓ 挪 1 小时、←/→ 挪一天、Enter 打开详情、拖动中 Esc 取消 —— 没有鼠标也能完成一次改期。
27
- - **新增:乐观更新 + 失败回滚 + 5 秒撤销**。本地先动画面再落盘,失败自动回滚并把服务器原话弹出来;成功后提示「已改期 · 撤销」。
28
- - **重复日程与超过 24 小时的日程暂不支持拖动改期**(提示去详情里编辑):CalDAV 里整个系列是一个对象,而 update 只能改 master 的 DTSTART —— 独立评审实测「把某次实例的目标时间发过去」等于**重锚系列起点**(早于它的实例全丢、COUNT/UNTIL 语义被改、撤销也回不到原系列)。宁可不做,也不做半个数据事故。
29
- - 几何算法全部抽成纯函数(`snapMinutes` / `slotFromEvent` / `moveSlot` / `slotFromDrag` / `resizeSlot` / `rangeOfSlot` / `conflictsForSlot` / `isRecurring`),新增 12 条单测**直接测发布文件里的实现**(跨天、跨月、越午夜、吸附、钳制、冲突判定、拖拽接线契约)。
30
- - 交互细节(两轮独立评审后补的洞):5px 阈值区分点击与拖动;**点事件不再冒泡去触发「新建日程」**(slot 是日列的子节点,此前点一下会同时弹详情与新建表单,拖完松手也会弹);只认发起拖动的 `pointerId`;window 监听器**只在挂载时注册一次**并通过 ref 调最新实现(此前按渲染闭包挂/摘,卸载后残留的 `pointerup` 会替用户提交一次改期);`buttons === 0` / 窗口失焦 / `Esc`(捕获阶段,不顺手关掉浮层面板)都回到原位;边缘自动滚动改用 **rAF 持续滚**并在滚动后重算落点。
31
- - 落盘:改期请求**按 uid 串行 + 合并**(连按方向键只落最后一次)、跳过无效位移、带 15 秒超时;失败回滚后还会 reload 对账(超时可能已经写进去了)。
32
- - 位移改成**日历日 + 墙钟分钟**运算:此前按毫秒加,DST 切换日会偏一小时(评审用 `TZ=America/New_York` 复现,中国时区看不见);日末钳制也吸附到 15 分钟网格。
33
- - **修一个渲染即崩的 P0**:焦点恢复的 `useEffect` 依赖数组引用了声明在后面的 `data`,TDZ 直接抛错、整个面板打不开(纯函数测试测不到,评审渲染才发现)。
34
- - 明确取舍:拖动越过午夜**滚到次日**(与 Google 日历一致,也让幽灵块按 `slot.dayKey` 的日列渲染自洽),而不是硬钳在当天最后一刻。
35
-
36
- ## 0.7.0(2026-09-19)
37
-
38
- - **新增**:面板**记住上次用的视图**(月/周/议程,存 localStorage;隐私模式写不进去就退回「月」),下次打开不再固定跳回月视图。
39
- - **新增**:周视图**默认落在 07:00**(半夜那几格基本没人看,但需要时还能往上滚,不裁剪任何事件)。
40
- - **适配窄容器**:面板在设置页里比对话页浮层窄得多,现在用容器查询自适应 —— 窄的时候隐藏芯片里的时间前缀(让日程标题露出来)、隐藏重复的面板标题、收紧工具栏间距。
41
- - **修复**:月视图的格子由 `<button>` 改为 `<div role="button" tabIndex=0>`。按钮不能嵌套按钮(芯片本身是按钮),一旦同格有多条日程,浏览器会把外层按钮提前闭合、把芯片挤成网格的兄弟节点;现在结构合法,键盘 Enter/空格仍可新建,并加了回归测试(月视图里不允许出现 `button`)。
42
-
43
- ## 0.6.0(2026-09-19)
44
-
45
- - **新增设置页日历面板**:月 / 周 / 议程三种视图;点日程开右侧详情(时间、时长、重复规则的人话、地点、备注、uid),可直接改标题时间、加重复、删除(二次确认);新建支持全天 / 地点 / 备注 / RRULE;保存前做冲突检测。
46
- - **新增对话页悬浮入口**:右下角 📅 小按钮点开同一个面板(非模态、Esc 关闭)。自绘 root 使用平台 seed 模块表里的 `react-dom/client`,控件优先用官方 `ui-primitives`(Button / Input / Checkbox / Modal / writeClipboard),老宿主缺这些时自动退回自绘控件,面板不会整块消失。
47
- - **新增网页端后端** `/_dsh/dsh-calendar/settings`(status / list / create / update / delete):与 dsh-email 设置路由同一套安全模型 —— 仅回环地址可达、Host 必须是 localhost 名(挡 DNS rebinding)、写操作要求 `application/json` 且校验 Origin / Sec-Fetch-Site、响应永不回显凭据。
48
- - 参数校验复用工具层同一套断言(`assertIsoTime` / `assertTimeRange`),校验失败不打扰 CalDAV 服务器;为此把 `asRecord` / `optionalString` / `assertIsoTime` / `assertTimeRange` / `isoNoMillis` / `sortEvents` 变成共享导出,避免两处语义漂移。
49
- - 未配置 CalDAV 时面板显示引导态与「查看示例」,不再只丢一条报错。
50
- - **新增面板内连接配置**:面板工具栏的「连接设置」支持 Google / iCloud / Nextcloud / 自建四种服务商。填完先「测试连接」(真去列未来 30 天日程),通过才允许保存;保存时服务端还会再测一次 —— 因此「保存成功」等价于「这套凭据刚才真的连上了」,一个连不上的地址不会被写进配置。密码 / clientSecret / refreshToken 不回填到前端(placeholder 显示「已保存,留空不改」),留空即沿用已存值。
51
- - 面板配置写入宿主 settings 命名空间 `dsh-calendar`(`src/settings.ts`):**面板没填过的字段仍由 profile 的 `cordis.patch.yml` 兜底**,两份配置共存、老部署零迁移;宿主没有 settings 服务时面板自动退化为只读并说明原因。工具层改为「每次调用现取配置」(`CalendarConfigSource`),所以面板保存后无需重启。
52
- - 后端新增 `connection` / `testConnection` / `saveConnection` 三个动作;新增依赖 `schemastery`。
53
- - **修复**:宿主 settings 服务改为**懒接入**(每个请求前 `ctx.get('settings')`)。此前依赖 `ctx.inject(['settings'])` 子 fiber 的时序 —— 插件被重复 apply、或命名空间已被注册时它会静默失效,面板就永远停在「settings 服务不可用」。现在命名空间已被注册也不当作失败:值从 `describe()` 描述符读、写走 provider 的 `replace`,功能完全一致。
54
- - **修复**:Nextcloud 表单缺 `username`(认证账号)字段,照原表单填完会报「未配置 username」(`user` 是用来拼 URL 的,认证用的是 `username`)。
55
- - 连接设置表单补齐「怎么拿到这些值」:字段级小字提示 + 可展开的分步说明 + 外链(Google Cloud 凭据页 / OAuth Playground / Apple ID 设置),Nextcloud 的 `user` 与 `username` 也分别写了说明。测试 88 → 102 项。
56
- - **新增 `scripts/google-oauth.mjs`**:一条命令换 Google refresh token —— 起一次性本地回环回调、自动打开浏览器、收到 code 后换 token 并打印;README(中英)的 Google 段改为用它,`files` 增加 `scripts` 让 npm 包内也带这份脚本。测试 102 → 106 项(含本地假令牌端点的全流程测试)。
57
- - 该脚本随后加固:**clientId 自检**(拦下控制台列表里被截断显示的那串,避免拿到一张 Google 400 页)、**授权地址预检**(打开浏览器前先问一次 Google,400 就在终端把原因说清楚)、**PKCE(S256)**、以及回调端口的收尾(预检失败/超时/拒绝都不再留下监听)。测试 106 → 111 项。
58
- - **新增兜底存储**:宿主没有 settings 服务、或命名空间注册失败且无人注册时,连接配置改存插件自己的文件 `$DSH_HOME/data/dsh-calendar/connection.json`(0600,与 dsh-email 的 token 文件同源),面板里会写明「存在哪个文件」而不是笼统一句「不可用」;`/connection` 也会带上 `settingsKind`(settings|file)与 `settingsReason`,便于排查。
59
- - 文案:兜底存储的说明降级为弹窗底部一行小字(不再是一块看起来像报错的灰条),并改正「密码存在 settings.yaml」的说法 —— 兜底生效时它其实存在 `connection.json`。
60
- - **修复**:settings 命名空间改为**插件加载时同步注册**。此前是在请求处理里懒注册,而宿主的 `register` 内部会 `ctx.effect(...)`(需要插件的活动作用域),在请求上下文里会失败;失败又被吞掉,于是表现成「面板看着能用,一保存就报 `settings namespace "dsh-calendar" is not registered`」。现在注册发生在 apply 阶段,真实失败会以 `dsh-calendar: …` 警告打到终端;插件被重复 apply 时第二个实例不再注册、直接搭既有注册的车。
61
- - **修复**:Windows 上打开浏览器改用 `rundll32 url.dll,FileProtocolHandler`。此前用 `cmd /c start <url>`,授权 URL 里的 `&` 被 cmd 当成命令分隔符,浏览器只收到第一段 —— Google 的表现是 `Required parameter is missing: response_type`(预检查不出来,因为脚本自己发的请求是完整的)。换 token 脚本改为**交互式**:直接敲 `node scripts/google-oauth.mjs`,它会依次问 clientId 与 clientSecret,并识别「把文档示例文字当值粘进来」这种情况。
62
- - CI 增加 `node --check lib/client.js`(网页端源码不走 tsc,只能语法自检)。测试 79 → 88 项。
63
-
64
- > 完整历史(含详细改动说明)。README 只保留最近几个版本的一句话摘要。
65
-
66
- ## 中文版
67
-
68
- - **0.5.4(2026-09-18)**:**修复**:①`calendar_update` 重建 VEVENT 会静默丢掉原事件的 ATTENDEE / ORGANIZER / EXDATE / STATUS / CATEGORIES / VALARM(改一次标题就删掉邀请人和提醒),现在改为在原始 VCALENDAR 上做字段级覆盖,并补齐 RFC 5545 必需的 VERSION / PRODID / UID / DTSTAMP;②RECURRENCE-ID 覆盖实例被忽略(被单独改期的实例按原时间+旧标题返回,或被 EXDATE 排掉后整条消失),现在建覆盖映射并在展开时替换对应实例;③`calendar_create` 返回本地拼的 uid 而忽略服务器 `Location`,导致 create 后 update 找不到事件(现在优先取 Location,缺失时回读确认),且 create 的 PUT body 补上 VERSION / PRODID / DTSTAMP。**优化**:重复事件展开预算耗尽时不再静默返回 0 条(DTSTART 在 2010 的每小时系列实测 680ms 且返回空),改为显式报错并提示缩小时间范围或补 COUNT/UNTIL;`calendar_search` 支持 `start` / `end` 并走 timeRange 查询(缺省用有界窗口),不再先整本下载再过滤。测试 68 → 79 项。
69
- - **0.5.3(2026-09-11)**:复验官方 Harness 0.1.5-rc.1,更新整套同载与真实服务验证记录;运行时代码未变。
70
- - **0.5.2(2026-09-08)**:补充官方 Harness 0.1.3-alpha.2 的安装、加载与真实 Google 工具调用验证,更新兼容性和 Node 版本要求;运行时代码与 0.5.0 相同。
71
- - **0.5.1(2026-09-08)**:补充真实 Google OAuth/CalDAV 读取验证、`calendar.readonly` 与 `calendar` 范围对比及 Testing 刷新令牌到期说明;运行时代码与 0.5.0 相同。
72
- - **0.5.0(2026-09-07)**:修复 Google CalDAV #2:新增 OAuth 凭据与环境变量配置、请求时刷新、取消与代理透传;健康检查区分 Basic/OAuth,修正误导的应用专用密码说明。保留其他服务的 Basic 认证。
73
- - **0.4.0**:新增 `calendar_health` 自检(离线检查 CalDAV 端点与凭据配置,不验证连接)。
74
- - **0.3.2**:
75
- - 修复 `calendar_update` 更新其他字段时丢失 `rrule` 的问题。
76
- - 更新与新建都会校验 `end >= start`,并拒绝 `2025-02-30` 这类不存在的日期。
77
- - `calendar_list` / `calendar_search` 输出按开始时间稳定排序;搜索 `limit` clamp 到 1-200。
78
- - CalDAV 客户端创建失败后清空缓存,下一次调用可自动重试,不再永久复用 rejected promise。
79
-
80
- ## English
81
-
82
- - **0.5.4 (2026-09-18)**: **Fixes**: (1) `calendar_update` rebuilt the VEVENT and silently dropped ATTENDEE / ORGANIZER / EXDATE / STATUS / CATEGORIES / VALARM — renaming an event deleted its guests and reminders; the update now does field-level replacement on the original VCALENDAR and fills in the RFC 5545 essentials (VERSION / PRODID / UID / DTSTAMP). (2) RECURRENCE-ID overrides were ignored: a moved instance came back with its old time and title, or disappeared entirely when an EXDATE removed the original slot; overrides are now mapped and substituted during expansion. (3) `calendar_create` returned a locally invented uid instead of the server `Location`, so a follow-up update could not find the event (Location is now preferred, with a read-back check when absent), and the create body now carries VERSION / PRODID / DTSTAMP. **Improvements**: an exhausted expansion budget no longer returns an empty result silently (an hourly series starting in 2010 took 680ms and returned nothing) but raises a clear error suggesting a narrower range or COUNT/UNTIL; `calendar_search` accepts `start`/`end` and queries by timeRange instead of downloading the whole calendar first. Tests 68 → 79.
83
- - **0.5.3 (2026-09-11)**: revalidate official Harness 0.1.5-rc.1 and refresh suite co-load and live-service evidence; runtime code is unchanged.
84
- - **0.5.2 (2026-09-08)**: document installation, loading and real Google tool execution in official Harness 0.1.3-alpha.2; update compatibility and Node requirements. Runtime code is unchanged from 0.5.0.
85
- - **0.5.1 (2026-09-08)**: document live Google OAuth/CalDAV read validation, the `calendar.readonly` versus `calendar` scope results and Testing refresh-token expiration. Runtime code is unchanged from 0.5.0.
86
- - **0.5.0 (2026-09-07)**: fix Google CalDAV #2 with OAuth configuration/environment credentials, request-time refresh, cancellation and proxy forwarding. Make health checks and error guidance authentication-aware; retain Basic authentication for other servers.
87
- - **0.4.0**: new `calendar_health` self-check (offline endpoint and credential configuration checks, not a connection test).
88
- - **0.3.2**:
89
- - Fix `calendar_update` dropping `rrule` while updating other fields.
90
- - Validate `end >= start` and reject impossible dates such as `2025-02-30`.
91
- - Sort `calendar_list` / `calendar_search` output by start time and clamp search `limit` to 1-200.
92
- - Reset the cached CalDAV client after creation failure so the next tool call can retry.
1
+ # Changelog
2
+
3
+ ## 0.8.3(2026-09-21)
4
+
5
+ - 已知事件的修改、删除及创建后回读改为直接 CalDAV multiget,省掉整集合索引查询;每次仍读取最新 ETag,保留条件写入。
6
+ - 限定事件地址属于当前日历;无 calendar-data 的响应不会触发写入或删除。
7
+ - 新增真实 tsdav 请求回归,覆盖请求次数、ETag、取消与缺失事件;全量 161 项测试通过。更新中英文介绍,补齐已有的可视化面板与连接设置说明。
8
+
9
+ ## 0.8.2(2026-09-20)
10
+
11
+ - **修主题色误用**:此前把宿主遮罩 token `--dsw-alias-bg-mask-3` 当淡色 hover/底纹用;DSH 0.1.6-alpha.2 里它实测亮/暗主题都是 `rgba(0,0,0,.48)`,导致周视图「今天」整列、月视图格子 hover、加载骨架屏、详情 tag 全部发深灰(浏览器视觉验收抓到,视觉上像一块无字灰板)。现改为 `color-mix`(label-primary 5%~7% / business-primary 7%),mask-3 只保留在 `.dshc-overlay` / `.dshc-modalwrap` 两处真正的遮罩上。
12
+ - **修 Esc 关错层**:详情抽屉/新建表单打开时按 Esc 会连整个日历浮层面板一起关掉。现在 Esc 只关最上面一层,第二次才关面板;焦点在上层宿主 `PRIM.Modal` 里时让行给宿主;输入法组合状态(`isComposing`)不误关;设置页与对话页两个面板并存时一次也只关一层,并按实际打开顺序关。
13
+ - **测试**:render 测试 7 → 15 条(新增抽屉/宿主 Modal 真假路径/宿主高层浮层让行/普通宿主元素兜底/层序/IME 等用例),全量 154 pass。该版经两位独立评审:首轮抓到「宿主 Portal 抢 Esc」「双面板一次连关两层」「IME 误关」,二轮抓到「宿主高层 Modal 盖上来时关错下面那层」,均已修。
14
+
15
+ ## 0.8.1(2026-09-19)
16
+
17
+ - **新增真 DOM 行为测试层**(`test/render.test.mjs`,devDependencies 里加 `react` / `react-dom` / `jsdom`,不进发布包):用 jsdom + 真 React 渲染周视图,然后真派发 `pointerdown/move/up`、`click`、`keydown`。7 条覆盖:渲染不抛、点事件不会顺手弹「新建」、拖动只提交一次且按视口坐标换算、拖动中 Esc 零请求、卸载后不留监听器且之后的 pointerup 不提交、拖到边缘 rAF 持续滚动、重复日程被面板挡住。
18
+ - **它的第一批产出就是三个真问题**:
19
+ ① **同一批次内拖动不提交**:提交前的「有没有落点」判断读的是 React state(`ghost`),而 `pointermove` 与 `pointerup` 落在同一批次时 state 还没刷新 → 明明拖了却不落盘。改为在 `dragRef` 上记同步标记。
20
+ ② `requestAnimationFrame` / `cancelAnimationFrame` 按全局调用:浏览器里有,但模块作用域下应当显式走 `window.*`。
21
+ ③ 三处 React key 警告(日期头、事件块、幽灵块、日列的子节点用了数组却没给 key)——dev 模式控制台一直在吵。
22
+
23
+ ## 0.8.0(2026-09-19)
24
+
25
+ - **新增:周视图拖拽改期**。拖动事件块上下改时间、左右换天(15 分钟吸附);拖块底部 6px 改时长;拖动中显示幽灵落点,与已有日程重叠时描成黄色(允许重叠,只是提醒);拖到容器上下边缘自动滚动,长会议不用先滚再拖。
26
+ - **新增:键盘改期**。Tab 聚焦后 ↑/↓ 挪 15 分钟、Shift+↑/↓ 挪 1 小时、←/→ 挪一天、Enter 打开详情、拖动中 Esc 取消 —— 没有鼠标也能完成一次改期。
27
+ - **新增:乐观更新 + 失败回滚 + 5 秒撤销**。本地先动画面再落盘,失败自动回滚并把服务器原话弹出来;成功后提示「已改期 · 撤销」。
28
+ - **重复日程与超过 24 小时的日程暂不支持拖动改期**(提示去详情里编辑):CalDAV 里整个系列是一个对象,而 update 只能改 master 的 DTSTART —— 独立评审实测「把某次实例的目标时间发过去」等于**重锚系列起点**(早于它的实例全丢、COUNT/UNTIL 语义被改、撤销也回不到原系列)。宁可不做,也不做半个数据事故。
29
+ - 几何算法全部抽成纯函数(`snapMinutes` / `slotFromEvent` / `moveSlot` / `slotFromDrag` / `resizeSlot` / `rangeOfSlot` / `conflictsForSlot` / `isRecurring`),新增 12 条单测**直接测发布文件里的实现**(跨天、跨月、越午夜、吸附、钳制、冲突判定、拖拽接线契约)。
30
+ - 交互细节(两轮独立评审后补的洞):5px 阈值区分点击与拖动;**点事件不再冒泡去触发「新建日程」**(slot 是日列的子节点,此前点一下会同时弹详情与新建表单,拖完松手也会弹);只认发起拖动的 `pointerId`;window 监听器**只在挂载时注册一次**并通过 ref 调最新实现(此前按渲染闭包挂/摘,卸载后残留的 `pointerup` 会替用户提交一次改期);`buttons === 0` / 窗口失焦 / `Esc`(捕获阶段,不顺手关掉浮层面板)都回到原位;边缘自动滚动改用 **rAF 持续滚**并在滚动后重算落点。
31
+ - 落盘:改期请求**按 uid 串行 + 合并**(连按方向键只落最后一次)、跳过无效位移、带 15 秒超时;失败回滚后还会 reload 对账(超时可能已经写进去了)。
32
+ - 位移改成**日历日 + 墙钟分钟**运算:此前按毫秒加,DST 切换日会偏一小时(评审用 `TZ=America/New_York` 复现,中国时区看不见);日末钳制也吸附到 15 分钟网格。
33
+ - **修一个渲染即崩的 P0**:焦点恢复的 `useEffect` 依赖数组引用了声明在后面的 `data`,TDZ 直接抛错、整个面板打不开(纯函数测试测不到,评审渲染才发现)。
34
+ - 明确取舍:拖动越过午夜**滚到次日**(与 Google 日历一致,也让幽灵块按 `slot.dayKey` 的日列渲染自洽),而不是硬钳在当天最后一刻。
35
+
36
+ ## 0.7.0(2026-09-19)
37
+
38
+ - **新增**:面板**记住上次用的视图**(月/周/议程,存 localStorage;隐私模式写不进去就退回「月」),下次打开不再固定跳回月视图。
39
+ - **新增**:周视图**默认落在 07:00**(半夜那几格基本没人看,但需要时还能往上滚,不裁剪任何事件)。
40
+ - **适配窄容器**:面板在设置页里比对话页浮层窄得多,现在用容器查询自适应 —— 窄的时候隐藏芯片里的时间前缀(让日程标题露出来)、隐藏重复的面板标题、收紧工具栏间距。
41
+ - **修复**:月视图的格子由 `<button>` 改为 `<div role="button" tabIndex=0>`。按钮不能嵌套按钮(芯片本身是按钮),一旦同格有多条日程,浏览器会把外层按钮提前闭合、把芯片挤成网格的兄弟节点;现在结构合法,键盘 Enter/空格仍可新建,并加了回归测试(月视图里不允许出现 `button`)。
42
+
43
+ ## 0.6.0(2026-09-19)
44
+
45
+ - **新增设置页日历面板**:月 / 周 / 议程三种视图;点日程开右侧详情(时间、时长、重复规则的人话、地点、备注、uid),可直接改标题时间、加重复、删除(二次确认);新建支持全天 / 地点 / 备注 / RRULE;保存前做冲突检测。
46
+ - **新增对话页悬浮入口**:右下角 📅 小按钮点开同一个面板(非模态、Esc 关闭)。自绘 root 使用平台 seed 模块表里的 `react-dom/client`,控件优先用官方 `ui-primitives`(Button / Input / Checkbox / Modal / writeClipboard),老宿主缺这些时自动退回自绘控件,面板不会整块消失。
47
+ - **新增网页端后端** `/_dsh/dsh-calendar/settings`(status / list / create / update / delete):与 dsh-email 设置路由同一套安全模型 —— 仅回环地址可达、Host 必须是 localhost 名(挡 DNS rebinding)、写操作要求 `application/json` 且校验 Origin / Sec-Fetch-Site、响应永不回显凭据。
48
+ - 参数校验复用工具层同一套断言(`assertIsoTime` / `assertTimeRange`),校验失败不打扰 CalDAV 服务器;为此把 `asRecord` / `optionalString` / `assertIsoTime` / `assertTimeRange` / `isoNoMillis` / `sortEvents` 变成共享导出,避免两处语义漂移。
49
+ - 未配置 CalDAV 时面板显示引导态与「查看示例」,不再只丢一条报错。
50
+ - **新增面板内连接配置**:面板工具栏的「连接设置」支持 Google / iCloud / Nextcloud / 自建四种服务商。填完先「测试连接」(真去列未来 30 天日程),通过才允许保存;保存时服务端还会再测一次 —— 因此「保存成功」等价于「这套凭据刚才真的连上了」,一个连不上的地址不会被写进配置。密码 / clientSecret / refreshToken 不回填到前端(placeholder 显示「已保存,留空不改」),留空即沿用已存值。
51
+ - 面板配置写入宿主 settings 命名空间 `dsh-calendar`(`src/settings.ts`):**面板没填过的字段仍由 profile 的 `cordis.patch.yml` 兜底**,两份配置共存、老部署零迁移;宿主没有 settings 服务时面板自动退化为只读并说明原因。工具层改为「每次调用现取配置」(`CalendarConfigSource`),所以面板保存后无需重启。
52
+ - 后端新增 `connection` / `testConnection` / `saveConnection` 三个动作;新增依赖 `schemastery`。
53
+ - **修复**:宿主 settings 服务改为**懒接入**(每个请求前 `ctx.get('settings')`)。此前依赖 `ctx.inject(['settings'])` 子 fiber 的时序 —— 插件被重复 apply、或命名空间已被注册时它会静默失效,面板就永远停在「settings 服务不可用」。现在命名空间已被注册也不当作失败:值从 `describe()` 描述符读、写走 provider 的 `replace`,功能完全一致。
54
+ - **修复**:Nextcloud 表单缺 `username`(认证账号)字段,照原表单填完会报「未配置 username」(`user` 是用来拼 URL 的,认证用的是 `username`)。
55
+ - 连接设置表单补齐「怎么拿到这些值」:字段级小字提示 + 可展开的分步说明 + 外链(Google Cloud 凭据页 / OAuth Playground / Apple ID 设置),Nextcloud 的 `user` 与 `username` 也分别写了说明。测试 88 → 102 项。
56
+ - **新增 `scripts/google-oauth.mjs`**:一条命令换 Google refresh token —— 起一次性本地回环回调、自动打开浏览器、收到 code 后换 token 并打印;README(中英)的 Google 段改为用它,`files` 增加 `scripts` 让 npm 包内也带这份脚本。测试 102 → 106 项(含本地假令牌端点的全流程测试)。
57
+ - 该脚本随后加固:**clientId 自检**(拦下控制台列表里被截断显示的那串,避免拿到一张 Google 400 页)、**授权地址预检**(打开浏览器前先问一次 Google,400 就在终端把原因说清楚)、**PKCE(S256)**、以及回调端口的收尾(预检失败/超时/拒绝都不再留下监听)。测试 106 → 111 项。
58
+ - **新增兜底存储**:宿主没有 settings 服务、或命名空间注册失败且无人注册时,连接配置改存插件自己的文件 `$DSH_HOME/data/dsh-calendar/connection.json`(0600,与 dsh-email 的 token 文件同源),面板里会写明「存在哪个文件」而不是笼统一句「不可用」;`/connection` 也会带上 `settingsKind`(settings|file)与 `settingsReason`,便于排查。
59
+ - 文案:兜底存储的说明降级为弹窗底部一行小字(不再是一块看起来像报错的灰条),并改正「密码存在 settings.yaml」的说法 —— 兜底生效时它其实存在 `connection.json`。
60
+ - **修复**:settings 命名空间改为**插件加载时同步注册**。此前是在请求处理里懒注册,而宿主的 `register` 内部会 `ctx.effect(...)`(需要插件的活动作用域),在请求上下文里会失败;失败又被吞掉,于是表现成「面板看着能用,一保存就报 `settings namespace "dsh-calendar" is not registered`」。现在注册发生在 apply 阶段,真实失败会以 `dsh-calendar: …` 警告打到终端;插件被重复 apply 时第二个实例不再注册、直接搭既有注册的车。
61
+ - **修复**:Windows 上打开浏览器改用 `rundll32 url.dll,FileProtocolHandler`。此前用 `cmd /c start <url>`,授权 URL 里的 `&` 被 cmd 当成命令分隔符,浏览器只收到第一段 —— Google 的表现是 `Required parameter is missing: response_type`(预检查不出来,因为脚本自己发的请求是完整的)。换 token 脚本改为**交互式**:直接敲 `node scripts/google-oauth.mjs`,它会依次问 clientId 与 clientSecret,并识别「把文档示例文字当值粘进来」这种情况。
62
+ - CI 增加 `node --check lib/client.js`(网页端源码不走 tsc,只能语法自检)。测试 79 → 88 项。
63
+
64
+ > 完整历史(含详细改动说明)。README 只保留最近几个版本的一句话摘要。
65
+
66
+ ## 中文版
67
+
68
+ - **0.5.4(2026-09-18)**:**修复**:①`calendar_update` 重建 VEVENT 会静默丢掉原事件的 ATTENDEE / ORGANIZER / EXDATE / STATUS / CATEGORIES / VALARM(改一次标题就删掉邀请人和提醒),现在改为在原始 VCALENDAR 上做字段级覆盖,并补齐 RFC 5545 必需的 VERSION / PRODID / UID / DTSTAMP;②RECURRENCE-ID 覆盖实例被忽略(被单独改期的实例按原时间+旧标题返回,或被 EXDATE 排掉后整条消失),现在建覆盖映射并在展开时替换对应实例;③`calendar_create` 返回本地拼的 uid 而忽略服务器 `Location`,导致 create 后 update 找不到事件(现在优先取 Location,缺失时回读确认),且 create 的 PUT body 补上 VERSION / PRODID / DTSTAMP。**优化**:重复事件展开预算耗尽时不再静默返回 0 条(DTSTART 在 2010 的每小时系列实测 680ms 且返回空),改为显式报错并提示缩小时间范围或补 COUNT/UNTIL;`calendar_search` 支持 `start` / `end` 并走 timeRange 查询(缺省用有界窗口),不再先整本下载再过滤。测试 68 → 79 项。
69
+ - **0.5.3(2026-09-11)**:复验官方 Harness 0.1.5-rc.1,更新整套同载与真实服务验证记录;运行时代码未变。
70
+ - **0.5.2(2026-09-08)**:补充官方 Harness 0.1.3-alpha.2 的安装、加载与真实 Google 工具调用验证,更新兼容性和 Node 版本要求;运行时代码与 0.5.0 相同。
71
+ - **0.5.1(2026-09-08)**:补充真实 Google OAuth/CalDAV 读取验证、`calendar.readonly` 与 `calendar` 范围对比及 Testing 刷新令牌到期说明;运行时代码与 0.5.0 相同。
72
+ - **0.5.0(2026-09-07)**:修复 Google CalDAV #2:新增 OAuth 凭据与环境变量配置、请求时刷新、取消与代理透传;健康检查区分 Basic/OAuth,修正误导的应用专用密码说明。保留其他服务的 Basic 认证。
73
+ - **0.4.0**:新增 `calendar_health` 自检(离线检查 CalDAV 端点与凭据配置,不验证连接)。
74
+ - **0.3.2**:
75
+ - 修复 `calendar_update` 更新其他字段时丢失 `rrule` 的问题。
76
+ - 更新与新建都会校验 `end >= start`,并拒绝 `2025-02-30` 这类不存在的日期。
77
+ - `calendar_list` / `calendar_search` 输出按开始时间稳定排序;搜索 `limit` clamp 到 1-200。
78
+ - CalDAV 客户端创建失败后清空缓存,下一次调用可自动重试,不再永久复用 rejected promise。
79
+
80
+ ## English
81
+
82
+ - **0.5.4 (2026-09-18)**: **Fixes**: (1) `calendar_update` rebuilt the VEVENT and silently dropped ATTENDEE / ORGANIZER / EXDATE / STATUS / CATEGORIES / VALARM — renaming an event deleted its guests and reminders; the update now does field-level replacement on the original VCALENDAR and fills in the RFC 5545 essentials (VERSION / PRODID / UID / DTSTAMP). (2) RECURRENCE-ID overrides were ignored: a moved instance came back with its old time and title, or disappeared entirely when an EXDATE removed the original slot; overrides are now mapped and substituted during expansion. (3) `calendar_create` returned a locally invented uid instead of the server `Location`, so a follow-up update could not find the event (Location is now preferred, with a read-back check when absent), and the create body now carries VERSION / PRODID / DTSTAMP. **Improvements**: an exhausted expansion budget no longer returns an empty result silently (an hourly series starting in 2010 took 680ms and returned nothing) but raises a clear error suggesting a narrower range or COUNT/UNTIL; `calendar_search` accepts `start`/`end` and queries by timeRange instead of downloading the whole calendar first. Tests 68 → 79.
83
+ - **0.5.3 (2026-09-11)**: revalidate official Harness 0.1.5-rc.1 and refresh suite co-load and live-service evidence; runtime code is unchanged.
84
+ - **0.5.2 (2026-09-08)**: document installation, loading and real Google tool execution in official Harness 0.1.3-alpha.2; update compatibility and Node requirements. Runtime code is unchanged from 0.5.0.
85
+ - **0.5.1 (2026-09-08)**: document live Google OAuth/CalDAV read validation, the `calendar.readonly` versus `calendar` scope results and Testing refresh-token expiration. Runtime code is unchanged from 0.5.0.
86
+ - **0.5.0 (2026-09-07)**: fix Google CalDAV #2 with OAuth configuration/environment credentials, request-time refresh, cancellation and proxy forwarding. Make health checks and error guidance authentication-aware; retain Basic authentication for other servers.
87
+ - **0.4.0**: new `calendar_health` self-check (offline endpoint and credential configuration checks, not a connection test).
88
+ - **0.3.2**:
89
+ - Fix `calendar_update` dropping `rrule` while updating other fields.
90
+ - Validate `end >= start` and reject impossible dates such as `2025-02-30`.
91
+ - Sort `calendar_list` / `calendar_search` output by start time and clamp search `limit` to 1-200.
92
+ - Reset the cached CalDAV client after creation failure so the next tool call can retry.
package/README.en.md CHANGED
@@ -8,6 +8,8 @@ DSH community plugin: read/write calendar events via CalDAV. Provides 5 calendar
8
8
 
9
9
  ## Compatibility
10
10
 
11
+ Version **0.8.4** (2026-09-23) supports the Web mount paths introduced in Harness **0.1.7**. The calendar panel keeps its requests under the application path when deployed through a reverse proxy, preserving normal settings and event operations. The current host baseline is official-source 0.1.7-alpha.2 with a local tool-scheduler fix; external CalDAV operations require their own account validation.
12
+
11
13
  2026-09-21: the current release package was installed through the official CLI in an isolated profile and co-loaded with the other two most-downloaded plugins on source-built Harness `0.1.6-alpha.2`. All 18 plugin tools registered; calendar/email configuration checks, PPT theme listing and 17-row table generation passed. The host is based on the official alpha.2 release plus the tool-scheduler `Symbol.for` fix (`93badd88`). This run did not connect to live mail or calendar services.
12
14
 
13
15
  Verified with official `@deepseek-ai/dsh@0.1.5-rc.1` and Node `24.16.0` on 2026-09-11: all 18 components load alongside Modlens, with passing tool-schema, skill-registration and offline read-only invocation checks. Uses the `cordis.patch.yml` + `dsh.bundle.patch` bundle model. Node requirements match this Harness release: 22.19 or later within 22.x, or 24 or later. Live external-service workflows require separate configuration and validation.
package/README.md CHANGED
@@ -13,6 +13,8 @@ DSH 社区插件:通过 CalDAV 读写日历事件。提供 5 个日历操作
13
13
 
14
14
  ## 兼容性
15
15
 
16
+ **0.8.4(2026-09-23)**适配 Harness **0.1.7** 的 Web 子路径部署:日历面板的请求会跟随应用路径,修复经过反向代理访问时设置与事件操作失败的问题。当前验证宿主为官方源码构建的 0.1.7-alpha.2(含本地工具调度器修复);真实 CalDAV 业务仍需有效账号单独验证。
17
+
16
18
  2026-09-21:当前发布包经官方 CLI 安装到隔离 profile,在源码构建的 Harness `0.1.6-alpha.2` 上与另外两个下载量前三插件共同加载,18 个插件工具注册正常;日历/邮件配置自检、PPT 主题查询和 17 行表格生成通过。测试本体基于官方 alpha.2 发布提交,另含工具调度器 `Symbol.for` 修复(`93badd88`)。本轮未连接真实邮箱或日历服务。
17
19
 
18
20
  已在官方 `@deepseek-ai/dsh@0.1.5-rc.1`、Node `24.16.0` 上验证(2026-09-11):18 个组件与 Modlens 同载,工具 schema、技能注册及离线只读调用检查通过。采用 `cordis.patch.yml` + `dsh.bundle.patch` 组合包模型。Node 要求与该版本 Harness 一致:22.19 及以上的 22.x,或 24 及以上。外部服务的实际业务操作需按各组件配置单独验证。
package/lib/client.js CHANGED
@@ -13,7 +13,8 @@ const React = require("react");
13
13
  const { useState, useEffect, useMemo, useRef, useCallback } = React;
14
14
  const h = React.createElement;
15
15
 
16
- const ROUTE = "/_dsh/dsh-calendar/settings";
16
+ // Resolve against the Harness document base, including any reverse-proxy prefix.
17
+ const ROUTE = "_dsh/dsh-calendar/settings";
17
18
 
18
19
  /** 三视图;order 决定 tab 顺序。 */
19
20
  const VIEWS = ["month", "week", "agenda"];
@@ -149,7 +150,7 @@ const UI = {
149
150
  "action.demo": "查看示例", "action.exitDemo": "退出示例",
150
151
  "state.loading": "正在读取日历…", "state.empty": "这段时间没有日程。",
151
152
  "state.notConfigured": "还没配置 CalDAV 账号",
152
- "state.notConfiguredHint": "在 profile 的 cordis.patch.yml 里给 dsh-calendar 填上 provider / caldavUrl / username / password(或 OAuth 四件套)后重启即可。现在可以先看看示例面板。",
153
+ "state.notConfiguredHint": "点击“连接设置”,选择日历服务并填写账号信息,测试连接后保存即可。也可以先查看示例,了解日历的用法。",
153
154
  "state.readonly": "只读",
154
155
  "demo.banner": "示例数据(不是你的真实日历)—— 点右上角「退出示例」回到真实数据。",
155
156
  "field.summary": "标题", "field.date": "日期", "field.start": "开始", "field.end": "结束",
@@ -179,7 +180,7 @@ const UI = {
179
180
  "move.failed": "改期失败:{message}",
180
181
  "conn.button": "连接设置",
181
182
  "conn.title": "CalDAV 连接设置",
182
- "conn.intro": "填完点「测试连接」,通了才会保存。密码只存在本机(不进日志、不进导出)。",
183
+ "conn.intro": "测试连接不会修改日历。连接成功后,点击“保存并启用”。",
183
184
  "conn.provider": "服务商",
184
185
  "conn.caldavUrl": "日历集合 URL",
185
186
  "conn.username": "账号",
@@ -202,8 +203,8 @@ const UI = {
202
203
  "conn.okSample": "(例如:{sample})",
203
204
  "conn.fail": "连接失败",
204
205
  "conn.savedToast": "连接已保存,工具下一次调用就用它",
205
- "conn.noSettings": "当前宿主的 settings 服务不可用,面板不能保存:请在 profile 的 cordis.patch.yml 里配置 dsh-calendar 后重启。",
206
- "conn.storageFallback": "连接保存在插件自己的文件:~/.dsh/data/dsh-calendar/connection.json({reason},功能不受影响)。",
206
+ "conn.noSettings": "当前无法保存连接设置。请检查 DSH 与日历插件是否已更新,再重新打开此页面。",
207
+ "conn.storageFallback": "连接信息保存在运行 DSH 的设备上,保存后立即生效。",
207
208
  "conn.needProvider": "先选一个服务商",
208
209
  "conn.current": "当前:{summary}",
209
210
  "conn.steps": "怎么拿到这些值?(点开看步骤)",
@@ -244,7 +245,7 @@ const UI = {
244
245
  "action.demo": "See a sample", "action.exitDemo": "Exit sample",
245
246
  "state.loading": "Loading your calendar…", "state.empty": "Nothing scheduled in this range.",
246
247
  "state.notConfigured": "No CalDAV account configured yet",
247
- "state.notConfiguredHint": "Fill in provider / caldavUrl / username / password (or the four OAuth fields) for dsh-calendar in your profile's cordis.patch.yml and restart. Meanwhile you can look at a sample panel.",
248
+ "state.notConfiguredHint": "Open Connection settings, choose your calendar service and enter your account details, then test and save the connection. You can also explore the sample calendar first.",
248
249
  "state.readonly": "read-only",
249
250
  "demo.banner": "Sample data (not your real calendar) — hit「Exit sample」to go back.",
250
251
  "field.summary": "Title", "field.date": "Date", "field.start": "Start", "field.end": "End",
@@ -274,7 +275,7 @@ const UI = {
274
275
  "move.failed": "Could not reschedule: {message}",
275
276
  "conn.button": "Connection",
276
277
  "conn.title": "CalDAV connection",
277
- "conn.intro": "Fill this in and hit「Test connection」— nothing is saved until it works. The password stays on this machine only (no logs, no exports).",
278
+ "conn.intro": "Testing the connection does not change your calendar. Once it succeeds, click Save and enable.",
278
279
  "conn.provider": "Provider",
279
280
  "conn.caldavUrl": "Calendar collection URL",
280
281
  "conn.username": "Account",
@@ -297,8 +298,8 @@ const UI = {
297
298
  "conn.okSample": " (e.g. {sample})",
298
299
  "conn.fail": "Connection failed",
299
300
  "conn.savedToast": "Saved — the tools pick it up on their next call",
300
- "conn.noSettings": "This host has no settings service, so the panel cannot save: configure dsh-calendar in the profile's cordis.patch.yml and restart.",
301
- "conn.storageFallback": "Saved in the plugin's own file: ~/.dsh/data/dsh-calendar/connection.json ({reason}; nothing else changes).",
301
+ "conn.noSettings": "Connection settings cannot be saved right now. Check that DSH and the calendar plugin are up to date, then reopen this page.",
302
+ "conn.storageFallback": "Connection details are stored on the device running DSH. Saved changes take effect immediately.",
302
303
  "conn.needProvider": "Pick a provider first",
303
304
  "conn.current": "Now: {summary}",
304
305
  "conn.steps": "Where do these values come from?",
@@ -1455,7 +1456,7 @@ function ConnectionForm(props) {
1455
1456
  : null,
1456
1457
  h("div", { className: "dshc-field" }, [
1457
1458
  h("label", null, t("conn.provider")),
1458
- h("select", { className: "dshc-input", value: form.provider, onChange: (e) => patch({ provider: e.target.value }) },
1459
+ h("select", { className: "dshc-input", "aria-label": t("conn.provider"), value: form.provider, onChange: (e) => patch({ provider: e.target.value }) },
1459
1460
  [h("option", { value: "", key: "__none" }, "— " + t("conn.needProvider") + " —")].concat(
1460
1461
  PROVIDER_NAMES.map((name) => h("option", { value: name, key: name }, name === "custom" ? "自建 CalDAV" : name === "icloud" ? "iCloud" : name === "nextcloud" ? "Nextcloud" : "Google"))
1461
1462
  ))
@@ -1476,8 +1477,9 @@ function ConnectionForm(props) {
1476
1477
  const hintKey = FIELD_HINT[form.provider] ? FIELD_HINT[form.provider][key] : undefined;
1477
1478
  return h("div", { className: "dshc-field", key }, [
1478
1479
  h("label", null, t(FIELD_LABEL[key])),
1479
- h(Txt, {
1480
- type: secret ? "password" : "text",
1480
+ h(Txt, {
1481
+ type: secret ? "password" : "text",
1482
+ "aria-label": t(FIELD_LABEL[key]),
1481
1483
  value: form[key] || "",
1482
1484
  placeholder: stored ? t("conn.keep") : "",
1483
1485
  onChange: (e) => patch({ [key]: e.target.value })
@@ -1496,7 +1498,7 @@ function ConnectionForm(props) {
1496
1498
  maySave !== true || (connection !== null && connection !== undefined && connection.settingsKind === "file")
1497
1499
  ? h("div", { className: "dshc-sub", style: { marginTop: "10px" } },
1498
1500
  connection !== null && connection !== undefined && connection.settingsKind === "file"
1499
- ? t("conn.storageFallback", { reason: connection.settingsReason || "插件未注入宿主 settings 服务" })
1501
+ ? t("conn.storageFallback")
1500
1502
  : t("conn.current", { summary: connectionSummary(connection) }))
1501
1503
  : null
1502
1504
  ]);
package/lib/config.js CHANGED
@@ -93,12 +93,10 @@ export function resolveCredentials(config, env = process.env) {
93
93
  const username = nonEmpty(config?.username);
94
94
  const password = nonEmpty(config?.password) ?? nonEmpty(env.DSH_CALENDAR_PASSWORD);
95
95
  if (username === undefined) {
96
- throw new ConfigError('dsh-calendar 未配置 username:请在 profile 的 cordis.patch.yml 覆盖 calendar 行的 config,' +
97
- '填上 CalDAV 账号(iCloud 为账号邮箱)后重启。');
96
+ throw new ConfigError('日历账号未填写:请在日历的“连接设置”中填写“账号”(iCloud 使用 Apple ID 邮箱),然后重新测试连接。');
98
97
  }
99
98
  if (password === undefined) {
100
- throw new ConfigError('dsh-calendar 未配置密码:请设置环境变量 DSH_CALENDAR_PASSWORD,' +
101
- '或在 profile 的 cordis.patch.yml 覆盖 calendar 行的 password(iCloud 请用应用专用密码)后重启。');
99
+ throw new ConfigError('日历密码未填写:请在“连接设置”中填写“密码 / 应用专用密码”,然后重新测试连接。iCloud 需要应用专用密码。');
102
100
  }
103
101
  return { username, password };
104
102
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-calendar",
3
- "version": "0.8.3",
3
+ "version": "0.8.4",
4
4
  "description": "DSH 日历插件:可视化周/月视图、拖拽改期与 CalDAV 日程管理,支持 Google OAuth2、iCloud、Nextcloud。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",