adspower-browser 2.0.2 → 2.0.4

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 CHANGED
@@ -61,6 +61,61 @@ ads start
61
61
  - `ads open-browser '{"profile_id":"abc123","launch_args":"..."}'`
62
62
  - Commands with no params: omit `<arg>` or use `'{}'`.
63
63
 
64
+ ## Shell Tab Completion
65
+
66
+ The CLI supports prefix tab completion for subcommands and common flags (`-k`, `-p`, etc.) via [`@bomb.sh/tab`](https://bomb.sh/docs/tab/). Enable it once in your shell:
67
+
68
+ **macOS — zsh**
69
+
70
+ ```bash
71
+ ads complete zsh > ~/.ads-completion.zsh
72
+ echo 'source ~/.ads-completion.zsh' >> ~/.zshrc
73
+ source ~/.ads-completion.zsh
74
+ ```
75
+
76
+ **Linux — bash**
77
+
78
+ ```bash
79
+ ads complete bash > ~/.ads-completion.bash
80
+ echo 'source ~/.ads-completion.bash' >> ~/.bashrc
81
+ source ~/.ads-completion.bash
82
+ ```
83
+
84
+ On Linux login shells, ensure `~/.bashrc` is sourced (e.g. from `~/.bash_profile`).
85
+
86
+ **Linux — zsh**
87
+
88
+ ```bash
89
+ ads complete zsh > ~/.ads-completion.zsh
90
+ echo 'source ~/.ads-completion.zsh' >> ~/.zshrc
91
+ source ~/.ads-completion.zsh
92
+ ```
93
+
94
+ **Windows — PowerShell**
95
+
96
+ ```powershell
97
+ ads complete powershell > $HOME\.ads-completion.ps1
98
+ if (-not (Test-Path $PROFILE)) { New-Item -Path $PROFILE -ItemType File -Force }
99
+ Add-Content $PROFILE '. $HOME\.ads-completion.ps1'
100
+ . $HOME\.ads-completion.ps1
101
+ ```
102
+
103
+ **Windows — Git Bash**
104
+
105
+ ```bash
106
+ ads complete bash > ~/.ads-completion.bash
107
+ echo 'source ~/.ads-completion.bash' >> ~/.bashrc
108
+ source ~/.ads-completion.bash
109
+ ```
110
+
111
+ After setup on zsh/bash, `ads`, `adspower`, and `adspower-browser` share the same completions. On PowerShell and Git Bash, use `ads` for tab completion:
112
+
113
+ ```bash
114
+ ads <Tab><Tab> # list subcommands
115
+ ads open-<Tab> # complete to open-browser
116
+ ads sta<Tab> # complete to start / status
117
+ ```
118
+
64
119
  ## Essential Commands With CLI
65
120
 
66
121
  You can use `ads -h` or `ads <command> -h` to view the specific parameters.
@@ -149,4 +204,14 @@ ads download-kernel '{"kernel_type":"Chrome","kernel_version":"..."}' # kernel
149
204
 
150
205
  ```bash
151
206
  ads update-patch '{"version_type":"stable"}' # version_type?:stable|beta
207
+ ```
208
+
209
+ ## Use CLI in Docker
210
+
211
+ copy the [`docker-compose.yml`](./docker-compose.yml)
212
+
213
+ ```bash
214
+ docker-compose -f ./docker-compose.yml up -d
215
+
216
+ docker-compose exec adspower-cli /bin/bash
152
217
  ```
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+
3
+ // src/core/winHideChildProcess.js
4
+ if (process.platform !== "win32") {
5
+ return;
6
+ }
7
+ var cp = require("child_process");
8
+ function withWindowsHide(options) {
9
+ if (typeof options === "object" && options !== null && !Array.isArray(options)) {
10
+ if (options.windowsHide === false) {
11
+ return options;
12
+ }
13
+ return { ...options, windowsHide: true };
14
+ }
15
+ return { windowsHide: true };
16
+ }
17
+ function normalizeExecArgs(options, callback) {
18
+ if (typeof options === "function") {
19
+ return { options: { windowsHide: true }, callback: options };
20
+ }
21
+ return { options: withWindowsHide(options || {}), callback };
22
+ }
23
+ function normalizeSpawnArgs(args, options) {
24
+ if (Array.isArray(args)) {
25
+ return { args, options: withWindowsHide(options || {}) };
26
+ }
27
+ return { args: [], options: withWindowsHide(args || {}) };
28
+ }
29
+ var origExec = cp.exec.bind(cp);
30
+ cp.exec = function exec(cmd, options, callback) {
31
+ const { options: opts, callback: cb } = normalizeExecArgs(options, callback);
32
+ return origExec(cmd, opts, cb);
33
+ };
34
+ var origExecSync = cp.execSync.bind(cp);
35
+ cp.execSync = function execSync(cmd, options) {
36
+ return origExecSync(cmd, withWindowsHide(options || {}));
37
+ };
38
+ var origSpawn = cp.spawn.bind(cp);
39
+ cp.spawn = function spawn(command, args, options) {
40
+ const normalized = normalizeSpawnArgs(args, options);
41
+ return origSpawn(command, normalized.args, normalized.options);
42
+ };
43
+ var origSpawnSync = cp.spawnSync.bind(cp);
44
+ cp.spawnSync = function spawnSync(command, args, options) {
45
+ const normalized = normalizeSpawnArgs(args, options);
46
+ return origSpawnSync(command, normalized.args, normalized.options);
47
+ };
package/cli/index.js CHANGED
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  ));
25
25
 
26
26
  // src/index.ts
27
- var import_commander = require("commander");
27
+ var import_commander2 = require("commander");
28
28
 
29
29
  // src/store/index.ts
30
30
  var Store = class {
@@ -93,6 +93,7 @@ var Store = class {
93
93
  var store = new Store();
94
94
 
95
95
  // src/core/start.ts
96
+ var fs2 = __toESM(require("fs"));
96
97
  var path2 = __toESM(require("path"));
97
98
  var import_node_child_process2 = require("child_process");
98
99
 
@@ -105,7 +106,8 @@ var util = __toESM(require("util"));
105
106
  var import_node_child_process = require("child_process");
106
107
  var import_colors = require("colors");
107
108
  var import_fs_extra2 = require("fs-extra2");
108
- var VERSION = "1.0.0";
109
+ var VERSION = (0, import_fs_extra2.readJsonSync)(path.join(__dirname, "../package.json")).version;
110
+ var VERSION_FILE = "1.0.0";
109
111
  var toTerminalLink = (url, label) => {
110
112
  const text = label || url;
111
113
  return `\x1B]8;;${url}\x07${text}\x1B]8;;\x07`;
@@ -133,7 +135,7 @@ var browsersKill = async () => {
133
135
  };
134
136
  var taskKillBrowser = () => new Promise((resolve) => {
135
137
  const cmd = ["linux", "darwin"].includes(process.platform) ? 'pkill -u `whoami` -f "SunBrowser"' : "taskkill -PID SunBrowser.exe";
136
- (0, import_node_child_process.exec)(cmd, (err) => {
138
+ (0, import_node_child_process.exec)(cmd, { windowsHide: true }, (err) => {
137
139
  if (err) {
138
140
  }
139
141
  resolve();
@@ -141,7 +143,7 @@ var taskKillBrowser = () => new Promise((resolve) => {
141
143
  });
142
144
  var taskKillFlowser = () => new Promise((resolve) => {
143
145
  const cmd = ["linux", "darwin"].includes(process.platform) ? 'pkill -u `whoami` -f "FlowerBrowser"' : "taskkill -PID FlowerBrowser.exe";
144
- (0, import_node_child_process.exec)(cmd, (err) => {
146
+ (0, import_node_child_process.exec)(cmd, { windowsHide: true }, (err) => {
145
147
  if (err) {
146
148
  }
147
149
  resolve();
@@ -158,7 +160,7 @@ var getPidFileDir = () => {
158
160
  return dir;
159
161
  };
160
162
  var pidFileName = () => {
161
- const md5 = crypto.createHash("md5").update(VERSION).digest("hex");
163
+ const md5 = crypto.createHash("md5").update(VERSION_FILE).digest("hex");
162
164
  return md5;
163
165
  };
164
166
  var writePidFile = (config2) => {
@@ -183,6 +185,7 @@ var isRunning = (pid) => {
183
185
  if (pid) {
184
186
  (0, import_node_child_process.exec)(
185
187
  util.format(process.platform === "win32" ? 'tasklist /fi "PID eq %s" | findstr /i "node.exe"' : 'ps -f -p %s | grep "node"', pid),
188
+ { windowsHide: true },
186
189
  function(err, stdout, stderr) {
187
190
  resolve(!err && !!stdout.toString().trim());
188
191
  }
@@ -285,45 +288,18 @@ var initSqlite3 = () => {
285
288
  logSuccess(`[i] SQLite file initialized successfully!`);
286
289
  }
287
290
  };
288
- var renderKernelProgress = (result) => {
289
- const status = result.status || "pending";
290
- const progress = ["completed", "installing"].includes(status) ? 100 : Math.max(0, Math.min(100, Number(result.progress) || 0));
291
- if (!process.stdout.isTTY) {
292
- logInfo(`Kernel progress: ${progress}% [${status}]`);
293
- return;
294
- }
295
- const width = 30;
296
- const filled = Math.round(progress / 100 * width);
297
- const bar = `${"=".repeat(filled)}${"-".repeat(width - filled)}`;
298
- process.stdout.write(`\r[${bar}] ${progress.toFixed(0).padStart(3, " ")}% ${status} `);
299
- };
300
- var finishKernelProgress = () => {
301
- if (process.stdout.isTTY) {
302
- process.stdout.write("\n");
291
+
292
+ // src/core/start.ts
293
+ var getRuntimeExecArgv = () => {
294
+ if (process.platform !== "win32") {
295
+ return [];
303
296
  }
304
- };
305
- var trackKernelDownload = async (fnc, args) => {
306
- while (true) {
307
- const result = await fnc(args);
308
- try {
309
- const resultJson = JSON.parse(result.replace("Kernel download/update status: ", ""));
310
- if (resultJson && resultJson.status && ["pending", "downloading", "completed", "installing", "failed"].includes(resultJson.status)) {
311
- renderKernelProgress(resultJson);
312
- if (["completed", "failed"].includes(resultJson.status)) {
313
- finishKernelProgress();
314
- return result;
315
- }
316
- await sleepTime(3e3);
317
- } else {
318
- return result;
319
- }
320
- } catch (error) {
321
- return result;
322
- }
297
+ const preload = path2.join(__dirname, "core/winHideChildProcess.js");
298
+ if (!fs2.existsSync(preload)) {
299
+ return [];
323
300
  }
301
+ return ["--require", preload];
324
302
  };
325
-
326
- // src/core/start.ts
327
303
  var getEnv = () => {
328
304
  const env = {
329
305
  ...process.env,
@@ -364,7 +340,8 @@ var startChild = (type) => {
364
340
  detached: true,
365
341
  windowsHide: true,
366
342
  // 隐藏子进程的控制台窗口
367
- stdio: ["ignore", "ignore", "ignore", "ipc"]
343
+ stdio: ["ignore", "ignore", "ignore", "ipc"],
344
+ execArgv: getRuntimeExecArgv()
368
345
  };
369
346
  child = (0, import_node_child_process2.fork)(mainJs, [], forkOptions);
370
347
  ensureBrowserPath();
@@ -547,9 +524,6 @@ var getChildStatus = async () => {
547
524
  }
548
525
  };
549
526
 
550
- // src/index.ts
551
- var import_colors2 = require("colors");
552
-
553
527
  // ../core/src/constants/api.ts
554
528
  var import_axios = __toESM(require("axios"));
555
529
 
@@ -1401,39 +1375,33 @@ var browserHandlers = {
1401
1375
  const requestBody = buildRequestBodyFor("open-browser", resolvedParams);
1402
1376
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.START_BROWSER}`, requestBody);
1403
1377
  if (response.data.code === 0) {
1404
- const autoNote = didAutoSetHeadless ? "\n\u5DF2\u6839\u636E\u8FD0\u884C\u73AF\u5883\u81EA\u52A8\u4F7F\u7528 headless=1\uFF08\u65E0\u53EF\u7528\u56FE\u5F62\u4F1A\u8BDD\uFF09\u3002\nAuto-set headless=1 (no graphical session detected)." : "";
1405
- return `Browser opened successfully with: ${Object.entries(response.data.data).map(([key, value]) => {
1406
- if (value && typeof value === "object") {
1407
- return Object.entries(value).map(([key2, value2]) => `ws.${key2}: ${value2}`).join("\n");
1408
- }
1409
- return `${key}: ${value}`;
1410
- }).join("\n")}${autoNote}`;
1378
+ return JSON.stringify(response.data.data, null, 2);
1411
1379
  }
1412
- throw new Error(`Failed to open browser: ${response.data.msg}`);
1380
+ throw new Error(response.data.msg);
1413
1381
  },
1414
1382
  async closeBrowser(params) {
1415
1383
  const requestBody = buildRequestBodyFor("close-browser", params);
1416
1384
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.CLOSE_BROWSER}`, requestBody);
1417
1385
  if (response.data.code === 0) {
1418
- return "Browser closed successfully";
1386
+ return JSON.stringify(response.data.data, null, 2);
1419
1387
  }
1420
- throw new Error(`Failed to close browser: ${response.data.msg}`);
1388
+ throw new Error(response.data.msg);
1421
1389
  },
1422
1390
  async createBrowser(params) {
1423
1391
  const requestBody = buildRequestBodyFor("create-browser", params);
1424
1392
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.CREATE_BROWSER}`, requestBody);
1425
1393
  if (response.data.code === 0) {
1426
- return `Browser created successfully with: ${Object.entries(response.data.data).map(([key, value]) => `${key}: ${value}`).join("\n")}`;
1394
+ return JSON.stringify(response.data.data, null, 2);
1427
1395
  }
1428
- throw new Error(`Failed to create browser: ${response.data.msg}`);
1396
+ throw new Error(response.data.msg);
1429
1397
  },
1430
1398
  async updateBrowser(params) {
1431
1399
  const requestBody = buildRequestBodyFor("update-browser", params);
1432
1400
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.UPDATE_BROWSER}`, requestBody);
1433
1401
  if (response.data.code === 0) {
1434
- return `Browser updated successfully with: ${Object.entries(response.data.data || {}).map(([key, value]) => `${key}: ${value}`).join("\n")}`;
1402
+ return JSON.stringify(response.data.data, null, 2);
1435
1403
  }
1436
- throw new Error(`Failed to update browser: ${response.data.msg}`);
1404
+ throw new Error(response.data.msg);
1437
1405
  },
1438
1406
  async deleteBrowser(params) {
1439
1407
  const response = await getApiClient().post(
@@ -1441,64 +1409,63 @@ var browserHandlers = {
1441
1409
  buildRequestBodyFor("delete-browser", params)
1442
1410
  );
1443
1411
  if (response.data.code === 0) {
1444
- return `Browsers deleted successfully: ${params.profile_id.join(", ")}`;
1412
+ return JSON.stringify(response.data.data, null, 2);
1445
1413
  }
1446
- throw new Error(`Failed to delete browsers: ${response.data.msg}`);
1414
+ throw new Error(response.data.msg);
1447
1415
  },
1448
1416
  async getBrowserList(params) {
1449
1417
  const requestBody = buildRequestBodyFor("get-browser-list", params);
1450
1418
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.GET_BROWSER_LIST}`, requestBody);
1451
1419
  if (response.data.code === 0) {
1452
- return `Browser list: ${JSON.stringify(response.data.data.list, null, 2)}`;
1420
+ return JSON.stringify(response.data.data, null, 2);
1453
1421
  }
1454
- throw new Error(`Failed to get browser list: ${response.data.msg}`);
1422
+ throw new Error(response.data.msg);
1455
1423
  },
1456
1424
  async getOpenedBrowser() {
1457
1425
  const response = await getApiClient().get(`${getLocalApiBase()}${API_ENDPOINTS.GET_OPENED_BROWSER}`);
1458
1426
  if (response.data.code === 0) {
1459
- return `Opened browser list: ${JSON.stringify(response.data.data.list, null, 2)}`;
1427
+ return JSON.stringify(response.data.data, null, 2);
1460
1428
  }
1461
- throw new Error(`Failed to get opened browsers: ${response.data.msg}`);
1429
+ throw new Error(response.data.msg);
1462
1430
  },
1463
1431
  async moveBrowser(params) {
1464
1432
  const requestBody = buildRequestBodyFor("move-browser", params);
1465
1433
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.MOVE_BROWSER}`, requestBody);
1466
- const { group_id, user_ids } = params;
1467
1434
  if (response.data.code === 0) {
1468
- return `Browsers moved successfully to group ${group_id}: ${user_ids.join(", ")}`;
1435
+ return JSON.stringify(response.data.data, null, 2);
1469
1436
  }
1470
- throw new Error(`Failed to move browsers: ${response.data.msg}`);
1437
+ throw new Error(response.data.msg);
1471
1438
  },
1472
1439
  async getProfileCookies(params) {
1473
1440
  const query = buildQueryParamsFor("get-profile-cookies", params);
1474
1441
  const response = await getApiClient().get(`${getLocalApiBase()}${API_ENDPOINTS.GET_PROFILE_COOKIES}`, { params: query });
1475
1442
  if (response.data.code === 0) {
1476
- return `Profile cookies: ${JSON.stringify(response.data.data, null, 2)}`;
1443
+ return JSON.stringify(response.data.data, null, 2);
1477
1444
  }
1478
- throw new Error(`Failed to get profile cookies: ${response.data.msg}`);
1445
+ throw new Error(response.data.msg);
1479
1446
  },
1480
1447
  async getProfileUa(params) {
1481
1448
  const requestBody = buildRequestBodyFor("get-profile-ua", params);
1482
1449
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.GET_PROFILE_UA}`, requestBody);
1483
1450
  if (response.data.code === 0) {
1484
- return `Profile User-Agent: ${JSON.stringify(response.data.data, null, 2)}`;
1451
+ return JSON.stringify(response.data.data, null, 2);
1485
1452
  }
1486
- throw new Error(`Failed to get profile User-Agent: ${response.data.msg}`);
1453
+ throw new Error(response.data.msg);
1487
1454
  },
1488
1455
  async closeAllProfiles(_params) {
1489
1456
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.CLOSE_ALL_PROFILES}`, {});
1490
- if (response.data.code === 0) {
1491
- return "All profiles closed successfully";
1457
+ if (response.data.data.code === 0) {
1458
+ return JSON.stringify(response.data.data, null, 2);
1492
1459
  }
1493
- throw new Error(`Failed to close all profiles: ${response.data.msg}`);
1460
+ throw new Error(response.data.data.msg);
1494
1461
  },
1495
1462
  async newFingerprint(params) {
1496
1463
  const requestBody = buildRequestBodyFor("new-fingerprint", params);
1497
1464
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.NEW_FINGERPRINT}`, requestBody);
1498
1465
  if (response.data.code === 0) {
1499
- return `New fingerprint created: ${JSON.stringify(response.data.data, null, 2)}`;
1466
+ return JSON.stringify(response.data.data, null, 2);
1500
1467
  }
1501
- throw new Error(`Failed to create new fingerprint: ${response.data.msg}`);
1468
+ throw new Error(response.data.msg);
1502
1469
  },
1503
1470
  async deleteCacheV2(params) {
1504
1471
  const response = await getApiClient().post(
@@ -1506,33 +1473,33 @@ var browserHandlers = {
1506
1473
  buildRequestBodyFor("delete-cache-v2", params)
1507
1474
  );
1508
1475
  if (response.data.code === 0) {
1509
- return `Cache deleted successfully for profiles: ${params.profile_id.join(", ")}`;
1476
+ return JSON.stringify(response.data.data, null, 2);
1510
1477
  }
1511
- throw new Error(`Failed to delete cache: ${response.data.msg}`);
1478
+ throw new Error(response.data.msg);
1512
1479
  },
1513
1480
  async shareProfile(params) {
1514
1481
  const requestBody = buildRequestBodyFor("share-profile", params);
1515
1482
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.SHARE_PROFILE}`, requestBody);
1516
1483
  if (response.data.code === 0) {
1517
- return `Profiles shared successfully: ${params.profile_id.join(", ")}`;
1484
+ return JSON.stringify(response.data.data, null, 2);
1518
1485
  }
1519
- throw new Error(`Failed to share profiles: ${response.data.msg}`);
1486
+ throw new Error(response.data.msg);
1520
1487
  },
1521
1488
  async getBrowserActive(params) {
1522
1489
  const query = buildQueryParamsFor("get-browser-active", params);
1523
1490
  const response = await getApiClient().get(`${getLocalApiBase()}${API_ENDPOINTS.GET_BROWSER_ACTIVE}`, { params: query });
1524
1491
  if (response.data.code === 0) {
1525
- return `Browser active info: ${JSON.stringify(response.data.data, null, 2)}`;
1492
+ return JSON.stringify(response.data.data, null, 2);
1526
1493
  }
1527
- throw new Error(`Failed to get browser active: ${response.data.msg}`);
1494
+ throw new Error(response.data.msg);
1528
1495
  },
1529
1496
  async getCloudActive(params) {
1530
1497
  const requestBody = buildRequestBodyFor("get-cloud-active", params);
1531
1498
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.GET_CLOUD_ACTIVE}`, requestBody);
1532
1499
  if (response.data.code === 0) {
1533
- return `Cloud active browsers: ${JSON.stringify(response.data.data, null, 2)}`;
1500
+ return JSON.stringify(response.data.data, null, 2);
1534
1501
  }
1535
- throw new Error(`Failed to get cloud active browsers: ${response.data.msg}`);
1502
+ throw new Error(response.data.msg);
1536
1503
  }
1537
1504
  };
1538
1505
 
@@ -1541,28 +1508,26 @@ var groupHandlers = {
1541
1508
  async createGroup(params) {
1542
1509
  const requestBody = buildRequestBodyFor("create-group", params);
1543
1510
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.CREATE_GROUP}`, requestBody);
1544
- const { group_name, remark } = params;
1545
1511
  if (response.data.code === 0) {
1546
- return `Group created successfully with name: ${group_name}${remark ? `, remark: ${remark}` : ""}`;
1512
+ return JSON.stringify(response.data.data, null, 2);
1547
1513
  }
1548
- throw new Error(`Failed to create group: ${response.data.msg}`);
1514
+ throw new Error(response.data.msg);
1549
1515
  },
1550
1516
  async updateGroup(params) {
1551
1517
  const requestBody = buildRequestBodyFor("update-group", params);
1552
1518
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.UPDATE_GROUP}`, requestBody);
1553
- const { group_id, group_name, remark } = params;
1554
1519
  if (response.data.code === 0) {
1555
- return `Group updated successfully with id: ${group_id}, name: ${group_name}${remark !== void 0 ? `, remark: ${remark === null ? "(cleared)" : remark}` : ""}`;
1520
+ return JSON.stringify(response.data.data, null, 2);
1556
1521
  }
1557
- throw new Error(`Failed to update group: ${response.data.msg}`);
1522
+ throw new Error(response.data.msg);
1558
1523
  },
1559
1524
  async getGroupList(params) {
1560
1525
  const query = buildQueryParamsFor("get-group-list", params);
1561
1526
  const response = await getApiClient().get(`${getLocalApiBase()}${API_ENDPOINTS.GET_GROUP_LIST}`, { params: query });
1562
1527
  if (response.data.code === 0) {
1563
- return `Group list: ${JSON.stringify(response.data.data.list, null, 2)}`;
1528
+ return JSON.stringify(response.data.data, null, 2);
1564
1529
  }
1565
- throw new Error(`Failed to get group list: ${response.data.msg}`);
1530
+ throw new Error(response.data.msg);
1566
1531
  }
1567
1532
  };
1568
1533
 
@@ -1570,12 +1535,12 @@ var groupHandlers = {
1570
1535
  var applicationHandlers = {
1571
1536
  async checkStatus() {
1572
1537
  const response = await getApiClient().get(`${getLocalApiBase()}${API_ENDPOINTS.STATUS}`);
1573
- return `Connection status: ${JSON.stringify(response.data, null, 2)}`;
1538
+ return JSON.stringify(response.data, null, 2);
1574
1539
  },
1575
1540
  async getApplicationList(params) {
1576
1541
  const query = buildQueryParamsFor("get-application-list", params);
1577
1542
  const response = await getApiClient().get(`${getLocalApiBase()}${API_ENDPOINTS.GET_APPLICATION_LIST}`, { params: query });
1578
- return `Application list: ${JSON.stringify(response.data.data.list, null, 2)}`;
1543
+ return JSON.stringify(response.data.data, null, 2);
1579
1544
  }
1580
1545
  };
1581
1546
 
@@ -1607,25 +1572,25 @@ var proxyHandlers = {
1607
1572
  const requestBody = params.map((proxy) => buildCreateProxyRequestBody(proxy));
1608
1573
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.CREATE_PROXY}`, requestBody);
1609
1574
  if (response.data.code === 0) {
1610
- return `Proxy created successfully with: ${Object.entries(response.data.data || {}).map(([key, value]) => `${key}: ${value}`).join("\n")}`;
1575
+ return JSON.stringify(response.data.data, null, 2);
1611
1576
  }
1612
- throw new Error(`Failed to create proxy: ${response.data.msg}`);
1577
+ throw new Error(response.data.msg);
1613
1578
  },
1614
1579
  async updateProxy(params) {
1615
1580
  const requestBody = buildRequestBodyFor("update-proxy", params);
1616
1581
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.UPDATE_PROXY}`, requestBody);
1617
1582
  if (response.data.code === 0) {
1618
- return `Proxy updated successfully with: ${Object.entries(response.data.data || {}).map(([key, value]) => `${key}: ${value}`).join("\n")}`;
1583
+ return JSON.stringify(response.data.data, null, 2);
1619
1584
  }
1620
- throw new Error(`Failed to update proxy: ${response.data.msg}`);
1585
+ throw new Error(response.data.msg);
1621
1586
  },
1622
1587
  async getProxyList(params) {
1623
1588
  const requestBody = buildRequestBodyFor("get-proxy-list", params);
1624
1589
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.GET_PROXY_LIST}`, requestBody);
1625
1590
  if (response.data.code === 0) {
1626
- return `Proxy list: ${JSON.stringify(response.data.data.list || response.data.data, null, 2)}`;
1591
+ return JSON.stringify(response.data.data, null, 2);
1627
1592
  }
1628
- throw new Error(`Failed to get proxy list: ${response.data.msg}`);
1593
+ throw new Error(response.data.msg);
1629
1594
  },
1630
1595
  async deleteProxy(params) {
1631
1596
  const response = await getApiClient().post(
@@ -1634,9 +1599,9 @@ var proxyHandlers = {
1634
1599
  );
1635
1600
  const { proxy_id } = params;
1636
1601
  if (response.data.code === 0) {
1637
- return `Proxies deleted successfully: ${proxy_id.join(", ")}`;
1602
+ return JSON.stringify(response.data.data, null, 2);
1638
1603
  }
1639
- throw new Error(`Failed to delete proxies: ${response.data.msg}`);
1604
+ throw new Error(response.data.msg);
1640
1605
  }
1641
1606
  };
1642
1607
 
@@ -1656,30 +1621,30 @@ var tagHandlers = {
1656
1621
  }
1657
1622
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.GET_TAG_LIST}`, requestBody);
1658
1623
  if (response.data.code === 0) {
1659
- return `Tag list: ${JSON.stringify(response.data.data.list || response.data.data, null, 2)}`;
1624
+ return JSON.stringify(response.data.data, null, 2);
1660
1625
  }
1661
- throw new Error(`Failed to get tag list: ${response.data.msg}`);
1626
+ throw new Error(response.data.msg);
1662
1627
  },
1663
1628
  async createTag({ tags }) {
1664
1629
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.CREATE_TAG}`, { tags });
1665
1630
  if (response.data.code === 0) {
1666
- return `Tags created successfully: ${JSON.stringify(response.data.data, null, 2)}`;
1631
+ return JSON.stringify(response.data.data, null, 2);
1667
1632
  }
1668
- throw new Error(`Failed to create tags: ${response.data.msg}`);
1633
+ throw new Error(response.data.msg);
1669
1634
  },
1670
1635
  async updateTag({ tags }) {
1671
1636
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.UPDATE_TAG}`, { tags });
1672
1637
  if (response.data.code === 0) {
1673
- return `Tags updated successfully: ${JSON.stringify(response.data.data, null, 2)}`;
1638
+ return JSON.stringify(response.data.data, null, 2);
1674
1639
  }
1675
- throw new Error(`Failed to update tags: ${response.data.msg}`);
1640
+ throw new Error(response.data.msg);
1676
1641
  },
1677
1642
  async deleteTag({ ids }) {
1678
1643
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.DELETE_TAG}`, { ids });
1679
1644
  if (response.data.code === 0) {
1680
- return `Tags deleted successfully: ${ids.join(", ")}`;
1645
+ return JSON.stringify(response.data.data, null, 2);
1681
1646
  }
1682
- throw new Error(`Failed to delete tags: ${response.data.msg}`);
1647
+ throw new Error(response.data.msg);
1683
1648
  }
1684
1649
  };
1685
1650
 
@@ -1748,9 +1713,9 @@ var kernelHandlers = {
1748
1713
  kernel_version
1749
1714
  });
1750
1715
  if (response.data.code === 0) {
1751
- return `Kernel download/update status: ${JSON.stringify(response.data.data, null, 2)}`;
1716
+ return JSON.stringify(response.data.data, null, 2);
1752
1717
  }
1753
- throw new Error(`Failed to download/update kernel: ${response.data.msg}`);
1718
+ throw new Error(response.data.msg);
1754
1719
  },
1755
1720
  async getKernelList({ kernel_type }) {
1756
1721
  const params = new URLSearchParams();
@@ -1759,9 +1724,9 @@ var kernelHandlers = {
1759
1724
  }
1760
1725
  const response = await getApiClient().get(`${getLocalApiBase()}${API_ENDPOINTS.GET_KERNEL_LIST}`, { params });
1761
1726
  if (response.data.code === 0) {
1762
- return `Kernel list: ${JSON.stringify(response.data.data.list || response.data.data, null, 2)}`;
1727
+ return JSON.stringify(response.data.data, null, 2);
1763
1728
  }
1764
- throw new Error(`Failed to get kernel list: ${response.data.msg}`);
1729
+ throw new Error(response.data.msg);
1765
1730
  }
1766
1731
  };
1767
1732
 
@@ -1774,9 +1739,9 @@ var patchHandlers = {
1774
1739
  }
1775
1740
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.UPDATE_PATCH}`, requestBody);
1776
1741
  if (response.data.code === 0) {
1777
- return `Patch update status: ${JSON.stringify(response.data.data, null, 2)}, message: ${response.data.msg}`;
1742
+ return JSON.stringify(response.data.data, null, 2);
1778
1743
  }
1779
- throw new Error(`Failed to update patch: ${response.data.msg}`);
1744
+ throw new Error(response.data.msg);
1780
1745
  }
1781
1746
  };
1782
1747
 
@@ -2537,167 +2502,258 @@ var schemas = {
2537
2502
  };
2538
2503
 
2539
2504
  // src/cli.ts
2505
+ function formatJsonValueForHelp(value, indent) {
2506
+ const pad = " ".repeat(indent);
2507
+ const childPad = " ".repeat(indent + 1);
2508
+ if (value === null || typeof value !== "object") {
2509
+ return JSON.stringify(value);
2510
+ }
2511
+ if (Array.isArray(value)) {
2512
+ if (value.length === 0) {
2513
+ return "[]";
2514
+ }
2515
+ const lines2 = value.map((item) => `${childPad}${formatJsonValueForHelp(item, indent + 1)}`);
2516
+ return `[
2517
+ ${lines2.join(",\n")}
2518
+ ${pad}]`;
2519
+ }
2520
+ const entries = Object.entries(value);
2521
+ if (entries.length === 0) {
2522
+ return "{}";
2523
+ }
2524
+ const lines = entries.map(([key, val]) => {
2525
+ if (["enum", "oneOf", "required"].includes(key) && Array.isArray(val)) {
2526
+ return `${childPad}${JSON.stringify(key)}: ${JSON.stringify(val)}`;
2527
+ }
2528
+ return `${childPad}${JSON.stringify(key)}: ${formatJsonValueForHelp(val, indent + 1)}`;
2529
+ });
2530
+ return `{
2531
+ ${lines.join(",\n")}
2532
+ ${pad}}`;
2533
+ }
2534
+ function formatSchemaPropertiesForHelp(properties) {
2535
+ return formatJsonValueForHelp(properties, 0);
2536
+ }
2537
+ function schemaParamsDescription(schema, type) {
2538
+ let paramStr = "view help: https://documenter.getpostman.com/view/45822952/2sB2x5JDXn\n";
2539
+ switch (type) {
2540
+ case "open-browser":
2541
+ paramStr += `use cmd: "ads open-browser <profile_id>"
2542
+ or use params: "ads open-browser '{"profile_id":"..."}' "
2543
+ `;
2544
+ break;
2545
+ case "close-browser":
2546
+ paramStr += `use cmd: "ads close-browser <profile_id>"
2547
+ or use params: "ads close-browser '{"profile_id":"..."}' "
2548
+ `;
2549
+ break;
2550
+ case "get-profile-cookies":
2551
+ paramStr += `use cmd: "ads get-profile-cookies <profile_id>"
2552
+ or use params: "ads get-profile-cookies '{"profile_id":"..."}' "
2553
+ `;
2554
+ break;
2555
+ case "get-browser-active":
2556
+ paramStr += `use cmd: "ads get-browser-active <profile_id>"
2557
+ or use params: "ads get-browser-active '{"profile_id":"..."}' "
2558
+ `;
2559
+ break;
2560
+ }
2561
+ const _str = formatSchemaPropertiesForHelp(schema.toJSONSchema().properties);
2562
+ return paramStr + _str;
2563
+ }
2540
2564
  var STATELESS_HANDLERS = {
2541
2565
  "open-browser": {
2542
2566
  fn: browserHandlers.openBrowser,
2543
2567
  description: buildCliCommandDescription(
2544
2568
  "open-browser",
2545
2569
  "Open the browser, both environment and profile mean browser"
2546
- )
2570
+ ),
2571
+ paramsDescription: schemaParamsDescription(schemas.openBrowserSchema, "open-browser")
2547
2572
  },
2548
2573
  "close-browser": {
2549
2574
  fn: browserHandlers.closeBrowser,
2550
- description: buildCliCommandDescription("close-browser", "Close the browser")
2575
+ description: buildCliCommandDescription("close-browser", "Close the browser"),
2576
+ paramsDescription: schemaParamsDescription(schemas.closeBrowserSchema, "close-browser")
2551
2577
  },
2552
2578
  "create-browser": {
2553
2579
  fn: browserHandlers.createBrowser,
2554
- description: buildCliCommandDescription("create-browser", "Create a browser")
2580
+ description: buildCliCommandDescription("create-browser", "Create a browser"),
2581
+ paramsDescription: schemaParamsDescription(schemas.createBrowserSchema, "create-browser")
2555
2582
  },
2556
2583
  "update-browser": {
2557
2584
  fn: browserHandlers.updateBrowser,
2558
- description: buildCliCommandDescription("update-browser", "Update the browser")
2585
+ description: buildCliCommandDescription("update-browser", "Update the browser"),
2586
+ paramsDescription: schemaParamsDescription(schemas.updateBrowserSchema, "update-browser")
2559
2587
  },
2560
2588
  "delete-browser": {
2561
2589
  fn: browserHandlers.deleteBrowser,
2562
- description: buildCliCommandDescription("delete-browser", "Delete the browser")
2590
+ description: buildCliCommandDescription("delete-browser", "Delete the browser"),
2591
+ paramsDescription: schemaParamsDescription(schemas.deleteBrowserSchema, "delete-browser")
2563
2592
  },
2564
2593
  "get-browser-list": {
2565
2594
  fn: browserHandlers.getBrowserList,
2566
- description: buildCliCommandDescription("get-browser-list", "Get the list of browsers")
2595
+ description: buildCliCommandDescription("get-browser-list", "Get the list of browsers"),
2596
+ paramsDescription: schemaParamsDescription(schemas.getBrowserListSchema, "get-browser-list")
2567
2597
  },
2568
2598
  "get-opened-browser": {
2569
2599
  fn: browserHandlers.getOpenedBrowser,
2570
- description: buildCliCommandDescription("get-opened-browser", "Get the list of opened browsers")
2600
+ description: buildCliCommandDescription("get-opened-browser", "Get the list of opened browsers"),
2601
+ paramsDescription: schemaParamsDescription(schemas.emptySchema, "get-opened-browser")
2571
2602
  },
2572
2603
  "move-browser": {
2573
2604
  fn: browserHandlers.moveBrowser,
2574
- description: buildCliCommandDescription("move-browser", "Move browsers to a group")
2605
+ description: buildCliCommandDescription("move-browser", "Move browsers to a group"),
2606
+ paramsDescription: schemaParamsDescription(schemas.moveBrowserSchema, "move-browser")
2575
2607
  },
2576
2608
  "get-profile-cookies": {
2577
2609
  fn: browserHandlers.getProfileCookies,
2578
2610
  description: buildCliCommandDescription(
2579
2611
  "get-profile-cookies",
2580
2612
  "Query and return cookies of the specified profile. Only one profile can be queried per request."
2581
- )
2613
+ ),
2614
+ paramsDescription: schemaParamsDescription(schemas.getProfileCookiesSchema, "get-profile-cookies")
2582
2615
  },
2583
2616
  "get-profile-ua": {
2584
2617
  fn: browserHandlers.getProfileUa,
2585
2618
  description: buildCliCommandDescription(
2586
2619
  "get-profile-ua",
2587
2620
  "Query and return the User-Agent of specified profiles. Up to 10 profiles can be queried per request."
2588
- )
2621
+ ),
2622
+ paramsDescription: schemaParamsDescription(schemas.getProfileUaSchema, "get-profile-ua")
2589
2623
  },
2590
2624
  "close-all-profiles": {
2591
2625
  fn: browserHandlers.closeAllProfiles,
2592
2626
  description: buildCliCommandDescription(
2593
2627
  "close-all-profiles",
2594
2628
  "Close all opened profiles on the current device"
2595
- )
2629
+ ),
2630
+ paramsDescription: schemaParamsDescription(schemas.closeAllProfilesSchema, "close-all-profiles")
2596
2631
  },
2597
2632
  "new-fingerprint": {
2598
2633
  fn: browserHandlers.newFingerprint,
2599
2634
  description: buildCliCommandDescription(
2600
2635
  "new-fingerprint",
2601
2636
  "Generate a new fingerprint for specified profiles. Up to 10 profiles are supported per request."
2602
- )
2637
+ ),
2638
+ paramsDescription: schemaParamsDescription(schemas.newFingerprintSchema, "new-fingerprint")
2603
2639
  },
2604
2640
  "delete-cache-v2": {
2605
2641
  fn: browserHandlers.deleteCacheV2,
2606
2642
  description: buildCliCommandDescription(
2607
2643
  "delete-cache-v2",
2608
2644
  "Clear local cache of specific profiles.For account security, please ensure that there are no open browsers on the device when using this interface."
2609
- )
2645
+ ),
2646
+ paramsDescription: schemaParamsDescription(schemas.deleteCacheV2Schema, "delete-cache-v2")
2610
2647
  },
2611
2648
  "share-profile": {
2612
2649
  fn: browserHandlers.shareProfile,
2613
2650
  description: buildCliCommandDescription(
2614
2651
  "share-profile",
2615
2652
  "Share profiles via account email or phone number. The maximum number of profiles that can be shared at one time is 200."
2616
- )
2653
+ ),
2654
+ paramsDescription: schemaParamsDescription(schemas.shareProfileSchema, "share-profile")
2617
2655
  },
2618
2656
  "get-browser-active": {
2619
2657
  fn: browserHandlers.getBrowserActive,
2620
- description: buildCliCommandDescription("get-browser-active", "Get active browser profile information")
2658
+ description: buildCliCommandDescription("get-browser-active", "Get active browser profile information"),
2659
+ paramsDescription: schemaParamsDescription(schemas.getBrowserActiveSchema, "get-browser-active")
2621
2660
  },
2622
2661
  "get-cloud-active": {
2623
2662
  fn: browserHandlers.getCloudActive,
2624
2663
  description: buildCliCommandDescription(
2625
2664
  "get-cloud-active",
2626
2665
  'Query the status of browser profiles by user_ids, up to 100 profiles per request. If the team has enabled "Multi device mode," specific statuses cannot be retrieved and the response will indicate "Profile not opened."'
2627
- )
2666
+ ),
2667
+ paramsDescription: schemaParamsDescription(schemas.getCloudActiveSchema, "get-cloud-active")
2628
2668
  },
2629
2669
  "create-group": {
2630
2670
  fn: groupHandlers.createGroup,
2631
- description: buildCliCommandDescription("create-group", "Create a browser group")
2671
+ description: buildCliCommandDescription("create-group", "Create a browser group"),
2672
+ paramsDescription: schemaParamsDescription(schemas.createGroupSchema, "create-group")
2632
2673
  },
2633
2674
  "update-group": {
2634
2675
  fn: groupHandlers.updateGroup,
2635
- description: buildCliCommandDescription("update-group", "Update the browser group")
2676
+ description: buildCliCommandDescription("update-group", "Update the browser group"),
2677
+ paramsDescription: schemaParamsDescription(schemas.updateGroupSchema, "update-group")
2636
2678
  },
2637
2679
  "get-group-list": {
2638
2680
  fn: groupHandlers.getGroupList,
2639
- description: buildCliCommandDescription("get-group-list", "Get the list of groups")
2681
+ description: buildCliCommandDescription("get-group-list", "Get the list of groups"),
2682
+ paramsDescription: schemaParamsDescription(schemas.getGroupListSchema, "get-group-list")
2640
2683
  },
2641
2684
  "check-status": {
2642
2685
  fn: applicationHandlers.checkStatus,
2643
2686
  description: buildCliCommandDescription(
2644
2687
  "check-status",
2645
2688
  "Check the availability of the current device API interface (Connection Status)"
2646
- )
2689
+ ),
2690
+ paramsDescription: schemaParamsDescription(schemas.emptySchema, "check-status")
2647
2691
  },
2648
2692
  "get-application-list": {
2649
2693
  fn: applicationHandlers.getApplicationList,
2650
2694
  description: buildCliCommandDescription(
2651
2695
  "get-application-list",
2652
2696
  "Get the list of applications (categories)"
2653
- )
2697
+ ),
2698
+ paramsDescription: schemaParamsDescription(schemas.getApplicationListSchema, "get-application-list")
2654
2699
  },
2655
2700
  "create-proxy": {
2656
2701
  fn: proxyHandlers.createProxy,
2657
- description: buildCliCommandDescription("create-proxy", "Create the proxy")
2702
+ description: buildCliCommandDescription("create-proxy", "Create the proxy"),
2703
+ paramsDescription: schemaParamsDescription(schemas.createProxySchema, "create-proxy")
2658
2704
  },
2659
2705
  "update-proxy": {
2660
2706
  fn: proxyHandlers.updateProxy,
2661
- description: buildCliCommandDescription("update-proxy", "Update the proxy")
2707
+ description: buildCliCommandDescription("update-proxy", "Update the proxy"),
2708
+ paramsDescription: schemaParamsDescription(schemas.updateProxySchema, "update-proxy")
2662
2709
  },
2663
2710
  "get-proxy-list": {
2664
2711
  fn: proxyHandlers.getProxyList,
2665
- description: buildCliCommandDescription("get-proxy-list", "Get the list of proxies")
2712
+ description: buildCliCommandDescription("get-proxy-list", "Get the list of proxies"),
2713
+ paramsDescription: schemaParamsDescription(schemas.getProxyListSchema, "get-proxy-list")
2666
2714
  },
2667
2715
  "delete-proxy": {
2668
2716
  fn: proxyHandlers.deleteProxy,
2669
- description: buildCliCommandDescription("delete-proxy", "Delete the proxy")
2717
+ description: buildCliCommandDescription("delete-proxy", "Delete the proxy"),
2718
+ paramsDescription: schemaParamsDescription(schemas.deleteProxySchema, "delete-proxy")
2670
2719
  },
2671
2720
  "get-tag-list": {
2672
2721
  fn: tagHandlers.getTagList,
2673
- description: buildCliCommandDescription("get-tag-list", "Get the list of browser tags")
2722
+ description: buildCliCommandDescription("get-tag-list", "Get the list of browser tags"),
2723
+ paramsDescription: schemaParamsDescription(schemas.getTagListSchema, "get-tag-list")
2674
2724
  },
2675
2725
  "create-tag": {
2676
2726
  fn: tagHandlers.createTag,
2677
- description: buildCliCommandDescription("create-tag", "Create browser tags (batch supported)")
2727
+ description: buildCliCommandDescription("create-tag", "Create browser tags (batch supported)"),
2728
+ paramsDescription: schemaParamsDescription(schemas.createTagSchema, "create-tag")
2678
2729
  },
2679
2730
  "update-tag": {
2680
2731
  fn: tagHandlers.updateTag,
2681
- description: buildCliCommandDescription("update-tag", "Update browser tags (batch supported)")
2732
+ description: buildCliCommandDescription("update-tag", "Update browser tags (batch supported)"),
2733
+ paramsDescription: schemaParamsDescription(schemas.updateTagSchema, "update-tag")
2682
2734
  },
2683
2735
  "delete-tag": {
2684
2736
  fn: tagHandlers.deleteTag,
2685
- description: buildCliCommandDescription("delete-tag", "Delete browser tags")
2737
+ description: buildCliCommandDescription("delete-tag", "Delete browser tags"),
2738
+ paramsDescription: schemaParamsDescription(schemas.deleteTagSchema, "delete-tag")
2686
2739
  },
2687
2740
  "download-kernel": {
2688
2741
  fn: kernelHandlers.downloadKernel,
2689
2742
  description: buildCliCommandDescription(
2690
2743
  "download-kernel",
2691
2744
  "Download or update a browser kernel version"
2692
- )
2745
+ ),
2746
+ paramsDescription: schemaParamsDescription(schemas.downloadKernelSchema, "download-kernel")
2693
2747
  },
2694
2748
  "get-kernel-list": {
2695
2749
  fn: kernelHandlers.getKernelList,
2696
- description: buildCliCommandDescription("get-kernel-list", "Get browser kernel list by type or all")
2750
+ description: buildCliCommandDescription("get-kernel-list", "Get browser kernel list by type or all"),
2751
+ paramsDescription: schemaParamsDescription(schemas.getKernelListSchema, "get-kernel-list")
2697
2752
  },
2698
2753
  "update-patch": {
2699
2754
  fn: patchHandlers.updatePatch,
2700
- description: buildCliCommandDescription("update-patch", "Update AdsPower to latest patch version")
2755
+ description: buildCliCommandDescription("update-patch", "Update AdsPower to latest patch version"),
2756
+ paramsDescription: schemaParamsDescription(schemas.updatePatchSchema, "update-patch")
2701
2757
  }
2702
2758
  };
2703
2759
  var SINGLE_PROFILE_ID_COMMANDS = {
@@ -2765,10 +2821,242 @@ function resolveStartApiKey(optionApiKey, env = process.env) {
2765
2821
  };
2766
2822
  }
2767
2823
 
2824
+ // src/completion.ts
2825
+ var import_commander = __toESM(require("@bomb.sh/tab/commander"));
2826
+ var CLI_BIN_ALIASES = ["ads", "adspower", "adspower-browser"];
2827
+ function patchShellCompletionScript(shell, script) {
2828
+ if (shell === "zsh") {
2829
+ return script.replace(/^#compdef .+$/m, `#compdef ${CLI_BIN_ALIASES.join(" ")}`).replace(/^compdef _ads ads$/m, `compdef _ads ${CLI_BIN_ALIASES.join(" ")}`);
2830
+ }
2831
+ if (shell === "bash") {
2832
+ return script.replace(
2833
+ /^complete -F __ads_complete ads$/m,
2834
+ `complete -F __ads_complete ${CLI_BIN_ALIASES.join(" ")}`
2835
+ );
2836
+ }
2837
+ return script;
2838
+ }
2839
+ function setupShellCompletion(program2) {
2840
+ program2.name("ads");
2841
+ (0, import_commander.default)(program2);
2842
+ }
2843
+ function isShellCompletionRequest(argv = process.argv) {
2844
+ const completionIndex = argv.indexOf("complete");
2845
+ const dashDashIndex = argv.indexOf("--");
2846
+ return completionIndex !== -1 && dashDashIndex !== -1 && dashDashIndex > completionIndex;
2847
+ }
2848
+ function wrapShellScriptOutput(shell) {
2849
+ if (shell !== "zsh" && shell !== "bash") {
2850
+ return () => {
2851
+ };
2852
+ }
2853
+ const originalWrite = process.stdout.write.bind(process.stdout);
2854
+ process.stdout.write = ((chunk, encoding, callback) => {
2855
+ const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString(typeof encoding === "string" ? encoding : "utf8");
2856
+ const patched = patchShellCompletionScript(shell, text);
2857
+ if (typeof encoding === "function") {
2858
+ return originalWrite(patched, encoding);
2859
+ }
2860
+ return originalWrite(
2861
+ patched,
2862
+ encoding,
2863
+ callback
2864
+ );
2865
+ });
2866
+ return () => {
2867
+ process.stdout.write = originalWrite;
2868
+ };
2869
+ }
2870
+
2871
+ // src/handleAction.ts
2872
+ var readline = __toESM(require("readline/promises"));
2873
+ var import_colors2 = require("colors");
2874
+ var renderKernelProgress = (result) => {
2875
+ const status = result.status || "pending";
2876
+ const progress = ["completed", "installing"].includes(status) ? 100 : Math.max(0, Math.min(100, Number(result.progress) || 0));
2877
+ if (!process.stdout.isTTY) {
2878
+ logInfo(`Kernel progress: ${progress}% [${status}]`);
2879
+ return;
2880
+ }
2881
+ const width = 30;
2882
+ const filled = Math.round(progress / 100 * width);
2883
+ const bar = `${"=".repeat(filled)}${"-".repeat(width - filled)}`;
2884
+ process.stdout.write(`\r[${bar}] ${progress.toFixed(0).padStart(3, " ")}% ${status} `);
2885
+ };
2886
+ var finishKernelProgress = () => {
2887
+ if (process.stdout.isTTY) {
2888
+ process.stdout.write("\n");
2889
+ }
2890
+ };
2891
+ var trackKernelDownload = async (fnc, args) => {
2892
+ while (true) {
2893
+ const result = await fnc(args);
2894
+ try {
2895
+ const resultJson = JSON.parse(result);
2896
+ if (resultJson && resultJson.status && ["pending", "downloading", "completed", "installing", "failed"].includes(resultJson.status)) {
2897
+ renderKernelProgress(resultJson);
2898
+ if (["completed", "failed"].includes(resultJson.status)) {
2899
+ finishKernelProgress();
2900
+ return result;
2901
+ }
2902
+ await sleepTime(3e3);
2903
+ } else {
2904
+ return result;
2905
+ }
2906
+ } catch (error) {
2907
+ return result;
2908
+ }
2909
+ }
2910
+ };
2911
+ var handleAction = async (params, options, command, fnc) => {
2912
+ const isRun = await hasRunning(options);
2913
+ if (!isRun) {
2914
+ logError("[!] Adspower runtime is not running");
2915
+ const info = `[i] Please run "${(0, import_colors2.green)("adspower-browser start -k <apiKey>")}" to start the adspower runtime`;
2916
+ console.log(info);
2917
+ return;
2918
+ }
2919
+ const { apiKey, port } = getApiKeyAndPort(options);
2920
+ updateConfig(apiKey, port);
2921
+ const commandName = command.name();
2922
+ const resolved = resolveStatelessCommandArgs(commandName, params);
2923
+ if (!resolved.ok) {
2924
+ logError(resolved.error);
2925
+ return;
2926
+ }
2927
+ const args = resolved.args;
2928
+ logSuccess(`Executing command: ${commandName}, params: ${JSON.stringify(args)}`);
2929
+ const loading = createLoading(`Executing ${commandName}...`);
2930
+ try {
2931
+ if (commandName === "download-kernel") {
2932
+ loading.stop();
2933
+ const result = await trackKernelDownload(fnc, args);
2934
+ const out = typeof result === "string" ? result : JSON.stringify(result, null, 2);
2935
+ logInfo(`
2936
+
2937
+ ${out}
2938
+
2939
+ `);
2940
+ } else {
2941
+ const result = await fnc(args);
2942
+ const out = typeof result === "string" ? result : JSON.stringify(result, null, 2);
2943
+ loading.stop();
2944
+ logInfo(`
2945
+
2946
+ ${out}
2947
+ `);
2948
+ if (commandName === "update-patch" && !out.includes("The client is already on the latest patch version. No update is required")) {
2949
+ await sleepTime(1e3 * 60);
2950
+ await restartChild();
2951
+ }
2952
+ return out;
2953
+ }
2954
+ } catch (error) {
2955
+ loading.stop();
2956
+ const msg = error instanceof Error ? error.message : JSON.stringify(error);
2957
+ logError(`
2958
+ ${msg}
2959
+ `);
2960
+ await handleError(msg, commandName, params);
2961
+ } finally {
2962
+ loading.stop();
2963
+ }
2964
+ };
2965
+ var handleError = async (msg, commandName, params) => {
2966
+ if (commandName === "open-browser") {
2967
+ if (msg.includes("ready,please to download!")) {
2968
+ const reg = /(SunBrowser|FlowerBrowser) (\d+) is not ready,please to download!/;
2969
+ const match = msg.match(reg);
2970
+ if (match) {
2971
+ const kernelType = match[1] === "FlowerBrowser" ? "Firefox" : "Chrome";
2972
+ const kernelVersion = match[2];
2973
+ if (kernelType && kernelVersion) {
2974
+ const answer = await promptYesNo(`[?] Kernel ${match[1]} ${kernelVersion} is not ready. Download now?`);
2975
+ if (answer === "y") {
2976
+ const _params = { "kernel_type": kernelType, "kernel_version": kernelVersion };
2977
+ await handleAction(
2978
+ JSON.stringify(_params),
2979
+ {},
2980
+ { name: () => "download-kernel" },
2981
+ STATELESS_HANDLERS["download-kernel"].fn
2982
+ );
2983
+ await sleepTime(1e3 * 3);
2984
+ await handleAction(
2985
+ params,
2986
+ {},
2987
+ { name: () => "open-browser" },
2988
+ STATELESS_HANDLERS["open-browser"].fn
2989
+ );
2990
+ }
2991
+ }
2992
+ }
2993
+ }
2994
+ }
2995
+ if (commandName === "close-browser") {
2996
+ if (msg.includes("Profile does not exist")) {
2997
+ const answer = await promptYesNo(`[?] Profile does not exist. Check all opened profiles?`);
2998
+ if (answer === "y") {
2999
+ const result = await handleAction(
3000
+ "{}",
3001
+ {},
3002
+ { name: () => "get-opened-browser" },
3003
+ STATELESS_HANDLERS["get-opened-browser"].fn
3004
+ );
3005
+ if (result) {
3006
+ try {
3007
+ const data = JSON.parse(result);
3008
+ const userIds = data.list.map((item) => item.user_id);
3009
+ if (userIds.length === 1) {
3010
+ const answer2 = await promptYesNo(`[?] Only one opened profile. Close it now?`);
3011
+ if (answer2 === "y") {
3012
+ await handleAction(
3013
+ `{"profile_id":["${userIds[0]}"]}`,
3014
+ {},
3015
+ { name: () => "close-browser" },
3016
+ STATELESS_HANDLERS["close-browser"].fn
3017
+ );
3018
+ }
3019
+ } else if (userIds.length > 1) {
3020
+ logWarning(`[!] Closeable profiles: ${userIds.join(", ")}`);
3021
+ logWarning(`[!] If you want to close all profiles, please enter "ads close-all-profiles"`);
3022
+ }
3023
+ } catch (error) {
3024
+ console.error(error);
3025
+ }
3026
+ }
3027
+ }
3028
+ }
3029
+ }
3030
+ };
3031
+ async function promptYesNo(question) {
3032
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
3033
+ logWarning("[!] Interactive prompt is unavailable in non-interactive mode.");
3034
+ return null;
3035
+ }
3036
+ const rl = readline.createInterface({
3037
+ input: process.stdin,
3038
+ output: process.stdout
3039
+ });
3040
+ try {
3041
+ while (true) {
3042
+ const answer = (await rl.question(`${question} [y/N]: `)).trim().toLowerCase();
3043
+ if (answer === "y" || answer === "yes") {
3044
+ return "y";
3045
+ }
3046
+ if (answer === "n" || answer === "no" || answer === "") {
3047
+ return "n";
3048
+ }
3049
+ logWarning("[!] Please enter y or n.");
3050
+ }
3051
+ } finally {
3052
+ rl.close();
3053
+ }
3054
+ }
3055
+
2768
3056
  // src/index.ts
2769
- var program = new import_commander.Command();
2770
- program.name("adspower-browser").description("CLI and runtime for adspower-browser").version(VERSION);
2771
- program.command("start").description("Start the adspower runtime").option("-k, --api-key <apiKey>", "Set the API key for the adspower runtime").addOption(new import_commander.Option("--base-url <baseUrl>", "Set the base URL for the adspower runtime").hideHelp()).addOption(new import_commander.Option("--node-env <nodeEnv>", "Set the node environment for the adspower runtime").hideHelp()).action(async (options) => {
3057
+ var program = new import_commander2.Command();
3058
+ program.description("CLI and runtime for adspower-browser").version(VERSION);
3059
+ program.command("start").description("Start the adspower runtime").option("-k, --api-key <apiKey>", "Set the API key for the adspower runtime").addOption(new import_commander2.Option("--base-url <baseUrl>", "Set the base URL for the adspower runtime").hideHelp()).addOption(new import_commander2.Option("--node-env <nodeEnv>", "Set the node environment for the adspower runtime").hideHelp()).action(async (options) => {
2772
3060
  const resolvedApiKey = resolveStartApiKey(options.apiKey, process.env);
2773
3061
  if (!resolvedApiKey.ok) {
2774
3062
  logError(resolvedApiKey.error);
@@ -2794,53 +3082,19 @@ program.command("status").description("Get the status of the adspower runtime").
2794
3082
  });
2795
3083
  for (const cmd of Object.keys(STATELESS_HANDLERS)) {
2796
3084
  const fnc = STATELESS_HANDLERS[cmd].fn;
2797
- program.command(`${cmd} [params]`).description(STATELESS_HANDLERS[cmd].description).option("-k, --api-key <apiKey>", "Set the API key for the adspower runtime").option("-p, --port <port>", "Set the port for the adspower runtime").action(async (params, options, command) => {
2798
- const isRun = await hasRunning(options);
2799
- if (!isRun) {
2800
- logError("[!] Adspower runtime is not running");
2801
- const info = `[i] Please run "${(0, import_colors2.green)("adspower-browser start -k <apiKey>")}" to start the adspower runtime`;
2802
- console.log(info);
2803
- return;
2804
- }
2805
- const { apiKey, port } = getApiKeyAndPort(options);
2806
- updateConfig(apiKey, port);
2807
- const resolved = resolveStatelessCommandArgs(command.name(), params);
2808
- if (!resolved.ok) {
2809
- logError(resolved.error);
2810
- return;
2811
- }
2812
- const args = resolved.args;
2813
- logSuccess(`Executing command: ${command.name()}, params: ${JSON.stringify(args)}`);
2814
- const loading = createLoading(`Executing ${command.name()}...`);
2815
- try {
2816
- if (command.name() === "download-kernel") {
2817
- loading.stop();
2818
- const result = await trackKernelDownload(fnc, args);
2819
- const out = typeof result === "string" ? result : JSON.stringify(result, null, 2);
2820
- logInfo(`
2821
-
2822
- ${out}
2823
-
2824
- `);
2825
- } else {
2826
- const result = await fnc(args);
2827
- const out = typeof result === "string" ? result : JSON.stringify(result, null, 2);
2828
- logInfo(`
2829
-
2830
- ${out}
2831
- `);
2832
- if (command.name() === "update-patch" && !out.includes("The client is already on the latest patch version. No update is required")) {
2833
- loading.stop();
2834
- await sleepTime(1e3 * 60);
2835
- await restartChild();
2836
- }
2837
- }
2838
- } finally {
2839
- loading.stop();
2840
- }
3085
+ program.command(`${cmd}`).description(STATELESS_HANDLERS[cmd].description).option("-k, --api-key <apiKey>", "Set the API key for the adspower runtime").option("-p, --port <port>", "Set the port for the adspower runtime").argument("[params]", STATELESS_HANDLERS[cmd].paramsDescription).action(async (params, options, command) => {
3086
+ await handleAction(params, options, command, fnc);
2841
3087
  });
2842
3088
  }
2843
- program.parseAsync(process.argv).catch((error) => {
2844
- console.error(error);
2845
- process.exit(1);
2846
- });
3089
+ setupShellCompletion(program);
3090
+ var shellScriptArg = process.argv[2] === "complete" ? process.argv[3] : void 0;
3091
+ var restoreStdout = wrapShellScriptOutput(shellScriptArg);
3092
+ if (isShellCompletionRequest()) {
3093
+ program.parse(process.argv);
3094
+ restoreStdout();
3095
+ } else {
3096
+ program.parseAsync(process.argv).catch((error) => {
3097
+ console.error(error);
3098
+ process.exit(1);
3099
+ }).finally(restoreStdout);
3100
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adspower-browser",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "main": "cli/index.js",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -13,12 +13,13 @@
13
13
  "adspower": "node cli/index.js"
14
14
  },
15
15
  "dependencies": {
16
+ "@bomb.sh/tab": "^0.0.15",
16
17
  "axios": "^1.8.4",
17
18
  "colors": "^1.4.0",
18
19
  "commander": "^14.0.3",
19
20
  "fs-extra2": "^1.0.1",
20
21
  "playwright-core": "^1.51.1",
21
- "zod": "^3.24.2"
22
+ "zod": "^4.4.3"
22
23
  },
23
24
  "devDependencies": {
24
25
  "@adspower/local-api-core": "workspace:*",