feat: add bounded session and history navigation
Add session scrolling, latest-message navigation and fingerprint location under the shared UI gate; reuse navigation in history reads and provide read-only smoke. Navigation index snapshot passed 124 tests and a full build. Windows 4.1.13.63 read-only validation passed 10/10, including two-scroll history location; no sends. Record scope limits, including next-unread navigation not yet implemented.
This commit is contained in:
+66
-10
@@ -74,8 +74,13 @@ try
|
||||
var output = GetOption(args, "--output") ?? Path.Combine("artifacts", "ui-tree.json");
|
||||
var report = WechatDoctor.Run(cancellationToken);
|
||||
var snapshot = await WechatUiInspector.CaptureAsync(output, cancellationToken);
|
||||
var marker = $"wxagent-smoke-{DateTimeOffset.UtcNow:yyyyMMddHHmmss}-{Guid.NewGuid():N}";
|
||||
var confirmed = await WechatChatClient.SendTextAsync(marker, cancellationToken);
|
||||
var readOnly = HasOption(args, "--read-only");
|
||||
ChatMessageSnapshot? confirmed = null;
|
||||
if (!readOnly && report.Errors.Count == 0)
|
||||
{
|
||||
var marker = $"wxagent-smoke-{DateTimeOffset.UtcNow:yyyyMMddHHmmss}-{Guid.NewGuid():N}";
|
||||
confirmed = await WechatChatClient.SendTextAsync(marker, cancellationToken);
|
||||
}
|
||||
WriteJson(new
|
||||
{
|
||||
scope = "M1",
|
||||
@@ -83,9 +88,10 @@ try
|
||||
output = Path.GetFullPath(output),
|
||||
nodes = CountNodes(snapshot),
|
||||
sanitized = true,
|
||||
sentTo = "file-transfer-assistant",
|
||||
confirmed.Fingerprint,
|
||||
confirmed = true
|
||||
sentTo = confirmed is null ? null : "file-transfer-assistant",
|
||||
Fingerprint = confirmed?.Fingerprint,
|
||||
sendSkipped = readOnly,
|
||||
confirmed = confirmed is not null
|
||||
});
|
||||
return report.Errors.Count == 0 ? 0 : 2;
|
||||
}
|
||||
@@ -321,10 +327,32 @@ try
|
||||
var includeContent = HasOption(args, "--include-content");
|
||||
var limit = GetPositiveIntOption(args, "--limit", 100, 1000);
|
||||
var scrolls = GetPositiveIntOption(args, "--scrolls", 10, 100, allowZero: true);
|
||||
var messages = await WechatChatClient.ReadHistoryAsync(limit, scrolls, cancellationToken);
|
||||
var messages = await WechatChatClient.ReadHistoryAsync(limit, scrolls, cancellationToken,
|
||||
GetOption(args, "--session") ?? WechatLocators.FileTransferAssistant);
|
||||
WriteJson(new { messages = messages.Select(message => ToMessageOutput(message, includeContent)) });
|
||||
return 0;
|
||||
}
|
||||
case "chat" when args[1] == "latest":
|
||||
{
|
||||
var messages = await WechatChatClient.GoToLatestAsync(GetOption(args, "--session") ?? WechatLocators.FileTransferAssistant,
|
||||
GetPositiveIntOption(args, "--scrolls", 100, 100), cancellationToken);
|
||||
WriteJson(new { messages = messages.Select(message => ToMessageOutput(message, HasOption(args, "--include-content"))) });
|
||||
return 0;
|
||||
}
|
||||
case "chat" when args[1] == "merged-open":
|
||||
{
|
||||
var windowHandle = await WechatChatClient.OpenMergedChatAsync(GetOption(args, "--session") ?? WechatLocators.FileTransferAssistant,
|
||||
GetRequiredOption(args, "--fingerprint"), cancellationToken);
|
||||
WriteJson(new { windowHandle });
|
||||
return 0;
|
||||
}
|
||||
case "chat" when args[1] == "locate":
|
||||
{
|
||||
var result = await WechatChatClient.LocateMessageAsync(GetOption(args, "--session") ?? WechatLocators.FileTransferAssistant,
|
||||
GetRequiredOption(args, "--fingerprint"), GetPositiveIntOption(args, "--scrolls", 30, 100), cancellationToken);
|
||||
WriteJson(new { result.Scrolls, message = ToMessageOutput(result.Message, HasOption(args, "--include-content")) });
|
||||
return 0;
|
||||
}
|
||||
case "chat" when args[1] == "monitor":
|
||||
{
|
||||
var includeContent = HasOption(args, "--include-content");
|
||||
@@ -359,6 +387,18 @@ try
|
||||
WriteJson(new { sessions = await WechatChatClient.ListVisibleSessionsAsync(cancellationToken) });
|
||||
return 0;
|
||||
}
|
||||
case "session" when args[1] == "scroll":
|
||||
{
|
||||
var direction = GetRequiredOption(args, "--direction") switch
|
||||
{
|
||||
"up" => WechatScrollDirection.Up,
|
||||
"down" => WechatScrollDirection.Down,
|
||||
_ => throw new WxAgentException(WxAgentErrorCode.InvalidArgument, "Direction must be up or down.")
|
||||
};
|
||||
var result = await WechatChatClient.ScrollSessionsAsync(direction, GetPositiveIntOption(args, "--pages", 1, 100), cancellationToken);
|
||||
WriteJson(new { result.Scrolls, result.ViewportChanged, sessions = result.Sessions.Select(session => new { name = HasOption(args, "--include-content") ? session.Name : null, nameId = MaskIdentifier(session.Name), session.IsCurrent }) });
|
||||
return 0;
|
||||
}
|
||||
case "session" when args[1] == "search":
|
||||
{
|
||||
var query = GetRequiredOption(args, "--query");
|
||||
@@ -620,7 +660,7 @@ static int ValidateCommandLine(string[] values)
|
||||
|
||||
if (values[0] == "smoke")
|
||||
{
|
||||
ValidateOptions(values, 1, ["--output", "--timeout"], []);
|
||||
ValidateOptions(values, 1, ["--output", "--timeout"], ["--read-only"]);
|
||||
return 30;
|
||||
}
|
||||
|
||||
@@ -693,7 +733,16 @@ static int ValidateCommandLine(string[] values)
|
||||
ValidateOptions(values, 2, ["--limit", "--timeout"], ["--include-content"]);
|
||||
return 30;
|
||||
case "history":
|
||||
ValidateOptions(values, 2, ["--limit", "--scrolls", "--timeout"], ["--include-content"]);
|
||||
ValidateOptions(values, 2, ["--session", "--limit", "--scrolls", "--timeout"], ["--include-content"]);
|
||||
return 60;
|
||||
case "latest":
|
||||
ValidateOptions(values, 2, ["--session", "--scrolls", "--timeout"], ["--include-content"]);
|
||||
return 60;
|
||||
case "merged-open":
|
||||
ValidateOptions(values, 2, ["--session", "--fingerprint", "--timeout"], []);
|
||||
return 60;
|
||||
case "locate":
|
||||
ValidateOptions(values, 2, ["--session", "--fingerprint", "--scrolls", "--timeout"], ["--include-content"]);
|
||||
return 60;
|
||||
case "monitor":
|
||||
ValidateOptions(values, 2, ["--seconds", "--state-file", "--session", "--timeout"], ["--include-content", "--independent"]);
|
||||
@@ -714,6 +763,9 @@ static int ValidateCommandLine(string[] values)
|
||||
case "current":
|
||||
ValidateOptions(values, 2, ["--timeout"], []);
|
||||
return 30;
|
||||
case "scroll":
|
||||
ValidateOptions(values, 2, ["--direction", "--pages", "--timeout"], ["--include-content"]);
|
||||
return 60;
|
||||
case "search":
|
||||
ValidateOptions(values, 2, ["--query", "--ui-output", "--timeout"], ["--exact"]);
|
||||
return 30;
|
||||
@@ -863,7 +915,7 @@ WxAgent.Host commands:
|
||||
doctor [--timeout 30]
|
||||
diagnose --output <dir> [--baseline <ui-tree.json>] [--timeout 60]
|
||||
inspect-ui --output <path> [--window-title <title>] [--timeout 30]
|
||||
smoke [--output <path>] [--timeout 30]
|
||||
smoke [--output <path>] [--read-only] [--timeout 30]
|
||||
m4-smoke [--timeout 60]
|
||||
m5-smoke [--timeout 60]
|
||||
tray-status [--timeout 30]
|
||||
@@ -883,10 +935,14 @@ WxAgent.Host commands:
|
||||
chat send-image --path <image> [--session <name>] [--timeout 60]
|
||||
chat mention --session <name> --member <display-name> --text <text> --confirm CONFIRM [--timeout 60]
|
||||
chat read [--limit 20] [--include-content] [--timeout 30]
|
||||
chat history [--limit 100] [--scrolls 10] [--include-content] [--timeout 60]
|
||||
chat history [--session <name>] [--limit 100] [--scrolls 10] [--include-content] [--timeout 60]
|
||||
chat latest [--session <name>] [--scrolls 100] [--include-content] [--timeout 60]
|
||||
chat merged-open --fingerprint <visible-message-fingerprint> [--session <name>] [--timeout 60]
|
||||
chat locate --fingerprint <visible-message-fingerprint> [--session <name>] [--scrolls 30] [--include-content] [--timeout 60]
|
||||
chat monitor [--seconds 60] [--session <name>] [--independent] [--state-file <path>] [--include-content] [--timeout <seconds>]
|
||||
chat listen [--seconds 30] [--include-content] [--timeout <seconds>]
|
||||
session list [--timeout 30]
|
||||
session scroll --direction <up|down> [--pages 1] [--include-content] [--timeout 60]
|
||||
session search --query <text> [--exact] [--ui-output <path>] [--timeout 30]
|
||||
session current [--timeout 30]
|
||||
session open --name <session-name> [--query <keyword>] [--timeout 30]
|
||||
|
||||
Reference in New Issue
Block a user