@xbrowser/cli 1.0.6 → 1.0.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.
- package/README.md +19 -16
- package/dist/cli.js +84 -42
- package/dist/daemon-main.js +1 -0
- package/dist/index.js +84 -42
- 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 模式** — 后台常驻,快速响应
|
|
@@ -256,7 +256,7 @@ xbrowser --cdp auto "goto https://example.com , title"
|
|
|
256
256
|
| `html --selector "#main"` | 获取指定元素 HTML | `xbrowser html --selector "#main"` |
|
|
257
257
|
| `text` | 获取页面文本 | `xbrowser text` |
|
|
258
258
|
| `text --selector "#article"` | 获取指定元素文本 | `xbrowser text --selector "#article"` |
|
|
259
|
-
| `
|
|
259
|
+
| `eval "expression"` | 执行 JS 获取元素属性 | `xbrowser eval "document.querySelector('#link').href"` |
|
|
260
260
|
|
|
261
261
|
### 截图与快照
|
|
262
262
|
|
|
@@ -282,20 +282,20 @@ xbrowser --cdp auto "goto https://example.com , title"
|
|
|
282
282
|
|------|------|------|
|
|
283
283
|
| `eval <expression>` | 执行 JS 表达式 | `xbrowser eval "document.title"` |
|
|
284
284
|
| `eval "1 + 2"` | 计算表达式 | `xbrowser eval "1 + 2"` |
|
|
285
|
-
| `
|
|
285
|
+
| `eval "(a, b) => a + b" --args 1 2` | 执行带参数的函数 | `xbrowser eval "(a, b) => a + b" --args 1 2` |
|
|
286
286
|
|
|
287
287
|
### 存储
|
|
288
288
|
|
|
289
289
|
| 命令 | 说明 | 示例 |
|
|
290
290
|
|------|------|------|
|
|
291
|
-
| `
|
|
292
|
-
| `
|
|
293
|
-
| `
|
|
294
|
-
| `
|
|
295
|
-
| `
|
|
296
|
-
| `
|
|
297
|
-
| `
|
|
298
|
-
| `
|
|
291
|
+
| `get-cookies` | 获取所有 Cookie | `xbrowser get-cookies` |
|
|
292
|
+
| `set-cookie <name> <value>` | 设置 Cookie | `xbrowser set-cookie session abc123` |
|
|
293
|
+
| `set-cookie <name> <value> --domain .example.com` | 指定域名 | `xbrowser set-cookie session abc123 --domain .example.com` |
|
|
294
|
+
| `clear-cookies` | 清除所有 Cookie | `xbrowser clear-cookies` |
|
|
295
|
+
| `get-local-storage` | 获取所有 localStorage | `xbrowser get-local-storage` |
|
|
296
|
+
| `get-local-storage --key token` | 获取指定 key | `xbrowser get-local-storage --key token` |
|
|
297
|
+
| `set-local-storage <key> <value>` | 设置 localStorage | `xbrowser set-local-storage token "abc"` |
|
|
298
|
+
| `clear-local-storage` | 清除 localStorage | `xbrowser clear-local-storage` |
|
|
299
299
|
|
|
300
300
|
### 帧操作
|
|
301
301
|
|
|
@@ -309,8 +309,8 @@ xbrowser --cdp auto "goto https://example.com , title"
|
|
|
309
309
|
|
|
310
310
|
| 命令 | 说明 | 示例 |
|
|
311
311
|
|------|------|------|
|
|
312
|
-
| `
|
|
313
|
-
| `
|
|
312
|
+
| `set-viewport <width> <height>` | 设置视口大小 | `xbrowser set-viewport 1920 1080` |
|
|
313
|
+
| `set-viewport 375 812 --isMobile true` | 移动设备模式 | `xbrowser set-viewport 375 812 --isMobile true` |
|
|
314
314
|
|
|
315
315
|
### 配置管理
|
|
316
316
|
|
|
@@ -416,7 +416,10 @@ xbrowser create my-plugin --template static --force
|
|
|
416
416
|
| `;` | 分割管线(前一个完成后开始下一个) | `goto https://example.com ; goto https://other.com` |
|
|
417
417
|
| `\|\|` | 前一步成功则跳过后续 | `goto https://example.com \|\| goto https://fallback.com` |
|
|
418
418
|
|
|
419
|
-
|
|
419
|
+
**注意**:
|
|
420
|
+
- 命令链中如果包含特殊字符(如 `#`、`>`),需要用引号包裹整个命令链或对单个参数加引号。
|
|
421
|
+
- `->` 和 `+` 分隔符要求两边有空格(`goto url -> title` ✅,`goto url->title` ❌)。
|
|
422
|
+
- `,` 和 `;` 不要求空格。
|
|
420
423
|
|
|
421
424
|
```bash
|
|
422
425
|
# 正确 — 整体引号
|
|
@@ -440,7 +443,7 @@ project > browser > page > element
|
|
|
440
443
|
| Scope | 说明 | 需要的条件 | 典型命令 |
|
|
441
444
|
|-------|------|------------|----------|
|
|
442
445
|
| **project** | 项目级别 | 无 | config, daemon, plugin |
|
|
443
|
-
| **browser** | 浏览器级别 | 浏览器实例 |
|
|
446
|
+
| **browser** | 浏览器级别 | 浏览器实例 | set-viewport, session |
|
|
444
447
|
| **page** | 页面级别 | 活跃页面 | goto, wait, scroll, screenshot |
|
|
445
448
|
| **element** | 元素级别 | 页面中的元素 | click, fill, type, hover |
|
|
446
449
|
|
package/dist/cli.js
CHANGED
|
@@ -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");
|
|
@@ -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
|
}
|
|
@@ -10147,6 +10184,11 @@ async function handlePlugin(args, options, mode) {
|
|
|
10147
10184
|
case "uninstall": {
|
|
10148
10185
|
const name = subArgs[0];
|
|
10149
10186
|
if (!name) outputError("Usage: xbrowser plugin uninstall <name>");
|
|
10187
|
+
const installed = await installer.list();
|
|
10188
|
+
const exists = installed.some((p) => p.name === name || p.metadata?.name === name);
|
|
10189
|
+
if (!exists) {
|
|
10190
|
+
outputError(`Plugin "${name}" is not installed. Use 'xbrowser plugin list' to see installed plugins.`);
|
|
10191
|
+
}
|
|
10150
10192
|
await installer.uninstall(name);
|
|
10151
10193
|
outputResult({ ok: true, name }, mode);
|
|
10152
10194
|
break;
|
package/dist/daemon-main.js
CHANGED
|
@@ -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");
|
package/dist/index.js
CHANGED
|
@@ -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");
|
|
@@ -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
|
}
|
|
@@ -10487,6 +10524,11 @@ async function handlePlugin(args, options, mode) {
|
|
|
10487
10524
|
case "uninstall": {
|
|
10488
10525
|
const name = subArgs[0];
|
|
10489
10526
|
if (!name) outputError("Usage: xbrowser plugin uninstall <name>");
|
|
10527
|
+
const installed = await installer.list();
|
|
10528
|
+
const exists = installed.some((p) => p.name === name || p.metadata?.name === name);
|
|
10529
|
+
if (!exists) {
|
|
10530
|
+
outputError(`Plugin "${name}" is not installed. Use 'xbrowser plugin list' to see installed plugins.`);
|
|
10531
|
+
}
|
|
10490
10532
|
await installer.uninstall(name);
|
|
10491
10533
|
outputResult({ ok: true, name }, mode);
|
|
10492
10534
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xbrowser/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
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": {
|