siluzan-tso-cli 1.1.53-beta.3 → 1.1.53-beta.5
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 +33 -18
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/core/intent-routing.md +2 -2
- package/dist/skill/references/core/playbooks.md +1 -1
- package/dist/skill/references/report-templates/google-inquiry-analysis.md +22 -15
- package/dist/skill/references/report-templates/google-quarterly-plan.md +6 -6
- package/dist/skill/references/report-templates/google-quarterly-report.md +11 -10
- package/dist/skill/report-templates/google-inquiry-analysis.md +22 -15
- package/dist/skill/report-templates/google-quarterly-plan.md +6 -6
- package/dist/skill/report-templates/google-quarterly-report.html +22 -9
- package/dist/skill/report-templates/google-quarterly-report.md +11 -10
- 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.53-beta.
|
|
54
|
+
> **注意**:当前为测试版(1.1.53-beta.5),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
55
55
|
|
|
56
56
|
| 助手 | 建议 `--ai` |
|
|
57
57
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
|
@@ -2467,7 +2467,13 @@ function rawRequest(url, options) {
|
|
|
2467
2467
|
}
|
|
2468
2468
|
reject(err);
|
|
2469
2469
|
});
|
|
2470
|
-
if (options.body)
|
|
2470
|
+
if (options.body !== void 0) {
|
|
2471
|
+
const payload = typeof options.body === "string" ? Buffer.from(options.body) : options.body;
|
|
2472
|
+
if (!headers["Content-Length"] && !headers["content-length"]) {
|
|
2473
|
+
req.setHeader("Content-Length", payload.length);
|
|
2474
|
+
}
|
|
2475
|
+
req.write(payload);
|
|
2476
|
+
}
|
|
2471
2477
|
req.end();
|
|
2472
2478
|
});
|
|
2473
2479
|
}
|
|
@@ -2562,6 +2568,20 @@ function formatHttpError(status, rawBody, opts) {
|
|
|
2562
2568
|
function buildAuthHeaders(config) {
|
|
2563
2569
|
return buildSiluzanAuthHeaders(config);
|
|
2564
2570
|
}
|
|
2571
|
+
async function parseApiResponse(status, text2, verbose) {
|
|
2572
|
+
if (status < 200 || status >= 300) {
|
|
2573
|
+
throw new Error(formatHttpError(status, text2, { verbose }));
|
|
2574
|
+
}
|
|
2575
|
+
if (!text2.trim()) return null;
|
|
2576
|
+
try {
|
|
2577
|
+
return parseJsonWithStringIds(text2);
|
|
2578
|
+
} catch {
|
|
2579
|
+
if (verbose) {
|
|
2580
|
+
console.error(` \u26A0\uFE0F \u54CD\u5E94\u975E JSON\uFF0C\u539F\u59CB\u5185\u5BB9\uFF1A${redactSensitive(text2).slice(0, 200)}`);
|
|
2581
|
+
}
|
|
2582
|
+
return text2;
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2565
2585
|
async function apiFetch(url, config, options = {}, verbose = false) {
|
|
2566
2586
|
const method = options.method ?? "GET";
|
|
2567
2587
|
const reqHeaders = {
|
|
@@ -2580,19 +2600,7 @@ async function apiFetch(url, config, options = {}, verbose = false) {
|
|
|
2580
2600
|
headers: reqHeaders,
|
|
2581
2601
|
body
|
|
2582
2602
|
});
|
|
2583
|
-
|
|
2584
|
-
if (res.status < 200 || res.status >= 300) {
|
|
2585
|
-
throw new Error(formatHttpError(res.status, text2, { verbose }));
|
|
2586
|
-
}
|
|
2587
|
-
if (!text2.trim()) return null;
|
|
2588
|
-
try {
|
|
2589
|
-
return parseJsonWithStringIds(text2);
|
|
2590
|
-
} catch {
|
|
2591
|
-
if (verbose) {
|
|
2592
|
-
console.error(` \u26A0\uFE0F \u54CD\u5E94\u975E JSON\uFF0C\u539F\u59CB\u5185\u5BB9\uFF1A${redactSensitive(text2).slice(0, 200)}`);
|
|
2593
|
-
}
|
|
2594
|
-
return text2;
|
|
2595
|
-
}
|
|
2603
|
+
return parseApiResponse(res.status, res.text, verbose);
|
|
2596
2604
|
}
|
|
2597
2605
|
async function apiFetchWithHeaders(url, config, options = {}, verbose = false) {
|
|
2598
2606
|
const method = options.method ?? "GET";
|
|
@@ -134432,16 +134440,23 @@ function parseInquiryRecords(raw) {
|
|
|
134432
134440
|
for (const item of list) {
|
|
134433
134441
|
if (!item || typeof item !== "object") continue;
|
|
134434
134442
|
const row = item;
|
|
134435
|
-
const countryZh = pick(row, [
|
|
134436
|
-
|
|
134443
|
+
const countryZh = pick(row, [
|
|
134444
|
+
"\u76EE\u6807\u56FD\u5BB6/\u5730\u533A",
|
|
134445
|
+
"countryZh",
|
|
134446
|
+
"country",
|
|
134447
|
+
"\u56FD\u5BB6",
|
|
134448
|
+
"\u56FD\u5BB6(\u4E2D\u6587)"
|
|
134449
|
+
]);
|
|
134450
|
+
const date = pick(row, ["\u8BE2\u76D8\u65E5\u671F", "date", "\u65F6\u95F4", "time"]);
|
|
134437
134451
|
const month = normalizeMonth(pick(row, ["month", "\u6708\u4EFD", "ym"]), date || void 0);
|
|
134438
134452
|
if (!countryZh && !month) continue;
|
|
134439
134453
|
out.push({
|
|
134440
134454
|
month,
|
|
134441
134455
|
countryZh,
|
|
134442
134456
|
date: date || void 0,
|
|
134443
|
-
product: pick(row, ["product", "\u4EA7\u54C1"]) || void 0,
|
|
134444
|
-
source: pick(row, ["source", "\u5BA2\u6237\u6765\u6E90", "\u6765\u6E90"]) || void 0
|
|
134457
|
+
product: pick(row, ["\u4EA7\u54C1/\u54C1\u7C7B", "product", "\u4EA7\u54C1"]) || void 0,
|
|
134458
|
+
source: pick(row, ["\u8BE2\u76D8\u6765\u6E90\u5173\u952E\u8BCD", "source", "\u5BA2\u6237\u6765\u6E90", "\u6765\u6E90"]) || void 0,
|
|
134459
|
+
quality: pick(row, ["\u8BE2\u76D8\u8D28\u91CF\u5206\u7EA7", "qualityGrade", "quality"]) || void 0
|
|
134445
134460
|
});
|
|
134446
134461
|
}
|
|
134447
134462
|
return out;
|
package/dist/skill/_meta.json
CHANGED
|
@@ -323,9 +323,9 @@
|
|
|
323
323
|
| P1 / P4 / P10 | 账户 ID | 「请提供 Google 广告账户 ID(mediaCustomerId)。」 |
|
|
324
324
|
| P1 / P4 | 时间 | 按 `agent-conventions.md` §五 反问区间 |
|
|
325
325
|
| P10 | 时间 | 季度话术可省略(上一完整季);月度报告 / 下月规划用上一完整月或用户指定月 |
|
|
326
|
-
| P10 | 询盘附件 |
|
|
326
|
+
| P10 | 询盘附件 | **未带表先问「有没有本期询盘表」并等待**;有则先看一眼表头再转 `inquiries.json` 给 `--inquiries`;用户说没有再 collect。**禁止**不问就出报告;**禁止**把 xlsx/csv 原文件传给 collect |
|
|
327
327
|
| P6 | 非 OKKI 话术 | 若用户实际要普通周期报告 → 改 P4 并说明 |
|
|
328
|
-
| P7 | 无询盘文件 |
|
|
328
|
+
| P7 | 无询盘文件 | 贴字段清单,**禁止编造询盘**;用表前先看一眼表头;若用户只要账户级零转化 → 改 **P3** |
|
|
329
329
|
| P3(§零·D) | 时间区间 | 按 `agent-conventions.md` §五 反问;巡检默认近 7 天须写明区间 |
|
|
330
330
|
| W3 | 预算/地域 | 先列待确认项,再进入 campaign-plan 流水线 |
|
|
331
331
|
|
|
@@ -154,7 +154,7 @@
|
|
|
154
154
|
- **时间窗口强约束**:**严格 3 个月** = 分析月份 + 向前 2 个完整自然月,**禁止**扩展到 7 个月。
|
|
155
155
|
- **步骤**:
|
|
156
156
|
1. (可选)Read `subagent-orchestration.md` § P7。
|
|
157
|
-
2. 询盘资料入场:用户附文件 →
|
|
157
|
+
2. 询盘资料入场:用户附文件 → 先看一眼表头再落盘 `./snap-inquiry/inquiries.json`(列名接近即可);仅给账户 ID → 反问账户 + 分析月份并贴字段清单,**禁止编造询盘数据**。
|
|
158
158
|
3. CLI 拉数(同一目录):`list-accounts`、`google-analysis --sections campaigns,keywords,search-terms,campaign-geo`,并按月拉 `m1/m2/m3` 的 `campaigns,geographic`。
|
|
159
159
|
4. 脚本聚合计算 8 Sheet 数据;国家→大洲映射读 `geo-continents.json`,**禁止**硬编码国家名。
|
|
160
160
|
- **产物**:必产 8 Sheet xlsx(版式见模板),**只能**由 Agent 脚本生成,**禁止**假设 `… excel` 子命令存在。
|
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
2. 同时贴出**询盘字段清单 + 1 行示例**,让用户用任意方式补齐再回传:
|
|
45
45
|
|
|
46
46
|
```
|
|
47
|
-
请把近 3 个月({S} ~ {E})的询盘记录回贴或上传(Excel / CSV / 截图 /
|
|
48
|
-
|
|
49
|
-
示例:
|
|
47
|
+
请把近 3 个月({S} ~ {E})的询盘记录回贴或上传(Excel / CSV / 截图 / 文本表格均可),字段如下(* 为必填):
|
|
48
|
+
序号 | 询盘日期* | 询盘来源关键词 | 目标国家/地区* | 产品/品类* | 客户名称/公司 | 联系方式 | 询盘内容摘要 | 询盘质量分级* | 跟进状态 | 是否成交 | 成交金额(USD)
|
|
49
|
+
示例:1 | 2026-04-12 | WhatsApp | 印度 | 滴灌带 | | | | 合格 | | |
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
3. 拿到资料后由宿主 Agent 解析、落盘 `inquiries.json`,再进入「拉数与写 Excel」节。
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
1. **账户**:`mediaCustomerId` 来自 `list-accounts -m Google -k <id>`,**禁止猜 ID**。
|
|
59
59
|
2. **分析月份**:默认**上一个完整自然月**(例:今天 5/13 → 默认 4 月)。用户未明确时**反问**(A) 上月 B) 本月 1 号到昨天 C) 自定义 YYYY-MM)。
|
|
60
60
|
3. **时间窗口(硬约束)**:**严格 3 个月** = 分析月份 + 向前 2 个完整自然月。例:分析月 = 2026-04 → `--start 2026-02-01 --end 2026-04-30`。**所有月度表只展示 3 行**(不延伸到 7 个月)。
|
|
61
|
-
4.
|
|
62
|
-
5. **日期规范化**:`2026.4.1` / `2026/4/1` 等先规范成 `YYYY-MM-DD` 再传 CLI
|
|
61
|
+
4. **用询盘数据前先看一眼表头**。常见列见上;* 表示通常要有对应含义的列(`询盘日期`≈时间/date,`目标国家/地区`≈国家,`产品/品类`≈产品,`询盘质量分级`有则用)。列名接近即可,不必逐格校验。
|
|
62
|
+
5. **日期规范化**:`2026.4.1` / `2026/4/1` 等先规范成 `YYYY-MM-DD` 再传 CLI。`月份` 可由询盘日期推导。
|
|
63
63
|
|
|
64
64
|
---
|
|
65
65
|
|
|
@@ -155,23 +155,30 @@ Sheet 5 整段系列明细读:`./snap-inquiry/campaigns-<accountId>_<S>-<E>.js
|
|
|
155
155
|
```json
|
|
156
156
|
[
|
|
157
157
|
{
|
|
158
|
-
"month": "4月份",
|
|
159
158
|
"seq": 1,
|
|
159
|
+
"date": "2026-04-12",
|
|
160
|
+
"sourceKeyword": "WhatsApp",
|
|
160
161
|
"country": "印度",
|
|
161
|
-
"time": "2026-04-12",
|
|
162
162
|
"product": "滴灌带",
|
|
163
|
-
"
|
|
164
|
-
"
|
|
163
|
+
"company": null,
|
|
164
|
+
"contact": null,
|
|
165
|
+
"summary": null,
|
|
166
|
+
"quality": "合格",
|
|
167
|
+
"followUp": null,
|
|
168
|
+
"won": null,
|
|
169
|
+
"amountUsd": null
|
|
165
170
|
}
|
|
166
171
|
]
|
|
167
172
|
```
|
|
168
173
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
- `
|
|
172
|
-
- `
|
|
173
|
-
- `
|
|
174
|
-
- `
|
|
174
|
+
落盘前先看一眼表头,按含义对上即可(`时间`=`询盘日期`,`国家(中文)`=`目标国家/地区`,`产品`=`产品/品类`)。
|
|
175
|
+
|
|
176
|
+
- `date`:询盘日期,`YYYY-MM-DD`。
|
|
177
|
+
- `country`:目标国家/地区,中文名,与 `countryOrRegionZh` 字典对齐。
|
|
178
|
+
- `product`:产品/品类,Sheet 3 产品分桶。
|
|
179
|
+
- `sourceKeyword` / `source`:来源,Sheet 3 来源分桶(可空)。
|
|
180
|
+
- `quality` / 其余可选列:有则写入,没有就空着。
|
|
181
|
+
- `month`:可由 `date` 推导。**禁止编造**缺失值。
|
|
175
182
|
|
|
176
183
|
---
|
|
177
184
|
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
| 5 | `keywords` | 关键词与搜索主题 | Search 分组 + 匹配 + 否词方向;有 PMax 则 Search Themes |
|
|
34
34
|
| 6 | `audience` | 受众规划 | Audience Signal / 名单 / 再营销;没有的标「需创建或导入」 |
|
|
35
35
|
| 7 | `creative` | 素材与落地页 | 主题、资产缺口、测试假设(每轮 1~2 变量)、广告↔页面映射 |
|
|
36
|
-
| 8 | `roadmap` | 季度执行路线图 |
|
|
36
|
+
| 8 | `roadmap` | 季度执行路线图 | 第一个月 / 第二个月 / 第三个月:任务、交付物、完成条件、依赖 |
|
|
37
37
|
| 9 | `risks` | 风险与待确认 | 预算、数据、素材、页面、销售承接、合规;假设清单 |
|
|
38
38
|
|
|
39
39
|
每条结论前加口径标签之一:`已确认` / `基于历史数据` / `建议验证` / `待业务确认`。
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"keywords": { "analysis": ["产品词精确/词组…", "否词方向:求职/教程/免费"] },
|
|
49
49
|
"audience": { "analysis": ["待业务确认:客户名单未导入"] },
|
|
50
50
|
"creative": { "analysis": ["主题:工业场景…", "缺口:PMax 视频"] },
|
|
51
|
-
"roadmap": { "analysis": ["
|
|
51
|
+
"roadmap": { "analysis": ["第一个月:目标与基础…", "第二个月:核心建设…", "第三个月:已验证方向扩"] },
|
|
52
52
|
"risks": { "analysis": ["销售回传缺失 → 主目标暂用表单并标注"] }
|
|
53
53
|
}
|
|
54
54
|
}
|
|
@@ -104,7 +104,7 @@ CPA、询盘目标**不**从历史外推。要写数字须用户给,或标「
|
|
|
104
104
|
| Q23 | 广告↔页 | 每个核心主题至少一个明确页面方向。禁止广告讲 A、页面展 B |
|
|
105
105
|
| Q24 | 转化路径 | CTA、表单字段、感谢页、电话/WhatsApp/邮件、CRM 回传、销售跟进 |
|
|
106
106
|
| Q25 | 销售承接 | 接收人、响应时效、分配、无效反馈、结果回传。无承接则降低扩量优先级 |
|
|
107
|
-
| Q26 | 三月节奏 |
|
|
107
|
+
| Q26 | 三月节奏 | 见下表。写「第一个月 / 第二个月 / 第三个月」,禁止写「第1月」(会被读成 1 月 / 2 月 / 3 月)。能从本期结束日推下期日历月时写成「第一个月(10月)」。月度报告改成「本月 / 次月 / 再次月」 |
|
|
108
108
|
| Q27 | 依赖 | 每项关键规划标依赖、负责人或待确认 |
|
|
109
109
|
| Q28 | 风险 | 至少覆盖:预算不足、转化量不足、数据质量、落地页未完成、素材不足、销售承接、市场合规 |
|
|
110
110
|
| Q29 | 假设 | 假设不得写成事实;用四类口径标签 |
|
|
@@ -114,9 +114,9 @@ CPA、询盘目标**不**从历史外推。要写数字须用户给,或标「
|
|
|
114
114
|
|
|
115
115
|
| 阶段 | 核心任务 | 交付 | 完成条件 |
|
|
116
116
|
| ---- | -------- | ---- | -------- |
|
|
117
|
-
|
|
|
118
|
-
|
|
|
119
|
-
|
|
|
117
|
+
| 第一个月 · 基础与验证 | 目标、预算、市场优先级;补转化追踪、落地页、素材、受众 | 目标表、预算表、Campaign 结构、词/Themes、素材与页面清单 | 核心投放基础具备,关键依赖写清 |
|
|
118
|
+
| 第二个月 · 重点建设 | 核心市场与核心类型;有限变量测试 | 核心 Campaign、素材测试批次、受众组合、页面优化版 | 核心方向验证完,形成可续投项目 |
|
|
119
|
+
| 第三个月 · 扩展与沉淀 | 只围已验证方向扩市场/预算/词/素材/受众 | 扩展计划、下季建议、有效资产、未完成项 | 可扩展方向和下季待解决问题都明确 |
|
|
120
120
|
|
|
121
121
|
## 硬约束
|
|
122
122
|
|
|
@@ -24,21 +24,22 @@ CLI **不读** xlsx / csv / 截图。
|
|
|
24
24
|
|
|
25
25
|
**禁止**把原始 `.xlsx` / `.csv` 传给 `--inquiries`(会 `JSON.parse` 失败)。用户说没有:可 `--inquiry-conversion <转化动作名>`(须用户点名);再没有则询盘位留空并脚注。**禁止编造询盘行。**
|
|
26
26
|
|
|
27
|
-
落盘 JSON:根为数组或 `{ "items": [...] }
|
|
27
|
+
落盘 JSON:根为数组或 `{ "items": [...] }`。**用之前先看一眼表头**,有日期/国家/产品这类列即可(列名接近即可,如 `时间`=`询盘日期`)。**禁止编造**。
|
|
28
28
|
|
|
29
|
-
| 用途 |
|
|
29
|
+
| 用途 | 常见键 | 归一 |
|
|
30
30
|
| ---- | -------- | ---- |
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
31
|
+
| 询盘日期 | `询盘日期` / `date` / `时间` / `time` | `YYYY-MM-DD`;Excel 序列号由 Agent 转好 |
|
|
32
|
+
| 目标国家/地区 | `目标国家/地区` / `国家(中文)` / `国家` / `country` / `countryZh` | 英文/缩写先译中文,与 geographic `countryNameZh` 对齐 |
|
|
33
|
+
| 产品/品类 | `产品/品类` / `产品` / `product` | 自由文本 |
|
|
34
|
+
| 询盘来源关键词 | `询盘来源关键词` / `客户来源` / `来源` / `source` | 可选 |
|
|
35
|
+
| 询盘质量分级 | `询盘质量分级` / `quality` / `qualityGrade` | 有则用 |
|
|
36
|
+
| 月份 | `月份` / `month` / `ym` | 可由询盘日期推导 |
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
样例:
|
|
38
39
|
|
|
39
40
|
```json
|
|
40
41
|
[
|
|
41
|
-
{ "
|
|
42
|
+
{ "询盘日期": "2026-04-12", "目标国家/地区": "印度", "产品/品类": "协作机器人", "询盘来源关键词": "WhatsApp" }
|
|
42
43
|
]
|
|
43
44
|
```
|
|
44
45
|
|
|
@@ -111,7 +112,7 @@ Agent JSON Schema:`assets/google-quarterly-report.schema.json`。
|
|
|
111
112
|
"keywords": { "analysis": ["产品词精确/词组;否词:求职/教程"] },
|
|
112
113
|
"audience": { "analysis": ["待业务确认:客户名单未导入"] },
|
|
113
114
|
"creative": { "analysis": ["主题:工业场景;缺口:PMax 视频"] },
|
|
114
|
-
"roadmap": { "analysis": ["
|
|
115
|
+
"roadmap": { "analysis": ["第一个月基础验证;第二个月核心建设;第三个月已验证方向扩"] },
|
|
115
116
|
"risks": { "analysis": ["销售回传缺失"] }
|
|
116
117
|
}
|
|
117
118
|
}
|
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
2. 同时贴出**询盘字段清单 + 1 行示例**,让用户用任意方式补齐再回传:
|
|
45
45
|
|
|
46
46
|
```
|
|
47
|
-
请把近 3 个月({S} ~ {E})的询盘记录回贴或上传(Excel / CSV / 截图 /
|
|
48
|
-
|
|
49
|
-
示例:
|
|
47
|
+
请把近 3 个月({S} ~ {E})的询盘记录回贴或上传(Excel / CSV / 截图 / 文本表格均可),字段如下(* 为必填):
|
|
48
|
+
序号 | 询盘日期* | 询盘来源关键词 | 目标国家/地区* | 产品/品类* | 客户名称/公司 | 联系方式 | 询盘内容摘要 | 询盘质量分级* | 跟进状态 | 是否成交 | 成交金额(USD)
|
|
49
|
+
示例:1 | 2026-04-12 | WhatsApp | 印度 | 滴灌带 | | | | 合格 | | |
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
3. 拿到资料后由宿主 Agent 解析、落盘 `inquiries.json`,再进入「拉数与写 Excel」节。
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
1. **账户**:`mediaCustomerId` 来自 `list-accounts -m Google -k <id>`,**禁止猜 ID**。
|
|
59
59
|
2. **分析月份**:默认**上一个完整自然月**(例:今天 5/13 → 默认 4 月)。用户未明确时**反问**(A) 上月 B) 本月 1 号到昨天 C) 自定义 YYYY-MM)。
|
|
60
60
|
3. **时间窗口(硬约束)**:**严格 3 个月** = 分析月份 + 向前 2 个完整自然月。例:分析月 = 2026-04 → `--start 2026-02-01 --end 2026-04-30`。**所有月度表只展示 3 行**(不延伸到 7 个月)。
|
|
61
|
-
4.
|
|
62
|
-
5. **日期规范化**:`2026.4.1` / `2026/4/1` 等先规范成 `YYYY-MM-DD` 再传 CLI
|
|
61
|
+
4. **用询盘数据前先看一眼表头**。常见列见上;* 表示通常要有对应含义的列(`询盘日期`≈时间/date,`目标国家/地区`≈国家,`产品/品类`≈产品,`询盘质量分级`有则用)。列名接近即可,不必逐格校验。
|
|
62
|
+
5. **日期规范化**:`2026.4.1` / `2026/4/1` 等先规范成 `YYYY-MM-DD` 再传 CLI。`月份` 可由询盘日期推导。
|
|
63
63
|
|
|
64
64
|
---
|
|
65
65
|
|
|
@@ -155,23 +155,30 @@ Sheet 5 整段系列明细读:`./snap-inquiry/campaigns-<accountId>_<S>-<E>.js
|
|
|
155
155
|
```json
|
|
156
156
|
[
|
|
157
157
|
{
|
|
158
|
-
"month": "4月份",
|
|
159
158
|
"seq": 1,
|
|
159
|
+
"date": "2026-04-12",
|
|
160
|
+
"sourceKeyword": "WhatsApp",
|
|
160
161
|
"country": "印度",
|
|
161
|
-
"time": "2026-04-12",
|
|
162
162
|
"product": "滴灌带",
|
|
163
|
-
"
|
|
164
|
-
"
|
|
163
|
+
"company": null,
|
|
164
|
+
"contact": null,
|
|
165
|
+
"summary": null,
|
|
166
|
+
"quality": "合格",
|
|
167
|
+
"followUp": null,
|
|
168
|
+
"won": null,
|
|
169
|
+
"amountUsd": null
|
|
165
170
|
}
|
|
166
171
|
]
|
|
167
172
|
```
|
|
168
173
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
- `
|
|
172
|
-
- `
|
|
173
|
-
- `
|
|
174
|
-
- `
|
|
174
|
+
落盘前先看一眼表头,按含义对上即可(`时间`=`询盘日期`,`国家(中文)`=`目标国家/地区`,`产品`=`产品/品类`)。
|
|
175
|
+
|
|
176
|
+
- `date`:询盘日期,`YYYY-MM-DD`。
|
|
177
|
+
- `country`:目标国家/地区,中文名,与 `countryOrRegionZh` 字典对齐。
|
|
178
|
+
- `product`:产品/品类,Sheet 3 产品分桶。
|
|
179
|
+
- `sourceKeyword` / `source`:来源,Sheet 3 来源分桶(可空)。
|
|
180
|
+
- `quality` / 其余可选列:有则写入,没有就空着。
|
|
181
|
+
- `month`:可由 `date` 推导。**禁止编造**缺失值。
|
|
175
182
|
|
|
176
183
|
---
|
|
177
184
|
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
| 5 | `keywords` | 关键词与搜索主题 | Search 分组 + 匹配 + 否词方向;有 PMax 则 Search Themes |
|
|
34
34
|
| 6 | `audience` | 受众规划 | Audience Signal / 名单 / 再营销;没有的标「需创建或导入」 |
|
|
35
35
|
| 7 | `creative` | 素材与落地页 | 主题、资产缺口、测试假设(每轮 1~2 变量)、广告↔页面映射 |
|
|
36
|
-
| 8 | `roadmap` | 季度执行路线图 |
|
|
36
|
+
| 8 | `roadmap` | 季度执行路线图 | 第一个月 / 第二个月 / 第三个月:任务、交付物、完成条件、依赖 |
|
|
37
37
|
| 9 | `risks` | 风险与待确认 | 预算、数据、素材、页面、销售承接、合规;假设清单 |
|
|
38
38
|
|
|
39
39
|
每条结论前加口径标签之一:`已确认` / `基于历史数据` / `建议验证` / `待业务确认`。
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"keywords": { "analysis": ["产品词精确/词组…", "否词方向:求职/教程/免费"] },
|
|
49
49
|
"audience": { "analysis": ["待业务确认:客户名单未导入"] },
|
|
50
50
|
"creative": { "analysis": ["主题:工业场景…", "缺口:PMax 视频"] },
|
|
51
|
-
"roadmap": { "analysis": ["
|
|
51
|
+
"roadmap": { "analysis": ["第一个月:目标与基础…", "第二个月:核心建设…", "第三个月:已验证方向扩"] },
|
|
52
52
|
"risks": { "analysis": ["销售回传缺失 → 主目标暂用表单并标注"] }
|
|
53
53
|
}
|
|
54
54
|
}
|
|
@@ -104,7 +104,7 @@ CPA、询盘目标**不**从历史外推。要写数字须用户给,或标「
|
|
|
104
104
|
| Q23 | 广告↔页 | 每个核心主题至少一个明确页面方向。禁止广告讲 A、页面展 B |
|
|
105
105
|
| Q24 | 转化路径 | CTA、表单字段、感谢页、电话/WhatsApp/邮件、CRM 回传、销售跟进 |
|
|
106
106
|
| Q25 | 销售承接 | 接收人、响应时效、分配、无效反馈、结果回传。无承接则降低扩量优先级 |
|
|
107
|
-
| Q26 | 三月节奏 |
|
|
107
|
+
| Q26 | 三月节奏 | 见下表。写「第一个月 / 第二个月 / 第三个月」,禁止写「第1月」(会被读成 1 月 / 2 月 / 3 月)。能从本期结束日推下期日历月时写成「第一个月(10月)」。月度报告改成「本月 / 次月 / 再次月」 |
|
|
108
108
|
| Q27 | 依赖 | 每项关键规划标依赖、负责人或待确认 |
|
|
109
109
|
| Q28 | 风险 | 至少覆盖:预算不足、转化量不足、数据质量、落地页未完成、素材不足、销售承接、市场合规 |
|
|
110
110
|
| Q29 | 假设 | 假设不得写成事实;用四类口径标签 |
|
|
@@ -114,9 +114,9 @@ CPA、询盘目标**不**从历史外推。要写数字须用户给,或标「
|
|
|
114
114
|
|
|
115
115
|
| 阶段 | 核心任务 | 交付 | 完成条件 |
|
|
116
116
|
| ---- | -------- | ---- | -------- |
|
|
117
|
-
|
|
|
118
|
-
|
|
|
119
|
-
|
|
|
117
|
+
| 第一个月 · 基础与验证 | 目标、预算、市场优先级;补转化追踪、落地页、素材、受众 | 目标表、预算表、Campaign 结构、词/Themes、素材与页面清单 | 核心投放基础具备,关键依赖写清 |
|
|
118
|
+
| 第二个月 · 重点建设 | 核心市场与核心类型;有限变量测试 | 核心 Campaign、素材测试批次、受众组合、页面优化版 | 核心方向验证完,形成可续投项目 |
|
|
119
|
+
| 第三个月 · 扩展与沉淀 | 只围已验证方向扩市场/预算/词/素材/受众 | 扩展计划、下季建议、有效资产、未完成项 | 可扩展方向和下季待解决问题都明确 |
|
|
120
120
|
|
|
121
121
|
## 硬约束
|
|
122
122
|
|
|
@@ -247,11 +247,10 @@
|
|
|
247
247
|
.bcell .n { font-size: 13px; color: var(--text-2); margin-top: 4px; }
|
|
248
248
|
.closing {
|
|
249
249
|
text-align: center; background: #fff; border: 1px solid var(--line-light);
|
|
250
|
-
border-radius: var(--radius-lg); padding: 56px 24px; margin: 20px 0
|
|
250
|
+
border-radius: var(--radius-lg); padding: 56px 24px; margin: 20px 0 24px; box-shadow: var(--shadow);
|
|
251
251
|
}
|
|
252
252
|
.closing h2 { margin: 0 0 10px; font-size: 36px; font-weight: 600; }
|
|
253
253
|
.closing p { margin: 0; color: var(--text-3); font-size: 13px; }
|
|
254
|
-
.footnote { text-align: center; color: var(--text-3); font-size: 12px; padding: 12px 0 24px; }
|
|
255
254
|
.hidden { display: none !important; }
|
|
256
255
|
@media print { .topnav { display: none; } .page, .chapter, .cover { break-inside: avoid; box-shadow: none; } }
|
|
257
256
|
</style>
|
|
@@ -332,6 +331,20 @@
|
|
|
332
331
|
return `${String(range.start).slice(0, 10)} ~ ${String(range.end).slice(0, 10)}`;
|
|
333
332
|
}
|
|
334
333
|
|
|
334
|
+
/** 下期三个月:写「第一个月」而不是「第1月」,避免被读成 1 月 / 2 月 / 3 月。 */
|
|
335
|
+
function nextPeriodMonthLabels(current) {
|
|
336
|
+
const base = ["第一个月", "第二个月", "第三个月"];
|
|
337
|
+
const end = current && current.end;
|
|
338
|
+
const match = typeof end === "string" ? /^(\d{4})-(\d{2})-(\d{2})$/.exec(end.trim()) : null;
|
|
339
|
+
if (!match) return base;
|
|
340
|
+
let month = Number(match[2]);
|
|
341
|
+
return base.map((label) => {
|
|
342
|
+
month += 1;
|
|
343
|
+
if (month > 12) month = 1;
|
|
344
|
+
return `${label}(${month}月)`;
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
|
|
335
348
|
function ellipsis(text, max) {
|
|
336
349
|
const s = String(text ?? "").trim();
|
|
337
350
|
return s.length > max ? s.slice(0, max) + "…" : s;
|
|
@@ -492,7 +505,7 @@
|
|
|
492
505
|
<div class="bcell"><div class="p">${money(planDefaults.spendLow, currency)}</div><div class="n">建议档 +30%</div></div>
|
|
493
506
|
<div class="bcell"><div class="p">${money(planDefaults.spendHigh, currency)}</div><div class="n">扩量档 +50%</div></div>
|
|
494
507
|
</div>
|
|
495
|
-
${monthSplitTable(planDefaults, currency)}
|
|
508
|
+
${monthSplitTable(planDefaults, currency, meta.current)}
|
|
496
509
|
</div>
|
|
497
510
|
<div class="plan-stack">${planChapters(plan)}</div>
|
|
498
511
|
</section>
|
|
@@ -500,7 +513,6 @@
|
|
|
500
513
|
<h2>谢谢</h2>
|
|
501
514
|
<p>${esc(name)} · ${esc(periodLabel(meta.current))}</p>
|
|
502
515
|
</section>
|
|
503
|
-
<p class="footnote">${esc(name)} · ${esc(periodLabel(meta.current))}</p>
|
|
504
516
|
`;
|
|
505
517
|
|
|
506
518
|
const months = data.monthly || [];
|
|
@@ -858,17 +870,18 @@
|
|
|
858
870
|
return `<div class="plan-card"><div class="tag">${esc(title)}</div><ul>${items.map((x) => `<li>${esc(x)}</li>`).join("")}</ul></div>`;
|
|
859
871
|
}
|
|
860
872
|
|
|
861
|
-
function monthSplitTable(defaults, currency) {
|
|
873
|
+
function monthSplitTable(defaults, currency, current) {
|
|
862
874
|
const months = defaults && defaults.monthSuggested;
|
|
863
875
|
if (!Array.isArray(months) || months.length < 3) return "";
|
|
864
876
|
const shares = (defaults.monthShares || [0.3, 0.35, 0.35]).map((n) => Math.round(Number(n) * 100) + "%");
|
|
877
|
+
const labels = nextPeriodMonthLabels(current);
|
|
865
878
|
return `<h3 class="st">建议档月度拆分</h3>
|
|
866
879
|
<div class="table-wrap"><table class="data compact">
|
|
867
|
-
<thead><tr><th
|
|
880
|
+
<thead><tr><th>下期月份</th><th class="num">占比</th><th class="num">建议花费</th></tr></thead>
|
|
868
881
|
<tbody>
|
|
869
|
-
<tr><td
|
|
870
|
-
<tr><td
|
|
871
|
-
<tr><td
|
|
882
|
+
<tr><td>${esc(labels[0])}</td><td class="num">${shares[0] || "30%"}</td><td class="num">${money(months[0], currency)}</td></tr>
|
|
883
|
+
<tr><td>${esc(labels[1])}</td><td class="num">${shares[1] || "35%"}</td><td class="num">${money(months[1], currency)}</td></tr>
|
|
884
|
+
<tr><td>${esc(labels[2])}</td><td class="num">${shares[2] || "35%"}</td><td class="num">${money(months[2], currency)}</td></tr>
|
|
872
885
|
</tbody>
|
|
873
886
|
</table></div>`;
|
|
874
887
|
}
|
|
@@ -24,21 +24,22 @@ CLI **不读** xlsx / csv / 截图。
|
|
|
24
24
|
|
|
25
25
|
**禁止**把原始 `.xlsx` / `.csv` 传给 `--inquiries`(会 `JSON.parse` 失败)。用户说没有:可 `--inquiry-conversion <转化动作名>`(须用户点名);再没有则询盘位留空并脚注。**禁止编造询盘行。**
|
|
26
26
|
|
|
27
|
-
落盘 JSON:根为数组或 `{ "items": [...] }
|
|
27
|
+
落盘 JSON:根为数组或 `{ "items": [...] }`。**用之前先看一眼表头**,有日期/国家/产品这类列即可(列名接近即可,如 `时间`=`询盘日期`)。**禁止编造**。
|
|
28
28
|
|
|
29
|
-
| 用途 |
|
|
29
|
+
| 用途 | 常见键 | 归一 |
|
|
30
30
|
| ---- | -------- | ---- |
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
31
|
+
| 询盘日期 | `询盘日期` / `date` / `时间` / `time` | `YYYY-MM-DD`;Excel 序列号由 Agent 转好 |
|
|
32
|
+
| 目标国家/地区 | `目标国家/地区` / `国家(中文)` / `国家` / `country` / `countryZh` | 英文/缩写先译中文,与 geographic `countryNameZh` 对齐 |
|
|
33
|
+
| 产品/品类 | `产品/品类` / `产品` / `product` | 自由文本 |
|
|
34
|
+
| 询盘来源关键词 | `询盘来源关键词` / `客户来源` / `来源` / `source` | 可选 |
|
|
35
|
+
| 询盘质量分级 | `询盘质量分级` / `quality` / `qualityGrade` | 有则用 |
|
|
36
|
+
| 月份 | `月份` / `month` / `ym` | 可由询盘日期推导 |
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
样例:
|
|
38
39
|
|
|
39
40
|
```json
|
|
40
41
|
[
|
|
41
|
-
{ "
|
|
42
|
+
{ "询盘日期": "2026-04-12", "目标国家/地区": "印度", "产品/品类": "协作机器人", "询盘来源关键词": "WhatsApp" }
|
|
42
43
|
]
|
|
43
44
|
```
|
|
44
45
|
|
|
@@ -111,7 +112,7 @@ Agent JSON Schema:`assets/google-quarterly-report.schema.json`。
|
|
|
111
112
|
"keywords": { "analysis": ["产品词精确/词组;否词:求职/教程"] },
|
|
112
113
|
"audience": { "analysis": ["待业务确认:客户名单未导入"] },
|
|
113
114
|
"creative": { "analysis": ["主题:工业场景;缺口:PMax 视频"] },
|
|
114
|
-
"roadmap": { "analysis": ["
|
|
115
|
+
"roadmap": { "analysis": ["第一个月基础验证;第二个月核心建设;第三个月已验证方向扩"] },
|
|
115
116
|
"risks": { "analysis": ["销售回传缺失"] }
|
|
116
117
|
}
|
|
117
118
|
}
|
|
@@ -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.53-beta.
|
|
12
|
+
$PKG_VERSION = '1.1.53-beta.5'
|
|
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.53-beta.
|
|
12
|
+
readonly PKG_VERSION="1.1.53-beta.5"
|
|
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"
|