siluzan-tso-cli 1.1.26-beta.2 → 1.1.26
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 -2
- package/dist/index.js +1 -1
- package/dist/skill/SKILL.md +1 -1
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/README.md +1 -1
- package/dist/skill/references/accounts/accounts.md +3 -3
- package/dist/skill/references/accounts/finance.md +32 -32
- package/dist/skill/references/accounts/open-account-google-ui.md +1 -1
- package/dist/skill/references/analytics/rag.md +1 -1
- package/dist/skill/references/analytics/reporting.md +5 -5
- package/dist/skill/references/core/agent-conventions.md +2 -2
- package/dist/skill/references/core/deliverable-preflight.md +66 -67
- package/dist/skill/references/core/playbooks.md +2 -2
- package/dist/skill/references/core/setup.md +5 -5
- package/dist/skill/references/core/skill-authoring.md +1 -1
- package/dist/skill/references/core/workflows.md +4 -4
- package/dist/skill/references/misc/tso-home.md +2 -2
- package/dist/skill/report-templates/REPORT-WORKFLOW.md +4 -4
- package/dist/skill/scripts/install.ps1 +3 -3
- package/dist/skill/scripts/install.sh +3 -3
- package/package.json +1 -1
- package/dist/skill/scripts/check-deliverable-snap.mjs +0 -170
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ HTML 报告模板引用以下 CDN:`cdn.tailwindcss.com`、`cdnjs.cloudflare.co
|
|
|
43
43
|
在**用户的目标项目根目录**执行(根据用户使用的助手选择 `--ai`):
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
npm install -g siluzan-tso-cli
|
|
46
|
+
npm install -g siluzan-tso-cli
|
|
47
47
|
siluzan-tso init --ai cursor # 写入 Cursor(默认)
|
|
48
48
|
siluzan-tso init --ai cursor,claude # 同时写入多个平台
|
|
49
49
|
siluzan-tso init --ai all # 写入所有支持的平台
|
|
@@ -51,7 +51,6 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
|
|
|
51
51
|
siluzan-tso init --force # 强制覆盖已存在文件
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
> **注意**:当前为测试版(1.1.26-beta.2),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
|
|
55
54
|
|
|
56
55
|
| 助手 | 建议 `--ai` |
|
|
57
56
|
| ----------------------- | ------------------------------------ |
|
package/dist/index.js
CHANGED
package/dist/skill/SKILL.md
CHANGED
|
@@ -17,7 +17,7 @@ allowed-tools: Bash(siluzan-tso:*) Read Write
|
|
|
17
17
|
|
|
18
18
|
> **Agent 纪律(每个新任务必读)**:Read `references/core/agent-conventions.md`,再按 `SKILL.md` 任务表 Read 域文档。禁止跨话题复用参数记忆;数据类任务一律 `--json-out` + **仅用代码**读落盘 JSON(见 `references/core/tips.md`)——**禁止**用 Read 工具打开 `writtenFiles` 里的完整 `*.json`。
|
|
19
19
|
>
|
|
20
|
-
> **报告/Excel 交付前**:Read `references/core/deliverable-preflight.md
|
|
20
|
+
> **报告/Excel 交付前**:Read `references/core/deliverable-preflight.md`,**Read 最终产物**并按自检表确认币种与章节完整;币种只认当次 `list-accounts` 的 `currencyCode`。
|
|
21
21
|
>
|
|
22
22
|
> **开户**:首次进入开户话题须先向用户罗列该媒体(或未指明媒体时六平台)**全部必填项**,见 `references/accounts/open-account-by-media.md` §「首次响应硬规范」。
|
|
23
23
|
>
|
package/dist/skill/_meta.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
| `core/setup.md` | 安装、登录(手机验证码优先)、配置、更新 |
|
|
10
10
|
| `core/agent-conventions.md` | **Agent 必读**:加载纪律、硬规范、数据转换、时间/币种/批量 |
|
|
11
11
|
| `core/tips.md` | `--json-out` 协议、outline→脚本读 JSON |
|
|
12
|
-
| `core/deliverable-preflight.md` |
|
|
12
|
+
| `core/deliverable-preflight.md` | **交付前审阅最终产物**:Agent Read 报告文件并对照自检表(币种/章节) |
|
|
13
13
|
| `core/playbooks.md` | P1–P7 高频任务标准动作 |
|
|
14
14
|
| `core/workflows.md` | 多命令串联业务流程 |
|
|
15
15
|
| `core/skill-authoring.md` | Skill 文档维护最佳实践(维护者) |
|
|
@@ -257,7 +257,7 @@ siluzan-tso account-history --start 2026-03-01 --end 2026-03-31 --json-out ./sna
|
|
|
257
257
|
| 状态 | 含义 | 下一步操作 |
|
|
258
258
|
| ---------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
259
259
|
| `Pending` | 审核中 | 等待,可反复运行此命令轮询;审核周期因媒体而异 |
|
|
260
|
-
| `Approved` | 审核通过 | 运行 `list-accounts -m <媒体>` 确认账户已出现;引导用户充值激活(`config show` 取 `webUrl`,按 `finance.md` 打开对应媒体充值页;例如 Google 为 `https://www
|
|
260
|
+
| `Approved` | 审核通过 | 运行 `list-accounts -m <媒体>` 确认账户已出现;引导用户充值激活(`config show` 取 `webUrl`,按 `finance.md` 打开对应媒体充值页;例如 Google 为 `https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google`;Kwai、Yandex 当前没有对应充值界面) |
|
|
261
261
|
| `Rejected` | 被拒 | 查看 `--json-out` 落盘中的 `reason` 字段了解拒绝原因;修改资料后重新提交;若原因不明,引导用户联系丝路赞客服 |
|
|
262
262
|
|
|
263
263
|
---
|
|
@@ -810,7 +810,7 @@ siluzan-tso account email-deauth -c <mediaCustomerId> --invitation-id <id> --res
|
|
|
810
810
|
|
|
811
811
|
| 功能 | 媒体 | 网页路径 |
|
|
812
812
|
| --------------------------------------- | ------ | ---------------------------------------------- |
|
|
813
|
-
| **账户激活**(邀请他人激活 / 充值激活) | Google | `https://www
|
|
813
|
+
| **账户激活**(邀请他人激活 / 充值激活) | Google | `https://www.siluzan.com/v3/foreign_trade/tso/manageAccounts` |
|
|
814
814
|
|
|
815
815
|
**Agent 建议话术**:
|
|
816
816
|
|
|
@@ -819,5 +819,5 @@ siluzan-tso account email-deauth -c <mediaCustomerId> --invitation-id <id> --res
|
|
|
819
819
|
siluzan-tso config show # 查看 webUrl 字段
|
|
820
820
|
|
|
821
821
|
# 账户激活(Google)→ 引导至账户管理页
|
|
822
|
-
# https://www
|
|
822
|
+
# https://www.siluzan.com/v3/foreign_trade/tso/manageAccounts
|
|
823
823
|
```
|
|
@@ -121,10 +121,10 @@ siluzan-tso config show
|
|
|
121
121
|
|
|
122
122
|
| 媒体 | `mediaType` 参数 | 传统充值/现金充值链接 |
|
|
123
123
|
| ---- | ---------------- | ------------ |
|
|
124
|
-
| Google | `Google` | `https://www
|
|
125
|
-
| TikTok | `TikTok` | `https://www
|
|
126
|
-
| Meta / Facebook | `MetaAd` | `https://www
|
|
127
|
-
| Microsoft / Bing | `MicrosoftAd` | `https://www
|
|
124
|
+
| Google | `Google` | `https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google` |
|
|
125
|
+
| TikTok | `TikTok` | `https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=TikTok` |
|
|
126
|
+
| Meta / Facebook | `MetaAd` | `https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=MetaAd` |
|
|
127
|
+
| Microsoft / Bing | `MicrosoftAd` | `https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=MicrosoftAd` |
|
|
128
128
|
|
|
129
129
|
> Yandex、Kwai 当前没有传统充值/现金充值界面;用户询问这些媒体充值时,不要拼接充值页链接,应说明当前网页不提供对应充值入口,并建议联系丝路赞客服或业务负责人确认处理方式。
|
|
130
130
|
|
|
@@ -132,8 +132,8 @@ siluzan-tso config show
|
|
|
132
132
|
|
|
133
133
|
| 媒体 | 批量充值链接 |
|
|
134
134
|
| ---- | ------------ |
|
|
135
|
-
| Google | `https://www
|
|
136
|
-
| TikTok | `https://www
|
|
135
|
+
| Google | `https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay_batch?mediaType=Google` |
|
|
136
|
+
| TikTok | `https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay_batch?mediaType=TikTok` |
|
|
137
137
|
|
|
138
138
|
> Meta、Microsoft/Bing、Yandex、Kwai 当前不要引导到批量充值页。
|
|
139
139
|
|
|
@@ -141,10 +141,10 @@ siluzan-tso config show
|
|
|
141
141
|
|
|
142
142
|
| 媒体 | 月结充值链接 |
|
|
143
143
|
| ---- | ------------ |
|
|
144
|
-
| Google | `https://www
|
|
145
|
-
| TikTok | `https://www
|
|
146
|
-
| Meta / Facebook | `https://www
|
|
147
|
-
| Microsoft / Bing | `https://www
|
|
144
|
+
| Google | `https://www.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=Google` |
|
|
145
|
+
| TikTok | `https://www.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=TikTok` |
|
|
146
|
+
| Meta / Facebook | `https://www.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=MetaAd` |
|
|
147
|
+
| Microsoft / Bing | `https://www.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=MicrosoftAd` |
|
|
148
148
|
|
|
149
149
|
> Yandex、Kwai 当前不要引导到月结充值页。
|
|
150
150
|
|
|
@@ -155,17 +155,17 @@ siluzan-tso config show
|
|
|
155
155
|
```
|
|
156
156
|
需要进行充值,请访问丝路赞平台对应页面完成操作:
|
|
157
157
|
|
|
158
|
-
- Google 充值: https://www
|
|
159
|
-
- TikTok 充值: https://www
|
|
160
|
-
- Meta 充值: https://www
|
|
161
|
-
- Microsoft/Bing 充值:https://www
|
|
162
|
-
- Google 批量充值: https://www
|
|
163
|
-
- TikTok 批量充值: https://www
|
|
164
|
-
- Google 月结充值: https://www
|
|
165
|
-
- TikTok 月结充值: https://www
|
|
166
|
-
- Meta 月结充值: https://www
|
|
167
|
-
- Microsoft/Bing 月结充值:https://www
|
|
168
|
-
- 丝路赞钱包: https://www
|
|
158
|
+
- Google 充值: https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
|
|
159
|
+
- TikTok 充值: https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=TikTok
|
|
160
|
+
- Meta 充值: https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=MetaAd
|
|
161
|
+
- Microsoft/Bing 充值:https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=MicrosoftAd
|
|
162
|
+
- Google 批量充值: https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay_batch?mediaType=Google
|
|
163
|
+
- TikTok 批量充值: https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay_batch?mediaType=TikTok
|
|
164
|
+
- Google 月结充值: https://www.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=Google
|
|
165
|
+
- TikTok 月结充值: https://www.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=TikTok
|
|
166
|
+
- Meta 月结充值: https://www.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=MetaAd
|
|
167
|
+
- Microsoft/Bing 月结充值:https://www.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=MicrosoftAd
|
|
168
|
+
- 丝路赞钱包: https://www.siluzan.com/v3/foreign_trade/tso/recharge/siluzanWallet
|
|
169
169
|
|
|
170
170
|
Yandex、Kwai 当前没有传统充值/现金充值和月结充值界面,需联系丝路赞客服或业务负责人确认处理方式。
|
|
171
171
|
批量充值当前仅支持 Google 和 TikTok;Meta、Microsoft/Bing、Yandex、Kwai 不要引导到批量充值页。
|
|
@@ -174,17 +174,17 @@ Yandex、Kwai 当前没有传统充值/现金充值和月结充值界面,需
|
|
|
174
174
|
**示例:**
|
|
175
175
|
|
|
176
176
|
```
|
|
177
|
-
- Google 充值:https://www
|
|
178
|
-
- TikTok 充值:https://www
|
|
179
|
-
- Meta 充值:https://www
|
|
180
|
-
- Microsoft/Bing 充值:https://www
|
|
181
|
-
- Google 批量充值:https://www
|
|
182
|
-
- TikTok 批量充值:https://www
|
|
183
|
-
- Google 月结充值:https://www
|
|
184
|
-
- TikTok 月结充值:https://www
|
|
185
|
-
- Meta 月结充值:https://www
|
|
186
|
-
- Microsoft/Bing 月结充值:https://www
|
|
187
|
-
- 丝路赞钱包:https://www
|
|
177
|
+
- Google 充值:https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
|
|
178
|
+
- TikTok 充值:https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=TikTok
|
|
179
|
+
- Meta 充值:https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=MetaAd
|
|
180
|
+
- Microsoft/Bing 充值:https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=MicrosoftAd
|
|
181
|
+
- Google 批量充值:https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay_batch?mediaType=Google
|
|
182
|
+
- TikTok 批量充值:https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay_batch?mediaType=TikTok
|
|
183
|
+
- Google 月结充值:https://www.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=Google
|
|
184
|
+
- TikTok 月结充值:https://www.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=TikTok
|
|
185
|
+
- Meta 月结充值:https://www.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=MetaAd
|
|
186
|
+
- Microsoft/Bing 月结充值:https://www.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=MicrosoftAd
|
|
187
|
+
- 丝路赞钱包:https://www.siluzan.com/v3/foreign_trade/tso/recharge/siluzanWallet
|
|
188
188
|
```
|
|
189
189
|
|
|
190
190
|
---
|
|
@@ -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
|
|
63
|
+
# 审核通过后:config show → https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
---
|
|
@@ -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
|
|
196
|
-
| Google | 小时报(Hourly) | `https://www
|
|
197
|
-
| TikTok | 日报 | `https://www
|
|
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` |
|
|
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
|
|
210
|
+
# webUrl: https://www.siluzan.com
|
|
211
211
|
|
|
212
212
|
# 第三步:拼接链接(Google 日报)
|
|
213
|
-
# https://www
|
|
213
|
+
# https://www.siluzan.com/media-report/publish/rpt_abc123?culture=zh-CN
|
|
214
214
|
```
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
2. 涉及写入/修改/删除的操作必须与用户确认
|
|
38
38
|
3. 按计划执行,说明每步意图
|
|
39
39
|
4. 用成对的读命令复核写入结果;异步任务每 5s 轮询直到完成
|
|
40
|
-
5. **交付前**(报告/Excel/含金额话术):Read `references/core/deliverable-preflight.md
|
|
40
|
+
5. **交付前**(报告/Excel/含金额话术):Read `references/core/deliverable-preflight.md`,**Read 最终产物文件**并按自检表 A/B/C 逐项确认后再发给用户
|
|
41
41
|
6. 全部完成后预测用户下一步操作
|
|
42
42
|
|
|
43
43
|
### 执行模式速查
|
|
@@ -136,7 +136,7 @@
|
|
|
136
136
|
- **符号**:`CNY` → **¥**;`USD` → **$**。多账户按 `currencyCode` 分表,**禁止**跨币种求和。
|
|
137
137
|
- **金额单位统一为「元」**:报告保留 2 位小数。
|
|
138
138
|
- **Google 广告诊断报告**:`report-templates/google-ads-diagnosis.md` § 撰写硬约束 — 每日趋势金额/CPA 必须 2 位小数;每个模块除表格外须有「分析」+「建议」,禁止只贴数据。
|
|
139
|
-
-
|
|
139
|
+
- **交付前审阅产物**:报告/Excel 交付前 Agent **Read 最终文件**并对照 `deliverable-preflight.md` 自检表;未审阅禁止交付。
|
|
140
140
|
- **品牌名优先级**:(1) 用户明确提供 → (2) `list-accounts.mag.advertiserName` → (3) 网址域名占位 `[待确认品牌名]`。**严禁**把英文域名翻译为虚构中文品牌。
|
|
141
141
|
|
|
142
142
|
---
|
|
@@ -1,107 +1,106 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 交付前审阅最终产物(Agent 自检)
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> 用户反馈:产出物常出现**币种错误**、**报告缺章/缺数**。
|
|
4
|
+
> **不靠外部校验脚本**——由 **Agent 在交付用户前,亲自查看已生成的最终文件**(HTML / Markdown / Excel 等),对照清单结论后再发送。
|
|
4
5
|
|
|
5
6
|
---
|
|
6
7
|
|
|
7
|
-
##
|
|
8
|
+
## 原则
|
|
8
9
|
|
|
9
|
-
|
|
|
10
|
-
| ---- |
|
|
11
|
-
|
|
|
12
|
-
|
|
|
10
|
+
| 必须 | 禁止 |
|
|
11
|
+
| ---- | ---- |
|
|
12
|
+
| **Read 最终交付文件**(你刚写出的 `.html` / `.md` 等) | 用 Read 打开 `--json-out` 落盘的业务 `*.json` 来「核对」(见 `tips.md`) |
|
|
13
|
+
| 对照当次 `report-templates/*.md` 章节逐项勾选 | 未打开产物就声称「报告已好」 |
|
|
14
|
+
| 币种与**当次对话**里 `list-accounts` / CLI 表格已确认的 `currencyCode` 一致 | 凭媒体猜 USD;CNY 用 `$` |
|
|
15
|
+
| 缺数据的章节写 `[ 数据不可用:… ]` | 空白章节、编造数字填坑 |
|
|
16
|
+
|
|
17
|
+
拉数阶段仍用 `--json-out` + **代码**读 JSON 生成产物;**审阅阶段**只看**最终产物** + 记忆中的账户元数据(账户 ID、区间、币种),不跑 `check-*.mjs` 类脚本。
|
|
13
18
|
|
|
14
19
|
---
|
|
15
20
|
|
|
16
|
-
##
|
|
21
|
+
## 审阅时机
|
|
17
22
|
|
|
18
|
-
|
|
23
|
+
在以下动作**之后、发给用户之前**:
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
1. 已用脚本/CLI 拉数并生成报告文件(或 Excel)。
|
|
26
|
+
2. 文件已写入磁盘路径(你知道路径)。
|
|
21
27
|
|
|
22
|
-
|
|
23
|
-
siluzan-tso list-accounts -m Google -k <mediaCustomerId> --json-out ./snap
|
|
24
|
-
node -e "
|
|
25
|
-
const d=require('./snap/list-accounts-google.json');
|
|
26
|
-
const ma=(d.items||[]).map(x=>x.ma||x).find(m=>String(m.mediaCustomerId)===process.argv[1]);
|
|
27
|
-
if(!ma){console.error('账户未找到');process.exit(1);}
|
|
28
|
-
console.log(ma.currencyCode, ma.mediaCustomerName);
|
|
29
|
-
" <mediaCustomerId>
|
|
30
|
-
```
|
|
28
|
+
**然后必须 Read 该文件**(或 Excel 时对用户说明各 Sheet 名称与首行摘要——若无法 Read 二进制 xlsx,须在对话中贴出**自检表**逐条勾选,并说明依据来自生成脚本的 stdout 摘要,而非猜)。
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
- 首行必须有:`统计区间:YYYY-MM-DD ~ YYYY-MM-DD(货币:CNY|USD)`。
|
|
34
|
-
- 符号:**CNY → ¥**,**USD → $**。详见 `references/accounts/currency.md`。
|
|
30
|
+
---
|
|
35
31
|
|
|
36
|
-
|
|
32
|
+
## 自检表 A · 币种(每条必勾)
|
|
37
33
|
|
|
38
|
-
|
|
39
|
-
- 拉数后打开 **`manifest-<accountId>.json`**(用脚本 `JSON.parse`,勿 Read 整份若很大),核对 `artifacts[].section` 与模板一致。
|
|
34
|
+
对照 `references/accounts/currency.md`:
|
|
40
35
|
|
|
41
|
-
|
|
36
|
+
- [ ] 报告**封面/首行**含 `统计区间:…(货币:CNY)` 或 `(货币:USD)`(或等价英文标注)
|
|
37
|
+
- [ ] 代码与**一致**:`CNY` → 全文金额用 **¥**;`USD` → **$**;未混用
|
|
38
|
+
- [ ] 与当次 `list-accounts -k …` 得到的 **`currencyCode` 相同**(回顾对话中 CLI 表格或你记录的「币种」一行)
|
|
39
|
+
- [ ] 多账户报告:分币种分表,**无** CNY+USD 直接相加的一行「总计」
|
|
40
|
+
- [ ] 未出现「Google 账户所以是美金」类表述
|
|
42
41
|
|
|
43
|
-
|
|
42
|
+
**不通过** → 改产物文件后**重新 Read** 再审,不得交付。
|
|
44
43
|
|
|
45
|
-
|
|
44
|
+
---
|
|
46
45
|
|
|
47
|
-
|
|
46
|
+
## 自检表 B · 结构完整(对照当次模板)
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
node scripts/check-deliverable-snap.mjs ./snap --preset p4-google
|
|
51
|
-
# 或自定义:--required overview,campaigns,geographic
|
|
52
|
-
# 已知账户为 CNY 时:--expect-currency CNY
|
|
53
|
-
```
|
|
48
|
+
先确认当次用的是哪份模板(如 `google-period-report.md`、`okki-weekly-google-client.md`、`google-inquiry-analysis.md`),再逐项:
|
|
54
49
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
| `--expect-currency CNY\|USD` | 与 `list-accounts` / `overview` 中 `currencyCode` 对照 |
|
|
50
|
+
- [ ] 模板要求的**每一章/Sheet**在产物里都存在(标题或 Sheet 名可对应)
|
|
51
|
+
- [ ] **无**整章空白(除非该章标注 `[ 数据不可用:… ]`)
|
|
52
|
+
- [ ] 执行摘要 / 概览:有消耗、展示、点击等**至少一项非空数字**(或明确写无数据)
|
|
53
|
+
- [ ] 周期报告默认维(P4):概览、日趋势、系列、设备、地域、关键词等**均有对应段落**(Meta 无接口的维度按模板写「未提供」)
|
|
54
|
+
- [ ] 优化建议:独立一节,**不是**只有表格没有文字
|
|
55
|
+
- [ ] Google 诊断:每模块除表格外有「分析」+「建议」(见 `google-ads-diagnosis.md`)
|
|
62
56
|
|
|
63
|
-
|
|
57
|
+
**不通过** → 补拉 CLI 维度、重跑生成逻辑、**重写产物**后再 Read 审阅。
|
|
64
58
|
|
|
65
|
-
|
|
59
|
+
---
|
|
66
60
|
|
|
67
|
-
|
|
61
|
+
## 自检表 C · 数字可信(抽样,不读大 JSON)
|
|
68
62
|
|
|
69
|
-
|
|
70
|
-
node -e "
|
|
71
|
-
const o=require('./snap/overview-<id>_<start>-<end>.json');
|
|
72
|
-
const r=o.record||{};
|
|
73
|
-
const p=r.currentPeriod||{};
|
|
74
|
-
console.log('spend',p.spend,'clicks',p.clicks,'currency',r.currencyCode);
|
|
75
|
-
"
|
|
76
|
-
```
|
|
63
|
+
不打开落盘 JSON,用以下**已掌握信息**对照产物:
|
|
77
64
|
|
|
78
|
-
|
|
65
|
+
- [ ] 报告总消耗/CPA 数量级与你在生成过程中 **CLI/脚本 stdout 打印的汇总**一致(同一会话里应有过一行 summary;若无,先补跑一次极小 `node -e` 只打印 totals 再对照——**仅用于核对,不把 JSON 贴进对话**)
|
|
66
|
+
- [ ] 账户 ID、账户名、统计区间与用户需求一致
|
|
67
|
+
- [ ] 无「示例账户」「占位 123456」等模板残留
|
|
68
|
+
- [ ] 表格行数与预期同一(如 P3 要求每个 `-a` ID 都有一行)
|
|
69
|
+
|
|
70
|
+
**不通过** → 修正产物或重新生成,禁止手改数字糊弄。
|
|
79
71
|
|
|
80
72
|
---
|
|
81
73
|
|
|
82
|
-
##
|
|
74
|
+
## 向用户交付时的格式(建议)
|
|
83
75
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
76
|
+
审阅通过后,消息中附带简短**自检结论**(证明你看过产物):
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
交付前自检(已通过):
|
|
80
|
+
- 产物:./out/report-xxx.html
|
|
81
|
+
- 币种:CNY(来自 list-accounts,与报告首行一致)
|
|
82
|
+
- 章节:8/8 默认维度齐全;关键词章 [ 数据不可用:接口超时 ] 已标注
|
|
83
|
+
- 区间:2026-04-01 ~ 2026-04-30
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
若某项未通过,**不要**写「已通过」,应说明正在补全。
|
|
89
87
|
|
|
90
88
|
---
|
|
91
89
|
|
|
92
|
-
##
|
|
90
|
+
## 与 Playbook 的关系
|
|
93
91
|
|
|
94
|
-
|
|
|
95
|
-
|
|
|
96
|
-
|
|
|
97
|
-
|
|
|
98
|
-
|
|
|
92
|
+
| Playbook | 审阅时重点 |
|
|
93
|
+
| -------- | ---------- |
|
|
94
|
+
| P1 | 画像是否含 stats + 系列要点;币种 |
|
|
95
|
+
| P4 | `google-period-report.md` 8 块是否齐 |
|
|
96
|
+
| P4-FB | 无接口维度是否写「未提供」 |
|
|
97
|
+
| P6 / P7 | 按各自 `report-templates/*.md` Sheet/章节表逐项 |
|
|
99
98
|
|
|
100
99
|
---
|
|
101
100
|
|
|
102
101
|
## 相关文档
|
|
103
102
|
|
|
104
103
|
- `references/accounts/currency.md`
|
|
105
|
-
- `report-templates/REPORT-WORKFLOW.md`
|
|
106
|
-
- `references/core/tips.md
|
|
104
|
+
- `report-templates/REPORT-WORKFLOW.md`
|
|
105
|
+
- `references/core/tips.md`(拉数阶段)
|
|
107
106
|
- `references/core/playbooks.md`
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
4. `ad campaigns -a <mediaCustomerId> --start <S> --end <D> --json-out ./snap-p1`
|
|
25
25
|
5. 诊断/画像报告:Read `report-templates/google-ads-diagnosis.md`(**硬约束:每日趋势 2 位小数、每模块必有分析**)+ `google-account-diagnosis-report.md`(章节与 CLI);`google-analysis --json-out` 须含 `daily-metrics`(按日趋势)。
|
|
26
26
|
6. 首行标注统计区间和货币;HTML 可对齐 `report-template.html` + `section-*` 区块。
|
|
27
|
-
7.
|
|
27
|
+
7. 交付前:**Read 最终产物**,按 `deliverable-preflight.md` 自检表确认币种与章节。
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
@@ -67,7 +67,7 @@ siluzan-tso accounts-digest -m Google -a id1,id2,... --start <S> --end <D> --jso
|
|
|
67
67
|
1. 确认时间范围;区间 > 3 个月时分段(季度/月)。
|
|
68
68
|
2. 按 `google-period-report.md` 默认维度执行 `google-analysis --json-out <dir>`。
|
|
69
69
|
3. 报告须含:账户概览、投放趋势、Top 关键词/系列/地区分布、优化建议。
|
|
70
|
-
4.
|
|
70
|
+
4. 交付前:**Read 最终 HTML/报告文件**,对照 `google-period-report.md` 与 `deliverable-preflight.md` 自检。
|
|
71
71
|
|
|
72
72
|
---
|
|
73
73
|
|
|
@@ -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
|
|
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
|
|
67
|
+
API Key 获取入口:`https://www.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
|
|
133
|
-
googleApiUrl : https://googleapi
|
|
134
|
-
webUrl : https://www
|
|
132
|
+
apiBaseUrl : https://tso-api.siluzan.com
|
|
133
|
+
googleApiUrl : https://googleapi.mysiluzan.com
|
|
134
|
+
webUrl : https://www.siluzan.com
|
|
135
135
|
apiKey : abcd****1234
|
|
136
136
|
```
|
|
137
137
|
|
|
@@ -53,7 +53,7 @@ siluzan-tso/ # 安装后目录名
|
|
|
53
53
|
|
|
54
54
|
- 从 SKILL.md **只链接一层**(`references/foo.md`),避免 A→B→C 链式引用。
|
|
55
55
|
- 路径用正斜杠,不用 Windows 反斜杠。
|
|
56
|
-
- 占位符 `https://www
|
|
56
|
+
- 占位符 `https://www.siluzan.com`、`https://tso-api.siluzan.com`、`npm install -g siluzan-tso-cli` 由构建脚本替换,文档中禁止硬编码环境 URL。
|
|
57
57
|
|
|
58
58
|
---
|
|
59
59
|
|
|
@@ -70,7 +70,7 @@ siluzan-tso account-history -m Google
|
|
|
70
70
|
siluzan-tso list-accounts -m Google
|
|
71
71
|
|
|
72
72
|
# 第四步:充值激活(必须网页完成)
|
|
73
|
-
# siluzan-tso config show 取 webUrl,打开:https://www
|
|
73
|
+
# siluzan-tso config show 取 webUrl,打开:https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
|
|
74
74
|
# 美元账户最低约 100 USD,人民币账户约 700 CNY
|
|
75
75
|
```
|
|
76
76
|
|
|
@@ -790,7 +790,7 @@ siluzan-tso balance -m Google -a <mediaCustomerId>
|
|
|
790
790
|
siluzan-tso config show # 取 webUrl
|
|
791
791
|
|
|
792
792
|
# 诊断入口(网页 AICreation 向导内嵌):
|
|
793
|
-
# https://www
|
|
793
|
+
# https://www.siluzan.com/v3/foreign_trade/tso/advertising/AICreation
|
|
794
794
|
# → 输入推广链接时,系统会自动触发网站诊断
|
|
795
795
|
```
|
|
796
796
|
|
|
@@ -851,7 +851,7 @@ siluzan-tso account bm-bind \
|
|
|
851
851
|
--bm-id <businessManagerId>
|
|
852
852
|
|
|
853
853
|
# 第三步:确认绑定状态(在网页确认)
|
|
854
|
-
# https://www
|
|
854
|
+
# https://www.siluzan.com/v3/foreign_trade/tso/manageAccounts → 找到对应账户查看 BM 状态
|
|
855
855
|
```
|
|
856
856
|
|
|
857
857
|
### 场景 C:TikTok BC 绑定 / 解绑
|
|
@@ -875,7 +875,7 @@ siluzan-tso account bc-unbind --customers <mediaCustomerId> --bc-id <bcId>
|
|
|
875
875
|
siluzan-tso config show # 取 webUrl
|
|
876
876
|
|
|
877
877
|
# 打开账户管理页:
|
|
878
|
-
# https://www
|
|
878
|
+
# https://www.siluzan.com/v3/foreign_trade/tso/manageAccounts
|
|
879
879
|
# → 选中 Google 账户 → 点击「激活账户」→ 选择激活方式
|
|
880
880
|
```
|
|
881
881
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
siluzan-tso config show # 取 webUrl
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
首页地址:`https://www
|
|
9
|
+
首页地址:`https://www.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
|
|
28
|
+
1. **「和首页一样的总览」** → 打开 `https://www.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
|
|
|
@@ -51,11 +51,11 @@
|
|
|
51
51
|
|
|
52
52
|
---
|
|
53
53
|
|
|
54
|
-
### 步骤 4b
|
|
54
|
+
### 步骤 4b:交付前审阅最终产物(**必做**)
|
|
55
55
|
|
|
56
|
-
- Read `references/core/deliverable-preflight.md
|
|
57
|
-
-
|
|
58
|
-
-
|
|
56
|
+
- Read `references/core/deliverable-preflight.md` 自检表 A/B/C。
|
|
57
|
+
- **Read 刚生成的报告文件**(HTML/Markdown 等),对照当次 `report-templates/*.md` 逐项确认章节与币种。
|
|
58
|
+
- 未通过:**修改产物或补拉数据后重新生成**,再次 Read 审阅;不得在未审阅时交付。
|
|
59
59
|
|
|
60
60
|
---
|
|
61
61
|
|
|
@@ -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.26
|
|
12
|
+
$PKG_VERSION = '1.1.26'
|
|
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
|
|
15
|
+
$INSTALL_CMD = 'npm install -g siluzan-tso-cli'
|
|
16
|
+
$WEB_BASE = 'https://www.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.26
|
|
12
|
+
readonly PKG_VERSION="1.1.26"
|
|
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
|
|
15
|
+
readonly INSTALL_CMD="npm install -g siluzan-tso-cli"
|
|
16
|
+
readonly WEB_BASE="https://www.siluzan.com"
|
|
17
17
|
|
|
18
18
|
# -- Constants ----------------------------------------------------------------
|
|
19
19
|
readonly NODE_MAJOR_MIN=18
|
package/package.json
CHANGED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* 交付前快照自检(币种 + 缺文件/空数据)
|
|
4
|
-
*
|
|
5
|
-
* 用法:
|
|
6
|
-
* node scripts/check-deliverable-snap.mjs <snapDir> [--preset p4-google] [--required a,b]
|
|
7
|
-
* node scripts/check-deliverable-snap.mjs ./snap --expect-currency CNY
|
|
8
|
-
*
|
|
9
|
-
* 退出码:0 通过;1 有 error;2 用法错误
|
|
10
|
-
*/
|
|
11
|
-
import fs from "node:fs";
|
|
12
|
-
import path from "node:path";
|
|
13
|
-
|
|
14
|
-
const PRESETS = {
|
|
15
|
-
"p4-google": [
|
|
16
|
-
"overview",
|
|
17
|
-
"daily-metrics",
|
|
18
|
-
"dimension-summary",
|
|
19
|
-
"campaigns",
|
|
20
|
-
"devices",
|
|
21
|
-
"geographic",
|
|
22
|
-
"keywords",
|
|
23
|
-
],
|
|
24
|
-
"p1-google": ["list-accounts", "stats", "ad-campaigns"],
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
function parseArgs(argv) {
|
|
28
|
-
const snapDir = argv[2];
|
|
29
|
-
if (!snapDir) return { error: "缺少 snapDir" };
|
|
30
|
-
let preset;
|
|
31
|
-
let required = [];
|
|
32
|
-
let expectCurrency;
|
|
33
|
-
for (let i = 3; i < argv.length; i++) {
|
|
34
|
-
if (argv[i] === "--preset" && argv[i + 1]) {
|
|
35
|
-
preset = argv[++i];
|
|
36
|
-
} else if (argv[i] === "--required" && argv[i + 1]) {
|
|
37
|
-
required = argv[++i].split(",").map((s) => s.trim()).filter(Boolean);
|
|
38
|
-
} else if (argv[i] === "--expect-currency" && argv[i + 1]) {
|
|
39
|
-
expectCurrency = argv[++i].toUpperCase();
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
if (preset) {
|
|
43
|
-
const p = PRESETS[preset];
|
|
44
|
-
if (!p) return { error: `未知 preset:${preset},可选:${Object.keys(PRESETS).join(", ")}` };
|
|
45
|
-
required = [...new Set([...required, ...p])];
|
|
46
|
-
}
|
|
47
|
-
return { snapDir: path.resolve(snapDir), required, expectCurrency };
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function readJson(filePath) {
|
|
51
|
-
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function listManifests(dir) {
|
|
55
|
-
return fs.readdirSync(dir).filter((f) => /^manifest(-.*)?\.json$/.test(f) || /^report-manifest(-.*)?\.json$/.test(f) || /^cli-manifest(-.*)?\.json$/.test(f));
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function sectionMatches(artifactSection, required) {
|
|
59
|
-
return required.some((r) => artifactSection === r || artifactSection.startsWith(`${r}-`) || artifactSection.includes(r));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function itemCount(payload) {
|
|
63
|
-
if (!payload || typeof payload !== "object") return null;
|
|
64
|
-
if (Array.isArray(payload.items)) return payload.items.length;
|
|
65
|
-
if (Array.isArray(payload.data?.items)) return payload.data.items.length;
|
|
66
|
-
if (payload.record && typeof payload.record === "object") return 1;
|
|
67
|
-
if (Array.isArray(payload.data)) return payload.data.length;
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function extractCurrencyFromPayload(payload, section) {
|
|
72
|
-
if (!payload || typeof payload !== "object") return null;
|
|
73
|
-
const rec = payload.record ?? payload.data?.record;
|
|
74
|
-
if (rec?.currencyCode) return String(rec.currencyCode);
|
|
75
|
-
const items = payload.items ?? payload.data?.items;
|
|
76
|
-
if (Array.isArray(items) && items.length > 0) {
|
|
77
|
-
const ma = items[0].ma ?? items[0];
|
|
78
|
-
if (ma?.currencyCode) return String(ma.currencyCode);
|
|
79
|
-
if (items[0].currencyCode) return String(items[0].currencyCode);
|
|
80
|
-
}
|
|
81
|
-
if (section.includes("list-accounts") && Array.isArray(items) && items[0]?.ma?.currencyCode) {
|
|
82
|
-
return String(items[0].ma.currencyCode);
|
|
83
|
-
}
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function main() {
|
|
88
|
-
const parsed = parseArgs(process.argv);
|
|
89
|
-
if (parsed.error) {
|
|
90
|
-
console.error(parsed.error);
|
|
91
|
-
process.exit(2);
|
|
92
|
-
}
|
|
93
|
-
const { snapDir, required, expectCurrency } = parsed;
|
|
94
|
-
if (!fs.existsSync(snapDir)) {
|
|
95
|
-
console.error(`目录不存在:${snapDir}`);
|
|
96
|
-
process.exit(2);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const manifests = listManifests(snapDir);
|
|
100
|
-
if (manifests.length === 0) {
|
|
101
|
-
console.error(`未找到 manifest / report-manifest / cli-manifest:${snapDir}`);
|
|
102
|
-
process.exit(1);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const errors = [];
|
|
106
|
-
const warnings = [];
|
|
107
|
-
let currencySeen = null;
|
|
108
|
-
|
|
109
|
-
for (const mf of manifests) {
|
|
110
|
-
const man = readJson(path.join(snapDir, mf));
|
|
111
|
-
const arts = man.artifacts ?? [];
|
|
112
|
-
console.log(`\n📋 ${mf}(${arts.length} 个 artifact)`);
|
|
113
|
-
|
|
114
|
-
if (required.length > 0) {
|
|
115
|
-
for (const req of required) {
|
|
116
|
-
const hit = arts.some((a) => sectionMatches(String(a.section ?? ""), [req]));
|
|
117
|
-
if (!hit) errors.push(`[${mf}] 缺少维度/命令:${req}`);
|
|
118
|
-
else console.log(` ✓ 已拉取:${req}`);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
for (const art of arts) {
|
|
123
|
-
const fp = path.join(snapDir, art.file);
|
|
124
|
-
if (!fs.existsSync(fp)) {
|
|
125
|
-
errors.push(`[${mf}] 文件缺失:${art.file}`);
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
let payload;
|
|
129
|
-
try {
|
|
130
|
-
payload = readJson(fp);
|
|
131
|
-
} catch (e) {
|
|
132
|
-
errors.push(`[${mf}] JSON 解析失败:${art.file}`);
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
const n = itemCount(payload);
|
|
136
|
-
const sec = String(art.section ?? "");
|
|
137
|
-
if (n === 0) warnings.push(`[${mf}] ${art.file} items 为空(章节可能写「无数据」)`);
|
|
138
|
-
const ccy = extractCurrencyFromPayload(payload, sec);
|
|
139
|
-
if (ccy) {
|
|
140
|
-
if (!currencySeen) currencySeen = ccy;
|
|
141
|
-
else if (currencySeen !== ccy) warnings.push(`[${mf}] 币种不一致:${ccy} vs 先前 ${currencySeen}`);
|
|
142
|
-
if (sec.includes("overview") || sec.includes("list-accounts")) {
|
|
143
|
-
console.log(` 💱 币种来源 ${art.file}:${ccy}`);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (expectCurrency) {
|
|
150
|
-
if (!currencySeen) warnings.push(`未从快照解析到 currencyCode,无法对照 --expect-currency ${expectCurrency}`);
|
|
151
|
-
else if (currencySeen !== expectCurrency) {
|
|
152
|
-
errors.push(`币种不符:快照为 ${currencySeen},期望 ${expectCurrency}(报告须用 ¥/ $ 与代码一致)`);
|
|
153
|
-
} else console.log(`\n✓ 币种与期望一致:${expectCurrency}`);
|
|
154
|
-
} else if (currencySeen) {
|
|
155
|
-
console.log(`\n💱 建议在报告首行写:统计区间:…(货币:${currencySeen})`);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (warnings.length) {
|
|
159
|
-
console.log("\n⚠️ 警告:");
|
|
160
|
-
warnings.forEach((w) => console.log(` - ${w}`));
|
|
161
|
-
}
|
|
162
|
-
if (errors.length) {
|
|
163
|
-
console.log("\n❌ 错误:");
|
|
164
|
-
errors.forEach((e) => console.log(` - ${e}`));
|
|
165
|
-
process.exit(1);
|
|
166
|
-
}
|
|
167
|
-
console.log("\n✅ 交付前自检通过(仍须确认报告正文金额来自脚本、非手填)\n");
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
main();
|