ali-skills 0.0.15 → 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,25 +167,6 @@ 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 {
161
- type: "internal",
162
- url: `${host.replace("gitlab.alibaba-inc.com", "code.alibaba-inc.com")}/${repoPath.replace(/\.git$/, "")}.git`,
163
- ref
164
- };
165
- }
166
170
  const internalRepoWithSubpathMatch = input.match(/^(https?:\/\/(?:[^@/]+@)?(?:code|gitlab)\.alibaba-inc\.com)\/([^/]+)\/([^/]+)\/(.+)$/);
167
171
  if (internalRepoWithSubpathMatch) {
168
172
  const [, host, owner, repo, subpath] = internalRepoWithSubpathMatch;
@@ -220,6 +224,26 @@ function isWellKnownUrl(input) {
220
224
  return false;
221
225
  }
222
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
+ }
223
247
  const silentOutput = new Writable({ write(_chunk, _encoding, callback) {
224
248
  callback();
225
249
  } });
@@ -2056,6 +2080,25 @@ async function saveSelectedAgents(agents) {
2056
2080
  lock.lastSelectedAgents = agents;
2057
2081
  await writeSkillLock(lock);
2058
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
+ }
2059
2102
  const LOCAL_LOCK_FILE = "skills-lock.json";
2060
2103
  const CURRENT_VERSION = 1;
2061
2104
  function getLocalLockPath(cwd) {
@@ -2066,11 +2109,27 @@ async function readLocalLock(cwd) {
2066
2109
  try {
2067
2110
  const content = await readFile(lockPath, "utf-8");
2068
2111
  const parsed = JSON.parse(content);
2069
- if (typeof parsed.version !== "number" || !parsed.skills) return createEmptyLocalLock();
2070
- if (parsed.version < CURRENT_VERSION) return createEmptyLocalLock();
2071
- 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
+ };
2072
2128
  } catch {
2073
- return createEmptyLocalLock();
2129
+ return {
2130
+ lock: createEmptyLocalLock(),
2131
+ isOutdated: false
2132
+ };
2074
2133
  }
2075
2134
  }
2076
2135
  async function writeLocalLock(lock, cwd) {
@@ -2112,7 +2171,7 @@ async function collectFiles(baseDir, currentDir, results) {
2112
2171
  }));
2113
2172
  }
2114
2173
  async function addSkillToLocalLock(skillName, entry, cwd) {
2115
- const lock = await readLocalLock(cwd);
2174
+ const { lock } = await readLocalLock(cwd);
2116
2175
  lock.skills[skillName] = entry;
2117
2176
  await writeLocalLock(lock, cwd);
2118
2177
  }
@@ -2132,7 +2191,7 @@ function logSkillParseFailures(failures) {
2132
2191
  if (f.hint) M.message(import_picocolors.default.yellow(` 提示: ${f.hint}`));
2133
2192
  }
2134
2193
  }
2135
- var version$1 = "2.0.15";
2194
+ var version$1 = "2.0.16";
2136
2195
  const isCancelled$1 = (value) => typeof value === "symbol";
2137
2196
  async function isSourcePrivate(source) {
2138
2197
  const ownerRepo = parseOwnerRepo(source);
@@ -2386,7 +2445,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
2386
2445
  value: key,
2387
2446
  label: config.displayName
2388
2447
  })));
2389
- if (pD(selected)) {
2448
+ if (isCancelled$1(selected)) {
2390
2449
  xe("Installation cancelled");
2391
2450
  process.exit(0);
2392
2451
  }
@@ -2400,7 +2459,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
2400
2459
  } else M.info(`Installing to: ${installedAgents.map((a) => import_picocolors.default.cyan(agents[a].displayName)).join(", ")}`);
2401
2460
  } else {
2402
2461
  const selected = await selectAgentsInteractive({ global: options.global });
2403
- if (pD(selected)) {
2462
+ if (isCancelled$1(selected)) {
2404
2463
  xe("Installation cancelled");
2405
2464
  process.exit(0);
2406
2465
  }
@@ -2524,8 +2583,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
2524
2583
  await addSkillToLock(skill.installName, {
2525
2584
  source: sourceIdentifier,
2526
2585
  sourceType: "well-known",
2527
- sourceUrl: skill.sourceUrl,
2528
- skillFolderHash: ""
2586
+ sourceUrl: sanitizeSourceUrl(skill.sourceUrl)
2529
2587
  });
2530
2588
  } catch {}
2531
2589
  }
@@ -2886,7 +2944,7 @@ async function runAdd(args, options = {}) {
2886
2944
  value: key,
2887
2945
  label: config.displayName
2888
2946
  })));
2889
- if (pD(selected)) {
2947
+ if (isCancelled$1(selected)) {
2890
2948
  xe("Installation cancelled");
2891
2949
  await cleanup(tempDir);
2892
2950
  process.exit(0);
@@ -2901,7 +2959,7 @@ async function runAdd(args, options = {}) {
2901
2959
  } else M.info(`Installing to: ${installedAgents.map((a) => import_picocolors.default.cyan(agents[a].displayName)).join(", ")}`);
2902
2960
  } else {
2903
2961
  const selected = await selectAgentsInteractive({ global: options.global });
2904
- if (pD(selected)) {
2962
+ if (isCancelled$1(selected)) {
2905
2963
  xe("Installation cancelled");
2906
2964
  await cleanup(tempDir);
2907
2965
  process.exit(0);
@@ -3117,18 +3175,28 @@ async function runAdd(args, options = {}) {
3117
3175
  for (const skill of selectedSkills) {
3118
3176
  const skillDisplayName = getSkillDisplayName(skill);
3119
3177
  if (successfulSkillNames.has(skillDisplayName)) try {
3120
- let skillFolderHash = "";
3178
+ let skillFolderHash;
3179
+ let commitHash;
3121
3180
  const skillPathValue = skillFiles[skill.name];
3122
- 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) {
3123
3187
  const hash = await fetchSkillFolderHash(normalizedSource, skillPathValue, getGitHubToken());
3124
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;
3125
3192
  }
3126
3193
  await addSkillToLock(skill.name, {
3127
3194
  source: lockSource || normalizedSource,
3128
3195
  sourceType: effectiveSourceType,
3129
- sourceUrl: parsed.url,
3130
- skillPath: skillPathValue,
3131
- skillFolderHash,
3196
+ sourceUrl: sanitizeSourceUrl(parsed.url),
3197
+ skillPath,
3198
+ ...skillFolderHash && { skillFolderHash },
3199
+ ...commitHash && { commitHash },
3132
3200
  pluginName: skill.pluginName
3133
3201
  });
3134
3202
  } catch {}
@@ -3141,8 +3209,9 @@ async function runAdd(args, options = {}) {
3141
3209
  if (successfulSkillNames.has(skillDisplayName)) try {
3142
3210
  const computedHash = await computeSkillFolderHash(skill.path);
3143
3211
  const skillFilePath = skillFiles[skill.name];
3212
+ const rawSource = lockSource || parsed.url;
3144
3213
  const lockEntry = {
3145
- source: lockSource || parsed.url,
3214
+ source: effectiveSourceType === "internal" || effectiveSourceType === "github" ? rawSource.replace(/^https?:\/\/[^@]+@/, "https://") : rawSource,
3146
3215
  sourceType: effectiveSourceType,
3147
3216
  computedHash
3148
3217
  };
@@ -3305,7 +3374,7 @@ const BOLD$2 = "\x1B[1m";
3305
3374
  const DIM$5 = "\x1B[38;5;102m";
3306
3375
  const TEXT$4 = "\x1B[38;5;145m";
3307
3376
  const CYAN$1 = "\x1B[36m";
3308
- const YELLOW$4 = "\x1B[33m";
3377
+ const YELLOW$5 = "\x1B[33m";
3309
3378
  const SKILLS_API_URL = process.env.SKILLS_API_URL;
3310
3379
  const SEARCH_ENDPOINT = SKILLS_API_URL ? `${SKILLS_API_URL.replace(/\/+$/, "")}/search` : "https://next-ai-base.pre-fn.alibaba-inc.com/api/skills/search";
3311
3380
  function formatInstalls(count) {
@@ -3375,7 +3444,7 @@ async function runSearchPrompt(initialQuery = "") {
3375
3444
  const source = skill.source ? ` ${DIM$5}${skill.source}${RESET$5}` : "";
3376
3445
  const installs = formatInstalls(skill.installs);
3377
3446
  const installsBadge = installs ? ` ${CYAN$1}${installs}${RESET$5}` : "";
3378
- const githubBadge = skill.sourceType === "github" ? ` ${YELLOW$4}GitHub${RESET$5}` : "";
3447
+ const githubBadge = skill.sourceType === "github" ? ` ${YELLOW$5}GitHub${RESET$5}` : "";
3379
3448
  const loadingIndicator = loading && i === 0 ? ` ${DIM$5}...${RESET$5}` : "";
3380
3449
  lines.push(` ${arrow} ${name}${source}${githubBadge}${installsBadge}${loadingIndicator}`);
3381
3450
  }
@@ -3484,7 +3553,7 @@ ${DIM$5} 2) npx @ali/cli-skills add <owner/repo@skill>${RESET$5}`;
3484
3553
  for (const skill of results.slice(0, 6)) {
3485
3554
  const pkg = skill.source || skill.slug;
3486
3555
  const installs = formatInstalls(skill.installs);
3487
- const githubBadge = skill.sourceType === "github" ? ` ${YELLOW$4}GitHub${RESET$5}` : "";
3556
+ const githubBadge = skill.sourceType === "github" ? ` ${YELLOW$5}GitHub${RESET$5}` : "";
3488
3557
  console.log(`${TEXT$4}${pkg}@${skill.name}${RESET$5}${githubBadge}${installs ? ` ${CYAN$1}${installs}${RESET$5}` : ""}`);
3489
3558
  const skillUrl = buildSkillUrl(skill);
3490
3559
  console.log(`${DIM$5}└ ${skillUrl}${RESET$5}`);
@@ -3612,7 +3681,7 @@ async function runSync(args, options = {}) {
3612
3681
  M.info(`${import_picocolors.default.cyan(skill.name)} ${import_picocolors.default.dim(`from ${skill.packageName}`)}`);
3613
3682
  if (skill.description) M.message(import_picocolors.default.dim(` ${skill.description}`));
3614
3683
  }
3615
- const localLock = await readLocalLock(cwd);
3684
+ const { lock: localLock } = await readLocalLock(cwd);
3616
3685
  const toInstall = [];
3617
3686
  const upToDate = [];
3618
3687
  if (options.force) {
@@ -3812,7 +3881,8 @@ function parseSyncOptions(args) {
3812
3881
  return { options };
3813
3882
  }
3814
3883
  async function runInstallFromLock(args) {
3815
- 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.");
3816
3886
  const skillEntries = Object.entries(lock.skills);
3817
3887
  if (skillEntries.length === 0) {
3818
3888
  M.warn("No project skills found in skills-lock.json");
@@ -3863,7 +3933,7 @@ const RESET$4 = "\x1B[0m";
3863
3933
  const BOLD$1 = "\x1B[1m";
3864
3934
  const DIM$4 = "\x1B[38;5;102m";
3865
3935
  const CYAN = "\x1B[36m";
3866
- const YELLOW$3 = "\x1B[33m";
3936
+ const YELLOW$4 = "\x1B[33m";
3867
3937
  function shortenPath(fullPath, cwd) {
3868
3938
  const home = homedir();
3869
3939
  if (fullPath.startsWith(home)) return fullPath.replace(home, "~");
@@ -3897,7 +3967,7 @@ async function runList(args) {
3897
3967
  const validAgents = Object.keys(agents);
3898
3968
  const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
3899
3969
  if (invalidAgents.length > 0) {
3900
- console.log(`${YELLOW$3}Invalid agents: ${invalidAgents.join(", ")}${RESET$4}`);
3970
+ console.log(`${YELLOW$4}Invalid agents: ${invalidAgents.join(", ")}${RESET$4}`);
3901
3971
  console.log(`${DIM$4}Valid agents: ${validAgents.join(", ")}${RESET$4}`);
3902
3972
  process.exit(1);
3903
3973
  }
@@ -3934,7 +4004,7 @@ async function runList(args) {
3934
4004
  const prefix = indent ? " " : "";
3935
4005
  const shortPath = shortenPath(skill.canonicalPath, cwd);
3936
4006
  const agentNames = skill.agents.map((a) => agents[a].displayName);
3937
- 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}`;
3938
4008
  console.log(`${prefix}${CYAN}${skill.name}${RESET$4} ${DIM$4}${shortPath}${RESET$4}`);
3939
4009
  console.log(`${prefix} ${DIM$4}Agents:${RESET$4} ${agentInfo}`);
3940
4010
  }
@@ -4537,7 +4607,7 @@ const DIM$3 = "\x1B[38;5;102m";
4537
4607
  const TEXT$3 = "\x1B[38;5;145m";
4538
4608
  const RESET$3 = "\x1B[0m";
4539
4609
  const GREEN$2 = "\x1B[32m";
4540
- const YELLOW$2 = "\x1B[33m";
4610
+ const YELLOW$3 = "\x1B[33m";
4541
4611
  function startLocalServer() {
4542
4612
  return new Promise((resolve) => {
4543
4613
  let resolveCallback;
@@ -4685,7 +4755,7 @@ async function status() {
4685
4755
  console.log(` 工号: ${auth.empId}`);
4686
4756
  console.log(` 网关: ${auth.gatewayUrl}`);
4687
4757
  if (expired) {
4688
- console.log(` Token: ${YELLOW$2}即将过期${RESET$3}`);
4758
+ console.log(` Token: ${YELLOW$3}即将过期${RESET$3}`);
4689
4759
  console.log(`${TEXT$3}建议重新登录: npx ali-skills login${RESET$3}`);
4690
4760
  } else console.log(` Token: ${GREEN$2}有效${RESET$3} (还剩 ${remainingDays} 天)`);
4691
4761
  }
@@ -4773,7 +4843,7 @@ const TEXT$2 = "\x1B[38;5;145m";
4773
4843
  const RESET$2 = "\x1B[0m";
4774
4844
  const GREEN$1 = "\x1B[32m";
4775
4845
  const RED$1 = "\x1B[31m";
4776
- const YELLOW$1 = "\x1B[33m";
4846
+ const YELLOW$2 = "\x1B[33m";
4777
4847
  function openBrowser$1(url) {
4778
4848
  const platform = process.platform;
4779
4849
  spawn(platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open", [url], {
@@ -4808,7 +4878,7 @@ function getPlatformPrivateToken(platformKey, explicitToken) {
4808
4878
  }
4809
4879
  async function promptConfigureToken(platformKey, platform) {
4810
4880
  console.log();
4811
- console.log(`${YELLOW$1}⚠️ ${platform.name} 需要配置 Private Token${RESET$2}`);
4881
+ console.log(`${YELLOW$2}⚠️ ${platform.name} 需要配置 Private Token${RESET$2}`);
4812
4882
  if (platform.tokenDocUrl) console.log(`${DIM$2}Token 获取地址: ${platform.tokenDocUrl}${RESET$2}`);
4813
4883
  if (!await ye({
4814
4884
  message: "是否现在配置?",
@@ -5038,7 +5108,7 @@ const DIM$1 = "\x1B[38;5;102m";
5038
5108
  const TEXT$1 = "\x1B[38;5;145m";
5039
5109
  const RESET$1 = "\x1B[0m";
5040
5110
  const GREEN = "\x1B[32m";
5041
- const YELLOW = "\x1B[33m";
5111
+ const YELLOW$1 = "\x1B[33m";
5042
5112
  const RED = "\x1B[31m";
5043
5113
  function showConfigHelp() {
5044
5114
  console.log(`
@@ -5108,12 +5178,12 @@ async function configurePlatform(platformKey) {
5108
5178
  console.log(`${GREEN}✓ ${platform.name} 使用内置凭证,无需配置${RESET$1}`);
5109
5179
  break;
5110
5180
  case "app_code+buc":
5111
- console.log(`${YELLOW}! ${platform.name} 需要 BUC 登录${RESET$1}`);
5181
+ console.log(`${YELLOW$1}! ${platform.name} 需要 BUC 登录${RESET$1}`);
5112
5182
  console.log(`${DIM$1}请运行: npx ali-skills login${RESET$1}`);
5113
5183
  break;
5114
5184
  case "buc_sso_refresh":
5115
5185
  case "buc_sso_ticket":
5116
- console.log(`${YELLOW}! ${platform.name} 需要 BUC 登录${RESET$1}`);
5186
+ console.log(`${YELLOW$1}! ${platform.name} 需要 BUC 登录${RESET$1}`);
5117
5187
  console.log(`${DIM$1}请运行: npx ali-skills login${RESET$1}`);
5118
5188
  break;
5119
5189
  default:
@@ -5210,6 +5280,7 @@ const RESET = "\x1B[0m";
5210
5280
  const BOLD = "\x1B[1m";
5211
5281
  const DIM = "\x1B[38;5;102m";
5212
5282
  const TEXT = "\x1B[38;5;145m";
5283
+ const YELLOW = "\x1B[33m";
5213
5284
  const LOGO_LINES = [
5214
5285
  " █████╗ ██╗ ██╗ ███████╗██╗ ██╗██╗██╗ ██╗ ███████╗",
5215
5286
  "██╔══██╗██║ ██║ ██╔════╝██║ ██╔╝██║██║ ██║ ██╔════╝",
@@ -5571,26 +5642,42 @@ function readSkillLock() {
5571
5642
  try {
5572
5643
  const content = readFileSync(lockPath, "utf-8");
5573
5644
  const parsed = JSON.parse(content);
5574
- if (typeof parsed.version !== "number" || !parsed.skills) return {
5575
- version: CURRENT_LOCK_VERSION,
5576
- skills: {}
5645
+ if (typeof parsed.version !== "number") return {
5646
+ lock: {
5647
+ ...parsed,
5648
+ version: CURRENT_LOCK_VERSION
5649
+ },
5650
+ isOutdated: true
5577
5651
  };
5578
5652
  if (parsed.version < CURRENT_LOCK_VERSION) return {
5579
- version: CURRENT_LOCK_VERSION,
5580
- 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
5581
5666
  };
5582
- return parsed;
5583
5667
  } catch {
5584
5668
  return {
5585
- version: CURRENT_LOCK_VERSION,
5586
- skills: {}
5669
+ lock: {
5670
+ version: CURRENT_LOCK_VERSION,
5671
+ skills: {}
5672
+ },
5673
+ isOutdated: false
5587
5674
  };
5588
5675
  }
5589
5676
  }
5590
5677
  function getSkipReason(entry) {
5591
5678
  if (entry.sourceType === "local") return "Local path";
5592
5679
  if (entry.sourceType === "git") return "Git URL (hash tracking not supported)";
5593
- if (!entry.skillFolderHash) return "No version hash available";
5680
+ if (!(entry.sourceType === "internal" ? entry.commitHash : entry.skillFolderHash)) return "No version hash available";
5594
5681
  if (!entry.skillPath) return "No skill path recorded";
5595
5682
  return "No version tracking";
5596
5683
  }
@@ -5599,6 +5686,39 @@ async function checkSkillsForUpdates(skills, token) {
5599
5686
  const errors = [];
5600
5687
  const skipped = [];
5601
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
+ }
5602
5722
  if (!entry.skillFolderHash || !entry.skillPath) {
5603
5723
  skipped.push({
5604
5724
  name: skillName,
@@ -5645,7 +5765,7 @@ async function runCheck(args = []) {
5645
5765
  let skipped = [];
5646
5766
  let skillCount = 0;
5647
5767
  if (isGlobal) {
5648
- const globalLock = readSkillLock();
5768
+ const { lock: globalLock, isOutdated: isGlobalLockOutdated } = readSkillLock();
5649
5769
  const globalSkillNames = Object.keys(globalLock.skills);
5650
5770
  skillCount = globalSkillNames.length;
5651
5771
  if (globalSkillNames.length === 0) {
@@ -5667,9 +5787,11 @@ async function runCheck(args = []) {
5667
5787
  if (skipped.length > 0) {
5668
5788
  console.log();
5669
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}`);
5670
5791
  for (const skill of skipped) {
5671
5792
  console.log(` ${TEXT}•${RESET} ${skill.name} ${DIM}(${skill.reason})${RESET}`);
5672
- 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}`);
5673
5795
  }
5674
5796
  }
5675
5797
  console.log();
@@ -5679,7 +5801,7 @@ async function runCheck(args = []) {
5679
5801
  console.log(`${DIM}Run${RESET} ${TEXT}npx ali-skills update -g${RESET} ${DIM}to update all global skills${RESET}`);
5680
5802
  }
5681
5803
  } else {
5682
- const projectLock = await readLocalLock();
5804
+ const { lock: projectLock, isOutdated: isLocalLockOutdated } = await readLocalLock();
5683
5805
  const projectSkillNames = Object.keys(projectLock.skills);
5684
5806
  skillCount = projectSkillNames.length;
5685
5807
  if (projectSkillNames.length === 0) {
@@ -5773,6 +5895,7 @@ async function runCheck(args = []) {
5773
5895
  if (skipped.length > 0) {
5774
5896
  console.log();
5775
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}`);
5776
5899
  for (const skill of skipped) console.log(` ${TEXT}•${RESET} ${skill.name} ${DIM}(${skill.reason})${RESET}`);
5777
5900
  }
5778
5901
  console.log();
@@ -5800,10 +5923,11 @@ async function runUpdate(args = []) {
5800
5923
  let skillsToCheck = {};
5801
5924
  let scopeLabel = "project";
5802
5925
  if (isGlobal) {
5803
- skillsToCheck = readSkillLock().skills;
5926
+ const { lock: globalLock } = readSkillLock();
5927
+ skillsToCheck = globalLock.skills;
5804
5928
  scopeLabel = "global";
5805
5929
  } else {
5806
- const projectLock = await readLocalLock();
5930
+ const { lock: projectLock } = await readLocalLock();
5807
5931
  for (const [name, entry] of Object.entries(projectLock.skills)) {
5808
5932
  let sourceUrl;
5809
5933
  if (entry.sourceType === "github") sourceUrl = `https://github.com/${entry.source}`;
@@ -5829,7 +5953,7 @@ async function runUpdate(args = []) {
5829
5953
  }
5830
5954
  const availableUpdates = [];
5831
5955
  const skipped = [];
5832
- const projectLock = !isGlobal ? await readLocalLock() : null;
5956
+ const projectLock = (!isGlobal ? await readLocalLock() : null)?.lock ?? null;
5833
5957
  for (const skillName of skillNames) {
5834
5958
  const entry = skillsToCheck[skillName];
5835
5959
  if (!entry) continue;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ali/cli-skills",
3
- "version": "2.0.15",
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.15",
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.15"
34
+ "@ali/cli-skills": "^2.0.16"
35
35
  },
36
36
  "bundleDependencies": [
37
37
  "@ali/cli-skills"