@tgebrowser/cli 1.1.0
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 +87 -0
- package/build/cli.js +1212 -0
- package/package.json +40 -0
package/README.MD
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# tgebrowser
|
|
2
|
+
|
|
3
|
+
TgeBrowser automation CLI for AI agents.
|
|
4
|
+
|
|
5
|
+
## Install CLI (npm)
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g tgebrowser
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Install as Cursor / Agent Skill
|
|
12
|
+
|
|
13
|
+
Skills live at the repo root. Install with:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx skills add TgeBrowser/tgebrowser
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
- Project scope (default): skill goes to `.cursor/skills/tgebrowser/` (or your agent’s skills dir).
|
|
20
|
+
- Global: add `-g` (e.g. `~/.cursor/skills/` for Cursor).
|
|
21
|
+
|
|
22
|
+
## Usage with AI Agents
|
|
23
|
+
|
|
24
|
+
Use the CLI in terminal or let the agent run it; the installed skill gives the agent context on when and how to call `tgebrowser` (environments, groups, proxies, etc.).
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
## How to Run
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
tgebrowser [--port PORT] [--api-key KEY] <command> [<arg>]
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Two forms for `<arg>`:**
|
|
34
|
+
|
|
35
|
+
1. **Single value (shorthand)** — for environment-related commands, pass one envId or userIndex.
|
|
36
|
+
|
|
37
|
+
2. **JSON string** — full parameters for any command (recommended):
|
|
38
|
+
- `tgebrowser open-browser '{"envId":901,"args":["--headless"]}'`
|
|
39
|
+
- Commands with no params: omit `<arg>` or use `'{}'`.
|
|
40
|
+
|
|
41
|
+
## Essential Commands
|
|
42
|
+
|
|
43
|
+
### Browser environment – open/close
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
tgebrowser open-browser '{"envId":901,"args":["--headless"],"port":1111}'
|
|
47
|
+
tgebrowser close-browser '{"envId":901}'
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Browser environment – create/update/delete/list
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
tgebrowser create-browser '{"browserName":"My Env","fingerprint":{"os":"Windows"}}'
|
|
54
|
+
tgebrowser update-browser '{"envId":900,"browserName":"New Name"}'
|
|
55
|
+
tgebrowser delete-browser '{"envId":900}'
|
|
56
|
+
tgebrowser get-browser-list '{"current":1,"pageSize":20}'
|
|
57
|
+
tgebrowser get-opened-browser
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Browser environment – cookies/UA/fingerprint/cache/active
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
tgebrowser get-profile-cookies '{"envId":900}'
|
|
64
|
+
tgebrowser get-profile-ua '{"envId":900}'
|
|
65
|
+
tgebrowser close-all-profiles
|
|
66
|
+
tgebrowser new-fingerprint '{"envId":900}'
|
|
67
|
+
tgebrowser delete-cache '{"envId":900}'
|
|
68
|
+
tgebrowser get-browser-active '{}'
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Group
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
tgebrowser get-group-list '{"current":1,"pageSize":20}'
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Application (categories)
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
tgebrowser check-status # No params – API availability
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Proxy
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
tgebrowser get-proxy-list '{"current":1,"pageSize":20}'
|
|
87
|
+
```
|
package/build/cli.js
ADDED
|
@@ -0,0 +1,1212 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
10
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
|
|
29
|
+
// package.json
|
|
30
|
+
var require_package = __commonJS({
|
|
31
|
+
"package.json"(exports2, module2) {
|
|
32
|
+
module2.exports = {
|
|
33
|
+
name: "tgebrowser",
|
|
34
|
+
version: "1.1.0",
|
|
35
|
+
main: "build/cli.js",
|
|
36
|
+
type: "commonjs",
|
|
37
|
+
bin: {
|
|
38
|
+
tgebrowser: "./build/cli.js"
|
|
39
|
+
},
|
|
40
|
+
scripts: {
|
|
41
|
+
build: "tsup",
|
|
42
|
+
tgebrowser: "node build/cli.js"
|
|
43
|
+
},
|
|
44
|
+
dependencies: {
|
|
45
|
+
axios: "^1.8.4",
|
|
46
|
+
playwright: "^1.51.1",
|
|
47
|
+
zod: "^3.24.2"
|
|
48
|
+
},
|
|
49
|
+
devDependencies: {
|
|
50
|
+
"@tgebrowser/core": "workspace:*",
|
|
51
|
+
"@types/node": "^22.13.13",
|
|
52
|
+
typescript: "^5.8.2",
|
|
53
|
+
tsup: "^8.5.1"
|
|
54
|
+
},
|
|
55
|
+
engines: {
|
|
56
|
+
node: ">=18.0.0"
|
|
57
|
+
},
|
|
58
|
+
files: [
|
|
59
|
+
"build"
|
|
60
|
+
],
|
|
61
|
+
description: "TgeBrowser Local API CLI and Cursor/agent skill for browser environments, groups, proxies.",
|
|
62
|
+
keywords: ["tgebrowser", "browser", "cursor", "skill", "agent-skills", "automation"],
|
|
63
|
+
repository: {
|
|
64
|
+
type: "git",
|
|
65
|
+
url: "https://github.com/tgebrowser/tgebrowser.git",
|
|
66
|
+
directory: "packages/tgebrowser-cli"
|
|
67
|
+
},
|
|
68
|
+
bugs: { url: "https://github.com/tgebrowser/tgebrowser/issues" },
|
|
69
|
+
homepage: "https://github.com/tgebrowser/tgebrowser/tree/main/packages/tgebrowser#readme"
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// ../core/src/client.ts
|
|
75
|
+
var import_axios = __toESM(require("axios"));
|
|
76
|
+
function parseArgs() {
|
|
77
|
+
const args = process.argv;
|
|
78
|
+
let port;
|
|
79
|
+
let apiKey;
|
|
80
|
+
for (let i = 0; i < args.length; i++) {
|
|
81
|
+
if (args[i] === "--port" && i + 1 < args.length) {
|
|
82
|
+
port = args[i + 1];
|
|
83
|
+
}
|
|
84
|
+
if (args[i] === "--api-key" && i + 1 < args.length) {
|
|
85
|
+
apiKey = args[i + 1];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
port: port || process.env.PORT || "50326",
|
|
90
|
+
apiKey: apiKey || process.env.API_KEY
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
var config = parseArgs();
|
|
94
|
+
var PORT = config.port;
|
|
95
|
+
var API_KEY = config.apiKey;
|
|
96
|
+
var BASE_URL = `http://127.0.0.1:${PORT}`;
|
|
97
|
+
var ENDPOINTS = {
|
|
98
|
+
STATUS: "/api/status",
|
|
99
|
+
START_BROWSER: "/api/browser/start",
|
|
100
|
+
CLOSE_BROWSER: "/api/browser/stop",
|
|
101
|
+
CREATE_BROWSER: "/api/browser/create",
|
|
102
|
+
UPDATE_BROWSER: "/api/browser/update",
|
|
103
|
+
DELETE_BROWSER: "/api/browser/delete",
|
|
104
|
+
BATCH_DELETE_BROWSER: "/api/browser/delete/batch",
|
|
105
|
+
GET_BROWSER_LIST: "/api/browser/list",
|
|
106
|
+
GET_BROWSER_DETAIL: "/api/browser/detail",
|
|
107
|
+
CLOSE_ALL_PROFILES: "/api/browser/stop-all",
|
|
108
|
+
DELETE_CACHE_V2: "/api/browser/cache/delete",
|
|
109
|
+
BATCH_DELETE_CACHE: "/api/browser/batch/delete-cache",
|
|
110
|
+
GET_OPENED_BROWSER: "/api/browser/open/list",
|
|
111
|
+
GET_MOBILE_DEVICES: "/api/browser/mobile-devices",
|
|
112
|
+
WINDOW_SORT: "/api/windowbounds/sort",
|
|
113
|
+
WINDOW_SORT_CUSTOM: "/api/windowbounds/sort/custom",
|
|
114
|
+
GET_GROUP_LIST: "/api/groups/list",
|
|
115
|
+
CREATE_GROUP: "/api/groups",
|
|
116
|
+
UPDATE_GROUP: (groupId) => `/api/groups/${groupId}`,
|
|
117
|
+
DELETE_GROUP: (groupId) => `/api/groups/${groupId}`,
|
|
118
|
+
GET_PROXY_LIST: "/api/proxies/list",
|
|
119
|
+
CREATE_PROXY: "/api/proxies",
|
|
120
|
+
UPDATE_PROXY: (proxyId) => `/api/proxies/${proxyId}`,
|
|
121
|
+
DELETE_PROXY: (proxyId) => `/api/proxies/${proxyId}`,
|
|
122
|
+
WINDOW_HIDE: "/api/window/hide",
|
|
123
|
+
WINDOW_SHOW: "/api/window/show",
|
|
124
|
+
UPDATE_COOKIE: "/api/browser/cookie/update",
|
|
125
|
+
BATCH_UPDATE: "/api/browser/batch/update"
|
|
126
|
+
};
|
|
127
|
+
var apiClient = import_axios.default.create({
|
|
128
|
+
baseURL: BASE_URL,
|
|
129
|
+
timeout: 1e4,
|
|
130
|
+
headers: {
|
|
131
|
+
"Content-Type": "application/json",
|
|
132
|
+
...API_KEY ? { "Authorization": `Bearer ${API_KEY}` } : {}
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// ../core/src/profile/actions.ts
|
|
137
|
+
function assertSuccess(data, action) {
|
|
138
|
+
if (data && data.success) return;
|
|
139
|
+
const message = data && typeof data.message === "string" ? data.message : "Unknown error";
|
|
140
|
+
throw new Error(`Failed to ${action}: ${message}`);
|
|
141
|
+
}
|
|
142
|
+
function buildBody(params) {
|
|
143
|
+
const body = {};
|
|
144
|
+
for (const [key, value] of Object.entries(params)) {
|
|
145
|
+
if (value === void 0) continue;
|
|
146
|
+
if (Array.isArray(value)) {
|
|
147
|
+
const mapped = value.map((item) => item && typeof item === "object" ? buildBody(item) : item).filter((v) => v !== void 0);
|
|
148
|
+
if (mapped.length > 0) body[key] = mapped;
|
|
149
|
+
} else if (value && typeof value === "object") {
|
|
150
|
+
body[key] = buildBody(value);
|
|
151
|
+
} else {
|
|
152
|
+
body[key] = value;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return body;
|
|
156
|
+
}
|
|
157
|
+
var profileActions = {
|
|
158
|
+
async open({ envId, userIndex, args, port }) {
|
|
159
|
+
const body = {};
|
|
160
|
+
if (envId !== void 0) body.envId = envId;
|
|
161
|
+
if (userIndex !== void 0) body.userIndex = userIndex;
|
|
162
|
+
if (args && args.length > 0) body.args = args;
|
|
163
|
+
if (port !== void 0) body.port = port;
|
|
164
|
+
const response = await apiClient.post(ENDPOINTS.START_BROWSER, body);
|
|
165
|
+
assertSuccess(response.data, "open browser");
|
|
166
|
+
const info = response.data.data || {};
|
|
167
|
+
const wsUrl = typeof info.ws === "object" ? info.ws?.puppeteer ?? info.ws?.selenium ?? JSON.stringify(info.ws) : info.ws;
|
|
168
|
+
return `Browser started: envId=${info.envId}, userIndex=${info.userIndex}, ws=${wsUrl}, http=${info.http}, port=${info.port}
|
|
169
|
+
|
|
170
|
+
To automate this browser, use connect-browser-with-ws with wsUrl="${wsUrl}"`;
|
|
171
|
+
},
|
|
172
|
+
async close({ envId, userIndex }) {
|
|
173
|
+
const body = {};
|
|
174
|
+
if (envId !== void 0) body.envId = envId;
|
|
175
|
+
if (userIndex !== void 0) body.userIndex = userIndex;
|
|
176
|
+
const response = await apiClient.post(ENDPOINTS.CLOSE_BROWSER, body);
|
|
177
|
+
assertSuccess(response.data, "close browser");
|
|
178
|
+
return "Browser closed successfully";
|
|
179
|
+
},
|
|
180
|
+
async create(params) {
|
|
181
|
+
const response = await apiClient.post(ENDPOINTS.CREATE_BROWSER, buildBody(params));
|
|
182
|
+
assertSuccess(response.data, "create browser");
|
|
183
|
+
const info = response.data.data || {};
|
|
184
|
+
return `Browser created: envId=${info.envId}, userIndex=${info.userIndex}`;
|
|
185
|
+
},
|
|
186
|
+
async update(params) {
|
|
187
|
+
const response = await apiClient.post(ENDPOINTS.UPDATE_BROWSER, buildBody(params));
|
|
188
|
+
assertSuccess(response.data, "update browser");
|
|
189
|
+
const info = response.data.data || {};
|
|
190
|
+
return `Browser updated: envId=${info.envId ?? params.envId}`;
|
|
191
|
+
},
|
|
192
|
+
async delete({ envId, userIndex }) {
|
|
193
|
+
const body = {};
|
|
194
|
+
if (envId !== void 0) body.envId = envId;
|
|
195
|
+
if (userIndex !== void 0) body.userIndex = userIndex;
|
|
196
|
+
const response = await apiClient.post(ENDPOINTS.DELETE_BROWSER, body);
|
|
197
|
+
assertSuccess(response.data, "delete browser");
|
|
198
|
+
return `Browser deleted: envId=${body.envId ?? ""} userIndex=${body.userIndex ?? ""}`;
|
|
199
|
+
},
|
|
200
|
+
async list(params) {
|
|
201
|
+
const searchParams = {};
|
|
202
|
+
if (params.current !== void 0) searchParams.current = params.current.toString();
|
|
203
|
+
if (params.pageSize !== void 0) searchParams.pageSize = params.pageSize.toString();
|
|
204
|
+
if (params.keyword) searchParams.keyword = params.keyword;
|
|
205
|
+
if (params.groupId !== void 0) searchParams.groupId = params.groupId.toString();
|
|
206
|
+
const response = await apiClient.get(ENDPOINTS.GET_BROWSER_LIST, { params: searchParams });
|
|
207
|
+
assertSuccess(response.data, "get browser list");
|
|
208
|
+
const raw = response.data.data || {};
|
|
209
|
+
const summary = {
|
|
210
|
+
total: raw.total,
|
|
211
|
+
current: raw.current,
|
|
212
|
+
pageSize: raw.pageSize,
|
|
213
|
+
list: (raw.list || []).map((item) => ({
|
|
214
|
+
envId: item.envId,
|
|
215
|
+
userIndex: item.userIndex,
|
|
216
|
+
browserName: item.browserName,
|
|
217
|
+
groupId: item.groupId,
|
|
218
|
+
remark: item.remark,
|
|
219
|
+
lastOpenedTime: item.lastOpenedTime
|
|
220
|
+
}))
|
|
221
|
+
};
|
|
222
|
+
return `Browser list: ${JSON.stringify(summary, null, 2)}`;
|
|
223
|
+
},
|
|
224
|
+
async openedList() {
|
|
225
|
+
const response = await apiClient.get(ENDPOINTS.GET_OPENED_BROWSER);
|
|
226
|
+
assertSuccess(response.data, "get opened browsers");
|
|
227
|
+
return `Opened browser list: ${JSON.stringify(response.data.data, null, 2)}`;
|
|
228
|
+
},
|
|
229
|
+
async getCookies({ envId, userIndex }) {
|
|
230
|
+
const body = {};
|
|
231
|
+
if (envId !== void 0) body.envId = envId;
|
|
232
|
+
if (userIndex !== void 0) body.userIndex = userIndex;
|
|
233
|
+
const response = await apiClient.post(ENDPOINTS.GET_BROWSER_DETAIL, body);
|
|
234
|
+
assertSuccess(response.data, "get profile cookies");
|
|
235
|
+
return `Profile cookies: ${JSON.stringify(response.data.data?.cookie, null, 2)}`;
|
|
236
|
+
},
|
|
237
|
+
async getUa({ envId, userIndex }) {
|
|
238
|
+
const body = {};
|
|
239
|
+
if (envId !== void 0) body.envId = envId;
|
|
240
|
+
if (userIndex !== void 0) body.userIndex = userIndex;
|
|
241
|
+
const response = await apiClient.post(ENDPOINTS.GET_BROWSER_DETAIL, body);
|
|
242
|
+
assertSuccess(response.data, "get profile User-Agent");
|
|
243
|
+
const ua = response.data.data?.fingerprint?.userAgent;
|
|
244
|
+
return `Profile User-Agent: ${ua ?? ""}`;
|
|
245
|
+
},
|
|
246
|
+
async closeAll() {
|
|
247
|
+
const response = await apiClient.post(ENDPOINTS.CLOSE_ALL_PROFILES, {});
|
|
248
|
+
assertSuccess(response.data, "close all browsers");
|
|
249
|
+
return "All browsers stopped successfully";
|
|
250
|
+
},
|
|
251
|
+
async newFingerprint({ envId, userIndex }) {
|
|
252
|
+
const body = {};
|
|
253
|
+
if (envId !== void 0) body.envId = envId;
|
|
254
|
+
if (userIndex !== void 0) body.userIndex = userIndex;
|
|
255
|
+
body.fingerprint = { randomFingerprint: true };
|
|
256
|
+
const response = await apiClient.post(ENDPOINTS.UPDATE_BROWSER, body);
|
|
257
|
+
assertSuccess(response.data, "refresh fingerprint");
|
|
258
|
+
return `Fingerprint updated for envId=${body.envId ?? ""} userIndex=${body.userIndex ?? ""}`;
|
|
259
|
+
},
|
|
260
|
+
async deleteCache({ envId, userIndex }) {
|
|
261
|
+
const body = {};
|
|
262
|
+
if (envId !== void 0) body.envId = envId;
|
|
263
|
+
if (userIndex !== void 0) body.userIndex = userIndex;
|
|
264
|
+
const response = await apiClient.post(ENDPOINTS.DELETE_CACHE_V2, body);
|
|
265
|
+
assertSuccess(response.data, "delete cache");
|
|
266
|
+
return `Cache deleted for envId=${body.envId ?? ""} userIndex=${body.userIndex ?? ""}`;
|
|
267
|
+
},
|
|
268
|
+
async getActive(_params) {
|
|
269
|
+
const response = await apiClient.get(ENDPOINTS.GET_OPENED_BROWSER);
|
|
270
|
+
assertSuccess(response.data, "get active browsers");
|
|
271
|
+
return `Active browsers: ${JSON.stringify(response.data.data, null, 2)}`;
|
|
272
|
+
},
|
|
273
|
+
async batchDelete({ envIds, userIndexes, permanent }) {
|
|
274
|
+
const body = {};
|
|
275
|
+
if (envIds && envIds.length > 0) body.envIds = envIds;
|
|
276
|
+
if (userIndexes && userIndexes.length > 0) body.userIndexes = userIndexes;
|
|
277
|
+
if (permanent !== void 0) body.permanent = permanent;
|
|
278
|
+
const response = await apiClient.post(ENDPOINTS.BATCH_DELETE_BROWSER, body);
|
|
279
|
+
assertSuccess(response.data, "batch delete browsers");
|
|
280
|
+
const info = response.data.data || {};
|
|
281
|
+
return `Batch delete result: total=${info.total}, deleted=${JSON.stringify(info.deleted)}, failed=${JSON.stringify(info.failed)}`;
|
|
282
|
+
},
|
|
283
|
+
async batchDeleteCache({ envIds, userIndexes }) {
|
|
284
|
+
const body = {};
|
|
285
|
+
if (envIds && envIds.length > 0) body.envIds = envIds;
|
|
286
|
+
if (userIndexes && userIndexes.length > 0) body.userIndexes = userIndexes;
|
|
287
|
+
const response = await apiClient.post(ENDPOINTS.BATCH_DELETE_CACHE, body);
|
|
288
|
+
assertSuccess(response.data, "batch delete cache");
|
|
289
|
+
const info = response.data.data || {};
|
|
290
|
+
return `Batch delete cache result: total=${info.total}, success=${info.success}, failed=${info.failed}`;
|
|
291
|
+
},
|
|
292
|
+
async getMobileDevices({ os: os2 }) {
|
|
293
|
+
const params = {};
|
|
294
|
+
if (os2) params.os = os2;
|
|
295
|
+
const response = await apiClient.get(ENDPOINTS.GET_MOBILE_DEVICES, { params });
|
|
296
|
+
assertSuccess(response.data, "get mobile devices");
|
|
297
|
+
return `Mobile devices: ${JSON.stringify(response.data.data, null, 2)}`;
|
|
298
|
+
},
|
|
299
|
+
async getDetail({ envId, userIndex }) {
|
|
300
|
+
const body = {};
|
|
301
|
+
if (envId !== void 0) body.envId = envId;
|
|
302
|
+
if (userIndex !== void 0) body.userIndex = userIndex;
|
|
303
|
+
const response = await apiClient.post(ENDPOINTS.GET_BROWSER_DETAIL, body);
|
|
304
|
+
assertSuccess(response.data, "get browser detail");
|
|
305
|
+
return `Browser detail: ${JSON.stringify(response.data.data, null, 2)}`;
|
|
306
|
+
},
|
|
307
|
+
async updateCookie({ envId, userIndex, cookie }) {
|
|
308
|
+
const body = { cookie };
|
|
309
|
+
if (envId !== void 0) body.envId = envId;
|
|
310
|
+
if (userIndex !== void 0) body.userIndex = userIndex;
|
|
311
|
+
const response = await apiClient.post(ENDPOINTS.UPDATE_COOKIE, body);
|
|
312
|
+
assertSuccess(response.data, "update cookie");
|
|
313
|
+
return `Cookie updated for envId=${body.envId ?? ""} userIndex=${body.userIndex ?? ""}`;
|
|
314
|
+
},
|
|
315
|
+
async batchUpdate({ envIds, field, value }) {
|
|
316
|
+
const response = await apiClient.put(ENDPOINTS.BATCH_UPDATE, { envIds, field, value });
|
|
317
|
+
assertSuccess(response.data, "batch update");
|
|
318
|
+
const info = response.data.data || {};
|
|
319
|
+
return `Batch update result: total=${info.total}, success=${info.success}, failed=${info.failed}`;
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
// ../core/src/profile/schema.ts
|
|
324
|
+
var import_zod = require("zod");
|
|
325
|
+
var CHROME_VERSIONS = [
|
|
326
|
+
"133",
|
|
327
|
+
"135",
|
|
328
|
+
"137",
|
|
329
|
+
"139",
|
|
330
|
+
"141",
|
|
331
|
+
"143",
|
|
332
|
+
"ua_auto"
|
|
333
|
+
];
|
|
334
|
+
var TLS_CIPHER_SUITES = {
|
|
335
|
+
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: "0xC02C",
|
|
336
|
+
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: "0xC030",
|
|
337
|
+
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: "0xC02B",
|
|
338
|
+
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: "0xC02F",
|
|
339
|
+
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: "0xCCA9",
|
|
340
|
+
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: "0xCCA8",
|
|
341
|
+
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: "0x009F",
|
|
342
|
+
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: "0x009E",
|
|
343
|
+
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: "0xC024",
|
|
344
|
+
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: "0xC028",
|
|
345
|
+
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: "0xC00A",
|
|
346
|
+
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: "0xC014",
|
|
347
|
+
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: "0x006B",
|
|
348
|
+
TLS_DHE_RSA_WITH_AES_256_CBC_SHA: "0x0039",
|
|
349
|
+
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: "0xC023",
|
|
350
|
+
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: "0xC027",
|
|
351
|
+
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: "0xC009",
|
|
352
|
+
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: "0xC013",
|
|
353
|
+
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: "0x0067",
|
|
354
|
+
TLS_DHE_RSA_WITH_AES_128_CBC_SHA: "0x0033",
|
|
355
|
+
TLS_RSA_WITH_AES_256_GCM_SHA384: "0x009D",
|
|
356
|
+
TLS_RSA_WITH_AES_128_GCM_SHA256: "0x009C",
|
|
357
|
+
TLS_RSA_WITH_AES_256_CBC_SHA256: "0x003D",
|
|
358
|
+
TLS_RSA_WITH_AES_128_CBC_SHA256: "0x003C",
|
|
359
|
+
TLS_RSA_WITH_AES_256_CBC_SHA: "0x0035",
|
|
360
|
+
TLS_RSA_WITH_AES_128_CBC_SHA: "0x002F",
|
|
361
|
+
TLS_AES_128_CCM_8_SHA256: "0x1305",
|
|
362
|
+
TLS_AES_128_CCM_SHA256: "0x1304"
|
|
363
|
+
};
|
|
364
|
+
var TLS_HEX_CODES = Object.values(TLS_CIPHER_SUITES);
|
|
365
|
+
var browserKernelConfigSchema = import_zod.z.object({
|
|
366
|
+
version: import_zod.z.union(
|
|
367
|
+
CHROME_VERSIONS.map((v) => import_zod.z.literal(v))
|
|
368
|
+
).optional().describe("The version of the browser, supported: 133, 135, 137, 139, 141, 143, ua_auto"),
|
|
369
|
+
type: import_zod.z.literal("chrome").optional().describe("The type of the browser, only chrome is supported")
|
|
370
|
+
}).optional().superRefine((data, ctx) => {
|
|
371
|
+
if (!data) return;
|
|
372
|
+
const version = data.version;
|
|
373
|
+
if (version === void 0) return;
|
|
374
|
+
if (!CHROME_VERSIONS.includes(version)) {
|
|
375
|
+
ctx.addIssue({ code: import_zod.z.ZodIssueCode.custom, message: `Unsupported version "${version}". Supported: ${CHROME_VERSIONS.join(", ")}` });
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
var randomUaConfigSchema = import_zod.z.object({
|
|
379
|
+
ua_version: import_zod.z.array(import_zod.z.string()).optional(),
|
|
380
|
+
ua_system_version: import_zod.z.array(
|
|
381
|
+
import_zod.z.enum([
|
|
382
|
+
"Android 9",
|
|
383
|
+
"Android 10",
|
|
384
|
+
"Android 11",
|
|
385
|
+
"Android 12",
|
|
386
|
+
"Android 13",
|
|
387
|
+
"Android 14",
|
|
388
|
+
"Android 15",
|
|
389
|
+
"iOS 14",
|
|
390
|
+
"iOS 15",
|
|
391
|
+
"iOS 16",
|
|
392
|
+
"iOS 17",
|
|
393
|
+
"iOS 18",
|
|
394
|
+
"Windows 7",
|
|
395
|
+
"Windows 8",
|
|
396
|
+
"Windows 10",
|
|
397
|
+
"Windows 11",
|
|
398
|
+
"Mac OS X 10",
|
|
399
|
+
"Mac OS X 11",
|
|
400
|
+
"Mac OS X 12",
|
|
401
|
+
"Mac OS X 13",
|
|
402
|
+
"Mac OS X 14",
|
|
403
|
+
"Mac OS X 15",
|
|
404
|
+
"Mac OS X",
|
|
405
|
+
"Windows",
|
|
406
|
+
"iOS",
|
|
407
|
+
"Android",
|
|
408
|
+
"Linux"
|
|
409
|
+
])
|
|
410
|
+
).optional()
|
|
411
|
+
}).optional();
|
|
412
|
+
var webglConfigSchema = import_zod.z.object({
|
|
413
|
+
unmasked_vendor: import_zod.z.string().describe("WebGL vendor string. Required when webgl=2."),
|
|
414
|
+
unmasked_renderer: import_zod.z.string().describe("WebGL renderer string. Required when webgl=2."),
|
|
415
|
+
webgpu: import_zod.z.object({
|
|
416
|
+
webgpu_switch: import_zod.z.enum(["0", "1", "2"])
|
|
417
|
+
}).optional()
|
|
418
|
+
});
|
|
419
|
+
var macAddressConfigSchema = import_zod.z.object({
|
|
420
|
+
model: import_zod.z.enum(["0", "1", "2"]),
|
|
421
|
+
address: import_zod.z.string().optional()
|
|
422
|
+
});
|
|
423
|
+
var mediaDevicesNumSchema = import_zod.z.object({
|
|
424
|
+
audioinput_num: import_zod.z.string().regex(/^[1-9]$/),
|
|
425
|
+
videoinput_num: import_zod.z.string().regex(/^[1-9]$/),
|
|
426
|
+
audiooutput_num: import_zod.z.string().regex(/^[1-9]$/)
|
|
427
|
+
});
|
|
428
|
+
var sharedFingerprintFields = {
|
|
429
|
+
mobileDeviceId: import_zod.z.number().optional(),
|
|
430
|
+
platformVersion: import_zod.z.number().optional(),
|
|
431
|
+
kernel: import_zod.z.string().optional(),
|
|
432
|
+
userAgent: import_zod.z.string().optional(),
|
|
433
|
+
webrtc: import_zod.z.string().optional(),
|
|
434
|
+
resolution: import_zod.z.string().optional(),
|
|
435
|
+
windowWidth: import_zod.z.number().optional(),
|
|
436
|
+
windowHeight: import_zod.z.number().optional(),
|
|
437
|
+
language: import_zod.z.string().optional(),
|
|
438
|
+
languageBaseIp: import_zod.z.boolean().optional(),
|
|
439
|
+
uiLanguage: import_zod.z.string().optional(),
|
|
440
|
+
uiLanguageBaseIp: import_zod.z.boolean().optional(),
|
|
441
|
+
timezone: import_zod.z.string().optional(),
|
|
442
|
+
timezoneBaseIp: import_zod.z.boolean().optional(),
|
|
443
|
+
geolocationBaseIp: import_zod.z.boolean().optional(),
|
|
444
|
+
lng: import_zod.z.string().optional(),
|
|
445
|
+
lat: import_zod.z.string().optional(),
|
|
446
|
+
canvas: import_zod.z.boolean().optional(),
|
|
447
|
+
audioContext: import_zod.z.boolean().optional(),
|
|
448
|
+
speechVoices: import_zod.z.boolean().optional(),
|
|
449
|
+
clientRects: import_zod.z.boolean().optional(),
|
|
450
|
+
fonts: import_zod.z.array(import_zod.z.string()).optional(),
|
|
451
|
+
disableTLS: import_zod.z.array(import_zod.z.string()).optional(),
|
|
452
|
+
ram: import_zod.z.number().optional(),
|
|
453
|
+
cpu: import_zod.z.number().optional(),
|
|
454
|
+
hardwareAcceleration: import_zod.z.boolean().optional(),
|
|
455
|
+
disableSandbox: import_zod.z.boolean().optional(),
|
|
456
|
+
startupParams: import_zod.z.string().optional(),
|
|
457
|
+
deviceName: import_zod.z.string().optional(),
|
|
458
|
+
deviceMedia: import_zod.z.boolean().optional(),
|
|
459
|
+
portScanProtection: import_zod.z.string().optional(),
|
|
460
|
+
randomFingerprint: import_zod.z.boolean().optional(),
|
|
461
|
+
blockLargeImages: import_zod.z.boolean().optional(),
|
|
462
|
+
maxImageKB: import_zod.z.number().optional(),
|
|
463
|
+
syncCookies: import_zod.z.boolean().optional(),
|
|
464
|
+
clearCacheOnStart: import_zod.z.boolean().optional(),
|
|
465
|
+
clearCachePreserveExtensionsOnStart: import_zod.z.boolean().optional(),
|
|
466
|
+
clearCookiesOnStart: import_zod.z.boolean().optional(),
|
|
467
|
+
clearHistoryOnStart: import_zod.z.boolean().optional(),
|
|
468
|
+
disableMediaAutoplay: import_zod.z.boolean().optional(),
|
|
469
|
+
muteAllMedia: import_zod.z.boolean().optional(),
|
|
470
|
+
disableGoogleTranslate: import_zod.z.boolean().optional(),
|
|
471
|
+
disableSavePasswordPrompt: import_zod.z.boolean().optional(),
|
|
472
|
+
disableNotifications: import_zod.z.boolean().optional(),
|
|
473
|
+
blockClipboardRead: import_zod.z.boolean().optional(),
|
|
474
|
+
stopOnNetworkIssue: import_zod.z.boolean().optional(),
|
|
475
|
+
stopOnIPChange: import_zod.z.boolean().optional(),
|
|
476
|
+
stopOnCountryChange: import_zod.z.boolean().optional()
|
|
477
|
+
};
|
|
478
|
+
var sharedProxyFields = {
|
|
479
|
+
host: import_zod.z.string().optional(),
|
|
480
|
+
port: import_zod.z.number().optional(),
|
|
481
|
+
username: import_zod.z.string().optional(),
|
|
482
|
+
password: import_zod.z.string().optional(),
|
|
483
|
+
timezone: import_zod.z.string().optional(),
|
|
484
|
+
proxyId: import_zod.z.number().optional()
|
|
485
|
+
};
|
|
486
|
+
var startInfoSchema = import_zod.z.object({
|
|
487
|
+
startPage: import_zod.z.object({
|
|
488
|
+
mode: import_zod.z.string().optional(),
|
|
489
|
+
value: import_zod.z.array(import_zod.z.string()).optional()
|
|
490
|
+
}).optional(),
|
|
491
|
+
otherConfig: import_zod.z.object({
|
|
492
|
+
openConfigPage: import_zod.z.boolean().optional(),
|
|
493
|
+
checkPage: import_zod.z.boolean().optional(),
|
|
494
|
+
extensionTab: import_zod.z.boolean().optional()
|
|
495
|
+
}).optional()
|
|
496
|
+
}).optional();
|
|
497
|
+
var profileSchemas = {
|
|
498
|
+
create: import_zod.z.object({
|
|
499
|
+
browserName: import_zod.z.string().describe("Environment name"),
|
|
500
|
+
groupId: import_zod.z.number().optional().describe("Group id of the environment"),
|
|
501
|
+
remark: import_zod.z.string().optional().describe("Remark for the environment"),
|
|
502
|
+
proxy: import_zod.z.object({
|
|
503
|
+
protocol: import_zod.z.string().describe("Proxy protocol, e.g. http, socks5, direct"),
|
|
504
|
+
...sharedProxyFields
|
|
505
|
+
}).optional(),
|
|
506
|
+
fingerprint: import_zod.z.object({
|
|
507
|
+
os: import_zod.z.string().describe("Operating system, e.g. Windows, macOS, Android, iOS"),
|
|
508
|
+
...sharedFingerprintFields
|
|
509
|
+
}).optional(),
|
|
510
|
+
startInfo: startInfoSchema,
|
|
511
|
+
Cookie: import_zod.z.any().optional()
|
|
512
|
+
}),
|
|
513
|
+
update: import_zod.z.object({
|
|
514
|
+
envId: import_zod.z.number().describe("Environment id to update"),
|
|
515
|
+
browserName: import_zod.z.string().describe("Environment name"),
|
|
516
|
+
groupId: import_zod.z.number().optional().describe("Group id"),
|
|
517
|
+
remark: import_zod.z.string().optional().describe("Remark"),
|
|
518
|
+
proxy: import_zod.z.object({
|
|
519
|
+
protocol: import_zod.z.string().optional(),
|
|
520
|
+
ipChecker: import_zod.z.string().optional(),
|
|
521
|
+
...sharedProxyFields
|
|
522
|
+
}).optional(),
|
|
523
|
+
fingerprint: import_zod.z.object({
|
|
524
|
+
os: import_zod.z.string().optional(),
|
|
525
|
+
...sharedFingerprintFields
|
|
526
|
+
}).optional(),
|
|
527
|
+
Cookie: import_zod.z.any().optional(),
|
|
528
|
+
startInfo: startInfoSchema
|
|
529
|
+
}),
|
|
530
|
+
open: import_zod.z.object({
|
|
531
|
+
envId: import_zod.z.number().optional().describe("Environment id to start"),
|
|
532
|
+
userIndex: import_zod.z.number().optional().describe("Environment index to start"),
|
|
533
|
+
args: import_zod.z.array(import_zod.z.string()).optional().describe("Extra browser args"),
|
|
534
|
+
port: import_zod.z.number().optional().describe("Custom remote debugging port")
|
|
535
|
+
}).refine((data) => data.envId !== void 0 || data.userIndex !== void 0, {
|
|
536
|
+
message: "Either envId or userIndex must be provided"
|
|
537
|
+
}),
|
|
538
|
+
close: import_zod.z.object({
|
|
539
|
+
envId: import_zod.z.number().optional().describe("Environment id to stop"),
|
|
540
|
+
userIndex: import_zod.z.number().optional().describe("Environment index to stop")
|
|
541
|
+
}).refine((data) => data.envId !== void 0 || data.userIndex !== void 0, {
|
|
542
|
+
message: "Either envId or userIndex must be provided"
|
|
543
|
+
}),
|
|
544
|
+
delete: import_zod.z.object({
|
|
545
|
+
envId: import_zod.z.number().optional().describe("Environment id to delete"),
|
|
546
|
+
userIndex: import_zod.z.number().optional().describe("Environment index to delete")
|
|
547
|
+
}).refine((data) => data.envId !== void 0 || data.userIndex !== void 0, {
|
|
548
|
+
message: "Either envId or userIndex must be provided"
|
|
549
|
+
}),
|
|
550
|
+
list: import_zod.z.object({
|
|
551
|
+
current: import_zod.z.number().optional().describe("Current page"),
|
|
552
|
+
pageSize: import_zod.z.number().optional().describe("Page size"),
|
|
553
|
+
keyword: import_zod.z.string().optional().describe("Search keyword"),
|
|
554
|
+
groupId: import_zod.z.number().optional().describe("Group id")
|
|
555
|
+
}).strict(),
|
|
556
|
+
cookies: import_zod.z.object({
|
|
557
|
+
envId: import_zod.z.number().optional().describe("Environment id"),
|
|
558
|
+
userIndex: import_zod.z.number().optional().describe("Environment index")
|
|
559
|
+
}).refine((data) => data.envId !== void 0 || data.userIndex !== void 0, {
|
|
560
|
+
message: "Either envId or userIndex must be provided"
|
|
561
|
+
}),
|
|
562
|
+
ua: import_zod.z.object({
|
|
563
|
+
envId: import_zod.z.number().optional().describe("Environment id"),
|
|
564
|
+
userIndex: import_zod.z.number().optional().describe("Environment index")
|
|
565
|
+
}).refine((data) => data.envId !== void 0 || data.userIndex !== void 0, {
|
|
566
|
+
message: "Either envId or userIndex must be provided"
|
|
567
|
+
}),
|
|
568
|
+
closeAll: import_zod.z.object({}).strict(),
|
|
569
|
+
newFingerprint: import_zod.z.object({
|
|
570
|
+
envId: import_zod.z.number().optional().describe("Environment id"),
|
|
571
|
+
userIndex: import_zod.z.number().optional().describe("Environment index")
|
|
572
|
+
}).refine((data) => data.envId !== void 0 || data.userIndex !== void 0, {
|
|
573
|
+
message: "Either envId or userIndex must be provided"
|
|
574
|
+
}),
|
|
575
|
+
deleteCache: import_zod.z.object({
|
|
576
|
+
envId: import_zod.z.number().optional().describe("Environment id"),
|
|
577
|
+
userIndex: import_zod.z.number().optional().describe("Environment index")
|
|
578
|
+
}).refine((data) => data.envId !== void 0 || data.userIndex !== void 0, {
|
|
579
|
+
message: "Either envId or userIndex must be provided"
|
|
580
|
+
}),
|
|
581
|
+
active: import_zod.z.object({
|
|
582
|
+
profileId: import_zod.z.string().optional().describe("The profile id"),
|
|
583
|
+
profileNo: import_zod.z.string().optional().describe("The profile number")
|
|
584
|
+
}).refine((data) => data.profileId || data.profileNo, {
|
|
585
|
+
message: "Either profileId or profileNo must be provided"
|
|
586
|
+
}),
|
|
587
|
+
openedList: import_zod.z.object({}).strict(),
|
|
588
|
+
batchDelete: import_zod.z.object({
|
|
589
|
+
envIds: import_zod.z.array(import_zod.z.number().int().positive()).optional().describe("Array of environment ids to delete"),
|
|
590
|
+
userIndexes: import_zod.z.array(import_zod.z.number().int().min(1)).optional().describe("Array of environment indexes to delete"),
|
|
591
|
+
permanent: import_zod.z.boolean().optional().describe("true=hard delete, false=soft delete (default)")
|
|
592
|
+
}).refine((data) => data.envIds && data.envIds.length > 0 || data.userIndexes && data.userIndexes.length > 0, {
|
|
593
|
+
message: "Either envIds or userIndexes must be provided"
|
|
594
|
+
}),
|
|
595
|
+
batchDeleteCache: import_zod.z.object({
|
|
596
|
+
envIds: import_zod.z.array(import_zod.z.number().int().positive()).optional().describe("Array of environment ids"),
|
|
597
|
+
userIndexes: import_zod.z.array(import_zod.z.number().int().min(1)).optional().describe("Array of environment indexes")
|
|
598
|
+
}).refine((data) => data.envIds && data.envIds.length > 0 || data.userIndexes && data.userIndexes.length > 0, {
|
|
599
|
+
message: "Either envIds or userIndexes must be provided"
|
|
600
|
+
}),
|
|
601
|
+
mobileDevices: import_zod.z.object({
|
|
602
|
+
os: import_zod.z.enum(["Android", "iOS"]).optional().describe("Filter by OS: Android or iOS")
|
|
603
|
+
}).strict(),
|
|
604
|
+
detail: import_zod.z.object({
|
|
605
|
+
envId: import_zod.z.number().int().positive().optional().describe("Environment id"),
|
|
606
|
+
userIndex: import_zod.z.number().int().min(1).optional().describe("Environment index")
|
|
607
|
+
}).refine((data) => data.envId !== void 0 || data.userIndex !== void 0, {
|
|
608
|
+
message: "Either envId or userIndex must be provided"
|
|
609
|
+
}),
|
|
610
|
+
updateCookie: import_zod.z.object({
|
|
611
|
+
envId: import_zod.z.number().int().positive().optional().describe("Environment id"),
|
|
612
|
+
userIndex: import_zod.z.number().int().min(1).optional().describe("Environment index"),
|
|
613
|
+
cookie: import_zod.z.string().describe("Cookie string. Empty string or null clears the cookie.")
|
|
614
|
+
}).refine((data) => data.envId !== void 0 || data.userIndex !== void 0, {
|
|
615
|
+
message: "Either envId or userIndex must be provided"
|
|
616
|
+
}),
|
|
617
|
+
batchUpdate: import_zod.z.object({
|
|
618
|
+
envIds: import_zod.z.array(import_zod.z.number().int().positive()).describe("Array of environment ids"),
|
|
619
|
+
field: import_zod.z.string().describe('Field name to update, e.g. "browserName", "remark", "fingerprint"'),
|
|
620
|
+
value: import_zod.z.any().describe("New value for the field")
|
|
621
|
+
})
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
// ../core/src/automation/actions.ts
|
|
625
|
+
var import_path = __toESM(require("path"));
|
|
626
|
+
var import_os = __toESM(require("os"));
|
|
627
|
+
|
|
628
|
+
// ../core/src/automation/session.ts
|
|
629
|
+
var import_playwright = require("playwright");
|
|
630
|
+
var BrowserSession = class {
|
|
631
|
+
browser;
|
|
632
|
+
page;
|
|
633
|
+
screenshots;
|
|
634
|
+
constructor() {
|
|
635
|
+
this.browser = null;
|
|
636
|
+
this.page = null;
|
|
637
|
+
this.screenshots = /* @__PURE__ */ new Map();
|
|
638
|
+
}
|
|
639
|
+
get browserInstance() {
|
|
640
|
+
return this.browser;
|
|
641
|
+
}
|
|
642
|
+
get pageInstance() {
|
|
643
|
+
return this.page;
|
|
644
|
+
}
|
|
645
|
+
set pageInstance(page) {
|
|
646
|
+
this.page = page;
|
|
647
|
+
}
|
|
648
|
+
get screenshotsInstance() {
|
|
649
|
+
return this.screenshots;
|
|
650
|
+
}
|
|
651
|
+
checkConnected() {
|
|
652
|
+
const error = new Error("Browser not connected, please connect browser first");
|
|
653
|
+
if (!this.browser) throw error;
|
|
654
|
+
if (!this.browser.isConnected()) throw error;
|
|
655
|
+
if (!this.page) throw error;
|
|
656
|
+
}
|
|
657
|
+
async connectWithWs(wsUrl) {
|
|
658
|
+
this.browser = await import_playwright.chromium.connectOverCDP(wsUrl);
|
|
659
|
+
const defaultContext = this.browser.contexts()[0];
|
|
660
|
+
this.page = defaultContext.pages()[0];
|
|
661
|
+
await this.page.bringToFront().catch((error) => {
|
|
662
|
+
console.error("Failed to bring page to front", error);
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
async reset() {
|
|
666
|
+
this.browser = null;
|
|
667
|
+
this.page = null;
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
var session_default = new BrowserSession();
|
|
671
|
+
|
|
672
|
+
// ../core/src/automation/actions.ts
|
|
673
|
+
var defaultDownloadsPath = import_path.default.join(import_os.default.homedir(), "Downloads");
|
|
674
|
+
|
|
675
|
+
// ../core/src/automation/schema.ts
|
|
676
|
+
var import_zod2 = require("zod");
|
|
677
|
+
var automationSchemas = {
|
|
678
|
+
connect: import_zod2.z.object({
|
|
679
|
+
userId: import_zod2.z.string().optional().describe("The browser id of the browser to connect"),
|
|
680
|
+
serialNumber: import_zod2.z.string().optional().describe("The serial number of the browser to connect"),
|
|
681
|
+
wsUrl: import_zod2.z.string().describe("The ws url of the browser, get from the open-browser tool content `ws.puppeteer`")
|
|
682
|
+
}).strict(),
|
|
683
|
+
navigate: import_zod2.z.object({ url: import_zod2.z.string().describe("The url to navigate to") }).strict(),
|
|
684
|
+
screenshot: import_zod2.z.object({
|
|
685
|
+
savePath: import_zod2.z.string().optional().describe("The path to save the screenshot"),
|
|
686
|
+
isFullPage: import_zod2.z.boolean().optional().describe("The is full page of the screenshot")
|
|
687
|
+
}).strict(),
|
|
688
|
+
clickElement: import_zod2.z.object({ selector: import_zod2.z.string().describe("The selector of the element to click, find from the page source code") }).strict(),
|
|
689
|
+
fillInput: import_zod2.z.object({
|
|
690
|
+
selector: import_zod2.z.string().describe("The selector of the input to fill, find from the page source code"),
|
|
691
|
+
text: import_zod2.z.string().describe("The text to fill in the input")
|
|
692
|
+
}).strict(),
|
|
693
|
+
selectOption: import_zod2.z.object({
|
|
694
|
+
selector: import_zod2.z.string().describe("The selector of the option to select, find from the page source code"),
|
|
695
|
+
value: import_zod2.z.string().describe("The value of the option to select")
|
|
696
|
+
}).strict(),
|
|
697
|
+
hoverElement: import_zod2.z.object({ selector: import_zod2.z.string().describe("The selector of the element to hover, find from the page source code") }).strict(),
|
|
698
|
+
scrollElement: import_zod2.z.object({ selector: import_zod2.z.string().describe("The selector of the element to scroll, find from the page source code") }).strict(),
|
|
699
|
+
pressKey: import_zod2.z.object({
|
|
700
|
+
key: import_zod2.z.string().describe('The key to press, eg: "Enter"'),
|
|
701
|
+
selector: import_zod2.z.string().optional().describe("The selector of the element to press the key, find from the page source code")
|
|
702
|
+
}).strict(),
|
|
703
|
+
evaluateScript: import_zod2.z.object({ script: import_zod2.z.string().describe("The script to evaluate") }).strict(),
|
|
704
|
+
dragElement: import_zod2.z.object({
|
|
705
|
+
selector: import_zod2.z.string().describe("The selector of the element to drag, find from the page source code"),
|
|
706
|
+
targetSelector: import_zod2.z.string().describe("The selector of the element to drag to, find from the page source code")
|
|
707
|
+
}).strict(),
|
|
708
|
+
iframeClickElement: import_zod2.z.object({
|
|
709
|
+
selector: import_zod2.z.string().describe("The selector of the element to click, find from the page source code"),
|
|
710
|
+
iframeSelector: import_zod2.z.string().describe("The selector of the iframe to click, find from the page source code")
|
|
711
|
+
}).strict(),
|
|
712
|
+
empty: import_zod2.z.object({}).strict()
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
// ../core/src/group/actions.ts
|
|
716
|
+
function assertSuccess2(data, action) {
|
|
717
|
+
if (data && data.success) return;
|
|
718
|
+
const message = data && typeof data.message === "string" ? data.message : "Unknown error";
|
|
719
|
+
throw new Error(`Failed to ${action}: ${message}`);
|
|
720
|
+
}
|
|
721
|
+
var groupActions = {
|
|
722
|
+
async list({ current, pageSize }) {
|
|
723
|
+
const params = {};
|
|
724
|
+
if (current !== void 0) params.current = current.toString();
|
|
725
|
+
if (pageSize !== void 0) params.pageSize = pageSize.toString();
|
|
726
|
+
const response = await apiClient.get(ENDPOINTS.GET_GROUP_LIST, { params });
|
|
727
|
+
assertSuccess2(response.data, "get group list");
|
|
728
|
+
return `Group list: ${JSON.stringify(response.data.data, null, 2)}`;
|
|
729
|
+
},
|
|
730
|
+
async create({ name }) {
|
|
731
|
+
const response = await apiClient.post(ENDPOINTS.CREATE_GROUP, { name });
|
|
732
|
+
assertSuccess2(response.data, "create group");
|
|
733
|
+
return `Group created: ${JSON.stringify(response.data.data, null, 2)}`;
|
|
734
|
+
},
|
|
735
|
+
async update({ groupId, name }) {
|
|
736
|
+
const response = await apiClient.put(ENDPOINTS.UPDATE_GROUP(groupId), { name });
|
|
737
|
+
assertSuccess2(response.data, "update group");
|
|
738
|
+
return `Group updated: groupId=${groupId}`;
|
|
739
|
+
},
|
|
740
|
+
async delete({ groupId }) {
|
|
741
|
+
const response = await apiClient.delete(ENDPOINTS.DELETE_GROUP(groupId));
|
|
742
|
+
assertSuccess2(response.data, "delete group");
|
|
743
|
+
return `Group deleted: groupId=${groupId}`;
|
|
744
|
+
}
|
|
745
|
+
};
|
|
746
|
+
|
|
747
|
+
// ../core/src/group/schema.ts
|
|
748
|
+
var import_zod3 = require("zod");
|
|
749
|
+
var groupSchemas = {
|
|
750
|
+
list: import_zod3.z.object({
|
|
751
|
+
current: import_zod3.z.number().optional().describe("Current page"),
|
|
752
|
+
pageSize: import_zod3.z.number().optional().describe("Page size")
|
|
753
|
+
}).strict(),
|
|
754
|
+
create: import_zod3.z.object({
|
|
755
|
+
name: import_zod3.z.string().describe("Group name")
|
|
756
|
+
}).strict(),
|
|
757
|
+
update: import_zod3.z.object({
|
|
758
|
+
groupId: import_zod3.z.number().int().positive().describe("Group id to update"),
|
|
759
|
+
name: import_zod3.z.string().describe("New group name")
|
|
760
|
+
}).strict(),
|
|
761
|
+
delete: import_zod3.z.object({
|
|
762
|
+
groupId: import_zod3.z.number().int().positive().describe("Group id to delete")
|
|
763
|
+
}).strict()
|
|
764
|
+
};
|
|
765
|
+
|
|
766
|
+
// ../core/src/proxy/actions.ts
|
|
767
|
+
function assertSuccess3(data, action) {
|
|
768
|
+
if (data && data.success) return;
|
|
769
|
+
const message = data && typeof data.message === "string" ? data.message : "Unknown error";
|
|
770
|
+
throw new Error(`Failed to ${action}: ${message}`);
|
|
771
|
+
}
|
|
772
|
+
var proxyActions = {
|
|
773
|
+
async list({ current, pageSize }) {
|
|
774
|
+
const params = {};
|
|
775
|
+
if (current !== void 0) params.current = current.toString();
|
|
776
|
+
if (pageSize !== void 0) params.pageSize = pageSize.toString();
|
|
777
|
+
const response = await apiClient.get(ENDPOINTS.GET_PROXY_LIST, { params });
|
|
778
|
+
assertSuccess3(response.data, "get proxy list");
|
|
779
|
+
return `Proxy list: ${JSON.stringify(response.data.data, null, 2)}`;
|
|
780
|
+
},
|
|
781
|
+
async create(params) {
|
|
782
|
+
const response = await apiClient.post(ENDPOINTS.CREATE_PROXY, params);
|
|
783
|
+
assertSuccess3(response.data, "create proxy");
|
|
784
|
+
return `Proxy created: ${JSON.stringify(response.data.data, null, 2)}`;
|
|
785
|
+
},
|
|
786
|
+
async update({ proxyId, ...rest }) {
|
|
787
|
+
const response = await apiClient.put(ENDPOINTS.UPDATE_PROXY(proxyId), rest);
|
|
788
|
+
assertSuccess3(response.data, "update proxy");
|
|
789
|
+
return `Proxy updated: proxyId=${proxyId}`;
|
|
790
|
+
},
|
|
791
|
+
async delete({ proxyId }) {
|
|
792
|
+
const response = await apiClient.delete(ENDPOINTS.DELETE_PROXY(proxyId));
|
|
793
|
+
assertSuccess3(response.data, "delete proxy");
|
|
794
|
+
return `Proxy deleted: proxyId=${proxyId}`;
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
|
|
798
|
+
// ../core/src/proxy/schema.ts
|
|
799
|
+
var import_zod4 = require("zod");
|
|
800
|
+
var proxySchemas = {
|
|
801
|
+
list: import_zod4.z.object({
|
|
802
|
+
current: import_zod4.z.number().optional().describe("Current page"),
|
|
803
|
+
pageSize: import_zod4.z.number().optional().describe("Page size")
|
|
804
|
+
}).strict(),
|
|
805
|
+
create: import_zod4.z.object({
|
|
806
|
+
protocol: import_zod4.z.enum(["http", "socks5"]).describe("Proxy protocol: http or socks5"),
|
|
807
|
+
host: import_zod4.z.string().optional().describe("Proxy host (required for http/socks5)"),
|
|
808
|
+
port: import_zod4.z.number().optional().describe("Proxy port (required for http/socks5)"),
|
|
809
|
+
username: import_zod4.z.string().optional().describe("Proxy username"),
|
|
810
|
+
password: import_zod4.z.string().optional().describe("Proxy password"),
|
|
811
|
+
ipChecker: import_zod4.z.enum(["iptrush", "ip234", "ipinfo", "ipapi"]).optional().describe("IP checker service")
|
|
812
|
+
}).strict(),
|
|
813
|
+
update: import_zod4.z.object({
|
|
814
|
+
proxyId: import_zod4.z.number().int().positive().describe("Proxy id to update"),
|
|
815
|
+
protocol: import_zod4.z.enum(["http", "socks5"]).optional().describe("Proxy protocol"),
|
|
816
|
+
host: import_zod4.z.string().optional().describe("Proxy host"),
|
|
817
|
+
port: import_zod4.z.number().optional().describe("Proxy port"),
|
|
818
|
+
username: import_zod4.z.string().optional().describe("Proxy username"),
|
|
819
|
+
password: import_zod4.z.string().optional().describe("Proxy password"),
|
|
820
|
+
ipChecker: import_zod4.z.enum(["iptrush", "ip234", "ipinfo", "ipapi"]).optional().describe("IP checker service")
|
|
821
|
+
}).strict(),
|
|
822
|
+
delete: import_zod4.z.object({
|
|
823
|
+
proxyId: import_zod4.z.number().int().positive().describe("Proxy id to delete")
|
|
824
|
+
}).strict()
|
|
825
|
+
};
|
|
826
|
+
|
|
827
|
+
// ../core/src/system/actions.ts
|
|
828
|
+
function assertSuccess4(data, action) {
|
|
829
|
+
if (data && data.success) return;
|
|
830
|
+
const message = data && typeof data.message === "string" ? data.message : "Unknown error";
|
|
831
|
+
throw new Error(`Failed to ${action}: ${message}`);
|
|
832
|
+
}
|
|
833
|
+
var systemActions = {
|
|
834
|
+
async checkStatus() {
|
|
835
|
+
const response = await apiClient.get(ENDPOINTS.STATUS);
|
|
836
|
+
return `Connection status: ${JSON.stringify(response.data, null, 2)}`;
|
|
837
|
+
},
|
|
838
|
+
async windowSort({ envIds }) {
|
|
839
|
+
const body = {};
|
|
840
|
+
if (envIds && envIds.length > 0) body.envIds = envIds;
|
|
841
|
+
const response = await apiClient.post(ENDPOINTS.WINDOW_SORT, body);
|
|
842
|
+
assertSuccess4(response.data, "sort windows");
|
|
843
|
+
return `Window sort result: ${response.data.message || JSON.stringify(response.data.data)}`;
|
|
844
|
+
},
|
|
845
|
+
async windowSortCustom(params) {
|
|
846
|
+
const response = await apiClient.post(ENDPOINTS.WINDOW_SORT_CUSTOM, params);
|
|
847
|
+
assertSuccess4(response.data, "custom sort windows");
|
|
848
|
+
return `Custom window sort result: ${response.data.message || JSON.stringify(response.data.data)}`;
|
|
849
|
+
},
|
|
850
|
+
async windowHide() {
|
|
851
|
+
const response = await apiClient.post(ENDPOINTS.WINDOW_HIDE, {});
|
|
852
|
+
assertSuccess4(response.data, "hide window");
|
|
853
|
+
return `Window hidden: ${JSON.stringify(response.data.data)}`;
|
|
854
|
+
},
|
|
855
|
+
async windowShow() {
|
|
856
|
+
const response = await apiClient.post(ENDPOINTS.WINDOW_SHOW, {});
|
|
857
|
+
assertSuccess4(response.data, "show window");
|
|
858
|
+
return `Window shown: ${JSON.stringify(response.data.data)}`;
|
|
859
|
+
}
|
|
860
|
+
};
|
|
861
|
+
|
|
862
|
+
// ../core/src/system/schema.ts
|
|
863
|
+
var import_zod5 = require("zod");
|
|
864
|
+
var systemSchemas = {
|
|
865
|
+
windowSort: import_zod5.z.object({
|
|
866
|
+
envIds: import_zod5.z.array(import_zod5.z.number().int().positive()).optional().describe("Target environment ids to sort. If omitted, sorts all open windows.")
|
|
867
|
+
}).strict(),
|
|
868
|
+
windowSortCustom: import_zod5.z.object({
|
|
869
|
+
type: import_zod5.z.enum(["box", "diagonal"]).describe("Layout type: box (grid) or diagonal"),
|
|
870
|
+
width: import_zod5.z.number().positive().describe("Window width"),
|
|
871
|
+
height: import_zod5.z.number().positive().describe("Window height"),
|
|
872
|
+
col: import_zod5.z.number().int().positive().describe("Column count"),
|
|
873
|
+
startX: import_zod5.z.number().describe("Starting X coordinate"),
|
|
874
|
+
startY: import_zod5.z.number().describe("Starting Y coordinate"),
|
|
875
|
+
spaceX: import_zod5.z.number().describe("Horizontal spacing between windows"),
|
|
876
|
+
spaceY: import_zod5.z.number().describe("Vertical spacing between windows"),
|
|
877
|
+
offsetX: import_zod5.z.number().describe("X offset"),
|
|
878
|
+
offsetY: import_zod5.z.number().describe("Y offset"),
|
|
879
|
+
envIds: import_zod5.z.array(import_zod5.z.number().int().positive()).optional().describe("Target environment ids"),
|
|
880
|
+
minWindowCount: import_zod5.z.number().int().positive().optional().describe("Minimum number of windows to trigger sort")
|
|
881
|
+
}).strict()
|
|
882
|
+
};
|
|
883
|
+
|
|
884
|
+
// src/cli.ts
|
|
885
|
+
var COMMANDS = {
|
|
886
|
+
// ─ Browser Environment ───────────────────────────────
|
|
887
|
+
"env-list": {
|
|
888
|
+
handler: profileActions.list,
|
|
889
|
+
desc: "Query environment list (paginated)"
|
|
890
|
+
},
|
|
891
|
+
"env-open-list": {
|
|
892
|
+
handler: profileActions.openedList,
|
|
893
|
+
desc: "Query open/running environments"
|
|
894
|
+
},
|
|
895
|
+
"env-create": {
|
|
896
|
+
handler: profileActions.create,
|
|
897
|
+
desc: "Create a new browser environment"
|
|
898
|
+
},
|
|
899
|
+
"env-update": {
|
|
900
|
+
handler: profileActions.update,
|
|
901
|
+
desc: "Update an environment"
|
|
902
|
+
},
|
|
903
|
+
"env-delete": {
|
|
904
|
+
handler: profileActions.delete,
|
|
905
|
+
desc: "Delete an environment",
|
|
906
|
+
shorthandKey: "envId"
|
|
907
|
+
},
|
|
908
|
+
"env-delete-batch": {
|
|
909
|
+
handler: profileActions.batchDelete,
|
|
910
|
+
desc: "Batch delete environments"
|
|
911
|
+
},
|
|
912
|
+
"env-detail": {
|
|
913
|
+
handler: profileActions.getDetail,
|
|
914
|
+
desc: "Get environment detail",
|
|
915
|
+
shorthandKey: "envId"
|
|
916
|
+
},
|
|
917
|
+
"get-cookies": {
|
|
918
|
+
handler: profileActions.getCookies,
|
|
919
|
+
desc: "Get environment cookies",
|
|
920
|
+
shorthandKey: "envId"
|
|
921
|
+
},
|
|
922
|
+
"env-ua": {
|
|
923
|
+
handler: profileActions.getUa,
|
|
924
|
+
desc: "Get environment User-Agent",
|
|
925
|
+
shorthandKey: "envId"
|
|
926
|
+
},
|
|
927
|
+
"env-fingerprint": {
|
|
928
|
+
handler: profileActions.newFingerprint,
|
|
929
|
+
desc: "Refresh environment fingerprint",
|
|
930
|
+
shorthandKey: "envId"
|
|
931
|
+
},
|
|
932
|
+
"env-mobile-devices": {
|
|
933
|
+
handler: profileActions.getMobileDevices,
|
|
934
|
+
desc: "Query mobile device list"
|
|
935
|
+
},
|
|
936
|
+
"update-cookie": {
|
|
937
|
+
handler: profileActions.updateCookie,
|
|
938
|
+
desc: "Update environment cookie"
|
|
939
|
+
},
|
|
940
|
+
"batch-update": {
|
|
941
|
+
handler: profileActions.batchUpdate,
|
|
942
|
+
desc: "Batch update a field across environments"
|
|
943
|
+
},
|
|
944
|
+
// ─ Browser Control ───────────────────────────────────
|
|
945
|
+
"start-browser": {
|
|
946
|
+
handler: profileActions.open,
|
|
947
|
+
desc: "Start/open a browser environment",
|
|
948
|
+
shorthandKey: "envId"
|
|
949
|
+
},
|
|
950
|
+
"stop-browser": {
|
|
951
|
+
handler: profileActions.close,
|
|
952
|
+
desc: "Stop a browser environment",
|
|
953
|
+
shorthandKey: "envId"
|
|
954
|
+
},
|
|
955
|
+
"stop-all-browsers": {
|
|
956
|
+
handler: profileActions.closeAll,
|
|
957
|
+
desc: "Stop all running environments"
|
|
958
|
+
},
|
|
959
|
+
"browser-active": {
|
|
960
|
+
handler: profileActions.getActive,
|
|
961
|
+
desc: "Get active browser info",
|
|
962
|
+
shorthandKey: "envId"
|
|
963
|
+
},
|
|
964
|
+
// ─ Cache ─────────────────────────────────────────────
|
|
965
|
+
"clear-cache": {
|
|
966
|
+
handler: profileActions.deleteCache,
|
|
967
|
+
desc: "Clear environment local cache",
|
|
968
|
+
shorthandKey: "envId"
|
|
969
|
+
},
|
|
970
|
+
"clear-cache-batch": {
|
|
971
|
+
handler: profileActions.batchDeleteCache,
|
|
972
|
+
desc: "Batch clear environment caches"
|
|
973
|
+
},
|
|
974
|
+
// ─ Groups ────────────────────────────────────────────
|
|
975
|
+
"group-list": {
|
|
976
|
+
handler: groupActions.list,
|
|
977
|
+
desc: "Query group list"
|
|
978
|
+
},
|
|
979
|
+
"group-create": {
|
|
980
|
+
handler: groupActions.create,
|
|
981
|
+
desc: "Create a group"
|
|
982
|
+
},
|
|
983
|
+
"group-update": {
|
|
984
|
+
handler: groupActions.update,
|
|
985
|
+
desc: "Update a group"
|
|
986
|
+
},
|
|
987
|
+
"group-delete": {
|
|
988
|
+
handler: groupActions.delete,
|
|
989
|
+
desc: "Delete a group"
|
|
990
|
+
},
|
|
991
|
+
// ─ Proxies ───────────────────────────────────────────
|
|
992
|
+
"proxy-list": {
|
|
993
|
+
handler: proxyActions.list,
|
|
994
|
+
desc: "Query proxy list"
|
|
995
|
+
},
|
|
996
|
+
"proxy-create": {
|
|
997
|
+
handler: proxyActions.create,
|
|
998
|
+
desc: "Create a proxy"
|
|
999
|
+
},
|
|
1000
|
+
"proxy-update": {
|
|
1001
|
+
handler: proxyActions.update,
|
|
1002
|
+
desc: "Update a proxy"
|
|
1003
|
+
},
|
|
1004
|
+
"proxy-delete": {
|
|
1005
|
+
handler: proxyActions.delete,
|
|
1006
|
+
desc: "Delete a proxy"
|
|
1007
|
+
},
|
|
1008
|
+
// ─ System ────────────────────────────────────────────
|
|
1009
|
+
"check-status": {
|
|
1010
|
+
handler: systemActions.checkStatus,
|
|
1011
|
+
desc: "Check API connection status"
|
|
1012
|
+
},
|
|
1013
|
+
"window-sort": {
|
|
1014
|
+
handler: systemActions.windowSort,
|
|
1015
|
+
desc: "Auto-layout browser windows"
|
|
1016
|
+
},
|
|
1017
|
+
"window-sort-custom": {
|
|
1018
|
+
handler: systemActions.windowSortCustom,
|
|
1019
|
+
desc: "Custom window layout"
|
|
1020
|
+
},
|
|
1021
|
+
"window-hide": {
|
|
1022
|
+
handler: systemActions.windowHide,
|
|
1023
|
+
desc: "Hide app window and tray"
|
|
1024
|
+
},
|
|
1025
|
+
"window-show": {
|
|
1026
|
+
handler: systemActions.windowShow,
|
|
1027
|
+
desc: "Show app window and tray"
|
|
1028
|
+
}
|
|
1029
|
+
};
|
|
1030
|
+
function parseValue(s) {
|
|
1031
|
+
s = s.trim();
|
|
1032
|
+
if (s === "true") return true;
|
|
1033
|
+
if (s === "false") return false;
|
|
1034
|
+
if (s === "null") return null;
|
|
1035
|
+
if (s.startsWith("{") && s.endsWith("}") || s.startsWith("[") && s.endsWith("]")) {
|
|
1036
|
+
try {
|
|
1037
|
+
return JSON.parse(s);
|
|
1038
|
+
} catch {
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
if (!isNaN(Number(s)) && s !== "") return Number(s);
|
|
1042
|
+
return s;
|
|
1043
|
+
}
|
|
1044
|
+
function parseArgs2(argv) {
|
|
1045
|
+
const globalOpts = {};
|
|
1046
|
+
let i = 0;
|
|
1047
|
+
while (i < argv.length) {
|
|
1048
|
+
const arg = argv[i];
|
|
1049
|
+
if (arg === "--port" || arg === "--api-key" || arg === "--host" || arg === "--timeout") {
|
|
1050
|
+
globalOpts[arg] = argv[i + 1] || "";
|
|
1051
|
+
i += 2;
|
|
1052
|
+
continue;
|
|
1053
|
+
}
|
|
1054
|
+
if (arg === "-p") {
|
|
1055
|
+
globalOpts["--port"] = argv[i + 1] || "";
|
|
1056
|
+
i += 2;
|
|
1057
|
+
continue;
|
|
1058
|
+
}
|
|
1059
|
+
if (arg === "-j") {
|
|
1060
|
+
globalOpts["--json"] = argv[i + 1] || "";
|
|
1061
|
+
i += 2;
|
|
1062
|
+
continue;
|
|
1063
|
+
}
|
|
1064
|
+
if (arg === "--json-stdin") {
|
|
1065
|
+
globalOpts["--json-stdin"] = "true";
|
|
1066
|
+
i++;
|
|
1067
|
+
continue;
|
|
1068
|
+
}
|
|
1069
|
+
if (arg === "-h" || arg === "--help") {
|
|
1070
|
+
globalOpts["--help"] = "true";
|
|
1071
|
+
i++;
|
|
1072
|
+
continue;
|
|
1073
|
+
}
|
|
1074
|
+
if (arg === "-V" || arg === "--version") {
|
|
1075
|
+
globalOpts["--version"] = "true";
|
|
1076
|
+
i++;
|
|
1077
|
+
continue;
|
|
1078
|
+
}
|
|
1079
|
+
break;
|
|
1080
|
+
}
|
|
1081
|
+
const command = argv[i] || "";
|
|
1082
|
+
const rest = argv.slice(i + 1);
|
|
1083
|
+
if (globalOpts["--help"] || command === "help") {
|
|
1084
|
+
const helpCmd = command === "help" ? rest[0] : void 0;
|
|
1085
|
+
printHelp(helpCmd);
|
|
1086
|
+
process.exit(0);
|
|
1087
|
+
}
|
|
1088
|
+
if (globalOpts["--version"] || command === "--version") {
|
|
1089
|
+
const pkg = require_package();
|
|
1090
|
+
console.log(`tgebrowser v${pkg.version}`);
|
|
1091
|
+
process.exit(0);
|
|
1092
|
+
}
|
|
1093
|
+
if (!command || !COMMANDS[command]) {
|
|
1094
|
+
printHelp();
|
|
1095
|
+
process.exit(1);
|
|
1096
|
+
}
|
|
1097
|
+
let args = {};
|
|
1098
|
+
if (globalOpts["--json"]) {
|
|
1099
|
+
try {
|
|
1100
|
+
args = JSON.parse(globalOpts["--json"]);
|
|
1101
|
+
} catch {
|
|
1102
|
+
throw new Error("Invalid JSON in --json");
|
|
1103
|
+
}
|
|
1104
|
+
} else if (globalOpts["--json-stdin"]) {
|
|
1105
|
+
const input = require("fs").readFileSync(0, "utf-8");
|
|
1106
|
+
try {
|
|
1107
|
+
args = JSON.parse(input);
|
|
1108
|
+
} catch {
|
|
1109
|
+
throw new Error("Invalid JSON from stdin");
|
|
1110
|
+
}
|
|
1111
|
+
} else if (rest.length > 0) {
|
|
1112
|
+
const first = rest[0].trim();
|
|
1113
|
+
if (first.startsWith("{")) {
|
|
1114
|
+
try {
|
|
1115
|
+
args = JSON.parse(first);
|
|
1116
|
+
} catch {
|
|
1117
|
+
throw new Error("Invalid JSON argument");
|
|
1118
|
+
}
|
|
1119
|
+
} else if (first.includes("=")) {
|
|
1120
|
+
for (const arg of rest) {
|
|
1121
|
+
const eqIdx = arg.indexOf("=");
|
|
1122
|
+
if (eqIdx > 0) {
|
|
1123
|
+
args[arg.slice(0, eqIdx)] = parseValue(arg.slice(eqIdx + 1));
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
} else if (COMMANDS[command].shorthandKey) {
|
|
1127
|
+
args[COMMANDS[command].shorthandKey] = parseValue(first);
|
|
1128
|
+
} else {
|
|
1129
|
+
for (const arg of rest) {
|
|
1130
|
+
const eqIdx = arg.indexOf("=");
|
|
1131
|
+
if (eqIdx > 0) {
|
|
1132
|
+
args[arg.slice(0, eqIdx)] = parseValue(arg.slice(eqIdx + 1));
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
return { command, args, globalOpts };
|
|
1138
|
+
}
|
|
1139
|
+
function printHelp(cmd) {
|
|
1140
|
+
if (cmd) {
|
|
1141
|
+
const def = COMMANDS[cmd];
|
|
1142
|
+
if (!def) {
|
|
1143
|
+
console.error(`Unknown command: ${cmd}`);
|
|
1144
|
+
process.exit(1);
|
|
1145
|
+
}
|
|
1146
|
+
console.log(`Command: ${cmd}`);
|
|
1147
|
+
console.log(`Description: ${def.desc}`);
|
|
1148
|
+
console.log();
|
|
1149
|
+
console.log("Usage:");
|
|
1150
|
+
console.log(` tgebrowser ${cmd} [key=value ...]`);
|
|
1151
|
+
console.log(` tgebrowser ${cmd} --json '{...}'`);
|
|
1152
|
+
return;
|
|
1153
|
+
}
|
|
1154
|
+
const categories = [
|
|
1155
|
+
{ name: "Browser Environment", cmds: ["env-list", "env-open-list", "env-create", "env-update", "env-delete", "env-delete-batch", "env-detail", "get-cookies", "update-cookie", "env-ua", "env-fingerprint", "env-mobile-devices", "batch-update"] },
|
|
1156
|
+
{ name: "Browser Control", cmds: ["start-browser", "stop-browser", "stop-all-browsers", "browser-active"] },
|
|
1157
|
+
{ name: "Cache", cmds: ["clear-cache", "clear-cache-batch"] },
|
|
1158
|
+
{ name: "Groups", cmds: ["group-list", "group-create", "group-update", "group-delete"] },
|
|
1159
|
+
{ name: "Proxies", cmds: ["proxy-list", "proxy-create", "proxy-update", "proxy-delete"] },
|
|
1160
|
+
{ name: "System", cmds: ["check-status", "window-sort", "window-sort-custom", "window-hide", "window-show"] }
|
|
1161
|
+
];
|
|
1162
|
+
console.log("TgeBrowser CLI - Command line tool for TgeBrowser Local API");
|
|
1163
|
+
console.log();
|
|
1164
|
+
console.log("Usage:");
|
|
1165
|
+
console.log(" tgebrowser [options] <command> [key=value ...]");
|
|
1166
|
+
console.log(" tgebrowser [options] <command> --json '{...}'");
|
|
1167
|
+
console.log(" tgebrowser [options] <command> --json-stdin");
|
|
1168
|
+
console.log();
|
|
1169
|
+
console.log("Options:");
|
|
1170
|
+
console.log(" -p, --port <n> Local API port");
|
|
1171
|
+
console.log(" --api-key <key> Local API authentication key");
|
|
1172
|
+
console.log(" --timeout <seconds> HTTP timeout in seconds (default: 30)");
|
|
1173
|
+
console.log(" -j, --json <json> JSON request body");
|
|
1174
|
+
console.log(" --json-stdin Read JSON from stdin");
|
|
1175
|
+
console.log(" -h, --help Show help");
|
|
1176
|
+
console.log(" -V, --version Show version");
|
|
1177
|
+
console.log();
|
|
1178
|
+
for (const cat of categories) {
|
|
1179
|
+
console.log(` ${cat.name}:`);
|
|
1180
|
+
for (const cmd2 of cat.cmds) {
|
|
1181
|
+
const def = COMMANDS[cmd2];
|
|
1182
|
+
if (def) console.log(` ${cmd2.padEnd(24)} ${def.desc}`);
|
|
1183
|
+
}
|
|
1184
|
+
console.log();
|
|
1185
|
+
}
|
|
1186
|
+
console.log("Examples:");
|
|
1187
|
+
console.log(" tgebrowser env-list");
|
|
1188
|
+
console.log(" tgebrowser env-list current=1 pageSize=20");
|
|
1189
|
+
console.log(" tgebrowser start-browser envId=1");
|
|
1190
|
+
console.log(` tgebrowser env-create --json '{"browserName":"test","fingerprint":{"os":"Windows"}}'`);
|
|
1191
|
+
console.log(' tgebrowser --api-key "your-key" env-list');
|
|
1192
|
+
console.log(" tgebrowser help start-browser");
|
|
1193
|
+
}
|
|
1194
|
+
async function main() {
|
|
1195
|
+
const argv = process.argv.slice(2);
|
|
1196
|
+
if (argv.length === 0) {
|
|
1197
|
+
printHelp();
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
const { command, args, globalOpts } = parseArgs2(argv);
|
|
1201
|
+
if (globalOpts["--port"]) process.env.TGEBROWSER_PORT = globalOpts["--port"];
|
|
1202
|
+
if (globalOpts["--api-key"]) process.env.TGEBROWSER_API_KEY = globalOpts["--api-key"];
|
|
1203
|
+
const handler = COMMANDS[command].handler;
|
|
1204
|
+
const result = await handler(args);
|
|
1205
|
+
const out = typeof result === "string" ? result : JSON.stringify(result, null, 2);
|
|
1206
|
+
process.stdout.write(out + "\n");
|
|
1207
|
+
}
|
|
1208
|
+
main().catch((err) => {
|
|
1209
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1210
|
+
process.stderr.write(msg + "\n");
|
|
1211
|
+
process.exit(1);
|
|
1212
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tgebrowser/cli",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"main": "build/cli.js",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"bin": {
|
|
7
|
+
"tgebrowser": "./build/cli.js",
|
|
8
|
+
"tge-cli": "./build/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsup",
|
|
12
|
+
"tgebrowser": "node build/cli.js"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"axios": "^1.8.4",
|
|
16
|
+
"playwright": "^1.51.1",
|
|
17
|
+
"zod": "^3.24.2"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@tgebrowser/core": "workspace:*",
|
|
21
|
+
"@types/node": "^22.13.13",
|
|
22
|
+
"typescript": "^5.8.2",
|
|
23
|
+
"tsup": "^8.5.1"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18.0.0"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"build"
|
|
30
|
+
],
|
|
31
|
+
"description": "TgeBrowser Local API CLI and Cursor/agent skill for browser environments, groups, proxies.",
|
|
32
|
+
"keywords": ["tgebrowser", "browser", "cursor", "skill", "agent-skills", "automation"],
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/tgebrowser/tgebrowser.git",
|
|
36
|
+
"directory": "packages/tgebrowser-cli"
|
|
37
|
+
},
|
|
38
|
+
"bugs": { "url": "https://github.com/tgebrowser/tgebrowser/issues" },
|
|
39
|
+
"homepage": "https://github.com/tgebrowser/tgebrowser/tree/main/packages/tgebrowser#readme"
|
|
40
|
+
}
|