feat: complete M4 contact and group automation

This commit is contained in:
2026-09-04 23:01:02 +08:00
parent 5e3aa97644
commit 77e1e9dc2b
6 changed files with 1016 additions and 1 deletions
+81
View File
@@ -62,6 +62,65 @@ try
});
return report.Errors.Count == 0 ? 0 : 2;
}
case "m4-smoke":
{
var windows = await WechatChatClient.GetSubWindowsAsync(cancellationToken);
var history = await WechatChatClient.GetHistoryMessageAsync("文件传输助手", 3, cancellationToken: cancellationToken);
await WechatChatClient.OpenSessionInSubWindowAsync("文件传输助手", cancellationToken);
await Task.Delay(500, cancellationToken);
var windowsAfterDoubleClick = await WechatChatClient.GetSubWindowsAsync(cancellationToken);
await WechatChatClient.CloseSubWindowAsync("文件传输助手", cancellationToken);
var contacts = await WechatChatClient.GetFriendsAsync(5000, cancellationToken);
var newFriends = await WechatChatClient.GetNewFriendsAsync(true, cancellationToken);
var groups = await WechatChatClient.GetRecentGroupsAsync(cancellationToken);
var myInfo = await WechatChatClient.GetMyInfoAsync(cancellationToken);
await WechatChatClient.SwitchToChatsAsync(cancellationToken);
var confirmationGuarded = false;
try
{
WechatOperationPolicy.RequireConfirmation(null, "m4 smoke destructive operation");
}
catch (WxAgentException exception) when (exception.Code == WxAgentErrorCode.InvalidArgument)
{
confirmationGuarded = true;
}
WriteJson(new
{
scope = "M4",
subWindows = windowsAfterDoubleClick.Select(window => new { window.Kind, window.ProcessId }),
subWindowOpened = windowsAfterDoubleClick.Count > windows.Count,
historyCount = history.Count,
contactCount = contacts.Count,
newFriendCount = newFriends.Count,
recentGroupCount = groups.Count,
accountDetected = !string.IsNullOrWhiteSpace(myInfo.DisplayName),
confirmationGuarded,
privacy = "names and account identifiers omitted"
});
return confirmationGuarded
&& !string.IsNullOrWhiteSpace(myInfo.DisplayName)
&& history.Count > 0
&& windowsAfterDoubleClick.Count > windows.Count ? 0 : 2;
}
case "group" when args[1] == "at-all":
{
var group = GetRequiredOption(args, "--group");
var message = GetRequiredOption(args, "--message");
var confirmation = GetRequiredOption(args, "--confirm");
var result = await WechatChatClient.AtAllAsync(group, message, confirmation, cancellationToken);
WriteJson(result);
return result.Success ? 0 : 2;
}
case "group" when args[1] == "verify-at-all":
{
var group = GetRequiredOption(args, "--group");
var message = GetRequiredOption(args, "--message");
var history = await WechatChatClient.GetHistoryMessageAsync(group, 10, cancellationToken: cancellationToken);
var found = history.Any(item => item.Text.Contains("@所有人", StringComparison.Ordinal)
&& item.Text.Contains(message, StringComparison.Ordinal));
WriteJson(new { found, checkedMessages = history.Count, privacy = "message text omitted" });
return found ? 0 : 2;
}
case "chat" when args[1] == "send":
{
var message = await WechatChatClient.SendTextAsync(GetRequiredOption(args, "--text"), cancellationToken);
@@ -274,6 +333,24 @@ static int ValidateCommandLine(string[] values)
return 30;
}
if (values[0] == "m4-smoke")
{
ValidateOptions(values, 1, ["--timeout"], []);
return 60;
}
if (values[0] == "group" && values.Length >= 2 && values[1] == "at-all")
{
ValidateOptions(values, 2, ["--group", "--message", "--confirm", "--timeout"], []);
return 30;
}
if (values[0] == "group" && values.Length >= 2 && values[1] == "verify-at-all")
{
ValidateOptions(values, 2, ["--group", "--message", "--timeout"], []);
return 30;
}
if (values[0] == "chat" && values.Length >= 2)
{
switch (values[1])
@@ -448,6 +525,9 @@ WxAgent.Host commands:
doctor [--timeout 30]
inspect-ui --output <path> [--timeout 30]
smoke [--output <path>] [--timeout 30]
m4-smoke [--timeout 60]
group at-all --group <name> --message <text> --confirm CONFIRM [--timeout 30]
group verify-at-all --group <name> --message <text> [--timeout 30]
chat send --text <one-line-text> [--timeout 30]
chat reply-latest --text <one-line-text> [--timeout 60]
chat send-file --path <file> [--timeout 60]
@@ -465,5 +545,6 @@ WxAgent.Host commands:
db query --account <fingerprint> --database <relative-path> [--key-file <path>] [--timeout 30]
Chat commands are restricted to File Transfer Assistant. Message content is omitted unless --include-content is explicit.
M4 modifying operations are library APIs and require the exact confirmation token CONFIRM.
Database keys are never printed. db scan only saves verified keys when --save is present.
""");