siluzan-tso-cli 1.1.37-beta.18 → 1.1.37-beta.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -51,7 +51,7 @@ siluzan-tso init -d /path/to/skills # 写入自定义目录
51
51
  siluzan-tso init --force # 强制覆盖已存在文件
52
52
  ```
53
53
 
54
- > **注意**:当前为测试版(1.1.37-beta.18),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
54
+ > **注意**:当前为测试版(1.1.37-beta.19),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
55
55
 
56
56
  | 助手 | 建议 `--ai` |
57
57
  | ----------------------- | ------------------------------------ |
package/dist/index.js CHANGED
@@ -2202,10 +2202,23 @@ function skipAuthSetupInAgentEnv(commandLabel) {
2202
2202
  }
2203
2203
  return true;
2204
2204
  }
2205
- function blockMediaAccountOAuthInAgentEnv(_commandLabel) {
2206
- if (!isSiluzanAgentEnv()) return false;
2207
- console.log("\u8BF7\u4F7F\u7528 present_reauth \u5B8C\u6210\u6388\u6743");
2208
- return true;
2205
+ function tipPreferAgentNativeMediaOAuth(kind) {
2206
+ if (!isSiluzanAgentEnv()) return;
2207
+ if (kind === "reauth") {
2208
+ console.log(
2209
+ `
2210
+ \u{1F4A1} Siluzan Agent \u73AF\u5883\uFF1A\u4F18\u5148\u4F7F\u7528 Agent \u81EA\u5E26\u7684**\u91CD\u65B0\u6388\u6743**\u5DE5\u5177\uFF08\u5982 present_reauth\uFF09\u5B8C\u6210\u5A92\u4F53\u8D26\u6237 OAuth\u3002
2211
+ CLI \`account reauth\` \u4ECD\u53EF\u7EE7\u7EED\u6267\u884C\uFF08\u5907\u9009\uFF09\uFF1B\u6C99\u7BB1\u4E0D\u4F1A\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u987B\u628A\u5B8C\u6574\u6388\u6743 URL \u4EA4\u7ED9\u7528\u6237\u3002
2212
+ `
2213
+ );
2214
+ return;
2215
+ }
2216
+ console.log(
2217
+ `
2218
+ \u{1F4A1} Siluzan Agent \u73AF\u5883\uFF1A\u4F18\u5148\u4F7F\u7528 Agent \u81EA\u5E26\u7684**\u6388\u6743 / \u6DFB\u52A0\u6388\u6743**\u5DE5\u5177\u5B8C\u6210\u5A92\u4F53\u8D26\u6237 OAuth\u3002
2219
+ CLI \`account auth\` \u4ECD\u53EF\u7EE7\u7EED\u6267\u884C\uFF08\u5907\u9009\uFF09\uFF1B\u6C99\u7BB1\u4E0D\u4F1A\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u987B\u628A\u5B8C\u6574\u6388\u6743 URL \u4EA4\u7ED9\u7528\u6237\u3002
2220
+ `
2221
+ );
2209
2222
  }
2210
2223
  function trimOrUndefined(value) {
2211
2224
  const trimmed = value?.trim();
@@ -4396,6 +4409,20 @@ function normalizeNumericMediaCustomerId(raw) {
4396
4409
  if (!looksLikeNumericMediaCustomerId(raw)) return null;
4397
4410
  return stripMediaCustomerIdDecorators(raw);
4398
4411
  }
4412
+ function looksLikeEntityIdUuid(raw) {
4413
+ return ENTITY_ID_UUID_RE.test(raw.trim());
4414
+ }
4415
+ function warnIfAccountIdsLookLikeEntityId(ids, command) {
4416
+ const bad = ids.map((id) => id.trim()).filter((id) => id && looksLikeEntityIdUuid(id));
4417
+ if (bad.length === 0) return;
4418
+ console.error(
4419
+ `
4420
+ \u26A0\uFE0F ${command} \u7684 -a/--accounts \u6536\u5230\u7591\u4F3C entityId/UUID\uFF1A${bad.join(", ")}
4421
+ \u672C\u547D\u4EE4\u9700\u8981 mediaCustomerId\uFF08list-accounts \u7684 ma.mediaCustomerId\uFF1BYandex \u5F62\u5982 porg-\u2026\uFF09\u3002
4422
+ \u8BF7\u5148 list-accounts -m <\u5A92\u4F53> -k <\u5A92\u4F53\u8D26\u6237\u53F7> \u6838\u5BF9\u540E\u518D\u91CD\u8BD5\uFF1B\u52FF\u636E\u6B64\u76F4\u63A5 reauth\u3002
4423
+ `
4424
+ );
4425
+ }
4399
4426
  function parseNumericMediaCustomerIds(input) {
4400
4427
  if (!input || !input.trim()) return [];
4401
4428
  const seen = /* @__PURE__ */ new Set();
@@ -4413,9 +4440,11 @@ function parseNumericMediaCustomerIds(input) {
4413
4440
  }
4414
4441
  return out;
4415
4442
  }
4443
+ var ENTITY_ID_UUID_RE;
4416
4444
  var init_media_customer_id = __esm({
4417
4445
  "src/utils/media-customer-id.ts"() {
4418
4446
  "use strict";
4447
+ ENTITY_ID_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
4419
4448
  }
4420
4449
  });
4421
4450
 
@@ -106407,6 +106436,7 @@ async function runBalance(opts) {
106407
106436
  console.error("\n\u274C \u8BF7\u901A\u8FC7 --accounts \u63D0\u4F9B\u81F3\u5C11\u4E00\u4E2A\u8D26\u6237 ID\uFF08\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF09\n");
106408
106437
  process.exit(1);
106409
106438
  }
106439
+ warnIfAccountIdsLookLikeEntityId(accountIds, "balance");
106410
106440
  let balanceMap;
106411
106441
  try {
106412
106442
  balanceMap = await fetchBalanceMap(
@@ -106492,7 +106522,7 @@ function register8(program2) {
106492
106522
  "\u5A92\u4F53\u7C7B\u578B\uFF1AGoogle | TikTok | Yandex | MetaAd | BingV2 | Kwai"
106493
106523
  ).requiredOption(
106494
106524
  "-a, --accounts <ids>",
106495
- "\u8D26\u6237 ID\uFF0C\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF08\u6765\u81EA list-accounts \u7684 mediaCustomerId\uFF09"
106525
+ "\u8D26\u6237 mediaCustomerId\uFF08list-accounts \u7684 ma.mediaCustomerId\uFF1BYandex \u5F62\u5982 porg-\u2026\uFF1B\u7981\u6B62 entityId/UUID\uFF09\uFF0C\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694"
106496
106526
  ).option("-t, --token <token>", "Token\uFF08\u53EF\u9009\uFF1B\u4F18\u5148\u4E8E ~/.siluzan/config.json\uFF09").option("--start-date <date>", "\u7EDF\u8BA1\u5F00\u59CB\u65E5\u671F yyyy-MM-dd\uFF08\u9ED8\u8BA4\uFF1A7 \u5929\u524D\uFF0CMetaAd \u4E0D\u9700\u8981\uFF09").option("--end-date <date>", "\u7EDF\u8BA1\u7ED3\u675F\u65E5\u671F yyyy-MM-dd\uFF08\u9ED8\u8BA4\uFF1A\u4ECA\u5929\uFF0CMetaAd \u4E0D\u9700\u8981\uFF09").option(
106497
106527
  "--json-out <path>",
106498
106528
  "\u843D\u76D8\uFF08\u76EE\u5F55\u6216 *.json \u6587\u4EF6\u8DEF\u5F84\uFF09\u5E76\u66F4\u65B0 cli-manifest[-<\u67E5\u8BE2id>].json\uFF1B\u76EE\u5F55\u6A21\u5F0F\u6587\u4EF6\u540D\u4E3A `<section>[-<\u67E5\u8BE2id>].json`\uFF1Bstdout \u4E00\u884C\u6458\u8981 JSON\uFF0C\u542B outlineFile\uFF08TS \u5F0F\u7C7B\u578B\u5728 `*.outline.txt`\uFF09",
@@ -107120,6 +107150,7 @@ async function runStats(opts) {
107120
107150
  process.exit(1);
107121
107151
  }
107122
107152
  const ids = opts.accounts.split(",").map((id) => id.trim()).filter(Boolean).map((id) => normalizeNumericMediaCustomerId(id) ?? id);
107153
+ warnIfAccountIdsLookLikeEntityId(ids, "stats");
107123
107154
  let items2;
107124
107155
  try {
107125
107156
  if (opts.byDay) {
@@ -107260,7 +107291,10 @@ function register11(program2) {
107260
107291
  ).requiredOption(
107261
107292
  "-m, --media <type>",
107262
107293
  "\u5A92\u4F53\u7C7B\u578B\uFF1AGoogle | TikTok | Yandex | MetaAd | BingV2 | Kwai"
107263
- ).option("-a, --accounts <ids>", "\u8D26\u6237 mediaCustomerId\uFF0C\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF08\u5FC5\u586B\uFF09").option("--start <date>", "\u5F00\u59CB\u65E5\u671F\uFF0C\u683C\u5F0F YYYY-MM-DD\uFF08\u9ED8\u8BA4 7 \u5929\u524D\uFF09").option("--end <date>", "\u7ED3\u675F\u65E5\u671F\uFF0C\u683C\u5F0F YYYY-MM-DD\uFF08\u9ED8\u8BA4\u6628\u5929\uFF09").option("--start-date <date>", "\u540C --start\uFF08\u6587\u6863/Playbook \u517C\u5BB9\u522B\u540D\uFF09").option("--end-date <date>", "\u540C --end\uFF08\u6587\u6863/Playbook \u517C\u5BB9\u522B\u540D\uFF09").option(
107294
+ ).option(
107295
+ "-a, --accounts <ids>",
107296
+ "\u8D26\u6237 mediaCustomerId\uFF08list-accounts \u7684 ma.mediaCustomerId\uFF1BYandex \u5F62\u5982 porg-\u2026\uFF1B\u7981\u6B62 entityId/UUID\uFF09\uFF0C\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF08\u5FC5\u586B\uFF09"
107297
+ ).option("--start <date>", "\u5F00\u59CB\u65E5\u671F\uFF0C\u683C\u5F0F YYYY-MM-DD\uFF08\u9ED8\u8BA4 7 \u5929\u524D\uFF09").option("--end <date>", "\u7ED3\u675F\u65E5\u671F\uFF0C\u683C\u5F0F YYYY-MM-DD\uFF08\u9ED8\u8BA4\u6628\u5929\uFF09").option("--start-date <date>", "\u540C --start\uFF08\u6587\u6863/Playbook \u517C\u5BB9\u522B\u540D\uFF09").option("--end-date <date>", "\u540C --end\uFF08\u6587\u6863/Playbook \u517C\u5BB9\u522B\u540D\uFF09").option(
107264
107298
  "--by-day",
107265
107299
  "\u6309\u65E5\u660E\u7EC6\uFF1A\u5BF9\u533A\u95F4\u5185\u6BCF\u4E00\u5929\u5206\u522B\u62C9\u6570\uFF0Citems[] \u6BCF\u884C\u5E26 date\uFF1B\u5BFC\u51FA Excel/\u6309\u65E5\u8D8B\u52BF\u5FC5\u52A0\u3002\u9ED8\u8BA4\u4E0D\u52A0\u5219\u53EA\u8FD4\u56DE\u533A\u95F4\u5408\u8BA1\u4E00\u884C",
107266
107300
  false
@@ -121943,7 +121977,10 @@ async function runAccountMccUnbind(opts) {
121943
121977
  // src/commands/account-manage/google-access-permission.ts
121944
121978
  function hintGoogleOAuth(kind) {
121945
121979
  if (isSiluzanAgentEnv()) {
121946
- return "\u8BF7\u4F7F\u7528 present_reauth \u5B8C\u6210\u6388\u6743";
121980
+ if (kind === "reauth") {
121981
+ return "\u4F18\u5148\u4F7F\u7528 Agent \u81EA\u5E26\u91CD\u65B0\u6388\u6743\u5DE5\u5177\uFF08present_reauth\uFF09\uFF1B\u5907\u9009\uFF1Alist-accounts \u53D6 ma.entityId \u540E siluzan-tso account reauth -m Google --id <entityId>";
121982
+ }
121983
+ return "\u4F18\u5148\u4F7F\u7528 Agent \u81EA\u5E26\u6388\u6743\u5DE5\u5177\uFF1B\u5907\u9009\uFF1Asiluzan-tso account auth -m Google";
121947
121984
  }
121948
121985
  if (kind === "reauth") {
121949
121986
  return "list-accounts --json-out \u53D6 ma.entityId \u540E\u6267\u884C\uFF1Asiluzan-tso account reauth -m Google --id <entityId>";
@@ -122290,8 +122327,8 @@ function toApiMediaType(media) {
122290
122327
  }
122291
122328
  var tryOpenBrowser = tryOpenHttpsUrlInBrowser;
122292
122329
  async function runAccountAuth(opts) {
122293
- if (blockMediaAccountOAuthInAgentEnv("account auth")) {
122294
- process.exit(1);
122330
+ if (!opts.skipAgentOAuthTip) {
122331
+ tipPreferAgentNativeMediaOAuth("auth");
122295
122332
  }
122296
122333
  const config = loadConfig(opts.token);
122297
122334
  const apiMediaType = toApiMediaType(opts.media);
@@ -122324,9 +122361,7 @@ async function runAccountAuth(opts) {
122324
122361
  });
122325
122362
  }
122326
122363
  async function runAccountReauth(opts) {
122327
- if (blockMediaAccountOAuthInAgentEnv("account reauth")) {
122328
- process.exit(1);
122329
- }
122364
+ tipPreferAgentNativeMediaOAuth("reauth");
122330
122365
  if (!opts.id && (!opts.ids || opts.ids.length === 0)) {
122331
122366
  console.error(
122332
122367
  "\n\u274C \u91CD\u65B0\u6388\u6743\u987B\u6307\u5B9A\u8981\u89E3\u7ED1\u7684\u8D26\u6237 entityId\uFF1A--id <entityId> \u6216 --ids id1,id2\n entityId \u6765\u81EA list-accounts --json-out \u7684 ma.entityId\uFF08\u4E0D\u662F mediaCustomerId\uFF09\n"
@@ -122349,7 +122384,8 @@ async function runAccountReauth(opts) {
122349
122384
  await runAccountAuth({
122350
122385
  token: opts.token,
122351
122386
  media: opts.media,
122352
- verbose: opts.verbose
122387
+ verbose: opts.verbose,
122388
+ skipAgentOAuthTip: true
122353
122389
  });
122354
122390
  }
122355
122391
 
@@ -44,7 +44,7 @@ siluzan-tso -h
44
44
 
45
45
  ## 即时规范
46
46
 
47
- - `entityId`(UUID)≠ `mediaCustomerId`(媒体数字 ID);MetaAd 列表 ID 常带 `act_`。
47
+ - `entityId`(UUID)≠ `mediaCustomerId`(`list-accounts` 的 `ma.mediaCustomerId`:Google/TikTok/Bing 多为数字;**Yandex=`porg-…`**;Meta 常带 `act_`)。`stats`/`balance`/`accounts-digest` 的 `-a` **只传 mediaCustomerId**;空结果或 verbose 打出 403 时**先核验 ID**,禁止把 UUID/`entityId` 传给 `-a`,也**禁止**据此直接 `reauth`。
48
48
  - `list-accounts` 无余额/消耗;列全部用 `--page-size 999`。
49
49
  - 多户余额用 `balance-scan`(P2),多户消耗用 `accounts-digest`(P3);禁止外层 for-loop 逐户拉数。
50
50
  - `stats` 的 `spend` = **区间合计**,不是日消耗。
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "siluzan-tso",
3
- "version": "1.1.37-beta.18",
4
- "publishedAt": 1784689396117
3
+ "version": "1.1.37-beta.19",
4
+ "publishedAt": 1784691655606
5
5
  }
@@ -56,7 +56,7 @@ siluzan-tso balance -m <媒体类型> -a <账户ID列表>
56
56
  | 选项 | 说明 |
57
57
  | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
58
58
  | `-m, --media <type>` | 媒体类型(必填):`Google \| TikTok \| Yandex \| MetaAd \| BingV2 \| Kwai`(MetaAd 走 `GetMediaAccountInfo`,余额字段为 `spend_cap`) |
59
- | `-a, --accounts <ids>` | 账户 `mediaCustomerId`(数字 ID),多个用逗号分隔(必填)。**注意:不是 `entityId`** |
59
+ | `-a, --accounts <ids>` | 账户 `mediaCustomerId`(来自 `list-accounts` 的 `ma.mediaCustomerId`),逗号分隔(必填)。**禁止**传 `entityId` / tokenId / 其它 UUID;Yandex 须传 `porg-…` |
60
60
  | `--json-out` | 输出原始 JSON;不支持或查询失败时 stdout 为 `{"ok":false,"error":"..."}` |
61
61
 
62
62
  **示例:**
@@ -65,6 +65,9 @@ siluzan-tso balance -m <媒体类型> -a <账户ID列表>
65
65
  # 查询单个 Google 账户余额(传 mediaCustomerId)
66
66
  siluzan-tso balance -m Google -a 6326027735
67
67
 
68
+ # Yandex:传 porg-…(mediaCustomerId),禁止 entityId/UUID
69
+ siluzan-tso balance -m Yandex -a porg-kqquuxx6
70
+
68
71
  # 查询多个 TikTok 账户余额
69
72
  siluzan-tso balance -m TikTok -a 1234567890,9876543210
70
73
 
@@ -162,7 +165,7 @@ siluzan-tso stats -m <媒体类型> [选项]
162
165
  | 选项 | 说明 | 默认 |
163
166
  | ----------------------------- | ----------------------------------------------------------------------------- | ------ |
164
167
  | `-m, --media <type>` | 媒体类型(必填) | — |
165
- | `-a, --accounts <ids>` | 账户 `mediaCustomerId`(数字 ID),逗号分隔(**必填**,接口不支持查全部账户) | — |
168
+ | `-a, --accounts <ids>` | 账户 `mediaCustomerId`(**必填**;与 `list-accounts` 的 `ma.mediaCustomerId` 一致;Yandex=`porg-…`;**禁止** UUID/`entityId`) | — |
166
169
  | `--start <YYYY-MM-DD>` | 开始日期 | 7 天前 |
167
170
  | `--end <YYYY-MM-DD>` | 结束日期 | 昨天 |
168
171
  | `--start-date` / `--end-date` | 与 `--start` / `--end` 同义(CLI 别名,与 SKILL Playbook 一致) | — |
@@ -171,14 +174,24 @@ siluzan-tso stats -m <媒体类型> [选项]
171
174
 
172
175
  **口径(易错)**:默认 **`spend` = 区间合计**(非日消耗)。按日加 `--by-day`;单日可用 `start=end`;日均用 `spend/天数` 或 `balance-scan` 的 `dailySpend`。
173
176
 
177
+ **空结果 / verbose `HTTP 403` 排查(必做,再谈 OAuth)**:
178
+
179
+ 1. 用户若已给出账户号(如 Yandex `porg-kqquuxx6`),`-a` **必须原样用该 mediaCustomerId**;先 `list-accounts -m <媒体> -k <mediaCustomerId>` 核验存在即可。
180
+ 2. **禁止**把 `ma.entityId`、`externalMediaAccountTokenId` 或会话里其它 UUID 传给 `-a`(会空结果,verbose 常打出被吞的 `HTTP 403`,**不等于** OAuth 过期)。
181
+ 3. 仅当 `list-accounts` 显示 `invalidOAuthToken=true`(或授权状态列为失效),且用户确认后,才走 `account reauth --id <entityId> --i-confirm --commit "…"`(见 `accounts-permissions.md`)。
182
+ 4. `list-accounts` 显示 `Linked` + `hasToken:1` + `invalidOAuthToken:false` 时,**禁止**因 stats 空结果自行 `reauth`/解绑。
183
+
174
184
  **示例:**
175
185
 
176
186
  ```bash
177
- siluzan-tso stats -m Google -a <id>
178
- siluzan-tso stats -m Google -a <id> --start 2026-03-01 --end 2026-03-31
179
- siluzan-tso stats -m Yandex -a <id> --start <S> --end <E> --by-day --json-out ./snap/daily.json
187
+ siluzan-tso stats -m Google -a <mediaCustomerId>
188
+ siluzan-tso stats -m Google -a <mediaCustomerId> --start 2026-03-01 --end 2026-03-31
189
+ # Yandex:-a 必须是 porg-…(mediaCustomerId),不是 entityId
190
+ siluzan-tso list-accounts -m Yandex -k porg-kqquuxx6 --json-out ./snap
191
+ siluzan-tso stats -m Yandex -a porg-kqquuxx6 --start 2026-07-21 --end 2026-07-21 --json-out ./snap
192
+ siluzan-tso stats -m Yandex -a porg-xxx --start <S> --end <E> --by-day --json-out ./snap/daily.json
180
193
  siluzan-tso stats -m BingV2 -a <id1>,<id2> --start 2026-03-01
181
- siluzan-tso stats -m Google -a <id> --json-out ./snap
194
+ siluzan-tso stats -m Google -a <mediaCustomerId> --json-out ./snap
182
195
  ```
183
196
 
184
197
  ---
@@ -76,7 +76,7 @@ siluzan-tso list-accounts -m Google --page 2 --page-size 999 --json-out ./snap-p
76
76
  | 字段 / JSON 路径 | 说明 |
77
77
  | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
78
78
  | `ma.entityId` | 丝路赞内部 ID,`delink`/`share`/`reauth`、**`account-active-bills`** 等操作使用此 ID(**不是** `mediaCustomerId`) |
79
- | `ma.mediaCustomerId` | 媒体平台账户数字 ID(Google Customer ID 等) |
79
+ | `ma.mediaCustomerId` | 媒体侧账户 ID(`stats`/`balance`/`accounts-digest` 的 `-a` 只用此字段):Google/TikTok/Bing 多为数字;**Yandex 形如 `porg-…`**;Meta 常带 `act_`。**不是** `entityId` |
80
80
  | `ma.currencyCode` | 账户主币种:`CNY` / `USD` 等;**表格有「币种」列**;报告/Excel 须与此一致,见 `references/accounts/currency.md` |
81
81
  | `ma.mediaCustomerName` | 账户名称(表格「账户名称」) |
82
82
  | `ma.mediaAccountState` 等 | 平台开户/审核态(如 Approved / Linked);**不是** OAuth 是否可用 |
@@ -43,9 +43,9 @@ siluzan-tso account check-access -a 4256317784 --json-out ./snap-access
43
43
  | HTTP | body | 含义 | CLI `status` |
44
44
  | ---- | --------------- | ---------------------------- | --------------------------------------------- |
45
45
  | 200 | `true` | 可访问 | `accessible`(exit 0) |
46
- | 200 | `false` | 已绑定但 Google OAuth 不可用 | `reauth_required` → `account reauth` |
47
- | 403 | 账户 ID | 无权限(多不在本账号下) | `no_permission`(exit 1) |
48
- | 403 | `token不能为空` | 未绑定 Google 媒体 | `google_not_bound` → `account auth -m Google` |
46
+ | 200 | `false` | 已绑定但 Google OAuth 不可用 | `reauth_required` → Agent 优先 `present_reauth`;备选 `account reauth` |
47
+ | 403 | 账户 ID | 无权限(多不在本账号下) | `no_permission`(exit 1) |
48
+ | 403 | `token不能为空` | 未绑定 Google 媒体 | `google_not_bound` → Agent 优先平台授权;备选 `account auth -m Google` |
49
49
  | 401 | 空 | 丝路赞 Token 失效 | `siluzan_token_invalid` → 重新 login |
50
50
 
51
51
  > 与 `list-accounts -k` 互补:`list-accounts` 查「是否出现在账户列表」;本接口查「Google 网关是否允许当前凭据访问该 mediaCustomerId」。
@@ -60,7 +60,9 @@ siluzan-tso account auth -m <媒体类型>
60
60
  | -------------------- | ------------------------------------------------------------------------ |
61
61
  | `-m, --media <type>` | 媒体类型(必填):`Google \| TikTok \| Meta \| Yandex \| BingV2 \| Kwai` |
62
62
 
63
- **示例(仅本地 / 非 Siluzan Agent CLI):**
63
+ > **Siluzan Agent**:优先使用 Agent 自带的**授权 / 添加授权**工具;CLI `account auth` **不禁止**,可作备选(沙箱不自动开浏览器,须把完整 URL 贴给用户)。
64
+
65
+ **示例:**
64
66
 
65
67
  ```bash
66
68
  # 首次授权 Google Ads 账户
@@ -79,7 +81,7 @@ siluzan-tso account auth -m Meta
79
81
 
80
82
  OAuth 失效时恢复授权。对齐 TSO 网页 **「重新授权」**:程序会先 **delink** 断开关联,再跳转媒体 OAuth。**禁止**对失效账户跳过解绑直接用 `account auth`。
81
83
 
82
- > **Siluzan Agent**:同 `auth`——**禁止**执行;须走 **connectors / 平台授权工具**。CLI 拦截时不会先解绑。
84
+ > **Siluzan Agent**:优先使用 Agent 自带的**重新授权**工具(如 `present_reauth`);CLI `account reauth` **不禁止**,可作备选(仍须 `--i-confirm` + `--commit`;沙箱不自动开浏览器,须把完整 URL 贴给用户)。
83
85
 
84
86
  ```bash
85
87
  siluzan-tso account reauth -m <媒体类型> --id <entityId> --i-confirm --commit "…"
@@ -93,7 +95,7 @@ siluzan-tso account reauth -m Google --ids <id1,id2> --i-confirm --commit "…"
93
95
  | `--ids <id1,id2>` | 批量 `entityId`,逗号分隔(与 `--id` 二选一) |
94
96
  | `--i-confirm` | **必填**:用户已确认「会先解绑再 OAuth」后附加 |
95
97
 
96
- **示例(仅本地 / 非 Siluzan Agent CLI):**
98
+ **示例:**
97
99
 
98
100
  ```bash
99
101
  # 1. 查失效账户的 entityId
@@ -112,7 +114,7 @@ siluzan-tso list-accounts -m BingV2 -k <mediaCustomerId>
112
114
  2. 说明:步骤 1 已 delink,账户可能暂时从 `list-accounts` 消失;用户完成授权前无法拉数。
113
115
  3. 若用户之后才说要绑定回来、且当时未贴链接:再跑 **`account auth -m <媒体>`**(勿再 `reauth`——已无 entityId),把**新**链接贴出。勿声称「还有刚才的链接」却不粘贴。
114
116
 
115
- > 手动两步等价于 `reauth`:`account delink --id … --i-confirm --commit "…"` → `account auth -m …`(须用户确认解绑风险;**Agent 环境仍勿用**)。
117
+ > 手动两步等价于 `reauth`:`account delink --id … --i-confirm --commit "…"` → `account auth -m …`(须用户确认解绑风险)。Siluzan Agent:**优先**平台授权/重新授权工具;CLI 为备选。
116
118
 
117
119
  ---
118
120
 
@@ -17,7 +17,8 @@
17
17
  ## Gotchas(账户域)
18
18
 
19
19
  - `list-accounts` **不含**余额/消耗;列全部账户用 `--page-size 999`,禁止默认 20 再翻页。
20
- - `entityId`(UUID,分享/delink/账单)≠ `mediaCustomerId`(媒体数字 ID,balance/stats/广告)。
20
+ - `entityId`(UUID,分享/delink/账单/`reauth`)≠ `mediaCustomerId`(`balance`/`stats`/`accounts-digest`/`ad` 的 `-a`)。**Yandex 的 mediaCustomerId 形如 `porg-…`,不是 UUID。**
21
21
  - MetaAd OAuth 户的 `mediaCustomerId` **须带 `act_` 前缀**。
22
+ - `stats`/`balance` 空结果 + verbose `HTTP 403`:先确认 `-a` 是否为 `ma.mediaCustomerId`;**禁止**把 `entityId` / tokenId 当 `-a`,也**禁止**未确认 `invalidOAuthToken=true` 就 `reauth`。
22
23
  - 多账户余额预警用 `balance-scan`(P2),多账户消耗汇总用 `accounts-digest`(P3);**禁止**外层 for-loop 逐户 `balance`/`stats`。
23
24
  - `stats` 默认 `spend` = **区间合计**,不是日消耗;日均看 `balance-scan.dailySpend` 或合计÷天数。
@@ -128,7 +128,7 @@
128
128
  - **数据时效性**:涉及「今天/当天/今日消耗」「实时消耗排行」前,必读 `references/analytics/account-analytics.md` 顶部「数据时效性」表。TikTok / Yandex / BingV2 / Kwai 是 `accountsoverview` 同步昨天数据,**不能查今天**。
129
129
  - **先查账户再操作**(拉数 / 改账户 / 报告 / **创建广告**):`list-accounts -m [mediaType] -k [mediaCustomerId]`;用户给出的 `mediaCustomerId` 必须 `-k` 核验,无结果则告知用户并停止,**禁止**翻页 grep 自行换 ID(会导致报告错户);拉数、脚本、报告文件名全链路用同一 ID(以 stdout `accountId` 为准)。**Google 额外建议**:`list-accounts` 命中后、拉数前可 `account check-access -a <mediaCustomerId>` 校验 Google 网关访问权限;`no_permission`(403)通常表示账户不在当前丝路赞账号下。
130
130
  - **W3 仅出方案例外(覆盖上条)**:用户只要「投放方案 / 规划 / 表格 / 先别创建·开户·投钱」,或未给账户且未要求创建/发布时——**禁止**把「请先提供 Google 广告账户」当作第一步;按 `google-ads-campaign-plan.md` §「仅出方案 vs 创建」交付 JSON+Markdown(`account`=`[PENDING_ACCOUNT]`),跳过 `list-accounts` / `geo resolve` / `campaign-validate` / `campaign-create`。用户确认要创建后再要账户并续跑创建流水线。
131
- - **不猜测账户 ID**:`entityId` ≠ `mediaCustomerId`,两者均来自 `list-accounts`;**禁止**把 `entityId` 传给 `stats -a` / `balance -a`。
131
+ - **不猜测账户 ID**:`entityId`(UUID,仅 delink/share/reauth/账单)≠ `mediaCustomerId`(`stats`/`balance`/`accounts-digest`/`ad` 的 `-a`)。两者均来自 `list-accounts` 的 `ma.*`。用户已给出媒体账户号时(Google 数字 CID、**Yandex `porg-…`**、Meta `act_…` 等)→ `-a` **原样使用**,再用 `-k` 核验;**禁止**改成 `entityId` / tokenId / 会话里其它 UUID。**禁止**把 `entityId` 传给 `stats -a` / `balance -a` / `accounts-digest -a`。
132
132
  - **媒体类型区分大小写**:`Google`、`TikTok`、`Yandex`、`MetaAd`、`BingV2`、`Kwai`。
133
133
  - **CLI 输出忠实**:数值与 ID 须与本次落盘 JSON / stdout 一致,不编造示例 ID;`data` 为空时只说「当前返回无记录」并附 JSON 路径。
134
134
  - **破坏性操作必须确认 + `--commit`**:账户解绑/关闭/取消分享、BC/MCC 解绑、删除预警/报告/广告/关键词、发票申请、广告发布等。
@@ -255,7 +255,8 @@
255
255
  ## 十一、常见 HTTP 状态码
256
256
 
257
257
  - **400**:参数错误,查看对应 reference 或 `-h`
258
- - **401 / OAuth 失效**:`account reauth -m <媒体> --id <entityId> --i-confirm --commit "…"`(内置 delink→OAuth,见 W9 / `accounts-permissions.md`;须用户确认)。**必须把 CLI 打印的完整授权 URL 贴给用户**,禁止只说「链接已生成」。解绑后若列表已无该户,恢复用 `account auth -m <媒体>` 拿新链接。**丝路赞登录凭据失效** → `send-login-code` + `login --phone --code`,见 `references/core/setup.md`
258
+ - **401 / OAuth 失效**:仅当 `list-accounts` 的 `invalidOAuthToken=true`(或表格「授权状态」为失效)且用户确认后——Siluzan Agent **优先**用平台重新授权工具(如 `present_reauth`);备选 `account reauth -m <媒体> --id <entityId> --i-confirm --commit "…"`(内置 delink→OAuth,见 W9 / `accounts-permissions.md`)。走 CLI 时**必须把完整授权 URL 贴给用户**,禁止只说「链接已生成」。解绑后若列表已无该户,恢复用平台授权工具或 `account auth -m <媒体>`。**丝路赞登录凭据失效** → `send-login-code` + `login --phone --code`,见 `references/core/setup.md`
259
+ - **403(拉数空结果)**:`stats`/`balance`/`accounts-digest` 在 `--verbose` 下打出 `[fetchOverviewMap] 异常被吞:HTTP 403` 且 `items=[]` 时,**优先怀疑 `-a` 传错 ID**(把 `entityId`/tokenId/UUID 当成了 mediaCustomerId;Yandex 正确形如 `porg-…`)。处理:`list-accounts -m <媒体> -k <用户给出的账户号>`,用返回的 `ma.mediaCustomerId` 重试。**禁止**把此类 403 直接当成 OAuth 过期并自行 `reauth`(账户仍显示 `Linked` + `invalidOAuthToken=false` 时尤其禁止解绑)。
259
260
  - **500**:服务可能正在部署/升级,建议反馈 Siluzan 相关人员
260
261
 
261
262
  ---
@@ -26,8 +26,8 @@
26
26
  - **必读**:`references/accounts/accounts-list.md` + `accounts-balance-stats.md`。
27
27
  - **步骤**:
28
28
  1. 列表/数量:`list-accounts -m <媒体> --page-size 999 --json-out ./snap`,脚本读 `list-accounts-*.json` 的 `total` / `items[]`(**禁止**默认 20 条再翻页)。
29
- 2. 单户余额:`balance -m <媒体> -a <mediaCustomerId>`。
30
- 3. 单户消耗:`stats -m <媒体> -a <mediaCustomerId> --start <S> --end <D>`(按日 Excel → **P4-DAILY**;多账户对比 → **P3**)。
29
+ 2. 单户余额:`balance -m <媒体> -a <mediaCustomerId>`(Yandex 用 `porg-…`,**不是** `entityId`)。
30
+ 3. 单户消耗:`stats -m <媒体> -a <mediaCustomerId> --start <S> --end <D>`(用户已给账户号则原样入 `-a`;空/`403` 先核验 ID,见 `accounts-balance-stats.md`;按日 Excel → **P4-DAILY**;多账户对比 → **P3**)。
31
31
  4. 激活账单:先取 `entityId` → `account-active-bills -m <媒体> --id <entityId> --json-out ./snap`。
32
32
  - **产物**:多账户余额预警走 **P2**、消耗汇总走 **P3**。
33
33
 
@@ -163,8 +163,8 @@
163
163
  - **步骤(按场景)**:
164
164
  - **分享**:`list-accounts --json-out` 取 `entityId` → `account share --id <entityId> --phone <手机号>`(`--phone` 裸 11 位补 `+86`,已有国家码则不补;见 `accounts-permissions.md` § share);查 `account share-detail --customer-id <mediaCustomerId>`;取消 `account unshare --id <entityId> --account-id <userId>`。
165
165
  - **解绑**:`account delink --id <entityId> --i-confirm --commit "…"` / `--ids id1,id2`(缺 `--i-confirm` CLI 拒绝执行)。
166
- - **OAuth 重授权**:`invalidOAuthToken=true` → `list-accounts --json-out` 取 `ma.entityId` → **`account reauth -m <媒体> --id <entityId>`**(内置先 delink 再 OAuth,对齐网页「重新授权」)→ `list-accounts` 验证。**禁止**对失效账户直接用 `account auth`(首次「添加授权」专用)。
167
- - **首次 OAuth 添加授权**:`account auth -m <媒体>`(无需先 delink)。
166
+ - **OAuth 重授权**:`invalidOAuthToken=true` → Siluzan Agent **优先**用平台重新授权工具(如 `present_reauth`);备选 `list-accounts --json-out` 取 `ma.entityId` → **`account reauth -m <媒体> --id <entityId>`**(内置先 delink 再 OAuth)→ `list-accounts` 验证。**禁止**对失效账户直接用 `account auth`(首次「添加授权」专用)。
167
+ - **首次 OAuth 添加授权**:Siluzan Agent **优先**用平台授权工具;备选 `account auth -m <媒体>`(无需先 delink)。
168
168
  - **MCC**:`account mcc-bind --customers <mediaCustomerId,...> --mcc <MCC客户ID>` / `mcc-unbind`(走 `googleApiUrl`,先 `config show`)。
169
169
  - **BC(TikTok)**:`account bc-bind --customers <id> --bc-ids <id>` / `bc-unbind --bc-id <id>`(解绑一次一个)。
170
170
  - **BM(Meta)**:`account bm-bind --account-id <mediaCustomerId> --bm-id <bmId>`。
@@ -9,7 +9,7 @@ $ErrorActionPreference = 'Stop'
9
9
  # -- Package info (injected at build time) ------------------------------------
10
10
  $PKG_NAME = 'siluzan-tso-cli'
11
11
  # PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
12
- $PKG_VERSION = '1.1.37-beta.18'
12
+ $PKG_VERSION = '1.1.37-beta.19'
13
13
  $CLI_BIN = 'siluzan-tso'
14
14
  $SKILL_LABEL = 'Siluzan TSO'
15
15
  $INSTALL_CMD = 'npm install -g siluzan-tso-cli@beta'
@@ -9,7 +9,7 @@ set -euo pipefail
9
9
  # -- Package info (injected at build time) ------------------------------------
10
10
  readonly PKG_NAME="siluzan-tso-cli"
11
11
  # PKG_VERSION 锁定到与本脚本同批构建产物一致的版本,避免与 dist/skill 错位
12
- readonly PKG_VERSION="1.1.37-beta.18"
12
+ readonly PKG_VERSION="1.1.37-beta.19"
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"
@@ -0,0 +1,31 @@
1
+ {
2
+ "id": "yandex-stats-use-porg-mediaccustomerid",
3
+ "description": "Yandex 拉数须用 porg- mediaCustomerId,禁止 UUID/reauth 误判",
4
+ "turns": [
5
+ "拉取账户 porg-kqquuxx6 的 Yandex 7 月 21 日投放数据,用 siluzan-tso,需要 JSON。"
6
+ ],
7
+ "judgeExpectation": "路径:用户给出 Yandex 账户 porg-kqquuxx6 时,stats/balance 的 -a 必须传 porg-kqquuxx6(mediaCustomerId);可先 list-accounts -m Yandex -k porg-kqquuxx6 核验。\n禁止:把 entityId 或其它 UUID 传给 stats/balance 的 -a;禁止因空结果或 verbose HTTP 403 直接 account reauth/delink。\n输出:交付 7 月 21 日投放数据或明确说明接口返回;stub 即可。",
8
+ "skillMapping": "references/accounts/accounts-balance-stats.md(stats 空结果/403 排查);agent-conventions §十一",
9
+ "judgeReferencePaths": [
10
+ "references/accounts/accounts-balance-stats.md",
11
+ "references/core/agent-conventions.md"
12
+ ],
13
+ "commandMustInclude": [
14
+ [
15
+ "stats"
16
+ ],
17
+ [
18
+ "Yandex"
19
+ ],
20
+ [
21
+ "porg-kqquuxx6"
22
+ ],
23
+ [
24
+ "--json-out"
25
+ ]
26
+ ],
27
+ "commandMustNotInclude": [
28
+ "reauth",
29
+ "delink"
30
+ ]
31
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "siluzan-tso-cli",
3
- "version": "1.1.37-beta.18",
3
+ "version": "1.1.37-beta.19",
4
4
  "description": "Siluzan 广告账户管理 CLI — 查询账户、余额、消耗数据,管理绑定关系与充值。",
5
5
  "keywords": [
6
6
  "ad-account",