mirror of
https://github.com/LeoYeAI/openclaw-master-skills.git
synced 2026-07-27 22:15:43 +00:00
feat(v0.5.0): weekly update 2026-03-16 — 48 new skills (total 387)
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"registry": "https://clawhub.ai",
|
||||
"slug": "openclaw-todoist",
|
||||
"installedVersion": "1.2.0",
|
||||
"installedAt": 1773626662009
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
name: todoist
|
||||
description: "Todoist task management for OpenClaw. Unified todo API with multi-agent identity, scheduled checks and reminders."
|
||||
metadata:
|
||||
openclaw:
|
||||
emoji: "✅"
|
||||
requires: {}
|
||||
---
|
||||
|
||||
# Todoist Skill
|
||||
|
||||
为 OpenClaw 提供统一的待办管理能力,支持多 Agent 身份识别。
|
||||
|
||||
## 身份系统
|
||||
|
||||
每个 OpenClaw 实例有唯一 ID,每个 Agent 有独立标签:
|
||||
|
||||
```
|
||||
实例 ID: 8259c9d1 (自动生成)
|
||||
Agent 标签: agent-8259c9d1-main
|
||||
```
|
||||
|
||||
## 命令
|
||||
|
||||
| 命令 | 说明 |
|
||||
|------|------|
|
||||
| `list [filter]` | 列出任务 (today/personal/agent/overdue) |
|
||||
| `add <内容> [type] [日期]` | 添加任务 |
|
||||
| `subtask <父任务> <内容>` | 添加子任务 |
|
||||
| `show <关键词>` | 查看任务详情 |
|
||||
| `update <任务> <字段> <值>` | 更新任务 |
|
||||
| `claim <任务>` | 认领任务 |
|
||||
| `complete <任务>` | 完成任务 |
|
||||
| `delete <任务>` | 删除任务 |
|
||||
| `projects` | 列出项目 |
|
||||
| `labels` | 列出标签 |
|
||||
|
||||
## 配置
|
||||
|
||||
| 命令 | 说明 |
|
||||
|------|------|
|
||||
| `show` | 显示配置 |
|
||||
| `set-time HH:MM` | 设置每日提醒时间 |
|
||||
| `set-interval N` | 设置心跳检查间隔(小时) |
|
||||
| `set-agent <name>` | 切换当前 Agent |
|
||||
| `add-agent <name>` | 添加新 Agent |
|
||||
|
||||
## 🔄 自动同步任务到 TASK.md
|
||||
|
||||
心跳时会自动同步 Todoist 任务到 `~/.openclaw/workspace/TASK.md`:
|
||||
|
||||
```bash
|
||||
~/.openclaw/workspace/skills/openclaw-todoist/scripts/sync-to-task.sh
|
||||
```
|
||||
|
||||
生成的 TASK.md 格式:
|
||||
```markdown
|
||||
# 当前任务
|
||||
|
||||
_自动同步自 Todoist (2026-03-16 10:00)_
|
||||
|
||||
## ⚠️ 逾期任务
|
||||
- [ ] 任务名 (逾期: 2026-03-15)
|
||||
|
||||
## 📅 今日任务
|
||||
- [ ] 任务名
|
||||
|
||||
## 📌 待办(无日期)
|
||||
- [ ] 任务名
|
||||
```
|
||||
|
||||
### 心跳配置
|
||||
|
||||
在 `HEARTBEAT.md` 中添加:
|
||||
|
||||
```markdown
|
||||
# 心跳任务
|
||||
|
||||
## 每次心跳自动执行
|
||||
|
||||
1. **同步 Todoist 任务到 TASK.md**
|
||||
```bash
|
||||
~/.openclaw/workspace/skills/openclaw-todoist/scripts/sync-to-task.sh
|
||||
```
|
||||
|
||||
## 静默条件
|
||||
- 无任务时回复 HEARTBEAT_OK
|
||||
- 有逾期任务时主动提醒
|
||||
```
|
||||
|
||||
### 一键配置
|
||||
|
||||
```bash
|
||||
~/.openclaw/workspace/skills/openclaw-todoist/scripts/setup-heartbeat.sh
|
||||
```
|
||||
|
||||
### 提醒逻辑
|
||||
|
||||
- ✅ 自动同步所有任务到 TASK.md
|
||||
- ⚠️ **仅逾期任务**时主动提醒用户
|
||||
- 无任务或无逾期 → 静默(HEARTBEAT_OK)
|
||||
|
||||
## 发布内容
|
||||
|
||||
```
|
||||
skills/todoist/
|
||||
├── SKILL.md
|
||||
└── todoist.sh
|
||||
|
||||
scripts/
|
||||
├── agent-config.sh
|
||||
└── heartbeat-tasks.sh
|
||||
```
|
||||
|
||||
## 用户配置文件(不包含在发布中)
|
||||
|
||||
```
|
||||
~/.openclaw/workspace/
|
||||
├── .todoist-token # 用户 API token
|
||||
└── .agent-identity.json # 用户身份配置
|
||||
```
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"ownerId": "kn7ehs23ek43b5tw6yt3hy35rh82w875",
|
||||
"slug": "openclaw-todoist",
|
||||
"version": "1.2.0",
|
||||
"publishedAt": 1773626429583
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
#!/bin/bash
|
||||
# Agent Identity Configuration Tool
|
||||
|
||||
IDENTITY_FILE="$HOME/.openclaw/workspace/.agent-identity.json"
|
||||
|
||||
# Ensure file exists
|
||||
if [ ! -f "$IDENTITY_FILE" ]; then
|
||||
INSTANCE_ID=$(hostname | shasum -a 256 | cut -c1-8)
|
||||
cat > "$IDENTITY_FILE" << EOF
|
||||
{
|
||||
"instance_id": "$INSTANCE_ID",
|
||||
"instance_name": "$(hostname)",
|
||||
"user": "$(whoami)",
|
||||
"current_agent": "main",
|
||||
"todoist": {
|
||||
"daily_reminder_time": "09:00",
|
||||
"heartbeat_check_interval_hours": 4
|
||||
},
|
||||
"agents": {
|
||||
"main": {
|
||||
"name": "main",
|
||||
"full_id": "$INSTANCE_ID:main",
|
||||
"todoist_label": "agent-$INSTANCE_ID-main"
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
echo "✅ 已创建身份配置: $IDENTITY_FILE"
|
||||
fi
|
||||
|
||||
show_config() {
|
||||
echo "📋 当前配置:"
|
||||
echo ""
|
||||
cat "$IDENTITY_FILE" | jq -C '.'
|
||||
}
|
||||
|
||||
set_reminder_time() {
|
||||
local time="$1"
|
||||
if [[ ! "$time" =~ ^[0-2][0-9]:[0-5][0-9]$ ]]; then
|
||||
echo "❌ 时间格式错误,应为 HH:MM (如 09:00)"
|
||||
exit 1
|
||||
fi
|
||||
cat "$IDENTITY_FILE" | jq ".todoist.daily_reminder_time = \"$time\"" > /tmp/identity.tmp
|
||||
mv /tmp/identity.tmp "$IDENTITY_FILE"
|
||||
echo "✅ 每日提醒时间已设置为: $time"
|
||||
}
|
||||
|
||||
set_heartbeat_interval() {
|
||||
local hours="$1"
|
||||
if [[ ! "$hours" =~ ^[0-9]+$ ]]; then
|
||||
echo "❌ 间隔应为小时数 (如 4)"
|
||||
exit 1
|
||||
fi
|
||||
cat "$IDENTITY_FILE" | jq ".todoist.heartbeat_check_interval_hours = $hours" > /tmp/identity.tmp
|
||||
mv /tmp/identity.tmp "$IDENTITY_FILE"
|
||||
echo "✅ 心跳检查间隔已设置为: ${hours} 小时"
|
||||
}
|
||||
|
||||
set_current_agent() {
|
||||
local agent="$1"
|
||||
# Check if agent exists
|
||||
if ! cat "$IDENTITY_FILE" | jq -e ".agents.$agent" > /dev/null 2>&1; then
|
||||
echo "❌ Agent 不存在: $agent"
|
||||
echo "可用 agents: $(cat "$IDENTITY_FILE" | jq -r '.agents | keys[]' | tr '\n' ' ')"
|
||||
exit 1
|
||||
fi
|
||||
cat "$IDENTITY_FILE" | jq ".current_agent = \"$agent\"" > /tmp/identity.tmp
|
||||
mv /tmp/identity.tmp "$IDENTITY_FILE"
|
||||
echo "✅ 当前 Agent 已切换为: $agent"
|
||||
}
|
||||
|
||||
add_agent() {
|
||||
local name="$1"
|
||||
local instance_id=$(cat "$IDENTITY_FILE" | jq -r '.instance_id')
|
||||
local label="agent-$instance_id-$name"
|
||||
|
||||
cat "$IDENTITY_FILE" | jq ".agents.$name = {\"name\": \"$name\", \"full_id\": \"$instance_id:$name\", \"todoist_label\": \"$label\"}" > /tmp/identity.tmp
|
||||
mv /tmp/identity.tmp "$IDENTITY_FILE"
|
||||
echo "✅ 已添加 Agent: $name (标签: $label)"
|
||||
|
||||
# Create label in Todoist
|
||||
TOKEN=$(cat ~/.openclaw/workspace/.todoist-token 2>/dev/null)
|
||||
if [ -n "$TOKEN" ]; then
|
||||
curl -s -X POST "https://api.todoist.com/api/v1/labels" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"name\": \"$label\"}" > /dev/null 2>&1
|
||||
echo " 已在 Todoist 创建标签"
|
||||
fi
|
||||
}
|
||||
|
||||
case "${1:-show}" in
|
||||
show|config)
|
||||
show_config
|
||||
;;
|
||||
set-time)
|
||||
set_reminder_time "$2"
|
||||
;;
|
||||
set-interval)
|
||||
set_heartbeat_interval "$2"
|
||||
;;
|
||||
set-agent)
|
||||
set_current_agent "$2"
|
||||
;;
|
||||
add-agent)
|
||||
add_agent "$2"
|
||||
;;
|
||||
*)
|
||||
echo "用法: agent-config.sh <command> [args]"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " show 显示当前配置"
|
||||
echo " set-time HH:MM 设置每日提醒时间"
|
||||
echo " set-interval N 设置心跳检查间隔(小时)"
|
||||
echo " set-agent <name> 切换当前 Agent"
|
||||
echo " add-agent <name> 添加新 Agent"
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/bin/bash
|
||||
# Heartbeat task check - runs periodically
|
||||
|
||||
IDENTITY_FILE="$HOME/.openclaw/workspace/.agent-identity.json"
|
||||
TOKEN_FILE="$HOME/.openclaw/workspace/.todoist-token"
|
||||
LOG_FILE="$HOME/.openclaw/workspace/memory/heartbeat-tasks.log"
|
||||
|
||||
log() {
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Check if enabled
|
||||
if [ ! -f "$TOKEN_FILE" ]; then
|
||||
log "⚠️ Todoist token not found"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
TOKEN=$(cat "$TOKEN_FILE")
|
||||
TODAY=$(date +%Y-%m-%d)
|
||||
|
||||
# Get identity
|
||||
INSTANCE_ID=$(cat "$IDENTITY_FILE" | jq -r '.instance_id')
|
||||
CURRENT_AGENT=$(cat "$IDENTITY_FILE" | jq -r '.current_agent')
|
||||
AGENT_LABEL=$(cat "$IDENTITY_FILE" | jq -r ".agents.$CURRENT_AGENT.todoist_label")
|
||||
|
||||
log "🔍 检查任务 (实例: $INSTANCE_ID, Agent: $CURRENT_AGENT)"
|
||||
|
||||
# Get tasks due today
|
||||
TODAY_TASKS=$(curl -s "https://api.todoist.com/api/v1/tasks" \
|
||||
-H "Authorization: Bearer $TOKEN" | \
|
||||
jq -r ".results[] | select(.due.date == \"$TODAY\") | .content")
|
||||
|
||||
if [ -n "$TODAY_TASKS" ]; then
|
||||
log "📅 今日任务:"
|
||||
echo "$TODAY_TASKS" | while read task; do
|
||||
log " ⬜ $task"
|
||||
done
|
||||
else
|
||||
log "✅ 今日无待办任务"
|
||||
fi
|
||||
|
||||
# Get agent-specific tasks
|
||||
AGENT_TASKS=$(curl -s "https://api.todoist.com/api/v1/tasks" \
|
||||
-H "Authorization: Bearer $TOKEN" | \
|
||||
jq -r ".results[] | select(.labels | index(\"$AGENT_LABEL\")) | .content")
|
||||
|
||||
if [ -n "$AGENT_TASKS" ]; then
|
||||
log ""
|
||||
log "🤖 Agent 任务 ($CURRENT_AGENT):"
|
||||
echo "$AGENT_TASKS" | while read task; do
|
||||
log " ⬜ $task"
|
||||
done
|
||||
fi
|
||||
|
||||
# Get overdue tasks
|
||||
OVERDUE=$(curl -s "https://api.todoist.com/api/v1/tasks" \
|
||||
-H "Authorization: Bearer $TOKEN" | \
|
||||
jq -r ".results[] | select(.due.date < \"$TODAY\") | .content")
|
||||
|
||||
if [ -n "$OVERDUE" ]; then
|
||||
log ""
|
||||
log "⚠️ 逾期任务:"
|
||||
echo "$OVERDUE" | while read task; do
|
||||
log " 🔴 $task"
|
||||
done
|
||||
fi
|
||||
@@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
# Setup Todoist heartbeat checks in HEARTBEAT.md
|
||||
|
||||
HEARTBEAT_FILE="$HOME/.openclaw/workspace/HEARTBEAT.md"
|
||||
TODOIST_CHECK='~/.openclaw/workspace/skills/todoist/todoist.sh'
|
||||
|
||||
# Check if already configured
|
||||
if grep -q "todoist.sh list" "$HEARTBEAT_FILE" 2>/dev/null; then
|
||||
echo "✅ Todoist 心跳检查已配置"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create or append to HEARTBEAT.md
|
||||
if [ ! -f "$HEARTBEAT_FILE" ]; then
|
||||
cat > "$HEARTBEAT_FILE" << 'EOF'
|
||||
# 心跳任务
|
||||
|
||||
## 每次心跳检查
|
||||
|
||||
1. **Todoist 任务**
|
||||
- 检查今日任务
|
||||
- 检查过期任务
|
||||
- 有紧急事项时提醒用户
|
||||
|
||||
```bash
|
||||
~/.openclaw/workspace/skills/todoist/todoist.sh list today
|
||||
~/.openclaw/workspace/skills/todoist/todoist.sh list overdue
|
||||
```
|
||||
|
||||
## 静默条件
|
||||
- 无任务时回复 HEARTBEAT_OK
|
||||
- 有过期任务或重要截止日期时主动提醒
|
||||
EOF
|
||||
echo "✅ 已创建 HEARTBEAT.md 并配置 Todoist 心跳检查"
|
||||
else
|
||||
# Append to existing file
|
||||
cat >> "$HEARTBEAT_FILE" << 'EOF'
|
||||
|
||||
## Todoist 任务检查
|
||||
|
||||
```bash
|
||||
~/.openclaw/workspace/skills/todoist/todoist.sh list today
|
||||
~/.openclaw/workspace/skills/todoist/todoist.sh list overdue
|
||||
```
|
||||
|
||||
有紧急事项时主动提醒,否则静默。
|
||||
EOF
|
||||
echo "✅ 已添加 Todoist 心跳检查到现有 HEARTBEAT.md"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📌 下次心跳时会自动检查 Todoist 任务"
|
||||
@@ -0,0 +1,79 @@
|
||||
#!/bin/bash
|
||||
# Sync Todoist tasks to TASK.md
|
||||
# Called by heartbeat to keep tasks in sync
|
||||
|
||||
set -e
|
||||
|
||||
TASK_FILE="$HOME/.openclaw/workspace/TASK.md"
|
||||
TODOIST_SCRIPT="$HOME/.openclaw/workspace/skills/openclaw-todoist/todoist.sh"
|
||||
TOKEN_FILE="$HOME/.openclaw/workspace/.todoist-token"
|
||||
|
||||
# Skip if Todoist not configured
|
||||
[ ! -f "$TOKEN_FILE" ] && exit 0
|
||||
|
||||
# Get tasks from Todoist API
|
||||
TOKEN=$(cat "$TOKEN_FILE")
|
||||
API_BASE="https://api.todoist.com/api/v1"
|
||||
|
||||
# Fetch today's tasks and overdue tasks
|
||||
today=$(date +%Y-%m-%d)
|
||||
all_tasks=$(curl -s "$API_BASE/tasks" -H "Authorization: Bearer $TOKEN")
|
||||
|
||||
today_tasks=$(echo "$all_tasks" | jq -r ".results[] | select(.due.date == \"$today\") | .content" 2>/dev/null || true)
|
||||
overdue_tasks=$(echo "$all_tasks" | jq -r ".results[] | select(.due.date < \"$today\" and .due.date != null) | \"\(.content) (逾期: \(.due.date))\"" 2>/dev/null || true)
|
||||
no_due_tasks=$(echo "$all_tasks" | jq -r ".results[] | select(.due.date == null) | .content" 2>/dev/null || true)
|
||||
|
||||
# Check if we have any tasks
|
||||
has_today=$(echo "$today_tasks" | grep -v '^$' | head -1 || true)
|
||||
has_overdue=$(echo "$overdue_tasks" | grep -v '^$' | head -1 || true)
|
||||
has_nodue=$(echo "$no_due_tasks" | grep -v '^$' | head -1 || true)
|
||||
|
||||
# No tasks at all - remove TASK.md if exists
|
||||
if [ -z "$has_today" ] && [ -z "$has_overdue" ] && [ -z "$has_nodue" ]; then
|
||||
[ -f "$TASK_FILE" ] && rm "$TASK_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Build TASK.md content
|
||||
{
|
||||
echo "# 当前任务"
|
||||
echo ""
|
||||
echo "_自动同步自 Todoist ($(date '+%Y-%m-%d %H:%M'))_"
|
||||
echo ""
|
||||
|
||||
if [ -n "$has_overdue" ]; then
|
||||
echo "## ⚠️ 逾期任务"
|
||||
echo ""
|
||||
echo "$overdue_tasks" | while read -r line; do
|
||||
[ -n "$line" ] && echo "- [ ] $line"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ -n "$has_today" ]; then
|
||||
echo "## 📅 今日任务"
|
||||
echo ""
|
||||
echo "$today_tasks" | while read -r line; do
|
||||
[ -n "$line" ] && echo "- [ ] $line"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ -n "$has_nodue" ]; then
|
||||
echo "## 📌 待办(无日期)"
|
||||
echo ""
|
||||
echo "$no_due_tasks" | while read -r line; do
|
||||
[ -n "$line" ] && echo "- [ ] $line"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "---"
|
||||
echo "完成或修改任务请使用 Todoist 命令或 App"
|
||||
} > "$TASK_FILE"
|
||||
|
||||
# Return status for heartbeat
|
||||
if [ -n "$has_overdue" ]; then
|
||||
echo "⚠️ 有 $(echo "$overdue_tasks" | grep -v '^$' | wc -l | tr -d ' ') 个逾期任务"
|
||||
exit 0
|
||||
fi
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "todoist",
|
||||
"version": "1.0.0",
|
||||
"description": "Todoist task management for OpenClaw with multi-agent identity support",
|
||||
"author": "kings0527",
|
||||
"license": "MIT"
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
#!/bin/bash
|
||||
# Todoist CLI wrapper for OpenClaw
|
||||
|
||||
set -e
|
||||
|
||||
TOKEN_FILE="$HOME/.openclaw/workspace/.todoist-token"
|
||||
IDENTITY_FILE="$HOME/.openclaw/workspace/.agent-identity.json"
|
||||
API_BASE="https://api.todoist.com/api/v1"
|
||||
|
||||
# Load token
|
||||
if [ ! -f "$TOKEN_FILE" ]; then
|
||||
echo "Token not found: $TOKEN_FILE"
|
||||
exit 1
|
||||
fi
|
||||
TOKEN=$(cat "$TOKEN_FILE")
|
||||
|
||||
# Load identity
|
||||
load_identity() {
|
||||
if [ -f "$IDENTITY_FILE" ]; then
|
||||
INSTANCE_ID=$(jq -r .instance_id "$IDENTITY_FILE")
|
||||
CURRENT_AGENT=$(jq -r .current_agent "$IDENTITY_FILE")
|
||||
AGENT_LABEL=$(jq -r ".agents.$CURRENT_AGENT.todoist_label" "$IDENTITY_FILE")
|
||||
else
|
||||
INSTANCE_ID=$(hostname | shasum -a 256 | cut -c1-8)
|
||||
CURRENT_AGENT="main"
|
||||
AGENT_LABEL="agent-$INSTANCE_ID-main"
|
||||
fi
|
||||
}
|
||||
|
||||
# API helpers
|
||||
api_get() { curl -s "$API_BASE/$1" -H "Authorization: Bearer $TOKEN"; }
|
||||
api_post() { curl -s -X POST "$API_BASE/$1" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$2"; }
|
||||
|
||||
get_task_id() {
|
||||
api_get "tasks" | jq -r ".results[] | select(.content | test(\"$1\"; \"i\")) | .id" | head -1
|
||||
}
|
||||
|
||||
get_project_id() {
|
||||
api_get "projects" | jq -r ".results[] | select(.name | contains(\"$1\")) | .id" | head -1
|
||||
}
|
||||
|
||||
# Commands
|
||||
cmd_list() {
|
||||
local filter="${1:-all}"
|
||||
load_identity
|
||||
echo "Tasks (Instance: $INSTANCE_ID, Agent: $CURRENT_AGENT)"
|
||||
echo ""
|
||||
|
||||
local tasks=$(api_get "tasks")
|
||||
local today=$(date +%Y-%m-%d)
|
||||
|
||||
case "$filter" in
|
||||
today)
|
||||
echo "Today:"
|
||||
echo "$tasks" | jq -r ".results[] | select(.due.date == \"$today\") | \" [ ] \(.content)\""
|
||||
;;
|
||||
overdue)
|
||||
echo "Overdue:"
|
||||
echo "$tasks" | jq -r ".results[] | select(.due.date < \"$today\") | \" [!] \(.content) (\(.due.date))\""
|
||||
;;
|
||||
personal)
|
||||
local pid=$(get_project_id "个人事务")
|
||||
echo "Personal:"
|
||||
echo "$tasks" | jq -r ".results[] | select(.project_id == \"$pid\") | \" [ ] \(.content)\""
|
||||
;;
|
||||
agent)
|
||||
echo "Agent ($CURRENT_AGENT):"
|
||||
echo "$tasks" | jq -r ".results[] | select(.labels | index(\"$AGENT_LABEL\")) | \" [ ] \(.content)\""
|
||||
;;
|
||||
*)
|
||||
local pid=$(get_project_id "个人事务")
|
||||
echo "Personal:"
|
||||
echo "$tasks" | jq -r ".results[] | select(.project_id == \"$pid\") | \" [ ] \(.content)\""
|
||||
echo ""
|
||||
echo "Agent ($CURRENT_AGENT):"
|
||||
echo "$tasks" | jq -r ".results[] | select(.labels | index(\"$AGENT_LABEL\")) | \" [ ] \(.content)\""
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
cmd_add() {
|
||||
local content="$1"
|
||||
local type="${2:-personal}"
|
||||
local due="${3:-}"
|
||||
load_identity
|
||||
|
||||
local pid
|
||||
local labels="[]"
|
||||
|
||||
if [ "$type" = "agent" ]; then
|
||||
pid=$(get_project_id "Agent 任务")
|
||||
labels="[\"$AGENT_LABEL\"]"
|
||||
echo "Adding Agent task [$CURRENT_AGENT]: $content"
|
||||
else
|
||||
pid=$(get_project_id "个人事务")
|
||||
echo "Adding personal task: $content"
|
||||
fi
|
||||
|
||||
local payload="{\"content\":\"$content\",\"project_id\":\"$pid\",\"labels\":$labels"
|
||||
[ -n "$due" ] && payload="$payload,\"due_string\":\"$due\""
|
||||
payload="$payload}"
|
||||
|
||||
api_post "tasks" "$payload" | jq -r '.content // "Added"'
|
||||
}
|
||||
|
||||
cmd_subtask() {
|
||||
local parent="$1"
|
||||
local content="$2"
|
||||
local pid=$(get_task_id "$parent")
|
||||
[ -z "$pid" ] && { echo "Parent not found: $parent"; exit 1; }
|
||||
echo "Adding subtask to: $parent"
|
||||
api_post "tasks" "{\"content\":\"$content\",\"parent_id\":\"$pid\"}" | jq -r '.content // "Added"'
|
||||
}
|
||||
|
||||
cmd_show() {
|
||||
local q="$1"
|
||||
local id=$(get_task_id "$q")
|
||||
[ -z "$id" ] && { echo "Task not found: $q"; exit 1; }
|
||||
local t=$(api_get "tasks" | jq -r ".results[] | select(.id == \"$id\")")
|
||||
echo "Task: $(echo "$t" | jq -r .content)"
|
||||
echo "Due: $(echo "$t" | jq -r '.due.string // "none"')"
|
||||
echo "Labels: $(echo "$t" | jq -r '.labels | join(", ") // "none"')"
|
||||
echo ""
|
||||
echo "Subtasks:"
|
||||
api_get "tasks" | jq -r ".results[] | select(.parent_id == \"$id\") | \" - \(.content)\""
|
||||
}
|
||||
|
||||
cmd_update() {
|
||||
local q="$1"
|
||||
local field="$2"
|
||||
local val="$3"
|
||||
local id=$(get_task_id "$q")
|
||||
[ -z "$id" ] && { echo "Task not found: $q"; exit 1; }
|
||||
|
||||
local payload
|
||||
case "$field" in
|
||||
date|due) payload="{\"due_string\":\"$val\"}" ;;
|
||||
content) payload="{\"content\":\"$val\"}" ;;
|
||||
priority) payload="{\"priority\":$val}" ;;
|
||||
*) echo "Unknown field: $field"; exit 1 ;;
|
||||
esac
|
||||
|
||||
curl -s -X POST "$API_BASE/tasks/$id" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$payload" > /dev/null
|
||||
echo "Updated: $q ($field = $val)"
|
||||
}
|
||||
|
||||
cmd_claim() {
|
||||
local q="$1"
|
||||
load_identity
|
||||
local id=$(get_task_id "$q")
|
||||
[ -z "$id" ] && { echo "Task not found: $q"; exit 1; }
|
||||
local t=$(api_get "tasks" | jq -r ".results[] | select(.id == \"$id\")")
|
||||
local lbls=$(echo "$t" | jq -r '.labels')
|
||||
local new=$(echo "[$lbls, \"$AGENT_LABEL\"]" | jq -s 'add | unique')
|
||||
curl -s -X POST "$API_BASE/tasks/$id" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "{\"labels\":$new}" > /dev/null
|
||||
echo "Claimed: $(echo "$t" | jq -r .content) -> $CURRENT_AGENT"
|
||||
}
|
||||
|
||||
cmd_complete() {
|
||||
local q="$1"
|
||||
local id=$(get_task_id "$q")
|
||||
[ -z "$id" ] && { echo "Task not found: $q"; exit 1; }
|
||||
local name=$(api_get "tasks" | jq -r ".results[] | select(.id == \"$id\") | .content")
|
||||
api_post "tasks/$id/close" "{}" > /dev/null
|
||||
echo "Completed: $name"
|
||||
}
|
||||
|
||||
cmd_delete() {
|
||||
local q="$1"
|
||||
local id=$(get_task_id "$q")
|
||||
[ -z "$id" ] && { echo "Task not found: $q"; exit 1; }
|
||||
local name=$(api_get "tasks" | jq -r ".results[] | select(.id == \"$id\") | .content")
|
||||
curl -s -X DELETE "$API_BASE/tasks/$id" -H "Authorization: Bearer $TOKEN" > /dev/null
|
||||
echo "Deleted: $name"
|
||||
}
|
||||
|
||||
cmd_projects() { api_get "projects" | jq -r '.results[] | " \(.name)"'; }
|
||||
cmd_labels() { api_get "labels" | jq -r '.results[] | " \(.name)"'; }
|
||||
cmd_config() { jq -C . "$IDENTITY_FILE"; }
|
||||
|
||||
# Main
|
||||
case "${1:-help}" in
|
||||
list|ls) cmd_list "$2" ;;
|
||||
add) cmd_add "$2" "$3" "$4" ;;
|
||||
subtask) cmd_subtask "$2" "$3" ;;
|
||||
show) cmd_show "$2" ;;
|
||||
update) cmd_update "$2" "$3" "$4" ;;
|
||||
claim) cmd_claim "$2" ;;
|
||||
complete|done) cmd_complete "$2" ;;
|
||||
delete|rm) cmd_delete "$2" ;;
|
||||
projects) cmd_projects ;;
|
||||
labels) cmd_labels ;;
|
||||
config) cmd_config ;;
|
||||
*)
|
||||
echo "Todoist CLI"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " list [today|personal|agent|overdue] List tasks"
|
||||
echo " add <content> [type] [due] Add task"
|
||||
echo " subtask <parent> <content> Add subtask"
|
||||
echo " show <keyword> Show task details"
|
||||
echo " update <task> <field> <value> Update task"
|
||||
echo " claim <task> Claim task for current agent"
|
||||
echo " complete <task> Complete task"
|
||||
echo " delete <task> Delete task"
|
||||
echo " projects List projects"
|
||||
echo " labels List labels"
|
||||
echo " config Show config"
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user