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: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,17 @@ For commands that may have side effects, preview the request with --dry-run firs
lark-cli im +messages-send --chat-id oc_xxx --text "hello" --dry-run
```

### Shell Completion

`lark-cli` ships a working `completion` subcommand, but it is intentionally hidden from the default help output because the CLI is primarily optimized for agent workflows.

```bash
lark-cli completion zsh
lark-cli completion bash
lark-cli completion fish
lark-cli completion powershell
```

### Schema Introspection

Use schema to inspect any API method's parameters, request body, response structure, supported identities, and scopes:
Expand Down
2 changes: 2 additions & 0 deletions shortcuts/base/base_execute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,8 @@ func TestBaseFieldExecuteSearchOptions(t *testing.T) {
}
if got := stdout.String(); !strings.Contains(got, `"options"`) || !strings.Contains(got, `"已完成"`) {
t.Fatalf("stdout=%s", got)
} else if strings.Contains(got, `"opt_1"`) {
t.Fatalf("stdout should not expose option ids: %s", got)
}
}

Expand Down
25 changes: 24 additions & 1 deletion shortcuts/base/field_ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,31 @@ func executeFieldSearchOptions(runtime *common.RuntimeContext) error {
"field_id": fieldRef,
"field_name": fieldRef,
"keyword": strings.TrimSpace(runtime.Str("keyword")),
"options": options,
"options": stripFieldOptionIDs(options),
"total": total,
}, nil)
return nil
}

func stripFieldOptionIDs(options []interface{}) []interface{} {
if len(options) == 0 {
return options
}
normalized := make([]interface{}, 0, len(options))
for _, option := range options {
record, ok := option.(map[string]interface{})
if !ok {
normalized = append(normalized, option)
continue
}
copied := make(map[string]interface{}, len(record))
for key, value := range record {
if key == "id" {
continue
}
copied[key] = value
}
normalized = append(normalized, copied)
}
return normalized
}
2 changes: 1 addition & 1 deletion skills/lark-im/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Chat (oc_xxx)

### Identity and Token Mapping

- `--as user` means **user identity** and uses `user_access_token`. Calls run as the authorized end user, so permissions depend on both the app scopes and that user's own access to the target chat/message/resource.
- `--as user` means **user identity** and uses `user_access_token`. Calls run as the authorized end user, so permissions depend on both the app scopes and that user's own access to the target chat/message/resource. For direct messages to users, the app also still needs to be visible to the target user; user token auth does not bypass app visibility or availability settings.
- `--as bot` means **bot identity** and uses `tenant_access_token`. Calls run as the app bot, so behavior depends on the bot's membership, app visibility, availability range, and bot-specific scopes.
- If an IM API says it supports both `user` and `bot`, the token type changes who the operator is. The same API can succeed with one identity and fail with the other because owner/admin status, chat membership, tenant boundary, or app availability are checked against the current caller.

Expand Down
4 changes: 4 additions & 0 deletions skills/lark-im/references/lark-im-messages-send.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ When using `--as bot`, the message is sent in the app's name, so make sure the a

When using `--as user`, the message is sent as the authorized end user and requires the `im:message.send_as_user` and `im:message` scopes.

For direct messages to users, `--as user` still does **not** bypass app visibility. If the target user is outside the app's visible or available range, the send can still fail even though the operator already completed `auth login`.

## Choose The Right Content Flag

| Need | Recommended flag | Why |
Expand Down Expand Up @@ -175,6 +177,7 @@ lark-cli im +messages-send --chat-id oc_xxx --markdown $'## Test\n\nhello' --dry
- Using `--content` without making the JSON match the effective `--msg-type`.
- Explicitly setting `--msg-type` to something that conflicts with `--text`, `--markdown`, or media flags.
- Mixing `--text`, `--markdown`, or `--content` with media flags in one command.
- Assuming `--as user` can message any target user once the sender has logged in. The app still needs to be visible to the recipient, or Feishu will reject the send with visibility / authorization errors.

## `content` Format Reference

Expand Down Expand Up @@ -218,6 +221,7 @@ lark-cli im +messages-send --chat-id oc_xxx --markdown $'## Test\n\nhello' --dry
- When using `--video`, `--video-cover` is required as the video cover
- `--dry-run` uses placeholder image keys for remote Markdown images and placeholder media keys for local uploads
- Failures return an error code and message
- For `--as user` direct messages, make sure the app's visible range includes the target user. A logged-in sender token alone is not enough when the app is not visible to that recipient.
- `--as user` uses a user access token (UAT) and requires the `im:message.send_as_user` and `im:message` scopes; the message is sent as the authorized end user
- `--as bot` uses a tenant access token (TAT) and requires the `im:message:send_as_bot` scope
- When sending as a bot, the app must already be in the target group or already have a direct-message relationship with the target user
Loading