siluzan-tso-cli 1.0.0-beta.30 → 1.0.0-beta.32

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
@@ -20,7 +20,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
20
20
  siluzan-tso init --force # 强制覆盖已存在文件
21
21
  ```
22
22
 
23
- > **注意**:当前为测试版(1.0.0-beta.30),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
23
+ > **注意**:当前为测试版(1.0.0-beta.32),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
24
24
 
25
25
  | 助手 | 建议 `--ai` |
26
26
  |------|-------------|
package/dist/index.js CHANGED
@@ -802,11 +802,16 @@ function findDpByUrl(nodes, targetUrl) {
802
802
  }
803
803
  return void 0;
804
804
  }
805
- async function fetchDataPermission(mainApiUrl, authToken) {
805
+ async function fetchDataPermission(mainApiUrl, auth) {
806
806
  const url = `${mainApiUrl}/command/menu/GetUserPermissions`;
807
+ const authHeaders = auth.apiKey ? { "x-api-key": auth.apiKey } : { Authorization: `Bearer ${auth.authToken}` };
807
808
  try {
808
809
  const res = await fetch(url, {
809
- headers: { Authorization: `Bearer ${authToken}`, "Content-Type": "application/json" }
810
+ headers: {
811
+ "Content-Type": "application/json",
812
+ "Accept-Language": "zh-CN",
813
+ ...authHeaders
814
+ }
810
815
  });
811
816
  if (!res.ok) return "";
812
817
  const json = await res.json();
@@ -1218,6 +1223,18 @@ async function runUpdate(options) {
1218
1223
  console.log(" \u5982\u679C AI \u52A9\u624B\u6B63\u5728\u8FD0\u884C\uFF0C\u5EFA\u8BAE\u91CD\u542F\u4EE5\u4F7F\u65B0 Skill \u6587\u4EF6\u751F\u6548\u3002\n");
1219
1224
  }
1220
1225
 
1226
+ // src/utils/list-json-envelope.ts
1227
+ function wrapListJson(params) {
1228
+ const itemCount = Array.isArray(params.items) ? params.items.length : 0;
1229
+ return {
1230
+ page: params.page,
1231
+ pageSize: params.pageSize,
1232
+ total: params.total === void 0 || params.total === null ? null : params.total,
1233
+ itemCount,
1234
+ items: params.items
1235
+ };
1236
+ }
1237
+
1221
1238
  // src/utils/cli-table.ts
1222
1239
  import Table from "cli-table3";
1223
1240
  var ASCII_TABLE_CHARS = {
@@ -1537,7 +1554,7 @@ async function runListAccounts(opts) {
1537
1554
  process.exit(1);
1538
1555
  }
1539
1556
  }
1540
- if (items.length > 0) {
1557
+ if (items.length > 0 && !opts.quick) {
1541
1558
  const groups = /* @__PURE__ */ new Map();
1542
1559
  for (const item of items) {
1543
1560
  const id = item.ma.mediaCustomerId;
@@ -1611,17 +1628,32 @@ async function runListAccounts(opts) {
1611
1628
  }
1612
1629
  }
1613
1630
  if (opts.json) {
1614
- console.log(JSON.stringify(items, null, 2));
1631
+ console.log(
1632
+ JSON.stringify(
1633
+ wrapListJson({
1634
+ page,
1635
+ pageSize,
1636
+ total: total ?? null,
1637
+ items
1638
+ }),
1639
+ null,
1640
+ 2
1641
+ )
1642
+ );
1615
1643
  return;
1616
1644
  }
1645
+ const totalInfo = total !== void 0 ? `\uFF0C\u5171 ${total} \u6761` : "";
1646
+ let listHeader = `
1647
+ \u5E7F\u544A\u8D26\u6237\u5217\u8868\uFF08\u7B2C ${page} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761${totalInfo}\uFF09`;
1648
+ if (opts.quick) {
1649
+ listHeader += "\n \uFF08\u5FEB\u901F\u6A21\u5F0F\uFF1A\u672A\u5408\u5E76\u4F59\u989D\u3001\u6295\u653E\u6D88\u8017\u4E0E Arit \u5F97\u5206\uFF1B\u8868\u4E2D\u5BF9\u5E94\u5217\u4E3A\u300C-\u300D\u3002TikTok/Meta \u4ECD\u5408\u5E76\u5217\u8868\u63A5\u53E3\u540C\u5305\u5185\u7684 adList\u3002\uFF09";
1650
+ }
1651
+ listHeader += "\n";
1652
+ console.log(listHeader);
1617
1653
  if (items.length === 0) {
1618
- console.log("\n\u6682\u65E0\u5E7F\u544A\u8D26\u6237\u6570\u636E\u3002\n");
1654
+ console.log("\u6682\u65E0\u5E7F\u544A\u8D26\u6237\u6570\u636E\u3002\n");
1619
1655
  return;
1620
1656
  }
1621
- const totalInfo = total !== void 0 ? `\uFF0C\u5171 ${total} \u6761` : "";
1622
- console.log(`
1623
- \u5E7F\u544A\u8D26\u6237\u5217\u8868\uFF08\u7B2C ${page} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761${totalInfo}\uFF09
1624
- `);
1625
1657
  const isGoogle = opts.media === "Google";
1626
1658
  const isYandex = opts.media === "Yandex";
1627
1659
  const isTikTok = opts.media === "TikTok";
@@ -1989,26 +2021,30 @@ async function runBalance(opts) {
1989
2021
  `);
1990
2022
  process.exit(1);
1991
2023
  }
2024
+ const out = accountIds.map((id) => {
2025
+ const info = balanceMap.get(id);
2026
+ return {
2027
+ mediaCustomerId: id,
2028
+ remainingAccountBudget: info?.remainingAccountBudget ?? null,
2029
+ status: info?.status ?? null,
2030
+ currencyCode: info?.currencyCode ?? null,
2031
+ name: info?.name ?? null
2032
+ };
2033
+ });
1992
2034
  if (opts.json) {
1993
- const out = accountIds.map((id) => {
1994
- const info = balanceMap.get(id);
1995
- return {
1996
- mediaCustomerId: id,
1997
- remainingAccountBudget: info?.remainingAccountBudget ?? null,
1998
- status: info?.status ?? null,
1999
- currencyCode: info?.currencyCode ?? null,
2000
- name: info?.name ?? null
2001
- };
2002
- });
2003
- console.log(JSON.stringify(out, null, 2));
2035
+ const n = out.length;
2036
+ console.log(JSON.stringify(wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items: out }), null, 2));
2004
2037
  return;
2005
2038
  }
2006
2039
  if (balanceMap.size === 0) {
2007
- console.log("\n\u672A\u8FD4\u56DE\u4F59\u989D\u6570\u636E\uFF0C\u8BF7\u786E\u8BA4\u8D26\u6237 ID \u662F\u5426\u6B63\u786E\u4E14\u8D26\u6237\u72B6\u6001\u6709\u6548\u3002\n");
2040
+ console.log(`
2041
+ ${media} \u8D26\u6237\u4F59\u989D\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 0 \u6761\uFF0C\u5171 0 \u6761\uFF09
2042
+ `);
2043
+ console.log("\u672A\u8FD4\u56DE\u4F59\u989D\u6570\u636E\uFF0C\u8BF7\u786E\u8BA4\u8D26\u6237 ID \u662F\u5426\u6B63\u786E\u4E14\u8D26\u6237\u72B6\u6001\u6709\u6548\u3002\n");
2008
2044
  return;
2009
2045
  }
2010
2046
  console.log(`
2011
- ${media} \u8D26\u6237\u4F59\u989D
2047
+ ${media} \u8D26\u6237\u4F59\u989D\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${out.length} \u6761\uFF0C\u5171 ${out.length} \u6761\uFF09
2012
2048
  `);
2013
2049
  const cols = [
2014
2050
  { key: "id", header: "\u8D26\u6237ID" },
@@ -2084,17 +2120,20 @@ async function runStats(opts) {
2084
2120
  }
2085
2121
  const items = Array.isArray(raw) ? raw : raw.items ?? [];
2086
2122
  if (opts.json) {
2087
- console.log(JSON.stringify(items, null, 2));
2123
+ const n = items.length;
2124
+ console.log(JSON.stringify(wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items }), null, 2));
2088
2125
  return;
2089
2126
  }
2127
+ const rangeLabel = `${startDate} ~ ${endDate}`;
2090
2128
  if (items.length === 0) {
2091
2129
  console.log(`
2092
- ${opts.media} \u5728 ${startDate} ~ ${endDate} \u65E0\u6295\u653E\u6570\u636E\u3002
2130
+ ${opts.media} \u6295\u653E\u6570\u636E\uFF08${rangeLabel}\uFF09\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 0 \u6761\uFF0C\u5171 0 \u6761\uFF09
2093
2131
  `);
2132
+ console.log("\u65E0\u6295\u653E\u6570\u636E\u3002\n");
2094
2133
  return;
2095
2134
  }
2096
2135
  console.log(`
2097
- ${opts.media} \u6295\u653E\u6570\u636E\uFF08${startDate} ~ ${endDate}\uFF09
2136
+ ${opts.media} \u6295\u653E\u6570\u636E\uFF08${rangeLabel}\uFF09\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${items.length} \u6761\uFF09
2098
2137
  `);
2099
2138
  const cols = [
2100
2139
  { key: "id", header: "\u8D26\u6237ID" },
@@ -2162,27 +2201,43 @@ async function runAccountHistory(opts) {
2162
2201
  params.set("mediaAccountState", opts.status ?? historyStates);
2163
2202
  const url = `${config.apiBaseUrl}/query/media-account/?${params}`;
2164
2203
  let items;
2204
+ let total;
2165
2205
  try {
2166
- items = await apiFetch2(url, config, {}, opts.verbose);
2206
+ const res = await apiFetchWithHeaders2(url, config, {}, opts.verbose);
2207
+ items = res.data ?? [];
2208
+ const hit = res.headers["s-total-hits"];
2209
+ if (hit !== void 0) total = parseInt(hit, 10) || void 0;
2167
2210
  } catch (err) {
2168
2211
  console.error(`
2169
2212
  \u274C \u67E5\u8BE2\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
2170
2213
  `);
2171
2214
  process.exit(1);
2172
2215
  }
2216
+ const page = opts.page ?? 1;
2217
+ const pageSize = opts.pageSize ?? 20;
2173
2218
  if (opts.json) {
2174
- console.log(JSON.stringify(items, null, 2));
2219
+ console.log(
2220
+ JSON.stringify(
2221
+ wrapListJson({
2222
+ page,
2223
+ pageSize,
2224
+ total: total ?? null,
2225
+ items
2226
+ }),
2227
+ null,
2228
+ 2
2229
+ )
2230
+ );
2175
2231
  return;
2176
2232
  }
2233
+ const totalInfo = total !== void 0 ? `\uFF0C\u5171 ${total} \u6761` : "";
2234
+ console.log(`
2235
+ \u5F00\u6237\u7533\u8BF7\u5386\u53F2\uFF08\u7B2C ${page} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761${totalInfo}\uFF09
2236
+ `);
2177
2237
  if (items.length === 0) {
2178
- console.log("\n\u6682\u65E0\u5F00\u6237\u7533\u8BF7\u8BB0\u5F55\u3002\n");
2238
+ console.log("\u6682\u65E0\u5F00\u6237\u7533\u8BF7\u8BB0\u5F55\u3002\n");
2179
2239
  return;
2180
2240
  }
2181
- const page = opts.page ?? 1;
2182
- const pageSize = opts.pageSize ?? 20;
2183
- console.log(`
2184
- \u5F00\u6237\u7533\u8BF7\u5386\u53F2\uFF08\u7B2C ${page} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF09
2185
- `);
2186
2241
  const rows = items.map((item) => ({
2187
2242
  mediaType: item.ma.mediaAccountType ?? "",
2188
2243
  mediaCustomerId: item.ma.mediaCustomerId ?? "(\u672A\u5F00\u901A)",
@@ -2198,7 +2253,8 @@ async function runAccountHistory(opts) {
2198
2253
  { key: "createdAt", header: "\u521B\u5EFA\u65E5\u671F" }
2199
2254
  ];
2200
2255
  printCliTable(rows, cols);
2201
- if (items.length >= pageSize) {
2256
+ const hasMore = total !== void 0 ? page * pageSize < total : items.length >= pageSize;
2257
+ if (hasMore) {
2202
2258
  console.log(`
2203
2259
  \u4F7F\u7528 --page <n> \u7FFB\u9875\uFF0C--page-size <n> \u8C03\u6574\u6BCF\u9875\u6570\u91CF\u3002`);
2204
2260
  }
@@ -2245,14 +2301,14 @@ async function runReportList(opts) {
2245
2301
  ...item,
2246
2302
  viewUrl: item.reportReady ? `${webUrl}/media-report/${pathByType[item.reportType ?? ""] ?? "publish"}/${item.entityId}?culture=zh-CN` : ""
2247
2303
  }));
2304
+ const page = opts.page ?? 1;
2305
+ const pageSize = opts.pageSize ?? 20;
2248
2306
  if (opts.json) {
2249
- console.log(JSON.stringify({ ...data, results: itemsWithUrl }, null, 2));
2307
+ console.log(JSON.stringify(wrapListJson({ page, pageSize, total, items: itemsWithUrl }), null, 2));
2250
2308
  return;
2251
2309
  }
2252
- const page = opts.page ?? 1;
2253
- const pageSize = opts.pageSize ?? 20;
2254
2310
  console.log(`
2255
- \u4F18\u5316\u62A5\u544A\u5217\u8868\uFF08\u7B2C ${page}/${Math.ceil(total / pageSize)} \u9875\uFF0C\u5171 ${total} \u6761\uFF09
2311
+ \u4F18\u5316\u62A5\u544A\u5217\u8868\uFF08\u7B2C ${page}/${Math.max(1, Math.ceil(total / pageSize))} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${total} \u6761\uFF09
2256
2312
  `);
2257
2313
  if (items.length === 0) {
2258
2314
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -2489,15 +2545,19 @@ async function runReportPushList(opts) {
2489
2545
  `);
2490
2546
  process.exit(1);
2491
2547
  }
2548
+ const items = data.results ?? [];
2549
+ const total = data.totalResultCount ?? 0;
2550
+ const page = opts.page ?? 1;
2551
+ const pageSize = opts.pageSize ?? 20;
2492
2552
  if (opts.json) {
2493
- console.log(JSON.stringify(data, null, 2));
2553
+ console.log(JSON.stringify(wrapListJson({ page, pageSize, total, items }), null, 2));
2494
2554
  return;
2495
2555
  }
2496
- const items = data.results ?? [];
2497
- const total = data.totalResultCount ?? 0;
2498
- console.log(`
2499
- \u63A8\u9001\u7BA1\u7406\u5217\u8868\uFF08\u5171 ${total} \u6761\uFF09
2500
- `);
2556
+ console.log(
2557
+ `
2558
+ \u63A8\u9001\u7BA1\u7406\u5217\u8868\uFF08\u7B2C ${page}/${Math.max(1, Math.ceil(total / pageSize))} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${total} \u6761\uFF09
2559
+ `
2560
+ );
2501
2561
  if (items.length === 0) {
2502
2562
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
2503
2563
  return;
@@ -3629,16 +3689,16 @@ async function runTransferList(opts) {
3629
3689
  `);
3630
3690
  process.exit(1);
3631
3691
  }
3632
- if (opts.json) {
3633
- console.log(JSON.stringify(data, null, 2));
3634
- return;
3635
- }
3636
3692
  const items = data.list ?? data.results ?? [];
3637
3693
  const total = data.total ?? data.totalResultCount ?? 0;
3638
3694
  const page = opts.page ?? 1;
3639
3695
  const pageSize = opts.pageSize ?? 20;
3696
+ if (opts.json) {
3697
+ console.log(JSON.stringify(wrapListJson({ page, pageSize, total, items }), null, 2));
3698
+ return;
3699
+ }
3640
3700
  console.log(`
3641
- \u8F6C\u8D26\u8BB0\u5F55\uFF08\u7B2C ${page}/${Math.ceil(total / pageSize)} \u9875\uFF0C\u5171 ${total} \u6761\uFF09
3701
+ \u8F6C\u8D26\u8BB0\u5F55\uFF08\u7B2C ${page}/${Math.max(1, Math.ceil(total / pageSize))} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${total} \u6761\uFF09
3642
3702
  `);
3643
3703
  if (items.length === 0) {
3644
3704
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -3684,7 +3744,7 @@ import * as os6 from "os";
3684
3744
  async function ensureDataPermission(config) {
3685
3745
  if (config.dataPermission) return config;
3686
3746
  if (!config.mainApiUrl) return config;
3687
- const dp = await fetchDataPermission(config.mainApiUrl, config.authToken);
3747
+ const dp = await fetchDataPermission(config.mainApiUrl, config);
3688
3748
  if (!dp) return config;
3689
3749
  const configPath = path7.join(os6.homedir(), ".siluzan", "config.json");
3690
3750
  try {
@@ -3720,16 +3780,16 @@ async function runInvoiceList(opts) {
3720
3780
  `);
3721
3781
  process.exit(1);
3722
3782
  }
3723
- if (opts.json) {
3724
- console.log(JSON.stringify(data, null, 2));
3725
- return;
3726
- }
3727
3783
  const items = data.results ?? [];
3728
3784
  const total = data.totalResultCount ?? 0;
3729
3785
  const page = opts.page ?? 1;
3730
3786
  const pageSize = opts.pageSize ?? 20;
3787
+ if (opts.json) {
3788
+ console.log(JSON.stringify(wrapListJson({ page, pageSize, total, items }), null, 2));
3789
+ return;
3790
+ }
3731
3791
  console.log(`
3732
- \u5F00\u7968\u8BB0\u5F55\uFF08\u7B2C ${page}/${Math.ceil(total / pageSize)} \u9875\uFF0C\u5171 ${total} \u6761\uFF09
3792
+ \u5F00\u7968\u8BB0\u5F55\uFF08\u7B2C ${page}/${Math.max(1, Math.ceil(total / pageSize))} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${total} \u6761\uFF09
3733
3793
  `);
3734
3794
  if (items.length === 0) {
3735
3795
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -3853,17 +3913,17 @@ async function runInvoiceBillable(opts) {
3853
3913
  `);
3854
3914
  process.exit(1);
3855
3915
  }
3856
- if (opts.json) {
3857
- console.log(JSON.stringify(data, null, 2));
3858
- return;
3859
- }
3860
3916
  const items = data.results ?? [];
3861
3917
  const total = data.totalResultCount ?? 0;
3862
3918
  const page = opts.page ?? 1;
3863
3919
  const pageSize = opts.pageSize ?? 20;
3920
+ if (opts.json) {
3921
+ console.log(JSON.stringify(wrapListJson({ page, pageSize, total, items }), null, 2));
3922
+ return;
3923
+ }
3864
3924
  const label = opts.wallet ? "\u94B1\u5305\u53EF\u5F00\u7968\u8BB0\u5F55" : "\u5145\u503C\u53EF\u5F00\u7968\u8BA2\u5355";
3865
3925
  console.log(`
3866
- ${label}\uFF08\u7B2C ${page}/${Math.ceil(total / pageSize)} \u9875\uFF0C\u5171 ${total} \u6761\uFF09
3926
+ ${label}\uFF08\u7B2C ${page}/${Math.max(1, Math.ceil(total / pageSize))} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${total} \u6761\uFF09
3867
3927
  `);
3868
3928
  if (items.length === 0) {
3869
3929
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -4088,17 +4148,19 @@ async function runInvoiceInfoList(opts) {
4088
4148
  `);
4089
4149
  process.exit(1);
4090
4150
  }
4091
- if (opts.json) {
4092
- console.log(JSON.stringify(data, null, 2));
4093
- return;
4094
- }
4095
4151
  const items = data.results ?? [];
4096
4152
  const total = data.totalResultCount ?? 0;
4097
4153
  const page = opts.page ?? 1;
4098
4154
  const pageSize = opts.pageSize ?? 20;
4099
- console.log(`
4100
- \u53D1\u7968\u62AC\u5934\uFF08\u7B2C ${page}/${Math.max(1, Math.ceil(total / pageSize))} \u9875\uFF0C\u5171 ${total} \u6761\uFF09
4101
- `);
4155
+ if (opts.json) {
4156
+ console.log(JSON.stringify(wrapListJson({ page, pageSize, total, items }), null, 2));
4157
+ return;
4158
+ }
4159
+ console.log(
4160
+ `
4161
+ \u53D1\u7968\u62AC\u5934\uFF08\u7B2C ${page}/${Math.max(1, Math.ceil(total / pageSize))} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${total} \u6761\uFF09
4162
+ `
4163
+ );
4102
4164
  if (items.length === 0) {
4103
4165
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
4104
4166
  return;
@@ -4256,16 +4318,16 @@ async function runAiCreationList(opts) {
4256
4318
  `);
4257
4319
  process.exit(1);
4258
4320
  }
4259
- if (opts.json) {
4260
- console.log(JSON.stringify(data, null, 2));
4261
- return;
4262
- }
4263
4321
  const items = data.results ?? [];
4264
4322
  const total = data.totalResultCount ?? 0;
4265
4323
  const page = opts.page ?? 1;
4266
4324
  const pageSize = opts.pageSize ?? 20;
4325
+ if (opts.json) {
4326
+ console.log(JSON.stringify(wrapListJson({ page, pageSize, total, items }), null, 2));
4327
+ return;
4328
+ }
4267
4329
  console.log(`
4268
- AI\u667A\u6295\u8BB0\u5F55\uFF08\u7B2C ${page}/${Math.ceil(total / pageSize)} \u9875\uFF0C\u5171 ${total} \u6761\uFF09
4330
+ AI\u667A\u6295\u8BB0\u5F55\uFF08\u7B2C ${page}/${Math.max(1, Math.ceil(total / pageSize))} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${total} \u6761\uFF09
4269
4331
  `);
4270
4332
  if (items.length === 0) {
4271
4333
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -5287,16 +5349,16 @@ async function runOptimizeList(opts) {
5287
5349
  `);
5288
5350
  process.exit(1);
5289
5351
  }
5290
- if (opts.json) {
5291
- console.log(JSON.stringify(data, null, 2));
5292
- return;
5293
- }
5294
5352
  const items = data.results ?? [];
5295
5353
  const total = data.totalResultCount ?? 0;
5296
5354
  const page = opts.page ?? 1;
5297
5355
  const pageSize = opts.pageSize ?? 20;
5356
+ if (opts.json) {
5357
+ console.log(JSON.stringify(wrapListJson({ page, pageSize, total, items }), null, 2));
5358
+ return;
5359
+ }
5298
5360
  console.log(`
5299
- AI\u5E7F\u544A\u4F18\u5316\uFF08\u7B2C ${page}/${Math.ceil(total / pageSize)} \u9875\uFF0C\u5171 ${total} \u4E2A\u8D26\u6237\uFF09
5361
+ AI\u5E7F\u544A\u4F18\u5316\uFF08\u7B2C ${page}/${Math.max(1, Math.ceil(total / pageSize))} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${total} \u6761\uFF09
5300
5362
  `);
5301
5363
  if (items.length === 0) {
5302
5364
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -5341,21 +5403,21 @@ async function runOptimizeRecords(opts) {
5341
5403
  `);
5342
5404
  process.exit(1);
5343
5405
  }
5344
- if (opts.json) {
5345
- console.log(JSON.stringify(data, null, 2));
5346
- return;
5347
- }
5348
5406
  const items = data.results ?? [];
5349
5407
  const total = data.totalResultCount ?? 0;
5350
5408
  const page = opts.page ?? 1;
5351
5409
  const pageSize = opts.pageSize ?? 20;
5410
+ if (opts.json) {
5411
+ console.log(JSON.stringify(wrapListJson({ page, pageSize, total, items }), null, 2));
5412
+ return;
5413
+ }
5352
5414
  const stateLabels = {
5353
5415
  Created: "\u5DF2\u521B\u5EFA",
5354
5416
  Optimizing: "\u4F18\u5316\u4E2D",
5355
5417
  Optimized: "\u5DF2\u5B8C\u6210"
5356
5418
  };
5357
5419
  console.log(`
5358
- \u4F18\u5316\u8BB0\u5F55\uFF08\u7B2C ${page}/${Math.ceil(total / pageSize)} \u9875\uFF0C\u5171 ${total} \u6761\uFF09
5420
+ \u4F18\u5316\u8BB0\u5F55\uFF08\u7B2C ${page}/${Math.max(1, Math.ceil(total / pageSize))} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${total} \u6761\uFF09
5359
5421
  `);
5360
5422
  if (items.length === 0) {
5361
5423
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -5383,15 +5445,19 @@ async function runOptimizeChildren(opts) {
5383
5445
  `);
5384
5446
  process.exit(1);
5385
5447
  }
5448
+ const items = data.results ?? [];
5449
+ const total = data.totalResultCount ?? 0;
5450
+ const page = opts.page ?? 1;
5451
+ const pageSize = opts.pageSize ?? 20;
5386
5452
  if (opts.json) {
5387
- console.log(JSON.stringify(data, null, 2));
5453
+ console.log(JSON.stringify(wrapListJson({ page, pageSize, total, items }), null, 2));
5388
5454
  return;
5389
5455
  }
5390
- const items = data.results ?? [];
5391
- const total = data.totalResultCount ?? 0;
5392
- console.log(`
5393
- \u5E7F\u544A\u7CFB\u5217\u4F18\u5316\u660E\u7EC6\uFF08parentId: ${opts.parentId}\uFF0C\u5171 ${total} \u6761\uFF09
5394
- `);
5456
+ console.log(
5457
+ `
5458
+ \u5E7F\u544A\u7CFB\u5217\u4F18\u5316\u660E\u7EC6\uFF08parentId: ${opts.parentId}\uFF0C\u7B2C ${page}/${Math.max(1, Math.ceil(total / pageSize))} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${total} \u6761\uFF09
5459
+ `
5460
+ );
5395
5461
  if (items.length === 0) {
5396
5462
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
5397
5463
  return;
@@ -5437,16 +5503,16 @@ async function runForewarningList(opts) {
5437
5503
  `);
5438
5504
  process.exit(1);
5439
5505
  }
5440
- if (opts.json) {
5441
- console.log(JSON.stringify(data, null, 2));
5442
- return;
5443
- }
5444
5506
  const items = data.results ?? [];
5445
5507
  const total = data.totalResultCount ?? 0;
5446
5508
  const page = opts.page ?? 1;
5447
5509
  const pageSize = opts.pageSize ?? 20;
5510
+ if (opts.json) {
5511
+ console.log(JSON.stringify(wrapListJson({ page, pageSize, total, items }), null, 2));
5512
+ return;
5513
+ }
5448
5514
  console.log(`
5449
- \u667A\u80FD\u9884\u8B66\u89C4\u5219\uFF08\u7B2C ${page}/${Math.ceil(total / pageSize)} \u9875\uFF0C\u5171 ${total} \u6761\uFF09
5515
+ \u667A\u80FD\u9884\u8B66\u89C4\u5219\uFF08\u7B2C ${page}/${Math.max(1, Math.ceil(total / pageSize))} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${total} \u6761\uFF09
5450
5516
  `);
5451
5517
  if (items.length === 0) {
5452
5518
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -5505,16 +5571,16 @@ async function runForewarningRecords(opts) {
5505
5571
  `);
5506
5572
  process.exit(1);
5507
5573
  }
5508
- if (opts.json) {
5509
- console.log(JSON.stringify(data, null, 2));
5510
- return;
5511
- }
5512
5574
  const items = data.results ?? [];
5513
5575
  const total = data.totalResultCount ?? 0;
5514
5576
  const page = opts.page ?? 1;
5515
5577
  const pageSize = opts.pageSize ?? 20;
5578
+ if (opts.json) {
5579
+ console.log(JSON.stringify(wrapListJson({ page, pageSize, total, items }), null, 2));
5580
+ return;
5581
+ }
5516
5582
  console.log(`
5517
- \u9884\u8B66\u8BB0\u5F55\uFF08\u7B2C ${page}/${Math.ceil(total / pageSize)} \u9875\uFF0C\u5171 ${total} \u6761\uFF09
5583
+ \u9884\u8B66\u8BB0\u5F55\uFF08\u7B2C ${page}/${Math.max(1, Math.ceil(total / pageSize))} \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${total} \u6761\uFF09
5518
5584
  `);
5519
5585
  if (items.length === 0) {
5520
5586
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -5594,8 +5660,11 @@ async function runForewarningNotifyAccounts(opts) {
5594
5660
  `);
5595
5661
  process.exit(1);
5596
5662
  }
5663
+ const page = 1;
5664
+ const pageSize = Math.max(accounts.length, 1);
5665
+ const total = accounts.length;
5597
5666
  if (opts.json) {
5598
- console.log(JSON.stringify(accounts, null, 2));
5667
+ console.log(JSON.stringify(wrapListJson({ page, pageSize, total, items: accounts }), null, 2));
5599
5668
  return;
5600
5669
  }
5601
5670
  const returnUrl = encodeURIComponent("https://tso.siluzan.com");
@@ -5606,7 +5675,9 @@ async function runForewarningNotifyAccounts(opts) {
5606
5675
  qrLink = typeof qrData === "string" ? qrData : qrData.redirectUrl ?? qrData.url ?? "";
5607
5676
  } catch {
5608
5677
  }
5609
- console.log("\n\u{1F4F1} \u5FAE\u4FE1\u901A\u77E5\u5BF9\u8C61\u5217\u8868\n");
5678
+ console.log(`
5679
+ \u{1F4F1} \u5FAE\u4FE1\u901A\u77E5\u5BF9\u8C61\u5217\u8868\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${accounts.length} \u6761\uFF0C\u5171 ${accounts.length} \u6761\uFF09
5680
+ `);
5610
5681
  console.log(" \u901A\u77E5\u6E20\u9053\uFF1A\u4E1D\u8DEF\u8D5E\u5E73\u53F0\u5FAE\u4FE1\u670D\u52A1\u53F7\uFF08\u9700\u626B\u7801\u5173\u6CE8\u540E\u624D\u80FD\u6536\u5230\u9884\u8B66\u901A\u77E5\uFF09\n");
5611
5682
  if (qrLink) {
5612
5683
  try {
@@ -5773,12 +5844,13 @@ async function fetchTikTokClues(opts, config) {
5773
5844
  `);
5774
5845
  process.exit(1);
5775
5846
  }
5847
+ const n = leads.length;
5776
5848
  if (opts.json) {
5777
- console.log(JSON.stringify(leads, null, 2));
5849
+ console.log(JSON.stringify(wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items: leads }), null, 2));
5778
5850
  return;
5779
5851
  }
5780
5852
  console.log(`
5781
- TikTok \u7EBF\u7D22\u8868\u5355\uFF08\u8D26\u6237 ${opts.account}\uFF0C\u5171 ${leads.length} \u6761\uFF09
5853
+ TikTok \u7EBF\u7D22\u8868\u5355\uFF08\u8D26\u6237 ${opts.account}\uFF0C\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${leads.length} \u6761\uFF0C\u5171 ${leads.length} \u6761\uFF09
5782
5854
  `);
5783
5855
  if (leads.length === 0) {
5784
5856
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -5813,12 +5885,13 @@ async function fetchMetaClues(opts, config) {
5813
5885
  const leads = (raw.formLeadsGroups ?? []).flatMap(
5814
5886
  (group) => (group.leads ?? []).filter((l) => !l["platform"] || l["platform"] === "fb").map((l) => ({ ...l, form: group.form }))
5815
5887
  );
5888
+ const n = leads.length;
5816
5889
  if (opts.json) {
5817
- console.log(JSON.stringify(leads, null, 2));
5890
+ console.log(JSON.stringify(wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items: leads }), null, 2));
5818
5891
  return;
5819
5892
  }
5820
5893
  console.log(`
5821
- Meta \u7EBF\u7D22\u8868\u5355\uFF08\u8D26\u6237 ${opts.account}\uFF0C\u5171 ${leads.length} \u6761\uFF09
5894
+ Meta \u7EBF\u7D22\u8868\u5355\uFF08\u8D26\u6237 ${opts.account}\uFF0C\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${leads.length} \u6761\uFF0C\u5171 ${leads.length} \u6761\uFF09
5822
5895
  `);
5823
5896
  if (leads.length === 0) {
5824
5897
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -5885,13 +5958,24 @@ async function runAdCampaigns(opts) {
5885
5958
  `);
5886
5959
  process.exit(1);
5887
5960
  }
5961
+ const items = data.data ?? [];
5962
+ const n = items.length;
5888
5963
  if (opts.json) {
5889
- console.log(JSON.stringify(data, null, 2));
5964
+ console.log(
5965
+ JSON.stringify(
5966
+ {
5967
+ ...wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items }),
5968
+ code: data.code ?? null,
5969
+ message: data.message ?? null
5970
+ },
5971
+ null,
5972
+ 2
5973
+ )
5974
+ );
5890
5975
  return;
5891
5976
  }
5892
- const items = data.data ?? [];
5893
5977
  console.log(`
5894
- \u5E7F\u544A\u7CFB\u5217\uFF08\u8D26\u6237\uFF1A${opts.account}\uFF0C\u5171 ${items.length} \u6761\uFF09
5978
+ \u5E7F\u544A\u7CFB\u5217\uFF08\u8D26\u6237\uFF1A${opts.account}\uFF0C\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${items.length} \u6761\uFF09
5895
5979
  `);
5896
5980
  if (items.length === 0) {
5897
5981
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -5945,13 +6029,20 @@ async function runAdGroups(opts) {
5945
6029
  `);
5946
6030
  process.exit(1);
5947
6031
  }
6032
+ const items = data.data ?? [];
6033
+ const n = items.length;
5948
6034
  if (opts.json) {
5949
- console.log(JSON.stringify(data, null, 2));
6035
+ console.log(
6036
+ JSON.stringify(
6037
+ { ...wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items }), code: data.code ?? null },
6038
+ null,
6039
+ 2
6040
+ )
6041
+ );
5950
6042
  return;
5951
6043
  }
5952
- const items = data.data ?? [];
5953
6044
  console.log(`
5954
- \u5E7F\u544A\u7EC4\uFF08\u8D26\u6237\uFF1A${opts.account}\uFF0C\u5171 ${items.length} \u6761\uFF09
6045
+ \u5E7F\u544A\u7EC4\uFF08\u8D26\u6237\uFF1A${opts.account}\uFF0C\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${items.length} \u6761\uFF09
5955
6046
  `);
5956
6047
  if (items.length === 0) {
5957
6048
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -6003,13 +6094,14 @@ async function runAdList(opts) {
6003
6094
  `);
6004
6095
  process.exit(1);
6005
6096
  }
6097
+ const items = data.data ?? [];
6098
+ const n = items.length;
6006
6099
  if (opts.json) {
6007
- console.log(JSON.stringify(data, null, 2));
6100
+ console.log(JSON.stringify(wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items }), null, 2));
6008
6101
  return;
6009
6102
  }
6010
- const items = data.data ?? [];
6011
6103
  console.log(`
6012
- \u5E7F\u544A\uFF08\u8D26\u6237\uFF1A${opts.account}\uFF0C\u5171 ${items.length} \u6761\uFF09
6104
+ \u5E7F\u544A\uFF08\u8D26\u6237\uFF1A${opts.account}\uFF0C\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${items.length} \u6761\uFF09
6013
6105
  `);
6014
6106
  if (items.length === 0) {
6015
6107
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -6066,10 +6158,6 @@ async function runAdKeywords(opts) {
6066
6158
  `);
6067
6159
  process.exit(1);
6068
6160
  }
6069
- if (opts.json) {
6070
- console.log(JSON.stringify(data, null, 2));
6071
- return;
6072
- }
6073
6161
  const rawItems = data.data ?? [];
6074
6162
  const seen = /* @__PURE__ */ new Set();
6075
6163
  const items = rawItems.filter((item) => {
@@ -6079,8 +6167,13 @@ async function runAdKeywords(opts) {
6079
6167
  return true;
6080
6168
  });
6081
6169
  const label = opts.negative ? "\u5426\u5B9A\u5173\u952E\u8BCD" : "\u5173\u952E\u8BCD";
6170
+ const n = items.length;
6171
+ if (opts.json) {
6172
+ console.log(JSON.stringify(wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items }), null, 2));
6173
+ return;
6174
+ }
6082
6175
  console.log(`
6083
- ${label}\uFF08\u8D26\u6237\uFF1A${opts.account}\uFF0C\u5171 ${items.length} \u6761` + (rawItems.length !== items.length ? `\uFF0C\u539F\u59CB ${rawItems.length} \u6761\u5DF2\u53BB\u91CD` : "") + `\uFF09
6176
+ ${label}\uFF08\u8D26\u6237\uFF1A${opts.account}\uFF0C\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${items.length} \u6761` + (rawItems.length !== items.length ? `\uFF0C\u539F\u59CB ${rawItems.length} \u6761\u5DF2\u53BB\u91CD` : "") + `\uFF09
6084
6177
  `);
6085
6178
  if (items.length === 0) {
6086
6179
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -6774,10 +6867,6 @@ async function runAdExtensionList(opts) {
6774
6867
  `);
6775
6868
  process.exit(1);
6776
6869
  }
6777
- if (opts.json) {
6778
- console.log(JSON.stringify(data, null, 2));
6779
- return;
6780
- }
6781
6870
  let items = data.data ?? [];
6782
6871
  if (opts.type) {
6783
6872
  const filterType = opts.type.toUpperCase();
@@ -6785,8 +6874,13 @@ async function runAdExtensionList(opts) {
6785
6874
  (i) => String(i["typeV2"] ?? i["assetFieldType"] ?? "").toUpperCase() === filterType
6786
6875
  );
6787
6876
  }
6877
+ const n = items.length;
6878
+ if (opts.json) {
6879
+ console.log(JSON.stringify(wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items }), null, 2));
6880
+ return;
6881
+ }
6788
6882
  console.log(`
6789
- \u9644\u52A0\u4FE1\u606F\uFF08\u8D26\u6237\uFF1A${opts.account}\uFF0C\u5171 ${items.length} \u6761\uFF09
6883
+ \u9644\u52A0\u4FE1\u606F\uFF08\u8D26\u6237\uFF1A${opts.account}\uFF0C\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${items.length} \u6761\uFF09
6790
6884
  `);
6791
6885
  if (items.length === 0) {
6792
6886
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -6908,13 +7002,14 @@ async function runAdSearchTerms(opts) {
6908
7002
  `);
6909
7003
  process.exit(1);
6910
7004
  }
7005
+ const items = data.data ?? [];
7006
+ const n = items.length;
6911
7007
  if (opts.json) {
6912
- console.log(JSON.stringify(data, null, 2));
7008
+ console.log(JSON.stringify(wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items }), null, 2));
6913
7009
  return;
6914
7010
  }
6915
- const items = data.data ?? [];
6916
7011
  console.log(`
6917
- \u641C\u7D22\u5B57\u8BCD\uFF08\u8D26\u6237\uFF1A${opts.account}\uFF0C\u5171 ${items.length} \u6761\uFF09
7012
+ \u641C\u7D22\u5B57\u8BCD\uFF08\u8D26\u6237\uFF1A${opts.account}\uFF0C\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${items.length} \u6761\uFF09
6918
7013
  `);
6919
7014
  if (items.length === 0) {
6920
7015
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -7001,15 +7096,16 @@ async function runAdGeoList(opts) {
7001
7096
  `);
7002
7097
  process.exit(1);
7003
7098
  }
7004
- if (opts.json) {
7005
- console.log(JSON.stringify(data, null, 2));
7006
- return;
7007
- }
7008
7099
  const rawData = data.data;
7009
7100
  const items = Array.isArray(rawData) ? rawData : rawData?.countries ?? [];
7010
7101
  const modeLabel = { targeted: "\u5DF2\u5B9A\u4F4D", excluded: "\u5DF2\u6392\u9664", report: "\u6D88\u8017\u62A5\u544A" }[opts.mode];
7102
+ const n = items.length;
7103
+ if (opts.json) {
7104
+ console.log(JSON.stringify(wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items }), null, 2));
7105
+ return;
7106
+ }
7011
7107
  console.log(`
7012
- \u5730\u7406\u4F4D\u7F6E\uFF08${modeLabel}\uFF0C\u8D26\u6237\uFF1A${opts.account}\uFF0C\u5171 ${items.length} \u6761\uFF09
7108
+ \u5730\u7406\u4F4D\u7F6E\uFF08${modeLabel}\uFF0C\u8D26\u6237\uFF1A${opts.account}\uFF0C\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${items.length} \u6761\uFF09
7013
7109
  `);
7014
7110
  if (items.length === 0) {
7015
7111
  console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
@@ -7189,12 +7285,13 @@ async function runKeywordSuggest(opts) {
7189
7285
  return !excludes.some((exc) => kw.includes(exc));
7190
7286
  });
7191
7287
  }
7288
+ const n = items.length;
7192
7289
  if (opts.json) {
7193
- console.log(JSON.stringify(items, null, 2));
7290
+ console.log(JSON.stringify(wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items }), null, 2));
7194
7291
  return;
7195
7292
  }
7196
7293
  console.log(`
7197
- \u5173\u952E\u5B57\u63A8\u8350\uFF08\u5171 ${items.length} \u4E2A\uFF09
7294
+ \u5173\u952E\u5B57\u63A8\u8350\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${items.length} \u6761\uFF09
7198
7295
  `);
7199
7296
  if (items.length === 0) {
7200
7297
  console.log(" \u6682\u65E0\u63A8\u8350\u5173\u952E\u8BCD\u3002\n");
@@ -7705,11 +7802,13 @@ async function runAccountWithdrawList(opts) {
7705
7802
  `);
7706
7803
  process.exit(1);
7707
7804
  }
7805
+ const allItems = Array.isArray(data) ? data : [];
7806
+ const page = 1;
7807
+ const rawTotal = allItems.length;
7708
7808
  if (opts.json) {
7709
- console.log(JSON.stringify(data, null, 2));
7809
+ console.log(JSON.stringify(wrapListJson({ page, pageSize: Math.max(rawTotal, 1), total: rawTotal, items: allItems }), null, 2));
7710
7810
  return;
7711
7811
  }
7712
- const allItems = Array.isArray(data) ? data : [];
7713
7812
  const suspendedItems = allItems.filter((item) => item.mai?.status === "Suspended");
7714
7813
  const skippedCount = allItems.length - suspendedItems.length;
7715
7814
  if (skippedCount > 0) {
@@ -7718,7 +7817,10 @@ async function runAccountWithdrawList(opts) {
7718
7817
  `);
7719
7818
  }
7720
7819
  if (suspendedItems.length === 0) {
7721
- console.log("\n \u6682\u65E0 Google Suspended\uFF08\u88AB\u5C01\uFF09\u5E7F\u544A\u8D26\u6237\u3002\n");
7820
+ console.log(`
7821
+ Google Suspended\uFF08\u88AB\u5C01\u7981\uFF09\u8D26\u6237\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 0 \u6761\uFF0C\u5171 0 \u6761\uFF09
7822
+ `);
7823
+ console.log(" \u6682\u65E0 Google Suspended\uFF08\u88AB\u5C01\uFF09\u5E7F\u544A\u8D26\u6237\u3002\n");
7722
7824
  return;
7723
7825
  }
7724
7826
  const withdrawable = suspendedItems.filter((item) => {
@@ -7731,9 +7833,11 @@ async function runAccountWithdrawList(opts) {
7731
7833
  const adjustments = Number(item.mai?.totalAdjustmentsMicros ?? 0);
7732
7834
  return balance - adjustments <= 0;
7733
7835
  });
7734
- console.log(`
7735
- Google Suspended\uFF08\u88AB\u5C01\u7981\uFF09\u8D26\u6237\uFF08\u5171 ${suspendedItems.length} \u6761\uFF0C\u5176\u4E2D ${withdrawable.length} \u6761\u6709\u4F59\u989D\u53EF\u63D0\u73B0\uFF09
7736
- `);
7836
+ console.log(
7837
+ `
7838
+ Google Suspended\uFF08\u88AB\u5C01\u7981\uFF09\u8D26\u6237\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${suspendedItems.length} \u6761\uFF0C\u5171 ${suspendedItems.length} \u6761\uFF0C\u5176\u4E2D ${withdrawable.length} \u6761\u6709\u4F59\u989D\u53EF\u63D0\u73B0\uFF09
7839
+ `
7840
+ );
7737
7841
  const cols = [
7738
7842
  { key: "entityId", header: "entityId" },
7739
7843
  { key: "mediaCustomerId", header: "mediaCustomerId" },
@@ -8038,16 +8142,21 @@ async function runAccountEmailAuthList(opts) {
8038
8142
  `);
8039
8143
  process.exit(1);
8040
8144
  }
8145
+ const page = 1;
8146
+ const total = items.length;
8041
8147
  if (opts.json) {
8042
- console.log(JSON.stringify(items, null, 2));
8148
+ console.log(JSON.stringify(wrapListJson({ page, pageSize: Math.max(total, 1), total, items }), null, 2));
8043
8149
  return;
8044
8150
  }
8045
8151
  if (items.length === 0) {
8046
- console.log("\n \u6682\u65E0\u90AE\u7BB1\u6388\u6743\u8BB0\u5F55\u3002\n");
8152
+ console.log(`
8153
+ \u8D26\u6237 ${opts.customerId} \u7684\u90AE\u7BB1\u6388\u6743\u5217\u8868\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 0 \u6761\uFF0C\u5171 0 \u6761\uFF09
8154
+ `);
8155
+ console.log(" \u6682\u65E0\u90AE\u7BB1\u6388\u6743\u8BB0\u5F55\u3002\n");
8047
8156
  return;
8048
8157
  }
8049
8158
  console.log(`
8050
- \u8D26\u6237 ${opts.customerId} \u7684\u90AE\u7BB1\u6388\u6743\u5217\u8868\uFF08\u5171 ${items.length} \u6761\uFF09
8159
+ \u8D26\u6237 ${opts.customerId} \u7684\u90AE\u7BB1\u6388\u6743\u5217\u8868\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${items.length} \u6761\uFF0C\u5171 ${items.length} \u6761\uFF09
8051
8160
  `);
8052
8161
  const cols = [
8053
8162
  { key: "invitationId", header: "\u9080\u8BF7 ID" },
@@ -8215,17 +8324,20 @@ async function runListAdvertiserGroups(opts) {
8215
8324
  `);
8216
8325
  process.exit(1);
8217
8326
  }
8327
+ const groups = data?.profile?.mediaAccountGroups ?? [];
8328
+ const n = groups.length;
8329
+ const page = 1;
8218
8330
  if (opts.json) {
8219
- console.log(JSON.stringify(data?.profile?.mediaAccountGroups ?? [], null, 2));
8331
+ console.log(JSON.stringify(wrapListJson({ page, pageSize: Math.max(n, 1), total: n, items: groups }), null, 2));
8220
8332
  return;
8221
8333
  }
8222
- const groups = data?.profile?.mediaAccountGroups ?? [];
8223
8334
  if (groups.length === 0) {
8224
- console.log("\n \u6682\u65E0\u5E7F\u544A\u4E3B\u7EC4\uFF0C\u8BF7\u5148\u5728 Siluzan TSO \u5E73\u53F0\u521B\u5EFA\u5E7F\u544A\u4E3B\u3002\n");
8335
+ console.log("\n\u5E7F\u544A\u4E3B\u7EC4\u5217\u8868\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 0 \u6761\uFF0C\u5171 0 \u6761\uFF09\n");
8336
+ console.log(" \u6682\u65E0\u5E7F\u544A\u4E3B\u7EC4\uFF0C\u8BF7\u5148\u5728 Siluzan TSO \u5E73\u53F0\u521B\u5EFA\u5E7F\u544A\u4E3B\u3002\n");
8225
8337
  return;
8226
8338
  }
8227
8339
  console.log(`
8228
- \u5E7F\u544A\u4E3B\u7EC4\u5217\u8868\uFF08\u5171 ${groups.length} \u6761\uFF09
8340
+ \u5E7F\u544A\u4E3B\u7EC4\u5217\u8868\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${groups.length} \u6761\uFF0C\u5171 ${groups.length} \u6761\uFF09
8229
8341
  `);
8230
8342
  const cols = [
8231
8343
  { key: "magKey", header: "magKey\uFF08\u5F00\u6237\u65F6\u4F7F\u7528\uFF09" },
@@ -8447,12 +8559,13 @@ async function uploadAttachment(filePath, apiBaseUrl, config, verbose) {
8447
8559
  const form = new FormData();
8448
8560
  form.append("file", new Blob([fileBuffer], { type: mimeType }), fileName);
8449
8561
  const uploadUrl = `${apiBaseUrl}/command/attachment`;
8562
+ const authHeaders = config.apiKey ? { "x-api-key": config.apiKey } : { Authorization: `Bearer ${config.authToken}` };
8450
8563
  const res = await fetch(uploadUrl, {
8451
8564
  method: "POST",
8452
8565
  headers: {
8453
- Authorization: `Bearer ${config.authToken}`,
8566
+ "Accept-Language": "zh-CN",
8567
+ ...authHeaders,
8454
8568
  Datapermission: config.dataPermission ?? ""
8455
- // 注意:不手动设置 Content-Type,让 fetch 自动添加含 boundary 的值
8456
8569
  },
8457
8570
  body: form
8458
8571
  });
@@ -8682,12 +8795,13 @@ async function runOpenAccountGoogleTimezones(opts) {
8682
8795
  return code.includes(kw) || name.includes(kw) || time.includes(kw) || label.includes(kw);
8683
8796
  });
8684
8797
  }
8798
+ const n = rows.length;
8685
8799
  if (opts.json) {
8686
- console.log(JSON.stringify(rows, null, 2));
8800
+ console.log(JSON.stringify(wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items: rows }), null, 2));
8687
8801
  return;
8688
8802
  }
8689
8803
  console.log(`
8690
- Google \u5F00\u6237\u53EF\u9009\u65F6\u533A\uFF08\u4E0E\u7F51\u9875 /openAnAccount \u4E0B\u62C9\u4E00\u81F4\uFF0C\u5171 ${rows.length} \u6761\uFF09
8804
+ Google \u5F00\u6237\u53EF\u9009\u65F6\u533A\uFF08\u4E0E\u7F51\u9875 /openAnAccount \u4E0B\u62C9\u4E00\u81F4\uFF0C\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${rows.length} \u6761\uFF0C\u5171 ${rows.length} \u6761\uFF09
8691
8805
  `);
8692
8806
  if (rows.length === 0) {
8693
8807
  console.log(" \u65E0\u6570\u636E\u3002\u53EF\u5C1D\u8BD5\u53BB\u6389 --keyword \u6216\u52A0 --verbose\u3002\n");
@@ -9064,12 +9178,13 @@ async function runOpenAccountTikTokTimezones(opts) {
9064
9178
  return code.includes(kw) || name.includes(kw) || time.includes(kw);
9065
9179
  });
9066
9180
  }
9181
+ const n = rows.length;
9067
9182
  if (opts.json) {
9068
- console.log(JSON.stringify(rows, null, 2));
9183
+ console.log(JSON.stringify(wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items: rows }), null, 2));
9069
9184
  return;
9070
9185
  }
9071
9186
  console.log(`
9072
- TikTok \u5F00\u6237\u53EF\u9009\u65F6\u533A\uFF08\u5171 ${rows.length} \u6761\uFF09
9187
+ TikTok \u5F00\u6237\u53EF\u9009\u65F6\u533A\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${rows.length} \u6761\uFF0C\u5171 ${rows.length} \u6761\uFF09
9073
9188
  `);
9074
9189
  if (rows.length === 0) {
9075
9190
  console.log(" \u65E0\u6570\u636E\u3002\n");
@@ -9109,12 +9224,13 @@ async function runOpenAccountTikTokIndustries(opts) {
9109
9224
  if (kw) {
9110
9225
  rows = rows.filter((r) => String(r.IndustryName ?? "").toLowerCase().includes(kw));
9111
9226
  }
9227
+ const n = rows.length;
9112
9228
  if (opts.json) {
9113
- console.log(JSON.stringify(rows, null, 2));
9229
+ console.log(JSON.stringify(wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items: rows }), null, 2));
9114
9230
  return;
9115
9231
  }
9116
9232
  console.log(`
9117
- TikTok \u884C\u4E1A\u5217\u8868\uFF08\u5171 ${rows.length} \u6761\uFF0C--industry-id \u4F20\u53F6\u5B50\u8282\u70B9 ID\uFF09
9233
+ TikTok \u884C\u4E1A\u5217\u8868\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${rows.length} \u6761\uFF0C\u5171 ${rows.length} \u6761\uFF0C--industry-id \u4F20\u53F6\u5B50\u8282\u70B9 ID\uFF09
9118
9234
  `);
9119
9235
  if (rows.length === 0) {
9120
9236
  console.log(" \u65E0\u6570\u636E\u3002\n");
@@ -9153,12 +9269,13 @@ async function runOpenAccountBingIndustries(opts) {
9153
9269
  if (kw) {
9154
9270
  list = list.filter((r) => r.name.toLowerCase().includes(kw));
9155
9271
  }
9272
+ const n = list.length;
9156
9273
  if (opts.json) {
9157
- console.log(JSON.stringify(list, null, 2));
9274
+ console.log(JSON.stringify(wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items: list }), null, 2));
9158
9275
  return;
9159
9276
  }
9160
9277
  console.log(`
9161
- BingV2 \u884C\u4E1A\u5217\u8868\uFF08\u5171 ${list.length} \u6761\uFF0C\u5C06 name \u503C\u4F20\u7ED9 --trade-id\uFF09
9278
+ BingV2 \u884C\u4E1A\u5217\u8868\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${list.length} \u6761\uFF0C\u5171 ${list.length} \u6761\uFF0C\u5C06 name \u503C\u4F20\u7ED9 --trade-id\uFF09
9162
9279
  `);
9163
9280
  if (list.length === 0) {
9164
9281
  console.log(" \u65E0\u6570\u636E\u3002\n");
@@ -9193,12 +9310,13 @@ async function runOpenAccountTikTokAreas(opts) {
9193
9310
  (r) => String(r.Key ?? "").toLowerCase().includes(kw) || String(r.Value ?? "").toLowerCase().includes(kw)
9194
9311
  );
9195
9312
  }
9313
+ const n = rows.length;
9196
9314
  if (opts.json) {
9197
- console.log(JSON.stringify(rows, null, 2));
9315
+ console.log(JSON.stringify(wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items: rows }), null, 2));
9198
9316
  return;
9199
9317
  }
9200
9318
  console.log(`
9201
- TikTok \u6CE8\u518C\u5730\u5217\u8868\uFF08\u5171 ${rows.length} \u6761\uFF0C--registered-area \u4F20 Key \u503C\uFF09
9319
+ TikTok \u6CE8\u518C\u5730\u5217\u8868\uFF08\u7B2C 1 \u9875\uFF0C\u672C\u9875 ${rows.length} \u6761\uFF0C\u5171 ${rows.length} \u6761\uFF0C--registered-area \u4F20 Key \u503C\uFF09
9202
9320
  `);
9203
9321
  if (rows.length === 0) {
9204
9322
  console.log(" \u65E0\u6570\u636E\u3002\n");
@@ -9357,7 +9475,15 @@ program.command("list-accounts").description("\u67E5\u8BE2\u5E7F\u544A\u8D26\u62
9357
9475
  "-s, --status <status>",
9358
9476
  "\u8D26\u6237\u72B6\u6001\uFF1Anormal\uFF08\u6B63\u5E38\uFF09| invalid\uFF08\u5931\u6548\uFF09| all\uFF08\u5168\u90E8\uFF0C\u9ED8\u8BA4\uFF09",
9359
9477
  "all"
9360
- ).option("-p, --page <n>", "\u9875\u7801\uFF08\u9ED8\u8BA4 1\uFF09", parseInt).option("--page-size <n>", "\u6BCF\u9875\u6570\u91CF\uFF08\u9ED8\u8BA4 20\uFF09", parseInt).option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF1B\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option("--json", "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA\u539F\u59CB\u54CD\u5E94", false).option(
9478
+ ).option("-p, --page <n>", "\u9875\u7801\uFF08\u9ED8\u8BA4 1\uFF09", parseInt).option("--page-size <n>", "\u6BCF\u9875\u6570\u91CF\uFF08\u9ED8\u8BA4 20\uFF09", parseInt).option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF1B\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option(
9479
+ "--json",
9480
+ "\u4EE5 JSON \u8F93\u51FA\uFF08\u542B\u5206\u9875\u4FE1\u5C01\u4E0E items\uFF1B\u9ED8\u8BA4\u4ECD\u4F1A\u5408\u5E76\u4F59\u989D/\u6D88\u8017/Arit\uFF0C\u4E0E\u8868\u683C\u4E00\u81F4\u3002\u52A0 --quick \u5219 items \u4EC5\u542B\u5217\u8868\u63A5\u53E3\u5B57\u6BB5\uFF09",
9481
+ false
9482
+ ).option(
9483
+ "--quick",
9484
+ "\u5FEB\u901F\u6A21\u5F0F\uFF1A\u53EA\u8BF7\u6C42\u8D26\u6237\u5217\u8868\u63A5\u53E3\uFF0C\u4E0D\u518D\u5E76\u884C\u62C9\u53D6\u4F59\u989D\uFF08GetMediaAccountInfo\uFF09\u3001\u6295\u653E\u6982\u89C8\uFF08accountsoverview\uFF09\u3001ARIT \u8BCA\u65AD\u5F97\u5206\uFF1B\u8BF7\u6C42\u66F4\u5C11\u3001\u8FD4\u56DE\u66F4\u5FEB\u3002\u8868\u683C\u4E0E JSON \u4E2D\u4F59\u989D\u3001\u6D88\u8017\u3001\u5C55\u793A/\u70B9\u51FB/\u8F6C\u5316/CPC\u3001Arit \u7B49\u5C06\u4E3A\u7A7A\u6216\u300C-\u300D\u3002TikTok/Meta \u5217\u8868\u54CD\u5E94\u5185\u7684 adList \u4ECD\u4F1A\u6309\u7F51\u9875\u903B\u8F91\u5408\u5E76\u5230\u540C\u6761\u8BB0\u5F55\u3002",
9485
+ false
9486
+ ).option(
9361
9487
  "--unicode",
9362
9488
  "\u4F7F\u7528 Unicode \u7EBF\u6846\u8868\u683C\uFF08cli-table3\uFF09\uFF1B\u9ED8\u8BA4 ASCII +-|",
9363
9489
  false
@@ -9374,6 +9500,7 @@ program.command("list-accounts").description("\u67E5\u8BE2\u5E7F\u544A\u8D26\u62
9374
9500
  page: opts.page,
9375
9501
  pageSize: opts.pageSize,
9376
9502
  json: opts.json,
9503
+ quick: opts.quick,
9377
9504
  unicode: opts.unicode,
9378
9505
  verbose: opts.verbose
9379
9506
  });
@@ -73,6 +73,7 @@ description: >-
73
73
  | TSO 首页(网页) | `config show` 取 `webUrl` → `{webUrl}/v3/foreign_trade/tso/home` |
74
74
  | 查广告主组(TikTok 等取 magKey) | `siluzan-tso open-account list-groups` |
75
75
  | Google 开户(脚本) | `siluzan-tso open-account google --company "…" --promotion-link "…" --promotion-type b2c ...`(**无需 magKey**) |
76
+
76
77
  | Google 开户时区列表 | `siluzan-tso open-account google-timezones`(可加 `--keyword`) |
77
78
  | TikTok 开户时区列表 | `siluzan-tso open-account tiktok-timezones`(可加 `--keyword`) |
78
79
  | TikTok 行业列表 | `siluzan-tso open-account tiktok-industries`(两级结构,传叶子节点 ID) |
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "siluzan-tso",
3
- "version": "1.0.0-beta.30",
4
- "publishedAt": 1774507264267
3
+ "version": "1.0.0-beta.32",
4
+ "publishedAt": 1774516818975
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "siluzan-tso-cli",
3
- "version": "1.0.0-beta.30",
3
+ "version": "1.0.0-beta.32",
4
4
  "description": "Siluzan 广告账户管理 CLI — 查询账户、余额、消耗数据,管理绑定关系与充值。",
5
5
  "type": "module",
6
6
  "bin": {