@xbrowser/cli 1.0.6 → 1.0.8
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.
- package/README.md +23 -18
- package/dist/{browser-X7OVRKJH.js → browser-6QN42A4K.js} +2 -2
- package/dist/{browser-U4VWPTS2.js → browser-AN6MKGOD.js} +1 -1
- package/dist/{browser-AXCKBSWS.js → browser-MUPES4UY.js} +2 -2
- package/dist/{cdp-driver-CWNZVWHX.js → cdp-driver-E4I3AEJK.js} +4 -0
- package/dist/{cdp-driver-ZAVN7GRB.js → cdp-driver-LKNM6OQI.js} +1 -1
- package/dist/{chunk-5QAYN5EZ.js → chunk-EUHVZVVL.js} +1 -1
- package/dist/{chunk-7POCCXIB.js → chunk-HRTXMFW4.js} +4 -0
- package/dist/{chunk-SEFIJY2M.js → chunk-IX4JY6OO.js} +4 -0
- package/dist/{chunk-MXG2H3HJ.js → chunk-JUNEBEGF.js} +1 -1
- package/dist/cli.js +100 -46
- package/dist/daemon-main.js +5 -4
- package/dist/index.js +101 -47
- package/dist/{session-replayer-GCGY6KFK.js → session-replayer-YWMSSZWC.js} +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# xbrowser
|
|
2
2
|
|
|
3
|
-
> **Browser automation CLI** for web scraping, headless browsing, SEO analysis, and AI agent workflows. 49 commands,
|
|
3
|
+
> **Browser automation CLI** for web scraping, headless browsing, SEO analysis, and AI agent workflows. 49 commands, 20+ plugins. A command-line alternative to Playwright, Puppeteer, and Selenium — **no code required**.
|
|
4
4
|
|
|
5
5
|
[](https://github.com/dyyz1993/xbrowser/actions)
|
|
6
6
|
[](https://codecov.io/gh/dyyz1993/xbrowser)
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
- **命令链** — 用 `&&`、`,`、`+`、`->`、`;` 串联多个命令,一行搞定复杂流程
|
|
14
14
|
- **管道 & Heredoc** — 支持 stdin 管道和 heredoc 批量执行
|
|
15
15
|
- **录制 / 回放** — 录制浏览器操作为 YAML,随时回放,可转换为 JS/Python/Bash 脚本
|
|
16
|
-
- **插件系统** — 基于 `@dyyz1993/xcli-core`,用 TypeScript
|
|
16
|
+
- **插件系统** — 基于 `@dyyz1993/xcli-core`,用 TypeScript 编写站点插件。快速开始:`xbrowser create my-plugin --template static`
|
|
17
17
|
- **CDP 连接** — 连接已运行的 Chrome/Chromium,无需重新启动浏览器
|
|
18
18
|
- **会话管理** — 多会话并行,独立上下文
|
|
19
19
|
- **Daemon 模式** — 后台常驻,快速响应
|
|
@@ -50,8 +50,10 @@ xbrowser "goto https://example.com && wait .content && text --selector .content"
|
|
|
50
50
|
|
|
51
51
|
**SEO & Backlink Automation**
|
|
52
52
|
```bash
|
|
53
|
-
#
|
|
54
|
-
xbrowser publish --
|
|
53
|
+
# Publish articles to SEO platforms via site plugins
|
|
54
|
+
xbrowser devto publish --file article.md
|
|
55
|
+
xbrowser juejin publish --file article.md
|
|
56
|
+
# (Each platform has its own plugin — run `xbrowser plugin list` to see available)
|
|
55
57
|
```
|
|
56
58
|
|
|
57
59
|
## 快速开始
|
|
@@ -256,7 +258,7 @@ xbrowser --cdp auto "goto https://example.com , title"
|
|
|
256
258
|
| `html --selector "#main"` | 获取指定元素 HTML | `xbrowser html --selector "#main"` |
|
|
257
259
|
| `text` | 获取页面文本 | `xbrowser text` |
|
|
258
260
|
| `text --selector "#article"` | 获取指定元素文本 | `xbrowser text --selector "#article"` |
|
|
259
|
-
| `
|
|
261
|
+
| `eval "expression"` | 执行 JS 获取元素属性 | `xbrowser eval "document.querySelector('#link').href"` |
|
|
260
262
|
|
|
261
263
|
### 截图与快照
|
|
262
264
|
|
|
@@ -282,20 +284,20 @@ xbrowser --cdp auto "goto https://example.com , title"
|
|
|
282
284
|
|------|------|------|
|
|
283
285
|
| `eval <expression>` | 执行 JS 表达式 | `xbrowser eval "document.title"` |
|
|
284
286
|
| `eval "1 + 2"` | 计算表达式 | `xbrowser eval "1 + 2"` |
|
|
285
|
-
| `
|
|
287
|
+
| `eval "(a, b) => a + b" --args 1 2` | 执行带参数的函数 | `xbrowser eval "(a, b) => a + b" --args 1 2` |
|
|
286
288
|
|
|
287
289
|
### 存储
|
|
288
290
|
|
|
289
291
|
| 命令 | 说明 | 示例 |
|
|
290
292
|
|------|------|------|
|
|
291
|
-
| `
|
|
292
|
-
| `
|
|
293
|
-
| `
|
|
294
|
-
| `
|
|
295
|
-
| `
|
|
296
|
-
| `
|
|
297
|
-
| `
|
|
298
|
-
| `
|
|
293
|
+
| `get-cookies` | 获取所有 Cookie | `xbrowser get-cookies` |
|
|
294
|
+
| `set-cookie <name> <value>` | 设置 Cookie | `xbrowser set-cookie session abc123` |
|
|
295
|
+
| `set-cookie <name> <value> --domain .example.com` | 指定域名 | `xbrowser set-cookie session abc123 --domain .example.com` |
|
|
296
|
+
| `clear-cookies` | 清除所有 Cookie | `xbrowser clear-cookies` |
|
|
297
|
+
| `get-local-storage` | 获取所有 localStorage | `xbrowser get-local-storage` |
|
|
298
|
+
| `get-local-storage --key token` | 获取指定 key | `xbrowser get-local-storage --key token` |
|
|
299
|
+
| `set-local-storage <key> <value>` | 设置 localStorage | `xbrowser set-local-storage token "abc"` |
|
|
300
|
+
| `clear-local-storage` | 清除 localStorage | `xbrowser clear-local-storage` |
|
|
299
301
|
|
|
300
302
|
### 帧操作
|
|
301
303
|
|
|
@@ -309,8 +311,8 @@ xbrowser --cdp auto "goto https://example.com , title"
|
|
|
309
311
|
|
|
310
312
|
| 命令 | 说明 | 示例 |
|
|
311
313
|
|------|------|------|
|
|
312
|
-
| `
|
|
313
|
-
| `
|
|
314
|
+
| `set-viewport <width> <height>` | 设置视口大小 | `xbrowser set-viewport 1920 1080` |
|
|
315
|
+
| `set-viewport 375 812 --isMobile true` | 移动设备模式 | `xbrowser set-viewport 375 812 --isMobile true` |
|
|
314
316
|
|
|
315
317
|
### 配置管理
|
|
316
318
|
|
|
@@ -416,7 +418,10 @@ xbrowser create my-plugin --template static --force
|
|
|
416
418
|
| `;` | 分割管线(前一个完成后开始下一个) | `goto https://example.com ; goto https://other.com` |
|
|
417
419
|
| `\|\|` | 前一步成功则跳过后续 | `goto https://example.com \|\| goto https://fallback.com` |
|
|
418
420
|
|
|
419
|
-
|
|
421
|
+
**注意**:
|
|
422
|
+
- 命令链中如果包含特殊字符(如 `#`、`>`),需要用引号包裹整个命令链或对单个参数加引号。
|
|
423
|
+
- `->` 和 `+` 分隔符要求两边有空格(`goto url -> title` ✅,`goto url->title` ❌)。
|
|
424
|
+
- `,` 和 `;` 不要求空格。
|
|
420
425
|
|
|
421
426
|
```bash
|
|
422
427
|
# 正确 — 整体引号
|
|
@@ -440,7 +445,7 @@ project > browser > page > element
|
|
|
440
445
|
| Scope | 说明 | 需要的条件 | 典型命令 |
|
|
441
446
|
|-------|------|------------|----------|
|
|
442
447
|
| **project** | 项目级别 | 无 | config, daemon, plugin |
|
|
443
|
-
| **browser** | 浏览器级别 | 浏览器实例 |
|
|
448
|
+
| **browser** | 浏览器级别 | 浏览器实例 | set-viewport, session |
|
|
444
449
|
| **page** | 页面级别 | 活跃页面 | goto, wait, scroll, screenshot |
|
|
445
450
|
| **element** | 元素级别 | 页面中的元素 | click, fill, type, hover |
|
|
446
451
|
|
|
@@ -20,8 +20,8 @@ import {
|
|
|
20
20
|
saveSessionDiskMeta,
|
|
21
21
|
setActivePage,
|
|
22
22
|
touchSession
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import "./chunk-
|
|
23
|
+
} from "./chunk-EUHVZVVL.js";
|
|
24
|
+
import "./chunk-IX4JY6OO.js";
|
|
25
25
|
import "./chunk-TNEN6VQ2.js";
|
|
26
26
|
import "./chunk-GDKLH7ZY.js";
|
|
27
27
|
import "./chunk-ABXMBNQ6.js";
|
|
@@ -20,8 +20,8 @@ import {
|
|
|
20
20
|
saveSessionDiskMeta,
|
|
21
21
|
setActivePage,
|
|
22
22
|
touchSession
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import "./chunk-
|
|
23
|
+
} from "./chunk-JUNEBEGF.js";
|
|
24
|
+
import "./chunk-IX4JY6OO.js";
|
|
25
25
|
import "./chunk-TNEN6VQ2.js";
|
|
26
26
|
import "./chunk-GDKLH7ZY.js";
|
|
27
27
|
import "./chunk-KFQGP6VL.js";
|
|
@@ -1669,6 +1669,10 @@ Last error: ${lastError.message}` : "";
|
|
|
1669
1669
|
}
|
|
1670
1670
|
};
|
|
1671
1671
|
this._emit("dialog", dialog);
|
|
1672
|
+
setTimeout(() => {
|
|
1673
|
+
this.conn.send("Page.handleJavaScriptDialog", { accept: false }, this.sessionId).catch(() => {
|
|
1674
|
+
});
|
|
1675
|
+
}, 100);
|
|
1672
1676
|
})
|
|
1673
1677
|
);
|
|
1674
1678
|
this._subscriptions.push(
|
|
@@ -1674,6 +1674,10 @@ Last error: ${lastError.message}` : "";
|
|
|
1674
1674
|
}
|
|
1675
1675
|
};
|
|
1676
1676
|
this._emit("dialog", dialog);
|
|
1677
|
+
setTimeout(() => {
|
|
1678
|
+
this.conn.send("Page.handleJavaScriptDialog", { accept: false }, this.sessionId).catch(() => {
|
|
1679
|
+
});
|
|
1680
|
+
}, 100);
|
|
1677
1681
|
})
|
|
1678
1682
|
);
|
|
1679
1683
|
this._subscriptions.push(
|
|
@@ -1668,6 +1668,10 @@ Last error: ${lastError.message}` : "";
|
|
|
1668
1668
|
}
|
|
1669
1669
|
};
|
|
1670
1670
|
this._emit("dialog", dialog);
|
|
1671
|
+
setTimeout(() => {
|
|
1672
|
+
this.conn.send("Page.handleJavaScriptDialog", { accept: false }, this.sessionId).catch(() => {
|
|
1673
|
+
});
|
|
1674
|
+
}, 100);
|
|
1671
1675
|
})
|
|
1672
1676
|
);
|
|
1673
1677
|
this._subscriptions.push(
|
package/dist/cli.js
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
resolveLaunchOpts,
|
|
26
26
|
saveSessionDiskMeta,
|
|
27
27
|
setActivePage
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-HRTXMFW4.js";
|
|
29
29
|
import "./chunk-TNEN6VQ2.js";
|
|
30
30
|
import {
|
|
31
31
|
forwardCommandLog,
|
|
@@ -2131,6 +2131,7 @@ function createTurndown() {
|
|
|
2131
2131
|
return turndown;
|
|
2132
2132
|
}
|
|
2133
2133
|
function postClean(md) {
|
|
2134
|
+
md = md.replace(/<(?:table|div|tbody|thead|tr|td|th|span|colgroup|col)\b[^>]*(?:>[\s\S]{200,}?<\/(?:table|div|tbody|thead|tr|td|th|span|colgroup|col)>)/g, "\n[\u26A0\uFE0F HTML block removed \u2014 complex table/layout not converted to Markdown]\n");
|
|
2134
2135
|
md = md.replace(/\n{3,}/g, "\n\n");
|
|
2135
2136
|
md = md.replace(/!\[[^\]]*\]\(\s*\)/g, "");
|
|
2136
2137
|
md = md.replace(/\[([^\]]*)\]\(\s*\)/g, "$1");
|
|
@@ -6966,7 +6967,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6966
6967
|
}
|
|
6967
6968
|
let targetPageOverride = null;
|
|
6968
6969
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
6969
|
-
const { findTargetPage } = await import("./browser-
|
|
6970
|
+
const { findTargetPage } = await import("./browser-AN6MKGOD.js");
|
|
6970
6971
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
6971
6972
|
if (!targetPageOverride) {
|
|
6972
6973
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -8810,6 +8811,8 @@ var TEMPLATES = {
|
|
|
8810
8811
|
{
|
|
8811
8812
|
path: "index.ts",
|
|
8812
8813
|
content: [
|
|
8814
|
+
`import { z } from 'zod';`,
|
|
8815
|
+
`import { ok } from '@dyyz1993/xcli-core';`,
|
|
8813
8816
|
`import type { XCLIAPI } from '@dyyz1993/xcli-core';`,
|
|
8814
8817
|
``,
|
|
8815
8818
|
`export default function (xcli: XCLIAPI): void {`,
|
|
@@ -8827,7 +8830,7 @@ var TEMPLATES = {
|
|
|
8827
8830
|
` (sel: string) => document.querySelector(sel)?.textContent ?? '',`,
|
|
8828
8831
|
` params.selector || 'body'`,
|
|
8829
8832
|
` );`,
|
|
8830
|
-
` return {
|
|
8833
|
+
` return ok({ text });`,
|
|
8831
8834
|
` },`,
|
|
8832
8835
|
` });`,
|
|
8833
8836
|
`}`
|
|
@@ -8835,14 +8838,21 @@ var TEMPLATES = {
|
|
|
8835
8838
|
},
|
|
8836
8839
|
{
|
|
8837
8840
|
path: "package.json",
|
|
8838
|
-
content:
|
|
8839
|
-
|
|
8840
|
-
"
|
|
8841
|
-
"
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
}
|
|
8845
|
-
`
|
|
8841
|
+
content: [
|
|
8842
|
+
`{`,
|
|
8843
|
+
` "name": "xbrowser-plugin-{{projectName}}",`,
|
|
8844
|
+
` "version": "1.0.0",`,
|
|
8845
|
+
` "main": "index.ts",`,
|
|
8846
|
+
` "type": "module",`,
|
|
8847
|
+
` "dependencies": { "zod": "^3.24.0" },`,
|
|
8848
|
+
` "peerDependencies": { "@dyyz1993/xcli-core": ">=1.0.0" },`,
|
|
8849
|
+
` "xbrowser": {`,
|
|
8850
|
+
` "name": "{{projectName}}",`,
|
|
8851
|
+
` "description": "A static page plugin",`,
|
|
8852
|
+
` "commands": ["scrape"]`,
|
|
8853
|
+
` }`,
|
|
8854
|
+
`}`
|
|
8855
|
+
].join("\n")
|
|
8846
8856
|
}
|
|
8847
8857
|
]
|
|
8848
8858
|
},
|
|
@@ -8853,6 +8863,8 @@ var TEMPLATES = {
|
|
|
8853
8863
|
{
|
|
8854
8864
|
path: "index.ts",
|
|
8855
8865
|
content: [
|
|
8866
|
+
`import { z } from 'zod';`,
|
|
8867
|
+
`import { ok } from '@dyyz1993/xcli-core';`,
|
|
8856
8868
|
`import type { XCLIAPI } from '@dyyz1993/xcli-core';`,
|
|
8857
8869
|
``,
|
|
8858
8870
|
`export default function (xcli: XCLIAPI): void {`,
|
|
@@ -8867,7 +8879,7 @@ var TEMPLATES = {
|
|
|
8867
8879
|
` parameters: z.object({ url: z.string() }),`,
|
|
8868
8880
|
` handler: async (params, ctx) => {`,
|
|
8869
8881
|
` await ctx.page.goto(params.url);`,
|
|
8870
|
-
` return {
|
|
8882
|
+
` return ok({ url: params.url });`,
|
|
8871
8883
|
` },`,
|
|
8872
8884
|
` });`,
|
|
8873
8885
|
``,
|
|
@@ -8882,7 +8894,7 @@ var TEMPLATES = {
|
|
|
8882
8894
|
` case 'fill': await page.fill(params.selector, ''); break;`,
|
|
8883
8895
|
` case 'hover': await page.hover(params.selector); break;`,
|
|
8884
8896
|
` }`,
|
|
8885
|
-
` return {
|
|
8897
|
+
` return ok({ action: params.action, selector: params.selector });`,
|
|
8886
8898
|
` },`,
|
|
8887
8899
|
` });`,
|
|
8888
8900
|
`}`
|
|
@@ -8890,14 +8902,21 @@ var TEMPLATES = {
|
|
|
8890
8902
|
},
|
|
8891
8903
|
{
|
|
8892
8904
|
path: "package.json",
|
|
8893
|
-
content:
|
|
8894
|
-
|
|
8895
|
-
"
|
|
8896
|
-
"
|
|
8897
|
-
|
|
8898
|
-
|
|
8899
|
-
}
|
|
8900
|
-
`
|
|
8905
|
+
content: [
|
|
8906
|
+
`{`,
|
|
8907
|
+
` "name": "xbrowser-plugin-{{projectName}}",`,
|
|
8908
|
+
` "version": "1.0.0",`,
|
|
8909
|
+
` "main": "index.ts",`,
|
|
8910
|
+
` "type": "module",`,
|
|
8911
|
+
` "dependencies": { "zod": "^3.24.0" },`,
|
|
8912
|
+
` "peerDependencies": { "@dyyz1993/xcli-core": ">=1.0.0" },`,
|
|
8913
|
+
` "xbrowser": {`,
|
|
8914
|
+
` "name": "{{projectName}}",`,
|
|
8915
|
+
` "description": "A dynamic page plugin",`,
|
|
8916
|
+
` "commands": ["navigate", "interact"]`,
|
|
8917
|
+
` }`,
|
|
8918
|
+
`}`
|
|
8919
|
+
].join("\n")
|
|
8901
8920
|
}
|
|
8902
8921
|
]
|
|
8903
8922
|
},
|
|
@@ -8908,6 +8927,8 @@ var TEMPLATES = {
|
|
|
8908
8927
|
{
|
|
8909
8928
|
path: "index.ts",
|
|
8910
8929
|
content: [
|
|
8930
|
+
`import { z } from 'zod';`,
|
|
8931
|
+
`import { ok } from '@dyyz1993/xcli-core';`,
|
|
8911
8932
|
`import type { XCLIAPI } from '@dyyz1993/xcli-core';`,
|
|
8912
8933
|
``,
|
|
8913
8934
|
`export default function (xcli: XCLIAPI): void {`,
|
|
@@ -8921,14 +8942,13 @@ var TEMPLATES = {
|
|
|
8921
8942
|
` description: 'Check login status',`,
|
|
8922
8943
|
` scope: 'project',`,
|
|
8923
8944
|
` parameters: z.object({}),`,
|
|
8924
|
-
` handler: async (
|
|
8945
|
+
` handler: async () => {`,
|
|
8925
8946
|
` const loggedIn = await site.isLoggedIn();`,
|
|
8926
|
-
` return {
|
|
8947
|
+
` return ok({ loggedIn });`,
|
|
8927
8948
|
` },`,
|
|
8928
8949
|
` });`,
|
|
8929
8950
|
``,
|
|
8930
8951
|
` site.login(async (ctx) => {`,
|
|
8931
|
-
` console.log('Login handler for {{projectName}}');`,
|
|
8932
8952
|
` await ctx.storage.set('auth_token', 'dummy');`,
|
|
8933
8953
|
` });`,
|
|
8934
8954
|
``,
|
|
@@ -8940,14 +8960,22 @@ var TEMPLATES = {
|
|
|
8940
8960
|
},
|
|
8941
8961
|
{
|
|
8942
8962
|
path: "package.json",
|
|
8943
|
-
content:
|
|
8944
|
-
|
|
8945
|
-
"
|
|
8946
|
-
"
|
|
8947
|
-
|
|
8948
|
-
|
|
8949
|
-
}
|
|
8950
|
-
`
|
|
8963
|
+
content: [
|
|
8964
|
+
`{`,
|
|
8965
|
+
` "name": "xbrowser-plugin-{{projectName}}",`,
|
|
8966
|
+
` "version": "1.0.0",`,
|
|
8967
|
+
` "main": "index.ts",`,
|
|
8968
|
+
` "type": "module",`,
|
|
8969
|
+
` "dependencies": { "zod": "^3.24.0" },`,
|
|
8970
|
+
` "peerDependencies": { "@dyyz1993/xcli-core": ">=1.0.0" },`,
|
|
8971
|
+
` "xbrowser": {`,
|
|
8972
|
+
` "name": "{{projectName}}",`,
|
|
8973
|
+
` "description": "A plugin with login/logout support",`,
|
|
8974
|
+
` "requiresLogin": true,`,
|
|
8975
|
+
` "commands": ["check"]`,
|
|
8976
|
+
` }`,
|
|
8977
|
+
`}`
|
|
8978
|
+
].join("\n")
|
|
8951
8979
|
}
|
|
8952
8980
|
]
|
|
8953
8981
|
},
|
|
@@ -8958,6 +8986,8 @@ var TEMPLATES = {
|
|
|
8958
8986
|
{
|
|
8959
8987
|
path: "index.ts",
|
|
8960
8988
|
content: [
|
|
8989
|
+
`import { z } from 'zod';`,
|
|
8990
|
+
`import { ok } from '@dyyz1993/xcli-core';`,
|
|
8961
8991
|
`import type { XCLIAPI } from '@dyyz1993/xcli-core';`,
|
|
8962
8992
|
``,
|
|
8963
8993
|
`export default function (xcli: XCLIAPI): void {`,
|
|
@@ -8970,9 +9000,9 @@ var TEMPLATES = {
|
|
|
8970
9000
|
` description: 'Fetch data from API',`,
|
|
8971
9001
|
` scope: 'project',`,
|
|
8972
9002
|
` parameters: z.object({ endpoint: z.string(), method: z.enum(['GET', 'POST']).optional() }),`,
|
|
8973
|
-
` handler: async (params
|
|
9003
|
+
` handler: async (params) => {`,
|
|
8974
9004
|
` const method = params.method || 'GET';`,
|
|
8975
|
-
` return {
|
|
9005
|
+
` return ok({ endpoint: params.endpoint, method });`,
|
|
8976
9006
|
` },`,
|
|
8977
9007
|
` });`,
|
|
8978
9008
|
``,
|
|
@@ -8980,8 +9010,8 @@ var TEMPLATES = {
|
|
|
8980
9010
|
` description: 'List available endpoints',`,
|
|
8981
9011
|
` scope: 'project',`,
|
|
8982
9012
|
` parameters: z.object({}),`,
|
|
8983
|
-
` handler: async (
|
|
8984
|
-
` return {
|
|
9013
|
+
` handler: async () => {`,
|
|
9014
|
+
` return ok({ endpoints: ['/api/data', '/api/status'] });`,
|
|
8985
9015
|
` },`,
|
|
8986
9016
|
` });`,
|
|
8987
9017
|
`}`
|
|
@@ -8989,14 +9019,21 @@ var TEMPLATES = {
|
|
|
8989
9019
|
},
|
|
8990
9020
|
{
|
|
8991
9021
|
path: "package.json",
|
|
8992
|
-
content:
|
|
8993
|
-
|
|
8994
|
-
"
|
|
8995
|
-
"
|
|
8996
|
-
|
|
8997
|
-
|
|
8998
|
-
}
|
|
8999
|
-
`
|
|
9022
|
+
content: [
|
|
9023
|
+
`{`,
|
|
9024
|
+
` "name": "xbrowser-plugin-{{projectName}}",`,
|
|
9025
|
+
` "version": "1.0.0",`,
|
|
9026
|
+
` "main": "index.ts",`,
|
|
9027
|
+
` "type": "module",`,
|
|
9028
|
+
` "dependencies": { "zod": "^3.24.0" },`,
|
|
9029
|
+
` "peerDependencies": { "@dyyz1993/xcli-core": ">=1.0.0" },`,
|
|
9030
|
+
` "xbrowser": {`,
|
|
9031
|
+
` "name": "{{projectName}}",`,
|
|
9032
|
+
` "description": "An API integration plugin",`,
|
|
9033
|
+
` "commands": ["fetch", "list-endpoints"]`,
|
|
9034
|
+
` }`,
|
|
9035
|
+
`}`
|
|
9036
|
+
].join("\n")
|
|
9000
9037
|
}
|
|
9001
9038
|
]
|
|
9002
9039
|
}
|
|
@@ -9611,6 +9648,18 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
9611
9648
|
params = { width, height };
|
|
9612
9649
|
break;
|
|
9613
9650
|
}
|
|
9651
|
+
case "mouse": {
|
|
9652
|
+
const action = options.action || args.find((a) => ["move", "click", "dblclick", "down", "up"].includes(a));
|
|
9653
|
+
const actionIdx = action ? args.indexOf(action) : -1;
|
|
9654
|
+
const x = options.x !== void 0 ? Number(options.x) : actionIdx >= 0 && args[actionIdx + 1] ? Number(args[actionIdx + 1]) : void 0;
|
|
9655
|
+
const y = options.y !== void 0 ? Number(options.y) : actionIdx >= 0 && args[actionIdx + 2] ? Number(args[actionIdx + 2]) : void 0;
|
|
9656
|
+
if (!action || x === void 0 || y === void 0) {
|
|
9657
|
+
outputError("Usage: xbrowser mouse <move|click|dblclick> <x> <y>\n xbrowser mouse --action <action> --x <x> --y <y>");
|
|
9658
|
+
}
|
|
9659
|
+
cmdName = "mouse";
|
|
9660
|
+
params = { action, x, y, ...options.button ? { button: options.button } : {} };
|
|
9661
|
+
break;
|
|
9662
|
+
}
|
|
9614
9663
|
case "html":
|
|
9615
9664
|
cmdName = "html";
|
|
9616
9665
|
params = { selector: options.selector || options.s };
|
|
@@ -10147,6 +10196,11 @@ async function handlePlugin(args, options, mode) {
|
|
|
10147
10196
|
case "uninstall": {
|
|
10148
10197
|
const name = subArgs[0];
|
|
10149
10198
|
if (!name) outputError("Usage: xbrowser plugin uninstall <name>");
|
|
10199
|
+
const installed = await installer.list();
|
|
10200
|
+
const exists = installed.some((p) => p.name === name || p.metadata?.name === name);
|
|
10201
|
+
if (!exists) {
|
|
10202
|
+
outputError(`Plugin "${name}" is not installed. Use 'xbrowser plugin list' to see installed plugins.`);
|
|
10203
|
+
}
|
|
10150
10204
|
await installer.uninstall(name);
|
|
10151
10205
|
outputResult({ ok: true, name }, mode);
|
|
10152
10206
|
break;
|
|
@@ -12553,7 +12607,7 @@ async function handleServe(_args, options, mode) {
|
|
|
12553
12607
|
\u{1F310} xbrowser HTTP Server`);
|
|
12554
12608
|
console.log(`
|
|
12555
12609
|
URL: ${output.url}`);
|
|
12556
|
-
console.log(` Auth: ${output.authRequired ? "Enabled (Bearer token)" : "Disabled (dev mode)"}
|
|
12610
|
+
console.log(` Auth: ${output.authRequired ? "Enabled (Bearer token, except /health)" : "Disabled (dev mode)"}
|
|
12557
12611
|
`);
|
|
12558
12612
|
console.log(` Endpoints:`);
|
|
12559
12613
|
for (const [, value] of Object.entries(output.endpoints)) {
|
|
@@ -12673,7 +12727,7 @@ async function main() {
|
|
|
12673
12727
|
const command = process.argv[2];
|
|
12674
12728
|
const isLongRunning = command === "preview" || command === "serve";
|
|
12675
12729
|
if (!isLongRunning) {
|
|
12676
|
-
const { ensureProcessCanExit } = await import("./browser-
|
|
12730
|
+
const { ensureProcessCanExit } = await import("./browser-AN6MKGOD.js");
|
|
12677
12731
|
await ensureProcessCanExit().catch(() => {
|
|
12678
12732
|
});
|
|
12679
12733
|
process.exit(exitCode);
|
package/dist/daemon-main.js
CHANGED
|
@@ -21,8 +21,8 @@ import {
|
|
|
21
21
|
resolveLaunchOpts,
|
|
22
22
|
saveSessionDiskMeta,
|
|
23
23
|
setActivePage
|
|
24
|
-
} from "./chunk-
|
|
25
|
-
import "./chunk-
|
|
24
|
+
} from "./chunk-JUNEBEGF.js";
|
|
25
|
+
import "./chunk-IX4JY6OO.js";
|
|
26
26
|
import "./chunk-TNEN6VQ2.js";
|
|
27
27
|
import {
|
|
28
28
|
getDaemonConfig,
|
|
@@ -2089,6 +2089,7 @@ function createTurndown() {
|
|
|
2089
2089
|
return turndown;
|
|
2090
2090
|
}
|
|
2091
2091
|
function postClean(md) {
|
|
2092
|
+
md = md.replace(/<(?:table|div|tbody|thead|tr|td|th|span|colgroup|col)\b[^>]*(?:>[\s\S]{200,}?<\/(?:table|div|tbody|thead|tr|td|th|span|colgroup|col)>)/g, "\n[\u26A0\uFE0F HTML block removed \u2014 complex table/layout not converted to Markdown]\n");
|
|
2092
2093
|
md = md.replace(/\n{3,}/g, "\n\n");
|
|
2093
2094
|
md = md.replace(/!\[[^\]]*\]\(\s*\)/g, "");
|
|
2094
2095
|
md = md.replace(/\[([^\]]*)\]\(\s*\)/g, "$1");
|
|
@@ -6924,7 +6925,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6924
6925
|
}
|
|
6925
6926
|
let targetPageOverride = null;
|
|
6926
6927
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
6927
|
-
const { findTargetPage } = await import("./browser-
|
|
6928
|
+
const { findTargetPage } = await import("./browser-MUPES4UY.js");
|
|
6928
6929
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
6929
6930
|
if (!targetPageOverride) {
|
|
6930
6931
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -8608,7 +8609,7 @@ function createRPCHandler() {
|
|
|
8608
8609
|
const isNewFormat = Array.isArray(parsed.actions);
|
|
8609
8610
|
if (isNewFormat) {
|
|
8610
8611
|
try {
|
|
8611
|
-
const { SessionReplayer } = await import("./session-replayer-
|
|
8612
|
+
const { SessionReplayer } = await import("./session-replayer-YWMSSZWC.js");
|
|
8612
8613
|
const replayer = new SessionReplayer({
|
|
8613
8614
|
page: session.page,
|
|
8614
8615
|
stepDelay: slowMo * 500,
|
package/dist/index.js
CHANGED
|
@@ -81,8 +81,8 @@ import {
|
|
|
81
81
|
resolveLaunchOpts,
|
|
82
82
|
saveSessionDiskMeta,
|
|
83
83
|
setActivePage
|
|
84
|
-
} from "./chunk-
|
|
85
|
-
import "./chunk-
|
|
84
|
+
} from "./chunk-EUHVZVVL.js";
|
|
85
|
+
import "./chunk-IX4JY6OO.js";
|
|
86
86
|
import "./chunk-TNEN6VQ2.js";
|
|
87
87
|
import {
|
|
88
88
|
errMsg
|
|
@@ -2171,6 +2171,7 @@ function createTurndown() {
|
|
|
2171
2171
|
return turndown;
|
|
2172
2172
|
}
|
|
2173
2173
|
function postClean(md) {
|
|
2174
|
+
md = md.replace(/<(?:table|div|tbody|thead|tr|td|th|span|colgroup|col)\b[^>]*(?:>[\s\S]{200,}?<\/(?:table|div|tbody|thead|tr|td|th|span|colgroup|col)>)/g, "\n[\u26A0\uFE0F HTML block removed \u2014 complex table/layout not converted to Markdown]\n");
|
|
2174
2175
|
md = md.replace(/\n{3,}/g, "\n\n");
|
|
2175
2176
|
md = md.replace(/!\[[^\]]*\]\(\s*\)/g, "");
|
|
2176
2177
|
md = md.replace(/\[([^\]]*)\]\(\s*\)/g, "$1");
|
|
@@ -7286,7 +7287,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7286
7287
|
}
|
|
7287
7288
|
let targetPageOverride = null;
|
|
7288
7289
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7289
|
-
const { findTargetPage } = await import("./browser-
|
|
7290
|
+
const { findTargetPage } = await import("./browser-6QN42A4K.js");
|
|
7290
7291
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7291
7292
|
if (!targetPageOverride) {
|
|
7292
7293
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -9145,6 +9146,8 @@ var TEMPLATES = {
|
|
|
9145
9146
|
{
|
|
9146
9147
|
path: "index.ts",
|
|
9147
9148
|
content: [
|
|
9149
|
+
`import { z } from 'zod';`,
|
|
9150
|
+
`import { ok } from '@dyyz1993/xcli-core';`,
|
|
9148
9151
|
`import type { XCLIAPI } from '@dyyz1993/xcli-core';`,
|
|
9149
9152
|
``,
|
|
9150
9153
|
`export default function (xcli: XCLIAPI): void {`,
|
|
@@ -9162,7 +9165,7 @@ var TEMPLATES = {
|
|
|
9162
9165
|
` (sel: string) => document.querySelector(sel)?.textContent ?? '',`,
|
|
9163
9166
|
` params.selector || 'body'`,
|
|
9164
9167
|
` );`,
|
|
9165
|
-
` return {
|
|
9168
|
+
` return ok({ text });`,
|
|
9166
9169
|
` },`,
|
|
9167
9170
|
` });`,
|
|
9168
9171
|
`}`
|
|
@@ -9170,14 +9173,21 @@ var TEMPLATES = {
|
|
|
9170
9173
|
},
|
|
9171
9174
|
{
|
|
9172
9175
|
path: "package.json",
|
|
9173
|
-
content:
|
|
9174
|
-
|
|
9175
|
-
"
|
|
9176
|
-
"
|
|
9177
|
-
|
|
9178
|
-
|
|
9179
|
-
}
|
|
9180
|
-
`
|
|
9176
|
+
content: [
|
|
9177
|
+
`{`,
|
|
9178
|
+
` "name": "xbrowser-plugin-{{projectName}}",`,
|
|
9179
|
+
` "version": "1.0.0",`,
|
|
9180
|
+
` "main": "index.ts",`,
|
|
9181
|
+
` "type": "module",`,
|
|
9182
|
+
` "dependencies": { "zod": "^3.24.0" },`,
|
|
9183
|
+
` "peerDependencies": { "@dyyz1993/xcli-core": ">=1.0.0" },`,
|
|
9184
|
+
` "xbrowser": {`,
|
|
9185
|
+
` "name": "{{projectName}}",`,
|
|
9186
|
+
` "description": "A static page plugin",`,
|
|
9187
|
+
` "commands": ["scrape"]`,
|
|
9188
|
+
` }`,
|
|
9189
|
+
`}`
|
|
9190
|
+
].join("\n")
|
|
9181
9191
|
}
|
|
9182
9192
|
]
|
|
9183
9193
|
},
|
|
@@ -9188,6 +9198,8 @@ var TEMPLATES = {
|
|
|
9188
9198
|
{
|
|
9189
9199
|
path: "index.ts",
|
|
9190
9200
|
content: [
|
|
9201
|
+
`import { z } from 'zod';`,
|
|
9202
|
+
`import { ok } from '@dyyz1993/xcli-core';`,
|
|
9191
9203
|
`import type { XCLIAPI } from '@dyyz1993/xcli-core';`,
|
|
9192
9204
|
``,
|
|
9193
9205
|
`export default function (xcli: XCLIAPI): void {`,
|
|
@@ -9202,7 +9214,7 @@ var TEMPLATES = {
|
|
|
9202
9214
|
` parameters: z.object({ url: z.string() }),`,
|
|
9203
9215
|
` handler: async (params, ctx) => {`,
|
|
9204
9216
|
` await ctx.page.goto(params.url);`,
|
|
9205
|
-
` return {
|
|
9217
|
+
` return ok({ url: params.url });`,
|
|
9206
9218
|
` },`,
|
|
9207
9219
|
` });`,
|
|
9208
9220
|
``,
|
|
@@ -9217,7 +9229,7 @@ var TEMPLATES = {
|
|
|
9217
9229
|
` case 'fill': await page.fill(params.selector, ''); break;`,
|
|
9218
9230
|
` case 'hover': await page.hover(params.selector); break;`,
|
|
9219
9231
|
` }`,
|
|
9220
|
-
` return {
|
|
9232
|
+
` return ok({ action: params.action, selector: params.selector });`,
|
|
9221
9233
|
` },`,
|
|
9222
9234
|
` });`,
|
|
9223
9235
|
`}`
|
|
@@ -9225,14 +9237,21 @@ var TEMPLATES = {
|
|
|
9225
9237
|
},
|
|
9226
9238
|
{
|
|
9227
9239
|
path: "package.json",
|
|
9228
|
-
content:
|
|
9229
|
-
|
|
9230
|
-
"
|
|
9231
|
-
"
|
|
9232
|
-
|
|
9233
|
-
|
|
9234
|
-
}
|
|
9235
|
-
`
|
|
9240
|
+
content: [
|
|
9241
|
+
`{`,
|
|
9242
|
+
` "name": "xbrowser-plugin-{{projectName}}",`,
|
|
9243
|
+
` "version": "1.0.0",`,
|
|
9244
|
+
` "main": "index.ts",`,
|
|
9245
|
+
` "type": "module",`,
|
|
9246
|
+
` "dependencies": { "zod": "^3.24.0" },`,
|
|
9247
|
+
` "peerDependencies": { "@dyyz1993/xcli-core": ">=1.0.0" },`,
|
|
9248
|
+
` "xbrowser": {`,
|
|
9249
|
+
` "name": "{{projectName}}",`,
|
|
9250
|
+
` "description": "A dynamic page plugin",`,
|
|
9251
|
+
` "commands": ["navigate", "interact"]`,
|
|
9252
|
+
` }`,
|
|
9253
|
+
`}`
|
|
9254
|
+
].join("\n")
|
|
9236
9255
|
}
|
|
9237
9256
|
]
|
|
9238
9257
|
},
|
|
@@ -9243,6 +9262,8 @@ var TEMPLATES = {
|
|
|
9243
9262
|
{
|
|
9244
9263
|
path: "index.ts",
|
|
9245
9264
|
content: [
|
|
9265
|
+
`import { z } from 'zod';`,
|
|
9266
|
+
`import { ok } from '@dyyz1993/xcli-core';`,
|
|
9246
9267
|
`import type { XCLIAPI } from '@dyyz1993/xcli-core';`,
|
|
9247
9268
|
``,
|
|
9248
9269
|
`export default function (xcli: XCLIAPI): void {`,
|
|
@@ -9256,14 +9277,13 @@ var TEMPLATES = {
|
|
|
9256
9277
|
` description: 'Check login status',`,
|
|
9257
9278
|
` scope: 'project',`,
|
|
9258
9279
|
` parameters: z.object({}),`,
|
|
9259
|
-
` handler: async (
|
|
9280
|
+
` handler: async () => {`,
|
|
9260
9281
|
` const loggedIn = await site.isLoggedIn();`,
|
|
9261
|
-
` return {
|
|
9282
|
+
` return ok({ loggedIn });`,
|
|
9262
9283
|
` },`,
|
|
9263
9284
|
` });`,
|
|
9264
9285
|
``,
|
|
9265
9286
|
` site.login(async (ctx) => {`,
|
|
9266
|
-
` console.log('Login handler for {{projectName}}');`,
|
|
9267
9287
|
` await ctx.storage.set('auth_token', 'dummy');`,
|
|
9268
9288
|
` });`,
|
|
9269
9289
|
``,
|
|
@@ -9275,14 +9295,22 @@ var TEMPLATES = {
|
|
|
9275
9295
|
},
|
|
9276
9296
|
{
|
|
9277
9297
|
path: "package.json",
|
|
9278
|
-
content:
|
|
9279
|
-
|
|
9280
|
-
"
|
|
9281
|
-
"
|
|
9282
|
-
|
|
9283
|
-
|
|
9284
|
-
}
|
|
9285
|
-
`
|
|
9298
|
+
content: [
|
|
9299
|
+
`{`,
|
|
9300
|
+
` "name": "xbrowser-plugin-{{projectName}}",`,
|
|
9301
|
+
` "version": "1.0.0",`,
|
|
9302
|
+
` "main": "index.ts",`,
|
|
9303
|
+
` "type": "module",`,
|
|
9304
|
+
` "dependencies": { "zod": "^3.24.0" },`,
|
|
9305
|
+
` "peerDependencies": { "@dyyz1993/xcli-core": ">=1.0.0" },`,
|
|
9306
|
+
` "xbrowser": {`,
|
|
9307
|
+
` "name": "{{projectName}}",`,
|
|
9308
|
+
` "description": "A plugin with login/logout support",`,
|
|
9309
|
+
` "requiresLogin": true,`,
|
|
9310
|
+
` "commands": ["check"]`,
|
|
9311
|
+
` }`,
|
|
9312
|
+
`}`
|
|
9313
|
+
].join("\n")
|
|
9286
9314
|
}
|
|
9287
9315
|
]
|
|
9288
9316
|
},
|
|
@@ -9293,6 +9321,8 @@ var TEMPLATES = {
|
|
|
9293
9321
|
{
|
|
9294
9322
|
path: "index.ts",
|
|
9295
9323
|
content: [
|
|
9324
|
+
`import { z } from 'zod';`,
|
|
9325
|
+
`import { ok } from '@dyyz1993/xcli-core';`,
|
|
9296
9326
|
`import type { XCLIAPI } from '@dyyz1993/xcli-core';`,
|
|
9297
9327
|
``,
|
|
9298
9328
|
`export default function (xcli: XCLIAPI): void {`,
|
|
@@ -9305,9 +9335,9 @@ var TEMPLATES = {
|
|
|
9305
9335
|
` description: 'Fetch data from API',`,
|
|
9306
9336
|
` scope: 'project',`,
|
|
9307
9337
|
` parameters: z.object({ endpoint: z.string(), method: z.enum(['GET', 'POST']).optional() }),`,
|
|
9308
|
-
` handler: async (params
|
|
9338
|
+
` handler: async (params) => {`,
|
|
9309
9339
|
` const method = params.method || 'GET';`,
|
|
9310
|
-
` return {
|
|
9340
|
+
` return ok({ endpoint: params.endpoint, method });`,
|
|
9311
9341
|
` },`,
|
|
9312
9342
|
` });`,
|
|
9313
9343
|
``,
|
|
@@ -9315,8 +9345,8 @@ var TEMPLATES = {
|
|
|
9315
9345
|
` description: 'List available endpoints',`,
|
|
9316
9346
|
` scope: 'project',`,
|
|
9317
9347
|
` parameters: z.object({}),`,
|
|
9318
|
-
` handler: async (
|
|
9319
|
-
` return {
|
|
9348
|
+
` handler: async () => {`,
|
|
9349
|
+
` return ok({ endpoints: ['/api/data', '/api/status'] });`,
|
|
9320
9350
|
` },`,
|
|
9321
9351
|
` });`,
|
|
9322
9352
|
`}`
|
|
@@ -9324,14 +9354,21 @@ var TEMPLATES = {
|
|
|
9324
9354
|
},
|
|
9325
9355
|
{
|
|
9326
9356
|
path: "package.json",
|
|
9327
|
-
content:
|
|
9328
|
-
|
|
9329
|
-
"
|
|
9330
|
-
"
|
|
9331
|
-
|
|
9332
|
-
|
|
9333
|
-
}
|
|
9334
|
-
`
|
|
9357
|
+
content: [
|
|
9358
|
+
`{`,
|
|
9359
|
+
` "name": "xbrowser-plugin-{{projectName}}",`,
|
|
9360
|
+
` "version": "1.0.0",`,
|
|
9361
|
+
` "main": "index.ts",`,
|
|
9362
|
+
` "type": "module",`,
|
|
9363
|
+
` "dependencies": { "zod": "^3.24.0" },`,
|
|
9364
|
+
` "peerDependencies": { "@dyyz1993/xcli-core": ">=1.0.0" },`,
|
|
9365
|
+
` "xbrowser": {`,
|
|
9366
|
+
` "name": "{{projectName}}",`,
|
|
9367
|
+
` "description": "An API integration plugin",`,
|
|
9368
|
+
` "commands": ["fetch", "list-endpoints"]`,
|
|
9369
|
+
` }`,
|
|
9370
|
+
`}`
|
|
9371
|
+
].join("\n")
|
|
9335
9372
|
}
|
|
9336
9373
|
]
|
|
9337
9374
|
}
|
|
@@ -9951,6 +9988,18 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
9951
9988
|
params = { width, height };
|
|
9952
9989
|
break;
|
|
9953
9990
|
}
|
|
9991
|
+
case "mouse": {
|
|
9992
|
+
const action = options.action || args.find((a) => ["move", "click", "dblclick", "down", "up"].includes(a));
|
|
9993
|
+
const actionIdx = action ? args.indexOf(action) : -1;
|
|
9994
|
+
const x = options.x !== void 0 ? Number(options.x) : actionIdx >= 0 && args[actionIdx + 1] ? Number(args[actionIdx + 1]) : void 0;
|
|
9995
|
+
const y = options.y !== void 0 ? Number(options.y) : actionIdx >= 0 && args[actionIdx + 2] ? Number(args[actionIdx + 2]) : void 0;
|
|
9996
|
+
if (!action || x === void 0 || y === void 0) {
|
|
9997
|
+
outputError("Usage: xbrowser mouse <move|click|dblclick> <x> <y>\n xbrowser mouse --action <action> --x <x> --y <y>");
|
|
9998
|
+
}
|
|
9999
|
+
cmdName = "mouse";
|
|
10000
|
+
params = { action, x, y, ...options.button ? { button: options.button } : {} };
|
|
10001
|
+
break;
|
|
10002
|
+
}
|
|
9954
10003
|
case "html":
|
|
9955
10004
|
cmdName = "html";
|
|
9956
10005
|
params = { selector: options.selector || options.s };
|
|
@@ -10487,6 +10536,11 @@ async function handlePlugin(args, options, mode) {
|
|
|
10487
10536
|
case "uninstall": {
|
|
10488
10537
|
const name = subArgs[0];
|
|
10489
10538
|
if (!name) outputError("Usage: xbrowser plugin uninstall <name>");
|
|
10539
|
+
const installed = await installer.list();
|
|
10540
|
+
const exists = installed.some((p) => p.name === name || p.metadata?.name === name);
|
|
10541
|
+
if (!exists) {
|
|
10542
|
+
outputError(`Plugin "${name}" is not installed. Use 'xbrowser plugin list' to see installed plugins.`);
|
|
10543
|
+
}
|
|
10490
10544
|
await installer.uninstall(name);
|
|
10491
10545
|
outputResult({ ok: true, name }, mode);
|
|
10492
10546
|
break;
|
|
@@ -12893,7 +12947,7 @@ async function handleServe(_args, options, mode) {
|
|
|
12893
12947
|
\u{1F310} xbrowser HTTP Server`);
|
|
12894
12948
|
console.log(`
|
|
12895
12949
|
URL: ${output.url}`);
|
|
12896
|
-
console.log(` Auth: ${output.authRequired ? "Enabled (Bearer token)" : "Disabled (dev mode)"}
|
|
12950
|
+
console.log(` Auth: ${output.authRequired ? "Enabled (Bearer token, except /health)" : "Disabled (dev mode)"}
|
|
12897
12951
|
`);
|
|
12898
12952
|
console.log(` Endpoints:`);
|
|
12899
12953
|
for (const [, value] of Object.entries(output.endpoints)) {
|
|
@@ -15800,7 +15854,7 @@ var DataCollector = class {
|
|
|
15800
15854
|
return results;
|
|
15801
15855
|
}
|
|
15802
15856
|
async createBrowserContext() {
|
|
15803
|
-
const { launch } = await import("./cdp-driver-
|
|
15857
|
+
const { launch } = await import("./cdp-driver-LKNM6OQI.js");
|
|
15804
15858
|
const { browser } = await launch({
|
|
15805
15859
|
headless: true,
|
|
15806
15860
|
args: ["--no-sandbox", "--disable-setuid-sandbox"]
|
|
@@ -31,7 +31,7 @@ var SessionReplayer = class {
|
|
|
31
31
|
if (this.opts.page) {
|
|
32
32
|
this.page = this.opts.page;
|
|
33
33
|
} else if (this.opts.cdpUrl) {
|
|
34
|
-
const { launch } = await import("./cdp-driver-
|
|
34
|
+
const { launch } = await import("./cdp-driver-LKNM6OQI.js");
|
|
35
35
|
const { browser } = await launch({ cdpEndpoint: this.opts.cdpUrl });
|
|
36
36
|
let contexts = browser.contexts();
|
|
37
37
|
for (let i = 0; i < 10 && contexts.length === 0; i++) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xbrowser/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Browser automation CLI for web scraping, headless browsing, SEO analysis, and AI agent workflows. A command-line alternative to Playwright, Puppeteer, and Selenium.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|