siluzan-tso-cli 1.1.35-beta.3 → 1.1.35-beta.4

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/README.md CHANGED
@@ -51,7 +51,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
51
51
  siluzan-tso init --force # 强制覆盖已存在文件
52
52
  ```
53
53
 
54
- > **注意**:当前为测试版(1.1.35-beta.3),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
54
+ > **注意**:当前为测试版(1.1.35-beta.4),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
55
55
 
56
56
  | 助手 | 建议 `--ai` |
57
57
  | ----------------------- | ------------------------------------ |
package/dist/index.js CHANGED
@@ -105346,12 +105346,12 @@ init_cli_json_snapshot();
105346
105346
 
105347
105347
  // src/utils/list-json-envelope.ts
105348
105348
  function wrapListJson(params) {
105349
- const itemCount = Array.isArray(params.items) ? params.items.length : 0;
105349
+ const itemCount2 = Array.isArray(params.items) ? params.items.length : 0;
105350
105350
  return {
105351
105351
  page: params.page,
105352
105352
  pageSize: params.pageSize,
105353
105353
  total: params.total === void 0 || params.total === null ? null : params.total,
105354
- itemCount,
105354
+ itemCount: itemCount2,
105355
105355
  items: params.items
105356
105356
  };
105357
105357
  }
@@ -124534,7 +124534,7 @@ function buildGoogleAdsDiagnosisCollectAgentHint(snapDir) {
124534
124534
  "Google Ads \u8BCA\u65AD collect \u5DF2\u5B8C\u6210\uFF08\u4EC5\u4E8B\u5B9E\u6570\u636E\uFF0C\u4E0D\u542B\u5EFA\u8BAE\u6027\u6587\u6848\uFF09\u3002",
124535
124535
  `1) Read ${dir}/${GOOGLE_ADS_DIAGNOSIS_COLLECT_BASENAME}\uFF08reportData + agentBrief\uFF09\uFF1B`,
124536
124536
  "2) Read references/report-templates/google-ads-diagnosis.md\uFF0C\u7531 Agent \u64B0\u5199\u5168\u90E8 analysis/suggestions\u3001diagnosisOverview\u3001summary\u3001accountInfo.businessModel/industry\u3001budgetCompetitiveness[].strategy\u3001newFeatures[].optimizerRecommendation\u3001adCreativeOptimization.items[].suggestion \u7B49\uFF1B",
124537
- `3) \u5C06 reportData \u4E0E\u53D9\u4E8B\u5B57\u6BB5\u5408\u5E76\u5199\u5165 ${dir}/${GOOGLE_ADS_DIAGNOSIS_REPORT_BASENAME}\uFF08**\u7981\u6B62\u6539\u5199** campaigns/geographic/keywords \u7684 items \u884C\uFF0C\u53EA\u586B analysis/suggestions\uFF09\uFF1B`,
124537
+ `3) \u5C06 reportData \u4E0E\u53D9\u4E8B\u5B57\u6BB5\u5408\u5E76\u5199\u5165 ${dir}/${GOOGLE_ADS_DIAGNOSIS_REPORT_BASENAME}\uFF08**\u7981\u6B62\u5199\u5165/\u8986\u76D6** campaigns/geographic/keywords \u7684 items \u884C\uFF0C\u53EA\u586B analysis/suggestions\uFF1Bitems \u4EE5 collect \u4E3A\u51C6\uFF0Crender \u4F1A\u81EA\u52A8\u8986\u76D6 Agent \u6539\u52A8\u7684\u5BF9\u6BD4\u8868\uFF09\uFF1B`,
124538
124538
  `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`,
124539
124539
  "\u7981\u6B62\u5728\u672A\u7ECF\u8FC7 Agent \u64B0\u5199\u7684\u60C5\u51B5\u4E0B\u76F4\u63A5 render collect \u4EA7\u7269\uFF1B\u7F3A\u4EFB\u4E00\u5EFA\u8BAE\u5B57\u6BB5 render \u4F1A\u5931\u8D25\u3002"
124540
124540
  ].join("\n");
@@ -124587,6 +124587,20 @@ function buildGoogleAdsDiagnosisAgentBrief(input) {
124587
124587
  campaigns: input.campaignHints,
124588
124588
  keywords: input.keywordHints
124589
124589
  },
124590
+ comparisonTableItemCounts: input.comparisonTableItemCounts,
124591
+ agentRules: {
124592
+ doNotModifyItemRows: [
124593
+ "campaigns.items",
124594
+ "geographic.items",
124595
+ "keywords.items"
124596
+ ],
124597
+ renderRestoresComparisonItemsFromCollect: "render \u9ED8\u8BA4\u540C\u76EE\u5F55 google-ads-diagnosis-collect.json \u4F1A\u4EE5 collect \u8986\u76D6\u4E0A\u8FF0 items\uFF08Agent \u53EA\u586B analysis/suggestions\uFF09",
124598
+ mayEditItemFields: [
124599
+ "biddingStrategy.items[].recommendationReason",
124600
+ "newFeatures.items[].optimizerRecommendation",
124601
+ "adCreativeOptimization.items[].suggestion"
124602
+ ]
124603
+ },
124590
124604
  agentDeliverable: {
124591
124605
  outputFile: "google-ads-diagnosis.json",
124592
124606
  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",
@@ -125380,11 +125394,58 @@ function buildGoogleAdsDiagnosisCollectPayload(opts) {
125380
125394
  profile.industry,
125381
125395
  ...campaignCurrent.map((r) => String(r.campaignName ?? ""))
125382
125396
  ].filter(Boolean),
125383
- keywordHints: zeroConvKw.slice(0, 5).map((r) => String(r.keyword ?? ""))
125397
+ keywordHints: zeroConvKw.slice(0, 5).map((r) => String(r.keyword ?? "")),
125398
+ comparisonTableItemCounts: {
125399
+ campaigns: campaignItems.length,
125400
+ geographic: geoItems.length,
125401
+ keywords: kwItems.length
125402
+ }
125384
125403
  });
125385
125404
  return { reportData: data, agentBrief };
125386
125405
  }
125387
125406
 
125407
+ // src/commands/google-ads-diagnosis/collect-integrity.ts
125408
+ function asRecord5(value) {
125409
+ if (value && typeof value === "object" && !Array.isArray(value)) {
125410
+ return value;
125411
+ }
125412
+ return null;
125413
+ }
125414
+ function itemCount(block) {
125415
+ const items = asRecord5(block)?.items;
125416
+ return Array.isArray(items) ? items.length : 0;
125417
+ }
125418
+ function getCollectIntegrityWarnings(reportData) {
125419
+ const warnings = [];
125420
+ const kwItems = itemCount(reportData.keywords);
125421
+ const fullKwItems = itemCount(reportData.fullKeywords);
125422
+ const keywordCount = Number(asRecord5(reportData.structure)?.keywordCount ?? 0);
125423
+ if (kwItems === 0 && fullKwItems > 0) {
125424
+ warnings.push(
125425
+ `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`
125426
+ );
125427
+ } else if (kwItems === 0 && keywordCount > 0) {
125428
+ warnings.push(
125429
+ `keywords.items \u5BF9\u6BD4\u8868\u4E3A\u7A7A\uFF0C\u4F46 structure.keywordCount=${keywordCount}\uFF1B\u8BF7\u786E\u8BA4\u4E0A\u4E00\u5468\u671F keywords \u5FEB\u7167\u662F\u5426\u62C9\u53D6\u6210\u529F\u3002`
125430
+ );
125431
+ }
125432
+ const campaignItems = itemCount(reportData.campaigns);
125433
+ const campaignCount = Number(asRecord5(reportData.structure)?.campaignCount ?? 0);
125434
+ if (campaignItems === 0 && campaignCount > 0) {
125435
+ warnings.push(
125436
+ `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`
125437
+ );
125438
+ }
125439
+ const geoItems = itemCount(reportData.geographic);
125440
+ const fullGeoItems = itemCount(reportData.fullGeographic);
125441
+ if (geoItems === 0 && fullGeoItems > 0) {
125442
+ warnings.push(
125443
+ `geographic.items \u5BF9\u6BD4\u8868\u4E3A\u7A7A\uFF0C\u4F46 fullGeographic.items \u6709 ${fullGeoItems} \u884C\uFF1B\u8BF7\u786E\u8BA4\u4E0A\u4E00\u5468\u671F geographic \u5FEB\u7167\u662F\u5426\u62C9\u53D6\u6210\u529F\u3002`
125444
+ );
125445
+ }
125446
+ return warnings;
125447
+ }
125448
+
125388
125449
  // src/commands/google-ads-diagnosis/invoke-google-analysis.ts
125389
125450
  import { spawnSync as spawnSync2 } from "child_process";
125390
125451
  function invokeGoogleAnalysisCli(opts) {
@@ -125527,6 +125588,12 @@ async function runGoogleAdsDiagnosisCollect(opts) {
125527
125588
  website: websiteUrl || opts.website,
125528
125589
  landingPage
125529
125590
  });
125591
+ for (const warning of getCollectIntegrityWarnings(reportData)) {
125592
+ console.error(`
125593
+ \u26A0\uFE0F collect \u5B8C\u6574\u6027\uFF1A${warning}
125594
+ `);
125595
+ degraded = true;
125596
+ }
125530
125597
  const collectPayload = {
125531
125598
  kind: "siluzan-tso-google-ads-diagnosis-collect",
125532
125599
  collectedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -125567,7 +125634,7 @@ import fs18 from "fs/promises";
125567
125634
  import path23 from "path";
125568
125635
 
125569
125636
  // src/commands/google-ads-diagnosis/report-content.ts
125570
- function asRecord5(value) {
125637
+ function asRecord6(value) {
125571
125638
  if (value && typeof value === "object" && !Array.isArray(value)) {
125572
125639
  return value;
125573
125640
  }
@@ -125576,7 +125643,7 @@ function asRecord5(value) {
125576
125643
  function getNestedValue(root, path34) {
125577
125644
  let cur = root;
125578
125645
  for (const key of path34) {
125579
- const rec = asRecord5(cur);
125646
+ const rec = asRecord6(cur);
125580
125647
  if (!rec) return void 0;
125581
125648
  cur = rec[key];
125582
125649
  }
@@ -125593,7 +125660,7 @@ function validateBudgetCompetitivenessStrategies(data) {
125593
125660
  }
125594
125661
  const warnings = [];
125595
125662
  for (let i = 0; i < items.length; i++) {
125596
- const row = asRecord5(items[i]);
125663
+ const row = asRecord6(items[i]);
125597
125664
  const name2 = String(row?.name ?? row?.metric ?? i);
125598
125665
  if (!hasNarrativeContent(row?.strategy)) {
125599
125666
  warnings.push(`budgetCompetitiveness[${name2}].strategy \u4E3A\u7A7A\uFF08\u987B\u7531 Agent \u586B\u5199\uFF09`);
@@ -125602,13 +125669,13 @@ function validateBudgetCompetitivenessStrategies(data) {
125602
125669
  return warnings;
125603
125670
  }
125604
125671
  function validateNewFeatureRecommendations(data) {
125605
- const nf = asRecord5(data.newFeatures);
125672
+ const nf = asRecord6(data.newFeatures);
125606
125673
  if (!nf) return [];
125607
125674
  const items = nf.items;
125608
125675
  if (!Array.isArray(items)) return [];
125609
125676
  const warnings = [];
125610
125677
  for (let i = 0; i < items.length; i++) {
125611
- const row = asRecord5(items[i]);
125678
+ const row = asRecord6(items[i]);
125612
125679
  const name2 = String(row?.strategyName ?? row?.feature ?? row?.strategy ?? i);
125613
125680
  if (!hasNarrativeContent(row?.optimizerRecommendation)) {
125614
125681
  warnings.push(`newFeatures.items[${name2}].optimizerRecommendation \u4E3A\u7A7A\uFF08\u987B\u7531 Agent \u586B\u5199\uFF09`);
@@ -125617,13 +125684,13 @@ function validateNewFeatureRecommendations(data) {
125617
125684
  return warnings;
125618
125685
  }
125619
125686
  function validateAdCreativeItemSuggestions(data) {
125620
- const creative = asRecord5(data.adCreativeOptimization);
125687
+ const creative = asRecord6(data.adCreativeOptimization);
125621
125688
  if (!creative) return [];
125622
125689
  const items = creative.items;
125623
125690
  if (!Array.isArray(items) || items.length === 0) return [];
125624
125691
  const warnings = [];
125625
125692
  for (let i = 0; i < items.length; i++) {
125626
- const row = asRecord5(items[i]);
125693
+ const row = asRecord6(items[i]);
125627
125694
  const title = String(row?.adTitle ?? i);
125628
125695
  if (!hasNarrativeContent(row?.suggestion ?? row?.suggestions)) {
125629
125696
  warnings.push(
@@ -125638,7 +125705,7 @@ function validateGoogleAdsDiagnosisContent(data) {
125638
125705
  (key) => data[key] === void 0
125639
125706
  );
125640
125707
  const warnings = [];
125641
- const accountInfo = asRecord5(data.accountInfo);
125708
+ const accountInfo = asRecord6(data.accountInfo);
125642
125709
  if (accountInfo && !accountInfo.companyName && !accountInfo.period) {
125643
125710
  warnings.push("accountInfo \u7F3A\u5C11 companyName \u4E0E period\uFF0C\u9875\u7709\u53EF\u80FD\u4E3A\u7A7A");
125644
125711
  }
@@ -125686,7 +125753,7 @@ var GOOGLE_ADS_DIAGNOSIS_RESTORE_ITEM_MODULES = [
125686
125753
  GOOGLE_ADS_DIAGNOSIS_BIDDING_STRATEGY_MODULE,
125687
125754
  GOOGLE_ADS_DIAGNOSIS_NEW_FEATURES_MODULE
125688
125755
  ];
125689
- function asRecord6(value) {
125756
+ function asRecord7(value) {
125690
125757
  if (value && typeof value === "object" && !Array.isArray(value)) {
125691
125758
  return value;
125692
125759
  }
@@ -125697,7 +125764,7 @@ function isValidRateChange(value) {
125697
125764
  return typeof value === "number" && Number.isFinite(value);
125698
125765
  }
125699
125766
  function isComparisonTableRowValid(row) {
125700
- const rec = asRecord6(row);
125767
+ const rec = asRecord7(row);
125701
125768
  if (!rec) return false;
125702
125769
  if (!String(rec.title ?? "").trim()) return false;
125703
125770
  if (!Number.isFinite(Number(rec.currentCost))) return false;
@@ -125709,12 +125776,12 @@ function isComparisonTableRowValid(row) {
125709
125776
  return true;
125710
125777
  }
125711
125778
  function isNewFeatureRowValid(row) {
125712
- const rec = asRecord6(row);
125779
+ const rec = asRecord7(row);
125713
125780
  if (!rec) return false;
125714
125781
  return Boolean(String(rec.strategyName ?? rec.feature ?? rec.strategy ?? "").trim());
125715
125782
  }
125716
125783
  function isBiddingStrategyRowValid(row) {
125717
- const rec = asRecord6(row);
125784
+ const rec = asRecord7(row);
125718
125785
  if (!rec) return false;
125719
125786
  if (!String(rec.campaignName ?? "").trim()) return false;
125720
125787
  if (!Number.isFinite(Number(rec.duration)) || Number(rec.duration) <= 0) return false;
@@ -125739,14 +125806,32 @@ function moduleItemsNeedRestore(items, validator) {
125739
125806
  if (!Array.isArray(items) || items.length === 0) return false;
125740
125807
  return items.some((row) => !validator(row));
125741
125808
  }
125809
+ function isComparisonTableModule(mod) {
125810
+ return GOOGLE_ADS_DIAGNOSIS_COMPARISON_MODULES.includes(mod);
125811
+ }
125812
+ function comparisonItemsDifferFromCollect(finalItems, collectItems) {
125813
+ if (!Array.isArray(finalItems)) return true;
125814
+ if (finalItems.length !== collectItems.length) return true;
125815
+ return JSON.stringify(finalItems) !== JSON.stringify(collectItems);
125816
+ }
125742
125817
  function getFactItemsErrors(data) {
125743
125818
  const errors = [];
125744
125819
  for (const mod of GOOGLE_ADS_DIAGNOSIS_RESTORE_ITEM_MODULES) {
125745
125820
  const validator = MODULE_ITEM_VALIDATORS[mod];
125746
125821
  const hint = MODULE_ITEM_ERROR_HINT[mod];
125747
- const block = asRecord6(data[mod]);
125822
+ const block = asRecord7(data[mod]);
125748
125823
  const items = block?.items;
125749
- if (!Array.isArray(items) || items.length === 0) continue;
125824
+ if (!Array.isArray(items) || items.length === 0) {
125825
+ if (mod === "keywords") {
125826
+ const fullKw = asRecord7(data.fullKeywords)?.items;
125827
+ if (Array.isArray(fullKw) && fullKw.length > 0) {
125828
+ errors.push(
125829
+ "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"
125830
+ );
125831
+ }
125832
+ }
125833
+ continue;
125834
+ }
125750
125835
  for (let i = 0; i < items.length; i++) {
125751
125836
  if (!validator(items[i])) {
125752
125837
  errors.push(`${mod}.items[${i}] ${hint}`);
@@ -125763,15 +125848,15 @@ var LANDING_PAGE_SPEED_KEYS = [
125763
125848
  "speedIndex"
125764
125849
  ];
125765
125850
  function isLandingPageSpeedValid(value) {
125766
- const rec = asRecord6(value);
125851
+ const rec = asRecord7(value);
125767
125852
  if (!rec) return false;
125768
125853
  return LANDING_PAGE_SPEED_KEYS.every(
125769
125854
  (key) => typeof rec[key] === "number" && Number.isFinite(rec[key])
125770
125855
  );
125771
125856
  }
125772
125857
  function restoreLandingPageSpeedFromCollect(finalData, collectReportData) {
125773
- const finalBlock = asRecord6(finalData[GOOGLE_ADS_DIAGNOSIS_LANDING_PAGE_MODULE]);
125774
- const collectBlock = asRecord6(collectReportData[GOOGLE_ADS_DIAGNOSIS_LANDING_PAGE_MODULE]);
125858
+ const finalBlock = asRecord7(finalData[GOOGLE_ADS_DIAGNOSIS_LANDING_PAGE_MODULE]);
125859
+ const collectBlock = asRecord7(collectReportData[GOOGLE_ADS_DIAGNOSIS_LANDING_PAGE_MODULE]);
125775
125860
  if (!collectBlock) return { data: finalData, restored: false };
125776
125861
  const needsDesktop = !isLandingPageSpeedValid(finalBlock?.desktop) && isLandingPageSpeedValid(collectBlock.desktop);
125777
125862
  const needsMobile = !isLandingPageSpeedValid(finalBlock?.mobile) && isLandingPageSpeedValid(collectBlock.mobile);
@@ -125789,12 +125874,13 @@ function mergeComparisonItemsFromCollect(finalData, collectReportData) {
125789
125874
  const restoredModules = [];
125790
125875
  for (const mod of GOOGLE_ADS_DIAGNOSIS_RESTORE_ITEM_MODULES) {
125791
125876
  const validator = MODULE_ITEM_VALIDATORS[mod];
125792
- const finalBlock = asRecord6(data[mod]);
125793
- const collectBlock = asRecord6(collectReportData[mod]);
125877
+ const finalBlock = asRecord7(data[mod]);
125878
+ const collectBlock = asRecord7(collectReportData[mod]);
125794
125879
  const finalItems = finalBlock?.items;
125795
125880
  const collectItems = collectBlock?.items;
125796
- if (!moduleItemsNeedRestore(finalItems, validator)) continue;
125797
125881
  if (!Array.isArray(collectItems) || collectItems.length === 0) continue;
125882
+ const needsRestore = isComparisonTableModule(mod) ? comparisonItemsDifferFromCollect(finalItems, collectItems) : moduleItemsNeedRestore(finalItems, validator);
125883
+ if (!needsRestore) continue;
125798
125884
  data[mod] = {
125799
125885
  ...finalBlock ?? {},
125800
125886
  items: collectItems
@@ -125805,7 +125891,7 @@ function mergeComparisonItemsFromCollect(finalData, collectReportData) {
125805
125891
  }
125806
125892
 
125807
125893
  // src/commands/google-ads-diagnosis/narrative-consistency-check.ts
125808
- function asRecord7(value) {
125894
+ function asRecord8(value) {
125809
125895
  if (value && typeof value === "object" && !Array.isArray(value)) {
125810
125896
  return value;
125811
125897
  }
@@ -125813,14 +125899,14 @@ function asRecord7(value) {
125813
125899
  }
125814
125900
  function collectNarrativeTexts(data) {
125815
125901
  const texts = [];
125816
- const summary = asRecord7(data.summary);
125902
+ const summary = asRecord8(data.summary);
125817
125903
  if (Array.isArray(summary?.keyIssues)) {
125818
125904
  for (const item of summary.keyIssues) texts.push(String(item ?? ""));
125819
125905
  }
125820
- const overview = asRecord7(data.diagnosisOverview);
125906
+ const overview = asRecord8(data.diagnosisOverview);
125821
125907
  if (Array.isArray(overview?.disadvantages)) {
125822
125908
  for (const item of overview.disadvantages) {
125823
- const rec = asRecord7(item);
125909
+ const rec = asRecord8(item);
125824
125910
  if (rec) {
125825
125911
  texts.push(String(rec.title ?? ""), String(rec.description ?? ""));
125826
125912
  } else {
@@ -125831,16 +125917,16 @@ function collectNarrativeTexts(data) {
125831
125917
  return texts.filter((t) => t.trim().length > 0);
125832
125918
  }
125833
125919
  function newFeatureAccountStatus(data, strategy) {
125834
- const nf = asRecord7(data.newFeatures);
125920
+ const nf = asRecord8(data.newFeatures);
125835
125921
  const items = nf?.items;
125836
125922
  if (!Array.isArray(items)) return null;
125837
- const row = items.find((it) => asRecord7(it)?.strategy === strategy);
125838
- const rec = asRecord7(row);
125923
+ const row = items.find((it) => asRecord8(it)?.strategy === strategy);
125924
+ const rec = asRecord8(row);
125839
125925
  if (!rec || typeof rec.accountStatus !== "boolean") return null;
125840
125926
  return rec.accountStatus;
125841
125927
  }
125842
125928
  function goldAccountFlag(data, key) {
125843
- const gold = asRecord7(data.goldAccount);
125929
+ const gold = asRecord8(data.goldAccount);
125844
125930
  const value = gold?.[key];
125845
125931
  return typeof value === "boolean" ? value : null;
125846
125932
  }
@@ -125871,7 +125957,7 @@ function getNarrativeConsistencyErrors(data) {
125871
125957
  }
125872
125958
 
125873
125959
  // src/commands/google-ads-diagnosis/render-report.ts
125874
- function asRecord8(value) {
125960
+ function asRecord9(value) {
125875
125961
  if (value && typeof value === "object" && !Array.isArray(value)) {
125876
125962
  return value;
125877
125963
  }
@@ -125880,8 +125966,8 @@ function asRecord8(value) {
125880
125966
  async function tryLoadCollectReportData(collectPath) {
125881
125967
  try {
125882
125968
  const raw = JSON.parse(await fs18.readFile(collectPath, "utf8"));
125883
- const root = asRecord8(raw);
125884
- const reportData = asRecord8(root?.reportData);
125969
+ const root = asRecord9(raw);
125970
+ const reportData = asRecord9(root?.reportData);
125885
125971
  return reportData ?? root;
125886
125972
  } catch {
125887
125973
  return null;
@@ -125898,7 +125984,7 @@ async function runGoogleAdsDiagnosisRender(opts) {
125898
125984
  `);
125899
125985
  process.exit(1);
125900
125986
  }
125901
- let data = asRecord8(dataRaw);
125987
+ let data = asRecord9(dataRaw);
125902
125988
  if (!opts.noMergeCollect) {
125903
125989
  const collectPath = path23.resolve(
125904
125990
  opts.collectFile ?? path23.join(path23.dirname(dataPath), GOOGLE_ADS_DIAGNOSIS_COLLECT_BASENAME)
@@ -126411,7 +126497,7 @@ function ensureScorecardFromSnapshot(healthDiagnosis, merged) {
126411
126497
  }
126412
126498
 
126413
126499
  // src/commands/facebook-analysis/merge-snapshot.ts
126414
- function asRecord9(value) {
126500
+ function asRecord10(value) {
126415
126501
  if (value && typeof value === "object" && !Array.isArray(value)) {
126416
126502
  return value;
126417
126503
  }
@@ -126460,7 +126546,7 @@ async function readManifest(snapshotDir) {
126460
126546
  async function loadSectionFile(snapshotDir, file) {
126461
126547
  try {
126462
126548
  const raw = await fs21.readFile(path28.join(snapshotDir, file), "utf8");
126463
- return asRecord9(JSON.parse(raw));
126549
+ return asRecord10(JSON.parse(raw));
126464
126550
  } catch {
126465
126551
  return null;
126466
126552
  }
@@ -126508,7 +126594,7 @@ async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
126508
126594
  if (data) sectionMap.set(art.section, data);
126509
126595
  }
126510
126596
  const overview = sectionMap.get("overview");
126511
- const current = asRecord9(overview?.currentPeriod);
126597
+ const current = asRecord10(overview?.currentPeriod);
126512
126598
  const accountName = typeof overview?.accountName === "string" ? overview.accountName : void 0;
126513
126599
  const accountId = manifest.accountId ?? (typeof overview?.accountId === "string" ? overview.accountId : void 0);
126514
126600
  const kpis = { ...payload.kpis ?? {} };
@@ -126630,7 +126716,7 @@ function isFiniteNumber(value) {
126630
126716
  function asArray2(value) {
126631
126717
  return Array.isArray(value) ? value : [];
126632
126718
  }
126633
- function asRecord10(value) {
126719
+ function asRecord11(value) {
126634
126720
  if (value && typeof value === "object" && !Array.isArray(value)) {
126635
126721
  return value;
126636
126722
  }
@@ -126642,26 +126728,26 @@ function pushMissing(missing, id, chapter, dimension, hint) {
126642
126728
  function countAdSetsWithSpend(tables) {
126643
126729
  const rows = asArray2(tables?.adSets);
126644
126730
  return rows.filter((row) => {
126645
- const r = asRecord10(row);
126731
+ const r = asRecord11(row);
126646
126732
  const spend = r?.spend;
126647
126733
  return isFiniteNumber(spend) && spend > 0;
126648
126734
  }).length;
126649
126735
  }
126650
126736
  function chartLabels(chart) {
126651
- const c = asRecord10(chart);
126737
+ const c = asRecord11(chart);
126652
126738
  return asArray2(c?.labels).length;
126653
126739
  }
126654
126740
  function validateMetaPeriodReportContent(data) {
126655
126741
  const missing = [];
126656
- const meta = asRecord10(data.meta) ?? {};
126657
- const kpis = asRecord10(data.kpis) ?? {};
126658
- const narrative = asRecord10(data.narrative) ?? {};
126659
- const tables = asRecord10(data.tables);
126660
- const charts = asRecord10(data.charts);
126661
- const sections = asRecord10(data.sections);
126662
- const health = asRecord10(data.healthDiagnosis);
126663
- const priorityPlan = asRecord10(data.priorityPlan);
126664
- const actionChecklist = asRecord10(data.actionChecklist);
126742
+ const meta = asRecord11(data.meta) ?? {};
126743
+ const kpis = asRecord11(data.kpis) ?? {};
126744
+ const narrative = asRecord11(data.narrative) ?? {};
126745
+ const tables = asRecord11(data.tables);
126746
+ const charts = asRecord11(data.charts);
126747
+ const sections = asRecord11(data.sections);
126748
+ const health = asRecord11(data.healthDiagnosis);
126749
+ const priorityPlan = asRecord11(data.priorityPlan);
126750
+ const actionChecklist = asRecord11(data.actionChecklist);
126665
126751
  const adSetsWithSpend2 = countAdSetsWithSpend(tables ?? void 0);
126666
126752
  const regionalNarratives = asArray2(narrative.regional).length;
126667
126753
  const recommendations = asArray2(narrative.recommendations);
@@ -126733,7 +126819,7 @@ function validateMetaPeriodReportContent(data) {
126733
126819
  "charts.audience.labels \u81F3\u5C11 1 \u9879"
126734
126820
  );
126735
126821
  }
126736
- const funnel = asRecord10(charts?.funnel);
126822
+ const funnel = asRecord11(charts?.funnel);
126737
126823
  if (!isFiniteNumber(funnel?.reach)) {
126738
126824
  pushMissing(
126739
126825
  missing,
@@ -126797,7 +126883,7 @@ function validateMetaPeriodReportContent(data) {
126797
126883
  );
126798
126884
  } else {
126799
126885
  for (let i = 0; i < regionalNarratives; i++) {
126800
- const row = asRecord10(asArray2(narrative.regional)[i]);
126886
+ const row = asRecord11(asArray2(narrative.regional)[i]);
126801
126887
  if (textLen2(row?.text) < 80) {
126802
126888
  pushMissing(
126803
126889
  missing,
@@ -126827,7 +126913,7 @@ function validateMetaPeriodReportContent(data) {
126827
126913
  "\u5FC5\u987B\u6070\u597D 4 \u6761\uFF08\u7B80\u5316\u8868\u5355/\u533A\u57DF\u8C03\u6574/\u9884\u7B97\u91CD\u6784/\u7D20\u6750\u5EFA\u8BAE\uFF09"
126828
126914
  );
126829
126915
  } else {
126830
- const titles = recommendations.map((r) => asRecord10(r)?.title);
126916
+ const titles = recommendations.map((r) => asRecord11(r)?.title);
126831
126917
  for (const title of RECOMMENDATION_TITLES) {
126832
126918
  if (!titles.includes(title)) {
126833
126919
  pushMissing(
@@ -126840,7 +126926,7 @@ function validateMetaPeriodReportContent(data) {
126840
126926
  }
126841
126927
  }
126842
126928
  for (let i = 0; i < recommendations.length; i++) {
126843
- const rec = asRecord10(recommendations[i]);
126929
+ const rec = asRecord11(recommendations[i]);
126844
126930
  if (textLen2(rec?.content) < 150) {
126845
126931
  pushMissing(
126846
126932
  missing,
@@ -126862,7 +126948,7 @@ function validateMetaPeriodReportContent(data) {
126862
126948
  );
126863
126949
  } else {
126864
126950
  for (let i = 0; i < supplementary.length; i++) {
126865
- const row = asRecord10(supplementary[i]);
126951
+ const row = asRecord11(supplementary[i]);
126866
126952
  if (!textLen2(row?.dimension) || !textLen2(row?.issue)) {
126867
126953
  pushMissing(
126868
126954
  missing,
@@ -126944,7 +127030,7 @@ function validateMetaPeriodReportContent(data) {
126944
127030
  );
126945
127031
  } else {
126946
127032
  for (let i = 0; i < fourQuestions.length; i++) {
126947
- const q = asRecord10(fourQuestions[i]);
127033
+ const q = asRecord11(fourQuestions[i]);
126948
127034
  const evidence = asArray2(q?.evidence).filter((e) => textLen2(e) > 0);
126949
127035
  if (evidence.length < 2) {
126950
127036
  pushMissing(
@@ -126968,7 +127054,7 @@ function validateMetaPeriodReportContent(data) {
126968
127054
  }
126969
127055
  let scorecardValidRows = 0;
126970
127056
  for (let i = 0; i < scorecard.length; i++) {
126971
- const row = asRecord10(scorecard[i]);
127057
+ const row = asRecord11(scorecard[i]);
126972
127058
  const itemOk = textLen2(row?.item) > 0;
126973
127059
  const dataOk = textLen2(row?.data) > 0;
126974
127060
  const signalOk = SCORECARD_SIGNALS.includes(row?.signal);
@@ -127010,7 +127096,7 @@ function validateMetaPeriodReportContent(data) {
127010
127096
  );
127011
127097
  }
127012
127098
  for (const key of ["platform", "country", "adSets"]) {
127013
- const insight = textLen2(asRecord10(sections?.[key])?.insight);
127099
+ const insight = textLen2(asRecord11(sections?.[key])?.insight);
127014
127100
  if (insight < 200) {
127015
127101
  pushMissing(
127016
127102
  missing,
@@ -127021,7 +127107,7 @@ function validateMetaPeriodReportContent(data) {
127021
127107
  );
127022
127108
  }
127023
127109
  }
127024
- const audience = asRecord10(sections?.audience);
127110
+ const audience = asRecord11(sections?.audience);
127025
127111
  if (asArray2(audience?.goldenProfile).filter((s) => textLen2(s) > 0).length < 3) {
127026
127112
  pushMissing(
127027
127113
  missing,
@@ -127049,7 +127135,7 @@ function validateMetaPeriodReportContent(data) {
127049
127135
  "\u2265150 \u5B57"
127050
127136
  );
127051
127137
  }
127052
- const landingRows = asArray2(asRecord10(sections?.landingPage)?.rows);
127138
+ const landingRows = asArray2(asRecord11(sections?.landingPage)?.rows);
127053
127139
  if (landingRows.length < 3) {
127054
127140
  pushMissing(
127055
127141
  missing,
@@ -127134,7 +127220,7 @@ async function readJsonFile2(filePath) {
127134
127220
  throw new Error(`\u65E0\u6CD5\u89E3\u6790 JSON\uFF1A${filePath}`);
127135
127221
  }
127136
127222
  }
127137
- function asRecord11(value) {
127223
+ function asRecord12(value) {
127138
127224
  if (value && typeof value === "object" && !Array.isArray(value)) {
127139
127225
  return value;
127140
127226
  }
@@ -127149,7 +127235,7 @@ function injectReportData2(html, payload) {
127149
127235
  }
127150
127236
  async function runFacebookAnalysisRender(opts) {
127151
127237
  const dataPath = path29.resolve(opts.dataFile);
127152
- let data = asRecord11(await readJsonFile2(dataPath));
127238
+ let data = asRecord12(await readJsonFile2(dataPath));
127153
127239
  if (opts.snapshotDir?.trim()) {
127154
127240
  data = await mergeFacebookSnapshotIntoReport(data, path29.resolve(opts.snapshotDir));
127155
127241
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "siluzan-tso",
3
- "version": "1.1.35-beta.3",
4
- "publishedAt": 1783323427829
3
+ "version": "1.1.35-beta.4",
4
+ "publishedAt": 1783328413873
5
5
  }
@@ -47,7 +47,7 @@ siluzan-tso google-ads-diagnosis render \
47
47
  - 若环比列全为 `null`,检查落盘目录是否存在上一周期文件(如 `campaigns-<id>_20260503-20260602.json`);不存在则**重新执行 collect**(勿用手动拼装或 Python 脚本绕过 CLI)。
48
48
 
49
49
  - **render 自动合并(默认开启)**:若同目录存在 `google-ads-diagnosis-collect.json`,且 Agent 改坏了 `campaigns` / `geographic` / `keywords` 的 `items`(缺 `title`/`currentCost` 或环比写成字符串)或整体覆盖丢弃了 `landingPageAnalysis.desktop`/`mobile`,CLI **自动从 collect.reportData 恢复**,保留 Agent 的 `analysis`/`suggestions`。可用 `--no-merge-collect` 关闭;`--collect <file>` 指定 collect 路径。
50
- - **render 硬校验**:合并后对比表仍不完整则 **exit 1**(避免 HTML 表体全空);`summary.keyIssues` / `diagnosisOverview.disadvantages` 与 `newFeatures`/`goldAccount` 等事实字段出现已知矛盾模式(见「撰写硬约束」第 5 条)时同样 **exit 1**。
50
+ - **render 硬校验**:合并后对比表仍不完整则 **exit 1**(避免 HTML 表体全空);`campaigns/geographic/keywords.items` 默认同目录 collect **整表覆盖** Agent 改动(Agent 只填 analysis/suggestions);`summary.keyIssues` / `diagnosisOverview.disadvantages` 与 `newFeatures`/`goldAccount` 等事实字段出现已知矛盾模式(见「撰写硬约束」第 5 条)时同样 **exit 1**。
51
51
 
52
52
  - **禁止**在 `collect` 阶段生成或写入 `analysis` / `suggestions` / `diagnosisOverview` / `summary` 等建议性文案。
53
53
  - **禁止**跳过 Agent 直接 `render` collect 产物(`render` 会校验全部叙事 / 建议字段;调试可加 `--lenient`)。
@@ -130,6 +130,13 @@ siluzan-tso google-ads-diagnosis render \
130
130
  - `render` 会在同目录存在 `google-ads-diagnosis-collect.json` 时自动从 collect 恢复缺失/损坏的 `desktop`/`mobile`(保留 Agent 写的 `analysis`/`suggestions`),但**不能依赖这个兜底**——终稿应本就保留完整字段。
131
131
  - 若 `collect` 里 `desktop`/`mobile` 本身就是空/全 0(说明 Lighthouse 没有抓到数据),`analysis` 必须写「着陆页测速数据未获取」,**禁止**编造评分或分析文字。
132
132
 
133
+ ### 7. 环比对比表 `campaigns/geographic/keywords.items` — Agent 禁止写入
134
+
135
+ - `collect` 已根据当期 + 上一周期快照生成对比行(`title`、`currentCost`/`previousCost`、`costRateChange`、`currentClicks`/`previousClicks`、`clicksRateChange`、`currentCvr`/`previousCvr`、`cvrRateChange`)。Agent 撰写终稿时**只填** `analysis` / `suggestions`,**禁止**写入、清空、删减或「手工重写」`items` 数组
136
+ - `agentBrief.comparisonTableItemCounts` 给出 collect 侧行数(如 `keywords: 15`);终稿 `keywords.items.length` 须与之一致。若 Agent 误改,`render` 会**始终以**同目录 `google-ads-diagnosis-collect.json` **覆盖**上述三个模块的 `items`(保留 Agent 的 narrative)。
137
+ - 分析文案须引用对比表中的具体词/系列/国家名与环比数字(如「fitness mat 消耗 $230.60,环比下降 39.6%」),**禁止**在 `items` 有数据时写「关键词对比表为空」类结论。
138
+ - `biddingStrategy.items` / `newFeatures.items` 行结构由 collect 生成,Agent 可在合法行上填写 `recommendationReason` / `optimizerRecommendation`,但勿篡改 `duration`(须为天数 number)、`biddingStrategyType`、`strategyName` 等事实字段。
139
+
133
140
  ---
134
141
 
135
142
  ## 页眉信息(报告头)
@@ -246,17 +253,19 @@ siluzan-tso google-ads-diagnosis render \
246
253
  - 指标列:花费(上期/本期/环比)、点击(上期/本期/环比)、转化率(上期/本期/环比)
247
254
  - **数据**:`campaigns.items`(`title`、`previousCost`、`currentCost`、`costRateChange`、`previousClicks`、`currentClicks`、`clicksRateChange`、`previousCvr`、`currentCvr`、`cvrRateChange`)
248
255
  - **分析 / 建议**:`campaigns.analysis`、`campaigns.suggestions`
249
- - **Agent 禁止改写 `items` 行**(须原样保留 collect `reportData`);`render` 会从同目录 collect 自动恢复被改坏的 items
256
+ - **Agent 禁止写入 `items` 行**(只填 `analysis`/`suggestions`);`render` 会以 collect 为准**自动覆盖** Agent 改动的对比表 items
250
257
 
251
258
  #### 国家地区分析
252
259
 
253
260
  - 维度列:**国家/地区**
254
261
  - **数据**:`geographic.items`(同上结构)
262
+ - **Agent 禁止写入 `items` 行**;`render` 自动从 collect 恢复
255
263
 
256
264
  #### 关键词分析
257
265
 
258
266
  - 维度列:**关键词**
259
- - **数据**:`keywords.items`
267
+ - **数据**:`keywords.items`(字段同上;行数见 `agentBrief.comparisonTableItemCounts.keywords`)
268
+ - **Agent 禁止写入/清空 `items`**;分析须引用表中具体词名与环比,勿写「对比表为空」
260
269
 
261
270
  #### 转化成本 / 按日趋势(若页面已渲染)
262
271
 
@@ -47,7 +47,7 @@ siluzan-tso google-ads-diagnosis render \
47
47
  - 若环比列全为 `null`,检查落盘目录是否存在上一周期文件(如 `campaigns-<id>_20260503-20260602.json`);不存在则**重新执行 collect**(勿用手动拼装或 Python 脚本绕过 CLI)。
48
48
 
49
49
  - **render 自动合并(默认开启)**:若同目录存在 `google-ads-diagnosis-collect.json`,且 Agent 改坏了 `campaigns` / `geographic` / `keywords` 的 `items`(缺 `title`/`currentCost` 或环比写成字符串)或整体覆盖丢弃了 `landingPageAnalysis.desktop`/`mobile`,CLI **自动从 collect.reportData 恢复**,保留 Agent 的 `analysis`/`suggestions`。可用 `--no-merge-collect` 关闭;`--collect <file>` 指定 collect 路径。
50
- - **render 硬校验**:合并后对比表仍不完整则 **exit 1**(避免 HTML 表体全空);`summary.keyIssues` / `diagnosisOverview.disadvantages` 与 `newFeatures`/`goldAccount` 等事实字段出现已知矛盾模式(见「撰写硬约束」第 5 条)时同样 **exit 1**。
50
+ - **render 硬校验**:合并后对比表仍不完整则 **exit 1**(避免 HTML 表体全空);`campaigns/geographic/keywords.items` 默认同目录 collect **整表覆盖** Agent 改动(Agent 只填 analysis/suggestions);`summary.keyIssues` / `diagnosisOverview.disadvantages` 与 `newFeatures`/`goldAccount` 等事实字段出现已知矛盾模式(见「撰写硬约束」第 5 条)时同样 **exit 1**。
51
51
 
52
52
  - **禁止**在 `collect` 阶段生成或写入 `analysis` / `suggestions` / `diagnosisOverview` / `summary` 等建议性文案。
53
53
  - **禁止**跳过 Agent 直接 `render` collect 产物(`render` 会校验全部叙事 / 建议字段;调试可加 `--lenient`)。
@@ -130,6 +130,13 @@ siluzan-tso google-ads-diagnosis render \
130
130
  - `render` 会在同目录存在 `google-ads-diagnosis-collect.json` 时自动从 collect 恢复缺失/损坏的 `desktop`/`mobile`(保留 Agent 写的 `analysis`/`suggestions`),但**不能依赖这个兜底**——终稿应本就保留完整字段。
131
131
  - 若 `collect` 里 `desktop`/`mobile` 本身就是空/全 0(说明 Lighthouse 没有抓到数据),`analysis` 必须写「着陆页测速数据未获取」,**禁止**编造评分或分析文字。
132
132
 
133
+ ### 7. 环比对比表 `campaigns/geographic/keywords.items` — Agent 禁止写入
134
+
135
+ - `collect` 已根据当期 + 上一周期快照生成对比行(`title`、`currentCost`/`previousCost`、`costRateChange`、`currentClicks`/`previousClicks`、`clicksRateChange`、`currentCvr`/`previousCvr`、`cvrRateChange`)。Agent 撰写终稿时**只填** `analysis` / `suggestions`,**禁止**写入、清空、删减或「手工重写」`items` 数组
136
+ - `agentBrief.comparisonTableItemCounts` 给出 collect 侧行数(如 `keywords: 15`);终稿 `keywords.items.length` 须与之一致。若 Agent 误改,`render` 会**始终以**同目录 `google-ads-diagnosis-collect.json` **覆盖**上述三个模块的 `items`(保留 Agent 的 narrative)。
137
+ - 分析文案须引用对比表中的具体词/系列/国家名与环比数字(如「fitness mat 消耗 $230.60,环比下降 39.6%」),**禁止**在 `items` 有数据时写「关键词对比表为空」类结论。
138
+ - `biddingStrategy.items` / `newFeatures.items` 行结构由 collect 生成,Agent 可在合法行上填写 `recommendationReason` / `optimizerRecommendation`,但勿篡改 `duration`(须为天数 number)、`biddingStrategyType`、`strategyName` 等事实字段。
139
+
133
140
  ---
134
141
 
135
142
  ## 页眉信息(报告头)
@@ -246,17 +253,19 @@ siluzan-tso google-ads-diagnosis render \
246
253
  - 指标列:花费(上期/本期/环比)、点击(上期/本期/环比)、转化率(上期/本期/环比)
247
254
  - **数据**:`campaigns.items`(`title`、`previousCost`、`currentCost`、`costRateChange`、`previousClicks`、`currentClicks`、`clicksRateChange`、`previousCvr`、`currentCvr`、`cvrRateChange`)
248
255
  - **分析 / 建议**:`campaigns.analysis`、`campaigns.suggestions`
249
- - **Agent 禁止改写 `items` 行**(须原样保留 collect `reportData`);`render` 会从同目录 collect 自动恢复被改坏的 items
256
+ - **Agent 禁止写入 `items` 行**(只填 `analysis`/`suggestions`);`render` 会以 collect 为准**自动覆盖** Agent 改动的对比表 items
250
257
 
251
258
  #### 国家地区分析
252
259
 
253
260
  - 维度列:**国家/地区**
254
261
  - **数据**:`geographic.items`(同上结构)
262
+ - **Agent 禁止写入 `items` 行**;`render` 自动从 collect 恢复
255
263
 
256
264
  #### 关键词分析
257
265
 
258
266
  - 维度列:**关键词**
259
- - **数据**:`keywords.items`
267
+ - **数据**:`keywords.items`(字段同上;行数见 `agentBrief.comparisonTableItemCounts.keywords`)
268
+ - **Agent 禁止写入/清空 `items`**;分析须引用表中具体词名与环比,勿写「对比表为空」
260
269
 
261
270
  #### 转化成本 / 按日趋势(若页面已渲染)
262
271
 
@@ -9,7 +9,7 @@ $ErrorActionPreference = 'Stop'
9
9
  # -- Package info (injected at build time) ------------------------------------
10
10
  $PKG_NAME = 'siluzan-tso-cli'
11
11
  # PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
12
- $PKG_VERSION = '1.1.35-beta.3'
12
+ $PKG_VERSION = '1.1.35-beta.4'
13
13
  $CLI_BIN = 'siluzan-tso'
14
14
  $SKILL_LABEL = 'Siluzan TSO'
15
15
  $INSTALL_CMD = 'npm install -g siluzan-tso-cli@beta'
@@ -9,7 +9,7 @@ set -euo pipefail
9
9
  # -- Package info (injected at build time) ------------------------------------
10
10
  readonly PKG_NAME="siluzan-tso-cli"
11
11
  # PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
12
- readonly PKG_VERSION="1.1.35-beta.3"
12
+ readonly PKG_VERSION="1.1.35-beta.4"
13
13
  readonly CLI_BIN="siluzan-tso"
14
14
  readonly SKILL_LABEL="Siluzan TSO"
15
15
  readonly INSTALL_CMD="npm install -g siluzan-tso-cli@beta"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "siluzan-tso-cli",
3
- "version": "1.1.35-beta.3",
3
+ "version": "1.1.35-beta.4",
4
4
  "description": "Siluzan 广告账户管理 CLI — 查询账户、余额、消耗数据,管理绑定关系与充值。",
5
5
  "keywords": [
6
6
  "ad-account",