calendar: add todo edit command

Allow editing todo fields (due date, priority) in place via todoman,
instead of requiring delete + recreate. Updates all docs for consistency.
This commit is contained in:
Yanxin Lu
2026-03-24 21:56:23 -07:00
parent 20ee61498c
commit 734790a599
5 changed files with 136 additions and 5 deletions

View File

@@ -128,14 +128,16 @@ $SKILL_DIR/scripts/calendar.sh reply --envelope-id 42 --action decline \
# 待办管理
$SKILL_DIR/scripts/calendar.sh todo add --summary "跟进报销" --due "2026-03-25" --priority high
$SKILL_DIR/scripts/calendar.sh todo list
$SKILL_DIR/scripts/calendar.sh todo edit --match "报销" --due "2026-03-28"
$SKILL_DIR/scripts/calendar.sh todo complete --match "报销"
$SKILL_DIR/scripts/calendar.sh todo delete --match "报销"
$SKILL_DIR/scripts/calendar.sh todo check # 每日摘要cron
# 查看日历(检查冲突)
khal list today 7d
```
**支持操作**: 发送邀请 (`send`)、接受/拒绝/暂定 (`reply`)、待办管理 (`todo add/list/complete/delete/check`)
**支持操作**: 发送邀请 (`send`)、接受/拒绝/暂定 (`reply`)、待办管理 (`todo add/list/edit/complete/delete/check`)
**依赖**: himalaya邮件、vdirsyncerCalDAV 同步、khal查看日历、todoman待办管理
**同步**: 发送/回复/待办变更后自动 `vdirsyncer sync`,心跳也会定期同步
**注意**: 发送日历邀请属于对外邮件,需先确认

View File

@@ -42,6 +42,7 @@ $SKILL_DIR/scripts/calendar.sh reply [options]
# Manage todos
$SKILL_DIR/scripts/calendar.sh todo add [options]
$SKILL_DIR/scripts/calendar.sh todo list [options]
$SKILL_DIR/scripts/calendar.sh todo edit [options]
$SKILL_DIR/scripts/calendar.sh todo complete [options]
$SKILL_DIR/scripts/calendar.sh todo delete [options]
$SKILL_DIR/scripts/calendar.sh todo check
@@ -198,6 +199,23 @@ $SKILL_DIR/scripts/calendar.sh todo list # pending only
$SKILL_DIR/scripts/calendar.sh todo list --all # include completed
```
### `todo edit` — Modify a Todo
```bash
$SKILL_DIR/scripts/calendar.sh todo edit --match "保险报销" --due "2026-03-26"
$SKILL_DIR/scripts/calendar.sh todo edit --uid "abc123@openclaw" --priority high
$SKILL_DIR/scripts/calendar.sh todo edit --match "census" --due "2026-03-28" --priority low
```
| Flag | Required | Description |
|-----------------|----------|-----------------------------------------------------|
| `--uid` | * | Todo UID |
| `--match` | * | Match on summary text |
| `--due` | No | New due date (YYYY-MM-DD) |
| `--priority` | No | New priority: `high`, `medium`, or `low` |
\* One of `--uid` or `--match` is required. At least one edit flag must be provided.
### `todo complete` — Mark as Done
```bash

View File

@@ -188,7 +188,55 @@ $SKILL_DIR/scripts/calendar.sh todo list --all
- [ ] Priority grouping is correct in wrapper output
- [ ] `--all` flag works (same output when none are completed)
## 10. Complete a Todo
## 10. Edit a Todo
Change the due date and priority of the test todo from step 8.
```bash
# Edit due date
$SKILL_DIR/scripts/calendar.sh todo edit --match "Test Todo" --due "$(date -d '+5 days' +%Y-%m-%d)"
# Verify change
$SKILL_DIR/scripts/calendar.sh todo list
```
**Verify:**
- [ ] Script exits without error
- [ ] Output shows "Updated todo: Test Todo" with the change
- [ ] `todo list` shows the new due date
- [ ] `vdirsyncer sync` ran
```bash
# Edit priority
$SKILL_DIR/scripts/calendar.sh todo edit --match "Test Todo" --priority high
# Verify change
$SKILL_DIR/scripts/calendar.sh todo list
```
**Verify:**
- [ ] Priority changed to high
- [ ] Todo appears under the high priority group in formatted output
```bash
# Edit multiple fields at once
$SKILL_DIR/scripts/calendar.sh todo edit --match "Test Todo" --due "$TEST_DATE" --priority low
```
**Verify:**
- [ ] Both due date and priority updated in one command
```bash
# Error: no matching todo
$SKILL_DIR/scripts/calendar.sh todo edit --match "nonexistent" --due "$TEST_DATE"
# Should print error and exit non-zero
# Error: no fields to edit
$SKILL_DIR/scripts/calendar.sh todo edit --match "Test Todo"
# Should print "Nothing to change" message
```
## 11. Complete a Todo
```bash
$SKILL_DIR/scripts/calendar.sh todo complete --match "Test Todo"
@@ -200,7 +248,7 @@ $SKILL_DIR/scripts/calendar.sh todo complete --match "Test Todo"
- [ ] `$SKILL_DIR/scripts/calendar.sh todo list --all` — appears as completed (with checkmark)
- [ ] `vdirsyncer sync` ran
## 11. Delete a Todo
## 12. Delete a Todo
Create a second test todo, then delete it.
@@ -223,7 +271,7 @@ $SKILL_DIR/scripts/calendar.sh todo delete --match "Delete Me"
- [ ] `todo list` (todoman) does not show "Delete Me Todo"
- [ ] `vdirsyncer sync` ran
## 12. Todo Check (Cron Output)
## 13. Todo Check (Cron Output)
```bash
# Create a test todo
@@ -245,7 +293,7 @@ $SKILL_DIR/scripts/calendar.sh todo check
# Should produce no output
```
## 13. Regression: Existing Invite Commands
## 14. Regression: Existing Invite Commands
Verify the rename didn't break VEVENT flow.

View File

@@ -10,6 +10,7 @@ Subcommands:
python calendar.py reply [options] # accept/decline/tentative
python calendar.py todo add [options] # create a VTODO task
python calendar.py todo list [options] # list pending tasks
python calendar.py todo edit [options] # edit a task's fields
python calendar.py todo complete [options] # mark task as done
python calendar.py todo delete [options] # remove a task
python calendar.py todo check # daily digest for cron
@@ -600,6 +601,58 @@ def cmd_todo_complete(args):
_sync_calendar()
def _find_todo(uid="", match=""):
"""Find a single todo by UID or summary match. Returns (todoman_id, todo_dict)."""
todos = _todoman_list_json("--sort", "due")
if uid:
matches = [t for t in todos if uid in (t.get("uid") or "")]
if not matches:
print(f"Error: No todo with UID '{uid}'", file=sys.stderr)
sys.exit(1)
elif match:
matches = [t for t in todos if match in (t.get("summary") or "")]
if not matches:
print(f"Error: No todo matching '{match}'", file=sys.stderr)
sys.exit(1)
if len(matches) > 1:
print(f"Error: Multiple todos match '{match}':", file=sys.stderr)
for t in matches:
print(f" - {t.get('summary')} (uid: {t.get('uid')})", file=sys.stderr)
sys.exit(1)
else:
print("Error: --uid or --match is required", file=sys.stderr)
sys.exit(1)
return matches[0]["id"], matches[0]
def cmd_todo_edit(args):
"""Edit a todo's fields via todoman."""
todo_id, matched = _find_todo(uid=args.uid, match=args.match)
# Build todoman edit command args
todo_args = []
changes = []
if args.due:
todo_args += ["--due", args.due]
changes.append(f"due -> {args.due}")
if args.priority:
todo_args += ["--priority", args.priority]
prio_label = PRIORITY_LABELS.get(PRIORITY_MAP.get(args.priority, 5), "")
changes.append(f"priority -> {prio_label}")
if not changes:
print("Nothing to change. Specify at least one of --due, --priority.")
return
# Run todoman edit (non-interactive)
_run_todoman("edit", str(todo_id), "--no-interactive", *todo_args)
print(f"Updated todo: {matched.get('summary')}")
for c in changes:
print(f" {c}")
_sync_calendar()
def cmd_todo_delete(args):
"""Delete a todo via todoman."""
if args.uid:
@@ -688,6 +741,13 @@ def main():
comp_p.add_argument("--uid", default="", help="Todo UID")
comp_p.add_argument("--match", default="", help="Fuzzy match on summary")
# todo edit
edit_p = todo_sub.add_parser("edit", help="Edit a todo's fields")
edit_p.add_argument("--uid", default="", help="Todo UID")
edit_p.add_argument("--match", default="", help="Fuzzy match on summary")
edit_p.add_argument("--due", default="", help="New due date (YYYY-MM-DD)")
edit_p.add_argument("--priority", default="", choices=["", "high", "medium", "low"], help="New priority")
# todo delete
del_p = todo_sub.add_parser("delete", help="Delete a todo")
del_p.add_argument("--uid", default="", help="Todo UID")
@@ -709,6 +769,8 @@ def main():
cmd_todo_list(args)
elif args.todo_command == "complete":
cmd_todo_complete(args)
elif args.todo_command == "edit":
cmd_todo_edit(args)
elif args.todo_command == "delete":
cmd_todo_delete(args)
elif args.todo_command == "check":

View File

@@ -6,6 +6,7 @@
# ./calendar.sh reply [options] # accept/decline/tentative
# ./calendar.sh todo add [options] # create a todo
# ./calendar.sh todo list [options] # list pending todos
# ./calendar.sh todo edit [options] # edit a todo's fields
# ./calendar.sh todo complete [options] # mark todo as done
# ./calendar.sh todo delete [options] # remove a todo
# ./calendar.sh todo check # daily digest for cron