@optima-chat/browser-cli 0.5.6 → 0.5.7

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.
@@ -30,17 +30,13 @@ owner_repo: Optima-Chat/optima-browser-use
30
30
 
31
31
  脚本执行零 token 消耗,比手动操作快 10 倍以上。
32
32
 
33
- ## 浏览器模式
33
+ ## 前提条件:Desktop 桌面应用
34
34
 
35
- 系统支持三种浏览器模式,自动选择最优方案:
35
+ **Browser Skill 需要用户安装 Optima Browser Operator 桌面应用。** 所有浏览器操作都通过 Desktop app 控制用户本地的 Chrome 或紫鸟浏览器。
36
36
 
37
- | 模式 | 触发条件 | 说明 |
38
- |------|----------|------|
39
- | **Desktop + 紫鸟** | 用户安装了 Desktop app 且配置了紫鸟 | 通过紫鸟反指纹浏览器操作,保留多店铺登录态 |
40
- | **Desktop + Chrome** | 用户安装了 Desktop app | 通过用户本地 Chrome 操作 |
41
- | **Cloud** | 无 Desktop app | 后端 headless Chromium,无登录态 |
37
+ 如果 `browser-cli launch` 返回 `desktop_not_connected` 错误,提示用户:
42
38
 
43
- **自动路由**:默认 `browser-cli launch` 会自动选择。如果用户安装了 Optima Browser Operator 桌面应用并在线,自动走 Desktop 模式。
39
+ > "需要安装 Optima Browser Operator 桌面应用才能使用浏览器功能。下载地址: https://github.com/Optima-Chat/optima-browser-use/releases"
44
40
 
45
41
  ### 紫鸟浏览器(跨境电商多店铺管理)
46
42
 
@@ -67,7 +63,7 @@ browser-cli launch --connector ziniao --ziniao-profile 27774259938707 --url http
67
63
  **重要**:
68
64
  - 用户说"迪士尼店铺"、"林总店铺"等 → 先 `ziniao profiles` 查列表,按名称模糊匹配找到 profile_id
69
65
  - 用户说"打开紫鸟"但没指定店铺 → 先列出 profiles 让用户选
70
- - 紫鸟需要 Desktop app 在线 + 紫鸟 WebDriver 模式已启动
66
+ - 紫鸟需要 Desktop app 在线(紫鸟 WebDriver 会按需自动启动)
71
67
 
72
68
  ## 命令
73
69
 
@@ -225,22 +221,16 @@ browser-cli close
225
221
  /mnt/efs/{userId}/images/... → 自动转换 ✓
226
222
  ```
227
223
 
228
- ## 需要用户登录态的任务
224
+ ## Desktop 桌面应用未连接时
229
225
 
230
- 当用户要求操作需要登录的平台(TikTok Shop、小红书、Instagram 等),需要用户的真实浏览器(有登录态)。
226
+ 如果 `browser-cli launch` 返回错误,提示用户安装 Desktop app:
231
227
 
232
- **推荐方案:Optima Browser Operator 桌面应用**
233
-
234
- 1. 用户下载安装桌面应用(Mac .dmg / Windows .exe):https://github.com/Optima-Chat/optima-browser-use/releases
228
+ 1. 下载安装(Mac .dmg / Windows .exe):https://github.com/Optima-Chat/optima-browser-use/releases
235
229
  2. 首次启动自动打开浏览器登录授权
236
- 3. 授权后自动连接,后续 `browser-cli launch` 自动走 Desktop 模式
230
+ 3. 授权后自动连接
237
231
 
238
232
  **跨境电商用户(多店铺)**:推荐安装紫鸟浏览器 + Desktop app,可以按店铺 profile 分别操作,每个店铺独立登录态。
239
233
 
240
- **备选方案:Chrome 扩展**
241
-
242
- 安装 Optima Browser Operator Chrome 扩展,直接用 Chrome 已登录的账号操作。
243
-
244
234
  ## 注意事项
245
235
 
246
236
  - **脚本优先**:每次操作前先 `browser-cli scripts`,有脚本就用脚本
@@ -248,6 +238,5 @@ browser-cli close
248
238
  - **避免不必要的截图**:截图消耗 token,日常导航用 DOM 输出即可
249
239
  - **5 分钟超时**:无操作 5 分钟后会话自动关闭
250
240
  - **务必关闭**:操作完成后运行 `browser-cli close` 释放资源
251
- - **login_required 处理**:如果 runscript 返回 `login_required` 错误,说明该平台未登录。如果用户已安装 Extension 且 Extension 已连接,用户的 Chrome 通常已经登录了——让用户在自己的 Chrome 里手动登录该平台,然后重新 `runscript`。如果没有 Extension(走 Chromium),用 `browser-cli launch --url <平台URL>` 引导用户登录
241
+ - **login_required 处理**:如果 runscript 返回 `login_required` 错误,说明该平台未登录。让用户在自己的浏览器里手动登录该平台,然后重新 `runscript`
252
242
  - **Fallback 后更新脚本**:如果脚本频繁失败,重新生成并 submit-script 覆盖
253
- - **Extension 模式**:标记了 `REQUIRES_USER_SESSION=True` 的脚本会自动使用用户的真实 Chrome(通过 Optima Browser Operator 扩展),未标记的脚本走 Chromium。这由后端自动判断,无需手动指定
package/dist/index.js CHANGED
@@ -196,53 +196,38 @@ var BrowserAPI = class {
196
196
  async getStatus(sessionId) {
197
197
  return request(`/api/sessions/${sessionId}/status`);
198
198
  }
199
- async navigate(sessionId, url) {
200
- return request(`/api/sessions/${sessionId}/navigate`, {
199
+ /** Execute an action then fetch DOM state separately.
200
+ * Decoupled to prevent EventBus overflow on remote CDP tunnels. */
201
+ async actThenState(sessionId, path, body, timeout) {
202
+ await request(`/api/sessions/${sessionId}/${path}`, {
201
203
  method: "POST",
202
- body: JSON.stringify({ url })
204
+ body: JSON.stringify(body)
203
205
  });
206
+ return this.getState(sessionId);
207
+ }
208
+ async navigate(sessionId, url) {
209
+ return this.actThenState(sessionId, "navigate", { url });
204
210
  }
205
211
  async back(sessionId) {
206
- return request(`/api/sessions/${sessionId}/back`, {
207
- method: "POST",
208
- body: JSON.stringify({})
209
- });
212
+ return this.actThenState(sessionId, "back", {});
210
213
  }
211
214
  async refresh(sessionId) {
212
- return request(`/api/sessions/${sessionId}/refresh`, {
213
- method: "POST",
214
- body: JSON.stringify({})
215
- });
215
+ return this.actThenState(sessionId, "refresh", {});
216
216
  }
217
217
  async click(sessionId, index) {
218
- return request(`/api/sessions/${sessionId}/click`, {
219
- method: "POST",
220
- body: JSON.stringify({ index })
221
- });
218
+ return this.actThenState(sessionId, "click", { index });
222
219
  }
223
220
  async input(sessionId, index, text, clear = true) {
224
- return request(`/api/sessions/${sessionId}/input`, {
225
- method: "POST",
226
- body: JSON.stringify({ index, text, clear })
227
- });
221
+ return this.actThenState(sessionId, "input", { index, text, clear });
228
222
  }
229
223
  async scroll(sessionId, down, pages = 1) {
230
- return request(`/api/sessions/${sessionId}/scroll`, {
231
- method: "POST",
232
- body: JSON.stringify({ down, pages })
233
- });
224
+ return this.actThenState(sessionId, "scroll", { down, pages });
234
225
  }
235
226
  async keys(sessionId, keys) {
236
- return request(`/api/sessions/${sessionId}/keys`, {
237
- method: "POST",
238
- body: JSON.stringify({ keys })
239
- });
227
+ return this.actThenState(sessionId, "keys", { keys });
240
228
  }
241
229
  async select(sessionId, index, text) {
242
- return request(`/api/sessions/${sessionId}/select`, {
243
- method: "POST",
244
- body: JSON.stringify({ index, text })
245
- });
230
+ return this.actThenState(sessionId, "select", { index, text });
246
231
  }
247
232
  async getState(sessionId) {
248
233
  return request(`/api/sessions/${sessionId}/state`);
@@ -266,22 +251,21 @@ var BrowserAPI = class {
266
251
  return request(`/api/sessions/${sessionId}/tabs`);
267
252
  }
268
253
  async switchTab(sessionId, tabId) {
269
- return request(`/api/sessions/${sessionId}/switch`, {
270
- method: "POST",
271
- body: JSON.stringify({ tab_id: tabId })
272
- });
254
+ return this.actThenState(sessionId, "switch", { tab_id: tabId });
273
255
  }
274
256
  async closeTab(sessionId, tabId) {
275
- return request(
257
+ await request(
276
258
  `/api/sessions/${sessionId}/tabs/${tabId}`,
277
259
  { method: "DELETE" }
278
260
  );
261
+ return this.getState(sessionId);
279
262
  }
280
263
  async uploadFiles(sessionId, index, filePaths) {
281
- return request(`/api/sessions/${sessionId}/upload`, {
264
+ await request(`/api/sessions/${sessionId}/upload`, {
282
265
  method: "POST",
283
266
  body: JSON.stringify({ index, file_paths: filePaths })
284
267
  });
268
+ return this.getState(sessionId);
285
269
  }
286
270
  // Script methods
287
271
  async submitScript(name, code) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optima-chat/browser-cli",
3
- "version": "0.5.6",
3
+ "version": "0.5.7",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {