siluzan-tso-cli 1.1.18 → 1.1.19-beta.2

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 (98) hide show
  1. package/README.md +8 -7
  2. package/assets/siluzan-ads/references/hosted-automation-user-catalog.md +17 -19
  3. package/dist/index.js +1112 -874
  4. package/dist/skill/SKILL.md +66 -38
  5. package/dist/skill/_meta.json +2 -2
  6. package/dist/skill/references/account-analytics.md +95 -88
  7. package/dist/skill/references/accounts.md +10 -9
  8. package/dist/skill/references/finance.md +5 -5
  9. package/dist/skill/references/google-ads-rules/google-ads-account-audit.md +1 -0
  10. package/dist/skill/references/google-ads-rules/google-ads-keyword-optimization.md +1 -1
  11. package/dist/skill/references/google-ads-rules/google-ads-landing-page-discovery-via-webfetch.md +72 -0
  12. package/dist/skill/references/google-ads-rules/google-ads-launch-plan-template.md +25 -16
  13. package/dist/skill/references/google-ads.md +236 -1025
  14. package/dist/skill/references/google-analysis-batch.md +53 -46
  15. package/dist/skill/references/hosted-automation-monitoring-json.md +10 -10
  16. package/dist/skill/references/hosted-automation-optimize-ab-winner.md +3 -3
  17. package/dist/skill/references/hosted-automation-optimize-index.md +5 -5
  18. package/dist/skill/references/hosted-automation-optimize-scale.md +2 -2
  19. package/dist/skill/references/hosted-automation-optimize-weak-downbid.md +5 -5
  20. package/dist/skill/references/hosted-automation-scenarios.md +5 -5
  21. package/dist/skill/references/hosted-automation-self-control.md +24 -23
  22. package/dist/skill/references/hosted-automation-user-catalog.md +17 -19
  23. package/dist/skill/references/keyword-planner-workflows.md +104 -0
  24. package/dist/skill/references/open-account-google-ui.md +0 -1
  25. package/dist/skill/references/reporting.md +2 -2
  26. package/dist/skill/references/setup.md +21 -22
  27. package/dist/skill/references/tips.md +2 -1
  28. package/dist/skill/references/tso-home.md +1 -1
  29. package/dist/skill/references/workflows.md +10 -4
  30. package/dist/skill/references/write-audit-restore.md +39 -6
  31. package/dist/skill/report-templates/README.md +1 -0
  32. package/dist/skill/report-templates/REPORT-WORKFLOW.md +4 -0
  33. package/dist/skill/report-templates/google-period-report.md +16 -16
  34. package/dist/skill/report-templates/okki-weekly-google-client.md +105 -0
  35. package/dist/skill/scripts/install.ps1 +2 -2
  36. package/dist/skill/scripts/install.sh +2 -2
  37. package/eval/cases/accounts-entityid-vs-mediaccustomerid.scenario.json +2 -14
  38. package/eval/cases/accounts-mcc-bind-inquiry.scenario.json +1 -3
  39. package/eval/cases/accounts-single-balance-not-bulk.scenario.json +3 -14
  40. package/eval/cases/budget-display-not-raw-micros.scenario.json +1 -8
  41. package/eval/cases/clue-meta-leads-json.scenario.json +2 -14
  42. package/eval/cases/clue-tiktok-leads-json.scenario.json +2 -11
  43. package/eval/cases/destructive-account-delink-needs-confirm.scenario.json +3 -9
  44. package/eval/cases/destructive-forewarning-delete-needs-confirm.scenario.json +3 -9
  45. package/eval/cases/destructive-invoice-apply-needs-confirm.scenario.json +3 -9
  46. package/eval/cases/finance-invoice-info-list.scenario.json +3 -11
  47. package/eval/cases/forewarning-list-google.scenario.json +3 -14
  48. package/eval/cases/google-ads-no-structural-without-confirm.scenario.json +2 -6
  49. package/eval/cases/google-analysis-keywords-route.scenario.json +2 -14
  50. package/eval/cases/human-p1-multiturn.scenario.json +1 -5
  51. package/eval/cases/meta-single-balance-not-bulk.scenario.json +3 -17
  52. package/eval/cases/open-account-bing-noninteractive.scenario.json +1 -4
  53. package/eval/cases/open-account-google-noninteractive.scenario.json +1 -3
  54. package/eval/cases/open-account-tiktok-license-file.scenario.json +1 -3
  55. package/eval/cases/optimize-list-by-account.scenario.json +3 -11
  56. package/eval/cases/p1-single-account-profile.scenario.json +1 -11
  57. package/eval/cases/p2-balance-scan-bulk.scenario.json +2 -9
  58. package/eval/cases/p3-accounts-digest.scenario.json +1 -5
  59. package/eval/cases/p4-period-report-window.scenario.json +1 -8
  60. package/eval/cases/report-list-google.scenario.json +2 -11
  61. package/eval/cases/report-push-list-google.scenario.json +2 -11
  62. package/eval/cases/reporting-vs-account-analytics-routing.scenario.json +1 -4
  63. package/eval/cases/setup-login-or-env.scenario.json +1 -3
  64. package/eval/cases/setup-siluzan-data-permission-env.scenario.json +1 -3
  65. package/eval/cases/skill-optimize-vs-google-ads-distinction.scenario.json +1 -4
  66. package/eval/cases/tiktok-bc-bind-inquiry.scenario.json +2 -6
  67. package/eval/cases/time-range-user-delegates-default.scenario.json +1 -8
  68. package/eval/cases/tips-json-filtering.scenario.json +1 -3
  69. package/eval/cases/tips-large-json-pagination.scenario.json +1 -3
  70. package/eval/cases/uj-ad-outdoor-campgear-search-plan.scenario.json +1 -3
  71. package/eval/cases/uj-analytics-30d-pdf-campaign-device-geo.scenario.json +6 -18
  72. package/eval/cases/uj-analytics-compare-google-tiktok-last-month-roi.scenario.json +1 -8
  73. package/eval/cases/uj-analytics-google-weekly-trends-campaigns-keywords.scenario.json +2 -11
  74. package/eval/cases/uj-analytics-report-push-weekly-email.scenario.json +1 -3
  75. package/eval/cases/uj-finance-invoice-records-this-month.scenario.json +2 -11
  76. package/eval/cases/uj-life-newbie-siluzan-google-end-to-end.scenario.json +1 -4
  77. package/eval/cases/uj-ops-google-accounts-list-normal.scenario.json +2 -14
  78. package/eval/cases/uj-ops-google-yesterday-spend-conversions.scenario.json +2 -14
  79. package/eval/cases/uj-ops-open-google-b2c-usd-shenzhen.scenario.json +1 -4
  80. package/eval/cases/uj-ops-pause-worst-adgroup-confirm.scenario.json +2 -6
  81. package/eval/cases/uj-ops-tiktok-leads-last-week.scenario.json +3 -17
  82. package/eval/cases/uj-patrol-cpc-spike-adgroups-over-15.scenario.json +2 -9
  83. package/eval/cases/uj-patrol-forewarning-create-daily-cap-3000.scenario.json +1 -3
  84. package/eval/cases/uj-patrol-forewarning-trigger-records.scenario.json +3 -17
  85. package/eval/cases/uj-patrol-google-balances-low.scenario.json +2 -11
  86. package/eval/cases/uj-roi-optimize-records-then-execute-cautiously.scenario.json +3 -14
  87. package/eval/cases/uj-roi-search-terms-add-negative-keywords.scenario.json +2 -14
  88. package/eval/stub-fixtures/balance-meta.json +3 -1
  89. package/eval/stub-fixtures/clue-meta.json +6 -1
  90. package/eval/stub-fixtures/clue-tiktok.json +3 -1
  91. package/eval/stub-fixtures/forewarning-create-ok.json +5 -1
  92. package/eval/stub-fixtures/forewarning-records.json +3 -1
  93. package/eval/stub-fixtures/google-analysis.json +81 -21
  94. package/eval/stub-fixtures/invoice-billable.json +3 -1
  95. package/eval/stub-fixtures/invoice-list.json +14 -2
  96. package/eval/stub-fixtures/report-push-list.json +3 -1
  97. package/package.json +2 -2
  98. package/scripts/postinstall.mjs +1 -2
package/dist/index.js CHANGED
@@ -2231,11 +2231,7 @@ function rawRequest(url, options) {
2231
2231
  error: "timeout"
2232
2232
  });
2233
2233
  }
2234
- reject(
2235
- new Error(
2236
- `\u8BF7\u6C42\u8D85\u65F6\uFF08${(timeoutMs / 1e3).toFixed(0)} \u79D2\uFF09\uFF1A${method} ${url}`
2237
- )
2238
- );
2234
+ reject(new Error(`\u8BF7\u6C42\u8D85\u65F6\uFF08${(timeoutMs / 1e3).toFixed(0)} \u79D2\uFF09\uFF1A${method} ${url}`));
2239
2235
  });
2240
2236
  req.on("error", (err) => {
2241
2237
  if (perfOn) {
@@ -3296,7 +3292,7 @@ var DEFAULT_API_BASE;
3296
3292
  var init_defaults = __esm({
3297
3293
  "src/config/defaults.ts"() {
3298
3294
  "use strict";
3299
- DEFAULT_API_BASE = "https://tso-api.siluzan.com";
3295
+ DEFAULT_API_BASE = "https://tso-api-ci.siluzan.com";
3300
3296
  }
3301
3297
  });
3302
3298
 
@@ -3531,9 +3527,7 @@ function ensureWriteCommitForMutatingHttp() {
3531
3527
  if (isTsoArgvExemptFromWriteCommit(process.argv.slice(2))) return;
3532
3528
  const c = getResolvedWriteAuditCommit();
3533
3529
  if (c !== "") return;
3534
- console.error(
3535
- '\n\u274C \u5199\u64CD\u4F5C\u5FC5\u987B\u63D0\u4F9B\u8BF4\u660E\uFF08commit\uFF09\uFF1A\u8BF7\u4F7F\u7528 --commit "\u2026"'
3536
- );
3530
+ console.error('\n\u274C \u5199\u64CD\u4F5C\u5FC5\u987B\u63D0\u4F9B\u8BF4\u660E\uFF08commit\uFF09\uFF1A\u8BF7\u4F7F\u7528 --commit "\u2026"');
3537
3531
  process.exit(1);
3538
3532
  }
3539
3533
  async function withWriteAudit(params, execute) {
@@ -4076,7 +4070,9 @@ function parseGoogleAccountSpendOverviewRows(raw) {
4076
4070
  if (r.mode === "googleCombined") {
4077
4071
  const accounts = r.accounts ?? {};
4078
4072
  const rows = [];
4079
- for (const [id, item] of Object.entries(accounts)) {
4073
+ for (const [id, item] of Object.entries(
4074
+ accounts
4075
+ )) {
4080
4076
  const data = item?.data;
4081
4077
  if (!data) continue;
4082
4078
  rows.push({
@@ -4155,7 +4151,7 @@ var init_balance = __esm({
4155
4151
  }
4156
4152
  });
4157
4153
 
4158
- // src/commands/accounts-digest.ts
4154
+ // src/commands/accounts-digest/list-fetch.ts
4159
4155
  async function fetchAccountsByMedia(media, config, opts) {
4160
4156
  const cfg = DIGEST_PLATFORM_CONFIG[media];
4161
4157
  if (!cfg) throw new Error(`accounts-digest \u6682\u4E0D\u652F\u6301\u5A92\u4F53\uFF1A${media}`);
@@ -4192,6 +4188,63 @@ async function fetchAccountsByMedia(media, config, opts) {
4192
4188
  if (!opts.silent) process.stderr.write("\n");
4193
4189
  return { items: all, total };
4194
4190
  }
4191
+ var DIGEST_PLATFORM_CONFIG;
4192
+ var init_list_fetch = __esm({
4193
+ "src/commands/accounts-digest/list-fetch.ts"() {
4194
+ "use strict";
4195
+ init_auth();
4196
+ DIGEST_PLATFORM_CONFIG = {
4197
+ Google: {
4198
+ path: "/query/media-account/",
4199
+ pageParam: "pageNo",
4200
+ fixedParams: { MediaType: "Google", mediaAccountState: "Approved,Linked" },
4201
+ responseType: "array"
4202
+ },
4203
+ Yandex: {
4204
+ path: "/query/media-account/",
4205
+ pageParam: "pageNo",
4206
+ fixedParams: { MediaType: "Yandex", mediaAccountState: "Approved,Linked" },
4207
+ responseType: "array"
4208
+ },
4209
+ TikTok: {
4210
+ path: "/query/media-account/tiktok/SearchMediaAcountByCriteria",
4211
+ pageParam: "pageNum",
4212
+ fixedParams: {
4213
+ MediaType: "TikTok",
4214
+ advStatus: "STATUS_ENABLE,STATUS_LIMIT,STATUS_DISABLE",
4215
+ mediaAccountState: "Approved,Linked",
4216
+ isForce: false
4217
+ },
4218
+ responseType: "mas"
4219
+ },
4220
+ BingV2: {
4221
+ path: "/query/media-account/BingV2/SearchBingV2MediaAcountByUserId",
4222
+ pageParam: "pageNum",
4223
+ fixedParams: {
4224
+ MediaType: "BingV2",
4225
+ advStatus: "APPROVED",
4226
+ mediaAccountState: "Approved,Linked",
4227
+ isForce: false
4228
+ },
4229
+ responseType: "mas"
4230
+ },
4231
+ Kwai: {
4232
+ path: "/query/media-account/SearchMediaAcountByCriteria",
4233
+ pageParam: "pageNum",
4234
+ fixedParams: {
4235
+ MediaTypes: "Kwai",
4236
+ MediaType: "Kwai",
4237
+ advStatus: "",
4238
+ mediaAccountState: "Approved,Linked",
4239
+ isForce: false
4240
+ },
4241
+ responseType: "mas"
4242
+ }
4243
+ };
4244
+ }
4245
+ });
4246
+
4247
+ // src/commands/accounts-digest/run.ts
4195
4248
  function round2(n) {
4196
4249
  if (n == null) return null;
4197
4250
  const v = Number(n);
@@ -4239,11 +4292,9 @@ async function runAccountsDigest(opts) {
4239
4292
  accountsList = res.items;
4240
4293
  scannedFromList = true;
4241
4294
  } catch (err) {
4242
- console.error(
4243
- `
4295
+ console.error(`
4244
4296
  \u274C \u62C9\u53D6\u8D26\u6237\u6E05\u5355\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
4245
- `
4246
- );
4297
+ `);
4247
4298
  process.exit(1);
4248
4299
  }
4249
4300
  }
@@ -4396,13 +4447,32 @@ ${media} \u8D26\u6237\u6295\u653E\u753B\u50CF\uFF1A\u8FD4\u56DE ${rows.length} \
4396
4447
  `
4397
4448
  );
4398
4449
  }
4450
+ var init_run = __esm({
4451
+ "src/commands/accounts-digest/run.ts"() {
4452
+ "use strict";
4453
+ init_auth();
4454
+ init_cli_json_snapshot();
4455
+ init_balance();
4456
+ init_cli_table();
4457
+ init_list_fetch();
4458
+ }
4459
+ });
4460
+
4461
+ // src/commands/accounts-digest/_register.ts
4399
4462
  function register10(program2) {
4400
4463
  program2.command("accounts-digest").description(
4401
4464
  "\u591A\u8D26\u6237\u6295\u653E\u753B\u50CF\uFF1A\u4E00\u6761\u547D\u4EE4\u62FF\u9F50\u6D88\u8017/\u70B9\u51FB/\u8F6C\u5316/\u4F59\u989D/\u6D3E\u751F\u6307\u6807\uFF08CTR/CPC/CPA\uFF09\uFF0C\u66FF\u4EE3 AI \u9010\u8D26\u6237 `list-accounts` + `stats` \u7684\u7F16\u6392\u3002\u5178\u578B\u573A\u666F\uFF1A\u300C\u8FD9 10 \u4E2A\u8D26\u6237\uFF08\u6216\u67D0\u5A92\u4F53\u5168\u90E8\u8D26\u6237\uFF09\u5E2E\u6211\u6574\u7406\u4E00\u4E0B\u300D\u3002"
4402
4465
  ).requiredOption(
4403
4466
  "-m, --media <type>",
4404
4467
  "\u5A92\u4F53\u7C7B\u578B\uFF1AGoogle | TikTok | Yandex | BingV2 | Kwai\uFF08MetaAd \u65E0\u6D88\u8017\u6C47\u603B\u63A5\u53E3\uFF09"
4405
- ).option("-a, --accounts <ids>", "\u6307\u5B9A\u8D26\u6237 mediaCustomerId\uFF0C\u9017\u53F7\u5206\u9694\uFF1B\u7559\u7A7A\u5219\u626B\u63CF\u8BE5\u5A92\u4F53\u4E0B\u5168\u90E8\u8D26\u6237").option("--start <date>", "\u7EDF\u8BA1\u5F00\u59CB\u65E5\u671F YYYY-MM-DD\uFF08SKILL \u8981\u6C42 AI \u5148\u4E0E\u7528\u6237\u786E\u8BA4\uFF09").option("--end <date>", "\u7EDF\u8BA1\u7ED3\u675F\u65E5\u671F YYYY-MM-DD\uFF08SKILL \u8981\u6C42 AI \u5148\u4E0E\u7528\u6237\u786E\u8BA4\uFF09").option("--min-spend <n>", "\u8FC7\u6EE4\uFF1A\u533A\u95F4\u5185\u6D88\u8017 \u2264 \u6B64\u503C\u7684\u8D26\u6237\u4E0D\u8FD4\u56DE\uFF08\u9ED8\u8BA4 0\uFF09", (v) => parseFloat(v)).option("--page-size <n>", "\u8D26\u6237\u6E05\u5355\u5206\u9875\u5927\u5C0F\uFF08\u9ED8\u8BA4 200\uFF0C\u4E0A\u9650 500\uFF09", (v) => parseInt(v, 10)).option("--max-pages <n>", "\u6700\u591A\u626B\u63CF\u9875\u6570\uFF08\u9ED8\u8BA4 20\uFF0C\u4E0A\u9650 200\uFF09", (v) => parseInt(v, 10)).option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF1B\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option("--json", "\u8F93\u51FA\u7ED3\u6784\u5316 JSON\uFF0C\u542B data.items \u4E0E meta\uFF08\u533A\u95F4/\u6C47\u603B/\u5E01\u79CD\u5907\u6CE8\uFF09", false).option(
4468
+ ).option(
4469
+ "-a, --accounts <ids>",
4470
+ "\u6307\u5B9A\u8D26\u6237 mediaCustomerId\uFF0C\u9017\u53F7\u5206\u9694\uFF1B\u7559\u7A7A\u5219\u626B\u63CF\u8BE5\u5A92\u4F53\u4E0B\u5168\u90E8\u8D26\u6237"
4471
+ ).option("--start <date>", "\u7EDF\u8BA1\u5F00\u59CB\u65E5\u671F YYYY-MM-DD\uFF08SKILL \u8981\u6C42 AI \u5148\u4E0E\u7528\u6237\u786E\u8BA4\uFF09").option("--end <date>", "\u7EDF\u8BA1\u7ED3\u675F\u65E5\u671F YYYY-MM-DD\uFF08SKILL \u8981\u6C42 AI \u5148\u4E0E\u7528\u6237\u786E\u8BA4\uFF09").option(
4472
+ "--min-spend <n>",
4473
+ "\u8FC7\u6EE4\uFF1A\u533A\u95F4\u5185\u6D88\u8017 \u2264 \u6B64\u503C\u7684\u8D26\u6237\u4E0D\u8FD4\u56DE\uFF08\u9ED8\u8BA4 0\uFF09",
4474
+ (v) => parseFloat(v)
4475
+ ).option("--page-size <n>", "\u8D26\u6237\u6E05\u5355\u5206\u9875\u5927\u5C0F\uFF08\u9ED8\u8BA4 200\uFF0C\u4E0A\u9650 500\uFF09", (v) => parseInt(v, 10)).option("--max-pages <n>", "\u6700\u591A\u626B\u63CF\u9875\u6570\uFF08\u9ED8\u8BA4 20\uFF0C\u4E0A\u9650 200\uFF09", (v) => parseInt(v, 10)).option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF1B\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option("--json", "\u8F93\u51FA\u7ED3\u6784\u5316 JSON\uFF0C\u542B data.items \u4E0E meta\uFF08\u533A\u95F4/\u6C47\u603B/\u5E01\u79CD\u5907\u6CE8\uFF09", false).option(
4406
4476
  "--json-out <path>",
4407
4477
  "\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF08\u4E0E --json \u4E92\u65A5\uFF09\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
4408
4478
  void 0
@@ -4425,62 +4495,28 @@ function register10(program2) {
4425
4495
  }
4426
4496
  );
4427
4497
  }
4428
- var DIGEST_PLATFORM_CONFIG;
4498
+ var init_register = __esm({
4499
+ "src/commands/accounts-digest/_register.ts"() {
4500
+ "use strict";
4501
+ init_run();
4502
+ }
4503
+ });
4504
+
4505
+ // src/commands/accounts-digest/index.ts
4429
4506
  var init_accounts_digest = __esm({
4507
+ "src/commands/accounts-digest/index.ts"() {
4508
+ "use strict";
4509
+ init_run();
4510
+ init_list_fetch();
4511
+ init_register();
4512
+ }
4513
+ });
4514
+
4515
+ // src/commands/accounts-digest.ts
4516
+ var init_accounts_digest2 = __esm({
4430
4517
  "src/commands/accounts-digest.ts"() {
4431
4518
  "use strict";
4432
- init_auth();
4433
- init_cli_json_snapshot();
4434
- init_balance();
4435
- init_cli_table();
4436
- DIGEST_PLATFORM_CONFIG = {
4437
- Google: {
4438
- path: "/query/media-account/",
4439
- pageParam: "pageNo",
4440
- fixedParams: { MediaType: "Google", mediaAccountState: "Approved,Linked" },
4441
- responseType: "array"
4442
- },
4443
- Yandex: {
4444
- path: "/query/media-account/",
4445
- pageParam: "pageNo",
4446
- fixedParams: { MediaType: "Yandex", mediaAccountState: "Approved,Linked" },
4447
- responseType: "array"
4448
- },
4449
- TikTok: {
4450
- path: "/query/media-account/tiktok/SearchMediaAcountByCriteria",
4451
- pageParam: "pageNum",
4452
- fixedParams: {
4453
- MediaType: "TikTok",
4454
- advStatus: "STATUS_ENABLE,STATUS_LIMIT,STATUS_DISABLE",
4455
- mediaAccountState: "Approved,Linked",
4456
- isForce: false
4457
- },
4458
- responseType: "mas"
4459
- },
4460
- BingV2: {
4461
- path: "/query/media-account/BingV2/SearchBingV2MediaAcountByUserId",
4462
- pageParam: "pageNum",
4463
- fixedParams: {
4464
- MediaType: "BingV2",
4465
- advStatus: "APPROVED",
4466
- mediaAccountState: "Approved,Linked",
4467
- isForce: false
4468
- },
4469
- responseType: "mas"
4470
- },
4471
- Kwai: {
4472
- path: "/query/media-account/SearchMediaAcountByCriteria",
4473
- pageParam: "pageNum",
4474
- fixedParams: {
4475
- MediaTypes: "Kwai",
4476
- MediaType: "Kwai",
4477
- advStatus: "",
4478
- mediaAccountState: "Approved,Linked",
4479
- isForce: false
4480
- },
4481
- responseType: "mas"
4482
- }
4483
- };
4519
+ init_accounts_digest();
4484
4520
  }
4485
4521
  });
4486
4522
 
@@ -4641,125 +4677,451 @@ var init_strip_legacy_google_fields = __esm({
4641
4677
  }
4642
4678
  });
4643
4679
 
4644
- // src/utils/google-analysis-snapshot.ts
4645
- var init_google_analysis_snapshot = __esm({
4646
- "src/utils/google-analysis-snapshot.ts"() {
4680
+ // src/commands/google-analysis/sections.ts
4681
+ var SECTIONS;
4682
+ var init_sections = __esm({
4683
+ "src/commands/google-analysis/sections.ts"() {
4647
4684
  "use strict";
4648
- init_google_analysis();
4649
- }
4650
- });
4651
-
4652
- // src/utils/http-retry.ts
4653
- function classifyError(err) {
4654
- const status = parseHttpStatusFromError(err);
4655
- if (status === 401) return { class: "abort", status };
4656
- if (status === void 0) {
4657
- return { class: "retryable" };
4658
- }
4659
- if (status === 408 || status === 429) return { class: "retryable", status };
4660
- if (status >= 500 && status <= 599) return { class: "retryable", status };
4661
- if (status >= 400 && status <= 499) return { class: "permanent", status };
4662
- return { class: "permanent", status };
4663
- }
4664
- function computeBackoffMs(attempt, policy) {
4665
- const exp = policy.baseMs * 2 ** Math.max(0, attempt - 1);
4666
- const capped = Math.min(exp, policy.maxBackoffMs);
4667
- const jitter = Math.floor(Math.random() * policy.baseMs);
4668
- return capped + jitter;
4669
- }
4670
- function sleep2(ms, signal) {
4671
- return new Promise((resolve8, reject) => {
4672
- if (signal?.aborted) {
4673
- reject(new Error("retry sleep aborted"));
4674
- return;
4675
- }
4676
- const timer = setTimeout(() => {
4677
- signal?.removeEventListener("abort", onAbort);
4678
- resolve8();
4679
- }, ms);
4680
- const onAbort = () => {
4681
- clearTimeout(timer);
4682
- reject(new Error("retry sleep aborted"));
4683
- };
4684
- signal?.addEventListener("abort", onAbort, { once: true });
4685
- });
4686
- }
4687
- async function withTaskTimeout(factory, timeoutMs, label) {
4688
- if (!timeoutMs || timeoutMs <= 0) return factory();
4689
- let timer;
4690
- try {
4691
- return await Promise.race([
4692
- factory(),
4693
- new Promise((_, reject) => {
4694
- timer = setTimeout(() => {
4695
- reject(
4696
- new Error(
4697
- `\u8BF7\u6C42\u8D85\u65F6\uFF08${(timeoutMs / 1e3).toFixed(0)} \u79D2\uFF09\uFF1A${label}`
4698
- )
4699
- );
4700
- }, timeoutMs);
4701
- })
4702
- ]);
4703
- } finally {
4704
- if (timer) clearTimeout(timer);
4705
- }
4706
- }
4707
- async function fetchWithRetry(factory, options) {
4708
- const policy = { ...DEFAULT_RETRY_POLICY, ...options.policy ?? {} };
4709
- let lastErr;
4710
- let lastStatus;
4711
- for (let attempt = 1; attempt <= policy.maxAttempts; attempt++) {
4712
- if (options.signal?.aborted) {
4713
- throw new AbortRunError({
4714
- message: `\u4EFB\u52A1\u88AB\u5916\u90E8\u4FE1\u53F7\u4E2D\u6B62\uFF1A${options.label}`
4715
- });
4716
- }
4717
- try {
4718
- return await withTaskTimeout(factory, policy.taskTimeoutMs, options.label);
4719
- } catch (raw) {
4720
- const err = raw instanceof Error ? raw : new Error(String(raw));
4721
- const cls = classifyError(err);
4722
- lastErr = err;
4723
- lastStatus = cls.status;
4724
- if (cls.class === "abort") {
4725
- throw new AbortRunError({
4726
- message: `Token \u5931\u6548\u6216\u81F4\u547D\u9519\u8BEF\uFF08${options.label}\uFF09\uFF1A${err.message}`,
4727
- status: cls.status,
4728
- cause: err
4729
- });
4730
- }
4731
- if (cls.class === "permanent" || attempt >= policy.maxAttempts) {
4732
- throw new HttpRetryError({
4733
- message: cls.class === "permanent" ? `\u6C38\u4E45\u5931\u8D25\uFF08${options.label}\uFF09\uFF1A${err.message}` : `\u91CD\u8BD5 ${attempt} \u6B21\u4ECD\u5931\u8D25\uFF08${options.label}\uFF09\uFF1A${err.message}`,
4734
- class: cls.class === "permanent" ? "permanent" : "retryable",
4735
- status: cls.status,
4736
- attempts: attempt,
4737
- cause: err
4738
- });
4739
- }
4740
- const backoffMs = computeBackoffMs(attempt, policy);
4741
- options.onRetry?.({ attempt, backoffMs, status: cls.status, error: err });
4742
- try {
4743
- await sleep2(backoffMs, options.signal);
4744
- } catch {
4745
- throw new AbortRunError({
4746
- message: `\u91CD\u8BD5\u7B49\u5F85\u88AB\u4E2D\u6B62\uFF1A${options.label}`,
4747
- cause: err
4748
- });
4749
- }
4750
- }
4751
- }
4752
- throw new HttpRetryError({
4753
- message: `\u672A\u77E5\u91CD\u8BD5\u5931\u8D25\uFF08${options.label}\uFF09\uFF1A${lastErr?.message ?? "no error"}`,
4754
- class: "retryable",
4755
- status: lastStatus,
4756
- attempts: policy.maxAttempts,
4757
- cause: lastErr
4758
- });
4759
- }
4760
- var HttpRetryError, AbortRunError, DEFAULT_RETRY_POLICY;
4761
- var init_http_retry = __esm({
4762
- "src/utils/http-retry.ts"() {
4685
+ SECTIONS = [
4686
+ {
4687
+ name: "overview",
4688
+ description: "\u8D26\u6237\u603B\u89C8 OverviewSectionData\uFF08\u5B9E\u65F6\uFF0C\u53EF\u67E5\u5F53\u5929\uFF09",
4689
+ dateMode: "range",
4690
+ path: (id) => `/reporting/media-account/${id}/OverviewSectionData`
4691
+ },
4692
+ {
4693
+ name: "keywords",
4694
+ description: "\u5173\u952E\u8BCD\u5206\u6BB5 KeywordSectionData",
4695
+ dateMode: "range",
4696
+ path: (id) => `/reporting/media-account/${id}/KeywordSectionData`,
4697
+ defaultQuery: { limit: 100, orderByCost: true },
4698
+ keywordOptions: true
4699
+ },
4700
+ {
4701
+ name: "search-terms",
4702
+ description: "\u641C\u7D22\u8BCD searchtermmanagement/v2/list",
4703
+ dateMode: "range",
4704
+ path: (id) => `/searchtermmanagement/v2/list/${id}`,
4705
+ defaultQuery: { limit: 100, orderByCost: true },
4706
+ keywordOptions: true
4707
+ },
4708
+ {
4709
+ name: "campaigns",
4710
+ description: "\u5E7F\u544A\u7CFB\u5217\u5206\u6BB5 CampaignSectionData",
4711
+ dateMode: "range",
4712
+ path: (id) => `/reporting/media-account/${id}/CampaignSectionData`
4713
+ },
4714
+ {
4715
+ name: "campaign-hour",
4716
+ description: "\u7CFB\u5217\u6309\u5C0F\u65F6 campaign-hour\uFF08Query\uFF1AstartDate\u3001endDate\uFF09",
4717
+ dateMode: "range",
4718
+ path: (id) => `/reporting/media-account/${id}/campaign-hour`
4719
+ },
4720
+ {
4721
+ name: "ads",
4722
+ description: "\u5E7F\u544A\u7EA7\u5217\u8868 admanagement/v2/list",
4723
+ dateMode: "range",
4724
+ path: (id) => `/admanagement/v2/list/${id}`
4725
+ },
4726
+ {
4727
+ name: "extensions",
4728
+ description: "\u9644\u52A0\u4FE1\u606F extensionmanagement/v2/list",
4729
+ dateMode: "range",
4730
+ path: (id) => `/extensionmanagement/v2/list/${id}`,
4731
+ extensionLevelOption: true
4732
+ },
4733
+ {
4734
+ name: "devices",
4735
+ description: "\u8BBE\u5907\u5206\u6BB5 DeviceSectionData",
4736
+ dateMode: "range",
4737
+ path: (id) => `/reporting/media-account/${id}/DeviceSectionData`
4738
+ },
4739
+ {
4740
+ name: "geographic",
4741
+ description: "\u56FD\u5BB6/\u5730\u533A\u5206\u6BB5 GeographicSectionData",
4742
+ dateMode: "range",
4743
+ path: (id) => `/reporting/media-account/${id}/GeographicSectionData`
4744
+ },
4745
+ {
4746
+ name: "audience",
4747
+ description: "\u53D7\u4F17\u5206\u6BB5 AdGroupAudienceData",
4748
+ dateMode: "range",
4749
+ path: (id) => `/reporting/media-account/${id}/AdGroupAudienceData`,
4750
+ audienceFilterOption: true
4751
+ },
4752
+ {
4753
+ name: "asset-images",
4754
+ description: "\u56FE\u7247\u7D20\u6750 CampaignAssetView",
4755
+ dateMode: "range",
4756
+ path: (id) => `/reporting/media-account/${id}/CampaignAssetView`
4757
+ },
4758
+ {
4759
+ name: "videos",
4760
+ description: "\u89C6\u9891\u7D20\u6750 Videos",
4761
+ dateMode: "range",
4762
+ path: (id) => `/reporting/media-account/${id}/Videos`
4763
+ },
4764
+ {
4765
+ name: "materials",
4766
+ description: "\u7D20\u6750\u5408\u5E76\uFF08CampaignAssetView + Videos\uFF09",
4767
+ dateMode: "range",
4768
+ path: (id) => `/reporting/media-account/${id}/CampaignAssetView`
4769
+ },
4770
+ {
4771
+ name: "resource-counts",
4772
+ description: "\u8D26\u6237\u7ED3\u6784 resource-counts",
4773
+ dateMode: "range",
4774
+ path: (id) => `/campaignmanagement/${id}/resource-counts`
4775
+ },
4776
+ {
4777
+ name: "conversion-actions",
4778
+ description: "\u8F6C\u5316\u52A8\u4F5C conversion-actions",
4779
+ dateMode: "range",
4780
+ path: (id) => `/reporting/media-account/${id}/conversion-actions`
4781
+ },
4782
+ {
4783
+ name: "daily-metrics",
4784
+ description: "\u6309\u65E5\u6307\u6807\uFF08\u4E3B\u5E73\u53F0 /report/media-account/google/account-daily-reports\uFF0C\u542B\u641C\u7D22\u4EFD\u989D\u7B49\uFF09",
4785
+ dateMode: "range",
4786
+ /** 仅用于 manifest endpointHint;实际请求走 fetchSectionPayload 专用分支(apiBaseUrl + 东八区起止时刻) */
4787
+ path: () => "/report/media-account/google/account-daily-reports"
4788
+ },
4789
+ {
4790
+ name: "gold-account",
4791
+ description: "\u9EC4\u91D1\u8D26\u6237\u8BCA\u65AD GoldAccountData",
4792
+ dateMode: "range",
4793
+ path: (id) => `/reporting/media-account/${id}/GoldAccountData`
4794
+ },
4795
+ {
4796
+ name: "ads-index",
4797
+ description: "\u5E7F\u544A\u8D28\u91CF\u6307\u6807 AdsIndexData",
4798
+ dateMode: "range",
4799
+ path: (id) => `/reporting/media-account/${id}/AdsIndexData`
4800
+ },
4801
+ {
4802
+ name: "final-urls",
4803
+ description: "\u6700\u7EC8\u5230\u8FBE\u7F51\u5740 ads/final-urls\uFF08\u65E0\u65E5\u671F\u53C2\u6570\uFF09",
4804
+ dateMode: "none",
4805
+ path: (id) => `/reporting/media-account/${id}/ads/final-urls`
4806
+ },
4807
+ {
4808
+ name: "dimension-summary",
4809
+ description: "\u8D26\u6237\u7EF4\u5EA6\u6C47\u603B reports/combined",
4810
+ dateMode: "range",
4811
+ path: (id) => `/reporting/media-account/${id}/reports/combined`
4812
+ },
4813
+ {
4814
+ name: "campaign-types",
4815
+ description: "\u5E7F\u544A\u7CFB\u5217\u7C7B\u578B\u6C47\u603B campaigns/types-summary\uFF08\u5B9E\u65F6\uFF0C\u53EF\u67E5\u5F53\u5929\uFF09",
4816
+ dateMode: "none",
4817
+ path: (id) => `/reporting/media-account/${id}/campaigns/types-summary`
4818
+ }
4819
+ ];
4820
+ }
4821
+ });
4822
+
4823
+ // src/commands/google-analysis/fetch.ts
4824
+ function defaultDateRange3() {
4825
+ const end = /* @__PURE__ */ new Date();
4826
+ end.setDate(end.getDate() - 1);
4827
+ const start = new Date(end);
4828
+ start.setDate(start.getDate() - 6);
4829
+ const fmt2 = (d) => d.toISOString().slice(0, 10);
4830
+ return { startDate: fmt2(start), endDate: fmt2(end) };
4831
+ }
4832
+ function resolveDateRange2(start, end) {
4833
+ if (start && end) return { startDate: start, endDate: end };
4834
+ if (!start && !end) return defaultDateRange3();
4835
+ console.error("\n\u274C --start \u4E0E --end \u987B\u540C\u65F6\u4F20\u5165\uFF0C\u6216\u540C\u65F6\u7701\u7565\u4EE5\u4F7F\u7528\u9ED8\u8BA4\u8FD1 7 \u5929\uFF08\u622A\u81F3\u6628\u5929\uFF09\u3002\n");
4836
+ process.exit(1);
4837
+ }
4838
+ function buildSearchParams(def, start, end, extras) {
4839
+ const params = new URLSearchParams();
4840
+ if (def.dateMode === "range") {
4841
+ const { startDate, endDate } = resolveDateRange2(start, end);
4842
+ params.set("startDate", startDate);
4843
+ params.set("endDate", endDate);
4844
+ }
4845
+ const merged = { ...def.defaultQuery };
4846
+ for (const [k, v] of Object.entries(extras)) {
4847
+ if (v !== void 0 && v !== "") merged[k] = v;
4848
+ }
4849
+ for (const [k, v] of Object.entries(merged)) {
4850
+ if (v === void 0 || v === null) continue;
4851
+ params.set(k, typeof v === "boolean" ? String(v) : String(v));
4852
+ }
4853
+ const s = params.toString();
4854
+ return s ? `?${s}` : "";
4855
+ }
4856
+ async function fetchJson(config, pathWithQuery, verbose) {
4857
+ const url = `${config.googleApiUrl}${pathWithQuery}`;
4858
+ return apiFetch2(url, config, {}, verbose);
4859
+ }
4860
+ function assertNever(x, ctx) {
4861
+ throw new Error(`${ctx}\uFF1A\u672A\u5904\u7406\u7684\u5206\u652F ${String(x)}`);
4862
+ }
4863
+ function rowsFromAccountDailyReportsEnvelope(raw, mediaCustomerId) {
4864
+ const block = raw.accounts?.[mediaCustomerId];
4865
+ const list = block?.data;
4866
+ return Array.isArray(list) ? list : [];
4867
+ }
4868
+ async function fetchGoogleAnalysisSectionJson(config, fullPath, verbose, name) {
4869
+ switch (name) {
4870
+ case "overview":
4871
+ return fetchJson(config, fullPath, verbose);
4872
+ case "keywords":
4873
+ return fetchJson(config, fullPath, verbose);
4874
+ case "search-terms":
4875
+ return fetchJson(config, fullPath, verbose);
4876
+ case "campaigns":
4877
+ return fetchJson(config, fullPath, verbose);
4878
+ case "campaign-hour":
4879
+ return fetchJson(config, fullPath, verbose);
4880
+ case "ads":
4881
+ return fetchJson(config, fullPath, verbose);
4882
+ case "extensions":
4883
+ return fetchJson(config, fullPath, verbose);
4884
+ case "devices":
4885
+ return fetchJson(config, fullPath, verbose);
4886
+ case "geographic":
4887
+ return fetchJson(config, fullPath, verbose);
4888
+ case "audience":
4889
+ return fetchJson(config, fullPath, verbose);
4890
+ case "asset-images":
4891
+ return fetchJson(config, fullPath, verbose);
4892
+ case "videos":
4893
+ return fetchJson(config, fullPath, verbose);
4894
+ case "resource-counts":
4895
+ return fetchJson(config, fullPath, verbose);
4896
+ case "conversion-actions":
4897
+ return fetchJson(config, fullPath, verbose);
4898
+ case "gold-account":
4899
+ return fetchJson(config, fullPath, verbose);
4900
+ case "ads-index":
4901
+ return fetchJson(config, fullPath, verbose);
4902
+ case "final-urls":
4903
+ return fetchJson(config, fullPath, verbose);
4904
+ case "dimension-summary":
4905
+ return fetchJson(config, fullPath, verbose);
4906
+ case "campaign-types":
4907
+ return fetchJson(config, fullPath, verbose);
4908
+ default:
4909
+ return assertNever(name, "google-analysis");
4910
+ }
4911
+ }
4912
+ function endpointHintFrom(def) {
4913
+ const segs = def.path("0").split("/").filter(Boolean).filter((s) => !/^\d+$/.test(s));
4914
+ if (segs.length === 0) return void 0;
4915
+ return segs.join("/");
4916
+ }
4917
+ function manifestDateRange(def, start, end) {
4918
+ if (def.dateMode === "none") return null;
4919
+ const { startDate, endDate } = resolveDateRange2(start, end);
4920
+ return { mode: "range", start: startDate, end: endDate };
4921
+ }
4922
+ async function fetchSectionPayload(def, opts, config, id) {
4923
+ const extras = {};
4924
+ if (def.keywordOptions) {
4925
+ if (typeof opts.limit === "number" && opts.limit > 0) {
4926
+ extras.limit = opts.limit;
4927
+ }
4928
+ if (opts.noOrderByCost) {
4929
+ extras.orderByCost = false;
4930
+ }
4931
+ }
4932
+ if (def.extensionLevelOption && opts.level) {
4933
+ extras.level = opts.level;
4934
+ }
4935
+ if (def.audienceFilterOption && opts.audienceType) {
4936
+ extras.audienceTypeFilter = opts.audienceType;
4937
+ }
4938
+ if (def.name === "materials") {
4939
+ const { startDate, endDate } = resolveDateRange2(opts.start, opts.end);
4940
+ const q = `?${new URLSearchParams({ startDate, endDate }).toString()}`;
4941
+ const videoPath = `/reporting/media-account/${id}/Videos${q}`;
4942
+ const imagePath = `/reporting/media-account/${id}/CampaignAssetView${q}`;
4943
+ const [images, videos] = await Promise.all([
4944
+ fetchJson(config, imagePath, !!opts.verbose),
4945
+ fetchJson(config, videoPath, !!opts.verbose)
4946
+ ]);
4947
+ const merged = { images, videos };
4948
+ return stripLegacyGoogleFieldsIfV2Present(merged);
4949
+ }
4950
+ if (def.name === "daily-metrics") {
4951
+ const { startDate, endDate } = resolveDateRange2(opts.start, opts.end);
4952
+ const params = new URLSearchParams({
4953
+ mediaCustomerIds: id,
4954
+ startDate: `${startDate}T00:00:00+08:00`,
4955
+ endDate: `${endDate}T23:59:59+08:00`
4956
+ });
4957
+ const url = `${config.apiBaseUrl}/report/media-account/google/account-daily-reports?${params.toString()}`;
4958
+ const raw = await apiFetch2(url, config, {}, !!opts.verbose);
4959
+ const rows = rowsFromAccountDailyReportsEnvelope(raw, id);
4960
+ return stripLegacyGoogleFieldsIfV2Present(rows);
4961
+ }
4962
+ const sectionPath = def.path(id);
4963
+ const query = buildSearchParams(def, opts.start, opts.end, extras);
4964
+ const data = await fetchGoogleAnalysisSectionJson(
4965
+ config,
4966
+ `${sectionPath}${query}`,
4967
+ !!opts.verbose,
4968
+ def.name
4969
+ );
4970
+ return stripLegacyGoogleFieldsIfV2Present(data);
4971
+ }
4972
+ function endpointHintForSection(def) {
4973
+ if (def.name === "materials") return "CampaignAssetView+Videos";
4974
+ return endpointHintFrom(def);
4975
+ }
4976
+ async function fetchOneGoogleSection(opts) {
4977
+ const def = SECTIONS.find((s) => s.name === opts.section);
4978
+ if (!def) throw new Error(`\u672A\u77E5 google-analysis \u7EF4\u5EA6\uFF1A${opts.section}`);
4979
+ const payload = await fetchSectionPayload(
4980
+ def,
4981
+ {
4982
+ account: opts.accountId,
4983
+ start: opts.start,
4984
+ end: opts.end,
4985
+ verbose: opts.verbose,
4986
+ limit: opts.limit,
4987
+ noOrderByCost: opts.noOrderByCost,
4988
+ level: opts.level,
4989
+ audienceType: opts.audienceType
4990
+ },
4991
+ opts.config,
4992
+ opts.accountId
4993
+ );
4994
+ return {
4995
+ payload,
4996
+ dateRange: manifestDateRange(def, opts.start, opts.end),
4997
+ endpointHint: endpointHintForSection(def),
4998
+ section: def.name
4999
+ };
5000
+ }
5001
+ var init_fetch = __esm({
5002
+ "src/commands/google-analysis/fetch.ts"() {
5003
+ "use strict";
5004
+ init_auth();
5005
+ init_strip_legacy_google_fields();
5006
+ init_sections();
5007
+ }
5008
+ });
5009
+
5010
+ // src/utils/google-analysis-snapshot.ts
5011
+ var init_google_analysis_snapshot = __esm({
5012
+ "src/utils/google-analysis-snapshot.ts"() {
5013
+ "use strict";
5014
+ init_google_analysis();
5015
+ }
5016
+ });
5017
+
5018
+ // src/utils/http-retry.ts
5019
+ function classifyError(err) {
5020
+ const status = parseHttpStatusFromError(err);
5021
+ if (status === 401) return { class: "abort", status };
5022
+ if (status === void 0) {
5023
+ return { class: "retryable" };
5024
+ }
5025
+ if (status === 408 || status === 429) return { class: "retryable", status };
5026
+ if (status >= 500 && status <= 599) return { class: "retryable", status };
5027
+ if (status >= 400 && status <= 499) return { class: "permanent", status };
5028
+ return { class: "permanent", status };
5029
+ }
5030
+ function computeBackoffMs(attempt, policy) {
5031
+ const exp = policy.baseMs * 2 ** Math.max(0, attempt - 1);
5032
+ const capped = Math.min(exp, policy.maxBackoffMs);
5033
+ const jitter = Math.floor(Math.random() * policy.baseMs);
5034
+ return capped + jitter;
5035
+ }
5036
+ function sleep2(ms, signal) {
5037
+ return new Promise((resolve8, reject) => {
5038
+ if (signal?.aborted) {
5039
+ reject(new Error("retry sleep aborted"));
5040
+ return;
5041
+ }
5042
+ const timer = setTimeout(() => {
5043
+ signal?.removeEventListener("abort", onAbort);
5044
+ resolve8();
5045
+ }, ms);
5046
+ const onAbort = () => {
5047
+ clearTimeout(timer);
5048
+ reject(new Error("retry sleep aborted"));
5049
+ };
5050
+ signal?.addEventListener("abort", onAbort, { once: true });
5051
+ });
5052
+ }
5053
+ async function withTaskTimeout(factory, timeoutMs, label) {
5054
+ if (!timeoutMs || timeoutMs <= 0) return factory();
5055
+ let timer;
5056
+ try {
5057
+ return await Promise.race([
5058
+ factory(),
5059
+ new Promise((_, reject) => {
5060
+ timer = setTimeout(() => {
5061
+ reject(new Error(`\u8BF7\u6C42\u8D85\u65F6\uFF08${(timeoutMs / 1e3).toFixed(0)} \u79D2\uFF09\uFF1A${label}`));
5062
+ }, timeoutMs);
5063
+ })
5064
+ ]);
5065
+ } finally {
5066
+ if (timer) clearTimeout(timer);
5067
+ }
5068
+ }
5069
+ async function fetchWithRetry(factory, options) {
5070
+ const policy = { ...DEFAULT_RETRY_POLICY, ...options.policy ?? {} };
5071
+ let lastErr;
5072
+ let lastStatus;
5073
+ for (let attempt = 1; attempt <= policy.maxAttempts; attempt++) {
5074
+ if (options.signal?.aborted) {
5075
+ throw new AbortRunError({
5076
+ message: `\u4EFB\u52A1\u88AB\u5916\u90E8\u4FE1\u53F7\u4E2D\u6B62\uFF1A${options.label}`
5077
+ });
5078
+ }
5079
+ try {
5080
+ return await withTaskTimeout(factory, policy.taskTimeoutMs, options.label);
5081
+ } catch (raw) {
5082
+ const err = raw instanceof Error ? raw : new Error(String(raw));
5083
+ const cls = classifyError(err);
5084
+ lastErr = err;
5085
+ lastStatus = cls.status;
5086
+ if (cls.class === "abort") {
5087
+ throw new AbortRunError({
5088
+ message: `Token \u5931\u6548\u6216\u81F4\u547D\u9519\u8BEF\uFF08${options.label}\uFF09\uFF1A${err.message}`,
5089
+ status: cls.status,
5090
+ cause: err
5091
+ });
5092
+ }
5093
+ if (cls.class === "permanent" || attempt >= policy.maxAttempts) {
5094
+ throw new HttpRetryError({
5095
+ message: cls.class === "permanent" ? `\u6C38\u4E45\u5931\u8D25\uFF08${options.label}\uFF09\uFF1A${err.message}` : `\u91CD\u8BD5 ${attempt} \u6B21\u4ECD\u5931\u8D25\uFF08${options.label}\uFF09\uFF1A${err.message}`,
5096
+ class: cls.class === "permanent" ? "permanent" : "retryable",
5097
+ status: cls.status,
5098
+ attempts: attempt,
5099
+ cause: err
5100
+ });
5101
+ }
5102
+ const backoffMs = computeBackoffMs(attempt, policy);
5103
+ options.onRetry?.({ attempt, backoffMs, status: cls.status, error: err });
5104
+ try {
5105
+ await sleep2(backoffMs, options.signal);
5106
+ } catch {
5107
+ throw new AbortRunError({
5108
+ message: `\u91CD\u8BD5\u7B49\u5F85\u88AB\u4E2D\u6B62\uFF1A${options.label}`,
5109
+ cause: err
5110
+ });
5111
+ }
5112
+ }
5113
+ }
5114
+ throw new HttpRetryError({
5115
+ message: `\u672A\u77E5\u91CD\u8BD5\u5931\u8D25\uFF08${options.label}\uFF09\uFF1A${lastErr?.message ?? "no error"}`,
5116
+ class: "retryable",
5117
+ status: lastStatus,
5118
+ attempts: policy.maxAttempts,
5119
+ cause: lastErr
5120
+ });
5121
+ }
5122
+ var HttpRetryError, AbortRunError, DEFAULT_RETRY_POLICY;
5123
+ var init_http_retry = __esm({
5124
+ "src/utils/http-retry.ts"() {
4763
5125
  "use strict";
4764
5126
  init_dist();
4765
5127
  HttpRetryError = class extends Error {
@@ -5295,12 +5657,7 @@ async function runBatch(opts) {
5295
5657
  aborterPaused.signal
5296
5658
  );
5297
5659
  };
5298
- await runPool(
5299
- accountIds,
5300
- accountConcurrencyRef,
5301
- runOneAccount,
5302
- aborterPaused.signal
5303
- );
5660
+ await runPool(accountIds, accountConcurrencyRef, runOneAccount, aborterPaused.signal);
5304
5661
  const pausedByDeadline = deadlineAt > 0 && Date.now() > deadlineAt;
5305
5662
  const pausedByExternalSignal = !!opts.signal?.aborted;
5306
5663
  const forcedPaused = pausedByDeadline || pausedByExternalSignal;
@@ -5384,7 +5741,7 @@ var DEFAULT_ADAPTIVE, AdaptiveThrottle;
5384
5741
  var init_batch_runner = __esm({
5385
5742
  "src/utils/batch-runner.ts"() {
5386
5743
  "use strict";
5387
- init_google_analysis2();
5744
+ init_google_analysis3();
5388
5745
  init_google_analysis_snapshot();
5389
5746
  init_http_retry();
5390
5747
  init_batch_manifest();
@@ -5541,10 +5898,14 @@ async function resolveBatchAccounts(config, opts) {
5541
5898
  if (chunks.length > 0) {
5542
5899
  const [bMaps, oMaps] = await Promise.all([
5543
5900
  Promise.all(
5544
- chunks.map((ids) => fetchBalanceMap("Google", ids, config, opts.start, opts.end, opts.verbose))
5901
+ chunks.map(
5902
+ (ids) => fetchBalanceMap("Google", ids, config, opts.start, opts.end, opts.verbose)
5903
+ )
5545
5904
  ),
5546
5905
  Promise.all(
5547
- chunks.map((ids) => fetchOverviewMap("Google", ids, config, opts.start, opts.end, opts.verbose))
5906
+ chunks.map(
5907
+ (ids) => fetchOverviewMap("Google", ids, config, opts.start, opts.end, opts.verbose)
5908
+ )
5548
5909
  )
5549
5910
  ]);
5550
5911
  for (const m of bMaps) for (const [k, v] of m) balanceMap.set(k, v);
@@ -5563,7 +5924,11 @@ async function executeBatchRun(input) {
5563
5924
  if (input.refreshDp) config = await refreshDataPermission(config);
5564
5925
  const runId = input.runId?.trim() || generateRunId();
5565
5926
  if (!isValidRunId(runId)) throw new Error(`\u975E\u6CD5 runId\uFF1A${runId}`);
5566
- const { accounts: filtered, scanned, explicit } = await resolveBatchAccounts(config, {
5927
+ const {
5928
+ accounts: filtered,
5929
+ scanned,
5930
+ explicit
5931
+ } = await resolveBatchAccounts(config, {
5567
5932
  explicitAccountIds: input.explicitAccountIds,
5568
5933
  minSpend: input.minSpend,
5569
5934
  start: input.start,
@@ -5768,10 +6133,7 @@ async function cmdResume(opts) {
5768
6133
  }
5769
6134
  let config = loadConfig(opts.token);
5770
6135
  if (opts.refreshDp) config = await refreshDataPermission(config);
5771
- const { paths, manifest, accounts, states } = await loadResumeState(
5772
- opts.jsonOut,
5773
- opts.runId
5774
- );
6136
+ const { paths, manifest, accounts, states } = await loadResumeState(opts.jsonOut, opts.runId);
5775
6137
  const acquired = await tryAcquireLock(paths);
5776
6138
  if (!acquired) {
5777
6139
  emitSummary({
@@ -5868,275 +6230,83 @@ async function cmdStatus(opts) {
5868
6230
  for (const t of states.values()) {
5869
6231
  if (t.state === "failed_permanent" || t.state === "failed_retryable") {
5870
6232
  failed.push({ id: t.id, lastError: t.lastError, lastStatus: t.lastStatus });
5871
- }
5872
- }
5873
- emitSummary({
5874
- runId: opts.runId,
5875
- state: progress?.state ?? "running",
5876
- manifestFile: paths.runManifestFile,
5877
- progressFile: paths.progressFile,
5878
- runDir: paths.runDir,
5879
- accountsTotal: accounts.length,
5880
- sections: manifest.sections,
5881
- progress: progress ?? null,
5882
- failedSample: failed.slice(0, 5)
5883
- });
5884
- process.exit(decideExitCode(progress?.state ?? "running", false));
5885
- }
5886
- function registerGoogleAnalysisBatchCommands(program2) {
5887
- const grp = program2.command("google-analysis-batch").description(
5888
- "Google \u8D26\u6237\u5206\u6790\u7684\u6279\u5904\u7406\u5F15\u64CE\uFF1A\u5355\u8FDB\u7A0B\u5185\u505A\u8D26\u6237\xD7\u7EF4\u5EA6\u53CC\u5C42\u5E76\u53D1\u3001\u81EA\u52A8\u91CD\u8BD5\u3001\u65AD\u70B9\u7EED\u8DD1\u3002Agent \u5927\u6279\u91CF\u62C9\u6570\u9996\u9009\u3002"
5889
- );
5890
- grp.command("run").description("\u4E00\u6B21\u6027\u6279\u8DD1\uFF1A\u81EA\u52A8\u62C9\u8D26\u6237\u6E05\u5355 + \u6309\u8D26\u6237\xD7\u7EF4\u5EA6\u5E76\u53D1\u6267\u884C + \u843D\u76D8 manifest/progress").requiredOption("--json-out <baseDir>", "\u4EA7\u7269\u6839\u76EE\u5F55\uFF08\u6BCF\u4E2A runId \u4E00\u4E2A\u5B50\u76EE\u5F55\uFF09").option("--run-id <id>", "\u53EF\u9009\u81EA\u5B9A\u4E49 runId\uFF08\u7559\u7A7A\u81EA\u52A8\u751F\u6210 run-YYYYMMDD-HHmmss-<rand4>\uFF09").option(
5891
- "-a, --accounts <ids>",
5892
- "\u663E\u5F0F\u6307\u5B9A mediaCustomerId \u5217\u8868\uFF08\u9017\u53F7\u5206\u9694\uFF09\uFF1B\u4F20\u5165\u5219\u8DF3\u8FC7\u8D26\u6237\u6E05\u5355\u62C9\u53D6\u4E0E --min-spend \u8FC7\u6EE4"
5893
- ).option("--start <date>", "\u7EDF\u8BA1\u5F00\u59CB\u65E5\u671F YYYY-MM-DD\uFF08\u5F3A\u70C8\u5EFA\u8BAE\u663E\u5F0F\u6307\u5B9A\uFF09").option("--end <date>", "\u7EDF\u8BA1\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option(
5894
- "--sections <list>",
5895
- `\u8981\u62C9\u53D6\u7684\u7EF4\u5EA6\uFF08\u9017\u53F7\u5206\u9694\uFF09\uFF0C\u9ED8\u8BA4 ${DEFAULT_SECTIONS.join(",")}`
5896
- ).option(
5897
- "--account-concurrency <n>",
5898
- `\u8D26\u6237\u7EA7\u5E76\u53D1\uFF0C\u9ED8\u8BA4 ${DEFAULT_ACCOUNT_CONCURRENCY}\uFF08\u4E0A\u9650 16\uFF09`,
5899
- (v) => parseInt(v, 10)
5900
- ).option(
5901
- "--section-concurrency <n>",
5902
- `\u5355\u8D26\u6237\u5185\u7EF4\u5EA6\u5E76\u53D1\uFF0C\u9ED8\u8BA4 ${DEFAULT_SECTION_CONCURRENCY}\uFF08\u4E0A\u9650 16\uFF09`,
5903
- (v) => parseInt(v, 10)
5904
- ).option(
5905
- "--keyword-limit <n>",
5906
- "\u900F\u4F20\u7ED9 keywords / search-terms \u7684\u6761\u6570\u4E0A\u9650\uFF08\u63A7\u5236\u5927\u8D26\u6237\u54CD\u5E94\u4F53\u79EF\uFF09",
5907
- (v) => parseInt(v, 10)
5908
- ).option(
5909
- "--min-spend <n>",
5910
- "\u533A\u95F4\u5185\u6D88\u8017 \u2264 \u6B64\u503C\u7684\u8D26\u6237\u8DF3\u8FC7\uFF1B0=\u4E0D\u8FC7\u6EE4\uFF08\u4E0E --accounts \u540C\u4F20\u65F6\u65E0\u6548\uFF09",
5911
- (v) => parseFloat(v)
5912
- ).option(
5913
- "--deadline <duration>",
5914
- "\u6574\u4EFB\u52A1\u786C\u622A\u6B62\u65F6\u95F4\uFF08\u5982 30m / 2h / 90s\uFF09\uFF0C\u5230\u671F\u540E\u505C\u6B62\u6D3E\u53D1\u5E76\u6807\u8BB0 paused"
5915
- ).option(
5916
- "--task-timeout-ms <n>",
5917
- "\u5355 task \u786C\u8D85\u65F6\u6BEB\u79D2\uFF0C\u9ED8\u8BA4 60000",
5918
- (v) => parseInt(v, 10)
5919
- ).option(
5920
- "--max-attempts <n>",
5921
- "\u53EF\u91CD\u8BD5\u9519\u8BEF\u7684\u6700\u5927\u5C1D\u8BD5\u6B21\u6570\uFF0C\u9ED8\u8BA4 3",
5922
- (v) => parseInt(v, 10)
5923
- ).option("--refresh-dp", "\u6267\u884C\u524D\u5F3A\u5236\u5237\u65B0\u4E00\u6B21 Datapermission\uFF08\u4E00\u822C\u65E0\u9700\uFF09", false).option("--no-verbose-progress", "\u5173\u95ED stderr \u7684\u8FDB\u5EA6\u6761\uFF08CI \u73AF\u5883\u63A8\u8350\uFF09").option("-t, --token <token>", "Auth Token\uFF08\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option("--verbose", "\u663E\u793A\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
5924
- await cmdRun(opts);
5925
- });
5926
- grp.command("resume").description("\u7EED\u8DD1\uFF1A\u4EC5\u91CD\u65B0\u6267\u884C pending / failed_retryable \u7684 task\uFF0C\u5DF2\u6210\u529F\u7684\u4E0D\u91CD\u590D\u8BF7\u6C42").requiredOption("--json-out <baseDir>", "\u4EA7\u7269\u6839\u76EE\u5F55").requiredOption("--run-id <id>", "\u8981\u7EED\u8DD1\u7684 runId").option("--deadline <duration>", "\u53EF\u8986\u76D6\u539F deadline\uFF08\u540C run \u7684\u683C\u5F0F\uFF09").option("--refresh-dp", "\u6267\u884C\u524D\u5F3A\u5236\u5237\u65B0\u4E00\u6B21 Datapermission", false).option("--no-verbose-progress", "\u5173\u95ED stderr \u7684\u8FDB\u5EA6\u6761").option("-t, --token <token>", "Auth Token\uFF08\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option("--verbose", "\u663E\u793A\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
5927
- await cmdResume(opts);
5928
- });
5929
- grp.command("status").description("\u53EA\u8BFB\u67E5\u8BE2\uFF1A\u6253\u5370 progress.json + \u5931\u8D25\u6837\u4F8B\uFF08\u6700\u591A 5 \u4E2A\uFF09\uFF0C\u4E0D\u53D1\u8D77\u4EFB\u4F55 HTTP").requiredOption("--json-out <baseDir>", "\u4EA7\u7269\u6839\u76EE\u5F55").requiredOption("--run-id <id>", "\u8981\u67E5\u8BE2\u7684 runId").action(async (opts) => {
5930
- await cmdStatus(opts);
5931
- });
5932
- }
5933
- var DEFAULT_SECTIONS, DEFAULT_ACCOUNT_CONCURRENCY, DEFAULT_SECTION_CONCURRENCY, SUMMARY_KIND, EXIT_OK, EXIT_PARTIAL, EXIT_FAILED, EXIT_USAGE;
5934
- var init_google_analysis_batch = __esm({
5935
- "src/commands/google-analysis-batch.ts"() {
5936
- "use strict";
5937
- init_auth();
5938
- init_accounts_digest();
5939
- init_batch_manifest();
5940
- init_batch_runner();
5941
- init_http_retry();
5942
- init_google_analysis2();
5943
- init_balance();
5944
- init_version();
5945
- DEFAULT_SECTIONS = [
5946
- "campaigns",
5947
- "geographic",
5948
- "keywords"
5949
- ];
5950
- DEFAULT_ACCOUNT_CONCURRENCY = 4;
5951
- DEFAULT_SECTION_CONCURRENCY = 6;
5952
- SUMMARY_KIND = "siluzan-tso-batch-summary";
5953
- EXIT_OK = 0;
5954
- EXIT_PARTIAL = 2;
5955
- EXIT_FAILED = 3;
5956
- EXIT_USAGE = 4;
5957
- }
5958
- });
5959
-
5960
- // src/commands/google-analysis.ts
5961
- import * as path20 from "path";
5962
- import { performance as performance4 } from "perf_hooks";
5963
- function defaultDateRange3() {
5964
- const end = /* @__PURE__ */ new Date();
5965
- end.setDate(end.getDate() - 1);
5966
- const start = new Date(end);
5967
- start.setDate(start.getDate() - 6);
5968
- const fmt2 = (d) => d.toISOString().slice(0, 10);
5969
- return { startDate: fmt2(start), endDate: fmt2(end) };
5970
- }
5971
- function resolveDateRange2(start, end) {
5972
- if (start && end) return { startDate: start, endDate: end };
5973
- if (!start && !end) return defaultDateRange3();
5974
- console.error("\n\u274C --start \u4E0E --end \u987B\u540C\u65F6\u4F20\u5165\uFF0C\u6216\u540C\u65F6\u7701\u7565\u4EE5\u4F7F\u7528\u9ED8\u8BA4\u8FD1 7 \u5929\uFF08\u622A\u81F3\u6628\u5929\uFF09\u3002\n");
5975
- process.exit(1);
5976
- }
5977
- function buildSearchParams(def, start, end, extras) {
5978
- const params = new URLSearchParams();
5979
- if (def.dateMode === "range") {
5980
- const { startDate, endDate } = resolveDateRange2(start, end);
5981
- params.set("startDate", startDate);
5982
- params.set("endDate", endDate);
5983
- }
5984
- const merged = { ...def.defaultQuery };
5985
- for (const [k, v] of Object.entries(extras)) {
5986
- if (v !== void 0 && v !== "") merged[k] = v;
5987
- }
5988
- for (const [k, v] of Object.entries(merged)) {
5989
- if (v === void 0 || v === null) continue;
5990
- params.set(k, typeof v === "boolean" ? String(v) : String(v));
5991
- }
5992
- const s = params.toString();
5993
- return s ? `?${s}` : "";
5994
- }
5995
- async function fetchJson(config, pathWithQuery, verbose) {
5996
- const url = `${config.googleApiUrl}${pathWithQuery}`;
5997
- return apiFetch2(url, config, {}, verbose);
5998
- }
5999
- function assertNever(x, ctx) {
6000
- throw new Error(`${ctx}\uFF1A\u672A\u5904\u7406\u7684\u5206\u652F ${String(x)}`);
6001
- }
6002
- function rowsFromAccountDailyReportsEnvelope(raw, mediaCustomerId) {
6003
- const block = raw.accounts?.[mediaCustomerId];
6004
- const list = block?.data;
6005
- return Array.isArray(list) ? list : [];
6006
- }
6007
- async function fetchGoogleAnalysisSectionJson(config, fullPath, verbose, name) {
6008
- switch (name) {
6009
- case "overview":
6010
- return fetchJson(config, fullPath, verbose);
6011
- case "keywords":
6012
- return fetchJson(config, fullPath, verbose);
6013
- case "search-terms":
6014
- return fetchJson(config, fullPath, verbose);
6015
- case "campaigns":
6016
- return fetchJson(config, fullPath, verbose);
6017
- case "campaign-hour":
6018
- return fetchJson(config, fullPath, verbose);
6019
- case "ads":
6020
- return fetchJson(config, fullPath, verbose);
6021
- case "extensions":
6022
- return fetchJson(config, fullPath, verbose);
6023
- case "devices":
6024
- return fetchJson(config, fullPath, verbose);
6025
- case "geographic":
6026
- return fetchJson(config, fullPath, verbose);
6027
- case "audience":
6028
- return fetchJson(config, fullPath, verbose);
6029
- case "asset-images":
6030
- return fetchJson(config, fullPath, verbose);
6031
- case "videos":
6032
- return fetchJson(config, fullPath, verbose);
6033
- case "resource-counts":
6034
- return fetchJson(config, fullPath, verbose);
6035
- case "conversion-actions":
6036
- return fetchJson(config, fullPath, verbose);
6037
- case "gold-account":
6038
- return fetchJson(config, fullPath, verbose);
6039
- case "ads-index":
6040
- return fetchJson(config, fullPath, verbose);
6041
- case "final-urls":
6042
- return fetchJson(config, fullPath, verbose);
6043
- case "dimension-summary":
6044
- return fetchJson(config, fullPath, verbose);
6045
- case "campaign-types":
6046
- return fetchJson(config, fullPath, verbose);
6047
- default:
6048
- return assertNever(name, "google-analysis");
6049
- }
6050
- }
6051
- function endpointHintFrom(def) {
6052
- const segs = def.path("0").split("/").filter(Boolean).filter((s) => !/^\d+$/.test(s));
6053
- if (segs.length === 0) return void 0;
6054
- return segs.join("/");
6055
- }
6056
- function manifestDateRange(def, start, end) {
6057
- if (def.dateMode === "none") return null;
6058
- const { startDate, endDate } = resolveDateRange2(start, end);
6059
- return { mode: "range", start: startDate, end: endDate };
6060
- }
6061
- async function fetchSectionPayload(def, opts, config, id) {
6062
- const extras = {};
6063
- if (def.keywordOptions) {
6064
- if (typeof opts.limit === "number" && opts.limit > 0) {
6065
- extras.limit = opts.limit;
6066
- }
6067
- if (opts.noOrderByCost) {
6068
- extras.orderByCost = false;
6069
- }
6070
- }
6071
- if (def.extensionLevelOption && opts.level) {
6072
- extras.level = opts.level;
6073
- }
6074
- if (def.audienceFilterOption && opts.audienceType) {
6075
- extras.audienceTypeFilter = opts.audienceType;
6076
- }
6077
- if (def.name === "materials") {
6078
- const { startDate, endDate } = resolveDateRange2(opts.start, opts.end);
6079
- const q = `?${new URLSearchParams({ startDate, endDate }).toString()}`;
6080
- const videoPath = `/reporting/media-account/${id}/Videos${q}`;
6081
- const imagePath = `/reporting/media-account/${id}/CampaignAssetView${q}`;
6082
- const [images, videos] = await Promise.all([
6083
- fetchJson(config, imagePath, !!opts.verbose),
6084
- fetchJson(config, videoPath, !!opts.verbose)
6085
- ]);
6086
- const merged = { images, videos };
6087
- return stripLegacyGoogleFieldsIfV2Present(merged);
6088
- }
6089
- if (def.name === "daily-metrics") {
6090
- const { startDate, endDate } = resolveDateRange2(opts.start, opts.end);
6091
- const params = new URLSearchParams({
6092
- mediaCustomerIds: id,
6093
- startDate: `${startDate}T00:00:00+08:00`,
6094
- endDate: `${endDate}T23:59:59+08:00`
6095
- });
6096
- const url = `${config.apiBaseUrl}/report/media-account/google/account-daily-reports?${params.toString()}`;
6097
- const raw = await apiFetch2(url, config, {}, !!opts.verbose);
6098
- const rows = rowsFromAccountDailyReportsEnvelope(raw, id);
6099
- return stripLegacyGoogleFieldsIfV2Present(rows);
6233
+ }
6100
6234
  }
6101
- const sectionPath = def.path(id);
6102
- const query = buildSearchParams(def, opts.start, opts.end, extras);
6103
- const data = await fetchGoogleAnalysisSectionJson(
6104
- config,
6105
- `${sectionPath}${query}`,
6106
- !!opts.verbose,
6107
- def.name
6108
- );
6109
- return stripLegacyGoogleFieldsIfV2Present(data);
6110
- }
6111
- function endpointHintForSection(def) {
6112
- if (def.name === "materials") return "CampaignAssetView+Videos";
6113
- return endpointHintFrom(def);
6235
+ emitSummary({
6236
+ runId: opts.runId,
6237
+ state: progress?.state ?? "running",
6238
+ manifestFile: paths.runManifestFile,
6239
+ progressFile: paths.progressFile,
6240
+ runDir: paths.runDir,
6241
+ accountsTotal: accounts.length,
6242
+ sections: manifest.sections,
6243
+ progress: progress ?? null,
6244
+ failedSample: failed.slice(0, 5)
6245
+ });
6246
+ process.exit(decideExitCode(progress?.state ?? "running", false));
6114
6247
  }
6115
- async function fetchOneGoogleSection(opts) {
6116
- const def = SECTIONS.find((s) => s.name === opts.section);
6117
- if (!def) throw new Error(`\u672A\u77E5 google-analysis \u7EF4\u5EA6\uFF1A${opts.section}`);
6118
- const payload = await fetchSectionPayload(
6119
- def,
6120
- {
6121
- account: opts.accountId,
6122
- start: opts.start,
6123
- end: opts.end,
6124
- verbose: opts.verbose,
6125
- limit: opts.limit,
6126
- noOrderByCost: opts.noOrderByCost,
6127
- level: opts.level,
6128
- audienceType: opts.audienceType
6129
- },
6130
- opts.config,
6131
- opts.accountId
6248
+ function registerGoogleAnalysisBatchCommands(program2) {
6249
+ const grp = program2.command("google-analysis-batch").description(
6250
+ "Google \u8D26\u6237\u5206\u6790\u7684\u6279\u5904\u7406\u5F15\u64CE\uFF1A\u5355\u8FDB\u7A0B\u5185\u505A\u8D26\u6237\xD7\u7EF4\u5EA6\u53CC\u5C42\u5E76\u53D1\u3001\u81EA\u52A8\u91CD\u8BD5\u3001\u65AD\u70B9\u7EED\u8DD1\u3002Agent \u5927\u6279\u91CF\u62C9\u6570\u9996\u9009\u3002"
6132
6251
  );
6133
- return {
6134
- payload,
6135
- dateRange: manifestDateRange(def, opts.start, opts.end),
6136
- endpointHint: endpointHintForSection(def),
6137
- section: def.name
6138
- };
6252
+ grp.command("run").description("\u4E00\u6B21\u6027\u6279\u8DD1\uFF1A\u81EA\u52A8\u62C9\u8D26\u6237\u6E05\u5355 + \u6309\u8D26\u6237\xD7\u7EF4\u5EA6\u5E76\u53D1\u6267\u884C + \u843D\u76D8 manifest/progress").requiredOption("--json-out <baseDir>", "\u4EA7\u7269\u6839\u76EE\u5F55\uFF08\u6BCF\u4E2A runId \u4E00\u4E2A\u5B50\u76EE\u5F55\uFF09").option("--run-id <id>", "\u53EF\u9009\u81EA\u5B9A\u4E49 runId\uFF08\u7559\u7A7A\u81EA\u52A8\u751F\u6210 run-YYYYMMDD-HHmmss-<rand4>\uFF09").option(
6253
+ "-a, --accounts <ids>",
6254
+ "\u663E\u5F0F\u6307\u5B9A mediaCustomerId \u5217\u8868\uFF08\u9017\u53F7\u5206\u9694\uFF09\uFF1B\u4F20\u5165\u5219\u8DF3\u8FC7\u8D26\u6237\u6E05\u5355\u62C9\u53D6\u4E0E --min-spend \u8FC7\u6EE4"
6255
+ ).option("--start <date>", "\u7EDF\u8BA1\u5F00\u59CB\u65E5\u671F YYYY-MM-DD\uFF08\u5F3A\u70C8\u5EFA\u8BAE\u663E\u5F0F\u6307\u5B9A\uFF09").option("--end <date>", "\u7EDF\u8BA1\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option("--sections <list>", `\u8981\u62C9\u53D6\u7684\u7EF4\u5EA6\uFF08\u9017\u53F7\u5206\u9694\uFF09\uFF0C\u9ED8\u8BA4 ${DEFAULT_SECTIONS.join(",")}`).option(
6256
+ "--account-concurrency <n>",
6257
+ `\u8D26\u6237\u7EA7\u5E76\u53D1\uFF0C\u9ED8\u8BA4 ${DEFAULT_ACCOUNT_CONCURRENCY}\uFF08\u4E0A\u9650 16\uFF09`,
6258
+ (v) => parseInt(v, 10)
6259
+ ).option(
6260
+ "--section-concurrency <n>",
6261
+ `\u5355\u8D26\u6237\u5185\u7EF4\u5EA6\u5E76\u53D1\uFF0C\u9ED8\u8BA4 ${DEFAULT_SECTION_CONCURRENCY}\uFF08\u4E0A\u9650 16\uFF09`,
6262
+ (v) => parseInt(v, 10)
6263
+ ).option(
6264
+ "--keyword-limit <n>",
6265
+ "\u900F\u4F20\u7ED9 keywords / search-terms \u7684\u6761\u6570\u4E0A\u9650\uFF08\u63A7\u5236\u5927\u8D26\u6237\u54CD\u5E94\u4F53\u79EF\uFF09",
6266
+ (v) => parseInt(v, 10)
6267
+ ).option(
6268
+ "--min-spend <n>",
6269
+ "\u533A\u95F4\u5185\u6D88\u8017 \u2264 \u6B64\u503C\u7684\u8D26\u6237\u8DF3\u8FC7\uFF1B0=\u4E0D\u8FC7\u6EE4\uFF08\u4E0E --accounts \u540C\u4F20\u65F6\u65E0\u6548\uFF09",
6270
+ (v) => parseFloat(v)
6271
+ ).option(
6272
+ "--deadline <duration>",
6273
+ "\u6574\u4EFB\u52A1\u786C\u622A\u6B62\u65F6\u95F4\uFF08\u5982 30m / 2h / 90s\uFF09\uFF0C\u5230\u671F\u540E\u505C\u6B62\u6D3E\u53D1\u5E76\u6807\u8BB0 paused"
6274
+ ).option("--task-timeout-ms <n>", "\u5355 task \u786C\u8D85\u65F6\u6BEB\u79D2\uFF0C\u9ED8\u8BA4 60000", (v) => parseInt(v, 10)).option("--max-attempts <n>", "\u53EF\u91CD\u8BD5\u9519\u8BEF\u7684\u6700\u5927\u5C1D\u8BD5\u6B21\u6570\uFF0C\u9ED8\u8BA4 3", (v) => parseInt(v, 10)).option("--refresh-dp", "\u6267\u884C\u524D\u5F3A\u5236\u5237\u65B0\u4E00\u6B21 Datapermission\uFF08\u4E00\u822C\u65E0\u9700\uFF09", false).option("--no-verbose-progress", "\u5173\u95ED stderr \u7684\u8FDB\u5EA6\u6761\uFF08CI \u73AF\u5883\u63A8\u8350\uFF09").option("-t, --token <token>", "Auth Token\uFF08\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option("--verbose", "\u663E\u793A\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
6275
+ await cmdRun(opts);
6276
+ });
6277
+ grp.command("resume").description("\u7EED\u8DD1\uFF1A\u4EC5\u91CD\u65B0\u6267\u884C pending / failed_retryable \u7684 task\uFF0C\u5DF2\u6210\u529F\u7684\u4E0D\u91CD\u590D\u8BF7\u6C42").requiredOption("--json-out <baseDir>", "\u4EA7\u7269\u6839\u76EE\u5F55").requiredOption("--run-id <id>", "\u8981\u7EED\u8DD1\u7684 runId").option("--deadline <duration>", "\u53EF\u8986\u76D6\u539F deadline\uFF08\u540C run \u7684\u683C\u5F0F\uFF09").option("--refresh-dp", "\u6267\u884C\u524D\u5F3A\u5236\u5237\u65B0\u4E00\u6B21 Datapermission", false).option("--no-verbose-progress", "\u5173\u95ED stderr \u7684\u8FDB\u5EA6\u6761").option("-t, --token <token>", "Auth Token\uFF08\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option("--verbose", "\u663E\u793A\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
6278
+ await cmdResume(opts);
6279
+ });
6280
+ grp.command("status").description("\u53EA\u8BFB\u67E5\u8BE2\uFF1A\u6253\u5370 progress.json + \u5931\u8D25\u6837\u4F8B\uFF08\u6700\u591A 5 \u4E2A\uFF09\uFF0C\u4E0D\u53D1\u8D77\u4EFB\u4F55 HTTP").requiredOption("--json-out <baseDir>", "\u4EA7\u7269\u6839\u76EE\u5F55").requiredOption("--run-id <id>", "\u8981\u67E5\u8BE2\u7684 runId").action(async (opts) => {
6281
+ await cmdStatus(opts);
6282
+ });
6139
6283
  }
6284
+ var DEFAULT_SECTIONS, DEFAULT_ACCOUNT_CONCURRENCY, DEFAULT_SECTION_CONCURRENCY, SUMMARY_KIND, EXIT_OK, EXIT_PARTIAL, EXIT_FAILED, EXIT_USAGE;
6285
+ var init_google_analysis_batch = __esm({
6286
+ "src/commands/google-analysis-batch.ts"() {
6287
+ "use strict";
6288
+ init_auth();
6289
+ init_accounts_digest2();
6290
+ init_batch_manifest();
6291
+ init_batch_runner();
6292
+ init_http_retry();
6293
+ init_google_analysis3();
6294
+ init_balance();
6295
+ init_version();
6296
+ DEFAULT_SECTIONS = ["campaigns", "geographic", "keywords"];
6297
+ DEFAULT_ACCOUNT_CONCURRENCY = 4;
6298
+ DEFAULT_SECTION_CONCURRENCY = 6;
6299
+ SUMMARY_KIND = "siluzan-tso-batch-summary";
6300
+ EXIT_OK = 0;
6301
+ EXIT_PARTIAL = 2;
6302
+ EXIT_FAILED = 3;
6303
+ EXIT_USAGE = 4;
6304
+ }
6305
+ });
6306
+
6307
+ // src/commands/google-analysis/register-cli.ts
6308
+ import * as path20 from "path";
6309
+ import { performance as performance4 } from "perf_hooks";
6140
6310
  function resolveSectionList(sections, exclude) {
6141
6311
  const allNames = SECTIONS.map((s) => s.name);
6142
6312
  const splitClean = (s) => (s ?? "").split(",").map((x) => x.trim()).filter(Boolean);
@@ -6178,7 +6348,9 @@ async function runAllSections(opts) {
6178
6348
  process.exit(1);
6179
6349
  }
6180
6350
  if (!opts.jsonOut || !opts.jsonOut.trim()) {
6181
- console.error("\n\u274C all \u6A21\u5F0F\u5FC5\u987B\u4F20 --json-out <\u76EE\u5F55>\uFF0821 \u4E2A\u7EF4\u5EA6\u7ED3\u679C\u843D\u76D8\u540E\u7531 manifest \u7D22\u5F15\uFF09\u3002\n");
6351
+ console.error(
6352
+ "\n\u274C all \u6A21\u5F0F\u5FC5\u987B\u4F20 --json-out <\u76EE\u5F55>\uFF0821 \u4E2A\u7EF4\u5EA6\u7ED3\u679C\u843D\u76D8\u540E\u7531 manifest \u7D22\u5F15\uFF09\u3002\n"
6353
+ );
6182
6354
  process.exit(1);
6183
6355
  }
6184
6356
  const targets = resolveSectionList(opts.sections, opts.exclude);
@@ -6317,9 +6489,7 @@ async function runMultiAccountViaBatch(accountIds, opts) {
6317
6489
  process.exit(3);
6318
6490
  }
6319
6491
  function registerGoogleAnalysisCommands(program2) {
6320
- program2.command("google-analysis").description(
6321
- "Google \u8D26\u6237\u5206\u6790\u6279\u91CF\u62C9\u53D6\u4E00\u4E2A\u6216\u591A\u4E2A\u7EF4\u5EA6-a \u652F\u6301\u9017\u53F7\u5206\u9694\u591A ID"
6322
- ).argument("[legacy-section]", "\uFF08\u5DF2\u5E9F\u5F03\uFF09\u5386\u53F2\u7684\u5355\u7EF4\u5EA6\u5B50\u547D\u4EE4\u540D\uFF0C\u8BF7\u6539\u7528 --sections <name>").requiredOption(
6492
+ program2.command("google-analysis").description("Google \u8D26\u6237\u5206\u6790\u6279\u91CF\u62C9\u53D6\u4E00\u4E2A\u6216\u591A\u4E2A\u7EF4\u5EA6-a \u652F\u6301\u9017\u53F7\u5206\u9694\u591A ID").argument("[legacy-section]", "\uFF08\u5DF2\u5E9F\u5F03\uFF09\u5386\u53F2\u7684\u5355\u7EF4\u5EA6\u5B50\u547D\u4EE4\u540D\uFF0C\u8BF7\u6539\u7528 --sections <name>").requiredOption(
6323
6493
  "-a, --account <ids>",
6324
6494
  "Google mediaCustomerId\uFF1B\u652F\u6301\u5355 ID \u6216\u9017\u53F7\u5206\u9694\u591A ID\uFF08\u591A ID \u65F6\u81EA\u52A8\u8F6C\u53D1\u5230 google-analysis-batch \u5F15\u64CE\uFF09"
6325
6495
  ).requiredOption(
@@ -6338,10 +6508,7 @@ function registerGoogleAnalysisCommands(program2) {
6338
6508
  "--concurrency <n>",
6339
6509
  "\u5E76\u53D1\u6570\uFF0C\u9ED8\u8BA4 5\uFF1B\u4E0A\u9650 16\uFF08\u4E0E http-raw maxSockets \u5BF9\u9F50\uFF09\uFF1B\u8D26\u6237\u5927\u6216\u7F51\u7EDC\u6162\u65F6\u8C03\u5C0F",
6340
6510
  (v) => parseInt(v, 10)
6341
- ).option("--limit <n>", "\u900F\u4F20\u7ED9 keywords / search-terms \u7EF4\u5EA6\u7684\u6761\u6570\u4E0A\u9650", (v) => parseInt(v, 10)).option("--no-order-by-cost", "\u900F\u4F20\uFF1Akeywords / search-terms \u4E0D\u6309\u6D88\u8017\u6392\u5E8F", false).option(
6342
- "--level <level>",
6343
- "\u900F\u4F20\u7ED9 extensions \u7EF4\u5EA6\u7684 level \u8FC7\u6EE4\uFF1AAccount | Campaign | Ad Group"
6344
- ).option(
6511
+ ).option("--limit <n>", "\u900F\u4F20\u7ED9 keywords / search-terms \u7EF4\u5EA6\u7684\u6761\u6570\u4E0A\u9650", (v) => parseInt(v, 10)).option("--no-order-by-cost", "\u900F\u4F20\uFF1Akeywords / search-terms \u4E0D\u6309\u6D88\u8017\u6392\u5E8F", false).option("--level <level>", "\u900F\u4F20\u7ED9 extensions \u7EF4\u5EA6\u7684 level \u8FC7\u6EE4\uFF1AAccount | Campaign | Ad Group").option(
6345
6512
  "--audience-type <type>",
6346
6513
  "\u900F\u4F20\u7ED9 audience \u7EF4\u5EA6\u7684 audienceTypeFilter\uFF1ASystemDefined | UserDefined"
6347
6514
  ).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).addHelpText(
@@ -6392,156 +6559,39 @@ ${fixHint}
6392
6559
  console.error("\n\u274C \u591A\u8D26\u6237\u6A21\u5F0F\u5FC5\u987B\u4F20 --json-out <\u76EE\u5F55>\uFF08\u6309 runId \u5B50\u76EE\u5F55\u7EC4\u7EC7\u4EA7\u7269\uFF09\u3002\n");
6393
6560
  process.exit(1);
6394
6561
  }
6395
- await runMultiAccountViaBatch(ids, opts);
6396
- return;
6397
- }
6398
- await runAllSections({ ...opts, account: ids[0] });
6399
- });
6400
- }
6401
- var SECTIONS;
6402
- var init_google_analysis2 = __esm({
6403
- "src/commands/google-analysis.ts"() {
6404
- "use strict";
6405
- init_auth();
6406
- init_google_analysis_snapshot();
6407
- init_strip_legacy_google_fields();
6408
- init_version();
6409
- init_http_retry();
6410
- SECTIONS = [
6411
- {
6412
- name: "overview",
6413
- description: "\u8D26\u6237\u603B\u89C8 OverviewSectionData\uFF08\u5B9E\u65F6\uFF0C\u53EF\u67E5\u5F53\u5929\uFF09",
6414
- dateMode: "range",
6415
- path: (id) => `/reporting/media-account/${id}/OverviewSectionData`
6416
- },
6417
- {
6418
- name: "keywords",
6419
- description: "\u5173\u952E\u8BCD\u5206\u6BB5 KeywordSectionData",
6420
- dateMode: "range",
6421
- path: (id) => `/reporting/media-account/${id}/KeywordSectionData`,
6422
- defaultQuery: { limit: 100, orderByCost: true },
6423
- keywordOptions: true
6424
- },
6425
- {
6426
- name: "search-terms",
6427
- description: "\u641C\u7D22\u8BCD searchtermmanagement/v2/list",
6428
- dateMode: "range",
6429
- path: (id) => `/searchtermmanagement/v2/list/${id}`,
6430
- defaultQuery: { limit: 100, orderByCost: true },
6431
- keywordOptions: true
6432
- },
6433
- {
6434
- name: "campaigns",
6435
- description: "\u5E7F\u544A\u7CFB\u5217\u5206\u6BB5 CampaignSectionData",
6436
- dateMode: "range",
6437
- path: (id) => `/reporting/media-account/${id}/CampaignSectionData`
6438
- },
6439
- {
6440
- name: "campaign-hour",
6441
- description: "\u7CFB\u5217\u6309\u5C0F\u65F6 campaign-hour\uFF08Query\uFF1AstartDate\u3001endDate\uFF09",
6442
- dateMode: "range",
6443
- path: (id) => `/reporting/media-account/${id}/campaign-hour`
6444
- },
6445
- {
6446
- name: "ads",
6447
- description: "\u5E7F\u544A\u7EA7\u5217\u8868 admanagement/v2/list",
6448
- dateMode: "range",
6449
- path: (id) => `/admanagement/v2/list/${id}`
6450
- },
6451
- {
6452
- name: "extensions",
6453
- description: "\u9644\u52A0\u4FE1\u606F extensionmanagement/v2/list",
6454
- dateMode: "range",
6455
- path: (id) => `/extensionmanagement/v2/list/${id}`,
6456
- extensionLevelOption: true
6457
- },
6458
- {
6459
- name: "devices",
6460
- description: "\u8BBE\u5907\u5206\u6BB5 DeviceSectionData",
6461
- dateMode: "range",
6462
- path: (id) => `/reporting/media-account/${id}/DeviceSectionData`
6463
- },
6464
- {
6465
- name: "geographic",
6466
- description: "\u56FD\u5BB6/\u5730\u533A\u5206\u6BB5 GeographicSectionData",
6467
- dateMode: "range",
6468
- path: (id) => `/reporting/media-account/${id}/GeographicSectionData`
6469
- },
6470
- {
6471
- name: "audience",
6472
- description: "\u53D7\u4F17\u5206\u6BB5 AdGroupAudienceData",
6473
- dateMode: "range",
6474
- path: (id) => `/reporting/media-account/${id}/AdGroupAudienceData`,
6475
- audienceFilterOption: true
6476
- },
6477
- {
6478
- name: "asset-images",
6479
- description: "\u56FE\u7247\u7D20\u6750 CampaignAssetView",
6480
- dateMode: "range",
6481
- path: (id) => `/reporting/media-account/${id}/CampaignAssetView`
6482
- },
6483
- {
6484
- name: "videos",
6485
- description: "\u89C6\u9891\u7D20\u6750 Videos",
6486
- dateMode: "range",
6487
- path: (id) => `/reporting/media-account/${id}/Videos`
6488
- },
6489
- {
6490
- name: "materials",
6491
- description: "\u7D20\u6750\u5408\u5E76\uFF08CampaignAssetView + Videos\uFF09",
6492
- dateMode: "range",
6493
- path: (id) => `/reporting/media-account/${id}/CampaignAssetView`
6494
- },
6495
- {
6496
- name: "resource-counts",
6497
- description: "\u8D26\u6237\u7ED3\u6784 resource-counts",
6498
- dateMode: "range",
6499
- path: (id) => `/campaignmanagement/${id}/resource-counts`
6500
- },
6501
- {
6502
- name: "conversion-actions",
6503
- description: "\u8F6C\u5316\u52A8\u4F5C conversion-actions",
6504
- dateMode: "range",
6505
- path: (id) => `/reporting/media-account/${id}/conversion-actions`
6506
- },
6507
- {
6508
- name: "daily-metrics",
6509
- description: "\u6309\u65E5\u6307\u6807\uFF08\u4E3B\u5E73\u53F0 /report/media-account/google/account-daily-reports\uFF0C\u542B\u641C\u7D22\u4EFD\u989D\u7B49\uFF09",
6510
- dateMode: "range",
6511
- /** 仅用于 manifest endpointHint;实际请求走 fetchSectionPayload 专用分支(apiBaseUrl + 东八区起止时刻) */
6512
- path: () => "/report/media-account/google/account-daily-reports"
6513
- },
6514
- {
6515
- name: "gold-account",
6516
- description: "\u9EC4\u91D1\u8D26\u6237\u8BCA\u65AD GoldAccountData",
6517
- dateMode: "range",
6518
- path: (id) => `/reporting/media-account/${id}/GoldAccountData`
6519
- },
6520
- {
6521
- name: "ads-index",
6522
- description: "\u5E7F\u544A\u8D28\u91CF\u6307\u6807 AdsIndexData",
6523
- dateMode: "range",
6524
- path: (id) => `/reporting/media-account/${id}/AdsIndexData`
6525
- },
6526
- {
6527
- name: "final-urls",
6528
- description: "\u6700\u7EC8\u5230\u8FBE\u7F51\u5740 ads/final-urls\uFF08\u65E0\u65E5\u671F\u53C2\u6570\uFF09",
6529
- dateMode: "none",
6530
- path: (id) => `/reporting/media-account/${id}/ads/final-urls`
6531
- },
6532
- {
6533
- name: "dimension-summary",
6534
- description: "\u8D26\u6237\u7EF4\u5EA6\u6C47\u603B reports/combined",
6535
- dateMode: "range",
6536
- path: (id) => `/reporting/media-account/${id}/reports/combined`
6537
- },
6538
- {
6539
- name: "campaign-types",
6540
- description: "\u5E7F\u544A\u7CFB\u5217\u7C7B\u578B\u6C47\u603B campaigns/types-summary\uFF08\u5B9E\u65F6\uFF0C\u53EF\u67E5\u5F53\u5929\uFF09",
6541
- dateMode: "none",
6542
- path: (id) => `/reporting/media-account/${id}/campaigns/types-summary`
6543
- }
6544
- ];
6562
+ await runMultiAccountViaBatch(ids, opts);
6563
+ return;
6564
+ }
6565
+ await runAllSections({ ...opts, account: ids[0] });
6566
+ });
6567
+ }
6568
+ var init_register_cli = __esm({
6569
+ "src/commands/google-analysis/register-cli.ts"() {
6570
+ "use strict";
6571
+ init_auth();
6572
+ init_google_analysis_snapshot();
6573
+ init_version();
6574
+ init_http_retry();
6575
+ init_sections();
6576
+ init_fetch();
6577
+ }
6578
+ });
6579
+
6580
+ // src/commands/google-analysis/index.ts
6581
+ var init_google_analysis2 = __esm({
6582
+ "src/commands/google-analysis/index.ts"() {
6583
+ "use strict";
6584
+ init_sections();
6585
+ init_fetch();
6586
+ init_register_cli();
6587
+ }
6588
+ });
6589
+
6590
+ // src/commands/google-analysis.ts
6591
+ var init_google_analysis3 = __esm({
6592
+ "src/commands/google-analysis.ts"() {
6593
+ "use strict";
6594
+ init_google_analysis2();
6545
6595
  }
6546
6596
  });
6547
6597
 
@@ -6553,11 +6603,8 @@ import * as path21 from "path";
6553
6603
  import { fileURLToPath as fileURLToPath4 } from "url";
6554
6604
  import { Command } from "commander";
6555
6605
 
6556
- // src/commands/login.ts
6606
+ // src/commands/login/urls.ts
6557
6607
  init_defaults();
6558
- init_dist();
6559
- import * as readline from "readline";
6560
- import * as os2 from "os";
6561
6608
  function deriveWebBaseUrl(tsoApiBase) {
6562
6609
  try {
6563
6610
  const u = new URL(tsoApiBase);
@@ -6569,6 +6616,14 @@ function deriveWebBaseUrl(tsoApiBase) {
6569
6616
  }
6570
6617
  var WEB_BASE_URL = deriveWebBaseUrl(DEFAULT_API_BASE);
6571
6618
  var API_KEY_MANAGEMENT_URL = `${WEB_BASE_URL}/v3/foreign_trade/settings/apiKeyManagement`;
6619
+
6620
+ // src/commands/login/send-code.ts
6621
+ init_defaults();
6622
+ init_dist();
6623
+
6624
+ // src/commands/login/helpers.ts
6625
+ init_dist();
6626
+ import * as os2 from "os";
6572
6627
  function printPostLoginReminderBanner() {
6573
6628
  const lines = [
6574
6629
  "",
@@ -6609,7 +6664,7 @@ function printPostLoginReminderBanner() {
6609
6664
  }
6610
6665
  function parseAllowedServices(raw) {
6611
6666
  const allowed = ["CSO", "TSO", "CUT"];
6612
- if (!raw) return ["TSO", "CUT"];
6667
+ if (!raw) return ["CSO", "TSO", "CUT"];
6613
6668
  const parts = raw.split(",").map((s) => s.trim().toUpperCase()).filter(Boolean);
6614
6669
  const result = [];
6615
6670
  for (const p of parts) {
@@ -6644,6 +6699,15 @@ function validateAndNormalizePhone(rawInput) {
6644
6699
  }
6645
6700
  return normalizeChinaPhone(rawPhone);
6646
6701
  }
6702
+ function normalizeBearerTokenInput(raw) {
6703
+ const t = raw.trim();
6704
+ if (/^bearer\s+/i.test(t)) {
6705
+ return t.replace(/^bearer\s+/i, "").trim();
6706
+ }
6707
+ return t;
6708
+ }
6709
+
6710
+ // src/commands/login/send-code.ts
6647
6711
  async function runSendLoginCode(opts) {
6648
6712
  const phone = validateAndNormalizePhone(opts.phone);
6649
6713
  const tsoApiBase = process.env.SILUZAN_TSO_API_BASE ?? DEFAULT_API_BASE;
@@ -6668,13 +6732,10 @@ async function runSendLoginCode(opts) {
6668
6732
  console.log("\u53EF\u9009\u53C2\u6570\uFF1A--name / --valid-days / --expires-at / --services");
6669
6733
  console.log("\uFF08\u9ED8\u8BA4\u521B\u5EFA 90 \u5929\u6709\u6548\u3001\u52FE\u9009 TSO + CUT \u670D\u52A1\u7684 API Key\uFF09\n");
6670
6734
  }
6671
- function normalizeBearerTokenInput(raw) {
6672
- const t = raw.trim();
6673
- if (/^bearer\s+/i.test(t)) {
6674
- return t.replace(/^bearer\s+/i, "").trim();
6675
- }
6676
- return t;
6677
- }
6735
+
6736
+ // src/commands/login/phone-flow.ts
6737
+ init_defaults();
6738
+ init_dist();
6678
6739
  async function executePhoneLoginWithVerifiedCode(phone, code, opts) {
6679
6740
  let allowedServices;
6680
6741
  try {
@@ -6698,8 +6759,6 @@ async function executePhoneLoginWithVerifiedCode(phone, code, opts) {
6698
6759
  console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n");
6699
6760
  console.log(` \u624B\u673A\u53F7 : ${phone}`);
6700
6761
  console.log(` \u9A8C\u8BC1\u7801 : ${code}`);
6701
- console.log(` SSO : ${ssoBaseUrl}`);
6702
- console.log(` CSO API : ${csoBaseUrl}`);
6703
6762
  console.log(` \u670D\u52A1\u8303\u56F4 : ${allowedServices.join(", ")}`);
6704
6763
  if (opts.expiresAt) {
6705
6764
  console.log(` \u8FC7\u671F\u65F6\u95F4 : ${opts.expiresAt}`);
@@ -6754,12 +6813,8 @@ async function executePhoneLoginWithVerifiedCode(phone, code, opts) {
6754
6813
  `
6755
6814
  );
6756
6815
  } else if (/验证码错误|验证码/.test(msg)) {
6757
- console.error(
6758
- `
6759
- \u9A8C\u8BC1\u7801\u53EF\u80FD\u5DF2\u8FC7\u671F\u6216\u8F93\u9519\u3002\u8BF7\u91CD\u65B0\u53D1\u7801\u540E\u518D\u8BD5\uFF1A
6760
- siluzan-tso send-login-code --phone ${phone}
6761
- `
6762
- );
6816
+ console.error(` \u8BF7\u68C0\u67E5\u9A8C\u8BC1\u7801\u662F\u5426\u6B63\u786E
6817
+ `);
6763
6818
  }
6764
6819
  process.exit(1);
6765
6820
  }
@@ -6773,19 +6828,28 @@ async function runPhoneLogin(opts) {
6773
6828
  console.error(` 2) siluzan-tso login --phone ${phone} --code <\u6536\u5230\u76846\u4F4D\u9A8C\u8BC1\u7801>
6774
6829
  `);
6775
6830
  console.error("\uFF08\u62C6\u6210\u4E24\u6B65\u662F\u4E3A\u4E86\u907F\u514D AI Agent \u5361\u5728\u4EA4\u4E92\u8F93\u5165\u65F6\u53CD\u590D\u91CD\u8BD5\u5BFC\u81F4\u77ED\u4FE1\u8F70\u70B8\uFF09\n");
6776
- console.error("\u6216\u5728\u7EC8\u7AEF\u6267\u884C\uFF1Asiluzan-tso login\uFF08\u65E0\u53C2\u6570\uFF09\uFF0C\u9009\u62E9\u300C\u624B\u673A\u53F7 + \u77ED\u4FE1\u9A8C\u8BC1\u7801\u300D\u7531\u672C CLI \u53D1\u7801\u3002\n");
6831
+ console.error(
6832
+ "\u6216\u5728\u7EC8\u7AEF\u6267\u884C\uFF1Asiluzan-tso login\uFF08\u65E0\u53C2\u6570\uFF09\uFF0C\u9009\u62E9\u300C\u624B\u673A\u53F7 + \u77ED\u4FE1\u9A8C\u8BC1\u7801\u300D\u7531\u672C CLI \u53D1\u7801\u3002\n"
6833
+ );
6777
6834
  process.exit(1);
6778
6835
  }
6779
6836
  await executePhoneLoginWithVerifiedCode(phone, code, opts);
6780
6837
  }
6838
+
6839
+ // src/commands/login/interactive.ts
6840
+ init_defaults();
6841
+ init_dist();
6842
+ import * as readline from "readline";
6781
6843
  async function runInteractiveJwtLogin() {
6782
6844
  const shared = readSharedConfig();
6783
6845
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
6784
6846
  const prompt = (q) => new Promise((res) => rl.question(q, (a) => res(a.trim())));
6785
6847
  try {
6786
6848
  if (shared.apiKey) {
6787
- console.log(`
6788
- \u5DF2\u4FDD\u5B58 API Key\uFF08${maskSecret(shared.apiKey)}\uFF09\u3002\u6539\u7528 JWT \u5C06\u6E05\u9664 API Key \u5E76\u4F18\u5148\u4F7F\u7528 Bearer Token\u3002`);
6849
+ console.log(
6850
+ `
6851
+ \u5DF2\u4FDD\u5B58 API Key\uFF08${maskSecret(shared.apiKey)}\uFF09\u3002\u6539\u7528 JWT \u5C06\u6E05\u9664 API Key \u5E76\u4F18\u5148\u4F7F\u7528 Bearer Token\u3002`
6852
+ );
6789
6853
  const ans = await prompt("\u662F\u5426\u7EE7\u7EED\uFF1F(y/N) ");
6790
6854
  if (ans.toLowerCase() !== "y") {
6791
6855
  console.log("\n\u5DF2\u53D6\u6D88\u3002\n");
@@ -6968,8 +7032,12 @@ async function runLogin(opts = {}) {
6968
7032
  }
6969
7033
  await runLoginMethodMenu(opts);
6970
7034
  }
7035
+
7036
+ // src/commands/login/_register.ts
6971
7037
  function register(program2) {
6972
- program2.command("send-login-code").description("\u5411\u624B\u673A\u53F7\u53D1\u9001\u4E1D\u8DEF\u8D5E\u767B\u5F55\u77ED\u4FE1\u9A8C\u8BC1\u7801\uFF08\u65E0\u4EA4\u4E92\uFF0C\u9002\u5408 Agent\uFF1A\u5148\u53D1\u7801\u518D login --phone --code\uFF09").requiredOption("--phone <phone>", "\u4E2D\u56FD\u5927\u9646\u624B\u673A\u53F7\uFF08\u53EF\u5E26 +86\uFF09").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
7038
+ program2.command("send-login-code").description(
7039
+ "\u5411\u624B\u673A\u53F7\u53D1\u9001\u4E1D\u8DEF\u8D5E\u767B\u5F55\u77ED\u4FE1\u9A8C\u8BC1\u7801\uFF08\u65E0\u4EA4\u4E92\uFF0C\u9002\u5408 Agent\uFF1A\u5148\u53D1\u7801\u518D login --phone --code\uFF09"
7040
+ ).requiredOption("--phone <phone>", "\u4E2D\u56FD\u5927\u9646\u624B\u673A\u53F7\uFF08\u53EF\u5E26 +86\uFF09").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
6973
7041
  await runSendLoginCode({ phone: opts.phone, verbose: opts.verbose });
6974
7042
  });
6975
7043
  program2.command("login").description(
@@ -6985,7 +7053,7 @@ function register(program2) {
6985
7053
  }
6986
7054
  validDays = n;
6987
7055
  }
6988
- await runLogin({
7056
+ const loginOpts = {
6989
7057
  apiKey: opts.apiKey,
6990
7058
  phone: opts.phone,
6991
7059
  code: opts.code,
@@ -6995,7 +7063,8 @@ function register(program2) {
6995
7063
  services: opts.services,
6996
7064
  verbose: opts.verbose,
6997
7065
  manual: opts.manual
6998
- });
7066
+ };
7067
+ await runLogin(loginOpts);
6999
7068
  }
7000
7069
  );
7001
7070
  }
@@ -7274,7 +7343,9 @@ auditId: ${record.auditId ?? "\u2014"}`);
7274
7343
  if (record.commit) console.log(`commit: ${record.commit}`);
7275
7344
  if (record.runId) console.log(`runId: ${record.runId}`);
7276
7345
  if (record.preSnapshotRef) {
7277
- console.log(`preSnapshotRef: ${record.preSnapshotRef}\uFF08\u53EF\u8BFB: ${snapshotOk === true ? "\u662F" : snapshotOk === false ? "\u5426" : "\u2014"}\uFF09`);
7346
+ console.log(
7347
+ `preSnapshotRef: ${record.preSnapshotRef}\uFF08\u53EF\u8BFB: ${snapshotOk === true ? "\u662F" : snapshotOk === false ? "\u5426" : "\u2014"}\uFF09`
7348
+ );
7278
7349
  }
7279
7350
  if (record.invokedCommand) console.log(`\u547D\u4EE4: ${record.invokedCommand}`);
7280
7351
  console.log(`url(\u8131\u654F): ${record.urlRedacted}
@@ -7513,7 +7584,9 @@ function printPlanForHuman(envelope) {
7513
7584
  );
7514
7585
  }
7515
7586
  if (plan.subsequentWrites.length > 10) {
7516
- console.log(` \u2026\u2026 \u8FD8\u6709 ${plan.subsequentWrites.length - 10} \u6761\uFF0C\u8BF7\u8FD0\u884C audit list --resource-key "${plan.resourceKey ?? ""}" --json \u67E5\u770B\u5B8C\u6574\u5386\u53F2`);
7587
+ console.log(
7588
+ ` \u2026\u2026 \u8FD8\u6709 ${plan.subsequentWrites.length - 10} \u6761\uFF0C\u8BF7\u8FD0\u884C audit list --resource-key "${plan.resourceKey ?? ""}" --json \u67E5\u770B\u5B8C\u6574\u5386\u53F2`
7589
+ );
7517
7590
  }
7518
7591
  }
7519
7592
  if (plan.steps.length > 0) {
@@ -7609,11 +7682,21 @@ function register3(program2) {
7609
7682
  const auditCmd = program2.command("audit").description(
7610
7683
  "\u672C\u673A HTTP \u5199\u64CD\u4F5C\u5BA1\u8BA1\uFF08POST/PUT/PATCH/DELETE\uFF09\uFF1A~/.siluzan/write-audit/tso/\uFF1B\u987B --commit\uFF1B\u652F\u6301 list/show\u3001restore-plan\uFF08\u8865\u507F\u5199\u8BA1\u5212\uFF09\u4E0E restore-apply\uFF1B\u4FDD\u7559 90 \u65E5\uFF1B"
7611
7684
  );
7612
- auditCmd.command("list").description("\u5217\u51FA\u6700\u8FD1 N \u4E2A\u5317\u4EAC\u65E5\u5386\u65E5\u7684\u5199\u8BF7\u6C42\u6458\u8981\uFF08\u6210\u529F/\u5931\u8D25\u3001\u8DEF\u5F84\u3001\u51ED\u636E\u63D0\u793A\uFF09\uFF1B--json \u542B\u8131\u654F body").option("--days <n>", "\u56DE\u6EAF\u5929\u6570\uFF081\u2013400\uFF0C\u9ED8\u8BA4 7\uFF09", "7").option("--json", "\u8F93\u51FA JSON", false).option(
7685
+ auditCmd.command("list").description(
7686
+ "\u5217\u51FA\u6700\u8FD1 N \u4E2A\u5317\u4EAC\u65E5\u5386\u65E5\u7684\u5199\u8BF7\u6C42\u6458\u8981\uFF08\u6210\u529F/\u5931\u8D25\u3001\u8DEF\u5F84\u3001\u51ED\u636E\u63D0\u793A\uFF09\uFF1B--json \u542B\u8131\u654F body"
7687
+ ).option("--days <n>", "\u56DE\u6EAF\u5929\u6570\uFF081\u2013400\uFF0C\u9ED8\u8BA4 7\uFF09", "7").option("--json", "\u8F93\u51FA JSON", false).option(
7613
7688
  "--json-out <path>",
7614
7689
  "\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF08\u4E0E --json \u4E92\u65A5\uFF09\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
7615
7690
  void 0
7616
- ).option("--failures-only", "\u4EC5\u5931\u8D25\u8BB0\u5F55", false).option("--match <sub>", "\u5B50\u4E32\u5339\u914D commit/pathname/cmd/url/auditId/runId\uFF08\u626B JSONL\uFF09", void 0).option("--method <verb>", "HTTP \u65B9\u6CD5\u8FC7\u6EE4\uFF0C\u5982 PUT\u3001POST", void 0).option("--outcome <success|failure>", "\u6309\u7ED3\u679C\u8FC7\u6EE4", void 0).option("--run-id <id>", "\u6309 runId \u5B50\u4E32\u8FC7\u6EE4\uFF08\u73AF\u5883\u53D8\u91CF SILUZAN_AUDIT_RUN_ID \u5199\u5165\u7684\u8BB0\u5F55\uFF09", void 0).option("--since-ts <iso>", "\u4EC5 ts \u4E0D\u65E9\u4E8E\u8BE5 ISO \u65F6\u95F4\uFF08\u5728 --days \u7A97\u53E3\u5185\u518D\u7B5B\uFF09", void 0).option(
7691
+ ).option("--failures-only", "\u4EC5\u5931\u8D25\u8BB0\u5F55", false).option(
7692
+ "--match <sub>",
7693
+ "\u5B50\u4E32\u5339\u914D commit/pathname/cmd/url/auditId/runId\uFF08\u626B JSONL\uFF09",
7694
+ void 0
7695
+ ).option("--method <verb>", "HTTP \u65B9\u6CD5\u8FC7\u6EE4\uFF0C\u5982 PUT\u3001POST", void 0).option("--outcome <success|failure>", "\u6309\u7ED3\u679C\u8FC7\u6EE4", void 0).option(
7696
+ "--run-id <id>",
7697
+ "\u6309 runId \u5B50\u4E32\u8FC7\u6EE4\uFF08\u73AF\u5883\u53D8\u91CF SILUZAN_AUDIT_RUN_ID \u5199\u5165\u7684\u8BB0\u5F55\uFF09",
7698
+ void 0
7699
+ ).option("--since-ts <iso>", "\u4EC5 ts \u4E0D\u65E9\u4E8E\u8BE5 ISO \u65F6\u95F4\uFF08\u5728 --days \u7A97\u53E3\u5185\u518D\u7B5B\uFF09", void 0).option(
7617
7700
  "--resource-key <key>",
7618
7701
  "\u7CBE\u786E\u5339\u914D resourceKey\uFF08host+pathname\uFF09\uFF0C\u7528\u4E8E restore-plan \u914D\u5957\u8FFD\u6EAF\u540C\u8D44\u6E90\u5168\u91CF\u5386\u53F2",
7619
7702
  void 0
@@ -7956,7 +8039,14 @@ function register5(program2) {
7956
8039
 
7957
8040
  // src/commands/list-accounts/_shared.ts
7958
8041
  init_auth();
7959
- var VALID_MEDIA_TYPES = ["Google", "TikTok", "Yandex", "MetaAd", "BingV2", "Kwai"];
8042
+ var VALID_MEDIA_TYPES = [
8043
+ "Google",
8044
+ "TikTok",
8045
+ "Yandex",
8046
+ "MetaAd",
8047
+ "BingV2",
8048
+ "Kwai"
8049
+ ];
7960
8050
  var PLATFORM_CONFIG = {
7961
8051
  Google: {
7962
8052
  path: "/query/media-account/",
@@ -8938,11 +9028,14 @@ function register8(program2) {
8938
9028
  );
8939
9029
  }
8940
9030
 
8941
- // src/commands/balance-scan.ts
9031
+ // src/commands/balance-scan/run.ts
8942
9032
  init_auth();
8943
9033
  init_cli_json_snapshot();
8944
9034
  init_balance();
8945
9035
  init_cli_table();
9036
+
9037
+ // src/commands/balance-scan/list-fetch.ts
9038
+ init_auth();
8946
9039
  var SCAN_PLATFORM_CONFIG = {
8947
9040
  Google: {
8948
9041
  path: "/query/media-account/",
@@ -9081,6 +9174,8 @@ async function fetchAllAccountPages(media, pageSize, maxPages, config, verbose)
9081
9174
  }
9082
9175
  return { items: allItems, total };
9083
9176
  }
9177
+
9178
+ // src/commands/balance-scan/run.ts
9084
9179
  async function runBalanceScan(opts) {
9085
9180
  let config = loadConfig(opts.token);
9086
9181
  if (opts.refreshDp) {
@@ -9235,7 +9330,6 @@ async function runBalanceScan(opts) {
9235
9330
  });
9236
9331
  const meta = {
9237
9332
  media,
9238
- /** 取数策略:list = 全量翻清单后阈值过滤,subset = -a 指定 ID 跳过翻页全部展示 */
9239
9333
  source: isSubset ? "subset" : "list",
9240
9334
  scannedAccounts: allItems.length,
9241
9335
  validAccounts: validIds.length,
@@ -9317,6 +9411,8 @@ ${media} \u8D26\u6237\u4F59\u989D\u626B\u63CF\u5B8C\u6210\uFF1A\u5171\u626B\u63C
9317
9411
  `
9318
9412
  );
9319
9413
  }
9414
+
9415
+ // src/commands/balance-scan/_register.ts
9320
9416
  function register9(program2) {
9321
9417
  program2.command("balance-scan").description(
9322
9418
  "\u4E00\u952E\u626B\u63CF\u67D0\u5A92\u4F53\u4E0B\u6240\u6709\u8D26\u6237\u7684\u4F59\u989D\uFF0C\u7B5B\u51FA\u7EED\u822A\u5929\u6570\u4E0D\u8DB3\u7684\u8D26\u6237\u3002\u66FF\u4EE3\u5FAA\u73AF\u8C03\u7528 balance \u7684\u4F20\u7EDF\u505A\u6CD5\uFF0C\u5178\u578B\u573A\u666F\uFF1A\u300C\u5E2E\u6211\u627E\u51FA 117 \u4E2A Bing \u8D26\u6237\u91CC\u4F59\u989D\u4E0D\u8DB3 7 \u5929\u7684\u300D\u3002"
@@ -9364,7 +9460,7 @@ function register9(program2) {
9364
9460
  }
9365
9461
 
9366
9462
  // src/index.ts
9367
- init_accounts_digest();
9463
+ init_accounts_digest2();
9368
9464
 
9369
9465
  // src/commands/stats.ts
9370
9466
  init_auth();
@@ -9652,7 +9748,14 @@ function register12(program2) {
9652
9748
  }
9653
9749
 
9654
9750
  // src/commands/report/_shared.ts
9655
- var VALID_MEDIA_TYPES5 = ["Google", "TikTok", "Yandex", "MetaAd", "BingV2", "Kwai"];
9751
+ var VALID_MEDIA_TYPES5 = [
9752
+ "Google",
9753
+ "TikTok",
9754
+ "Yandex",
9755
+ "MetaAd",
9756
+ "BingV2",
9757
+ "Kwai"
9758
+ ];
9656
9759
  var REPORT_PUSH_MEDIA = /* @__PURE__ */ new Set(["Google", "TikTok"]);
9657
9760
  function assertReportPushMedia(media) {
9658
9761
  if (!REPORT_PUSH_MEDIA.has(media)) {
@@ -10349,7 +10452,7 @@ async function runReportPushReceiveEmails(opts) {
10349
10452
  // src/commands/report/register-commander-types.ts
10350
10453
  var splitCsv = (v) => v.split(",").map((s) => s.trim()).filter(Boolean);
10351
10454
 
10352
- // src/commands/report-tiktok-analysis.ts
10455
+ // src/commands/report-tiktok-analysis/_shared.ts
10353
10456
  init_auth();
10354
10457
  init_version();
10355
10458
  var TIKTOK_TAKE_DEFAULT = 100;
@@ -10388,6 +10491,14 @@ function reportingUrl(config, accountId, segment, query) {
10388
10491
  const q = query ? query.startsWith("?") ? query : `?${query}` : "";
10389
10492
  return `${config.apiBaseUrl}/reporting/media-account/TikTok/${accountId}/${segment}${q}`;
10390
10493
  }
10494
+ var AUDIENCE_DIMENSIONS = [
10495
+ "gender",
10496
+ "age",
10497
+ "interest_category",
10498
+ "country_code",
10499
+ "platform",
10500
+ "language"
10501
+ ];
10391
10502
  async function emitTiktokSnapshot(opts, section, accountId, startDate, endDate, data) {
10392
10503
  const summary = await writeReportAnalysisSnapshot({
10393
10504
  snapshotDir: opts.jsonOut,
@@ -10402,6 +10513,10 @@ async function emitTiktokSnapshot(opts, section, accountId, startDate, endDate,
10402
10513
  async function fetchTikTokJson(config, url, verbose) {
10403
10514
  return apiFetch2(url, config, {}, verbose);
10404
10515
  }
10516
+
10517
+ // src/commands/report-tiktok-analysis/run.ts
10518
+ init_auth();
10519
+ init_version();
10405
10520
  async function runReportTikTokOverview(opts) {
10406
10521
  const id = assertTikTokAccountId(opts.account);
10407
10522
  const { startDate, endDate } = resolveDateRange(opts.start, opts.end);
@@ -10525,14 +10640,6 @@ async function runReportTikTokAds(opts) {
10525
10640
  process.exit(1);
10526
10641
  }
10527
10642
  }
10528
- var AUDIENCE_DIMENSIONS = [
10529
- "gender",
10530
- "age",
10531
- "interest_category",
10532
- "country_code",
10533
- "platform",
10534
- "language"
10535
- ];
10536
10643
  async function runReportTikTokAudience(opts) {
10537
10644
  const id = assertTikTokAccountId(opts.account);
10538
10645
  const { startDate, endDate } = resolveDateRange(opts.start, opts.end);
@@ -10710,6 +10817,8 @@ async function runReportTikTokInterestList(opts) {
10710
10817
  process.exit(1);
10711
10818
  }
10712
10819
  }
10820
+
10821
+ // src/commands/report-tiktok-analysis/_register.ts
10713
10822
  function addDateAndFetchOptions(c) {
10714
10823
  return c.requiredOption("-a, --account <id>", "TikTok \u5E7F\u544A\u4E3B mediaCustomerId\uFF08\u6570\u5B57\uFF09").option("--start <date>", "\u5F00\u59CB\u65E5\u671F YYYY-MM-DD\uFF08\u4E0E --end \u540C\u4F20\u6216\u540C\u7701\u7565\uFF09").option("--end <date>", "\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option("--take <n>", "\u6D88\u8017/\u6761\u6570\u4E0A\u9650\uFF08\u9ED8\u8BA4 100\uFF0C\u4E0E\u524D\u7AEF take \u4E00\u81F4\uFF09", (v) => parseInt(v, 10)).option("-t, --token <token>", "Auth Token").option("--json", "JSON \u683C\u5F0F\u8F93\u51FA", false).option(
10715
10824
  "--json-out <dir>",
@@ -10748,7 +10857,9 @@ function registerReportTiktokCommands(reportCmd) {
10748
10857
  }
10749
10858
  await runReportTikTokAudience({ ...opts, dimension: d });
10750
10859
  });
10751
- reportCmd.command("tiktok-audience-merged").description(`${desc} \u2014 \u5408\u5E76 gender + age + interest_category \u4E09\u6B21 AudienceReport\uFF08\u9ED8\u8BA4 stdout \u4E3A JSON\uFF09`).requiredOption("-a, --account <id>", "TikTok mediaCustomerId").option("--start <date>", "\u5F00\u59CB\u65E5\u671F").option("--end <date>", "\u7ED3\u675F\u65E5\u671F").option("--take <n>", "\u6761\u6570\u4E0A\u9650\uFF08\u9ED8\u8BA4 100\uFF09", (v) => parseInt(v, 10)).option("-t, --token <token>", "Auth Token").option("--json", "\u4E0E --json-out \u4E92\u65A5\uFF1B\u663E\u5F0F\u58F0\u660E stdout JSON\uFF08\u9ED8\u8BA4\u5DF2\u662F JSON\uFF09", false).option(
10860
+ reportCmd.command("tiktok-audience-merged").description(
10861
+ `${desc} \u2014 \u5408\u5E76 gender + age + interest_category \u4E09\u6B21 AudienceReport\uFF08\u9ED8\u8BA4 stdout \u4E3A JSON\uFF09`
10862
+ ).requiredOption("-a, --account <id>", "TikTok mediaCustomerId").option("--start <date>", "\u5F00\u59CB\u65E5\u671F").option("--end <date>", "\u7ED3\u675F\u65E5\u671F").option("--take <n>", "\u6761\u6570\u4E0A\u9650\uFF08\u9ED8\u8BA4 100\uFF09", (v) => parseInt(v, 10)).option("-t, --token <token>", "Auth Token").option("--json", "\u4E0E --json-out \u4E92\u65A5\uFF1B\u663E\u5F0F\u58F0\u660E stdout JSON\uFF08\u9ED8\u8BA4\u5DF2\u662F JSON\uFF09", false).option(
10752
10863
  "--json-out <dir>",
10753
10864
  "\u5C06\u5408\u5E76 JSON \u5199\u5165\u76EE\u5F55\uFF08\u6587\u4EF6\u540D\u5E26 accountId \u540E\u7F00\uFF09\u5E76\u66F4\u65B0 report-manifest-<accountId>.json\uFF1Bstdout \u4EC5\u4E00\u884C\u6458\u8981 JSON"
10754
10865
  ).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
@@ -10757,9 +10868,11 @@ function registerReportTiktokCommands(reportCmd) {
10757
10868
  reportCmd.command("tiktok-areacode").description("TikTok \u5730\u533A\u4EE3\u7801\u679A\u4E3E\uFF08\u4E3B\u5E73\u53F0 query/media-account/tiktok/TikTokAreacode/Read\uFF09").option("-t, --token <token>", "Auth Token").option("--json", "JSON \u683C\u5F0F\u8F93\u51FA", false).option(
10758
10869
  "--json-out <dir>",
10759
10870
  "\u5C06 JSON \u5199\u5165\u76EE\u5F55\uFF08\u6587\u4EF6\u540D\u5E26 accountId \u540E\u7F00\uFF09\u5E76\u66F4\u65B0 report-manifest-<accountId>.json\uFF08\u4E0E --json \u4E92\u65A5\uFF09\uFF1Bstdout \u4EC5\u4E00\u884C\u6458\u8981 JSON"
10760
- ).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
10761
- await runReportTikTokAreacode(opts);
10762
- });
10871
+ ).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
10872
+ async (opts) => {
10873
+ await runReportTikTokAreacode(opts);
10874
+ }
10875
+ );
10763
10876
  reportCmd.command("tiktok-interest-list").description(
10764
10877
  "TikTok \u5174\u8DA3\u7C7B\u76EE\uFF08tiktokApiUrl GetInterestList\uFF0C\u89E3\u6790 country_code/interest \u62A5\u8868\u65F6\u5E38\u7528\uFF09"
10765
10878
  ).requiredOption("-a, --account <id>", "TikTok mediaCustomerId").option("-t, --token <token>", "Auth Token").option("--json", "JSON \u683C\u5F0F\u8F93\u51FA", false).option(
@@ -10772,7 +10885,7 @@ function registerReportTiktokCommands(reportCmd) {
10772
10885
  );
10773
10886
  }
10774
10887
 
10775
- // src/commands/report-bing-analysis.ts
10888
+ // src/commands/report-bing-analysis/_shared.ts
10776
10889
  init_auth();
10777
10890
  init_version();
10778
10891
  var BING_KEYWORD_LIMIT_DEFAULT = 100;
@@ -10876,6 +10989,9 @@ async function emitBingSnapshot(opts, section, accountId, startDate, endDate, da
10876
10989
  async function fetchBingJson(config, url, verbose) {
10877
10990
  return apiFetch2(url, config, {}, verbose);
10878
10991
  }
10992
+
10993
+ // src/commands/report-bing-analysis/run.ts
10994
+ init_auth();
10879
10995
  async function runReportBingOverview(opts) {
10880
10996
  const id = assertBingAccountId(opts.account);
10881
10997
  const { startDate, endDate } = resolveBingDateRange(opts.start, opts.end);
@@ -11190,6 +11306,8 @@ async function runReportBingSearchTerms(opts) {
11190
11306
  process.exit(1);
11191
11307
  }
11192
11308
  }
11309
+
11310
+ // src/commands/report-bing-analysis/_register.ts
11193
11311
  function addBingDateOptions(c) {
11194
11312
  return c.requiredOption(
11195
11313
  "-a, --account <id>",
@@ -11331,7 +11449,9 @@ function register13(program2) {
11331
11449
  verbose: opts.verbose
11332
11450
  });
11333
11451
  });
11334
- pushCmd.command("create").description("\u65B0\u5EFA\u63A8\u9001\u914D\u7F6E\uFF08POST /command/report-push/settings/{\u5A92\u4F53}\uFF0C\u4E0E\u7F51\u9875\u300C\u6DFB\u52A0\u63A8\u9001\u300D\u4E00\u81F4\uFF09").requiredOption("-m, --media <type>", "\u5A92\u4F53\uFF1AGoogle | TikTok").requiredOption("--name <name>", "\u63A8\u9001\u540D\u79F0\uFF08\u5BF9\u5E94 body.Name\uFF09").requiredOption(
11452
+ pushCmd.command("create").description(
11453
+ "\u65B0\u5EFA\u63A8\u9001\u914D\u7F6E\uFF08POST /command/report-push/settings/{\u5A92\u4F53}\uFF0C\u4E0E\u7F51\u9875\u300C\u6DFB\u52A0\u63A8\u9001\u300D\u4E00\u81F4\uFF09"
11454
+ ).requiredOption("-m, --media <type>", "\u5A92\u4F53\uFF1AGoogle | TikTok").requiredOption("--name <name>", "\u63A8\u9001\u540D\u79F0\uFF08\u5BF9\u5E94 body.Name\uFF09").requiredOption(
11335
11455
  "--media-accounts <ids>",
11336
11456
  "\u5E7F\u544A\u8D26\u6237 entityId\uFF0C\u9017\u53F7\u5206\u9694\uFF08list-accounts --json \u2192 ma.entityId\uFF09",
11337
11457
  splitCsv
@@ -11619,73 +11739,8 @@ function register14(program2) {
11619
11739
  });
11620
11740
  }
11621
11741
 
11622
- // src/commands/invoice.ts
11742
+ // src/commands/invoice/_shared.ts
11623
11743
  init_auth();
11624
- init_cli_json_snapshot();
11625
- init_cli_table();
11626
- function formatDate(d) {
11627
- return d.toISOString().slice(0, 10);
11628
- }
11629
- async function runInvoiceList(opts) {
11630
- const config = await ensureDataPermission(loadConfig(opts.token));
11631
- const endDate = opts.endDate ?? formatDate(/* @__PURE__ */ new Date());
11632
- const startDefault = /* @__PURE__ */ new Date();
11633
- startDefault.setMonth(startDefault.getMonth() - 3);
11634
- const startDate = opts.startDate ?? formatDate(startDefault);
11635
- const params = new URLSearchParams();
11636
- params.set("pageIndex", String(opts.page ?? 1));
11637
- params.set("pageSize", String(opts.pageSize ?? 20));
11638
- params.set("searchValue", opts.keyword ?? "");
11639
- params.set("startDate", startDate);
11640
- params.set("endDate", endDate);
11641
- const url = `${config.apiBaseUrl}/invoice-request?${params}`;
11642
- let data;
11643
- try {
11644
- data = await apiFetch2(url, config, {}, opts.verbose);
11645
- } catch (err) {
11646
- console.error(`
11647
- \u274C \u67E5\u8BE2\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
11648
- `);
11649
- process.exit(1);
11650
- }
11651
- const items = data.results ?? [];
11652
- const total = data.totalResultCount ?? 0;
11653
- const page = opts.page ?? 1;
11654
- const pageSize = opts.pageSize ?? 20;
11655
- const invListPayload = wrapListJson({ page, pageSize, total, items });
11656
- if (await emitCliJsonOrSnapshot(opts, {
11657
- section: "invoice-list",
11658
- commandLabel: "invoice list",
11659
- payload: invListPayload
11660
- })) {
11661
- return;
11662
- }
11663
- console.log(
11664
- `
11665
- \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
11666
- `
11667
- );
11668
- if (items.length === 0) {
11669
- console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
11670
- return;
11671
- }
11672
- const cols = [
11673
- { key: "requestNo", header: "\u7533\u8BF7\u5355\u53F7" },
11674
- { key: "companyName", header: "\u4F01\u4E1A" },
11675
- { key: "billType", header: "\u7C7B\u578B" },
11676
- { key: "invoiceStatus", header: "\u72B6\u6001" },
11677
- { key: "applyTime", header: "\u7533\u8BF7\u65F6\u95F4" }
11678
- ];
11679
- const rows = items.map((item) => ({
11680
- requestNo: item.requestNo ?? "",
11681
- companyName: item.companyName ?? "",
11682
- billType: item.billType ?? "",
11683
- invoiceStatus: item.invoiceStatus ?? "",
11684
- applyTime: item.applyTime ?? ""
11685
- }));
11686
- printCliTable(rows, cols);
11687
- console.log();
11688
- }
11689
11744
  var PI_LATIN_TEXT_RE = /^[A-Za-z][\x20-\x7E\u00B7\u2018-\u2019\u201C-\u201D\u3000-\u303F\uFF00-\uFF65\uFF70-\uFF9F]*$/;
11690
11745
  function isValidEmail(s) {
11691
11746
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s.trim());
@@ -11767,6 +11822,79 @@ function assertInvoiceTypeAllowedForCurrencies(invoiceType, currencyCodes, media
11767
11822
  process.exit(1);
11768
11823
  }
11769
11824
  }
11825
+
11826
+ // src/commands/invoice/list.ts
11827
+ init_auth();
11828
+ init_cli_json_snapshot();
11829
+ init_cli_table();
11830
+ function formatDate(d) {
11831
+ return d.toISOString().slice(0, 10);
11832
+ }
11833
+ async function runInvoiceList(opts) {
11834
+ const config = await ensureDataPermission(loadConfig(opts.token));
11835
+ const endDate = opts.endDate ?? formatDate(/* @__PURE__ */ new Date());
11836
+ const startDefault = /* @__PURE__ */ new Date();
11837
+ startDefault.setMonth(startDefault.getMonth() - 3);
11838
+ const startDate = opts.startDate ?? formatDate(startDefault);
11839
+ const params = new URLSearchParams();
11840
+ params.set("pageIndex", String(opts.page ?? 1));
11841
+ params.set("pageSize", String(opts.pageSize ?? 20));
11842
+ params.set("searchValue", opts.keyword ?? "");
11843
+ params.set("startDate", startDate);
11844
+ params.set("endDate", endDate);
11845
+ const url = `${config.apiBaseUrl}/invoice-request?${params}`;
11846
+ let data;
11847
+ try {
11848
+ data = await apiFetch2(url, config, {}, opts.verbose);
11849
+ } catch (err) {
11850
+ console.error(`
11851
+ \u274C \u67E5\u8BE2\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
11852
+ `);
11853
+ process.exit(1);
11854
+ }
11855
+ const items = data.results ?? [];
11856
+ const total = data.totalResultCount ?? 0;
11857
+ const page = opts.page ?? 1;
11858
+ const pageSize = opts.pageSize ?? 20;
11859
+ const invListPayload = wrapListJson({ page, pageSize, total, items });
11860
+ if (await emitCliJsonOrSnapshot(opts, {
11861
+ section: "invoice-list",
11862
+ commandLabel: "invoice list",
11863
+ payload: invListPayload
11864
+ })) {
11865
+ return;
11866
+ }
11867
+ console.log(
11868
+ `
11869
+ \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
11870
+ `
11871
+ );
11872
+ if (items.length === 0) {
11873
+ console.log(" \u6682\u65E0\u6570\u636E\u3002\n");
11874
+ return;
11875
+ }
11876
+ const cols = [
11877
+ { key: "requestNo", header: "\u7533\u8BF7\u5355\u53F7" },
11878
+ { key: "companyName", header: "\u4F01\u4E1A" },
11879
+ { key: "billType", header: "\u7C7B\u578B" },
11880
+ { key: "invoiceStatus", header: "\u72B6\u6001" },
11881
+ { key: "applyTime", header: "\u7533\u8BF7\u65F6\u95F4" }
11882
+ ];
11883
+ const rows = items.map((item) => ({
11884
+ requestNo: item.requestNo ?? "",
11885
+ companyName: item.companyName ?? "",
11886
+ billType: item.billType ?? "",
11887
+ invoiceStatus: item.invoiceStatus ?? "",
11888
+ applyTime: item.applyTime ?? ""
11889
+ }));
11890
+ printCliTable(rows, cols);
11891
+ console.log();
11892
+ }
11893
+
11894
+ // src/commands/invoice/billable.ts
11895
+ init_auth();
11896
+ init_cli_json_snapshot();
11897
+ init_cli_table();
11770
11898
  async function runInvoiceBillable(opts) {
11771
11899
  const config = await ensureDataPermission(loadConfig(opts.token));
11772
11900
  const params = new URLSearchParams();
@@ -11848,6 +11976,10 @@ ${label}\uFF08\u7B2C ${page}/${Math.max(1, Math.ceil(total / pageSize))} \u9875\
11848
11976
  '\n \u5F00\u7968\u65F6\u8BF7\u628A\u6240\u9009\u884C\u7684 entityId \u4F20\u7ED9\uFF1Asiluzan-tso invoice apply --bill-ids "<entityId>" ...\n'
11849
11977
  );
11850
11978
  }
11979
+
11980
+ // src/commands/invoice/apply.ts
11981
+ init_auth();
11982
+ init_cli_json_snapshot();
11851
11983
  async function runInvoiceApply(opts) {
11852
11984
  const config = await ensureDataPermission(loadConfig(opts.token));
11853
11985
  const validInvoiceTypes = ["PI", "VATI", "VATSI"];
@@ -12012,6 +12144,8 @@ async function runInvoiceApply(opts) {
12012
12144
  \u2705 \u5F00\u7968\u7533\u8BF7\u5DF2\u63D0\u4EA4\uFF08${opts.billIds.length} \u6761\u8BA2\u5355\uFF09
12013
12145
  `);
12014
12146
  }
12147
+
12148
+ // src/commands/invoice/_register.ts
12015
12149
  function register15(program2) {
12016
12150
  const invoiceCmd = program2.command("invoice").description("\u5F00\u7968\u8BB0\u5F55\u4E0E\u5F00\u7968\u7533\u8BF7\uFF0C\u4E0D\u652F\u6301\u8D26\u6237\u6FC0\u6D3B\u5145\u503C\u8BA2\u5355\u7684\u5F00\u7968\uFF0C\u5982\u9700\u5F00\u7968\u8BF7\u8054\u7CFB\u7EBF\u4E0B\u8FD0\u8425");
12017
12151
  invoiceCmd.command("list").description("\u67E5\u8BE2\u5F00\u7968\u7533\u8BF7\u8BB0\u5F55").option("-k, --keyword <text>", "\u53D1\u7968\u53F7\u6216\u5173\u952E\u5B57").option("--start <date>", "\u5F00\u59CB\u65E5\u671F YYYY-MM-DD").option("--end <date>", "\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option("-p, --page <n>", "\u9875\u7801", parseInt).option("--page-size <n>", "\u6BCF\u9875\u6570\u91CF", parseInt).option("-t, --token <token>", "Auth Token").option("--json", "JSON \u683C\u5F0F\u8F93\u51FA", false).option(
@@ -12057,7 +12191,10 @@ function register15(program2) {
12057
12191
  ).requiredOption("--bill-ids <ids>", "\u8981\u5F00\u7968\u7684\u8BA2\u5355 entityId\uFF0C\u9017\u53F7\u5206\u9694").requiredOption("--bill-type <type>", "\u8D26\u5355\u6765\u6E90\u7C7B\u578B\uFF1AAmountAccount | WalletRecharge").requiredOption(
12058
12192
  "--invoice-type <type>",
12059
12193
  "\u53D1\u7968\u7C7B\u578B\uFF1API\uFF08\u5F62\u5F0F\u53D1\u7968\uFF09| VATI\uFF08\u589E\u503C\u7A0E\u666E\u7968\uFF09| VATSI\uFF08\u589E\u503C\u7A0E\u4E13\u7968\uFF09"
12060
- ).requiredOption("--recipient-name <name>", "\u8054\u7CFB\u4EBA/\u6536\u4EF6\u4EBA\u59D3\u540D\uFF08\u5199\u5165 RecipientInfomation\uFF09").requiredOption("--recipient-phone <phone>", "\u8054\u7CFB\u4EBA/\u6536\u4EF6\u4EBA\u624B\u673A\u53F7").option("--recipient-email <email>", "\u63A8\u9001\u90AE\u7BB1\uFF08\u9009\u586B\uFF1B\u82E5\u586B\u5199\u987B\u5408\u6CD5\uFF09").option("--company-name-en <name>", "\u516C\u53F8\u82F1\u6587\u540D\u79F0\uFF08PI \u5FC5\u586B\uFF09").option("--registered-address-en <addr>", "\u82F1\u6587\u5355\u4F4D\u5730\u5740\uFF08PI \u5FC5\u586B\uFF09").option("--company-name <name>", "\u516C\u53F8\u4E2D\u6587\u540D\u79F0\uFF08\u589E\u503C\u7A0E\u7968\u5FC5\u586B\uFF09").option("--tax-id <id>", "\u4F01\u4E1A\u7A0E\u53F7\uFF08\u589E\u503C\u7A0E\u7968\u5FC5\u586B\uFF09").option("--title <title>", "\u53D1\u7968\u62AC\u5934\uFF08\u589E\u503C\u7A0E\u7968\u5FC5\u586B\uFF09").option("--company-phone <phone>", "\u516C\u53F8\u5EA7\u673A/\u7535\u8BDD\uFF08\u589E\u503C\u7A0E\u7968\u5FC5\u586B\uFF0C\u5BF9\u5E94 InvoiceInfomation.Phone\uFF09").option("--media <type>", "\u5A92\u4F53\u7C7B\u578B\uFF08\u6838\u5BF9\u5E01\u79CD\u65F6\u4F20\u7ED9\u53EF\u5F00\u7968\u67E5\u8BE2\uFF0C\u4E0E billable \u4E00\u81F4\uFF09").option(
12194
+ ).requiredOption("--recipient-name <name>", "\u8054\u7CFB\u4EBA/\u6536\u4EF6\u4EBA\u59D3\u540D\uFF08\u5199\u5165 RecipientInfomation\uFF09").requiredOption("--recipient-phone <phone>", "\u8054\u7CFB\u4EBA/\u6536\u4EF6\u4EBA\u624B\u673A\u53F7").option("--recipient-email <email>", "\u63A8\u9001\u90AE\u7BB1\uFF08\u9009\u586B\uFF1B\u82E5\u586B\u5199\u987B\u5408\u6CD5\uFF09").option("--company-name-en <name>", "\u516C\u53F8\u82F1\u6587\u540D\u79F0\uFF08PI \u5FC5\u586B\uFF09").option("--registered-address-en <addr>", "\u82F1\u6587\u5355\u4F4D\u5730\u5740\uFF08PI \u5FC5\u586B\uFF09").option("--company-name <name>", "\u516C\u53F8\u4E2D\u6587\u540D\u79F0\uFF08\u589E\u503C\u7A0E\u7968\u5FC5\u586B\uFF09").option("--tax-id <id>", "\u4F01\u4E1A\u7A0E\u53F7\uFF08\u589E\u503C\u7A0E\u7968\u5FC5\u586B\uFF09").option("--title <title>", "\u53D1\u7968\u62AC\u5934\uFF08\u589E\u503C\u7A0E\u7968\u5FC5\u586B\uFF09").option(
12195
+ "--company-phone <phone>",
12196
+ "\u516C\u53F8\u5EA7\u673A/\u7535\u8BDD\uFF08\u589E\u503C\u7A0E\u7968\u5FC5\u586B\uFF0C\u5BF9\u5E94 InvoiceInfomation.Phone\uFF09"
12197
+ ).option("--media <type>", "\u5A92\u4F53\u7C7B\u578B\uFF08\u6838\u5BF9\u5E01\u79CD\u65F6\u4F20\u7ED9\u53EF\u5F00\u7968\u67E5\u8BE2\uFF0C\u4E0E billable \u4E00\u81F4\uFF09").option(
12061
12198
  "--skip-currency-check",
12062
12199
  "\u8DF3\u8FC7\u5E01\u79CD\u4E0E\u53D1\u7968\u7C7B\u578B\u6821\u9A8C\uFF08\u65E0\u6CD5\u4ECE\u53EF\u5F00\u7968\u5217\u8868\u89E3\u6790 entityId \u65F6\u4F7F\u7528\uFF0C\u9700\u81EA\u884C\u4FDD\u8BC1\u4E0E Web \u89C4\u5219\u4E00\u81F4\uFF09",
12063
12200
  false
@@ -12352,10 +12489,8 @@ function register16(program2) {
12352
12489
  });
12353
12490
  }
12354
12491
 
12355
- // src/commands/optimize.ts
12492
+ // src/commands/optimize/_shared.ts
12356
12493
  init_auth();
12357
- init_cli_json_snapshot();
12358
- init_cli_table();
12359
12494
  function formatOptimizeListDate(d) {
12360
12495
  return d.includes("+") ? d : `${d}+08:00`;
12361
12496
  }
@@ -12373,6 +12508,11 @@ async function fetchOptimizeListPage(config, opts, verbose) {
12373
12508
  totalResultCount: data.totalResultCount ?? 0
12374
12509
  };
12375
12510
  }
12511
+
12512
+ // src/commands/optimize/list.ts
12513
+ init_auth();
12514
+ init_cli_json_snapshot();
12515
+ init_cli_table();
12376
12516
  async function runOptimizeList(opts) {
12377
12517
  const config = loadConfig(opts.token);
12378
12518
  const pageSize = opts.pageSize ?? 20;
@@ -12502,15 +12642,18 @@ AI\u5E7F\u544A\u4F18\u5316\uFF08\u7B2C ${page}/${Math.max(1, Math.ceil(total / p
12502
12642
  process.exit(1);
12503
12643
  }
12504
12644
  }
12645
+
12646
+ // src/commands/optimize/records.ts
12647
+ init_auth();
12648
+ init_cli_json_snapshot();
12505
12649
  async function runOptimizeRecords(opts) {
12506
12650
  const config = loadConfig(opts.token);
12507
- const formatDate2 = (d) => d.includes("+") ? d : `${d}+08:00`;
12508
12651
  const params = new URLSearchParams();
12509
12652
  params.set("pageIndex", String(opts.page ?? 1));
12510
12653
  params.set("pageSize", String(opts.pageSize ?? 20));
12511
12654
  if (opts.account) params.set("mediaCustomerId", opts.account);
12512
- if (opts.startDate) params.set("startDate", formatDate2(opts.startDate));
12513
- if (opts.endDate) params.set("endDate", formatDate2(opts.endDate));
12655
+ if (opts.startDate) params.set("startDate", formatOptimizeListDate(opts.startDate));
12656
+ if (opts.endDate) params.set("endDate", formatOptimizeListDate(opts.endDate));
12514
12657
  const url = `${config.apiBaseUrl}/Smart-Ads-Optimize/v2?${params}`;
12515
12658
  let data;
12516
12659
  try {
@@ -12556,6 +12699,9 @@ async function runOptimizeRecords(opts) {
12556
12699
  }
12557
12700
  console.log();
12558
12701
  }
12702
+
12703
+ // src/commands/optimize/get.ts
12704
+ init_auth();
12559
12705
  async function runOptimizeGet(opts) {
12560
12706
  const config = await ensureDataPermission(loadConfig(opts.token));
12561
12707
  const url = `${config.apiBaseUrl}/Smart-Ads-Optimize/v2/${encodeURIComponent(opts.id)}`;
@@ -12572,6 +12718,10 @@ async function runOptimizeGet(opts) {
12572
12718
  }
12573
12719
  console.log(JSON.stringify(data, null, 2));
12574
12720
  }
12721
+
12722
+ // src/commands/optimize/children.ts
12723
+ init_auth();
12724
+ init_cli_json_snapshot();
12575
12725
  async function runOptimizeChildren(opts) {
12576
12726
  const config = loadConfig(opts.token);
12577
12727
  const params = new URLSearchParams();
@@ -12619,6 +12769,8 @@ async function runOptimizeChildren(opts) {
12619
12769
  }
12620
12770
  console.log();
12621
12771
  }
12772
+
12773
+ // src/commands/optimize/_register.ts
12622
12774
  function register17(program2) {
12623
12775
  const optimizeCmd = program2.command("optimize").description("AI \u5E7F\u544A\u4F18\u5316\uFF08Google\uFF09");
12624
12776
  optimizeCmd.command("list").description("\u67E5\u8BE2\u8D26\u6237\u7EA7\u4F18\u5316\u4E3B\u5217\u8868\uFF08\u5BF9\u5E94\u9875\u9762 /advertising/intelligentOptimization\uFF09").option("-a, --account <id>", "\u8D26\u6237 mediaCustomerId\uFF08\u7559\u7A7A\u67E5\u5168\u90E8\uFF09").option(
@@ -12681,15 +12833,13 @@ function register17(program2) {
12681
12833
  });
12682
12834
  }
12683
12835
 
12684
- // src/commands/forewarning.ts
12836
+ // src/commands/forewarning/_shared.ts
12837
+ var VALID_MEDIA_TYPES7 = ["Google", "TikTok"];
12838
+
12839
+ // src/commands/forewarning/list.ts
12685
12840
  init_auth();
12686
12841
  init_cli_json_snapshot();
12687
- import os4 from "os";
12688
- import path13 from "path";
12689
- import QRCode from "qrcode";
12690
- import open2 from "open";
12691
12842
  init_cli_table();
12692
- var VALID_MEDIA_TYPES7 = ["Google", "TikTok"];
12693
12843
  async function runForewarningList(opts) {
12694
12844
  if (!VALID_MEDIA_TYPES7.includes(opts.media)) {
12695
12845
  console.error(
@@ -12767,6 +12917,11 @@ async function runForewarningList(opts) {
12767
12917
  printCliTable(rows, cols);
12768
12918
  console.log();
12769
12919
  }
12920
+
12921
+ // src/commands/forewarning/records.ts
12922
+ init_auth();
12923
+ init_cli_json_snapshot();
12924
+ init_cli_table();
12770
12925
  async function runForewarningRecords(opts) {
12771
12926
  if (!VALID_MEDIA_TYPES7.includes(opts.media)) {
12772
12927
  console.error(`
@@ -12839,6 +12994,9 @@ async function runForewarningRecords(opts) {
12839
12994
  printCliTable(rows, cols);
12840
12995
  console.log();
12841
12996
  }
12997
+
12998
+ // src/commands/forewarning/actions.ts
12999
+ init_auth();
12842
13000
  async function runForewarningStart(opts) {
12843
13001
  const config = loadConfig(opts.token);
12844
13002
  const url = `${config.apiBaseUrl}/command/smart-strategy/settings/${opts.media}/${opts.id}/start`;
@@ -12878,6 +13036,29 @@ async function runForewarningDelete(opts) {
12878
13036
  }
12879
13037
  console.log("\n\u2705 \u9884\u8B66\u89C4\u5219\u5DF2\u5220\u9664\n");
12880
13038
  }
13039
+ async function runForewarningGet(opts) {
13040
+ const config = loadConfig(opts.token);
13041
+ const url = `${config.apiBaseUrl}/query/smart-strategy/settings/${opts.media}/${opts.id}`;
13042
+ let data;
13043
+ try {
13044
+ data = await apiFetch2(url, config, {}, opts.verbose);
13045
+ } catch (err) {
13046
+ console.error(`
13047
+ \u274C \u67E5\u8BE2\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
13048
+ `);
13049
+ process.exit(1);
13050
+ }
13051
+ console.log(JSON.stringify(data, null, 2));
13052
+ }
13053
+
13054
+ // src/commands/forewarning/notify-accounts.ts
13055
+ init_auth();
13056
+ init_cli_json_snapshot();
13057
+ import os4 from "os";
13058
+ import path13 from "path";
13059
+ import QRCode from "qrcode";
13060
+ import open2 from "open";
13061
+ init_cli_table();
12881
13062
  async function runForewarningNotifyAccounts(opts) {
12882
13063
  const config = loadConfig(opts.token);
12883
13064
  const listUrl = `${config.apiBaseUrl}/query/notice-account/getAccount`;
@@ -12947,6 +13128,9 @@ async function runForewarningNotifyAccounts(opts) {
12947
13128
  console.log();
12948
13129
  console.log(" \u{1F4A1} \u5C06\u5DF2\u5173\u6CE8\u8D26\u6237\u7684 entityId \u4F20\u7ED9 --notify \u53C2\u6570\u4EE5\u63A5\u6536\u9884\u8B66\u901A\u77E5\n");
12949
13130
  }
13131
+
13132
+ // src/commands/forewarning/create.ts
13133
+ init_auth();
12950
13134
  var WEEKDAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
12951
13135
  function buildRuleBody(opts) {
12952
13136
  const accountIds = opts.accounts.split(",").map((s) => s.trim()).filter(Boolean);
@@ -13034,20 +13218,8 @@ async function runForewarningCreate(opts) {
13034
13218
  \u2705 \u9884\u8B66\u89C4\u5219\u5DF2${isUpdate ? "\u66F4\u65B0" : "\u521B\u5EFA"}\uFF1A${opts.name}
13035
13219
  `);
13036
13220
  }
13037
- async function runForewarningGet(opts) {
13038
- const config = loadConfig(opts.token);
13039
- const url = `${config.apiBaseUrl}/query/smart-strategy/settings/${opts.media}/${opts.id}`;
13040
- let data;
13041
- try {
13042
- data = await apiFetch2(url, config, {}, opts.verbose);
13043
- } catch (err) {
13044
- console.error(`
13045
- \u274C \u67E5\u8BE2\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
13046
- `);
13047
- process.exit(1);
13048
- }
13049
- console.log(JSON.stringify(data, null, 2));
13050
- }
13221
+
13222
+ // src/commands/forewarning/_register.ts
13051
13223
  function register18(program2) {
13052
13224
  const forewarningCmd = program2.command("forewarning").description("\u667A\u80FD\u9884\u8B66\u89C4\u5219\u4E0E\u9884\u8B66\u8BB0\u5F55\u7BA1\u7406");
13053
13225
  forewarningCmd.command("list").description("\u67E5\u8BE2\u9884\u8B66\u89C4\u5219\u5217\u8868").requiredOption("-m, --media <type>", "\u5A92\u4F53\u7C7B\u578B\uFF1AGoogle | TikTok").option("-a, --account <id>", "\u8D26\u6237 ID \u7B5B\u9009").option("-k, --keyword <text>", "\u89C4\u5219\u540D\u79F0\u5173\u952E\u5B57").option("--start <date>", "\u5F00\u59CB\u65E5\u671F YYYY-MM-DD").option("--end <date>", "\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option("-p, --page <n>", "\u9875\u7801", parseInt).option("--page-size <n>", "\u6BCF\u9875\u6570\u91CF", parseInt).option("-t, --token <token>", "Auth Token").option("--json", "JSON \u683C\u5F0F\u8F93\u51FA", false).option(
@@ -14084,8 +14256,7 @@ async function runAdCampaignEdit(opts) {
14084
14256
  if (opts.biddingStrategy !== void 0) body["biddingStrategyTypeV2"] = opts.biddingStrategy;
14085
14257
  if (opts.targetSpendBidCeiling !== void 0)
14086
14258
  body["targetSpend_BidCeilingAmount"] = toCentAmount(opts.targetSpendBidCeiling);
14087
- if (opts.targetCpa !== void 0)
14088
- body["targetCpa_BidingAmount"] = toCentAmount(opts.targetCpa);
14259
+ if (opts.targetCpa !== void 0) body["targetCpa_BidingAmount"] = toCentAmount(opts.targetCpa);
14089
14260
  if (opts.targetSearchNetwork !== void 0)
14090
14261
  body["targetSearchNetwork"] = opts.targetSearchNetwork;
14091
14262
  if (opts.targetContentNetwork !== void 0)
@@ -14303,9 +14474,7 @@ async function runAdGroupEdit(opts) {
14303
14474
  const hasMax = opts.maxCPCAmount !== void 0;
14304
14475
  const hasTcpa = opts.targetCpaAmount !== void 0;
14305
14476
  if (!hasName && !hasMax && !hasTcpa) {
14306
- console.error(
14307
- "\n\u274C \u8BF7\u81F3\u5C11\u6307\u5B9A\u4E00\u9879\u4FEE\u6539\uFF1A--name / --max-cpc / --target-cpa\n"
14308
- );
14477
+ console.error("\n\u274C \u8BF7\u81F3\u5C11\u6307\u5B9A\u4E00\u9879\u4FEE\u6539\uFF1A--name / --max-cpc / --target-cpa\n");
14309
14478
  process.exit(1);
14310
14479
  }
14311
14480
  if (hasMax && (!Number.isFinite(opts.maxCPCAmount) || opts.maxCPCAmount < 0)) {
@@ -15617,7 +15786,10 @@ function register20(program2) {
15617
15786
  "Google \u5E7F\u544A\u7BA1\u7406\uFF08Google API \u5730\u5740\u4ECE TSO API \u81EA\u52A8\u63A8\u5BFC\uFF0C\u53EF\u901A\u8FC7 SILUZAN_GOOGLE_API \u73AF\u5883\u53D8\u91CF\u8986\u76D6\uFF09\n \u542B\uFF1A\u7CFB\u5217/\u7EC4/\u521B\u610F/\u5173\u952E\u8BCD\u7B49\u5E38\u89C4\u5E7F\u544A\u6295\u653E\u4E0E\u7BA1\u7406\u80FD\u529B"
15618
15787
  );
15619
15788
  const adBatchCmd = adCmd.command("batch").description("\u5F02\u6B65\u6279\u91CF\u521B\u5EFA\u4EFB\u52A1\u4E0E\u8349\u7A3F\uFF08\u67E5\u8BE2\u8BE6\u60C5\u3001\u53D1\u5E03\u3001\u66F4\u65B0\uFF1B\u4E0E ad campaign-create \u540C\u6E90\uFF09");
15620
- adBatchCmd.command("list").description("\u67E5\u8BE2\u6279\u91CF\u521B\u5EFA / \u667A\u6295\u8BB0\u5F55\u5217\u8868").option("-s, --state <state>", "\u72B6\u6001\uFF1ACreating | Successfully | Failed | HasFailed | Unpublished").option("--customer-id <id>", "\u5BA2\u6237 ID").option("--customer-name <name>", "\u5BA2\u6237\u540D\u79F0").option("-k, --keyword <text>", "\u5173\u952E\u5B57\u641C\u7D22").option("--start <date>", "\u521B\u5EFA\u5F00\u59CB\u65E5\u671F YYYY-MM-DD").option("--end <date>", "\u521B\u5EFA\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option("-p, --page <n>", "\u9875\u7801", parseInt).option("--page-size <n>", "\u6BCF\u9875\u6570\u91CF", parseInt).option("-t, --token <token>", "Auth Token").option("--json", "JSON \u683C\u5F0F\u8F93\u51FA", false).option(
15789
+ adBatchCmd.command("list").description("\u67E5\u8BE2\u6279\u91CF\u521B\u5EFA / \u667A\u6295\u8BB0\u5F55\u5217\u8868").option(
15790
+ "-s, --state <state>",
15791
+ "\u72B6\u6001\uFF1ACreating | Successfully | Failed | HasFailed | Unpublished"
15792
+ ).option("--customer-id <id>", "\u5BA2\u6237 ID").option("--customer-name <name>", "\u5BA2\u6237\u540D\u79F0").option("-k, --keyword <text>", "\u5173\u952E\u5B57\u641C\u7D22").option("--start <date>", "\u521B\u5EFA\u5F00\u59CB\u65E5\u671F YYYY-MM-DD").option("--end <date>", "\u521B\u5EFA\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option("-p, --page <n>", "\u9875\u7801", parseInt).option("--page-size <n>", "\u6BCF\u9875\u6570\u91CF", parseInt).option("-t, --token <token>", "Auth Token").option("--json", "JSON \u683C\u5F0F\u8F93\u51FA", false).option(
15621
15793
  "--json-out <path>",
15622
15794
  "\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF08\u4E0E --json \u4E92\u65A5\uFF09\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
15623
15795
  void 0
@@ -15645,19 +15817,25 @@ function register20(program2) {
15645
15817
  "--json-out <path>",
15646
15818
  "\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF08\u4E0E --json \u4E92\u65A5\uFF09\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
15647
15819
  void 0
15648
- ).option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
15649
- await runAiCreationGet({
15650
- token: opts.token,
15651
- id: opts.id,
15652
- json: opts.json,
15653
- jsonOut: opts.jsonOut,
15654
- verbose: opts.verbose
15655
- });
15656
- });
15820
+ ).option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
15821
+ async (opts) => {
15822
+ await runAiCreationGet({
15823
+ token: opts.token,
15824
+ id: opts.id,
15825
+ json: opts.json,
15826
+ jsonOut: opts.jsonOut,
15827
+ verbose: opts.verbose
15828
+ });
15829
+ }
15830
+ );
15657
15831
  adBatchCmd.command("publish").description("\u53D1\u5E03\u8349\u7A3F\uFF08Draft \u2192 \u63D0\u4EA4 Google \u5F02\u6B65\u521B\u5EFA\uFF09").requiredOption("--id <id>", "\u8349\u7A3F\u8BB0\u5F55 ID\uFF08draftStatus \u5FC5\u987B\u4E3A Draft\uFF09").option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
15658
15832
  await runAiCreationPublish({ token: opts.token, id: opts.id, verbose: opts.verbose });
15659
15833
  });
15660
- adBatchCmd.command("update").description("\u66F4\u65B0\u8349\u7A3F\u5B57\u6BB5\u540E\u4FDD\u5B58\uFF08--id \u5FC5\u4F20\uFF1B--budget / --url / --campaign-name \u81F3\u5C11\u4F20\u4E00\u4E2A\uFF09").requiredOption("--id <id>", "\u8349\u7A3F\u8BB0\u5F55 ID").option("--budget <amount>", "\u65B0\u65E5\u9884\u7B97\uFF08\u8D26\u6237\u4E3B\u5E01\u79CD\u91D1\u989D\uFF0C\u5982 50 \u8868\u793A\u6BCF\u5929 50 USD/CNY\uFF09", parseFloat).option("--url <url>", "\u65B0\u63A8\u5E7F\u94FE\u63A5").option("--campaign-name <name>", "\u65B0\u5E7F\u544A\u7CFB\u5217\u540D\u79F0").option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
15834
+ adBatchCmd.command("update").description("\u66F4\u65B0\u8349\u7A3F\u5B57\u6BB5\u540E\u4FDD\u5B58\uFF08--id \u5FC5\u4F20\uFF1B--budget / --url / --campaign-name \u81F3\u5C11\u4F20\u4E00\u4E2A\uFF09").requiredOption("--id <id>", "\u8349\u7A3F\u8BB0\u5F55 ID").option(
15835
+ "--budget <amount>",
15836
+ "\u65B0\u65E5\u9884\u7B97\uFF08\u8D26\u6237\u4E3B\u5E01\u79CD\u91D1\u989D\uFF0C\u5982 50 \u8868\u793A\u6BCF\u5929 50 USD/CNY\uFF09",
15837
+ parseFloat
15838
+ ).option("--url <url>", "\u65B0\u63A8\u5E7F\u94FE\u63A5").option("--campaign-name <name>", "\u65B0\u5E7F\u544A\u7CFB\u5217\u540D\u79F0").option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
15661
15839
  async (opts) => {
15662
15840
  await runAiCreationUpdate({
15663
15841
  token: opts.token,
@@ -15925,7 +16103,10 @@ function register20(program2) {
15925
16103
  "--budget <amount>",
15926
16104
  "\u65E5\u9884\u7B97\uFF1A\u8D26\u6237\u4E3B\u5E01\u79CD\u91D1\u989D\uFF08\u5982 100 = \u6BCF\u5929 100 USD/CNY\uFF1B\u5185\u90E8 \xD7100 \u5199\u5165\u63A5\u53E3\uFF09",
15927
16105
  parseFloat
15928
- ).option("--bidding <strategy>", "\u51FA\u4EF7\u7B56\u7565\uFF1ATARGET_SPEND | MANUAL_CPC | TARGET_CPA | TARGET_ROAS").option(
16106
+ ).option(
16107
+ "--bidding <strategy>",
16108
+ "\u51FA\u4EF7\u7B56\u7565\uFF1ATARGET_SPEND | MANUAL_CPC | TARGET_CPA | TARGET_ROAS"
16109
+ ).option(
15929
16110
  "--location-ids <ids>",
15930
16111
  "\u6295\u653E\u5730\u7406\u4F4D\u7F6E ID\uFF0C\u9017\u53F7\u5206\u9694\uFF08\u7528 ad geo search \u83B7\u53D6\uFF0C\u5982 2840=\u7F8E\u56FD\uFF09",
15931
16112
  (v) => v.split(",").map((s) => s.trim())
@@ -15953,7 +16134,10 @@ function register20(program2) {
15953
16134
  "--keywords <kws>",
15954
16135
  "\u5173\u952E\u8BCD\uFF0C\u9017\u53F7\u5206\u9694\uFF08\u53EF\u9009\uFF1B\u683C\u5F0F\uFF1A\u8BCD\u2192BROAD\uFF0C*\u8BCD*\u2192PHRASE\uFF0C[\u8BCD]\u2192EXACT\uFF09",
15955
16136
  (v) => v.split(",").map((s) => s.trim())
15956
- ).option("--match-type <type>", "\u65E0\u524D\u7F00\u5173\u952E\u8BCD\u7684\u9ED8\u8BA4\u5339\u914D\u7C7B\u578B\uFF1ABROAD | PHRASE | EXACT\uFF08\u9ED8\u8BA4 BROAD\uFF09").option(
16137
+ ).option(
16138
+ "--match-type <type>",
16139
+ "\u65E0\u524D\u7F00\u5173\u952E\u8BCD\u7684\u9ED8\u8BA4\u5339\u914D\u7C7B\u578B\uFF1ABROAD | PHRASE | EXACT\uFF08\u9ED8\u8BA4 BROAD\uFF09"
16140
+ ).option(
15957
16141
  "--headlines <titles>",
15958
16142
  "\u5E7F\u544A\u6807\u9898\uFF0C\u9017\u53F7\u5206\u9694\uFF0C\u81F3\u5C11 3 \u6761\uFF0C\u6BCF\u6761 \u2264 30 \u5B57\u7B26\uFF08\u4E0E --descriptions \u548C --final-url \u540C\u65F6\u4F20\u624D\u751F\u6210\u5E7F\u544A\uFF09",
15959
16143
  (v) => v.split(",").map((s) => s.trim())
@@ -16084,7 +16268,10 @@ function register20(program2) {
16084
16268
  "--budget <amount>",
16085
16269
  "\u65B0\u9884\u7B97\uFF0C\u4E3B\u5E01\u79CD\u91D1\u989D\uFF08\u5982 100 \u8868\u793A \xA5100\uFF1B\u652F\u6301\u5C0F\u6570\uFF1BCLI \u5185\u90E8\u81EA\u52A8 \xD7100 \u5199\u5165\u300C\u5206\u300D\u5B57\u6BB5\uFF09",
16086
16270
  parseFloat
16087
- ).option("--bidding <strategy>", "\u51FA\u4EF7\u7B56\u7565\uFF1ATARGET_SPEND | TARGET_CPA | TARGET_ROAS | MANUAL_CPC").option(
16271
+ ).option(
16272
+ "--bidding <strategy>",
16273
+ "\u51FA\u4EF7\u7B56\u7565\uFF1ATARGET_SPEND | TARGET_CPA | TARGET_ROAS | MANUAL_CPC"
16274
+ ).option(
16088
16275
  "--bid-ceiling <amount>",
16089
16276
  "TARGET_SPEND \u51FA\u4EF7\u4E0A\u9650\uFF0C\u4E3B\u5E01\u79CD\u91D1\u989D\uFF080 = \u4E0D\u9650\uFF1BCLI \u5185\u90E8 \xD7100 \u5199\u5165\uFF09",
16090
16277
  parseFloat
@@ -16181,7 +16368,10 @@ function register20(program2) {
16181
16368
  });
16182
16369
  }
16183
16370
  );
16184
- adCmd.command("keyword-delete").description("\u5220\u9664\u641C\u7D22\u5173\u952E\u8BCD").requiredOption("-a, --account <id>", "Google \u8D26\u6237 mediaCustomerId").requiredOption("--id <keywordId>", "\u5173\u952E\u8BCD ID\uFF08\u6765\u81EA ad keywords --json \u2192 id\uFF09").requiredOption("--adgroup-id <id>", "\u5173\u952E\u8BCD\u6240\u5C5E\u5E7F\u544A\u7EC4 ID\uFF08\u6765\u81EA ad keywords --json \u2192 adGroupId\uFF09").option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
16371
+ adCmd.command("keyword-delete").description("\u5220\u9664\u641C\u7D22\u5173\u952E\u8BCD").requiredOption("-a, --account <id>", "Google \u8D26\u6237 mediaCustomerId").requiredOption("--id <keywordId>", "\u5173\u952E\u8BCD ID\uFF08\u6765\u81EA ad keywords --json \u2192 id\uFF09").requiredOption(
16372
+ "--adgroup-id <id>",
16373
+ "\u5173\u952E\u8BCD\u6240\u5C5E\u5E7F\u544A\u7EC4 ID\uFF08\u6765\u81EA ad keywords --json \u2192 adGroupId\uFF09"
16374
+ ).option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
16185
16375
  async (opts) => {
16186
16376
  await runAdKeywordDelete({
16187
16377
  token: opts.token,
@@ -17738,7 +17928,10 @@ function register22(program2) {
17738
17928
  });
17739
17929
  }
17740
17930
  );
17741
- accountCmd.command("auth").description("\u6DFB\u52A0\u6388\u6743\uFF1A\u53D1\u8D77\u5A92\u4F53 OAuth\uFF0C\u6D4F\u89C8\u5668\u6253\u5F00\u6388\u6743\u9875\uFF08\u7F51\u9875 manageAccounts\u300C\u6DFB\u52A0\u6388\u6743\u300D\uFF09").requiredOption("-m, --media <type>", "\u5A92\u4F53\u7C7B\u578B\uFF1AGoogle | TikTok | Meta | Yandex | BingV2 | Kwai").option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
17931
+ accountCmd.command("auth").description("\u6DFB\u52A0\u6388\u6743\uFF1A\u53D1\u8D77\u5A92\u4F53 OAuth\uFF0C\u6D4F\u89C8\u5668\u6253\u5F00\u6388\u6743\u9875\uFF08\u7F51\u9875 manageAccounts\u300C\u6DFB\u52A0\u6388\u6743\u300D\uFF09").requiredOption(
17932
+ "-m, --media <type>",
17933
+ "\u5A92\u4F53\u7C7B\u578B\uFF1AGoogle | TikTok | Meta | Yandex | BingV2 | Kwai"
17934
+ ).option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
17742
17935
  await runAccountAuth({ token: opts.token, media: opts.media, verbose: opts.verbose });
17743
17936
  });
17744
17937
  accountCmd.command("mcc-bind").description("Google\uFF1A\u5C06\u5B50\u8D26\u6237\u7ED1\u5B9A\u5230\u7ECF\u7406\u8D26\u6237\uFF08MCC\uFF09\uFF0C\u9700\u5DF2\u914D\u7F6E googleApiUrl").requiredOption(
@@ -17783,15 +17976,17 @@ function register22(program2) {
17783
17976
  "--json-out <path>",
17784
17977
  "\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF08\u4E0E --json \u4E92\u65A5\uFF09\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
17785
17978
  void 0
17786
- ).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
17787
- await runAccountClose({
17788
- token: opts.token,
17789
- accountIds: opts.accounts.split(",").map((s) => s.trim()).filter(Boolean),
17790
- json: opts.json,
17791
- jsonOut: opts.jsonOut,
17792
- verbose: opts.verbose
17793
- });
17794
- });
17979
+ ).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
17980
+ async (opts) => {
17981
+ await runAccountClose({
17982
+ token: opts.token,
17983
+ accountIds: opts.accounts.split(",").map((s) => s.trim()).filter(Boolean),
17984
+ json: opts.json,
17985
+ jsonOut: opts.jsonOut,
17986
+ verbose: opts.verbose
17987
+ });
17988
+ }
17989
+ );
17795
17990
  accountCmd.command("bm-bind").description("Meta\uFF1A\u5C06\u5E7F\u544A\u8D26\u6237\u7ED1\u5B9A\u5230 Business Manager\uFF08BM\uFF09").requiredOption("--account-id <id>", "Meta \u5E7F\u544A\u8D26\u6237 mediaCustomerId\uFF08\u6765\u81EA list-accounts\uFF09").requiredOption("--bm-id <id>", "Business Manager ID").option("--action-type <type>", "\u64CD\u4F5C\u7C7B\u578B\uFF08\u9ED8\u8BA4 bind\uFF09").option("-t, --token <token>", "Auth Token").option("--json", "\u8F93\u51FA\u539F\u59CB JSON", false).option(
17796
17991
  "--json-out <path>",
17797
17992
  "\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF08\u4E0E --json \u4E92\u65A5\uFF09\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
@@ -17813,14 +18008,16 @@ function register22(program2) {
17813
18008
  "--json-out <path>",
17814
18009
  "\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF08\u4E0E --json \u4E92\u65A5\uFF09\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
17815
18010
  void 0
17816
- ).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
17817
- await runAccountWithdrawList({
17818
- token: opts.token,
17819
- json: opts.json,
17820
- jsonOut: opts.jsonOut,
17821
- verbose: opts.verbose
17822
- });
17823
- });
18011
+ ).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
18012
+ async (opts) => {
18013
+ await runAccountWithdrawList({
18014
+ token: opts.token,
18015
+ json: opts.json,
18016
+ jsonOut: opts.jsonOut,
18017
+ verbose: opts.verbose
18018
+ });
18019
+ }
18020
+ );
17824
18021
  accountCmd.command("withdraw-submit").description("Google\uFF1A\u63D0\u4EA4\u88AB\u5C01\u8D26\u6237\u63D0\u73B0\u7533\u8BF7\uFF08\u81EA\u52A8\u67E5\u8BE2\u4F59\u989D\u548C\u7BA1\u7406\u8D39\uFF0C\u8BA1\u7B97\u63D0\u73B0\u91D1\u989D\uFF09").requiredOption(
17825
18022
  "--accounts <entityIds>",
17826
18023
  "\u8981\u63D0\u73B0\u7684\u8D26\u6237 entityId\uFF0C\u9017\u53F7\u5206\u9694\uFF08\u6765\u81EA account withdraw-list\uFF09"
@@ -17828,15 +18025,17 @@ function register22(program2) {
17828
18025
  "--json-out <path>",
17829
18026
  "\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF08\u4E0E --json \u4E92\u65A5\uFF09\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
17830
18027
  void 0
17831
- ).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
17832
- await runAccountWithdrawSubmit({
17833
- token: opts.token,
17834
- accounts: opts.accounts.split(",").map((s) => s.trim()).filter(Boolean),
17835
- json: opts.json,
17836
- jsonOut: opts.jsonOut,
17837
- verbose: opts.verbose
17838
- });
17839
- });
18028
+ ).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
18029
+ async (opts) => {
18030
+ await runAccountWithdrawSubmit({
18031
+ token: opts.token,
18032
+ accounts: opts.accounts.split(",").map((s) => s.trim()).filter(Boolean),
18033
+ json: opts.json,
18034
+ jsonOut: opts.jsonOut,
18035
+ verbose: opts.verbose
18036
+ });
18037
+ }
18038
+ );
17840
18039
  accountCmd.command("bc-bind").description("TikTok\uFF1A\u5C06\u5E7F\u544A\u8D26\u6237\u7ED1\u5B9A\u5230 Business Center\uFF08BC\uFF09").requiredOption(
17841
18040
  "--customers <ids>",
17842
18041
  "TikTok \u5E7F\u544A\u8D26\u6237 mediaCustomerId\uFF0C\u591A\u4E2A\u9017\u53F7\u5206\u9694\uFF08\u6765\u81EA list-accounts -m TikTok\uFF09"
@@ -17874,7 +18073,10 @@ function register22(program2) {
17874
18073
  );
17875
18074
  accountCmd.command("email-auth-list").description(
17876
18075
  "Google\uFF1A\u67E5\u8BE2\u5E7F\u544A\u8D26\u6237\u7684\u90AE\u7BB1\u6388\u6743\u5217\u8868\uFF08\u5DF2\u53D1\u51FA\u7684\u6388\u6743\u9080\u8BF7\uFF09\uFF1B\u67E5\u8BE2\u53C2\u6570\u4E0E\u7F51\u9875\u4E00\u81F4\u4E3A customerId\uFF0C--agent-type \u53EF\u9009"
17877
- ).requiredOption("-c, --customer-id <id>", "Google \u5E7F\u544A\u8D26\u6237 mediaCustomerId\uFF08\u6765\u81EA list-accounts\uFF09").option(
18076
+ ).requiredOption(
18077
+ "-c, --customer-id <id>",
18078
+ "Google \u5E7F\u544A\u8D26\u6237 mediaCustomerId\uFF08\u6765\u81EA list-accounts\uFF09"
18079
+ ).option(
17878
18080
  "--agent-type <type>",
17879
18081
  "\u53EF\u9009\uFF0C\u90E8\u5206\u7F51\u5173\u9700\u8981\u65F6\u4F20\u5165\uFF08\u4E0E list-accounts \u4E2D ma.accountType \u4E00\u81F4\uFF09"
17880
18082
  ).option("-t, --token <token>", "Auth Token").option("--json", "\u8F93\u51FA\u539F\u59CB JSON", false).option(
@@ -18536,7 +18738,12 @@ async function runOpenAccountGoogleTimezones(opts) {
18536
18738
  });
18537
18739
  }
18538
18740
  const n = rows.length;
18539
- const googleTzPayload = wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items: rows });
18741
+ const googleTzPayload = wrapListJson({
18742
+ page: 1,
18743
+ pageSize: Math.max(n, 1),
18744
+ total: n,
18745
+ items: rows
18746
+ });
18540
18747
  if (await emitCliJsonOrSnapshot(opts, {
18541
18748
  section: "open-account-google-timezones",
18542
18749
  commandLabel: "open-account google-timezones",
@@ -18955,7 +19162,12 @@ async function runOpenAccountTikTokTimezones(opts) {
18955
19162
  });
18956
19163
  }
18957
19164
  const n = rows.length;
18958
- const tiktokTzPayload = wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items: rows });
19165
+ const tiktokTzPayload = wrapListJson({
19166
+ page: 1,
19167
+ pageSize: Math.max(n, 1),
19168
+ total: n,
19169
+ items: rows
19170
+ });
18959
19171
  if (await emitCliJsonOrSnapshot(opts, {
18960
19172
  section: "open-account-tiktok-timezones",
18961
19173
  commandLabel: "open-account tiktok-timezones",
@@ -19009,7 +19221,12 @@ async function runOpenAccountTikTokIndustries(opts) {
19009
19221
  );
19010
19222
  }
19011
19223
  const n = rows.length;
19012
- const tiktokIndPayload = wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items: rows });
19224
+ const tiktokIndPayload = wrapListJson({
19225
+ page: 1,
19226
+ pageSize: Math.max(n, 1),
19227
+ total: n,
19228
+ items: rows
19229
+ });
19013
19230
  if (await emitCliJsonOrSnapshot(opts, {
19014
19231
  section: "open-account-tiktok-industries",
19015
19232
  commandLabel: "open-account tiktok-industries",
@@ -19064,7 +19281,12 @@ async function runOpenAccountTikTokAreas(opts) {
19064
19281
  );
19065
19282
  }
19066
19283
  const n = rows.length;
19067
- const tiktokAreasPayload = wrapListJson({ page: 1, pageSize: Math.max(n, 1), total: n, items: rows });
19284
+ const tiktokAreasPayload = wrapListJson({
19285
+ page: 1,
19286
+ pageSize: Math.max(n, 1),
19287
+ total: n,
19288
+ items: rows
19289
+ });
19068
19290
  if (await emitCliJsonOrSnapshot(opts, {
19069
19291
  section: "open-account-tiktok-areas",
19070
19292
  commandLabel: "open-account tiktok-areas",
@@ -19100,14 +19322,16 @@ function register23(program2) {
19100
19322
  "--json-out <path>",
19101
19323
  "\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF08\u4E0E --json \u4E92\u65A5\uFF09\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
19102
19324
  void 0
19103
- ).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
19104
- await runListAdvertiserGroups({
19105
- token: opts.token,
19106
- json: opts.json,
19107
- jsonOut: opts.jsonOut,
19108
- verbose: opts.verbose
19109
- });
19110
- });
19325
+ ).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
19326
+ async (opts) => {
19327
+ await runListAdvertiserGroups({
19328
+ token: opts.token,
19329
+ json: opts.json,
19330
+ jsonOut: opts.jsonOut,
19331
+ verbose: opts.verbose
19332
+ });
19333
+ }
19334
+ );
19111
19335
  openAccountCmd.command("yandex").description("\u63D0\u4EA4 Yandex \u5F00\u6237\u7533\u8BF7\uFF08\u65E0\u9700\u56FE\u7247\uFF0C\u6309\u516C\u53F8\u540D\u81EA\u52A8\u521B\u5EFA/\u5173\u8054\u5E7F\u544A\u4E3B\u7EC4\uFF09").requiredOption("--company <name>", "\u516C\u53F8\u540D\u79F0\uFF08\u7528\u4E8E\u5339\u914D\u6216\u521B\u5EFA\u5E7F\u544A\u4E3B\u7EC4\uFF0C\u4E0E\u7F51\u9875\u884C\u4E3A\u4E00\u81F4\uFF09").requiredOption("--email <email>", "\u8054\u7CFB\u90AE\u7BB1").requiredOption("--tin <tin>", "\u7EB3\u7A0E\u4EBA\u8BC6\u522B\u53F7\uFF08TIN / INN\uFF09").option("--advertiser-id <magKey>", "\u53EF\u9009\uFF1A\u624B\u52A8\u6307\u5B9A\u5E7F\u544A\u4E3B\u7EC4 magKey\uFF08\u4E00\u822C\u65E0\u9700\u586B\u5199\uFF09").option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
19112
19336
  async (opts) => {
19113
19337
  await runOpenAccountYandex({
@@ -19147,67 +19371,77 @@ function register23(program2) {
19147
19371
  "--json-out <path>",
19148
19372
  "\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF08\u4E0E --json \u4E92\u65A5\uFF09\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
19149
19373
  void 0
19150
- ).option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
19151
- await runOpenAccountTikTokTimezones({
19152
- token: opts.token,
19153
- keyword: opts.keyword,
19154
- json: opts.json,
19155
- jsonOut: opts.jsonOut,
19156
- verbose: opts.verbose
19157
- });
19158
- });
19374
+ ).option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
19375
+ async (opts) => {
19376
+ await runOpenAccountTikTokTimezones({
19377
+ token: opts.token,
19378
+ keyword: opts.keyword,
19379
+ json: opts.json,
19380
+ jsonOut: opts.jsonOut,
19381
+ verbose: opts.verbose
19382
+ });
19383
+ }
19384
+ );
19159
19385
  openAccountCmd.command("tiktok-industries").description("\u5217\u51FA TikTok \u884C\u4E1A\u5206\u7C7B\uFF08\u4E24\u7EA7\u7ED3\u6784\uFF0C--industry-id \u4F20\u53F6\u5B50\u8282\u70B9 ID\uFF09").option("-k, --keyword <text>", "\u6309\u884C\u4E1A\u540D\u79F0\u8FC7\u6EE4").option("--json", "JSON \u8F93\u51FA", false).option(
19160
19386
  "--json-out <path>",
19161
19387
  "\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF08\u4E0E --json \u4E92\u65A5\uFF09\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
19162
19388
  void 0
19163
- ).option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
19164
- await runOpenAccountTikTokIndustries({
19165
- token: opts.token,
19166
- keyword: opts.keyword,
19167
- json: opts.json,
19168
- jsonOut: opts.jsonOut,
19169
- verbose: opts.verbose
19170
- });
19171
- });
19389
+ ).option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
19390
+ async (opts) => {
19391
+ await runOpenAccountTikTokIndustries({
19392
+ token: opts.token,
19393
+ keyword: opts.keyword,
19394
+ json: opts.json,
19395
+ jsonOut: opts.jsonOut,
19396
+ verbose: opts.verbose
19397
+ });
19398
+ }
19399
+ );
19172
19400
  openAccountCmd.command("tiktok-areas").description("\u5217\u51FA TikTok \u6CE8\u518C\u5730\u4EE3\u7801\uFF08--registered-area \u4F20 Key \u503C\uFF0C\u5982 CN\uFF09").option("-k, --keyword <text>", "\u6309\u4EE3\u7801\u6216\u540D\u79F0\u8FC7\u6EE4").option("--json", "JSON \u8F93\u51FA", false).option(
19173
19401
  "--json-out <path>",
19174
19402
  "\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF08\u4E0E --json \u4E92\u65A5\uFF09\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
19175
19403
  void 0
19176
- ).option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
19177
- await runOpenAccountTikTokAreas({
19178
- token: opts.token,
19179
- keyword: opts.keyword,
19180
- json: opts.json,
19181
- jsonOut: opts.jsonOut,
19182
- verbose: opts.verbose
19183
- });
19184
- });
19404
+ ).option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
19405
+ async (opts) => {
19406
+ await runOpenAccountTikTokAreas({
19407
+ token: opts.token,
19408
+ keyword: opts.keyword,
19409
+ json: opts.json,
19410
+ jsonOut: opts.jsonOut,
19411
+ verbose: opts.verbose
19412
+ });
19413
+ }
19414
+ );
19185
19415
  openAccountCmd.command("bing-industries").description("\u5217\u51FA BingV2 \u884C\u4E1A\u5206\u7C7B\uFF08\u5C06 name \u503C\u4F20\u7ED9 open-account bing \u7684 --trade-id\uFF09").option("-k, --keyword <text>", "\u6309\u4E2D\u6587\u540D\u6216\u82F1\u6587\u540D\u8FC7\u6EE4").option("--json", "JSON \u8F93\u51FA", false).option(
19186
19416
  "--json-out <path>",
19187
19417
  "\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF08\u4E0E --json \u4E92\u65A5\uFF09\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
19188
19418
  void 0
19189
- ).option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
19190
- await runOpenAccountBingIndustries({
19191
- token: opts.token,
19192
- keyword: opts.keyword,
19193
- json: opts.json,
19194
- jsonOut: opts.jsonOut,
19195
- verbose: opts.verbose
19196
- });
19197
- });
19419
+ ).option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
19420
+ async (opts) => {
19421
+ await runOpenAccountBingIndustries({
19422
+ token: opts.token,
19423
+ keyword: opts.keyword,
19424
+ json: opts.json,
19425
+ jsonOut: opts.jsonOut,
19426
+ verbose: opts.verbose
19427
+ });
19428
+ }
19429
+ );
19198
19430
  openAccountCmd.command("google-timezones").description("\u5217\u51FA Google \u5F00\u6237\u53EF\u9009\u65F6\u533A\uFF08\u4E0E\u7F51\u9875 /openAnAccount \u7B2C\u4E8C\u6B65\u4E0B\u62C9\u91CC\u6570\u636E\u6E90\u4E00\u81F4\uFF09").option("-k, --keyword <text>", "\u6309 Code / \u540D\u79F0 / UTC \u8BF4\u660E\u8FC7\u6EE4").option("--json", "JSON \u8F93\u51FA", false).option(
19199
19431
  "--json-out <path>",
19200
19432
  "\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF08\u4E0E --json \u4E92\u65A5\uFF09\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
19201
19433
  void 0
19202
- ).option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
19203
- await runOpenAccountGoogleTimezones({
19204
- token: opts.token,
19205
- keyword: opts.keyword,
19206
- json: opts.json,
19207
- jsonOut: opts.jsonOut,
19208
- verbose: opts.verbose
19209
- });
19210
- });
19434
+ ).option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
19435
+ async (opts) => {
19436
+ await runOpenAccountGoogleTimezones({
19437
+ token: opts.token,
19438
+ keyword: opts.keyword,
19439
+ json: opts.json,
19440
+ jsonOut: opts.jsonOut,
19441
+ verbose: opts.verbose
19442
+ });
19443
+ }
19444
+ );
19211
19445
  openAccountCmd.command("google-wizard").description("\u4EA4\u4E92\u5F0F Google \u5F00\u6237\uFF08\u5BF9\u9F50\u7F51\u9875\u4E94\u6B65\u8BF4\u660E + \u4E24\u6B65\u8868\u5355\uFF1B\u9700\u7EC8\u7AEF TTY\uFF09").option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
19212
19446
  await runOpenAccountGoogleWizard({ token: opts.token, verbose: opts.verbose });
19213
19447
  });
@@ -19238,7 +19472,11 @@ function register23(program2) {
19238
19472
  });
19239
19473
  }
19240
19474
  );
19241
- openAccountCmd.command("tiktok").description("\u63D0\u4EA4 TikTok \u5F00\u6237\u7533\u8BF7\uFF08\u9700\u4E0A\u4F20\u8425\u4E1A\u6267\u7167\u56FE\u7247\uFF0C\u6309\u516C\u53F8\u540D\u81EA\u52A8\u521B\u5EFA/\u5173\u8054\u5E7F\u544A\u4E3B\u7EC4\uFF09").requiredOption("--account-name <name>", "\u5E7F\u544A\u8D26\u6237\u540D\u79F0").requiredOption("--timezone <tz>", "\u65F6\u533A\uFF0C\u5982 UTC+8\uFF08\u53EF\u5148\u67E5 open-account tiktok-timezones\uFF09").requiredOption("--company <name>", "\u516C\u53F8\u540D\u79F0").requiredOption("--industry-id <id>", "\u884C\u4E1A ID\uFF08\u6570\u5B57\uFF0CTikTok \u884C\u4E1A\u53F6\u5B50\u8282\u70B9 ID\uFF09", parseInt).requiredOption("--registered-area <code>", "\u6CE8\u518C\u5730\u56FD\u5BB6\u4EE3\u7801\uFF0C\u5982 CN").requiredOption("--promotion-link <url>", "\u63A8\u5E7F\u94FE\u63A5").requiredOption("--license-no <no>", "\u8425\u4E1A\u6267\u7167\u7F16\u7801\uFF08\u793E\u4F1A\u7EDF\u4E00\u4FE1\u7528\u4EE3\u7801\uFF09").requiredOption("--license-file <path>", "\u8425\u4E1A\u6267\u7167\u56FE\u7247\u672C\u5730\u8DEF\u5F84\uFF08JPG/PNG\uFF09").option("--bc-type <type>", "\u4E1A\u52A1\u4E2D\u5FC3\u7C7B\u578B\uFF1AShop | Store | App | B2B | Other\uFF08\u9ED8\u8BA4 Shop\uFF09", "Shop").option("--partner-id <id>", "BC \u5408\u4F5C\u4F19\u4F34 ID\uFF08bc_id\uFF0C\u53EF\u9009\uFF09").option("--counts <n>", "\u672C\u6B21\u5F00\u6237\u6570\u91CF\uFF081-10\uFF0C\u9ED8\u8BA4 1\uFF09", parseInt).requiredOption("--representative-name <name>", "\u6CD5\u4EBA\u59D3\u540D\uFF08\u94F6\u8054\u9A8C\u8BC1\u5FC5\u586B\uFF09").requiredOption("--representative-id <id>", "\u6CD5\u4EBA\u8EAB\u4EFD\u8BC1\u53F7\uFF08\u94F6\u8054\u9A8C\u8BC1\u5FC5\u586B\uFF09").requiredOption("--unionpay-account <no>", "\u6CD5\u4EBA\u94F6\u8054\u8D26\u53F7\uFF08\u94F6\u8054\u9A8C\u8BC1\u5FC5\u586B\uFF09").requiredOption("--representative-phone <phone>", "\u6CD5\u4EBA\u624B\u673A\u53F7\uFF08\u94F6\u8054\u9A8C\u8BC1\u5FC5\u586B\uFF09").option("--advertiser-id <magKey>", "\u53EF\u9009\uFF1A\u624B\u52A8\u6307\u5B9A\u5E7F\u544A\u4E3B\u7EC4 magKey\uFF08\u4E00\u822C\u65E0\u9700\u586B\u5199\uFF09").option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
19475
+ openAccountCmd.command("tiktok").description("\u63D0\u4EA4 TikTok \u5F00\u6237\u7533\u8BF7\uFF08\u9700\u4E0A\u4F20\u8425\u4E1A\u6267\u7167\u56FE\u7247\uFF0C\u6309\u516C\u53F8\u540D\u81EA\u52A8\u521B\u5EFA/\u5173\u8054\u5E7F\u544A\u4E3B\u7EC4\uFF09").requiredOption("--account-name <name>", "\u5E7F\u544A\u8D26\u6237\u540D\u79F0").requiredOption("--timezone <tz>", "\u65F6\u533A\uFF0C\u5982 UTC+8\uFF08\u53EF\u5148\u67E5 open-account tiktok-timezones\uFF09").requiredOption("--company <name>", "\u516C\u53F8\u540D\u79F0").requiredOption("--industry-id <id>", "\u884C\u4E1A ID\uFF08\u6570\u5B57\uFF0CTikTok \u884C\u4E1A\u53F6\u5B50\u8282\u70B9 ID\uFF09", parseInt).requiredOption("--registered-area <code>", "\u6CE8\u518C\u5730\u56FD\u5BB6\u4EE3\u7801\uFF0C\u5982 CN").requiredOption("--promotion-link <url>", "\u63A8\u5E7F\u94FE\u63A5").requiredOption("--license-no <no>", "\u8425\u4E1A\u6267\u7167\u7F16\u7801\uFF08\u793E\u4F1A\u7EDF\u4E00\u4FE1\u7528\u4EE3\u7801\uFF09").requiredOption("--license-file <path>", "\u8425\u4E1A\u6267\u7167\u56FE\u7247\u672C\u5730\u8DEF\u5F84\uFF08JPG/PNG\uFF09").option(
19476
+ "--bc-type <type>",
19477
+ "\u4E1A\u52A1\u4E2D\u5FC3\u7C7B\u578B\uFF1AShop | Store | App | B2B | Other\uFF08\u9ED8\u8BA4 Shop\uFF09",
19478
+ "Shop"
19479
+ ).option("--partner-id <id>", "BC \u5408\u4F5C\u4F19\u4F34 ID\uFF08bc_id\uFF0C\u53EF\u9009\uFF09").option("--counts <n>", "\u672C\u6B21\u5F00\u6237\u6570\u91CF\uFF081-10\uFF0C\u9ED8\u8BA4 1\uFF09", parseInt).requiredOption("--representative-name <name>", "\u6CD5\u4EBA\u59D3\u540D\uFF08\u94F6\u8054\u9A8C\u8BC1\u5FC5\u586B\uFF09").requiredOption("--representative-id <id>", "\u6CD5\u4EBA\u8EAB\u4EFD\u8BC1\u53F7\uFF08\u94F6\u8054\u9A8C\u8BC1\u5FC5\u586B\uFF09").requiredOption("--unionpay-account <no>", "\u6CD5\u4EBA\u94F6\u8054\u8D26\u53F7\uFF08\u94F6\u8054\u9A8C\u8BC1\u5FC5\u586B\uFF09").requiredOption("--representative-phone <phone>", "\u6CD5\u4EBA\u624B\u673A\u53F7\uFF08\u94F6\u8054\u9A8C\u8BC1\u5FC5\u586B\uFF09").option("--advertiser-id <magKey>", "\u53EF\u9009\uFF1A\u624B\u52A8\u6307\u5B9A\u5E7F\u544A\u4E3B\u7EC4 magKey\uFF08\u4E00\u822C\u65E0\u9700\u586B\u5199\uFF09").option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
19242
19480
  async (opts) => {
19243
19481
  await runOpenAccountTikTok({
19244
19482
  token: opts.token,
@@ -19300,7 +19538,7 @@ function register24(program2) {
19300
19538
  }
19301
19539
 
19302
19540
  // src/index.ts
19303
- init_google_analysis2();
19541
+ init_google_analysis3();
19304
19542
  init_google_analysis_batch();
19305
19543
  init_version();
19306
19544
  installProcessHandlers();