bip-skills 1.4.5 → 1.4.7
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/cli.mjs +209 -38
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -11,7 +11,7 @@ import "./_chunks/libs/esprima.mjs";
|
|
|
11
11
|
import { t as xdgConfig } from "./_chunks/libs/xdg-basedir.mjs";
|
|
12
12
|
import { execSync, spawn, spawnSync } from "child_process";
|
|
13
13
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
14
|
-
import { basename, dirname, isAbsolute, join, normalize, relative, resolve, sep } from "path";
|
|
14
|
+
import { basename, dirname, isAbsolute, join, normalize, posix, relative, resolve, sep } from "path";
|
|
15
15
|
import { homedir, platform, tmpdir } from "os";
|
|
16
16
|
import { createHash } from "crypto";
|
|
17
17
|
import { fileURLToPath } from "url";
|
|
@@ -396,12 +396,9 @@ var GitCloneError = class extends Error {
|
|
|
396
396
|
};
|
|
397
397
|
async function cloneRepo(url, ref) {
|
|
398
398
|
const tempDir = await mkdtemp(join(tmpdir(), "skills-"));
|
|
399
|
-
const git = esm_default({
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
...process.env,
|
|
403
|
-
GIT_TERMINAL_PROMPT: "0"
|
|
404
|
-
}
|
|
399
|
+
const git = esm_default({ timeout: { block: CLONE_TIMEOUT_MS } }).env({
|
|
400
|
+
...process.env,
|
|
401
|
+
GIT_TERMINAL_PROMPT: "0"
|
|
405
402
|
});
|
|
406
403
|
const cloneOptions = ref ? [
|
|
407
404
|
"--depth",
|
|
@@ -1488,6 +1485,54 @@ var WellKnownProvider = class {
|
|
|
1488
1485
|
displayName = "Well-Known Skills";
|
|
1489
1486
|
WELL_KNOWN_PATH = ".well-known/skills";
|
|
1490
1487
|
INDEX_FILE = "index.json";
|
|
1488
|
+
buildUrl(baseUrl, relativePath) {
|
|
1489
|
+
const normalizedRelative = relativePath.replace(/^\/+/, "");
|
|
1490
|
+
return new URL(normalizedRelative, `${baseUrl.replace(/\/?$/, "/")}`).toString();
|
|
1491
|
+
}
|
|
1492
|
+
getSkillRoot(entry) {
|
|
1493
|
+
if (entry.entry) {
|
|
1494
|
+
const normalizedEntry = posix.normalize(entry.entry).replace(/^\/+/, "");
|
|
1495
|
+
const entryDir = posix.dirname(normalizedEntry);
|
|
1496
|
+
return entryDir === "." ? "" : entryDir;
|
|
1497
|
+
}
|
|
1498
|
+
return entry.name;
|
|
1499
|
+
}
|
|
1500
|
+
resolveRepositoryUrl(index, resolvedBaseUrl, entry) {
|
|
1501
|
+
if (!entry.repositoryId) return `${resolvedBaseUrl.replace(/\/$/, "")}/${this.WELL_KNOWN_PATH}/${this.INDEX_FILE}`;
|
|
1502
|
+
return (index.repositories?.find((repo) => repo.id === entry.repositoryId))?.repository || `${resolvedBaseUrl.replace(/\/$/, "")}/${this.WELL_KNOWN_PATH}/${this.INDEX_FILE}`;
|
|
1503
|
+
}
|
|
1504
|
+
resolveInlineBaseUrl(repositoryUrl) {
|
|
1505
|
+
if (!repositoryUrl.startsWith("http://") && !repositoryUrl.startsWith("https://")) return null;
|
|
1506
|
+
try {
|
|
1507
|
+
const parsed = new URL(repositoryUrl);
|
|
1508
|
+
if (parsed.pathname.endsWith(`/${this.INDEX_FILE}`)) parsed.pathname = parsed.pathname.replace(new RegExp(`/${this.INDEX_FILE}$`), "");
|
|
1509
|
+
else parsed.pathname = parsed.pathname.replace(/\/$/, "");
|
|
1510
|
+
parsed.search = "";
|
|
1511
|
+
parsed.hash = "";
|
|
1512
|
+
return parsed.toString().replace(/\/$/, "");
|
|
1513
|
+
} catch {
|
|
1514
|
+
return null;
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
resolveInstallTarget(index, resolvedBaseUrl, entry) {
|
|
1518
|
+
const repositoryUrl = this.resolveRepositoryUrl(index, resolvedBaseUrl, entry);
|
|
1519
|
+
const skillRoot = this.getSkillRoot(entry);
|
|
1520
|
+
const inlineBaseUrl = this.resolveInlineBaseUrl(repositoryUrl);
|
|
1521
|
+
if (inlineBaseUrl) {
|
|
1522
|
+
const skillMdRelativePath = entry.entry || posix.join(skillRoot, "SKILL.md");
|
|
1523
|
+
return {
|
|
1524
|
+
type: "inline",
|
|
1525
|
+
repositoryUrl,
|
|
1526
|
+
skillRoot,
|
|
1527
|
+
skillMdUrl: this.buildUrl(inlineBaseUrl, skillMdRelativePath)
|
|
1528
|
+
};
|
|
1529
|
+
}
|
|
1530
|
+
return {
|
|
1531
|
+
type: "repository",
|
|
1532
|
+
repositoryUrl,
|
|
1533
|
+
subpath: skillRoot
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1491
1536
|
match(url) {
|
|
1492
1537
|
if (!url.startsWith("http://") && !url.startsWith("https://")) return { matches: false };
|
|
1493
1538
|
try {
|
|
@@ -1530,14 +1575,17 @@ var WellKnownProvider = class {
|
|
|
1530
1575
|
debugLog(`[well-known] index response body: ${responseText}`);
|
|
1531
1576
|
const index = JSON.parse(responseText);
|
|
1532
1577
|
if (!index.skills || !Array.isArray(index.skills)) continue;
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1578
|
+
const totalSkillCount = index.skills.length;
|
|
1579
|
+
const validSkills = index.skills.filter((entry) => this.isValidSkillEntry(entry));
|
|
1580
|
+
const invalidSkillCount = totalSkillCount - validSkills.length;
|
|
1581
|
+
return {
|
|
1582
|
+
index: {
|
|
1583
|
+
...index,
|
|
1584
|
+
skills: validSkills
|
|
1585
|
+
},
|
|
1586
|
+
resolvedBaseUrl: resolvedBase,
|
|
1587
|
+
totalSkillCount,
|
|
1588
|
+
invalidSkillCount
|
|
1541
1589
|
};
|
|
1542
1590
|
} catch {
|
|
1543
1591
|
continue;
|
|
@@ -1561,6 +1609,12 @@ var WellKnownProvider = class {
|
|
|
1561
1609
|
if (file.startsWith("/") || file.startsWith("\\") || file.includes("..")) return false;
|
|
1562
1610
|
}
|
|
1563
1611
|
if (!e.files.some((f) => typeof f === "string" && f.toLowerCase() === "skill.md")) return false;
|
|
1612
|
+
if (e.entry !== void 0) {
|
|
1613
|
+
if (typeof e.entry !== "string") return false;
|
|
1614
|
+
if (e.entry.startsWith("/") || e.entry.startsWith("\\") || e.entry.includes("..")) return false;
|
|
1615
|
+
if (!e.entry.toLowerCase().endsWith("/skill.md") && e.entry.toLowerCase() !== "skill.md") return false;
|
|
1616
|
+
}
|
|
1617
|
+
if (e.repositoryId !== void 0 && typeof e.repositoryId !== "string") return false;
|
|
1564
1618
|
return true;
|
|
1565
1619
|
}
|
|
1566
1620
|
async fetchSkill(url, options = {}) {
|
|
@@ -1576,28 +1630,40 @@ var WellKnownProvider = class {
|
|
|
1576
1630
|
if (!skillName) return null;
|
|
1577
1631
|
const skillEntry = index.skills.find((s) => s.name === skillName);
|
|
1578
1632
|
if (!skillEntry) return null;
|
|
1579
|
-
return this.fetchSkillByEntry(resolvedBaseUrl, skillEntry);
|
|
1633
|
+
return this.fetchSkillByEntry(index, resolvedBaseUrl, skillEntry);
|
|
1580
1634
|
} catch {
|
|
1581
1635
|
return null;
|
|
1582
1636
|
}
|
|
1583
1637
|
}
|
|
1584
|
-
async fetchSkillByEntry(baseUrl, entry) {
|
|
1638
|
+
async fetchSkillByEntry(index, baseUrl, entry) {
|
|
1585
1639
|
try {
|
|
1586
|
-
const
|
|
1587
|
-
const
|
|
1588
|
-
|
|
1640
|
+
const installTarget = this.resolveInstallTarget(index, baseUrl, entry);
|
|
1641
|
+
const files = /* @__PURE__ */ new Map();
|
|
1642
|
+
if (installTarget.type === "repository") return {
|
|
1643
|
+
name: entry.name,
|
|
1644
|
+
description: entry.description,
|
|
1645
|
+
content: "",
|
|
1646
|
+
installName: entry.name,
|
|
1647
|
+
sourceUrl: installTarget.repositoryUrl,
|
|
1648
|
+
files,
|
|
1649
|
+
declaredFiles: [...entry.files],
|
|
1650
|
+
indexEntry: entry,
|
|
1651
|
+
installTarget
|
|
1652
|
+
};
|
|
1653
|
+
const response = await fetch(installTarget.skillMdUrl);
|
|
1589
1654
|
if (!response.ok) return null;
|
|
1590
1655
|
const content = await response.text();
|
|
1591
1656
|
const { data } = (0, import_gray_matter.default)(content);
|
|
1592
1657
|
if (!data.name || !data.description) return null;
|
|
1593
|
-
const files = /* @__PURE__ */ new Map();
|
|
1594
1658
|
files.set("SKILL.md", content);
|
|
1595
1659
|
const filePromises = entry.files.filter((f) => f.toLowerCase() !== "skill.md").map(async (filePath) => {
|
|
1596
1660
|
try {
|
|
1597
|
-
const
|
|
1661
|
+
const normalizedFilePath = filePath.replace(/^\/+/, "");
|
|
1662
|
+
const fileRelativePath = installTarget.skillRoot ? posix.join(installTarget.skillRoot, normalizedFilePath) : normalizedFilePath;
|
|
1663
|
+
const fileUrl = this.buildUrl(this.resolveInlineBaseUrl(installTarget.repositoryUrl) || baseUrl, fileRelativePath);
|
|
1598
1664
|
const fileResponse = await fetch(fileUrl);
|
|
1599
1665
|
if (fileResponse.ok) return {
|
|
1600
|
-
path:
|
|
1666
|
+
path: normalizedFilePath,
|
|
1601
1667
|
content: await fileResponse.text()
|
|
1602
1668
|
};
|
|
1603
1669
|
} catch {}
|
|
@@ -1610,24 +1676,51 @@ var WellKnownProvider = class {
|
|
|
1610
1676
|
description: data.description,
|
|
1611
1677
|
content,
|
|
1612
1678
|
installName: entry.name,
|
|
1613
|
-
sourceUrl: skillMdUrl,
|
|
1679
|
+
sourceUrl: installTarget.skillMdUrl,
|
|
1614
1680
|
metadata: data.metadata,
|
|
1615
1681
|
files,
|
|
1616
|
-
|
|
1682
|
+
declaredFiles: [...entry.files],
|
|
1683
|
+
indexEntry: entry,
|
|
1684
|
+
installTarget
|
|
1617
1685
|
};
|
|
1618
1686
|
} catch {
|
|
1619
1687
|
return null;
|
|
1620
1688
|
}
|
|
1621
1689
|
}
|
|
1622
1690
|
async fetchAllSkills(url, options = {}) {
|
|
1691
|
+
return (await this.fetchAllSkillsWithStatus(url, options)).skills;
|
|
1692
|
+
}
|
|
1693
|
+
async fetchAllSkillsWithStatus(url, options = {}) {
|
|
1623
1694
|
try {
|
|
1624
1695
|
const result = await this.fetchIndex(url, options);
|
|
1625
|
-
if (!result) return
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1696
|
+
if (!result) return {
|
|
1697
|
+
skills: [],
|
|
1698
|
+
status: "index-not-found",
|
|
1699
|
+
totalSkillCount: 0,
|
|
1700
|
+
invalidSkillCount: 0
|
|
1701
|
+
};
|
|
1702
|
+
const { index, resolvedBaseUrl, totalSkillCount, invalidSkillCount } = result;
|
|
1703
|
+
if (index.skills.length === 0) return {
|
|
1704
|
+
skills: [],
|
|
1705
|
+
status: "no-valid-entries",
|
|
1706
|
+
totalSkillCount,
|
|
1707
|
+
invalidSkillCount
|
|
1708
|
+
};
|
|
1709
|
+
const skillPromises = index.skills.map((entry) => this.fetchSkillByEntry(index, resolvedBaseUrl, entry));
|
|
1710
|
+
const skills = (await Promise.all(skillPromises)).filter((s) => s !== null);
|
|
1711
|
+
return {
|
|
1712
|
+
skills,
|
|
1713
|
+
status: skills.length > 0 ? "ok" : "no-installable-skills",
|
|
1714
|
+
totalSkillCount,
|
|
1715
|
+
invalidSkillCount
|
|
1716
|
+
};
|
|
1629
1717
|
} catch {
|
|
1630
|
-
return
|
|
1718
|
+
return {
|
|
1719
|
+
skills: [],
|
|
1720
|
+
status: "index-not-found",
|
|
1721
|
+
totalSkillCount: 0,
|
|
1722
|
+
invalidSkillCount: 0
|
|
1723
|
+
};
|
|
1631
1724
|
}
|
|
1632
1725
|
}
|
|
1633
1726
|
toRawUrl(url) {
|
|
@@ -1833,7 +1926,7 @@ function createEmptyLocalLock() {
|
|
|
1833
1926
|
skills: {}
|
|
1834
1927
|
};
|
|
1835
1928
|
}
|
|
1836
|
-
var version$1 = "1.4.
|
|
1929
|
+
var version$1 = "1.4.7";
|
|
1837
1930
|
const isCancelled$1 = (value) => typeof value === "symbol";
|
|
1838
1931
|
async function isSourcePrivate(source) {
|
|
1839
1932
|
const ownerRepo = parseOwnerRepo(source);
|
|
@@ -1843,6 +1936,44 @@ async function isSourcePrivate(source) {
|
|
|
1843
1936
|
function initTelemetry(version) {
|
|
1844
1937
|
setVersion(version);
|
|
1845
1938
|
}
|
|
1939
|
+
function getWellKnownFileCount(skill) {
|
|
1940
|
+
return skill.declaredFiles.length > 0 ? skill.declaredFiles.length : skill.files.size;
|
|
1941
|
+
}
|
|
1942
|
+
function getWellKnownEmptyStateMessage(status, totalSkillCount, invalidSkillCount) {
|
|
1943
|
+
switch (status) {
|
|
1944
|
+
case "no-valid-entries": return totalSkillCount > 0 ? `Found a skills index, but all ${totalSkillCount} entr${totalSkillCount === 1 ? "y is" : "ies are"} invalid. Check that each entry has a top-level SKILL.md in files[].` : "Found a skills index, but it does not contain any valid skill entries.";
|
|
1945
|
+
case "no-installable-skills":
|
|
1946
|
+
if (invalidSkillCount > 0) return `Found a skills index, but no installable skills could be loaded. ${invalidSkillCount} invalid entr${invalidSkillCount === 1 ? "y was" : "ies were"} skipped.`;
|
|
1947
|
+
return "Found a skills index, but no installable skills could be loaded from it.";
|
|
1948
|
+
default: return "No skills found at this URL. Make sure the server has a /.well-known/skills/index.json file.";
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
async function prepareRepositoryBackedWellKnownSkill(skill) {
|
|
1952
|
+
if (skill.installTarget.type !== "repository") throw new Error("Skill is not repository-backed");
|
|
1953
|
+
const tempDir = await cloneRepo(skill.installTarget.repositoryUrl);
|
|
1954
|
+
try {
|
|
1955
|
+
const exactMatches = skill.installTarget.subpath ? await discoverSkills(tempDir, skill.installTarget.subpath, {
|
|
1956
|
+
includeInternal: true,
|
|
1957
|
+
fullDepth: true
|
|
1958
|
+
}) : [];
|
|
1959
|
+
const repoWideMatches = exactMatches.length > 0 ? exactMatches : await discoverSkills(tempDir, void 0, {
|
|
1960
|
+
includeInternal: true,
|
|
1961
|
+
fullDepth: true
|
|
1962
|
+
});
|
|
1963
|
+
const matched = repoWideMatches.find((candidate) => candidate.name.toLowerCase() === skill.installName.toLowerCase()) || exactMatches[0] || repoWideMatches[0];
|
|
1964
|
+
if (!matched) throw new Error(`No skill found at ${skill.installTarget.repositoryUrl}${skill.installTarget.subpath ? ` (${skill.installTarget.subpath})` : ""}`);
|
|
1965
|
+
return {
|
|
1966
|
+
preparedSkill: {
|
|
1967
|
+
...matched,
|
|
1968
|
+
name: skill.installName
|
|
1969
|
+
},
|
|
1970
|
+
tempDir
|
|
1971
|
+
};
|
|
1972
|
+
} catch (error) {
|
|
1973
|
+
await cleanupTempDir(tempDir).catch(() => {});
|
|
1974
|
+
throw error;
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1846
1977
|
function riskLabel(risk) {
|
|
1847
1978
|
switch (risk) {
|
|
1848
1979
|
case "critical": return import_picocolors.default.red(import_picocolors.default.bold("Critical Risk"));
|
|
@@ -2039,14 +2170,15 @@ async function handleWellKnownSkills(source, url, options, spinner, allowFallbac
|
|
|
2039
2170
|
const shouldReportToSun = isInternalSkillSourceUrl(url);
|
|
2040
2171
|
try {
|
|
2041
2172
|
spinner.start("Discovering skills from well-known endpoint...");
|
|
2042
|
-
const
|
|
2173
|
+
const discovery = await wellKnownProvider.fetchAllSkillsWithStatus(url, { fallbackToRoot });
|
|
2174
|
+
const skills = discovery.skills;
|
|
2043
2175
|
if (skills.length === 0) {
|
|
2044
2176
|
if (allowFallback) {
|
|
2045
2177
|
spinner.stop(import_picocolors.default.yellow("Default well-known endpoint unavailable"));
|
|
2046
2178
|
return false;
|
|
2047
2179
|
}
|
|
2048
|
-
spinner.stop(import_picocolors.default.red("No skills found"));
|
|
2049
|
-
Se(import_picocolors.default.red(
|
|
2180
|
+
spinner.stop(import_picocolors.default.red("No usable skills found"));
|
|
2181
|
+
Se(import_picocolors.default.red(getWellKnownEmptyStateMessage(discovery.status, discovery.totalSkillCount, discovery.invalidSkillCount)));
|
|
2050
2182
|
process.exit(1);
|
|
2051
2183
|
}
|
|
2052
2184
|
spinner.stop(`Found ${import_picocolors.default.green(skills.length)} skill${skills.length > 1 ? "s" : ""}`);
|
|
@@ -2054,6 +2186,7 @@ async function handleWellKnownSkills(source, url, options, spinner, allowFallbac
|
|
|
2054
2186
|
M.info(`Skill: ${import_picocolors.default.cyan(skill.installName)}`);
|
|
2055
2187
|
M.message(import_picocolors.default.dim(skill.description));
|
|
2056
2188
|
if (skill.files.size > 1) M.message(import_picocolors.default.dim(` Files: ${Array.from(skill.files.keys()).join(", ")}`));
|
|
2189
|
+
else if (skill.declaredFiles.length > 1) M.message(import_picocolors.default.dim(` Files: ${skill.declaredFiles.join(", ")}`));
|
|
2057
2190
|
}
|
|
2058
2191
|
if (options.list) {
|
|
2059
2192
|
console.log();
|
|
@@ -2061,7 +2194,8 @@ async function handleWellKnownSkills(source, url, options, spinner, allowFallbac
|
|
|
2061
2194
|
for (const skill of skills) {
|
|
2062
2195
|
M.message(` ${import_picocolors.default.cyan(skill.installName)}`);
|
|
2063
2196
|
M.message(` ${import_picocolors.default.dim(skill.description)}`);
|
|
2064
|
-
|
|
2197
|
+
const fileCount = getWellKnownFileCount(skill);
|
|
2198
|
+
if (fileCount > 1) M.message(` ${import_picocolors.default.dim(`Files: ${fileCount}`)}`);
|
|
2065
2199
|
}
|
|
2066
2200
|
console.log();
|
|
2067
2201
|
Se("Run without --list to install");
|
|
@@ -2213,7 +2347,8 @@ async function handleWellKnownSkills(source, url, options, spinner, allowFallbac
|
|
|
2213
2347
|
const shortCanonical = shortenPath$2(getCanonicalPath(skill.installName, { global: installGlobally }), cwd);
|
|
2214
2348
|
summaryLines.push(`${import_picocolors.default.cyan(shortCanonical)}`);
|
|
2215
2349
|
summaryLines.push(...buildAgentSummaryLines(targetAgents, installMode));
|
|
2216
|
-
|
|
2350
|
+
const fileCount = getWellKnownFileCount(skill);
|
|
2351
|
+
if (fileCount > 1) summaryLines.push(` ${import_picocolors.default.dim("files:")} ${fileCount}`);
|
|
2217
2352
|
const skillOverwrites = overwriteStatus.get(skill.installName);
|
|
2218
2353
|
const overwriteAgents = targetAgents.filter((a) => skillOverwrites?.get(a)).map((a) => agents[a].displayName);
|
|
2219
2354
|
if (overwriteAgents.length > 0) summaryLines.push(` ${import_picocolors.default.yellow("overwrites:")} ${formatList$1(overwriteAgents)}`);
|
|
@@ -2227,19 +2362,55 @@ async function handleWellKnownSkills(source, url, options, spinner, allowFallbac
|
|
|
2227
2362
|
process.exit(0);
|
|
2228
2363
|
}
|
|
2229
2364
|
}
|
|
2365
|
+
const preparedRepositorySkills = /* @__PURE__ */ new Map();
|
|
2366
|
+
const repositoryPrepFailures = /* @__PURE__ */ new Map();
|
|
2367
|
+
const repositoryTempDirs = [];
|
|
2368
|
+
const repositoryBackedSkills = selectedSkills.filter((skill) => skill.installTarget.type === "repository");
|
|
2369
|
+
if (repositoryBackedSkills.length > 0) {
|
|
2370
|
+
spinner.start("Preparing repository-backed skills...");
|
|
2371
|
+
for (const skill of repositoryBackedSkills) try {
|
|
2372
|
+
const prepared = await prepareRepositoryBackedWellKnownSkill(skill);
|
|
2373
|
+
preparedRepositorySkills.set(skill.installName, prepared.preparedSkill);
|
|
2374
|
+
repositoryTempDirs.push(prepared.tempDir);
|
|
2375
|
+
} catch (error) {
|
|
2376
|
+
repositoryPrepFailures.set(skill.installName, error instanceof Error ? error.message : "Unknown error");
|
|
2377
|
+
}
|
|
2378
|
+
spinner.stop("Repository-backed skills prepared");
|
|
2379
|
+
}
|
|
2230
2380
|
spinner.start("Installing skills...");
|
|
2231
2381
|
const results = [];
|
|
2232
2382
|
for (const skill of selectedSkills) for (const agent of targetAgents) {
|
|
2233
|
-
|
|
2383
|
+
let installOutcome;
|
|
2384
|
+
const prepError = repositoryPrepFailures.get(skill.installName);
|
|
2385
|
+
if (prepError) installOutcome = {
|
|
2386
|
+
success: false,
|
|
2387
|
+
path: "",
|
|
2388
|
+
mode: installMode,
|
|
2389
|
+
error: prepError
|
|
2390
|
+
};
|
|
2391
|
+
else if (skill.installTarget.type === "repository") {
|
|
2392
|
+
const preparedSkill = preparedRepositorySkills.get(skill.installName);
|
|
2393
|
+
if (!preparedSkill) installOutcome = {
|
|
2394
|
+
success: false,
|
|
2395
|
+
path: "",
|
|
2396
|
+
mode: installMode,
|
|
2397
|
+
error: "Repository-backed skill was not prepared"
|
|
2398
|
+
};
|
|
2399
|
+
else installOutcome = await installSkillForAgent(preparedSkill, agent, {
|
|
2400
|
+
global: installGlobally,
|
|
2401
|
+
mode: installMode
|
|
2402
|
+
});
|
|
2403
|
+
} else installOutcome = await installWellKnownSkillForAgent(skill, agent, {
|
|
2234
2404
|
global: installGlobally,
|
|
2235
2405
|
mode: installMode
|
|
2236
2406
|
});
|
|
2237
2407
|
results.push({
|
|
2238
2408
|
skill: skill.installName,
|
|
2239
2409
|
agent: agents[agent].displayName,
|
|
2240
|
-
...
|
|
2410
|
+
...installOutcome
|
|
2241
2411
|
});
|
|
2242
2412
|
}
|
|
2413
|
+
await Promise.all(repositoryTempDirs.map((dir) => cleanupTempDir(dir).catch(() => {})));
|
|
2243
2414
|
spinner.stop("Installation complete");
|
|
2244
2415
|
console.log();
|
|
2245
2416
|
const successful = results.filter((r) => r.success);
|