diff --git a/internal/cli/param_aliases_generated.go b/internal/cli/param_aliases_generated.go index 91d14d1d..8827cceb 100644 --- a/internal/cli/param_aliases_generated.go +++ b/internal/cli/param_aliases_generated.go @@ -2525,7 +2525,7 @@ var generatedParamAliases = []ParamAliasEntry{ "user-id": "user", "userid": "user", }, - Blocked: []string{"at-user-ids", "conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "id", "name", "open-conversation-ids", "source", "src-conversation-id", "target", "to-user", "user-ids", "users"}, + Blocked: []string{"at-user-ids", "conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "id", "name", "open-conversation-ids", "role-id", "source", "src-conversation-id", "target", "to-user", "user-ids", "users"}, }, { CLIPath: "chat +chat-role-update", diff --git a/internal/cli/param_concepts.json b/internal/cli/param_concepts.json index ab32e71c..4b9086b4 100644 --- a/internal/cli/param_concepts.json +++ b/internal/cli/param_concepts.json @@ -153,6 +153,7 @@ "chat +chat-role-update": {"block": ["role-ids"], "note": "This command requires one role id; list cardinality is not reduced automatically."}, "chat group-role remove": {"block": ["role-ids"], "note": "This command requires one role id; list cardinality is not reduced automatically."}, "chat group-role update": {"block": ["role-ids"], "note": "This command requires one role id; list cardinality is not reduced automatically."}, + "chat +chat-role-set-user": {"block": ["role-id"], "note": "This command requires a role-id list; one id is not promoted into a batch input."}, "chat group-role remove-user": {"block": ["role-id"], "note": "This command requires a role-id list; one id is not promoted into a batch input."}, "chat +messages-send-by-webhook": {"scoped_aliases": {"at-user-ids": "at-users"}, "scope_strict": true, "note": "Both names denote the same userId list used for @ mentions on this exact shortcut."}, "chat message send-by-webhook": {"scoped_aliases": {"at-user-ids": "at-users"}, "scope_strict": true, "note": "Both names denote the same userId list used for @ mentions on this exact command."}, diff --git a/internal/helpers/chat.go b/internal/helpers/chat.go index 528fbbd9..ea69d203 100644 --- a/internal/helpers/chat.go +++ b/internal/helpers/chat.go @@ -32,7 +32,10 @@ func resolveChatGroupRoleSetUserRoleIDs(cmd *cobra.Command) ([]string, error) { roleIDsChanged := cmd.Flags().Changed("role-ids") switch { case roleIDChanged && roleIDsChanged: - return nil, apperrors.NewValidation("--role-id 与 --role-ids 不能同时指定") + // PreRunE rejects callers that explicitly pass both flags. Reaching this + // branch means the hidden legacy flag was promoted to satisfy Cobra's + // required marker on the public canonical flag. + return parseCSVValues(mustGetFlag(cmd, "role-ids")), nil case roleIDChanged: roleIDs := parseCSVValues(mustGetFlag(cmd, "role-id")) if len(roleIDs) == 0 { @@ -49,6 +52,13 @@ func resolveChatGroupRoleSetUserRoleIDs(cmd *cobra.Command) ([]string, error) { } } +func prepareChatGroupRoleSetUserRoleID(cmd *cobra.Command) error { + if cmd.Flags().Changed("role-id") && cmd.Flags().Changed("role-ids") { + return apperrors.NewValidation("--role-id 与 --role-ids 不能同时指定") + } + return promoteLegacyChatString(cmd, "role-id", "role-ids") +} + // promoteLegacyChatString copies an explicitly supplied legacy flag into the // new canonical flag. Cobra validates MarkFlagRequired after PreRunE, and the // overwrite also preserves the migration rule that a legacy value wins when @@ -7778,6 +7788,9 @@ flow-status 取值:1=处理中(PROCESSING),2=输入中(INPUTTING),3=完成 Example: ` dws chat group-role set-user --conversation-id --user --role-id # 查询人员: dws contact user search --keyword "姓名" --format json # 查询 role-id: dws chat group-role list --conversation-id `, + PreRunE: func(cmd *cobra.Command, args []string) error { + return prepareChatGroupRoleSetUserRoleID(cmd) + }, RunE: func(cmd *cobra.Command, args []string) error { if err := validateRequiredFlags(cmd, "conversation-id"); err != nil { return err @@ -7843,6 +7856,7 @@ flow-status 取值:1=处理中(PROCESSING),2=输入中(INPUTTING),3=完成 chatGroupRoleSetUserCmd.Flags().String("role-ids", "", "已隐藏的兼容参数:群身份 openRoleId 列表,逗号分隔") _ = chatGroupRoleSetUserCmd.Flags().MarkHidden("role-ids") corecmd.AnnotateFlagAlias(chatGroupRoleSetUserCmd, "role-ids", "role-id") + _ = chatGroupRoleSetUserCmd.MarkFlagRequired("role-id") chatGroupRoleRemoveUserCmd := &cobra.Command{ Use: "remove-user", diff --git a/internal/shortcut/chat/chat_group.go b/internal/shortcut/chat/chat_group.go index f2bb5a4c..a959874e 100644 --- a/internal/shortcut/chat/chat_group.go +++ b/internal/shortcut/chat/chat_group.go @@ -1882,7 +1882,7 @@ var ChatRoleSetUser = shortcut.Shortcut{ Command: "+chat-role-set-user", Product: "im", Description: "设置用户的群身份(覆盖该用户的全部群身份)", - Intent: "当你想为某成员整体设定其在群内的身份时使用;会实际改写该用户的群身份集合(覆盖其原有全部身份),需传群、用户和一个 openRoleId。", + Intent: "当你想为某成员整体设定其在群内的身份时使用;会实际改写该用户的群身份集合(覆盖其原有全部身份),需传群、用户和 openRoleId 列表(传空则清除全部)。", Risk: shortcut.RiskWrite, Safety: contract.SafetySpec{ Effect: "write", Risk: "medium", @@ -1904,28 +1904,22 @@ var ChatRoleSetUser = shortcut.Shortcut{ }, Selection: contract.SelectionSpec{ AgentSummary: "设置用户的群身份(覆盖该用户的全部群身份)", - UseWhen: []string{"当你想为某成员整体设定其在群内的身份时使用;会实际改写该用户的群身份集合(覆盖其原有全部身份),需传群、用户和一个 openRoleId。"}, + UseWhen: []string{"当你想为某成员整体设定其在群内的身份时使用;会实际改写该用户的群身份集合(覆盖其原有全部身份),需传群、用户和 openRoleId 列表(传空则清除全部)。"}, AvoidWhen: []string{"需要该 Shortcut 未公开的底层参数、原始响应或不同执行语义时,改用对应原子命令"}, - Examples: []string{"dws chat +chat-role-set-user --group --user --role-id "}, + Examples: []string{"dws chat +chat-role-set-user --group --user --role-ids roleId1,roleId2"}, }, }, Flags: []shortcut.Flag{ {Name: "group", Type: shortcut.FlagString, Desc: "群 openConversationId", Required: true}, {Name: "user", Type: shortcut.FlagString, Desc: "用户 userId 或 openDingTalkId", Required: true}, - {Name: "role-id", Type: shortcut.FlagStringSlice, Desc: "群身份 openRoleId;公开入口必须提供一个非空群身份 openRoleId", Aliases: []string{"role-ids"}}, - }, - Constraints: []shortcut.Constraint{ - {Kind: shortcut.ConstraintCustom, Flags: []string{"role-id"}, Description: "公开入口必须提供一个非空群身份 openRoleId"}, - }, - Tips: []string{`dws chat +chat-role-set-user --group --user --role-id `}, - Validate: func(rt *shortcut.RuntimeContext) error { - return validateChatRoleSetUserRoleFlags(rt) + {Name: "role-ids", Type: shortcut.FlagStringSlice, Desc: "群身份 openRoleId 列表(空则清除全部)", Required: true}, }, + Tips: []string{`dws chat +chat-role-set-user --group --user --role-ids roleId1,roleId2`}, Execute: func(rt *shortcut.RuntimeContext) error { user := rt.Str("user") params := map[string]any{ "openConversationId": rt.Str("group"), - "openRoleIds": chatRoleSetUserRoleIDs(rt), + "openRoleIds": rt.StrSlice("role-ids"), } if isOpenID(user) { params["openDingTalkId"] = user @@ -1936,43 +1930,6 @@ var ChatRoleSetUser = shortcut.Shortcut{ }, } -func validateChatRoleSetUserRoleFlags(rt *shortcut.RuntimeContext) error { - roleIDChanged := rt.Changed("role-id") - roleIDsChanged := rt.Changed("role-ids") - switch { - case roleIDChanged && roleIDsChanged: - return apperrors.NewValidation("--role-id 与 --role-ids 不能同时指定") - case roleIDChanged: - roleIDs := compactChatRoleSetUserRoleIDs(rt.StrSlice("role-id")) - if len(roleIDs) == 0 { - return apperrors.NewValidation("--role-id 不能为空") - } - if len(roleIDs) > 1 { - return apperrors.NewValidation("--role-id 只允许指定一个群身份") - } - case !roleIDChanged && !roleIDsChanged: - return apperrors.NewValidation("缺少必填参数 --role-id") - } - return nil -} - -func chatRoleSetUserRoleIDs(rt *shortcut.RuntimeContext) []string { - if rt.Changed("role-id") { - return compactChatRoleSetUserRoleIDs(rt.StrSlice("role-id")) - } - return rt.StrSlice("role-ids") -} - -func compactChatRoleSetUserRoleIDs(values []string) []string { - out := values[:0] - for _, value := range values { - if value = strings.TrimSpace(value); value != "" { - out = append(out, value) - } - } - return out -} - // ChatRoleRemoveUser removes specific roles from a user (remove_custom_user_roles, im). var ChatRoleRemoveUser = shortcut.Shortcut{ Service: "chat", diff --git a/scripts/policy/interface-migrations/approved-flag-migrations-v1.json b/scripts/policy/interface-migrations/approved-flag-migrations-v1.json index 700f46d0..c1c596fa 100644 --- a/scripts/policy/interface-migrations/approved-flag-migrations-v1.json +++ b/scripts/policy/interface-migrations/approved-flag-migrations-v1.json @@ -790,7 +790,7 @@ "required": true } }, - "state": "pending", + "state": "consumed", "reason": "保留旧 argv 兼容性,并将单值群身份 flag 设为唯一可见入口" }, {