ali-skills 0.0.13 → 0.0.14

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { r as __toESM } from "./_chunks/rolldown-runtime.mjs";
2
+ import { n as __require, r as __toESM } from "./_chunks/rolldown-runtime.mjs";
3
3
  import { l as pD, u as require_picocolors } from "./_chunks/libs/@clack/core.mjs";
4
- import { a as Y, c as ve, i as Se, l as xe, n as M, o as be, r as Me, s as fe, t as Ie, u as ye } from "./_chunks/libs/@clack/prompts.mjs";
4
+ import { a as Y, c as ge, d as ye, i as Se, l as ve, n as M, o as be, r as Me, s as fe, t as Ie, u as xe } from "./_chunks/libs/@clack/prompts.mjs";
5
5
  import "./_chunks/libs/@kwsites/file-exists.mjs";
6
6
  import "./_chunks/libs/@kwsites/promise-deferred.mjs";
7
7
  import { t as esm_default } from "./_chunks/libs/simple-git.mjs";
@@ -9,15 +9,16 @@ import { t as require_gray_matter } from "./_chunks/libs/gray-matter.mjs";
9
9
  import "./_chunks/libs/extend-shallow.mjs";
10
10
  import "./_chunks/libs/esprima.mjs";
11
11
  import { t as xdgConfig } from "./_chunks/libs/xdg-basedir.mjs";
12
- import { execSync, spawn, spawnSync } from "child_process";
12
+ import { execSync, spawn } from "child_process";
13
13
  import { createWriteStream, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
14
14
  import { basename, dirname, isAbsolute, join, normalize, relative, resolve, sep } from "path";
15
15
  import { homedir, platform, tmpdir } from "os";
16
16
  import { createHash } from "crypto";
17
- import { fileURLToPath } from "url";
17
+ import { URL as URL$1, fileURLToPath } from "url";
18
18
  import * as readline from "readline";
19
19
  import { Writable } from "stream";
20
20
  import { access, cp, lstat, mkdir, mkdtemp, readFile, readdir, readlink, realpath, rm, stat, symlink, writeFile } from "fs/promises";
21
+ import * as http from "http";
21
22
  var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
22
23
  function getOwnerRepo(parsed) {
23
24
  if (parsed.type === "local") return null;
@@ -1977,6 +1978,26 @@ async function fetchSkillFolderHash(ownerRepo, skillPath, token) {
1977
1978
  }
1978
1979
  return null;
1979
1980
  }
1981
+ async function fetchAliInternalCommitHash(source, skillPath = "", token) {
1982
+ const branches = ["main", "master"];
1983
+ const privateToken = token || process.env.GITLAB_PRIVATE_TOKEN || process.env.CODE_ALIBABA_TOKEN || GITLAB_ACCOUNT.token;
1984
+ for (const branch of branches) try {
1985
+ let url = `https://code.alibaba-inc.com/api/v4/projects/${encodeURIComponent(source)}/repository/commits?ref_name=${branch}&per_page=1`;
1986
+ if (skillPath) url += `&path=${encodeURIComponent(skillPath)}`;
1987
+ const headers = {
1988
+ Accept: "application/json",
1989
+ "User-Agent": "skills-cli",
1990
+ "Private-Token": privateToken
1991
+ };
1992
+ const response = await fetch(url, { headers });
1993
+ if (!response.ok) continue;
1994
+ const data = await response.json();
1995
+ if (data && data.length > 0) return data[0].id;
1996
+ } catch {
1997
+ continue;
1998
+ }
1999
+ return null;
2000
+ }
1980
2001
  async function addSkillToLock(skillName, entry) {
1981
2002
  const lock = await readSkillLock$1();
1982
2003
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -2101,7 +2122,7 @@ function logSkillParseFailures(failures) {
2101
2122
  if (f.hint) M.message(import_picocolors.default.yellow(` 提示: ${f.hint}`));
2102
2123
  }
2103
2124
  }
2104
- var version$1 = "2.0.13";
2125
+ var version$1 = "2.0.14";
2105
2126
  const isCancelled$1 = (value) => typeof value === "symbol";
2106
2127
  async function isSourcePrivate(source) {
2107
2128
  const ownerRepo = parseOwnerRepo(source);
@@ -3108,11 +3129,25 @@ async function runAdd(args, options = {}) {
3108
3129
  const skillDisplayName = getSkillDisplayName(skill);
3109
3130
  if (successfulSkillNames.has(skillDisplayName)) try {
3110
3131
  const computedHash = await computeSkillFolderHash(skill.path);
3111
- await addSkillToLocalLock(skill.name, {
3132
+ const skillFilePath = skillFiles[skill.name];
3133
+ const lockEntry = {
3112
3134
  source: lockSource || parsed.url,
3113
3135
  sourceType: effectiveSourceType,
3114
3136
  computedHash
3115
- }, cwd);
3137
+ };
3138
+ if (effectiveSourceType === "github" && skillFilePath && normalizedSource) {
3139
+ const folderHash = await fetchSkillFolderHash(normalizedSource, skillFilePath, getGitHubToken());
3140
+ if (folderHash) lockEntry.skillFolderHash = folderHash;
3141
+ lockEntry.skillPath = skillFilePath.replace(/\/?SKILL\.md$/i, "").replace(/\/+$/, "");
3142
+ }
3143
+ if (effectiveSourceType === "internal") {
3144
+ const source = normalizedSource || getOwnerRepo(parsed) || parsed.url;
3145
+ const skillFolder = skillFilePath ? skillFilePath.replace(/\/?SKILL\.md$/i, "").replace(/\/+$/, "") : "";
3146
+ const commitHash = await fetchAliInternalCommitHash(source, skillFolder, null);
3147
+ if (commitHash) lockEntry.commitHash = commitHash;
3148
+ lockEntry.skillPath = skillFolder;
3149
+ }
3150
+ await addSkillToLocalLock(skill.name, lockEntry, cwd);
3116
3151
  } catch {}
3117
3152
  }
3118
3153
  }
@@ -3254,12 +3289,12 @@ function parseAddOptions(args) {
3254
3289
  options
3255
3290
  };
3256
3291
  }
3257
- const RESET$2 = "\x1B[0m";
3292
+ const RESET$5 = "\x1B[0m";
3258
3293
  const BOLD$2 = "\x1B[1m";
3259
- const DIM$2 = "\x1B[38;5;102m";
3260
- const TEXT$1 = "\x1B[38;5;145m";
3294
+ const DIM$5 = "\x1B[38;5;102m";
3295
+ const TEXT$4 = "\x1B[38;5;145m";
3261
3296
  const CYAN$1 = "\x1B[36m";
3262
- const YELLOW$1 = "\x1B[33m";
3297
+ const YELLOW$4 = "\x1B[33m";
3263
3298
  const SKILLS_API_URL = process.env.SKILLS_API_URL;
3264
3299
  const SEARCH_ENDPOINT = SKILLS_API_URL ? `${SKILLS_API_URL.replace(/\/+$/, "")}/search` : "https://next-ai-base.pre-fn.alibaba-inc.com/api/skills/search";
3265
3300
  function formatInstalls(count) {
@@ -3313,29 +3348,29 @@ async function runSearchPrompt(initialQuery = "") {
3313
3348
  if (lastRenderedLines > 0) process.stdout.write(MOVE_UP(lastRenderedLines) + MOVE_TO_COL(1));
3314
3349
  process.stdout.write(CLEAR_DOWN);
3315
3350
  const lines = [];
3316
- const cursor = `${BOLD$2}_${RESET$2}`;
3317
- lines.push(`${TEXT$1}Search skills:${RESET$2} ${query}${cursor}`);
3351
+ const cursor = `${BOLD$2}_${RESET$5}`;
3352
+ lines.push(`${TEXT$4}Search skills:${RESET$5} ${query}${cursor}`);
3318
3353
  lines.push("");
3319
- if (!query || query.length < 2) lines.push(`${DIM$2}Start typing to search (min 2 chars)${RESET$2}`);
3320
- else if (results.length === 0 && loading) lines.push(`${DIM$2}Searching...${RESET$2}`);
3321
- else if (results.length === 0) lines.push(`${DIM$2}No skills found${RESET$2}`);
3354
+ if (!query || query.length < 2) lines.push(`${DIM$5}Start typing to search (min 2 chars)${RESET$5}`);
3355
+ else if (results.length === 0 && loading) lines.push(`${DIM$5}Searching...${RESET$5}`);
3356
+ else if (results.length === 0) lines.push(`${DIM$5}No skills found${RESET$5}`);
3322
3357
  else {
3323
3358
  const visible = results.slice(0, 8);
3324
3359
  for (let i = 0; i < visible.length; i++) {
3325
3360
  const skill = visible[i];
3326
3361
  const isSelected = i === selectedIndex;
3327
- const arrow = isSelected ? `${BOLD$2}>${RESET$2}` : " ";
3328
- const name = isSelected ? `${BOLD$2}${skill.name}${RESET$2}` : `${TEXT$1}${skill.name}${RESET$2}`;
3329
- const source = skill.source ? ` ${DIM$2}${skill.source}${RESET$2}` : "";
3362
+ const arrow = isSelected ? `${BOLD$2}>${RESET$5}` : " ";
3363
+ const name = isSelected ? `${BOLD$2}${skill.name}${RESET$5}` : `${TEXT$4}${skill.name}${RESET$5}`;
3364
+ const source = skill.source ? ` ${DIM$5}${skill.source}${RESET$5}` : "";
3330
3365
  const installs = formatInstalls(skill.installs);
3331
- const installsBadge = installs ? ` ${CYAN$1}${installs}${RESET$2}` : "";
3332
- const githubBadge = skill.sourceType === "github" ? ` ${YELLOW$1}GitHub${RESET$2}` : "";
3333
- const loadingIndicator = loading && i === 0 ? ` ${DIM$2}...${RESET$2}` : "";
3366
+ const installsBadge = installs ? ` ${CYAN$1}${installs}${RESET$5}` : "";
3367
+ const githubBadge = skill.sourceType === "github" ? ` ${YELLOW$4}GitHub${RESET$5}` : "";
3368
+ const loadingIndicator = loading && i === 0 ? ` ${DIM$5}...${RESET$5}` : "";
3334
3369
  lines.push(` ${arrow} ${name}${source}${githubBadge}${installsBadge}${loadingIndicator}`);
3335
3370
  }
3336
3371
  }
3337
3372
  lines.push("");
3338
- lines.push(`${DIM$2}up/down navigate | enter select | esc cancel${RESET$2}`);
3373
+ lines.push(`${DIM$5}up/down navigate | enter select | esc cancel${RESET$5}`);
3339
3374
  for (const line of lines) process.stdout.write(line + "\n");
3340
3375
  lastRenderedLines = lines.length;
3341
3376
  }
@@ -3419,9 +3454,9 @@ async function runSearchPrompt(initialQuery = "") {
3419
3454
  async function runFind(args) {
3420
3455
  const query = args.join(" ");
3421
3456
  const isNonInteractive = !process.stdin.isTTY;
3422
- const agentTip = `${DIM$2}Tip: if running in a coding agent, follow these steps:${RESET$2}
3423
- ${DIM$2} 1) npx @ali/cli-skills find [query]${RESET$2}
3424
- ${DIM$2} 2) npx @ali/cli-skills add <owner/repo@skill>${RESET$2}`;
3457
+ const agentTip = `${DIM$5}Tip: if running in a coding agent, follow these steps:${RESET$5}
3458
+ ${DIM$5} 1) npx @ali/cli-skills find [query]${RESET$5}
3459
+ ${DIM$5} 2) npx @ali/cli-skills add <owner/repo@skill>${RESET$5}`;
3425
3460
  if (query) {
3426
3461
  const results = await searchSkillsAPI(query);
3427
3462
  track({
@@ -3430,18 +3465,18 @@ ${DIM$2} 2) npx @ali/cli-skills add <owner/repo@skill>${RESET$2}`;
3430
3465
  resultCount: String(results.length)
3431
3466
  });
3432
3467
  if (results.length === 0) {
3433
- console.log(`${DIM$2}No skills found for "${query}"${RESET$2}`);
3468
+ console.log(`${DIM$5}No skills found for "${query}"${RESET$5}`);
3434
3469
  return;
3435
3470
  }
3436
- console.log(`${DIM$2}Install with${RESET$2} npx ali-skills add <owner/repo>`);
3471
+ console.log(`${DIM$5}Install with${RESET$5} npx ali-skills add <owner/repo>`);
3437
3472
  console.log();
3438
3473
  for (const skill of results.slice(0, 6)) {
3439
3474
  const pkg = skill.source || skill.slug;
3440
3475
  const installs = formatInstalls(skill.installs);
3441
- const githubBadge = skill.sourceType === "github" ? ` ${YELLOW$1}GitHub${RESET$2}` : "";
3442
- console.log(`${TEXT$1}${pkg}@${skill.name}${RESET$2}${githubBadge}${installs ? ` ${CYAN$1}${installs}${RESET$2}` : ""}`);
3476
+ const githubBadge = skill.sourceType === "github" ? ` ${YELLOW$4}GitHub${RESET$5}` : "";
3477
+ console.log(`${TEXT$4}${pkg}@${skill.name}${RESET$5}${githubBadge}${installs ? ` ${CYAN$1}${installs}${RESET$5}` : ""}`);
3443
3478
  const skillUrl = buildSkillUrl(skill);
3444
- console.log(`${DIM$2}└ ${skillUrl}${RESET$2}`);
3479
+ console.log(`${DIM$5}└ ${skillUrl}${RESET$5}`);
3445
3480
  console.log();
3446
3481
  }
3447
3482
  return;
@@ -3458,14 +3493,14 @@ ${DIM$2} 2) npx @ali/cli-skills add <owner/repo@skill>${RESET$2}`;
3458
3493
  interactive: "1"
3459
3494
  });
3460
3495
  if (!selected) {
3461
- console.log(`${DIM$2}Search cancelled${RESET$2}`);
3496
+ console.log(`${DIM$5}Search cancelled${RESET$5}`);
3462
3497
  console.log();
3463
3498
  return;
3464
3499
  }
3465
3500
  const pkg = selected.source || selected.slug;
3466
3501
  const skillName = selected.name;
3467
3502
  console.log();
3468
- console.log(`${TEXT$1}Installing ${BOLD$2}${skillName}${RESET$2} from ${DIM$2}${pkg}${RESET$2}...`);
3503
+ console.log(`${TEXT$4}Installing ${BOLD$2}${skillName}${RESET$5} from ${DIM$5}${pkg}${RESET$5}...`);
3469
3504
  console.log();
3470
3505
  const { source, options } = parseAddOptions([
3471
3506
  pkg,
@@ -3475,7 +3510,7 @@ ${DIM$2} 2) npx @ali/cli-skills add <owner/repo@skill>${RESET$2}`;
3475
3510
  await runAdd(source, options);
3476
3511
  console.log();
3477
3512
  const skillUrl = buildSkillUrl(selected);
3478
- console.log(`${DIM$2}View the skill at${RESET$2} ${TEXT$1}${skillUrl}${RESET$2}`);
3513
+ console.log(`${DIM$5}View the skill at${RESET$5} ${TEXT$4}${skillUrl}${RESET$5}`);
3479
3514
  console.log();
3480
3515
  }
3481
3516
  const isCancelled = (value) => typeof value === "symbol";
@@ -3813,11 +3848,11 @@ async function runInstallFromLock(args) {
3813
3848
  }
3814
3849
  }
3815
3850
  }
3816
- const RESET$1 = "\x1B[0m";
3851
+ const RESET$4 = "\x1B[0m";
3817
3852
  const BOLD$1 = "\x1B[1m";
3818
- const DIM$1 = "\x1B[38;5;102m";
3853
+ const DIM$4 = "\x1B[38;5;102m";
3819
3854
  const CYAN = "\x1B[36m";
3820
- const YELLOW = "\x1B[33m";
3855
+ const YELLOW$3 = "\x1B[33m";
3821
3856
  function shortenPath(fullPath, cwd) {
3822
3857
  const home = homedir();
3823
3858
  if (fullPath.startsWith(home)) return fullPath.replace(home, "~");
@@ -3851,8 +3886,8 @@ async function runList(args) {
3851
3886
  const validAgents = Object.keys(agents);
3852
3887
  const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
3853
3888
  if (invalidAgents.length > 0) {
3854
- console.log(`${YELLOW}Invalid agents: ${invalidAgents.join(", ")}${RESET$1}`);
3855
- console.log(`${DIM$1}Valid agents: ${validAgents.join(", ")}${RESET$1}`);
3889
+ console.log(`${YELLOW$3}Invalid agents: ${invalidAgents.join(", ")}${RESET$4}`);
3890
+ console.log(`${DIM$4}Valid agents: ${validAgents.join(", ")}${RESET$4}`);
3856
3891
  process.exit(1);
3857
3892
  }
3858
3893
  agentFilter = options.agent;
@@ -3879,20 +3914,20 @@ async function runList(args) {
3879
3914
  console.log("[]");
3880
3915
  return;
3881
3916
  }
3882
- console.log(`${DIM$1}No ${scopeLabel.toLowerCase()} skills found.${RESET$1}`);
3883
- if (scope) console.log(`${DIM$1}Try listing project skills without -g${RESET$1}`);
3884
- else console.log(`${DIM$1}Try listing global skills with -g${RESET$1}`);
3917
+ console.log(`${DIM$4}No ${scopeLabel.toLowerCase()} skills found.${RESET$4}`);
3918
+ if (scope) console.log(`${DIM$4}Try listing project skills without -g${RESET$4}`);
3919
+ else console.log(`${DIM$4}Try listing global skills with -g${RESET$4}`);
3885
3920
  return;
3886
3921
  }
3887
3922
  function printSkill(skill, indent = false) {
3888
3923
  const prefix = indent ? " " : "";
3889
3924
  const shortPath = shortenPath(skill.canonicalPath, cwd);
3890
3925
  const agentNames = skill.agents.map((a) => agents[a].displayName);
3891
- const agentInfo = skill.agents.length > 0 ? formatList(agentNames) : `${YELLOW}not linked${RESET$1}`;
3892
- console.log(`${prefix}${CYAN}${skill.name}${RESET$1} ${DIM$1}${shortPath}${RESET$1}`);
3893
- console.log(`${prefix} ${DIM$1}Agents:${RESET$1} ${agentInfo}`);
3926
+ const agentInfo = skill.agents.length > 0 ? formatList(agentNames) : `${YELLOW$3}not linked${RESET$4}`;
3927
+ console.log(`${prefix}${CYAN}${skill.name}${RESET$4} ${DIM$4}${shortPath}${RESET$4}`);
3928
+ console.log(`${prefix} ${DIM$4}Agents:${RESET$4} ${agentInfo}`);
3894
3929
  }
3895
- console.log(`${BOLD$1}${scopeLabel} Skills${RESET$1}`);
3930
+ console.log(`${BOLD$1}${scopeLabel} Skills${RESET$4}`);
3896
3931
  console.log();
3897
3932
  const groupedSkills = {};
3898
3933
  const ungroupedSkills = [];
@@ -3908,13 +3943,13 @@ async function runList(args) {
3908
3943
  const sortedGroups = Object.keys(groupedSkills).sort();
3909
3944
  for (const group of sortedGroups) {
3910
3945
  const title = group.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
3911
- console.log(`${BOLD$1}${title}${RESET$1}`);
3946
+ console.log(`${BOLD$1}${title}${RESET$4}`);
3912
3947
  const skills = groupedSkills[group];
3913
3948
  if (skills) for (const skill of skills) printSkill(skill, true);
3914
3949
  console.log();
3915
3950
  }
3916
3951
  if (ungroupedSkills.length > 0) {
3917
- console.log(`${BOLD$1}General${RESET$1}`);
3952
+ console.log(`${BOLD$1}General${RESET$4}`);
3918
3953
  for (const skill of ungroupedSkills) printSkill(skill, true);
3919
3954
  console.log();
3920
3955
  }
@@ -4397,6 +4432,758 @@ function parsePublishOptions(args) {
4397
4432
  }
4398
4433
  return { options };
4399
4434
  }
4435
+ const CONFIG_DIR = join(homedir(), ".ali-skills");
4436
+ const CONFIG_FILE = join(CONFIG_DIR, "config.json");
4437
+ const AUTH_FILE = join(CONFIG_DIR, "auth.json");
4438
+ function ensureConfigDir() {
4439
+ if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, {
4440
+ recursive: true,
4441
+ mode: 448
4442
+ });
4443
+ }
4444
+ function safeWriteFile(path, data) {
4445
+ ensureConfigDir();
4446
+ writeFileSync(path, data, { mode: 384 });
4447
+ }
4448
+ function readConfig() {
4449
+ try {
4450
+ if (!existsSync(CONFIG_FILE)) return {
4451
+ version: 1,
4452
+ gatewayUrl: getGatewayUrl(),
4453
+ defaultTimeout: 3e4
4454
+ };
4455
+ const content = readFileSync(CONFIG_FILE, "utf-8");
4456
+ return JSON.parse(content);
4457
+ } catch {
4458
+ return {
4459
+ version: 1,
4460
+ gatewayUrl: getGatewayUrl(),
4461
+ defaultTimeout: 3e4
4462
+ };
4463
+ }
4464
+ }
4465
+ function saveConfig(config) {
4466
+ safeWriteFile(CONFIG_FILE, JSON.stringify(config, null, 2));
4467
+ }
4468
+ function readAuth() {
4469
+ try {
4470
+ if (!existsSync(AUTH_FILE)) return null;
4471
+ const content = readFileSync(AUTH_FILE, "utf-8");
4472
+ return JSON.parse(content);
4473
+ } catch {
4474
+ return null;
4475
+ }
4476
+ }
4477
+ function saveAuth(auth) {
4478
+ const data = {
4479
+ version: 1,
4480
+ ...auth
4481
+ };
4482
+ safeWriteFile(AUTH_FILE, JSON.stringify(data, null, 2));
4483
+ }
4484
+ function removeAuth() {
4485
+ try {
4486
+ if (existsSync(AUTH_FILE)) {
4487
+ const { unlinkSync } = __require("fs");
4488
+ unlinkSync(AUTH_FILE);
4489
+ }
4490
+ } catch {}
4491
+ }
4492
+ function isAuthExpired(auth) {
4493
+ return Date.now() >= auth.expiresAt - 10080 * 60 * 1e3;
4494
+ }
4495
+ function getPrivateToken() {
4496
+ return readAuth()?.privateToken || null;
4497
+ }
4498
+ function getGatewayUrl() {
4499
+ const envUrl = process.env.SKILLS_API_URL || process.env.ALI_GATEWAY_URL;
4500
+ if (envUrl) switch (envUrl.toLowerCase()) {
4501
+ case "local": return "http://localhost:3000";
4502
+ case "daily": return "https://next-ai-base.pre-fn.alibaba-inc.com";
4503
+ case "pre": return "https://ali-skills.pre.alibaba-inc.com";
4504
+ case "prod": return "https://ali-skills.alibaba-inc.com";
4505
+ default: return envUrl;
4506
+ }
4507
+ return "https://ali-skills.alibaba-inc.com";
4508
+ }
4509
+ function getConfigFilePath() {
4510
+ return CONFIG_FILE;
4511
+ }
4512
+ function setPlatformToken(platform, data) {
4513
+ const config = readConfig();
4514
+ if (!config.platforms) config.platforms = {};
4515
+ config.platforms[platform] = data;
4516
+ saveConfig(config);
4517
+ }
4518
+ function removePlatformToken(platform) {
4519
+ const config = readConfig();
4520
+ if (config.platforms && config.platforms[platform]) {
4521
+ delete config.platforms[platform];
4522
+ saveConfig(config);
4523
+ }
4524
+ }
4525
+ const DIM$3 = "\x1B[38;5;102m";
4526
+ const TEXT$3 = "\x1B[38;5;145m";
4527
+ const RESET$3 = "\x1B[0m";
4528
+ const GREEN$2 = "\x1B[32m";
4529
+ const YELLOW$2 = "\x1B[33m";
4530
+ function startLocalServer() {
4531
+ return new Promise((resolve) => {
4532
+ let resolveCallback;
4533
+ const callbackPromise = new Promise((resolve) => {
4534
+ resolveCallback = resolve;
4535
+ });
4536
+ const server = http.createServer((req, res) => {
4537
+ const url = new URL$1(req.url || "/", `http://localhost`);
4538
+ if (url.pathname === "/callback") {
4539
+ const empId = url.searchParams.get("emp_id") || "";
4540
+ const account = url.searchParams.get("account") || "";
4541
+ const name = url.searchParams.get("name") || "";
4542
+ const privateToken = url.searchParams.get("private_token") || "";
4543
+ const ssoRefreshToken = url.searchParams.get("sso_refresh_token") || "";
4544
+ const expiresAt = url.searchParams.get("expires_at") || "0";
4545
+ if (!empId || !privateToken) {
4546
+ res.writeHead(400, { "Content-Type": "text/html" });
4547
+ res.end(`
4548
+ <html>
4549
+ <body style="font-family: sans-serif; text-align: center; padding: 50px;">
4550
+ <h1 style="color: #ff4d4f;">登录失败</h1>
4551
+ <p>缺少必要的参数</p>
4552
+ </body>
4553
+ </html>
4554
+ `);
4555
+ return;
4556
+ }
4557
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
4558
+ res.end(`
4559
+ <html>
4560
+ <head><meta charset='UTF-8'><title>登录成功</title>
4561
+ <style>
4562
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; text-align: center; padding: 50px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; min-height: 100vh; margin: 0; display: flex; flex-direction: column; justify-content: center; align-items: center; }
4563
+ .card { background: rgba(255, 255, 255, 0.95); padding: 40px; border-radius: 16px; box-shadow: 0 20px 60px rgba(0,0,0,0.3); color: #333; max-width: 400px; }
4564
+ h1 { margin: 0 0 16px 0; color: #52c41a; }
4565
+ .icon { font-size: 64px; margin-bottom: 16px; }
4566
+ .user-info { background: #f6ffed; border: 1px solid #b7eb8f; border-radius: 8px; padding: 16px; margin: 16px 0; text-align: left; }
4567
+ .user-info p { margin: 8px 0; }
4568
+ .hint { color: #666; font-size: 14px; margin-top: 24px; }
4569
+ </style>
4570
+ </head>
4571
+ <body>
4572
+ <div class="card">
4573
+ <div class="icon">✓</div>
4574
+ <h1>登录成功</h1>
4575
+ <div class="user-info">
4576
+ <p><strong>姓名:</strong> ${name}</p>
4577
+ <p><strong>账号:</strong> ${account}</p>
4578
+ <p><strong>工号:</strong> ${empId}</p>
4579
+ </div>
4580
+ <p class="hint">您可以关闭此页面并返回 CLI</p>
4581
+ </div>
4582
+ </body>
4583
+ </html>
4584
+ `);
4585
+ resolveCallback({
4586
+ empId,
4587
+ account,
4588
+ name,
4589
+ privateToken,
4590
+ ssoRefreshToken,
4591
+ expiresAt: parseInt(expiresAt, 10)
4592
+ });
4593
+ setTimeout(() => server.close(), 1e3);
4594
+ } else {
4595
+ res.writeHead(404);
4596
+ res.end("Not Found");
4597
+ }
4598
+ });
4599
+ server.listen(0, "localhost", () => {
4600
+ const port = server.address().port;
4601
+ resolve({
4602
+ port,
4603
+ waitForCallback: () => callbackPromise,
4604
+ close: () => server.close()
4605
+ });
4606
+ });
4607
+ });
4608
+ }
4609
+ function openBrowser$2(url) {
4610
+ const platform = process.platform;
4611
+ spawn(platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open", [url], {
4612
+ detached: true,
4613
+ stdio: "ignore"
4614
+ });
4615
+ }
4616
+ async function login() {
4617
+ const existingAuth = readAuth();
4618
+ if (existingAuth && !isAuthExpired(existingAuth)) {
4619
+ console.log(`${TEXT$3}您已经登录为: ${existingAuth.name} (${existingAuth.account})${RESET$3}`);
4620
+ console.log(`${DIM$3}如需重新登录,请先执行: npx ali-skills logout${RESET$3}`);
4621
+ return;
4622
+ }
4623
+ console.log(`${TEXT$3}正在启动本地服务...${RESET$3}`);
4624
+ const { port, waitForCallback, close } = await startLocalServer();
4625
+ const callbackUrl = `http://localhost:${port}/callback`;
4626
+ const gatewayUrl = getGatewayUrl();
4627
+ const loginUrl = `${gatewayUrl}/api/gateway/login?callback_url=${encodeURIComponent(callbackUrl)}&type=cli`;
4628
+ console.log(`${TEXT$3}正在打开浏览器进行 BUC 授权...${RESET$3}`);
4629
+ console.log(`${DIM$3}如果浏览器没有自动打开,请手动访问:${RESET$3}`);
4630
+ console.log(`${DIM$3}${loginUrl}${RESET$3}`);
4631
+ openBrowser$2(loginUrl);
4632
+ console.log(`${TEXT$3}等待授权完成...${RESET$3}`);
4633
+ try {
4634
+ const { empId, account, name, privateToken, ssoRefreshToken, expiresAt } = await waitForCallback();
4635
+ saveAuth({
4636
+ empId,
4637
+ account,
4638
+ name,
4639
+ privateToken,
4640
+ ssoRefreshToken,
4641
+ expiresAt: expiresAt * 1e3,
4642
+ gatewayUrl
4643
+ });
4644
+ console.log();
4645
+ console.log(`${GREEN$2}✓ 登录成功!${RESET$3}`);
4646
+ console.log(`${TEXT$3}欢迎: ${name} (${account})${RESET$3}`);
4647
+ console.log(`${DIM$3}Token 有效期至: ${(/* @__PURE__ */ new Date(expiresAt * 1e3)).toLocaleDateString()}${RESET$3}`);
4648
+ if (!ssoRefreshToken) console.log(`${DIM$3}注意: SSO_REFRESH_TOKEN 未获取,需要时将从服务端获取${RESET$3}`);
4649
+ } catch (error) {
4650
+ close();
4651
+ throw error;
4652
+ }
4653
+ }
4654
+ async function logout() {
4655
+ if (!readAuth()) {
4656
+ console.log(`${DIM$3}您尚未登录${RESET$3}`);
4657
+ return;
4658
+ }
4659
+ removeAuth();
4660
+ console.log(`${GREEN$2}✓ 已登出${RESET$3}`);
4661
+ }
4662
+ async function status() {
4663
+ const auth = readAuth();
4664
+ if (!auth) {
4665
+ console.log(`${DIM$3}您尚未登录${RESET$3}`);
4666
+ console.log(`${TEXT$3}请执行: npx ali-skills login${RESET$3}`);
4667
+ return;
4668
+ }
4669
+ const expired = isAuthExpired(auth);
4670
+ const remaining = auth.expiresAt - Date.now();
4671
+ const remainingDays = Math.max(0, Math.floor(remaining / (1440 * 60 * 1e3)));
4672
+ console.log(`${TEXT$3}登录状态:${RESET$3}`);
4673
+ console.log(` 用户: ${auth.name} (${auth.account})`);
4674
+ console.log(` 工号: ${auth.empId}`);
4675
+ console.log(` 网关: ${auth.gatewayUrl}`);
4676
+ if (expired) {
4677
+ console.log(` Token: ${YELLOW$2}即将过期${RESET$3}`);
4678
+ console.log(`${TEXT$3}建议重新登录: npx ali-skills login${RESET$3}`);
4679
+ } else console.log(` Token: ${GREEN$2}有效${RESET$3} (还剩 ${remainingDays} 天)`);
4680
+ }
4681
+ async function ensureLogin() {
4682
+ const auth = readAuth();
4683
+ if (!auth) throw new Error("未登录,请先执行: npx ali-skills login");
4684
+ if (isAuthExpired(auth)) throw new Error("登录已过期,请重新执行: npx ali-skills login");
4685
+ return {
4686
+ privateToken: auth.privateToken,
4687
+ ssoRefreshToken: auth.ssoRefreshToken
4688
+ };
4689
+ }
4690
+ const PLATFORMS = {
4691
+ code: {
4692
+ name: "Code (GitLab)",
4693
+ host: "code.alibaba-inc.com",
4694
+ aliases: ["gitlab", "git"],
4695
+ authType: "private_token",
4696
+ tokenHeaderName: "PRIVATE-TOKEN",
4697
+ tokenDocUrl: "https://code.alibaba-inc.com/profile/account"
4698
+ },
4699
+ yuque: {
4700
+ name: "语雀",
4701
+ host: "aliyuque.antfin.com",
4702
+ aliases: ["yuque"],
4703
+ authType: "private_token",
4704
+ tokenHeaderName: "X-Auth-Token",
4705
+ tokenDocUrl: "https://aliyuque.antfin.com/settings/tokens"
4706
+ },
4707
+ o2: {
4708
+ name: "O2 平台",
4709
+ host: "o2.alibaba-inc.com",
4710
+ authType: "app_code+buc",
4711
+ appCode: process.env.O2_APP_CODE || "SYKcE5kklxmOS7Z2XatNn"
4712
+ },
4713
+ o2open: {
4714
+ name: "O2 开放接口",
4715
+ host: "open.o2.alibaba-inc.com",
4716
+ authType: "app_code",
4717
+ appCode: process.env.O2_APP_CODE || "cli-skills"
4718
+ },
4719
+ aone: {
4720
+ name: "Aone",
4721
+ host: "aone.alibaba-inc.com",
4722
+ authType: "buc_sso_refresh",
4723
+ ssoType: "refresh_token"
4724
+ },
4725
+ aonedevops: {
4726
+ name: "Aone DevOps",
4727
+ host: "devops.alibaba-inc.com",
4728
+ authType: "buc_sso_refresh",
4729
+ ssoType: "refresh_token"
4730
+ }
4731
+ };
4732
+ function detectPlatformWithKey(hostname) {
4733
+ for (const [key, config] of Object.entries(PLATFORMS)) {
4734
+ if (config.host === hostname) return {
4735
+ key,
4736
+ config
4737
+ };
4738
+ if (config.aliases?.some((alias) => hostname.includes(alias))) return {
4739
+ key,
4740
+ config
4741
+ };
4742
+ }
4743
+ for (const [key, config] of Object.entries(PLATFORMS)) if (hostname.endsWith(config.host) || hostname === config.host) return {
4744
+ key,
4745
+ config
4746
+ };
4747
+ return null;
4748
+ }
4749
+ function getPlatform(key) {
4750
+ if (PLATFORMS[key]) return PLATFORMS[key];
4751
+ for (const [, config] of Object.entries(PLATFORMS)) if (config.aliases?.includes(key)) return config;
4752
+ return null;
4753
+ }
4754
+ function listPlatforms() {
4755
+ return Object.entries(PLATFORMS).map(([key, config]) => ({
4756
+ key,
4757
+ config
4758
+ }));
4759
+ }
4760
+ const DIM$2 = "\x1B[38;5;102m";
4761
+ const TEXT$2 = "\x1B[38;5;145m";
4762
+ const RESET$2 = "\x1B[0m";
4763
+ const GREEN$1 = "\x1B[32m";
4764
+ const RED$1 = "\x1B[31m";
4765
+ const YELLOW$1 = "\x1B[33m";
4766
+ function openBrowser$1(url) {
4767
+ const platform = process.platform;
4768
+ spawn(platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open", [url], {
4769
+ detached: true,
4770
+ stdio: "ignore"
4771
+ });
4772
+ }
4773
+ function detectAuthMode(platformKey, platform, hostname) {
4774
+ if (platform.authType === "private_token") return "private_token";
4775
+ if (platformKey === "o2" || platform.authType === "app_code+buc") return "app_code+buc";
4776
+ if (platform.authType === "app_code") return "app_code";
4777
+ if (hostname.endsWith(".alibaba-inc.com") || hostname === "alibaba-inc.com") return "sso_cookie";
4778
+ return "sso_ticket";
4779
+ }
4780
+ function getAuthModeDescription(mode) {
4781
+ switch (mode) {
4782
+ case "private_token": return "Private Token";
4783
+ case "app_code": return "App Code";
4784
+ case "app_code+buc": return "App Code + BUC SSO";
4785
+ case "sso_cookie": return "SSO Cookie (REFRESH_TOKEN)";
4786
+ case "sso_ticket": return "SSO Ticket";
4787
+ case "gateway": return "Gateway Proxy";
4788
+ default: return "Auto";
4789
+ }
4790
+ }
4791
+ function getPlatformPrivateToken(platformKey, explicitToken) {
4792
+ if (explicitToken) return explicitToken;
4793
+ const envVarName = `ALI_SKILLS_${platformKey.toUpperCase()}_TOKEN`;
4794
+ const envToken = process.env[envVarName] || process.env[`${platformKey.toUpperCase()}_TOKEN`];
4795
+ if (envToken) return envToken;
4796
+ return readConfig().platforms?.[platformKey]?.privateToken || null;
4797
+ }
4798
+ async function promptConfigureToken(platformKey, platform) {
4799
+ console.log();
4800
+ console.log(`${YELLOW$1}⚠️ ${platform.name} 需要配置 Private Token${RESET$2}`);
4801
+ if (platform.tokenDocUrl) console.log(`${DIM$2}Token 获取地址: ${platform.tokenDocUrl}${RESET$2}`);
4802
+ if (!await ye({
4803
+ message: "是否现在配置?",
4804
+ initialValue: true
4805
+ })) {
4806
+ console.log(`${DIM$2}已取消配置${RESET$2}`);
4807
+ return null;
4808
+ }
4809
+ if (platform.tokenDocUrl) {
4810
+ console.log(`${TEXT$2}正在打开浏览器...${RESET$2}`);
4811
+ openBrowser$1(platform.tokenDocUrl);
4812
+ }
4813
+ const token = await ge({
4814
+ message: `请输入 ${platform.name} 的 Private Token:`,
4815
+ mask: "*"
4816
+ });
4817
+ if (pD(token) || !token) {
4818
+ console.log(`${DIM$2}已取消配置${RESET$2}`);
4819
+ return null;
4820
+ }
4821
+ setPlatformToken(platformKey, { privateToken: token });
4822
+ console.log(`${GREEN$1}✓ ${platform.name} Token 已保存${RESET$2}`);
4823
+ return token;
4824
+ }
4825
+ async function sendDirectRequest(targetUrl, platform, token, options) {
4826
+ const requestHeaders = {
4827
+ "User-Agent": "ali-skills-cli/1.0",
4828
+ [platform.tokenHeaderName]: token
4829
+ };
4830
+ if (options.headers) Object.entries(options.headers).forEach(([key, value]) => {
4831
+ if (key.toLowerCase() !== platform.tokenHeaderName?.toLowerCase()) requestHeaders[key] = value;
4832
+ });
4833
+ let body;
4834
+ if (options.body) {
4835
+ body = options.body;
4836
+ if (!requestHeaders["Content-Type"]) requestHeaders["Content-Type"] = "application/json";
4837
+ }
4838
+ if (!options.quiet) {
4839
+ console.log(`${DIM$2}${options.method.toUpperCase()} ${targetUrl}${RESET$2}`);
4840
+ console.log(`${DIM$2}→ 直接请求 (Header: ${platform.tokenHeaderName})${RESET$2}`);
4841
+ }
4842
+ const controller = new AbortController();
4843
+ const timeout = options.timeout || 3e4;
4844
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
4845
+ const response = await fetch(targetUrl, {
4846
+ method: options.method.toUpperCase(),
4847
+ headers: requestHeaders,
4848
+ body: body || void 0,
4849
+ signal: controller.signal
4850
+ });
4851
+ clearTimeout(timeoutId);
4852
+ const responseBody = await response.text();
4853
+ if (!options.quiet) {
4854
+ const statusColor = response.ok ? GREEN$1 : RED$1;
4855
+ console.log(`${statusColor}${response.status} ${response.statusText}${RESET$2}`);
4856
+ if (options.includeHeaders) {
4857
+ console.log();
4858
+ console.log(`${TEXT$2}Response Headers:${RESET$2}`);
4859
+ response.headers.forEach((value, key) => {
4860
+ console.log(` ${key}: ${value}`);
4861
+ });
4862
+ console.log();
4863
+ }
4864
+ }
4865
+ let outputBody = responseBody;
4866
+ if (!options.raw && options.pretty !== false) try {
4867
+ const json = JSON.parse(responseBody);
4868
+ outputBody = JSON.stringify(json, null, 2);
4869
+ } catch {}
4870
+ if (options.output) {
4871
+ const { writeFileSync } = __require("fs");
4872
+ writeFileSync(options.output, outputBody);
4873
+ console.log(`${GREEN$1}✓ 已保存到 ${options.output}${RESET$2}`);
4874
+ } else console.log(outputBody);
4875
+ if (!response.ok) process.exit(1);
4876
+ }
4877
+ async function sendGatewayRequest(targetUrl, platformKey, options, authMode = "gateway") {
4878
+ let credentials;
4879
+ try {
4880
+ credentials = await ensureLogin();
4881
+ } catch (error) {
4882
+ console.error(`${RED$1}Error: ${error.message}${RESET$2}`);
4883
+ process.exit(1);
4884
+ }
4885
+ const proxyUrl = `${getGatewayUrl()}/api/gateway/proxy`;
4886
+ const requestHeaders = {
4887
+ Authorization: `Bearer ${credentials.privateToken}`,
4888
+ "X-Private-Token": credentials.privateToken,
4889
+ "X-Target-Url": targetUrl,
4890
+ "X-Target-Method": options.method.toUpperCase(),
4891
+ "X-Platform": platformKey,
4892
+ "X-Auth-Mode": authMode
4893
+ };
4894
+ if (options.headers) Object.entries(options.headers).forEach(([key, value]) => {
4895
+ requestHeaders[key] = value;
4896
+ });
4897
+ let body;
4898
+ if (options.body) {
4899
+ body = options.body;
4900
+ if (!requestHeaders["Content-Type"]) requestHeaders["Content-Type"] = "application/json";
4901
+ }
4902
+ if (!options.quiet) {
4903
+ console.log(`${DIM$2}${options.method.toUpperCase()} ${targetUrl}${RESET$2}`);
4904
+ console.log(`${DIM$2}→ Gateway: ${proxyUrl}${RESET$2}`);
4905
+ }
4906
+ const controller = new AbortController();
4907
+ const timeout = options.timeout || 3e4;
4908
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
4909
+ const response = await fetch(proxyUrl, {
4910
+ method: "POST",
4911
+ headers: requestHeaders,
4912
+ body: body || void 0,
4913
+ signal: controller.signal
4914
+ });
4915
+ clearTimeout(timeoutId);
4916
+ if (response.status === 401) {
4917
+ if ((await response.json().catch(() => ({
4918
+ error: "Unauthorized",
4919
+ code: "UNKNOWN"
4920
+ }))).code === "INVALID_TOKEN") {
4921
+ console.error(`${RED$1}Error: Token 已失效,请重新登录${RESET$2}`);
4922
+ console.log(`${TEXT$2}执行: npx ali-skills login${RESET$2}`);
4923
+ process.exit(1);
4924
+ }
4925
+ }
4926
+ const responseBody = await response.text();
4927
+ const requestId = response.headers.get("X-Gateway-Request-Id");
4928
+ if (!options.quiet) {
4929
+ const statusColor = response.ok ? GREEN$1 : RED$1;
4930
+ console.log(`${statusColor}${response.status} ${response.statusText}${RESET$2}`);
4931
+ if (requestId) console.log(`${DIM$2}Request ID: ${requestId}${RESET$2}`);
4932
+ if (options.includeHeaders) {
4933
+ console.log();
4934
+ console.log(`${TEXT$2}Response Headers:${RESET$2}`);
4935
+ response.headers.forEach((value, key) => {
4936
+ console.log(` ${key}: ${value}`);
4937
+ });
4938
+ console.log();
4939
+ }
4940
+ }
4941
+ let outputBody = responseBody;
4942
+ if (!options.raw && options.pretty !== false) try {
4943
+ const json = JSON.parse(responseBody);
4944
+ outputBody = JSON.stringify(json, null, 2);
4945
+ } catch {}
4946
+ if (options.output) {
4947
+ const { writeFileSync } = __require("fs");
4948
+ writeFileSync(options.output, outputBody);
4949
+ console.log(`${GREEN$1}✓ 已保存到 ${options.output}${RESET$2}`);
4950
+ } else console.log(outputBody);
4951
+ if (!response.ok) process.exit(1);
4952
+ }
4953
+ async function proxyRequest(targetUrl, options) {
4954
+ let url;
4955
+ try {
4956
+ url = new URL(targetUrl);
4957
+ } catch {
4958
+ console.error(`${RED$1}Error: 无效的 URL "${targetUrl}"${RESET$2}`);
4959
+ process.exit(1);
4960
+ }
4961
+ const platformResult = detectPlatformWithKey(url.hostname);
4962
+ if (!platformResult) {
4963
+ console.error(`${RED$1}Error: 无法识别平台 "${url.hostname}"${RESET$2}`);
4964
+ console.log(`${DIM$2}支持的平台:${RESET$2}`);
4965
+ console.log(`${DIM$2} - code.alibaba-inc.com (GitLab)${RESET$2}`);
4966
+ console.log(`${DIM$2} - aliyuque.antfin.com (语雀)${RESET$2}`);
4967
+ console.log(`${DIM$2} - o2.alibaba-inc.com${RESET$2}`);
4968
+ console.log(`${DIM$2} - aone.alibaba-inc.com${RESET$2}`);
4969
+ process.exit(1);
4970
+ }
4971
+ const { key: platformKey, config: platform } = platformResult;
4972
+ if (!options.quiet) console.log(`${DIM$2}平台: ${platform.name}${RESET$2}`);
4973
+ const authMode = options.authMode === "auto" || !options.authMode ? detectAuthMode(platformKey, platform, url.hostname) : options.authMode;
4974
+ if (!options.quiet && authMode !== "auto") console.log(`${DIM$2}认证方式: ${getAuthModeDescription(authMode)}${RESET$2}`);
4975
+ try {
4976
+ switch (authMode) {
4977
+ case "private_token": {
4978
+ let token = getPlatformPrivateToken(platformKey, options.token);
4979
+ if (!token) {
4980
+ token = await promptConfigureToken(platformKey, platform);
4981
+ if (!token) {
4982
+ console.error(`${RED$1}Error: ${platform.name} 需要配置 Private Token 才能访问${RESET$2}`);
4983
+ console.log(`${DIM$2}您可以通过以下方式配置:${RESET$2}`);
4984
+ console.log(` 1. 参数: --token <your_token>`);
4985
+ console.log(` 2. 环境变量: ALI_SKILLS_${platformKey.toUpperCase()}_TOKEN=<your_token>`);
4986
+ console.log(` 3. 配置文件: npx ali-skills gateway config --platform ${platformKey}`);
4987
+ process.exit(1);
4988
+ }
4989
+ }
4990
+ await sendDirectRequest(targetUrl, platform, token, options);
4991
+ break;
4992
+ }
4993
+ case "app_code":
4994
+ case "app_code+buc":
4995
+ case "sso_cookie":
4996
+ case "sso_ticket":
4997
+ case "gateway":
4998
+ await sendGatewayRequest(targetUrl, platformKey, options, authMode);
4999
+ break;
5000
+ default: if (platform.authType === "private_token") {
5001
+ const token = getPlatformPrivateToken(platformKey, options.token);
5002
+ if (token) await sendDirectRequest(targetUrl, platform, token, options);
5003
+ else {
5004
+ console.error(`${RED$1}Error: ${platform.name} 需要配置 Private Token${RESET$2}`);
5005
+ console.log(`${DIM$2}您可以通过以下方式配置:${RESET$2}`);
5006
+ console.log(` 1. 参数: --token <your_token>`);
5007
+ console.log(` 2. 环境变量: ALI_SKILLS_${platformKey.toUpperCase()}_TOKEN=<your_token>`);
5008
+ console.log(` 3. 配置文件: npx ali-skills gateway config --platform ${platformKey}`);
5009
+ process.exit(1);
5010
+ }
5011
+ } else await sendGatewayRequest(targetUrl, platformKey, options, "gateway");
5012
+ }
5013
+ } catch (error) {
5014
+ if (error instanceof Error) if (error.name === "AbortError") console.error(`${RED$1}Error: 请求超时${RESET$2}`);
5015
+ else console.error(`${RED$1}Error: ${error.message}${RESET$2}`);
5016
+ process.exit(1);
5017
+ }
5018
+ }
5019
+ function readBodyFromFile(filePath) {
5020
+ const { readFileSync, existsSync } = __require("fs");
5021
+ const { resolve } = __require("path");
5022
+ const fullPath = resolve(filePath);
5023
+ if (!existsSync(fullPath)) throw new Error(`File not found: ${filePath}`);
5024
+ return readFileSync(fullPath, "utf-8");
5025
+ }
5026
+ const DIM$1 = "\x1B[38;5;102m";
5027
+ const TEXT$1 = "\x1B[38;5;145m";
5028
+ const RESET$1 = "\x1B[0m";
5029
+ const GREEN = "\x1B[32m";
5030
+ const YELLOW = "\x1B[33m";
5031
+ const RED = "\x1B[31m";
5032
+ function showConfigHelp() {
5033
+ console.log(`
5034
+ ${TEXT$1}npx ali-skills config - 配置各平台访问凭证${RESET$1}
5035
+
5036
+ ${DIM$1}Usage:${RESET$1}
5037
+ npx ali-skills config <platform> 配置指定平台的 token
5038
+ npx ali-skills config --list 列出已配置的平台
5039
+ npx ali-skills config --remove <p> 移除指定平台的配置
5040
+
5041
+ ${DIM$1}Supported Platforms:${RESET$1}`);
5042
+ const platforms = listPlatforms();
5043
+ const displayWidth = (str) => {
5044
+ let width = 0;
5045
+ for (const char of str) width += char.charCodeAt(0) > 127 ? 2 : 1;
5046
+ return width;
5047
+ };
5048
+ const maxNameWidth = Math.max(...platforms.map(({ config }) => displayWidth(config.name)));
5049
+ for (const { key, config } of platforms) {
5050
+ const authType = config.authType === "private_token" ? "需配置 Token" : config.authType === "app_code" ? "内置凭证" : config.authType === "buc_sso_refresh" ? "需 BUC 登录" : "需 BUC 登录";
5051
+ const namePadding = " ".repeat(15 - displayWidth(config.name) + maxNameWidth);
5052
+ console.log(` ${key.padEnd(12)} ${config.name}${namePadding} ${DIM$1}${authType}${RESET$1}`);
5053
+ }
5054
+ console.log(`
5055
+ ${DIM$1}Examples:${RESET$1}
5056
+ npx ali-skills config code
5057
+ npx ali-skills config yuque
5058
+ npx ali-skills config --list
5059
+ npx ali-skills config --remove code
5060
+ `);
5061
+ }
5062
+ async function prompt(question, defaultValue) {
5063
+ const rl = (await import("readline")).createInterface({
5064
+ input: process.stdin,
5065
+ output: process.stdout
5066
+ });
5067
+ return new Promise((resolve) => {
5068
+ const fullQuestion = defaultValue ? `${question} (默认: ${defaultValue}): ` : `${question}: `;
5069
+ rl.question(fullQuestion, (answer) => {
5070
+ rl.close();
5071
+ resolve(answer.trim() || defaultValue || "");
5072
+ });
5073
+ });
5074
+ }
5075
+ async function openBrowser(url) {
5076
+ const { spawn } = await import("node:child_process");
5077
+ const platform = process.platform;
5078
+ spawn(platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open", [url], {
5079
+ detached: true,
5080
+ stdio: "ignore"
5081
+ });
5082
+ }
5083
+ async function configurePlatform(platformKey) {
5084
+ const platform = getPlatform(platformKey);
5085
+ if (!platform) {
5086
+ console.error(`${RED}Error: 不支持的平台 "${platformKey}"${RESET$1}`);
5087
+ console.log(`${DIM$1}运行 'npx ali-skills config --list' 查看支持的平台${RESET$1}`);
5088
+ process.exit(1);
5089
+ }
5090
+ console.log(`${TEXT$1}配置 ${platform.name}${RESET$1}`);
5091
+ console.log(`${DIM$1}认证方式: ${platform.authType}${RESET$1}`);
5092
+ switch (platform.authType) {
5093
+ case "private_token":
5094
+ await configurePrivateToken(platformKey, platform);
5095
+ break;
5096
+ case "app_code":
5097
+ console.log(`${GREEN}✓ ${platform.name} 使用内置凭证,无需配置${RESET$1}`);
5098
+ break;
5099
+ case "app_code+buc":
5100
+ console.log(`${YELLOW}! ${platform.name} 需要 BUC 登录${RESET$1}`);
5101
+ console.log(`${DIM$1}请运行: npx ali-skills login${RESET$1}`);
5102
+ break;
5103
+ case "buc_sso_refresh":
5104
+ case "buc_sso_ticket":
5105
+ console.log(`${YELLOW}! ${platform.name} 需要 BUC 登录${RESET$1}`);
5106
+ console.log(`${DIM$1}请运行: npx ali-skills login${RESET$1}`);
5107
+ break;
5108
+ default:
5109
+ console.error(`${RED}Error: 未知的认证类型${RESET$1}`);
5110
+ process.exit(1);
5111
+ }
5112
+ }
5113
+ async function configurePrivateToken(platformKey, platform) {
5114
+ if (!platform.tokenDocUrl) {
5115
+ console.error(`${RED}Error: 未找到 ${platform.name} 的 token 文档地址${RESET$1}`);
5116
+ process.exit(1);
5117
+ }
5118
+ console.log();
5119
+ console.log(`${DIM$1}1. 正在打开 ${platform.name} Token 页面...${RESET$1}`);
5120
+ console.log(`${DIM$1} ${platform.tokenDocUrl}${RESET$1}`);
5121
+ await openBrowser(platform.tokenDocUrl);
5122
+ console.log();
5123
+ console.log(`${DIM$1}2. 请在浏览器中创建 Access Token,然后复制到这里${RESET$1}`);
5124
+ const token = await prompt("Access Token");
5125
+ if (!token) {
5126
+ console.error(`${RED}Error: Token 不能为空${RESET$1}`);
5127
+ process.exit(1);
5128
+ }
5129
+ setPlatformToken(platformKey, { privateToken: token });
5130
+ console.log();
5131
+ console.log(`${GREEN}✓ ${platform.name} Token 已保存${RESET$1}`);
5132
+ console.log(`${DIM$1}配置文件: ${getConfigFilePath()}${RESET$1}`);
5133
+ }
5134
+ function listConfigured() {
5135
+ const config = readConfig();
5136
+ const platforms = Object.entries(config.platforms);
5137
+ if (platforms.length === 0) {
5138
+ console.log(`${DIM$1}尚未配置任何平台${RESET$1}`);
5139
+ console.log(`${TEXT$1}运行 'npx ali-skills config <platform>' 开始配置${RESET$1}`);
5140
+ return;
5141
+ }
5142
+ console.log(`${TEXT$1}已配置的平台:${RESET$1}`);
5143
+ for (const [key, token] of platforms) {
5144
+ const name = getPlatform(key)?.name || key;
5145
+ const hasToken = token.privateToken ? "✓" : "✗";
5146
+ console.log(` ${hasToken} ${name} (${key})`);
5147
+ }
5148
+ }
5149
+ function removePlatform(platformKey) {
5150
+ const name = getPlatform(platformKey)?.name || platformKey;
5151
+ removePlatformToken(platformKey);
5152
+ console.log(`${GREEN}✓ 已移除 ${name} 的配置${RESET$1}`);
5153
+ }
5154
+ async function runConfig(args) {
5155
+ if (args.length === 0) {
5156
+ showConfigHelp();
5157
+ return;
5158
+ }
5159
+ const command = args[0];
5160
+ switch (command) {
5161
+ case "--help":
5162
+ case "-h":
5163
+ showConfigHelp();
5164
+ break;
5165
+ case "--list":
5166
+ case "-l":
5167
+ listConfigured();
5168
+ break;
5169
+ case "--remove":
5170
+ case "-r": {
5171
+ const platform = args[1];
5172
+ if (!platform) {
5173
+ console.error(`${RED}Error: 请指定要移除的平台${RESET$1}`);
5174
+ process.exit(1);
5175
+ }
5176
+ removePlatform(platform);
5177
+ break;
5178
+ }
5179
+ default: if (!command.startsWith("-")) await configurePlatform(command);
5180
+ else {
5181
+ console.error(`${RED}Error: 未知选项 "${command}"${RESET$1}`);
5182
+ showConfigHelp();
5183
+ process.exit(1);
5184
+ }
5185
+ }
5186
+ }
4400
5187
  const __dirname = dirname(fileURLToPath(import.meta.url));
4401
5188
  function getVersion() {
4402
5189
  try {
@@ -4439,32 +5226,32 @@ function showBanner() {
4439
5226
  console.log();
4440
5227
  console.log(`${DIM}The open agent skills ecosystem${RESET}`);
4441
5228
  console.log();
4442
- console.log(` ${DIM}$${RESET} ${TEXT}npx @ali/cli-skills add ${DIM}<package>${RESET} ${DIM}Add a new skill${RESET}`);
4443
- console.log(` ${DIM}$${RESET} ${TEXT}npx @ali/cli-skills remove${RESET} ${DIM}Remove installed skills${RESET}`);
4444
- console.log(` ${DIM}$${RESET} ${TEXT}npx @ali/cli-skills list${RESET} ${DIM}List installed skills${RESET}`);
4445
- console.log(` ${DIM}$${RESET} ${TEXT}npx @ali/cli-skills find ${DIM}[query]${RESET} ${DIM}Search for skills${RESET}`);
5229
+ console.log(` ${DIM}$${RESET} ${TEXT}npx ali-skills add ${DIM}<package>${RESET} ${DIM}Add a new skill${RESET}`);
5230
+ console.log(` ${DIM}$${RESET} ${TEXT}npx ali-skills remove${RESET} ${DIM}Remove installed skills${RESET}`);
5231
+ console.log(` ${DIM}$${RESET} ${TEXT}npx ali-skills list${RESET} ${DIM}List installed skills${RESET}`);
5232
+ console.log(` ${DIM}$${RESET} ${TEXT}npx ali-skills find ${DIM}[query]${RESET} ${DIM}Search for skills${RESET}`);
4446
5233
  console.log();
4447
- console.log(` ${DIM}$${RESET} ${TEXT}npx @ali/cli-skills publish${RESET} ${DIM}Publish skills to OSS${RESET}`);
5234
+ console.log(` ${DIM}$${RESET} ${TEXT}npx ali-skills publish${RESET} ${DIM}Publish skills to OSS${RESET}`);
4448
5235
  console.log();
4449
- console.log(` ${DIM}$${RESET} ${TEXT}npx @ali/cli-skills check${RESET} ${DIM}Check for updates${RESET}`);
4450
- console.log(` ${DIM}$${RESET} ${TEXT}npx @ali/cli-skills update${RESET} ${DIM}Update all skills${RESET}`);
5236
+ console.log(` ${DIM}$${RESET} ${TEXT}npx ali-skills check${RESET} ${DIM}Check for updates${RESET}`);
5237
+ console.log(` ${DIM}$${RESET} ${TEXT}npx ali-skills update${RESET} ${DIM}Update all skills${RESET}`);
4451
5238
  console.log();
4452
- console.log(` ${DIM}$${RESET} ${TEXT}npx @ali/cli-skills experimental_install${RESET} ${DIM}Restore from skills-lock.json${RESET}`);
4453
- console.log(` ${DIM}$${RESET} ${TEXT}npx @ali/cli-skills init ${DIM}[name]${RESET} ${DIM}Create a new skill${RESET}`);
4454
- console.log(` ${DIM}$${RESET} ${TEXT}npx @ali/cli-skills experimental_sync${RESET} ${DIM}Sync skills from node_modules${RESET}`);
5239
+ console.log(` ${DIM}$${RESET} ${TEXT}npx ali-skills experimental_install${RESET} ${DIM}Restore from skills-lock.json${RESET}`);
5240
+ console.log(` ${DIM}$${RESET} ${TEXT}npx ali-skills init ${DIM}[name]${RESET} ${DIM}Create a new skill${RESET}`);
5241
+ console.log(` ${DIM}$${RESET} ${TEXT}npx ali-skills experimental_sync${RESET} ${DIM}Sync skills from node_modules${RESET}`);
4455
5242
  console.log();
4456
- console.log(`${DIM}try:${RESET} npx @ali/cli-skills add vercel-labs/agent-skills`);
5243
+ console.log(`${DIM}try:${RESET} npx ali-skills add group/project`);
4457
5244
  console.log();
4458
- console.log(`Discover more skills at ${TEXT}https://skills.sh/${RESET}`);
5245
+ console.log(`Discover more skills at ${TEXT}https://ali-skills.alibaba-inc.com/${RESET}`);
4459
5246
  console.log();
4460
5247
  }
4461
5248
  function showHelp() {
4462
5249
  console.log(`
4463
- ${BOLD}Usage:${RESET} cli-skills <command> [options]
5250
+ ${BOLD}Usage:${RESET} ali-skills <command> [options]
4464
5251
 
4465
5252
  ${BOLD}Manage Skills:${RESET}
4466
5253
  add <package> Add a skill package (alias: a)
4467
- e.g. vercel-labs/agent-skills
5254
+ e.g. group/project
4468
5255
  https://github.com/vercel-labs/agent-skills
4469
5256
  remove [skills] Remove installed skills
4470
5257
  list, ls List installed skills
@@ -4474,8 +5261,12 @@ ${BOLD}Publish:${RESET}
4474
5261
  publish [options] Publish skills from current repo to OSS (alias: pub)
4475
5262
 
4476
5263
  ${BOLD}Updates:${RESET}
4477
- check Check for available skill updates
4478
- update Update all skills to latest versions
5264
+ check Check for available skill updates (project-level by default)
5265
+ check -g Check global skill updates
5266
+ update Update skills interactively (project-level by default)
5267
+ update -g Update global skills
5268
+ update -y Update all skills without prompting
5269
+ update <skill> Update specific skill(s)
4479
5270
 
4480
5271
  ${BOLD}Project:${RESET}
4481
5272
  experimental_install Restore skills from skills-lock.json
@@ -4514,32 +5305,32 @@ ${BOLD}Options:${RESET}
4514
5305
  --version, -v Show version number
4515
5306
 
4516
5307
  ${BOLD}Examples:${RESET}
4517
- ${DIM}$${RESET} cli-skills add vercel-labs/agent-skills
4518
- ${DIM}$${RESET} cli-skills add vercel-labs/agent-skills -g
4519
- ${DIM}$${RESET} cli-skills add vercel-labs/agent-skills --agent claude-code cursor
4520
- ${DIM}$${RESET} cli-skills add vercel-labs/agent-skills --skill pr-review commit
4521
- ${DIM}$${RESET} cli-skills remove ${DIM}# interactive remove${RESET}
4522
- ${DIM}$${RESET} cli-skills remove web-design ${DIM}# remove by name${RESET}
4523
- ${DIM}$${RESET} cli-skills rm --global frontend-design
4524
- ${DIM}$${RESET} cli-skills list ${DIM}# list project skills${RESET}
4525
- ${DIM}$${RESET} cli-skills ls -g ${DIM}# list global skills${RESET}
4526
- ${DIM}$${RESET} cli-skills ls -a claude-code ${DIM}# filter by agent${RESET}
4527
- ${DIM}$${RESET} cli-skills ls --json ${DIM}# JSON output${RESET}
4528
- ${DIM}$${RESET} cli-skills find ${DIM}# interactive search${RESET}
4529
- ${DIM}$${RESET} cli-skills find typescript ${DIM}# search by keyword${RESET}
4530
- ${DIM}$${RESET} cli-skills check
4531
- ${DIM}$${RESET} cli-skills update
4532
- ${DIM}$${RESET} cli-skills experimental_install ${DIM}# restore from skills-lock.json${RESET}
4533
- ${DIM}$${RESET} cli-skills init my-skill
4534
- ${DIM}$${RESET} cli-skills experimental_sync ${DIM}# sync from node_modules${RESET}
4535
- ${DIM}$${RESET} cli-skills experimental_sync -y ${DIM}# sync without prompts${RESET}
5308
+ ${DIM}$${RESET} ali-skills add group/project
5309
+ ${DIM}$${RESET} ali-skills add group/project -g
5310
+ ${DIM}$${RESET} ali-skills add group/project --agent claude-code cursor
5311
+ ${DIM}$${RESET} ali-skills add group/project --skill pr-review commit
5312
+ ${DIM}$${RESET} ali-skills remove ${DIM}# interactive remove${RESET}
5313
+ ${DIM}$${RESET} ali-skills remove web-design ${DIM}# remove by name${RESET}
5314
+ ${DIM}$${RESET} ali-skills rm --global frontend-design
5315
+ ${DIM}$${RESET} ali-skills list ${DIM}# list project skills${RESET}
5316
+ ${DIM}$${RESET} ali-skills ls -g ${DIM}# list global skills${RESET}
5317
+ ${DIM}$${RESET} ali-skills ls -a claude-code ${DIM}# filter by agent${RESET}
5318
+ ${DIM}$${RESET} ali-skills ls --json ${DIM}# JSON output${RESET}
5319
+ ${DIM}$${RESET} ali-skills find ${DIM}# interactive search${RESET}
5320
+ ${DIM}$${RESET} ali-skills find typescript ${DIM}# search by keyword${RESET}
5321
+ ${DIM}$${RESET} ali-skills check
5322
+ ${DIM}$${RESET} ali-skills update
5323
+ ${DIM}$${RESET} ali-skills experimental_install ${DIM}# restore from skills-lock.json${RESET}
5324
+ ${DIM}$${RESET} ali-skills init my-skill
5325
+ ${DIM}$${RESET} ali-skills experimental_sync ${DIM}# sync from node_modules${RESET}
5326
+ ${DIM}$${RESET} ali-skills experimental_sync -y ${DIM}# sync without prompts${RESET}
4536
5327
 
4537
- Discover more skills at ${TEXT}https://skills.sh/${RESET}
5328
+ Discover more skills at ${TEXT}https://ali-skills.alibaba-inc.com/${RESET}
4538
5329
  `);
4539
5330
  }
4540
5331
  function showRemoveHelp() {
4541
5332
  console.log(`
4542
- ${BOLD}Usage:${RESET} cli-skills remove [skills...] [options]
5333
+ ${BOLD}Usage:${RESET} ali-skills remove [skills...] [options]
4543
5334
 
4544
5335
  ${BOLD}Description:${RESET}
4545
5336
  Remove installed skills from agents. If no skill names are provided,
@@ -4556,17 +5347,159 @@ ${BOLD}Options:${RESET}
4556
5347
  --all Shorthand for --skill '*' --agent '*' -y
4557
5348
 
4558
5349
  ${BOLD}Examples:${RESET}
4559
- ${DIM}$${RESET} cli-skills remove ${DIM}# interactive selection${RESET}
4560
- ${DIM}$${RESET} cli-skills remove my-skill ${DIM}# remove specific skill${RESET}
4561
- ${DIM}$${RESET} cli-skills remove skill1 skill2 -y ${DIM}# remove multiple skills${RESET}
4562
- ${DIM}$${RESET} cli-skills remove --global my-skill ${DIM}# remove from global scope${RESET}
4563
- ${DIM}$${RESET} cli-skills rm --agent claude-code my-skill ${DIM}# remove from specific agent${RESET}
4564
- ${DIM}$${RESET} cli-skills remove --all ${DIM}# remove all skills${RESET}
4565
- ${DIM}$${RESET} cli-skills remove --skill '*' -a cursor ${DIM}# remove all skills from cursor${RESET}
5350
+ ${DIM}$${RESET} ali-skills remove ${DIM}# interactive selection${RESET}
5351
+ ${DIM}$${RESET} ali-skills remove my-skill ${DIM}# remove specific skill${RESET}
5352
+ ${DIM}$${RESET} ali-skills remove skill1 skill2 -y ${DIM}# remove multiple skills${RESET}
5353
+ ${DIM}$${RESET} ali-skills remove --global my-skill ${DIM}# remove from global scope${RESET}
5354
+ ${DIM}$${RESET} ali-skills rm --agent claude-code my-skill ${DIM}# remove from specific agent${RESET}
5355
+ ${DIM}$${RESET} ali-skills remove --all ${DIM}# remove all skills${RESET}
5356
+ ${DIM}$${RESET} ali-skills remove --skill '*' -a cursor ${DIM}# remove all skills from cursor${RESET}
4566
5357
 
4567
- Discover more skills at ${TEXT}https://skills.sh/${RESET}
5358
+ Discover more skills at ${TEXT}https://ali-skills.alibaba-inc.com/${RESET}
4568
5359
  `);
4569
5360
  }
5361
+ function showGatewayHelp() {
5362
+ console.log(`
5363
+ ${BOLD}Gateway Commands:${RESET}
5364
+ login Login to Gateway (BUC OAuth)
5365
+ logout Logout from Gateway
5366
+ status Show login status
5367
+ request <url> Send HTTP request via Gateway proxy
5368
+ req <url> Alias for request
5369
+
5370
+ ${BOLD}Config Commands:${RESET}
5371
+ config <platform> Configure platform token
5372
+ config --list List configured platforms
5373
+ config --remove <p> Remove platform config
5374
+
5375
+ ${BOLD}Request Options:${RESET}
5376
+ -X, --method <method> HTTP method (default: GET)
5377
+ -b, --body <body> Request body (JSON string or @file)
5378
+ -h, --header <header> Custom header (can be used multiple times)
5379
+ -o, --output <file> Save response to file
5380
+ -i, --include-headers Include response headers in output
5381
+ -t, --timeout <ms> Request timeout (default: 30000)
5382
+ --pretty Pretty print JSON output (default: true)
5383
+ --raw Raw output without formatting
5384
+ -q, --quiet Quiet mode, only output response body
5385
+
5386
+ ${BOLD}Examples:${RESET}
5387
+ ${DIM}$${RESET} ali-skills login
5388
+ ${DIM}$${RESET} ali-skills config code
5389
+ ${DIM}$${RESET} ali-skills config yuque
5390
+ ${DIM}$${RESET} ali-skills req https://o2.alibaba-inc.com/api/v2/apps
5391
+ ${DIM}$${RESET} ali-skills req https://code.alibaba-inc.com/api/v4/projects -X GET
5392
+ ${DIM}$${RESET} ali-skills req https://aliyuque.antfin.com/api/v2/repos -o repos.json
5393
+ ${DIM}$${RESET} ali-skills logout
5394
+ `);
5395
+ }
5396
+ function parseRequestOptions(args) {
5397
+ let url = "";
5398
+ const options = { method: "GET" };
5399
+ const headers = {};
5400
+ for (let i = 0; i < args.length; i++) {
5401
+ const arg = args[i];
5402
+ switch (arg) {
5403
+ case "-m":
5404
+ case "--method":
5405
+ options.method = args[++i] || "GET";
5406
+ break;
5407
+ case "-b":
5408
+ case "--body":
5409
+ options.body = args[++i];
5410
+ break;
5411
+ case "-h":
5412
+ case "--header": {
5413
+ const header = args[++i];
5414
+ if (header) {
5415
+ const [key, ...valueParts] = header.split(":");
5416
+ if (key && valueParts.length > 0) headers[key.trim()] = valueParts.join(":").trim();
5417
+ }
5418
+ break;
5419
+ }
5420
+ case "-o":
5421
+ case "--output":
5422
+ options.output = args[++i];
5423
+ break;
5424
+ case "-i":
5425
+ case "--include-headers":
5426
+ options.includeHeaders = true;
5427
+ break;
5428
+ case "-t":
5429
+ case "--timeout":
5430
+ options.timeout = parseInt(args[++i], 10);
5431
+ break;
5432
+ case "--pretty":
5433
+ options.pretty = true;
5434
+ break;
5435
+ case "--raw":
5436
+ options.raw = true;
5437
+ break;
5438
+ case "-q":
5439
+ case "--quiet":
5440
+ options.quiet = true;
5441
+ break;
5442
+ default:
5443
+ if (!arg.startsWith("-") && !url) url = arg;
5444
+ break;
5445
+ }
5446
+ }
5447
+ if (Object.keys(headers).length > 0) options.headers = headers;
5448
+ if (options.body?.startsWith("@")) options.body = readBodyFromFile(options.body.slice(1));
5449
+ return {
5450
+ url,
5451
+ options
5452
+ };
5453
+ }
5454
+ async function runGatewayCommand(args) {
5455
+ if (args.length === 0) {
5456
+ showGatewayHelp();
5457
+ return;
5458
+ }
5459
+ const command = args[0];
5460
+ const rest = args.slice(1);
5461
+ switch (command) {
5462
+ case "login":
5463
+ showLogo();
5464
+ console.log();
5465
+ await login();
5466
+ break;
5467
+ case "logout":
5468
+ await logout();
5469
+ break;
5470
+ case "status":
5471
+ await status();
5472
+ break;
5473
+ case "token": {
5474
+ const token = getPrivateToken();
5475
+ if (token) console.log(token);
5476
+ else {
5477
+ console.error("Not logged in");
5478
+ process.exit(1);
5479
+ }
5480
+ break;
5481
+ }
5482
+ case "request":
5483
+ case "req": {
5484
+ const { url, options } = parseRequestOptions(rest);
5485
+ if (!url) {
5486
+ console.error("Error: URL is required");
5487
+ showGatewayHelp();
5488
+ process.exit(1);
5489
+ }
5490
+ await proxyRequest(url, options);
5491
+ break;
5492
+ }
5493
+ case "--help":
5494
+ case "-h":
5495
+ showGatewayHelp();
5496
+ break;
5497
+ default:
5498
+ console.error(`Unknown gateway command: ${command}`);
5499
+ showGatewayHelp();
5500
+ process.exit(1);
5501
+ }
5502
+ }
4570
5503
  function runInit(args) {
4571
5504
  const cwd = process.cwd();
4572
5505
  const skillName = args[0] || basename(cwd);
@@ -4608,10 +5541,10 @@ Describe when this skill should be used.
4608
5541
  console.log(` 2. Update the ${TEXT}name${RESET} and ${TEXT}description${RESET} in the frontmatter`);
4609
5542
  console.log();
4610
5543
  console.log(`${DIM}Publishing:${RESET}`);
4611
- console.log(` ${DIM}GitHub:${RESET} Push to a repo, then ${TEXT}npx @ali/cli-skills add <owner>/<repo>${RESET}`);
4612
- console.log(` ${DIM}URL:${RESET} Host the file, then ${TEXT}npx @ali/cli-skills add https://example.com/${displayPath}${RESET}`);
5544
+ console.log(` ${DIM}GitHub:${RESET} Push to a repo, then ${TEXT}npx ali-skills add <owner>/<repo>${RESET}`);
5545
+ console.log(` ${DIM}URL:${RESET} Host the file, then ${TEXT}npx ali-skills add https://example.com/${displayPath}${RESET}`);
4613
5546
  console.log();
4614
- console.log(`Browse existing skills for inspiration at ${TEXT}https://skills.sh/${RESET}`);
5547
+ console.log(`Browse existing skills for inspiration at ${TEXT}https://ali-skills.alibaba-inc.com/${RESET}`);
4615
5548
  console.log();
4616
5549
  }
4617
5550
  const AGENTS_DIR = ".agents";
@@ -4650,31 +5583,11 @@ function getSkipReason(entry) {
4650
5583
  if (!entry.skillPath) return "No skill path recorded";
4651
5584
  return "No version tracking";
4652
5585
  }
4653
- function printSkippedSkills(skipped) {
4654
- if (skipped.length === 0) return;
4655
- console.log();
4656
- console.log(`${DIM}${skipped.length} skill(s) cannot be checked automatically:${RESET}`);
4657
- for (const skill of skipped) {
4658
- console.log(` ${TEXT}•${RESET} ${skill.name} ${DIM}(${skill.reason})${RESET}`);
4659
- console.log(` ${DIM}To update: ${TEXT}npx @ali/cli-skills add ${skill.sourceUrl} -g -y${RESET}`);
4660
- }
4661
- }
4662
- async function runCheck(args = []) {
4663
- console.log(`${TEXT}Checking for skill updates...${RESET}`);
4664
- console.log();
4665
- const lock = readSkillLock();
4666
- const skillNames = Object.keys(lock.skills);
4667
- if (skillNames.length === 0) {
4668
- console.log(`${DIM}No skills tracked in lock file.${RESET}`);
4669
- console.log(`${DIM}Install skills with${RESET} ${TEXT}npx @ali/cli-skills add <package>${RESET}`);
4670
- return;
4671
- }
4672
- const token = getGitHubToken();
4673
- const skillsBySource = /* @__PURE__ */ new Map();
5586
+ async function checkSkillsForUpdates(skills, token) {
5587
+ const updates = [];
5588
+ const errors = [];
4674
5589
  const skipped = [];
4675
- for (const skillName of skillNames) {
4676
- const entry = lock.skills[skillName];
4677
- if (!entry) continue;
5590
+ for (const [skillName, entry] of Object.entries(skills)) {
4678
5591
  if (!entry.skillFolderHash || !entry.skillPath) {
4679
5592
  skipped.push({
4680
5593
  name: skillName,
@@ -4683,84 +5596,260 @@ async function runCheck(args = []) {
4683
5596
  });
4684
5597
  continue;
4685
5598
  }
4686
- const existing = skillsBySource.get(entry.source) || [];
4687
- existing.push({
4688
- name: skillName,
4689
- entry
4690
- });
4691
- skillsBySource.set(entry.source, existing);
4692
- }
4693
- const totalSkills = skillNames.length - skipped.length;
4694
- if (totalSkills === 0) {
4695
- console.log(`${DIM}No GitHub skills to check.${RESET}`);
4696
- printSkippedSkills(skipped);
4697
- return;
4698
- }
4699
- console.log(`${DIM}Checking ${totalSkills} skill(s) for updates...${RESET}`);
4700
- const updates = [];
4701
- const errors = [];
4702
- for (const [source, skills] of skillsBySource) for (const { name, entry } of skills) try {
4703
- const latestHash = await fetchSkillFolderHash(source, entry.skillPath, token);
4704
- if (!latestHash) {
5599
+ try {
5600
+ const latestHash = await fetchSkillFolderHash(entry.source, entry.skillPath, token);
5601
+ if (!latestHash) {
5602
+ errors.push({
5603
+ name: skillName,
5604
+ source: entry.source,
5605
+ error: "Could not fetch from GitHub"
5606
+ });
5607
+ continue;
5608
+ }
5609
+ if (latestHash !== entry.skillFolderHash) updates.push({
5610
+ name: skillName,
5611
+ source: entry.source,
5612
+ entry
5613
+ });
5614
+ } catch (err) {
4705
5615
  errors.push({
4706
- name,
4707
- source,
4708
- error: "Could not fetch from GitHub"
5616
+ name: skillName,
5617
+ source: entry.source,
5618
+ error: err instanceof Error ? err.message : "Unknown error"
4709
5619
  });
4710
- continue;
4711
5620
  }
4712
- if (latestHash !== entry.skillFolderHash) updates.push({
4713
- name,
4714
- source
4715
- });
4716
- } catch (err) {
4717
- errors.push({
4718
- name,
4719
- source,
4720
- error: err instanceof Error ? err.message : "Unknown error"
4721
- });
4722
5621
  }
5622
+ return {
5623
+ updates,
5624
+ errors,
5625
+ skipped
5626
+ };
5627
+ }
5628
+ async function runCheck(args = []) {
5629
+ const isGlobal = args.includes("-g") || args.includes("--global");
5630
+ console.log(`${TEXT}Checking for skill updates...${RESET}`);
4723
5631
  console.log();
4724
- if (updates.length === 0) console.log(`${TEXT}✓ All skills are up to date${RESET}`);
4725
- else {
4726
- console.log(`${TEXT}${updates.length} update(s) available:${RESET}`);
4727
- console.log();
4728
- for (const update of updates) {
4729
- console.log(` ${TEXT}↑${RESET} ${update.name}`);
4730
- console.log(` ${DIM}source: ${update.source}${RESET}`);
5632
+ const token = getGitHubToken();
5633
+ let updates = [];
5634
+ let skipped = [];
5635
+ let skillCount = 0;
5636
+ if (isGlobal) {
5637
+ const globalLock = readSkillLock();
5638
+ const globalSkillNames = Object.keys(globalLock.skills);
5639
+ skillCount = globalSkillNames.length;
5640
+ if (globalSkillNames.length === 0) {
5641
+ console.log(`${DIM}No global skills found.${RESET}`);
5642
+ console.log();
5643
+ return;
5644
+ }
5645
+ console.log(`${BOLD}Global skills${RESET}`);
5646
+ console.log(`${DIM}Checking ${globalSkillNames.length} skill(s)...${RESET}`);
5647
+ const result = await checkSkillsForUpdates(globalLock.skills, token);
5648
+ updates = result.updates;
5649
+ result.errors;
5650
+ skipped = result.skipped;
5651
+ if (updates.length === 0) console.log(`${TEXT} ✓ All global skills are up to date${RESET}`);
5652
+ else {
5653
+ console.log(`${TEXT} ${updates.length} update(s) available:${RESET}`);
5654
+ for (const update of updates) console.log(` ${TEXT}↑${RESET} ${update.name} ${DIM}(${update.source})${RESET}`);
5655
+ }
5656
+ if (skipped.length > 0) {
5657
+ console.log();
5658
+ console.log(`${DIM} ${skipped.length} skill(s) cannot be checked automatically:${RESET}`);
5659
+ for (const skill of skipped) {
5660
+ console.log(` ${TEXT}•${RESET} ${skill.name} ${DIM}(${skill.reason})${RESET}`);
5661
+ console.log(` ${DIM}To update: ${TEXT}npx ali-skills add ${skill.sourceUrl} -g -y${RESET}`);
5662
+ }
4731
5663
  }
4732
5664
  console.log();
4733
- console.log(`${DIM}Run${RESET} ${TEXT}npx @ali/cli-skills update${RESET} ${DIM}to update all skills${RESET}`);
4734
- }
4735
- if (errors.length > 0) {
5665
+ if (updates.length > 0) {
5666
+ console.log(`${TEXT}${updates.length} update(s) available${RESET}`);
5667
+ console.log();
5668
+ console.log(`${DIM}Run${RESET} ${TEXT}npx ali-skills update -g${RESET} ${DIM}to update all global skills${RESET}`);
5669
+ }
5670
+ } else {
5671
+ const projectLock = await readLocalLock();
5672
+ const projectSkillNames = Object.keys(projectLock.skills);
5673
+ skillCount = projectSkillNames.length;
5674
+ if (projectSkillNames.length === 0) {
5675
+ console.log(`${DIM}No project-level skills found.${RESET}`);
5676
+ console.log();
5677
+ console.log(`${DIM}To check global skills, use:${RESET} ${TEXT}npx ali-skills check -g${RESET}`);
5678
+ return;
5679
+ }
5680
+ console.log(`${BOLD}Project-level skills${RESET}`);
5681
+ console.log(`${DIM}Checking ${projectSkillNames.length} skill(s)...${RESET}`);
5682
+ for (const [skillName, entry] of Object.entries(projectLock.skills)) {
5683
+ if (entry.sourceType === "internal") {
5684
+ if (!entry.commitHash) {
5685
+ skipped.push({
5686
+ name: skillName,
5687
+ reason: "Reinstall required to enable update checking (missing commit hash)",
5688
+ sourceUrl: `https://code.alibaba-inc.com/${entry.source}`
5689
+ });
5690
+ continue;
5691
+ }
5692
+ const skillPath = (entry.skillPath || "").replace(/\/?SKILL\.md$/i, "");
5693
+ const latestCommit = await fetchAliInternalCommitHash(entry.source, skillPath, null);
5694
+ if (latestCommit === null) skipped.push({
5695
+ name: skillName,
5696
+ reason: "Ali internal repository (API authentication failed)",
5697
+ sourceUrl: `https://code.alibaba-inc.com/${entry.source}`
5698
+ });
5699
+ else if (latestCommit !== entry.commitHash) updates.push({
5700
+ name: skillName,
5701
+ source: entry.source,
5702
+ entry: {
5703
+ source: entry.source,
5704
+ sourceType: entry.sourceType,
5705
+ sourceUrl: `https://code.alibaba-inc.com/${entry.source}`,
5706
+ skillPath,
5707
+ skillFolderHash: entry.computedHash,
5708
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
5709
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
5710
+ }
5711
+ });
5712
+ continue;
5713
+ }
5714
+ if (entry.sourceType === "github") {
5715
+ if (!entry.skillFolderHash) {
5716
+ skipped.push({
5717
+ name: skillName,
5718
+ reason: "Reinstall required to enable update checking (missing folder hash)",
5719
+ sourceUrl: `https://github.com/${entry.source}`
5720
+ });
5721
+ continue;
5722
+ }
5723
+ const possiblePaths = entry.skillPath ? [entry.skillPath] : [`skills/${skillName}`, `skills/${skillName}/SKILL.md`];
5724
+ let foundMatch = false;
5725
+ for (const skillPath of possiblePaths) try {
5726
+ const latestHash = await fetchSkillFolderHash(entry.source, skillPath, token);
5727
+ if (latestHash === null) continue;
5728
+ foundMatch = true;
5729
+ if (latestHash !== entry.skillFolderHash) updates.push({
5730
+ name: skillName,
5731
+ source: entry.source,
5732
+ entry: {
5733
+ source: entry.source,
5734
+ sourceType: entry.sourceType,
5735
+ sourceUrl: `https://github.com/${entry.source}`,
5736
+ skillPath,
5737
+ skillFolderHash: entry.skillFolderHash,
5738
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
5739
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
5740
+ }
5741
+ });
5742
+ break;
5743
+ } catch {
5744
+ continue;
5745
+ }
5746
+ if (!foundMatch) skipped.push({
5747
+ name: skillName,
5748
+ reason: "Unable to verify (API failed for all possible paths)",
5749
+ sourceUrl: `https://github.com/${entry.source}`
5750
+ });
5751
+ } else skipped.push({
5752
+ name: skillName,
5753
+ reason: `${entry.sourceType} source type not supported for update checking`,
5754
+ sourceUrl: entry.source
5755
+ });
5756
+ }
5757
+ if (updates.length === 0) console.log(`${TEXT} ✓ All project skills are up to date${RESET}`);
5758
+ else {
5759
+ console.log(`${TEXT} ${updates.length} update(s) available:${RESET}`);
5760
+ for (const update of updates) console.log(` ${TEXT}↑${RESET} ${update.name} ${DIM}(${update.source})${RESET}`);
5761
+ }
5762
+ if (skipped.length > 0) {
5763
+ console.log();
5764
+ console.log(`${DIM} ${skipped.length} skill(s) cannot be checked automatically:${RESET}`);
5765
+ for (const skill of skipped) console.log(` ${TEXT}•${RESET} ${skill.name} ${DIM}(${skill.reason})${RESET}`);
5766
+ }
4736
5767
  console.log();
4737
- console.log(`${DIM}Could not check ${errors.length} skill(s) (may need reinstall)${RESET}`);
5768
+ if (updates.length > 0) {
5769
+ console.log(`${TEXT}${updates.length} update(s) available${RESET}`);
5770
+ console.log();
5771
+ console.log(`${DIM}Run${RESET} ${TEXT}npx ali-skills update${RESET} ${DIM}to update all project skills${RESET}`);
5772
+ console.log(`${DIM}Run${RESET} ${TEXT}npx ali-skills update <skill-name>${RESET} ${DIM}to update specific skill${RESET}`);
5773
+ }
4738
5774
  }
4739
- printSkippedSkills(skipped);
4740
5775
  track({
4741
5776
  event: "check",
4742
- skillCount: String(totalSkills),
5777
+ skillCount: String(skillCount),
4743
5778
  updatesAvailable: String(updates.length)
4744
5779
  });
4745
5780
  console.log();
4746
5781
  }
4747
- async function runUpdate() {
5782
+ async function runUpdate(args = []) {
5783
+ const isGlobal = args.includes("-g") || args.includes("--global");
5784
+ const yesFlag = args.includes("-y") || args.includes("--yes");
5785
+ const skillArgs = args.filter((arg) => !arg.startsWith("-"));
4748
5786
  console.log(`${TEXT}Checking for skill updates...${RESET}`);
4749
5787
  console.log();
4750
- const lock = readSkillLock();
4751
- const skillNames = Object.keys(lock.skills);
5788
+ const token = getGitHubToken();
5789
+ let skillsToCheck = {};
5790
+ let scopeLabel = "project";
5791
+ if (isGlobal) {
5792
+ skillsToCheck = readSkillLock().skills;
5793
+ scopeLabel = "global";
5794
+ } else {
5795
+ const projectLock = await readLocalLock();
5796
+ for (const [name, entry] of Object.entries(projectLock.skills)) {
5797
+ let sourceUrl;
5798
+ if (entry.sourceType === "github") sourceUrl = `https://github.com/${entry.source}`;
5799
+ else if (entry.sourceType === "internal") sourceUrl = `https://code.alibaba-inc.com/${entry.source}`;
5800
+ else sourceUrl = entry.source;
5801
+ skillsToCheck[name] = {
5802
+ source: entry.source,
5803
+ sourceType: entry.sourceType,
5804
+ sourceUrl,
5805
+ skillPath: entry.skillPath || "",
5806
+ skillFolderHash: entry.skillFolderHash || entry.computedHash,
5807
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
5808
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
5809
+ };
5810
+ }
5811
+ }
5812
+ const skillNames = Object.keys(skillsToCheck);
4752
5813
  if (skillNames.length === 0) {
4753
- console.log(`${DIM}No skills tracked in lock file.${RESET}`);
4754
- console.log(`${DIM}Install skills with${RESET} ${TEXT}npx @ali/cli-skills add <package>${RESET}`);
5814
+ console.log(`${DIM}No ${scopeLabel}-level skills found.${RESET}`);
5815
+ console.log();
5816
+ if (!isGlobal) console.log(`${DIM}To update global skills, use:${RESET} ${TEXT}npx ali-skills update -g${RESET}`);
4755
5817
  return;
4756
5818
  }
4757
- const token = getGitHubToken();
4758
- const updates = [];
5819
+ const availableUpdates = [];
4759
5820
  const skipped = [];
5821
+ const projectLock = !isGlobal ? await readLocalLock() : null;
4760
5822
  for (const skillName of skillNames) {
4761
- const entry = lock.skills[skillName];
5823
+ const entry = skillsToCheck[skillName];
4762
5824
  if (!entry) continue;
4763
- if (!entry.skillFolderHash || !entry.skillPath) {
5825
+ if (entry.sourceType === "internal" && projectLock) {
5826
+ const localEntry = projectLock.skills[skillName];
5827
+ if (!localEntry?.commitHash) {
5828
+ skipped.push({
5829
+ name: skillName,
5830
+ reason: "Reinstall required to enable update checking (missing commit hash)",
5831
+ sourceUrl: entry.sourceUrl
5832
+ });
5833
+ continue;
5834
+ }
5835
+ try {
5836
+ const skillPath = (localEntry.skillPath || "").replace(/\/?SKILL\.md$/i, "");
5837
+ const latestCommit = await fetchAliInternalCommitHash(entry.source, skillPath, null);
5838
+ if (latestCommit && latestCommit !== localEntry.commitHash) availableUpdates.push({
5839
+ name: skillName,
5840
+ source: entry.source,
5841
+ entry
5842
+ });
5843
+ } catch {
5844
+ skipped.push({
5845
+ name: skillName,
5846
+ reason: "Ali internal repository (API check failed)",
5847
+ sourceUrl: entry.sourceUrl
5848
+ });
5849
+ }
5850
+ continue;
5851
+ }
5852
+ if (!entry.skillFolderHash) {
4764
5853
  skipped.push({
4765
5854
  name: skillName,
4766
5855
  reason: getSkipReason(entry),
@@ -4768,58 +5857,97 @@ async function runUpdate() {
4768
5857
  });
4769
5858
  continue;
4770
5859
  }
5860
+ if (entry.sourceType === "github") {
5861
+ const possiblePaths = entry.skillPath ? [entry.skillPath] : [`skills/${skillName}`, `skills/${skillName}/SKILL.md`];
5862
+ for (const skillPath of possiblePaths) try {
5863
+ const latestHash = await fetchSkillFolderHash(entry.source, skillPath, token);
5864
+ if (latestHash === null) continue;
5865
+ if (latestHash !== entry.skillFolderHash) availableUpdates.push({
5866
+ name: skillName,
5867
+ source: entry.source,
5868
+ entry
5869
+ });
5870
+ break;
5871
+ } catch {
5872
+ continue;
5873
+ }
5874
+ continue;
5875
+ }
4771
5876
  try {
4772
- const latestHash = await fetchSkillFolderHash(entry.source, entry.skillPath, token);
4773
- if (latestHash && latestHash !== entry.skillFolderHash) updates.push({
5877
+ const latestHash = await fetchSkillFolderHash(entry.source, entry.skillPath || "", token);
5878
+ if (latestHash && latestHash !== entry.skillFolderHash) availableUpdates.push({
4774
5879
  name: skillName,
4775
5880
  source: entry.source,
4776
5881
  entry
4777
5882
  });
4778
5883
  } catch {}
4779
5884
  }
4780
- if (skillNames.length - skipped.length === 0) {
4781
- console.log(`${DIM}No skills to check.${RESET}`);
4782
- printSkippedSkills(skipped);
5885
+ if (availableUpdates.length === 0) {
5886
+ console.log(`${TEXT} All ${scopeLabel} skills are up to date${RESET}`);
5887
+ console.log();
4783
5888
  return;
4784
5889
  }
4785
- if (updates.length === 0) {
4786
- console.log(`${TEXT}✓ All skills are up to date${RESET}`);
5890
+ let selectedUpdates = [];
5891
+ if (skillArgs.length > 0) {
5892
+ const requestedSkills = skillArgs.map((s) => s.toLowerCase());
5893
+ selectedUpdates = availableUpdates.filter((u) => requestedSkills.includes(u.name.toLowerCase()));
5894
+ for (const reqSkill of skillArgs) {
5895
+ const exists = skillNames.some((n) => n.toLowerCase() === reqSkill.toLowerCase());
5896
+ const hasUpdate = availableUpdates.some((u) => u.name.toLowerCase() === reqSkill.toLowerCase());
5897
+ if (!exists) console.log(`${DIM}Skill not found: ${reqSkill}${RESET}`);
5898
+ else if (!hasUpdate) console.log(`${TEXT}✓ ${reqSkill} is already up to date${RESET}`);
5899
+ }
5900
+ } else if (yesFlag) selectedUpdates = availableUpdates;
5901
+ else {
5902
+ console.log(`${TEXT}Found ${availableUpdates.length} ${scopeLabel} skill update(s) available:${RESET}`);
4787
5903
  console.log();
5904
+ const selected = await fe({
5905
+ message: "Select skills to update (space to select, enter to confirm):",
5906
+ options: [{
5907
+ value: "__ALL__",
5908
+ label: `${import_picocolors.default.green("Update all")} (${availableUpdates.length} skill(s))`
5909
+ }, ...availableUpdates.map((u) => ({
5910
+ value: u.name,
5911
+ label: ` ${u.name} ${DIM}(${u.source})${RESET}`
5912
+ }))],
5913
+ required: true
5914
+ });
5915
+ if (pD(selected)) {
5916
+ Se(import_picocolors.default.yellow("Update cancelled."));
5917
+ return;
5918
+ }
5919
+ const selectedArray = selected;
5920
+ if (selectedArray.includes("__ALL__")) selectedUpdates = availableUpdates;
5921
+ else selectedUpdates = availableUpdates.filter((u) => selectedArray.includes(u.name));
5922
+ }
5923
+ if (selectedUpdates.length === 0) {
5924
+ console.log(`${DIM}No skills selected for update.${RESET}`);
4788
5925
  return;
4789
5926
  }
4790
- console.log(`${TEXT}Found ${updates.length} update(s)${RESET}`);
5927
+ console.log();
5928
+ console.log(`${TEXT}Updating ${selectedUpdates.length} ${scopeLabel} skill(s)...${RESET}`);
4791
5929
  console.log();
4792
5930
  let successCount = 0;
4793
5931
  let failCount = 0;
4794
- for (const update of updates) {
5932
+ for (const update of selectedUpdates) {
4795
5933
  console.log(`${TEXT}Updating ${update.name}...${RESET}`);
4796
- let installUrl = update.entry.sourceUrl;
4797
- if (update.entry.skillPath) {
4798
- let skillFolder = update.entry.skillPath;
4799
- if (skillFolder.endsWith("/SKILL.md")) skillFolder = skillFolder.slice(0, -9);
4800
- else if (skillFolder.endsWith("SKILL.md")) skillFolder = skillFolder.slice(0, -8);
4801
- if (skillFolder.endsWith("/")) skillFolder = skillFolder.slice(0, -1);
5934
+ let skillFolder = update.entry.skillPath || "";
5935
+ if (skillFolder.endsWith("/SKILL.md")) skillFolder = skillFolder.slice(0, -9);
5936
+ else if (skillFolder.endsWith("SKILL.md")) skillFolder = skillFolder.slice(0, -8);
5937
+ if (skillFolder.endsWith("/")) skillFolder = skillFolder.slice(0, -1);
5938
+ let installUrl;
5939
+ if (skillFolder) {
4802
5940
  installUrl = update.entry.sourceUrl.replace(/\.git$/, "").replace(/\/$/, "");
4803
5941
  installUrl = `${installUrl}/tree/main/${skillFolder}`;
4804
- }
4805
- if (spawnSync("npx", [
4806
- "-y",
4807
- "@ali/cli-skills",
4808
- "add",
4809
- installUrl,
4810
- "-g",
4811
- "-y"
4812
- ], {
4813
- stdio: [
4814
- "inherit",
4815
- "pipe",
4816
- "pipe"
4817
- ],
4818
- shell: process.platform === "win32"
4819
- }).status === 0) {
5942
+ } else installUrl = update.entry.sourceUrl;
5943
+ try {
5944
+ await runAdd([installUrl], {
5945
+ yes: true,
5946
+ global: isGlobal
5947
+ });
4820
5948
  successCount++;
4821
5949
  console.log(` ${TEXT}✓${RESET} Updated ${update.name}`);
4822
- } else {
5950
+ } catch {
4823
5951
  failCount++;
4824
5952
  console.log(` ${DIM}✗ Failed to update ${update.name}${RESET}`);
4825
5953
  }
@@ -4829,7 +5957,7 @@ async function runUpdate() {
4829
5957
  if (failCount > 0) console.log(`${DIM}Failed to update ${failCount} skill(s)${RESET}`);
4830
5958
  track({
4831
5959
  event: "update",
4832
- skillCount: String(updates.length),
5960
+ skillCount: String(selectedUpdates.length),
4833
5961
  successCount: String(successCount),
4834
5962
  failCount: String(failCount)
4835
5963
  });
@@ -4857,6 +5985,11 @@ async function main() {
4857
5985
  console.log();
4858
5986
  runInit(restArgs);
4859
5987
  break;
5988
+ case "config":
5989
+ showLogo();
5990
+ console.log();
5991
+ await runConfig(restArgs);
5992
+ break;
4860
5993
  case "experimental_install":
4861
5994
  showLogo();
4862
5995
  await runInstallFromLock(restArgs);
@@ -4900,9 +6033,33 @@ async function main() {
4900
6033
  case "check":
4901
6034
  await runCheck(restArgs);
4902
6035
  break;
6036
+ case "login":
6037
+ await login();
6038
+ break;
6039
+ case "logout":
6040
+ await logout();
6041
+ break;
6042
+ case "status":
6043
+ await status();
6044
+ break;
6045
+ case "req":
6046
+ case "request": {
6047
+ const { url, options } = parseRequestOptions(restArgs);
6048
+ if (!url) {
6049
+ console.error("Error: URL is required");
6050
+ showGatewayHelp();
6051
+ process.exit(1);
6052
+ }
6053
+ await proxyRequest(url, options);
6054
+ break;
6055
+ }
6056
+ case "gateway":
6057
+ case "gw":
6058
+ await runGatewayCommand(restArgs);
6059
+ break;
4903
6060
  case "update":
4904
6061
  case "upgrade":
4905
- await runUpdate();
6062
+ await runUpdate(restArgs);
4906
6063
  break;
4907
6064
  case "--help":
4908
6065
  case "-h":
@@ -4914,7 +6071,7 @@ async function main() {
4914
6071
  break;
4915
6072
  default:
4916
6073
  console.log(`Unknown command: ${command}`);
4917
- console.log(`Run ${BOLD}cli-skills --help${RESET} for usage.`);
6074
+ console.log(`Run ${BOLD}ali-skills --help${RESET} for usage.`);
4918
6075
  }
4919
6076
  }
4920
6077
  main().then(async () => {