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:
|
|
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
|
|
148
|
-
if (
|
|
149
|
-
const [, host,
|
|
150
|
-
if (
|
|
151
|
-
|
|
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")}/${
|
|
163
|
-
|
|
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"
|
|
2060
|
-
|
|
2061
|
-
|
|
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
|
|
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.
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
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
|
|
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:
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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"
|
|
5564
|
-
|
|
5565
|
-
|
|
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
|
-
|
|
5569
|
-
|
|
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
|
-
|
|
5575
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
5941
|
-
installUrl = `${installUrl}/tree/
|
|
5942
|
-
} else installUrl =
|
|
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,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ali-skills",
|
|
3
|
-
"version": "0.0.
|
|
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.
|
|
34
|
+
"@ali/cli-skills": "^2.0.16"
|
|
35
35
|
},
|
|
36
36
|
"bundleDependencies": [
|
|
37
37
|
"@ali/cli-skills"
|