@web-auto/webauto 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/apps/desktop-console/default-settings.json +1 -0
  2. package/apps/desktop-console/dist/main/index.mjs +1618 -0
  3. package/apps/desktop-console/{src → dist}/main/preload.mjs +10 -0
  4. package/apps/desktop-console/dist/renderer/index.js +3063 -0
  5. package/apps/desktop-console/entry/ui-console.mjs +299 -0
  6. package/apps/webauto/entry/account.mjs +356 -0
  7. package/apps/webauto/entry/lib/account-detect.mjs +160 -0
  8. package/apps/webauto/entry/lib/account-store.mjs +587 -0
  9. package/apps/webauto/entry/lib/profilepool.mjs +1 -1
  10. package/apps/webauto/entry/xhs-install.mjs +27 -3
  11. package/apps/webauto/entry/xhs-status.mjs +152 -0
  12. package/apps/webauto/entry/xhs-unified.mjs +595 -17
  13. package/bin/webauto.mjs +263 -15
  14. package/dist/apps/webauto/server.js +66 -0
  15. package/dist/modules/camo-backend/src/index.js +575 -0
  16. package/dist/modules/camo-backend/src/internal/BrowserSession.js +817 -0
  17. package/dist/modules/camo-backend/src/internal/ElementRegistry.js +61 -0
  18. package/dist/modules/camo-backend/src/internal/ProfileLock.js +85 -0
  19. package/dist/modules/camo-backend/src/internal/SessionManager.js +172 -0
  20. package/dist/modules/camo-backend/src/internal/container-matcher.js +852 -0
  21. package/dist/modules/camo-backend/src/internal/engine-manager.js +258 -0
  22. package/dist/modules/camo-backend/src/internal/fingerprint.js +203 -0
  23. package/dist/modules/camo-backend/src/internal/pageRuntime.js +29 -0
  24. package/dist/modules/camo-backend/src/internal/runtimeInjector.js +30 -0
  25. package/dist/modules/camo-backend/src/internal/state-bus.js +46 -0
  26. package/dist/modules/camo-backend/src/internal/storage-paths.js +36 -0
  27. package/dist/modules/camo-backend/src/internal/ws-server.js +1202 -0
  28. package/dist/modules/camo-runtime/src/utils/browser-service.mjs +423 -0
  29. package/dist/modules/camo-runtime/src/utils/config.mjs +77 -0
  30. package/dist/modules/container-registry/src/index.js +184 -0
  31. package/dist/modules/logging/src/index.js +92 -0
  32. package/dist/modules/operations/src/builtin.js +27 -0
  33. package/dist/modules/operations/src/container-binding.js +75 -0
  34. package/dist/modules/operations/src/executor.js +146 -0
  35. package/dist/modules/operations/src/operations/click.js +167 -0
  36. package/dist/modules/operations/src/operations/extract.js +204 -0
  37. package/dist/modules/operations/src/operations/find-child.js +17 -0
  38. package/dist/modules/operations/src/operations/highlight.js +138 -0
  39. package/dist/modules/operations/src/operations/key.js +61 -0
  40. package/dist/modules/operations/src/operations/navigate.js +148 -0
  41. package/dist/modules/operations/src/operations/scroll.js +126 -0
  42. package/dist/modules/operations/src/operations/type.js +190 -0
  43. package/dist/modules/operations/src/queue.js +100 -0
  44. package/dist/modules/operations/src/registry.js +11 -0
  45. package/dist/modules/operations/src/system/mouse.js +33 -0
  46. package/dist/modules/state/src/atomic-json.js +33 -0
  47. package/dist/modules/workflow/blocks/AnchorVerificationBlock.js +71 -0
  48. package/dist/modules/workflow/blocks/BehaviorRandomizer.js +26 -0
  49. package/dist/modules/workflow/blocks/CallWorkflowBlock.js +38 -0
  50. package/dist/modules/workflow/blocks/CloseDetailBlock.js +209 -0
  51. package/dist/modules/workflow/blocks/CollectBatch.js +137 -0
  52. package/dist/modules/workflow/blocks/CollectCommentsBlock.js +415 -0
  53. package/dist/modules/workflow/blocks/CollectSearchListBlock.js +599 -0
  54. package/dist/modules/workflow/blocks/CollectWeiboPosts.js +229 -0
  55. package/dist/modules/workflow/blocks/DetectPageStateBlock.js +259 -0
  56. package/dist/modules/workflow/blocks/EnsureLoginBlock.js +162 -0
  57. package/dist/modules/workflow/blocks/EnsureSession.js +426 -0
  58. package/dist/modules/workflow/blocks/ErrorClassifier.js +164 -0
  59. package/dist/modules/workflow/blocks/ErrorRecoveryBlock.js +319 -0
  60. package/dist/modules/workflow/blocks/ExpandCommentsBlock.js +1032 -0
  61. package/dist/modules/workflow/blocks/ExtractDetailBlock.js +310 -0
  62. package/dist/modules/workflow/blocks/ExtractPostFields.js +88 -0
  63. package/dist/modules/workflow/blocks/GenerateSmartReplyBlock.js +68 -0
  64. package/dist/modules/workflow/blocks/GoToSearchBlock.js +497 -0
  65. package/dist/modules/workflow/blocks/GracefulFallbackBlock.js +104 -0
  66. package/dist/modules/workflow/blocks/HighlightBlock.js +66 -0
  67. package/dist/modules/workflow/blocks/InitAutoScroll.js +65 -0
  68. package/dist/modules/workflow/blocks/LoadContainerDefinition.js +50 -0
  69. package/dist/modules/workflow/blocks/LoadContainerIndex.js +43 -0
  70. package/dist/modules/workflow/blocks/LocateAndGuardBlock.js +176 -0
  71. package/dist/modules/workflow/blocks/LoginRecoveryBlock.js +242 -0
  72. package/dist/modules/workflow/blocks/MatchContainers.js +64 -0
  73. package/dist/modules/workflow/blocks/MonitoringBlock.js +190 -0
  74. package/dist/modules/workflow/blocks/OpenDetailBlock.js +1240 -0
  75. package/dist/modules/workflow/blocks/OrganizeXhsNotesBlock.js +117 -0
  76. package/dist/modules/workflow/blocks/PersistXhsNoteBlock.js +270 -0
  77. package/dist/modules/workflow/blocks/PickSinglePost.js +69 -0
  78. package/dist/modules/workflow/blocks/ProgressTracker.js +125 -0
  79. package/dist/modules/workflow/blocks/RecordFixtureBlock.js +44 -0
  80. package/dist/modules/workflow/blocks/RenderMarkdown.js +48 -0
  81. package/dist/modules/workflow/blocks/SaveFile.js +54 -0
  82. package/dist/modules/workflow/blocks/ScrollNextBatch.js +72 -0
  83. package/dist/modules/workflow/blocks/SessionHealthBlock.js +73 -0
  84. package/dist/modules/workflow/blocks/StartBrowserService.js +45 -0
  85. package/dist/modules/workflow/blocks/ValidateContainerDefinition.js +67 -0
  86. package/dist/modules/workflow/blocks/ValidateExtract.js +35 -0
  87. package/dist/modules/workflow/blocks/WaitSearchPermitBlock.js +162 -0
  88. package/dist/modules/workflow/blocks/WaitStable.js +74 -0
  89. package/dist/modules/workflow/blocks/WarmupCommentsBlock.js +120 -0
  90. package/dist/modules/workflow/blocks/WorkflowExecutor.js +156 -0
  91. package/dist/modules/workflow/blocks/XiaohongshuCollectFromLinksBlock.js +1004 -0
  92. package/dist/modules/workflow/blocks/XiaohongshuCollectLinksBlock.js +1049 -0
  93. package/dist/modules/workflow/blocks/XiaohongshuFullCollectBlock.js +782 -0
  94. package/dist/modules/workflow/blocks/helpers/anchorVerify.js +198 -0
  95. package/dist/modules/workflow/blocks/helpers/asyncWorkQueue.js +53 -0
  96. package/dist/modules/workflow/blocks/helpers/commentScroller.js +334 -0
  97. package/dist/modules/workflow/blocks/helpers/commentSectionLocator.js +126 -0
  98. package/dist/modules/workflow/blocks/helpers/containerAnchors.js +301 -0
  99. package/dist/modules/workflow/blocks/helpers/debugArtifacts.js +6 -0
  100. package/dist/modules/workflow/blocks/helpers/downloadPaths.js +29 -0
  101. package/dist/modules/workflow/blocks/helpers/expandCommentsController.js +53 -0
  102. package/dist/modules/workflow/blocks/helpers/expandCommentsExtractor.js +129 -0
  103. package/dist/modules/workflow/blocks/helpers/macosVisionOcrPlugin.js +116 -0
  104. package/dist/modules/workflow/blocks/helpers/mergeXhsMarkdown.js +109 -0
  105. package/dist/modules/workflow/blocks/helpers/openDetailController.js +56 -0
  106. package/dist/modules/workflow/blocks/helpers/openDetailTypes.js +7 -0
  107. package/dist/modules/workflow/blocks/helpers/openDetailViewport.js +474 -0
  108. package/dist/modules/workflow/blocks/helpers/openDetailWaiter.js +104 -0
  109. package/dist/modules/workflow/blocks/helpers/operationLogger.js +195 -0
  110. package/dist/modules/workflow/blocks/helpers/persistedNotes.js +107 -0
  111. package/dist/modules/workflow/blocks/helpers/replyExpander.js +260 -0
  112. package/dist/modules/workflow/blocks/helpers/scrollIntoView.js +138 -0
  113. package/dist/modules/workflow/blocks/helpers/searchExecutor.js +328 -0
  114. package/dist/modules/workflow/blocks/helpers/searchGate.js +46 -0
  115. package/dist/modules/workflow/blocks/helpers/searchPageState.js +164 -0
  116. package/dist/modules/workflow/blocks/helpers/searchResultWaiter.js +64 -0
  117. package/dist/modules/workflow/blocks/helpers/simpleAnchor.js +134 -0
  118. package/dist/modules/workflow/blocks/helpers/smartReply.js +40 -0
  119. package/dist/modules/workflow/blocks/helpers/systemInput.js +635 -0
  120. package/dist/modules/workflow/blocks/helpers/targetCountMode.js +9 -0
  121. package/dist/modules/workflow/blocks/helpers/xhsCliArgs.js +80 -0
  122. package/dist/modules/workflow/blocks/helpers/xhsCommentDom.js +805 -0
  123. package/dist/modules/workflow/blocks/helpers/xhsNoteOrganizer.js +140 -0
  124. package/dist/modules/workflow/blocks/restore/RestorePhaseBlock.js +204 -0
  125. package/dist/modules/workflow/config/workflowRegistry.js +32 -0
  126. package/dist/modules/workflow/definitions/batch-collect-workflow.js +63 -0
  127. package/dist/modules/workflow/definitions/scroll-extract-workflow.js +74 -0
  128. package/dist/modules/workflow/definitions/xiaohongshu-collect-workflow-v2.js +81 -0
  129. package/dist/modules/workflow/definitions/xiaohongshu-collect-workflow.js +57 -0
  130. package/dist/modules/workflow/definitions/xiaohongshu-full-collect-workflow-v3.js +68 -0
  131. package/dist/modules/workflow/definitions/xiaohongshu-note-collect.js +49 -0
  132. package/dist/modules/workflow/definitions/xiaohongshu-phase1-workflow-v3.js +30 -0
  133. package/dist/modules/workflow/definitions/xiaohongshu-phase2-links-workflow-v3.js +40 -0
  134. package/dist/modules/workflow/definitions/xiaohongshu-phase3-collect-workflow-v1.js +54 -0
  135. package/dist/modules/workflow/definitions/xiaohongshu-phase34-from-links-workflow-v3.js +25 -0
  136. package/dist/modules/workflow/src/WeiboEventDrivenWorkflowRunner.js +308 -0
  137. package/dist/modules/workflow/src/context.js +70 -0
  138. package/dist/modules/workflow/src/index.js +5 -0
  139. package/dist/modules/workflow/src/orchestrator.js +230 -0
  140. package/dist/modules/workflow/src/runner.js +55 -0
  141. package/dist/modules/workflow/src/runtime.js +70 -0
  142. package/dist/modules/workflow/workflows/WeiboFeedExtractionWorkflow.js +359 -0
  143. package/dist/modules/workflow/workflows/XiaohongshuLoginWorkflow.js +110 -0
  144. package/dist/modules/xiaohongshu/app/src/blocks/MatchCommentsBlock.js +139 -0
  145. package/dist/modules/xiaohongshu/app/src/blocks/Phase1EnsureServicesBlock.js +36 -0
  146. package/dist/modules/xiaohongshu/app/src/blocks/Phase1MonitorCookieBlock.js +213 -0
  147. package/dist/modules/xiaohongshu/app/src/blocks/Phase1StartProfileBlock.js +121 -0
  148. package/dist/modules/xiaohongshu/app/src/blocks/Phase2CollectLinksBlock.js +1249 -0
  149. package/dist/modules/xiaohongshu/app/src/blocks/Phase2SearchBlock.js +703 -0
  150. package/dist/modules/xiaohongshu/app/src/blocks/Phase34CloseDetailBlock.js +41 -0
  151. package/dist/modules/xiaohongshu/app/src/blocks/Phase34CloseTabsBlock.js +44 -0
  152. package/dist/modules/xiaohongshu/app/src/blocks/Phase34CollectCommentsBlock.js +150 -0
  153. package/dist/modules/xiaohongshu/app/src/blocks/Phase34ExtractDetailBlock.js +117 -0
  154. package/dist/modules/xiaohongshu/app/src/blocks/Phase34OpenDetailBlock.js +102 -0
  155. package/dist/modules/xiaohongshu/app/src/blocks/Phase34OpenTabsBlock.js +109 -0
  156. package/dist/modules/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.js +117 -0
  157. package/dist/modules/xiaohongshu/app/src/blocks/Phase34ProcessSingleNoteBlock.js +114 -0
  158. package/dist/modules/xiaohongshu/app/src/blocks/Phase34ValidateLinksBlock.js +90 -0
  159. package/dist/modules/xiaohongshu/app/src/blocks/Phase3InteractBlock.js +1009 -0
  160. package/dist/modules/xiaohongshu/app/src/blocks/Phase4MultiTabHarvestBlock.js +233 -0
  161. package/dist/modules/xiaohongshu/app/src/blocks/ReplyInteractBlock.js +291 -0
  162. package/dist/modules/xiaohongshu/app/src/blocks/XhsDiscoverFallbackBlock.js +240 -0
  163. package/dist/modules/xiaohongshu/app/src/blocks/helpers/commentMatchDsl.js +126 -0
  164. package/dist/modules/xiaohongshu/app/src/blocks/helpers/commentMatcher.js +99 -0
  165. package/dist/modules/xiaohongshu/app/src/blocks/helpers/evidence.js +27 -0
  166. package/dist/modules/xiaohongshu/app/src/blocks/helpers/sharding.js +42 -0
  167. package/dist/modules/xiaohongshu/app/src/blocks/helpers/xhsComments.js +270 -0
  168. package/dist/modules/xiaohongshu/app/src/index.js +9 -0
  169. package/dist/modules/xiaohongshu/app/src/utils/checkpoints.js +222 -0
  170. package/dist/modules/xiaohongshu/app/src/utils/controllerAction.js +43 -0
  171. package/dist/services/controller/src/controller.js +1476 -0
  172. package/dist/services/controller/src/index.js +2 -0
  173. package/dist/services/controller/src/payload-normalizer.js +129 -0
  174. package/dist/services/shared/heartbeat.js +120 -0
  175. package/dist/services/shared/lib/errorHandler.js +2 -0
  176. package/dist/services/shared/serviceProcessLogger.js +139 -0
  177. package/dist/services/unified-api/RemoteBrowserSession.js +176 -0
  178. package/dist/services/unified-api/RemoteSessionManager.js +148 -0
  179. package/dist/services/unified-api/container-operations-handler.js +115 -0
  180. package/dist/services/unified-api/server.js +652 -0
  181. package/dist/services/unified-api/state-registry.js +274 -0
  182. package/dist/services/unified-api/task-persistence.js +66 -0
  183. package/dist/services/unified-api/task-state.js +130 -0
  184. package/modules/camo-runtime/src/autoscript/action-providers/xhs/search.mjs +12 -5
  185. package/modules/xiaohongshu/app/pnpm-lock.yaml +24 -0
  186. package/package.json +38 -10
  187. package/.beads/README.md +0 -81
  188. package/.beads/config.yaml +0 -67
  189. package/.beads/interactions.jsonl +0 -0
  190. package/.beads/issues.jsonl +0 -180
  191. package/.beads/metadata.json +0 -4
  192. package/.claude/settings.local.json +0 -10
  193. package/.github/workflows/ci.yml +0 -55
  194. package/AGENTS.md +0 -253
  195. package/apps/desktop-console/README.md +0 -27
  196. package/apps/desktop-console/package-lock.json +0 -897
  197. package/apps/desktop-console/package.json +0 -20
  198. package/apps/desktop-console/scripts/build-and-install.mjs +0 -19
  199. package/apps/desktop-console/scripts/build.mjs +0 -45
  200. package/apps/desktop-console/scripts/test-preload.mjs +0 -13
  201. package/apps/desktop-console/src/main/config.mts +0 -26
  202. package/apps/desktop-console/src/main/core-daemon-manager.mts +0 -131
  203. package/apps/desktop-console/src/main/desktop-settings.mts +0 -267
  204. package/apps/desktop-console/src/main/heartbeat-watchdog.mts +0 -50
  205. package/apps/desktop-console/src/main/heartbeat-watchdog.test.mts +0 -68
  206. package/apps/desktop-console/src/main/index-streaming.test.mts +0 -20
  207. package/apps/desktop-console/src/main/index.mts +0 -980
  208. package/apps/desktop-console/src/main/profile-store.mts +0 -239
  209. package/apps/desktop-console/src/main/profile-store.test.mts +0 -54
  210. package/apps/desktop-console/src/main/state-bridge.mts +0 -114
  211. package/apps/desktop-console/src/main/task-state-types.ts +0 -32
  212. package/apps/desktop-console/src/renderer/hooks/use-task-state.mts +0 -120
  213. package/apps/desktop-console/src/renderer/index.mts +0 -133
  214. package/apps/desktop-console/src/renderer/index.test.mts +0 -34
  215. package/apps/desktop-console/src/renderer/path-helpers.mts +0 -46
  216. package/apps/desktop-console/src/renderer/path-helpers.test.mts +0 -14
  217. package/apps/desktop-console/src/renderer/tabs/debug.mts +0 -48
  218. package/apps/desktop-console/src/renderer/tabs/debug.test.mts +0 -22
  219. package/apps/desktop-console/src/renderer/tabs/logs.mts +0 -421
  220. package/apps/desktop-console/src/renderer/tabs/logs.test.mts +0 -27
  221. package/apps/desktop-console/src/renderer/tabs/preflight.mts +0 -486
  222. package/apps/desktop-console/src/renderer/tabs/preflight.test.mts +0 -33
  223. package/apps/desktop-console/src/renderer/tabs/profile-pool.mts +0 -213
  224. package/apps/desktop-console/src/renderer/tabs/results.mts +0 -171
  225. package/apps/desktop-console/src/renderer/tabs/run.test.mts +0 -63
  226. package/apps/desktop-console/src/renderer/tabs/runtime.mts +0 -151
  227. package/apps/desktop-console/src/renderer/tabs/settings.mts +0 -146
  228. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/account-flow.mts +0 -486
  229. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/guide-browser-check.mts +0 -56
  230. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/helpers.mts +0 -262
  231. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/layout-block.mts +0 -430
  232. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/live-stats.mts +0 -847
  233. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/run-flow.mts +0 -443
  234. package/apps/desktop-console/src/renderer/tabs/xiaohongshu-state.mts +0 -425
  235. package/apps/desktop-console/src/renderer/tabs/xiaohongshu.mts +0 -497
  236. package/apps/desktop-console/src/renderer/tabs/xiaohongshu.test.mts +0 -291
  237. package/apps/desktop-console/src/renderer/ui-components.mts +0 -31
  238. package/docs/README_camoufox_chinese.md +0 -141
  239. package/docs/USAGE_V3.md +0 -163
  240. package/docs/arch/OCR_MACOS_PLUGIN.md +0 -39
  241. package/docs/arch/PORTS.md +0 -40
  242. package/docs/arch/REGRESSION_CHECKLIST.md +0 -121
  243. package/docs/arch/SEARCH_GATE.md +0 -224
  244. package/docs/arch/VIEWPORT_SAFETY.md +0 -182
  245. package/docs/arch/XIAOHONGSHU_OFFLINE_MOCK_DESIGN.md +0 -267
  246. package/docs/xiaohongshu-container-driven-summary.md +0 -221
  247. package/docs/xiaohongshu-full-collect-runbook.md +0 -134
  248. package/docs/xiaohongshu-next-steps.md +0 -228
  249. package/docs/xiaohongshu-quickstart.md +0 -73
  250. package/docs/xiaohongshu-workflow-summary.md +0 -227
  251. package/modules/container-registry/tests/container-registry.test.ts +0 -16
  252. package/modules/logging/tests/logging.test.ts +0 -38
  253. package/modules/operations/tests/operations.test.ts +0 -22
  254. package/modules/operations/tests/viewport-filter.test.ts +0 -161
  255. package/modules/operations/tests/visible-only.test.ts +0 -250
  256. package/modules/session-manager/tests/session-manager.test.ts +0 -23
  257. package/modules/state/src/atomic-json.test.ts +0 -30
  258. package/modules/state/src/paths.test.ts +0 -59
  259. package/modules/state/src/xiaohongshu-collect-state.test.ts +0 -259
  260. package/modules/workflow/blocks/AnchorVerificationBlock.d.ts.map +0 -1
  261. package/modules/workflow/blocks/AnchorVerificationBlock.js.map +0 -1
  262. package/modules/workflow/blocks/DetectPageStateBlock.d.ts.map +0 -1
  263. package/modules/workflow/blocks/DetectPageStateBlock.js.map +0 -1
  264. package/modules/workflow/blocks/ErrorRecoveryBlock.d.ts.map +0 -1
  265. package/modules/workflow/blocks/ErrorRecoveryBlock.js.map +0 -1
  266. package/modules/workflow/blocks/WaitSearchPermitBlock.d.ts.map +0 -1
  267. package/modules/workflow/blocks/WaitSearchPermitBlock.js.map +0 -1
  268. package/modules/workflow/blocks/helpers/containerAnchors.d.ts.map +0 -1
  269. package/modules/workflow/blocks/helpers/containerAnchors.js.map +0 -1
  270. package/modules/workflow/blocks/helpers/downloadPaths.test.ts +0 -62
  271. package/modules/workflow/blocks/helpers/mergeXhsMarkdown.test.ts +0 -121
  272. package/modules/workflow/blocks/helpers/operationLogger.d.ts.map +0 -1
  273. package/modules/workflow/blocks/helpers/operationLogger.js.map +0 -1
  274. package/modules/workflow/blocks/helpers/persistedNotes.test.ts +0 -268
  275. package/modules/workflow/blocks/helpers/searchPageState.d.ts.map +0 -1
  276. package/modules/workflow/blocks/helpers/searchPageState.js.map +0 -1
  277. package/modules/workflow/blocks/helpers/targetCountMode.test.ts +0 -29
  278. package/modules/workflow/blocks/helpers/xhsCliArgs.test.ts +0 -75
  279. package/modules/workflow/tests/smartReply.test.ts +0 -32
  280. package/modules/xiaohongshu/app/src/blocks/Phase3Interact.matcher.test.ts +0 -33
  281. package/modules/xiaohongshu/app/src/utils/__tests__/checkpoints.test.ts +0 -141
  282. package/modules/xiaohongshu/app/tests/commentMatchDsl.test.ts +0 -50
  283. package/modules/xiaohongshu/app/tests/commentMatcher.test.ts +0 -46
  284. package/modules/xiaohongshu/app/tests/sharding.test.ts +0 -31
  285. package/package-scripts.json +0 -8
  286. package/runtime/infra/utils/README.md +0 -13
  287. package/runtime/infra/utils/scripts/README.md +0 -0
  288. package/runtime/infra/utils/scripts/development/eval-in-session.mjs +0 -40
  289. package/runtime/infra/utils/scripts/development/highlight-search-containers.mjs +0 -35
  290. package/runtime/infra/utils/scripts/service/kill-port.mjs +0 -24
  291. package/runtime/infra/utils/scripts/service/start-api.mjs +0 -39
  292. package/runtime/infra/utils/scripts/service/start-browser-service.mjs +0 -106
  293. package/runtime/infra/utils/scripts/service/stop-api.mjs +0 -18
  294. package/runtime/infra/utils/scripts/service/stop-browser-service.mjs +0 -104
  295. package/runtime/infra/utils/scripts/test-services.mjs +0 -94
  296. package/services/shared/heartbeat.test.ts +0 -102
  297. package/services/unified-api/__tests__/task-state.test.ts +0 -95
  298. package/sitecustomize.py +0 -19
  299. package/tests/README.md +0 -194
  300. package/tests/e2e/workflows/weibo-feed-extraction.test.ts +0 -171
  301. package/tests/fixtures/data/container-definitions.json +0 -67
  302. package/tests/fixtures/pages/simple-page.html +0 -69
  303. package/tests/integration/01-test-container-match.mjs +0 -188
  304. package/tests/integration/02-test-dom-branch.mjs +0 -161
  305. package/tests/integration/03-test-container-operation-system.mjs +0 -91
  306. package/tests/integration/05-test-container-lifecycle-events.mjs +0 -224
  307. package/tests/integration/05-test-container-lifecycle-with-events.mjs +0 -250
  308. package/tests/integration/06-test-container-dom-tree-drawing.mjs +0 -256
  309. package/tests/integration/07-test-weibo-container-lifecycle.mjs +0 -355
  310. package/tests/integration/08-test-weibo-feed-workflow.test.mjs +0 -164
  311. package/tests/integration/10-test-visual-analyzer.mjs +0 -312
  312. package/tests/integration/11-test-visual-loop.mjs +0 -284
  313. package/tests/integration/12-test-simple-visual-loop.mjs +0 -242
  314. package/tests/integration/13-test-visual-robust.mjs +0 -185
  315. package/tests/integration/14-test-visual-highlight-loop.mjs +0 -271
  316. package/tests/integration/inspect-page.mjs +0 -50
  317. package/tests/integration/run-all-tests.mjs +0 -95
  318. package/tests/patch_verification/CODEX_PATCH_TEST.md +0 -103
  319. package/tests/patch_verification/PHASE2_ANALYSIS.md +0 -179
  320. package/tests/patch_verification/PHASE2_OPTIMIZATION_REPORT.md +0 -55
  321. package/tests/patch_verification/PHASE2_TO_PHASE4_SUMMARY.md +0 -126
  322. package/tests/patch_verification/QUICK_TEST_SEQUENCE.md +0 -262
  323. package/tests/patch_verification/README.md +0 -143
  324. package/tests/patch_verification/RUN_TESTS.md +0 -60
  325. package/tests/patch_verification/TEST_EXECUTION.md +0 -99
  326. package/tests/patch_verification/TEST_PLAN.md +0 -328
  327. package/tests/patch_verification/TEST_RESULTS.md +0 -34
  328. package/tests/patch_verification/TOOL_TEST_PLAN.md +0 -48
  329. package/tests/patch_verification/run-tool-test.mjs +0 -121
  330. package/tests/patch_verification/temp_test_files/test01.txt +0 -1
  331. package/tests/patch_verification/temp_test_files/test02.txt +0 -3
  332. package/tests/patch_verification/temp_test_files/test02_gnu.txt +0 -3
  333. package/tests/patch_verification/temp_test_files/test03.txt +0 -1
  334. package/tests/patch_verification/temp_test_files/test03_multiline.txt +0 -5
  335. package/tests/patch_verification/temp_test_files/test04_function.ts +0 -5
  336. package/tests/patch_verification/temp_test_files/test05_import.ts +0 -4
  337. package/tests/patch_verification/temp_test_files/test06_special_chars.txt +0 -4
  338. package/tests/patch_verification/temp_test_files/test07_indentation.ts +0 -5
  339. package/tests/patch_verification/temp_test_files/test08_mismatch.txt +0 -1
  340. package/tests/patch_verification/temp_test_files/test_add_02.txt +0 -3
  341. package/tests/patch_verification/temp_test_files/test_simple.txt +0 -1
  342. package/tests/runner/TestReporter.mjs +0 -57
  343. package/tests/runner/TestRunner.mjs +0 -244
  344. package/tests/unit/commands/profile.test.mjs +0 -10
  345. package/tests/unit/container/change-notifier.test.mjs +0 -181
  346. package/tests/unit/lifecycle/session-registry.test.mjs +0 -135
  347. package/tests/unit/operations/registry.test.ts +0 -73
  348. package/tests/unit/utils/browser-service.test.mjs +0 -153
  349. package/tests/unit/utils/config.test.mjs +0 -166
  350. package/tests/unit/utils/fingerprint.test.mjs +0 -166
  351. package/tsconfig.json +0 -31
  352. package/tsconfig.services.json +0 -26
  353. /package/apps/desktop-console/{src → dist}/renderer/index.html +0 -0
  354. /package/apps/desktop-console/{src/renderer/tabs → dist/renderer}/run.mts +0 -0
@@ -1,239 +0,0 @@
1
- import os from 'node:os';
2
- import path from 'node:path';
3
- import { promises as fs } from 'node:fs';
4
- import { pathToFileURL } from 'node:url';
5
-
6
- export type ProfileScanEntry = {
7
- profileId: string;
8
- profileDir: string;
9
- profileMtimeMs: number;
10
- fingerprintPath: string;
11
- fingerprintMtimeMs: number | null;
12
- fingerprint: {
13
- platform?: string;
14
- originalPlatform?: string;
15
- osVersion?: string;
16
- userAgent?: string;
17
- viewport?: { width?: number; height?: number };
18
- fingerprintSalt?: string;
19
- } | null;
20
- };
21
-
22
- export type ProfileScanResult = {
23
- ok: true;
24
- profilesRoot: string;
25
- fingerprintsRoot: string;
26
- entries: ProfileScanEntry[];
27
- };
28
-
29
- export type ProfileStore = {
30
- listProfiles: () => Promise<{ ok: true; root: string; profiles: string[] }>;
31
- scanProfiles: () => Promise<ProfileScanResult>;
32
- profileCreate: (input: { profileId: string }) => Promise<{ ok: true; profileId: string; profileDir: string }>;
33
- profileDelete: (input: { profileId: string; deleteFingerprint?: boolean }) => Promise<{ ok: true; profileId: string }>;
34
- fingerprintDelete: (input: { profileId: string }) => Promise<{ ok: true; profileId: string }>;
35
- fingerprintRegenerate: (input: {
36
- profileId: string;
37
- platform?: 'windows' | 'macos' | 'random';
38
- }) => Promise<{
39
- ok: true;
40
- profileId: string;
41
- fingerprintPath: string;
42
- fingerprint: {
43
- platform?: string;
44
- originalPlatform?: string;
45
- osVersion?: string;
46
- userAgent?: string;
47
- viewport?: { width?: number; height?: number };
48
- fingerprintSalt?: string;
49
- };
50
- }>;
51
- };
52
-
53
- type Options = {
54
- repoRoot: string;
55
- homeDir?: string;
56
- };
57
-
58
- function resolveHomeDir(opts: Options) {
59
- if (opts.homeDir) return opts.homeDir;
60
- const homeDir =
61
- process.platform === 'win32'
62
- ? (process.env.USERPROFILE || os.homedir() || '')
63
- : (process.env.HOME || os.homedir() || '');
64
- if (!homeDir) throw new Error('无法获取用户主目录:HOME/USERPROFILE 未设置');
65
- return homeDir;
66
- }
67
-
68
- function resolvePortableRoot(opts: Options) {
69
- const root = String(process.env.WEBAUTO_PORTABLE_ROOT || process.env.WEBAUTO_ROOT || '').trim();
70
- if (!root) return '';
71
- return path.join(root, '.webauto');
72
- }
73
-
74
- function isWithinDir(root: string, target: string) {
75
- const rel = path.relative(root, target);
76
- return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));
77
- }
78
-
79
- function validateProfileId(profileId: string) {
80
- const id = String(profileId || '').trim();
81
- if (!id) throw new Error('profileId 不能为空');
82
- if (id === '.' || id === '..') throw new Error('profileId 非法');
83
- if (/[\\/]/.test(id)) throw new Error('profileId 不能包含路径分隔符');
84
- return id;
85
- }
86
-
87
- function resolveRoots(opts: Options) {
88
- const homeDir = resolveHomeDir(opts);
89
- const envProfiles = String(process.env.WEBAUTO_PATHS_PROFILES || '').trim();
90
- const envFingerprints = String(process.env.WEBAUTO_PATHS_FINGERPRINTS || '').trim();
91
- const portable = resolvePortableRoot(opts);
92
- return {
93
- profilesRoot: envProfiles || (portable ? path.join(portable, 'profiles') : path.join(homeDir, '.webauto', 'profiles')),
94
- fingerprintsRoot: envFingerprints || (portable ? path.join(portable, 'fingerprints') : path.join(homeDir, '.webauto', 'fingerprints')),
95
- };
96
- }
97
-
98
- function resolveProfileDir(opts: Options, profileId: string) {
99
- const { profilesRoot } = resolveRoots(opts);
100
- const profileDir = path.join(profilesRoot, profileId);
101
- if (!isWithinDir(profilesRoot, profileDir)) throw new Error('unsafe profile path');
102
- return { profilesRoot, profileDir };
103
- }
104
-
105
- function resolveFingerprintPath(opts: Options, profileId: string) {
106
- const { fingerprintsRoot } = resolveRoots(opts);
107
- const fingerprintPath = path.join(fingerprintsRoot, `${profileId}.json`);
108
- if (!isWithinDir(fingerprintsRoot, fingerprintPath)) throw new Error('unsafe fingerprint path');
109
- return { fingerprintsRoot, fingerprintPath };
110
- }
111
-
112
- export function createProfileStore(opts: Options): ProfileStore {
113
- let cachedFingerprintMod: any = null;
114
- async function getFingerprintModule() {
115
- if (cachedFingerprintMod) return cachedFingerprintMod;
116
- const p = path.join(opts.repoRoot, 'dist', 'modules', 'camo-backend', 'src', 'internal', 'fingerprint.js');
117
- cachedFingerprintMod = await import(pathToFileURL(p).href);
118
- return cachedFingerprintMod;
119
- }
120
-
121
- async function listProfiles() {
122
- const { profilesRoot } = resolveRoots(opts);
123
- const entries: string[] = [];
124
- try {
125
- const dirs = await fs.readdir(profilesRoot, { withFileTypes: true });
126
- for (const ent of dirs) {
127
- if (!ent.isDirectory()) continue;
128
- const name = ent.name;
129
- if (!name || name.startsWith('.')) continue;
130
- entries.push(name);
131
- }
132
- } catch {
133
- // ignore
134
- }
135
- entries.sort((a, b) => a.localeCompare(b));
136
- return { ok: true as const, root: profilesRoot, profiles: entries };
137
- }
138
-
139
- async function scanProfiles(): Promise<ProfileScanResult> {
140
- const { profilesRoot, fingerprintsRoot } = resolveRoots(opts);
141
- const entries: ProfileScanEntry[] = [];
142
-
143
- const dirs = await fs.readdir(profilesRoot, { withFileTypes: true }).catch(() => []);
144
- for (const ent of dirs) {
145
- if (!ent.isDirectory()) continue;
146
- const profileId = ent.name;
147
- if (!profileId || profileId.startsWith('.')) continue;
148
-
149
- const profileDir = path.join(profilesRoot, profileId);
150
- const profileStat = await fs.stat(profileDir).catch(() => null);
151
-
152
- const fingerprintPath = path.join(fingerprintsRoot, `${profileId}.json`);
153
- const fpStat = await fs.stat(fingerprintPath).catch(() => null);
154
- let fingerprint: ProfileScanEntry['fingerprint'] = null;
155
- if (fpStat?.isFile()) {
156
- try {
157
- const raw = await fs.readFile(fingerprintPath, 'utf8');
158
- const parsed = JSON.parse(raw || '{}');
159
- if (parsed && typeof parsed === 'object') fingerprint = parsed as any;
160
- } catch {
161
- fingerprint = null;
162
- }
163
- }
164
-
165
- entries.push({
166
- profileId,
167
- profileDir,
168
- profileMtimeMs: profileStat?.mtimeMs || 0,
169
- fingerprintPath,
170
- fingerprintMtimeMs: fpStat?.mtimeMs || null,
171
- fingerprint,
172
- });
173
- }
174
-
175
- entries.sort((a, b) => {
176
- if (a.profileMtimeMs !== b.profileMtimeMs) return b.profileMtimeMs - a.profileMtimeMs;
177
- return a.profileId.localeCompare(b.profileId);
178
- });
179
-
180
- return { ok: true, profilesRoot, fingerprintsRoot, entries };
181
- }
182
-
183
- async function profileCreate(input: { profileId: string }) {
184
- const profileId = validateProfileId(input?.profileId);
185
- const { profileDir } = resolveProfileDir(opts, profileId);
186
- await fs.mkdir(profileDir, { recursive: true });
187
- return { ok: true as const, profileId, profileDir };
188
- }
189
-
190
- async function profileDelete(input: { profileId: string; deleteFingerprint?: boolean }) {
191
- const profileId = validateProfileId(input?.profileId);
192
- const { profileDir } = resolveProfileDir(opts, profileId);
193
- await fs.rm(profileDir, { recursive: true, force: true });
194
- if (input?.deleteFingerprint) {
195
- const { fingerprintPath } = resolveFingerprintPath(opts, profileId);
196
- await fs.rm(fingerprintPath, { force: true });
197
- }
198
- return { ok: true as const, profileId };
199
- }
200
-
201
- async function fingerprintDelete(input: { profileId: string }) {
202
- const profileId = validateProfileId(input?.profileId);
203
- const { fingerprintPath } = resolveFingerprintPath(opts, profileId);
204
- await fs.rm(fingerprintPath, { force: true });
205
- return { ok: true as const, profileId };
206
- }
207
-
208
- async function fingerprintRegenerate(input: { profileId: string; platform?: 'windows' | 'macos' | 'random' }) {
209
- const profileId = validateProfileId(input?.profileId);
210
- const mod = await getFingerprintModule();
211
- const platform = input?.platform === 'windows' || input?.platform === 'macos' ? input.platform : null;
212
- const { fingerprintPath } = resolveFingerprintPath(opts, profileId);
213
- const fingerprint = mod.generateFingerprint(profileId, { platform });
214
- const saved = await mod.saveFingerprint(fingerprintPath, fingerprint);
215
- if (!saved) throw new Error('failed to save fingerprint');
216
- return {
217
- ok: true as const,
218
- profileId,
219
- fingerprintPath,
220
- fingerprint: {
221
- platform: fingerprint?.platform,
222
- originalPlatform: fingerprint?.originalPlatform,
223
- osVersion: fingerprint?.osVersion,
224
- userAgent: fingerprint?.userAgent,
225
- viewport: fingerprint?.viewport,
226
- fingerprintSalt: fingerprint?.fingerprintSalt,
227
- },
228
- };
229
- }
230
-
231
- return {
232
- listProfiles,
233
- scanProfiles,
234
- profileCreate,
235
- profileDelete,
236
- fingerprintDelete,
237
- fingerprintRegenerate,
238
- };
239
- }
@@ -1,54 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import os from 'node:os';
3
- import path from 'node:path';
4
- import { promises as fs } from 'node:fs';
5
-
6
- import { createProfileStore } from './profile-store.mts';
7
-
8
- async function withTempDir(fn: (dir: string) => Promise<void>) {
9
- const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'webauto-desktop-console-'));
10
- try {
11
- await fn(dir);
12
- } finally {
13
- await fs.rm(dir, { recursive: true, force: true });
14
- }
15
- }
16
-
17
- await withTempDir(async (homeDir) => {
18
- const store = createProfileStore({ repoRoot: process.cwd(), homeDir });
19
-
20
- const list0 = await store.listProfiles();
21
- assert.deepStrictEqual(list0.profiles, []);
22
-
23
- const scan0 = await store.scanProfiles();
24
- assert.equal(scan0.ok, true);
25
- assert.equal(scan0.entries.length, 0);
26
-
27
- await store.profileCreate({ profileId: 'xiaohongshu_fresh' });
28
- const scan1 = await store.scanProfiles();
29
- assert.equal(scan1.entries.length, 1);
30
- assert.equal(scan1.entries[0]!.profileId, 'xiaohongshu_fresh');
31
- assert.equal(!!scan1.entries[0]!.fingerprint, false);
32
-
33
- // Regenerate fingerprint for the created profile.
34
- const regen = await store.fingerprintRegenerate({ profileId: 'xiaohongshu_fresh', platform: 'random' });
35
- assert.equal(regen.ok, true);
36
- assert.ok(regen.fingerprint.userAgent);
37
-
38
- const scan2 = await store.scanProfiles();
39
- assert.equal(scan2.entries.length, 1);
40
- assert.equal(!!scan2.entries[0]!.fingerprint, true);
41
-
42
- const delFp = await store.fingerprintDelete({ profileId: 'xiaohongshu_fresh' });
43
- assert.equal(delFp.ok, true);
44
- const scan3 = await store.scanProfiles();
45
- assert.equal(!!scan3.entries[0]!.fingerprint, false);
46
-
47
- const delProfile = await store.profileDelete({ profileId: 'xiaohongshu_fresh', deleteFingerprint: true });
48
- assert.equal(delProfile.ok, true);
49
- const scan4 = await store.scanProfiles();
50
- assert.equal(scan4.entries.length, 0);
51
-
52
- await assert.rejects(() => store.profileCreate({ profileId: '../bad' }), /profileId/);
53
- await assert.rejects(() => store.profileCreate({ profileId: '' }), /profileId/);
54
- });
@@ -1,114 +0,0 @@
1
- // apps/desktop-console/src/main/state-bridge.mts
2
- // Bridge between unified-api state and Desktop UI (webauto-04b)
3
-
4
- import { ipcMain, BrowserWindow } from 'electron';
5
- import WebSocket from 'ws';
6
- import type { TaskState, StateUpdate } from './task-state-types.js';
7
-
8
- const UNIFIED_API_WS = process.env.WEBAUTO_UNIFIED_WS || 'ws://127.0.0.1:7701/ws';
9
-
10
- // Fallback if unified-api is not available
11
- const API_URL = 'http://127.0.0.1:7701';
12
-
13
- class StateBridge {
14
- private ws: WebSocket | null = null;
15
- private reconnectTimer: NodeJS.Timeout | null = null;
16
- private win: BrowserWindow | null = null;
17
- private tasks: Map<string, TaskState> = new Map();
18
- private handlersRegistered = false;
19
-
20
- start(win: BrowserWindow) {
21
- this.win = win;
22
- this.connect();
23
- this.setupIPCHandlers();
24
- }
25
-
26
- private connect() {
27
- if (this.ws) {
28
- this.ws.close();
29
- this.ws = null;
30
- }
31
- try {
32
- this.ws = new WebSocket(UNIFIED_API_WS);
33
- this.ws.on('open', () => {
34
- console.log('[StateBridge] connected to', UNIFIED_API_WS);
35
- this.ws?.send(JSON.stringify({ type: 'subscribe', topic: 'task:*' }));
36
- });
37
- this.ws.on('message', (data) => {
38
- try {
39
- const msg = JSON.parse(data.toString());
40
- if (msg.type === 'task:update' && msg.data) {
41
- this.handleTaskUpdate(msg.data);
42
- }
43
- } catch (err) {
44
- console.warn('[StateBridge] parse error:', err);
45
- }
46
- });
47
- this.ws.on('close', () => {
48
- console.log('[StateBridge] disconnected, reconnecting...');
49
- this.scheduleReconnect();
50
- });
51
- this.ws.on('error', (err) => {
52
- console.warn('[StateBridge] error:', err.message);
53
- });
54
- } catch (err) {
55
- console.warn('[StateBridge] connect failed:', err);
56
- this.scheduleReconnect();
57
- }
58
- }
59
-
60
- private scheduleReconnect() {
61
- if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
62
- this.reconnectTimer = setTimeout(() => this.connect(), 3000);
63
- }
64
-
65
- private handleTaskUpdate(update: StateUpdate) {
66
- const task = this.tasks.get(update.runId);
67
- if (task) {
68
- this.tasks.set(update.runId, { ...task, ...update.data });
69
- }
70
- this.win?.webContents.send('state:update', update);
71
- }
72
-
73
- private setupIPCHandlers() {
74
- if (this.handlersRegistered) return;
75
- this.handlersRegistered = true;
76
-
77
- const fetchJson = async (url: string) => {
78
- try {
79
- const res = await globalThis.fetch(url, { signal: AbortSignal.timeout(5000) });
80
- if (!res.ok) return null;
81
- return await res.json().catch(() => null);
82
- } catch {
83
- return null;
84
- }
85
- };
86
-
87
- ipcMain.handle('state:getTasks', async () => {
88
- const json = await fetchJson(`${API_URL}/api/v1/tasks`);
89
- return json?.data || [];
90
- });
91
-
92
- ipcMain.handle('state:getTask', async (_e, runId: string) => {
93
- const json = await fetchJson(`${API_URL}/api/v1/tasks/${runId}`);
94
- return json?.data ?? null;
95
- });
96
-
97
- ipcMain.handle('state:getEvents', async (_e, runId: string, since?: number) => {
98
- let url = `${API_URL}/api/v1/tasks/${runId}/events`;
99
- if (since) url += `?since=${since}`;
100
- const json = await fetchJson(url);
101
- return json?.data || [];
102
- });
103
- }
104
-
105
- stop() {
106
- if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
107
- if (this.ws) this.ws.close();
108
- this.ws = null;
109
- this.win = null;
110
- }
111
- }
112
-
113
- export const stateBridge = new StateBridge();
114
- export default stateBridge;
@@ -1,32 +0,0 @@
1
- // apps/desktop-console/src/main/task-state-types.ts
2
- // Shared types for task state (webauto-04b)
3
-
4
- // Note: This file is intentionally minimal to avoid build issues
5
-
6
- export interface TaskState {
7
- runId: string;
8
- profileId: string;
9
- keyword: string;
10
- phase: string;
11
- status: string;
12
- progress: { total: number; processed: number; failed: number };
13
- stats: {
14
- notesProcessed: number;
15
- commentsCollected: number;
16
- likesPerformed: number;
17
- repliesGenerated: number;
18
- imagesDownloaded: number;
19
- ocrProcessed: number;
20
- };
21
- startedAt: number;
22
- updatedAt: number;
23
- completedAt?: number;
24
- lastError?: any;
25
- }
26
-
27
- export interface StateUpdate {
28
- runId: string;
29
- type: string;
30
- data: any;
31
- timestamp: number;
32
- }
@@ -1,120 +0,0 @@
1
- // apps/desktop-console/src/renderer/hooks/use-task-state.mts
2
- // Renderer-side task state store backed by preload-exposed window.api.
3
-
4
- // Inline types to avoid import path issues
5
- export interface TaskState {
6
- runId: string;
7
- profileId: string;
8
- keyword: string;
9
- phase: string;
10
- status: string;
11
- progress: { total: number; processed: number; failed: number };
12
- stats: {
13
- notesProcessed: number;
14
- commentsCollected: number;
15
- likesPerformed: number;
16
- repliesGenerated: number;
17
- imagesDownloaded: number;
18
- ocrProcessed: number;
19
- };
20
- startedAt: number;
21
- updatedAt: number;
22
- completedAt?: number;
23
- lastError?: any;
24
- }
25
-
26
- export interface StateUpdate {
27
- runId: string;
28
- type: string;
29
- data: any;
30
- timestamp: number;
31
- }
32
-
33
- type Listener = (update: StateUpdate) => void;
34
-
35
- class TaskStateStore {
36
- private tasks: Map<string, TaskState> = new Map();
37
- private listeners: Set<Listener> = new Set();
38
- private started = false;
39
- private unsubscribeState: (() => void) | null = null;
40
-
41
- start() {
42
- if (this.started) return;
43
- this.started = true;
44
- const api = window?.api;
45
- if (!api || typeof api.onStateUpdate !== 'function') {
46
- console.warn('[TaskStateStore] onStateUpdate API unavailable');
47
- return;
48
- }
49
- this.unsubscribeState = api.onStateUpdate((update: StateUpdate) => {
50
- this.handleUpdate(update);
51
- });
52
- void this.loadTasks();
53
- }
54
-
55
- private async loadTasks() {
56
- const api = window?.api;
57
- if (!api || typeof api.stateGetTasks !== 'function') return;
58
- try {
59
- const tasks: TaskState[] = await api.stateGetTasks();
60
- tasks.forEach(t => this.tasks.set(t.runId, t));
61
- this.notify({ runId: '', type: 'init', data: tasks, timestamp: Date.now() });
62
- } catch (err) {
63
- console.warn('[TaskStateStore] loadTasks failed:', err);
64
- }
65
- }
66
-
67
- private handleUpdate(update: StateUpdate) {
68
- if (update.type === 'init') {
69
- const arr = update.data as TaskState[];
70
- arr.forEach(t => this.tasks.set(t.runId, t));
71
- } else {
72
- const existing = this.tasks.get(update.runId);
73
- if (existing) {
74
- this.tasks.set(update.runId, { ...existing, ...update.data });
75
- }
76
- }
77
- this.notify(update);
78
- }
79
-
80
- subscribe(listener: Listener): () => void {
81
- this.listeners.add(listener);
82
- return () => this.listeners.delete(listener);
83
- }
84
-
85
- private notify(update: StateUpdate) {
86
- this.listeners.forEach(l => {
87
- try { l(update); } catch {}
88
- });
89
- }
90
-
91
- getTask(runId: string): TaskState | undefined {
92
- return this.tasks.get(runId);
93
- }
94
-
95
- getAllTasks(): TaskState[] {
96
- return Array.from(this.tasks.values());
97
- }
98
-
99
- dispose() {
100
- if (typeof this.unsubscribeState === 'function') this.unsubscribeState();
101
- this.unsubscribeState = null;
102
- this.started = false;
103
- }
104
- }
105
-
106
- export const taskStateStore = new TaskStateStore();
107
-
108
- // For use in vanilla JS without React
109
- export function useTaskState(callback: (update: StateUpdate) => void): () => void {
110
- taskStateStore.start();
111
- return taskStateStore.subscribe(callback);
112
- }
113
-
114
- export function getTask(runId: string): TaskState | undefined {
115
- return taskStateStore.getTask(runId);
116
- }
117
-
118
- export function getAllTasks(): TaskState[] {
119
- return taskStateStore.getAllTasks();
120
- }
@@ -1,133 +0,0 @@
1
- import { renderPreflight } from './tabs/preflight.mts';
2
- import { renderSettings } from './tabs/settings.mts';
3
- import { renderLogs } from './tabs/logs.mts';
4
- import { renderXiaohongshuTab } from './tabs/xiaohongshu.mts';
5
- import { createEl } from './ui-components.mts';
6
-
7
- declare global {
8
- interface Window {
9
- api: any;
10
- }
11
- }
12
-
13
- type TabId = 'xiaohongshu' | 'preflight' | 'logs' | 'settings';
14
-
15
- const tabs: Array<{ id: TabId; label: string; render: (root: HTMLElement, ctx: any) => void }> = [
16
- { id: 'xiaohongshu', label: '小红书', render: renderXiaohongshuTab },
17
- { id: 'preflight', label: '预处理', render: renderPreflight },
18
- { id: 'logs', label: '日志', render: renderLogs },
19
- { id: 'settings', label: '设置', render: renderSettings },
20
- ];
21
-
22
- const tabsEl = document.getElementById('tabs')!;
23
- const contentEl = document.getElementById('content')!;
24
- const statusEl = document.getElementById('status')!;
25
- const mainEl = document.getElementById('main') as HTMLElement | null;
26
-
27
- const ctx: any = {
28
- settings: null as any,
29
- activeRunId: null as string | null,
30
- _activeRunIds: new Set<string>(),
31
- _activeRunsListeners: [] as Array<() => void>,
32
- _logLines: [] as string[],
33
- appendLog(line: string) {
34
- const l = String(line || '').trim();
35
- if (!l) return;
36
- this._logLines.push(l);
37
- // Logs tab 会接管渲染;这里不再直接写 DOM
38
- },
39
- clearLog() {
40
- this._logLines = [];
41
- },
42
- onActiveRunsChanged(listener: () => void) {
43
- this._activeRunsListeners.push(listener);
44
- return () => {
45
- this._activeRunsListeners = this._activeRunsListeners.filter((x: () => void) => x !== listener);
46
- };
47
- },
48
- notifyActiveRunsChanged() {
49
- this._activeRunsListeners.forEach((listener: () => void) => {
50
- try { listener(); } catch {}
51
- });
52
- },
53
- setStatus(s: string) {
54
- statusEl.textContent = s;
55
- },
56
- runScript(scriptPath: string, args: string[]) {
57
- window.api.runScript(scriptPath, args);
58
- },
59
- setActiveTab(id: TabId) {
60
- setActiveTab(id);
61
- },
62
- };
63
-
64
- function startDesktopHeartbeat() {
65
- const sendHeartbeat = async () => {
66
- try {
67
- if (typeof window.api?.desktopHeartbeat === 'function') {
68
- await window.api.desktopHeartbeat();
69
- }
70
- } catch {
71
- // ignore heartbeat errors
72
- }
73
- };
74
-
75
- void sendHeartbeat();
76
- const timer = setInterval(() => {
77
- void sendHeartbeat();
78
- }, 10_000);
79
- window.addEventListener('beforeunload', () => clearInterval(timer));
80
- }
81
-
82
- async function loadSettings() {
83
- ctx.settings = await window.api.settingsGet();
84
- }
85
-
86
- function setActiveTab(id: TabId) {
87
- tabsEl.textContent = '';
88
- for (const t of tabs) {
89
- const el = createEl('div', { className: `tab ${t.id === id ? 'active' : ''}` }, [t.label]);
90
- el.addEventListener('click', () => setActiveTab(t.id));
91
- tabsEl.appendChild(el);
92
- }
93
- contentEl.textContent = '';
94
- const tab = tabs.find((x) => x.id === id)!;
95
- tab.render(contentEl, ctx);
96
- }
97
-
98
- function installCmdEvents() {
99
- window.api.onCmdEvent((evt: any) => {
100
- const runTag = evt?.runId ? `[rid:${evt.runId}] ` : '';
101
- const runId = String(evt?.runId || '').trim();
102
- if (evt?.type === 'started') {
103
- ctx.activeRunId = evt.runId;
104
- if (runId) {
105
- ctx._activeRunIds.add(runId);
106
- ctx.notifyActiveRunsChanged();
107
- }
108
- ctx.appendLog(`${runTag}[started] ${evt.title} pid=${evt.pid} runId=${evt.runId}`);
109
- ctx.setStatus(`running: ${evt.title}`);
110
- } else if (evt?.type === 'stdout') {
111
- ctx.appendLog(`${runTag}${evt.line}`);
112
- } else if (evt?.type === 'stderr') {
113
- ctx.appendLog(`${runTag}[stderr] ${evt.line}`);
114
- } else if (evt?.type === 'exit') {
115
- if (runId) {
116
- ctx._activeRunIds.delete(runId);
117
- ctx.notifyActiveRunsChanged();
118
- }
119
- ctx.appendLog(`${runTag}[exit] code=${evt.exitCode ?? 'null'} signal=${evt.signal ?? 'null'}`);
120
- ctx.setStatus(ctx._activeRunIds.size > 0 ? `running: ${ctx._activeRunIds.size} tasks` : 'idle');
121
- }
122
- });
123
- }
124
-
125
- async function main() {
126
- startDesktopHeartbeat();
127
- await loadSettings();
128
- installCmdEvents();
129
- setActiveTab('xiaohongshu');
130
- ctx.setStatus('idle');
131
- }
132
-
133
- void main();