@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,233 @@
1
+ import path from 'node:path';
2
+ import os from 'node:os';
3
+ async function controllerAction(action, payload, apiUrl) {
4
+ const res = await fetch(`${apiUrl}/v1/controller/action`, {
5
+ method: 'POST',
6
+ headers: { 'Content-Type': 'application/json' },
7
+ body: JSON.stringify({ action, payload }),
8
+ signal: AbortSignal.timeout(30000),
9
+ });
10
+ const data = await res.json().catch(() => ({}));
11
+ return data.data || data;
12
+ }
13
+ async function delay(ms) {
14
+ return new Promise(r => setTimeout(r, ms));
15
+ }
16
+ async function ensureDir(pathname) {
17
+ const { mkdir } = await import('node:fs/promises');
18
+ await mkdir(pathname, { recursive: true });
19
+ }
20
+ async function appendJsonl(filePath, rows) {
21
+ const { appendFile } = await import('node:fs/promises');
22
+ const lines = rows.map((row) => JSON.stringify(row)).join('\n') + '\n';
23
+ await appendFile(filePath, lines, 'utf8');
24
+ }
25
+ function resolveDownloadRoot() {
26
+ const custom = process.env.WEBAUTO_DOWNLOAD_ROOT || process.env.WEBAUTO_DOWNLOAD_DIR;
27
+ if (custom && custom.trim())
28
+ return custom;
29
+ const home = process.env.HOME || process.env.USERPROFILE || os.homedir();
30
+ return path.join(home, '.webauto', 'download');
31
+ }
32
+ async function listPages(profile, apiUrl) {
33
+ const res = await controllerAction('browser:page:list', { profileId: profile }, apiUrl);
34
+ const pages = res?.pages || res?.data?.pages || [];
35
+ const activeIndex = res?.activeIndex ?? res?.data?.activeIndex ?? -1;
36
+ return { pages, activeIndex };
37
+ }
38
+ async function switchToTab(profile, apiUrl, index) {
39
+ await controllerAction('browser:page:switch', { profileId: profile, index }, apiUrl).catch(() => null);
40
+ await delay(500);
41
+ const listRes = await listPages(profile, apiUrl);
42
+ const activeIndex = listRes.activeIndex;
43
+ const pages = listRes.pages || [];
44
+ const activeUrl = pages.find((p) => p.active)?.url || 'N/A';
45
+ return { activeIndex, activeUrl };
46
+ }
47
+ async function openTabViaWindowOpen(profile, apiUrl) {
48
+ await controllerAction('browser:page:switch', { profileId: profile, index: 0 }, apiUrl).catch(() => null);
49
+ await controllerAction('system:shortcut', { app: 'camoufox', shortcut: 'new-tab' }, apiUrl).catch(() => null);
50
+ await delay(500);
51
+ }
52
+ async function ensureTabPool(profile, apiUrl, requiredTotal = 5) {
53
+ const existing = await listPages(profile, apiUrl);
54
+ const currentCount = existing.pages.length;
55
+ const needed = Math.max(0, requiredTotal - currentCount);
56
+ if (needed > 0) {
57
+ for (let i = 0; i < needed; i += 1) {
58
+ await openTabViaWindowOpen(profile, apiUrl);
59
+ }
60
+ }
61
+ const finalPages = await listPages(profile, apiUrl);
62
+ return finalPages.pages.slice(1, requiredTotal).map((p) => ({ index: p.index, pageId: p.pageId }));
63
+ }
64
+ async function scrollCommentSection(profile, apiUrl, distance = 600) {
65
+ const res = await controllerAction('container:operation', {
66
+ containerId: 'xiaohongshu_detail.comment_section',
67
+ operationId: 'scroll',
68
+ sessionId: profile,
69
+ config: { direction: 'down', distance, repeat: 1 },
70
+ }, apiUrl).catch(() => null);
71
+ return res?.success !== false;
72
+ }
73
+ async function isCommentEnd(profile, apiUrl) {
74
+ const res = await controllerAction('container:operation', {
75
+ containerId: 'xiaohongshu_detail.comment_section.end_marker',
76
+ operationId: 'extract',
77
+ sessionId: profile,
78
+ config: { max_items: 1, visibleOnly: true },
79
+ }, apiUrl).catch(() => null);
80
+ const items = Array.isArray(res?.extracted) ? res.extracted : [];
81
+ return items.length > 0;
82
+ }
83
+ async function isCommentEmpty(profile, apiUrl) {
84
+ const res = await controllerAction('container:operation', {
85
+ containerId: 'xiaohongshu_detail.comment_section.empty_state',
86
+ operationId: 'extract',
87
+ sessionId: profile,
88
+ config: { max_items: 1, visibleOnly: true },
89
+ }, apiUrl).catch(() => null);
90
+ const items = Array.isArray(res?.extracted) ? res.extracted : [];
91
+ return items.length > 0;
92
+ }
93
+ async function extractComments(profile, apiUrl, limit) {
94
+ const res = await controllerAction('container:operation', {
95
+ containerId: 'xiaohongshu_detail.comment_section.comment_item',
96
+ operationId: 'extract',
97
+ sessionId: profile,
98
+ config: { max_items: limit, visibleOnly: true },
99
+ }, apiUrl).catch(() => null);
100
+ return Array.isArray(res?.extracted) ? res.extracted : [];
101
+ }
102
+ async function clickShowMore(profile, apiUrl) {
103
+ await controllerAction('container:operation', {
104
+ containerId: 'xiaohongshu_detail.comment_section.show_more_button',
105
+ operationId: 'click',
106
+ sessionId: profile,
107
+ config: { scroll_to_view: true, wait_after: 500, visibleOnly: true },
108
+ }, apiUrl).catch(() => null);
109
+ }
110
+ export async function execute(input) {
111
+ const { profile, keyword, env, links, maxCommentsPerNote = 50, unifiedApiUrl = 'http://127.0.0.1:7701', } = input;
112
+ const downloadRoot = resolveDownloadRoot();
113
+ console.log(`[Phase4MultiTab] 开始多Tab轮转采集,总链接: ${links.length}`);
114
+ const tabPool = await ensureTabPool(profile, unifiedApiUrl, 5);
115
+ const workers = [
116
+ { slot: 1, tabIndex: tabPool[0]?.index ?? 1, currentLinkIndex: 0, commentsThisRound: 0, totalComments: 0 },
117
+ { slot: 2, tabIndex: tabPool[1]?.index ?? 2, currentLinkIndex: 1, commentsThisRound: 0, totalComments: 0 },
118
+ { slot: 3, tabIndex: tabPool[2]?.index ?? 3, currentLinkIndex: 2, commentsThisRound: 0, totalComments: 0 },
119
+ { slot: 4, tabIndex: tabPool[3]?.index ?? 4, currentLinkIndex: 3, commentsThisRound: 0, totalComments: 0 },
120
+ ];
121
+ const linkStates = links.map((l, i) => ({
122
+ ...l,
123
+ index: i,
124
+ done: false,
125
+ totalComments: 0,
126
+ }));
127
+ let completedLinks = 0;
128
+ const errors = [];
129
+ let round = 0;
130
+ const maxRounds = links.length * 2;
131
+ while (completedLinks < links.length && round < maxRounds) {
132
+ round++;
133
+ const worker = workers[(round - 1) % workers.length];
134
+ let linkToProcess = linkStates.find(l => !l.done && l.index >= worker.currentLinkIndex);
135
+ if (!linkToProcess) {
136
+ linkToProcess = linkStates.find(l => !l.done);
137
+ }
138
+ if (!linkToProcess) {
139
+ console.log(`[Phase4MultiTab] 所有链接已完成`);
140
+ break;
141
+ }
142
+ worker.currentLinkIndex = linkToProcess.index;
143
+ console.log(`\n[Round ${round}] slot-${worker.slot}(tab-${worker.tabIndex}) -> note ${linkToProcess.noteId}`);
144
+ try {
145
+ const activeInfo = await switchToTab(profile, unifiedApiUrl, worker.tabIndex);
146
+ console.log(`[Phase4MultiTab] activeIndex=${activeInfo.activeIndex} url=${String(activeInfo.activeUrl).slice(0, 60)}`);
147
+ const navRes = await controllerAction('browser:goto', {
148
+ profile,
149
+ url: linkToProcess.safeUrl,
150
+ }, unifiedApiUrl);
151
+ const navOk = navRes?.success === true || navRes?.result?.ok === true || navRes?.ok === true;
152
+ if (!navOk) {
153
+ console.log(`[Phase4MultiTab] navRes=${JSON.stringify(navRes)}`);
154
+ throw new Error(`导航失败: ${navRes?.error || JSON.stringify(navRes)}`);
155
+ }
156
+ await delay(2000);
157
+ await controllerAction('container:operation', {
158
+ containerId: 'xiaohongshu_detail.comment_button',
159
+ operationId: 'highlight',
160
+ sessionId: profile,
161
+ }, unifiedApiUrl).catch(() => null);
162
+ await controllerAction('container:operation', {
163
+ containerId: 'xiaohongshu_detail.comment_button',
164
+ operationId: 'click',
165
+ sessionId: profile,
166
+ config: { useSystemMouse: true, visibleOnly: true },
167
+ }, unifiedApiUrl).catch(() => null);
168
+ await delay(1200);
169
+ let collected = 0;
170
+ let scrollAttempts = 0;
171
+ const maxScrolls = Infinity;
172
+ await clickShowMore(profile, unifiedApiUrl);
173
+ await delay(800);
174
+ while (collected < maxCommentsPerNote && scrollAttempts < maxScrolls) {
175
+ const items = await extractComments(profile, unifiedApiUrl, maxCommentsPerNote - collected);
176
+ if (items.length === 0) {
177
+ const empty = await isCommentEmpty(profile, unifiedApiUrl);
178
+ if (empty) {
179
+ console.log(`[Phase4MultiTab] slot-${worker.slot} 评论区空`);
180
+ break;
181
+ }
182
+ await scrollCommentSection(profile, unifiedApiUrl, 650);
183
+ await delay(900);
184
+ scrollAttempts++;
185
+ continue;
186
+ }
187
+ const noteDir = path.join(downloadRoot, 'xiaohongshu', env, keyword, linkToProcess.noteId);
188
+ await ensureDir(noteDir);
189
+ const payload = items.map((item) => ({
190
+ ...item,
191
+ noteId: linkToProcess.noteId,
192
+ ts: new Date().toISOString(),
193
+ }));
194
+ await appendJsonl(path.join(noteDir, 'comments.jsonl'), payload);
195
+ collected += items.length;
196
+ scrollAttempts = 0;
197
+ const isEnd = await isCommentEnd(profile, unifiedApiUrl);
198
+ if (isEnd) {
199
+ console.log(`[Phase4MultiTab] slot-${worker.slot} 评论到底`);
200
+ break;
201
+ }
202
+ await clickShowMore(profile, unifiedApiUrl);
203
+ await delay(600);
204
+ await scrollCommentSection(profile, unifiedApiUrl, 650);
205
+ await delay(900);
206
+ }
207
+ worker.commentsThisRound = collected;
208
+ worker.totalComments += collected;
209
+ linkToProcess.totalComments += collected;
210
+ linkToProcess.done = true;
211
+ completedLinks++;
212
+ console.log(`[Phase4MultiTab] slot-${worker.slot} ✅ 采集 ${collected} 条,该帖累计 ${linkToProcess.totalComments} 条`);
213
+ console.log(`[Phase4MultiTab] 进度: ${completedLinks}/${links.length} 帖子完成`);
214
+ }
215
+ catch (err) {
216
+ const errorMsg = err?.message || String(err);
217
+ console.error(`[Phase4MultiTab] slot-${worker.slot} ❌ 失败: ${errorMsg}`);
218
+ errors.push(`${linkToProcess.noteId}: ${errorMsg}`);
219
+ linkToProcess.done = true;
220
+ completedLinks++;
221
+ }
222
+ await delay(800);
223
+ }
224
+ const totalComments = linkStates.reduce((sum, l) => sum + l.totalComments, 0);
225
+ console.log(`\n[Phase4MultiTab] 完成: ${completedLinks} 帖子, ${totalComments} 条评论`);
226
+ return {
227
+ success: true,
228
+ totalNotes: completedLinks,
229
+ totalComments,
230
+ errors,
231
+ };
232
+ }
233
+ //# sourceMappingURL=Phase4MultiTabHarvestBlock.js.map
@@ -0,0 +1,291 @@
1
+ /**
2
+ * Block: ReplyInteract(开发态:模拟回复)
3
+ *
4
+ * 职责:
5
+ * 1) 在指定评论上点击“回复”
6
+ * 2) 定位回复输入框并输入内容(系统级键盘)
7
+ * 3) 截图留证(包含高亮与 DEV 叠加文案)
8
+ *
9
+ * 约束:
10
+ * - 点击必须走坐标点击(mouse:click),禁止 DOM click
11
+ * - 不提交(不发送真正回复)
12
+ */
13
+ import path from 'node:path';
14
+ import { controllerAction, delay } from '../utils/controllerAction.js';
15
+ import { resolveDownloadRoot, savePngBase64, takeScreenshotBase64 } from './helpers/evidence.js';
16
+ async function findReplyButtonTarget(sessionId, apiUrl, commentVisibleIndex) {
17
+ const res = await controllerAction('browser:execute', {
18
+ profile: sessionId,
19
+ script: `(() => {
20
+ const idx = ${JSON.stringify(commentVisibleIndex)};
21
+ const isVisible = (el) => {
22
+ const r = el.getBoundingClientRect();
23
+ return r.width > 0 && r.height > 0 && r.bottom > 0 && r.top < window.innerHeight && r.right > 0 && r.left < window.innerWidth;
24
+ };
25
+ const items = Array.from(document.querySelectorAll('.comment-item')).filter(isVisible);
26
+ const root = items[idx];
27
+ if (!root) return { ok: false, reason: 'comment-not-found', total: items.length };
28
+
29
+ const textEq = (el, s) => (el && (el.textContent || '').replace(/\\s+/g,' ').trim() === s);
30
+ const candidates = Array.from(root.querySelectorAll('span.count,button,a,span,div'));
31
+ const raw = candidates.find(el => textEq(el, '回复')) || null;
32
+ if (!raw) return { ok: false, reason: 'reply-button-not-found' };
33
+
34
+ const target = raw.closest && (raw.closest('button,a,[role=\"button\"]') || raw) || raw;
35
+ const r = target.getBoundingClientRect();
36
+ if (!r || !r.width || !r.height) return { ok: false, reason: 'reply-rect-empty' };
37
+
38
+ const x1 = Math.max(0, r.left);
39
+ const y1 = Math.max(0, r.top);
40
+ const x2 = Math.min(window.innerWidth, r.right);
41
+ const y2 = Math.min(window.innerHeight, r.bottom);
42
+ const mx = Math.round((x1 + x2) / 2);
43
+ const my = Math.round((y1 + y2) / 2);
44
+ const pad = 10;
45
+ const points = [
46
+ { x: mx, y: my },
47
+ { x: Math.round(x1 + pad), y: my },
48
+ { x: Math.round(x2 - pad), y: my },
49
+ { x: mx, y: Math.round(y1 + pad) },
50
+ { x: mx, y: Math.round(y2 - pad) },
51
+ ].filter(p => Number.isFinite(p.x) && Number.isFinite(p.y) && p.x >= 0 && p.y >= 0 && p.x <= window.innerWidth && p.y <= window.innerHeight);
52
+
53
+ let clickPoint = points[0] || { x: mx, y: my };
54
+ for (const p of points) {
55
+ const hit = document.elementFromPoint(p.x, p.y);
56
+ if (hit && (hit === target || target.contains(hit))) { clickPoint = p; break; }
57
+ }
58
+
59
+ return {
60
+ ok: true,
61
+ rect: { x: Math.round(r.left), y: Math.round(r.top), width: Math.round(r.width), height: Math.round(r.height) },
62
+ clickPoint,
63
+ };
64
+ })()`,
65
+ }, apiUrl);
66
+ const payload = res?.result || res?.data?.result || res;
67
+ return payload;
68
+ }
69
+ async function findReplyInputTarget(sessionId, apiUrl) {
70
+ const res = await controllerAction('browser:execute', {
71
+ profile: sessionId,
72
+ script: `(() => {
73
+ const isVisible = (el) => {
74
+ if (!el || !el.getBoundingClientRect) return false;
75
+ const r = el.getBoundingClientRect();
76
+ return r.width > 0 && r.height > 0 && r.bottom > 0 && r.top < window.innerHeight && r.right > 0 && r.left < window.innerWidth;
77
+ };
78
+ const score = (el) => {
79
+ const ph = (el.getAttribute && (el.getAttribute('placeholder') || el.getAttribute('aria-label') || '')) || '';
80
+ const cls = (el.className || '').toString();
81
+ const hint = (ph + ' ' + cls).replace(/\\s+/g,' ').trim();
82
+ let s = 0;
83
+ if (hint.includes('回复')) s += 4;
84
+ if (hint.includes('评论') || hint.includes('说点什么') || hint.includes('说说')) s += 2;
85
+ if (cls.includes('reply')) s += 3;
86
+ if (cls.includes('comment')) s += 1;
87
+ return s;
88
+ };
89
+
90
+ const active = document.activeElement;
91
+ const isInputLike = (el) => el && (el.tagName === 'TEXTAREA' || (el.tagName === 'INPUT') || (el.isContentEditable === true));
92
+ if (isInputLike(active) && isVisible(active)) {
93
+ const r = active.getBoundingClientRect();
94
+ const mx = Math.round((r.left + r.right) / 2);
95
+ const my = Math.round((r.top + r.bottom) / 2);
96
+ return { ok: true, rect: { x: Math.round(r.left), y: Math.round(r.top), width: Math.round(r.width), height: Math.round(r.height) }, clickPoint: { x: mx, y: my } };
97
+ }
98
+
99
+ const all = Array.from(document.querySelectorAll('textarea, input[type=\"text\"], input:not([type]), [contenteditable=\"true\"], [contenteditable=\"plaintext-only\"]'))
100
+ .filter(isVisible);
101
+ if (!all.length) return { ok: false, reason: 'no-visible-input' };
102
+
103
+ const best = all
104
+ .map((el) => ({ el, s: score(el) }))
105
+ .sort((a,b) => b.s - a.s)[0];
106
+ const el = best.el;
107
+ const r = el.getBoundingClientRect();
108
+ const mx = Math.round((r.left + r.right) / 2);
109
+ const my = Math.round((r.top + r.bottom) / 2);
110
+ return { ok: true, rect: { x: Math.round(r.left), y: Math.round(r.top), width: Math.round(r.width), height: Math.round(r.height) }, clickPoint: { x: mx, y: my } };
111
+ })()`,
112
+ }, apiUrl);
113
+ const payload = res?.result || res?.data?.result || res;
114
+ return payload;
115
+ }
116
+ async function drawOverlay(sessionId, apiUrl, opts) {
117
+ const ttlMs = typeof opts.ttlMs === 'number' ? Math.max(600, Math.min(15000, Math.floor(opts.ttlMs))) : 4000;
118
+ await controllerAction('browser:execute', {
119
+ profile: sessionId,
120
+ script: `(() => {
121
+ const id = ${JSON.stringify(opts.id)};
122
+ const rect = ${JSON.stringify(opts.rect || null)};
123
+ const color = ${JSON.stringify(opts.color)};
124
+ const label = ${JSON.stringify(opts.label || '')};
125
+ const ttl = ${JSON.stringify(ttlMs)};
126
+
127
+ const ensure = (elId, baseStyle) => {
128
+ let el = document.getElementById(elId);
129
+ if (!el) {
130
+ el = document.createElement('div');
131
+ el.id = elId;
132
+ document.body.appendChild(el);
133
+ }
134
+ Object.assign(el.style, baseStyle);
135
+ return el;
136
+ };
137
+
138
+ if (rect) {
139
+ ensure(id, {
140
+ position: 'fixed',
141
+ left: rect.x + 'px',
142
+ top: rect.y + 'px',
143
+ width: rect.width + 'px',
144
+ height: rect.height + 'px',
145
+ border: '3px solid ' + color,
146
+ boxSizing: 'border-box',
147
+ zIndex: '2147483647',
148
+ pointerEvents: 'none',
149
+ });
150
+ }
151
+
152
+ if (label) {
153
+ ensure(id + '-label', {
154
+ position: 'fixed',
155
+ left: '12px',
156
+ top: '12px',
157
+ maxWidth: '70vw',
158
+ padding: '8px 10px',
159
+ background: 'rgba(0,0,0,0.75)',
160
+ color: '#fff',
161
+ fontSize: '12px',
162
+ lineHeight: '1.3',
163
+ borderRadius: '8px',
164
+ zIndex: '2147483647',
165
+ pointerEvents: 'none',
166
+ whiteSpace: 'pre-wrap',
167
+ }).textContent = label;
168
+ }
169
+
170
+ setTimeout(() => {
171
+ try {
172
+ const a = document.getElementById(id);
173
+ if (a && a.parentElement) a.parentElement.removeChild(a);
174
+ const b = document.getElementById(id + '-label');
175
+ if (b && b.parentElement) b.parentElement.removeChild(b);
176
+ } catch {}
177
+ }, ttl);
178
+
179
+ return true;
180
+ })()`,
181
+ }, apiUrl).catch(() => null);
182
+ }
183
+ async function verifyTyped(sessionId, apiUrl, expected) {
184
+ const res = await controllerAction('browser:execute', {
185
+ profile: sessionId,
186
+ script: `(() => {
187
+ const exp = ${JSON.stringify(expected)};
188
+ const el = document.activeElement;
189
+ if (!el) return { ok: false, value: '' };
190
+ let v = '';
191
+ if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) v = el.value || '';
192
+ else if (el instanceof HTMLElement && el.isContentEditable) v = (el.textContent || '');
193
+ v = (v || '').replace(/\\s+/g,' ').trim();
194
+ return { ok: true, value: v, contains: exp ? v.includes(exp) : false };
195
+ })()`,
196
+ }, apiUrl).catch(() => null);
197
+ const payload = res?.result || res?.data?.result || res;
198
+ return Boolean(payload?.contains);
199
+ }
200
+ export async function execute(input) {
201
+ const { sessionId, noteId, commentVisibleIndex, replyText, dryRun = false, unifiedApiUrl = 'http://127.0.0.1:7701', env = 'debug', keyword = 'unknown', dev = true, } = input;
202
+ let screenshot = null;
203
+ let replyButtonRect = undefined;
204
+ let replyInputRect = undefined;
205
+ try {
206
+ const btn = await findReplyButtonTarget(sessionId, unifiedApiUrl, commentVisibleIndex);
207
+ if (!btn.ok || !btn.clickPoint || !btn.rect) {
208
+ throw new Error(`reply button not found: ${btn.reason || 'unknown'}`);
209
+ }
210
+ replyButtonRect = btn.rect;
211
+ await drawOverlay(sessionId, unifiedApiUrl, {
212
+ id: 'webauto-reply-button-rect',
213
+ rect: btn.rect,
214
+ color: '#00e5ff',
215
+ ttlMs: 6000,
216
+ });
217
+ await delay(350);
218
+ if (!dryRun) {
219
+ // ✅ 坐标点击(系统点击)
220
+ await controllerAction('mouse:click', { profileId: sessionId, x: Math.round(btn.clickPoint.x), y: Math.round(btn.clickPoint.y) }, unifiedApiUrl);
221
+ await delay(700);
222
+ }
223
+ else {
224
+ await delay(450);
225
+ }
226
+ const inputTarget = await findReplyInputTarget(sessionId, unifiedApiUrl);
227
+ if (inputTarget.ok && inputTarget.clickPoint && inputTarget.rect) {
228
+ replyInputRect = inputTarget.rect;
229
+ await drawOverlay(sessionId, unifiedApiUrl, {
230
+ id: 'webauto-reply-input-rect',
231
+ rect: inputTarget.rect,
232
+ color: '#ff00ff',
233
+ ttlMs: 6000,
234
+ });
235
+ await delay(250);
236
+ if (!dryRun) {
237
+ // ✅ 坐标点击聚焦输入框
238
+ await controllerAction('mouse:click', { profileId: sessionId, x: Math.round(inputTarget.clickPoint.x), y: Math.round(inputTarget.clickPoint.y) }, unifiedApiUrl);
239
+ await delay(220);
240
+ // 清空(可选):dev 模式仍执行,避免误拼接
241
+ const isMac = process.platform === 'darwin';
242
+ await controllerAction('keyboard:press', { profileId: sessionId, key: isMac ? 'Meta+A' : 'Control+A' }, unifiedApiUrl).catch(() => { });
243
+ await delay(80);
244
+ await controllerAction('keyboard:press', { profileId: sessionId, key: 'Backspace' }, unifiedApiUrl).catch(() => { });
245
+ await delay(120);
246
+ // ✅ 系统级输入(不提交)
247
+ await controllerAction('keyboard:type', { profileId: sessionId, text: String(replyText || ''), delay: 90, submit: false }, unifiedApiUrl);
248
+ await delay(260);
249
+ }
250
+ else {
251
+ await delay(180);
252
+ }
253
+ }
254
+ const typed = !dryRun && replyInputRect
255
+ ? await verifyTyped(sessionId, unifiedApiUrl, String(replyText || '').slice(0, 6))
256
+ : false;
257
+ if (dev || dryRun) {
258
+ await drawOverlay(sessionId, unifiedApiUrl, {
259
+ id: 'webauto-dev-reply-label',
260
+ color: '#00ff00',
261
+ label: `[${dryRun ? 'DRYRUN' : 'DEV'}] note=${noteId} commentIdx=${commentVisibleIndex}\nreply: ${String(replyText || '').slice(0, 80)}`,
262
+ ttlMs: 9000,
263
+ });
264
+ await delay(180);
265
+ }
266
+ const base64 = await takeScreenshotBase64(sessionId, unifiedApiUrl);
267
+ if (base64) {
268
+ const outDir = path.join(resolveDownloadRoot(), 'xiaohongshu', env, keyword, 'smart-reply', noteId);
269
+ const name = `reply-dev-${String(commentVisibleIndex).padStart(3, '0')}-${Date.now()}.png`;
270
+ screenshot = await savePngBase64(base64, path.join(outDir, name));
271
+ }
272
+ return {
273
+ success: true,
274
+ noteId,
275
+ typed,
276
+ evidence: { screenshot },
277
+ debug: { replyButtonRect, replyInputRect },
278
+ };
279
+ }
280
+ catch (e) {
281
+ return {
282
+ success: false,
283
+ noteId,
284
+ typed: false,
285
+ evidence: { screenshot },
286
+ debug: { replyButtonRect, replyInputRect },
287
+ error: e?.message || String(e),
288
+ };
289
+ }
290
+ }
291
+ //# sourceMappingURL=ReplyInteractBlock.js.map