Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@

[中文版](./README.zh.md) | [English](./README.md)

The official [Lark/Feishu](https://www.larksuite.com/) CLI tool, maintained by the [larksuite](https://github.com/larksuite) team — built for humans and AI Agents. Covers core business domains including Messenger, Docs, Base, Sheets, Slides, Calendar, Mail, Tasks, Meetings, and more, with 200+ commands and 22 AI Agent [Skills](./skills/).
The official [Lark/Feishu](https://www.larksuite.com/) CLI tool, maintained by the [larksuite](https://github.com/larksuite) team — built for humans and AI Agents. Covers core business domains including Messenger, Docs, Base, Sheets, Slides, Calendar, Mail, Tasks, Meetings, and more, with 200+ commands and 23 AI Agent [Skills](./skills/).

[Install](#installation--quick-start) · [AI Agent Skills](#agent-skills) · [Auth](#authentication) · [Commands](#three-layer-command-system) · [Advanced](#advanced-usage) · [Security](#security--risk-warnings-read-before-use) · [Contributing](#contributing)

## Why lark-cli?

- **Agent-Native Design** — 22 structured [Skills](./skills/) out of the box, compatible with popular AI tools — Agents can operate Lark with zero extra setup
- **Wide Coverage** — 14 business domains, 200+ curated commands, 22 AI Agent [Skills](./skills/)
- **Wide Coverage** — 15 business domains, 200+ curated commands, 23 AI Agent [Skills](./skills/)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- **AI-Friendly & Optimized** — Every command is tested with real Agents, featuring concise parameters, smart defaults, and structured output to maximize Agent call success rates
- **Open Source, Zero Barriers** — MIT license, ready to use, just `npm install`
- **Up and Running in 3 Minutes** — One-click app creation, interactive login, from install to first API call in just 3 steps
Expand All @@ -38,7 +38,7 @@ The official [Lark/Feishu](https://www.larksuite.com/) CLI tool, maintained by t
| 🎥 Meetings | Search meeting records, query meeting minutes & recordings |
| 🕐 Attendance | Query personal attendance check-in records |
| ✍️ Approval | Query approval tasks, approve/reject/transfer tasks, cancel and CC instances |
| 🎯 OKR | Query, create, update OKRs; manage objective & key results, alignments and indicators. |
| 🎯 OKR | Query, create, update OKRs; manage objective & key results, alignments, indicators and progress. |

## Installation & Quick Start

Expand Down Expand Up @@ -132,14 +132,14 @@ lark-cli auth status
## Agent Skills

| Skill | Description |
| ------------------------------- |----------------------------------------------------------------------------------------------------------------|
|---------------------------------|----------------------------------------------------------------------------------------------------------------|
| `lark-shared` | App config, auth login, identity switching, scope management, security rules (auto-loaded by all other skills) |
| `lark-calendar` | Calendar events, agenda view, free/busy queries, time suggestions |
| `lark-im` | Send/reply messages, group chat management, message search, upload/download images & files, reactions |
| `lark-doc` | Create, read, update, search documents (Markdown-based) |
| `lark-drive` | Upload, download files, manage permissions & comments |
| `lark-sheets` | Create, read, write, append, find, export spreadsheets |
| `lark-slides` | Create and manage presentations, read presentation content, and add or remove slides |
| `lark-slides` | Create and manage presentations, read presentation content, and add or remove slides |
| `lark-base` | Tables, fields, records, views, dashboards, data aggregation & analytics |
| `lark-task` | Tasks, task lists, subtasks, reminders, member assignment |
| `lark-mail` | Browse, search, read emails, send, reply, forward, draft management, watch new mail |
Expand All @@ -155,6 +155,7 @@ lark-cli auth status
| `lark-approval` | Query approval tasks, approve/reject/transfer tasks, cancel and CC instances |
| `lark-workflow-meeting-summary` | Workflow: meeting minutes aggregation & structured report |
| `lark-workflow-standup-report` | Workflow: agenda & todo summary |
| `lark-okr` | Query, create, update OKRs; manage objective & key results, alignments and indicators. |
Comment thread
coderabbitai[bot] marked this conversation as resolved.

## Authentication

Expand Down
41 changes: 21 additions & 20 deletions README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@

[中文版](./README.zh.md) | [English](./README.md)

飞书官方 CLI 工具,由 [larksuite](https://github.com/larksuite) 团队维护 — 让人类和 AI Agent 都能在终端中操作飞书。覆盖消息、文档、多维表格、电子表格、幻灯片、日历、邮箱、任务、会议等核心业务域,提供 200+ 命令及 22 个 AI Agent [Skills](./skills/)。
飞书官方 CLI 工具,由 [larksuite](https://github.com/larksuite) 团队维护 — 让人类和 AI Agent 都能在终端中操作飞书。覆盖消息、文档、多维表格、电子表格、幻灯片、日历、邮箱、任务、会议等核心业务域,提供 200+ 命令及 23 个 AI Agent [Skills](./skills/)。

[安装](#安装与快速开始) · [AI Agent Skills](#agent-skills) · [认证](#认证) · [命令](#三层命令调用) · [进阶用法](#进阶用法) · [安全](#安全与风险提示使用前必读) · [贡献](#贡献)

## 为什么选 lark-cli?

- **为 Agent 原生设计** — 22 个 [Skills](./skills/) 开箱即用,适配主流 AI 工具,Agent 无需额外适配即可操作飞书
- **覆盖面广** — 14 大业务域、200+ 精选命令、22 个 AI Agent [Skills](./skills/)
- **覆盖面广** — 15 大业务域、200+ 精选命令、23 个 AI Agent [Skills](./skills/)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- **AI 友好调优** — 每条命令经过 Agent 实测验证,提供更友好的参数、智能默认值和结构化输出,大幅提升 Agent 调用成功率
- **开源零门槛** — MIT 协议,开箱即用,`npm install` 即可使用
- **三分钟上手** — 一键创建应用、交互式登录授权,从安装到第一次 API 调用只需三步
Expand All @@ -22,23 +22,23 @@

## 功能

| 类别 | 能力 |
| ------------- |--------------------------------------------|
| 📅 日历 | 查看日程、创建日程、邀请参会人、查询忙闲状态、时间建议 |
| 💬 即时通讯 | 发送/回复消息、创建和管理群聊、查看聊天记录与话题、搜索消息、下载媒体文件 |
| 📄 云文档 | 创建、读取、更新文档、搜索文档、读写素材与画板 |
| 📁 云空间 | 上传和下载文件、搜索文档与知识库、管理评论 |
| 类别 | 能力 |
| ------------- |------------------------------------------|
| 📅 日历 | 查看日程、创建日程、邀请参会人、查询忙闲状态、时间建议 |
| 💬 即时通讯 | 发送/回复消息、创建和管理群聊、查看聊天记录与话题、搜索消息、下载媒体文件 |
| 📄 云文档 | 创建、读取、更新文档、搜索文档、读写素材与画板 |
| 📁 云空间 | 上传和下载文件、搜索文档与知识库、管理评论 |
| 📊 多维表格 | 创建和管理数据表、字段、记录、视图、仪表盘、自动化流程、表单、角色权限,数据聚合分析 |
| 📈 电子表格 | 创建、读取、写入、追加、查找和导出表格数据 |
| 🖼️ 幻灯片 | 创建和管理演示文稿、读取演示文稿内容,以及新增或删除幻灯片页面 |
| ✅ 任务 | 创建、查询、更新和完成任务;管理任务清单、子任务、评论与提醒 |
| 📚 知识库 | 创建和管理知识空间、节点和文档 |
| 👤 通讯录 | 按姓名/邮箱/手机号搜索用户、获取用户信息 |
| 📧 邮箱 | 浏览、搜索、阅读邮件,发送、回复、转发邮件,管理草稿,监听新邮件 |
| 🎥 视频会议 | 搜索会议记录、查询会议纪要与录制 |
| 🕐 考勤打卡 | 查询个人考勤打卡记录 |
| ✍️ 审批 | 查询审批任务、同意/拒绝/转交审批任务、撤回与抄送审批实例 |
| 🎯 OKR | 查询、创建、更新 OKR,管理目标、关键结果、对齐和指标 |
| 📈 电子表格 | 创建、读取、写入、追加、查找和导出表格数据 |
| 🖼️ 幻灯片 | 创建和管理演示文稿、读取演示文稿内容,以及新增或删除幻灯片页面 |
| ✅ 任务 | 创建、查询、更新和完成任务;管理任务清单、子任务、评论与提醒 |
| 📚 知识库 | 创建和管理知识空间、节点和文档 |
| 👤 通讯录 | 按姓名/邮箱/手机号搜索用户、获取用户信息 |
| 📧 邮箱 | 浏览、搜索、阅读邮件,发送、回复、转发邮件,管理草稿,监听新邮件 |
| 🎥 视频会议 | 搜索会议记录、查询会议纪要与录制 |
| 🕐 考勤打卡 | 查询个人考勤打卡记录 |
| ✍️ 审批 | 查询审批任务、同意/拒绝/转交审批任务、撤回与抄送审批实例 |
| 🎯 OKR | 查询、创建、更新 OKR,管理目标、关键结果、对齐、指标和进展记录 |

## 安装与快速开始

Expand Down Expand Up @@ -133,14 +133,14 @@ lark-cli auth status
## Agent Skills

| Skill | 说明 |
| --------------------------------- |-------------------------------------------|
|---------------------------------|-------------------------------------------|
| `lark-shared` | 应用配置、认证登录、身份切换、权限管理、安全规则(所有其他 skill 自动加载) |
| `lark-calendar` | 日历日程、议程查看、忙闲查询、时间建议 |
| `lark-im` | 发送/回复消息、群聊管理、消息搜索、上传下载图片与文件、表情回复 |
| `lark-doc` | 创建、读取、更新、搜索文档(基于 Markdown) |
| `lark-drive` | 上传、下载文件,管理权限与评论 |
| `lark-sheets` | 创建、读取、写入、追加、查找、导出电子表格 |
| `lark-slides` | 创建和管理演示文稿、读取演示文稿内容,以及新增或删除幻灯片页面 |
| `lark-slides` | 创建和管理演示文稿、读取演示文稿内容,以及新增或删除幻灯片页面 |
| `lark-base` | 多维表格、字段、记录、视图、仪表盘、数据聚合分析 |
| `lark-task` | 任务、任务清单、子任务、提醒、成员分配 |
| `lark-mail` | 浏览、搜索、阅读邮件,发送、回复、转发,草稿管理,监听新邮件 |
Expand All @@ -156,6 +156,7 @@ lark-cli auth status
| `lark-approval` | 审批任务查询、同意/拒绝/转交审批任务、撤回与抄送审批实例 |
| `lark-workflow-meeting-summary` | 工作流:会议纪要汇总与结构化报告 |
| `lark-workflow-standup-report` | 工作流:日程待办摘要 |
| `lark-okr` | 查询、创建、更新 OKR,管理目标、关键结果、对齐、指标和进展记录 |

## 认证

Expand Down
2 changes: 1 addition & 1 deletion internal/registry/service_descriptions.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,6 @@
},
"okr": {
"en": { "title": "OKR", "description": "Lark OKR objectives, key results, alignments, indicators" },
"zh": { "title": "OKR", "description": "飞书 OKR 目标、关键结果、对齐、量化指标" }
"zh": { "title": "OKR", "description": "飞书 OKR 目标、关键结果、对齐、量化指标、进展记录" }
Comment on lines 68 to +69
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Keep okr EN/ZH descriptions semantically aligned.
zh now includes progress records, but en does not. This creates localized capability mismatch.

Suggested fix
-    "en": { "title": "OKR", "description": "Lark OKR objectives, key results, alignments, indicators" },
+    "en": { "title": "OKR", "description": "Lark OKR objectives, key results, alignments, indicators, progress records" },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"en": { "title": "OKR", "description": "Lark OKR objectives, key results, alignments, indicators" },
"zh": { "title": "OKR", "description": "飞书 OKR 目标、关键结果、对齐、量化指标" }
"zh": { "title": "OKR", "description": "飞书 OKR 目标、关键结果、对齐、量化指标、进展记录" }
"en": { "title": "OKR", "description": "Lark OKR objectives, key results, alignments, indicators, progress records" },
"zh": { "title": "OKR", "description": "飞书 OKR 目标、关键结果、对齐、量化指标、进展记录" }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/registry/service_descriptions.json` around lines 68 - 69, The EN and
ZH entries for the "OKR" service in service_descriptions.json are semantically
mismatched: the "zh" description mentions progress records while "en" does not;
update the "en" description for the "OKR" entry (the object under key "en"
alongside "zh") to include the same capabilities (e.g., add "progress records"
or equivalent phrase) so both locales describe the same features, or
alternatively remove "progress records" from the "zh" description to keep them
aligned—edit the "en" description string to mirror the ZH items (object title
"OKR", description field).

}
}
53 changes: 53 additions & 0 deletions shortcuts/okr/okr_cli_resp.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,56 @@
OwnerType string `json:"owner_type"`
UserID *string `json:"user_id,omitempty"`
}

// ProgressStatus 进展状态
type ProgressStatus int32

const (
ProgressStatusNormal ProgressStatus = 0 // 正常
ProgressStatusOverdue ProgressStatus = 1 // 逾期
ProgressStatusDone ProgressStatus = 2 // 已完成
)

// ParseProgressStatus parses a progress status string into ProgressStatus.
// Accepts "normal", "overdue", "done" or their numeric values "0", "1", "2".
func ParseProgressStatus(s string) (ProgressStatus, bool) {
switch s {
case "normal", "0":
return ProgressStatusNormal, true
case "overdue", "1":
return ProgressStatusOverdue, true
case "done", "2":
return ProgressStatusDone, true
default:
return 0, false
}
}

// String returns a human-readable name for ProgressStatus.
func (s ProgressStatus) String() string {
switch s {
case ProgressStatusNormal:
return "normal"
case ProgressStatusOverdue:
return "overdue"
case ProgressStatusDone:
return "done"
default:
return ""

Check warning on line 137 in shortcuts/okr/okr_cli_resp.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/okr/okr_cli_resp.go#L136-L137

Added lines #L136 - L137 were not covered by tests
}
}

// RespProgressRate 进度率(面向用户的响应格式,Status 为可读字符串)
type RespProgressRate struct {
Percent *float64 `json:"percent,omitempty"`
Status *string `json:"status,omitempty"`
}

// RespProgress 进展记录
type RespProgress struct {
ID string `json:"progress_id"`
ModifyTime string `json:"modify_time"`
CreateTime *string `json:"create_time,omitempty"`
Content *string `json:"content,omitempty"`
ProgressRate *RespProgressRate `json:"progress_rate,omitempty"`
}
146 changes: 146 additions & 0 deletions shortcuts/okr/okr_image_upload.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT

package okr

import (
"context"
"encoding/json"
"errors"
"fmt"
"path/filepath"
"strconv"
"strings"

larkcore "github.com/larksuite/oapi-sdk-go/v3/core"

"github.com/larksuite/cli/internal/output"
"github.com/larksuite/cli/shortcuts/common"
)

// allowedImageExts lists the file extensions supported by the OKR image upload API.
var allowedImageExts = map[string]bool{
".jpg": true,
".jpeg": true,
".png": true,
".gif": true,
".bmp": true,
}

// OKRUploadImage uploads an image for use in OKR progress rich text.
var OKRUploadImage = common.Shortcut{
Service: "okr",
Command: "+upload-image",
Description: "Upload an image for use in OKR progress rich text",
Risk: "write",
Scopes: []string{"okr:okr.progress.file:upload"},
AuthTypes: []string{"user", "bot"},
Flags: []common.Flag{
{Name: "file", Desc: "local image path (supports JPG, JPEG, PNG, GIF, BMP)", Required: true},
{Name: "target-id", Desc: "target ID (objective or key result ID) for the progress", Required: true},
{Name: "target-type", Desc: "target type: objective | key_result", Required: true, Enum: []string{"objective", "key_result"}},
},
Validate: func(ctx context.Context, runtime *common.RuntimeContext) error {
filePath := runtime.Str("file")
if filePath == "" {
return common.FlagErrorf("--file is required")
}

Check warning on line 47 in shortcuts/okr/okr_image_upload.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/okr/okr_image_upload.go#L46-L47

Added lines #L46 - L47 were not covered by tests
ext := strings.ToLower(filepath.Ext(filePath))
if !allowedImageExts[ext] {
return common.FlagErrorf("--file must be an image (supported: JPG, JPEG, PNG, GIF, BMP), got %q", ext)
}
Comment thread
syh-cpdsss marked this conversation as resolved.

targetID := runtime.Str("target-id")
if targetID == "" {
return common.FlagErrorf("--target-id is required")
}

Check warning on line 56 in shortcuts/okr/okr_image_upload.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/okr/okr_image_upload.go#L55-L56

Added lines #L55 - L56 were not covered by tests
if id, err := strconv.ParseInt(targetID, 10, 64); err != nil || id <= 0 {
return common.FlagErrorf("--target-id must be a positive int64")
}

targetType := runtime.Str("target-type")
if _, ok := targetTypeAllowed[targetType]; !ok {
return common.FlagErrorf("--target-type must be one of: objective | key_result")
}

Check warning on line 64 in shortcuts/okr/okr_image_upload.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/okr/okr_image_upload.go#L63-L64

Added lines #L63 - L64 were not covered by tests
return nil
},
DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI {
filePath := runtime.Str("file")
targetID := runtime.Str("target-id")
targetType := runtime.Str("target-type")
targetTypeVal := targetTypeAllowed[targetType]

return common.NewDryRunAPI().
POST("/open-apis/okr/v1/images/upload").
Body(map[string]interface{}{
"file": "@" + filePath,
"target_id": targetID,
"target_type": targetTypeVal,
}).
Desc(fmt.Sprintf("Upload image for OKR %s %s", targetType, targetID))
},
Execute: func(ctx context.Context, runtime *common.RuntimeContext) error {
filePath := runtime.Str("file")
targetID := runtime.Str("target-id")
targetType := runtime.Str("target-type")
targetTypeVal := targetTypeAllowed[targetType]

info, err := runtime.FileIO().Stat(filePath)
if err != nil {
return common.WrapInputStatError(err)
}

f, err := runtime.FileIO().Open(filePath)
if err != nil {
return common.WrapInputStatError(err)
}

Check warning on line 96 in shortcuts/okr/okr_image_upload.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/okr/okr_image_upload.go#L95-L96

Added lines #L95 - L96 were not covered by tests
defer f.Close()

fileName := filepath.Base(filePath)
fmt.Fprintf(runtime.IO().ErrOut, "Uploading: %s (%s)\n", fileName, common.FormatSize(info.Size()))

fd := larkcore.NewFormdata()
fd.AddField("target_id", targetID)
fd.AddField("target_type", fmt.Sprintf("%d", targetTypeVal))
fd.AddFile("data", f)

apiResp, err := runtime.DoAPI(&larkcore.ApiReq{
HttpMethod: "POST",
ApiPath: "/open-apis/okr/v1/images/upload",
Body: fd,
}, larkcore.WithFileUpload())
if err != nil {
var exitErr *output.ExitError
if errors.As(err, &exitErr) {
return err
}
return output.ErrNetwork("upload failed: %v", err)

Check warning on line 117 in shortcuts/okr/okr_image_upload.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/okr/okr_image_upload.go#L113-L117

Added lines #L113 - L117 were not covered by tests
}

var result map[string]interface{}
if err := json.Unmarshal(apiResp.RawBody, &result); err != nil {
return output.Errorf(output.ExitAPI, "api_error", "upload failed: invalid response JSON: %v", err)
}

Check warning on line 123 in shortcuts/okr/okr_image_upload.go

View check run for this annotation

Codecov / codecov/patch

shortcuts/okr/okr_image_upload.go#L122-L123

Added lines #L122 - L123 were not covered by tests

if larkCode := int(common.GetFloat(result, "code")); larkCode != 0 {
msg, _ := result["msg"].(string)
return output.ErrAPI(larkCode, fmt.Sprintf("upload failed: [%d] %s", larkCode, msg), result["error"])
}

data, _ := result["data"].(map[string]interface{})
fileToken, _ := data["file_token"].(string)
url, _ := data["url"].(string)

if fileToken == "" {
return output.Errorf(output.ExitAPI, "api_error", "upload failed: no file_token returned")
}

runtime.Out(map[string]interface{}{
"file_token": fileToken,
"url": url,
"file_name": fileName,
"size": info.Size(),
}, nil)
return nil
},
}
Loading
Loading