skills 1.5.12 → 1.5.14
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/README.md +3 -0
- package/dist/cli.mjs +253 -64
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/cli.mjs
CHANGED
|
@@ -10,6 +10,7 @@ import { t as require_dist } from "./_chunks/libs/@vercel/detect-agent.mjs";
|
|
|
10
10
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "fs";
|
|
11
11
|
import { basename, dirname, extname, isAbsolute, join, normalize, relative, resolve, sep } from "path";
|
|
12
12
|
import { fileURLToPath } from "url";
|
|
13
|
+
import { createHash } from "node:crypto";
|
|
13
14
|
import { stripVTControlCharacters } from "node:util";
|
|
14
15
|
import { homedir, platform, tmpdir } from "os";
|
|
15
16
|
import * as readline from "readline";
|
|
@@ -18,8 +19,7 @@ import { promisify } from "util";
|
|
|
18
19
|
import { execFile, execSync, spawn, spawnSync } from "child_process";
|
|
19
20
|
import { access, cp, lstat, mkdir, mkdtemp, readFile, readdir, readlink, realpath, rm, stat, symlink, writeFile } from "fs/promises";
|
|
20
21
|
import { parse } from "yaml";
|
|
21
|
-
import { createHash } from "crypto";
|
|
22
|
-
import { createHash as createHash$1 } from "node:crypto";
|
|
22
|
+
import { createHash as createHash$1 } from "crypto";
|
|
23
23
|
import { gunzipSync, inflateRawSync } from "node:zlib";
|
|
24
24
|
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
25
25
|
function getOwnerRepo(parsed) {
|
|
@@ -720,7 +720,7 @@ async function computeSkillFolderHash(skillDir) {
|
|
|
720
720
|
const files = [];
|
|
721
721
|
await collectFiles(skillDir, skillDir, files);
|
|
722
722
|
files.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
723
|
-
const hash = createHash("sha256");
|
|
723
|
+
const hash = createHash$1("sha256");
|
|
724
724
|
for (const file of files) {
|
|
725
725
|
hash.update(file.relativePath);
|
|
726
726
|
hash.update(file.content);
|
|
@@ -1617,6 +1617,16 @@ async function detectInstalledAgents() {
|
|
|
1617
1617
|
installed: await config.detectInstalled()
|
|
1618
1618
|
})))).filter((r) => r.installed).map((r) => r.type);
|
|
1619
1619
|
}
|
|
1620
|
+
const EVE_SUBAGENTS_DIR = join("agent", "subagents");
|
|
1621
|
+
function getEveSubagents(cwd = process.cwd()) {
|
|
1622
|
+
const dir = join(cwd, EVE_SUBAGENTS_DIR);
|
|
1623
|
+
if (!existsSync(dir)) return [];
|
|
1624
|
+
try {
|
|
1625
|
+
return readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
1626
|
+
} catch {
|
|
1627
|
+
return [];
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1620
1630
|
function getUniversalAgents() {
|
|
1621
1631
|
return Object.entries(agents).filter(([_, config]) => config.skillsDir === ".agents/skills" && config.showInUniversalList !== false).map(([type]) => type);
|
|
1622
1632
|
}
|
|
@@ -1654,8 +1664,12 @@ async function isDirEntryOrSymlinkToDir(entry, entryPath) {
|
|
|
1654
1664
|
function getCanonicalSkillsDir(global, cwd) {
|
|
1655
1665
|
return join(global ? homedir() : cwd || process.cwd(), AGENTS_DIR$1, SKILLS_SUBDIR);
|
|
1656
1666
|
}
|
|
1657
|
-
function
|
|
1667
|
+
function getEveSubagentSkillsDir(subagent, cwd) {
|
|
1668
|
+
return join(cwd || process.cwd(), EVE_SUBAGENTS_DIR, sanitizeName(subagent), "skills");
|
|
1669
|
+
}
|
|
1670
|
+
function getAgentBaseDir(agentType, global, cwd, eveSubagent) {
|
|
1658
1671
|
if (isUniversalAgent(agentType)) return getCanonicalSkillsDir(global, cwd);
|
|
1672
|
+
if (agentType === "eve" && eveSubagent) return getEveSubagentSkillsDir(eveSubagent, cwd);
|
|
1659
1673
|
const agent = agents[agentType];
|
|
1660
1674
|
const baseDir = global ? homedir() : cwd || process.cwd();
|
|
1661
1675
|
if (global) {
|
|
@@ -1717,6 +1731,7 @@ async function installSkillForAgent(skill, agentType, options = {}) {
|
|
|
1717
1731
|
const agent = agents[agentType];
|
|
1718
1732
|
const isGlobal = options.global ?? false;
|
|
1719
1733
|
const cwd = options.cwd || process.cwd();
|
|
1734
|
+
const eveSubagent = options.eveSubagent;
|
|
1720
1735
|
if (isGlobal && agent.globalSkillsDir === void 0) return {
|
|
1721
1736
|
success: false,
|
|
1722
1737
|
path: "",
|
|
@@ -1725,9 +1740,9 @@ async function installSkillForAgent(skill, agentType, options = {}) {
|
|
|
1725
1740
|
};
|
|
1726
1741
|
const skillName = sanitizeName(skill.name || basename(skill.path));
|
|
1727
1742
|
const installMode = options.mode ?? "symlink";
|
|
1728
|
-
const canonicalBase = agentType === "eve" && installMode === "symlink" ? getAgentBaseDir(agentType, isGlobal, cwd) : getCanonicalSkillsDir(isGlobal, cwd);
|
|
1743
|
+
const canonicalBase = agentType === "eve" && installMode === "symlink" ? getAgentBaseDir(agentType, isGlobal, cwd, eveSubagent) : getCanonicalSkillsDir(isGlobal, cwd);
|
|
1729
1744
|
const canonicalDir = join(canonicalBase, skillName);
|
|
1730
|
-
const agentBase = getAgentBaseDir(agentType, isGlobal, cwd);
|
|
1745
|
+
const agentBase = getAgentBaseDir(agentType, isGlobal, cwd, eveSubagent);
|
|
1731
1746
|
const agentDir = join(agentBase, skillName);
|
|
1732
1747
|
if (!isPathSafe$1(canonicalBase, canonicalDir)) return {
|
|
1733
1748
|
success: false,
|
|
@@ -1869,7 +1884,7 @@ async function isSkillInstalled(skillName, agentType, options = {}) {
|
|
|
1869
1884
|
const agent = agents[agentType];
|
|
1870
1885
|
const sanitized = sanitizeName(skillName);
|
|
1871
1886
|
if (options.global && agent.globalSkillsDir === void 0) return false;
|
|
1872
|
-
const targetBase = options.global ? agent.globalSkillsDir : join(options.cwd || process.cwd(), agent.skillsDir);
|
|
1887
|
+
const targetBase = options.global ? agent.globalSkillsDir : agentType === "eve" && options.eveSubagent ? getEveSubagentSkillsDir(options.eveSubagent, options.cwd) : join(options.cwd || process.cwd(), agent.skillsDir);
|
|
1873
1888
|
const skillDir = join(targetBase, sanitized);
|
|
1874
1889
|
if (!isPathSafe$1(targetBase, skillDir)) return false;
|
|
1875
1890
|
try {
|
|
@@ -1883,14 +1898,14 @@ function getInstallPath(skillName, agentType, options = {}) {
|
|
|
1883
1898
|
agents[agentType];
|
|
1884
1899
|
options.cwd || process.cwd();
|
|
1885
1900
|
const sanitized = sanitizeName(skillName);
|
|
1886
|
-
const targetBase = getAgentBaseDir(agentType, options.global ?? false, options.cwd);
|
|
1901
|
+
const targetBase = getAgentBaseDir(agentType, options.global ?? false, options.cwd, options.eveSubagent);
|
|
1887
1902
|
const installPath = join(targetBase, sanitized);
|
|
1888
1903
|
if (!isPathSafe$1(targetBase, installPath)) throw new Error("Invalid skill name: potential path traversal detected");
|
|
1889
1904
|
return installPath;
|
|
1890
1905
|
}
|
|
1891
1906
|
function getCanonicalPath(skillName, options = {}) {
|
|
1892
1907
|
const sanitized = sanitizeName(skillName);
|
|
1893
|
-
const canonicalBase = options.agent === "eve" ? getAgentBaseDir("eve", options.global ?? false, options.cwd) : getCanonicalSkillsDir(options.global ?? false, options.cwd);
|
|
1908
|
+
const canonicalBase = options.agent === "eve" ? getAgentBaseDir("eve", options.global ?? false, options.cwd, options.eveSubagent) : getCanonicalSkillsDir(options.global ?? false, options.cwd);
|
|
1894
1909
|
const canonicalPath = join(canonicalBase, sanitized);
|
|
1895
1910
|
if (!isPathSafe$1(canonicalBase, canonicalPath)) throw new Error("Invalid skill name: potential path traversal detected");
|
|
1896
1911
|
return canonicalPath;
|
|
@@ -1900,6 +1915,7 @@ async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
|
|
|
1900
1915
|
const isGlobal = options.global ?? false;
|
|
1901
1916
|
const cwd = options.cwd || process.cwd();
|
|
1902
1917
|
const installMode = options.mode ?? "symlink";
|
|
1918
|
+
const eveSubagent = options.eveSubagent;
|
|
1903
1919
|
if (isGlobal && agent.globalSkillsDir === void 0) return {
|
|
1904
1920
|
success: false,
|
|
1905
1921
|
path: "",
|
|
@@ -1907,9 +1923,9 @@ async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
|
|
|
1907
1923
|
error: `${agent.displayName} does not support global skill installation`
|
|
1908
1924
|
};
|
|
1909
1925
|
const skillName = sanitizeName(skill.installName);
|
|
1910
|
-
const canonicalBase = agentType === "eve" && installMode === "symlink" ? getAgentBaseDir(agentType, isGlobal, cwd) : getCanonicalSkillsDir(isGlobal, cwd);
|
|
1926
|
+
const canonicalBase = agentType === "eve" && installMode === "symlink" ? getAgentBaseDir(agentType, isGlobal, cwd, eveSubagent) : getCanonicalSkillsDir(isGlobal, cwd);
|
|
1911
1927
|
const canonicalDir = join(canonicalBase, skillName);
|
|
1912
|
-
const agentBase = getAgentBaseDir(agentType, isGlobal, cwd);
|
|
1928
|
+
const agentBase = getAgentBaseDir(agentType, isGlobal, cwd, eveSubagent);
|
|
1913
1929
|
const agentDir = join(agentBase, skillName);
|
|
1914
1930
|
if (!isPathSafe$1(canonicalBase, canonicalDir)) return {
|
|
1915
1931
|
success: false,
|
|
@@ -1981,6 +1997,7 @@ async function installBlobSkillForAgent(skill, agentType, options = {}) {
|
|
|
1981
1997
|
const isGlobal = options.global ?? false;
|
|
1982
1998
|
const cwd = options.cwd || process.cwd();
|
|
1983
1999
|
const installMode = options.mode ?? "symlink";
|
|
2000
|
+
const eveSubagent = options.eveSubagent;
|
|
1984
2001
|
if (isGlobal && agent.globalSkillsDir === void 0) return {
|
|
1985
2002
|
success: false,
|
|
1986
2003
|
path: "",
|
|
@@ -1988,7 +2005,7 @@ async function installBlobSkillForAgent(skill, agentType, options = {}) {
|
|
|
1988
2005
|
error: `${agent.displayName} does not support global skill installation`
|
|
1989
2006
|
};
|
|
1990
2007
|
const skillName = sanitizeName(skill.installName);
|
|
1991
|
-
const agentBase = getAgentBaseDir(agentType, isGlobal, cwd);
|
|
2008
|
+
const agentBase = getAgentBaseDir(agentType, isGlobal, cwd, eveSubagent);
|
|
1992
2009
|
if (agentType === "eve" && !isEvePackagedSkill(skill.files)) {
|
|
1993
2010
|
const flatSkillPath = join(agentBase, toEveFlatSkillFileName(skill.installName));
|
|
1994
2011
|
if (!isPathSafe$1(agentBase, flatSkillPath)) return {
|
|
@@ -2018,7 +2035,7 @@ async function installBlobSkillForAgent(skill, agentType, options = {}) {
|
|
|
2018
2035
|
};
|
|
2019
2036
|
}
|
|
2020
2037
|
}
|
|
2021
|
-
const canonicalBase = agentType === "eve" && installMode === "symlink" ? getAgentBaseDir(agentType, isGlobal, cwd) : getCanonicalSkillsDir(isGlobal, cwd);
|
|
2038
|
+
const canonicalBase = agentType === "eve" && installMode === "symlink" ? getAgentBaseDir(agentType, isGlobal, cwd, eveSubagent) : getCanonicalSkillsDir(isGlobal, cwd);
|
|
2022
2039
|
const canonicalDir = join(canonicalBase, skillName);
|
|
2023
2040
|
const agentDir = join(agentBase, skillName);
|
|
2024
2041
|
if (!isPathSafe$1(canonicalBase, canonicalDir)) return {
|
|
@@ -2119,6 +2136,14 @@ async function listInstalledSkills(options = {}) {
|
|
|
2119
2136
|
path: agentDir,
|
|
2120
2137
|
agentType
|
|
2121
2138
|
});
|
|
2139
|
+
if (agentType === "eve" && !isGlobal) for (const subagent of getEveSubagents(cwd)) {
|
|
2140
|
+
const subagentDir = getEveSubagentSkillsDir(subagent, cwd);
|
|
2141
|
+
if (!scopes.some((s) => s.path === subagentDir && s.global === isGlobal)) scopes.push({
|
|
2142
|
+
global: isGlobal,
|
|
2143
|
+
path: subagentDir,
|
|
2144
|
+
agentType
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2122
2147
|
}
|
|
2123
2148
|
const allAgentTypes = Object.keys(agents);
|
|
2124
2149
|
for (const agentType of allAgentTypes) {
|
|
@@ -2623,7 +2648,7 @@ var WellKnownProvider = class {
|
|
|
2623
2648
|
}
|
|
2624
2649
|
}
|
|
2625
2650
|
computeDigest(bytes) {
|
|
2626
|
-
return `sha256:${createHash
|
|
2651
|
+
return `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
|
|
2627
2652
|
}
|
|
2628
2653
|
extractArchive(bytes, artifactUrl, contentType) {
|
|
2629
2654
|
if (this.isZipArchive(bytes, artifactUrl, contentType)) return this.extractZip(bytes);
|
|
@@ -3041,6 +3066,14 @@ async function fetchSkillDownload(source, slug) {
|
|
|
3041
3066
|
return null;
|
|
3042
3067
|
}
|
|
3043
3068
|
}
|
|
3069
|
+
function computeSnapshotHash(files) {
|
|
3070
|
+
const hash = createHash("sha256");
|
|
3071
|
+
for (const file of [...files].sort((a, b) => a.path.localeCompare(b.path))) {
|
|
3072
|
+
hash.update(file.path);
|
|
3073
|
+
hash.update(file.contents);
|
|
3074
|
+
}
|
|
3075
|
+
return hash.digest("hex");
|
|
3076
|
+
}
|
|
3044
3077
|
async function tryBlobInstall(ownerRepo, options = {}) {
|
|
3045
3078
|
const tree = await fetchRepoTree(ownerRepo, options.ref, options.getToken);
|
|
3046
3079
|
if (!tree) return null;
|
|
@@ -3099,23 +3132,24 @@ async function tryBlobInstall(ownerRepo, options = {}) {
|
|
|
3099
3132
|
return {
|
|
3100
3133
|
skills: downloads.map(({ skill, download }) => {
|
|
3101
3134
|
const mdPathLower = skill.mdPath.toLowerCase();
|
|
3102
|
-
mdPathLower.endsWith("/skill.md") ? skill.mdPath.slice(0, -9) : mdPathLower === "skill.md"
|
|
3135
|
+
const files = (mdPathLower.endsWith("/skill.md") ? skill.mdPath.slice(0, -9) : mdPathLower === "skill.md" ? "" : skill.mdPath.slice(0, -9)) ? download.files : download.files.filter((file) => file.path.toLowerCase() === "skill.md");
|
|
3103
3136
|
return {
|
|
3104
3137
|
name: skill.name,
|
|
3105
3138
|
description: skill.description,
|
|
3106
3139
|
path: "",
|
|
3107
3140
|
rawContent: skill.content,
|
|
3108
3141
|
metadata: skill.metadata,
|
|
3109
|
-
files
|
|
3110
|
-
snapshotHash: download.hash,
|
|
3142
|
+
files,
|
|
3143
|
+
snapshotHash: files.length === download.files.length ? download.hash : computeSnapshotHash(files),
|
|
3111
3144
|
repoPath: skill.mdPath
|
|
3112
3145
|
};
|
|
3113
3146
|
}),
|
|
3114
3147
|
tree
|
|
3115
3148
|
};
|
|
3116
3149
|
}
|
|
3117
|
-
var version$1 = "1.5.
|
|
3150
|
+
var version$1 = "1.5.14";
|
|
3118
3151
|
const isCancelled$1 = (value) => typeof value === "symbol";
|
|
3152
|
+
const EVE_AGENT_LABEL = "eve agent";
|
|
3119
3153
|
async function isSourcePrivate(source) {
|
|
3120
3154
|
const ownerRepo = parseOwnerRepo(source);
|
|
3121
3155
|
if (!ownerRepo) return false;
|
|
@@ -3175,12 +3209,25 @@ function shortenPath$2(fullPath, cwd) {
|
|
|
3175
3209
|
if (fullPath === cwd || fullPath.startsWith(cwd + sep)) return "." + fullPath.slice(cwd.length);
|
|
3176
3210
|
return fullPath;
|
|
3177
3211
|
}
|
|
3212
|
+
function computeSingleFileSkillHash(contents) {
|
|
3213
|
+
const hash = createHash("sha256");
|
|
3214
|
+
hash.update("SKILL.md");
|
|
3215
|
+
hash.update(contents);
|
|
3216
|
+
return hash.digest("hex");
|
|
3217
|
+
}
|
|
3178
3218
|
function formatList$1(items, maxShow = 5) {
|
|
3179
3219
|
if (items.length <= maxShow) return items.join(", ");
|
|
3180
3220
|
const shown = items.slice(0, maxShow);
|
|
3181
3221
|
const remaining = items.length - maxShow;
|
|
3182
3222
|
return `${shown.join(", ")} +${remaining} more`;
|
|
3183
3223
|
}
|
|
3224
|
+
function formatSkillPromptSubject(skills) {
|
|
3225
|
+
const namedSubject = formatList$1(skills.map((skill) => import_picocolors.default.cyan(getSkillDisplayName(skill))), 3);
|
|
3226
|
+
return stripTerminalEscapes(namedSubject).length <= 80 ? namedSubject : `${skills.length} selected skills`;
|
|
3227
|
+
}
|
|
3228
|
+
function formatEveInstallPromptMessage(skills) {
|
|
3229
|
+
return `Detected an eve project. Install ${formatSkillPromptSubject(skills)} for your ${EVE_AGENT_LABEL} to use?`;
|
|
3230
|
+
}
|
|
3184
3231
|
function splitAgentsByType(agentTypes) {
|
|
3185
3232
|
const universal = [];
|
|
3186
3233
|
const symlinked = [];
|
|
@@ -3203,6 +3250,37 @@ function buildAgentSummaryLines(targetAgents, installMode) {
|
|
|
3203
3250
|
}
|
|
3204
3251
|
return lines;
|
|
3205
3252
|
}
|
|
3253
|
+
function targetDisplayName(target) {
|
|
3254
|
+
const base = agents[target.agent].displayName;
|
|
3255
|
+
return target.subagent ? `${base} (${target.subagent})` : base;
|
|
3256
|
+
}
|
|
3257
|
+
function targetKey(target) {
|
|
3258
|
+
return target.subagent ? `${target.agent}:${target.subagent}` : target.agent;
|
|
3259
|
+
}
|
|
3260
|
+
function buildInstallTargets(targetAgents, eveSubagentTargets) {
|
|
3261
|
+
const targets = [];
|
|
3262
|
+
for (const agent of targetAgents) if (agent === "eve") for (const subagent of eveSubagentTargets) targets.push({
|
|
3263
|
+
agent,
|
|
3264
|
+
subagent
|
|
3265
|
+
});
|
|
3266
|
+
else targets.push({ agent });
|
|
3267
|
+
return targets;
|
|
3268
|
+
}
|
|
3269
|
+
function buildTargetSummaryLines(targets, installMode) {
|
|
3270
|
+
const lines = [];
|
|
3271
|
+
const rootAgents = targets.filter((t) => !t.subagent).map((t) => t.agent);
|
|
3272
|
+
const subagentNames = targets.filter((t) => t.subagent).map(targetDisplayName);
|
|
3273
|
+
const { universal, symlinked } = splitAgentsByType(rootAgents);
|
|
3274
|
+
if (installMode === "symlink") {
|
|
3275
|
+
if (universal.length > 0) lines.push(` ${import_picocolors.default.green("universal:")} ${formatList$1(universal)}`);
|
|
3276
|
+
if (symlinked.length > 0) lines.push(` ${import_picocolors.default.dim("symlink →")} ${formatList$1(symlinked)}`);
|
|
3277
|
+
if (subagentNames.length > 0) lines.push(` ${import_picocolors.default.dim("copy →")} ${formatList$1(subagentNames)}`);
|
|
3278
|
+
} else {
|
|
3279
|
+
const allNames = targets.map(targetDisplayName);
|
|
3280
|
+
lines.push(` ${import_picocolors.default.dim("copy →")} ${formatList$1(allNames)}`);
|
|
3281
|
+
}
|
|
3282
|
+
return lines;
|
|
3283
|
+
}
|
|
3206
3284
|
function ensureUniversalAgents(targetAgents) {
|
|
3207
3285
|
const universalAgents = getUniversalAgents();
|
|
3208
3286
|
const result = [...targetAgents];
|
|
@@ -3617,16 +3695,6 @@ async function runAdd(args, options = {}) {
|
|
|
3617
3695
|
if (!ownerRepo) return Promise.resolve(null);
|
|
3618
3696
|
return isRepoPrivate(ownerRepo.owner, ownerRepo.repo).catch(() => null);
|
|
3619
3697
|
})();
|
|
3620
|
-
if (ownerRepoRaw?.split("/")[0]?.toLowerCase() === "openclaw" && !options.dangerouslyAcceptOpenclawRisks) {
|
|
3621
|
-
console.log();
|
|
3622
|
-
M.warn(import_picocolors.default.yellow(import_picocolors.default.bold("⚠ OpenClaw skills are unverified community submissions.")));
|
|
3623
|
-
M.message(import_picocolors.default.yellow("This source contains user-submitted skills that have not been reviewed for safety or quality."));
|
|
3624
|
-
M.message(import_picocolors.default.yellow("Skills run with full agent permissions and could be malicious."));
|
|
3625
|
-
console.log();
|
|
3626
|
-
M.message(`If you understand the risks, re-run with:\n\n ${import_picocolors.default.cyan(`npx skills add ${source} --dangerously-accept-openclaw-risks`)}\n`);
|
|
3627
|
-
Se(import_picocolors.default.red("Installation blocked"));
|
|
3628
|
-
process.exit(1);
|
|
3629
|
-
}
|
|
3630
3698
|
if (parsed.type === "well-known") {
|
|
3631
3699
|
await handleWellKnownSkills(source, parsed.url, options, spinner);
|
|
3632
3700
|
return;
|
|
@@ -3820,7 +3888,7 @@ async function runAdd(args, options = {}) {
|
|
|
3820
3888
|
spinner.stop(`${totalAgents} agents`);
|
|
3821
3889
|
if (installedAgents.includes("eve") && (options.yes || !agentResult.isAgent)) {
|
|
3822
3890
|
const useEve = options.yes ? true : await ye({
|
|
3823
|
-
message:
|
|
3891
|
+
message: formatEveInstallPromptMessage(selectedSkills),
|
|
3824
3892
|
initialValue: true
|
|
3825
3893
|
});
|
|
3826
3894
|
if (pD(useEve)) {
|
|
@@ -3830,7 +3898,7 @@ async function runAdd(args, options = {}) {
|
|
|
3830
3898
|
}
|
|
3831
3899
|
if (useEve) {
|
|
3832
3900
|
targetAgents = ["eve"];
|
|
3833
|
-
M.info(`Installing to: ${import_picocolors.default.cyan(
|
|
3901
|
+
M.info(`Installing to: ${import_picocolors.default.cyan(EVE_AGENT_LABEL)}`);
|
|
3834
3902
|
} else {
|
|
3835
3903
|
const selected = await selectAgentsInteractive({ global: options.global });
|
|
3836
3904
|
if (pD(selected)) {
|
|
@@ -3872,6 +3940,35 @@ async function runAdd(args, options = {}) {
|
|
|
3872
3940
|
targetAgents = selected;
|
|
3873
3941
|
}
|
|
3874
3942
|
}
|
|
3943
|
+
if (options.subagent && options.subagent.length > 0 && !targetAgents.includes("eve")) targetAgents = [...targetAgents, "eve"];
|
|
3944
|
+
let eveSubagentTargets = [void 0];
|
|
3945
|
+
if (targetAgents.includes("eve")) {
|
|
3946
|
+
const availableSubagents = getEveSubagents(process.cwd());
|
|
3947
|
+
if (options.subagent && options.subagent.length > 0) eveSubagentTargets = options.subagent.map((s) => s === "root" || s === "." ? void 0 : s);
|
|
3948
|
+
else if (availableSubagents.length > 0 && !options.yes) {
|
|
3949
|
+
const selectedSubagents = await fe({
|
|
3950
|
+
message: "Where should Eve skills be installed?",
|
|
3951
|
+
options: [{
|
|
3952
|
+
value: "",
|
|
3953
|
+
label: "Root agent",
|
|
3954
|
+
hint: "agent/skills"
|
|
3955
|
+
}, ...availableSubagents.map((name) => ({
|
|
3956
|
+
value: name,
|
|
3957
|
+
label: name,
|
|
3958
|
+
hint: `agent/subagents/${name}/skills`
|
|
3959
|
+
}))],
|
|
3960
|
+
initialValues: [""],
|
|
3961
|
+
required: true
|
|
3962
|
+
});
|
|
3963
|
+
if (pD(selectedSubagents)) {
|
|
3964
|
+
xe("Installation cancelled");
|
|
3965
|
+
await cleanup(tempDir);
|
|
3966
|
+
process.exit(0);
|
|
3967
|
+
}
|
|
3968
|
+
eveSubagentTargets = selectedSubagents.map((s) => s === "" ? void 0 : s);
|
|
3969
|
+
}
|
|
3970
|
+
}
|
|
3971
|
+
const installTargets = buildInstallTargets(targetAgents, eveSubagentTargets);
|
|
3875
3972
|
let installGlobally = options.global ?? false;
|
|
3876
3973
|
const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== void 0);
|
|
3877
3974
|
if (options.global === void 0 && !options.yes && supportsGlobal) {
|
|
@@ -3895,8 +3992,9 @@ async function runAdd(args, options = {}) {
|
|
|
3895
3992
|
installGlobally = scope;
|
|
3896
3993
|
}
|
|
3897
3994
|
let installMode = options.copy ? "copy" : "symlink";
|
|
3898
|
-
const
|
|
3899
|
-
|
|
3995
|
+
const allEve = installTargets.every((t) => t.agent === "eve");
|
|
3996
|
+
const uniqueDirs = new Set(installTargets.map((t) => t.subagent ? `eve:subagent:${t.subagent}` : agents[t.agent].skillsDir));
|
|
3997
|
+
if (!options.copy && !options.yes && uniqueDirs.size > 1 && !allEve) {
|
|
3900
3998
|
const modeChoice = await ve({
|
|
3901
3999
|
message: "Installation method",
|
|
3902
4000
|
options: [{
|
|
@@ -3915,19 +4013,21 @@ async function runAdd(args, options = {}) {
|
|
|
3915
4013
|
process.exit(0);
|
|
3916
4014
|
}
|
|
3917
4015
|
installMode = modeChoice;
|
|
3918
|
-
} else if (uniqueDirs.size <= 1) installMode = "copy";
|
|
4016
|
+
} else if (uniqueDirs.size <= 1 || allEve) installMode = "copy";
|
|
3919
4017
|
const cwd = process.cwd();
|
|
3920
4018
|
const summaryLines = [];
|
|
3921
|
-
|
|
3922
|
-
const overwriteChecks = await Promise.all(selectedSkills.flatMap((skill) => targetAgents.map(async (agent) => ({
|
|
4019
|
+
const overwriteChecks = await Promise.all(selectedSkills.flatMap((skill) => installTargets.map(async (target) => ({
|
|
3923
4020
|
skillName: skill.name,
|
|
3924
|
-
|
|
3925
|
-
installed: await isSkillInstalled(skill.name, agent, {
|
|
4021
|
+
target,
|
|
4022
|
+
installed: await isSkillInstalled(skill.name, target.agent, {
|
|
4023
|
+
global: installGlobally,
|
|
4024
|
+
eveSubagent: target.subagent
|
|
4025
|
+
})
|
|
3926
4026
|
}))));
|
|
3927
4027
|
const overwriteStatus = /* @__PURE__ */ new Map();
|
|
3928
|
-
for (const { skillName,
|
|
4028
|
+
for (const { skillName, target, installed } of overwriteChecks) {
|
|
3929
4029
|
if (!overwriteStatus.has(skillName)) overwriteStatus.set(skillName, /* @__PURE__ */ new Map());
|
|
3930
|
-
overwriteStatus.get(skillName).set(
|
|
4030
|
+
overwriteStatus.get(skillName).set(targetKey(target), installed);
|
|
3931
4031
|
}
|
|
3932
4032
|
const groupedSummary = {};
|
|
3933
4033
|
const ungroupedSummary = [];
|
|
@@ -3939,14 +4039,15 @@ async function runAdd(args, options = {}) {
|
|
|
3939
4039
|
const printSkillSummary = (skills) => {
|
|
3940
4040
|
for (const skill of skills) {
|
|
3941
4041
|
if (summaryLines.length > 0) summaryLines.push("");
|
|
3942
|
-
const shortCanonical = shortenPath$2(
|
|
4042
|
+
const shortCanonical = shortenPath$2(installTargets.length === 1 ? getCanonicalPath(skill.name, {
|
|
3943
4043
|
global: installGlobally,
|
|
3944
|
-
agent:
|
|
4044
|
+
agent: installTargets[0].agent,
|
|
4045
|
+
eveSubagent: installTargets[0].subagent
|
|
3945
4046
|
}) : getCanonicalPath(skill.name, { global: installGlobally }), cwd);
|
|
3946
4047
|
summaryLines.push(`${import_picocolors.default.cyan(shortCanonical)}`);
|
|
3947
|
-
summaryLines.push(...
|
|
4048
|
+
summaryLines.push(...buildTargetSummaryLines(installTargets, installMode));
|
|
3948
4049
|
const skillOverwrites = overwriteStatus.get(skill.name);
|
|
3949
|
-
const overwriteAgents =
|
|
4050
|
+
const overwriteAgents = installTargets.filter((t) => skillOverwrites?.get(targetKey(t))).map(targetDisplayName);
|
|
3950
4051
|
if (overwriteAgents.length > 0) summaryLines.push(` ${import_picocolors.default.yellow("overwrites:")} ${formatList$1(overwriteAgents)}`);
|
|
3951
4052
|
}
|
|
3952
4053
|
};
|
|
@@ -3986,7 +4087,8 @@ async function runAdd(args, options = {}) {
|
|
|
3986
4087
|
}
|
|
3987
4088
|
spinner.start("Installing skills...");
|
|
3988
4089
|
const results = [];
|
|
3989
|
-
for (const skill of selectedSkills) for (const
|
|
4090
|
+
for (const skill of selectedSkills) for (const target of installTargets) {
|
|
4091
|
+
const { agent, subagent } = target;
|
|
3990
4092
|
let result;
|
|
3991
4093
|
if (blobResult && "files" in skill) {
|
|
3992
4094
|
const blobSkill = skill;
|
|
@@ -3995,15 +4097,27 @@ async function runAdd(args, options = {}) {
|
|
|
3995
4097
|
files: blobSkill.files
|
|
3996
4098
|
}, agent, {
|
|
3997
4099
|
global: installGlobally,
|
|
3998
|
-
mode: installMode
|
|
4100
|
+
mode: installMode,
|
|
4101
|
+
eveSubagent: subagent
|
|
3999
4102
|
});
|
|
4000
|
-
} else result = await
|
|
4103
|
+
} else if (tempDir && skill.path === tempDir && skill.rawContent) result = await installBlobSkillForAgent({
|
|
4104
|
+
installName: skill.name,
|
|
4105
|
+
files: [{
|
|
4106
|
+
path: "SKILL.md",
|
|
4107
|
+
contents: skill.rawContent
|
|
4108
|
+
}]
|
|
4109
|
+
}, agent, {
|
|
4001
4110
|
global: installGlobally,
|
|
4002
4111
|
mode: installMode
|
|
4003
4112
|
});
|
|
4113
|
+
else result = await installSkillForAgent(skill, agent, {
|
|
4114
|
+
global: installGlobally,
|
|
4115
|
+
mode: installMode,
|
|
4116
|
+
eveSubagent: subagent
|
|
4117
|
+
});
|
|
4004
4118
|
results.push({
|
|
4005
4119
|
skill: getSkillDisplayName(skill),
|
|
4006
|
-
agent:
|
|
4120
|
+
agent: targetDisplayName(target),
|
|
4007
4121
|
pluginName: skill.pluginName,
|
|
4008
4122
|
...result
|
|
4009
4123
|
});
|
|
@@ -4069,17 +4183,20 @@ async function runAdd(args, options = {}) {
|
|
|
4069
4183
|
}
|
|
4070
4184
|
if (successful.length > 0 && !installGlobally) {
|
|
4071
4185
|
const successfulSkillNames = new Set(successful.map((r) => r.skill));
|
|
4186
|
+
const eveSubagents = targetAgents.includes("eve") ? eveSubagentTargets.map((s) => s ?? "") : void 0;
|
|
4187
|
+
const recordSubagents = eveSubagents && (eveSubagents.length > 1 || eveSubagents.some((s) => s !== ""));
|
|
4072
4188
|
for (const skill of selectedSkills) {
|
|
4073
4189
|
const skillDisplayName = getSkillDisplayName(skill);
|
|
4074
4190
|
if (successfulSkillNames.has(skillDisplayName)) try {
|
|
4075
|
-
const computedHash = blobResult && "snapshotHash" in skill ? skill.snapshotHash : await computeSkillFolderHash(skill.path);
|
|
4191
|
+
const computedHash = blobResult && "snapshotHash" in skill ? skill.snapshotHash : tempDir && skill.path === tempDir && skill.rawContent ? computeSingleFileSkillHash(skill.rawContent) : await computeSkillFolderHash(skill.path);
|
|
4076
4192
|
const skillPathValue = skillFiles[skill.name];
|
|
4077
4193
|
await addSkillToLocalLock(skill.name, {
|
|
4078
4194
|
source: lockSource || parsed.url,
|
|
4079
4195
|
ref: parsed.ref,
|
|
4080
4196
|
sourceType: parsed.type,
|
|
4081
4197
|
...skillPathValue && { skillPath: skillPathValue },
|
|
4082
|
-
computedHash
|
|
4198
|
+
computedHash,
|
|
4199
|
+
...recordSubagents && { subagents: eveSubagents }
|
|
4083
4200
|
}, cwd);
|
|
4084
4201
|
} catch {}
|
|
4085
4202
|
}
|
|
@@ -4237,8 +4354,17 @@ function parseAddOptions(args) {
|
|
|
4237
4354
|
i--;
|
|
4238
4355
|
} else if (arg === "--full-depth") options.fullDepth = true;
|
|
4239
4356
|
else if (arg === "--copy") options.copy = true;
|
|
4240
|
-
else if (arg === "--
|
|
4241
|
-
|
|
4357
|
+
else if (arg === "--subagent") {
|
|
4358
|
+
options.subagent = options.subagent || [];
|
|
4359
|
+
i++;
|
|
4360
|
+
let nextArg = args[i];
|
|
4361
|
+
while (i < args.length && nextArg && !nextArg.startsWith("-")) {
|
|
4362
|
+
options.subagent.push(nextArg);
|
|
4363
|
+
i++;
|
|
4364
|
+
nextArg = args[i];
|
|
4365
|
+
}
|
|
4366
|
+
i--;
|
|
4367
|
+
} else if (arg && !arg.startsWith("-")) source.push(arg);
|
|
4242
4368
|
}
|
|
4243
4369
|
return {
|
|
4244
4370
|
source,
|
|
@@ -4257,9 +4383,54 @@ function formatInstalls(count) {
|
|
|
4257
4383
|
if (count >= 1e3) return `${(count / 1e3).toFixed(1).replace(/\.0$/, "")}K installs`;
|
|
4258
4384
|
return `${count} install${count === 1 ? "" : "s"}`;
|
|
4259
4385
|
}
|
|
4260
|
-
|
|
4386
|
+
const GITHUB_OWNER_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,38})$/i;
|
|
4387
|
+
function parseFindOptions(args) {
|
|
4388
|
+
const queryParts = [];
|
|
4389
|
+
const options = {};
|
|
4390
|
+
const errors = [];
|
|
4391
|
+
for (let i = 0; i < args.length; i++) {
|
|
4392
|
+
const arg = args[i];
|
|
4393
|
+
if (!arg) continue;
|
|
4394
|
+
let ownerValue;
|
|
4395
|
+
if (arg === "--owner") {
|
|
4396
|
+
const value = args[i + 1];
|
|
4397
|
+
if (!value || value.startsWith("-")) {
|
|
4398
|
+
errors.push("--owner requires a GitHub owner");
|
|
4399
|
+
continue;
|
|
4400
|
+
}
|
|
4401
|
+
ownerValue = value;
|
|
4402
|
+
i++;
|
|
4403
|
+
} else if (arg.startsWith("--owner=")) {
|
|
4404
|
+
ownerValue = arg.slice(8);
|
|
4405
|
+
if (!ownerValue) {
|
|
4406
|
+
errors.push("--owner requires a GitHub owner");
|
|
4407
|
+
continue;
|
|
4408
|
+
}
|
|
4409
|
+
} else {
|
|
4410
|
+
queryParts.push(arg);
|
|
4411
|
+
continue;
|
|
4412
|
+
}
|
|
4413
|
+
const owner = ownerValue.trim().toLowerCase();
|
|
4414
|
+
if (!GITHUB_OWNER_PATTERN.test(owner)) {
|
|
4415
|
+
errors.push("--owner must be a valid GitHub owner");
|
|
4416
|
+
continue;
|
|
4417
|
+
}
|
|
4418
|
+
options.owner = owner;
|
|
4419
|
+
}
|
|
4420
|
+
return {
|
|
4421
|
+
query: queryParts.join(" "),
|
|
4422
|
+
options,
|
|
4423
|
+
errors
|
|
4424
|
+
};
|
|
4425
|
+
}
|
|
4426
|
+
async function searchSkillsAPI(query, owner) {
|
|
4261
4427
|
try {
|
|
4262
|
-
const
|
|
4428
|
+
const params = new URLSearchParams({
|
|
4429
|
+
q: query,
|
|
4430
|
+
limit: "10"
|
|
4431
|
+
});
|
|
4432
|
+
if (owner) params.set("owner", owner);
|
|
4433
|
+
const url = `${SEARCH_API_BASE}/api/search?${params.toString()}`;
|
|
4263
4434
|
const res = await fetch(url);
|
|
4264
4435
|
if (!res.ok) return [];
|
|
4265
4436
|
return (await res.json()).skills.map((skill) => ({
|
|
@@ -4277,7 +4448,7 @@ const SHOW_CURSOR = "\x1B[?25h";
|
|
|
4277
4448
|
const CLEAR_DOWN = "\x1B[J";
|
|
4278
4449
|
const MOVE_UP = (n) => `\x1b[${n}A`;
|
|
4279
4450
|
const MOVE_TO_COL = (n) => `\x1b[${n}G`;
|
|
4280
|
-
async function runSearchPrompt(initialQuery = "") {
|
|
4451
|
+
async function runSearchPrompt(initialQuery = "", owner) {
|
|
4281
4452
|
let results = [];
|
|
4282
4453
|
let selectedIndex = 0;
|
|
4283
4454
|
let query = initialQuery;
|
|
@@ -4334,7 +4505,7 @@ async function runSearchPrompt(initialQuery = "") {
|
|
|
4334
4505
|
const debounceMs = Math.max(150, 350 - q.length * 50);
|
|
4335
4506
|
debounceTimer = setTimeout(async () => {
|
|
4336
4507
|
try {
|
|
4337
|
-
results = await searchSkillsAPI(q);
|
|
4508
|
+
results = await searchSkillsAPI(q, owner);
|
|
4338
4509
|
selectedIndex = 0;
|
|
4339
4510
|
} catch {
|
|
4340
4511
|
results = [];
|
|
@@ -4407,20 +4578,27 @@ async function isRepoPublic(owner, repo) {
|
|
|
4407
4578
|
return await isRepoPrivate(owner, repo) === false;
|
|
4408
4579
|
}
|
|
4409
4580
|
async function runFind(args) {
|
|
4410
|
-
const query = args
|
|
4581
|
+
const { query, options: findOptions, errors } = parseFindOptions(args);
|
|
4582
|
+
const owner = findOptions.owner;
|
|
4411
4583
|
const isNonInteractive = !process.stdin.isTTY;
|
|
4412
4584
|
const agentTip = `${DIM$3}Tip: if running in a coding agent, follow these steps:${RESET$3}
|
|
4413
|
-
${DIM$3} 1) npx skills find [query]${RESET$3}
|
|
4585
|
+
${DIM$3} 1) npx skills find [query] [--owner <owner>]${RESET$3}
|
|
4414
4586
|
${DIM$3} 2) npx skills add <owner/repo@skill>${RESET$3}`;
|
|
4587
|
+
if (errors.length > 0) {
|
|
4588
|
+
for (const error of errors) console.error(error);
|
|
4589
|
+
console.error("Usage: npx skills find <query> [--owner <owner>]");
|
|
4590
|
+
return;
|
|
4591
|
+
}
|
|
4415
4592
|
if (query) {
|
|
4416
|
-
const results = await searchSkillsAPI(query);
|
|
4593
|
+
const results = await searchSkillsAPI(query, owner);
|
|
4417
4594
|
track({
|
|
4418
4595
|
event: "find",
|
|
4419
4596
|
query,
|
|
4420
4597
|
resultCount: String(results.length)
|
|
4421
4598
|
});
|
|
4422
4599
|
if (results.length === 0) {
|
|
4423
|
-
|
|
4600
|
+
const ownerSuffix = owner ? ` from owner "${owner}"` : "";
|
|
4601
|
+
console.log(`${DIM$3}No skills found for "${query}"${ownerSuffix}${RESET$3}`);
|
|
4424
4602
|
return;
|
|
4425
4603
|
}
|
|
4426
4604
|
console.log(`${DIM$3}Install with${RESET$3} npx skills add <owner/repo@skill>`);
|
|
@@ -4437,10 +4615,10 @@ ${DIM$3} 2) npx skills add <owner/repo@skill>${RESET$3}`;
|
|
|
4437
4615
|
if (isNonInteractive || await isRunningInAgent()) {
|
|
4438
4616
|
console.log(agentTip);
|
|
4439
4617
|
console.log();
|
|
4440
|
-
console.log(`${DIM$3}Usage: npx skills find <query
|
|
4618
|
+
console.log(`${DIM$3}Usage: npx skills find <query> [--owner <owner>]${RESET$3}`);
|
|
4441
4619
|
return;
|
|
4442
4620
|
}
|
|
4443
|
-
const selected = await runSearchPrompt();
|
|
4621
|
+
const selected = await runSearchPrompt("", owner);
|
|
4444
4622
|
track({
|
|
4445
4623
|
event: "find",
|
|
4446
4624
|
query: "",
|
|
@@ -4457,12 +4635,12 @@ ${DIM$3} 2) npx skills add <owner/repo@skill>${RESET$3}`;
|
|
|
4457
4635
|
console.log();
|
|
4458
4636
|
console.log(`${TEXT$2}Installing ${BOLD$3}${skillName}${RESET$3} from ${DIM$3}${pkg}${RESET$3}...`);
|
|
4459
4637
|
console.log();
|
|
4460
|
-
const { source, options } = parseAddOptions([
|
|
4638
|
+
const { source, options: addOptions } = parseAddOptions([
|
|
4461
4639
|
pkg,
|
|
4462
4640
|
"--skill",
|
|
4463
4641
|
skillName
|
|
4464
4642
|
]);
|
|
4465
|
-
await runAdd(source,
|
|
4643
|
+
await runAdd(source, addOptions);
|
|
4466
4644
|
console.log();
|
|
4467
4645
|
const info = getOwnerRepoFromString(pkg);
|
|
4468
4646
|
if (info && await isRepoPublic(info.owner, info.repo)) console.log(`${DIM$3}View the skill at${RESET$3} ${TEXT$2}https://skills.sh/${selected.slug}${RESET$3}`);
|
|
@@ -4982,6 +5160,7 @@ async function removeCommand(skillNames, options) {
|
|
|
4982
5160
|
} else {
|
|
4983
5161
|
await scanDir(getCanonicalSkillsDir(false, cwd));
|
|
4984
5162
|
for (const agent of Object.values(agents)) await scanDir(join(cwd, agent.skillsDir));
|
|
5163
|
+
for (const subagent of getEveSubagents(cwd)) await scanDir(getEveSubagentSkillsDir(subagent, cwd));
|
|
4985
5164
|
}
|
|
4986
5165
|
const installedSkills = Array.from(skillNamesSet).sort();
|
|
4987
5166
|
spinner.stop(`Found ${installedSkills.length} unique installed skill(s)`);
|
|
@@ -5055,7 +5234,10 @@ async function removeCommand(skillNames, options) {
|
|
|
5055
5234
|
const pathsToCleanup = new Set([skillPath]);
|
|
5056
5235
|
const sanitizedName = sanitizeName(skillName);
|
|
5057
5236
|
if (isGlobal && agent.globalSkillsDir) pathsToCleanup.add(join(agent.globalSkillsDir, sanitizedName));
|
|
5058
|
-
else
|
|
5237
|
+
else {
|
|
5238
|
+
pathsToCleanup.add(join(cwd, agent.skillsDir, sanitizedName));
|
|
5239
|
+
if (agentKey === "eve") for (const subagent of getEveSubagents(cwd)) pathsToCleanup.add(join(getEveSubagentSkillsDir(subagent, cwd), sanitizedName));
|
|
5240
|
+
}
|
|
5059
5241
|
for (const pathToCleanup of pathsToCleanup) {
|
|
5060
5242
|
if (pathToCleanup === canonicalPath) continue;
|
|
5061
5243
|
try {
|
|
@@ -5571,12 +5753,14 @@ async function updateProjectSkills(options = {}) {
|
|
|
5571
5753
|
const safeName = sanitizeMetadata(skill.name);
|
|
5572
5754
|
console.log(`${TEXT$1}Updating ${safeName}...${RESET$1}`);
|
|
5573
5755
|
const installUrl = formatSourceInput(skill.entry.source, skill.entry.ref);
|
|
5756
|
+
const subagentArgs = skill.entry.subagents?.length ? ["--subagent", ...skill.entry.subagents.map((s) => s === "" ? "root" : s)] : [];
|
|
5574
5757
|
if (spawnSync(process.execPath, [
|
|
5575
5758
|
cliEntry,
|
|
5576
5759
|
"add",
|
|
5577
5760
|
installUrl,
|
|
5578
5761
|
"--skill",
|
|
5579
5762
|
skill.name,
|
|
5763
|
+
...subagentArgs,
|
|
5580
5764
|
"-y"
|
|
5581
5765
|
], {
|
|
5582
5766
|
stdio: [
|
|
@@ -6084,6 +6268,9 @@ ${BOLD}Manage Skills:${RESET}
|
|
|
6084
6268
|
list, ls List installed skills
|
|
6085
6269
|
find [query] Search for skills interactively
|
|
6086
6270
|
|
|
6271
|
+
${BOLD}Find Options:${RESET}
|
|
6272
|
+
--owner <owner> Search only repositories from a GitHub owner
|
|
6273
|
+
|
|
6087
6274
|
${BOLD}Updates:${RESET}
|
|
6088
6275
|
update [skills...] Update skills to latest versions (alias: upgrade)
|
|
6089
6276
|
|
|
@@ -6104,6 +6291,7 @@ ${BOLD}Add Options:${RESET}
|
|
|
6104
6291
|
-l, --list List available skills in the repository without installing
|
|
6105
6292
|
-y, --yes Skip confirmation prompts
|
|
6106
6293
|
--copy Copy files instead of symlinking to agent directories
|
|
6294
|
+
--subagent <names> Install to Eve subagents (use 'root' for the root agent)
|
|
6107
6295
|
--all Shorthand for --skill '*' --agent '*' -y
|
|
6108
6296
|
--full-depth Search all subdirectories even when a root SKILL.md exists
|
|
6109
6297
|
|
|
@@ -6150,6 +6338,7 @@ ${BOLD}Examples:${RESET}
|
|
|
6150
6338
|
${DIM}$${RESET} skills ls --json ${DIM}# JSON output${RESET}
|
|
6151
6339
|
${DIM}$${RESET} skills find ${DIM}# interactive search${RESET}
|
|
6152
6340
|
${DIM}$${RESET} skills find typescript ${DIM}# search by keyword${RESET}
|
|
6341
|
+
${DIM}$${RESET} skills find react --owner vercel ${DIM}# search within an owner${RESET}
|
|
6153
6342
|
${DIM}$${RESET} skills update
|
|
6154
6343
|
${DIM}$${RESET} skills update my-skill ${DIM}# update a single skill${RESET}
|
|
6155
6344
|
${DIM}$${RESET} skills update -g ${DIM}# update global skills only${RESET}
|