siluzan-tso-cli 1.1.33 → 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
@@ -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.34-beta.2),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
54
55
 
55
56
  | 助手 | 建议 `--ai` |
56
57
  | ----------------------- | ------------------------------------ |
package/dist/index.js CHANGED
@@ -3829,7 +3829,7 @@ var DEFAULT_API_BASE;
3829
3829
  var init_defaults = __esm({
3830
3830
  "src/config/defaults.ts"() {
3831
3831
  "use strict";
3832
- DEFAULT_API_BASE = "https://tso-api.siluzan.com";
3832
+ DEFAULT_API_BASE = "https://tso-api-ci.siluzan.com";
3833
3833
  }
3834
3834
  });
3835
3835
 
@@ -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",
4
- "publishedAt": 1782887221443
3
+ "version": "1.1.34-beta.2",
4
+ "publishedAt": 1782898503071
5
5
  }
@@ -280,7 +280,7 @@ siluzan-tso account-history --start 2026-03-01 --end 2026-03-31 --json-out ./sna
280
280
  | 状态 | 含义 | 下一步操作 |
281
281
  | ---------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
282
282
  | `Pending` | 审核中 | 等待,可反复运行此命令轮询;审核周期因媒体而异 |
283
- | `Approved` | 审核通过 | 运行 `list-accounts -m <媒体>` 确认账户已出现;引导用户充值激活(`config show` 取 `webUrl`,按 `finance.md` 打开对应媒体充值页;例如 Google 为 `https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google`;Kwai、Yandex 当前没有对应充值界面) |
283
+ | `Approved` | 审核通过 | 运行 `list-accounts -m <媒体>` 确认账户已出现;引导用户充值激活(`config show` 取 `webUrl`,按 `finance.md` 打开对应媒体充值页;例如 Google 为 `https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google`;Kwai、Yandex 当前没有对应充值界面) |
284
284
  | `Rejected` | 被拒 | 查看 `--json-out` 落盘中的 `reason` 字段了解拒绝原因;修改资料后重新提交;若原因不明,引导用户联系丝路赞客服 |
285
285
 
286
286
  ---
@@ -888,7 +888,7 @@ siluzan-tso account email-deauth -c <mediaCustomerId> --invitation-id <id> --res
888
888
 
889
889
  | 功能 | 媒体 | 网页路径 |
890
890
  | --------------------------------------- | ------ | ------------------------------------------------- |
891
- | **账户激活**(邀请他人激活 / 充值激活) | Google | `https://www.siluzan.com/v3/foreign_trade/tso/manageAccounts` |
891
+ | **账户激活**(邀请他人激活 / 充值激活) | Google | `https://www-ci.siluzan.com/v3/foreign_trade/tso/manageAccounts` |
892
892
 
893
893
  **Agent 建议话术**:
894
894
 
@@ -897,5 +897,5 @@ siluzan-tso account email-deauth -c <mediaCustomerId> --invitation-id <id> --res
897
897
  siluzan-tso config show # 查看 webUrl 字段
898
898
 
899
899
  # 账户激活(Google)→ 引导至账户管理页
900
- # https://www.siluzan.com/v3/foreign_trade/tso/manageAccounts
900
+ # https://www-ci.siluzan.com/v3/foreign_trade/tso/manageAccounts
901
901
  ```
@@ -117,7 +117,7 @@ siluzan-tso config show
117
117
 
118
118
  ### 充值页链接(按媒体 × 类型)
119
119
 
120
- 链接模式:`https://www.siluzan.com/v3/foreign_trade/tso/recharge/<page>?mediaType=<mediaType>`;丝路赞钱包:`https://www.siluzan.com/v3/foreign_trade/tso/recharge/siluzanWallet`(无媒体参数)。
120
+ 链接模式:`https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/<page>?mediaType=<mediaType>`;丝路赞钱包:`https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/siluzanWallet`(无媒体参数)。
121
121
 
122
122
  | 充值类型 | `<page>` | 支持媒体(`mediaType` 参数) |
123
123
  | ------------------------- | --------------------- | ------------------------------------------- |
@@ -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
  ## 首次响应硬规范(必读)
@@ -60,7 +60,7 @@ siluzan-tso open-account google-wizard
60
60
 
61
61
  ```bash
62
62
  siluzan-tso account-history -m Google
63
- # 审核通过后:config show → https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
63
+ # 审核通过后:config show → https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
64
64
  ```
65
65
 
66
66
  ---
@@ -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
 
@@ -192,9 +192,9 @@ siluzan-tso report push receive-emails -m Google [--json-out ./snap]
192
192
 
193
193
  | 媒体 | 报告类型 | URL 模板 |
194
194
  | ------ | ---------------- | ----------------------------------------------------------- |
195
- | Google | 日报(Daily) | `https://www.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
196
- | Google | 小时报(Hourly) | `https://www.siluzan.com/media-report/hour/{entityId}?culture=zh-CN` |
197
- | TikTok | 日报 | `https://www.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
195
+ | Google | 日报(Daily) | `https://www-ci.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
196
+ | Google | 小时报(Hourly) | `https://www-ci.siluzan.com/media-report/hour/{entityId}?culture=zh-CN` |
197
+ | TikTok | 日报 | `https://www-ci.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
198
198
 
199
199
  `entityId` 来自 `siluzan-tso report list --json-out ./snap` 中每条记录的 `entityId` 字段。
200
200
 
@@ -207,8 +207,8 @@ siluzan-tso report list -m Google --json-out ./snap
207
207
 
208
208
  # 第二步:查看 webUrl
209
209
  siluzan-tso config show
210
- # webUrl: https://www.siluzan.com
210
+ # webUrl: https://www-ci.siluzan.com
211
211
 
212
212
  # 第三步:拼接链接(Google 日报)
213
- # https://www.siluzan.com/media-report/publish/rpt_abc123?culture=zh-CN
213
+ # https://www-ci.siluzan.com/media-report/publish/rpt_abc123?culture=zh-CN
214
214
  ```
@@ -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 步:让用户报出手机号后,立刻发码(命令立即返回,不会等待输入)
@@ -129,9 +129,9 @@ siluzan-tso config show
129
129
 
130
130
  ```
131
131
  构建环境 : production
132
- apiBaseUrl : https://tso-api.siluzan.com
133
- googleApiUrl : https://googleapi.mysiluzan.com
134
- webUrl : https://www.siluzan.com
132
+ apiBaseUrl : https://tso-api-ci.siluzan.com
133
+ googleApiUrl : https://googleapi-ci.mysiluzan.com
134
+ webUrl : https://www-ci.siluzan.com
135
135
  apiKey : abcd****1234
136
136
  ```
137
137
 
@@ -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
 
@@ -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,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.33'
12
+ $PKG_VERSION = '1.1.34-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.33"
12
+ readonly PKG_VERSION="1.1.34-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.33",
3
+ "version": "1.1.34-beta.2",
4
4
  "description": "Siluzan 广告账户管理 CLI — 查询账户、余额、消耗数据,管理绑定关系与充值。",
5
5
  "keywords": [
6
6
  "ad-account",