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 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@beta
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
@@ -3328,7 +3328,7 @@ var DEFAULT_API_BASE;
3328
3328
  var init_defaults = __esm({
3329
3329
  "src/config/defaults.ts"() {
3330
3330
  "use strict";
3331
- DEFAULT_API_BASE = "https://tso-api-ci.siluzan.com";
3331
+ DEFAULT_API_BASE = "https://tso-api.siluzan.com";
3332
3332
  }
3333
3333
  });
3334
3334
 
@@ -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`,运行 `node scripts/check-deliverable-snap.mjs <snapDir>`;币种只认 `currencyCode`,禁止默认 Google=美金。
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
  >
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "siluzan-tso",
3
- "version": "1.1.26-beta.2",
4
- "publishedAt": 1780539987793
3
+ "version": "1.1.26",
4
+ "publishedAt": 1780540766602
5
5
  }
@@ -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` | **交付前自检**:币种 + manifest 完整性;`scripts/check-deliverable-snap.mjs` |
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-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google`;Kwai、Yandex 当前没有对应充值界面) |
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-ci.siluzan.com/v3/foreign_trade/tso/manageAccounts` |
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-ci.siluzan.com/v3/foreign_trade/tso/manageAccounts
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-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google` |
125
- | TikTok | `TikTok` | `https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=TikTok` |
126
- | Meta / Facebook | `MetaAd` | `https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=MetaAd` |
127
- | Microsoft / Bing | `MicrosoftAd` | `https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=MicrosoftAd` |
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-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay_batch?mediaType=Google` |
136
- | TikTok | `https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay_batch?mediaType=TikTok` |
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-ci.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=Google` |
145
- | TikTok | `https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=TikTok` |
146
- | Meta / Facebook | `https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=MetaAd` |
147
- | Microsoft / Bing | `https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=MicrosoftAd` |
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-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
159
- - TikTok 充值: https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=TikTok
160
- - Meta 充值: https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=MetaAd
161
- - Microsoft/Bing 充值:https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=MicrosoftAd
162
- - Google 批量充值: https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay_batch?mediaType=Google
163
- - TikTok 批量充值: https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay_batch?mediaType=TikTok
164
- - Google 月结充值: https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=Google
165
- - TikTok 月结充值: https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=TikTok
166
- - Meta 月结充值: https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=MetaAd
167
- - Microsoft/Bing 月结充值:https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=MicrosoftAd
168
- - 丝路赞钱包: https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/siluzanWallet
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-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
178
- - TikTok 充值:https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=TikTok
179
- - Meta 充值:https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=MetaAd
180
- - Microsoft/Bing 充值:https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=MicrosoftAd
181
- - Google 批量充值:https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay_batch?mediaType=Google
182
- - TikTok 批量充值:https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay_batch?mediaType=TikTok
183
- - Google 月结充值:https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=Google
184
- - TikTok 月结充值:https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=TikTok
185
- - Meta 月结充值:https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=MetaAd
186
- - Microsoft/Bing 月结充值:https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/accountBillingQuota?mediaType=MicrosoftAd
187
- - 丝路赞钱包:https://www-ci.siluzan.com/v3/foreign_trade/tso/recharge/siluzanWallet
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-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
63
+ # 审核通过后:config show → https://www.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
64
64
  ```
65
65
 
66
66
  ---
@@ -1,6 +1,6 @@
1
1
  # rag:知识库检索(TSO 广告投放辅助)
2
2
 
3
- 知识库管理页面在 https://www-ci.siluzan.com/knowledge-base/
3
+ 知识库管理页面在 https://www.siluzan.com/knowledge-base/
4
4
 
5
5
  为 **广告投放、账户分析、拓词、诊断报告** 等 TSO 业务提供**企业已入库**的产品、行业、客户背景事实依据。
6
6
 
@@ -192,9 +192,9 @@ siluzan-tso report push receive-emails -m Google [--json-out ./snap]
192
192
 
193
193
  | 媒体 | 报告类型 | URL 模板 |
194
194
  | ------ | ---------------- | -------------------------------------------------------- |
195
- | Google | 日报(Daily) | `https://www-ci.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
196
- | Google | 小时报(Hourly) | `https://www-ci.siluzan.com/media-report/hour/{entityId}?culture=zh-CN` |
197
- | TikTok | 日报 | `https://www-ci.siluzan.com/media-report/publish/{entityId}?culture=zh-CN` |
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-ci.siluzan.com
210
+ # webUrl: https://www.siluzan.com
211
211
 
212
212
  # 第三步:拼接链接(Google 日报)
213
- # https://www-ci.siluzan.com/media-report/publish/rpt_abc123?culture=zh-CN
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`,运行 `node scripts/check-deliverable-snap.mjs`;币种须来自 `list-accounts` / `overview` 的 `currencyCode`
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
- - **交付前自检**:报告/Excel 交付前运行 `scripts/check-deliverable-snap.mjs`(见 `deliverable-preflight.md`);自检失败禁止交付。
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
- > 用户反馈 Agent 产出物常见两类问题:**币种错误**(Google 默认美金、符号混用)、**报告缺章/缺数**(少拉维度、Read JSON 截断后手填)。本节给出**可执行**防线。
3
+ > 用户反馈:产出物常出现**币种错误**、**报告缺章/缺数**。
4
+ > **不靠外部校验脚本**——由 **Agent 在交付用户前,亲自查看已生成的最终文件**(HTML / Markdown / Excel 等),对照清单结论后再发送。
4
5
 
5
6
  ---
6
7
 
7
- ## 根因(简要)
8
+ ## 原则
8
9
 
9
- | 问题 | 典型原因 |
10
- | ---- | -------- |
11
- | 币种错误 | 未先 `list-accounts` `currencyCode`;报告脚本写死 `USD`;CNY 用 `$` |
12
- | 数据缺失 | 未按模板拉全 `--sections`;未读 `manifest` 就写报告;Read JSON 截断后编造;多账户漏 ID |
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
- ## 强制流程(报告/Excel 交付前)
21
+ ## 审阅时机
17
22
 
18
- 与 `references/core/agent-conventions.md`「计划 → 确认 → 执行 → **验证**」一致,**交付前增加验证步**:
23
+ 在以下动作**之后、发给用户之前**:
19
24
 
20
- ### 1. 币种(第一步就做)
25
+ 1. 已用脚本/CLI 拉数并生成报告文件(或 Excel)。
26
+ 2. 文件已写入磁盘路径(你知道路径)。
21
27
 
22
- ```bash
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
- - 将输出的 **`currencyCode`** 写入报告生成脚本(从 JSON 读,勿写死)。
33
- - 首行必须有:`统计区间:YYYY-MM-DD ~ YYYY-MM-DD(货币:CNY|USD)`。
34
- - 符号:**CNY → ¥**,**USD → $**。详见 `references/accounts/currency.md`。
30
+ ---
35
31
 
36
- ### 2. 拉数完整(对照模板 + manifest)
32
+ ## 自检表 A · 币种(每条必勾)
37
33
 
38
- - 周期报告:按 `report-templates/google-period-report.md` 默认 7 维(或用户追加维)一次 `google-analysis --sections … --json-out`。
39
- - 拉数后打开 **`manifest-<accountId>.json`**(用脚本 `JSON.parse`,勿 Read 整份若很大),核对 `artifacts[].section` 与模板一致。
34
+ 对照 `references/accounts/currency.md`:
40
35
 
41
- ### 3. 写报告只用脚本读 JSON
36
+ - [ ] 报告**封面/首行**含 `统计区间:…(货币:CNY)` 或 `(货币:USD)`(或等价英文标注)
37
+ - [ ] 代码与**一致**:`CNY` → 全文金额用 **¥**;`USD` → **$**;未混用
38
+ - [ ] 与当次 `list-accounts -k …` 得到的 **`currencyCode` 相同**(回顾对话中 CLI 表格或你记录的「币种」一行)
39
+ - [ ] 多账户报告:分币种分表,**无** CNY+USD 直接相加的一行「总计」
40
+ - [ ] 未出现「Google 账户所以是美金」类表述
42
41
 
43
- `references/core/tips.md`:**禁止** Read 业务 `*.json`;用 `node`/Python 聚合后写 HTML/xlsx。
42
+ **不通过** 改产物文件后**重新 Read** 再审,不得交付。
44
43
 
45
- ### 4. 交付前运行自检脚本(必做)
44
+ ---
46
45
 
47
- Skill 自带脚本(安装后在 skill 根目录):
46
+ ## 自检表 B · 结构完整(对照当次模板)
48
47
 
49
- ```bash
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
- | `<snapDir>` | `--json-out` 目录 |
58
- | `--preset p4-google` | 对齐 Google 周期报告默认 7 维 |
59
- | `--preset p1-google` | 单账户画像:list-accounts + stats + ad-campaigns |
60
- | `--required a,b` | 额外必填 section(逗号分隔,前缀匹配) |
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
- **退出码 1** 补拉缺失维度或修币种后再交付。**禁止**在自检失败时仍把报告发给用户。
57
+ **不通过**补拉 CLI 维度、重跑生成逻辑、**重写产物**后再 Read 审阅。
64
58
 
65
- ### 5. 报告正文抽检(脚本输出对照)
59
+ ---
66
60
 
67
- 交付前用脚本打印 3 个汇总(示例):
61
+ ## 自检表 C · 数字可信(抽样,不读大 JSON)
68
62
 
69
- ```bash
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
- ## Playbook 挂钩
74
+ ## 向用户交付时的格式(建议)
83
75
 
84
- | Playbook | 自检命令 |
85
- | -------- | -------- |
86
- | P1 | `--preset p1-google` + `--expect-currency`(来自 list-accounts) |
87
- | P4 | `--preset p4-google` |
88
- | P6 / P7 | 按 `okki-weekly-google-client.md` / `google-inquiry-analysis.md` 自建 `--required`(含各月 `campaigns`、`geographic` 等) |
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
- | **skill-eval 场景** | 断言 Agent `list-accounts` 且报告含 `(货币:XXX)` |
97
- | **CLI `snap check`** | 将本脚本收编为 `siluzan-tso snap check`(待开发) |
98
- | **报告模板内嵌币种占位** | 脚本写 `{currencyCode}` 而非手写符号 |
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` § 步骤 4–5
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. 交付前:`node scripts/check-deliverable-snap.mjs ./snap-p1 --preset p1-google --expect-currency <来自 list-accounts>`。
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. 交付前:`node scripts/check-deliverable-snap.mjs <dir> --preset p4-google --expect-currency <currencyCode>`。
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@beta
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-ci.siluzan.com/v3/foreign_trade/settings/apiKeyManagement`
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-ci.siluzan.com
133
- googleApiUrl : https://googleapi-ci.mysiluzan.com
134
- webUrl : https://www-ci.siluzan.com
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-ci.siluzan.com`、`https://tso-api-ci.siluzan.com`、`npm install -g siluzan-tso-cli@beta` 由构建脚本替换,文档中禁止硬编码环境 URL。
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-ci.siluzan.com/v3/foreign_trade/tso/recharge/pay?mediaType=Google
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-ci.siluzan.com/v3/foreign_trade/tso/advertising/AICreation
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-ci.siluzan.com/v3/foreign_trade/tso/manageAccounts → 找到对应账户查看 BM 状态
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-ci.siluzan.com/v3/foreign_trade/tso/manageAccounts
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-ci.siluzan.com/v3/foreign_trade/tso/home`
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-ci.siluzan.com/v3/foreign_trade/tso/home`。
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
- - 运行 `node scripts/check-deliverable-snap.mjs <snapDir> --preset p4-google`(或按模板 `--required` / `--expect-currency`)。
58
- - 退出码非 0:**补拉数据或修正币种**,不得交付。
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-beta.2'
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@beta'
16
- $WEB_BASE = 'https://www-ci.siluzan.com'
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-beta.2"
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@beta"
16
- readonly WEB_BASE="https://www-ci.siluzan.com"
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,6 +1,6 @@
1
1
  {
2
2
  "name": "siluzan-tso-cli",
3
- "version": "1.1.26-beta.2",
3
+ "version": "1.1.26",
4
4
  "description": "Siluzan 广告账户管理 CLI — 查询账户、余额、消耗数据,管理绑定关系与充值。",
5
5
  "keywords": [
6
6
  "ad-account",
@@ -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();