773 lines
25 KiB
Go
773 lines
25 KiB
Go
// Copyright 2026 Alibaba Group
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package helpers
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/cli"
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/cobracmd"
|
|
apperrors "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/errors"
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/executor"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func init() {
|
|
RegisterPublic(func() Handler {
|
|
return chatHandler{}
|
|
})
|
|
}
|
|
|
|
type chatHandler struct{}
|
|
|
|
func (chatHandler) Name() string {
|
|
return "chat"
|
|
}
|
|
|
|
func (chatHandler) Command(runner executor.Runner) *cobra.Command {
|
|
root := &cobra.Command{
|
|
Use: "chat",
|
|
Short: "群聊 / 消息 / 机器人",
|
|
Long: "管理钉钉会话与群聊:创建群、搜索群、查看群成员、添加机器人到群、修改群名称、拉取会话消息、发送群消息、机器人消息与 Webhook。",
|
|
Args: cobra.NoArgs,
|
|
TraverseChildren: true,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
return cmd.Help()
|
|
},
|
|
}
|
|
|
|
message := &cobra.Command{
|
|
Use: "message",
|
|
Short: "会话消息管理",
|
|
Args: cobra.NoArgs,
|
|
TraverseChildren: true,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
return cmd.Help()
|
|
},
|
|
}
|
|
message.AddCommand(
|
|
newChatMessageSendByBotCommand(runner),
|
|
newChatMessageRecallByBotCommand(runner),
|
|
newChatMessageSendByWebhookCommand(runner),
|
|
)
|
|
|
|
bot := &cobra.Command{
|
|
Use: "bot",
|
|
Short: "机器人管理",
|
|
Args: cobra.NoArgs,
|
|
TraverseChildren: true,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
return cmd.Help()
|
|
},
|
|
}
|
|
bot.AddCommand(newChatBotSearchCommand(runner))
|
|
|
|
root.AddCommand(message, newChatSearchCommand(runner), newChatGroupCommand(runner), bot)
|
|
return root
|
|
}
|
|
|
|
func newChatMessageSendByBotCommand(runner executor.Runner) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "send-by-bot",
|
|
Short: "机器人发送消息(--group 群聊 / --users 单聊)",
|
|
Args: cobra.NoArgs,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
params, tool, err := buildChatMessageSendByBotInvocation(cmd)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
invocation := executor.NewHelperInvocation(
|
|
cobracmd.LegacyCommandPath(cmd),
|
|
"chat",
|
|
tool,
|
|
params,
|
|
)
|
|
invocation.DryRun = commandDryRun(cmd)
|
|
result, err := runner.Run(cmd.Context(), invocation)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return writeCommandPayload(cmd, result)
|
|
},
|
|
}
|
|
preferLegacyLeaf(cmd)
|
|
|
|
cmd.Flags().String("group", "", "群会话 openConversationId (群聊必填)")
|
|
cmd.Flags().String("robot-code", "", "机器人 Code")
|
|
cmd.Flags().String("text", "", "消息内容 (Markdown)")
|
|
cmd.Flags().String("title", "", "消息标题")
|
|
cmd.Flags().String("users", "", "接收者 userId 列表,逗号分隔,最多 20 个 (单聊必填)")
|
|
return cmd
|
|
}
|
|
|
|
func newChatSearchCommand(runner executor.Runner) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "search",
|
|
Short: "根据名称搜索会话列表",
|
|
Example: ` dws chat search --query "项目冲刺"`,
|
|
Args: cobra.NoArgs,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
query, err := cmd.Flags().GetString("query")
|
|
if err != nil {
|
|
return apperrors.NewInternal("failed to read --query")
|
|
}
|
|
query = strings.TrimSpace(query)
|
|
if query == "" {
|
|
return apperrors.NewValidation("--query is required")
|
|
}
|
|
|
|
searchReq := map[string]any{"query": query}
|
|
cursor, err := cmd.Flags().GetString("cursor")
|
|
if err != nil {
|
|
return apperrors.NewInternal("failed to read --cursor")
|
|
}
|
|
if strings.TrimSpace(cursor) != "" {
|
|
searchReq["cursor"] = cursor
|
|
}
|
|
|
|
result, err := runner.Run(cmd.Context(), executor.NewHelperInvocation(
|
|
cobracmd.LegacyCommandPath(cmd),
|
|
"chat",
|
|
"search_groups_by_keyword",
|
|
map[string]any{"OpenSearchRequest": searchReq},
|
|
))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return writeCommandPayload(cmd, result)
|
|
},
|
|
}
|
|
preferLegacyLeaf(cmd)
|
|
|
|
cmd.Flags().String("query", "", "搜索关键词 (必填)")
|
|
cmd.Flags().String("cursor", "", "分页游标 (首页留空)")
|
|
return cmd
|
|
}
|
|
|
|
func newChatGroupCommand(runner executor.Runner) *cobra.Command {
|
|
root := &cobra.Command{
|
|
Use: "group",
|
|
Short: "群组管理",
|
|
Args: cobra.NoArgs,
|
|
TraverseChildren: true,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
return cmd.Help()
|
|
},
|
|
}
|
|
|
|
members := &cobra.Command{
|
|
Use: "members",
|
|
Short: "群成员管理",
|
|
Args: cobra.NoArgs,
|
|
TraverseChildren: true,
|
|
DisableAutoGenTag: true,
|
|
RunE: newChatGroupMembersListRunE(runner),
|
|
}
|
|
members.Flags().String("id", "", "群 ID / openconversation_id (必填)")
|
|
members.Flags().String("cursor", "", "分页游标")
|
|
preferLegacyLeaf(members)
|
|
|
|
members.AddCommand(
|
|
newChatGroupMemberAddCommand(runner),
|
|
newChatGroupMemberRemoveCommand(runner),
|
|
newChatGroupMembersAddBotCommand(runner),
|
|
)
|
|
|
|
root.AddCommand(
|
|
newChatGroupCreateCommand(runner),
|
|
members,
|
|
newChatGroupRenameCommand(runner),
|
|
)
|
|
return root
|
|
}
|
|
|
|
func newChatGroupCreateCommand(runner executor.Runner) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "create",
|
|
Short: "创建群",
|
|
Example: ` dws chat group create --name "Q1 项目冲刺群" --users userId1,userId2,userId3`,
|
|
Args: cobra.NoArgs,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
name, err := cmd.Flags().GetString("name")
|
|
if err != nil {
|
|
return apperrors.NewInternal("failed to read --name")
|
|
}
|
|
name = strings.TrimSpace(name)
|
|
if name == "" {
|
|
return apperrors.NewValidation("--name is required")
|
|
}
|
|
|
|
users, err := cmd.Flags().GetString("users")
|
|
if err != nil {
|
|
return apperrors.NewInternal("failed to read --users")
|
|
}
|
|
memberUserIDs := splitCSVStrings(users)
|
|
if len(memberUserIDs) == 0 {
|
|
return apperrors.NewValidation("--users is required")
|
|
}
|
|
|
|
currentUserID, err := getCurrentUserID(cmd.Context(), runner)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
allMembers := prependOwner(currentUserID, memberUserIDs)
|
|
|
|
inv := executor.NewHelperInvocation(
|
|
cobracmd.LegacyCommandPath(cmd),
|
|
"chat",
|
|
"create_internal_group",
|
|
map[string]any{
|
|
"groupMembers": stringSliceToAny(allMembers),
|
|
"groupName": name,
|
|
},
|
|
)
|
|
inv.DryRun = commandDryRun(cmd)
|
|
result, err := runner.Run(cmd.Context(), inv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
normalizeChatGroupCreateResponse(&result)
|
|
return writeCommandPayload(cmd, result)
|
|
},
|
|
}
|
|
preferLegacyLeaf(cmd)
|
|
|
|
cmd.Flags().String("name", "", "群名称 (必填)")
|
|
cmd.Flags().String("users", "", "群成员 userId 列表,逗号分隔 (必填)")
|
|
return cmd
|
|
}
|
|
|
|
func buildChatMessageSendByBotInvocation(cmd *cobra.Command) (map[string]any, string, error) {
|
|
guard := cli.NewStdinGuard()
|
|
|
|
group, err := cmd.Flags().GetString("group")
|
|
if err != nil {
|
|
return nil, "", apperrors.NewInternal("failed to read --group")
|
|
}
|
|
users, err := cmd.Flags().GetString("users")
|
|
if err != nil {
|
|
return nil, "", apperrors.NewInternal("failed to read --users")
|
|
}
|
|
robotCode, err := cmd.Flags().GetString("robot-code")
|
|
if err != nil {
|
|
return nil, "", apperrors.NewInternal("failed to read --robot-code")
|
|
}
|
|
title, err := resolveStringFlag(cmd, "title", guard, false)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
// --text is the primary content flag: receives stdin pipe when empty.
|
|
text, err := resolveStringFlag(cmd, "text", guard, true)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
|
|
switch {
|
|
case strings.TrimSpace(group) == "" && strings.TrimSpace(users) == "":
|
|
return nil, "", apperrors.NewValidation("either --group or --users is required")
|
|
case strings.TrimSpace(group) != "" && strings.TrimSpace(users) != "":
|
|
return nil, "", apperrors.NewValidation("--group and --users are mutually exclusive")
|
|
}
|
|
if strings.TrimSpace(robotCode) == "" {
|
|
return nil, "", apperrors.NewValidation("--robot-code is required")
|
|
}
|
|
if strings.TrimSpace(title) == "" {
|
|
return nil, "", apperrors.NewValidation("--title is required")
|
|
}
|
|
if strings.TrimSpace(text) == "" {
|
|
return nil, "", apperrors.NewValidation("--text is required")
|
|
}
|
|
|
|
params := map[string]any{
|
|
"markdown": text,
|
|
"robotCode": robotCode,
|
|
"title": title,
|
|
}
|
|
if strings.TrimSpace(group) != "" {
|
|
params["openConversationId"] = group
|
|
return params, "send_robot_group_message", nil
|
|
}
|
|
|
|
params["userIds"] = splitCSV(users)
|
|
return params, "batch_send_robot_msg_to_users", nil
|
|
}
|
|
|
|
func splitCSV(raw string) []any {
|
|
parts := strings.Split(raw, ",")
|
|
values := make([]any, 0, len(parts))
|
|
for _, part := range parts {
|
|
trimmed := strings.TrimSpace(part)
|
|
if trimmed == "" {
|
|
continue
|
|
}
|
|
values = append(values, trimmed)
|
|
}
|
|
return values
|
|
}
|
|
|
|
func splitCSVStrings(raw string) []string {
|
|
parts := strings.Split(raw, ",")
|
|
values := make([]string, 0, len(parts))
|
|
for _, part := range parts {
|
|
trimmed := strings.TrimSpace(part)
|
|
if trimmed == "" {
|
|
continue
|
|
}
|
|
values = append(values, trimmed)
|
|
}
|
|
return values
|
|
}
|
|
|
|
func stringSliceToAny(values []string) []any {
|
|
out := make([]any, 0, len(values))
|
|
for _, value := range values {
|
|
out = append(out, value)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func getCurrentUserID(ctx context.Context, runner executor.Runner) (string, error) {
|
|
result, err := runner.Run(ctx, executor.NewHelperInvocation(
|
|
"contact raw get_current_user_profile",
|
|
"contact",
|
|
"get_current_user_profile",
|
|
nil,
|
|
))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
content := helperResponseContent(result)
|
|
if len(content) == 0 {
|
|
// EchoRunner and dry-run previews do not have runtime content, so fall back
|
|
// to the explicitly provided members instead of failing the preview path.
|
|
if !result.Invocation.Implemented {
|
|
return "", nil
|
|
}
|
|
return "", apperrors.NewInternal("contact.get_current_user_profile returned no content")
|
|
}
|
|
|
|
if arr, ok := content["result"].([]any); ok && len(arr) > 0 {
|
|
if first, ok := arr[0].(map[string]any); ok {
|
|
if employee, ok := first["orgEmployeeModel"].(map[string]any); ok {
|
|
if userID, ok := employee["userId"].(string); ok && strings.TrimSpace(userID) != "" {
|
|
return userID, nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if object, ok := content["result"].(map[string]any); ok {
|
|
if userID, ok := object["userId"].(string); ok && strings.TrimSpace(userID) != "" {
|
|
return userID, nil
|
|
}
|
|
}
|
|
return "", apperrors.NewInternal("unable to parse userId from contact.get_current_user_profile")
|
|
}
|
|
|
|
func prependOwner(owner string, memberUserIDs []string) []string {
|
|
seen := map[string]bool{}
|
|
allMembers := make([]string, 0, len(memberUserIDs)+1)
|
|
if trimmedOwner := strings.TrimSpace(owner); trimmedOwner != "" {
|
|
seen[trimmedOwner] = true
|
|
allMembers = append(allMembers, trimmedOwner)
|
|
}
|
|
for _, userID := range memberUserIDs {
|
|
trimmed := strings.TrimSpace(userID)
|
|
if trimmed == "" || seen[trimmed] {
|
|
continue
|
|
}
|
|
seen[trimmed] = true
|
|
allMembers = append(allMembers, trimmed)
|
|
}
|
|
return allMembers
|
|
}
|
|
|
|
func normalizeChatGroupCreateResponse(result *executor.Result) {
|
|
if result == nil {
|
|
return
|
|
}
|
|
content := helperResponseContent(*result)
|
|
if len(content) == 0 {
|
|
return
|
|
}
|
|
payload, ok := content["result"].(map[string]any)
|
|
if !ok {
|
|
return
|
|
}
|
|
if value, exists := payload["openCid"]; exists {
|
|
payload["openConversationId"] = value
|
|
delete(payload, "openCid")
|
|
}
|
|
delete(payload, "cid")
|
|
}
|
|
|
|
func helperResponseContent(result executor.Result) map[string]any {
|
|
if len(result.Response) == 0 {
|
|
return nil
|
|
}
|
|
content, _ := result.Response["content"].(map[string]any)
|
|
return content
|
|
}
|
|
|
|
// ── message recall-by-bot ──────────────────────────────────
|
|
|
|
func newChatMessageRecallByBotCommand(runner executor.Runner) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "recall-by-bot",
|
|
Short: "机器人撤回消息(--group 群聊 / 不传为单聊)",
|
|
Long: "群聊撤回:传 --group 和 --keys;单聊撤回:只传 --keys。--keys 是逗号分隔的 processQueryKey 列表。",
|
|
Example: ` dws chat message recall-by-bot --robot-code <robot-code> --group <id> --keys <key>
|
|
dws chat message recall-by-bot --robot-code <robot-code> --keys key1,key2`,
|
|
Args: cobra.NoArgs,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
robotCode, _ := cmd.Flags().GetString("robot-code")
|
|
keysStr, _ := cmd.Flags().GetString("keys")
|
|
groupID, _ := cmd.Flags().GetString("group")
|
|
if strings.TrimSpace(robotCode) == "" {
|
|
return apperrors.NewValidation("--robot-code is required")
|
|
}
|
|
if strings.TrimSpace(keysStr) == "" {
|
|
return apperrors.NewValidation("--keys is required")
|
|
}
|
|
processQueryKeys := splitCSV(keysStr)
|
|
if strings.TrimSpace(groupID) != "" {
|
|
params := map[string]any{
|
|
"robotCode": robotCode,
|
|
"openConversationId": groupID,
|
|
"processQueryKeys": processQueryKeys,
|
|
}
|
|
inv := executor.NewHelperInvocation(
|
|
cobracmd.LegacyCommandPath(cmd), "bot", "recall_robot_group_message", params,
|
|
)
|
|
inv.DryRun = commandDryRun(cmd)
|
|
result, err := runner.Run(cmd.Context(), inv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return writeCommandPayload(cmd, result)
|
|
}
|
|
params := map[string]any{
|
|
"robotCode": robotCode,
|
|
"processQueryKeys": processQueryKeys,
|
|
}
|
|
inv := executor.NewHelperInvocation(
|
|
cobracmd.LegacyCommandPath(cmd), "bot", "batch_recall_robot_users_msg", params,
|
|
)
|
|
inv.DryRun = commandDryRun(cmd)
|
|
result, err := runner.Run(cmd.Context(), inv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return writeCommandPayload(cmd, result)
|
|
},
|
|
}
|
|
preferLegacyLeaf(cmd)
|
|
cmd.Flags().String("robot-code", "", "机器人 Code (必填)")
|
|
cmd.Flags().String("group", "", "群会话 openConversationId (群聊撤回必填)")
|
|
cmd.Flags().String("keys", "", "逗号分隔的消息 processQueryKey 列表 (必填)")
|
|
return cmd
|
|
}
|
|
|
|
// ── message send-by-webhook ────────────────────────────────
|
|
|
|
func newChatMessageSendByWebhookCommand(runner executor.Runner) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "send-by-webhook",
|
|
Short: "自定义机器人 Webhook 发送群消息",
|
|
Long: "自定义机器人 Webhook 发送群消息。如需 @指定人,在 --text 中包含 @userId 或 @手机号。",
|
|
Example: ` dws chat message send-by-webhook --token <token> --title "告警" --text "CPU 超 90%" --at-all
|
|
dws chat message send-by-webhook --token <token> --title "test" --text "hi" --at-users 034766`,
|
|
Args: cobra.NoArgs,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
guard := cli.NewStdinGuard()
|
|
token, _ := cmd.Flags().GetString("token")
|
|
title, err := resolveStringFlag(cmd, "title", guard, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// --text is the primary content flag: receives stdin pipe when empty.
|
|
text, err := resolveStringFlag(cmd, "text", guard, true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if strings.TrimSpace(token) == "" {
|
|
return apperrors.NewValidation("--token is required")
|
|
}
|
|
if strings.TrimSpace(title) == "" {
|
|
return apperrors.NewValidation("--title is required")
|
|
}
|
|
if strings.TrimSpace(text) == "" {
|
|
return apperrors.NewValidation("--text is required")
|
|
}
|
|
params := map[string]any{
|
|
"robotToken": token,
|
|
"title": title,
|
|
"text": text,
|
|
}
|
|
if v, _ := cmd.Flags().GetBool("at-all"); v {
|
|
params["isAtAll"] = true
|
|
}
|
|
if v, _ := cmd.Flags().GetString("at-mobiles"); v != "" {
|
|
params["atMobiles"] = splitCSV(v)
|
|
}
|
|
if v, _ := cmd.Flags().GetString("at-users"); v != "" {
|
|
params["atUserIds"] = splitCSV(v)
|
|
}
|
|
invocation := executor.NewHelperInvocation(
|
|
cobracmd.LegacyCommandPath(cmd), "bot", "send_message_by_custom_robot", params,
|
|
)
|
|
invocation.DryRun = commandDryRun(cmd)
|
|
result, err := runner.Run(cmd.Context(), invocation)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return writeCommandPayload(cmd, result)
|
|
},
|
|
}
|
|
preferLegacyLeaf(cmd)
|
|
cmd.Flags().String("token", "", "Webhook token (必填)")
|
|
cmd.Flags().String("title", "", "消息标题 (必填)")
|
|
cmd.Flags().String("text", "", "消息内容 (必填)")
|
|
cmd.Flags().Bool("at-all", false, "@所有人")
|
|
cmd.Flags().String("at-mobiles", "", "按手机号 @,逗号分隔")
|
|
cmd.Flags().String("at-users", "", "按 userId @,逗号分隔")
|
|
return cmd
|
|
}
|
|
|
|
// ── group members list ─────────────────────────────────────
|
|
|
|
func newChatGroupMembersListRunE(runner executor.Runner) func(*cobra.Command, []string) error {
|
|
return func(cmd *cobra.Command, args []string) error {
|
|
groupID, _ := cmd.Flags().GetString("id")
|
|
if strings.TrimSpace(groupID) == "" {
|
|
return apperrors.NewValidation("--id is required")
|
|
}
|
|
params := map[string]any{
|
|
"openconversation_id": groupID,
|
|
}
|
|
if v, _ := cmd.Flags().GetString("cursor"); v != "" {
|
|
params["cursor"] = v
|
|
}
|
|
result, err := runner.Run(cmd.Context(), executor.NewHelperInvocation(
|
|
cobracmd.LegacyCommandPath(cmd), "chat", "get_group_members", params,
|
|
))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return writeCommandPayload(cmd, result)
|
|
}
|
|
}
|
|
|
|
// ── group rename ───────────────────────────────────────────
|
|
|
|
func newChatGroupRenameCommand(runner executor.Runner) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "rename",
|
|
Short: "更新群名称",
|
|
Example: ` dws chat group rename --id <openconversation_id> --name "新群名"`,
|
|
Args: cobra.NoArgs,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
groupID, _ := cmd.Flags().GetString("id")
|
|
name, _ := cmd.Flags().GetString("name")
|
|
if strings.TrimSpace(groupID) == "" {
|
|
return apperrors.NewValidation("--id is required")
|
|
}
|
|
if strings.TrimSpace(name) == "" {
|
|
return apperrors.NewValidation("--name is required")
|
|
}
|
|
params := map[string]any{
|
|
"openconversation_id": groupID,
|
|
"group_name": name,
|
|
}
|
|
inv := executor.NewHelperInvocation(
|
|
cobracmd.LegacyCommandPath(cmd), "chat", "update_group_name", params,
|
|
)
|
|
inv.DryRun = commandDryRun(cmd)
|
|
result, err := runner.Run(cmd.Context(), inv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return writeCommandPayload(cmd, result)
|
|
},
|
|
}
|
|
preferLegacyLeaf(cmd)
|
|
cmd.Flags().String("id", "", "群 ID / openconversation_id (必填)")
|
|
cmd.Flags().String("name", "", "新群名称 (必填)")
|
|
return cmd
|
|
}
|
|
|
|
// ── group members add ──────────────────────────────────────
|
|
|
|
func newChatGroupMemberAddCommand(runner executor.Runner) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "add",
|
|
Short: "添加群成员",
|
|
Example: ` dws chat group members add --id <openconversation_id> --users userId1,userId2`,
|
|
Args: cobra.NoArgs,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
groupID, _ := cmd.Flags().GetString("id")
|
|
usersStr, _ := cmd.Flags().GetString("users")
|
|
if strings.TrimSpace(groupID) == "" {
|
|
return apperrors.NewValidation("--id is required")
|
|
}
|
|
if strings.TrimSpace(usersStr) == "" {
|
|
return apperrors.NewValidation("--users is required")
|
|
}
|
|
params := map[string]any{
|
|
"openconversation_id": groupID,
|
|
"userId": splitCSV(usersStr),
|
|
}
|
|
inv := executor.NewHelperInvocation(
|
|
cobracmd.LegacyCommandPath(cmd), "chat", "add_group_member", params,
|
|
)
|
|
inv.DryRun = commandDryRun(cmd)
|
|
result, err := runner.Run(cmd.Context(), inv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return writeCommandPayload(cmd, result)
|
|
},
|
|
}
|
|
preferLegacyLeaf(cmd)
|
|
cmd.Flags().String("id", "", "群 ID / openconversation_id (必填)")
|
|
cmd.Flags().String("users", "", "要添加的 userId 列表,逗号分隔 (必填)")
|
|
return cmd
|
|
}
|
|
|
|
// ── group members remove ───────────────────────────────────
|
|
|
|
func newChatGroupMemberRemoveCommand(runner executor.Runner) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "remove",
|
|
Short: "移除群成员",
|
|
Example: ` dws chat group members remove --id <openconversation_id> --users userId1,userId2`,
|
|
Args: cobra.NoArgs,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
groupID, _ := cmd.Flags().GetString("id")
|
|
usersStr, _ := cmd.Flags().GetString("users")
|
|
if strings.TrimSpace(groupID) == "" {
|
|
return apperrors.NewValidation("--id is required")
|
|
}
|
|
if strings.TrimSpace(usersStr) == "" {
|
|
return apperrors.NewValidation("--users is required")
|
|
}
|
|
params := map[string]any{
|
|
"openconversationId": groupID,
|
|
"userIdList": splitCSV(usersStr),
|
|
}
|
|
inv := executor.NewHelperInvocation(
|
|
cobracmd.LegacyCommandPath(cmd), "chat", "remove_group_member", params,
|
|
)
|
|
inv.DryRun = commandDryRun(cmd)
|
|
result, err := runner.Run(cmd.Context(), inv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return writeCommandPayload(cmd, result)
|
|
},
|
|
}
|
|
preferLegacyLeaf(cmd)
|
|
cmd.Flags().String("id", "", "Group ID / openconversation_id (required)")
|
|
cmd.Flags().String("users", "", "Comma-separated userId list to remove (required)")
|
|
return cmd
|
|
}
|
|
|
|
// ── group members add-bot ──────────────────────────────────
|
|
|
|
func newChatGroupMembersAddBotCommand(runner executor.Runner) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "add-bot",
|
|
Short: "Add bot to group",
|
|
Example: ` dws chat group members add-bot --robot-code <robot-code> --id <openconversation_id>`,
|
|
Args: cobra.NoArgs,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
robotCode, _ := cmd.Flags().GetString("robot-code")
|
|
groupID, _ := cmd.Flags().GetString("id")
|
|
if strings.TrimSpace(robotCode) == "" {
|
|
return apperrors.NewValidation("--robot-code is required")
|
|
}
|
|
if strings.TrimSpace(groupID) == "" {
|
|
return apperrors.NewValidation("--id is required")
|
|
}
|
|
params := map[string]any{
|
|
"robotCode": robotCode,
|
|
"openConversationId": groupID,
|
|
}
|
|
inv := executor.NewHelperInvocation(
|
|
cobracmd.LegacyCommandPath(cmd), "bot", "add_robot_to_group", params,
|
|
)
|
|
inv.DryRun = commandDryRun(cmd)
|
|
result, err := runner.Run(cmd.Context(), inv)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return writeCommandPayload(cmd, result)
|
|
},
|
|
}
|
|
preferLegacyLeaf(cmd)
|
|
cmd.Flags().String("robot-code", "", "Bot code (required)")
|
|
cmd.Flags().String("id", "", "Group openConversationId (required)")
|
|
return cmd
|
|
}
|
|
|
|
// ── bot search ─────────────────────────────────────────────
|
|
|
|
func newChatBotSearchCommand(runner executor.Runner) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "search",
|
|
Short: "Search my bots",
|
|
Example: " dws chat bot search --page 1\n dws chat bot search --page 1 --size 10 --name \"日报\"",
|
|
Args: cobra.NoArgs,
|
|
DisableAutoGenTag: true,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
page, _ := cmd.Flags().GetInt("page")
|
|
params := map[string]any{
|
|
"currentPage": page,
|
|
}
|
|
if v, _ := cmd.Flags().GetInt("size"); v > 0 {
|
|
params["pageSize"] = v
|
|
}
|
|
if v, _ := cmd.Flags().GetString("name"); v != "" {
|
|
params["robotName"] = v
|
|
}
|
|
result, err := runner.Run(cmd.Context(), executor.NewHelperInvocation(
|
|
cobracmd.LegacyCommandPath(cmd), "bot", "search_my_robots", params,
|
|
))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return writeCommandPayload(cmd, result)
|
|
},
|
|
}
|
|
preferLegacyLeaf(cmd)
|
|
cmd.Flags().Int("page", 1, "Page number, starting from 1")
|
|
cmd.Flags().Int("size", 0, "Items per page (default 50)")
|
|
cmd.Flags().String("name", "", "Search by name")
|
|
return cmd
|
|
}
|