@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
@@ -1,213 +0,0 @@
1
- import { createEl, labeledInput, section } from '../ui-components.mjs';
2
- import { resolveWebautoRoot } from '../path-helpers.mjs';
3
-
4
- const PHASES = [
5
- { id: 'phase1', label: 'Phase1: 启动浏览器' },
6
- { id: 'phase2', label: 'Phase2: 搜索采集' },
7
- { id: 'phase3', label: 'Phase3: 评论互动' },
8
- { id: 'phase4', label: 'Phase4: 内容采集' },
9
- { id: 'unified', label: 'Unified: 统一采集' },
10
- ];
11
-
12
- export function renderProfilePool(root: HTMLElement, ctx: any) {
13
- const webautoRoot = resolveWebautoRoot(ctx.settings?.downloadRoot || '', window.api);
14
-
15
- const containerStyle = 'background:#1a1a2e; color:#eee; padding:16px; border-radius:8px;';
16
- const listStyle = 'max-height:150px; overflow:auto; background:#16213e; border:1px solid #0f3460; border-radius:4px; padding:8px;';
17
- const itemStyle = 'cursor:pointer; padding:6px 10px; margin:3px 0; background:#0f3460; border-radius:4px; color:#fff; font-size:13px;';
18
- const selectedItemStyle = 'cursor:pointer; padding:6px 10px; margin:3px 0; background:#e94560; border-radius:4px; color:#fff; font-weight:bold; font-size:13px;';
19
- const labelStyle = 'color:#eaeaea; font-size:12px; margin-bottom:6px; font-weight:500;';
20
- const sectionTitleStyle = 'color:#fff; font-size:14px; font-weight:bold; margin:16px 0 8px 0; border-bottom:1px solid #0f3460; padding-bottom:4px;';
21
-
22
- // Top section: Available and Selected profiles
23
- const availableProfiles = createEl('div', { style: listStyle });
24
- const selectedProfiles = createEl('div', { style: listStyle });
25
- const statusText = createEl('div', { style: 'color:#e94560; font-size:13px; margin:8px 0; font-weight:bold;' });
26
-
27
- // Bottom section: Per-phase profile assignment
28
- const phaseSections = createEl('div', { style: 'margin-top:16px;' });
29
-
30
- let profiles: string[] = [];
31
- let selected: Set<string> = new Set();
32
- let phaseProfiles: Record<string, Set<string>> = {};
33
-
34
- function loadSavedConfig() {
35
- if (ctx.settings?.allowedProfiles) {
36
- selected = new Set(ctx.settings.allowedProfiles);
37
- }
38
- // Load phase-specific assignments
39
- if (ctx.settings?.phaseProfiles) {
40
- phaseProfiles = {};
41
- for (const [phaseId, profs] of Object.entries(ctx.settings.phaseProfiles)) {
42
- phaseProfiles[phaseId] = new Set(profs as string[]);
43
- }
44
- }
45
- // Default: all selected profiles enabled for all phases
46
- PHASES.forEach(phase => {
47
- if (!phaseProfiles[phase.id]) {
48
- phaseProfiles[phase.id] = new Set(selected);
49
- }
50
- });
51
- }
52
-
53
- async function loadProfiles() {
54
- try {
55
- const res = await fetch((ctx.settings?.coreDaemonUrl || 'http://127.0.0.1:7700') + '/profile/list');
56
- const data = await res.json();
57
- profiles = data.allowed || [];
58
- loadSavedConfig();
59
- renderTopSection();
60
- renderPhaseSections();
61
- } catch (e) {
62
- statusText.textContent = '❌ 加载失败: ' + (e as Error).message;
63
- }
64
- }
65
-
66
- function renderTopSection() {
67
- availableProfiles.textContent = '';
68
- selectedProfiles.textContent = '';
69
-
70
- profiles.forEach(p => {
71
- if (!selected.has(p)) {
72
- const row = createEl('div', { style: itemStyle }, ['+ ' + p]);
73
- row.onclick = () => {
74
- selected.add(p);
75
- // Auto-enable for all phases
76
- PHASES.forEach(ph => {
77
- if (!phaseProfiles[ph.id]) phaseProfiles[ph.id] = new Set();
78
- phaseProfiles[ph.id].add(p);
79
- });
80
- renderTopSection();
81
- renderPhaseSections();
82
- };
83
- availableProfiles.appendChild(row);
84
- }
85
- });
86
-
87
- if (selected.size === 0) {
88
- selectedProfiles.appendChild(createEl('div', { style: 'color:#888; padding:20px; text-align:center; font-size:12px;' }, ['点击左侧 + 添加 Profile']));
89
- } else {
90
- selected.forEach(p => {
91
- const row = createEl('div', { style: selectedItemStyle }, ['✓ ' + p]);
92
- row.onclick = () => {
93
- selected.delete(p);
94
- // Remove from all phases
95
- PHASES.forEach(ph => phaseProfiles[ph.id]?.delete(p));
96
- renderTopSection();
97
- renderPhaseSections();
98
- };
99
- selectedProfiles.appendChild(row);
100
- });
101
- }
102
-
103
- statusText.textContent = `📊 可用: ${profiles.length - selected.size} | 已加入: ${selected.size}`;
104
- }
105
-
106
- function renderPhaseSections() {
107
- phaseSections.textContent = '';
108
- phaseSections.appendChild(createEl('div', { style: sectionTitleStyle }, ['阶段 Profile 分配(可取消勾选)']));
109
-
110
- PHASES.forEach(phase => {
111
- const phaseBox = createEl('div', { style: 'background:#0f3460; padding:10px; margin:8px 0; border-radius:4px;' });
112
- const phaseHeader = createEl('div', { style: 'color:#e94560; font-size:13px; font-weight:bold; margin-bottom:8px;' }, [phase.label]);
113
- phaseBox.appendChild(phaseHeader);
114
-
115
- const checkboxesRow = createEl('div', { style: 'display:flex; flex-wrap:wrap; gap:8px;' });
116
-
117
- if (selected.size === 0) {
118
- checkboxesRow.appendChild(createEl('span', { style: 'color:#666; font-size:12px;' }, ['先添加 Profile 到上方池']));
119
- } else {
120
- selected.forEach(profile => {
121
- const isEnabled = phaseProfiles[phase.id]?.has(profile) ?? true;
122
- const label = createEl('label', { style: 'display:flex; align-items:center; gap:4px; cursor:pointer; color:#fff; font-size:12px; padding:4px 8px; background:#16213e; border-radius:3px;' });
123
- const checkbox = createEl('input', { type: 'checkbox', checked: isEnabled }) as HTMLInputElement;
124
- checkbox.onchange = () => {
125
- if (!phaseProfiles[phase.id]) phaseProfiles[phase.id] = new Set();
126
- if (checkbox.checked) {
127
- phaseProfiles[phase.id].add(profile);
128
- } else {
129
- phaseProfiles[phase.id].delete(profile);
130
- }
131
- };
132
- label.appendChild(checkbox);
133
- label.appendChild(createEl('span', {}, [profile]));
134
- checkboxesRow.appendChild(label);
135
- });
136
- }
137
-
138
- phaseBox.appendChild(checkboxesRow);
139
- phaseSections.appendChild(phaseBox);
140
- });
141
- }
142
-
143
- const btnStyle = 'padding:6px 12px; margin-right:6px; background:#0f3460; color:#fff; border:none; border-radius:4px; cursor:pointer; font-size:12px;';
144
- const btnPrimaryStyle = 'padding:6px 12px; margin-right:6px; background:#e94560; color:#fff; border:none; border-radius:4px; cursor:pointer; font-weight:bold; font-size:12px;';
145
-
146
- const btnSave = createEl('button', { style: btnPrimaryStyle }, ['💾 保存']);
147
- btnSave.onclick = async () => {
148
- const phaseConfig: Record<string, string[]> = {};
149
- PHASES.forEach(ph => {
150
- phaseConfig[ph.id] = Array.from(phaseProfiles[ph.id] || []);
151
- });
152
- await window.api.settingsSet({
153
- allowedProfiles: Array.from(selected),
154
- phaseProfiles: phaseConfig
155
- });
156
- ctx.settings.allowedProfiles = Array.from(selected);
157
- ctx.settings.phaseProfiles = phaseConfig;
158
- ctx.appendLog('[ProfilePool] ✅ 已保存');
159
- };
160
-
161
- const btnRefresh = createEl('button', { style: btnStyle }, ['🔄 刷新']);
162
- btnRefresh.onclick = () => loadProfiles();
163
-
164
- const btnSelectAll = createEl('button', { style: btnStyle }, ['☑️ 全选']);
165
- btnSelectAll.onclick = () => {
166
- profiles.forEach(p => {
167
- selected.add(p);
168
- PHASES.forEach(ph => {
169
- if (!phaseProfiles[ph.id]) phaseProfiles[ph.id] = new Set();
170
- phaseProfiles[ph.id].add(p);
171
- });
172
- });
173
- renderTopSection();
174
- renderPhaseSections();
175
- };
176
-
177
- const btnClear = createEl('button', { style: btnStyle }, ['清空']);
178
- btnClear.onclick = () => {
179
- selected.clear();
180
- phaseProfiles = {};
181
- renderTopSection();
182
- renderPhaseSections();
183
- };
184
-
185
- const wrapper = createEl('div', { style: containerStyle });
186
- wrapper.appendChild(
187
- section('Profile Pool', [
188
- // Top: Pool management
189
- createEl('div', { style: 'display:grid; grid-template-columns:1fr 1fr; gap:12px;' }, [
190
- createEl('div', {}, [
191
- createEl('div', { style: labelStyle }, ['可用 Profiles(点击加入)']),
192
- availableProfiles,
193
- ]),
194
- createEl('div', {}, [
195
- createEl('div', { style: labelStyle }, ['Profile 池(点击移除)']),
196
- selectedProfiles,
197
- ]),
198
- ]),
199
- statusText,
200
- createEl('div', { style: 'margin:8px 0;' }, [
201
- btnRefresh,
202
- btnSelectAll,
203
- btnClear,
204
- btnSave,
205
- ]),
206
- // Bottom: Phase assignments
207
- phaseSections,
208
- ]),
209
- );
210
-
211
- root.appendChild(wrapper);
212
- loadProfiles();
213
- }
@@ -1,171 +0,0 @@
1
- import { createEl, section } from '../ui-components.mts';
2
-
3
- export function renderResults(root: HTMLElement, ctx: any) {
4
- const entryList = createEl('div', { className: 'list' });
5
- const fileList = createEl('div', { className: 'list' });
6
- const rightTop = createEl('div', {});
7
- const preview = createEl('div', {});
8
-
9
- const filterInput = createEl('input', { placeholder: 'filter filename (contains)', value: '' }) as HTMLInputElement;
10
- const onlyImages = createEl('input', { type: 'checkbox' }) as HTMLInputElement;
11
- const onlyText = createEl('input', { type: 'checkbox' }) as HTMLInputElement;
12
- const statusLine = createEl('div', { className: 'muted' }, ['']);
13
-
14
- let currentEntry: any = null;
15
- let currentFiles: any[] = [];
16
-
17
- async function refresh() {
18
- entryList.textContent = '';
19
- fileList.textContent = '';
20
- rightTop.textContent = '';
21
- preview.textContent = '';
22
- statusLine.textContent = '';
23
- currentEntry = null;
24
- currentFiles = [];
25
-
26
- const res = await window.api.resultsScan({ downloadRoot: ctx.settings?.downloadRoot });
27
- if (!res?.ok) {
28
- entryList.appendChild(createEl('div', { className: 'item' }, [String(res?.error || 'scan failed')]));
29
- return;
30
- }
31
- const entries = res.entries || [];
32
- entries.forEach((e: any) => {
33
- const s = e.state || null;
34
- const badge =
35
- s && s.status
36
- ? ` [${s.status}] links=${s.links || 0}/${s.target || 0} ok=${s.completed || 0} fail=${s.failed || 0}`
37
- : ' [no-state]';
38
- const item = createEl('div', { className: 'item' }, [`${e.env}/${e.keyword}${badge}`]);
39
- item.onclick = () => void openEntry(e);
40
- entryList.appendChild(item);
41
- });
42
- }
43
-
44
- async function openEntry(e: any) {
45
- currentEntry = e;
46
- currentFiles = [];
47
- rightTop.textContent = '';
48
- preview.textContent = '';
49
- fileList.textContent = '';
50
-
51
- const openDirBtn = createEl('button', { className: 'secondary' }, ['打开目录']) as HTMLButtonElement;
52
- openDirBtn.onclick = () => void window.api.osOpenPath(e.path);
53
-
54
- rightTop.appendChild(createEl('div', { className: 'row' }, [
55
- openDirBtn,
56
- createEl('div', { className: 'muted' }, [String(e.path || '')]),
57
- ]));
58
-
59
- const res = await window.api.fsListDir({ root: e.path, recursive: true, maxEntries: 2000 });
60
- if (!res?.ok) {
61
- statusLine.textContent = `list failed: ${String(res?.error || '')}`;
62
- return;
63
- }
64
- const files = (res.entries || []).filter((x: any) => x && x.isDir === false);
65
- currentFiles = files;
66
- statusLine.textContent = `files=${files.length}${res.truncated ? ' (truncated)' : ''}`;
67
- renderFileList();
68
- }
69
-
70
- function isImagePath(p: string) {
71
- const ext = p.toLowerCase().split('.').pop() || '';
72
- return ext === 'png' || ext === 'jpg' || ext === 'jpeg' || ext === 'webp';
73
- }
74
-
75
- function isTextPath(p: string) {
76
- const ext = p.toLowerCase().split('.').pop() || '';
77
- return ext === 'jsonl' || ext === 'json' || ext === 'txt' || ext === 'log' || ext === 'md';
78
- }
79
-
80
- function renderFileList() {
81
- fileList.textContent = '';
82
- preview.textContent = '';
83
-
84
- const needle = filterInput.value.trim().toLowerCase();
85
- const list = currentFiles
86
- .filter((x: any) => {
87
- const rel = String(x.rel || x.name || '').toLowerCase();
88
- if (needle && !rel.includes(needle)) return false;
89
- if (onlyImages.checked && !isImagePath(rel)) return false;
90
- if (onlyText.checked && !isTextPath(rel)) return false;
91
- return true;
92
- })
93
- .slice(0, 600);
94
-
95
- list.forEach((f: any) => {
96
- const label = String(f.rel || f.name || '');
97
- const item = createEl('div', { className: 'item' }, [label]);
98
- item.onclick = () => void previewFile(f);
99
- fileList.appendChild(item);
100
- });
101
- }
102
-
103
- async function previewFile(f: any) {
104
- preview.textContent = '';
105
- const p = String(f.path || '');
106
- if (!p) return;
107
-
108
- const actions = createEl('div', { className: 'row' }, [
109
- createEl('button', { className: 'secondary' }, ['打开文件']),
110
- ]);
111
- (actions.querySelector('button') as HTMLButtonElement).onclick = () => void window.api.osOpenPath(p);
112
- preview.appendChild(actions);
113
-
114
- if (isImagePath(p)) {
115
- const res = await window.api.fsReadFileBase64({ path: p, maxBytes: 8_000_000 });
116
- if (!res?.ok) {
117
- preview.appendChild(createEl('div', { className: 'muted' }, [String(res?.error || 'read image failed')]));
118
- return;
119
- }
120
- const ext = p.toLowerCase().endsWith('.png') ? 'png' : p.toLowerCase().endsWith('.webp') ? 'webp' : 'jpeg';
121
- const img = createEl('img', { style: 'max-width:100%; border:1px solid #ddd; border-radius:6px;' }) as HTMLImageElement;
122
- img.src = `data:image/${ext};base64,${res.data}`;
123
- preview.appendChild(img);
124
- return;
125
- }
126
- if (isTextPath(p)) {
127
- await previewText(p);
128
- return;
129
- }
130
- preview.appendChild(createEl('div', { className: 'muted' }, ['(no preview)']));
131
- }
132
-
133
- async function previewText(filePath: string) {
134
- const res = await window.api.fsReadTextPreview({ path: filePath, maxBytes: 50_000, maxLines: 200 });
135
- if (!res?.ok) {
136
- preview.appendChild(createEl('div', { className: 'muted' }, [String(res?.error || 'read failed')]));
137
- return;
138
- }
139
- preview.appendChild(createEl('pre', { style: 'white-space:pre-wrap; margin:0;' }, [res.text]));
140
- }
141
-
142
- root.appendChild(
143
- section('结果目录', [
144
- createEl('div', { className: 'row' }, [
145
- createEl('button', { className: 'secondary' }, ['刷新']),
146
- createEl('div', { className: 'muted' }, [`root=${ctx.settings?.downloadRoot || ''}`]),
147
- ]),
148
- createEl('div', { className: 'row' }, [
149
- createEl('div', { style: 'display:flex; flex-direction:column; gap:6px;' }, [
150
- createEl('label', {}, ['only images']),
151
- onlyImages,
152
- ]),
153
- createEl('div', { style: 'display:flex; flex-direction:column; gap:6px;' }, [
154
- createEl('label', {}, ['only text']),
155
- onlyText,
156
- ]),
157
- filterInput,
158
- statusLine,
159
- ]),
160
- createEl('div', { className: 'split' }, [
161
- entryList,
162
- createEl('div', {}, [rightTop, fileList, preview]),
163
- ]),
164
- ]),
165
- );
166
- (root.querySelector('button') as HTMLButtonElement).onclick = () => void refresh();
167
- filterInput.oninput = () => renderFileList();
168
- onlyImages.onchange = () => renderFileList();
169
- onlyText.onchange = () => renderFileList();
170
- void refresh();
171
- }
@@ -1,63 +0,0 @@
1
- import { readFile } from 'node:fs/promises';
2
- import path from 'node:path';
3
- import { test } from 'node:test';
4
- import assert from 'node:assert/strict';
5
- import { fileURLToPath } from 'node:url';
6
-
7
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
- const runPath = path.join(__dirname, 'run.mts');
9
-
10
- async function getSrc() {
11
- return readFile(runPath, 'utf8');
12
- }
13
-
14
- test('only fullCollect supports multi-profile modes in resolveProfileArgsForRun', async () => {
15
- const src = await getSrc();
16
- assert.match(
17
- src,
18
- /supportsMultiProfile\s*=\s*t\s*===\s*'fullCollect'/,
19
- );
20
- });
21
-
22
- test('fullCollect uses scripts scan result as script path when available', async () => {
23
- const src = await getSrc();
24
- assert.match(src, /scriptsXhsFullCollect/);
25
- assert.match(src, /const scriptPath = chosen\?\.path \|\| window\.api\.pathJoin\('apps', 'webauto', 'entry', 'xhs-unified\.mjs'\);/);
26
- });
27
-
28
- test('run tab persists default keyword/target/env/dry-run on execute', async () => {
29
- const src = await getSrc();
30
- assert.match(src, /persistRunInputs\(\{ keyword, target:.*env, dryRun: dryRun\.checked \}\)/);
31
- });
32
-
33
- test('run template includes target argument and fullCollect validation', async () => {
34
- const src = await getSrc();
35
- assert.match(src, /\['--target', target\]/);
36
- assert.match(src, /labeledInput\('target', targetInput\)/);
37
- assert.match(src, /if \(t === 'fullCollect'\) \{/);
38
- assert.match(src, /fullCollect: 必须填写 keyword/);
39
- assert.match(src, /alert\('Full Collect: 必须填写 keyword'\)/);
40
- assert.match(src, /fullCollect: 必须填写 target(正整数)/);
41
- assert.match(src, /alert\('Full Collect: 必须填写 target(正整数)'\)/);
42
- });
43
-
44
- test('non-fullCollect single selection uses runtime picker', async () => {
45
- const src = await getSrc();
46
- assert.match(src, /const useRuntimeForSingle = templateSel\.value !== 'fullCollect';/);
47
- assert.match(src, /profilePickSel\.style\.display = mode === 'profile' && !useRuntimeForSingle \? '' : 'none';/);
48
- assert.match(src, /runtimePickSel\.style\.display = mode === 'profile' && useRuntimeForSingle \? '' : 'none';/);
49
- });
50
-
51
- test('profilepool mode shows profilesBox and auto-selects pool members', async () => {
52
- const src = await getSrc();
53
- assert.match(src, /profilesBox\.style\.display = \(mode === 'profiles' \|\| mode === 'profilepool'\) \? '' : 'none';/);
54
- assert.match(src, /mode === 'profilepool'[\s\S]*pid\.startsWith\(v\)/);
55
- });
56
-
57
- test('run tab is debug-only and points orchestration to xiaohongshu tab', async () => {
58
- const src = await getSrc();
59
- assert.match(src, /完整编排(Phase1\/2\/Unified \+ 分片)已迁移到“小红书”Tab;这里仅保留调试入口/);
60
- assert.doesNotMatch(src, /orchestratePhase12Unified/);
61
- assert.doesNotMatch(src, /phase-orchestrate\.mjs/);
62
- assert.doesNotMatch(src, /Phase2 collect links/);
63
- });
@@ -1,151 +0,0 @@
1
- import { createEl, section } from '../ui-components.mts';
2
-
3
- type SessionState = {
4
- profileId: string;
5
- sessionId?: string;
6
- currentUrl?: string;
7
- lastPhase?: string;
8
- lastActiveAt?: string;
9
- createdAt?: string;
10
- status?: string;
11
- };
12
-
13
- function toMap(obj: any): Record<string, string> {
14
- return obj && typeof obj === 'object' ? (obj as any) : {};
15
- }
16
-
17
- function formatAge(iso?: string): string {
18
- if (!iso) return '';
19
- const t = Date.parse(iso);
20
- if (!Number.isFinite(t)) return '';
21
- const ms = Date.now() - t;
22
- const sec = Math.max(0, Math.floor(ms / 1000));
23
- if (sec < 60) return `${sec}s`;
24
- const min = Math.floor(sec / 60);
25
- if (min < 60) return `${min}m`;
26
- const hr = Math.floor(min / 60);
27
- return `${hr}h`;
28
- }
29
-
30
- function titleFor(profileId: string, alias: string, color: string) {
31
- // Window title is the only cross-browser surface we can touch without injecting UI overlays.
32
- return `${color} ${alias || profileId} | ${profileId}`;
33
- }
34
-
35
- function headerLabelFor(profileId: string, alias: string) {
36
- return alias ? `${alias} (${profileId})` : profileId;
37
- }
38
-
39
- export function renderRuntime(root: HTMLElement, ctx: any) {
40
- const status = createEl('div', { className: 'muted' }, ['']);
41
- const list = createEl('div', { className: 'runtime-list' });
42
- const refreshBtn = createEl('button', { className: 'secondary' }, ['刷新 runtime']) as HTMLButtonElement;
43
-
44
- let sessions: SessionState[] = [];
45
-
46
- async function refresh() {
47
- status.textContent = 'loading...';
48
- const res = await window.api.runtimeListSessions().catch(() => []);
49
- sessions = Array.isArray(res) ? res : [];
50
- status.textContent = `running=${sessions.length}`;
51
- renderList();
52
- }
53
-
54
- function renderList() {
55
- list.textContent = '';
56
- const aliases = toMap(ctx.settings?.profileAliases);
57
- const colors = toMap(ctx.settings?.profileColors);
58
-
59
- if (sessions.length === 0) {
60
- list.appendChild(createEl('div', { className: 'muted' }, ['暂无运行中的 session(或 Unified API 尚未同步 session 状态)']));
61
- return;
62
- }
63
-
64
- for (const s of sessions) {
65
- const profileId = String(s?.profileId || '');
66
- const alias = String(aliases[profileId] || '');
67
- const color = String(colors[profileId] || '#cccccc');
68
- const showName = alias ? `${alias}` : profileId;
69
-
70
- const row = createEl('div', { className: 'runtime-item' });
71
- const head = createEl('div', { className: 'runtime-head' });
72
- const badge = createEl('div', { className: 'runtime-badge', style: `background:${color}` }, ['']);
73
- const name = createEl('div', { className: 'runtime-name' }, [showName]);
74
- const meta = createEl('div', { className: 'runtime-meta muted' }, [
75
- profileId !== showName ? `(${profileId})` : '',
76
- s?.currentUrl ? ` url=${String(s.currentUrl)}` : '',
77
- ]);
78
- const phase = createEl('div', { className: 'runtime-phase muted' }, [s?.lastPhase ? `phase=${String(s.lastPhase)}` : '']);
79
- const age = createEl('div', { className: 'runtime-age muted' }, [s?.lastActiveAt ? `active ${formatAge(s.lastActiveAt)}` : '']);
80
-
81
- head.appendChild(badge);
82
- head.appendChild(createEl('div', { style: 'display:flex; flex-direction:column; gap:2px; min-width:0;' }, [name, meta, phase, age]));
83
-
84
- const controls = createEl('div', { className: 'runtime-controls' });
85
- const colorInput = createEl('input', { type: 'color', value: color }) as HTMLInputElement;
86
- colorInput.onchange = async () => {
87
- const next = { ...toMap(ctx.settings?.profileColors) };
88
- next[profileId] = String(colorInput.value || '#cccccc');
89
- const updated = await window.api.settingsSet({ profileColors: next }).catch(() => null);
90
- if (updated) ctx.settings = updated;
91
- const alias2 = String(toMap(ctx.settings?.profileAliases)[profileId] || '');
92
- const nextColor = String(colorInput.value || '#cccccc');
93
- const title = titleFor(profileId, alias2, nextColor);
94
- await window.api.runtimeSetBrowserTitle({ profileId, title }).catch(() => null);
95
- await window.api.runtimeSetHeaderBar({ profileId, label: headerLabelFor(profileId, alias2), color: nextColor }).catch(() => null);
96
- void refresh();
97
- };
98
-
99
- const btnFocus = createEl('button', { className: 'secondary' }, ['focus']) as HTMLButtonElement;
100
- btnFocus.onclick = async () => {
101
- await window.api.runtimeFocus({ profileId }).catch(() => null);
102
- };
103
-
104
- const btnMark = createEl('button', { className: 'secondary' }, ['mark']) as HTMLButtonElement;
105
- btnMark.onclick = async () => {
106
- const alias2 = String(toMap(ctx.settings?.profileAliases)[profileId] || '');
107
- await window.api.runtimeSetHeaderBar({ profileId, label: headerLabelFor(profileId, alias2), color }).catch(() => null);
108
- };
109
-
110
- const btnRestart = createEl('button', { className: 'secondary' }, ['phase1']) as HTMLButtonElement;
111
- btnRestart.onclick = async () => {
112
- await window.api.runtimeRestartPhase1({ profileId }).catch(() => null);
113
- };
114
-
115
- const btnKill = createEl('button', { className: 'danger' }, ['kill']) as HTMLButtonElement;
116
- btnKill.onclick = async () => {
117
- if (!confirm(`关闭 session: ${profileId}?`)) return;
118
- await window.api.runtimeKill({ profileId }).catch(() => null);
119
- await refresh();
120
- };
121
-
122
- controls.appendChild(colorInput);
123
- controls.appendChild(btnFocus);
124
- controls.appendChild(btnMark);
125
- controls.appendChild(btnRestart);
126
- controls.appendChild(btnKill);
127
-
128
- row.appendChild(head);
129
- row.appendChild(controls);
130
- list.appendChild(row);
131
- }
132
- }
133
-
134
- // Auto refresh on settings change (aliases/colors updated in Preflight)
135
- window.api.onSettingsChanged((next: any) => {
136
- ctx.settings = next;
137
- renderList();
138
- });
139
-
140
- refreshBtn.onclick = () => void refresh();
141
-
142
- section('Runtime Dashboard', [
143
- createEl('div', { style: 'display:flex; gap:8px; align-items:center;' }, [refreshBtn, status]),
144
- list,
145
- createEl('div', { className: 'muted' }, [
146
- '提示:颜色与 alias 会持久化到 settings;颜色也会 best-effort 写入浏览器页面 title(用于在浏览器窗口标题/Tab 上区分)。',
147
- ]),
148
- ]).forEach((x) => root.appendChild(x));
149
-
150
- void refresh();
151
- }