@web-auto/webauto 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/apps/desktop-console/default-settings.json +1 -0
  2. package/apps/desktop-console/dist/main/index.mjs +1618 -0
  3. package/apps/desktop-console/{src → dist}/main/preload.mjs +10 -0
  4. package/apps/desktop-console/dist/renderer/index.js +3063 -0
  5. package/apps/desktop-console/entry/ui-console.mjs +299 -0
  6. package/apps/webauto/entry/account.mjs +356 -0
  7. package/apps/webauto/entry/lib/account-detect.mjs +160 -0
  8. package/apps/webauto/entry/lib/account-store.mjs +587 -0
  9. package/apps/webauto/entry/lib/profilepool.mjs +1 -1
  10. package/apps/webauto/entry/xhs-install.mjs +27 -3
  11. package/apps/webauto/entry/xhs-status.mjs +152 -0
  12. package/apps/webauto/entry/xhs-unified.mjs +595 -17
  13. package/bin/webauto.mjs +263 -15
  14. package/dist/apps/webauto/server.js +66 -0
  15. package/dist/modules/camo-backend/src/index.js +575 -0
  16. package/dist/modules/camo-backend/src/internal/BrowserSession.js +817 -0
  17. package/dist/modules/camo-backend/src/internal/ElementRegistry.js +61 -0
  18. package/dist/modules/camo-backend/src/internal/ProfileLock.js +85 -0
  19. package/dist/modules/camo-backend/src/internal/SessionManager.js +172 -0
  20. package/dist/modules/camo-backend/src/internal/container-matcher.js +852 -0
  21. package/dist/modules/camo-backend/src/internal/engine-manager.js +258 -0
  22. package/dist/modules/camo-backend/src/internal/fingerprint.js +203 -0
  23. package/dist/modules/camo-backend/src/internal/pageRuntime.js +29 -0
  24. package/dist/modules/camo-backend/src/internal/runtimeInjector.js +30 -0
  25. package/dist/modules/camo-backend/src/internal/state-bus.js +46 -0
  26. package/dist/modules/camo-backend/src/internal/storage-paths.js +36 -0
  27. package/dist/modules/camo-backend/src/internal/ws-server.js +1202 -0
  28. package/dist/modules/camo-runtime/src/utils/browser-service.mjs +423 -0
  29. package/dist/modules/camo-runtime/src/utils/config.mjs +77 -0
  30. package/dist/modules/container-registry/src/index.js +184 -0
  31. package/dist/modules/logging/src/index.js +92 -0
  32. package/dist/modules/operations/src/builtin.js +27 -0
  33. package/dist/modules/operations/src/container-binding.js +75 -0
  34. package/dist/modules/operations/src/executor.js +146 -0
  35. package/dist/modules/operations/src/operations/click.js +167 -0
  36. package/dist/modules/operations/src/operations/extract.js +204 -0
  37. package/dist/modules/operations/src/operations/find-child.js +17 -0
  38. package/dist/modules/operations/src/operations/highlight.js +138 -0
  39. package/dist/modules/operations/src/operations/key.js +61 -0
  40. package/dist/modules/operations/src/operations/navigate.js +148 -0
  41. package/dist/modules/operations/src/operations/scroll.js +126 -0
  42. package/dist/modules/operations/src/operations/type.js +190 -0
  43. package/dist/modules/operations/src/queue.js +100 -0
  44. package/dist/modules/operations/src/registry.js +11 -0
  45. package/dist/modules/operations/src/system/mouse.js +33 -0
  46. package/dist/modules/state/src/atomic-json.js +33 -0
  47. package/dist/modules/workflow/blocks/AnchorVerificationBlock.js +71 -0
  48. package/dist/modules/workflow/blocks/BehaviorRandomizer.js +26 -0
  49. package/dist/modules/workflow/blocks/CallWorkflowBlock.js +38 -0
  50. package/dist/modules/workflow/blocks/CloseDetailBlock.js +209 -0
  51. package/dist/modules/workflow/blocks/CollectBatch.js +137 -0
  52. package/dist/modules/workflow/blocks/CollectCommentsBlock.js +415 -0
  53. package/dist/modules/workflow/blocks/CollectSearchListBlock.js +599 -0
  54. package/dist/modules/workflow/blocks/CollectWeiboPosts.js +229 -0
  55. package/dist/modules/workflow/blocks/DetectPageStateBlock.js +259 -0
  56. package/dist/modules/workflow/blocks/EnsureLoginBlock.js +162 -0
  57. package/dist/modules/workflow/blocks/EnsureSession.js +426 -0
  58. package/dist/modules/workflow/blocks/ErrorClassifier.js +164 -0
  59. package/dist/modules/workflow/blocks/ErrorRecoveryBlock.js +319 -0
  60. package/dist/modules/workflow/blocks/ExpandCommentsBlock.js +1032 -0
  61. package/dist/modules/workflow/blocks/ExtractDetailBlock.js +310 -0
  62. package/dist/modules/workflow/blocks/ExtractPostFields.js +88 -0
  63. package/dist/modules/workflow/blocks/GenerateSmartReplyBlock.js +68 -0
  64. package/dist/modules/workflow/blocks/GoToSearchBlock.js +497 -0
  65. package/dist/modules/workflow/blocks/GracefulFallbackBlock.js +104 -0
  66. package/dist/modules/workflow/blocks/HighlightBlock.js +66 -0
  67. package/dist/modules/workflow/blocks/InitAutoScroll.js +65 -0
  68. package/dist/modules/workflow/blocks/LoadContainerDefinition.js +50 -0
  69. package/dist/modules/workflow/blocks/LoadContainerIndex.js +43 -0
  70. package/dist/modules/workflow/blocks/LocateAndGuardBlock.js +176 -0
  71. package/dist/modules/workflow/blocks/LoginRecoveryBlock.js +242 -0
  72. package/dist/modules/workflow/blocks/MatchContainers.js +64 -0
  73. package/dist/modules/workflow/blocks/MonitoringBlock.js +190 -0
  74. package/dist/modules/workflow/blocks/OpenDetailBlock.js +1240 -0
  75. package/dist/modules/workflow/blocks/OrganizeXhsNotesBlock.js +117 -0
  76. package/dist/modules/workflow/blocks/PersistXhsNoteBlock.js +270 -0
  77. package/dist/modules/workflow/blocks/PickSinglePost.js +69 -0
  78. package/dist/modules/workflow/blocks/ProgressTracker.js +125 -0
  79. package/dist/modules/workflow/blocks/RecordFixtureBlock.js +44 -0
  80. package/dist/modules/workflow/blocks/RenderMarkdown.js +48 -0
  81. package/dist/modules/workflow/blocks/SaveFile.js +54 -0
  82. package/dist/modules/workflow/blocks/ScrollNextBatch.js +72 -0
  83. package/dist/modules/workflow/blocks/SessionHealthBlock.js +73 -0
  84. package/dist/modules/workflow/blocks/StartBrowserService.js +45 -0
  85. package/dist/modules/workflow/blocks/ValidateContainerDefinition.js +67 -0
  86. package/dist/modules/workflow/blocks/ValidateExtract.js +35 -0
  87. package/dist/modules/workflow/blocks/WaitSearchPermitBlock.js +162 -0
  88. package/dist/modules/workflow/blocks/WaitStable.js +74 -0
  89. package/dist/modules/workflow/blocks/WarmupCommentsBlock.js +120 -0
  90. package/dist/modules/workflow/blocks/WorkflowExecutor.js +156 -0
  91. package/dist/modules/workflow/blocks/XiaohongshuCollectFromLinksBlock.js +1004 -0
  92. package/dist/modules/workflow/blocks/XiaohongshuCollectLinksBlock.js +1049 -0
  93. package/dist/modules/workflow/blocks/XiaohongshuFullCollectBlock.js +782 -0
  94. package/dist/modules/workflow/blocks/helpers/anchorVerify.js +198 -0
  95. package/dist/modules/workflow/blocks/helpers/asyncWorkQueue.js +53 -0
  96. package/dist/modules/workflow/blocks/helpers/commentScroller.js +334 -0
  97. package/dist/modules/workflow/blocks/helpers/commentSectionLocator.js +126 -0
  98. package/dist/modules/workflow/blocks/helpers/containerAnchors.js +301 -0
  99. package/dist/modules/workflow/blocks/helpers/debugArtifacts.js +6 -0
  100. package/dist/modules/workflow/blocks/helpers/downloadPaths.js +29 -0
  101. package/dist/modules/workflow/blocks/helpers/expandCommentsController.js +53 -0
  102. package/dist/modules/workflow/blocks/helpers/expandCommentsExtractor.js +129 -0
  103. package/dist/modules/workflow/blocks/helpers/macosVisionOcrPlugin.js +116 -0
  104. package/dist/modules/workflow/blocks/helpers/mergeXhsMarkdown.js +109 -0
  105. package/dist/modules/workflow/blocks/helpers/openDetailController.js +56 -0
  106. package/dist/modules/workflow/blocks/helpers/openDetailTypes.js +7 -0
  107. package/dist/modules/workflow/blocks/helpers/openDetailViewport.js +474 -0
  108. package/dist/modules/workflow/blocks/helpers/openDetailWaiter.js +104 -0
  109. package/dist/modules/workflow/blocks/helpers/operationLogger.js +195 -0
  110. package/dist/modules/workflow/blocks/helpers/persistedNotes.js +107 -0
  111. package/dist/modules/workflow/blocks/helpers/replyExpander.js +260 -0
  112. package/dist/modules/workflow/blocks/helpers/scrollIntoView.js +138 -0
  113. package/dist/modules/workflow/blocks/helpers/searchExecutor.js +328 -0
  114. package/dist/modules/workflow/blocks/helpers/searchGate.js +46 -0
  115. package/dist/modules/workflow/blocks/helpers/searchPageState.js +164 -0
  116. package/dist/modules/workflow/blocks/helpers/searchResultWaiter.js +64 -0
  117. package/dist/modules/workflow/blocks/helpers/simpleAnchor.js +134 -0
  118. package/dist/modules/workflow/blocks/helpers/smartReply.js +40 -0
  119. package/dist/modules/workflow/blocks/helpers/systemInput.js +635 -0
  120. package/dist/modules/workflow/blocks/helpers/targetCountMode.js +9 -0
  121. package/dist/modules/workflow/blocks/helpers/xhsCliArgs.js +80 -0
  122. package/dist/modules/workflow/blocks/helpers/xhsCommentDom.js +805 -0
  123. package/dist/modules/workflow/blocks/helpers/xhsNoteOrganizer.js +140 -0
  124. package/dist/modules/workflow/blocks/restore/RestorePhaseBlock.js +204 -0
  125. package/dist/modules/workflow/config/workflowRegistry.js +32 -0
  126. package/dist/modules/workflow/definitions/batch-collect-workflow.js +63 -0
  127. package/dist/modules/workflow/definitions/scroll-extract-workflow.js +74 -0
  128. package/dist/modules/workflow/definitions/xiaohongshu-collect-workflow-v2.js +81 -0
  129. package/dist/modules/workflow/definitions/xiaohongshu-collect-workflow.js +57 -0
  130. package/dist/modules/workflow/definitions/xiaohongshu-full-collect-workflow-v3.js +68 -0
  131. package/dist/modules/workflow/definitions/xiaohongshu-note-collect.js +49 -0
  132. package/dist/modules/workflow/definitions/xiaohongshu-phase1-workflow-v3.js +30 -0
  133. package/dist/modules/workflow/definitions/xiaohongshu-phase2-links-workflow-v3.js +40 -0
  134. package/dist/modules/workflow/definitions/xiaohongshu-phase3-collect-workflow-v1.js +54 -0
  135. package/dist/modules/workflow/definitions/xiaohongshu-phase34-from-links-workflow-v3.js +25 -0
  136. package/dist/modules/workflow/src/WeiboEventDrivenWorkflowRunner.js +308 -0
  137. package/dist/modules/workflow/src/context.js +70 -0
  138. package/dist/modules/workflow/src/index.js +5 -0
  139. package/dist/modules/workflow/src/orchestrator.js +230 -0
  140. package/dist/modules/workflow/src/runner.js +55 -0
  141. package/dist/modules/workflow/src/runtime.js +70 -0
  142. package/dist/modules/workflow/workflows/WeiboFeedExtractionWorkflow.js +359 -0
  143. package/dist/modules/workflow/workflows/XiaohongshuLoginWorkflow.js +110 -0
  144. package/dist/modules/xiaohongshu/app/src/blocks/MatchCommentsBlock.js +139 -0
  145. package/dist/modules/xiaohongshu/app/src/blocks/Phase1EnsureServicesBlock.js +36 -0
  146. package/dist/modules/xiaohongshu/app/src/blocks/Phase1MonitorCookieBlock.js +213 -0
  147. package/dist/modules/xiaohongshu/app/src/blocks/Phase1StartProfileBlock.js +121 -0
  148. package/dist/modules/xiaohongshu/app/src/blocks/Phase2CollectLinksBlock.js +1249 -0
  149. package/dist/modules/xiaohongshu/app/src/blocks/Phase2SearchBlock.js +703 -0
  150. package/dist/modules/xiaohongshu/app/src/blocks/Phase34CloseDetailBlock.js +41 -0
  151. package/dist/modules/xiaohongshu/app/src/blocks/Phase34CloseTabsBlock.js +44 -0
  152. package/dist/modules/xiaohongshu/app/src/blocks/Phase34CollectCommentsBlock.js +150 -0
  153. package/dist/modules/xiaohongshu/app/src/blocks/Phase34ExtractDetailBlock.js +117 -0
  154. package/dist/modules/xiaohongshu/app/src/blocks/Phase34OpenDetailBlock.js +102 -0
  155. package/dist/modules/xiaohongshu/app/src/blocks/Phase34OpenTabsBlock.js +109 -0
  156. package/dist/modules/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.js +117 -0
  157. package/dist/modules/xiaohongshu/app/src/blocks/Phase34ProcessSingleNoteBlock.js +114 -0
  158. package/dist/modules/xiaohongshu/app/src/blocks/Phase34ValidateLinksBlock.js +90 -0
  159. package/dist/modules/xiaohongshu/app/src/blocks/Phase3InteractBlock.js +1009 -0
  160. package/dist/modules/xiaohongshu/app/src/blocks/Phase4MultiTabHarvestBlock.js +233 -0
  161. package/dist/modules/xiaohongshu/app/src/blocks/ReplyInteractBlock.js +291 -0
  162. package/dist/modules/xiaohongshu/app/src/blocks/XhsDiscoverFallbackBlock.js +240 -0
  163. package/dist/modules/xiaohongshu/app/src/blocks/helpers/commentMatchDsl.js +126 -0
  164. package/dist/modules/xiaohongshu/app/src/blocks/helpers/commentMatcher.js +99 -0
  165. package/dist/modules/xiaohongshu/app/src/blocks/helpers/evidence.js +27 -0
  166. package/dist/modules/xiaohongshu/app/src/blocks/helpers/sharding.js +42 -0
  167. package/dist/modules/xiaohongshu/app/src/blocks/helpers/xhsComments.js +270 -0
  168. package/dist/modules/xiaohongshu/app/src/index.js +9 -0
  169. package/dist/modules/xiaohongshu/app/src/utils/checkpoints.js +222 -0
  170. package/dist/modules/xiaohongshu/app/src/utils/controllerAction.js +43 -0
  171. package/dist/services/controller/src/controller.js +1476 -0
  172. package/dist/services/controller/src/index.js +2 -0
  173. package/dist/services/controller/src/payload-normalizer.js +129 -0
  174. package/dist/services/shared/heartbeat.js +120 -0
  175. package/dist/services/shared/lib/errorHandler.js +2 -0
  176. package/dist/services/shared/serviceProcessLogger.js +139 -0
  177. package/dist/services/unified-api/RemoteBrowserSession.js +176 -0
  178. package/dist/services/unified-api/RemoteSessionManager.js +148 -0
  179. package/dist/services/unified-api/container-operations-handler.js +115 -0
  180. package/dist/services/unified-api/server.js +652 -0
  181. package/dist/services/unified-api/state-registry.js +274 -0
  182. package/dist/services/unified-api/task-persistence.js +66 -0
  183. package/dist/services/unified-api/task-state.js +130 -0
  184. package/modules/camo-runtime/src/autoscript/action-providers/xhs/search.mjs +12 -5
  185. package/modules/xiaohongshu/app/pnpm-lock.yaml +24 -0
  186. package/package.json +38 -10
  187. package/.beads/README.md +0 -81
  188. package/.beads/config.yaml +0 -67
  189. package/.beads/interactions.jsonl +0 -0
  190. package/.beads/issues.jsonl +0 -180
  191. package/.beads/metadata.json +0 -4
  192. package/.claude/settings.local.json +0 -10
  193. package/.github/workflows/ci.yml +0 -55
  194. package/AGENTS.md +0 -253
  195. package/apps/desktop-console/README.md +0 -27
  196. package/apps/desktop-console/package-lock.json +0 -897
  197. package/apps/desktop-console/package.json +0 -20
  198. package/apps/desktop-console/scripts/build-and-install.mjs +0 -19
  199. package/apps/desktop-console/scripts/build.mjs +0 -45
  200. package/apps/desktop-console/scripts/test-preload.mjs +0 -13
  201. package/apps/desktop-console/src/main/config.mts +0 -26
  202. package/apps/desktop-console/src/main/core-daemon-manager.mts +0 -131
  203. package/apps/desktop-console/src/main/desktop-settings.mts +0 -267
  204. package/apps/desktop-console/src/main/heartbeat-watchdog.mts +0 -50
  205. package/apps/desktop-console/src/main/heartbeat-watchdog.test.mts +0 -68
  206. package/apps/desktop-console/src/main/index-streaming.test.mts +0 -20
  207. package/apps/desktop-console/src/main/index.mts +0 -980
  208. package/apps/desktop-console/src/main/profile-store.mts +0 -239
  209. package/apps/desktop-console/src/main/profile-store.test.mts +0 -54
  210. package/apps/desktop-console/src/main/state-bridge.mts +0 -114
  211. package/apps/desktop-console/src/main/task-state-types.ts +0 -32
  212. package/apps/desktop-console/src/renderer/hooks/use-task-state.mts +0 -120
  213. package/apps/desktop-console/src/renderer/index.mts +0 -133
  214. package/apps/desktop-console/src/renderer/index.test.mts +0 -34
  215. package/apps/desktop-console/src/renderer/path-helpers.mts +0 -46
  216. package/apps/desktop-console/src/renderer/path-helpers.test.mts +0 -14
  217. package/apps/desktop-console/src/renderer/tabs/debug.mts +0 -48
  218. package/apps/desktop-console/src/renderer/tabs/debug.test.mts +0 -22
  219. package/apps/desktop-console/src/renderer/tabs/logs.mts +0 -421
  220. package/apps/desktop-console/src/renderer/tabs/logs.test.mts +0 -27
  221. package/apps/desktop-console/src/renderer/tabs/preflight.mts +0 -486
  222. package/apps/desktop-console/src/renderer/tabs/preflight.test.mts +0 -33
  223. package/apps/desktop-console/src/renderer/tabs/profile-pool.mts +0 -213
  224. package/apps/desktop-console/src/renderer/tabs/results.mts +0 -171
  225. package/apps/desktop-console/src/renderer/tabs/run.test.mts +0 -63
  226. package/apps/desktop-console/src/renderer/tabs/runtime.mts +0 -151
  227. package/apps/desktop-console/src/renderer/tabs/settings.mts +0 -146
  228. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/account-flow.mts +0 -486
  229. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/guide-browser-check.mts +0 -56
  230. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/helpers.mts +0 -262
  231. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/layout-block.mts +0 -430
  232. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/live-stats.mts +0 -847
  233. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/run-flow.mts +0 -443
  234. package/apps/desktop-console/src/renderer/tabs/xiaohongshu-state.mts +0 -425
  235. package/apps/desktop-console/src/renderer/tabs/xiaohongshu.mts +0 -497
  236. package/apps/desktop-console/src/renderer/tabs/xiaohongshu.test.mts +0 -291
  237. package/apps/desktop-console/src/renderer/ui-components.mts +0 -31
  238. package/docs/README_camoufox_chinese.md +0 -141
  239. package/docs/USAGE_V3.md +0 -163
  240. package/docs/arch/OCR_MACOS_PLUGIN.md +0 -39
  241. package/docs/arch/PORTS.md +0 -40
  242. package/docs/arch/REGRESSION_CHECKLIST.md +0 -121
  243. package/docs/arch/SEARCH_GATE.md +0 -224
  244. package/docs/arch/VIEWPORT_SAFETY.md +0 -182
  245. package/docs/arch/XIAOHONGSHU_OFFLINE_MOCK_DESIGN.md +0 -267
  246. package/docs/xiaohongshu-container-driven-summary.md +0 -221
  247. package/docs/xiaohongshu-full-collect-runbook.md +0 -134
  248. package/docs/xiaohongshu-next-steps.md +0 -228
  249. package/docs/xiaohongshu-quickstart.md +0 -73
  250. package/docs/xiaohongshu-workflow-summary.md +0 -227
  251. package/modules/container-registry/tests/container-registry.test.ts +0 -16
  252. package/modules/logging/tests/logging.test.ts +0 -38
  253. package/modules/operations/tests/operations.test.ts +0 -22
  254. package/modules/operations/tests/viewport-filter.test.ts +0 -161
  255. package/modules/operations/tests/visible-only.test.ts +0 -250
  256. package/modules/session-manager/tests/session-manager.test.ts +0 -23
  257. package/modules/state/src/atomic-json.test.ts +0 -30
  258. package/modules/state/src/paths.test.ts +0 -59
  259. package/modules/state/src/xiaohongshu-collect-state.test.ts +0 -259
  260. package/modules/workflow/blocks/AnchorVerificationBlock.d.ts.map +0 -1
  261. package/modules/workflow/blocks/AnchorVerificationBlock.js.map +0 -1
  262. package/modules/workflow/blocks/DetectPageStateBlock.d.ts.map +0 -1
  263. package/modules/workflow/blocks/DetectPageStateBlock.js.map +0 -1
  264. package/modules/workflow/blocks/ErrorRecoveryBlock.d.ts.map +0 -1
  265. package/modules/workflow/blocks/ErrorRecoveryBlock.js.map +0 -1
  266. package/modules/workflow/blocks/WaitSearchPermitBlock.d.ts.map +0 -1
  267. package/modules/workflow/blocks/WaitSearchPermitBlock.js.map +0 -1
  268. package/modules/workflow/blocks/helpers/containerAnchors.d.ts.map +0 -1
  269. package/modules/workflow/blocks/helpers/containerAnchors.js.map +0 -1
  270. package/modules/workflow/blocks/helpers/downloadPaths.test.ts +0 -62
  271. package/modules/workflow/blocks/helpers/mergeXhsMarkdown.test.ts +0 -121
  272. package/modules/workflow/blocks/helpers/operationLogger.d.ts.map +0 -1
  273. package/modules/workflow/blocks/helpers/operationLogger.js.map +0 -1
  274. package/modules/workflow/blocks/helpers/persistedNotes.test.ts +0 -268
  275. package/modules/workflow/blocks/helpers/searchPageState.d.ts.map +0 -1
  276. package/modules/workflow/blocks/helpers/searchPageState.js.map +0 -1
  277. package/modules/workflow/blocks/helpers/targetCountMode.test.ts +0 -29
  278. package/modules/workflow/blocks/helpers/xhsCliArgs.test.ts +0 -75
  279. package/modules/workflow/tests/smartReply.test.ts +0 -32
  280. package/modules/xiaohongshu/app/src/blocks/Phase3Interact.matcher.test.ts +0 -33
  281. package/modules/xiaohongshu/app/src/utils/__tests__/checkpoints.test.ts +0 -141
  282. package/modules/xiaohongshu/app/tests/commentMatchDsl.test.ts +0 -50
  283. package/modules/xiaohongshu/app/tests/commentMatcher.test.ts +0 -46
  284. package/modules/xiaohongshu/app/tests/sharding.test.ts +0 -31
  285. package/package-scripts.json +0 -8
  286. package/runtime/infra/utils/README.md +0 -13
  287. package/runtime/infra/utils/scripts/README.md +0 -0
  288. package/runtime/infra/utils/scripts/development/eval-in-session.mjs +0 -40
  289. package/runtime/infra/utils/scripts/development/highlight-search-containers.mjs +0 -35
  290. package/runtime/infra/utils/scripts/service/kill-port.mjs +0 -24
  291. package/runtime/infra/utils/scripts/service/start-api.mjs +0 -39
  292. package/runtime/infra/utils/scripts/service/start-browser-service.mjs +0 -106
  293. package/runtime/infra/utils/scripts/service/stop-api.mjs +0 -18
  294. package/runtime/infra/utils/scripts/service/stop-browser-service.mjs +0 -104
  295. package/runtime/infra/utils/scripts/test-services.mjs +0 -94
  296. package/services/shared/heartbeat.test.ts +0 -102
  297. package/services/unified-api/__tests__/task-state.test.ts +0 -95
  298. package/sitecustomize.py +0 -19
  299. package/tests/README.md +0 -194
  300. package/tests/e2e/workflows/weibo-feed-extraction.test.ts +0 -171
  301. package/tests/fixtures/data/container-definitions.json +0 -67
  302. package/tests/fixtures/pages/simple-page.html +0 -69
  303. package/tests/integration/01-test-container-match.mjs +0 -188
  304. package/tests/integration/02-test-dom-branch.mjs +0 -161
  305. package/tests/integration/03-test-container-operation-system.mjs +0 -91
  306. package/tests/integration/05-test-container-lifecycle-events.mjs +0 -224
  307. package/tests/integration/05-test-container-lifecycle-with-events.mjs +0 -250
  308. package/tests/integration/06-test-container-dom-tree-drawing.mjs +0 -256
  309. package/tests/integration/07-test-weibo-container-lifecycle.mjs +0 -355
  310. package/tests/integration/08-test-weibo-feed-workflow.test.mjs +0 -164
  311. package/tests/integration/10-test-visual-analyzer.mjs +0 -312
  312. package/tests/integration/11-test-visual-loop.mjs +0 -284
  313. package/tests/integration/12-test-simple-visual-loop.mjs +0 -242
  314. package/tests/integration/13-test-visual-robust.mjs +0 -185
  315. package/tests/integration/14-test-visual-highlight-loop.mjs +0 -271
  316. package/tests/integration/inspect-page.mjs +0 -50
  317. package/tests/integration/run-all-tests.mjs +0 -95
  318. package/tests/patch_verification/CODEX_PATCH_TEST.md +0 -103
  319. package/tests/patch_verification/PHASE2_ANALYSIS.md +0 -179
  320. package/tests/patch_verification/PHASE2_OPTIMIZATION_REPORT.md +0 -55
  321. package/tests/patch_verification/PHASE2_TO_PHASE4_SUMMARY.md +0 -126
  322. package/tests/patch_verification/QUICK_TEST_SEQUENCE.md +0 -262
  323. package/tests/patch_verification/README.md +0 -143
  324. package/tests/patch_verification/RUN_TESTS.md +0 -60
  325. package/tests/patch_verification/TEST_EXECUTION.md +0 -99
  326. package/tests/patch_verification/TEST_PLAN.md +0 -328
  327. package/tests/patch_verification/TEST_RESULTS.md +0 -34
  328. package/tests/patch_verification/TOOL_TEST_PLAN.md +0 -48
  329. package/tests/patch_verification/run-tool-test.mjs +0 -121
  330. package/tests/patch_verification/temp_test_files/test01.txt +0 -1
  331. package/tests/patch_verification/temp_test_files/test02.txt +0 -3
  332. package/tests/patch_verification/temp_test_files/test02_gnu.txt +0 -3
  333. package/tests/patch_verification/temp_test_files/test03.txt +0 -1
  334. package/tests/patch_verification/temp_test_files/test03_multiline.txt +0 -5
  335. package/tests/patch_verification/temp_test_files/test04_function.ts +0 -5
  336. package/tests/patch_verification/temp_test_files/test05_import.ts +0 -4
  337. package/tests/patch_verification/temp_test_files/test06_special_chars.txt +0 -4
  338. package/tests/patch_verification/temp_test_files/test07_indentation.ts +0 -5
  339. package/tests/patch_verification/temp_test_files/test08_mismatch.txt +0 -1
  340. package/tests/patch_verification/temp_test_files/test_add_02.txt +0 -3
  341. package/tests/patch_verification/temp_test_files/test_simple.txt +0 -1
  342. package/tests/runner/TestReporter.mjs +0 -57
  343. package/tests/runner/TestRunner.mjs +0 -244
  344. package/tests/unit/commands/profile.test.mjs +0 -10
  345. package/tests/unit/container/change-notifier.test.mjs +0 -181
  346. package/tests/unit/lifecycle/session-registry.test.mjs +0 -135
  347. package/tests/unit/operations/registry.test.ts +0 -73
  348. package/tests/unit/utils/browser-service.test.mjs +0 -153
  349. package/tests/unit/utils/config.test.mjs +0 -166
  350. package/tests/unit/utils/fingerprint.test.mjs +0 -166
  351. package/tsconfig.json +0 -31
  352. package/tsconfig.services.json +0 -26
  353. /package/apps/desktop-console/{src → dist}/renderer/index.html +0 -0
  354. /package/apps/desktop-console/{src/renderer/tabs → dist/renderer}/run.mts +0 -0
@@ -0,0 +1,635 @@
1
+ /**
2
+ * System Input Helper (browser-service)
3
+ *
4
+ * 统一封装系统级鼠标/键盘/滚轮操作,避免在各 Block 内重复实现。
5
+ * 注意:这里只做"系统事件发送",不做任何 DOM click/scroll 等 JS 行为。
6
+ */
7
+ import os from 'node:os';
8
+ import path from 'node:path';
9
+ import { promises as fs } from 'node:fs';
10
+ import { isDebugArtifactsEnabled } from './debugArtifacts.js';
11
+ import { logControllerActionError, logControllerActionResult, logControllerActionStart, logError, logOperation, } from './operationLogger.js';
12
+ // 调试截图保存目录
13
+ function resolveDownloadRoot() {
14
+ const custom = process.env.WEBAUTO_DOWNLOAD_ROOT || process.env.WEBAUTO_DOWNLOAD_DIR;
15
+ if (custom && custom.trim())
16
+ return custom;
17
+ const home = process.env.HOME || process.env.USERPROFILE;
18
+ if (home && home.trim())
19
+ return path.join(home, '.webauto', 'download');
20
+ return path.join(os.homedir(), '.webauto', 'download');
21
+ }
22
+ const DEBUG_ENABLED = isDebugArtifactsEnabled();
23
+ const DEBUG_SCREENSHOT_DIR = DEBUG_ENABLED
24
+ ? path.join(resolveDownloadRoot(), 'logs', 'debug-screenshots')
25
+ : '';
26
+ const DEFAULT_CONTROLLER_URL = process.env.WEBAUTO_CONTROLLER_URL || 'http://127.0.0.1:7701/v1/controller/action';
27
+ /**
28
+ * 保存调试截图
29
+ */
30
+ async function saveDebugScreenshot(kind, sessionId, meta = {}) {
31
+ if (!DEBUG_ENABLED)
32
+ return {};
33
+ try {
34
+ await fs.mkdir(DEBUG_SCREENSHOT_DIR, { recursive: true });
35
+ const ts = new Date().toISOString().replace(/[:.]/g, '-');
36
+ const base = `${ts}-${kind}-${sessionId}`;
37
+ const pngPath = path.join(DEBUG_SCREENSHOT_DIR, `${base}.png`);
38
+ const jsonPath = path.join(DEBUG_SCREENSHOT_DIR, `${base}.json`);
39
+ const controllerUrl = DEFAULT_CONTROLLER_URL;
40
+ // 截图
41
+ async function takeShot() {
42
+ const response = await fetch(controllerUrl, {
43
+ method: 'POST',
44
+ headers: { 'Content-Type': 'application/json' },
45
+ body: JSON.stringify({
46
+ action: 'browser:screenshot',
47
+ payload: { profileId: sessionId, fullPage: false },
48
+ }),
49
+ });
50
+ if (!response.ok)
51
+ throw new Error(`HTTP ${response.status}`);
52
+ const data = await response.json().catch(() => ({}));
53
+ return data.data || data;
54
+ }
55
+ let shot = null;
56
+ try {
57
+ shot = await takeShot();
58
+ }
59
+ catch {
60
+ try {
61
+ shot = await takeShot();
62
+ }
63
+ catch {
64
+ shot = null;
65
+ }
66
+ }
67
+ // 提取 base64
68
+ const b64 = shot?.data?.data ??
69
+ shot?.data?.body?.data ??
70
+ shot?.body?.data ??
71
+ shot?.result?.data ??
72
+ shot?.result ??
73
+ shot?.data ??
74
+ shot;
75
+ if (typeof b64 === 'string' && b64.length > 10) {
76
+ await fs.writeFile(pngPath, Buffer.from(b64, 'base64'));
77
+ }
78
+ // 保存元数据
79
+ await fs.writeFile(jsonPath, JSON.stringify({ ts, kind, sessionId, ...meta, pngPath: b64 ? pngPath : null }, null, 2), 'utf-8');
80
+ console.log(`[systemInput][debug] saved ${kind}: ${pngPath}`);
81
+ return { pngPath: b64 ? pngPath : undefined, jsonPath };
82
+ }
83
+ catch {
84
+ return {};
85
+ }
86
+ }
87
+ async function controllerAction(action, payload) {
88
+ const opId = logControllerActionStart(action, payload, { source: 'systemInput' });
89
+ try {
90
+ const response = await fetch(DEFAULT_CONTROLLER_URL, {
91
+ method: 'POST',
92
+ headers: { 'Content-Type': 'application/json' },
93
+ body: JSON.stringify({ action, payload }),
94
+ signal: AbortSignal.timeout ? AbortSignal.timeout(12000) : undefined,
95
+ });
96
+ if (!response.ok) {
97
+ throw new Error(`HTTP ${response.status}: ${await response.text()}`);
98
+ }
99
+ const data = await response.json().catch(() => ({}));
100
+ const result = data.data || data;
101
+ logControllerActionResult(opId, action, result, { source: 'systemInput' });
102
+ return result;
103
+ }
104
+ catch (error) {
105
+ logControllerActionError(opId, action, error, payload, { source: 'systemInput' });
106
+ throw error;
107
+ }
108
+ }
109
+ async function probePoint(profileId, x, y) {
110
+ try {
111
+ const res = await controllerAction('browser:execute', {
112
+ profile: profileId,
113
+ script: `(() => {
114
+ const x = ${JSON.stringify(x)};
115
+ const y = ${JSON.stringify(y)};
116
+ const el = document.elementFromPoint(x, y);
117
+ const tag = el && el.tagName ? String(el.tagName) : null;
118
+ const className = el && el.className ? String(el.className) : null;
119
+ const textSnippet = el && el.textContent ? String(el.textContent).trim().slice(0, 80) : null;
120
+ const linkEl = el && el.closest ? el.closest('a[href]') : null;
121
+ const href = linkEl ? (linkEl.getAttribute('href') || linkEl.href || '') : '';
122
+
123
+ const modal = document.querySelector('.r-captcha-modal, .captcha-modal-content');
124
+ const modalText = modal ? (modal.textContent || '') : '';
125
+ const isCaptcha = Boolean(modal) || modalText.includes('请通过验证') || modalText.includes('扫码验证');
126
+
127
+ // 图片查看器/媒体预览层:出现时禁止继续点击(开发阶段不做兜底纠错)
128
+ const dialog = document.querySelector('[aria-modal=\"true\"], [role=\"dialog\"][aria-modal=\"true\"], [role=\"dialog\"]');
129
+ const hasBigImage = Array.from(document.querySelectorAll('img')).some((img) => {
130
+ try {
131
+ const r = img.getBoundingClientRect();
132
+ return r && r.width > (window.innerWidth || 0) * 0.55 && r.height > (window.innerHeight || 0) * 0.55;
133
+ } catch {
134
+ return false;
135
+ }
136
+ });
137
+ const mediaOverlay =
138
+ document.querySelector('.media-viewer, .image-viewer, .photo-viewer, .preview-modal, .viewer-modal') ||
139
+ document.querySelector('[class*=\"viewer\"][class*=\"image\"], [class*=\"viewer\"][class*=\"photo\"], [class*=\"preview\"][class*=\"image\"], [class*=\"preview\"][class*=\"photo\"]');
140
+ const isMediaViewerOpen = Boolean(mediaOverlay) || (Boolean(dialog) && hasBigImage);
141
+
142
+ const isImageTag = tag === 'IMG' || tag === 'VIDEO' || tag === 'CANVAS';
143
+ const imageAncestor = el && el.closest ? el.closest('img,video,canvas') : null;
144
+ const isImageLike = Boolean(isImageTag || imageAncestor);
145
+
146
+ const cover = el && el.closest ? el.closest('a.cover') : null;
147
+ const isCover = Boolean(cover);
148
+
149
+ return { tag, className, textSnippet, href: href || null, isCaptcha, isMediaViewerOpen, isImageLike, isCover };
150
+ })()`,
151
+ });
152
+ const payload = res?.result ?? res?.data?.result ?? res;
153
+ return {
154
+ tag: typeof payload?.tag === 'string' ? payload.tag : null,
155
+ className: typeof payload?.className === 'string' ? payload.className : null,
156
+ textSnippet: typeof payload?.textSnippet === 'string' ? payload.textSnippet : null,
157
+ href: typeof payload?.href === 'string' ? payload.href : null,
158
+ isCaptcha: Boolean(payload?.isCaptcha),
159
+ isMediaViewerOpen: Boolean(payload?.isMediaViewerOpen),
160
+ isImageLike: Boolean(payload?.isImageLike),
161
+ isCover: Boolean(payload?.isCover),
162
+ };
163
+ }
164
+ catch {
165
+ return {
166
+ tag: null,
167
+ className: null,
168
+ textSnippet: null,
169
+ href: null,
170
+ isCaptcha: false,
171
+ isMediaViewerOpen: false,
172
+ isImageLike: false,
173
+ isCover: false,
174
+ };
175
+ }
176
+ }
177
+ async function isCaptchaOverlayVisible(profileId) {
178
+ try {
179
+ const res = await controllerAction('browser:execute', {
180
+ profile: profileId,
181
+ script: `(() => {
182
+ const modal =
183
+ document.querySelector('.r-captcha-modal') ||
184
+ document.querySelector('.captcha-modal-content') ||
185
+ document.querySelector('[class*="captcha-modal"]') ||
186
+ document.querySelector('[class*="captcha"][class*="modal"]');
187
+ const title =
188
+ document.querySelector('.captcha-modal-title') ||
189
+ document.querySelector('.captcha-modal__header .text-h6-bold') ||
190
+ null;
191
+ const modalText = modal ? (modal.textContent || '') : '';
192
+ const titleText = title ? (title.textContent || '') : '';
193
+ return (
194
+ Boolean(modal) ||
195
+ titleText.includes('请通过验证') ||
196
+ modalText.includes('请通过验证') ||
197
+ modalText.includes('扫码验证') ||
198
+ modalText.includes('二维码') ||
199
+ modalText.includes('问题反馈')
200
+ );
201
+ })()`,
202
+ });
203
+ const payload = res?.result ?? res?.data?.result ?? res;
204
+ return Boolean(payload);
205
+ }
206
+ catch {
207
+ return false;
208
+ }
209
+ }
210
+ export async function assertNoCaptcha(profileId, context) {
211
+ const visible = await isCaptchaOverlayVisible(profileId);
212
+ if (!visible)
213
+ return;
214
+ await saveDebugScreenshot(`captcha_detected_${context || 'system'}`, profileId, { context });
215
+ throw new Error(`captcha_modal_detected (context=${context || 'system'})`);
216
+ }
217
+ function shouldGuardAgainstImageClick(context) {
218
+ const c = String(context || '').trim();
219
+ if (!c)
220
+ return false;
221
+ // 详情页/评论相关的坐标点击:禁止落在图片/视频上(避免打开图片查看器触发风控)
222
+ return (c.includes('scroll') ||
223
+ c.includes('comment') ||
224
+ c.includes('reply') ||
225
+ c.includes('select_latest_tab'));
226
+ }
227
+ function shouldStopOnMediaViewer(context) {
228
+ const c = String(context || '').trim();
229
+ if (!c)
230
+ return false;
231
+ // 开发阶段:评论/滚动相关任何点击遇到媒体查看器,直接停
232
+ return c.includes('scroll') || c.includes('comment') || c.includes('reply');
233
+ }
234
+ function isDangerousHrefInDetail(href) {
235
+ const h = typeof href === 'string' ? href : '';
236
+ if (!h)
237
+ return false;
238
+ // 在详情/评论区域,点击到链接通常意味着误点(头像/话题/推荐等)
239
+ return (h.includes('/user/') ||
240
+ h.includes('/user/profile') ||
241
+ h.includes('/profile') ||
242
+ h.includes('/search_result') ||
243
+ h.startsWith('http://') ||
244
+ h.startsWith('https://'));
245
+ }
246
+ async function highlightClickPoint(profileId, x, y, color = '#ff3b30', durationMs = 900) {
247
+ try {
248
+ const size = 18;
249
+ await controllerAction('browser:execute', {
250
+ profile: profileId,
251
+ script: `(() => {
252
+ const p = { x: ${JSON.stringify(x)}, y: ${JSON.stringify(y)} };
253
+ const size = ${JSON.stringify(size)};
254
+ let el = document.getElementById('webauto-click-point');
255
+ if (!el) {
256
+ el = document.createElement('div');
257
+ el.id = 'webauto-click-point';
258
+ el.style.position = 'fixed';
259
+ el.style.pointerEvents = 'none';
260
+ el.style.zIndex = '2147483647';
261
+ el.style.borderRadius = '50%';
262
+ el.style.boxSizing = 'border-box';
263
+ document.body.appendChild(el);
264
+ }
265
+ el.style.left = (p.x - size / 2) + 'px';
266
+ el.style.top = (p.y - size / 2) + 'px';
267
+ el.style.width = size + 'px';
268
+ el.style.height = size + 'px';
269
+ el.style.border = '3px solid ${color}';
270
+ el.style.background = 'rgba(255, 59, 48, 0.08)';
271
+ setTimeout(() => {
272
+ try { el && el.parentElement && el.parentElement.removeChild(el); } catch {}
273
+ }, ${durationMs});
274
+ return true;
275
+ })()`,
276
+ });
277
+ }
278
+ catch {
279
+ // ignore
280
+ }
281
+ }
282
+ async function highlightTargetRectAtPoint(options) {
283
+ const { profileId, x, y, context, color = '#ff3b30', durationMs = 1200 } = options;
284
+ try {
285
+ const res = await controllerAction('browser:execute', {
286
+ profile: profileId,
287
+ script: `(() => {
288
+ const p = { x: ${JSON.stringify(x)}, y: ${JSON.stringify(y)} };
289
+ const context = ${JSON.stringify(String(context || ''))};
290
+ const el = document.elementFromPoint(p.x, p.y);
291
+ if (!el || !(el instanceof HTMLElement)) return null;
292
+
293
+ const tag = el.tagName ? String(el.tagName) : null;
294
+ // 优先高亮“可点击目标”本身(展开回复/更多评论等),避免只画一个点看不出点了啥
295
+ let target = el;
296
+ if (context.includes('reply') || context.includes('expand') || context.includes('comment')) {
297
+ const t =
298
+ el.closest('button') ||
299
+ el.closest('[role=\"button\"]') ||
300
+ el.closest('.show-more') ||
301
+ el.closest('[class*=\"show-more\"]') ||
302
+ el.closest('[class*=\"expand\"]') ||
303
+ el.closest('[class*=\"more\"]');
304
+ if (t && t instanceof HTMLElement) target = t;
305
+ }
306
+ const r = target.getBoundingClientRect();
307
+ if (!r || !r.width || !r.height) return null;
308
+
309
+ let overlay = document.getElementById('webauto-click-target-rect');
310
+ if (!overlay) {
311
+ overlay = document.createElement('div');
312
+ overlay.id = 'webauto-click-target-rect';
313
+ overlay.style.position = 'fixed';
314
+ overlay.style.pointerEvents = 'none';
315
+ overlay.style.zIndex = '2147483647';
316
+ overlay.style.boxSizing = 'border-box';
317
+ overlay.style.borderRadius = '6px';
318
+ document.body.appendChild(overlay);
319
+ }
320
+ overlay.style.left = r.left + 'px';
321
+ overlay.style.top = r.top + 'px';
322
+ overlay.style.width = r.width + 'px';
323
+ overlay.style.height = r.height + 'px';
324
+ overlay.style.border = '3px solid ${color}';
325
+ overlay.style.background = 'rgba(255, 59, 48, 0.05)';
326
+ setTimeout(() => {
327
+ try { overlay && overlay.parentElement && overlay.parentElement.removeChild(overlay); } catch {}
328
+ }, ${durationMs});
329
+
330
+ return { tag, rect: { x: r.left, y: r.top, width: r.width, height: r.height } };
331
+ })()`,
332
+ });
333
+ const payload = res?.result ?? res?.data?.result ?? res;
334
+ if (!payload)
335
+ return null;
336
+ return payload;
337
+ }
338
+ catch {
339
+ return null;
340
+ }
341
+ }
342
+ export async function browserServiceCommand(browserServiceUrl, action, args, timeoutMs = 8000) {
343
+ const response = await fetch(`${browserServiceUrl}/command`, {
344
+ method: 'POST',
345
+ headers: { 'Content-Type': 'application/json' },
346
+ body: JSON.stringify({ action, args }),
347
+ signal: AbortSignal.timeout
348
+ ? AbortSignal.timeout(timeoutMs)
349
+ : undefined,
350
+ });
351
+ if (!response.ok) {
352
+ throw new Error(`browser-service HTTP ${response.status}: ${await response.text()}`);
353
+ }
354
+ const data = await response.json().catch(() => ({}));
355
+ if (data?.ok === false || data?.success === false) {
356
+ throw new Error(data?.error || 'browser-service command failed');
357
+ }
358
+ return data?.body || data?.data || data;
359
+ }
360
+ export async function systemHoverAt(profileId, x, y, browserServiceUrl = 'http://127.0.0.1:7704') {
361
+ await browserServiceCommand(browserServiceUrl, 'mouse:move', { profileId, x: Math.floor(x), y: Math.floor(y), steps: 3 }, 8000).catch(() => { });
362
+ }
363
+ export async function systemClickAt(profileId, x, y, browserServiceUrl = 'http://127.0.0.1:7704', context) {
364
+ // 先尝试将目标元素滚动到视口中心(如果元素在视口外)
365
+ try {
366
+ const { scrollElementAtPointIntoView } = await import('./scrollIntoView.js');
367
+ const scrollResult = await scrollElementAtPointIntoView(profileId, x, y);
368
+ if (scrollResult.success && !scrollResult.visible) {
369
+ // 元素滚动后仍不可见,可能需要调整坐标或元素已消失
370
+ console.warn(`[systemInput] Element scrolled but not visible at (${x}, ${y})`);
371
+ }
372
+ // 等待滚动稳定
373
+ await new Promise((r) => setTimeout(r, 200));
374
+ }
375
+ catch (e) {
376
+ // 滚动失败不影响后续点击尝试(可能元素本身就在视口内)
377
+ console.warn(`[systemInput] scrollIntoView failed: ${e?.message || e}`);
378
+ }
379
+ const probe = await probePoint(profileId, x, y);
380
+ const clickOpId = logOperation({
381
+ kind: 'system_click_attempt',
382
+ action: 'mouse:click',
383
+ sessionId: profileId,
384
+ context: context || null,
385
+ reason: context || null,
386
+ target: { x, y, probe },
387
+ });
388
+ // 风控/验证码:出现就立即停下(开发阶段不做重试/兜底),保留证据便于人工处理
389
+ if (probe.isCaptcha) {
390
+ await saveDebugScreenshot(`captcha_detected_${context || 'system'}`, profileId, { x, y, context, probe });
391
+ logError({
392
+ kind: 'system_click_blocked',
393
+ action: 'mouse:click',
394
+ sessionId: profileId,
395
+ context: context || null,
396
+ reason: 'captcha_detected',
397
+ error: 'captcha_modal_detected',
398
+ payload: { x, y, probe },
399
+ opId: clickOpId,
400
+ });
401
+ throw new Error(`captcha_modal_detected (context=${context || 'system'})`);
402
+ }
403
+ // 媒体查看器/预览层:出现就立即停下(避免乱点)
404
+ if (shouldStopOnMediaViewer(context) && probe.isMediaViewerOpen) {
405
+ await saveDebugScreenshot(`media_viewer_open_${context || 'system'}`, profileId, { x, y, context, probe });
406
+ logError({
407
+ kind: 'system_click_blocked',
408
+ action: 'mouse:click',
409
+ sessionId: profileId,
410
+ context: context || null,
411
+ reason: 'media_viewer_open',
412
+ error: 'media_viewer_open',
413
+ payload: { x, y, probe },
414
+ opId: clickOpId,
415
+ });
416
+ throw new Error(`media_viewer_open (context=${context || 'system'})`);
417
+ }
418
+ // 详情页/评论相关点击:禁止点到链接(通常是头像/话题/推荐/外链)
419
+ if (shouldGuardAgainstImageClick(context) && isDangerousHrefInDetail(probe.href)) {
420
+ await saveDebugScreenshot(`unsafe_click_href_${context || 'system'}`, profileId, { x, y, context, probe });
421
+ logError({
422
+ kind: 'system_click_blocked',
423
+ action: 'mouse:click',
424
+ sessionId: profileId,
425
+ context: context || null,
426
+ reason: 'unsafe_click_href_in_detail',
427
+ error: 'unsafe_click_href_in_detail',
428
+ payload: { x, y, probe },
429
+ opId: clickOpId,
430
+ });
431
+ throw new Error(`unsafe_click_href_in_detail (context=${context || 'system'})`);
432
+ }
433
+ // 详情页/评论滚动相关点击:禁止点到图片/视频(会打开查看器/新层)
434
+ if (shouldGuardAgainstImageClick(context) && probe.isImageLike) {
435
+ await saveDebugScreenshot(`unsafe_click_image_${context || 'system'}`, profileId, { x, y, context, probe });
436
+ logError({
437
+ kind: 'system_click_blocked',
438
+ action: 'mouse:click',
439
+ sessionId: profileId,
440
+ context: context || null,
441
+ reason: 'unsafe_click_image_in_detail',
442
+ error: 'unsafe_click_image_in_detail',
443
+ payload: { x, y, probe },
444
+ opId: clickOpId,
445
+ });
446
+ throw new Error(`unsafe_click_image_in_detail (context=${context || 'system'})`);
447
+ }
448
+ // 高亮后再截图(便于复盘点位是否正确)
449
+ const hi = await highlightTargetRectAtPoint({
450
+ profileId,
451
+ x,
452
+ y,
453
+ context,
454
+ color: '#ff3b30',
455
+ durationMs: 1100,
456
+ });
457
+ // 同时保留点位小圆点,便于确认“点到的确切坐标”
458
+ await highlightClickPoint(profileId, x, y, '#ff3b30', 1100);
459
+ await new Promise((r) => setTimeout(r, 180));
460
+ await saveDebugScreenshot(`before_click_${context || 'system'}`, profileId, {
461
+ x,
462
+ y,
463
+ context,
464
+ probe,
465
+ highlightRect: hi?.rect ?? null,
466
+ highlightTag: hi?.tag ?? null,
467
+ });
468
+ await systemHoverAt(profileId, x, y, browserServiceUrl);
469
+ await new Promise((r) => setTimeout(r, 80));
470
+ await browserServiceCommand(browserServiceUrl, 'mouse:click', {
471
+ profileId,
472
+ x: Math.floor(x),
473
+ y: Math.floor(y),
474
+ clicks: 1,
475
+ delay: 40 + Math.floor(Math.random() * 60),
476
+ }, 8000);
477
+ logOperation({
478
+ kind: 'system_click_done',
479
+ action: 'mouse:click',
480
+ sessionId: profileId,
481
+ context: context || null,
482
+ reason: context || null,
483
+ target: { x, y, probe },
484
+ meta: { opId: clickOpId },
485
+ });
486
+ }
487
+ export function isDevMode() {
488
+ const raw = String(process.env.WEBAUTO_DEV || '').trim().toLowerCase();
489
+ return raw === '1' || raw === 'true' || raw === 'yes' || raw === 'dev';
490
+ }
491
+ export async function systemMouseWheel(options) {
492
+ const { profileId, deltaY, focusPoint, browserServiceUrl = 'http://127.0.0.1:7704', browserWsUrl = process.env.WEBAUTO_BROWSER_WS_URL || 'ws://127.0.0.1:8765', context, } = options;
493
+ // 风控/验证码:出现就立即停下(开发阶段不做重试/兜底),保留证据便于人工处理
494
+ if (await isCaptchaOverlayVisible(profileId)) {
495
+ await saveDebugScreenshot(`captcha_detected_wheel_${context || 'system'}`, profileId, { deltaY, focusPoint, context });
496
+ logError({
497
+ kind: 'system_scroll_blocked',
498
+ action: 'mouse:wheel',
499
+ sessionId: profileId,
500
+ context: context || null,
501
+ reason: 'captcha_detected',
502
+ error: 'captcha_modal_detected',
503
+ payload: { deltaY, focusPoint },
504
+ });
505
+ throw new Error(`captcha_modal_detected (context=${context || 'system'})`);
506
+ }
507
+ const scrollOpId = logOperation({
508
+ kind: 'system_scroll_attempt',
509
+ action: 'mouse:wheel',
510
+ sessionId: profileId,
511
+ context: context || null,
512
+ reason: context || null,
513
+ target: { deltaY, focusPoint },
514
+ });
515
+ try {
516
+ if (focusPoint) {
517
+ await systemHoverAt(profileId, focusPoint.x, focusPoint.y, browserServiceUrl);
518
+ await new Promise((r) => setTimeout(r, 60));
519
+ }
520
+ await browserServiceCommand(browserServiceUrl, 'mouse:wheel', { profileId, deltaX: 0, deltaY }, 8000);
521
+ logOperation({
522
+ kind: 'system_scroll_done',
523
+ action: 'mouse:wheel',
524
+ sessionId: profileId,
525
+ context: context || null,
526
+ reason: context || null,
527
+ target: { deltaY, focusPoint },
528
+ meta: { opId: scrollOpId },
529
+ });
530
+ return;
531
+ }
532
+ catch (err) {
533
+ console.warn('[WarmupComments] browser-service mouse:wheel failed, fallback to ws:', err?.message || err);
534
+ }
535
+ try {
536
+ await browserServiceWsScroll({
537
+ profileId,
538
+ deltaY,
539
+ browserWsUrl,
540
+ coordinates: focusPoint ? { x: focusPoint.x, y: focusPoint.y } : null,
541
+ });
542
+ logOperation({
543
+ kind: 'system_scroll_done',
544
+ action: 'mouse:wheel',
545
+ sessionId: profileId,
546
+ context: context || null,
547
+ reason: context || null,
548
+ target: { deltaY, focusPoint },
549
+ meta: { opId: scrollOpId, via: 'ws' },
550
+ });
551
+ }
552
+ catch (error) {
553
+ logError({
554
+ kind: 'system_scroll_failed',
555
+ action: 'mouse:wheel',
556
+ sessionId: profileId,
557
+ context: context || null,
558
+ reason: context || null,
559
+ error: error instanceof Error ? error.message : String(error),
560
+ payload: { deltaY, focusPoint },
561
+ opId: scrollOpId,
562
+ });
563
+ throw error;
564
+ }
565
+ }
566
+ async function browserServiceWsScroll(options) {
567
+ const { profileId, deltaY, browserWsUrl, coordinates } = options;
568
+ const { default: WebSocket } = await import('ws');
569
+ const requestId = `${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`;
570
+ return new Promise((resolve, reject) => {
571
+ const timer = setTimeout(() => {
572
+ try {
573
+ ws.close();
574
+ }
575
+ catch { }
576
+ reject(new Error('browser-service ws timeout'));
577
+ }, 15000);
578
+ const ws = new WebSocket(browserWsUrl);
579
+ const cleanup = () => {
580
+ clearTimeout(timer);
581
+ try {
582
+ ws.close();
583
+ }
584
+ catch { }
585
+ };
586
+ ws.on('open', () => {
587
+ try {
588
+ ws.send(JSON.stringify({
589
+ type: 'command',
590
+ request_id: requestId,
591
+ session_id: profileId,
592
+ data: {
593
+ command_type: 'user_action',
594
+ action: 'operation',
595
+ parameters: {
596
+ operation_type: 'scroll',
597
+ ...(coordinates ? { target: { coordinates } } : {}),
598
+ deltaY,
599
+ },
600
+ },
601
+ }));
602
+ }
603
+ catch (err) {
604
+ cleanup();
605
+ reject(err);
606
+ }
607
+ });
608
+ ws.on('message', (buf) => {
609
+ try {
610
+ const msg = JSON.parse(String(buf || ''));
611
+ if (msg?.type !== 'response')
612
+ return;
613
+ if (String(msg?.request_id || '') !== requestId)
614
+ return;
615
+ const payload = msg?.data || {};
616
+ if (payload?.success === false) {
617
+ cleanup();
618
+ reject(new Error(payload?.error || 'browser-service ws scroll failed'));
619
+ return;
620
+ }
621
+ cleanup();
622
+ resolve();
623
+ }
624
+ catch (err) {
625
+ cleanup();
626
+ reject(err);
627
+ }
628
+ });
629
+ ws.on('error', (err) => {
630
+ cleanup();
631
+ reject(err);
632
+ });
633
+ });
634
+ }
635
+ //# sourceMappingURL=systemInput.js.map
@@ -0,0 +1,9 @@
1
+ export function resolveTargetCount(input) {
2
+ const requested = Number.isFinite(input.targetCount)
3
+ ? Math.max(0, Math.floor(input.targetCount))
4
+ : 0;
5
+ const mode = input.mode === 'incremental' ? 'incremental' : 'absolute';
6
+ const targetTotal = mode === 'incremental' ? input.baseCount + requested : requested;
7
+ return { requested, targetTotal, mode };
8
+ }
9
+ //# sourceMappingURL=targetCountMode.js.map