fix(chat): align im id flag migration scope

This commit is contained in:
长真
2026-08-12 23:45:05 +08:00
parent a55bd9bff8
commit dbee2de1d5
9 changed files with 414 additions and 155 deletions
+91 -71
View File
@@ -889,11 +889,9 @@ var generatedParamAliases = []ParamAliasEntry{
Blocked: []string{"cursor"},
},
{
CLIPath: "chat category add-conv",
Aliases: map[string]string{
"chat-id": "conversation-id",
},
Blocked: []string{"category-id", "conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
CLIPath: "chat category add-conv",
Blocked: []string{"category-id"},
Ambiguous: []string{"chat", "chat-id", "open-conversation-id"},
},
{
CLIPath: "chat category create",
@@ -918,11 +916,9 @@ var generatedParamAliases = []ParamAliasEntry{
Blocked: []string{"category-ids"},
},
{
CLIPath: "chat category remove-conv",
Aliases: map[string]string{
"chat-id": "conversation-id",
},
Blocked: []string{"category-id", "conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
CLIPath: "chat category remove-conv",
Blocked: []string{"category-id"},
Ambiguous: []string{"chat", "chat-id", "open-conversation-id"},
},
{
CLIPath: "chat category rename",
@@ -934,37 +930,44 @@ var generatedParamAliases = []ParamAliasEntry{
{
CLIPath: "chat chmod",
Aliases: map[string]string{
"chat-id": "conversation-id",
"staff-id": "user",
"uid": "user",
"user-id": "user",
"userid": "user",
"chat": "conversation-id",
"chat-id": "conversation-id",
"group": "conversation-id",
"open-conversation-id": "conversation-id",
"staff-id": "user",
"uid": "user",
"user-id": "user",
"userid": "user",
},
Blocked: []string{"at-user-ids", "conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "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", "source", "src-conversation-id", "target", "to-user", "user-ids", "users"},
},
{
CLIPath: "chat clear-messages",
Aliases: map[string]string{
"chat-id": "conversation-id",
"chat-id": "conversation-id",
"group": "conversation-id",
"open-conversation-id": "conversation-id",
},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
},
{
CLIPath: "chat clear-red-point",
Aliases: map[string]string{
"chat-id": "conversation-id",
"chat-id": "conversation-id",
"group": "conversation-id",
"open-conversation-id": "conversation-id",
},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
},
{
CLIPath: "chat conversation-info",
Aliases: map[string]string{
"chat-id": "conversation-id",
"staff-id": "user",
"uid": "user",
"userid": "user",
},
Blocked: []string{"at-user-ids", "conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "target", "to-user", "user-ids", "users"},
Blocked: []string{"at-user-ids", "name", "to-user", "user-ids", "users"},
Ambiguous: []string{"chat-id", "open-conversation-id"},
},
{
CLIPath: "chat group audit-join-validation",
@@ -976,9 +979,12 @@ var generatedParamAliases = []ParamAliasEntry{
{
CLIPath: "chat group bots",
Aliases: map[string]string{
"chat-id": "conversation-id",
"chat": "group",
"chat-id": "group",
"conversation-id": "group",
"open-conversation-id": "group",
},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "id", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
},
{
CLIPath: "chat group create",
@@ -1181,19 +1187,16 @@ var generatedParamAliases = []ParamAliasEntry{
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
},
{
CLIPath: "chat group-mute",
Aliases: map[string]string{
"chat-id": "conversation-id",
},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
CLIPath: "chat group-mute",
Ambiguous: []string{"chat-id", "open-conversation-id"},
},
{
CLIPath: "chat group-mute-member",
Aliases: map[string]string{
"chat-id": "conversation-id",
"user-ids": "users",
},
Blocked: []string{"at-user-ids", "conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "staff-id", "target", "uid", "userid"},
Blocked: []string{"at-user-ids", "staff-id", "uid", "userid"},
Ambiguous: []string{"chat-id", "open-conversation-id"},
},
{
CLIPath: "chat group-role add",
@@ -1256,21 +1259,29 @@ var generatedParamAliases = []ParamAliasEntry{
{
CLIPath: "chat hide",
Aliases: map[string]string{
"chat-id": "conversation-id",
"chat-id": "conversation-id",
"group": "conversation-id",
"open-conversation-id": "conversation-id",
},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
},
{
CLIPath: "chat mark-read",
Aliases: map[string]string{
"chat-id": "conversation-id",
"chat-id": "conversation-id",
"group": "conversation-id",
"msg-id": "message-id",
"open-conversation-id": "conversation-id",
"open-message-id": "message-id",
},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "message-ids", "msg-ids", "name", "open-conversation-ids", "open-message-ids", "open-task-id", "ref-msg-id", "resource-id", "source", "src-conversation-id", "src-msg-id", "target", "topic-id"},
},
{
CLIPath: "chat mark-unread",
Aliases: map[string]string{
"chat-id": "conversation-id",
"chat-id": "conversation-id",
"group": "conversation-id",
"open-conversation-id": "conversation-id",
},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
},
@@ -1279,7 +1290,8 @@ var generatedParamAliases = []ParamAliasEntry{
Aliases: map[string]string{
"chat-id": "conversation-id",
},
Blocked: []string{"conversation-ids", "group-id", "group-ids", "message-ids", "msg-ids", "open-conversation-ids", "open-message-ids", "open-task-id", "ref-msg-id", "resource-id", "src-msg-id", "topic-id"},
Blocked: []string{"conversation-ids", "group-id", "group-ids", "open-conversation-ids"},
Ambiguous: []string{"open-message-id"},
},
{
CLIPath: "chat message add-favorite",
@@ -1298,7 +1310,8 @@ var generatedParamAliases = []ParamAliasEntry{
Aliases: map[string]string{
"chat-id": "conversation-id",
},
Blocked: []string{"conversation-ids", "group-id", "group-ids", "message-ids", "msg-ids", "open-conversation-ids", "open-message-ids", "open-task-id", "ref-msg-id", "resource-id", "src-msg-id", "topic-id"},
Blocked: []string{"conversation-ids", "group-id", "group-ids", "open-conversation-ids"},
Ambiguous: []string{"open-message-id"},
},
{
CLIPath: "chat message combine-forward",
@@ -1353,7 +1366,6 @@ var generatedParamAliases = []ParamAliasEntry{
{
CLIPath: "chat message list",
Aliases: map[string]string{
"chat-id": "conversation-id",
"max-result": "limit",
"max-results": "limit",
"page-size": "limit",
@@ -1366,7 +1378,8 @@ var generatedParamAliases = []ParamAliasEntry{
"user-id": "user",
"userid": "user",
},
Blocked: []string{"at-user-ids", "conversation-ids", "count", "cursor", "dest-conversation-id", "end", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "page", "source", "src-conversation-id", "target", "to-user", "user-ids", "users"},
Blocked: []string{"at-user-ids", "count", "cursor", "end", "name", "page", "to-user", "user-ids", "users"},
Ambiguous: []string{"chat-id", "open-conversation-id"},
},
{
CLIPath: "chat message list-all",
@@ -1413,11 +1426,8 @@ var generatedParamAliases = []ParamAliasEntry{
},
},
{
CLIPath: "chat message list-mentions",
Aliases: map[string]string{
"chat-id": "conversation-id",
},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
CLIPath: "chat message list-mentions",
Ambiguous: []string{"chat-id", "open-conversation-id"},
},
{
CLIPath: "chat message list-pin-msg",
@@ -1446,32 +1456,37 @@ var generatedParamAliases = []ParamAliasEntry{
{
CLIPath: "chat message read-status",
Aliases: map[string]string{
"chat-id": "conversation-id",
"user-ids": "users",
"chat-id": "conversation-id",
"msg-id": "message-id",
"open-conversation-id": "conversation-id",
"open-message-id": "message-id",
"user-ids": "users",
},
Blocked: []string{"at-user-ids", "conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "message-ids", "msg-ids", "name", "open-conversation-ids", "open-message-ids", "open-task-id", "ref-msg-id", "resource-id", "source", "src-conversation-id", "src-msg-id", "staff-id", "target", "topic-id", "uid", "userid"},
},
{
CLIPath: "chat message recall",
Aliases: map[string]string{
"chat-id": "conversation-id",
"chat-id": "conversation-id",
"open-conversation-id": "conversation-id",
},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "message-ids", "msg-ids", "name", "open-conversation-ids", "open-message-ids", "open-task-id", "ref-msg-id", "resource-id", "source", "src-conversation-id", "src-msg-id", "target", "topic-id"},
},
{
CLIPath: "chat message recall-by-bot",
Aliases: map[string]string{
"chat-id": "conversation-id",
"robot": "robot-code",
"robot": "robot-code",
},
Blocked: []string{"bot-code", "bot-id", "conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-bot-id", "open-conversation-ids", "robot-id", "source", "src-conversation-id", "target"},
Blocked: []string{"bot-code", "bot-id", "open-bot-id", "robot-id"},
Ambiguous: []string{"chat-id", "open-conversation-id"},
},
{
CLIPath: "chat message remove-emoji",
Aliases: map[string]string{
"chat-id": "conversation-id",
},
Blocked: []string{"conversation-ids", "group-id", "group-ids", "message-ids", "msg-ids", "open-conversation-ids", "open-message-ids", "open-task-id", "ref-msg-id", "resource-id", "src-msg-id", "topic-id"},
Blocked: []string{"conversation-ids", "group-id", "group-ids", "open-conversation-ids"},
Ambiguous: []string{"open-message-id"},
},
{
CLIPath: "chat message remove-favorite",
@@ -1490,22 +1505,23 @@ var generatedParamAliases = []ParamAliasEntry{
Aliases: map[string]string{
"chat-id": "conversation-id",
},
Blocked: []string{"conversation-ids", "group-id", "group-ids", "message-ids", "msg-ids", "open-conversation-ids", "open-message-ids", "open-task-id", "ref-msg-id", "resource-id", "src-msg-id", "topic-id"},
Blocked: []string{"conversation-ids", "group-id", "group-ids", "open-conversation-ids"},
Ambiguous: []string{"open-message-id"},
},
{
CLIPath: "chat message reply",
Aliases: map[string]string{
"chat-id": "conversation-id",
"ref-message-id": "ref-msg-id",
"chat": "conversation-id",
"chat-id": "conversation-id",
"group": "conversation-id",
"open-conversation-id": "conversation-id",
"ref-message-id": "ref-msg-id",
},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "message-id", "msg-id", "msg-ids", "name", "open-conversation-ids", "open-message-id", "source", "src-conversation-id", "src-msg-id", "staff-id", "target", "uid", "user", "user-id", "userid"},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "id", "message-id", "msg-id", "msg-ids", "name", "open-conversation-ids", "open-message-id", "source", "src-conversation-id", "src-msg-id", "staff-id", "target", "uid", "user", "user-id", "userid"},
},
{
CLIPath: "chat message search",
Aliases: map[string]string{
"chat-id": "conversation-id",
},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
CLIPath: "chat message search",
Ambiguous: []string{"chat-id", "open-conversation-id"},
},
{
CLIPath: "chat message search-advanced",
@@ -1518,7 +1534,6 @@ var generatedParamAliases = []ParamAliasEntry{
{
CLIPath: "chat message send",
Aliases: map[string]string{
"chat-id": "conversation-id",
"file": "file-path",
"staff-id": "user",
"to-user": "user",
@@ -1526,18 +1541,18 @@ var generatedParamAliases = []ParamAliasEntry{
"user-id": "user",
"userid": "user",
},
Blocked: []string{"at-user-ids", "conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "target", "user-ids", "users"},
Blocked: []string{"at-user-ids", "name", "user-ids", "users"},
Ambiguous: []string{"chat-id", "open-conversation-id"},
},
{
CLIPath: "chat message send-by-bot",
Aliases: map[string]string{
"at-users": "at-user-ids",
"chat-id": "conversation-id",
"robot": "robot-code",
"user-ids": "users",
},
Blocked: []string{"bot-code", "bot-id", "conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-bot-id", "open-conversation-ids", "robot-id", "source", "src-conversation-id", "staff-id", "target", "to-user-id", "uid", "user", "user-id", "userid"},
Ambiguous: []string{"at-ids"},
Blocked: []string{"bot-code", "bot-id", "open-bot-id", "robot-id", "staff-id", "to-user-id", "uid", "user", "user-id", "userid"},
Ambiguous: []string{"at-ids", "chat-id", "open-conversation-id"},
},
{
CLIPath: "chat message send-by-webhook",
@@ -1546,11 +1561,9 @@ var generatedParamAliases = []ParamAliasEntry{
},
},
{
CLIPath: "chat message send-card",
Aliases: map[string]string{
"chat-id": "conversation-id",
},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "staff-id", "target", "uid", "user", "user-id", "userid"},
CLIPath: "chat message send-card",
Blocked: []string{"staff-id", "uid", "user", "user-id", "userid"},
Ambiguous: []string{"chat", "chat-id", "open-conversation-id"},
},
{
CLIPath: "chat message set-pin-msg",
@@ -1602,23 +1615,30 @@ var generatedParamAliases = []ParamAliasEntry{
{
CLIPath: "chat mute-at-all",
Aliases: map[string]string{
"chat-id": "conversation-id",
"chat-id": "conversation-id",
"group": "conversation-id",
"open-conversation-id": "conversation-id",
},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
},
{
CLIPath: "chat mute-red-envelope",
Aliases: map[string]string{
"chat-id": "conversation-id",
"chat-id": "conversation-id",
"group": "conversation-id",
"open-conversation-id": "conversation-id",
},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
},
{
CLIPath: "chat set-top",
Aliases: map[string]string{
"chat-id": "conversation-id",
"chat": "conversation-id",
"chat-id": "conversation-id",
"group": "conversation-id",
"open-conversation-id": "conversation-id",
},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
Blocked: []string{"conversation-ids", "dest-conversation-id", "group-id", "group-ids", "group-name", "id", "name", "open-conversation-ids", "source", "src-conversation-id", "target"},
},
{
CLIPath: "contact +dept-members",
+16 -10
View File
@@ -49,10 +49,16 @@
"chat group members": {"bind": {"id": "open_conversation_id"}},
"chat group members add": {"bind": {"id": "open_conversation_id"}, "block": ["user-id", "open-dingtalk-id"], "note": "The real --users is a list and may contain mixed userId/openDingTalkId values; singular inputs are not promoted automatically."},
"chat group members remove": {"bind": {"id": "open_conversation_id"}},
"chat message add-emoji": {"scoped_aliases": {"chat-id": "conversation-id"}, "block": ["group-id", "group-ids", "conversation-ids", "open-conversation-ids"], "note": "Native --chat/--group/--id/--conversation-id/--open-conversation-id stay native; numeric groupId and list spellings are rejected."},
"chat message add-text-emotion": {"scoped_aliases": {"chat-id": "conversation-id"}, "block": ["group-id", "group-ids", "conversation-ids", "open-conversation-ids"], "note": "Native --chat/--group/--id/--conversation-id/--open-conversation-id stay native; numeric groupId and list spellings are rejected."},
"chat message remove-emoji": {"scoped_aliases": {"chat-id": "conversation-id"}, "block": ["group-id", "group-ids", "conversation-ids", "open-conversation-ids"], "note": "Native --chat/--group/--id/--conversation-id/--open-conversation-id stay native; numeric groupId and list spellings are rejected."},
"chat message remove-text-emotion": {"scoped_aliases": {"chat-id": "conversation-id"}, "block": ["group-id", "group-ids", "conversation-ids", "open-conversation-ids"], "note": "Native --chat/--group/--id/--conversation-id/--open-conversation-id stay native; numeric groupId and list spellings are rejected."},
"chat conversation-info": {"ambiguous": ["chat-id", "open-conversation-id"], "note": "Visible --conversation-id and legacy --group both remain executable outside the approved hidden-alias migration set."},
"chat group-mute": {"ambiguous": ["chat-id", "open-conversation-id"], "note": "Visible --conversation-id and legacy --group both remain executable outside the approved hidden-alias migration set."},
"chat group-mute-member": {"ambiguous": ["chat-id", "open-conversation-id"], "note": "Visible --conversation-id and legacy --group both remain executable outside the approved hidden-alias migration set."},
"chat message add-emoji": {"scoped_aliases": {"chat-id": "conversation-id"}, "block": ["group-id", "group-ids", "conversation-ids", "open-conversation-ids"], "ambiguous": ["open-message-id"], "note": "Native --chat/--group/--id/--conversation-id/--open-conversation-id and visible --message-id/--msg-id stay executable; numeric/list spellings are rejected."},
"chat message add-text-emotion": {"scoped_aliases": {"chat-id": "conversation-id"}, "block": ["group-id", "group-ids", "conversation-ids", "open-conversation-ids"], "ambiguous": ["open-message-id"], "note": "Native --chat/--group/--id/--conversation-id/--open-conversation-id and visible --message-id/--msg-id stay executable; numeric/list spellings are rejected."},
"chat message list-mentions": {"ambiguous": ["chat-id", "open-conversation-id"], "note": "Visible --conversation-id and legacy --group both remain executable outside the approved hidden-alias migration set."},
"chat message recall-by-bot": {"ambiguous": ["chat-id", "open-conversation-id"], "note": "Visible --conversation-id and legacy --group both remain executable outside the approved hidden-alias migration set."},
"chat message remove-emoji": {"scoped_aliases": {"chat-id": "conversation-id"}, "block": ["group-id", "group-ids", "conversation-ids", "open-conversation-ids"], "ambiguous": ["open-message-id"], "note": "Native --chat/--group/--id/--conversation-id/--open-conversation-id and visible --message-id/--msg-id stay executable; numeric/list spellings are rejected."},
"chat message remove-text-emotion": {"scoped_aliases": {"chat-id": "conversation-id"}, "block": ["group-id", "group-ids", "conversation-ids", "open-conversation-ids"], "ambiguous": ["open-message-id"], "note": "Native --chat/--group/--id/--conversation-id/--open-conversation-id and visible --message-id/--msg-id stay executable; numeric/list spellings are rejected."},
"chat message search": {"ambiguous": ["chat-id", "open-conversation-id"], "note": "Visible --conversation-id and legacy --group both remain executable outside the approved hidden-alias migration set."},
"chat mute": {"scoped_aliases": {"chat-id": "conversation-id"}, "block": ["group-id", "group-ids", "conversation-ids", "open-conversation-ids"], "note": "Native --conversation-id and hidden compatibility --group/--id/--chat/--open-conversation-id remain unchanged; reviewed chat-id reduces to --conversation-id."},
"drive list": {"ambiguous": ["space"], "note": "both --space-id and native compatibility --workspace-id/--workspace exist; bare --space cannot choose one"},
"drive upload": {"ambiguous": ["space"], "note": "both --space-id and native compatibility --workspace-id/--workspace exist; bare --space cannot choose one"},
@@ -73,12 +79,12 @@
"chat +unread-chats": {"scoped_aliases": {"limit": "count", "size": "count"}, "scope_strict": true, "note": "On this exact command, limit and size both denote the returned unread-conversation count."},
"chat message list-unread-conversations": {"scoped_aliases": {"limit": "count", "size": "count"}, "scope_strict": true, "note": "On this exact command, limit and size both denote the returned unread-conversation count."},
"chat +messages-list-direct": {"scoped_aliases": {"start": "time"}, "block": ["end"], "scope_strict": true, "note": "This exact command accepts one start boundary in yyyy-MM-dd HH:mm:ss; an end-only input cannot be represented."},
"chat message list": {"scoped_aliases": {"start": "time"}, "block": ["end"], "scope_strict": true, "note": "This exact command accepts one start boundary in yyyy-MM-dd HH:mm:ss; an end-only input cannot be represented."},
"chat message list": {"scoped_aliases": {"start": "time"}, "block": ["end"], "ambiguous": ["chat-id", "open-conversation-id"], "scope_strict": true, "note": "This exact command accepts one start boundary in yyyy-MM-dd HH:mm:ss; an end-only input cannot be represented. Visible --conversation-id and legacy --group both remain executable outside the approved hidden-alias migration set."},
"chat message list-by-sender": {"scoped_aliases": {"user-id": "sender-user-id", "open-dingtalk-id": "sender-open-dingtalk-id"}, "block": ["time"], "scope_strict": true, "note": "Only same-role sender identifiers are mapped; --time cannot supply the required RFC3339 start/end range."},
"contact +resolve-dept": {"bind": {"name": "search_query"}, "note": "The real --name is a department-name search keyword and carries the search_query concept on this shortcut."},
"contact +list-sub-depts": {"block": ["name", "query"], "note": "--dept is an integer department id; names and search queries require a separate resolution command"},
"contact +dept-members": {"bind": {"dept": "search_query"}, "scoped_aliases": {"name": "dept"}, "note": "The real --dept is a department-name search keyword; search spellings come from search_query, while --name remains command-scoped."},
"chat message send": {"scoped_aliases": {"to-user": "user", "file": "file-path"}, "note": "Recipient and local-file-path aliases are exact to this command; obsolete file metadata flags remain unsupported."},
"chat message send": {"scoped_aliases": {"to-user": "user", "file": "file-path"}, "ambiguous": ["chat-id", "open-conversation-id"], "note": "Recipient and local-file-path aliases are exact to this command; obsolete file metadata flags remain unsupported. Visible --conversation-id and legacy --group both remain executable outside the approved hidden-alias migration set."},
"chat +group-members": {"bind": {"group": "group_name"}, "note": "The real --group is a group-name search keyword on this shortcut, not an identifier."},
"chat +category-create": {"scoped_aliases": {"name": "title"}, "scope_strict": true, "note": "The reviewed name/title mapping preserves the category display-name value on this exact shortcut."},
"chat category create": {"scoped_aliases": {"name": "title"}, "scope_strict": true, "note": "The reviewed name/title mapping preserves the category display-name value on this exact command."},
@@ -87,8 +93,8 @@
"chat +category-delete": {"block": ["category-ids"], "note": "This command requires one category id; list cardinality is not reduced automatically."},
"chat category delete": {"block": ["category-ids"], "note": "This command requires one category id; list cardinality is not reduced automatically."},
"chat category list-conversations": {"block": ["category-ids"], "note": "This command requires one category id; list cardinality is not reduced automatically."},
"chat category add-conv": {"block": ["category-id"], "note": "This command requires a category-id list; one id is not promoted into a batch input."},
"chat category remove-conv": {"block": ["category-id"], "note": "This command requires a category-id list; one id is not promoted into a batch input."},
"chat category add-conv": {"block": ["category-id"], "ambiguous": ["chat", "chat-id", "open-conversation-id"], "note": "This command requires a category-id list; one id is not promoted into a batch input. Visible --conversation-id and legacy --group both remain executable outside the approved hidden-alias migration set."},
"chat category remove-conv": {"block": ["category-id"], "ambiguous": ["chat", "chat-id", "open-conversation-id"], "note": "This command requires a category-id list; one id is not promoted into a batch input. Visible --conversation-id and legacy --group both remain executable outside the approved hidden-alias migration set."},
"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."},
@@ -98,7 +104,7 @@
"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."},
"doc block insert": {"block": ["before-block-id"], "note": "Parent and reference roles remain distinct. --before-block-id needs both --ref-block and --where before, while role-free --block-id cannot choose parent versus reference.", "scoped_aliases": {"parent-block-id": "parent-block", "ref-block-id": "ref-block", "reference-block-id": "ref-block"}, "ambiguous": ["block-id"], "scope_strict": true},
"chat message send-by-bot": {"scoped_aliases": {"at-users": "at-user-ids"}, "block": ["user-id", "to-user-id"], "ambiguous": ["at-ids"], "note": "The reviewed @ userId-list alias is exact; singular recipients are not promoted, and bare --at-ids cannot choose an identifier domain."},
"chat message send-by-bot": {"scoped_aliases": {"at-users": "at-user-ids"}, "block": ["user-id", "to-user-id"], "ambiguous": ["at-ids", "chat-id", "open-conversation-id"], "note": "The reviewed @ userId-list alias is exact; singular recipients are not promoted, and bare --at-ids cannot choose an identifier domain. Visible --conversation-id and legacy --group both remain executable outside the approved hidden-alias migration set."},
"doc +export-get": {"block": ["doc-id", "document-id", "file-id", "node", "node-id", "task-id", "url"], "note": "This command queries one export jobId. Document node identifiers and import taskId spellings are different entities and are rejected.", "scoped_aliases": {"export-job-id": "job-id"}, "scope_strict": true},
"doc block delete": {"block": ["index"], "note": "index (position) vs node (node id) are different"},
"doc +copy": {"scoped_aliases": {"folder-id": "folder", "parent-folder": "folder", "parent-folder-id": "folder", "parent-node-id": "folder"}, "block": ["parent-id"], "scope_strict": true, "note": "This exact Doc command expects a Doc folder nodeId/dentryUuid/URL. Reviewed folder spellings preserve that value; generic --parent-id stays blocked because it may carry a numeric Drive dentryId."},
@@ -130,7 +136,7 @@
"chat +messages-read-status": {"block": ["user-id", "open-dingtalk-id"], "note": "The real --users is a mixed userId/openDingTalkId list."},
"chat category create-smart": {"bind": {"members": "open_dingtalk_ids"}, "scoped_aliases": {"title": "name"}, "note": "The real --members is an openDingTalkId list; the reviewed title/name alias is exact to the category display name."},
"chat message reply": {"block": ["user", "user-id", "userid", "uid", "staff-id"], "note": "The required --ref-sender is a role-specific openDingTalkId and must not accept generic userId spellings."},
"chat message send-card": {"block": ["user", "user-id", "userid", "uid", "staff-id"], "note": "The real --receiver is a role-specific openDingTalkId and must not accept generic userId spellings."},
"chat message send-card": {"block": ["user", "user-id", "userid", "uid", "staff-id"], "ambiguous": ["chat", "chat-id", "open-conversation-id"], "note": "The real --receiver is a role-specific openDingTalkId and must not accept generic userId spellings. Visible --conversation-id and legacy --group both remain executable outside the approved hidden-alias migration set."},
"chat +category-add-conversation": {"block": ["category-id"], "note": "The real --category-ids is a list; a singular category ID is not promoted automatically."},
"chat +category-list-conversations": {"block": ["category-ids"], "note": "The real --category-id is singular; list cardinality is not reduced automatically."},
"chat +category-remove-conversation": {"block": ["category-id"], "note": "The real --category-ids is a list; a singular category ID is not promoted automatically."},
+19 -18
View File
@@ -1396,7 +1396,8 @@ func TestDeliveryCatalogChatParamDeclsFrom87910880Reviewed(t *testing.T) {
}
}
// Hidden conversation aliases must stay unpublished (merge-base parity).
// Manifest-covered migrations hide legacy aliases; manifest-external
// commands keep their existing visible flags for compatibility.
editLeaf, err := queryDeliverySchemaPayload([]string{"chat message edit"})
if err != nil {
t.Fatal(err)
@@ -1415,10 +1416,11 @@ func TestDeliveryCatalogChatParamDeclsFrom87910880Reviewed(t *testing.T) {
if _, ok := listParams["conversation-id"]; !ok {
t.Fatalf("chat category list-by-conv missing public canonical --conversation-id")
}
for _, hidden := range []string{"group", "id"} {
if _, ok := listParams[hidden]; ok {
t.Fatalf("chat category list-by-conv unexpectedly publishes hidden alias --%s", hidden)
}
if _, ok := listParams["group"]; !ok {
t.Fatalf("chat category list-by-conv unexpectedly hides manifest-external --group")
}
if _, ok := listParams["id"]; ok {
t.Fatalf("chat category list-by-conv unexpectedly publishes hidden alias --id")
}
for _, path := range []string{
@@ -1435,9 +1437,9 @@ func TestDeliveryCatalogChatParamDeclsFrom87910880Reviewed(t *testing.T) {
if _, ok := params["conversation-id"]; !ok {
t.Fatalf("%s missing public canonical --conversation-id", path)
}
for _, hidden := range []string{"group", "id", "chat"} {
if _, ok := params[hidden]; ok {
t.Fatalf("%s unexpectedly publishes hidden alias --%s", path, hidden)
for _, visible := range []string{"group", "id", "chat"} {
if _, ok := params[visible]; !ok {
t.Fatalf("%s unexpectedly hides manifest-external --%s", path, visible)
}
}
}
@@ -1447,17 +1449,16 @@ func TestDeliveryCatalogChatParamDeclsFrom87910880Reviewed(t *testing.T) {
t.Fatal(err)
}
groupBotsParams := schemaMap(groupBots["parameters"])
if _, ok := groupBotsParams["conversation-id"]; !ok {
t.Fatal("chat group bots missing public canonical --conversation-id")
group := groupBotsParams["group"]
if group == nil {
t.Fatal("chat group bots missing public legacy --group")
}
groupName := groupBotsParams["group-name"]
if groupName == nil {
t.Fatal("chat group bots missing public canonical --group-name")
if group["property"] != "openConversationId" {
t.Fatalf("chat group bots --group property = %#v, want openConversationId", group["property"])
}
if groupName["property"] != "groupName" {
t.Fatalf("chat group bots --group-name property = %#v, want groupName", groupName["property"])
}
if _, ok := groupBotsParams["group"]; ok {
t.Fatal("chat group bots unexpectedly publishes hidden --group alias")
for _, migrated := range []string{"conversation-id", "group-name"} {
if _, ok := groupBotsParams[migrated]; ok {
t.Fatalf("chat group bots unexpectedly publishes migrated --%s", migrated)
}
}
}
+10
View File
@@ -116,6 +116,16 @@ func TestCrossPlatformCoverageRegisterFlagsAllKinds(t *testing.T) {
}
}
func TestCrossPlatformCoverageAnnotateFlagAliasIgnoresMissingInputs(t *testing.T) {
AnnotateFlagAlias(nil, "alias", "canonical")
cmd := newTestCommand()
AnnotateFlagAlias(cmd, "missing", "canonical")
if flag := cmd.Flags().Lookup("missing"); flag != nil {
t.Fatalf("unexpected missing flag registered: %#v", flag)
}
}
// ── effective value fallback chain ─────────────────────────────────
func TestCrossPlatformCoverageEffectiveValueFallbackChain(t *testing.T) {
+125 -26
View File
@@ -238,18 +238,101 @@ func chatMessageID(cmd *cobra.Command) (string, error) {
}
func installChatIMIDFlagAliases(root *cobra.Command) {
var visit func(*cobra.Command)
visit = func(cmd *cobra.Command) {
installChatFlagAliases(cmd, "conversation-id", []string{"group", "id", "chat", "open-conversation-id"}, requireChatConversationID)
installChatFlagAliases(cmd, "message-id", []string{"msg-id", "open-message-id"}, chatMessageID)
clearChatAliasRequiredAnnotations(cmd, "group", "id", "chat", "open-conversation-id", "msg-id", "open-message-id")
conversationMigrationPaths := chatMigrationPathSet(chatPendingConversationIDMigrationPaths)
messageMigrationPaths := chatMigrationPathSet(chatPendingMessageIDMigrationPaths)
var visit func(*cobra.Command, []string)
visit = func(cmd *cobra.Command, path []string) {
key := strings.Join(path, " ")
if conversationMigrationPaths[key] {
installChatFlagAliases(cmd, "conversation-id", []string{"group", "id", "chat", "open-conversation-id"}, requireChatConversationID)
clearChatAliasRequiredAnnotations(cmd, "group", "id", "chat", "open-conversation-id")
}
if messageMigrationPaths[key] {
installChatFlagAliases(cmd, "message-id", []string{"msg-id", "open-message-id"}, chatMessageID)
clearChatAliasRequiredAnnotations(cmd, "msg-id", "open-message-id")
}
for _, child := range cmd.Commands() {
visit(child)
visit(child, append(path, child.Name()))
}
}
visit(root)
visit(root, nil)
restoreChatGroupBotsLegacyRequired(root)
restoreChatPendingMigrationCanonicalRequired(root)
restoreChatManifestExternalVisibleFlags(root)
}
func chatMigrationPathSet(paths [][]string) map[string]bool {
set := make(map[string]bool, len(paths))
for _, path := range paths {
set[strings.Join(path, " ")] = true
}
return set
}
func restoreChatManifestExternalVisibleFlags(root *cobra.Command) {
if root == nil {
return
}
for _, spec := range chatManifestExternalVisibleFlagSpecs {
cmd, _, err := root.Find(spec.path)
if err != nil || cmd == nil {
continue
}
for _, flag := range spec.flags {
ensureVisibleStringFlag(cmd, flag.name, flag.usage)
}
for _, flag := range spec.optionalFlags {
if f := cmd.Flags().Lookup(flag); f != nil && f.Annotations != nil {
delete(f.Annotations, cobra.BashCompOneRequiredFlag)
}
}
}
}
func ensureVisibleStringFlag(cmd *cobra.Command, name, usage string) {
flag := cmd.Flags().Lookup(name)
if flag == nil {
cmd.Flags().String(name, "", usage)
flag = cmd.Flags().Lookup(name)
}
if flag != nil {
flag.Hidden = false
}
}
type chatVisibleFlagSpec struct {
name string
usage string
}
type chatVisibleFlagCommandSpec struct {
path []string
flags []chatVisibleFlagSpec
optionalFlags []string
}
var chatManifestExternalVisibleFlagSpecs = []chatVisibleFlagCommandSpec{
{path: []string{"category", "add-conv"}, flags: []chatVisibleFlagSpec{{"group", "--conversation-id 的别名"}}},
{path: []string{"category", "list-by-conv"}, flags: []chatVisibleFlagSpec{{"group", "--conversation-id 的别名"}}, optionalFlags: []string{"conversation-id"}},
{path: []string{"category", "remove-conv"}, flags: []chatVisibleFlagSpec{{"group", "--conversation-id 的别名"}}},
{path: []string{"conversation-info"}, flags: []chatVisibleFlagSpec{{"group", "--conversation-id 的别名"}}},
{path: []string{"file", "upload"}, flags: []chatVisibleFlagSpec{{"group", "--conversation-id 的别名"}}},
{path: []string{"group", "get-mute-config"}, flags: []chatVisibleFlagSpec{{"group", "--conversation-id 的别名"}}},
{path: []string{"group-mute"}, flags: []chatVisibleFlagSpec{{"group", "--conversation-id 的别名"}}},
{path: []string{"group-mute-member"}, flags: []chatVisibleFlagSpec{{"group", "--conversation-id 的别名"}}},
{path: []string{"message", "add-emoji"}, flags: []chatVisibleFlagSpec{{"msg-id", "--message-id 的别名"}}},
{path: []string{"message", "add-text-emotion"}, flags: []chatVisibleFlagSpec{{"msg-id", "--message-id 的别名"}}},
{path: []string{"message", "list"}, flags: []chatVisibleFlagSpec{{"group", "--conversation-id 的别名"}}},
{path: []string{"message", "list-mentions"}, flags: []chatVisibleFlagSpec{{"group", "--conversation-id 的别名"}}},
{path: []string{"message", "recall-by-bot"}, flags: []chatVisibleFlagSpec{{"group", "--conversation-id 的别名"}}},
{path: []string{"message", "remove-emoji"}, flags: []chatVisibleFlagSpec{{"msg-id", "--message-id 的别名"}}},
{path: []string{"message", "remove-text-emotion"}, flags: []chatVisibleFlagSpec{{"msg-id", "--message-id 的别名"}}},
{path: []string{"message", "search"}, flags: []chatVisibleFlagSpec{{"group", "--conversation-id 的别名"}}},
{path: []string{"message", "send"}, flags: []chatVisibleFlagSpec{{"group", "--conversation-id 的别名"}}},
{path: []string{"message", "send-by-bot"}, flags: []chatVisibleFlagSpec{{"group", "--conversation-id 的别名"}}},
{path: []string{"message", "send-card"}, flags: []chatVisibleFlagSpec{{"group", "--conversation-id 的别名"}, {"receiver", "--open-dingtalk-id 的兼容别名"}}},
{path: []string{"message", "update-text-emotion"}, flags: []chatVisibleFlagSpec{{"group", "--conversation-id 的别名"}, {"id", "--conversation-id 的别名"}, {"chat", "--conversation-id 的别名"}}, optionalFlags: []string{"conversation-id"}},
{path: []string{"mute"}, flags: []chatVisibleFlagSpec{{"chat", "--conversation-id 的别名"}, {"id", "--conversation-id 的别名"}}},
}
func restoreChatGroupBotsLegacyRequired(root *cobra.Command) {
@@ -5330,12 +5413,11 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
Example: ` dws chat category list-by-conv --conversation-id <openConversationId>
# 查询群 ID: dws chat search --query "群名"`,
RunE: func(cmd *cobra.Command, args []string) error {
groupID := flagOrFallback(cmd, "conversation-id", "group", "id")
if groupID == "" {
return fmt.Errorf("flag --group is required")
if err := validateRequiredFlagWithAliases(cmd, "conversation-id", "group", "id"); err != nil {
return err
}
return callMCPToolOnServer("im", "list_conv_categories_by_conv", map[string]any{
"openConversationId": groupID,
"openConversationId": flagOrFallback(cmd, "conversation-id", "group", "id"),
})
},
}
@@ -5366,6 +5448,7 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
},
Parameters: []contract.ParamDecl{
{Name: "conversation-id", Property: "openConversationId", Required: boolPtr(true)},
{Name: "group", Property: "openConversationId", Required: boolPtr(false)},
{Name: "id", Property: "openConversationId", Required: boolPtr(false)},
},
},
@@ -5522,7 +5605,7 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
Example: ` dws chat message add-emoji --conversation-id <openConversationId> --message-id <openMsgId> --emoji "赞"
# 查询会话 ID: dws chat search --query "群名"`,
RunE: func(cmd *cobra.Command, args []string) error {
if err := validateRequiredFlagWithAliases(cmd, "conversation-id", "group", "id", "chat"); err != nil {
if err := validateRequiredFlagWithAliases(cmd, "conversation-id", "group", "id", "chat", "open-conversation-id"); err != nil {
return err
}
if _, err := chatMessageID(cmd); err != nil {
@@ -5532,7 +5615,7 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
return err
}
return callMCPToolOnServer("im", "add_emoji_reaction", map[string]any{
"openConversationId": flagOrFallback(cmd, "conversation-id", "group", "id", "chat"),
"openConversationId": flagOrFallback(cmd, "conversation-id", "group", "id", "chat", "open-conversation-id"),
"openMsgId": flagOrFallback(cmd, "message-id", "msg-id"),
"emojiName": mustGetFlag(cmd, "emoji"),
})
@@ -5574,6 +5657,7 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
chatMessageAddEmojiCmd.Flags().String("group", "", "--conversation-id 的别名")
chatMessageAddEmojiCmd.Flags().String("id", "", "--conversation-id 的别名")
chatMessageAddEmojiCmd.Flags().String("chat", "", "--conversation-id 的别名")
chatMessageAddEmojiCmd.Flags().String("open-conversation-id", "", "--conversation-id 的别名")
chatMessageAddEmojiCmd.Flags().String("message-id", "", "消息 openMsgId (必填)")
chatMessageAddEmojiCmd.Flags().String("emoji", "", "emoji 表情名称 (必填)")
@@ -5583,7 +5667,7 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
Example: ` dws chat message remove-emoji --conversation-id <openConversationId> --message-id <openMsgId> --emoji "赞"
# 查询会话 ID: dws chat search --query "群名"`,
RunE: func(cmd *cobra.Command, args []string) error {
if err := validateRequiredFlagWithAliases(cmd, "conversation-id", "group", "id", "chat"); err != nil {
if err := validateRequiredFlagWithAliases(cmd, "conversation-id", "group", "id", "chat", "open-conversation-id"); err != nil {
return err
}
if _, err := chatMessageID(cmd); err != nil {
@@ -5593,7 +5677,7 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
return err
}
return callMCPToolOnServer("im", "remove_emoji_reaction", map[string]any{
"openConversationId": flagOrFallback(cmd, "conversation-id", "group", "id", "chat"),
"openConversationId": flagOrFallback(cmd, "conversation-id", "group", "id", "chat", "open-conversation-id"),
"openMsgId": flagOrFallback(cmd, "message-id", "msg-id"),
"emojiName": mustGetFlag(cmd, "emoji"),
})
@@ -5635,6 +5719,7 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
chatMessageRemoveEmojiCmd.Flags().String("group", "", "--conversation-id 的别名")
chatMessageRemoveEmojiCmd.Flags().String("id", "", "--conversation-id 的别名")
chatMessageRemoveEmojiCmd.Flags().String("chat", "", "--conversation-id 的别名")
chatMessageRemoveEmojiCmd.Flags().String("open-conversation-id", "", "--conversation-id 的别名")
chatMessageRemoveEmojiCmd.Flags().String("message-id", "", "消息 openMsgId (必填)")
chatMessageRemoveEmojiCmd.Flags().String("emoji", "", "emoji 表情名称 (必填)")
@@ -5643,7 +5728,7 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
Short: "对消息添加文字表情回应",
Example: ` dws chat message add-text-emotion --conversation-id <openConversationId> --message-id <openMsgId> --emotion-id <emotionId> --emotion-name "赞" --text "nice" --background-id im_bg_5`,
RunE: func(cmd *cobra.Command, args []string) error {
if err := validateRequiredFlagWithAliases(cmd, "conversation-id", "group", "id", "chat"); err != nil {
if err := validateRequiredFlagWithAliases(cmd, "conversation-id", "group", "id", "chat", "open-conversation-id"); err != nil {
return err
}
if _, err := chatMessageID(cmd); err != nil {
@@ -5653,7 +5738,7 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
return err
}
return callMCPToolOnServer("im", "add_text_emotion", map[string]any{
"openConversationId": flagOrFallback(cmd, "conversation-id", "group", "id", "chat"),
"openConversationId": flagOrFallback(cmd, "conversation-id", "group", "id", "chat", "open-conversation-id"),
"openMsgId": flagOrFallback(cmd, "message-id", "msg-id"),
"emotionId": mustGetFlag(cmd, "emotion-id"),
"emotionName": mustGetFlag(cmd, "emotion-name"),
@@ -5697,6 +5782,7 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
chatMessageAddTextEmotionCmd.Flags().String("group", "", "--conversation-id 的别名")
chatMessageAddTextEmotionCmd.Flags().String("id", "", "--conversation-id 的别名")
chatMessageAddTextEmotionCmd.Flags().String("chat", "", "--conversation-id 的别名")
chatMessageAddTextEmotionCmd.Flags().String("open-conversation-id", "", "--conversation-id 的别名")
chatMessageAddTextEmotionCmd.Flags().String("message-id", "", "消息 openMsgId (必填)")
chatMessageAddTextEmotionCmd.Flags().String("emotion-id", "", "表情 ID (必填,通过 create-text-emotion 获取)")
chatMessageAddTextEmotionCmd.Flags().String("emotion-name", "", "表情名称 (必填)")
@@ -5708,7 +5794,7 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
Short: "移除消息的文字表情回应",
Example: ` dws chat message remove-text-emotion --conversation-id <openConversationId> --message-id <openMsgId> --emotion-id <emotionId> --emotion-name "赞" --text "nice" --background-id <backgroundId>`,
RunE: func(cmd *cobra.Command, args []string) error {
if err := validateRequiredFlagWithAliases(cmd, "conversation-id", "group", "id", "chat"); err != nil {
if err := validateRequiredFlagWithAliases(cmd, "conversation-id", "group", "id", "chat", "open-conversation-id"); err != nil {
return err
}
if _, err := chatMessageID(cmd); err != nil {
@@ -5718,7 +5804,7 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
return err
}
return callMCPToolOnServer("im", "remove_text_emotion", map[string]any{
"openConversationId": flagOrFallback(cmd, "conversation-id", "group", "id", "chat"),
"openConversationId": flagOrFallback(cmd, "conversation-id", "group", "id", "chat", "open-conversation-id"),
"openMsgId": flagOrFallback(cmd, "message-id", "msg-id"),
"emotionId": mustGetFlag(cmd, "emotion-id"),
"emotionName": mustGetFlag(cmd, "emotion-name"),
@@ -5762,6 +5848,7 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
chatMessageRemoveTextEmotionCmd.Flags().String("group", "", "--conversation-id 的别名")
chatMessageRemoveTextEmotionCmd.Flags().String("id", "", "--conversation-id 的别名")
chatMessageRemoveTextEmotionCmd.Flags().String("chat", "", "--conversation-id 的别名")
chatMessageRemoveTextEmotionCmd.Flags().String("open-conversation-id", "", "--conversation-id 的别名")
chatMessageRemoveTextEmotionCmd.Flags().String("message-id", "", "消息 openMsgId (必填)")
chatMessageRemoveTextEmotionCmd.Flags().String("emotion-id", "", "表情 ID (必填)")
chatMessageRemoveTextEmotionCmd.Flags().String("emotion-name", "", "表情名称 (必填)")
@@ -5773,7 +5860,7 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
Short: "更新消息的文字表情回应",
Example: ` dws chat message update-text-emotion --conversation-id <openConversationId> --message-id <openMsgId> --old-emotion-id <oldEmotionId> --emotion-id <emotionId> --emotion-name "赞" --text "nice" --background-id im_bg_5`,
RunE: func(cmd *cobra.Command, args []string) error {
if err := validateRequiredFlagWithAliases(cmd, "conversation-id", "group", "id", "chat"); err != nil {
if err := validateRequiredFlagWithAliases(cmd, "conversation-id", "group", "id", "chat", "open-conversation-id"); err != nil {
return err
}
if _, err := chatMessageID(cmd); err != nil {
@@ -5783,7 +5870,7 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
return err
}
return callMCPToolOnServer("im", "update_text_emotion", map[string]any{
"openConversationId": flagOrFallback(cmd, "conversation-id", "group", "id", "chat"),
"openConversationId": flagOrFallback(cmd, "conversation-id", "group", "id", "chat", "open-conversation-id"),
"openMsgId": flagOrFallback(cmd, "message-id", "msg-id"),
"oldEmotionId": mustGetFlag(cmd, "old-emotion-id"),
"emotionId": mustGetFlag(cmd, "emotion-id"),
@@ -5823,16 +5910,21 @@ chat message edit 或 chat message recall 的 --message-id 和 --conversation-id
},
Parameters: []contract.ParamDecl{
{Name: "background-id", Property: "backgroundId", Required: boolPtr(true), Description: "新文字表情的背景 ID"},
{Name: "chat", Property: "openConversationId", Required: boolPtr(false), Description: "会话 openConversationId 兼容入口"},
{Name: "conversation-id", Property: "openConversationId", Required: boolPtr(false), Description: "会话 openConversationId"},
{Name: "emotion-id", Property: "emotionId", Required: boolPtr(true), Description: "新的文字表情 ID,可通过 create-text-emotion 获取"},
{Name: "emotion-name", Property: "emotionName", Required: boolPtr(true), Description: "新的文字表情名称"},
{Name: "group", Property: "openConversationId", Required: boolPtr(false), Description: "会话 openConversationId 兼容入口"},
{Name: "id", Property: "openConversationId", Required: boolPtr(false), Description: "会话 openConversationId 兼容入口"},
{Name: "message-id", Property: "openMsgId", Required: boolPtr(true), Description: "需要原地更新文字表情的消息 openMsgId"},
{Name: "old-emotion-id", Property: "oldEmotionId", Required: boolPtr(true), Description: "消息上当前文字表情的 emotionId"},
{Name: "open-conversation-id", Property: "openConversationId", Required: boolPtr(false), Description: "会话 openConversationId 兼容入口"},
{Name: "text", Property: "text", Required: boolPtr(true), Description: "新的文字表情内容"},
},
},
})
chatMessageUpdateTextEmotionCmd.Flags().String("conversation-id", "", "会话 openConversationId (必填,支持单聊/群聊)")
chatMessageUpdateTextEmotionCmd.Flags().String("open-conversation-id", "", "--conversation-id 的别名")
chatMessageUpdateTextEmotionCmd.Flags().String("message-id", "", "消息 openMsgId (必填)")
chatMessageUpdateTextEmotionCmd.Flags().String("old-emotion-id", "", "待更新的原表情 ID (必填)")
chatMessageUpdateTextEmotionCmd.Flags().String("emotion-id", "", "新表情 ID (必填)")
@@ -6751,9 +6843,12 @@ flow-status 取值:1=处理中(PROCESSING),2=输入中(INPUTTING),3=完成
- 群聊:dws chat search --query "群名"
- 单聊:dws chat conversation-info --open-dingtalk-id <openDingTalkId>
(openDingTalkId 可通过 dws contact user search --query "姓名" 获取)`,
Example: ` dws chat message forward --src-conversation-id <srcOpenConversationId> --msg-id <srcOpenMessageId> --dest-conversation-id <destOpenConversationId>`,
Example: ` dws chat message forward --src-conversation-id <srcOpenConversationId> --message-id <srcOpenMessageId> --dest-conversation-id <destOpenConversationId>`,
RunE: func(cmd *cobra.Command, args []string) error {
if err := validateRequiredFlags(cmd, "src-conversation-id", "msg-id", "dest-conversation-id"); err != nil {
if err := validateRequiredFlags(cmd, "src-conversation-id", "dest-conversation-id"); err != nil {
return err
}
if err := validateRequiredFlagWithAliases(cmd, "message-id", "msg-id"); err != nil {
return err
}
toolArgs := map[string]any{
@@ -6790,7 +6885,7 @@ flow-status 取值:1=处理中(PROCESSING),2=输入中(INPUTTING),3=完成
AgentSummary: "把一条已有消息转发到另一个会话",
UseWhen: []string{"已知源消息与源、目标会话 ID 时"},
AvoidWhen: []string{"合并转发多条消息时使用 chat message combine-forward"},
Examples: []string{"dws chat message forward --src-conversation-id <srcConversationId> --msg-id <openMessageId> --dest-conversation-id <destConversationId>"},
Examples: []string{"dws chat message forward --src-conversation-id <srcConversationId> --message-id <openMessageId> --dest-conversation-id <destConversationId>"},
},
Parameters: []contract.ParamDecl{
{Name: "dest-conversation-id", Property: "destOpenCid"},
@@ -6874,11 +6969,11 @@ flow-status 取值:1=处理中(PROCESSING),2=输入中(INPUTTING),3=完成
返回的是原始配置记录,不等同于当前被禁言成员列表;全员禁言开关也不在本命令的返回范围内。`,
Example: ` dws chat group get-mute-config --conversation-id <openConversationId>`,
RunE: func(cmd *cobra.Command, args []string) error {
if err := validateRequiredFlags(cmd, "conversation-id"); err != nil {
if err := validateRequiredFlagWithAliases(cmd, "conversation-id", "group"); err != nil {
return err
}
return callMCPToolOnServer("im", "get_group_mute_config", map[string]any{
"openConversationId": flagOrFallback(cmd, "conversation-id", "group", "id", "chat"),
"openConversationId": flagOrFallback(cmd, "conversation-id", "group"),
})
},
}
@@ -6907,9 +7002,13 @@ flow-status 取值:1=处理中(PROCESSING),2=输入中(INPUTTING),3=完成
AvoidWhen: []string{"设置全员禁言用 chat group-mute;禁言个人用 chat group-mute-member"},
Examples: []string{"dws chat group get-mute-config --conversation-id <openConversationId> --format json"},
},
Parameters: []contract.ParamDecl{
{Name: "group", Property: "openConversationId", Required: boolPtr(false)},
},
},
})
chatGroupGetMuteConfigCmd.Flags().String("conversation-id", "", "群聊 openConversationId (必填)")
chatGroupGetMuteConfigCmd.Flags().String("group", "", "--conversation-id 的别名")
chatGroupCmd.AddCommand(chatGroupGetMuteConfigCmd)
// ── group-mute: 全员禁言 ───────────────────────────────
+77 -2
View File
@@ -12,6 +12,7 @@ import (
"testing"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/edition"
"github.com/spf13/cobra"
)
func runChatCoverageCommand(t *testing.T, caller edition.ToolCaller, args ...string) error {
@@ -126,6 +127,80 @@ func TestCrossPlatformCoverageChatStableCompatibilityHintsRemainAvailable(t *tes
}
}
func TestCrossPlatformCoverageChatAliasInstallerRemainingEdges(t *testing.T) {
restoreChatManifestExternalVisibleFlags(nil)
mismatchedRoot := &cobra.Command{Use: "chat"}
mismatchedRoot.AddCommand(&cobra.Command{Use: "other"})
restoreChatManifestExternalVisibleFlags(mismatchedRoot)
missingPrimary := &cobra.Command{Use: "leaf"}
installChatFlagAliases(missingPrimary, "conversation-id", []string{"group"}, requireChatConversationID)
if flag := missingPrimary.Flags().Lookup("group"); flag != nil {
t.Fatalf("alias registered without canonical flag: %#v", flag)
}
skipGroup := &cobra.Command{Use: "leaf", RunE: func(cmd *cobra.Command, args []string) error { return nil }}
skipGroup.Flags().String("conversation-id", "", "")
skipGroup.Flags().String("group-name", "", "")
installChatFlagAliases(skipGroup, "conversation-id", []string{"group", "chat"}, requireChatConversationID)
if flag := skipGroup.Flags().Lookup("group"); flag != nil {
t.Fatalf("group alias registered beside group-name: %#v", flag)
}
if flag := skipGroup.Flags().Lookup("chat"); flag == nil {
t.Fatal("non-group alias was not registered")
}
preRunCalled := false
withPreRun := &cobra.Command{
Use: "leaf",
PreRunE: func(cmd *cobra.Command, args []string) error {
preRunCalled = true
return nil
},
RunE: func(cmd *cobra.Command, args []string) error { return nil },
}
withPreRun.Flags().String("conversation-id", "", "")
installChatFlagAliases(withPreRun, "conversation-id", []string{"group"}, requireChatConversationID)
withPreRun.SetArgs([]string{"--group", "cid"})
if err := withPreRun.ExecuteContext(context.Background()); err != nil {
t.Fatalf("execute with alias and previous PreRunE: %v", err)
}
if !preRunCalled {
t.Fatal("previous PreRunE was not called")
}
}
func TestCrossPlatformCoverageChatMessageForwardRequiresMessageID(t *testing.T) {
caller := &productExampleCaller{}
InitDeps(caller)
deps.Out.w = io.Discard
deps.Out.errW = io.Discard
root := newChatCommand()
command, _, err := root.Find([]string{"message", "forward"})
if err != nil {
t.Fatal(err)
}
for _, name := range []string{"message-id", "msg-id"} {
if flag := command.Flags().Lookup(name); flag != nil && flag.Annotations != nil {
delete(flag.Annotations, cobra.BashCompOneRequiredFlag)
}
}
if err := command.Flags().Set("src-conversation-id", "src"); err != nil {
t.Fatal(err)
}
if err := command.Flags().Set("dest-conversation-id", "dest"); err != nil {
t.Fatal(err)
}
err = command.RunE(command, nil)
if err == nil || !strings.Contains(err.Error(), "missing required flag: --message-id") {
t.Fatalf("forward missing message id error = %v", err)
}
if caller.calls != 0 {
t.Fatalf("tool calls = %d, want 0", caller.calls)
}
}
func TestCrossPlatformCoverageChatGroupUpdateIconAcceptsUploadedMediaIDPrefixes(t *testing.T) {
previousDeps, previousArgs := deps, os.Args
os.Args = []string{"dws", "chat"}
@@ -439,8 +514,8 @@ func TestCrossPlatformCoverageChatIMIDMigrationRequiredFlagErrors(t *testing.T)
{name: "role set user missing conversation", path: []string{"group-role", "set-user"}, flag: map[string]string{"user": "D1", "role-ids": "r1"}, want: "conversation-id"},
{name: "role remove user missing conversation", path: []string{"group-role", "remove-user"}, flag: map[string]string{"user": "D1", "role-ids": "r1"}, want: "conversation-id"},
{name: "role query user missing conversation", path: []string{"group-role", "query-user"}, flag: map[string]string{"user": "D1"}, want: "conversation-id"},
{name: "bots conflicting conversation aliases", path: []string{"group", "bots"}, flag: map[string]string{"conversation-id": "cid1", "id": "cid2"}, want: "conflicts"},
{name: "bots conflicting group aliases", path: []string{"group", "bots"}, flag: map[string]string{"group-name": "项目群", "group": "cid"}, want: "conflicts"},
{name: "bots missing legacy group", path: []string{"group", "bots"}, want: "group"},
{name: "bots rejects migrated conversation id", path: []string{"group", "bots"}, flag: map[string]string{"conversation-id": "cid"}, want: "no such flag"},
{name: "dismiss missing conversation", path: []string{"group", "dismiss"}, flag: map[string]string{"yes": "true"}, want: "conversation-id"},
{name: "set history missing conversation", path: []string{"group", "set-history"}, flag: map[string]string{"option": "ALL"}, want: "conversation-id"},
{name: "set pin missing message", path: []string{"message", "set-pin-msg"}, flag: map[string]string{"open-conversation-id": "cid"}, want: "message-id"},
+14 -14
View File
@@ -171,7 +171,7 @@ func TestCrossPlatformCoverageChatMessageHelpDocumentsPostSendIDChain(t *testing
}
}
func TestCrossPlatformCoverageChatReactionHelpHidesConversationAliases(t *testing.T) {
func TestCrossPlatformCoverageChatReactionHelpKeepsManifestExternalAliasesVisible(t *testing.T) {
for _, command := range []string{"add-emoji", "remove-emoji", "add-text-emotion", "remove-text-emotion"} {
t.Run(command, func(t *testing.T) {
cmd := newChatCommand()
@@ -187,16 +187,16 @@ func TestCrossPlatformCoverageChatReactionHelpHidesConversationAliases(t *testin
if !strings.Contains(help, "--conversation-id") {
t.Fatalf("chat message %s help missing --conversation-id:\n%s", command, help)
}
for _, hidden := range []string{"--group", "--id", "--chat"} {
if strings.Contains(help, hidden+" string") {
t.Fatalf("chat message %s help exposes hidden alias %s:\n%s", command, hidden, help)
for _, visible := range []string{"--group", "--id", "--chat"} {
if !strings.Contains(help, visible+" string") {
t.Fatalf("chat message %s help hides manifest-external alias %s:\n%s", command, visible, help)
}
}
})
}
}
func TestCrossPlatformCoverageChatGroupBotsHelpSplitsGroupName(t *testing.T) {
func TestCrossPlatformCoverageChatGroupBotsHelpKeepsLegacyGroup(t *testing.T) {
cmd := newChatCommand()
var output bytes.Buffer
cmd.SetOut(&output)
@@ -207,13 +207,13 @@ func TestCrossPlatformCoverageChatGroupBotsHelpSplitsGroupName(t *testing.T) {
}
help := output.String()
for _, visible := range []string{"--conversation-id", "--group-name"} {
if !strings.Contains(help, visible) {
t.Fatalf("chat group bots help missing %s:\n%s", visible, help)
}
if !strings.Contains(help, "--group string") {
t.Fatalf("chat group bots help missing visible --group:\n%s", help)
}
if strings.Contains(help, "--group string") {
t.Fatalf("chat group bots help exposes hidden --group alias:\n%s", help)
for _, hidden := range []string{"--conversation-id", "--group-name"} {
if strings.Contains(help, hidden) {
t.Fatalf("chat group bots help exposes migrated flag %s:\n%s", hidden, help)
}
}
}
@@ -233,9 +233,9 @@ func TestCrossPlatformCoverageChatSendCardHelpUsesCanonicalIDFlags(t *testing.T)
t.Fatalf("send-card help missing %s:\n%s", visible, help)
}
}
for _, hidden := range []string{"--group", "--receiver"} {
if strings.Contains(help, hidden+" string") {
t.Fatalf("send-card help exposes hidden alias %s:\n%s", hidden, help)
for _, visible := range []string{"--group", "--receiver"} {
if !strings.Contains(help, visible+" string") {
t.Fatalf("send-card help hides manifest-external alias %s:\n%s", visible, help)
}
}
}
+61 -13
View File
@@ -81,6 +81,32 @@ func TestCrossPlatformCoverageChatUpdateTextEmotion(t *testing.T) {
},
},
},
{
name: "open-conversation-id alias",
args: []string{
"message", "update-text-emotion",
"--open-conversation-id", "conv-3",
"--message-id", "msg-3",
"--old-emotion-id", "old-3",
"--emotion-id", "new-3",
"--emotion-name", "smile",
"--text", "done",
"--background-id", "im_bg_2",
},
want: guardedMutationCall{
productID: "im",
toolName: "update_text_emotion",
args: map[string]any{
"openConversationId": "conv-3",
"openMsgId": "msg-3",
"oldEmotionId": "old-3",
"emotionId": "new-3",
"emotionName": "smile",
"text": "done",
"backgroundId": "im_bg_2",
},
},
},
}
for _, test := range tests {
test := test
@@ -163,19 +189,41 @@ func TestCrossPlatformCoverageChatUpdateTextEmotionRequiredFlags(t *testing.T) {
}
func TestCrossPlatformCoverageChatGroupGetMuteConfig(t *testing.T) {
caller := &guardedMutationCaller{}
err := executeGuardedMutationCommand(t, caller, newChatCommand,
"group", "get-mute-config", "--group", "conv-1")
if err != nil {
t.Fatalf("get-mute-config returned error: %v", err)
}
want := guardedMutationCall{
productID: "im",
toolName: "get_group_mute_config",
args: map[string]any{"openConversationId": "conv-1"},
}
if len(caller.calls) != 1 || !reflect.DeepEqual(caller.calls[0], want) {
t.Fatalf("tool calls = %#v, want %#v", caller.calls, want)
for _, test := range []struct {
name string
args []string
want guardedMutationCall
}{
{
name: "legacy group alias",
args: []string{"group", "get-mute-config", "--group", "conv-1"},
want: guardedMutationCall{
productID: "im",
toolName: "get_group_mute_config",
args: map[string]any{"openConversationId": "conv-1"},
},
},
{
name: "canonical conversation id",
args: []string{"group", "get-mute-config", "--conversation-id", "conv-2"},
want: guardedMutationCall{
productID: "im",
toolName: "get_group_mute_config",
args: map[string]any{"openConversationId": "conv-2"},
},
},
} {
test := test
t.Run(test.name, func(t *testing.T) {
caller := &guardedMutationCaller{}
err := executeGuardedMutationCommand(t, caller, newChatCommand, test.args...)
if err != nil {
t.Fatalf("get-mute-config returned error: %v", err)
}
if len(caller.calls) != 1 || !reflect.DeepEqual(caller.calls[0], test.want) {
t.Fatalf("tool calls = %#v, want %#v", caller.calls, test.want)
}
})
}
}
@@ -117,7 +117,7 @@ func TestCrossPlatformCoverageWukongWeeklyChatCategoryQueries(t *testing.T) {
caller := &wukongWeeklySyncCaller{}
_, _, err := executeWukongWeeklySyncCommand(t, "chat", caller, newChatCommand, "category", "list-by-conv")
if err == nil || !strings.Contains(err.Error(), "missing required flag: --conversation-id") {
t.Fatalf("missing group error = %v", err)
t.Fatalf("missing conversation ID error = %v", err)
}
requireWukongWeeklySyncNoCalls(t, caller)