@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,852 @@
1
+ import { ContainerRegistry, } from '../../../container-registry/src/index.js';
2
+ export class ContainerMatcher {
3
+ registry;
4
+ constructor(registry = new ContainerRegistry()) {
5
+ this.registry = registry;
6
+ }
7
+ async matchRoot(session, pageContext) {
8
+ const url = pageContext?.url;
9
+ if (!url) {
10
+ throw new Error('page_context.url is required');
11
+ }
12
+ const containers = this.registry.getContainersForUrl(url);
13
+ if (!containers || !Object.keys(containers).length) {
14
+ return null;
15
+ }
16
+ const page = await session.ensurePage(url);
17
+ await this.waitForStableDom(page);
18
+ const currentUrl = page.url() || url;
19
+ const pagePath = this.safePathname(currentUrl);
20
+ const rootContainers = Object.entries(containers)
21
+ .filter(([containerId]) => !containerId.includes('.'))
22
+ .sort((a, b) => this.scoreContainer(b[1]) - this.scoreContainer(a[1]));
23
+ for (let attempt = 0; attempt < 3; attempt++) {
24
+ for (const [containerId, containerDef] of rootContainers) {
25
+ const match = await this.matchContainer(page, containerId, containerDef, currentUrl, pagePath);
26
+ if (match) {
27
+ return match;
28
+ }
29
+ }
30
+ try {
31
+ await page.waitForTimeout(300);
32
+ }
33
+ catch {
34
+ break;
35
+ }
36
+ }
37
+ return null;
38
+ }
39
+ async inspectTree(session, pageContext, options = {}) {
40
+ const url = pageContext?.url;
41
+ if (!url) {
42
+ throw new Error('page_context.url is required');
43
+ }
44
+ const containers = this.registry.getContainersForUrl(url);
45
+ if (!containers || !Object.keys(containers).length) {
46
+ throw new Error('No container definitions available for this URL');
47
+ }
48
+ const timings = [];
49
+ const totalStart = Date.now();
50
+ const page = await session.ensurePage(url);
51
+ const waitStart = Date.now();
52
+ await this.waitForStableDom(page);
53
+ timings.push({ step: 'wait_for_dom', duration_ms: Date.now() - waitStart });
54
+ const currentUrl = page.url() || url;
55
+ const pagePath = this.safePathname(currentUrl);
56
+ const maxDepth = this.clampNumber(options.max_depth ?? options.maxDepth ?? 4, 1, 6);
57
+ const maxChildren = this.clampNumber(options.max_children ?? options.maxChildren ?? 6, 1, 12);
58
+ const preferredRootId = options.root_container_id || options.root_id;
59
+ const preferredSelector = options.root_selector;
60
+ let rootMatch = null;
61
+ const matchStart = Date.now();
62
+ if (preferredRootId && containers[preferredRootId]) {
63
+ rootMatch = await this.matchContainer(page, preferredRootId, containers[preferredRootId], currentUrl, pagePath);
64
+ }
65
+ if (!rootMatch) {
66
+ rootMatch = await this.matchRoot(session, pageContext);
67
+ }
68
+ if (!rootMatch) {
69
+ throw new Error('No DOM elements matched known containers');
70
+ }
71
+ timings.push({ step: 'match_root', duration_ms: Date.now() - matchStart });
72
+ const effectiveSelector = preferredSelector || rootMatch.container?.matched_selector;
73
+ const collectStart = Date.now();
74
+ // 仅收集以根容器为起点的子树内的匹配结果,避免对当前页面无关的容器做全量扫描
75
+ const subtreeIds = this.collectSubtreeIds(containers, rootMatch.container.id);
76
+ const matchMap = await this.collectContainerMatches(page, containers, effectiveSelector, undefined, subtreeIds);
77
+ timings.push({ step: 'collect_container_matches', duration_ms: Date.now() - collectStart });
78
+ const buildTreeStart = Date.now();
79
+ const containerTree = this.buildContainerTree(containers, rootMatch.container.id, matchMap);
80
+ timings.push({ step: 'build_container_tree', duration_ms: Date.now() - buildTreeStart });
81
+ const domCaptureStart = Date.now();
82
+ const matchedPaths = [];
83
+ if (matchMap) {
84
+ for (const result of Object.values(matchMap)) {
85
+ if (result.nodes && Array.isArray(result.nodes)) {
86
+ for (const node of result.nodes) {
87
+ if (node.dom_path)
88
+ matchedPaths.push(node.dom_path);
89
+ }
90
+ }
91
+ }
92
+ }
93
+ const domTree = await this.captureDomTreeWithRetry(page, effectiveSelector, maxDepth, maxChildren, matchedPaths);
94
+ timings.push({ step: 'capture_dom_tree', duration_ms: Date.now() - domCaptureStart });
95
+ const annotateStart = Date.now();
96
+ const annotations = this.buildDomAnnotations(matchMap);
97
+ this.attachDomAnnotations(domTree, annotations);
98
+ timings.push({ step: 'annotate_dom', duration_ms: Date.now() - annotateStart });
99
+ timings.push({ step: 'total', duration_ms: Date.now() - totalStart });
100
+ return {
101
+ root_match: rootMatch,
102
+ container_tree: containerTree,
103
+ dom_tree: domTree,
104
+ matches: matchMap,
105
+ metadata: {
106
+ captured_at: Date.now(),
107
+ max_depth: maxDepth,
108
+ max_children: maxChildren,
109
+ root_selector: effectiveSelector || null,
110
+ root_container_id: rootMatch.container.id || null,
111
+ page_url: currentUrl,
112
+ page_path: pagePath,
113
+ timings,
114
+ },
115
+ };
116
+ }
117
+ async inspectDomBranch(session, pageContext, options = {}) {
118
+ const url = pageContext?.url;
119
+ if (!url) {
120
+ throw new Error('page_context.url is required');
121
+ }
122
+ const path = this.normalizeDomPath(options.path || options.dom_path || options.node_path);
123
+ if (!path) {
124
+ throw new Error('DOM path is required');
125
+ }
126
+ const page = await session.ensurePage(url);
127
+ await this.waitForStableDom(page);
128
+ const maxDepth = this.clampNumber(options.max_depth ?? options.maxDepth ?? 4, 1, 6);
129
+ const maxChildren = this.clampNumber(options.max_children ?? options.maxChildren ?? 6, 1, 20);
130
+ const containers = this.registry.getContainersForUrl(url);
131
+ const preferredRootId = options.root_container_id || options.root_id;
132
+ const rootSelector = options.root_selector ||
133
+ (await this.resolveRootSelector(session, pageContext, containers, preferredRootId));
134
+ if (!rootSelector) {
135
+ throw new Error('无法确定根容器选择器');
136
+ }
137
+ const branch = await this.captureDomBranch(page, rootSelector, path, maxDepth, maxChildren);
138
+ if (!branch) {
139
+ throw new Error('无法捕获 DOM 分支');
140
+ }
141
+ let annotations = {};
142
+ if (containers && Object.keys(containers).length) {
143
+ const matchSummary = await this.collectContainerMatches(page, containers, rootSelector, 8);
144
+ annotations = this.buildDomAnnotations(matchSummary);
145
+ }
146
+ this.attachDomAnnotations(branch, annotations);
147
+ return {
148
+ path,
149
+ node: branch,
150
+ metadata: {
151
+ captured_at: Date.now(),
152
+ max_depth: maxDepth,
153
+ max_children: maxChildren,
154
+ root_selector: rootSelector,
155
+ },
156
+ };
157
+ }
158
+ async waitForStableDom(page) {
159
+ try {
160
+ await page.waitForLoadState('domcontentloaded', { timeout: 20000 });
161
+ await page.waitForLoadState('networkidle', { timeout: 5000 }).catch(() => { });
162
+ await page.waitForFunction(() => {
163
+ const app = document.querySelector('#app');
164
+ if (app && app.children.length > 0) {
165
+ return true;
166
+ }
167
+ return document.body?.children?.length > 2;
168
+ }, { timeout: 12000 }).catch(() => { });
169
+ }
170
+ catch { }
171
+ }
172
+ async matchContainer(page, containerId, container, url, pagePath) {
173
+ if (!this.matchesPagePatterns(container, url, pagePath)) {
174
+ return null;
175
+ }
176
+ const selectors = container.selectors || [];
177
+ if (!selectors.length) {
178
+ console.warn('[container-matcher] container has no selectors', containerId);
179
+ return null;
180
+ }
181
+ for (const selector of selectors) {
182
+ const css = this.selectorToCss(selector);
183
+ if (!css)
184
+ continue;
185
+ let handles = [];
186
+ try {
187
+ handles = await page.$$(css);
188
+ }
189
+ catch (err) {
190
+ console.warn('[container-matcher] selector failed', css, err);
191
+ continue;
192
+ }
193
+ const count = handles.length;
194
+ if (!count) {
195
+ console.warn('[container-matcher] selector matched 0 nodes', css);
196
+ continue;
197
+ }
198
+ const guards = container.metadata || {};
199
+ if (!(await this.evaluateGuards(handles[0], guards))) {
200
+ await Promise.all(handles.map((h) => h.dispose().catch(() => { })));
201
+ continue;
202
+ }
203
+ const payload = {
204
+ container: {
205
+ id: container.id || containerId,
206
+ name: container.name,
207
+ type: container.type,
208
+ matched_selector: css,
209
+ match_count: count,
210
+ definition: container,
211
+ },
212
+ match_details: {
213
+ container_id: containerId,
214
+ selector_variant: selector.variant || 'primary',
215
+ selector_classes: selector.classes || [],
216
+ matched_selector: css,
217
+ page_url: url,
218
+ match_count: count,
219
+ },
220
+ };
221
+ await Promise.all(handles.map((h) => h.dispose().catch(() => { })));
222
+ return payload;
223
+ }
224
+ return null;
225
+ }
226
+ scoreContainer(container) {
227
+ const meta = container.metadata || {};
228
+ const req = Array.isArray(meta.required_descendants_any) ? meta.required_descendants_any.length : 0;
229
+ const excl = Array.isArray(meta.excluded_descendants_any) ? meta.excluded_descendants_any.length : 0;
230
+ const selectors = container.selectors || [];
231
+ const specificSelector = selectors.some((s) => {
232
+ const css = s.css || '';
233
+ return css && css !== '#app';
234
+ });
235
+ return req * 2 + excl + (specificSelector ? 1 : 0);
236
+ }
237
+ selectorToCss(selector) {
238
+ if (selector.css) {
239
+ return selector.css;
240
+ }
241
+ if (selector.id) {
242
+ return `#${selector.id}`;
243
+ }
244
+ if (selector.classes && selector.classes.length) {
245
+ return selector.classes.map((cls) => `.${cls}`).join('');
246
+ }
247
+ return null;
248
+ }
249
+ matchesPagePatterns(container, pageUrl, pagePath) {
250
+ const host = this.safeHostname(pageUrl);
251
+ const patterns = container.page_patterns || container.pagePatterns;
252
+ if (!patterns || !patterns.length) {
253
+ return true;
254
+ }
255
+ const includes = [];
256
+ const excludes = [];
257
+ for (const pattern of patterns) {
258
+ if (typeof pattern !== 'string')
259
+ continue;
260
+ if (pattern.startsWith('!')) {
261
+ excludes.push(pattern.slice(1));
262
+ }
263
+ else {
264
+ includes.push(pattern);
265
+ }
266
+ }
267
+ for (const pattern of excludes) {
268
+ if (this.valueMatchesPattern(pageUrl, pattern) ||
269
+ this.valueMatchesPattern(pagePath, pattern) ||
270
+ this.valueMatchesPattern(host, pattern)) {
271
+ return false;
272
+ }
273
+ }
274
+ if (!includes.length) {
275
+ return true;
276
+ }
277
+ for (const pattern of includes) {
278
+ if (this.valueMatchesPattern(pageUrl, pattern) ||
279
+ this.valueMatchesPattern(pagePath, pattern) ||
280
+ this.valueMatchesPattern(host, pattern)) {
281
+ return true;
282
+ }
283
+ }
284
+ return false;
285
+ }
286
+ patternMatch(value, pattern) {
287
+ if (!pattern)
288
+ return false;
289
+ const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
290
+ const regex = new RegExp(`^${escaped}$`);
291
+ return regex.test(value);
292
+ }
293
+ valueMatchesPattern(value, pattern) {
294
+ if (this.patternMatch(value, pattern)) {
295
+ return true;
296
+ }
297
+ if (!pattern.includes('*') && value.includes(pattern)) {
298
+ return true;
299
+ }
300
+ return false;
301
+ }
302
+ async evaluateGuards(handle, metadata) {
303
+ const req = Array.isArray(metadata?.required_descendants_any)
304
+ ? metadata.required_descendants_any
305
+ : [];
306
+ const excl = Array.isArray(metadata?.excluded_descendants_any)
307
+ ? metadata.excluded_descendants_any
308
+ : [];
309
+ if (!req.length && !excl.length) {
310
+ return true;
311
+ }
312
+ try {
313
+ return await handle.evaluate((element, guards) => {
314
+ const { reqSelectors, exclSelectors } = guards;
315
+ if (Array.isArray(reqSelectors) && reqSelectors.length) {
316
+ const hasRequired = reqSelectors.some((sel) => {
317
+ try {
318
+ return !!element.querySelector(sel);
319
+ }
320
+ catch {
321
+ return false;
322
+ }
323
+ });
324
+ if (!hasRequired) {
325
+ return false;
326
+ }
327
+ }
328
+ if (Array.isArray(exclSelectors) && exclSelectors.length) {
329
+ const hasExcluded = exclSelectors.some((sel) => {
330
+ try {
331
+ return !!element.querySelector(sel);
332
+ }
333
+ catch {
334
+ return false;
335
+ }
336
+ });
337
+ if (hasExcluded) {
338
+ return false;
339
+ }
340
+ }
341
+ return true;
342
+ }, {
343
+ reqSelectors: req,
344
+ exclSelectors: excl,
345
+ });
346
+ }
347
+ catch {
348
+ return false;
349
+ }
350
+ }
351
+ clampNumber(value, min, max) {
352
+ if (Number.isNaN(value))
353
+ return min;
354
+ return Math.max(min, Math.min(max, value));
355
+ }
356
+ async collectContainerMatches(page, containers, rootSelector, maxNodes = 4, onlyContainerIds) {
357
+ const summary = {};
358
+ for (const [containerId, container] of Object.entries(containers)) {
359
+ if (onlyContainerIds && !onlyContainerIds.has(containerId)) {
360
+ continue;
361
+ }
362
+ const selectors = [];
363
+ const nodes = [];
364
+ let matchCount = 0;
365
+ for (const selector of container.selectors || []) {
366
+ const css = this.selectorToCss(selector);
367
+ if (!css)
368
+ continue;
369
+ let handles = [];
370
+ try {
371
+ handles = await page.$$(css);
372
+ }
373
+ catch {
374
+ continue;
375
+ }
376
+ const count = handles.length;
377
+ if (!count) {
378
+ await Promise.all(handles.map((h) => h.dispose().catch(() => { })));
379
+ continue;
380
+ }
381
+ selectors.push(css);
382
+ matchCount += count;
383
+ for (const handle of handles.slice(0, maxNodes)) {
384
+ const info = await this.describeElement(handle, rootSelector);
385
+ if (info) {
386
+ info.selector = css;
387
+ nodes.push(info);
388
+ }
389
+ }
390
+ await Promise.all(handles.map((h) => h.dispose().catch(() => { })));
391
+ if (nodes.length >= maxNodes) {
392
+ break;
393
+ }
394
+ }
395
+ summary[containerId] = {
396
+ container: {
397
+ id: container.id || containerId,
398
+ name: container.name,
399
+ type: container.type,
400
+ },
401
+ selectors,
402
+ match_count: matchCount,
403
+ nodes,
404
+ };
405
+ }
406
+ return summary;
407
+ }
408
+ collectSubtreeIds(containers, rootId) {
409
+ const result = new Set();
410
+ const visit = (containerId) => {
411
+ if (result.has(containerId))
412
+ return;
413
+ const container = containers[containerId];
414
+ if (!container)
415
+ return;
416
+ result.add(containerId);
417
+ const childIds = this.resolveChildIds(containerId, container, containers);
418
+ for (const childId of childIds) {
419
+ visit(childId);
420
+ }
421
+ };
422
+ visit(rootId);
423
+ return result;
424
+ }
425
+ buildContainerTree(containers, rootId, matchMap) {
426
+ const targetRoot = containers[rootId] ? rootId : this.inferFallbackRoot(containers, rootId);
427
+ if (!targetRoot) {
428
+ return null;
429
+ }
430
+ const build = (containerId) => {
431
+ const container = containers[containerId];
432
+ if (!container)
433
+ return null;
434
+ const childIds = this.resolveChildIds(containerId, container, containers);
435
+ const node = {
436
+ id: container.id || containerId,
437
+ name: container.name,
438
+ type: container.type,
439
+ capabilities: container.capabilities || [],
440
+ // 保留容器定义中的 metadata,供上层 UI 使用(例如 source_dom_path / 设计时信息)
441
+ metadata: container.metadata ? { ...container.metadata } : undefined,
442
+ selectors: (container.selectors || []).map((sel) => ({
443
+ ...sel,
444
+ })),
445
+ // 将容器定义中的 operations 透传给前端,用于浮窗编辑和演练。
446
+ operations: Array.isArray(container.operations)
447
+ ? container.operations.map((op) => ({ ...op }))
448
+ : [],
449
+ match: this.summarizeMatchPayload(containerId, matchMap),
450
+ children: [],
451
+ };
452
+ for (const childId of childIds) {
453
+ const childNode = build(childId);
454
+ if (childNode) {
455
+ node.children.push(childNode);
456
+ }
457
+ }
458
+ return node;
459
+ };
460
+ return build(targetRoot);
461
+ }
462
+ resolveChildIds(containerId, container, containers) {
463
+ const declared = Array.isArray(container.children) ? container.children : [];
464
+ const explicit = declared.filter((child) => Boolean(containers[child]));
465
+ if (explicit.length) {
466
+ return explicit;
467
+ }
468
+ const prefix = `${containerId}.`;
469
+ const targetDepth = containerId.split('.').length;
470
+ const fallback = [];
471
+ for (const key of Object.keys(containers)) {
472
+ if (!key.startsWith(prefix))
473
+ continue;
474
+ if (key.split('.').length === targetDepth + 1) {
475
+ fallback.push(key);
476
+ }
477
+ }
478
+ return fallback.sort();
479
+ }
480
+ inferFallbackRoot(containers, preferredId) {
481
+ if (preferredId && containers[preferredId]) {
482
+ return preferredId;
483
+ }
484
+ const topLevel = Object.keys(containers).filter((id) => !id.includes('.')).sort();
485
+ if (topLevel.length)
486
+ return topLevel[0];
487
+ const keys = Object.keys(containers).sort();
488
+ return keys[0] || null;
489
+ }
490
+ summarizeMatchPayload(containerId, matchMap) {
491
+ const payload = matchMap[containerId] || {};
492
+ return {
493
+ match_count: payload.match_count || 0,
494
+ selectors: payload.selectors || [],
495
+ nodes: payload.nodes || [],
496
+ };
497
+ }
498
+ async captureDomTreeWithRetry(page, selector, maxDepth, maxChildren, forcePaths) {
499
+ const attempts = [];
500
+ if (selector)
501
+ attempts.push(selector);
502
+ attempts.push('#app', 'body', null);
503
+ const tried = new Set();
504
+ for (const candidate of attempts) {
505
+ const key = candidate ?? '__root__';
506
+ if (tried.has(key))
507
+ continue;
508
+ tried.add(key);
509
+ const retries = candidate && candidate === selector ? 5 : 3;
510
+ for (let i = 0; i < retries; i++) {
511
+ const outline = await this.captureDomTree(page, candidate || undefined, maxDepth, maxChildren, forcePaths);
512
+ if (outline) {
513
+ return outline;
514
+ }
515
+ await page.waitForTimeout(250).catch(() => { });
516
+ }
517
+ }
518
+ return this.captureFallbackDomTree(page, maxDepth, maxChildren);
519
+ }
520
+ async captureDomTree(page, selector, maxDepth, maxChildren, forcePaths) {
521
+ const runtimeTree = await page
522
+ .evaluate((config) => {
523
+ const runtime = window.__webautoRuntime;
524
+ if (!runtime?.dom?.getBranch) {
525
+ return null;
526
+ }
527
+ return runtime.dom.getBranch('root', {
528
+ rootSelector: config.selector || null,
529
+ maxDepth: config.maxDepth,
530
+ maxChildren: config.maxChildren,
531
+ forcePaths: config.forcePaths,
532
+ });
533
+ }, { selector, maxDepth, maxChildren, forcePaths })
534
+ .catch(() => null);
535
+ if (runtimeTree?.node) {
536
+ const normalized = this.normalizeRuntimeNode(runtimeTree.node);
537
+ if (normalized) {
538
+ return normalized;
539
+ }
540
+ }
541
+ return this.captureDomTreeLegacy(page, selector, maxDepth, maxChildren);
542
+ }
543
+ async captureDomTreeLegacy(page, selector, maxDepth, maxChildren) {
544
+ try {
545
+ return await page.evaluate((config) => {
546
+ const target = config.selector ? document.querySelector(config.selector) : document.body;
547
+ if (!target)
548
+ return null;
549
+ const walk = (element, path, depth) => {
550
+ const meta = {
551
+ path: path.join('/'),
552
+ tag: element.tagName,
553
+ id: element.id || null,
554
+ classes: Array.from(element.classList || []),
555
+ childCount: element.children?.length || 0,
556
+ textSnippet: (element.textContent || '').trim().slice(0, 80),
557
+ children: [],
558
+ };
559
+ if (depth >= config.maxDepth) {
560
+ return meta;
561
+ }
562
+ const children = Array.from(element.children || []).slice(0, config.maxChildren);
563
+ meta.children = children.map((child, idx) => walk(child, path.concat(String(idx)), depth + 1));
564
+ return meta;
565
+ };
566
+ return walk(target, ['root'], 0);
567
+ }, {
568
+ selector,
569
+ maxDepth,
570
+ maxChildren,
571
+ });
572
+ }
573
+ catch {
574
+ return null;
575
+ }
576
+ }
577
+ async captureFallbackDomTree(page, maxDepth, maxChildren) {
578
+ try {
579
+ return await page.evaluate((config) => {
580
+ const root = document.body || document.documentElement;
581
+ if (!root)
582
+ return null;
583
+ const walk = (element, path, depth) => {
584
+ const meta = {
585
+ path: path.join('/'),
586
+ tag: element.tagName,
587
+ id: element.id || null,
588
+ classes: Array.from(element.classList || []),
589
+ childCount: element.children?.length || 0,
590
+ textSnippet: (element.textContent || '').trim().slice(0, 80),
591
+ children: [],
592
+ };
593
+ if (depth >= config.maxDepth) {
594
+ return meta;
595
+ }
596
+ const kids = Array.from(element.children || []).slice(0, config.maxChildren);
597
+ meta.children = kids.map((child, idx) => walk(child, path.concat(String(idx)), depth + 1));
598
+ return meta;
599
+ };
600
+ return walk(root, ['root'], 0);
601
+ }, {
602
+ maxDepth: Math.max(1, Math.min(Number(maxDepth) || 4, 8)),
603
+ maxChildren: Math.max(1, Math.min(Number(maxChildren) || 8, 40)),
604
+ });
605
+ }
606
+ catch {
607
+ return null;
608
+ }
609
+ }
610
+ buildDomAnnotations(matchMap) {
611
+ const annotations = {};
612
+ for (const [containerId, payload] of Object.entries(matchMap)) {
613
+ const nodes = payload.nodes || [];
614
+ for (const node of nodes) {
615
+ const path = node.dom_path;
616
+ if (!path)
617
+ continue;
618
+ annotations[path] = annotations[path] || [];
619
+ annotations[path].push({
620
+ container_id: containerId,
621
+ container_name: payload.container?.name || payload.container?.id,
622
+ selector: node.selector,
623
+ });
624
+ }
625
+ }
626
+ return annotations;
627
+ }
628
+ attachDomAnnotations(domTree, annotations) {
629
+ if (!domTree)
630
+ return;
631
+ const visit = (node) => {
632
+ node.containers = annotations[node.path] || [];
633
+ for (const child of node.children || []) {
634
+ visit(child);
635
+ }
636
+ };
637
+ visit(domTree);
638
+ }
639
+ async captureDomBranch(page, selector, path, maxDepth, maxChildren) {
640
+ const runtimeBranch = await page
641
+ .evaluate((config) => {
642
+ const runtime = window.__webautoRuntime;
643
+ if (!runtime?.dom?.getBranch) {
644
+ return null;
645
+ }
646
+ return runtime.dom.getBranch(config.path, {
647
+ rootSelector: config.selector,
648
+ maxDepth: config.maxDepth,
649
+ maxChildren: config.maxChildren,
650
+ });
651
+ }, { selector, path, maxDepth, maxChildren })
652
+ .catch(() => null);
653
+ if (runtimeBranch?.node) {
654
+ return this.normalizeRuntimeNode(runtimeBranch.node);
655
+ }
656
+ return this.captureDomBranchLegacy(page, selector, path, maxDepth, maxChildren);
657
+ }
658
+ async captureDomBranchLegacy(page, selector, path, maxDepth, maxChildren) {
659
+ try {
660
+ return await page.evaluate((config) => {
661
+ const normalizePath = (raw) => {
662
+ if (!raw)
663
+ return ['root'];
664
+ const tokens = raw.split('/').filter((token) => token.length);
665
+ if (!tokens.length || tokens[0] === '__root__') {
666
+ tokens[0] = 'root';
667
+ }
668
+ if (tokens[0] !== 'root') {
669
+ tokens.unshift('root');
670
+ }
671
+ return tokens;
672
+ };
673
+ const pathParts = normalizePath(config.path);
674
+ const root = document.querySelector(config.selector);
675
+ if (!root)
676
+ return null;
677
+ const resolvePath = (node, parts, index) => {
678
+ if (!node)
679
+ return null;
680
+ if (index >= parts.length)
681
+ return node;
682
+ const targetIdx = Number(parts[index]);
683
+ const childNodes = Array.from(node.children ?? []);
684
+ if (!Number.isFinite(targetIdx) || targetIdx < 0 || targetIdx >= childNodes.length) {
685
+ return null;
686
+ }
687
+ return resolvePath(childNodes[targetIdx], parts, index + 1);
688
+ };
689
+ const startNode = resolvePath(root, pathParts, 1);
690
+ if (!startNode)
691
+ return null;
692
+ const walk = (element, pathTokens, depth) => {
693
+ const meta = {
694
+ path: pathTokens.join('/'),
695
+ tag: element.tagName,
696
+ id: element.id || null,
697
+ classes: Array.from(element.classList || []),
698
+ childCount: element.children?.length || 0,
699
+ textSnippet: (element.textContent || '').trim().slice(0, 80),
700
+ children: [],
701
+ };
702
+ if (depth >= config.maxDepth) {
703
+ return meta;
704
+ }
705
+ const children = Array.from(element.children || []).slice(0, config.maxChildren);
706
+ meta.children = children.map((child, idx) => walk(child, pathTokens.concat(String(idx)), depth + 1));
707
+ return meta;
708
+ };
709
+ return walk(startNode, pathParts, 0);
710
+ }, {
711
+ selector,
712
+ path,
713
+ maxDepth,
714
+ maxChildren,
715
+ });
716
+ }
717
+ catch {
718
+ return null;
719
+ }
720
+ }
721
+ async describeElement(handle, rootSelector) {
722
+ try {
723
+ return await handle.evaluate((element, selector) => {
724
+ const resolvedRoot = selector ? document.querySelector(selector) : null;
725
+ const computePath = (root) => {
726
+ const indices = [];
727
+ let current = element;
728
+ let guard = 0;
729
+ let foundRoot = false;
730
+ while (current && guard < 80) {
731
+ if (root && current === root) {
732
+ foundRoot = true;
733
+ break;
734
+ }
735
+ const parent = current.parentElement;
736
+ if (!parent)
737
+ break;
738
+ const idx = Array.prototype.indexOf.call(parent.children || [], current);
739
+ indices.unshift(String(idx));
740
+ current = parent;
741
+ guard += 1;
742
+ }
743
+ return {
744
+ path: ['root', ...indices].join('/'),
745
+ foundRoot,
746
+ };
747
+ };
748
+ const rootPathInfo = resolvedRoot ? computePath(resolvedRoot) : null;
749
+ const useRoot = Boolean(rootPathInfo?.foundRoot);
750
+ const domPath = useRoot ? rootPathInfo?.path : null;
751
+ const classes = Array.from(element.classList || []);
752
+ const snippet = (element.textContent || '').replace(/\s+/g, ' ').trim().slice(0, 120);
753
+ return {
754
+ dom_path: domPath,
755
+ dom_root_selector: useRoot ? selector : null,
756
+ tag: element.tagName,
757
+ id: element.id || null,
758
+ classes,
759
+ textSnippet: snippet,
760
+ };
761
+ }, rootSelector || null);
762
+ }
763
+ catch {
764
+ return null;
765
+ }
766
+ finally {
767
+ try {
768
+ await handle.dispose();
769
+ }
770
+ catch {
771
+ // ignore
772
+ }
773
+ }
774
+ }
775
+ safePathname(raw) {
776
+ try {
777
+ return new URL(raw).pathname || '/';
778
+ }
779
+ catch {
780
+ return raw;
781
+ }
782
+ }
783
+ safeHostname(raw) {
784
+ try {
785
+ return new URL(raw).hostname || '';
786
+ }
787
+ catch {
788
+ return '';
789
+ }
790
+ }
791
+ normalizeDomPath(path) {
792
+ if (!path)
793
+ return null;
794
+ const tokens = path.split('/').filter((token) => token.length);
795
+ if (!tokens.length)
796
+ return 'root';
797
+ if (tokens[0] === '__root__') {
798
+ tokens[0] = 'root';
799
+ }
800
+ if (tokens[0] !== 'root') {
801
+ tokens.unshift('root');
802
+ }
803
+ return tokens.join('/');
804
+ }
805
+ normalizeRuntimeNode(node) {
806
+ if (!node)
807
+ return null;
808
+ const normalizedPath = this.normalizeDomPath(node.path || 'root') || 'root';
809
+ const normalized = {
810
+ path: normalizedPath,
811
+ tag: node.tag ? String(node.tag).toUpperCase() : 'DIV',
812
+ id: node.id || null,
813
+ classes: Array.isArray(node.classes) ? [...node.classes] : [],
814
+ childCount: typeof node.childCount === 'number'
815
+ ? node.childCount
816
+ : Array.isArray(node.children)
817
+ ? node.children.length
818
+ : 0,
819
+ textSnippet: node.textSnippet || node.text || '',
820
+ selector: node.selector || null,
821
+ containers: Array.isArray(node.containers) ? [...node.containers] : [],
822
+ children: [],
823
+ };
824
+ if (Array.isArray(node.children)) {
825
+ normalized.children = node.children
826
+ .map((child, index) => {
827
+ if (!child.path) {
828
+ child.path = `${normalizedPath}/${index}`;
829
+ }
830
+ return this.normalizeRuntimeNode(child);
831
+ })
832
+ .filter(Boolean);
833
+ }
834
+ return normalized;
835
+ }
836
+ async resolveRootSelector(session, pageContext, containers, preferredId) {
837
+ if (!containers || !Object.keys(containers).length) {
838
+ const match = await this.matchRoot(session, pageContext);
839
+ return match?.container?.matched_selector || null;
840
+ }
841
+ if (preferredId && containers[preferredId]) {
842
+ const page = await session.ensurePage(pageContext.url);
843
+ const match = await this.matchContainer(page, preferredId, containers[preferredId], pageContext.url, this.safePathname(pageContext.url));
844
+ if (match?.container?.matched_selector) {
845
+ return match.container.matched_selector;
846
+ }
847
+ }
848
+ const rootMatch = await this.matchRoot(session, pageContext);
849
+ return rootMatch?.container?.matched_selector || null;
850
+ }
851
+ }
852
+ //# sourceMappingURL=container-matcher.js.map