@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,20 +0,0 @@
1
- {
2
- "name": "@webauto/desktop-console",
3
- "version": "0.1.1",
4
- "private": true,
5
- "type": "module",
6
- "main": "dist/main/index.mjs",
7
- "description": "Cross-platform desktop console for WebAuto (scripts runner)",
8
- "scripts": {
9
- "build": "node scripts/build.mjs",
10
- "start": "electron .",
11
- "test-preload": "node scripts/test-preload.mjs",
12
- "test:renderer": "tsx --test src/renderer/index.test.mts src/renderer/path-helpers.test.mts src/renderer/tabs/debug.test.mts src/renderer/tabs/logs.test.mts src/renderer/tabs/preflight.test.mts src/renderer/tabs/run.test.mts src/renderer/tabs/xiaohongshu.test.mts",
13
- "clean": "node --input-type=module -e \"import('node:fs').then((fs)=>fs.rmSync('dist',{recursive:true,force:true}))\""
14
- },
15
- "devDependencies": {
16
- "@types/node": "^20.0.0",
17
- "electron": "^39.2.7",
18
- "typescript": "^5.0.0"
19
- }
20
- }
@@ -1,19 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Build and globally install desktop-console
4
- * Usage: node scripts/build-and-install.mjs
5
- */
6
- import { execSync } from 'child_process';
7
- import path from 'path';
8
- import { fileURLToPath } from 'url';
9
-
10
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
- const APP_ROOT = path.resolve(__dirname, '..');
12
-
13
- console.log('[build-and-install] Building...');
14
- execSync('npm run build', { cwd: APP_ROOT, stdio: 'inherit' });
15
-
16
- console.log('[build-and-install] Installing globally...');
17
- execSync('npm install -g .', { cwd: APP_ROOT, stdio: 'inherit' });
18
-
19
- console.log('[build-and-install] Done');
@@ -1,45 +0,0 @@
1
- import { execSync } from 'node:child_process';
2
- import fs from 'node:fs';
3
- import path from 'node:path';
4
-
5
- const appRoot = process.cwd();
6
- const distDir = path.join(appRoot, 'dist');
7
- const distMainDir = path.join(distDir, 'main');
8
- const distRendererDir = path.join(distDir, 'renderer');
9
-
10
- console.log('[desktop-console] ensuring dependencies...');
11
- try {
12
- execSync('npm install', { stdio: 'inherit', cwd: appRoot });
13
- } catch {
14
- // ignore
15
- }
16
-
17
- console.log('[desktop-console] cleaning dist...');
18
- try {
19
- fs.rmSync(distDir, { recursive: true, force: true });
20
- } catch {
21
- // ignore
22
- }
23
-
24
- console.log('[desktop-console] building main process (ESM)...');
25
- execSync(
26
- 'npx esbuild src/main/index.mts --bundle --platform=node --format=esm --outfile=dist/main/index.mjs --sourcemap --external:electron --external:ws --loader:.ts=ts',
27
- { stdio: 'inherit' },
28
- );
29
-
30
- console.log('[desktop-console] copying preload (ESM)...');
31
- fs.mkdirSync(distMainDir, { recursive: true });
32
- fs.copyFileSync(path.join(appRoot, 'src/main/preload.mjs'), path.join(distMainDir, 'preload.mjs'));
33
-
34
- console.log('[desktop-console] building renderer (ESM)...');
35
- execSync(
36
- 'npx esbuild src/renderer/index.mts --bundle --platform=browser --format=esm --outfile=dist/renderer/index.js --sourcemap --target=es2022',
37
- { stdio: 'inherit' },
38
- );
39
-
40
- console.log('[desktop-console] copying renderer assets...');
41
- fs.mkdirSync(distRendererDir, { recursive: true });
42
- fs.copyFileSync(path.join(appRoot, 'src/renderer/index.html'), path.join(distRendererDir, 'index.html'));
43
- fs.copyFileSync(path.join(appRoot, 'src/renderer/tabs/run.mts'), path.join(distRendererDir, 'run.mts'));
44
-
45
- console.log('[desktop-console] build complete');
@@ -1,13 +0,0 @@
1
- import { join } from 'node:path';
2
- import { spawnSync } from 'node:child_process';
3
-
4
- const electronBin = process.platform === 'win32' ? 'electron.cmd' : 'electron';
5
- const appRoot = process.cwd();
6
-
7
- const result = spawnSync('npx', [electronBin, '.'], {
8
- stdio: 'inherit',
9
- cwd: appRoot,
10
- env: { ...process.env, WEBAUTO_DESKTOP_CONSOLE_PRELOAD_TEST: '1' },
11
- });
12
-
13
- process.exit(result.status || 0);
@@ -1,26 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
-
5
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
- const CONFIG_PATH = path.join(__dirname, '../../../apps/webauto/resources/config/ports.json');
7
-
8
- let cachedConfig: any = null;
9
-
10
- export function loadPortConfig() {
11
- if (cachedConfig) return cachedConfig;
12
- try {
13
- cachedConfig = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
14
- } catch {
15
- cachedConfig = { coreDaemon: { port: 7700, url: 'http://127.0.0.1:7700' } };
16
- }
17
- return cachedConfig;
18
- }
19
-
20
- export function getCoreDaemonUrl(): string {
21
- return loadPortConfig().coreDaemon?.url || 'http://127.0.0.1:7700';
22
- }
23
-
24
- export function getCoreDaemonPort(): number {
25
- return loadPortConfig().coreDaemon?.port || 7700;
26
- }
@@ -1,131 +0,0 @@
1
- import { spawn } from 'child_process';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
-
5
- const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../..');
6
- const CORE_HEALTH_URLS = ['http://127.0.0.1:7701/health', 'http://127.0.0.1:7704/health'];
7
- const START_API_SCRIPT = path.join(REPO_ROOT, 'runtime', 'infra', 'utils', 'scripts', 'service', 'start-api.mjs');
8
- const STOP_API_SCRIPT = path.join(REPO_ROOT, 'runtime', 'infra', 'utils', 'scripts', 'service', 'stop-api.mjs');
9
-
10
- function sleep(ms: number) {
11
- return new Promise((resolve) => setTimeout(resolve, ms));
12
- }
13
-
14
- function resolveNodeBin() {
15
- const explicit = String(process.env.WEBAUTO_NODE_BIN || '').trim();
16
- if (explicit) return explicit;
17
- const npmNode = String(process.env.npm_node_execpath || '').trim();
18
- if (npmNode) return npmNode;
19
- return process.platform === 'win32' ? 'node.exe' : 'node';
20
- }
21
-
22
- async function checkHttpHealth(url: string) {
23
- try {
24
- const res = await fetch(url, { signal: AbortSignal.timeout(1000) });
25
- return res.ok;
26
- } catch {
27
- return false;
28
- }
29
- }
30
-
31
- async function areCoreServicesHealthy() {
32
- const health = await Promise.all(CORE_HEALTH_URLS.map((url) => checkHttpHealth(url)));
33
- return health.every(Boolean);
34
- }
35
-
36
- async function runNodeScript(scriptPath: string, timeoutMs: number) {
37
- return new Promise<boolean>((resolve) => {
38
- const nodeBin = resolveNodeBin();
39
- const child = spawn(nodeBin, [scriptPath], {
40
- cwd: REPO_ROOT,
41
- stdio: 'ignore',
42
- windowsHide: true,
43
- detached: false,
44
- env: {
45
- ...process.env,
46
- BROWSER_SERVICE_AUTO_EXIT: '0',
47
- },
48
- });
49
-
50
- const timer = setTimeout(() => {
51
- try {
52
- child.kill('SIGTERM');
53
- } catch {}
54
- resolve(false);
55
- }, timeoutMs);
56
-
57
- child.once('error', () => {
58
- clearTimeout(timer);
59
- resolve(false);
60
- });
61
-
62
- child.once('exit', (code) => {
63
- clearTimeout(timer);
64
- resolve(code === 0);
65
- });
66
- });
67
- }
68
-
69
- async function runCommand(command: string, args: string[], timeoutMs: number) {
70
- return new Promise<boolean>((resolve) => {
71
- const child = spawn(command, args, {
72
- cwd: REPO_ROOT,
73
- stdio: 'ignore',
74
- windowsHide: true,
75
- detached: false,
76
- env: {
77
- ...process.env,
78
- },
79
- });
80
-
81
- const timer = setTimeout(() => {
82
- try {
83
- child.kill('SIGTERM');
84
- } catch {}
85
- resolve(false);
86
- }, timeoutMs);
87
-
88
- child.once('error', () => {
89
- clearTimeout(timer);
90
- resolve(false);
91
- });
92
-
93
- child.once('exit', (code) => {
94
- clearTimeout(timer);
95
- resolve(code === 0);
96
- });
97
- });
98
- }
99
-
100
- export async function startCoreDaemon(): Promise<boolean> {
101
- if (await areCoreServicesHealthy()) return true;
102
-
103
- const startedApi = await runNodeScript(START_API_SCRIPT, 40_000);
104
- if (!startedApi) {
105
- console.error('[CoreDaemonManager] Failed to start unified API service');
106
- return false;
107
- }
108
-
109
- const startedBrowser = await runCommand('npx', ['--yes', '@web-auto/camo', 'init'], 40_000);
110
- if (!startedBrowser) {
111
- console.error('[CoreDaemonManager] Failed to start camo browser backend');
112
- return false;
113
- }
114
-
115
- for (let i = 0; i < 20; i += 1) {
116
- if (await areCoreServicesHealthy()) return true;
117
- await sleep(300);
118
- }
119
-
120
- console.error('[CoreDaemonManager] Services still unhealthy after start');
121
- return false;
122
- }
123
-
124
- export async function stopCoreDaemon(): Promise<boolean> {
125
- const stoppedApi = await runNodeScript(STOP_API_SCRIPT, 20_000);
126
- if (!stoppedApi) {
127
- console.error('[CoreDaemonManager] Failed to stop core services');
128
- return false;
129
- }
130
- return true;
131
- }
@@ -1,267 +0,0 @@
1
- import { promises as fs } from 'node:fs';
2
- import os from 'node:os';
3
- import path from 'node:path';
4
- import { pathToFileURL } from 'node:url';
5
-
6
- export type ReplyStyle = 'friendly' | 'professional' | 'humorous' | 'concise' | 'custom';
7
-
8
- export type AiReplyConfig = {
9
- enabled: boolean;
10
- provider: 'openai-compatible';
11
- baseUrl: string;
12
- apiKey: string;
13
- model: string;
14
- temperature: number;
15
- maxChars: number;
16
- timeoutMs: number;
17
- stylePreset: ReplyStyle;
18
- styleCustom: string;
19
- };
20
-
21
- export type DesktopConsoleSettings = {
22
- unifiedApiUrl: string;
23
- browserServiceUrl: string;
24
- searchGateUrl: string;
25
- downloadRoot: string;
26
- defaultEnv: 'debug' | 'prod';
27
- defaultKeyword: string;
28
- defaultTarget: number;
29
- defaultDryRun: boolean;
30
- timeouts: { loginTimeoutSec: number; cmdTimeoutSec: number };
31
- profileAliases: Record<string, string>;
32
- profileColors: Record<string, string>;
33
- aiReply: AiReplyConfig;
34
- };
35
-
36
- type DefaultsFile = Partial<DesktopConsoleSettings> & {
37
- downloadRootParts?: string[];
38
- };
39
-
40
- type ConfigApi = {
41
- loadConfig: () => Promise<any>;
42
- saveConfig: (cfg: any) => Promise<void>;
43
- loader: { ensureExists: () => Promise<void>; merge: (base: any, override: any) => any };
44
- };
45
-
46
- function resolveHomeDir() {
47
- const homeDir =
48
- process.platform === 'win32'
49
- ? (process.env.USERPROFILE || os.homedir() || '')
50
- : (process.env.HOME || os.homedir() || '');
51
- if (!homeDir) throw new Error('无法获取用户主目录:HOME/USERPROFILE 未设置');
52
- return homeDir;
53
- }
54
-
55
- export function resolveLegacySettingsPath() {
56
- return path.join(resolveHomeDir(), '.webauto', 'ui-settings.console.json');
57
- }
58
-
59
- export function resolveDefaultDownloadRoot() {
60
- return path.join(resolveHomeDir(), '.webauto', 'download');
61
- }
62
-
63
- function normalizeAiReplyConfig(raw: any): AiReplyConfig {
64
- if (!raw || typeof raw !== 'object') {
65
- return {
66
- enabled: false,
67
- provider: 'openai-compatible',
68
- baseUrl: 'http://127.0.0.1:5520',
69
- apiKey: '',
70
- model: 'iflow.glm-5',
71
- temperature: 0.7,
72
- maxChars: 20,
73
- timeoutMs: 25000,
74
- stylePreset: 'friendly',
75
- styleCustom: '',
76
- };
77
- }
78
- const stylePresets: ReplyStyle[] = ['friendly', 'professional', 'humorous', 'concise', 'custom'];
79
- const preset = String(raw.stylePreset || 'friendly');
80
- return {
81
- enabled: Boolean(raw.enabled ?? false),
82
- provider: 'openai-compatible',
83
- baseUrl: String(raw.baseUrl || 'http://127.0.0.1:5520'),
84
- apiKey: String(raw.apiKey || ''),
85
- model: String(raw.model || 'iflow.glm-5'),
86
- temperature: Math.max(0, Math.min(2, Number(raw.temperature ?? 0.7))),
87
- maxChars: Math.max(5, Math.min(500, Math.floor(Number(raw.maxChars ?? 20)))),
88
- timeoutMs: Math.max(5000, Math.floor(Number(raw.timeoutMs ?? 25000))),
89
- stylePreset: stylePresets.includes(preset as ReplyStyle) ? (preset as ReplyStyle) : 'friendly',
90
- styleCustom: String(raw.styleCustom || ''),
91
- };
92
- }
93
-
94
- function normalizeSettings(defaults: Partial<DesktopConsoleSettings>, input: Partial<DesktopConsoleSettings>): DesktopConsoleSettings {
95
- const aliasesRaw = (input as any).profileAliases ?? (defaults as any).profileAliases ?? {};
96
- const aliases: Record<string, string> = {};
97
- if (aliasesRaw && typeof aliasesRaw === 'object') {
98
- for (const [k, v] of Object.entries(aliasesRaw as any)) {
99
- const key = String(k || '').trim();
100
- const val = String(v || '').trim();
101
- if (!key) continue;
102
- if (!val) continue;
103
- aliases[key] = val;
104
- }
105
- }
106
- const merged: DesktopConsoleSettings = {
107
- unifiedApiUrl: String(input.unifiedApiUrl || defaults.unifiedApiUrl || 'http://127.0.0.1:7701'),
108
- browserServiceUrl: String(input.browserServiceUrl || defaults.browserServiceUrl || 'http://127.0.0.1:7704'),
109
- searchGateUrl: String(input.searchGateUrl || defaults.searchGateUrl || 'http://127.0.0.1:7790'),
110
- downloadRoot: String(input.downloadRoot || defaults.downloadRoot || resolveDefaultDownloadRoot()),
111
- defaultEnv: (String(input.defaultEnv || defaults.defaultEnv || 'debug') === 'prod' ? 'prod' : 'debug'),
112
- defaultKeyword: String(input.defaultKeyword ?? defaults.defaultKeyword ?? ''),
113
- defaultTarget: Math.max(1, Math.floor(Number((input as any).defaultTarget ?? (defaults as any).defaultTarget ?? 20) || 20)),
114
- defaultDryRun: Boolean((input as any).defaultDryRun ?? (defaults as any).defaultDryRun ?? false),
115
- timeouts: {
116
- loginTimeoutSec: Math.max(
117
- 30,
118
- Math.floor(
119
- Number(
120
- (input.timeouts as any)?.loginTimeoutSec ??
121
- (defaults.timeouts as any)?.loginTimeoutSec ??
122
- 900,
123
- ),
124
- ),
125
- ),
126
- cmdTimeoutSec: Math.max(
127
- 0,
128
- Math.floor(
129
- Number(
130
- (input.timeouts as any)?.cmdTimeoutSec ??
131
- (defaults.timeouts as any)?.cmdTimeoutSec ??
132
- 0,
133
- ),
134
- ),
135
- ),
136
- },
137
- profileAliases: aliases,
138
- profileColors: normalizeColorMap((input as any).profileColors ?? (defaults as any).profileColors ?? {}),
139
- aiReply: normalizeAiReplyConfig((input as any).aiReply ?? (defaults as any).aiReply ?? {}),
140
- };
141
- return merged;
142
- }
143
-
144
- function normalizeColorMap(raw: any): Record<string, string> {
145
- const out: Record<string, string> = {};
146
- if (!raw || typeof raw !== 'object') return out;
147
- for (const [k, v] of Object.entries(raw as any)) {
148
- const key = String(k || '').trim();
149
- const val = String(v || '').trim();
150
- if (!key || !val) continue;
151
- // Accept only simple #RRGGBB to avoid injecting unexpected CSS.
152
- if (!/^#[0-9a-fA-F]{6}$/.test(val)) continue;
153
- out[key] = val;
154
- }
155
- return out;
156
- }
157
-
158
- async function readDefaultSettingsFromAppRoot(appRoot: string): Promise<DesktopConsoleSettings> {
159
- const defaultsPath = path.join(appRoot, 'default-settings.json');
160
- let raw: DefaultsFile = {};
161
- try {
162
- const text = await fs.readFile(defaultsPath, 'utf8');
163
- raw = (JSON.parse(text) || {}) as DefaultsFile;
164
- } catch {
165
- raw = {};
166
- }
167
-
168
- const base: Partial<DesktopConsoleSettings> = {
169
- unifiedApiUrl: raw.unifiedApiUrl,
170
- browserServiceUrl: raw.browserServiceUrl,
171
- searchGateUrl: raw.searchGateUrl,
172
- defaultEnv: raw.defaultEnv as any,
173
- defaultKeyword: raw.defaultKeyword,
174
- timeouts: raw.timeouts as any,
175
- };
176
-
177
- const downloadRoot =
178
- typeof (raw as any).downloadRoot === 'string'
179
- ? String((raw as any).downloadRoot)
180
- : Array.isArray(raw.downloadRootParts)
181
- ? path.join(resolveHomeDir(), ...raw.downloadRootParts.map((x) => String(x)))
182
- : resolveDefaultDownloadRoot();
183
-
184
- return normalizeSettings({ ...base, downloadRoot }, {});
185
- }
186
-
187
- async function readLegacySettings(): Promise<Partial<DesktopConsoleSettings> | null> {
188
- const legacyPath = resolveLegacySettingsPath();
189
- try {
190
- const text = await fs.readFile(legacyPath, 'utf8');
191
- const parsed = JSON.parse(text) || {};
192
- if (!parsed || typeof parsed !== 'object') return null;
193
- return parsed as Partial<DesktopConsoleSettings>;
194
- } catch {
195
- return null;
196
- }
197
- }
198
-
199
- async function tryLoadConfigApi(repoRoot: string): Promise<ConfigApi | null> {
200
- const distEntry = path.join(repoRoot, 'dist', 'modules', 'config', 'index.js');
201
- try {
202
- await fs.access(distEntry);
203
- } catch {
204
- return null;
205
- }
206
- try {
207
- const mod = (await import(pathToFileURL(distEntry).href)) as any;
208
- if (!mod?.loadConfig || !mod?.saveConfig || !mod?.loader?.ensureExists) return null;
209
- return mod as ConfigApi;
210
- } catch {
211
- return null;
212
- }
213
- }
214
-
215
- export async function readDesktopConsoleSettings(input: { appRoot: string; repoRoot: string }): Promise<DesktopConsoleSettings> {
216
- const defaults = await readDefaultSettingsFromAppRoot(input.appRoot);
217
- const configApi = await tryLoadConfigApi(input.repoRoot);
218
-
219
- if (!configApi) {
220
- const legacy = await readLegacySettings();
221
- return normalizeSettings(defaults, legacy || {});
222
- }
223
-
224
- await configApi.loader.ensureExists();
225
- const cfg = await configApi.loadConfig();
226
- const fromConfig = (cfg && cfg.desktopConsole) ? (cfg.desktopConsole as Partial<DesktopConsoleSettings>) : null;
227
- if (fromConfig) {
228
- return normalizeSettings(defaults, fromConfig);
229
- }
230
-
231
- const legacy = await readLegacySettings();
232
- if (legacy) {
233
- const migrated = normalizeSettings(defaults, legacy);
234
- const nextCfg = configApi.loader.merge(cfg, { desktopConsole: migrated });
235
- await configApi.saveConfig(nextCfg);
236
- return migrated;
237
- }
238
-
239
- const seeded = normalizeSettings(defaults, {});
240
- const nextCfg = configApi.loader.merge(cfg, { desktopConsole: seeded });
241
- await configApi.saveConfig(nextCfg);
242
- return seeded;
243
- }
244
-
245
- export async function writeDesktopConsoleSettings(
246
- input: { appRoot: string; repoRoot: string },
247
- next: Partial<DesktopConsoleSettings>,
248
- ): Promise<DesktopConsoleSettings> {
249
- const current = await readDesktopConsoleSettings(input);
250
- const defaults = await readDefaultSettingsFromAppRoot(input.appRoot);
251
- const merged = normalizeSettings(defaults, { ...current, ...next, timeouts: { ...current.timeouts, ...(next.timeouts || {}) } });
252
-
253
- const configApi = await tryLoadConfigApi(input.repoRoot);
254
- if (configApi) {
255
- await configApi.loader.ensureExists();
256
- const cfg = await configApi.loadConfig();
257
- const nextCfg = configApi.loader.merge(cfg, { desktopConsole: merged });
258
- await configApi.saveConfig(nextCfg);
259
- return merged;
260
- }
261
-
262
- // fallback: still write legacy file for compatibility when dist config is unavailable
263
- const legacyPath = resolveLegacySettingsPath();
264
- await fs.mkdir(path.dirname(legacyPath), { recursive: true });
265
- await fs.writeFile(legacyPath, JSON.stringify(merged, null, 2), 'utf8');
266
- return merged;
267
- }
@@ -1,50 +0,0 @@
1
- export const DEFAULT_UI_HEARTBEAT_TIMEOUT_MS = 5 * 60_000;
2
-
3
- export type WatchdogAction = 'none' | 'kill_runs' | 'stop_core_services';
4
-
5
- export type WatchdogDecision = {
6
- action: WatchdogAction;
7
- nextHandled: boolean;
8
- reason:
9
- | 'healthy'
10
- | 'already_handled'
11
- | 'stale_ui_alive'
12
- | 'stale_ui_unavailable_with_runs'
13
- | 'stale_ui_unavailable_idle';
14
- };
15
-
16
- export type WatchdogInput = {
17
- staleMs: number;
18
- timeoutMs: number;
19
- alreadyHandled: boolean;
20
- runCount: number;
21
- uiOperational: boolean;
22
- };
23
-
24
- export function resolveUiHeartbeatTimeoutMs(env: Record<string, string | undefined> = process.env): number {
25
- const raw = Number.parseInt(String(env.WEBAUTO_UI_HEARTBEAT_TIMEOUT_MS || '').trim(), 10);
26
- if (Number.isFinite(raw) && raw >= 30_000 && raw <= 60 * 60_000) {
27
- return raw;
28
- }
29
- return DEFAULT_UI_HEARTBEAT_TIMEOUT_MS;
30
- }
31
-
32
- export function decideWatchdogAction(input: WatchdogInput): WatchdogDecision {
33
- if (input.staleMs <= input.timeoutMs) {
34
- return { action: 'none', nextHandled: false, reason: 'healthy' };
35
- }
36
-
37
- if (input.alreadyHandled) {
38
- return { action: 'none', nextHandled: true, reason: 'already_handled' };
39
- }
40
-
41
- if (input.uiOperational) {
42
- return { action: 'none', nextHandled: true, reason: 'stale_ui_alive' };
43
- }
44
-
45
- if (input.runCount > 0) {
46
- return { action: 'kill_runs', nextHandled: true, reason: 'stale_ui_unavailable_with_runs' };
47
- }
48
-
49
- return { action: 'stop_core_services', nextHandled: true, reason: 'stale_ui_unavailable_idle' };
50
- }
@@ -1,68 +0,0 @@
1
- import assert from 'node:assert/strict';
2
-
3
- import {
4
- DEFAULT_UI_HEARTBEAT_TIMEOUT_MS,
5
- decideWatchdogAction,
6
- resolveUiHeartbeatTimeoutMs,
7
- } from './heartbeat-watchdog.mts';
8
-
9
- {
10
- const d = decideWatchdogAction({
11
- staleMs: 9_000,
12
- timeoutMs: 10_000,
13
- alreadyHandled: false,
14
- runCount: 2,
15
- uiOperational: false,
16
- });
17
- assert.deepStrictEqual(d, { action: 'none', nextHandled: false, reason: 'healthy' });
18
- }
19
-
20
- {
21
- const d = decideWatchdogAction({
22
- staleMs: 90_000,
23
- timeoutMs: 60_000,
24
- alreadyHandled: false,
25
- runCount: 3,
26
- uiOperational: true,
27
- });
28
- assert.deepStrictEqual(d, { action: 'none', nextHandled: true, reason: 'stale_ui_alive' });
29
- }
30
-
31
- {
32
- const d = decideWatchdogAction({
33
- staleMs: 90_000,
34
- timeoutMs: 60_000,
35
- alreadyHandled: false,
36
- runCount: 1,
37
- uiOperational: false,
38
- });
39
- assert.deepStrictEqual(d, { action: 'kill_runs', nextHandled: true, reason: 'stale_ui_unavailable_with_runs' });
40
- }
41
-
42
- {
43
- const d = decideWatchdogAction({
44
- staleMs: 90_000,
45
- timeoutMs: 60_000,
46
- alreadyHandled: false,
47
- runCount: 0,
48
- uiOperational: false,
49
- });
50
- assert.deepStrictEqual(d, { action: 'stop_core_services', nextHandled: true, reason: 'stale_ui_unavailable_idle' });
51
- }
52
-
53
- {
54
- const d = decideWatchdogAction({
55
- staleMs: 90_000,
56
- timeoutMs: 60_000,
57
- alreadyHandled: true,
58
- runCount: 9,
59
- uiOperational: false,
60
- });
61
- assert.deepStrictEqual(d, { action: 'none', nextHandled: true, reason: 'already_handled' });
62
- }
63
-
64
- {
65
- assert.equal(resolveUiHeartbeatTimeoutMs({ WEBAUTO_UI_HEARTBEAT_TIMEOUT_MS: '120000' }), 120_000);
66
- assert.equal(resolveUiHeartbeatTimeoutMs({ WEBAUTO_UI_HEARTBEAT_TIMEOUT_MS: '1000' }), DEFAULT_UI_HEARTBEAT_TIMEOUT_MS);
67
- assert.equal(resolveUiHeartbeatTimeoutMs({ WEBAUTO_UI_HEARTBEAT_TIMEOUT_MS: 'abc' }), DEFAULT_UI_HEARTBEAT_TIMEOUT_MS);
68
- }
@@ -1,20 +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 mainPath = path.join(__dirname, 'index.mts');
9
-
10
- test('spawnCommand uses buffered line emitter and flushes on close', async () => {
11
- const src = await readFile(mainPath, 'utf8');
12
- assert.match(src, /function createLineEmitter\(runId: string, type: StreamEventType\)/);
13
- assert.match(src, /let pending = '';/);
14
- assert.match(src, /pending \+= chunk\.toString\('utf8'\);/);
15
- assert.match(src, /const stdoutLines = createLineEmitter\(runId, 'stdout'\);/);
16
- assert.match(src, /const stderrLines = createLineEmitter\(runId, 'stderr'\);/);
17
- assert.match(src, /stdoutLines\.push\(chunk\);/);
18
- assert.match(src, /stderrLines\.push\(chunk\);/);
19
- assert.match(src, /stdoutLines\.flush\(\);\s*stderrLines\.flush\(\);\s*finalize\(/s);
20
- });