From c86ba9c4d74f6b5f894e453a0df1b300f36bd5a9 Mon Sep 17 00:00:00 2001 From: Rogee Date: Fri, 11 Sep 2026 16:57:31 +0800 Subject: [PATCH] refactor: split node agent and Go control plane --- AGENTS.md | 20 +- README.md | 12 +- WxAgent.sln | 44 +- control-plane/go.mod | 3 + docs/WebUI-MCP-开发计划.md | 18 +- docs/WebUI-面向普通用户重构落地指导.md | 8 +- docs/WxAgent-CSharp-开发计划.md | 24 +- ...-远程多节点控制与白名单数据上报开发计划.md | 554 ++++++++++++++++++ docs/validation/General-Sending-2026-09-06.md | 2 +- docs/validation/M1-2026-09-04.md | 4 +- docs/validation/M1A-2026-09-04.md | 2 +- .../M2-Search-Quote-History-2026-09-04.md | 4 +- docs/validation/M3-Listening-2026-09-04.md | 4 +- .../M4-Management-History-2026-09-04.md | 4 +- .../M5-Moments-Rich-Messages-2026-09-04.md | 4 +- .../Review-Database-Management-Safety.md | 4 +- docs/validation/WebUI-MCP-2026-09-07.md | 4 +- .../WxAgent.Core/AccountBindingMatcher.cs | 0 .../WxAgent.Core/ChatMessages.cs | 0 .../WxAgent.Core/DatabaseModels.cs | 0 .../WxAgent.Core/InterprocessCommandGate.cs | 0 .../WxAgent.Core/KeyCachePlanner.cs | 0 .../WxAgent.Core/MemoryPatternScanner.cs | 0 .../WxAgent.Core/MessageEvents.cs | 0 .../WxAgent.Core/SqlCipherPageVerifier.cs | 0 .../WxAgent.Core/UiNodeSnapshot.cs | 0 .../WxAgent.Core/UiSnapshotDiagnostics.cs | 0 .../WxAgent.Core/WcdbConfigCipher.cs | 0 .../WxAgent.Core/WcdbKeyCandidateScanner.cs | 0 .../WxAgent.Core/WechatContactQuery.cs | 0 .../WxAgent.Core/WechatDbMessage.cs | 0 .../WxAgent.Core/WechatDerivedText.cs | 0 .../WxAgent.Core/WechatGroupMemberQuery.cs | 0 .../WxAgent.Core/WechatLocators.cs | 0 {src => node-agent}/WxAgent.Core/WechatM5.cs | 0 .../WxAgent.Core/WechatManagement.cs | 0 .../WxAgent.Core/WechatMergedChat.cs | 0 .../WxAgent.Core/WechatNavigation.cs | 0 .../WxAgent.Core/WechatNoteWindow.cs | 0 .../WxAgent.Core/WechatSearchPage.cs | 0 .../WxAgent.Core/WechatSendConfirmation.cs | 0 .../WxAgent.Core/WechatSessions.cs | 0 .../WxAgent.Core/WechatStability.cs | 0 .../WxAgent.Core/WechatTextInput.cs | 0 .../WxAgent.Core/WxAgent.Core.csproj | 0 .../WxAgent.Core/WxAgentErrorCode.cs | 0 {src => node-agent}/WxAgent.Host/Program.cs | 0 .../WxAgent.Host/WindowsAgentBackend.cs | 0 .../WxAgent.Host/WxAgent.Host.csproj | 0 .../WxAgent.Service/AccountBindingStore.cs | 0 .../WxAgent.Service/AgentService.cs | 0 .../WxAgent.Service/AgentTools.cs | 0 .../WxAgent.Service/ArtifactStore.cs | 0 .../DatabaseMessageContracts.cs | 0 .../WxAgent.Service/DirectoryContracts.cs | 0 .../WxAgent.Service/EventHub.cs | 0 .../WxAgent.Service/EventPump.cs | 0 .../WxAgent.Service/OperationQueue.cs | 0 .../WxAgent.Service/OperationStore.cs | 0 .../WxAgent.Service/ReadOnlyContracts.cs | 0 .../WxAgent.Service/RuntimeLog.cs | 0 .../WxAgent.Service/ServiceHost.cs | 0 .../WxAgent.Service/ServiceOptions.cs | 0 .../WxAgent.Service/ServiceSecurity.cs | 0 .../WxAgent.Service/SessionContracts.cs | 0 .../WxAgent.Service/WxAgent.Service.csproj | 0 .../WxAgent.Service/wwwroot/app.js | 0 .../WxAgent.Service/wwwroot/index.html | 0 .../WxAgent.Service/wwwroot/styles.css | 0 {src => node-agent}/WxAgent.Tray/Program.cs | 0 .../WxAgent.Tray/WxAgent.Tray.csproj | 0 {src => node-agent}/WxAgent.Tray/wxagent.ico | Bin .../WxAgent.Windows/DatabaseKeyStore.cs | 0 .../ListenerCheckpointStore.cs | 0 .../WxAgent.Windows/NativeMethods.txt | 0 .../WxAgent.Windows/ProcessMemoryScanner.cs | 0 .../SqlCipherDatabaseReader.cs | 0 .../WechatChatClient.Listening.cs | 0 .../WxAgent.Windows/WechatChatClient.M5.cs | 0 .../WechatChatClient.Management.cs | 0 .../WechatChatClient.Navigation.cs | 0 .../WechatChatClient.Search.cs | 0 .../WxAgent.Windows/WechatChatClient.cs | 0 .../WxAgent.Windows/WechatContactDbReader.cs | 0 .../WechatDatabaseDiscovery.cs | 0 .../WxAgent.Windows/WechatDatabaseScanner.cs | 0 .../WxAgent.Windows/WechatDesktop.cs | 0 .../WxAgent.Windows/WechatDoctor.cs | 0 .../WxAgent.Windows/WechatListenerSmoke.cs | 0 .../WxAgent.Windows/WechatMessageDbReader.cs | 0 .../WxAgent.Windows/WechatNativeWindow.cs | 0 .../WxAgent.Windows/WechatRecoverySmoke.cs | 0 .../WxAgent.Windows/WechatStabilityRunner.cs | 0 .../WxAgent.Windows/WechatTray.cs | 0 .../WxAgent.Windows/WechatUiInspector.cs | 0 .../WxAgent.Windows/WxAgent.Windows.csproj | 0 .../AccountBindingMatcherTests.cs | 0 .../WxAgent.Core.Tests/CoreTests.cs | 0 .../InterprocessCommandGateTests.cs | 0 .../KeyCachePlannerTests.cs | 0 .../WxAgent.Core.Tests/MemoryScanningTests.cs | 0 .../WxAgent.Core.Tests/UiDiagnosticsTests.cs | 0 .../WechatContactQueryTests.cs | 0 .../WechatDbMessageTests.cs | 0 .../WechatDerivedTextTests.cs | 0 .../WechatGroupMemberQueryTests.cs | 0 .../WxAgent.Core.Tests/WechatM5Tests.cs | 0 .../WechatManagementTests.cs | 0 .../WechatMentionConfirmationTests.cs | 0 .../WechatMergedChatTests.cs | 0 .../WechatNavigationTests.cs | 0 .../WechatNoteWindowTests.cs | 0 .../WechatSearchRulesTests.cs | 0 .../WechatSendConfirmationTests.cs | 0 .../WechatStabilityTests.cs | 0 .../WechatTextInputTests.cs | 0 .../WxAgent.Core.Tests.csproj | 2 +- .../AccountBindingStoreTests.cs | 0 .../ArtifactStoreTests.cs | 0 .../WxAgent.Service.Tests/EventHubTests.cs | 0 .../WxAgent.Service.Tests/EventPumpTests.cs | 0 .../OperationQueueTests.cs | 0 .../OperationStoreTests.cs | 0 .../ServiceBoundaryTests.cs | 0 .../WxAgent.Service.Tests/ServiceTests.cs | 0 .../WxAgent.Service.Tests/SessionTests.cs | 0 .../WxAgent.Service.Tests/SseTests.cs | 0 .../WxAgent.Service.Tests.csproj | 2 +- tests/{ => node-agent}/check_contact_query.py | 12 +- 129 files changed, 654 insertions(+), 77 deletions(-) create mode 100644 control-plane/go.mod create mode 100644 docs/WxAgent-远程多节点控制与白名单数据上报开发计划.md rename {src => node-agent}/WxAgent.Core/AccountBindingMatcher.cs (100%) rename {src => node-agent}/WxAgent.Core/ChatMessages.cs (100%) rename {src => node-agent}/WxAgent.Core/DatabaseModels.cs (100%) rename {src => node-agent}/WxAgent.Core/InterprocessCommandGate.cs (100%) rename {src => node-agent}/WxAgent.Core/KeyCachePlanner.cs (100%) rename {src => node-agent}/WxAgent.Core/MemoryPatternScanner.cs (100%) rename {src => node-agent}/WxAgent.Core/MessageEvents.cs (100%) rename {src => node-agent}/WxAgent.Core/SqlCipherPageVerifier.cs (100%) rename {src => node-agent}/WxAgent.Core/UiNodeSnapshot.cs (100%) rename {src => node-agent}/WxAgent.Core/UiSnapshotDiagnostics.cs (100%) rename {src => node-agent}/WxAgent.Core/WcdbConfigCipher.cs (100%) rename {src => node-agent}/WxAgent.Core/WcdbKeyCandidateScanner.cs (100%) rename {src => node-agent}/WxAgent.Core/WechatContactQuery.cs (100%) rename {src => node-agent}/WxAgent.Core/WechatDbMessage.cs (100%) rename {src => node-agent}/WxAgent.Core/WechatDerivedText.cs (100%) rename {src => node-agent}/WxAgent.Core/WechatGroupMemberQuery.cs (100%) rename {src => node-agent}/WxAgent.Core/WechatLocators.cs (100%) rename {src => node-agent}/WxAgent.Core/WechatM5.cs (100%) rename {src => node-agent}/WxAgent.Core/WechatManagement.cs (100%) rename {src => node-agent}/WxAgent.Core/WechatMergedChat.cs (100%) rename {src => node-agent}/WxAgent.Core/WechatNavigation.cs (100%) rename {src => node-agent}/WxAgent.Core/WechatNoteWindow.cs (100%) rename {src => node-agent}/WxAgent.Core/WechatSearchPage.cs (100%) rename {src => node-agent}/WxAgent.Core/WechatSendConfirmation.cs (100%) rename {src => node-agent}/WxAgent.Core/WechatSessions.cs (100%) rename {src => node-agent}/WxAgent.Core/WechatStability.cs (100%) rename {src => node-agent}/WxAgent.Core/WechatTextInput.cs (100%) rename {src => node-agent}/WxAgent.Core/WxAgent.Core.csproj (100%) rename {src => node-agent}/WxAgent.Core/WxAgentErrorCode.cs (100%) rename {src => node-agent}/WxAgent.Host/Program.cs (100%) rename {src => node-agent}/WxAgent.Host/WindowsAgentBackend.cs (100%) rename {src => node-agent}/WxAgent.Host/WxAgent.Host.csproj (100%) rename {src => node-agent}/WxAgent.Service/AccountBindingStore.cs (100%) rename {src => node-agent}/WxAgent.Service/AgentService.cs (100%) rename {src => node-agent}/WxAgent.Service/AgentTools.cs (100%) rename {src => node-agent}/WxAgent.Service/ArtifactStore.cs (100%) rename {src => node-agent}/WxAgent.Service/DatabaseMessageContracts.cs (100%) rename {src => node-agent}/WxAgent.Service/DirectoryContracts.cs (100%) rename {src => node-agent}/WxAgent.Service/EventHub.cs (100%) rename {src => node-agent}/WxAgent.Service/EventPump.cs (100%) rename {src => node-agent}/WxAgent.Service/OperationQueue.cs (100%) rename {src => node-agent}/WxAgent.Service/OperationStore.cs (100%) rename {src => node-agent}/WxAgent.Service/ReadOnlyContracts.cs (100%) rename {src => node-agent}/WxAgent.Service/RuntimeLog.cs (100%) rename {src => node-agent}/WxAgent.Service/ServiceHost.cs (100%) rename {src => node-agent}/WxAgent.Service/ServiceOptions.cs (100%) rename {src => node-agent}/WxAgent.Service/ServiceSecurity.cs (100%) rename {src => node-agent}/WxAgent.Service/SessionContracts.cs (100%) rename {src => node-agent}/WxAgent.Service/WxAgent.Service.csproj (100%) rename {src => node-agent}/WxAgent.Service/wwwroot/app.js (100%) rename {src => node-agent}/WxAgent.Service/wwwroot/index.html (100%) rename {src => node-agent}/WxAgent.Service/wwwroot/styles.css (100%) rename {src => node-agent}/WxAgent.Tray/Program.cs (100%) rename {src => node-agent}/WxAgent.Tray/WxAgent.Tray.csproj (100%) rename {src => node-agent}/WxAgent.Tray/wxagent.ico (100%) rename {src => node-agent}/WxAgent.Windows/DatabaseKeyStore.cs (100%) rename {src => node-agent}/WxAgent.Windows/ListenerCheckpointStore.cs (100%) rename {src => node-agent}/WxAgent.Windows/NativeMethods.txt (100%) rename {src => node-agent}/WxAgent.Windows/ProcessMemoryScanner.cs (100%) rename {src => node-agent}/WxAgent.Windows/SqlCipherDatabaseReader.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatChatClient.Listening.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatChatClient.M5.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatChatClient.Management.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatChatClient.Navigation.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatChatClient.Search.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatChatClient.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatContactDbReader.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatDatabaseDiscovery.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatDatabaseScanner.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatDesktop.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatDoctor.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatListenerSmoke.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatMessageDbReader.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatNativeWindow.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatRecoverySmoke.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatStabilityRunner.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatTray.cs (100%) rename {src => node-agent}/WxAgent.Windows/WechatUiInspector.cs (100%) rename {src => node-agent}/WxAgent.Windows/WxAgent.Windows.csproj (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/AccountBindingMatcherTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/CoreTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/InterprocessCommandGateTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/KeyCachePlannerTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/MemoryScanningTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/UiDiagnosticsTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/WechatContactQueryTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/WechatDbMessageTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/WechatDerivedTextTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/WechatGroupMemberQueryTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/WechatM5Tests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/WechatManagementTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/WechatMentionConfirmationTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/WechatMergedChatTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/WechatNavigationTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/WechatNoteWindowTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/WechatSearchRulesTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/WechatSendConfirmationTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/WechatStabilityTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/WechatTextInputTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Core.Tests/WxAgent.Core.Tests.csproj (88%) rename tests/{ => node-agent}/WxAgent.Service.Tests/AccountBindingStoreTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Service.Tests/ArtifactStoreTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Service.Tests/EventHubTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Service.Tests/EventPumpTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Service.Tests/OperationQueueTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Service.Tests/OperationStoreTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Service.Tests/ServiceBoundaryTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Service.Tests/ServiceTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Service.Tests/SessionTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Service.Tests/SseTests.cs (100%) rename tests/{ => node-agent}/WxAgent.Service.Tests/WxAgent.Service.Tests.csproj (86%) rename tests/{ => node-agent}/check_contact_query.py (83%) diff --git a/AGENTS.md b/AGENTS.md index b47cff6..0e2060d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -19,11 +19,15 @@ ## 项目边界 ```text -src/WxAgent.Core net8.0:模型、解析、去重、状态机和业务用例 -src/WxAgent.Windows net8.0-windows:FlaUI、UIA 和 Win32 -src/WxAgent.Host net8.0-windows:Desktop Agent 和 CLI -tests/WxAgent.Core.Tests Linux 可执行的纯逻辑测试 -tests/WxAgent.Windows.Tests Windows 真机测试,需要时再创建 +node-agent/WxAgent.Core net8.0:模型、解析、去重、状态机和业务用例 +node-agent/WxAgent.Windows net8.0-windows:FlaUI、UIA 和 Win32 +node-agent/WxAgent.Host net8.0-windows:Desktop Agent 和 CLI +node-agent/WxAgent.Tray net8.0-windows:托盘常驻与生命周期管理 +node-agent/WxAgent.Service net8.0:节点本地服务兼容层 +control-plane/ Go:远程中心控制面;测试与 Go 代码同目录 + +tests/node-agent/WxAgent.Core.Tests Linux 可执行的纯逻辑测试 +tests/node-agent/WxAgent.Service.Tests 节点本地服务测试 ``` - 保持 Windows 专用代码与纯业务逻辑分离,使 Core 测试可在 Linux 执行。 @@ -38,9 +42,9 @@ tests/WxAgent.Windows.Tests Windows 真机测试,需要时再创建 ```bash dotnet restore WxAgent.sln -p:EnableWindowsTargeting=true -dotnet test tests/WxAgent.Core.Tests -c Release +dotnet test tests/node-agent/WxAgent.Core.Tests -c Release dotnet build WxAgent.sln -c Release -p:EnableWindowsTargeting=true -dotnet publish src/WxAgent.Host -c Release -r win-x64 --self-contained true \ +dotnet publish node-agent/WxAgent.Host -c Release -r win-x64 --self-contained true \ -p:EnableWindowsTargeting=true -p:PublishSingleFile=true -p:PublishTrimmed=false ``` @@ -71,7 +75,7 @@ dotnet publish src/WxAgent.Host -c Release -r win-x64 --self-contained true \ ```bash ssh rogee@10.1.1.101 'powershell -NoProfile -Command "New-Item -ItemType Directory -Force C:\Users\Rogee\wx-agent | Out-Null"' -scp -r src/WxAgent.Host/bin/Release/net8.0-windows10.0.19041.0/win-x64/publish/* \ +scp -r node-agent/WxAgent.Host/bin/Release/net8.0-windows10.0.19041.0/win-x64/publish/* \ rogee@10.1.1.101:'C:/Users/Rogee/wx-agent/' ``` diff --git a/README.md b/README.md index f7dab91..9d6372b 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,12 @@ WxAgent 使用 C#/.NET 8 独立实现微信 Windows 桌面端自动化能力。当前已完成 **M1 技术验证**、M2 会话/消息扩展切片、M3 监听和完整消息模型,并包含只读数据库 MVP。 +## 项目结构 + +- `node-agent/`:Windows 节点端,C#/.NET 8;包含 UIA、Win32、Desktop Agent、CLI、托盘和节点本地服务兼容层。 +- `control-plane/`:远程中心控制面,Go;Go 测试与实现代码同目录。 +- `tests/node-agent/`:节点端 .NET 测试及只读 SQL 离线检查。 + ## 当前能力 - `doctor`:检测 Windows 会话、`Weixin.exe` 进程/版本/只读访问权限、微信窗口、关键 UIA 控件和数据库根目录。 @@ -28,9 +34,9 @@ WxAgent 使用 C#/.NET 8 独立实现微信 Windows 桌面端自动化能力。 ```bash export PATH="$HOME/.dotnet:$PATH" dotnet restore WxAgent.sln -p:EnableWindowsTargeting=true -dotnet test tests/WxAgent.Core.Tests -c Release +dotnet test tests/node-agent/WxAgent.Core.Tests -c Release dotnet build WxAgent.sln -c Release -p:EnableWindowsTargeting=true -dotnet publish src/WxAgent.Host -c Release -r win-x64 --self-contained true \ +dotnet publish node-agent/WxAgent.Host -c Release -r win-x64 --self-contained true \ -p:EnableWindowsTargeting=true -p:PublishSingleFile=true \ -p:IncludeNativeLibrariesForSelfExtract=true -p:PublishTrimmed=false ``` @@ -73,7 +79,7 @@ WxAgent.Host db contacts --account --contains "搜索 目标主机:`10.1.1.101`,用户 `rogee`,微信 `C:\Program Files\Tencent\Weixin\Weixin.exe`。UIA 命令必须在微信所在的已登录、未锁定交互会话中运行;SSH Session 0 只能用于部署和非 UI 数据库命令。 ```bash -scp -r src/WxAgent.Host/bin/Release/net8.0-windows10.0.19041.0/win-x64/publish/* \ +scp -r node-agent/WxAgent.Host/bin/Release/net8.0-windows10.0.19041.0/win-x64/publish/* \ rogee@10.1.1.101:'C:/Users/Rogee/wx-agent/' ``` diff --git a/WxAgent.sln b/WxAgent.sln index 3571dbf..a9f16f8 100644 --- a/WxAgent.sln +++ b/WxAgent.sln @@ -1,25 +1,26 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{11E9B433-75E3-446D-B8FF-958A0F541BA5}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "node-agent", "node-agent", "{11E9B433-75E3-446D-B8FF-958A0F541BA5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WxAgent.Core", "src\WxAgent.Core\WxAgent.Core.csproj", "{EDC68F82-2F67-40A5-B6CA-B4D26349E988}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WxAgent.Core", "node-agent\WxAgent.Core\WxAgent.Core.csproj", "{EDC68F82-2F67-40A5-B6CA-B4D26349E988}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WxAgent.Windows", "src\WxAgent.Windows\WxAgent.Windows.csproj", "{2552B68F-0F33-4B71-AE13-CF53ACD15D4D}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WxAgent.Windows", "node-agent\WxAgent.Windows\WxAgent.Windows.csproj", "{2552B68F-0F33-4B71-AE13-CF53ACD15D4D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WxAgent.Host", "src\WxAgent.Host\WxAgent.Host.csproj", "{70B4D2DF-1FDC-4C80-85A0-F03B1A979915}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WxAgent.Host", "node-agent\WxAgent.Host\WxAgent.Host.csproj", "{70B4D2DF-1FDC-4C80-85A0-F03B1A979915}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WxAgent.Service", "node-agent\WxAgent.Service\WxAgent.Service.csproj", "{8280C39E-328E-4321-8D96-238405B5F19D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WxAgent.Tray", "node-agent\WxAgent.Tray\WxAgent.Tray.csproj", "{FCDBB182-E1EB-44C4-8DB8-20BF2913E929}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{CE7C3E9D-F9B0-4A30-AA6F-A645D75888D9}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WxAgent.Core.Tests", "tests\WxAgent.Core.Tests\WxAgent.Core.Tests.csproj", "{1F24FB68-6917-4984-89FC-5F9C64E2965D}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "node-agent", "tests\node-agent", "{64E9FE15-8AE0-44A8-8240-4B8BC3E8823A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WxAgent.Service", "src\WxAgent.Service\WxAgent.Service.csproj", "{8280C39E-328E-4321-8D96-238405B5F19D}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WxAgent.Core.Tests", "tests\node-agent\WxAgent.Core.Tests\WxAgent.Core.Tests.csproj", "{1F24FB68-6917-4984-89FC-5F9C64E2965D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WxAgent.Service.Tests", "tests\WxAgent.Service.Tests\WxAgent.Service.Tests.csproj", "{99273C3C-2BCE-431A-AEFA-EFBDEE5ECAFB}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WxAgent.Tray", "src\WxAgent.Tray\WxAgent.Tray.csproj", "{FCDBB182-E1EB-44C4-8DB8-20BF2913E929}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WxAgent.Service.Tests", "tests\node-agent\WxAgent.Service.Tests\WxAgent.Service.Tests.csproj", "{99273C3C-2BCE-431A-AEFA-EFBDEE5ECAFB}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -42,30 +43,31 @@ Global {70B4D2DF-1FDC-4C80-85A0-F03B1A979915}.Debug|Any CPU.Build.0 = Debug|Any CPU {70B4D2DF-1FDC-4C80-85A0-F03B1A979915}.Release|Any CPU.ActiveCfg = Release|Any CPU {70B4D2DF-1FDC-4C80-85A0-F03B1A979915}.Release|Any CPU.Build.0 = Release|Any CPU - {1F24FB68-6917-4984-89FC-5F9C64E2965D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1F24FB68-6917-4984-89FC-5F9C64E2965D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1F24FB68-6917-4984-89FC-5F9C64E2965D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1F24FB68-6917-4984-89FC-5F9C64E2965D}.Release|Any CPU.Build.0 = Release|Any CPU {8280C39E-328E-4321-8D96-238405B5F19D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8280C39E-328E-4321-8D96-238405B5F19D}.Debug|Any CPU.Build.0 = Debug|Any CPU {8280C39E-328E-4321-8D96-238405B5F19D}.Release|Any CPU.ActiveCfg = Release|Any CPU {8280C39E-328E-4321-8D96-238405B5F19D}.Release|Any CPU.Build.0 = Release|Any CPU - {99273C3C-2BCE-431A-AEFA-EFBDEE5ECAFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {99273C3C-2BCE-431A-AEFA-EFBDEE5ECAFB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {99273C3C-2BCE-431A-AEFA-EFBDEE5ECAFB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {99273C3C-2BCE-431A-AEFA-EFBDEE5ECAFB}.Release|Any CPU.Build.0 = Release|Any CPU {FCDBB182-E1EB-44C4-8DB8-20BF2913E929}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FCDBB182-E1EB-44C4-8DB8-20BF2913E929}.Debug|Any CPU.Build.0 = Debug|Any CPU {FCDBB182-E1EB-44C4-8DB8-20BF2913E929}.Release|Any CPU.ActiveCfg = Release|Any CPU {FCDBB182-E1EB-44C4-8DB8-20BF2913E929}.Release|Any CPU.Build.0 = Release|Any CPU + {1F24FB68-6917-4984-89FC-5F9C64E2965D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1F24FB68-6917-4984-89FC-5F9C64E2965D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1F24FB68-6917-4984-89FC-5F9C64E2965D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F24FB68-6917-4984-89FC-5F9C64E2965D}.Release|Any CPU.Build.0 = Release|Any CPU + {99273C3C-2BCE-431A-AEFA-EFBDEE5ECAFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {99273C3C-2BCE-431A-AEFA-EFBDEE5ECAFB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {99273C3C-2BCE-431A-AEFA-EFBDEE5ECAFB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {99273C3C-2BCE-431A-AEFA-EFBDEE5ECAFB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {EDC68F82-2F67-40A5-B6CA-B4D26349E988} = {11E9B433-75E3-446D-B8FF-958A0F541BA5} {2552B68F-0F33-4B71-AE13-CF53ACD15D4D} = {11E9B433-75E3-446D-B8FF-958A0F541BA5} {70B4D2DF-1FDC-4C80-85A0-F03B1A979915} = {11E9B433-75E3-446D-B8FF-958A0F541BA5} - {1F24FB68-6917-4984-89FC-5F9C64E2965D} = {CE7C3E9D-F9B0-4A30-AA6F-A645D75888D9} {8280C39E-328E-4321-8D96-238405B5F19D} = {11E9B433-75E3-446D-B8FF-958A0F541BA5} - {99273C3C-2BCE-431A-AEFA-EFBDEE5ECAFB} = {CE7C3E9D-F9B0-4A30-AA6F-A645D75888D9} {FCDBB182-E1EB-44C4-8DB8-20BF2913E929} = {11E9B433-75E3-446D-B8FF-958A0F541BA5} + {64E9FE15-8AE0-44A8-8240-4B8BC3E8823A} = {CE7C3E9D-F9B0-4A30-AA6F-A645D75888D9} + {1F24FB68-6917-4984-89FC-5F9C64E2965D} = {64E9FE15-8AE0-44A8-8240-4B8BC3E8823A} + {99273C3C-2BCE-431A-AEFA-EFBDEE5ECAFB} = {64E9FE15-8AE0-44A8-8240-4B8BC3E8823A} EndGlobalSection EndGlobal diff --git a/control-plane/go.mod b/control-plane/go.mod new file mode 100644 index 0000000..86f13e8 --- /dev/null +++ b/control-plane/go.mod @@ -0,0 +1,3 @@ +module git.ipao.vip/rogee/wx-win-agent/control-plane + +go 1.23 diff --git a/docs/WebUI-MCP-开发计划.md b/docs/WebUI-MCP-开发计划.md index 1634d82..4fb655a 100644 --- a/docs/WebUI-MCP-开发计划.md +++ b/docs/WebUI-MCP-开发计划.md @@ -14,9 +14,9 @@ - [C# 开发计划](WxAgent-CSharp-开发计划.md):总体目标、项目边界、自动化规则。 - [PENDING](PENDING.md):最新功能边界、暂缓事项和未闭环问题;与早期计划冲突时以此为准。 -- `src/WxAgent.Host/Program.cs`:现有 CLI 入口、参数校验、JSON 输出与 smoke。 -- `src/WxAgent.Windows/WechatChatClient*.cs`:UI 操作及管理 API。 -- `src/WxAgent.Core`:业务模型、错误码、监听及只读数据相关逻辑。 +- `node-agent/WxAgent.Host/Program.cs`:现有 CLI 入口、参数校验、JSON 输出与 smoke。 +- `node-agent/WxAgent.Windows/WechatChatClient*.cs`:UI 操作及管理 API。 +- `node-agent/WxAgent.Core`:业务模型、错误码、监听及只读数据相关逻辑。 - `docs/validation/`:已记录的验收证据;实现存在不等于已通过真机验收。 ### 1.1 当前事实 @@ -67,10 +67,10 @@ 建议新增位置: ```text -src/WxAgent.Host/Api/ REST 路由和鉴权 -src/WxAgent.Host/Mcp/ MCP 工具薄适配 -src/WxAgent.Host/wwwroot/ 本地 Web UI -src/WxAgent.Core/ 必要的跨平台契约、校验和任务状态逻辑 +node-agent/WxAgent.Host/Api/ REST 路由和鉴权 +node-agent/WxAgent.Host/Mcp/ MCP 工具薄适配 +node-agent/WxAgent.Host/wwwroot/ 本地 Web UI +node-agent/WxAgent.Core/ 必要的跨平台契约、校验和任务状态逻辑 ``` 仅在实际代码需要时创建文件。Windows 类型留在 Windows/Host;不新建微服务、插件系统或通用仓储框架。 @@ -359,9 +359,9 @@ Queued → Running → Succeeded / Failed / Cancelled / Unconfirmed ```bash dotnet restore WxAgent.sln -p:EnableWindowsTargeting=true -dotnet test tests/WxAgent.Core.Tests -c Release +dotnet test tests/node-agent/WxAgent.Core.Tests -c Release dotnet build WxAgent.sln -c Release -p:EnableWindowsTargeting=true -dotnet publish src/WxAgent.Host -c Release -r win-x64 --self-contained true \ +dotnet publish node-agent/WxAgent.Host -c Release -r win-x64 --self-contained true \ -p:EnableWindowsTargeting=true -p:PublishSingleFile=true -p:PublishTrimmed=false ``` diff --git a/docs/WebUI-面向普通用户重构落地指导.md b/docs/WebUI-面向普通用户重构落地指导.md index 7f916f9..53eafb0 100644 --- a/docs/WebUI-面向普通用户重构落地指导.md +++ b/docs/WebUI-面向普通用户重构落地指导.md @@ -34,9 +34,9 @@ 基线文件: -- `src/WxAgent.Service/wwwroot/index.html`、`app.js`、`styles.css` -- `src/WxAgent.Service/ServiceHost.cs`、`AgentService.cs` -- `src/WxAgent.Service/OperationQueue.cs`、`OperationStore.cs` +- `node-agent/WxAgent.Service/wwwroot/index.html`、`app.js`、`styles.css` +- `node-agent/WxAgent.Service/ServiceHost.cs`、`AgentService.cs` +- `node-agent/WxAgent.Service/OperationQueue.cs`、`OperationStore.cs` - [功能矩阵](WebUI-MCP-功能矩阵.md)、[验收记录](validation/WebUI-MCP-2026-09-07.md)、[暂缓事项](PENDING.md) | 领域 | 当前实现 | 改造缺口 | @@ -271,7 +271,7 @@ R3、R4 可分别评审,但同一桌面的真机 UI 写操作不得并行。R2 复用现有测试项目;本次是指导文档,以下命令在后续代码实施时执行,不代表本次已执行。 ```bash -dotnet test tests/WxAgent.Core.Tests -c Release +dotnet test tests/node-agent/WxAgent.Core.Tests -c Release dotnet build WxAgent.sln -c Release -p:EnableWindowsTargeting=true ``` diff --git a/docs/WxAgent-CSharp-开发计划.md b/docs/WxAgent-CSharp-开发计划.md index d971efd..f210b90 100644 --- a/docs/WxAgent-CSharp-开发计划.md +++ b/docs/WxAgent-CSharp-开发计划.md @@ -52,28 +52,36 @@ ```text WxAgent.sln -├── src/ +├── node-agent/ │ ├── WxAgent.Core/ # net8.0,模型、解析、去重、状态机、业务用例 │ ├── WxAgent.Windows/ # net8.0-windows,FlaUI/UIA/Win32 实现 │ ├── WxAgent.Host/ # net8.0-windows,Desktop Agent 和 CLI +│ ├── WxAgent.Service/ # net8.0,节点本地服务兼容层 │ └── WxAgent.Tray/ # net8.0-windows,托盘常驻、配置和服务生命周期 +├── control-plane/ +│ └── go.mod # Go 远程中心控制面;测试与实现代码同目录 └── tests/ - └── WxAgent.Core.Tests/ # net8.0,可在 Linux 执行 + └── node-agent/ + ├── WxAgent.Core.Tests/ # net8.0,可在 Linux 执行 + └── WxAgent.Service.Tests/ # net8.0,节点本地服务测试 ``` 开始真机自动化后再增加: ```text -tests/WxAgent.Windows.Tests/ # 仅在 Windows 真机执行 +tests/node-agent/WxAgent.Windows.Tests/ # 仅在 Windows 真机执行 ``` +远程中心控制面使用 Go;Go 的 `*_test.go` 与被测实现放在 `control-plane/` 对应包目录,不建立独立测试目录。 + 这种拆分的目的不是建立通用插件框架,而是让纯业务逻辑能够在 Linux 运行测试,同时隔离 Windows 专用引用。 ## 4. 技术选型 | 能力 | 选型 | 说明 | | --- | --- | --- | -| Runtime | .NET 8 LTS,后续可升级 .NET 10 | 优先使用成熟工具链 | +| 节点 Runtime | .NET 8 LTS,后续可升级 .NET 10 | Windows 节点端统一使用 .NET | +| 控制面 Runtime | Go | 单文件部署、低资源占用和并发连接;测试与实现同目录 | | UI Automation | FlaUI.UIA3 | 首选封装,缺失能力再直接调用 UIA COM | | Win32 | Microsoft.Windows.CsWin32 | 按需生成 P/Invoke,不手写大批声明 | | 并发 | `Channel`、`Task`、`IAsyncEnumerable` | 所有 UI 写操作进入单队列 | @@ -113,9 +121,9 @@ tests/WxAgent.Windows.Tests/ # 仅在 Windows 真机执行 ```bash dotnet restore WxAgent.sln -p:EnableWindowsTargeting=true -dotnet test tests/WxAgent.Core.Tests -c Release +dotnet test tests/node-agent/WxAgent.Core.Tests -c Release dotnet build WxAgent.sln -c Release -p:EnableWindowsTargeting=true -dotnet publish src/WxAgent.Host \ +dotnet publish node-agent/WxAgent.Host \ -c Release \ -r win-x64 \ --self-contained true \ @@ -127,8 +135,8 @@ dotnet publish src/WxAgent.Host \ 发布产物: ```text -src/WxAgent.Host/bin/Release/net8.0-windows10.0.19041.0/win-x64/publish/ -src/WxAgent.Tray/bin/Release/net8.0-windows10.0.19041.0/win-x64/publish/ +node-agent/WxAgent.Host/bin/Release/net8.0-windows10.0.19041.0/win-x64/publish/ +node-agent/WxAgent.Tray/bin/Release/net8.0-windows10.0.19041.0/win-x64/publish/ installer/WxAgent.iss → WxAgent-Setup.exe ``` diff --git a/docs/WxAgent-远程多节点控制与白名单数据上报开发计划.md b/docs/WxAgent-远程多节点控制与白名单数据上报开发计划.md new file mode 100644 index 0000000..e66cf5c --- /dev/null +++ b/docs/WxAgent-远程多节点控制与白名单数据上报开发计划.md @@ -0,0 +1,554 @@ +# WxAgent 远程多节点控制与白名单数据上报开发计划 + +> 版本:0.5 +> 日期:2026-09-11 +> 状态:后续阶段计划 + +## 1. 目标 + +在不增加本地 Web UI 和 MCP 的前提下,实现多个 Windows 微信节点的统一远程管理: + +- 远程 Web 管理页面统一查看节点、任务、心跳、运行状态和已授权上报数据。 +- 节点主动向中心控制面建立出站连接,不要求节点开放公网入站端口。 +- 本地仅保留 CLI 作为人工操作和诊断入口。 +- 节点仅上报本地配置白名单内的群聊和私聊数据。 +- 非白名单会话数据不上传、不进入中心缓存、数据库或普通日志。 +- 远程 Web 交互不得改变用户使用桌面微信的 UI 习惯或日常操作方式。 +- 支持多账号显式切换;只切换当前活动账号,不聚合多个账号的数据或状态。 +- Agent 必须配置认证地址和 Token 后,才允许连接中心并上报数据。 +- 远程 Web 必须完成用户认证后才允许登录和访问管理功能。 + +本计划是 `docs/WxAgent-CSharp-开发计划.md` 的后续计划,不改变基础功能和 UIA 实现计划。远程能力应在基础 M6 稳定性工作完成后立项。 + +实现语言边界已冻结:Windows 节点端继续使用 C#/.NET 8;远程中心控制面使用 Go,作为独立 Go module 置于 `control-plane/`。Go 测试与被测实现放在同一包目录,不建立独立测试目录;两端仅通过版本化 HTTP/WebSocket/RabbitMQ 契约通信。 + +## 2. 范围 + +### 2.1 包含 + +- 中心控制面 API +- 远程 Web 管理页面 +- 节点注册、身份认证和节点状态 +- 持久化任务队列、任务租约、结果和审计 +- 节点主动出站长连接、断线重连和心跳 +- Desktop Agent 远程任务消费与结果上报 +- 本地白名单配置和上报前过滤 +- 白名单群聊、私聊数据的安全上报、去重和远程展示 +- 多账号显式切换和账号上下文隔离,不做账号数据聚合 +- Agent 认证地址、Token 配置和认证状态 +- 远程 Web 用户认证、会话管理和访问审计 +- 节点、任务、数据上报和连接状态的诊断信息 + +### 2.2 不包含 + +- 本地 Web UI +- 本地 MCP 服务 +- 节点公网入站端口 +- 远程任意 Shell、PowerShell 或文件系统执行 +- 上传完整微信数据库、登录凭据、密钥或非白名单会话数据 +- 自动扩大、覆盖或绕过节点本地白名单 +- Windows Service;UIA Agent 必须运行在已登录的交互式用户会话中 +- SaaS、多租户、计费和商业授权 + +## 3. 总体架构 + +```text + ┌────────────────────┐ + │ 远程 Web 管理页面 │ + └─────────┬──────────┘ + │ HTTPS + ┌─────────▼──────────┐ + │ 中心控制面 │ + │ API / 认证 / 审计 │ + │ 任务队列 / 状态存储 │ + │ 白名单数据存储 │ + └──────┬───────┬──────┘ + │ │ + 任务投递│ │状态、事件和数据接收 + │ │ + ┌──────▼───────▼──────┐ + │ mTLS WebSocket/HTTPS │ + │ 出站连接网关 │ + └──────────┬──────────┘ + │ 节点主动出站 + ┌───────────────▼───────────────┐ + │ Windows 节点 Desktop Agent │ + │ 心跳 / 任务 / 认证 / 白名单 │ + └───────────────┬───────────────┘ + │ 单窗口串行队列 + ┌───────────────▼───────────────┐ + │ 微信 UIA Worker │ + └────────────────────────────────┘ + ▲ + │ 本机操作和诊断 + ┌─────┴─────┐ + │ 本地 CLI │ + └───────────┘ +``` + +### 3.1 组件职责 + +#### 中心控制面 + +- 提供远程 Web 使用的 HTTPS API。 +- 注册节点并维护节点身份、能力、版本、在线状态和最后心跳。 +- 保存任务、任务状态、租约、结果和审计记录。 +- 接收节点心跳、任务结果和白名单数据。 +- 向已认证节点投递任务或通知节点重新消费任务。 +- 初期作为一个可独立部署的进程实现,不提前拆分微服务。 + +#### 节点 Desktop Agent + +- 在已登录且未锁定的 Windows 用户会话中常驻运行。 +- 主动建立到中心的 mTLS WebSocket 或等价长连接。 +- 必须同时配置认证地址和 Token;认证缺失或失败时禁止数据上报,并标记明确错误状态。 +- 消费分配给本节点的任务并写入本地任务队列。 +- 将所有微信窗口写操作交给现有单一 UIA 命令队列。 +- 发送心跳、连接状态、微信状态、任务状态和结果。 +- 对所有出站数据执行统一本地授权检查:序列化/入队前过滤,实际发送和每次重试前按当前配置复核;任务结果不得绕过该边界。 + +#### 本地 CLI + +- 作为节点本地唯一人工操作和诊断入口。 +- 配置、查看和测试本节点的群聊/私聊上报白名单。 +- 查看 Agent、微信连接、任务和上报队列状态。 +- 不承担远程 Web 服务、MCP 服务或长期公网监听。 + +#### 远程 Web 管理页面 + +- 查看节点列表、连接状态、微信状态、Agent 版本和最近心跳。 +- 创建、查看、取消和追踪远程业务任务。 +- 查看任务结果、错误、审计记录和已上报的白名单数据。 +- 当前版本只展示节点本地白名单摘要,不得通过 Web 扩大节点上报范围。 +- 所有登录、任务和数据查询功能必须先通过用户认证;未认证用户不得进入管理页面或调用业务 API。 + +### 3.2 桌面交互和多账号原则 + +- 远程 Web 只提交业务任务和查看状态,不替代用户对桌面微信的日常操作,不要求用户改变现有 UI 使用习惯。 +- Agent 不安装桌面覆盖层、不接管全局键盘/鼠标、不修改微信布局、快捷键或用户设置;远程任务通过现有 UIA 能力和本地串行队列执行。 +- 用户正在手动操作同一微信窗口时,Agent 不强行抢焦点或插队;未开始的任务应有界等待、返回 `UiInteractionConflict` 或由用户显式确认后执行,等待不得超过任务截止时间。 +- 单一命令队列只能约束 Agent,不能锁住用户操作。任务入口及每个关键写步骤(填写输入框、发送、确认变更等)前,必须重新检查活动账号、目标会话、窗口/焦点、输入框及必要页面状态;发现人工输入、会话变化或状态无法确认时,停止后续写步骤,不自动恢复焦点、覆盖草稿或清理用户输入。 +- 若中止前已完成部分业务操作,在最终结果中记录已确认的部分效果;可能已产生业务副作用但无法确认时进入 `ResultUnconfirmed`,不得按“未执行”重试。用户确认仅允许重新检查后执行,不免除步骤前复核。 +- UIA 检查和桌面点击不是原子操作,不承诺在任意人工并发下绝对安全;无法可靠检测冲突的写路径应拒绝远程执行,待用户停止操作并显式确认后重新校验。 +- 多账号只实现显式切换:同一微信实例同时只允许一个活动账号,不并行操作多个账号,不聚合账号的消息、联系人、任务或统计数据。 +- 账号相关配置、游标、缓存、任务和上报数据必须带 `account_id` 并彼此隔离;远程 Web 分账号展示,不提供跨账号聚合视图。 + +## 4. 任务与连接模型 + +### 4.1 任务投递 + +中心任务队列是任务事实源,WebSocket 只是实时投递和通知通道: + +```text +Web 提交任务 + → 中心持久化 Pending + → 按 node_id + account_id 分配带执行代次的任务租约 + → 节点持久化任务和去重记录后确认 Accepted + → 本地串行队列调度,执行前持久化 Running + → 校验租约、授权及桌面上下文后执行 + → 持久化最终结果,再向中心回传(状态规则见 §4.5) +``` + +要求: + +- 至少一次投递只保证任务可重复送达,不保证 UI 副作用恰好一次。任务必须支持 `task_id` 和幂等键;同一节点、账号和幂等键绑定相同命令及参数,不同载荷复用该键时拒绝请求。 +- 节点必须先持久化任务、载荷校验信息和去重记录,再确认 `Accepted`;仅进入内存队列不能确认。重复投递只返回已有状态/结果,不创建第二次执行;记录保留期限必须覆盖任务可投递/恢复窗口。 +- 每次租约带递增的执行代次;节点在每个关键写步骤前校验代次、租约和截止时间。租约失效、撤销、认证失效或连接中断后,停止启动新的写步骤并记录已知结果;已发出的 UI 动作不能假定已撤回。 +- 中心不得仅因断线或租约过期就重新执行写任务。须确认旧执行者已停止且任务未进入 `Running`,才允许向原目标节点和账号重新投递;无法证明时禁止自动接管,进入 `ResultUnconfirmed`。代次校验用于拒绝旧执行者继续推进状态,不宣称它能撤销桌面点击。 +- 首版执行记录只持久化接收、开始执行和最终结果:任何 UI 操作前先落盘 `Running`,落盘失败不得执行;恢复时发现 `Running` 且无最终结果,一律进入 `ResultUnconfirmed`,不自动重放。不维护逐步骤持久化日志或断点续执行;正常中止时将已确认的部分效果写入最终结果,步骤前安全复核仍保留。 +- 发送消息、联系人变更、群成员变更、朋友圈操作等不可盲目自动重试。读任务只能在命令明确可安全重复且不与旧执行者并发操作窗口时有界重试;重复回传结果不等于重新执行任务。 +- 任务命令使用业务白名单,不支持任意 Shell 或远程代码执行;命令权限与数据上报授权分开校验,见 §5.1。 +- 远程任务不得绕过节点已有的单窗口 UI 写队列。 + +### 4.2 节点状态 + +节点至少上报: + +- `node_id` +- Agent 版本和协议版本 +- 最近心跳时间 +- 长连接状态 +- 微信进程和登录状态 +- 当前任务摘要 +- 本地任务队列长度 +- 白名单配置版本和上报游标 +- 最近错误码和 Correlation ID + +状态至少包括: + +```text +Registered +Online +Degraded +Offline +SessionLocked +WechatNotRunning +WechatNotLoggedIn +``` + +心跳超时只能标记节点状态,不应直接删除未完成任务或清空数据队列。 + +### 4.3 断线恢复 + +- 节点使用指数退避重连,并限制最大重连频率。 +- 中心保留未完成任务和任务租约状态。 +- 节点重连后先同步持久化任务状态、执行代次、最终结果和取消请求,再按 §4.1、§4.5 判断可恢复性;已知结果只补传,不重新执行,不确定任务保留待核对状态。 +- 白名单数据使用本地有限缓存;缓存必须有大小和时间上限。补传前按当前账号作用域、白名单、数据类型授权和认证状态重新校验,禁止沿用入队时的授权。 +- 任务通过持久化执行记录防止重复启动;事件和数据通过持久化序号及幂等键防止重复入库。不以序号或幂等键替代 UI 副作用确认。 + +### 4.4 多账号切换 + +- 每个微信实例维护独立的账号列表和当前活动账号;同一实例同一时刻只操作一个账号。 +- 账号切换必须是显式任务或本地 CLI 操作;切换前暂停或完成当前账号的任务,不在切换过程中并发执行 UI 操作。 +- 切换只改变当前活动账号,不合并消息、联系人、任务、游标、缓存、统计或上报数据。 +- 远程任务必须携带 `account_id`;节点在执行前校验目标账号,账号不匹配时不得误操作当前账号。 +- 切换后必须重新确认微信登录状态、当前账号和白名单配置;不默认补传切换前其他账号的历史数据。 +- `account_id` 必须绑定节点本地可验证的账号身份,不能仅用昵称、PID 或窗口句柄推断;身份无法确认时拒绝账号业务任务和会话数据上报。检测到用户自行切换或重新登录时,也必须停止旧上下文执行并重新确认,不能仅处理 Agent 发起的切换。 + +### 4.5 任务状态、取消和超时 + +| 状态 | 含义与转换约束 | +| --- | --- | +| `Pending` | 中心已持久化,尚未取得节点持久化接收确认。 | +| `Accepted` | 节点已持久化,等待串行调度;校验通过后先持久化 `Running`,再开始执行。 | +| `Running` | 节点已持久化开始执行记录,不代表已产生业务效果;持续检查租约、取消、截止时间和桌面上下文。 | +| `Succeeded` | 终态;全部业务效果已确认。取消请求到达前已完成的任务仍可返回此状态。 | +| `Failed` | 终态;失败原因和已确认步骤明确,可能包含已确认的部分业务效果,不隐含回滚或可重试。 | +| `Cancelled` | 终态;确认执行者已停止且未产生业务副作用。仅切换页面等已知 UI 状态变化应单独记录。 | +| `Expired` | 终态;截止时间到达,且确认执行者已停止、未产生业务副作用。 | +| `ResultUnconfirmed` | 自动执行流程的终态;存在业务副作用可能性或无法证明旧执行者停止,禁止自动重放,等待人工核对。 | + +- 正常流转为 `Pending → Accepted → Running → Succeeded/Failed/ResultUnconfirmed`;尚未执行的任务可在确认安全后直接进入 `Cancelled/Expired`。 +- 取消意图使用独立、可空的持久化字段 `cancel_requested_at`,首次请求时设置,重复请求不重置;不替换 `Pending/Accepted/Running` 主状态。Web 对带此字段的非终态显示“取消待确认”。从未投递且中心能原子阻止后续投递的任务可直接取消;已投递或接收确认丢失时必须等待节点核对,不能因节点离线显示“已取消”。 +- 节点收到取消或到达截止时间后,在下一个安全检查点停止启动新步骤;取消不能回滚已经完成的发送或变更。全部效果确认完成时为 `Succeeded`,部分效果确认且余下已停止时为 `Failed` 并记录取消/超时原因;存在不确定效果时为 `ResultUnconfirmed`。 +- 中心按状态版本和执行代次校验更新,拒绝乱序回退及终态覆盖;过期代次的回报只作为核对证据,不直接推动状态。重复取消和结果回传必须幂等。 +- `ResultUnconfirmed` 的人工核对结论单独审计,不将原任务重新置为 `Pending/Running`;如确需再次操作,必须显式创建新任务并关联原任务、提示重复副作用风险。 +- R0 冻结任务截止时间、租约续期/到期安全余量及取消确认等待上限。无法安全判断时停止新写步骤;确认等待超时且仍无法证明未执行时使用 `ResultUnconfirmed`,不能伪造取消或过期成功。 + +## 5. 本地白名单与数据上报 + +### 5.1 授权边界 + +本阶段采用**本地白名单模式**: + +- 每个节点单独配置允许上报的群聊和私聊。 +- 本地配置是上报授权的唯一来源。 +- 远程 Web 只能展示白名单摘要和已上报数据,不能扩大上报范围。 +- 非白名单会话即使被 UIA 监听器发现,也必须在本地过滤掉。 +- 所有出站通道共用本地授权边界,覆盖消息事件、任务结果、错误详情、诊断、状态摘要及附件;在出站序列化和入队前检查,在实际发送和每次重试前再次检查。 +- 命令白名单只决定能否执行操作,不授予读取结果的上报权限。远程读取非白名单会话内容的任务应在读取前拒绝;其他任务也不得借结果、截图、异常或审计回传该会话信息。首版任务内容结果限定单账号、单会话;身份或数据类型授权不满足时整份内容不回传,仅回传允许的控制元数据。不支持跨会话组合结果及部分内容剥离;独立消息事件仍各自校验,不受此任务结果限制。 +- 无会话内容的控制元数据(任务 ID、状态、错误码等)可在认证通过后按固定字段列表上报;授权被撤销时,仍可回传不含会话标识、名称、正文或附件的任务状态,并标记 `ReportingNotAuthorized`,不改变实际执行结果。普通日志仍遵守默认脱敏要求。 + +身份匹配要求: + +- 白名单必须绑定 `node_id + account_id` 作用域内唯一且可验证的 `chat_id` 及会话类型。显示名称和名称哈希仅用于辅助显示,不能在本节点或跨节点单独作为授权身份;UIA RuntimeId 也不能作为持久身份。 +- 仅凭同名无法唯一识别、多候选、类型不符、账号不确定、标识失效或绑定无法验证时默认拒绝上报,返回 `ChatIdentityUnconfirmed`;由本地 CLI 重新确认绑定,不能自动迁移授权。同名但各自稳定身份已验证的会话可分别授权。 +- 改名但稳定身份仍可验证时保留绑定;仅能得到名称的会话不启用远程数据上报。R0 必须明确当前微信版本的账号/会话标识来源、验证证据及失效条件,不能把显示名包装成“稳定 ID”。 + +### 5.2 上报流程 + +```text +UIA 事件/本地读取/任务结果/诊断 + → 识别账号、会话身份及数据类型 + → 统一本地授权判断 + → 未授权或身份不确定:丢弃内容,仅保留允许的控制元数据 + → 已授权:标准化、脱敏、原子持久化序号和上传项 + → 实际发送/每次重试前按当前配置及认证状态复核 + → 撤销:阻断并清理对应待上传内容 + → 仍获授权:中心 HTTPS/长连接上报 + → 中心按作用域和序号保存,持久化后确认 +``` + +会话数据事件至少包含以下字段;无会话内容的控制元数据使用 R0 冻结的独立字段列表,不为填充本模型而泄漏会话信息: + +- `node_id` +- `account_id`(本地账号的脱敏标识) +- `chat_id` 或本地会话标识 +- 会话类型:群聊或私聊 +- `event_seq` +- 事件/消息类型 +- 发生时间 +- 按当前消息模型生成的内容或内容摘要 +- `config_version`(入队时的节点上报配置版本) +- `authorization_version`(本次发送复核通过的节点上报配置版本,不覆盖入队版本) +- `correlation_id` + +### 5.3 数据禁止项 + +以下数据不得上报: + +- 非白名单群聊和私聊的消息、事件及附件 +- 完整微信数据库 +- 数据库密钥、登录凭据、Cookie 或 Token +- 未脱敏的诊断 UI 树和普通日志中的非授权内容 +- 与任务无关的本地文件或进程内存内容 + +白名单会话内的图片、文件、语音等附件是否上报,应由后续协议和本地配置单独定义,不能默认扩大为全量附件上传。 + +### 5.4 去重与保留 + +- 使用 `node_id + account_id + chat_id + event_seq` 作为上报幂等键;中心唯一约束、查询、缓存和确认游标都使用相同账号作用域。 +- `event_seq` 在每个 `node_id + account_id + chat_id` 内单调递增,并与上传项原子持久化;重试复用原序号,不因重连、账号切换、配置更新或缓存清理归零。序号状态丢失时停止上报,恢复可信状态或重新注册新节点身份后才能继续,禁止复用旧身份从零发送。 +- 中心拒绝或忽略重复事件,不重复展示;相同幂等键但事件内容不同应拒绝并报警,不覆盖已有数据。事件内容(含入队 `config_version`)不可变,发送级 `authorization_version` 和请求 Correlation ID 不参与内容一致性比较,以允许重新授权复核后的合法重试。 +- 中心持久化成功后才确认,节点正常完成上传时仅删除已确认项;授权撤销、过期和缓存淘汰按本节及 §5.5 主动丢弃,不必等待中心确认,也不能将其记为上传成功。 +- 撤销、过期和缓存淘汰允许产生序号空洞;确认只针对实际持久化项,不把最大已收序号等同于之前全部收到。游标和补传规则不得为填洞重建已撤销内容。 +- 节点和中心都设置有界缓存、失败重试次数和数据保留期限。 +- 删除或过期策略必须同时适用于消息正文、附件、缓存和诊断副本。 + +### 5.5 授权撤销与在途数据 + +- 删除会话、关闭会话/账号/全局上报或收紧数据类型授权时,立即阻断受影响的新入队和发送,并清理未发送及待重试的对应内容(含任务结果、附件暂存、诊断副本);清理失败时保持阻断,不能沿用旧配置继续发送。 +- 配置生效与上传发送许可检查必须本地串行化:撤销生效后,尚未提交网络发送的请求不得再发出。批次逐项复核;`config_version` 仅用于审计,不能替代当前授权判断。 +- 已提交网络发送的在途请求应尽力取消,但无法保证撤回中心已接收的数据;它们可能在本地撤销生效后才到达中心。CLI 必须明确提示此边界,不承诺追溯删除;取消确认不明的请求也不得在撤销后重试。 +- 撤销上报不自动删除中心此前合法接收的数据,既有数据按保留策略处理;需要追溯删除时另行执行经过认证和审计的删除流程,覆盖正文、附件、缓存与诊断副本。 +- 配置加载失败时阻断所有受影响发送;Token 失效时阻断全部远程发送和任务消费。配置/认证恢复后必须重新校验,不得直接排空旧队列;重新授权也不恢复已清理内容或自动补传历史。 + +## 6. 配置模型 + +### 6.1 节点本地配置 + +```json +{ + "reporting": { + "enabled": true, + "configVersion": 1, + "accounts": [ + { + "accountId": "local-verified-account-id", + "enabled": true, + "allowedChats": [ + { + "type": "group", + "chatId": "local-verified-group-id", + "enabled": true + }, + { + "type": "private", + "chatId": "local-verified-private-id", + "enabled": true + } + ] + } + ] + } +} +``` + +示例仅表示结构,不代表最终消息协议。配置要求: + +- 本地 CLI 必须指定或确认已验证的 `accountId`,可读取、修改、校验并显示脱敏摘要;新账号默认关闭、白名单为空,不继承其他账号配置。文件中 `accountId` 对应协议中的 `account_id`,`chatId` 对应 `chat_id`。 +- 全局、账号及会话开关必须全部允许才可上报;账号缺失、重复账号/会话绑定或身份不可验证时拒绝生效,不按名称回退。 +- 整份节点上报配置使用一个持久化 `configVersion`;任一开关或账号白名单变更时递增,并与配置原子写入、记录本地审计。不维护各账号独立版本或删除后的版本高水位;删除/重建账号不重置整份配置版本。 +- Agent 只使用当前生效且校验通过的配置;实际发送仍分别检查全局开关、目标账号、会话和数据类型授权。`config_version` 与 `authorization_version` 均指节点上报配置版本;共享版本仅标识配置修订,不合并账号权限、数据或游标。 +- 配置加载失败时默认拒绝数据上报,不默认放开范围;撤销、关闭和队列清理遵守 §5.5。 +- 白名单变更不能自动触发历史数据全量补传;本例不授予附件上传权限,数据类型策略须在 R0 单独冻结。 + +### 6.2 Agent 远程认证配置 + +Agent 只有在同时配置并成功验证以下两项后,才允许连接中心、消费远程任务或上报白名单数据: + +- `authAddress`:中心认证/接入地址,必须使用 HTTPS 或等价安全传输。 +- `token`:节点专用认证 Token,按节点单独签发,可撤销、可轮换。 + +示例: + +```json +{ + "remote": { + "authAddress": "https://control.example.com/api/auth", + "token": "" + } +} +``` + +要求: + +- 缺少任一字段、地址不可达、Token 无效或认证过期时,默认拒绝远程任务和数据上报;本地 CLI 和本地微信能力可继续用于诊断。 +- Token 由本地 CLI 配置或更新,存储使用最小权限;日志、诊断输出和远程状态不得输出完整 Token。 +- 认证状态至少包含 `NotConfigured`、`Authenticating`、`Authenticated` 和 `AuthenticationFailed`。 +- 认证地址和 Token 不能通过未认证的远程 Web 请求下发到节点。 + +### 6.3 中心展示模型 + +中心仅保存节点上报的配置摘要,例如: + +- 节点 ID +- 当前活动账号的脱敏标识(不合并多个账号) +- 配置版本 +- 白名单数量和类型统计 +- 最近生效时间 +- 最近上报游标 +- 最近上报时间 + +中心不应将本地白名单转换成可以覆盖节点配置的远程期望状态,除非后续单独增加显式授权和审批流程。中心也不得跨账号合并消息、联系人、任务或统计数据。 + +## 7. 安全要求 + +- Agent 必须同时配置有效的 `authAddress` 和 `token`;未完成认证时禁止远程任务消费和白名单数据上报。 +- 远程 Web 必须先完成用户认证才允许登录和访问管理页面;所有业务 API、任务操作和数据查询都必须校验登录会话或访问令牌。 +- 每个节点使用独立身份;优先 mTLS,短期令牌作为受控替代方案。 +- 节点仅主动出站,中心不要求开放节点公网入站端口。 +- 节点不直接暴露 RabbitMQ 等 broker,也不持有 broker 管理权限;如使用消息队列,队列由中心控制面封装。 +- Web 管理页面实行用户认证、角色权限和操作审计。 +- 每个任务绑定目标节点、账号和命令权限,服务端和节点端都执行命令白名单校验;节点另按 §5.1 对全部出站内容校验本地数据授权,任务权限不得扩大上报范围。 +- 远程 API、任务、事件和数据上报均携带 Correlation ID。 +- 远程存储的白名单消息和附件使用 TLS 传输,并按部署环境启用静态加密和保留期限。 +- 普通日志不得记录完整消息正文、联系人名称、附件内容、密钥或令牌。 +- 节点证书、令牌和配置文件使用最小权限保存,支持撤销节点身份。 + +## 8. 项目边界 + +### 8.1 节点发布包 + +节点发布包只包含: + +- Desktop Agent +- 本地 CLI +- Windows UIA/Win32 实现 +- 本地配置、短期去重和有界上报缓存 +- 脱敏日志和诊断工具 + +节点发布包不包含: + +- Web 前端 +- MCP 服务 +- 公网监听服务 +- 中心数据库和中心消息队列 + +### 8.2 中心部署 + +中心初期采用一个可独立部署的 Go 控制面进程,包含: + +- HTTPS API +- WebSocket 出站连接网关 +- 节点注册和鉴权 +- 任务存储/队列 +- 节点状态和审计存储 +- 白名单数据存储接口 + +只有在实际吞吐、可用性或团队协作需要证明后,才拆分独立网关、消息队列或数据服务。 + +## 9. 里程碑 + +### R0:协议和边界冻结 + +- 冻结节点/账号/会话身份来源和失效规则、任务状态、心跳、结果和事件模型;同名或身份不确定时默认拒绝。 +- 冻结接收/开始/最终结果持久化、执行代次、租约失效停止规则、独立取消意图字段、超时及 `ResultUnconfirmed` 人工核对边界;不实现逐步骤恢复,不承诺 UI 副作用恰好一次。 +- 冻结整份上报配置的单一版本、账号独立授权、序号、幂等键和确认游标,以及序号空洞和本地状态丢失处理。 +- 冻结 Agent 认证地址、Token 和认证失败时的默认拒绝行为。 +- 冻结远程 Web 用户认证、会话过期和未认证访问规则。 +- 冻结本地白名单作为唯一上报授权来源。 +- 冻结全部出站通道的统一授权边界、单账号单会话任务内容结果、允许的控制元数据字段及撤销/在途边界;非白名单内容不得进入上传队列、中心 API、数据库、缓存和普通日志。 +- 明确消息正文、摘要、附件和语音等数据类型的上报策略。 + +验收:形成版本化协议文档和脱敏示例;没有“默认全量上报”路径。 + +### R1:中心控制面最小闭环 + +- 节点注册和身份认证。 +- 节点状态、心跳和审计存储。 +- 任务创建、查询、取消和状态流转。 +- 一个节点的任务投递和结果回传。 + +验收:中心重启后任务状态不丢失;未完成任务不会被错误标记成功;取消请求不等于已取消,乱序/过期代次回报不能覆盖终态,不确定任务不能自动重新执行。 + +### R2:节点出站连接和任务执行 + +- Desktop Agent 主动连接、鉴权和重连。 +- 多账号显式切换、当前活动账号确认和账号上下文隔离。 +- 任务租约、确认、超时和幂等处理。 +- 本地任务队列与现有 UIA 单队列衔接。 +- 心跳和微信状态上报。 + +验收:节点无公网入站端口时仍可完成任务;覆盖接收、开始执行及最终结果落盘边界的崩溃,`Running` 无最终结果时不自动重放并显式上报不确定;切换账号不会合并或串用任何账号数据,人工干预时停止后续写步骤。 + +### R3:白名单数据上报 + +- CLI 配置群聊/私聊白名单。 +- 消息事件在本地过滤后进入有界上传队列。 +- 白名单数据按序上报、去重和断点恢复。 +- 非白名单数据泄漏检查。 + +验收:非白名单及身份不确定内容不通过消息、任务结果、错误或诊断进入中心 API、数据库、缓存和普通日志;离线入队后撤销的内容不在重连时补传;跨账号同会话 ID/序号不互相去重;白名单数据可查询且无重复。在途撤销按 §5.5 验证并明确提示,不宣称已经发送的数据可撤回。 + +### R4:远程 Web 管理页面 + +- 节点列表和状态。 +- 任务创建、查询、取消和结果查看。 +- 配置摘要和上报游标。 +- 白名单数据检索和基本展示。 +- 登录认证、会话过期、用户权限和操作审计。 +- 不改变桌面微信 UI 习惯的远程交互和冲突提示;明确展示取消待确认、部分效果和结果不确定状态,不提供隐式重试。 + +验收:Web 只能查看中心已接收的数据,不能绕过本地白名单扩大上报范围;未认证用户不能登录或调用业务 API;远程交互不强制改变用户桌面微信操作方式。 + +### R5:稳定性与安全验收 + +- 多节点并发任务。 +- 网络断开、中心重启和节点重启恢复。 +- 证书/令牌撤销。 +- 任务、事件和数据重复投递测试。 +- 缓存上限、保留期限和敏感信息扫描。 + +验收:达到预定节点规模和任务吞吐;失败任务可定位,数据边界和权限边界可验证。 + +## 10. 测试计划 + +### 10.1 Linux 纯逻辑测试 + +- 白名单匹配和默认拒绝。 +- 群聊/私聊会话身份标准化。 +- 整份配置版本递增、原子更新和加载失败处理;共享版本不改变账号独立授权。 +- Agent 认证地址、Token 缺失/失效和默认拒绝。 +- 多账号切换状态和账号数据隔离。 +- 任务状态机、持久化接收确认、执行代次及幂等键;同键不同载荷拒绝。 +- 租约失效、独立取消意图与完成竞态、截止时间和终态不可回退;重复取消不重置请求时间,`Running` 无最终结果不自动重试。 +- 所有出站通道的内容授权和控制元数据字段列表;任务结果非单账号单会话或授权不满足时整份内容拒绝,任务权限不能代替数据授权。 +- 同名/多候选/标识失效默认拒绝;同 `chat_id + event_seq` 在不同账号下不碰撞。 +- 离线入队后撤销、关闭或配置失效时禁止发送;重新授权不恢复已清理内容;批次部分撤销和发送许可竞态。 +- 心跳超时和节点状态转换。 +- 事件序号与上传项原子持久化、断点续传和重复数据去重;序号空洞不误确认,状态丢失不复用旧序号。 +- 脱敏序列化和日志过滤。 + +### 10.2 Windows 真机测试 + +- 本地 CLI 配置白名单。 +- 本地 CLI 配置认证地址和 Token;缺少或认证失败时不上报。 +- 白名单会话消息发现和上报。 +- 非白名单会话消息发现但不上报。 +- 微信重启、Agent 重启和网络断开恢复。 +- 多账号切换只切换当前账号,不聚合数据。 +- 远程任务不强制抢焦点、不改变窗口布局;分别在打开会话后、填写输入框前、发送前人为切换会话/账号或编辑草稿,验证停止后续写步骤、不覆盖用户输入,部分效果和不确定状态正确记录。 +- 在接收持久化前后、`Running` 落盘后但尚未执行、发送成功但最终结果未落盘及结果落盘后终止 Agent;验证无最终结果的 `Running` 统一为 `ResultUnconfirmed`、已有最终结果只补传,均不自动重发;租约失效/连接中断后不再启动新写步骤。 +- 多个任务进入同一微信窗口时保持串行。 +- 锁定桌面、微信退出和重新登录后的状态恢复。 + +### 10.3 中心集成测试 + +- 多节点注册和独立身份校验。 +- Agent 未配置认证地址或 Token 时拒绝上报。 +- 节点断线时租约回收不触发写任务盲目接管;旧执行者未确认停止时禁止并发重执行,过期代次结果仅用于核对。 +- 节点离线取消、取消与发送完成竞态、任务超时和重复取消;确认未知时显示 `ResultUnconfirmed`,不伪造取消成功。 +- Web 完成用户认证后创建任务到节点执行的完整链路。 +- 未认证用户访问页面、API、任务和数据查询均被拒绝。 +- 重复心跳、重复任务结果和重复事件上报。 +- 中心重启后的任务、状态和数据一致性。 +- 通过远程读取任务、跨会话组合结果、异常及诊断尝试回传内容;验证非白名单及不支持的任务内容结果被整份拒绝、仅允许的控制元数据可回传,扫描 API、数据库、缓存和日志确认无泄漏。 +- 离线入队→删除白名单/关闭上报→重连,验证无撤销后重试;在途撤销与中心已接收数据按 §5.5 边界验收。 +- 两账号使用相同本地会话 ID 和序号分别上报,验证中心存储、查询、缓存和游标完全隔离。 + +## 11. 第一批任务 + +1. 新建并冻结本计划对应的远程协议草案。 +2. 在 Core 中定义节点、账号、任务、心跳、事件和白名单模型。 +3. 实现本地 CLI 的账号独立白名单、身份绑定校验、整份上报配置单一版本和默认拒绝逻辑。 +4. 实现本地 CLI 的认证地址和 Token 配置、校验及脱敏显示。 +5. 为消息、任务结果、错误和诊断增加统一出站授权检查,实现入队过滤、发送前复核及撤销清理。 +6. 实现中心任务/节点状态、节点接收/开始/最终结果及独立取消意图字段的持久化,覆盖租约、超时和不确定结果,不做逐步骤恢复。 +7. 实现单节点出站连接、心跳和最小任务闭环;持久化后确认,恢复时只重投明确安全的任务。 +8. 实现账号显式切换和切换后的状态确认,不实现账号聚合。 +9. 使用文件传输助手及专用测试群验证白名单上报。 +10. 完成所有出站通道泄漏检查、离线撤销、同名拒绝、跨账号去重和崩溃恢复的自动化测试。 +11. 验证远程 Web 未认证访问拒绝、取消/不确定状态展示及执行期间人工干预后的安全停止。 + +第一阶段不修改基础计划的 M0–M6 顺序;远程能力从 R0 开始,在基础稳定性验收后推进。 diff --git a/docs/validation/General-Sending-2026-09-06.md b/docs/validation/General-Sending-2026-09-06.md index d8e18b6..cef16cc 100644 --- a/docs/validation/General-Sending-2026-09-06.md +++ b/docs/validation/General-Sending-2026-09-06.md @@ -19,7 +19,7 @@ ## 验证结果 -Linux:`dotnet test tests/WxAgent.Core.Tests -c Release --no-restore`,**121/121 通过**;完整解决方案 Release build 无警告、无错误。新增测试覆盖新旧指纹、错误类型/正文/文件名、结构化提及、Unicode 提及间隔、文本长度/控制字符及多行引用解析。 +Linux:`dotnet test tests/node-agent/WxAgent.Core.Tests -c Release --no-restore`,**121/121 通过**;完整解决方案 Release build 无警告、无错误。新增测试覆盖新旧指纹、错误类型/正文/文件名、结构化提及、Unicode 提及间隔、文本长度/控制字符及多行引用解析。 最终包执行 `Test-GeneralSending.ps1 -IncludeMentions`,**9/9 通过**: diff --git a/docs/validation/M1-2026-09-04.md b/docs/validation/M1-2026-09-04.md index 3b26c64..0d27355 100644 --- a/docs/validation/M1-2026-09-04.md +++ b/docs/validation/M1-2026-09-04.md @@ -11,9 +11,9 @@ ## Linux 检查 ```bash -dotnet test tests/WxAgent.Core.Tests -c Release +dotnet test tests/node-agent/WxAgent.Core.Tests -c Release dotnet build WxAgent.sln -c Release -p:EnableWindowsTargeting=true -dotnet publish src/WxAgent.Host -c Release -r win-x64 --self-contained true \ +dotnet publish node-agent/WxAgent.Host -c Release -r win-x64 --self-contained true \ -p:EnableWindowsTargeting=true -p:PublishSingleFile=true \ -p:IncludeNativeLibrariesForSelfExtract=true -p:PublishTrimmed=false ``` diff --git a/docs/validation/M1A-2026-09-04.md b/docs/validation/M1A-2026-09-04.md index c5b238d..5371462 100644 --- a/docs/validation/M1A-2026-09-04.md +++ b/docs/validation/M1A-2026-09-04.md @@ -8,7 +8,7 @@ ## Linux - .NET SDK:`8.0.424` -- `dotnet test tests/WxAgent.Core.Tests -c Release`:7/7 通过。 +- `dotnet test tests/node-agent/WxAgent.Core.Tests -c Release`:7/7 通过。 - `dotnet build WxAgent.sln -c Release -p:EnableWindowsTargeting=true`:0 warning / 0 error。 - self-contained single-file `win-x64` 发布成功;产物约 182 MB,包含自提取 SQLCipher native library。 diff --git a/docs/validation/M2-Search-Quote-History-2026-09-04.md b/docs/validation/M2-Search-Quote-History-2026-09-04.md index 6a22e34..b46514c 100644 --- a/docs/validation/M2-Search-Quote-History-2026-09-04.md +++ b/docs/validation/M2-Search-Quote-History-2026-09-04.md @@ -10,9 +10,9 @@ ## Linux 验证 ```bash -dotnet test tests/WxAgent.Core.Tests -c Release +dotnet test tests/node-agent/WxAgent.Core.Tests -c Release dotnet build WxAgent.sln -c Release -p:EnableWindowsTargeting=true -dotnet publish src/WxAgent.Host -c Release -r win-x64 --self-contained true \ +dotnet publish node-agent/WxAgent.Host -c Release -r win-x64 --self-contained true \ -p:EnableWindowsTargeting=true -p:PublishSingleFile=true \ -p:IncludeNativeLibrariesForSelfExtract=true -p:PublishTrimmed=false ``` diff --git a/docs/validation/M3-Listening-2026-09-04.md b/docs/validation/M3-Listening-2026-09-04.md index 40f7efb..c585b0f 100644 --- a/docs/validation/M3-Listening-2026-09-04.md +++ b/docs/validation/M3-Listening-2026-09-04.md @@ -11,9 +11,9 @@ ## Linux 验证 ```bash -dotnet test tests/WxAgent.Core.Tests -c Release +dotnet test tests/node-agent/WxAgent.Core.Tests -c Release dotnet build WxAgent.sln -c Release -p:EnableWindowsTargeting=true -dotnet publish src/WxAgent.Host -c Release -r win-x64 --self-contained true \ +dotnet publish node-agent/WxAgent.Host -c Release -r win-x64 --self-contained true \ -p:EnableWindowsTargeting=true -p:PublishSingleFile=true \ -p:IncludeNativeLibrariesForSelfExtract=true -p:PublishTrimmed=false ``` diff --git a/docs/validation/M4-Management-History-2026-09-04.md b/docs/validation/M4-Management-History-2026-09-04.md index 0808091..2fa5ec3 100644 --- a/docs/validation/M4-Management-History-2026-09-04.md +++ b/docs/validation/M4-Management-History-2026-09-04.md @@ -22,13 +22,13 @@ ## Linux 验证 ```text -~/.dotnet/dotnet test tests/WxAgent.Core.Tests -c Release --no-restore +~/.dotnet/dotnet test tests/node-agent/WxAgent.Core.Tests -c Release --no-restore Passed: 19, Failed: 0 ~/.dotnet/dotnet build WxAgent.sln -c Release -p:EnableWindowsTargeting=true --no-restore Build succeeded. 0 Warning(s), 0 Error(s) -~/.dotnet/dotnet publish src/WxAgent.Host -c Release -r win-x64 --self-contained true \ +~/.dotnet/dotnet publish node-agent/WxAgent.Host -c Release -r win-x64 --self-contained true \ -p:EnableWindowsTargeting=true -p:PublishSingleFile=true -p:PublishTrimmed=false --no-restore Publish succeeded. ``` diff --git a/docs/validation/M5-Moments-Rich-Messages-2026-09-04.md b/docs/validation/M5-Moments-Rich-Messages-2026-09-04.md index e506bd5..527873a 100644 --- a/docs/validation/M5-Moments-Rich-Messages-2026-09-04.md +++ b/docs/validation/M5-Moments-Rich-Messages-2026-09-04.md @@ -20,13 +20,13 @@ ## Linux 验证 ```text -~/.dotnet/dotnet test tests/WxAgent.Core.Tests -c Release --no-restore +~/.dotnet/dotnet test tests/node-agent/WxAgent.Core.Tests -c Release --no-restore Passed: 30, Failed: 0 ~/.dotnet/dotnet build WxAgent.sln -c Release -p:EnableWindowsTargeting=true --no-restore Build succeeded. 0 Warning(s), 0 Error(s) -~/.dotnet/dotnet publish src/WxAgent.Host -c Release -r win-x64 --self-contained true \ +~/.dotnet/dotnet publish node-agent/WxAgent.Host -c Release -r win-x64 --self-contained true \ -p:EnableWindowsTargeting=true -p:PublishSingleFile=true -p:PublishTrimmed=false --no-restore Publish succeeded. ``` diff --git a/docs/validation/Review-Database-Management-Safety.md b/docs/validation/Review-Database-Management-Safety.md index 6d8d167..649876e 100644 --- a/docs/validation/Review-Database-Management-Safety.md +++ b/docs/validation/Review-Database-Management-Safety.md @@ -49,8 +49,8 @@ ```bash dotnet build WxAgent.sln -c Release -p:EnableWindowsTargeting=true --no-restore --verbosity minimal -dotnet test tests/WxAgent.Core.Tests -c Release --no-restore --verbosity minimal -python3 tests/check_contact_query.py +dotnet test tests/node-agent/WxAgent.Core.Tests -c Release --no-restore --verbosity minimal +python3 tests/node-agent/check_contact_query.py git diff --check ``` diff --git a/docs/validation/WebUI-MCP-2026-09-07.md b/docs/validation/WebUI-MCP-2026-09-07.md index 5e56d76..e56b744 100644 --- a/docs/validation/WebUI-MCP-2026-09-07.md +++ b/docs/validation/WebUI-MCP-2026-09-07.md @@ -37,8 +37,8 @@ ## 自动化证据 -- `dotnet test tests/WxAgent.Core.Tests -c Release`:153 passed。 -- `dotnet test tests/WxAgent.Service.Tests -c Release`:12 passed。 +- `dotnet test tests/node-agent/WxAgent.Core.Tests -c Release`:153 passed。 +- `dotnet test tests/node-agent/WxAgent.Service.Tests -c Release`:12 passed。 - `dotnet build WxAgent.sln -c Release -p:EnableWindowsTargeting=true`:成功,0 warning/0 error。 - self-contained `win-x64` publish:成功,包含 `wwwroot` 与 MCP 依赖。 diff --git a/src/WxAgent.Core/AccountBindingMatcher.cs b/node-agent/WxAgent.Core/AccountBindingMatcher.cs similarity index 100% rename from src/WxAgent.Core/AccountBindingMatcher.cs rename to node-agent/WxAgent.Core/AccountBindingMatcher.cs diff --git a/src/WxAgent.Core/ChatMessages.cs b/node-agent/WxAgent.Core/ChatMessages.cs similarity index 100% rename from src/WxAgent.Core/ChatMessages.cs rename to node-agent/WxAgent.Core/ChatMessages.cs diff --git a/src/WxAgent.Core/DatabaseModels.cs b/node-agent/WxAgent.Core/DatabaseModels.cs similarity index 100% rename from src/WxAgent.Core/DatabaseModels.cs rename to node-agent/WxAgent.Core/DatabaseModels.cs diff --git a/src/WxAgent.Core/InterprocessCommandGate.cs b/node-agent/WxAgent.Core/InterprocessCommandGate.cs similarity index 100% rename from src/WxAgent.Core/InterprocessCommandGate.cs rename to node-agent/WxAgent.Core/InterprocessCommandGate.cs diff --git a/src/WxAgent.Core/KeyCachePlanner.cs b/node-agent/WxAgent.Core/KeyCachePlanner.cs similarity index 100% rename from src/WxAgent.Core/KeyCachePlanner.cs rename to node-agent/WxAgent.Core/KeyCachePlanner.cs diff --git a/src/WxAgent.Core/MemoryPatternScanner.cs b/node-agent/WxAgent.Core/MemoryPatternScanner.cs similarity index 100% rename from src/WxAgent.Core/MemoryPatternScanner.cs rename to node-agent/WxAgent.Core/MemoryPatternScanner.cs diff --git a/src/WxAgent.Core/MessageEvents.cs b/node-agent/WxAgent.Core/MessageEvents.cs similarity index 100% rename from src/WxAgent.Core/MessageEvents.cs rename to node-agent/WxAgent.Core/MessageEvents.cs diff --git a/src/WxAgent.Core/SqlCipherPageVerifier.cs b/node-agent/WxAgent.Core/SqlCipherPageVerifier.cs similarity index 100% rename from src/WxAgent.Core/SqlCipherPageVerifier.cs rename to node-agent/WxAgent.Core/SqlCipherPageVerifier.cs diff --git a/src/WxAgent.Core/UiNodeSnapshot.cs b/node-agent/WxAgent.Core/UiNodeSnapshot.cs similarity index 100% rename from src/WxAgent.Core/UiNodeSnapshot.cs rename to node-agent/WxAgent.Core/UiNodeSnapshot.cs diff --git a/src/WxAgent.Core/UiSnapshotDiagnostics.cs b/node-agent/WxAgent.Core/UiSnapshotDiagnostics.cs similarity index 100% rename from src/WxAgent.Core/UiSnapshotDiagnostics.cs rename to node-agent/WxAgent.Core/UiSnapshotDiagnostics.cs diff --git a/src/WxAgent.Core/WcdbConfigCipher.cs b/node-agent/WxAgent.Core/WcdbConfigCipher.cs similarity index 100% rename from src/WxAgent.Core/WcdbConfigCipher.cs rename to node-agent/WxAgent.Core/WcdbConfigCipher.cs diff --git a/src/WxAgent.Core/WcdbKeyCandidateScanner.cs b/node-agent/WxAgent.Core/WcdbKeyCandidateScanner.cs similarity index 100% rename from src/WxAgent.Core/WcdbKeyCandidateScanner.cs rename to node-agent/WxAgent.Core/WcdbKeyCandidateScanner.cs diff --git a/src/WxAgent.Core/WechatContactQuery.cs b/node-agent/WxAgent.Core/WechatContactQuery.cs similarity index 100% rename from src/WxAgent.Core/WechatContactQuery.cs rename to node-agent/WxAgent.Core/WechatContactQuery.cs diff --git a/src/WxAgent.Core/WechatDbMessage.cs b/node-agent/WxAgent.Core/WechatDbMessage.cs similarity index 100% rename from src/WxAgent.Core/WechatDbMessage.cs rename to node-agent/WxAgent.Core/WechatDbMessage.cs diff --git a/src/WxAgent.Core/WechatDerivedText.cs b/node-agent/WxAgent.Core/WechatDerivedText.cs similarity index 100% rename from src/WxAgent.Core/WechatDerivedText.cs rename to node-agent/WxAgent.Core/WechatDerivedText.cs diff --git a/src/WxAgent.Core/WechatGroupMemberQuery.cs b/node-agent/WxAgent.Core/WechatGroupMemberQuery.cs similarity index 100% rename from src/WxAgent.Core/WechatGroupMemberQuery.cs rename to node-agent/WxAgent.Core/WechatGroupMemberQuery.cs diff --git a/src/WxAgent.Core/WechatLocators.cs b/node-agent/WxAgent.Core/WechatLocators.cs similarity index 100% rename from src/WxAgent.Core/WechatLocators.cs rename to node-agent/WxAgent.Core/WechatLocators.cs diff --git a/src/WxAgent.Core/WechatM5.cs b/node-agent/WxAgent.Core/WechatM5.cs similarity index 100% rename from src/WxAgent.Core/WechatM5.cs rename to node-agent/WxAgent.Core/WechatM5.cs diff --git a/src/WxAgent.Core/WechatManagement.cs b/node-agent/WxAgent.Core/WechatManagement.cs similarity index 100% rename from src/WxAgent.Core/WechatManagement.cs rename to node-agent/WxAgent.Core/WechatManagement.cs diff --git a/src/WxAgent.Core/WechatMergedChat.cs b/node-agent/WxAgent.Core/WechatMergedChat.cs similarity index 100% rename from src/WxAgent.Core/WechatMergedChat.cs rename to node-agent/WxAgent.Core/WechatMergedChat.cs diff --git a/src/WxAgent.Core/WechatNavigation.cs b/node-agent/WxAgent.Core/WechatNavigation.cs similarity index 100% rename from src/WxAgent.Core/WechatNavigation.cs rename to node-agent/WxAgent.Core/WechatNavigation.cs diff --git a/src/WxAgent.Core/WechatNoteWindow.cs b/node-agent/WxAgent.Core/WechatNoteWindow.cs similarity index 100% rename from src/WxAgent.Core/WechatNoteWindow.cs rename to node-agent/WxAgent.Core/WechatNoteWindow.cs diff --git a/src/WxAgent.Core/WechatSearchPage.cs b/node-agent/WxAgent.Core/WechatSearchPage.cs similarity index 100% rename from src/WxAgent.Core/WechatSearchPage.cs rename to node-agent/WxAgent.Core/WechatSearchPage.cs diff --git a/src/WxAgent.Core/WechatSendConfirmation.cs b/node-agent/WxAgent.Core/WechatSendConfirmation.cs similarity index 100% rename from src/WxAgent.Core/WechatSendConfirmation.cs rename to node-agent/WxAgent.Core/WechatSendConfirmation.cs diff --git a/src/WxAgent.Core/WechatSessions.cs b/node-agent/WxAgent.Core/WechatSessions.cs similarity index 100% rename from src/WxAgent.Core/WechatSessions.cs rename to node-agent/WxAgent.Core/WechatSessions.cs diff --git a/src/WxAgent.Core/WechatStability.cs b/node-agent/WxAgent.Core/WechatStability.cs similarity index 100% rename from src/WxAgent.Core/WechatStability.cs rename to node-agent/WxAgent.Core/WechatStability.cs diff --git a/src/WxAgent.Core/WechatTextInput.cs b/node-agent/WxAgent.Core/WechatTextInput.cs similarity index 100% rename from src/WxAgent.Core/WechatTextInput.cs rename to node-agent/WxAgent.Core/WechatTextInput.cs diff --git a/src/WxAgent.Core/WxAgent.Core.csproj b/node-agent/WxAgent.Core/WxAgent.Core.csproj similarity index 100% rename from src/WxAgent.Core/WxAgent.Core.csproj rename to node-agent/WxAgent.Core/WxAgent.Core.csproj diff --git a/src/WxAgent.Core/WxAgentErrorCode.cs b/node-agent/WxAgent.Core/WxAgentErrorCode.cs similarity index 100% rename from src/WxAgent.Core/WxAgentErrorCode.cs rename to node-agent/WxAgent.Core/WxAgentErrorCode.cs diff --git a/src/WxAgent.Host/Program.cs b/node-agent/WxAgent.Host/Program.cs similarity index 100% rename from src/WxAgent.Host/Program.cs rename to node-agent/WxAgent.Host/Program.cs diff --git a/src/WxAgent.Host/WindowsAgentBackend.cs b/node-agent/WxAgent.Host/WindowsAgentBackend.cs similarity index 100% rename from src/WxAgent.Host/WindowsAgentBackend.cs rename to node-agent/WxAgent.Host/WindowsAgentBackend.cs diff --git a/src/WxAgent.Host/WxAgent.Host.csproj b/node-agent/WxAgent.Host/WxAgent.Host.csproj similarity index 100% rename from src/WxAgent.Host/WxAgent.Host.csproj rename to node-agent/WxAgent.Host/WxAgent.Host.csproj diff --git a/src/WxAgent.Service/AccountBindingStore.cs b/node-agent/WxAgent.Service/AccountBindingStore.cs similarity index 100% rename from src/WxAgent.Service/AccountBindingStore.cs rename to node-agent/WxAgent.Service/AccountBindingStore.cs diff --git a/src/WxAgent.Service/AgentService.cs b/node-agent/WxAgent.Service/AgentService.cs similarity index 100% rename from src/WxAgent.Service/AgentService.cs rename to node-agent/WxAgent.Service/AgentService.cs diff --git a/src/WxAgent.Service/AgentTools.cs b/node-agent/WxAgent.Service/AgentTools.cs similarity index 100% rename from src/WxAgent.Service/AgentTools.cs rename to node-agent/WxAgent.Service/AgentTools.cs diff --git a/src/WxAgent.Service/ArtifactStore.cs b/node-agent/WxAgent.Service/ArtifactStore.cs similarity index 100% rename from src/WxAgent.Service/ArtifactStore.cs rename to node-agent/WxAgent.Service/ArtifactStore.cs diff --git a/src/WxAgent.Service/DatabaseMessageContracts.cs b/node-agent/WxAgent.Service/DatabaseMessageContracts.cs similarity index 100% rename from src/WxAgent.Service/DatabaseMessageContracts.cs rename to node-agent/WxAgent.Service/DatabaseMessageContracts.cs diff --git a/src/WxAgent.Service/DirectoryContracts.cs b/node-agent/WxAgent.Service/DirectoryContracts.cs similarity index 100% rename from src/WxAgent.Service/DirectoryContracts.cs rename to node-agent/WxAgent.Service/DirectoryContracts.cs diff --git a/src/WxAgent.Service/EventHub.cs b/node-agent/WxAgent.Service/EventHub.cs similarity index 100% rename from src/WxAgent.Service/EventHub.cs rename to node-agent/WxAgent.Service/EventHub.cs diff --git a/src/WxAgent.Service/EventPump.cs b/node-agent/WxAgent.Service/EventPump.cs similarity index 100% rename from src/WxAgent.Service/EventPump.cs rename to node-agent/WxAgent.Service/EventPump.cs diff --git a/src/WxAgent.Service/OperationQueue.cs b/node-agent/WxAgent.Service/OperationQueue.cs similarity index 100% rename from src/WxAgent.Service/OperationQueue.cs rename to node-agent/WxAgent.Service/OperationQueue.cs diff --git a/src/WxAgent.Service/OperationStore.cs b/node-agent/WxAgent.Service/OperationStore.cs similarity index 100% rename from src/WxAgent.Service/OperationStore.cs rename to node-agent/WxAgent.Service/OperationStore.cs diff --git a/src/WxAgent.Service/ReadOnlyContracts.cs b/node-agent/WxAgent.Service/ReadOnlyContracts.cs similarity index 100% rename from src/WxAgent.Service/ReadOnlyContracts.cs rename to node-agent/WxAgent.Service/ReadOnlyContracts.cs diff --git a/src/WxAgent.Service/RuntimeLog.cs b/node-agent/WxAgent.Service/RuntimeLog.cs similarity index 100% rename from src/WxAgent.Service/RuntimeLog.cs rename to node-agent/WxAgent.Service/RuntimeLog.cs diff --git a/src/WxAgent.Service/ServiceHost.cs b/node-agent/WxAgent.Service/ServiceHost.cs similarity index 100% rename from src/WxAgent.Service/ServiceHost.cs rename to node-agent/WxAgent.Service/ServiceHost.cs diff --git a/src/WxAgent.Service/ServiceOptions.cs b/node-agent/WxAgent.Service/ServiceOptions.cs similarity index 100% rename from src/WxAgent.Service/ServiceOptions.cs rename to node-agent/WxAgent.Service/ServiceOptions.cs diff --git a/src/WxAgent.Service/ServiceSecurity.cs b/node-agent/WxAgent.Service/ServiceSecurity.cs similarity index 100% rename from src/WxAgent.Service/ServiceSecurity.cs rename to node-agent/WxAgent.Service/ServiceSecurity.cs diff --git a/src/WxAgent.Service/SessionContracts.cs b/node-agent/WxAgent.Service/SessionContracts.cs similarity index 100% rename from src/WxAgent.Service/SessionContracts.cs rename to node-agent/WxAgent.Service/SessionContracts.cs diff --git a/src/WxAgent.Service/WxAgent.Service.csproj b/node-agent/WxAgent.Service/WxAgent.Service.csproj similarity index 100% rename from src/WxAgent.Service/WxAgent.Service.csproj rename to node-agent/WxAgent.Service/WxAgent.Service.csproj diff --git a/src/WxAgent.Service/wwwroot/app.js b/node-agent/WxAgent.Service/wwwroot/app.js similarity index 100% rename from src/WxAgent.Service/wwwroot/app.js rename to node-agent/WxAgent.Service/wwwroot/app.js diff --git a/src/WxAgent.Service/wwwroot/index.html b/node-agent/WxAgent.Service/wwwroot/index.html similarity index 100% rename from src/WxAgent.Service/wwwroot/index.html rename to node-agent/WxAgent.Service/wwwroot/index.html diff --git a/src/WxAgent.Service/wwwroot/styles.css b/node-agent/WxAgent.Service/wwwroot/styles.css similarity index 100% rename from src/WxAgent.Service/wwwroot/styles.css rename to node-agent/WxAgent.Service/wwwroot/styles.css diff --git a/src/WxAgent.Tray/Program.cs b/node-agent/WxAgent.Tray/Program.cs similarity index 100% rename from src/WxAgent.Tray/Program.cs rename to node-agent/WxAgent.Tray/Program.cs diff --git a/src/WxAgent.Tray/WxAgent.Tray.csproj b/node-agent/WxAgent.Tray/WxAgent.Tray.csproj similarity index 100% rename from src/WxAgent.Tray/WxAgent.Tray.csproj rename to node-agent/WxAgent.Tray/WxAgent.Tray.csproj diff --git a/src/WxAgent.Tray/wxagent.ico b/node-agent/WxAgent.Tray/wxagent.ico similarity index 100% rename from src/WxAgent.Tray/wxagent.ico rename to node-agent/WxAgent.Tray/wxagent.ico diff --git a/src/WxAgent.Windows/DatabaseKeyStore.cs b/node-agent/WxAgent.Windows/DatabaseKeyStore.cs similarity index 100% rename from src/WxAgent.Windows/DatabaseKeyStore.cs rename to node-agent/WxAgent.Windows/DatabaseKeyStore.cs diff --git a/src/WxAgent.Windows/ListenerCheckpointStore.cs b/node-agent/WxAgent.Windows/ListenerCheckpointStore.cs similarity index 100% rename from src/WxAgent.Windows/ListenerCheckpointStore.cs rename to node-agent/WxAgent.Windows/ListenerCheckpointStore.cs diff --git a/src/WxAgent.Windows/NativeMethods.txt b/node-agent/WxAgent.Windows/NativeMethods.txt similarity index 100% rename from src/WxAgent.Windows/NativeMethods.txt rename to node-agent/WxAgent.Windows/NativeMethods.txt diff --git a/src/WxAgent.Windows/ProcessMemoryScanner.cs b/node-agent/WxAgent.Windows/ProcessMemoryScanner.cs similarity index 100% rename from src/WxAgent.Windows/ProcessMemoryScanner.cs rename to node-agent/WxAgent.Windows/ProcessMemoryScanner.cs diff --git a/src/WxAgent.Windows/SqlCipherDatabaseReader.cs b/node-agent/WxAgent.Windows/SqlCipherDatabaseReader.cs similarity index 100% rename from src/WxAgent.Windows/SqlCipherDatabaseReader.cs rename to node-agent/WxAgent.Windows/SqlCipherDatabaseReader.cs diff --git a/src/WxAgent.Windows/WechatChatClient.Listening.cs b/node-agent/WxAgent.Windows/WechatChatClient.Listening.cs similarity index 100% rename from src/WxAgent.Windows/WechatChatClient.Listening.cs rename to node-agent/WxAgent.Windows/WechatChatClient.Listening.cs diff --git a/src/WxAgent.Windows/WechatChatClient.M5.cs b/node-agent/WxAgent.Windows/WechatChatClient.M5.cs similarity index 100% rename from src/WxAgent.Windows/WechatChatClient.M5.cs rename to node-agent/WxAgent.Windows/WechatChatClient.M5.cs diff --git a/src/WxAgent.Windows/WechatChatClient.Management.cs b/node-agent/WxAgent.Windows/WechatChatClient.Management.cs similarity index 100% rename from src/WxAgent.Windows/WechatChatClient.Management.cs rename to node-agent/WxAgent.Windows/WechatChatClient.Management.cs diff --git a/src/WxAgent.Windows/WechatChatClient.Navigation.cs b/node-agent/WxAgent.Windows/WechatChatClient.Navigation.cs similarity index 100% rename from src/WxAgent.Windows/WechatChatClient.Navigation.cs rename to node-agent/WxAgent.Windows/WechatChatClient.Navigation.cs diff --git a/src/WxAgent.Windows/WechatChatClient.Search.cs b/node-agent/WxAgent.Windows/WechatChatClient.Search.cs similarity index 100% rename from src/WxAgent.Windows/WechatChatClient.Search.cs rename to node-agent/WxAgent.Windows/WechatChatClient.Search.cs diff --git a/src/WxAgent.Windows/WechatChatClient.cs b/node-agent/WxAgent.Windows/WechatChatClient.cs similarity index 100% rename from src/WxAgent.Windows/WechatChatClient.cs rename to node-agent/WxAgent.Windows/WechatChatClient.cs diff --git a/src/WxAgent.Windows/WechatContactDbReader.cs b/node-agent/WxAgent.Windows/WechatContactDbReader.cs similarity index 100% rename from src/WxAgent.Windows/WechatContactDbReader.cs rename to node-agent/WxAgent.Windows/WechatContactDbReader.cs diff --git a/src/WxAgent.Windows/WechatDatabaseDiscovery.cs b/node-agent/WxAgent.Windows/WechatDatabaseDiscovery.cs similarity index 100% rename from src/WxAgent.Windows/WechatDatabaseDiscovery.cs rename to node-agent/WxAgent.Windows/WechatDatabaseDiscovery.cs diff --git a/src/WxAgent.Windows/WechatDatabaseScanner.cs b/node-agent/WxAgent.Windows/WechatDatabaseScanner.cs similarity index 100% rename from src/WxAgent.Windows/WechatDatabaseScanner.cs rename to node-agent/WxAgent.Windows/WechatDatabaseScanner.cs diff --git a/src/WxAgent.Windows/WechatDesktop.cs b/node-agent/WxAgent.Windows/WechatDesktop.cs similarity index 100% rename from src/WxAgent.Windows/WechatDesktop.cs rename to node-agent/WxAgent.Windows/WechatDesktop.cs diff --git a/src/WxAgent.Windows/WechatDoctor.cs b/node-agent/WxAgent.Windows/WechatDoctor.cs similarity index 100% rename from src/WxAgent.Windows/WechatDoctor.cs rename to node-agent/WxAgent.Windows/WechatDoctor.cs diff --git a/src/WxAgent.Windows/WechatListenerSmoke.cs b/node-agent/WxAgent.Windows/WechatListenerSmoke.cs similarity index 100% rename from src/WxAgent.Windows/WechatListenerSmoke.cs rename to node-agent/WxAgent.Windows/WechatListenerSmoke.cs diff --git a/src/WxAgent.Windows/WechatMessageDbReader.cs b/node-agent/WxAgent.Windows/WechatMessageDbReader.cs similarity index 100% rename from src/WxAgent.Windows/WechatMessageDbReader.cs rename to node-agent/WxAgent.Windows/WechatMessageDbReader.cs diff --git a/src/WxAgent.Windows/WechatNativeWindow.cs b/node-agent/WxAgent.Windows/WechatNativeWindow.cs similarity index 100% rename from src/WxAgent.Windows/WechatNativeWindow.cs rename to node-agent/WxAgent.Windows/WechatNativeWindow.cs diff --git a/src/WxAgent.Windows/WechatRecoverySmoke.cs b/node-agent/WxAgent.Windows/WechatRecoverySmoke.cs similarity index 100% rename from src/WxAgent.Windows/WechatRecoverySmoke.cs rename to node-agent/WxAgent.Windows/WechatRecoverySmoke.cs diff --git a/src/WxAgent.Windows/WechatStabilityRunner.cs b/node-agent/WxAgent.Windows/WechatStabilityRunner.cs similarity index 100% rename from src/WxAgent.Windows/WechatStabilityRunner.cs rename to node-agent/WxAgent.Windows/WechatStabilityRunner.cs diff --git a/src/WxAgent.Windows/WechatTray.cs b/node-agent/WxAgent.Windows/WechatTray.cs similarity index 100% rename from src/WxAgent.Windows/WechatTray.cs rename to node-agent/WxAgent.Windows/WechatTray.cs diff --git a/src/WxAgent.Windows/WechatUiInspector.cs b/node-agent/WxAgent.Windows/WechatUiInspector.cs similarity index 100% rename from src/WxAgent.Windows/WechatUiInspector.cs rename to node-agent/WxAgent.Windows/WechatUiInspector.cs diff --git a/src/WxAgent.Windows/WxAgent.Windows.csproj b/node-agent/WxAgent.Windows/WxAgent.Windows.csproj similarity index 100% rename from src/WxAgent.Windows/WxAgent.Windows.csproj rename to node-agent/WxAgent.Windows/WxAgent.Windows.csproj diff --git a/tests/WxAgent.Core.Tests/AccountBindingMatcherTests.cs b/tests/node-agent/WxAgent.Core.Tests/AccountBindingMatcherTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/AccountBindingMatcherTests.cs rename to tests/node-agent/WxAgent.Core.Tests/AccountBindingMatcherTests.cs diff --git a/tests/WxAgent.Core.Tests/CoreTests.cs b/tests/node-agent/WxAgent.Core.Tests/CoreTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/CoreTests.cs rename to tests/node-agent/WxAgent.Core.Tests/CoreTests.cs diff --git a/tests/WxAgent.Core.Tests/InterprocessCommandGateTests.cs b/tests/node-agent/WxAgent.Core.Tests/InterprocessCommandGateTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/InterprocessCommandGateTests.cs rename to tests/node-agent/WxAgent.Core.Tests/InterprocessCommandGateTests.cs diff --git a/tests/WxAgent.Core.Tests/KeyCachePlannerTests.cs b/tests/node-agent/WxAgent.Core.Tests/KeyCachePlannerTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/KeyCachePlannerTests.cs rename to tests/node-agent/WxAgent.Core.Tests/KeyCachePlannerTests.cs diff --git a/tests/WxAgent.Core.Tests/MemoryScanningTests.cs b/tests/node-agent/WxAgent.Core.Tests/MemoryScanningTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/MemoryScanningTests.cs rename to tests/node-agent/WxAgent.Core.Tests/MemoryScanningTests.cs diff --git a/tests/WxAgent.Core.Tests/UiDiagnosticsTests.cs b/tests/node-agent/WxAgent.Core.Tests/UiDiagnosticsTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/UiDiagnosticsTests.cs rename to tests/node-agent/WxAgent.Core.Tests/UiDiagnosticsTests.cs diff --git a/tests/WxAgent.Core.Tests/WechatContactQueryTests.cs b/tests/node-agent/WxAgent.Core.Tests/WechatContactQueryTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/WechatContactQueryTests.cs rename to tests/node-agent/WxAgent.Core.Tests/WechatContactQueryTests.cs diff --git a/tests/WxAgent.Core.Tests/WechatDbMessageTests.cs b/tests/node-agent/WxAgent.Core.Tests/WechatDbMessageTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/WechatDbMessageTests.cs rename to tests/node-agent/WxAgent.Core.Tests/WechatDbMessageTests.cs diff --git a/tests/WxAgent.Core.Tests/WechatDerivedTextTests.cs b/tests/node-agent/WxAgent.Core.Tests/WechatDerivedTextTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/WechatDerivedTextTests.cs rename to tests/node-agent/WxAgent.Core.Tests/WechatDerivedTextTests.cs diff --git a/tests/WxAgent.Core.Tests/WechatGroupMemberQueryTests.cs b/tests/node-agent/WxAgent.Core.Tests/WechatGroupMemberQueryTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/WechatGroupMemberQueryTests.cs rename to tests/node-agent/WxAgent.Core.Tests/WechatGroupMemberQueryTests.cs diff --git a/tests/WxAgent.Core.Tests/WechatM5Tests.cs b/tests/node-agent/WxAgent.Core.Tests/WechatM5Tests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/WechatM5Tests.cs rename to tests/node-agent/WxAgent.Core.Tests/WechatM5Tests.cs diff --git a/tests/WxAgent.Core.Tests/WechatManagementTests.cs b/tests/node-agent/WxAgent.Core.Tests/WechatManagementTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/WechatManagementTests.cs rename to tests/node-agent/WxAgent.Core.Tests/WechatManagementTests.cs diff --git a/tests/WxAgent.Core.Tests/WechatMentionConfirmationTests.cs b/tests/node-agent/WxAgent.Core.Tests/WechatMentionConfirmationTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/WechatMentionConfirmationTests.cs rename to tests/node-agent/WxAgent.Core.Tests/WechatMentionConfirmationTests.cs diff --git a/tests/WxAgent.Core.Tests/WechatMergedChatTests.cs b/tests/node-agent/WxAgent.Core.Tests/WechatMergedChatTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/WechatMergedChatTests.cs rename to tests/node-agent/WxAgent.Core.Tests/WechatMergedChatTests.cs diff --git a/tests/WxAgent.Core.Tests/WechatNavigationTests.cs b/tests/node-agent/WxAgent.Core.Tests/WechatNavigationTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/WechatNavigationTests.cs rename to tests/node-agent/WxAgent.Core.Tests/WechatNavigationTests.cs diff --git a/tests/WxAgent.Core.Tests/WechatNoteWindowTests.cs b/tests/node-agent/WxAgent.Core.Tests/WechatNoteWindowTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/WechatNoteWindowTests.cs rename to tests/node-agent/WxAgent.Core.Tests/WechatNoteWindowTests.cs diff --git a/tests/WxAgent.Core.Tests/WechatSearchRulesTests.cs b/tests/node-agent/WxAgent.Core.Tests/WechatSearchRulesTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/WechatSearchRulesTests.cs rename to tests/node-agent/WxAgent.Core.Tests/WechatSearchRulesTests.cs diff --git a/tests/WxAgent.Core.Tests/WechatSendConfirmationTests.cs b/tests/node-agent/WxAgent.Core.Tests/WechatSendConfirmationTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/WechatSendConfirmationTests.cs rename to tests/node-agent/WxAgent.Core.Tests/WechatSendConfirmationTests.cs diff --git a/tests/WxAgent.Core.Tests/WechatStabilityTests.cs b/tests/node-agent/WxAgent.Core.Tests/WechatStabilityTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/WechatStabilityTests.cs rename to tests/node-agent/WxAgent.Core.Tests/WechatStabilityTests.cs diff --git a/tests/WxAgent.Core.Tests/WechatTextInputTests.cs b/tests/node-agent/WxAgent.Core.Tests/WechatTextInputTests.cs similarity index 100% rename from tests/WxAgent.Core.Tests/WechatTextInputTests.cs rename to tests/node-agent/WxAgent.Core.Tests/WechatTextInputTests.cs diff --git a/tests/WxAgent.Core.Tests/WxAgent.Core.Tests.csproj b/tests/node-agent/WxAgent.Core.Tests/WxAgent.Core.Tests.csproj similarity index 88% rename from tests/WxAgent.Core.Tests/WxAgent.Core.Tests.csproj rename to tests/node-agent/WxAgent.Core.Tests/WxAgent.Core.Tests.csproj index c8ddb60..799d12b 100644 --- a/tests/WxAgent.Core.Tests/WxAgent.Core.Tests.csproj +++ b/tests/node-agent/WxAgent.Core.Tests/WxAgent.Core.Tests.csproj @@ -13,6 +13,6 @@ - + diff --git a/tests/WxAgent.Service.Tests/AccountBindingStoreTests.cs b/tests/node-agent/WxAgent.Service.Tests/AccountBindingStoreTests.cs similarity index 100% rename from tests/WxAgent.Service.Tests/AccountBindingStoreTests.cs rename to tests/node-agent/WxAgent.Service.Tests/AccountBindingStoreTests.cs diff --git a/tests/WxAgent.Service.Tests/ArtifactStoreTests.cs b/tests/node-agent/WxAgent.Service.Tests/ArtifactStoreTests.cs similarity index 100% rename from tests/WxAgent.Service.Tests/ArtifactStoreTests.cs rename to tests/node-agent/WxAgent.Service.Tests/ArtifactStoreTests.cs diff --git a/tests/WxAgent.Service.Tests/EventHubTests.cs b/tests/node-agent/WxAgent.Service.Tests/EventHubTests.cs similarity index 100% rename from tests/WxAgent.Service.Tests/EventHubTests.cs rename to tests/node-agent/WxAgent.Service.Tests/EventHubTests.cs diff --git a/tests/WxAgent.Service.Tests/EventPumpTests.cs b/tests/node-agent/WxAgent.Service.Tests/EventPumpTests.cs similarity index 100% rename from tests/WxAgent.Service.Tests/EventPumpTests.cs rename to tests/node-agent/WxAgent.Service.Tests/EventPumpTests.cs diff --git a/tests/WxAgent.Service.Tests/OperationQueueTests.cs b/tests/node-agent/WxAgent.Service.Tests/OperationQueueTests.cs similarity index 100% rename from tests/WxAgent.Service.Tests/OperationQueueTests.cs rename to tests/node-agent/WxAgent.Service.Tests/OperationQueueTests.cs diff --git a/tests/WxAgent.Service.Tests/OperationStoreTests.cs b/tests/node-agent/WxAgent.Service.Tests/OperationStoreTests.cs similarity index 100% rename from tests/WxAgent.Service.Tests/OperationStoreTests.cs rename to tests/node-agent/WxAgent.Service.Tests/OperationStoreTests.cs diff --git a/tests/WxAgent.Service.Tests/ServiceBoundaryTests.cs b/tests/node-agent/WxAgent.Service.Tests/ServiceBoundaryTests.cs similarity index 100% rename from tests/WxAgent.Service.Tests/ServiceBoundaryTests.cs rename to tests/node-agent/WxAgent.Service.Tests/ServiceBoundaryTests.cs diff --git a/tests/WxAgent.Service.Tests/ServiceTests.cs b/tests/node-agent/WxAgent.Service.Tests/ServiceTests.cs similarity index 100% rename from tests/WxAgent.Service.Tests/ServiceTests.cs rename to tests/node-agent/WxAgent.Service.Tests/ServiceTests.cs diff --git a/tests/WxAgent.Service.Tests/SessionTests.cs b/tests/node-agent/WxAgent.Service.Tests/SessionTests.cs similarity index 100% rename from tests/WxAgent.Service.Tests/SessionTests.cs rename to tests/node-agent/WxAgent.Service.Tests/SessionTests.cs diff --git a/tests/WxAgent.Service.Tests/SseTests.cs b/tests/node-agent/WxAgent.Service.Tests/SseTests.cs similarity index 100% rename from tests/WxAgent.Service.Tests/SseTests.cs rename to tests/node-agent/WxAgent.Service.Tests/SseTests.cs diff --git a/tests/WxAgent.Service.Tests/WxAgent.Service.Tests.csproj b/tests/node-agent/WxAgent.Service.Tests/WxAgent.Service.Tests.csproj similarity index 86% rename from tests/WxAgent.Service.Tests/WxAgent.Service.Tests.csproj rename to tests/node-agent/WxAgent.Service.Tests/WxAgent.Service.Tests.csproj index 399d42d..9b05f0a 100644 --- a/tests/WxAgent.Service.Tests/WxAgent.Service.Tests.csproj +++ b/tests/node-agent/WxAgent.Service.Tests/WxAgent.Service.Tests.csproj @@ -5,6 +5,6 @@ - + diff --git a/tests/check_contact_query.py b/tests/node-agent/check_contact_query.py similarity index 83% rename from tests/check_contact_query.py rename to tests/node-agent/check_contact_query.py index f7c3fd3..beb8c57 100644 --- a/tests/check_contact_query.py +++ b/tests/node-agent/check_contact_query.py @@ -5,24 +5,24 @@ import sqlite3 from pathlib import Path source = ( - Path(__file__).resolve().parents[1] / "src/WxAgent.Core/WechatContactQuery.cs" + Path(__file__).resolve().parents[2] / "node-agent/WxAgent.Core/WechatContactQuery.cs" ).read_text() match = re.search(r'public const string Sql = """\s*(.*?)\s*""";', source, re.S) assert match is not None sql = match.group(1) -with sqlite3.connect(":memory:") as db: - db.execute( +with sqlite3.connect(":memory:") as connection: + connection.execute( "CREATE TABLE contact(username TEXT PRIMARY KEY, nick_name TEXT, remark TEXT, small_head_url TEXT)" ) - db.executemany( + connection.executemany( "INSERT INTO contact VALUES (?, ?, ?, NULL)", [(f"wxid_{i:04}", "same display name", None) for i in range(501)] + [("room@chatroom", "group", None), ("literal", "O'Brien_%", None)], ) def query(limit=201, offset=0, contains=None, groups=None): - return db.execute( + return connection.execute( sql, {"limit": limit, "offset": offset, "contains": contains, "groups": groups} ).fetchall() @@ -38,7 +38,7 @@ with sqlite3.connect(":memory:") as db: assert len(query(limit=10000, groups=0)) == 502 assert len(query(limit=10000, contains="same display name")) == 501 assert query(offset=503) == [] - assert db.execute("SELECT count(*) FROM contact").fetchone()[0] == 503 + assert connection.execute("SELECT count(*) FROM contact").fetchone()[0] == 503 print( "contact SQL: pagination, duplicate names, literal filtering and group filtering passed"