siluzan-tso-cli 1.1.59-beta.3 → 1.1.60-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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.59-beta.3),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
54
+ > **注意**:当前为测试版(1.1.60-beta.1),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
55
55
 
56
56
  | 助手 | 建议 `--ai` |
57
57
  | ----------------------- | ------------------------------------ |
package/dist/index.js CHANGED
@@ -116498,17 +116498,19 @@ function validateCampaignCreateConfigCore(cfg) {
116498
116498
  }
116499
116499
  validateLocationsFidelity(cfg, campaign, errors);
116500
116500
  validateTargetedPlatforms(campaign, errors, warnings);
116501
- const targetedLanguages = campaign["targetedLanguages"];
116502
- if (!Array.isArray(targetedLanguages) || targetedLanguages.length === 0) {
116503
- pushErr2(errors, "campaign.targetedLanguages \u4E0D\u80FD\u4E3A\u7A7A\uFF08\u82F1\u8BED id=1000\uFF0C\u4E2D\u6587 id=1017\uFF09");
116504
- } else {
116505
- for (let i = 0; i < targetedLanguages.length; i++) {
116506
- const lang = targetedLanguages[i];
116507
- if (!lang || lang["id"] === void 0 && lang["Id"] === void 0) {
116508
- pushErr2(
116509
- errors,
116510
- `campaign.targetedLanguages[${i}] \u7F3A\u5C11 id \u5B57\u6BB5\uFF08\u540E\u7AEF BuildCampaignCriterion \u8BFB domainCriterion.Id \u6784\u5EFA ResourceNames.LanguageConstant\uFF09`
116511
- );
116501
+ if (campaign["ChannelTypeV2"] !== "SEARCH") {
116502
+ const targetedLanguages = campaign["targetedLanguages"];
116503
+ if (!Array.isArray(targetedLanguages) || targetedLanguages.length === 0) {
116504
+ pushErr2(errors, "campaign.targetedLanguages \u4E0D\u80FD\u4E3A\u7A7A\uFF08\u82F1\u8BED id=1000\uFF0C\u4E2D\u6587 id=1017\uFF09");
116505
+ } else {
116506
+ for (let i = 0; i < targetedLanguages.length; i++) {
116507
+ const lang = targetedLanguages[i];
116508
+ if (!lang || lang["id"] === void 0 && lang["Id"] === void 0) {
116509
+ pushErr2(
116510
+ errors,
116511
+ `campaign.targetedLanguages[${i}] \u7F3A\u5C11 id \u5B57\u6BB5\uFF08\u540E\u7AEF BuildCampaignCriterion \u8BFB domainCriterion.Id \u6784\u5EFA ResourceNames.LanguageConstant\uFF09`
116512
+ );
116513
+ }
116512
116514
  }
116513
116515
  }
116514
116516
  }
@@ -117117,6 +117119,11 @@ async function runAdCampaignCreate(opts) {
117117
117119
  console.error("\n\u274C \u672A\u914D\u7F6E apiBaseUrl\uFF0C\u8BF7\u6267\u884C\uFF1Asiluzan-tso config set --api-base <URL>\n");
117118
117120
  process.exit(1);
117119
117121
  }
117122
+ const campaignForSubmit = cfg.campaign;
117123
+ if (campaignForSubmit["ChannelTypeV2"] === "SEARCH") {
117124
+ delete campaignForSubmit["targetedLanguages"];
117125
+ delete campaignForSubmit["TargetedLanguages"];
117126
+ }
117120
117127
  const campaignWithCents = convertBatchMoneyTreeFromYuan(cfg.campaign);
117121
117128
  const ext = campaignWithCents.ExtensionsForBatchJob;
117122
117129
  if (Array.isArray(ext) && ext.length > 0) {
@@ -135530,11 +135537,8 @@ function hasAudienceRows(rows) {
135530
135537
  return type === "UserList" || type === "CustomAudience" || type === "UserInterest" || type === "CustomIntent" || type === "CombinedAudience" || type === "CustomAffinity" || Number(row.impressions) > 0;
135531
135538
  });
135532
135539
  }
135533
- function hasSearchTextAdRows(rows) {
135534
- return rows.some((row) => {
135535
- const type = String(row.typeV2 ?? "");
135536
- return type === "RESPONSIVE_SEARCH_AD" || type === "EXPANDED_TEXT_AD";
135537
- });
135540
+ function hasResponsiveSearchAdRows(rows) {
135541
+ return rows.some((row) => String(row.typeV2 ?? "") === "RESPONSIVE_SEARCH_AD");
135538
135542
  }
135539
135543
  function campaignsUseBidding(rows) {
135540
135544
  return rows.some(
@@ -135564,22 +135568,14 @@ function reconcileGoldAccount(gold, evidence = {}) {
135564
135568
  const audiences = evidence.audiences ?? [];
135565
135569
  const ads = evidence.ads ?? [];
135566
135570
  const presentBecause = (sentence) => `${NOT_QUALIFIED}\u3002${sentence}\u662F\u5426\u8FBE\u6807\u4E0D\u7531\u8BE5\u5BF9\u8C61\u662F\u5426\u5B58\u5728\u51B3\u5B9A\u3002`;
135567
- const textAdsPresent = hasSearchTextAdRows(ads) || gold.responsiveSearchAdQualified === true || gold.textAdQualified === true || gold.expandedTextAdQualified === true;
135568
- if (textAdsPresent) notes.textAds = true;
135569
- noteUnqualified(
135570
- gold,
135571
- suggestions,
135572
- "expandedTextAdQualified",
135573
- "\u6587\u5B57\u5E7F\u544A",
135574
- textAdsPresent,
135575
- presentBecause("\u8D26\u6237\u91CC\u5DF2\u6709\u641C\u7D22\u6587\u5B57\u5E7F\u544A\uFF0C")
135576
- );
135571
+ const responsiveSearchAdsPresent = hasResponsiveSearchAdRows(ads) || gold.responsiveSearchAdQualified === true;
135572
+ if (responsiveSearchAdsPresent) notes.textAds = true;
135577
135573
  noteUnqualified(
135578
135574
  gold,
135579
135575
  suggestions,
135580
135576
  "responsiveSearchAdQualified",
135581
135577
  "\u81EA\u9002\u5E94\u641C\u7D22\u5E7F\u544A",
135582
- hasSearchTextAdRows(ads),
135578
+ hasResponsiveSearchAdRows(ads),
135583
135579
  presentBecause("\u8D26\u6237\u91CC\u5DF2\u6709\u81EA\u9002\u5E94\u641C\u7D22\u5E7F\u544A\uFF0C")
135584
135580
  );
135585
135581
  const responsiveDisplay = displayAds(ads);
@@ -137180,7 +137176,7 @@ var GOLD_CLAIM_RULES = [
137180
137176
  id: "text-ads-already-exist",
137181
137177
  textPattern: /请创建文字广告|没有文字广告|缺少文字广告|未创建文字广告/,
137182
137178
  isContradicted: (data) => goldAssetNoted(data, "textAds") || goldAccountFlag(data, "expandedTextAdQualified") === true || goldAccountFlag(data, "responsiveSearchAdQualified") === true,
137183
- hint: "\u8D26\u6237\u5DF2\u6709\u641C\u7D22\u6587\u5B57\u5E7F\u544A\u3002\u6587\u5B57\u5E7F\u544A\u9879\u672A\u8FBE\u6807\u4E0D\u7B49\u4E8E\u6CA1\u6709\u5E7F\u544A\uFF0C\u7981\u6B62\u5199\u300C\u8BF7\u521B\u5EFA\u6587\u5B57\u5E7F\u544A\u300D\u3002"
137179
+ hint: "\u641C\u7D22\u521B\u610F\u770B\u81EA\u9002\u5E94\u641C\u7D22\u5E7F\u544A\u3002\u62A5\u544A\u4E0D\u518D\u5355\u5217\u5DF2\u505C\u7528\u7684\u6587\u5B57\u5E7F\u544A\u3002\u7981\u6B62\u5199\u300C\u8BF7\u521B\u5EFA\u6587\u5B57\u5E7F\u544A\u300D\u3002"
137184
137180
  },
137185
137181
  {
137186
137182
  id: "callout-already-exists",
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "siluzan-tso",
3
- "version": "1.1.59-beta.3",
4
- "publishedAt": 1793098194200
3
+ "version": "1.1.60-beta.1",
4
+ "publishedAt": 1793157724295
5
5
  }
@@ -17,7 +17,6 @@
17
17
  "BudgetId": 0,
18
18
  "BudgetBudgetDeliveryMethodV2": "STANDARD",
19
19
  "TargetSpend_BidCeilingAmount": 2,
20
- "ManualCpc_EnhancedCpcEnabled": false,
21
20
  "TargetGoogleSearch": true,
22
21
  "TargetSearchNetwork": false,
23
22
  "TargetContentNetwork": false,
@@ -37,11 +36,6 @@
37
36
  ],
38
37
  "excludedLocations": [],
39
38
  "excludedIpAddresses": [],
40
- "targetedLanguages": [
41
- {
42
- "id": 1000
43
- }
44
- ],
45
39
  "targetedPlatforms": [
46
40
  {
47
41
  "id": 30001,
@@ -35,7 +35,6 @@
35
35
  "BudgetId": 0,
36
36
  "BudgetBudgetDeliveryMethodV2": "STANDARD",
37
37
  "TargetSpend_BidCeilingAmount": 2,
38
- "ManualCpc_EnhancedCpcEnabled": false,
39
38
  "TargetGoogleSearch": true,
40
39
  "TargetSearchNetwork": false,
41
40
  "TargetContentNetwork": false,
@@ -49,7 +48,6 @@
49
48
  "targetedLocations": [{ "id": "2840", "bidModifier": 0, "bidModifierSpecified": false }],
50
49
  "excludedLocations": [],
51
50
  "excludedIpAddresses": [],
52
- "targetedLanguages": [{ "id": 1000 }],
53
51
  "targetedPlatforms": [
54
52
  { "id": 30001, "bidModifier": 0 },
55
53
  { "id": 30002, "bidModifier": 0 },
@@ -36,7 +36,6 @@
36
36
  "BudgetId": 0,
37
37
  "BudgetBudgetDeliveryMethodV2": "STANDARD",
38
38
  "TargetSpend_BidCeilingAmount": 1.5,
39
- "ManualCpc_EnhancedCpcEnabled": false,
40
39
  "TargetGoogleSearch": true,
41
40
  "TargetSearchNetwork": false,
42
41
  "TargetContentNetwork": false,
@@ -50,7 +49,6 @@
50
49
  "targetedLocations": [{ "id": "2840", "bidModifier": 0, "bidModifierSpecified": false }],
51
50
  "excludedLocations": [],
52
51
  "excludedIpAddresses": [],
53
- "targetedLanguages": [{ "id": 1000 }],
54
52
  "targetedPlatforms": [
55
53
  { "id": 30000, "bidModifier": 0 },
56
54
  { "id": 30001, "bidModifier": 0 },
@@ -162,7 +162,6 @@ siluzan-tso ad batch diff --batch-id <taskId> --config-file ./campaign.json --js
162
162
  | `TargetSpend_BidCeilingAmount` | number | TARGET_SPEND 时 ✅ | 每次点击费用上限(元) |
163
163
  | `TargetCpa_BidingAmount` | number | TARGET_CPA 时 ✅ | 目标 CPA(元) |
164
164
  | `TargetRoas` | number | TARGET_ROAS 时 ✅ | 目标 ROAS(如 2.5 表示 250%) |
165
- | `ManualCpc_EnhancedCpcEnabled` | boolean | | 是否增强 CPC |
166
165
 
167
166
  ### 网络(后端硬约束)
168
167
 
@@ -179,7 +178,6 @@ siluzan-tso ad batch diff --batch-id <taskId> --config-file ./campaign.json --js
179
178
  | ----------------------- | ---------------------------------------- | :--: | ---------------------------------------------------------------------------------------- |
180
179
  | `targetedLocations` | `{ id: string, bidModifier?: number }[]` | ✅ | 至少 1 个;**id 必须来自** `siluzan-tso ad geo search -a <acct> -q <地区名>`(禁止编造) |
181
180
  | `excludedLocations` | 同上 | | 排除地区;**不得与 `targetedLocations` 有相同 id**(validate 报错;「刚果」等歧义地名 resolve 后须核对) |
182
- | `targetedLanguages` | `{ id: number }[]` | ✅ | 英语 1000,中文 1017 |
183
181
  | `targetedPlatforms` | `{ id: number, bidModifier?: number }[]` | | **30000 桌面 / 30001 移动 / 30002 平板**;`bidModifier` 为**百分比整数**(见下) |
184
182
  | `excludedIpAddresses` | string[] | | 排除 IP |
185
183
  | `PositiveGeoTargetType` | number | | |
@@ -6,9 +6,7 @@
6
6
  "url": "https://www.example.com",
7
7
  "budget": 100,
8
8
  "biddingStrategyTypeV2": "MANUAL_CPC",
9
- "manualCpcEnhancedCpcEnabled": false,
10
9
  "maxCpcDefault": 5,
11
- "languageId": 1000,
12
10
  "startTime": "2026-07-15",
13
11
  "endTime": "2037-12-30",
14
12
  "locations": ["United States", "Canada"],
@@ -225,7 +225,6 @@ const campaign = {
225
225
  BudgetShared: false,
226
226
  BudgetId: 0,
227
227
  BudgetBudgetDeliveryMethodV2: "STANDARD",
228
- ManualCpc_EnhancedCpcEnabled: Boolean(plan.manualCpcEnhancedCpcEnabled ?? false),
229
228
  TargetGoogleSearch: true,
230
229
  TargetSearchNetwork: false,
231
230
  TargetContentNetwork: false,
@@ -235,7 +234,6 @@ const campaign = {
235
234
  targetedLocations: geo.targetedLocations,
236
235
  excludedLocations: [],
237
236
  excludedIpAddresses: [],
238
- targetedLanguages: [{ id: Number(plan.languageId ?? 1000) }],
239
237
  NegativeKeywordsForBatchJob: negBlocks,
240
238
  ExtensionsForBatchJob: buildExtensions(plan.extensions, url),
241
239
  AdGroupsForBatchJob: adGroups,
@@ -42,7 +42,7 @@
42
42
  | 日预算 | `campaign.Budget`(**元**,CLI 内部 ×100 转分) |
43
43
  | 出价策略 / 上限 / tCPA | `campaign.BiddingStrategyTypeV2`、`campaign.TargetSpend_BidCeilingAmount`、`campaign.TargetCpa_BidingAmount`、`campaign.TargetRoas` |
44
44
  | 投放地域 | `campaign.targetedLocations: [{ id: "<geoId>" }]`(**必须**先 `ad geo search` 取 id,禁止编造)、外层 `locations`(与 targetedLocations 同序同量) |
45
- | 语言 | `campaign.targetedLanguages: [{ id: 1000 }]`(英语 1000 / 中文 1017) |
45
+ | 语言 | 搜索广告不再提交 `campaign.targetedLanguages`。`DSALanguageCode` 仍是动态搜索广告语言,与广告系列语言不是同一个字段。 |
46
46
  | 起止日期 | `campaign.StartTime`、`campaign.EndTime`(YYYY-MM-DD) |
47
47
  | 落地页 | 外层 `url`;广告组级 `KeywordsForBatchJob[].FinalURL`、创意级 `AdsForBatchJob[].Finalurl` |
48
48
  | 关键词 | `campaign.AdGroupsForBatchJob[].KeywordsForBatchJob`(`MatchTypeV2` + `KeywordText`) |
@@ -335,7 +335,6 @@ siluzan-tso google-ads-diagnosis render \
335
335
  | ------------------ | ----------- | -------- |
336
336
  | 转化追踪设置 | 达标/未达标 | |
337
337
  | G A与广告账户联结 | | |
338
- | 文字广告 | | |
339
338
  | 自适应搜索广告 | | |
340
339
  | 自适应展示广告 | | |
341
340
  | 附加结构化信息摘要 | | |
@@ -345,6 +344,8 @@ siluzan-tso google-ads-diagnosis render \
345
344
  | 受众群体设置 | | |
346
345
  | 出价策略 | | |
347
346
 
347
+ > 黄金账户表**不含**「文字广告」(`expandedTextAdQualified`,加大型文字广告已停用)。搜索创意只看「自适应搜索广告」(`responsiveSearchAdQualified`)。
348
+ >
348
349
  > 黄金账户表**不含**「否定词添加」(`adsNegativeQualified`):collect 未拉取否词数据,render 会剥离该字段。
349
350
  >
350
351
  > 达标 / 未达标只看接口布尔值。明细里有 `RESPONSIVE_SEARCH_AD`、宣传信息、GA4 转化或受众,**不**把对应行改成达标。
@@ -353,7 +354,7 @@ siluzan-tso google-ads-diagnosis render \
353
354
  >
354
355
  > 自适应展示广告只挂在暂停系列上:保持未达标,建议写「已有自适应展示广告,所在展示系列已暂停,本期无消耗」,禁止写「请使用」。
355
356
 
356
- **得分**:`goldAccountScore`;**未达标项数**:若有 `goldAccountUnqualifiedCount` 可注明。
357
+ **得分**:页面按 `goldAccountScore` 展示。接口原值仍含已停用的 `expandedTextAdQualified`(3 分);该项为 `true` 时,页面扣掉这 3 分。**未达标项数**按当前表内项目重算。
357
358
 
358
359
  ---
359
360
 
@@ -2096,7 +2096,7 @@
2096
2096
  const GOLD_ACCOUNT_ITEMS = [
2097
2097
  { key: "conversionTrackingQualified", name: "转化追踪设置" },
2098
2098
  { key: "gaConfigured", name: "G A与广告账户联结" },
2099
- { key: "expandedTextAdQualified", name: "文字广告" },
2099
+ // expandedTextAdQualified 已停用,搜索创意只看自适应搜索广告
2100
2100
  { key: "responsiveSearchAdQualified", name: "自适应搜索广告" },
2101
2101
  {
2102
2102
  key: "multiAssetResponsiveDisplayAdQualified",
@@ -5001,10 +5001,12 @@
5001
5001
  );
5002
5002
  // 按当前展示项重算(已排除否词项),勿用可能含 adsNegativeQualified 的接口计数
5003
5003
  const unqualifiedCount = totalItems - qualifiedCount;
5004
- const scoreValue =
5005
- goldAccount.goldAccountScore !== undefined && goldAccount.goldAccountScore !== null
5006
- ? String(goldAccount.goldAccountScore)
5007
- : "--";
5004
+ // 接口得分仍含已停用的 expandedTextAdQualified(3 分)。展示时扣掉,只保留自适应搜索广告。
5005
+ const rawScore = Number(goldAccount.goldAccountScore);
5006
+ const legacyTextAdPoints = goldAccount.expandedTextAdQualified === true ? 3 : 0;
5007
+ const scoreValue = Number.isFinite(rawScore)
5008
+ ? String(Math.max(0, rawScore - legacyTextAdPoints))
5009
+ : "--";
5008
5010
 
5009
5011
  const goldItemSuggestions = goldAccount.goldItemSuggestions || {};
5010
5012
  const goldAccountRows = GOLD_ACCOUNT_ITEMS.map((item) => {
@@ -335,7 +335,6 @@ siluzan-tso google-ads-diagnosis render \
335
335
  | ------------------ | ----------- | -------- |
336
336
  | 转化追踪设置 | 达标/未达标 | |
337
337
  | G A与广告账户联结 | | |
338
- | 文字广告 | | |
339
338
  | 自适应搜索广告 | | |
340
339
  | 自适应展示广告 | | |
341
340
  | 附加结构化信息摘要 | | |
@@ -345,6 +344,8 @@ siluzan-tso google-ads-diagnosis render \
345
344
  | 受众群体设置 | | |
346
345
  | 出价策略 | | |
347
346
 
347
+ > 黄金账户表**不含**「文字广告」(`expandedTextAdQualified`,加大型文字广告已停用)。搜索创意只看「自适应搜索广告」(`responsiveSearchAdQualified`)。
348
+ >
348
349
  > 黄金账户表**不含**「否定词添加」(`adsNegativeQualified`):collect 未拉取否词数据,render 会剥离该字段。
349
350
  >
350
351
  > 达标 / 未达标只看接口布尔值。明细里有 `RESPONSIVE_SEARCH_AD`、宣传信息、GA4 转化或受众,**不**把对应行改成达标。
@@ -353,7 +354,7 @@ siluzan-tso google-ads-diagnosis render \
353
354
  >
354
355
  > 自适应展示广告只挂在暂停系列上:保持未达标,建议写「已有自适应展示广告,所在展示系列已暂停,本期无消耗」,禁止写「请使用」。
355
356
 
356
- **得分**:`goldAccountScore`;**未达标项数**:若有 `goldAccountUnqualifiedCount` 可注明。
357
+ **得分**:页面按 `goldAccountScore` 展示。接口原值仍含已停用的 `expandedTextAdQualified`(3 分);该项为 `true` 时,页面扣掉这 3 分。**未达标项数**按当前表内项目重算。
357
358
 
358
359
  ---
359
360
 
@@ -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.59-beta.3'
12
+ $PKG_VERSION = '1.1.60-beta.1'
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.59-beta.3"
12
+ readonly PKG_VERSION="1.1.60-beta.1"
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.59-beta.3",
3
+ "version": "1.1.60-beta.1",
4
4
  "description": "Siluzan 广告账户管理 CLI — 查询账户、余额、消耗数据,管理绑定关系与充值。",
5
5
  "keywords": [
6
6
  "ad-account",