siluzan-tso-cli 1.1.61 → 1.1.62-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -43,7 +43,7 @@ HTML 报告模板外部资源:**ECharts** 统一使用 `https://staticpn.siluz
43
43
  在**用户的目标项目根目录**执行(根据用户使用的助手选择 `--ai`):
44
44
 
45
45
  ```bash
46
- npm install -g siluzan-tso-cli
46
+ npm install -g siluzan-tso-cli@beta
47
47
  siluzan-tso init --ai cursor # 写入 Cursor(默认)
48
48
  siluzan-tso init --ai cursor,claude # 同时写入多个平台
49
49
  siluzan-tso init --ai all # 写入所有支持的平台
@@ -51,6 +51,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
51
51
  siluzan-tso init --force # 强制覆盖已存在文件
52
52
  ```
53
53
 
54
+ > **注意**:当前为测试版(1.1.62-beta.2),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
54
55
 
55
56
  | 助手 | 建议 `--ai` |
56
57
  | ----------------------- | ------------------------------------ |
package/dist/index.js CHANGED
@@ -4051,7 +4051,7 @@ var DEFAULT_API_BASE;
4051
4051
  var init_defaults = __esm({
4052
4052
  "src/config/defaults.ts"() {
4053
4053
  "use strict";
4054
- DEFAULT_API_BASE = "https://tso-api.siluzan.com";
4054
+ DEFAULT_API_BASE = "https://tso-api-ci.siluzan.com";
4055
4055
  }
4056
4056
  });
4057
4057
 
@@ -6529,9 +6529,13 @@ function buildOutlineHints(section) {
6529
6529
  if (section === "campaigns") {
6530
6530
  hints.push(
6531
6531
  ...GOOGLE_ANALYSIS_CAMPAIGNS_OUTLINE_BUDGET_HINTS,
6532
- ...GOOGLE_ANALYSIS_CAMPAIGNS_COMPETITIVE_METRICS_HINTS
6532
+ ...GOOGLE_ANALYSIS_CAMPAIGNS_COMPETITIVE_METRICS_HINTS,
6533
+ ...GOOGLE_ANALYSIS_CONVERSIONS_VALUE_HINTS
6533
6534
  );
6534
6535
  }
6536
+ if (section === "ads" || section === "keywords" || section === "search-terms") {
6537
+ hints.push(...GOOGLE_ANALYSIS_CONVERSIONS_VALUE_HINTS);
6538
+ }
6535
6539
  if (section === "ads") {
6536
6540
  hints.push(...GOOGLE_ANALYSIS_ADS_OUTLINE_BUDGET_HINTS);
6537
6541
  }
@@ -6651,7 +6655,7 @@ async function writeGoogleAnalysisSnapshot(params) {
6651
6655
  agentHint: OUTLINE_AGENT_HINT
6652
6656
  };
6653
6657
  }
6654
- var LEGACY_MANIFEST_FILE, CLI_PACKAGE, SCHEMA_VERSION2, DEFAULT_FIELD_GUIDE, GOOGLE_ANALYSIS_CAMPAIGNS_OUTLINE_BUDGET_HINTS, GOOGLE_ANALYSIS_ADS_OUTLINE_BUDGET_HINTS, GOOGLE_ANALYSIS_CAMPAIGNS_COMPETITIVE_METRICS_HINTS, RATE_BEARING_SECTIONS, GOOGLE_ANALYSIS_RATE_NORMALIZED_OUTLINE_HINTS, GOOGLE_ANALYSIS_ENVELOPE_OUTLINE_HINTS, GOOGLE_ANALYSIS_OVERVIEW_ACTIVE_DAYS_HINTS, GOOGLE_ANALYSIS_ZH_FIELD_HINTS_BY_SECTION;
6658
+ var LEGACY_MANIFEST_FILE, CLI_PACKAGE, SCHEMA_VERSION2, DEFAULT_FIELD_GUIDE, GOOGLE_ANALYSIS_CAMPAIGNS_OUTLINE_BUDGET_HINTS, GOOGLE_ANALYSIS_ADS_OUTLINE_BUDGET_HINTS, GOOGLE_ANALYSIS_CONVERSIONS_VALUE_HINTS, GOOGLE_ANALYSIS_CAMPAIGNS_COMPETITIVE_METRICS_HINTS, RATE_BEARING_SECTIONS, GOOGLE_ANALYSIS_RATE_NORMALIZED_OUTLINE_HINTS, GOOGLE_ANALYSIS_ENVELOPE_OUTLINE_HINTS, GOOGLE_ANALYSIS_OVERVIEW_ACTIVE_DAYS_HINTS, GOOGLE_ANALYSIS_ZH_FIELD_HINTS_BY_SECTION;
6655
6659
  var init_google_analysis = __esm({
6656
6660
  "src/utils/snapshot/google-analysis.ts"() {
6657
6661
  "use strict";
@@ -6674,6 +6678,9 @@ var init_google_analysis = __esm({
6674
6678
  GOOGLE_ANALYSIS_ADS_OUTLINE_BUDGET_HINTS = [
6675
6679
  "// \u91D1\u989D\uFF1A`ads[].spend` / `averageCpc` / `costPerConversion` \u843D\u76D8\u524D\u5DF2\u7EDF\u4E00\u4E3A**\u5143**\uFF08`costPerConversion` \u7531\u7F51\u5173\u5FAE\u5143 \xF71e6\uFF09\uFF1B**\u7981\u6B62**\u518D\u5BF9 `costPerConversion` \u505A \xF71_000_000\u3002"
6676
6680
  ];
6681
+ GOOGLE_ANALYSIS_CONVERSIONS_VALUE_HINTS = [
6682
+ "// \u8F6C\u5316\u4EF7\u503C\uFF1A`conversionsValue` \u662F\u8D26\u6237\u5E01\u79CD\u91D1\u989D\uFF08Google\u300C\u8F6C\u5316\u4EF7\u503C\u300D\uFF09\uFF0C\u4E0D\u662F `conversions`\uFF08\u6B21\u6570\uFF09\u3002\u62A5\u544A\u5199\u8F6C\u5316\u4EF7\u503C\u6216 ROAS \u65F6\u7528\u5B83\uFF1AROAS = conversionsValue / spend\uFF08spend \u4E3A 0 \u65F6\u8BE5\u683C\u5199\u300C\u2014\u300D\uFF09\u3002\u7981\u6B62\u7528\u6D88\u8017\u3001\u70B9\u51FB\u3001\u8F6C\u5316\u6B21\u6570\u81EA\u884C\u4F30\u7B97\u3002\u884C\u4E0A\u6CA1\u6709\u8BE5\u5B57\u6BB5\u65F6\u5199\u300C\u672A\u8FD4\u56DE\u300D\uFF0C\u7981\u6B62\u628A\u7CFB\u5217\u4EF7\u503C\u644A\u5230\u8BCD\u6216\u641C\u7D22\u5B57\u8BCD\u4E0A\u3002"
6683
+ ];
6677
6684
  GOOGLE_ANALYSIS_CAMPAIGNS_COMPETITIVE_METRICS_HINTS = [
6678
6685
  "// \u7ADE\u4E89\u6307\u6807\uFF1A`campaigns[].competitiveMetrics` \u4E3A **0~1 \u5C0F\u6570**\uFF08\u5982 `0.0999` = 9.99%\uFF09\uFF0C\u542B Top/AbsoluteTop/Content/ClickShare \u7B49\uFF1B\u65E0\u6570\u636E\u65F6\u4E3A `null`\u3002",
6679
6686
  "// \u884C\u9876 `searchImpressionShare` / `searchBudgetLostImpressionShare` / `searchRankLostImpressionShare` \u843D\u76D8\u524D\u5DF2\u5F52\u4E00\u4E3A **0~1 \u5C0F\u6570**\uFF08\u4E0E `competitiveMetrics` \u540C\u540D\u9879\u4E00\u81F4\uFF09\uFF1B\u5C55\u793A\u4E3A % \u65F6 \xD7100\u3002",
@@ -114974,6 +114981,12 @@ function sameWriteValue(expected, actual) {
114974
114981
  }
114975
114982
  return false;
114976
114983
  }
114984
+ function biddingStrategiesMatch(expected, actual) {
114985
+ if (sameWriteValue(expected, actual)) return true;
114986
+ const exp = String(expected).trim().toUpperCase();
114987
+ const act = String(actual ?? "").trim().toUpperCase();
114988
+ return exp === "TARGET_CPA" && act === "MAXIMIZE_CONVERSIONS" || exp === "TARGET_ROAS" && act === "MAXIMIZE_CONVERSION_VALUE";
114989
+ }
114977
114990
  function fieldCheck(field, expected, actual, present) {
114978
114991
  if (!present) return { field, expected, actual: void 0, state: "unread" };
114979
114992
  return {
@@ -115027,10 +115040,22 @@ function evaluateCampaignReadback(after, expected, readFailed) {
115027
115040
  };
115028
115041
  push("name", expected.name, ["name", "Name"]);
115029
115042
  push("statusV2", expected.statusV2, ["statusV2", "StatusV2"]);
115030
- push("biddingStrategyTypeV2", expected.biddingStrategyTypeV2, [
115031
- "biddingStrategyTypeV2",
115032
- "BiddingStrategyTypeV2"
115033
- ]);
115043
+ if (expected.biddingStrategyTypeV2 !== void 0) {
115044
+ const found = readKey(after, ["biddingStrategyTypeV2", "BiddingStrategyTypeV2"]);
115045
+ checks.push(
115046
+ found.present ? {
115047
+ field: "biddingStrategyTypeV2",
115048
+ expected: expected.biddingStrategyTypeV2,
115049
+ actual: found.value,
115050
+ state: biddingStrategiesMatch(expected.biddingStrategyTypeV2, found.value) ? "match" : "mismatch"
115051
+ } : {
115052
+ field: "biddingStrategyTypeV2",
115053
+ expected: expected.biddingStrategyTypeV2,
115054
+ actual: void 0,
115055
+ state: "unread"
115056
+ }
115057
+ );
115058
+ }
115034
115059
  push("targetSpend_BidCeilingAmount", expected.targetSpendBidCeilingCents, [
115035
115060
  "targetSpend_BidCeilingAmount",
115036
115061
  "TargetSpend_BidCeilingAmount"
@@ -115334,7 +115359,8 @@ ${label2}\uFF08\u8D26\u6237\uFF1A${opts.account}\uFF0C\u7B2C 1 \u9875\uFF0C\u672
115334
115359
  { key: "impressions", header: "\u5C55\u793A" },
115335
115360
  { key: "clicks", header: "\u70B9\u51FB" },
115336
115361
  { key: "ctr", header: "\u70B9\u51FB\u7387" },
115337
- { key: "spend", header: "\u8D39\u7528" }
115362
+ { key: "spend", header: "\u8D39\u7528" },
115363
+ { key: "conversionsValue", header: "\u8F6C\u5316\u4EF7\u503C" }
115338
115364
  ];
115339
115365
  const rows = items3.map((item) => {
115340
115366
  const kwText = String(item["text"] ?? item["keywordText"] ?? "\u2014");
@@ -115344,6 +115370,8 @@ ${label2}\uFF08\u8D26\u6237\uFF1A${opts.account}\uFF0C\u7B2C 1 \u9875\uFF0C\u672
115344
115370
  const matchType = String(item["matchTypeV2"] ?? "");
115345
115371
  const ctr = item["ctr"] != null ? (Number(item["ctr"]) * 100).toFixed(2) + "%" : "\u2014";
115346
115372
  const spend = item["spend"] != null ? Number(item["spend"]).toFixed(2) : "\u2014";
115373
+ const valueRaw = item["conversionsValue"];
115374
+ const conversionsValue = typeof valueRaw === "number" && Number.isFinite(valueRaw) ? valueRaw.toFixed(2) : "\u2014";
115347
115375
  return {
115348
115376
  keyword: kwText.slice(0, kwW),
115349
115377
  campaign: campaign.slice(0, campW),
@@ -115353,7 +115381,8 @@ ${label2}\uFF08\u8D26\u6237\uFF1A${opts.account}\uFF0C\u7B2C 1 \u9875\uFF0C\u672
115353
115381
  impressions: String(item["impressions"] ?? 0),
115354
115382
  clicks: String(item["clicks"] ?? 0),
115355
115383
  ctr,
115356
- spend
115384
+ spend,
115385
+ conversionsValue
115357
115386
  };
115358
115387
  });
115359
115388
  printCliTable(rows, cols);
@@ -119265,12 +119294,15 @@ async function runAdSearchTerms(opts) {
119265
119294
  { key: "impressions", header: "\u5C55\u793A" },
119266
119295
  { key: "clicks", header: "\u70B9\u51FB" },
119267
119296
  { key: "ctr", header: "\u70B9\u51FB\u7387" },
119268
- { key: "cost", header: "\u8D39\u7528" }
119297
+ { key: "cost", header: "\u8D39\u7528" },
119298
+ { key: "conversionsValue", header: "\u8F6C\u5316\u4EF7\u503C" }
119269
119299
  ];
119270
119300
  const rows = items3.map((item) => {
119271
119301
  const term = String(item["searchTermText"] ?? "");
119272
119302
  const ctr = item["ctr"] != null ? (Number(item["ctr"]) * 100).toFixed(2) + "%" : "\u2014";
119273
119303
  const cost = item["cost"] != null ? Number(item["cost"]).toFixed(2) : "\u2014";
119304
+ const valueRaw = item["conversionsValue"];
119305
+ const conversionsValue = typeof valueRaw === "number" && Number.isFinite(valueRaw) ? valueRaw.toFixed(2) : "\u2014";
119274
119306
  return {
119275
119307
  term: term.slice(0, termW),
119276
119308
  campaign: String(item["campaignName"] ?? "").slice(0, campW),
@@ -119279,7 +119311,8 @@ async function runAdSearchTerms(opts) {
119279
119311
  impressions: String(item["impressions"] ?? 0),
119280
119312
  clicks: String(item["clicks"] ?? 0),
119281
119313
  ctr,
119282
- cost
119314
+ cost,
119315
+ conversionsValue
119283
119316
  };
119284
119317
  });
119285
119318
  printCliTable(rows, cols);
@@ -124693,6 +124726,16 @@ async function runAdPmaxGet(opts) {
124693
124726
  `);
124694
124727
  });
124695
124728
  }
124729
+ function readDisplayNumber(value, label2) {
124730
+ const n = typeof value === "number" ? value : Number(String(value).trim());
124731
+ if (!Number.isFinite(n)) {
124732
+ console.error(`
124733
+ \u274C ${label2}\u987B\u4E3A\u6709\u9650\u6570\u5B57\uFF0C\u6536\u5230 ${String(value)}
124734
+ `);
124735
+ process.exit(1);
124736
+ }
124737
+ return n;
124738
+ }
124696
124739
  async function runAdPmaxEdit(opts) {
124697
124740
  const accountId = requireAccountId(opts.account);
124698
124741
  const campaignId = opts.campaignId.trim();
@@ -124702,11 +124745,13 @@ async function runAdPmaxEdit(opts) {
124702
124745
  } else {
124703
124746
  body = {};
124704
124747
  if (opts.status !== void 0) body["statusV2"] = parseStatusV2(opts.status);
124705
- if (opts.budget !== void 0) body["budget"] = toCentAmount(opts.budget);
124748
+ if (opts.budget !== void 0) body["budget"] = toCentAmount(readDisplayNumber(opts.budget, "\u9884\u7B97"));
124706
124749
  if (opts.budgetId !== void 0) body["budgetId"] = opts.budgetId.trim();
124707
124750
  if (opts.bidding !== void 0) body["biddingStrategyTypeV2"] = opts.bidding.toUpperCase();
124708
- if (opts.targetCpa !== void 0) body["targetCpa_BidingAmount"] = toCentAmount(opts.targetCpa);
124709
- if (opts.targetRoas !== void 0) body["targetRoas"] = opts.targetRoas;
124751
+ if (opts.targetCpa !== void 0) {
124752
+ body["targetCpa_BidingAmount"] = toCentAmount(readDisplayNumber(opts.targetCpa, "\u76EE\u6807 CPA"));
124753
+ }
124754
+ if (opts.targetRoas !== void 0) body["targetRoas"] = readDisplayNumber(opts.targetRoas, "\u76EE\u6807 ROAS");
124710
124755
  if (opts.urlExpansionOptOut !== void 0) {
124711
124756
  body["urlExpansionOptOut"] = opts.urlExpansionOptOut;
124712
124757
  }
@@ -126327,7 +126372,7 @@ function register21(program2) {
126327
126372
  ).requiredOption("-a, --account <id>", "Google \u5A92\u4F53\u5BA2\u6237 ID").requiredOption("--campaign-id <id>", "\u6D3B\u52A8 ID").option("--patch-file <path>", "PATCH JSON\uFF08budget/targetCpa \u586B\u5143\uFF09").option(
126328
126373
  "--status <status>",
126329
126374
  "2|3|4 \u6216 Enabled|Paused|Removed\uFF08Removed \u4E0D\u53EF\u6062\u590D\uFF0C\u987B\u7528\u6237\u540C\u610F\u540E\u52A0 --i-confirm\uFF09"
126330
- ).option("--i-confirm", "\u72B6\u6001\u6539 Removed \u65F6\u5FC5\u586B\uFF1A\u5DF2\u83B7\u7528\u6237\u660E\u786E\u540C\u610F", false).option("--budget <yuan>", "\u65E5\u9884\u7B97\uFF08\u5143\uFF09\uFF1B\u987B\u914D\u5408 --budget-id").option("--budget-id <id>", "budgetId\uFF08\u6765\u81EA pmax-get\uFF09").option("--bidding <strategy>", "\u51FA\u4EF7\u7B56\u7565\uFF0C\u5982 MAXIMIZE_CONVERSIONS").option("--target-cpa <yuan>", "\u76EE\u6807 CPA\uFF08\u5143\uFF09").option("--target-roas <n>", "\u76EE\u6807 ROAS").option("--url-expansion-opt-out", "\u5173\u95ED\u6700\u7EC8\u5230\u8FBE\u7F51\u5740\u6269\u5C55").option("-t, --token <token>", "Auth Token")
126375
+ ).option("--i-confirm", "\u72B6\u6001\u6539 Removed \u65F6\u5FC5\u586B\uFF1A\u5DF2\u83B7\u7528\u6237\u660E\u786E\u540C\u610F", false).option("--budget <yuan>", "\u65E5\u9884\u7B97\uFF08\u5143\uFF09\uFF1B\u987B\u914D\u5408 --budget-id", parseFloat).option("--budget-id <id>", "budgetId\uFF08\u6765\u81EA pmax-get\uFF09").option("--bidding <strategy>", "\u51FA\u4EF7\u7B56\u7565\uFF0C\u5982 MAXIMIZE_CONVERSIONS").option("--target-cpa <yuan>", "\u76EE\u6807 CPA\uFF08\u5143\uFF09", parseFloat).option("--target-roas <n>", "\u76EE\u6807 ROAS", parseFloat).option("--url-expansion-opt-out", "\u5173\u95ED\u6700\u7EC8\u5230\u8FBE\u7F51\u5740\u6269\u5C55").option("-t, --token <token>", "Auth Token")
126331
126376
  ).action(
126332
126377
  async (opts) => {
126333
126378
  await runAdPmaxEdit(opts);
@@ -126595,7 +126640,7 @@ function register21(program2) {
126595
126640
  parseFloat
126596
126641
  ).option(
126597
126642
  "--target-cpa <n>",
126598
- "\u7EC4\u7EA7\u76EE\u6807 CPA\uFF0C\u4E3B\u5E01\u79CD\u91D1\u989D\uFF08CLI \u5185\u90E8 \xD7100 \u5199\u5165\u300C\u5206\u300D\u5B57\u6BB5\uFF09",
126643
+ "\u7EC4\u7EA7\u76EE\u6807 CPA\uFF0C\u4E3B\u5E01\u79CD\u91D1\u989D\uFF08CLI \u5185\u90E8 \xD7100 \u5199\u5165\u300C\u5206\u300D\u5B57\u6BB5\uFF1B0 \u6E05\u7A7A\uFF0C\u56DE\u5230\u7CFB\u5217\u51FA\u4EF7\uFF09",
126599
126644
  parseFloat
126600
126645
  ).option("--start <date>", "\u5217\u8868\u67E5\u8BE2\u8D77\u59CB\u65E5\u671F YYYY-MM-DD").option("--end <date>", "\u5217\u8868\u67E5\u8BE2\u7ED3\u675F\u65E5\u671F YYYY-MM-DD").option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
126601
126646
  async (opts) => {
@@ -139099,7 +139144,7 @@ function matchConversionAction(actions, name2) {
139099
139144
  return label2.includes(needle);
139100
139145
  });
139101
139146
  if (!hit) return null;
139102
- const n = num2(hit.conversions ?? hit.conversionsValue ?? hit.allConversions);
139147
+ const n = num2(hit.conversions ?? hit.allConversions);
139103
139148
  return n;
139104
139149
  }
139105
139150
  function buildQuarterlyFacts(input) {
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "siluzan-tso",
3
- "version": "1.1.61",
4
- "publishedAt": 1793271700039
3
+ "version": "1.1.62-beta.2",
4
+ "publishedAt": 1793277242701
5
5
  }
@@ -170,7 +170,7 @@ siluzan-tso account-history --start 2026-03-01 --end 2026-03-31 --json-out ./sna
170
170
  | 状态 | 含义 | 下一步操作 |
171
171
  | ---------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
172
172
  | `Pending` | 审核中 | 等待,可反复运行此命令轮询;审核周期因媒体而异 |
173
- | `Approved` | 审核通过 | 运行 `list-accounts -m <媒体>` 确认账户已出现;引导用户充值激活(`config show` 取 `webUrl`,按 `finance.md` 打开对应媒体充值页;例如 Google 为 `https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google`;Yandex 当前没有对应充值界面) |
173
+ | `Approved` | 审核通过 | 运行 `list-accounts -m <媒体>` 确认账户已出现;引导用户充值激活(`config show` 取 `webUrl`,按 `finance.md` 打开对应媒体充值页;例如 Google 为 `https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google`;Yandex 当前没有对应充值界面) |
174
174
  | `Rejected` | 被拒 | 查看 `--json-out` 落盘中的 `reason` 字段了解拒绝原因;修改资料后重新提交;若原因不明,引导用户联系丝路赞客服 |
175
175
 
176
176
  ---
@@ -490,7 +490,7 @@ siluzan-tso account email-deauth -c <mediaCustomerId> --invitation-id <id> --res
490
490
 
491
491
  | 功能 | 媒体 | 网页路径 |
492
492
  | --------------------------------------- | ------ | ------------------------------------------------- |
493
- | **账户激活**(邀请他人激活 / 充值激活) | Google | `https://www.siluzan.com/v3/foreign_trade/tso/manageAccounts` |
493
+ | **账户激活**(邀请他人激活 / 充值激活) | Google | `https://www-ci.siluzan.com/v3/foreign_trade/tso/manageAccounts` |
494
494
 
495
495
  **Agent 建议话术**:
496
496
 
@@ -499,5 +499,5 @@ siluzan-tso account email-deauth -c <mediaCustomerId> --invitation-id <id> --res
499
499
  siluzan-tso config show # 查看 webUrl 字段
500
500
 
501
501
  # 账户激活(Google)→ 引导至账户管理页
502
- # https://www.siluzan.com/v3/foreign_trade/tso/manageAccounts
502
+ # https://www-ci.siluzan.com/v3/foreign_trade/tso/manageAccounts
503
503
  ```
@@ -126,7 +126,7 @@ siluzan-tso config show
126
126
 
127
127
  ### 充值页链接(按媒体 × 类型)
128
128
 
129
- 链接模式:`https://www.siluzan.com/v3/foreign_trade/tso/recharge/<page>?mediaType=<mediaType>`;丝路赞钱包:`https://www.siluzan.com/v3/foreign_trade/tso/recharge/siluzanWallet`(无媒体参数)。
129
+ 链接模式:`https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/<page>?mediaType=<mediaType>`;丝路赞钱包:`https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/siluzanWallet`(无媒体参数)。
130
130
 
131
131
  | 充值类型 | `<page>` | 支持媒体(`mediaType` 参数) |
132
132
  | ------------------------- | --------------------- | ------------------------------------------- |
@@ -1,6 +1,6 @@
1
1
  # 各媒体开户
2
2
 
3
- > 网页链接:`https://www.siluzan.com/v3/foreign_trade/tso/accountOpeningHistory?tso=%2Fv3umijs%2Ftso%2FaccountOpeningHistory`
3
+ > 网页链接:`https://www-ci.siluzan.com/v3/foreign_trade/tso/accountOpeningHistory?tso=%2Fv3umijs%2Ftso%2FaccountOpeningHistory`
4
4
  > 多命令串联见 `references/core/workflows.md` § 流程一。
5
5
 
6
6
  ## Contents
@@ -65,7 +65,7 @@ siluzan-tso open-account google-wizard
65
65
 
66
66
  ```bash
67
67
  siluzan-tso account-history -m Google
68
- # 审核通过后:config show → https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
68
+ # 审核通过后:config show → https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
69
69
  ```
70
70
 
71
71
  ---
@@ -202,12 +202,15 @@ const data = d.record ?? d.items; // record 非空=汇总维度;否则=列表
202
202
  | 消耗 | `spend` |
203
203
  | 展示 | `impressions` |
204
204
  | 点击 | `clicks` |
205
- | 转化 | `conversions` |
205
+ | 转化次数 | `conversions` |
206
+ | 转化价值 | `conversionsValue` |
206
207
  | 点击率 | `ctr` |
207
208
  | 转化率 | `conversionRate` |
208
209
  | 平均点击成本 | `averageCpc` |
209
210
  | 转化成本 | `costPerConversion` |
210
211
 
212
+ `conversionsValue` 是账户币种的 Google「转化价值」,和 `conversions`(次数)不是一回事。带 `startDate` / `endDate` 时,`keywords`、`search-terms`、`campaigns`、`ads`,以及 `ad keywords` / `ad search-terms` / `ad campaigns` / `ad groups` / `ad list` 的行上会有这个字段。报告要写转化价值或 ROAS 时用它:`ROAS = conversionsValue / spend`(`spend` 为 0 时该格写「—」)。禁止用消耗、点击、转化次数自己算。行上没有该字段(设备、每日趋势,或当次快照未返回)写「未返回」,禁止把系列价值摊到关键词或搜索字词上。账户级三格仍只汇总 `campaigns` 的 `items[]`。
213
+
211
214
  ### CampaignSectionData 关键字段
212
215
 
213
216
  > `campaigns` 维度的系列行在 `items[]`(`schemaVersion 3` 起统一信封;本节下文的 `campaigns[]` 即指 `items[]`)。
@@ -1,6 +1,6 @@
1
1
  # rag:知识库检索(TSO 广告投放辅助)
2
2
 
3
- 知识库管理页面在 https://www.siluzan.com/knowledge-base/
3
+ 知识库管理页面在 https://www-ci.siluzan.com/knowledge-base/
4
4
 
5
5
  为 **广告投放、账户分析、拓词、诊断报告** 等 TSO 业务提供**企业已入库**的产品、行业、客户背景事实依据。
6
6
 
@@ -190,9 +190,9 @@ siluzan-tso report push receive-emails -m Google [--json-out ./snap]
190
190
 
191
191
  | 媒体 | 报告类型 | URL 模板 |
192
192
  | ------ | ---------------- | ----------------------------------------------------------- |
193
- | Google | 日报(Daily) | `https://www.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
194
- | Google | 小时报(Hourly) | `https://www.siluzan.com/media-report/hour/{entityId}?culture=zh-CN` |
195
- | TikTok | 日报 | `https://www.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
193
+ | Google | 日报(Daily) | `https://www-ci.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
194
+ | Google | 小时报(Hourly) | `https://www-ci.siluzan.com/media-report/hour/{entityId}?culture=zh-CN` |
195
+ | TikTok | 日报 | `https://www-ci.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
196
196
 
197
197
  `entityId` 来自 `siluzan-tso report list --json-out ./snap` 中每条记录的 `entityId` 字段。
198
198
 
@@ -205,8 +205,8 @@ siluzan-tso report list -m Google --json-out ./snap
205
205
 
206
206
  # 第二步:查看 webUrl
207
207
  siluzan-tso config show
208
- # webUrl: https://www.siluzan.com
208
+ # webUrl: https://www-ci.siluzan.com
209
209
 
210
210
  # 第三步:拼接链接(Google 日报)
211
- # https://www.siluzan.com/media-report/publish/rpt_abc123?culture=zh-CN
211
+ # https://www-ci.siluzan.com/media-report/publish/rpt_abc123?culture=zh-CN
212
212
  ```
@@ -81,7 +81,7 @@
81
81
  - **步骤**:
82
82
  1. **账户核验**:`list-accounts -m Google -k <mediaCustomerId> --json-out <dir>`;无记录则停止并告知用户。
83
83
  2. 确认时间范围;区间 > 3 个月时分段(季度/月)。
84
- 3. **拉数**:用户已指定 Sheet/维度 → 只拉对应 `--sections`(见 `google-period-report-excel.md` 映射表);未指定 → 按 `google-period-report.md` 默认 9 个拉数维(含 `audience`、`negative-keywords`),并可并行追问可选追加。终稿要「转化价值 / 单转化价值 / ROAS」的上期时,再按 excel 规格拉等长上期 `--sections campaigns` 后汇总,禁止把这三格留成「—」。
84
+ 3. **拉数**:用户已指定 Sheet/维度 → 只拉对应 `--sections`(见 `google-period-report-excel.md` 映射表);未指定 → 按 `google-period-report.md` 默认 9 个拉数维(含 `audience`、`negative-keywords`),并可并行追问可选追加。终稿要「转化价值 / 单转化价值 / ROAS」的上期时,再按 excel 规格拉等长上期 `--sections campaigns` 后汇总,禁止把这三格留成「—」。关键词 / 搜索字词表用各自行的 `conversionsValue`(ROAS = 该值 / `spend`),不要用系列汇总值摊下去。
85
85
  4. **门禁**:对每个 section Read `<section>-<accountId>_*.outline.txt` 后再写脚本。
86
86
  5. 脚本读盘写 `google-period-report.json`(`meta` + `narrative`,`meta.lang` 跟本轮语言);用户要 **Excel** → Agent 脚本写 xlsx(**禁止**宿主第三方 xlsx Skill;**无** CLI excel 子命令;表头跟 `meta.lang`)。
87
87
  6. 默认 HTML:`google-analysis render --data ./google-period-report.json --snapshot-dir ./snap-google --out ./google-period-report.html --lang <zh|en>`。须含账户概览、投放趋势、Top 关键词/系列/地区/受众分布、当前否词名单、优化建议。
@@ -10,7 +10,7 @@
10
10
  ## 安装 CLI
11
11
 
12
12
  ```bash
13
- npm install -g siluzan-tso-cli
13
+ npm install -g siluzan-tso-cli@beta
14
14
  ```
15
15
 
16
16
  ---
@@ -64,7 +64,7 @@ siluzan-tso config set --api-key <Key> # 或 config 直接写入
64
64
  siluzan-tso config set --token <Token> # 备用:设置 JWT Token
65
65
  ```
66
66
 
67
- API Key 获取入口:`https://www.siluzan.com/v3/foreign_trade/settings/apiKeyManagement`
67
+ API Key 获取入口:`https://www-ci.siluzan.com/v3/foreign_trade/settings/apiKeyManagement`
68
68
 
69
69
  ```bash
70
70
  # 第 1 步:让用户报出手机号后,立刻发码(命令立即返回,不会等待输入)
@@ -127,9 +127,9 @@ siluzan-tso config show
127
127
 
128
128
  ```
129
129
  构建环境 : production
130
- apiBaseUrl : https://tso-api.siluzan.com
131
- googleApiUrl : https://googleapi.mysiluzan.com
132
- webUrl : https://www.siluzan.com
130
+ apiBaseUrl : https://tso-api-ci.siluzan.com
131
+ googleApiUrl : https://googleapi-ci.mysiluzan.com
132
+ webUrl : https://www-ci.siluzan.com
133
133
  apiKey : abcd****1234
134
134
  ```
135
135
 
@@ -50,7 +50,7 @@ siluzan-tso ad campaigns -a <accountId> [--start <YYYY-MM-DD>] [--end <YYYY-MM-D
50
50
 
51
51
  命令名:列表是 **`ad campaigns`**(兼容别名 `campaign-list`),**没有** `google-ads` 命名空间。`--json-out` **必须带路径**(落盘,勿管道 stdout)。
52
52
 
53
- 带 `--start` / `--end` 时,同行的 **`spend` / `impressions` / `clicks` / `conversions` 为该闭区间合计**(**不是**日消耗)。
53
+ 带 `--start` / `--end` 时,同行的 **`spend` / `impressions` / `clicks` / `conversions` / `conversionsValue` 为该闭区间合计**(**不是**日消耗)。`conversionsValue` 是账户币种的转化价值,不是转化次数。报告写转化价值或 ROAS 时用它(ROAS = `conversionsValue` / `spend`)。`ad groups`、`ad list`、`ad keywords`、`ad search-terms` 在同一日期窗口下也返回该字段。
54
54
  与日预算比较「是否超预算」时,**必须** `start=end=统计日`;多日窗口须先 ÷ 天数或改用 `balance-scan.dailySpend` / `overview.averageDailyCost` 再谈「日均」。
55
55
 
56
56
  > **缓存**:网关侧此列表按 `账户 + 日期区间` 缓存 60 秒(Redis)。若刚 `campaign-create` / `campaign-edit` / `campaign-status` / `campaign-delete` 后立刻查询想看到最新结果,加 `--fresh` 跳过缓存(网关 `newest=true`);日常巡检/报表不需要,留空更省配额。
@@ -120,7 +120,7 @@ siluzan-tso ad adgroup-edit \
120
120
  [--start/--end <YYYY-MM-DD>]
121
121
  ```
122
122
 
123
- `--max-cpc` / `--target-cpa` 与 `ad groups --json-out ./snap` 中 `maxCPCAmountYuan` / `targetCpaAmountYuan` 对齐(**元**,CLI 出口已统一)。列表里的 `0` 多半是未设置。`--target-cpa 0` 会照写,Google 常回 `Too low`,这个 PATCH 也不能把组级目标 CPA 清回未设置。
123
+ `--max-cpc` / `--target-cpa` 与 `ad groups --json-out ./snap` 中 `maxCPCAmountYuan` / `targetCpaAmountYuan` 对齐(**元**,CLI 出口已统一)。列表里的 `0` 多半是未设置。`--target-cpa 0` 清空组级目标 CPA,回到系列出价。`--max-cpc` 仍须大于 0,广告组不能没有最高 CPC。
124
124
 
125
125
  ### 删除
126
126
 
@@ -185,6 +185,8 @@ siluzan-tso ad ad-delete -a <accountId> --id <adId>
185
185
  siluzan-tso ad keywords -a <accountId> [--negative] [--start/--end <date>] [--json-out ./snap]
186
186
  ```
187
187
 
188
+ 带日期时行上有 `conversionsValue`(账户币种的转化价值,不是 `conversions` 次数)。`--json-out` 里直接读这个字段;终端表「转化价值」列在字段缺失时为「—」。否定关键词名单没有这个指标。
189
+
188
190
  ### 添加关键词
189
191
 
190
192
  ```bash
@@ -263,6 +265,8 @@ siluzan-tso keyword geo-list [--country-code <US,CN,...>] [--name-contains <text
263
265
  siluzan-tso ad search-terms -a <accountId> [--start/--end YYYY-MM-DD] [--json-out ./snap]
264
266
  ```
265
267
 
268
+ 行上 `conversionsValue` 是该窗口的转化价值(账户币种)。ROAS = `conversionsValue` / `spend`(或同行费用字段)。不要用点击或转化次数换算。
269
+
266
270
  ---
267
271
 
268
272
  ## ad geo — 地理位置定向管理
@@ -246,6 +246,8 @@ siluzan-tso ad campaign-edit \
246
246
  | `TARGET_ROAS` | **必填** `--target-roas`(2.5 = 250%) |
247
247
  | `MAXIMIZE_CONVERSIONS` | 可选 `--target-cpa`(目标 CPA,元) |
248
248
 
249
+ `TARGET_CPA` 写到 Google 的「尽可能提高转化次数」并带上目标 CPA。回读 `biddingStrategyTypeV2` 可能是 `MAXIMIZE_CONVERSIONS`,以 `targetCpa_BidingAmount` 是否等于本次金额为准。`TARGET_ROAS` 在目标回报率大于 0 时回读为 `TARGET_ROAS`;旧网关可能仍回 `MAXIMIZE_CONVERSION_VALUE`,同样以 `targetRoas` 为准。
250
+
249
251
  示例:
250
252
 
251
253
  ```bash
@@ -361,7 +363,7 @@ siluzan-tso ad keyword-edit \
361
363
  [--max-cpc <n>] [--final-url <url>] [--status Enabled|Paused]
362
364
  ```
363
365
 
364
- 传 `--match-type` 时 CLI 自动规范 `keywordText` 括号/引号格式。至少传一项。`--max-cpc` 为主币种元(CLI ×100 写入 `maxCpc`「分」字段,与 `adgroup-edit --max-cpc` 同口径)。`ad keywords --json-out ./snap` 出价见 `maxCPCYuan`。列表里的 `0` 多半是未设置;`--max-cpc 0` 会照写,Google 常回 `Too low`,不能用来清空关键词出价。`--status` 写入 `userStatus`(关键词级开关,非系列的 `status`)。
366
+ 传 `--match-type` 时 CLI 自动规范 `keywordText` 括号/引号格式。至少传一项。`--max-cpc` 为主币种元(CLI ×100 写入 `maxCpc`「分」字段,与 `adgroup-edit --max-cpc` 同口径)。`ad keywords --json-out ./snap` 出价见 `maxCPCYuan`。列表里的 `0` 多半是未设置。`--max-cpc 0` 清空关键词出价,回到广告组出价;不要用它表示「写成 0 元」。`--status` 写入 `userStatus`(关键词级开关,非系列的 `status`)。
365
367
 
366
368
  ---
367
369
 
@@ -228,8 +228,8 @@ siluzan-tso ad campaigns -a <CID> --json-out ./snap
228
228
 
229
229
  ### 10.2 预算分配合理性
230
230
 
231
- 1. 从 `campaigns` 获取每个系列的 spend、conversions、costPerConversion
232
- 2. 计算每个系列的 ROAS 或 CPA
231
+ 1. 从 `campaigns` 获取每个系列的 spend、conversions、costPerConversion、conversionsValue
232
+ 2. ROAS 用该行 `conversionsValue / spend`(`conversionsValuePerCost` 已是这一比值,不要再平均);CPA 用 `costPerConversion`
233
233
  3. 检查以下不合理分配:
234
234
 
235
235
  | 问题 | 检测方式 | 处理 |
@@ -165,7 +165,7 @@ Account
165
165
  **设定初始 tROAS:**
166
166
 
167
167
  1. 先用 Max Conversion Value(不设目标)运行 2-4 周
168
- 2. 计算平均 ROAS
168
+ 2. 平均 ROAS 直接用系列行的 `conversionsValue / spend`(或行上的 `conversionsValuePerCost`),不要用转化次数估算价值
169
169
  3. 设 tROAS = 平均 ROAS 或低 10-20%(给算法空间)
170
170
  4. 每 2 周提高不超过 15-20%
171
171
 
@@ -6,7 +6,7 @@
6
6
  siluzan-tso config show # 取 webUrl
7
7
  ```
8
8
 
9
- 首页地址:`https://www.siluzan.com/v3/foreign_trade/tso/home`
9
+ 首页地址:`https://www-ci.siluzan.com/v3/foreign_trade/tso/home`
10
10
 
11
11
  ---
12
12
 
@@ -25,7 +25,7 @@ siluzan-tso config show # 取 webUrl
25
25
 
26
26
  ## 推荐话术
27
27
 
28
- 1. **「和首页一样的总览」** → 打开 `https://www.siluzan.com/v3/foreign_trade/tso/home`。
28
+ 1. **「和首页一样的总览」** → 打开 `https://www-ci.siluzan.com/v3/foreign_trade/tso/home`。
29
29
  2. **「某个 Google 账户昨天花了多少」** → `list-accounts -m Google` + `stats -m Google -a <id>`。
30
30
  3. **「有待充值账户」** → 说明聚合数据在首页;CLI 可 `list-accounts` + `balance` 逐户排查,或引导充值页。
31
31
 
@@ -118,7 +118,7 @@ function valueKpis(items) {
118
118
 
119
119
  禁止对行上的 `conversionsValuePerCost` 再平均(那是行级「转化价值/费用」,不是账户 ROAS)。
120
120
 
121
- 关键词、搜索词、设备、每日趋势的 outline 若没有 `conversionsValue`,该列写「该维度未返回」,禁止把系列转化价值摊进去。上期 `campaigns` 拉数失败时,这三格写明原因,不要留空。
121
+ 关键词、搜索字词表的转化价值读各自行的 `conversionsValue`(账户币种),ROAS = 该值 / 该行 `spend`。禁止把系列汇总摊到词上,也禁止用转化次数估算。设备、每日趋势的 outline 若没有 `conversionsValue`,该列写「该维度未返回」。关键词或搜索字词当次 outline 也没有该字段时同样写「未返回」。上期 `campaigns` 拉数失败时,账户级三格写明原因,不要留空。
122
122
 
123
123
  英文终稿表头:转化价值 → Conversion value,单转化价值 → Value / conversion,ROAS 保持 ROAS。
124
124
 
@@ -118,7 +118,7 @@ function valueKpis(items) {
118
118
 
119
119
  禁止对行上的 `conversionsValuePerCost` 再平均(那是行级「转化价值/费用」,不是账户 ROAS)。
120
120
 
121
- 关键词、搜索词、设备、每日趋势的 outline 若没有 `conversionsValue`,该列写「该维度未返回」,禁止把系列转化价值摊进去。上期 `campaigns` 拉数失败时,这三格写明原因,不要留空。
121
+ 关键词、搜索字词表的转化价值读各自行的 `conversionsValue`(账户币种),ROAS = 该值 / 该行 `spend`。禁止把系列汇总摊到词上,也禁止用转化次数估算。设备、每日趋势的 outline 若没有 `conversionsValue`,该列写「该维度未返回」。关键词或搜索字词当次 outline 也没有该字段时同样写「未返回」。上期 `campaigns` 拉数失败时,账户级三格写明原因,不要留空。
122
122
 
123
123
  英文终稿表头:转化价值 → Conversion value,单转化价值 → Value / conversion,ROAS 保持 ROAS。
124
124
 
@@ -9,11 +9,11 @@ $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.61'
12
+ $PKG_VERSION = '1.1.62-beta.2'
13
13
  $CLI_BIN = 'siluzan-tso'
14
14
  $SKILL_LABEL = 'Siluzan TSO'
15
- $INSTALL_CMD = 'npm install -g siluzan-tso-cli'
16
- $WEB_BASE = 'https://www.siluzan.com'
15
+ $INSTALL_CMD = 'npm install -g siluzan-tso-cli@beta'
16
+ $WEB_BASE = 'https://www-ci.siluzan.com'
17
17
 
18
18
  # -- Constants ----------------------------------------------------------------
19
19
  $NODE_MAJOR_MIN = 18
@@ -9,11 +9,11 @@ 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.61"
12
+ readonly PKG_VERSION="1.1.62-beta.2"
13
13
  readonly CLI_BIN="siluzan-tso"
14
14
  readonly SKILL_LABEL="Siluzan TSO"
15
- readonly INSTALL_CMD="npm install -g siluzan-tso-cli"
16
- readonly WEB_BASE="https://www.siluzan.com"
15
+ readonly INSTALL_CMD="npm install -g siluzan-tso-cli@beta"
16
+ readonly WEB_BASE="https://www-ci.siluzan.com"
17
17
 
18
18
  # -- Constants ----------------------------------------------------------------
19
19
  readonly NODE_MAJOR_MIN=18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "siluzan-tso-cli",
3
- "version": "1.1.61",
3
+ "version": "1.1.62-beta.2",
4
4
  "description": "Siluzan 广告账户管理 CLI — 查询账户、余额、消耗数据,管理绑定关系与充值。",
5
5
  "keywords": [
6
6
  "ad-account",