@web-auto/webauto 0.1.1 → 0.1.2

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 +247 -12
  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 +37 -9
  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,497 @@
1
+ /**
2
+ * Workflow Block: GoToSearchBlock
3
+ *
4
+ * 导航到搜索页并执行搜索(模拟人工操作)
5
+ * 警告:不要构造 search_result URL 直达,避免风控验证码
6
+ */
7
+ import { ensureHomePage, getCurrentUrl, urlKeywordEquals } from './helpers/searchPageState.js';
8
+ import { verifySearchBarAnchor, readSearchInputValue, executeSearch, performSystemClickFocus, controllerAction } from './helpers/searchExecutor.js';
9
+ import { waitForSearchResultsReady } from './helpers/searchResultWaiter.js';
10
+ import os from 'node:os';
11
+ import path from 'node:path';
12
+ import { promises as fs } from 'node:fs';
13
+ import { countPersistedNotes } from './helpers/persistedNotes.js';
14
+ import { isDebugArtifactsEnabled } from './helpers/debugArtifacts.js';
15
+ /**
16
+ * 导航到搜索页并执行搜索
17
+ *
18
+ * @param input - 输入参数
19
+ * @returns Promise<GoToSearchOutput>
20
+ */
21
+ export async function execute(input) {
22
+ const { sessionId, keyword, env = 'debug', serviceUrl = 'http://127.0.0.1:7701', debugDir, } = input;
23
+ const profile = sessionId;
24
+ const controllerUrl = `${serviceUrl}/v1/controller/action`;
25
+ const steps = [];
26
+ let entryAnchor;
27
+ let exitAnchor;
28
+ let searchInputContainerId = 'xiaohongshu_search.search_bar';
29
+ const debugEnabled = isDebugArtifactsEnabled();
30
+ function resolveDownloadRoot() {
31
+ const custom = process.env.WEBAUTO_DOWNLOAD_ROOT || process.env.WEBAUTO_DOWNLOAD_DIR;
32
+ if (custom && custom.trim())
33
+ return custom;
34
+ const home = process.env.HOME || process.env.USERPROFILE || os.homedir();
35
+ return path.join(home, '.webauto', 'download');
36
+ }
37
+ function sanitizeFilenamePart(value) {
38
+ return String(value || '')
39
+ .trim()
40
+ .replace(/[\\/:"*?<>|]+/g, '_')
41
+ .replace(/\s+/g, '_')
42
+ .slice(0, 80);
43
+ }
44
+ function extractBase64FromScreenshotResponse(raw) {
45
+ const v = raw?.data?.data ??
46
+ raw?.data?.body?.data ??
47
+ raw?.body?.data ??
48
+ raw?.result?.data ??
49
+ raw?.result ??
50
+ raw?.data ??
51
+ raw;
52
+ return typeof v === 'string' && v.length > 10 ? v : undefined;
53
+ }
54
+ async function resolveDebugDir() {
55
+ if (!debugEnabled)
56
+ return null;
57
+ if (debugDir)
58
+ return debugDir;
59
+ try {
60
+ const persisted = await countPersistedNotes({
61
+ platform: 'xiaohongshu',
62
+ env,
63
+ keyword,
64
+ downloadRoot: resolveDownloadRoot(),
65
+ requiredFiles: ['content.md'],
66
+ });
67
+ return path.join(persisted.keywordDir, '_debug', 'search');
68
+ }
69
+ catch {
70
+ return null;
71
+ }
72
+ }
73
+ async function saveDebugScreenshot(kind, meta) {
74
+ if (!debugEnabled)
75
+ return {};
76
+ const dir = await resolveDebugDir();
77
+ if (!dir)
78
+ return {};
79
+ try {
80
+ await fs.mkdir(dir, { recursive: true });
81
+ const ts = new Date().toISOString().replace(/[:.]/g, '-');
82
+ const base = `${ts}-${sanitizeFilenamePart(kind)}`;
83
+ const pngPath = path.join(dir, `${base}.png`);
84
+ const jsonPath = path.join(dir, `${base}.json`);
85
+ const shot = await controllerAction(controllerUrl, 'browser:screenshot', {
86
+ profileId: profile,
87
+ fullPage: false,
88
+ });
89
+ const b64 = extractBase64FromScreenshotResponse(shot);
90
+ if (b64) {
91
+ await fs.writeFile(pngPath, Buffer.from(b64, 'base64'));
92
+ }
93
+ await fs.writeFile(jsonPath, JSON.stringify({
94
+ ts,
95
+ kind,
96
+ sessionId: profile,
97
+ keyword,
98
+ url: await getCurrentUrl({ profile, controllerUrl }).catch(() => ''),
99
+ ...meta,
100
+ pngPath: b64 ? pngPath : null,
101
+ }, null, 2), 'utf-8');
102
+ console.log(`[GoToSearch][debug] saved ${kind}: ${pngPath}`);
103
+ return { pngPath: b64 ? pngPath : undefined, jsonPath };
104
+ }
105
+ catch (e) {
106
+ console.warn(`[GoToSearch][debug] save screenshot failed (${kind}): ${e?.message || String(e)}`);
107
+ return {};
108
+ }
109
+ }
110
+ function pushStep(step) {
111
+ steps.push(step);
112
+ try {
113
+ console.log('[GoToSearch][step]', JSON.stringify({
114
+ id: step.id,
115
+ status: step.status,
116
+ error: step.error,
117
+ anchor: step.anchor,
118
+ meta: step.meta,
119
+ }, null, 2));
120
+ }
121
+ catch {
122
+ console.log('[GoToSearch][step]', step.id, step.status);
123
+ }
124
+ }
125
+ try {
126
+ // 0) 如果已经在正确的搜索结果页,则禁止“重复搜索”:直接等待列表就绪后返回
127
+ const url0 = await getCurrentUrl({ profile, controllerUrl });
128
+ if (url0.includes('/search_result')) {
129
+ if (!urlKeywordEquals(url0, keyword)) {
130
+ // 开发阶段:不做任何兜底纠错,直接失败并落盘证据(用于定位 keyword 漂移原因)
131
+ pushStep({
132
+ id: 'already_on_search_result_keyword_mismatch',
133
+ status: 'failed',
134
+ meta: { url: url0, keyword },
135
+ error: 'keyword_mismatch',
136
+ });
137
+ await saveDebugScreenshot('keyword_mismatch', { url: url0, keyword });
138
+ return {
139
+ success: false,
140
+ searchPageReady: false,
141
+ searchExecuted: false,
142
+ url: url0,
143
+ steps,
144
+ error: `keyword_changed: ${url0}`,
145
+ };
146
+ }
147
+ const ready = await waitForSearchResultsReady({
148
+ profile,
149
+ controllerUrl,
150
+ keyword,
151
+ maxWaitMs: 12000,
152
+ });
153
+ if (!ready.ok) {
154
+ pushStep({
155
+ id: 'already_on_search_result_wait_list',
156
+ status: 'failed',
157
+ error: ready.noResults ? 'search_no_results' : 'search_result_not_ready',
158
+ meta: { url: ready.url || url0 },
159
+ });
160
+ await saveDebugScreenshot('search_result_not_ready', { url: ready.url || url0 });
161
+ return {
162
+ success: false,
163
+ searchPageReady: false,
164
+ searchExecuted: false,
165
+ url: ready.url || url0,
166
+ steps,
167
+ error: ready.noResults ? 'Search returned no results' : 'Search results not ready (timeout)',
168
+ };
169
+ }
170
+ if (ready.listAnchor?.rect) {
171
+ exitAnchor = {
172
+ containerId: 'xiaohongshu_search.search_result_list',
173
+ selector: ready.listAnchor.selector,
174
+ rect: ready.listAnchor.rect,
175
+ verified: true,
176
+ };
177
+ }
178
+ pushStep({
179
+ id: 'already_on_search_result',
180
+ status: 'success',
181
+ anchor: exitAnchor,
182
+ meta: { url: ready.url || url0 },
183
+ });
184
+ return {
185
+ success: true,
186
+ searchPageReady: true,
187
+ searchExecuted: false,
188
+ url: ready.url || url0,
189
+ entryAnchor: undefined,
190
+ exitAnchor,
191
+ steps,
192
+ anchor: exitAnchor || {
193
+ containerId: 'xiaohongshu_search.search_result_list',
194
+ verified: false,
195
+ },
196
+ };
197
+ }
198
+ // 注意:SearchGate 节流由上游 workflow 的 WaitSearchPermitBlock 负责,这里不再重复申请 permit。
199
+ // 1. 确保在站内(最好是首页或搜索页)
200
+ const homePageState = await ensureHomePage({ profile, controllerUrl });
201
+ // 1.1 根据当前页面类型选择输入框容器(主页 / 搜索页)
202
+ searchInputContainerId = homePageState.onSearchPage
203
+ ? 'xiaohongshu_search.search_bar'
204
+ : 'xiaohongshu_home.search_input';
205
+ // 1.5 验证搜索框锚点
206
+ const anchorResult = await verifySearchBarAnchor({
207
+ profile,
208
+ controllerUrl,
209
+ searchInputContainerId,
210
+ keyword
211
+ });
212
+ if (!anchorResult.found) {
213
+ entryAnchor = {
214
+ containerId: searchInputContainerId,
215
+ selector: anchorResult.selector,
216
+ rect: anchorResult.rect,
217
+ verified: false,
218
+ };
219
+ console.log('[GoToSearch][entryAnchor]', JSON.stringify(entryAnchor, null, 2));
220
+ pushStep({
221
+ id: 'verify_search_bar_anchor',
222
+ status: 'failed',
223
+ error: anchorResult.error || 'anchor_not_found',
224
+ anchor: entryAnchor,
225
+ });
226
+ await saveDebugScreenshot('search_bar_anchor_not_found', {
227
+ searchInputContainerId,
228
+ selector: anchorResult.selector,
229
+ rect: anchorResult.rect,
230
+ error: anchorResult.error || 'anchor_not_found',
231
+ });
232
+ return {
233
+ success: false,
234
+ searchPageReady: false,
235
+ searchExecuted: false,
236
+ url: '',
237
+ entryAnchor,
238
+ exitAnchor: undefined,
239
+ steps,
240
+ anchor: {
241
+ containerId: searchInputContainerId,
242
+ selector: anchorResult.selector,
243
+ verified: false
244
+ },
245
+ error: `Search bar anchor not found: ${anchorResult.error || 'unknown error'}`
246
+ };
247
+ }
248
+ // 1.6 执行 container:operation highlight
249
+ try {
250
+ await controllerAction(controllerUrl, 'container:operation', {
251
+ containerId: searchInputContainerId,
252
+ operationId: 'highlight',
253
+ config: {
254
+ selector: anchorResult.selector,
255
+ style: '3px solid #ff4444',
256
+ duration: 2000,
257
+ },
258
+ sessionId: profile
259
+ });
260
+ console.log('[GoToSearch] Search bar highlighted successfully');
261
+ }
262
+ catch (error) {
263
+ console.warn('[GoToSearch] Highlight error:', error.message);
264
+ }
265
+ // 1.7 获取 Rect 并验证
266
+ const rect = anchorResult.rect;
267
+ const rectVerified = rect && rect.y < 200 && rect.width > 0 && rect.height > 0;
268
+ if (!rectVerified) {
269
+ console.warn(`[GoToSearch] Rect validation failed: ${JSON.stringify(rect)}`);
270
+ }
271
+ else {
272
+ console.log(`[GoToSearch] Rect verified: y=${rect.y}, width=${rect.width}, height=${rect.height}`);
273
+ }
274
+ entryAnchor = {
275
+ containerId: searchInputContainerId,
276
+ selector: anchorResult.selector,
277
+ rect,
278
+ verified: Boolean(rectVerified),
279
+ };
280
+ console.log('[GoToSearch][entryAnchor]', JSON.stringify(entryAnchor, null, 2));
281
+ pushStep({
282
+ id: 'verify_search_bar_anchor',
283
+ status: rectVerified ? 'success' : 'success',
284
+ anchor: entryAnchor,
285
+ });
286
+ // 1.8 使用容器运行时 + 系统点击聚焦搜索框
287
+ if (anchorResult.selector) {
288
+ const clickResult = await performSystemClickFocus({ profile, controllerUrl, searchInputContainerId, keyword }, anchorResult.selector);
289
+ pushStep({
290
+ id: 'system_click_focus_input',
291
+ status: clickResult.focused ? 'success' : 'failed',
292
+ anchor: entryAnchor,
293
+ meta: { focused: clickResult.focused },
294
+ error: clickResult.error
295
+ });
296
+ if (!clickResult.focused) {
297
+ await saveDebugScreenshot('search_input_not_focused', {
298
+ searchInputContainerId,
299
+ selector: anchorResult.selector,
300
+ rect,
301
+ error: clickResult.error || 'not_focused',
302
+ });
303
+ return {
304
+ success: false,
305
+ searchPageReady: false,
306
+ searchExecuted: false,
307
+ url: await getCurrentUrl({ profile, controllerUrl }),
308
+ entryAnchor,
309
+ exitAnchor: undefined,
310
+ steps,
311
+ anchor: entryAnchor,
312
+ error: 'Search input not focused after system click',
313
+ };
314
+ }
315
+ }
316
+ else {
317
+ console.warn('[GoToSearch] Skip system click: no selector from anchorResult');
318
+ pushStep({
319
+ id: 'system_click_focus_input',
320
+ status: 'skipped',
321
+ anchor: entryAnchor,
322
+ meta: { reason: 'no_selector' },
323
+ });
324
+ }
325
+ // 2. 执行搜索
326
+ const searchResult = await executeSearch({ profile, controllerUrl, searchInputContainerId, keyword }, anchorResult.selector);
327
+ const finalUrl = await getCurrentUrl({ profile, controllerUrl });
328
+ // 2.1 检查输入框中的值是否为当前关键字
329
+ const currentValue = await readSearchInputValue({ profile, controllerUrl, searchInputContainerId, keyword }, anchorResult.selector);
330
+ const trimmedValue = currentValue.trim();
331
+ const trimmedExpected = keyword.trim();
332
+ // 主页搜索:触发回车后可能立刻跳转,旧输入框消失导致读到空值;开发阶段不把该校验作为失败依据
333
+ const valueCheckSkipped = !trimmedValue;
334
+ const valueMatches = valueCheckSkipped ? true : trimmedValue === trimmedExpected;
335
+ pushStep({
336
+ id: 'system_type_keyword',
337
+ status: searchResult.success ? 'success' : 'failed',
338
+ anchor: entryAnchor,
339
+ meta: {
340
+ value: currentValue,
341
+ expected: keyword,
342
+ searchExecuted: searchResult.success,
343
+ valueCheckSkipped,
344
+ finalUrl,
345
+ debug: searchResult?.debug ?? null,
346
+ },
347
+ ...(searchResult.success
348
+ ? {}
349
+ : { error: searchResult.error || (!valueMatches ? 'keyword_mismatch' : 'type_failed') }),
350
+ });
351
+ if (!searchResult.success) {
352
+ await saveDebugScreenshot('search_trigger_failed', {
353
+ searchInputContainerId,
354
+ selector: anchorResult.selector,
355
+ rect,
356
+ error: searchResult.error || 'trigger_failed',
357
+ });
358
+ return {
359
+ success: false,
360
+ searchPageReady: false,
361
+ searchExecuted: false,
362
+ url: finalUrl,
363
+ entryAnchor,
364
+ exitAnchor: undefined,
365
+ steps,
366
+ error: searchResult.error || `Search input/trigger failed, current url=${finalUrl || 'unknown'}`,
367
+ };
368
+ }
369
+ // 2.5 等待搜索结果就绪
370
+ const ready = await waitForSearchResultsReady({
371
+ profile,
372
+ controllerUrl,
373
+ keyword,
374
+ maxWaitMs: 30000
375
+ });
376
+ if (!ready.ok) {
377
+ pushStep({
378
+ id: 'wait_search_result_list',
379
+ status: 'failed',
380
+ error: ready.noResults ? 'search_no_results' : 'search_result_not_ready',
381
+ anchor: {
382
+ containerId: 'xiaohongshu_search.search_result_list',
383
+ verified: false,
384
+ },
385
+ meta: { url: ready.url || finalUrl },
386
+ });
387
+ await saveDebugScreenshot('search_result_not_ready', {
388
+ url: ready.url || finalUrl,
389
+ noResults: Boolean(ready.noResults),
390
+ });
391
+ return {
392
+ success: false,
393
+ searchPageReady: false,
394
+ searchExecuted: true,
395
+ url: ready.url || finalUrl,
396
+ entryAnchor,
397
+ exitAnchor: undefined,
398
+ steps,
399
+ error: ready.noResults ? 'Search returned no results' : 'Search results not ready (timeout)',
400
+ };
401
+ }
402
+ // 2.6 严格校验:搜索结果页 keyword 必须严格等于输入 keyword(禁止接受推荐/纠错关键词)
403
+ // 注意:页面可能短暂进入 search_result 后被站点重定向到其它 keyword;这里以“当前 URL”为准做硬校验
404
+ const urlAfterReady = await getCurrentUrl({ profile, controllerUrl });
405
+ if (!urlKeywordEquals(urlAfterReady || ready.url || finalUrl, keyword)) {
406
+ pushStep({
407
+ id: 'search_result_keyword_mismatch',
408
+ status: 'failed',
409
+ error: 'keyword_mismatch',
410
+ meta: { url: urlAfterReady || ready.url || finalUrl, keyword },
411
+ });
412
+ await saveDebugScreenshot('keyword_mismatch_after_search', {
413
+ url: urlAfterReady || ready.url || finalUrl,
414
+ keyword,
415
+ finalUrl,
416
+ readyUrl: ready.url || null,
417
+ });
418
+ return {
419
+ success: false,
420
+ searchPageReady: false,
421
+ searchExecuted: true,
422
+ url: urlAfterReady || ready.url || finalUrl,
423
+ entryAnchor,
424
+ exitAnchor: undefined,
425
+ steps,
426
+ error: `keyword_mismatch_after_search: ${urlAfterReady || ready.url || finalUrl}`,
427
+ };
428
+ }
429
+ if (ready.listAnchor?.rect) {
430
+ exitAnchor = {
431
+ containerId: 'xiaohongshu_search.search_result_list',
432
+ selector: ready.listAnchor.selector,
433
+ rect: ready.listAnchor.rect,
434
+ verified: true,
435
+ };
436
+ console.log('[GoToSearch][exitAnchor]', JSON.stringify(exitAnchor, null, 2));
437
+ pushStep({
438
+ id: 'wait_search_result_list',
439
+ status: 'success',
440
+ anchor: exitAnchor,
441
+ meta: { url: ready.url || finalUrl },
442
+ });
443
+ }
444
+ else {
445
+ pushStep({
446
+ id: 'wait_search_result_list',
447
+ status: 'success',
448
+ anchor: {
449
+ containerId: 'xiaohongshu_search.search_result_list',
450
+ verified: false,
451
+ },
452
+ meta: { url: ready.url || finalUrl, note: 'items_detected_no_anchor' },
453
+ });
454
+ exitAnchor = undefined;
455
+ }
456
+ // 3. 检查是否出现验证码
457
+ const urlForCaptcha = urlAfterReady || ready.url || finalUrl;
458
+ if (urlForCaptcha.includes('captcha') || urlForCaptcha.includes('verify')) {
459
+ await saveDebugScreenshot('captcha_detected', { url: urlForCaptcha });
460
+ return {
461
+ success: false,
462
+ searchPageReady: false,
463
+ searchExecuted: true,
464
+ url: urlForCaptcha,
465
+ error: 'Triggered CAPTCHA after search'
466
+ };
467
+ }
468
+ return {
469
+ success: true,
470
+ searchPageReady: true,
471
+ searchExecuted: true,
472
+ url: urlAfterReady || ready.url || finalUrl,
473
+ entryAnchor,
474
+ exitAnchor,
475
+ steps,
476
+ anchor: {
477
+ containerId: searchInputContainerId,
478
+ selector: anchorResult.selector,
479
+ rect,
480
+ verified: rectVerified,
481
+ },
482
+ };
483
+ }
484
+ catch (error) {
485
+ return {
486
+ success: false,
487
+ searchPageReady: false,
488
+ searchExecuted: false,
489
+ url: '',
490
+ entryAnchor,
491
+ exitAnchor,
492
+ steps,
493
+ error: `GoToSearch failed: ${error.message}`
494
+ };
495
+ }
496
+ }
497
+ //# sourceMappingURL=GoToSearchBlock.js.map
@@ -0,0 +1,104 @@
1
+ export async function execute(input) {
2
+ const { primaryFn, fallbackFn, context, errorTypes = ['DEGRADED', 'TEMPORARY'] } = input;
3
+ try {
4
+ const result = await primaryFn();
5
+ return {
6
+ success: true,
7
+ result,
8
+ usedFallback: false
9
+ };
10
+ }
11
+ catch (err) {
12
+ const errorMsg = err.message || String(err);
13
+ // 检查是否属于可降级错误类型
14
+ const isDegradable = errorTypes.some(type => errorMsg.toLowerCase().includes(type.toLowerCase()));
15
+ if (!isDegradable) {
16
+ // 不可降级错误,直接抛出
17
+ throw err;
18
+ }
19
+ console.log(`[GracefulFallback] 主功能失败,启用降级方案: ${errorMsg}`);
20
+ try {
21
+ const fallbackResult = await fallbackFn();
22
+ return {
23
+ success: true,
24
+ result: fallbackResult,
25
+ usedFallback: true,
26
+ error: `降级处理: ${errorMsg}`
27
+ };
28
+ }
29
+ catch (fallbackErr) {
30
+ // 降级方案也失败,返回空结果
31
+ console.warn(`[GracefulFallback] 降级方案也失败: ${fallbackErr.message}`);
32
+ return {
33
+ success: false,
34
+ result: null,
35
+ usedFallback: true,
36
+ error: `主功能与降级方案均失败: ${errorMsg}`
37
+ };
38
+ }
39
+ }
40
+ }
41
+ /**
42
+ * 便捷函数:创建图片下载降级
43
+ */
44
+ export function createImageDownloadFallback(sessionId, imageUrls) {
45
+ return {
46
+ primaryFn: async () => {
47
+ // 主功能:目前仅返回全部 URL,由调用方负责下载
48
+ // (占位实现,避免依赖不存在的 downloadImage 辅助函数)
49
+ return imageUrls;
50
+ },
51
+ fallbackFn: async () => {
52
+ // 降级方案:只返回前 3 张 URL
53
+ return imageUrls.slice(0, 3);
54
+ }
55
+ };
56
+ }
57
+ /**
58
+ * 便捷函数:创建评论展开降级
59
+ */
60
+ export function createCommentExpandFallback(sessionId) {
61
+ return {
62
+ primaryFn: async () => {
63
+ // 主功能:完整评论展开(调用真实 ExpandCommentsBlock)
64
+ const { execute: expandComments } = await import('./ExpandCommentsBlock.js');
65
+ return await expandComments({ sessionId });
66
+ },
67
+ fallbackFn: async () => {
68
+ // 降级方案:只展开基础评论(不展开回复)
69
+ return {
70
+ success: true,
71
+ comments: [],
72
+ reachedEnd: false,
73
+ emptyState: true,
74
+ message: '降级:基础评论采集'
75
+ };
76
+ }
77
+ };
78
+ }
79
+ /**
80
+ * 便捷函数:创建详情提取降级
81
+ *
82
+ * 主路径走完整的 ExtractDetailBlock(包含 gallery.images 等字段);
83
+ * 只有在“可降级错误”时才返回一个仅含基础 header/content 的占位 detail,gallery.images 为空。
84
+ */
85
+ export function createDetailExtractFallback(sessionId) {
86
+ return {
87
+ primaryFn: async () => {
88
+ const { execute: extractDetail } = await import('./ExtractDetailBlock.js');
89
+ return await extractDetail({ sessionId });
90
+ },
91
+ fallbackFn: async () => {
92
+ return {
93
+ success: true,
94
+ detail: {
95
+ header: { title: '基础标题', author: '基础作者' },
96
+ content: { text: '' },
97
+ gallery: { images: [] }
98
+ },
99
+ message: '降级:基础详情提取'
100
+ };
101
+ }
102
+ };
103
+ }
104
+ //# sourceMappingURL=GracefulFallbackBlock.js.map
@@ -0,0 +1,66 @@
1
+ /**
2
+ * HighlightBlock - 基础高亮 Block
3
+ *
4
+ * 职责:
5
+ * - 封装 container:operation highlight 调用
6
+ * - 支持单个/批量容器高亮
7
+ * - 支持自定义样式和持续时间
8
+ * - 返回 rect/anchor 信息用于验证
9
+ * - 失败时降级(不阻塞主流程)
10
+ */
11
+ import { controllerAction } from '../../xiaohongshu/app/src/utils/controllerAction.js';
12
+ export class HighlightBlock {
13
+ unifiedApiUrl;
14
+ logger;
15
+ constructor(unifiedApiUrl, logger = console) {
16
+ this.unifiedApiUrl = unifiedApiUrl;
17
+ this.logger = logger;
18
+ }
19
+ async execute(input) {
20
+ const { sessionId, containerIds, durationMs = 1200, style = '2px solid #ffaa00', throwOnError = false } = input;
21
+ const ids = Array.isArray(containerIds) ? containerIds : [containerIds];
22
+ const highlighted = [];
23
+ const failed = [];
24
+ const anchors = new Map();
25
+ const results = await Promise.allSettled(ids.map((id) => this.highlightOne(sessionId, id, durationMs, style)));
26
+ for (let i = 0; i < results.length; i++) {
27
+ const result = results[i];
28
+ const id = ids[i];
29
+ if (result.status === 'fulfilled' && result.value) {
30
+ highlighted.push(id);
31
+ if (result.value.anchor || result.value.rect)
32
+ anchors.set(id, result.value);
33
+ }
34
+ else {
35
+ failed.push(id);
36
+ }
37
+ }
38
+ if (throwOnError && highlighted.length === 0) {
39
+ throw new Error(`HighlightBlock: all ${ids.length} container(s) failed to highlight`);
40
+ }
41
+ return {
42
+ success: highlighted.length > 0,
43
+ highlighted,
44
+ failed,
45
+ anchors
46
+ };
47
+ }
48
+ async highlightOne(sessionId, containerId, durationMs, style) {
49
+ const response = await controllerAction('container:operation', {
50
+ containerId,
51
+ operationId: 'highlight',
52
+ sessionId,
53
+ config: {
54
+ duration: durationMs,
55
+ style,
56
+ channel: 'highlight-block'
57
+ }
58
+ }, this.unifiedApiUrl);
59
+ return response;
60
+ }
61
+ }
62
+ export async function highlightContainers(unifiedApiUrl, sessionId, containerIds, options = {}) {
63
+ const block = new HighlightBlock(unifiedApiUrl, console);
64
+ return block.execute({ sessionId, containerIds, ...options });
65
+ }
66
+ //# sourceMappingURL=HighlightBlock.js.map