@zrhsh/wukong-cli 0.4.28 → 0.4.30

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/dist/cli.js CHANGED
@@ -172,6 +172,8 @@ var init_environments = __esm({
172
172
  displayName: "Development",
173
173
  authBaseUrl: "https://portal-dev.zrhsh.com",
174
174
  apiBaseUrl: "https://nrp-dev.zrhsh.com",
175
+ yosBaseUrl: "https://yos-dev.zrhsh.com",
176
+ srmBaseUrl: "https://srm-dev.zrhsh.com",
175
177
  clientId: "wukong-cli-dev"
176
178
  },
177
179
  beta: {
@@ -179,6 +181,8 @@ var init_environments = __esm({
179
181
  displayName: "Testing",
180
182
  authBaseUrl: "https://portal-beta.zrhsh.com",
181
183
  apiBaseUrl: "https://nrp-recode.zrhsh.com",
184
+ yosBaseUrl: "https://yos-beta.zrhsh.com",
185
+ srmBaseUrl: "https://srm-recode.zrhsh.com",
182
186
  clientId: "wukong-cli-beta"
183
187
  },
184
188
  uat: {
@@ -186,6 +190,8 @@ var init_environments = __esm({
186
190
  displayName: "UAT (User Acceptance Testing)",
187
191
  authBaseUrl: "https://portal-uat.zrhsh.com",
188
192
  apiBaseUrl: "https://nrp-pd.zrhsh.com",
193
+ yosBaseUrl: "https://yos-uat.zrhsh.com",
194
+ srmBaseUrl: "https://srm-pd.zrhsh.com",
189
195
  clientId: "wukong-cli-uat"
190
196
  },
191
197
  prod: {
@@ -193,6 +199,8 @@ var init_environments = __esm({
193
199
  displayName: "Production",
194
200
  authBaseUrl: "https://portal.zrhsh.com",
195
201
  apiBaseUrl: "https://nrp.zrhsh.com",
202
+ yosBaseUrl: "https://yos.zrhsh.com",
203
+ srmBaseUrl: "https://srm.zrhsh.com",
196
204
  clientId: "wukong-cli-prod"
197
205
  }
198
206
  };
@@ -262,6 +270,9 @@ function loadConfig() {
262
270
  return {};
263
271
  }
264
272
  }
273
+ function normalizeBaseUrl(url) {
274
+ return url.replace(/\/+$/, "");
275
+ }
265
276
  function getMergedEnvironmentConfig(env) {
266
277
  const config = loadConfig();
267
278
  const defaultEnvConfig = ENVIRONMENTS[env];
@@ -290,12 +301,21 @@ function getMergedEnvironmentConfig(env) {
290
301
  return {
291
302
  name: env,
292
303
  displayName: defaultEnvConfig.displayName,
293
- authBaseUrl: envConfig.authBaseUrl,
294
- apiBaseUrl: envConfig.apiBaseUrl,
304
+ authBaseUrl: normalizeBaseUrl(envConfig.authBaseUrl),
305
+ apiBaseUrl: normalizeBaseUrl(envConfig.apiBaseUrl),
306
+ // 跨域地址允许不写,缺省沿用内置默认值
307
+ yosBaseUrl: normalizeBaseUrl(envConfig.yosBaseUrl ?? defaultEnvConfig.yosBaseUrl),
308
+ srmBaseUrl: normalizeBaseUrl(envConfig.srmBaseUrl ?? defaultEnvConfig.srmBaseUrl),
295
309
  clientId: envConfig.clientId
296
310
  };
297
311
  }
298
- return defaultEnvConfig;
312
+ return {
313
+ ...defaultEnvConfig,
314
+ authBaseUrl: normalizeBaseUrl(defaultEnvConfig.authBaseUrl),
315
+ apiBaseUrl: normalizeBaseUrl(defaultEnvConfig.apiBaseUrl),
316
+ yosBaseUrl: normalizeBaseUrl(defaultEnvConfig.yosBaseUrl),
317
+ srmBaseUrl: normalizeBaseUrl(defaultEnvConfig.srmBaseUrl)
318
+ };
299
319
  }
300
320
  function getDefaultEnvironment() {
301
321
  const envFromVar = process.env.WUKONG_CLI_ENV;
@@ -801,6 +821,7 @@ init_esm_shims();
801
821
  var VersionCache = class {
802
822
  lastCheckTime = 0;
803
823
  cachedVersion = null;
824
+ cachedHighlights = [];
804
825
  checkInterval;
805
826
  /**
806
827
  * Constructor
@@ -824,17 +845,27 @@ var VersionCache = class {
824
845
  }
825
846
  /**
826
847
  * Set cached version with timestamp
848
+ *
849
+ * @param highlights 该版本的更新要点,缺省为空数组
827
850
  */
828
- set(version) {
851
+ set(version, highlights = []) {
829
852
  this.cachedVersion = version;
853
+ this.cachedHighlights = highlights;
830
854
  this.lastCheckTime = Date.now();
831
855
  }
856
+ /**
857
+ * Get cached highlights
858
+ */
859
+ getHighlights() {
860
+ return this.cachedHighlights;
861
+ }
832
862
  /**
833
863
  * Clear cache
834
864
  */
835
865
  clear() {
836
866
  this.lastCheckTime = 0;
837
867
  this.cachedVersion = null;
868
+ this.cachedHighlights = [];
838
869
  }
839
870
  /**
840
871
  * Get time since last check
@@ -853,6 +884,10 @@ var VersionCache = class {
853
884
  get version() {
854
885
  return this.cachedVersion;
855
886
  }
887
+ /** Cached highlights */
888
+ get highlights() {
889
+ return this.cachedHighlights;
890
+ }
856
891
  };
857
892
 
858
893
  // src/utils/version/compare.ts
@@ -897,23 +932,28 @@ var VersionChecker = class {
897
932
  return {
898
933
  hasUpdate: compareVersions(cached, this.currentVersion) > 0,
899
934
  currentVersion: this.currentVersion,
900
- latestVersion: cached
935
+ latestVersion: cached,
936
+ latestHighlights: this.cache.getHighlights()
901
937
  };
902
938
  }
903
939
  }
904
- const latestVersion = await this.provider.getLatestVersion();
905
- if (!latestVersion) {
940
+ const release = this.provider.getLatestRelease ? await this.provider.getLatestRelease() : await this.provider.getLatestVersion().then(
941
+ (version) => version ? { version, highlights: [] } : null
942
+ );
943
+ if (!release) {
906
944
  return {
907
945
  hasUpdate: false,
908
946
  currentVersion: this.currentVersion,
909
- latestVersion: null
947
+ latestVersion: null,
948
+ latestHighlights: []
910
949
  };
911
950
  }
912
- this.cache.set(latestVersion);
951
+ this.cache.set(release.version, release.highlights);
913
952
  return {
914
- hasUpdate: compareVersions(latestVersion, this.currentVersion) > 0,
953
+ hasUpdate: compareVersions(release.version, this.currentVersion) > 0,
915
954
  currentVersion: this.currentVersion,
916
- latestVersion
955
+ latestVersion: release.version,
956
+ latestHighlights: release.highlights
917
957
  };
918
958
  }
919
959
  /**
@@ -923,7 +963,7 @@ var VersionChecker = class {
923
963
  try {
924
964
  const result = await this.checkForUpdate();
925
965
  if (result.hasUpdate && notifier && result.latestVersion) {
926
- notifier.notify(result.currentVersion, result.latestVersion);
966
+ notifier.notify(result.currentVersion, result.latestVersion, result.latestHighlights);
927
967
  }
928
968
  } catch (error2) {
929
969
  }
@@ -933,6 +973,7 @@ var VersionChecker = class {
933
973
  */
934
974
  clearCache() {
935
975
  this.cache.clear();
976
+ this.provider.clearCache?.();
936
977
  }
937
978
  /**
938
979
  * Get current cache info
@@ -947,17 +988,37 @@ var VersionChecker = class {
947
988
 
948
989
  // src/utils/version/provider.ts
949
990
  init_esm_shims();
950
- var NpmVersionProvider = class {
991
+ function parseHighlights(value) {
992
+ if (!Array.isArray(value)) {
993
+ return [];
994
+ }
995
+ return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter((item) => item.length > 0).slice(0, 5);
996
+ }
997
+ var NpmVersionProvider = class _NpmVersionProvider {
951
998
  constructor(packageName, registryUrl) {
952
999
  this.packageName = packageName;
953
1000
  this.registryUrl = registryUrl;
954
1001
  this.timeout = 5e3;
955
1002
  }
956
1003
  timeout;
1004
+ cachedRelease = null;
1005
+ cachedAt = 0;
1006
+ /** 同一次进程内复用结果,避免 getLatestVersion / getLatestRelease 重复请求 */
1007
+ static REUSE_MS = 6e4;
957
1008
  /**
958
1009
  * Get latest version from npm
959
1010
  */
960
1011
  async getLatestVersion() {
1012
+ const release = await this.getLatestRelease();
1013
+ return release?.version ?? null;
1014
+ }
1015
+ /**
1016
+ * 获取最新版本及其更新摘要
1017
+ */
1018
+ async getLatestRelease() {
1019
+ if (this.cachedRelease && Date.now() - this.cachedAt < _NpmVersionProvider.REUSE_MS) {
1020
+ return this.cachedRelease;
1021
+ }
961
1022
  try {
962
1023
  const controller = new AbortController();
963
1024
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
@@ -969,11 +1030,28 @@ var NpmVersionProvider = class {
969
1030
  return null;
970
1031
  }
971
1032
  const data = await response.json();
972
- return data["dist-tags"]?.latest || null;
1033
+ const version = data["dist-tags"]?.latest;
1034
+ if (!version) {
1035
+ return null;
1036
+ }
1037
+ const highlights = parseHighlights(
1038
+ data.versions?.[version]?.wukongCli?.highlights ?? data.wukongCli?.highlights
1039
+ );
1040
+ const release = { version, highlights };
1041
+ this.cachedRelease = release;
1042
+ this.cachedAt = Date.now();
1043
+ return release;
973
1044
  } catch (error2) {
974
1045
  return null;
975
1046
  }
976
1047
  }
1048
+ /**
1049
+ * 清除进程内复用缓存
1050
+ */
1051
+ clearCache() {
1052
+ this.cachedRelease = null;
1053
+ this.cachedAt = 0;
1054
+ }
977
1055
  };
978
1056
 
979
1057
  // src/utils/version/persistent-cache.ts
@@ -994,6 +1072,7 @@ var PersistentVersionCache = class extends VersionCache {
994
1072
  if (typeof data.lastCheckTime === "number" && typeof data.version === "string") {
995
1073
  this.lastCheckTime = data.lastCheckTime;
996
1074
  this.cachedVersion = data.version;
1075
+ this.cachedHighlights = Array.isArray(data.highlights) ? data.highlights.filter((item) => typeof item === "string") : [];
997
1076
  }
998
1077
  } catch {
999
1078
  }
@@ -1003,14 +1082,15 @@ var PersistentVersionCache = class extends VersionCache {
1003
1082
  mkdirSync(dirname(this.cacheFilePath), { recursive: true });
1004
1083
  const data = {
1005
1084
  lastCheckTime: this.lastCheckTime,
1006
- version: this.cachedVersion ?? ""
1085
+ version: this.cachedVersion ?? "",
1086
+ highlights: this.cachedHighlights
1007
1087
  };
1008
1088
  writeFileSync(this.cacheFilePath, JSON.stringify(data), "utf-8");
1009
1089
  } catch {
1010
1090
  }
1011
1091
  }
1012
- set(version) {
1013
- super.set(version);
1092
+ set(version, highlights = []) {
1093
+ super.set(version, highlights);
1014
1094
  this.saveToFile();
1015
1095
  }
1016
1096
  clear() {
@@ -1026,10 +1106,24 @@ import { join } from "path";
1026
1106
  // src/utils/version/notifier.ts
1027
1107
  init_esm_shims();
1028
1108
  import chalk2 from "chalk";
1109
+ var MAX_HIGHLIGHTS = 3;
1110
+ var SEPARATOR = "\u2500".repeat(58);
1029
1111
  var ConsoleNotifier = class {
1030
- notify(currentVersion, latestVersion) {
1031
- const message = `New version available: ${currentVersion} \u2192 ${latestVersion}, run 'wukong-cli update' to update.`;
1032
- console.log(chalk2.yellow(message));
1112
+ notify(currentVersion, latestVersion, highlights = []) {
1113
+ const lines = [
1114
+ SEPARATOR,
1115
+ `New version available: ${currentVersion} \u2192 ${latestVersion}`
1116
+ ];
1117
+ if (highlights.length > 0) {
1118
+ lines.push("\u672C\u6B21\u66F4\u65B0\uFF1A");
1119
+ for (const item of highlights.slice(0, MAX_HIGHLIGHTS)) {
1120
+ lines.push(` \u2022 ${item}`);
1121
+ }
1122
+ }
1123
+ lines.push("\u5347\u7EA7\uFF1Awukong-cli update");
1124
+ lines.push(" \u6216 npm i -g @zrhsh/wukong-cli@latest");
1125
+ lines.push(SEPARATOR);
1126
+ process.stderr.write(chalk2.yellow(lines.join("\n")) + "\n");
1033
1127
  }
1034
1128
  };
1035
1129
 
@@ -2242,6 +2336,7 @@ authCommands.command("status").description("Show authentication status").action(
2242
2336
  printEnvironmentInfo(env, envConfig.displayName);
2243
2337
  console.log(chalk5.dim(`Run: wukong-cli auth login`));
2244
2338
  console.log("");
2339
+ process.exitCode = 1;
2245
2340
  return;
2246
2341
  }
2247
2342
  try {
@@ -2266,6 +2361,7 @@ authCommands.command("status").description("Show authentication status").action(
2266
2361
  printEnvironmentInfo(env, envConfig.displayName);
2267
2362
  console.log(chalk5.dim(`Run: wukong-cli auth login`));
2268
2363
  console.log("");
2364
+ process.exitCode = 1;
2269
2365
  }
2270
2366
  } catch (error2) {
2271
2367
  if (error2 instanceof ConfigFileError) {
@@ -2273,6 +2369,7 @@ authCommands.command("status").description("Show authentication status").action(
2273
2369
  console.log("");
2274
2370
  console.log(chalk5.red(error2.toUserMessage()));
2275
2371
  console.log("");
2372
+ process.exitCode = 1;
2276
2373
  return;
2277
2374
  }
2278
2375
  console.log(chalk5.yellow(`\u2717 Not authenticated`));
@@ -2280,6 +2377,7 @@ authCommands.command("status").description("Show authentication status").action(
2280
2377
  printEnvironmentInfo(env, envConfig.displayName);
2281
2378
  console.log(chalk5.dim(`Run: wukong-cli auth login`));
2282
2379
  console.log("");
2380
+ process.exitCode = 1;
2283
2381
  }
2284
2382
  });
2285
2383
  authCommands.command("token").description("Display current token structure and JWT payload claims").action(async () => {
@@ -2473,12 +2571,96 @@ function detectPageQueryEnvelope(body) {
2473
2571
  }
2474
2572
  return {
2475
2573
  code: "PAGEQUERY_ENVELOPE",
2476
- message: 'current/size \u51FA\u73B0\u5728\u8BF7\u6C42\u4F53\u9876\u5C42\uFF0C\u4F46 param \u5185\u6CA1\u6709\u5D4C\u5957\u7684\u4E1A\u52A1\u6761\u4EF6\u3002\u672C\u6846\u67B6\u7684\u5206\u9875\u67E5\u8BE2\u63A5\u53E3\u9700\u8981\u53CC\u5C42 param\uFF1A{"param":{"current":1,"size":20,"param":{...\u4E1A\u52A1\u6761\u4EF6}}}\u3002\u5199\u6210\u5355\u5C42\u65F6\u63A5\u53E3\u4ECD\u8FD4\u56DE 200\uFF0C\u4F46\u67E5\u8BE2\u6761\u4EF6\u4F1A\u88AB\u9759\u9ED8\u4E22\u5F03\u5E76\u8FD4\u56DE\u5168\u91CF\u6570\u636E\u3002'
2574
+ message: 'current/size \u51FA\u73B0\u5728\u8BF7\u6C42\u4F53\u9876\u5C42\uFF0C\u4E14 param \u5185\u6CA1\u6709\u5D4C\u5957\u7684\u4E1A\u52A1\u6761\u4EF6\u3002\n \u82E5\u5165\u53C2\u6765\u81EA\u7528\u6237 / \u63A5\u53E3\u6587\u6863 / \u4EE3\u7801 / \u6293\u5305 \u2192 \u4EE5\u539F\u59CB\u5165\u53C2\u4E3A\u51C6\uFF0C\u5FFD\u7565\u672C\u63D0\u793A\u3001\u539F\u6837\u4F20\u9012\u5373\u53EF\u3002\n \u53EA\u6709\u5728\u6CA1\u6709\u4EFB\u4F55\u539F\u59CB\u5165\u53C2\u3001\u4E14\u786E\u8BA4\u662F\u4E3B\u7AD9\u5206\u9875\u63A5\u53E3\u65F6\uFF0C\u624D\u5C1D\u8BD5\u53CC\u5C42 param\uFF1A\n {"param":{"current":1,"size":20,"param":{...\u4E1A\u52A1\u6761\u4EF6}}}\n \u8BD5\u5B8C\u8BF7\u6BD4\u5BF9\u7ED3\u679C\uFF08\u6539\u4E00\u4E2A\u7B5B\u9009\u6761\u4EF6\uFF0C\u770B\u603B\u6570\u662F\u5426\u53D8\u5316\uFF09\uFF0C\u5426\u5219\u53EF\u80FD 200 \u4F46\u6761\u4EF6\u88AB\u4E22\u5F03\u3002'
2477
2575
  };
2478
2576
  }
2479
2577
 
2578
+ // src/core/http/target-url.ts
2579
+ init_esm_shims();
2580
+ var MSYS_ROOT_TAIL = /^[A-Za-z]:.*\/(?:PortableGit|Git|mingw64|usr)(?=\/)/i;
2581
+ var SERVICE_SEGMENT = /^(?:oceanet|wukong|yst|yos|srm)(?:-|$)/i;
2582
+ function fixGitBashPath(input) {
2583
+ if (!input || input.startsWith("http")) {
2584
+ return input;
2585
+ }
2586
+ if (!/^[A-Za-z]:[\\/]/.test(input)) {
2587
+ return input;
2588
+ }
2589
+ const normalized = input.replace(/\\/g, "/");
2590
+ const rootMatch = normalized.match(MSYS_ROOT_TAIL);
2591
+ if (rootMatch) {
2592
+ return normalized.slice(rootMatch[0].length);
2593
+ }
2594
+ const segments = normalized.split("/");
2595
+ const serviceIndex = segments.findIndex((segment) => SERVICE_SEGMENT.test(segment));
2596
+ if (serviceIndex > 0) {
2597
+ return `/${segments.slice(serviceIndex).join("/")}`;
2598
+ }
2599
+ return input;
2600
+ }
2601
+ function joinUrl(baseUrl, path2) {
2602
+ const base = baseUrl.replace(/\/+$/, "");
2603
+ if (!path2) {
2604
+ return base;
2605
+ }
2606
+ return `${base}${path2.startsWith("/") ? path2 : `/${path2}`}`;
2607
+ }
2608
+ function isOceanetApiHost(targetUrl, apiBaseUrl) {
2609
+ try {
2610
+ return new URL(targetUrl).host.toLowerCase() === new URL(apiBaseUrl).host.toLowerCase();
2611
+ } catch {
2612
+ return false;
2613
+ }
2614
+ }
2615
+ function getHost(targetUrl) {
2616
+ try {
2617
+ return new URL(targetUrl).host.toLowerCase();
2618
+ } catch {
2619
+ return "";
2620
+ }
2621
+ }
2622
+ function resolveTokenKind(targetUrl) {
2623
+ const host = getHost(targetUrl);
2624
+ if (/^srm[.-]/i.test(host)) {
2625
+ return "yst";
2626
+ }
2627
+ if (/^yos[.-]/i.test(host)) {
2628
+ return "main";
2629
+ }
2630
+ return targetUrl.includes("/yst-") ? "yst" : "main";
2631
+ }
2632
+
2633
+ // src/core/http/response-guard.ts
2634
+ init_esm_shims();
2635
+ var AUTH_ERROR_CODES = [401, 403, 9913, 9914];
2636
+ var LOGIN_HINT = "Run: wukong-cli auth login";
2637
+ function isAuthErrorCode(code) {
2638
+ return AUTH_ERROR_CODES.includes(code);
2639
+ }
2640
+ function withLoginHint(message) {
2641
+ if (message.includes(LOGIN_HINT)) {
2642
+ return message;
2643
+ }
2644
+ return `${message}
2645
+ Hint: \u767B\u5F55\u6001\u53EF\u80FD\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55\u3002${LOGIN_HINT}`;
2646
+ }
2647
+ function looksLikeHtml(value) {
2648
+ if (typeof value !== "string") {
2649
+ return false;
2650
+ }
2651
+ const head = value.trimStart().slice(0, 64).toLowerCase();
2652
+ return head.startsWith("<!doctype html") || head.startsWith("<html");
2653
+ }
2654
+ function describeHtmlResponse() {
2655
+ return [
2656
+ "\u63A5\u53E3\u8FD4\u56DE\u7684\u662F HTML \u9875\u9762\uFF0C\u4E0D\u662F JSON\u3002",
2657
+ "\u5E38\u89C1\u539F\u56E0\uFF1A\u767B\u5F55\u6001\u5931\u6548\u88AB\u91CD\u5B9A\u5411\u5230\u767B\u5F55\u9875\u3001\u63A5\u53E3\u8DEF\u5F84\u9519\u8BEF\u3001base URL \u6307\u5411\u4E86\u524D\u7AEF\u7AD9\u70B9\u3002",
2658
+ `\u8BF7\u5148\u6267\u884C wukong-cli auth status \u786E\u8BA4\u767B\u5F55\u6001\uFF0C\u5FC5\u8981\u65F6 ${LOGIN_HINT}`
2659
+ ].join("\n");
2660
+ }
2661
+
2480
2662
  // src/commands/http.ts
2481
- function fail(message, jsonMode, errorCode = null) {
2663
+ function fail(message, jsonMode, errorCode = null, exitCode = 1) {
2482
2664
  if (jsonMode) {
2483
2665
  process.stderr.write(
2484
2666
  JSON.stringify({ error: { code: errorCode, message } }, null, 2) + "\n"
@@ -2486,16 +2668,7 @@ function fail(message, jsonMode, errorCode = null) {
2486
2668
  } else {
2487
2669
  console.error(chalk6.red(message));
2488
2670
  }
2489
- process.exit(1);
2490
- }
2491
- function fixGitBashPath(url) {
2492
- if (url.includes(":") && !url.startsWith("http")) {
2493
- const oceanetIndex = url.indexOf("/oceanet-");
2494
- if (oceanetIndex >= 0) {
2495
- return url.substring(oceanetIndex);
2496
- }
2497
- }
2498
- return url;
2671
+ process.exit(exitCode);
2499
2672
  }
2500
2673
  function parseHeaders(headers) {
2501
2674
  const result = {};
@@ -2516,7 +2689,7 @@ function buildUrl2(url, baseUrl) {
2516
2689
  }
2517
2690
  const config = OCEANET_CONFIG();
2518
2691
  const base = baseUrl || config.API_BASE_URL;
2519
- return `${base}${cleanUrl}`;
2692
+ return joinUrl(base, cleanUrl);
2520
2693
  }
2521
2694
  function parseParams(params) {
2522
2695
  if (!params || Object.keys(params).length === 0) {
@@ -2532,6 +2705,9 @@ function warnOnPageQueryEnvelope(context) {
2532
2705
  if (!["POST", "PUT", "PATCH"].includes(context.method.toUpperCase())) {
2533
2706
  return;
2534
2707
  }
2708
+ if (!isOceanetApiHost(context.fullUrl, OCEANET_CONFIG().API_BASE_URL)) {
2709
+ return;
2710
+ }
2535
2711
  const issue = detectPageQueryEnvelope(context.data);
2536
2712
  if (!issue) {
2537
2713
  return;
@@ -2627,7 +2803,12 @@ function handleError(error2, jsonMode) {
2627
2803
  ${error2.toUserMessage()}`, jsonMode);
2628
2804
  }
2629
2805
  if (error2 instanceof ApiError) {
2630
- return fail(`API Error (code: ${error2.code}): ${error2.message}`, jsonMode, error2.code);
2806
+ const message = `API Error (code: ${error2.code}): ${error2.message}`;
2807
+ return fail(
2808
+ isAuthErrorCode(error2.code) ? withLoginHint(message) : message,
2809
+ jsonMode,
2810
+ error2.code
2811
+ );
2631
2812
  }
2632
2813
  return fail(error2 instanceof Error ? error2.message : String(error2), jsonMode);
2633
2814
  }
@@ -2635,11 +2816,6 @@ async function executeRequest(method, url, options) {
2635
2816
  const jsonMode = options.json === true;
2636
2817
  const spinner = ora4({ text: "Sending request...", isSilent: jsonMode }).start();
2637
2818
  try {
2638
- const accessToken = await getAccessToken();
2639
- if (!accessToken) {
2640
- spinner.fail("Not authenticated");
2641
- fail("Not authenticated. Please run: wukong-cli auth login", jsonMode);
2642
- }
2643
2819
  const parsed = parseRequestBody(options.data ?? "");
2644
2820
  if (parsed.error) {
2645
2821
  spinner.fail("Invalid request body");
@@ -2647,9 +2823,18 @@ async function executeRequest(method, url, options) {
2647
2823
  fail(`Invalid JSON in -d: ${parsed.error}
2648
2824
  Received: ${received}`, jsonMode);
2649
2825
  }
2826
+ const fullUrl = buildUrl2(url, options.baseUrl);
2827
+ const tokenKind = resolveTokenKind(fullUrl);
2828
+ if (tokenKind === "main") {
2829
+ const accessToken = await getAccessToken();
2830
+ if (!accessToken) {
2831
+ spinner.fail("Not authenticated");
2832
+ fail("Not authenticated. Please run: wukong-cli auth login", jsonMode);
2833
+ }
2834
+ }
2650
2835
  const context = {
2651
2836
  method,
2652
- fullUrl: buildUrl2(url, options.baseUrl),
2837
+ fullUrl,
2653
2838
  data: parsed.data,
2654
2839
  headers: parseHeaders(options.headers),
2655
2840
  params: options.params,
@@ -2657,7 +2842,11 @@ async function executeRequest(method, url, options) {
2657
2842
  spinner
2658
2843
  };
2659
2844
  warnOnPageQueryEnvelope(context);
2660
- const result = context.fullUrl.includes("/yst-") ? await sendWithYstToken(context) : await sendWithMainToken(context);
2845
+ const result = tokenKind === "yst" ? await sendWithYstToken(context) : await sendWithMainToken(context);
2846
+ if (looksLikeHtml(result.data)) {
2847
+ spinner.fail("Unexpected HTML response");
2848
+ fail(describeHtmlResponse(), jsonMode, null, 2);
2849
+ }
2661
2850
  spinner.succeed(`Response received (${result.duration}ms)`);
2662
2851
  renderResult(result, jsonMode);
2663
2852
  } catch (error2) {
@@ -2925,6 +3114,8 @@ function reportSwitch(name, previous) {
2925
3114
  console.log(chalk9.dim(` Environment: ${config.displayName}`));
2926
3115
  console.log(chalk9.dim(` API Base: ${config.apiBaseUrl}`));
2927
3116
  console.log(chalk9.dim(` Auth Base: ${config.authBaseUrl}`));
3117
+ console.log(chalk9.dim(` YOS Base: ${config.yosBaseUrl} ${chalk9.dim("(main token)")}`));
3118
+ console.log(chalk9.dim(` SRM Base: ${config.srmBaseUrl} ${chalk9.dim("(YST token)")}`));
2928
3119
  console.log(chalk9.dim(` Config: ${getUserConfigPath()}`));
2929
3120
  if (previous !== name) {
2930
3121
  console.log(chalk9.dim(` Previous: ${previous}`));
@@ -3006,6 +3197,8 @@ function runCurrent(json) {
3006
3197
  displayName: config.displayName,
3007
3198
  authBaseUrl: config.authBaseUrl,
3008
3199
  apiBaseUrl: config.apiBaseUrl,
3200
+ yosBaseUrl: config.yosBaseUrl,
3201
+ srmBaseUrl: config.srmBaseUrl,
3009
3202
  clientId: config.clientId
3010
3203
  },
3011
3204
  null,
@@ -3018,6 +3211,8 @@ function runCurrent(json) {
3018
3211
  console.log(`${chalk9.bold(env)} - ${chalk9.dim(config.displayName)}`);
3019
3212
  console.log(chalk9.dim(` API Base: ${config.apiBaseUrl}`));
3020
3213
  console.log(chalk9.dim(` Auth Base: ${config.authBaseUrl}`));
3214
+ console.log(chalk9.dim(` YOS Base: ${config.yosBaseUrl} (main token)`));
3215
+ console.log(chalk9.dim(` SRM Base: ${config.srmBaseUrl} (YST token)`));
3021
3216
  console.log(chalk9.dim(` Client ID: ${config.clientId}`));
3022
3217
  console.log(chalk9.dim(` Source: ${SOURCE_LABEL[source]}`));
3023
3218
  console.log("");