siluzan-tso-cli 1.1.33-beta.3 → 1.1.34-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
@@ -51,7 +51,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
51
51
  siluzan-tso init --force # 强制覆盖已存在文件
52
52
  ```
53
53
 
54
- > **注意**:当前为测试版(1.1.33-beta.3),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
54
+ > **注意**:当前为测试版(1.1.34-beta.2),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
55
55
 
56
56
  | 助手 | 建议 `--ai` |
57
57
  | ----------------------- | ------------------------------------ |
package/dist/index.js CHANGED
@@ -126091,7 +126091,7 @@ function validateNewFeatureRecommendations(data) {
126091
126091
  const warnings = [];
126092
126092
  for (let i = 0; i < items.length; i++) {
126093
126093
  const row = asRecord5(items[i]);
126094
- const name2 = String(row?.strategyName ?? row?.strategy ?? i);
126094
+ const name2 = String(row?.strategyName ?? row?.feature ?? row?.strategy ?? i);
126095
126095
  if (!hasNarrativeContent(row?.optimizerRecommendation)) {
126096
126096
  warnings.push(`newFeatures.items[${name2}].optimizerRecommendation \u4E3A\u7A7A\uFF08\u987B\u7531 Agent \u586B\u5199\uFF09`);
126097
126097
  }
@@ -126161,6 +126161,13 @@ var GOOGLE_ADS_DIAGNOSIS_COMPARISON_MODULES = [
126161
126161
  "geographic",
126162
126162
  "keywords"
126163
126163
  ];
126164
+ var GOOGLE_ADS_DIAGNOSIS_BIDDING_STRATEGY_MODULE = "biddingStrategy";
126165
+ var GOOGLE_ADS_DIAGNOSIS_NEW_FEATURES_MODULE = "newFeatures";
126166
+ var GOOGLE_ADS_DIAGNOSIS_RESTORE_ITEM_MODULES = [
126167
+ ...GOOGLE_ADS_DIAGNOSIS_COMPARISON_MODULES,
126168
+ GOOGLE_ADS_DIAGNOSIS_BIDDING_STRATEGY_MODULE,
126169
+ GOOGLE_ADS_DIAGNOSIS_NEW_FEATURES_MODULE
126170
+ ];
126164
126171
  function asRecord6(value) {
126165
126172
  if (value && typeof value === "object" && !Array.isArray(value)) {
126166
126173
  return value;
@@ -126183,21 +126190,48 @@ function isComparisonTableRowValid(row) {
126183
126190
  if (!isValidRateChange(rec.cvrRateChange)) return false;
126184
126191
  return true;
126185
126192
  }
126186
- function moduleItemsNeedRestore(items) {
126193
+ function isNewFeatureRowValid(row) {
126194
+ const rec = asRecord6(row);
126195
+ if (!rec) return false;
126196
+ return Boolean(String(rec.strategyName ?? rec.feature ?? rec.strategy ?? "").trim());
126197
+ }
126198
+ function isBiddingStrategyRowValid(row) {
126199
+ const rec = asRecord6(row);
126200
+ if (!rec) return false;
126201
+ if (!String(rec.campaignName ?? "").trim()) return false;
126202
+ if (!Number.isFinite(Number(rec.duration)) || Number(rec.duration) <= 0) return false;
126203
+ if (!String(rec.biddingStrategyType ?? "").trim()) return false;
126204
+ return true;
126205
+ }
126206
+ var MODULE_ITEM_VALIDATORS = {
126207
+ campaigns: isComparisonTableRowValid,
126208
+ geographic: isComparisonTableRowValid,
126209
+ keywords: isComparisonTableRowValid,
126210
+ biddingStrategy: isBiddingStrategyRowValid,
126211
+ newFeatures: isNewFeatureRowValid
126212
+ };
126213
+ var MODULE_ITEM_ERROR_HINT = {
126214
+ campaigns: "\u7F3A\u5C11 title/currentCost/currentClicks \u6216\u73AF\u6BD4\u5B57\u6BB5\u88AB\u5199\u6210\u5B57\u7B26\u4E32\uFF08\u987B\u4FDD\u7559 collect \u4E8B\u5B9E\u884C\uFF0C\u4EC5\u7531 Agent \u586B\u5199 analysis/suggestions\uFF09",
126215
+ geographic: "\u7F3A\u5C11 title/currentCost/currentClicks \u6216\u73AF\u6BD4\u5B57\u6BB5\u88AB\u5199\u6210\u5B57\u7B26\u4E32\uFF08\u987B\u4FDD\u7559 collect \u4E8B\u5B9E\u884C\uFF0C\u4EC5\u7531 Agent \u586B\u5199 analysis/suggestions\uFF09",
126216
+ keywords: "\u7F3A\u5C11 title/currentCost/currentClicks \u6216\u73AF\u6BD4\u5B57\u6BB5\u88AB\u5199\u6210\u5B57\u7B26\u4E32\uFF08\u987B\u4FDD\u7559 collect \u4E8B\u5B9E\u884C\uFF0C\u4EC5\u7531 Agent \u586B\u5199 analysis/suggestions\uFF09",
126217
+ biddingStrategy: "\u7F3A\u5C11 campaignName/duration(\u5929\u6570)/biddingStrategyType\uFF08Agent \u52FF\u628A duration \u5199\u6210\u6587\u6848\u5B57\u7B26\u4E32\uFF0C\u52FF\u7528 currentStrategy \u66FF\u4EE3 biddingStrategyType\uFF09",
126218
+ newFeatures: "\u7F3A\u5C11 strategyName/strategy\uFF08collect \u4E8B\u5B9E\u884C\uFF1BAgent \u53EA\u586B optimizerRecommendation\uFF0C\u52FF\u6539\u7528 feature \u5B57\u6BB5\u66FF\u4EE3 strategyName\uFF09"
126219
+ };
126220
+ function moduleItemsNeedRestore(items, validator) {
126187
126221
  if (!Array.isArray(items) || items.length === 0) return false;
126188
- return items.some((row) => !isComparisonTableRowValid(row));
126222
+ return items.some((row) => !validator(row));
126189
126223
  }
126190
- function getComparisonTableErrors(data) {
126224
+ function getFactItemsErrors(data) {
126191
126225
  const errors = [];
126192
- for (const mod of GOOGLE_ADS_DIAGNOSIS_COMPARISON_MODULES) {
126226
+ for (const mod of GOOGLE_ADS_DIAGNOSIS_RESTORE_ITEM_MODULES) {
126227
+ const validator = MODULE_ITEM_VALIDATORS[mod];
126228
+ const hint = MODULE_ITEM_ERROR_HINT[mod];
126193
126229
  const block = asRecord6(data[mod]);
126194
126230
  const items = block?.items;
126195
126231
  if (!Array.isArray(items) || items.length === 0) continue;
126196
126232
  for (let i = 0; i < items.length; i++) {
126197
- if (!isComparisonTableRowValid(items[i])) {
126198
- errors.push(
126199
- `${mod}.items[${i}] \u7F3A\u5C11 title/currentCost/currentClicks \u6216\u73AF\u6BD4\u5B57\u6BB5\u88AB\u5199\u6210\u5B57\u7B26\u4E32\uFF08\u987B\u4FDD\u7559 collect \u4E8B\u5B9E\u884C\uFF0C\u4EC5\u7531 Agent \u586B\u5199 analysis/suggestions\uFF09`
126200
- );
126233
+ if (!validator(items[i])) {
126234
+ errors.push(`${mod}.items[${i}] ${hint}`);
126201
126235
  }
126202
126236
  }
126203
126237
  }
@@ -126206,12 +126240,13 @@ function getComparisonTableErrors(data) {
126206
126240
  function mergeComparisonItemsFromCollect(finalData, collectReportData) {
126207
126241
  const data = { ...finalData };
126208
126242
  const restoredModules = [];
126209
- for (const mod of GOOGLE_ADS_DIAGNOSIS_COMPARISON_MODULES) {
126243
+ for (const mod of GOOGLE_ADS_DIAGNOSIS_RESTORE_ITEM_MODULES) {
126244
+ const validator = MODULE_ITEM_VALIDATORS[mod];
126210
126245
  const finalBlock = asRecord6(data[mod]);
126211
126246
  const collectBlock = asRecord6(collectReportData[mod]);
126212
126247
  const finalItems = finalBlock?.items;
126213
126248
  const collectItems = collectBlock?.items;
126214
- if (!moduleItemsNeedRestore(finalItems)) continue;
126249
+ if (!moduleItemsNeedRestore(finalItems, validator)) continue;
126215
126250
  if (!Array.isArray(collectItems) || collectItems.length === 0) continue;
126216
126251
  data[mod] = {
126217
126252
  ...finalBlock ?? {},
@@ -126265,16 +126300,16 @@ async function runGoogleAdsDiagnosisRender(opts) {
126265
126300
  if (restoredModules.length > 0) {
126266
126301
  console.log(
126267
126302
  `
126268
- \u2139\uFE0F \u5DF2\u4ECE collect \u6062\u590D \xA73.5 \u5BF9\u6BD4\u8868 items\uFF08${restoredModules.join("\u3001")}\uFF09\uFF1BAgent \u53EA\u5E94\u586B\u5199 analysis/suggestions\uFF0C\u52FF\u6539\u5199 items \u884C\u6570\u636E\u3002
126303
+ \u2139\uFE0F \u5DF2\u4ECE collect \u6062\u590D\u4E8B\u5B9E items\uFF08${restoredModules.join("\u3001")}\uFF09\uFF1BAgent \u53EA\u5E94\u586B\u5199 analysis/suggestions\uFF0C\u52FF\u6539\u5199 items \u884C\uFF08\u542B biddingStrategy.duration \u5929\u6570\uFF09\u3002
126269
126304
  \u6765\u6E90\uFF1A${collectPath}
126270
126305
  `
126271
126306
  );
126272
126307
  }
126273
126308
  }
126274
126309
  }
126275
- const comparisonErrors = getComparisonTableErrors(data);
126310
+ const comparisonErrors = getFactItemsErrors(data);
126276
126311
  if (comparisonErrors.length > 0) {
126277
- console.error("\n\u274C \u5BF9\u6BD4\u8868 items \u4E0D\u5B8C\u6574\uFF0CHTML \u4E2D\u7CFB\u5217/\u5730\u57DF/\u5173\u952E\u8BCD\u8868\u4F1A\u663E\u793A\u4E3A\u7A7A\uFF1A\n");
126312
+ console.error("\n\u274C \u4E8B\u5B9E items \u4E0D\u5B8C\u6574\uFF0CHTML \u4E2D\u90E8\u5206\u8868\u683C\u4F1A\u663E\u793A\u4E3A\u7A7A\uFF1A\n");
126278
126313
  for (const err of comparisonErrors) {
126279
126314
  console.error(` \xB7 ${err}`);
126280
126315
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "siluzan-tso",
3
- "version": "1.1.33-beta.3",
4
- "publishedAt": 1782887114389
3
+ "version": "1.1.34-beta.2",
4
+ "publishedAt": 1782898503071
5
5
  }
@@ -351,6 +351,8 @@ siluzan-tso google-ads-diagnosis render \
351
351
  **区块 ID**:`section-bidding-strategy`
352
352
  **数据**:`biddingStrategy.items`(仅「有问题」的系列进入表格;无数据时页面为「出价策略配置良好」)
353
353
 
354
+ **items 行字段(collect 事实,Agent 禁止改写)**:`campaignName`、`duration`(**天数 number**,如 `34`,勿写 `"2026-05-28 至今"` 文案)、`biddingStrategyType`(如 `MANUAL_CPC`,勿用 `currentStrategy` 替代)、`recommendedStrategy`、`recommendationReason`、`isCorrect`
355
+
354
356
  | 广告系列 | 投放时长 | 当前出价策略 | 推荐出价策略 | 状态 |
355
357
  | -------- | -------- | ------------ | ------------ | ---- |
356
358
  | | | | | |
@@ -381,7 +383,12 @@ siluzan-tso google-ads-diagnosis render \
381
383
  ## 11 新产品应用
382
384
 
383
385
  **区块 ID**:`section-new-features`
384
- **数据**:`newFeatures.items`
386
+ **数据**:`newFeatures.items`(collect 来自 campaign-types;过滤 `strategy === "AiMax"` 的行)
387
+
388
+ **items 行字段**:
389
+ - collect 事实(勿改):`strategy`(如 `PerformanceMax`)、`strategyName`(如 `效果最大化`)、`accountStatus`(**boolean**,`true`=已启用)
390
+ - Agent 只填:`optimizerRecommendation`
391
+ - **禁止**用 `feature` 替代 `strategyName`(render 模板会兜底读 `feature`,但 collect 合并校验会告警)
385
392
 
386
393
  | 策略/功能 (Strategy/Feature) | 账户状态 (Account Status) | 优化师建议 (Senior Optimizer Recommendation) |
387
394
  | ---------------------------- | ------------------------- | -------------------------------------------- |
@@ -3799,24 +3799,39 @@
3799
3799
  const list = Array.isArray(items) ? items.slice() : [];
3800
3800
  const placeholder =
3801
3801
  '<tr><td colspan="5" class="empty-row">暂无出价策略问题,所有系列符合推荐规则</td></tr>';
3802
+ const formatBiddingDuration = (item) => {
3803
+ const raw = item?.duration;
3804
+ if (typeof raw === "string" && raw.trim()) return raw.trim();
3805
+ const days = Number(raw);
3806
+ if (Number.isFinite(days) && days > 0) {
3807
+ return `${formatNumber(days, 0)} 天`;
3808
+ }
3809
+ return "—";
3810
+ };
3811
+ const resolveStrategyCorrect = (item) => {
3812
+ if (typeof item?.isCorrect === "boolean") return item.isCorrect;
3813
+ const status = String(item?.status ?? "");
3814
+ if (/匹配|正常|达标/.test(status)) return true;
3815
+ if (/优化|需/.test(status)) return false;
3816
+ return false;
3817
+ };
3802
3818
  const rowBuilder = (item) => {
3803
3819
  const campaign = escapeHtml(
3804
3820
  String(item?.campaignName || "未命名系列"),
3805
3821
  );
3806
- const duration = escapeHtml(
3807
- `${formatNumber(item?.duration, 0)} 天`,
3808
- );
3822
+ const duration = escapeHtml(formatBiddingDuration(item));
3809
3823
  const currentStrategy = buildStrategyTag(
3810
- item?.biddingStrategyType,
3824
+ item?.biddingStrategyType ?? item?.currentStrategy,
3811
3825
  false,
3812
3826
  );
3813
3827
  const recommended = buildRecommendedStrategyCell(
3814
3828
  item?.recommendedStrategy,
3815
3829
  item?.recommendationReason,
3816
3830
  );
3817
- const status = Boolean(item?.isCorrect)
3831
+ const isCorrect = resolveStrategyCorrect(item);
3832
+ const status = isCorrect
3818
3833
  ? '<span class="status-tag status-qualified">策略匹配</span>'
3819
- : `<span class="status-tag status-unqualified" style="cursor: help;" title="${escapeHtml(item?.recommendationReason || "")}">
3834
+ : `<span class="status-tag status-unqualified" style="cursor: help;" title="${escapeHtml(item?.recommendationReason || item?.status || "")}">
3820
3835
  需优化
3821
3836
  <span style="margin-left:4px;cursor:pointer;color:#64748b;">?</span>
3822
3837
  </span>
@@ -4004,6 +4019,18 @@
4004
4019
  };
4005
4020
  };
4006
4021
 
4022
+ const resolveFeatureEnabled = (item) => {
4023
+ const raw = item?.accountStatus;
4024
+ if (typeof raw === "boolean") return raw;
4025
+ const text = String(raw ?? "")
4026
+ .trim()
4027
+ .toLowerCase();
4028
+ if (!text) return false;
4029
+ if (/未启用|disabled|false|否/.test(text)) return false;
4030
+ if (/已启用|enabled|true|是/.test(text)) return true;
4031
+ return Boolean(raw);
4032
+ };
4033
+
4007
4034
  const buildNewFeaturesRows = (items) => {
4008
4035
  const list = (Array.isArray(items) ? items : []).filter(
4009
4036
  (item) => String(item?.strategy ?? "") !== "AiMax",
@@ -4012,16 +4039,22 @@
4012
4039
  '<tr><td colspan="3" class="empty-row">暂无新产品应用数据</td></tr>';
4013
4040
  const rowBuilder = (item) => {
4014
4041
  const name = escapeHtml(
4015
- String(item?.strategyName || item?.strategy || "未命名功能"),
4042
+ String(
4043
+ item?.strategyName ||
4044
+ item?.feature ||
4045
+ item?.strategy ||
4046
+ "未命名功能",
4047
+ ),
4016
4048
  );
4017
- const status = Boolean(item?.accountStatus)
4049
+ const enabled = resolveFeatureEnabled(item);
4050
+ const status = enabled
4018
4051
  ? '<span class="feature-status is-enabled"><span class="feature-icon">✅</span>已启用</span>'
4019
4052
  : '<span class="feature-status is-disabled"><span class="feature-icon">❌</span>未启用</span>';
4020
4053
  const recommendation = String(
4021
4054
  item?.optimizerRecommendation || "",
4022
4055
  ).trim();
4023
4056
  const recommendationHtml = recommendation
4024
- ? `<span class="recommendation-text${item?.accountStatus ? " is-excellent" : ""}">${escapeHtml(
4057
+ ? `<span class="recommendation-text${enabled ? " is-excellent" : ""}">${escapeHtml(
4025
4058
  recommendation,
4026
4059
  )}</span>`
4027
4060
  : '<span class="recommendation-text">暂无建议</span>';
@@ -351,6 +351,8 @@ siluzan-tso google-ads-diagnosis render \
351
351
  **区块 ID**:`section-bidding-strategy`
352
352
  **数据**:`biddingStrategy.items`(仅「有问题」的系列进入表格;无数据时页面为「出价策略配置良好」)
353
353
 
354
+ **items 行字段(collect 事实,Agent 禁止改写)**:`campaignName`、`duration`(**天数 number**,如 `34`,勿写 `"2026-05-28 至今"` 文案)、`biddingStrategyType`(如 `MANUAL_CPC`,勿用 `currentStrategy` 替代)、`recommendedStrategy`、`recommendationReason`、`isCorrect`
355
+
354
356
  | 广告系列 | 投放时长 | 当前出价策略 | 推荐出价策略 | 状态 |
355
357
  | -------- | -------- | ------------ | ------------ | ---- |
356
358
  | | | | | |
@@ -381,7 +383,12 @@ siluzan-tso google-ads-diagnosis render \
381
383
  ## 11 新产品应用
382
384
 
383
385
  **区块 ID**:`section-new-features`
384
- **数据**:`newFeatures.items`
386
+ **数据**:`newFeatures.items`(collect 来自 campaign-types;过滤 `strategy === "AiMax"` 的行)
387
+
388
+ **items 行字段**:
389
+ - collect 事实(勿改):`strategy`(如 `PerformanceMax`)、`strategyName`(如 `效果最大化`)、`accountStatus`(**boolean**,`true`=已启用)
390
+ - Agent 只填:`optimizerRecommendation`
391
+ - **禁止**用 `feature` 替代 `strategyName`(render 模板会兜底读 `feature`,但 collect 合并校验会告警)
385
392
 
386
393
  | 策略/功能 (Strategy/Feature) | 账户状态 (Account Status) | 优化师建议 (Senior Optimizer Recommendation) |
387
394
  | ---------------------------- | ------------------------- | -------------------------------------------- |
@@ -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.33-beta.3'
12
+ $PKG_VERSION = '1.1.34-beta.2'
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.33-beta.3"
12
+ readonly PKG_VERSION="1.1.34-beta.2"
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.33-beta.3",
3
+ "version": "1.1.34-beta.2",
4
4
  "description": "Siluzan 广告账户管理 CLI — 查询账户、余额、消耗数据,管理绑定关系与充值。",
5
5
  "keywords": [
6
6
  "ad-account",