adspower-browser 2.0.1 → 2.0.3

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.
Files changed (3) hide show
  1. package/README.MD +38 -0
  2. package/cli/index.js +442 -202
  3. package/package.json +3 -2
package/README.MD CHANGED
@@ -61,6 +61,34 @@ 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
+ **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
+ **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
+ After setup, `ads`, `adspower`, and `adspower-browser` share the same completions:
85
+
86
+ ```bash
87
+ ads <Tab><Tab> # list subcommands
88
+ ads open-<Tab> # complete to open-browser
89
+ ads sta<Tab> # complete to start / status
90
+ ```
91
+
64
92
  ## Essential Commands With CLI
65
93
 
66
94
  You can use `ads -h` or `ads <command> -h` to view the specific parameters.
@@ -149,4 +177,14 @@ ads download-kernel '{"kernel_type":"Chrome","kernel_version":"..."}' # kernel
149
177
 
150
178
  ```bash
151
179
  ads update-patch '{"version_type":"stable"}' # version_type?:stable|beta
180
+ ```
181
+
182
+ ## Use CLI in Docker
183
+
184
+ copy the [`docker-compose.yml`](./docker-compose.yml)
185
+
186
+ ```bash
187
+ docker-compose -f ./docker-compose.yml up -d
188
+
189
+ docker-compose exec adspower-cli /bin/bash
152
190
  ```
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 {
@@ -105,7 +105,8 @@ var util = __toESM(require("util"));
105
105
  var import_node_child_process = require("child_process");
106
106
  var import_colors = require("colors");
107
107
  var import_fs_extra2 = require("fs-extra2");
108
- var VERSION = "1.0.0";
108
+ var VERSION = (0, import_fs_extra2.readJsonSync)(path.join(__dirname, "../package.json")).version;
109
+ var VERSION_FILE = "1.0.0";
109
110
  var toTerminalLink = (url, label) => {
110
111
  const text = label || url;
111
112
  return `\x1B]8;;${url}\x07${text}\x1B]8;;\x07`;
@@ -158,7 +159,7 @@ var getPidFileDir = () => {
158
159
  return dir;
159
160
  };
160
161
  var pidFileName = () => {
161
- const md5 = crypto.createHash("md5").update(VERSION).digest("hex");
162
+ const md5 = crypto.createHash("md5").update(VERSION_FILE).digest("hex");
162
163
  return md5;
163
164
  };
164
165
  var writePidFile = (config2) => {
@@ -285,43 +286,6 @@ var initSqlite3 = () => {
285
286
  logSuccess(`[i] SQLite file initialized successfully!`);
286
287
  }
287
288
  };
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");
303
- }
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
- }
323
- }
324
- };
325
289
 
326
290
  // src/core/start.ts
327
291
  var getEnv = () => {
@@ -547,9 +511,6 @@ var getChildStatus = async () => {
547
511
  }
548
512
  };
549
513
 
550
- // src/index.ts
551
- var import_colors2 = require("colors");
552
-
553
514
  // ../core/src/constants/api.ts
554
515
  var import_axios = __toESM(require("axios"));
555
516
 
@@ -669,7 +630,6 @@ var LOCAL_API_CONTRACTS = {
669
630
  remark: { apiName: "remark", location: "body" },
670
631
  user_proxy_config: { apiName: "user_proxy_config", location: "body" },
671
632
  proxyid: { apiName: "proxyid", location: "body" },
672
- repeat_config: { apiName: "repeat_config", location: "body" },
673
633
  ignore_cookie_error: { apiName: "ignore_cookie_error", location: "body" },
674
634
  tabs: { apiName: "tabs", location: "body" },
675
635
  ip: { apiName: "ip", location: "body" },
@@ -1402,39 +1362,33 @@ var browserHandlers = {
1402
1362
  const requestBody = buildRequestBodyFor("open-browser", resolvedParams);
1403
1363
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.START_BROWSER}`, requestBody);
1404
1364
  if (response.data.code === 0) {
1405
- 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)." : "";
1406
- return `Browser opened successfully with: ${Object.entries(response.data.data).map(([key, value]) => {
1407
- if (value && typeof value === "object") {
1408
- return Object.entries(value).map(([key2, value2]) => `ws.${key2}: ${value2}`).join("\n");
1409
- }
1410
- return `${key}: ${value}`;
1411
- }).join("\n")}${autoNote}`;
1365
+ return JSON.stringify(response.data.data, null, 2);
1412
1366
  }
1413
- throw new Error(`Failed to open browser: ${response.data.msg}`);
1367
+ throw new Error(response.data.msg);
1414
1368
  },
1415
1369
  async closeBrowser(params) {
1416
1370
  const requestBody = buildRequestBodyFor("close-browser", params);
1417
1371
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.CLOSE_BROWSER}`, requestBody);
1418
1372
  if (response.data.code === 0) {
1419
- return "Browser closed successfully";
1373
+ return JSON.stringify(response.data.data, null, 2);
1420
1374
  }
1421
- throw new Error(`Failed to close browser: ${response.data.msg}`);
1375
+ throw new Error(response.data.msg);
1422
1376
  },
1423
1377
  async createBrowser(params) {
1424
1378
  const requestBody = buildRequestBodyFor("create-browser", params);
1425
1379
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.CREATE_BROWSER}`, requestBody);
1426
1380
  if (response.data.code === 0) {
1427
- return `Browser created successfully with: ${Object.entries(response.data.data).map(([key, value]) => `${key}: ${value}`).join("\n")}`;
1381
+ return JSON.stringify(response.data.data, null, 2);
1428
1382
  }
1429
- throw new Error(`Failed to create browser: ${response.data.msg}`);
1383
+ throw new Error(response.data.msg);
1430
1384
  },
1431
1385
  async updateBrowser(params) {
1432
1386
  const requestBody = buildRequestBodyFor("update-browser", params);
1433
1387
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.UPDATE_BROWSER}`, requestBody);
1434
1388
  if (response.data.code === 0) {
1435
- return `Browser updated successfully with: ${Object.entries(response.data.data || {}).map(([key, value]) => `${key}: ${value}`).join("\n")}`;
1389
+ return JSON.stringify(response.data.data, null, 2);
1436
1390
  }
1437
- throw new Error(`Failed to update browser: ${response.data.msg}`);
1391
+ throw new Error(response.data.msg);
1438
1392
  },
1439
1393
  async deleteBrowser(params) {
1440
1394
  const response = await getApiClient().post(
@@ -1442,64 +1396,63 @@ var browserHandlers = {
1442
1396
  buildRequestBodyFor("delete-browser", params)
1443
1397
  );
1444
1398
  if (response.data.code === 0) {
1445
- return `Browsers deleted successfully: ${params.profile_id.join(", ")}`;
1399
+ return JSON.stringify(response.data.data, null, 2);
1446
1400
  }
1447
- throw new Error(`Failed to delete browsers: ${response.data.msg}`);
1401
+ throw new Error(response.data.msg);
1448
1402
  },
1449
1403
  async getBrowserList(params) {
1450
1404
  const requestBody = buildRequestBodyFor("get-browser-list", params);
1451
1405
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.GET_BROWSER_LIST}`, requestBody);
1452
1406
  if (response.data.code === 0) {
1453
- return `Browser list: ${JSON.stringify(response.data.data.list, null, 2)}`;
1407
+ return JSON.stringify(response.data.data, null, 2);
1454
1408
  }
1455
- throw new Error(`Failed to get browser list: ${response.data.msg}`);
1409
+ throw new Error(response.data.msg);
1456
1410
  },
1457
1411
  async getOpenedBrowser() {
1458
1412
  const response = await getApiClient().get(`${getLocalApiBase()}${API_ENDPOINTS.GET_OPENED_BROWSER}`);
1459
1413
  if (response.data.code === 0) {
1460
- return `Opened browser list: ${JSON.stringify(response.data.data.list, null, 2)}`;
1414
+ return JSON.stringify(response.data.data, null, 2);
1461
1415
  }
1462
- throw new Error(`Failed to get opened browsers: ${response.data.msg}`);
1416
+ throw new Error(response.data.msg);
1463
1417
  },
1464
1418
  async moveBrowser(params) {
1465
1419
  const requestBody = buildRequestBodyFor("move-browser", params);
1466
1420
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.MOVE_BROWSER}`, requestBody);
1467
- const { group_id, user_ids } = params;
1468
1421
  if (response.data.code === 0) {
1469
- return `Browsers moved successfully to group ${group_id}: ${user_ids.join(", ")}`;
1422
+ return JSON.stringify(response.data.data, null, 2);
1470
1423
  }
1471
- throw new Error(`Failed to move browsers: ${response.data.msg}`);
1424
+ throw new Error(response.data.msg);
1472
1425
  },
1473
1426
  async getProfileCookies(params) {
1474
1427
  const query = buildQueryParamsFor("get-profile-cookies", params);
1475
1428
  const response = await getApiClient().get(`${getLocalApiBase()}${API_ENDPOINTS.GET_PROFILE_COOKIES}`, { params: query });
1476
1429
  if (response.data.code === 0) {
1477
- return `Profile cookies: ${JSON.stringify(response.data.data, null, 2)}`;
1430
+ return JSON.stringify(response.data.data, null, 2);
1478
1431
  }
1479
- throw new Error(`Failed to get profile cookies: ${response.data.msg}`);
1432
+ throw new Error(response.data.msg);
1480
1433
  },
1481
1434
  async getProfileUa(params) {
1482
1435
  const requestBody = buildRequestBodyFor("get-profile-ua", params);
1483
1436
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.GET_PROFILE_UA}`, requestBody);
1484
1437
  if (response.data.code === 0) {
1485
- return `Profile User-Agent: ${JSON.stringify(response.data.data, null, 2)}`;
1438
+ return JSON.stringify(response.data.data, null, 2);
1486
1439
  }
1487
- throw new Error(`Failed to get profile User-Agent: ${response.data.msg}`);
1440
+ throw new Error(response.data.msg);
1488
1441
  },
1489
1442
  async closeAllProfiles(_params) {
1490
1443
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.CLOSE_ALL_PROFILES}`, {});
1491
- if (response.data.code === 0) {
1492
- return "All profiles closed successfully";
1444
+ if (response.data.data.code === 0) {
1445
+ return JSON.stringify(response.data.data, null, 2);
1493
1446
  }
1494
- throw new Error(`Failed to close all profiles: ${response.data.msg}`);
1447
+ throw new Error(response.data.data.msg);
1495
1448
  },
1496
1449
  async newFingerprint(params) {
1497
1450
  const requestBody = buildRequestBodyFor("new-fingerprint", params);
1498
1451
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.NEW_FINGERPRINT}`, requestBody);
1499
1452
  if (response.data.code === 0) {
1500
- return `New fingerprint created: ${JSON.stringify(response.data.data, null, 2)}`;
1453
+ return JSON.stringify(response.data.data, null, 2);
1501
1454
  }
1502
- throw new Error(`Failed to create new fingerprint: ${response.data.msg}`);
1455
+ throw new Error(response.data.msg);
1503
1456
  },
1504
1457
  async deleteCacheV2(params) {
1505
1458
  const response = await getApiClient().post(
@@ -1507,33 +1460,33 @@ var browserHandlers = {
1507
1460
  buildRequestBodyFor("delete-cache-v2", params)
1508
1461
  );
1509
1462
  if (response.data.code === 0) {
1510
- return `Cache deleted successfully for profiles: ${params.profile_id.join(", ")}`;
1463
+ return JSON.stringify(response.data.data, null, 2);
1511
1464
  }
1512
- throw new Error(`Failed to delete cache: ${response.data.msg}`);
1465
+ throw new Error(response.data.msg);
1513
1466
  },
1514
1467
  async shareProfile(params) {
1515
1468
  const requestBody = buildRequestBodyFor("share-profile", params);
1516
1469
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.SHARE_PROFILE}`, requestBody);
1517
1470
  if (response.data.code === 0) {
1518
- return `Profiles shared successfully: ${params.profile_id.join(", ")}`;
1471
+ return JSON.stringify(response.data.data, null, 2);
1519
1472
  }
1520
- throw new Error(`Failed to share profiles: ${response.data.msg}`);
1473
+ throw new Error(response.data.msg);
1521
1474
  },
1522
1475
  async getBrowserActive(params) {
1523
1476
  const query = buildQueryParamsFor("get-browser-active", params);
1524
1477
  const response = await getApiClient().get(`${getLocalApiBase()}${API_ENDPOINTS.GET_BROWSER_ACTIVE}`, { params: query });
1525
1478
  if (response.data.code === 0) {
1526
- return `Browser active info: ${JSON.stringify(response.data.data, null, 2)}`;
1479
+ return JSON.stringify(response.data.data, null, 2);
1527
1480
  }
1528
- throw new Error(`Failed to get browser active: ${response.data.msg}`);
1481
+ throw new Error(response.data.msg);
1529
1482
  },
1530
1483
  async getCloudActive(params) {
1531
1484
  const requestBody = buildRequestBodyFor("get-cloud-active", params);
1532
1485
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.GET_CLOUD_ACTIVE}`, requestBody);
1533
1486
  if (response.data.code === 0) {
1534
- return `Cloud active browsers: ${JSON.stringify(response.data.data, null, 2)}`;
1487
+ return JSON.stringify(response.data.data, null, 2);
1535
1488
  }
1536
- throw new Error(`Failed to get cloud active browsers: ${response.data.msg}`);
1489
+ throw new Error(response.data.msg);
1537
1490
  }
1538
1491
  };
1539
1492
 
@@ -1542,28 +1495,26 @@ var groupHandlers = {
1542
1495
  async createGroup(params) {
1543
1496
  const requestBody = buildRequestBodyFor("create-group", params);
1544
1497
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.CREATE_GROUP}`, requestBody);
1545
- const { group_name, remark } = params;
1546
1498
  if (response.data.code === 0) {
1547
- return `Group created successfully with name: ${group_name}${remark ? `, remark: ${remark}` : ""}`;
1499
+ return JSON.stringify(response.data.data, null, 2);
1548
1500
  }
1549
- throw new Error(`Failed to create group: ${response.data.msg}`);
1501
+ throw new Error(response.data.msg);
1550
1502
  },
1551
1503
  async updateGroup(params) {
1552
1504
  const requestBody = buildRequestBodyFor("update-group", params);
1553
1505
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.UPDATE_GROUP}`, requestBody);
1554
- const { group_id, group_name, remark } = params;
1555
1506
  if (response.data.code === 0) {
1556
- return `Group updated successfully with id: ${group_id}, name: ${group_name}${remark !== void 0 ? `, remark: ${remark === null ? "(cleared)" : remark}` : ""}`;
1507
+ return JSON.stringify(response.data.data, null, 2);
1557
1508
  }
1558
- throw new Error(`Failed to update group: ${response.data.msg}`);
1509
+ throw new Error(response.data.msg);
1559
1510
  },
1560
1511
  async getGroupList(params) {
1561
1512
  const query = buildQueryParamsFor("get-group-list", params);
1562
1513
  const response = await getApiClient().get(`${getLocalApiBase()}${API_ENDPOINTS.GET_GROUP_LIST}`, { params: query });
1563
1514
  if (response.data.code === 0) {
1564
- return `Group list: ${JSON.stringify(response.data.data.list, null, 2)}`;
1515
+ return JSON.stringify(response.data.data, null, 2);
1565
1516
  }
1566
- throw new Error(`Failed to get group list: ${response.data.msg}`);
1517
+ throw new Error(response.data.msg);
1567
1518
  }
1568
1519
  };
1569
1520
 
@@ -1571,12 +1522,12 @@ var groupHandlers = {
1571
1522
  var applicationHandlers = {
1572
1523
  async checkStatus() {
1573
1524
  const response = await getApiClient().get(`${getLocalApiBase()}${API_ENDPOINTS.STATUS}`);
1574
- return `Connection status: ${JSON.stringify(response.data, null, 2)}`;
1525
+ return JSON.stringify(response.data, null, 2);
1575
1526
  },
1576
1527
  async getApplicationList(params) {
1577
1528
  const query = buildQueryParamsFor("get-application-list", params);
1578
1529
  const response = await getApiClient().get(`${getLocalApiBase()}${API_ENDPOINTS.GET_APPLICATION_LIST}`, { params: query });
1579
- return `Application list: ${JSON.stringify(response.data.data.list, null, 2)}`;
1530
+ return JSON.stringify(response.data.data, null, 2);
1580
1531
  }
1581
1532
  };
1582
1533
 
@@ -1608,25 +1559,25 @@ var proxyHandlers = {
1608
1559
  const requestBody = params.map((proxy) => buildCreateProxyRequestBody(proxy));
1609
1560
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.CREATE_PROXY}`, requestBody);
1610
1561
  if (response.data.code === 0) {
1611
- return `Proxy created successfully with: ${Object.entries(response.data.data || {}).map(([key, value]) => `${key}: ${value}`).join("\n")}`;
1562
+ return JSON.stringify(response.data.data, null, 2);
1612
1563
  }
1613
- throw new Error(`Failed to create proxy: ${response.data.msg}`);
1564
+ throw new Error(response.data.msg);
1614
1565
  },
1615
1566
  async updateProxy(params) {
1616
1567
  const requestBody = buildRequestBodyFor("update-proxy", params);
1617
1568
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.UPDATE_PROXY}`, requestBody);
1618
1569
  if (response.data.code === 0) {
1619
- return `Proxy updated successfully with: ${Object.entries(response.data.data || {}).map(([key, value]) => `${key}: ${value}`).join("\n")}`;
1570
+ return JSON.stringify(response.data.data, null, 2);
1620
1571
  }
1621
- throw new Error(`Failed to update proxy: ${response.data.msg}`);
1572
+ throw new Error(response.data.msg);
1622
1573
  },
1623
1574
  async getProxyList(params) {
1624
1575
  const requestBody = buildRequestBodyFor("get-proxy-list", params);
1625
1576
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.GET_PROXY_LIST}`, requestBody);
1626
1577
  if (response.data.code === 0) {
1627
- return `Proxy list: ${JSON.stringify(response.data.data.list || response.data.data, null, 2)}`;
1578
+ return JSON.stringify(response.data.data, null, 2);
1628
1579
  }
1629
- throw new Error(`Failed to get proxy list: ${response.data.msg}`);
1580
+ throw new Error(response.data.msg);
1630
1581
  },
1631
1582
  async deleteProxy(params) {
1632
1583
  const response = await getApiClient().post(
@@ -1635,9 +1586,9 @@ var proxyHandlers = {
1635
1586
  );
1636
1587
  const { proxy_id } = params;
1637
1588
  if (response.data.code === 0) {
1638
- return `Proxies deleted successfully: ${proxy_id.join(", ")}`;
1589
+ return JSON.stringify(response.data.data, null, 2);
1639
1590
  }
1640
- throw new Error(`Failed to delete proxies: ${response.data.msg}`);
1591
+ throw new Error(response.data.msg);
1641
1592
  }
1642
1593
  };
1643
1594
 
@@ -1657,30 +1608,30 @@ var tagHandlers = {
1657
1608
  }
1658
1609
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.GET_TAG_LIST}`, requestBody);
1659
1610
  if (response.data.code === 0) {
1660
- return `Tag list: ${JSON.stringify(response.data.data.list || response.data.data, null, 2)}`;
1611
+ return JSON.stringify(response.data.data, null, 2);
1661
1612
  }
1662
- throw new Error(`Failed to get tag list: ${response.data.msg}`);
1613
+ throw new Error(response.data.msg);
1663
1614
  },
1664
1615
  async createTag({ tags }) {
1665
1616
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.CREATE_TAG}`, { tags });
1666
1617
  if (response.data.code === 0) {
1667
- return `Tags created successfully: ${JSON.stringify(response.data.data, null, 2)}`;
1618
+ return JSON.stringify(response.data.data, null, 2);
1668
1619
  }
1669
- throw new Error(`Failed to create tags: ${response.data.msg}`);
1620
+ throw new Error(response.data.msg);
1670
1621
  },
1671
1622
  async updateTag({ tags }) {
1672
1623
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.UPDATE_TAG}`, { tags });
1673
1624
  if (response.data.code === 0) {
1674
- return `Tags updated successfully: ${JSON.stringify(response.data.data, null, 2)}`;
1625
+ return JSON.stringify(response.data.data, null, 2);
1675
1626
  }
1676
- throw new Error(`Failed to update tags: ${response.data.msg}`);
1627
+ throw new Error(response.data.msg);
1677
1628
  },
1678
1629
  async deleteTag({ ids }) {
1679
1630
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.DELETE_TAG}`, { ids });
1680
1631
  if (response.data.code === 0) {
1681
- return `Tags deleted successfully: ${ids.join(", ")}`;
1632
+ return JSON.stringify(response.data.data, null, 2);
1682
1633
  }
1683
- throw new Error(`Failed to delete tags: ${response.data.msg}`);
1634
+ throw new Error(response.data.msg);
1684
1635
  }
1685
1636
  };
1686
1637
 
@@ -1749,9 +1700,9 @@ var kernelHandlers = {
1749
1700
  kernel_version
1750
1701
  });
1751
1702
  if (response.data.code === 0) {
1752
- return `Kernel download/update status: ${JSON.stringify(response.data.data, null, 2)}`;
1703
+ return JSON.stringify(response.data.data, null, 2);
1753
1704
  }
1754
- throw new Error(`Failed to download/update kernel: ${response.data.msg}`);
1705
+ throw new Error(response.data.msg);
1755
1706
  },
1756
1707
  async getKernelList({ kernel_type }) {
1757
1708
  const params = new URLSearchParams();
@@ -1760,9 +1711,9 @@ var kernelHandlers = {
1760
1711
  }
1761
1712
  const response = await getApiClient().get(`${getLocalApiBase()}${API_ENDPOINTS.GET_KERNEL_LIST}`, { params });
1762
1713
  if (response.data.code === 0) {
1763
- return `Kernel list: ${JSON.stringify(response.data.data.list || response.data.data, null, 2)}`;
1714
+ return JSON.stringify(response.data.data, null, 2);
1764
1715
  }
1765
- throw new Error(`Failed to get kernel list: ${response.data.msg}`);
1716
+ throw new Error(response.data.msg);
1766
1717
  }
1767
1718
  };
1768
1719
 
@@ -1775,9 +1726,9 @@ var patchHandlers = {
1775
1726
  }
1776
1727
  const response = await getApiClient().post(`${getLocalApiBase()}${API_ENDPOINTS.UPDATE_PATCH}`, requestBody);
1777
1728
  if (response.data.code === 0) {
1778
- return `Patch update status: ${JSON.stringify(response.data.data, null, 2)}, message: ${response.data.msg}`;
1729
+ return JSON.stringify(response.data.data, null, 2);
1779
1730
  }
1780
- throw new Error(`Failed to update patch: ${response.data.msg}`);
1731
+ throw new Error(response.data.msg);
1781
1732
  }
1782
1733
  };
1783
1734
 
@@ -2234,8 +2185,8 @@ var fingerprintConfigSchema = import_zod.z.object({
2234
2185
  webrtc: import_zod.z.enum(["disabled", "forward", "proxy", "local", "disableUDP"]).optional().describe("WebRTC: forward: forward, use proxy IP to cover real IP, used in proxy scene, more secure (need to upgrade to V2.6.8.6 or later version); proxy: replace, use proxy IP to cover real IP, used in proxy scene; local: real, the website will get the real IP; disabled: disabled (default), the website will not get the IP; disableUDP: disable UDP, disable non-proxy UDP traffic (only supported by Chrome kernel)."),
2235
2186
  audio: import_zod.z.enum(["0", "1"]).optional().describe("Audio fingerprint: 0 close, 1 (default) add noise"),
2236
2187
  do_not_track: import_zod.z.enum(["default", "true", "false"]).optional().describe("Do Not Track: default, true (open), false (close)"),
2237
- hardware_concurrency: import_zod.z.enum(["2", "4", "6", "8", "16"]).optional().describe("CPU cores: 2, 4 (default if omitted), 6, 8, 16; omit to follow current computer"),
2238
- device_memory: import_zod.z.enum(["2", "4", "6", "8"]).optional().describe("Device memory (GB): 2, 4, 6, 8 (default if omitted); omit to follow current computer"),
2188
+ hardware_concurrency: import_zod.z.enum(["default", "2", "4", "6", "8", "16", "32"]).optional().describe("CPU cores: default(follow computer actual CPU cores), 2, 4 (default if omitted), 6, 8, 16; omit to follow current computer"),
2189
+ device_memory: import_zod.z.enum(["default", "2", "4", "6", "8"]).optional().describe("Device memory (GB): default(follow computer actual device memory), 2, 4, 6, 8 (default if omitted); omit to follow current computer"),
2239
2190
  scan_port_type: import_zod.z.enum(["0", "1"]).optional().describe("Port scan protection: 0 close, 1 (default) enable"),
2240
2191
  allow_scan_ports: import_zod.z.array(import_zod.z.string()).optional().describe('Ports allowed when scan_port_type=1, e.g. ["4000","4001"]. Empty to not pass.'),
2241
2192
  media_devices: import_zod.z.enum(["0", "1", "2"]).optional().describe("Media devices: 0 off (use computer default), 1 noise (count follows local), 2 noise (use media_devices_num). V2.6.4.2+"),
@@ -2290,7 +2241,7 @@ var schemas = {
2290
2241
  remark: import_zod.z.string().optional().describe("Remarks to describe the profile. Maximum 1500 characters."),
2291
2242
  user_proxy_config: userProxyConfigSchema.default({ proxy_soft: "no_proxy" }).describe("Proxy configuration. If proxyid is provided, proxyid takes priority and this field is ignored. Defaults to no_proxy when neither proxyid nor a custom proxy is needed."),
2292
2243
  proxyid: import_zod.z.string().optional().describe(" Already added proxy (proxy ID). user_proxy_config and proxyid cannot be empty at the same time. Takes priority over user_proxy_config when provided."),
2293
- repeat_config: import_zod.z.array(import_zod.z.union([import_zod.z.literal(0), import_zod.z.literal(2), import_zod.z.literal(3), import_zod.z.literal(4)])).optional().describe("Account deduplication settings (0, 2, 3, or 4), 0: allow duplicate (default), 2: deduplicate by account and password, 3: deduplicate by cookie, 4: deduplicate by c_user (c_user is Facebook's unique identifier)"),
2244
+ repeat_config: import_zod.z.enum(["0", "2", "3", "4"]).optional().describe("Account deduplication settings (0, 2, 3, or 4), 0: allow duplicate (default), 2: deduplicate by account and password, 3: deduplicate by cookie, 4: deduplicate by c_user (c_user is Facebook's unique identifier)"),
2294
2245
  ignore_cookie_error: import_zod.z.enum(["0", "1"]).optional().describe("Handle cookie verification failures: 0 (default) return data as-is, 1 filter out incorrectly formatted cookies"),
2295
2246
  tabs: import_zod.z.array(import_zod.z.string()).optional().describe('URLs to open on startup, eg: ["https://www.google.com"]'),
2296
2247
  ip: import_zod.z.string().optional().describe("IP address"),
@@ -2538,167 +2489,258 @@ var schemas = {
2538
2489
  };
2539
2490
 
2540
2491
  // src/cli.ts
2492
+ function formatJsonValueForHelp(value, indent) {
2493
+ const pad = " ".repeat(indent);
2494
+ const childPad = " ".repeat(indent + 1);
2495
+ if (value === null || typeof value !== "object") {
2496
+ return JSON.stringify(value);
2497
+ }
2498
+ if (Array.isArray(value)) {
2499
+ if (value.length === 0) {
2500
+ return "[]";
2501
+ }
2502
+ const lines2 = value.map((item) => `${childPad}${formatJsonValueForHelp(item, indent + 1)}`);
2503
+ return `[
2504
+ ${lines2.join(",\n")}
2505
+ ${pad}]`;
2506
+ }
2507
+ const entries = Object.entries(value);
2508
+ if (entries.length === 0) {
2509
+ return "{}";
2510
+ }
2511
+ const lines = entries.map(([key, val]) => {
2512
+ if (["enum", "oneOf", "required"].includes(key) && Array.isArray(val)) {
2513
+ return `${childPad}${JSON.stringify(key)}: ${JSON.stringify(val)}`;
2514
+ }
2515
+ return `${childPad}${JSON.stringify(key)}: ${formatJsonValueForHelp(val, indent + 1)}`;
2516
+ });
2517
+ return `{
2518
+ ${lines.join(",\n")}
2519
+ ${pad}}`;
2520
+ }
2521
+ function formatSchemaPropertiesForHelp(properties) {
2522
+ return formatJsonValueForHelp(properties, 0);
2523
+ }
2524
+ function schemaParamsDescription(schema, type) {
2525
+ let paramStr = "view help: https://documenter.getpostman.com/view/45822952/2sB2x5JDXn\n";
2526
+ switch (type) {
2527
+ case "open-browser":
2528
+ paramStr += `use cmd: "ads open-browser <profile_id>"
2529
+ or use params: "ads open-browser '{"profile_id":"..."}' "
2530
+ `;
2531
+ break;
2532
+ case "close-browser":
2533
+ paramStr += `use cmd: "ads close-browser <profile_id>"
2534
+ or use params: "ads close-browser '{"profile_id":"..."}' "
2535
+ `;
2536
+ break;
2537
+ case "get-profile-cookies":
2538
+ paramStr += `use cmd: "ads get-profile-cookies <profile_id>"
2539
+ or use params: "ads get-profile-cookies '{"profile_id":"..."}' "
2540
+ `;
2541
+ break;
2542
+ case "get-browser-active":
2543
+ paramStr += `use cmd: "ads get-browser-active <profile_id>"
2544
+ or use params: "ads get-browser-active '{"profile_id":"..."}' "
2545
+ `;
2546
+ break;
2547
+ }
2548
+ const _str = formatSchemaPropertiesForHelp(schema.toJSONSchema().properties);
2549
+ return paramStr + _str;
2550
+ }
2541
2551
  var STATELESS_HANDLERS = {
2542
2552
  "open-browser": {
2543
2553
  fn: browserHandlers.openBrowser,
2544
2554
  description: buildCliCommandDescription(
2545
2555
  "open-browser",
2546
2556
  "Open the browser, both environment and profile mean browser"
2547
- )
2557
+ ),
2558
+ paramsDescription: schemaParamsDescription(schemas.openBrowserSchema, "open-browser")
2548
2559
  },
2549
2560
  "close-browser": {
2550
2561
  fn: browserHandlers.closeBrowser,
2551
- description: buildCliCommandDescription("close-browser", "Close the browser")
2562
+ description: buildCliCommandDescription("close-browser", "Close the browser"),
2563
+ paramsDescription: schemaParamsDescription(schemas.closeBrowserSchema, "close-browser")
2552
2564
  },
2553
2565
  "create-browser": {
2554
2566
  fn: browserHandlers.createBrowser,
2555
- description: buildCliCommandDescription("create-browser", "Create a browser")
2567
+ description: buildCliCommandDescription("create-browser", "Create a browser"),
2568
+ paramsDescription: schemaParamsDescription(schemas.createBrowserSchema, "create-browser")
2556
2569
  },
2557
2570
  "update-browser": {
2558
2571
  fn: browserHandlers.updateBrowser,
2559
- description: buildCliCommandDescription("update-browser", "Update the browser")
2572
+ description: buildCliCommandDescription("update-browser", "Update the browser"),
2573
+ paramsDescription: schemaParamsDescription(schemas.updateBrowserSchema, "update-browser")
2560
2574
  },
2561
2575
  "delete-browser": {
2562
2576
  fn: browserHandlers.deleteBrowser,
2563
- description: buildCliCommandDescription("delete-browser", "Delete the browser")
2577
+ description: buildCliCommandDescription("delete-browser", "Delete the browser"),
2578
+ paramsDescription: schemaParamsDescription(schemas.deleteBrowserSchema, "delete-browser")
2564
2579
  },
2565
2580
  "get-browser-list": {
2566
2581
  fn: browserHandlers.getBrowserList,
2567
- description: buildCliCommandDescription("get-browser-list", "Get the list of browsers")
2582
+ description: buildCliCommandDescription("get-browser-list", "Get the list of browsers"),
2583
+ paramsDescription: schemaParamsDescription(schemas.getBrowserListSchema, "get-browser-list")
2568
2584
  },
2569
2585
  "get-opened-browser": {
2570
2586
  fn: browserHandlers.getOpenedBrowser,
2571
- description: buildCliCommandDescription("get-opened-browser", "Get the list of opened browsers")
2587
+ description: buildCliCommandDescription("get-opened-browser", "Get the list of opened browsers"),
2588
+ paramsDescription: schemaParamsDescription(schemas.emptySchema, "get-opened-browser")
2572
2589
  },
2573
2590
  "move-browser": {
2574
2591
  fn: browserHandlers.moveBrowser,
2575
- description: buildCliCommandDescription("move-browser", "Move browsers to a group")
2592
+ description: buildCliCommandDescription("move-browser", "Move browsers to a group"),
2593
+ paramsDescription: schemaParamsDescription(schemas.moveBrowserSchema, "move-browser")
2576
2594
  },
2577
2595
  "get-profile-cookies": {
2578
2596
  fn: browserHandlers.getProfileCookies,
2579
2597
  description: buildCliCommandDescription(
2580
2598
  "get-profile-cookies",
2581
2599
  "Query and return cookies of the specified profile. Only one profile can be queried per request."
2582
- )
2600
+ ),
2601
+ paramsDescription: schemaParamsDescription(schemas.getProfileCookiesSchema, "get-profile-cookies")
2583
2602
  },
2584
2603
  "get-profile-ua": {
2585
2604
  fn: browserHandlers.getProfileUa,
2586
2605
  description: buildCliCommandDescription(
2587
2606
  "get-profile-ua",
2588
2607
  "Query and return the User-Agent of specified profiles. Up to 10 profiles can be queried per request."
2589
- )
2608
+ ),
2609
+ paramsDescription: schemaParamsDescription(schemas.getProfileUaSchema, "get-profile-ua")
2590
2610
  },
2591
2611
  "close-all-profiles": {
2592
2612
  fn: browserHandlers.closeAllProfiles,
2593
2613
  description: buildCliCommandDescription(
2594
2614
  "close-all-profiles",
2595
2615
  "Close all opened profiles on the current device"
2596
- )
2616
+ ),
2617
+ paramsDescription: schemaParamsDescription(schemas.closeAllProfilesSchema, "close-all-profiles")
2597
2618
  },
2598
2619
  "new-fingerprint": {
2599
2620
  fn: browserHandlers.newFingerprint,
2600
2621
  description: buildCliCommandDescription(
2601
2622
  "new-fingerprint",
2602
2623
  "Generate a new fingerprint for specified profiles. Up to 10 profiles are supported per request."
2603
- )
2624
+ ),
2625
+ paramsDescription: schemaParamsDescription(schemas.newFingerprintSchema, "new-fingerprint")
2604
2626
  },
2605
2627
  "delete-cache-v2": {
2606
2628
  fn: browserHandlers.deleteCacheV2,
2607
2629
  description: buildCliCommandDescription(
2608
2630
  "delete-cache-v2",
2609
2631
  "Clear local cache of specific profiles.For account security, please ensure that there are no open browsers on the device when using this interface."
2610
- )
2632
+ ),
2633
+ paramsDescription: schemaParamsDescription(schemas.deleteCacheV2Schema, "delete-cache-v2")
2611
2634
  },
2612
2635
  "share-profile": {
2613
2636
  fn: browserHandlers.shareProfile,
2614
2637
  description: buildCliCommandDescription(
2615
2638
  "share-profile",
2616
2639
  "Share profiles via account email or phone number. The maximum number of profiles that can be shared at one time is 200."
2617
- )
2640
+ ),
2641
+ paramsDescription: schemaParamsDescription(schemas.shareProfileSchema, "share-profile")
2618
2642
  },
2619
2643
  "get-browser-active": {
2620
2644
  fn: browserHandlers.getBrowserActive,
2621
- description: buildCliCommandDescription("get-browser-active", "Get active browser profile information")
2645
+ description: buildCliCommandDescription("get-browser-active", "Get active browser profile information"),
2646
+ paramsDescription: schemaParamsDescription(schemas.getBrowserActiveSchema, "get-browser-active")
2622
2647
  },
2623
2648
  "get-cloud-active": {
2624
2649
  fn: browserHandlers.getCloudActive,
2625
2650
  description: buildCliCommandDescription(
2626
2651
  "get-cloud-active",
2627
2652
  '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."'
2628
- )
2653
+ ),
2654
+ paramsDescription: schemaParamsDescription(schemas.getCloudActiveSchema, "get-cloud-active")
2629
2655
  },
2630
2656
  "create-group": {
2631
2657
  fn: groupHandlers.createGroup,
2632
- description: buildCliCommandDescription("create-group", "Create a browser group")
2658
+ description: buildCliCommandDescription("create-group", "Create a browser group"),
2659
+ paramsDescription: schemaParamsDescription(schemas.createGroupSchema, "create-group")
2633
2660
  },
2634
2661
  "update-group": {
2635
2662
  fn: groupHandlers.updateGroup,
2636
- description: buildCliCommandDescription("update-group", "Update the browser group")
2663
+ description: buildCliCommandDescription("update-group", "Update the browser group"),
2664
+ paramsDescription: schemaParamsDescription(schemas.updateGroupSchema, "update-group")
2637
2665
  },
2638
2666
  "get-group-list": {
2639
2667
  fn: groupHandlers.getGroupList,
2640
- description: buildCliCommandDescription("get-group-list", "Get the list of groups")
2668
+ description: buildCliCommandDescription("get-group-list", "Get the list of groups"),
2669
+ paramsDescription: schemaParamsDescription(schemas.getGroupListSchema, "get-group-list")
2641
2670
  },
2642
2671
  "check-status": {
2643
2672
  fn: applicationHandlers.checkStatus,
2644
2673
  description: buildCliCommandDescription(
2645
2674
  "check-status",
2646
2675
  "Check the availability of the current device API interface (Connection Status)"
2647
- )
2676
+ ),
2677
+ paramsDescription: schemaParamsDescription(schemas.emptySchema, "check-status")
2648
2678
  },
2649
2679
  "get-application-list": {
2650
2680
  fn: applicationHandlers.getApplicationList,
2651
2681
  description: buildCliCommandDescription(
2652
2682
  "get-application-list",
2653
2683
  "Get the list of applications (categories)"
2654
- )
2684
+ ),
2685
+ paramsDescription: schemaParamsDescription(schemas.getApplicationListSchema, "get-application-list")
2655
2686
  },
2656
2687
  "create-proxy": {
2657
2688
  fn: proxyHandlers.createProxy,
2658
- description: buildCliCommandDescription("create-proxy", "Create the proxy")
2689
+ description: buildCliCommandDescription("create-proxy", "Create the proxy"),
2690
+ paramsDescription: schemaParamsDescription(schemas.createProxySchema, "create-proxy")
2659
2691
  },
2660
2692
  "update-proxy": {
2661
2693
  fn: proxyHandlers.updateProxy,
2662
- description: buildCliCommandDescription("update-proxy", "Update the proxy")
2694
+ description: buildCliCommandDescription("update-proxy", "Update the proxy"),
2695
+ paramsDescription: schemaParamsDescription(schemas.updateProxySchema, "update-proxy")
2663
2696
  },
2664
2697
  "get-proxy-list": {
2665
2698
  fn: proxyHandlers.getProxyList,
2666
- description: buildCliCommandDescription("get-proxy-list", "Get the list of proxies")
2699
+ description: buildCliCommandDescription("get-proxy-list", "Get the list of proxies"),
2700
+ paramsDescription: schemaParamsDescription(schemas.getProxyListSchema, "get-proxy-list")
2667
2701
  },
2668
2702
  "delete-proxy": {
2669
2703
  fn: proxyHandlers.deleteProxy,
2670
- description: buildCliCommandDescription("delete-proxy", "Delete the proxy")
2704
+ description: buildCliCommandDescription("delete-proxy", "Delete the proxy"),
2705
+ paramsDescription: schemaParamsDescription(schemas.deleteProxySchema, "delete-proxy")
2671
2706
  },
2672
2707
  "get-tag-list": {
2673
2708
  fn: tagHandlers.getTagList,
2674
- description: buildCliCommandDescription("get-tag-list", "Get the list of browser tags")
2709
+ description: buildCliCommandDescription("get-tag-list", "Get the list of browser tags"),
2710
+ paramsDescription: schemaParamsDescription(schemas.getTagListSchema, "get-tag-list")
2675
2711
  },
2676
2712
  "create-tag": {
2677
2713
  fn: tagHandlers.createTag,
2678
- description: buildCliCommandDescription("create-tag", "Create browser tags (batch supported)")
2714
+ description: buildCliCommandDescription("create-tag", "Create browser tags (batch supported)"),
2715
+ paramsDescription: schemaParamsDescription(schemas.createTagSchema, "create-tag")
2679
2716
  },
2680
2717
  "update-tag": {
2681
2718
  fn: tagHandlers.updateTag,
2682
- description: buildCliCommandDescription("update-tag", "Update browser tags (batch supported)")
2719
+ description: buildCliCommandDescription("update-tag", "Update browser tags (batch supported)"),
2720
+ paramsDescription: schemaParamsDescription(schemas.updateTagSchema, "update-tag")
2683
2721
  },
2684
2722
  "delete-tag": {
2685
2723
  fn: tagHandlers.deleteTag,
2686
- description: buildCliCommandDescription("delete-tag", "Delete browser tags")
2724
+ description: buildCliCommandDescription("delete-tag", "Delete browser tags"),
2725
+ paramsDescription: schemaParamsDescription(schemas.deleteTagSchema, "delete-tag")
2687
2726
  },
2688
2727
  "download-kernel": {
2689
2728
  fn: kernelHandlers.downloadKernel,
2690
2729
  description: buildCliCommandDescription(
2691
2730
  "download-kernel",
2692
2731
  "Download or update a browser kernel version"
2693
- )
2732
+ ),
2733
+ paramsDescription: schemaParamsDescription(schemas.downloadKernelSchema, "download-kernel")
2694
2734
  },
2695
2735
  "get-kernel-list": {
2696
2736
  fn: kernelHandlers.getKernelList,
2697
- description: buildCliCommandDescription("get-kernel-list", "Get browser kernel list by type or all")
2737
+ description: buildCliCommandDescription("get-kernel-list", "Get browser kernel list by type or all"),
2738
+ paramsDescription: schemaParamsDescription(schemas.getKernelListSchema, "get-kernel-list")
2698
2739
  },
2699
2740
  "update-patch": {
2700
2741
  fn: patchHandlers.updatePatch,
2701
- description: buildCliCommandDescription("update-patch", "Update AdsPower to latest patch version")
2742
+ description: buildCliCommandDescription("update-patch", "Update AdsPower to latest patch version"),
2743
+ paramsDescription: schemaParamsDescription(schemas.updatePatchSchema, "update-patch")
2702
2744
  }
2703
2745
  };
2704
2746
  var SINGLE_PROFILE_ID_COMMANDS = {
@@ -2766,10 +2808,242 @@ function resolveStartApiKey(optionApiKey, env = process.env) {
2766
2808
  };
2767
2809
  }
2768
2810
 
2811
+ // src/completion.ts
2812
+ var import_commander = __toESM(require("@bomb.sh/tab/commander"));
2813
+ var CLI_BIN_ALIASES = ["ads", "adspower", "adspower-browser"];
2814
+ function patchShellCompletionScript(shell, script) {
2815
+ if (shell === "zsh") {
2816
+ return script.replace(/^#compdef .+$/m, `#compdef ${CLI_BIN_ALIASES.join(" ")}`).replace(/^compdef _ads ads$/m, `compdef _ads ${CLI_BIN_ALIASES.join(" ")}`);
2817
+ }
2818
+ if (shell === "bash") {
2819
+ return script.replace(
2820
+ /^complete -F __ads_complete ads$/m,
2821
+ `complete -F __ads_complete ${CLI_BIN_ALIASES.join(" ")}`
2822
+ );
2823
+ }
2824
+ return script;
2825
+ }
2826
+ function setupShellCompletion(program2) {
2827
+ program2.name("ads");
2828
+ (0, import_commander.default)(program2);
2829
+ }
2830
+ function isShellCompletionRequest(argv = process.argv) {
2831
+ const completionIndex = argv.indexOf("complete");
2832
+ const dashDashIndex = argv.indexOf("--");
2833
+ return completionIndex !== -1 && dashDashIndex !== -1 && dashDashIndex > completionIndex;
2834
+ }
2835
+ function wrapShellScriptOutput(shell) {
2836
+ if (shell !== "zsh" && shell !== "bash") {
2837
+ return () => {
2838
+ };
2839
+ }
2840
+ const originalWrite = process.stdout.write.bind(process.stdout);
2841
+ process.stdout.write = ((chunk, encoding, callback) => {
2842
+ const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString(typeof encoding === "string" ? encoding : "utf8");
2843
+ const patched = patchShellCompletionScript(shell, text);
2844
+ if (typeof encoding === "function") {
2845
+ return originalWrite(patched, encoding);
2846
+ }
2847
+ return originalWrite(
2848
+ patched,
2849
+ encoding,
2850
+ callback
2851
+ );
2852
+ });
2853
+ return () => {
2854
+ process.stdout.write = originalWrite;
2855
+ };
2856
+ }
2857
+
2858
+ // src/handleAction.ts
2859
+ var readline = __toESM(require("readline/promises"));
2860
+ var import_colors2 = require("colors");
2861
+ var renderKernelProgress = (result) => {
2862
+ const status = result.status || "pending";
2863
+ const progress = ["completed", "installing"].includes(status) ? 100 : Math.max(0, Math.min(100, Number(result.progress) || 0));
2864
+ if (!process.stdout.isTTY) {
2865
+ logInfo(`Kernel progress: ${progress}% [${status}]`);
2866
+ return;
2867
+ }
2868
+ const width = 30;
2869
+ const filled = Math.round(progress / 100 * width);
2870
+ const bar = `${"=".repeat(filled)}${"-".repeat(width - filled)}`;
2871
+ process.stdout.write(`\r[${bar}] ${progress.toFixed(0).padStart(3, " ")}% ${status} `);
2872
+ };
2873
+ var finishKernelProgress = () => {
2874
+ if (process.stdout.isTTY) {
2875
+ process.stdout.write("\n");
2876
+ }
2877
+ };
2878
+ var trackKernelDownload = async (fnc, args) => {
2879
+ while (true) {
2880
+ const result = await fnc(args);
2881
+ try {
2882
+ const resultJson = JSON.parse(result);
2883
+ if (resultJson && resultJson.status && ["pending", "downloading", "completed", "installing", "failed"].includes(resultJson.status)) {
2884
+ renderKernelProgress(resultJson);
2885
+ if (["completed", "failed"].includes(resultJson.status)) {
2886
+ finishKernelProgress();
2887
+ return result;
2888
+ }
2889
+ await sleepTime(3e3);
2890
+ } else {
2891
+ return result;
2892
+ }
2893
+ } catch (error) {
2894
+ return result;
2895
+ }
2896
+ }
2897
+ };
2898
+ var handleAction = async (params, options, command, fnc) => {
2899
+ const isRun = await hasRunning(options);
2900
+ if (!isRun) {
2901
+ logError("[!] Adspower runtime is not running");
2902
+ const info = `[i] Please run "${(0, import_colors2.green)("adspower-browser start -k <apiKey>")}" to start the adspower runtime`;
2903
+ console.log(info);
2904
+ return;
2905
+ }
2906
+ const { apiKey, port } = getApiKeyAndPort(options);
2907
+ updateConfig(apiKey, port);
2908
+ const commandName = command.name();
2909
+ const resolved = resolveStatelessCommandArgs(commandName, params);
2910
+ if (!resolved.ok) {
2911
+ logError(resolved.error);
2912
+ return;
2913
+ }
2914
+ const args = resolved.args;
2915
+ logSuccess(`Executing command: ${commandName}, params: ${JSON.stringify(args)}`);
2916
+ const loading = createLoading(`Executing ${commandName}...`);
2917
+ try {
2918
+ if (commandName === "download-kernel") {
2919
+ loading.stop();
2920
+ const result = await trackKernelDownload(fnc, args);
2921
+ const out = typeof result === "string" ? result : JSON.stringify(result, null, 2);
2922
+ logInfo(`
2923
+
2924
+ ${out}
2925
+
2926
+ `);
2927
+ } else {
2928
+ const result = await fnc(args);
2929
+ const out = typeof result === "string" ? result : JSON.stringify(result, null, 2);
2930
+ loading.stop();
2931
+ logInfo(`
2932
+
2933
+ ${out}
2934
+ `);
2935
+ if (commandName === "update-patch" && !out.includes("The client is already on the latest patch version. No update is required")) {
2936
+ await sleepTime(1e3 * 60);
2937
+ await restartChild();
2938
+ }
2939
+ return out;
2940
+ }
2941
+ } catch (error) {
2942
+ loading.stop();
2943
+ const msg = error instanceof Error ? error.message : JSON.stringify(error);
2944
+ logError(`
2945
+ ${msg}
2946
+ `);
2947
+ await handleError(msg, commandName, params);
2948
+ } finally {
2949
+ loading.stop();
2950
+ }
2951
+ };
2952
+ var handleError = async (msg, commandName, params) => {
2953
+ if (commandName === "open-browser") {
2954
+ if (msg.includes("ready,please to download!")) {
2955
+ const reg = /(SunBrowser|FlowerBrowser) (\d+) is not ready,please to download!/;
2956
+ const match = msg.match(reg);
2957
+ if (match) {
2958
+ const kernelType = match[1] === "FlowerBrowser" ? "Firefox" : "Chrome";
2959
+ const kernelVersion = match[2];
2960
+ if (kernelType && kernelVersion) {
2961
+ const answer = await promptYesNo(`[?] Kernel ${match[1]} ${kernelVersion} is not ready. Download now?`);
2962
+ if (answer === "y") {
2963
+ const _params = { "kernel_type": kernelType, "kernel_version": kernelVersion };
2964
+ await handleAction(
2965
+ JSON.stringify(_params),
2966
+ {},
2967
+ { name: () => "download-kernel" },
2968
+ STATELESS_HANDLERS["download-kernel"].fn
2969
+ );
2970
+ await sleepTime(1e3 * 3);
2971
+ await handleAction(
2972
+ params,
2973
+ {},
2974
+ { name: () => "open-browser" },
2975
+ STATELESS_HANDLERS["open-browser"].fn
2976
+ );
2977
+ }
2978
+ }
2979
+ }
2980
+ }
2981
+ }
2982
+ if (commandName === "close-browser") {
2983
+ if (msg.includes("Profile does not exist")) {
2984
+ const answer = await promptYesNo(`[?] Profile does not exist. Check all opened profiles?`);
2985
+ if (answer === "y") {
2986
+ const result = await handleAction(
2987
+ "{}",
2988
+ {},
2989
+ { name: () => "get-opened-browser" },
2990
+ STATELESS_HANDLERS["get-opened-browser"].fn
2991
+ );
2992
+ if (result) {
2993
+ try {
2994
+ const data = JSON.parse(result);
2995
+ const userIds = data.list.map((item) => item.user_id);
2996
+ if (userIds.length === 1) {
2997
+ const answer2 = await promptYesNo(`[?] Only one opened profile. Close it now?`);
2998
+ if (answer2 === "y") {
2999
+ await handleAction(
3000
+ `{"profile_id":["${userIds[0]}"]}`,
3001
+ {},
3002
+ { name: () => "close-browser" },
3003
+ STATELESS_HANDLERS["close-browser"].fn
3004
+ );
3005
+ }
3006
+ } else if (userIds.length > 1) {
3007
+ logWarning(`[!] Closeable profiles: ${userIds.join(", ")}`);
3008
+ logWarning(`[!] If you want to close all profiles, please enter "ads close-all-profiles"`);
3009
+ }
3010
+ } catch (error) {
3011
+ console.error(error);
3012
+ }
3013
+ }
3014
+ }
3015
+ }
3016
+ }
3017
+ };
3018
+ async function promptYesNo(question) {
3019
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
3020
+ logWarning("[!] Interactive prompt is unavailable in non-interactive mode.");
3021
+ return null;
3022
+ }
3023
+ const rl = readline.createInterface({
3024
+ input: process.stdin,
3025
+ output: process.stdout
3026
+ });
3027
+ try {
3028
+ while (true) {
3029
+ const answer = (await rl.question(`${question} [y/N]: `)).trim().toLowerCase();
3030
+ if (answer === "y" || answer === "yes") {
3031
+ return "y";
3032
+ }
3033
+ if (answer === "n" || answer === "no" || answer === "") {
3034
+ return "n";
3035
+ }
3036
+ logWarning("[!] Please enter y or n.");
3037
+ }
3038
+ } finally {
3039
+ rl.close();
3040
+ }
3041
+ }
3042
+
2769
3043
  // src/index.ts
2770
- var program = new import_commander.Command();
2771
- program.name("adspower-browser").description("CLI and runtime for adspower-browser").version(VERSION);
2772
- 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) => {
3044
+ var program = new import_commander2.Command();
3045
+ program.description("CLI and runtime for adspower-browser").version(VERSION);
3046
+ 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) => {
2773
3047
  const resolvedApiKey = resolveStartApiKey(options.apiKey, process.env);
2774
3048
  if (!resolvedApiKey.ok) {
2775
3049
  logError(resolvedApiKey.error);
@@ -2795,53 +3069,19 @@ program.command("status").description("Get the status of the adspower runtime").
2795
3069
  });
2796
3070
  for (const cmd of Object.keys(STATELESS_HANDLERS)) {
2797
3071
  const fnc = STATELESS_HANDLERS[cmd].fn;
2798
- 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) => {
2799
- const isRun = await hasRunning(options);
2800
- if (!isRun) {
2801
- logError("[!] Adspower runtime is not running");
2802
- const info = `[i] Please run "${(0, import_colors2.green)("adspower-browser start -k <apiKey>")}" to start the adspower runtime`;
2803
- console.log(info);
2804
- return;
2805
- }
2806
- const { apiKey, port } = getApiKeyAndPort(options);
2807
- updateConfig(apiKey, port);
2808
- const resolved = resolveStatelessCommandArgs(command.name(), params);
2809
- if (!resolved.ok) {
2810
- logError(resolved.error);
2811
- return;
2812
- }
2813
- const args = resolved.args;
2814
- logSuccess(`Executing command: ${command.name()}, params: ${JSON.stringify(args)}`);
2815
- const loading = createLoading(`Executing ${command.name()}...`);
2816
- try {
2817
- if (command.name() === "download-kernel") {
2818
- loading.stop();
2819
- const result = await trackKernelDownload(fnc, args);
2820
- const out = typeof result === "string" ? result : JSON.stringify(result, null, 2);
2821
- logInfo(`
2822
-
2823
- ${out}
2824
-
2825
- `);
2826
- } else {
2827
- const result = await fnc(args);
2828
- const out = typeof result === "string" ? result : JSON.stringify(result, null, 2);
2829
- logInfo(`
2830
-
2831
- ${out}
2832
- `);
2833
- if (command.name() === "update-patch" && !out.includes("The client is already on the latest patch version. No update is required")) {
2834
- loading.stop();
2835
- await sleepTime(1e3 * 60);
2836
- await restartChild();
2837
- }
2838
- }
2839
- } finally {
2840
- loading.stop();
2841
- }
3072
+ 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) => {
3073
+ await handleAction(params, options, command, fnc);
2842
3074
  });
2843
3075
  }
2844
- program.parseAsync(process.argv).catch((error) => {
2845
- console.error(error);
2846
- process.exit(1);
2847
- });
3076
+ setupShellCompletion(program);
3077
+ var shellScriptArg = process.argv[2] === "complete" ? process.argv[3] : void 0;
3078
+ var restoreStdout = wrapShellScriptOutput(shellScriptArg);
3079
+ if (isShellCompletionRequest()) {
3080
+ program.parse(process.argv);
3081
+ restoreStdout();
3082
+ } else {
3083
+ program.parseAsync(process.argv).catch((error) => {
3084
+ console.error(error);
3085
+ process.exit(1);
3086
+ }).finally(restoreStdout);
3087
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adspower-browser",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
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:*",