siluzan-tso-cli 1.1.55 → 1.1.56-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4049,7 +4049,7 @@ var DEFAULT_API_BASE;
4049
4049
  var init_defaults = __esm({
4050
4050
  "src/config/defaults.ts"() {
4051
4051
  "use strict";
4052
- DEFAULT_API_BASE = "https://tso-api.siluzan.com";
4052
+ DEFAULT_API_BASE = "https://tso-api-ci.siluzan.com";
4053
4053
  }
4054
4054
  });
4055
4055
 
@@ -103126,7 +103126,7 @@ function narrativeClaimsMobileSpendLeads(text2) {
103126
103126
  if (!t.includes("\u79FB\u52A8")) return false;
103127
103127
  return /移动(?:端|设备)?(?:为|是)主要消耗/.test(t) || /移动(?:端|设备)?为主要(?:消耗)?设备/.test(t) || /移动(?:端|设备)?(?:消耗|花费|费用|流量)?占比高/.test(t);
103128
103128
  }
103129
- function asRecord16(value) {
103129
+ function asRecord18(value) {
103130
103130
  if (value && typeof value === "object" && !Array.isArray(value)) return value;
103131
103131
  return null;
103132
103132
  }
@@ -103134,16 +103134,16 @@ function stringList(value) {
103134
103134
  return (Array.isArray(value) ? value : []).map((item) => typeof item === "string" ? item.trim() : "").filter(Boolean);
103135
103135
  }
103136
103136
  function collectOkkiNarrativeText(data) {
103137
- const narrative = asRecord16(data.narrative) ?? {};
103137
+ const narrative = asRecord18(data.narrative) ?? {};
103138
103138
  const parts = [];
103139
- const sheetAnalysis = asRecord16(narrative.sheetAnalysis) ?? {};
103139
+ const sheetAnalysis = asRecord18(narrative.sheetAnalysis) ?? {};
103140
103140
  for (const block of Object.values(sheetAnalysis)) {
103141
- const rec = asRecord16(block);
103141
+ const rec = asRecord18(block);
103142
103142
  parts.push(...stringList(rec?.summary), ...stringList(rec?.suggestions));
103143
103143
  }
103144
- const review = asRecord16(narrative.review) ?? {};
103144
+ const review = asRecord18(narrative.review) ?? {};
103145
103145
  for (const block of Object.values(review)) {
103146
- const rec = asRecord16(block);
103146
+ const rec = asRecord18(block);
103147
103147
  for (const key of ["overview", "summary", "suggestion"]) {
103148
103148
  const value = rec?.[key];
103149
103149
  if (typeof value === "string" && value.trim()) parts.push(value.trim());
@@ -103160,7 +103160,7 @@ var init_okki_display = __esm({
103160
103160
  // src/commands/google-analysis/merge-snapshot.ts
103161
103161
  import * as fs27 from "fs/promises";
103162
103162
  import * as path32 from "path";
103163
- function asRecord17(value) {
103163
+ function asRecord19(value) {
103164
103164
  if (value && typeof value === "object" && !Array.isArray(value)) {
103165
103165
  return value;
103166
103166
  }
@@ -103256,7 +103256,7 @@ function periodMetricsFromRow(row) {
103256
103256
  }
103257
103257
  function items(envelope) {
103258
103258
  if (!envelope || !Array.isArray(envelope.items)) return [];
103259
- return envelope.items.filter((row) => asRecord17(row) !== null);
103259
+ return envelope.items.filter((row) => asRecord19(row) !== null);
103260
103260
  }
103261
103261
  function record(envelope) {
103262
103262
  return envelope?.record ?? null;
@@ -103303,14 +103303,14 @@ function sumCampaignRowsToPeriodKpis(rows) {
103303
103303
  }
103304
103304
  async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
103305
103305
  const absDir = path32.resolve(snapshotDir);
103306
- const metaAccountId = typeof asRecord17(payload.meta)?.accountId === "string" ? asRecord17(payload.meta)?.accountId : void 0;
103306
+ const metaAccountId = typeof asRecord19(payload.meta)?.accountId === "string" ? asRecord19(payload.meta)?.accountId : void 0;
103307
103307
  const manifest = await readManifest(snapshotDir, metaAccountId);
103308
103308
  if (!manifest) {
103309
103309
  throw new Error(`\u672A\u5728 ${absDir} \u627E\u5230 manifest*.json\uFF0C\u8BF7\u5148\u6267\u884C google-analysis --json-out`);
103310
103310
  }
103311
103311
  const accountId = manifest.googleAnalysis?.accountId ?? metaAccountId;
103312
103312
  const dateRange = manifest.googleAnalysis?.dateRange;
103313
- const preferredDateTag = dateTagFromRange(dateRange) ?? dateTagFromMeta(asRecord17(payload.meta) ?? void 0);
103313
+ const preferredDateTag = dateTagFromRange(dateRange) ?? dateTagFromMeta(asRecord19(payload.meta) ?? void 0);
103314
103314
  const sectionMap = /* @__PURE__ */ new Map();
103315
103315
  for (const art of manifest.artifacts ?? []) {
103316
103316
  const data = await loadSectionFile(absDir, art.file);
@@ -103318,8 +103318,8 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
103318
103318
  }
103319
103319
  await recoverMissingReportSections(sectionMap, absDir, accountId, preferredDateTag);
103320
103320
  const overviewRecord = record(sectionMap.get("overview"));
103321
- const currentPeriod = asRecord17(overviewRecord?.currentPeriod);
103322
- const previousPeriod = asRecord17(overviewRecord?.previousPeriod);
103321
+ const currentPeriod = asRecord19(overviewRecord?.currentPeriod);
103322
+ const previousPeriod = asRecord19(overviewRecord?.previousPeriod);
103323
103323
  const meta = { ...payload.meta ?? {} };
103324
103324
  if (!meta.accountId && accountId) meta.accountId = accountId;
103325
103325
  if (!meta.currency) {
@@ -103465,7 +103465,7 @@ function textLen(value) {
103465
103465
  function asArray(value) {
103466
103466
  return Array.isArray(value) ? value : [];
103467
103467
  }
103468
- function asRecord18(value) {
103468
+ function asRecord20(value) {
103469
103469
  if (value && typeof value === "object" && !Array.isArray(value)) {
103470
103470
  return value;
103471
103471
  }
@@ -103479,7 +103479,7 @@ function pushMissing(missing, id, chapter, dimension, hint) {
103479
103479
  }
103480
103480
  function validateOkkiWeeklyReportContent(data) {
103481
103481
  const missing = [];
103482
- const meta = asRecord18(data.meta) ?? {};
103482
+ const meta = asRecord20(data.meta) ?? {};
103483
103483
  if (!textLen(meta.accountId)) {
103484
103484
  pushMissing(
103485
103485
  missing,
@@ -103489,7 +103489,7 @@ function validateOkkiWeeklyReportContent(data) {
103489
103489
  "meta.accountId \u5FC5\u586B\uFF1B\u53EF\u7531 --snapshot-dir \u5408\u5E76 overview/manifest"
103490
103490
  );
103491
103491
  }
103492
- const snapshotSections = asRecord18(data.snapshot?.sections) ?? {};
103492
+ const snapshotSections = asRecord20(data.snapshot?.sections) ?? {};
103493
103493
  const snapshotPresent = {};
103494
103494
  for (const section of OKKI_SNAPSHOT_SECTIONS) {
103495
103495
  const present = snapshotSections[section] === true;
@@ -103504,12 +103504,12 @@ function validateOkkiWeeklyReportContent(data) {
103504
103504
  );
103505
103505
  }
103506
103506
  }
103507
- const narrative = asRecord18(data.narrative) ?? {};
103508
- const sheetAnalysis = asRecord18(narrative.sheetAnalysis) ?? {};
103509
- const review = asRecord18(narrative.review) ?? {};
103507
+ const narrative = asRecord20(data.narrative) ?? {};
103508
+ const sheetAnalysis = asRecord20(narrative.sheetAnalysis) ?? {};
103509
+ const review = asRecord20(narrative.review) ?? {};
103510
103510
  const sheetAnalysisCounts = {};
103511
103511
  for (const key of OKKI_SHEET_KEYS) {
103512
- const block = asRecord18(sheetAnalysis[key]);
103512
+ const block = asRecord20(sheetAnalysis[key]);
103513
103513
  const summary = stringList2(block?.summary);
103514
103514
  const suggestions = stringList2(block?.suggestions);
103515
103515
  sheetAnalysisCounts[key] = { summary: summary.length, suggestions: suggestions.length };
@@ -103535,7 +103535,7 @@ function validateOkkiWeeklyReportContent(data) {
103535
103535
  }
103536
103536
  const reviewFilled = {};
103537
103537
  for (const key of OKKI_REVIEW_KEYS) {
103538
- const block = asRecord18(review[key]);
103538
+ const block = asRecord20(review[key]);
103539
103539
  const overview = textLen(block?.overview);
103540
103540
  const summary = textLen(block?.summary);
103541
103541
  const suggestion = textLen(block?.suggestion);
@@ -103570,7 +103570,7 @@ function validateOkkiWeeklyReportContent(data) {
103570
103570
  }
103571
103571
  }
103572
103572
  const deviceRows2 = Array.isArray(data.tables?.devices) ? data.tables.devices : [];
103573
- const deviceSpend = summarizeOkkiDeviceSpend(deviceRows2.filter((row) => asRecord18(row) !== null));
103573
+ const deviceSpend = summarizeOkkiDeviceSpend(deviceRows2.filter((row) => asRecord20(row) !== null));
103574
103574
  if (deviceSpend.total > 0 && deviceSpend.desktop >= deviceSpend.mobile && narrativeClaimsMobileSpendLeads(collectOkkiNarrativeText(data))) {
103575
103575
  pushMissing(
103576
103576
  missing,
@@ -103659,7 +103659,7 @@ function round25(value) {
103659
103659
  }
103660
103660
  function items2(envelope) {
103661
103661
  if (!envelope || !Array.isArray(envelope.items)) return [];
103662
- return envelope.items.filter((row) => asRecord18(row) !== null);
103662
+ return envelope.items.filter((row) => asRecord20(row) !== null);
103663
103663
  }
103664
103664
  function dateTagFromRange2(dateRange) {
103665
103665
  if (!dateRange || dateRange.mode !== "range") return void 0;
@@ -103703,14 +103703,14 @@ async function loadSectionFile2(snapshotDir, file) {
103703
103703
  }
103704
103704
  async function mergeOkkiSnapshotIntoReport(payload, snapshotDir) {
103705
103705
  const absDir = path33.resolve(snapshotDir);
103706
- const metaAccountId = typeof asRecord18(payload.meta)?.accountId === "string" ? asRecord18(payload.meta)?.accountId : void 0;
103706
+ const metaAccountId = typeof asRecord20(payload.meta)?.accountId === "string" ? asRecord20(payload.meta)?.accountId : void 0;
103707
103707
  const manifest = await readManifest2(absDir, metaAccountId);
103708
103708
  if (!manifest) {
103709
103709
  throw new Error(`\u672A\u5728 ${absDir} \u627E\u5230 manifest*.json\uFF0C\u8BF7\u5148\u6267\u884C google-analysis --json-out`);
103710
103710
  }
103711
103711
  const accountId = manifest.googleAnalysis?.accountId ?? metaAccountId;
103712
103712
  const dateRange = manifest.googleAnalysis?.dateRange;
103713
- const preferredDateTag = dateTagFromRange2(dateRange) ?? dateTagFromMeta2(asRecord18(payload.meta) ?? void 0);
103713
+ const preferredDateTag = dateTagFromRange2(dateRange) ?? dateTagFromMeta2(asRecord20(payload.meta) ?? void 0);
103714
103714
  const sectionMap = /* @__PURE__ */ new Map();
103715
103715
  for (const art of manifest.artifacts ?? []) {
103716
103716
  const data = await loadSectionFile2(absDir, art.file);
@@ -103736,7 +103736,7 @@ async function mergeOkkiSnapshotIntoReport(payload, snapshotDir) {
103736
103736
  snapshotPresent[section] = sectionMap.has(section);
103737
103737
  }
103738
103738
  const overviewRecord = sectionMap.get("overview")?.record ?? null;
103739
- const currentPeriod = asRecord18(overviewRecord?.currentPeriod);
103739
+ const currentPeriod = asRecord20(overviewRecord?.currentPeriod);
103740
103740
  const meta = { ...payload.meta ?? {} };
103741
103741
  if (!meta.accountId && accountId) meta.accountId = accountId;
103742
103742
  if (!meta.currency) {
@@ -103879,18 +103879,18 @@ function prefixLines(items3, firstPrefix) {
103879
103879
  });
103880
103880
  }
103881
103881
  function analysisLines(data, key) {
103882
- const block = asRecord18(asRecord18(data.narrative)?.sheetAnalysis)?.[key];
103883
- const rec = asRecord18(block);
103882
+ const block = asRecord20(asRecord20(data.narrative)?.sheetAnalysis)?.[key];
103883
+ const rec = asRecord20(block);
103884
103884
  return [
103885
103885
  ...prefixLines(stringList2(rec?.summary), "\u603B\u7ED3\uFF1A"),
103886
103886
  ...prefixLines(stringList2(rec?.suggestions), "\u5EFA\u8BAE\uFF1A")
103887
103887
  ];
103888
103888
  }
103889
103889
  function reviewLines(data) {
103890
- const review = asRecord18(asRecord18(data.narrative)?.review) ?? {};
103890
+ const review = asRecord20(asRecord20(data.narrative)?.review) ?? {};
103891
103891
  const lines = [];
103892
103892
  OKKI_REVIEW_KEYS.forEach((key, idx) => {
103893
- const block = asRecord18(review[key]) ?? {};
103893
+ const block = asRecord20(review[key]) ?? {};
103894
103894
  lines.push(`${idx + 1}\u3001${REVIEW_LABELS2[key]}\uFF1A${str(block.overview, "")}`);
103895
103895
  lines.push(` \u603B\u7ED3\uFF1A${str(block.summary, "")}`);
103896
103896
  lines.push(` \u5EFA\u8BAE\uFF1A${str(block.suggestion, "")}`);
@@ -104022,7 +104022,7 @@ function geoRows(data) {
104022
104022
  });
104023
104023
  }
104024
104024
  function buildOkkiWeeklySheetDrafts(data) {
104025
- const meta = asRecord18(data.meta) ?? {};
104025
+ const meta = asRecord20(data.meta) ?? {};
104026
104026
  const period = formatOkkiZhDateRange(str(meta.startDate, ""), str(meta.endDate, ""));
104027
104027
  const campaigns = campaignRows(data);
104028
104028
  const drafts = {
@@ -104283,7 +104283,7 @@ function textLen2(value) {
104283
104283
  function asArray2(value) {
104284
104284
  return Array.isArray(value) ? value : [];
104285
104285
  }
104286
- function asRecord19(value) {
104286
+ function asRecord21(value) {
104287
104287
  if (value && typeof value === "object" && !Array.isArray(value)) {
104288
104288
  return value;
104289
104289
  }
@@ -104294,9 +104294,9 @@ function pushMissing2(missing, id, chapter, dimension, hint) {
104294
104294
  }
104295
104295
  function validateGooglePeriodReportContent(data) {
104296
104296
  const missing = [];
104297
- const meta = asRecord19(data.meta) ?? {};
104298
- const narrative = asRecord19(data.narrative) ?? {};
104299
- const sections = asRecord19(narrative.sections) ?? {};
104297
+ const meta = asRecord21(data.meta) ?? {};
104298
+ const narrative = asRecord21(data.narrative) ?? {};
104299
+ const sections = asRecord21(narrative.sections) ?? {};
104300
104300
  if (!textLen2(meta.accountId)) {
104301
104301
  pushMissing2(
104302
104302
  missing,
@@ -104316,7 +104316,7 @@ function validateGooglePeriodReportContent(data) {
104316
104316
  "\u22651 \u6BB5\u6267\u884C\u6458\u8981\uFF0C\u6982\u8FF0\u672C\u671F\u6D88\u8017/\u8F6C\u5316/CTR/CPA \u8D70\u52BF"
104317
104317
  );
104318
104318
  }
104319
- const kpis = asRecord19(data.kpis);
104319
+ const kpis = asRecord21(data.kpis);
104320
104320
  const hasCoreKpi = ["cost", "impressions", "clicks"].some(
104321
104321
  (key) => Number.isFinite(Number(kpis?.[key]))
104322
104322
  );
@@ -104332,7 +104332,7 @@ function validateGooglePeriodReportContent(data) {
104332
104332
  const sectionAnalysisCounts = {};
104333
104333
  const sectionSuggestionCounts = {};
104334
104334
  for (const key of SECTION_KEYS) {
104335
- const section = asRecord19(sections[key]);
104335
+ const section = asRecord21(sections[key]);
104336
104336
  const analysis = asArray2(section?.analysis).filter((s) => textLen2(s) > 0);
104337
104337
  const suggestions = asArray2(section?.suggestions).filter((s) => textLen2(s) > 0);
104338
104338
  sectionAnalysisCounts[key] = analysis.length;
@@ -104358,7 +104358,7 @@ function validateGooglePeriodReportContent(data) {
104358
104358
  }
104359
104359
  const recommendations = asArray2(narrative.recommendations).filter((r) => {
104360
104360
  if (typeof r === "string") return textLen2(r) > 0;
104361
- const rec = asRecord19(r);
104361
+ const rec = asRecord21(r);
104362
104362
  return textLen2(rec?.content) > 0;
104363
104363
  });
104364
104364
  if (recommendations.length < 3) {
@@ -104447,7 +104447,7 @@ async function readJsonFile3(filePath) {
104447
104447
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
104448
104448
  }
104449
104449
  }
104450
- function asRecord20(value) {
104450
+ function asRecord22(value) {
104451
104451
  if (value && typeof value === "object" && !Array.isArray(value)) {
104452
104452
  return value;
104453
104453
  }
@@ -104462,7 +104462,7 @@ function injectReportData2(html, payload) {
104462
104462
  }
104463
104463
  async function runGoogleAnalysisRender(opts) {
104464
104464
  const dataPath = path35.resolve(opts.dataFile);
104465
- let data = asRecord20(await readJsonFile3(dataPath));
104465
+ let data = asRecord22(await readJsonFile3(dataPath));
104466
104466
  if (opts.snapshotDir?.trim()) {
104467
104467
  data = await mergeGoogleAnalysisSnapshotIntoReport(data, path35.resolve(opts.snapshotDir));
104468
104468
  }
@@ -133404,7 +133404,8 @@ function resolveSkillTemplatePath2(basename13) {
133404
133404
  const candidates = [
133405
133405
  path22.join(dir, "skill", "report-templates", basename13),
133406
133406
  path22.join(dir, "skill", "siluzan-ads", "report-templates", basename13),
133407
- path22.join(dir, "..", "..", "assets", "siluzan-ads", "report-templates", basename13)
133407
+ path22.join(dir, "..", "..", "assets", "siluzan-ads", "report-templates", basename13),
133408
+ path22.join(dir, "..", "..", "..", "assets", "siluzan-ads", "report-templates", basename13)
133408
133409
  ];
133409
133410
  for (const p of candidates) {
133410
133411
  if (fs17.existsSync(p)) return p;
@@ -133427,7 +133428,7 @@ function buildGoogleAdsDiagnosisCollectAgentHint(snapDir) {
133427
133428
  "Google Ads \u8BCA\u65AD collect \u5DF2\u5B8C\u6210\uFF08\u4EC5\u4E8B\u5B9E\u6570\u636E\uFF0C\u4E0D\u542B\u5EFA\u8BAE\u6027\u6587\u6848\uFF09\u3002",
133428
133429
  `1) Read ${dir}/${GOOGLE_ADS_DIAGNOSIS_DIGEST_BASENAME}\uFF1A\u5404 section \u7ED3\u6784\u3001\u884C\u6570\u3001\u5F85\u586B\u5B57\u6BB5\u6E05\u5355\u90FD\u5728\u91CC\u9762\uFF1B`,
133429
133430
  `2) ${dir}/${GOOGLE_ADS_DIAGNOSIS_REPORT_BASENAME} \u5DF2\u662F\u7EC8\u7A3F\u9AA8\u67B6\uFF08items \u4E8B\u5B9E\u884C\u5DF2\u586B\u597D\u3001\u53D9\u4E8B\u5B57\u6BB5\u7559\u7A7A\uFF09\uFF0C\u76F4\u63A5\u5728\u5B83\u4E0A\u9762\u586B\u7A7A\uFF1B`,
133430
- "3) Read references/report-templates/google-ads-diagnosis.md\uFF0C\u64B0\u5199\u5168\u90E8 analysis/suggestions\u3001diagnosisOverview\u3001summary\u3001accountInfo.businessModel/industry\u3001budgetCompetitiveness[].strategy\u3001newFeatures[].optimizerRecommendation\u3001adCreativeOptimization.items[].suggestion \u7B49\uFF1B",
133431
+ "3) Read references/report-templates/google-ads-diagnosis.md\uFF0C\u64B0\u5199\u5168\u90E8 analysis/suggestions\u3001diagnosisOverview.advantages/disadvantages\uFF08\u6BCF\u6761 {title, description}\uFF0C\u7981\u6B62\u7EAF\u5B57\u7B26\u4E32\uFF09\u3001summary\u3001accountInfo.businessModel/industry\u3001budgetCompetitiveness[].strategy\u3001newFeatures[].optimizerRecommendation\u3001adCreativeOptimization.items[].suggestion \u7B49\uFF1B",
133431
133432
  `4) siluzan-tso google-ads-diagnosis render --data ${dir}/${GOOGLE_ADS_DIAGNOSIS_REPORT_BASENAME} --out ${dir}/google-ads-diagnosis-report.html\uFF08\u9ED8\u8BA4\u540C\u76EE\u5F55 collect \u81EA\u52A8\u6062\u590D\u88AB\u6539\u574F\u7684 items\uFF09\u3002`,
133432
133433
  `\u7981\u6B62\u7528 node -e \u9010\u6BB5 dump ${GOOGLE_ADS_DIAGNOSIS_COLLECT_BASENAME} \u6765\u6478\u7ED3\u6784\u2014\u2014\u7ED3\u6784\u770B digest\u3001\u6570\u5B57\u770B\u9AA8\u67B6\u6587\u4EF6\u5373\u53EF\u3002`,
133433
133434
  "\u7981\u6B62\u5199\u5165/\u8986\u76D6 campaigns/geographic/keywords \u7684 items \u884C\uFF0C\u53EA\u586B analysis/suggestions\u3002",
@@ -133494,12 +133495,148 @@ function buildGoogleAdsDiagnosisAgentBrief(input) {
133494
133495
  },
133495
133496
  agentDeliverable: {
133496
133497
  outputFile: "google-ads-diagnosis.json",
133497
- structure: "\u4E0E reportData \u540C\u7ED3\u6784\u7684 sectionData\uFF1B\u987B\u586B diagnosisOverview\u3001metrics.analysis/suggestions\u3001\u5404\u6A21\u5757 analysis/suggestions\u3001summary.keyIssues\u3001summary.optimizationRoadmap[]\uFF08priority/focusArea/actionItems/expectedOutcome\uFF09\u3001budgetCompetitiveness[].strategy\u3001newFeatures[].optimizerRecommendation \u7B49",
133498
+ structure: "\u4E0E reportData \u540C\u7ED3\u6784\u7684 sectionData\uFF1B\u987B\u586B diagnosisOverview.advantages/disadvantages\uFF08\u6BCF\u6761 {title, description}\uFF09\u3001metrics.analysis/suggestions\u3001\u5404\u6A21\u5757 analysis/suggestions\u3001summary.keyIssues\u3001summary.optimizationRoadmap[]\uFF08priority/focusArea/actionItems/expectedOutcome\uFF09\u3001budgetCompetitiveness[].strategy\u3001newFeatures[].optimizerRecommendation \u7B49",
133498
133499
  thenRun: "siluzan-tso google-ads-diagnosis render --data ./<snap>/google-ads-diagnosis.json --out ./<snap>/google-ads-diagnosis-report.html"
133499
133500
  }
133500
133501
  };
133501
133502
  }
133502
133503
 
133504
+ // src/commands/google-ads-diagnosis/snapshot-io.ts
133505
+ init_google_analysis_snapshot();
133506
+ import fs18 from "fs";
133507
+ import path23 from "path";
133508
+ function dateRangeManifest(start, end) {
133509
+ if (start && end) return { mode: "range", start, end };
133510
+ return null;
133511
+ }
133512
+ function findSectionSnapshotFile(snapDir, section, accountId, start, end) {
133513
+ const exactName = googleAnalysisSectionFilename(
133514
+ section,
133515
+ accountId,
133516
+ dateRangeManifest(start, end)
133517
+ );
133518
+ const exactPath = path23.join(snapDir, exactName);
133519
+ if (fs18.existsSync(exactPath)) return exactPath;
133520
+ if (start && end) return void 0;
133521
+ const files = fs18.readdirSync(snapDir);
133522
+ return files.filter((f) => f.startsWith(`${section}-${accountId}`) && f.endsWith(".json")).sort().map((f) => path23.join(snapDir, f)).at(-1);
133523
+ }
133524
+ function loadSectionSnapshot(snapDir, section, accountId, start, end) {
133525
+ const file = findSectionSnapshotFile(snapDir, section, accountId, start, end);
133526
+ if (!file || !fs18.existsSync(file)) return null;
133527
+ try {
133528
+ return JSON.parse(fs18.readFileSync(file, "utf8"));
133529
+ } catch {
133530
+ return null;
133531
+ }
133532
+ }
133533
+ function sectionItems(env) {
133534
+ if (!env?.items || !Array.isArray(env.items)) return [];
133535
+ return env.items.filter(
133536
+ (x) => !!x && typeof x === "object" && !Array.isArray(x)
133537
+ );
133538
+ }
133539
+ function sectionRecord(env) {
133540
+ const r = env?.record;
133541
+ if (r && typeof r === "object" && !Array.isArray(r)) return r;
133542
+ return null;
133543
+ }
133544
+
133545
+ // src/commands/google-ads-diagnosis/gold-text-ads.ts
133546
+ function asRecord7(value) {
133547
+ if (value && typeof value === "object" && !Array.isArray(value)) {
133548
+ return value;
133549
+ }
133550
+ return null;
133551
+ }
133552
+ function hasSearchTextAds(gold) {
133553
+ return gold.expandedTextAdQualified === true || gold.textAdQualified === true || gold.responsiveSearchAdQualified === true;
133554
+ }
133555
+ function applyTextAdQualification(gold) {
133556
+ if (!hasSearchTextAds(gold) || gold.expandedTextAdQualified === true) return gold;
133557
+ return { ...gold, expandedTextAdQualified: true };
133558
+ }
133559
+ var DISPLAY_PAUSED_SUGGESTION = "\u5DF2\u6709\u81EA\u9002\u5E94\u5C55\u793A\u5E7F\u544A\uFF0C\u6240\u5728\u5C55\u793A\u7CFB\u5217\u5DF2\u6682\u505C\uFF0C\u672C\u671F\u65E0\u6D88\u8017";
133560
+ function statusOf(row) {
133561
+ return String(row.statusV2 ?? row.status ?? "").toUpperCase();
133562
+ }
133563
+ function isEnabled(row) {
133564
+ return statusOf(row) === "ENABLED";
133565
+ }
133566
+ function hasEnabledExtension(rows, type) {
133567
+ return rows.some((row) => String(row.typeV2 ?? "") === type && isEnabled(row));
133568
+ }
133569
+ function hasGa4Link(rows) {
133570
+ return rows.some((row) => {
133571
+ if (!isEnabled(row)) return false;
133572
+ const type = String(row.type ?? "");
133573
+ const name2 = String(row.name ?? "");
133574
+ return type.startsWith("GoogleAnalytics") || /GA4/i.test(name2);
133575
+ });
133576
+ }
133577
+ function hasAudienceSetup(rows) {
133578
+ return rows.some((row) => {
133579
+ const type = String(row.criterionType ?? "");
133580
+ return type === "UserList" || type === "CustomAudience" || type === "UserInterest" || type === "CustomIntent" || type === "CombinedAudience" || type === "CustomAffinity" || Number(row.impressions) > 0;
133581
+ });
133582
+ }
133583
+ function displayAds(rows) {
133584
+ return rows.filter((row) => String(row.typeV2 ?? "") === "RESPONSIVE_DISPLAY_AD");
133585
+ }
133586
+ function displayIsServing(rows) {
133587
+ return rows.some(
133588
+ (row) => isEnabled(row) && statusOf({ statusV2: row.parentCampaignStatusV2 }) === "ENABLED"
133589
+ );
133590
+ }
133591
+ function reconcileGoldAccount(gold, evidence = {}) {
133592
+ const next = { ...applyTextAdQualification(gold) };
133593
+ const conversions = evidence.conversionActions ?? [];
133594
+ const extensions = evidence.extensions ?? [];
133595
+ const audiences = evidence.audiences ?? [];
133596
+ const ads = evidence.ads ?? [];
133597
+ if (hasGa4Link(conversions)) next.gaConfigured = true;
133598
+ if (hasEnabledExtension(extensions, "CALLOUT")) next.adsCalloutExtensionQualified = true;
133599
+ if (hasEnabledExtension(extensions, "STRUCTURED_SNIPPET")) {
133600
+ next.adsStructuredSnippetExtensionQualified = true;
133601
+ }
133602
+ if (hasAudienceSetup(audiences)) next.audienceQualified = true;
133603
+ const responsiveDisplay = displayAds(ads);
133604
+ if (displayIsServing(responsiveDisplay)) {
133605
+ next.multiAssetResponsiveDisplayAdQualified = true;
133606
+ } else if (responsiveDisplay.length > 0 && next.multiAssetResponsiveDisplayAdQualified !== true) {
133607
+ const suggestions = asRecord7(next.goldItemSuggestions) ?? {};
133608
+ next.goldItemSuggestions = {
133609
+ ...suggestions,
133610
+ \u81EA\u9002\u5E94\u5C55\u793A\u5E7F\u544A: DISPLAY_PAUSED_SUGGESTION
133611
+ };
133612
+ }
133613
+ return next;
133614
+ }
133615
+ function parsePeriod(period) {
133616
+ const matched = period.match(/(\d{4}-\d{2}-\d{2})\D+(\d{4}-\d{2}-\d{2})/);
133617
+ if (!matched) return {};
133618
+ return { start: matched[1], end: matched[2] };
133619
+ }
133620
+ function reconcileGoldAccountInReport(data, snapDir) {
133621
+ const gold = asRecord7(data.goldAccount) ?? {};
133622
+ const account = asRecord7(data.accountInfo);
133623
+ const accountId = String(account?.companyId ?? "").replace(/\D/g, "");
133624
+ const { start, end } = parsePeriod(String(account?.period ?? ""));
133625
+ const evidence = {};
133626
+ if (snapDir && accountId) {
133627
+ evidence.conversionActions = sectionItems(
133628
+ loadSectionSnapshot(snapDir, "conversion-actions", accountId, start, end)
133629
+ );
133630
+ evidence.extensions = sectionItems(
133631
+ loadSectionSnapshot(snapDir, "extensions", accountId, start, end)
133632
+ );
133633
+ evidence.audiences = sectionItems(loadSectionSnapshot(snapDir, "audience", accountId, start, end));
133634
+ evidence.ads = sectionItems(loadSectionSnapshot(snapDir, "ads", accountId, start, end));
133635
+ }
133636
+ const next = reconcileGoldAccount(gold, evidence);
133637
+ return { ...data, goldAccount: next };
133638
+ }
133639
+
133503
133640
  // src/commands/google-ads-diagnosis/default-section-data.ts
133504
133641
  function createDefaultDiagnosisReportData() {
133505
133642
  return {
@@ -133649,47 +133786,6 @@ function emptySummary() {
133649
133786
  return { keyIssues: [], optimizationRoadmap: [] };
133650
133787
  }
133651
133788
 
133652
- // src/commands/google-ads-diagnosis/snapshot-io.ts
133653
- init_google_analysis_snapshot();
133654
- import fs18 from "fs";
133655
- import path23 from "path";
133656
- function dateRangeManifest(start, end) {
133657
- if (start && end) return { mode: "range", start, end };
133658
- return null;
133659
- }
133660
- function findSectionSnapshotFile(snapDir, section, accountId, start, end) {
133661
- const exactName = googleAnalysisSectionFilename(
133662
- section,
133663
- accountId,
133664
- dateRangeManifest(start, end)
133665
- );
133666
- const exactPath = path23.join(snapDir, exactName);
133667
- if (fs18.existsSync(exactPath)) return exactPath;
133668
- if (start && end) return void 0;
133669
- const files = fs18.readdirSync(snapDir);
133670
- return files.filter((f) => f.startsWith(`${section}-${accountId}`) && f.endsWith(".json")).sort().map((f) => path23.join(snapDir, f)).at(-1);
133671
- }
133672
- function loadSectionSnapshot(snapDir, section, accountId, start, end) {
133673
- const file = findSectionSnapshotFile(snapDir, section, accountId, start, end);
133674
- if (!file || !fs18.existsSync(file)) return null;
133675
- try {
133676
- return JSON.parse(fs18.readFileSync(file, "utf8"));
133677
- } catch {
133678
- return null;
133679
- }
133680
- }
133681
- function sectionItems(env) {
133682
- if (!env?.items || !Array.isArray(env.items)) return [];
133683
- return env.items.filter(
133684
- (x) => !!x && typeof x === "object" && !Array.isArray(x)
133685
- );
133686
- }
133687
- function sectionRecord(env) {
133688
- const r = env?.record;
133689
- if (r && typeof r === "object" && !Array.isArray(r)) return r;
133690
- return null;
133691
- }
133692
-
133693
133789
  // src/commands/google-ads-diagnosis/build-report-data.ts
133694
133790
  function num(value) {
133695
133791
  const n = Number(value);
@@ -134033,8 +134129,9 @@ function buildGoogleAdsDiagnosisCollectPayload(opts) {
134033
134129
  const resourceRecord = sectionRecord(
134034
134130
  loadSectionSnapshot(snapDir, "resource-counts", accountId, start, end)
134035
134131
  );
134036
- const goldRecord = sectionRecord(loadSectionSnapshot(snapDir, "gold-account", accountId, start, end)) ?? {};
134037
- delete goldRecord.adsNegativeQualified;
134132
+ const goldRaw = sectionRecord(loadSectionSnapshot(snapDir, "gold-account", accountId, start, end)) ?? {};
134133
+ delete goldRaw.adsNegativeQualified;
134134
+ let goldRecord = goldRaw;
134038
134135
  const campaignCurrent = sectionItems(
134039
134136
  loadSectionSnapshot(snapDir, "campaigns", accountId, start, end)
134040
134137
  );
@@ -134153,7 +134250,6 @@ function buildGoogleAdsDiagnosisCollectPayload(opts) {
134153
134250
  items: conversionCostItems,
134154
134251
  ...emptyModuleNarrative()
134155
134252
  };
134156
- data.goldAccount = goldRecord;
134157
134253
  data.budgetCompetitiveness = buildBudgetCompetitiveness(overviewRecord, dimensionRecord);
134158
134254
  data.diagnosisOverview = emptyDiagnosisOverview();
134159
134255
  const geoTargeting = geoCurrent.map(
@@ -134178,6 +134274,16 @@ function buildGoogleAdsDiagnosisCollectPayload(opts) {
134178
134274
  const audienceRows = sectionItems(
134179
134275
  loadSectionSnapshot(snapDir, "audience", accountId, start, end)
134180
134276
  );
134277
+ const extensionRows = sectionItems(
134278
+ loadSectionSnapshot(snapDir, "extensions", accountId, start, end)
134279
+ );
134280
+ goldRecord = reconcileGoldAccount(goldRaw, {
134281
+ conversionActions: conversionRows,
134282
+ extensions: extensionRows,
134283
+ audiences: audienceRows,
134284
+ ads: adRows
134285
+ });
134286
+ data.goldAccount = goldRecord;
134181
134287
  data.fullAudience = {
134182
134288
  items: audienceRows.map(
134183
134289
  (row) => toTargetingItem(row, "audience", String(row.audienceName ?? row.audience ?? "\u53D7\u4F17"))
@@ -134284,14 +134390,14 @@ function buildGoogleAdsDiagnosisCollectPayload(opts) {
134284
134390
  }
134285
134391
 
134286
134392
  // src/commands/google-ads-diagnosis/collect-digest.ts
134287
- function asRecord7(value) {
134393
+ function asRecord8(value) {
134288
134394
  if (value && typeof value === "object" && !Array.isArray(value)) {
134289
134395
  return value;
134290
134396
  }
134291
134397
  return null;
134292
134398
  }
134293
134399
  function fieldsOfFirstRow(rows) {
134294
- const first = asRecord7(rows[0]);
134400
+ const first = asRecord8(rows[0]);
134295
134401
  return first ? Object.keys(first) : [];
134296
134402
  }
134297
134403
  function describeSectionShapes(reportData) {
@@ -134301,7 +134407,7 @@ function describeSectionShapes(reportData) {
134301
134407
  if (Array.isArray(value)) {
134302
134408
  return { section, itemCount: value.length, fields: fieldsOfFirstRow(value), needsNarrative };
134303
134409
  }
134304
- const record2 = asRecord7(value);
134410
+ const record2 = asRecord8(value);
134305
134411
  if (!record2) {
134306
134412
  return { section, itemCount: null, fields: [], needsNarrative };
134307
134413
  }
@@ -134319,7 +134425,7 @@ function describeSectionShapes(reportData) {
134319
134425
  function narrativeChecklist(shapes) {
134320
134426
  const lines = [
134321
134427
  "- `accountInfo.businessModel`\u3001`accountInfo.industry`",
134322
- "- `diagnosisOverview.advantages`\u3001`diagnosisOverview.disadvantages`",
134428
+ '- `diagnosisOverview.advantages`\u3001`diagnosisOverview.disadvantages`\uFF1A\u6BCF\u6761 `{"title":"\u77ED\u6807\u9898","description":"\u4F9D\u636E"}`\u3002\u7EAF\u5B57\u7B26\u4E32\u4F1A\u5728 render \u65F6\u6309\u7B2C\u4E00\u4E2A\u300C\uFF1A\u300D\u62C6\u5F00\uFF1B\u7F3A title \u6216 description \u5219\u62D2\u7EDD\u51FA HTML\uFF08\u5426\u5219\u9875\u9762\u663E\u793A\u300C\u672A\u586B\u5199\u300D\uFF09',
134323
134429
  "- `summary.keyIssues`\u3001`summary.optimizationRoadmap`"
134324
134430
  ];
134325
134431
  for (const shape of shapes) {
@@ -134370,21 +134476,21 @@ function buildCollectDigest(reportData, meta) {
134370
134476
  }
134371
134477
 
134372
134478
  // src/commands/google-ads-diagnosis/collect-integrity.ts
134373
- function asRecord8(value) {
134479
+ function asRecord9(value) {
134374
134480
  if (value && typeof value === "object" && !Array.isArray(value)) {
134375
134481
  return value;
134376
134482
  }
134377
134483
  return null;
134378
134484
  }
134379
134485
  function itemCount(block) {
134380
- const items3 = asRecord8(block)?.items;
134486
+ const items3 = asRecord9(block)?.items;
134381
134487
  return Array.isArray(items3) ? items3.length : 0;
134382
134488
  }
134383
134489
  function getCollectIntegrityWarnings(reportData) {
134384
134490
  const warnings = [];
134385
134491
  const kwItems = itemCount(reportData.keywords);
134386
134492
  const fullKwItems = itemCount(reportData.fullKeywords);
134387
- const keywordCount = Number(asRecord8(reportData.structure)?.keywordCount ?? 0);
134493
+ const keywordCount = Number(asRecord9(reportData.structure)?.keywordCount ?? 0);
134388
134494
  if (kwItems === 0 && fullKwItems > 0) {
134389
134495
  warnings.push(
134390
134496
  `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`
@@ -134395,7 +134501,7 @@ function getCollectIntegrityWarnings(reportData) {
134395
134501
  );
134396
134502
  }
134397
134503
  const campaignItems = itemCount(reportData.campaigns);
134398
- const campaignCount = Number(asRecord8(reportData.structure)?.campaignCount ?? 0);
134504
+ const campaignCount = Number(asRecord9(reportData.structure)?.campaignCount ?? 0);
134399
134505
  if (campaignItems === 0 && campaignCount > 0) {
134400
134506
  warnings.push(
134401
134507
  `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`
@@ -134453,7 +134559,7 @@ function invokeGoogleAnalysisCli(opts) {
134453
134559
 
134454
134560
  // src/commands/google-ads-diagnosis/write-draft.ts
134455
134561
  import fs20 from "fs/promises";
134456
- function asRecord9(value) {
134562
+ function asRecord10(value) {
134457
134563
  if (value && typeof value === "object" && !Array.isArray(value)) {
134458
134564
  return value;
134459
134565
  }
@@ -134462,7 +134568,7 @@ function asRecord9(value) {
134462
134568
  function valueAtPath(data, keys) {
134463
134569
  let cursor = data;
134464
134570
  for (const key of keys) {
134465
- const record2 = asRecord9(cursor);
134571
+ const record2 = asRecord10(cursor);
134466
134572
  if (!record2) return void 0;
134467
134573
  cursor = record2[key];
134468
134574
  }
@@ -134481,7 +134587,7 @@ function hasAgentNarrative(data) {
134481
134587
  async function writeDiagnosisDraft(opts) {
134482
134588
  try {
134483
134589
  const existing = JSON.parse(await fs20.readFile(opts.draftPath, "utf8"));
134484
- const record2 = asRecord9(existing);
134590
+ const record2 = asRecord10(existing);
134485
134591
  if (record2 && hasAgentNarrative(record2)) return "skipped-existing-narrative";
134486
134592
  } catch {
134487
134593
  }
@@ -134671,7 +134777,7 @@ import fs22 from "fs/promises";
134671
134777
  import path26 from "path";
134672
134778
 
134673
134779
  // src/commands/google-ads-diagnosis/report-content.ts
134674
- function asRecord10(value) {
134780
+ function asRecord11(value) {
134675
134781
  if (value && typeof value === "object" && !Array.isArray(value)) {
134676
134782
  return value;
134677
134783
  }
@@ -134680,7 +134786,7 @@ function asRecord10(value) {
134680
134786
  function getNestedValue(root, path55) {
134681
134787
  let cur = root;
134682
134788
  for (const key of path55) {
134683
- const rec = asRecord10(cur);
134789
+ const rec = asRecord11(cur);
134684
134790
  if (!rec) return void 0;
134685
134791
  cur = rec[key];
134686
134792
  }
@@ -134697,7 +134803,7 @@ function validateBudgetCompetitivenessStrategies(data) {
134697
134803
  }
134698
134804
  const warnings = [];
134699
134805
  for (let i = 0; i < items3.length; i++) {
134700
- const row = asRecord10(items3[i]);
134806
+ const row = asRecord11(items3[i]);
134701
134807
  const name2 = String(row?.name ?? row?.metric ?? i);
134702
134808
  if (!hasNarrativeContent(row?.strategy)) {
134703
134809
  warnings.push(`budgetCompetitiveness[${name2}].strategy \u4E3A\u7A7A\uFF08\u987B\u7531 Agent \u586B\u5199\uFF09`);
@@ -134706,13 +134812,13 @@ function validateBudgetCompetitivenessStrategies(data) {
134706
134812
  return warnings;
134707
134813
  }
134708
134814
  function validateNewFeatureRecommendations(data) {
134709
- const nf = asRecord10(data.newFeatures);
134815
+ const nf = asRecord11(data.newFeatures);
134710
134816
  if (!nf) return [];
134711
134817
  const items3 = nf.items;
134712
134818
  if (!Array.isArray(items3)) return [];
134713
134819
  const warnings = [];
134714
134820
  for (let i = 0; i < items3.length; i++) {
134715
- const row = asRecord10(items3[i]);
134821
+ const row = asRecord11(items3[i]);
134716
134822
  const name2 = String(row?.strategyName ?? row?.feature ?? row?.strategy ?? i);
134717
134823
  if (!hasNarrativeContent(row?.optimizerRecommendation)) {
134718
134824
  warnings.push(`newFeatures.items[${name2}].optimizerRecommendation \u4E3A\u7A7A\uFF08\u987B\u7531 Agent \u586B\u5199\uFF09`);
@@ -134720,14 +134826,34 @@ function validateNewFeatureRecommendations(data) {
134720
134826
  }
134721
134827
  return warnings;
134722
134828
  }
134829
+ function validateDiagnosisOverviewItems(data) {
134830
+ const overview = asRecord11(data.diagnosisOverview);
134831
+ if (!overview) return [];
134832
+ const warnings = [];
134833
+ for (const key of ["advantages", "disadvantages"]) {
134834
+ const items3 = overview[key];
134835
+ if (!Array.isArray(items3)) continue;
134836
+ items3.forEach((item, index) => {
134837
+ const row = asRecord11(item);
134838
+ const title = String(row?.title ?? "").trim();
134839
+ const description = String(row?.description ?? "").trim();
134840
+ if (!title || !description) {
134841
+ warnings.push(
134842
+ `diagnosisOverview.${key}[${index}] \u987B\u542B\u975E\u7A7A title \u4E0E description\uFF08\u6A21\u677F\u53EA\u8BFB\u8FD9\u4E24\u4E2A\u5B57\u6BB5\uFF0C\u7F3A\u4E86\u4F1A\u663E\u793A\u300C\u672A\u586B\u5199\u300D\uFF09\u3002\u5199\u6210 {"title":"\u77ED\u6807\u9898","description":"\u4F9D\u636E"}\uFF0C\u6216\u300C\u6807\u9898\uFF1A\u8BF4\u660E\u300D`
134843
+ );
134844
+ }
134845
+ });
134846
+ }
134847
+ return warnings;
134848
+ }
134723
134849
  function validateAdCreativeItemSuggestions(data) {
134724
- const creative = asRecord10(data.adCreativeOptimization);
134850
+ const creative = asRecord11(data.adCreativeOptimization);
134725
134851
  if (!creative) return [];
134726
134852
  const items3 = creative.items;
134727
134853
  if (!Array.isArray(items3) || items3.length === 0) return [];
134728
134854
  const warnings = [];
134729
134855
  for (let i = 0; i < items3.length; i++) {
134730
- const row = asRecord10(items3[i]);
134856
+ const row = asRecord11(items3[i]);
134731
134857
  const title = String(row?.adTitle ?? i);
134732
134858
  if (!hasNarrativeContent(row?.suggestion ?? row?.suggestions)) {
134733
134859
  warnings.push(`adCreativeOptimization.items[${title}].suggestion \u4E3A\u7A7A\uFF08\u987B\u7531 Agent \u586B\u5199\uFF09`);
@@ -134738,7 +134864,7 @@ function validateAdCreativeItemSuggestions(data) {
134738
134864
  function validateGoogleAdsDiagnosisContent(data) {
134739
134865
  const missingKeys = GOOGLE_ADS_DIAGNOSIS_TOP_LEVEL_KEYS.filter((key) => data[key] === void 0);
134740
134866
  const warnings = [];
134741
- const accountInfo = asRecord10(data.accountInfo);
134867
+ const accountInfo = asRecord11(data.accountInfo);
134742
134868
  if (accountInfo && !accountInfo.companyName && !accountInfo.period) {
134743
134869
  warnings.push("accountInfo \u7F3A\u5C11 companyName \u4E0E period\uFF0C\u9875\u7709\u53EF\u80FD\u4E3A\u7A7A");
134744
134870
  }
@@ -134752,6 +134878,7 @@ function validateGoogleAdsDiagnosisContent(data) {
134752
134878
  }
134753
134879
  }
134754
134880
  warnings.push(
134881
+ ...validateDiagnosisOverviewItems(data),
134755
134882
  ...validateBudgetCompetitivenessStrategies(data),
134756
134883
  ...validateNewFeatureRecommendations(data),
134757
134884
  ...validateAdCreativeItemSuggestions(data)
@@ -134786,7 +134913,7 @@ var GOOGLE_ADS_DIAGNOSIS_RESTORE_ITEM_MODULES = [
134786
134913
  GOOGLE_ADS_DIAGNOSIS_BIDDING_STRATEGY_MODULE,
134787
134914
  GOOGLE_ADS_DIAGNOSIS_NEW_FEATURES_MODULE
134788
134915
  ];
134789
- function asRecord11(value) {
134916
+ function asRecord12(value) {
134790
134917
  if (value && typeof value === "object" && !Array.isArray(value)) {
134791
134918
  return value;
134792
134919
  }
@@ -134797,7 +134924,7 @@ function isValidRateChange(value) {
134797
134924
  return typeof value === "number" && Number.isFinite(value);
134798
134925
  }
134799
134926
  function isComparisonTableRowValid(row) {
134800
- const rec = asRecord11(row);
134927
+ const rec = asRecord12(row);
134801
134928
  if (!rec) return false;
134802
134929
  if (!String(rec.title ?? "").trim()) return false;
134803
134930
  if (!Number.isFinite(Number(rec.currentCost))) return false;
@@ -134809,12 +134936,12 @@ function isComparisonTableRowValid(row) {
134809
134936
  return true;
134810
134937
  }
134811
134938
  function isNewFeatureRowValid(row) {
134812
- const rec = asRecord11(row);
134939
+ const rec = asRecord12(row);
134813
134940
  if (!rec) return false;
134814
134941
  return Boolean(String(rec.strategyName ?? rec.feature ?? rec.strategy ?? "").trim());
134815
134942
  }
134816
134943
  function isBiddingStrategyRowValid(row) {
134817
- const rec = asRecord11(row);
134944
+ const rec = asRecord12(row);
134818
134945
  if (!rec) return false;
134819
134946
  if (!String(rec.campaignName ?? "").trim()) return false;
134820
134947
  if (!Number.isFinite(Number(rec.duration)) || Number(rec.duration) <= 0) return false;
@@ -134852,11 +134979,11 @@ function getFactItemsErrors(data) {
134852
134979
  for (const mod of GOOGLE_ADS_DIAGNOSIS_RESTORE_ITEM_MODULES) {
134853
134980
  const validator = MODULE_ITEM_VALIDATORS[mod];
134854
134981
  const hint = MODULE_ITEM_ERROR_HINT[mod];
134855
- const block = asRecord11(data[mod]);
134982
+ const block = asRecord12(data[mod]);
134856
134983
  const items3 = block?.items;
134857
134984
  if (!Array.isArray(items3) || items3.length === 0) {
134858
134985
  if (mod === "keywords") {
134859
- const fullKw = asRecord11(data.fullKeywords)?.items;
134986
+ const fullKw = asRecord12(data.fullKeywords)?.items;
134860
134987
  if (Array.isArray(fullKw) && fullKw.length > 0) {
134861
134988
  errors.push(
134862
134989
  "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"
@@ -134881,15 +135008,15 @@ var LANDING_PAGE_SPEED_KEYS = [
134881
135008
  "speedIndex"
134882
135009
  ];
134883
135010
  function isLandingPageSpeedValid(value) {
134884
- const rec = asRecord11(value);
135011
+ const rec = asRecord12(value);
134885
135012
  if (!rec) return false;
134886
135013
  return LANDING_PAGE_SPEED_KEYS.every(
134887
135014
  (key) => typeof rec[key] === "number" && Number.isFinite(rec[key])
134888
135015
  );
134889
135016
  }
134890
135017
  function restoreLandingPageSpeedFromCollect(finalData, collectReportData) {
134891
- const finalBlock = asRecord11(finalData[GOOGLE_ADS_DIAGNOSIS_LANDING_PAGE_MODULE]);
134892
- const collectBlock = asRecord11(collectReportData[GOOGLE_ADS_DIAGNOSIS_LANDING_PAGE_MODULE]);
135018
+ const finalBlock = asRecord12(finalData[GOOGLE_ADS_DIAGNOSIS_LANDING_PAGE_MODULE]);
135019
+ const collectBlock = asRecord12(collectReportData[GOOGLE_ADS_DIAGNOSIS_LANDING_PAGE_MODULE]);
134893
135020
  if (!collectBlock) return { data: finalData, restored: false };
134894
135021
  const needsDesktop = !isLandingPageSpeedValid(finalBlock?.desktop) && isLandingPageSpeedValid(collectBlock.desktop);
134895
135022
  const needsMobile = !isLandingPageSpeedValid(finalBlock?.mobile) && isLandingPageSpeedValid(collectBlock.mobile);
@@ -134912,8 +135039,8 @@ function mergeComparisonItemsFromCollect(finalData, collectReportData) {
134912
135039
  const restoredModules = [];
134913
135040
  for (const mod of GOOGLE_ADS_DIAGNOSIS_RESTORE_ITEM_MODULES) {
134914
135041
  const validator = MODULE_ITEM_VALIDATORS[mod];
134915
- const finalBlock = asRecord11(data[mod]);
134916
- const collectBlock = asRecord11(collectReportData[mod]);
135042
+ const finalBlock = asRecord12(data[mod]);
135043
+ const collectBlock = asRecord12(collectReportData[mod]);
134917
135044
  const finalItems = finalBlock?.items;
134918
135045
  const collectItems = collectBlock?.items;
134919
135046
  if (!Array.isArray(collectItems) || collectItems.length === 0) continue;
@@ -134929,7 +135056,7 @@ function mergeComparisonItemsFromCollect(finalData, collectReportData) {
134929
135056
  }
134930
135057
 
134931
135058
  // src/commands/google-ads-diagnosis/narrative-consistency-check.ts
134932
- function asRecord12(value) {
135059
+ function asRecord13(value) {
134933
135060
  if (value && typeof value === "object" && !Array.isArray(value)) {
134934
135061
  return value;
134935
135062
  }
@@ -134940,14 +135067,14 @@ function normalizeSuggestionText(value) {
134940
135067
  }
134941
135068
  function collectNarrativeTexts(data) {
134942
135069
  const texts = [];
134943
- const summary = asRecord12(data.summary);
135070
+ const summary = asRecord13(data.summary);
134944
135071
  if (Array.isArray(summary?.keyIssues)) {
134945
135072
  for (const item of summary.keyIssues) texts.push(String(item ?? ""));
134946
135073
  }
134947
- const overview = asRecord12(data.diagnosisOverview);
135074
+ const overview = asRecord13(data.diagnosisOverview);
134948
135075
  if (Array.isArray(overview?.disadvantages)) {
134949
135076
  for (const item of overview.disadvantages) {
134950
- const rec = asRecord12(item);
135077
+ const rec = asRecord13(item);
134951
135078
  if (rec) {
134952
135079
  texts.push(String(rec.title ?? ""), String(rec.description ?? ""));
134953
135080
  } else {
@@ -134958,16 +135085,16 @@ function collectNarrativeTexts(data) {
134958
135085
  return texts.filter((t) => t.trim().length > 0);
134959
135086
  }
134960
135087
  function newFeatureAccountStatus(data, strategy) {
134961
- const nf = asRecord12(data.newFeatures);
135088
+ const nf = asRecord13(data.newFeatures);
134962
135089
  const items3 = nf?.items;
134963
135090
  if (!Array.isArray(items3)) return null;
134964
- const row = items3.find((it) => asRecord12(it)?.strategy === strategy);
134965
- const rec = asRecord12(row);
135091
+ const row = items3.find((it) => asRecord13(it)?.strategy === strategy);
135092
+ const rec = asRecord13(row);
134966
135093
  if (!rec || typeof rec.accountStatus !== "boolean") return null;
134967
135094
  return rec.accountStatus;
134968
135095
  }
134969
135096
  function goldAccountFlag(data, key) {
134970
- const gold = asRecord12(data.goldAccount);
135097
+ const gold = asRecord13(data.goldAccount);
134971
135098
  const value = gold?.[key];
134972
135099
  return typeof value === "boolean" ? value : null;
134973
135100
  }
@@ -135012,7 +135139,7 @@ function getRepetitiveNarrativeErrors(data) {
135012
135139
  const errors = [];
135013
135140
  const budget = data.budgetCompetitiveness;
135014
135141
  if (Array.isArray(budget) && budget.length >= 3) {
135015
- const strategies = budget.map((row) => normalizeSuggestionText(asRecord12(row)?.strategy)).filter((s) => s.length > 0);
135142
+ const strategies = budget.map((row) => normalizeSuggestionText(asRecord13(row)?.strategy)).filter((s) => s.length > 0);
135016
135143
  const dup = findIdenticalTexts(strategies, 3);
135017
135144
  if (dup) {
135018
135145
  errors.push(
@@ -135020,10 +135147,10 @@ function getRepetitiveNarrativeErrors(data) {
135020
135147
  );
135021
135148
  }
135022
135149
  }
135023
- const creative = asRecord12(data.adCreativeOptimization);
135150
+ const creative = asRecord13(data.adCreativeOptimization);
135024
135151
  const creativeItems = creative?.items;
135025
135152
  if (Array.isArray(creativeItems) && creativeItems.length >= 3) {
135026
- const suggestions = creativeItems.map((row) => normalizeSuggestionText(asRecord12(row)?.suggestion)).filter((s) => s.length > 0);
135153
+ const suggestions = creativeItems.map((row) => normalizeSuggestionText(asRecord13(row)?.suggestion)).filter((s) => s.length > 0);
135027
135154
  const dup = findIdenticalTexts(suggestions, 3);
135028
135155
  if (dup) {
135029
135156
  errors.push(
@@ -135034,7 +135161,7 @@ function getRepetitiveNarrativeErrors(data) {
135034
135161
  return errors;
135035
135162
  }
135036
135163
  function getLandingPageTopicErrors(data) {
135037
- const lp = asRecord12(data.landingPageAnalysis);
135164
+ const lp = asRecord13(data.landingPageAnalysis);
135038
135165
  if (!lp) return [];
135039
135166
  const analysis = String(lp.analysis ?? "");
135040
135167
  if (!analysis.trim()) return [];
@@ -135063,8 +135190,75 @@ function getNarrativeConsistencyErrors(data) {
135063
135190
  return errors;
135064
135191
  }
135065
135192
 
135193
+ // src/commands/google-ads-diagnosis/overview-items.ts
135194
+ function asRecord14(value) {
135195
+ if (value && typeof value === "object" && !Array.isArray(value)) {
135196
+ return value;
135197
+ }
135198
+ return null;
135199
+ }
135200
+ function proseColonIndex(text2) {
135201
+ const cn = text2.indexOf("\uFF1A");
135202
+ if (cn > 0 && cn < text2.length - 1) return cn;
135203
+ for (let i = 1; i < text2.length - 1; i++) {
135204
+ if (text2[i] !== ":") continue;
135205
+ if (text2[i + 1] === "/") continue;
135206
+ const scheme = text2.slice(Math.max(0, i - 5), i);
135207
+ if (/https?$/i.test(scheme)) continue;
135208
+ return i;
135209
+ }
135210
+ return -1;
135211
+ }
135212
+ function splitOverviewProse(text2) {
135213
+ const trimmed = text2.trim();
135214
+ const cut = proseColonIndex(trimmed);
135215
+ if (cut > 0) {
135216
+ const title = trimmed.slice(0, cut).trim();
135217
+ const description = trimmed.slice(cut + 1).trim();
135218
+ if (title && description) return { title, description };
135219
+ }
135220
+ return { title: trimmed, description: trimmed };
135221
+ }
135222
+ function normalizeOverviewItem(item) {
135223
+ if (typeof item === "string" || typeof item === "number") {
135224
+ const text2 = String(item).trim();
135225
+ if (!text2) return null;
135226
+ return splitOverviewProse(text2);
135227
+ }
135228
+ const rec = asRecord14(item);
135229
+ if (!rec) return null;
135230
+ const title = String(rec.title ?? "").trim();
135231
+ const description = String(rec.description ?? "").trim();
135232
+ if (title && description) return { title, description };
135233
+ const prose = title || description;
135234
+ if (!prose) return null;
135235
+ const split = splitOverviewProse(prose);
135236
+ return {
135237
+ title: title || split.title,
135238
+ description: description || split.description
135239
+ };
135240
+ }
135241
+ function normalizeDiagnosisOverview(data) {
135242
+ const overview = asRecord14(data.diagnosisOverview);
135243
+ if (!overview) return { data, coerced: [] };
135244
+ const coerced = [];
135245
+ const nextOverview = { ...overview };
135246
+ for (const key of ["advantages", "disadvantages"]) {
135247
+ const items3 = overview[key];
135248
+ if (!Array.isArray(items3)) continue;
135249
+ nextOverview[key] = items3.map((item) => {
135250
+ if (typeof item === "string" || typeof item === "number") coerced.push(key);
135251
+ return normalizeOverviewItem(item) ?? { title: "", description: "" };
135252
+ });
135253
+ }
135254
+ return {
135255
+ data: { ...data, diagnosisOverview: nextOverview },
135256
+ coerced
135257
+ };
135258
+ }
135259
+
135066
135260
  // src/commands/google-ads-diagnosis/render-report.ts
135067
- function asRecord13(value) {
135261
+ function asRecord15(value) {
135068
135262
  if (value && typeof value === "object" && !Array.isArray(value)) {
135069
135263
  return value;
135070
135264
  }
@@ -135073,8 +135267,8 @@ function asRecord13(value) {
135073
135267
  async function tryLoadCollectReportData(collectPath) {
135074
135268
  try {
135075
135269
  const raw = JSON.parse(await fs22.readFile(collectPath, "utf8"));
135076
- const root = asRecord13(raw);
135077
- const reportData = asRecord13(root?.reportData);
135270
+ const root = asRecord15(raw);
135271
+ const reportData = asRecord15(root?.reportData);
135078
135272
  return reportData ?? root;
135079
135273
  } catch {
135080
135274
  return null;
@@ -135091,7 +135285,7 @@ async function runGoogleAdsDiagnosisRender(opts) {
135091
135285
  `);
135092
135286
  process.exit(1);
135093
135287
  }
135094
- let data = asRecord13(dataRaw);
135288
+ let data = asRecord15(dataRaw);
135095
135289
  if (!opts.noMergeCollect) {
135096
135290
  const collectPath = path26.resolve(
135097
135291
  opts.collectFile ?? path26.join(path26.dirname(dataPath), GOOGLE_ADS_DIAGNOSIS_COLLECT_BASENAME)
@@ -135123,6 +135317,17 @@ async function runGoogleAdsDiagnosisRender(opts) {
135123
135317
  }
135124
135318
  }
135125
135319
  }
135320
+ data = reconcileGoldAccountInReport(data, path26.dirname(dataPath));
135321
+ const overview = normalizeDiagnosisOverview(data);
135322
+ data = overview.data;
135323
+ if (overview.coerced.length > 0) {
135324
+ const fields = [...new Set(overview.coerced)].join("\u3001");
135325
+ console.log(
135326
+ `
135327
+ \u2139\uFE0F \u5DF2\u5C06 diagnosisOverview.${fields} \u7684\u7EAF\u5B57\u7B26\u4E32\u6309\u7B2C\u4E00\u4E2A\u5192\u53F7\u62C6\u6210 {title, description} \u518D\u6CE8\u5165 HTML\u3002
135328
+ `
135329
+ );
135330
+ }
135126
135331
  const narrativeErrors = getNarrativeConsistencyErrors(data);
135127
135332
  if (narrativeErrors.length > 0) {
135128
135333
  console.error("\n\u274C \u53D9\u4E8B\u6587\u6848\u4E0E\u4E8B\u5B9E\u5B57\u6BB5\u77DB\u76FE\uFF0C\u7981\u6B62\u6E32\u67D3\uFF1A\n");
@@ -136421,26 +136626,26 @@ import fs26 from "fs/promises";
136421
136626
  import path31 from "path";
136422
136627
 
136423
136628
  // src/commands/google-quarterly/report-content.ts
136424
- function asRecord14(value) {
136629
+ function asRecord16(value) {
136425
136630
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
136426
136631
  }
136427
136632
  function asStringArray(value) {
136428
136633
  return Array.isArray(value) ? value.map((x) => String(x).trim()).filter(Boolean) : [];
136429
136634
  }
136430
136635
  function validateQuarterlyNarrative(data) {
136431
- const root = asRecord14(data);
136432
- const narrative = asRecord14(root?.narrative);
136636
+ const root = asRecord16(data);
136637
+ const narrative = asRecord16(root?.narrative);
136433
136638
  const missing = [];
136434
136639
  if (!narrative) {
136435
136640
  return { ok: false, missing: ["narrative"] };
136436
136641
  }
136437
136642
  if (asStringArray(narrative.executiveSummary).length < 1) missing.push("narrative.executiveSummary");
136438
- const sections = asRecord14(narrative.sections);
136643
+ const sections = asRecord16(narrative.sections);
136439
136644
  for (const key of ["efficiency", "adType", "region", "summary"]) {
136440
- const block = asRecord14(sections?.[key]);
136645
+ const block = asRecord16(sections?.[key]);
136441
136646
  if (asStringArray(block?.analysis).length < 1) missing.push(`narrative.sections.${key}.analysis`);
136442
136647
  }
136443
- const plan = asRecord14(narrative.plan);
136648
+ const plan = asRecord16(narrative.plan);
136444
136649
  if (asStringArray(plan?.analysis ?? plan?.goals).length < 1 && !String(plan?.text ?? "").trim()) {
136445
136650
  missing.push("narrative.plan");
136446
136651
  }
@@ -136453,8 +136658,8 @@ function mergeCollectFacts(agentData, collect) {
136453
136658
  ...facts,
136454
136659
  narrative: agentData.narrative ?? collect.narrative,
136455
136660
  meta: {
136456
- ...asRecord14(collect.meta) ?? {},
136457
- ...asRecord14(agentData.meta) ?? {}
136661
+ ...asRecord16(collect.meta) ?? {},
136662
+ ...asRecord16(agentData.meta) ?? {}
136458
136663
  }
136459
136664
  };
136460
136665
  }
@@ -136466,7 +136671,7 @@ import { fileURLToPath as fileURLToPath8 } from "url";
136466
136671
  var TSO_CLI_ROOT = path30.join(path30.dirname(fileURLToPath8(import.meta.url)), "../..");
136467
136672
 
136468
136673
  // src/commands/google-quarterly/render-report.ts
136469
- function asRecord15(value) {
136674
+ function asRecord17(value) {
136470
136675
  if (value && typeof value === "object" && !Array.isArray(value)) {
136471
136676
  return value;
136472
136677
  }
@@ -136495,7 +136700,7 @@ async function runGoogleQuarterlyRender(opts) {
136495
136700
  `);
136496
136701
  process.exit(1);
136497
136702
  }
136498
- const merged = mergeCollectFacts(asRecord15(agentRaw), asRecord15(collectRaw));
136703
+ const merged = mergeCollectFacts(asRecord17(agentRaw), asRecord17(collectRaw));
136499
136704
  const check = validateQuarterlyNarrative(merged);
136500
136705
  if (!check.ok && !opts.lenient) {
136501
136706
  console.error("\n\u274C narrative \u4E0D\u5B8C\u6574\uFF0C\u62D2\u7EDD\u51FA HTML\uFF1A\n");
@@ -136659,7 +136864,7 @@ import * as fs33 from "fs/promises";
136659
136864
  import * as path40 from "path";
136660
136865
 
136661
136866
  // src/commands/facebook-analysis/report-metrics.ts
136662
- function asRecord21(value) {
136867
+ function asRecord23(value) {
136663
136868
  if (value && typeof value === "object" && !Array.isArray(value)) {
136664
136869
  return value;
136665
136870
  }
@@ -136796,7 +137001,7 @@ function localizeFacebookReportLabels(payload) {
136796
137001
  for (const rows of Object.values(tables)) {
136797
137002
  if (!Array.isArray(rows)) continue;
136798
137003
  for (const row of rows) {
136799
- localizeMetricLabels(asRecord21(row));
137004
+ localizeMetricLabels(asRecord23(row));
136800
137005
  }
136801
137006
  }
136802
137007
  return payload;
@@ -136829,7 +137034,7 @@ async function readManifest3(snapshotDir) {
136829
137034
  async function loadSectionFile3(snapshotDir, file) {
136830
137035
  try {
136831
137036
  const raw = await fs33.readFile(path40.join(snapshotDir, file), "utf8");
136832
- return asRecord21(JSON.parse(raw));
137037
+ return asRecord23(JSON.parse(raw));
136833
137038
  } catch {
136834
137039
  return null;
136835
137040
  }
@@ -136885,7 +137090,7 @@ async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
136885
137090
  if (data) sectionMap.set(art.section, data);
136886
137091
  }
136887
137092
  const overview = sectionMap.get("overview");
136888
- const current = asRecord21(overview?.currentPeriod);
137093
+ const current = asRecord23(overview?.currentPeriod);
136889
137094
  const accountName = typeof overview?.accountName === "string" ? overview.accountName : void 0;
136890
137095
  const accountId = manifest.accountId ?? (typeof overview?.accountId === "string" ? overview.accountId : void 0);
136891
137096
  const kpis = { ...payload.kpis ?? {} };
@@ -137022,7 +137227,7 @@ function writeSimpleXlsx(filePath, sheets, opts = {}) {
137022
137227
  }
137023
137228
 
137024
137229
  // src/commands/facebook-analysis/render-excel.ts
137025
- function asRecord22(value) {
137230
+ function asRecord24(value) {
137026
137231
  if (value && typeof value === "object" && !Array.isArray(value)) {
137027
137232
  return value;
137028
137233
  }
@@ -137070,8 +137275,8 @@ function bullets(value) {
137070
137275
  return asArray3(value).map((item) => typeof item === "string" ? item.trim() : "").filter(Boolean);
137071
137276
  }
137072
137277
  function insightLines(section) {
137073
- const rec = asRecord22(section);
137074
- const insight = asRecord22(rec?.insight) ?? rec;
137278
+ const rec = asRecord24(section);
137279
+ const insight = asRecord24(rec?.insight) ?? rec;
137075
137280
  return [...bullets(insight?.analysis), ...bullets(insight?.advice)];
137076
137281
  }
137077
137282
  function numberedSection(index, title, lines) {
@@ -137080,15 +137285,15 @@ function numberedSection(index, title, lines) {
137080
137285
  ${body}`;
137081
137286
  }
137082
137287
  function buildSummaryNarrative(data) {
137083
- const kpis = asRecord22(data.kpis) ?? {};
137084
- const meta = asRecord22(data.meta) ?? {};
137085
- const sections = asRecord22(data.sections) ?? {};
137288
+ const kpis = asRecord24(data.kpis) ?? {};
137289
+ const meta = asRecord24(data.meta) ?? {};
137290
+ const sections = asRecord24(data.sections) ?? {};
137086
137291
  const period = str2(meta.periodLabel) || `${str2(meta.startDate)} ~ ${str2(meta.endDate)}`.trim();
137087
137292
  const account = str2(meta.accountName) || "Facebook \u5E7F\u544A\u8D26\u6237";
137088
137293
  const campaign = str2(meta.campaignName);
137089
137294
  const resultLabel = displayResultType(kpis.resultType ?? meta.resultType) || "\u6210\u6548";
137090
137295
  const resultNoun = /潜在客户|lead/i.test(resultLabel) ? "\u4E2A\u6F5C\u5728\u5BA2\u6237\u8868\u5355" : `\u4E2A${resultLabel}`;
137091
- const firstQuestion = asRecord22(asArray3(data.fourQuestions)[0]);
137296
+ const firstQuestion = asRecord24(asArray3(data.fourQuestions)[0]);
137092
137297
  const extra = str2(firstQuestion?.verdict);
137093
137298
  const spendLine = [
137094
137299
  campaign ? `\uFF08\u5E7F\u544A\u7CFB\u5217\uFF1A${campaign}\uFF09` : "",
@@ -137108,7 +137313,7 @@ function buildSummaryNarrative(data) {
137108
137313
  numberedSection(3, "\u5E7F\u544A\u9891\u6B21\u4E0E\u65E5\u8D8B\u52BF", insightLines(sections.daily))
137109
137314
  ].join("\n");
137110
137315
  const recBlocks = asArray3(data.recommendations).map((raw, i) => {
137111
- const rec = asRecord22(raw);
137316
+ const rec = asRecord24(raw);
137112
137317
  if (!rec) return "";
137113
137318
  const title = [str2(rec.title), str2(rec.tag)].filter(Boolean).join(" \xB7 ");
137114
137319
  return numberedSection(i + 1, title || "\u4F18\u5316\u5EFA\u8BAE", bullets(rec.items));
@@ -137119,9 +137324,9 @@ function buildSummaryNarrative(data) {
137119
137324
  return [partOne, partTwo, partThree];
137120
137325
  }
137121
137326
  function buildMetaPeriodExcelSheets(data) {
137122
- const meta = asRecord22(data.meta) ?? {};
137123
- const kpis = asRecord22(data.kpis) ?? {};
137124
- const tables = asRecord22(data.tables) ?? {};
137327
+ const meta = asRecord24(data.meta) ?? {};
137328
+ const kpis = asRecord24(data.kpis) ?? {};
137329
+ const tables = asRecord24(data.tables) ?? {};
137125
137330
  const currency = str2(meta.currency) || "USD";
137126
137331
  const resultType = displayResultType(kpis.resultType ?? meta.resultType);
137127
137332
  const attribution = displayAttribution(kpis.attributionSetting ?? meta.attributionSetting);
@@ -137140,19 +137345,19 @@ function buildMetaPeriodExcelSheets(data) {
137140
137345
  ];
137141
137346
  const dailyRows = [metricHeaders(currency, "\u5355\u65E5")];
137142
137347
  for (const raw of asArray3(tables.daily)) {
137143
- const row = asRecord22(raw);
137348
+ const row = asRecord24(raw);
137144
137349
  if (!row) continue;
137145
137350
  dailyRows.push([normalizeInsightDate(row.date), ...metricCells(row)]);
137146
137351
  }
137147
137352
  const countryRows = [metricHeaders(currency, "\u56FD\u5BB6/\u5730\u533A")];
137148
137353
  for (const raw of asArray3(tables.countries)) {
137149
- const row = asRecord22(raw);
137354
+ const row = asRecord24(raw);
137150
137355
  if (!row) continue;
137151
137356
  countryRows.push([str2(row.countryOrRegion), ...metricCells(row)]);
137152
137357
  }
137153
137358
  const campaignRows3 = [metricHeaders(currency, "\u5E7F\u544A\u7CFB\u5217\u540D\u79F0")];
137154
137359
  for (const raw of asArray3(tables.campaigns)) {
137155
- const row = asRecord22(raw);
137360
+ const row = asRecord24(raw);
137156
137361
  if (!row) continue;
137157
137362
  campaignRows3.push([str2(row.campaignName), ...metricCells(row)]);
137158
137363
  }
@@ -137171,7 +137376,7 @@ function buildMetaPeriodExcelSheets(data) {
137171
137376
  ]
137172
137377
  ];
137173
137378
  for (const raw of asArray3(tables.audiences)) {
137174
- const row = asRecord22(raw);
137379
+ const row = asRecord24(raw);
137175
137380
  if (!row) continue;
137176
137381
  audienceRows.push([str2(row.age), str2(row.gender), ...metricCells(row)]);
137177
137382
  }
@@ -137203,7 +137408,7 @@ function isFiniteNumber(value) {
137203
137408
  function asArray4(value) {
137204
137409
  return Array.isArray(value) ? value : [];
137205
137410
  }
137206
- function asRecord23(value) {
137411
+ function asRecord25(value) {
137207
137412
  if (value && typeof value === "object" && !Array.isArray(value)) {
137208
137413
  return value;
137209
137414
  }
@@ -137216,8 +137421,8 @@ function stringList3(value) {
137216
137421
  return asArray4(value).map((item) => typeof item === "string" ? item.trim() : "").filter(Boolean);
137217
137422
  }
137218
137423
  function insightLists(section) {
137219
- const rec = asRecord23(section);
137220
- const insight = asRecord23(rec?.insight) ?? rec;
137424
+ const rec = asRecord25(section);
137425
+ const insight = asRecord25(rec?.insight) ?? rec;
137221
137426
  return {
137222
137427
  analysis: stringList3(insight?.analysis),
137223
137428
  advice: stringList3(insight?.advice)
@@ -137247,11 +137452,11 @@ function requireInsight(missing, key, chapter, section, required) {
137247
137452
  }
137248
137453
  function validateMetaPeriodReportContent(data) {
137249
137454
  const missing = [];
137250
- const meta = asRecord23(data.meta) ?? {};
137251
- const kpis = asRecord23(data.kpis) ?? {};
137252
- const tables = asRecord23(data.tables) ?? {};
137253
- const charts = asRecord23(data.charts) ?? {};
137254
- const sections = asRecord23(data.sections) ?? {};
137455
+ const meta = asRecord25(data.meta) ?? {};
137456
+ const kpis = asRecord25(data.kpis) ?? {};
137457
+ const tables = asRecord25(data.tables) ?? {};
137458
+ const charts = asRecord25(data.charts) ?? {};
137459
+ const sections = asRecord25(data.sections) ?? {};
137255
137460
  const fourQuestions = asArray4(data.fourQuestions);
137256
137461
  const recommendations = asArray4(data.recommendations);
137257
137462
  if (!textLen3(meta.accountName) && !textLen3(meta.accountId)) {
@@ -137330,7 +137535,7 @@ function validateMetaPeriodReportContent(data) {
137330
137535
  "\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 []"
137331
137536
  );
137332
137537
  }
137333
- const dailyChart = asRecord23(charts.daily);
137538
+ const dailyChart = asRecord25(charts.daily);
137334
137539
  if (!Array.isArray(dailyChart?.labels)) {
137335
137540
  pushMissing3(
137336
137541
  missing,
@@ -137340,7 +137545,7 @@ function validateMetaPeriodReportContent(data) {
137340
137545
  "\u987B\u6709 charts.daily.labels \u6570\u7EC4\uFF1B\u53EF\u7531 --snapshot-dir \u5408\u5E76 daily\u3002\u672C\u671F\u65E0\u6D88\u8017\u53EF\u4E3A []"
137341
137546
  );
137342
137547
  }
137343
- const countryChart = asRecord23(charts.country);
137548
+ const countryChart = asRecord25(charts.country);
137344
137549
  if (!Array.isArray(countryChart?.labels)) {
137345
137550
  pushMissing3(
137346
137551
  missing,
@@ -137350,7 +137555,7 @@ function validateMetaPeriodReportContent(data) {
137350
137555
  "\u987B\u6709 charts.country.labels \u6570\u7EC4\uFF1B\u53EF\u7531 --snapshot-dir \u5408\u5E76 country\u3002\u672C\u671F\u65E0\u6D88\u8017\u53EF\u4E3A []"
137351
137556
  );
137352
137557
  }
137353
- const audienceChart = asRecord23(charts.audience);
137558
+ const audienceChart = asRecord25(charts.audience);
137354
137559
  if (!Array.isArray(audienceChart?.labels)) {
137355
137560
  pushMissing3(
137356
137561
  missing,
@@ -137369,7 +137574,7 @@ function validateMetaPeriodReportContent(data) {
137369
137574
  "\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"
137370
137575
  );
137371
137576
  } else {
137372
- const titles = fourQuestions.map((q) => asRecord23(q)?.title);
137577
+ const titles = fourQuestions.map((q) => asRecord25(q)?.title);
137373
137578
  for (const title of FOUR_QUESTION_TITLES) {
137374
137579
  if (!titles.includes(title)) {
137375
137580
  pushMissing3(
@@ -137382,7 +137587,7 @@ function validateMetaPeriodReportContent(data) {
137382
137587
  }
137383
137588
  }
137384
137589
  for (let i = 0; i < fourQuestions.length; i++) {
137385
- const q = asRecord23(fourQuestions[i]);
137590
+ const q = asRecord25(fourQuestions[i]);
137386
137591
  if (textLen3(q?.verdict) < 8) {
137387
137592
  pushMissing3(
137388
137593
  missing,
@@ -137422,7 +137627,7 @@ function validateMetaPeriodReportContent(data) {
137422
137627
  );
137423
137628
  } else {
137424
137629
  for (let i = 0; i < recommendations.length; i++) {
137425
- const rec = asRecord23(recommendations[i]);
137630
+ const rec = asRecord25(recommendations[i]);
137426
137631
  if (textLen3(rec?.title) < 2) {
137427
137632
  pushMissing3(
137428
137633
  missing,
@@ -137515,7 +137720,7 @@ async function readJsonFile4(filePath) {
137515
137720
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
137516
137721
  }
137517
137722
  }
137518
- function asRecord24(value) {
137723
+ function asRecord26(value) {
137519
137724
  if (value && typeof value === "object" && !Array.isArray(value)) {
137520
137725
  return value;
137521
137726
  }
@@ -137544,7 +137749,7 @@ function defaultOutPath(dataPath, format, out) {
137544
137749
  }
137545
137750
  async function runFacebookAnalysisRender(opts) {
137546
137751
  const dataPath = path41.resolve(opts.dataFile);
137547
- let data = asRecord24(await readJsonFile4(dataPath));
137752
+ let data = asRecord26(await readJsonFile4(dataPath));
137548
137753
  if (opts.snapshotDir?.trim()) {
137549
137754
  data = await mergeFacebookSnapshotIntoReport(data, path41.resolve(opts.snapshotDir));
137550
137755
  }
@@ -137608,7 +137813,7 @@ import { fileURLToPath as fileURLToPath11 } from "url";
137608
137813
  // src/commands/facebook-analysis/diagnosis-merge-snapshot.ts
137609
137814
  import * as fs35 from "fs/promises";
137610
137815
  import * as path42 from "path";
137611
- function asRecord25(value) {
137816
+ function asRecord27(value) {
137612
137817
  if (value && typeof value === "object" && !Array.isArray(value)) {
137613
137818
  return value;
137614
137819
  }
@@ -137619,7 +137824,7 @@ function num8(value) {
137619
137824
  return Number.isFinite(n) ? n : void 0;
137620
137825
  }
137621
137826
  function asRows(value) {
137622
- return Array.isArray(value) ? value.filter((r) => asRecord25(r) !== null) : [];
137827
+ return Array.isArray(value) ? value.filter((r) => asRecord27(r) !== null) : [];
137623
137828
  }
137624
137829
  function pickMetricExtras(row, extras) {
137625
137830
  const out = {
@@ -137668,14 +137873,14 @@ async function readManifest4(snapshotDir, accountId) {
137668
137873
  async function loadSectionFile4(snapshotDir, file) {
137669
137874
  try {
137670
137875
  const raw = await fs35.readFile(path42.join(snapshotDir, file), "utf8");
137671
- return asRecord25(JSON.parse(raw));
137876
+ return asRecord27(JSON.parse(raw));
137672
137877
  } catch {
137673
137878
  return null;
137674
137879
  }
137675
137880
  }
137676
137881
  async function mergeMetaDiagnosisSnapshotIntoReport(payload, snapshotDir) {
137677
137882
  const absDir = path42.resolve(snapshotDir);
137678
- const metaAccountId = typeof asRecord25(payload.meta)?.accountId === "string" ? asRecord25(payload.meta)?.accountId : void 0;
137883
+ const metaAccountId = typeof asRecord27(payload.meta)?.accountId === "string" ? asRecord27(payload.meta)?.accountId : void 0;
137679
137884
  const manifest = await readManifest4(snapshotDir, metaAccountId);
137680
137885
  if (!manifest) {
137681
137886
  throw new Error(
@@ -137688,8 +137893,8 @@ async function mergeMetaDiagnosisSnapshotIntoReport(payload, snapshotDir) {
137688
137893
  if (data) sectionMap.set(art.section, data);
137689
137894
  }
137690
137895
  const overview = sectionMap.get("overview");
137691
- const currentPeriod = asRecord25(overview?.currentPeriod);
137692
- const previousPeriod = asRecord25(overview?.previousPeriod);
137896
+ const currentPeriod = asRecord27(overview?.currentPeriod);
137897
+ const previousPeriod = asRecord27(overview?.previousPeriod);
137693
137898
  const accountId = manifest.accountId ?? metaAccountId;
137694
137899
  const meta = { ...payload.meta ?? {} };
137695
137900
  if (!meta.accountId && accountId) meta.accountId = accountId;
@@ -137823,7 +138028,7 @@ function textLen4(value) {
137823
138028
  function asArray5(value) {
137824
138029
  return Array.isArray(value) ? value : [];
137825
138030
  }
137826
- function asRecord26(value) {
138031
+ function asRecord28(value) {
137827
138032
  if (value && typeof value === "object" && !Array.isArray(value)) {
137828
138033
  return value;
137829
138034
  }
@@ -137834,9 +138039,9 @@ function pushMissing4(missing, id, chapter, dimension, hint) {
137834
138039
  }
137835
138040
  function validateMetaDiagnosisReportContent(data) {
137836
138041
  const missing = [];
137837
- const meta = asRecord26(data.meta) ?? {};
137838
- const narrative = asRecord26(data.narrative) ?? {};
137839
- const sections = asRecord26(narrative.sections) ?? {};
138042
+ const meta = asRecord28(data.meta) ?? {};
138043
+ const narrative = asRecord28(data.narrative) ?? {};
138044
+ const sections = asRecord28(narrative.sections) ?? {};
137840
138045
  if (!textLen4(meta.accountId)) {
137841
138046
  pushMissing4(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
137842
138047
  }
@@ -137854,7 +138059,7 @@ function validateMetaDiagnosisReportContent(data) {
137854
138059
  const sectionSuggestionCounts = {};
137855
138060
  const sectionNotAvailable = {};
137856
138061
  for (const key of NORMAL_SECTION_KEYS) {
137857
- const section = asRecord26(sections[key]);
138062
+ const section = asRecord28(sections[key]);
137858
138063
  const analysis = asArray5(section?.analysis).filter((s) => textLen4(s) > 0);
137859
138064
  const suggestions = asArray5(section?.suggestions).filter((s) => textLen4(s) > 0);
137860
138065
  sectionAnalysisCounts[key] = analysis.length;
@@ -137880,7 +138085,7 @@ function validateMetaDiagnosisReportContent(data) {
137880
138085
  }
137881
138086
  }
137882
138087
  for (const key of NA_SECTION_KEYS) {
137883
- const section = asRecord26(sections[key]);
138088
+ const section = asRecord28(sections[key]);
137884
138089
  const analysis = asArray5(section?.analysis).filter((s) => textLen4(s) > 0);
137885
138090
  const suggestions = asArray5(section?.suggestions).filter((s) => textLen4(s) > 0);
137886
138091
  const notAvailable = section?.notAvailable === true;
@@ -137902,7 +138107,7 @@ function validateMetaDiagnosisReportContent(data) {
137902
138107
  }
137903
138108
  const recommendations = asArray5(narrative.recommendations).filter((r) => {
137904
138109
  if (typeof r === "string") return textLen4(r) > 0;
137905
- const rec = asRecord26(r);
138110
+ const rec = asRecord28(r);
137906
138111
  return textLen4(rec?.content) > 0;
137907
138112
  });
137908
138113
  if (recommendations.length < 3) {
@@ -137975,7 +138180,7 @@ async function readJsonFile5(filePath) {
137975
138180
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
137976
138181
  }
137977
138182
  }
137978
- function asRecord27(value) {
138183
+ function asRecord29(value) {
137979
138184
  if (value && typeof value === "object" && !Array.isArray(value)) {
137980
138185
  return value;
137981
138186
  }
@@ -137990,7 +138195,7 @@ function injectReportData4(html, payload) {
137990
138195
  }
137991
138196
  async function runFacebookAnalysisDiagnosisRender(opts) {
137992
138197
  const dataPath = path43.resolve(opts.dataFile);
137993
- let data = asRecord27(await readJsonFile5(dataPath));
138198
+ let data = asRecord29(await readJsonFile5(dataPath));
137994
138199
  if (opts.snapshotDir?.trim()) {
137995
138200
  data = await mergeMetaDiagnosisSnapshotIntoReport(data, path43.resolve(opts.snapshotDir));
137996
138201
  }
@@ -138189,7 +138394,7 @@ function resolveFacebookPageSize(raw, fallback = FB_ENTITY_PAGE_SIZE_DEFAULT) {
138189
138394
  if (!Number.isFinite(n) || n <= 0) return fallback;
138190
138395
  return Math.min(Math.max(Math.floor(n), 1), FB_ENTITY_PAGE_SIZE_MAX);
138191
138396
  }
138192
- function asRecord28(value) {
138397
+ function asRecord30(value) {
138193
138398
  return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
138194
138399
  }
138195
138400
  function pickProp(obj, ...keys) {
@@ -138199,12 +138404,12 @@ function pickProp(obj, ...keys) {
138199
138404
  return void 0;
138200
138405
  }
138201
138406
  function unwrapFacebookPaged(raw) {
138202
- const rec = asRecord28(raw);
138407
+ const rec = asRecord30(raw);
138203
138408
  if (!rec) return { items: [] };
138204
138409
  const data = pickProp(rec, "data", "Data");
138205
138410
  const items3 = Array.isArray(data) ? data : [];
138206
- const paging = asRecord28(pickProp(rec, "paging", "Paging"));
138207
- const cursors = paging ? asRecord28(pickProp(paging, "cursors", "Cursors")) : void 0;
138411
+ const paging = asRecord30(pickProp(rec, "paging", "Paging"));
138412
+ const cursors = paging ? asRecord30(pickProp(paging, "cursors", "Cursors")) : void 0;
138208
138413
  const afterRaw = cursors ? pickProp(cursors, "after", "After") : void 0;
138209
138414
  const after = typeof afterRaw === "string" && afterRaw.trim() ? afterRaw.trim() : void 0;
138210
138415
  return { items: items3, after };
@@ -138352,7 +138557,7 @@ async function fetchFacebookInsights(config, digits, level, opts) {
138352
138557
  opts.verbose
138353
138558
  );
138354
138559
  if (Array.isArray(raw)) return raw;
138355
- const rec = asRecord28(raw);
138560
+ const rec = asRecord30(raw);
138356
138561
  const data = rec ? pickProp(rec, "data", "Data") : void 0;
138357
138562
  return Array.isArray(data) ? data : [];
138358
138563
  }
@@ -138361,7 +138566,7 @@ function sumActionArray(raw) {
138361
138566
  let sum = 0;
138362
138567
  let hit = false;
138363
138568
  for (const item of raw) {
138364
- const rec = asRecord28(item);
138569
+ const rec = asRecord30(item);
138365
138570
  if (!rec) continue;
138366
138571
  const n = Number(rec.value);
138367
138572
  if (!Number.isFinite(n)) continue;
@@ -139640,7 +139845,7 @@ import { fileURLToPath as fileURLToPath12 } from "url";
139640
139845
  // src/commands/bing-analysis/merge-snapshot.ts
139641
139846
  import * as fs37 from "fs/promises";
139642
139847
  import * as path46 from "path";
139643
- function asRecord29(value) {
139848
+ function asRecord31(value) {
139644
139849
  if (value && typeof value === "object" && !Array.isArray(value)) {
139645
139850
  return value;
139646
139851
  }
@@ -139655,7 +139860,7 @@ function round27(value) {
139655
139860
  }
139656
139861
  function asRows2(value) {
139657
139862
  if (Array.isArray(value)) {
139658
- return value.filter((r) => asRecord29(r) !== null);
139863
+ return value.filter((r) => asRecord31(r) !== null);
139659
139864
  }
139660
139865
  return [];
139661
139866
  }
@@ -139737,17 +139942,17 @@ function campaignStatusDisplay(status) {
139737
139942
  return status == null || status === "" ? "\u2014" : String(status);
139738
139943
  }
139739
139944
  function mapDeviceRows(payload) {
139740
- const obj = asRecord29(payload);
139945
+ const obj = asRecord31(payload);
139741
139946
  return asRows2(obj?.devices).map((r) => pickMetrics(r, ["deviceType"]));
139742
139947
  }
139743
139948
  function mapGeographicRows(payload) {
139744
- const obj = asRecord29(payload);
139949
+ const obj = asRecord31(payload);
139745
139950
  return asRows2(obj?.countries).map(
139746
139951
  (r) => pickMetrics(r, ["countryOrRegion", "countryCriteriaId", "regionName", "cityName"])
139747
139952
  );
139748
139953
  }
139749
139954
  function mapAudienceLabelRows(payload, labelKey) {
139750
- const obj = asRecord29(payload);
139955
+ const obj = asRecord31(payload);
139751
139956
  return asRows2(obj?.audience).map((r) => {
139752
139957
  const m = pickMetrics(r, ["audience", "bidModifier"]);
139753
139958
  m[labelKey] = r.audience;
@@ -139755,7 +139960,7 @@ function mapAudienceLabelRows(payload, labelKey) {
139755
139960
  });
139756
139961
  }
139757
139962
  function mapAudienceFromMerged(payload) {
139758
- const data = asRecord29(asRecord29(payload)?.data);
139963
+ const data = asRecord31(asRecord31(payload)?.data);
139759
139964
  return {
139760
139965
  audienceAge: mapAudienceLabelRows(data?.ageAudience, "ageRange"),
139761
139966
  audienceGender: mapAudienceLabelRows(data?.genderAudience, "gender")
@@ -139850,7 +140055,7 @@ function mapSearchTermRows(payload) {
139850
140055
  }
139851
140056
  async function mergeBingAnalysisSnapshotIntoReport(payload, snapshotDir) {
139852
140057
  const absDir = path46.resolve(snapshotDir);
139853
- const metaAccountId = typeof asRecord29(payload.meta)?.accountId === "string" ? asRecord29(payload.meta)?.accountId : void 0;
140058
+ const metaAccountId = typeof asRecord31(payload.meta)?.accountId === "string" ? asRecord31(payload.meta)?.accountId : void 0;
139854
140059
  const manifest = await readManifest5(snapshotDir, metaAccountId);
139855
140060
  if (!manifest) {
139856
140061
  throw new Error(`\u672A\u5728 ${absDir} \u627E\u5230 report-manifest*.json\uFF0C\u8BF7\u5148\u6267\u884C bing-analysis --json-out`);
@@ -139860,9 +140065,9 @@ async function mergeBingAnalysisSnapshotIntoReport(payload, snapshotDir) {
139860
140065
  const data = await loadSectionPayload(absDir, art.file);
139861
140066
  if (data != null) sectionMap.set(art.section, data);
139862
140067
  }
139863
- const overview = asRecord29(sectionMap.get("overview"));
139864
- const currentPeriod = asRecord29(overview?.currentPeriod);
139865
- const previousPeriod = asRecord29(overview?.previousPeriod);
140068
+ const overview = asRecord31(sectionMap.get("overview"));
140069
+ const currentPeriod = asRecord31(overview?.currentPeriod);
140070
+ const previousPeriod = asRecord31(overview?.previousPeriod);
139866
140071
  const accountId = manifest.accountId ?? metaAccountId;
139867
140072
  const campaignRows3 = mapCampaignRows2(sectionMap.get("campaigns"));
139868
140073
  const campaignKpis = sumBingCampaignRowsToPeriodKpis(campaignRows3);
@@ -139989,7 +140194,7 @@ function textLen5(value) {
139989
140194
  function asArray6(value) {
139990
140195
  return Array.isArray(value) ? value : [];
139991
140196
  }
139992
- function asRecord30(value) {
140197
+ function asRecord32(value) {
139993
140198
  if (value && typeof value === "object" && !Array.isArray(value)) {
139994
140199
  return value;
139995
140200
  }
@@ -140000,9 +140205,9 @@ function pushMissing5(missing, id, chapter, dimension, hint) {
140000
140205
  }
140001
140206
  function validateBingPeriodReportContent(data) {
140002
140207
  const missing = [];
140003
- const meta = asRecord30(data.meta) ?? {};
140004
- const narrative = asRecord30(data.narrative) ?? {};
140005
- const sections = asRecord30(narrative.sections) ?? {};
140208
+ const meta = asRecord32(data.meta) ?? {};
140209
+ const narrative = asRecord32(data.narrative) ?? {};
140210
+ const sections = asRecord32(narrative.sections) ?? {};
140006
140211
  if (!textLen5(meta.accountId)) {
140007
140212
  pushMissing5(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
140008
140213
  }
@@ -140019,7 +140224,7 @@ function validateBingPeriodReportContent(data) {
140019
140224
  const sectionAnalysisCounts = {};
140020
140225
  const sectionSuggestionCounts = {};
140021
140226
  for (const key of SECTION_KEYS2) {
140022
- const section = asRecord30(sections[key]);
140227
+ const section = asRecord32(sections[key]);
140023
140228
  const analysis = asArray6(section?.analysis).filter((s) => textLen5(s) > 0);
140024
140229
  const suggestions = asArray6(section?.suggestions).filter((s) => textLen5(s) > 0);
140025
140230
  sectionAnalysisCounts[key] = analysis.length;
@@ -140045,7 +140250,7 @@ function validateBingPeriodReportContent(data) {
140045
140250
  }
140046
140251
  const recommendations = asArray6(narrative.recommendations).filter((r) => {
140047
140252
  if (typeof r === "string") return textLen5(r) > 0;
140048
- const rec = asRecord30(r);
140253
+ const rec = asRecord32(r);
140049
140254
  return textLen5(rec?.content) > 0;
140050
140255
  });
140051
140256
  if (recommendations.length < 3) {
@@ -140106,7 +140311,7 @@ async function readJsonFile6(filePath) {
140106
140311
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
140107
140312
  }
140108
140313
  }
140109
- function asRecord31(value) {
140314
+ function asRecord33(value) {
140110
140315
  if (value && typeof value === "object" && !Array.isArray(value)) {
140111
140316
  return value;
140112
140317
  }
@@ -140121,7 +140326,7 @@ function injectReportData5(html, payload) {
140121
140326
  }
140122
140327
  async function runBingAnalysisRender(opts) {
140123
140328
  const dataPath = path47.resolve(opts.dataFile);
140124
- let data = asRecord31(await readJsonFile6(dataPath));
140329
+ let data = asRecord33(await readJsonFile6(dataPath));
140125
140330
  if (opts.snapshotDir?.trim()) {
140126
140331
  data = await mergeBingAnalysisSnapshotIntoReport(data, path47.resolve(opts.snapshotDir));
140127
140332
  }
@@ -140594,7 +140799,7 @@ import { fileURLToPath as fileURLToPath13 } from "url";
140594
140799
  // src/commands/tiktok-analysis/merge-snapshot.ts
140595
140800
  import * as fs39 from "fs/promises";
140596
140801
  import * as path49 from "path";
140597
- function asRecord32(value) {
140802
+ function asRecord34(value) {
140598
140803
  if (value && typeof value === "object" && !Array.isArray(value)) {
140599
140804
  return value;
140600
140805
  }
@@ -140772,7 +140977,7 @@ function mapAudienceMerged(payload) {
140772
140977
  }
140773
140978
  async function mergeTikTokAnalysisSnapshotIntoReport(payload, snapshotDir) {
140774
140979
  const absDir = path49.resolve(snapshotDir);
140775
- const metaAccountId = typeof asRecord32(payload.meta)?.accountId === "string" ? asRecord32(payload.meta)?.accountId : void 0;
140980
+ const metaAccountId = typeof asRecord34(payload.meta)?.accountId === "string" ? asRecord34(payload.meta)?.accountId : void 0;
140776
140981
  const manifest = await readManifest6(snapshotDir, metaAccountId);
140777
140982
  if (!manifest) {
140778
140983
  throw new Error(
@@ -140886,7 +141091,7 @@ function textLen6(value) {
140886
141091
  function asArray7(value) {
140887
141092
  return Array.isArray(value) ? value : [];
140888
141093
  }
140889
- function asRecord33(value) {
141094
+ function asRecord35(value) {
140890
141095
  if (value && typeof value === "object" && !Array.isArray(value)) {
140891
141096
  return value;
140892
141097
  }
@@ -140897,9 +141102,9 @@ function pushMissing6(missing, id, chapter, dimension, hint) {
140897
141102
  }
140898
141103
  function validateTikTokPeriodReportContent(data) {
140899
141104
  const missing = [];
140900
- const meta = asRecord33(data.meta) ?? {};
140901
- const narrative = asRecord33(data.narrative) ?? {};
140902
- const sections = asRecord33(narrative.sections) ?? {};
141105
+ const meta = asRecord35(data.meta) ?? {};
141106
+ const narrative = asRecord35(data.narrative) ?? {};
141107
+ const sections = asRecord35(narrative.sections) ?? {};
140903
141108
  if (!textLen6(meta.accountId)) {
140904
141109
  pushMissing6(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
140905
141110
  }
@@ -140916,7 +141121,7 @@ function validateTikTokPeriodReportContent(data) {
140916
141121
  const sectionAnalysisCounts = {};
140917
141122
  const sectionSuggestionCounts = {};
140918
141123
  for (const key of SECTION_KEYS3) {
140919
- const section = asRecord33(sections[key]);
141124
+ const section = asRecord35(sections[key]);
140920
141125
  const analysis = asArray7(section?.analysis).filter((s) => textLen6(s) > 0);
140921
141126
  const suggestions = asArray7(section?.suggestions).filter((s) => textLen6(s) > 0);
140922
141127
  sectionAnalysisCounts[key] = analysis.length;
@@ -140942,7 +141147,7 @@ function validateTikTokPeriodReportContent(data) {
140942
141147
  }
140943
141148
  const recommendations = asArray7(narrative.recommendations).filter((r) => {
140944
141149
  if (typeof r === "string") return textLen6(r) > 0;
140945
- const rec = asRecord33(r);
141150
+ const rec = asRecord35(r);
140946
141151
  return textLen6(rec?.content) > 0;
140947
141152
  });
140948
141153
  if (recommendations.length < 3) {
@@ -141003,7 +141208,7 @@ async function readJsonFile7(filePath) {
141003
141208
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
141004
141209
  }
141005
141210
  }
141006
- function asRecord34(value) {
141211
+ function asRecord36(value) {
141007
141212
  if (value && typeof value === "object" && !Array.isArray(value)) {
141008
141213
  return value;
141009
141214
  }
@@ -141018,7 +141223,7 @@ function injectReportData6(html, payload) {
141018
141223
  }
141019
141224
  async function runTikTokAnalysisRender(opts) {
141020
141225
  const dataPath = path50.resolve(opts.dataFile);
141021
- let data = asRecord34(await readJsonFile7(dataPath));
141226
+ let data = asRecord36(await readJsonFile7(dataPath));
141022
141227
  if (opts.snapshotDir?.trim()) {
141023
141228
  data = await mergeTikTokAnalysisSnapshotIntoReport(data, path50.resolve(opts.snapshotDir));
141024
141229
  }
@@ -142117,7 +142322,7 @@ function endpointHintForYandexSection(def) {
142117
142322
  // src/commands/yandex-analysis/merge-snapshot.ts
142118
142323
  import * as fs41 from "fs/promises";
142119
142324
  import * as path51 from "path";
142120
- function asRecord35(value) {
142325
+ function asRecord37(value) {
142121
142326
  if (value && typeof value === "object" && !Array.isArray(value)) {
142122
142327
  return value;
142123
142328
  }
@@ -142137,11 +142342,11 @@ function normalizeYandexRoi(value) {
142137
142342
  return r === -1 ? void 0 : r;
142138
142343
  }
142139
142344
  function asItems(payload) {
142140
- const obj = asRecord35(payload);
142345
+ const obj = asRecord37(payload);
142141
142346
  if (!obj) return [];
142142
142347
  const items3 = obj.items;
142143
142348
  if (!Array.isArray(items3)) return [];
142144
- return items3.filter((r) => asRecord35(r) !== null);
142349
+ return items3.filter((r) => asRecord37(r) !== null);
142145
142350
  }
142146
142351
  function pickMetrics2(row, extras = []) {
142147
142352
  const spend = num12(row.spend) ?? 0;
@@ -142277,7 +142482,7 @@ function aggregateDailyToWeekly(dailyRows) {
142277
142482
  });
142278
142483
  }
142279
142484
  function prepareYandexDailyPayload(payload) {
142280
- const obj = asRecord35(payload) ?? {};
142485
+ const obj = asRecord37(payload) ?? {};
142281
142486
  const items3 = asItems(obj).map((r) => {
142282
142487
  const date = normalizeYandexDailyDate(r.date);
142283
142488
  return date ? { ...r, date } : r;
@@ -142346,7 +142551,7 @@ function mapDeviceRows2(payload) {
142346
142551
  }
142347
142552
  async function mergeYandexAnalysisSnapshotIntoReport(payload, snapshotDir) {
142348
142553
  const absDir = path51.resolve(snapshotDir);
142349
- const metaAccountId = typeof asRecord35(payload.meta)?.accountId === "string" ? asRecord35(payload.meta)?.accountId : void 0;
142554
+ const metaAccountId = typeof asRecord37(payload.meta)?.accountId === "string" ? asRecord37(payload.meta)?.accountId : void 0;
142350
142555
  const manifest = await readManifest7(snapshotDir, metaAccountId);
142351
142556
  if (!manifest) {
142352
142557
  throw new Error(
@@ -142358,8 +142563,8 @@ async function mergeYandexAnalysisSnapshotIntoReport(payload, snapshotDir) {
142358
142563
  const data = await loadSectionPayload3(absDir, art.file);
142359
142564
  if (data != null) sectionMap.set(art.section, data);
142360
142565
  }
142361
- const overview = asRecord35(sectionMap.get("overview"));
142362
- const totals = asRecord35(overview?.totals);
142566
+ const overview = asRecord37(sectionMap.get("overview"));
142567
+ const totals = asRecord37(overview?.totals);
142363
142568
  const accountId = manifest.accountId ?? metaAccountId;
142364
142569
  const meta = { ...payload.meta ?? {} };
142365
142570
  if (!meta.accountId && accountId) meta.accountId = accountId;
@@ -142581,7 +142786,7 @@ function textLen7(value) {
142581
142786
  function asArray8(value) {
142582
142787
  return Array.isArray(value) ? value : [];
142583
142788
  }
142584
- function asRecord36(value) {
142789
+ function asRecord38(value) {
142585
142790
  if (value && typeof value === "object" && !Array.isArray(value)) {
142586
142791
  return value;
142587
142792
  }
@@ -142594,23 +142799,23 @@ function normKey(value) {
142594
142799
  return String(value ?? "").trim().toLowerCase();
142595
142800
  }
142596
142801
  function insightMatchRecord(item) {
142597
- const rec = asRecord36(item);
142802
+ const rec = asRecord38(item);
142598
142803
  if (!rec) return {};
142599
- return asRecord36(rec.match) ?? rec;
142804
+ return asRecord38(rec.match) ?? rec;
142600
142805
  }
142601
142806
  function findRowInsight(list, primaryField, primaryValue, row) {
142602
142807
  const target = normKey(primaryValue);
142603
142808
  if (!target) return null;
142604
142809
  const candidates = list.filter((it) => normKey(insightMatchRecord(it)[primaryField]) === target);
142605
- if (candidates.length <= 1) return asRecord36(candidates[0]);
142810
+ if (candidates.length <= 1) return asRecord38(candidates[0]);
142606
142811
  const campaign = normKey(row.campaignName);
142607
142812
  const narrowed = candidates.find(
142608
142813
  (it) => normKey(insightMatchRecord(it).campaignName) === campaign
142609
142814
  );
142610
- return asRecord36(narrowed ?? candidates[0]);
142815
+ return asRecord38(narrowed ?? candidates[0]);
142611
142816
  }
142612
142817
  function topRowsBySpend(rows, limit) {
142613
- return rows.map((r) => asRecord36(r)).filter((r) => r != null).sort((a, b) => (Number(b.spend) || 0) - (Number(a.spend) || 0)).slice(0, limit);
142818
+ return rows.map((r) => asRecord38(r)).filter((r) => r != null).sort((a, b) => (Number(b.spend) || 0) - (Number(a.spend) || 0)).slice(0, limit);
142614
142819
  }
142615
142820
  var ROW_INSIGHT_SPECS = [
142616
142821
  {
@@ -142625,17 +142830,17 @@ var ROW_INSIGHT_SPECS = [
142625
142830
  ];
142626
142831
  function validateYandexPeriodReportContent(data) {
142627
142832
  const missing = [];
142628
- const meta = asRecord36(data.meta) ?? {};
142629
- const narrative = asRecord36(data.narrative) ?? {};
142630
- const sections = asRecord36(narrative.sections) ?? {};
142631
- const kpis = asRecord36(data.kpis) ?? {};
142833
+ const meta = asRecord38(data.meta) ?? {};
142834
+ const narrative = asRecord38(data.narrative) ?? {};
142835
+ const sections = asRecord38(narrative.sections) ?? {};
142836
+ const kpis = asRecord38(data.kpis) ?? {};
142632
142837
  if (!textLen7(meta.accountId)) {
142633
142838
  pushMissing7(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
142634
142839
  }
142635
142840
  const sectionAnalysisCounts = {};
142636
142841
  const sectionSuggestionCounts = {};
142637
142842
  for (const key of SECTION_KEYS4) {
142638
- const section = asRecord36(sections[key]);
142843
+ const section = asRecord38(sections[key]);
142639
142844
  const analysis = asArray8(section?.analysis).filter((s) => textLen7(s) > 0);
142640
142845
  const suggestions = asArray8(section?.suggestions).filter((s) => textLen7(s) > 0);
142641
142846
  sectionAnalysisCounts[key] = analysis.length;
@@ -142661,7 +142866,7 @@ function validateYandexPeriodReportContent(data) {
142661
142866
  }
142662
142867
  const recommendations = asArray8(narrative.recommendations).filter((r) => {
142663
142868
  if (typeof r === "string") return textLen7(r) > 0;
142664
- const rec = asRecord36(r);
142869
+ const rec = asRecord38(r);
142665
142870
  return textLen7(rec?.content) > 0 || textLen7(rec?.text) > 0;
142666
142871
  });
142667
142872
  if (recommendations.length < 3) {
@@ -142683,8 +142888,8 @@ function validateYandexPeriodReportContent(data) {
142683
142888
  "\u81F3\u5C11\u4E00\u9879\u6709\u6548\u6570\u5B57\uFF08\u8BF7\u4F20 --snapshot-dir \u7531 CLI \u4ECE overview \u5408\u5E76\uFF09"
142684
142889
  );
142685
142890
  }
142686
- const tables = asRecord36(data.tables) ?? {};
142687
- const weeklyRows = asArray8(tables.weekly).map((r) => asRecord36(r)).filter((r) => r != null);
142891
+ const tables = asRecord38(data.tables) ?? {};
142892
+ const weeklyRows = asArray8(tables.weekly).map((r) => asRecord38(r)).filter((r) => r != null);
142688
142893
  for (const [i, row] of weeklyRows.entries()) {
142689
142894
  const label2 = `${row.weekLabel ?? ""} ${row.startDate ?? ""} ${row.endDate ?? ""}`;
142690
142895
  if (/nan/i.test(label2) || !normalizeYandexDailyDate(row.startDate) || !normalizeYandexDailyDate(row.endDate)) {
@@ -142697,7 +142902,7 @@ function validateYandexPeriodReportContent(data) {
142697
142902
  );
142698
142903
  }
142699
142904
  }
142700
- const rowInsights = asRecord36(narrative.rowInsights) ?? {};
142905
+ const rowInsights = asRecord38(narrative.rowInsights) ?? {};
142701
142906
  const rowInsightCoverage = {};
142702
142907
  for (const spec of ROW_INSIGHT_SPECS) {
142703
142908
  const shown = topRowsBySpend(asArray8(tables[spec.tableKey]), spec.limit).filter(
@@ -142777,7 +142982,7 @@ async function readJsonFile8(filePath) {
142777
142982
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
142778
142983
  }
142779
142984
  }
142780
- function asRecord37(value) {
142985
+ function asRecord39(value) {
142781
142986
  if (value && typeof value === "object" && !Array.isArray(value)) {
142782
142987
  return value;
142783
142988
  }
@@ -142805,7 +143010,7 @@ function injectReportData7(html, payload) {
142805
143010
  }
142806
143011
  async function runYandexAnalysisRender(opts) {
142807
143012
  const dataPath = path53.resolve(opts.dataFile);
142808
- let data = asRecord37(await readJsonFile8(dataPath));
143013
+ let data = asRecord39(await readJsonFile8(dataPath));
142809
143014
  if (opts.snapshotDir?.trim()) {
142810
143015
  data = await mergeYandexAnalysisSnapshotIntoReport(data, path53.resolve(opts.snapshotDir));
142811
143016
  }
@@ -143001,7 +143206,7 @@ function unwrapYandexItems(raw) {
143001
143206
  }
143002
143207
  return [];
143003
143208
  }
143004
- function asRecord38(raw) {
143209
+ function asRecord40(raw) {
143005
143210
  return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
143006
143211
  }
143007
143212
 
@@ -143080,7 +143285,7 @@ async function runYandexAccountStatus(opts) {
143080
143285
  } catch (err) {
143081
143286
  fail3("\u67E5\u8BE2 Yandex \u8D26\u6237\u603B\u89C8\u5931\u8D25", err);
143082
143287
  }
143083
- const row = asRecord38(result.raw);
143288
+ const row = asRecord40(result.raw);
143084
143289
  await emitOrTable(opts, {
143085
143290
  section: "yandex-account-status",
143086
143291
  commandLabel: "yandex-analysis account-status",