bip-skills 1.4.3 → 1.4.5
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 +397 -272
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -29,9 +29,17 @@ const DEFAULT_DISCOVERY_SITE_URL = DEFAULT_WELL_KNOWN_BASE_URL;
|
|
|
29
29
|
const DEFAULT_SEARCH_API_BASE = DEFAULT_WELL_KNOWN_BASE_URL;
|
|
30
30
|
const DEFAULT_GIT_HOST = "git.yonyou.com";
|
|
31
31
|
const DEFAULT_GIT_BASE_URL = `https://${DEFAULT_GIT_HOST}`;
|
|
32
|
+
const DEFAULT_GIT_FALLBACK_SSH_HOST = "git.yyrd.com";
|
|
33
|
+
const DEFAULT_INSTALL_REPORT_URL = "https://sun.yyuap.com/api/install-report";
|
|
32
34
|
function isYyuapHost(hostname) {
|
|
33
35
|
return hostname === "yyuap.com" || hostname.endsWith(".yyuap.com");
|
|
34
36
|
}
|
|
37
|
+
function isYyrdHost(hostname) {
|
|
38
|
+
return hostname === "yyrd.com" || hostname.endsWith(".yyrd.com");
|
|
39
|
+
}
|
|
40
|
+
function isInternalSkillSourceHost(hostname) {
|
|
41
|
+
return isYyuapHost(hostname) || isYyrdHost(hostname);
|
|
42
|
+
}
|
|
35
43
|
function isAllowedReportingUrl(url) {
|
|
36
44
|
try {
|
|
37
45
|
return isYyuapHost(new URL(url).hostname);
|
|
@@ -73,6 +81,20 @@ async function isRepoPrivate(owner, repo) {
|
|
|
73
81
|
return null;
|
|
74
82
|
}
|
|
75
83
|
}
|
|
84
|
+
function extractSourceHostname(sourceUrl) {
|
|
85
|
+
if (sourceUrl.startsWith("http://") || sourceUrl.startsWith("https://") || sourceUrl.startsWith("ssh://") || sourceUrl.startsWith("git://")) try {
|
|
86
|
+
return new URL(sourceUrl).hostname;
|
|
87
|
+
} catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
const scpLikeMatch = sourceUrl.match(/^(?:[^@]+@)?([^:/]+):.+$/);
|
|
91
|
+
if (scpLikeMatch) return scpLikeMatch[1] ?? null;
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
function isInternalSkillSourceUrl(sourceUrl) {
|
|
95
|
+
const hostname = extractSourceHostname(sourceUrl);
|
|
96
|
+
return hostname ? isInternalSkillSourceHost(hostname) : false;
|
|
97
|
+
}
|
|
76
98
|
function isLocalPath(input) {
|
|
77
99
|
return isAbsolute(input) || input.startsWith("./") || input.startsWith("../") || input === "." || input === ".." || /^[a-zA-Z]:[/\\]/.test(input);
|
|
78
100
|
}
|
|
@@ -1399,6 +1421,7 @@ function getAllowedReportingUrl(envVarName) {
|
|
|
1399
1421
|
}
|
|
1400
1422
|
const TELEMETRY_URL = getAllowedReportingUrl("SKILLS_TELEMETRY_URL");
|
|
1401
1423
|
const AUDIT_URL = getAllowedReportingUrl("SKILLS_AUDIT_URL");
|
|
1424
|
+
const INSTALL_REPORT_URL = isAllowedReportingUrl(DEFAULT_INSTALL_REPORT_URL) ? DEFAULT_INSTALL_REPORT_URL : null;
|
|
1402
1425
|
let cliVersion = null;
|
|
1403
1426
|
function isCI() {
|
|
1404
1427
|
return !!(process.env.CI || process.env.GITHUB_ACTIONS || process.env.GITLAB_CI || process.env.CIRCLECI || process.env.TRAVIS || process.env.BUILDKITE || process.env.JENKINS_URL || process.env.TEAMCITY_VERSION);
|
|
@@ -1427,17 +1450,24 @@ async function fetchAuditData(source, skillSlugs, timeoutMs = 3e3) {
|
|
|
1427
1450
|
return null;
|
|
1428
1451
|
}
|
|
1429
1452
|
}
|
|
1430
|
-
function
|
|
1431
|
-
if (!TELEMETRY_URL) return;
|
|
1453
|
+
function sendTelemetry(url, data) {
|
|
1432
1454
|
if (!isEnabled()) return;
|
|
1433
1455
|
try {
|
|
1434
1456
|
const params = new URLSearchParams();
|
|
1435
1457
|
if (cliVersion) params.set("v", cliVersion);
|
|
1436
1458
|
if (isCI()) params.set("ci", "1");
|
|
1437
1459
|
for (const [key, value] of Object.entries(data)) if (value !== void 0 && value !== null) params.set(key, String(value));
|
|
1438
|
-
fetch(`${
|
|
1460
|
+
fetch(`${url}?${params.toString()}`).catch(() => {});
|
|
1439
1461
|
} catch {}
|
|
1440
1462
|
}
|
|
1463
|
+
function track(data) {
|
|
1464
|
+
if (!TELEMETRY_URL) return;
|
|
1465
|
+
sendTelemetry(TELEMETRY_URL, data);
|
|
1466
|
+
}
|
|
1467
|
+
function trackInstallReport(data) {
|
|
1468
|
+
if (!INSTALL_REPORT_URL) return;
|
|
1469
|
+
sendTelemetry(INSTALL_REPORT_URL, data);
|
|
1470
|
+
}
|
|
1441
1471
|
var ProviderRegistryImpl = class {
|
|
1442
1472
|
providers = [];
|
|
1443
1473
|
register(provider) {
|
|
@@ -1476,15 +1506,16 @@ var WellKnownProvider = class {
|
|
|
1476
1506
|
return { matches: false };
|
|
1477
1507
|
}
|
|
1478
1508
|
}
|
|
1479
|
-
async fetchIndex(baseUrl) {
|
|
1509
|
+
async fetchIndex(baseUrl, options = {}) {
|
|
1480
1510
|
try {
|
|
1511
|
+
const { fallbackToRoot = true } = options;
|
|
1481
1512
|
const parsed = new URL(baseUrl);
|
|
1482
1513
|
const basePath = parsed.pathname.replace(/\/$/, "");
|
|
1483
1514
|
const urlsToTry = [{
|
|
1484
1515
|
indexUrl: `${parsed.protocol}//${parsed.host}${basePath}/${this.WELL_KNOWN_PATH}/${this.INDEX_FILE}`,
|
|
1485
1516
|
baseUrl: `${parsed.protocol}//${parsed.host}${basePath}`
|
|
1486
1517
|
}];
|
|
1487
|
-
if (basePath && basePath !== "") urlsToTry.push({
|
|
1518
|
+
if (fallbackToRoot && basePath && basePath !== "") urlsToTry.push({
|
|
1488
1519
|
indexUrl: `${parsed.protocol}//${parsed.host}/${this.WELL_KNOWN_PATH}/${this.INDEX_FILE}`,
|
|
1489
1520
|
baseUrl: `${parsed.protocol}//${parsed.host}`
|
|
1490
1521
|
});
|
|
@@ -1532,10 +1563,10 @@ var WellKnownProvider = class {
|
|
|
1532
1563
|
if (!e.files.some((f) => typeof f === "string" && f.toLowerCase() === "skill.md")) return false;
|
|
1533
1564
|
return true;
|
|
1534
1565
|
}
|
|
1535
|
-
async fetchSkill(url) {
|
|
1566
|
+
async fetchSkill(url, options = {}) {
|
|
1536
1567
|
try {
|
|
1537
1568
|
const parsed = new URL(url);
|
|
1538
|
-
const result = await this.fetchIndex(url);
|
|
1569
|
+
const result = await this.fetchIndex(url, options);
|
|
1539
1570
|
if (!result) return null;
|
|
1540
1571
|
const { index, resolvedBaseUrl } = result;
|
|
1541
1572
|
let skillName = null;
|
|
@@ -1588,9 +1619,9 @@ var WellKnownProvider = class {
|
|
|
1588
1619
|
return null;
|
|
1589
1620
|
}
|
|
1590
1621
|
}
|
|
1591
|
-
async fetchAllSkills(url) {
|
|
1622
|
+
async fetchAllSkills(url, options = {}) {
|
|
1592
1623
|
try {
|
|
1593
|
-
const result = await this.fetchIndex(url);
|
|
1624
|
+
const result = await this.fetchIndex(url, options);
|
|
1594
1625
|
if (!result) return [];
|
|
1595
1626
|
const { index, resolvedBaseUrl } = result;
|
|
1596
1627
|
const skillPromises = index.skills.map((entry) => this.fetchSkillByEntry(resolvedBaseUrl, entry));
|
|
@@ -1621,8 +1652,8 @@ var WellKnownProvider = class {
|
|
|
1621
1652
|
return "unknown";
|
|
1622
1653
|
}
|
|
1623
1654
|
}
|
|
1624
|
-
async hasSkillsIndex(url) {
|
|
1625
|
-
return await this.fetchIndex(url) !== null;
|
|
1655
|
+
async hasSkillsIndex(url, options = {}) {
|
|
1656
|
+
return await this.fetchIndex(url, options) !== null;
|
|
1626
1657
|
}
|
|
1627
1658
|
};
|
|
1628
1659
|
const wellKnownProvider = new WellKnownProvider();
|
|
@@ -1802,7 +1833,7 @@ function createEmptyLocalLock() {
|
|
|
1802
1833
|
skills: {}
|
|
1803
1834
|
};
|
|
1804
1835
|
}
|
|
1805
|
-
var version$1 = "1.4.
|
|
1836
|
+
var version$1 = "1.4.5";
|
|
1806
1837
|
const isCancelled$1 = (value) => typeof value === "symbol";
|
|
1807
1838
|
async function isSourcePrivate(source) {
|
|
1808
1839
|
const ownerRepo = parseOwnerRepo(source);
|
|
@@ -1968,304 +1999,364 @@ async function selectAgentsInteractive(options) {
|
|
|
1968
1999
|
return selected;
|
|
1969
2000
|
}
|
|
1970
2001
|
setVersion(version$1);
|
|
2002
|
+
function resolveInstallOutcome(successCount, failCount) {
|
|
2003
|
+
if (failCount === 0) return "success";
|
|
2004
|
+
if (successCount === 0) return "failure";
|
|
2005
|
+
return "partial_failure";
|
|
2006
|
+
}
|
|
2007
|
+
function buildFailedDetails(results) {
|
|
2008
|
+
const failed = results.filter((result) => !result.success).map((result) => `${result.skill}@${result.agent}${result.error ? `:${result.error}` : ""}`);
|
|
2009
|
+
return failed.length > 0 ? JSON.stringify(failed) : void 0;
|
|
2010
|
+
}
|
|
2011
|
+
function reportInstallToSunIfNeeded(params) {
|
|
2012
|
+
if (!isInternalSkillSourceUrl(params.sourceUrl)) return;
|
|
2013
|
+
trackInstallReport({
|
|
2014
|
+
event: "install",
|
|
2015
|
+
source: params.source,
|
|
2016
|
+
sourceUrl: params.sourceUrl,
|
|
2017
|
+
skills: params.skills.join(","),
|
|
2018
|
+
agents: params.agents.join(","),
|
|
2019
|
+
...params.installGlobally && { global: "1" },
|
|
2020
|
+
...params.skillFiles && { skillFiles: JSON.stringify(params.skillFiles) },
|
|
2021
|
+
...params.sourceType && { sourceType: params.sourceType },
|
|
2022
|
+
result: resolveInstallOutcome(params.successfulCount, params.failedCount),
|
|
2023
|
+
successCount: String(params.successfulCount),
|
|
2024
|
+
failCount: String(params.failedCount),
|
|
2025
|
+
...params.failedDetails && { failedDetails: params.failedDetails },
|
|
2026
|
+
...params.errorMessage && { errorMessage: params.errorMessage }
|
|
2027
|
+
});
|
|
2028
|
+
}
|
|
1971
2029
|
function isBareSkillNameSource(source) {
|
|
1972
2030
|
return /^[a-z0-9]([a-z0-9-]{0,62}[a-z0-9])?$/.test(source);
|
|
1973
2031
|
}
|
|
1974
2032
|
function shouldProbeDefaultWellKnownPath(source) {
|
|
1975
2033
|
return source.includes("/") && !source.includes("@") && !source.startsWith("http://") && !source.startsWith("https://") && !source.startsWith("git@") && !source.startsWith("ssh://") && !source.startsWith("./") && !source.startsWith("../") && source !== "." && source !== "..";
|
|
1976
2034
|
}
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
}
|
|
1985
|
-
|
|
1986
|
-
Se(import_picocolors.default.red("No skills found at this URL. Make sure the server has a /.well-known/skills/index.json file."));
|
|
1987
|
-
process.exit(1);
|
|
1988
|
-
}
|
|
1989
|
-
spinner.stop(`Found ${import_picocolors.default.green(skills.length)} skill${skills.length > 1 ? "s" : ""}`);
|
|
1990
|
-
for (const skill of skills) {
|
|
1991
|
-
M.info(`Skill: ${import_picocolors.default.cyan(skill.installName)}`);
|
|
1992
|
-
M.message(import_picocolors.default.dim(skill.description));
|
|
1993
|
-
if (skill.files.size > 1) M.message(import_picocolors.default.dim(` Files: ${Array.from(skill.files.keys()).join(", ")}`));
|
|
1994
|
-
}
|
|
1995
|
-
if (options.list) {
|
|
1996
|
-
console.log();
|
|
1997
|
-
M.step(import_picocolors.default.bold("Available Skills"));
|
|
1998
|
-
for (const skill of skills) {
|
|
1999
|
-
M.message(` ${import_picocolors.default.cyan(skill.installName)}`);
|
|
2000
|
-
M.message(` ${import_picocolors.default.dim(skill.description)}`);
|
|
2001
|
-
if (skill.files.size > 1) M.message(` ${import_picocolors.default.dim(`Files: ${skill.files.size}`)}`);
|
|
2002
|
-
}
|
|
2003
|
-
console.log();
|
|
2004
|
-
Se("Run without --list to install");
|
|
2005
|
-
process.exit(0);
|
|
2006
|
-
}
|
|
2007
|
-
let selectedSkills;
|
|
2008
|
-
if (options.skill?.includes("*")) {
|
|
2009
|
-
selectedSkills = skills;
|
|
2010
|
-
M.info(`Installing all ${skills.length} skills`);
|
|
2011
|
-
} else if (options.skill && options.skill.length > 0) {
|
|
2012
|
-
selectedSkills = skills.filter((s) => options.skill.some((name) => s.installName.toLowerCase() === name.toLowerCase() || s.name.toLowerCase() === name.toLowerCase()));
|
|
2013
|
-
if (selectedSkills.length === 0) {
|
|
2035
|
+
function buildFallbackGitSshUrl(source) {
|
|
2036
|
+
return `git@${DEFAULT_GIT_FALLBACK_SSH_HOST}:${source.replace(/\.git$/, "")}.git`;
|
|
2037
|
+
}
|
|
2038
|
+
async function handleWellKnownSkills(source, url, options, spinner, allowFallback = false, fallbackToRoot = true) {
|
|
2039
|
+
const shouldReportToSun = isInternalSkillSourceUrl(url);
|
|
2040
|
+
try {
|
|
2041
|
+
spinner.start("Discovering skills from well-known endpoint...");
|
|
2042
|
+
const skills = await wellKnownProvider.fetchAllSkills(url, { fallbackToRoot });
|
|
2043
|
+
if (skills.length === 0) {
|
|
2014
2044
|
if (allowFallback) {
|
|
2015
|
-
|
|
2045
|
+
spinner.stop(import_picocolors.default.yellow("Default well-known endpoint unavailable"));
|
|
2016
2046
|
return false;
|
|
2017
2047
|
}
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
for (const s of skills) M.message(` - ${s.installName}`);
|
|
2048
|
+
spinner.stop(import_picocolors.default.red("No skills found"));
|
|
2049
|
+
Se(import_picocolors.default.red("No skills found at this URL. Make sure the server has a /.well-known/skills/index.json file."));
|
|
2021
2050
|
process.exit(1);
|
|
2022
2051
|
}
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
selectedSkills = skills;
|
|
2029
|
-
M.info(`Installing all ${skills.length} skills`);
|
|
2030
|
-
} else {
|
|
2031
|
-
const selected = await multiselect({
|
|
2032
|
-
message: "Select skills to install",
|
|
2033
|
-
options: skills.map((s) => ({
|
|
2034
|
-
value: s,
|
|
2035
|
-
label: s.installName,
|
|
2036
|
-
hint: s.description.length > 60 ? s.description.slice(0, 57) + "..." : s.description
|
|
2037
|
-
})),
|
|
2038
|
-
required: true
|
|
2039
|
-
});
|
|
2040
|
-
if (pD(selected)) {
|
|
2041
|
-
xe("Installation cancelled");
|
|
2042
|
-
process.exit(0);
|
|
2052
|
+
spinner.stop(`Found ${import_picocolors.default.green(skills.length)} skill${skills.length > 1 ? "s" : ""}`);
|
|
2053
|
+
for (const skill of skills) {
|
|
2054
|
+
M.info(`Skill: ${import_picocolors.default.cyan(skill.installName)}`);
|
|
2055
|
+
M.message(import_picocolors.default.dim(skill.description));
|
|
2056
|
+
if (skill.files.size > 1) M.message(import_picocolors.default.dim(` Files: ${Array.from(skill.files.keys()).join(", ")}`));
|
|
2043
2057
|
}
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
M.info(`Valid agents: ${validAgents.join(", ")}`);
|
|
2056
|
-
process.exit(1);
|
|
2058
|
+
if (options.list) {
|
|
2059
|
+
console.log();
|
|
2060
|
+
M.step(import_picocolors.default.bold("Available Skills"));
|
|
2061
|
+
for (const skill of skills) {
|
|
2062
|
+
M.message(` ${import_picocolors.default.cyan(skill.installName)}`);
|
|
2063
|
+
M.message(` ${import_picocolors.default.dim(skill.description)}`);
|
|
2064
|
+
if (skill.files.size > 1) M.message(` ${import_picocolors.default.dim(`Files: ${skill.files.size}`)}`);
|
|
2065
|
+
}
|
|
2066
|
+
console.log();
|
|
2067
|
+
Se("Run without --list to install");
|
|
2068
|
+
process.exit(0);
|
|
2057
2069
|
}
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2070
|
+
let selectedSkills;
|
|
2071
|
+
if (options.skill?.includes("*")) {
|
|
2072
|
+
selectedSkills = skills;
|
|
2073
|
+
M.info(`Installing all ${skills.length} skills`);
|
|
2074
|
+
} else if (options.skill && options.skill.length > 0) {
|
|
2075
|
+
selectedSkills = skills.filter((s) => options.skill.some((name) => s.installName.toLowerCase() === name.toLowerCase() || s.name.toLowerCase() === name.toLowerCase()));
|
|
2076
|
+
if (selectedSkills.length === 0) {
|
|
2077
|
+
if (allowFallback) {
|
|
2078
|
+
M.info(`Skill not found on default well-known endpoint: ${options.skill.join(", ")}`);
|
|
2079
|
+
return false;
|
|
2080
|
+
}
|
|
2081
|
+
M.error(`No matching skills found for: ${options.skill.join(", ")}`);
|
|
2082
|
+
M.info("Available skills:");
|
|
2083
|
+
for (const s of skills) M.message(` - ${s.installName}`);
|
|
2084
|
+
process.exit(1);
|
|
2085
|
+
}
|
|
2086
|
+
} else if (skills.length === 1) {
|
|
2087
|
+
selectedSkills = skills;
|
|
2088
|
+
const firstSkill = skills[0];
|
|
2089
|
+
M.info(`Skill: ${import_picocolors.default.cyan(firstSkill.installName)}`);
|
|
2090
|
+
} else if (options.yes) {
|
|
2091
|
+
selectedSkills = skills;
|
|
2092
|
+
M.info(`Installing all ${skills.length} skills`);
|
|
2067
2093
|
} else {
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2094
|
+
const selected = await multiselect({
|
|
2095
|
+
message: "Select skills to install",
|
|
2096
|
+
options: skills.map((s) => ({
|
|
2097
|
+
value: s,
|
|
2098
|
+
label: s.installName,
|
|
2099
|
+
hint: s.description.length > 60 ? s.description.slice(0, 57) + "..." : s.description
|
|
2100
|
+
})),
|
|
2101
|
+
required: true
|
|
2102
|
+
});
|
|
2073
2103
|
if (pD(selected)) {
|
|
2074
2104
|
xe("Installation cancelled");
|
|
2075
2105
|
process.exit(0);
|
|
2076
2106
|
}
|
|
2077
|
-
|
|
2107
|
+
selectedSkills = selected;
|
|
2078
2108
|
}
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2109
|
+
let targetAgents;
|
|
2110
|
+
const validAgents = Object.keys(agents);
|
|
2111
|
+
if (options.agent?.includes("*")) {
|
|
2112
|
+
targetAgents = validAgents;
|
|
2113
|
+
M.info(`Installing to all ${targetAgents.length} agents`);
|
|
2114
|
+
} else if (options.agent && options.agent.length > 0) {
|
|
2115
|
+
const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
|
|
2116
|
+
if (invalidAgents.length > 0) {
|
|
2117
|
+
M.error(`Invalid agents: ${invalidAgents.join(", ")}`);
|
|
2118
|
+
M.info(`Valid agents: ${validAgents.join(", ")}`);
|
|
2119
|
+
process.exit(1);
|
|
2120
|
+
}
|
|
2121
|
+
targetAgents = options.agent;
|
|
2085
2122
|
} else {
|
|
2086
|
-
|
|
2087
|
-
|
|
2123
|
+
spinner.start("Loading agents...");
|
|
2124
|
+
const installedAgents = await detectInstalledAgents();
|
|
2125
|
+
const totalAgents = Object.keys(agents).length;
|
|
2126
|
+
spinner.stop(`${totalAgents} agents`);
|
|
2127
|
+
if (installedAgents.length === 0) if (options.yes) {
|
|
2128
|
+
targetAgents = validAgents;
|
|
2129
|
+
M.info("Installing to all agents");
|
|
2130
|
+
} else {
|
|
2131
|
+
M.info("Select agents to install skills to");
|
|
2132
|
+
const selected = await promptForAgents("Which agents do you want to install to?", Object.entries(agents).map(([key, config]) => ({
|
|
2133
|
+
value: key,
|
|
2134
|
+
label: config.displayName
|
|
2135
|
+
})));
|
|
2136
|
+
if (pD(selected)) {
|
|
2137
|
+
xe("Installation cancelled");
|
|
2138
|
+
process.exit(0);
|
|
2139
|
+
}
|
|
2140
|
+
targetAgents = selected;
|
|
2141
|
+
}
|
|
2142
|
+
else if (installedAgents.length === 1 || options.yes) {
|
|
2143
|
+
targetAgents = ensureUniversalAgents(installedAgents);
|
|
2144
|
+
if (installedAgents.length === 1) {
|
|
2145
|
+
const firstAgent = installedAgents[0];
|
|
2146
|
+
M.info(`Installing to: ${import_picocolors.default.cyan(agents[firstAgent].displayName)}`);
|
|
2147
|
+
} else M.info(`Installing to: ${installedAgents.map((a) => import_picocolors.default.cyan(agents[a].displayName)).join(", ")}`);
|
|
2148
|
+
} else {
|
|
2149
|
+
const selected = await selectAgentsInteractive({ global: options.global });
|
|
2150
|
+
if (pD(selected)) {
|
|
2151
|
+
xe("Installation cancelled");
|
|
2152
|
+
process.exit(0);
|
|
2153
|
+
}
|
|
2154
|
+
targetAgents = selected;
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
let installGlobally = options.global ?? false;
|
|
2158
|
+
const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== void 0);
|
|
2159
|
+
if (options.global === void 0 && !options.yes && supportsGlobal) {
|
|
2160
|
+
const scope = await ve({
|
|
2161
|
+
message: "Installation scope",
|
|
2162
|
+
options: [{
|
|
2163
|
+
value: false,
|
|
2164
|
+
label: "Project",
|
|
2165
|
+
hint: "Install in current directory (committed with your project)"
|
|
2166
|
+
}, {
|
|
2167
|
+
value: true,
|
|
2168
|
+
label: "Global",
|
|
2169
|
+
hint: "Install in home directory (available across all projects)"
|
|
2170
|
+
}]
|
|
2171
|
+
});
|
|
2172
|
+
if (pD(scope)) {
|
|
2088
2173
|
xe("Installation cancelled");
|
|
2089
2174
|
process.exit(0);
|
|
2090
2175
|
}
|
|
2091
|
-
|
|
2176
|
+
installGlobally = scope;
|
|
2092
2177
|
}
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2178
|
+
let installMode = options.copy ? "copy" : "symlink";
|
|
2179
|
+
if (!options.copy && !options.yes) {
|
|
2180
|
+
const modeChoice = await ve({
|
|
2181
|
+
message: "Installation method",
|
|
2182
|
+
options: [{
|
|
2183
|
+
value: "symlink",
|
|
2184
|
+
label: "Symlink (Recommended)",
|
|
2185
|
+
hint: "Single source of truth, easy updates"
|
|
2186
|
+
}, {
|
|
2187
|
+
value: "copy",
|
|
2188
|
+
label: "Copy to all agents",
|
|
2189
|
+
hint: "Independent copies for each agent"
|
|
2190
|
+
}]
|
|
2191
|
+
});
|
|
2192
|
+
if (pD(modeChoice)) {
|
|
2193
|
+
xe("Installation cancelled");
|
|
2194
|
+
process.exit(0);
|
|
2195
|
+
}
|
|
2196
|
+
installMode = modeChoice;
|
|
2112
2197
|
}
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
label: "Copy to all agents",
|
|
2126
|
-
hint: "Independent copies for each agent"
|
|
2127
|
-
}]
|
|
2128
|
-
});
|
|
2129
|
-
if (pD(modeChoice)) {
|
|
2130
|
-
xe("Installation cancelled");
|
|
2131
|
-
process.exit(0);
|
|
2198
|
+
const cwd = process.cwd();
|
|
2199
|
+
const summaryLines = [];
|
|
2200
|
+
targetAgents.map((a) => agents[a].displayName);
|
|
2201
|
+
const overwriteChecks = await Promise.all(selectedSkills.flatMap((skill) => targetAgents.map(async (agent) => ({
|
|
2202
|
+
skillName: skill.installName,
|
|
2203
|
+
agent,
|
|
2204
|
+
installed: await isSkillInstalled(skill.installName, agent, { global: installGlobally })
|
|
2205
|
+
}))));
|
|
2206
|
+
const overwriteStatus = /* @__PURE__ */ new Map();
|
|
2207
|
+
for (const { skillName, agent, installed } of overwriteChecks) {
|
|
2208
|
+
if (!overwriteStatus.has(skillName)) overwriteStatus.set(skillName, /* @__PURE__ */ new Map());
|
|
2209
|
+
overwriteStatus.get(skillName).set(agent, installed);
|
|
2132
2210
|
}
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
}))));
|
|
2143
|
-
const overwriteStatus = /* @__PURE__ */ new Map();
|
|
2144
|
-
for (const { skillName, agent, installed } of overwriteChecks) {
|
|
2145
|
-
if (!overwriteStatus.has(skillName)) overwriteStatus.set(skillName, /* @__PURE__ */ new Map());
|
|
2146
|
-
overwriteStatus.get(skillName).set(agent, installed);
|
|
2147
|
-
}
|
|
2148
|
-
for (const skill of selectedSkills) {
|
|
2149
|
-
if (summaryLines.length > 0) summaryLines.push("");
|
|
2150
|
-
const shortCanonical = shortenPath$2(getCanonicalPath(skill.installName, { global: installGlobally }), cwd);
|
|
2151
|
-
summaryLines.push(`${import_picocolors.default.cyan(shortCanonical)}`);
|
|
2152
|
-
summaryLines.push(...buildAgentSummaryLines(targetAgents, installMode));
|
|
2153
|
-
if (skill.files.size > 1) summaryLines.push(` ${import_picocolors.default.dim("files:")} ${skill.files.size}`);
|
|
2154
|
-
const skillOverwrites = overwriteStatus.get(skill.installName);
|
|
2155
|
-
const overwriteAgents = targetAgents.filter((a) => skillOverwrites?.get(a)).map((a) => agents[a].displayName);
|
|
2156
|
-
if (overwriteAgents.length > 0) summaryLines.push(` ${import_picocolors.default.yellow("overwrites:")} ${formatList$1(overwriteAgents)}`);
|
|
2157
|
-
}
|
|
2158
|
-
console.log();
|
|
2159
|
-
Me(summaryLines.join("\n"), "Installation Summary");
|
|
2160
|
-
if (!options.yes) {
|
|
2161
|
-
const confirmed = await ye({ message: "Proceed with installation?" });
|
|
2162
|
-
if (pD(confirmed) || !confirmed) {
|
|
2163
|
-
xe("Installation cancelled");
|
|
2164
|
-
process.exit(0);
|
|
2211
|
+
for (const skill of selectedSkills) {
|
|
2212
|
+
if (summaryLines.length > 0) summaryLines.push("");
|
|
2213
|
+
const shortCanonical = shortenPath$2(getCanonicalPath(skill.installName, { global: installGlobally }), cwd);
|
|
2214
|
+
summaryLines.push(`${import_picocolors.default.cyan(shortCanonical)}`);
|
|
2215
|
+
summaryLines.push(...buildAgentSummaryLines(targetAgents, installMode));
|
|
2216
|
+
if (skill.files.size > 1) summaryLines.push(` ${import_picocolors.default.dim("files:")} ${skill.files.size}`);
|
|
2217
|
+
const skillOverwrites = overwriteStatus.get(skill.installName);
|
|
2218
|
+
const overwriteAgents = targetAgents.filter((a) => skillOverwrites?.get(a)).map((a) => agents[a].displayName);
|
|
2219
|
+
if (overwriteAgents.length > 0) summaryLines.push(` ${import_picocolors.default.yellow("overwrites:")} ${formatList$1(overwriteAgents)}`);
|
|
2165
2220
|
}
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2221
|
+
console.log();
|
|
2222
|
+
Me(summaryLines.join("\n"), "Installation Summary");
|
|
2223
|
+
if (!options.yes) {
|
|
2224
|
+
const confirmed = await ye({ message: "Proceed with installation?" });
|
|
2225
|
+
if (pD(confirmed) || !confirmed) {
|
|
2226
|
+
xe("Installation cancelled");
|
|
2227
|
+
process.exit(0);
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
spinner.start("Installing skills...");
|
|
2231
|
+
const results = [];
|
|
2232
|
+
for (const skill of selectedSkills) for (const agent of targetAgents) {
|
|
2233
|
+
const result = await installWellKnownSkillForAgent(skill, agent, {
|
|
2234
|
+
global: installGlobally,
|
|
2235
|
+
mode: installMode
|
|
2236
|
+
});
|
|
2237
|
+
results.push({
|
|
2238
|
+
skill: skill.installName,
|
|
2239
|
+
agent: agents[agent].displayName,
|
|
2240
|
+
...result
|
|
2241
|
+
});
|
|
2242
|
+
}
|
|
2243
|
+
spinner.stop("Installation complete");
|
|
2244
|
+
console.log();
|
|
2245
|
+
const successful = results.filter((r) => r.success);
|
|
2246
|
+
const failed = results.filter((r) => !r.success);
|
|
2247
|
+
const sourceIdentifier = wellKnownProvider.getSourceIdentifier(url);
|
|
2248
|
+
const skillFiles = {};
|
|
2249
|
+
for (const skill of selectedSkills) skillFiles[skill.installName] = skill.sourceUrl;
|
|
2250
|
+
if (await isSourcePrivate(sourceIdentifier) !== true) track({
|
|
2251
|
+
event: "install",
|
|
2252
|
+
source: sourceIdentifier,
|
|
2253
|
+
skills: selectedSkills.map((s) => s.installName).join(","),
|
|
2254
|
+
agents: targetAgents.join(","),
|
|
2255
|
+
...installGlobally && { global: "1" },
|
|
2256
|
+
skillFiles: JSON.stringify(skillFiles),
|
|
2257
|
+
sourceType: "well-known"
|
|
2173
2258
|
});
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2259
|
+
reportInstallToSunIfNeeded({
|
|
2260
|
+
source: sourceIdentifier,
|
|
2261
|
+
sourceUrl: url,
|
|
2262
|
+
skills: selectedSkills.map((s) => s.installName),
|
|
2263
|
+
agents: targetAgents,
|
|
2264
|
+
installGlobally,
|
|
2265
|
+
skillFiles,
|
|
2266
|
+
sourceType: "well-known",
|
|
2267
|
+
successfulCount: successful.length,
|
|
2268
|
+
failedCount: failed.length,
|
|
2269
|
+
failedDetails: buildFailedDetails(results)
|
|
2178
2270
|
});
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
const failed = results.filter((r) => !r.success);
|
|
2184
|
-
const sourceIdentifier = wellKnownProvider.getSourceIdentifier(url);
|
|
2185
|
-
const skillFiles = {};
|
|
2186
|
-
for (const skill of selectedSkills) skillFiles[skill.installName] = skill.sourceUrl;
|
|
2187
|
-
if (await isSourcePrivate(sourceIdentifier) !== true) track({
|
|
2188
|
-
event: "install",
|
|
2189
|
-
source: sourceIdentifier,
|
|
2190
|
-
skills: selectedSkills.map((s) => s.installName).join(","),
|
|
2191
|
-
agents: targetAgents.join(","),
|
|
2192
|
-
...installGlobally && { global: "1" },
|
|
2193
|
-
skillFiles: JSON.stringify(skillFiles),
|
|
2194
|
-
sourceType: "well-known"
|
|
2195
|
-
});
|
|
2196
|
-
if (successful.length > 0 && installGlobally) {
|
|
2197
|
-
const successfulSkillNames = new Set(successful.map((r) => r.skill));
|
|
2198
|
-
for (const skill of selectedSkills) if (successfulSkillNames.has(skill.installName)) try {
|
|
2199
|
-
await addSkillToLock(skill.installName, {
|
|
2200
|
-
source: sourceIdentifier,
|
|
2201
|
-
sourceType: "well-known",
|
|
2202
|
-
sourceUrl: skill.sourceUrl,
|
|
2203
|
-
skillFolderHash: ""
|
|
2204
|
-
});
|
|
2205
|
-
} catch {}
|
|
2206
|
-
}
|
|
2207
|
-
if (successful.length > 0 && !installGlobally) {
|
|
2208
|
-
const successfulSkillNames = new Set(successful.map((r) => r.skill));
|
|
2209
|
-
for (const skill of selectedSkills) if (successfulSkillNames.has(skill.installName)) try {
|
|
2210
|
-
const matchingResult = successful.find((r) => r.skill === skill.installName);
|
|
2211
|
-
const installDir = matchingResult?.canonicalPath || matchingResult?.path;
|
|
2212
|
-
if (installDir) {
|
|
2213
|
-
const computedHash = await computeSkillFolderHash(installDir);
|
|
2214
|
-
await addSkillToLocalLock(skill.installName, {
|
|
2271
|
+
if (successful.length > 0 && installGlobally) {
|
|
2272
|
+
const successfulSkillNames = new Set(successful.map((r) => r.skill));
|
|
2273
|
+
for (const skill of selectedSkills) if (successfulSkillNames.has(skill.installName)) try {
|
|
2274
|
+
await addSkillToLock(skill.installName, {
|
|
2215
2275
|
source: sourceIdentifier,
|
|
2216
2276
|
sourceType: "well-known",
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
}
|
|
2222
|
-
if (successful.length > 0) {
|
|
2223
|
-
const bySkill = /* @__PURE__ */ new Map();
|
|
2224
|
-
for (const r of successful) {
|
|
2225
|
-
const skillResults = bySkill.get(r.skill) || [];
|
|
2226
|
-
skillResults.push(r);
|
|
2227
|
-
bySkill.set(r.skill, skillResults);
|
|
2277
|
+
sourceUrl: skill.sourceUrl,
|
|
2278
|
+
skillFolderHash: ""
|
|
2279
|
+
});
|
|
2280
|
+
} catch {}
|
|
2228
2281
|
}
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2282
|
+
if (successful.length > 0 && !installGlobally) {
|
|
2283
|
+
const successfulSkillNames = new Set(successful.map((r) => r.skill));
|
|
2284
|
+
for (const skill of selectedSkills) if (successfulSkillNames.has(skill.installName)) try {
|
|
2285
|
+
const matchingResult = successful.find((r) => r.skill === skill.installName);
|
|
2286
|
+
const installDir = matchingResult?.canonicalPath || matchingResult?.path;
|
|
2287
|
+
if (installDir) {
|
|
2288
|
+
const computedHash = await computeSkillFolderHash(installDir);
|
|
2289
|
+
await addSkillToLocalLock(skill.installName, {
|
|
2290
|
+
source: sourceIdentifier,
|
|
2291
|
+
sourceType: "well-known",
|
|
2292
|
+
computedHash
|
|
2293
|
+
}, cwd);
|
|
2240
2294
|
}
|
|
2241
|
-
}
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2295
|
+
} catch {}
|
|
2296
|
+
}
|
|
2297
|
+
if (successful.length > 0) {
|
|
2298
|
+
const bySkill = /* @__PURE__ */ new Map();
|
|
2299
|
+
for (const r of successful) {
|
|
2300
|
+
const skillResults = bySkill.get(r.skill) || [];
|
|
2301
|
+
skillResults.push(r);
|
|
2302
|
+
bySkill.set(r.skill, skillResults);
|
|
2303
|
+
}
|
|
2304
|
+
const skillCount = bySkill.size;
|
|
2305
|
+
const symlinkFailures = successful.filter((r) => r.mode === "symlink" && r.symlinkFailed);
|
|
2306
|
+
const copiedAgents = symlinkFailures.map((r) => r.agent);
|
|
2307
|
+
const resultLines = [];
|
|
2308
|
+
for (const [skillName, skillResults] of bySkill) {
|
|
2309
|
+
const firstResult = skillResults[0];
|
|
2310
|
+
if (firstResult.mode === "copy") {
|
|
2311
|
+
resultLines.push(`${import_picocolors.default.green("✓")} ${skillName} ${import_picocolors.default.dim("(copied)")}`);
|
|
2312
|
+
for (const r of skillResults) {
|
|
2313
|
+
const shortPath = shortenPath$2(r.path, cwd);
|
|
2314
|
+
resultLines.push(` ${import_picocolors.default.dim("→")} ${shortPath}`);
|
|
2315
|
+
}
|
|
2316
|
+
} else {
|
|
2317
|
+
if (firstResult.canonicalPath) {
|
|
2318
|
+
const shortPath = shortenPath$2(firstResult.canonicalPath, cwd);
|
|
2319
|
+
resultLines.push(`${import_picocolors.default.green("✓")} ${shortPath}`);
|
|
2320
|
+
} else resultLines.push(`${import_picocolors.default.green("✓")} ${skillName}`);
|
|
2321
|
+
resultLines.push(...buildResultLines(skillResults, targetAgents));
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
const title = import_picocolors.default.green(`Installed ${skillCount} skill${skillCount !== 1 ? "s" : ""}`);
|
|
2325
|
+
Me(resultLines.join("\n"), title);
|
|
2326
|
+
if (symlinkFailures.length > 0) {
|
|
2327
|
+
M.warn(import_picocolors.default.yellow(`Symlinks failed for: ${formatList$1(copiedAgents)}`));
|
|
2328
|
+
M.message(import_picocolors.default.dim(" Files were copied instead. On Windows, enable Developer Mode for symlink support."));
|
|
2247
2329
|
}
|
|
2248
2330
|
}
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
M.
|
|
2253
|
-
M.message(import_picocolors.default.dim(" Files were copied instead. On Windows, enable Developer Mode for symlink support."));
|
|
2331
|
+
if (failed.length > 0) {
|
|
2332
|
+
console.log();
|
|
2333
|
+
M.error(import_picocolors.default.red(`Failed to install ${failed.length}`));
|
|
2334
|
+
for (const r of failed) M.message(` ${import_picocolors.default.red("✗")} ${r.skill} → ${r.agent}: ${import_picocolors.default.dim(r.error)}`);
|
|
2254
2335
|
}
|
|
2255
|
-
}
|
|
2256
|
-
if (failed.length > 0) {
|
|
2257
2336
|
console.log();
|
|
2258
|
-
|
|
2259
|
-
|
|
2337
|
+
Se(import_picocolors.default.green("Done!") + import_picocolors.default.dim(" Review skills before use; they run with full agent permissions."));
|
|
2338
|
+
await promptForFindSkills(options, targetAgents);
|
|
2339
|
+
return true;
|
|
2340
|
+
} catch (error) {
|
|
2341
|
+
if (shouldReportToSun) reportInstallToSunIfNeeded({
|
|
2342
|
+
source: wellKnownProvider.getSourceIdentifier(url),
|
|
2343
|
+
sourceUrl: url,
|
|
2344
|
+
skills: options.skill || [],
|
|
2345
|
+
agents: options.agent || [],
|
|
2346
|
+
installGlobally: options.global ?? false,
|
|
2347
|
+
sourceType: "well-known",
|
|
2348
|
+
successfulCount: 0,
|
|
2349
|
+
failedCount: 1,
|
|
2350
|
+
errorMessage: error instanceof Error ? error.message : "Unknown error occurred"
|
|
2351
|
+
});
|
|
2352
|
+
throw error;
|
|
2260
2353
|
}
|
|
2261
|
-
console.log();
|
|
2262
|
-
Se(import_picocolors.default.green("Done!") + import_picocolors.default.dim(" Review skills before use; they run with full agent permissions."));
|
|
2263
|
-
await promptForFindSkills(options, targetAgents);
|
|
2264
|
-
return true;
|
|
2265
2354
|
}
|
|
2266
2355
|
async function runAdd(args, options = {}) {
|
|
2267
2356
|
let source = args[0] || DEFAULT_WELL_KNOWN_BASE_URL;
|
|
2268
2357
|
let installTipShown = false;
|
|
2358
|
+
let parsed = null;
|
|
2359
|
+
let installReportContext = null;
|
|
2269
2360
|
const showInstallTip = () => {
|
|
2270
2361
|
if (installTipShown) return;
|
|
2271
2362
|
M.message(import_picocolors.default.dim("Tip: use the --yes (-y) and --global (-g) flags to install without prompts."));
|
|
@@ -2285,16 +2376,17 @@ async function runAdd(args, options = {}) {
|
|
|
2285
2376
|
if (source && isBareSkillNameSource(source)) {
|
|
2286
2377
|
options.skill = options.skill || [];
|
|
2287
2378
|
if (!options.skill.includes(source)) options.skill.push(source);
|
|
2288
|
-
if (await handleWellKnownSkills(source, DEFAULT_WELL_KNOWN_BASE_URL, options, spinner, true)) return;
|
|
2379
|
+
if (await handleWellKnownSkills(source, DEFAULT_WELL_KNOWN_BASE_URL, options, spinner, true, true)) return;
|
|
2289
2380
|
Se(import_picocolors.default.red(`No skills found for: ${source}`));
|
|
2290
2381
|
process.exit(1);
|
|
2291
2382
|
}
|
|
2292
2383
|
if (source && shouldProbeDefaultWellKnownPath(source)) {
|
|
2293
|
-
if (await handleWellKnownSkills(source, `${DEFAULT_WELL_KNOWN_BASE_URL}/${source.replace(/^\/+/, "")}`, options, spinner, true)) return;
|
|
2294
|
-
|
|
2384
|
+
if (await handleWellKnownSkills(source, `${DEFAULT_WELL_KNOWN_BASE_URL}/${source.replace(/^\/+/, "")}`, options, spinner, true, false)) return;
|
|
2385
|
+
source = buildFallbackGitSshUrl(source);
|
|
2386
|
+
M.info(`Falling back to git source: ${import_picocolors.default.cyan(source)}`);
|
|
2295
2387
|
}
|
|
2296
2388
|
spinner.start("Parsing source...");
|
|
2297
|
-
|
|
2389
|
+
parsed = parseSource(source);
|
|
2298
2390
|
spinner.stop(`Source: ${parsed.type === "local" ? parsed.localPath : parsed.url}${parsed.ref ? ` @ ${import_picocolors.default.yellow(parsed.ref)}` : ""}${parsed.subpath ? ` (${parsed.subpath})` : ""}${parsed.skillFilter ? ` ${import_picocolors.default.dim("@")}${import_picocolors.default.cyan(parsed.skillFilter)}` : ""}`);
|
|
2299
2391
|
if (parsed.skillFilter) {
|
|
2300
2392
|
options.skill = options.skill || [];
|
|
@@ -2617,6 +2709,15 @@ async function runAdd(args, options = {}) {
|
|
|
2617
2709
|
skillFiles[skill.name] = relativePath;
|
|
2618
2710
|
}
|
|
2619
2711
|
const normalizedSource = getOwnerRepo(parsed);
|
|
2712
|
+
installReportContext = {
|
|
2713
|
+
source: normalizedSource || parsed.url,
|
|
2714
|
+
sourceUrl: parsed.url,
|
|
2715
|
+
skills: selectedSkills.map((s) => s.name),
|
|
2716
|
+
agents: targetAgents,
|
|
2717
|
+
installGlobally,
|
|
2718
|
+
sourceType: parsed.type,
|
|
2719
|
+
skillFiles
|
|
2720
|
+
};
|
|
2620
2721
|
if (normalizedSource) {
|
|
2621
2722
|
const ownerRepo = parseOwnerRepo(normalizedSource);
|
|
2622
2723
|
if (ownerRepo) {
|
|
@@ -2637,6 +2738,18 @@ async function runAdd(args, options = {}) {
|
|
|
2637
2738
|
skillFiles: JSON.stringify(skillFiles)
|
|
2638
2739
|
});
|
|
2639
2740
|
}
|
|
2741
|
+
reportInstallToSunIfNeeded({
|
|
2742
|
+
source: installReportContext.source,
|
|
2743
|
+
sourceUrl: installReportContext.sourceUrl,
|
|
2744
|
+
skills: installReportContext.skills,
|
|
2745
|
+
agents: installReportContext.agents,
|
|
2746
|
+
installGlobally: installReportContext.installGlobally,
|
|
2747
|
+
sourceType: installReportContext.sourceType,
|
|
2748
|
+
skillFiles: installReportContext.skillFiles,
|
|
2749
|
+
successfulCount: successful.length,
|
|
2750
|
+
failedCount: failed.length,
|
|
2751
|
+
failedDetails: buildFailedDetails(results)
|
|
2752
|
+
});
|
|
2640
2753
|
if (successful.length > 0 && installGlobally && normalizedSource) {
|
|
2641
2754
|
const successfulSkillNames = new Set(successful.map((r) => r.skill));
|
|
2642
2755
|
for (const skill of selectedSkills) {
|
|
@@ -2740,6 +2853,18 @@ async function runAdd(args, options = {}) {
|
|
|
2740
2853
|
Se(import_picocolors.default.green("Done!") + import_picocolors.default.dim(" Review skills before use; they run with full agent permissions."));
|
|
2741
2854
|
await promptForFindSkills(options, targetAgents);
|
|
2742
2855
|
} catch (error) {
|
|
2856
|
+
if (parsed) reportInstallToSunIfNeeded({
|
|
2857
|
+
source: getOwnerRepo(parsed) || parsed.url,
|
|
2858
|
+
sourceUrl: parsed.url,
|
|
2859
|
+
skills: installReportContext?.skills || [],
|
|
2860
|
+
agents: installReportContext?.agents || [],
|
|
2861
|
+
installGlobally: installReportContext?.installGlobally || false,
|
|
2862
|
+
sourceType: installReportContext?.sourceType || parsed.type,
|
|
2863
|
+
skillFiles: installReportContext?.skillFiles,
|
|
2864
|
+
successfulCount: 0,
|
|
2865
|
+
failedCount: 1,
|
|
2866
|
+
errorMessage: error instanceof Error ? error.message : "Unknown error occurred"
|
|
2867
|
+
});
|
|
2743
2868
|
if (error instanceof GitCloneError) {
|
|
2744
2869
|
M.error(import_picocolors.default.red("Failed to clone repository"));
|
|
2745
2870
|
for (const line of error.message.split("\n")) M.message(import_picocolors.default.dim(line));
|