siluzan-tso-cli 1.1.37-beta.2 → 1.1.37-beta.3
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 +1 -1
- package/dist/index.js +28 -1
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/assets/pmax-lead-form-template.md +5 -5
- package/dist/skill/references/accounts/accounts.md +3 -1
- package/dist/skill/references/core/agent-conventions.md +5 -2
- package/dist/skill/references/core/tips.md +4 -3
- package/dist/skill/references/google-ads/google-ads.md +3 -1
- package/dist/skill/references/operations/hosted-automation-self-control.md +14 -9
- package/dist/skill/references/operations/hosted-automation-user-catalog.md +2 -0
- package/dist/skill/scripts/install.ps1 +1 -1
- package/dist/skill/scripts/install.sh +1 -1
- package/package.json +1 -1
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.37-beta.
|
|
54
|
+
> **注意**:当前为测试版(1.1.37-beta.3),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
55
55
|
|
|
56
56
|
| 助手 | 建议 `--ai` |
|
|
57
57
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -113039,6 +113039,10 @@ var VALID_LEAD_FORM_INPUT_TYPES = [
|
|
|
113039
113039
|
"POSTAL_CODE",
|
|
113040
113040
|
"STREET_ADDRESS"
|
|
113041
113041
|
];
|
|
113042
|
+
var LEAD_FORM_HEADLINE_MAX_LEN = 30;
|
|
113043
|
+
var LEAD_FORM_DESCRIPTION_MAX_LEN = 200;
|
|
113044
|
+
var LEAD_FORM_BUSINESS_NAME_MAX_LEN = 25;
|
|
113045
|
+
var LEAD_FORM_CTA_DESCRIPTION_MAX_LEN = 30;
|
|
113042
113046
|
function loadLeadFormExtensionConfig(configFile) {
|
|
113043
113047
|
let raw;
|
|
113044
113048
|
try {
|
|
@@ -113066,10 +113070,30 @@ function validateLeadFormPayload(lf, prefix = "leadForm") {
|
|
|
113066
113070
|
return errors;
|
|
113067
113071
|
}
|
|
113068
113072
|
if (!lf.businessName?.trim()) errors.push(`${prefix}.businessName \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
113073
|
+
else if (lf.businessName.trim().length > LEAD_FORM_BUSINESS_NAME_MAX_LEN) {
|
|
113074
|
+
errors.push(
|
|
113075
|
+
`${prefix}.businessName \u8D85\u957F\uFF08${lf.businessName.trim().length}/${LEAD_FORM_BUSINESS_NAME_MAX_LEN}\uFF09\uFF1A\u300C${lf.businessName.trim()}\u300D`
|
|
113076
|
+
);
|
|
113077
|
+
}
|
|
113069
113078
|
if (!lf.headline?.trim()) errors.push(`${prefix}.headline \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
113079
|
+
else if (lf.headline.trim().length > LEAD_FORM_HEADLINE_MAX_LEN) {
|
|
113080
|
+
errors.push(
|
|
113081
|
+
`${prefix}.headline \u8D85\u957F\uFF08${lf.headline.trim().length}/${LEAD_FORM_HEADLINE_MAX_LEN}\uFF09\uFF1A\u300C${lf.headline.trim()}\u300D`
|
|
113082
|
+
);
|
|
113083
|
+
}
|
|
113070
113084
|
if (!lf.description?.trim()) errors.push(`${prefix}.description \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
113085
|
+
else if (lf.description.trim().length > LEAD_FORM_DESCRIPTION_MAX_LEN) {
|
|
113086
|
+
errors.push(
|
|
113087
|
+
`${prefix}.description \u8D85\u957F\uFF08${lf.description.trim().length}/${LEAD_FORM_DESCRIPTION_MAX_LEN}\uFF09`
|
|
113088
|
+
);
|
|
113089
|
+
}
|
|
113071
113090
|
if (!lf.privacyPolicyUrl?.trim()) errors.push(`${prefix}.privacyPolicyUrl \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
113072
113091
|
if (!lf.finalUrl?.trim()) errors.push(`${prefix}.finalUrl \u4E0D\u80FD\u4E3A\u7A7A`);
|
|
113092
|
+
if (lf.callToActionDescription?.trim() && lf.callToActionDescription.trim().length > LEAD_FORM_CTA_DESCRIPTION_MAX_LEN) {
|
|
113093
|
+
errors.push(
|
|
113094
|
+
`${prefix}.callToActionDescription \u8D85\u957F\uFF08${lf.callToActionDescription.trim().length}/${LEAD_FORM_CTA_DESCRIPTION_MAX_LEN}\uFF09`
|
|
113095
|
+
);
|
|
113096
|
+
}
|
|
113073
113097
|
if (!Array.isArray(lf.fields) || lf.fields.length === 0) {
|
|
113074
113098
|
errors.push(`${prefix}.fields \u81F3\u5C11 1 \u9879`);
|
|
113075
113099
|
} else {
|
|
@@ -116555,7 +116579,10 @@ function classifyExtensionAttachError(error) {
|
|
|
116555
116579
|
return `${raw}\uFF08\u591A\u4E3A header \u4E0D\u5728\u5408\u6CD5\u679A\u4E3E\uFF1B\u8FD0\u884C ad extension snippet-headers \u6838\u5BF9\uFF09`;
|
|
116556
116580
|
}
|
|
116557
116581
|
if (/lead form|lead_form|LEAD_FORM/i.test(raw)) {
|
|
116558
|
-
return `${raw}\uFF08\u68C0\u67E5
|
|
116582
|
+
return `${raw}\uFF08\u68C0\u67E5\uFF1Aheadline\u226430\u3001description\u2264200\u3001businessName\u226425\uFF1Bfields \u52FF\u7528 MESSAGE\uFF1BGoogle Ads UI \u662F\u5426\u5DF2\u63A5\u53D7 Lead Form ToS\uFF09`;
|
|
116583
|
+
}
|
|
116584
|
+
if (/^HTTP 400\b/i.test(raw)) {
|
|
116585
|
+
return `${raw}\uFF08\u6269\u5C55\u5B57\u6BB5\u8FDD\u89C4\u5E38\u89C1\uFF1Asnippet header \u975E\u679A\u4E3E\u3001Lead Form \u6587\u6848\u8D85\u957F\u3001URL \u65E0\u6548\uFF1B\u52A0 --verbose \u770B\u7F51\u5173\u539F\u6587\uFF09`;
|
|
116559
116586
|
}
|
|
116560
116587
|
return raw;
|
|
116561
116588
|
}
|
package/dist/skill/_meta.json
CHANGED
|
@@ -40,14 +40,14 @@ siluzan-tso ad extension update -a <accountId> --id <extensionId> --config-file
|
|
|
40
40
|
| ---------------------------------- | -------- | :--: | -------------------------------------------------------------- |
|
|
41
41
|
| `account` | string | ✅ | Google 媒体客户 ID |
|
|
42
42
|
| `campaignId` | string | ✅ | PMax 活动 ID(`channelTypeV2=PERFORMANCE_MAX`) |
|
|
43
|
-
| `leadForm.businessName` | string | ✅ |
|
|
44
|
-
| `leadForm.headline` | string | ✅ |
|
|
45
|
-
| `leadForm.description` | string | ✅ |
|
|
43
|
+
| `leadForm.businessName` | string | ✅ | 商家名称(≤25 字符) |
|
|
44
|
+
| `leadForm.headline` | string | ✅ | 表单标题(**≤30 字符**,超长网关常直接 HTTP 400) |
|
|
45
|
+
| `leadForm.description` | string | ✅ | 表单描述(≤200 字符) |
|
|
46
46
|
| `leadForm.privacyPolicyUrl` | string | ✅ | 隐私政策 URL |
|
|
47
47
|
| `leadForm.finalUrl` | string | ✅ | 落地页 URL |
|
|
48
48
|
| `leadForm.callToActionType` | string | | 默认 `LEARN_MORE` |
|
|
49
|
-
| `leadForm.callToActionDescription` | string | | 默认 `Contact us
|
|
50
|
-
| `leadForm.fields` | object[] | ✅ | 至少 1 项;`inputType` 如 `FULL_NAME`、`EMAIL`、`PHONE_NUMBER` |
|
|
49
|
+
| `leadForm.callToActionDescription` | string | | 默认 `Contact us`(≤30 字符) |
|
|
50
|
+
| `leadForm.fields` | object[] | ✅ | 至少 1 项;`inputType` 如 `FULL_NAME`、`EMAIL`、`PHONE_NUMBER`(**无** `MESSAGE`) |
|
|
51
51
|
| `leadForm.webhook` | object | | 写入 Google 的 Webhook(非平台接收端) |
|
|
52
52
|
|
|
53
53
|
---
|
|
@@ -203,7 +203,7 @@ siluzan-tso accounts-digest -m Google -a id1,id2 --min-spend 10 \
|
|
|
203
203
|
--start 2026-04-01 --end 2026-04-15 --json-out ./snap-p3
|
|
204
204
|
```
|
|
205
205
|
|
|
206
|
-
**`data.items[]` 主要字段**:`mediaCustomerId`、`name`、`advertiserName`、`currencyCode`、`balance`、`spend
|
|
206
|
+
**`data.items[]` 主要字段**:`mediaCustomerId`、`name`、`advertiserName`、`currencyCode`、`balance`、`spend`(**区间合计**,同 `stats`)、`impressions`、`clicks`、`conversions`、`ctr`(%)、`cpc`、`cpa`。跨币种汇总见 `references/accounts/currency.md`(**禁止**对 `meta.totals` 跨币种直接当最终结论)。
|
|
207
207
|
|
|
208
208
|
---
|
|
209
209
|
|
|
@@ -230,6 +230,8 @@ siluzan-tso stats -m <媒体类型> [选项]
|
|
|
230
230
|
| `--start-date` / `--end-date` | 与 `--start` / `--end` 同义(CLI 别名,与 SKILL Playbook 一致) | — |
|
|
231
231
|
| `--json-out` | 输出原始 JSON;**失败时 stdout 仍为 JSON**(`{"ok":false,"error":"..."}`) | — |
|
|
232
232
|
|
|
233
|
+
**口径(易错)**:返回的 **`spend` = `--start`~`--end` 闭区间合计消耗**,默认近 7 天即约 **7 日之和**,**不是**「一天的消耗」。要日消耗须 `start=end`;要日均用 `spend/天数` 或 `balance-scan` 的 `dailySpend`。**禁止**把默认窗口的 `spend` 当成日消耗去比日预算或写「今天花了 X」。
|
|
234
|
+
|
|
233
235
|
**示例:**
|
|
234
236
|
|
|
235
237
|
```bash
|
|
@@ -194,10 +194,13 @@
|
|
|
194
194
|
|
|
195
195
|
| 任务 | 推荐命令 | 禁止 |
|
|
196
196
|
| --------------------------- | -------------------------------------------------------------------------------------- | -------------------------------- |
|
|
197
|
-
| 多账户余额 / 预算不足预警 | `balance-scan -m <媒体> --threshold-days 7`
|
|
198
|
-
| 多账户投放画像 | `accounts-digest -m <媒体> [-a ...] --start --end --json-out
|
|
197
|
+
| 多账户余额 / 预算不足预警 | `balance-scan -m <媒体> --threshold-days 7`(用 **`dailySpend`** / `remainingDays`) | 逐账户 `balance --accounts ...`;把 `stats` 多日 **`spend` 当「日消耗」** |
|
|
198
|
+
| 多账户投放画像 | `accounts-digest -m <媒体> [-a ...] --start --end --json-out`(**`spend`=区间合计**) | 逐账户 `stats`;把合计 `spend` 说成「每天花了」 |
|
|
199
199
|
| 多账户 × 多维度 Google 数据 | 全量:`google-analysis-batch run`(省略 `-a`);2~10:`google-analysis -a id1,id2,...` | 外层 for-loop;先 list 再拼 `-a` |
|
|
200
200
|
| 多系列诊断 | `ad campaigns --json-out` + node 读文件过滤 | 逐系列 `ad campaign-get` |
|
|
201
|
+
| 单日预算熔断 / 当日花费比日预算 | `ad campaigns --start <当日> --end <当日>`(**start=end**)后再比 `spend` 与 `budget` | 用默认近 7 天窗口的 `spend` 对比日预算 |
|
|
202
|
+
|
|
203
|
+
**消耗口径(自动化必读)**:凡 `--start`/`--end` 读命令的 `spend` = **闭区间合计**,默认近 7 天 ≠ 一天。日均用 `balance-scan.dailySpend` 或 `合计÷天数`;详见 `references/operations/hosted-automation-self-control.md`「检查项常用 JSON 字段」。
|
|
201
204
|
|
|
202
205
|
**`google-analysis-batch` 纪律**(详见 `references/analytics/google-analysis-batch.md`):拉全量时省略 `-a`;中断后**必须** `resume --run-id <id>`,**禁止**重新 `run`;stdout 始终单行 JSON(`kind=siluzan-tso-batch-summary`);退出码 `0` 全成功 / `2` 部分成功 / `3` 全失败或 Token 失效 / `4` 用法错误;401 → 整批终止,按 `references/core/setup.md` 重登录后 `resume`。
|
|
203
206
|
|
|
@@ -93,16 +93,17 @@ low.forEach((a) => console.log(' ', a.mediaCustomerId, a.name, '余额:', a.rema
|
|
|
93
93
|
|
|
94
94
|
### 3. 汇总消耗数据
|
|
95
95
|
|
|
96
|
-
`stats` 的 `AccountOverviewItem` 使用 **`spend`**(非 `cost
|
|
96
|
+
`stats` 的 `AccountOverviewItem` 使用 **`spend`**(非 `cost`)。**`spend` = `--start`~`--end` 区间合计**(默认近 7 天 ≈ 7 日之和,**不是**「一天的消耗」):
|
|
97
97
|
|
|
98
98
|
```bash
|
|
99
|
-
siluzan-tso stats -m Google --
|
|
99
|
+
siluzan-tso stats -m Google -a <id> --start 2026-07-06 --end 2026-07-12 --json-out ./snap-cli
|
|
100
100
|
node -e "
|
|
101
101
|
const d = require('./snap-cli/stats-google.json');
|
|
102
102
|
const list = d.items || [];
|
|
103
|
+
// 「总消耗」= 区间合计;日均请 total/天数,或 balance-scan.dailySpend;勿说成每天花了 total
|
|
103
104
|
const total = list.reduce((s, a) => s + Number(a.spend ?? 0), 0);
|
|
104
105
|
const clicks = list.reduce((s, a) => s + Number(a.clicks ?? 0), 0);
|
|
105
|
-
console.log('
|
|
106
|
+
console.log('区间总消耗:', total.toFixed(2), ' 总点击:', clicks);
|
|
106
107
|
list
|
|
107
108
|
.slice()
|
|
108
109
|
.sort((a, b) => Number(b.spend) - Number(a.spend))
|
|
@@ -97,7 +97,9 @@
|
|
|
97
97
|
siluzan-tso ad campaigns -a <accountId> [--start <YYYY-MM-DD>] [--end <YYYY-MM-DD>] [--json-out ./snap]
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
-
落盘 JSON 中
|
|
100
|
+
落盘 JSON 中 **`budget` 为日预算**(主币种「元」,CLI 已 ÷100),另有 `statusDisplay`(状态文案)。
|
|
101
|
+
带 `--start` / `--end` 时,同行的 **`spend` / `impressions` / `clicks` / `conversions` 为该闭区间合计**(**不是**日消耗)。
|
|
102
|
+
与日预算比较「是否超预算」时,**必须** `start=end=统计日`;多日窗口须先 ÷ 天数或改用 `balance-scan.dailySpend` / `overview.averageDailyCost` 再谈「日均」。
|
|
101
103
|
|
|
102
104
|
### 启停
|
|
103
105
|
|
|
@@ -26,11 +26,15 @@
|
|
|
26
26
|
|
|
27
27
|
| 检查意图 | 可关注的 JSON 字段(键名以实际 stdout 为准) |
|
|
28
28
|
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
-
|
|
|
29
|
+
| **区间合计费用** | 系列/组/创意列表中的 **`spend`** = **`--start`~`--end` 整段合计**(**不是**「一天的消耗」;窗口 7 天则约为 7 日之和) |
|
|
30
|
+
| **日预算** | **`ad campaigns --json-out ./snap`** 的 **`budget`**(CLI 已为元)= **每日预算上限**,与 `spend` **量纲不同** |
|
|
31
|
+
| 日预算与「当日」费用比 | **仅当** `--start` 与 `--end` 为**同一统计日**时,才可用 `spend` 对比 `budget`;**禁止**用多日 `spend` 去除以或对比日预算(会把周/月合计误当成「一天花了这么多」) |
|
|
32
|
+
| 转化次数 | **`conversions`**(窗口内合计) |
|
|
33
|
+
| 实际 CPA | 宿主侧 **`spend / conversions`**(同窗口合计;`conversions` 为 0 时不做 CPA 判断) |
|
|
33
34
|
| 目标 CPA(系列 / 组) | 系列列表 JSON 中的 **`targetCpa_BidingAmount`** 等;组列表 **`ad groups --json-out ./snap`** 中的 **`targetCpaAmount`**(写入口径见 `references/google-ads/google-ads.md`「广告组编辑」) |
|
|
35
|
+
| 日均消耗(续航用) | 用 `balance-scan` 的 **`dailySpend`**(近 7 日合计/7),或自算 `spend / 活跃天数`;**禁止**把多日 `spend` 直接当「日消耗」 |
|
|
36
|
+
|
|
37
|
+
> **硬约束(自动化 / 预警必读)**:凡带 `--start` / `--end` 的读命令,返回的 `spend` / `impressions` / `clicks` / `conversions` 均为**该闭区间合计**。要「一天的消耗」必须 `start=end=该日`,或显式 `合计 ÷ 天数`;要「日均」用 `balance-scan.dailySpend` / `overview.averageDailyCost`。
|
|
34
38
|
|
|
35
39
|
若某条检查所需字段在**当前**落盘 JSON 中不存在,**禁止猜测**:先换用 `references/analytics/account-analytics.md` 中其它子命令拉数,或与维护方确认是否需扩展 `siluzan-tso`;宿主侧不得编造字段。
|
|
36
40
|
|
|
@@ -38,21 +42,22 @@
|
|
|
38
42
|
|
|
39
43
|
## 场景 1:单日预算熔断(Campaign)
|
|
40
44
|
|
|
41
|
-
|
|
45
|
+
**业务目标**:当**当日**系列花费相对**日预算**达到设定比例(如 **≥ 110%**,建议 **110%–120%** 缓冲 API 延迟)时,**将系列状态置为 Paused**;恢复由人工加预算后在网页或 CLI 再启用。
|
|
42
46
|
|
|
43
47
|
### 检查项(宿主每轮执行)
|
|
44
48
|
|
|
45
49
|
1. 解析 `mediaCustomerId`(见上文前置)。
|
|
46
|
-
2.
|
|
50
|
+
2. 拉系列列表(**必须** `--start` = `--end` = **当日**统计日;**禁止**用默认近 7 天窗口做本场景):
|
|
47
51
|
|
|
48
52
|
```bash
|
|
49
|
-
siluzan-tso ad campaigns -a <mediaCustomerId> --start
|
|
53
|
+
siluzan-tso ad campaigns -a <mediaCustomerId> --start <当日YYYY-MM-DD> --end <当日YYYY-MM-DD> --json-out ./snap
|
|
50
54
|
```
|
|
51
55
|
|
|
52
56
|
3. 对 `items[]` 中每条系列(`id` 为系列 ID):
|
|
53
|
-
- 读取 **`spend
|
|
54
|
-
- 计算阈值:`threshold =
|
|
57
|
+
- 读取 **`spend`**(= **仅当日**合计费用)与 **`budget`**(**日预算**,元)。
|
|
58
|
+
- 计算阈值:`threshold = budget * (coefficient / 100)`,系数 `coefficient` 建议 **110–120**(配置项)。
|
|
55
59
|
- **IF** `spend >= threshold` **且**宿主策略允许对该系列熔断(如排除白名单),则进入写操作。
|
|
60
|
+
- **禁止**:`--start`≠`--end` 时仍用 `spend` 对比 `budget`(会把多日合计误判成单日超预算)。
|
|
56
61
|
|
|
57
62
|
### 最终操作
|
|
58
63
|
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
**总索引**:[`references/operations/hosted-automation-scenarios.md`](references/operations/hosted-automation-scenarios.md) · **自控全文**:[`references/operations/hosted-automation-self-control.md`](references/operations/hosted-automation-self-control.md) · **金额硬规范**(展示用 `*Display` 等):[`SKILL.md`](../SKILL.md)「金额与货币单位硬约束」。
|
|
16
16
|
|
|
17
|
+
> **消耗 ≠ 日消耗**:`ad campaigns` / `stats` / `accounts-digest` 的 **`spend` 是 `--start`~`--end` 合计**。单日熔断必须 `start=end=当日`;续航日均用 **`balance-scan.dailySpend`**,禁止把默认近 7 天 `spend` 当成「一天的花费」去比日预算。
|
|
18
|
+
|
|
17
19
|
## 异常监控与报警系统
|
|
18
20
|
|
|
19
21
|
编排(定时、HTTP 探活、通知)在宿主;**读哪些 JSON 字段、用什么命令** 以 **[`references/operations/hosted-automation-monitoring-json.md`](references/operations/hosted-automation-monitoring-json.md)** 为准(键名以当次 `--json-out` 落盘 JSON 为准,勿套用 Google Ads API 官方字段名解析本 CLI 输出)。
|
|
@@ -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.37-beta.
|
|
12
|
+
$PKG_VERSION = '1.1.37-beta.3'
|
|
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.37-beta.
|
|
12
|
+
readonly PKG_VERSION="1.1.37-beta.3"
|
|
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"
|