ali-skills 0.0.25 → 0.0.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.
@@ -2340,7 +2340,7 @@ function logSkillParseFailures(failures) {
2340
2340
  if (f.hint) M.message(import_picocolors.default.yellow(` 提示: ${f.hint}`));
2341
2341
  }
2342
2342
  }
2343
- var version$1 = "2.0.25";
2343
+ var version$1 = "2.0.27";
2344
2344
  const isCancelled$1 = (value) => typeof value === "symbol";
2345
2345
  function redactSensitiveText(text) {
2346
2346
  return text.replace(/(https?:\/\/)([^/\s:@]+)(?::([^@/\s]*))?@/gi, "$1").replace(/([?&](?:private_token|access_token|token|api_key|access_key|secret|password)=)[^&\s]+/gi, "$1***");
@@ -2531,6 +2531,18 @@ async function selectAgentsInteractive(options) {
2531
2531
  return [];
2532
2532
  }
2533
2533
  setVersion(version$1);
2534
+ function isCiEnvironment() {
2535
+ if (process.env.CI) return true;
2536
+ if (process.env.GITHUB_ACTIONS) return true;
2537
+ if (process.env.GITLAB_CI) return true;
2538
+ if (process.env.BUILDKITE) return true;
2539
+ if (process.env.JENKINS_URL) return true;
2540
+ return false;
2541
+ }
2542
+ function resolveInstallMode(options) {
2543
+ if (options.installMode) return options.installMode;
2544
+ return options.copy ? "copy" : "symlink";
2545
+ }
2534
2546
  async function handleWellKnownSkills(source, url, options, spinner) {
2535
2547
  spinner.start("Discovering skills from well-known endpoint...");
2536
2548
  const skills = await wellKnownProvider.fetchAllSkills(url);
@@ -2661,8 +2673,8 @@ async function handleWellKnownSkills(source, url, options, spinner) {
2661
2673
  }
2662
2674
  installGlobally = scope;
2663
2675
  }
2664
- let installMode = options.copy ? "copy" : "symlink";
2665
- if (!options.copy && !options.yes) {
2676
+ let installMode = resolveInstallMode(options);
2677
+ if (!options.installMode && !options.copy && !options.yes) {
2666
2678
  const modeChoice = await ve({
2667
2679
  message: "Installation method",
2668
2680
  options: getInstallMethodOptions()
@@ -2819,6 +2831,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
2819
2831
  async function runAdd(args, options = {}) {
2820
2832
  const source = args[0];
2821
2833
  let installTipShown = false;
2834
+ const ciMode = options.ci ?? isCiEnvironment();
2822
2835
  const showInstallTip = () => {
2823
2836
  if (installTipShown) return;
2824
2837
  M.message(import_picocolors.default.dim("Tip: use the --yes (-y) and --global (-g) flags to install without prompts."));
@@ -2836,6 +2849,7 @@ async function runAdd(args, options = {}) {
2836
2849
  console.log();
2837
2850
  process.exit(1);
2838
2851
  }
2852
+ if (ciMode && !options.yes) options.yes = true;
2839
2853
  if (options.all) {
2840
2854
  options.skill = ["*"];
2841
2855
  options.agent = ["*"];
@@ -3161,8 +3175,8 @@ async function runAdd(args, options = {}) {
3161
3175
  }
3162
3176
  installGlobally = scope;
3163
3177
  }
3164
- let installMode = options.copy ? "copy" : "symlink";
3165
- if (!options.copy && !options.yes) {
3178
+ let installMode = resolveInstallMode(options);
3179
+ if (!options.installMode && !options.copy && !options.yes) {
3166
3180
  const modeChoice = await ve({
3167
3181
  message: "Installation method",
3168
3182
  options: getInstallMethodOptions()
@@ -3498,6 +3512,12 @@ async function promptForFindSkills(options, targetAgents) {
3498
3512
  function parseAddOptions(args) {
3499
3513
  const options = {};
3500
3514
  const source = [];
3515
+ const installModes = [
3516
+ "symlink",
3517
+ "copy",
3518
+ "symlink-isolated",
3519
+ "copy-isolated"
3520
+ ];
3501
3521
  for (let i = 0; i < args.length; i++) {
3502
3522
  const arg = args[i];
3503
3523
  if (arg === "-g" || arg === "--global") options.global = true;
@@ -3531,7 +3551,13 @@ function parseAddOptions(args) {
3531
3551
  options.branch = args[i];
3532
3552
  } else if (arg === "--full-depth") options.fullDepth = true;
3533
3553
  else if (arg === "--copy") options.copy = true;
3534
- else if (arg && !arg.startsWith("-")) source.push(arg);
3554
+ else if (arg === "--ci") options.ci = true;
3555
+ else if (arg === "--install-mode") {
3556
+ i++;
3557
+ const mode = args[i];
3558
+ if (!mode || !installModes.includes(mode)) throw new Error(`Invalid value for --install-mode: ${mode ?? "(empty)"} (expected: symlink, copy, symlink-isolated, copy-isolated)`);
3559
+ options.installMode = mode;
3560
+ } else if (arg && !arg.startsWith("-")) source.push(arg);
3535
3561
  }
3536
3562
  return {
3537
3563
  source,
@@ -4720,6 +4746,10 @@ function readConfig() {
4720
4746
  function saveConfig(config) {
4721
4747
  safeWriteFile(CONFIG_FILE, JSON.stringify(config, null, 2));
4722
4748
  }
4749
+ function getSsoRefreshCookieTtlMs() {
4750
+ const sec = Number(process.env.ALI_SKILLS_SSO_REFRESH_COOKIE_TTL_SECONDS?.trim() || process.env.BUC_SSO_REFRESH_COOKIE_TTL_SECONDS?.trim() || "7200");
4751
+ return (Number.isFinite(sec) && sec > 0 ? sec : 7200) * 1e3;
4752
+ }
4723
4753
  function readAuth() {
4724
4754
  try {
4725
4755
  if (!existsSync(AUTH_FILE)) return null;
@@ -4951,6 +4981,9 @@ function startLocalServer() {
4951
4981
  const name = url.searchParams.get("name") || "";
4952
4982
  const privateToken = url.searchParams.get("private_token") || "";
4953
4983
  const ssoRefreshToken = url.searchParams.get("sso_refresh_token") || "";
4984
+ const ssoRtExpRaw = url.searchParams.get("sso_refresh_token_expires_at") || "";
4985
+ const ssoRtExpSec = parseInt(ssoRtExpRaw, 10);
4986
+ const ssoRefreshTokenExpiresAtMs = ssoRefreshToken && ssoRtExpRaw !== "" && Number.isFinite(ssoRtExpSec) && ssoRtExpSec > 0 ? ssoRtExpSec * 1e3 : void 0;
4954
4987
  const expiresAt = url.searchParams.get("expires_at") || "0";
4955
4988
  if (!empId || !privateToken) {
4956
4989
  res.writeHead(400, { "Content-Type": "text/html" });
@@ -5107,6 +5140,7 @@ function startLocalServer() {
5107
5140
  name,
5108
5141
  privateToken,
5109
5142
  ssoRefreshToken,
5143
+ ssoRefreshTokenExpiresAtMs,
5110
5144
  expiresAt: parseInt(expiresAt, 10)
5111
5145
  });
5112
5146
  setTimeout(() => server.close(), 1e3);
@@ -5132,13 +5166,51 @@ function openBrowser$2(url) {
5132
5166
  stdio: "ignore"
5133
5167
  });
5134
5168
  }
5135
- async function login() {
5136
- const existingAuth = readAuth();
5137
- if (existingAuth && !isAuthExpired(existingAuth)) {
5138
- console.log(`${YELLOW$3}! 您已经登录为: ${existingAuth.name} (${existingAuth.account})${RESET$3}`);
5139
- console.log();
5140
- console.log(`${DIM$3}如需重新登录,请先执行: npx ali-skills logout${RESET$3}`);
5141
- return;
5169
+ async function revokeGatewaySessionIfPossible(auth) {
5170
+ try {
5171
+ const revokeUrl = `${auth.gatewayUrl || getGatewayUrl()}/api/gateway/revoke`;
5172
+ const revokeRes = await fetch(revokeUrl, {
5173
+ method: "POST",
5174
+ headers: { "X-Private-Token": auth.privateToken }
5175
+ });
5176
+ if (revokeRes.ok) console.log(`${GREEN$2}✓ 已撤销当前网关会话${RESET$3}`);
5177
+ else if (revokeRes.status === 404) console.log(`${DIM$3}服务端暂不支持撤销网关会话,继续本机登出${RESET$3}`);
5178
+ else console.log(`${YELLOW$3}⚠️ 撤销网关会话失败,继续本机登出${RESET$3}`);
5179
+ } catch {
5180
+ console.log(`${YELLOW$3}⚠️ 撤销网关会话失败,继续本机登出${RESET$3}`);
5181
+ }
5182
+ }
5183
+ function getEffectiveSsoRefreshCookieExpiresAtMs(auth) {
5184
+ if (!auth.ssoRefreshToken?.trim()) return null;
5185
+ if (typeof auth.ssoRefreshTokenExpiresAt === "number" && auth.ssoRefreshTokenExpiresAt > 0) return auth.ssoRefreshTokenExpiresAt;
5186
+ if (typeof auth.ssoRefreshTokenFetchedAt === "number" && auth.ssoRefreshTokenFetchedAt > 0) return auth.ssoRefreshTokenFetchedAt + getSsoRefreshCookieTtlMs();
5187
+ return null;
5188
+ }
5189
+ function exitIfSsoRefreshCookieExpired(auth, opts) {
5190
+ const exp = getEffectiveSsoRefreshCookieExpiresAtMs(auth);
5191
+ if (exp === null) return;
5192
+ if (Date.now() < exp) return;
5193
+ if (!opts?.quiet) {
5194
+ console.error(`${YELLOW$3}SSO_REFRESH_TOKEN 已超过预估有效期,根域 cookie 直连会鉴权失败${RESET$3}`);
5195
+ console.log(`${DIM$3}请执行: npx ali-skills login --reauth${RESET$3}`);
5196
+ }
5197
+ process.exit(1);
5198
+ }
5199
+ async function login(options) {
5200
+ if (options?.reauth) {
5201
+ const auth = readAuth();
5202
+ if (auth) {
5203
+ await revokeGatewaySessionIfPossible(auth);
5204
+ removeAuth();
5205
+ }
5206
+ } else {
5207
+ const existingAuth = readAuth();
5208
+ if (existingAuth && !isAuthExpired(existingAuth)) {
5209
+ console.log(`${YELLOW$3}! 您已经登录为: ${existingAuth.name} (${existingAuth.account})${RESET$3}`);
5210
+ console.log();
5211
+ console.log(`${DIM$3}如需重新登录,请执行: npx ali-skills login --reauth${RESET$3}`);
5212
+ return;
5213
+ }
5142
5214
  }
5143
5215
  console.log(`${TEXT$3}正在启动本地服务...${RESET$3}`);
5144
5216
  const { port, waitForCallback, close } = await startLocalServer();
@@ -5151,7 +5223,9 @@ async function login() {
5151
5223
  openBrowser$2(loginUrl);
5152
5224
  console.log(`${TEXT$3}等待授权完成...${RESET$3}`);
5153
5225
  try {
5154
- const { empId, account, name, privateToken, ssoRefreshToken, expiresAt } = await waitForCallback();
5226
+ const { empId, account, name, privateToken, ssoRefreshToken, ssoRefreshTokenExpiresAtMs, expiresAt } = await waitForCallback();
5227
+ let ssoRtExpStored;
5228
+ if (ssoRefreshToken) ssoRtExpStored = ssoRefreshTokenExpiresAtMs ?? Date.now() + getSsoRefreshCookieTtlMs();
5155
5229
  saveAuth({
5156
5230
  empId,
5157
5231
  account,
@@ -5161,13 +5235,19 @@ async function login() {
5161
5235
  ssoRefreshToken,
5162
5236
  ssoRefreshTokenFetchedAt: ssoRefreshToken ? Date.now() : void 0,
5163
5237
  ssoRefreshTokenLastCheckedAt: ssoRefreshToken ? Date.now() : void 0,
5238
+ ssoRefreshTokenExpiresAt: ssoRtExpStored,
5164
5239
  expiresAt: expiresAt * 1e3
5165
5240
  });
5166
5241
  console.log();
5167
5242
  console.log(`${GREEN$2}✓ 登录成功!${RESET$3}`);
5168
5243
  console.log(`${TEXT$3}欢迎: ${name} (${account})${RESET$3}`);
5169
5244
  console.log(`${DIM$3}Token 有效期至: ${(/* @__PURE__ */ new Date(expiresAt * 1e3)).toLocaleDateString()}${RESET$3}`);
5170
- if (!ssoRefreshToken) console.log(`${DIM$3}注意: SSO_REFRESH_TOKEN 未获取,需要时将从服务端获取${RESET$3}`);
5245
+ if (ssoRefreshToken && ssoRtExpStored) console.log(`${DIM$3}SSO_REFRESH 预估过期: ${new Date(ssoRtExpStored).toLocaleString()}${RESET$3}`);
5246
+ if (!ssoRefreshToken) {
5247
+ console.log();
5248
+ console.log(`${YELLOW$3}⚠ SSO_REFRESH_TOKEN 获取异常:本次授权回调未携带该凭证,网关代理等依赖 SSO Cookie 的能力可能不可用${RESET$3}`);
5249
+ console.log(`${DIM$3}可尝试:在网页端(https://ali-skills.alibaba-inc.com)退出平台登录后重新执行 login 命令。同时请将此问题反馈给本工具开发者处理,感谢!${RESET$3}`);
5250
+ }
5171
5251
  } catch (error) {
5172
5252
  close();
5173
5253
  throw error;
@@ -5262,18 +5342,7 @@ async function logout(platformInput, yuqueGroup, clearAll) {
5262
5342
  return;
5263
5343
  }
5264
5344
  try {
5265
- try {
5266
- const revokeUrl = `${getGatewayUrl()}/api/gateway/revoke`;
5267
- const revokeRes = await fetch(revokeUrl, {
5268
- method: "POST",
5269
- headers: { "X-Private-Token": auth.privateToken }
5270
- });
5271
- if (revokeRes.ok) console.log(`${GREEN$2}✓ 已撤销当前网关会话${RESET$3}`);
5272
- else if (revokeRes.status === 404) console.log(`${DIM$3}服务端暂不支持撤销网关会话,继续本机登出${RESET$3}`);
5273
- else console.log(`${YELLOW$3}⚠️ 撤销网关会话失败,继续本机登出${RESET$3}`);
5274
- } catch {
5275
- console.log(`${YELLOW$3}⚠️ 撤销网关会话失败,继续本机登出${RESET$3}`);
5276
- }
5345
+ await revokeGatewaySessionIfPossible(auth);
5277
5346
  removeAuth();
5278
5347
  console.log(`${GREEN$2}✓ 已登出${RESET$3}`);
5279
5348
  } catch (error) {
@@ -5433,6 +5502,11 @@ async function status(args = {}) {
5433
5502
  console.log(` 工号: ${auth.empId}`);
5434
5503
  console.log(` 网关: ${getGatewayUrl()}`);
5435
5504
  console.log(` SSO_REFRESH_TOKEN: ${auth.ssoRefreshToken ? `${GREEN$2}已缓存${RESET$3}` : `${YELLOW$3}未缓存${RESET$3}`}`);
5505
+ const ssoRtExp = getEffectiveSsoRefreshCookieExpiresAtMs(auth);
5506
+ if (auth.ssoRefreshToken && ssoRtExp) {
5507
+ const rtDead = Date.now() >= ssoRtExp;
5508
+ console.log(` SSO_REFRESH 预估过期: ${new Date(ssoRtExp).toLocaleString()}${rtDead ? ` ${YELLOW$3}(已过期)${RESET$3}` : ""}`);
5509
+ } else if (auth.ssoRefreshToken) console.log(` SSO_REFRESH 预估过期: ${YELLOW$3}未知${RESET$3} ${DIM$3}(可 login --reauth 重新写入)${RESET$3}`);
5436
5510
  if (expired) {
5437
5511
  console.log(` Token: ${YELLOW$3}即将过期${RESET$3}`);
5438
5512
  console.log(`${TEXT$3}建议重新登录: npx ali-skills login${RESET$3}`);
@@ -5461,13 +5535,14 @@ async function ensureSsoRefreshToken() {
5461
5535
  });
5462
5536
  if (response.status === 200) {
5463
5537
  const data = await response.json();
5538
+ const mergedRtExp = typeof data.ssoRefreshTokenExpiresAt === "number" && data.ssoRefreshTokenExpiresAt > 0 ? data.ssoRefreshTokenExpiresAt : Date.now() + getSsoRefreshCookieTtlMs();
5464
5539
  saveAuth({
5465
5540
  ...auth,
5466
5541
  gatewayUrl: auth.gatewayUrl || getGatewayUrl(),
5467
5542
  ssoRefreshToken: data.ssoRefreshToken,
5468
5543
  ssoRefreshTokenFetchedAt: Date.now(),
5469
5544
  ssoRefreshTokenLastCheckedAt: Date.now(),
5470
- ssoRefreshTokenExpiresAt: data.ssoRefreshTokenExpiresAt
5545
+ ssoRefreshTokenExpiresAt: mergedRtExp
5471
5546
  });
5472
5547
  console.log(`${DIM$3}已从服务端获取 SSO_REFRESH_TOKEN${RESET$3}`);
5473
5548
  return data.ssoRefreshToken;
@@ -5768,6 +5843,13 @@ async function sendDirectRequest(targetUrl, platform, token, options) {
5768
5843
  if (!response.ok) process.exit(1);
5769
5844
  }
5770
5845
  async function sendSsoCookieDirectRequest(targetUrl, options) {
5846
+ const printReauthAndRetryHint = (location, forceStderr = false) => {
5847
+ const log = forceStderr ? console.error : console.log;
5848
+ log(`${YELLOW$2}检测到被重定向到登录页,当前 SSO_REFRESH_TOKEN 很可能已失效${RESET$2}`);
5849
+ if (location) log(`${DIM$2}Location: ${location}${RESET$2}`);
5850
+ log(`${TEXT$2}请先执行: npx ali-skills login --reauth(刷新 SSO_REFRESH_TOKEN)${RESET$2}`);
5851
+ log(`${TEXT$2}刷新后请重新发起当前请求${RESET$2}`);
5852
+ };
5771
5853
  let ssoRefreshToken = null;
5772
5854
  try {
5773
5855
  await ensureLogin();
@@ -5785,6 +5867,8 @@ async function sendSsoCookieDirectRequest(targetUrl, options) {
5785
5867
  console.log(`${TEXT$2}建议执行: npx ali-skills login${RESET$2}`);
5786
5868
  process.exit(1);
5787
5869
  }
5870
+ const authForRt = readAuth();
5871
+ if (authForRt) exitIfSsoRefreshCookieExpired(authForRt, { quiet: options.quiet });
5788
5872
  const requestHeaders = {
5789
5873
  "User-Agent": "ali-skills-cli/1.0",
5790
5874
  Cookie: `SSO_REFRESH_TOKEN=${ssoRefreshToken}`
@@ -5804,7 +5888,7 @@ async function sendSsoCookieDirectRequest(targetUrl, options) {
5804
5888
  const controller = new AbortController();
5805
5889
  const timeout = options.timeout || 3e4;
5806
5890
  const timeoutId = setTimeout(() => controller.abort(), timeout);
5807
- const { response, responseBody } = await fetchWithRedirects(targetUrl, options.method.toUpperCase(), requestHeaders, body, timeout, options.quiet);
5891
+ const { response, responseBody, loginRedirectUrl } = await fetchWithRedirects(targetUrl, options.method.toUpperCase(), requestHeaders, body, timeout, options.quiet, { stopOnAlibabaLoginRedirect: true });
5808
5892
  clearTimeout(timeoutId);
5809
5893
  if (!options.quiet) {
5810
5894
  const statusColor = response.ok ? GREEN$1 : RED$2;
@@ -5816,7 +5900,15 @@ async function sendSsoCookieDirectRequest(targetUrl, options) {
5816
5900
  console.log(`${DIM$2} 2. 目标服务未启用该认证链路${RESET$2}`);
5817
5901
  console.log(`${DIM$2} 3. 当前账号在目标系统无访问权限${RESET$2}`);
5818
5902
  console.log(`${TEXT$2}建议: 重新登录后重试,或联系目标系统确认登录态策略${RESET$2}`);
5819
- }
5903
+ } else if (loginRedirectUrl) printReauthAndRetryHint(loginRedirectUrl);
5904
+ }
5905
+ if (options.includeHeaders) {
5906
+ console.log();
5907
+ console.log(`${TEXT$2}Response Headers:${RESET$2}`);
5908
+ response.headers.forEach((value, key) => {
5909
+ console.log(` ${key}: ${value}`);
5910
+ });
5911
+ console.log();
5820
5912
  }
5821
5913
  let outputBody = responseBody;
5822
5914
  if (!options.raw && options.pretty !== false) try {
@@ -5827,7 +5919,14 @@ async function sendSsoCookieDirectRequest(targetUrl, options) {
5827
5919
  const { writeFileSync } = __require("fs");
5828
5920
  writeFileSync(options.output, outputBody);
5829
5921
  console.log(`${GREEN$1}✓ 已保存到 ${options.output}${RESET$2}`);
5830
- } else console.log(outputBody);
5922
+ } else {
5923
+ if (options.quiet && !response.ok && outputBody.trim().length === 0 && (loginRedirectUrl || response.headers.get("location"))) {
5924
+ const location = loginRedirectUrl || response.headers.get("location") || "(empty)";
5925
+ console.error(`HTTP ${response.status} ${response.statusText} (Location: ${location})`);
5926
+ printReauthAndRetryHint(location, true);
5927
+ }
5928
+ console.log(outputBody);
5929
+ }
5831
5930
  if (!response.ok) process.exit(1);
5832
5931
  }
5833
5932
  async function sendSsoTicketDirectRequest(targetUrl, options) {
@@ -5932,7 +6031,7 @@ async function sendPlainDirectRequest(targetUrl, options, allowSsoCookieFallback
5932
6031
  } else console.log(outputBody);
5933
6032
  if (!response.ok) process.exit(1);
5934
6033
  }
5935
- async function fetchWithRedirects(initialUrl, method, headers, body, timeout, quiet) {
6034
+ async function fetchWithRedirects(initialUrl, method, headers, body, timeout, quiet, opts) {
5936
6035
  const controller = new AbortController();
5937
6036
  const timeoutId = setTimeout(() => controller.abort(), timeout);
5938
6037
  let currentUrl = initialUrl;
@@ -5960,7 +6059,15 @@ async function fetchWithRedirects(initialUrl, method, headers, body, timeout, qu
5960
6059
  };
5961
6060
  if (redirects >= MAX_REDIRECTS) throw new Error(`重定向次数超过上限(${MAX_REDIRECTS})`);
5962
6061
  const nextUrl = new URL(location, currentUrl).toString();
5963
- if (new URL(nextUrl).hostname === "login.alibaba-inc.com") sawAlibabaLoginRedirect = true;
6062
+ if (new URL(nextUrl).hostname === "login.alibaba-inc.com") {
6063
+ sawAlibabaLoginRedirect = true;
6064
+ if (opts?.stopOnAlibabaLoginRedirect) return {
6065
+ response,
6066
+ responseBody: await response.text(),
6067
+ sawAlibabaLoginRedirect,
6068
+ loginRedirectUrl: nextUrl
6069
+ };
6070
+ }
5964
6071
  redirects += 1;
5965
6072
  if (!quiet) console.log(`${DIM$2}↪ 重定向 ${redirects}: ${response.status} ${response.statusText} -> ${nextUrl}${RESET$2}`);
5966
6073
  currentUrl = nextUrl;
@@ -6519,9 +6626,6 @@ ${BOLD}Manage Skills:${RESET}
6519
6626
  list, ls List installed skills
6520
6627
  find [query] Search for skills interactively
6521
6628
 
6522
- ${BOLD}Publish:${RESET}
6523
- publish [options] Publish skills from current repo to OSS (alias: pub)
6524
-
6525
6629
  ${BOLD}Updates:${RESET}
6526
6630
  check Check for available skill updates (project-level by default)
6527
6631
  check -g Check global skill updates
@@ -6532,9 +6636,7 @@ ${BOLD}Updates:${RESET}
6532
6636
  update <skill> Update specific skill(s)
6533
6637
 
6534
6638
  ${BOLD}Project:${RESET}
6535
- experimental_install Restore skills from skills-lock.json
6536
6639
  init [name] Initialize a skill (creates <name>/SKILL.md or ./SKILL.md)
6537
- experimental_sync Sync skills from node_modules into agent directories
6538
6640
 
6539
6641
  ${BOLD}Gateway:${RESET}
6540
6642
  gateway 鉴权请求能力入口(login/logout/status/req)
@@ -6548,8 +6650,10 @@ ${BOLD}Add Options:${RESET}
6548
6650
  -s, --skill <skills> Specify skill names to install (use '*' for all skills)
6549
6651
  -l, --list List available skills in the repository without installing
6550
6652
  -y, --yes Skip confirmation prompts
6653
+ --ci Enable CI mode (auto non-interactive, implies --yes)
6551
6654
  --github Force fetching from GitHub when using owner/repo shorthand
6552
- --copy Copy files instead of symlinking to agent directories
6655
+ --install-mode <mode> Install mode: symlink|copy|symlink-isolated|copy-isolated (default: symlink)
6656
+ --copy Backward-compatible alias of --install-mode copy (recommended: use --install-mode)
6553
6657
  --all Shorthand for --skill '*' --agent '*' -y
6554
6658
  --full-depth Search all subdirectories even when a root SKILL.md exists
6555
6659
 
@@ -6560,10 +6664,6 @@ ${BOLD}Remove Options:${RESET}
6560
6664
  -y, --yes Skip confirmation prompts
6561
6665
  --all Shorthand for --skill '*' --agent '*' -y
6562
6666
 
6563
- ${BOLD}Experimental Sync Options:${RESET}
6564
- -a, --agent <agents> Specify agents to install to (use '*' for all agents)
6565
- -y, --yes Skip confirmation prompts
6566
-
6567
6667
  ${BOLD}List Options:${RESET}
6568
6668
  -g, --global List global skills (default: project)
6569
6669
  -a, --agent <agents> Filter by specific agents
@@ -6573,14 +6673,12 @@ ${BOLD}Options:${RESET}
6573
6673
  --help, -h Show this help message
6574
6674
  --version, -v Show version number
6575
6675
 
6576
- ${BOLD}Debug:${RESET}
6577
- ALI_SKILLS_DEBUG_UPDATE=1 Print detailed logs for check/update diagnosis
6578
-
6579
6676
  ${BOLD}Examples:${RESET}
6580
6677
  ${DIM}$${RESET} ali-skills add group/project
6581
6678
  ${DIM}$${RESET} ali-skills add group/project -g
6582
6679
  ${DIM}$${RESET} ali-skills add group/project --agent claude-code cursor
6583
6680
  ${DIM}$${RESET} ali-skills add group/project --skill pr-review commit
6681
+ ${DIM}$${RESET} ali-skills add group/project --install-mode symlink-isolated
6584
6682
  ${DIM}$${RESET} ali-skills remove ${DIM}# interactive remove${RESET}
6585
6683
  ${DIM}$${RESET} ali-skills remove web-design ${DIM}# remove by name${RESET}
6586
6684
  ${DIM}$${RESET} ali-skills rm --global frontend-design
@@ -6593,10 +6691,7 @@ ${BOLD}Examples:${RESET}
6593
6691
  ${DIM}$${RESET} ali-skills check
6594
6692
  ${DIM}$${RESET} ali-skills check web-design react-best-practices
6595
6693
  ${DIM}$${RESET} ali-skills update
6596
- ${DIM}$${RESET} ali-skills experimental_install ${DIM}# restore from skills-lock.json${RESET}
6597
6694
  ${DIM}$${RESET} ali-skills init my-skill
6598
- ${DIM}$${RESET} ali-skills experimental_sync ${DIM}# sync from node_modules${RESET}
6599
- ${DIM}$${RESET} ali-skills experimental_sync -y ${DIM}# sync without prompts${RESET}
6600
6695
 
6601
6696
  Discover more skills at ${TEXT}https://ali-skills.alibaba-inc.com/${RESET}
6602
6697
  `);
@@ -6636,7 +6731,7 @@ function showGatewayHelp() {
6636
6731
  const platformKeysForHelp = listPlatforms().filter((p) => p.key !== "aone").map((p) => p.key).join(", ");
6637
6732
  console.log(`
6638
6733
  ${BOLD}Gateway Commands:${RESET}
6639
- login [platform] Login to Gateway or configure platform token
6734
+ login [--reauth] [platform] Login to Gateway or configure platform token; --reauth 等价于先 logout 再登录
6640
6735
  logout [platform] Logout BUC or clear platform token
6641
6736
  status [platform] [--all] Show login status, single platform, or all platform statuses
6642
6737
  request [platform] <url|path> Send HTTP request (supports platform + path shorthand)
@@ -6666,6 +6761,7 @@ ${BOLD}Request Options:${RESET}
6666
6761
 
6667
6762
  ${BOLD}Examples:${RESET}
6668
6763
  ${DIM}$${RESET} ali-skills login
6764
+ ${DIM}$${RESET} ali-skills login --reauth
6669
6765
  ${DIM}$${RESET} ali-skills login code
6670
6766
  ${DIM}$${RESET} ali-skills login yuque
6671
6767
  ${DIM}$${RESET} ali-skills login yuque group
@@ -6929,6 +7025,16 @@ function parseLogoutArgs(args) {
6929
7025
  clearAll
6930
7026
  };
6931
7027
  }
7028
+ function stripReauthFlag(args) {
7029
+ let reauth = false;
7030
+ const rest = [];
7031
+ for (const a of args) if (a === "--reauth") reauth = true;
7032
+ else rest.push(a);
7033
+ return {
7034
+ reauth,
7035
+ rest
7036
+ };
7037
+ }
6932
7038
  async function runGatewayCommand(args) {
6933
7039
  if (args.length === 0) {
6934
7040
  showGatewayHelp();
@@ -6937,11 +7043,14 @@ async function runGatewayCommand(args) {
6937
7043
  const command = args[0];
6938
7044
  const rest = args.slice(1);
6939
7045
  switch (command) {
6940
- case "login":
7046
+ case "login": {
6941
7047
  showLogo();
6942
7048
  console.log();
6943
- await login();
7049
+ const { reauth, rest: loginRest } = stripReauthFlag(rest);
7050
+ if (loginRest.length > 0) await runPlatformLogin(loginRest);
7051
+ else await login({ reauth });
6944
7052
  break;
7053
+ }
6945
7054
  case "logout": {
6946
7055
  const lo = parseLogoutArgs(rest);
6947
7056
  await logout(lo.platform, lo.yuqueGroup, lo.clearAll);
@@ -7593,7 +7702,14 @@ async function main() {
7593
7702
  case "a":
7594
7703
  case "add": {
7595
7704
  showLogo();
7596
- const { source: addSource, options: addOpts } = parseAddOptions(restArgs);
7705
+ let addParsed;
7706
+ try {
7707
+ addParsed = parseAddOptions(restArgs);
7708
+ } catch (error) {
7709
+ console.error(error instanceof Error ? error.message : "Invalid add options");
7710
+ process.exit(1);
7711
+ }
7712
+ const { source: addSource, options: addOpts } = addParsed;
7597
7713
  await runAdd(addSource, addOpts);
7598
7714
  break;
7599
7715
  }
@@ -7628,10 +7744,12 @@ async function main() {
7628
7744
  case "check":
7629
7745
  await runCheck(restArgs);
7630
7746
  break;
7631
- case "login":
7632
- if (restArgs.length > 0) await runPlatformLogin(restArgs);
7633
- else await login();
7747
+ case "login": {
7748
+ const { reauth, rest: loginRest } = stripReauthFlag(restArgs);
7749
+ if (loginRest.length > 0) await runPlatformLogin(loginRest);
7750
+ else await login({ reauth });
7634
7751
  break;
7752
+ }
7635
7753
  case "logout": {
7636
7754
  const lo = parseLogoutArgs(restArgs);
7637
7755
  await logout(lo.platform, lo.yuqueGroup, lo.clearAll);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ali/cli-skills",
3
- "version": "2.0.25",
3
+ "version": "2.0.27",
4
4
  "description": "The open agent skills ecosystem",
5
5
  "type": "module",
6
6
  "bin": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ali-skills",
3
- "version": "0.0.25",
3
+ "version": "0.0.26",
4
4
  "description": "The open agent skills ecosystem",
5
5
  "type": "module",
6
6
  "bin": {
@@ -31,7 +31,7 @@
31
31
  "author": "",
32
32
  "license": "MIT",
33
33
  "dependencies": {
34
- "@ali/cli-skills": "^2.0.25"
34
+ "@ali/cli-skills": "^2.0.27"
35
35
  },
36
36
  "bundleDependencies": [
37
37
  "@ali/cli-skills"