bip-skills 1.4.5 → 1.4.6
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 +205 -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.6";
|
|
1837
1930
|
const isCancelled$1 = (value) => typeof value === "symbol";
|
|
1838
1931
|
async function isSourcePrivate(source) {
|
|
1839
1932
|
const ownerRepo = parseOwnerRepo(source);
|
|
@@ -1843,6 +1936,40 @@ 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 discovered = await discoverSkills(tempDir, skill.installTarget.subpath, {
|
|
1956
|
+
includeInternal: true,
|
|
1957
|
+
fullDepth: true
|
|
1958
|
+
});
|
|
1959
|
+
const matched = discovered.find((candidate) => candidate.name.toLowerCase() === skill.installName.toLowerCase()) || discovered[0];
|
|
1960
|
+
if (!matched) throw new Error(`No skill found at ${skill.installTarget.repositoryUrl}${skill.installTarget.subpath ? ` (${skill.installTarget.subpath})` : ""}`);
|
|
1961
|
+
return {
|
|
1962
|
+
preparedSkill: {
|
|
1963
|
+
...matched,
|
|
1964
|
+
name: skill.installName
|
|
1965
|
+
},
|
|
1966
|
+
tempDir
|
|
1967
|
+
};
|
|
1968
|
+
} catch (error) {
|
|
1969
|
+
await cleanupTempDir(tempDir).catch(() => {});
|
|
1970
|
+
throw error;
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1846
1973
|
function riskLabel(risk) {
|
|
1847
1974
|
switch (risk) {
|
|
1848
1975
|
case "critical": return import_picocolors.default.red(import_picocolors.default.bold("Critical Risk"));
|
|
@@ -2039,14 +2166,15 @@ async function handleWellKnownSkills(source, url, options, spinner, allowFallbac
|
|
|
2039
2166
|
const shouldReportToSun = isInternalSkillSourceUrl(url);
|
|
2040
2167
|
try {
|
|
2041
2168
|
spinner.start("Discovering skills from well-known endpoint...");
|
|
2042
|
-
const
|
|
2169
|
+
const discovery = await wellKnownProvider.fetchAllSkillsWithStatus(url, { fallbackToRoot });
|
|
2170
|
+
const skills = discovery.skills;
|
|
2043
2171
|
if (skills.length === 0) {
|
|
2044
2172
|
if (allowFallback) {
|
|
2045
2173
|
spinner.stop(import_picocolors.default.yellow("Default well-known endpoint unavailable"));
|
|
2046
2174
|
return false;
|
|
2047
2175
|
}
|
|
2048
|
-
spinner.stop(import_picocolors.default.red("No skills found"));
|
|
2049
|
-
Se(import_picocolors.default.red(
|
|
2176
|
+
spinner.stop(import_picocolors.default.red("No usable skills found"));
|
|
2177
|
+
Se(import_picocolors.default.red(getWellKnownEmptyStateMessage(discovery.status, discovery.totalSkillCount, discovery.invalidSkillCount)));
|
|
2050
2178
|
process.exit(1);
|
|
2051
2179
|
}
|
|
2052
2180
|
spinner.stop(`Found ${import_picocolors.default.green(skills.length)} skill${skills.length > 1 ? "s" : ""}`);
|
|
@@ -2054,6 +2182,7 @@ async function handleWellKnownSkills(source, url, options, spinner, allowFallbac
|
|
|
2054
2182
|
M.info(`Skill: ${import_picocolors.default.cyan(skill.installName)}`);
|
|
2055
2183
|
M.message(import_picocolors.default.dim(skill.description));
|
|
2056
2184
|
if (skill.files.size > 1) M.message(import_picocolors.default.dim(` Files: ${Array.from(skill.files.keys()).join(", ")}`));
|
|
2185
|
+
else if (skill.declaredFiles.length > 1) M.message(import_picocolors.default.dim(` Files: ${skill.declaredFiles.join(", ")}`));
|
|
2057
2186
|
}
|
|
2058
2187
|
if (options.list) {
|
|
2059
2188
|
console.log();
|
|
@@ -2061,7 +2190,8 @@ async function handleWellKnownSkills(source, url, options, spinner, allowFallbac
|
|
|
2061
2190
|
for (const skill of skills) {
|
|
2062
2191
|
M.message(` ${import_picocolors.default.cyan(skill.installName)}`);
|
|
2063
2192
|
M.message(` ${import_picocolors.default.dim(skill.description)}`);
|
|
2064
|
-
|
|
2193
|
+
const fileCount = getWellKnownFileCount(skill);
|
|
2194
|
+
if (fileCount > 1) M.message(` ${import_picocolors.default.dim(`Files: ${fileCount}`)}`);
|
|
2065
2195
|
}
|
|
2066
2196
|
console.log();
|
|
2067
2197
|
Se("Run without --list to install");
|
|
@@ -2213,7 +2343,8 @@ async function handleWellKnownSkills(source, url, options, spinner, allowFallbac
|
|
|
2213
2343
|
const shortCanonical = shortenPath$2(getCanonicalPath(skill.installName, { global: installGlobally }), cwd);
|
|
2214
2344
|
summaryLines.push(`${import_picocolors.default.cyan(shortCanonical)}`);
|
|
2215
2345
|
summaryLines.push(...buildAgentSummaryLines(targetAgents, installMode));
|
|
2216
|
-
|
|
2346
|
+
const fileCount = getWellKnownFileCount(skill);
|
|
2347
|
+
if (fileCount > 1) summaryLines.push(` ${import_picocolors.default.dim("files:")} ${fileCount}`);
|
|
2217
2348
|
const skillOverwrites = overwriteStatus.get(skill.installName);
|
|
2218
2349
|
const overwriteAgents = targetAgents.filter((a) => skillOverwrites?.get(a)).map((a) => agents[a].displayName);
|
|
2219
2350
|
if (overwriteAgents.length > 0) summaryLines.push(` ${import_picocolors.default.yellow("overwrites:")} ${formatList$1(overwriteAgents)}`);
|
|
@@ -2227,19 +2358,55 @@ async function handleWellKnownSkills(source, url, options, spinner, allowFallbac
|
|
|
2227
2358
|
process.exit(0);
|
|
2228
2359
|
}
|
|
2229
2360
|
}
|
|
2361
|
+
const preparedRepositorySkills = /* @__PURE__ */ new Map();
|
|
2362
|
+
const repositoryPrepFailures = /* @__PURE__ */ new Map();
|
|
2363
|
+
const repositoryTempDirs = [];
|
|
2364
|
+
const repositoryBackedSkills = selectedSkills.filter((skill) => skill.installTarget.type === "repository");
|
|
2365
|
+
if (repositoryBackedSkills.length > 0) {
|
|
2366
|
+
spinner.start("Preparing repository-backed skills...");
|
|
2367
|
+
for (const skill of repositoryBackedSkills) try {
|
|
2368
|
+
const prepared = await prepareRepositoryBackedWellKnownSkill(skill);
|
|
2369
|
+
preparedRepositorySkills.set(skill.installName, prepared.preparedSkill);
|
|
2370
|
+
repositoryTempDirs.push(prepared.tempDir);
|
|
2371
|
+
} catch (error) {
|
|
2372
|
+
repositoryPrepFailures.set(skill.installName, error instanceof Error ? error.message : "Unknown error");
|
|
2373
|
+
}
|
|
2374
|
+
spinner.stop("Repository-backed skills prepared");
|
|
2375
|
+
}
|
|
2230
2376
|
spinner.start("Installing skills...");
|
|
2231
2377
|
const results = [];
|
|
2232
2378
|
for (const skill of selectedSkills) for (const agent of targetAgents) {
|
|
2233
|
-
|
|
2379
|
+
let installOutcome;
|
|
2380
|
+
const prepError = repositoryPrepFailures.get(skill.installName);
|
|
2381
|
+
if (prepError) installOutcome = {
|
|
2382
|
+
success: false,
|
|
2383
|
+
path: "",
|
|
2384
|
+
mode: installMode,
|
|
2385
|
+
error: prepError
|
|
2386
|
+
};
|
|
2387
|
+
else if (skill.installTarget.type === "repository") {
|
|
2388
|
+
const preparedSkill = preparedRepositorySkills.get(skill.installName);
|
|
2389
|
+
if (!preparedSkill) installOutcome = {
|
|
2390
|
+
success: false,
|
|
2391
|
+
path: "",
|
|
2392
|
+
mode: installMode,
|
|
2393
|
+
error: "Repository-backed skill was not prepared"
|
|
2394
|
+
};
|
|
2395
|
+
else installOutcome = await installSkillForAgent(preparedSkill, agent, {
|
|
2396
|
+
global: installGlobally,
|
|
2397
|
+
mode: installMode
|
|
2398
|
+
});
|
|
2399
|
+
} else installOutcome = await installWellKnownSkillForAgent(skill, agent, {
|
|
2234
2400
|
global: installGlobally,
|
|
2235
2401
|
mode: installMode
|
|
2236
2402
|
});
|
|
2237
2403
|
results.push({
|
|
2238
2404
|
skill: skill.installName,
|
|
2239
2405
|
agent: agents[agent].displayName,
|
|
2240
|
-
...
|
|
2406
|
+
...installOutcome
|
|
2241
2407
|
});
|
|
2242
2408
|
}
|
|
2409
|
+
await Promise.all(repositoryTempDirs.map((dir) => cleanupTempDir(dir).catch(() => {})));
|
|
2243
2410
|
spinner.stop("Installation complete");
|
|
2244
2411
|
console.log();
|
|
2245
2412
|
const successful = results.filter((r) => r.success);
|