ali-skills 0.0.11 → 0.0.12

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.
@@ -166,6 +166,14 @@ function parseSource(input) {
166
166
  type: "internal",
167
167
  url: input.replace(/\bgitlab\.alibaba-inc\.com\b/g, "code.alibaba-inc.com")
168
168
  };
169
+ const internalSshMatch = input.match(/^git@(?:code|gitlab)\.alibaba-inc\.com:(.+?)(?:\.git)?$/);
170
+ if (internalSshMatch) {
171
+ const repoPath = internalSshMatch[1];
172
+ if (repoPath.includes("/")) return {
173
+ type: "internal",
174
+ url: `git@code.alibaba-inc.com:${repoPath}.git`
175
+ };
176
+ }
169
177
  if (isWellKnownUrl(input)) return {
170
178
  type: "well-known",
171
179
  url: input
@@ -365,6 +373,37 @@ async function searchMultiselect(options) {
365
373
  });
366
374
  }
367
375
  const CLONE_TIMEOUT_MS = 6e4;
376
+ function getGitUserConfig() {
377
+ try {
378
+ const name = execSync("git config user.name", {
379
+ encoding: "utf-8",
380
+ stdio: [
381
+ "pipe",
382
+ "pipe",
383
+ "ignore"
384
+ ]
385
+ }).trim();
386
+ const email = execSync("git config user.email", {
387
+ encoding: "utf-8",
388
+ stdio: [
389
+ "pipe",
390
+ "pipe",
391
+ "ignore"
392
+ ]
393
+ }).trim();
394
+ if (!name || !email) return null;
395
+ const emailMatch = email.match(/^([a-z0-9._-]+)@/i);
396
+ return {
397
+ username: (name || (emailMatch ? emailMatch[1] : "")) ?? "",
398
+ email
399
+ };
400
+ } catch {
401
+ return null;
402
+ }
403
+ }
404
+ function getCurrentUser() {
405
+ return getGitUserConfig();
406
+ }
368
407
  var GitCloneError = class extends Error {
369
408
  url;
370
409
  isTimeout;
@@ -677,12 +716,24 @@ async function parseSkillMd(skillMdPath, options) {
677
716
  });
678
717
  return null;
679
718
  }
719
+ const extractAuthorInfo = (data) => {
720
+ const authorObj = data.author && typeof data.author === "object" && !Array.isArray(data.author) ? data.author : {};
721
+ return {
722
+ authorName: typeof authorObj.nickname === "string" && authorObj.nickname || typeof authorObj.name === "string" && authorObj.name || void 0,
723
+ authorEmpId: typeof authorObj.empId === "string" && authorObj.empId || void 0,
724
+ authorAvatar: typeof authorObj.avatar === "string" && authorObj.avatar || void 0
725
+ };
726
+ };
727
+ const { authorName, authorEmpId, authorAvatar } = extractAuthorInfo(data);
680
728
  return {
681
729
  name: data.name,
682
730
  description: data.description,
683
731
  path: dirname(skillMdPath),
684
732
  rawContent: content,
685
- metadata: data.metadata
733
+ metadata: data.metadata,
734
+ authorName,
735
+ authorEmpId,
736
+ authorAvatar
686
737
  };
687
738
  }
688
739
  async function findSkillDirs(dir, depth = 0, maxDepth = 5) {
@@ -2032,7 +2083,7 @@ function logSkillParseFailures(failures) {
2032
2083
  if (f.hint) M.message(import_picocolors.default.yellow(` 提示: ${f.hint}`));
2033
2084
  }
2034
2085
  }
2035
- var version$1 = "2.0.10";
2086
+ var version$1 = "2.0.11";
2036
2087
  const isCancelled$1 = (value) => typeof value === "symbol";
2037
2088
  async function isSourcePrivate(source) {
2038
2089
  const ownerRepo = parseOwnerRepo(source);
@@ -2405,16 +2456,20 @@ async function handleWellKnownSkills(source, url, options, spinner) {
2405
2456
  skillFiles[skill.installName] = skill.sourceUrl;
2406
2457
  if (skill.description) skillDescriptions[skill.installName] = skill.description;
2407
2458
  }
2408
- if (await isSourcePrivate(sourceIdentifier) !== true) track({
2409
- event: "install",
2410
- source: sourceIdentifier,
2411
- skills: selectedSkills.map((s) => s.installName).join(","),
2412
- agents: targetAgents.join(","),
2413
- ...installGlobally && { global: "1" },
2414
- skillFiles: JSON.stringify(skillFiles),
2415
- sourceType: "well-known",
2416
- descriptions: JSON.stringify(skillDescriptions)
2417
- });
2459
+ if (await isSourcePrivate(sourceIdentifier) !== true) {
2460
+ const currentUser = getCurrentUser();
2461
+ track({
2462
+ event: "install",
2463
+ source: sourceIdentifier,
2464
+ skills: selectedSkills.map((s) => s.installName).join(","),
2465
+ agents: targetAgents.join(","),
2466
+ ...installGlobally && { global: "1" },
2467
+ skillFiles: JSON.stringify(skillFiles),
2468
+ sourceType: "well-known",
2469
+ descriptions: JSON.stringify(skillDescriptions),
2470
+ ...currentUser && { user: JSON.stringify(currentUser) }
2471
+ });
2472
+ }
2418
2473
  if (successful.length > 0 && installGlobally) {
2419
2474
  const successfulSkillNames = new Set(successful.map((r) => r.skill));
2420
2475
  for (const skill of selectedSkills) if (successfulSkillNames.has(skill.installName)) try {
@@ -2523,6 +2578,13 @@ async function runAdd(args, options = {}) {
2523
2578
  const spinner = Y();
2524
2579
  spinner.start("Parsing source...");
2525
2580
  const parsed = parseSource(resolvedSource);
2581
+ if (parsed.type === "internal" && parsed.url.startsWith("git@")) {
2582
+ const sshMatch = parsed.url.match(/^git@code\.alibaba-inc\.com:(.+)$/);
2583
+ if (sshMatch) {
2584
+ const repoPath = sshMatch[1].replace(/\.git$/, "");
2585
+ parsed.url = `https://${GITLAB_ACCOUNT.user}:${GITLAB_ACCOUNT.token}@code.alibaba-inc.com/${repoPath}.git`;
2586
+ }
2587
+ }
2526
2588
  if (options.branch) {
2527
2589
  parsed.ref = options.branch;
2528
2590
  parsed.subpath = void 0;
@@ -2927,6 +2989,7 @@ async function runAdd(args, options = {}) {
2927
2989
  const failed = results.filter((r) => !r.success);
2928
2990
  const skillFiles = {};
2929
2991
  const skillDescriptions = {};
2992
+ const skillMdAuthors = {};
2930
2993
  for (const skill of selectedSkills) {
2931
2994
  let relativePath;
2932
2995
  if (tempDir && skill.path === tempDir) relativePath = "SKILL.md";
@@ -2934,29 +2997,59 @@ async function runAdd(args, options = {}) {
2934
2997
  else continue;
2935
2998
  skillFiles[skill.name] = relativePath;
2936
2999
  if (skill.description) skillDescriptions[skill.name] = skill.description;
3000
+ if (skill.authorName || skill.authorEmpId || skill.authorAvatar) skillMdAuthors[skill.name] = {
3001
+ name: skill.authorName,
3002
+ empId: skill.authorEmpId,
3003
+ avatar: skill.authorAvatar
3004
+ };
2937
3005
  }
2938
3006
  const normalizedSource = getOwnerRepo(parsed);
2939
3007
  const effectiveSourceType = parsed.type;
2940
3008
  const lockSource = parsed.url.startsWith("git@") ? parsed.url : normalizedSource;
2941
- let skillAuthor;
3009
+ const trackableSkillNames = selectedSkills.filter((s) => isValidSkillName(s.name)).map((s) => s.name);
3010
+ const skillMdLastCommitAuthors = {};
2942
3011
  if (parsed.type === "internal" && normalizedSource) {
2943
3012
  const gitlabToken = GITLAB_ACCOUNT.token;
2944
3013
  if (gitlabToken) {
2945
3014
  const project = await getGitLabProject(normalizedSource, gitlabToken);
2946
- if (project) {
2947
- const firstSkillPath = Object.values(skillFiles)[0];
2948
- if (firstSkillPath) {
2949
- const author = await getSkillLastCommitAuthor(project.id, firstSkillPath, gitlabToken);
2950
- if (author) skillAuthor = author;
3015
+ if (project) for (const skillName of trackableSkillNames) {
3016
+ const skillFilePath = skillFiles[skillName];
3017
+ if (skillFilePath) {
3018
+ const author = await getSkillLastCommitAuthor(project.id, skillFilePath, gitlabToken);
3019
+ if (author) {
3020
+ const formattedName = author.username ? `${author.name}/${author.username}` : author.name;
3021
+ skillMdLastCommitAuthors[skillName] = {
3022
+ employeeId: author.employeeId,
3023
+ email: author.email,
3024
+ name: formattedName
3025
+ };
3026
+ }
2951
3027
  }
2952
3028
  }
2953
3029
  }
2954
3030
  }
2955
- const trackableSkillNames = selectedSkills.filter((s) => isValidSkillName(s.name)).map((s) => s.name);
2956
3031
  if (normalizedSource && trackableSkillNames.length > 0) {
2957
3032
  const ownerRepo = parseOwnerRepo(normalizedSource);
2958
3033
  if (ownerRepo) {
2959
- if (await isRepoPrivate(ownerRepo.owner, ownerRepo.repo) === false) track({
3034
+ if (await isRepoPrivate(ownerRepo.owner, ownerRepo.repo) === false) {
3035
+ const currentUser = getCurrentUser();
3036
+ track({
3037
+ event: "install",
3038
+ source: normalizedSource,
3039
+ skills: trackableSkillNames.join(","),
3040
+ agents: targetAgents.join(","),
3041
+ ...installGlobally && { global: "1" },
3042
+ skillFiles: JSON.stringify(skillFiles),
3043
+ sourceType: effectiveSourceType,
3044
+ skillMdLastCommitAuthors: JSON.stringify(skillMdLastCommitAuthors),
3045
+ skillMdConfigAuthors: JSON.stringify(skillMdAuthors),
3046
+ descriptions: JSON.stringify(skillDescriptions),
3047
+ ...currentUser && { user: JSON.stringify(currentUser) }
3048
+ });
3049
+ }
3050
+ } else {
3051
+ const currentUser = getCurrentUser();
3052
+ track({
2960
3053
  event: "install",
2961
3054
  source: normalizedSource,
2962
3055
  skills: trackableSkillNames.join(","),
@@ -2964,20 +3057,12 @@ async function runAdd(args, options = {}) {
2964
3057
  ...installGlobally && { global: "1" },
2965
3058
  skillFiles: JSON.stringify(skillFiles),
2966
3059
  sourceType: effectiveSourceType,
2967
- author: JSON.stringify(skillAuthor),
2968
- descriptions: JSON.stringify(skillDescriptions)
3060
+ skillMdLastCommitAuthors: JSON.stringify(skillMdLastCommitAuthors),
3061
+ skillMdConfigAuthors: JSON.stringify(skillMdAuthors),
3062
+ descriptions: JSON.stringify(skillDescriptions),
3063
+ ...currentUser && { user: JSON.stringify(currentUser) }
2969
3064
  });
2970
- } else track({
2971
- event: "install",
2972
- source: normalizedSource,
2973
- skills: trackableSkillNames.join(","),
2974
- agents: targetAgents.join(","),
2975
- ...installGlobally && { global: "1" },
2976
- skillFiles: JSON.stringify(skillFiles),
2977
- sourceType: effectiveSourceType,
2978
- author: JSON.stringify(skillAuthor),
2979
- descriptions: JSON.stringify(skillDescriptions)
2980
- });
3065
+ }
2981
3066
  }
2982
3067
  if (successful.length > 0 && installGlobally && normalizedSource) {
2983
3068
  const successfulSkillNames = new Set(successful.map((r) => r.skill));
@@ -4026,13 +4111,19 @@ function detectRepoInfo() {
4026
4111
  }).trim();
4027
4112
  if (!remoteUrl) return null;
4028
4113
  if (remoteUrl.includes("code.alibaba-inc.com") || remoteUrl.includes("gitlab.alibaba-inc.com")) {
4029
- const match = remoteUrl.match(/(?:code|gitlab)\.alibaba-inc\.com[/:]([^/]+)\/([^/.]+)/);
4030
- if (match) return {
4031
- sourceType: "internal",
4032
- owner: match[1],
4033
- repo: match[2],
4034
- remoteUrl
4035
- };
4114
+ const match = remoteUrl.match(/(?:code|gitlab)\.alibaba-inc\.com[\/:](.+?)(?:\.git)?$/);
4115
+ if (match) {
4116
+ const pathParts = match[1].split("/");
4117
+ if (pathParts.length >= 2) {
4118
+ const repo = pathParts.pop();
4119
+ return {
4120
+ sourceType: "internal",
4121
+ owner: pathParts.join("/"),
4122
+ repo,
4123
+ remoteUrl
4124
+ };
4125
+ }
4126
+ }
4036
4127
  }
4037
4128
  if (remoteUrl.includes("github.com")) {
4038
4129
  const match = remoteUrl.match(/github\.com[/:]([^/]+)\/([^/.]+)/);
@@ -4233,12 +4324,18 @@ async function runPublish(args, options = {}) {
4233
4324
  const registerResult = await registerSkill({
4234
4325
  source,
4235
4326
  sourceType: repoInfo.sourceType,
4236
- skills: successful.map((r) => ({
4237
- name: r.skill,
4238
- zipUrl: r.zipUrl,
4239
- zipHash: r.hash,
4240
- description: selectedSkills.find((s) => getSkillDisplayName(s) === r.skill)?.description ?? ""
4241
- }))
4327
+ skills: successful.map((r) => {
4328
+ const skill = selectedSkills.find((s) => getSkillDisplayName(s) === r.skill);
4329
+ return {
4330
+ name: r.skill,
4331
+ zipUrl: r.zipUrl,
4332
+ zipHash: r.hash,
4333
+ description: skill?.description ?? "",
4334
+ authorName: skill?.authorName,
4335
+ authorEmpId: skill?.authorEmpId,
4336
+ authorAvatar: skill?.authorAvatar
4337
+ };
4338
+ })
4242
4339
  });
4243
4340
  if (registerResult.success) spinner.stop("Skills registered");
4244
4341
  else spinner.stop(import_picocolors.default.yellow(`Registration warning: ${registerResult.error}`));
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ali/cli-skills",
3
- "version": "2.0.10",
3
+ "version": "2.0.11",
4
4
  "description": "The open agent skills ecosystem",
5
5
  "type": "module",
6
6
  "bin": {
@@ -25,7 +25,7 @@
25
25
  "test": "vitest",
26
26
  "type-check": "tsc --noEmit",
27
27
  "publish:snapshot": "tnpm version prerelease --preid=snapshot --no-git-tag-version && tnpm publish --tag snapshot",
28
- "publish:latest:patch": "tnpm version patch && tnpm publish && git push --follow-tags"
28
+ "publish:latest:patch": "tnpm version patch && tnpm publish && git push --follow-tags --no-verify"
29
29
  },
30
30
  "lint-staged": {
31
31
  "src/**/*.ts": "prettier --write",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ali-skills",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
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.10"
34
+ "@ali/cli-skills": "^2.0.11"
35
35
  },
36
36
  "bundleDependencies": [
37
37
  "@ali/cli-skills"