dsh-calendar 0.11.1 → 0.12.0

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
@@ -4,6 +4,19 @@
4
4
 
5
5
  [历史英文记录](docs/CHANGELOG.en.md)
6
6
 
7
+ ## 0.12.0(2026-10-25)
8
+
9
+ - 日历主工作台,日期导航、月周议程切换与日程编辑分层更清楚。
10
+ - 提供 DSH 原生侧栏入口,保留设置页;统一中英、深浅色、窄屏、键盘焦点与真实空/失败状态。
11
+ - 浏览器源码移至 templates/client.js、templates/panels/ 与共享组件,独立构建为 lib/client.js;移除重复的首次引导。
12
+ - 官方 DSH 0.2.1-rc.3 Web 逐项实际操作验收,账户模拟和未验收范围见 [工作台说明](docs/WORKBENCH.md)。
13
+
14
+ ## 0.11.2(2026-10-20)
15
+
16
+ - 修复 #3:更新时间时保留原 TZID 对应的本地钟点和夏令时规则,不再写出 TZID 与 UTC `Z` 混用的属性。
17
+ - 含 EXDATE、RDATE 或单次覆盖的系列,拒绝整体改开始时间、全天类型或重复规则,防止取消场次复活、改期场次重复。
18
+ - 重复系列更新 / 删除必须显式传 `scope:"series"`;面板编辑先读取系列主记录,并提示影响全部场次,删除确认包含视图外场次。
19
+
7
20
  ## 0.11.1(2026-10-20)
8
21
 
9
22
  - 修复 calendar_update 传入空字符串时无法清空说明、地点或重复规则的问题;省略字段仍保留原值。
package/README.en.md CHANGED
@@ -13,6 +13,8 @@ Feedback and contributions are welcome: report [issues](https://github.com/STARD
13
13
 
14
14
  See the [0.10.4 validation record](docs/validation/0.10.4.md) for DSH `0.2.1-alpha.5` browser checks and the remaining limits.
15
15
 
16
+ Open the new native sidebar workbench after updating and restarting DSH. Settings remains available. See the [workbench guide and validation boundaries](docs/WORKBENCH.md).
17
+
16
18
  ## What it does
17
19
 
18
20
  - Month, week and agenda views with drag and keyboard rescheduling.
package/README.md CHANGED
@@ -13,6 +13,8 @@
13
13
 
14
14
  DSH `0.2.1-alpha.5` 的本轮检查与未验收范围见 [0.10.4 验收记录](docs/validation/0.10.4.md)。
15
15
 
16
+ 更新并重启 DSH 后,可从原生侧栏打开新版工作台,原设置入口继续保留。详见[工作台说明与验收范围](docs/WORKBENCH.md)。
17
+
16
18
  ## 功能
17
19
 
18
20
  - 月、周与议程视图,支持拖拽和键盘改期。
package/docs/USAGE.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  ## 本次改进
6
6
 
7
+ 重复系列的 `calendar_update` / `calendar_delete` 需先向用户说明影响,确认操作全部场次后传 `scope:"series"`。无法只改或删除某一次。面板编辑读取系列原始日期,删除确认覆盖整个系列。有取消、额外或单独改期场次的系列不能整体改开始时间、全天类型或重复规则,请在原日历客户端处理;描述、地点、标题仍可修改。带 TZID 的时间保留其本地钟点与夏令时语义。
8
+
7
9
  日期使用 YYYY-MM-DD;带时间使用带 Z 或 UTC 偏移的 ISO 格式。错误日期会在创建或更新远端日程前报错,原日程保留。
8
10
 
9
11
  ## 安装
@@ -0,0 +1,29 @@
1
+ # dsh-calendar 工作台 / Workbench
2
+
3
+ 日历主工作台,日期导航、月周议程切换与日程编辑分层更清楚。
4
+
5
+ Calendar workbench with clearer date navigation, views and event editing.
6
+
7
+ ## 使用 / Use
8
+
9
+ 更新插件并重启 DSH,在原生左侧栏打开工作台;没有固定时可在“更多”中找到。原有“设置”入口继续可用。侧栏排序和固定由 DSH 管理。
10
+
11
+ Update the plugin, restart DSH and open its native sidebar panel (or More if it is not pinned). The existing Settings entry remains available. DSH owns sidebar order and pinning.
12
+
13
+ 界面跟随宿主中英文和深浅色,保留用户内容原文。窄窗口中先显示列表,打开详情后可返回;编辑器按可用宽度分栏或顺序排列。危险操作需要明确确认,未保存内容不会因切页而静默丢失。
14
+
15
+ The UI follows host language and theme without translating user content. Narrow master/detail views have a Back action; editors adapt their columns to available space. Destructive actions require confirmation and edits are protected.
16
+
17
+ ## 源码 / Source
18
+
19
+ 编辑 templates/client.js、templates/panels/*.js 与 templates/workbench-ui.js,运行 pnpm run build。lib/client.js 是确定性产物,请随源码提交。公共组件的规范源位于 dsh-suite/ui/workbench-ui.js,Suite 的同步脚本显式分发副本;单个仓库可独立构建和安装。
20
+
21
+ Edit the template sources and run pnpm run build. Commit generated lib/client.js with source changes. The vendored UI has no Suite runtime dependency.
22
+
23
+ ## 验收范围 / Validation boundary
24
+
25
+ 2026-10-25:Windows、官方 DSH 0.2.1-rc.3 Web,后台 Chrome/Playwright 实际点击和输入;覆盖中英文、浅深色、1536px 与 390px、状态读回与控制台。Browser plugin 不可用,因此使用本地 Playwright。
26
+
27
+ 邮件使用受控 AgentMail HTTP 服务,日历使用受控 CalDAV 协议传输;插件处理器、存储、校验和原生宿主均实际运行。未使用真实邮箱、真实日历账号或付费模型。RSS 访问 Node.js 官方公开来源。PPT 实际生成并渲染 PPTX、下载 ZIP;两个视频插件实际运行官方引擎并播放 MP4。
28
+
29
+ 这些是 Web 共用界面的验收结果,不代表已验收 Electron 专属菜单、系统权限、真实账号、全部外部来源或所有可选模型/引擎。Docker、Slack、钉钉继续按用户约定搁置。
package/lib/caldav.d.ts CHANGED
@@ -45,10 +45,12 @@ export declare class CalendarService {
45
45
  }>;
46
46
  /** Insert one already reviewed UID resource; tsdav uses If-None-Match:* and never overwrites existing objects. */
47
47
  importRaw(uid: string, data: string, signal?: AbortSignal): Promise<void>;
48
+ /** Read the resource master rather than a projected occurrence. */
49
+ get(uid: string, signal?: AbortSignal): Promise<CalendarEvent>;
48
50
  /** 按 uid 更新事件;未提供的字段保留原值。 */
49
- update(uid: string, changes: Partial<EventFields>, signal?: AbortSignal): Promise<CalendarEvent>;
51
+ update(uid: string, changes: Partial<EventFields>, signal?: AbortSignal, scope?: 'series'): Promise<CalendarEvent>;
50
52
  /** 按 uid 删除事件。 */
51
- delete(uid: string, signal?: AbortSignal): Promise<{
53
+ delete(uid: string, signal?: AbortSignal, scope?: 'series'): Promise<{
52
54
  uid: string;
53
55
  href: string;
54
56
  }>;
package/lib/caldav.js CHANGED
@@ -9,7 +9,7 @@ import { createHash } from 'node:crypto';
9
9
  import ICAL from 'ical.js';
10
10
  import { createProxyFetch } from './proxy-fetch.js';
11
11
  import { createOAuthFetch, OAuthError } from './oauth.js';
12
- import { buildICalString, expandEventFromICal, ExpansionLimitError, generateUid, parseEventFromICal, updateICalString, } from './ical.js';
12
+ import { buildICalString, expandEventFromICal, ExpansionLimitError, generateUid, parseEventFromICal, updateICalString, isRecurringResource, } from './ical.js';
13
13
  /** CalDAV 操作错误:带中文指引。 */
14
14
  export class CalDAVError extends Error {
15
15
  status;
@@ -279,8 +279,22 @@ export class CalendarService {
279
279
  throw translateError(error, '导入日程', this.config);
280
280
  }
281
281
  }
282
+ /** Read the resource master rather than a projected occurrence. */
283
+ async get(uid, signal) {
284
+ try {
285
+ const object = await this.findObject(uid, signal);
286
+ const event = object && parseEventFromICal(String(object.data ?? ''), object.url, object.etag);
287
+ if (!event)
288
+ throw new CalDAVError('找不到或无法解析日程,请刷新日历后重试。');
289
+ return event;
290
+ }
291
+ catch (error) {
292
+ signal?.throwIfAborted();
293
+ throw translateError(error, '读取系列事件', this.config);
294
+ }
295
+ }
282
296
  /** 按 uid 更新事件;未提供的字段保留原值。 */
283
- async update(uid, changes, signal) {
297
+ async update(uid, changes, signal, scope) {
284
298
  signal?.throwIfAborted();
285
299
  let object;
286
300
  try {
@@ -295,6 +309,10 @@ export class CalendarService {
295
309
  '该事件可能已被删除或 uid 已过期。');
296
310
  }
297
311
  const existing = parseEventFromICal(String(object.data ?? ''), object.url, object.etag);
312
+ if (!existing)
313
+ throw new CalDAVError('无法解析原日程,更新已取消;请在原日历客户端检查。');
314
+ if (isRecurringResource(String(object.data ?? '')) && scope !== 'series')
315
+ throw new CalDAVError('这是整个重复系列。请先向用户说明影响,确认后显式传 scope="series";当前不支持只改某一次。');
298
316
  const start = changes.start ?? existing?.start;
299
317
  const end = changes.end ?? existing?.end;
300
318
  if (start === undefined || end === undefined) {
@@ -340,7 +358,7 @@ export class CalendarService {
340
358
  return event;
341
359
  }
342
360
  /** 按 uid 删除事件。 */
343
- async delete(uid, signal) {
361
+ async delete(uid, signal, scope) {
344
362
  signal?.throwIfAborted();
345
363
  let object;
346
364
  try {
@@ -354,6 +372,8 @@ export class CalendarService {
354
372
  throw new CalDAVError('找不到 uid 对应的事件:请用 calendar_list 或 calendar_search 重新获取最新 uid,' +
355
373
  '该事件可能已被删除或 uid 已过期。');
356
374
  }
375
+ if (isRecurringResource(String(object.data ?? '')) && scope !== 'series')
376
+ throw new CalDAVError('这是整个重复系列。请先向用户说明影响,确认后显式传 scope="series";当前不支持只删某一次。');
357
377
  try {
358
378
  const client = await this.client();
359
379
  signal?.throwIfAborted();