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

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 asRecord17(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 = asRecord17(data.narrative) ?? {};
103138
103138
  const parts = [];
103139
- const sheetAnalysis = asRecord16(narrative.sheetAnalysis) ?? {};
103139
+ const sheetAnalysis = asRecord17(narrative.sheetAnalysis) ?? {};
103140
103140
  for (const block of Object.values(sheetAnalysis)) {
103141
- const rec = asRecord16(block);
103141
+ const rec = asRecord17(block);
103142
103142
  parts.push(...stringList(rec?.summary), ...stringList(rec?.suggestions));
103143
103143
  }
103144
- const review = asRecord16(narrative.review) ?? {};
103144
+ const review = asRecord17(narrative.review) ?? {};
103145
103145
  for (const block of Object.values(review)) {
103146
- const rec = asRecord16(block);
103146
+ const rec = asRecord17(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 asRecord18(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) => asRecord18(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 asRecord18(payload.meta)?.accountId === "string" ? asRecord18(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(asRecord18(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 = asRecord18(overviewRecord?.currentPeriod);
103322
+ const previousPeriod = asRecord18(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 asRecord19(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 = asRecord19(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 = asRecord19(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 = asRecord19(data.narrative) ?? {};
103508
+ const sheetAnalysis = asRecord19(narrative.sheetAnalysis) ?? {};
103509
+ const review = asRecord19(narrative.review) ?? {};
103510
103510
  const sheetAnalysisCounts = {};
103511
103511
  for (const key of OKKI_SHEET_KEYS) {
103512
- const block = asRecord18(sheetAnalysis[key]);
103512
+ const block = asRecord19(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 = asRecord19(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) => asRecord19(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) => asRecord19(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 asRecord19(payload.meta)?.accountId === "string" ? asRecord19(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(asRecord19(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 = asRecord19(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 = asRecord19(asRecord19(data.narrative)?.sheetAnalysis)?.[key];
103883
+ const rec = asRecord19(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 = asRecord19(asRecord19(data.narrative)?.review) ?? {};
103891
103891
  const lines = [];
103892
103892
  OKKI_REVIEW_KEYS.forEach((key, idx) => {
103893
- const block = asRecord18(review[key]) ?? {};
103893
+ const block = asRecord19(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 = asRecord19(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 asRecord20(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 = asRecord20(data.meta) ?? {};
104298
+ const narrative = asRecord20(data.narrative) ?? {};
104299
+ const sections = asRecord20(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 = asRecord20(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 = asRecord20(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 = asRecord20(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 asRecord21(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 = asRecord21(await readJsonFile3(dataPath));
104466
104466
  if (opts.snapshotDir?.trim()) {
104467
104467
  data = await mergeGoogleAnalysisSnapshotIntoReport(data, path35.resolve(opts.snapshotDir));
104468
104468
  }
@@ -133427,7 +133427,7 @@ function buildGoogleAdsDiagnosisCollectAgentHint(snapDir) {
133427
133427
  "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
133428
  `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
133429
  `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",
133430
+ "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
133431
  `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
133432
  `\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
133433
  "\u7981\u6B62\u5199\u5165/\u8986\u76D6 campaigns/geographic/keywords \u7684 items \u884C\uFF0C\u53EA\u586B analysis/suggestions\u3002",
@@ -133494,7 +133494,7 @@ function buildGoogleAdsDiagnosisAgentBrief(input) {
133494
133494
  },
133495
133495
  agentDeliverable: {
133496
133496
  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",
133497
+ 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
133498
  thenRun: "siluzan-tso google-ads-diagnosis render --data ./<snap>/google-ads-diagnosis.json --out ./<snap>/google-ads-diagnosis-report.html"
133499
133499
  }
133500
133500
  };
@@ -134319,7 +134319,7 @@ function describeSectionShapes(reportData) {
134319
134319
  function narrativeChecklist(shapes) {
134320
134320
  const lines = [
134321
134321
  "- `accountInfo.businessModel`\u3001`accountInfo.industry`",
134322
- "- `diagnosisOverview.advantages`\u3001`diagnosisOverview.disadvantages`",
134322
+ '- `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
134323
  "- `summary.keyIssues`\u3001`summary.optimizationRoadmap`"
134324
134324
  ];
134325
134325
  for (const shape of shapes) {
@@ -134720,6 +134720,26 @@ function validateNewFeatureRecommendations(data) {
134720
134720
  }
134721
134721
  return warnings;
134722
134722
  }
134723
+ function validateDiagnosisOverviewItems(data) {
134724
+ const overview = asRecord10(data.diagnosisOverview);
134725
+ if (!overview) return [];
134726
+ const warnings = [];
134727
+ for (const key of ["advantages", "disadvantages"]) {
134728
+ const items3 = overview[key];
134729
+ if (!Array.isArray(items3)) continue;
134730
+ items3.forEach((item, index) => {
134731
+ const row = asRecord10(item);
134732
+ const title = String(row?.title ?? "").trim();
134733
+ const description = String(row?.description ?? "").trim();
134734
+ if (!title || !description) {
134735
+ warnings.push(
134736
+ `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`
134737
+ );
134738
+ }
134739
+ });
134740
+ }
134741
+ return warnings;
134742
+ }
134723
134743
  function validateAdCreativeItemSuggestions(data) {
134724
134744
  const creative = asRecord10(data.adCreativeOptimization);
134725
134745
  if (!creative) return [];
@@ -134752,6 +134772,7 @@ function validateGoogleAdsDiagnosisContent(data) {
134752
134772
  }
134753
134773
  }
134754
134774
  warnings.push(
134775
+ ...validateDiagnosisOverviewItems(data),
134755
134776
  ...validateBudgetCompetitivenessStrategies(data),
134756
134777
  ...validateNewFeatureRecommendations(data),
134757
134778
  ...validateAdCreativeItemSuggestions(data)
@@ -135063,8 +135084,75 @@ function getNarrativeConsistencyErrors(data) {
135063
135084
  return errors;
135064
135085
  }
135065
135086
 
135066
- // src/commands/google-ads-diagnosis/render-report.ts
135087
+ // src/commands/google-ads-diagnosis/overview-items.ts
135067
135088
  function asRecord13(value) {
135089
+ if (value && typeof value === "object" && !Array.isArray(value)) {
135090
+ return value;
135091
+ }
135092
+ return null;
135093
+ }
135094
+ function proseColonIndex(text2) {
135095
+ const cn = text2.indexOf("\uFF1A");
135096
+ if (cn > 0 && cn < text2.length - 1) return cn;
135097
+ for (let i = 1; i < text2.length - 1; i++) {
135098
+ if (text2[i] !== ":") continue;
135099
+ if (text2[i + 1] === "/") continue;
135100
+ const scheme = text2.slice(Math.max(0, i - 5), i);
135101
+ if (/https?$/i.test(scheme)) continue;
135102
+ return i;
135103
+ }
135104
+ return -1;
135105
+ }
135106
+ function splitOverviewProse(text2) {
135107
+ const trimmed = text2.trim();
135108
+ const cut = proseColonIndex(trimmed);
135109
+ if (cut > 0) {
135110
+ const title = trimmed.slice(0, cut).trim();
135111
+ const description = trimmed.slice(cut + 1).trim();
135112
+ if (title && description) return { title, description };
135113
+ }
135114
+ return { title: trimmed, description: trimmed };
135115
+ }
135116
+ function normalizeOverviewItem(item) {
135117
+ if (typeof item === "string" || typeof item === "number") {
135118
+ const text2 = String(item).trim();
135119
+ if (!text2) return null;
135120
+ return splitOverviewProse(text2);
135121
+ }
135122
+ const rec = asRecord13(item);
135123
+ if (!rec) return null;
135124
+ const title = String(rec.title ?? "").trim();
135125
+ const description = String(rec.description ?? "").trim();
135126
+ if (title && description) return { title, description };
135127
+ const prose = title || description;
135128
+ if (!prose) return null;
135129
+ const split = splitOverviewProse(prose);
135130
+ return {
135131
+ title: title || split.title,
135132
+ description: description || split.description
135133
+ };
135134
+ }
135135
+ function normalizeDiagnosisOverview(data) {
135136
+ const overview = asRecord13(data.diagnosisOverview);
135137
+ if (!overview) return { data, coerced: [] };
135138
+ const coerced = [];
135139
+ const nextOverview = { ...overview };
135140
+ for (const key of ["advantages", "disadvantages"]) {
135141
+ const items3 = overview[key];
135142
+ if (!Array.isArray(items3)) continue;
135143
+ nextOverview[key] = items3.map((item) => {
135144
+ if (typeof item === "string" || typeof item === "number") coerced.push(key);
135145
+ return normalizeOverviewItem(item) ?? { title: "", description: "" };
135146
+ });
135147
+ }
135148
+ return {
135149
+ data: { ...data, diagnosisOverview: nextOverview },
135150
+ coerced
135151
+ };
135152
+ }
135153
+
135154
+ // src/commands/google-ads-diagnosis/render-report.ts
135155
+ function asRecord14(value) {
135068
135156
  if (value && typeof value === "object" && !Array.isArray(value)) {
135069
135157
  return value;
135070
135158
  }
@@ -135073,8 +135161,8 @@ function asRecord13(value) {
135073
135161
  async function tryLoadCollectReportData(collectPath) {
135074
135162
  try {
135075
135163
  const raw = JSON.parse(await fs22.readFile(collectPath, "utf8"));
135076
- const root = asRecord13(raw);
135077
- const reportData = asRecord13(root?.reportData);
135164
+ const root = asRecord14(raw);
135165
+ const reportData = asRecord14(root?.reportData);
135078
135166
  return reportData ?? root;
135079
135167
  } catch {
135080
135168
  return null;
@@ -135091,7 +135179,7 @@ async function runGoogleAdsDiagnosisRender(opts) {
135091
135179
  `);
135092
135180
  process.exit(1);
135093
135181
  }
135094
- let data = asRecord13(dataRaw);
135182
+ let data = asRecord14(dataRaw);
135095
135183
  if (!opts.noMergeCollect) {
135096
135184
  const collectPath = path26.resolve(
135097
135185
  opts.collectFile ?? path26.join(path26.dirname(dataPath), GOOGLE_ADS_DIAGNOSIS_COLLECT_BASENAME)
@@ -135123,6 +135211,16 @@ async function runGoogleAdsDiagnosisRender(opts) {
135123
135211
  }
135124
135212
  }
135125
135213
  }
135214
+ const overview = normalizeDiagnosisOverview(data);
135215
+ data = overview.data;
135216
+ if (overview.coerced.length > 0) {
135217
+ const fields = [...new Set(overview.coerced)].join("\u3001");
135218
+ console.log(
135219
+ `
135220
+ \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
135221
+ `
135222
+ );
135223
+ }
135126
135224
  const narrativeErrors = getNarrativeConsistencyErrors(data);
135127
135225
  if (narrativeErrors.length > 0) {
135128
135226
  console.error("\n\u274C \u53D9\u4E8B\u6587\u6848\u4E0E\u4E8B\u5B9E\u5B57\u6BB5\u77DB\u76FE\uFF0C\u7981\u6B62\u6E32\u67D3\uFF1A\n");
@@ -136421,26 +136519,26 @@ import fs26 from "fs/promises";
136421
136519
  import path31 from "path";
136422
136520
 
136423
136521
  // src/commands/google-quarterly/report-content.ts
136424
- function asRecord14(value) {
136522
+ function asRecord15(value) {
136425
136523
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
136426
136524
  }
136427
136525
  function asStringArray(value) {
136428
136526
  return Array.isArray(value) ? value.map((x) => String(x).trim()).filter(Boolean) : [];
136429
136527
  }
136430
136528
  function validateQuarterlyNarrative(data) {
136431
- const root = asRecord14(data);
136432
- const narrative = asRecord14(root?.narrative);
136529
+ const root = asRecord15(data);
136530
+ const narrative = asRecord15(root?.narrative);
136433
136531
  const missing = [];
136434
136532
  if (!narrative) {
136435
136533
  return { ok: false, missing: ["narrative"] };
136436
136534
  }
136437
136535
  if (asStringArray(narrative.executiveSummary).length < 1) missing.push("narrative.executiveSummary");
136438
- const sections = asRecord14(narrative.sections);
136536
+ const sections = asRecord15(narrative.sections);
136439
136537
  for (const key of ["efficiency", "adType", "region", "summary"]) {
136440
- const block = asRecord14(sections?.[key]);
136538
+ const block = asRecord15(sections?.[key]);
136441
136539
  if (asStringArray(block?.analysis).length < 1) missing.push(`narrative.sections.${key}.analysis`);
136442
136540
  }
136443
- const plan = asRecord14(narrative.plan);
136541
+ const plan = asRecord15(narrative.plan);
136444
136542
  if (asStringArray(plan?.analysis ?? plan?.goals).length < 1 && !String(plan?.text ?? "").trim()) {
136445
136543
  missing.push("narrative.plan");
136446
136544
  }
@@ -136453,8 +136551,8 @@ function mergeCollectFacts(agentData, collect) {
136453
136551
  ...facts,
136454
136552
  narrative: agentData.narrative ?? collect.narrative,
136455
136553
  meta: {
136456
- ...asRecord14(collect.meta) ?? {},
136457
- ...asRecord14(agentData.meta) ?? {}
136554
+ ...asRecord15(collect.meta) ?? {},
136555
+ ...asRecord15(agentData.meta) ?? {}
136458
136556
  }
136459
136557
  };
136460
136558
  }
@@ -136466,7 +136564,7 @@ import { fileURLToPath as fileURLToPath8 } from "url";
136466
136564
  var TSO_CLI_ROOT = path30.join(path30.dirname(fileURLToPath8(import.meta.url)), "../..");
136467
136565
 
136468
136566
  // src/commands/google-quarterly/render-report.ts
136469
- function asRecord15(value) {
136567
+ function asRecord16(value) {
136470
136568
  if (value && typeof value === "object" && !Array.isArray(value)) {
136471
136569
  return value;
136472
136570
  }
@@ -136495,7 +136593,7 @@ async function runGoogleQuarterlyRender(opts) {
136495
136593
  `);
136496
136594
  process.exit(1);
136497
136595
  }
136498
- const merged = mergeCollectFacts(asRecord15(agentRaw), asRecord15(collectRaw));
136596
+ const merged = mergeCollectFacts(asRecord16(agentRaw), asRecord16(collectRaw));
136499
136597
  const check = validateQuarterlyNarrative(merged);
136500
136598
  if (!check.ok && !opts.lenient) {
136501
136599
  console.error("\n\u274C narrative \u4E0D\u5B8C\u6574\uFF0C\u62D2\u7EDD\u51FA HTML\uFF1A\n");
@@ -136659,7 +136757,7 @@ import * as fs33 from "fs/promises";
136659
136757
  import * as path40 from "path";
136660
136758
 
136661
136759
  // src/commands/facebook-analysis/report-metrics.ts
136662
- function asRecord21(value) {
136760
+ function asRecord22(value) {
136663
136761
  if (value && typeof value === "object" && !Array.isArray(value)) {
136664
136762
  return value;
136665
136763
  }
@@ -136796,7 +136894,7 @@ function localizeFacebookReportLabels(payload) {
136796
136894
  for (const rows of Object.values(tables)) {
136797
136895
  if (!Array.isArray(rows)) continue;
136798
136896
  for (const row of rows) {
136799
- localizeMetricLabels(asRecord21(row));
136897
+ localizeMetricLabels(asRecord22(row));
136800
136898
  }
136801
136899
  }
136802
136900
  return payload;
@@ -136829,7 +136927,7 @@ async function readManifest3(snapshotDir) {
136829
136927
  async function loadSectionFile3(snapshotDir, file) {
136830
136928
  try {
136831
136929
  const raw = await fs33.readFile(path40.join(snapshotDir, file), "utf8");
136832
- return asRecord21(JSON.parse(raw));
136930
+ return asRecord22(JSON.parse(raw));
136833
136931
  } catch {
136834
136932
  return null;
136835
136933
  }
@@ -136885,7 +136983,7 @@ async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
136885
136983
  if (data) sectionMap.set(art.section, data);
136886
136984
  }
136887
136985
  const overview = sectionMap.get("overview");
136888
- const current = asRecord21(overview?.currentPeriod);
136986
+ const current = asRecord22(overview?.currentPeriod);
136889
136987
  const accountName = typeof overview?.accountName === "string" ? overview.accountName : void 0;
136890
136988
  const accountId = manifest.accountId ?? (typeof overview?.accountId === "string" ? overview.accountId : void 0);
136891
136989
  const kpis = { ...payload.kpis ?? {} };
@@ -137022,7 +137120,7 @@ function writeSimpleXlsx(filePath, sheets, opts = {}) {
137022
137120
  }
137023
137121
 
137024
137122
  // src/commands/facebook-analysis/render-excel.ts
137025
- function asRecord22(value) {
137123
+ function asRecord23(value) {
137026
137124
  if (value && typeof value === "object" && !Array.isArray(value)) {
137027
137125
  return value;
137028
137126
  }
@@ -137070,8 +137168,8 @@ function bullets(value) {
137070
137168
  return asArray3(value).map((item) => typeof item === "string" ? item.trim() : "").filter(Boolean);
137071
137169
  }
137072
137170
  function insightLines(section) {
137073
- const rec = asRecord22(section);
137074
- const insight = asRecord22(rec?.insight) ?? rec;
137171
+ const rec = asRecord23(section);
137172
+ const insight = asRecord23(rec?.insight) ?? rec;
137075
137173
  return [...bullets(insight?.analysis), ...bullets(insight?.advice)];
137076
137174
  }
137077
137175
  function numberedSection(index, title, lines) {
@@ -137080,15 +137178,15 @@ function numberedSection(index, title, lines) {
137080
137178
  ${body}`;
137081
137179
  }
137082
137180
  function buildSummaryNarrative(data) {
137083
- const kpis = asRecord22(data.kpis) ?? {};
137084
- const meta = asRecord22(data.meta) ?? {};
137085
- const sections = asRecord22(data.sections) ?? {};
137181
+ const kpis = asRecord23(data.kpis) ?? {};
137182
+ const meta = asRecord23(data.meta) ?? {};
137183
+ const sections = asRecord23(data.sections) ?? {};
137086
137184
  const period = str2(meta.periodLabel) || `${str2(meta.startDate)} ~ ${str2(meta.endDate)}`.trim();
137087
137185
  const account = str2(meta.accountName) || "Facebook \u5E7F\u544A\u8D26\u6237";
137088
137186
  const campaign = str2(meta.campaignName);
137089
137187
  const resultLabel = displayResultType(kpis.resultType ?? meta.resultType) || "\u6210\u6548";
137090
137188
  const resultNoun = /潜在客户|lead/i.test(resultLabel) ? "\u4E2A\u6F5C\u5728\u5BA2\u6237\u8868\u5355" : `\u4E2A${resultLabel}`;
137091
- const firstQuestion = asRecord22(asArray3(data.fourQuestions)[0]);
137189
+ const firstQuestion = asRecord23(asArray3(data.fourQuestions)[0]);
137092
137190
  const extra = str2(firstQuestion?.verdict);
137093
137191
  const spendLine = [
137094
137192
  campaign ? `\uFF08\u5E7F\u544A\u7CFB\u5217\uFF1A${campaign}\uFF09` : "",
@@ -137108,7 +137206,7 @@ function buildSummaryNarrative(data) {
137108
137206
  numberedSection(3, "\u5E7F\u544A\u9891\u6B21\u4E0E\u65E5\u8D8B\u52BF", insightLines(sections.daily))
137109
137207
  ].join("\n");
137110
137208
  const recBlocks = asArray3(data.recommendations).map((raw, i) => {
137111
- const rec = asRecord22(raw);
137209
+ const rec = asRecord23(raw);
137112
137210
  if (!rec) return "";
137113
137211
  const title = [str2(rec.title), str2(rec.tag)].filter(Boolean).join(" \xB7 ");
137114
137212
  return numberedSection(i + 1, title || "\u4F18\u5316\u5EFA\u8BAE", bullets(rec.items));
@@ -137119,9 +137217,9 @@ function buildSummaryNarrative(data) {
137119
137217
  return [partOne, partTwo, partThree];
137120
137218
  }
137121
137219
  function buildMetaPeriodExcelSheets(data) {
137122
- const meta = asRecord22(data.meta) ?? {};
137123
- const kpis = asRecord22(data.kpis) ?? {};
137124
- const tables = asRecord22(data.tables) ?? {};
137220
+ const meta = asRecord23(data.meta) ?? {};
137221
+ const kpis = asRecord23(data.kpis) ?? {};
137222
+ const tables = asRecord23(data.tables) ?? {};
137125
137223
  const currency = str2(meta.currency) || "USD";
137126
137224
  const resultType = displayResultType(kpis.resultType ?? meta.resultType);
137127
137225
  const attribution = displayAttribution(kpis.attributionSetting ?? meta.attributionSetting);
@@ -137140,19 +137238,19 @@ function buildMetaPeriodExcelSheets(data) {
137140
137238
  ];
137141
137239
  const dailyRows = [metricHeaders(currency, "\u5355\u65E5")];
137142
137240
  for (const raw of asArray3(tables.daily)) {
137143
- const row = asRecord22(raw);
137241
+ const row = asRecord23(raw);
137144
137242
  if (!row) continue;
137145
137243
  dailyRows.push([normalizeInsightDate(row.date), ...metricCells(row)]);
137146
137244
  }
137147
137245
  const countryRows = [metricHeaders(currency, "\u56FD\u5BB6/\u5730\u533A")];
137148
137246
  for (const raw of asArray3(tables.countries)) {
137149
- const row = asRecord22(raw);
137247
+ const row = asRecord23(raw);
137150
137248
  if (!row) continue;
137151
137249
  countryRows.push([str2(row.countryOrRegion), ...metricCells(row)]);
137152
137250
  }
137153
137251
  const campaignRows3 = [metricHeaders(currency, "\u5E7F\u544A\u7CFB\u5217\u540D\u79F0")];
137154
137252
  for (const raw of asArray3(tables.campaigns)) {
137155
- const row = asRecord22(raw);
137253
+ const row = asRecord23(raw);
137156
137254
  if (!row) continue;
137157
137255
  campaignRows3.push([str2(row.campaignName), ...metricCells(row)]);
137158
137256
  }
@@ -137171,7 +137269,7 @@ function buildMetaPeriodExcelSheets(data) {
137171
137269
  ]
137172
137270
  ];
137173
137271
  for (const raw of asArray3(tables.audiences)) {
137174
- const row = asRecord22(raw);
137272
+ const row = asRecord23(raw);
137175
137273
  if (!row) continue;
137176
137274
  audienceRows.push([str2(row.age), str2(row.gender), ...metricCells(row)]);
137177
137275
  }
@@ -137203,7 +137301,7 @@ function isFiniteNumber(value) {
137203
137301
  function asArray4(value) {
137204
137302
  return Array.isArray(value) ? value : [];
137205
137303
  }
137206
- function asRecord23(value) {
137304
+ function asRecord24(value) {
137207
137305
  if (value && typeof value === "object" && !Array.isArray(value)) {
137208
137306
  return value;
137209
137307
  }
@@ -137216,8 +137314,8 @@ function stringList3(value) {
137216
137314
  return asArray4(value).map((item) => typeof item === "string" ? item.trim() : "").filter(Boolean);
137217
137315
  }
137218
137316
  function insightLists(section) {
137219
- const rec = asRecord23(section);
137220
- const insight = asRecord23(rec?.insight) ?? rec;
137317
+ const rec = asRecord24(section);
137318
+ const insight = asRecord24(rec?.insight) ?? rec;
137221
137319
  return {
137222
137320
  analysis: stringList3(insight?.analysis),
137223
137321
  advice: stringList3(insight?.advice)
@@ -137247,11 +137345,11 @@ function requireInsight(missing, key, chapter, section, required) {
137247
137345
  }
137248
137346
  function validateMetaPeriodReportContent(data) {
137249
137347
  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) ?? {};
137348
+ const meta = asRecord24(data.meta) ?? {};
137349
+ const kpis = asRecord24(data.kpis) ?? {};
137350
+ const tables = asRecord24(data.tables) ?? {};
137351
+ const charts = asRecord24(data.charts) ?? {};
137352
+ const sections = asRecord24(data.sections) ?? {};
137255
137353
  const fourQuestions = asArray4(data.fourQuestions);
137256
137354
  const recommendations = asArray4(data.recommendations);
137257
137355
  if (!textLen3(meta.accountName) && !textLen3(meta.accountId)) {
@@ -137330,7 +137428,7 @@ function validateMetaPeriodReportContent(data) {
137330
137428
  "\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
137429
  );
137332
137430
  }
137333
- const dailyChart = asRecord23(charts.daily);
137431
+ const dailyChart = asRecord24(charts.daily);
137334
137432
  if (!Array.isArray(dailyChart?.labels)) {
137335
137433
  pushMissing3(
137336
137434
  missing,
@@ -137340,7 +137438,7 @@ function validateMetaPeriodReportContent(data) {
137340
137438
  "\u987B\u6709 charts.daily.labels \u6570\u7EC4\uFF1B\u53EF\u7531 --snapshot-dir \u5408\u5E76 daily\u3002\u672C\u671F\u65E0\u6D88\u8017\u53EF\u4E3A []"
137341
137439
  );
137342
137440
  }
137343
- const countryChart = asRecord23(charts.country);
137441
+ const countryChart = asRecord24(charts.country);
137344
137442
  if (!Array.isArray(countryChart?.labels)) {
137345
137443
  pushMissing3(
137346
137444
  missing,
@@ -137350,7 +137448,7 @@ function validateMetaPeriodReportContent(data) {
137350
137448
  "\u987B\u6709 charts.country.labels \u6570\u7EC4\uFF1B\u53EF\u7531 --snapshot-dir \u5408\u5E76 country\u3002\u672C\u671F\u65E0\u6D88\u8017\u53EF\u4E3A []"
137351
137449
  );
137352
137450
  }
137353
- const audienceChart = asRecord23(charts.audience);
137451
+ const audienceChart = asRecord24(charts.audience);
137354
137452
  if (!Array.isArray(audienceChart?.labels)) {
137355
137453
  pushMissing3(
137356
137454
  missing,
@@ -137369,7 +137467,7 @@ function validateMetaPeriodReportContent(data) {
137369
137467
  "\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
137468
  );
137371
137469
  } else {
137372
- const titles = fourQuestions.map((q) => asRecord23(q)?.title);
137470
+ const titles = fourQuestions.map((q) => asRecord24(q)?.title);
137373
137471
  for (const title of FOUR_QUESTION_TITLES) {
137374
137472
  if (!titles.includes(title)) {
137375
137473
  pushMissing3(
@@ -137382,7 +137480,7 @@ function validateMetaPeriodReportContent(data) {
137382
137480
  }
137383
137481
  }
137384
137482
  for (let i = 0; i < fourQuestions.length; i++) {
137385
- const q = asRecord23(fourQuestions[i]);
137483
+ const q = asRecord24(fourQuestions[i]);
137386
137484
  if (textLen3(q?.verdict) < 8) {
137387
137485
  pushMissing3(
137388
137486
  missing,
@@ -137422,7 +137520,7 @@ function validateMetaPeriodReportContent(data) {
137422
137520
  );
137423
137521
  } else {
137424
137522
  for (let i = 0; i < recommendations.length; i++) {
137425
- const rec = asRecord23(recommendations[i]);
137523
+ const rec = asRecord24(recommendations[i]);
137426
137524
  if (textLen3(rec?.title) < 2) {
137427
137525
  pushMissing3(
137428
137526
  missing,
@@ -137515,7 +137613,7 @@ async function readJsonFile4(filePath) {
137515
137613
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
137516
137614
  }
137517
137615
  }
137518
- function asRecord24(value) {
137616
+ function asRecord25(value) {
137519
137617
  if (value && typeof value === "object" && !Array.isArray(value)) {
137520
137618
  return value;
137521
137619
  }
@@ -137544,7 +137642,7 @@ function defaultOutPath(dataPath, format, out) {
137544
137642
  }
137545
137643
  async function runFacebookAnalysisRender(opts) {
137546
137644
  const dataPath = path41.resolve(opts.dataFile);
137547
- let data = asRecord24(await readJsonFile4(dataPath));
137645
+ let data = asRecord25(await readJsonFile4(dataPath));
137548
137646
  if (opts.snapshotDir?.trim()) {
137549
137647
  data = await mergeFacebookSnapshotIntoReport(data, path41.resolve(opts.snapshotDir));
137550
137648
  }
@@ -137608,7 +137706,7 @@ import { fileURLToPath as fileURLToPath11 } from "url";
137608
137706
  // src/commands/facebook-analysis/diagnosis-merge-snapshot.ts
137609
137707
  import * as fs35 from "fs/promises";
137610
137708
  import * as path42 from "path";
137611
- function asRecord25(value) {
137709
+ function asRecord26(value) {
137612
137710
  if (value && typeof value === "object" && !Array.isArray(value)) {
137613
137711
  return value;
137614
137712
  }
@@ -137619,7 +137717,7 @@ function num8(value) {
137619
137717
  return Number.isFinite(n) ? n : void 0;
137620
137718
  }
137621
137719
  function asRows(value) {
137622
- return Array.isArray(value) ? value.filter((r) => asRecord25(r) !== null) : [];
137720
+ return Array.isArray(value) ? value.filter((r) => asRecord26(r) !== null) : [];
137623
137721
  }
137624
137722
  function pickMetricExtras(row, extras) {
137625
137723
  const out = {
@@ -137668,14 +137766,14 @@ async function readManifest4(snapshotDir, accountId) {
137668
137766
  async function loadSectionFile4(snapshotDir, file) {
137669
137767
  try {
137670
137768
  const raw = await fs35.readFile(path42.join(snapshotDir, file), "utf8");
137671
- return asRecord25(JSON.parse(raw));
137769
+ return asRecord26(JSON.parse(raw));
137672
137770
  } catch {
137673
137771
  return null;
137674
137772
  }
137675
137773
  }
137676
137774
  async function mergeMetaDiagnosisSnapshotIntoReport(payload, snapshotDir) {
137677
137775
  const absDir = path42.resolve(snapshotDir);
137678
- const metaAccountId = typeof asRecord25(payload.meta)?.accountId === "string" ? asRecord25(payload.meta)?.accountId : void 0;
137776
+ const metaAccountId = typeof asRecord26(payload.meta)?.accountId === "string" ? asRecord26(payload.meta)?.accountId : void 0;
137679
137777
  const manifest = await readManifest4(snapshotDir, metaAccountId);
137680
137778
  if (!manifest) {
137681
137779
  throw new Error(
@@ -137688,8 +137786,8 @@ async function mergeMetaDiagnosisSnapshotIntoReport(payload, snapshotDir) {
137688
137786
  if (data) sectionMap.set(art.section, data);
137689
137787
  }
137690
137788
  const overview = sectionMap.get("overview");
137691
- const currentPeriod = asRecord25(overview?.currentPeriod);
137692
- const previousPeriod = asRecord25(overview?.previousPeriod);
137789
+ const currentPeriod = asRecord26(overview?.currentPeriod);
137790
+ const previousPeriod = asRecord26(overview?.previousPeriod);
137693
137791
  const accountId = manifest.accountId ?? metaAccountId;
137694
137792
  const meta = { ...payload.meta ?? {} };
137695
137793
  if (!meta.accountId && accountId) meta.accountId = accountId;
@@ -137823,7 +137921,7 @@ function textLen4(value) {
137823
137921
  function asArray5(value) {
137824
137922
  return Array.isArray(value) ? value : [];
137825
137923
  }
137826
- function asRecord26(value) {
137924
+ function asRecord27(value) {
137827
137925
  if (value && typeof value === "object" && !Array.isArray(value)) {
137828
137926
  return value;
137829
137927
  }
@@ -137834,9 +137932,9 @@ function pushMissing4(missing, id, chapter, dimension, hint) {
137834
137932
  }
137835
137933
  function validateMetaDiagnosisReportContent(data) {
137836
137934
  const missing = [];
137837
- const meta = asRecord26(data.meta) ?? {};
137838
- const narrative = asRecord26(data.narrative) ?? {};
137839
- const sections = asRecord26(narrative.sections) ?? {};
137935
+ const meta = asRecord27(data.meta) ?? {};
137936
+ const narrative = asRecord27(data.narrative) ?? {};
137937
+ const sections = asRecord27(narrative.sections) ?? {};
137840
137938
  if (!textLen4(meta.accountId)) {
137841
137939
  pushMissing4(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
137842
137940
  }
@@ -137854,7 +137952,7 @@ function validateMetaDiagnosisReportContent(data) {
137854
137952
  const sectionSuggestionCounts = {};
137855
137953
  const sectionNotAvailable = {};
137856
137954
  for (const key of NORMAL_SECTION_KEYS) {
137857
- const section = asRecord26(sections[key]);
137955
+ const section = asRecord27(sections[key]);
137858
137956
  const analysis = asArray5(section?.analysis).filter((s) => textLen4(s) > 0);
137859
137957
  const suggestions = asArray5(section?.suggestions).filter((s) => textLen4(s) > 0);
137860
137958
  sectionAnalysisCounts[key] = analysis.length;
@@ -137880,7 +137978,7 @@ function validateMetaDiagnosisReportContent(data) {
137880
137978
  }
137881
137979
  }
137882
137980
  for (const key of NA_SECTION_KEYS) {
137883
- const section = asRecord26(sections[key]);
137981
+ const section = asRecord27(sections[key]);
137884
137982
  const analysis = asArray5(section?.analysis).filter((s) => textLen4(s) > 0);
137885
137983
  const suggestions = asArray5(section?.suggestions).filter((s) => textLen4(s) > 0);
137886
137984
  const notAvailable = section?.notAvailable === true;
@@ -137902,7 +138000,7 @@ function validateMetaDiagnosisReportContent(data) {
137902
138000
  }
137903
138001
  const recommendations = asArray5(narrative.recommendations).filter((r) => {
137904
138002
  if (typeof r === "string") return textLen4(r) > 0;
137905
- const rec = asRecord26(r);
138003
+ const rec = asRecord27(r);
137906
138004
  return textLen4(rec?.content) > 0;
137907
138005
  });
137908
138006
  if (recommendations.length < 3) {
@@ -137975,7 +138073,7 @@ async function readJsonFile5(filePath) {
137975
138073
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
137976
138074
  }
137977
138075
  }
137978
- function asRecord27(value) {
138076
+ function asRecord28(value) {
137979
138077
  if (value && typeof value === "object" && !Array.isArray(value)) {
137980
138078
  return value;
137981
138079
  }
@@ -137990,7 +138088,7 @@ function injectReportData4(html, payload) {
137990
138088
  }
137991
138089
  async function runFacebookAnalysisDiagnosisRender(opts) {
137992
138090
  const dataPath = path43.resolve(opts.dataFile);
137993
- let data = asRecord27(await readJsonFile5(dataPath));
138091
+ let data = asRecord28(await readJsonFile5(dataPath));
137994
138092
  if (opts.snapshotDir?.trim()) {
137995
138093
  data = await mergeMetaDiagnosisSnapshotIntoReport(data, path43.resolve(opts.snapshotDir));
137996
138094
  }
@@ -138189,7 +138287,7 @@ function resolveFacebookPageSize(raw, fallback = FB_ENTITY_PAGE_SIZE_DEFAULT) {
138189
138287
  if (!Number.isFinite(n) || n <= 0) return fallback;
138190
138288
  return Math.min(Math.max(Math.floor(n), 1), FB_ENTITY_PAGE_SIZE_MAX);
138191
138289
  }
138192
- function asRecord28(value) {
138290
+ function asRecord29(value) {
138193
138291
  return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
138194
138292
  }
138195
138293
  function pickProp(obj, ...keys) {
@@ -138199,12 +138297,12 @@ function pickProp(obj, ...keys) {
138199
138297
  return void 0;
138200
138298
  }
138201
138299
  function unwrapFacebookPaged(raw) {
138202
- const rec = asRecord28(raw);
138300
+ const rec = asRecord29(raw);
138203
138301
  if (!rec) return { items: [] };
138204
138302
  const data = pickProp(rec, "data", "Data");
138205
138303
  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;
138304
+ const paging = asRecord29(pickProp(rec, "paging", "Paging"));
138305
+ const cursors = paging ? asRecord29(pickProp(paging, "cursors", "Cursors")) : void 0;
138208
138306
  const afterRaw = cursors ? pickProp(cursors, "after", "After") : void 0;
138209
138307
  const after = typeof afterRaw === "string" && afterRaw.trim() ? afterRaw.trim() : void 0;
138210
138308
  return { items: items3, after };
@@ -138352,7 +138450,7 @@ async function fetchFacebookInsights(config, digits, level, opts) {
138352
138450
  opts.verbose
138353
138451
  );
138354
138452
  if (Array.isArray(raw)) return raw;
138355
- const rec = asRecord28(raw);
138453
+ const rec = asRecord29(raw);
138356
138454
  const data = rec ? pickProp(rec, "data", "Data") : void 0;
138357
138455
  return Array.isArray(data) ? data : [];
138358
138456
  }
@@ -138361,7 +138459,7 @@ function sumActionArray(raw) {
138361
138459
  let sum = 0;
138362
138460
  let hit = false;
138363
138461
  for (const item of raw) {
138364
- const rec = asRecord28(item);
138462
+ const rec = asRecord29(item);
138365
138463
  if (!rec) continue;
138366
138464
  const n = Number(rec.value);
138367
138465
  if (!Number.isFinite(n)) continue;
@@ -139640,7 +139738,7 @@ import { fileURLToPath as fileURLToPath12 } from "url";
139640
139738
  // src/commands/bing-analysis/merge-snapshot.ts
139641
139739
  import * as fs37 from "fs/promises";
139642
139740
  import * as path46 from "path";
139643
- function asRecord29(value) {
139741
+ function asRecord30(value) {
139644
139742
  if (value && typeof value === "object" && !Array.isArray(value)) {
139645
139743
  return value;
139646
139744
  }
@@ -139655,7 +139753,7 @@ function round27(value) {
139655
139753
  }
139656
139754
  function asRows2(value) {
139657
139755
  if (Array.isArray(value)) {
139658
- return value.filter((r) => asRecord29(r) !== null);
139756
+ return value.filter((r) => asRecord30(r) !== null);
139659
139757
  }
139660
139758
  return [];
139661
139759
  }
@@ -139737,17 +139835,17 @@ function campaignStatusDisplay(status) {
139737
139835
  return status == null || status === "" ? "\u2014" : String(status);
139738
139836
  }
139739
139837
  function mapDeviceRows(payload) {
139740
- const obj = asRecord29(payload);
139838
+ const obj = asRecord30(payload);
139741
139839
  return asRows2(obj?.devices).map((r) => pickMetrics(r, ["deviceType"]));
139742
139840
  }
139743
139841
  function mapGeographicRows(payload) {
139744
- const obj = asRecord29(payload);
139842
+ const obj = asRecord30(payload);
139745
139843
  return asRows2(obj?.countries).map(
139746
139844
  (r) => pickMetrics(r, ["countryOrRegion", "countryCriteriaId", "regionName", "cityName"])
139747
139845
  );
139748
139846
  }
139749
139847
  function mapAudienceLabelRows(payload, labelKey) {
139750
- const obj = asRecord29(payload);
139848
+ const obj = asRecord30(payload);
139751
139849
  return asRows2(obj?.audience).map((r) => {
139752
139850
  const m = pickMetrics(r, ["audience", "bidModifier"]);
139753
139851
  m[labelKey] = r.audience;
@@ -139755,7 +139853,7 @@ function mapAudienceLabelRows(payload, labelKey) {
139755
139853
  });
139756
139854
  }
139757
139855
  function mapAudienceFromMerged(payload) {
139758
- const data = asRecord29(asRecord29(payload)?.data);
139856
+ const data = asRecord30(asRecord30(payload)?.data);
139759
139857
  return {
139760
139858
  audienceAge: mapAudienceLabelRows(data?.ageAudience, "ageRange"),
139761
139859
  audienceGender: mapAudienceLabelRows(data?.genderAudience, "gender")
@@ -139850,7 +139948,7 @@ function mapSearchTermRows(payload) {
139850
139948
  }
139851
139949
  async function mergeBingAnalysisSnapshotIntoReport(payload, snapshotDir) {
139852
139950
  const absDir = path46.resolve(snapshotDir);
139853
- const metaAccountId = typeof asRecord29(payload.meta)?.accountId === "string" ? asRecord29(payload.meta)?.accountId : void 0;
139951
+ const metaAccountId = typeof asRecord30(payload.meta)?.accountId === "string" ? asRecord30(payload.meta)?.accountId : void 0;
139854
139952
  const manifest = await readManifest5(snapshotDir, metaAccountId);
139855
139953
  if (!manifest) {
139856
139954
  throw new Error(`\u672A\u5728 ${absDir} \u627E\u5230 report-manifest*.json\uFF0C\u8BF7\u5148\u6267\u884C bing-analysis --json-out`);
@@ -139860,9 +139958,9 @@ async function mergeBingAnalysisSnapshotIntoReport(payload, snapshotDir) {
139860
139958
  const data = await loadSectionPayload(absDir, art.file);
139861
139959
  if (data != null) sectionMap.set(art.section, data);
139862
139960
  }
139863
- const overview = asRecord29(sectionMap.get("overview"));
139864
- const currentPeriod = asRecord29(overview?.currentPeriod);
139865
- const previousPeriod = asRecord29(overview?.previousPeriod);
139961
+ const overview = asRecord30(sectionMap.get("overview"));
139962
+ const currentPeriod = asRecord30(overview?.currentPeriod);
139963
+ const previousPeriod = asRecord30(overview?.previousPeriod);
139866
139964
  const accountId = manifest.accountId ?? metaAccountId;
139867
139965
  const campaignRows3 = mapCampaignRows2(sectionMap.get("campaigns"));
139868
139966
  const campaignKpis = sumBingCampaignRowsToPeriodKpis(campaignRows3);
@@ -139989,7 +140087,7 @@ function textLen5(value) {
139989
140087
  function asArray6(value) {
139990
140088
  return Array.isArray(value) ? value : [];
139991
140089
  }
139992
- function asRecord30(value) {
140090
+ function asRecord31(value) {
139993
140091
  if (value && typeof value === "object" && !Array.isArray(value)) {
139994
140092
  return value;
139995
140093
  }
@@ -140000,9 +140098,9 @@ function pushMissing5(missing, id, chapter, dimension, hint) {
140000
140098
  }
140001
140099
  function validateBingPeriodReportContent(data) {
140002
140100
  const missing = [];
140003
- const meta = asRecord30(data.meta) ?? {};
140004
- const narrative = asRecord30(data.narrative) ?? {};
140005
- const sections = asRecord30(narrative.sections) ?? {};
140101
+ const meta = asRecord31(data.meta) ?? {};
140102
+ const narrative = asRecord31(data.narrative) ?? {};
140103
+ const sections = asRecord31(narrative.sections) ?? {};
140006
140104
  if (!textLen5(meta.accountId)) {
140007
140105
  pushMissing5(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
140008
140106
  }
@@ -140019,7 +140117,7 @@ function validateBingPeriodReportContent(data) {
140019
140117
  const sectionAnalysisCounts = {};
140020
140118
  const sectionSuggestionCounts = {};
140021
140119
  for (const key of SECTION_KEYS2) {
140022
- const section = asRecord30(sections[key]);
140120
+ const section = asRecord31(sections[key]);
140023
140121
  const analysis = asArray6(section?.analysis).filter((s) => textLen5(s) > 0);
140024
140122
  const suggestions = asArray6(section?.suggestions).filter((s) => textLen5(s) > 0);
140025
140123
  sectionAnalysisCounts[key] = analysis.length;
@@ -140045,7 +140143,7 @@ function validateBingPeriodReportContent(data) {
140045
140143
  }
140046
140144
  const recommendations = asArray6(narrative.recommendations).filter((r) => {
140047
140145
  if (typeof r === "string") return textLen5(r) > 0;
140048
- const rec = asRecord30(r);
140146
+ const rec = asRecord31(r);
140049
140147
  return textLen5(rec?.content) > 0;
140050
140148
  });
140051
140149
  if (recommendations.length < 3) {
@@ -140106,7 +140204,7 @@ async function readJsonFile6(filePath) {
140106
140204
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
140107
140205
  }
140108
140206
  }
140109
- function asRecord31(value) {
140207
+ function asRecord32(value) {
140110
140208
  if (value && typeof value === "object" && !Array.isArray(value)) {
140111
140209
  return value;
140112
140210
  }
@@ -140121,7 +140219,7 @@ function injectReportData5(html, payload) {
140121
140219
  }
140122
140220
  async function runBingAnalysisRender(opts) {
140123
140221
  const dataPath = path47.resolve(opts.dataFile);
140124
- let data = asRecord31(await readJsonFile6(dataPath));
140222
+ let data = asRecord32(await readJsonFile6(dataPath));
140125
140223
  if (opts.snapshotDir?.trim()) {
140126
140224
  data = await mergeBingAnalysisSnapshotIntoReport(data, path47.resolve(opts.snapshotDir));
140127
140225
  }
@@ -140594,7 +140692,7 @@ import { fileURLToPath as fileURLToPath13 } from "url";
140594
140692
  // src/commands/tiktok-analysis/merge-snapshot.ts
140595
140693
  import * as fs39 from "fs/promises";
140596
140694
  import * as path49 from "path";
140597
- function asRecord32(value) {
140695
+ function asRecord33(value) {
140598
140696
  if (value && typeof value === "object" && !Array.isArray(value)) {
140599
140697
  return value;
140600
140698
  }
@@ -140772,7 +140870,7 @@ function mapAudienceMerged(payload) {
140772
140870
  }
140773
140871
  async function mergeTikTokAnalysisSnapshotIntoReport(payload, snapshotDir) {
140774
140872
  const absDir = path49.resolve(snapshotDir);
140775
- const metaAccountId = typeof asRecord32(payload.meta)?.accountId === "string" ? asRecord32(payload.meta)?.accountId : void 0;
140873
+ const metaAccountId = typeof asRecord33(payload.meta)?.accountId === "string" ? asRecord33(payload.meta)?.accountId : void 0;
140776
140874
  const manifest = await readManifest6(snapshotDir, metaAccountId);
140777
140875
  if (!manifest) {
140778
140876
  throw new Error(
@@ -140886,7 +140984,7 @@ function textLen6(value) {
140886
140984
  function asArray7(value) {
140887
140985
  return Array.isArray(value) ? value : [];
140888
140986
  }
140889
- function asRecord33(value) {
140987
+ function asRecord34(value) {
140890
140988
  if (value && typeof value === "object" && !Array.isArray(value)) {
140891
140989
  return value;
140892
140990
  }
@@ -140897,9 +140995,9 @@ function pushMissing6(missing, id, chapter, dimension, hint) {
140897
140995
  }
140898
140996
  function validateTikTokPeriodReportContent(data) {
140899
140997
  const missing = [];
140900
- const meta = asRecord33(data.meta) ?? {};
140901
- const narrative = asRecord33(data.narrative) ?? {};
140902
- const sections = asRecord33(narrative.sections) ?? {};
140998
+ const meta = asRecord34(data.meta) ?? {};
140999
+ const narrative = asRecord34(data.narrative) ?? {};
141000
+ const sections = asRecord34(narrative.sections) ?? {};
140903
141001
  if (!textLen6(meta.accountId)) {
140904
141002
  pushMissing6(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
140905
141003
  }
@@ -140916,7 +141014,7 @@ function validateTikTokPeriodReportContent(data) {
140916
141014
  const sectionAnalysisCounts = {};
140917
141015
  const sectionSuggestionCounts = {};
140918
141016
  for (const key of SECTION_KEYS3) {
140919
- const section = asRecord33(sections[key]);
141017
+ const section = asRecord34(sections[key]);
140920
141018
  const analysis = asArray7(section?.analysis).filter((s) => textLen6(s) > 0);
140921
141019
  const suggestions = asArray7(section?.suggestions).filter((s) => textLen6(s) > 0);
140922
141020
  sectionAnalysisCounts[key] = analysis.length;
@@ -140942,7 +141040,7 @@ function validateTikTokPeriodReportContent(data) {
140942
141040
  }
140943
141041
  const recommendations = asArray7(narrative.recommendations).filter((r) => {
140944
141042
  if (typeof r === "string") return textLen6(r) > 0;
140945
- const rec = asRecord33(r);
141043
+ const rec = asRecord34(r);
140946
141044
  return textLen6(rec?.content) > 0;
140947
141045
  });
140948
141046
  if (recommendations.length < 3) {
@@ -141003,7 +141101,7 @@ async function readJsonFile7(filePath) {
141003
141101
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
141004
141102
  }
141005
141103
  }
141006
- function asRecord34(value) {
141104
+ function asRecord35(value) {
141007
141105
  if (value && typeof value === "object" && !Array.isArray(value)) {
141008
141106
  return value;
141009
141107
  }
@@ -141018,7 +141116,7 @@ function injectReportData6(html, payload) {
141018
141116
  }
141019
141117
  async function runTikTokAnalysisRender(opts) {
141020
141118
  const dataPath = path50.resolve(opts.dataFile);
141021
- let data = asRecord34(await readJsonFile7(dataPath));
141119
+ let data = asRecord35(await readJsonFile7(dataPath));
141022
141120
  if (opts.snapshotDir?.trim()) {
141023
141121
  data = await mergeTikTokAnalysisSnapshotIntoReport(data, path50.resolve(opts.snapshotDir));
141024
141122
  }
@@ -142117,7 +142215,7 @@ function endpointHintForYandexSection(def) {
142117
142215
  // src/commands/yandex-analysis/merge-snapshot.ts
142118
142216
  import * as fs41 from "fs/promises";
142119
142217
  import * as path51 from "path";
142120
- function asRecord35(value) {
142218
+ function asRecord36(value) {
142121
142219
  if (value && typeof value === "object" && !Array.isArray(value)) {
142122
142220
  return value;
142123
142221
  }
@@ -142137,11 +142235,11 @@ function normalizeYandexRoi(value) {
142137
142235
  return r === -1 ? void 0 : r;
142138
142236
  }
142139
142237
  function asItems(payload) {
142140
- const obj = asRecord35(payload);
142238
+ const obj = asRecord36(payload);
142141
142239
  if (!obj) return [];
142142
142240
  const items3 = obj.items;
142143
142241
  if (!Array.isArray(items3)) return [];
142144
- return items3.filter((r) => asRecord35(r) !== null);
142242
+ return items3.filter((r) => asRecord36(r) !== null);
142145
142243
  }
142146
142244
  function pickMetrics2(row, extras = []) {
142147
142245
  const spend = num12(row.spend) ?? 0;
@@ -142277,7 +142375,7 @@ function aggregateDailyToWeekly(dailyRows) {
142277
142375
  });
142278
142376
  }
142279
142377
  function prepareYandexDailyPayload(payload) {
142280
- const obj = asRecord35(payload) ?? {};
142378
+ const obj = asRecord36(payload) ?? {};
142281
142379
  const items3 = asItems(obj).map((r) => {
142282
142380
  const date = normalizeYandexDailyDate(r.date);
142283
142381
  return date ? { ...r, date } : r;
@@ -142346,7 +142444,7 @@ function mapDeviceRows2(payload) {
142346
142444
  }
142347
142445
  async function mergeYandexAnalysisSnapshotIntoReport(payload, snapshotDir) {
142348
142446
  const absDir = path51.resolve(snapshotDir);
142349
- const metaAccountId = typeof asRecord35(payload.meta)?.accountId === "string" ? asRecord35(payload.meta)?.accountId : void 0;
142447
+ const metaAccountId = typeof asRecord36(payload.meta)?.accountId === "string" ? asRecord36(payload.meta)?.accountId : void 0;
142350
142448
  const manifest = await readManifest7(snapshotDir, metaAccountId);
142351
142449
  if (!manifest) {
142352
142450
  throw new Error(
@@ -142358,8 +142456,8 @@ async function mergeYandexAnalysisSnapshotIntoReport(payload, snapshotDir) {
142358
142456
  const data = await loadSectionPayload3(absDir, art.file);
142359
142457
  if (data != null) sectionMap.set(art.section, data);
142360
142458
  }
142361
- const overview = asRecord35(sectionMap.get("overview"));
142362
- const totals = asRecord35(overview?.totals);
142459
+ const overview = asRecord36(sectionMap.get("overview"));
142460
+ const totals = asRecord36(overview?.totals);
142363
142461
  const accountId = manifest.accountId ?? metaAccountId;
142364
142462
  const meta = { ...payload.meta ?? {} };
142365
142463
  if (!meta.accountId && accountId) meta.accountId = accountId;
@@ -142581,7 +142679,7 @@ function textLen7(value) {
142581
142679
  function asArray8(value) {
142582
142680
  return Array.isArray(value) ? value : [];
142583
142681
  }
142584
- function asRecord36(value) {
142682
+ function asRecord37(value) {
142585
142683
  if (value && typeof value === "object" && !Array.isArray(value)) {
142586
142684
  return value;
142587
142685
  }
@@ -142594,23 +142692,23 @@ function normKey(value) {
142594
142692
  return String(value ?? "").trim().toLowerCase();
142595
142693
  }
142596
142694
  function insightMatchRecord(item) {
142597
- const rec = asRecord36(item);
142695
+ const rec = asRecord37(item);
142598
142696
  if (!rec) return {};
142599
- return asRecord36(rec.match) ?? rec;
142697
+ return asRecord37(rec.match) ?? rec;
142600
142698
  }
142601
142699
  function findRowInsight(list, primaryField, primaryValue, row) {
142602
142700
  const target = normKey(primaryValue);
142603
142701
  if (!target) return null;
142604
142702
  const candidates = list.filter((it) => normKey(insightMatchRecord(it)[primaryField]) === target);
142605
- if (candidates.length <= 1) return asRecord36(candidates[0]);
142703
+ if (candidates.length <= 1) return asRecord37(candidates[0]);
142606
142704
  const campaign = normKey(row.campaignName);
142607
142705
  const narrowed = candidates.find(
142608
142706
  (it) => normKey(insightMatchRecord(it).campaignName) === campaign
142609
142707
  );
142610
- return asRecord36(narrowed ?? candidates[0]);
142708
+ return asRecord37(narrowed ?? candidates[0]);
142611
142709
  }
142612
142710
  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);
142711
+ return rows.map((r) => asRecord37(r)).filter((r) => r != null).sort((a, b) => (Number(b.spend) || 0) - (Number(a.spend) || 0)).slice(0, limit);
142614
142712
  }
142615
142713
  var ROW_INSIGHT_SPECS = [
142616
142714
  {
@@ -142625,17 +142723,17 @@ var ROW_INSIGHT_SPECS = [
142625
142723
  ];
142626
142724
  function validateYandexPeriodReportContent(data) {
142627
142725
  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) ?? {};
142726
+ const meta = asRecord37(data.meta) ?? {};
142727
+ const narrative = asRecord37(data.narrative) ?? {};
142728
+ const sections = asRecord37(narrative.sections) ?? {};
142729
+ const kpis = asRecord37(data.kpis) ?? {};
142632
142730
  if (!textLen7(meta.accountId)) {
142633
142731
  pushMissing7(missing, "meta-account", "\u5143\u4FE1\u606F", "\u8D26\u6237 ID", "meta.accountId \u5FC5\u586B");
142634
142732
  }
142635
142733
  const sectionAnalysisCounts = {};
142636
142734
  const sectionSuggestionCounts = {};
142637
142735
  for (const key of SECTION_KEYS4) {
142638
- const section = asRecord36(sections[key]);
142736
+ const section = asRecord37(sections[key]);
142639
142737
  const analysis = asArray8(section?.analysis).filter((s) => textLen7(s) > 0);
142640
142738
  const suggestions = asArray8(section?.suggestions).filter((s) => textLen7(s) > 0);
142641
142739
  sectionAnalysisCounts[key] = analysis.length;
@@ -142661,7 +142759,7 @@ function validateYandexPeriodReportContent(data) {
142661
142759
  }
142662
142760
  const recommendations = asArray8(narrative.recommendations).filter((r) => {
142663
142761
  if (typeof r === "string") return textLen7(r) > 0;
142664
- const rec = asRecord36(r);
142762
+ const rec = asRecord37(r);
142665
142763
  return textLen7(rec?.content) > 0 || textLen7(rec?.text) > 0;
142666
142764
  });
142667
142765
  if (recommendations.length < 3) {
@@ -142683,8 +142781,8 @@ function validateYandexPeriodReportContent(data) {
142683
142781
  "\u81F3\u5C11\u4E00\u9879\u6709\u6548\u6570\u5B57\uFF08\u8BF7\u4F20 --snapshot-dir \u7531 CLI \u4ECE overview \u5408\u5E76\uFF09"
142684
142782
  );
142685
142783
  }
142686
- const tables = asRecord36(data.tables) ?? {};
142687
- const weeklyRows = asArray8(tables.weekly).map((r) => asRecord36(r)).filter((r) => r != null);
142784
+ const tables = asRecord37(data.tables) ?? {};
142785
+ const weeklyRows = asArray8(tables.weekly).map((r) => asRecord37(r)).filter((r) => r != null);
142688
142786
  for (const [i, row] of weeklyRows.entries()) {
142689
142787
  const label2 = `${row.weekLabel ?? ""} ${row.startDate ?? ""} ${row.endDate ?? ""}`;
142690
142788
  if (/nan/i.test(label2) || !normalizeYandexDailyDate(row.startDate) || !normalizeYandexDailyDate(row.endDate)) {
@@ -142697,7 +142795,7 @@ function validateYandexPeriodReportContent(data) {
142697
142795
  );
142698
142796
  }
142699
142797
  }
142700
- const rowInsights = asRecord36(narrative.rowInsights) ?? {};
142798
+ const rowInsights = asRecord37(narrative.rowInsights) ?? {};
142701
142799
  const rowInsightCoverage = {};
142702
142800
  for (const spec of ROW_INSIGHT_SPECS) {
142703
142801
  const shown = topRowsBySpend(asArray8(tables[spec.tableKey]), spec.limit).filter(
@@ -142777,7 +142875,7 @@ async function readJsonFile8(filePath) {
142777
142875
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
142778
142876
  }
142779
142877
  }
142780
- function asRecord37(value) {
142878
+ function asRecord38(value) {
142781
142879
  if (value && typeof value === "object" && !Array.isArray(value)) {
142782
142880
  return value;
142783
142881
  }
@@ -142805,7 +142903,7 @@ function injectReportData7(html, payload) {
142805
142903
  }
142806
142904
  async function runYandexAnalysisRender(opts) {
142807
142905
  const dataPath = path53.resolve(opts.dataFile);
142808
- let data = asRecord37(await readJsonFile8(dataPath));
142906
+ let data = asRecord38(await readJsonFile8(dataPath));
142809
142907
  if (opts.snapshotDir?.trim()) {
142810
142908
  data = await mergeYandexAnalysisSnapshotIntoReport(data, path53.resolve(opts.snapshotDir));
142811
142909
  }
@@ -143001,7 +143099,7 @@ function unwrapYandexItems(raw) {
143001
143099
  }
143002
143100
  return [];
143003
143101
  }
143004
- function asRecord38(raw) {
143102
+ function asRecord39(raw) {
143005
143103
  return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
143006
143104
  }
143007
143105
 
@@ -143080,7 +143178,7 @@ async function runYandexAccountStatus(opts) {
143080
143178
  } catch (err) {
143081
143179
  fail3("\u67E5\u8BE2 Yandex \u8D26\u6237\u603B\u89C8\u5931\u8D25", err);
143082
143180
  }
143083
- const row = asRecord38(result.raw);
143181
+ const row = asRecord39(result.raw);
143084
143182
  await emitOrTable(opts, {
143085
143183
  section: "yandex-account-status",
143086
143184
  commandLabel: "yandex-analysis account-status",