@web-auto/webauto 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/apps/desktop-console/default-settings.json +1 -0
  2. package/apps/desktop-console/dist/main/index.mjs +1618 -0
  3. package/apps/desktop-console/{src → dist}/main/preload.mjs +10 -0
  4. package/apps/desktop-console/dist/renderer/index.js +3063 -0
  5. package/apps/desktop-console/entry/ui-console.mjs +299 -0
  6. package/apps/webauto/entry/account.mjs +356 -0
  7. package/apps/webauto/entry/lib/account-detect.mjs +160 -0
  8. package/apps/webauto/entry/lib/account-store.mjs +587 -0
  9. package/apps/webauto/entry/lib/profilepool.mjs +1 -1
  10. package/apps/webauto/entry/xhs-install.mjs +27 -3
  11. package/apps/webauto/entry/xhs-status.mjs +152 -0
  12. package/apps/webauto/entry/xhs-unified.mjs +595 -17
  13. package/bin/webauto.mjs +247 -12
  14. package/dist/apps/webauto/server.js +66 -0
  15. package/dist/modules/camo-backend/src/index.js +575 -0
  16. package/dist/modules/camo-backend/src/internal/BrowserSession.js +817 -0
  17. package/dist/modules/camo-backend/src/internal/ElementRegistry.js +61 -0
  18. package/dist/modules/camo-backend/src/internal/ProfileLock.js +85 -0
  19. package/dist/modules/camo-backend/src/internal/SessionManager.js +172 -0
  20. package/dist/modules/camo-backend/src/internal/container-matcher.js +852 -0
  21. package/dist/modules/camo-backend/src/internal/engine-manager.js +258 -0
  22. package/dist/modules/camo-backend/src/internal/fingerprint.js +203 -0
  23. package/dist/modules/camo-backend/src/internal/pageRuntime.js +29 -0
  24. package/dist/modules/camo-backend/src/internal/runtimeInjector.js +30 -0
  25. package/dist/modules/camo-backend/src/internal/state-bus.js +46 -0
  26. package/dist/modules/camo-backend/src/internal/storage-paths.js +36 -0
  27. package/dist/modules/camo-backend/src/internal/ws-server.js +1202 -0
  28. package/dist/modules/camo-runtime/src/utils/browser-service.mjs +423 -0
  29. package/dist/modules/camo-runtime/src/utils/config.mjs +77 -0
  30. package/dist/modules/container-registry/src/index.js +184 -0
  31. package/dist/modules/logging/src/index.js +92 -0
  32. package/dist/modules/operations/src/builtin.js +27 -0
  33. package/dist/modules/operations/src/container-binding.js +75 -0
  34. package/dist/modules/operations/src/executor.js +146 -0
  35. package/dist/modules/operations/src/operations/click.js +167 -0
  36. package/dist/modules/operations/src/operations/extract.js +204 -0
  37. package/dist/modules/operations/src/operations/find-child.js +17 -0
  38. package/dist/modules/operations/src/operations/highlight.js +138 -0
  39. package/dist/modules/operations/src/operations/key.js +61 -0
  40. package/dist/modules/operations/src/operations/navigate.js +148 -0
  41. package/dist/modules/operations/src/operations/scroll.js +126 -0
  42. package/dist/modules/operations/src/operations/type.js +190 -0
  43. package/dist/modules/operations/src/queue.js +100 -0
  44. package/dist/modules/operations/src/registry.js +11 -0
  45. package/dist/modules/operations/src/system/mouse.js +33 -0
  46. package/dist/modules/state/src/atomic-json.js +33 -0
  47. package/dist/modules/workflow/blocks/AnchorVerificationBlock.js +71 -0
  48. package/dist/modules/workflow/blocks/BehaviorRandomizer.js +26 -0
  49. package/dist/modules/workflow/blocks/CallWorkflowBlock.js +38 -0
  50. package/dist/modules/workflow/blocks/CloseDetailBlock.js +209 -0
  51. package/dist/modules/workflow/blocks/CollectBatch.js +137 -0
  52. package/dist/modules/workflow/blocks/CollectCommentsBlock.js +415 -0
  53. package/dist/modules/workflow/blocks/CollectSearchListBlock.js +599 -0
  54. package/dist/modules/workflow/blocks/CollectWeiboPosts.js +229 -0
  55. package/dist/modules/workflow/blocks/DetectPageStateBlock.js +259 -0
  56. package/dist/modules/workflow/blocks/EnsureLoginBlock.js +162 -0
  57. package/dist/modules/workflow/blocks/EnsureSession.js +426 -0
  58. package/dist/modules/workflow/blocks/ErrorClassifier.js +164 -0
  59. package/dist/modules/workflow/blocks/ErrorRecoveryBlock.js +319 -0
  60. package/dist/modules/workflow/blocks/ExpandCommentsBlock.js +1032 -0
  61. package/dist/modules/workflow/blocks/ExtractDetailBlock.js +310 -0
  62. package/dist/modules/workflow/blocks/ExtractPostFields.js +88 -0
  63. package/dist/modules/workflow/blocks/GenerateSmartReplyBlock.js +68 -0
  64. package/dist/modules/workflow/blocks/GoToSearchBlock.js +497 -0
  65. package/dist/modules/workflow/blocks/GracefulFallbackBlock.js +104 -0
  66. package/dist/modules/workflow/blocks/HighlightBlock.js +66 -0
  67. package/dist/modules/workflow/blocks/InitAutoScroll.js +65 -0
  68. package/dist/modules/workflow/blocks/LoadContainerDefinition.js +50 -0
  69. package/dist/modules/workflow/blocks/LoadContainerIndex.js +43 -0
  70. package/dist/modules/workflow/blocks/LocateAndGuardBlock.js +176 -0
  71. package/dist/modules/workflow/blocks/LoginRecoveryBlock.js +242 -0
  72. package/dist/modules/workflow/blocks/MatchContainers.js +64 -0
  73. package/dist/modules/workflow/blocks/MonitoringBlock.js +190 -0
  74. package/dist/modules/workflow/blocks/OpenDetailBlock.js +1240 -0
  75. package/dist/modules/workflow/blocks/OrganizeXhsNotesBlock.js +117 -0
  76. package/dist/modules/workflow/blocks/PersistXhsNoteBlock.js +270 -0
  77. package/dist/modules/workflow/blocks/PickSinglePost.js +69 -0
  78. package/dist/modules/workflow/blocks/ProgressTracker.js +125 -0
  79. package/dist/modules/workflow/blocks/RecordFixtureBlock.js +44 -0
  80. package/dist/modules/workflow/blocks/RenderMarkdown.js +48 -0
  81. package/dist/modules/workflow/blocks/SaveFile.js +54 -0
  82. package/dist/modules/workflow/blocks/ScrollNextBatch.js +72 -0
  83. package/dist/modules/workflow/blocks/SessionHealthBlock.js +73 -0
  84. package/dist/modules/workflow/blocks/StartBrowserService.js +45 -0
  85. package/dist/modules/workflow/blocks/ValidateContainerDefinition.js +67 -0
  86. package/dist/modules/workflow/blocks/ValidateExtract.js +35 -0
  87. package/dist/modules/workflow/blocks/WaitSearchPermitBlock.js +162 -0
  88. package/dist/modules/workflow/blocks/WaitStable.js +74 -0
  89. package/dist/modules/workflow/blocks/WarmupCommentsBlock.js +120 -0
  90. package/dist/modules/workflow/blocks/WorkflowExecutor.js +156 -0
  91. package/dist/modules/workflow/blocks/XiaohongshuCollectFromLinksBlock.js +1004 -0
  92. package/dist/modules/workflow/blocks/XiaohongshuCollectLinksBlock.js +1049 -0
  93. package/dist/modules/workflow/blocks/XiaohongshuFullCollectBlock.js +782 -0
  94. package/dist/modules/workflow/blocks/helpers/anchorVerify.js +198 -0
  95. package/dist/modules/workflow/blocks/helpers/asyncWorkQueue.js +53 -0
  96. package/dist/modules/workflow/blocks/helpers/commentScroller.js +334 -0
  97. package/dist/modules/workflow/blocks/helpers/commentSectionLocator.js +126 -0
  98. package/dist/modules/workflow/blocks/helpers/containerAnchors.js +301 -0
  99. package/dist/modules/workflow/blocks/helpers/debugArtifacts.js +6 -0
  100. package/dist/modules/workflow/blocks/helpers/downloadPaths.js +29 -0
  101. package/dist/modules/workflow/blocks/helpers/expandCommentsController.js +53 -0
  102. package/dist/modules/workflow/blocks/helpers/expandCommentsExtractor.js +129 -0
  103. package/dist/modules/workflow/blocks/helpers/macosVisionOcrPlugin.js +116 -0
  104. package/dist/modules/workflow/blocks/helpers/mergeXhsMarkdown.js +109 -0
  105. package/dist/modules/workflow/blocks/helpers/openDetailController.js +56 -0
  106. package/dist/modules/workflow/blocks/helpers/openDetailTypes.js +7 -0
  107. package/dist/modules/workflow/blocks/helpers/openDetailViewport.js +474 -0
  108. package/dist/modules/workflow/blocks/helpers/openDetailWaiter.js +104 -0
  109. package/dist/modules/workflow/blocks/helpers/operationLogger.js +195 -0
  110. package/dist/modules/workflow/blocks/helpers/persistedNotes.js +107 -0
  111. package/dist/modules/workflow/blocks/helpers/replyExpander.js +260 -0
  112. package/dist/modules/workflow/blocks/helpers/scrollIntoView.js +138 -0
  113. package/dist/modules/workflow/blocks/helpers/searchExecutor.js +328 -0
  114. package/dist/modules/workflow/blocks/helpers/searchGate.js +46 -0
  115. package/dist/modules/workflow/blocks/helpers/searchPageState.js +164 -0
  116. package/dist/modules/workflow/blocks/helpers/searchResultWaiter.js +64 -0
  117. package/dist/modules/workflow/blocks/helpers/simpleAnchor.js +134 -0
  118. package/dist/modules/workflow/blocks/helpers/smartReply.js +40 -0
  119. package/dist/modules/workflow/blocks/helpers/systemInput.js +635 -0
  120. package/dist/modules/workflow/blocks/helpers/targetCountMode.js +9 -0
  121. package/dist/modules/workflow/blocks/helpers/xhsCliArgs.js +80 -0
  122. package/dist/modules/workflow/blocks/helpers/xhsCommentDom.js +805 -0
  123. package/dist/modules/workflow/blocks/helpers/xhsNoteOrganizer.js +140 -0
  124. package/dist/modules/workflow/blocks/restore/RestorePhaseBlock.js +204 -0
  125. package/dist/modules/workflow/config/workflowRegistry.js +32 -0
  126. package/dist/modules/workflow/definitions/batch-collect-workflow.js +63 -0
  127. package/dist/modules/workflow/definitions/scroll-extract-workflow.js +74 -0
  128. package/dist/modules/workflow/definitions/xiaohongshu-collect-workflow-v2.js +81 -0
  129. package/dist/modules/workflow/definitions/xiaohongshu-collect-workflow.js +57 -0
  130. package/dist/modules/workflow/definitions/xiaohongshu-full-collect-workflow-v3.js +68 -0
  131. package/dist/modules/workflow/definitions/xiaohongshu-note-collect.js +49 -0
  132. package/dist/modules/workflow/definitions/xiaohongshu-phase1-workflow-v3.js +30 -0
  133. package/dist/modules/workflow/definitions/xiaohongshu-phase2-links-workflow-v3.js +40 -0
  134. package/dist/modules/workflow/definitions/xiaohongshu-phase3-collect-workflow-v1.js +54 -0
  135. package/dist/modules/workflow/definitions/xiaohongshu-phase34-from-links-workflow-v3.js +25 -0
  136. package/dist/modules/workflow/src/WeiboEventDrivenWorkflowRunner.js +308 -0
  137. package/dist/modules/workflow/src/context.js +70 -0
  138. package/dist/modules/workflow/src/index.js +5 -0
  139. package/dist/modules/workflow/src/orchestrator.js +230 -0
  140. package/dist/modules/workflow/src/runner.js +55 -0
  141. package/dist/modules/workflow/src/runtime.js +70 -0
  142. package/dist/modules/workflow/workflows/WeiboFeedExtractionWorkflow.js +359 -0
  143. package/dist/modules/workflow/workflows/XiaohongshuLoginWorkflow.js +110 -0
  144. package/dist/modules/xiaohongshu/app/src/blocks/MatchCommentsBlock.js +139 -0
  145. package/dist/modules/xiaohongshu/app/src/blocks/Phase1EnsureServicesBlock.js +36 -0
  146. package/dist/modules/xiaohongshu/app/src/blocks/Phase1MonitorCookieBlock.js +213 -0
  147. package/dist/modules/xiaohongshu/app/src/blocks/Phase1StartProfileBlock.js +121 -0
  148. package/dist/modules/xiaohongshu/app/src/blocks/Phase2CollectLinksBlock.js +1249 -0
  149. package/dist/modules/xiaohongshu/app/src/blocks/Phase2SearchBlock.js +703 -0
  150. package/dist/modules/xiaohongshu/app/src/blocks/Phase34CloseDetailBlock.js +41 -0
  151. package/dist/modules/xiaohongshu/app/src/blocks/Phase34CloseTabsBlock.js +44 -0
  152. package/dist/modules/xiaohongshu/app/src/blocks/Phase34CollectCommentsBlock.js +150 -0
  153. package/dist/modules/xiaohongshu/app/src/blocks/Phase34ExtractDetailBlock.js +117 -0
  154. package/dist/modules/xiaohongshu/app/src/blocks/Phase34OpenDetailBlock.js +102 -0
  155. package/dist/modules/xiaohongshu/app/src/blocks/Phase34OpenTabsBlock.js +109 -0
  156. package/dist/modules/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.js +117 -0
  157. package/dist/modules/xiaohongshu/app/src/blocks/Phase34ProcessSingleNoteBlock.js +114 -0
  158. package/dist/modules/xiaohongshu/app/src/blocks/Phase34ValidateLinksBlock.js +90 -0
  159. package/dist/modules/xiaohongshu/app/src/blocks/Phase3InteractBlock.js +1009 -0
  160. package/dist/modules/xiaohongshu/app/src/blocks/Phase4MultiTabHarvestBlock.js +233 -0
  161. package/dist/modules/xiaohongshu/app/src/blocks/ReplyInteractBlock.js +291 -0
  162. package/dist/modules/xiaohongshu/app/src/blocks/XhsDiscoverFallbackBlock.js +240 -0
  163. package/dist/modules/xiaohongshu/app/src/blocks/helpers/commentMatchDsl.js +126 -0
  164. package/dist/modules/xiaohongshu/app/src/blocks/helpers/commentMatcher.js +99 -0
  165. package/dist/modules/xiaohongshu/app/src/blocks/helpers/evidence.js +27 -0
  166. package/dist/modules/xiaohongshu/app/src/blocks/helpers/sharding.js +42 -0
  167. package/dist/modules/xiaohongshu/app/src/blocks/helpers/xhsComments.js +270 -0
  168. package/dist/modules/xiaohongshu/app/src/index.js +9 -0
  169. package/dist/modules/xiaohongshu/app/src/utils/checkpoints.js +222 -0
  170. package/dist/modules/xiaohongshu/app/src/utils/controllerAction.js +43 -0
  171. package/dist/services/controller/src/controller.js +1476 -0
  172. package/dist/services/controller/src/index.js +2 -0
  173. package/dist/services/controller/src/payload-normalizer.js +129 -0
  174. package/dist/services/shared/heartbeat.js +120 -0
  175. package/dist/services/shared/lib/errorHandler.js +2 -0
  176. package/dist/services/shared/serviceProcessLogger.js +139 -0
  177. package/dist/services/unified-api/RemoteBrowserSession.js +176 -0
  178. package/dist/services/unified-api/RemoteSessionManager.js +148 -0
  179. package/dist/services/unified-api/container-operations-handler.js +115 -0
  180. package/dist/services/unified-api/server.js +652 -0
  181. package/dist/services/unified-api/state-registry.js +274 -0
  182. package/dist/services/unified-api/task-persistence.js +66 -0
  183. package/dist/services/unified-api/task-state.js +130 -0
  184. package/modules/camo-runtime/src/autoscript/action-providers/xhs/search.mjs +12 -5
  185. package/modules/xiaohongshu/app/pnpm-lock.yaml +24 -0
  186. package/package.json +37 -9
  187. package/.beads/README.md +0 -81
  188. package/.beads/config.yaml +0 -67
  189. package/.beads/interactions.jsonl +0 -0
  190. package/.beads/issues.jsonl +0 -180
  191. package/.beads/metadata.json +0 -4
  192. package/.claude/settings.local.json +0 -10
  193. package/.github/workflows/ci.yml +0 -55
  194. package/AGENTS.md +0 -253
  195. package/apps/desktop-console/README.md +0 -27
  196. package/apps/desktop-console/package-lock.json +0 -897
  197. package/apps/desktop-console/package.json +0 -20
  198. package/apps/desktop-console/scripts/build-and-install.mjs +0 -19
  199. package/apps/desktop-console/scripts/build.mjs +0 -45
  200. package/apps/desktop-console/scripts/test-preload.mjs +0 -13
  201. package/apps/desktop-console/src/main/config.mts +0 -26
  202. package/apps/desktop-console/src/main/core-daemon-manager.mts +0 -131
  203. package/apps/desktop-console/src/main/desktop-settings.mts +0 -267
  204. package/apps/desktop-console/src/main/heartbeat-watchdog.mts +0 -50
  205. package/apps/desktop-console/src/main/heartbeat-watchdog.test.mts +0 -68
  206. package/apps/desktop-console/src/main/index-streaming.test.mts +0 -20
  207. package/apps/desktop-console/src/main/index.mts +0 -980
  208. package/apps/desktop-console/src/main/profile-store.mts +0 -239
  209. package/apps/desktop-console/src/main/profile-store.test.mts +0 -54
  210. package/apps/desktop-console/src/main/state-bridge.mts +0 -114
  211. package/apps/desktop-console/src/main/task-state-types.ts +0 -32
  212. package/apps/desktop-console/src/renderer/hooks/use-task-state.mts +0 -120
  213. package/apps/desktop-console/src/renderer/index.mts +0 -133
  214. package/apps/desktop-console/src/renderer/index.test.mts +0 -34
  215. package/apps/desktop-console/src/renderer/path-helpers.mts +0 -46
  216. package/apps/desktop-console/src/renderer/path-helpers.test.mts +0 -14
  217. package/apps/desktop-console/src/renderer/tabs/debug.mts +0 -48
  218. package/apps/desktop-console/src/renderer/tabs/debug.test.mts +0 -22
  219. package/apps/desktop-console/src/renderer/tabs/logs.mts +0 -421
  220. package/apps/desktop-console/src/renderer/tabs/logs.test.mts +0 -27
  221. package/apps/desktop-console/src/renderer/tabs/preflight.mts +0 -486
  222. package/apps/desktop-console/src/renderer/tabs/preflight.test.mts +0 -33
  223. package/apps/desktop-console/src/renderer/tabs/profile-pool.mts +0 -213
  224. package/apps/desktop-console/src/renderer/tabs/results.mts +0 -171
  225. package/apps/desktop-console/src/renderer/tabs/run.test.mts +0 -63
  226. package/apps/desktop-console/src/renderer/tabs/runtime.mts +0 -151
  227. package/apps/desktop-console/src/renderer/tabs/settings.mts +0 -146
  228. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/account-flow.mts +0 -486
  229. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/guide-browser-check.mts +0 -56
  230. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/helpers.mts +0 -262
  231. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/layout-block.mts +0 -430
  232. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/live-stats.mts +0 -847
  233. package/apps/desktop-console/src/renderer/tabs/xiaohongshu/run-flow.mts +0 -443
  234. package/apps/desktop-console/src/renderer/tabs/xiaohongshu-state.mts +0 -425
  235. package/apps/desktop-console/src/renderer/tabs/xiaohongshu.mts +0 -497
  236. package/apps/desktop-console/src/renderer/tabs/xiaohongshu.test.mts +0 -291
  237. package/apps/desktop-console/src/renderer/ui-components.mts +0 -31
  238. package/docs/README_camoufox_chinese.md +0 -141
  239. package/docs/USAGE_V3.md +0 -163
  240. package/docs/arch/OCR_MACOS_PLUGIN.md +0 -39
  241. package/docs/arch/PORTS.md +0 -40
  242. package/docs/arch/REGRESSION_CHECKLIST.md +0 -121
  243. package/docs/arch/SEARCH_GATE.md +0 -224
  244. package/docs/arch/VIEWPORT_SAFETY.md +0 -182
  245. package/docs/arch/XIAOHONGSHU_OFFLINE_MOCK_DESIGN.md +0 -267
  246. package/docs/xiaohongshu-container-driven-summary.md +0 -221
  247. package/docs/xiaohongshu-full-collect-runbook.md +0 -134
  248. package/docs/xiaohongshu-next-steps.md +0 -228
  249. package/docs/xiaohongshu-quickstart.md +0 -73
  250. package/docs/xiaohongshu-workflow-summary.md +0 -227
  251. package/modules/container-registry/tests/container-registry.test.ts +0 -16
  252. package/modules/logging/tests/logging.test.ts +0 -38
  253. package/modules/operations/tests/operations.test.ts +0 -22
  254. package/modules/operations/tests/viewport-filter.test.ts +0 -161
  255. package/modules/operations/tests/visible-only.test.ts +0 -250
  256. package/modules/session-manager/tests/session-manager.test.ts +0 -23
  257. package/modules/state/src/atomic-json.test.ts +0 -30
  258. package/modules/state/src/paths.test.ts +0 -59
  259. package/modules/state/src/xiaohongshu-collect-state.test.ts +0 -259
  260. package/modules/workflow/blocks/AnchorVerificationBlock.d.ts.map +0 -1
  261. package/modules/workflow/blocks/AnchorVerificationBlock.js.map +0 -1
  262. package/modules/workflow/blocks/DetectPageStateBlock.d.ts.map +0 -1
  263. package/modules/workflow/blocks/DetectPageStateBlock.js.map +0 -1
  264. package/modules/workflow/blocks/ErrorRecoveryBlock.d.ts.map +0 -1
  265. package/modules/workflow/blocks/ErrorRecoveryBlock.js.map +0 -1
  266. package/modules/workflow/blocks/WaitSearchPermitBlock.d.ts.map +0 -1
  267. package/modules/workflow/blocks/WaitSearchPermitBlock.js.map +0 -1
  268. package/modules/workflow/blocks/helpers/containerAnchors.d.ts.map +0 -1
  269. package/modules/workflow/blocks/helpers/containerAnchors.js.map +0 -1
  270. package/modules/workflow/blocks/helpers/downloadPaths.test.ts +0 -62
  271. package/modules/workflow/blocks/helpers/mergeXhsMarkdown.test.ts +0 -121
  272. package/modules/workflow/blocks/helpers/operationLogger.d.ts.map +0 -1
  273. package/modules/workflow/blocks/helpers/operationLogger.js.map +0 -1
  274. package/modules/workflow/blocks/helpers/persistedNotes.test.ts +0 -268
  275. package/modules/workflow/blocks/helpers/searchPageState.d.ts.map +0 -1
  276. package/modules/workflow/blocks/helpers/searchPageState.js.map +0 -1
  277. package/modules/workflow/blocks/helpers/targetCountMode.test.ts +0 -29
  278. package/modules/workflow/blocks/helpers/xhsCliArgs.test.ts +0 -75
  279. package/modules/workflow/tests/smartReply.test.ts +0 -32
  280. package/modules/xiaohongshu/app/src/blocks/Phase3Interact.matcher.test.ts +0 -33
  281. package/modules/xiaohongshu/app/src/utils/__tests__/checkpoints.test.ts +0 -141
  282. package/modules/xiaohongshu/app/tests/commentMatchDsl.test.ts +0 -50
  283. package/modules/xiaohongshu/app/tests/commentMatcher.test.ts +0 -46
  284. package/modules/xiaohongshu/app/tests/sharding.test.ts +0 -31
  285. package/package-scripts.json +0 -8
  286. package/runtime/infra/utils/README.md +0 -13
  287. package/runtime/infra/utils/scripts/README.md +0 -0
  288. package/runtime/infra/utils/scripts/development/eval-in-session.mjs +0 -40
  289. package/runtime/infra/utils/scripts/development/highlight-search-containers.mjs +0 -35
  290. package/runtime/infra/utils/scripts/service/kill-port.mjs +0 -24
  291. package/runtime/infra/utils/scripts/service/start-api.mjs +0 -39
  292. package/runtime/infra/utils/scripts/service/start-browser-service.mjs +0 -106
  293. package/runtime/infra/utils/scripts/service/stop-api.mjs +0 -18
  294. package/runtime/infra/utils/scripts/service/stop-browser-service.mjs +0 -104
  295. package/runtime/infra/utils/scripts/test-services.mjs +0 -94
  296. package/services/shared/heartbeat.test.ts +0 -102
  297. package/services/unified-api/__tests__/task-state.test.ts +0 -95
  298. package/sitecustomize.py +0 -19
  299. package/tests/README.md +0 -194
  300. package/tests/e2e/workflows/weibo-feed-extraction.test.ts +0 -171
  301. package/tests/fixtures/data/container-definitions.json +0 -67
  302. package/tests/fixtures/pages/simple-page.html +0 -69
  303. package/tests/integration/01-test-container-match.mjs +0 -188
  304. package/tests/integration/02-test-dom-branch.mjs +0 -161
  305. package/tests/integration/03-test-container-operation-system.mjs +0 -91
  306. package/tests/integration/05-test-container-lifecycle-events.mjs +0 -224
  307. package/tests/integration/05-test-container-lifecycle-with-events.mjs +0 -250
  308. package/tests/integration/06-test-container-dom-tree-drawing.mjs +0 -256
  309. package/tests/integration/07-test-weibo-container-lifecycle.mjs +0 -355
  310. package/tests/integration/08-test-weibo-feed-workflow.test.mjs +0 -164
  311. package/tests/integration/10-test-visual-analyzer.mjs +0 -312
  312. package/tests/integration/11-test-visual-loop.mjs +0 -284
  313. package/tests/integration/12-test-simple-visual-loop.mjs +0 -242
  314. package/tests/integration/13-test-visual-robust.mjs +0 -185
  315. package/tests/integration/14-test-visual-highlight-loop.mjs +0 -271
  316. package/tests/integration/inspect-page.mjs +0 -50
  317. package/tests/integration/run-all-tests.mjs +0 -95
  318. package/tests/patch_verification/CODEX_PATCH_TEST.md +0 -103
  319. package/tests/patch_verification/PHASE2_ANALYSIS.md +0 -179
  320. package/tests/patch_verification/PHASE2_OPTIMIZATION_REPORT.md +0 -55
  321. package/tests/patch_verification/PHASE2_TO_PHASE4_SUMMARY.md +0 -126
  322. package/tests/patch_verification/QUICK_TEST_SEQUENCE.md +0 -262
  323. package/tests/patch_verification/README.md +0 -143
  324. package/tests/patch_verification/RUN_TESTS.md +0 -60
  325. package/tests/patch_verification/TEST_EXECUTION.md +0 -99
  326. package/tests/patch_verification/TEST_PLAN.md +0 -328
  327. package/tests/patch_verification/TEST_RESULTS.md +0 -34
  328. package/tests/patch_verification/TOOL_TEST_PLAN.md +0 -48
  329. package/tests/patch_verification/run-tool-test.mjs +0 -121
  330. package/tests/patch_verification/temp_test_files/test01.txt +0 -1
  331. package/tests/patch_verification/temp_test_files/test02.txt +0 -3
  332. package/tests/patch_verification/temp_test_files/test02_gnu.txt +0 -3
  333. package/tests/patch_verification/temp_test_files/test03.txt +0 -1
  334. package/tests/patch_verification/temp_test_files/test03_multiline.txt +0 -5
  335. package/tests/patch_verification/temp_test_files/test04_function.ts +0 -5
  336. package/tests/patch_verification/temp_test_files/test05_import.ts +0 -4
  337. package/tests/patch_verification/temp_test_files/test06_special_chars.txt +0 -4
  338. package/tests/patch_verification/temp_test_files/test07_indentation.ts +0 -5
  339. package/tests/patch_verification/temp_test_files/test08_mismatch.txt +0 -1
  340. package/tests/patch_verification/temp_test_files/test_add_02.txt +0 -3
  341. package/tests/patch_verification/temp_test_files/test_simple.txt +0 -1
  342. package/tests/runner/TestReporter.mjs +0 -57
  343. package/tests/runner/TestRunner.mjs +0 -244
  344. package/tests/unit/commands/profile.test.mjs +0 -10
  345. package/tests/unit/container/change-notifier.test.mjs +0 -181
  346. package/tests/unit/lifecycle/session-registry.test.mjs +0 -135
  347. package/tests/unit/operations/registry.test.ts +0 -73
  348. package/tests/unit/utils/browser-service.test.mjs +0 -153
  349. package/tests/unit/utils/config.test.mjs +0 -166
  350. package/tests/unit/utils/fingerprint.test.mjs +0 -166
  351. package/tsconfig.json +0 -31
  352. package/tsconfig.services.json +0 -26
  353. /package/apps/desktop-console/{src → dist}/renderer/index.html +0 -0
  354. /package/apps/desktop-console/{src/renderer/tabs → dist/renderer}/run.mts +0 -0
@@ -0,0 +1,423 @@
1
+ #!/usr/bin/env node
2
+ import { execSync } from 'node:child_process';
3
+ import fs from 'node:fs';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import { BROWSER_SERVICE_URL, loadConfig, setRepoRoot } from './config.mjs';
7
+ export async function callAPI(action, payload = {}) {
8
+ const r = await fetch(`${BROWSER_SERVICE_URL}/command`, {
9
+ method: 'POST',
10
+ headers: { 'Content-Type': 'application/json' },
11
+ body: JSON.stringify({ action, args: payload }),
12
+ });
13
+ let body;
14
+ try {
15
+ body = await r.json();
16
+ }
17
+ catch {
18
+ const text = await r.text();
19
+ throw new Error(`HTTP ${r.status}: ${text}`);
20
+ }
21
+ if (!r.ok)
22
+ throw new Error(body?.error || `HTTP ${r.status}`);
23
+ return body;
24
+ }
25
+ export async function getSessionByProfile(profileId) {
26
+ const status = await callAPI('getStatus', {});
27
+ const activeSession = status?.sessions?.find((s) => s.profileId === profileId) || null;
28
+ if (activeSession) {
29
+ return activeSession;
30
+ }
31
+ if (!profileId) {
32
+ return null;
33
+ }
34
+ // Some browser-service builds do not populate getStatus.sessions reliably.
35
+ // Fallback to page:list so runtime can still attach to an active profile tab set.
36
+ try {
37
+ const pagePayload = await callAPI('page:list', { profileId });
38
+ const pages = Array.isArray(pagePayload?.pages)
39
+ ? pagePayload.pages
40
+ : Array.isArray(pagePayload?.data?.pages)
41
+ ? pagePayload.data.pages
42
+ : [];
43
+ if (!pages.length)
44
+ return null;
45
+ const activeIndex = Number(pagePayload?.activeIndex ?? pagePayload?.data?.activeIndex);
46
+ const activePage = Number.isFinite(activeIndex)
47
+ ? pages.find((page) => Number(page?.index) === activeIndex)
48
+ : (pages.find((page) => page?.active) || pages[0]);
49
+ return {
50
+ profileId,
51
+ session_id: profileId,
52
+ sessionId: profileId,
53
+ current_url: activePage?.url || null,
54
+ recoveredFromPages: true,
55
+ };
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ }
61
+ function buildDomSnapshotScript(maxDepth, maxChildren) {
62
+ return `(() => {
63
+ const MAX_DEPTH = ${maxDepth};
64
+ const MAX_CHILDREN = ${maxChildren};
65
+ const viewportWidth = Number(window.innerWidth || 0);
66
+ const viewportHeight = Number(window.innerHeight || 0);
67
+
68
+ const normalizeRect = (rect) => {
69
+ if (!rect) return null;
70
+ const left = Number(rect.left ?? rect.x ?? 0);
71
+ const top = Number(rect.top ?? rect.y ?? 0);
72
+ const width = Number(rect.width ?? 0);
73
+ const height = Number(rect.height ?? 0);
74
+ return {
75
+ left,
76
+ top,
77
+ right: left + width,
78
+ bottom: top + height,
79
+ x: left,
80
+ y: top,
81
+ width,
82
+ height,
83
+ };
84
+ };
85
+
86
+ const sanitizeClasses = (el) => {
87
+ const classAttr = typeof el.className === 'string'
88
+ ? el.className
89
+ : (el.getAttribute && el.getAttribute('class')) || '';
90
+ return classAttr.split(/\\s+/).filter(Boolean).slice(0, 24);
91
+ };
92
+
93
+ const collectAttrs = (el) => {
94
+ if (!el || !el.getAttribute) return null;
95
+ const keys = [
96
+ 'href',
97
+ 'src',
98
+ 'name',
99
+ 'type',
100
+ 'value',
101
+ 'placeholder',
102
+ 'role',
103
+ 'aria-label',
104
+ 'aria-hidden',
105
+ 'title',
106
+ ];
107
+ const attrs = {};
108
+ for (const key of keys) {
109
+ const value = el.getAttribute(key);
110
+ if (value === null || value === undefined || value === '') continue;
111
+ attrs[key] = String(value).slice(0, 400);
112
+ }
113
+ return Object.keys(attrs).length > 0 ? attrs : null;
114
+ };
115
+
116
+ const inViewport = (rect) => {
117
+ if (!rect) return false;
118
+ if (rect.width <= 0 || rect.height <= 0) return false;
119
+ return (
120
+ rect.right > 0
121
+ && rect.bottom > 0
122
+ && rect.left < viewportWidth
123
+ && rect.top < viewportHeight
124
+ );
125
+ };
126
+
127
+ const isRendered = (el) => {
128
+ try {
129
+ const style = window.getComputedStyle(el);
130
+ if (!style) return false;
131
+ if (style.display === 'none') return false;
132
+ if (style.visibility === 'hidden' || style.visibility === 'collapse') return false;
133
+ const opacity = Number.parseFloat(String(style.opacity || '1'));
134
+ if (Number.isFinite(opacity) && opacity <= 0.01) return false;
135
+ return true;
136
+ } catch {
137
+ return false;
138
+ }
139
+ };
140
+
141
+ const clampPoint = (value, max) => {
142
+ if (!Number.isFinite(value)) return 0;
143
+ if (max <= 1) return 0;
144
+ return Math.max(0, Math.min(max - 1, value));
145
+ };
146
+
147
+ const hitTestVisible = (el, rect) => {
148
+ if (!rect || viewportWidth <= 0 || viewportHeight <= 0) return false;
149
+ const samplePoints = [
150
+ [rect.left + rect.width * 0.5, rect.top + rect.height * 0.5],
151
+ [rect.left + rect.width * 0.2, rect.top + rect.height * 0.2],
152
+ [rect.left + rect.width * 0.8, rect.top + rect.height * 0.8],
153
+ ];
154
+ for (const [rawX, rawY] of samplePoints) {
155
+ const x = clampPoint(rawX, viewportWidth);
156
+ const y = clampPoint(rawY, viewportHeight);
157
+ const topEl = document.elementFromPoint(x, y);
158
+ if (!topEl) continue;
159
+ if (topEl === el) return true;
160
+ if (el.contains && el.contains(topEl)) return true;
161
+ if (topEl.contains && topEl.contains(el)) return true;
162
+ }
163
+ return false;
164
+ };
165
+
166
+ const collect = (el, depth = 0, path = 'root') => {
167
+ if (!el || depth > MAX_DEPTH) return null;
168
+ const classes = sanitizeClasses(el);
169
+ const rect = normalizeRect(el.getBoundingClientRect ? el.getBoundingClientRect() : null);
170
+ const tag = String(el.tagName || el.nodeName || '').toLowerCase();
171
+ const id = el.id || null;
172
+ const text = typeof el.textContent === 'string'
173
+ ? el.textContent.replace(/\\s+/g, ' ').trim()
174
+ : '';
175
+ const selector = tag
176
+ ? \`\${tag}\${id ? '#' + id : ''}\${classes.length ? '.' + classes.slice(0, 3).join('.') : ''}\`
177
+ : null;
178
+
179
+ const node = {
180
+ tag,
181
+ id,
182
+ classes,
183
+ selector,
184
+ path,
185
+ };
186
+ const attrs = collectAttrs(el);
187
+ if (attrs) node.attrs = attrs;
188
+ if (attrs && attrs.href) node.href = attrs.href;
189
+ if (rect) node.rect = rect;
190
+ if (text) node.textSnippet = text.slice(0, 120);
191
+ if (rect) {
192
+ const rendered = isRendered(el);
193
+ const withinViewport = inViewport(rect);
194
+ const visible = rendered && withinViewport && hitTestVisible(el, rect);
195
+ node.visible = visible;
196
+ } else {
197
+ node.visible = false;
198
+ }
199
+
200
+ const children = Array.from(el.children || []);
201
+ if (children.length > 0 && depth < MAX_DEPTH) {
202
+ node.children = [];
203
+ const limit = Math.min(children.length, MAX_CHILDREN);
204
+ for (let i = 0; i < limit; i += 1) {
205
+ const child = collect(children[i], depth + 1, \`\${path}/\${i}\`);
206
+ if (child) node.children.push(child);
207
+ }
208
+ }
209
+
210
+ return node;
211
+ };
212
+
213
+ const root = collect(document.body || document.documentElement, 0, 'root');
214
+ return {
215
+ dom_tree: root,
216
+ viewport: {
217
+ width: viewportWidth,
218
+ height: viewportHeight,
219
+ },
220
+ };
221
+ })()`;
222
+ }
223
+ export async function getDomSnapshotByProfile(profileId, options = {}) {
224
+ const maxDepth = Math.max(1, Math.min(20, Number(options.maxDepth) || 10));
225
+ const maxChildren = Math.max(1, Math.min(500, Number(options.maxChildren) || 120));
226
+ const response = await callAPI('evaluate', {
227
+ profileId,
228
+ script: buildDomSnapshotScript(maxDepth, maxChildren),
229
+ });
230
+ const payload = response?.result || response || {};
231
+ const tree = payload.dom_tree || null;
232
+ if (tree && payload.viewport && typeof payload.viewport === 'object') {
233
+ tree.__viewport = {
234
+ width: Number(payload.viewport.width) || 0,
235
+ height: Number(payload.viewport.height) || 0,
236
+ };
237
+ }
238
+ return tree;
239
+ }
240
+ export async function getViewportByProfile(profileId) {
241
+ const response = await callAPI('evaluate', {
242
+ profileId,
243
+ script: `(() => ({ width: Number(window.innerWidth || 0), height: Number(window.innerHeight || 0) }))()`,
244
+ });
245
+ const viewport = response?.result || response?.viewport || {};
246
+ const width = Number(viewport?.width) || 1280;
247
+ const height = Number(viewport?.height) || 720;
248
+ return { width, height };
249
+ }
250
+ export async function checkBrowserService() {
251
+ try {
252
+ const r = await fetch(`${BROWSER_SERVICE_URL}/health`, { signal: AbortSignal.timeout(2000) });
253
+ return r.ok;
254
+ }
255
+ catch {
256
+ return false;
257
+ }
258
+ }
259
+ function hasContainerLibrary(repoRoot) {
260
+ if (!repoRoot)
261
+ return false;
262
+ const root = path.resolve(String(repoRoot));
263
+ const candidate = path.join(root, 'apps', 'webauto', 'resources', 'container-library');
264
+ return fs.existsSync(candidate);
265
+ }
266
+ function walkUpForRepoRoot(startDir) {
267
+ if (!startDir)
268
+ return null;
269
+ let cursor = path.resolve(startDir);
270
+ for (;;) {
271
+ if (hasContainerLibrary(cursor))
272
+ return cursor;
273
+ const parent = path.dirname(cursor);
274
+ if (parent === cursor)
275
+ return null;
276
+ cursor = parent;
277
+ }
278
+ }
279
+ function scanCommonRepoRoots() {
280
+ const home = os.homedir();
281
+ const roots = [
282
+ path.join(home, 'Documents', 'github'),
283
+ path.join(home, 'github'),
284
+ path.join(home, 'code'),
285
+ path.join(home, 'projects'),
286
+ path.join('/Volumes', 'extension', 'code'),
287
+ path.join('C:', 'code'),
288
+ path.join('D:', 'code'),
289
+ path.join('C:', 'projects'),
290
+ path.join('D:', 'projects'),
291
+ path.join('C:', 'Users', os.userInfo().username, 'code'),
292
+ path.join('C:', 'Users', os.userInfo().username, 'projects'),
293
+ path.join('C:', 'Users', os.userInfo().username, 'Documents', 'github'),
294
+ ].filter(Boolean);
295
+ for (const root of roots) {
296
+ if (!fs.existsSync(root))
297
+ continue;
298
+ try {
299
+ const entries = fs.readdirSync(root, { withFileTypes: true });
300
+ for (const entry of entries) {
301
+ if (!entry.isDirectory())
302
+ continue;
303
+ if (!entry.name.toLowerCase().includes('webauto'))
304
+ continue;
305
+ const candidate = path.join(root, entry.name);
306
+ if (hasContainerLibrary(candidate))
307
+ return candidate;
308
+ }
309
+ }
310
+ catch {
311
+ // ignore scanning errors and continue
312
+ }
313
+ }
314
+ return null;
315
+ }
316
+ export function findRepoRootCandidate() {
317
+ const cfg = loadConfig();
318
+ const candidates = [
319
+ process.env.WEBAUTO_REPO_ROOT,
320
+ process.cwd(),
321
+ cfg.repoRoot,
322
+ path.join('/Volumes', 'extension', 'code', 'webauto'),
323
+ path.join('/Volumes', 'extension', 'code', 'WebAuto'),
324
+ path.join(os.homedir(), 'Documents', 'github', 'webauto'),
325
+ path.join(os.homedir(), 'Documents', 'github', 'WebAuto'),
326
+ path.join(os.homedir(), 'github', 'webauto'),
327
+ path.join(os.homedir(), 'github', 'WebAuto'),
328
+ path.join('C:', 'code', 'webauto'),
329
+ path.join('C:', 'code', 'WebAuto'),
330
+ path.join('C:', 'Users', os.userInfo().username, 'code', 'webauto'),
331
+ path.join('C:', 'Users', os.userInfo().username, 'code', 'WebAuto'),
332
+ ].filter(Boolean);
333
+ for (const root of candidates) {
334
+ if (!hasContainerLibrary(root))
335
+ continue;
336
+ const resolved = path.resolve(String(root));
337
+ if (cfg.repoRoot !== resolved) {
338
+ setRepoRoot(resolved);
339
+ }
340
+ return resolved;
341
+ }
342
+ const walked = walkUpForRepoRoot(process.cwd());
343
+ if (walked) {
344
+ if (cfg.repoRoot !== walked) {
345
+ setRepoRoot(walked);
346
+ }
347
+ return walked;
348
+ }
349
+ const scanned = scanCommonRepoRoots();
350
+ if (scanned) {
351
+ if (cfg.repoRoot !== scanned) {
352
+ setRepoRoot(scanned);
353
+ }
354
+ return scanned;
355
+ }
356
+ return null;
357
+ }
358
+ export function detectCamoufoxPath() {
359
+ try {
360
+ const cmd = process.platform === 'win32' ? 'python -m camoufox path' : 'python3 -m camoufox path';
361
+ const out = execSync(cmd, {
362
+ encoding: 'utf8',
363
+ stdio: ['ignore', 'pipe', 'pipe'],
364
+ });
365
+ const lines = out.trim().split(/\r?\n/);
366
+ for (let i = lines.length - 1; i >= 0; i -= 1) {
367
+ const line = lines[i].trim();
368
+ if (line && (line.startsWith('/') || line.match(/^[A-Z]:\\/)))
369
+ return line;
370
+ }
371
+ }
372
+ catch {
373
+ return null;
374
+ }
375
+ return null;
376
+ }
377
+ export function ensureCamoufox() {
378
+ if (detectCamoufoxPath())
379
+ return;
380
+ console.log('Camoufox is not found. Installing...');
381
+ execSync('npx --yes --package=camoufox camoufox fetch', { stdio: 'inherit' });
382
+ if (!detectCamoufoxPath()) {
383
+ throw new Error('Camoufox install finished but executable was not detected');
384
+ }
385
+ console.log('Camoufox installed.');
386
+ }
387
+ export async function ensureBrowserService() {
388
+ if (await checkBrowserService())
389
+ return;
390
+ const provider = String(process.env.WEBAUTO_BROWSER_PROVIDER || 'camo').trim().toLowerCase();
391
+ if (provider === 'none' || provider === 'external') {
392
+ throw new Error(`Browser backend is not healthy at ${BROWSER_SERVICE_URL} (provider=${provider}). ` +
393
+ 'Start backend manually or set WEBAUTO_BROWSER_PROVIDER=camo.');
394
+ }
395
+ if (provider === 'camo') {
396
+ const repoRoot = findRepoRootCandidate();
397
+ if (repoRoot) {
398
+ try {
399
+ execSync(`npx --yes @web-auto/camo config repo-root ${JSON.stringify(repoRoot)}`, { stdio: 'ignore' });
400
+ }
401
+ catch {
402
+ // best-effort only; init will still try using current config
403
+ }
404
+ }
405
+ try {
406
+ console.log('Starting browser backend via camo init...');
407
+ execSync('npx --yes @web-auto/camo init', { stdio: 'inherit' });
408
+ }
409
+ catch (error) {
410
+ throw new Error(`camo init failed: ${error?.message || String(error)}`);
411
+ }
412
+ for (let i = 0; i < 20; i += 1) {
413
+ await new Promise((r) => setTimeout(r, 400));
414
+ if (await checkBrowserService()) {
415
+ console.log('Browser backend is ready (provider=camo).');
416
+ return;
417
+ }
418
+ }
419
+ throw new Error('Browser backend failed to become healthy after camo init');
420
+ }
421
+ throw new Error(`Unsupported WEBAUTO_BROWSER_PROVIDER=${provider}; only "camo" is supported.`);
422
+ }
423
+ //# sourceMappingURL=browser-service.mjs.map
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import os from 'node:os';
5
+ export const CONFIG_DIR = path.join(os.homedir(), '.webauto');
6
+ export const PROFILES_DIR = path.join(CONFIG_DIR, 'profiles');
7
+ export const CONFIG_FILE = path.join(CONFIG_DIR, 'camo-cli.json');
8
+ export const BROWSER_SERVICE_URL = process.env.WEBAUTO_BROWSER_URL || 'http://127.0.0.1:7704';
9
+ export function ensureDir(p) {
10
+ if (!fs.existsSync(p))
11
+ fs.mkdirSync(p, { recursive: true });
12
+ }
13
+ export function readJson(p) {
14
+ try {
15
+ if (!fs.existsSync(p))
16
+ return null;
17
+ return JSON.parse(fs.readFileSync(p, 'utf8'));
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ export function writeJson(p, data) {
24
+ ensureDir(path.dirname(p));
25
+ fs.writeFileSync(p, JSON.stringify(data, null, 2));
26
+ }
27
+ export function loadConfig() {
28
+ const raw = readJson(CONFIG_FILE) || {};
29
+ return {
30
+ defaultProfile: typeof raw.defaultProfile === 'string' ? raw.defaultProfile : null,
31
+ repoRoot: typeof raw.repoRoot === 'string' ? raw.repoRoot : null,
32
+ };
33
+ }
34
+ export function saveConfig(config) {
35
+ writeJson(CONFIG_FILE, config);
36
+ }
37
+ export function listProfiles() {
38
+ if (!fs.existsSync(PROFILES_DIR))
39
+ return [];
40
+ return fs.readdirSync(PROFILES_DIR, { withFileTypes: true })
41
+ .filter((d) => d.isDirectory())
42
+ .map((d) => d.name)
43
+ .filter((name) => !name.includes(':') && !name.includes('/') && !name.startsWith('.'))
44
+ .sort();
45
+ }
46
+ export function isValidProfileId(profileId) {
47
+ return typeof profileId === 'string' && /^[a-zA-Z0-9._-]+$/.test(profileId);
48
+ }
49
+ export function createProfile(profileId) {
50
+ if (!isValidProfileId(profileId)) {
51
+ throw new Error('Invalid profileId. Use only letters, numbers, dot, underscore, dash.');
52
+ }
53
+ const profileDir = path.join(PROFILES_DIR, profileId);
54
+ if (fs.existsSync(profileDir))
55
+ throw new Error(`Profile already exists: ${profileId}`);
56
+ ensureDir(profileDir);
57
+ }
58
+ export function deleteProfile(profileId) {
59
+ const profileDir = path.join(PROFILES_DIR, profileId);
60
+ if (!fs.existsSync(profileDir))
61
+ throw new Error(`Profile not found: ${profileId}`);
62
+ fs.rmSync(profileDir, { recursive: true, force: true });
63
+ }
64
+ export function setDefaultProfile(profileId) {
65
+ const cfg = loadConfig();
66
+ cfg.defaultProfile = profileId;
67
+ saveConfig(cfg);
68
+ }
69
+ export function setRepoRoot(repoRoot) {
70
+ const cfg = loadConfig();
71
+ cfg.repoRoot = repoRoot;
72
+ saveConfig(cfg);
73
+ }
74
+ export function getDefaultProfile() {
75
+ return loadConfig().defaultProfile;
76
+ }
77
+ //# sourceMappingURL=config.mjs.map
@@ -0,0 +1,184 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import { fileURLToPath } from 'url';
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+ const PROJECT_ROOT = resolveProjectRoot(__dirname);
8
+ // 新的外置容器树根目录(开发用):~/.webauto/container-lib
9
+ const PRIMARY_USER_CONTAINER_ROOT = process.env.WEBAUTO_CONTAINER_ROOT || path.join(os.homedir(), '.webauto', 'container-lib');
10
+ const INDEX_PATH = path.join(PROJECT_ROOT, 'apps/webauto/resources/container-library.index.json');
11
+ function isLegacyContainer(definition) {
12
+ try {
13
+ return Boolean(definition?.metadata?.legacy_data);
14
+ }
15
+ catch {
16
+ return false;
17
+ }
18
+ }
19
+ export class ContainerRegistry {
20
+ indexCache = null;
21
+ listSites() {
22
+ const registry = this.ensureIndex();
23
+ return Object.entries(registry).map(([key, meta]) => ({
24
+ key,
25
+ website: meta.website || '',
26
+ path: meta.path || '',
27
+ }));
28
+ }
29
+ getContainersForSite(siteKey) {
30
+ if (!siteKey)
31
+ return {};
32
+ const registry = this.ensureIndex();
33
+ const site = registry[siteKey] || { path: path.join('apps/webauto/resources/container-library', siteKey) };
34
+ return this.fetchContainersForSite(siteKey, site);
35
+ }
36
+ resolveSiteKey(url) {
37
+ const registry = this.ensureIndex();
38
+ return this.findSiteKey(url, registry);
39
+ }
40
+ async load() {
41
+ // 兼容异步加载,但当前是同步实现
42
+ this.ensureIndex();
43
+ return;
44
+ }
45
+ getContainersForUrl(url) {
46
+ const registry = this.ensureIndex();
47
+ const siteKey = this.findSiteKey(url, registry);
48
+ if (!siteKey) {
49
+ return {};
50
+ }
51
+ const site = registry[siteKey] || { path: `apps/webauto/resources/container-library/${siteKey}` };
52
+ return this.fetchContainersForSite(siteKey, site);
53
+ }
54
+ fetchContainersForSite(siteKey, site) {
55
+ // 不做内存级别缓存,确保用户容器定义变更后,每次调用都能读取到最新文件。
56
+ // 内部会同时加载内置容器与用户容器目录并合并。
57
+ return this.loadSiteContainers(siteKey, site?.path);
58
+ }
59
+ ensureIndex() {
60
+ if (this.indexCache) {
61
+ return this.indexCache;
62
+ }
63
+ if (fs.existsSync(INDEX_PATH)) {
64
+ try {
65
+ this.indexCache = (JSON.parse(fs.readFileSync(INDEX_PATH, 'utf-8')) || {});
66
+ return this.indexCache;
67
+ }
68
+ catch {
69
+ // fall through
70
+ }
71
+ }
72
+ this.indexCache = {};
73
+ return this.indexCache;
74
+ }
75
+ loadSiteContainers(siteKey, relativePath) {
76
+ const containers = {};
77
+ const builtinPath = path.join(PROJECT_ROOT, relativePath || path.join('apps/webauto/resources/container-library', siteKey));
78
+ if (fs.existsSync(builtinPath)) {
79
+ this.walkSite(builtinPath, containers);
80
+ this.loadLegacyFile(builtinPath, containers);
81
+ }
82
+ const userPath = path.join(PRIMARY_USER_CONTAINER_ROOT, siteKey);
83
+ if (fs.existsSync(userPath)) {
84
+ this.walkSite(userPath, containers);
85
+ this.loadLegacyFile(userPath, containers);
86
+ }
87
+ return containers;
88
+ }
89
+ walkSite(sitePath, output) {
90
+ const stack = [{ dir: sitePath, parts: [] }];
91
+ while (stack.length) {
92
+ const { dir, parts } = stack.pop();
93
+ let hasContainerFile = false;
94
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
95
+ if (entry.isFile() && entry.name === 'container.json') {
96
+ const relParts = parts.length ? parts : [path.basename(dir)];
97
+ const containerId = relParts.join('.');
98
+ try {
99
+ const raw = JSON.parse(fs.readFileSync(path.join(dir, entry.name), 'utf-8'));
100
+ if (raw && typeof raw === 'object') {
101
+ if (isLegacyContainer(raw)) {
102
+ continue;
103
+ }
104
+ const id = raw.id || containerId;
105
+ output[id] = { id, ...raw };
106
+ }
107
+ }
108
+ catch {
109
+ // ignore malformed container
110
+ }
111
+ hasContainerFile = true;
112
+ }
113
+ else if (entry.isDirectory()) {
114
+ stack.push({ dir: path.join(dir, entry.name), parts: [...parts, entry.name] });
115
+ }
116
+ }
117
+ if (!hasContainerFile && parts.length === 0) {
118
+ // root dir may not contain direct containers, continue
119
+ continue;
120
+ }
121
+ }
122
+ }
123
+ loadLegacyFile(sitePath, output) {
124
+ const legacyFile = path.join(sitePath, 'containers.json');
125
+ if (!fs.existsSync(legacyFile)) {
126
+ return;
127
+ }
128
+ try {
129
+ const raw = JSON.parse(fs.readFileSync(legacyFile, 'utf-8'));
130
+ const containers = raw?.containers;
131
+ if (containers && typeof containers === 'object') {
132
+ for (const [key, value] of Object.entries(containers)) {
133
+ if (!output[key] && value && typeof value === 'object') {
134
+ if (isLegacyContainer(value)) {
135
+ continue;
136
+ }
137
+ output[key] = { id: key, ...value };
138
+ }
139
+ }
140
+ }
141
+ }
142
+ catch {
143
+ // ignore legacy parse error
144
+ }
145
+ }
146
+ findSiteKey(url, registry) {
147
+ let host = '';
148
+ try {
149
+ const parsed = new URL(url);
150
+ host = (parsed.hostname || '').toLowerCase();
151
+ }
152
+ catch {
153
+ return null;
154
+ }
155
+ let bestKey = null;
156
+ let bestLen = -1;
157
+ for (const [key, value] of Object.entries(registry)) {
158
+ const domain = (value.website || '').toLowerCase();
159
+ if (!domain)
160
+ continue;
161
+ if (host === domain || host.endsWith(`.${domain}`)) {
162
+ if (domain.length > bestLen) {
163
+ bestKey = key;
164
+ bestLen = domain.length;
165
+ }
166
+ }
167
+ }
168
+ return bestKey;
169
+ }
170
+ }
171
+ function resolveProjectRoot(startDir) {
172
+ let current = startDir;
173
+ const { root } = path.parse(startDir);
174
+ while (true) {
175
+ if (fs.existsSync(path.join(current, 'package.json'))) {
176
+ return current;
177
+ }
178
+ if (current === root) {
179
+ return startDir;
180
+ }
181
+ current = path.resolve(current, '..');
182
+ }
183
+ }
184
+ //# sourceMappingURL=index.js.map