@web-auto/webauto 0.1.3 → 0.1.6

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 (174) hide show
  1. package/apps/desktop-console/default-settings.json +2 -2
  2. package/apps/desktop-console/dist/main/index.mjs +915 -85
  3. package/apps/desktop-console/dist/main/preload.mjs +7 -0
  4. package/apps/desktop-console/dist/renderer/index.html +622 -50
  5. package/apps/desktop-console/dist/renderer/index.js +2415 -470
  6. package/apps/desktop-console/dist/renderer/run.mts +6 -5
  7. package/apps/desktop-console/entry/ui-cli.mjs +672 -0
  8. package/apps/desktop-console/entry/ui-console.mjs +416 -29
  9. package/apps/webauto/entry/account.mjs +89 -53
  10. package/apps/webauto/entry/browser-status.mjs +7 -10
  11. package/apps/webauto/entry/lib/account-detect.mjs +254 -28
  12. package/apps/webauto/entry/lib/account-store.mjs +219 -30
  13. package/apps/webauto/entry/lib/bus-publish.mjs +63 -0
  14. package/apps/webauto/entry/lib/camo-cli.mjs +93 -0
  15. package/apps/webauto/entry/lib/profilepool.mjs +14 -5
  16. package/apps/webauto/entry/lib/quota-status.mjs +23 -0
  17. package/apps/webauto/entry/lib/schedule-store.mjs +1068 -0
  18. package/apps/webauto/entry/profilepool.mjs +106 -17
  19. package/apps/webauto/entry/schedule.mjs +612 -0
  20. package/apps/webauto/entry/weibo-unified.mjs +134 -0
  21. package/apps/webauto/entry/xhs-install.mjs +236 -29
  22. package/apps/webauto/entry/xhs-status.mjs +5 -2
  23. package/apps/webauto/entry/xhs-unified.mjs +631 -98
  24. package/apps/webauto/resources/container-library/weibo/weibo_detail_page/comment_item/container.json +40 -0
  25. package/apps/webauto/resources/container-library/weibo/weibo_detail_page/reply_expand_button/container.json +38 -0
  26. package/apps/webauto/resources/container-library/weibo/weibo_detail_page/reply_list/container.json +37 -0
  27. package/apps/webauto/resources/container-library/weibo/weibo_search_page/container.json +8 -3
  28. package/apps/webauto/resources/container-library/weibo/weibo_search_page/login_anchor/container.json +30 -0
  29. package/apps/webauto/resources/container-library/weibo/weibo_search_page/search_bar/container.json +47 -0
  30. package/apps/webauto/resources/container-library/weibo/weibo_search_page/search_button/container.json +39 -0
  31. package/bin/camoufox-cli.mjs +61 -0
  32. package/bin/webauto.mjs +301 -54
  33. package/dist/modules/camo-backend/src/index.js +49 -1
  34. package/dist/modules/camo-backend/src/internal/BrowserSession.js +572 -3
  35. package/dist/modules/camo-backend/src/internal/SessionManager.js +13 -1
  36. package/dist/modules/camo-backend/src/internal/storage-paths.js +6 -0
  37. package/dist/modules/collection-manager/bloom-filter.js +91 -0
  38. package/dist/modules/collection-manager/date-utils.js +275 -0
  39. package/dist/modules/collection-manager/index.js +258 -0
  40. package/dist/modules/collection-manager/storage.js +195 -0
  41. package/dist/modules/collection-manager/types.js +47 -0
  42. package/dist/modules/logging/src/index.js +1 -1
  43. package/dist/modules/process-registry/index.js +230 -0
  44. package/dist/modules/rate-limiter/index.js +242 -0
  45. package/dist/modules/workflow/blocks/ExecuteWeiboSearchBlock.js +128 -0
  46. package/dist/modules/workflow/blocks/PersistXhsNoteBlock.js +7 -3
  47. package/dist/modules/workflow/blocks/RenderMarkdown.js +4 -1
  48. package/dist/modules/workflow/blocks/WeiboCollectCommentsBlock.js +282 -0
  49. package/dist/modules/workflow/blocks/WeiboCollectFromLinksBlock.js +283 -0
  50. package/dist/modules/workflow/blocks/WeiboCollectSearchLinksBlock.js +208 -0
  51. package/dist/modules/workflow/blocks/WeiboCollectTimelineListBlock.js +128 -0
  52. package/dist/modules/workflow/blocks/WeiboCollectUserPostsListBlock.js +127 -0
  53. package/dist/modules/workflow/blocks/helpers/downloadPaths.js +21 -0
  54. package/dist/modules/workflow/config/workflowRegistry.js +2 -0
  55. package/dist/modules/workflow/definitions/weibo-search-workflow-v1.js +47 -0
  56. package/dist/modules/workflow/src/runner.js +6 -0
  57. package/dist/modules/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.js +4 -0
  58. package/dist/modules/xiaohongshu/app/src/blocks/Phase3InteractBlock.js +2 -2
  59. package/dist/modules/xiaohongshu/app/src/blocks/helpers/sharding.js +123 -0
  60. package/dist/modules/xiaohongshu/app/src/container-registry/src/index.d.ts +37 -0
  61. package/dist/modules/xiaohongshu/app/src/container-registry/src/index.js +184 -0
  62. package/dist/modules/xiaohongshu/app/src/workflow/blocks/AnchorVerificationBlock.d.ts +31 -0
  63. package/dist/modules/xiaohongshu/app/src/workflow/blocks/AnchorVerificationBlock.js +71 -0
  64. package/dist/modules/xiaohongshu/app/src/workflow/blocks/DetectPageStateBlock.d.ts +48 -0
  65. package/dist/modules/xiaohongshu/app/src/workflow/blocks/DetectPageStateBlock.js +259 -0
  66. package/dist/modules/xiaohongshu/app/src/workflow/blocks/ErrorRecoveryBlock.d.ts +28 -0
  67. package/dist/modules/xiaohongshu/app/src/workflow/blocks/ErrorRecoveryBlock.js +319 -0
  68. package/dist/modules/xiaohongshu/app/src/workflow/blocks/WaitSearchPermitBlock.d.ts +36 -0
  69. package/dist/modules/xiaohongshu/app/src/workflow/blocks/WaitSearchPermitBlock.js +162 -0
  70. package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/containerAnchors.d.ts +36 -0
  71. package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/containerAnchors.js +301 -0
  72. package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/operationLogger.d.ts +29 -0
  73. package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/operationLogger.js +195 -0
  74. package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/searchPageState.d.ts +25 -0
  75. package/dist/modules/xiaohongshu/app/src/workflow/blocks/helpers/searchPageState.js +164 -0
  76. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/MatchCommentsBlock.d.ts +66 -0
  77. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/MatchCommentsBlock.js +139 -0
  78. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1EnsureServicesBlock.d.ts +16 -0
  79. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1EnsureServicesBlock.js +36 -0
  80. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1MonitorCookieBlock.d.ts +27 -0
  81. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1MonitorCookieBlock.js +213 -0
  82. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1StartProfileBlock.d.ts +18 -0
  83. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase1StartProfileBlock.js +121 -0
  84. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase2CollectLinksBlock.d.ts +34 -0
  85. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase2CollectLinksBlock.js +1249 -0
  86. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase2SearchBlock.d.ts +17 -0
  87. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase2SearchBlock.js +703 -0
  88. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CloseDetailBlock.d.ts +15 -0
  89. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CloseDetailBlock.js +41 -0
  90. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CloseTabsBlock.d.ts +26 -0
  91. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CloseTabsBlock.js +44 -0
  92. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CollectCommentsBlock.d.ts +29 -0
  93. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34CollectCommentsBlock.js +150 -0
  94. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ExtractDetailBlock.d.ts +38 -0
  95. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ExtractDetailBlock.js +117 -0
  96. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34OpenDetailBlock.d.ts +30 -0
  97. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34OpenDetailBlock.js +102 -0
  98. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34OpenTabsBlock.d.ts +23 -0
  99. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34OpenTabsBlock.js +109 -0
  100. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.d.ts +32 -0
  101. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.js +117 -0
  102. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ProcessSingleNoteBlock.d.ts +35 -0
  103. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ProcessSingleNoteBlock.js +114 -0
  104. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ValidateLinksBlock.d.ts +34 -0
  105. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase34ValidateLinksBlock.js +90 -0
  106. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase3InteractBlock.d.ts +111 -0
  107. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase3InteractBlock.js +1009 -0
  108. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase4MultiTabHarvestBlock.d.ts +20 -0
  109. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/Phase4MultiTabHarvestBlock.js +233 -0
  110. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/ReplyInteractBlock.d.ts +48 -0
  111. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/ReplyInteractBlock.js +291 -0
  112. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/XhsDiscoverFallbackBlock.d.ts +23 -0
  113. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/XhsDiscoverFallbackBlock.js +240 -0
  114. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/commentMatchDsl.d.ts +55 -0
  115. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/commentMatchDsl.js +126 -0
  116. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/commentMatcher.d.ts +21 -0
  117. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/commentMatcher.js +99 -0
  118. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/evidence.d.ts +5 -0
  119. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/evidence.js +27 -0
  120. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/sharding.d.ts +37 -0
  121. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/sharding.js +165 -0
  122. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/xhsComments.d.ts +33 -0
  123. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/blocks/helpers/xhsComments.js +270 -0
  124. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/index.d.ts +9 -0
  125. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/index.js +9 -0
  126. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/utils/checkpoints.d.ts +50 -0
  127. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/utils/checkpoints.js +222 -0
  128. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/utils/controllerAction.d.ts +10 -0
  129. package/dist/modules/xiaohongshu/app/src/xiaohongshu/app/src/utils/controllerAction.js +43 -0
  130. package/dist/services/shared/serviceProcessLogger.js +1 -1
  131. package/dist/services/unified-api/server.js +105 -11
  132. package/modules/camo-backend/src/index.ts +46 -1
  133. package/modules/camo-backend/src/internal/BrowserSession.ts +619 -3
  134. package/modules/camo-backend/src/internal/SessionManager.ts +12 -1
  135. package/modules/camo-backend/src/internal/storage-paths.ts +5 -0
  136. package/modules/camo-runtime/src/autoscript/action-providers/xhs/comments.mjs +38 -2
  137. package/modules/camo-runtime/src/autoscript/action-providers/xhs/interaction.mjs +47 -2
  138. package/modules/camo-runtime/src/autoscript/action-providers/xhs/search.mjs +94 -11
  139. package/modules/camo-runtime/src/autoscript/action-providers/xhs.mjs +208 -2
  140. package/modules/camo-runtime/src/autoscript/runtime.mjs +7 -1
  141. package/modules/camo-runtime/src/autoscript/xhs-unified-template.mjs +76 -43
  142. package/modules/camo-runtime/src/container/runtime-core/operations/index.mjs +75 -1
  143. package/modules/camo-runtime/src/container/runtime-core/operations/selector-scripts.mjs +71 -4
  144. package/modules/camo-runtime/src/container/runtime-core/operations/tab-pool.mjs +183 -27
  145. package/modules/collection-manager/bloom-filter.ts +112 -0
  146. package/modules/collection-manager/date-utils.ts +316 -0
  147. package/modules/collection-manager/index.ts +309 -0
  148. package/modules/collection-manager/package.json +10 -0
  149. package/modules/collection-manager/storage.ts +174 -0
  150. package/modules/collection-manager/types.ts +156 -0
  151. package/modules/logging/src/index.ts +1 -1
  152. package/modules/process-registry/index.ts +284 -0
  153. package/modules/rate-limiter/index.ts +322 -0
  154. package/modules/state/src/paths.ts +9 -1
  155. package/modules/task-scheduler/index.ts +293 -0
  156. package/modules/workflow/blocks/ExecuteWeiboSearchBlock.ts +167 -0
  157. package/modules/workflow/blocks/PersistXhsNoteBlock.ts +7 -3
  158. package/modules/workflow/blocks/RenderMarkdown.ts +4 -1
  159. package/modules/workflow/blocks/WeiboCollectCommentsBlock.ts +339 -0
  160. package/modules/workflow/blocks/WeiboCollectFromLinksBlock.ts +338 -0
  161. package/modules/workflow/blocks/helpers/downloadPaths.ts +16 -0
  162. package/modules/workflow/config/workflowRegistry.ts +2 -0
  163. package/modules/workflow/definitions/weibo-search-workflow-v1.ts +47 -0
  164. package/modules/workflow/src/runner.ts +6 -0
  165. package/modules/xiaohongshu/app/src/blocks/Phase1StartProfileBlock.ts +1 -1
  166. package/modules/xiaohongshu/app/src/blocks/Phase34PersistDetailBlock.ts +4 -0
  167. package/modules/xiaohongshu/app/src/blocks/Phase3InteractBlock.ts +2 -3
  168. package/modules/xiaohongshu/app/src/blocks/helpers/sharding.ts +152 -0
  169. package/package.json +14 -5
  170. package/scripts/postinstall-resources.mjs +62 -0
  171. package/scripts/test/run-coverage.mjs +76 -0
  172. package/scripts/weibo/search.ts +49 -0
  173. package/services/shared/serviceProcessLogger.ts +1 -1
  174. package/services/unified-api/server.ts +98 -12
package/bin/webauto.mjs CHANGED
@@ -37,23 +37,65 @@ function isGlobalInstall() {
37
37
  !existsSync(path.join(ROOT, '.git'));
38
38
  }
39
39
 
40
- function npmBin() {
41
- return process.platform === 'win32' ? 'npm.cmd' : 'npm';
40
+ function resolveOnPath(candidates) {
41
+ const pathEnv = process.env.PATH || process.env.Path || '';
42
+ const dirs = pathEnv.split(path.delimiter).filter(Boolean);
43
+ for (const dir of dirs) {
44
+ for (const name of candidates) {
45
+ const full = path.join(dir, name);
46
+ if (existsSync(full)) return full;
47
+ }
48
+ }
49
+ return null;
50
+ }
51
+
52
+ function wrapWindowsRunner(cmdPath, prefix = []) {
53
+ if (process.platform !== 'win32') return { cmd: cmdPath, prefix };
54
+ const lower = String(cmdPath || '').toLowerCase();
55
+ if (lower.endsWith('.ps1')) {
56
+ return {
57
+ cmd: 'powershell.exe',
58
+ prefix: ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', cmdPath, ...prefix],
59
+ };
60
+ }
61
+ if (lower.endsWith('.cmd') || lower.endsWith('.bat')) {
62
+ return {
63
+ cmd: 'cmd.exe',
64
+ prefix: ['/d', '/s', '/c', cmdPath, ...prefix],
65
+ };
66
+ }
67
+ return { cmd: cmdPath, prefix };
68
+ }
69
+
70
+ function npmRunner() {
71
+ if (process.platform !== 'win32') return { cmd: 'npm', prefix: [] };
72
+ const npmNames = ['npm.cmd', 'npm.exe', 'npm.bat', 'npm.ps1'];
73
+ const resolved = resolveOnPath(npmNames) || 'npm.cmd';
74
+ return wrapWindowsRunner(resolved);
75
+ }
76
+
77
+ function uiConsoleScriptPath() {
78
+ return path.join(ROOT, 'apps', 'desktop-console', 'entry', 'ui-console.mjs');
42
79
  }
43
80
 
44
81
  function printMainHelp() {
45
82
  console.log(`webauto CLI
46
83
 
47
84
  Usage:
85
+ webauto # 直接启动 UI Console
48
86
  webauto --help
49
87
  webauto account --help
50
- webauto ui console --help
88
+ webauto schedule --help
89
+ webauto deps --help
90
+ webauto ui --help
51
91
  webauto xhs --help
52
92
 
53
93
  Core Commands:
54
94
  webauto account <list|sync|add|get|update|delete|login|sync-alias> [options]
95
+ webauto schedule <list|get|add|update|delete|import|export|run|run-due|daemon> [options]
96
+ webauto deps <check|auto|install|uninstall|reinstall> [options]
55
97
  webauto ui console [--build] [--install] [--check]
56
- webauto ui test <scenario> [options]
98
+ webauto ui cli <action> [options]
57
99
  webauto xhs install [--download-browser] [--download-geoip] [--ensure-backend]
58
100
  webauto xhs unified [xhs options...]
59
101
  webauto xhs status [--run-id <id>] [--json]
@@ -61,36 +103,44 @@ Core Commands:
61
103
 
62
104
  Build & Release:
63
105
  webauto build:dev # Local link mode
64
- webauto build:release # Prepare npm release
106
+ webauto build:release # Full release gate (tests/build/pack)
107
+ webauto build:release -- --skip-tests
108
+ webauto build:release -- --skip-pack
65
109
 
66
110
  Examples (standard):
67
111
  webauto account add --platform xiaohongshu --alias 主号
68
112
  webauto account list
69
113
  webauto account login xhs-0001 --url https://www.xiaohongshu.com
70
114
  webauto account sync-alias xhs-0001
115
+ webauto schedule add --name "工作服-半小时" --schedule-type interval --interval-minutes 30 --profile xiaohongshu-batch-1 --keyword "工作服定制" --max-notes 50 --env debug
116
+ webauto schedule list
117
+ webauto schedule daemon --interval-sec 30
118
+ webauto deps install --all
119
+ webauto deps reinstall --all
71
120
  webauto ui console --check
72
121
  webauto ui console --build
73
122
  webauto ui console --install
74
- webauto ui test env-check
75
- webauto ui test account-flow --profile test-001
76
- webauto ui test config-save --output ./report.json
77
- webauto ui test crawl-run --keyword "测试" --target 10
123
+ webauto ui cli start --build
124
+ webauto ui cli tab --tab 配置
125
+ webauto ui cli input --selector "#keyword-input" --value "seedance2.0"
126
+ webauto ui cli click --selector "#start-btn"
78
127
  webauto xhs install --ensure-backend
79
128
  webauto xhs unified --profile xiaohongshu-batch-1 --keyword "seedance2.0" --max-notes 100 --do-comments true --persist-comments true --do-likes true --like-keywords "真牛逼" --env debug --tab-count 4
80
129
 
81
130
  Tips:
82
131
  - xhs 命令会转发到 apps/webauto/entry/xhs-*.mjs
83
132
  - account 命令会转发到 apps/webauto/entry/account.mjs
133
+ - schedule 命令会转发到 apps/webauto/entry/schedule.mjs
84
134
  - 全量参数请看: webauto xhs --help
85
135
  `);
86
136
  }
87
137
 
88
138
  function printUiConsoleHelp() {
89
- console.log(`webauto ui console
139
+ console.log(`webauto ui
90
140
 
91
141
  Usage:
92
142
  webauto ui console [--build] [--install] [--check] [--no-daemon]
93
- webauto ui test <scenario> [options]
143
+ webauto ui cli <action> [options]
94
144
 
95
145
  Options:
96
146
  --check 只检查构建/依赖状态,不启动 UI
@@ -98,27 +148,41 @@ Options:
98
148
  --install 缺少依赖时自动安装
99
149
  --no-daemon 前台模式运行(不后台守护)
100
150
 
101
- Test Scenarios:
102
- env-check 环境检查(camo CLI + 服务健康)
103
- account-flow 账户创建/登录流程测试
104
- config-save 配置导入/导出测试
105
- crawl-run 完整爬取流程测试(dry-run 模式)
106
-
107
- Test Options:
108
- --profile <id> 测试用 profile ID
109
- --keyword <kw> 测试关键词
110
- --target <n> 目标数量
111
- --headless 无头模式
112
- --output <path> 输出 JSON 报告路径
151
+ CLI Actions:
152
+ start 启动 UI(可配合 --build/--install)
153
+ status 获取 UI 运行状态(含 runId/错误计数)
154
+ snapshot 获取 UI 快照(含当前 tab 与关键控件值)
155
+ tab 切换 tab(--tab config 或 --label 配置)
156
+ click 点击控件(--selector)
157
+ focus 聚焦控件(--selector)
158
+ input 输入文本(--selector --value)
159
+ select 选择下拉项(--selector --value)
160
+ press 输入按键(--key Enter/Escape)
161
+ probe 读取控件状态(exists/count/value/text/checked,可选 --detailed)
162
+ click-text 按文案点击按钮(无 id 控件)
163
+ dialogs 控制 alert/confirm/prompt 静默模式
164
+ wait 等待元素状态(--selector --state visible|exists|hidden|text_contains|text_equals|value_equals|not_disabled)
165
+ run 按 steps.json 执行动作序列
166
+ full-cover 真实 UI CLI 全功能覆盖回归(无 mock)
167
+
168
+ Common Options:
169
+ --auto-start 未检测到 UI 时自动拉起
170
+ --host <host> 控制通道 host(默认 127.0.0.1)
171
+ --port <n> 控制通道端口(默认 7716)
172
+ --json 输出 JSON
173
+ --detailed probe 时返回 rect/style/attributes 等详细信息
113
174
 
114
175
  Examples:
115
176
  webauto ui console --check
116
177
  webauto ui console --build
117
178
  webauto ui console --install
118
- webauto ui test env-check
119
- webauto ui test account-flow --profile test-001
120
- webauto ui test config-save --output ./report.json
121
- webauto ui test crawl-run --keyword "测试" --target 10 --headless
179
+ webauto ui cli start --build
180
+ webauto ui cli status --json
181
+ webauto ui cli tab --tab 配置
182
+ webauto ui cli input --selector "#keyword-input" --value "春晚"
183
+ webauto ui cli click --selector "#start-btn"
184
+ webauto ui cli probe --selector "#start-btn" --detailed
185
+ webauto ui cli full-cover --build --output ./.tmp/ui-cli-full-cover.json
122
186
  `);
123
187
  }
124
188
 
@@ -126,13 +190,13 @@ function printXhsHelp() {
126
190
  console.log(`webauto xhs
127
191
 
128
192
  Usage:
129
- webauto xhs install [--download-browser] [--download-geoip] [--ensure-backend]
193
+ webauto xhs install [--download-browser] [--download-geoip] [--ensure-backend] [--install|--reinstall|--uninstall] [--browser|--geoip|--all]
130
194
  webauto xhs unified --profile <id> --keyword <kw> [options...]
131
195
  webauto xhs status [--run-id <id>] [--json]
132
196
  webauto xhs orchestrate --profile <id> --keyword <kw> [options...]
133
197
 
134
198
  Subcommands:
135
- install 运行 xhs-install,检查/安装 camoufox、geoip,按需拉起 backend
199
+ install 运行资源管理(兼容旧入口),支持检查/安装/卸载/重装 camoufox、geoip,按需拉起 backend
136
200
  unified 运行统一脚本(搜索 + 打开详情 + 评论抓取 + 点赞)
137
201
  status 查询当前任务状态与错误摘要(支持 runId 详情)
138
202
  orchestrate 运行编排入口(默认调用 unified 模式)
@@ -227,6 +291,57 @@ Examples:
227
291
  `);
228
292
  }
229
293
 
294
+ function printScheduleHelp() {
295
+ console.log(`webauto schedule
296
+
297
+ Usage:
298
+ webauto schedule --help
299
+ webauto schedule list [--json]
300
+ webauto schedule get <taskId> [--json]
301
+ webauto schedule add [options]
302
+ webauto schedule update <taskId> [options]
303
+ webauto schedule delete <taskId> [--json]
304
+ webauto schedule import [--file <path> | --payload-json <json>] [--json]
305
+ webauto schedule export [taskId] [--file <path>] [--json]
306
+ webauto schedule run <taskId> [--json]
307
+ webauto schedule run-due [--limit <n>] [--json]
308
+ webauto schedule daemon [--interval-sec <n>] [--limit <n>] [--once] [--json]
309
+
310
+ Examples:
311
+ webauto schedule add --name "deepseek-每30分钟" --schedule-type interval --interval-minutes 30 --profile xiaohongshu-batch-1 --keyword deepseek --max-notes 100 --do-comments true --do-likes true --like-keywords 牛逼 --env debug
312
+ webauto schedule add --name "每天早上任务" --schedule-type daily --run-at 2026-02-20T09:00:00+08:00 --max-runs 30 --profile xiaohongshu-batch-1 --keyword 工作服
313
+ webauto schedule add --name "每周巡检" --schedule-type weekly --run-at 2026-02-22T10:30:00+08:00 --max-runs 8 --profile xiaohongshu-batch-1 --keyword deepseek
314
+ webauto schedule list
315
+ webauto schedule run-due --json
316
+ webauto schedule daemon --interval-sec 30
317
+ `);
318
+ }
319
+
320
+ function printDepsHelp() {
321
+ console.log(`webauto deps
322
+
323
+ Usage:
324
+ webauto deps --help
325
+ webauto deps check [--browser|--geoip|--all] [--json]
326
+ webauto deps auto [--browser|--geoip|--all] [--json]
327
+ webauto deps install [--browser|--geoip|--all] [--ensure-backend] [--json]
328
+ webauto deps uninstall [--browser|--geoip|--all] [--json]
329
+ webauto deps reinstall [--browser|--geoip|--all] [--ensure-backend] [--json]
330
+
331
+ Notes:
332
+ - 不指定资源范围时默认 --all
333
+ - install/reinstall 默认会追加 --ensure-backend(可用 --no-ensure-backend 关闭)
334
+ - auto 模式用于 npm 安装后自动补齐缺失资源
335
+
336
+ Examples:
337
+ webauto deps check --all --json
338
+ webauto deps install --all
339
+ webauto deps install --browser --ensure-backend
340
+ webauto deps uninstall --geoip
341
+ webauto deps reinstall --all --json
342
+ `);
343
+ }
344
+
230
345
  function exists(p) {
231
346
  try {
232
347
  return existsSync(p);
@@ -244,7 +359,14 @@ async function run(cmd, args, options = {}) {
244
359
  ...options,
245
360
  });
246
361
  child.on('error', reject);
247
- child.on('exit', (code) => (code === 0 ? resolve() : reject(new Error(`exit ${code}`))));
362
+ child.on('exit', (code) => {
363
+ if (code === 0) return resolve();
364
+ if (process.platform === 'win32' && code === 3221226505) {
365
+ console.warn(`[webauto] Ignored spurious exit on Windows (code ${code})`);
366
+ return resolve();
367
+ }
368
+ return reject(new Error(`exit ${code}`));
369
+ });
248
370
  });
249
371
  }
250
372
 
@@ -256,11 +378,19 @@ async function runInDir(dir, cmd, args) {
256
378
  stdio: 'inherit',
257
379
  });
258
380
  child.on('error', reject);
259
- child.on('exit', (code) => (code === 0 ? resolve() : reject(new Error(`exit ${code}`))));
381
+ child.on('exit', (code) => {
382
+ if (code === 0) return resolve();
383
+ if (process.platform === 'win32' && code === 3221226505) {
384
+ console.warn(`[webauto] Ignored spurious exit on Windows (code ${code})`);
385
+ return resolve();
386
+ }
387
+ return reject(new Error(`exit ${code}`));
388
+ });
260
389
  });
261
390
  }
262
391
 
263
392
  function checkDesktopConsoleDeps() {
393
+ if (isGlobalInstall()) return true;
264
394
  // Check for electron in various locations:
265
395
  // 1. Global npm root (when installed globally alongside webauto)
266
396
  // 2. Package's own node_modules
@@ -291,16 +421,30 @@ async function ensureDepsAndBuild() {
291
421
  process.exit(1);
292
422
  }
293
423
 
424
+ // Global package should already ship renderer build.
425
+ if (isGlobalInstall()) {
426
+ if (!checkDesktopConsoleBuilt()) {
427
+ console.error('❌ desktop-console dist missing from package. Please reinstall @web-auto/webauto.');
428
+ process.exit(1);
429
+ }
430
+ const pkgJson = JSON.parse(readFileSync(path.join(ROOT, 'package.json'), 'utf-8'));
431
+ saveState({ initialized: true, version: pkgJson.version });
432
+ console.log('[webauto] Setup complete!');
433
+ return;
434
+ }
435
+
294
436
  // Install deps if needed
295
437
  if (!checkDesktopConsoleDeps()) {
296
438
  console.log('[webauto] Installing desktop-console dependencies...');
297
- await runInDir(appDir, npmBin(), ['install']);
439
+ const npm = npmRunner();
440
+ await runInDir(appDir, npm.cmd, [...npm.prefix, 'install']);
298
441
  }
299
442
 
300
443
  // Build if needed
301
444
  if (!checkDesktopConsoleBuilt()) {
302
445
  console.log('[webauto] Building desktop-console...');
303
- await runInDir(appDir, npmBin(), ['run', 'build']);
446
+ const npm = npmRunner();
447
+ await runInDir(appDir, npm.cmd, [...npm.prefix, 'run', 'build']);
304
448
  }
305
449
 
306
450
  // Mark as initialized
@@ -309,7 +453,7 @@ async function ensureDepsAndBuild() {
309
453
  console.log('[webauto] Setup complete!');
310
454
  }
311
455
 
312
- async function uiConsole({ build, install, checkOnly }) {
456
+ async function uiConsole({ build, install, checkOnly, noDaemon }) {
313
457
  const okServices = checkServicesBuilt();
314
458
  const okDeps = checkDesktopConsoleDeps();
315
459
  const okUiBuilt = checkDesktopConsoleBuilt();
@@ -332,13 +476,14 @@ async function uiConsole({ build, install, checkOnly }) {
332
476
  }
333
477
  } else {
334
478
  // Local dev mode - require explicit build
335
- if (!okServices) {
336
- if (!build) {
337
- console.error('❌ missing dist/ (services/modules). Run: npm run build:services');
338
- process.exit(2);
479
+ if (!okServices) {
480
+ if (!build) {
481
+ console.error('❌ missing dist/ (services/modules). Run: npm run build:services');
482
+ process.exit(2);
483
+ }
484
+ const npm = npmRunner();
485
+ await run(npm.cmd, [...npm.prefix, 'run', 'build:services']);
339
486
  }
340
- await run(npmBin(), ['run', 'build:services']);
341
- }
342
487
  }
343
488
 
344
489
  if (!okDeps) {
@@ -349,7 +494,8 @@ async function uiConsole({ build, install, checkOnly }) {
349
494
  process.exit(2);
350
495
  }
351
496
  if (!isGlobalInstall()) {
352
- await runInDir(path.join(ROOT, 'apps', 'desktop-console'), npmBin(), ['install']);
497
+ const npm = npmRunner();
498
+ await runInDir(path.join(ROOT, 'apps', 'desktop-console'), npm.cmd, [...npm.prefix, 'install']);
353
499
  }
354
500
  }
355
501
 
@@ -358,16 +504,20 @@ async function uiConsole({ build, install, checkOnly }) {
358
504
  console.error('❌ missing apps/desktop-console/dist. Run: npm --prefix apps/desktop-console run build');
359
505
  process.exit(2);
360
506
  }
361
- await runInDir(path.join(ROOT, 'apps', 'desktop-console'), npmBin(), ['run', 'build']);
507
+ const npm = npmRunner();
508
+ await runInDir(path.join(ROOT, 'apps', 'desktop-console'), npm.cmd, [...npm.prefix, 'run', 'build']);
362
509
  }
363
510
 
364
- await runInDir(path.join(ROOT, 'apps', 'desktop-console'), npmBin(), ['start']);
511
+ const uiScript = uiConsoleScriptPath();
512
+ const uiArgs = [];
513
+ if (noDaemon) uiArgs.push('--no-daemon');
514
+ await run(process.execPath, [uiScript, ...uiArgs]);
365
515
  }
366
516
 
367
517
  async function main() {
368
518
  const rawArgv = process.argv.slice(2);
369
519
  const args = minimist(process.argv.slice(2), {
370
- boolean: ['help', 'build', 'install', 'check', 'full', 'link'],
520
+ boolean: ['help', 'build', 'install', 'check', 'full', 'link', 'skip-tests', 'skip-pack', 'no-daemon'],
371
521
  alias: { h: 'help' },
372
522
  });
373
523
 
@@ -379,7 +529,21 @@ async function main() {
379
529
  printAccountHelp();
380
530
  return;
381
531
  }
382
- if (cmd === 'ui' && sub === 'console') {
532
+ if (cmd === 'weibo') {
533
+ const script = path.join(ROOT, 'apps', 'webauto', 'entry', 'weibo-unified.mjs');
534
+ await run(process.execPath, [script, ...rawArgv.slice(1)]);
535
+ return;
536
+ }
537
+
538
+ if (cmd === 'schedule') {
539
+ printScheduleHelp();
540
+ return;
541
+ }
542
+ if (cmd === 'deps') {
543
+ printDepsHelp();
544
+ return;
545
+ }
546
+ if (cmd === 'ui') {
383
547
  printUiConsoleHelp();
384
548
  return;
385
549
  }
@@ -392,28 +556,50 @@ async function main() {
392
556
  }
393
557
 
394
558
  if (!cmd) {
395
- printMainHelp();
559
+ await uiConsole({
560
+ build: false,
561
+ install: false,
562
+ checkOnly: false,
563
+ noDaemon: args['no-daemon'] === true,
564
+ });
396
565
  return;
397
566
  }
398
567
 
399
568
  // build:dev - local development mode
400
569
  if (cmd === 'build:dev') {
401
570
  console.log('[webauto] Running local dev setup...');
402
- await run(npmBin(), ['run', 'build:services']);
403
- await runInDir(path.join(ROOT, 'apps', 'desktop-console'), npmBin(), ['install']);
404
- await runInDir(path.join(ROOT, 'apps', 'desktop-console'), npmBin(), ['run', 'build']);
571
+ const npm = npmRunner();
572
+ await run(npm.cmd, [...npm.prefix, 'run', 'build:services']);
573
+ await runInDir(path.join(ROOT, 'apps', 'desktop-console'), npm.cmd, [...npm.prefix, 'install']);
574
+ await runInDir(path.join(ROOT, 'apps', 'desktop-console'), npm.cmd, [...npm.prefix, 'run', 'build']);
405
575
  console.log('[webauto] Dev setup complete');
406
576
  return;
407
577
  }
408
578
 
409
579
  // build:release - prepare for npm publish
410
580
  if (cmd === 'build:release') {
411
- console.log('[webauto] Building release version...');
412
- await run(npmBin(), ['run', 'build:services']);
581
+ const skipTests = args['skip-tests'] === true;
582
+ const skipPack = args['skip-pack'] === true;
583
+ console.log('[webauto] Running release gate...');
584
+ const npm = npmRunner();
585
+ await run(npm.cmd, [...npm.prefix, 'run', 'prebuild']);
586
+ if (!skipTests) {
587
+ await run(npm.cmd, [...npm.prefix, 'run', 'test:ci']);
588
+ await run(npm.cmd, [...npm.prefix, 'run', 'coverage:ci']);
589
+ } else {
590
+ console.log('[webauto] Skipping tests (--skip-tests)');
591
+ }
592
+ await run(npm.cmd, [...npm.prefix, 'run', 'build:services']);
593
+ await run(npm.cmd, [...npm.prefix, '--prefix', 'apps/desktop-console', 'run', 'build']);
594
+ if (!skipPack) {
595
+ await run(npm.cmd, [...npm.prefix, 'pack', '--dry-run']);
596
+ } else {
597
+ console.log('[webauto] Skipping npm pack validation (--skip-pack)');
598
+ }
413
599
  // Clean up state for fresh install
414
600
  saveState({ initialized: false, version: null });
415
- console.log('[webauto] Release build complete');
416
- console.log('[webauto] Ready to publish');
601
+ console.log('[webauto] Release gate complete');
602
+ console.log('[webauto] Ready to publish (npm publish --access public)');
417
603
  return;
418
604
  }
419
605
 
@@ -422,13 +608,20 @@ async function main() {
422
608
  build: args.build === true,
423
609
  install: args.install === true,
424
610
  checkOnly: args.check === true,
611
+ noDaemon: args['no-daemon'] === true,
425
612
  });
426
613
  return;
427
614
  }
428
615
 
616
+ if (cmd === 'ui' && sub === 'cli') {
617
+ const script = path.join(ROOT, 'apps', 'desktop-console', 'entry', 'ui-cli.mjs');
618
+ await run(process.execPath, [script, ...rawArgv.slice(2)]);
619
+ return;
620
+ }
429
621
 
430
- // Delegate to ui-console.mjs for test scenarios
622
+ // Legacy: keep compatibility for historical `ui test` usage.
431
623
  if (cmd === 'ui' && sub === 'test') {
624
+ console.warn('[webauto] `ui test` 已废弃,建议改用 `webauto ui cli ...`。');
432
625
  const uiConsoleScript = path.join(ROOT, 'apps', 'desktop-console', 'entry', 'ui-console.mjs');
433
626
  await run(process.execPath, [uiConsoleScript, ...rawArgv.slice(1)]);
434
627
  return;
@@ -439,6 +632,60 @@ async function main() {
439
632
  return;
440
633
  }
441
634
 
635
+ if (cmd === 'weibo') {
636
+ const script = path.join(ROOT, 'apps', 'webauto', 'entry', 'weibo-unified.mjs');
637
+ await run(process.execPath, [script, ...rawArgv.slice(1)]);
638
+ return;
639
+ }
640
+
641
+ if (cmd === 'schedule') {
642
+ const script = path.join(ROOT, 'apps', 'webauto', 'entry', 'schedule.mjs');
643
+ await run(process.execPath, [script, ...rawArgv.slice(1)]);
644
+ return;
645
+ }
646
+
647
+ if (cmd === 'deps') {
648
+ if (!sub || sub === 'help') {
649
+ printDepsHelp();
650
+ return;
651
+ }
652
+ const script = path.join(ROOT, 'apps', 'webauto', 'entry', 'xhs-install.mjs');
653
+ const passthrough = rawArgv.slice(2);
654
+ const hasSelection = passthrough.some((item) => (
655
+ item === '--browser'
656
+ || item === '--geoip'
657
+ || item === '--all'
658
+ || item === '--download-browser'
659
+ || item === '--download-geoip'
660
+ ));
661
+ const disableEnsureBackend = passthrough.includes('--no-ensure-backend');
662
+ const modeArgs = [];
663
+ if (sub === 'check') {
664
+ // keep default mode from xhs-install (check).
665
+ } else if (sub === 'auto') {
666
+ modeArgs.push('--auto');
667
+ if (!hasSelection) modeArgs.push('--all');
668
+ } else if (sub === 'install') {
669
+ modeArgs.push('--install');
670
+ if (!hasSelection) modeArgs.push('--all');
671
+ if (!disableEnsureBackend) modeArgs.push('--ensure-backend');
672
+ } else if (sub === 'uninstall' || sub === 'remove') {
673
+ modeArgs.push('--uninstall');
674
+ if (!hasSelection) modeArgs.push('--all');
675
+ } else if (sub === 'reinstall') {
676
+ modeArgs.push('--reinstall');
677
+ if (!hasSelection) modeArgs.push('--all');
678
+ if (!disableEnsureBackend) modeArgs.push('--ensure-backend');
679
+ } else {
680
+ console.error(`❌ 未知 deps 子命令: ${sub}`);
681
+ printDepsHelp();
682
+ process.exit(2);
683
+ }
684
+ const forwarded = passthrough.filter((item) => item !== '--no-ensure-backend');
685
+ await run(process.execPath, [script, ...modeArgs, ...forwarded]);
686
+ return;
687
+ }
688
+
442
689
  if (cmd === 'xhs') {
443
690
  if (!sub || sub === 'help') {
444
691
  printXhsHelp();
@@ -270,9 +270,29 @@ async function handleCommand(payload, manager, wsServer, options = {}) {
270
270
  ...(args.ownerPid ? { ownerPid: args.ownerPid } : {}),
271
271
  };
272
272
  const res = await manager.createSession(opts);
273
+ const session = manager.getSession(opts.profileId);
274
+ if (!session) {
275
+ throw new Error(`session for profile ${opts.profileId} not started`);
276
+ }
277
+ let recording = null;
278
+ if (args.record === true || args.recording === true) {
279
+ recording = await session.startRecording({
280
+ name: args.recordName || args.recordingName,
281
+ outputPath: args.recordOutput || args.recordingOutput || args.recordOutputPath,
282
+ overlay: typeof args.recordOverlay === 'boolean' ? args.recordOverlay : undefined,
283
+ });
284
+ }
273
285
  options.onSessionStart?.();
274
286
  broadcast('browser:started', { profileId: opts.profileId, sessionId: res.sessionId });
275
- return { ok: true, body: { ok: true, sessionId: res.sessionId, profileId: opts.profileId } };
287
+ return {
288
+ ok: true,
289
+ body: {
290
+ ok: true,
291
+ sessionId: res.sessionId,
292
+ profileId: opts.profileId,
293
+ ...(recording ? { recording } : {}),
294
+ },
295
+ };
276
296
  }
277
297
  case 'goto': {
278
298
  const profileId = args.profileId || 'default';
@@ -324,6 +344,34 @@ async function handleCommand(payload, manager, wsServer, options = {}) {
324
344
  case 'getStatus': {
325
345
  return { ok: true, body: { ok: true, sessions: manager.listSessions() } };
326
346
  }
347
+ case 'record:start': {
348
+ const profileId = args.profileId || 'default';
349
+ const session = manager.getSession(profileId);
350
+ if (!session)
351
+ throw new Error(`session for profile ${profileId} not started`);
352
+ const recording = await session.startRecording({
353
+ name: args.name || args.recordName,
354
+ outputPath: args.outputPath || args.output || args.recordOutput,
355
+ overlay: typeof args.overlay === 'boolean' ? args.overlay : undefined,
356
+ });
357
+ return { ok: true, body: { ok: true, profileId, recording } };
358
+ }
359
+ case 'record:stop': {
360
+ const profileId = args.profileId || 'default';
361
+ const session = manager.getSession(profileId);
362
+ if (!session)
363
+ throw new Error(`session for profile ${profileId} not started`);
364
+ const recording = await session.stopRecording({ reason: String(args.reason || 'manual') });
365
+ return { ok: true, body: { ok: true, profileId, recording } };
366
+ }
367
+ case 'record:status': {
368
+ const profileId = args.profileId || 'default';
369
+ const session = manager.getSession(profileId);
370
+ if (!session)
371
+ throw new Error(`session for profile ${profileId} not started`);
372
+ const recording = session.getRecordingStatus();
373
+ return { ok: true, body: { ok: true, profileId, recording } };
374
+ }
327
375
  case 'system:display': {
328
376
  const metrics = getDisplayMetrics();
329
377
  return { ok: true, body: { ok: true, metrics: metrics || null } };