@zentodo/cli 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.cjs CHANGED
@@ -3613,7 +3613,7 @@ var authCapabilities = [
3613
3613
  id: "auth.login.password",
3614
3614
  domain: "auth",
3615
3615
  action: "login-password",
3616
- summary: "\u90AE\u7BB1 + \u5BC6\u7801\u767B\u5F55\u3002",
3616
+ summary: "\u90AE\u7BB1 + \u5BC6\u7801\u767B\u5F55\uFF08PC \u7AEF\u63A5\u53E3\uFF09\u3002",
3617
3617
  description: "\u8C03\u7528 /userController/loginXzbb \u5B8C\u6210\u8EAB\u4EFD\u6821\u9A8C\uFF0C\u8FD4\u56DE\u7528\u6237\u4FE1\u606F\u4E0E usrKey\u3002",
3618
3618
  http: { method: "POST", path: "/userController/loginXzbb" },
3619
3619
  params: [
@@ -3626,6 +3626,24 @@ var authCapabilities = [
3626
3626
  cli: { group: "auth", command: "login-password", examples: ["zentodo auth login-password --email a@b.com --password ****"] },
3627
3627
  tool: { readOnlyHint: false }
3628
3628
  },
3629
+ {
3630
+ id: "auth.login.email",
3631
+ domain: "auth",
3632
+ action: "login-email",
3633
+ summary: "\u90AE\u7BB1\u9A8C\u8BC1\u7801\u767B\u5F55\uFF08App \u7AEF\u63A5\u53E3\uFF0C\u63A8\u8350\uFF09\u3002",
3634
+ description: "\u8C03\u7528 /userController/emailLogin\uFF0C\u53EA\u9700\u90AE\u7BB1\uFF0C\u914D\u5408 email-code \u547D\u4EE4\u5148\u53D1\u9A8C\u8BC1\u7801\u3002\u8FD4\u56DE usrKey\uFF08Long\uFF09\u3002",
3635
+ http: { method: "POST", path: "/userController/emailLogin" },
3636
+ params: [
3637
+ { name: "email", backendName: "usrEmail", type: "string", required: true, description: "\u8D26\u53F7\u90AE\u7BB1\u3002" },
3638
+ { name: "invite_code", backendName: "inviteCode", type: "string", description: "\u9080\u8BF7\u7801\uFF08\u53EF\u9009\uFF09\u3002" },
3639
+ { name: "password", backendName: "usrPwd", type: "string", default: "", sendEmpty: true, description: "\u5BC6\u7801\uFF08\u4F20\u7A7A\u5B57\u7B26\u4E32\u5373\u53EF\uFF09\u3002" }
3640
+ ],
3641
+ output: { shape: "scalar" },
3642
+ scopes: ["read"],
3643
+ idempotent: true,
3644
+ cli: { group: "auth", command: "login-email", examples: ["zentodo auth login-email --email a@b.com"] },
3645
+ tool: { readOnlyHint: false }
3646
+ },
3629
3647
  {
3630
3648
  id: "auth.email-code.send",
3631
3649
  domain: "auth",
@@ -5739,7 +5757,7 @@ var DEFAULT_CONFIG = {
5739
5757
  current_profile: "default",
5740
5758
  profiles: {
5741
5759
  default: {
5742
- server: "http://fwq.qmlist.net/xzbbserver",
5760
+ server: "http://ztdfwq.qmlist.net:8082/zentodoserver",
5743
5761
  output: "text",
5744
5762
  rate_limit_qps: 5,
5745
5763
  retry: { attempts: 3, base_ms: 250 }
@@ -6474,6 +6492,68 @@ function registerAuth(root) {
6474
6492
  { format }
6475
6493
  );
6476
6494
  });
6495
+ auth.command("login-email").description("\u90AE\u7BB1\u9A8C\u8BC1\u7801\u767B\u5F55\uFF08App \u7AEF\u63A8\u8350\u65B9\u5F0F\uFF09\u3002\u5148\u7528 email-code \u53D1\u9A8C\u8BC1\u7801\uFF0C\u6536\u5230\u540E\u7528\u6B64\u547D\u4EE4\u767B\u5F55\u3002").requiredOption("--email <email>", "\u8D26\u53F7\u90AE\u7BB1").option("--invite-code <code>", "\u9080\u8BF7\u7801\uFF08\u53EF\u9009\uFF09").option("--scope <csv>", "\u672C\u5730 Token \u7684 scope\uFF0C\u9017\u53F7\u5206\u9694", "read,write,sync").option("--expires <duration>", "Token \u6709\u6548\u671F\uFF08\u4F8B 30d / 12h / 5m\uFF09", "30d").action(async (opts, thisCmd) => {
6496
+ const globalFlags = thisCmd.optsWithGlobals();
6497
+ const format = resolveFormat({
6498
+ json: !!globalFlags["json"],
6499
+ ndjson: !!globalFlags["ndjson"],
6500
+ yaml: !!globalFlags["yaml"]
6501
+ });
6502
+ ensureHome();
6503
+ const cfg = loadConfig();
6504
+ const { name, profile } = getProfile(cfg, globalFlags["profile"]);
6505
+ const effective = applyEnvOverrides(profile);
6506
+ const cap = capabilityById("auth.login.email");
6507
+ const http = new HttpClient({ baseUrl: effective.server });
6508
+ const result = await runCapability(
6509
+ cap,
6510
+ { email: opts.email, invite_code: opts.inviteCode, password: "" },
6511
+ { http, grantedScopes: ["read", "write"] }
6512
+ );
6513
+ if (!result.ok) {
6514
+ writeResult(result, { format });
6515
+ process.exit(401);
6516
+ return;
6517
+ }
6518
+ const usrKey = result.data;
6519
+ if (!usrKey) {
6520
+ writeResult(
6521
+ {
6522
+ ok: false,
6523
+ data: null,
6524
+ error: { code: "ErrUnauthorized", message: "\u767B\u5F55\u6210\u529F\u4F46\u54CD\u5E94\u4E2D\u672A\u643A\u5E26 usrKey" },
6525
+ meta: result.meta
6526
+ },
6527
+ { format }
6528
+ );
6529
+ process.exit(401);
6530
+ return;
6531
+ }
6532
+ const scopes = opts.scope.split(",").map((s) => s.trim()).filter(Boolean);
6533
+ const ttlMs = parseDuration(opts.expires);
6534
+ const secrets = await createSecretStore();
6535
+ let hmac2 = await secrets.get(`${name}:hmac-secret`);
6536
+ if (!hmac2) {
6537
+ hmac2 = createTokenSecret();
6538
+ await secrets.set(`${name}:hmac-secret`, hmac2);
6539
+ }
6540
+ const token = signToken(
6541
+ { usrKey: String(usrKey), scopes, expiresAt: ttlMs > 0 ? Date.now() + ttlMs : 0 },
6542
+ hmac2
6543
+ );
6544
+ await secrets.set(name, token);
6545
+ setProfile(cfg, name, { user_key: usrKey, email: opts.email });
6546
+ saveConfig(cfg);
6547
+ writeResult(
6548
+ {
6549
+ ok: true,
6550
+ data: { profile: name, user_key: usrKey, scopes, expires_in_ms: ttlMs },
6551
+ error: null,
6552
+ meta: result.meta
6553
+ },
6554
+ { format }
6555
+ );
6556
+ });
6477
6557
  auth.command("whoami").description("\u663E\u793A\u5F53\u524D Profile \u4E0E usrKey").action(async (_opts, thisCmd) => {
6478
6558
  const globalFlags = thisCmd.optsWithGlobals();
6479
6559
  const format = resolveFormat({
@@ -6982,7 +7062,7 @@ function buildEntry(opts) {
6982
7062
  usrKey = profile.user_key;
6983
7063
  }
6984
7064
  const env = {
6985
- ZENTODO_SERVER: server ?? "http://fwq.qmlist.net/xzbbserver",
7065
+ ZENTODO_SERVER: server ?? "http://ztdfwq.qmlist.net:8082/zentodoserver",
6986
7066
  ZENTODO_SCOPES: opts.scopes
6987
7067
  };
6988
7068
  if (usrKey !== void 0 && usrKey !== null) {
@@ -44,6 +44,16 @@ description: Manage the user's ZenTodo productivity workspace — tasks, subtask
44
44
 
45
45
  2. **登录 ZenTodo**(一次性):
46
46
 
47
+ **推荐:邮箱验证码登录(与 App 端一致)**
48
+ ```bash
49
+ # 第一步:发送验证码到邮箱
50
+ zentodo auth email-code --email 你的邮箱
51
+
52
+ # 第二步:收到验证码后登录(验证码会在后台自动校验)
53
+ zentodo auth login-email --email 你的邮箱
54
+ ```
55
+
56
+ **或者:邮箱 + 密码登录**
47
57
  ```bash
48
58
  zentodo auth login-password --email 你的邮箱 --password 你的密码
49
59
  ```
@@ -61,7 +71,31 @@ description: Manage the user's ZenTodo productivity workspace — tasks, subtask
61
71
 
62
72
  如果当前 shell 找不到 `zentodo`,设置环境变量 `ZENTODO_CLI` 指向绝对路径,并在所有命令前加 `node $ZENTODO_CLI`。
63
73
 
64
- ## 通用输出契约(**关键**)
74
+ ## ⚠️ 重要约束(必须遵守)
75
+
76
+ **绝对不要直接用 `curl` 或其他 HTTP 工具调用 ZenTodo 后端接口。**
77
+
78
+ 原因:
79
+ 1. 后端所有接口要求 `multipart/form-data` 格式,直接 curl 默认发 JSON 会导致 400 或 302 重定向
80
+ 2. `usrKey` 等认证参数必须通过 FormData 传递,JSON 格式无效
81
+ 3. CLI 已经处理好了格式转换、认证注入、错误映射
82
+
83
+ **正确做法:所有操作必须通过 `zentodo` CLI 命令完成。**
84
+
85
+ ```bash
86
+ # ✅ 正确
87
+ zentodo --json project list
88
+ zentodo --json task list
89
+
90
+ # ❌ 错误(不要这样做)
91
+ curl -X POST http://ztdfwq.qmlist.net:8082/zentodoserver/projectController/getAllProjectByUserId
92
+ ```
93
+
94
+ 如果 `zentodo` 命令不可用,先按"前置条件"安装,不要绕过 CLI 直接调接口。
95
+
96
+ ---
97
+
98
+
65
99
 
66
100
  所有命令加 `--json` 后,输出统一为:
67
101
 
@@ -126,7 +126,7 @@
126
126
 
127
127
  ### `zentodo auth login-password` _(幂等)_
128
128
 
129
- 邮箱 + 密码登录。
129
+ 邮箱 + 密码登录(PC 端接口)。
130
130
 
131
131
  - **后端端点**:`POST /userController/loginXzbb`
132
132
  - **所需 scope**:`read`
@@ -143,6 +143,26 @@
143
143
  zentodo auth login-password --email a@b.com --password ****
144
144
  ```
145
145
 
146
+ ### `zentodo auth login-email` _(幂等)_
147
+
148
+ 邮箱验证码登录(App 端接口,推荐)。
149
+
150
+ - **后端端点**:`POST /userController/emailLogin`
151
+ - **所需 scope**:`read`
152
+ - **对应 Skill 工具**:`zentodo.auth.login-email`
153
+
154
+ | 参数 | 类型 | 必填 | 说明 |
155
+ | --- | --- | --- | --- |
156
+ | `email` | string | 是 | 账号邮箱。 |
157
+ | `invite_code` | string | 否 | 邀请码(可选)。 |
158
+ | `password` | string | 否 | 密码(传空字符串即可)。 |
159
+
160
+ **示例:**
161
+
162
+ ```
163
+ zentodo auth login-email --email a@b.com
164
+ ```
165
+
146
166
  ### `zentodo auth email-code`
147
167
 
148
168
  发送邮箱登录验证码。
@@ -3,6 +3,7 @@
3
3
  | 领域 | CLI 命令 | MCP 工具 | 后端端点 | Scope |
4
4
  | --- | --- | --- | --- | --- |
5
5
  | auth | `zentodo auth login-password` | `zentodo.auth.login-password` | `POST /userController/loginXzbb` | read |
6
+ | auth | `zentodo auth login-email` | `zentodo.auth.login-email` | `POST /userController/emailLogin` | read |
6
7
  | auth | `zentodo auth email-code` | `zentodo.auth.email-code` | `POST /userController/sendAuthEmailCode` | read |
7
8
  | auth | `zentodo auth register` | `zentodo.auth.register` | `POST /userController/regisiterApp` | write |
8
9
  | auth | `zentodo auth find-password` | `zentodo.auth.find-password` | `POST /userController/findPasswordByUsrEmail` | read |
@@ -37,6 +37,50 @@
37
37
  "shape": "object"
38
38
  }
39
39
  },
40
+ {
41
+ "name": "zentodo.auth.login-email",
42
+ "domain": "auth",
43
+ "action": "login-email",
44
+ "description": "调用 /userController/emailLogin,只需邮箱,配合 email-code 命令先发验证码。返回 usrKey(Long)。",
45
+ "http": {
46
+ "method": "POST",
47
+ "path": "/userController/emailLogin"
48
+ },
49
+ "scopes": [
50
+ "read"
51
+ ],
52
+ "annotations": {
53
+ "readOnly": false,
54
+ "idempotent": true,
55
+ "destructive": false
56
+ },
57
+ "params": [
58
+ {
59
+ "name": "email",
60
+ "backendName": "usrEmail",
61
+ "type": "string",
62
+ "required": true,
63
+ "description": "账号邮箱。"
64
+ },
65
+ {
66
+ "name": "invite_code",
67
+ "backendName": "inviteCode",
68
+ "type": "string",
69
+ "description": "邀请码(可选)。"
70
+ },
71
+ {
72
+ "name": "password",
73
+ "backendName": "usrPwd",
74
+ "type": "string",
75
+ "default": "",
76
+ "sendEmpty": true,
77
+ "description": "密码(传空字符串即可)。"
78
+ }
79
+ ],
80
+ "output": {
81
+ "shape": "scalar"
82
+ }
83
+ },
40
84
  {
41
85
  "name": "zentodo.auth.email-code",
42
86
  "domain": "auth",
@@ -26,6 +26,20 @@
26
26
  | `email` | string | 是 | 账号邮箱。 |
27
27
  | `password` | string | 是 | 账号密码。 |
28
28
 
29
+ ## `zentodo.auth.login-email`
30
+
31
+ 调用 /userController/emailLogin,只需邮箱,配合 email-code 命令先发验证码。返回 usrKey(Long)。
32
+
33
+ - **后端端点**:`POST /userController/emailLogin`
34
+ - **所需 scope**:`read`
35
+ - **标注**:只读=false,幂等=true,破坏性=false
36
+
37
+ | 参数 | 类型 | 必填 | 说明 |
38
+ | --- | --- | --- | --- |
39
+ | `email` | string | 是 | 账号邮箱。 |
40
+ | `invite_code` | string | 否 | 邀请码(可选)。 |
41
+ | `password` | string | 否 | 密码(传空字符串即可)。 |
42
+
29
43
  ## `zentodo.auth.email-code`
30
44
 
31
45
  调用 /userController/sendAuthEmailCode 向指定邮箱发送验证码。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zentodo/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "ZenTodo 命令行工具 — 为 AI Agent 和开发者设计,覆盖任务、项目、番茄钟、日记、同步等全部能力。安装后自动配置 Claude Agent Skill。",
5
5
  "type": "module",
6
6
  "bin": {
@@ -44,6 +44,16 @@ description: Manage the user's ZenTodo productivity workspace — tasks, subtask
44
44
 
45
45
  2. **登录 ZenTodo**(一次性):
46
46
 
47
+ **推荐:邮箱验证码登录(与 App 端一致)**
48
+ ```bash
49
+ # 第一步:发送验证码到邮箱
50
+ zentodo auth email-code --email 你的邮箱
51
+
52
+ # 第二步:收到验证码后登录(验证码会在后台自动校验)
53
+ zentodo auth login-email --email 你的邮箱
54
+ ```
55
+
56
+ **或者:邮箱 + 密码登录**
47
57
  ```bash
48
58
  zentodo auth login-password --email 你的邮箱 --password 你的密码
49
59
  ```
@@ -61,7 +71,31 @@ description: Manage the user's ZenTodo productivity workspace — tasks, subtask
61
71
 
62
72
  如果当前 shell 找不到 `zentodo`,设置环境变量 `ZENTODO_CLI` 指向绝对路径,并在所有命令前加 `node $ZENTODO_CLI`。
63
73
 
64
- ## 通用输出契约(**关键**)
74
+ ## ⚠️ 重要约束(必须遵守)
75
+
76
+ **绝对不要直接用 `curl` 或其他 HTTP 工具调用 ZenTodo 后端接口。**
77
+
78
+ 原因:
79
+ 1. 后端所有接口要求 `multipart/form-data` 格式,直接 curl 默认发 JSON 会导致 400 或 302 重定向
80
+ 2. `usrKey` 等认证参数必须通过 FormData 传递,JSON 格式无效
81
+ 3. CLI 已经处理好了格式转换、认证注入、错误映射
82
+
83
+ **正确做法:所有操作必须通过 `zentodo` CLI 命令完成。**
84
+
85
+ ```bash
86
+ # ✅ 正确
87
+ zentodo --json project list
88
+ zentodo --json task list
89
+
90
+ # ❌ 错误(不要这样做)
91
+ curl -X POST http://ztdfwq.qmlist.net:8082/zentodoserver/projectController/getAllProjectByUserId
92
+ ```
93
+
94
+ 如果 `zentodo` 命令不可用,先按"前置条件"安装,不要绕过 CLI 直接调接口。
95
+
96
+ ---
97
+
98
+
65
99
 
66
100
  所有命令加 `--json` 后,输出统一为:
67
101
 
@@ -126,7 +126,7 @@
126
126
 
127
127
  ### `zentodo auth login-password` _(幂等)_
128
128
 
129
- 邮箱 + 密码登录。
129
+ 邮箱 + 密码登录(PC 端接口)。
130
130
 
131
131
  - **后端端点**:`POST /userController/loginXzbb`
132
132
  - **所需 scope**:`read`
@@ -143,6 +143,26 @@
143
143
  zentodo auth login-password --email a@b.com --password ****
144
144
  ```
145
145
 
146
+ ### `zentodo auth login-email` _(幂等)_
147
+
148
+ 邮箱验证码登录(App 端接口,推荐)。
149
+
150
+ - **后端端点**:`POST /userController/emailLogin`
151
+ - **所需 scope**:`read`
152
+ - **对应 Skill 工具**:`zentodo.auth.login-email`
153
+
154
+ | 参数 | 类型 | 必填 | 说明 |
155
+ | --- | --- | --- | --- |
156
+ | `email` | string | 是 | 账号邮箱。 |
157
+ | `invite_code` | string | 否 | 邀请码(可选)。 |
158
+ | `password` | string | 否 | 密码(传空字符串即可)。 |
159
+
160
+ **示例:**
161
+
162
+ ```
163
+ zentodo auth login-email --email a@b.com
164
+ ```
165
+
146
166
  ### `zentodo auth email-code`
147
167
 
148
168
  发送邮箱登录验证码。
@@ -3,6 +3,7 @@
3
3
  | 领域 | CLI 命令 | MCP 工具 | 后端端点 | Scope |
4
4
  | --- | --- | --- | --- | --- |
5
5
  | auth | `zentodo auth login-password` | `zentodo.auth.login-password` | `POST /userController/loginXzbb` | read |
6
+ | auth | `zentodo auth login-email` | `zentodo.auth.login-email` | `POST /userController/emailLogin` | read |
6
7
  | auth | `zentodo auth email-code` | `zentodo.auth.email-code` | `POST /userController/sendAuthEmailCode` | read |
7
8
  | auth | `zentodo auth register` | `zentodo.auth.register` | `POST /userController/regisiterApp` | write |
8
9
  | auth | `zentodo auth find-password` | `zentodo.auth.find-password` | `POST /userController/findPasswordByUsrEmail` | read |
@@ -37,6 +37,50 @@
37
37
  "shape": "object"
38
38
  }
39
39
  },
40
+ {
41
+ "name": "zentodo.auth.login-email",
42
+ "domain": "auth",
43
+ "action": "login-email",
44
+ "description": "调用 /userController/emailLogin,只需邮箱,配合 email-code 命令先发验证码。返回 usrKey(Long)。",
45
+ "http": {
46
+ "method": "POST",
47
+ "path": "/userController/emailLogin"
48
+ },
49
+ "scopes": [
50
+ "read"
51
+ ],
52
+ "annotations": {
53
+ "readOnly": false,
54
+ "idempotent": true,
55
+ "destructive": false
56
+ },
57
+ "params": [
58
+ {
59
+ "name": "email",
60
+ "backendName": "usrEmail",
61
+ "type": "string",
62
+ "required": true,
63
+ "description": "账号邮箱。"
64
+ },
65
+ {
66
+ "name": "invite_code",
67
+ "backendName": "inviteCode",
68
+ "type": "string",
69
+ "description": "邀请码(可选)。"
70
+ },
71
+ {
72
+ "name": "password",
73
+ "backendName": "usrPwd",
74
+ "type": "string",
75
+ "default": "",
76
+ "sendEmpty": true,
77
+ "description": "密码(传空字符串即可)。"
78
+ }
79
+ ],
80
+ "output": {
81
+ "shape": "scalar"
82
+ }
83
+ },
40
84
  {
41
85
  "name": "zentodo.auth.email-code",
42
86
  "domain": "auth",
@@ -26,6 +26,20 @@
26
26
  | `email` | string | 是 | 账号邮箱。 |
27
27
  | `password` | string | 是 | 账号密码。 |
28
28
 
29
+ ## `zentodo.auth.login-email`
30
+
31
+ 调用 /userController/emailLogin,只需邮箱,配合 email-code 命令先发验证码。返回 usrKey(Long)。
32
+
33
+ - **后端端点**:`POST /userController/emailLogin`
34
+ - **所需 scope**:`read`
35
+ - **标注**:只读=false,幂等=true,破坏性=false
36
+
37
+ | 参数 | 类型 | 必填 | 说明 |
38
+ | --- | --- | --- | --- |
39
+ | `email` | string | 是 | 账号邮箱。 |
40
+ | `invite_code` | string | 否 | 邀请码(可选)。 |
41
+ | `password` | string | 否 | 密码(传空字符串即可)。 |
42
+
29
43
  ## `zentodo.auth.email-code`
30
44
 
31
45
  调用 /userController/sendAuthEmailCode 向指定邮箱发送验证码。