siluzan-tso-cli 1.1.19-beta.8 → 1.1.19

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
@@ -43,7 +43,7 @@ HTML 报告模板引用以下 CDN:`cdn.tailwindcss.com`、`cdnjs.cloudflare.co
43
43
  在**用户的目标项目根目录**执行(根据用户使用的助手选择 `--ai`):
44
44
 
45
45
  ```bash
46
- npm install -g siluzan-tso-cli@beta
46
+ npm install -g siluzan-tso-cli
47
47
  siluzan-tso init --ai cursor # 写入 Cursor(默认)
48
48
  siluzan-tso init --ai cursor,claude # 同时写入多个平台
49
49
  siluzan-tso init --ai all # 写入所有支持的平台
@@ -51,7 +51,6 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
51
51
  siluzan-tso init --force # 强制覆盖已存在文件
52
52
  ```
53
53
 
54
- > **注意**:当前为测试版(1.1.19-beta.8),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
55
54
 
56
55
  | 助手 | 建议 `--ai` |
57
56
  | ----------------------- | ------------------------------------ |
package/dist/index.js CHANGED
@@ -3292,7 +3292,7 @@ var DEFAULT_API_BASE;
3292
3292
  var init_defaults = __esm({
3293
3293
  "src/config/defaults.ts"() {
3294
3294
  "use strict";
3295
- DEFAULT_API_BASE = "https://tso-api-ci.siluzan.com";
3295
+ DEFAULT_API_BASE = "https://tso-api.siluzan.com";
3296
3296
  }
3297
3297
  });
3298
3298
 
@@ -4526,6 +4526,18 @@ import * as path11 from "path";
4526
4526
  function googleAnalysisManifestFile(accountId) {
4527
4527
  return `${applyIdSuffix("manifest", accountId)}.json`;
4528
4528
  }
4529
+ function buildOutlineHints(section) {
4530
+ const hints = [];
4531
+ if (RATE_BEARING_SECTIONS.has(section)) {
4532
+ hints.push(...GOOGLE_ANALYSIS_RATE_NORMALIZED_OUTLINE_HINTS);
4533
+ }
4534
+ if (section === "campaigns") {
4535
+ hints.push(...GOOGLE_ANALYSIS_CAMPAIGNS_OUTLINE_BUDGET_HINTS);
4536
+ }
4537
+ const zhHints = GOOGLE_ANALYSIS_ZH_FIELD_HINTS_BY_SECTION[section];
4538
+ if (zhHints) hints.push(...zhHints);
4539
+ return hints.length > 0 ? hints : void 0;
4540
+ }
4529
4541
  function sectionToFilename(section, accountId) {
4530
4542
  if (!/^[a-z0-9-]+$/.test(section)) {
4531
4543
  throw new Error(`\u975E\u6CD5\u5B50\u547D\u4EE4\u540D\uFF0C\u65E0\u6CD5\u751F\u6210\u6587\u4EF6\u540D\uFF1A${section}`);
@@ -4585,7 +4597,7 @@ async function writeGoogleAnalysisSnapshot(params) {
4585
4597
  await fs7.writeFile(path11.join(absDir, fileName), `${body}
4586
4598
  `, "utf8");
4587
4599
  const outlineFileName = snapshotOutlineFileName(fileName);
4588
- const outlineExtra = params.section === "campaigns" ? GOOGLE_ANALYSIS_CAMPAIGNS_OUTLINE_BUDGET_HINTS : void 0;
4600
+ const outlineExtra = buildOutlineHints(params.section);
4589
4601
  const outlineBody = formatOutlineFileBody(fileName, params.payload, outlineExtra);
4590
4602
  await fs7.writeFile(path11.join(absDir, outlineFileName), `${outlineBody}
4591
4603
  `, "utf8");
@@ -4620,7 +4632,7 @@ async function writeGoogleAnalysisSnapshot(params) {
4620
4632
  agentHint: OUTLINE_AGENT_HINT
4621
4633
  };
4622
4634
  }
4623
- var LEGACY_MANIFEST_FILE, CLI_PACKAGE2, SCHEMA_VERSION2, DEFAULT_FIELD_GUIDE2, GOOGLE_ANALYSIS_CAMPAIGNS_OUTLINE_BUDGET_HINTS;
4635
+ var LEGACY_MANIFEST_FILE, CLI_PACKAGE2, SCHEMA_VERSION2, DEFAULT_FIELD_GUIDE2, GOOGLE_ANALYSIS_CAMPAIGNS_OUTLINE_BUDGET_HINTS, RATE_BEARING_SECTIONS, GOOGLE_ANALYSIS_RATE_NORMALIZED_OUTLINE_HINTS, GOOGLE_ANALYSIS_ZH_FIELD_HINTS_BY_SECTION;
4624
4636
  var init_google_analysis = __esm({
4625
4637
  "src/utils/snapshot/google-analysis.ts"() {
4626
4638
  "use strict";
@@ -4628,7 +4640,7 @@ var init_google_analysis = __esm({
4628
4640
  init_dir();
4629
4641
  LEGACY_MANIFEST_FILE = "manifest.json";
4630
4642
  CLI_PACKAGE2 = "siluzan-tso-cli";
4631
- SCHEMA_VERSION2 = 1;
4643
+ SCHEMA_VERSION2 = 2;
4632
4644
  DEFAULT_FIELD_GUIDE2 = {
4633
4645
  markdownRefs: ["references/account-analytics.md"],
4634
4646
  tsTypesModule: "tso-cli/src/types/google-analysis-api.ts"
@@ -4637,6 +4649,40 @@ var init_google_analysis = __esm({
4637
4649
  "// \u91D1\u989D\uFF1A`campaigns[].budgetAmount`\uFF1D\u7F51\u5173\u300C\u5206\u300D\uFF08\u4E3B\u5E01\u79CD\xD7100 \u7684\u6574\u6570\uFF09\uFF0C**\u5143\uFF1D\xF7100**\uFF1B**\u7981\u6B62**\u6309\u5FAE\u5143 **\xF71_000_000**\uFF08\u4F1A\u7EA6\u5C0F\u4E00\u4E07\u500D\uFF09\u3002",
4638
4650
  "// \u540C\u6587\u4EF6 `spend`\u3001`averageCpc`\u3001`costPerConversion` \u7B49\u5DF2\u4E3A\u300C\u5143\u300D\u5C0F\u6570\u3002\u8BE6 `references/account-analytics.md`\u300CCampaignSectionData\u300D\u3002"
4639
4651
  ];
4652
+ RATE_BEARING_SECTIONS = /* @__PURE__ */ new Set([
4653
+ "overview",
4654
+ "keywords",
4655
+ "search-terms",
4656
+ "campaigns",
4657
+ "ads",
4658
+ "extensions",
4659
+ "devices",
4660
+ "geographic",
4661
+ "campaign-geo",
4662
+ "campaign-device",
4663
+ "audience",
4664
+ "asset-images",
4665
+ "videos",
4666
+ "materials",
4667
+ "daily-metrics",
4668
+ "dimension-summary",
4669
+ "ads-index"
4670
+ ]);
4671
+ GOOGLE_ANALYSIS_RATE_NORMALIZED_OUTLINE_HINTS = [
4672
+ "// \u6982\u7387\u5B57\u6BB5\uFF1A`ctr` / `conversionRate` \u81EA manifest schemaVersion 2\uFF082026-05\uFF09\u8D77\u5DF2\u7531 CLI \u7EDF\u4E00\u5F52\u4E00\u4E3A **0~1 \u5C0F\u6570**\uFF08\u5982 `0.0964` = 9.64%\uFF09\u3002",
4673
+ "// \u5199 Excel 0~1 \u5C0F\u6570\u5217\uFF1A\u76F4\u63A5\u5199\u5165\uFF1B\u5199\u300Cx%\u300D\u6587\u6848\uFF1A`(v * 100).toFixed(2) + '%'`\uFF1B**\u7981\u6B62**\u518D \xF7100\u3002`interactionRate` \u4ECD\u662F\u5B57\u7B26\u4E32 0~1 \u5C0F\u6570\uFF0C`parseFloat` \u540E\u4F7F\u7528\u3002"
4674
+ ];
4675
+ GOOGLE_ANALYSIS_ZH_FIELD_HINTS_BY_SECTION = {
4676
+ keywords: [
4677
+ "// \u4E2D\u6587\u8BD1\u540D\uFF1A`keywordMatchTypeZh`\uFF08\u7531 `keywordMatchType` \u7ECF match-type-en2zh.json \u7FFB\u8BD1\uFF0C\u8986\u76D6 BROAD/PHRASE/EXACT \u4E0E Broad/Phrase/Exact \u5927\u5C0F\u5199\uFF1B\u672A\u547D\u4E2D\u65F6\u8BE5\u5B57\u6BB5\u7F3A\u7701\uFF09\u3002"
4678
+ ],
4679
+ "search-terms": [
4680
+ "// \u4E2D\u6587\u8BD1\u540D\uFF1A`matchTypeZh`\uFF08\u7531 `matchType` \u7ECF match-type-en2zh.json \u7FFB\u8BD1\uFF1B\u672A\u547D\u4E2D\u65F6\u8BE5\u5B57\u6BB5\u7F3A\u7701\uFF09\u3002"
4681
+ ],
4682
+ "campaign-geo": [
4683
+ "// \u4E2D\u6587\u8BD1\u540D\uFF1A`countryOrRegionZh`\uFF08\u7531 `countryOrRegion` \u7ECF geo-en2zh.json \u7FFB\u8BD1\uFF0C\u76EE\u524D\u8986\u76D6 105 \u4E2A\u56FD\u5BB6/\u5730\u533A\uFF1B\u672A\u547D\u4E2D\u65F6\u8BE5\u5B57\u6BB5\u7F3A\u7701\uFF09\u3002"
4684
+ ]
4685
+ };
4640
4686
  }
4641
4687
  });
4642
4688
 
@@ -4694,7 +4740,7 @@ var init_sections = __esm({
4694
4740
  description: "\u5173\u952E\u8BCD\u5206\u6BB5 KeywordSectionData",
4695
4741
  dateMode: "range",
4696
4742
  path: (id) => `/reporting/media-account/${id}/KeywordSectionData`,
4697
- defaultQuery: { limit: 100, orderByCost: true },
4743
+ defaultQuery: { limit: 200, orderByCost: true },
4698
4744
  keywordOptions: true
4699
4745
  },
4700
4746
  {
@@ -4702,7 +4748,7 @@ var init_sections = __esm({
4702
4748
  description: "\u641C\u7D22\u8BCD searchtermmanagement/v2/list",
4703
4749
  dateMode: "range",
4704
4750
  path: (id) => `/searchtermmanagement/v2/list/${id}`,
4705
- defaultQuery: { limit: 100, orderByCost: true },
4751
+ defaultQuery: { limit: 200, orderByCost: true },
4706
4752
  keywordOptions: true
4707
4753
  },
4708
4754
  {
@@ -4833,6 +4879,340 @@ var init_sections = __esm({
4833
4879
  }
4834
4880
  });
4835
4881
 
4882
+ // src/commands/google-analysis/normalize-rates.ts
4883
+ function divIfFiniteNumber(v) {
4884
+ return typeof v === "number" && Number.isFinite(v) ? v / 100 : v;
4885
+ }
4886
+ function divideRatesInPlace(value, seen) {
4887
+ if (value === null || typeof value !== "object") return;
4888
+ if (seen.has(value)) return;
4889
+ seen.add(value);
4890
+ if (Array.isArray(value)) {
4891
+ for (const item of value) divideRatesInPlace(item, seen);
4892
+ return;
4893
+ }
4894
+ const obj = value;
4895
+ for (const k of Object.keys(obj)) {
4896
+ if (RATE_FIELD_NAMES.has(k)) {
4897
+ obj[k] = divIfFiniteNumber(obj[k]);
4898
+ } else {
4899
+ divideRatesInPlace(obj[k], seen);
4900
+ }
4901
+ }
4902
+ }
4903
+ function normalizeRateScales(payload, section) {
4904
+ if (!PERCENT_SCALE_SECTIONS.has(section)) return payload;
4905
+ divideRatesInPlace(payload, /* @__PURE__ */ new WeakSet());
4906
+ return payload;
4907
+ }
4908
+ var PERCENT_SCALE_SECTIONS, RATE_FIELD_NAMES;
4909
+ var init_normalize_rates = __esm({
4910
+ "src/commands/google-analysis/normalize-rates.ts"() {
4911
+ "use strict";
4912
+ PERCENT_SCALE_SECTIONS = /* @__PURE__ */ new Set([
4913
+ "overview",
4914
+ "keywords",
4915
+ "search-terms",
4916
+ "campaigns",
4917
+ "ads",
4918
+ "extensions",
4919
+ "devices",
4920
+ "ads-index"
4921
+ ]);
4922
+ RATE_FIELD_NAMES = /* @__PURE__ */ new Set(["ctr", "conversionRate"]);
4923
+ }
4924
+ });
4925
+
4926
+ // src/commands/google-analysis/match-type-en2zh.json
4927
+ var match_type_en2zh_default;
4928
+ var init_match_type_en2zh = __esm({
4929
+ "src/commands/google-analysis/match-type-en2zh.json"() {
4930
+ match_type_en2zh_default = {
4931
+ BROAD: "\u5E7F\u6CDB\u5339\u914D",
4932
+ PHRASE: "\u8BCD\u7EC4\u5339\u914D",
4933
+ EXACT: "\u7CBE\u786E\u5339\u914D",
4934
+ NEAR_PHRASE: "\u8FD1\u4E49\u8BCD\u7EC4\u5339\u914D",
4935
+ NEAR_EXACT: "\u8FD1\u4E49\u7CBE\u786E\u5339\u914D",
4936
+ Broad: "\u5E7F\u6CDB\u5339\u914D",
4937
+ Phrase: "\u8BCD\u7EC4\u5339\u914D",
4938
+ Exact: "\u7CBE\u786E\u5339\u914D",
4939
+ Near_Phrase: "\u8FD1\u4E49\u8BCD\u7EC4\u5339\u914D",
4940
+ Near_Exact: "\u8FD1\u4E49\u7CBE\u786E\u5339\u914D"
4941
+ };
4942
+ }
4943
+ });
4944
+
4945
+ // src/commands/google-analysis/geo-en2zh.json
4946
+ var geo_en2zh_default;
4947
+ var init_geo_en2zh = __esm({
4948
+ "src/commands/google-analysis/geo-en2zh.json"() {
4949
+ geo_en2zh_default = {
4950
+ Afghanistan: "\u963F\u5BCC\u6C57",
4951
+ Albania: "\u963F\u5C14\u5DF4\u5C3C\u4E9A",
4952
+ Algeria: "\u963F\u5C14\u53CA\u5229\u4E9A",
4953
+ Andorra: "\u5B89\u9053\u5C14",
4954
+ Angola: "\u5B89\u54E5\u62C9",
4955
+ "Antigua & Barbuda": "\u5B89\u63D0\u74DC\u548C\u5DF4\u5E03\u8FBE",
4956
+ "Antigua and Barbuda": "\u5B89\u63D0\u74DC\u548C\u5DF4\u5E03\u8FBE",
4957
+ Argentina: "\u963F\u6839\u5EF7",
4958
+ Armenia: "\u4E9A\u7F8E\u5C3C\u4E9A",
4959
+ Australia: "\u6FB3\u5927\u5229\u4E9A",
4960
+ Austria: "\u5965\u5730\u5229",
4961
+ Azerbaijan: "\u963F\u585E\u62DC\u7586",
4962
+ Bahamas: "\u5DF4\u54C8\u9A6C",
4963
+ Bahrain: "\u5DF4\u6797",
4964
+ Bangladesh: "\u5B5F\u52A0\u62C9\u56FD",
4965
+ Barbados: "\u5DF4\u5DF4\u591A\u65AF",
4966
+ Belarus: "\u767D\u4FC4\u7F57\u65AF",
4967
+ Belgium: "\u6BD4\u5229\u65F6",
4968
+ Belize: "\u4F2F\u5229\u5179",
4969
+ Benin: "\u8D1D\u5B81",
4970
+ Bhutan: "\u4E0D\u4E39",
4971
+ Bolivia: "\u73BB\u5229\u7EF4\u4E9A",
4972
+ "Bosnia & Herzegovina": "\u6CE2\u65AF\u5C3C\u4E9A\u548C\u9ED1\u585E\u54E5\u7EF4\u90A3",
4973
+ "Bosnia and Herzegovina": "\u6CE2\u65AF\u5C3C\u4E9A\u548C\u9ED1\u585E\u54E5\u7EF4\u90A3",
4974
+ Botswana: "\u535A\u8328\u74E6\u7EB3",
4975
+ Brazil: "\u5DF4\u897F",
4976
+ Brunei: "\u6587\u83B1",
4977
+ Bulgaria: "\u4FDD\u52A0\u5229\u4E9A",
4978
+ "Burkina Faso": "\u5E03\u57FA\u7EB3\u6CD5\u7D22",
4979
+ Burundi: "\u5E03\u9686\u8FEA",
4980
+ "Cabo Verde": "\u4F5B\u5F97\u89D2",
4981
+ Cambodia: "\u67EC\u57D4\u5BE8",
4982
+ Cameroon: "\u5580\u9EA6\u9686",
4983
+ Canada: "\u52A0\u62FF\u5927",
4984
+ "Central African Republic": "\u4E2D\u975E\u5171\u548C\u56FD",
4985
+ Chad: "\u4E4D\u5F97",
4986
+ Chile: "\u667A\u5229",
4987
+ China: "\u4E2D\u56FD",
4988
+ Colombia: "\u54E5\u4F26\u6BD4\u4E9A",
4989
+ Comoros: "\u79D1\u6469\u7F57",
4990
+ "Costa Rica": "\u54E5\u65AF\u8FBE\u9ECE\u52A0",
4991
+ "Cote d'Ivoire": "\u79D1\u7279\u8FEA\u74E6",
4992
+ Croatia: "\u514B\u7F57\u5730\u4E9A",
4993
+ Cuba: "\u53E4\u5DF4",
4994
+ Cyprus: "\u585E\u6D66\u8DEF\u65AF",
4995
+ Czechia: "\u6377\u514B",
4996
+ "Democratic Republic of the Congo": "\u521A\u679C\u6C11\u4E3B\u5171\u548C\u56FD",
4997
+ Denmark: "\u4E39\u9EA6",
4998
+ Djibouti: "\u5409\u5E03\u63D0",
4999
+ Dominica: "\u591A\u7C73\u5C3C\u514B",
5000
+ "Dominican Republic": "\u591A\u7C73\u5C3C\u52A0\u5171\u548C\u56FD",
5001
+ Ecuador: "\u5384\u74DC\u591A\u5C14",
5002
+ Egypt: "\u57C3\u53CA",
5003
+ "El Salvador": "\u8428\u5C14\u74E6\u591A",
5004
+ "Equatorial Guinea": "\u8D64\u9053\u51E0\u5185\u4E9A",
5005
+ Eritrea: "\u5384\u7ACB\u7279\u91CC\u4E9A",
5006
+ Estonia: "\u7231\u6C99\u5C3C\u4E9A",
5007
+ Eswatini: "\u65AF\u5A01\u58EB\u5170",
5008
+ Ethiopia: "\u57C3\u585E\u4FC4\u6BD4\u4E9A",
5009
+ Fiji: "\u6590\u6D4E",
5010
+ Finland: "\u82AC\u5170",
5011
+ France: "\u6CD5\u56FD",
5012
+ Gabon: "\u52A0\u84EC",
5013
+ Gambia: "\u5188\u6BD4\u4E9A",
5014
+ Georgia: "\u683C\u9C81\u5409\u4E9A",
5015
+ Germany: "\u5FB7\u56FD",
5016
+ Ghana: "\u52A0\u7EB3",
5017
+ Greece: "\u5E0C\u814A",
5018
+ Grenada: "\u683C\u6797\u7EB3\u8FBE",
5019
+ Guatemala: "\u5371\u5730\u9A6C\u62C9",
5020
+ Guinea: "\u51E0\u5185\u4E9A",
5021
+ "Guinea-Bissau": "\u51E0\u5185\u4E9A\u6BD4\u7ECD",
5022
+ Guyana: "\u572D\u4E9A\u90A3",
5023
+ Haiti: "\u6D77\u5730",
5024
+ Honduras: "\u6D2A\u90FD\u62C9\u65AF",
5025
+ "Hong Kong": "\u9999\u6E2F",
5026
+ Hungary: "\u5308\u7259\u5229",
5027
+ Iceland: "\u51B0\u5C9B",
5028
+ India: "\u5370\u5EA6",
5029
+ Indonesia: "\u5370\u5EA6\u5C3C\u897F\u4E9A",
5030
+ Iran: "\u4F0A\u6717",
5031
+ Iraq: "\u4F0A\u62C9\u514B",
5032
+ Ireland: "\u7231\u5C14\u5170",
5033
+ "Isle of Man": "\u9A6C\u6069\u5C9B",
5034
+ Israel: "\u4EE5\u8272\u5217",
5035
+ Italy: "\u610F\u5927\u5229",
5036
+ Jamaica: "\u7259\u4E70\u52A0",
5037
+ Japan: "\u65E5\u672C",
5038
+ Johannesburg: "\u7EA6\u7FF0\u5185\u65AF\u5821",
5039
+ Jordan: "\u7EA6\u65E6",
5040
+ Kazakhstan: "\u54C8\u8428\u514B\u65AF\u5766",
5041
+ Kenya: "\u80AF\u5C3C\u4E9A",
5042
+ Kiribati: "\u57FA\u91CC\u5DF4\u65AF",
5043
+ Kosovo: "\u79D1\u7D22\u6C83",
5044
+ Kuwait: "\u79D1\u5A01\u7279",
5045
+ Kyrgyzstan: "\u5409\u5C14\u5409\u65AF\u65AF\u5766",
5046
+ Laos: "\u8001\u631D",
5047
+ Latvia: "\u62C9\u8131\u7EF4\u4E9A",
5048
+ Lebanon: "\u9ECE\u5DF4\u5AE9",
5049
+ Lesotho: "\u83B1\u7D22\u6258",
5050
+ Liberia: "\u5229\u6BD4\u91CC\u4E9A",
5051
+ Libya: "\u5229\u6BD4\u4E9A",
5052
+ Liechtenstein: "\u5217\u652F\u6566\u58EB\u767B",
5053
+ Lithuania: "\u7ACB\u9676\u5B9B",
5054
+ Luxembourg: "\u5362\u68EE\u5821",
5055
+ Macau: "\u6FB3\u95E8",
5056
+ Madagascar: "\u9A6C\u8FBE\u52A0\u65AF\u52A0",
5057
+ Malawi: "\u9A6C\u62C9\u7EF4",
5058
+ Malaysia: "\u9A6C\u6765\u897F\u4E9A",
5059
+ Maldives: "\u9A6C\u5C14\u4EE3\u592B",
5060
+ Mali: "\u9A6C\u91CC",
5061
+ Malta: "\u9A6C\u8033\u4ED6",
5062
+ "Marshall Islands": "\u9A6C\u7ECD\u5C14\u7FA4\u5C9B",
5063
+ Mauritania: "\u6BDB\u91CC\u5854\u5C3C\u4E9A",
5064
+ Mauritius: "\u6BDB\u91CC\u6C42\u65AF",
5065
+ Mexico: "\u58A8\u897F\u54E5",
5066
+ Micronesia: "\u5BC6\u514B\u7F57\u5C3C\u897F\u4E9A",
5067
+ Moldova: "\u6469\u5C14\u591A\u74E6",
5068
+ Monaco: "\u6469\u7EB3\u54E5",
5069
+ Mongolia: "\u8499\u53E4",
5070
+ Montenegro: "\u9ED1\u5C71",
5071
+ Morocco: "\u6469\u6D1B\u54E5",
5072
+ Mozambique: "\u83AB\u6851\u6BD4\u514B",
5073
+ "Myanmar (Burma)": "\u7F05\u7538",
5074
+ Namibia: "\u7EB3\u7C73\u6BD4\u4E9A",
5075
+ Nauru: "\u7459\u9C81",
5076
+ Nepal: "\u5C3C\u6CCA\u5C14",
5077
+ Netherlands: "\u8377\u5170",
5078
+ "New Zealand": "\u65B0\u897F\u5170",
5079
+ Nicaragua: "\u5C3C\u52A0\u62C9\u74DC",
5080
+ Niger: "\u5C3C\u65E5\u5C14",
5081
+ Nigeria: "\u5C3C\u65E5\u5229\u4E9A",
5082
+ "North Korea": "\u671D\u9C9C",
5083
+ "North Macedonia": "\u5317\u9A6C\u5176\u987F",
5084
+ Norway: "\u632A\u5A01",
5085
+ Oman: "\u963F\u66FC",
5086
+ Pakistan: "\u5DF4\u57FA\u65AF\u5766",
5087
+ Palau: "\u5E15\u52B3",
5088
+ Palestine: "\u5DF4\u52D2\u65AF\u5766",
5089
+ Panama: "\u5DF4\u62FF\u9A6C",
5090
+ "Papua New Guinea": "\u5DF4\u5E03\u4E9A\u65B0\u51E0\u5185\u4E9A",
5091
+ Paraguay: "\u5DF4\u62C9\u572D",
5092
+ Peru: "\u79D8\u9C81",
5093
+ Philippines: "\u83F2\u5F8B\u5BBE",
5094
+ Poland: "\u6CE2\u5170",
5095
+ Portugal: "\u8461\u8404\u7259",
5096
+ "Puerto Rico": "\u6CE2\u591A\u9ECE\u5404",
5097
+ Qatar: "\u5361\u5854\u5C14",
5098
+ "Republic of the Congo": "\u521A\u679C\u5171\u548C\u56FD",
5099
+ Romania: "\u7F57\u9A6C\u5C3C\u4E9A",
5100
+ Russia: "\u4FC4\u7F57\u65AF",
5101
+ Rwanda: "\u5362\u65FA\u8FBE",
5102
+ "Saint Kitts and Nevis": "\u5723\u57FA\u8328\u548C\u5C3C\u7EF4\u65AF",
5103
+ "Saint Lucia": "\u5723\u5362\u897F\u4E9A",
5104
+ "Saint Vincent and the Grenadines": "\u5723\u6587\u68EE\u7279\u548C\u683C\u6797\u7EB3\u4E01\u65AF",
5105
+ Samoa: "\u8428\u6469\u4E9A",
5106
+ "San Marino": "\u5723\u9A6C\u529B\u8BFA",
5107
+ "S\xE3o Tom\xE9 & Pr\xEDncipe": "\u5723\u591A\u7F8E\u548C\u666E\u6797\u897F\u6BD4",
5108
+ "Sao Tome and Principe": "\u5723\u591A\u7F8E\u548C\u666E\u6797\u897F\u6BD4",
5109
+ "Saudi Arabia": "\u6C99\u7279\u963F\u62C9\u4F2F",
5110
+ Senegal: "\u585E\u5185\u52A0\u5C14",
5111
+ Serbia: "\u585E\u5C14\u7EF4\u4E9A",
5112
+ Seychelles: "\u585E\u820C\u5C14",
5113
+ "Sierra Leone": "\u585E\u62C9\u5229\u6602",
5114
+ Singapore: "\u65B0\u52A0\u5761",
5115
+ Slovakia: "\u65AF\u6D1B\u4F10\u514B",
5116
+ Slovenia: "\u65AF\u6D1B\u6587\u5C3C\u4E9A",
5117
+ "Solomon Islands": "\u6240\u7F57\u95E8\u7FA4\u5C9B",
5118
+ Somalia: "\u7D22\u9A6C\u91CC",
5119
+ "South Africa": "\u5357\u975E",
5120
+ "South Korea": "\u97E9\u56FD",
5121
+ "South Sudan": "\u5357\u82CF\u4E39",
5122
+ Spain: "\u897F\u73ED\u7259",
5123
+ "Spanish Fork": "Spanish Fork",
5124
+ "Sri Lanka": "\u65AF\u91CC\u5170\u5361",
5125
+ "St. Kitts & Nevis": "\u5723\u57FA\u8328\u548C\u5C3C\u7EF4\u65AF",
5126
+ "St. Lucia": "\u5723\u5362\u897F\u4E9A",
5127
+ "St. Vincent & Grenadines": "\u5723\u6587\u68EE\u7279\u548C\u683C\u6797\u7EB3\u4E01\u65AF",
5128
+ Sudan: "\u82CF\u4E39",
5129
+ Suriname: "\u82CF\u91CC\u5357",
5130
+ Sweden: "\u745E\u5178",
5131
+ Switzerland: "\u745E\u58EB",
5132
+ Syria: "\u53D9\u5229\u4E9A",
5133
+ Taiwan: "\u53F0\u6E7E",
5134
+ Tajikistan: "\u5854\u5409\u514B\u65AF\u5766",
5135
+ Tanzania: "\u5766\u6851\u5C3C\u4E9A",
5136
+ Thailand: "\u6CF0\u56FD",
5137
+ "Timor-Leste": "\u4E1C\u5E1D\u6C76",
5138
+ Togo: "\u591A\u54E5",
5139
+ Tonga: "\u6C64\u52A0",
5140
+ "Trinidad & Tobago": "\u7279\u7ACB\u5C3C\u8FBE\u548C\u591A\u5DF4\u54E5",
5141
+ "Trinidad and Tobago": "\u7279\u7ACB\u5C3C\u8FBE\u548C\u591A\u5DF4\u54E5",
5142
+ Tunisia: "\u7A81\u5C3C\u65AF",
5143
+ Turkiye: "\u571F\u8033\u5176",
5144
+ Turkmenistan: "\u571F\u5E93\u66FC\u65AF\u5766",
5145
+ Tuvalu: "\u56FE\u74E6\u5362",
5146
+ Uganda: "\u4E4C\u5E72\u8FBE",
5147
+ Ukraine: "\u4E4C\u514B\u5170",
5148
+ "United Arab Emirates": "\u963F\u8054\u914B",
5149
+ "United Kingdom": "\u82F1\u56FD",
5150
+ "United States": "\u7F8E\u56FD",
5151
+ Uruguay: "\u4E4C\u62C9\u572D",
5152
+ Uzbekistan: "\u4E4C\u5179\u522B\u514B\u65AF\u5766",
5153
+ Vanuatu: "\u74E6\u52AA\u963F\u56FE",
5154
+ "Vatican City": "\u68B5\u8482\u5188",
5155
+ Venezuela: "\u59D4\u5185\u745E\u62C9",
5156
+ Vietnam: "\u8D8A\u5357",
5157
+ Yemen: "\u4E5F\u95E8",
5158
+ Zambia: "\u8D5E\u6BD4\u4E9A",
5159
+ Zimbabwe: "\u6D25\u5DF4\u5E03\u97E6"
5160
+ };
5161
+ }
5162
+ });
5163
+
5164
+ // src/commands/google-analysis/translate-fields.ts
5165
+ function lookupZh(dict, key) {
5166
+ if (typeof key !== "string" || key === "") return void 0;
5167
+ return dict[key];
5168
+ }
5169
+ function annotateRow(row, source, target, dict) {
5170
+ if (row[target] !== void 0) return;
5171
+ const zh = lookupZh(dict, row[source]);
5172
+ if (zh !== void 0) row[target] = zh;
5173
+ }
5174
+ function annotateArrayRows(rows, source, target, dict) {
5175
+ if (!Array.isArray(rows)) return;
5176
+ for (const r of rows) {
5177
+ if (r && typeof r === "object" && !Array.isArray(r)) {
5178
+ annotateRow(r, source, target, dict);
5179
+ }
5180
+ }
5181
+ }
5182
+ function annotateZhFields(payload, section) {
5183
+ if (payload === null || typeof payload !== "object") return payload;
5184
+ switch (section) {
5185
+ case "keywords": {
5186
+ const rows = payload.keywords;
5187
+ annotateArrayRows(rows, "keywordMatchType", "keywordMatchTypeZh", MATCH_TYPE_DICT);
5188
+ break;
5189
+ }
5190
+ case "search-terms": {
5191
+ const rows = payload.data;
5192
+ annotateArrayRows(rows, "matchType", "matchTypeZh", MATCH_TYPE_DICT);
5193
+ break;
5194
+ }
5195
+ case "campaign-geo": {
5196
+ const rows = payload.countries;
5197
+ annotateArrayRows(rows, "countryOrRegion", "countryOrRegionZh", GEO_DICT);
5198
+ break;
5199
+ }
5200
+ default:
5201
+ break;
5202
+ }
5203
+ return payload;
5204
+ }
5205
+ var MATCH_TYPE_DICT, GEO_DICT;
5206
+ var init_translate_fields = __esm({
5207
+ "src/commands/google-analysis/translate-fields.ts"() {
5208
+ "use strict";
5209
+ init_match_type_en2zh();
5210
+ init_geo_en2zh();
5211
+ MATCH_TYPE_DICT = match_type_en2zh_default;
5212
+ GEO_DICT = geo_en2zh_default;
5213
+ }
5214
+ });
5215
+
4836
5216
  // src/commands/google-analysis/fetch.ts
4837
5217
  function defaultDateRange3() {
4838
5218
  const end = /* @__PURE__ */ new Date();
@@ -4870,6 +5250,31 @@ async function fetchJson(config, pathWithQuery, verbose) {
4870
5250
  const url = `${config.googleApiUrl}${pathWithQuery}`;
4871
5251
  return apiFetch2(url, config, {}, verbose);
4872
5252
  }
5253
+ function deviceBidModifierLookupKey(campaignId, adGroupId, deviceType) {
5254
+ return `${campaignId ?? ""}\0${adGroupId ?? ""}\0${deviceType ?? ""}`;
5255
+ }
5256
+ function mergeDeviceBidModifiersIntoReport(report, modifiers) {
5257
+ const rows = report.devices;
5258
+ if (!Array.isArray(rows) || rows.length === 0) return report;
5259
+ if (!Array.isArray(modifiers) || modifiers.length === 0) return report;
5260
+ const byKey = /* @__PURE__ */ new Map();
5261
+ for (const m of modifiers) {
5262
+ byKey.set(
5263
+ deviceBidModifierLookupKey(m.campaignId, m.adGroupId, m.deviceType),
5264
+ m
5265
+ );
5266
+ }
5267
+ const devices = rows.map((row) => {
5268
+ const hit = byKey.get(deviceBidModifierLookupKey(row.campaignId, row.adGroupId, row.deviceType)) ?? (row.adGroupId ? void 0 : byKey.get(deviceBidModifierLookupKey(row.campaignId, null, row.deviceType)));
5269
+ if (!hit || hit.bidModifier === void 0) return row;
5270
+ return {
5271
+ ...row,
5272
+ bidModifier: hit.bidModifier,
5273
+ bidModifierSpecified: hit.bidModifierSpecified
5274
+ };
5275
+ });
5276
+ return { ...report, devices };
5277
+ }
4873
5278
  function assertNever(x, ctx) {
4874
5279
  throw new Error(`${ctx}\uFF1A\u672A\u5904\u7406\u7684\u5206\u652F ${String(x)}`);
4875
5280
  }
@@ -4968,7 +5373,27 @@ async function fetchSectionPayload(def, opts, config, id) {
4968
5373
  fetchJson(config, videoPath, !!opts.verbose)
4969
5374
  ]);
4970
5375
  const merged = { images, videos };
4971
- return stripLegacyGoogleFieldsIfV2Present(merged);
5376
+ return annotateZhFields(
5377
+ normalizeRateScales(stripLegacyGoogleFieldsIfV2Present(merged), "materials"),
5378
+ "materials"
5379
+ );
5380
+ }
5381
+ if (def.name === "campaign-device") {
5382
+ const sectionPath2 = def.path(id);
5383
+ const query2 = buildSearchParams(def, opts.start, opts.end, extras);
5384
+ const [report, modifiers] = await Promise.all([
5385
+ fetchJson(config, `${sectionPath2}${query2}`, !!opts.verbose),
5386
+ fetchJson(
5387
+ config,
5388
+ `/campaignmanagement/${id}/BidModifiers/Devices`,
5389
+ !!opts.verbose
5390
+ )
5391
+ ]);
5392
+ const data2 = mergeDeviceBidModifiersIntoReport(report, modifiers);
5393
+ return annotateZhFields(
5394
+ normalizeRateScales(stripLegacyGoogleFieldsIfV2Present(data2), def.name),
5395
+ def.name
5396
+ );
4972
5397
  }
4973
5398
  if (def.name === "daily-metrics") {
4974
5399
  const { startDate, endDate } = resolveDateRange2(opts.start, opts.end);
@@ -4980,7 +5405,10 @@ async function fetchSectionPayload(def, opts, config, id) {
4980
5405
  const url = `${config.apiBaseUrl}/report/media-account/google/account-daily-reports?${params.toString()}`;
4981
5406
  const raw = await apiFetch2(url, config, {}, !!opts.verbose);
4982
5407
  const rows = rowsFromAccountDailyReportsEnvelope(raw, id);
4983
- return stripLegacyGoogleFieldsIfV2Present(rows);
5408
+ return annotateZhFields(
5409
+ normalizeRateScales(stripLegacyGoogleFieldsIfV2Present(rows), "daily-metrics"),
5410
+ "daily-metrics"
5411
+ );
4984
5412
  }
4985
5413
  const sectionPath = def.path(id);
4986
5414
  const query = buildSearchParams(def, opts.start, opts.end, extras);
@@ -4990,7 +5418,10 @@ async function fetchSectionPayload(def, opts, config, id) {
4990
5418
  !!opts.verbose,
4991
5419
  def.name
4992
5420
  );
4993
- return stripLegacyGoogleFieldsIfV2Present(data);
5421
+ return annotateZhFields(
5422
+ normalizeRateScales(stripLegacyGoogleFieldsIfV2Present(data), def.name),
5423
+ def.name
5424
+ );
4994
5425
  }
4995
5426
  function endpointHintForSection(def) {
4996
5427
  if (def.name === "materials") return "CampaignAssetView+Videos";
@@ -5030,6 +5461,8 @@ var init_fetch = __esm({
5030
5461
  init_auth();
5031
5462
  init_strip_legacy_google_fields();
5032
5463
  init_sections();
5464
+ init_normalize_rates();
5465
+ init_translate_fields();
5033
5466
  }
5034
5467
  });
5035
5468
 
@@ -6573,7 +7006,7 @@ function registerGoogleAnalysisCommands(program2) {
6573
7006
  "--concurrency <n>",
6574
7007
  "\u5E76\u53D1\u6570\uFF0C\u9ED8\u8BA4 5\uFF1B\u4E0A\u9650 16\uFF08\u4E0E http-raw maxSockets \u5BF9\u9F50\uFF09\uFF1B\u8D26\u6237\u5927\u6216\u7F51\u7EDC\u6162\u65F6\u8C03\u5C0F",
6575
7008
  (v) => parseInt(v, 10)
6576
- ).option("--limit <n>", "\u900F\u4F20\u7ED9 keywords / search-terms \u7EF4\u5EA6\u7684\u6761\u6570\u4E0A\u9650", (v) => parseInt(v, 10)).option("--no-order-by-cost", "\u900F\u4F20\uFF1Akeywords / search-terms \u4E0D\u6309\u6D88\u8017\u6392\u5E8F", false).option("--level <level>", "\u900F\u4F20\u7ED9 extensions \u7EF4\u5EA6\u7684 level \u8FC7\u6EE4\uFF1AAccount | Campaign | Ad Group").option(
7009
+ ).option("--limit <n>", "\u900F\u4F20\u7ED9 keywords / search-terms \u7EF4\u5EA6\u7684\u6761\u6570\u4E0A\u9650\uFF08\u9ED8\u8BA4 200\uFF09", (v) => parseInt(v, 10)).option("--no-order-by-cost", "\u900F\u4F20\uFF1Akeywords / search-terms \u4E0D\u6309\u6D88\u8017\u6392\u5E8F", false).option("--level <level>", "\u900F\u4F20\u7ED9 extensions \u7EF4\u5EA6\u7684 level \u8FC7\u6EE4\uFF1AAccount | Campaign | Ad Group").option(
6577
7010
  "--audience-type <type>",
6578
7011
  "\u900F\u4F20\u7ED9 audience \u7EF4\u5EA6\u7684 audienceTypeFilter\uFF1ASystemDefined | UserDefined"
6579
7012
  ).option(
@@ -6664,6 +7097,8 @@ var init_google_analysis2 = __esm({
6664
7097
  "use strict";
6665
7098
  init_sections();
6666
7099
  init_fetch();
7100
+ init_normalize_rates();
7101
+ init_translate_fields();
6667
7102
  init_register_cli();
6668
7103
  }
6669
7104
  });
@@ -2,10 +2,7 @@
2
2
  name: siluzan-tso
3
3
  description: >-
4
4
  Siluzan TSO 广告 skill(siluzan-tso-cli):Google/Bing/Yandex/TikTok/Kwai 账户开户、授权与分享、数据与消耗、Google 广告管理、发票与转账、优化报告与智能预警、TikTok/Meta 线索。
5
- Google 搜索方案/计划/待确认结构表时先读 references/google-ads.md。
6
- 关键字规划师/拓词/竞品网址拓词/词包清洗/否词/建户关键词编排:先读 references/keyword-planner-workflows.md。
7
- ①竞品URL+种子拓词→JSON筛排TopN ②多种子长尾 ③月搜阈值与词根/意图洗词 ④google-analysis keywords 叠分批 keyword 市场指标 ⑤search-terms 与拓词对照否词线索 ⑥CPC/竞争度/搜索量筛高意图 ⑦否词表+ad keyword-negative-create ⑧Campaign→AdGroup→匹配表+ad 落地 ⑨keyword --json-out 供脚本复用。无 Forecast、无 Planner 官方按月 12 个月趋势接口。
8
- 运营「OKKI 周报」固定话术(如「使用okki周报模板生成…」)→ `report-templates/okki-weekly-google-client.md`:拉数仅用现有 `stats`/`balance`/`google-analysis`(不新增拉数子命令);**多 Sheet Excel 由 Agent 落盘后写脚本生成**,CLI **不**提供内置「写 Excel」子命令。
5
+ 各能力执行细节按本文「功能以及对应文档」表路由到 references/;周期报告、OKKI 周报、Google 账户询盘分析等固定触发模板见 report-templates/ 与 REPORT-WORKFLOW.md。
9
6
  license: MIT
10
7
  metadata:
11
8
  requires: nodejs,siluzan-tso-cli
@@ -57,6 +54,8 @@ Windows 注意:部分 Agent 客户端通过 PowerShell / cmd 代执行命令
57
54
  | `references/write-audit-restore.md` | 本机写审计、`--commit`、补偿写 `audit restore-plan` / `restore-apply` |
58
55
  | `report-templates/report-template.html` | 默认 HTML 报告样式参考 |
59
56
  | `report-templates/okki-weekly-google-client.md` | **OKKI 周报**:固定话术 + 精简维度 CLI 拉数;**Excel 由 Agent 脚本写**(见 P6),无 CLI 内置写表命令 |
57
+ | `report-templates/google-inquiry-analysis.md` | **Google 询盘分析**:固定话术(`Goog账户询盘分析` 等)→ 严格 3 个月窗口 + 用户上传询盘资料 + 8 Sheet xlsx(见 P7);国家→大洲映射见 `references/geo-continents.json` |
58
+ | `references/geo-continents.json` | 国家中文名 → 7 大洲映射(亚洲/中东/欧洲/北美/南美/非洲/大洋洲),供询盘分析 Sheet 3 大洲透视 / Sheet 4 重点国切片(重点国可配置)使用 |
60
59
 
61
60
  ---
62
61
 
@@ -255,6 +254,33 @@ siluzan-tso accounts-digest -m Google -a id1,id2,... --start <S> --end <D> --jso
255
254
  - **强制顺序**:先 `fs.readFileSync(outlineFile,'utf8')` 读 outline 的最后一行(TS 式类型,几百字节)→ 再写聚合脚本 → 由脚本 `require()` 真实 JSON 做计算。**禁止**直接 `Read` JSON 看结构——批跑常见 `keywords-*.json` 数 MB × N 账户,几次 `Read` 就把对话窗口塞满。
256
255
  - 注意 outline 是 **`.outline.txt`** 不是 `.outline.json`,**禁止 `require()`**;其第 1 行注释明确写了 `// schema-only, NOT the data.`,**禁止**把它当业务数据贴给用户。
257
256
 
257
+ ### P7 · Google 账户询盘分析(运营固定模板)
258
+
259
+ > **触发**:用户话术含 **`Goog账户询盘分析`** / **`Google 账户询盘分析`** / **`分析XXX Google账号的询盘效果`** / **`我给你询盘信息分析Google账号XXX效果`**,或同时包含「询盘 + 账户 + Google」三要素。
260
+ >
261
+ > **不要**按 `google-period-report.md` 默认 8 维流程;改读 **`report-templates/google-inquiry-analysis.md`** 全文并按其结构交付。
262
+
263
+ 1. **时间窗口强约束**:**严格 3 个月** = 分析月份 + 向前 2 个完整自然月。**禁止**扩展到 7 个月(即使样表里有 7 个月);样表的 4~7 列旧数据由 Agent 在 Sheet 4/6 中跨 7 月写时**留空或不写**,仅写当前 3 月。
264
+ 2. **询盘资料入场**:
265
+ - **流程 A**(用户已附文件):宿主 Agent 解析任意载体(xlsx/csv/pdf/截图/文本表格)→ 抽取询盘行 → 落盘 `./snap-inquiry/inquiries.json`(字段见模板「询盘字段清单」)。
266
+ - **流程 B**(仅给账户 ID):先反问账户 + 分析月份,同时贴出字段清单 + 1 行示例让用户回贴/上传。**禁止**自行编造询盘数据。
267
+ 3. **CLI 拉数**(同一 `--json-out` 目录):
268
+ ```bash
269
+ siluzan-tso list-accounts -m Google -k <mediaCustomerId> --json-out ./snap-inquiry
270
+ siluzan-tso google-analysis -a <mediaCustomerId> \
271
+ --start <S> --end <D> \
272
+ --sections daily-metrics,campaigns,keywords,search-terms,campaign-geo,geographic \
273
+ --json-out ./snap-inquiry
274
+ # Sheet 6 月份×国家明细:3 次月度 geographic 循环
275
+ siluzan-tso google-analysis -a <mediaCustomerId> --start <M1S> --end <M1E> --sections geographic --json-out ./snap-inquiry/m1
276
+ siluzan-tso google-analysis -a <mediaCustomerId> --start <M2S> --end <M2E> --sections geographic --json-out ./snap-inquiry/m2
277
+ siluzan-tso google-analysis -a <mediaCustomerId> --start <M3S> --end <M3E> --sections geographic --json-out ./snap-inquiry/m3
278
+ ```
279
+ 4. **先 outline 后脚本**:与 P6 同纪律。读各 `*.outline.txt` 拿字段结构 → 写聚合脚本读 JSON → 计算 8 Sheet 数据。
280
+ 5. **国家 → 大洲映射**:脚本里读 `references/geo-continents.json`,未命中标 `未知大洲` 不阻塞,结尾打印未命中清单。Sheet 4「重点国 vs 非重点国」切片:按 `focusCountries`(中文国家名数组,运营未指定时默认取分析月询盘 Top1 国家,详见 `report-templates/google-inquiry-analysis.md`「重点国家配置」节)判桶,无需走大洲表;**禁止**在脚本中硬编码任何具体国家名。
281
+ 6. **必产 8 Sheet xlsx**:版式/Sheet 名/列定义/数值格式以 `report-templates/google-inquiry-analysis.md` 为准;**只能**由 Agent 在当前环境执行脚本(Node `xlsx`/`exceljs`,Python `openpyxl` 均可)生成,**禁止**假设 `siluzan-tso … excel` 这类 CLI 子命令存在。
282
+ 7. 遵守 SKILL 硬规范:金额 `*Display`、`budgetAmount` 是分(÷100)、禁止手填业务数、禁止编造 ID。
283
+
258
284
  ---
259
285
 
260
286
  ## Tips
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "siluzan-tso",
3
- "version": "1.1.19-beta.8",
4
- "publishedAt": 1778652640240
3
+ "version": "1.1.19",
4
+ "publishedAt": 1778754808006
5
5
  }