# dsh-ticktick

> [**English**](README.md) | **中文**

DeepSeek Harness 的滴答清单（[TickTick](https://ticktick.com) / [Dida365](https://dida365.com)）双向任务同步插件，基于官方 OAuth 2.0 Open API：拉取各清单任务、创建 / 更新 / 完成 / 删除任务、一键去重同步——agent 与 Web 设置面板均可使用。

## 功能

- **官方 Open API** — 基于滴答清单开放平台（`/open/v1`）的 OAuth 2.0 授权码流程，401 时自动用 refresh_token 刷新。
- **双区域** — Dida365（国内，默认）与 TickTick（国际版）可选，设置面板或 `ticktick_config` 均可切换。
- **拉取** — `ticktick_tasks` / `ticktick_sync` 汇总各清单未完成（或已完成）任务，按截止时间排序，带清单名；**包含收集箱**（开放 API 的清单列表不返回收集箱，插件按 `inbox` 固定处理）。
- **推送** — `ticktick_add` 创建单个或多个任务（标题、按 id 或名称指定清单——`inbox` / `收集箱` 都会落到收集箱、ISO 8601 或纯日期截止时间、优先级 0-5 或 none/low/medium/high、标签、备注）。
- **一键同步** — `ticktick_sync` 的 `direction=pull`（按清单分组汇总，含收集箱）或 `direction=push`（按清单内标题去重创建，收集箱同样去重，重复执行不会产生副本）。
- **维护** — `ticktick_update`、`ticktick_complete`、`ticktick_delete`（清单 id 可省略，自动查找，含收集箱）。
- **设置面板** — 设置 → TickTick：配置凭据、发起授权（弹窗 + 手动粘贴 code）、刷新令牌、快捷添加任务（清单下拉置顶收集箱，已归档清单不展示）、就地完成今日任务。
- 凭据与令牌持久化到 `~/.dsh/dsh-ticktick.json`（权限 0600）；`ticktick_status` 不回显任何密钥。
- 系统提示中公告插件，agent 知道何时使用。

## 安装

```sh
# 发布到 GitHub 后（仓库打上 `dsh-plugin` topic）
dsh plugin --profile web add github:zhengjy01/dsh-ticktick

# 本地开发
dsh plugin --profile web add link:/path/to/dsh-ticktick
```

重启 `dsh web`。插件无需构建步骤——`lib/index.js` 是纯 ESM。

## 配置

1. 在开放平台创建应用：<https://developer.dida365.com/docs#/openapi>（国内）或 <https://developer.ticktick.com/manage/>（国际版），并注册回调地址：
   `http://127.0.0.1:3080/api/dsh-ticktick/oauth/callback`
   （按你实际的 `dsh web` 端口填写，或自定义 `redirectUri`——必须与注册的完全一致。）
2. 把 `client_id` / `client_secret` 交给插件，可在设置面板（设置 → TickTick）填写，或直接让 agent 配置：

   ```text
   帮我配置滴答清单，client_id 是 xxx，client_secret 是 yyy，区域用国内版 Dida365
   ```

   agent 会调用 `ticktick_config` 持久化凭据。
3. 授权：在面板点「开始授权」（或 `ticktick_oauth_start`）并登录。回调会自动完成；若未自动完成，把 code 粘贴回来并调用 `ticktick_oauth_finish`。

之后即可：

```text
把今天滴答清单里没做完的任务同步给我          → ticktick_sync (pull)
帮我把这些任务同步到滴答清单：买牛奶、写周报   → ticktick_sync (push, 去重)
明天下午3点提醒我开会，加到「工作」清单       → ticktick_add
```

> `client_secret` 与 OAuth 令牌都是凭据：持有者可以读取和修改你的任务。它们存放在 `~/.dsh/dsh-ticktick.json`（权限 0600）；如泄露可用 `ticktick_config(reset: true)` 清除。

## 工具一览

| 工具 | 用途 |
| --- | --- |
| `ticktick_status` | 连接与授权状态 |
| `ticktick_config` | 设置 / 清除 `clientId`、`clientSecret`、`region`（`cn`/`intl`）、`redirectUri` |
| `ticktick_oauth_start` | 生成授权链接 |
| `ticktick_oauth_finish` | 用粘贴的 `code` / 回调 URL 换取令牌 |
| `ticktick_lists` | 列出所有清单（id + 名称） |
| `ticktick_tasks` | 拉取任务（按清单、已完成、条数限制） |
| `ticktick_add` | 创建任务 |
| `ticktick_update` | 更新任务 |
| `ticktick_complete` | 完成任务 |
| `ticktick_delete` | 删除任务 |
| `ticktick_sync` | 拉取汇总 / 按标题去重推送 |

## 说明

- 使用 Node 内置 `fetch`（Node 22+）与 `crypto`——零运行时依赖。
- OAuth 回调路由仅限本机回环且校验 OAuth `state`；其余 `/api/dsh-ticktick/*` 路由仅限本机回环 + 同源。
- 开放 API 未覆盖：智能清单筛选与定时提醒（`reminders`/`repeatFlag` 传入时会透传，但未建模为工具参数）。收集箱（`inbox`）也不在 `GET /project` 的清单列表里，但插件已按固定 id 处理——拉取、创建、完成、删除、同步均含收集箱。
- Web 设置面板通过仅限回环的 `/api/dsh-ticktick` 路由族与宿主通信。

## License

MIT
