ali-skills 0.0.14 → 0.0.16

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.
@@ -94,9 +94,32 @@ function parseSource(input) {
94
94
  const githubRepoMatch = input.match(/github\.com\/([^/]+)\/([^/]+)/);
95
95
  if (githubRepoMatch) {
96
96
  const [, owner, repo] = githubRepoMatch;
97
+ const cleanRepo = repo.replace(/\.git$/, "");
98
+ const credentialMatch = input.match(/^(https?:\/\/)(?:([^@]+)@)?github\.com/);
99
+ const protocol = credentialMatch?.[1] ?? "https://";
100
+ const credential = credentialMatch?.[2];
97
101
  return {
98
102
  type: "github",
99
- url: `https://github.com/${owner}/${repo.replace(/\.git$/, "")}.git`
103
+ url: credential ? `${protocol}${credential}@github.com/${owner}/${cleanRepo}.git` : `${protocol}github.com/${owner}/${cleanRepo}.git`
104
+ };
105
+ }
106
+ const internalTreeWithPathMatch = input.match(/^(https?:\/\/(?:[^@/]+@)?(?:code|gitlab)\.alibaba-inc\.com)\/(.+?)(?:\/-)?\/tree\/([^/]+)\/(.+)/);
107
+ if (internalTreeWithPathMatch) {
108
+ const [, host, repoPath, ref, subpath] = internalTreeWithPathMatch;
109
+ if (repoPath && repoPath.includes("/")) return {
110
+ type: "internal",
111
+ url: `${host.replace("gitlab.alibaba-inc.com", "code.alibaba-inc.com")}/${repoPath.replace(/\.git$/, "")}.git`,
112
+ ref,
113
+ subpath: subpath ? sanitizeSubpath(subpath) : subpath
114
+ };
115
+ }
116
+ const internalTreeMatch = input.match(/^(https?:\/\/(?:[^@/]+@)?(?:code|gitlab)\.alibaba-inc\.com)\/(.+?)(?:\/-)?\/tree\/([^/]+)$/);
117
+ if (internalTreeMatch) {
118
+ const [, host, repoPath, ref] = internalTreeMatch;
119
+ if (repoPath && repoPath.includes("/")) return {
120
+ type: "internal",
121
+ url: `${host.replace("gitlab.alibaba-inc.com", "code.alibaba-inc.com")}/${repoPath.replace(/\.git$/, "")}.git`,
122
+ ref
100
123
  };
101
124
  }
102
125
  const gitlabTreeWithPathMatch = input.match(/^(https?):\/\/([^/]+)\/(.+?)\/-\/tree\/([^/]+)\/(.+)/);
@@ -144,23 +167,14 @@ function parseSource(input) {
144
167
  subpath: subpath ? sanitizeSubpath(subpath) : subpath
145
168
  };
146
169
  }
147
- const internalTreeWithPathMatch = input.match(/^(https?:\/\/(?:[^@/]+@)?(?:code|gitlab)\.alibaba-inc\.com)\/(.+?)(?:\/-)?\/tree\/([^/]+)\/(.+)/);
148
- if (internalTreeWithPathMatch) {
149
- const [, host, repoPath, ref, subpath] = internalTreeWithPathMatch;
150
- if (repoPath && repoPath.includes("/")) return {
151
- type: "internal",
152
- url: `${host.replace("gitlab.alibaba-inc.com", "code.alibaba-inc.com")}/${repoPath.replace(/\.git$/, "")}.git`,
153
- ref,
154
- subpath: subpath ? sanitizeSubpath(subpath) : subpath
155
- };
156
- }
157
- const internalTreeMatch = input.match(/^(https?:\/\/(?:[^@/]+@)?(?:code|gitlab)\.alibaba-inc\.com)\/(.+?)(?:\/-)?\/tree\/([^/]+)$/);
158
- if (internalTreeMatch) {
159
- const [, host, repoPath, ref] = internalTreeMatch;
160
- if (repoPath && repoPath.includes("/")) return {
170
+ const internalRepoWithSubpathMatch = input.match(/^(https?:\/\/(?:[^@/]+@)?(?:code|gitlab)\.alibaba-inc\.com)\/([^/]+)\/([^/]+)\/(.+)$/);
171
+ if (internalRepoWithSubpathMatch) {
172
+ const [, host, owner, repo, subpath] = internalRepoWithSubpathMatch;
173
+ if (!owner || !repo) throw new Error(`Invalid internal URL format: ${input}`);
174
+ return {
161
175
  type: "internal",
162
- url: `${host.replace("gitlab.alibaba-inc.com", "code.alibaba-inc.com")}/${repoPath.replace(/\.git$/, "")}.git`,
163
- ref
176
+ url: `${host.replace("gitlab.alibaba-inc.com", "code.alibaba-inc.com")}/${owner}/${repo.replace(/\.git$/, "")}.git`,
177
+ subpath: sanitizeSubpath(subpath)
164
178
  };
165
179
  }
166
180
  if (isInternalUrl(input)) return {
@@ -210,6 +224,26 @@ function isWellKnownUrl(input) {
210
224
  return false;
211
225
  }
212
226
  }
227
+ function getDisplaySource(sourceUrl) {
228
+ if (sourceUrl.startsWith("/") || sourceUrl.startsWith(".") || sourceUrl.startsWith("~")) return sourceUrl;
229
+ const sshMatch = sourceUrl.match(/^git@([^:]+):(.+)$/);
230
+ if (sshMatch) {
231
+ const [, host, path] = sshMatch;
232
+ if (!host || !path) return sourceUrl;
233
+ const cleanPath = path.replace(/\.git$/, "");
234
+ if (host === "code.alibaba-inc.com" || host === "gitlab.alibaba-inc.com") return cleanPath;
235
+ return `https://${host}/${cleanPath}`;
236
+ }
237
+ if (sourceUrl.startsWith("http://") || sourceUrl.startsWith("https://")) try {
238
+ const url = new URL(sourceUrl);
239
+ const cleanPath = url.pathname.replace(/\.git$/, "").replace(/^\//, "");
240
+ if (url.hostname === "code.alibaba-inc.com" || url.hostname === "gitlab.alibaba-inc.com") return cleanPath;
241
+ return `https://${url.hostname}/${cleanPath}`;
242
+ } catch {
243
+ return sourceUrl.replace(/^https?:\/\/[^@]+@/, "https://");
244
+ }
245
+ return sourceUrl;
246
+ }
213
247
  const silentOutput = new Writable({ write(_chunk, _encoding, callback) {
214
248
  callback();
215
249
  } });
@@ -2046,6 +2080,25 @@ async function saveSelectedAgents(agents) {
2046
2080
  lock.lastSelectedAgents = agents;
2047
2081
  await writeSkillLock(lock);
2048
2082
  }
2083
+ function sanitizeSourceUrl(url) {
2084
+ const sshMatch = url.match(/^git@([^:]+):(.+)$/);
2085
+ if (sshMatch) {
2086
+ const [, host, path] = sshMatch;
2087
+ if (!host || !path) return url;
2088
+ return `https://${host}/${path.replace(/\.git$/, "")}.git`;
2089
+ }
2090
+ if (url.startsWith("http://") || url.startsWith("https://")) try {
2091
+ const parsed = new URL(url);
2092
+ parsed.username = "";
2093
+ parsed.password = "";
2094
+ let cleanUrl = parsed.toString();
2095
+ if (!cleanUrl.endsWith(".git")) cleanUrl += ".git";
2096
+ return cleanUrl;
2097
+ } catch {
2098
+ return url;
2099
+ }
2100
+ return url;
2101
+ }
2049
2102
  const LOCAL_LOCK_FILE = "skills-lock.json";
2050
2103
  const CURRENT_VERSION = 1;
2051
2104
  function getLocalLockPath(cwd) {
@@ -2056,11 +2109,27 @@ async function readLocalLock(cwd) {
2056
2109
  try {
2057
2110
  const content = await readFile(lockPath, "utf-8");
2058
2111
  const parsed = JSON.parse(content);
2059
- if (typeof parsed.version !== "number" || !parsed.skills) return createEmptyLocalLock();
2060
- if (parsed.version < CURRENT_VERSION) return createEmptyLocalLock();
2061
- return parsed;
2112
+ if (typeof parsed.version !== "number") return {
2113
+ lock: parsed,
2114
+ isOutdated: true
2115
+ };
2116
+ if (parsed.version < CURRENT_VERSION) return {
2117
+ lock: parsed,
2118
+ isOutdated: true
2119
+ };
2120
+ if (!parsed.skills) return {
2121
+ lock: createEmptyLocalLock(),
2122
+ isOutdated: false
2123
+ };
2124
+ return {
2125
+ lock: parsed,
2126
+ isOutdated: false
2127
+ };
2062
2128
  } catch {
2063
- return createEmptyLocalLock();
2129
+ return {
2130
+ lock: createEmptyLocalLock(),
2131
+ isOutdated: false
2132
+ };
2064
2133
  }
2065
2134
  }
2066
2135
  async function writeLocalLock(lock, cwd) {
@@ -2102,7 +2171,7 @@ async function collectFiles(baseDir, currentDir, results) {
2102
2171
  }));
2103
2172
  }
2104
2173
  async function addSkillToLocalLock(skillName, entry, cwd) {
2105
- const lock = await readLocalLock(cwd);
2174
+ const { lock } = await readLocalLock(cwd);
2106
2175
  lock.skills[skillName] = entry;
2107
2176
  await writeLocalLock(lock, cwd);
2108
2177
  }
@@ -2122,7 +2191,7 @@ function logSkillParseFailures(failures) {
2122
2191
  if (f.hint) M.message(import_picocolors.default.yellow(` 提示: ${f.hint}`));
2123
2192
  }
2124
2193
  }
2125
- var version$1 = "2.0.14";
2194
+ var version$1 = "2.0.16";
2126
2195
  const isCancelled$1 = (value) => typeof value === "symbol";
2127
2196
  async function isSourcePrivate(source) {
2128
2197
  const ownerRepo = parseOwnerRepo(source);
@@ -2376,7 +2445,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
2376
2445
  value: key,
2377
2446
  label: config.displayName
2378
2447
  })));
2379
- if (pD(selected)) {
2448
+ if (isCancelled$1(selected)) {
2380
2449
  xe("Installation cancelled");
2381
2450
  process.exit(0);
2382
2451
  }
@@ -2390,7 +2459,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
2390
2459
  } else M.info(`Installing to: ${installedAgents.map((a) => import_picocolors.default.cyan(agents[a].displayName)).join(", ")}`);
2391
2460
  } else {
2392
2461
  const selected = await selectAgentsInteractive({ global: options.global });
2393
- if (pD(selected)) {
2462
+ if (isCancelled$1(selected)) {
2394
2463
  xe("Installation cancelled");
2395
2464
  process.exit(0);
2396
2465
  }
@@ -2514,8 +2583,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
2514
2583
  await addSkillToLock(skill.installName, {
2515
2584
  source: sourceIdentifier,
2516
2585
  sourceType: "well-known",
2517
- sourceUrl: skill.sourceUrl,
2518
- skillFolderHash: ""
2586
+ sourceUrl: sanitizeSourceUrl(skill.sourceUrl)
2519
2587
  });
2520
2588
  } catch {}
2521
2589
  }
@@ -2662,7 +2730,8 @@ async function runAdd(args, options = {}) {
2662
2730
  } else {
2663
2731
  spinner.start("Cloning repository...");
2664
2732
  try {
2665
- tempDir = await cloneRepo(parsed.url, parsed.ref);
2733
+ const ref = parsed.ref === "HEAD" ? void 0 : parsed.ref;
2734
+ tempDir = await cloneRepo(parsed.url, ref);
2666
2735
  skillsDir = tempDir;
2667
2736
  spinner.stop("Repository cloned");
2668
2737
  } catch (cloneError) {
@@ -2875,7 +2944,7 @@ async function runAdd(args, options = {}) {
2875
2944
  value: key,
2876
2945
  label: config.displayName
2877
2946
  })));
2878
- if (pD(selected)) {
2947
+ if (isCancelled$1(selected)) {
2879
2948
  xe("Installation cancelled");
2880
2949
  await cleanup(tempDir);
2881
2950
  process.exit(0);
@@ -2890,7 +2959,7 @@ async function runAdd(args, options = {}) {
2890
2959
  } else M.info(`Installing to: ${installedAgents.map((a) => import_picocolors.default.cyan(agents[a].displayName)).join(", ")}`);
2891
2960
  } else {
2892
2961
  const selected = await selectAgentsInteractive({ global: options.global });
2893
- if (pD(selected)) {
2962
+ if (isCancelled$1(selected)) {
2894
2963
  xe("Installation cancelled");
2895
2964
  await cleanup(tempDir);
2896
2965
  process.exit(0);
@@ -3106,18 +3175,28 @@ async function runAdd(args, options = {}) {
3106
3175
  for (const skill of selectedSkills) {
3107
3176
  const skillDisplayName = getSkillDisplayName(skill);
3108
3177
  if (successfulSkillNames.has(skillDisplayName)) try {
3109
- let skillFolderHash = "";
3178
+ let skillFolderHash;
3179
+ let commitHash;
3110
3180
  const skillPathValue = skillFiles[skill.name];
3111
- if (parsed.type === "github" && skillPathValue) {
3181
+ let skillPath = skillPathValue;
3182
+ if (skillPath) {
3183
+ if (skillPath.endsWith("/SKILL.md")) skillPath = skillPath.slice(0, -9);
3184
+ else if (skillPath.endsWith("SKILL.md")) skillPath = skillPath.slice(0, -8);
3185
+ }
3186
+ if (effectiveSourceType === "github" && skillPathValue) {
3112
3187
  const hash = await fetchSkillFolderHash(normalizedSource, skillPathValue, getGitHubToken());
3113
3188
  if (hash) skillFolderHash = hash;
3189
+ } else if (effectiveSourceType === "internal" && skillPath !== void 0) {
3190
+ const hash = await fetchAliInternalCommitHash(normalizedSource, skillPath, null);
3191
+ if (hash) commitHash = hash;
3114
3192
  }
3115
3193
  await addSkillToLock(skill.name, {
3116
3194
  source: lockSource || normalizedSource,
3117
3195
  sourceType: effectiveSourceType,
3118
- sourceUrl: parsed.url,
3119
- skillPath: skillPathValue,
3120
- skillFolderHash,
3196
+ sourceUrl: sanitizeSourceUrl(parsed.url),
3197
+ skillPath,
3198
+ ...skillFolderHash && { skillFolderHash },
3199
+ ...commitHash && { commitHash },
3121
3200
  pluginName: skill.pluginName
3122
3201
  });
3123
3202
  } catch {}
@@ -3130,8 +3209,9 @@ async function runAdd(args, options = {}) {
3130
3209
  if (successfulSkillNames.has(skillDisplayName)) try {
3131
3210
  const computedHash = await computeSkillFolderHash(skill.path);
3132
3211
  const skillFilePath = skillFiles[skill.name];
3212
+ const rawSource = lockSource || parsed.url;
3133
3213
  const lockEntry = {
3134
- source: lockSource || parsed.url,
3214
+ source: effectiveSourceType === "internal" || effectiveSourceType === "github" ? rawSource.replace(/^https?:\/\/[^@]+@/, "https://") : rawSource,
3135
3215
  sourceType: effectiveSourceType,
3136
3216
  computedHash
3137
3217
  };
@@ -3294,7 +3374,7 @@ const BOLD$2 = "\x1B[1m";
3294
3374
  const DIM$5 = "\x1B[38;5;102m";
3295
3375
  const TEXT$4 = "\x1B[38;5;145m";
3296
3376
  const CYAN$1 = "\x1B[36m";
3297
- const YELLOW$4 = "\x1B[33m";
3377
+ const YELLOW$5 = "\x1B[33m";
3298
3378
  const SKILLS_API_URL = process.env.SKILLS_API_URL;
3299
3379
  const SEARCH_ENDPOINT = SKILLS_API_URL ? `${SKILLS_API_URL.replace(/\/+$/, "")}/search` : "https://next-ai-base.pre-fn.alibaba-inc.com/api/skills/search";
3300
3380
  function formatInstalls(count) {
@@ -3364,7 +3444,7 @@ async function runSearchPrompt(initialQuery = "") {
3364
3444
  const source = skill.source ? ` ${DIM$5}${skill.source}${RESET$5}` : "";
3365
3445
  const installs = formatInstalls(skill.installs);
3366
3446
  const installsBadge = installs ? ` ${CYAN$1}${installs}${RESET$5}` : "";
3367
- const githubBadge = skill.sourceType === "github" ? ` ${YELLOW$4}GitHub${RESET$5}` : "";
3447
+ const githubBadge = skill.sourceType === "github" ? ` ${YELLOW$5}GitHub${RESET$5}` : "";
3368
3448
  const loadingIndicator = loading && i === 0 ? ` ${DIM$5}...${RESET$5}` : "";
3369
3449
  lines.push(` ${arrow} ${name}${source}${githubBadge}${installsBadge}${loadingIndicator}`);
3370
3450
  }
@@ -3473,7 +3553,7 @@ ${DIM$5} 2) npx @ali/cli-skills add <owner/repo@skill>${RESET$5}`;
3473
3553
  for (const skill of results.slice(0, 6)) {
3474
3554
  const pkg = skill.source || skill.slug;
3475
3555
  const installs = formatInstalls(skill.installs);
3476
- const githubBadge = skill.sourceType === "github" ? ` ${YELLOW$4}GitHub${RESET$5}` : "";
3556
+ const githubBadge = skill.sourceType === "github" ? ` ${YELLOW$5}GitHub${RESET$5}` : "";
3477
3557
  console.log(`${TEXT$4}${pkg}@${skill.name}${RESET$5}${githubBadge}${installs ? ` ${CYAN$1}${installs}${RESET$5}` : ""}`);
3478
3558
  const skillUrl = buildSkillUrl(skill);
3479
3559
  console.log(`${DIM$5}└ ${skillUrl}${RESET$5}`);
@@ -3601,7 +3681,7 @@ async function runSync(args, options = {}) {
3601
3681
  M.info(`${import_picocolors.default.cyan(skill.name)} ${import_picocolors.default.dim(`from ${skill.packageName}`)}`);
3602
3682
  if (skill.description) M.message(import_picocolors.default.dim(` ${skill.description}`));
3603
3683
  }
3604
- const localLock = await readLocalLock(cwd);
3684
+ const { lock: localLock } = await readLocalLock(cwd);
3605
3685
  const toInstall = [];
3606
3686
  const upToDate = [];
3607
3687
  if (options.force) {
@@ -3801,7 +3881,8 @@ function parseSyncOptions(args) {
3801
3881
  return { options };
3802
3882
  }
3803
3883
  async function runInstallFromLock(args) {
3804
- const lock = await readLocalLock(process.cwd());
3884
+ const { lock, isOutdated } = await readLocalLock(process.cwd());
3885
+ if (isOutdated) M.warn("Project lock file may be outdated. Some skills might not install correctly.");
3805
3886
  const skillEntries = Object.entries(lock.skills);
3806
3887
  if (skillEntries.length === 0) {
3807
3888
  M.warn("No project skills found in skills-lock.json");
@@ -3852,7 +3933,7 @@ const RESET$4 = "\x1B[0m";
3852
3933
  const BOLD$1 = "\x1B[1m";
3853
3934
  const DIM$4 = "\x1B[38;5;102m";
3854
3935
  const CYAN = "\x1B[36m";
3855
- const YELLOW$3 = "\x1B[33m";
3936
+ const YELLOW$4 = "\x1B[33m";
3856
3937
  function shortenPath(fullPath, cwd) {
3857
3938
  const home = homedir();
3858
3939
  if (fullPath.startsWith(home)) return fullPath.replace(home, "~");
@@ -3886,7 +3967,7 @@ async function runList(args) {
3886
3967
  const validAgents = Object.keys(agents);
3887
3968
  const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
3888
3969
  if (invalidAgents.length > 0) {
3889
- console.log(`${YELLOW$3}Invalid agents: ${invalidAgents.join(", ")}${RESET$4}`);
3970
+ console.log(`${YELLOW$4}Invalid agents: ${invalidAgents.join(", ")}${RESET$4}`);
3890
3971
  console.log(`${DIM$4}Valid agents: ${validAgents.join(", ")}${RESET$4}`);
3891
3972
  process.exit(1);
3892
3973
  }
@@ -3923,7 +4004,7 @@ async function runList(args) {
3923
4004
  const prefix = indent ? " " : "";
3924
4005
  const shortPath = shortenPath(skill.canonicalPath, cwd);
3925
4006
  const agentNames = skill.agents.map((a) => agents[a].displayName);
3926
- const agentInfo = skill.agents.length > 0 ? formatList(agentNames) : `${YELLOW$3}not linked${RESET$4}`;
4007
+ const agentInfo = skill.agents.length > 0 ? formatList(agentNames) : `${YELLOW$4}not linked${RESET$4}`;
3927
4008
  console.log(`${prefix}${CYAN}${skill.name}${RESET$4} ${DIM$4}${shortPath}${RESET$4}`);
3928
4009
  console.log(`${prefix} ${DIM$4}Agents:${RESET$4} ${agentInfo}`);
3929
4010
  }
@@ -4526,7 +4607,7 @@ const DIM$3 = "\x1B[38;5;102m";
4526
4607
  const TEXT$3 = "\x1B[38;5;145m";
4527
4608
  const RESET$3 = "\x1B[0m";
4528
4609
  const GREEN$2 = "\x1B[32m";
4529
- const YELLOW$2 = "\x1B[33m";
4610
+ const YELLOW$3 = "\x1B[33m";
4530
4611
  function startLocalServer() {
4531
4612
  return new Promise((resolve) => {
4532
4613
  let resolveCallback;
@@ -4674,7 +4755,7 @@ async function status() {
4674
4755
  console.log(` 工号: ${auth.empId}`);
4675
4756
  console.log(` 网关: ${auth.gatewayUrl}`);
4676
4757
  if (expired) {
4677
- console.log(` Token: ${YELLOW$2}即将过期${RESET$3}`);
4758
+ console.log(` Token: ${YELLOW$3}即将过期${RESET$3}`);
4678
4759
  console.log(`${TEXT$3}建议重新登录: npx ali-skills login${RESET$3}`);
4679
4760
  } else console.log(` Token: ${GREEN$2}有效${RESET$3} (还剩 ${remainingDays} 天)`);
4680
4761
  }
@@ -4762,7 +4843,7 @@ const TEXT$2 = "\x1B[38;5;145m";
4762
4843
  const RESET$2 = "\x1B[0m";
4763
4844
  const GREEN$1 = "\x1B[32m";
4764
4845
  const RED$1 = "\x1B[31m";
4765
- const YELLOW$1 = "\x1B[33m";
4846
+ const YELLOW$2 = "\x1B[33m";
4766
4847
  function openBrowser$1(url) {
4767
4848
  const platform = process.platform;
4768
4849
  spawn(platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open", [url], {
@@ -4797,7 +4878,7 @@ function getPlatformPrivateToken(platformKey, explicitToken) {
4797
4878
  }
4798
4879
  async function promptConfigureToken(platformKey, platform) {
4799
4880
  console.log();
4800
- console.log(`${YELLOW$1}⚠️ ${platform.name} 需要配置 Private Token${RESET$2}`);
4881
+ console.log(`${YELLOW$2}⚠️ ${platform.name} 需要配置 Private Token${RESET$2}`);
4801
4882
  if (platform.tokenDocUrl) console.log(`${DIM$2}Token 获取地址: ${platform.tokenDocUrl}${RESET$2}`);
4802
4883
  if (!await ye({
4803
4884
  message: "是否现在配置?",
@@ -5027,7 +5108,7 @@ const DIM$1 = "\x1B[38;5;102m";
5027
5108
  const TEXT$1 = "\x1B[38;5;145m";
5028
5109
  const RESET$1 = "\x1B[0m";
5029
5110
  const GREEN = "\x1B[32m";
5030
- const YELLOW = "\x1B[33m";
5111
+ const YELLOW$1 = "\x1B[33m";
5031
5112
  const RED = "\x1B[31m";
5032
5113
  function showConfigHelp() {
5033
5114
  console.log(`
@@ -5097,12 +5178,12 @@ async function configurePlatform(platformKey) {
5097
5178
  console.log(`${GREEN}✓ ${platform.name} 使用内置凭证,无需配置${RESET$1}`);
5098
5179
  break;
5099
5180
  case "app_code+buc":
5100
- console.log(`${YELLOW}! ${platform.name} 需要 BUC 登录${RESET$1}`);
5181
+ console.log(`${YELLOW$1}! ${platform.name} 需要 BUC 登录${RESET$1}`);
5101
5182
  console.log(`${DIM$1}请运行: npx ali-skills login${RESET$1}`);
5102
5183
  break;
5103
5184
  case "buc_sso_refresh":
5104
5185
  case "buc_sso_ticket":
5105
- console.log(`${YELLOW}! ${platform.name} 需要 BUC 登录${RESET$1}`);
5186
+ console.log(`${YELLOW$1}! ${platform.name} 需要 BUC 登录${RESET$1}`);
5106
5187
  console.log(`${DIM$1}请运行: npx ali-skills login${RESET$1}`);
5107
5188
  break;
5108
5189
  default:
@@ -5199,6 +5280,7 @@ const RESET = "\x1B[0m";
5199
5280
  const BOLD = "\x1B[1m";
5200
5281
  const DIM = "\x1B[38;5;102m";
5201
5282
  const TEXT = "\x1B[38;5;145m";
5283
+ const YELLOW = "\x1B[33m";
5202
5284
  const LOGO_LINES = [
5203
5285
  " █████╗ ██╗ ██╗ ███████╗██╗ ██╗██╗██╗ ██╗ ███████╗",
5204
5286
  "██╔══██╗██║ ██║ ██╔════╝██║ ██╔╝██║██║ ██║ ██╔════╝",
@@ -5560,26 +5642,42 @@ function readSkillLock() {
5560
5642
  try {
5561
5643
  const content = readFileSync(lockPath, "utf-8");
5562
5644
  const parsed = JSON.parse(content);
5563
- if (typeof parsed.version !== "number" || !parsed.skills) return {
5564
- version: CURRENT_LOCK_VERSION,
5565
- skills: {}
5645
+ if (typeof parsed.version !== "number") return {
5646
+ lock: {
5647
+ ...parsed,
5648
+ version: CURRENT_LOCK_VERSION
5649
+ },
5650
+ isOutdated: true
5566
5651
  };
5567
5652
  if (parsed.version < CURRENT_LOCK_VERSION) return {
5568
- version: CURRENT_LOCK_VERSION,
5569
- skills: {}
5653
+ lock: parsed,
5654
+ isOutdated: true
5655
+ };
5656
+ if (!parsed.skills) return {
5657
+ lock: {
5658
+ version: CURRENT_LOCK_VERSION,
5659
+ skills: {}
5660
+ },
5661
+ isOutdated: false
5662
+ };
5663
+ return {
5664
+ lock: parsed,
5665
+ isOutdated: false
5570
5666
  };
5571
- return parsed;
5572
5667
  } catch {
5573
5668
  return {
5574
- version: CURRENT_LOCK_VERSION,
5575
- skills: {}
5669
+ lock: {
5670
+ version: CURRENT_LOCK_VERSION,
5671
+ skills: {}
5672
+ },
5673
+ isOutdated: false
5576
5674
  };
5577
5675
  }
5578
5676
  }
5579
5677
  function getSkipReason(entry) {
5580
5678
  if (entry.sourceType === "local") return "Local path";
5581
5679
  if (entry.sourceType === "git") return "Git URL (hash tracking not supported)";
5582
- if (!entry.skillFolderHash) return "No version hash available";
5680
+ if (!(entry.sourceType === "internal" ? entry.commitHash : entry.skillFolderHash)) return "No version hash available";
5583
5681
  if (!entry.skillPath) return "No skill path recorded";
5584
5682
  return "No version tracking";
5585
5683
  }
@@ -5588,6 +5686,39 @@ async function checkSkillsForUpdates(skills, token) {
5588
5686
  const errors = [];
5589
5687
  const skipped = [];
5590
5688
  for (const [skillName, entry] of Object.entries(skills)) {
5689
+ if (entry.sourceType === "internal") {
5690
+ if (!entry.commitHash || !entry.skillPath) {
5691
+ skipped.push({
5692
+ name: skillName,
5693
+ reason: getSkipReason(entry),
5694
+ sourceUrl: entry.sourceUrl
5695
+ });
5696
+ continue;
5697
+ }
5698
+ try {
5699
+ const latestCommit = await fetchAliInternalCommitHash(entry.source, entry.skillPath, null);
5700
+ if (!latestCommit) {
5701
+ errors.push({
5702
+ name: skillName,
5703
+ source: entry.source,
5704
+ error: "Could not fetch from GitLab"
5705
+ });
5706
+ continue;
5707
+ }
5708
+ if (latestCommit !== entry.commitHash) updates.push({
5709
+ name: skillName,
5710
+ source: entry.source,
5711
+ entry
5712
+ });
5713
+ } catch (err) {
5714
+ errors.push({
5715
+ name: skillName,
5716
+ source: entry.source,
5717
+ error: err instanceof Error ? err.message : "Unknown error"
5718
+ });
5719
+ }
5720
+ continue;
5721
+ }
5591
5722
  if (!entry.skillFolderHash || !entry.skillPath) {
5592
5723
  skipped.push({
5593
5724
  name: skillName,
@@ -5634,7 +5765,7 @@ async function runCheck(args = []) {
5634
5765
  let skipped = [];
5635
5766
  let skillCount = 0;
5636
5767
  if (isGlobal) {
5637
- const globalLock = readSkillLock();
5768
+ const { lock: globalLock, isOutdated: isGlobalLockOutdated } = readSkillLock();
5638
5769
  const globalSkillNames = Object.keys(globalLock.skills);
5639
5770
  skillCount = globalSkillNames.length;
5640
5771
  if (globalSkillNames.length === 0) {
@@ -5656,9 +5787,11 @@ async function runCheck(args = []) {
5656
5787
  if (skipped.length > 0) {
5657
5788
  console.log();
5658
5789
  console.log(`${DIM} ${skipped.length} skill(s) cannot be checked automatically:${RESET}`);
5790
+ if (isGlobalLockOutdated) console.log(`${YELLOW} Note: Your lock file may be outdated. Re-adding these skills may fix this.${RESET}`);
5659
5791
  for (const skill of skipped) {
5660
5792
  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}`);
5793
+ const displaySource = getDisplaySource(skill.sourceUrl);
5794
+ console.log(` ${DIM}To update: ${TEXT}npx ali-skills add ${displaySource} -g -y${RESET}`);
5662
5795
  }
5663
5796
  }
5664
5797
  console.log();
@@ -5668,7 +5801,7 @@ async function runCheck(args = []) {
5668
5801
  console.log(`${DIM}Run${RESET} ${TEXT}npx ali-skills update -g${RESET} ${DIM}to update all global skills${RESET}`);
5669
5802
  }
5670
5803
  } else {
5671
- const projectLock = await readLocalLock();
5804
+ const { lock: projectLock, isOutdated: isLocalLockOutdated } = await readLocalLock();
5672
5805
  const projectSkillNames = Object.keys(projectLock.skills);
5673
5806
  skillCount = projectSkillNames.length;
5674
5807
  if (projectSkillNames.length === 0) {
@@ -5762,6 +5895,7 @@ async function runCheck(args = []) {
5762
5895
  if (skipped.length > 0) {
5763
5896
  console.log();
5764
5897
  console.log(`${DIM} ${skipped.length} skill(s) cannot be checked automatically:${RESET}`);
5898
+ if (isLocalLockOutdated) console.log(`${YELLOW} Note: Your lock file may be outdated. Re-adding these skills may fix this.${RESET}`);
5765
5899
  for (const skill of skipped) console.log(` ${TEXT}•${RESET} ${skill.name} ${DIM}(${skill.reason})${RESET}`);
5766
5900
  }
5767
5901
  console.log();
@@ -5789,10 +5923,11 @@ async function runUpdate(args = []) {
5789
5923
  let skillsToCheck = {};
5790
5924
  let scopeLabel = "project";
5791
5925
  if (isGlobal) {
5792
- skillsToCheck = readSkillLock().skills;
5926
+ const { lock: globalLock } = readSkillLock();
5927
+ skillsToCheck = globalLock.skills;
5793
5928
  scopeLabel = "global";
5794
5929
  } else {
5795
- const projectLock = await readLocalLock();
5930
+ const { lock: projectLock } = await readLocalLock();
5796
5931
  for (const [name, entry] of Object.entries(projectLock.skills)) {
5797
5932
  let sourceUrl;
5798
5933
  if (entry.sourceType === "github") sourceUrl = `https://github.com/${entry.source}`;
@@ -5818,7 +5953,7 @@ async function runUpdate(args = []) {
5818
5953
  }
5819
5954
  const availableUpdates = [];
5820
5955
  const skipped = [];
5821
- const projectLock = !isGlobal ? await readLocalLock() : null;
5956
+ const projectLock = (!isGlobal ? await readLocalLock() : null)?.lock ?? null;
5822
5957
  for (const skillName of skillNames) {
5823
5958
  const entry = skillsToCheck[skillName];
5824
5959
  if (!entry) continue;
@@ -5935,11 +6070,14 @@ async function runUpdate(args = []) {
5935
6070
  if (skillFolder.endsWith("/SKILL.md")) skillFolder = skillFolder.slice(0, -9);
5936
6071
  else if (skillFolder.endsWith("SKILL.md")) skillFolder = skillFolder.slice(0, -8);
5937
6072
  if (skillFolder.endsWith("/")) skillFolder = skillFolder.slice(0, -1);
6073
+ let sourceUrl = update.entry.sourceUrl || update.entry.source;
6074
+ if (update.entry.sourceType === "internal" && !sourceUrl.startsWith("http") && !sourceUrl.startsWith("git@")) sourceUrl = `https://code.alibaba-inc.com/${sourceUrl}.git`;
6075
+ else if (update.entry.sourceType === "github" && !sourceUrl.startsWith("http") && !sourceUrl.startsWith("git@")) sourceUrl = `https://github.com/${sourceUrl}.git`;
5938
6076
  let installUrl;
5939
6077
  if (skillFolder) {
5940
- installUrl = update.entry.sourceUrl.replace(/\.git$/, "").replace(/\/$/, "");
5941
- installUrl = `${installUrl}/tree/main/${skillFolder}`;
5942
- } else installUrl = update.entry.sourceUrl;
6078
+ installUrl = sourceUrl.replace(/\.git$/, "").replace(/\/$/, "");
6079
+ installUrl = `${installUrl}/tree/HEAD/${skillFolder}`;
6080
+ } else installUrl = sourceUrl;
5943
6081
  try {
5944
6082
  await runAdd([installUrl], {
5945
6083
  yes: true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ali/cli-skills",
3
- "version": "2.0.14",
3
+ "version": "2.0.16",
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.14",
3
+ "version": "0.0.16",
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.14"
34
+ "@ali/cli-skills": "^2.0.16"
35
35
  },
36
36
  "bundleDependencies": [
37
37
  "@ali/cli-skills"