@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,126 @@
1
+ /**
2
+ * Comment Section Locator Helper
3
+ *
4
+ * 共享定位逻辑:WarmupCommentsBlock / ExpandCommentsBlock
5
+ * - 通过容器锚点 verifyAnchorByContainerId 获取 rect
6
+ * - 必要时尝试点击 comment_button 激活评论区
7
+ */
8
+ import { logControllerActionError, logControllerActionResult, logControllerActionStart, } from './operationLogger.js';
9
+ export async function clickCommentButtonByContainerId(options) {
10
+ const { profile, serviceUrl, controllerUrl, commentButtonContainerId, highlightStyle = '2px solid #ff00ff', highlightMs = 1200, } = options;
11
+ try {
12
+ const { verifyAnchorByContainerId } = await import('./containerAnchors.js');
13
+ const vp = await getViewport(controllerUrl, profile);
14
+ const btnAnchor = await verifyAnchorByContainerId(commentButtonContainerId, profile, serviceUrl, highlightStyle, highlightMs);
15
+ if (btnAnchor.found && btnAnchor.rect && vp.innerWidth && vp.innerHeight) {
16
+ const bx = clamp(btnAnchor.rect.x + btnAnchor.rect.width / 2, 30, vp.innerWidth - 30);
17
+ const by = clamp(btnAnchor.rect.y + btnAnchor.rect.height / 2, 120, vp.innerHeight - 120);
18
+ console.log(`[WarmupComments] click comment_button @(${Math.floor(bx)},${Math.floor(by)})`);
19
+ const { systemClickAt } = await import('./systemInput.js');
20
+ await systemClickAt(profile, Math.floor(bx), Math.floor(by), undefined, 'click_comment_button');
21
+ await new Promise((r) => setTimeout(r, 800));
22
+ return { clicked: true, rect: btnAnchor.rect };
23
+ }
24
+ return {
25
+ clicked: false,
26
+ rect: btnAnchor.rect,
27
+ error: btnAnchor.error || 'comment_button anchor not found',
28
+ };
29
+ }
30
+ catch (e) {
31
+ return { clicked: false, error: e?.message || String(e) };
32
+ }
33
+ }
34
+ export async function locateCommentSection(options) {
35
+ const { profile, serviceUrl, controllerUrl, commentSectionContainerId, commentButtonContainerId, canClickCommentButton, highlightStyle = '2px solid #ffaa00', highlightMs = 2000, } = options;
36
+ const { verifyAnchorByContainerId } = await import('./containerAnchors.js');
37
+ let clicked = false;
38
+ const tryClickCommentButton = async (reason) => {
39
+ if (!canClickCommentButton)
40
+ return;
41
+ if (!commentButtonContainerId)
42
+ return;
43
+ if (clicked)
44
+ return;
45
+ try {
46
+ const vp = await getViewport(controllerUrl, profile);
47
+ const btnAnchor = await verifyAnchorByContainerId(commentButtonContainerId, profile, serviceUrl, '2px solid #ff00ff', 1200);
48
+ if (btnAnchor.found && btnAnchor.rect && vp.innerWidth && vp.innerHeight) {
49
+ const bx = clamp(btnAnchor.rect.x + btnAnchor.rect.width / 2, 30, vp.innerWidth - 30);
50
+ const by = clamp(btnAnchor.rect.y + btnAnchor.rect.height / 2, 120, vp.innerHeight - 120);
51
+ console.log(`[WarmupComments] click comment_button (${reason}) @(${Math.floor(bx)},${Math.floor(by)})`);
52
+ const { systemClickAt } = await import('./systemInput.js');
53
+ await systemClickAt(profile, Math.floor(bx), Math.floor(by), undefined, 'click_comment_button');
54
+ clicked = true;
55
+ await new Promise((r) => setTimeout(r, 800));
56
+ }
57
+ }
58
+ catch {
59
+ // ignore
60
+ }
61
+ };
62
+ try {
63
+ let anchor = await verifyAnchorByContainerId(commentSectionContainerId, profile, serviceUrl, highlightStyle, highlightMs);
64
+ if (!anchor?.found) {
65
+ await tryClickCommentButton('comment_section_not_found');
66
+ anchor = await verifyAnchorByContainerId(commentSectionContainerId, profile, serviceUrl, highlightStyle, highlightMs);
67
+ }
68
+ if (anchor.found && anchor.rect) {
69
+ console.log(`[WarmupComments] comment_section rect: ${JSON.stringify(anchor.rect)}`);
70
+ return { found: true, rect: anchor.rect, clickedCommentButton: clicked };
71
+ }
72
+ return {
73
+ found: false,
74
+ error: anchor.error || 'comment_section anchor not found',
75
+ clickedCommentButton: clicked,
76
+ };
77
+ }
78
+ catch (e) {
79
+ return {
80
+ found: false,
81
+ error: `comment_section anchor verify error: ${e?.message || e}`,
82
+ clickedCommentButton: clicked,
83
+ };
84
+ }
85
+ }
86
+ async function controllerAction(controllerUrl, action, payload = {}) {
87
+ const opId = logControllerActionStart(action, payload, { source: 'commentSectionLocator' });
88
+ try {
89
+ const response = await fetch(controllerUrl, {
90
+ method: 'POST',
91
+ headers: { 'Content-Type': 'application/json' },
92
+ body: JSON.stringify({ action, payload }),
93
+ signal: AbortSignal.timeout
94
+ ? AbortSignal.timeout(10000)
95
+ : undefined,
96
+ });
97
+ if (!response.ok) {
98
+ throw new Error(`HTTP ${response.status}: ${await response.text()}`);
99
+ }
100
+ const data = await response.json();
101
+ const result = data.data || data;
102
+ logControllerActionResult(opId, action, result, { source: 'commentSectionLocator' });
103
+ return result;
104
+ }
105
+ catch (error) {
106
+ logControllerActionError(opId, action, error, payload, { source: 'commentSectionLocator' });
107
+ throw error;
108
+ }
109
+ }
110
+ async function getViewport(controllerUrl, profile) {
111
+ try {
112
+ const result = await controllerAction(controllerUrl, 'browser:execute', {
113
+ profile,
114
+ script: '(() => ({ w: window.innerWidth || 0, h: window.innerHeight || 0 }))()',
115
+ });
116
+ const payload = result.result || result.data?.result || result;
117
+ return { innerWidth: Number(payload?.w || 0), innerHeight: Number(payload?.h || 0) };
118
+ }
119
+ catch {
120
+ return { innerWidth: 0, innerHeight: 0 };
121
+ }
122
+ }
123
+ function clamp(n, min, max) {
124
+ return Math.min(Math.max(n, min), max);
125
+ }
126
+ //# sourceMappingURL=commentSectionLocator.js.map
@@ -0,0 +1,301 @@
1
+ /**
2
+ * 容器锚点验证辅助函数(不依赖 containers:match)
3
+ * 直接从容器定义 JSON 读取 selector,然后用 browser:execute 高亮 + Rect 回环
4
+ *
5
+ * 注意:这里不使用 dist 里的 ContainerDefinitionLoader(V2 结构只保留了 classes,丢失 css),
6
+ * 而是直接读取 container-library 下的原始 JSON,保证 selector.css 可用。
7
+ */
8
+ import fs from 'node:fs';
9
+ import path from 'node:path';
10
+ import os from 'node:os';
11
+ import { logError, logOperation } from './operationLogger.js';
12
+ const repoRoot = path.resolve(process.cwd());
13
+ const userContainerRoot = process.env.WEBAUTO_USER_CONTAINER_ROOT || path.join(os.homedir(), '.webauto', 'container-lib');
14
+ const containerIndexPath = process.env.WEBAUTO_CONTAINER_INDEX || path.join(repoRoot, 'apps/webauto/resources/container-library.index.json');
15
+ const definitionCache = new Map();
16
+ function loadContainerIndex() {
17
+ try {
18
+ const content = fs.readFileSync(containerIndexPath, 'utf-8');
19
+ return JSON.parse(content);
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ }
25
+ function findSiteKeyForContainer(containerId, index) {
26
+ if (!index)
27
+ return null;
28
+ const keys = Object.keys(index);
29
+ for (const key of keys) {
30
+ if (containerId.startsWith(`${key}_`))
31
+ return key;
32
+ }
33
+ return null;
34
+ }
35
+ function findContainerJsonPath(containerId) {
36
+ const index = loadContainerIndex();
37
+ const siteKey = findSiteKeyForContainer(containerId, index) || 'xiaohongshu';
38
+ const rootDir = path.join(repoRoot, 'apps/webauto/resources/container-library', siteKey);
39
+ if (!fs.existsSync(rootDir)) {
40
+ return null;
41
+ }
42
+ const stack = [rootDir];
43
+ while (stack.length > 0) {
44
+ const current = stack.pop();
45
+ const stat = fs.statSync(current);
46
+ if (stat.isDirectory()) {
47
+ const entries = fs.readdirSync(current);
48
+ for (const entry of entries) {
49
+ stack.push(path.join(current, entry));
50
+ }
51
+ }
52
+ else if (current.endsWith('.json')) {
53
+ try {
54
+ const content = fs.readFileSync(current, 'utf-8');
55
+ const json = JSON.parse(content);
56
+ if (json && json.id === containerId) {
57
+ return current;
58
+ }
59
+ }
60
+ catch {
61
+ // ignore malformed JSON
62
+ }
63
+ }
64
+ }
65
+ return null;
66
+ }
67
+ async function findContainerDefinition(containerId) {
68
+ if (definitionCache.has(containerId)) {
69
+ const cached = definitionCache.get(containerId);
70
+ if (cached) {
71
+ return cached;
72
+ }
73
+ // 如果之前没有找到(缓存为 null),重新扫描一次,避免负缓存长期生效
74
+ }
75
+ // 优先从用户自定义容器根查找
76
+ if (userContainerRoot && fs.existsSync(userContainerRoot)) {
77
+ const userRoot = path.join(userContainerRoot, 'xiaohongshu');
78
+ if (fs.existsSync(userRoot)) {
79
+ const stack = [userRoot];
80
+ while (stack.length > 0) {
81
+ const current = stack.pop();
82
+ const stat = fs.statSync(current);
83
+ if (stat.isDirectory()) {
84
+ const entries = fs.readdirSync(current);
85
+ for (const entry of entries) {
86
+ stack.push(path.join(current, entry));
87
+ }
88
+ }
89
+ else if (current.endsWith('.json')) {
90
+ try {
91
+ const content = fs.readFileSync(current, 'utf-8');
92
+ const json = JSON.parse(content);
93
+ if (json && json.id === containerId) {
94
+ definitionCache.set(containerId, json);
95
+ return json;
96
+ }
97
+ }
98
+ catch {
99
+ // ignore
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
105
+ const jsonPath = findContainerJsonPath(containerId);
106
+ if (!jsonPath) {
107
+ return null;
108
+ }
109
+ try {
110
+ const content = fs.readFileSync(jsonPath, 'utf-8');
111
+ const json = JSON.parse(content);
112
+ definitionCache.set(containerId, json);
113
+ return json;
114
+ }
115
+ catch (error) {
116
+ return null;
117
+ }
118
+ }
119
+ function pickPrimarySelector(container) {
120
+ const selectors = container.selectors || [];
121
+ if (!selectors.length)
122
+ return null;
123
+ const primary = selectors.find((item) => item.variant === 'primary') || selectors[0];
124
+ return primary?.css || null;
125
+ }
126
+ export async function getPrimarySelectorByContainerId(containerId) {
127
+ const container = await findContainerDefinition(containerId);
128
+ if (!container) {
129
+ return null;
130
+ }
131
+ return pickPrimarySelector(container);
132
+ }
133
+ export async function getContainerExtractorsById(containerId) {
134
+ const container = await findContainerDefinition(containerId);
135
+ if (!container || !container.extractors || typeof container.extractors !== 'object') {
136
+ return null;
137
+ }
138
+ return container.extractors;
139
+ }
140
+ export async function verifyAnchorByContainerId(containerId, sessionId, serviceUrl = 'http://127.0.0.1:7701', highlightStyle = '3px solid #ff4444', highlightDuration = 2000) {
141
+ console.log(`[verifyAnchorByContainerId] Looking for container: ${containerId}`);
142
+ console.log(`[verifyAnchorByContainerId] containerIndexPath: ${containerIndexPath}`);
143
+ console.log(`[verifyAnchorByContainerId] repoRoot: ${repoRoot}`);
144
+ const container = await findContainerDefinition(containerId);
145
+ if (!container) {
146
+ console.error(`[verifyAnchorByContainerId] Container not found: ${containerId}`);
147
+ return { found: false, highlighted: false, error: `Container not found: ${containerId}` };
148
+ }
149
+ const selectors = (container.selectors || [])
150
+ .map((s) => s?.css)
151
+ .filter((css) => typeof css === 'string' && css.trim().length > 0);
152
+ if (!selectors.length) {
153
+ return { found: false, highlighted: false, error: `No selector defined for: ${containerId}` };
154
+ }
155
+ const matchOpId = logOperation({
156
+ kind: 'anchor_match_start',
157
+ action: 'anchor:verify',
158
+ sessionId,
159
+ payload: {
160
+ containerId,
161
+ selectorsCount: selectors.length,
162
+ serviceUrl,
163
+ },
164
+ });
165
+ try {
166
+ const selectorsJson = JSON.stringify(selectors);
167
+ const script = `(() => {
168
+ const selectors = ${selectorsJson};
169
+
170
+ const isVisible = (el) => {
171
+ if (!el) return false;
172
+ const style = window.getComputedStyle(el);
173
+ if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') return false;
174
+ const r = el.getBoundingClientRect();
175
+ if (!r.width || !r.height) return false;
176
+ if (r.bottom <= 0 || r.top >= window.innerHeight) return false;
177
+ return true;
178
+ };
179
+
180
+ let el = null;
181
+ let usedSelector = null;
182
+ for (const sel of selectors) {
183
+ const candidate = document.querySelector(sel);
184
+ if (candidate && isVisible(candidate)) {
185
+ el = candidate;
186
+ usedSelector = sel;
187
+ break;
188
+ }
189
+ }
190
+
191
+ if (!el) {
192
+ return { found: false, error: 'Element not found' };
193
+ }
194
+
195
+ // 创建或复用一个 overlay 高亮框,避免被页面样式覆盖
196
+ let overlay = document.getElementById('webauto-anchor-highlight');
197
+ if (!overlay) {
198
+ overlay = document.createElement('div');
199
+ overlay.id = 'webauto-anchor-highlight';
200
+ overlay.style.position = 'fixed';
201
+ overlay.style.pointerEvents = 'none';
202
+ overlay.style.zIndex = '2147483647';
203
+ document.body.appendChild(overlay);
204
+ }
205
+ const r = el.getBoundingClientRect();
206
+ overlay.style.left = r.x + 'px';
207
+ overlay.style.top = r.y + 'px';
208
+ overlay.style.width = r.width + 'px';
209
+ overlay.style.height = r.height + 'px';
210
+ overlay.style.border = '${highlightStyle.replace(/'/g, "\\'")}';
211
+ overlay.style.boxSizing = 'border-box';
212
+ overlay.style.background = 'transparent';
213
+
214
+ setTimeout(() => {
215
+ if (overlay && overlay.parentElement) {
216
+ overlay.parentElement.removeChild(overlay);
217
+ }
218
+ }, ${highlightDuration});
219
+ const rect = el.getBoundingClientRect();
220
+ return {
221
+ found: true,
222
+ selector: usedSelector,
223
+ rect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height }
224
+ };
225
+ })()`;
226
+ const response = await fetch(`${serviceUrl}/v1/controller/action`, {
227
+ method: 'POST',
228
+ headers: { 'Content-Type': 'application/json' },
229
+ body: JSON.stringify({
230
+ action: 'browser:execute',
231
+ payload: {
232
+ profile: sessionId,
233
+ script,
234
+ },
235
+ }),
236
+ // 本地 Unified API 调用在部分页面初始化时可能稍慢,适当放宽超时时间
237
+ signal: AbortSignal.timeout ? AbortSignal.timeout(30000) : undefined,
238
+ });
239
+ if (!response.ok) {
240
+ return {
241
+ found: false,
242
+ highlighted: false,
243
+ error: `HTTP ${response.status}: ${await response.text()}`,
244
+ };
245
+ }
246
+ const data = await response.json();
247
+ const result = data.data?.result || data.result;
248
+ if (!result?.found) {
249
+ logOperation({
250
+ kind: 'anchor_match_result',
251
+ action: 'anchor:verify',
252
+ sessionId,
253
+ result: {
254
+ found: false,
255
+ selector: result?.selector || null,
256
+ error: result?.error || 'Element not found',
257
+ },
258
+ meta: { opId: matchOpId, containerId },
259
+ });
260
+ return {
261
+ found: false,
262
+ highlighted: false,
263
+ selector: result?.selector,
264
+ error: result?.error || 'Element not found',
265
+ };
266
+ }
267
+ logOperation({
268
+ kind: 'anchor_match_result',
269
+ action: 'anchor:verify',
270
+ sessionId,
271
+ result: {
272
+ found: true,
273
+ selector: result?.selector || null,
274
+ rect: result?.rect || null,
275
+ },
276
+ meta: { opId: matchOpId, containerId },
277
+ });
278
+ return {
279
+ found: true,
280
+ highlighted: true,
281
+ rect: result.rect,
282
+ selector: result.selector,
283
+ };
284
+ }
285
+ catch (error) {
286
+ logError({
287
+ kind: 'anchor_match_error',
288
+ action: 'anchor:verify',
289
+ sessionId,
290
+ error: error?.message || String(error),
291
+ payload: { containerId, serviceUrl },
292
+ meta: { opId: matchOpId },
293
+ });
294
+ return {
295
+ found: false,
296
+ highlighted: false,
297
+ error: `verifyAnchor failed: ${error.message}`,
298
+ };
299
+ }
300
+ }
301
+ //# sourceMappingURL=containerAnchors.js.map
@@ -0,0 +1,6 @@
1
+ export function isDebugArtifactsEnabled() {
2
+ return (process.env.WEBAUTO_DEBUG === '1' ||
3
+ process.env.WEBAUTO_DEBUG_ARTIFACTS === '1' ||
4
+ process.env.WEBAUTO_DEBUG_SCREENSHOT === '1');
5
+ }
6
+ //# sourceMappingURL=debugArtifacts.js.map
@@ -0,0 +1,29 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ export function sanitizeForPath(name) {
4
+ if (!name)
5
+ return '';
6
+ return name.replace(/[\\/:"*?<>|]+/g, '_').trim();
7
+ }
8
+ export function resolveDownloadRoot(custom, homeDir) {
9
+ if (custom && custom.trim())
10
+ return custom;
11
+ if (homeDir && homeDir.trim())
12
+ return path.join(homeDir, '.webauto', 'download');
13
+ const envHome = process.env.HOME || process.env.USERPROFILE;
14
+ if (envHome && envHome.trim())
15
+ return path.join(envHome, '.webauto', 'download');
16
+ try {
17
+ return path.join(os.homedir(), '.webauto', 'download');
18
+ }
19
+ catch {
20
+ return path.join(process.cwd(), '.webauto', 'download');
21
+ }
22
+ }
23
+ export function resolveKeywordDir(input) {
24
+ const { platform, env, keyword, homeDir, downloadRoot } = input;
25
+ const safeKeyword = sanitizeForPath(keyword) || 'unknown';
26
+ const root = resolveDownloadRoot(downloadRoot, homeDir);
27
+ return path.join(root, platform, env, safeKeyword);
28
+ }
29
+ //# sourceMappingURL=downloadPaths.js.map
@@ -0,0 +1,53 @@
1
+ /**
2
+ * expandCommentsController.ts
3
+ *
4
+ * ExpandComments 专用的 controller 调用封装
5
+ */
6
+ import { logControllerActionError, logControllerActionResult, logControllerActionStart, } from './operationLogger.js';
7
+ /**
8
+ * 创建 ExpandComments Controller 客户端
9
+ */
10
+ export function createExpandCommentsControllerClient(config) {
11
+ const { profile, controllerUrl } = config;
12
+ async function controllerAction(action, payload = {}) {
13
+ const opId = logControllerActionStart(action, payload, { source: 'expandCommentsController' });
14
+ try {
15
+ const response = await fetch(controllerUrl, {
16
+ method: 'POST',
17
+ headers: { 'Content-Type': 'application/json' },
18
+ body: JSON.stringify({ action, payload }),
19
+ signal: AbortSignal.timeout
20
+ ? AbortSignal.timeout(10000)
21
+ : undefined,
22
+ });
23
+ if (!response.ok) {
24
+ throw new Error(`HTTP ${response.status}: ${await response.text()}`);
25
+ }
26
+ const data = await response.json();
27
+ const result = data.data || data;
28
+ logControllerActionResult(opId, action, result, { source: 'expandCommentsController' });
29
+ return result;
30
+ }
31
+ catch (error) {
32
+ logControllerActionError(opId, action, error, payload, { source: 'expandCommentsController' });
33
+ throw error;
34
+ }
35
+ }
36
+ async function getCurrentUrl() {
37
+ const response = await fetch(controllerUrl, {
38
+ method: 'POST',
39
+ headers: { 'Content-Type': 'application/json' },
40
+ body: JSON.stringify({
41
+ action: 'browser:execute',
42
+ payload: {
43
+ profile,
44
+ script: 'location.href',
45
+ },
46
+ }),
47
+ });
48
+ const data = await response.json();
49
+ return data.data?.result || data.result || '';
50
+ }
51
+ return { controllerAction, getCurrentUrl };
52
+ }
53
+ //# sourceMappingURL=expandCommentsController.js.map
@@ -0,0 +1,129 @@
1
+ /**
2
+ * expandCommentsExtractor.ts
3
+ *
4
+ * ExpandComments 的 DOM 提取逻辑封装(只读 query,不做 click/scroll)
5
+ */
6
+ export function buildExtractCommentsScript(cfg) {
7
+ const domConfig = {
8
+ rootSelectors: cfg.rootSelectors,
9
+ itemSelector: cfg.itemSelector,
10
+ fields: cfg.extractors,
11
+ };
12
+ return `(() => {
13
+ const cfg = ${JSON.stringify(domConfig)};
14
+ const pickRoot = () => {
15
+ const roots = cfg.rootSelectors || [];
16
+ for (const sel of roots) {
17
+ try {
18
+ const el = document.querySelector(sel);
19
+ if (el) return el;
20
+ } catch (_) {}
21
+ }
22
+ return null;
23
+ };
24
+
25
+ const root = pickRoot();
26
+ const scope = root || document;
27
+
28
+ const DEFAULT_ITEM_SELECTOR = [
29
+ '.comment-item',
30
+ "[class*='comment-item']",
31
+ // 一些页面的“回复/子评论”可能不叫 comment-item,但仍属于评论计数
32
+ // 注意:这里必须避免把“展开更多/显示更多”按钮误当成评论项
33
+ "[class*='reply-item']",
34
+ "[class*='replyItem']",
35
+ "[class*='sub-comment']",
36
+ "[class*='subComment']",
37
+ ].join(', ');
38
+
39
+ const rawItems = Array.from(scope.querySelectorAll(cfg.itemSelector || DEFAULT_ITEM_SELECTOR));
40
+ const items = rawItems.filter((el) => {
41
+ if (!(el instanceof HTMLElement)) return false;
42
+ // 排除明显的“展开更多/显示更多”按钮(这些会被 replyExpander 处理)
43
+ if (el.matches('.show-more, .reply-expand, [class*=\"show-more\"], [class*=\"reply-expand\"], [class*=\"expand\"][class*=\"more\"]')) {
44
+ return false;
45
+ }
46
+ const tag = String(el.tagName || '').toUpperCase();
47
+ if (tag === 'BUTTON') return false;
48
+ const t = (el.textContent || '').trim();
49
+ if (!t) return false;
50
+ // 常见展开按钮文案很短;避免把它当成评论
51
+ if (t.length <= 16 && t.includes('展开')) return false;
52
+ return true;
53
+ });
54
+
55
+ const comments = items.map((el, idx) => {
56
+ const item = {};
57
+ const fields = cfg.fields || {};
58
+
59
+ const getAttrValue = (node, attr) => {
60
+ if (!node) return '';
61
+ if (!attr || attr === 'textContent') {
62
+ return (node.textContent || '').trim();
63
+ }
64
+ if (attr === 'href') {
65
+ return (node.href || node.getAttribute('href') || '').trim();
66
+ }
67
+ const v = node.getAttribute(attr);
68
+ return v ? v.trim() : '';
69
+ };
70
+
71
+ for (const fieldName of Object.keys(fields)) {
72
+ const fieldCfg = fields[fieldName] || {};
73
+ const sels = Array.isArray(fieldCfg.selectors) ? fieldCfg.selectors : [];
74
+ let value = '';
75
+ for (const sel of sels) {
76
+ try {
77
+ const node = el.querySelector(sel);
78
+ if (!node) continue;
79
+ value = getAttrValue(node, fieldCfg.attr);
80
+ if (value) break;
81
+ } catch (_) {}
82
+ }
83
+ item[fieldName] = value;
84
+ }
85
+
86
+ item._idx = idx;
87
+ item.comment_id =
88
+ el.getAttribute('data-id') ||
89
+ el.getAttribute('data-comment-id') ||
90
+ el.getAttribute('data-commentid') ||
91
+ el.getAttribute('id') ||
92
+ '';
93
+
94
+ if (!item.text) {
95
+ item.text = (el.textContent || '').trim();
96
+ }
97
+ item.is_reply = !!el.closest('.reply-container');
98
+ return item;
99
+ });
100
+
101
+ return { found: true, comments };
102
+ })()`;
103
+ }
104
+ export function mergeExtractedComments(params) {
105
+ const { rawList, seenKeys, out, maxOut } = params;
106
+ const limit = typeof maxOut === 'number' && Number.isFinite(maxOut) && maxOut > 0 ? Math.floor(maxOut) : null;
107
+ for (const c of rawList) {
108
+ if (limit && out.length >= limit)
109
+ break;
110
+ if (!c || typeof c !== 'object')
111
+ continue;
112
+ const hasContent = Boolean(c.text && String(c.text).trim()) ||
113
+ Boolean(c.user_name && String(c.user_name).trim());
114
+ if (!hasContent)
115
+ continue;
116
+ const cid = c.comment_id || c.commentId || c.id || '';
117
+ const idx = typeof c._idx === 'number' ? String(c._idx) : '';
118
+ const key = cid
119
+ ? `id:${cid}`
120
+ : `idx:${idx}||${c.user_id || ''}||${c.user_name || ''}||${c.text || ''}||${c.timestamp || ''}`;
121
+ if (seenKeys.has(key))
122
+ continue;
123
+ seenKeys.add(key);
124
+ // 供上层做跨 tab / 跨批次去重
125
+ c._key = key;
126
+ out.push(c);
127
+ }
128
+ }
129
+ //# sourceMappingURL=expandCommentsExtractor.js.map