siluzan-tso-cli 1.1.52-beta.1 → 1.1.52-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.52-beta.1),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
54
+ > **注意**:当前为测试版(1.1.52-beta.2),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
55
55
 
56
56
  | 助手 | 建议 `--ai` |
57
57
  | ----------------------- | ------------------------------------ |
package/dist/index.js CHANGED
@@ -102922,67 +102922,6 @@ function summarizeOkkiDeviceSpend(rows) {
102922
102922
  otherConversions: conv.other
102923
102923
  };
102924
102924
  }
102925
- function pct1(shareValue) {
102926
- return `${(shareValue * 100).toFixed(1)}%`;
102927
- }
102928
- function deviceSpendLine(label, spend, shareValue, conversions) {
102929
- return `${label}\uFF1A\u6D88\u8017\xA5${spend.toFixed(2)}\uFF08\u5360\u6BD4${pct1(shareValue)}\uFF09\uFF0C\u8F6C\u5316${conversions}\u6B21`;
102930
- }
102931
- function formatOkkiDeviceFactsNarrative(facts) {
102932
- const sheetSummary = [
102933
- deviceSpendLine("Desktop", facts.desktop, facts.desktopShare, facts.desktopConversions),
102934
- deviceSpendLine("Mobile", facts.mobile, facts.mobileShare, facts.mobileConversions)
102935
- ];
102936
- if (facts.tablet > 0) {
102937
- sheetSummary.push(
102938
- deviceSpendLine("Tablet", facts.tablet, share(facts.tablet, facts.total), facts.tabletConversions)
102939
- );
102940
- }
102941
- const desktopLeads = facts.desktop >= facts.mobile;
102942
- const leadLabel = desktopLeads ? "\u684C\u9762\u7AEF" : "\u79FB\u52A8\u7AEF";
102943
- const leadSpend = desktopLeads ? facts.desktop : facts.mobile;
102944
- const leadShare = desktopLeads ? facts.desktopShare : facts.mobileShare;
102945
- return {
102946
- overview: `\u8BBE\u5907\u5206\u5E03\uFF1A${sheetSummary.join("\uFF1B")}`,
102947
- summary: `\u684C\u9762\u7AEF\u6D88\u8017\xA5${facts.desktop.toFixed(2)}\uFF0C\u79FB\u52A8\u7AEF\u6D88\u8017\xA5${facts.mobile.toFixed(2)}`,
102948
- sheetSummary,
102949
- spendSuggestion: `${leadLabel}\u6D88\u8017\xA5${leadSpend.toFixed(2)}\uFF08\u5360\u6BD4${pct1(leadShare)}\uFF09\uFF0C\u4E3A\u4E3B\u8981\u6D88\u8017\u8BBE\u5907\uFF0C\u5EFA\u8BAE\u5173\u6CE8\u8BE5\u7AEF\u843D\u5730\u9875\u4E0E\u51FA\u4EF7\u7CFB\u6570`
102950
- };
102951
- }
102952
- function mentionsOkkiDeviceSpendClaim(text2) {
102953
- const t = text2.replace(/\s+/g, "");
102954
- return /消耗¥/.test(t) || /占比/.test(t) || /为主要消耗/.test(t);
102955
- }
102956
- function ensureNarrative(data) {
102957
- if (!data.narrative || typeof data.narrative !== "object") data.narrative = {};
102958
- return data.narrative;
102959
- }
102960
- function asMutableRecord(value) {
102961
- return value && typeof value === "object" && !Array.isArray(value) ? value : {};
102962
- }
102963
- function applyOkkiDeviceFactsToNarrative(data) {
102964
- const facts = data.facts?.devices;
102965
- if (!facts || !(facts.total > 0)) return;
102966
- const lines = formatOkkiDeviceFactsNarrative(facts);
102967
- const narrative = ensureNarrative(data);
102968
- const sheetAnalysis = asMutableRecord(narrative.sheetAnalysis);
102969
- const sheetDevices = asMutableRecord(sheetAnalysis.devices);
102970
- const extraSheet = stringList(sheetDevices.suggestions).filter((item) => !mentionsOkkiDeviceSpendClaim(item));
102971
- sheetAnalysis.devices = {
102972
- summary: lines.sheetSummary,
102973
- suggestions: [lines.spendSuggestion, ...extraSheet]
102974
- };
102975
- narrative.sheetAnalysis = sheetAnalysis;
102976
- const review = asMutableRecord(narrative.review);
102977
- const reviewDevices = asMutableRecord(review.devices);
102978
- const extraReview = typeof reviewDevices.suggestion === "string" && !mentionsOkkiDeviceSpendClaim(reviewDevices.suggestion) ? reviewDevices.suggestion.trim() : "";
102979
- review.devices = {
102980
- overview: lines.overview,
102981
- summary: lines.summary,
102982
- suggestion: extraReview ? `${lines.spendSuggestion}\uFF1B${extraReview}` : lines.spendSuggestion
102983
- };
102984
- narrative.review = review;
102985
- }
102986
102925
  function narrativeClaimsMobileSpendLeads(text2) {
102987
102926
  const t = text2.replace(/\s+/g, "");
102988
102927
  if (!t.includes("\u79FB\u52A8")) return false;
@@ -103622,7 +103561,7 @@ async function mergeOkkiSnapshotIntoReport(payload, snapshotDir) {
103622
103561
  const averageDailyCost = num4(overviewRecord.averageDailyCost);
103623
103562
  if (averageDailyCost != null) kpis.averageDailyCost = round24(averageDailyCost);
103624
103563
  }
103625
- const merged = {
103564
+ return {
103626
103565
  ...payload,
103627
103566
  meta,
103628
103567
  kpis,
@@ -103638,8 +103577,6 @@ async function mergeOkkiSnapshotIntoReport(payload, snapshotDir) {
103638
103577
  },
103639
103578
  snapshot: { sections: snapshotPresent }
103640
103579
  };
103641
- applyOkkiDeviceFactsToNarrative(merged);
103642
- return merged;
103643
103580
  }
103644
103581
  var init_okki_merge_snapshot = __esm({
103645
103582
  "src/commands/google-analysis/okki-merge-snapshot.ts"() {
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "siluzan-tso",
3
- "version": "1.1.52-beta.1",
4
- "publishedAt": 1789440572594
3
+ "version": "1.1.52-beta.2",
4
+ "publishedAt": 1789442711860
5
5
  }
@@ -135,7 +135,7 @@
135
135
  1. (可选)Read `subagent-orchestration.md` § P6 决定是否分阶段委派。
136
136
  2. 确认 `mediaCustomerId` 与 `--start` / `--end`。
137
137
  3. 同一 `--json-out` 目录执行模板命令组合:`stats`、`balance`、`google-analysis --sections overview,campaigns,keywords,search-terms,campaign-device,campaign-geo-matched`。
138
- 4. 脚本读盘 → 只写 `okki-weekly-report.json` 的 `meta` + `narrative`(5 Sheet 表末分析 + 账户 Sheet 固定 5 维数据复盘;表为空也须写)。`deviceType` 是 `Desktop`/`Mobile`,禁止 `.get("DESKTOP")`;设备消耗/占比由 `okki-render` 覆盖。
138
+ 4. 脚本读盘 → 只写 `okki-weekly-report.json` 的 `meta` + `narrative`(5 Sheet 表末分析 + 账户 Sheet 固定 5 维数据复盘;表为空也须写)。`deviceType` 是 `Desktop`/`Mobile`,禁止 `.get("DESKTOP")`,按大小写不敏感分类累加后再写设备金额。
139
139
  5. `google-analysis okki-render --data ./okki-weekly-report.json --snapshot-dir ./snap-okki --out <xlsx>`。缺分析 / 缺 5 维复盘 / 缺 `campaign-device` 或 `campaign-geo-matched` 会拒绝出文件;按 stderr 补 JSON 后重跑。**禁止** Agent 手写 xlsx。
140
140
  6. 按 `okki-weekly-google-client.md` **默认客户话术**填数交付(用户另有话术/增删条目时从其自定义);数值与 xlsx 一致。
141
141
  - **产物**:`okki-render` 写出的 `.xlsx` 路径(缺文件 = 未完成)+ 对话内客户话术;**不**按 P4 默认 8 维追加。仅用户明确「只要话术 / 不要文件」时才省略 xlsx。
@@ -60,8 +60,8 @@ siluzan-tso google-analysis okki-render \
60
60
  - `sheetAnalysis.{campaigns,keywords,searchTerms,devices,geo}`:每个 Sheet 各 `{summary[](≥1), suggestions[](≥1)}`。**表为空也必须写**(例如「本周期无搜索词,暂无加词/否词建议」)。
61
61
  - `review.{account,keywords,searchTerms,devices,geo}`:账户 Sheet「数据复盘」固定 5 维,每维 `{overview, summary, suggestion}` 均非空。
62
62
  - `tables` / `kpis`:Agent 可省略;**render 以快照覆盖**。设备/国家只认 `campaign-device` / `campaign-geo-matched`。
63
- - `facts.devices`:render 合并快照后写入(桌面/移动/平板**费用合计**、转化次数与占比)。**设备消耗 / 占比 / 谁是主力由 CLI 按这组数覆盖** `narrative.review.devices` `sheetAnalysis.devices` 里带金额的句子;Agent 不必自己二次取值,只写不含金额的运营建议(落地页、出价系数)。
64
- - `campaign-device` 的 `deviceType` 字面量是 **`Desktop` / `Mobile` / `Tablet`**(Title Case)或中文「计算机 / 移动设备 / 平板」。脚本按大小写不敏感分类(`includes("desktop")`),**禁止** `totals.get("DESKTOP")` / `.get("MOBILE")`(键对不上会得到 0,写出「消耗¥0」)。
63
+ - `facts.devices`:render **合并后**才写入,写 JSON 时还没有这组数。设备消耗/占比必须在写 `narrative` 前由脚本从 `campaign-device` 累加(见下方「拉数」)。
64
+ - `campaign-device` 的 `deviceType` 字面量是 **`Desktop` / `Mobile` / `Tablet`**(Title Case)或中文「计算机 / 移动设备 / 平板」。**禁止** `totals.get("DESKTOP")` / `.get("MOBILE")`(键对不上就是 0,会写成「消耗¥0」)。`okki-render` **原样画出** Agent 的设备建议,不改写口吻。
65
65
 
66
66
  **禁止**:自己写 Node/Python 出 xlsx、用 Markdown 表代替、跳过 `okki-render`。`okki-render` 失败时按 stderr 缺项补 JSON 后重跑,不得改用手写表。
67
67
 
@@ -88,7 +88,25 @@ siluzan-tso google-analysis -a <mediaCustomerId> --start <S> --end <E> --json-ou
88
88
 
89
89
  - `stats`:区间消耗 / 曝光 / 点击 / 转化 / CTR / CPC,与账户级周报摘要对齐;金额用 `*Display` 或文档规定的展示字段。
90
90
  - `balance`:**当前**余额(非历史快照),话术写「截至查询时点」。
91
- - 「设备」「国家」两 Sheet **必须**用 **`campaign-device` / `campaign-geo-matched`**(按系列/组拆行),**不要**用账户级 `devices` / `geographic`,也**不要**用 `campaign-geo`(定向地理位置,与 OKKI「地理位置报告」口径不一致)。落盘文件名为 `campaign-device-<id>.json`、`campaign-geo-matched-<id>.json`。跨系列汇总在脚本中做:按 `deviceType` **分类累加**(`Desktop`/`desktop`/`计算机` 都算桌面),不要用全大写枚举当字典键。设备金额句交给 `okki-render` 覆盖,脚本不必再写进 `narrative`。
91
+ - 「设备」「国家」两 Sheet **必须**用 **`campaign-device` / `campaign-geo-matched`**(按系列/组拆行),**不要**用账户级 `devices` / `geographic`,也**不要**用 `campaign-geo`(定向地理位置,与 OKKI「地理位置报告」口径不一致)。落盘文件名为 `campaign-device-<id>.json`、`campaign-geo-matched-<id>.json`。跨系列汇总在脚本中做。
92
+ - **设备合计(写 narrative 前必做)**:按 `deviceType` **分类累加** `spend` / `conversions`,不要用原始字面量当字典键。生产常见值是 `Desktop` / `Mobile`,不是 `DESKTOP` / `MOBILE`。
93
+
94
+ ```js
95
+ function deviceKind(deviceType) {
96
+ const raw = String(deviceType ?? "");
97
+ const lower = raw.toLowerCase();
98
+ if (raw.includes("移动") || lower.includes("mobile")) return "mobile";
99
+ if (raw.includes("平板") || lower.includes("tablet")) return "tablet";
100
+ if (raw.includes("计算机") || raw.includes("电脑") || lower.includes("desktop") || lower.includes("computer")) {
101
+ return "desktop";
102
+ }
103
+ return "other";
104
+ }
105
+ // 正确:acc[deviceKind(row.deviceType)].spend += row.spend
106
+ // 错误:totals.get("DESKTOP") / totals["MOBILE"] → 键对不上,得到 0
107
+ ```
108
+
109
+ 占比用「该类费用 ÷ 设备费用合计」,不是行数或展示次数。桌面费用 ≥ 移动时,不要写「移动端为主要消耗 / 移动端占比高」。
92
110
  - 可选:`campaign-geo-matched` 支持 `--cost-greater` / `--click-greater` / `--conversions-greater`(见 `references/analytics/account-analytics.md`)。
93
111
  - TopN、占比、洞察在写 `narrative` 前由脚本对 JSON 完成,禁止心算。
94
112
  - 写 JSON 前先读各 `<section>-<id>.outline.txt` 再读 `.json`。
@@ -169,7 +187,7 @@ siluzan-tso google-analysis -a <mediaCustomerId> --start <S> --end <E> --json-ou
169
187
  总结:
170
188
  建议:
171
189
 
172
- 文案写入 `narrative.review`(每维 `overview` / `summary` / `suggestion`),由 `okki-render` 画到账户 Sheet 底部;缺任一维会拒绝出文件。**不得编造**表中不存在的数字。设备维的消耗/占比句由 CLI 按 `facts.devices` 覆盖,Agent 写错键也不会把 ¥0 画进 Excel。
190
+ 文案写入 `narrative.review`(每维 `overview` / `summary` / `suggestion`),由 `okki-render` **原样**画到账户 Sheet 底部;缺任一维会拒绝出文件。**不得编造**表中不存在的数字。设备维金额必须与脚本按 `deviceKind` 累加的结果一致。
173
191
 
174
192
  ---
175
193
 
@@ -205,7 +223,7 @@ siluzan-tso google-analysis -a <mediaCustomerId> --start <S> --end <E> --json-ou
205
223
  | R2 | 统计区间 |
206
224
  | R3(A→M,13 列) | `设备` \| `级别` \| `广告系列` \| `出价调整` \| `展示次数` \| `点击次数` \| `点击率` \| `平均每次点击费用` \| `费用` \| `所有转化次数` \| `转化次数` \| `每次转化费用` \| `转化率` |
207
225
  | R4… | `campaign-device-*.json`(`items[]`):`deviceType`→设备;`campaignName` / `adGroupName`→「广告系列」等;`allConversions`→「所有转化次数」;`conversions`→「转化次数」;`ctr` / `conversionRate` 直接写入;**出价调整**:写 `bidModifierDisplay`(与 Google 后台一致:未设置=`—`,`0.6`=`-40%`)。禁止把倍率当正百分比,禁止把未设置的 `0` 写成 `-100%`;**级别**列按运营约定(如填 `广告系列` 或 `账户`,全文一致) |
208
- | 表末「分析」 | **总结 / 金额建议由 `okki-render` `facts.devices` 覆盖**(费用合计,不是行数/展示;`deviceType` 是 `Desktop`/`Mobile`,不是 `DESKTOP`/`MOBILE`)。Agent 只需补不含金额的运营建议(出价系数、落地页、系列倾斜)。系列×设备高消耗组合、CPA/CPC 差异仍可写在建议里,不要自己重算消耗占比 |
226
+ | 表末「分析」 | **总结**:各设备消耗与转化占比、系列×设备高消耗组合、移动端 vs 桌面 CPA/CPC 差异。占比按 `deviceKind` 累加费用(见上文),`deviceType` 是 `Desktop`/`Mobile`,不是 `DESKTOP`/`MOBILE`。桌面费用 ≥ 移动时禁止写「移动端为主要消耗 / 移动端占比高」。**建议**:设备出价系数、落地页或系列倾斜(须引用设备类型与表中费用/转化),1~3 条;`okki-render` 不改写建议原文 |
209
227
 
210
228
  ---
211
229
 
@@ -60,8 +60,8 @@ siluzan-tso google-analysis okki-render \
60
60
  - `sheetAnalysis.{campaigns,keywords,searchTerms,devices,geo}`:每个 Sheet 各 `{summary[](≥1), suggestions[](≥1)}`。**表为空也必须写**(例如「本周期无搜索词,暂无加词/否词建议」)。
61
61
  - `review.{account,keywords,searchTerms,devices,geo}`:账户 Sheet「数据复盘」固定 5 维,每维 `{overview, summary, suggestion}` 均非空。
62
62
  - `tables` / `kpis`:Agent 可省略;**render 以快照覆盖**。设备/国家只认 `campaign-device` / `campaign-geo-matched`。
63
- - `facts.devices`:render 合并快照后写入(桌面/移动/平板**费用合计**、转化次数与占比)。**设备消耗 / 占比 / 谁是主力由 CLI 按这组数覆盖** `narrative.review.devices` `sheetAnalysis.devices` 里带金额的句子;Agent 不必自己二次取值,只写不含金额的运营建议(落地页、出价系数)。
64
- - `campaign-device` 的 `deviceType` 字面量是 **`Desktop` / `Mobile` / `Tablet`**(Title Case)或中文「计算机 / 移动设备 / 平板」。脚本按大小写不敏感分类(`includes("desktop")`),**禁止** `totals.get("DESKTOP")` / `.get("MOBILE")`(键对不上会得到 0,写出「消耗¥0」)。
63
+ - `facts.devices`:render **合并后**才写入,写 JSON 时还没有这组数。设备消耗/占比必须在写 `narrative` 前由脚本从 `campaign-device` 累加(见下方「拉数」)。
64
+ - `campaign-device` 的 `deviceType` 字面量是 **`Desktop` / `Mobile` / `Tablet`**(Title Case)或中文「计算机 / 移动设备 / 平板」。**禁止** `totals.get("DESKTOP")` / `.get("MOBILE")`(键对不上就是 0,会写成「消耗¥0」)。`okki-render` **原样画出** Agent 的设备建议,不改写口吻。
65
65
 
66
66
  **禁止**:自己写 Node/Python 出 xlsx、用 Markdown 表代替、跳过 `okki-render`。`okki-render` 失败时按 stderr 缺项补 JSON 后重跑,不得改用手写表。
67
67
 
@@ -88,7 +88,25 @@ siluzan-tso google-analysis -a <mediaCustomerId> --start <S> --end <E> --json-ou
88
88
 
89
89
  - `stats`:区间消耗 / 曝光 / 点击 / 转化 / CTR / CPC,与账户级周报摘要对齐;金额用 `*Display` 或文档规定的展示字段。
90
90
  - `balance`:**当前**余额(非历史快照),话术写「截至查询时点」。
91
- - 「设备」「国家」两 Sheet **必须**用 **`campaign-device` / `campaign-geo-matched`**(按系列/组拆行),**不要**用账户级 `devices` / `geographic`,也**不要**用 `campaign-geo`(定向地理位置,与 OKKI「地理位置报告」口径不一致)。落盘文件名为 `campaign-device-<id>.json`、`campaign-geo-matched-<id>.json`。跨系列汇总在脚本中做:按 `deviceType` **分类累加**(`Desktop`/`desktop`/`计算机` 都算桌面),不要用全大写枚举当字典键。设备金额句交给 `okki-render` 覆盖,脚本不必再写进 `narrative`。
91
+ - 「设备」「国家」两 Sheet **必须**用 **`campaign-device` / `campaign-geo-matched`**(按系列/组拆行),**不要**用账户级 `devices` / `geographic`,也**不要**用 `campaign-geo`(定向地理位置,与 OKKI「地理位置报告」口径不一致)。落盘文件名为 `campaign-device-<id>.json`、`campaign-geo-matched-<id>.json`。跨系列汇总在脚本中做。
92
+ - **设备合计(写 narrative 前必做)**:按 `deviceType` **分类累加** `spend` / `conversions`,不要用原始字面量当字典键。生产常见值是 `Desktop` / `Mobile`,不是 `DESKTOP` / `MOBILE`。
93
+
94
+ ```js
95
+ function deviceKind(deviceType) {
96
+ const raw = String(deviceType ?? "");
97
+ const lower = raw.toLowerCase();
98
+ if (raw.includes("移动") || lower.includes("mobile")) return "mobile";
99
+ if (raw.includes("平板") || lower.includes("tablet")) return "tablet";
100
+ if (raw.includes("计算机") || raw.includes("电脑") || lower.includes("desktop") || lower.includes("computer")) {
101
+ return "desktop";
102
+ }
103
+ return "other";
104
+ }
105
+ // 正确:acc[deviceKind(row.deviceType)].spend += row.spend
106
+ // 错误:totals.get("DESKTOP") / totals["MOBILE"] → 键对不上,得到 0
107
+ ```
108
+
109
+ 占比用「该类费用 ÷ 设备费用合计」,不是行数或展示次数。桌面费用 ≥ 移动时,不要写「移动端为主要消耗 / 移动端占比高」。
92
110
  - 可选:`campaign-geo-matched` 支持 `--cost-greater` / `--click-greater` / `--conversions-greater`(见 `references/analytics/account-analytics.md`)。
93
111
  - TopN、占比、洞察在写 `narrative` 前由脚本对 JSON 完成,禁止心算。
94
112
  - 写 JSON 前先读各 `<section>-<id>.outline.txt` 再读 `.json`。
@@ -169,7 +187,7 @@ siluzan-tso google-analysis -a <mediaCustomerId> --start <S> --end <E> --json-ou
169
187
  总结:
170
188
  建议:
171
189
 
172
- 文案写入 `narrative.review`(每维 `overview` / `summary` / `suggestion`),由 `okki-render` 画到账户 Sheet 底部;缺任一维会拒绝出文件。**不得编造**表中不存在的数字。设备维的消耗/占比句由 CLI 按 `facts.devices` 覆盖,Agent 写错键也不会把 ¥0 画进 Excel。
190
+ 文案写入 `narrative.review`(每维 `overview` / `summary` / `suggestion`),由 `okki-render` **原样**画到账户 Sheet 底部;缺任一维会拒绝出文件。**不得编造**表中不存在的数字。设备维金额必须与脚本按 `deviceKind` 累加的结果一致。
173
191
 
174
192
  ---
175
193
 
@@ -205,7 +223,7 @@ siluzan-tso google-analysis -a <mediaCustomerId> --start <S> --end <E> --json-ou
205
223
  | R2 | 统计区间 |
206
224
  | R3(A→M,13 列) | `设备` \| `级别` \| `广告系列` \| `出价调整` \| `展示次数` \| `点击次数` \| `点击率` \| `平均每次点击费用` \| `费用` \| `所有转化次数` \| `转化次数` \| `每次转化费用` \| `转化率` |
207
225
  | R4… | `campaign-device-*.json`(`items[]`):`deviceType`→设备;`campaignName` / `adGroupName`→「广告系列」等;`allConversions`→「所有转化次数」;`conversions`→「转化次数」;`ctr` / `conversionRate` 直接写入;**出价调整**:写 `bidModifierDisplay`(与 Google 后台一致:未设置=`—`,`0.6`=`-40%`)。禁止把倍率当正百分比,禁止把未设置的 `0` 写成 `-100%`;**级别**列按运营约定(如填 `广告系列` 或 `账户`,全文一致) |
208
- | 表末「分析」 | **总结 / 金额建议由 `okki-render` `facts.devices` 覆盖**(费用合计,不是行数/展示;`deviceType` 是 `Desktop`/`Mobile`,不是 `DESKTOP`/`MOBILE`)。Agent 只需补不含金额的运营建议(出价系数、落地页、系列倾斜)。系列×设备高消耗组合、CPA/CPC 差异仍可写在建议里,不要自己重算消耗占比 |
226
+ | 表末「分析」 | **总结**:各设备消耗与转化占比、系列×设备高消耗组合、移动端 vs 桌面 CPA/CPC 差异。占比按 `deviceKind` 累加费用(见上文),`deviceType` 是 `Desktop`/`Mobile`,不是 `DESKTOP`/`MOBILE`。桌面费用 ≥ 移动时禁止写「移动端为主要消耗 / 移动端占比高」。**建议**:设备出价系数、落地页或系列倾斜(须引用设备类型与表中费用/转化),1~3 条;`okki-render` 不改写建议原文 |
209
227
 
210
228
  ---
211
229
 
@@ -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.52-beta.1'
12
+ $PKG_VERSION = '1.1.52-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.52-beta.1"
12
+ readonly PKG_VERSION="1.1.52-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"
@@ -46,7 +46,7 @@ siluzan-tso google-analysis -a <mediaCustomerId> --start <S> --end <E> --json-ou
46
46
  **任务**:
47
47
 
48
48
  1. Read `report-templates/okki-weekly-google-client.md` 中 **§标准四步流程** 与 **§对外客户话术**(默认 7 条模板;主 Agent 若指定自定义话术则从其指示)。
49
- 2. 按 `assets/okki-weekly-report.schema.json` 写 `okki-weekly-report.json`:只填 `meta` + `narrative.sheetAnalysis`(5 Sheet,各 summary≥1 / suggestions≥1)+ `narrative.review`(固定 5 维:账户/关键词/搜索字词/设备/国家,每维 overview+summary+suggestion)。表为空也须写分析。`campaign-device` 的 `deviceType` 是 `Desktop`/`Mobile`/`Tablet`(不是 `DESKTOP`/`MOBILE`);设备消耗/占比由 `okki-render` 按快照覆盖,脚本不要用大写键二次取值,也不要把 ¥0 写进设备维。
49
+ 2. 按 `assets/okki-weekly-report.schema.json` 写 `okki-weekly-report.json`:只填 `meta` + `narrative.sheetAnalysis`(5 Sheet,各 summary≥1 / suggestions≥1)+ `narrative.review`(固定 5 维:账户/关键词/搜索字词/设备/国家,每维 overview+summary+suggestion)。表为空也须写分析。`campaign-device` 的 `deviceType` 是 `Desktop`/`Mobile`/`Tablet`(不是 `DESKTOP`/`MOBILE`);设备消耗按 `toLowerCase()` / `includes("desktop")` 分类累加,**禁止** `.get("DESKTOP")`。
50
50
  3. 执行:
51
51
  ```bash
52
52
  siluzan-tso google-analysis okki-render \
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "siluzan-tso-cli",
3
- "version": "1.1.52-beta.1",
3
+ "version": "1.1.52-beta.2",
4
4
  "description": "Siluzan 广告账户管理 CLI — 查询账户、余额、消耗数据,管理绑定关系与充值。",
5
5
  "keywords": [
6
6
  "ad-account",