siluzan-tso-cli 1.1.62 → 1.1.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -438,9 +438,9 @@ var require_semver = __commonJS({
438
438
  // This probably shouldn't be used publicly.
439
439
  // 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction.
440
440
  case "pre": {
441
- const base = Number(identifierBase) ? 1 : 0;
441
+ const base2 = Number(identifierBase) ? 1 : 0;
442
442
  if (this.prerelease.length === 0) {
443
- this.prerelease = [base];
443
+ this.prerelease = [base2];
444
444
  } else {
445
445
  let i = this.prerelease.length;
446
446
  while (--i >= 0) {
@@ -453,11 +453,11 @@ var require_semver = __commonJS({
453
453
  if (identifier === this.prerelease.join(".") && identifierBase === false) {
454
454
  throw new Error("invalid increment argument: identifier already exists");
455
455
  }
456
- this.prerelease.push(base);
456
+ this.prerelease.push(base2);
457
457
  }
458
458
  }
459
459
  if (identifier) {
460
- let prerelease = [identifier, base];
460
+ let prerelease = [identifier, base2];
461
461
  if (identifierBase === false) {
462
462
  prerelease = [identifier];
463
463
  }
@@ -3058,8 +3058,8 @@ async function writeCliJsonSnapshot(params) {
3058
3058
  if (fileName.toLowerCase() === manifestFile.toLowerCase()) {
3059
3059
  throw new Error(`\u8F93\u51FA\u6587\u4EF6\u4E0D\u80FD\u547D\u540D\u4E3A ${manifestFile}\uFF0C\u4E0E\u6E05\u5355\u6587\u4EF6\u51B2\u7A81`);
3060
3060
  }
3061
- const base = fileName.slice(0, -".json".length);
3062
- section = normalizeCliSnapshotSection(base || params.section);
3061
+ const base2 = fileName.slice(0, -".json".length);
3062
+ section = normalizeCliSnapshotSection(base2 || params.section);
3063
3063
  } else {
3064
3064
  absDir = await ensureSnapshotDir(trimmed);
3065
3065
  section = normalizeCliSnapshotSection(params.section);
@@ -3374,8 +3374,8 @@ function sanitizeNamespace(ns) {
3374
3374
  }
3375
3375
  function getWriteAuditRootDir(namespace) {
3376
3376
  const ns = sanitizeNamespace(namespace);
3377
- const base = process.env.SILUZAN_WRITE_AUDIT_BASE?.trim();
3378
- if (base) return path5.join(path5.resolve(base), ns);
3377
+ const base2 = process.env.SILUZAN_WRITE_AUDIT_BASE?.trim();
3378
+ if (base2) return path5.join(path5.resolve(base2), ns);
3379
3379
  if (ns === "tso") {
3380
3380
  const legacyOverride = process.env.SILUZAN_TSO_AUDIT_DIR?.trim();
3381
3381
  if (legacyOverride) return path5.resolve(legacyOverride);
@@ -8607,7 +8607,7 @@ var init_normalize_overview = __esm({
8607
8607
  function isRecord3(value) {
8608
8608
  return value != null && typeof value === "object" && !Array.isArray(value);
8609
8609
  }
8610
- function finiteNumber(value) {
8610
+ function finiteNumber2(value) {
8611
8611
  const n = typeof value === "number" ? value : Number(value);
8612
8612
  return Number.isFinite(n) ? n : 0;
8613
8613
  }
@@ -8624,16 +8624,16 @@ function targetedLocationsToGeographic(raw) {
8624
8624
  countryOrRegion: typeof row.locationName === "string" ? row.locationName : "",
8625
8625
  campaignId: row.campaignId == null ? void 0 : String(row.campaignId),
8626
8626
  campaignName: typeof row.campaignName === "string" ? row.campaignName : "",
8627
- impressions: finiteNumber(row.impressions),
8628
- clicks: finiteNumber(row.clicks),
8629
- ctr: finiteNumber(row.ctr) / 100,
8630
- spend: finiteNumber(row.spend),
8631
- conversions: finiteNumber(row.conversions),
8632
- allConversions: finiteNumber(row.allConversions),
8633
- averageCpc: finiteNumber(row.averageCpc),
8634
- conversionRate: finiteNumber(row.conversionRate),
8635
- costPerConversion: finiteNumber(row.costPerConversion),
8636
- interactions: finiteNumber(row.interactions),
8627
+ impressions: finiteNumber2(row.impressions),
8628
+ clicks: finiteNumber2(row.clicks),
8629
+ ctr: finiteNumber2(row.ctr) / 100,
8630
+ spend: finiteNumber2(row.spend),
8631
+ conversions: finiteNumber2(row.conversions),
8632
+ allConversions: finiteNumber2(row.allConversions),
8633
+ averageCpc: finiteNumber2(row.averageCpc),
8634
+ conversionRate: finiteNumber2(row.conversionRate),
8635
+ costPerConversion: finiteNumber2(row.costPerConversion),
8636
+ interactions: finiteNumber2(row.interactions),
8637
8637
  interactionRate: row.interactionRate ?? null
8638
8638
  }));
8639
8639
  return { countries };
@@ -104250,7 +104250,7 @@ function narrativeClaimsMobileSpendLeads(text3) {
104250
104250
  if (!t.includes("\u79FB\u52A8")) return false;
104251
104251
  return /移动(?:端|设备)?(?:为|是)主要消耗/.test(t) || /移动(?:端|设备)?为主要(?:消耗)?设备/.test(t) || /移动(?:端|设备)?(?:消耗|花费|费用|流量)?占比高/.test(t);
104252
104252
  }
104253
- function asRecord19(value) {
104253
+ function asRecord20(value) {
104254
104254
  if (value && typeof value === "object" && !Array.isArray(value)) return value;
104255
104255
  return null;
104256
104256
  }
@@ -104258,16 +104258,16 @@ function stringList(value) {
104258
104258
  return (Array.isArray(value) ? value : []).map((item) => typeof item === "string" ? item.trim() : "").filter(Boolean);
104259
104259
  }
104260
104260
  function collectOkkiNarrativeText(data) {
104261
- const narrative = asRecord19(data.narrative) ?? {};
104261
+ const narrative = asRecord20(data.narrative) ?? {};
104262
104262
  const parts = [];
104263
- const sheetAnalysis = asRecord19(narrative.sheetAnalysis) ?? {};
104263
+ const sheetAnalysis = asRecord20(narrative.sheetAnalysis) ?? {};
104264
104264
  for (const block of Object.values(sheetAnalysis)) {
104265
- const rec = asRecord19(block);
104265
+ const rec = asRecord20(block);
104266
104266
  parts.push(...stringList(rec?.summary), ...stringList(rec?.suggestions));
104267
104267
  }
104268
- const review = asRecord19(narrative.review) ?? {};
104268
+ const review = asRecord20(narrative.review) ?? {};
104269
104269
  for (const block of Object.values(review)) {
104270
- const rec = asRecord19(block);
104270
+ const rec = asRecord20(block);
104271
104271
  for (const key of ["overview", "summary", "suggestion"]) {
104272
104272
  const value = rec?.[key];
104273
104273
  if (typeof value === "string" && value.trim()) parts.push(value.trim());
@@ -104284,7 +104284,7 @@ var init_okki_display = __esm({
104284
104284
  // src/commands/google-analysis/merge-snapshot.ts
104285
104285
  import * as fs28 from "fs/promises";
104286
104286
  import * as path33 from "path";
104287
- function asRecord20(value) {
104287
+ function asRecord21(value) {
104288
104288
  if (value && typeof value === "object" && !Array.isArray(value)) {
104289
104289
  return value;
104290
104290
  }
@@ -104411,13 +104411,13 @@ function periodMetricsFromRow(row) {
104411
104411
  }
104412
104412
  function items(envelope) {
104413
104413
  if (!envelope || !Array.isArray(envelope.items)) return [];
104414
- return envelope.items.filter((row) => asRecord20(row) !== null);
104414
+ return envelope.items.filter((row) => asRecord21(row) !== null);
104415
104415
  }
104416
104416
  function record(envelope) {
104417
104417
  return envelope?.record ?? null;
104418
104418
  }
104419
104419
  function pickMetricRow(row, extraFields) {
104420
- const base = {
104420
+ const base2 = {
104421
104421
  spend: num4(row.spend) ?? 0,
104422
104422
  impressions: num4(row.impressions) ?? 0,
104423
104423
  clicks: num4(row.clicks) ?? 0,
@@ -104427,9 +104427,9 @@ function pickMetricRow(row, extraFields) {
104427
104427
  costPerConversion: num4(row.costPerConversion)
104428
104428
  };
104429
104429
  for (const f of extraFields) {
104430
- if (row[f] !== void 0) base[f] = row[f];
104430
+ if (row[f] !== void 0) base2[f] = row[f];
104431
104431
  }
104432
- return base;
104432
+ return base2;
104433
104433
  }
104434
104434
  function sumCampaignRowsToPeriodKpis(rows) {
104435
104435
  if (rows.length === 0) return null;
@@ -104458,14 +104458,14 @@ function sumCampaignRowsToPeriodKpis(rows) {
104458
104458
  }
104459
104459
  async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
104460
104460
  const absDir = path33.resolve(snapshotDir);
104461
- const metaAccountId = typeof asRecord20(payload.meta)?.accountId === "string" ? asRecord20(payload.meta)?.accountId : void 0;
104461
+ const metaAccountId = typeof asRecord21(payload.meta)?.accountId === "string" ? asRecord21(payload.meta)?.accountId : void 0;
104462
104462
  const manifest = await readManifest(snapshotDir, metaAccountId);
104463
104463
  if (!manifest) {
104464
104464
  throw new Error(`\u672A\u5728 ${absDir} \u627E\u5230 manifest*.json\uFF0C\u8BF7\u5148\u6267\u884C google-analysis --json-out`);
104465
104465
  }
104466
104466
  const accountId = manifest.googleAnalysis?.accountId ?? metaAccountId;
104467
104467
  const dateRange = manifest.googleAnalysis?.dateRange;
104468
- const preferredDateTag = dateTagFromRange(dateRange) ?? dateTagFromMeta(asRecord20(payload.meta) ?? void 0);
104468
+ const preferredDateTag = dateTagFromRange(dateRange) ?? dateTagFromMeta(asRecord21(payload.meta) ?? void 0);
104469
104469
  const sectionMap = /* @__PURE__ */ new Map();
104470
104470
  for (const art of manifest.artifacts ?? []) {
104471
104471
  const data = await loadSectionFile(absDir, art.file);
@@ -104473,8 +104473,8 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
104473
104473
  }
104474
104474
  await recoverMissingReportSections(sectionMap, absDir, accountId, preferredDateTag);
104475
104475
  const overviewRecord = record(sectionMap.get("overview"));
104476
- const currentPeriod = asRecord20(overviewRecord?.currentPeriod);
104477
- const previousPeriod = asRecord20(overviewRecord?.previousPeriod);
104476
+ const currentPeriod = asRecord21(overviewRecord?.currentPeriod);
104477
+ const previousPeriod = asRecord21(overviewRecord?.previousPeriod);
104478
104478
  const meta = { ...payload.meta ?? {} };
104479
104479
  if (!meta.accountId && accountId) meta.accountId = accountId;
104480
104480
  if (!meta.currency) {
@@ -104630,7 +104630,7 @@ function textLen(value) {
104630
104630
  function asArray(value) {
104631
104631
  return Array.isArray(value) ? value : [];
104632
104632
  }
104633
- function asRecord21(value) {
104633
+ function asRecord22(value) {
104634
104634
  if (value && typeof value === "object" && !Array.isArray(value)) {
104635
104635
  return value;
104636
104636
  }
@@ -104644,7 +104644,7 @@ function pushMissing(missing, id, chapter, dimension, hint) {
104644
104644
  }
104645
104645
  function validateOkkiWeeklyReportContent(data) {
104646
104646
  const missing = [];
104647
- const meta = asRecord21(data.meta) ?? {};
104647
+ const meta = asRecord22(data.meta) ?? {};
104648
104648
  if (!textLen(meta.accountId)) {
104649
104649
  pushMissing(
104650
104650
  missing,
@@ -104654,7 +104654,7 @@ function validateOkkiWeeklyReportContent(data) {
104654
104654
  "meta.accountId \u5FC5\u586B\uFF1B\u53EF\u7531 --snapshot-dir \u5408\u5E76 overview/manifest"
104655
104655
  );
104656
104656
  }
104657
- const snapshotSections = asRecord21(data.snapshot?.sections) ?? {};
104657
+ const snapshotSections = asRecord22(data.snapshot?.sections) ?? {};
104658
104658
  const snapshotPresent = {};
104659
104659
  for (const section of OKKI_SNAPSHOT_SECTIONS) {
104660
104660
  const present = snapshotSections[section] === true;
@@ -104669,12 +104669,12 @@ function validateOkkiWeeklyReportContent(data) {
104669
104669
  );
104670
104670
  }
104671
104671
  }
104672
- const narrative = asRecord21(data.narrative) ?? {};
104673
- const sheetAnalysis = asRecord21(narrative.sheetAnalysis) ?? {};
104674
- const review = asRecord21(narrative.review) ?? {};
104672
+ const narrative = asRecord22(data.narrative) ?? {};
104673
+ const sheetAnalysis = asRecord22(narrative.sheetAnalysis) ?? {};
104674
+ const review = asRecord22(narrative.review) ?? {};
104675
104675
  const sheetAnalysisCounts = {};
104676
104676
  for (const key of OKKI_SHEET_KEYS) {
104677
- const block = asRecord21(sheetAnalysis[key]);
104677
+ const block = asRecord22(sheetAnalysis[key]);
104678
104678
  const summary = stringList2(block?.summary);
104679
104679
  const suggestions = stringList2(block?.suggestions);
104680
104680
  sheetAnalysisCounts[key] = { summary: summary.length, suggestions: suggestions.length };
@@ -104700,7 +104700,7 @@ function validateOkkiWeeklyReportContent(data) {
104700
104700
  }
104701
104701
  const reviewFilled = {};
104702
104702
  for (const key of OKKI_REVIEW_KEYS) {
104703
- const block = asRecord21(review[key]);
104703
+ const block = asRecord22(review[key]);
104704
104704
  const overview = textLen(block?.overview);
104705
104705
  const summary = textLen(block?.summary);
104706
104706
  const suggestion = textLen(block?.suggestion);
@@ -104735,7 +104735,7 @@ function validateOkkiWeeklyReportContent(data) {
104735
104735
  }
104736
104736
  }
104737
104737
  const deviceRows2 = Array.isArray(data.tables?.devices) ? data.tables.devices : [];
104738
- const deviceSpend = summarizeOkkiDeviceSpend(deviceRows2.filter((row) => asRecord21(row) !== null));
104738
+ const deviceSpend = summarizeOkkiDeviceSpend(deviceRows2.filter((row) => asRecord22(row) !== null));
104739
104739
  if (deviceSpend.total > 0 && deviceSpend.desktop >= deviceSpend.mobile && narrativeClaimsMobileSpendLeads(collectOkkiNarrativeText(data))) {
104740
104740
  pushMissing(
104741
104741
  missing,
@@ -104824,7 +104824,7 @@ function round25(value) {
104824
104824
  }
104825
104825
  function items2(envelope) {
104826
104826
  if (!envelope || !Array.isArray(envelope.items)) return [];
104827
- return envelope.items.filter((row) => asRecord21(row) !== null);
104827
+ return envelope.items.filter((row) => asRecord22(row) !== null);
104828
104828
  }
104829
104829
  function dateTagFromRange2(dateRange) {
104830
104830
  if (!dateRange || dateRange.mode !== "range") return void 0;
@@ -104868,14 +104868,14 @@ async function loadSectionFile2(snapshotDir, file) {
104868
104868
  }
104869
104869
  async function mergeOkkiSnapshotIntoReport(payload, snapshotDir) {
104870
104870
  const absDir = path34.resolve(snapshotDir);
104871
- const metaAccountId = typeof asRecord21(payload.meta)?.accountId === "string" ? asRecord21(payload.meta)?.accountId : void 0;
104871
+ const metaAccountId = typeof asRecord22(payload.meta)?.accountId === "string" ? asRecord22(payload.meta)?.accountId : void 0;
104872
104872
  const manifest = await readManifest2(absDir, metaAccountId);
104873
104873
  if (!manifest) {
104874
104874
  throw new Error(`\u672A\u5728 ${absDir} \u627E\u5230 manifest*.json\uFF0C\u8BF7\u5148\u6267\u884C google-analysis --json-out`);
104875
104875
  }
104876
104876
  const accountId = manifest.googleAnalysis?.accountId ?? metaAccountId;
104877
104877
  const dateRange = manifest.googleAnalysis?.dateRange;
104878
- const preferredDateTag = dateTagFromRange2(dateRange) ?? dateTagFromMeta2(asRecord21(payload.meta) ?? void 0);
104878
+ const preferredDateTag = dateTagFromRange2(dateRange) ?? dateTagFromMeta2(asRecord22(payload.meta) ?? void 0);
104879
104879
  const sectionMap = /* @__PURE__ */ new Map();
104880
104880
  for (const art of manifest.artifacts ?? []) {
104881
104881
  const data = await loadSectionFile2(absDir, art.file);
@@ -104901,7 +104901,7 @@ async function mergeOkkiSnapshotIntoReport(payload, snapshotDir) {
104901
104901
  snapshotPresent[section] = sectionMap.has(section);
104902
104902
  }
104903
104903
  const overviewRecord = sectionMap.get("overview")?.record ?? null;
104904
- const currentPeriod = asRecord21(overviewRecord?.currentPeriod);
104904
+ const currentPeriod = asRecord22(overviewRecord?.currentPeriod);
104905
104905
  const meta = { ...payload.meta ?? {} };
104906
104906
  if (!meta.accountId && accountId) meta.accountId = accountId;
104907
104907
  if (!meta.currency) {
@@ -105058,18 +105058,18 @@ function prefixLines(items3, firstPrefix) {
105058
105058
  });
105059
105059
  }
105060
105060
  function analysisLines(data, key) {
105061
- const block = asRecord21(asRecord21(data.narrative)?.sheetAnalysis)?.[key];
105062
- const rec = asRecord21(block);
105061
+ const block = asRecord22(asRecord22(data.narrative)?.sheetAnalysis)?.[key];
105062
+ const rec = asRecord22(block);
105063
105063
  return [
105064
105064
  ...prefixLines(stringList2(rec?.summary), "\u603B\u7ED3\uFF1A"),
105065
105065
  ...prefixLines(stringList2(rec?.suggestions), "\u5EFA\u8BAE\uFF1A")
105066
105066
  ];
105067
105067
  }
105068
105068
  function reviewLines(data) {
105069
- const review = asRecord21(asRecord21(data.narrative)?.review) ?? {};
105069
+ const review = asRecord22(asRecord22(data.narrative)?.review) ?? {};
105070
105070
  const lines = [];
105071
105071
  OKKI_REVIEW_KEYS.forEach((key, idx) => {
105072
- const block = asRecord21(review[key]) ?? {};
105072
+ const block = asRecord22(review[key]) ?? {};
105073
105073
  lines.push(`${idx + 1}\u3001${REVIEW_LABELS2[key]}\uFF1A${str(block.overview, "")}`);
105074
105074
  lines.push(` \u603B\u7ED3\uFF1A${str(block.summary, "")}`);
105075
105075
  lines.push(` \u5EFA\u8BAE\uFF1A${str(block.suggestion, "")}`);
@@ -105204,7 +105204,7 @@ function geoRows(data, lang = "zh") {
105204
105204
  });
105205
105205
  }
105206
105206
  function buildOkkiWeeklySheetDrafts(data, lang = "zh") {
105207
- const meta = asRecord21(data.meta) ?? {};
105207
+ const meta = asRecord22(data.meta) ?? {};
105208
105208
  const period = formatOkkiDateRange(str(meta.startDate, ""), str(meta.endDate, ""), lang);
105209
105209
  const campaigns = campaignRows(data);
105210
105210
  const drafts = {
@@ -105479,7 +105479,7 @@ function textLen2(value) {
105479
105479
  function asArray2(value) {
105480
105480
  return Array.isArray(value) ? value : [];
105481
105481
  }
105482
- function asRecord22(value) {
105482
+ function asRecord23(value) {
105483
105483
  if (value && typeof value === "object" && !Array.isArray(value)) {
105484
105484
  return value;
105485
105485
  }
@@ -105490,9 +105490,9 @@ function pushMissing2(missing, id, chapter, dimension, hint) {
105490
105490
  }
105491
105491
  function validateGooglePeriodReportContent(data) {
105492
105492
  const missing = [];
105493
- const meta = asRecord22(data.meta) ?? {};
105494
- const narrative = asRecord22(data.narrative) ?? {};
105495
- const sections = asRecord22(narrative.sections) ?? {};
105493
+ const meta = asRecord23(data.meta) ?? {};
105494
+ const narrative = asRecord23(data.narrative) ?? {};
105495
+ const sections = asRecord23(narrative.sections) ?? {};
105496
105496
  if (!textLen2(meta.accountId)) {
105497
105497
  pushMissing2(
105498
105498
  missing,
@@ -105512,7 +105512,7 @@ function validateGooglePeriodReportContent(data) {
105512
105512
  "\u22651 \u6BB5\u6267\u884C\u6458\u8981\uFF0C\u6982\u8FF0\u672C\u671F\u6D88\u8017/\u8F6C\u5316/CTR/CPA \u8D70\u52BF"
105513
105513
  );
105514
105514
  }
105515
- const kpis = asRecord22(data.kpis);
105515
+ const kpis = asRecord23(data.kpis);
105516
105516
  const hasCoreKpi = ["cost", "impressions", "clicks"].some(
105517
105517
  (key) => Number.isFinite(Number(kpis?.[key]))
105518
105518
  );
@@ -105525,7 +105525,7 @@ function validateGooglePeriodReportContent(data) {
105525
105525
  "\u81F3\u5C11\u4E00\u9879\u987B\u4E3A\u6709\u6548\u6570\u5B57\uFF1B\u8BF7\u52A0 --snapshot-dir \u4ECE google-analysis \u5FEB\u7167\u5408\u5E76\uFF08\u52FF\u624B\u586B HTML\uFF09"
105526
105526
  );
105527
105527
  }
105528
- const negativeRows = asRecord22(data.tables)?.negativeKeywords;
105528
+ const negativeRows = asRecord23(data.tables)?.negativeKeywords;
105529
105529
  if (!Array.isArray(negativeRows)) {
105530
105530
  pushMissing2(
105531
105531
  missing,
@@ -105538,7 +105538,7 @@ function validateGooglePeriodReportContent(data) {
105538
105538
  const sectionAnalysisCounts = {};
105539
105539
  const sectionSuggestionCounts = {};
105540
105540
  for (const key of SECTION_KEYS) {
105541
- const section = asRecord22(sections[key]);
105541
+ const section = asRecord23(sections[key]);
105542
105542
  const analysis = asArray2(section?.analysis).filter((s) => textLen2(s) > 0);
105543
105543
  const suggestions = asArray2(section?.suggestions).filter((s) => textLen2(s) > 0);
105544
105544
  sectionAnalysisCounts[key] = analysis.length;
@@ -105564,7 +105564,7 @@ function validateGooglePeriodReportContent(data) {
105564
105564
  }
105565
105565
  const recommendations = asArray2(narrative.recommendations).filter((r) => {
105566
105566
  if (typeof r === "string") return textLen2(r) > 0;
105567
- const rec = asRecord22(r);
105567
+ const rec = asRecord23(r);
105568
105568
  return textLen2(rec?.content) > 0;
105569
105569
  });
105570
105570
  if (recommendations.length < 3) {
@@ -105655,7 +105655,7 @@ async function readJsonFile3(filePath) {
105655
105655
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
105656
105656
  }
105657
105657
  }
105658
- function asRecord23(value) {
105658
+ function asRecord24(value) {
105659
105659
  if (value && typeof value === "object" && !Array.isArray(value)) {
105660
105660
  return value;
105661
105661
  }
@@ -105671,7 +105671,7 @@ function injectReportData2(html, payload, lang) {
105671
105671
  }
105672
105672
  async function runGoogleAnalysisRender(opts) {
105673
105673
  const dataPath = path36.resolve(opts.dataFile);
105674
- let data = asRecord23(await readJsonFile3(dataPath));
105674
+ let data = asRecord24(await readJsonFile3(dataPath));
105675
105675
  if (opts.snapshotDir?.trim()) {
105676
105676
  data = await mergeGoogleAnalysisSnapshotIntoReport(data, path36.resolve(opts.snapshotDir));
105677
105677
  }
@@ -106416,8 +106416,8 @@ var init_batch_runner = __esm({
106416
106416
  shouldDowngrade(now = Date.now()) {
106417
106417
  if (this.window.length < this.opts.windowSize) return false;
106418
106418
  if (now - this.lastDowngradeAt < this.opts.cooldownMs) return false;
106419
- const fail4 = this.window.filter((s) => !s).length;
106420
- const rate2 = fail4 / this.window.length;
106419
+ const fail5 = this.window.filter((s) => !s).length;
106420
+ const rate2 = fail5 / this.window.length;
106421
106421
  if (rate2 >= this.opts.errorRateThreshold) {
106422
106422
  this.lastDowngradeAt = now;
106423
106423
  this.window.length = 0;
@@ -106998,8 +106998,8 @@ function resolveSectionList(sections, exclude) {
106998
106998
  );
106999
106999
  process.exit(1);
107000
107000
  }
107001
- const base = include.length > 0 ? SECTIONS.filter((s) => include.includes(s.name)) : SECTIONS;
107002
- return base.filter((s) => !drop.has(s.name));
107001
+ const base2 = include.length > 0 ? SECTIONS.filter((s) => include.includes(s.name)) : SECTIONS;
107002
+ return base2.filter((s) => !drop.has(s.name));
107003
107003
  }
107004
107004
  async function runWithConcurrency2(tasks, concurrency) {
107005
107005
  const results = new Array(tasks.length);
@@ -111258,7 +111258,7 @@ ${opts.media} \u6295\u653E\u6570\u636E\uFF08${rangeLabel}\uFF09\uFF08\u7B2C 1 \u
111258
111258
  totalImpressions += item.impressions ?? 0;
111259
111259
  totalClicks += item.clicks ?? 0;
111260
111260
  totalConversions += item.conversions ?? 0;
111261
- const base = {
111261
+ const base2 = {
111262
111262
  id: item.mediaAccountId ?? "",
111263
111263
  name: item.mediaCustomerName ?? "",
111264
111264
  spend: item.spend?.toFixed(2) ?? "0.00",
@@ -111267,7 +111267,7 @@ ${opts.media} \u6295\u653E\u6570\u636E\uFF08${rangeLabel}\uFF09\uFF08\u7B2C 1 \u
111267
111267
  conversions: String(item.conversions ?? 0),
111268
111268
  cpc: item.costPerClick?.toFixed(4) ?? "0.0000"
111269
111269
  };
111270
- return opts.byDay ? { date: item.date ?? "", ...base } : base;
111270
+ return opts.byDay ? { date: item.date ?? "", ...base2 } : base2;
111271
111271
  });
111272
111272
  if (items3.length > 1) {
111273
111273
  const avgCpc = totalClicks > 0 ? (totalSpend / totalClicks).toFixed(4) : "0.0000";
@@ -114102,9 +114102,9 @@ async function runForewarningCreate(opts) {
114102
114102
  process.exit(1);
114103
114103
  }
114104
114104
  const config = loadConfig(opts.token);
114105
- const base = `${config.apiBaseUrl}/command/smart-strategy/settings/${opts.media}`;
114105
+ const base2 = `${config.apiBaseUrl}/command/smart-strategy/settings/${opts.media}`;
114106
114106
  const isUpdate = Boolean(opts.id);
114107
- const url = isUpdate ? `${base}/${opts.id}` : base;
114107
+ const url = isUpdate ? `${base2}/${opts.id}` : base2;
114108
114108
  const method = isUpdate ? "PUT" : "POST";
114109
114109
  const body = buildRuleBody(opts);
114110
114110
  try {
@@ -115659,12 +115659,12 @@ async function runAdKeywordEdit(opts) {
115659
115659
  }
115660
115660
  const body = { ...keyword };
115661
115661
  if (opts.matchType !== void 0) {
115662
- const base = opts.text !== void 0 ? opts.text : firstKeywordTextFromRecord(keyword);
115663
- if (!String(base).trim()) {
115662
+ const base2 = opts.text !== void 0 ? opts.text : firstKeywordTextFromRecord(keyword);
115663
+ if (!String(base2).trim()) {
115664
115664
  console.error("\n\u274C \u65E0\u6CD5\u89E3\u6790\u5F53\u524D\u5173\u952E\u8BCD\u6587\u6848\uFF0C\u8BF7\u540C\u65F6\u4F20 --text <\u8BCD\u5E72>\n");
115665
115665
  process.exit(1);
115666
115666
  }
115667
- body["keywordText"] = [formatKeywordTextForMatchType(base, opts.matchType)];
115667
+ body["keywordText"] = [formatKeywordTextForMatchType(base2, opts.matchType)];
115668
115668
  body["matchTypeV2"] = opts.matchType;
115669
115669
  } else if (opts.text !== void 0) {
115670
115670
  body["keywordText"] = [opts.text];
@@ -115812,12 +115812,12 @@ async function runAdNegativeKeywordEdit(opts) {
115812
115812
  }
115813
115813
  const body = { ...keyword };
115814
115814
  if (opts.matchType !== void 0) {
115815
- const base = opts.text !== void 0 ? opts.text : firstKeywordTextFromRecord(keyword);
115816
- if (!String(base).trim()) {
115815
+ const base2 = opts.text !== void 0 ? opts.text : firstKeywordTextFromRecord(keyword);
115816
+ if (!String(base2).trim()) {
115817
115817
  console.error("\n\u274C \u65E0\u6CD5\u89E3\u6790\u5F53\u524D\u5426\u5B9A\u5173\u952E\u8BCD\u6587\u6848\uFF0C\u8BF7\u540C\u65F6\u4F20 --text <\u8BCD\u5E72>\n");
115818
115818
  process.exit(1);
115819
115819
  }
115820
- body["keywordText"] = [formatKeywordTextForMatchType(base, opts.matchType)];
115820
+ body["keywordText"] = [formatKeywordTextForMatchType(base2, opts.matchType)];
115821
115821
  body["matchTypeV2"] = opts.matchType;
115822
115822
  } else if (opts.text !== void 0) {
115823
115823
  body["keywordText"] = [opts.text];
@@ -119652,8 +119652,8 @@ function pickGeoCandidate(query, items3) {
119652
119652
  const key = geoQueryKey(query);
119653
119653
  const unserved = GEO_UNSERVED[normGeoName(query)];
119654
119654
  const parsed = items3.map((it) => {
119655
- const { base, level } = splitGeoName(geoItemDisplayName(it));
119656
- return { it, base, level: level || geoItemType(it) };
119655
+ const { base: base2, level } = splitGeoName(geoItemDisplayName(it));
119656
+ return { it, base: base2, level: level || geoItemType(it) };
119657
119657
  });
119658
119658
  const same = parsed.filter((p) => normGeoName(p.base) === key || normGeoName(geoItemDisplayName(p.it)) === key);
119659
119659
  const rank = (lvl) => {
@@ -120160,13 +120160,13 @@ function buildExtensionRemediateCommandLine(opts) {
120160
120160
  const props = asRecord2(ext["Properties"]) ?? {};
120161
120161
  const levelFlag = `--level ${level}`;
120162
120162
  const campaignFlag = level === "Campaign" ? `--campaign-id ${campaignId}` : "";
120163
- const base = ["siluzan-tso", "ad", "extension"];
120163
+ const base2 = ["siluzan-tso", "ad", "extension"];
120164
120164
  if (type === "SITELINK") {
120165
120165
  const text3 = pickString(props["Text"], props["LinkText"]);
120166
120166
  const url = pickString(props["DestinationUrl"]);
120167
120167
  if (!text3 || !url) return null;
120168
120168
  const parts = [
120169
- ...base,
120169
+ ...base2,
120170
120170
  "sitelink",
120171
120171
  `-a ${accountId}`,
120172
120172
  `--text ${shellArg(text3)}`,
@@ -120185,7 +120185,7 @@ function buildExtensionRemediateCommandLine(opts) {
120185
120185
  if (type === "CALLOUT") {
120186
120186
  const text3 = pickString(props["Text"], props["CalloutText"]);
120187
120187
  if (!text3) return null;
120188
- const parts = [...base, "callout", `-a ${accountId}`, `--text ${shellArg(text3)}`, levelFlag];
120188
+ const parts = [...base2, "callout", `-a ${accountId}`, `--text ${shellArg(text3)}`, levelFlag];
120189
120189
  if (campaignFlag) parts.push(campaignFlag);
120190
120190
  parts.push(`--json-out ${jsonOut}`);
120191
120191
  parts.push(`--commit ${shellArg("batch-diff remediate extension")}`);
@@ -120196,7 +120196,7 @@ function buildExtensionRemediateCommandLine(opts) {
120196
120196
  const phone = pickString(props["PhoneNumber"], props["phoneNumber"]);
120197
120197
  if (!code || !phone) return null;
120198
120198
  const parts = [
120199
- ...base,
120199
+ ...base2,
120200
120200
  "call",
120201
120201
  `-a ${accountId}`,
120202
120202
  `--country-code ${shellArg(code)}`,
@@ -120216,7 +120216,7 @@ function buildExtensionRemediateCommandLine(opts) {
120216
120216
  const valueStr = values.filter((v) => typeof v === "string" && v.trim().length > 0).join(",");
120217
120217
  if (!valueStr) return null;
120218
120218
  const parts = [
120219
- ...base,
120219
+ ...base2,
120220
120220
  "snippet",
120221
120221
  `-a ${accountId}`,
120222
120222
  `--header ${shellArg(header)}`,
@@ -120546,12 +120546,12 @@ function livePoolHasText(pool, text3) {
120546
120546
  return t.length > 0 && pool.has(t);
120547
120547
  }
120548
120548
  function listPlannedRsaAssets(ad, groupPath, adIndex, adGroupName) {
120549
- const base = `${groupPath}.AdsForBatchJob[${adIndex}]`;
120549
+ const base2 = `${groupPath}.AdsForBatchJob[${adIndex}]`;
120550
120550
  const out = [];
120551
120551
  const push = (kind, field, raw) => {
120552
120552
  if (typeof raw !== "string" || !raw.trim()) return;
120553
120553
  out.push({
120554
- path: `${base}.${field}`,
120554
+ path: `${base2}.${field}`,
120555
120555
  adGroupName,
120556
120556
  kind,
120557
120557
  field,
@@ -122709,12 +122709,12 @@ import { existsSync as existsSync4, readFileSync as readFileSync10 } from "fs";
122709
122709
 
122710
122710
  // src/commands/ad/pmax-urls.ts
122711
122711
  function pmaxChannelTypesUrl(googleApiUrl) {
122712
- const base = googleApiUrl.replace(/\/$/, "");
122713
- return `${base}/campaign/pmax/channel-types`;
122712
+ const base2 = googleApiUrl.replace(/\/$/, "");
122713
+ return `${base2}/campaign/pmax/channel-types`;
122714
122714
  }
122715
122715
  function pmaxCampaignUrl(googleApiUrl, accountId, campaignId) {
122716
- const base = googleApiUrl.replace(/\/$/, "");
122717
- const path56 = `${base}/accounts/${accountId}/campaign/pmax`;
122716
+ const base2 = googleApiUrl.replace(/\/$/, "");
122717
+ const path56 = `${base2}/accounts/${accountId}/campaign/pmax`;
122718
122718
  return campaignId ? `${path56}/${campaignId}` : path56;
122719
122719
  }
122720
122720
  function pmaxBrandAssetsUrl(googleApiUrl, accountId, campaignId) {
@@ -122724,53 +122724,53 @@ function pmaxBrandGuidelinesEnableUrl(googleApiUrl, accountId, campaignId) {
122724
122724
  return `${pmaxCampaignUrl(googleApiUrl, accountId, campaignId)}/brand-guidelines/enable`;
122725
122725
  }
122726
122726
  function pmaxAssetGroupUrl(googleApiUrl, accountId, assetGroupId, suffix) {
122727
- const base = googleApiUrl.replace(/\/$/, "");
122728
- const path56 = `${base}/accounts/${accountId}/campaign/pmax/asset-group/${assetGroupId}`;
122727
+ const base2 = googleApiUrl.replace(/\/$/, "");
122728
+ const path56 = `${base2}/accounts/${accountId}/campaign/pmax/asset-group/${assetGroupId}`;
122729
122729
  return suffix ? `${path56}/${suffix.replace(/^\//, "")}` : path56;
122730
122730
  }
122731
122731
  function pmaxCampaignAssetGroupUrl(googleApiUrl, accountId, campaignId) {
122732
- const base = googleApiUrl.replace(/\/$/, "");
122733
- return `${base}/accounts/${accountId}/campaign/pmax/${campaignId}/asset-group`;
122732
+ const base2 = googleApiUrl.replace(/\/$/, "");
122733
+ return `${base2}/accounts/${accountId}/campaign/pmax/${campaignId}/asset-group`;
122734
122734
  }
122735
122735
  function pmaxUserlistsUrl(googleApiUrl, accountId) {
122736
- const base = googleApiUrl.replace(/\/$/, "");
122737
- return `${base}/campaignmanagement/userlists/${accountId}`;
122736
+ const base2 = googleApiUrl.replace(/\/$/, "");
122737
+ return `${base2}/campaignmanagement/userlists/${accountId}`;
122738
122738
  }
122739
122739
  function pmaxAudiencesUrl(googleApiUrl, accountId, limit) {
122740
- const base = googleApiUrl.replace(/\/$/, "");
122741
- const url = `${base}/campaignmanagement/audiences/${accountId}`;
122740
+ const base2 = googleApiUrl.replace(/\/$/, "");
122741
+ const url = `${base2}/campaignmanagement/audiences/${accountId}`;
122742
122742
  if (limit != null && Number.isFinite(limit)) {
122743
122743
  return `${url}?limit=${Math.floor(limit)}`;
122744
122744
  }
122745
122745
  return url;
122746
122746
  }
122747
122747
  function pmaxImageAssetUrl(googleApiUrl, accountId, name2) {
122748
- const base = googleApiUrl.replace(/\/$/, "");
122749
- const url = `${base}/mediamanagement/imageasset/${accountId}`;
122748
+ const base2 = googleApiUrl.replace(/\/$/, "");
122749
+ const url = `${base2}/mediamanagement/imageasset/${accountId}`;
122750
122750
  if (name2?.trim()) {
122751
122751
  return `${url}?name=${encodeURIComponent(name2.trim())}`;
122752
122752
  }
122753
122753
  return url;
122754
122754
  }
122755
122755
  function pmaxAssetGroupReportUrl(googleApiUrl, accountId, query) {
122756
- const base = googleApiUrl.replace(/\/$/, "");
122756
+ const base2 = googleApiUrl.replace(/\/$/, "");
122757
122757
  const qs = query.toString();
122758
- return `${base}/reporting/media-account/${accountId}/pmax/asset-groups/reports${qs ? `?${qs}` : ""}`;
122758
+ return `${base2}/reporting/media-account/${accountId}/pmax/asset-groups/reports${qs ? `?${qs}` : ""}`;
122759
122759
  }
122760
122760
  function pmaxAssetReportUrl(googleApiUrl, accountId, query) {
122761
- const base = googleApiUrl.replace(/\/$/, "");
122761
+ const base2 = googleApiUrl.replace(/\/$/, "");
122762
122762
  const qs = query.toString();
122763
- return `${base}/reporting/media-account/${accountId}/pmax/asset-groups/reports/assets${qs ? `?${qs}` : ""}`;
122763
+ return `${base2}/reporting/media-account/${accountId}/pmax/asset-groups/reports/assets${qs ? `?${qs}` : ""}`;
122764
122764
  }
122765
122765
  function pmaxChannelReportUrl(googleApiUrl, accountId, query) {
122766
- const base = googleApiUrl.replace(/\/$/, "");
122766
+ const base2 = googleApiUrl.replace(/\/$/, "");
122767
122767
  const qs = query.toString();
122768
- return `${base}/reporting/media-account/${accountId}/pmax/campaigns/reports/channels${qs ? `?${qs}` : ""}`;
122768
+ return `${base2}/reporting/media-account/${accountId}/pmax/campaigns/reports/channels${qs ? `?${qs}` : ""}`;
122769
122769
  }
122770
122770
  function pmaxGeoReportUrl(googleApiUrl, accountId, query) {
122771
- const base = googleApiUrl.replace(/\/$/, "");
122771
+ const base2 = googleApiUrl.replace(/\/$/, "");
122772
122772
  const qs = query.toString();
122773
- return `${base}/reporting/media-account/${accountId}/pmax/campaigns/reports/geo${qs ? `?${qs}` : ""}`;
122773
+ return `${base2}/reporting/media-account/${accountId}/pmax/campaigns/reports/geo${qs ? `?${qs}` : ""}`;
122774
122774
  }
122775
122775
 
122776
122776
  // src/commands/ad/pmax-image-resolve.ts
@@ -123719,8 +123719,8 @@ function buildPmaxCreateApiBody(cfg, imageSlots) {
123719
123719
  return body;
123720
123720
  }
123721
123721
  function buildPmaxCreateUrl(googleApiUrl, accountId) {
123722
- const base = googleApiUrl.replace(/\/$/, "");
123723
- return `${base}/accounts/${accountId}/campaign/pmax`;
123722
+ const base2 = googleApiUrl.replace(/\/$/, "");
123723
+ return `${base2}/accounts/${accountId}/campaign/pmax`;
123724
123724
  }
123725
123725
 
123726
123726
  // src/commands/ad/pmax-video-upload.ts
@@ -123860,16 +123860,16 @@ var FAILED_VIDEO_STATES = /* @__PURE__ */ new Set(["FAILED", "REJECTED", "UNAVAI
123860
123860
  var PMAX_VIDEO_POLL_INTERVAL_MS = 1e4;
123861
123861
  var PMAX_VIDEO_POLL_MAX_ATTEMPTS = 120;
123862
123862
  function pyapiVideoUploadUrl(googleApiUrl) {
123863
- const base = googleApiUrl.replace(/\/$/, "");
123864
- return `${base}/pyapi/video/upload`;
123863
+ const base2 = googleApiUrl.replace(/\/$/, "");
123864
+ return `${base2}/pyapi/video/upload`;
123865
123865
  }
123866
123866
  function pyapiVideoStatusUrl(googleApiUrl, mediaAccountId, resourceName) {
123867
- const base = googleApiUrl.replace(/\/$/, "");
123867
+ const base2 = googleApiUrl.replace(/\/$/, "");
123868
123868
  const params = new URLSearchParams({
123869
123869
  media_account_id: mediaAccountId.replace(/-/g, ""),
123870
123870
  resource_name: resourceName
123871
123871
  });
123872
- return `${base}/pyapi/video/upload/status?${params.toString()}`;
123872
+ return `${base2}/pyapi/video/upload/status?${params.toString()}`;
123873
123873
  }
123874
123874
  function resolveVideoPath(configFile, relOrAbs) {
123875
123875
  const trimmed = relOrAbs.trim();
@@ -125842,6 +125842,997 @@ async function runAdPmaxBrandGuidelinesEnable(opts) {
125842
125842
  });
125843
125843
  }
125844
125844
 
125845
+ // src/commands/ad/demand-gen-body.ts
125846
+ init_shared();
125847
+ var WRITE_CENT_KEYS = ["budget", "targetCpa_BidingAmount", "currencyMinimumBudget"];
125848
+ var YUAN_TO_CENT = {
125849
+ budgetYuan: "budget",
125850
+ targetCpaAmountYuan: "targetCpa_BidingAmount",
125851
+ currencyMinimumBudgetYuan: "currencyMinimumBudget"
125852
+ };
125853
+ var READ_CENT_TO_YUAN = {
125854
+ budget: "budgetYuan",
125855
+ targetCpa_BidingAmount: "targetCpaAmountYuan",
125856
+ minimumDailyBudget: "minimumDailyBudgetYuan",
125857
+ currencyMinimumBudget: "currencyMinimumBudgetYuan",
125858
+ currencyMinimum: "currencyMinimumYuan",
125859
+ tenTimesTargetCpa: "tenTimesTargetCpaYuan",
125860
+ fifteenTimesTargetCpa: "fifteenTimesTargetCpaYuan"
125861
+ };
125862
+ var DISPLAY_ONLY_KEYS = [
125863
+ ...Object.keys(YUAN_TO_CENT),
125864
+ "minimumDailyBudgetYuan",
125865
+ "currencyMinimumYuan",
125866
+ "tenTimesTargetCpaYuan",
125867
+ "fifteenTimesTargetCpaYuan",
125868
+ "_agentMoneyHint",
125869
+ "_cliMoney"
125870
+ ];
125871
+ var DEMAND_GEN_CHANNEL_KEYS = [
125872
+ "youtubeInStream",
125873
+ "youtubeInFeed",
125874
+ "youtubeShorts",
125875
+ "discover",
125876
+ "gmail",
125877
+ "display",
125878
+ "maps"
125879
+ ];
125880
+ function finiteNumber(value) {
125881
+ if (typeof value === "number" && Number.isFinite(value)) return value;
125882
+ if (typeof value === "string" && value.trim() && Number.isFinite(Number(value))) {
125883
+ return Number(value);
125884
+ }
125885
+ return null;
125886
+ }
125887
+ function quoteLongResumeIds2(rawBody) {
125888
+ return rawBody.replace(
125889
+ /"(budgetId|campaignId|adGroupId)"\s*:\s*(-?\d+)/g,
125890
+ '"$1":"$2"'
125891
+ );
125892
+ }
125893
+ function normalizeResumeId(value) {
125894
+ if (value == null) return null;
125895
+ const text3 = String(value).trim();
125896
+ if (!text3 || text3.toLowerCase() === "null") return null;
125897
+ return text3;
125898
+ }
125899
+ function parseDemandGenCreateFailure(rawBody) {
125900
+ const text3 = rawBody.trim();
125901
+ if (!text3.startsWith("{")) return null;
125902
+ let parsed;
125903
+ try {
125904
+ parsed = JSON.parse(quoteLongResumeIds2(text3));
125905
+ } catch {
125906
+ return null;
125907
+ }
125908
+ if (!parsed || typeof parsed !== "object") return null;
125909
+ const rec = parsed;
125910
+ if (typeof rec["message"] !== "string" || !rec["message"].trim()) return null;
125911
+ if (!("budgetId" in rec) && !("campaignId" in rec) && !("adGroupId" in rec)) return null;
125912
+ return {
125913
+ message: rec["message"].trim(),
125914
+ budgetId: normalizeResumeId(rec["budgetId"]),
125915
+ campaignId: normalizeResumeId(rec["campaignId"]),
125916
+ adGroupId: normalizeResumeId(rec["adGroupId"])
125917
+ };
125918
+ }
125919
+ function readHttpRawBody2(err) {
125920
+ if (!err || typeof err !== "object" || !("rawBody" in err)) return "";
125921
+ const raw = err.rawBody;
125922
+ return typeof raw === "string" ? raw : "";
125923
+ }
125924
+ function unwrapDemandGenCreateBody(raw) {
125925
+ const nested = raw["createRequest"];
125926
+ const hasOwnPayload = raw["name"] != null || raw["budget"] != null || raw["budgetYuan"] != null;
125927
+ if (!hasOwnPayload && nested && typeof nested === "object" && !Array.isArray(nested)) {
125928
+ return { ...nested };
125929
+ }
125930
+ return { ...raw };
125931
+ }
125932
+ function normalizeDemandGenMoneyForWrite(raw) {
125933
+ const out = { ...raw };
125934
+ for (const [yuanKey, centKey] of Object.entries(YUAN_TO_CENT)) {
125935
+ const yuan = finiteNumber(out[yuanKey]);
125936
+ if (yuan != null) out[centKey] = yuan;
125937
+ }
125938
+ for (const key of DISPLAY_ONLY_KEYS) delete out[key];
125939
+ for (const key of WRITE_CENT_KEYS) {
125940
+ const amount = finiteNumber(out[key]);
125941
+ if (amount != null) out[key] = toCentAmount(amount);
125942
+ }
125943
+ return out;
125944
+ }
125945
+ function decorateDemandGenRead(value) {
125946
+ if (Array.isArray(value)) return value.map(decorateDemandGenRead);
125947
+ if (!value || typeof value !== "object") return value;
125948
+ const out = {};
125949
+ for (const [key, child] of Object.entries(value)) {
125950
+ out[key] = decorateDemandGenRead(child);
125951
+ }
125952
+ for (const [centKey, yuanKey] of Object.entries(READ_CENT_TO_YUAN)) {
125953
+ const amount = finiteNumber(out[centKey]);
125954
+ if (amount != null) out[yuanKey] = toDisplayMoney(amount);
125955
+ }
125956
+ return out;
125957
+ }
125958
+ function normalizeCampaignStatus(raw) {
125959
+ if (raw == null || String(raw).trim() === "") return null;
125960
+ const text3 = String(raw).trim().toLowerCase();
125961
+ if (text3 === "enabled" || text3 === "2") return "Enabled";
125962
+ if (text3 === "paused" || text3 === "3") return "Paused";
125963
+ if (text3 === "removed" || text3 === "4") return "Removed";
125964
+ return null;
125965
+ }
125966
+ function normalizeAdStatus(raw) {
125967
+ const status = normalizeCampaignStatus(raw);
125968
+ if (status === "Enabled" || status === "Paused") return status;
125969
+ return null;
125970
+ }
125971
+ function buildSelectedChannels(names) {
125972
+ const picked = new Set(names.map((name2) => name2.trim()).filter(Boolean));
125973
+ const unknown = [...picked].filter(
125974
+ (name2) => !DEMAND_GEN_CHANNEL_KEYS.includes(name2)
125975
+ );
125976
+ if (unknown.length > 0) {
125977
+ throw new Error(
125978
+ `\u672A\u77E5\u7248\u4F4D\uFF1A${unknown.join(", ")}\u3002\u53EF\u9009 ${DEMAND_GEN_CHANNEL_KEYS.join(", ")}`
125979
+ );
125980
+ }
125981
+ const out = {};
125982
+ let any = false;
125983
+ for (const key of DEMAND_GEN_CHANNEL_KEYS) {
125984
+ const on = picked.has(key);
125985
+ out[key] = on;
125986
+ if (on) any = true;
125987
+ }
125988
+ if (!any) throw new Error("SelectedChannels requires at least one channel.");
125989
+ return out;
125990
+ }
125991
+ function hasText(value) {
125992
+ return typeof value === "string" && value.trim().length > 0;
125993
+ }
125994
+ function hasKeywords(value) {
125995
+ return Array.isArray(value) && value.some((item) => hasText(item));
125996
+ }
125997
+ function demandGenCreateIssues(body) {
125998
+ const issues = [];
125999
+ if (body["automatic"] === true) {
126000
+ issues.push("\u4EBA\u5DE5\u64CD\u4F5C\u4E0D\u8981\u5E26 automatic\u3002\u5B66\u4E60\u671F\u5185\u81EA\u52A8\u6539\u4EF7\u3001\u6539\u8F6C\u5316\u76EE\u6807\u6216\u6362\u53D7\u4F17\u4F1A\u88AB\u62D2\u7EDD\u3002");
126001
+ }
126002
+ const bidding = String(body["biddingStrategyTypeV2"] ?? "").trim();
126003
+ if (!bidding || bidding.toUpperCase() === "UNSPECIFIED") {
126004
+ issues.push("Bidding strategy is required.");
126005
+ }
126006
+ if (hasText(body["channelStrategy"]) && body["selectedChannels"]) {
126007
+ issues.push("ChannelStrategy and SelectedChannels cannot both be set.");
126008
+ }
126009
+ if (hasText(body["audienceResourceName"]) && hasKeywords(body["audienceKeywords"])) {
126010
+ issues.push("AudienceResourceName and AudienceKeywords cannot both be set.");
126011
+ }
126012
+ return issues;
126013
+ }
126014
+ function demandGenEditIssues(body) {
126015
+ const issues = [];
126016
+ if (body["automatic"] === true) {
126017
+ issues.push("\u4EBA\u5DE5\u64CD\u4F5C\u4E0D\u8981\u5E26 automatic\u3002\u5B66\u4E60\u671F\u5185\u81EA\u52A8\u6539\u4EF7\u3001\u6539\u8F6C\u5316\u76EE\u6807\u6216\u6362\u53D7\u4F17\u4F1A\u88AB\u62D2\u7EDD\u3002");
126018
+ }
126019
+ if (body["statusV2"] != null && normalizeCampaignStatus(body["statusV2"]) == null) {
126020
+ issues.push("Campaign status must be Enabled, Paused, or Removed.");
126021
+ }
126022
+ if (normalizeCampaignStatus(body["statusV2"]) === "Enabled" && body["confirmEnable"] !== true) {
126023
+ issues.push("Enabling a campaign spends money. Set confirmEnable true.");
126024
+ }
126025
+ if (body["budget"] != null && !hasText(body["budgetId"])) {
126026
+ issues.push("\u4FEE\u6539\u9884\u7B97\u987B\u540C\u65F6\u5E26 budgetId\uFF08\u8FD9\u6761\u7CFB\u5217\u81EA\u5DF1\u7684\u672A\u5171\u4EAB\u9884\u7B97\uFF09\u3002");
126027
+ }
126028
+ return issues;
126029
+ }
126030
+ function demandGenResumeHint(failure) {
126031
+ const lines = [
126032
+ failure.message,
126033
+ "\u521B\u5EFA\u505C\u5728\u534A\u622A\u3002\u628A\u4E0B\u9762\u975E\u7A7A\u7F16\u53F7\u539F\u6837\u5199\u56DE JSON \u518D\u8DD1\u4E00\u6B21\uFF0C\u5176\u5B83\u5B57\u6BB5\u5148\u4E0D\u8981\u6539\u3002",
126034
+ "\u987A\u5E8F\u662F\u9884\u7B97 \u2192 \u7CFB\u5217 \u2192 \u5E7F\u544A\u7EC4\u3002\u53EA\u5E26\u7CFB\u5217\u3001\u4E0D\u5E26\u9884\u7B97\u4F1A\u88AB\u62D2\u3002\u5E7F\u544A\u7EC4\u91CC\u5DF2\u6709\u5E7F\u544A\u65F6\u4E0D\u4F1A\u518D\u63D2\u4E00\u5957\u3002"
126035
+ ];
126036
+ if (failure.budgetId) lines.push(`budgetId: ${failure.budgetId}`);
126037
+ if (failure.campaignId) lines.push(`campaignId: ${failure.campaignId}`);
126038
+ if (failure.adGroupId) lines.push(`adGroupId: ${failure.adGroupId}`);
126039
+ if (!failure.budgetId && !failure.campaignId && !failure.adGroupId) {
126040
+ return failure.message;
126041
+ }
126042
+ return lines.join("\n");
126043
+ }
126044
+
126045
+ // src/commands/ad/demand-gen-urls.ts
126046
+ function base(googleApiUrl) {
126047
+ return googleApiUrl.replace(/\/$/, "");
126048
+ }
126049
+ function demandGenCollectionUrl(googleApiUrl, accountId) {
126050
+ return `${base(googleApiUrl)}/accounts/${accountId}/campaign/demand-gen`;
126051
+ }
126052
+ function demandGenCampaignUrl(googleApiUrl, accountId, campaignId) {
126053
+ return `${demandGenCollectionUrl(googleApiUrl, accountId)}/${campaignId}`;
126054
+ }
126055
+ function demandGenMinimumBudgetUrl(googleApiUrl, accountId, currencyCode) {
126056
+ const url = `${demandGenCollectionUrl(googleApiUrl, accountId)}/minimum-daily-budget`;
126057
+ const code = currencyCode?.trim();
126058
+ return code ? `${url}?currencyCode=${encodeURIComponent(code)}` : url;
126059
+ }
126060
+ function demandGenBiddableConversionsUrl(googleApiUrl, accountId) {
126061
+ return `${demandGenCollectionUrl(googleApiUrl, accountId)}/conversions/biddable`;
126062
+ }
126063
+ function demandGenConversionsValidateUrl(googleApiUrl, accountId) {
126064
+ return `${demandGenCollectionUrl(googleApiUrl, accountId)}/conversions/validate`;
126065
+ }
126066
+ function demandGenAdGroupUrl(googleApiUrl, accountId, campaignId, adGroupId, suffix) {
126067
+ const path56 = `${demandGenCampaignUrl(googleApiUrl, accountId, campaignId)}/ad-groups/${adGroupId}`;
126068
+ return suffix ? `${path56}/${suffix.replace(/^\//, "")}` : path56;
126069
+ }
126070
+ function demandGenAdUrl(googleApiUrl, accountId, campaignId, adGroupId, adId, suffix) {
126071
+ const path56 = `${demandGenAdGroupUrl(googleApiUrl, accountId, campaignId, adGroupId)}/ads/${adId}`;
126072
+ return suffix ? `${path56}/${suffix.replace(/^\//, "")}` : path56;
126073
+ }
126074
+ function demandGenChannelReportUrl(googleApiUrl, accountId, campaignId, startDate, endDate) {
126075
+ const params = new URLSearchParams({ startDate, endDate });
126076
+ return `${demandGenCampaignUrl(googleApiUrl, accountId, campaignId)}/reports/channels?${params}`;
126077
+ }
126078
+
126079
+ // src/commands/ad/demand-gen.ts
126080
+ init_shared();
126081
+ var MONEY_HINT = "budget / targetCpa_BidingAmount / minimumDailyBudget \u662F\u5206\uFF08500 = 5 \u5143\uFF09\u3002\u770B\u65C1\u8FB9\u7684 *Yuan\u3002\u5199\u5165 --budget / JSON \u586B\u5143\uFF1B\u82E5\u540C\u65F6\u6709 *Yuan\uFF0C\u4EE5 Yuan \u4E3A\u51C6\u3002targetRoas \u662F\u6BD4\u7387\u3002\u62A5\u8868 spend \u5DF2\u662F\u8D26\u6237\u5E01\u79CD\uFF0C\u4E0D\u8981\u62FF\u53BB\u5F53\u9884\u7B97\u3002";
126082
+ function fail(message) {
126083
+ console.error(`
126084
+ \u274C ${message}
126085
+ `);
126086
+ process.exit(1);
126087
+ }
126088
+ function asRecord5(value) {
126089
+ return value && typeof value === "object" && !Array.isArray(value) ? value : { data: value };
126090
+ }
126091
+ async function emit(opts, section, commandLabel, payload, idSuffix) {
126092
+ return emitPmaxResult(
126093
+ { ...opts, account: opts.account },
126094
+ section,
126095
+ commandLabel,
126096
+ payload,
126097
+ idSuffix ?? opts.account
126098
+ );
126099
+ }
126100
+ function printIssues(issues) {
126101
+ if (issues.length === 0) return;
126102
+ fail(issues.join("\n"));
126103
+ }
126104
+ function loadBody(configFile) {
126105
+ return stripMetaKeys(loadPmaxJsonFile(configFile));
126106
+ }
126107
+ function imageKinds(body) {
126108
+ const paths = body["imagePaths"];
126109
+ const kinds = [];
126110
+ const specs = [
126111
+ ["marketing", "marketingImageAssetId", "marketingImageBase64"],
126112
+ ["square", "squareMarketingImageAssetId", "squareMarketingImageBase64"],
126113
+ ["logo", "logoImageAssetId", "logoImageBase64"]
126114
+ ];
126115
+ for (const [kind, idKey, b64Key] of specs) {
126116
+ const hasId = typeof body[idKey] === "string" && body[idKey].trim();
126117
+ const hasB64 = typeof body[b64Key] === "string" && body[b64Key].trim();
126118
+ const hasPath = Boolean(paths?.[kind]?.trim());
126119
+ if (hasId || hasB64 || hasPath) kinds.push(kind);
126120
+ }
126121
+ return kinds;
126122
+ }
126123
+ async function attachImages(configFile, body, accountId, config, googleApiUrl, verbose) {
126124
+ const kinds = imageKinds(body);
126125
+ if (kinds.length === 0) {
126126
+ const next2 = { ...body };
126127
+ delete next2["imagePaths"];
126128
+ return next2;
126129
+ }
126130
+ const paths = body["imagePaths"];
126131
+ if (kinds.some((kind) => Boolean(paths?.[kind]?.trim()))) {
126132
+ console.log("\n\u{1F4E4} \u6B63\u5728\u4E0A\u4F20 Demand Gen \u56FE\u7247\uFF08imagePaths \u2192 assetId\uFF09\u2026");
126133
+ }
126134
+ const slots = await resolvePmaxImageSlots(
126135
+ configFile,
126136
+ {
126137
+ imagePaths: body["imagePaths"],
126138
+ marketingImageAssetId: body["marketingImageAssetId"],
126139
+ squareMarketingImageAssetId: body["squareMarketingImageAssetId"],
126140
+ logoImageAssetId: body["logoImageAssetId"],
126141
+ marketingImageBase64: body["marketingImageBase64"],
126142
+ squareMarketingImageBase64: body["squareMarketingImageBase64"],
126143
+ logoImageBase64: body["logoImageBase64"]
126144
+ },
126145
+ accountId,
126146
+ config,
126147
+ googleApiUrl,
126148
+ { verbose, logUploads: false, requiredKinds: kinds }
126149
+ );
126150
+ const next = { ...body, ...slots };
126151
+ delete next["imagePaths"];
126152
+ return next;
126153
+ }
126154
+ function prepareCreateBody(raw) {
126155
+ const unwrapped = unwrapDemandGenCreateBody(raw);
126156
+ if (unwrapped["statusV2"] != null) {
126157
+ console.error(
126158
+ "\n\u26A0\uFE0F \u5DF2\u5FFD\u7565 statusV2\u3002Demand Gen \u521B\u5EFA\u56FA\u5B9A\u6682\u505C\u3002\u542F\u7528\u4F1A\u82B1\u94B1\uFF0C\u521B\u5EFA\u540E\u518D demand-gen edit --status Enabled --confirm-enable --i-confirm\u3002\n"
126159
+ );
126160
+ }
126161
+ const body = normalizeDemandGenMoneyForWrite(unwrapped);
126162
+ delete body["account"];
126163
+ delete body["imagePaths"];
126164
+ delete body["statusV2"];
126165
+ delete body["hasBiddableConversion"];
126166
+ if (typeof body["biddingStrategyTypeV2"] === "string") {
126167
+ body["biddingStrategyTypeV2"] = body["biddingStrategyTypeV2"].trim().toUpperCase();
126168
+ }
126169
+ return body;
126170
+ }
126171
+ function explainCreateError(err) {
126172
+ const failure = parseDemandGenCreateFailure(readHttpRawBody2(err));
126173
+ if (failure) return demandGenResumeHint(failure);
126174
+ return err instanceof Error ? err.message : String(err);
126175
+ }
126176
+ async function postCreate(opts, path56, commandLabel) {
126177
+ const accountId = requireAccountId(opts.account);
126178
+ const raw = loadBody(opts.configFile);
126179
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126180
+ let body;
126181
+ try {
126182
+ body = await attachImages(opts.configFile, raw, accountId, config, googleApiUrl, opts.verbose);
126183
+ body = prepareCreateBody(body);
126184
+ } catch (err) {
126185
+ fail(err instanceof Error ? err.message : String(err));
126186
+ }
126187
+ printIssues(demandGenCreateIssues(body));
126188
+ const url = path56 ? `${demandGenCollectionUrl(googleApiUrl, accountId)}/${path56}` : demandGenCollectionUrl(googleApiUrl, accountId);
126189
+ let data;
126190
+ try {
126191
+ data = await pmaxApiFetch(
126192
+ url,
126193
+ config,
126194
+ { method: "POST", body: JSON.stringify(body) },
126195
+ opts.verbose
126196
+ );
126197
+ } catch (err) {
126198
+ fail(explainCreateError(err));
126199
+ }
126200
+ const payload = decorateDemandGenRead(data);
126201
+ if (await emit({ ...opts, account: accountId }, `ad-demand-gen-${path56 || "create"}`, commandLabel, payload, accountId)) {
126202
+ return;
126203
+ }
126204
+ console.log(`
126205
+ \u2705 ${commandLabel}
126206
+ `);
126207
+ console.log(JSON.stringify(payload, null, 2));
126208
+ console.log();
126209
+ });
126210
+ }
126211
+ async function runDemandGenList(opts) {
126212
+ const accountId = requireAccountId(opts.account);
126213
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126214
+ let data;
126215
+ try {
126216
+ data = await pmaxApiFetch(demandGenCollectionUrl(googleApiUrl, accountId), config, {}, opts.verbose);
126217
+ } catch (err) {
126218
+ fail(`\u5217\u51FA Demand Gen \u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`);
126219
+ }
126220
+ const payload = {
126221
+ items: decorateDemandGenRead(data),
126222
+ agentHint: MONEY_HINT
126223
+ };
126224
+ if (await emit({ ...opts, account: accountId }, "ad-demand-gen-list", "ad demand-gen list", payload, accountId)) {
126225
+ return;
126226
+ }
126227
+ const items3 = Array.isArray(payload.items) ? payload.items : [];
126228
+ console.log(`
126229
+ Demand Gen \u7CFB\u5217 ${items3.length} \u6761\uFF08\u8D26\u6237 ${accountId}\uFF09`);
126230
+ console.log(` ${MONEY_HINT}
126231
+ `);
126232
+ for (const row of items3) {
126233
+ if (!row || typeof row !== "object") continue;
126234
+ const item = row;
126235
+ console.log(
126236
+ ` ${item["id"] ?? "\u2014"} ${item["name"] ?? "\u2014"} ${item["statusV2"] ?? "\u2014"} \u9884\u7B97 ${item["budgetYuan"] ?? "\u2014"} \u5143`
126237
+ );
126238
+ }
126239
+ console.log();
126240
+ });
126241
+ }
126242
+ async function runDemandGenGet(opts) {
126243
+ const accountId = requireAccountId(opts.account);
126244
+ const campaignId = opts.campaignId.trim();
126245
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126246
+ let data;
126247
+ try {
126248
+ data = await pmaxApiFetch(
126249
+ demandGenCampaignUrl(googleApiUrl, accountId, campaignId),
126250
+ config,
126251
+ {},
126252
+ opts.verbose
126253
+ );
126254
+ } catch (err) {
126255
+ fail(`\u8BFB\u53D6 Demand Gen \u8BE6\u60C5\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`);
126256
+ }
126257
+ const payload = asRecord5(decorateDemandGenRead(data));
126258
+ payload["agentHint"] = MONEY_HINT;
126259
+ if (await emit({ ...opts, account: accountId }, "ad-demand-gen-get", "ad demand-gen get", payload, campaignId)) {
126260
+ return;
126261
+ }
126262
+ console.log(`
126263
+ \u2705 Demand Gen ${campaignId}`);
126264
+ console.log(` \u540D\u79F0\uFF1A${payload["name"] ?? "\u2014"} \u72B6\u6001\uFF1A${payload["statusV2"] ?? "\u2014"}`);
126265
+ console.log(` \u9884\u7B97\uFF1A${payload["budgetYuan"] ?? "\u2014"} \u5143\uFF08\u7F51\u5173\u5206 ${payload["budget"] ?? "\u2014"}\uFF09`);
126266
+ console.log(` \u51FA\u4EF7\uFF1A${payload["biddingStrategyTypeV2"] ?? "\u2014"}`);
126267
+ console.log(` ${MONEY_HINT}`);
126268
+ console.log(` \u5B8C\u6574\u7ED3\u6784\u8BF7\u4F7F\u7528 --json-out
126269
+ `);
126270
+ });
126271
+ }
126272
+ async function runDemandGenMinimumBudget(opts) {
126273
+ const accountId = requireAccountId(opts.account);
126274
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126275
+ let data;
126276
+ try {
126277
+ data = await pmaxApiFetch(
126278
+ demandGenMinimumBudgetUrl(googleApiUrl, accountId, opts.currency),
126279
+ config,
126280
+ {},
126281
+ opts.verbose
126282
+ );
126283
+ } catch (err) {
126284
+ fail(`\u8BFB\u53D6\u6700\u4F4E\u65E5\u9884\u7B97\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`);
126285
+ }
126286
+ const payload = decorateDemandGenRead(data);
126287
+ if (await emit(
126288
+ { ...opts, account: accountId },
126289
+ "ad-demand-gen-minimum-budget",
126290
+ "ad demand-gen minimum-budget",
126291
+ payload,
126292
+ accountId
126293
+ )) {
126294
+ return;
126295
+ }
126296
+ const row = asRecord5(payload);
126297
+ console.log(
126298
+ `
126299
+ \u6700\u4F4E\u65E5\u9884\u7B97 ${row["minimumDailyBudgetYuan"] ?? "\u2014"} \u5143\uFF08${row["currencyCode"] ?? "\u8D26\u6237\u5E01\u79CD"}\uFF0C\u7F51\u5173\u5206 ${row["minimumDailyBudget"] ?? "\u2014"}\uFF09
126300
+ `
126301
+ );
126302
+ });
126303
+ }
126304
+ async function runDemandGenConversions(opts) {
126305
+ const accountId = requireAccountId(opts.account);
126306
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126307
+ let data;
126308
+ try {
126309
+ data = await pmaxApiFetch(
126310
+ demandGenBiddableConversionsUrl(googleApiUrl, accountId),
126311
+ config,
126312
+ {},
126313
+ opts.verbose
126314
+ );
126315
+ } catch (err) {
126316
+ fail(`\u8BFB\u53D6\u53EF\u51FA\u4EF7\u8F6C\u5316\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`);
126317
+ }
126318
+ if (await emit(
126319
+ { ...opts, account: accountId },
126320
+ "ad-demand-gen-conversions",
126321
+ "ad demand-gen conversions",
126322
+ data,
126323
+ accountId
126324
+ )) {
126325
+ return;
126326
+ }
126327
+ const row = asRecord5(data);
126328
+ console.log(
126329
+ `
126330
+ \u53EF\u51FA\u4EF7\u8F6C\u5316\uFF1A${row["hasBiddableConversion"] === true ? "\u6709" : "\u65E0"}\u3002\u6CA1\u6709\u65F6\u521B\u5EFA\u7528 TARGET_SPEND\uFF0C\u4E0D\u8981\u7528 MAXIMIZE_CONVERSIONS\u3002
126331
+ `
126332
+ );
126333
+ });
126334
+ }
126335
+ async function runDemandGenDraft(opts) {
126336
+ const accountId = requireAccountId(opts.account);
126337
+ const body = normalizeDemandGenMoneyForWrite(loadBody(opts.configFile));
126338
+ delete body["account"];
126339
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126340
+ let data;
126341
+ try {
126342
+ data = await pmaxApiFetch(
126343
+ `${demandGenCollectionUrl(googleApiUrl, accountId)}/draft`,
126344
+ config,
126345
+ { method: "POST", body: JSON.stringify(body) },
126346
+ opts.verbose
126347
+ );
126348
+ } catch (err) {
126349
+ fail(`\u751F\u6210\u8349\u7A3F\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`);
126350
+ }
126351
+ const payload = decorateDemandGenRead(data);
126352
+ if (await emit({ ...opts, account: accountId }, "ad-demand-gen-draft", "ad demand-gen draft", payload, accountId)) {
126353
+ return;
126354
+ }
126355
+ const row = asRecord5(payload);
126356
+ console.log(`
126357
+ \u2705 \u8349\u7A3F\u5DF2\u751F\u6210\uFF08\u672A\u5199\u5165 Google\uFF09`);
126358
+ console.log(` \u9700\u4EBA\u5DE5\u770B\uFF1A${row["reviewRequired"] === true ? "\u662F" : "\u5426"}`);
126359
+ console.log(` createRequest \u91CC\u7684\u91D1\u989D\u5DF2\u9644\u5E26 *Yuan\u3002\u786E\u8BA4\u524D\u8865\u89C6\u9891\u3001\u56FE\u7247\u3001\u5730\u57DF\u548C\u8BED\u8A00\u3002
126360
+ `);
126361
+ });
126362
+ }
126363
+ async function runDemandGenValidate(opts) {
126364
+ await postCreate(opts, "validate", "ad demand-gen validate");
126365
+ }
126366
+ async function runDemandGenCreate(opts) {
126367
+ await postCreate(opts, "", "ad demand-gen create");
126368
+ }
126369
+ async function runDemandGenConfirm(opts) {
126370
+ await postCreate(opts, "draft/confirm", "ad demand-gen confirm");
126371
+ }
126372
+ function readFlagNumber(value, label2) {
126373
+ const amount = typeof value === "number" ? value : Number(String(value).trim());
126374
+ if (!Number.isFinite(amount)) fail(`${label2}\u987B\u4E3A\u6709\u9650\u6570\u5B57\uFF0C\u6536\u5230 ${String(value)}`);
126375
+ return amount;
126376
+ }
126377
+ async function runDemandGenEdit(opts) {
126378
+ const accountId = requireAccountId(opts.account);
126379
+ const campaignId = opts.campaignId.trim();
126380
+ let body;
126381
+ if (opts.patchFile) {
126382
+ body = normalizeDemandGenMoneyForWrite(loadBody(opts.patchFile));
126383
+ delete body["account"];
126384
+ delete body["id"];
126385
+ delete body["agentHint"];
126386
+ } else {
126387
+ body = {};
126388
+ if (opts.name !== void 0) body["name"] = opts.name.trim();
126389
+ if (opts.status !== void 0) {
126390
+ const status2 = normalizeCampaignStatus(opts.status);
126391
+ if (!status2) fail("Campaign status must be Enabled, Paused, or Removed.");
126392
+ body["statusV2"] = status2;
126393
+ }
126394
+ if (opts.budget !== void 0) body["budget"] = readFlagNumber(opts.budget, "\u9884\u7B97");
126395
+ if (opts.budgetId !== void 0) body["budgetId"] = opts.budgetId.trim();
126396
+ if (opts.bidding !== void 0) body["biddingStrategyTypeV2"] = opts.bidding.trim().toUpperCase();
126397
+ if (opts.targetCpa !== void 0) {
126398
+ body["targetCpa_BidingAmount"] = readFlagNumber(opts.targetCpa, "\u76EE\u6807 CPA");
126399
+ }
126400
+ if (opts.targetRoas !== void 0) body["targetRoas"] = readFlagNumber(opts.targetRoas, "\u76EE\u6807 ROAS");
126401
+ if (opts.confirmLargeChange) body["confirmLargeChange"] = true;
126402
+ if (opts.confirmEnable) body["confirmEnable"] = true;
126403
+ body = normalizeDemandGenMoneyForWrite(body);
126404
+ }
126405
+ if (Object.keys(body).length === 0) {
126406
+ fail("\u8BF7\u6307\u5B9A --patch-file\uFF0C\u6216\u81F3\u5C11\u4E00\u9879\u4FEE\u6539\uFF08--name / --status / --budget / --bidding / \u2026\uFF09");
126407
+ }
126408
+ const status = normalizeCampaignStatus(body["statusV2"]);
126409
+ if (status) body["statusV2"] = status;
126410
+ printIssues(demandGenEditIssues(body));
126411
+ if (status === "Enabled") {
126412
+ ensureIConfirm({
126413
+ iConfirm: opts.iConfirm,
126414
+ actionLabel: `ad demand-gen edit --status Enabled\uFF08\u542F\u7528\u7CFB\u5217 ${campaignId} \u4F1A\u5F00\u59CB\u82B1\u94B1\uFF09`
126415
+ });
126416
+ }
126417
+ if (status === "Removed") {
126418
+ ensureIConfirm({
126419
+ iConfirm: opts.iConfirm,
126420
+ actionLabel: `ad demand-gen edit --status Removed\uFF08\u79FB\u9664 Demand Gen \u7CFB\u5217 ${campaignId}\uFF0C\u4E0D\u53EF\u6062\u590D\uFF09`
126421
+ });
126422
+ }
126423
+ if (body["automatic"] === true) {
126424
+ fail("\u4EBA\u5DE5\u64CD\u4F5C\u4E0D\u8981\u5E26 automatic\u3002");
126425
+ }
126426
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126427
+ try {
126428
+ await pmaxApiFetch(
126429
+ demandGenCampaignUrl(googleApiUrl, accountId, campaignId),
126430
+ config,
126431
+ { method: "PATCH", body: JSON.stringify(body) },
126432
+ opts.verbose
126433
+ );
126434
+ } catch (err) {
126435
+ fail(`\u66F4\u65B0 Demand Gen \u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`);
126436
+ }
126437
+ const payload = { ok: true, campaignId, patch: body };
126438
+ if (await emit({ ...opts, account: accountId }, "ad-demand-gen-edit", "ad demand-gen edit", payload, campaignId)) {
126439
+ return;
126440
+ }
126441
+ console.log(`
126442
+ \u2705 Demand Gen \u7CFB\u5217 ${campaignId} \u5DF2\u66F4\u65B0
126443
+ `);
126444
+ });
126445
+ }
126446
+ async function runDemandGenContent(opts) {
126447
+ const accountId = requireAccountId(opts.account);
126448
+ const body = loadBody(opts.configFile);
126449
+ delete body["account"];
126450
+ if (opts.adId?.trim()) {
126451
+ delete body["targetedLocations"];
126452
+ delete body["targetedLanguages"];
126453
+ }
126454
+ if (Object.keys(body).length === 0) fail("content JSON \u6CA1\u6709\u8981\u6539\u7684\u5B57\u6BB5");
126455
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126456
+ let next = body;
126457
+ try {
126458
+ next = await attachImages(opts.configFile, body, accountId, config, googleApiUrl, opts.verbose);
126459
+ } catch (err) {
126460
+ fail(err instanceof Error ? err.message : String(err));
126461
+ }
126462
+ delete next["imagePaths"];
126463
+ const url = opts.adId?.trim() ? demandGenAdUrl(googleApiUrl, accountId, opts.campaignId.trim(), opts.adGroupId.trim(), opts.adId.trim(), "content") : demandGenAdGroupUrl(googleApiUrl, accountId, opts.campaignId.trim(), opts.adGroupId.trim(), "content");
126464
+ try {
126465
+ await pmaxApiFetch(url, config, { method: "PUT", body: JSON.stringify(next) }, opts.verbose);
126466
+ } catch (err) {
126467
+ fail(`\u66F4\u65B0\u5E7F\u544A\u5185\u5BB9\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`);
126468
+ }
126469
+ const payload = { ok: true, campaignId: opts.campaignId, adGroupId: opts.adGroupId, adId: opts.adId ?? null };
126470
+ if (await emit({ ...opts, account: accountId }, "ad-demand-gen-content", "ad demand-gen content", payload)) return;
126471
+ console.log("\n\u2705 \u5E7F\u544A\u5185\u5BB9\u5DF2\u66F4\u65B0\u3002\u6539\u5B8C\u7528 demand-gen get \u8BFB\u56DE\u3002waitForReview \u65F6\u4E0D\u8981\u518D\u6539\u6587\u6848\u3002\n");
126472
+ });
126473
+ }
126474
+ async function runDemandGenChannels(opts) {
126475
+ const accountId = requireAccountId(opts.account);
126476
+ const hasStrategy = Boolean(opts.strategy?.trim());
126477
+ const hasSelected = Boolean(opts.selected?.trim());
126478
+ if (hasStrategy === hasSelected) {
126479
+ fail("channelStrategy \u548C selectedChannels \u4E8C\u9009\u4E00\uFF1A\u53EA\u4F20 --strategy\uFF0C\u6216\u53EA\u4F20 --selected\u3002");
126480
+ }
126481
+ const body = {};
126482
+ if (hasStrategy) body["channelStrategy"] = opts.strategy.trim();
126483
+ if (hasSelected) {
126484
+ try {
126485
+ body["selectedChannels"] = buildSelectedChannels(opts.selected.split(","));
126486
+ } catch (err) {
126487
+ fail(err instanceof Error ? err.message : String(err));
126488
+ }
126489
+ }
126490
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126491
+ const url = demandGenAdGroupUrl(
126492
+ googleApiUrl,
126493
+ accountId,
126494
+ opts.campaignId.trim(),
126495
+ opts.adGroupId.trim(),
126496
+ "channels"
126497
+ );
126498
+ try {
126499
+ await pmaxApiFetch(url, config, { method: "PATCH", body: JSON.stringify(body) }, opts.verbose);
126500
+ } catch (err) {
126501
+ fail(`\u66F4\u65B0\u7248\u4F4D\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`);
126502
+ }
126503
+ if (await emit({ ...opts, account: accountId }, "ad-demand-gen-channels", "ad demand-gen channels", { ok: true, patch: body })) {
126504
+ return;
126505
+ }
126506
+ console.log("\n\u2705 \u7248\u4F4D\u5DF2\u66F4\u65B0\n");
126507
+ });
126508
+ }
126509
+ async function putStatus(opts, kind) {
126510
+ const status = normalizeAdStatus(opts.status);
126511
+ if (!status) {
126512
+ fail("\u5E7F\u544A\u548C\u5E7F\u544A\u7EC4\u53EA\u63A5\u53D7 Enabled \u6216 Paused\u3002\u4E0D\u8981\u7528\u5B83\u542F\u7528\u7CFB\u5217\uFF1B\u5220\u5149\u4F1A 400\uFF0C\u53EA\u60F3\u505C\u6295\u7528 Paused\u3002");
126513
+ }
126514
+ const accountId = requireAccountId(opts.account);
126515
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126516
+ const url = kind === "ad" ? demandGenAdUrl(
126517
+ googleApiUrl,
126518
+ accountId,
126519
+ opts.campaignId.trim(),
126520
+ opts.adGroupId.trim(),
126521
+ opts.adId.trim(),
126522
+ "status"
126523
+ ) : demandGenAdGroupUrl(
126524
+ googleApiUrl,
126525
+ accountId,
126526
+ opts.campaignId.trim(),
126527
+ opts.adGroupId.trim(),
126528
+ "status"
126529
+ );
126530
+ try {
126531
+ await pmaxApiFetch(
126532
+ url,
126533
+ config,
126534
+ { method: "PUT", body: JSON.stringify({ status }) },
126535
+ opts.verbose
126536
+ );
126537
+ } catch (err) {
126538
+ fail(`\u66F4\u65B0\u72B6\u6001\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`);
126539
+ }
126540
+ console.log(`
126541
+ \u2705 \u5DF2\u8BBE\u4E3A ${status}\u3002\u7CFB\u5217\u72B6\u6001\u4E0D\u4F1A\u8DDF\u7740\u53D8\u3002
126542
+ `);
126543
+ });
126544
+ }
126545
+ async function runDemandGenAdGroupStatus(opts) {
126546
+ await putStatus(opts, "adgroup");
126547
+ }
126548
+ async function runDemandGenAdStatus(opts) {
126549
+ await putStatus(opts, "ad");
126550
+ }
126551
+ async function runDemandGenAdGroupRename(opts) {
126552
+ const name2 = opts.name.trim();
126553
+ if (!name2 || name2.length > 255) fail("\u5E7F\u544A\u7EC4\u540D\u987B\u4E3A 1\uFF5E255 \u4E2A\u5B57\u7B26\u3002");
126554
+ const accountId = requireAccountId(opts.account);
126555
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126556
+ const url = demandGenAdGroupUrl(
126557
+ googleApiUrl,
126558
+ accountId,
126559
+ opts.campaignId.trim(),
126560
+ opts.adGroupId.trim(),
126561
+ "name"
126562
+ );
126563
+ try {
126564
+ await pmaxApiFetch(url, config, { method: "PUT", body: JSON.stringify({ name: name2 }) }, opts.verbose);
126565
+ } catch (err) {
126566
+ fail(`\u5E7F\u544A\u7EC4\u6539\u540D\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`);
126567
+ }
126568
+ console.log(`
126569
+ \u2705 \u5E7F\u544A\u7EC4\u5DF2\u6539\u540D\u4E3A ${name2}
126570
+ `);
126571
+ });
126572
+ }
126573
+ async function runDemandGenAudience(opts) {
126574
+ const audienceResourceName = opts.resourceName.trim();
126575
+ if (!audienceResourceName.includes("/audiences/")) {
126576
+ fail("Audience resource name must be customers/{id}/audiences/{audienceId}.");
126577
+ }
126578
+ const accountId = requireAccountId(opts.account);
126579
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126580
+ const url = demandGenAdGroupUrl(
126581
+ googleApiUrl,
126582
+ accountId,
126583
+ opts.campaignId.trim(),
126584
+ opts.adGroupId.trim(),
126585
+ "audience"
126586
+ );
126587
+ try {
126588
+ await pmaxApiFetch(
126589
+ url,
126590
+ config,
126591
+ { method: "PUT", body: JSON.stringify({ audienceResourceName }) },
126592
+ opts.verbose
126593
+ );
126594
+ } catch (err) {
126595
+ fail(`\u66FF\u6362\u53D7\u4F17\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`);
126596
+ }
126597
+ console.log("\n\u2705 \u5E7F\u544A\u7EC4\u53D7\u4F17\u5DF2\u66FF\u6362\u3002\u4E00\u4E2A\u5E7F\u544A\u7EC4\u53EA\u80FD\u7ED1\u4E00\u4E2A Audience\u3002\n");
126598
+ });
126599
+ }
126600
+ async function runDemandGenAudienceKeywords(opts) {
126601
+ const audienceKeywords = opts.keywords.split(",").map((item) => item.trim()).filter(Boolean);
126602
+ if (audienceKeywords.length < 1 || audienceKeywords.length > 10) {
126603
+ fail("Audience keyword count must be between 1 and 10.");
126604
+ }
126605
+ const accountId = requireAccountId(opts.account);
126606
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126607
+ const url = demandGenAdGroupUrl(
126608
+ googleApiUrl,
126609
+ accountId,
126610
+ opts.campaignId.trim(),
126611
+ opts.adGroupId.trim(),
126612
+ "audience/keywords"
126613
+ );
126614
+ try {
126615
+ await pmaxApiFetch(
126616
+ url,
126617
+ config,
126618
+ { method: "PUT", body: JSON.stringify({ audienceKeywords }) },
126619
+ opts.verbose
126620
+ );
126621
+ } catch (err) {
126622
+ fail(`\u66FF\u6362\u53D7\u4F17\u8BCD\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`);
126623
+ }
126624
+ console.log("\n\u2705 \u641C\u7D22\u81EA\u5B9A\u4E49\u53D7\u4F17\u7684\u8BCD\u5DF2\u6574\u4EFD\u66FF\u6362\n");
126625
+ });
126626
+ }
126627
+ async function postChild(opts, kind) {
126628
+ const accountId = requireAccountId(opts.account);
126629
+ const raw = loadBody(opts.configFile);
126630
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126631
+ let body;
126632
+ try {
126633
+ body = await attachImages(opts.configFile, raw, accountId, config, googleApiUrl, opts.verbose);
126634
+ } catch (err) {
126635
+ fail(err instanceof Error ? err.message : String(err));
126636
+ }
126637
+ delete body["account"];
126638
+ delete body["imagePaths"];
126639
+ const url = kind === "adgroup" ? `${demandGenCampaignUrl(googleApiUrl, accountId, opts.campaignId.trim())}/ad-groups` : `${demandGenAdGroupUrl(googleApiUrl, accountId, opts.campaignId.trim(), opts.adGroupId.trim())}/ads`;
126640
+ let data;
126641
+ try {
126642
+ data = await pmaxApiFetch(url, config, { method: "POST", body: JSON.stringify(body) }, opts.verbose);
126643
+ } catch (err) {
126644
+ fail(err instanceof Error ? err.message : String(err));
126645
+ }
126646
+ if (await emit({ ...opts, account: accountId }, `ad-demand-gen-add-${kind}`, `ad demand-gen add-${kind}`, data)) {
126647
+ return;
126648
+ }
126649
+ console.log(`
126650
+ \u2705 \u5DF2\u6DFB\u52A0${kind === "adgroup" ? "\u5E7F\u544A\u7EC4" : "\u5E7F\u544A"}
126651
+ `);
126652
+ console.log(JSON.stringify(data, null, 2));
126653
+ console.log();
126654
+ });
126655
+ }
126656
+ async function runDemandGenAddAdGroup(opts) {
126657
+ await postChild(opts, "adgroup");
126658
+ }
126659
+ async function runDemandGenAddAd(opts) {
126660
+ await postChild(opts, "ad");
126661
+ }
126662
+ async function runDemandGenDeleteAd(opts) {
126663
+ ensureIConfirm({
126664
+ iConfirm: opts.iConfirm,
126665
+ actionLabel: `ad demand-gen delete-ad\uFF08\u5E7F\u544A\u7EC4\u81F3\u5C11\u7559 1 \u6761\u5E7F\u544A\uFF0C\u5426\u5219\u4F1A 400\uFF09`
126666
+ });
126667
+ const accountId = requireAccountId(opts.account);
126668
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126669
+ const url = demandGenAdUrl(
126670
+ googleApiUrl,
126671
+ accountId,
126672
+ opts.campaignId.trim(),
126673
+ opts.adGroupId.trim(),
126674
+ opts.adId.trim()
126675
+ );
126676
+ try {
126677
+ await pmaxApiFetch(url, config, { method: "DELETE" }, opts.verbose);
126678
+ } catch (err) {
126679
+ fail(`\u5220\u9664\u5E7F\u544A\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`);
126680
+ }
126681
+ console.log("\n\u2705 \u5E7F\u544A\u5DF2\u5220\u9664\n");
126682
+ });
126683
+ }
126684
+ async function runDemandGenDeleteAdGroup(opts) {
126685
+ ensureIConfirm({
126686
+ iConfirm: opts.iConfirm,
126687
+ actionLabel: `ad demand-gen delete-adgroup\uFF08\u7CFB\u5217\u81F3\u5C11\u7559 1 \u4E2A\u5E7F\u544A\u7EC4\uFF0C\u5426\u5219\u4F1A 400\uFF09`
126688
+ });
126689
+ const accountId = requireAccountId(opts.account);
126690
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126691
+ const url = demandGenAdGroupUrl(
126692
+ googleApiUrl,
126693
+ accountId,
126694
+ opts.campaignId.trim(),
126695
+ opts.adGroupId.trim()
126696
+ );
126697
+ try {
126698
+ await pmaxApiFetch(url, config, { method: "DELETE" }, opts.verbose);
126699
+ } catch (err) {
126700
+ fail(`\u5220\u9664\u5E7F\u544A\u7EC4\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`);
126701
+ }
126702
+ console.log("\n\u2705 \u5E7F\u544A\u7EC4\u5DF2\u5220\u9664\n");
126703
+ });
126704
+ }
126705
+ async function runDemandGenReport(opts) {
126706
+ const accountId = requireAccountId(opts.account);
126707
+ const startDate = toGoogleDate(opts.startDate, -7).replace(/\//g, "-");
126708
+ const endDate = toGoogleDate(opts.endDate, 0).replace(/\//g, "-");
126709
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126710
+ let data;
126711
+ try {
126712
+ data = await pmaxApiFetch(
126713
+ demandGenChannelReportUrl(googleApiUrl, accountId, opts.campaignId.trim(), startDate, endDate),
126714
+ config,
126715
+ {},
126716
+ opts.verbose
126717
+ );
126718
+ } catch (err) {
126719
+ fail(`\u8BFB\u53D6\u7248\u4F4D\u62A5\u8868\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`);
126720
+ }
126721
+ if (await emit({ ...opts, account: accountId }, "ad-demand-gen-report", "ad demand-gen report", data, opts.campaignId)) {
126722
+ return;
126723
+ }
126724
+ console.log(`
126725
+ \u2705 \u7248\u4F4D\u62A5\u8868 ${startDate} ~ ${endDate}`);
126726
+ console.log(" spend \u662F\u8D26\u6237\u5E01\u79CD\u6D6E\u70B9\uFF0C\u4E0D\u8981\u62FF\u53BB PATCH budget\u3002\u6682\u505C\u7CFB\u5217\u5168 0 \u662F\u6B63\u5E38\u7684\u3002\n");
126727
+ });
126728
+ }
126729
+ async function runDemandGenConversionsValidate(opts) {
126730
+ const accountId = requireAccountId(opts.account);
126731
+ const body = loadBody(opts.configFile);
126732
+ delete body["account"];
126733
+ await withGoogleApi(opts, async (config, googleApiUrl) => {
126734
+ let data;
126735
+ try {
126736
+ data = await pmaxApiFetch(
126737
+ demandGenConversionsValidateUrl(googleApiUrl, accountId),
126738
+ config,
126739
+ { method: "POST", body: JSON.stringify(body) },
126740
+ opts.verbose
126741
+ );
126742
+ } catch (err) {
126743
+ fail(`\u79BB\u7EBF\u8F6C\u5316\u6821\u9A8C\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}`);
126744
+ }
126745
+ if (await emit(
126746
+ { ...opts, account: accountId },
126747
+ "ad-demand-gen-conversions-validate",
126748
+ "ad demand-gen conversions-validate",
126749
+ data,
126750
+ accountId
126751
+ )) {
126752
+ return;
126753
+ }
126754
+ console.log("\n\u2705 \u79BB\u7EBF\u8F6C\u5316\u53EA\u505A\u4E86\u6821\u9A8C\uFF0C\u6CA1\u6709\u5199\u5165\u3002validatedOnly \u5E94\u4E3A true\u3002\n");
126755
+ });
126756
+ }
126757
+
126758
+ // src/commands/ad/demand-gen-register.ts
126759
+ function withCommon(cmd) {
126760
+ return cmd.option("-t, --token <token>", "Auth Token").option("--json-out <path>", "\u843D\u76D8\u54CD\u5E94\u5E76\u66F4\u65B0 cli-manifest").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false);
126761
+ }
126762
+ function registerDemandGen(adCmd) {
126763
+ const dg = adCmd.command("demand-gen").description(
126764
+ "Google Demand Gen\uFF08\u9700\u6C42\u5F00\u53D1\uFF09\u3002\u4E0D\u8981\u7528 campaign-edit / pmax-edit / campaign-create\u3002\n \u521B\u5EFA\u56FA\u5B9A\u6682\u505C\u3002\u542F\u7528\u7CFB\u5217\u4F1A\u82B1\u94B1\uFF1Aedit --status Enabled --confirm-enable --i-confirm\u3002"
126765
+ );
126766
+ withCommon(
126767
+ dg.command("list").description("\u672A\u5220\u9664\u7684 Demand Gen \u5217\u8868\u3002budget \u662F\u5206\uFF0C\u770B budgetYuan\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID")
126768
+ ).action(runDemandGenList);
126769
+ withCommon(
126770
+ dg.command("get").description("\u7CFB\u5217\u8BE6\u60C5\uFF1A\u5E7F\u544A\u7EC4\u3001\u5E7F\u544A\u3001\u53D7\u4F17\u3001\u80FD\u5426\u6295\u653E\u3002\u4E0D\u8981\u628A\u6574\u5305 PATCH \u56DE\u53BB\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--campaign-id <id>", "\u7CFB\u5217 ID")
126771
+ ).action(runDemandGenGet);
126772
+ withCommon(
126773
+ dg.command("minimum-budget").description("\u5E01\u79CD\u6700\u4F4E\u65E5\u9884\u7B97\u3002\u4E0D\u4F20 --currency \u7528\u8D26\u6237\u5E01\u79CD\u3002minimumDailyBudget \u662F\u5206\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").option("--currency <code>", "\u5982 USD")
126774
+ ).action(runDemandGenMinimumBudget);
126775
+ withCommon(
126776
+ dg.command("conversions").description("\u53EF\u51FA\u4EF7\u7684\u8BE2\u76D8/\u6210\u4EA4\u8F6C\u5316\u3002\u6CA1\u6709\u65F6\u521B\u5EFA\u7528 TARGET_SPEND\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID")
126777
+ ).action(runDemandGenConversions);
126778
+ withCommon(
126779
+ dg.command("draft").description("\u6309\u843D\u5730\u9875\u51FA\u8349\u7A3F\uFF0C\u4E0D\u5199 Google\u3002\u91D1\u989D\u586B\u5143\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--config-file <path>", "\u8349\u7A3F JSON\uFF08pageUrl\u3001mainKeyword\uFF09")
126780
+ ).action(runDemandGenDraft);
126781
+ withCommon(
126782
+ dg.command("validate").description("\u6574\u5355\u6821\u9A8C\uFF0C\u4E0D\u843D\u5E93\u3002JSON \u91D1\u989D\u586B\u5143\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--config-file <path>", "\u521B\u5EFA JSON")
126783
+ ).action(runDemandGenValidate);
126784
+ withCommon(
126785
+ dg.command("create").description("\u521B\u5EFA\u5E76\u56FA\u5B9A\u6682\u505C\u3002\u5931\u8D25\u65F6\u628A budgetId/campaignId/adGroupId \u5199\u56DE JSON \u518D\u8DD1\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--config-file <path>", "\u521B\u5EFA JSON\uFF0C\u6A21\u677F\u89C1 assets/demand-gen-create-template.json")
126786
+ ).action(runDemandGenCreate);
126787
+ withCommon(
126788
+ dg.command("confirm").description("\u653F\u7B56\u9884\u5BA1\u540E\u521B\u5EFA\uFF0C\u4ECD\u7136\u6682\u505C\u3002\u53EF\u76F4\u63A5\u4F20\u8349\u7A3F JSON\uFF08\u7528\u91CC\u9762\u7684 createRequest\uFF09\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--config-file <path>", "\u8865\u5B8C\u7D20\u6750\u540E\u7684\u521B\u5EFA JSON\uFF0C\u6216\u8349\u7A3F\u54CD\u5E94")
126789
+ ).action(runDemandGenConfirm);
126790
+ withCommon(
126791
+ dg.command("edit").description(
126792
+ "\u53EA\u6539\u7CFB\u5217\u540D\u3001\u9884\u7B97\u3001\u51FA\u4EF7\u6216\u72B6\u6001\u3002\u9884\u7B97\u586B\u5143\uFF0C\u4E14\u5FC5\u987B\u5E26 --budget-id\u3002\n \u542F\u7528\uFF1A--status Enabled --confirm-enable --i-confirm\u3002\u4E0D\u8981\u5E26 automatic\u3002"
126793
+ ).requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--campaign-id <id>", "\u7CFB\u5217 ID").option("--patch-file <path>", "\u53EA\u542B\u8981\u6539\u7684\u5B57\u6BB5\uFF1B\u91D1\u989D\u586B\u5143").option("--name <name>", "\u7CFB\u5217\u540D").option("--status <status>", "Enabled | Paused | Removed").option("--budget <amount>", "\u65E5\u9884\u7B97\uFF0C\u4E3B\u5E01\u79CD\u5143").option("--budget-id <id>", "\u8FD9\u6761\u7CFB\u5217\u81EA\u5DF1\u7684\u9884\u7B97 ID").option("--bidding <strategy>", "TARGET_CPA | TARGET_ROAS | \u2026").option("--target-cpa <amount>", "\u76EE\u6807 CPA\uFF0C\u5143\u3002\u5B57\u6BB5\u540D\u4ECD\u662F targetCpa_BidingAmount").option("--target-roas <ratio>", "\u76EE\u6807 ROAS \u6BD4\u7387\uFF0C2.5 = 250%").option("--confirm-large-change", "\u9884\u7B97\u6216\u51FA\u4EF7\u53D8\u52A8\u8D85\u8FC7 15% \u65F6\u5FC5\u5E26").option("--confirm-enable", "\u628A\u7CFB\u5217\u6539\u6210 Enabled \u65F6\u5FC5\u5E26").option("--i-confirm", "\u7528\u6237\u5DF2\u660E\u786E\u540C\u610F\u542F\u7528\u6216\u79FB\u9664")
126794
+ ).action(runDemandGenEdit);
126795
+ withCommon(
126796
+ dg.command("content").description("\u6539\u5E7F\u544A\u6587\u6848\u548C\u7D20\u6750\u3002\u4E0D\u4F20 --ad-id \u65F6\u6539\u6574\u7EC4\uFF0C\u5E76\u53EF\u4EE5\u6539\u5730\u57DF\u8BED\u8A00\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--campaign-id <id>", "\u7CFB\u5217 ID").requiredOption("--ad-group-id <id>", "\u5E7F\u544A\u7EC4 ID").option("--ad-id <id>", "\u53EA\u6539\u8FD9\u4E00\u6761\u5E7F\u544A\uFF1B\u4E0D\u8981\u5728 JSON \u91CC\u5E26\u5730\u57DF\u8BED\u8A00").requiredOption("--config-file <path>", "\u8981\u6539\u7684\u5B57\u6BB5\u3002\u7A7A\u5B57\u6BB5\u4FDD\u6301\u4E0D\u52A8")
126797
+ ).action(runDemandGenContent);
126798
+ withCommon(
126799
+ dg.command("channels").description("\u6539\u7248\u4F4D\u3002--strategy \u4E0E --selected \u4E8C\u9009\u4E00\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--campaign-id <id>", "\u7CFB\u5217 ID").requiredOption("--ad-group-id <id>", "\u5E7F\u544A\u7EC4 ID").option("--strategy <name>", "ALL_OWNED_AND_OPERATED_CHANNELS \u6216 ALL_CHANNELS").option("--selected <list>", "\u9017\u53F7\u5206\u9694\uFF1AyoutubeInStream,discover,gmail,maps,display,youtubeInFeed,youtubeShorts")
126800
+ ).action(runDemandGenChannels);
126801
+ withCommon(
126802
+ dg.command("adgroup-status").description("\u505C\u6216\u5F00\u5E7F\u544A\u7EC4\u3002\u7CFB\u5217\u72B6\u6001\u4E0D\u53D8\u3002\u53EA\u63A5\u53D7 Enabled \u6216 Paused\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--campaign-id <id>", "\u7CFB\u5217 ID").requiredOption("--ad-group-id <id>", "\u5E7F\u544A\u7EC4 ID").requiredOption("--status <status>", "Enabled | Paused")
126803
+ ).action(runDemandGenAdGroupStatus);
126804
+ withCommon(
126805
+ dg.command("ad-status").description("\u505C\u6216\u5F00\u4E00\u6761\u5E7F\u544A\u3002\u7CFB\u5217\u72B6\u6001\u4E0D\u53D8\u3002\u53EA\u63A5\u53D7 Enabled \u6216 Paused\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--campaign-id <id>", "\u7CFB\u5217 ID").requiredOption("--ad-group-id <id>", "\u5E7F\u544A\u7EC4 ID").requiredOption("--ad-id <id>", "\u5E7F\u544A ID").requiredOption("--status <status>", "Enabled | Paused")
126806
+ ).action(runDemandGenAdStatus);
126807
+ withCommon(
126808
+ dg.command("adgroup-rename").description("\u53EA\u6539\u5E7F\u544A\u7EC4\u540D\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--campaign-id <id>", "\u7CFB\u5217 ID").requiredOption("--ad-group-id <id>", "\u5E7F\u544A\u7EC4 ID").requiredOption("--name <name>", "1\uFF5E255 \u5B57\u7B26")
126809
+ ).action(runDemandGenAdGroupRename);
126810
+ withCommon(
126811
+ dg.command("audience").description("\u628A\u5E7F\u544A\u7EC4\u7684\u552F\u4E00\u4EBA\u7FA4\u6362\u6210\u8FD9\u4E2A Audience\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--campaign-id <id>", "\u7CFB\u5217 ID").requiredOption("--ad-group-id <id>", "\u5E7F\u544A\u7EC4 ID").requiredOption("--resource-name <name>", "customers/{id}/audiences/{audienceId}")
126812
+ ).action(runDemandGenAudience);
126813
+ withCommon(
126814
+ dg.command("audience-keywords").description("\u6574\u4EFD\u66FF\u6362\u641C\u7D22\u81EA\u5B9A\u4E49\u53D7\u4F17\u7684\u8BCD\uFF0C1\uFF5E10 \u4E2A\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--campaign-id <id>", "\u7CFB\u5217 ID").requiredOption("--ad-group-id <id>", "\u5E7F\u544A\u7EC4 ID").requiredOption("--keywords <list>", "\u9017\u53F7\u5206\u9694")
126815
+ ).action(runDemandGenAudienceKeywords);
126816
+ withCommon(
126817
+ dg.command("add-adgroup").description("\u518D\u52A0\u4E00\u4E2A\u5E7F\u544A\u7EC4\uFF1A\u4E00\u6761\u89C6\u9891\u5E7F\u544A + \u4E00\u6761\u56FE\u7247\u5E7F\u544A\u3002\u4E0D\u6539\u7CFB\u5217\u9884\u7B97\u548C\u51FA\u4EF7\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--campaign-id <id>", "\u7CFB\u5217 ID").requiredOption("--config-file <path>", "\u5E7F\u544A\u7EC4 JSON\uFF0CadGroupName \u5FC5\u586B")
126818
+ ).action(runDemandGenAddAdGroup);
126819
+ withCommon(
126820
+ dg.command("add-ad").description("\u518D\u52A0\u5E7F\u544A\u3002\u6709\u89C6\u9891\u52A0\u89C6\u9891\uFF0C\u6709\u56FE\u7247\u52A0\u56FE\u7247\uFF0C\u53EF\u4EE5\u53EA\u52A0\u4E00\u79CD\u3002Logo \u5FC5\u586B\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--campaign-id <id>", "\u7CFB\u5217 ID").requiredOption("--ad-group-id <id>", "\u5E7F\u544A\u7EC4 ID").requiredOption("--config-file <path>", "\u5E7F\u544A JSON")
126821
+ ).action(runDemandGenAddAd);
126822
+ withCommon(
126823
+ dg.command("delete-ad").description("\u5220\u9664\u4E00\u6761\u5E7F\u544A\u3002\u7EC4\u5185\u81F3\u5C11\u7559\u4E00\u6761\uFF0C\u5426\u5219 400\u3002\u987B --i-confirm\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--campaign-id <id>", "\u7CFB\u5217 ID").requiredOption("--ad-group-id <id>", "\u5E7F\u544A\u7EC4 ID").requiredOption("--ad-id <id>", "\u5E7F\u544A ID").option("--i-confirm", "\u7528\u6237\u5DF2\u660E\u786E\u540C\u610F\u5220\u9664")
126824
+ ).action(runDemandGenDeleteAd);
126825
+ withCommon(
126826
+ dg.command("delete-adgroup").description("\u5220\u9664\u4E00\u4E2A\u5E7F\u544A\u7EC4\u3002\u7CFB\u5217\u81F3\u5C11\u7559\u4E00\u4E2A\u7EC4\uFF0C\u5426\u5219 400\u3002\u987B --i-confirm\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--campaign-id <id>", "\u7CFB\u5217 ID").requiredOption("--ad-group-id <id>", "\u5E7F\u544A\u7EC4 ID").option("--i-confirm", "\u7528\u6237\u5DF2\u660E\u786E\u540C\u610F\u5220\u9664")
126827
+ ).action(runDemandGenDeleteAdGroup);
126828
+ withCommon(
126829
+ dg.command("report").description("\u6309\u7248\u4F4D\u3001\u5929\u3001\u5E7F\u544A\u770B\u6570\u3002spend \u662F\u8D26\u6237\u5E01\u79CD\u6D6E\u70B9\u3002\u6682\u505C\u7CFB\u5217\u5168 0 \u4ECD\u662F\u6210\u529F\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--campaign-id <id>", "\u7CFB\u5217 ID").option("--start-date <date>", "\u9ED8\u8BA4 7 \u5929\u524D\uFF0CYYYY-MM-DD").option("--end-date <date>", "\u9ED8\u8BA4\u4ECA\u5929")
126830
+ ).action(runDemandGenReport);
126831
+ withCommon(
126832
+ dg.command("conversions-validate").description("\u79BB\u7EBF\u8F6C\u5316\u53EA\u6821\u9A8C\uFF0C\u4E0D\u5199\u5165\u3002leadBiddable \u5FC5\u987B true\uFF0CpageViewBiddable \u5FC5\u987B false\u3002").requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--config-file <path>", "\u8F6C\u5316 JSON\u3002conversionValue \u662F\u8D26\u6237\u5E01\u79CD\uFF0C\u4E0D\u8981 \xD7100")
126833
+ ).action(runDemandGenConversionsValidate);
126834
+ }
126835
+
125845
126836
  // src/commands/ad/_register.ts
125846
126837
  function parseOptionalMatchType(raw) {
125847
126838
  if (!raw?.trim()) return void 0;
@@ -127170,6 +128161,7 @@ function register21(program2) {
127170
128161
  });
127171
128162
  }
127172
128163
  );
128164
+ registerDemandGen(adCmd);
127173
128165
  }
127174
128166
 
127175
128167
  // src/commands/meta-ad/account.ts
@@ -127404,9 +128396,9 @@ function metaAdContext(token) {
127404
128396
  return { config, facebookApiUrl: requireFacebookApi(config) };
127405
128397
  }
127406
128398
  function adsUrl(facebookApiUrl, account, path56) {
127407
- const base = metaAdsBaseUrl(facebookApiUrl, account);
128399
+ const base2 = metaAdsBaseUrl(facebookApiUrl, account);
127408
128400
  const p = path56.startsWith("/") ? path56 : `/${path56}`;
127409
- return `${base}${p}`;
128401
+ return `${base2}${p}`;
127410
128402
  }
127411
128403
  async function metaAdGet(url, config, verbose, action) {
127412
128404
  try {
@@ -130198,13 +131190,13 @@ function appendGeoTargetConstantIdsQuery(baseUrl, geoTargetConstantIds) {
130198
131190
  return `${baseUrl}?${qs}`;
130199
131191
  }
130200
131192
  function buildKeywordIdeaGoogleUrl(googleApiUrl, geoTargetConstantIds) {
130201
- const base = `${googleApiUrl.replace(/\/$/, "")}/keywordidea/google`;
130202
- return appendGeoTargetConstantIdsQuery(base, geoTargetConstantIds);
131193
+ const base2 = `${googleApiUrl.replace(/\/$/, "")}/keywordidea/google`;
131194
+ return appendGeoTargetConstantIdsQuery(base2, geoTargetConstantIds);
130203
131195
  }
130204
131196
  function buildKeywordRecommendationGoogleUrl(googleApiUrl, mediaCustomerId, geoTargetConstantIds) {
130205
131197
  const id = encodeURIComponent(mediaCustomerId.trim());
130206
- const base = `${googleApiUrl.replace(/\/$/, "")}/keywordrecommendation/recommend/${id}/google`;
130207
- return appendGeoTargetConstantIdsQuery(base, geoTargetConstantIds);
131198
+ const base2 = `${googleApiUrl.replace(/\/$/, "")}/keywordrecommendation/recommend/${id}/google`;
131199
+ return appendGeoTargetConstantIdsQuery(base2, geoTargetConstantIds);
130208
131200
  }
130209
131201
  function geoTargetConstantsListPath(googleApiUrl) {
130210
131202
  return `${googleApiUrl.replace(/\/$/, "")}/geotargetmanagement/GeoTargetConstans`;
@@ -131248,7 +132240,7 @@ function mccResponseHasSuccess(res, managerId) {
131248
132240
  }
131249
132241
  async function runAccountMccBind(opts) {
131250
132242
  const config = loadConfig(opts.token);
131251
- const base = googleGatewayBase(config);
132243
+ const base2 = googleGatewayBase(config);
131252
132244
  const managerIds = parseMccManagerIds(opts.mcc);
131253
132245
  if (managerIds.length === 0) {
131254
132246
  console.error("\n\u274C --mcc \u4E2D\u672A\u89E3\u6790\u51FA\u6709\u6548\u7684\u6570\u5B57\u578B MCC \u5BA2\u6237 ID\n");
@@ -131261,7 +132253,7 @@ async function runAccountMccBind(opts) {
131261
132253
  const body = { agentTypes: [...MCC_AGENT_TYPES], managerIds };
131262
132254
  const results = [];
131263
132255
  for (const customerId of opts.customers) {
131264
- const url = `${base}/command/media-account/${customerId}/CustomerLinks`;
132256
+ const url = `${base2}/command/media-account/${customerId}/CustomerLinks`;
131265
132257
  try {
131266
132258
  const response = await apiFetch2(
131267
132259
  url,
@@ -131306,7 +132298,7 @@ async function runAccountMccBind(opts) {
131306
132298
  async function runAccountMccUnbind(opts) {
131307
132299
  ensureIConfirm({ iConfirm: opts.iConfirm, actionLabel: "account mcc-unbind\uFF08Google MCC \u89E3\u7ED1\uFF09" });
131308
132300
  const config = loadConfig(opts.token);
131309
- const base = googleGatewayBase(config);
132301
+ const base2 = googleGatewayBase(config);
131310
132302
  const managerIds = parseMccManagerIds(opts.mcc);
131311
132303
  if (managerIds.length === 0) {
131312
132304
  console.error("\n\u274C --mcc \u4E2D\u672A\u89E3\u6790\u51FA\u6709\u6548\u7684\u6570\u5B57\u578B MCC \u5BA2\u6237 ID\n");
@@ -131318,7 +132310,7 @@ async function runAccountMccUnbind(opts) {
131318
132310
  }
131319
132311
  const results = [];
131320
132312
  for (const customerId of opts.customers) {
131321
- const url = `${base}/command/media-account/${customerId}/CustomerUnlinks`;
132313
+ const url = `${base2}/command/media-account/${customerId}/CustomerUnlinks`;
131322
132314
  try {
131323
132315
  const response = await apiFetch2(
131324
132316
  url,
@@ -131396,7 +132388,7 @@ function parseCustomerAccessPermissionBody(text3) {
131396
132388
  return trimmed;
131397
132389
  }
131398
132390
  function interpretCustomerAccessPermission(mediaCustomerId, httpStatus, rawBody) {
131399
- const base = {
132391
+ const base2 = {
131400
132392
  mediaCustomerId,
131401
132393
  httpStatus,
131402
132394
  rawBody
@@ -131404,7 +132396,7 @@ function interpretCustomerAccessPermission(mediaCustomerId, httpStatus, rawBody)
131404
132396
  if (httpStatus === 200) {
131405
132397
  if (rawBody === true) {
131406
132398
  return {
131407
- ...base,
132399
+ ...base2,
131408
132400
  status: "accessible",
131409
132401
  accessible: true,
131410
132402
  message: "\u5F53\u524D\u4E1D\u8DEF\u8D5E\u8D26\u53F7\u53EF\u8BBF\u95EE\u8BE5 Google \u5E7F\u544A\u8D26\u6237\u3002"
@@ -131412,7 +132404,7 @@ function interpretCustomerAccessPermission(mediaCustomerId, httpStatus, rawBody)
131412
132404
  }
131413
132405
  if (rawBody === false) {
131414
132406
  return {
131415
- ...base,
132407
+ ...base2,
131416
132408
  status: "reauth_required",
131417
132409
  accessible: false,
131418
132410
  message: "\u8D26\u6237\u5DF2\u7ED1\u5B9A\u4F46 Google OAuth \u4E0D\u53EF\u7528\uFF0C\u9700\u91CD\u65B0\u6388\u6743\u3002",
@@ -131420,7 +132412,7 @@ function interpretCustomerAccessPermission(mediaCustomerId, httpStatus, rawBody)
131420
132412
  };
131421
132413
  }
131422
132414
  return {
131423
- ...base,
132415
+ ...base2,
131424
132416
  status: "unknown",
131425
132417
  accessible: false,
131426
132418
  message: `HTTP 200 \u4F46\u54CD\u5E94\u4F53\u975E\u5E38\u89C4\uFF08${String(rawBody)}\uFF09\uFF0C\u8BF7\u7528 --verbose \u67E5\u770B\u539F\u59CB\u54CD\u5E94\u3002`
@@ -131430,7 +132422,7 @@ function interpretCustomerAccessPermission(mediaCustomerId, httpStatus, rawBody)
131430
132422
  const text3 = typeof rawBody === "string" ? rawBody : rawBody == null ? "" : String(rawBody);
131431
132423
  if (text3.includes("token\u4E0D\u80FD\u4E3A\u7A7A") || text3.toLowerCase().includes("token") && text3.includes("\u7A7A")) {
131432
132424
  return {
131433
- ...base,
132425
+ ...base2,
131434
132426
  status: "google_not_bound",
131435
132427
  accessible: false,
131436
132428
  message: "\u5F53\u524D\u4E1D\u8DEF\u8D5E\u8D26\u53F7\u672A\u7ED1\u5B9A Google \u5A92\u4F53\u6388\u6743\u3002",
@@ -131438,7 +132430,7 @@ function interpretCustomerAccessPermission(mediaCustomerId, httpStatus, rawBody)
131438
132430
  };
131439
132431
  }
131440
132432
  return {
131441
- ...base,
132433
+ ...base2,
131442
132434
  status: "no_permission",
131443
132435
  accessible: false,
131444
132436
  message: "\u5F53\u524D\u4E1D\u8DEF\u8D5E\u8D26\u53F7\u5BF9\u8BE5 Google \u5E7F\u544A\u8D26\u6237\u65E0\u8BBF\u95EE\u6743\u9650\uFF1B\u901A\u5E38\u8868\u793A\u8BE5\u8D26\u6237\u4E0D\u5728\u672C\u8D26\u53F7\u4E0B\uFF08\u6216\u672A\u5206\u4EAB\u7ED9\u4F60\uFF09\u3002",
@@ -131447,7 +132439,7 @@ function interpretCustomerAccessPermission(mediaCustomerId, httpStatus, rawBody)
131447
132439
  }
131448
132440
  if (httpStatus === 401) {
131449
132441
  return {
131450
- ...base,
132442
+ ...base2,
131451
132443
  status: "siluzan_token_invalid",
131452
132444
  accessible: false,
131453
132445
  message: "\u4E1D\u8DEF\u8D5E\u767B\u5F55\u51ED\u636E\u65E0\u6548\u6216\u5DF2\u8FC7\u671F\u3002",
@@ -131455,15 +132447,15 @@ function interpretCustomerAccessPermission(mediaCustomerId, httpStatus, rawBody)
131455
132447
  };
131456
132448
  }
131457
132449
  return {
131458
- ...base,
132450
+ ...base2,
131459
132451
  status: "unknown",
131460
132452
  accessible: false,
131461
132453
  message: `\u672A\u9884\u671F\u7684 HTTP ${httpStatus}\uFF1B\u8BF7\u7528 --verbose \u67E5\u770B\u539F\u59CB\u54CD\u5E94\u3002`
131462
132454
  };
131463
132455
  }
131464
132456
  function buildCustomerAccessPermissionUrl(googleApiUrl, mediaCustomerId) {
131465
- const base = googleApiUrl.replace(/\/$/, "");
131466
- return `${base}/query/media-account/${mediaCustomerId}/customer-access-permission`;
132457
+ const base2 = googleApiUrl.replace(/\/$/, "");
132458
+ return `${base2}/query/media-account/${mediaCustomerId}/customer-access-permission`;
131467
132459
  }
131468
132460
  async function fetchGoogleCustomerAccessPermission(config, mediaCustomerId, verbose) {
131469
132461
  await ensureDataPermission(config);
@@ -132151,8 +133143,8 @@ async function runAccountBcBind(opts) {
132151
133143
  process.exit(1);
132152
133144
  }
132153
133145
  const config = loadConfig(opts.token);
132154
- const base = tiktokGatewayBase(config);
132155
- const url = `${base}/bcmanagement/AddPartnerList`;
133146
+ const base2 = tiktokGatewayBase(config);
133147
+ const url = `${base2}/bcmanagement/AddPartnerList`;
132156
133148
  const body = { bcIds: opts.bcIds, mediacustomerIds: opts.customers };
132157
133149
  let result;
132158
133150
  try {
@@ -132202,8 +133194,8 @@ async function runAccountBcUnbind(opts) {
132202
133194
  process.exit(1);
132203
133195
  }
132204
133196
  const config = loadConfig(opts.token);
132205
- const base = tiktokGatewayBase(config);
132206
- const url = `${base}/bcmanagement/DeletePartnerAssetList`;
133197
+ const base2 = tiktokGatewayBase(config);
133198
+ const url = `${base2}/bcmanagement/DeletePartnerAssetList`;
132207
133199
  const body = [{ bcId: opts.bcId, mediacustomerIds: opts.customers }];
132208
133200
  let result;
132209
133201
  try {
@@ -132249,13 +133241,13 @@ function isLikelyPendingInvitationStatus(status) {
132249
133241
  return status.trim().toUpperCase().includes("PENDING");
132250
133242
  }
132251
133243
  async function fetchCustomerUserAccessInvitationList(config, customerId, verbose, agentType) {
132252
- const base = googleGatewayBase(config);
133244
+ const base2 = googleGatewayBase(config);
132253
133245
  const params = new URLSearchParams({ customerId });
132254
133246
  const at = agentType?.trim();
132255
133247
  if (at) {
132256
133248
  params.set("AgentType", at);
132257
133249
  }
132258
- const url = `${base}/query/media-account/GetCustomerUserAccessInvitation?${params}`;
133250
+ const url = `${base2}/query/media-account/GetCustomerUserAccessInvitation?${params}`;
132259
133251
  const data = await apiFetch2(url, config, {}, verbose ?? false);
132260
133252
  return Array.isArray(data) ? data : [];
132261
133253
  }
@@ -132359,8 +133351,8 @@ async function runAccountEmailAuthList(opts) {
132359
133351
  }
132360
133352
  async function runAccountEmailAuth(opts) {
132361
133353
  const config = await ensureDataPermission(loadConfig(opts.token));
132362
- const base = googleGatewayBase(config);
132363
- const url = `${base}/command/media-account/MutateCustomerUserAccessInvitation`;
133354
+ const base2 = googleGatewayBase(config);
133355
+ const url = `${base2}/command/media-account/MutateCustomerUserAccessInvitation`;
132364
133356
  const body = {
132365
133357
  CustomerId: opts.customerId,
132366
133358
  EmailAddress: opts.email,
@@ -132445,9 +133437,9 @@ async function runAccountEmailAuth(opts) {
132445
133437
  }
132446
133438
  async function runAccountEmailDeauth(opts) {
132447
133439
  const config = await ensureDataPermission(loadConfig(opts.token));
132448
- const base = googleGatewayBase(config);
133440
+ const base2 = googleGatewayBase(config);
132449
133441
  const endpoint = opts.accepted !== false ? "RemoveCustomerUserAccess" : "RemoveCustomerUserAccessInvitation";
132450
- const url = `${base}/command/media-account/${endpoint}`;
133442
+ const url = `${base2}/command/media-account/${endpoint}`;
132451
133443
  const resourceName = opts.resourceName?.trim() || `customers/${opts.customerId}/customerUserAccessInvitations/${opts.invitationId}`;
132452
133444
  const body = {
132453
133445
  CustomerId: opts.customerId,
@@ -133760,7 +134752,7 @@ async function runOpenAccountGoogle(opts) {
133760
134752
  const promotionLinkNorm = normalizePromotionLinkForGoogle(opts.promotionLink);
133761
134753
  const body = {
133762
134754
  accountInfo: Array.from({ length: counts }, (_, i) => {
133763
- const base = buildGoogleAccountInfoItem({
134755
+ const base2 = buildGoogleAccountInfoItem({
133764
134756
  accountName: opts.accountName,
133765
134757
  currency: opts.currency,
133766
134758
  timezone,
@@ -133773,9 +134765,9 @@ async function runOpenAccountGoogle(opts) {
133773
134765
  promotionType: opts.promotionType,
133774
134766
  autoAllotMailbox: opts.autoAllotMailbox
133775
134767
  });
133776
- const adv = base.advertiser_info;
134768
+ const adv = base2.advertiser_info;
133777
134769
  adv.name = counts > 1 ? `${opts.accountName}-${i + 1}` : opts.accountName;
133778
- return base;
134770
+ return base2;
133779
134771
  }),
133780
134772
  MediaAccountGroupId: magKey,
133781
134773
  IsSaltAdd: false,
@@ -134225,8 +135217,8 @@ function parseMetaOpenAccountLinkResponse(raw) {
134225
135217
  throw new Error("\u63A5\u53E3\u672A\u8FD4\u56DE\u6709\u6548\u7684 Meta/Facebook \u5F00\u6237\u94FE\u63A5\uFF08\u987B\u4E3A https URL\uFF09");
134226
135218
  }
134227
135219
  function metaOpenAccountLinkApiUrl(apiBaseUrl) {
134228
- const base = apiBaseUrl.replace(/\/$/, "");
134229
- return `${base}${META_OPEN_ACCOUNT_LINK_PATH}`;
135220
+ const base2 = apiBaseUrl.replace(/\/$/, "");
135221
+ return `${base2}${META_OPEN_ACCOUNT_LINK_PATH}`;
134230
135222
  }
134231
135223
  async function fetchMetaOpenAccountLink(config, verbose) {
134232
135224
  const url = metaOpenAccountLinkApiUrl(config.apiBaseUrl);
@@ -134888,8 +135880,8 @@ init_auth();
134888
135880
  function resolveAgentApiBase(tsoApiBaseUrl) {
134889
135881
  const fromEnv = process.env.SILUZAN_AGENT_BASE?.trim();
134890
135882
  if (fromEnv) return requireWhitelistedBase("SILUZAN_AGENT_BASE", fromEnv);
134891
- const base = tsoApiBaseUrl ?? "";
134892
- if (base.includes("-ci") || base.includes("ci.")) {
135883
+ const base2 = tsoApiBaseUrl ?? "";
135884
+ if (base2.includes("-ci") || base2.includes("ci.")) {
134893
135885
  return "https://agent-ci.mysiluzan.com";
134894
135886
  }
134895
135887
  return "https://agent.mysiluzan.com";
@@ -134918,8 +135910,8 @@ function pickDownloadedHtml(settled) {
134918
135910
  return { ok: true, value };
134919
135911
  }
134920
135912
  async function fetchWebsiteHtml(config, websiteUrl, verbose) {
134921
- const base = resolveAgentApiBase(config.apiBaseUrl);
134922
- const url = `${base}/download-assets`;
135913
+ const base2 = resolveAgentApiBase(config.apiBaseUrl);
135914
+ const url = `${base2}/download-assets`;
134923
135915
  const bodyStr = JSON.stringify({ urls: [websiteUrl] });
134924
135916
  const headers = {
134925
135917
  "Content-Type": "application/json; charset=utf-8",
@@ -135213,7 +136205,7 @@ function readJsonFile(filePath) {
135213
136205
  }
135214
136206
  });
135215
136207
  }
135216
- function asRecord5(value) {
136208
+ function asRecord6(value) {
135217
136209
  if (value && typeof value === "object" && !Array.isArray(value)) {
135218
136210
  return value;
135219
136211
  }
@@ -135276,10 +136268,10 @@ function injectReportData(html, payload, lang) {
135276
136268
  async function runWebsiteDiagnosisRender(opts) {
135277
136269
  const dataPath = path21.resolve(opts.dataFile);
135278
136270
  const dataRaw = await readJsonFile(dataPath);
135279
- let data = asRecord5(dataRaw);
136271
+ let data = asRecord6(dataRaw);
135280
136272
  if (opts.collectFile) {
135281
136273
  const collectRaw = await readJsonFile(path21.resolve(opts.collectFile));
135282
- data = mergeCollectLighthouse(data, asRecord5(collectRaw));
136274
+ data = mergeCollectLighthouse(data, asRecord6(collectRaw));
135283
136275
  }
135284
136276
  const planError = priorityPlanError(data);
135285
136277
  if (planError) {
@@ -135951,7 +136943,7 @@ function formatMarketReportContentErrors(result) {
135951
136943
 
135952
136944
  // src/commands/market-analysis/render-report.ts
135953
136945
  init_lang();
135954
- function asRecord6(value) {
136946
+ function asRecord7(value) {
135955
136947
  if (value && typeof value === "object" && !Array.isArray(value)) {
135956
136948
  return value;
135957
136949
  }
@@ -135981,7 +136973,7 @@ async function runMarketAnalysisRender(opts) {
135981
136973
  }
135982
136974
  let html;
135983
136975
  try {
135984
- html = resolveMarketAnalysisHtml(asRecord6(dataRaw));
136976
+ html = resolveMarketAnalysisHtml(asRecord7(dataRaw));
135985
136977
  } catch (err) {
135986
136978
  const message = err instanceof Error ? err.message : String(err);
135987
136979
  console.error(`
@@ -135993,7 +136985,7 @@ async function runMarketAnalysisRender(opts) {
135993
136985
  console.error("\n\u274C \u62A5\u544A HTML \u5185\u5BB9\u4E3A\u7A7A\n");
135994
136986
  process.exit(1);
135995
136987
  }
135996
- const reportData = asRecord6(dataRaw);
136988
+ const reportData = asRecord7(dataRaw);
135997
136989
  const lang = readReportLangOrExit({ flag: opts.lang, meta: reportData.meta });
135998
136990
  try {
135999
136991
  assertHtmlLangMatches(html, lang);
@@ -136276,7 +137268,7 @@ function sectionRecord(env) {
136276
137268
  }
136277
137269
 
136278
137270
  // src/commands/google-ads-diagnosis/gold-text-ads.ts
136279
- function asRecord7(value) {
137271
+ function asRecord8(value) {
136280
137272
  if (value && typeof value === "object" && !Array.isArray(value)) {
136281
137273
  return value;
136282
137274
  }
@@ -136330,7 +137322,7 @@ function noteUnqualified(gold, suggestions, flag, itemName, present, sentence) {
136330
137322
  }
136331
137323
  function reconcileGoldAccount(gold, evidence = {}) {
136332
137324
  const next = { ...gold };
136333
- const suggestions = { ...asRecord7(gold.goldItemSuggestions) ?? {} };
137325
+ const suggestions = { ...asRecord8(gold.goldItemSuggestions) ?? {} };
136334
137326
  const notes = {};
136335
137327
  const conversions = evidence.conversionActions ?? [];
136336
137328
  const extensions = evidence.extensions ?? [];
@@ -136437,8 +137429,8 @@ function loadEvidence(snapDir, accountId, start, end) {
136437
137429
  };
136438
137430
  }
136439
137431
  function reconcileGoldAccountInReport(data, snapDir) {
136440
- const gold = asRecord7(data.goldAccount) ?? {};
136441
- const account = asRecord7(data.accountInfo);
137432
+ const gold = asRecord8(data.goldAccount) ?? {};
137433
+ const account = asRecord8(data.accountInfo);
136442
137434
  const accountId = String(account?.companyId ?? "").replace(/\D/g, "");
136443
137435
  const { start, end } = parsePeriod(String(account?.period ?? ""));
136444
137436
  const evidence = snapDir && accountId ? loadEvidence(snapDir, accountId, start, end) : {};
@@ -137199,14 +138191,14 @@ function buildGoogleAdsDiagnosisCollectPayload(opts) {
137199
138191
  }
137200
138192
 
137201
138193
  // src/commands/google-ads-diagnosis/collect-digest.ts
137202
- function asRecord8(value) {
138194
+ function asRecord9(value) {
137203
138195
  if (value && typeof value === "object" && !Array.isArray(value)) {
137204
138196
  return value;
137205
138197
  }
137206
138198
  return null;
137207
138199
  }
137208
138200
  function fieldsOfFirstRow(rows) {
137209
- const first = asRecord8(rows[0]);
138201
+ const first = asRecord9(rows[0]);
137210
138202
  return first ? Object.keys(first) : [];
137211
138203
  }
137212
138204
  function describeSectionShapes(reportData) {
@@ -137216,7 +138208,7 @@ function describeSectionShapes(reportData) {
137216
138208
  if (Array.isArray(value)) {
137217
138209
  return { section, itemCount: value.length, fields: fieldsOfFirstRow(value), needsNarrative };
137218
138210
  }
137219
- const record2 = asRecord8(value);
138211
+ const record2 = asRecord9(value);
137220
138212
  if (!record2) {
137221
138213
  return { section, itemCount: null, fields: [], needsNarrative };
137222
138214
  }
@@ -137282,21 +138274,21 @@ function buildCollectDigest(reportData, meta) {
137282
138274
  }
137283
138275
 
137284
138276
  // src/commands/google-ads-diagnosis/collect-integrity.ts
137285
- function asRecord9(value) {
138277
+ function asRecord10(value) {
137286
138278
  if (value && typeof value === "object" && !Array.isArray(value)) {
137287
138279
  return value;
137288
138280
  }
137289
138281
  return null;
137290
138282
  }
137291
138283
  function itemCount(block) {
137292
- const items3 = asRecord9(block)?.items;
138284
+ const items3 = asRecord10(block)?.items;
137293
138285
  return Array.isArray(items3) ? items3.length : 0;
137294
138286
  }
137295
138287
  function getCollectIntegrityWarnings(reportData) {
137296
138288
  const warnings = [];
137297
138289
  const kwItems = itemCount(reportData.keywords);
137298
138290
  const fullKwItems = itemCount(reportData.fullKeywords);
137299
- const keywordCount = Number(asRecord9(reportData.structure)?.keywordCount ?? 0);
138291
+ const keywordCount = Number(asRecord10(reportData.structure)?.keywordCount ?? 0);
137300
138292
  if (kwItems === 0 && fullKwItems > 0) {
137301
138293
  warnings.push(
137302
138294
  `keywords.items \u5BF9\u6BD4\u8868\u4E3A\u7A7A\uFF0C\u4F46 fullKeywords.items \u6709 ${fullKwItems} \u884C\uFF1B\u8BF7\u786E\u8BA4 collect \u662F\u5426\u6210\u529F\u62C9\u53D6\u4E0A\u4E00\u5468\u671F keywords \u5FEB\u7167\uFF08\u73AF\u6BD4\u5217\u4F9D\u8D56 prev \u5468\u671F JSON\uFF09\u3002`
@@ -137307,7 +138299,7 @@ function getCollectIntegrityWarnings(reportData) {
137307
138299
  );
137308
138300
  }
137309
138301
  const campaignItems = itemCount(reportData.campaigns);
137310
- const campaignCount = Number(asRecord9(reportData.structure)?.campaignCount ?? 0);
138302
+ const campaignCount = Number(asRecord10(reportData.structure)?.campaignCount ?? 0);
137311
138303
  if (campaignItems === 0 && campaignCount > 0) {
137312
138304
  warnings.push(
137313
138305
  `campaigns.items \u5BF9\u6BD4\u8868\u4E3A\u7A7A\uFF0C\u4F46 structure.campaignCount=${campaignCount}\uFF1B\u8BF7\u786E\u8BA4\u4E0A\u4E00\u5468\u671F campaigns \u5FEB\u7167\u662F\u5426\u62C9\u53D6\u6210\u529F\u3002`
@@ -137365,7 +138357,7 @@ function invokeGoogleAnalysisCli(opts) {
137365
138357
 
137366
138358
  // src/commands/google-ads-diagnosis/write-draft.ts
137367
138359
  import fs21 from "fs/promises";
137368
- function asRecord10(value) {
138360
+ function asRecord11(value) {
137369
138361
  if (value && typeof value === "object" && !Array.isArray(value)) {
137370
138362
  return value;
137371
138363
  }
@@ -137374,7 +138366,7 @@ function asRecord10(value) {
137374
138366
  function valueAtPath(data, keys) {
137375
138367
  let cursor = data;
137376
138368
  for (const key of keys) {
137377
- const record2 = asRecord10(cursor);
138369
+ const record2 = asRecord11(cursor);
137378
138370
  if (!record2) return void 0;
137379
138371
  cursor = record2[key];
137380
138372
  }
@@ -137393,7 +138385,7 @@ function hasAgentNarrative(data) {
137393
138385
  async function writeDiagnosisDraft(opts) {
137394
138386
  try {
137395
138387
  const existing = JSON.parse(await fs21.readFile(opts.draftPath, "utf8"));
137396
- const record2 = asRecord10(existing);
138388
+ const record2 = asRecord11(existing);
137397
138389
  if (record2 && hasAgentNarrative(record2)) return "skipped-existing-narrative";
137398
138390
  } catch {
137399
138391
  }
@@ -137583,7 +138575,7 @@ import fs23 from "fs/promises";
137583
138575
  import path27 from "path";
137584
138576
 
137585
138577
  // src/commands/google-ads-diagnosis/report-content.ts
137586
- function asRecord11(value) {
138578
+ function asRecord12(value) {
137587
138579
  if (value && typeof value === "object" && !Array.isArray(value)) {
137588
138580
  return value;
137589
138581
  }
@@ -137592,7 +138584,7 @@ function asRecord11(value) {
137592
138584
  function getNestedValue(root, path56) {
137593
138585
  let cur = root;
137594
138586
  for (const key of path56) {
137595
- const rec = asRecord11(cur);
138587
+ const rec = asRecord12(cur);
137596
138588
  if (!rec) return void 0;
137597
138589
  cur = rec[key];
137598
138590
  }
@@ -137609,7 +138601,7 @@ function validateBudgetCompetitivenessStrategies(data) {
137609
138601
  }
137610
138602
  const warnings = [];
137611
138603
  for (let i = 0; i < items3.length; i++) {
137612
- const row = asRecord11(items3[i]);
138604
+ const row = asRecord12(items3[i]);
137613
138605
  const name2 = String(row?.name ?? row?.metric ?? i);
137614
138606
  if (!hasNarrativeContent(row?.strategy)) {
137615
138607
  warnings.push(`budgetCompetitiveness[${name2}].strategy \u4E3A\u7A7A\uFF08render \u4F1A\u6309\u672C\u671F\u6570\u503C\u4E0E\u6807\u51C6\u751F\u6210\uFF0C\u4E0D\u5E94\u7531 Agent \u586B\u5199\uFF09`);
@@ -137618,13 +138610,13 @@ function validateBudgetCompetitivenessStrategies(data) {
137618
138610
  return warnings;
137619
138611
  }
137620
138612
  function validateNewFeatureRecommendations(data) {
137621
- const nf = asRecord11(data.newFeatures);
138613
+ const nf = asRecord12(data.newFeatures);
137622
138614
  if (!nf) return [];
137623
138615
  const items3 = nf.items;
137624
138616
  if (!Array.isArray(items3)) return [];
137625
138617
  const warnings = [];
137626
138618
  for (let i = 0; i < items3.length; i++) {
137627
- const row = asRecord11(items3[i]);
138619
+ const row = asRecord12(items3[i]);
137628
138620
  const name2 = String(row?.strategyName ?? row?.feature ?? row?.strategy ?? i);
137629
138621
  if (!hasNarrativeContent(row?.optimizerRecommendation)) {
137630
138622
  warnings.push(`newFeatures.items[${name2}].optimizerRecommendation \u4E3A\u7A7A\uFF08render \u4F1A\u6309\u542F\u7528\u72B6\u6001\u751F\u6210\uFF0C\u4E0D\u5E94\u7531 Agent \u586B\u5199\uFF09`);
@@ -137633,14 +138625,14 @@ function validateNewFeatureRecommendations(data) {
137633
138625
  return warnings;
137634
138626
  }
137635
138627
  function validateDiagnosisOverviewItems(data) {
137636
- const overview = asRecord11(data.diagnosisOverview);
138628
+ const overview = asRecord12(data.diagnosisOverview);
137637
138629
  if (!overview) return [];
137638
138630
  const warnings = [];
137639
138631
  for (const key of ["advantages", "disadvantages"]) {
137640
138632
  const items3 = overview[key];
137641
138633
  if (!Array.isArray(items3)) continue;
137642
138634
  items3.forEach((item, index) => {
137643
- const row = asRecord11(item);
138635
+ const row = asRecord12(item);
137644
138636
  const title = String(row?.title ?? "").trim();
137645
138637
  const description = String(row?.description ?? "").trim();
137646
138638
  if (!title || !description) {
@@ -137653,13 +138645,13 @@ function validateDiagnosisOverviewItems(data) {
137653
138645
  return warnings;
137654
138646
  }
137655
138647
  function validateAdCreativeItemSuggestions(data) {
137656
- const creative = asRecord11(data.adCreativeOptimization);
138648
+ const creative = asRecord12(data.adCreativeOptimization);
137657
138649
  if (!creative) return [];
137658
138650
  const items3 = creative.items;
137659
138651
  if (!Array.isArray(items3) || items3.length === 0) return [];
137660
138652
  const warnings = [];
137661
138653
  for (let i = 0; i < items3.length; i++) {
137662
- const row = asRecord11(items3[i]);
138654
+ const row = asRecord12(items3[i]);
137663
138655
  const title = String(row?.adTitle ?? i);
137664
138656
  if (!hasNarrativeContent(row?.suggestion ?? row?.suggestions)) {
137665
138657
  warnings.push(`adCreativeOptimization.items[${title}].suggestion \u4E3A\u7A7A\uFF08render \u4F1A\u6309\u6807\u9898/\u63CF\u8FF0\u6761\u6570\u751F\u6210\uFF0C\u4E0D\u5E94\u7531 Agent \u586B\u5199\uFF09`);
@@ -137670,7 +138662,7 @@ function validateAdCreativeItemSuggestions(data) {
137670
138662
  function validateGoogleAdsDiagnosisContent(data) {
137671
138663
  const missingKeys = GOOGLE_ADS_DIAGNOSIS_TOP_LEVEL_KEYS.filter((key) => data[key] === void 0);
137672
138664
  const warnings = [];
137673
- const accountInfo = asRecord11(data.accountInfo);
138665
+ const accountInfo = asRecord12(data.accountInfo);
137674
138666
  if (accountInfo && !accountInfo.companyName && !accountInfo.period) {
137675
138667
  warnings.push("accountInfo \u7F3A\u5C11 companyName \u4E0E period\uFF0C\u9875\u7709\u53EF\u80FD\u4E3A\u7A7A");
137676
138668
  }
@@ -137719,7 +138711,7 @@ var GOOGLE_ADS_DIAGNOSIS_RESTORE_ITEM_MODULES = [
137719
138711
  GOOGLE_ADS_DIAGNOSIS_BIDDING_STRATEGY_MODULE,
137720
138712
  GOOGLE_ADS_DIAGNOSIS_NEW_FEATURES_MODULE
137721
138713
  ];
137722
- function asRecord12(value) {
138714
+ function asRecord13(value) {
137723
138715
  if (value && typeof value === "object" && !Array.isArray(value)) {
137724
138716
  return value;
137725
138717
  }
@@ -137730,7 +138722,7 @@ function isValidRateChange(value) {
137730
138722
  return typeof value === "number" && Number.isFinite(value);
137731
138723
  }
137732
138724
  function isComparisonTableRowValid(row) {
137733
- const rec = asRecord12(row);
138725
+ const rec = asRecord13(row);
137734
138726
  if (!rec) return false;
137735
138727
  if (!String(rec.title ?? "").trim()) return false;
137736
138728
  if (!Number.isFinite(Number(rec.currentCost))) return false;
@@ -137742,12 +138734,12 @@ function isComparisonTableRowValid(row) {
137742
138734
  return true;
137743
138735
  }
137744
138736
  function isNewFeatureRowValid(row) {
137745
- const rec = asRecord12(row);
138737
+ const rec = asRecord13(row);
137746
138738
  if (!rec) return false;
137747
138739
  return Boolean(String(rec.strategyName ?? rec.feature ?? rec.strategy ?? "").trim());
137748
138740
  }
137749
138741
  function isBiddingStrategyRowValid(row) {
137750
- const rec = asRecord12(row);
138742
+ const rec = asRecord13(row);
137751
138743
  if (!rec) return false;
137752
138744
  if (!String(rec.campaignName ?? "").trim()) return false;
137753
138745
  if (!Number.isFinite(Number(rec.duration)) || Number(rec.duration) <= 0) return false;
@@ -137785,11 +138777,11 @@ function getFactItemsErrors(data) {
137785
138777
  for (const mod of GOOGLE_ADS_DIAGNOSIS_RESTORE_ITEM_MODULES) {
137786
138778
  const validator = MODULE_ITEM_VALIDATORS[mod];
137787
138779
  const hint = MODULE_ITEM_ERROR_HINT[mod];
137788
- const block = asRecord12(data[mod]);
138780
+ const block = asRecord13(data[mod]);
137789
138781
  const items3 = block?.items;
137790
138782
  if (!Array.isArray(items3) || items3.length === 0) {
137791
138783
  if (mod === "keywords") {
137792
- const fullKw = asRecord12(data.fullKeywords)?.items;
138784
+ const fullKw = asRecord13(data.fullKeywords)?.items;
137793
138785
  if (Array.isArray(fullKw) && fullKw.length > 0) {
137794
138786
  errors.push(
137795
138787
  "keywords.items \u4E3A\u7A7A\u4F46 fullKeywords.items \u6709\u6570\u636E\uFF1B\u8BF7\u4FDD\u7559\u540C\u76EE\u5F55 google-ads-diagnosis-collect.json \u540E\u91CD\u65B0 render\uFF08\u4F1A\u81EA\u52A8\u6062\u590D\u5BF9\u6BD4\u8868\uFF09"
@@ -137814,15 +138806,15 @@ var LANDING_PAGE_SPEED_KEYS = [
137814
138806
  "speedIndex"
137815
138807
  ];
137816
138808
  function isLandingPageSpeedValid(value) {
137817
- const rec = asRecord12(value);
138809
+ const rec = asRecord13(value);
137818
138810
  if (!rec) return false;
137819
138811
  return LANDING_PAGE_SPEED_KEYS.every(
137820
138812
  (key) => typeof rec[key] === "number" && Number.isFinite(rec[key])
137821
138813
  );
137822
138814
  }
137823
138815
  function restoreLandingPageSpeedFromCollect(finalData, collectReportData) {
137824
- const finalBlock = asRecord12(finalData[GOOGLE_ADS_DIAGNOSIS_LANDING_PAGE_MODULE]);
137825
- const collectBlock = asRecord12(collectReportData[GOOGLE_ADS_DIAGNOSIS_LANDING_PAGE_MODULE]);
138816
+ const finalBlock = asRecord13(finalData[GOOGLE_ADS_DIAGNOSIS_LANDING_PAGE_MODULE]);
138817
+ const collectBlock = asRecord13(collectReportData[GOOGLE_ADS_DIAGNOSIS_LANDING_PAGE_MODULE]);
137826
138818
  if (!collectBlock) return { data: finalData, restored: false };
137827
138819
  const needsDesktop = !isLandingPageSpeedValid(finalBlock?.desktop) && isLandingPageSpeedValid(collectBlock.desktop);
137828
138820
  const needsMobile = !isLandingPageSpeedValid(finalBlock?.mobile) && isLandingPageSpeedValid(collectBlock.mobile);
@@ -137845,8 +138837,8 @@ function mergeComparisonItemsFromCollect(finalData, collectReportData) {
137845
138837
  const restoredModules = [];
137846
138838
  for (const mod of GOOGLE_ADS_DIAGNOSIS_RESTORE_ITEM_MODULES) {
137847
138839
  const validator = MODULE_ITEM_VALIDATORS[mod];
137848
- const finalBlock = asRecord12(data[mod]);
137849
- const collectBlock = asRecord12(collectReportData[mod]);
138840
+ const finalBlock = asRecord13(data[mod]);
138841
+ const collectBlock = asRecord13(collectReportData[mod]);
137850
138842
  const finalItems = finalBlock?.items;
137851
138843
  const collectItems = collectBlock?.items;
137852
138844
  if (!Array.isArray(collectItems) || collectItems.length === 0) continue;
@@ -137862,7 +138854,7 @@ function mergeComparisonItemsFromCollect(finalData, collectReportData) {
137862
138854
  }
137863
138855
 
137864
138856
  // src/commands/google-ads-diagnosis/narrative-consistency-check.ts
137865
- function asRecord13(value) {
138857
+ function asRecord14(value) {
137866
138858
  if (value && typeof value === "object" && !Array.isArray(value)) {
137867
138859
  return value;
137868
138860
  }
@@ -137873,14 +138865,14 @@ function normalizeSuggestionText(value) {
137873
138865
  }
137874
138866
  function collectNarrativeTexts(data) {
137875
138867
  const texts = [];
137876
- const summary = asRecord13(data.summary);
138868
+ const summary = asRecord14(data.summary);
137877
138869
  if (Array.isArray(summary?.keyIssues)) {
137878
138870
  for (const item of summary.keyIssues) texts.push(String(item ?? ""));
137879
138871
  }
137880
- const overview = asRecord13(data.diagnosisOverview);
138872
+ const overview = asRecord14(data.diagnosisOverview);
137881
138873
  if (Array.isArray(overview?.disadvantages)) {
137882
138874
  for (const item of overview.disadvantages) {
137883
- const rec = asRecord13(item);
138875
+ const rec = asRecord14(item);
137884
138876
  if (rec) {
137885
138877
  texts.push(String(rec.title ?? ""), String(rec.description ?? ""));
137886
138878
  } else {
@@ -137891,16 +138883,16 @@ function collectNarrativeTexts(data) {
137891
138883
  return texts.filter((t) => t.trim().length > 0);
137892
138884
  }
137893
138885
  function newFeatureAccountStatus(data, strategy) {
137894
- const nf = asRecord13(data.newFeatures);
138886
+ const nf = asRecord14(data.newFeatures);
137895
138887
  const items3 = nf?.items;
137896
138888
  if (!Array.isArray(items3)) return null;
137897
- const row = items3.find((it) => asRecord13(it)?.strategy === strategy);
137898
- const rec = asRecord13(row);
138889
+ const row = items3.find((it) => asRecord14(it)?.strategy === strategy);
138890
+ const rec = asRecord14(row);
137899
138891
  if (!rec || typeof rec.accountStatus !== "boolean") return null;
137900
138892
  return rec.accountStatus;
137901
138893
  }
137902
138894
  function goldAccountFlag(data, key) {
137903
- const gold = asRecord13(data.goldAccount);
138895
+ const gold = asRecord14(data.goldAccount);
137904
138896
  const value = gold?.[key];
137905
138897
  return typeof value === "boolean" ? value : null;
137906
138898
  }
@@ -137931,7 +138923,7 @@ var NARRATIVE_CONSISTENCY_RULES = [
137931
138923
  }
137932
138924
  ];
137933
138925
  function goldAssetNoted(data, key) {
137934
- const notes = asRecord13(asRecord13(data.goldAccount)?.goldAssetNotes);
138926
+ const notes = asRecord14(asRecord14(data.goldAccount)?.goldAssetNotes);
137935
138927
  return notes?.[key] === true;
137936
138928
  }
137937
138929
  var GOLD_CLAIM_RULES = [
@@ -137974,12 +138966,12 @@ var GOLD_CLAIM_RULES = [
137974
138966
  ];
137975
138967
  function collectGoldClaimTexts(data) {
137976
138968
  const texts = collectNarrativeTexts(data);
137977
- const overview = asRecord13(data.diagnosisOverview);
138969
+ const overview = asRecord14(data.diagnosisOverview);
137978
138970
  for (const key of ["advantages", "disadvantages"]) {
137979
138971
  const items3 = overview?.[key];
137980
138972
  if (!Array.isArray(items3)) continue;
137981
138973
  for (const item of items3) {
137982
- const rec = asRecord13(item);
138974
+ const rec = asRecord14(item);
137983
138975
  if (rec) texts.push(String(rec.title ?? ""), String(rec.description ?? ""));
137984
138976
  }
137985
138977
  }
@@ -138000,7 +138992,7 @@ function getRepetitiveNarrativeErrors(data) {
138000
138992
  const errors = [];
138001
138993
  const budget = data.budgetCompetitiveness;
138002
138994
  if (Array.isArray(budget) && budget.length >= 3) {
138003
- const strategies = budget.map((row) => normalizeSuggestionText(asRecord13(row)?.strategy)).filter((s) => s.length > 0);
138995
+ const strategies = budget.map((row) => normalizeSuggestionText(asRecord14(row)?.strategy)).filter((s) => s.length > 0);
138004
138996
  const dup = findIdenticalTexts(strategies, 3);
138005
138997
  if (dup) {
138006
138998
  errors.push(
@@ -138008,10 +139000,10 @@ function getRepetitiveNarrativeErrors(data) {
138008
139000
  );
138009
139001
  }
138010
139002
  }
138011
- const creative = asRecord13(data.adCreativeOptimization);
139003
+ const creative = asRecord14(data.adCreativeOptimization);
138012
139004
  const creativeItems = creative?.items;
138013
139005
  if (Array.isArray(creativeItems) && creativeItems.length >= 3) {
138014
- const suggestions = creativeItems.map((row) => normalizeSuggestionText(asRecord13(row)?.suggestion)).filter((s) => s.length > 0);
139006
+ const suggestions = creativeItems.map((row) => normalizeSuggestionText(asRecord14(row)?.suggestion)).filter((s) => s.length > 0);
138015
139007
  const dup = findIdenticalTexts(suggestions, 3);
138016
139008
  if (dup) {
138017
139009
  errors.push(
@@ -138022,7 +139014,7 @@ function getRepetitiveNarrativeErrors(data) {
138022
139014
  return errors;
138023
139015
  }
138024
139016
  function getLandingPageTopicErrors(data) {
138025
- const lp = asRecord13(data.landingPageAnalysis);
139017
+ const lp = asRecord14(data.landingPageAnalysis);
138026
139018
  if (!lp) return [];
138027
139019
  const analysis = String(lp.analysis ?? "");
138028
139020
  if (!analysis.trim()) return [];
@@ -138059,7 +139051,7 @@ function getNarrativeConsistencyErrors(data) {
138059
139051
  }
138060
139052
 
138061
139053
  // src/commands/google-ads-diagnosis/overview-items.ts
138062
- function asRecord14(value) {
139054
+ function asRecord15(value) {
138063
139055
  if (value && typeof value === "object" && !Array.isArray(value)) {
138064
139056
  return value;
138065
139057
  }
@@ -138093,7 +139085,7 @@ function normalizeOverviewItem(item) {
138093
139085
  if (!text3) return null;
138094
139086
  return splitOverviewProse(text3);
138095
139087
  }
138096
- const rec = asRecord14(item);
139088
+ const rec = asRecord15(item);
138097
139089
  if (!rec) return null;
138098
139090
  const title = String(rec.title ?? "").trim();
138099
139091
  const description = String(rec.description ?? "").trim();
@@ -138107,7 +139099,7 @@ function normalizeOverviewItem(item) {
138107
139099
  };
138108
139100
  }
138109
139101
  function normalizeDiagnosisOverview(data) {
138110
- const overview = asRecord14(data.diagnosisOverview);
139102
+ const overview = asRecord15(data.diagnosisOverview);
138111
139103
  if (!overview) return { data, coerced: [] };
138112
139104
  const coerced = [];
138113
139105
  const nextOverview = { ...overview };
@@ -138126,7 +139118,7 @@ function normalizeDiagnosisOverview(data) {
138126
139118
  }
138127
139119
 
138128
139120
  // src/commands/google-ads-diagnosis/data-rendered-copy.ts
138129
- function asRecord15(value) {
139121
+ function asRecord16(value) {
138130
139122
  if (value && typeof value === "object" && !Array.isArray(value)) {
138131
139123
  return value;
138132
139124
  }
@@ -138187,7 +139179,7 @@ function distinctCopies(rows, key) {
138187
139179
  function mapRows(rows, write) {
138188
139180
  if (!Array.isArray(rows)) return rows;
138189
139181
  const written = rows.map((item) => {
138190
- const row = asRecord15(item);
139182
+ const row = asRecord16(item);
138191
139183
  return row ? write(row) : item;
138192
139184
  });
138193
139185
  return written;
@@ -138201,7 +139193,7 @@ function applyDataRenderedCopy(data) {
138201
139193
  if (Array.isArray(budgetRows)) {
138202
139194
  next.budgetCompetitiveness = distinctCopies(budgetRows, "strategy");
138203
139195
  }
138204
- const bidding = asRecord15(data.biddingStrategy);
139196
+ const bidding = asRecord16(data.biddingStrategy);
138205
139197
  if (bidding) {
138206
139198
  next.biddingStrategy = {
138207
139199
  ...bidding,
@@ -138211,7 +139203,7 @@ function applyDataRenderedCopy(data) {
138211
139203
  }))
138212
139204
  };
138213
139205
  }
138214
- const features = asRecord15(data.newFeatures);
139206
+ const features = asRecord16(data.newFeatures);
138215
139207
  if (features) {
138216
139208
  next.newFeatures = {
138217
139209
  ...features,
@@ -138221,7 +139213,7 @@ function applyDataRenderedCopy(data) {
138221
139213
  }))
138222
139214
  };
138223
139215
  }
138224
- const creative = asRecord15(data.adCreativeOptimization);
139216
+ const creative = asRecord16(data.adCreativeOptimization);
138225
139217
  if (creative) {
138226
139218
  const creativeRows = mapRows(creative.items, (row) => ({
138227
139219
  ...row,
@@ -138238,7 +139230,7 @@ function applyDataRenderedCopy(data) {
138238
139230
  // src/commands/google-ads-diagnosis/render-report.ts
138239
139231
  init_lang();
138240
139232
  init_html();
138241
- function asRecord16(value) {
139233
+ function asRecord17(value) {
138242
139234
  if (value && typeof value === "object" && !Array.isArray(value)) {
138243
139235
  return value;
138244
139236
  }
@@ -138247,8 +139239,8 @@ function asRecord16(value) {
138247
139239
  async function tryLoadCollectReportData(collectPath) {
138248
139240
  try {
138249
139241
  const raw = JSON.parse(await fs23.readFile(collectPath, "utf8"));
138250
- const root = asRecord16(raw);
138251
- const reportData = asRecord16(root?.reportData);
139242
+ const root = asRecord17(raw);
139243
+ const reportData = asRecord17(root?.reportData);
138252
139244
  return reportData ?? root;
138253
139245
  } catch {
138254
139246
  return null;
@@ -138265,7 +139257,7 @@ async function runGoogleAdsDiagnosisRender(opts) {
138265
139257
  `);
138266
139258
  process.exit(1);
138267
139259
  }
138268
- let data = asRecord16(dataRaw);
139260
+ let data = asRecord17(dataRaw);
138269
139261
  if (!opts.noMergeCollect) {
138270
139262
  const collectPath = path27.resolve(
138271
139263
  opts.collectFile ?? path27.join(path27.dirname(dataPath), GOOGLE_ADS_DIAGNOSIS_COLLECT_BASENAME)
@@ -138471,13 +139463,13 @@ function sumCampaigns(rows) {
138471
139463
  }
138472
139464
  return withRates({ spend, impressions, clicks, conversions });
138473
139465
  }
138474
- function withRates(base) {
139466
+ function withRates(base2) {
138475
139467
  return {
138476
- ...base,
138477
- ctr: base.impressions > 0 ? base.clicks / base.impressions : 0,
138478
- cpc: base.clicks > 0 ? base.spend / base.clicks : 0,
138479
- cpa: base.conversions > 0 ? base.spend / base.conversions : 0,
138480
- cvr: base.clicks > 0 ? base.conversions / base.clicks : 0
139468
+ ...base2,
139469
+ ctr: base2.impressions > 0 ? base2.clicks / base2.impressions : 0,
139470
+ cpc: base2.clicks > 0 ? base2.spend / base2.clicks : 0,
139471
+ cpa: base2.conversions > 0 ? base2.spend / base2.conversions : 0,
139472
+ cvr: base2.clicks > 0 ? base2.conversions / base2.clicks : 0
138481
139473
  };
138482
139474
  }
138483
139475
  function pctChange(current, baseline) {
@@ -138638,8 +139630,8 @@ function parseKeywordSeedsFlag(raw) {
138638
139630
  // src/commands/google-quarterly/fetch-subdivisions.ts
138639
139631
  init_auth();
138640
139632
  async function fetchSubdivisions(opts) {
138641
- const base = opts.config.googleApiUrl?.replace(/\/$/, "");
138642
- if (!base) return null;
139633
+ const base2 = opts.config.googleApiUrl?.replace(/\/$/, "");
139634
+ if (!base2) return null;
138643
139635
  const qs = new URLSearchParams({
138644
139636
  startDate: opts.start,
138645
139637
  endDate: opts.end,
@@ -138648,7 +139640,7 @@ async function fetchSubdivisions(opts) {
138648
139640
  if (opts.countryCriterionId && opts.countryCriterionId > 0) {
138649
139641
  qs.set("countryCriterionId", String(opts.countryCriterionId));
138650
139642
  }
138651
- const url = `${base}/reporting/media-account/${opts.accountId}/reports/geo/subdivisions?${qs}`;
139643
+ const url = `${base2}/reporting/media-account/${opts.accountId}/reports/geo/subdivisions?${qs}`;
138652
139644
  try {
138653
139645
  const payload = await apiFetch2(url, opts.config, { verbose: opts.verbose });
138654
139646
  const rows = Array.isArray(payload) ? payload : payload && typeof payload === "object" && Array.isArray(payload.countries) ? payload.countries : payload && typeof payload === "object" && Array.isArray(payload.items) ? payload.items : [];
@@ -138687,8 +139679,8 @@ function pickMetric(headers, row, name2) {
138687
139679
  return Number.isFinite(n) ? n : null;
138688
139680
  }
138689
139681
  async function fetchYoutubeChannel(opts) {
138690
- const base = opts.config.youtubeApiUrl?.replace(/\/$/, "");
138691
- if (!base || !opts.externalTokenId.trim()) {
139682
+ const base2 = opts.config.youtubeApiUrl?.replace(/\/$/, "");
139683
+ if (!base2 || !opts.externalTokenId.trim()) {
138692
139684
  return {
138693
139685
  source: "unbound",
138694
139686
  subscribersGained: null,
@@ -138703,7 +139695,7 @@ async function fetchYoutubeChannel(opts) {
138703
139695
  endDate: opts.end
138704
139696
  });
138705
139697
  if (opts.channelId?.trim()) qs.set("ids", `channel==${opts.channelId.trim()}`);
138706
- const url = `${base}/query/report/YouTube/channel-kpi?${qs}`;
139698
+ const url = `${base2}/query/report/YouTube/channel-kpi?${qs}`;
138707
139699
  try {
138708
139700
  const payload = await apiFetch2(url, opts.config, { verbose: opts.verbose });
138709
139701
  const headers = Array.isArray(payload.columnHeaders) ? payload.columnHeaders : [];
@@ -139171,15 +140163,15 @@ function pickSpecialAds(videos, campaigns) {
139171
140163
  function countryName(row) {
139172
140164
  return String(row.countryNameZh ?? row.countryOrRegionZh ?? row.countryOrRegion ?? "").trim();
139173
140165
  }
139174
- function kpiDelta(cur, base) {
140166
+ function kpiDelta(cur, base2) {
139175
140167
  return {
139176
- spend: pctChange(cur.spend, base.spend),
139177
- impressions: pctChange(cur.impressions, base.impressions),
139178
- clicks: pctChange(cur.clicks, base.clicks),
139179
- conversions: pctChange(cur.conversions, base.conversions),
139180
- ctr: pctChange(cur.ctr, base.ctr),
139181
- cpc: pctChange(cur.cpc, base.cpc),
139182
- cpa: pctChange(cur.cpa, base.cpa)
140168
+ spend: pctChange(cur.spend, base2.spend),
140169
+ impressions: pctChange(cur.impressions, base2.impressions),
140170
+ clicks: pctChange(cur.clicks, base2.clicks),
140171
+ conversions: pctChange(cur.conversions, base2.conversions),
140172
+ ctr: pctChange(cur.ctr, base2.ctr),
140173
+ cpc: pctChange(cur.cpc, base2.cpc),
140174
+ cpa: pctChange(cur.cpa, base2.cpa)
139183
140175
  };
139184
140176
  }
139185
140177
  function matchConversionAction(actions, name2) {
@@ -139632,26 +140624,26 @@ import fs27 from "fs/promises";
139632
140624
  import path32 from "path";
139633
140625
 
139634
140626
  // src/commands/google-quarterly/report-content.ts
139635
- function asRecord17(value) {
140627
+ function asRecord18(value) {
139636
140628
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
139637
140629
  }
139638
140630
  function asStringArray(value) {
139639
140631
  return Array.isArray(value) ? value.map((x) => String(x).trim()).filter(Boolean) : [];
139640
140632
  }
139641
140633
  function validateQuarterlyNarrative(data) {
139642
- const root = asRecord17(data);
139643
- const narrative = asRecord17(root?.narrative);
140634
+ const root = asRecord18(data);
140635
+ const narrative = asRecord18(root?.narrative);
139644
140636
  const missing = [];
139645
140637
  if (!narrative) {
139646
140638
  return { ok: false, missing: ["narrative"] };
139647
140639
  }
139648
140640
  if (asStringArray(narrative.executiveSummary).length < 1) missing.push("narrative.executiveSummary");
139649
- const sections = asRecord17(narrative.sections);
140641
+ const sections = asRecord18(narrative.sections);
139650
140642
  for (const key of ["efficiency", "adType", "region", "summary"]) {
139651
- const block = asRecord17(sections?.[key]);
140643
+ const block = asRecord18(sections?.[key]);
139652
140644
  if (asStringArray(block?.analysis).length < 1) missing.push(`narrative.sections.${key}.analysis`);
139653
140645
  }
139654
- const plan = asRecord17(narrative.plan);
140646
+ const plan = asRecord18(narrative.plan);
139655
140647
  if (asStringArray(plan?.analysis ?? plan?.goals).length < 1 && !String(plan?.text ?? "").trim()) {
139656
140648
  missing.push("narrative.plan");
139657
140649
  }
@@ -139664,8 +140656,8 @@ function mergeCollectFacts(agentData, collect) {
139664
140656
  ...facts,
139665
140657
  narrative: agentData.narrative ?? collect.narrative,
139666
140658
  meta: {
139667
- ...asRecord17(collect.meta) ?? {},
139668
- ...asRecord17(agentData.meta) ?? {}
140659
+ ...asRecord18(collect.meta) ?? {},
140660
+ ...asRecord18(agentData.meta) ?? {}
139669
140661
  }
139670
140662
  };
139671
140663
  }
@@ -139679,7 +140671,7 @@ var TSO_CLI_ROOT = path31.join(path31.dirname(fileURLToPath8(import.meta.url)),
139679
140671
  // src/commands/google-quarterly/render-report.ts
139680
140672
  init_lang();
139681
140673
  init_html();
139682
- function asRecord18(value) {
140674
+ function asRecord19(value) {
139683
140675
  if (value && typeof value === "object" && !Array.isArray(value)) {
139684
140676
  return value;
139685
140677
  }
@@ -139708,7 +140700,7 @@ async function runGoogleQuarterlyRender(opts) {
139708
140700
  `);
139709
140701
  process.exit(1);
139710
140702
  }
139711
- const merged = mergeCollectFacts(asRecord18(agentRaw), asRecord18(collectRaw));
140703
+ const merged = mergeCollectFacts(asRecord19(agentRaw), asRecord19(collectRaw));
139712
140704
  const check = validateQuarterlyNarrative(merged);
139713
140705
  if (!check.ok && !opts.lenient) {
139714
140706
  console.error("\n\u274C narrative \u4E0D\u5B8C\u6574\uFF0C\u62D2\u7EDD\u51FA HTML\uFF1A\n");
@@ -139892,7 +140884,7 @@ import * as fs34 from "fs/promises";
139892
140884
  import * as path41 from "path";
139893
140885
 
139894
140886
  // src/commands/facebook-analysis/report-metrics.ts
139895
- function asRecord24(value) {
140887
+ function asRecord25(value) {
139896
140888
  if (value && typeof value === "object" && !Array.isArray(value)) {
139897
140889
  return value;
139898
140890
  }
@@ -140029,7 +141021,7 @@ function localizeFacebookReportLabels(payload) {
140029
141021
  for (const rows of Object.values(tables)) {
140030
141022
  if (!Array.isArray(rows)) continue;
140031
141023
  for (const row of rows) {
140032
- localizeMetricLabels(asRecord24(row));
141024
+ localizeMetricLabels(asRecord25(row));
140033
141025
  }
140034
141026
  }
140035
141027
  return payload;
@@ -140062,7 +141054,7 @@ async function readManifest3(snapshotDir) {
140062
141054
  async function loadSectionFile3(snapshotDir, file) {
140063
141055
  try {
140064
141056
  const raw = await fs34.readFile(path41.join(snapshotDir, file), "utf8");
140065
- return asRecord24(JSON.parse(raw));
141057
+ return asRecord25(JSON.parse(raw));
140066
141058
  } catch {
140067
141059
  return null;
140068
141060
  }
@@ -140118,7 +141110,7 @@ async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
140118
141110
  if (data) sectionMap.set(art.section, data);
140119
141111
  }
140120
141112
  const overview = sectionMap.get("overview");
140121
- const current = asRecord24(overview?.currentPeriod);
141113
+ const current = asRecord25(overview?.currentPeriod);
140122
141114
  const accountName = typeof overview?.accountName === "string" ? overview.accountName : void 0;
140123
141115
  const accountId = manifest.accountId ?? (typeof overview?.accountId === "string" ? overview.accountId : void 0);
140124
141116
  const kpis = { ...payload.kpis ?? {} };
@@ -140258,7 +141250,7 @@ function writeSimpleXlsx(filePath, sheets, opts = {}) {
140258
141250
  }
140259
141251
 
140260
141252
  // src/commands/facebook-analysis/render-excel.ts
140261
- function asRecord25(value) {
141253
+ function asRecord26(value) {
140262
141254
  if (value && typeof value === "object" && !Array.isArray(value)) {
140263
141255
  return value;
140264
141256
  }
@@ -140306,8 +141298,8 @@ function bullets(value) {
140306
141298
  return asArray3(value).map((item) => typeof item === "string" ? item.trim() : "").filter(Boolean);
140307
141299
  }
140308
141300
  function insightLines(section) {
140309
- const rec = asRecord25(section);
140310
- const insight = asRecord25(rec?.insight) ?? rec;
141301
+ const rec = asRecord26(section);
141302
+ const insight = asRecord26(rec?.insight) ?? rec;
140311
141303
  return [...bullets(insight?.analysis), ...bullets(insight?.advice)];
140312
141304
  }
140313
141305
  function numberedSection(index, title, lines) {
@@ -140316,15 +141308,15 @@ function numberedSection(index, title, lines) {
140316
141308
  ${body}`;
140317
141309
  }
140318
141310
  function buildSummaryNarrative(data) {
140319
- const kpis = asRecord25(data.kpis) ?? {};
140320
- const meta = asRecord25(data.meta) ?? {};
140321
- const sections = asRecord25(data.sections) ?? {};
141311
+ const kpis = asRecord26(data.kpis) ?? {};
141312
+ const meta = asRecord26(data.meta) ?? {};
141313
+ const sections = asRecord26(data.sections) ?? {};
140322
141314
  const period = str2(meta.periodLabel) || `${str2(meta.startDate)} ~ ${str2(meta.endDate)}`.trim();
140323
141315
  const account = str2(meta.accountName) || "Facebook \u5E7F\u544A\u8D26\u6237";
140324
141316
  const campaign = str2(meta.campaignName);
140325
141317
  const resultLabel = displayResultType(kpis.resultType ?? meta.resultType) || "\u6210\u6548";
140326
141318
  const resultNoun = /潜在客户|lead/i.test(resultLabel) ? "\u4E2A\u6F5C\u5728\u5BA2\u6237\u8868\u5355" : `\u4E2A${resultLabel}`;
140327
- const firstQuestion = asRecord25(asArray3(data.fourQuestions)[0]);
141319
+ const firstQuestion = asRecord26(asArray3(data.fourQuestions)[0]);
140328
141320
  const extra = str2(firstQuestion?.verdict);
140329
141321
  const spendLine = [
140330
141322
  campaign ? `\uFF08\u5E7F\u544A\u7CFB\u5217\uFF1A${campaign}\uFF09` : "",
@@ -140344,7 +141336,7 @@ function buildSummaryNarrative(data) {
140344
141336
  numberedSection(3, "\u5E7F\u544A\u9891\u6B21\u4E0E\u65E5\u8D8B\u52BF", insightLines(sections.daily))
140345
141337
  ].join("\n");
140346
141338
  const recBlocks = asArray3(data.recommendations).map((raw, i) => {
140347
- const rec = asRecord25(raw);
141339
+ const rec = asRecord26(raw);
140348
141340
  if (!rec) return "";
140349
141341
  const title = [str2(rec.title), str2(rec.tag)].filter(Boolean).join(" \xB7 ");
140350
141342
  return numberedSection(i + 1, title || "\u4F18\u5316\u5EFA\u8BAE", bullets(rec.items));
@@ -140355,9 +141347,9 @@ function buildSummaryNarrative(data) {
140355
141347
  return [partOne, partTwo, partThree];
140356
141348
  }
140357
141349
  function buildMetaPeriodExcelSheets(data) {
140358
- const meta = asRecord25(data.meta) ?? {};
140359
- const kpis = asRecord25(data.kpis) ?? {};
140360
- const tables = asRecord25(data.tables) ?? {};
141350
+ const meta = asRecord26(data.meta) ?? {};
141351
+ const kpis = asRecord26(data.kpis) ?? {};
141352
+ const tables = asRecord26(data.tables) ?? {};
140361
141353
  const currency = str2(meta.currency) || "USD";
140362
141354
  const resultType = displayResultType(kpis.resultType ?? meta.resultType);
140363
141355
  const attribution = displayAttribution(kpis.attributionSetting ?? meta.attributionSetting);
@@ -140376,19 +141368,19 @@ function buildMetaPeriodExcelSheets(data) {
140376
141368
  ];
140377
141369
  const dailyRows = [metricHeaders(currency, "\u5355\u65E5")];
140378
141370
  for (const raw of asArray3(tables.daily)) {
140379
- const row = asRecord25(raw);
141371
+ const row = asRecord26(raw);
140380
141372
  if (!row) continue;
140381
141373
  dailyRows.push([normalizeInsightDate(row.date), ...metricCells(row)]);
140382
141374
  }
140383
141375
  const countryRows = [metricHeaders(currency, "\u56FD\u5BB6/\u5730\u533A")];
140384
141376
  for (const raw of asArray3(tables.countries)) {
140385
- const row = asRecord25(raw);
141377
+ const row = asRecord26(raw);
140386
141378
  if (!row) continue;
140387
141379
  countryRows.push([str2(row.countryOrRegion), ...metricCells(row)]);
140388
141380
  }
140389
141381
  const campaignRows3 = [metricHeaders(currency, "\u5E7F\u544A\u7CFB\u5217\u540D\u79F0")];
140390
141382
  for (const raw of asArray3(tables.campaigns)) {
140391
- const row = asRecord25(raw);
141383
+ const row = asRecord26(raw);
140392
141384
  if (!row) continue;
140393
141385
  campaignRows3.push([str2(row.campaignName), ...metricCells(row)]);
140394
141386
  }
@@ -140407,7 +141399,7 @@ function buildMetaPeriodExcelSheets(data) {
140407
141399
  ]
140408
141400
  ];
140409
141401
  for (const raw of asArray3(tables.audiences)) {
140410
- const row = asRecord25(raw);
141402
+ const row = asRecord26(raw);
140411
141403
  if (!row) continue;
140412
141404
  audienceRows.push([str2(row.age), str2(row.gender), ...metricCells(row)]);
140413
141405
  }
@@ -140449,7 +141441,7 @@ function isFiniteNumber(value) {
140449
141441
  function asArray4(value) {
140450
141442
  return Array.isArray(value) ? value : [];
140451
141443
  }
140452
- function asRecord26(value) {
141444
+ function asRecord27(value) {
140453
141445
  if (value && typeof value === "object" && !Array.isArray(value)) {
140454
141446
  return value;
140455
141447
  }
@@ -140462,8 +141454,8 @@ function stringList3(value) {
140462
141454
  return asArray4(value).map((item) => typeof item === "string" ? item.trim() : "").filter(Boolean);
140463
141455
  }
140464
141456
  function insightLists(section) {
140465
- const rec = asRecord26(section);
140466
- const insight = asRecord26(rec?.insight) ?? rec;
141457
+ const rec = asRecord27(section);
141458
+ const insight = asRecord27(rec?.insight) ?? rec;
140467
141459
  return {
140468
141460
  analysis: stringList3(insight?.analysis),
140469
141461
  advice: stringList3(insight?.advice)
@@ -140493,11 +141485,11 @@ function requireInsight(missing, key, chapter, section, required) {
140493
141485
  }
140494
141486
  function validateMetaPeriodReportContent(data) {
140495
141487
  const missing = [];
140496
- const meta = asRecord26(data.meta) ?? {};
140497
- const kpis = asRecord26(data.kpis) ?? {};
140498
- const tables = asRecord26(data.tables) ?? {};
140499
- const charts = asRecord26(data.charts) ?? {};
140500
- const sections = asRecord26(data.sections) ?? {};
141488
+ const meta = asRecord27(data.meta) ?? {};
141489
+ const kpis = asRecord27(data.kpis) ?? {};
141490
+ const tables = asRecord27(data.tables) ?? {};
141491
+ const charts = asRecord27(data.charts) ?? {};
141492
+ const sections = asRecord27(data.sections) ?? {};
140501
141493
  const fourQuestions = asArray4(data.fourQuestions);
140502
141494
  const recommendations = asArray4(data.recommendations);
140503
141495
  if (!textLen3(meta.accountName) && !textLen3(meta.accountId)) {
@@ -140576,7 +141568,7 @@ function validateMetaPeriodReportContent(data) {
140576
141568
  "\u987B\u6709 tables.audiences \u6570\u7EC4\uFF1B\u62C9\u6570\u52A0 --sections audience\uFF0Crender \u65F6\u4F20 --snapshot-dir\u3002\u672C\u671F\u65E0\u6D88\u8017\u53EF\u4E3A []"
140577
141569
  );
140578
141570
  }
140579
- const dailyChart = asRecord26(charts.daily);
141571
+ const dailyChart = asRecord27(charts.daily);
140580
141572
  if (!Array.isArray(dailyChart?.labels)) {
140581
141573
  pushMissing3(
140582
141574
  missing,
@@ -140586,7 +141578,7 @@ function validateMetaPeriodReportContent(data) {
140586
141578
  "\u987B\u6709 charts.daily.labels \u6570\u7EC4\uFF1B\u53EF\u7531 --snapshot-dir \u5408\u5E76 daily\u3002\u672C\u671F\u65E0\u6D88\u8017\u53EF\u4E3A []"
140587
141579
  );
140588
141580
  }
140589
- const countryChart = asRecord26(charts.country);
141581
+ const countryChart = asRecord27(charts.country);
140590
141582
  if (!Array.isArray(countryChart?.labels)) {
140591
141583
  pushMissing3(
140592
141584
  missing,
@@ -140596,7 +141588,7 @@ function validateMetaPeriodReportContent(data) {
140596
141588
  "\u987B\u6709 charts.country.labels \u6570\u7EC4\uFF1B\u53EF\u7531 --snapshot-dir \u5408\u5E76 country\u3002\u672C\u671F\u65E0\u6D88\u8017\u53EF\u4E3A []"
140597
141589
  );
140598
141590
  }
140599
- const audienceChart = asRecord26(charts.audience);
141591
+ const audienceChart = asRecord27(charts.audience);
140600
141592
  if (!Array.isArray(audienceChart?.labels)) {
140601
141593
  pushMissing3(
140602
141594
  missing,
@@ -140615,7 +141607,7 @@ function validateMetaPeriodReportContent(data) {
140615
141607
  "\u5FC5\u987B\u6070\u597D 4 \u95EE\uFF1A\u94B1\u82B1\u5F97\u503C\u4E0D\u503C / \u8C01\u771F\u7684\u60F3\u4E70 / \u5E7F\u544A\u8FD8\u65B0\u9C9C\u5417 / \u7528\u6237\u4E3A\u4EC0\u4E48\u4E0D\u7559\u8D44"
140616
141608
  );
140617
141609
  } else {
140618
- const titles = fourQuestions.map((q) => asRecord26(q)?.title);
141610
+ const titles = fourQuestions.map((q) => asRecord27(q)?.title);
140619
141611
  for (const title of FOUR_QUESTION_TITLES) {
140620
141612
  if (!titles.includes(title)) {
140621
141613
  pushMissing3(
@@ -140628,7 +141620,7 @@ function validateMetaPeriodReportContent(data) {
140628
141620
  }
140629
141621
  }
140630
141622
  for (let i = 0; i < fourQuestions.length; i++) {
140631
- const q = asRecord26(fourQuestions[i]);
141623
+ const q = asRecord27(fourQuestions[i]);
140632
141624
  if (textLen3(q?.verdict) < 8) {
140633
141625
  pushMissing3(
140634
141626
  missing,
@@ -140668,7 +141660,7 @@ function validateMetaPeriodReportContent(data) {
140668
141660
  );
140669
141661
  } else {
140670
141662
  for (let i = 0; i < recommendations.length; i++) {
140671
- const rec = asRecord26(recommendations[i]);
141663
+ const rec = asRecord27(recommendations[i]);
140672
141664
  if (textLen3(rec?.title) < 2) {
140673
141665
  pushMissing3(
140674
141666
  missing,
@@ -140764,7 +141756,7 @@ async function readJsonFile4(filePath) {
140764
141756
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
140765
141757
  }
140766
141758
  }
140767
- function asRecord27(value) {
141759
+ function asRecord28(value) {
140768
141760
  if (value && typeof value === "object" && !Array.isArray(value)) {
140769
141761
  return value;
140770
141762
  }
@@ -140794,7 +141786,7 @@ function defaultOutPath(dataPath, format, out) {
140794
141786
  }
140795
141787
  async function runFacebookAnalysisRender(opts) {
140796
141788
  const dataPath = path42.resolve(opts.dataFile);
140797
- let data = asRecord27(await readJsonFile4(dataPath));
141789
+ let data = asRecord28(await readJsonFile4(dataPath));
140798
141790
  if (opts.snapshotDir?.trim()) {
140799
141791
  data = await mergeFacebookSnapshotIntoReport(data, path42.resolve(opts.snapshotDir));
140800
141792
  }
@@ -140860,7 +141852,7 @@ import { fileURLToPath as fileURLToPath11 } from "url";
140860
141852
  // src/commands/facebook-analysis/diagnosis-merge-snapshot.ts
140861
141853
  import * as fs36 from "fs/promises";
140862
141854
  import * as path43 from "path";
140863
- function asRecord28(value) {
141855
+ function asRecord29(value) {
140864
141856
  if (value && typeof value === "object" && !Array.isArray(value)) {
140865
141857
  return value;
140866
141858
  }
@@ -140871,7 +141863,7 @@ function num8(value) {
140871
141863
  return Number.isFinite(n) ? n : void 0;
140872
141864
  }
140873
141865
  function asRows(value) {
140874
- return Array.isArray(value) ? value.filter((r) => asRecord28(r) !== null) : [];
141866
+ return Array.isArray(value) ? value.filter((r) => asRecord29(r) !== null) : [];
140875
141867
  }
140876
141868
  function pickMetricExtras(row, extras) {
140877
141869
  const out = {
@@ -140920,14 +141912,14 @@ async function readManifest4(snapshotDir, accountId) {
140920
141912
  async function loadSectionFile4(snapshotDir, file) {
140921
141913
  try {
140922
141914
  const raw = await fs36.readFile(path43.join(snapshotDir, file), "utf8");
140923
- return asRecord28(JSON.parse(raw));
141915
+ return asRecord29(JSON.parse(raw));
140924
141916
  } catch {
140925
141917
  return null;
140926
141918
  }
140927
141919
  }
140928
141920
  async function mergeMetaDiagnosisSnapshotIntoReport(payload, snapshotDir) {
140929
141921
  const absDir = path43.resolve(snapshotDir);
140930
- const metaAccountId = typeof asRecord28(payload.meta)?.accountId === "string" ? asRecord28(payload.meta)?.accountId : void 0;
141922
+ const metaAccountId = typeof asRecord29(payload.meta)?.accountId === "string" ? asRecord29(payload.meta)?.accountId : void 0;
140931
141923
  const manifest = await readManifest4(snapshotDir, metaAccountId);
140932
141924
  if (!manifest) {
140933
141925
  throw new Error(
@@ -140940,8 +141932,8 @@ async function mergeMetaDiagnosisSnapshotIntoReport(payload, snapshotDir) {
140940
141932
  if (data) sectionMap.set(art.section, data);
140941
141933
  }
140942
141934
  const overview = sectionMap.get("overview");
140943
- const currentPeriod = asRecord28(overview?.currentPeriod);
140944
- const previousPeriod = asRecord28(overview?.previousPeriod);
141935
+ const currentPeriod = asRecord29(overview?.currentPeriod);
141936
+ const previousPeriod = asRecord29(overview?.previousPeriod);
140945
141937
  const accountId = manifest.accountId ?? metaAccountId;
140946
141938
  const meta = { ...payload.meta ?? {} };
140947
141939
  if (!meta.accountId && accountId) meta.accountId = accountId;
@@ -141075,7 +142067,7 @@ function textLen4(value) {
141075
142067
  function asArray5(value) {
141076
142068
  return Array.isArray(value) ? value : [];
141077
142069
  }
141078
- function asRecord29(value) {
142070
+ function asRecord30(value) {
141079
142071
  if (value && typeof value === "object" && !Array.isArray(value)) {
141080
142072
  return value;
141081
142073
  }
@@ -141086,9 +142078,9 @@ function pushMissing4(missing, id, chapter, dimension, hint) {
141086
142078
  }
141087
142079
  function validateMetaDiagnosisReportContent(data) {
141088
142080
  const missing = [];
141089
- const meta = asRecord29(data.meta) ?? {};
141090
- const narrative = asRecord29(data.narrative) ?? {};
141091
- const sections = asRecord29(narrative.sections) ?? {};
142081
+ const meta = asRecord30(data.meta) ?? {};
142082
+ const narrative = asRecord30(data.narrative) ?? {};
142083
+ const sections = asRecord30(narrative.sections) ?? {};
141092
142084
  if (!textLen4(meta.accountId)) {
141093
142085
  pushMissing4(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
141094
142086
  }
@@ -141106,7 +142098,7 @@ function validateMetaDiagnosisReportContent(data) {
141106
142098
  const sectionSuggestionCounts = {};
141107
142099
  const sectionNotAvailable = {};
141108
142100
  for (const key of NORMAL_SECTION_KEYS) {
141109
- const section = asRecord29(sections[key]);
142101
+ const section = asRecord30(sections[key]);
141110
142102
  const analysis = asArray5(section?.analysis).filter((s) => textLen4(s) > 0);
141111
142103
  const suggestions = asArray5(section?.suggestions).filter((s) => textLen4(s) > 0);
141112
142104
  sectionAnalysisCounts[key] = analysis.length;
@@ -141132,7 +142124,7 @@ function validateMetaDiagnosisReportContent(data) {
141132
142124
  }
141133
142125
  }
141134
142126
  for (const key of NA_SECTION_KEYS) {
141135
- const section = asRecord29(sections[key]);
142127
+ const section = asRecord30(sections[key]);
141136
142128
  const analysis = asArray5(section?.analysis).filter((s) => textLen4(s) > 0);
141137
142129
  const suggestions = asArray5(section?.suggestions).filter((s) => textLen4(s) > 0);
141138
142130
  const notAvailable = section?.notAvailable === true;
@@ -141154,7 +142146,7 @@ function validateMetaDiagnosisReportContent(data) {
141154
142146
  }
141155
142147
  const recommendations = asArray5(narrative.recommendations).filter((r) => {
141156
142148
  if (typeof r === "string") return textLen4(r) > 0;
141157
- const rec = asRecord29(r);
142149
+ const rec = asRecord30(r);
141158
142150
  return textLen4(rec?.content) > 0;
141159
142151
  });
141160
142152
  if (recommendations.length < 3) {
@@ -141229,7 +142221,7 @@ async function readJsonFile5(filePath) {
141229
142221
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
141230
142222
  }
141231
142223
  }
141232
- function asRecord30(value) {
142224
+ function asRecord31(value) {
141233
142225
  if (value && typeof value === "object" && !Array.isArray(value)) {
141234
142226
  return value;
141235
142227
  }
@@ -141245,7 +142237,7 @@ function injectReportData4(html, payload, lang) {
141245
142237
  }
141246
142238
  async function runFacebookAnalysisDiagnosisRender(opts) {
141247
142239
  const dataPath = path44.resolve(opts.dataFile);
141248
- let data = asRecord30(await readJsonFile5(dataPath));
142240
+ let data = asRecord31(await readJsonFile5(dataPath));
141249
142241
  if (opts.snapshotDir?.trim()) {
141250
142242
  data = await mergeMetaDiagnosisSnapshotIntoReport(data, path44.resolve(opts.snapshotDir));
141251
142243
  }
@@ -141325,8 +142317,8 @@ function resolveSectionList2(sections, exclude) {
141325
142317
  }
141326
142318
  const includeCanonical = new Set(include.map((n) => normalizeSectionToken(n)).filter(Boolean));
141327
142319
  const dropCanonical = new Set(dropRaw.map((n) => normalizeSectionToken(n)).filter(Boolean));
141328
- const base = include.length > 0 ? FACEBOOK_SECTIONS.filter((s) => includeCanonical.has(s.name)) : [...FACEBOOK_SECTIONS];
141329
- return base.filter((s) => !dropCanonical.has(s.name));
142320
+ const base2 = include.length > 0 ? FACEBOOK_SECTIONS.filter((s) => includeCanonical.has(s.name)) : [...FACEBOOK_SECTIONS];
142321
+ return base2.filter((s) => !dropCanonical.has(s.name));
141330
142322
  }
141331
142323
 
141332
142324
  // src/commands/facebook-analysis/run-batch.ts
@@ -141445,7 +142437,7 @@ function resolveFacebookPageSize(raw, fallback = FB_ENTITY_PAGE_SIZE_DEFAULT) {
141445
142437
  if (!Number.isFinite(n) || n <= 0) return fallback;
141446
142438
  return Math.min(Math.max(Math.floor(n), 1), FB_ENTITY_PAGE_SIZE_MAX);
141447
142439
  }
141448
- function asRecord31(value) {
142440
+ function asRecord32(value) {
141449
142441
  return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
141450
142442
  }
141451
142443
  function pickProp(obj, ...keys) {
@@ -141455,12 +142447,12 @@ function pickProp(obj, ...keys) {
141455
142447
  return void 0;
141456
142448
  }
141457
142449
  function unwrapFacebookPaged(raw) {
141458
- const rec = asRecord31(raw);
142450
+ const rec = asRecord32(raw);
141459
142451
  if (!rec) return { items: [] };
141460
142452
  const data = pickProp(rec, "data", "Data");
141461
142453
  const items3 = Array.isArray(data) ? data : [];
141462
- const paging = asRecord31(pickProp(rec, "paging", "Paging"));
141463
- const cursors = paging ? asRecord31(pickProp(paging, "cursors", "Cursors")) : void 0;
142454
+ const paging = asRecord32(pickProp(rec, "paging", "Paging"));
142455
+ const cursors = paging ? asRecord32(pickProp(paging, "cursors", "Cursors")) : void 0;
141464
142456
  const afterRaw = cursors ? pickProp(cursors, "after", "After") : void 0;
141465
142457
  const after = typeof afterRaw === "string" && afterRaw.trim() ? afterRaw.trim() : void 0;
141466
142458
  return { items: items3, after };
@@ -141522,14 +142514,14 @@ function parseEffectiveStatusFilter(raw) {
141522
142514
  return canonical.length ? canonical.join(",") : void 0;
141523
142515
  }
141524
142516
  function facebookAdsUrl(facebookApiUrl, digits, path56) {
141525
- const base = facebookApiUrl.replace(/\/$/, "");
142517
+ const base2 = facebookApiUrl.replace(/\/$/, "");
141526
142518
  const p = path56.startsWith("/") ? path56 : `/${path56}`;
141527
- return `${base}/api/fb/ads/${digits}${p}`;
142519
+ return `${base2}/api/fb/ads/${digits}${p}`;
141528
142520
  }
141529
142521
  function facebookInsightsUrl(facebookApiUrl, digits, level) {
141530
- const base = facebookApiUrl.replace(/\/$/, "");
142522
+ const base2 = facebookApiUrl.replace(/\/$/, "");
141531
142523
  const suffix = level === "account" ? "" : `/${level}`;
141532
- return `${base}/api/fb/ads/insights/accounts/${digits}${suffix}`;
142524
+ return `${base2}/api/fb/ads/insights/accounts/${digits}${suffix}`;
141533
142525
  }
141534
142526
  function buildEntityQuery(opts) {
141535
142527
  const q = new URLSearchParams();
@@ -141552,16 +142544,16 @@ function buildInsightsQuery(opts) {
141552
142544
  return q;
141553
142545
  }
141554
142546
  async function fetchFacebookAccount(config, digits, verbose) {
141555
- const base = requireFacebookApi(config);
142547
+ const base2 = requireFacebookApi(config);
141556
142548
  return apiFetch2(
141557
- facebookAdsUrl(base, digits, "/account"),
142549
+ facebookAdsUrl(base2, digits, "/account"),
141558
142550
  config,
141559
142551
  {},
141560
142552
  verbose
141561
142553
  );
141562
142554
  }
141563
142555
  async function fetchFacebookPagedList(config, digits, path56, opts) {
141564
- const base = requireFacebookApi(config);
142556
+ const base2 = requireFacebookApi(config);
141565
142557
  const items3 = [];
141566
142558
  let after;
141567
142559
  let pagesFetched = 0;
@@ -141575,7 +142567,7 @@ async function fetchFacebookPagedList(config, digits, path56, opts) {
141575
142567
  adsetId: opts.adsetId
141576
142568
  });
141577
142569
  const raw = await apiFetch2(
141578
- `${facebookAdsUrl(base, digits, path56)}?${query}`,
142570
+ `${facebookAdsUrl(base2, digits, path56)}?${query}`,
141579
142571
  config,
141580
142572
  {},
141581
142573
  opts.verbose
@@ -141591,7 +142583,7 @@ async function fetchFacebookPagedList(config, digits, path56, opts) {
141591
142583
  }
141592
142584
  async function fetchFacebookInsights(config, digits, level, opts) {
141593
142585
  assertFacebookInsightsQuery({ breakdown: opts.breakdown, timeIncrement: opts.timeIncrement });
141594
- const base = requireFacebookApi(config);
142586
+ const base2 = requireFacebookApi(config);
141595
142587
  const query = buildInsightsQuery({
141596
142588
  startDate: opts.startDate,
141597
142589
  endDate: opts.endDate,
@@ -141602,13 +142594,13 @@ async function fetchFacebookInsights(config, digits, level, opts) {
141602
142594
  adIds: opts.adIds
141603
142595
  });
141604
142596
  const raw = await apiFetch2(
141605
- `${facebookInsightsUrl(base, digits, level)}?${query}`,
142597
+ `${facebookInsightsUrl(base2, digits, level)}?${query}`,
141606
142598
  config,
141607
142599
  {},
141608
142600
  opts.verbose
141609
142601
  );
141610
142602
  if (Array.isArray(raw)) return raw;
141611
- const rec = asRecord31(raw);
142603
+ const rec = asRecord32(raw);
141612
142604
  const data = rec ? pickProp(rec, "data", "Data") : void 0;
141613
142605
  return Array.isArray(data) ? data : [];
141614
142606
  }
@@ -141617,7 +142609,7 @@ function sumActionArray(raw) {
141617
142609
  let sum = 0;
141618
142610
  let hit = false;
141619
142611
  for (const item of raw) {
141620
- const rec = asRecord31(item);
142612
+ const rec = asRecord32(item);
141621
142613
  if (!rec) continue;
141622
142614
  const n = Number(rec.value);
141623
142615
  if (!Number.isFinite(n)) continue;
@@ -141628,7 +142620,7 @@ function sumActionArray(raw) {
141628
142620
  }
141629
142621
 
141630
142622
  // src/commands/facebook-analysis/entities.ts
141631
- function fail(label2, err) {
142623
+ function fail2(label2, err) {
141632
142624
  const msg = err instanceof Error ? err.message : String(err);
141633
142625
  console.error(`
141634
142626
  \u274C ${label2}\uFF1A${msg}
@@ -141656,7 +142648,7 @@ async function runFacebookAccountStatus(opts) {
141656
142648
  try {
141657
142649
  row = await fetchFacebookAccount(config, manifestId, !!opts.verbose);
141658
142650
  } catch (err) {
141659
- fail("\u67E5\u8BE2 Facebook \u8D26\u6237\u5931\u8D25", err);
142651
+ fail2("\u67E5\u8BE2 Facebook \u8D26\u6237\u5931\u8D25", err);
141660
142652
  }
141661
142653
  const payload = { account: manifestId, ...row };
141662
142654
  if (await emitCliJsonOrSnapshot(opts, {
@@ -141706,7 +142698,7 @@ async function runFacebookEntityList(opts, kind) {
141706
142698
  try {
141707
142699
  effectiveStatus = parseEffectiveStatusFilter(opts.effectiveStatus);
141708
142700
  } catch (err) {
141709
- fail("\u53C2\u6570\u9519\u8BEF", err);
142701
+ fail2("\u53C2\u6570\u9519\u8BEF", err);
141710
142702
  }
141711
142703
  const pageSize = resolveFacebookPageSize(opts.pageSize);
141712
142704
  const config = loadConfig(opts.token);
@@ -141731,7 +142723,7 @@ async function runFacebookEntityList(opts, kind) {
141731
142723
  adsetId: opts.adsetId?.trim() || void 0
141732
142724
  });
141733
142725
  } catch (err) {
141734
- fail(`\u67E5\u8BE2 ${meta.title} \u5931\u8D25`, err);
142726
+ fail2(`\u67E5\u8BE2 ${meta.title} \u5931\u8D25`, err);
141735
142727
  }
141736
142728
  const payload = wrapListJson({
141737
142729
  page: 1,
@@ -141852,7 +142844,7 @@ async function runFacebookInsights(opts) {
141852
142844
  breakdown = resolveFacebookBreakdown(opts.breakdown);
141853
142845
  timeIncrement = parseOptionalNumber2(opts.timeIncrement);
141854
142846
  } catch (err) {
141855
- fail("\u53C2\u6570\u9519\u8BEF", err);
142847
+ fail2("\u53C2\u6570\u9519\u8BEF", err);
141856
142848
  }
141857
142849
  const config = loadConfig(opts.token);
141858
142850
  let items3;
@@ -141868,7 +142860,7 @@ async function runFacebookInsights(opts) {
141868
142860
  adIds: opts.adIds?.trim() || void 0
141869
142861
  });
141870
142862
  } catch (err) {
141871
- fail("\u67E5\u8BE2 Facebook Insights \u5931\u8D25", err);
142863
+ fail2("\u67E5\u8BE2 Facebook Insights \u5931\u8D25", err);
141872
142864
  }
141873
142865
  const payload = {
141874
142866
  account: manifestId,
@@ -142146,8 +143138,8 @@ function resolveSectionList3(sections, exclude) {
142146
143138
  const includeCanonical = new Set(include.map((n) => normalizeSectionToken2(n)).filter(Boolean));
142147
143139
  const dropCanonical = new Set(dropRaw.map((n) => normalizeSectionToken2(n)).filter(Boolean));
142148
143140
  const defaultSet = new Set(BING_DEFAULT_SECTION_NAMES);
142149
- const base = include.length > 0 ? BING_SECTIONS.filter((s) => includeCanonical.has(s.name)) : BING_SECTIONS.filter((s) => defaultSet.has(s.name));
142150
- return dropMergedWhenSplitPresent(base.filter((s) => !dropCanonical.has(s.name)));
143141
+ const base2 = include.length > 0 ? BING_SECTIONS.filter((s) => includeCanonical.has(s.name)) : BING_SECTIONS.filter((s) => defaultSet.has(s.name));
143142
+ return dropMergedWhenSplitPresent(base2.filter((s) => !dropCanonical.has(s.name)));
142151
143143
  }
142152
143144
 
142153
143145
  // src/commands/bing-analysis/fetch.ts
@@ -142898,7 +143890,7 @@ import { fileURLToPath as fileURLToPath12 } from "url";
142898
143890
  // src/commands/bing-analysis/merge-snapshot.ts
142899
143891
  import * as fs38 from "fs/promises";
142900
143892
  import * as path47 from "path";
142901
- function asRecord32(value) {
143893
+ function asRecord33(value) {
142902
143894
  if (value && typeof value === "object" && !Array.isArray(value)) {
142903
143895
  return value;
142904
143896
  }
@@ -142913,7 +143905,7 @@ function round27(value) {
142913
143905
  }
142914
143906
  function asRows2(value) {
142915
143907
  if (Array.isArray(value)) {
142916
- return value.filter((r) => asRecord32(r) !== null);
143908
+ return value.filter((r) => asRecord33(r) !== null);
142917
143909
  }
142918
143910
  return [];
142919
143911
  }
@@ -142995,17 +143987,17 @@ function campaignStatusDisplay(status) {
142995
143987
  return status == null || status === "" ? "\u2014" : String(status);
142996
143988
  }
142997
143989
  function mapDeviceRows(payload) {
142998
- const obj = asRecord32(payload);
143990
+ const obj = asRecord33(payload);
142999
143991
  return asRows2(obj?.devices).map((r) => pickMetrics(r, ["deviceType"]));
143000
143992
  }
143001
143993
  function mapGeographicRows(payload) {
143002
- const obj = asRecord32(payload);
143994
+ const obj = asRecord33(payload);
143003
143995
  return asRows2(obj?.countries).map(
143004
143996
  (r) => pickMetrics(r, ["countryOrRegion", "countryCriteriaId", "regionName", "cityName"])
143005
143997
  );
143006
143998
  }
143007
143999
  function mapAudienceLabelRows(payload, labelKey) {
143008
- const obj = asRecord32(payload);
144000
+ const obj = asRecord33(payload);
143009
144001
  return asRows2(obj?.audience).map((r) => {
143010
144002
  const m = pickMetrics(r, ["audience", "bidModifier"]);
143011
144003
  m[labelKey] = r.audience;
@@ -143013,7 +144005,7 @@ function mapAudienceLabelRows(payload, labelKey) {
143013
144005
  });
143014
144006
  }
143015
144007
  function mapAudienceFromMerged(payload) {
143016
- const data = asRecord32(asRecord32(payload)?.data);
144008
+ const data = asRecord33(asRecord33(payload)?.data);
143017
144009
  return {
143018
144010
  audienceAge: mapAudienceLabelRows(data?.ageAudience, "ageRange"),
143019
144011
  audienceGender: mapAudienceLabelRows(data?.genderAudience, "gender")
@@ -143108,7 +144100,7 @@ function mapSearchTermRows(payload) {
143108
144100
  }
143109
144101
  async function mergeBingAnalysisSnapshotIntoReport(payload, snapshotDir) {
143110
144102
  const absDir = path47.resolve(snapshotDir);
143111
- const metaAccountId = typeof asRecord32(payload.meta)?.accountId === "string" ? asRecord32(payload.meta)?.accountId : void 0;
144103
+ const metaAccountId = typeof asRecord33(payload.meta)?.accountId === "string" ? asRecord33(payload.meta)?.accountId : void 0;
143112
144104
  const manifest = await readManifest5(snapshotDir, metaAccountId);
143113
144105
  if (!manifest) {
143114
144106
  throw new Error(`\u672A\u5728 ${absDir} \u627E\u5230 report-manifest*.json\uFF0C\u8BF7\u5148\u6267\u884C bing-analysis --json-out`);
@@ -143118,9 +144110,9 @@ async function mergeBingAnalysisSnapshotIntoReport(payload, snapshotDir) {
143118
144110
  const data = await loadSectionPayload(absDir, art.file);
143119
144111
  if (data != null) sectionMap.set(art.section, data);
143120
144112
  }
143121
- const overview = asRecord32(sectionMap.get("overview"));
143122
- const currentPeriod = asRecord32(overview?.currentPeriod);
143123
- const previousPeriod = asRecord32(overview?.previousPeriod);
144113
+ const overview = asRecord33(sectionMap.get("overview"));
144114
+ const currentPeriod = asRecord33(overview?.currentPeriod);
144115
+ const previousPeriod = asRecord33(overview?.previousPeriod);
143124
144116
  const accountId = manifest.accountId ?? metaAccountId;
143125
144117
  const campaignRows3 = mapCampaignRows2(sectionMap.get("campaigns"));
143126
144118
  const campaignKpis = sumBingCampaignRowsToPeriodKpis(campaignRows3);
@@ -143247,7 +144239,7 @@ function textLen5(value) {
143247
144239
  function asArray6(value) {
143248
144240
  return Array.isArray(value) ? value : [];
143249
144241
  }
143250
- function asRecord33(value) {
144242
+ function asRecord34(value) {
143251
144243
  if (value && typeof value === "object" && !Array.isArray(value)) {
143252
144244
  return value;
143253
144245
  }
@@ -143258,9 +144250,9 @@ function pushMissing5(missing, id, chapter, dimension, hint) {
143258
144250
  }
143259
144251
  function validateBingPeriodReportContent(data) {
143260
144252
  const missing = [];
143261
- const meta = asRecord33(data.meta) ?? {};
143262
- const narrative = asRecord33(data.narrative) ?? {};
143263
- const sections = asRecord33(narrative.sections) ?? {};
144253
+ const meta = asRecord34(data.meta) ?? {};
144254
+ const narrative = asRecord34(data.narrative) ?? {};
144255
+ const sections = asRecord34(narrative.sections) ?? {};
143264
144256
  if (!textLen5(meta.accountId)) {
143265
144257
  pushMissing5(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
143266
144258
  }
@@ -143277,7 +144269,7 @@ function validateBingPeriodReportContent(data) {
143277
144269
  const sectionAnalysisCounts = {};
143278
144270
  const sectionSuggestionCounts = {};
143279
144271
  for (const key of SECTION_KEYS2) {
143280
- const section = asRecord33(sections[key]);
144272
+ const section = asRecord34(sections[key]);
143281
144273
  const analysis = asArray6(section?.analysis).filter((s) => textLen5(s) > 0);
143282
144274
  const suggestions = asArray6(section?.suggestions).filter((s) => textLen5(s) > 0);
143283
144275
  sectionAnalysisCounts[key] = analysis.length;
@@ -143303,7 +144295,7 @@ function validateBingPeriodReportContent(data) {
143303
144295
  }
143304
144296
  const recommendations = asArray6(narrative.recommendations).filter((r) => {
143305
144297
  if (typeof r === "string") return textLen5(r) > 0;
143306
- const rec = asRecord33(r);
144298
+ const rec = asRecord34(r);
143307
144299
  return textLen5(rec?.content) > 0;
143308
144300
  });
143309
144301
  if (recommendations.length < 3) {
@@ -143367,7 +144359,7 @@ async function readJsonFile6(filePath) {
143367
144359
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
143368
144360
  }
143369
144361
  }
143370
- function asRecord34(value) {
144362
+ function asRecord35(value) {
143371
144363
  if (value && typeof value === "object" && !Array.isArray(value)) {
143372
144364
  return value;
143373
144365
  }
@@ -143383,7 +144375,7 @@ function injectReportData5(html, payload, lang) {
143383
144375
  }
143384
144376
  async function runBingAnalysisRender(opts) {
143385
144377
  const dataPath = path48.resolve(opts.dataFile);
143386
- let data = asRecord34(await readJsonFile6(dataPath));
144378
+ let data = asRecord35(await readJsonFile6(dataPath));
143387
144379
  if (opts.snapshotDir?.trim()) {
143388
144380
  data = await mergeBingAnalysisSnapshotIntoReport(data, path48.resolve(opts.snapshotDir));
143389
144381
  }
@@ -143650,8 +144642,8 @@ function resolveSectionList4(sections, exclude) {
143650
144642
  }
143651
144643
  const includeCanonical = new Set(include.map((n) => normalizeSectionToken3(n)).filter(Boolean));
143652
144644
  const dropCanonical = new Set(dropRaw.map((n) => normalizeSectionToken3(n)).filter(Boolean));
143653
- const base = include.length > 0 ? TIKTOK_SECTIONS.filter((s) => includeCanonical.has(s.name)) : [...TIKTOK_SECTIONS];
143654
- return base.filter((s) => !dropCanonical.has(s.name));
144645
+ const base2 = include.length > 0 ? TIKTOK_SECTIONS.filter((s) => includeCanonical.has(s.name)) : [...TIKTOK_SECTIONS];
144646
+ return base2.filter((s) => !dropCanonical.has(s.name));
143655
144647
  }
143656
144648
 
143657
144649
  // src/commands/tiktok-analysis/fetch.ts
@@ -143730,12 +144722,12 @@ function endpointHintForTikTokSection(def) {
143730
144722
  // src/commands/tiktok-analysis/auxiliary.ts
143731
144723
  init_auth();
143732
144724
  async function fetchTikTokAreacode(config, verbose) {
143733
- const base = config.mainApiUrl?.trim();
143734
- if (!base) {
144725
+ const base2 = config.mainApiUrl?.trim();
144726
+ if (!base2) {
143735
144727
  console.error("\n\u274C \u65E0\u6CD5\u63A8\u5BFC mainApiUrl\uFF0C\u8BF7\u68C0\u67E5 tsoApiBaseUrl \u914D\u7F6E\u3002\n");
143736
144728
  process.exit(1);
143737
144729
  }
143738
- const url = `${base}/query/media-account/tiktok/TikTokAreacode/Read`;
144730
+ const url = `${base2}/query/media-account/tiktok/TikTokAreacode/Read`;
143739
144731
  return apiFetch2(url, config, {}, verbose);
143740
144732
  }
143741
144733
  async function fetchTikTokInterestList(config, account, verbose) {
@@ -143859,7 +144851,7 @@ import { fileURLToPath as fileURLToPath13 } from "url";
143859
144851
  // src/commands/tiktok-analysis/merge-snapshot.ts
143860
144852
  import * as fs40 from "fs/promises";
143861
144853
  import * as path50 from "path";
143862
- function asRecord35(value) {
144854
+ function asRecord36(value) {
143863
144855
  if (value && typeof value === "object" && !Array.isArray(value)) {
143864
144856
  return value;
143865
144857
  }
@@ -144037,7 +145029,7 @@ function mapAudienceMerged(payload) {
144037
145029
  }
144038
145030
  async function mergeTikTokAnalysisSnapshotIntoReport(payload, snapshotDir) {
144039
145031
  const absDir = path50.resolve(snapshotDir);
144040
- const metaAccountId = typeof asRecord35(payload.meta)?.accountId === "string" ? asRecord35(payload.meta)?.accountId : void 0;
145032
+ const metaAccountId = typeof asRecord36(payload.meta)?.accountId === "string" ? asRecord36(payload.meta)?.accountId : void 0;
144041
145033
  const manifest = await readManifest6(snapshotDir, metaAccountId);
144042
145034
  if (!manifest) {
144043
145035
  throw new Error(
@@ -144151,7 +145143,7 @@ function textLen6(value) {
144151
145143
  function asArray7(value) {
144152
145144
  return Array.isArray(value) ? value : [];
144153
145145
  }
144154
- function asRecord36(value) {
145146
+ function asRecord37(value) {
144155
145147
  if (value && typeof value === "object" && !Array.isArray(value)) {
144156
145148
  return value;
144157
145149
  }
@@ -144162,9 +145154,9 @@ function pushMissing6(missing, id, chapter, dimension, hint) {
144162
145154
  }
144163
145155
  function validateTikTokPeriodReportContent(data) {
144164
145156
  const missing = [];
144165
- const meta = asRecord36(data.meta) ?? {};
144166
- const narrative = asRecord36(data.narrative) ?? {};
144167
- const sections = asRecord36(narrative.sections) ?? {};
145157
+ const meta = asRecord37(data.meta) ?? {};
145158
+ const narrative = asRecord37(data.narrative) ?? {};
145159
+ const sections = asRecord37(narrative.sections) ?? {};
144168
145160
  if (!textLen6(meta.accountId)) {
144169
145161
  pushMissing6(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
144170
145162
  }
@@ -144181,7 +145173,7 @@ function validateTikTokPeriodReportContent(data) {
144181
145173
  const sectionAnalysisCounts = {};
144182
145174
  const sectionSuggestionCounts = {};
144183
145175
  for (const key of SECTION_KEYS3) {
144184
- const section = asRecord36(sections[key]);
145176
+ const section = asRecord37(sections[key]);
144185
145177
  const analysis = asArray7(section?.analysis).filter((s) => textLen6(s) > 0);
144186
145178
  const suggestions = asArray7(section?.suggestions).filter((s) => textLen6(s) > 0);
144187
145179
  sectionAnalysisCounts[key] = analysis.length;
@@ -144207,7 +145199,7 @@ function validateTikTokPeriodReportContent(data) {
144207
145199
  }
144208
145200
  const recommendations = asArray7(narrative.recommendations).filter((r) => {
144209
145201
  if (typeof r === "string") return textLen6(r) > 0;
144210
- const rec = asRecord36(r);
145202
+ const rec = asRecord37(r);
144211
145203
  return textLen6(rec?.content) > 0;
144212
145204
  });
144213
145205
  if (recommendations.length < 3) {
@@ -144271,7 +145263,7 @@ async function readJsonFile7(filePath) {
144271
145263
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
144272
145264
  }
144273
145265
  }
144274
- function asRecord37(value) {
145266
+ function asRecord38(value) {
144275
145267
  if (value && typeof value === "object" && !Array.isArray(value)) {
144276
145268
  return value;
144277
145269
  }
@@ -144287,7 +145279,7 @@ function injectReportData6(html, payload, lang) {
144287
145279
  }
144288
145280
  async function runTikTokAnalysisRender(opts) {
144289
145281
  const dataPath = path51.resolve(opts.dataFile);
144290
- let data = asRecord37(await readJsonFile7(dataPath));
145282
+ let data = asRecord38(await readJsonFile7(dataPath));
144291
145283
  if (opts.snapshotDir?.trim()) {
144292
145284
  data = await mergeTikTokAnalysisSnapshotIntoReport(data, path51.resolve(opts.snapshotDir));
144293
145285
  }
@@ -144571,16 +145563,16 @@ async function fetchTikTokPagedList(config, buildUrl, opts) {
144571
145563
  }
144572
145564
  return { items: items3, totalNumber, pagesFetched };
144573
145565
  }
144574
- function advertiserInfoUrl(base, advertiserIds) {
145566
+ function advertiserInfoUrl(base2, advertiserIds) {
144575
145567
  const q = new URLSearchParams({ advertiserids: advertiserIds });
144576
- return `${base}/tiktokadvquery/GetAdvertiserInfo/${TIKTOK_MEDIA_TYPE}?${q}`;
145568
+ return `${base2}/tiktokadvquery/GetAdvertiserInfo/${TIKTOK_MEDIA_TYPE}?${q}`;
144577
145569
  }
144578
- function entityListUrl(base, kind, query) {
145570
+ function entityListUrl(base2, kind, query) {
144579
145571
  const prefix = kind === "campaign" ? "tiktokcampaignmanagement/campaign" : kind === "adgroup" ? "tiktokadgroupmanagement/adgroup" : "tiktokadmanagement/ad";
144580
- return `${base}/${prefix}/${TIKTOK_MEDIA_TYPE}?${query}`;
145572
+ return `${base2}/${prefix}/${TIKTOK_MEDIA_TYPE}?${query}`;
144581
145573
  }
144582
- function officialReportUrl(base, query) {
144583
- return `${base}/query/report/${TIKTOK_MEDIA_TYPE}/search?${query}`;
145574
+ function officialReportUrl(base2, query) {
145575
+ return `${base2}/query/report/${TIKTOK_MEDIA_TYPE}/search?${query}`;
144584
145576
  }
144585
145577
  function buildEntityQuery2(opts) {
144586
145578
  const q = new URLSearchParams({
@@ -144609,16 +145601,16 @@ function buildOfficialReportQuery(opts) {
144609
145601
  });
144610
145602
  }
144611
145603
  async function fetchAdvertiserInfoList(config, advertiserId, verbose) {
144612
- const base = requireTikTokApiUrl(config);
144613
- const raw = await apiFetch2(advertiserInfoUrl(base, advertiserId), config, {}, verbose);
145604
+ const base2 = requireTikTokApiUrl(config);
145605
+ const raw = await apiFetch2(advertiserInfoUrl(base2, advertiserId), config, {}, verbose);
144614
145606
  return unwrapTikTokEnvelope(raw, "GetAdvertiserInfo").list;
144615
145607
  }
144616
145608
  async function fetchCampaignEntities(config, opts) {
144617
- const base = requireTikTokApiUrl(config);
145609
+ const base2 = requireTikTokApiUrl(config);
144618
145610
  return fetchTikTokPagedList(
144619
145611
  config,
144620
145612
  (pageNum, pageSize) => entityListUrl(
144621
- base,
145613
+ base2,
144622
145614
  "campaign",
144623
145615
  buildEntityQuery2({
144624
145616
  advertiserId: opts.advertiserId,
@@ -144631,11 +145623,11 @@ async function fetchCampaignEntities(config, opts) {
144631
145623
  );
144632
145624
  }
144633
145625
  async function fetchAdGroupEntities(config, opts) {
144634
- const base = requireTikTokApiUrl(config);
145626
+ const base2 = requireTikTokApiUrl(config);
144635
145627
  return fetchTikTokPagedList(
144636
145628
  config,
144637
145629
  (pageNum, pageSize) => entityListUrl(
144638
- base,
145630
+ base2,
144639
145631
  "adgroup",
144640
145632
  buildEntityQuery2({
144641
145633
  advertiserId: opts.advertiserId,
@@ -144649,11 +145641,11 @@ async function fetchAdGroupEntities(config, opts) {
144649
145641
  );
144650
145642
  }
144651
145643
  async function fetchAdEntities(config, opts) {
144652
- const base = requireTikTokApiUrl(config);
145644
+ const base2 = requireTikTokApiUrl(config);
144653
145645
  return fetchTikTokPagedList(
144654
145646
  config,
144655
145647
  (pageNum, pageSize) => entityListUrl(
144656
- base,
145648
+ base2,
144657
145649
  "ad",
144658
145650
  buildEntityQuery2({
144659
145651
  advertiserId: opts.advertiserId,
@@ -144670,11 +145662,11 @@ async function fetchAdEntities(config, opts) {
144670
145662
  }
144671
145663
  async function fetchOfficialReport(config, opts) {
144672
145664
  const metrics = expandTikTokOfficialReportMetrics(opts.metrics);
144673
- const base = requireTikTokApiUrl(config);
145665
+ const base2 = requireTikTokApiUrl(config);
144674
145666
  const raw = await fetchTikTokPagedList(
144675
145667
  config,
144676
145668
  (pageNum, pageSize) => officialReportUrl(
144677
- base,
145669
+ base2,
144678
145670
  buildOfficialReportQuery({
144679
145671
  advertiserId: opts.advertiserId,
144680
145672
  startDate: opts.startDate,
@@ -144697,7 +145689,7 @@ async function fetchOfficialReport(config, opts) {
144697
145689
  }
144698
145690
 
144699
145691
  // src/commands/tiktok-analysis/entities.ts
144700
- function fail2(label2, err) {
145692
+ function fail3(label2, err) {
144701
145693
  const msg = err instanceof Error ? err.message : String(err);
144702
145694
  console.error(`
144703
145695
  \u274C ${label2}\uFF1A${msg}
@@ -144711,7 +145703,7 @@ async function runTikTokAccountStatus(opts) {
144711
145703
  try {
144712
145704
  rows = await fetchAdvertiserInfoList(config, id, !!opts.verbose);
144713
145705
  } catch (err) {
144714
- fail2("\u67E5\u8BE2 TikTok \u8D26\u6237\u4FE1\u606F\u5931\u8D25\uFF08\u987B\u62E5\u6709\u8BE5\u5E7F\u544A\u4E3B\uFF0C\u5217\u8868\u53EF\u89C1\u4E0D\u591F\uFF09", err);
145706
+ fail3("\u67E5\u8BE2 TikTok \u8D26\u6237\u4FE1\u606F\u5931\u8D25\uFF08\u987B\u62E5\u6709\u8BE5\u5E7F\u544A\u4E3B\uFF0C\u5217\u8868\u53EF\u89C1\u4E0D\u591F\uFF09", err);
144715
145707
  }
144716
145708
  const payload = wrapListJson({
144717
145709
  page: 1,
@@ -144766,7 +145758,7 @@ async function runTikTokCampaignEntities(opts) {
144766
145758
  verbose: !!opts.verbose
144767
145759
  });
144768
145760
  } catch (err) {
144769
- fail2("\u67E5\u8BE2 TikTok \u7CFB\u5217\u5931\u8D25", err);
145761
+ fail3("\u67E5\u8BE2 TikTok \u7CFB\u5217\u5931\u8D25", err);
144770
145762
  }
144771
145763
  const payload = wrapListJson({
144772
145764
  page: 1,
@@ -144828,7 +145820,7 @@ async function runTikTokAdGroupEntities(opts) {
144828
145820
  verbose: !!opts.verbose
144829
145821
  });
144830
145822
  } catch (err) {
144831
- fail2("\u67E5\u8BE2 TikTok \u5E7F\u544A\u7EC4\u5931\u8D25", err);
145823
+ fail3("\u67E5\u8BE2 TikTok \u5E7F\u544A\u7EC4\u5931\u8D25", err);
144832
145824
  }
144833
145825
  const payload = wrapListJson({
144834
145826
  page: 1,
@@ -144895,7 +145887,7 @@ async function runTikTokAdEntities(opts) {
144895
145887
  verbose: !!opts.verbose
144896
145888
  });
144897
145889
  } catch (err) {
144898
- fail2("\u67E5\u8BE2 TikTok \u5E7F\u544A\u5931\u8D25", err);
145890
+ fail3("\u67E5\u8BE2 TikTok \u5E7F\u544A\u5931\u8D25", err);
144899
145891
  }
144900
145892
  const payload = wrapListJson({
144901
145893
  page: 1,
@@ -144969,7 +145961,7 @@ async function runTikTokOfficialReport(opts) {
144969
145961
  verbose: !!opts.verbose
144970
145962
  });
144971
145963
  } catch (err) {
144972
- fail2("\u67E5\u8BE2 TikTok \u5B98\u65B9\u62A5\u8868\u5931\u8D25", err);
145964
+ fail3("\u67E5\u8BE2 TikTok \u5B98\u65B9\u62A5\u8868\u5931\u8D25", err);
144973
145965
  }
144974
145966
  const totals = summarizeTikTokOfficialReport(result.items);
144975
145967
  const payload = {
@@ -145346,14 +146338,14 @@ function assertYandexAccountId(id) {
145346
146338
  return t;
145347
146339
  }
145348
146340
  function requireYandexApi(config) {
145349
- const base = (config.yandexApiUrl ?? "").replace(/\/$/, "");
145350
- if (!base) {
146341
+ const base2 = (config.yandexApiUrl ?? "").replace(/\/$/, "");
146342
+ if (!base2) {
145351
146343
  console.error(
145352
146344
  "\n\u274C \u672A\u627E\u5230 Yandex API \u5730\u5740\uFF08yandexApiUrl\uFF09\u3002\n \u4ECE TSO API \u5730\u5740\u81EA\u52A8\u63A8\u5BFC\uFF0C\u4E5F\u53EF\u901A\u8FC7\u73AF\u5883\u53D8\u91CF SILUZAN_YANDEX_API \u8986\u76D6\u3002\n"
145353
146345
  );
145354
146346
  process.exit(1);
145355
146347
  }
145356
- return base;
146348
+ return base2;
145357
146349
  }
145358
146350
  function resolveYandexLimit(raw) {
145359
146351
  const n = typeof raw === "number" ? raw : parseInt(String(raw ?? ""), 10);
@@ -145361,9 +146353,9 @@ function resolveYandexLimit(raw) {
145361
146353
  return Math.min(Math.floor(n), YANDEX_KEYWORD_LIMIT_MAX);
145362
146354
  }
145363
146355
  function analysisUrl(yandexApiUrl, pathSeg, query) {
145364
- const base = yandexApiUrl.replace(/\/$/, "");
146356
+ const base2 = yandexApiUrl.replace(/\/$/, "");
145365
146357
  const q = query ? query.startsWith("?") ? query : `?${query}` : "";
145366
- return `${base}/yandex-analysis/${pathSeg}${q}`;
146358
+ return `${base2}/yandex-analysis/${pathSeg}${q}`;
145367
146359
  }
145368
146360
  async function fetchYandexSectionPayload(def, opts, config, accountId) {
145369
146361
  const { startDate, endDate } = resolveYandexDateRange(opts.start, opts.end);
@@ -145389,7 +146381,7 @@ function endpointHintForYandexSection(def) {
145389
146381
  // src/commands/yandex-analysis/merge-snapshot.ts
145390
146382
  import * as fs42 from "fs/promises";
145391
146383
  import * as path52 from "path";
145392
- function asRecord38(value) {
146384
+ function asRecord39(value) {
145393
146385
  if (value && typeof value === "object" && !Array.isArray(value)) {
145394
146386
  return value;
145395
146387
  }
@@ -145409,11 +146401,11 @@ function normalizeYandexRoi(value) {
145409
146401
  return r === -1 ? void 0 : r;
145410
146402
  }
145411
146403
  function asItems(payload) {
145412
- const obj = asRecord38(payload);
146404
+ const obj = asRecord39(payload);
145413
146405
  if (!obj) return [];
145414
146406
  const items3 = obj.items;
145415
146407
  if (!Array.isArray(items3)) return [];
145416
- return items3.filter((r) => asRecord38(r) !== null);
146408
+ return items3.filter((r) => asRecord39(r) !== null);
145417
146409
  }
145418
146410
  function pickMetrics2(row, extras = []) {
145419
146411
  const spend = num12(row.spend) ?? 0;
@@ -145549,7 +146541,7 @@ function aggregateDailyToWeekly(dailyRows) {
145549
146541
  });
145550
146542
  }
145551
146543
  function prepareYandexDailyPayload(payload) {
145552
- const obj = asRecord38(payload) ?? {};
146544
+ const obj = asRecord39(payload) ?? {};
145553
146545
  const items3 = asItems(obj).map((r) => {
145554
146546
  const date = normalizeYandexDailyDate(r.date);
145555
146547
  return date ? { ...r, date } : r;
@@ -145618,7 +146610,7 @@ function mapDeviceRows2(payload) {
145618
146610
  }
145619
146611
  async function mergeYandexAnalysisSnapshotIntoReport(payload, snapshotDir) {
145620
146612
  const absDir = path52.resolve(snapshotDir);
145621
- const metaAccountId = typeof asRecord38(payload.meta)?.accountId === "string" ? asRecord38(payload.meta)?.accountId : void 0;
146613
+ const metaAccountId = typeof asRecord39(payload.meta)?.accountId === "string" ? asRecord39(payload.meta)?.accountId : void 0;
145622
146614
  const manifest = await readManifest7(snapshotDir, metaAccountId);
145623
146615
  if (!manifest) {
145624
146616
  throw new Error(
@@ -145630,8 +146622,8 @@ async function mergeYandexAnalysisSnapshotIntoReport(payload, snapshotDir) {
145630
146622
  const data = await loadSectionPayload3(absDir, art.file);
145631
146623
  if (data != null) sectionMap.set(art.section, data);
145632
146624
  }
145633
- const overview = asRecord38(sectionMap.get("overview"));
145634
- const totals = asRecord38(overview?.totals);
146625
+ const overview = asRecord39(sectionMap.get("overview"));
146626
+ const totals = asRecord39(overview?.totals);
145635
146627
  const accountId = manifest.accountId ?? metaAccountId;
145636
146628
  const meta = { ...payload.meta ?? {} };
145637
146629
  if (!meta.accountId && accountId) meta.accountId = accountId;
@@ -145724,8 +146716,8 @@ function resolveSectionList5(sections, exclude) {
145724
146716
  }
145725
146717
  const includeCanonical = new Set(include.map((n) => normalizeSectionToken4(n)).filter(Boolean));
145726
146718
  const dropCanonical = new Set(dropRaw.map((n) => normalizeSectionToken4(n)).filter(Boolean));
145727
- const base = include.length > 0 ? YANDEX_SECTIONS.filter((s) => includeCanonical.has(s.name)) : [...YANDEX_SECTIONS];
145728
- return base.filter((s) => !dropCanonical.has(s.name));
146719
+ const base2 = include.length > 0 ? YANDEX_SECTIONS.filter((s) => includeCanonical.has(s.name)) : [...YANDEX_SECTIONS];
146720
+ return base2.filter((s) => !dropCanonical.has(s.name));
145729
146721
  }
145730
146722
 
145731
146723
  // src/commands/yandex-analysis/run-batch.ts
@@ -145853,7 +146845,7 @@ function textLen7(value) {
145853
146845
  function asArray8(value) {
145854
146846
  return Array.isArray(value) ? value : [];
145855
146847
  }
145856
- function asRecord39(value) {
146848
+ function asRecord40(value) {
145857
146849
  if (value && typeof value === "object" && !Array.isArray(value)) {
145858
146850
  return value;
145859
146851
  }
@@ -145866,23 +146858,23 @@ function normKey(value) {
145866
146858
  return String(value ?? "").trim().toLowerCase();
145867
146859
  }
145868
146860
  function insightMatchRecord(item) {
145869
- const rec = asRecord39(item);
146861
+ const rec = asRecord40(item);
145870
146862
  if (!rec) return {};
145871
- return asRecord39(rec.match) ?? rec;
146863
+ return asRecord40(rec.match) ?? rec;
145872
146864
  }
145873
146865
  function findRowInsight(list, primaryField, primaryValue, row) {
145874
146866
  const target = normKey(primaryValue);
145875
146867
  if (!target) return null;
145876
146868
  const candidates = list.filter((it) => normKey(insightMatchRecord(it)[primaryField]) === target);
145877
- if (candidates.length <= 1) return asRecord39(candidates[0]);
146869
+ if (candidates.length <= 1) return asRecord40(candidates[0]);
145878
146870
  const campaign = normKey(row.campaignName);
145879
146871
  const narrowed = candidates.find(
145880
146872
  (it) => normKey(insightMatchRecord(it).campaignName) === campaign
145881
146873
  );
145882
- return asRecord39(narrowed ?? candidates[0]);
146874
+ return asRecord40(narrowed ?? candidates[0]);
145883
146875
  }
145884
146876
  function topRowsBySpend(rows, limit) {
145885
- return rows.map((r) => asRecord39(r)).filter((r) => r != null).sort((a, b) => (Number(b.spend) || 0) - (Number(a.spend) || 0)).slice(0, limit);
146877
+ return rows.map((r) => asRecord40(r)).filter((r) => r != null).sort((a, b) => (Number(b.spend) || 0) - (Number(a.spend) || 0)).slice(0, limit);
145886
146878
  }
145887
146879
  var ROW_INSIGHT_SPECS = [
145888
146880
  {
@@ -145897,17 +146889,17 @@ var ROW_INSIGHT_SPECS = [
145897
146889
  ];
145898
146890
  function validateYandexPeriodReportContent(data) {
145899
146891
  const missing = [];
145900
- const meta = asRecord39(data.meta) ?? {};
145901
- const narrative = asRecord39(data.narrative) ?? {};
145902
- const sections = asRecord39(narrative.sections) ?? {};
145903
- const kpis = asRecord39(data.kpis) ?? {};
146892
+ const meta = asRecord40(data.meta) ?? {};
146893
+ const narrative = asRecord40(data.narrative) ?? {};
146894
+ const sections = asRecord40(narrative.sections) ?? {};
146895
+ const kpis = asRecord40(data.kpis) ?? {};
145904
146896
  if (!textLen7(meta.accountId)) {
145905
146897
  pushMissing7(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
145906
146898
  }
145907
146899
  const sectionAnalysisCounts = {};
145908
146900
  const sectionSuggestionCounts = {};
145909
146901
  for (const key of SECTION_KEYS4) {
145910
- const section = asRecord39(sections[key]);
146902
+ const section = asRecord40(sections[key]);
145911
146903
  const analysis = asArray8(section?.analysis).filter((s) => textLen7(s) > 0);
145912
146904
  const suggestions = asArray8(section?.suggestions).filter((s) => textLen7(s) > 0);
145913
146905
  sectionAnalysisCounts[key] = analysis.length;
@@ -145933,7 +146925,7 @@ function validateYandexPeriodReportContent(data) {
145933
146925
  }
145934
146926
  const recommendations = asArray8(narrative.recommendations).filter((r) => {
145935
146927
  if (typeof r === "string") return textLen7(r) > 0;
145936
- const rec = asRecord39(r);
146928
+ const rec = asRecord40(r);
145937
146929
  return textLen7(rec?.content) > 0 || textLen7(rec?.text) > 0;
145938
146930
  });
145939
146931
  if (recommendations.length < 3) {
@@ -145955,8 +146947,8 @@ function validateYandexPeriodReportContent(data) {
145955
146947
  "\u81F3\u5C11\u4E00\u9879\u6709\u6548\u6570\u5B57\uFF08\u8BF7\u4F20 --snapshot-dir \u7531 CLI \u4ECE overview \u5408\u5E76\uFF09"
145956
146948
  );
145957
146949
  }
145958
- const tables = asRecord39(data.tables) ?? {};
145959
- const weeklyRows = asArray8(tables.weekly).map((r) => asRecord39(r)).filter((r) => r != null);
146950
+ const tables = asRecord40(data.tables) ?? {};
146951
+ const weeklyRows = asArray8(tables.weekly).map((r) => asRecord40(r)).filter((r) => r != null);
145960
146952
  for (const [i, row] of weeklyRows.entries()) {
145961
146953
  const label2 = `${row.weekLabel ?? ""} ${row.startDate ?? ""} ${row.endDate ?? ""}`;
145962
146954
  if (/nan/i.test(label2) || !normalizeYandexDailyDate(row.startDate) || !normalizeYandexDailyDate(row.endDate)) {
@@ -145969,7 +146961,7 @@ function validateYandexPeriodReportContent(data) {
145969
146961
  );
145970
146962
  }
145971
146963
  }
145972
- const rowInsights = asRecord39(narrative.rowInsights) ?? {};
146964
+ const rowInsights = asRecord40(narrative.rowInsights) ?? {};
145973
146965
  const rowInsightCoverage = {};
145974
146966
  for (const spec of ROW_INSIGHT_SPECS) {
145975
146967
  const shown = topRowsBySpend(asArray8(tables[spec.tableKey]), spec.limit).filter(
@@ -146052,7 +147044,7 @@ async function readJsonFile8(filePath) {
146052
147044
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
146053
147045
  }
146054
147046
  }
146055
- function asRecord40(value) {
147047
+ function asRecord41(value) {
146056
147048
  if (value && typeof value === "object" && !Array.isArray(value)) {
146057
147049
  return value;
146058
147050
  }
@@ -146081,7 +147073,7 @@ function injectReportData7(html, payload, lang) {
146081
147073
  }
146082
147074
  async function runYandexAnalysisRender(opts) {
146083
147075
  const dataPath = path54.resolve(opts.dataFile);
146084
- let data = asRecord40(await readJsonFile8(dataPath));
147076
+ let data = asRecord41(await readJsonFile8(dataPath));
146085
147077
  if (opts.snapshotDir?.trim()) {
146086
147078
  data = await mergeYandexAnalysisSnapshotIntoReport(data, path54.resolve(opts.snapshotDir));
146087
147079
  }
@@ -146279,12 +147271,12 @@ function unwrapYandexItems(raw) {
146279
147271
  }
146280
147272
  return [];
146281
147273
  }
146282
- function asRecord41(raw) {
147274
+ function asRecord42(raw) {
146283
147275
  return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
146284
147276
  }
146285
147277
 
146286
147278
  // src/commands/yandex-analysis/entities.ts
146287
- function fail3(label2, err) {
147279
+ function fail4(label2, err) {
146288
147280
  const msg = err instanceof Error ? err.message : String(err);
146289
147281
  console.error(`
146290
147282
  \u274C ${label2}\uFF1A${msg}
@@ -146356,9 +147348,9 @@ async function runYandexAccountStatus(opts) {
146356
147348
  try {
146357
147349
  result = await fetchPath(opts, "overview", {});
146358
147350
  } catch (err) {
146359
- fail3("\u67E5\u8BE2 Yandex \u8D26\u6237\u603B\u89C8\u5931\u8D25", err);
147351
+ fail4("\u67E5\u8BE2 Yandex \u8D26\u6237\u603B\u89C8\u5931\u8D25", err);
146360
147352
  }
146361
- const row = asRecord41(result.raw);
147353
+ const row = asRecord42(result.raw);
146362
147354
  await emitOrTable(opts, {
146363
147355
  section: "yandex-account-status",
146364
147356
  commandLabel: "yandex-analysis account-status",
@@ -146398,7 +147390,7 @@ async function runYandexCampaignEntities(opts) {
146398
147390
  network: flags.network
146399
147391
  });
146400
147392
  } catch (err) {
146401
- fail3("\u67E5\u8BE2 Yandex \u7CFB\u5217\u5931\u8D25", err);
147393
+ fail4("\u67E5\u8BE2 Yandex \u7CFB\u5217\u5931\u8D25", err);
146402
147394
  }
146403
147395
  const items3 = unwrapYandexItems(result.raw);
146404
147396
  await emitOrTable(opts, {
@@ -146444,7 +147436,7 @@ async function runYandexAdGroupEntities(opts) {
146444
147436
  campaignId: flags.campaignId
146445
147437
  });
146446
147438
  } catch (err) {
146447
- fail3("\u67E5\u8BE2 Yandex \u5E7F\u544A\u7EC4\u5931\u8D25", err);
147439
+ fail4("\u67E5\u8BE2 Yandex \u5E7F\u544A\u7EC4\u5931\u8D25", err);
146448
147440
  }
146449
147441
  const items3 = unwrapYandexItems(result.raw);
146450
147442
  await emitOrTable(opts, {
@@ -146494,7 +147486,7 @@ async function runYandexAdEntities(opts) {
146494
147486
  adGroupId: flags.adGroupId
146495
147487
  });
146496
147488
  } catch (err) {
146497
- fail3("\u67E5\u8BE2 Yandex \u5E7F\u544A\u5931\u8D25", err);
147489
+ fail4("\u67E5\u8BE2 Yandex \u5E7F\u544A\u5931\u8D25", err);
146498
147490
  }
146499
147491
  const items3 = unwrapYandexItems(result.raw);
146500
147492
  const filtered = flags.status != null;
@@ -146546,7 +147538,7 @@ async function runYandexInsights(opts) {
146546
147538
  adGroupId: flags.adGroupId
146547
147539
  });
146548
147540
  } catch (err) {
146549
- fail3("\u67E5\u8BE2 Yandex insights \u5931\u8D25", err);
147541
+ fail4("\u67E5\u8BE2 Yandex insights \u5931\u8D25", err);
146550
147542
  }
146551
147543
  const items3 = unwrapYandexItems(result.raw);
146552
147544
  await emitOrTable(opts, {