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:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user