siluzan-tso-cli 1.1.29-beta.7 → 1.1.29-beta.8

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.29-beta.7),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
54
+ > **注意**:当前为测试版(1.1.29-beta.8),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
55
55
 
56
56
  | 助手 | 建议 `--ai` |
57
57
  | ----------------------- | ------------------------------------ |
package/dist/index.js CHANGED
@@ -2601,6 +2601,9 @@ function pickStr(obj, key) {
2601
2601
  const v = obj[key];
2602
2602
  return typeof v === "string" && v.trim() ? v.trim() : void 0;
2603
2603
  }
2604
+ function pickPhone(data) {
2605
+ return pickStr(data, "phone") ?? pickStr(data, "mobile") ?? pickStr(data, "phoneNumber") ?? pickStr(data, "mobilePhone");
2606
+ }
2604
2607
  function pickCompanyId(data) {
2605
2608
  const direct = pickStr(data, "companyId") ?? pickStr(data, "companyID") ?? pickStr(data, "CompanyId");
2606
2609
  if (direct) return direct;
@@ -2617,10 +2620,11 @@ function parseMeResponse(text) {
2617
2620
  const data = json?.data && typeof json.data === "object" ? json.data : json;
2618
2621
  const id = pickStr(data, "entityId") ?? pickStr(data, "id") ?? pickStr(data, "userId") ?? pickStr(data, "accountId");
2619
2622
  const email = pickStr(data, "email");
2620
- const username = pickStr(data, "userName") ?? pickStr(data, "username") ?? pickStr(data, "name") ?? pickStr(data, "phone");
2623
+ const phone = pickPhone(data);
2624
+ const username = pickStr(data, "userName") ?? pickStr(data, "username") ?? pickStr(data, "name") ?? phone;
2621
2625
  const companyId = pickCompanyId(data);
2622
- if (!id && !email && !username && !companyId) return null;
2623
- return { id, email, username, companyId };
2626
+ if (!id && !email && !username && !phone && !companyId) return null;
2627
+ return { id, email, username, phone, companyId };
2624
2628
  } catch {
2625
2629
  return null;
2626
2630
  }
@@ -2645,6 +2649,7 @@ async function fetchSiluzanCurrentUser(apiBase, config) {
2645
2649
  entityId: parsed.id,
2646
2650
  email: parsed.email,
2647
2651
  username: parsed.username,
2652
+ phone: parsed.phone,
2648
2653
  companyId: parsed.companyId
2649
2654
  };
2650
2655
  } catch {
@@ -3099,6 +3104,18 @@ function normalizeChinaPhone(input) {
3099
3104
  function isValidChinaPhone(input) {
3100
3105
  return /^\+861\d{10}$/.test(normalizeChinaPhone(input));
3101
3106
  }
3107
+ function chinaPhonesEqual(a, b) {
3108
+ const na = normalizeChinaPhone(a.trim());
3109
+ const nb = normalizeChinaPhone(b.trim());
3110
+ if (isValidChinaPhone(na) && isValidChinaPhone(nb)) {
3111
+ return na === nb;
3112
+ }
3113
+ const da = a.replace(/\D/g, "");
3114
+ const db = b.replace(/\D/g, "");
3115
+ const ca = da.length >= 11 ? da.slice(-11) : da;
3116
+ const cb = db.length >= 11 ? db.slice(-11) : db;
3117
+ return ca.length === 11 && cb.length === 11 && ca === cb;
3118
+ }
3102
3119
  async function sendPhoneLoginCode(opts) {
3103
3120
  const phone = normalizeChinaPhone(opts.phone);
3104
3121
  const url = `${opts.ssoBaseUrl}/Account/SendVaildCode?Phone=${encodeURIComponent(
@@ -119379,6 +119396,89 @@ function register22(program2) {
119379
119396
  );
119380
119397
  }
119381
119398
 
119399
+ // src/commands/account-manage/me.ts
119400
+ init_dist();
119401
+ init_auth();
119402
+ init_cli_json_snapshot();
119403
+ function maskPhone(phone) {
119404
+ if (!phone) return "\u2014";
119405
+ const digits = phone.replace(/\D/g, "");
119406
+ if (digits.length < 7) return phone;
119407
+ const tail = digits.slice(-4);
119408
+ return `${digits.slice(0, 3)}****${tail}`;
119409
+ }
119410
+ async function runAccountMe(opts) {
119411
+ const config = loadConfig(opts.token);
119412
+ const me = await fetchSiluzanCurrentUser(config.apiBaseUrl, config);
119413
+ if (!me) {
119414
+ console.error(
119415
+ "\n\u274C \u65E0\u6CD5\u83B7\u53D6\u5F53\u524D\u8D26\u53F7\u4FE1\u606F\uFF08GET /query/account/me\uFF09\u3002\u8BF7\u68C0\u67E5\u51ED\u636E\u662F\u5426\u6709\u6548\uFF1Asiluzan-tso config show\n"
119416
+ );
119417
+ process.exit(1);
119418
+ }
119419
+ const phoneNormalized = me.phone ? normalizeChinaPhone(me.phone) : void 0;
119420
+ const payload = {
119421
+ entityId: me.entityId,
119422
+ email: me.email,
119423
+ username: me.username,
119424
+ phone: me.phone,
119425
+ phoneNormalized,
119426
+ companyId: me.companyId
119427
+ };
119428
+ if (opts.checkPhone?.trim()) {
119429
+ const requested = opts.checkPhone.trim();
119430
+ payload.requestedPhone = requested;
119431
+ if (!me.phone) {
119432
+ payload.matched = false;
119433
+ payload.message = "\u5F53\u524D\u767B\u5F55\u51ED\u636E\u672A\u8FD4\u56DE\u624B\u673A\u53F7\uFF0C\u65E0\u6CD5\u6821\u9A8C\u662F\u5426\u4E0E\u6307\u5B9A\u4F01\u4E1A\u7BA1\u5BB6\u8D26\u53F7\u4E00\u81F4\uFF1B\u8BF7\u4F7F\u7528\u8BE5\u624B\u673A\u53F7\u91CD\u65B0\u767B\u5F55\u540E\u518D\u67E5\u8BE2\u3002";
119434
+ } else {
119435
+ payload.matched = chinaPhonesEqual(me.phone, requested);
119436
+ if (!payload.matched) {
119437
+ payload.message = "\u6307\u5B9A\u624B\u673A\u53F7\u4E0E\u5F53\u524D\u767B\u5F55\u8D26\u53F7\u4E0D\u4E00\u81F4\uFF1B\u6682\u65F6\u4E0D\u652F\u6301\u67E5\u8BE2\u5176\u4ED6\u4E1D\u8DEF\u8D5E\u8D26\u53F7\u4E0B\u7684\u6570\u636E\uFF0C\u8BF7\u4F7F\u7528\u8BE5\u624B\u673A\u53F7\u91CD\u65B0\u767B\u5F55\u3002";
119438
+ }
119439
+ }
119440
+ }
119441
+ if (await emitCliJsonOrSnapshot(opts, {
119442
+ section: "account-me",
119443
+ commandLabel: "account me",
119444
+ payload
119445
+ })) {
119446
+ if (opts.checkPhone?.trim() && payload.matched === false) {
119447
+ process.exit(1);
119448
+ }
119449
+ return;
119450
+ }
119451
+ console.log("\n\u5F53\u524D\u767B\u5F55\u4E1D\u8DEF\u8D5E\u8D26\u53F7\uFF1A");
119452
+ console.log(` entityId : ${me.entityId ?? "\u2014"}`);
119453
+ console.log(` \u7528\u6237\u540D : ${me.username ?? "\u2014"}`);
119454
+ console.log(` \u624B\u673A\u53F7 : ${me.phone ?? "\u2014"}`);
119455
+ console.log(` \u90AE\u7BB1 : ${me.email ?? "\u2014"}`);
119456
+ console.log(` companyId : ${me.companyId ?? "\u2014"}`);
119457
+ console.log();
119458
+ if (opts.checkPhone?.trim()) {
119459
+ const requested = opts.checkPhone.trim();
119460
+ if (payload.matched) {
119461
+ console.log(`\u2705 \u624B\u673A\u53F7\u6821\u9A8C\u901A\u8FC7\uFF1A\u4E0E\u5F53\u524D\u767B\u5F55\u8D26\u53F7\u4E00\u81F4\uFF08${maskPhone(me.phone)}\uFF09
119462
+ `);
119463
+ return;
119464
+ }
119465
+ console.error(
119466
+ `
119467
+ \u274C \u6682\u65F6\u4E0D\u652F\u6301\u67E5\u8BE2\u5176\u4ED6\u4E1D\u8DEF\u8D5E\u8D26\u53F7\u4E0B\u7684\u6570\u636E\u3002
119468
+ \u60A8\u6307\u5B9A\u7684\u662F\uFF1A${requested}
119469
+ \u5F53\u524D\u767B\u5F55\u8D26\u53F7\uFF1A${me.phone ?? "\uFF08\u672A\u80FD\u8BC6\u522B\u624B\u673A\u53F7\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55\uFF09"}
119470
+
119471
+ \u5982\u9700\u67E5\u8BE2\u8BE5\u8D26\u53F7\u6570\u636E\uFF0C\u8BF7\u4F7F\u7528\u8BE5\u624B\u673A\u53F7\u91CD\u65B0\u767B\u5F55\uFF1A
119472
+ 1) siluzan-tso send-login-code --phone ${requested}
119473
+ 2) siluzan-tso login --phone ${requested} --code <\u9A8C\u8BC1\u7801>
119474
+
119475
+ \u9700\u8981\u6211\u5E2E\u60A8\u5207\u6362\u767B\u5F55\u5417\uFF1F
119476
+ `
119477
+ );
119478
+ process.exit(1);
119479
+ }
119480
+ }
119481
+
119382
119482
  // src/commands/account-manage/share.ts
119383
119483
  init_auth();
119384
119484
  init_cli_json_snapshot();
@@ -120506,6 +120606,25 @@ async function runAccountBmBind(opts) {
120506
120606
  // src/commands/account-manage-register.ts
120507
120607
  function register23(program2) {
120508
120608
  const accountCmd = program2.command("account").description("\u5E7F\u544A\u8D26\u6237\u7BA1\u7406\uFF1AOAuth \u6DFB\u52A0\u6388\u6743\u3001\u89E3\u9664\u5173\u8054\uFF08\u89E3\u7ED1\uFF09\u3001Google MCC \u7ED1\u5B9A/\u89E3\u7ED1\u3001\u8D26\u53F7\u5206\u4EAB");
120609
+ accountCmd.command("me").description(
120610
+ "\u67E5\u8BE2\u5F53\u524D\u767B\u5F55\u4E1D\u8DEF\u8D5E\u8D26\u53F7\u4FE1\u606F\uFF08GET /query/account/me\uFF09\uFF1B--check-phone \u7528\u4E8E\u6821\u9A8C\u7528\u6237\u6307\u5B9A\u7684\u4F01\u4E1A\u7BA1\u5BB6\u624B\u673A\u53F7"
120611
+ ).option("-t, --token <token>", "Auth Token").option(
120612
+ "--check-phone <phone>",
120613
+ "\u4E0E\u7528\u6237\u6D88\u606F\u4E2D\u7684\u624B\u673A\u53F7\u6BD4\u5BF9\uFF1B\u4E0D\u4E00\u81F4\u65F6\u9000\u51FA\u5E76\u63D0\u793A\u5207\u6362\u767B\u5F55\uFF08\u6682\u65F6\u4E0D\u652F\u6301\u67E5\u4ED6\u6237\u6570\u636E\uFF09"
120614
+ ).option(
120615
+ "--json-out <path>",
120616
+ "\u843D\u76D8 JSON\uFF1Bstdout \u4E00\u884C\u6458\u8981\uFF1B\u914D\u5408 --check-phone \u65F6 matched=false \u5219 exit 1",
120617
+ void 0
120618
+ ).option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(
120619
+ async (opts) => {
120620
+ await runAccountMe({
120621
+ token: opts.token,
120622
+ checkPhone: opts.checkPhone,
120623
+ jsonOut: opts.jsonOut,
120624
+ verbose: opts.verbose
120625
+ });
120626
+ }
120627
+ );
120509
120628
  accountCmd.command("delink").description(
120510
120629
  "\u89E3\u9664\u6388\u6743\uFF1A\u65AD\u5F00\u5E7F\u544A\u8D26\u6237\u4E0E\u5F53\u524D\u4E1D\u8DEF\u8D5E\u8D26\u53F7\u7684\u5173\u8054\uFF08\u7F51\u9875 manageAccounts\u300C\u89E3\u9664\u6388\u6743\u300D\uFF1B--id \u6216 --ids\uFF09"
120511
120630
  ).option("--id <entityId>", "\u5355\u4E2A\u8D26\u6237 entityId\uFF08\u6765\u81EA list-accounts \u7684 ma.entityId \u5B57\u6BB5\uFF09").option("--ids <entityIds>", "\u6279\u91CF entityId\uFF0C\u9017\u53F7\u5206\u9694\uFF08\u4E0E --id \u4E8C\u9009\u4E00\uFF0C\u53EF\u540C\u65F6\u4F20\uFF09").option("-t, --token <token>", "Auth Token").option("--verbose", "\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F", false).action(async (opts) => {
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "siluzan-tso",
3
- "version": "1.1.29-beta.7",
4
- "publishedAt": 1781140799897
3
+ "version": "1.1.29-beta.8",
4
+ "publishedAt": 1781235136696
5
5
  }
@@ -285,6 +285,26 @@ siluzan-tso account-history --start 2026-03-01 --end 2026-03-31 --json-out ./sna
285
285
 
286
286
  ## account — 账号管理(OAuth 授权 / 解除关联 / Google MCC / 分享)
287
287
 
288
+ ### account me — 当前登录丝路赞账号
289
+
290
+ 查询当前凭据对应的丝路赞用户(`GET /query/account/me`)。**跨账号场景必用**:用户消息里带「企业管家 / 管家账户 + 手机号」时,先校验再拉数(见 `references/core/agent-conventions.md` §跨账号)。
291
+
292
+ ```bash
293
+ # 查看当前登录账号
294
+ siluzan-tso account me
295
+
296
+ # Agent:校验用户指定的企业管家手机号是否与当前登录一致
297
+ siluzan-tso account me --check-phone 15130150466 --json-out ./snap-me
298
+ ```
299
+
300
+ | 场景 | 行为 |
301
+ | ---- | ---- |
302
+ | 未传 `--check-phone` | 输出 entityId / 手机号 / 邮箱 / companyId |
303
+ | `--check-phone` 与当前一致 | exit 0,JSON 含 `matched: true` |
304
+ | `--check-phone` 不一致 | exit 1,提示暂不支持查他户数据,引导 `send-login-code` + `login` |
305
+
306
+ ---
307
+
288
308
  ### auth — 添加媒体平台 OAuth 授权
289
309
 
290
310
  在浏览器中打开对应媒体的 OAuth 授权页面,授权后账户自动绑定到丝路赞。
@@ -80,6 +80,14 @@
80
80
  - **CLI 输出忠实**:数值与 ID 须与本次落盘 JSON / stdout 一致,不编造示例 ID;`data` 为空时只说「当前返回无记录」并附 JSON 路径。
81
81
  - **破坏性操作必须确认 + `--commit`**:账户解绑/关闭/取消分享、BC/MCC 解绑、删除预警/报告/广告/关键词、发票申请、广告发布等。
82
82
  - **不确定时读文档**:先读对应 references 或用 `-h`,不要猜参数。
83
+ - **跨账号 / 企业管家手机号**:用户消息中出现**中国大陆 11 位手机号**(常见语境:「企业管家」「管家账户」「账号 xxx」)且意图是查**该手机号名下**的账户数据时,**必须先**执行 `siluzan-tso account me --check-phone <手机号> --json-out ./snap-me`。**禁止**在未校验通过前用当前凭据拉他户数据。
84
+ - `matched: true`(或 CLI exit 0)→ 按原工作流继续(如 P3 `accounts-digest` 查 TOP 消耗)。
85
+ - `matched: false`(CLI exit 1)→ **停止拉数**,告知用户并询问是否切换登录,话术示例:
86
+ > 暂时不支持查询其他丝路赞账号下的数据。您指定的是 **{phone}**,当前登录的是 **{currentPhone}**。
87
+ > 如需查询该账号,请使用该手机号重新登录:`send-login-code --phone {phone}` → `login --phone {phone} --code <验证码>`。
88
+ > 需要我帮您切换登录吗?
89
+ - 用户**未指定手机号** → 不校验,按当前凭据正常执行。
90
+ - 当前凭据未返回手机号且用户指定了手机号 → 视同未校验通过,引导重新用手机号登录。
83
91
  - **Google 新建搜索系列**:流程仅在 `references/google-ads/google-ads-campaign-plan.md` 维护。
84
92
  - **开户首次响应**:对话内首次进入开户话题时,**必须先**按 `references/accounts/open-account-by-media.md` §「首次响应硬规范」输出**完整必填清单**(未指明媒体则列全平台六表),再收集资料;**禁止**未列清单就执行 `open-account` 或零散追问。
85
93
  - **Google 开户**:`open-account google-wizard` 仅限真实 TTY;Agent/自动化用非交互 `open-account google ...`,审核进度用 `account-history`。
@@ -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.29-beta.7'
12
+ $PKG_VERSION = '1.1.29-beta.8'
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.29-beta.7"
12
+ readonly PKG_VERSION="1.1.29-beta.8"
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"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "siluzan-tso-cli",
3
- "version": "1.1.29-beta.7",
3
+ "version": "1.1.29-beta.8",
4
4
  "description": "Siluzan 广告账户管理 CLI — 查询账户、余额、消耗数据,管理绑定关系与充值。",
5
5
  "keywords": [
6
6
  "ad-account",