bfi-cli 0.1.29 → 0.1.36
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.
- package/dist/_chunks/agents.mjs +733 -57
- package/dist/_chunks/agents2.mjs +66 -0
- package/dist/_chunks/libs/@clack/prompts.mjs +44 -1
- package/dist/_chunks/skills.mjs +445 -0
- package/dist/cli.mjs +612 -1631
- package/package.json +1 -1
- package/skills/skillhub-skills/SKILL.md +187 -0
- package/skills/bfi-skill/SKILL.md +0 -176
package/dist/cli.mjs
CHANGED
|
@@ -3,8 +3,9 @@ import { __exportAll, __toESM } from "./_chunks/rolldown-runtime.mjs";
|
|
|
3
3
|
import { isCancel } from "./_chunks/libs/@clack/core.mjs";
|
|
4
4
|
import { cancel, confirm, groupMultiselect, intro, log, multiselect as multiselect$1, note, outro, select, spinner } from "./_chunks/libs/@clack/prompts.mjs";
|
|
5
5
|
import { require_picocolors } from "./_chunks/libs/picocolors.mjs";
|
|
6
|
+
import { addSkillToLocalLock, addSkillToLock, computeSkillFolderHash, discoverSkills, dismissPrompt, filterSkills, getAllLockedSkills, getGitHubToken, getLastSelectedAgents, getSkillDisplayName, getSkillFromLock, isPromptDismissed, parseFrontmatter, parseSkillMd, readLocalLock, readSkillLock, removeSkillFromLock, sanitizeMetadata, saveSelectedAgents, stripTerminalEscapes } from "./_chunks/skills.mjs";
|
|
6
7
|
import { esm_default } from "./_chunks/libs/simple-git.mjs";
|
|
7
|
-
import {
|
|
8
|
+
import { EVE_SUBAGENTS_DIR, agents, detectInstalledAgents, getEveSubagents, getNonUniversalAgents, getUniversalAgents, getVisibleUniversalAgents, isUniversalAgent } from "./_chunks/agents.mjs";
|
|
8
9
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "fs";
|
|
9
10
|
import { basename, dirname, extname, isAbsolute, join, normalize, relative, resolve, sep } from "path";
|
|
10
11
|
import { fileURLToPath } from "url";
|
|
@@ -20,10 +21,8 @@ import http from "node:http";
|
|
|
20
21
|
import os$1 from "node:os";
|
|
21
22
|
import zlib, { gunzipSync, inflateRawSync } from "node:zlib";
|
|
22
23
|
import { promisify } from "util";
|
|
23
|
-
import { execFile,
|
|
24
|
+
import { execFile, spawn, spawnSync } from "child_process";
|
|
24
25
|
import { access, chmod, cp, lstat, mkdir, mkdtemp, readFile, readdir, readlink, realpath, rm, stat, symlink, writeFile } from "fs/promises";
|
|
25
|
-
import { parse } from "yaml";
|
|
26
|
-
import { createHash as createHash$1 } from "crypto";
|
|
27
26
|
import { determineAgent } from "@vercel/detect-agent";
|
|
28
27
|
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
29
28
|
const GIT_HOST = process.env.BFI_GIT_HOST || "git.yyrd.com";
|
|
@@ -283,18 +282,6 @@ function isWellKnownUrl(input) {
|
|
|
283
282
|
return false;
|
|
284
283
|
}
|
|
285
284
|
}
|
|
286
|
-
const CSI_RE = /\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]/g;
|
|
287
|
-
const OSC_RE = /\x1b\][\s\S]*?(?:\x07|\x1b\\)/g;
|
|
288
|
-
const DCS_PM_APC_RE = /\x1b[P^_][\s\S]*?(?:\x1b\\)/g;
|
|
289
|
-
const SIMPLE_ESC_RE = /\x1b[\x20-\x7e]/g;
|
|
290
|
-
const C1_RE = /[\x80-\x9f]/g;
|
|
291
|
-
const CONTROL_RE = /[\x00-\x06\x07\x08\x0b\x0c\x0d-\x1a\x1c-\x1f\x7f]/g;
|
|
292
|
-
function stripTerminalEscapes(str) {
|
|
293
|
-
return str.replace(OSC_RE, "").replace(DCS_PM_APC_RE, "").replace(CSI_RE, "").replace(SIMPLE_ESC_RE, "").replace(C1_RE, "").replace(CONTROL_RE, "");
|
|
294
|
-
}
|
|
295
|
-
function sanitizeMetadata(str) {
|
|
296
|
-
return stripTerminalEscapes(str).replace(/[\r\n]+/g, " ").trim();
|
|
297
|
-
}
|
|
298
285
|
const silentOutput = new Writable({ write(_chunk, _encoding, callback) {
|
|
299
286
|
callback();
|
|
300
287
|
} });
|
|
@@ -513,7 +500,9 @@ var SkillHubAPI = class {
|
|
|
513
500
|
};
|
|
514
501
|
if (url.protocol === "https:") requestOptions.rejectUnauthorized = this.rejectUnauthorized;
|
|
515
502
|
let bodyStr;
|
|
516
|
-
|
|
503
|
+
let bodyBuf;
|
|
504
|
+
if (options.body !== void 0) if (options.body instanceof Buffer) bodyBuf = options.body;
|
|
505
|
+
else if (options.body instanceof FormData || typeof options.body === "string") bodyStr = options.body;
|
|
517
506
|
else {
|
|
518
507
|
requestOptions.headers["Content-Type"] = "application/json";
|
|
519
508
|
bodyStr = JSON.stringify(options.body);
|
|
@@ -552,7 +541,8 @@ var SkillHubAPI = class {
|
|
|
552
541
|
});
|
|
553
542
|
});
|
|
554
543
|
req.on("error", reject);
|
|
555
|
-
if (
|
|
544
|
+
if (bodyBuf) req.write(bodyBuf);
|
|
545
|
+
else if (bodyStr) req.write(bodyStr);
|
|
556
546
|
req.end();
|
|
557
547
|
});
|
|
558
548
|
}
|
|
@@ -657,12 +647,13 @@ var SkillHubAPI = class {
|
|
|
657
647
|
return (await this.request("DELETE", `/namespaces/${namespace}/packages/${slug}/skills`, { body: { skills } })).body;
|
|
658
648
|
}
|
|
659
649
|
async gitParse(repositoryUrl, branch, directory) {
|
|
660
|
-
|
|
650
|
+
const body = {
|
|
661
651
|
repositoryUrl,
|
|
662
652
|
branch,
|
|
663
|
-
directory,
|
|
664
653
|
token: this.token
|
|
665
|
-
}
|
|
654
|
+
};
|
|
655
|
+
if (directory) body.directory = directory;
|
|
656
|
+
return (await this.request("POST", "/skills/git/parse", { body })).body;
|
|
666
657
|
}
|
|
667
658
|
async gitPublish(sessionId, namespace, visibility, selectedSkills, confirmWarnings) {
|
|
668
659
|
return (await this.request("POST", "/skills/git/publish", { body: {
|
|
@@ -739,51 +730,36 @@ var SkillHubAPI = class {
|
|
|
739
730
|
contentSummary
|
|
740
731
|
} })).body;
|
|
741
732
|
}
|
|
742
|
-
async publishSkill(namespace, zipBuffer, visibility = "
|
|
743
|
-
const url = new URL(this.buildUrl("/skills/publish"));
|
|
744
|
-
const isHttps = url.protocol === "https:";
|
|
745
|
-
const client = isHttps ? https : http;
|
|
746
|
-
const boundary = `----FormBoundary${Date.now()}${Math.random().toString(36).slice(2)}`;
|
|
747
|
-
const header = [
|
|
748
|
-
`--${boundary}`,
|
|
749
|
-
"Content-Disposition: form-data; name=\"file\"; filename=\"skill.zip\"",
|
|
750
|
-
"Content-Type: application/zip",
|
|
751
|
-
"",
|
|
752
|
-
""
|
|
753
|
-
].join("\r\n");
|
|
754
|
-
const footer = `\r\n--${boundary}--\r\n`;
|
|
755
|
-
const body = Buffer.concat([
|
|
756
|
-
Buffer.from(header, "utf8"),
|
|
757
|
-
zipBuffer,
|
|
758
|
-
Buffer.from(footer, "utf8")
|
|
759
|
-
]);
|
|
760
|
-
const requestOptions = {
|
|
761
|
-
method: "POST",
|
|
762
|
-
headers: {
|
|
763
|
-
...this.getHeaders(),
|
|
764
|
-
"Content-Type": `multipart/form-data; boundary=${boundary}`,
|
|
765
|
-
"Content-Length": String(body.length)
|
|
766
|
-
}
|
|
767
|
-
};
|
|
768
|
-
if (isHttps) requestOptions.rejectUnauthorized = this.rejectUnauthorized;
|
|
769
|
-
url.searchParams.set("namespace", namespace);
|
|
770
|
-
url.searchParams.set("visibility", visibility);
|
|
733
|
+
async publishSkill(namespace, zipBuffer, visibility = "public", confirmWarnings = false) {
|
|
771
734
|
return new Promise((resolve, reject) => {
|
|
772
|
-
const
|
|
735
|
+
const crlf = "\r\n";
|
|
736
|
+
const boundary = `----FormBoundary${Date.now()}${Math.random().toString(36).slice(2)}`;
|
|
737
|
+
const header = Buffer.from(`--${boundary}${crlf}Content-Disposition: form-data; name="file"; filename="skill.zip"${crlf}Content-Type: application/zip${crlf}${crlf}`, "utf8");
|
|
738
|
+
const footer = Buffer.from(`${crlf}--${boundary}--${crlf}`, "utf8");
|
|
739
|
+
const body = Buffer.concat([
|
|
740
|
+
header,
|
|
741
|
+
zipBuffer,
|
|
742
|
+
footer
|
|
743
|
+
]);
|
|
744
|
+
const cfm = confirmWarnings ? "true" : "false";
|
|
745
|
+
const url = new URL(this.buildUrl(`/skills/${namespace}/publish?visibility=${visibility}&confirmWarnings=${cfm}`));
|
|
746
|
+
const h = this.getHeaders();
|
|
747
|
+
h["Content-Type"] = `multipart/form-data; boundary=${boundary}`;
|
|
748
|
+
h["Content-Length"] = String(body.length);
|
|
749
|
+
const req = https.request(url, {
|
|
750
|
+
method: "POST",
|
|
751
|
+
headers: h,
|
|
752
|
+
rejectUnauthorized: this.rejectUnauthorized
|
|
753
|
+
}, (res) => {
|
|
773
754
|
let data = "";
|
|
774
755
|
res.on("data", (chunk) => data += chunk.toString());
|
|
775
756
|
res.on("end", () => {
|
|
776
757
|
try {
|
|
777
758
|
const parsed = JSON.parse(data);
|
|
778
759
|
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) resolve(parsed);
|
|
779
|
-
else {
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
error.body = parsed;
|
|
783
|
-
reject(error);
|
|
784
|
-
}
|
|
785
|
-
} catch (err) {
|
|
786
|
-
reject(err);
|
|
760
|
+
else reject(new Error(parsed.msg || parsed.message || `HTTP ${res.statusCode}`));
|
|
761
|
+
} catch {
|
|
762
|
+
reject(new Error(data || `HTTP ${res.statusCode}`));
|
|
787
763
|
}
|
|
788
764
|
});
|
|
789
765
|
});
|
|
@@ -804,13 +780,15 @@ var config_exports = /* @__PURE__ */ __exportAll({
|
|
|
804
780
|
loadProjectConfig: () => loadProjectConfig,
|
|
805
781
|
resolveConfig: () => resolveConfig,
|
|
806
782
|
saveGlobalConfig: () => saveGlobalConfig,
|
|
783
|
+
saveLockfile: () => saveLockfile,
|
|
807
784
|
saveProjectConfig: () => saveProjectConfig,
|
|
808
785
|
setConfigValue: () => setConfigValue
|
|
809
786
|
});
|
|
810
787
|
const GLOBAL_CONFIG_DIR = path$1.join(os$1.homedir(), ".bfi");
|
|
811
788
|
const GLOBAL_CONFIG_FILE = path$1.join(GLOBAL_CONFIG_DIR, "config.json");
|
|
812
789
|
const PROJECT_CONFIG_FILE = ".bfirc";
|
|
813
|
-
const
|
|
790
|
+
const LOCK_FILE_DIR = ".bfi";
|
|
791
|
+
const LOCK_FILE = path$1.join(LOCK_FILE_DIR, "lock.json");
|
|
814
792
|
function resolveConfig(globalOpts = {}) {
|
|
815
793
|
return {
|
|
816
794
|
registry: getConfigValue("registry", globalOpts) || "https://bfi.yyuap.com:811",
|
|
@@ -881,6 +859,18 @@ function loadLockfile(workdir) {
|
|
|
881
859
|
packages: {}
|
|
882
860
|
};
|
|
883
861
|
}
|
|
862
|
+
function saveLockfile(workdir, lock) {
|
|
863
|
+
try {
|
|
864
|
+
const lockDir = path$1.join(workdir, LOCK_FILE_DIR);
|
|
865
|
+
if (!fs.existsSync(lockDir)) fs.mkdirSync(lockDir, { recursive: true });
|
|
866
|
+
const lockPath = path$1.join(workdir, LOCK_FILE);
|
|
867
|
+
const content = JSON.stringify(lock, null, 2);
|
|
868
|
+
fs.writeFileSync(lockPath, content);
|
|
869
|
+
return true;
|
|
870
|
+
} catch (error) {
|
|
871
|
+
throw new Error(`Failed to save lockfile: ${error.message}`);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
884
874
|
function getConfigValue(key, globalOpts = {}) {
|
|
885
875
|
const projectConfig = loadProjectConfig(globalOpts.workdir || process.cwd());
|
|
886
876
|
const globalConfig = loadGlobalConfig();
|
|
@@ -947,6 +937,11 @@ function toCanonicalSlug(namespace, slug) {
|
|
|
947
937
|
function toSkillRefString(namespace, slug) {
|
|
948
938
|
return `@${namespace}/${slug}`;
|
|
949
939
|
}
|
|
940
|
+
var zip_exports = /* @__PURE__ */ __exportAll({
|
|
941
|
+
createZipFromDir: () => createZipFromDir,
|
|
942
|
+
extractZip: () => extractZip,
|
|
943
|
+
extractZipBuffer: () => extractZipBuffer
|
|
944
|
+
});
|
|
950
945
|
async function extractZip(zipPath, targetDir) {
|
|
951
946
|
return new Promise((resolve, reject) => {
|
|
952
947
|
const chunks = [];
|
|
@@ -1011,13 +1006,13 @@ function extractZipBuffer(buffer, targetDir) {
|
|
|
1011
1006
|
} else throw new Error(`Unsupported compression method: ${entry.compressionMethod}`);
|
|
1012
1007
|
}
|
|
1013
1008
|
}
|
|
1014
|
-
function collectFiles
|
|
1009
|
+
function collectFiles(dir, baseDir) {
|
|
1015
1010
|
const result = [];
|
|
1016
1011
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1017
1012
|
for (const entry of entries) {
|
|
1018
1013
|
const fullPath = path$1.join(dir, entry.name);
|
|
1019
1014
|
const relativePath = path$1.relative(baseDir, fullPath);
|
|
1020
|
-
if (entry.isDirectory()) result.push(...collectFiles
|
|
1015
|
+
if (entry.isDirectory()) result.push(...collectFiles(fullPath, baseDir));
|
|
1021
1016
|
else if (entry.isFile()) result.push({
|
|
1022
1017
|
relativePath,
|
|
1023
1018
|
buffer: fs.readFileSync(fullPath)
|
|
@@ -1026,7 +1021,7 @@ function collectFiles$1(dir, baseDir) {
|
|
|
1026
1021
|
return result;
|
|
1027
1022
|
}
|
|
1028
1023
|
function createZipFromDir(sourceDir) {
|
|
1029
|
-
const normalizedFiles = collectFiles
|
|
1024
|
+
const normalizedFiles = collectFiles(sourceDir, sourceDir).map((f) => ({
|
|
1030
1025
|
...f,
|
|
1031
1026
|
relativePath: f.relativePath.replace(/\\/g, "/")
|
|
1032
1027
|
}));
|
|
@@ -1103,6 +1098,14 @@ function crc32(data) {
|
|
|
1103
1098
|
}
|
|
1104
1099
|
return (crc ^ 4294967295) >>> 0;
|
|
1105
1100
|
}
|
|
1101
|
+
var git_exports = /* @__PURE__ */ __exportAll({
|
|
1102
|
+
GitCloneError: () => GitCloneError,
|
|
1103
|
+
cleanupTempDir: () => cleanupTempDir,
|
|
1104
|
+
cloneRepo: () => cloneRepo,
|
|
1105
|
+
isGitHubHttpsCloneUrl: () => isGitHubHttpsCloneUrl,
|
|
1106
|
+
isGitHubSsoAuthError: () => isGitHubSsoAuthError,
|
|
1107
|
+
parseGitHubRepoUrl: () => parseGitHubRepoUrl
|
|
1108
|
+
});
|
|
1106
1109
|
const DEFAULT_CLONE_TIMEOUT_MS = 3e5;
|
|
1107
1110
|
const CLONE_TIMEOUT_MS = (() => {
|
|
1108
1111
|
const raw = process.env.SKILLS_CLONE_TIMEOUT_MS;
|
|
@@ -1204,1240 +1207,90 @@ async function tryGhClone(repo, tempDir, ref) {
|
|
|
1204
1207
|
timeout: 5e3,
|
|
1205
1208
|
env: {
|
|
1206
1209
|
...process.env,
|
|
1207
|
-
GIT_TERMINAL_PROMPT: "0"
|
|
1208
|
-
}
|
|
1209
|
-
});
|
|
1210
|
-
const statusOutput = `${stdout}${stderr}`;
|
|
1211
|
-
if (/Git operations protocol:\s+ssh/i.test(statusOutput)) cloneTarget = repo.sshUrl;
|
|
1212
|
-
} catch {
|
|
1213
|
-
return false;
|
|
1214
|
-
}
|
|
1215
|
-
await execFileAsync("gh", [
|
|
1216
|
-
"repo",
|
|
1217
|
-
"clone",
|
|
1218
|
-
cloneTarget,
|
|
1219
|
-
tempDir,
|
|
1220
|
-
"--",
|
|
1221
|
-
...ref ? [
|
|
1222
|
-
"--depth=1",
|
|
1223
|
-
"--branch",
|
|
1224
|
-
ref
|
|
1225
|
-
] : ["--depth=1"]
|
|
1226
|
-
], {
|
|
1227
|
-
timeout: CLONE_TIMEOUT_MS,
|
|
1228
|
-
env: {
|
|
1229
|
-
...process.env,
|
|
1230
|
-
GIT_TERMINAL_PROMPT: "0"
|
|
1231
|
-
}
|
|
1232
|
-
});
|
|
1233
|
-
return true;
|
|
1234
|
-
}
|
|
1235
|
-
function buildGitHubAuthError(url, repo, message) {
|
|
1236
|
-
if (repo && isGitHubSsoAuthError(message)) return `GitHub 阻止了 ${url} 的 HTTPS 访问,因为组织强制使用 SAML SSO。\n skills 已尝试您现有的 git 凭据和可用回退方案,但均未成功。\n - 重新授权您的 GitHub 凭据/应用以符合该组织的 SSO 策略\n - 或使用 SSH 重新运行:npx skills add ${repo.sshUrl}\n - 验证访问权限:gh auth status -h github.com 或 ssh -T git@github.com`;
|
|
1237
|
-
if (repo) return `身份验证失败:${url}。\n - 私有仓库请确保您有访问权限\n - 使用 SSH 重试:npx skills add ${repo.sshUrl}\n - 检查访问权限:gh auth status -h github.com 或 ssh -T git@github.com`;
|
|
1238
|
-
return `身份验证失败:${url}。\n - 私有仓库请确保您有访问权限\n - SSH:使用 'ssh -T git@github.com' 检查您的密钥\n - HTTPS:运行 'gh auth login' 或配置 git 凭据`;
|
|
1239
|
-
}
|
|
1240
|
-
async function cloneRepo(url, ref) {
|
|
1241
|
-
if (/^ext::/i.test(url)) throw new GitCloneError("不支持的 Git 传输协议:ext", url);
|
|
1242
|
-
const tempDir = await mkdtemp(join(tmpdir(), "skills-"));
|
|
1243
|
-
const cloneOptions = ref ? [
|
|
1244
|
-
"--depth",
|
|
1245
|
-
"1",
|
|
1246
|
-
"--branch",
|
|
1247
|
-
ref
|
|
1248
|
-
] : ["--depth", "1"];
|
|
1249
|
-
const repo = parseGitHubRepoUrl(url);
|
|
1250
|
-
try {
|
|
1251
|
-
await createGitClient().clone(url, tempDir, cloneOptions);
|
|
1252
|
-
return tempDir;
|
|
1253
|
-
} catch (error) {
|
|
1254
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1255
|
-
const isTimeout = errorMessage.includes("block timeout") || errorMessage.includes("timed out");
|
|
1256
|
-
const isAuthError = isAuthFailure(errorMessage);
|
|
1257
|
-
if (isTimeout) {
|
|
1258
|
-
await rm(tempDir, {
|
|
1259
|
-
recursive: true,
|
|
1260
|
-
force: true
|
|
1261
|
-
}).catch(() => {});
|
|
1262
|
-
throw new GitCloneError(`克隆超时(${Math.round(CLONE_TIMEOUT_MS / 1e3)} 秒)。常见原因:\n - 仓库过大:使用 SKILLS_CLONE_TIMEOUT_MS=600000 (10 分钟) 提高超时时间\n - 网络较慢:重试,或手动克隆后将本地路径传给 'skills add'\n - 私有仓库未配置凭据:请确保身份验证已配置\n - SSH:ssh-add -l(检查已加载的密钥)\n - HTTPS:gh auth status(如果使用 GitHub CLI)`, url, true, false);
|
|
1263
|
-
}
|
|
1264
|
-
if (isAuthError && repo && isGitHubHttpsCloneUrl(url)) {
|
|
1265
|
-
try {
|
|
1266
|
-
await resetTempDir(tempDir);
|
|
1267
|
-
if (await tryGhClone(repo, tempDir, ref)) return tempDir;
|
|
1268
|
-
} catch {}
|
|
1269
|
-
try {
|
|
1270
|
-
await resetTempDir(tempDir);
|
|
1271
|
-
await createGitClient({ GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND ?? "ssh -o BatchMode=yes" }).clone(repo.sshUrl, tempDir, cloneOptions);
|
|
1272
|
-
return tempDir;
|
|
1273
|
-
} catch {}
|
|
1274
|
-
}
|
|
1275
|
-
await rm(tempDir, {
|
|
1276
|
-
recursive: true,
|
|
1277
|
-
force: true
|
|
1278
|
-
}).catch(() => {});
|
|
1279
|
-
if (isAuthError) throw new GitCloneError(buildGitHubAuthError(url, repo, errorMessage), url, false, true);
|
|
1280
|
-
throw new GitCloneError(`克隆失败 ${url}:${errorMessage}`, url, false, false);
|
|
1281
|
-
}
|
|
1282
|
-
}
|
|
1283
|
-
async function cleanupTempDir(dir) {
|
|
1284
|
-
const normalizedDir = normalize(resolve(dir));
|
|
1285
|
-
const normalizedTmpDir = normalize(resolve(tmpdir()));
|
|
1286
|
-
if (!normalizedDir.startsWith(normalizedTmpDir + sep) && normalizedDir !== normalizedTmpDir) throw new Error("Attempted to clean up directory outside of temp directory");
|
|
1287
|
-
await rm(dir, {
|
|
1288
|
-
recursive: true,
|
|
1289
|
-
force: true
|
|
1290
|
-
});
|
|
1291
|
-
}
|
|
1292
|
-
function parseFrontmatter(raw) {
|
|
1293
|
-
const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
|
|
1294
|
-
if (!match) return {
|
|
1295
|
-
data: {},
|
|
1296
|
-
content: raw
|
|
1297
|
-
};
|
|
1298
|
-
return {
|
|
1299
|
-
data: parse(match[1]) ?? {},
|
|
1300
|
-
content: match[2] ?? ""
|
|
1301
|
-
};
|
|
1302
|
-
}
|
|
1303
|
-
function isContainedIn(targetPath, basePath) {
|
|
1304
|
-
const normalizedBase = normalize(resolve(basePath));
|
|
1305
|
-
const normalizedTarget = normalize(resolve(targetPath));
|
|
1306
|
-
return normalizedTarget.startsWith(normalizedBase + sep) || normalizedTarget === normalizedBase;
|
|
1307
|
-
}
|
|
1308
|
-
function isValidRelativePath(path) {
|
|
1309
|
-
return path.startsWith("./");
|
|
1310
|
-
}
|
|
1311
|
-
async function getPluginSkillPaths(basePath) {
|
|
1312
|
-
const searchDirs = [];
|
|
1313
|
-
const addPluginSkillPaths = (pluginBase, skills) => {
|
|
1314
|
-
if (!isContainedIn(pluginBase, basePath)) return;
|
|
1315
|
-
if (skills && skills.length > 0) for (const skillPath of skills) {
|
|
1316
|
-
if (!isValidRelativePath(skillPath)) continue;
|
|
1317
|
-
const skillDir = dirname(join(pluginBase, skillPath));
|
|
1318
|
-
if (isContainedIn(skillDir, basePath)) searchDirs.push(skillDir);
|
|
1319
|
-
}
|
|
1320
|
-
searchDirs.push(join(pluginBase, "skills"));
|
|
1321
|
-
};
|
|
1322
|
-
try {
|
|
1323
|
-
const content = await readFile(join(basePath, ".claude-plugin/marketplace.json"), "utf-8");
|
|
1324
|
-
const manifest = JSON.parse(content);
|
|
1325
|
-
const pluginRoot = manifest.metadata?.pluginRoot;
|
|
1326
|
-
if (pluginRoot === void 0 || isValidRelativePath(pluginRoot)) for (const plugin of manifest.plugins ?? []) {
|
|
1327
|
-
if (typeof plugin.source !== "string" && plugin.source !== void 0) continue;
|
|
1328
|
-
if (plugin.source !== void 0 && !isValidRelativePath(plugin.source)) continue;
|
|
1329
|
-
addPluginSkillPaths(join(basePath, pluginRoot ?? "", plugin.source ?? ""), plugin.skills);
|
|
1330
|
-
}
|
|
1331
|
-
} catch {}
|
|
1332
|
-
try {
|
|
1333
|
-
const content = await readFile(join(basePath, ".claude-plugin/plugin.json"), "utf-8");
|
|
1334
|
-
addPluginSkillPaths(basePath, JSON.parse(content).skills);
|
|
1335
|
-
} catch {}
|
|
1336
|
-
return searchDirs;
|
|
1337
|
-
}
|
|
1338
|
-
async function getPluginGroupings(basePath) {
|
|
1339
|
-
const groupings = /* @__PURE__ */ new Map();
|
|
1340
|
-
try {
|
|
1341
|
-
const content = await readFile(join(basePath, ".claude-plugin/marketplace.json"), "utf-8");
|
|
1342
|
-
const manifest = JSON.parse(content);
|
|
1343
|
-
const pluginRoot = manifest.metadata?.pluginRoot;
|
|
1344
|
-
if (pluginRoot === void 0 || isValidRelativePath(pluginRoot)) for (const plugin of manifest.plugins ?? []) {
|
|
1345
|
-
if (!plugin.name) continue;
|
|
1346
|
-
if (typeof plugin.source !== "string" && plugin.source !== void 0) continue;
|
|
1347
|
-
if (plugin.source !== void 0 && !isValidRelativePath(plugin.source)) continue;
|
|
1348
|
-
const pluginBase = join(basePath, pluginRoot ?? "", plugin.source ?? "");
|
|
1349
|
-
if (!isContainedIn(pluginBase, basePath)) continue;
|
|
1350
|
-
if (plugin.skills && plugin.skills.length > 0) for (const skillPath of plugin.skills) {
|
|
1351
|
-
if (!isValidRelativePath(skillPath)) continue;
|
|
1352
|
-
const skillDir = join(pluginBase, skillPath);
|
|
1353
|
-
if (isContainedIn(skillDir, basePath)) groupings.set(resolve(skillDir), plugin.name);
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
} catch {}
|
|
1357
|
-
try {
|
|
1358
|
-
const content = await readFile(join(basePath, ".claude-plugin/plugin.json"), "utf-8");
|
|
1359
|
-
const manifest = JSON.parse(content);
|
|
1360
|
-
if (manifest.name && manifest.skills && manifest.skills.length > 0) for (const skillPath of manifest.skills) {
|
|
1361
|
-
if (!isValidRelativePath(skillPath)) continue;
|
|
1362
|
-
const skillDir = join(basePath, skillPath);
|
|
1363
|
-
if (isContainedIn(skillDir, basePath)) groupings.set(resolve(skillDir), manifest.name);
|
|
1364
|
-
}
|
|
1365
|
-
} catch {}
|
|
1366
|
-
return groupings;
|
|
1367
|
-
}
|
|
1368
|
-
const AGENTS_DIR$1 = ".agents";
|
|
1369
|
-
const SKILL_LOCK_FILE = ".skill-lock.json";
|
|
1370
|
-
const SKILL_LOCK_CURRENT_VERSION = 3;
|
|
1371
|
-
const LOCAL_LOCK_FILE = "skills-lock.json";
|
|
1372
|
-
const LOCAL_LOCK_CURRENT_VERSION = 1;
|
|
1373
|
-
function getSkillLockPath() {
|
|
1374
|
-
const xdgStateHome = process.env.XDG_STATE_HOME;
|
|
1375
|
-
if (xdgStateHome) return join(xdgStateHome, "skills", SKILL_LOCK_FILE);
|
|
1376
|
-
return join(homedir(), AGENTS_DIR$1, SKILL_LOCK_FILE);
|
|
1377
|
-
}
|
|
1378
|
-
function createEmptySkillLockFile() {
|
|
1379
|
-
return {
|
|
1380
|
-
version: SKILL_LOCK_CURRENT_VERSION,
|
|
1381
|
-
skills: {},
|
|
1382
|
-
dismissed: {}
|
|
1383
|
-
};
|
|
1384
|
-
}
|
|
1385
|
-
async function readSkillLock() {
|
|
1386
|
-
const lockPath = getSkillLockPath();
|
|
1387
|
-
try {
|
|
1388
|
-
const content = await readFile(lockPath, "utf-8");
|
|
1389
|
-
const parsed = JSON.parse(content);
|
|
1390
|
-
if (typeof parsed.version !== "number" || !parsed.skills) return createEmptySkillLockFile();
|
|
1391
|
-
if (parsed.version < SKILL_LOCK_CURRENT_VERSION) return createEmptySkillLockFile();
|
|
1392
|
-
return parsed;
|
|
1393
|
-
} catch {
|
|
1394
|
-
return createEmptySkillLockFile();
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1397
|
-
async function writeSkillLock(lock) {
|
|
1398
|
-
const lockPath = getSkillLockPath();
|
|
1399
|
-
await mkdir(dirname(lockPath), { recursive: true });
|
|
1400
|
-
await writeFile(lockPath, JSON.stringify(lock, null, 2), "utf-8");
|
|
1401
|
-
}
|
|
1402
|
-
let _ghWarningShown = false;
|
|
1403
|
-
function getGitHubToken() {
|
|
1404
|
-
if (process.env.GITHUB_TOKEN) return process.env.GITHUB_TOKEN;
|
|
1405
|
-
if (process.env.GH_TOKEN) return process.env.GH_TOKEN;
|
|
1406
|
-
if (!_ghWarningShown) {
|
|
1407
|
-
process.stderr.write(`${import_picocolors.default.yellow("│")} ${import_picocolors.default.yellow("GitHub rate limit reached")} — using your ${import_picocolors.default.cyan("gh")} login to continue.\n${import_picocolors.default.yellow("│")} ${import_picocolors.default.dim(`Tip: set ${import_picocolors.default.cyan("GITHUB_TOKEN")} to avoid this prompt, or use ${import_picocolors.default.cyan("--full-depth")} to clone instead.\n`)}`);
|
|
1408
|
-
_ghWarningShown = true;
|
|
1409
|
-
}
|
|
1410
|
-
try {
|
|
1411
|
-
const token = execSync("gh auth token", {
|
|
1412
|
-
encoding: "utf-8",
|
|
1413
|
-
stdio: [
|
|
1414
|
-
"pipe",
|
|
1415
|
-
"pipe",
|
|
1416
|
-
"pipe"
|
|
1417
|
-
]
|
|
1418
|
-
}).trim();
|
|
1419
|
-
if (token) return token;
|
|
1420
|
-
} catch {}
|
|
1421
|
-
return null;
|
|
1422
|
-
}
|
|
1423
|
-
async function addSkillToLock(skillName, entry) {
|
|
1424
|
-
const lock = await readSkillLock();
|
|
1425
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1426
|
-
const existingEntry = lock.skills[skillName];
|
|
1427
|
-
lock.skills[skillName] = {
|
|
1428
|
-
...entry,
|
|
1429
|
-
installedAt: existingEntry?.installedAt ?? now,
|
|
1430
|
-
updatedAt: now
|
|
1431
|
-
};
|
|
1432
|
-
await writeSkillLock(lock);
|
|
1433
|
-
}
|
|
1434
|
-
async function removeSkillFromLock(skillName) {
|
|
1435
|
-
const lock = await readSkillLock();
|
|
1436
|
-
if (!(skillName in lock.skills)) return false;
|
|
1437
|
-
delete lock.skills[skillName];
|
|
1438
|
-
await writeSkillLock(lock);
|
|
1439
|
-
return true;
|
|
1440
|
-
}
|
|
1441
|
-
async function getSkillFromLock(skillName) {
|
|
1442
|
-
return (await readSkillLock()).skills[skillName] ?? null;
|
|
1443
|
-
}
|
|
1444
|
-
async function getAllLockedSkills() {
|
|
1445
|
-
return (await readSkillLock()).skills;
|
|
1446
|
-
}
|
|
1447
|
-
async function isPromptDismissed(promptKey) {
|
|
1448
|
-
return (await readSkillLock()).dismissed?.[promptKey] === true;
|
|
1449
|
-
}
|
|
1450
|
-
async function dismissPrompt(promptKey) {
|
|
1451
|
-
const lock = await readSkillLock();
|
|
1452
|
-
if (!lock.dismissed) lock.dismissed = {};
|
|
1453
|
-
lock.dismissed[promptKey] = true;
|
|
1454
|
-
await writeSkillLock(lock);
|
|
1455
|
-
}
|
|
1456
|
-
async function getLastSelectedAgents() {
|
|
1457
|
-
return (await readSkillLock()).lastSelectedAgents;
|
|
1458
|
-
}
|
|
1459
|
-
async function saveSelectedAgents(agents) {
|
|
1460
|
-
const lock = await readSkillLock();
|
|
1461
|
-
lock.lastSelectedAgents = agents;
|
|
1462
|
-
await writeSkillLock(lock);
|
|
1463
|
-
}
|
|
1464
|
-
function getLocalLockPath(cwd) {
|
|
1465
|
-
return join(cwd || process.cwd(), LOCAL_LOCK_FILE);
|
|
1466
|
-
}
|
|
1467
|
-
function createEmptyLocalLock() {
|
|
1468
|
-
return {
|
|
1469
|
-
version: LOCAL_LOCK_CURRENT_VERSION,
|
|
1470
|
-
skills: {}
|
|
1471
|
-
};
|
|
1472
|
-
}
|
|
1473
|
-
async function readLocalLock(cwd) {
|
|
1474
|
-
const lockPath = getLocalLockPath(cwd);
|
|
1475
|
-
try {
|
|
1476
|
-
const content = await readFile(lockPath, "utf-8");
|
|
1477
|
-
const parsed = JSON.parse(content);
|
|
1478
|
-
if (typeof parsed.version !== "number" || !parsed.skills) return createEmptyLocalLock();
|
|
1479
|
-
if (parsed.version < LOCAL_LOCK_CURRENT_VERSION) return createEmptyLocalLock();
|
|
1480
|
-
return parsed;
|
|
1481
|
-
} catch {
|
|
1482
|
-
return createEmptyLocalLock();
|
|
1483
|
-
}
|
|
1484
|
-
}
|
|
1485
|
-
async function writeLocalLock(lock, cwd) {
|
|
1486
|
-
const lockPath = getLocalLockPath(cwd);
|
|
1487
|
-
const sortedSkills = {};
|
|
1488
|
-
for (const key of Object.keys(lock.skills).sort()) sortedSkills[key] = lock.skills[key];
|
|
1489
|
-
const sorted = {
|
|
1490
|
-
version: lock.version,
|
|
1491
|
-
skills: sortedSkills
|
|
1492
|
-
};
|
|
1493
|
-
await writeFile(lockPath, JSON.stringify(sorted, null, 2) + "\n", "utf-8");
|
|
1494
|
-
}
|
|
1495
|
-
async function computeSkillFolderHash(skillDir) {
|
|
1496
|
-
const files = [];
|
|
1497
|
-
await collectFiles(skillDir, skillDir, files);
|
|
1498
|
-
files.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
1499
|
-
const hash = createHash$1("sha256");
|
|
1500
|
-
for (const file of files) {
|
|
1501
|
-
hash.update(file.relativePath);
|
|
1502
|
-
hash.update(file.content);
|
|
1503
|
-
}
|
|
1504
|
-
return hash.digest("hex");
|
|
1505
|
-
}
|
|
1506
|
-
async function collectFiles(baseDir, currentDir, results) {
|
|
1507
|
-
const entries = await readdir(currentDir, { withFileTypes: true });
|
|
1508
|
-
await Promise.all(entries.map(async (entry) => {
|
|
1509
|
-
const fullPath = join(currentDir, entry.name);
|
|
1510
|
-
if (entry.isDirectory()) {
|
|
1511
|
-
if (entry.name === ".git" || entry.name === "node_modules") return;
|
|
1512
|
-
await collectFiles(baseDir, fullPath, results);
|
|
1513
|
-
} else if (entry.isFile()) {
|
|
1514
|
-
const content = await readFile(fullPath);
|
|
1515
|
-
const relativePath = relative(baseDir, fullPath).split("\\").join("/");
|
|
1516
|
-
results.push({
|
|
1517
|
-
relativePath,
|
|
1518
|
-
content
|
|
1519
|
-
});
|
|
1520
|
-
}
|
|
1521
|
-
}));
|
|
1522
|
-
}
|
|
1523
|
-
async function addSkillToLocalLock(skillName, entry, cwd) {
|
|
1524
|
-
const lock = await readLocalLock(cwd);
|
|
1525
|
-
lock.skills[skillName] = entry;
|
|
1526
|
-
await writeLocalLock(lock, cwd);
|
|
1527
|
-
}
|
|
1528
|
-
const SKIP_DIRS = [
|
|
1529
|
-
"node_modules",
|
|
1530
|
-
".git",
|
|
1531
|
-
"dist",
|
|
1532
|
-
"build",
|
|
1533
|
-
"__pycache__"
|
|
1534
|
-
];
|
|
1535
|
-
const AGENT_PROJECT_SKILL_DIRS = [
|
|
1536
|
-
".agents/skills",
|
|
1537
|
-
".claude/skills",
|
|
1538
|
-
".cline/skills",
|
|
1539
|
-
".codebuddy/skills",
|
|
1540
|
-
".codex/skills",
|
|
1541
|
-
".commandcode/skills",
|
|
1542
|
-
".continue/skills",
|
|
1543
|
-
".github/skills",
|
|
1544
|
-
".goose/skills",
|
|
1545
|
-
".iflow/skills",
|
|
1546
|
-
".junie/skills",
|
|
1547
|
-
".kilocode/skills",
|
|
1548
|
-
".kiro/skills",
|
|
1549
|
-
".mux/skills",
|
|
1550
|
-
".neovate/skills",
|
|
1551
|
-
".opencode/skills",
|
|
1552
|
-
".openhands/skills",
|
|
1553
|
-
".pi/skills",
|
|
1554
|
-
".qoder/skills",
|
|
1555
|
-
".roo/skills",
|
|
1556
|
-
".trae/skills",
|
|
1557
|
-
".windsurf/skills",
|
|
1558
|
-
".zcode/skills",
|
|
1559
|
-
".zencoder/skills"
|
|
1560
|
-
];
|
|
1561
|
-
function normalizeSkillName(name) {
|
|
1562
|
-
return name.toLowerCase().replace(/[\s_]+/g, "-");
|
|
1563
|
-
}
|
|
1564
|
-
function normalizeRelativePath(path) {
|
|
1565
|
-
return path.split(sep).join("/").replace(/\/+/g, "/");
|
|
1566
|
-
}
|
|
1567
|
-
function shouldInstallInternalSkills() {
|
|
1568
|
-
const envValue = process.env.INSTALL_INTERNAL_SKILLS;
|
|
1569
|
-
return envValue === "1" || envValue === "true";
|
|
1570
|
-
}
|
|
1571
|
-
async function hasSkillMd(dir) {
|
|
1572
|
-
try {
|
|
1573
|
-
return (await stat(join(dir, "SKILL.md"))).isFile();
|
|
1574
|
-
} catch {
|
|
1575
|
-
return false;
|
|
1576
|
-
}
|
|
1577
|
-
}
|
|
1578
|
-
async function parseSkillMd(skillMdPath, options) {
|
|
1579
|
-
try {
|
|
1580
|
-
const content = await readFile(skillMdPath, "utf-8");
|
|
1581
|
-
const { data } = parseFrontmatter(content);
|
|
1582
|
-
if (!data.name || !data.description) return null;
|
|
1583
|
-
if (typeof data.name !== "string" || typeof data.description !== "string") return null;
|
|
1584
|
-
if (data.metadata?.internal === true && !shouldInstallInternalSkills() && !options?.includeInternal) return null;
|
|
1585
|
-
return {
|
|
1586
|
-
name: sanitizeMetadata(data.name),
|
|
1587
|
-
description: sanitizeMetadata(data.description),
|
|
1588
|
-
path: dirname(skillMdPath),
|
|
1589
|
-
rawContent: content,
|
|
1590
|
-
metadata: data.metadata
|
|
1591
|
-
};
|
|
1592
|
-
} catch {
|
|
1593
|
-
return null;
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1596
|
-
async function findSkillDirs(dir, depth = 0, maxDepth = 5) {
|
|
1597
|
-
if (depth > maxDepth) return [];
|
|
1598
|
-
try {
|
|
1599
|
-
const [hasSkill, entries] = await Promise.all([hasSkillMd(dir), readdir(dir, { withFileTypes: true }).catch(() => [])]);
|
|
1600
|
-
const currentDir = hasSkill ? [dir] : [];
|
|
1601
|
-
const subDirResults = await Promise.all(entries.filter((entry) => entry.isDirectory() && !SKIP_DIRS.includes(entry.name)).map((entry) => findSkillDirs(join(dir, entry.name), depth + 1, maxDepth)));
|
|
1602
|
-
return [...currentDir, ...subDirResults.flat()];
|
|
1603
|
-
} catch {
|
|
1604
|
-
return [];
|
|
1605
|
-
}
|
|
1606
|
-
}
|
|
1607
|
-
function isSubpathSafe(basePath, subpath) {
|
|
1608
|
-
const normalizedBase = normalize(resolve(basePath));
|
|
1609
|
-
const normalizedTarget = normalize(resolve(join(basePath, subpath)));
|
|
1610
|
-
return normalizedTarget.startsWith(normalizedBase + sep) || normalizedTarget === normalizedBase;
|
|
1611
|
-
}
|
|
1612
|
-
async function discoverSkills(basePath, subpath, options) {
|
|
1613
|
-
const skills = [];
|
|
1614
|
-
const seenNames = /* @__PURE__ */ new Set();
|
|
1615
|
-
const localLock = await readLocalLock(basePath);
|
|
1616
|
-
const lockedSkillNames = new Set(Object.keys(localLock.skills).map(normalizeSkillName));
|
|
1617
|
-
if (subpath && !isSubpathSafe(basePath, subpath)) throw new Error(`Invalid subpath: "${subpath}" resolves outside the repository directory. Subpath must not contain ".." segments that escape the base path.`);
|
|
1618
|
-
const searchPath = subpath ? join(basePath, subpath) : basePath;
|
|
1619
|
-
const pluginGroupings = await getPluginGroupings(searchPath);
|
|
1620
|
-
const enhanceSkill = (skill) => {
|
|
1621
|
-
const resolvedPath = resolve(skill.path);
|
|
1622
|
-
if (pluginGroupings.has(resolvedPath)) skill.pluginName = pluginGroupings.get(resolvedPath);
|
|
1623
|
-
return skill;
|
|
1624
|
-
};
|
|
1625
|
-
const isInstalledProjectSkill = (skill) => {
|
|
1626
|
-
if (lockedSkillNames.size === 0) return false;
|
|
1627
|
-
const relativeDir = normalizeRelativePath(relative(basePath, skill.path));
|
|
1628
|
-
if (!AGENT_PROJECT_SKILL_DIRS.some((dir) => relativeDir === dir || relativeDir.startsWith(`${dir}/`))) return false;
|
|
1629
|
-
const skillName = normalizeSkillName(skill.name);
|
|
1630
|
-
const directoryName = normalizeSkillName(basename(skill.path));
|
|
1631
|
-
return lockedSkillNames.has(skillName) || lockedSkillNames.has(directoryName);
|
|
1632
|
-
};
|
|
1633
|
-
if (await hasSkillMd(searchPath)) {
|
|
1634
|
-
let skill = await parseSkillMd(join(searchPath, "SKILL.md"), options);
|
|
1635
|
-
if (skill) {
|
|
1636
|
-
if (!isInstalledProjectSkill(skill)) {
|
|
1637
|
-
skill = enhanceSkill(skill);
|
|
1638
|
-
skills.push(skill);
|
|
1639
|
-
seenNames.add(skill.name);
|
|
1640
|
-
if (!options?.fullDepth) return skills;
|
|
1641
|
-
}
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
const prioritySearchDirs = [
|
|
1645
|
-
searchPath,
|
|
1646
|
-
join(searchPath, "skills"),
|
|
1647
|
-
join(searchPath, "skills/.curated"),
|
|
1648
|
-
join(searchPath, "skills/.experimental"),
|
|
1649
|
-
join(searchPath, "skills/.system"),
|
|
1650
|
-
...AGENT_PROJECT_SKILL_DIRS.map((dir) => join(searchPath, dir))
|
|
1651
|
-
];
|
|
1652
|
-
const deepContainerDirs = new Set(prioritySearchDirs.slice(1));
|
|
1653
|
-
prioritySearchDirs.push(...await getPluginSkillPaths(searchPath));
|
|
1654
|
-
const tryAddSkillAt = async (skillDir) => {
|
|
1655
|
-
if (!await hasSkillMd(skillDir)) return false;
|
|
1656
|
-
let skill = await parseSkillMd(join(skillDir, "SKILL.md"), options);
|
|
1657
|
-
if (!skill || seenNames.has(skill.name)) return true;
|
|
1658
|
-
if (isInstalledProjectSkill(skill)) return true;
|
|
1659
|
-
skill = enhanceSkill(skill);
|
|
1660
|
-
skills.push(skill);
|
|
1661
|
-
seenNames.add(skill.name);
|
|
1662
|
-
return true;
|
|
1663
|
-
};
|
|
1664
|
-
for (const dir of prioritySearchDirs) {
|
|
1665
|
-
const walkDeep = deepContainerDirs.has(dir);
|
|
1666
|
-
try {
|
|
1667
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
1668
|
-
for (const entry of entries) {
|
|
1669
|
-
if (!entry.isDirectory()) continue;
|
|
1670
|
-
const childDir = join(dir, entry.name);
|
|
1671
|
-
if (await tryAddSkillAt(childDir) || !walkDeep) continue;
|
|
1672
|
-
if (SKIP_DIRS.includes(entry.name)) continue;
|
|
1673
|
-
try {
|
|
1674
|
-
const grandEntries = await readdir(childDir, { withFileTypes: true });
|
|
1675
|
-
for (const grand of grandEntries) {
|
|
1676
|
-
if (!grand.isDirectory() || SKIP_DIRS.includes(grand.name)) continue;
|
|
1677
|
-
await tryAddSkillAt(join(childDir, grand.name));
|
|
1678
|
-
}
|
|
1679
|
-
} catch {}
|
|
1680
|
-
}
|
|
1681
|
-
} catch {}
|
|
1682
|
-
}
|
|
1683
|
-
if (skills.length === 0 || options?.fullDepth) {
|
|
1684
|
-
const allSkillDirs = await findSkillDirs(searchPath);
|
|
1685
|
-
for (const skillDir of allSkillDirs) {
|
|
1686
|
-
let skill = await parseSkillMd(join(skillDir, "SKILL.md"), options);
|
|
1687
|
-
if (skill && !seenNames.has(skill.name) && !isInstalledProjectSkill(skill)) {
|
|
1688
|
-
skill = enhanceSkill(skill);
|
|
1689
|
-
skills.push(skill);
|
|
1690
|
-
seenNames.add(skill.name);
|
|
1691
|
-
}
|
|
1692
|
-
}
|
|
1693
|
-
}
|
|
1694
|
-
return skills;
|
|
1695
|
-
}
|
|
1696
|
-
function getSkillDisplayName(skill) {
|
|
1697
|
-
return skill.name || basename(skill.path);
|
|
1698
|
-
}
|
|
1699
|
-
function filterSkills(skills, inputNames) {
|
|
1700
|
-
const normalizedInputs = inputNames.map((n) => n.toLowerCase());
|
|
1701
|
-
return skills.filter((skill) => {
|
|
1702
|
-
const name = skill.name.toLowerCase();
|
|
1703
|
-
const displayName = getSkillDisplayName(skill).toLowerCase();
|
|
1704
|
-
return normalizedInputs.some((input) => input === name || input === displayName);
|
|
1705
|
-
});
|
|
1706
|
-
}
|
|
1707
|
-
var agents_exports = /* @__PURE__ */ __exportAll({
|
|
1708
|
-
EVE_SUBAGENTS_DIR: () => EVE_SUBAGENTS_DIR,
|
|
1709
|
-
agents: () => agents,
|
|
1710
|
-
detectInstalledAgents: () => detectInstalledAgents,
|
|
1711
|
-
getEveSubagents: () => getEveSubagents,
|
|
1712
|
-
getNonUniversalAgents: () => getNonUniversalAgents,
|
|
1713
|
-
getOpenClawGlobalSkillsDir: () => getOpenClawGlobalSkillsDir,
|
|
1714
|
-
getUniversalAgents: () => getUniversalAgents,
|
|
1715
|
-
getVisibleUniversalAgents: () => getVisibleUniversalAgents,
|
|
1716
|
-
isUniversalAgent: () => isUniversalAgent,
|
|
1717
|
-
isZCodeInstalled: () => isZCodeInstalled,
|
|
1718
|
-
setAgents: () => setAgents
|
|
1719
|
-
});
|
|
1720
|
-
const home = homedir();
|
|
1721
|
-
const configHome = xdgConfig ?? join(home, ".config");
|
|
1722
|
-
const codexHome = process.env.CODEX_HOME?.trim() || join(home, ".codex");
|
|
1723
|
-
const claudeHome = process.env.CLAUDE_CONFIG_DIR?.trim() || join(home, ".claude");
|
|
1724
|
-
const vibeHome = process.env.VIBE_HOME?.trim() || join(home, ".vibe");
|
|
1725
|
-
const hermesHome = process.env.HERMES_HOME?.trim() || join(home, ".hermes");
|
|
1726
|
-
const autohandHome = process.env.AUTOHAND_HOME?.trim() || join(home, ".autohand");
|
|
1727
|
-
const zedAppDataHome = process.env.APPDATA?.trim();
|
|
1728
|
-
const zedFlatpakConfigHome = process.env.FLATPAK_XDG_CONFIG_HOME?.trim();
|
|
1729
|
-
function packageJsonHasDependency(packageJsonPath, dependencyName) {
|
|
1730
|
-
try {
|
|
1731
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
1732
|
-
return !!(packageJson.dependencies?.[dependencyName] || packageJson.devDependencies?.[dependencyName]);
|
|
1733
|
-
} catch {
|
|
1734
|
-
return false;
|
|
1735
|
-
}
|
|
1736
|
-
}
|
|
1737
|
-
function getOpenClawGlobalSkillsDir(homeDir = home, pathExists = existsSync) {
|
|
1738
|
-
if (pathExists(join(homeDir, ".openclaw"))) return join(homeDir, ".openclaw/skills");
|
|
1739
|
-
if (pathExists(join(homeDir, ".clawdbot"))) return join(homeDir, ".clawdbot/skills");
|
|
1740
|
-
if (pathExists(join(homeDir, ".moltbot"))) return join(homeDir, ".moltbot/skills");
|
|
1741
|
-
return join(homeDir, ".openclaw/skills");
|
|
1742
|
-
}
|
|
1743
|
-
function isZCodeInstalled(homeDir = home, pathExists = existsSync) {
|
|
1744
|
-
return pathExists(join(homeDir, ".zcode")) || pathExists("/Applications/ZCode.app");
|
|
1745
|
-
}
|
|
1746
|
-
const agents = {
|
|
1747
|
-
"aider-desk": {
|
|
1748
|
-
name: "aider-desk",
|
|
1749
|
-
displayName: "AiderDesk",
|
|
1750
|
-
skillsDir: ".aider-desk/skills",
|
|
1751
|
-
globalSkillsDir: join(home, ".aider-desk/skills"),
|
|
1752
|
-
detectInstalled: async () => {
|
|
1753
|
-
return existsSync(join(home, ".aider-desk"));
|
|
1754
|
-
}
|
|
1755
|
-
},
|
|
1756
|
-
amp: {
|
|
1757
|
-
name: "amp",
|
|
1758
|
-
displayName: "Amp",
|
|
1759
|
-
skillsDir: ".agents/skills",
|
|
1760
|
-
globalSkillsDir: join(configHome, "agents/skills"),
|
|
1761
|
-
detectInstalled: async () => {
|
|
1762
|
-
return existsSync(join(configHome, "amp"));
|
|
1763
|
-
}
|
|
1764
|
-
},
|
|
1765
|
-
antigravity: {
|
|
1766
|
-
name: "antigravity",
|
|
1767
|
-
displayName: "Antigravity",
|
|
1768
|
-
skillsDir: ".agents/skills",
|
|
1769
|
-
globalSkillsDir: join(home, ".gemini/antigravity/skills"),
|
|
1770
|
-
detectInstalled: async () => {
|
|
1771
|
-
return existsSync(join(home, ".gemini/antigravity"));
|
|
1772
|
-
}
|
|
1773
|
-
},
|
|
1774
|
-
"antigravity-cli": {
|
|
1775
|
-
name: "antigravity-cli",
|
|
1776
|
-
displayName: "Antigravity CLI",
|
|
1777
|
-
skillsDir: ".agents/skills",
|
|
1778
|
-
globalSkillsDir: join(home, ".gemini/antigravity-cli/skills"),
|
|
1779
|
-
detectInstalled: async () => {
|
|
1780
|
-
return existsSync(join(home, ".gemini/antigravity-cli"));
|
|
1781
|
-
}
|
|
1782
|
-
},
|
|
1783
|
-
astrbot: {
|
|
1784
|
-
name: "astrbot",
|
|
1785
|
-
displayName: "AstrBot",
|
|
1786
|
-
skillsDir: "data/skills",
|
|
1787
|
-
globalSkillsDir: join(home, ".astrbot/data/skills"),
|
|
1788
|
-
detectInstalled: async () => {
|
|
1789
|
-
return existsSync(join(process.cwd(), "data/skills")) || existsSync(join(home, ".astrbot"));
|
|
1790
|
-
}
|
|
1791
|
-
},
|
|
1792
|
-
"autohand-code": {
|
|
1793
|
-
name: "autohand-code",
|
|
1794
|
-
displayName: "Autohand Code CLI",
|
|
1795
|
-
skillsDir: ".autohand/skills",
|
|
1796
|
-
globalSkillsDir: join(autohandHome, "skills"),
|
|
1797
|
-
detectInstalled: async () => {
|
|
1798
|
-
return existsSync(autohandHome);
|
|
1799
|
-
}
|
|
1800
|
-
},
|
|
1801
|
-
augment: {
|
|
1802
|
-
name: "augment",
|
|
1803
|
-
displayName: "Augment",
|
|
1804
|
-
skillsDir: ".augment/skills",
|
|
1805
|
-
globalSkillsDir: join(home, ".augment/skills"),
|
|
1806
|
-
detectInstalled: async () => {
|
|
1807
|
-
return existsSync(join(home, ".augment"));
|
|
1808
|
-
}
|
|
1809
|
-
},
|
|
1810
|
-
bob: {
|
|
1811
|
-
name: "bob",
|
|
1812
|
-
displayName: "IBM Bob",
|
|
1813
|
-
skillsDir: ".bob/skills",
|
|
1814
|
-
globalSkillsDir: join(home, ".bob/skills"),
|
|
1815
|
-
detectInstalled: async () => {
|
|
1816
|
-
return existsSync(join(home, ".bob"));
|
|
1817
|
-
}
|
|
1818
|
-
},
|
|
1819
|
-
"claude-code": {
|
|
1820
|
-
name: "claude-code",
|
|
1821
|
-
displayName: "Claude Code",
|
|
1822
|
-
skillsDir: ".claude/skills",
|
|
1823
|
-
globalSkillsDir: join(claudeHome, "skills"),
|
|
1824
|
-
detectInstalled: async () => {
|
|
1825
|
-
return existsSync(claudeHome);
|
|
1826
|
-
}
|
|
1827
|
-
},
|
|
1828
|
-
openclaw: {
|
|
1829
|
-
name: "openclaw",
|
|
1830
|
-
displayName: "OpenClaw",
|
|
1831
|
-
skillsDir: "skills",
|
|
1832
|
-
globalSkillsDir: getOpenClawGlobalSkillsDir(),
|
|
1833
|
-
detectInstalled: async () => {
|
|
1834
|
-
return existsSync(join(home, ".openclaw")) || existsSync(join(home, ".clawdbot")) || existsSync(join(home, ".moltbot"));
|
|
1835
|
-
}
|
|
1836
|
-
},
|
|
1837
|
-
cline: {
|
|
1838
|
-
name: "cline",
|
|
1839
|
-
displayName: "Cline",
|
|
1840
|
-
skillsDir: ".agents/skills",
|
|
1841
|
-
globalSkillsDir: join(home, ".agents", "skills"),
|
|
1842
|
-
detectInstalled: async () => {
|
|
1843
|
-
return existsSync(join(home, ".cline"));
|
|
1844
|
-
}
|
|
1845
|
-
},
|
|
1846
|
-
"codearts-agent": {
|
|
1847
|
-
name: "codearts-agent",
|
|
1848
|
-
displayName: "CodeArts Agent",
|
|
1849
|
-
skillsDir: ".codeartsdoer/skills",
|
|
1850
|
-
globalSkillsDir: join(home, ".codeartsdoer/skills"),
|
|
1851
|
-
detectInstalled: async () => {
|
|
1852
|
-
return existsSync(join(home, ".codeartsdoer"));
|
|
1853
|
-
}
|
|
1854
|
-
},
|
|
1855
|
-
codebuddy: {
|
|
1856
|
-
name: "codebuddy",
|
|
1857
|
-
displayName: "CodeBuddy",
|
|
1858
|
-
skillsDir: ".codebuddy/skills",
|
|
1859
|
-
globalSkillsDir: join(home, ".codebuddy/skills"),
|
|
1860
|
-
detectInstalled: async () => {
|
|
1861
|
-
return existsSync(join(process.cwd(), ".codebuddy")) || existsSync(join(home, ".codebuddy"));
|
|
1862
|
-
}
|
|
1863
|
-
},
|
|
1864
|
-
codemaker: {
|
|
1865
|
-
name: "codemaker",
|
|
1866
|
-
displayName: "Codemaker",
|
|
1867
|
-
skillsDir: ".codemaker/skills",
|
|
1868
|
-
globalSkillsDir: join(home, ".codemaker/skills"),
|
|
1869
|
-
detectInstalled: async () => {
|
|
1870
|
-
return existsSync(join(home, ".codemaker"));
|
|
1871
|
-
}
|
|
1872
|
-
},
|
|
1873
|
-
codestudio: {
|
|
1874
|
-
name: "codestudio",
|
|
1875
|
-
displayName: "Code Studio",
|
|
1876
|
-
skillsDir: ".codestudio/skills",
|
|
1877
|
-
globalSkillsDir: join(home, ".codestudio/skills"),
|
|
1878
|
-
detectInstalled: async () => {
|
|
1879
|
-
return existsSync(join(home, ".codestudio"));
|
|
1880
|
-
}
|
|
1881
|
-
},
|
|
1882
|
-
codex: {
|
|
1883
|
-
name: "codex",
|
|
1884
|
-
displayName: "Codex",
|
|
1885
|
-
skillsDir: ".agents/skills",
|
|
1886
|
-
globalSkillsDir: join(codexHome, "skills"),
|
|
1887
|
-
detectInstalled: async () => {
|
|
1888
|
-
return existsSync(codexHome) || existsSync("/etc/codex");
|
|
1889
|
-
}
|
|
1890
|
-
},
|
|
1891
|
-
"command-code": {
|
|
1892
|
-
name: "command-code",
|
|
1893
|
-
displayName: "Command Code",
|
|
1894
|
-
skillsDir: ".commandcode/skills",
|
|
1895
|
-
globalSkillsDir: join(home, ".commandcode/skills"),
|
|
1896
|
-
detectInstalled: async () => {
|
|
1897
|
-
return existsSync(join(home, ".commandcode"));
|
|
1898
|
-
}
|
|
1899
|
-
},
|
|
1900
|
-
continue: {
|
|
1901
|
-
name: "continue",
|
|
1902
|
-
displayName: "Continue",
|
|
1903
|
-
skillsDir: ".continue/skills",
|
|
1904
|
-
globalSkillsDir: join(home, ".continue/skills"),
|
|
1905
|
-
detectInstalled: async () => {
|
|
1906
|
-
return existsSync(join(process.cwd(), ".continue")) || existsSync(join(home, ".continue"));
|
|
1907
|
-
}
|
|
1908
|
-
},
|
|
1909
|
-
cortex: {
|
|
1910
|
-
name: "cortex",
|
|
1911
|
-
displayName: "Cortex Code",
|
|
1912
|
-
skillsDir: ".cortex/skills",
|
|
1913
|
-
globalSkillsDir: join(home, ".snowflake/cortex/skills"),
|
|
1914
|
-
detectInstalled: async () => {
|
|
1915
|
-
return existsSync(join(home, ".snowflake/cortex"));
|
|
1916
|
-
}
|
|
1917
|
-
},
|
|
1918
|
-
crush: {
|
|
1919
|
-
name: "crush",
|
|
1920
|
-
displayName: "Crush",
|
|
1921
|
-
skillsDir: ".crush/skills",
|
|
1922
|
-
globalSkillsDir: join(home, ".config/crush/skills"),
|
|
1923
|
-
detectInstalled: async () => {
|
|
1924
|
-
return existsSync(join(home, ".config/crush"));
|
|
1925
|
-
}
|
|
1926
|
-
},
|
|
1927
|
-
cursor: {
|
|
1928
|
-
name: "cursor",
|
|
1929
|
-
displayName: "Cursor",
|
|
1930
|
-
skillsDir: ".agents/skills",
|
|
1931
|
-
globalSkillsDir: join(home, ".cursor/skills"),
|
|
1932
|
-
detectInstalled: async () => {
|
|
1933
|
-
return existsSync(join(home, ".cursor"));
|
|
1934
|
-
}
|
|
1935
|
-
},
|
|
1936
|
-
deepagents: {
|
|
1937
|
-
name: "deepagents",
|
|
1938
|
-
displayName: "Deep Agents",
|
|
1939
|
-
skillsDir: ".agents/skills",
|
|
1940
|
-
globalSkillsDir: join(home, ".deepagents/agent/skills"),
|
|
1941
|
-
detectInstalled: async () => {
|
|
1942
|
-
return existsSync(join(home, ".deepagents"));
|
|
1943
|
-
}
|
|
1944
|
-
},
|
|
1945
|
-
devin: {
|
|
1946
|
-
name: "devin",
|
|
1947
|
-
displayName: "Devin for Terminal",
|
|
1948
|
-
skillsDir: ".devin/skills",
|
|
1949
|
-
globalSkillsDir: join(configHome, "devin/skills"),
|
|
1950
|
-
detectInstalled: async () => {
|
|
1951
|
-
return existsSync(join(configHome, "devin"));
|
|
1952
|
-
}
|
|
1953
|
-
},
|
|
1954
|
-
dexto: {
|
|
1955
|
-
name: "dexto",
|
|
1956
|
-
displayName: "Dexto",
|
|
1957
|
-
skillsDir: ".agents/skills",
|
|
1958
|
-
globalSkillsDir: join(home, ".agents/skills"),
|
|
1959
|
-
showInUniversalPrompt: false,
|
|
1960
|
-
detectInstalled: async () => {
|
|
1961
|
-
return existsSync(join(home, ".dexto"));
|
|
1962
|
-
}
|
|
1963
|
-
},
|
|
1964
|
-
droid: {
|
|
1965
|
-
name: "droid",
|
|
1966
|
-
displayName: "Droid",
|
|
1967
|
-
skillsDir: ".factory/skills",
|
|
1968
|
-
globalSkillsDir: join(home, ".factory/skills"),
|
|
1969
|
-
detectInstalled: async () => {
|
|
1970
|
-
return existsSync(join(home, ".factory"));
|
|
1971
|
-
}
|
|
1972
|
-
},
|
|
1973
|
-
eve: {
|
|
1974
|
-
name: "eve",
|
|
1975
|
-
displayName: "Eve",
|
|
1976
|
-
skillsDir: "agent/skills",
|
|
1977
|
-
globalSkillsDir: void 0,
|
|
1978
|
-
detectInstalled: async () => {
|
|
1979
|
-
const cwd = process.cwd();
|
|
1980
|
-
return existsSync(join(cwd, "agent")) && packageJsonHasDependency(join(cwd, "package.json"), "eve");
|
|
1981
|
-
}
|
|
1982
|
-
},
|
|
1983
|
-
firebender: {
|
|
1984
|
-
name: "firebender",
|
|
1985
|
-
displayName: "Firebender",
|
|
1986
|
-
skillsDir: ".agents/skills",
|
|
1987
|
-
globalSkillsDir: join(home, ".firebender/skills"),
|
|
1988
|
-
showInUniversalPrompt: false,
|
|
1989
|
-
detectInstalled: async () => {
|
|
1990
|
-
return existsSync(join(home, ".firebender"));
|
|
1991
|
-
}
|
|
1992
|
-
},
|
|
1993
|
-
forgecode: {
|
|
1994
|
-
name: "forgecode",
|
|
1995
|
-
displayName: "ForgeCode",
|
|
1996
|
-
skillsDir: ".forge/skills",
|
|
1997
|
-
globalSkillsDir: join(home, ".forge/skills"),
|
|
1998
|
-
detectInstalled: async () => {
|
|
1999
|
-
return existsSync(join(home, ".forge"));
|
|
2000
|
-
}
|
|
2001
|
-
},
|
|
2002
|
-
"gemini-cli": {
|
|
2003
|
-
name: "gemini-cli",
|
|
2004
|
-
displayName: "Gemini CLI",
|
|
2005
|
-
skillsDir: ".agents/skills",
|
|
2006
|
-
globalSkillsDir: join(home, ".gemini/skills"),
|
|
2007
|
-
detectInstalled: async () => {
|
|
2008
|
-
return existsSync(join(home, ".gemini"));
|
|
2009
|
-
}
|
|
2010
|
-
},
|
|
2011
|
-
"github-copilot": {
|
|
2012
|
-
name: "github-copilot",
|
|
2013
|
-
displayName: "GitHub Copilot",
|
|
2014
|
-
skillsDir: ".agents/skills",
|
|
2015
|
-
globalSkillsDir: join(home, ".copilot/skills"),
|
|
2016
|
-
detectInstalled: async () => {
|
|
2017
|
-
return existsSync(join(home, ".copilot"));
|
|
2018
|
-
}
|
|
2019
|
-
},
|
|
2020
|
-
goose: {
|
|
2021
|
-
name: "goose",
|
|
2022
|
-
displayName: "Goose",
|
|
2023
|
-
skillsDir: ".goose/skills",
|
|
2024
|
-
globalSkillsDir: join(configHome, "goose/skills"),
|
|
2025
|
-
detectInstalled: async () => {
|
|
2026
|
-
return existsSync(join(configHome, "goose"));
|
|
2027
|
-
}
|
|
2028
|
-
},
|
|
2029
|
-
"hermes-agent": {
|
|
2030
|
-
name: "hermes-agent",
|
|
2031
|
-
displayName: "Hermes Agent",
|
|
2032
|
-
skillsDir: ".hermes/skills",
|
|
2033
|
-
globalSkillsDir: join(hermesHome, "skills"),
|
|
2034
|
-
detectInstalled: async () => {
|
|
2035
|
-
return existsSync(hermesHome);
|
|
2036
|
-
}
|
|
2037
|
-
},
|
|
2038
|
-
"inference-sh": {
|
|
2039
|
-
name: "inference-sh",
|
|
2040
|
-
displayName: "inference.sh",
|
|
2041
|
-
skillsDir: ".inferencesh/skills",
|
|
2042
|
-
globalSkillsDir: join(home, ".inferencesh/skills"),
|
|
2043
|
-
detectInstalled: async () => {
|
|
2044
|
-
return existsSync(join(home, ".inferencesh"));
|
|
2045
|
-
}
|
|
2046
|
-
},
|
|
2047
|
-
jazz: {
|
|
2048
|
-
name: "jazz",
|
|
2049
|
-
displayName: "Jazz",
|
|
2050
|
-
skillsDir: ".jazz/skills",
|
|
2051
|
-
globalSkillsDir: join(home, ".jazz/skills"),
|
|
2052
|
-
detectInstalled: async () => {
|
|
2053
|
-
return existsSync(join(home, ".jazz")) || existsSync(join(process.cwd(), ".jazz"));
|
|
2054
|
-
}
|
|
2055
|
-
},
|
|
2056
|
-
junie: {
|
|
2057
|
-
name: "junie",
|
|
2058
|
-
displayName: "Junie",
|
|
2059
|
-
skillsDir: ".junie/skills",
|
|
2060
|
-
globalSkillsDir: join(home, ".junie/skills"),
|
|
2061
|
-
detectInstalled: async () => {
|
|
2062
|
-
return existsSync(join(home, ".junie"));
|
|
2063
|
-
}
|
|
2064
|
-
},
|
|
2065
|
-
"iflow-cli": {
|
|
2066
|
-
name: "iflow-cli",
|
|
2067
|
-
displayName: "iFlow CLI",
|
|
2068
|
-
skillsDir: ".iflow/skills",
|
|
2069
|
-
globalSkillsDir: join(home, ".iflow/skills"),
|
|
2070
|
-
detectInstalled: async () => {
|
|
2071
|
-
return existsSync(join(home, ".iflow"));
|
|
2072
|
-
}
|
|
2073
|
-
},
|
|
2074
|
-
kilo: {
|
|
2075
|
-
name: "kilo",
|
|
2076
|
-
displayName: "Kilo Code",
|
|
2077
|
-
skillsDir: ".kilocode/skills",
|
|
2078
|
-
globalSkillsDir: join(home, ".kilocode/skills"),
|
|
2079
|
-
detectInstalled: async () => {
|
|
2080
|
-
return existsSync(join(home, ".kilocode"));
|
|
2081
|
-
}
|
|
2082
|
-
},
|
|
2083
|
-
"kimi-code-cli": {
|
|
2084
|
-
name: "kimi-code-cli",
|
|
2085
|
-
displayName: "Kimi Code CLI",
|
|
2086
|
-
skillsDir: ".agents/skills",
|
|
2087
|
-
globalSkillsDir: join(home, ".agents/skills"),
|
|
2088
|
-
detectInstalled: async () => {
|
|
2089
|
-
return existsSync(join(home, ".kimi-code")) || existsSync(join(home, ".kimi"));
|
|
2090
|
-
}
|
|
2091
|
-
},
|
|
2092
|
-
"kiro-cli": {
|
|
2093
|
-
name: "kiro-cli",
|
|
2094
|
-
displayName: "Kiro CLI",
|
|
2095
|
-
skillsDir: ".kiro/skills",
|
|
2096
|
-
globalSkillsDir: join(home, ".kiro/skills"),
|
|
2097
|
-
detectInstalled: async () => {
|
|
2098
|
-
return existsSync(join(home, ".kiro"));
|
|
2099
|
-
}
|
|
2100
|
-
},
|
|
2101
|
-
kode: {
|
|
2102
|
-
name: "kode",
|
|
2103
|
-
displayName: "Kode",
|
|
2104
|
-
skillsDir: ".kode/skills",
|
|
2105
|
-
globalSkillsDir: join(home, ".kode/skills"),
|
|
2106
|
-
detectInstalled: async () => {
|
|
2107
|
-
return existsSync(join(home, ".kode"));
|
|
2108
|
-
}
|
|
2109
|
-
},
|
|
2110
|
-
lingma: {
|
|
2111
|
-
name: "lingma",
|
|
2112
|
-
displayName: "Lingma",
|
|
2113
|
-
skillsDir: ".lingma/skills",
|
|
2114
|
-
globalSkillsDir: join(home, ".lingma/skills"),
|
|
2115
|
-
detectInstalled: async () => {
|
|
2116
|
-
return existsSync(join(home, ".lingma"));
|
|
2117
|
-
}
|
|
2118
|
-
},
|
|
2119
|
-
loaf: {
|
|
2120
|
-
name: "loaf",
|
|
2121
|
-
displayName: "Loaf",
|
|
2122
|
-
skillsDir: ".agents/skills",
|
|
2123
|
-
globalSkillsDir: join(home, ".agents/skills"),
|
|
2124
|
-
showInUniversalPrompt: false,
|
|
2125
|
-
detectInstalled: async () => {
|
|
2126
|
-
return existsSync(join(home, ".loaf"));
|
|
2127
|
-
}
|
|
2128
|
-
},
|
|
2129
|
-
mcpjam: {
|
|
2130
|
-
name: "mcpjam",
|
|
2131
|
-
displayName: "MCPJam",
|
|
2132
|
-
skillsDir: ".mcpjam/skills",
|
|
2133
|
-
globalSkillsDir: join(home, ".mcpjam/skills"),
|
|
2134
|
-
detectInstalled: async () => {
|
|
2135
|
-
return existsSync(join(home, ".mcpjam"));
|
|
2136
|
-
}
|
|
2137
|
-
},
|
|
2138
|
-
"mistral-vibe": {
|
|
2139
|
-
name: "mistral-vibe",
|
|
2140
|
-
displayName: "Mistral Vibe",
|
|
2141
|
-
skillsDir: ".vibe/skills",
|
|
2142
|
-
globalSkillsDir: join(vibeHome, "skills"),
|
|
2143
|
-
detectInstalled: async () => {
|
|
2144
|
-
return existsSync(vibeHome);
|
|
2145
|
-
}
|
|
2146
|
-
},
|
|
2147
|
-
moxby: {
|
|
2148
|
-
name: "moxby",
|
|
2149
|
-
displayName: "Moxby",
|
|
2150
|
-
skillsDir: ".moxby/skills",
|
|
2151
|
-
globalSkillsDir: join(home, ".moxby/skills"),
|
|
2152
|
-
detectInstalled: async () => {
|
|
2153
|
-
return existsSync(join(home, ".moxby"));
|
|
2154
|
-
}
|
|
2155
|
-
},
|
|
2156
|
-
mux: {
|
|
2157
|
-
name: "mux",
|
|
2158
|
-
displayName: "Mux",
|
|
2159
|
-
skillsDir: ".mux/skills",
|
|
2160
|
-
globalSkillsDir: join(home, ".mux/skills"),
|
|
2161
|
-
detectInstalled: async () => {
|
|
2162
|
-
return existsSync(join(home, ".mux"));
|
|
2163
|
-
}
|
|
2164
|
-
},
|
|
2165
|
-
opencode: {
|
|
2166
|
-
name: "opencode",
|
|
2167
|
-
displayName: "OpenCode",
|
|
2168
|
-
skillsDir: ".agents/skills",
|
|
2169
|
-
globalSkillsDir: join(configHome, "opencode/skills"),
|
|
2170
|
-
detectInstalled: async () => {
|
|
2171
|
-
return existsSync(join(configHome, "opencode"));
|
|
2172
|
-
}
|
|
2173
|
-
},
|
|
2174
|
-
openhands: {
|
|
2175
|
-
name: "openhands",
|
|
2176
|
-
displayName: "OpenHands",
|
|
2177
|
-
skillsDir: ".openhands/skills",
|
|
2178
|
-
globalSkillsDir: join(home, ".openhands/skills"),
|
|
2179
|
-
detectInstalled: async () => {
|
|
2180
|
-
return existsSync(join(home, ".openhands"));
|
|
2181
|
-
}
|
|
2182
|
-
},
|
|
2183
|
-
ona: {
|
|
2184
|
-
name: "ona",
|
|
2185
|
-
displayName: "Ona",
|
|
2186
|
-
skillsDir: ".ona/skills",
|
|
2187
|
-
globalSkillsDir: join(home, ".ona/skills"),
|
|
2188
|
-
detectInstalled: async () => {
|
|
2189
|
-
return existsSync(join(home, ".ona"));
|
|
2190
|
-
}
|
|
2191
|
-
},
|
|
2192
|
-
pi: {
|
|
2193
|
-
name: "pi",
|
|
2194
|
-
displayName: "Pi",
|
|
2195
|
-
skillsDir: ".pi/skills",
|
|
2196
|
-
globalSkillsDir: join(home, ".pi/agent/skills"),
|
|
2197
|
-
detectInstalled: async () => {
|
|
2198
|
-
return existsSync(join(home, ".pi/agent"));
|
|
2199
|
-
}
|
|
2200
|
-
},
|
|
2201
|
-
qoder: {
|
|
2202
|
-
name: "qoder",
|
|
2203
|
-
displayName: "Qoder",
|
|
2204
|
-
skillsDir: ".qoder/skills",
|
|
2205
|
-
globalSkillsDir: join(home, ".qoder/skills"),
|
|
2206
|
-
detectInstalled: async () => {
|
|
2207
|
-
return existsSync(join(home, ".qoder"));
|
|
2208
|
-
}
|
|
2209
|
-
},
|
|
2210
|
-
"qoder-cn": {
|
|
2211
|
-
name: "qoder-cn",
|
|
2212
|
-
displayName: "Qoder CN",
|
|
2213
|
-
skillsDir: ".qoder/skills",
|
|
2214
|
-
globalSkillsDir: join(home, ".qoder-cn/skills"),
|
|
2215
|
-
detectInstalled: async () => {
|
|
2216
|
-
return existsSync(join(home, ".qoder-cn"));
|
|
2217
|
-
}
|
|
2218
|
-
},
|
|
2219
|
-
"qwen-code": {
|
|
2220
|
-
name: "qwen-code",
|
|
2221
|
-
displayName: "Qwen Code",
|
|
2222
|
-
skillsDir: ".qwen/skills",
|
|
2223
|
-
globalSkillsDir: join(home, ".qwen/skills"),
|
|
2224
|
-
detectInstalled: async () => {
|
|
2225
|
-
return existsSync(join(home, ".qwen"));
|
|
2226
|
-
}
|
|
2227
|
-
},
|
|
2228
|
-
replit: {
|
|
2229
|
-
name: "replit",
|
|
2230
|
-
displayName: "Replit",
|
|
2231
|
-
skillsDir: ".agents/skills",
|
|
2232
|
-
globalSkillsDir: join(configHome, "agents/skills"),
|
|
2233
|
-
showInUniversalList: false,
|
|
2234
|
-
detectInstalled: async () => {
|
|
2235
|
-
return existsSync(join(process.cwd(), ".replit"));
|
|
2236
|
-
}
|
|
2237
|
-
},
|
|
2238
|
-
reasonix: {
|
|
2239
|
-
name: "reasonix",
|
|
2240
|
-
displayName: "Reasonix",
|
|
2241
|
-
skillsDir: ".reasonix/skills",
|
|
2242
|
-
globalSkillsDir: join(home, ".reasonix/skills"),
|
|
2243
|
-
detectInstalled: async () => {
|
|
2244
|
-
return existsSync(join(home, ".reasonix"));
|
|
2245
|
-
}
|
|
2246
|
-
},
|
|
2247
|
-
rovodev: {
|
|
2248
|
-
name: "rovodev",
|
|
2249
|
-
displayName: "Rovo Dev",
|
|
2250
|
-
skillsDir: ".rovodev/skills",
|
|
2251
|
-
globalSkillsDir: join(home, ".rovodev/skills"),
|
|
2252
|
-
detectInstalled: async () => {
|
|
2253
|
-
return existsSync(join(home, ".rovodev"));
|
|
2254
|
-
}
|
|
2255
|
-
},
|
|
2256
|
-
roo: {
|
|
2257
|
-
name: "roo",
|
|
2258
|
-
displayName: "Roo Code",
|
|
2259
|
-
skillsDir: ".roo/skills",
|
|
2260
|
-
globalSkillsDir: join(home, ".roo/skills"),
|
|
2261
|
-
detectInstalled: async () => {
|
|
2262
|
-
return existsSync(join(home, ".roo"));
|
|
2263
|
-
}
|
|
2264
|
-
},
|
|
2265
|
-
"tabnine-cli": {
|
|
2266
|
-
name: "tabnine-cli",
|
|
2267
|
-
displayName: "Tabnine CLI",
|
|
2268
|
-
skillsDir: ".tabnine/agent/skills",
|
|
2269
|
-
globalSkillsDir: join(home, ".tabnine/agent/skills"),
|
|
2270
|
-
detectInstalled: async () => {
|
|
2271
|
-
return existsSync(join(home, ".tabnine"));
|
|
2272
|
-
}
|
|
2273
|
-
},
|
|
2274
|
-
terramind: {
|
|
2275
|
-
name: "terramind",
|
|
2276
|
-
displayName: "Terramind",
|
|
2277
|
-
skillsDir: ".terramind/skills",
|
|
2278
|
-
globalSkillsDir: join(home, ".terramind/skills"),
|
|
2279
|
-
detectInstalled: async () => {
|
|
2280
|
-
return existsSync(join(home, ".terramind"));
|
|
2281
|
-
}
|
|
2282
|
-
},
|
|
2283
|
-
tinycloud: {
|
|
2284
|
-
name: "tinycloud",
|
|
2285
|
-
displayName: "Tinycloud",
|
|
2286
|
-
skillsDir: ".tinycloud/skills",
|
|
2287
|
-
globalSkillsDir: join(home, ".tinycloud/skills"),
|
|
2288
|
-
detectInstalled: async () => {
|
|
2289
|
-
return existsSync(join(home, ".tinycloud"));
|
|
2290
|
-
}
|
|
2291
|
-
},
|
|
2292
|
-
trae: {
|
|
2293
|
-
name: "trae",
|
|
2294
|
-
displayName: "Trae",
|
|
2295
|
-
skillsDir: ".trae/skills",
|
|
2296
|
-
globalSkillsDir: join(home, ".trae/skills"),
|
|
2297
|
-
detectInstalled: async () => {
|
|
2298
|
-
return existsSync(join(home, ".trae"));
|
|
2299
|
-
}
|
|
2300
|
-
},
|
|
2301
|
-
"trae-cn": {
|
|
2302
|
-
name: "trae-cn",
|
|
2303
|
-
displayName: "Trae CN",
|
|
2304
|
-
skillsDir: ".trae/skills",
|
|
2305
|
-
globalSkillsDir: join(home, ".trae-cn/skills"),
|
|
2306
|
-
detectInstalled: async () => {
|
|
2307
|
-
return existsSync(join(home, ".trae-cn"));
|
|
2308
|
-
}
|
|
2309
|
-
},
|
|
2310
|
-
warp: {
|
|
2311
|
-
name: "warp",
|
|
2312
|
-
displayName: "Warp",
|
|
2313
|
-
skillsDir: ".agents/skills",
|
|
2314
|
-
globalSkillsDir: join(home, ".agents/skills"),
|
|
2315
|
-
detectInstalled: async () => {
|
|
2316
|
-
return existsSync(join(home, ".warp"));
|
|
2317
|
-
}
|
|
2318
|
-
},
|
|
2319
|
-
windsurf: {
|
|
2320
|
-
name: "windsurf",
|
|
2321
|
-
displayName: "Windsurf",
|
|
2322
|
-
skillsDir: ".windsurf/skills",
|
|
2323
|
-
globalSkillsDir: join(home, ".codeium/windsurf/skills"),
|
|
2324
|
-
detectInstalled: async () => {
|
|
2325
|
-
return existsSync(join(home, ".codeium/windsurf"));
|
|
2326
|
-
}
|
|
2327
|
-
},
|
|
2328
|
-
zed: {
|
|
2329
|
-
name: "zed",
|
|
2330
|
-
displayName: "Zed",
|
|
2331
|
-
skillsDir: ".agents/skills",
|
|
2332
|
-
globalSkillsDir: join(home, ".agents/skills"),
|
|
2333
|
-
detectInstalled: async () => {
|
|
2334
|
-
return existsSync(join(configHome, "zed")) || !!zedAppDataHome && existsSync(join(zedAppDataHome, "Zed")) || !!zedFlatpakConfigHome && existsSync(join(zedFlatpakConfigHome, "zed"));
|
|
2335
|
-
}
|
|
2336
|
-
},
|
|
2337
|
-
zcode: {
|
|
2338
|
-
name: "zcode",
|
|
2339
|
-
displayName: "ZCode",
|
|
2340
|
-
skillsDir: ".zcode/skills",
|
|
2341
|
-
globalSkillsDir: join(home, ".zcode/skills"),
|
|
2342
|
-
detectInstalled: async () => {
|
|
2343
|
-
return isZCodeInstalled();
|
|
2344
|
-
}
|
|
2345
|
-
},
|
|
2346
|
-
zencoder: {
|
|
2347
|
-
name: "zencoder",
|
|
2348
|
-
displayName: "Zencoder",
|
|
2349
|
-
skillsDir: ".zencoder/skills",
|
|
2350
|
-
globalSkillsDir: join(home, ".zencoder/skills"),
|
|
2351
|
-
detectInstalled: async () => {
|
|
2352
|
-
return existsSync(join(home, ".zencoder"));
|
|
2353
|
-
}
|
|
2354
|
-
},
|
|
2355
|
-
zenflow: {
|
|
2356
|
-
name: "zenflow",
|
|
2357
|
-
displayName: "Zenflow",
|
|
2358
|
-
skillsDir: ".zencoder/skills",
|
|
2359
|
-
globalSkillsDir: join(home, ".zencoder/skills"),
|
|
2360
|
-
detectInstalled: async () => {
|
|
2361
|
-
return existsSync(join(home, ".zencoder"));
|
|
2362
|
-
}
|
|
2363
|
-
},
|
|
2364
|
-
neovate: {
|
|
2365
|
-
name: "neovate",
|
|
2366
|
-
displayName: "Neovate",
|
|
2367
|
-
skillsDir: ".neovate/skills",
|
|
2368
|
-
globalSkillsDir: join(home, ".neovate/skills"),
|
|
2369
|
-
detectInstalled: async () => {
|
|
2370
|
-
return existsSync(join(home, ".neovate"));
|
|
2371
|
-
}
|
|
2372
|
-
},
|
|
2373
|
-
pochi: {
|
|
2374
|
-
name: "pochi",
|
|
2375
|
-
displayName: "Pochi",
|
|
2376
|
-
skillsDir: ".pochi/skills",
|
|
2377
|
-
globalSkillsDir: join(home, ".pochi/skills"),
|
|
2378
|
-
detectInstalled: async () => {
|
|
2379
|
-
return existsSync(join(home, ".pochi"));
|
|
2380
|
-
}
|
|
2381
|
-
},
|
|
2382
|
-
promptscript: {
|
|
2383
|
-
name: "promptscript",
|
|
2384
|
-
displayName: "PromptScript",
|
|
2385
|
-
skillsDir: ".agents/skills",
|
|
2386
|
-
globalSkillsDir: void 0,
|
|
2387
|
-
showInUniversalPrompt: false,
|
|
2388
|
-
detectInstalled: async () => {
|
|
2389
|
-
return existsSync(join(process.cwd(), ".promptscript")) || existsSync(join(process.cwd(), "promptscript.yaml"));
|
|
2390
|
-
}
|
|
2391
|
-
},
|
|
2392
|
-
adal: {
|
|
2393
|
-
name: "adal",
|
|
2394
|
-
displayName: "AdaL",
|
|
2395
|
-
skillsDir: ".adal/skills",
|
|
2396
|
-
globalSkillsDir: join(home, ".adal/skills"),
|
|
2397
|
-
detectInstalled: async () => {
|
|
2398
|
-
return existsSync(join(home, ".adal"));
|
|
2399
|
-
}
|
|
2400
|
-
},
|
|
2401
|
-
universal: {
|
|
2402
|
-
name: "universal",
|
|
2403
|
-
displayName: "共享目录",
|
|
2404
|
-
skillsDir: ".agents/skills",
|
|
2405
|
-
globalSkillsDir: join(configHome, "agents/skills"),
|
|
2406
|
-
showInUniversalList: false,
|
|
2407
|
-
detectInstalled: async () => false
|
|
2408
|
-
}
|
|
2409
|
-
};
|
|
2410
|
-
function setAgents(next) {
|
|
2411
|
-
for (const key of Object.keys(agents)) delete agents[key];
|
|
2412
|
-
Object.assign(agents, next);
|
|
2413
|
-
}
|
|
2414
|
-
async function detectInstalledAgents() {
|
|
2415
|
-
return (await Promise.all(Object.entries(agents).map(async ([type, config]) => ({
|
|
2416
|
-
type,
|
|
2417
|
-
installed: await config.detectInstalled()
|
|
2418
|
-
})))).filter((r) => r.installed).map((r) => r.type);
|
|
2419
|
-
}
|
|
2420
|
-
const EVE_SUBAGENTS_DIR = join("agent", "subagents");
|
|
2421
|
-
function getEveSubagents(cwd = process.cwd()) {
|
|
2422
|
-
const dir = join(cwd, EVE_SUBAGENTS_DIR);
|
|
2423
|
-
if (!existsSync(dir)) return [];
|
|
2424
|
-
try {
|
|
2425
|
-
return readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
1210
|
+
GIT_TERMINAL_PROMPT: "0"
|
|
1211
|
+
}
|
|
1212
|
+
});
|
|
1213
|
+
const statusOutput = `${stdout}${stderr}`;
|
|
1214
|
+
if (/Git operations protocol:\s+ssh/i.test(statusOutput)) cloneTarget = repo.sshUrl;
|
|
2426
1215
|
} catch {
|
|
2427
|
-
return
|
|
1216
|
+
return false;
|
|
2428
1217
|
}
|
|
1218
|
+
await execFileAsync("gh", [
|
|
1219
|
+
"repo",
|
|
1220
|
+
"clone",
|
|
1221
|
+
cloneTarget,
|
|
1222
|
+
tempDir,
|
|
1223
|
+
"--",
|
|
1224
|
+
...ref ? [
|
|
1225
|
+
"--depth=1",
|
|
1226
|
+
"--branch",
|
|
1227
|
+
ref
|
|
1228
|
+
] : ["--depth=1"]
|
|
1229
|
+
], {
|
|
1230
|
+
timeout: CLONE_TIMEOUT_MS,
|
|
1231
|
+
env: {
|
|
1232
|
+
...process.env,
|
|
1233
|
+
GIT_TERMINAL_PROMPT: "0"
|
|
1234
|
+
}
|
|
1235
|
+
});
|
|
1236
|
+
return true;
|
|
2429
1237
|
}
|
|
2430
|
-
function
|
|
2431
|
-
|
|
2432
|
-
}
|
|
2433
|
-
|
|
2434
|
-
return Object.entries(agents).filter(([_, config]) => config.skillsDir === ".agents/skills" && config.showInUniversalList !== false && config.showInUniversalPrompt !== false).map(([type]) => type);
|
|
1238
|
+
function buildGitHubAuthError(url, repo, message) {
|
|
1239
|
+
if (repo && isGitHubSsoAuthError(message)) return `GitHub 阻止了 ${url} 的 HTTPS 访问,因为组织强制使用 SAML SSO。\n skills 已尝试您现有的 git 凭据和可用回退方案,但均未成功。\n - 重新授权您的 GitHub 凭据/应用以符合该组织的 SSO 策略\n - 或使用 SSH 重新运行:npx skills add ${repo.sshUrl}\n - 验证访问权限:gh auth status -h github.com 或 ssh -T git@github.com`;
|
|
1240
|
+
if (repo) return `身份验证失败:${url}。\n - 私有仓库请确保您有访问权限\n - 使用 SSH 重试:npx skills add ${repo.sshUrl}\n - 检查访问权限:gh auth status -h github.com 或 ssh -T git@github.com`;
|
|
1241
|
+
return `身份验证失败:${url}。\n - 私有仓库请确保您有访问权限\n - SSH:使用 'ssh -T git@github.com' 检查您的密钥\n - HTTPS:运行 'gh auth login' 或配置 git 凭据`;
|
|
2435
1242
|
}
|
|
2436
|
-
function
|
|
2437
|
-
|
|
1243
|
+
async function cloneRepo(url, ref) {
|
|
1244
|
+
if (/^ext::/i.test(url)) throw new GitCloneError("不支持的 Git 传输协议:ext", url);
|
|
1245
|
+
const tempDir = await mkdtemp(join(tmpdir(), "skills-"));
|
|
1246
|
+
const cloneOptions = ref ? [
|
|
1247
|
+
"--depth",
|
|
1248
|
+
"1",
|
|
1249
|
+
"--branch",
|
|
1250
|
+
ref
|
|
1251
|
+
] : ["--depth", "1"];
|
|
1252
|
+
const repo = parseGitHubRepoUrl(url);
|
|
1253
|
+
try {
|
|
1254
|
+
await createGitClient().clone(url, tempDir, cloneOptions);
|
|
1255
|
+
return tempDir;
|
|
1256
|
+
} catch (error) {
|
|
1257
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1258
|
+
const isTimeout = errorMessage.includes("block timeout") || errorMessage.includes("timed out");
|
|
1259
|
+
const isAuthError = isAuthFailure(errorMessage);
|
|
1260
|
+
if (isTimeout) {
|
|
1261
|
+
await rm(tempDir, {
|
|
1262
|
+
recursive: true,
|
|
1263
|
+
force: true
|
|
1264
|
+
}).catch(() => {});
|
|
1265
|
+
throw new GitCloneError(`克隆超时(${Math.round(CLONE_TIMEOUT_MS / 1e3)} 秒)。常见原因:\n - 仓库过大:使用 SKILLS_CLONE_TIMEOUT_MS=600000 (10 分钟) 提高超时时间\n - 网络较慢:重试,或手动克隆后将本地路径传给 'skills add'\n - 私有仓库未配置凭据:请确保身份验证已配置\n - SSH:ssh-add -l(检查已加载的密钥)\n - HTTPS:gh auth status(如果使用 GitHub CLI)`, url, true, false);
|
|
1266
|
+
}
|
|
1267
|
+
if (isAuthError && repo && isGitHubHttpsCloneUrl(url)) {
|
|
1268
|
+
try {
|
|
1269
|
+
await resetTempDir(tempDir);
|
|
1270
|
+
if (await tryGhClone(repo, tempDir, ref)) return tempDir;
|
|
1271
|
+
} catch {}
|
|
1272
|
+
try {
|
|
1273
|
+
await resetTempDir(tempDir);
|
|
1274
|
+
await createGitClient({ GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND ?? "ssh -o BatchMode=yes" }).clone(repo.sshUrl, tempDir, cloneOptions);
|
|
1275
|
+
return tempDir;
|
|
1276
|
+
} catch {}
|
|
1277
|
+
}
|
|
1278
|
+
await rm(tempDir, {
|
|
1279
|
+
recursive: true,
|
|
1280
|
+
force: true
|
|
1281
|
+
}).catch(() => {});
|
|
1282
|
+
if (isAuthError) throw new GitCloneError(buildGitHubAuthError(url, repo, errorMessage), url, false, true);
|
|
1283
|
+
throw new GitCloneError(`克隆失败 ${url}:${errorMessage}`, url, false, false);
|
|
1284
|
+
}
|
|
2438
1285
|
}
|
|
2439
|
-
function
|
|
2440
|
-
|
|
1286
|
+
async function cleanupTempDir(dir) {
|
|
1287
|
+
const normalizedDir = normalize(resolve(dir));
|
|
1288
|
+
const normalizedTmpDir = normalize(resolve(tmpdir()));
|
|
1289
|
+
if (!normalizedDir.startsWith(normalizedTmpDir + sep) && normalizedDir !== normalizedTmpDir) throw new Error("Attempted to clean up directory outside of temp directory");
|
|
1290
|
+
await rm(dir, {
|
|
1291
|
+
recursive: true,
|
|
1292
|
+
force: true
|
|
1293
|
+
});
|
|
2441
1294
|
}
|
|
2442
1295
|
const AGENTS_DIR = ".agents";
|
|
2443
1296
|
const SKILLS_SUBDIR = "skills";
|
|
@@ -3931,6 +2784,14 @@ async function tryBlobInstall(ownerRepo, options = {}) {
|
|
|
3931
2784
|
tree
|
|
3932
2785
|
};
|
|
3933
2786
|
}
|
|
2787
|
+
var add_exports = /* @__PURE__ */ __exportAll({
|
|
2788
|
+
formatEveInstallPromptMessage: () => formatEveInstallPromptMessage,
|
|
2789
|
+
getLockSource: () => getLockSource,
|
|
2790
|
+
getProjectLockSourceUrl: () => getProjectLockSourceUrl,
|
|
2791
|
+
parseAddOptions: () => parseAddOptions,
|
|
2792
|
+
promptForAgents: () => promptForAgents,
|
|
2793
|
+
runAdd: () => runAdd
|
|
2794
|
+
});
|
|
3934
2795
|
const isCancelled = (value) => typeof value === "symbol";
|
|
3935
2796
|
const EVE_AGENT_LABEL = "eve agent";
|
|
3936
2797
|
async function isSourcePrivate(source) {
|
|
@@ -4456,7 +3317,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
4456
3317
|
}
|
|
4457
3318
|
console.log();
|
|
4458
3319
|
outro(import_picocolors.default.green("完成!") + import_picocolors.default.dim(" 使用前请审阅技能;技能以 Agent 的全部权限运行。"));
|
|
4459
|
-
await
|
|
3320
|
+
await promptForBfiSkill(options, targetAgents);
|
|
4460
3321
|
}
|
|
4461
3322
|
async function cloneWithGitHubFallback(url, ref, spinner) {
|
|
4462
3323
|
try {
|
|
@@ -4546,7 +3407,7 @@ async function installFromSkillHub(parsed, options, spinner) {
|
|
|
4546
3407
|
}
|
|
4547
3408
|
const meta = metadata;
|
|
4548
3409
|
spinner.stop(`Skill: ${import_picocolors.default.cyan(`@${namespace}/${slug}`)}${meta.description ? ` — ${import_picocolors.default.dim(meta.description)}` : ""}`);
|
|
4549
|
-
tempDir = join(tmpdir(), `.
|
|
3410
|
+
tempDir = join(tmpdir(), `.skillhub-skillshub-${canonicalSlug.replace(/[/:@]/g, "-")}-${Date.now()}`);
|
|
4550
3411
|
mkdirSync(tempDir, { recursive: true });
|
|
4551
3412
|
const zipPath = join(tempDir, "skill.zip");
|
|
4552
3413
|
spinner.start("正在下载技能...");
|
|
@@ -4704,7 +3565,7 @@ async function runAdd(args, options = {}) {
|
|
|
4704
3565
|
skills = blobResult.skills;
|
|
4705
3566
|
spinner$2.stop(`Found ${import_picocolors.default.green(skills.length)} skill${skills.length > 1 ? "s" : ""}`);
|
|
4706
3567
|
} else {
|
|
4707
|
-
tempDir = await cloneWithGitHubFallback(parsed.url, parsed.ref, spinner$2);
|
|
3568
|
+
tempDir = await cloneWithGitHubFallback(parsed.url, options.branch || parsed.ref, spinner$2);
|
|
4708
3569
|
spinner$2.stop("仓库克隆完成");
|
|
4709
3570
|
spinner$2.start("正在发现技能...");
|
|
4710
3571
|
skills = await discoverSkills(tempDir, parsed.subpath, {
|
|
@@ -4713,7 +3574,7 @@ async function runAdd(args, options = {}) {
|
|
|
4713
3574
|
});
|
|
4714
3575
|
}
|
|
4715
3576
|
} else {
|
|
4716
|
-
tempDir = await cloneWithGitHubFallback(parsed.url, parsed.ref, spinner$2);
|
|
3577
|
+
tempDir = await cloneWithGitHubFallback(parsed.url, options.branch || parsed.ref, spinner$2);
|
|
4717
3578
|
spinner$2.stop("仓库克隆完成");
|
|
4718
3579
|
spinner$2.start("正在发现技能...");
|
|
4719
3580
|
skills = await discoverSkills(tempDir, parsed.subpath, {
|
|
@@ -5213,7 +4074,7 @@ async function runAdd(args, options = {}) {
|
|
|
5213
4074
|
}
|
|
5214
4075
|
console.log();
|
|
5215
4076
|
outro(import_picocolors.default.green("完成!") + import_picocolors.default.dim(" Review skills before use; they run with full agent permissions."));
|
|
5216
|
-
await
|
|
4077
|
+
await promptForBfiSkill(options, targetAgents);
|
|
5217
4078
|
} catch (error) {
|
|
5218
4079
|
if (error instanceof GitCloneError) {
|
|
5219
4080
|
log.error(import_picocolors.default.red("克隆仓库失败"));
|
|
@@ -5231,42 +4092,41 @@ async function cleanup(tempDir) {
|
|
|
5231
4092
|
await cleanupTempDir(tempDir);
|
|
5232
4093
|
} catch {}
|
|
5233
4094
|
}
|
|
5234
|
-
async function
|
|
4095
|
+
async function promptForBfiSkill(options, targetAgents) {
|
|
5235
4096
|
if (!process.stdin.isTTY) return;
|
|
5236
4097
|
if (options?.yes) return;
|
|
5237
4098
|
try {
|
|
5238
|
-
if (await isPromptDismissed("
|
|
5239
|
-
if (await isSkillInstalled("
|
|
5240
|
-
await dismissPrompt("
|
|
4099
|
+
if (await isPromptDismissed("bfiSkillPrompt")) return;
|
|
4100
|
+
if (await isSkillInstalled("skillhub-skills", "claude-code", { global: true })) {
|
|
4101
|
+
await dismissPrompt("bfiSkillPrompt");
|
|
5241
4102
|
return;
|
|
5242
4103
|
}
|
|
5243
4104
|
console.log();
|
|
5244
4105
|
log.message(import_picocolors.default.dim("一次性提示 - 关闭后将不再询问。"));
|
|
5245
|
-
const install = await confirm({ message:
|
|
4106
|
+
const install = await confirm({ message: `安装 ${import_picocolors.default.cyan("skillhub-skills")} 技能?它能帮助 AI Agent 自动发现和使用 bfi CLI 的全部功能。` });
|
|
5246
4107
|
if (isCancel(install)) {
|
|
5247
|
-
await dismissPrompt("
|
|
4108
|
+
await dismissPrompt("bfiSkillPrompt");
|
|
5248
4109
|
return;
|
|
5249
4110
|
}
|
|
5250
4111
|
if (install) {
|
|
5251
|
-
await dismissPrompt("
|
|
5252
|
-
const
|
|
5253
|
-
if (!
|
|
4112
|
+
await dismissPrompt("bfiSkillPrompt");
|
|
4113
|
+
const bfiSkillAgents = targetAgents?.filter((a) => a !== "replit");
|
|
4114
|
+
if (!bfiSkillAgents || bfiSkillAgents.length === 0) return;
|
|
5254
4115
|
console.log();
|
|
5255
|
-
log.step("正在安装
|
|
4116
|
+
log.step("正在安装 skillhub-skills 技能...");
|
|
5256
4117
|
try {
|
|
5257
|
-
await runAdd(["
|
|
5258
|
-
skill: ["find-skills"],
|
|
4118
|
+
await runAdd(["@global/skillhub-skills"], {
|
|
5259
4119
|
global: true,
|
|
5260
4120
|
yes: true,
|
|
5261
|
-
agent:
|
|
4121
|
+
agent: bfiSkillAgents
|
|
5262
4122
|
});
|
|
5263
4123
|
} catch {
|
|
5264
|
-
log.warn("安装
|
|
5265
|
-
log.message(import_picocolors.default.dim("
|
|
4124
|
+
log.warn("安装 skillhub-skills 失败。你可以稍后重试:");
|
|
4125
|
+
log.message(import_picocolors.default.dim(" bfi skills add @global/skillhub-skills -g -y"));
|
|
5266
4126
|
}
|
|
5267
4127
|
} else {
|
|
5268
|
-
await dismissPrompt("
|
|
5269
|
-
log.message(import_picocolors.default.dim("你可以稍后通过以下命令安装:
|
|
4128
|
+
await dismissPrompt("bfiSkillPrompt");
|
|
4129
|
+
log.message(import_picocolors.default.dim("你可以稍后通过以下命令安装:bfi skills add @global/skillhub-skills -g -y"));
|
|
5270
4130
|
}
|
|
5271
4131
|
} catch {}
|
|
5272
4132
|
}
|
|
@@ -5311,7 +4171,10 @@ function parseAddOptions(args) {
|
|
|
5311
4171
|
}
|
|
5312
4172
|
} else if (arg === "--full-depth") options.fullDepth = true;
|
|
5313
4173
|
else if (arg === "--copy") options.copy = true;
|
|
5314
|
-
else if (arg === "--
|
|
4174
|
+
else if (arg === "--branch") {
|
|
4175
|
+
i++;
|
|
4176
|
+
if (args[i] && !args[i].startsWith("-")) options.branch = args[i];
|
|
4177
|
+
} else if (arg === "--subagent") {
|
|
5315
4178
|
options.subagent = options.subagent || [];
|
|
5316
4179
|
i++;
|
|
5317
4180
|
let nextArg = args[i];
|
|
@@ -5332,7 +4195,7 @@ function parseAddOptions(args) {
|
|
|
5332
4195
|
const RESET$11 = "\x1B[0m";
|
|
5333
4196
|
const BOLD$8 = "\x1B[1m";
|
|
5334
4197
|
const DIM$11 = "\x1B[38;5;102m";
|
|
5335
|
-
const TEXT$
|
|
4198
|
+
const TEXT$8 = "\x1B[38;5;145m";
|
|
5336
4199
|
const CYAN$2 = "\x1B[36m";
|
|
5337
4200
|
const SEARCH_API_BASE = process.env.SKILLS_API_URL || "https://skills.sh";
|
|
5338
4201
|
function formatInstalls$1(count) {
|
|
@@ -5422,7 +4285,7 @@ async function runSearchPrompt(initialQuery = "", owner) {
|
|
|
5422
4285
|
process.stdout.write(CLEAR_DOWN);
|
|
5423
4286
|
const lines = [];
|
|
5424
4287
|
const cursor = `${BOLD$8}_${RESET$11}`;
|
|
5425
|
-
lines.push(`${TEXT$
|
|
4288
|
+
lines.push(`${TEXT$8}搜索技能:${RESET$11} ${query}${cursor}`);
|
|
5426
4289
|
lines.push("");
|
|
5427
4290
|
if (!query || query.length < 2) lines.push(`${DIM$11}输入关键词搜索(最少 2 个字符)${RESET$11}`);
|
|
5428
4291
|
else if (results.length === 0 && loading) lines.push(`${DIM$11}搜索中...${RESET$11}`);
|
|
@@ -5433,7 +4296,7 @@ async function runSearchPrompt(initialQuery = "", owner) {
|
|
|
5433
4296
|
const skill = visible[i];
|
|
5434
4297
|
const isSelected = i === selectedIndex;
|
|
5435
4298
|
const arrow = isSelected ? `${BOLD$8}>${RESET$11}` : " ";
|
|
5436
|
-
const name = isSelected ? `${BOLD$8}${skill.name}${RESET$11}` : `${TEXT$
|
|
4299
|
+
const name = isSelected ? `${BOLD$8}${skill.name}${RESET$11}` : `${TEXT$8}${skill.name}${RESET$11}`;
|
|
5437
4300
|
const source = skill.source ? ` ${DIM$11}${skill.source}${RESET$11}` : "";
|
|
5438
4301
|
const installs = formatInstalls$1(skill.installs);
|
|
5439
4302
|
const installsBadge = installs ? ` ${CYAN$2}${installs}${RESET$11}` : "";
|
|
@@ -5560,7 +4423,7 @@ ${DIM$11} 2) npx skills add <owner/repo@skill>${RESET$11}`;
|
|
|
5560
4423
|
for (const skill of results.slice(0, 6)) {
|
|
5561
4424
|
const pkg = skill.source || skill.slug;
|
|
5562
4425
|
const installs = formatInstalls$1(skill.installs);
|
|
5563
|
-
console.log(`${TEXT$
|
|
4426
|
+
console.log(`${TEXT$8}${pkg}@${skill.name}${RESET$11}${installs ? ` ${CYAN$2}${installs}${RESET$11}` : ""}`);
|
|
5564
4427
|
console.log(`${DIM$11}└ https://skills.sh/${skill.slug}${RESET$11}`);
|
|
5565
4428
|
console.log();
|
|
5566
4429
|
}
|
|
@@ -5581,7 +4444,7 @@ ${DIM$11} 2) npx skills add <owner/repo@skill>${RESET$11}`;
|
|
|
5581
4444
|
const pkg = selected.source || selected.slug;
|
|
5582
4445
|
const skillName = selected.name;
|
|
5583
4446
|
console.log();
|
|
5584
|
-
console.log(`${TEXT$
|
|
4447
|
+
console.log(`${TEXT$8}正在从 ${DIM$11}${pkg}${RESET$11} 安装 ${BOLD$8}${skillName}${RESET$11}...`);
|
|
5585
4448
|
console.log();
|
|
5586
4449
|
const { source, options: addOptions } = parseAddOptions([
|
|
5587
4450
|
pkg,
|
|
@@ -5591,15 +4454,15 @@ ${DIM$11} 2) npx skills add <owner/repo@skill>${RESET$11}`;
|
|
|
5591
4454
|
await runAdd(source, addOptions);
|
|
5592
4455
|
console.log();
|
|
5593
4456
|
const info = getOwnerRepoFromString(pkg);
|
|
5594
|
-
if (info && await isRepoPublic(info.owner, info.repo)) console.log(`${DIM$11}查看技能:${RESET$11} ${TEXT$
|
|
5595
|
-
else console.log(`${DIM$11}发现更多技能:${RESET$11} ${TEXT$
|
|
4457
|
+
if (info && await isRepoPublic(info.owner, info.repo)) console.log(`${DIM$11}查看技能:${RESET$11} ${TEXT$8}https://skills.sh/${selected.slug}${RESET$11}`);
|
|
4458
|
+
else console.log(`${DIM$11}发现更多技能:${RESET$11} ${TEXT$8}https://skills.sh${RESET$11}`);
|
|
5596
4459
|
console.log();
|
|
5597
4460
|
}
|
|
5598
4461
|
const RESET$10 = "\x1B[0m";
|
|
5599
4462
|
const BOLD$7 = "\x1B[1m";
|
|
5600
4463
|
const DIM$10 = "\x1B[38;5;102m";
|
|
5601
4464
|
const CYAN$1 = "\x1B[36m";
|
|
5602
|
-
const YELLOW$
|
|
4465
|
+
const YELLOW$4 = "\x1B[33m";
|
|
5603
4466
|
function shortenPath(fullPath, cwd) {
|
|
5604
4467
|
const home = homedir();
|
|
5605
4468
|
if (fullPath.startsWith(home)) return fullPath.replace(home, "~");
|
|
@@ -5633,7 +4496,7 @@ async function runList(args) {
|
|
|
5633
4496
|
const validAgents = Object.keys(agents);
|
|
5634
4497
|
const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
|
|
5635
4498
|
if (invalidAgents.length > 0) {
|
|
5636
|
-
console.log(`${YELLOW$
|
|
4499
|
+
console.log(`${YELLOW$4}Invalid agents: ${invalidAgents.join(", ")}${RESET$10}`);
|
|
5637
4500
|
console.log(`${DIM$10}Valid agents: ${validAgents.join(", ")}${RESET$10}`);
|
|
5638
4501
|
process.exit(1);
|
|
5639
4502
|
}
|
|
@@ -5670,7 +4533,7 @@ async function runList(args) {
|
|
|
5670
4533
|
const prefix = indent ? " " : "";
|
|
5671
4534
|
const shortPath = shortenPath(skill.canonicalPath, cwd);
|
|
5672
4535
|
const agentNames = skill.agents.map((a) => agents[a].displayName);
|
|
5673
|
-
const agentInfo = skill.agents.length > 0 ? formatList(agentNames) : `${YELLOW$
|
|
4536
|
+
const agentInfo = skill.agents.length > 0 ? formatList(agentNames) : `${YELLOW$4}not linked${RESET$10}`;
|
|
5674
4537
|
const paddedName = sanitizeMetadata(skill.name).padEnd(maxNameLength);
|
|
5675
4538
|
const paddedPath = shortPath.padEnd(maxPathLength);
|
|
5676
4539
|
console.log(`${prefix}${CYAN$1}${paddedName}${RESET$10} ${DIM$10}${paddedPath}${RESET$10} ${DIM$10}Agents:${RESET$10} ${agentInfo}`);
|
|
@@ -5732,6 +4595,10 @@ async function runList(args) {
|
|
|
5732
4595
|
console.log();
|
|
5733
4596
|
}
|
|
5734
4597
|
}
|
|
4598
|
+
var remove_exports = /* @__PURE__ */ __exportAll({
|
|
4599
|
+
parseRemoveOptions: () => parseRemoveOptions,
|
|
4600
|
+
removeCommand: () => removeCommand
|
|
4601
|
+
});
|
|
5735
4602
|
async function removeCommand(skillNames, options) {
|
|
5736
4603
|
const agentResult = await detectAgent();
|
|
5737
4604
|
if (agentResult.isAgent) {
|
|
@@ -5980,7 +4847,7 @@ const __dirname$1 = dirname(fileURLToPath(import.meta.url));
|
|
|
5980
4847
|
const RESET$9 = "\x1B[0m";
|
|
5981
4848
|
const BOLD$6 = "\x1B[1m";
|
|
5982
4849
|
const DIM$9 = "\x1B[38;5;102m";
|
|
5983
|
-
const TEXT$
|
|
4850
|
+
const TEXT$7 = "\x1B[38;5;145m";
|
|
5984
4851
|
function parseUpdateOptions(args) {
|
|
5985
4852
|
const options = {};
|
|
5986
4853
|
const positional = [];
|
|
@@ -6074,13 +4941,13 @@ function printSkippedSkills(skipped) {
|
|
|
6074
4941
|
for (const [source, skills] of grouped) {
|
|
6075
4942
|
if (skills.length === 1) {
|
|
6076
4943
|
const skill = skills[0];
|
|
6077
|
-
console.log(` ${TEXT$
|
|
4944
|
+
console.log(` ${TEXT$7}•${RESET$9} ${sanitizeMetadata(skill.name)} ${DIM$9}(${skill.reason})${RESET$9}`);
|
|
6078
4945
|
} else {
|
|
6079
4946
|
const reason = skills[0].reason;
|
|
6080
4947
|
const names = skills.map((s) => sanitizeMetadata(s.name)).join(", ");
|
|
6081
|
-
console.log(` ${TEXT$
|
|
4948
|
+
console.log(` ${TEXT$7}•${RESET$9} ${names} ${DIM$9}(${reason})${RESET$9}`);
|
|
6082
4949
|
}
|
|
6083
|
-
console.log(` ${DIM$9}更新方法:${TEXT$
|
|
4950
|
+
console.log(` ${DIM$9}更新方法:${TEXT$7}npx skills add ${source} -g -y${RESET$9}`);
|
|
6084
4951
|
}
|
|
6085
4952
|
}
|
|
6086
4953
|
async function getProjectSkillsForUpdate(skillFilter) {
|
|
@@ -6129,7 +4996,7 @@ async function updateGlobalSkills(options = {}) {
|
|
|
6129
4996
|
if (skillNames.length === 0) {
|
|
6130
4997
|
if (!options.skills) {
|
|
6131
4998
|
console.log(`${DIM$9}锁文件中没有跟踪的全局技能。${RESET$9}`);
|
|
6132
|
-
console.log(`${DIM$9}安装技能:${RESET$9} ${TEXT$
|
|
4999
|
+
console.log(`${DIM$9}安装技能:${RESET$9} ${TEXT$7}npx skills add <package> -g${RESET$9}`);
|
|
6133
5000
|
}
|
|
6134
5001
|
return {
|
|
6135
5002
|
successCount,
|
|
@@ -6171,6 +5038,10 @@ async function updateGlobalSkills(options = {}) {
|
|
|
6171
5038
|
const sourceUrl = firstEntry.sourceUrl || firstEntry.source;
|
|
6172
5039
|
let tempDir = null;
|
|
6173
5040
|
process.stdout.write(`\r${DIM$9}Checking skills from source: ${source}${RESET$9}\x1b[K\n`);
|
|
5041
|
+
if (firstEntry.sourceType === "skillhub") {
|
|
5042
|
+
console.log(` ${DIM$9}SkillHub 技能请使用 bfi skills add 重新安装来更新${RESET$9}`);
|
|
5043
|
+
continue;
|
|
5044
|
+
}
|
|
6174
5045
|
try {
|
|
6175
5046
|
if (firstEntry.sourceType === "github") {
|
|
6176
5047
|
const tree = await fetchRepoTree(source, firstEntry.ref, getGitHubToken);
|
|
@@ -6234,18 +5105,18 @@ async function updateGlobalSkills(options = {}) {
|
|
|
6234
5105
|
};
|
|
6235
5106
|
}
|
|
6236
5107
|
if (updates.length === 0) {
|
|
6237
|
-
console.log(`${TEXT$
|
|
5108
|
+
console.log(`${TEXT$7}✓ 所有全局技能已是最新${RESET$9}`);
|
|
6238
5109
|
return {
|
|
6239
5110
|
successCount,
|
|
6240
5111
|
failCount,
|
|
6241
5112
|
checkedCount
|
|
6242
5113
|
};
|
|
6243
5114
|
}
|
|
6244
|
-
console.log(`${TEXT$
|
|
5115
|
+
console.log(`${TEXT$7}发现 ${updates.length} 个可更新全局技能${RESET$9}`);
|
|
6245
5116
|
console.log();
|
|
6246
5117
|
for (const update of updates) {
|
|
6247
5118
|
const safeName = sanitizeMetadata(update.name);
|
|
6248
|
-
console.log(`${TEXT$
|
|
5119
|
+
console.log(`${TEXT$7}正在更新 ${safeName}...${RESET$9}`);
|
|
6249
5120
|
const installUrl = buildUpdateInstallSource(update.entry);
|
|
6250
5121
|
if (!installUrl) {
|
|
6251
5122
|
failCount++;
|
|
@@ -6274,7 +5145,7 @@ async function updateGlobalSkills(options = {}) {
|
|
|
6274
5145
|
shell: false
|
|
6275
5146
|
}).status === 0) {
|
|
6276
5147
|
successCount++;
|
|
6277
|
-
console.log(` ${TEXT$
|
|
5148
|
+
console.log(` ${TEXT$7}✓${RESET$9} 已更新 ${safeName}`);
|
|
6278
5149
|
} else {
|
|
6279
5150
|
failCount++;
|
|
6280
5151
|
console.log(` ${DIM$9}✗ 更新 ${safeName} 失败${RESET$9}`);
|
|
@@ -6294,7 +5165,7 @@ async function updateProjectSkills(options = {}) {
|
|
|
6294
5165
|
if (projectSkills.length === 0) {
|
|
6295
5166
|
if (!options.skills) {
|
|
6296
5167
|
console.log(`${DIM$9}没有可更新的项目技能。${RESET$9}`);
|
|
6297
|
-
console.log(`${DIM$9}Install project skills with${RESET$9} ${TEXT$
|
|
5168
|
+
console.log(`${DIM$9}Install project skills with${RESET$9} ${TEXT$7}npx skills add <package>${RESET$9}`);
|
|
6298
5169
|
}
|
|
6299
5170
|
return {
|
|
6300
5171
|
successCount,
|
|
@@ -6325,8 +5196,8 @@ async function updateProjectSkills(options = {}) {
|
|
|
6325
5196
|
const targetParts = [];
|
|
6326
5197
|
if (hasUniversal) targetParts.push("Universal");
|
|
6327
5198
|
targetParts.push(...targetAgentNames);
|
|
6328
|
-
if (targetParts.length > 0) console.log(`${TEXT$
|
|
6329
|
-
console.log(`${TEXT$
|
|
5199
|
+
if (targetParts.length > 0) console.log(`${TEXT$7}更新目标:${targetParts.join(", ")}${RESET$9}`);
|
|
5200
|
+
console.log(`${TEXT$7}正在刷新 ${updatable.length} 个技能...${RESET$9}`);
|
|
6330
5201
|
console.log();
|
|
6331
5202
|
const bySource = /* @__PURE__ */ new Map();
|
|
6332
5203
|
for (const skill of updatable) {
|
|
@@ -6371,7 +5242,7 @@ async function updateProjectSkills(options = {}) {
|
|
|
6371
5242
|
const remainingSkills = skillsForSource.filter((s) => !deletedSkills.includes(s.name));
|
|
6372
5243
|
for (const skill of remainingSkills) {
|
|
6373
5244
|
const safeName = sanitizeMetadata(skill.name);
|
|
6374
|
-
console.log(`${TEXT$
|
|
5245
|
+
console.log(`${TEXT$7}正在更新 ${safeName}...${RESET$9}`);
|
|
6375
5246
|
const installUrl = buildLocalUpdateSource(skill.entry);
|
|
6376
5247
|
if (!installUrl) {
|
|
6377
5248
|
failCount++;
|
|
@@ -6397,7 +5268,7 @@ async function updateProjectSkills(options = {}) {
|
|
|
6397
5268
|
shell: false
|
|
6398
5269
|
}).status === 0) {
|
|
6399
5270
|
successCount++;
|
|
6400
|
-
console.log(` ${TEXT$
|
|
5271
|
+
console.log(` ${TEXT$7}✓${RESET$9} 已更新 ${safeName}`);
|
|
6401
5272
|
} else {
|
|
6402
5273
|
failCount++;
|
|
6403
5274
|
console.log(` ${DIM$9}✗ 更新 ${safeName} 失败${RESET$9}`);
|
|
@@ -6417,16 +5288,16 @@ function printLegacyProjectSkills(legacy) {
|
|
|
6417
5288
|
console.log(`${DIM$9}${legacy.length} project skill(s) cannot be updated automatically (installed before skillPath tracking):${RESET$9}`);
|
|
6418
5289
|
for (const skill of legacy) {
|
|
6419
5290
|
const reinstall = buildLocalUpdateSource(skill.entry);
|
|
6420
|
-
console.log(` ${TEXT$
|
|
6421
|
-
if (reinstall) console.log(` ${DIM$9}刷新方法:${TEXT$
|
|
5291
|
+
console.log(` ${TEXT$7}•${RESET$9} ${sanitizeMetadata(skill.name)}`);
|
|
5292
|
+
if (reinstall) console.log(` ${DIM$9}刷新方法:${TEXT$7}npx skills add ${reinstall} -y${RESET$9}`);
|
|
6422
5293
|
else console.log(` ${DIM$9}To refresh: reinstall using the original full Git URL; this lock entry only has an ambiguous shorthand.${RESET$9}`);
|
|
6423
5294
|
}
|
|
6424
5295
|
}
|
|
6425
5296
|
async function runUpdate(args = []) {
|
|
6426
5297
|
const options = parseUpdateOptions(args);
|
|
6427
5298
|
const scope = await resolveUpdateScope(options);
|
|
6428
|
-
if (options.skills) console.log(`${TEXT$
|
|
6429
|
-
else console.log(`${TEXT$
|
|
5299
|
+
if (options.skills) console.log(`${TEXT$7}正在更新 ${options.skills.join(", ")}...${RESET$9}`);
|
|
5300
|
+
else console.log(`${TEXT$7}正在检查技能更新...${RESET$9}`);
|
|
6430
5301
|
console.log();
|
|
6431
5302
|
let totalSuccess = 0;
|
|
6432
5303
|
let totalFail = 0;
|
|
@@ -6448,7 +5319,7 @@ async function runUpdate(args = []) {
|
|
|
6448
5319
|
}
|
|
6449
5320
|
if (options.skills && totalFound === 0) console.log(`${DIM$9}未找到匹配的已安装技能:${options.skills.join(", ")}${RESET$9}`);
|
|
6450
5321
|
console.log();
|
|
6451
|
-
if (totalSuccess > 0) console.log(`${TEXT$
|
|
5322
|
+
if (totalSuccess > 0) console.log(`${TEXT$7}✓ 已更新 ${totalSuccess} 个技能${RESET$9}`);
|
|
6452
5323
|
if (totalFail > 0) {
|
|
6453
5324
|
console.log(`${DIM$9}更新失败 ${totalFail} 个技能${RESET$9}`);
|
|
6454
5325
|
process.exitCode = 1;
|
|
@@ -6905,7 +5776,7 @@ function getOptionValue$3(args, flag) {
|
|
|
6905
5776
|
const RESET$8 = "\x1B[0m";
|
|
6906
5777
|
const BOLD$5 = "\x1B[1m";
|
|
6907
5778
|
const DIM$8 = "\x1B[38;5;102m";
|
|
6908
|
-
const TEXT$
|
|
5779
|
+
const TEXT$6 = "\x1B[38;5;145m";
|
|
6909
5780
|
const CYAN = "\x1B[36m";
|
|
6910
5781
|
const MARKETPLACE_API = process.env.SKILLS_API_URL || "https://skills.sh";
|
|
6911
5782
|
async function runSearch(args, globalOpts) {
|
|
@@ -6941,8 +5812,8 @@ function parseSearchQuery(args) {
|
|
|
6941
5812
|
const parts = [];
|
|
6942
5813
|
for (let i = 0; i < args.length; i++) {
|
|
6943
5814
|
const arg = args[i];
|
|
6944
|
-
if (arg === "--namespace" || arg === "--marketplace" || arg === "--all") {
|
|
6945
|
-
if (arg
|
|
5815
|
+
if (arg === "--namespace" || arg === "--marketplace" || arg === "--all" || arg === "--registry" || arg === "--token" || arg === "--json" || arg === "--limit") {
|
|
5816
|
+
if (arg !== "--marketplace" && arg !== "--all" && arg !== "--json") i++;
|
|
6946
5817
|
continue;
|
|
6947
5818
|
}
|
|
6948
5819
|
if (arg.startsWith("--")) continue;
|
|
@@ -6995,9 +5866,9 @@ async function searchSkillHub(query, namespace, globalOpts, json = false) {
|
|
|
6995
5866
|
const displaySlug = canonicalSlug.indexOf("--") > 0 ? canonicalSlug : `global--${canonicalSlug}`;
|
|
6996
5867
|
console.log(` ${BOLD$5}${name}${RESET$8}`);
|
|
6997
5868
|
if (desc) console.log(` ${DIM$8}${truncate$2(desc, 100)}${RESET$8}`);
|
|
6998
|
-
console.log(` ${TEXT$
|
|
5869
|
+
console.log(` ${TEXT$6}slug: ${displaySlug}${RESET$8}`);
|
|
6999
5870
|
if (skill.version) console.log(` ${DIM$8}version: ${skill.version}${RESET$8}`);
|
|
7000
|
-
console.log(` ${DIM$8}安装:${TEXT$
|
|
5871
|
+
console.log(` ${DIM$8}安装:${TEXT$6}bfi skills add ${displaySlug}${RESET$8}`);
|
|
7001
5872
|
console.log();
|
|
7002
5873
|
}
|
|
7003
5874
|
} catch (error) {
|
|
@@ -7052,8 +5923,8 @@ async function searchMarketplace(query, json = false) {
|
|
|
7052
5923
|
console.log(` ${BOLD$5}${skill.name}${RESET$8}`);
|
|
7053
5924
|
if (skill.source) console.log(` ${DIM$8}来源:${skill.source}${RESET$8}`);
|
|
7054
5925
|
if (installs) console.log(` ${CYAN}${installs}${RESET$8}`);
|
|
7055
|
-
console.log(` ${TEXT$
|
|
7056
|
-
if (skill.source) console.log(` ${DIM$8}安装:${TEXT$
|
|
5926
|
+
console.log(` ${TEXT$6}https://skills.sh/${skill.id}${RESET$8}`);
|
|
5927
|
+
if (skill.source) console.log(` ${DIM$8}安装:${TEXT$6}bfi skills add github:${skill.source}${RESET$8}`);
|
|
7057
5928
|
console.log();
|
|
7058
5929
|
}
|
|
7059
5930
|
} catch {
|
|
@@ -7077,9 +5948,9 @@ function getOptionValue$2(args, flag) {
|
|
|
7077
5948
|
const RESET$7 = "\x1B[0m";
|
|
7078
5949
|
const BOLD$4 = "\x1B[1m";
|
|
7079
5950
|
const DIM$7 = "\x1B[38;5;102m";
|
|
7080
|
-
const TEXT$
|
|
7081
|
-
const YELLOW$
|
|
7082
|
-
const RED$
|
|
5951
|
+
const TEXT$5 = "\x1B[38;5;145m";
|
|
5952
|
+
const YELLOW$3 = "\x1B[33m";
|
|
5953
|
+
const RED$3 = "\x1B[31m";
|
|
7083
5954
|
const GREEN$4 = "\x1B[32m";
|
|
7084
5955
|
async function runInfo(args, globalOpts) {
|
|
7085
5956
|
const ref = args[0];
|
|
@@ -7102,29 +5973,29 @@ async function runInfo(args, globalOpts) {
|
|
|
7102
5973
|
console.log();
|
|
7103
5974
|
console.log(`${BOLD$4}${skill.displayName || skill.name || skill.slug}${RESET$7}`);
|
|
7104
5975
|
console.log(`${DIM$7}${"─".repeat(48)}${RESET$7}`);
|
|
7105
|
-
console.log(` ${BOLD$4}Slug:${RESET$7} ${TEXT$
|
|
7106
|
-
if (skill.summary || skill.description) console.log(` ${BOLD$4}描述:${RESET$7} ${TEXT$
|
|
5976
|
+
console.log(` ${BOLD$4}Slug:${RESET$7} ${TEXT$5}${skill.slug}${RESET$7}`);
|
|
5977
|
+
if (skill.summary || skill.description) console.log(` ${BOLD$4}描述:${RESET$7} ${TEXT$5}${skill.summary || skill.description}${RESET$7}`);
|
|
7107
5978
|
const owner = skill.owner;
|
|
7108
5979
|
if (owner) {
|
|
7109
|
-
console.log(` ${BOLD$4}所有者:${RESET$7} ${TEXT$
|
|
7110
|
-
if (owner.handle) console.log(` ${BOLD$4}句柄:${RESET$7} ${TEXT$
|
|
5980
|
+
console.log(` ${BOLD$4}所有者:${RESET$7} ${TEXT$5}${owner.displayName || owner.handle}${RESET$7}`);
|
|
5981
|
+
if (owner.handle) console.log(` ${BOLD$4}句柄:${RESET$7} ${TEXT$5}${owner.handle}${RESET$7}`);
|
|
7111
5982
|
}
|
|
7112
5983
|
const latestVersion = skill.latestVersion;
|
|
7113
5984
|
if (latestVersion) {
|
|
7114
|
-
console.log(` ${BOLD$4}版本:${RESET$7} ${TEXT$
|
|
7115
|
-
if (latestVersion.license) console.log(` ${BOLD$4}许可证:${RESET$7} ${TEXT$
|
|
5985
|
+
console.log(` ${BOLD$4}版本:${RESET$7} ${TEXT$5}${latestVersion.version || "N/A"}${RESET$7}`);
|
|
5986
|
+
if (latestVersion.license) console.log(` ${BOLD$4}许可证:${RESET$7} ${TEXT$5}${latestVersion.license}${RESET$7}`);
|
|
7116
5987
|
if (latestVersion.changelog) console.log(` ${BOLD$4}变更日志:${RESET$7} ${DIM$7}${truncate$1(latestVersion.changelog, 80)}${RESET$7}`);
|
|
7117
5988
|
if (latestVersion.createdAt) {
|
|
7118
5989
|
const date = new Date(latestVersion.createdAt).toISOString().split("T")[0];
|
|
7119
|
-
console.log(` ${BOLD$4}发布时间:${RESET$7} ${TEXT$
|
|
5990
|
+
console.log(` ${BOLD$4}发布时间:${RESET$7} ${TEXT$5}${date}${RESET$7}`);
|
|
7120
5991
|
}
|
|
7121
5992
|
}
|
|
7122
5993
|
const stats = skill.stats;
|
|
7123
5994
|
if (stats) {
|
|
7124
5995
|
console.log();
|
|
7125
5996
|
console.log(` ${BOLD$4}统计:${RESET$7}`);
|
|
7126
|
-
if (stats.downloads !== void 0) console.log(` 下载量:${TEXT$
|
|
7127
|
-
if (stats.views !== void 0) console.log(` 浏览量:${TEXT$
|
|
5997
|
+
if (stats.downloads !== void 0) console.log(` 下载量:${TEXT$5}${stats.downloads}${RESET$7}`);
|
|
5998
|
+
if (stats.views !== void 0) console.log(` 浏览量:${TEXT$5}${stats.views}${RESET$7}`);
|
|
7128
5999
|
}
|
|
7129
6000
|
const tags = skill.tags;
|
|
7130
6001
|
if (Array.isArray(tags) && tags.length > 0) {
|
|
@@ -7132,28 +6003,28 @@ async function runInfo(args, globalOpts) {
|
|
|
7132
6003
|
const tag = t;
|
|
7133
6004
|
return tag.name || tag;
|
|
7134
6005
|
}).join(", ");
|
|
7135
|
-
console.log(` ${BOLD$4}标签:${RESET$7} ${TEXT$
|
|
6006
|
+
console.log(` ${BOLD$4}标签:${RESET$7} ${TEXT$5}${tagList}${RESET$7}`);
|
|
7136
6007
|
}
|
|
7137
6008
|
const moderation = skill.moderation;
|
|
7138
6009
|
if (moderation) {
|
|
7139
6010
|
const verdict = moderation.verdict;
|
|
7140
6011
|
if (verdict === "MALWARE_BLOCKED" || moderation.isMalwareBlocked) {
|
|
7141
6012
|
console.log();
|
|
7142
|
-
console.log(` ${RED$
|
|
7143
|
-
if (moderation.summary) console.log(` ${RED$
|
|
6013
|
+
console.log(` ${RED$3}${BOLD$4}⚠ 已封禁:检测到恶意软件${RESET$7}`);
|
|
6014
|
+
if (moderation.summary) console.log(` ${RED$3}${moderation.summary}${RESET$7}`);
|
|
7144
6015
|
} else if (verdict === "SUSPICIOUS" || moderation.isSuspicious) {
|
|
7145
6016
|
console.log();
|
|
7146
|
-
console.log(` ${YELLOW$
|
|
7147
|
-
if (moderation.summary) console.log(` ${YELLOW$
|
|
6017
|
+
console.log(` ${YELLOW$3}⚠ 可疑技能${RESET$7}`);
|
|
6018
|
+
if (moderation.summary) console.log(` ${YELLOW$3}${moderation.summary}${RESET$7}`);
|
|
7148
6019
|
} else if (verdict === "SAFE") console.log(` ${BOLD$4}安全:${RESET$7} ${GREEN$4}已验证安全${RESET$7}`);
|
|
7149
6020
|
}
|
|
7150
6021
|
if (skill.createdAt) {
|
|
7151
6022
|
const created = new Date(skill.createdAt).toISOString().split("T")[0];
|
|
7152
|
-
console.log(` ${BOLD$4}创建时间:${RESET$7} ${TEXT$
|
|
6023
|
+
console.log(` ${BOLD$4}创建时间:${RESET$7} ${TEXT$5}${created}${RESET$7}`);
|
|
7153
6024
|
}
|
|
7154
6025
|
if (skill.updatedAt) {
|
|
7155
6026
|
const updated = new Date(skill.updatedAt).toISOString().split("T")[0];
|
|
7156
|
-
console.log(` ${BOLD$4}更新时间:${RESET$7} ${TEXT$
|
|
6027
|
+
console.log(` ${BOLD$4}更新时间:${RESET$7} ${TEXT$5}${updated}${RESET$7}`);
|
|
7157
6028
|
}
|
|
7158
6029
|
console.log();
|
|
7159
6030
|
} catch (error) {
|
|
@@ -7267,17 +6138,17 @@ async function handleSet(args, _globalOpts) {
|
|
|
7267
6138
|
const RESET$5 = "\x1B[0m";
|
|
7268
6139
|
const BOLD$3 = "\x1B[1m";
|
|
7269
6140
|
const DIM$5 = "\x1B[38;5;102m";
|
|
7270
|
-
const TEXT$
|
|
6141
|
+
const TEXT$4 = "\x1B[38;5;145m";
|
|
7271
6142
|
async function runDocs(args, globalOpts) {
|
|
7272
6143
|
switch (args[0]) {
|
|
7273
6144
|
case "upload":
|
|
7274
6145
|
await handleUpload(args.slice(1), globalOpts);
|
|
7275
6146
|
break;
|
|
7276
6147
|
case "list":
|
|
7277
|
-
await handleList
|
|
6148
|
+
await handleList(args.slice(1), globalOpts);
|
|
7278
6149
|
break;
|
|
7279
6150
|
case "info":
|
|
7280
|
-
await handleInfo
|
|
6151
|
+
await handleInfo(args.slice(1), globalOpts);
|
|
7281
6152
|
break;
|
|
7282
6153
|
default: printDocsHelp();
|
|
7283
6154
|
}
|
|
@@ -7319,11 +6190,11 @@ async function handleUpload(args, globalOpts) {
|
|
|
7319
6190
|
try {
|
|
7320
6191
|
const fileBuffer = fs.readFileSync(resolvedPath);
|
|
7321
6192
|
const result = await api.uploadDoc(fileBuffer, fileName);
|
|
7322
|
-
console.log(`${TEXT$
|
|
6193
|
+
console.log(`${TEXT$4}✓ 上传成功${RESET$5}`);
|
|
7323
6194
|
console.log();
|
|
7324
|
-
if (result.id) console.log(` ${BOLD$3}ID:${RESET$5} ${TEXT$
|
|
7325
|
-
if (result.status) console.log(` ${BOLD$3}状态:${RESET$5} ${TEXT$
|
|
7326
|
-
if (result.fileName) console.log(` ${BOLD$3}文件:${RESET$5} ${TEXT$
|
|
6195
|
+
if (result.id) console.log(` ${BOLD$3}ID:${RESET$5} ${TEXT$4}${result.id}${RESET$5}`);
|
|
6196
|
+
if (result.status) console.log(` ${BOLD$3}状态:${RESET$5} ${TEXT$4}${result.status}${RESET$5}`);
|
|
6197
|
+
if (result.fileName) console.log(` ${BOLD$3}文件:${RESET$5} ${TEXT$4}${result.fileName}${RESET$5}`);
|
|
7327
6198
|
console.log();
|
|
7328
6199
|
if (result.id) console.log(`${DIM$5}查看状态:bfi docs info ${result.id}${RESET$5}`);
|
|
7329
6200
|
} catch (error) {
|
|
@@ -7331,7 +6202,7 @@ async function handleUpload(args, globalOpts) {
|
|
|
7331
6202
|
process.exit(1);
|
|
7332
6203
|
}
|
|
7333
6204
|
}
|
|
7334
|
-
async function handleList
|
|
6205
|
+
async function handleList(args, globalOpts) {
|
|
7335
6206
|
const page = parseInt(args[0] || "0", 10);
|
|
7336
6207
|
const size = parseInt(args[1] || "20", 10);
|
|
7337
6208
|
const { registry, token } = resolveConfig(globalOpts);
|
|
@@ -7352,7 +6223,7 @@ async function handleList$1(args, globalOpts) {
|
|
|
7352
6223
|
const status = doc.status || "unknown";
|
|
7353
6224
|
const createdAt = doc.createdAt || doc.created_at;
|
|
7354
6225
|
const dateStr = createdAt ? new Date(createdAt).toISOString().split("T")[0] : "N/A";
|
|
7355
|
-
console.log(` ${BOLD$3}#${id}${RESET$5} ${TEXT$
|
|
6226
|
+
console.log(` ${BOLD$3}#${id}${RESET$5} ${TEXT$4}${fileName}${RESET$5}`);
|
|
7356
6227
|
console.log(` ${DIM$5}状态:${status} | 日期:${dateStr}${RESET$5}`);
|
|
7357
6228
|
console.log();
|
|
7358
6229
|
}
|
|
@@ -7364,7 +6235,7 @@ async function handleList$1(args, globalOpts) {
|
|
|
7364
6235
|
process.exit(1);
|
|
7365
6236
|
}
|
|
7366
6237
|
}
|
|
7367
|
-
async function handleInfo
|
|
6238
|
+
async function handleInfo(args, globalOpts) {
|
|
7368
6239
|
const docId = args[0];
|
|
7369
6240
|
if (!docId) {
|
|
7370
6241
|
console.error("用法:bfi docs info <id>");
|
|
@@ -7387,18 +6258,18 @@ async function handleInfo$1(args, globalOpts) {
|
|
|
7387
6258
|
console.log();
|
|
7388
6259
|
console.log(`${BOLD$3}文档 #${doc.id}${RESET$5}`);
|
|
7389
6260
|
console.log(`${DIM$5}${"─".repeat(48)}${RESET$5}`);
|
|
7390
|
-
if (doc.fileName || doc.file_name) console.log(` ${BOLD$3}文件:${RESET$5} ${TEXT$
|
|
6261
|
+
if (doc.fileName || doc.file_name) console.log(` ${BOLD$3}文件:${RESET$5} ${TEXT$4}${doc.fileName || doc.file_name}${RESET$5}`);
|
|
7391
6262
|
if (doc.status) {
|
|
7392
|
-
const statusColor = doc.status === "completed" || doc.status === "COMPLETED" ? "\x1B[32m" : doc.status === "failed" || doc.status === "FAILED" ? "\x1B[31m" : TEXT$
|
|
6263
|
+
const statusColor = doc.status === "completed" || doc.status === "COMPLETED" ? "\x1B[32m" : doc.status === "failed" || doc.status === "FAILED" ? "\x1B[31m" : TEXT$4;
|
|
7393
6264
|
console.log(` ${BOLD$3}状态:${RESET$5} ${statusColor}${doc.status}${RESET$5}`);
|
|
7394
6265
|
}
|
|
7395
6266
|
if (doc.createdAt || doc.created_at) {
|
|
7396
6267
|
const date = new Date(doc.createdAt || doc.created_at).toISOString().replace("T", " ").slice(0, 19);
|
|
7397
|
-
console.log(` ${BOLD$3}创建时间:${RESET$5} ${TEXT$
|
|
6268
|
+
console.log(` ${BOLD$3}创建时间:${RESET$5} ${TEXT$4}${date}${RESET$5}`);
|
|
7398
6269
|
}
|
|
7399
6270
|
if (doc.updatedAt || doc.updated_at) {
|
|
7400
6271
|
const date = new Date(doc.updatedAt || doc.updated_at).toISOString().replace("T", " ").slice(0, 19);
|
|
7401
|
-
console.log(` ${BOLD$3}更新时间:${RESET$5} ${TEXT$
|
|
6272
|
+
console.log(` ${BOLD$3}更新时间:${RESET$5} ${TEXT$4}${date}${RESET$5}`);
|
|
7402
6273
|
}
|
|
7403
6274
|
if (doc.result) {
|
|
7404
6275
|
console.log();
|
|
@@ -7421,15 +6292,15 @@ async function handleInfo$1(args, globalOpts) {
|
|
|
7421
6292
|
const RESET$4 = "\x1B[0m";
|
|
7422
6293
|
const BOLD$2 = "\x1B[1m";
|
|
7423
6294
|
const DIM$4 = "\x1B[38;5;102m";
|
|
7424
|
-
const TEXT$
|
|
6295
|
+
const TEXT$3 = "\x1B[38;5;145m";
|
|
7425
6296
|
const GREEN$3 = "\x1B[32m";
|
|
7426
|
-
const YELLOW$
|
|
7427
|
-
const RED$
|
|
6297
|
+
const YELLOW$2 = "\x1B[33m";
|
|
6298
|
+
const RED$2 = "\x1B[31m";
|
|
7428
6299
|
async function runPublish(args, globalOpts) {
|
|
7429
6300
|
const fromIdx = args.indexOf("--from");
|
|
7430
6301
|
const mode = fromIdx !== -1 ? args[fromIdx + 1] : "dir";
|
|
7431
6302
|
const namespace = getOptionValue$1(args, "--namespace") || globalOpts.namespace || "global";
|
|
7432
|
-
const visibility = getOptionValue$1(args, "--visibility") || "
|
|
6303
|
+
const visibility = getOptionValue$1(args, "--visibility") || "public";
|
|
7433
6304
|
const yes = args.includes("--yes") || args.includes("-y");
|
|
7434
6305
|
const branch = getOptionValue$1(args, "--branch");
|
|
7435
6306
|
const directory = getOptionValue$1(args, "--directory");
|
|
@@ -7486,22 +6357,22 @@ async function publishFromDir(positionalArgs, api, namespace, visibility) {
|
|
|
7486
6357
|
const { data: frontmatter } = parseFrontmatter(fs.readFileSync(skillMdPath, "utf-8"));
|
|
7487
6358
|
const skillName = frontmatter.name || path$1.basename(resolvedDir);
|
|
7488
6359
|
console.log(`${DIM$4}正在从目录发布技能...${RESET$4}`);
|
|
7489
|
-
console.log(` ${BOLD$2}名称:${RESET$4} ${TEXT$
|
|
7490
|
-
console.log(` ${BOLD$2}命名空间:${RESET$4} ${TEXT$
|
|
7491
|
-
console.log(` ${BOLD$2}可见性:${RESET$4} ${TEXT$
|
|
7492
|
-
console.log(` ${BOLD$2}目录:${RESET$4} ${TEXT$
|
|
6360
|
+
console.log(` ${BOLD$2}名称:${RESET$4} ${TEXT$3}${skillName}${RESET$4}`);
|
|
6361
|
+
console.log(` ${BOLD$2}命名空间:${RESET$4} ${TEXT$3}${namespace}${RESET$4}`);
|
|
6362
|
+
console.log(` ${BOLD$2}可见性:${RESET$4} ${TEXT$3}${visibility}${RESET$4}`);
|
|
6363
|
+
console.log(` ${BOLD$2}目录:${RESET$4} ${TEXT$3}${resolvedDir}${RESET$4}`);
|
|
7493
6364
|
console.log();
|
|
7494
6365
|
console.log(`${DIM$4}正在创建 zip...${RESET$4}`);
|
|
7495
6366
|
const zipBuffer = createZipFromDir(resolvedDir);
|
|
7496
6367
|
console.log(` ${GREEN$3}Zip 已创建 (${formatSize(zipBuffer.length)})${RESET$4}`);
|
|
7497
6368
|
console.log(`${DIM$4}正在上传到 SkillHub...${RESET$4}`);
|
|
7498
6369
|
try {
|
|
7499
|
-
const res = await api.publishSkill(namespace, zipBuffer, visibility);
|
|
6370
|
+
const res = await api.publishSkill(namespace, zipBuffer, visibility, true);
|
|
7500
6371
|
console.log(` ${GREEN$3}发布成功!${RESET$4}`);
|
|
7501
|
-
if (res.slug) console.log(` ${BOLD$2}Slug:${RESET$4} ${TEXT$
|
|
7502
|
-
if (res.url) console.log(` ${BOLD$2}URL:${RESET$4} ${TEXT$
|
|
6372
|
+
if (res.slug) console.log(` ${BOLD$2}Slug:${RESET$4} ${TEXT$3}${res.slug}${RESET$4}`);
|
|
6373
|
+
if (res.url) console.log(` ${BOLD$2}URL:${RESET$4} ${TEXT$3}${res.url}${RESET$4}`);
|
|
7503
6374
|
} catch (error) {
|
|
7504
|
-
console.error(` ${RED$
|
|
6375
|
+
console.error(` ${RED$2}发布失败:${error.message}${RESET$4}`);
|
|
7505
6376
|
process.exit(1);
|
|
7506
6377
|
}
|
|
7507
6378
|
console.log();
|
|
@@ -7525,27 +6396,27 @@ async function publishFromZip(positionalArgs, api, namespace, visibility) {
|
|
|
7525
6396
|
await extractZip(resolvedZip, tmpDir);
|
|
7526
6397
|
const skillMdPath = findSkillMd(tmpDir);
|
|
7527
6398
|
if (!skillMdPath) {
|
|
7528
|
-
console.error(` ${RED$
|
|
6399
|
+
console.error(` ${RED$2}zip 文件中未找到 SKILL.md${RESET$4}`);
|
|
7529
6400
|
process.exit(1);
|
|
7530
6401
|
}
|
|
7531
6402
|
const skillDir = path$1.dirname(skillMdPath);
|
|
7532
6403
|
console.log(` ${GREEN$3}在 ${path$1.relative(tmpDir, skillDir) || "."} 中找到 SKILL.md${RESET$4}`);
|
|
7533
6404
|
const { data: frontmatter } = parseFrontmatter(fs.readFileSync(skillMdPath, "utf-8"));
|
|
7534
6405
|
const skillName = frontmatter.name || path$1.basename(skillDir);
|
|
7535
|
-
console.log(` ${BOLD$2}名称:${RESET$4} ${TEXT$
|
|
7536
|
-
console.log(` ${BOLD$2}命名空间:${RESET$4} ${TEXT$
|
|
7537
|
-
console.log(` ${BOLD$2}可见性:${RESET$4} ${TEXT$
|
|
6406
|
+
console.log(` ${BOLD$2}名称:${RESET$4} ${TEXT$3}${skillName}${RESET$4}`);
|
|
6407
|
+
console.log(` ${BOLD$2}命名空间:${RESET$4} ${TEXT$3}${namespace}${RESET$4}`);
|
|
6408
|
+
console.log(` ${BOLD$2}可见性:${RESET$4} ${TEXT$3}${visibility}${RESET$4}`);
|
|
7538
6409
|
console.log();
|
|
7539
6410
|
console.log(`${DIM$4}正在重新打包...${RESET$4}`);
|
|
7540
6411
|
const zipBuffer = createZipFromDir(skillDir);
|
|
7541
6412
|
console.log(` ${GREEN$3}Zip 已创建 (${formatSize(zipBuffer.length)})${RESET$4}`);
|
|
7542
6413
|
console.log(`${DIM$4}正在上传到 SkillHub...${RESET$4}`);
|
|
7543
|
-
const res = await api.publishSkill(namespace, zipBuffer, visibility);
|
|
6414
|
+
const res = await api.publishSkill(namespace, zipBuffer, visibility, true);
|
|
7544
6415
|
console.log(` ${GREEN$3}发布成功!${RESET$4}`);
|
|
7545
|
-
if (res.slug) console.log(` ${BOLD$2}Slug:${RESET$4} ${TEXT$
|
|
7546
|
-
if (res.url) console.log(` ${BOLD$2}URL:${RESET$4} ${TEXT$
|
|
6416
|
+
if (res.slug) console.log(` ${BOLD$2}Slug:${RESET$4} ${TEXT$3}${res.slug}${RESET$4}`);
|
|
6417
|
+
if (res.url) console.log(` ${BOLD$2}URL:${RESET$4} ${TEXT$3}${res.url}${RESET$4}`);
|
|
7547
6418
|
} catch (error) {
|
|
7548
|
-
if (error.message && !error.message.includes("Publish failed")) console.error(` ${RED$
|
|
6419
|
+
if (error.message && !error.message.includes("Publish failed")) console.error(` ${RED$2}错误:${error.message}${RESET$4}`);
|
|
7549
6420
|
process.exit(1);
|
|
7550
6421
|
} finally {
|
|
7551
6422
|
try {
|
|
@@ -7560,121 +6431,109 @@ async function publishFromZip(positionalArgs, api, namespace, visibility) {
|
|
|
7560
6431
|
async function publishFromGit(positionalArgs, api, namespace, visibility, yes, branch, directory, skillFilter) {
|
|
7561
6432
|
const repoArg = positionalArgs[0];
|
|
7562
6433
|
if (!repoArg) {
|
|
7563
|
-
console.error("用法:bfi publish <repo-url> --from git [options]");
|
|
7564
|
-
console.log("使用服务端发现从 Git 仓库发布技能。");
|
|
7565
|
-
console.log();
|
|
7566
|
-
console.log("示例:");
|
|
7567
|
-
console.log(` ${DIM$4}$ ${RESET$4}bfi publish https://github.com/user/repo --from git`);
|
|
7568
|
-
console.log(` ${DIM$4}$ ${RESET$4}bfi publish user/repo --from git --branch main`);
|
|
6434
|
+
console.error("用法:bfi skills publish <repo-url> --from git [options]");
|
|
7569
6435
|
process.exit(1);
|
|
7570
6436
|
}
|
|
7571
6437
|
let repoUrl;
|
|
6438
|
+
let parsedRef;
|
|
7572
6439
|
try {
|
|
7573
|
-
|
|
6440
|
+
const parsed = parseSource(repoArg);
|
|
6441
|
+
repoUrl = parsed.url;
|
|
6442
|
+
parsedRef = parsed.ref;
|
|
7574
6443
|
} catch {
|
|
7575
6444
|
repoUrl = repoArg;
|
|
7576
6445
|
}
|
|
7577
|
-
const effectiveBranch = branch || "main";
|
|
7578
|
-
const
|
|
6446
|
+
const effectiveBranch = branch || parsedRef || "main";
|
|
6447
|
+
const effectiveSubpath = directory || null;
|
|
7579
6448
|
console.log(`${DIM$4}正在从 Git 仓库发现技能...${RESET$4}`);
|
|
7580
|
-
console.log(` ${BOLD$2}仓库:${RESET$4} ${TEXT$
|
|
7581
|
-
console.log(` ${BOLD$2}分支:${RESET$4} ${TEXT$
|
|
7582
|
-
if (effectiveDir) console.log(` ${BOLD$2}目录:${RESET$4} ${TEXT$4}${effectiveDir}${RESET$4}`);
|
|
6449
|
+
console.log(` ${BOLD$2}仓库:${RESET$4} ${TEXT$3}${repoUrl}${RESET$4}`);
|
|
6450
|
+
console.log(` ${BOLD$2}分支:${RESET$4} ${TEXT$3}${effectiveBranch}${RESET$4}`);
|
|
7583
6451
|
console.log();
|
|
7584
|
-
let
|
|
6452
|
+
let tmpDir = null;
|
|
6453
|
+
let skills = [];
|
|
7585
6454
|
try {
|
|
7586
|
-
|
|
6455
|
+
console.log(`${DIM$4}正在克隆仓库...${RESET$4}`);
|
|
6456
|
+
const { cloneRepo } = await Promise.resolve().then(() => git_exports);
|
|
6457
|
+
tmpDir = await cloneRepo(repoUrl, effectiveBranch);
|
|
6458
|
+
console.log(` ${GREEN$3}仓库克隆完成${RESET$4}`);
|
|
6459
|
+
console.log(`${DIM$4}正在发现技能...${RESET$4}`);
|
|
6460
|
+
const { discoverSkills } = await import("./_chunks/skills.mjs").then((n) => n.skills_exports);
|
|
6461
|
+
skills = (await discoverSkills(tmpDir, effectiveSubpath || void 0)).map((s) => ({
|
|
6462
|
+
path: s.path,
|
|
6463
|
+
name: s.name,
|
|
6464
|
+
description: s.description || ""
|
|
6465
|
+
}));
|
|
7587
6466
|
} catch (error) {
|
|
7588
|
-
console.error(` ${RED$
|
|
6467
|
+
console.error(` ${RED$2}克隆或发现失败:${error.message}${RESET$4}`);
|
|
6468
|
+
if (tmpDir) try {
|
|
6469
|
+
const { cleanupTempDir } = await Promise.resolve().then(() => git_exports);
|
|
6470
|
+
await cleanupTempDir(tmpDir);
|
|
6471
|
+
} catch {}
|
|
7589
6472
|
process.exit(1);
|
|
7590
6473
|
}
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
console.log(`${BOLD$2}预检结果:${RESET$4}`);
|
|
7599
|
-
const errors = precheck.errors;
|
|
7600
|
-
const warnings = precheck.warnings;
|
|
7601
|
-
if (errors && errors.length > 0) {
|
|
7602
|
-
console.log(` ${RED$1}错误:${RESET$4}`);
|
|
7603
|
-
for (const e of errors) console.log(` ${RED$1}- ${e}${RESET$4}`);
|
|
7604
|
-
}
|
|
7605
|
-
if (warnings && warnings.length > 0) {
|
|
7606
|
-
console.log(` ${YELLOW$1}警告:${RESET$4}`);
|
|
7607
|
-
for (const w of warnings) console.log(` ${YELLOW$1}- ${w}${RESET$4}`);
|
|
7608
|
-
}
|
|
7609
|
-
}
|
|
7610
|
-
process.exit(1);
|
|
6474
|
+
if (skills.length === 0) {
|
|
6475
|
+
console.log(`${YELLOW$2}仓库中未发现技能。${RESET$4}`);
|
|
6476
|
+
if (tmpDir) try {
|
|
6477
|
+
const { cleanupTempDir } = await Promise.resolve().then(() => git_exports);
|
|
6478
|
+
await cleanupTempDir(tmpDir);
|
|
6479
|
+
} catch {}
|
|
6480
|
+
return;
|
|
7611
6481
|
}
|
|
7612
|
-
|
|
7613
|
-
console.log();
|
|
7614
|
-
let selectedSkills = discoveredSkills;
|
|
6482
|
+
let selectedSkills = skills;
|
|
7615
6483
|
if (skillFilter) {
|
|
7616
6484
|
const filters = skillFilter.split(",").map((s) => s.trim().toLowerCase());
|
|
7617
|
-
selectedSkills =
|
|
7618
|
-
const slug = String(s.slug || "").toLowerCase();
|
|
7619
|
-
const name = String(s.name || "").toLowerCase();
|
|
7620
|
-
return filters.some((f) => slug.includes(f) || name.includes(f));
|
|
7621
|
-
});
|
|
6485
|
+
selectedSkills = skills.filter((s) => filters.some((f) => s.name.toLowerCase().includes(f)));
|
|
7622
6486
|
if (selectedSkills.length === 0) {
|
|
7623
|
-
console.log(`${YELLOW$
|
|
7624
|
-
console.log("
|
|
7625
|
-
|
|
6487
|
+
console.log(`${YELLOW$2}未找到匹配 "${skillFilter}" 的技能${RESET$4}`);
|
|
6488
|
+
console.log(`可用:${skills.map((s) => s.name).join(", ")}`);
|
|
6489
|
+
try {
|
|
6490
|
+
fs.rmSync(tmpDir, {
|
|
6491
|
+
recursive: true,
|
|
6492
|
+
force: true
|
|
6493
|
+
});
|
|
6494
|
+
} catch {}
|
|
7626
6495
|
process.exit(1);
|
|
7627
6496
|
}
|
|
7628
6497
|
}
|
|
6498
|
+
console.log(`\n${BOLD$2}发现 ${skills.length} 个技能,将发布 ${selectedSkills.length} 个:${RESET$4}\n`);
|
|
7629
6499
|
for (const skill of selectedSkills) {
|
|
7630
|
-
const
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
const pathParts = skillPath ? skillPath.replace(/\\/g, "/").split("/") : [];
|
|
7635
|
-
const indent = " ";
|
|
7636
|
-
if (pathParts.length > 1) {
|
|
7637
|
-
const dirPath = pathParts.slice(0, -1).join(" ▸ ");
|
|
7638
|
-
console.log(` ${DIM$4}📁 ${dirPath}/${RESET$4}`);
|
|
7639
|
-
}
|
|
7640
|
-
console.log(` ${BOLD$2}${skillName}${RESET$4} ${DIM$4}(${slug})${RESET$4}`);
|
|
7641
|
-
if (description) console.log(` ${indent}${DIM$4}${truncate(String(description), 80)}${RESET$4}`);
|
|
7642
|
-
const skillPrecheck = skill.precheck;
|
|
7643
|
-
if (skillPrecheck) {
|
|
7644
|
-
const errors = skillPrecheck.errors;
|
|
7645
|
-
const warnings = skillPrecheck.warnings;
|
|
7646
|
-
if (errors && errors.length > 0) for (const e of errors) console.log(` ${RED$1}错误:${e}${RESET$4}`);
|
|
7647
|
-
if (warnings && warnings.length > 0) for (const w of warnings) console.log(` ${YELLOW$1}警告:${w}${RESET$4}`);
|
|
7648
|
-
}
|
|
6500
|
+
const relPath = path$1.relative(tmpDir, skill.path) || ".";
|
|
6501
|
+
console.log(` ${BOLD$2}${skill.name}${RESET$4}`);
|
|
6502
|
+
console.log(` ${DIM$4}📁 ${relPath.split("/").join(" ▸ ")}${RESET$4}`);
|
|
6503
|
+
if (skill.description) console.log(` ${DIM$4}${truncate(skill.description, 80)}${RESET$4}`);
|
|
7649
6504
|
console.log();
|
|
7650
6505
|
}
|
|
7651
|
-
let confirmWarnings = false;
|
|
7652
|
-
if (precheck) {
|
|
7653
|
-
const errors = precheck.errors;
|
|
7654
|
-
const warnings = precheck.warnings;
|
|
7655
|
-
if (errors && errors.length > 0 || warnings && warnings.length > 0) confirmWarnings = true;
|
|
7656
|
-
}
|
|
7657
|
-
const selectedSlugs = skillFilter ? selectedSkills.map((s) => String(s.slug)) : null;
|
|
7658
6506
|
if (!yes) {
|
|
7659
|
-
const
|
|
7660
|
-
|
|
7661
|
-
|
|
7662
|
-
|
|
6507
|
+
const { confirm } = await import("./_chunks/libs/@clack/prompts.mjs").then((n) => n.dist_exports);
|
|
6508
|
+
if (!await confirm({ message: `确认发布 ${selectedSkills.length} 个技能到 @${namespace}?` })) {
|
|
6509
|
+
console.log("已取消。");
|
|
6510
|
+
try {
|
|
6511
|
+
fs.rmSync(tmpDir, {
|
|
6512
|
+
recursive: true,
|
|
6513
|
+
force: true
|
|
6514
|
+
});
|
|
6515
|
+
} catch {}
|
|
6516
|
+
return;
|
|
6517
|
+
}
|
|
7663
6518
|
}
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7667
|
-
console.log(
|
|
7668
|
-
|
|
7669
|
-
|
|
7670
|
-
const
|
|
7671
|
-
console.log(` ${GREEN$3}✓
|
|
6519
|
+
const { createZipFromDir } = await Promise.resolve().then(() => zip_exports);
|
|
6520
|
+
let successCount = 0;
|
|
6521
|
+
for (const skill of selectedSkills) {
|
|
6522
|
+
console.log(`${DIM$4}正在发布 ${skill.name}...${RESET$4}`);
|
|
6523
|
+
try {
|
|
6524
|
+
const zipBuffer = createZipFromDir(skill.path);
|
|
6525
|
+
const res = await api.publishSkill(namespace, zipBuffer, visibility, true);
|
|
6526
|
+
console.log(` ${GREEN$3}✓ 已发布:${namespace}--${res.slug || skill.name}${RESET$4}`);
|
|
6527
|
+
successCount++;
|
|
6528
|
+
} catch (error) {
|
|
6529
|
+
console.error(` ${RED$2}✗ ${skill.name}:${error.message}${RESET$4}`);
|
|
7672
6530
|
}
|
|
7673
|
-
} catch (error) {
|
|
7674
|
-
console.error(` ${RED$1}发布失败:${error.message}${RESET$4}`);
|
|
7675
|
-
process.exit(1);
|
|
7676
6531
|
}
|
|
7677
|
-
console.log();
|
|
6532
|
+
console.log(`\n${GREEN$3}发布完成:${successCount}/${selectedSkills.length} 个技能${RESET$4}`);
|
|
6533
|
+
if (tmpDir) try {
|
|
6534
|
+
const { cleanupTempDir } = await Promise.resolve().then(() => git_exports);
|
|
6535
|
+
await cleanupTempDir(tmpDir);
|
|
6536
|
+
} catch {}
|
|
7678
6537
|
}
|
|
7679
6538
|
function getOptionValue$1(args, flag) {
|
|
7680
6539
|
const idx = args.indexOf(flag);
|
|
@@ -7719,149 +6578,276 @@ function truncate(text, maxLen) {
|
|
|
7719
6578
|
if (text.length <= maxLen) return text;
|
|
7720
6579
|
return text.slice(0, maxLen) + "...";
|
|
7721
6580
|
}
|
|
7722
|
-
async function confirmPrompt(message) {
|
|
7723
|
-
const rl = (await import("node:readline")).createInterface({
|
|
7724
|
-
input: process.stdin,
|
|
7725
|
-
output: process.stdout
|
|
7726
|
-
});
|
|
7727
|
-
return new Promise((resolve) => {
|
|
7728
|
-
rl.question(`${message} [Y/n] `, (answer) => {
|
|
7729
|
-
rl.close();
|
|
7730
|
-
const normalized = answer.trim().toLowerCase();
|
|
7731
|
-
if (normalized === "n" || normalized === "no") {
|
|
7732
|
-
console.log("Publish cancelled.");
|
|
7733
|
-
process.exit(0);
|
|
7734
|
-
}
|
|
7735
|
-
resolve();
|
|
7736
|
-
});
|
|
7737
|
-
});
|
|
7738
|
-
}
|
|
7739
6581
|
const RESET$3 = "\x1B[0m";
|
|
7740
6582
|
const BOLD$1 = "\x1B[1m";
|
|
7741
6583
|
const DIM$3 = "\x1B[38;5;102m";
|
|
7742
|
-
const TEXT$3 = "\x1B[38;5;145m";
|
|
7743
6584
|
const GREEN$2 = "\x1B[32m";
|
|
6585
|
+
const RED$1 = "\x1B[31m";
|
|
6586
|
+
const YELLOW$1 = "\x1B[33m";
|
|
7744
6587
|
async function runPackage(args, globalOpts) {
|
|
7745
6588
|
const subcommand = args[0];
|
|
7746
6589
|
const { registry, token } = resolveConfig(globalOpts);
|
|
7747
6590
|
const api = new SkillHubAPI(registry, token);
|
|
7748
6591
|
switch (subcommand) {
|
|
7749
6592
|
case "list":
|
|
7750
|
-
|
|
6593
|
+
case "ls":
|
|
6594
|
+
await handleLocalList(args.slice(1), globalOpts);
|
|
7751
6595
|
break;
|
|
7752
|
-
case "
|
|
7753
|
-
|
|
6596
|
+
case "install":
|
|
6597
|
+
case "i":
|
|
6598
|
+
await handleInstall(args.slice(1), api, globalOpts);
|
|
6599
|
+
break;
|
|
6600
|
+
case "uninstall":
|
|
6601
|
+
case "rm":
|
|
6602
|
+
await handleUninstall(args.slice(1), globalOpts);
|
|
6603
|
+
break;
|
|
6604
|
+
case "update":
|
|
6605
|
+
case "up":
|
|
6606
|
+
await handleUpdate(args.slice(1), api, globalOpts);
|
|
6607
|
+
break;
|
|
6608
|
+
case "search":
|
|
6609
|
+
await handleSearch(args.slice(1), api);
|
|
7754
6610
|
break;
|
|
7755
6611
|
case "create":
|
|
7756
6612
|
await handleCreate(args.slice(1), api, globalOpts);
|
|
7757
6613
|
break;
|
|
7758
|
-
case "add":
|
|
7759
|
-
await
|
|
6614
|
+
case "add-skills":
|
|
6615
|
+
await handleAddSkills(args.slice(1), api, globalOpts);
|
|
7760
6616
|
break;
|
|
7761
|
-
case "remove":
|
|
7762
|
-
|
|
7763
|
-
await handleRemove(args.slice(1), api, globalOpts);
|
|
6617
|
+
case "remove-skills":
|
|
6618
|
+
await handleRemoveSkills(args.slice(1), api, globalOpts);
|
|
7764
6619
|
break;
|
|
7765
6620
|
default: printPackageHelp();
|
|
7766
6621
|
}
|
|
7767
6622
|
}
|
|
6623
|
+
function getWorkdir(globalOpts, args) {
|
|
6624
|
+
if (args.includes("-g") || args.includes("--global")) return os$1.homedir();
|
|
6625
|
+
return globalOpts.workdir || process.cwd();
|
|
6626
|
+
}
|
|
7768
6627
|
function printPackageHelp() {
|
|
7769
|
-
console.log();
|
|
7770
6628
|
console.log(`${BOLD$1}包命令:${RESET$3}`);
|
|
7771
|
-
console.log(
|
|
7772
|
-
console.log(
|
|
7773
|
-
console.log(` ${DIM$3}bfi skills package
|
|
7774
|
-
console.log(` ${DIM$3}bfi skills package
|
|
7775
|
-
console.log(` ${DIM$3}bfi skills package
|
|
6629
|
+
console.log();
|
|
6630
|
+
console.log(`${BOLD$1}本地操作:${RESET$3}`);
|
|
6631
|
+
console.log(` ${DIM$3}bfi skills package list${RESET$3} 列出已安装的包`);
|
|
6632
|
+
console.log(` ${DIM$3}bfi skills package install <ref>${RESET$3} 安装包(含全部技能)`);
|
|
6633
|
+
console.log(` ${DIM$3}bfi skills package uninstall <ref>${RESET$3} 卸载包(含全部技能)`);
|
|
6634
|
+
console.log(` ${DIM$3}bfi skills package update [ref]${RESET$3} 更新包中技能`);
|
|
6635
|
+
console.log(` ${DIM$3}bfi skills package search <query>${RESET$3} 搜索包`);
|
|
6636
|
+
console.log();
|
|
6637
|
+
console.log(`${BOLD$1}服务端管理:${RESET$3}`);
|
|
6638
|
+
console.log(` ${DIM$3}bfi skills package create <slug>${RESET$3} 创建包`);
|
|
6639
|
+
console.log(` ${DIM$3}bfi skills package add-skills <ref> [skills...]${RESET$3} 添加技能到包`);
|
|
6640
|
+
console.log(` ${DIM$3}bfi skills package remove-skills <ref> [skills...]${RESET$3} 从包移除技能`);
|
|
7776
6641
|
console.log();
|
|
7777
6642
|
console.log(`${BOLD$1}选项:${RESET$3}`);
|
|
7778
|
-
console.log(` --namespace <ns>
|
|
7779
|
-
console.log(` --name <name>
|
|
7780
|
-
console.log(` --description <
|
|
7781
|
-
console.log(` --
|
|
7782
|
-
|
|
6643
|
+
console.log(` --namespace <ns> 目标命名空间`);
|
|
6644
|
+
console.log(` --name <name> 显示名称(create 时)`);
|
|
6645
|
+
console.log(` --description <t> 描述(create 时)`);
|
|
6646
|
+
console.log(` --json JSON 输出`);
|
|
6647
|
+
}
|
|
6648
|
+
async function handleLocalList(args, globalOpts) {
|
|
6649
|
+
const lock = loadLockfile(getWorkdir(globalOpts, args));
|
|
6650
|
+
args.includes("-g") || args.includes("--global");
|
|
6651
|
+
const pkgs = lock.packages || {};
|
|
6652
|
+
const entries = Object.entries(pkgs);
|
|
6653
|
+
if (args.includes("--json")) {
|
|
6654
|
+
console.log(JSON.stringify(Object.values(pkgs), null, 2));
|
|
6655
|
+
return;
|
|
6656
|
+
}
|
|
6657
|
+
if (entries.length === 0) {
|
|
6658
|
+
console.log("没有已安装的包。");
|
|
6659
|
+
console.log(`使用 ${DIM$3}bfi skills package install <ref>${RESET$3} 安装包。`);
|
|
6660
|
+
return;
|
|
6661
|
+
}
|
|
7783
6662
|
console.log();
|
|
7784
|
-
console.log(`${BOLD$1}
|
|
7785
|
-
console.log(` ${DIM$3}$ ${RESET$3}bfi skills package list --namespace myteam`);
|
|
7786
|
-
console.log(` ${DIM$3}$ ${RESET$3}bfi skills package info @myteam/my-package`);
|
|
7787
|
-
console.log(` ${DIM$3}$ ${RESET$3}bfi skills package create my-utils --namespace myteam`);
|
|
7788
|
-
console.log(` ${DIM$3}$ ${RESET$3}bfi skills package add @myteam/my-package @myteam/skill-a @myteam/skill-b`);
|
|
7789
|
-
console.log(` ${DIM$3}$ ${RESET$3}bfi skills package remove @myteam/my-package @myteam/skill-a`);
|
|
6663
|
+
console.log(`${BOLD$1}已安装的包(${entries.length} 个):${RESET$3}`);
|
|
7790
6664
|
console.log();
|
|
6665
|
+
for (const [ref, info] of entries) {
|
|
6666
|
+
const pkg = info;
|
|
6667
|
+
const skills = lock.skills || {};
|
|
6668
|
+
const pkgSkills = Object.entries(skills).filter(([, s]) => s.package?.slug === pkg.slug);
|
|
6669
|
+
console.log(` ${BOLD$1}${pkg.name || pkg.slug}${RESET$3}`);
|
|
6670
|
+
console.log(` ${DIM$3}命名空间:@${pkg.namespace} | 版本:${pkg.version || "latest"} | 技能数:${pkgSkills.length}${RESET$3}`);
|
|
6671
|
+
console.log();
|
|
6672
|
+
}
|
|
7791
6673
|
}
|
|
7792
|
-
async function
|
|
7793
|
-
const
|
|
7794
|
-
|
|
6674
|
+
async function handleInstall(args, api, globalOpts) {
|
|
6675
|
+
const pkgRef = args[0];
|
|
6676
|
+
if (!pkgRef) {
|
|
6677
|
+
console.error("用法:bfi skills package install <package-ref>");
|
|
6678
|
+
console.error(" 示例:bfi skills package install @global/my-package");
|
|
6679
|
+
process.exit(1);
|
|
6680
|
+
}
|
|
6681
|
+
const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
|
|
6682
|
+
console.log(`${DIM$3}正在获取包信息...${RESET$3}`);
|
|
6683
|
+
let pkgInfo;
|
|
7795
6684
|
try {
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
if (json) {
|
|
7799
|
-
console.log(JSON.stringify({
|
|
7800
|
-
namespace,
|
|
7801
|
-
packages
|
|
7802
|
-
}, null, 2));
|
|
7803
|
-
return;
|
|
7804
|
-
}
|
|
7805
|
-
if (packages.length === 0) {
|
|
7806
|
-
console.log(`命名空间 "${namespace}" 中没有包。`);
|
|
7807
|
-
console.log(`使用 --namespace <ns> 查看其他命名空间,或 bfi whoami 查看你的命名空间列表。`);
|
|
7808
|
-
return;
|
|
7809
|
-
}
|
|
7810
|
-
console.log();
|
|
7811
|
-
console.log(`${BOLD$1}@${namespace} 中的包${RESET$3}(${packages.length} 个):`);
|
|
7812
|
-
console.log();
|
|
7813
|
-
packages.forEach((pkg, index) => {
|
|
7814
|
-
const visibility = pkg.visibility || "private";
|
|
7815
|
-
const skillCount = pkg.skillCount || 0;
|
|
7816
|
-
console.log(` ${BOLD$1}${index + 1}. ${pkg.name || pkg.slug}${RESET$3}`);
|
|
7817
|
-
console.log(` ${DIM$3}Slug: ${pkg.slug}${RESET$3}`);
|
|
7818
|
-
console.log(` ${DIM$3}Visibility: ${visibility}${RESET$3}`);
|
|
7819
|
-
console.log(` ${DIM$3}Skills: ${skillCount}${RESET$3}`);
|
|
7820
|
-
if (pkg.description) console.log(` ${DIM$3}${pkg.description}${RESET$3}`);
|
|
7821
|
-
console.log();
|
|
7822
|
-
});
|
|
6685
|
+
pkgInfo = await api.getPackage(namespace, slug);
|
|
6686
|
+
pkgInfo = pkgInfo.data || pkgInfo;
|
|
7823
6687
|
} catch (error) {
|
|
7824
|
-
console.error(
|
|
6688
|
+
console.error(`${RED$1}获取包信息失败:${error.message}${RESET$3}`);
|
|
7825
6689
|
process.exit(1);
|
|
7826
6690
|
}
|
|
6691
|
+
const skills = pkgInfo.skills || [];
|
|
6692
|
+
if (skills.length === 0) {
|
|
6693
|
+
console.log(`${YELLOW$1}包中没有技能。${RESET$3}`);
|
|
6694
|
+
return;
|
|
6695
|
+
}
|
|
6696
|
+
console.log(`${BOLD$1}${pkgInfo.name || slug}${RESET$3}(${skills.length} 个技能):`);
|
|
6697
|
+
console.log();
|
|
6698
|
+
const { runAdd } = await Promise.resolve().then(() => add_exports);
|
|
6699
|
+
const installedSkills = [];
|
|
6700
|
+
for (const skill of skills) {
|
|
6701
|
+
const skillRef = skill.namespace ? `@${skill.namespace}/${skill.slug}` : skill.slug;
|
|
6702
|
+
console.log(` ${DIM$3}正在安装 ${skillRef}...${RESET$3}`);
|
|
6703
|
+
try {
|
|
6704
|
+
await runAdd([skillRef], {
|
|
6705
|
+
...globalOpts,
|
|
6706
|
+
yes: true
|
|
6707
|
+
});
|
|
6708
|
+
console.log(` ${GREEN$2}✓ ${skill.slug}${RESET$3}`);
|
|
6709
|
+
installedSkills.push(skill.slug);
|
|
6710
|
+
} catch (error) {
|
|
6711
|
+
console.log(` ${RED$1}✗ ${skill.slug}:${error.message}${RESET$3}`);
|
|
6712
|
+
}
|
|
6713
|
+
}
|
|
6714
|
+
const cwd = getWorkdir(globalOpts, args);
|
|
6715
|
+
const lock = loadLockfile(cwd);
|
|
6716
|
+
const pkgKey = `@${namespace}/${slug}`;
|
|
6717
|
+
if (!lock.packages) lock.packages = {};
|
|
6718
|
+
lock.packages[pkgKey] = {
|
|
6719
|
+
namespace,
|
|
6720
|
+
slug,
|
|
6721
|
+
name: pkgInfo.displayName || pkgInfo.name || slug,
|
|
6722
|
+
version: pkgInfo.version || "latest",
|
|
6723
|
+
skillCount: installedSkills.length
|
|
6724
|
+
};
|
|
6725
|
+
for (const skillSlug of installedSkills) {
|
|
6726
|
+
if (!lock.skills[skillSlug]) lock.skills[skillSlug] = {
|
|
6727
|
+
namespace,
|
|
6728
|
+
slug,
|
|
6729
|
+
version: "latest"
|
|
6730
|
+
};
|
|
6731
|
+
lock.skills[skillSlug].package = {
|
|
6732
|
+
namespace,
|
|
6733
|
+
slug
|
|
6734
|
+
};
|
|
6735
|
+
}
|
|
6736
|
+
saveLockfile(cwd, lock);
|
|
6737
|
+
console.log();
|
|
6738
|
+
console.log(`${GREEN$2}✓ 包安装完成${RESET$3}`);
|
|
7827
6739
|
}
|
|
7828
|
-
async function
|
|
6740
|
+
async function handleUninstall(args, globalOpts) {
|
|
7829
6741
|
const pkgRef = args[0];
|
|
7830
6742
|
if (!pkgRef) {
|
|
7831
|
-
console.error("
|
|
7832
|
-
console.log();
|
|
7833
|
-
console.log("Examples:");
|
|
7834
|
-
console.log(" bfi skills package info @myteam/my-package");
|
|
7835
|
-
console.log(" bfi skills package info myteam--my-package");
|
|
6743
|
+
console.error("用法:bfi skills package uninstall <package-ref>");
|
|
7836
6744
|
process.exit(1);
|
|
7837
6745
|
}
|
|
7838
|
-
const json = args.includes("--json");
|
|
7839
6746
|
const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
|
|
7840
|
-
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
6747
|
+
const pkgKey = `@${namespace}/${slug}`;
|
|
6748
|
+
const cwd = getWorkdir(globalOpts, args);
|
|
6749
|
+
const lock = loadLockfile(cwd);
|
|
6750
|
+
if (!lock.packages || !lock.packages[pkgKey]) {
|
|
6751
|
+
console.log(`${YELLOW$1}包未安装:${pkgKey}${RESET$3}`);
|
|
6752
|
+
return;
|
|
6753
|
+
}
|
|
6754
|
+
const skills = lock.skills || {};
|
|
6755
|
+
let removed = 0;
|
|
6756
|
+
for (const [skillName, info] of Object.entries(skills)) {
|
|
6757
|
+
const skillInfo = info;
|
|
6758
|
+
if (skillInfo.package?.slug === slug && skillInfo.package?.namespace === namespace) {
|
|
6759
|
+
const { removeCommand } = await Promise.resolve().then(() => remove_exports);
|
|
6760
|
+
try {
|
|
6761
|
+
await removeCommand([skillName], {
|
|
6762
|
+
global: false,
|
|
6763
|
+
yes: true
|
|
6764
|
+
});
|
|
6765
|
+
removed++;
|
|
6766
|
+
} catch {}
|
|
6767
|
+
}
|
|
6768
|
+
}
|
|
6769
|
+
delete lock.packages[pkgKey];
|
|
6770
|
+
const { saveLockfile } = await Promise.resolve().then(() => config_exports);
|
|
6771
|
+
saveLockfile(cwd, lock);
|
|
6772
|
+
console.log(`${GREEN$2}✓ 已卸载包,移除 ${removed} 个技能${RESET$3}`);
|
|
6773
|
+
}
|
|
6774
|
+
async function handleUpdate(args, api, globalOpts) {
|
|
6775
|
+
const pkgRef = args[0];
|
|
6776
|
+
const lock = loadLockfile(getWorkdir(globalOpts, args));
|
|
6777
|
+
let packagesToUpdate = [];
|
|
6778
|
+
const pkgs = lock.packages || {};
|
|
6779
|
+
if (pkgRef) {
|
|
6780
|
+
const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
|
|
6781
|
+
if (!pkgs[`@${namespace}/${slug}`]) {
|
|
6782
|
+
console.log(`${YELLOW$1}包未安装:@${namespace}/${slug}${RESET$3}`);
|
|
7845
6783
|
return;
|
|
7846
6784
|
}
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
6785
|
+
packagesToUpdate.push({
|
|
6786
|
+
namespace,
|
|
6787
|
+
slug
|
|
6788
|
+
});
|
|
6789
|
+
} else packagesToUpdate = Object.values(pkgs).map((p) => ({
|
|
6790
|
+
namespace: p.namespace,
|
|
6791
|
+
slug: p.slug
|
|
6792
|
+
}));
|
|
6793
|
+
if (packagesToUpdate.length === 0) {
|
|
6794
|
+
console.log("没有已安装的包需要更新。");
|
|
6795
|
+
return;
|
|
6796
|
+
}
|
|
6797
|
+
console.log(`${DIM$3}正在更新 ${packagesToUpdate.length} 个包...${RESET$3}`);
|
|
6798
|
+
for (const pkg of packagesToUpdate) try {
|
|
6799
|
+
const pkgInfo = await api.getPackage(pkg.namespace, pkg.slug);
|
|
6800
|
+
const skills = (pkgInfo.data || pkgInfo).skills || [];
|
|
6801
|
+
console.log(` ${DIM$3}更新 @${pkg.namespace}/${pkg.slug}(${skills.length} 个技能)...${RESET$3}`);
|
|
6802
|
+
for (const skill of skills) {
|
|
6803
|
+
const skillRef = skill.namespace ? `@${skill.namespace}/${skill.slug}` : skill.slug;
|
|
6804
|
+
const { runAdd } = await Promise.resolve().then(() => add_exports);
|
|
6805
|
+
try {
|
|
6806
|
+
await runAdd([skillRef], {
|
|
6807
|
+
...globalOpts,
|
|
6808
|
+
yes: true
|
|
6809
|
+
});
|
|
6810
|
+
} catch {}
|
|
7859
6811
|
}
|
|
7860
|
-
console.log();
|
|
7861
6812
|
} catch (error) {
|
|
7862
|
-
console.
|
|
6813
|
+
console.log(` ${RED$1}✗ @${pkg.namespace}/${pkg.slug}:${error.message}${RESET$3}`);
|
|
6814
|
+
}
|
|
6815
|
+
console.log(`${GREEN$2}✓ 包更新完成${RESET$3}`);
|
|
6816
|
+
}
|
|
6817
|
+
async function handleSearch(args, api) {
|
|
6818
|
+
const query = args.filter((a) => !a.startsWith("--")).join(" ");
|
|
6819
|
+
const json = args.includes("--json");
|
|
6820
|
+
if (!query) {
|
|
6821
|
+
console.error("用法:bfi skills package search <query>");
|
|
7863
6822
|
process.exit(1);
|
|
7864
6823
|
}
|
|
6824
|
+
const skills = (await api.searchSkills(query, { limit: 20 })).results || [];
|
|
6825
|
+
const namespaces = /* @__PURE__ */ new Map();
|
|
6826
|
+
for (const s of skills) {
|
|
6827
|
+
const { namespace } = parseSkillRef(s.slug, "global");
|
|
6828
|
+
if (!namespaces.has(namespace)) namespaces.set(namespace, []);
|
|
6829
|
+
namespaces.get(namespace).push(s);
|
|
6830
|
+
}
|
|
6831
|
+
if (json) {
|
|
6832
|
+
const groups = Array.from(namespaces.entries()).map(([ns, sk]) => ({
|
|
6833
|
+
namespace: ns,
|
|
6834
|
+
skillCount: sk.length,
|
|
6835
|
+
skills: sk.map((s) => ({
|
|
6836
|
+
name: s.displayName || s.name,
|
|
6837
|
+
slug: s.slug
|
|
6838
|
+
}))
|
|
6839
|
+
}));
|
|
6840
|
+
console.log(JSON.stringify(groups, null, 2));
|
|
6841
|
+
return;
|
|
6842
|
+
}
|
|
6843
|
+
console.log(`\n${BOLD$1}找到 ${skills.length} 个相关技能(按命名空间分组):${RESET$3}\n`);
|
|
6844
|
+
for (const [ns, sk] of namespaces) {
|
|
6845
|
+
console.log(` ${BOLD$1}@${ns}${RESET$3}(${sk.length} 个技能)`);
|
|
6846
|
+
for (const s of sk.slice(0, 5)) console.log(` ${DIM$3}- ${s.displayName || s.name} (${s.slug})${RESET$3}`);
|
|
6847
|
+
if (sk.length > 5) console.log(` ${DIM$3}... 还有 ${sk.length - 5} 个${RESET$3}`);
|
|
6848
|
+
console.log();
|
|
6849
|
+
}
|
|
6850
|
+
console.log(`${DIM$3}使用 bfi skills package create <slug> --namespace <ns> 创建包,然后 add-skills 添加这些技能。${RESET$3}`);
|
|
7865
6851
|
}
|
|
7866
6852
|
async function handleCreate(args, api, globalOpts) {
|
|
7867
6853
|
const slug = args[0];
|
|
@@ -7876,27 +6862,24 @@ async function handleCreate(args, api, globalOpts) {
|
|
|
7876
6862
|
try {
|
|
7877
6863
|
const result = await api.createPackage(namespace, {
|
|
7878
6864
|
slug,
|
|
7879
|
-
|
|
6865
|
+
displayName: name || slug,
|
|
7880
6866
|
description: description || "",
|
|
7881
|
-
visibility
|
|
6867
|
+
visibility: visibility.toUpperCase()
|
|
7882
6868
|
});
|
|
7883
6869
|
console.log(`${GREEN$2}✓ 已创建包 ${toSkillRefString(namespace, slug)}${RESET$3}`);
|
|
7884
|
-
const
|
|
7885
|
-
if (
|
|
7886
|
-
console.log(` ${BOLD$1}名称:${RESET$3} ${TEXT$3}${createdPkg.name || slug}${RESET$3}`);
|
|
7887
|
-
console.log(` ${BOLD$1}Visibility:${RESET$3} ${TEXT$3}${createdPkg.visibility || visibility}${RESET$3}`);
|
|
7888
|
-
}
|
|
6870
|
+
const pkg = result.package || result.data || result;
|
|
6871
|
+
if (pkg) console.log(` ${DIM$3}名称:${pkg.name || slug} | 可见性:${pkg.visibility || visibility}${RESET$3}`);
|
|
7889
6872
|
} catch (error) {
|
|
7890
|
-
console.error(
|
|
6873
|
+
console.error(`${RED$1}创建包失败:${error.message}${RESET$3}`);
|
|
7891
6874
|
process.exit(1);
|
|
7892
6875
|
}
|
|
7893
6876
|
}
|
|
7894
|
-
async function
|
|
6877
|
+
async function handleAddSkills(args, api, globalOpts) {
|
|
7895
6878
|
const pkgRef = args[0];
|
|
7896
6879
|
const skillRefs = args.slice(1);
|
|
7897
6880
|
if (!pkgRef) {
|
|
7898
|
-
console.error("用法:bfi skills package add <package-ref> [skill-ref...]");
|
|
7899
|
-
console.error("
|
|
6881
|
+
console.error("用法:bfi skills package add-skills <package-ref> [skill-ref...]");
|
|
6882
|
+
console.error(" 不指定技能时,添加命名空间下全部技能");
|
|
7900
6883
|
process.exit(1);
|
|
7901
6884
|
}
|
|
7902
6885
|
const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
|
|
@@ -7913,72 +6896,70 @@ async function handleAdd(args, api, globalOpts) {
|
|
|
7913
6896
|
};
|
|
7914
6897
|
});
|
|
7915
6898
|
if (skills.length === 0) {
|
|
7916
|
-
console.
|
|
7917
|
-
|
|
6899
|
+
console.log(`${YELLOW$1}命名空间 "${namespace}" 中没有技能。${RESET$3}`);
|
|
6900
|
+
return;
|
|
7918
6901
|
}
|
|
7919
6902
|
} catch (error) {
|
|
7920
|
-
console.error(
|
|
6903
|
+
console.error(`${RED$1}获取技能列表失败:${error.message}${RESET$3}`);
|
|
7921
6904
|
process.exit(1);
|
|
7922
6905
|
}
|
|
7923
6906
|
else skills = skillRefs.map((ref) => {
|
|
7924
|
-
const { namespace:
|
|
6907
|
+
const { namespace: ns, slug: s } = parseSkillRef(ref, namespace);
|
|
7925
6908
|
return {
|
|
7926
|
-
namespace:
|
|
7927
|
-
slug:
|
|
6909
|
+
namespace: ns,
|
|
6910
|
+
slug: s
|
|
7928
6911
|
};
|
|
7929
6912
|
});
|
|
7930
6913
|
try {
|
|
7931
6914
|
await api.addSkillsToPackage(namespace, slug, skills);
|
|
7932
6915
|
console.log(`${GREEN$2}✓ 已添加 ${skills.length} 个技能到 ${toSkillRefString(namespace, slug)}${RESET$3}`);
|
|
7933
|
-
for (const s of skills) console.log(` ${DIM$3}- ${toSkillRefString(s.namespace, s.slug)}${RESET$3}`);
|
|
7934
6916
|
} catch (error) {
|
|
7935
|
-
console.error(
|
|
6917
|
+
console.error(`${RED$1}添加失败:${error.message}${RESET$3}`);
|
|
7936
6918
|
process.exit(1);
|
|
7937
6919
|
}
|
|
7938
6920
|
}
|
|
7939
|
-
async function
|
|
6921
|
+
async function handleRemoveSkills(args, api, globalOpts) {
|
|
7940
6922
|
const pkgRef = args[0];
|
|
7941
6923
|
const skillRefs = args.slice(1);
|
|
7942
6924
|
if (!pkgRef) {
|
|
7943
|
-
console.error("用法:bfi skills package remove <package-ref> [skill-ref...]");
|
|
7944
|
-
console.error("
|
|
6925
|
+
console.error("用法:bfi skills package remove-skills <package-ref> [skill-ref...]");
|
|
6926
|
+
console.error(" 不指定技能时,移除包中全部技能");
|
|
7945
6927
|
process.exit(1);
|
|
7946
6928
|
}
|
|
7947
6929
|
const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
|
|
7948
6930
|
let skills;
|
|
7949
6931
|
if (skillRefs.length === 0) try {
|
|
7950
|
-
const
|
|
7951
|
-
|
|
7952
|
-
console.log("包中没有技能。");
|
|
7953
|
-
return;
|
|
7954
|
-
}
|
|
7955
|
-
skills = existingSkills.map((s) => ({
|
|
6932
|
+
const pkgInfo = await api.getPackage(namespace, slug);
|
|
6933
|
+
skills = ((pkgInfo.data || pkgInfo).skills || []).map((s) => ({
|
|
7956
6934
|
namespace: s.namespace || namespace,
|
|
7957
6935
|
slug: s.slug
|
|
7958
6936
|
}));
|
|
6937
|
+
if (skills.length === 0) {
|
|
6938
|
+
console.log("包中没有技能。");
|
|
6939
|
+
return;
|
|
6940
|
+
}
|
|
7959
6941
|
} catch (error) {
|
|
7960
|
-
console.error(
|
|
6942
|
+
console.error(`${RED$1}获取包信息失败:${error.message}${RESET$3}`);
|
|
7961
6943
|
process.exit(1);
|
|
7962
6944
|
}
|
|
7963
6945
|
else skills = skillRefs.map((ref) => {
|
|
7964
|
-
const { namespace:
|
|
6946
|
+
const { namespace: ns, slug: s } = parseSkillRef(ref, namespace);
|
|
7965
6947
|
return {
|
|
7966
|
-
namespace:
|
|
7967
|
-
slug:
|
|
6948
|
+
namespace: ns,
|
|
6949
|
+
slug: s
|
|
7968
6950
|
};
|
|
7969
6951
|
});
|
|
7970
6952
|
try {
|
|
7971
6953
|
await api.removeSkillsFromPackage(namespace, slug, skills);
|
|
7972
|
-
console.log(`${GREEN$2}✓
|
|
7973
|
-
for (const s of skills) console.log(` ${DIM$3}- ${toSkillRefString(s.namespace, s.slug)}${RESET$3}`);
|
|
6954
|
+
console.log(`${GREEN$2}✓ 已从包移除 ${skills.length} 个技能${RESET$3}`);
|
|
7974
6955
|
} catch (error) {
|
|
7975
|
-
console.error(
|
|
6956
|
+
console.error(`${RED$1}移除失败:${error.message}${RESET$3}`);
|
|
7976
6957
|
process.exit(1);
|
|
7977
6958
|
}
|
|
7978
6959
|
}
|
|
7979
6960
|
function getOptionValue(args, flag) {
|
|
7980
6961
|
const idx = args.indexOf(flag);
|
|
7981
|
-
return idx !== -1 && idx
|
|
6962
|
+
return idx !== -1 && args[idx + 1] ? args[idx + 1] : void 0;
|
|
7982
6963
|
}
|
|
7983
6964
|
const RESET$2 = "\x1B[0m";
|
|
7984
6965
|
const DIM$2 = "\x1B[38;5;102m";
|
|
@@ -8427,9 +7408,9 @@ async function main() {
|
|
|
8427
7408
|
globalOpts.workdir = process.cwd();
|
|
8428
7409
|
try {
|
|
8429
7410
|
const { resolveConfig } = await Promise.resolve().then(() => config_exports);
|
|
8430
|
-
const { resolveAgents } = await import("./_chunks/
|
|
7411
|
+
const { resolveAgents } = await import("./_chunks/agents2.mjs");
|
|
8431
7412
|
const { SkillHubAPI } = await Promise.resolve().then(() => api_exports);
|
|
8432
|
-
const { setAgents } = await
|
|
7413
|
+
const { setAgents } = await import("./_chunks/agents.mjs").then((n) => n.agents_exports);
|
|
8433
7414
|
const cfg = resolveConfig(globalOpts);
|
|
8434
7415
|
setAgents(await resolveAgents(cfg.token ? new SkillHubAPI(cfg.registry, cfg.token) : void 0));
|
|
8435
7416
|
} catch {}
|
|
@@ -8545,4 +7526,4 @@ async function main() {
|
|
|
8545
7526
|
}
|
|
8546
7527
|
}
|
|
8547
7528
|
main().finally(() => process.exit(process.exitCode ?? 0));
|
|
8548
|
-
export {
|
|
7529
|
+
export { loadGlobalConfig };
|