@lark-project/meegle 0.0.17 → 1.0.1

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/README.zh-CN.md CHANGED
@@ -1,22 +1,63 @@
1
1
  # Meegle CLI
2
2
 
3
- > **DEV** — 当前处于开发预览阶段,API 和命令可能发生变更。
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D16-brightgreen.svg)](https://nodejs.org/)
5
+ [![npm version](https://img.shields.io/npm/v/@lark-project/meegle.svg)](https://www.npmjs.com/package/@lark-project/meegle)
6
+
7
+ [English](./README.md) | [简体中文](./README.zh-CN.md)
4
8
 
5
9
  飞书项目([Meegle](https://meegle.com?utm_source=github&utm_medium=readme&utm_campaign=meegle_cli) / [Lark Project](https://project.feishu.cn?utm_source=github&utm_medium=readme&utm_campaign=meegle_cli))命令行工具。在终端中管理工作项、查看排期、搜索数据,无需打开浏览器。
6
10
 
11
+ [安装](#安装) · [快速开始](#快速开始人类用户) · [Agent Skill](#ai-agent-skill) · [命令](#命令一览) · [认证](#认证) · [配置](#配置) · [安全](#安全与风险提示) · [贡献](#贡献)
12
+
13
+ ## 为什么选择 Meegle CLI?
14
+
15
+ - **Agent 友好** — 附带一份 [AI Agent Skill](#ai-agent-skill),一条命令即可把 Meegle 操作手册喂给 Trae、Claude Code、Cursor、Windsurf、Gemini CLI 等主流 Agent。CLI 命令同时面向人类和 Agent 设计,结构化 JSON 输出、`--dry-run` 预览、`--device-code` 无 TTY 流程
16
+ - **覆盖完整** — 12 个业务域(工作项、工作流、子任务、评论、工时、关联、我的工作、视图、图表、团队、用户、空间),40+ 命令映射到 Meegle 核心能力
17
+ - **两层参数模型** — 日常用 `--flag-name` 轻便直接,复杂载荷(如 `fields[]`)用 `--params <json>` 兜底 —— 按场景选择合适粒度
18
+ - **输出格式灵活** — 支持 `json` / `table` / `ndjson` / `raw`,配合 `--select` 点路径投影可直接 pipe 给其他工具
19
+ - **默认安全** — 凭证存进系统 keychain、`${VAR}` 环境变量模板让 secret 不落地到 config 文件、多 profile 分离 staging / prod
20
+
21
+ ## 功能概览
22
+
23
+ | 域 | 能力 |
24
+ | -------------------------------------------------- | ---------------------------------------------------------------------------------------- |
25
+ | 📋 [工作项](#workitem--工作项域) | 创建、查看、更新、批量读、MQL 查询、查看操作记录、读元数据 |
26
+ | 🔀 [工作流](#workflow--工作流域) | 节点和状态流转、更新节点字段、列出可用流转和必填字段 |
27
+ | ✅ [子任务](#subtask--子任务) | 创建、更新、完成、回滚子任务 |
28
+ | 💬 [评论](#comment--评论域) | 在工作项上添加和列出评论 |
29
+ | ⏱️ [工时](#workhour--工时域) | 列出工时记录、查看团队成员排期 |
30
+ | 🔗 [关联](#relation--关系域) | 列出关联工作项、查看关联类型定义 |
31
+ | 📌 [我的工作](#mywork--工作台域) | 查看本周 / 已完成 / 逾期待办 |
32
+ | 👁️ [视图](#view--视图域) | 创建和更新固定视图、按名称搜索视图 |
33
+ | 📊 [图表](#chart--度量域) | 列出视图下的图表、查看图表详情 |
34
+ | 👥 [团队与用户](#team--user--人员域) | 列出团队、团队成员、搜索用户、查看当前登录身份 |
35
+ | 🗂️ [空间](#project--空间域) | 按关键词搜索空间 |
36
+ | 🔐 [认证与配置](#认证) | OAuth 登录、Device Code 流程、多 profile 配置、环境变量注入 |
37
+ | 🔗 [URL 解析](#url--url-解析) | 离线解析飞书项目 / Meegle URL,输出 `url_kind` + 结构化字段 |
38
+ | 🤖 [Agent Skill](#ai-agent-skill) | 内置 skill 供 Trae / Claude Code / Cursor / Windsurf / Gemini / Copilot 使用 |
7
39
 
8
40
  ## 安装
9
41
 
42
+ ### 前置条件
43
+
44
+ - Node.js >= 16(自带 `npm` / `npx`)
45
+
46
+ ### 安装命令
47
+
10
48
  ```bash
11
49
  npm install -g @lark-project/meegle
12
50
  ```
13
51
 
14
- 要求 Node.js >= 16。
52
+ ## 快速开始(人类用户)
15
53
 
16
- ## 快速开始
54
+ > **给 AI Agent 的提示:** 如果你是在替用户完成这套安装的 AI Agent,请直接跳到 [快速开始(AI Agent)](#快速开始ai-agent--ci--无头环境) —— 那里有你需要的非交互步骤。
17
55
 
18
56
  ```bash
19
- # 1. 登录
57
+ # (可选)持久化 host,后续登录就不用再选菜单
58
+ meegle config set host <host>
59
+
60
+ # 1. 登录(上下选择 host + 浏览器 OAuth)
20
61
  meegle auth login
21
62
 
22
63
  # 2. 查看本周待办
@@ -30,26 +71,84 @@ meegle workitem --help
30
71
  meegle inspect workitem.create
31
72
  ```
32
73
 
33
- ## 非交互环境下的初始化(CI / Agent / Claude Code)
74
+ ## 快速开始(AI Agent / CI / 无头环境)
34
75
 
35
- `meegle auth login` 默认使用上下选择菜单 + Authorization Code OAuth 流程,
36
- 两者都依赖真实终端和本地浏览器回调。在 CI Runner、管道、Claude Code 这类
37
- 没有 TTY 的环境里会直接报错或挂起。
76
+ `meegle auth login` 默认走上下选择菜单 + 浏览器 OAuth 回调,依赖真实 TTY,在 CI Runner、管道、Claude Code 这类没有 TTY 的环境里会挂起或报错。这些场景请改用 Device Code 流程 —— 命令会输出授权 URL,让用户在浏览器里完成授权。
38
77
 
39
- 这些场景请改用 Device Code 流程 —— 命令会输出一个 URL,让操作者在任意浏览
40
- 器里完成授权:
78
+ **Step 1 安装 CLI**
41
79
 
42
80
  ```bash
43
- # 方式 A:每次显式传入 host
44
- meegle auth login --device-code --host <host>
81
+ npm install -g @lark-project/meegle
82
+ ```
45
83
 
46
- # 方式 B:先持久化 host,再登录
84
+ **Step 2 持久化 host**
85
+
86
+ ```bash
47
87
  meegle config set host <host>
88
+ ```
89
+
90
+ `<host>` 示例:`project.feishu.cn`、`meegle.com`,或自建租户域名(如 `your-tenant.example.com`)。
91
+
92
+ **Step 3 — Device Code 登录**
93
+
94
+ > 建议后台执行。命令会输出授权 URL —— 提取后发给用户,用户在浏览器完成授权后命令自动退出。
95
+
96
+ ```bash
48
97
  meegle auth login --device-code
49
98
  ```
50
99
 
51
- `<host>` 示例:`project.feishu.cn`、`meegle.com`,或你的自建租户域名
52
- (如 `your-tenant.example.com`)。
100
+ 如不想持久化 host,也可以每次显式传入:
101
+
102
+ ```bash
103
+ meegle auth login --device-code --host <host>
104
+ ```
105
+
106
+ **Step 4 — 验证**
107
+
108
+ ```bash
109
+ meegle auth status
110
+ ```
111
+
112
+ 完全无人值守的 CI(没有真人参与)请改用环境变量注入 token,参见 [沙盒 / CI](#沙盒--ci直接注入环境变量)。
113
+
114
+ ## AI Agent Skill
115
+
116
+ `skills/meegle/` 是一份可直接加载的 **skill**,用来教 AI Agent —— Trae、Claude Code、Cursor、Windsurf、Gemini CLI、GitHub Copilot CLI —— 通过本 CLI 操作 Meegle。它把命令目录、MQL 语法、字段值写法、富文本 Markdown 规则,以及常见写入流程的 SOP 全部打包好。
117
+
118
+ ### 安装
119
+
120
+ ```bash
121
+ # 先装 CLI(skill 底层会调用 meegle 命令)
122
+ npm install -g @lark-project/meegle
123
+
124
+ # 再加载 skill —— 会自动探测已装的 Agent,并在各自的 skill 目录里登记
125
+ npx skills add larksuite/meegle-cli -y -g
126
+ ```
127
+
128
+ `npx skills add` 会从仓库读取 `skills/meegle/SKILL.md`,写入本机所有 Agent CLI 的 skill 目录。每次升级重跑一遍即可拉取最新内容。
129
+
130
+ ### 覆盖内容
131
+
132
+ - **命令参考** — 每个 `meegle` resource / method 的必填参数与示例
133
+ - **MQL 搜索** — `workitem query` 的语法、运算符、作用域关键字
134
+ - **字段值** — 复杂字段载荷(数组、嵌套 JSON、日期区间)的写法
135
+ - **富文本** — Meegle 富文本编辑器支持的 Markdown 子集
136
+ - **SOP** — 创建工作项、节点流转、状态流转、更新字段等场景的分步剧本
137
+ - **授权守护** — 所有业务命令前强制先过 `meegle auth status`
138
+
139
+ 完整内容见 [skills/meegle/SKILL.md](./skills/meegle/SKILL.md) 和 [skills/meegle/references/](./skills/meegle/references/)。
140
+
141
+ ### 使用方式
142
+
143
+ 安装后直接用自然语言和 Agent 对话。例如 Trae:
144
+
145
+ ```
146
+ 帮我看一下 PROJ 空间本周待办里的 P0 需求
147
+ ```
148
+
149
+ Agent 会参考 skill,自动选择合适的 `meegle` 命令执行。配合 `--dry-run`(见 [安全](#安全与风险提示))可以在 Agent 真正执行副作用前先预览请求。
150
+
151
+ > 小提示:skill 的名字 `meegle` 和 CLI 二进制同名。文档里提到 **`meegle` skill** 时指 `skills/meegle/` 里的文件;提到 **`meegle` CLI** 时指你 PATH 上的 `meegle` 命令。
53
152
 
54
153
  ## 命令一览
55
154
 
@@ -59,6 +158,7 @@ meegle auth login --device-code
59
158
  |------|------|
60
159
  | `workitem create` | 创建工作项 |
61
160
  | `workitem get` | 查看工作项概况 |
161
+ | `workitem +batch-get` | 按 ID 批量读取工作项(客户端侧在 `workitem get` 之上做扇出;`+` 前缀代表场景/语法糖命令) |
62
162
  | `workitem update` | 修改工作项字段 |
63
163
  | `workitem query` | 使用 MQL 搜索工作项 |
64
164
  | `workitem list-op-records` | 查看操作记录 |
@@ -143,6 +243,15 @@ meegle auth login --device-code
143
243
  |------|------|
144
244
  | `project search` | 搜索空间信息 |
145
245
 
246
+ ### attachment — 附件域
247
+
248
+ | 命令 | 说明 |
249
+ |------|------|
250
+ | `attachment prepare-upload` | 上传预处理 —— 返回带签名的对象存储 URL 与分片计划 |
251
+ | `attachment prepare-download` | 下载预处理 —— 返回带签名的对象存储 URL 与分片计划 |
252
+ | `attachment +upload` | 端到端上传:预处理 + 签名 HTTP POST,返回 `file_token` 与文件元信息 |
253
+ | `attachment +download` | 端到端下载:预处理 + 签名 HTTP GET + 原子写文件,用于消费 `workitem get` / `comment list` 返回的 `file_url` |
254
+
146
255
  ### auth — 认证域
147
256
 
148
257
  | 命令 | 说明 |
@@ -161,6 +270,14 @@ meegle auth login --device-code
161
270
  | `config get` | 读取配置项 |
162
271
  | `config profile create\|list\|use\|current\|delete` | 管理多环境 profile |
163
272
 
273
+ ### url — URL 解析
274
+
275
+ 离线、纯本地的 URL 解析工具,不发起任何网络调用。Skill 或 pipeline 解析飞书项目/Meegle URL 时优先走本命令,拿 `url_kind` 做分支,避免从原始路径猜字段。
276
+
277
+ | 命令 | 说明 |
278
+ |------|------|
279
+ | `url decode --url <URL>` | 将 URL 解析为 `url_kind` + `simple_name` / `work_item_type` / `work_item_id` / `view_id` / `chart_id` / `query` / `redirected_from` 等字段;未识别的 URL 返回 `url_kind: "unknown"`。 |
280
+
164
281
  ### 其他命令
165
282
 
166
283
  | 命令 | 说明 |
@@ -194,18 +311,56 @@ meegle workitem get --work-item-id 12345
194
311
  meegle workflow get-node --work-item-id 12345 --need-sub-task
195
312
  ```
196
313
 
314
+ ### 批量读取工作项
315
+
316
+ `workitem +batch-get` 会对每个 ID 分别调用 `workitem get` 并把结果聚合成一条响应。
317
+ 共享 flag(如 `--project-key`)会应用到每一次 per-item 调用上。命令以 `+` 开头,
318
+ 表示它是客户端侧的场景/语法糖命令,CLI 在 `get` 之上组合出批量语义,没有对应的
319
+ 单一后端接口。
320
+
321
+ ```bash
322
+ # 在一次调用里传入逗号分隔的多个 ID
323
+ meegle workitem +batch-get --project-key PROJ --work-item-ids "12345,12346,12347"
324
+
325
+ # 从文件读取 ID(每行一个,以 '#' 开头的行视为注释)
326
+ meegle workitem +batch-get --project-key PROJ --ids-file ./ids.txt
327
+
328
+ # 每个 item 输出一行 JSON,summary 作为最后一行
329
+ meegle workitem +batch-get --project-key PROJ --work-item-ids "12345,12346" -o ndjson
330
+ ```
331
+
332
+ 响应结构(JSON):
333
+
334
+ ```json
335
+ {
336
+ "summary": { "total": 3, "succeeded": 2, "failed": 1 },
337
+ "results": [
338
+ { "work_item_id": 12345, "data": { /* ... */ } },
339
+ { "work_item_id": 12346, "data": { /* ... */ } },
340
+ { "work_item_id": 12347, "error": { "code": "...", "message": "..." } }
341
+ ]
342
+ }
343
+ ```
344
+
345
+ 约束:单次调用最多 200 个 ID,固定 3 worker 并发。部分失败**不会**中断整批——
346
+ 请通过 `summary.failed` 或 per-item 的 `error` 字段判断;服务端返回 401 会终止整批。
347
+
197
348
  ### 创建工作项
198
349
 
199
350
  ```bash
200
- # 使用 --set 设置字段
351
+ # 通过 --params 传 fields[]
201
352
  meegle workitem create --project-key PROJ --work-item-type story \
202
- --set name=优化登录流程 \
203
- --set priority=P1
353
+ --params '{"fields":[
354
+ {"field_key":"name","field_value":"优化登录流程"},
355
+ {"field_key":"priority","field_value":"P1"}
356
+ ]}'
204
357
 
205
- # 复杂字段传 JSON
358
+ # 复杂字段值(数组、嵌套 JSON)也走 --params
206
359
  meegle workitem create --project-key PROJ --work-item-type story \
207
- --set name=排期任务 \
208
- --set schedule='[1722182400000,1722355199999]'
360
+ --params '{"fields":[
361
+ {"field_key":"name","field_value":"排期任务"},
362
+ {"field_key":"schedule","field_value":[1722182400000,1722355199999]}
363
+ ]}'
209
364
  ```
210
365
 
211
366
  ### 修改字段
@@ -213,14 +368,106 @@ meegle workitem create --project-key PROJ --work-item-type story \
213
368
  ```bash
214
369
  # 修改工作项名称
215
370
  meegle workitem update --work-item-id 12345 \
216
- --set name=新标题
371
+ --params '{"fields":[{"field_key":"name","field_value":"新标题"}]}'
217
372
 
218
373
  # 同时修改多个字段
219
374
  meegle workitem update --work-item-id 12345 \
220
- --set name=新标题 \
221
- --set priority=P0
375
+ --params '{"fields":[
376
+ {"field_key":"name","field_value":"新标题"},
377
+ {"field_key":"priority","field_value":"P0"}
378
+ ]}'
379
+ ```
380
+
381
+ ### 附件上传 / 下载
382
+
383
+ `attachment` 域把飞书项目的两段式附件协议拆成两层暴露:
384
+
385
+ - **基础命令**(`attachment prepare-upload` / `attachment prepare-download`)
386
+ 返回带签名的 URL 预处理结果——适合自己写脚本做 HTTP 传输或调试分片计划。
387
+ - **快捷命令**(`attachment +upload` / `attachment +download`)把基础预处理与
388
+ 签名后的对象存储 HTTP POST/GET 在客户端组合成端到端流程。`+` 前缀表示这是
389
+ 场景命令——CLI 在客户端把预处理输出与字节传输串起来。
390
+
391
+ `--resource-type` 告诉后端这次上传/下载是给什么场景用:
392
+
393
+ | `--resource-type` | 用途 |
394
+ |-------------------|------|
395
+ | `15` | 工作项附件字段 |
396
+ | `16` | 工作项富文本字段里的图片 |
397
+ | `13` | 评论附件 |
398
+ | `14` | 评论正文里的图片 |
399
+
400
+ **上传作用域**:每次上传需要 `--work-item-id` 或 `--work-item-type` 之一。
401
+ **只要工作项已经存在,就优先用 `--work-item-id`**(update / comment 场景);
402
+ 只有创建时带附件这种"工作项还不存在"的场景才用 `--work-item-type`。两者都传时,
403
+ `--work-item-id` 胜出,`--work-item-type` 被静默丢弃。
404
+
405
+ ```bash
406
+ # 为工作项附件字段上传文件 (resource-type 15)
407
+ meegle attachment +upload ./a.pdf \
408
+ --resource-type 15 \
409
+ --project-key PROJ --work-item-id 12345 --field-key files_field
410
+
411
+ # 创建时带附件场景 —— 工作项还不存在,用 --work-item-type
412
+ meegle attachment +upload ./a.pdf \
413
+ --resource-type 15 \
414
+ --project-key PROJ --work-item-type story --field-key files_field
415
+
416
+ # 为富文本字段上传图片 (resource-type 16)
417
+ meegle attachment +upload ./diagram.png \
418
+ --resource-type 16 \
419
+ --project-key PROJ --work-item-id 12345 --field-key spec_field
420
+
421
+ # 为评论上传附件 (resource-type 13)
422
+ meegle attachment +upload ./report.pdf \
423
+ --resource-type 13 \
424
+ --project-key PROJ --work-item-id 12345
425
+
426
+ # 为评论上传图片 (resource-type 14)
427
+ meegle attachment +upload ./screen.png \
428
+ --resource-type 14 \
429
+ --project-key PROJ --work-item-id 12345
430
+
431
+ # 下载:把其他命令响应里的 opaque file_url 直接传进来。
432
+ URL=$(meegle workitem get --project-key PROJ --work-item-id 12345 \
433
+ --fields files_field --format json \
434
+ | jq -r '.fields.files_field[0].url')
435
+ meegle attachment +download "$URL" \
436
+ --project-key PROJ --work-item-id 12345 \
437
+ --output ./local.pdf --overwrite
438
+ ```
439
+
440
+ `+upload` 输出 JSON 对象,包含 file_token 与文件元信息:
441
+
442
+ ```json
443
+ {
444
+ "file_token": "...",
445
+ "file_url": "https://...",
446
+ "name": "a.pdf",
447
+ "size": 12345,
448
+ "mime_type": "application/pdf"
449
+ }
450
+ ```
451
+
452
+ 要把结果拼到下游命令里,用 `jq` 或脚本语言提取所需字段:
453
+
454
+ ```bash
455
+ # 评论附件 —— comment add 直接接收 file_token
456
+ TOKEN=$(meegle attachment +upload ./report.pdf --resource-type 13 \
457
+ --project-key PROJ --work-item-id 12345 | jq -r '.file_token')
458
+ meegle comment add --work-item-id 12345 --content "看附件" --file-token "$TOKEN"
222
459
  ```
223
460
 
461
+ **字段级回灌格式**(拼接 `--fields` 时参考):
462
+
463
+ - **工作项附件字段** (`--resource-type 15`) —— `field_value` 是 JSON *字符串*,
464
+ 解析后是 `[{"name","type","size","fileToken"}]`。注意:`fileToken` 是驼峰(其他
465
+ 后端字段都是蛇形),`size` 是字符串不是数字。
466
+ - **富文本字段 / 评论图片** (`--resource-type 16` / `14`) —— 图片用
467
+ `![name](file_url) <!-- file_token -->` 的 markdown 嵌入。
468
+ - **评论附件** (`--resource-type 13`) —— `comment add --file-token` 直接接收
469
+ `file_token`。
470
+
224
471
  ### MQL 搜索
225
472
 
226
473
  ```bash
@@ -254,19 +501,31 @@ meegle user search --user-keys "张三,李四" --project-key PROJ
254
501
  meegle workitem get --work-item-id 12345 --project-key PROJ
255
502
  ```
256
503
 
257
- ### --set key=value(写入命令)
504
+ ### `fields[]`(写入命令)
505
+
506
+ `workitem create`、`workitem update`、`workflow update-node`、`subtask update` 需要传 `fields[]`,通过 `--params` 走:
507
+
508
+ ```bash
509
+ --params '{"fields":[
510
+ {"field_key":"name","field_value":"标题"},
511
+ {"field_key":"priority","field_value":"P1"}
512
+ ]}'
513
+ ```
514
+
515
+ ### --set key=value(通用)
258
516
 
259
- `workitem create`、`workitem update`、`workflow update-node`、`subtask update` 支持 `--set` 简便设置字段:
517
+ `--set` 是普通 flag 的**替代写法**,只影响**顶层参数**:`--set key=value` 等价于 `--key value`。适合在脚本里用统一的 key=value 语法,或通过 dot-path 写嵌套顶层对象。值自动类型推断(int / float / bool / string)。
260
518
 
261
519
  ```bash
262
- --set name=标题 # 字符串
263
- --set points=5 # 数字
264
- --set is_urgent=true # 布尔
265
- --set schedule='[1,2]' # JSON 数组
266
- --set role='{"role":"RD"}' # JSON 对象
520
+ # 下面两种等价:
521
+ meegle mywork todo --action this_week --page-num 1
522
+ meegle mywork todo --set action=this_week --set page_num=1
523
+
524
+ # dot-path 嵌套(Meegle 很少用到,但支持):
525
+ --set extra.flag=true # 变成 {"extra":{"flag":true}}
267
526
  ```
268
527
 
269
- `--set` 可重复使用,一次设置多个字段。
528
+ `--set` 只写**顶层参数**,**不会**写到工作项的 `fields[]`。写 `fields[]` 请用 `--params '{"fields":[...]}'`(见下)。
270
529
 
271
530
  ### --params JSON(兜底)
272
531
 
@@ -277,12 +536,32 @@ meegle workitem create --project-key PROJ --work-item-type story \
277
536
  --params '{"fields":[{"field_key":"name","field_value":"标题"}]}'
278
537
  ```
279
538
 
539
+ #### 从文件读取(`@file.json`)
540
+
541
+ Windows 上内联 JSON 体验很糟:CMD 必须把 `"` 写成 `\"`,PowerShell 把转义反斜杠传给原生命令时还会再吞一层。给 `--params` 加 `@` 前缀即可改为从文件读取,macOS、Linux、Windows 各种 shell 都能一致工作:
542
+
543
+ ```bash
544
+ # body.json:
545
+ # {"fields":[{"field_key":"name","field_value":"优化登录流程"}]}
546
+
547
+ meegle workitem create --project-key PROJ --work-item-type story \
548
+ --params @body.json
549
+
550
+ # 绝对路径同样支持
551
+ meegle workitem update --work-item-id 12345 --params @/tmp/patch.json
552
+
553
+ # PowerShell 用法相同,无需任何转义
554
+ meegle workitem create --project-key PROJ --work-item-type story --params '@body.json'
555
+ ```
556
+
557
+ 读取走系统默认编码,相对路径与绝对路径都接受。文件不存在会返回 `PARAM_INVALID`;文件内容不是合法 JSON 会返回 `INVALID_PARAMS_JSON`。
558
+
280
559
  ### 优先级
281
560
 
282
561
  当 `--set`、`--params` 和普通 flag 同时使用时:
283
562
 
284
- 1. `--set` 覆盖 `--params` 中同名字段
285
- 2. 普通 flag(如 `--project-key`)覆盖 `--params` 中同名顶层 key
563
+ 1. 普通 CLI flag 覆盖 `--params` / `--set` 中同名顶层 key
564
+ 2. `--set` 覆盖 `--params` 中同名顶层 key
286
565
 
287
566
  ### 数组参数
288
567
 
@@ -305,55 +584,71 @@ meegle workflow get-node --work-item-id 12345 --need-sub-task
305
584
 
306
585
  | Flag | 缩写 | 说明 |
307
586
  |------|------|------|
308
- | `--format` | `-o` | 输出格式:`json`(默认)、`table`、`ndjson`、`yaml`、`markdown`、`raw` |
587
+ | `--format` | `-o` | 输出格式:`json`(默认)、`table`、`ndjson`、`raw` |
309
588
  | `--select` | | 字段投影(支持 dot path) |
310
589
  | `--set` | | 设置嵌套参数(可重复) |
311
- | `--params` | `-P` | 完整 JSON 参数体 |
590
+ | `--params` | `-P` | 完整 JSON 参数体;以 `@` 开头改为从文件读取(如 `--params @body.json`) |
312
591
  | `--dry-run` | | 只渲染请求,不实际执行 |
313
592
  | `--verbose` | `-v` | 详细输出 |
314
593
  | `--profile` | | 指定配置 profile |
594
+ | `--refresh` | | 从服务端刷新本地命令缓存(旁路 24 小时缓存) |
315
595
 
316
- ## 输出格式
596
+ ## 进阶用法
597
+
598
+ ### 输出格式
317
599
 
318
600
  ```bash
319
601
  # JSON(默认)
320
602
  meegle workitem get --work-item-id 12345
321
603
 
322
- # 选取输出属性(支持 dot path)
323
- meegle workitem get --work-item-id 12345 --select "id,name,status"
324
- meegle mywork todo --action done --page-num 1 --select "list.work_item_info.work_item_name"
325
-
326
604
  # NDJSON(适合管道处理)
327
605
  meegle mywork todo --action this_week --page-num 1 -o ndjson
328
606
 
329
607
  # 表格
330
608
  meegle mywork todo --action this_week --page-num 1 -o table
609
+ ```
610
+
611
+ ### `--select` 字段投影
612
+
613
+ `--select` 按 `.` 分段做字段投影;数组之后的下一段会对数组中每个元素广播(broadcast)剩余路径,并保留原来的嵌套结构。
331
614
 
332
- # YAML
333
- meegle workitem get --work-item-id 12345 -o yaml
615
+ | 表达式 | 响应 | 投影结果 |
616
+ |---|---|---|
617
+ | `list` | `{"list":[{"a":1}], "total":1}` | `{"list":[{"a":1}]}` |
618
+ | `list.a` | `{"list":[{"a":1,"b":2},{"a":3,"b":4}]}` | `{"list":[{"a":1},{"a":3}]}` |
619
+ | `list.a,list.b` | 同上 | `{"list":[{"a":1,"b":2},{"a":3,"b":4}]}`(多路径按下标合并) |
620
+ | `list.work_item_info.work_item_name` | `{"list":[{"work_item_info":{"work_item_name":"x"}}]}` | `{"list":[{"work_item_info":{"work_item_name":"x"}}]}` |
621
+ | `nodes.0` | `{"nodes":[{"id":"a"},{"id":"b"}]}` | `{"nodes":{"0":{"id":"a"}}}`(数字段按索引) |
334
622
 
335
- # Markdown 表格
336
- meegle mywork todo --action this_week --page-num 1 -o markdown
623
+ ```bash
624
+ # 顶层选择
625
+ meegle workitem get --work-item-id 12345 --select "id,name,status"
337
626
 
338
- # Dry run(预览请求,不实际发送)
339
- meegle workitem create --project-key PROJ --work-item-type story --set name="测试" --dry-run
627
+ # 跨数组广播 —— 从嵌套记录里提取字段
628
+ meegle mywork todo --action done --page-num 1 \
629
+ --select "list.work_item_info.work_item_name,list.state_info.end_state_key_name"
630
+
631
+ # 顶层元数据 + 广播混合 —— total 和投影后的 list 记录会同时保留
632
+ meegle mywork todo --action done --page-num 1 \
633
+ --select "total,list.work_item_info.work_item_name"
340
634
  ```
341
635
 
342
- ### --select dot path
636
+ ### 元数据保留
343
637
 
344
- `--select` 支持用 `.` 访问嵌套属性,遇到数组时自动穿透:
638
+ 默认渲染下,响应的完整结构在所有 `--format` 中都会保留:列表接口返回的 `{"list":[...], "total":N, "pagination":{...}}` 原样呈现 —— 即使你没有在 `--select` 中点名,`total` / `pagination` 这些元数据字段依然可见。要钻到具体记录就显式用 `--select`(配合上面的广播语法)。`--format table` 和 `--format ndjson` 下,形如 `{"list":[...]}` 的单键包装(没有兄弟元数据)仍然会被无损展开成行展示。
345
639
 
346
- ```bash
347
- # 从嵌套结构中提取字段
348
- --select "list.work_item_info.work_item_name,list.state_info.end_state_key_name"
640
+ ### Dry Run
349
641
 
350
- # 混合顶层和嵌套
351
- --select "total,list.work_item_info.work_item_name"
642
+ 有副作用的命令先用 `--dry-run` 预览请求再执行:
643
+
644
+ ```bash
645
+ meegle workitem create --project-key PROJ --work-item-type story \
646
+ --params '{"fields":[{"field_key":"name","field_value":"测试"}]}' --dry-run
352
647
  ```
353
648
 
354
- ## 命令内省
649
+ ### 命令内省
355
650
 
356
- 使用 `inspect` 查看命令的完整参数信息:
651
+ `inspect` 查看任意命令的完整参数信息:
357
652
 
358
653
  ```bash
359
654
  # 列出所有命令
@@ -418,6 +713,7 @@ meegle config get host
418
713
  | `host` | 站点域名 | `project.feishu.cn`、`meegle.com` |
419
714
  | `user_access_token` | 用户访问令牌,支持 `${VAR}` 从环境变量读取 | `${CI_MEEGLE_TOKEN}` |
420
715
  | `access_token_header` | 自定义承载 token 的 HTTP header 名;置空则用默认的 `Authorization: Bearer <token>` | `x-meegle-auth` |
716
+ | `user_agent` | 追加到 `User-Agent` 的 caller 段(形如 `meegle-cli/<ver> <user_agent>`);支持 `${VAR}` 模板;被环境变量 `MEEGLE_USER_AGENT` 覆盖 | `my-service/1.0` |
421
717
 
422
718
  ### 沙盒 / CI:直接注入环境变量
423
719
 
@@ -426,7 +722,8 @@ meegle config get host
426
722
  ```bash
427
723
  export MEEGLE_HOST=project.feishu.cn
428
724
  export MEEGLE_USER_ACCESS_TOKEN=<your-user-token>
429
- meegle workitem get-brief --work_item_id 123
725
+ export MEEGLE_USER_AGENT=ci-runner # 可选;追加到 User-Agent,优先级高于 config.user_agent
726
+ meegle workitem get --work-item-id 123
430
727
  ```
431
728
 
432
729
  任一变量可以单独设置。走这个路径时 CLI 不访问 keychain,401 错误不会自动 refresh,由调用方自行轮转。
@@ -502,6 +799,26 @@ meegle auth login
502
799
 
503
800
  命令列表会自动缓存,过期后在后台静默刷新,不影响使用。
504
801
 
802
+ ## 安全与风险提示
803
+
804
+ 本工具被设计为可由 AI Agent 调用来自动化 Meegle 操作,这本身就带有模型幻觉、执行不可控、提示词注入等固有风险。一旦你授予了 Meegle 访问权限,Agent 就会在授权范围内以你的用户身份行事,可能完成字段更新、状态流转、工作项创建等高影响操作,使用前请充分评估。
805
+
806
+ 推荐的风险控制手段:
807
+
808
+ - 有副作用的命令先用 `--dry-run` 预览请求再正式执行
809
+ - 给 Agent 专用 profile(`meegle config profile create`),便于单独审计和吊销
810
+ - CI 或共享环境优先使用短期环境变量 token(`MEEGLE_USER_ACCESS_TOKEN`),401 时自行轮换;不要放松默认安全设置
811
+
812
+ 使用本工具即视为你自愿承担由此带来的全部相关责任。
813
+
814
+ ## Star History
815
+
816
+ [![Star History Chart](https://api.star-history.com/svg?repos=larksuite/meegle-cli&type=Date)](https://star-history.com/#larksuite/meegle-cli&Date)
817
+
818
+ ## 贡献
819
+
820
+ 欢迎社区贡献。Bug 反馈或功能建议请提 [Issue](https://github.com/larksuite/meegle-cli/issues) 或 [Pull Request](https://github.com/larksuite/meegle-cli/pulls)。对于较大改动,建议先通过 Issue 讨论。
821
+
505
822
  ## License
506
823
 
507
824
  本项目基于 **MIT 许可证** 开源。
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/bin/meegle.js CHANGED
@@ -1,8 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  const { spawnSync } = require("child_process");
3
+ const fs = require("fs");
3
4
  const os = require("os");
4
5
  const path = require("path");
5
6
 
7
+ const SUPPORTED = [
8
+ "darwin-arm64", "darwin-x64",
9
+ "linux-arm64", "linux-x64",
10
+ "win32-arm64", "win32-x64",
11
+ ];
12
+
6
13
  const platform = os.platform();
7
14
  const arch = os.arch();
8
15
  const ext = platform === "win32" ? ".exe" : "";
@@ -10,15 +17,28 @@ const binName = `meegle-${platform}-${arch}${ext}`;
10
17
  const binPath = path.join(__dirname, binName);
11
18
 
12
19
  try {
13
- require("fs").accessSync(binPath, require("fs").constants.X_OK);
20
+ fs.accessSync(binPath, fs.constants.X_OK);
14
21
  } catch {
22
+ const detected = `${platform}-${arch}`;
23
+ const isSupported = SUPPORTED.includes(detected);
15
24
  console.error(
16
- `Unsupported platform: ${platform}-${arch}\n` +
17
- `Expected binary at: ${binPath}\n` +
18
- `Supported: darwin-arm64, darwin-x64, linux-arm64, linux-x64, win32-x64, win32-arm64`
25
+ isSupported
26
+ ? `meegle binary is missing or not executable.\n` +
27
+ `Detected platform: ${detected}\n` +
28
+ `Expected binary at: ${binPath}\n` +
29
+ `Try reinstalling: npm i -g @lark-project/meegle\n` +
30
+ `If the problem persists, please file an issue with the output of: node -v && npm -v`
31
+ : `Unsupported platform: ${detected}\n` +
32
+ `Supported platforms: ${SUPPORTED.join(", ")}`
19
33
  );
20
34
  process.exit(1);
21
35
  }
22
36
 
23
37
  const result = spawnSync(binPath, process.argv.slice(2), { stdio: "inherit" });
38
+
39
+ // Re-raise the signal so parent shells see the real cause (e.g. 130 for SIGINT)
40
+ // instead of a generic exit 1.
41
+ if (result.signal) {
42
+ process.kill(process.pid, result.signal);
43
+ }
24
44
  process.exit(result.status ?? 1);