@web-auto/webauto 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/apps/desktop-console/default-settings.json +1 -0
  2. package/apps/desktop-console/dist/main/index.mjs +1618 -0
  3. package/apps/desktop-console/{src → dist}/main/preload.mjs +10 -0
  4. package/apps/desktop-console/dist/renderer/index.js +3063 -0
  5. package/apps/desktop-console/entry/ui-console.mjs +299 -0
  6. package/apps/webauto/entry/account.mjs +356 -0
  7. package/apps/webauto/entry/lib/account-detect.mjs +160 -0
  8. package/apps/webauto/entry/lib/account-store.mjs +587 -0
  9. package/apps/webauto/entry/lib/profilepool.mjs +1 -1
  10. package/apps/webauto/entry/xhs-install.mjs +27 -3
  11. package/apps/webauto/entry/xhs-status.mjs +152 -0
  12. package/apps/webauto/entry/xhs-unified.mjs +595 -17
  13. package/bin/webauto.mjs +263 -15
  14. package/dist/apps/webauto/server.js +66 -0
  15. package/dist/modules/camo-backend/src/index.js +575 -0
  16. package/dist/modules/camo-backend/src/internal/BrowserSession.js +817 -0
  17. package/dist/modules/camo-backend/src/internal/ElementRegistry.js +61 -0
  18. package/dist/modules/camo-backend/src/internal/ProfileLock.js +85 -0
  19. package/dist/modules/camo-backend/src/internal/SessionManager.js +172 -0
  20. package/dist/modules/camo-backend/src/internal/container-matcher.js +852 -0
  21. package/dist/modules/camo-backend/src/internal/engine-manager.js +258 -0
  22. package/dist/modules/camo-backend/src/internal/fingerprint.js +203 -0
  23. package/dist/modules/camo-backend/src/internal/pageRuntime.js +29 -0
  24. package/dist/modules/camo-backend/src/internal/runtimeInjector.js +30 -0
  25. package/dist/modules/camo-backend/src/internal/state-bus.js +46 -0
  26. package/dist/modules/camo-backend/src/internal/storage-paths.js +36 -0
  27. package/dist/modules/camo-backend/src/internal/ws-server.js +1202 -0
  28. package/dist/modules/camo-runtime/src/utils/browser-service.mjs +423 -0
  29. package/dist/modules/camo-runtime/src/utils/config.mjs +77 -0
  30. package/dist/modules/container-registry/src/index.js +184 -0
  31. package/dist/modules/logging/src/index.js +92 -0
  32. package/dist/modules/operations/src/builtin.js +27 -0
  33. package/dist/modules/operations/src/container-binding.js +75 -0
  34. package/dist/modules/operations/src/executor.js +146 -0
  35. package/dist/modules/operations/src/operations/click.js +167 -0
  36. package/dist/modules/operations/src/operations/extract.js +204 -0
  37. package/dist/modules/operations/src/operations/find-child.js +17 -0
  38. package/dist/modules/operations/src/operations/highlight.js +138 -0
  39. package/dist/modules/operations/src/operations/key.js +61 -0
  40. package/dist/modules/operations/src/operations/navigate.js +148 -0
  41. package/dist/modules/operations/src/operations/scroll.js +126 -0
  42. package/dist/modules/operations/src/operations/type.js +190 -0
  43. package/dist/modules/operations/src/queue.js +100 -0
  44. package/dist/modules/operations/src/registry.js +11 -0
  45. package/dist/modules/operations/src/system/mouse.js +33 -0
  46. package/dist/modules/state/src/atomic-json.js +33 -0
  47. package/dist/modules/workflow/blocks/AnchorVerificationBlock.js +71 -0
  48. package/dist/modules/workflow/blocks/BehaviorRandomizer.js +26 -0
  49. package/dist/modules/workflow/blocks/CallWorkflowBlock.js +38 -0
  50. package/dist/modules/workflow/blocks/CloseDetailBlock.js +209 -0
  51. package/dist/modules/workflow/blocks/CollectBatch.js +137 -0
  52. package/dist/modules/workflow/blocks/CollectCommentsBlock.js +415 -0
  53. package/dist/modules/workflow/blocks/CollectSearchListBlock.js +599 -0
  54. package/dist/modules/workflow/blocks/CollectWeiboPosts.js +229 -0
  55. package/dist/modules/workflow/blocks/DetectPageStateBlock.js +259 -0
  56. package/dist/modules/workflow/blocks/EnsureLoginBlock.js +162 -0
  57. package/dist/modules/workflow/blocks/EnsureSession.js +426 -0
  58. package/dist/modules/workflow/blocks/ErrorClassifier.js +164 -0
  59. package/dist/modules/workflow/blocks/ErrorRecoveryBlock.js +319 -0
  60. package/dist/modules/workflow/blocks/ExpandCommentsBlock.js +1032 -0
  61. package/dist/modules/workflow/blocks/ExtractDetailBlock.js +310 -0
  62. package/dist/modules/workflow/blocks/ExtractPostFields.js +88 -0
  63. package/dist/modules/workflow/blocks/GenerateSmartReplyBlock.js +68 -0
  64. package/dist/modules/workflow/blocks/GoToSearchBlock.js +497 -0
  65. package/dist/modules/workflow/blocks/GracefulFallbackBlock.js +104 -0
  66. package/dist/modules/workflow/blocks/HighlightBlock.js +66 -0
  67. package/dist/modules/workflow/blocks/InitAutoScroll.js +65 -0
  68. package/dist/modules/workflow/blocks/LoadContainerDefinition.js +50 -0
  69. package/dist/modules/workflow/blocks/LoadContainerIndex.js +43 -0
  70. package/dist/modules/workflow/blocks/LocateAndGuardBlock.js +176 -0
  71. package/dist/modules/workflow/blocks/LoginRecoveryBlock.js +242 -0
  72. package/dist/modules/workflow/blocks/MatchContainers.js +64 -0
  73. package/dist/modules/workflow/blocks/MonitoringBlock.js +190 -0
  74. package/dist/modules/workflow/blocks/OpenDetailBlock.js +1240 -0
  75. package/dist/modules/workflow/blocks/OrganizeXhsNotesBlock.js +117 -0
  76. package/dist/modules/workflow/blocks/PersistXhsNoteBlock.js +270 -0
  77. package/dist/modules/workflow/blocks/PickSinglePost.js +69 -0
  78. package/dist/modules/workflow/blocks/ProgressTracker.js +125 -0
  79. package/dist/modules/workflow/blocks/RecordFixtureBlock.js +44 -0
  80. package/dist/modules/workflow/blocks/RenderMarkdown.js +48 -0
  81. package/dist/modules/workflow/blocks/SaveFile.js +54 -0
  82. package/dist/modules/workflow/blocks/ScrollNextBatch.js +72 -0
  83. package/dist/modules/workflow/blocks/SessionHealthBlock.js +73 -0
  84. package/dist/modules/workflow/blocks/StartBrowserService.js +45 -0
  85. package/dist/modules/workflow/blocks/ValidateContainerDefinition.js +67 -0
  86. package/dist/modules/workflow/blocks/ValidateExtract.js +35 -0
  87. package/dist/modules/workflow/blocks/WaitSearchPermitBlock.js +162 -0
  88. package/dist/modules/workflow/blocks/WaitStable.js +74 -0
  89. package/dist/modules/workflow/blocks/WarmupCommentsBlock.js +120 -0
  90. package/dist/modules/workflow/blocks/WorkflowExecutor.js +156 -0
  91. package/dist/modules/workflow/blocks/XiaohongshuCollectFromLinksBlock.js +1004 -0
  92. package/dist/modules/workflow/blocks/XiaohongshuCollectLinksBlock.js +1049 -0
  93. package/dist/modules/workflow/blocks/XiaohongshuFullCollectBlock.js +782 -0
  94. package/dist/modules/workflow/blocks/helpers/anchorVerify.js +198 -0
  95. package/dist/modules/workflow/blocks/helpers/asyncWorkQueue.js +53 -0
  96. package/dist/modules/workflow/blocks/helpers/commentScroller.js +334 -0
  97. package/dist/modules/workflow/blocks/helpers/commentSectionLocator.js +126 -0
  98. package/dist/modules/workflow/blocks/helpers/containerAnchors.js +301 -0
  99. package/dist/modules/workflow/blocks/helpers/debugArtifacts.js +6 -0
  100. package/dist/modules/workflow/blocks/helpers/downloadPaths.js +29 -0
  101. package/dist/modules/workflow/blocks/helpers/expandCommentsController.js +53 -0
  102. package/dist/modules/workflow/blocks/helpers/expandCommentsExtractor.js +129 -0
  103. package/dist/modules/workflow/blocks/helpers/macosVisionOcrPlugin.js +116 -0
  104. package/dist/modules/workflow/blocks/helpers/mergeXhsMarkdown.js +109 -0
  105. package/dist/modules/workflow/blocks/helpers/openDetailController.js +56 -0
  106. package/dist/modules/workflow/blocks/helpers/openDetailTypes.js +7 -0
  107. package/dist/modules/workflow/blocks/helpers/openDetailViewport.js +474 -0
  108. package/dist/modules/workflow/blocks/helpers/openDetailWaiter.js +104 -0
  109. package/dist/modules/workflow/blocks/helpers/operationLogger.js +195 -0
  110. package/dist/modules/workflow/blocks/helpers/persistedNotes.js +107 -0
  111. package/dist/modules/workflow/blocks/helpers/replyExpander.js +260 -0
  112. package/dist/modules/workflow/blocks/helpers/scrollIntoView.js +138 -0
  113. package/dist/modules/workflow/blocks/helpers/searchExecutor.js +328 -0
  114. package/dist/modules/workflow/blocks/helpers/searchGate.js +46 -0
  115. package/dist/modules/workflow/blocks/helpers/searchPageState.js +164 -0
  116. package/dist/modules/workflow/blocks/helpers/searchResultWaiter.js +64 -0
  117. package/dist/modules/workflow/blocks/helpers/simpleAnchor.js +134 -0
  118. package/dist/modules/workflow/blocks/helpers/smartReply.js +40 -0
  119. package/dist/modules/workflow/blocks/helpers/systemInput.js +635 -0
  120. package/dist/modules/workflow/blocks/helpers/targetCountMode.js +9 -0
  121. package/dist/modules/workflow/blocks/helpers/xhsCliArgs.js +80 -0
  122. package/dist/modules/workflow/blocks/helpers/xhsCommentDom.js +805 -0
  123. package/dist/modules/workflow/blocks/helpers/xhsNoteOrganizer.js +140 -0
  124. package/dist/modules/workflow/blocks/restore/RestorePhaseBlock.js +204 -0
  125. package/dist/modules/workflow/config/workflowRegistry.js +32 -0
  126. package/dist/modules/workflow/definitions/batch-collect-workflow.js +63 -0
  127. package/dist/modules/workflow/definitions/scroll-extract-workflow.js +74 -0
  128. package/dist/modules/workflow/definitions/xiaohongshu-collect-workflow-v2.js +81 -0
  129. package/dist/modules/workflow/definitions/xiaohongshu-collect-workflow.js +57 -0
  130. package/dist/modules/workflow/definitions/xiaohongshu-full-collect-workflow-v3.js +68 -0
  131. package/dist/modules/workflow/definitions/xiaohongshu-note-collect.js +49 -0
  132. package/dist/modules/workflow/definitions/xiaohongshu-phase1-workflow-v3.js +30 -0
  133. package/dist/modules/workflow/definitions/xiaohongshu-phase2-links-workflow-v3.js +40 -0
  134. package/dist/modules/workflow/definitions/xiaohongshu-phase3-collect-workflow-v1.js +54 -0
  135. package/dist/modules/workflow/definitions/xiaohongshu-phase34-from-links-workflow-v3.js +25 -0
  136. package/dist/modules/workflow/src/WeiboEventDrivenWorkflowRunner.js +308 -0
  137. package/dist/modules/workflow/src/context.js +70 -0
  138. package/dist/modules/workflow/src/index.js +5 -0
  139. package/dist/modules/workflow/src/orchestrator.js +230 -0
  140. package/dist/modules/workflow/src/runner.js +55 -0
  141. package/dist/modules/workflow/src/runtime.js +70 -0
  142. package/dist/modules/workflow/workflows/WeiboFeedExtractionWorkflow.js +359 -0
  143. package/dist/modules/workflow/workflows/XiaohongshuLoginWorkflow.js +110 -0
  144. package/dist/modules/xiaohongshu/app/src/blocks/MatchCommentsBlock.js +139 -0
  145. package/dist/modules/xiaohongshu/app/src/blocks/Phase1EnsureServicesBlock.js +36 -0
  146. package/dist/modules/xiaohongshu/app/src/blocks/Phase1MonitorCookieBlock.js +213 -0
  147. package/dist/modules/xiaohongshu/app/src/blocks/Phase1StartProfileBlock.js +121 -0
  148. package/dist/modules/xiaohongshu/app/src/blocks/Phase2CollectLinksBlock.js +1249 -0
  149. package/dist/modules/xiaohongshu/app/src/blocks/Phase2SearchBlock.js +703 -0
  150. package/dist/modules/xiaohongshu/app/src/blocks/Phase34CloseDetailBlock.js +41 -0
  151. package/dist/modules/xiaohongshu/app/src/blocks/Phase34CloseTabsBlock.js +44 -0
  152. package/dist/modules/xiaohongshu/app/src/blocks/Phase34CollectCommentsBlock.js +150 -0
  153. package/dist/modules/xiaohongshu/app/src/blocks/Phase34ExtractDetailBlock.js +117 -0
  154. package/dist/modules/xiaohongshu/app/src/blocks/Phase34OpenDetailBlock.js +102 -0
  155. package/dist/modules/xiaohongshu/app/src/blocks/Phase34OpenTabsBlock.js +109 -0
  156. package/dist/modules/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.js +117 -0
  157. package/dist/modules/xiaohongshu/app/src/blocks/Phase34ProcessSingleNoteBlock.js +114 -0
  158. package/dist/modules/xiaohongshu/app/src/blocks/Phase34ValidateLinksBlock.js +90 -0
  159. package/dist/modules/xiaohongshu/app/src/blocks/Phase3InteractBlock.js +1009 -0
  160. package/dist/modules/xiaohongshu/app/src/blocks/Phase4MultiTabHarvestBlock.js +233 -0
  161. package/dist/modules/xiaohongshu/app/src/blocks/ReplyInteractBlock.js +291 -0
  162. package/dist/modules/xiaohongshu/app/src/blocks/XhsDiscoverFallbackBlock.js +240 -0
  163. package/dist/modules/xiaohongshu/app/src/blocks/helpers/commentMatchDsl.js +126 -0
  164. package/dist/modules/xiaohongshu/app/src/blocks/helpers/commentMatcher.js +99 -0
  165. package/dist/modules/xiaohongshu/app/src/blocks/helpers/evidence.js +27 -0
  166. package/dist/modules/xiaohongshu/app/src/blocks/helpers/sharding.js +42 -0
  167. package/dist/modules/xiaohongshu/app/src/blocks/helpers/xhsComments.js +270 -0
  168. package/dist/modules/xiaohongshu/app/src/index.js +9 -0
  169. package/dist/modules/xiaohongshu/app/src/utils/checkpoints.js +222 -0
  170. package/dist/modules/xiaohongshu/app/src/utils/controllerAction.js +43 -0
  171. package/dist/services/controller/src/controller.js +1476 -0
  172. package/dist/services/controller/src/index.js +2 -0
  173. package/dist/services/controller/src/payload-normalizer.js +129 -0
  174. package/dist/services/shared/heartbeat.js +120 -0
  175. package/dist/services/shared/lib/errorHandler.js +2 -0
  176. package/dist/services/shared/serviceProcessLogger.js +139 -0
  177. package/dist/services/unified-api/RemoteBrowserSession.js +176 -0
  178. package/dist/services/unified-api/RemoteSessionManager.js +148 -0
  179. package/dist/services/unified-api/container-operations-handler.js +115 -0
  180. package/dist/services/unified-api/server.js +652 -0
  181. package/dist/services/unified-api/state-registry.js +274 -0
  182. package/dist/services/unified-api/task-persistence.js +66 -0
  183. package/dist/services/unified-api/task-state.js +130 -0
  184. package/modules/camo-runtime/src/autoscript/action-providers/xhs/search.mjs +12 -5
  185. package/modules/xiaohongshu/app/pnpm-lock.yaml +24 -0
  186. package/package.json +38 -10
  187. package/.beads/README.md +0 -81
  188. package/.beads/config.yaml +0 -67
  189. package/.beads/interactions.jsonl +0 -0
  190. package/.beads/issues.jsonl +0 -180
  191. package/.beads/metadata.json +0 -4
  192. package/.claude/settings.local.json +0 -10
  193. package/.github/workflows/ci.yml +0 -55
  194. package/AGENTS.md +0 -253
  195. package/apps/desktop-console/README.md +0 -27
  196. package/apps/desktop-console/package-lock.json +0 -897
  197. package/apps/desktop-console/package.json +0 -20
  198. package/apps/desktop-console/scripts/build-and-install.mjs +0 -19
  199. package/apps/desktop-console/scripts/build.mjs +0 -45
  200. package/apps/desktop-console/scripts/test-preload.mjs +0 -13
  201. package/apps/desktop-console/src/main/config.mts +0 -26
  202. package/apps/desktop-console/src/main/core-daemon-manager.mts +0 -131
  203. package/apps/desktop-console/src/main/desktop-settings.mts +0 -267
  204. package/apps/desktop-console/src/main/heartbeat-watchdog.mts +0 -50
  205. package/apps/desktop-console/src/main/heartbeat-watchdog.test.mts +0 -68
  206. package/apps/desktop-console/src/main/index-streaming.test.mts +0 -20
  207. package/apps/desktop-console/src/main/index.mts +0 -980
  208. package/apps/desktop-console/src/main/profile-store.mts +0 -239
  209. package/apps/desktop-console/src/main/profile-store.test.mts +0 -54
  210. package/apps/desktop-console/src/main/state-bridge.mts +0 -114
  211. package/apps/desktop-console/src/main/task-state-types.ts +0 -32
  212. package/apps/desktop-console/src/renderer/hooks/use-task-state.mts +0 -120
  213. package/apps/desktop-console/src/renderer/index.mts +0 -133
  214. package/apps/desktop-console/src/renderer/index.test.mts +0 -34
  215. package/apps/desktop-console/src/renderer/path-helpers.mts +0 -46
  216. package/apps/desktop-console/src/renderer/path-helpers.test.mts +0 -14
  217. package/apps/desktop-console/src/renderer/tabs/debug.mts +0 -48
  218. package/apps/desktop-console/src/renderer/tabs/debug.test.mts +0 -22
  219. package/apps/desktop-console/src/renderer/tabs/logs.mts +0 -421
  220. package/apps/desktop-console/src/renderer/tabs/logs.test.mts +0 -27
  221. package/apps/desktop-console/src/renderer/tabs/preflight.mts +0 -486
  222. package/apps/desktop-console/src/renderer/tabs/preflight.test.mts +0 -33
  223. package/apps/desktop-console/src/renderer/tabs/profile-pool.mts +0 -213
  224. package/apps/desktop-console/src/renderer/tabs/results.mts +0 -171
  225. package/apps/desktop-console/src/renderer/tabs/run.test.mts +0 -63
  226. package/apps/desktop-console/src/renderer/tabs/runtime.mts +0 -151
  227. package/apps/desktop-console/src/renderer/tabs/settings.mts +0 -146
  228. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/account-flow.mts +0 -486
  229. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/guide-browser-check.mts +0 -56
  230. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/helpers.mts +0 -262
  231. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/layout-block.mts +0 -430
  232. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/live-stats.mts +0 -847
  233. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/run-flow.mts +0 -443
  234. package/apps/desktop-console/src/renderer/tabs/xiaohongshu-state.mts +0 -425
  235. package/apps/desktop-console/src/renderer/tabs/xiaohongshu.mts +0 -497
  236. package/apps/desktop-console/src/renderer/tabs/xiaohongshu.test.mts +0 -291
  237. package/apps/desktop-console/src/renderer/ui-components.mts +0 -31
  238. package/docs/README_camoufox_chinese.md +0 -141
  239. package/docs/USAGE_V3.md +0 -163
  240. package/docs/arch/OCR_MACOS_PLUGIN.md +0 -39
  241. package/docs/arch/PORTS.md +0 -40
  242. package/docs/arch/REGRESSION_CHECKLIST.md +0 -121
  243. package/docs/arch/SEARCH_GATE.md +0 -224
  244. package/docs/arch/VIEWPORT_SAFETY.md +0 -182
  245. package/docs/arch/XIAOHONGSHU_OFFLINE_MOCK_DESIGN.md +0 -267
  246. package/docs/xiaohongshu-container-driven-summary.md +0 -221
  247. package/docs/xiaohongshu-full-collect-runbook.md +0 -134
  248. package/docs/xiaohongshu-next-steps.md +0 -228
  249. package/docs/xiaohongshu-quickstart.md +0 -73
  250. package/docs/xiaohongshu-workflow-summary.md +0 -227
  251. package/modules/container-registry/tests/container-registry.test.ts +0 -16
  252. package/modules/logging/tests/logging.test.ts +0 -38
  253. package/modules/operations/tests/operations.test.ts +0 -22
  254. package/modules/operations/tests/viewport-filter.test.ts +0 -161
  255. package/modules/operations/tests/visible-only.test.ts +0 -250
  256. package/modules/session-manager/tests/session-manager.test.ts +0 -23
  257. package/modules/state/src/atomic-json.test.ts +0 -30
  258. package/modules/state/src/paths.test.ts +0 -59
  259. package/modules/state/src/xiaohongshu-collect-state.test.ts +0 -259
  260. package/modules/workflow/blocks/AnchorVerificationBlock.d.ts.map +0 -1
  261. package/modules/workflow/blocks/AnchorVerificationBlock.js.map +0 -1
  262. package/modules/workflow/blocks/DetectPageStateBlock.d.ts.map +0 -1
  263. package/modules/workflow/blocks/DetectPageStateBlock.js.map +0 -1
  264. package/modules/workflow/blocks/ErrorRecoveryBlock.d.ts.map +0 -1
  265. package/modules/workflow/blocks/ErrorRecoveryBlock.js.map +0 -1
  266. package/modules/workflow/blocks/WaitSearchPermitBlock.d.ts.map +0 -1
  267. package/modules/workflow/blocks/WaitSearchPermitBlock.js.map +0 -1
  268. package/modules/workflow/blocks/helpers/containerAnchors.d.ts.map +0 -1
  269. package/modules/workflow/blocks/helpers/containerAnchors.js.map +0 -1
  270. package/modules/workflow/blocks/helpers/downloadPaths.test.ts +0 -62
  271. package/modules/workflow/blocks/helpers/mergeXhsMarkdown.test.ts +0 -121
  272. package/modules/workflow/blocks/helpers/operationLogger.d.ts.map +0 -1
  273. package/modules/workflow/blocks/helpers/operationLogger.js.map +0 -1
  274. package/modules/workflow/blocks/helpers/persistedNotes.test.ts +0 -268
  275. package/modules/workflow/blocks/helpers/searchPageState.d.ts.map +0 -1
  276. package/modules/workflow/blocks/helpers/searchPageState.js.map +0 -1
  277. package/modules/workflow/blocks/helpers/targetCountMode.test.ts +0 -29
  278. package/modules/workflow/blocks/helpers/xhsCliArgs.test.ts +0 -75
  279. package/modules/workflow/tests/smartReply.test.ts +0 -32
  280. package/modules/xiaohongshu/app/src/blocks/Phase3Interact.matcher.test.ts +0 -33
  281. package/modules/xiaohongshu/app/src/utils/__tests__/checkpoints.test.ts +0 -141
  282. package/modules/xiaohongshu/app/tests/commentMatchDsl.test.ts +0 -50
  283. package/modules/xiaohongshu/app/tests/commentMatcher.test.ts +0 -46
  284. package/modules/xiaohongshu/app/tests/sharding.test.ts +0 -31
  285. package/package-scripts.json +0 -8
  286. package/runtime/infra/utils/README.md +0 -13
  287. package/runtime/infra/utils/scripts/README.md +0 -0
  288. package/runtime/infra/utils/scripts/development/eval-in-session.mjs +0 -40
  289. package/runtime/infra/utils/scripts/development/highlight-search-containers.mjs +0 -35
  290. package/runtime/infra/utils/scripts/service/kill-port.mjs +0 -24
  291. package/runtime/infra/utils/scripts/service/start-api.mjs +0 -39
  292. package/runtime/infra/utils/scripts/service/start-browser-service.mjs +0 -106
  293. package/runtime/infra/utils/scripts/service/stop-api.mjs +0 -18
  294. package/runtime/infra/utils/scripts/service/stop-browser-service.mjs +0 -104
  295. package/runtime/infra/utils/scripts/test-services.mjs +0 -94
  296. package/services/shared/heartbeat.test.ts +0 -102
  297. package/services/unified-api/__tests__/task-state.test.ts +0 -95
  298. package/sitecustomize.py +0 -19
  299. package/tests/README.md +0 -194
  300. package/tests/e2e/workflows/weibo-feed-extraction.test.ts +0 -171
  301. package/tests/fixtures/data/container-definitions.json +0 -67
  302. package/tests/fixtures/pages/simple-page.html +0 -69
  303. package/tests/integration/01-test-container-match.mjs +0 -188
  304. package/tests/integration/02-test-dom-branch.mjs +0 -161
  305. package/tests/integration/03-test-container-operation-system.mjs +0 -91
  306. package/tests/integration/05-test-container-lifecycle-events.mjs +0 -224
  307. package/tests/integration/05-test-container-lifecycle-with-events.mjs +0 -250
  308. package/tests/integration/06-test-container-dom-tree-drawing.mjs +0 -256
  309. package/tests/integration/07-test-weibo-container-lifecycle.mjs +0 -355
  310. package/tests/integration/08-test-weibo-feed-workflow.test.mjs +0 -164
  311. package/tests/integration/10-test-visual-analyzer.mjs +0 -312
  312. package/tests/integration/11-test-visual-loop.mjs +0 -284
  313. package/tests/integration/12-test-simple-visual-loop.mjs +0 -242
  314. package/tests/integration/13-test-visual-robust.mjs +0 -185
  315. package/tests/integration/14-test-visual-highlight-loop.mjs +0 -271
  316. package/tests/integration/inspect-page.mjs +0 -50
  317. package/tests/integration/run-all-tests.mjs +0 -95
  318. package/tests/patch_verification/CODEX_PATCH_TEST.md +0 -103
  319. package/tests/patch_verification/PHASE2_ANALYSIS.md +0 -179
  320. package/tests/patch_verification/PHASE2_OPTIMIZATION_REPORT.md +0 -55
  321. package/tests/patch_verification/PHASE2_TO_PHASE4_SUMMARY.md +0 -126
  322. package/tests/patch_verification/QUICK_TEST_SEQUENCE.md +0 -262
  323. package/tests/patch_verification/README.md +0 -143
  324. package/tests/patch_verification/RUN_TESTS.md +0 -60
  325. package/tests/patch_verification/TEST_EXECUTION.md +0 -99
  326. package/tests/patch_verification/TEST_PLAN.md +0 -328
  327. package/tests/patch_verification/TEST_RESULTS.md +0 -34
  328. package/tests/patch_verification/TOOL_TEST_PLAN.md +0 -48
  329. package/tests/patch_verification/run-tool-test.mjs +0 -121
  330. package/tests/patch_verification/temp_test_files/test01.txt +0 -1
  331. package/tests/patch_verification/temp_test_files/test02.txt +0 -3
  332. package/tests/patch_verification/temp_test_files/test02_gnu.txt +0 -3
  333. package/tests/patch_verification/temp_test_files/test03.txt +0 -1
  334. package/tests/patch_verification/temp_test_files/test03_multiline.txt +0 -5
  335. package/tests/patch_verification/temp_test_files/test04_function.ts +0 -5
  336. package/tests/patch_verification/temp_test_files/test05_import.ts +0 -4
  337. package/tests/patch_verification/temp_test_files/test06_special_chars.txt +0 -4
  338. package/tests/patch_verification/temp_test_files/test07_indentation.ts +0 -5
  339. package/tests/patch_verification/temp_test_files/test08_mismatch.txt +0 -1
  340. package/tests/patch_verification/temp_test_files/test_add_02.txt +0 -3
  341. package/tests/patch_verification/temp_test_files/test_simple.txt +0 -1
  342. package/tests/runner/TestReporter.mjs +0 -57
  343. package/tests/runner/TestRunner.mjs +0 -244
  344. package/tests/unit/commands/profile.test.mjs +0 -10
  345. package/tests/unit/container/change-notifier.test.mjs +0 -181
  346. package/tests/unit/lifecycle/session-registry.test.mjs +0 -135
  347. package/tests/unit/operations/registry.test.ts +0 -73
  348. package/tests/unit/utils/browser-service.test.mjs +0 -153
  349. package/tests/unit/utils/config.test.mjs +0 -166
  350. package/tests/unit/utils/fingerprint.test.mjs +0 -166
  351. package/tsconfig.json +0 -31
  352. package/tsconfig.services.json +0 -26
  353. /package/apps/desktop-console/{src → dist}/renderer/index.html +0 -0
  354. /package/apps/desktop-console/{src/renderer/tabs → dist/renderer}/run.mts +0 -0
@@ -0,0 +1,229 @@
1
+ /**
2
+ * 标准化微博采集 Workflow
3
+ *
4
+ * 输入:数量和输出文件
5
+ * 输出:指定数量的微博帖子到MD文件
6
+ */
7
+ import fs from 'fs/promises';
8
+ const UNIFIED_API = 'http://127.0.0.1:7701';
9
+ const PROFILE = 'weibo_fresh';
10
+ async function executeScript(script) {
11
+ const response = await fetch(`${UNIFIED_API}/v1/controller/action`, {
12
+ method: 'POST',
13
+ headers: { 'Content-Type': 'application/json' },
14
+ body: JSON.stringify({
15
+ action: 'browser:execute',
16
+ payload: {
17
+ sessionId: PROFILE,
18
+ script
19
+ }
20
+ })
21
+ });
22
+ const result = await response.json();
23
+ return result.data?.result ?? result.data;
24
+ }
25
+ async function mouseWheel(deltaY) {
26
+ await fetch(`${UNIFIED_API}/v1/controller/action`, {
27
+ method: 'POST',
28
+ headers: { 'Content-Type': 'application/json' },
29
+ body: JSON.stringify({
30
+ action: 'mouse:wheel',
31
+ payload: {
32
+ profileId: PROFILE,
33
+ deltaX: 0,
34
+ deltaY: Math.max(-800, Math.min(800, Number(deltaY) || 0)),
35
+ },
36
+ }),
37
+ }).then((r) => r.json().catch(() => ({})));
38
+ }
39
+ async function collectWeiboPosts(targetCount) {
40
+ console.log('🔄 Starting Weibo Collection');
41
+ console.log('========================================');
42
+ console.log(`📊 Target: ${targetCount} posts`);
43
+ console.log('');
44
+ const collectedPosts = new Map();
45
+ let scrollCount = 0;
46
+ let lastHeight = 0;
47
+ let noChangeCount = 0;
48
+ const maxNoChangeCount = 3;
49
+ while (collectedPosts.size < targetCount && scrollCount < 120 && noChangeCount < maxNoChangeCount) {
50
+ console.log(`📊 Progress: ${collectedPosts.size}/${targetCount} posts | Scroll: ${scrollCount} | No-change: ${noChangeCount}/${maxNoChangeCount}`);
51
+ // 获取当前页面的帖子
52
+ const extractScript = `
53
+ (function() {
54
+ const posts = document.querySelectorAll('[class*="Feed_wrap_"], [class*="Feed_body_"], article');
55
+ const results = [];
56
+
57
+ posts.forEach((post, index) => {
58
+ const data = {};
59
+
60
+ // 内容链接 - 优先查找包含status的微博链接
61
+ const statusLink = post.querySelector('a[href*="weibo.com"][href*="/status/"]');
62
+ if (statusLink) {
63
+ data.url = statusLink.href;
64
+ } else {
65
+ // 备选:查找包含Q开头的链接(微博短链接)
66
+ const shortLink = post.querySelector('a[href*="weibo.com/"][href*="Q"]');
67
+ if (shortLink) {
68
+ data.url = shortLink.href;
69
+ }
70
+ }
71
+
72
+ // 作者链接 - 查找用户主页链接
73
+ const userLink = post.querySelector('a[href*="weibo.com/u/"]');
74
+ if (userLink) {
75
+ data.authorUrl = userLink.href;
76
+ data.author = userLink.textContent?.trim() || '未知作者';
77
+ } else {
78
+ // 备选:查找其他作者链接
79
+ const authorSelectors = [
80
+ 'header a[href*="weibo.com"]',
81
+ 'a[href*="weibo.com"][href*="/u/"]',
82
+ 'a[href*="weibo.com"]'
83
+ ];
84
+ for (const sel of authorSelectors) {
85
+ const authorEl = post.querySelector(sel);
86
+ if (authorEl && authorEl.textContent && authorEl.textContent.trim()) {
87
+ data.author = authorEl.textContent.trim();
88
+ data.authorUrl = authorEl.href;
89
+ break;
90
+ }
91
+ }
92
+ }
93
+
94
+ // 内容 - 尝试多个选择器
95
+ const contentSelectors = [
96
+ '[class*="detail_wbtext"]',
97
+ '[class*="wbtext"]',
98
+ '[class*="content"]',
99
+ '[class*="text"]'
100
+ ];
101
+ for (const sel of contentSelectors) {
102
+ const contentEl = post.querySelector(sel);
103
+ if (contentEl && contentEl.textContent && contentEl.textContent.trim()) {
104
+ data.content = contentEl.textContent.trim().substring(0, 500); // 限制长度
105
+ break;
106
+ }
107
+ }
108
+
109
+ // 时间
110
+ const timeEl = post.querySelector('time');
111
+ if (timeEl) {
112
+ data.timestamp = timeEl.textContent?.trim() || timeEl.getAttribute('datetime');
113
+ }
114
+
115
+ // 只收集有内容的帖子
116
+ if (data.content) {
117
+ results.push(data);
118
+ }
119
+ });
120
+
121
+ return results;
122
+ })()
123
+ `;
124
+ const posts = await executeScript(extractScript);
125
+ // 去重并收集
126
+ if (Array.isArray(posts)) {
127
+ let newPosts = 0;
128
+ posts.forEach((post, index) => {
129
+ // 使用内容作为唯一标识,避免重复
130
+ const uniqueKey = post.url || (post.content ? post.content.substring(0, 50) : index);
131
+ if (uniqueKey && !collectedPosts.has(uniqueKey)) {
132
+ collectedPosts.set(uniqueKey, post);
133
+ newPosts++;
134
+ }
135
+ });
136
+ console.log(` ✅ Found ${posts.length} posts on page, added ${newPosts} new, total unique: ${collectedPosts.size}`);
137
+ }
138
+ // 检查页面高度是否变化,判断是否到底部
139
+ const currentHeight = await executeScript('document.documentElement.scrollHeight');
140
+ console.log(` 📏 Page height: ${currentHeight}, last: ${lastHeight}`);
141
+ if (currentHeight === lastHeight) {
142
+ noChangeCount++;
143
+ console.log(` ⚠️ Height unchanged (${noChangeCount}/${maxNoChangeCount})`);
144
+ }
145
+ else {
146
+ noChangeCount = 0; // 重置计数
147
+ }
148
+ lastHeight = currentHeight;
149
+ // 如果还需要更多,滚动
150
+ if (collectedPosts.size < targetCount && noChangeCount < maxNoChangeCount) {
151
+ console.log(' 🔄 Scrolling down...');
152
+ await mouseWheel(800);
153
+ await mouseWheel(800);
154
+ await new Promise(r => setTimeout(r, 3000)); // 等待加载
155
+ scrollCount++;
156
+ }
157
+ else {
158
+ if (collectedPosts.size >= targetCount) {
159
+ console.log(' ✅ Target count reached!');
160
+ }
161
+ else if (noChangeCount >= maxNoChangeCount) {
162
+ console.log(' ✅ Reached bottom of page!');
163
+ }
164
+ }
165
+ }
166
+ console.log(`\n✅ Collection completed! Total: ${collectedPosts.size} posts`);
167
+ return Array.from(collectedPosts.values());
168
+ }
169
+ async function generateMarkdown(posts, filename) {
170
+ const lines = [
171
+ '# 微博采集结果',
172
+ '',
173
+ `采集时间:${new Date().toLocaleString('zh-CN')}`,
174
+ `帖子数量:${posts.length}`,
175
+ '',
176
+ '---',
177
+ ''
178
+ ];
179
+ posts.forEach((post, index) => {
180
+ lines.push(`## ${index + 1}. ${post.author || '未知作者'}`);
181
+ lines.push('');
182
+ if (post.content) {
183
+ lines.push(`**内容:** ${post.content.substring(0, 500)}${post.content.length > 500 ? '...' : ''}`);
184
+ lines.push('');
185
+ }
186
+ if (post.url) {
187
+ lines.push(`**链接:** ${post.url}`);
188
+ lines.push('');
189
+ }
190
+ if (post.timestamp) {
191
+ lines.push(`**时间:** ${post.timestamp}`);
192
+ lines.push('');
193
+ }
194
+ if (post.authorUrl) {
195
+ lines.push(`**作者链接:** ${post.authorUrl}`);
196
+ lines.push('');
197
+ }
198
+ lines.push('---');
199
+ lines.push('');
200
+ });
201
+ const content = lines.join('\n');
202
+ await fs.writeFile(filename, content, 'utf-8');
203
+ console.log(`✅ Markdown saved to: ${filename}`);
204
+ }
205
+ async function main(input) {
206
+ const { count = 250, output = 'weibo_posts_250.md' } = input;
207
+ try {
208
+ // 采集帖子
209
+ const posts = await collectWeiboPosts(count);
210
+ if (posts.length === 0) {
211
+ console.log('⚠️ No posts collected.');
212
+ return;
213
+ }
214
+ // 生成 Markdown
215
+ console.log('\n2️⃣ Generating Markdown report...');
216
+ await generateMarkdown(posts, output);
217
+ // 显示结果摘要
218
+ console.log('\n📋 Collection Summary:');
219
+ console.log(` ✅ Total posts: ${posts.length}`);
220
+ console.log(` 📁 Output file: ${output}`);
221
+ console.log('\n🎉 Collection completed!');
222
+ }
223
+ catch (error) {
224
+ console.error('❌ Error:', error.message);
225
+ throw error;
226
+ }
227
+ }
228
+ export { main as execute };
229
+ //# sourceMappingURL=CollectWeiboPosts.js.map
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Workflow Block: DetectPageStateBlock
3
+ *
4
+ * 基于 URL + 容器匹配检测当前页面阶段:
5
+ * - xiaohongshu: login / detail / search / home / unknown
6
+ * - weibo: login / detail / search / home / unknown
7
+ *
8
+ * 用于在进入各 Phase 前做“入口锚点”判定。
9
+ */
10
+ import { logControllerActionError, logControllerActionResult, logControllerActionStart, } from './helpers/operationLogger.js';
11
+ const PLATFORM_CONTAINERS = {
12
+ xiaohongshu: [
13
+ { id: 'xiaohongshu_login.login_guard', name: '登录页', urlPattern: /\/login/ },
14
+ { id: 'xiaohongshu_detail.modal_shell', name: '详情页', urlPattern: /\/explore\// },
15
+ {
16
+ id: 'xiaohongshu_search.search_result_list',
17
+ name: '搜索结果页',
18
+ urlPattern: /\/search_result/,
19
+ },
20
+ { id: 'xiaohongshu_home', name: '主页/推荐流', urlPattern: /\/explore/ },
21
+ ],
22
+ weibo: [
23
+ { id: 'weibo_login.login_guard', name: '登录页', urlPattern: /\/signin/ },
24
+ { id: 'weibo_detail.modal_shell', name: '详情页', urlPattern: /\/\d+\// },
25
+ { id: 'weibo_search.feed_list', name: '搜索结果页', urlPattern: /\/search/ },
26
+ { id: 'weibo_home.feed_list', name: '主页', urlPattern: /^https:\/\/weibo\.com\/?$/ },
27
+ ],
28
+ };
29
+ function detectPlatformFromUrl(url) {
30
+ if (url.includes('xiaohongshu.com'))
31
+ return 'xiaohongshu';
32
+ if (url.includes('weibo.com'))
33
+ return 'weibo';
34
+ return 'unknown';
35
+ }
36
+ function detectPageByUrl(url, platformContainers) {
37
+ for (const def of platformContainers) {
38
+ if (def.urlPattern && def.urlPattern.test(url)) {
39
+ return def;
40
+ }
41
+ }
42
+ return null;
43
+ }
44
+ function detectPageByContainer(matchIds, platformContainers, currentUrl) {
45
+ const containerIds = new Set(matchIds);
46
+ for (const def of platformContainers) {
47
+ if (containerIds.has(def.id)) {
48
+ // 对于小红书搜索结果页,额外检查 URL 是否包含 search_result,避免误把首页当成搜索页
49
+ if (def.id === 'xiaohongshu_search.search_result_list' && !currentUrl.includes('search_result')) {
50
+ continue;
51
+ }
52
+ return def;
53
+ }
54
+ }
55
+ return null;
56
+ }
57
+ function mapContainerIdToStage(platform, containerId) {
58
+ if (!containerId)
59
+ return 'unknown';
60
+ if (platform === 'xiaohongshu') {
61
+ if (containerId === 'xiaohongshu_login.login_guard')
62
+ return 'login';
63
+ if (containerId === 'xiaohongshu_detail.modal_shell')
64
+ return 'detail';
65
+ if (containerId === 'xiaohongshu_search.search_result_list')
66
+ return 'search';
67
+ if (containerId === 'xiaohongshu_home')
68
+ return 'home';
69
+ return 'unknown';
70
+ }
71
+ if (platform === 'weibo') {
72
+ if (containerId === 'weibo_login.login_guard')
73
+ return 'login';
74
+ if (containerId === 'weibo_detail.modal_shell')
75
+ return 'detail';
76
+ if (containerId === 'weibo_search.feed_list')
77
+ return 'search';
78
+ if (containerId === 'weibo_home.feed_list')
79
+ return 'home';
80
+ return 'unknown';
81
+ }
82
+ return 'unknown';
83
+ }
84
+ function detectRiskControlByUrl(url, platform) {
85
+ const u = url.toLowerCase();
86
+ if (platform === 'xiaohongshu') {
87
+ return (u.includes('/website-login/captcha') ||
88
+ u.includes('/website-login/verify') ||
89
+ u.includes('/website-login/security') ||
90
+ u.includes('verifyuuid=') ||
91
+ u.includes('verifytype=') ||
92
+ u.includes('verifybiz='));
93
+ }
94
+ if (platform === 'weibo') {
95
+ return u.includes('/signup/verify') || u.includes('/security/') || u.includes('/sina/verify');
96
+ }
97
+ return false;
98
+ }
99
+ function detectLoginByUrl(url, platform) {
100
+ if (platform === 'xiaohongshu')
101
+ return /\/login/.test(url);
102
+ if (platform === 'weibo')
103
+ return /\/signin/.test(url);
104
+ return false;
105
+ }
106
+ export async function execute(input) {
107
+ const { sessionId, platform: platformHint = 'auto', serviceUrl = 'http://127.0.0.1:7701', } = input;
108
+ const controllerUrl = `${serviceUrl}/v1/controller/action`;
109
+ async function controllerAction(action, payload = {}) {
110
+ const opId = logControllerActionStart(action, payload, { source: 'DetectPageStateBlock' });
111
+ try {
112
+ const res = await fetch(controllerUrl, {
113
+ method: 'POST',
114
+ headers: { 'Content-Type': 'application/json' },
115
+ body: JSON.stringify({ action, payload }),
116
+ });
117
+ if (!res.ok) {
118
+ throw new Error(`HTTP ${res.status}: ${await res.text()}`);
119
+ }
120
+ const data = await res.json();
121
+ const result = data.data || data;
122
+ logControllerActionResult(opId, action, result, { source: 'DetectPageStateBlock' });
123
+ return result;
124
+ }
125
+ catch (error) {
126
+ logControllerActionError(opId, action, error, payload, { source: 'DetectPageStateBlock' });
127
+ throw error;
128
+ }
129
+ }
130
+ async function getCurrentUrl() {
131
+ const data = await controllerAction('browser:execute', {
132
+ profile: sessionId,
133
+ script: 'window.location.href',
134
+ });
135
+ return data?.result || data?.data?.result || '';
136
+ }
137
+ async function getDomSummary() {
138
+ try {
139
+ const data = await controllerAction('browser:execute', {
140
+ profile: sessionId,
141
+ script: `(() => {
142
+ const hasDetailMask = !!document.querySelector('.note-detail-mask');
143
+ const hasSearchInput = !!document.querySelector('input[type="search"], #search-input');
144
+ return {
145
+ hasDetailMask,
146
+ hasSearchInput,
147
+ readyState: document.readyState,
148
+ title: document.title
149
+ };
150
+ })()`
151
+ });
152
+ const result = data?.result || data?.data?.result || null;
153
+ if (result && typeof result === 'object')
154
+ return result;
155
+ return {};
156
+ }
157
+ catch {
158
+ return {};
159
+ }
160
+ }
161
+ async function matchContainers() {
162
+ // Controller's containers:match requires an explicit URL.
163
+ // Use the current page URL as the match target; this keeps matching aligned with the active document.
164
+ const currentUrl = await getCurrentUrl().catch(() => '');
165
+ const data = await controllerAction('containers:match', {
166
+ profile: sessionId,
167
+ url: currentUrl,
168
+ });
169
+ const rootId = data?.container?.id || data?.data?.container?.id || null;
170
+ const matches = data?.snapshot?.matches || data?.data?.snapshot?.matches || {};
171
+ const matchIds = Object.entries(matches)
172
+ .filter(([, info]) => {
173
+ const mc = info?.match_count ?? info?.matchCount ?? 0;
174
+ return mc > 0;
175
+ })
176
+ .map(([id]) => id);
177
+ return { rootId, matchIds };
178
+ }
179
+ // 1) 始终优先尝试通过 URL 判定平台和大致页面
180
+ const url = await getCurrentUrl().catch(() => '');
181
+ let platform;
182
+ if (platformHint === 'auto') {
183
+ platform = url ? detectPlatformFromUrl(url) : 'unknown';
184
+ }
185
+ else {
186
+ platform = platformHint;
187
+ }
188
+ if (platform === 'unknown') {
189
+ return {
190
+ success: false,
191
+ sessionId,
192
+ platform,
193
+ url,
194
+ stage: 'unknown',
195
+ error: url ? 'Unknown platform from URL' : 'URL unavailable',
196
+ };
197
+ }
198
+ // Hard-stop detection (URL-based) to avoid triggering risk-control via repeated container matching.
199
+ if (url && detectRiskControlByUrl(url, platform)) {
200
+ return {
201
+ success: true,
202
+ sessionId,
203
+ platform,
204
+ url,
205
+ stage: 'login',
206
+ pageName: 'risk_control',
207
+ rootId: null,
208
+ matchIds: [],
209
+ dom: await getDomSummary(),
210
+ };
211
+ }
212
+ if (url && detectLoginByUrl(url, platform)) {
213
+ return {
214
+ success: true,
215
+ sessionId,
216
+ platform,
217
+ url,
218
+ stage: 'login',
219
+ pageName: 'login_page',
220
+ rootId: null,
221
+ matchIds: [],
222
+ dom: await getDomSummary(),
223
+ };
224
+ }
225
+ const platformContainers = PLATFORM_CONTAINERS[platform] || [];
226
+ const urlDetection = url ? detectPageByUrl(url, platformContainers) : null;
227
+ // 2) 再尝试做一次容器匹配;如果失败则回退到 URL-only 的判定,而不是直接失败
228
+ let rootId = null;
229
+ let matchIds = [];
230
+ let matchError;
231
+ const dom = await getDomSummary();
232
+ try {
233
+ const matched = await matchContainers();
234
+ rootId = matched.rootId;
235
+ matchIds = matched.matchIds;
236
+ }
237
+ catch (error) {
238
+ matchError = error?.message || String(error);
239
+ }
240
+ const containerDetection = matchIds.length > 0
241
+ ? detectPageByContainer([rootId, ...matchIds].filter(Boolean), platformContainers, url)
242
+ : null;
243
+ // 以容器检测为主,URL 为辅;若容器匹配失败则退回 URL-only
244
+ const effectiveDetection = containerDetection || urlDetection || null;
245
+ const stage = mapContainerIdToStage(platform, effectiveDetection?.id);
246
+ return {
247
+ success: true,
248
+ sessionId,
249
+ platform,
250
+ url,
251
+ stage,
252
+ pageName: effectiveDetection?.name,
253
+ rootId,
254
+ matchIds,
255
+ dom,
256
+ error: matchError,
257
+ };
258
+ }
259
+ //# sourceMappingURL=DetectPageStateBlock.js.map
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Workflow Block: EnsureLoginBlock
3
+ *
4
+ * 通过容器匹配确保浏览器处于登录状态
5
+ * 基于登录锚点模型:*.login_anchor(已登录)或 xiaohongshu_login.login_guard(未登录)
6
+ */
7
+ /**
8
+ * 确保登录状态(容器驱动版)
9
+ *
10
+ * @param input - 输入参数
11
+ * @returns Promise<EnsureLoginOutput>
12
+ */
13
+ export async function execute(input) {
14
+ const { sessionId, serviceUrl = 'http://127.0.0.1:7701', maxWaitMs = 120000, // 2分钟
15
+ checkIntervalMs = 3000 } = input;
16
+ const startTime = Date.now();
17
+ const waitLimitMs = maxWaitMs <= 0 ? Number.POSITIVE_INFINITY : maxWaitMs;
18
+ // 检查登录状态的辅助函数
19
+ async function checkLoginStatus() {
20
+ try {
21
+ // 通过 Unified API 调用容器匹配
22
+ const controllerUrl = `${serviceUrl}/v1/controller/action`;
23
+ // 优先读取当前 URL 并传给 containers:match,避免为了匹配再额外跑 session-manager CLI(更稳定/更快)
24
+ let currentUrl = '';
25
+ try {
26
+ const urlResp = await fetch(controllerUrl, {
27
+ method: 'POST',
28
+ headers: { 'Content-Type': 'application/json' },
29
+ body: JSON.stringify({
30
+ action: 'browser:execute',
31
+ payload: {
32
+ profile: sessionId,
33
+ script: 'location.href',
34
+ },
35
+ }),
36
+ signal: AbortSignal.timeout ? AbortSignal.timeout(8000) : undefined,
37
+ });
38
+ if (urlResp.ok) {
39
+ const urlJson = await urlResp.json().catch(() => ({}));
40
+ currentUrl = urlJson?.data?.result || urlJson?.result || '';
41
+ }
42
+ }
43
+ catch {
44
+ currentUrl = '';
45
+ }
46
+ const response = await fetch(controllerUrl, {
47
+ method: 'POST',
48
+ headers: { 'Content-Type': 'application/json' },
49
+ body: JSON.stringify({
50
+ action: 'containers:match',
51
+ payload: {
52
+ profile: sessionId,
53
+ ...(currentUrl ? { url: currentUrl } : {}),
54
+ // 登录锚点通常在较浅层级即可命中;避免过深/过宽导致 containers:match 超时
55
+ maxDepth: 2,
56
+ maxChildren: 5
57
+ }
58
+ }),
59
+ // 为 containers:match 增加超时,避免长时间挂起
60
+ signal: AbortSignal.timeout ? AbortSignal.timeout(25000) : undefined
61
+ });
62
+ if (!response.ok) {
63
+ return { isLoggedIn: false, error: `HTTP ${response.status}: ${await response.text()}` };
64
+ }
65
+ const result = await response.json();
66
+ const data = result.data || result;
67
+ const tree = data.snapshot?.container_tree || data.container_tree;
68
+ // 递归查找匹配的容器
69
+ function findContainer(node, pattern) {
70
+ if (!node)
71
+ return null;
72
+ if (pattern.test(node.id || node.defId || ''))
73
+ return node;
74
+ if (Array.isArray(node.children)) {
75
+ for (const child of node.children) {
76
+ const found = findContainer(child, pattern);
77
+ if (found)
78
+ return found;
79
+ }
80
+ }
81
+ return null;
82
+ }
83
+ // 检查已登录容器
84
+ const loginAnchor = findContainer(tree, /\.login_anchor$/);
85
+ if (loginAnchor) {
86
+ return {
87
+ isLoggedIn: true,
88
+ containerId: loginAnchor.id || loginAnchor.defId
89
+ };
90
+ }
91
+ // 检查未登录容器
92
+ const loginGuard = findContainer(tree, /xiaohongshu_login\.login_guard$/);
93
+ if (loginGuard) {
94
+ return {
95
+ isLoggedIn: false,
96
+ containerId: loginGuard.id || loginGuard.defId
97
+ };
98
+ }
99
+ // 未匹配到任何登录相关容器
100
+ return {
101
+ isLoggedIn: false,
102
+ error: '未匹配到登录锚点容器(*.login_anchor 或 xiaohongshu_login.login_guard)'
103
+ };
104
+ }
105
+ catch (error) {
106
+ return {
107
+ isLoggedIn: false,
108
+ error: `容器匹配失败: ${error.message}`
109
+ };
110
+ }
111
+ }
112
+ try {
113
+ // 首次检查
114
+ let status = await checkLoginStatus();
115
+ if (status.isLoggedIn) {
116
+ return {
117
+ isLoggedIn: true,
118
+ loginMethod: 'container_match',
119
+ matchedContainer: status.containerId,
120
+ waitTimeMs: Date.now() - startTime
121
+ };
122
+ }
123
+ // 如果未登录,等待人工登录
124
+ console.log(`[EnsureLogin] 未检测到登录状态,匹配到容器: ${status.containerId || 'none'}`);
125
+ const waitHint = waitLimitMs === Number.POSITIVE_INFINITY
126
+ ? '无超时'
127
+ : `${waitLimitMs}ms`;
128
+ console.log(`[EnsureLogin] 等待人工登录,最大等待时间: ${waitHint}`);
129
+ while (Date.now() - startTime < waitLimitMs) {
130
+ await new Promise(resolve => setTimeout(resolve, checkIntervalMs));
131
+ status = await checkLoginStatus();
132
+ if (status.isLoggedIn) {
133
+ return {
134
+ isLoggedIn: true,
135
+ loginMethod: 'manual_wait',
136
+ matchedContainer: status.containerId,
137
+ waitTimeMs: Date.now() - startTime
138
+ };
139
+ }
140
+ if (status.error && !status.error.includes('未匹配到登录锚点容器')) {
141
+ console.warn(`[EnsureLogin] 检查时出现错误: ${status.error}`);
142
+ }
143
+ console.log(`[EnsureLogin] 登录状态检查中... (${Math.floor((Date.now() - startTime) / 1000)}s)`);
144
+ }
145
+ // 超时
146
+ return {
147
+ isLoggedIn: false,
148
+ loginMethod: 'timeout',
149
+ matchedContainer: status.containerId,
150
+ waitTimeMs: Date.now() - startTime,
151
+ error: `登录等待超时 (${waitLimitMs}ms)`
152
+ };
153
+ }
154
+ catch (error) {
155
+ return {
156
+ isLoggedIn: false,
157
+ loginMethod: 'container_match',
158
+ error: `EnsureLogin 执行错误: ${error.message}`
159
+ };
160
+ }
161
+ }
162
+ //# sourceMappingURL=EnsureLoginBlock.js.map