@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,474 @@
1
+ /**
2
+ * openDetailViewport.ts
3
+ *
4
+ * 视口与 DOM 相关的辅助工具:
5
+ * - 视口指标获取
6
+ * - 滚动容器推断
7
+ * - 滚动操作
8
+ * - 元素在视口内的确保(highlight + scroll 循环)
9
+ * - 封面 Rect 计算(by index / by noteId)
10
+ * - 点在封面内验证
11
+ * - Rect 高亮
12
+ * - 视口诊断信息 dump
13
+ */
14
+ /**
15
+ * 创建 OpenDetail 专用的视口工具集合
16
+ */
17
+ export function createOpenDetailViewportTools(config) {
18
+ const { controllerAction, profile, serviceUrl } = config;
19
+ async function getViewportMetrics() {
20
+ try {
21
+ const result = await controllerAction('browser:execute', {
22
+ profile,
23
+ script: '({ innerHeight: window.innerHeight || 0, innerWidth: window.innerWidth || 0 })',
24
+ });
25
+ const payload = result?.result ?? result?.data?.result ?? result;
26
+ return {
27
+ innerHeight: Number(payload?.innerHeight ?? 0),
28
+ innerWidth: Number(payload?.innerWidth ?? 0),
29
+ };
30
+ }
31
+ catch {
32
+ return { innerHeight: 0, innerWidth: 0 };
33
+ }
34
+ }
35
+ function inferScrollContainerId(itemContainerId) {
36
+ if (itemContainerId.includes('xiaohongshu_search.search_result_item')) {
37
+ return 'xiaohongshu_search.search_result_list';
38
+ }
39
+ if (itemContainerId.includes('xiaohongshu_home.feed_item')) {
40
+ return 'xiaohongshu_home.feed_list';
41
+ }
42
+ return null;
43
+ }
44
+ async function scrollTowardVisibility(direction, amount, containerId) {
45
+ const scrollContainerId = inferScrollContainerId(containerId);
46
+ const scrollAmount = Math.min(800, Math.max(120, Math.floor(Math.abs(amount))));
47
+ // 首选:列表容器滚动(系统滚轮/键盘),避免页面级 JS 滚动
48
+ if (scrollContainerId) {
49
+ try {
50
+ const op = await controllerAction('container:operation', {
51
+ containerId: scrollContainerId,
52
+ operationId: 'scroll',
53
+ sessionId: profile,
54
+ config: { direction, amount: scrollAmount },
55
+ });
56
+ const payload = op?.data ?? op;
57
+ const ok = Boolean(payload?.success ?? payload?.data?.success ?? op?.success);
58
+ if (ok) {
59
+ await new Promise((r) => setTimeout(r, 900));
60
+ return true;
61
+ }
62
+ }
63
+ catch {
64
+ // fall through
65
+ }
66
+ }
67
+ // 兜底:PageUp/PageDown(系统级)
68
+ try {
69
+ await controllerAction('keyboard:press', {
70
+ profileId: profile,
71
+ key: direction === 'up' ? 'PageUp' : 'PageDown',
72
+ });
73
+ await new Promise((r) => setTimeout(r, 900));
74
+ return true;
75
+ }
76
+ catch {
77
+ return false;
78
+ }
79
+ }
80
+ /**
81
+ * 通过 container:operation highlight + rect 提取
82
+ */
83
+ async function highlightByIndex(containerId, index, duration = 1200) {
84
+ const highlightResp = await controllerAction('container:operation', {
85
+ containerId,
86
+ operationId: 'highlight',
87
+ sessionId: profile,
88
+ config: { index, duration },
89
+ });
90
+ return rectFromOperationResponse(highlightResp);
91
+ }
92
+ /**
93
+ * 通过 selector highlight + rect 提取
94
+ */
95
+ async function highlightBySelector(containerId, selector, duration = 1200) {
96
+ const highlightResp = await controllerAction('container:operation', {
97
+ containerId,
98
+ operationId: 'highlight',
99
+ sessionId: profile,
100
+ config: { selector, index: 0, target: 'self', duration },
101
+ });
102
+ return rectFromOperationResponse(highlightResp);
103
+ }
104
+ /**
105
+ * 确保 selector 对应的元素完全在视口内(通过 highlight + scroll 循环)
106
+ */
107
+ async function ensureSelectorFullyInViewport(containerId, selector) {
108
+ const viewport = await getViewportMetrics();
109
+ const innerHeight = viewport.innerHeight || 0;
110
+ let rect = await highlightBySelector(containerId, selector, 800);
111
+ if (!rect)
112
+ return undefined;
113
+ if (!innerHeight)
114
+ return rect;
115
+ for (let attempt = 0; attempt < 12; attempt += 1) {
116
+ const top = rect.y;
117
+ const bottom = rect.y + rect.height;
118
+ const fullyVisible = rect.width > 0 && rect.height > 0 && top >= 0 && bottom <= innerHeight;
119
+ if (fullyVisible)
120
+ return rect;
121
+ const direction = top < 0 ? 'up' : 'down';
122
+ const delta = top < 0 ? Math.abs(top) : Math.max(0, bottom - innerHeight);
123
+ const ok = await scrollTowardVisibility(direction, Math.min(800, delta + 160), containerId);
124
+ if (!ok)
125
+ break;
126
+ rect = await highlightBySelector(containerId, selector, 800);
127
+ if (!rect)
128
+ break;
129
+ }
130
+ return rect;
131
+ }
132
+ /**
133
+ * 确保 domIndex 对应的元素完全在视口内
134
+ */
135
+ async function ensureDomIndexFullyInViewport(containerId, index) {
136
+ const viewport = await getViewportMetrics();
137
+ const innerHeight = viewport.innerHeight || 0;
138
+ let rect = await highlightByIndex(containerId, index, 800);
139
+ if (!rect)
140
+ return undefined;
141
+ if (!innerHeight)
142
+ return rect;
143
+ for (let attempt = 0; attempt < 12; attempt += 1) {
144
+ const top = rect.y;
145
+ const bottom = rect.y + rect.height;
146
+ const fullyVisible = rect.width > 0 && rect.height > 0 && top >= 0 && bottom <= innerHeight;
147
+ if (fullyVisible)
148
+ return rect;
149
+ const direction = top < 0 ? 'up' : 'down';
150
+ const delta = top < 0 ? Math.abs(top) : Math.max(0, bottom - innerHeight);
151
+ const ok = await scrollTowardVisibility(direction, Math.min(800, delta + 160), containerId);
152
+ if (!ok)
153
+ break;
154
+ rect = await highlightByIndex(containerId, index, 800);
155
+ if (!rect)
156
+ break;
157
+ }
158
+ return rect;
159
+ }
160
+ /**
161
+ * 通过 domIndex 计算封面(a.cover)的 Rect
162
+ */
163
+ async function computeCoverRectByIndex(index) {
164
+ try {
165
+ const res = await controllerAction('browser:execute', {
166
+ profile,
167
+ script: `(() => {
168
+ const cards = Array.from(document.querySelectorAll('.note-item'));
169
+ const card = cards[${index}];
170
+ if (!card) return null;
171
+ const cover = card.querySelector('a.cover');
172
+ if (!cover) return null;
173
+ const media = cover.querySelector('img,video');
174
+ const target = media || cover;
175
+ const r = target.getBoundingClientRect();
176
+ if (!r || !r.width || !r.height) return null;
177
+ const innerH = window.innerHeight || 0;
178
+ const inViewport = innerH ? (r.bottom > 0 && r.top < innerH) : true;
179
+ return { x: r.x, y: r.y, width: r.width, height: r.height, inViewport };
180
+ })()`,
181
+ });
182
+ const payload = res?.result ?? res?.data?.result ?? res;
183
+ if (payload &&
184
+ typeof payload.x === 'number' &&
185
+ typeof payload.y === 'number' &&
186
+ typeof payload.width === 'number' &&
187
+ typeof payload.height === 'number') {
188
+ return { x: payload.x, y: payload.y, width: payload.width, height: payload.height };
189
+ }
190
+ }
191
+ catch {
192
+ // ignore
193
+ }
194
+ return undefined;
195
+ }
196
+ /**
197
+ * 通过 domIndex 计算卡片(.note-item)的 Rect
198
+ * 用于“禁止点击显示不全的 note item”场景:必须确保整个卡片完全在视口安全区内。
199
+ */
200
+ async function computeCardRectByIndex(index) {
201
+ try {
202
+ const res = await controllerAction('browser:execute', {
203
+ profile,
204
+ script: `(() => {
205
+ const cards = Array.from(document.querySelectorAll('.note-item'));
206
+ const card = cards[${index}];
207
+ if (!card) return null;
208
+ const r = card.getBoundingClientRect();
209
+ if (!r || !r.width || !r.height) return null;
210
+ return { x: r.x, y: r.y, width: r.width, height: r.height };
211
+ })()`,
212
+ });
213
+ const payload = res?.result ?? res?.data?.result ?? res;
214
+ if (payload &&
215
+ typeof payload.x === 'number' &&
216
+ typeof payload.y === 'number' &&
217
+ typeof payload.width === 'number' &&
218
+ typeof payload.height === 'number') {
219
+ return { x: payload.x, y: payload.y, width: payload.width, height: payload.height };
220
+ }
221
+ }
222
+ catch {
223
+ // ignore
224
+ }
225
+ return undefined;
226
+ }
227
+ /**
228
+ * 通过 noteId 精确查找封面(a.cover)的 Rect
229
+ */
230
+ async function computeCoverRectByNoteId(noteId) {
231
+ const nid = String(noteId || '').trim();
232
+ if (!nid)
233
+ return undefined;
234
+ try {
235
+ const res = await controllerAction('browser:execute', {
236
+ profile,
237
+ script: `(() => {
238
+ const noteId = ${JSON.stringify(nid)};
239
+ const cards = Array.from(document.querySelectorAll('.note-item'));
240
+ for (const card of cards) {
241
+ try {
242
+ const cover = card.querySelector('a.cover');
243
+ if (!cover) continue;
244
+ const href = cover.getAttribute('href') || cover.href || '';
245
+ if (!href || href.indexOf(noteId) === -1) continue;
246
+ const media = cover.querySelector('img,video');
247
+ const target = media || cover;
248
+ const r = target.getBoundingClientRect();
249
+ if (!r || !r.width || !r.height) continue;
250
+ const innerH = window.innerHeight || 0;
251
+ const inViewport = innerH ? (r.bottom > 0 && r.top < innerH) : true;
252
+ return { x: r.x, y: r.y, width: r.width, height: r.height, inViewport };
253
+ } catch (_) {}
254
+ }
255
+ return null;
256
+ })()`,
257
+ });
258
+ const payload = res?.result ?? res?.data?.result ?? res;
259
+ if (payload &&
260
+ typeof payload.x === 'number' &&
261
+ typeof payload.y === 'number' &&
262
+ typeof payload.width === 'number' &&
263
+ typeof payload.height === 'number') {
264
+ return { x: payload.x, y: payload.y, width: payload.width, height: payload.height };
265
+ }
266
+ }
267
+ catch {
268
+ // ignore
269
+ }
270
+ return undefined;
271
+ }
272
+ /**
273
+ * 通过 noteId 精确查找卡片(.note-item)的 Rect
274
+ */
275
+ async function computeCardRectByNoteId(noteId) {
276
+ const nid = String(noteId || '').trim();
277
+ if (!nid)
278
+ return undefined;
279
+ try {
280
+ const res = await controllerAction('browser:execute', {
281
+ profile,
282
+ script: `(() => {
283
+ const noteId = ${JSON.stringify(nid)};
284
+ const cards = Array.from(document.querySelectorAll('.note-item'));
285
+ for (const card of cards) {
286
+ try {
287
+ const cover = card.querySelector('a.cover');
288
+ if (!cover) continue;
289
+ const href = cover.getAttribute('href') || cover.href || '';
290
+ if (!href || href.indexOf(noteId) === -1) continue;
291
+ const r = card.getBoundingClientRect();
292
+ if (!r || !r.width || !r.height) continue;
293
+ return { x: r.x, y: r.y, width: r.width, height: r.height };
294
+ } catch (_) {}
295
+ }
296
+ return null;
297
+ })()`,
298
+ });
299
+ const payload = res?.result ?? res?.data?.result ?? res;
300
+ if (payload &&
301
+ typeof payload.x === 'number' &&
302
+ typeof payload.y === 'number' &&
303
+ typeof payload.width === 'number' &&
304
+ typeof payload.height === 'number') {
305
+ return { x: payload.x, y: payload.y, width: payload.width, height: payload.height };
306
+ }
307
+ }
308
+ catch {
309
+ // ignore
310
+ }
311
+ return undefined;
312
+ }
313
+ /**
314
+ * 验证某个坐标点是否在封面(a.cover)内
315
+ */
316
+ async function isPointInsideCover(point) {
317
+ try {
318
+ const res = await controllerAction('browser:execute', {
319
+ profile,
320
+ script: `(() => {
321
+ const p = ${JSON.stringify(point)};
322
+ const el = document.elementFromPoint(p.x, p.y);
323
+ if (!el) return false;
324
+ const a = el.closest && el.closest('a.cover');
325
+ if (!a) return false;
326
+ const media = a.querySelector && a.querySelector('img,video');
327
+ const target = media || a;
328
+ const r = target.getBoundingClientRect();
329
+ if (!r || !r.width || !r.height) return false;
330
+ return p.x >= r.left && p.x <= r.right && p.y >= r.top && p.y <= r.bottom;
331
+ })()`,
332
+ });
333
+ const payload = res?.result ?? res?.data?.result ?? res;
334
+ return Boolean(payload);
335
+ }
336
+ catch {
337
+ return false;
338
+ }
339
+ }
340
+ /**
341
+ * 在页面上绘制高亮 Rect(用于视觉确认)
342
+ */
343
+ async function highlightRect(rect, durationMs = 1200, color = '#00ff00') {
344
+ try {
345
+ await controllerAction('browser:execute', {
346
+ profile,
347
+ script: `(() => {
348
+ const r = ${JSON.stringify(rect)};
349
+ let overlay = document.getElementById('webauto-click-rect');
350
+ if (!overlay) {
351
+ overlay = document.createElement('div');
352
+ overlay.id = 'webauto-click-rect';
353
+ overlay.style.position = 'fixed';
354
+ overlay.style.pointerEvents = 'none';
355
+ overlay.style.zIndex = '2147483647';
356
+ document.body.appendChild(overlay);
357
+ }
358
+ overlay.style.left = r.x + 'px';
359
+ overlay.style.top = r.y + 'px';
360
+ overlay.style.width = r.width + 'px';
361
+ overlay.style.height = r.height + 'px';
362
+ overlay.style.border = '3px solid ${color}';
363
+ overlay.style.boxSizing = 'border-box';
364
+ setTimeout(() => overlay && overlay.parentElement && overlay.parentElement.removeChild(overlay), ${durationMs});
365
+ return true;
366
+ })()`,
367
+ });
368
+ }
369
+ catch {
370
+ // ignore
371
+ }
372
+ }
373
+ /**
374
+ * 诊断:dump 当前视口内所有 .note-item 的 rect / title / href
375
+ */
376
+ async function dumpViewportDiagnostics() {
377
+ try {
378
+ const result = await controllerAction('browser:execute', {
379
+ profile,
380
+ script: `(() => {
381
+ const scrollY = window.scrollY || document.documentElement.scrollTop || 0;
382
+ const innerHeight = window.innerHeight || 0;
383
+ const items = Array.from(document.querySelectorAll('.note-item'));
384
+ const summary = items.map((el, idx) => {
385
+ const rect = el.getBoundingClientRect();
386
+ const titleEl = el.querySelector('.note-title, .title, [data-role="note-title"]');
387
+ const titleText = titleEl ? (titleEl.textContent || '').trim() : '';
388
+ let href = '';
389
+ const link = el.querySelector('a[href*="/explore/"], a[href*="/search_result/"]');
390
+ if (link instanceof HTMLAnchorElement) {
391
+ href = link.href || link.getAttribute('href') || '';
392
+ }
393
+ return {
394
+ index: idx,
395
+ rect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },
396
+ title: titleText,
397
+ href,
398
+ inViewport: rect.top >= 0 && rect.top < innerHeight,
399
+ };
400
+ });
401
+ return {
402
+ scrollY,
403
+ innerHeight,
404
+ totalItems: items.length,
405
+ visibleItems: summary.filter(i => i.inViewport).length,
406
+ items: summary.slice(0, 40),
407
+ };
408
+ })()`,
409
+ });
410
+ const diag = result.result || result.data?.result || result;
411
+ console.log('[OpenDetail][diagnostic] viewport summary:', JSON.stringify(diag));
412
+ }
413
+ catch (e) {
414
+ console.warn('[OpenDetail][diagnostic] dump viewport failed:', e.message || String(e));
415
+ }
416
+ }
417
+ return {
418
+ getViewportMetrics,
419
+ inferScrollContainerId,
420
+ scrollTowardVisibility,
421
+ highlightByIndex,
422
+ highlightBySelector,
423
+ ensureSelectorFullyInViewport,
424
+ ensureDomIndexFullyInViewport,
425
+ computeCoverRectByIndex,
426
+ computeCoverRectByNoteId,
427
+ computeCardRectByIndex,
428
+ computeCardRectByNoteId,
429
+ isPointInsideCover,
430
+ highlightRect,
431
+ dumpViewportDiagnostics,
432
+ };
433
+ }
434
+ /**
435
+ * 从 container:operation 响应中提取 Rect
436
+ */
437
+ function rectFromOperationResponse(raw) {
438
+ if (!raw || typeof raw !== 'object')
439
+ return undefined;
440
+ const payload = raw?.data ?? raw;
441
+ const rectData = payload?.rect ?? payload?.data?.rect;
442
+ if (!rectData || typeof rectData !== 'object')
443
+ return undefined;
444
+ if (typeof rectData.x === 'number' &&
445
+ typeof rectData.y === 'number' &&
446
+ typeof rectData.width === 'number' &&
447
+ typeof rectData.height === 'number') {
448
+ return { x: rectData.x, y: rectData.y, width: rectData.width, height: rectData.height };
449
+ }
450
+ if (typeof rectData.x1 === 'number' &&
451
+ typeof rectData.y1 === 'number' &&
452
+ typeof rectData.x2 === 'number' &&
453
+ typeof rectData.y2 === 'number') {
454
+ return {
455
+ x: rectData.x1,
456
+ y: rectData.y1,
457
+ width: rectData.x2 - rectData.x1,
458
+ height: rectData.y2 - rectData.y1,
459
+ };
460
+ }
461
+ if (typeof rectData.left === 'number' &&
462
+ typeof rectData.top === 'number' &&
463
+ typeof rectData.right === 'number' &&
464
+ typeof rectData.bottom === 'number') {
465
+ return {
466
+ x: rectData.left,
467
+ y: rectData.top,
468
+ width: rectData.right - rectData.left,
469
+ height: rectData.bottom - rectData.top,
470
+ };
471
+ }
472
+ return undefined;
473
+ }
474
+ //# sourceMappingURL=openDetailViewport.js.map
@@ -0,0 +1,104 @@
1
+ /**
2
+ * openDetailWaiter.ts
3
+ *
4
+ * 详情页就绪检测与"误点/回退"策略
5
+ */
6
+ /**
7
+ * 等待详情页就绪
8
+ */
9
+ export async function waitForDetail(deps, maxRetries = 10) {
10
+ const { getCurrentUrl, controllerAction, profile } = deps;
11
+ let safeUrl;
12
+ let noteId;
13
+ for (let i = 0; i < maxRetries; i++) {
14
+ const currentUrl = await getCurrentUrl();
15
+ // 个人主页/用户页:判定为误点(常见原因:点到作者头像/昵称)
16
+ if (currentUrl.includes('/user/profile')) {
17
+ return { ready: false };
18
+ }
19
+ // 0. 404 / 当前笔记暂时无法浏览 → 立即判定为失败
20
+ if (currentUrl.includes('/404') && currentUrl.includes('error_code=300031')) {
21
+ console.warn('[OpenDetail] Detected 404 note page, aborting detail wait');
22
+ return { ready: false };
23
+ }
24
+ // 1. 先用 URL 做一次快速检测:
25
+ // - /explore/{noteId}?...xsec_token=...
26
+ // - /search_result/{noteId}?...xsec_token=...
27
+ // 两者均视为详情已经就绪
28
+ if (currentUrl &&
29
+ (/\/explore\/[0-9a-z]+/i.test(currentUrl) || /\/search_result\/[0-9a-z]+/i.test(currentUrl)) &&
30
+ /[?&]xsec_token=/.test(currentUrl)) {
31
+ safeUrl = currentUrl;
32
+ const m = currentUrl.match(/\/(?:explore|search_result)\/([0-9a-z]+)/i);
33
+ noteId = m ? m[1] : undefined;
34
+ console.log('[OpenDetail] Detail URL ready (route + xsec_token)');
35
+ return { ready: true, safeUrl, noteId };
36
+ }
37
+ // 2. 再用 DOM 结构做一次检查(模态或评论区命中任意一个即可)
38
+ try {
39
+ const domResult = await controllerAction('browser:execute', {
40
+ profile,
41
+ script: `(() => {
42
+ const hasModal =
43
+ document.querySelector('.note-detail-mask') ||
44
+ document.querySelector('.note-detail-page') ||
45
+ document.querySelector('.note-detail-dialog') ||
46
+ document.querySelector('.note-detail') ||
47
+ document.querySelector('.detail-container') ||
48
+ document.querySelector('.media-container');
49
+ const hasComments =
50
+ document.querySelector('.comments-el') ||
51
+ document.querySelector('.comment-list') ||
52
+ document.querySelector('.comments-container');
53
+ return { hasModal: !!hasModal, hasComments: !!hasComments };
54
+ })()`,
55
+ });
56
+ const payload = domResult.result || domResult.data?.result || domResult;
57
+ if (payload?.hasModal || payload?.hasComments) {
58
+ const url = currentUrl || (await getCurrentUrl());
59
+ safeUrl = url && /[?&]xsec_token=/.test(url) ? url : undefined;
60
+ const m = url?.match(/\/(?:explore|search_result)\/([0-9a-z]+)/i);
61
+ noteId = m ? m[1] : undefined;
62
+ console.log('[OpenDetail] Detail DOM ready (hasModal/hasComments)');
63
+ return { ready: true, safeUrl, noteId };
64
+ }
65
+ console.log(`[OpenDetail] Detail not ready yet (iter=${i}, url=${currentUrl || 'unknown'})`);
66
+ }
67
+ catch (e) {
68
+ console.warn(`[OpenDetail] DOM readiness check failed (retry ${i}): ${e.message}`);
69
+ }
70
+ await new Promise((r) => setTimeout(r, 1000));
71
+ }
72
+ return { ready: false };
73
+ }
74
+ /**
75
+ * 误点后返回搜索列表
76
+ */
77
+ export async function backToSearchList(deps, maxWaitMs = 8000) {
78
+ const { controllerAction, profile, serviceUrl } = deps;
79
+ const { verifyAnchorByContainerId } = await import('./containerAnchors.js');
80
+ const listId = 'xiaohongshu_search.search_result_list';
81
+ const start = Date.now();
82
+ while (Date.now() - start < maxWaitMs) {
83
+ // 尝试系统级返回:优先 ESC,其次浏览器后退
84
+ for (const key of ['Escape', 'Meta+[', 'Alt+ArrowLeft']) {
85
+ try {
86
+ await controllerAction('keyboard:press', { profileId: profile, key });
87
+ }
88
+ catch {
89
+ // ignore
90
+ }
91
+ await new Promise((r) => setTimeout(r, 900));
92
+ try {
93
+ const anchor = await verifyAnchorByContainerId(listId, profile, serviceUrl, '2px solid #00bbff', 800);
94
+ if (anchor.found)
95
+ return true;
96
+ }
97
+ catch {
98
+ // ignore
99
+ }
100
+ }
101
+ }
102
+ return false;
103
+ }
104
+ //# sourceMappingURL=openDetailWaiter.js.map