Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,15 @@ MIT
### 收到的 Calendar 邀請

`event show`/`event agenda` 的 JSON 保留 optional `invitation`(外部 UID/Organizer);Imported Event 的 `event set` 回 `IMPORTED_EVENT_READ_ONLY`,刪除與還原不寄 attendee email。`email show` 保留 optional `calendar_sync`,event_id 僅在同時具備 Calendar read 權限時回傳。此版 upstream 收件同步預設停用,須待 provider 信任驗證後才啟用。

### Recurring Todo 固定 assignee

建立 rule 時可用 `--assignee-user-id` 指定目前 Workspace Member;省略時指派給 creator。Rule 建立後不能修改 assignee。

```bash
wspc todo rule add "Weekly review" --rrule "FREQ=WEEKLY" --dtstart 2026-09-15 --project prj_xxx --assignee-user-id usr_xxx
wspc todo rule ls --project-id prj_xxx
wspc todo rule show tdr_xxx --json
```

List/show 的 pretty 與 JSON 輸出顯示 creator、assignee 及 `assignee_status`。`not_member` 與 `unknown` 暫停產生或重建,保留既有 Todos。需要換人時先刪除舊 rule,再以適當起始日期建立新 rule,避免重複工作。
2,736 changes: 2,112 additions & 624 deletions spec/openapi.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/generated/cli/event/ls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { parseTimeInput, resolveTimezone } from "../../../handwritten/utils/pars

export const eventListCommand = new Command("ls")
.description("List calendar events")
.addHelpText("after", "\n### Overview\nReturn the authenticated user's events, ordered by `start` ascending, with cursor pagination.\n\n### When to Use\nRender calendar list/grid views, search for specific terms using full-text search, query events within a specific time window, or retrieve historically past events.\n\n### Constraints\n- **Default Visibility**: By default, soft-deleted events and past events (events where `end` is before the current time) are automatically hidden.\n- **Time Bounds Override**: Supplying any explicit time bound query parameter (`start_from`, `start_to`, `end_from`, `end_to`) or passing `include_past=true` overrides and disables the implicit past filter.\n- **Calendar Trash**: `deleted_only=true` returns only soft-deleted events for the current user and Workspace. It overrides `include_deleted` and disables the implicit past filter regardless of `include_past`. Explicit time bounds and `q` still apply. Series Masters remain single rows; cancelled occurrences are not Trash.\n- **Search Scope**: `q` performs a case-insensitive substring search across `title`, `description`, and `location`.\n- **Pagination**: Default `limit` is 50, clamped to `[1, 200]`. Matching events are ordered by `start ASC, id ASC` before cursor pagination. Cursor is a page position, not a Consistency bookmark or snapshot.\n\n### Troubleshooting\n- Returns 400 `VALIDATION_ERROR` if date query bounds are invalid (e.g. `start_from > start_to` or `end_from > end_to`).\n\nExamples:\n $ wspc event ls\n $ wspc event ls --deleted-only\n $ wspc event ls --from \"today\" --to \"next week\"\n")
.option("--q <value>", "Optional full-text search across title, description, and location (case-insensitive substring).")
.addHelpText("after", "\n### Overview\nReturn the authenticated user's events, ordered by `start` ascending, with cursor pagination.\n\n### When to Use\nRender calendar list/grid views, search for literal text, query events within a specific time window, or retrieve historically past events.\n\n### Constraints\n- **Default Visibility**: By default, soft-deleted events and past events (events where `end` is before the current time) are automatically hidden.\n- **Time Bounds Override**: Supplying any explicit time bound query parameter (`start_from`, `start_to`, `end_from`, `end_to`) or passing `include_past=true` overrides and disables the implicit past filter.\n- **Calendar Trash**: `deleted_only=true` returns only soft-deleted events for the current user and Workspace. It overrides `include_deleted` and disables the implicit past filter regardless of `include_past`. Explicit time bounds and `q` still apply. Series Masters remain single rows; cancelled occurrences are not Trash.\n- **Search Scope**: `q` performs a literal substring search across `title`, `description`, and `location`. ASCII case-insensitive; UTF-8 text is supported. Percent and underscore are literal characters, not wildcards.\n- **Pagination**: Default `limit` is 50, clamped to `[1, 200]`. Matching events are ordered by `start ASC, id ASC` before cursor pagination. Cursor is a page position, not a Consistency bookmark or snapshot.\n\n### Troubleshooting\n- Returns 400 `VALIDATION_ERROR` if date query bounds are invalid (e.g. `start_from > start_to` or `end_from > end_to`).\n\nExamples:\n $ wspc event ls\n $ wspc event ls --deleted-only\n $ wspc event ls --from \"today\" --to \"next week\"\n")
.option("--q <value>", "Optional literal substring search across title, description, and location. ASCII case-insensitive; UTF-8 text is supported. Percent and underscore are literal characters, not wildcards.")
.option("--from <value>", "Inclusive lower bound on the event `start` (ISO datetime with offset, or ISO date-only). When ANY of `start_from`/`start_to`/`end_from`/`end_to` is provided, the implicit past filter is disabled.")
.option("--to <value>", "Inclusive upper bound on the event `start`.")
.option("--end-from <value>", "Inclusive lower bound on the event `end`.")
Expand Down
4 changes: 3 additions & 1 deletion src/generated/cli/todo/rule/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import { runSdkCommand } from "../../../../handwritten/commands/run-sdk-command.

export const recurrenceRuleCreateCommand = new Command("add")
.description("Create a recurring todo rule")
.addHelpText("after", "\n### 🎯 Overview & Purpose\nCreate a recurrence rule that materializes upcoming todo instances on a repeating schedule.\n\n### 🔍 When to Use\n* Use this to set up recurring work like a weekly Standup, monthly reporting, or cyclical maintenance. The server automatically materializes upcoming todo instances on a 14-day rolling horizon.\n\n### 💡 Key Features & Constraints\n* **RFC-5545 Conformity**: The `rrule` parameter must be a valid RFC-5545 schedule string (e.g., `FREQ=WEEKLY;BYDAY=MO`) and must **not** include the `DTSTART` or `TZID` directive.\n* **Anchor Date**: `dtstart` specifies the local calendar starting date (`YYYY-MM-DD`) where the schedule rule is anchored.\n* **Nesting Constraints**: Recurrence rules can only be bound to root-level tasks. Child tasks (subtasks) cannot have recurrence rules. Setting a child task as a parent will trigger `PARENT_IS_CHILD`.\n* **Instance Independence**: Once materialized, each todo instance is fully independent with its own `status` and `due_at`.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`RRULE_INVALID` (HTTP 400)**: Thrown if the `rrule` schedule string is broken or contains illegal `DTSTART` directives.\n* **`PARENT_IS_CHILD` (HTTP 400)**: Thrown if the specified `parent_id` points to a child task.\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if date format is invalid or required fields are missing.\n\nExamples:\n $ wspc todo rule add \"Weekly review\" --rrule \"FREQ=WEEKLY;BYDAY=MO\" --dtstart 2026-05-18 --project prj_xxx\n $ wspc todo rule add \"Weekly review\" --rrule \"FREQ=WEEKLY;BYDAY=MO\" --dtstart 2026-05-18 --project prj_xxx --type typ_xxx\n")
.addHelpText("after", "\n### 🎯 Overview & Purpose\nCreate a recurrence rule that materializes upcoming todo instances on a repeating schedule.\n\n### 🔍 When to Use\n* Use this to set up recurring work like a weekly Standup, monthly reporting, or cyclical maintenance. The server automatically materializes upcoming todo instances on a 14-day rolling horizon.\n\n### 💡 Key Features & Constraints\n* **RFC-5545 Conformity**: The `rrule` parameter must be a valid RFC-5545 schedule string (e.g., `FREQ=WEEKLY;BYDAY=MO`) and must **not** include the `DTSTART` or `TZID` directive.\n* **Anchor Date**: `dtstart` specifies the local calendar starting date (`YYYY-MM-DD`) where the schedule rule is anchored.\n* **Nesting Constraints**: Recurrence rules can only be bound to root-level tasks. Child tasks (subtasks) cannot have recurrence rules. Setting a child task as a parent will trigger `PARENT_IS_CHILD`.\n* **Fixed Assignee**: Optional `assignee_user_id` assigns every occurrence and subtask to a current Workspace Member. Omit to use the creator. Assignment cannot change after rule creation. To change assignee, delete the old rule and create a new one; existing instances remain, so choose a start date that avoids overlap. If membership is absent or unavailable, materialization pauses and existing instances stay intact.\n* **Instance Independence**: Once materialized, each todo instance is fully independent with its own `status` and `due_at`.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`RRULE_INVALID` (HTTP 400)**: Thrown if the `rrule` schedule string is broken or contains illegal `DTSTART` directives.\n* **`PARENT_IS_CHILD` (HTTP 400)**: Thrown if the specified `parent_id` points to a child task.\n* **`VALIDATION_ERROR` (HTTP 400)**: Thrown if date format is invalid or required fields are missing.\n\nExamples:\n $ wspc todo rule add \"Weekly review\" --rrule \"FREQ=WEEKLY;BYDAY=MO\" --dtstart 2026-05-18 --project prj_xxx\n $ wspc todo rule add \"Weekly review\" --rrule \"FREQ=WEEKLY;BYDAY=MO\" --dtstart 2026-05-18 --project prj_xxx --type typ_xxx\n")
.argument("<title>", "title")
.option("--assignee-user-id <value>", "assignee_user_id")
.option("--rrule <value>", "rrule")
.option("--dtstart <value>", "dtstart")
.option("--description <value>", "description")
Expand All @@ -19,6 +20,7 @@ export const recurrenceRuleCreateCommand = new Command("add")
input: {
body: {
title,
assignee_user_id: opts.assigneeUserId,
rrule: opts.rrule,
dtstart: opts.dtstart,
description: opts.description,
Expand Down
2 changes: 1 addition & 1 deletion src/generated/cli/todo/rule/ls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ export const recurrenceRuleListCommand = new Command("ls")
user_id: opts.userId,
},
},
context: { kind: "recurrence_rule_list", display: {"shape":"list","columns":["id","rrule","dtstart","type_id"],"format":{"id":"id-short","rrule":"truncate","type_id":"id-short"},"emptyMessage":"no recurrence rules"} },
context: { kind: "recurrence_rule_list", display: {"shape":"list","columns":["id","rrule","dtstart","type_id","user_id","assignee_user_id","assignee_status"],"format":{"id":"id-short","rrule":"truncate","type_id":"id-short"},"emptyMessage":"no recurrence rules"} },
})
})
4 changes: 2 additions & 2 deletions src/generated/cli/todo/rule/show.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { runSdkCommand } from "../../../../handwritten/commands/run-sdk-command.

export const recurrenceRuleGetCommand = new Command("show")
.description("Get a recurring todo rule")
.addHelpText("after", "\n### 🎯 Overview & Purpose\nFetch a single recurrence rule along with its template todo snapshot and the count of materialized instances.\n\n### 🔍 When to Use\n* Use this to inspect rule details before editing, preview the task template that future occurrences will copy, or check the current materialization metrics.\n\n### 💡 Key Features & Constraints\n* **Snapshot Integrity**: The returned template represents a schema template snapshot — modifying the rule (PATCH) only alters future occurrences; already-materialized tasks are never mutated retroactively.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`NOT_FOUND` (HTTP 404)**: Thrown if the specified rule ID does not exist.\n\nExamples:\n $ wspc todo rule show tdr_xxx\n")
.addHelpText("after", "\n### 🎯 Overview & Purpose\nFetch a single recurrence rule along with its template todo snapshot and the count of materialized instances.\n\n### 🔍 When to Use\n* Use this to inspect rule details before editing, preview the task template that future occurrences will copy, or check the current materialization metrics.\n\n### 💡 Key Features & Constraints\n* **Snapshot Integrity**: The returned template represents a schema template snapshot — rule edits rebuild eligible open instances from today when membership is valid; modified roots are preserved.\n\n### ⚠️ Common Errors & Troubleshooting\n* **`NOT_FOUND` (HTTP 404)**: Thrown if the specified rule ID does not exist.\n\nExamples:\n $ wspc todo rule show tdr_xxx\n")
.argument("<id>", "id")
.action(async (id, opts) => {
await runSdkCommand({
Expand All @@ -15,6 +15,6 @@ export const recurrenceRuleGetCommand = new Command("show")
id,
},
},
context: { kind: "recurrence_rule_get", display: {"shape":"object","format":{"id":"id-short","type_id":"id-short"}} },
context: { kind: "recurrence_rule_get", display: {"shape":"object","dataPath":"rule","format":{"id":"id-short","type_id":"id-short"}} },
})
})
4 changes: 2 additions & 2 deletions src/generated/sdk/index.ts

Large diffs are not rendered by default.

Loading