From 85679d4258ad45b00228b373e4eeffab2d646ac1 Mon Sep 17 00:00:00 2001 From: calendar-assistant Date: Mon, 6 Jul 2026 14:10:57 +0800 Subject: [PATCH] feat: support semantic recurring calendar operations (#1723) --- skills/lark-calendar/SKILL.md | 7 +- .../references/lark-calendar-recurring.md | 90 +++++++++++++++++++ .../references/lark-calendar-update.md | 4 +- 3 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 skills/lark-calendar/references/lark-calendar-recurring.md diff --git a/skills/lark-calendar/SKILL.md b/skills/lark-calendar/SKILL.md index c5abe0111..c5b1d5f87 100644 --- a/skills/lark-calendar/SKILL.md +++ b/skills/lark-calendar/SKILL.md @@ -45,13 +45,15 @@ lark-cli calendar +agenda --as user | 场景 | 前置要求 | |------|----------| | 预约日程/会议、查会议室 | 先读 [lark-calendar-schedule-meeting.md](references/lark-calendar-schedule-meeting.md) | -| 编辑已有日程 | 先定位目标日程 `event_id`;若是重复性日程,必须定位到具体实例的 `event_id`(禁止使用原重复日程 ID) | +| 编辑已有日程 | 先定位目标日程 `event_id` | +| 编辑/删除重复性日程 | 先读 [重复性日程操作规范](references/lark-calendar-recurring.md),按操作范围(仅此次/全部/此次及后续)执行 | | 删除/修改后验证 | 等待 2 秒再查询(API 最终一致性),不要告知用户你等待了 | | 调用任何 Shortcut | 先读其对应 reference 文档 | ## 核心概念 -- **日程实例(Instance)**:重复性日程展开后的具体时间实例。操作重复日程的某次实例时,必须先定位该实例的 `event_id`,禁止使用原重复日程的 `event_id`。 +- **日程实例(Instance)**:重复性日程展开后的具体时间实例。「仅此次」操作时使用具体实例的 `event_id`;「全部」或「此次及后续」操作时需对原重复性日程操作(使用原日程 `event_id`),并按需处理例外。 +- **重复性日程例外(Exception)**:对重复性日程某次实例做过「仅此次」编辑后产生的独立日程(拥有独立 `event_id`)。删除/更新「全部」时必须同时处理例外,否则例外会残留。 - **全天日程(All-day Event)**:只按日期占用、没有具体起止时刻的日程,结束日期是包含在日程时间内的。 - **时间块 vs 时间范围**:时间块是具体确定的连续时间段(如 `14:00~15:00`),时间范围是泛指(如"今天下午")。`+room-find` 必须基于确定时间块,不能基于模糊范围。 - **会议室(Room)**:"room"不是"房间",是"会议室"。会议室是日程的一种参与人(resource attendee),不能脱离日程单独预定。 @@ -71,6 +73,7 @@ lark-cli calendar +agenda --as user | 从日程获取关联的视频会议 ID 或用户绑定的会议纪要文档 | 本 skill(`+meeting`) | | 从日程进一步拿 AI 智能纪要 / 逐字稿 / 妙记产物 | 先 `+meeting` 取 `meeting_id`,再 [`vc +detail`](../lark-vc/references/lark-vc-detail.md) → [`note +detail`](../lark-note/references/lark-note-detail.md) / [`minutes +detail`](../lark-minutes/references/lark-minutes-detail.md) | | 预约/改约日程、添加/移除参会人、添加/更换会议室、调整时间 | 先判断新建 vs 编辑,再进入 [schedule-meeting 工作流](references/lark-calendar-schedule-meeting.md) | +| 编辑/删除重复性日程(「改这个重复日程」「删掉后面的」「全部取消」等) | 先读 [重复性日程操作规范](references/lark-calendar-recurring.md),确认操作范围后执行 | ## 任务类型分流 diff --git a/skills/lark-calendar/references/lark-calendar-recurring.md b/skills/lark-calendar/references/lark-calendar-recurring.md new file mode 100644 index 000000000..54d36f727 --- /dev/null +++ b/skills/lark-calendar/references/lark-calendar-recurring.md @@ -0,0 +1,90 @@ +# 重复性日程操作规范 + +重复性日程的编辑/删除分为三种范围:「仅此次」「全部」「此次及后续」。用户未明确范围时,**必须询问确认**。 + +## 关键概念 + +- **event_id 结构**:`event_id` 的格式为 `{event_uid}_{originalTime}`。普通日程或重复性日程本体的 `originalTime` 为 `0`;例外的 `originalTime > 0`,代表该例外在原重复性序列中本来的时间位置。因此 `{event_uid}_0` 即为原重复性日程的 `event_id`。 +- **原重复性日程**:携带 `rrule` 的日程本体,`event_id` 形如 `{event_uid}_0`。系列的所有属性(标题、时间、rrule、描述等)都挂在本体上。 +- **例外(Exception)**:对某次实例做过「仅此次」编辑后产生的独立日程,`event_id` 形如 `{event_uid}_{originalTime}`(`originalTime > 0`)。通过 `event_uid` 部分即可关联回原重复性日程。 +- 删除/更新原重复性日程 **不会** 级联处理例外——必须手动逐个处理。 + +## 前置步骤(所有范围通用) + +1. 通过 `+agenda` 或 `+search-event` 定位重复性日程,获取原重复性日程的 `event_id`。 +2. 通过 `events instance_view` 或 `+agenda` 列出实例,识别哪些是例外(`event_id` 中 `originalTime > 0` 的即为例外)。 +3. 确认用户的操作范围。 + +## 编辑全部(更新时间) + +| 步骤 | 命令 | 说明 | +|------|------|------| +| 1 | `lark-cli calendar +update --event-id <原重复日程ID> --start ... --end ...` | 更新原重复性日程的时间 | +| 2 | `lark-cli calendar events delete --params '{"calendar_id":"","event_id":"<例外ID>","need_notification":false}'` (逐个) | 时间变更后例外已无意义,必须删除 | + +> 理由:更新时间会改变重复起止点,例外日程的原始占位已变,若保留会导致时间冲突或残留。 + +## 编辑全部(更新非时间字段) + +| 步骤 | 命令 | 说明 | +|------|------|------| +| 1 | `lark-cli calendar +update --event-id <原重复日程ID> --summary ... --description ...` | 更新原重复性日程的标题/描述等 | +| 2 | `lark-cli calendar +update --event-id <例外ID> --summary ... --description ...` (逐个) | 同步更新例外日程的对应字段 | + +> 理由:例外已脱离原重复性日程独立存在,不会自动继承原日程的更新。 + +## 删除全部 + +| 步骤 | 命令 | 说明 | +|------|------|------| +| 1 | `lark-cli calendar events delete --params '{"calendar_id":"","event_id":"<原重复日程ID>","need_notification":true}'` | 删除重复性日程本体 | +| 2 | `lark-cli calendar events delete --params '{"calendar_id":"","event_id":"<例外ID>","need_notification":false}'` (逐个) | 删除所有例外日程 | + +> 理由:例外是独立实体,删除原重复性日程不会级联删除例外。 + +## 编辑此次及后续 + +| 步骤 | 命令 | 说明 | +|------|------|------| +| 1 | `lark-cli calendar +update --event-id <原重复日程ID> --rrule "FREQ=...;UNTIL=<截止日期>"` | 截短原重复性日程(UNTIL 设为指定时间前一次实例的日期) | +| 2 | `lark-cli calendar events delete ...` (逐个) | 删除指定时间之后(含)的例外日程 | +| 3 | `lark-cli calendar +create --summary ... --start <指定时间> --end ... --rrule "FREQ=..." --attendee-ids ...` | 从指定时间开始创建新的重复性日程(即「后续」部分,携带编辑后的内容) | + +> UNTIL 计算规则:若用户选择「从第 N 次开始编辑」,UNTIL 应设置为第 N-1 次实例的日期(即保留到指定时间之前的最后一次)。 +> 新日程应继承原日程的参会人、会议室等配置(除非用户明确要修改)。 + +## 删除此次及后续 + +| 步骤 | 命令 | 说明 | +|------|------|------| +| 1 | `lark-cli calendar +update --event-id <原重复日程ID> --rrule "FREQ=...;UNTIL=<截止日期>"` | 截短原重复性日程(UNTIL 设为指定时间前一次实例的日期) | +| 2 | `lark-cli calendar events delete ...` (逐个) | 删除指定时间之后(含)的例外日程 | + +> 与「编辑此次及后续」的区别:不需要步骤 3(创建新的重复性日程),因为目标是删除后续而非替换。 + +## 仅此次 + +- **编辑仅此次**:通过 `+agenda` / `+search-event` 定位到具体实例的 `event_id`,然后正常调用 `+update`。 +- **删除仅此次**:定位到具体实例的 `event_id`,调用 `events delete`。 + +## 用户意图映射 + +| 用户表达 | 操作范围 | +|----------|----------| +| 「改这个重复日程的标题」「全部改」「每次都改」 | 编辑全部 | +| 「删掉这个重复日程」「取消所有」 | 删除全部 | +| 「从下周开始改时间」「后面的都改」 | 编辑此次及后续 | +| 「从下周开始不要了」「后面的都删」 | 删除此次及后续 | +| 「就改这一次」「只删这一次」 | 仅此次 | +| 未明确范围 | **必须询问用户** | + +## 注意事项 + +- 涉及时间戳计算(如推算 UNTIL 日期)时,必须调用系统命令或脚本,禁止心算。 + +## 参考 + +- [lark-calendar](../SKILL.md) — 日历全部命令 +- [lark-calendar-update](lark-calendar-update.md) — 更新日程 Shortcut +- [lark-calendar-create](lark-calendar-create.md) — 创建日程 Shortcut +- [lark-shared](../../lark-shared/SKILL.md) — 认证和全局参数 diff --git a/skills/lark-calendar/references/lark-calendar-update.md b/skills/lark-calendar/references/lark-calendar-update.md index 834ed9acf..cd5ee90e1 100644 --- a/skills/lark-calendar/references/lark-calendar-update.md +++ b/skills/lark-calendar/references/lark-calendar-update.md @@ -43,7 +43,7 @@ lark-cli calendar +update \ | 参数 | 必填 | 说明 | |------|------|------| -| `--event-id ` | 是 | 要更新的日程 ID。重复性日程要先定位到目标实例的 `event_id`,不要直接使用原重复日程 ID | +| `--event-id ` | 是 | 要更新的日程 ID。重复性日程请根据操作范围选择 ID,详见 [重复性日程操作规范](lark-calendar-recurring.md) | | `--calendar-id ` | 否 | 日历 ID(省略则使用 `primary`) | | `--summary ` | 否 | 新日程标题。仅在显式传入 `--summary` 时更新;若传空字符串,会把标题清空 | | `--description ` | 否 | 新日程描述。目前 API 方式不支持编辑富文本描述;如果日程描述通过客户端编辑为富文本内容,则使用 API 更新描述会导致富文本格式丢失。仅在显式传入 `--description` 时更新;若传空字符串,会把描述清空 | @@ -65,7 +65,7 @@ lark-cli calendar +update \ - 只想修改标题、描述、时间或重复规则时,不需要同时传 `--add-attendee-ids` 或 `--remove-attendee-ids`。 - 如需替换某个参与人、群组或会议室,使用 `--remove-attendee-ids <旧ID>` + `--add-attendee-ids <新ID>`。 - 会议室是 resource attendee,必须使用 `omm_` ID 添加到参会人列表,不能脱离日程单独预定。 -- 更新重复性日程的某一次实例时,必须先通过 `+agenda`、`+search-event` 或实例视图定位该实例的 `event_id`。 +- 更新重复性日程时,必须先确定操作范围(仅此次/全部/此次及后续),然后按 [重复性日程操作规范](lark-calendar-recurring.md) 执行。 - 如果需要验证更新结果,等待至少 2 秒后再查询,避免同步延迟导致读到旧数据。 - 当同一次命令组合多个动作时,执行顺序为“日程字段 -> 移除参会人 -> 添加参会人”。若中途失败,不会自动回滚已成功步骤;错误信息会说明已完成的步骤。