siluzan-tso-cli 1.1.45 → 1.1.46-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 (27) hide show
  1. package/README.md +2 -1
  2. package/dist/index.js +480 -106
  3. package/dist/skill/_meta.json +2 -2
  4. package/dist/skill/references/accounts/accounts-balance-stats.md +10 -10
  5. package/dist/skill/references/accounts/accounts-list.md +1 -1
  6. package/dist/skill/references/accounts/accounts-permissions.md +2 -2
  7. package/dist/skill/references/accounts/finance.md +1 -1
  8. package/dist/skill/references/accounts/open-account-by-media.md +1 -1
  9. package/dist/skill/references/accounts/open-account-google-ui.md +1 -1
  10. package/dist/skill/references/analytics/account-analytics.md +74 -13
  11. package/dist/skill/references/analytics/rag.md +1 -1
  12. package/dist/skill/references/analytics/reporting.md +5 -5
  13. package/dist/skill/references/core/setup.md +5 -5
  14. package/dist/skill/references/google-ads/rules/google-ads-keyword-strategy.md +8 -8
  15. package/dist/skill/references/misc/tso-home.md +2 -2
  16. package/dist/skill/references/operations/hosted-automation-monitoring-json.md +9 -9
  17. package/dist/skill/references/operations/hosted-automation-scenarios.md +2 -0
  18. package/dist/skill/references/report-templates/REPORT-WORKFLOW.md +3 -3
  19. package/dist/skill/references/report-templates/yandex-period-report-excel.md +45 -45
  20. package/dist/skill/references/report-templates/yandex-period-report.md +26 -27
  21. package/dist/skill/report-templates/REPORT-WORKFLOW.md +3 -3
  22. package/dist/skill/report-templates/yandex-period-report-excel.md +45 -45
  23. package/dist/skill/report-templates/yandex-period-report.html +1377 -1164
  24. package/dist/skill/report-templates/yandex-period-report.md +26 -27
  25. package/dist/skill/scripts/install.ps1 +3 -3
  26. package/dist/skill/scripts/install.sh +3 -3
  27. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4026,7 +4026,7 @@ var DEFAULT_API_BASE;
4026
4026
  var init_defaults = __esm({
4027
4027
  "src/config/defaults.ts"() {
4028
4028
  "use strict";
4029
- DEFAULT_API_BASE = "https://tso-api.siluzan.com";
4029
+ DEFAULT_API_BASE = "https://tso-api-ci.siluzan.com";
4030
4030
  }
4031
4031
  });
4032
4032
 
@@ -132231,7 +132231,6 @@ function syncOverviewBalanceFields(record2) {
132231
132231
  }
132232
132232
 
132233
132233
  // src/commands/bing-analysis/normalize-bing-rates.ts
132234
- var RATE_FIELD_NAMES2 = /* @__PURE__ */ new Set(["ctr", "conversionRate"]);
132235
132234
  var BING_RATE_BEARING_SECTIONS = /* @__PURE__ */ new Set([
132236
132235
  "overview",
132237
132236
  "device",
@@ -132245,34 +132244,12 @@ var BING_RATE_BEARING_SECTIONS = /* @__PURE__ */ new Set([
132245
132244
  "keywords",
132246
132245
  "search-terms"
132247
132246
  ]);
132248
- function divIfFiniteNumber2(v) {
132249
- return typeof v === "number" && Number.isFinite(v) ? v / 100 : v;
132250
- }
132251
- function divideRatesInPlace2(value, seen) {
132252
- if (value === null || typeof value !== "object") return;
132253
- if (seen.has(value)) return;
132254
- seen.add(value);
132255
- if (Array.isArray(value)) {
132256
- for (const item of value) divideRatesInPlace2(item, seen);
132257
- return;
132258
- }
132259
- const obj = value;
132260
- for (const k of Object.keys(obj)) {
132261
- if (RATE_FIELD_NAMES2.has(k)) {
132262
- obj[k] = divIfFiniteNumber2(obj[k]);
132263
- } else {
132264
- divideRatesInPlace2(obj[k], seen);
132265
- }
132266
- }
132267
- }
132268
- function normalizeBingRateScales(payload, section) {
132269
- if (!BING_RATE_BEARING_SECTIONS.has(section)) return payload;
132270
- divideRatesInPlace2(payload, /* @__PURE__ */ new WeakSet());
132247
+ function normalizeBingRateScales(payload, _section) {
132271
132248
  return payload;
132272
132249
  }
132273
132250
  var BING_RATE_NORMALIZED_OUTLINE_HINTS = [
132274
- "// \u6982\u7387\u5B57\u6BB5\uFF1A`ctr` / `conversionRate` \u5DF2\u7531 bing-analysis CLI \u4ECE\u7F51\u5173\u767E\u5206\u6570\u523B\u5EA6\u5F52\u4E00\u4E3A **0~1 \u5C0F\u6570**\uFF08\u5982 `0.0074` = 0.74%\uFF09\u3002",
132275
- "// \u5199\u300Cx%\u300D\u6587\u6848\uFF1A`(v * 100).toFixed(2) + '%'`\uFF1B**\u7981\u6B62**\u518D \xF7100\uFF0C\u4E5F**\u7981\u6B62**\u628A JSON \u6570\u503C\u5F53\u300C\u5DF2\u662F\u767E\u5206\u6570\u300D\u76F4\u63A5\u52A0 `%`\uFF08\u4F1A \xD7100 \u9519\u8BEF\uFF0C\u5982 0.74% \u663E\u793A\u6210 74%\uFF09\u3002"
132251
+ "// \u6982\u7387\u5B57\u6BB5\uFF1A`ctr` / `conversionRate` \u4E3A\u7F51\u5173\u539F\u751F **0~1 \u5C0F\u6570**\uFF08\u5982 `0.0031` = 0.31%\uFF09\uFF0Cbing-analysis CLI \u672A\u505A\u4EFB\u4F55\u91CF\u7EA7\u53D8\u6362\u3002",
132252
+ "// \u5199\u300Cx%\u300D\u6587\u6848\uFF1A`(v * 100).toFixed(2) + '%'`\uFF1B**\u7981\u6B62**\u518D \xF7100\uFF0C\u4E5F**\u7981\u6B62**\u628A JSON \u6570\u503C\u5F53\u300C\u5DF2\u662F\u767E\u5206\u6570\u300D\u76F4\u63A5\u52A0 `%`\uFF08\u4F1A \xD7100 \u9519\u8BEF\uFF0C\u5982 0.31% \u663E\u793A\u6210 31%\uFF09\u3002"
132276
132253
  ];
132277
132254
  function buildBingOutlineHints(section) {
132278
132255
  if (!BING_RATE_BEARING_SECTIONS.has(section)) return void 0;
@@ -132315,7 +132292,7 @@ function bingRangeTouchesTodayOrYesterday(startDate, endDate) {
132315
132292
  }
132316
132293
  return false;
132317
132294
  }
132318
- function resolveBingDateRange(start, end) {
132295
+ function resolveBingDateRange(start, end, allowToday = false) {
132319
132296
  if (start && end) {
132320
132297
  const s = parseLocalYmd(start);
132321
132298
  const e = parseLocalYmd(end);
@@ -132327,15 +132304,19 @@ function resolveBingDateRange(start, end) {
132327
132304
  console.error("\n\u274C \u5F00\u59CB\u65E5\u671F\u4E0D\u80FD\u665A\u4E8E\u7ED3\u675F\u65E5\u671F\u3002\n");
132328
132305
  process.exit(1);
132329
132306
  }
132330
- if (bingRangeTouchesTodayOrYesterday(start, end)) {
132307
+ if (!allowToday && bingRangeTouchesTodayOrYesterday(start, end)) {
132331
132308
  console.error(
132332
- "\n\u274C Bing \u62A5\u8868\u65F6\u95F4\u8303\u56F4\u4E0D\u80FD\u5305\u542B\u300C\u4ECA\u5929\u300D\u6216\u300C\u6628\u5929\u300D\uFF08\u63A5\u53E3\u9650\u5236\uFF09\u3002\u8BF7\u6539\u7528\u66F4\u65E9\u7684\u7ED3\u675F\u65E5\u671F\uFF0C\u4F8B\u5982\u524D\u5929\u53CA\u4EE5\u524D\u3002\n"
132309
+ "\n\u274C Bing \u62A5\u8868\u65F6\u95F4\u8303\u56F4\u4E0D\u80FD\u5305\u542B\u300C\u4ECA\u5929\u300D\u6216\u300C\u6628\u5929\u300D\uFF08\u63A5\u53E3\u9650\u5236\uFF09\u3002\u8BF7\u6539\u7528\u66F4\u65E9\u7684\u7ED3\u675F\u65E5\u671F\uFF0C\u4F8B\u5982\u524D\u5929\u53CA\u4EE5\u524D\uFF1B\u82E5\u9700\u67E5\u4ECA\u5929/\u8FD1\u5B9E\u65F6\u6570\u636E\uFF0C\u5BF9 campaigns/ad-groups/ads \u4F20 --aggregation \u6216 --return-only-complete-data\u3002\n"
132333
132310
  );
132334
132311
  process.exit(1);
132335
132312
  }
132336
132313
  return { startDate: start, endDate: end };
132337
132314
  }
132338
132315
  if (!start && !end) {
132316
+ if (allowToday) {
132317
+ const today = formatLocalYmd(stripLocalDate(/* @__PURE__ */ new Date()));
132318
+ return { startDate: today, endDate: today };
132319
+ }
132339
132320
  const endD = stripLocalDate(/* @__PURE__ */ new Date());
132340
132321
  endD.setDate(endD.getDate() - 2);
132341
132322
  const startD = new Date(endD);
@@ -132347,6 +132328,16 @@ function resolveBingDateRange(start, end) {
132347
132328
  );
132348
132329
  process.exit(1);
132349
132330
  }
132331
+ function parseOptionalBool(raw) {
132332
+ if (raw === void 0) return void 0;
132333
+ const t = raw.trim().toLowerCase();
132334
+ if (t === "true") return true;
132335
+ if (t === "false") return false;
132336
+ console.error(`
132337
+ \u274C --return-only-complete-data \u987B\u4E3A true \u6216 false\uFF0C\u5B9E\u9645\uFF1A${raw}
132338
+ `);
132339
+ process.exit(1);
132340
+ }
132350
132341
  function assertBingAccountId(id) {
132351
132342
  const t = id.trim();
132352
132343
  if (!t) {
@@ -132370,6 +132361,11 @@ function resolveLimit(raw) {
132370
132361
  async function fetchBingJson(config, url, verbose) {
132371
132362
  return apiFetch2(url, config, {}, verbose);
132372
132363
  }
132364
+ var AGGREGATION_CAPABLE_SECTIONS = /* @__PURE__ */ new Set([
132365
+ "campaigns",
132366
+ "ad-groups",
132367
+ "ads"
132368
+ ]);
132373
132369
  async function fetchBingOverviewPayload(config, id, startDate, endDate, verbose) {
132374
132370
  const params = new URLSearchParams({ startDate, endDate });
132375
132371
  const url = reportingUrl(config, id, "OverviewSectionData", params.toString());
@@ -132447,7 +132443,8 @@ async function fetchBingAudienceMergedPayload(config, id, startDate, endDate, ve
132447
132443
  );
132448
132444
  }
132449
132445
  async function fetchBingSectionPayload(def, opts, config, id) {
132450
- const { startDate, endDate } = resolveBingDateRange(opts.start, opts.end);
132446
+ const allowToday = opts.aggregation !== void 0 || opts.returnOnlyCompleteData !== void 0;
132447
+ const { startDate, endDate } = resolveBingDateRange(opts.start, opts.end, allowToday);
132451
132448
  const verbose = !!opts.verbose;
132452
132449
  if (def.name === "overview") {
132453
132450
  return fetchBingOverviewPayload(config, id, startDate, endDate, verbose);
@@ -132460,6 +132457,12 @@ async function fetchBingSectionPayload(def, opts, config, id) {
132460
132457
  params.set("limit", String(resolveLimit(opts.limit)));
132461
132458
  params.set("orderByCost", "true");
132462
132459
  }
132460
+ if (AGGREGATION_CAPABLE_SECTIONS.has(def.name)) {
132461
+ if (opts.aggregation) params.set("aggregation", opts.aggregation);
132462
+ if (opts.returnOnlyCompleteData !== void 0) {
132463
+ params.set("returnOnlyCompleteData", String(opts.returnOnlyCompleteData));
132464
+ }
132465
+ }
132463
132466
  const url = reportingUrl(config, id, def.segment, params.toString());
132464
132467
  const raw = await fetchBingJson(config, url, verbose);
132465
132468
  return normalizeBingRateScales(raw, def.name);
@@ -132502,7 +132505,8 @@ async function runAllBingSections(opts) {
132502
132505
  console.error("\n\u274C \u6CA1\u6709\u8981\u6267\u884C\u7684 section\uFF08\u8BF7\u68C0\u67E5 --sections / --exclude\uFF09\u3002\n");
132503
132506
  process.exit(1);
132504
132507
  }
132505
- const { startDate, endDate } = resolveBingDateRange(opts.start, opts.end);
132508
+ const allowToday = opts.aggregation !== void 0 || opts.returnOnlyCompleteData !== void 0;
132509
+ const { startDate, endDate } = resolveBingDateRange(opts.start, opts.end, allowToday);
132506
132510
  const concurrency = Math.max(
132507
132511
  1,
132508
132512
  Math.min(typeof opts.concurrency === "number" ? opts.concurrency : 5, 16)
@@ -132565,6 +132569,329 @@ async function runAllBingSections(opts) {
132565
132569
  if (failed > 0) process.exit(2);
132566
132570
  }
132567
132571
 
132572
+ // src/commands/bing-analysis/entities.ts
132573
+ init_auth();
132574
+ init_cli_json_snapshot();
132575
+ init_cli_table();
132576
+ async function runBingAccountStatus(opts) {
132577
+ const id = assertBingAccountId(opts.account);
132578
+ const config = loadConfig(opts.token);
132579
+ const url = reportingUrl(config, id, "account-status", "");
132580
+ let data;
132581
+ try {
132582
+ data = await fetchBingJson(config, url, !!opts.verbose);
132583
+ } catch (err) {
132584
+ console.error(`
132585
+ \u274C \u67E5\u8BE2\u8D26\u6237\u72B6\u6001\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
132586
+ `);
132587
+ process.exit(1);
132588
+ }
132589
+ if (await emitCliJsonOrSnapshot(opts, {
132590
+ section: "bing-account-status",
132591
+ commandLabel: "bing-analysis account-status",
132592
+ commandHint: id,
132593
+ payload: data,
132594
+ idSuffix: id
132595
+ })) {
132596
+ return;
132597
+ }
132598
+ console.log(`
132599
+ Bing \u8D26\u6237\u72B6\u6001\uFF08${id}\uFF09
132600
+ `);
132601
+ printCliTable(
132602
+ [{ accountId: data.accountId ?? id, status: data.status ?? "", timeZone: data.timeZone ?? "" }],
132603
+ [
132604
+ { key: "accountId", header: "\u8D26\u6237ID" },
132605
+ { key: "status", header: "\u751F\u547D\u5468\u671F\u72B6\u6001" },
132606
+ { key: "timeZone", header: "\u65F6\u533A" }
132607
+ ]
132608
+ );
132609
+ console.log();
132610
+ }
132611
+ async function runBingCampaignEntities(opts) {
132612
+ const id = assertBingAccountId(opts.account);
132613
+ const config = loadConfig(opts.token);
132614
+ const url = reportingUrl(config, id, "campaigns", "");
132615
+ let rows;
132616
+ try {
132617
+ rows = await fetchBingJson(config, url, !!opts.verbose);
132618
+ } catch (err) {
132619
+ console.error(`
132620
+ \u274C \u67E5\u8BE2\u7CFB\u5217\u5217\u8868\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
132621
+ `);
132622
+ process.exit(1);
132623
+ }
132624
+ const payload = wrapListJson({
132625
+ page: 1,
132626
+ pageSize: Math.max(rows.length, 1),
132627
+ total: rows.length,
132628
+ items: rows
132629
+ });
132630
+ if (await emitCliJsonOrSnapshot(opts, {
132631
+ section: "bing-campaign-entities",
132632
+ commandLabel: "bing-analysis campaign-entities",
132633
+ commandHint: id,
132634
+ payload,
132635
+ idSuffix: id
132636
+ })) {
132637
+ return;
132638
+ }
132639
+ console.log(`
132640
+ Bing \u5E7F\u544A\u7CFB\u5217\uFF08${id}\uFF0C\u5171 ${rows.length} \u6761\uFF09
132641
+ `);
132642
+ if (rows.length === 0) {
132643
+ console.log(" \u6682\u65E0\u7CFB\u5217\u3002\n");
132644
+ return;
132645
+ }
132646
+ printCliTable(
132647
+ rows.map((r) => ({
132648
+ campaignId: String(r.campaignId),
132649
+ name: r.name ?? "",
132650
+ status: r.status ?? "",
132651
+ dailyBudget: r.dailyBudget != null ? String(r.dailyBudget) : "",
132652
+ isSharedBudget: r.isSharedBudget ? "\u662F" : "\u5426",
132653
+ biddingScheme: r.biddingScheme ?? ""
132654
+ })),
132655
+ [
132656
+ { key: "campaignId", header: "\u7CFB\u5217ID" },
132657
+ { key: "name", header: "\u7CFB\u5217\u540D\u79F0" },
132658
+ { key: "status", header: "\u72B6\u6001" },
132659
+ { key: "dailyBudget", header: "\u65E5\u9884\u7B97" },
132660
+ { key: "isSharedBudget", header: "\u5171\u4EAB\u9884\u7B97" },
132661
+ { key: "biddingScheme", header: "\u51FA\u4EF7\u7B56\u7565" }
132662
+ ]
132663
+ );
132664
+ console.log();
132665
+ }
132666
+ async function runBingAdEntities(opts) {
132667
+ const id = assertBingAccountId(opts.account);
132668
+ if (!opts.campaignId?.trim()) {
132669
+ console.error("\n\u274C --campaign-id \u4E0D\u80FD\u4E3A\u7A7A\uFF08\u4E0D\u5E26 campaignId \u4F1A 400\uFF1B\u5168\u8D26\u6237\u8BF7\u7528 bulk-ads\uFF09\u3002\n");
132670
+ process.exit(1);
132671
+ }
132672
+ const config = loadConfig(opts.token);
132673
+ const params = new URLSearchParams({ campaignId: opts.campaignId.trim() });
132674
+ if (opts.editorialStatus) params.set("editorialStatus", opts.editorialStatus);
132675
+ if (opts.skip !== void 0) params.set("skip", String(opts.skip));
132676
+ if (opts.take !== void 0) params.set("take", String(opts.take));
132677
+ const url = reportingUrl(config, id, "ads", params.toString());
132678
+ let rows;
132679
+ try {
132680
+ rows = await fetchBingJson(config, url, !!opts.verbose);
132681
+ } catch (err) {
132682
+ console.error(`
132683
+ \u274C \u67E5\u8BE2\u5E7F\u544A\u5217\u8868\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
132684
+ `);
132685
+ process.exit(1);
132686
+ }
132687
+ const payload = wrapListJson({
132688
+ page: 1,
132689
+ pageSize: Math.max(rows.length, 1),
132690
+ total: null,
132691
+ items: rows
132692
+ });
132693
+ if (await emitCliJsonOrSnapshot(opts, {
132694
+ section: "bing-ad-entities",
132695
+ commandLabel: "bing-analysis ad-entities",
132696
+ commandHint: `${id}:${opts.campaignId}`,
132697
+ payload,
132698
+ idSuffix: `${id}-${opts.campaignId}`
132699
+ })) {
132700
+ return;
132701
+ }
132702
+ console.log(`
132703
+ Bing \u5E7F\u544A\uFF08${id}\uFF0C\u7CFB\u5217 ${opts.campaignId}\uFF0C\u672C\u9875 ${rows.length} \u6761\uFF0C\u65E0\u603B\u6570\uFF09
132704
+ `);
132705
+ if (rows.length === 0) {
132706
+ console.log(" \u6682\u65E0\u5E7F\u544A\u3002\n");
132707
+ return;
132708
+ }
132709
+ printCliTable(
132710
+ rows.map((r) => ({
132711
+ adId: String(r.adId),
132712
+ adGroupId: String(r.adGroupId),
132713
+ status: r.status ?? "",
132714
+ editorialStatus: r.editorialStatus ?? "",
132715
+ finalUrls: (r.finalUrls ?? []).join(" | ")
132716
+ })),
132717
+ [
132718
+ { key: "adId", header: "\u5E7F\u544AID" },
132719
+ { key: "adGroupId", header: "\u5E7F\u544A\u7EC4ID" },
132720
+ { key: "status", header: "\u72B6\u6001" },
132721
+ { key: "editorialStatus", header: "\u5BA1\u6838\u72B6\u6001" },
132722
+ { key: "finalUrls", header: "\u843D\u5730\u9875 URL" }
132723
+ ]
132724
+ );
132725
+ console.log();
132726
+ }
132727
+ async function runBingBulkAds(opts) {
132728
+ const id = assertBingAccountId(opts.account);
132729
+ const config = loadConfig(opts.token);
132730
+ const params = new URLSearchParams();
132731
+ if (opts.editorialStatus) params.set("editorialStatus", opts.editorialStatus);
132732
+ if (opts.lastSyncTimeUtc) params.set("lastSyncTimeUtc", opts.lastSyncTimeUtc);
132733
+ if (opts.take !== void 0) params.set("take", String(opts.take));
132734
+ const url = reportingUrl(config, id, "bulk/ads", params.toString());
132735
+ let data;
132736
+ try {
132737
+ data = await fetchBingJson(config, url, !!opts.verbose);
132738
+ } catch (err) {
132739
+ console.error(`
132740
+ \u274C Bulk \u4E0B\u8F7D\u5E7F\u544A\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
132741
+ `);
132742
+ process.exit(1);
132743
+ }
132744
+ if (await emitCliJsonOrSnapshot(opts, {
132745
+ section: "bing-bulk-ads",
132746
+ commandLabel: "bing-analysis bulk-ads",
132747
+ commandHint: id,
132748
+ payload: data,
132749
+ idSuffix: id
132750
+ })) {
132751
+ return;
132752
+ }
132753
+ const items2 = data.items ?? [];
132754
+ console.log(
132755
+ `
132756
+ Bing Bulk \u5E7F\u544A\uFF08${id}\uFF09\uFF1AtotalAds=${data.totalAds}\uFF0CtotalMatched=${data.totalMatched}\uFF0C\u672C\u9875 ${items2.length} \u6761${data.totalMatched > items2.length ? "\uFF08\u5DF2\u88AB take \u622A\u65AD\uFF09" : ""}\uFF0CisIncremental=${data.isIncremental}\uFF0CsyncTimeUtc=${data.syncTimeUtc ?? "\u65E0"}
132757
+ `
132758
+ );
132759
+ if (items2.length === 0) {
132760
+ console.log(" \u6682\u65E0\u5E7F\u544A\uFF08\u6216\u589E\u91CF\u4E0B\u8F7D\u533A\u95F4\u5185\u65E0\u53D8\u66F4\uFF09\u3002\n");
132761
+ return;
132762
+ }
132763
+ printCliTable(
132764
+ items2.map((r) => ({
132765
+ adId: String(r.adId),
132766
+ campaignId: r.campaignId != null ? String(r.campaignId) : "",
132767
+ campaignName: r.campaignName ?? "",
132768
+ adGroupName: r.adGroupName ?? "",
132769
+ status: r.status ?? "",
132770
+ editorialStatus: r.editorialStatus ?? "",
132771
+ lastModifiedTime: r.lastModifiedTime ?? "",
132772
+ finalUrls: (r.finalUrls ?? []).join(" | ")
132773
+ })),
132774
+ [
132775
+ { key: "adId", header: "\u5E7F\u544AID" },
132776
+ { key: "campaignId", header: "\u7CFB\u5217ID" },
132777
+ { key: "campaignName", header: "\u7CFB\u5217\u540D\u79F0" },
132778
+ { key: "adGroupName", header: "\u5E7F\u544A\u7EC4\u540D\u79F0" },
132779
+ { key: "status", header: "\u72B6\u6001" },
132780
+ { key: "editorialStatus", header: "\u5BA1\u6838\u72B6\u6001" },
132781
+ { key: "lastModifiedTime", header: "\u6700\u540E\u4FEE\u6539\u65F6\u95F4" },
132782
+ { key: "finalUrls", header: "\u843D\u5730\u9875 URL" }
132783
+ ]
132784
+ );
132785
+ console.log();
132786
+ }
132787
+ async function runBingInsertionOrders(opts) {
132788
+ const id = assertBingAccountId(opts.account);
132789
+ const config = loadConfig(opts.token);
132790
+ const params = new URLSearchParams();
132791
+ if (opts.pageIndex !== void 0) params.set("pageIndex", String(opts.pageIndex));
132792
+ if (opts.pageSize !== void 0) params.set("pageSize", String(opts.pageSize));
132793
+ const url = reportingUrl(config, id, "insertion-orders", params.toString());
132794
+ let data;
132795
+ try {
132796
+ data = await fetchBingJson(config, url, !!opts.verbose);
132797
+ } catch (err) {
132798
+ console.error(`
132799
+ \u274C \u67E5\u8BE2\u63D2\u5165\u8BA2\u5355\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
132800
+ `);
132801
+ process.exit(1);
132802
+ }
132803
+ if (await emitCliJsonOrSnapshot(opts, {
132804
+ section: "bing-insertion-orders",
132805
+ commandLabel: "bing-analysis insertion-orders",
132806
+ commandHint: id,
132807
+ payload: data,
132808
+ idSuffix: id
132809
+ })) {
132810
+ return;
132811
+ }
132812
+ const items2 = data.items ?? [];
132813
+ console.log(
132814
+ `
132815
+ Bing \u63D2\u5165\u8BA2\u5355\uFF08${id}\uFF0C\u7B2C ${data.pageIndex} \u9875\uFF0CpageSize ${data.pageSize}\uFF0C\u672C\u9875 ${items2.length} \u6761\uFF1B\u672C\u63A5\u53E3\u4E0D\u52A0\u603B\uFF0C\u65E0 IO \u65F6\u8BF4\u660E\u65E0\u989D\u5EA6\u4E0A\u9650\uFF09
132816
+ `
132817
+ );
132818
+ if (items2.length === 0) {
132819
+ console.log(" \u6682\u65E0\u63D2\u5165\u8BA2\u5355\u8BB0\u5F55\u3002\n");
132820
+ return;
132821
+ }
132822
+ printCliTable(
132823
+ items2.map((row) => ({
132824
+ id: row.id != null ? String(row.id) : "",
132825
+ name: row.name ?? "",
132826
+ status: row.status ?? "",
132827
+ budgetRemaining: row.budgetRemaining != null ? String(row.budgetRemaining) : "",
132828
+ budgetSpent: row.budgetSpent != null ? String(row.budgetSpent) : "",
132829
+ spendCapAmount: row.spendCapAmount != null ? String(row.spendCapAmount) : "",
132830
+ startDate: row.startDate ?? "",
132831
+ endDate: row.endDate ?? ""
132832
+ })),
132833
+ [
132834
+ { key: "id", header: "IO ID" },
132835
+ { key: "name", header: "\u540D\u79F0" },
132836
+ { key: "status", header: "\u72B6\u6001" },
132837
+ { key: "budgetRemaining", header: "\u5269\u4F59\u989D\u5EA6" },
132838
+ { key: "budgetSpent", header: "\u5DF2\u82B1\u8D39" },
132839
+ { key: "spendCapAmount", header: "\u82B1\u8D39\u4E0A\u9650" },
132840
+ { key: "startDate", header: "\u5F00\u59CB" },
132841
+ { key: "endDate", header: "\u7ED3\u675F" }
132842
+ ]
132843
+ );
132844
+ console.log();
132845
+ }
132846
+ async function runBingMonthlySpend(opts) {
132847
+ const id = assertBingAccountId(opts.account);
132848
+ if (opts.year === void 0 !== (opts.month === void 0)) {
132849
+ console.error("\n\u274C --year \u4E0E --month \u987B\u6210\u5BF9\u4F20\u5165\uFF0C\u6216\u540C\u65F6\u7701\u7565\u4EE5\u67E5\u8BE2\u5317\u4EAC\u5F53\u6708\u3002\n");
132850
+ process.exit(1);
132851
+ }
132852
+ const config = loadConfig(opts.token);
132853
+ const params = new URLSearchParams();
132854
+ if (opts.year !== void 0) params.set("year", String(opts.year));
132855
+ if (opts.month !== void 0) params.set("month", String(opts.month));
132856
+ const url = reportingUrl(config, id, "monthly-spend", params.toString());
132857
+ let data;
132858
+ try {
132859
+ data = await fetchBingJson(config, url, !!opts.verbose);
132860
+ } catch (err) {
132861
+ console.error(`
132862
+ \u274C \u67E5\u8BE2\u6708\u6D88\u8017\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
132863
+ `);
132864
+ process.exit(1);
132865
+ }
132866
+ if (await emitCliJsonOrSnapshot(opts, {
132867
+ section: "bing-monthly-spend",
132868
+ commandLabel: "bing-analysis monthly-spend",
132869
+ commandHint: id,
132870
+ payload: data,
132871
+ idSuffix: id
132872
+ })) {
132873
+ return;
132874
+ }
132875
+ console.log(`
132876
+ Bing \u5B98\u65B9\u6708\u6D88\u8017\uFF08${id}\uFF09
132877
+ `);
132878
+ printCliTable(
132879
+ [
132880
+ {
132881
+ accountId: data.accountId ?? id,
132882
+ monthYear: data.monthYear ?? "",
132883
+ amount: data.amount != null ? String(data.amount) : ""
132884
+ }
132885
+ ],
132886
+ [
132887
+ { key: "accountId", header: "\u8D26\u6237ID" },
132888
+ { key: "monthYear", header: "\u67E5\u8BE2\u6708\u4EFD" },
132889
+ { key: "amount", header: "\u5B98\u65B9\u6708\u82B1\u8D39" }
132890
+ ]
132891
+ );
132892
+ console.log();
132893
+ }
132894
+
132568
132895
  // src/commands/bing-analysis/register-cli.ts
132569
132896
  import { Command as Command3 } from "commander";
132570
132897
 
@@ -133088,6 +133415,11 @@ async function runBingAnalysisRender(opts) {
133088
133415
  }
133089
133416
 
133090
133417
  // src/commands/bing-analysis/register-cli.ts
133418
+ var ACCOUNT_OPTION = [
133419
+ "-a, --account <id>",
133420
+ "Bing mediaCustomerId\uFF08\u6570\u5B57\uFF0C\u4E0E list-accounts -m BingV2 \u4E00\u81F4\uFF09"
133421
+ ];
133422
+ var JSON_OUT_OPTION_DESC = "\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\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";
133091
133423
  function registerBatchCommand2(sectionHelp, aliasHelp) {
133092
133424
  return new Command3("run").description(
133093
133425
  "\u6279\u91CF\u62C9\u53D6 TSO reporting/media-account/BingV2 Section \u6570\u636E\uFF08\u7701\u7565\u5B50\u547D\u4EE4\u540D\u65F6\u9ED8\u8BA4\u6267\u884C\u672C\u547D\u4EE4\uFF09"
@@ -133097,22 +133429,36 @@ function registerBatchCommand2(sectionHelp, aliasHelp) {
133097
133429
  ).requiredOption(
133098
133430
  "--json-out <dir>",
133099
133431
  "\u7ED3\u679C\u843D\u76D8\u76EE\u5F55\uFF1B\u6BCF\u7EF4\u5EA6 `<section>-<accountId>.json` + `report-manifest-<accountId>.json`"
133100
- ).option("-t, --token <token>", "Auth Token").option("--start <date>", "\u5F00\u59CB\u65E5\u671F YYYY-MM-DD\uFF08\u4E0E --end \u540C\u4F20\u6216\u540C\u7701\u7565\uFF1B\u4E0D\u53EF\u542B\u4ECA\u5929/\u6628\u5929\uFF09").option("--end <date>", "\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option(
133432
+ ).option("-t, --token <token>", "Auth Token").option(
133433
+ "--start <date>",
133434
+ "\u5F00\u59CB\u65E5\u671F YYYY-MM-DD\uFF08\u4E0E --end \u540C\u4F20\u6216\u540C\u7701\u7565\uFF1B\u4E0D\u53EF\u542B\u4ECA\u5929/\u6628\u5929\uFF0C\u9664\u975E\u4F20\u4E86 --aggregation \u6216 --return-only-complete-data\uFF09"
133435
+ ).option("--end <date>", "\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option(
133101
133436
  "--sections <list>",
133102
133437
  `\u4EC5\u6267\u884C\u6307\u5B9A\u7EF4\u5EA6\uFF08\u9017\u53F7\u5206\u9694\uFF09\uFF0C\u5982 overview,campaigns,keywords\uFF1B\u7701\u7565=\u5168\u90E8 11 \u4E2A\u3002\u53EF\u9009\uFF1A${sectionHelp}\uFF1B\u522B\u540D\uFF1A${aliasHelp}`
133103
133438
  ).option("--exclude <list>", "\u6392\u9664\u6307\u5B9A\u7EF4\u5EA6\uFF08\u9017\u53F7\u5206\u9694\uFF09\uFF0C\u4E0E --sections \u53EF\u53E0\u52A0").option(
133104
133439
  "--limit <n>",
133105
133440
  "\u4EC5 keywords / search-terms\uFF1A\u6761\u6570\u4E0A\u9650\uFF08\u9ED8\u8BA4 100\uFF0C\u4E0E\u524D\u7AEF KeywordReport/SearchQueryReport \u4E00\u81F4\uFF09",
133106
133441
  (v) => parseInt(v, 10)
133107
- ).option("--concurrency <n>", "\u5E76\u53D1\u6570\uFF0C\u9ED8\u8BA4 5\uFF0C\u4E0A\u9650 16", (v) => parseInt(v, 10)).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
133108
- await runAllBingSections(opts);
133109
- });
133442
+ ).option("--concurrency <n>", "\u5E76\u53D1\u6570\uFF0C\u9ED8\u8BA4 5\uFF0C\u4E0A\u9650 16", (v) => parseInt(v, 10)).option(
133443
+ "--aggregation <value>",
133444
+ "\u4EC5 campaigns/ad-groups/ads\uFF1A\u5B98\u65B9 ReportAggregation\uFF08Summary \u9ED8\u8BA4/Daily/Hourly/Weekly \u7B49\uFF09\uFF1B\u4F20\u5165\u540E\u81EA\u52A8\u5141\u8BB8\u65E5\u671F\u542B\u4ECA\u5929/\u6628\u5929\uFF0C\u7528\u4E8E\u8FD1\u5B9E\u65F6\u76D1\u63A7\u800C\u975Eperiodic\u62A5\u544A"
133445
+ ).option(
133446
+ "--return-only-complete-data <bool>",
133447
+ "\u4EC5 campaigns/ad-groups/ads\uFF1Atrue/false\uFF0C\u663E\u5F0F\u8986\u76D6\u7F51\u5173\u9ED8\u8BA4\u7684\u6309\u65E5\u671F\u81EA\u52A8\u5224\u65AD\uFF1B\u4F20\u5165\u540E\u81EA\u52A8\u5141\u8BB8\u65E5\u671F\u542B\u4ECA\u5929/\u6628\u5929"
133448
+ ).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
133449
+ async (opts) => {
133450
+ await runAllBingSections({
133451
+ ...opts,
133452
+ returnOnlyCompleteData: parseOptionalBool(opts.returnOnlyCompleteData)
133453
+ });
133454
+ }
133455
+ );
133110
133456
  }
133111
133457
  function registerBingAnalysisCommands(program2) {
133112
133458
  const sectionHelp = BING_SECTION_NAMES.join(", ");
133113
133459
  const aliasHelp = Object.keys(BING_SECTION_ALIASES).join(", ");
133114
133460
  const root = program2.command("bing-analysis").description(
133115
- "Bing\uFF08BingV2\uFF09\u8D26\u6237\u5206\u6790\uFF1A\u6279\u91CF\u62C9\u53D6 Section \u6570\u636E\uFF08\u9ED8\u8BA4\uFF0C\u65E5\u671F\u4E0D\u53EF\u542B\u4ECA\u5929/\u6628\u5929\uFF09\uFF0C\u6216\u7531 render \u751F\u6210 bing-period-report.html \u7EC8\u7A3F"
133461
+ "Bing\uFF08BingV2\uFF09\u8D26\u6237\u5206\u6790\uFF1A\u6279\u91CF\u62C9\u53D6 Section \u62A5\u8868\u6570\u636E\uFF08\u9ED8\u8BA4\uFF0C\u65E5\u671F\u4E0D\u53EF\u542B\u4ECA\u5929/\u6628\u5929\uFF0C\u4F20 --aggregation \u53EF\u89E3\u9501\uFF09\u3001\u7531 render \u751F\u6210 bing-period-report.html \u7EC8\u7A3F\uFF0C\u6216\u67E5\u8BE2\u8D26\u6237\u72B6\u6001/\u7CFB\u5217\u4E0E\u5E7F\u544A\u539F\u59CB\u5B9E\u4F53/\u62D2\u5BA1 Bulk \u5DE1\u68C0/IO/\u6708\u6D88\u8017"
133116
133462
  );
133117
133463
  root.addCommand(registerBatchCommand2(sectionHelp, aliasHelp), { isDefault: true });
133118
133464
  root.command("render").description(
@@ -133127,6 +133473,50 @@ function registerBingAnalysisCommands(program2) {
133127
133473
  out: opts.out
133128
133474
  });
133129
133475
  });
133476
+ root.command("account-status").description("\u8D26\u6237\u72B6\u6001\uFF08GET \u2026/account-status\uFF1Bstatus=Active \u4E3A\u6B63\u5E38\u6295\u653E\uFF1B\u4E0D\u5E26\u65E5\u671F\u533A\u95F4\uFF09").requiredOption(...ACCOUNT_OPTION).option("-t, --token <token>", "Auth Token").option("--json-out <path>", JSON_OUT_OPTION_DESC, void 0).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
133477
+ async (opts) => {
133478
+ await runBingAccountStatus(opts);
133479
+ }
133480
+ );
133481
+ root.command("campaign-entities").description(
133482
+ "\u7CFB\u5217\u539F\u59CB\u5B9E\u4F53\uFF08GET \u2026/campaigns\uFF1AdailyBudget/isSharedBudget/status/biddingScheme\uFF1B\u4E0E `run --sections campaigns` \u7684\u82B1\u8D39/\u70B9\u51FB\u7B49\u62A5\u8868\u6570\u503C\u4E0D\u540C\uFF09"
133483
+ ).requiredOption(...ACCOUNT_OPTION).option("-t, --token <token>", "Auth Token").option("--json-out <path>", JSON_OUT_OPTION_DESC, void 0).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
133484
+ async (opts) => {
133485
+ await runBingCampaignEntities(opts);
133486
+ }
133487
+ );
133488
+ root.command("ad-entities").description(
133489
+ "\u5355\u7CFB\u5217\u5E7F\u544A\u5217\u8868\uFF08GET \u2026/ads\uFF1B\u5FC5\u987B\u5E26 --campaign-id\uFF0C\u5426\u5219 400\uFF1B\u5168\u8D26\u6237\u8BF7\u7528 bulk-ads\uFF1B\u4E0E `run --sections ads` \u7684\u82B1\u8D39/\u8F6C\u5316\u7B49\u62A5\u8868\u6570\u503C\u4E0D\u540C\uFF09"
133490
+ ).requiredOption(...ACCOUNT_OPTION).requiredOption(
133491
+ "--campaign-id <id>",
133492
+ "\u7CFB\u5217 campaignId\uFF08\u5FC5\u586B\uFF0C\u6765\u81EA campaign-entities \u6216 --sections campaigns\uFF09"
133493
+ ).option("--editorial-status <status>", "\u5B98\u65B9\u5BA1\u6838\u679A\u4E3E\uFF0C\u5982 Disapproved / Active / Inactive").option("--skip <n>", "\u5206\u9875 skip\uFF0C\u9ED8\u8BA4 0", (v) => parseInt(v, 10)).option("--take <n>", "\u5206\u9875 take\uFF0C\u9ED8\u8BA4 200\uFF0C\u4E0A\u9650 500", (v) => parseInt(v, 10)).option("-t, --token <token>", "Auth Token").option("--json-out <path>", JSON_OUT_OPTION_DESC, void 0).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
133494
+ async (opts) => {
133495
+ await runBingAdEntities(opts);
133496
+ }
133497
+ );
133498
+ root.command("bulk-ads").description(
133499
+ "\u5168\u8D26\u6237 Bulk \u5E7F\u544A\u4E0B\u8F7D\uFF08GET \u2026/bulk/ads\uFF1B\u5F02\u6B65\u4EFB\u52A1\uFF0C\u7F51\u5173\u7B49\u6587\u4EF6\u5C31\u7EEA\u624D\u8FD4\u56DE\uFF0C\u5927\u8D26\u6237\u53EF\u80FD\u8981\u51E0\u5206\u949F\uFF09"
133500
+ ).requiredOption(...ACCOUNT_OPTION).option("--editorial-status <status>", "\u5B98\u65B9\u5BA1\u6838\u679A\u4E3E\uFF0C\u5982 Disapproved\uFF1B\u4E0D\u4F20\u8FD4\u56DE\u5168\u90E8\u5E7F\u544A").option(
133501
+ "--last-sync-time-utc <iso>",
133502
+ "\u4E0A\u6B21\u54CD\u5E94\u7684 syncTimeUtc\uFF0C\u539F\u6837\u56DE\u4F20\u53EA\u4E0B\u8F7D\u6B64\u540E\u53D8\u66F4\u7684\u5B9E\u4F53\uFF1B\u6700\u65E9\u56DE\u6EAF 30 \u5929\uFF0C\u66F4\u65E9\u9700\u7701\u7565\u8D70\u5168\u91CF"
133503
+ ).option("--take <n>", "\u4E0D\u4F20\u6216 0 \u4E0D\u622A\u65AD\uFF1B\u4F20\u6B63\u6570\u65F6\u4E0A\u9650 5000", (v) => parseInt(v, 10)).option("-t, --token <token>", "Auth Token").option("--json-out <path>", JSON_OUT_OPTION_DESC, void 0).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
133504
+ async (opts) => {
133505
+ await runBingBulkAds(opts);
133506
+ }
133507
+ );
133508
+ root.command("insertion-orders").description("\u63D2\u5165\u8BA2\u5355\u5217\u8868\uFF08GET \u2026/insertion-orders\uFF1B\u4E00\u9875\u539F\u6587\u4E0D\u52A0\u603B\uFF0CpageSize \u4E0A\u9650 100\uFF09").requiredOption(...ACCOUNT_OPTION).option("--page-index <n>", "\u9875\u7801\uFF0C\u4ECE 0 \u5F00\u59CB\uFF0C\u9ED8\u8BA4 0", (v) => parseInt(v, 10)).option("--page-size <n>", "\u6BCF\u9875\u6761\u6570\uFF0C\u9ED8\u8BA4/\u4E0A\u9650 100", (v) => parseInt(v, 10)).option("-t, --token <token>", "Auth Token").option("--json-out <path>", JSON_OUT_OPTION_DESC, void 0).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
133509
+ async (opts) => {
133510
+ await runBingInsertionOrders(opts);
133511
+ }
133512
+ );
133513
+ root.command("monthly-spend").description(
133514
+ "\u5B98\u65B9\u6708\u6D88\u8017\uFF08GET \u2026/monthly-spend\uFF1B\u975E\u9884\u4ED8\u4F59\u989D\uFF0C--year/--month \u987B\u6210\u5BF9\u4F20\u5165\u6216\u90FD\u7701\u7565\u67E5\u5317\u4EAC\u5F53\u6708\uFF09"
133515
+ ).requiredOption(...ACCOUNT_OPTION).option("--year <n>", "\u5E74\u4EFD\uFF0C\u987B\u4E0E --month \u6210\u5BF9\u4F20\u5165", (v) => parseInt(v, 10)).option("--month <n>", "\u6708\u4EFD 1-12\uFF0C\u987B\u4E0E --year \u6210\u5BF9\u4F20\u5165", (v) => parseInt(v, 10)).option("-t, --token <token>", "Auth Token").option("--json-out <path>", JSON_OUT_OPTION_DESC, void 0).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
133516
+ async (opts) => {
133517
+ await runBingMonthlySpend(opts);
133518
+ }
133519
+ );
133130
133520
  }
133131
133521
 
133132
133522
  // src/commands/tiktok-analysis/sections.ts
@@ -134136,18 +134526,18 @@ function assertYandexSearchTermsRange(startDate, endDate) {
134136
134526
  process.exit(1);
134137
134527
  }
134138
134528
  if (daysInclusive(s, e) > YANDEX_SEARCH_TERMS_MAX_DAYS) {
134139
- console.error(
134140
- `
134529
+ console.error(`
134141
134530
  \u274C search-terms \u67E5\u8BE2\u8DE8\u5EA6\u4E0D\u80FD\u8D85\u8FC7 ${YANDEX_SEARCH_TERMS_MAX_DAYS} \u5929\u3002
134142
- `
134143
- );
134531
+ `);
134144
134532
  process.exit(1);
134145
134533
  }
134146
134534
  }
134147
134535
  function assertYandexAccountId(id) {
134148
134536
  const t = id.trim();
134149
134537
  if (!t) {
134150
- console.error("\n\u274C --account \u4E0D\u80FD\u4E3A\u7A7A\uFF08Yandex Client-Login / mediaCustomerId\uFF0C\u5982 porg-xxx\uFF09\u3002\n");
134538
+ console.error(
134539
+ "\n\u274C --account \u4E0D\u80FD\u4E3A\u7A7A\uFF08Yandex Client-Login / mediaCustomerId\uFF0C\u5982 porg-xxx\uFF09\u3002\n"
134540
+ );
134151
134541
  process.exit(1);
134152
134542
  }
134153
134543
  return t;
@@ -134398,13 +134788,7 @@ function mapKeywordRows2(payload) {
134398
134788
  }
134399
134789
  function mapSearchTermRows2(payload) {
134400
134790
  return asItems(payload).map(
134401
- (r) => pickMetrics2(r, [
134402
- "searchQuery",
134403
- "matchedKeyword",
134404
- "campaignId",
134405
- "campaignName",
134406
- "adGroupId"
134407
- ])
134791
+ (r) => pickMetrics2(r, ["searchQuery", "matchedKeyword", "campaignId", "campaignName", "adGroupId"])
134408
134792
  );
134409
134793
  }
134410
134794
  function mapGeoRows(payload) {
@@ -134420,7 +134804,9 @@ async function mergeYandexAnalysisSnapshotIntoReport(payload, snapshotDir) {
134420
134804
  const metaAccountId = typeof asRecord26(payload.meta)?.accountId === "string" ? asRecord26(payload.meta)?.accountId : void 0;
134421
134805
  const manifest = await readManifest6(snapshotDir, metaAccountId);
134422
134806
  if (!manifest) {
134423
- throw new Error(`\u672A\u5728 ${absDir} \u627E\u5230 report-manifest*.json\uFF0C\u8BF7\u5148\u6267\u884C yandex-analysis --json-out`);
134807
+ throw new Error(
134808
+ `\u672A\u5728 ${absDir} \u627E\u5230 report-manifest*.json\uFF0C\u8BF7\u5148\u6267\u884C yandex-analysis --json-out`
134809
+ );
134424
134810
  }
134425
134811
  const sectionMap = /* @__PURE__ */ new Map();
134426
134812
  for (const art of manifest.artifacts ?? []) {
@@ -134453,7 +134839,8 @@ async function mergeYandexAnalysisSnapshotIntoReport(payload, snapshotDir) {
134453
134839
  }
134454
134840
  if (overview) {
134455
134841
  if (num10(overview.balance) != null) kpis.balance = round25(num10(overview.balance));
134456
- if (num10(overview.avgDailySpend) != null) kpis.avgDailySpend = round25(num10(overview.avgDailySpend));
134842
+ if (num10(overview.avgDailySpend) != null)
134843
+ kpis.avgDailySpend = round25(num10(overview.avgDailySpend));
134457
134844
  if (num10(overview.activeDays) != null) kpis.activeDays = num10(overview.activeDays);
134458
134845
  if (overview.balanceAsOf != null) kpis.balanceAsOf = overview.balanceAsOf;
134459
134846
  }
@@ -134556,43 +134943,45 @@ async function runAllYandexSections(opts) {
134556
134943
  );
134557
134944
  const cliVersion = getCurrentVersion2();
134558
134945
  const overallT0 = performance8.now();
134559
- const tasks = targets.map((def) => async () => {
134560
- const t0 = performance8.now();
134561
- const hint = endpointHintForYandexSection(def);
134562
- try {
134563
- const raw = await fetchYandexSectionPayload(
134564
- def,
134565
- { ...opts, start: startDate, end: endDate },
134566
- config,
134567
- id
134568
- );
134569
- const payload = def.name === "daily" ? prepareYandexDailyPayload(raw) : raw;
134570
- const summary2 = await writeReportAnalysisSnapshot({
134571
- snapshotDir: opts.jsonOut,
134572
- section: def.name,
134573
- accountId: id,
134574
- dateRange: { start: startDate, end: endDate },
134575
- payload,
134576
- cliVersion,
134577
- outlineExtraHints: buildYandexOutlineHints(def.name)
134578
- });
134579
- return {
134580
- section: def.name,
134581
- ok: true,
134582
- elapsedMs: performance8.now() - t0,
134583
- file: summary2.writtenFiles[0],
134584
- endpointHint: hint
134585
- };
134586
- } catch (err) {
134587
- return {
134588
- section: def.name,
134589
- ok: false,
134590
- elapsedMs: performance8.now() - t0,
134591
- error: err instanceof Error ? err.message : String(err),
134592
- endpointHint: hint
134593
- };
134946
+ const tasks = targets.map(
134947
+ (def) => async () => {
134948
+ const t0 = performance8.now();
134949
+ const hint = endpointHintForYandexSection(def);
134950
+ try {
134951
+ const raw = await fetchYandexSectionPayload(
134952
+ def,
134953
+ { ...opts, start: startDate, end: endDate },
134954
+ config,
134955
+ id
134956
+ );
134957
+ const payload = def.name === "daily" ? prepareYandexDailyPayload(raw) : raw;
134958
+ const summary2 = await writeReportAnalysisSnapshot({
134959
+ snapshotDir: opts.jsonOut,
134960
+ section: def.name,
134961
+ accountId: id,
134962
+ dateRange: { start: startDate, end: endDate },
134963
+ payload,
134964
+ cliVersion,
134965
+ outlineExtraHints: buildYandexOutlineHints(def.name)
134966
+ });
134967
+ return {
134968
+ section: def.name,
134969
+ ok: true,
134970
+ elapsedMs: performance8.now() - t0,
134971
+ file: summary2.writtenFiles[0],
134972
+ endpointHint: hint
134973
+ };
134974
+ } catch (err) {
134975
+ return {
134976
+ section: def.name,
134977
+ ok: false,
134978
+ elapsedMs: performance8.now() - t0,
134979
+ error: err instanceof Error ? err.message : String(err),
134980
+ endpointHint: hint
134981
+ };
134982
+ }
134594
134983
  }
134595
- });
134984
+ );
134596
134985
  const results = await runWithConcurrency6(tasks, concurrency);
134597
134986
  const succeeded = results.filter((r) => r.ok).length;
134598
134987
  const failed = results.length - succeeded;
@@ -134697,16 +135086,6 @@ function validateYandexPeriodReportContent(data) {
134697
135086
  if (!textLen7(meta.accountId)) {
134698
135087
  pushMissing6(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
134699
135088
  }
134700
- const executiveSummary = asArray7(narrative.executiveSummary).filter((p) => textLen7(p) > 0);
134701
- if (executiveSummary.length < 1) {
134702
- pushMissing6(
134703
- missing,
134704
- "narrative-executive-summary",
134705
- "\u6267\u884C\u6458\u8981",
134706
- "narrative.executiveSummary",
134707
- "\u22651 \u6BB5\u6267\u884C\u6458\u8981\uFF0C\u6982\u8FF0\u672C\u671F\u6D88\u8017/\u70B9\u51FB/\u8F6C\u5316/CTR/CPC \u8D70\u52BF"
134708
- );
134709
- }
134710
135089
  const sectionAnalysisCounts = {};
134711
135090
  const sectionSuggestionCounts = {};
134712
135091
  for (const key of SECTION_KEYS4) {
@@ -134807,7 +135186,6 @@ function validateYandexPeriodReportContent(data) {
134807
135186
  ok: missing.length === 0,
134808
135187
  missing,
134809
135188
  stats: {
134810
- executiveSummaryCount: executiveSummary.length,
134811
135189
  recommendationCount: recommendations.length,
134812
135190
  sectionAnalysisCounts,
134813
135191
  sectionSuggestionCounts,
@@ -134893,10 +135271,8 @@ async function runYandexAnalysisRender(opts) {
134893
135271
  `);
134894
135272
  const { stats: stats2 } = contentCheck;
134895
135273
  const sectionSummary = Object.entries(stats2.sectionAnalysisCounts).map(([key, count]) => `${key} \u603B\u7ED3${count}/\u5EFA\u8BAE${stats2.sectionSuggestionCounts[key] ?? 0}`).join("\uFF5C");
134896
- console.error(
134897
- ` \u7EDF\u8BA1\uFF1A\u6267\u884C\u6458\u8981 ${stats2.executiveSummaryCount} \u6BB5\uFF5C\u4F18\u5316\u5EFA\u8BAE ${stats2.recommendationCount} \u6761\uFF5C${sectionSummary}
134898
- `
134899
- );
135274
+ console.error(` \u7EDF\u8BA1\uFF1A\u4F18\u5316\u5EFA\u8BAE ${stats2.recommendationCount} \u6761\uFF5C${sectionSummary}
135275
+ `);
134900
135276
  process.exit(1);
134901
135277
  }
134902
135278
  const templatePath = yandexPeriodReportTemplatePath();
@@ -134921,7 +135297,7 @@ async function runYandexAnalysisRender(opts) {
134921
135297
  \u2705 Yandex \u5E7F\u544A\u8D26\u6237\u5206\u6790 HTML \u62A5\u544A\u5DF2\u751F\u6210\uFF1A${outPath}
134922
135298
  `);
134923
135299
  console.log(
134924
- ` \u5FC5\u542B\u5B57\u6BB5\u5DF2\u5168\u90E8\u8986\u76D6\uFF5C\u6267\u884C\u6458\u8981 ${stats.executiveSummaryCount} \u6BB5\uFF5C\u4F18\u5316\u5EFA\u8BAE ${stats.recommendationCount} \u6761\uFF5C8 \u4E2A\u5206\u6790\u7AE0\u8282\u5747\u5DF2\u9F50\u5168
135300
+ ` \u5FC5\u542B\u5B57\u6BB5\u5DF2\u5168\u90E8\u8986\u76D6\uFF5C\u4F18\u5316\u5EFA\u8BAE ${stats.recommendationCount} \u6761\uFF5C8 \u4E2A\u5206\u6790\u7AE0\u8282\u5747\u5DF2\u9F50\u5168
134925
135301
  `
134926
135302
  );
134927
135303
  console.log("\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00 HTML \u6587\u4EF6\u5373\u53EF\u67E5\u770B\u5B8C\u6574\u7AE0\u8282\uFF08\u6837\u5F0F\u5BF9\u9F50\u5F00\u53D1\u6837\u4F8B\uFF09\u3002\n");
@@ -134929,9 +135305,7 @@ async function runYandexAnalysisRender(opts) {
134929
135305
 
134930
135306
  // src/commands/yandex-analysis/register-cli.ts
134931
135307
  function registerBatchCommand4(sectionHelp, aliasHelp) {
134932
- return new Command5("run").description(
134933
- "\u6279\u91CF\u62C9\u53D6 YandexAPI /yandex-analysis \u5404\u7EF4\u5EA6\uFF08\u7701\u7565\u5B50\u547D\u4EE4\u540D\u65F6\u9ED8\u8BA4\u6267\u884C\u672C\u547D\u4EE4\uFF09"
134934
- ).requiredOption(
135308
+ return new Command5("run").description("\u6279\u91CF\u62C9\u53D6 YandexAPI /yandex-analysis \u5404\u7EF4\u5EA6\uFF08\u7701\u7565\u5B50\u547D\u4EE4\u540D\u65F6\u9ED8\u8BA4\u6267\u884C\u672C\u547D\u4EE4\uFF09").requiredOption(
134935
135309
  "-a, --account <id>",
134936
135310
  "Yandex Client-Login / mediaCustomerId\uFF08\u5982 porg-xxx\uFF0C\u4E0E list-accounts -m Yandex \u4E00\u81F4\uFF09"
134937
135311
  ).requiredOption(