siluzan-tso-cli 1.1.54-beta.1 → 1.1.54-beta.2

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.54-beta.1),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
54
+ > **注意**:当前为测试版(1.1.54-beta.2),供内部测试使用。正式发布后安装命令将改为 `npm install -g siluzan-tso-cli`。
55
55
 
56
56
  | 助手 | 建议 `--ai` |
57
57
  | ----------------------- | ------------------------------------ |
package/dist/index.js CHANGED
@@ -4399,6 +4399,16 @@ var init_fetch_wrapper = __esm({
4399
4399
  });
4400
4400
 
4401
4401
  // src/utils/auth.ts
4402
+ function requireWhitelistedBase(label, raw) {
4403
+ const trimmed = raw.trim().replace(/\/$/, "");
4404
+ const err = validateBaseUrl(trimmed);
4405
+ if (err) {
4406
+ console.error(`
4407
+ \u274C ${label} \u4E0D\u5408\u6CD5\uFF1A${err}`);
4408
+ process.exit(1);
4409
+ }
4410
+ return trimmed;
4411
+ }
4402
4412
  function loadConfig(tokenArg) {
4403
4413
  const shared = readSharedConfig();
4404
4414
  const { authToken, apiKey } = resolveSiluzanCredentials({
@@ -4409,27 +4419,18 @@ function loadConfig(tokenArg) {
4409
4419
  if (!apiKey && !authToken) {
4410
4420
  printAuthMissingHelp("siluzan-tso");
4411
4421
  }
4412
- const apiBaseUrl = process.env.SILUZAN_TSO_API_BASE ?? DEFAULT_API_BASE;
4413
- const apiErr = validateBaseUrl(apiBaseUrl);
4414
- if (apiErr) {
4415
- console.error(`
4416
- \u274C tsoApiBaseUrl \u4E0D\u5408\u6CD5\uFF1A${apiErr}`);
4417
- process.exit(1);
4418
- }
4419
- const googleApiUrl = process.env.SILUZAN_GOOGLE_API ?? deriveGoogleApiUrl(apiBaseUrl);
4420
- const googleApiErr = validateBaseUrl(googleApiUrl);
4421
- if (googleApiErr) {
4422
- console.error(`
4423
- \u274C googleApiUrl \u4E0D\u5408\u6CD5\uFF1A${googleApiErr}`);
4424
- process.exit(1);
4425
- }
4426
- const csoBaseUrl = process.env.SILUZAN_CSO_BASE ?? deriveCsoApiBaseUrl(apiBaseUrl);
4427
- const csoErr = validateBaseUrl(csoBaseUrl);
4428
- if (csoErr) {
4429
- console.error(`
4430
- \u274C csoBaseUrl \u4E0D\u5408\u6CD5\uFF1A${csoErr}`);
4431
- process.exit(1);
4432
- }
4422
+ const apiBaseUrl = requireWhitelistedBase(
4423
+ "tsoApiBaseUrl",
4424
+ process.env.SILUZAN_TSO_API_BASE ?? DEFAULT_API_BASE
4425
+ );
4426
+ const googleApiUrl = requireWhitelistedBase(
4427
+ "googleApiUrl",
4428
+ process.env.SILUZAN_GOOGLE_API ?? deriveGoogleApiUrl(apiBaseUrl)
4429
+ );
4430
+ const csoBaseUrl = requireWhitelistedBase(
4431
+ "csoBaseUrl",
4432
+ process.env.SILUZAN_CSO_BASE ?? deriveCsoApiBaseUrl(apiBaseUrl)
4433
+ );
4433
4434
  return {
4434
4435
  apiBaseUrl,
4435
4436
  authToken,
@@ -4438,9 +4439,15 @@ function loadConfig(tokenArg) {
4438
4439
  mainApiUrl: deriveMainApiUrl(apiBaseUrl),
4439
4440
  tiktokApiUrl: deriveTiktokApiUrl(apiBaseUrl),
4440
4441
  facebookApiUrl: deriveFacebookApiUrl(apiBaseUrl),
4441
- yandexApiUrl: process.env.SILUZAN_YANDEX_API ?? deriveYandexApiUrl(apiBaseUrl),
4442
+ yandexApiUrl: requireWhitelistedBase(
4443
+ "yandexApiUrl",
4444
+ process.env.SILUZAN_YANDEX_API ?? deriveYandexApiUrl(apiBaseUrl)
4445
+ ),
4442
4446
  chatGptApiUrl: deriveChatGptApiUrl(apiBaseUrl),
4443
- youtubeApiUrl: process.env.SILUZAN_YOUTUBE_API ?? deriveYouTubeApiUrl(apiBaseUrl),
4447
+ youtubeApiUrl: requireWhitelistedBase(
4448
+ "youtubeApiUrl",
4449
+ process.env.SILUZAN_YOUTUBE_API ?? deriveYouTubeApiUrl(apiBaseUrl)
4450
+ ),
4444
4451
  csoBaseUrl,
4445
4452
  dataPermission: process.env.SILUZAN_DATA_PERMISSION ?? shared.dataPermission
4446
4453
  };
@@ -106033,6 +106040,13 @@ import { Command as Command6 } from "commander";
106033
106040
 
106034
106041
  // src/commands/login/urls.ts
106035
106042
  init_defaults();
106043
+ init_auth();
106044
+ function requireTsoApiBase() {
106045
+ return requireWhitelistedBase(
106046
+ "tsoApiBaseUrl",
106047
+ process.env.SILUZAN_TSO_API_BASE ?? DEFAULT_API_BASE
106048
+ );
106049
+ }
106036
106050
  function deriveWebBaseUrl(tsoApiBase) {
106037
106051
  try {
106038
106052
  const u = new URL(tsoApiBase);
@@ -106046,7 +106060,6 @@ var WEB_BASE_URL = deriveWebBaseUrl(DEFAULT_API_BASE);
106046
106060
  var API_KEY_MANAGEMENT_URL = `${WEB_BASE_URL}/v3/foreign_trade/settings/apiKeyManagement`;
106047
106061
 
106048
106062
  // src/commands/login/send-code.ts
106049
- init_defaults();
106050
106063
  init_dist();
106051
106064
 
106052
106065
  // src/commands/login/helpers.ts
@@ -106139,7 +106152,7 @@ function normalizeBearerTokenInput(raw) {
106139
106152
  async function runSendLoginCode(opts) {
106140
106153
  if (skipAuthSetupInAgentEnv("siluzan-tso send-login-code")) return;
106141
106154
  const phone = validateAndNormalizePhone(opts.phone);
106142
- const tsoApiBase = process.env.SILUZAN_TSO_API_BASE ?? DEFAULT_API_BASE;
106155
+ const tsoApiBase = requireTsoApiBase();
106143
106156
  const ssoBaseUrl = deriveSsoBaseUrl(tsoApiBase);
106144
106157
  console.log("\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
106145
106158
  console.log(" Siluzan \u53D1\u9001\u767B\u5F55\u77ED\u4FE1\u9A8C\u8BC1\u7801");
@@ -106163,7 +106176,6 @@ async function runSendLoginCode(opts) {
106163
106176
  }
106164
106177
 
106165
106178
  // src/commands/login/phone-flow.ts
106166
- init_defaults();
106167
106179
  init_dist();
106168
106180
  async function executePhoneLoginWithVerifiedCode(phone, code, opts) {
106169
106181
  let allowedServices;
@@ -106179,7 +106191,7 @@ async function executePhoneLoginWithVerifiedCode(phone, code, opts) {
106179
106191
  if (opts.validDays !== void 0 && opts.expiresAt !== void 0) {
106180
106192
  console.warn("\u26A0\uFE0F --valid-days \u4E0E --expires-at \u540C\u65F6\u4F20\u5165\uFF0C\u5C06\u4EE5 --expires-at \u4E3A\u51C6\u3002");
106181
106193
  }
106182
- const tsoApiBase = process.env.SILUZAN_TSO_API_BASE ?? DEFAULT_API_BASE;
106194
+ const tsoApiBase = requireTsoApiBase();
106183
106195
  const ssoBaseUrl = deriveSsoBaseUrl(tsoApiBase);
106184
106196
  const csoBaseUrl = deriveCsoApiBaseUrl(tsoApiBase);
106185
106197
  const apiKeyName = opts.name ?? defaultApiKeyName();
@@ -106187,7 +106199,6 @@ async function executePhoneLoginWithVerifiedCode(phone, code, opts) {
106187
106199
  console.log(" Siluzan \u767B\u5F55\uFF08\u624B\u673A\u53F7 + \u77ED\u4FE1\u9A8C\u8BC1\u7801\uFF09");
106188
106200
  console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n");
106189
106201
  console.log(` \u624B\u673A\u53F7 : ${phone}`);
106190
- console.log(` \u9A8C\u8BC1\u7801 : ${code}`);
106191
106202
  console.log(` \u670D\u52A1\u8303\u56F4 : ${allowedServices.join(", ")}`);
106192
106203
  if (opts.expiresAt) {
106193
106204
  console.log(` \u8FC7\u671F\u65F6\u95F4 : ${opts.expiresAt}`);
@@ -106266,7 +106277,6 @@ async function runPhoneLogin(opts) {
106266
106277
  }
106267
106278
 
106268
106279
  // src/commands/login/interactive.ts
106269
- init_defaults();
106270
106280
  init_dist();
106271
106281
  import * as readline from "readline";
106272
106282
  async function runInteractiveJwtLogin() {
@@ -106377,7 +106387,7 @@ async function runInteractivePhoneLogin(menuOpts) {
106377
106387
  try {
106378
106388
  const phoneRaw = await prompt("\n\u8BF7\u8F93\u5165\u624B\u673A\u53F7\uFF08\u5927\u9646\u53F7\u7801\uFF0C\u53EF\u5E26 +86\uFF09\uFF1A");
106379
106389
  const phone = validateAndNormalizePhone(phoneRaw);
106380
- const tsoApiBase = process.env.SILUZAN_TSO_API_BASE ?? DEFAULT_API_BASE;
106390
+ const tsoApiBase = requireTsoApiBase();
106381
106391
  const ssoBaseUrl = deriveSsoBaseUrl(tsoApiBase);
106382
106392
  console.log("\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
106383
106393
  console.log(" \u53D1\u9001\u767B\u5F55\u77ED\u4FE1\u9A8C\u8BC1\u7801");
@@ -113767,6 +113777,24 @@ async function runAdKeywordDelete(opts) {
113767
113777
  \u2705 \u5173\u952E\u8BCD ${opts.id} \u5DF2\u5220\u9664
113768
113778
  `);
113769
113779
  }
113780
+ function findKeywordEditMismatches(requested, returned, changed) {
113781
+ const mismatches = [];
113782
+ const str3 = (v) => typeof v === "string" ? v.trim() : "";
113783
+ if (changed.finalUrl !== void 0 && str3(returned["finalURL"]) !== str3(requested["finalURL"])) {
113784
+ mismatches.push(
113785
+ `finalURL\uFF1A\u671F\u671B ${str3(requested["finalURL"]) || "(\u7A7A)"}\uFF0C\u5B9E\u9645 ${str3(returned["finalURL"]) || "(\u7A7A)"}`
113786
+ );
113787
+ }
113788
+ if (changed.maxCpc !== void 0 && typeof returned["maxCPC"] === "number" && returned["maxCPC"] !== Number(requested["maxCPC"])) {
113789
+ mismatches.push(
113790
+ `maxCPC\uFF08\u5206\uFF09\uFF1A\u671F\u671B ${String(requested["maxCPC"])}\uFF0C\u5B9E\u9645 ${String(returned["maxCPC"])}`
113791
+ );
113792
+ }
113793
+ if (changed.status !== void 0 && typeof returned["userStatusV2"] === "string" && str3(returned["userStatusV2"]).toLowerCase() !== changed.status.toLowerCase()) {
113794
+ mismatches.push(`userStatusV2\uFF1A\u671F\u671B ${changed.status}\uFF0C\u5B9E\u9645 ${str3(returned["userStatusV2"])}`);
113795
+ }
113796
+ return mismatches;
113797
+ }
113770
113798
  async function runAdKeywordEdit(opts) {
113771
113799
  opts = withResolvedAdAccount(opts);
113772
113800
  const config = await ensureDataPermission(loadConfig(opts.token));
@@ -113823,6 +113851,17 @@ async function runAdKeywordEdit(opts) {
113823
113851
  `
113824
113852
  );
113825
113853
  }
113854
+ const mismatches = first ? findKeywordEditMismatches(body, first, opts) : [];
113855
+ if (mismatches.length > 0) {
113856
+ console.error(
113857
+ `
113858
+ \u274C \u7F51\u5173\u8FD4\u56DE\u6210\u529F\uFF0C\u4F46\u4EE5\u4E0B\u5B57\u6BB5\u672A\u751F\u6548\uFF1A
113859
+ ${mismatches.map((m) => ` - ${m}`).join("\n")}
113860
+ \u8BF7\u52FF\u6539\u7528\u300C\u5220\u9664\u540E\u91CD\u5EFA\u300D\u7ED5\u8FC7\uFF08\u4F1A\u4E22\u5931\u5173\u952E\u8BCD id \u4E0E\u5386\u53F2\u6570\u636E\uFF09\uFF0C\u8BF7\u53CD\u9988\u5E73\u53F0\u6392\u67E5\u3002
113861
+ `
113862
+ );
113863
+ process.exit(1);
113864
+ }
113826
113865
  } catch (err) {
113827
113866
  console.error(`
113828
113867
  \u274C \u7F16\u8F91\u5173\u952E\u8BCD\u5931\u8D25\uFF1A${err instanceof Error ? err.message : String(err)}
@@ -131224,9 +131263,10 @@ function attachLandingPageMeta(lighthouse, resolved) {
131224
131263
 
131225
131264
  // src/commands/website-diagnosis/shared.ts
131226
131265
  init_dist();
131266
+ init_auth();
131227
131267
  function resolveAgentApiBase(tsoApiBaseUrl) {
131228
131268
  const fromEnv = process.env.SILUZAN_AGENT_BASE?.trim();
131229
- if (fromEnv) return fromEnv.replace(/\/$/, "");
131269
+ if (fromEnv) return requireWhitelistedBase("SILUZAN_AGENT_BASE", fromEnv);
131230
131270
  const base = tsoApiBaseUrl ?? "";
131231
131271
  if (base.includes("-ci") || base.includes("ci.")) {
131232
131272
  return "https://agent-ci.mysiluzan.com";
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "slug": "siluzan-tso",
3
- "version": "1.1.54-beta.1",
4
- "publishedAt": 1791792884011
3
+ "version": "1.1.54-beta.2",
4
+ "publishedAt": 1791860407374
5
5
  }
@@ -324,7 +324,7 @@ siluzan-tso ad keyword-delete -a <accountId> --id <keywordId> --adgroup-id <adGr
324
324
 
325
325
  ## ad keyword-edit — 搜索关键词编辑
326
326
 
327
- 先用 `ad keywords --json-out ./snap` 取完整对象,再提交修改。`id` 可能与请求不一致,CLI 检测到变化会提示。
327
+ 先用 `ad keywords --json-out ./snap` 取完整对象,再提交修改。只改 `--final-url` / `--max-cpc` / `--status` 时原地更新,`id` 与历史数据保留;改 `--text` / `--match-type`(Google 侧词面与匹配类型不可变)会新建并删除旧词,`id` 变化时 CLI 会提示。若回执显示字段未生效,CLI 报错退出:**不要**自行改用 `keyword-delete` + `keyword-create` 重建(丢失 id 与历史数据),应反馈平台。
328
328
 
329
329
  ```bash
330
330
  siluzan-tso ad keyword-edit \
@@ -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.54-beta.1'
12
+ $PKG_VERSION = '1.1.54-beta.2'
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.54-beta.1"
12
+ readonly PKG_VERSION="1.1.54-beta.2"
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.54-beta.1",
3
+ "version": "1.1.54-beta.2",
4
4
  "description": "Siluzan 广告账户管理 CLI — 查询账户、余额、消耗数据,管理绑定关系与充值。",
5
5
  "keywords": [
6
6
  "ad-account",