skai 0.0.6 → 0.0.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/index.js +370 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -740,6 +740,79 @@ function getSkillInstallPath(skillName, agent, options) {
|
|
|
740
740
|
const basePath = options.global ? agent.globalPath : path5.join(process.cwd(), agent.projectPath);
|
|
741
741
|
return path5.join(basePath, sanitizeName(skillName));
|
|
742
742
|
}
|
|
743
|
+
var DISABLED_SUFFIX = ".disabled";
|
|
744
|
+
function listManagedSkills(agent, options = {}) {
|
|
745
|
+
const skills = [];
|
|
746
|
+
const checkPath = (basePath, scope) => {
|
|
747
|
+
if (!fs5.existsSync(basePath)) return;
|
|
748
|
+
try {
|
|
749
|
+
const entries = fs5.readdirSync(basePath, { withFileTypes: true });
|
|
750
|
+
for (const entry of entries) {
|
|
751
|
+
if (entry.isDirectory() && !entry.name.startsWith(".")) {
|
|
752
|
+
const isDisabled = entry.name.endsWith(DISABLED_SUFFIX);
|
|
753
|
+
const name = isDisabled ? entry.name.slice(0, -DISABLED_SUFFIX.length) : entry.name;
|
|
754
|
+
skills.push({
|
|
755
|
+
name,
|
|
756
|
+
path: path5.join(basePath, entry.name),
|
|
757
|
+
agent,
|
|
758
|
+
scope,
|
|
759
|
+
enabled: !isDisabled
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
} catch {
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
if (!options.global) {
|
|
767
|
+
const projectPath = path5.join(process.cwd(), agent.projectPath);
|
|
768
|
+
checkPath(projectPath, "project");
|
|
769
|
+
}
|
|
770
|
+
if (!options.projectOnly) {
|
|
771
|
+
checkPath(agent.globalPath, "global");
|
|
772
|
+
}
|
|
773
|
+
return skills;
|
|
774
|
+
}
|
|
775
|
+
function toggleSkill(skill) {
|
|
776
|
+
const currentPath = skill.path;
|
|
777
|
+
const basePath = path5.dirname(currentPath);
|
|
778
|
+
const currentName = path5.basename(currentPath);
|
|
779
|
+
let newName;
|
|
780
|
+
let newEnabled;
|
|
781
|
+
if (skill.enabled) {
|
|
782
|
+
newName = currentName + DISABLED_SUFFIX;
|
|
783
|
+
newEnabled = false;
|
|
784
|
+
} else {
|
|
785
|
+
newName = currentName.slice(0, -DISABLED_SUFFIX.length);
|
|
786
|
+
newEnabled = true;
|
|
787
|
+
}
|
|
788
|
+
const newPath = path5.join(basePath, newName);
|
|
789
|
+
if (!isPathSafe(newPath, basePath)) {
|
|
790
|
+
return {
|
|
791
|
+
skillName: skill.name,
|
|
792
|
+
agent: skill.agent,
|
|
793
|
+
success: false,
|
|
794
|
+
enabled: skill.enabled,
|
|
795
|
+
error: "Invalid skill path"
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
try {
|
|
799
|
+
fs5.renameSync(currentPath, newPath);
|
|
800
|
+
return {
|
|
801
|
+
skillName: skill.name,
|
|
802
|
+
agent: skill.agent,
|
|
803
|
+
success: true,
|
|
804
|
+
enabled: newEnabled
|
|
805
|
+
};
|
|
806
|
+
} catch (error) {
|
|
807
|
+
return {
|
|
808
|
+
skillName: skill.name,
|
|
809
|
+
agent: skill.agent,
|
|
810
|
+
success: false,
|
|
811
|
+
enabled: skill.enabled,
|
|
812
|
+
error: error instanceof Error ? error.message : String(error)
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
}
|
|
743
816
|
|
|
744
817
|
// src/tree-select.ts
|
|
745
818
|
import * as p from "@clack/prompts";
|
|
@@ -1656,6 +1729,227 @@ async function treeSelect(nodes) {
|
|
|
1656
1729
|
return [];
|
|
1657
1730
|
}
|
|
1658
1731
|
|
|
1732
|
+
// src/skill-manager.ts
|
|
1733
|
+
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
1734
|
+
var MAX_VISIBLE_ITEMS2 = 12;
|
|
1735
|
+
var MAX_NAME_WIDTH = 25;
|
|
1736
|
+
var MAX_AGENT_WIDTH = 14;
|
|
1737
|
+
var S_STEP_ACTIVE2 = import_picocolors2.default.green("\u25C6");
|
|
1738
|
+
var S_STEP_CANCEL2 = import_picocolors2.default.red("\u25A0");
|
|
1739
|
+
var S_STEP_SUBMIT2 = import_picocolors2.default.green("\u25C7");
|
|
1740
|
+
var S_BAR2 = import_picocolors2.default.gray("\u2502");
|
|
1741
|
+
var S_BAR_END2 = import_picocolors2.default.gray("\u2514");
|
|
1742
|
+
var S_TOGGLE_ON = import_picocolors2.default.green("\u25CF");
|
|
1743
|
+
var S_TOGGLE_OFF = import_picocolors2.default.dim("\u25CB");
|
|
1744
|
+
var S_TOGGLE_ACTIVE_ON = import_picocolors2.default.green("\u25C9");
|
|
1745
|
+
var S_TOGGLE_ACTIVE_OFF = import_picocolors2.default.cyan("\u25CE");
|
|
1746
|
+
function symbol2(state) {
|
|
1747
|
+
switch (state) {
|
|
1748
|
+
case "active":
|
|
1749
|
+
return S_STEP_ACTIVE2;
|
|
1750
|
+
case "cancel":
|
|
1751
|
+
return S_STEP_CANCEL2;
|
|
1752
|
+
case "submit":
|
|
1753
|
+
return S_STEP_SUBMIT2;
|
|
1754
|
+
default:
|
|
1755
|
+
return import_picocolors2.default.cyan("\u25C6");
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
function getSkillKey(skill) {
|
|
1759
|
+
return `${skill.agent.name}:${skill.scope}:${skill.name}`;
|
|
1760
|
+
}
|
|
1761
|
+
var SkillManagerPrompt = class extends x {
|
|
1762
|
+
state_data;
|
|
1763
|
+
maxItems;
|
|
1764
|
+
constructor(skills) {
|
|
1765
|
+
super(
|
|
1766
|
+
{
|
|
1767
|
+
render: () => this.renderPrompt()
|
|
1768
|
+
},
|
|
1769
|
+
false
|
|
1770
|
+
);
|
|
1771
|
+
this.state_data = {
|
|
1772
|
+
skills,
|
|
1773
|
+
cursor: 0,
|
|
1774
|
+
scrollOffset: 0,
|
|
1775
|
+
changes: /* @__PURE__ */ new Map()
|
|
1776
|
+
};
|
|
1777
|
+
this.maxItems = MAX_VISIBLE_ITEMS2;
|
|
1778
|
+
this.on("cursor", (action) => this.handleCursor(action ?? "up"));
|
|
1779
|
+
}
|
|
1780
|
+
handleCursor(action) {
|
|
1781
|
+
switch (action) {
|
|
1782
|
+
case "up":
|
|
1783
|
+
this.state_data.cursor = Math.max(0, this.state_data.cursor - 1);
|
|
1784
|
+
this.adjustScroll();
|
|
1785
|
+
break;
|
|
1786
|
+
case "down":
|
|
1787
|
+
this.state_data.cursor = Math.min(
|
|
1788
|
+
this.state_data.skills.length - 1,
|
|
1789
|
+
this.state_data.cursor + 1
|
|
1790
|
+
);
|
|
1791
|
+
this.adjustScroll();
|
|
1792
|
+
break;
|
|
1793
|
+
case "space":
|
|
1794
|
+
this.toggleCurrent();
|
|
1795
|
+
break;
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
adjustScroll() {
|
|
1799
|
+
if (this.state_data.cursor < this.state_data.scrollOffset) {
|
|
1800
|
+
this.state_data.scrollOffset = this.state_data.cursor;
|
|
1801
|
+
} else if (this.state_data.cursor >= this.state_data.scrollOffset + this.maxItems) {
|
|
1802
|
+
this.state_data.scrollOffset = this.state_data.cursor - this.maxItems + 1;
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
toggleCurrent() {
|
|
1806
|
+
const skill = this.state_data.skills[this.state_data.cursor];
|
|
1807
|
+
if (!skill) return;
|
|
1808
|
+
const key = getSkillKey(skill);
|
|
1809
|
+
const currentState = this.state_data.changes.has(key) ? this.state_data.changes.get(key) : skill.enabled;
|
|
1810
|
+
this.state_data.changes.set(key, !currentState);
|
|
1811
|
+
}
|
|
1812
|
+
getEffectiveState(skill) {
|
|
1813
|
+
const key = getSkillKey(skill);
|
|
1814
|
+
return this.state_data.changes.has(key) ? this.state_data.changes.get(key) : skill.enabled;
|
|
1815
|
+
}
|
|
1816
|
+
renderPrompt() {
|
|
1817
|
+
const lines = [];
|
|
1818
|
+
const { skills, cursor, scrollOffset, changes } = this.state_data;
|
|
1819
|
+
lines.push(`${import_picocolors2.default.gray(S_BAR2)}`);
|
|
1820
|
+
lines.push(`${symbol2(this.state)} Manage installed skills`);
|
|
1821
|
+
if (this.state === "submit") {
|
|
1822
|
+
const changeCount2 = changes.size;
|
|
1823
|
+
if (changeCount2 === 0) {
|
|
1824
|
+
lines.push(`${import_picocolors2.default.gray(S_BAR2)} ${import_picocolors2.default.dim("No changes")}`);
|
|
1825
|
+
} else {
|
|
1826
|
+
lines.push(`${import_picocolors2.default.gray(S_BAR2)} ${import_picocolors2.default.dim(`${changeCount2} change(s) applied`)}`);
|
|
1827
|
+
}
|
|
1828
|
+
return lines.join("\n");
|
|
1829
|
+
}
|
|
1830
|
+
if (this.state === "cancel") {
|
|
1831
|
+
lines.push(`${import_picocolors2.default.gray(S_BAR2)} ${import_picocolors2.default.dim("Cancelled")}`);
|
|
1832
|
+
lines.push(`${import_picocolors2.default.gray(S_BAR2)}`);
|
|
1833
|
+
return lines.join("\n");
|
|
1834
|
+
}
|
|
1835
|
+
if (skills.length === 0) {
|
|
1836
|
+
lines.push(`${import_picocolors2.default.cyan(S_BAR2)}`);
|
|
1837
|
+
lines.push(`${import_picocolors2.default.cyan(S_BAR2)} ${import_picocolors2.default.dim("No skills installed")}`);
|
|
1838
|
+
lines.push(`${import_picocolors2.default.cyan(S_BAR2)} ${import_picocolors2.default.dim('Use "skai <source>" to install skills')}`);
|
|
1839
|
+
lines.push(`${import_picocolors2.default.cyan(S_BAR_END2)}`);
|
|
1840
|
+
return lines.join("\n");
|
|
1841
|
+
}
|
|
1842
|
+
const changeCount = changes.size;
|
|
1843
|
+
const changeText = changeCount > 0 ? import_picocolors2.default.yellow(` \u2022 ${changeCount} pending change(s)`) : "";
|
|
1844
|
+
lines.push(
|
|
1845
|
+
`${import_picocolors2.default.cyan(S_BAR2)} ${import_picocolors2.default.dim("\u2191/\u2193 navigate \u2022 space toggle \u2022 enter apply")}${changeText}`
|
|
1846
|
+
);
|
|
1847
|
+
lines.push(`${import_picocolors2.default.cyan(S_BAR2)} ${import_picocolors2.default.dim("\u2500".repeat(50))}`);
|
|
1848
|
+
const headerName = "SKILL".padEnd(MAX_NAME_WIDTH);
|
|
1849
|
+
const headerAgent = "AGENT".padEnd(MAX_AGENT_WIDTH);
|
|
1850
|
+
const headerScope = "SCOPE".padEnd(8);
|
|
1851
|
+
const headerStatus = "STATUS";
|
|
1852
|
+
lines.push(
|
|
1853
|
+
`${import_picocolors2.default.cyan(S_BAR2)} ${import_picocolors2.default.dim(" " + headerName + headerAgent + headerScope + headerStatus)}`
|
|
1854
|
+
);
|
|
1855
|
+
const aboveCount = scrollOffset;
|
|
1856
|
+
const belowCount = Math.max(0, skills.length - scrollOffset - this.maxItems);
|
|
1857
|
+
if (aboveCount > 0) {
|
|
1858
|
+
lines.push(`${import_picocolors2.default.cyan(S_BAR2)} ${import_picocolors2.default.dim(`\u2191 ${aboveCount} more above`)}`);
|
|
1859
|
+
}
|
|
1860
|
+
const visibleSkills = skills.slice(scrollOffset, scrollOffset + this.maxItems);
|
|
1861
|
+
for (let i = 0; i < visibleSkills.length; i++) {
|
|
1862
|
+
const skill = visibleSkills[i];
|
|
1863
|
+
const globalIndex = scrollOffset + i;
|
|
1864
|
+
const isActive = globalIndex === cursor;
|
|
1865
|
+
const enabled = this.getEffectiveState(skill);
|
|
1866
|
+
const wasChanged = changes.has(getSkillKey(skill));
|
|
1867
|
+
let toggle;
|
|
1868
|
+
if (isActive && enabled) {
|
|
1869
|
+
toggle = S_TOGGLE_ACTIVE_ON;
|
|
1870
|
+
} else if (isActive && !enabled) {
|
|
1871
|
+
toggle = S_TOGGLE_ACTIVE_OFF;
|
|
1872
|
+
} else if (enabled) {
|
|
1873
|
+
toggle = S_TOGGLE_ON;
|
|
1874
|
+
} else {
|
|
1875
|
+
toggle = S_TOGGLE_OFF;
|
|
1876
|
+
}
|
|
1877
|
+
const name = skill.name.length > MAX_NAME_WIDTH ? skill.name.slice(0, MAX_NAME_WIDTH - 2) + ".." : skill.name.padEnd(MAX_NAME_WIDTH);
|
|
1878
|
+
const agent = skill.agent.displayName.length > MAX_AGENT_WIDTH ? skill.agent.displayName.slice(0, MAX_AGENT_WIDTH - 2) + ".." : skill.agent.displayName.padEnd(MAX_AGENT_WIDTH);
|
|
1879
|
+
const scope = skill.scope.padEnd(8);
|
|
1880
|
+
const status = enabled ? import_picocolors2.default.green("enabled") : import_picocolors2.default.dim("disabled");
|
|
1881
|
+
const changedMarker = wasChanged ? import_picocolors2.default.yellow(" *") : "";
|
|
1882
|
+
const line = isActive ? `${toggle} ${name}${agent}${scope}${status}${changedMarker}` : `${toggle} ${import_picocolors2.default.dim(name)}${import_picocolors2.default.dim(agent)}${import_picocolors2.default.dim(scope)}${status}${changedMarker}`;
|
|
1883
|
+
lines.push(`${import_picocolors2.default.cyan(S_BAR2)} ${line}`);
|
|
1884
|
+
}
|
|
1885
|
+
if (belowCount > 0) {
|
|
1886
|
+
lines.push(`${import_picocolors2.default.cyan(S_BAR2)} ${import_picocolors2.default.dim(`\u2193 ${belowCount} more below`)}`);
|
|
1887
|
+
}
|
|
1888
|
+
lines.push(`${import_picocolors2.default.cyan(S_BAR_END2)}`);
|
|
1889
|
+
return lines.join("\n");
|
|
1890
|
+
}
|
|
1891
|
+
async run() {
|
|
1892
|
+
const result = await this.prompt();
|
|
1893
|
+
if (BD(result)) {
|
|
1894
|
+
return result;
|
|
1895
|
+
}
|
|
1896
|
+
return {
|
|
1897
|
+
skills: this.state_data.skills,
|
|
1898
|
+
changes: this.state_data.changes
|
|
1899
|
+
};
|
|
1900
|
+
}
|
|
1901
|
+
};
|
|
1902
|
+
async function manageSkills() {
|
|
1903
|
+
let targetAgents = detectInstalledAgents();
|
|
1904
|
+
if (targetAgents.length === 0) {
|
|
1905
|
+
targetAgents = getAllAgents();
|
|
1906
|
+
}
|
|
1907
|
+
const allSkills = [];
|
|
1908
|
+
for (const agent of targetAgents) {
|
|
1909
|
+
const skills2 = listManagedSkills(agent);
|
|
1910
|
+
allSkills.push(...skills2);
|
|
1911
|
+
}
|
|
1912
|
+
allSkills.sort((a, b2) => {
|
|
1913
|
+
const agentCmp = a.agent.displayName.localeCompare(b2.agent.displayName);
|
|
1914
|
+
if (agentCmp !== 0) return agentCmp;
|
|
1915
|
+
const scopeCmp = a.scope.localeCompare(b2.scope);
|
|
1916
|
+
if (scopeCmp !== 0) return scopeCmp;
|
|
1917
|
+
return a.name.localeCompare(b2.name);
|
|
1918
|
+
});
|
|
1919
|
+
const prompt = new SkillManagerPrompt(allSkills);
|
|
1920
|
+
const result = await prompt.run();
|
|
1921
|
+
if (BD(result)) {
|
|
1922
|
+
return null;
|
|
1923
|
+
}
|
|
1924
|
+
const { skills, changes } = result;
|
|
1925
|
+
if (changes.size === 0) {
|
|
1926
|
+
return { enabled: 0, disabled: 0, failed: 0, errors: [] };
|
|
1927
|
+
}
|
|
1928
|
+
const results = { enabled: 0, disabled: 0, failed: 0, errors: [] };
|
|
1929
|
+
for (const skill of skills) {
|
|
1930
|
+
const key = getSkillKey(skill);
|
|
1931
|
+
if (!changes.has(key)) continue;
|
|
1932
|
+
const newState = changes.get(key);
|
|
1933
|
+
if (newState === skill.enabled) continue;
|
|
1934
|
+
const toggleResult = toggleSkill(skill);
|
|
1935
|
+
if (toggleResult.success) {
|
|
1936
|
+
if (toggleResult.enabled) {
|
|
1937
|
+
results.enabled++;
|
|
1938
|
+
} else {
|
|
1939
|
+
results.disabled++;
|
|
1940
|
+
}
|
|
1941
|
+
} else {
|
|
1942
|
+
results.failed++;
|
|
1943
|
+
results.errors.push({
|
|
1944
|
+
skill: skill.name,
|
|
1945
|
+
agent: skill.agent.displayName,
|
|
1946
|
+
error: toggleResult.error || "Unknown error"
|
|
1947
|
+
});
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
return results;
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1659
1953
|
// src/dependencies.ts
|
|
1660
1954
|
import * as fs6 from "fs";
|
|
1661
1955
|
import * as path6 from "path";
|
|
@@ -1929,31 +2223,31 @@ function formatInstallStatus(statuses, isDryRun) {
|
|
|
1929
2223
|
${agent}:`));
|
|
1930
2224
|
for (const skill of skills) {
|
|
1931
2225
|
let icon;
|
|
1932
|
-
let
|
|
2226
|
+
let color3;
|
|
1933
2227
|
let suffix = "";
|
|
1934
2228
|
switch (skill.status) {
|
|
1935
2229
|
case "installed":
|
|
1936
2230
|
icon = "\u2713";
|
|
1937
|
-
|
|
2231
|
+
color3 = chalk.green;
|
|
1938
2232
|
suffix = skill.path ? chalk.dim(` \u2192 ${skill.path}`) : "";
|
|
1939
2233
|
break;
|
|
1940
2234
|
case "would-install":
|
|
1941
2235
|
icon = "\u25CB";
|
|
1942
|
-
|
|
2236
|
+
color3 = chalk.cyan;
|
|
1943
2237
|
suffix = skill.path ? chalk.dim(` \u2192 ${skill.path}`) : "";
|
|
1944
2238
|
break;
|
|
1945
2239
|
case "skipped":
|
|
1946
2240
|
icon = "\u2013";
|
|
1947
|
-
|
|
2241
|
+
color3 = chalk.yellow;
|
|
1948
2242
|
suffix = skill.reason ? chalk.dim(` (${skill.reason})`) : "";
|
|
1949
2243
|
break;
|
|
1950
2244
|
case "failed":
|
|
1951
2245
|
icon = "\u2717";
|
|
1952
|
-
|
|
2246
|
+
color3 = chalk.red;
|
|
1953
2247
|
suffix = skill.reason ? chalk.dim(` (${skill.reason})`) : "";
|
|
1954
2248
|
break;
|
|
1955
2249
|
}
|
|
1956
|
-
console.log(` ${
|
|
2250
|
+
console.log(` ${color3(icon)} ${skill.skillName}${suffix}`);
|
|
1957
2251
|
}
|
|
1958
2252
|
}
|
|
1959
2253
|
if (isDryRun) {
|
|
@@ -1977,12 +2271,6 @@ async function runInstall(source, options) {
|
|
|
1977
2271
|
clack.intro(chalk.cyan("skai - AI Agent Skills Package Manager"));
|
|
1978
2272
|
if (!source) {
|
|
1979
2273
|
clack.log.error("Please provide a source (GitHub repo, URL, or local path)");
|
|
1980
|
-
clack.log.info("Usage: skai <source> [options]");
|
|
1981
|
-
clack.log.info("");
|
|
1982
|
-
clack.log.info("Examples:");
|
|
1983
|
-
clack.log.info(" skai pproenca/dot-skills");
|
|
1984
|
-
clack.log.info(" skai https://github.com/org/repo");
|
|
1985
|
-
clack.log.info(" skai ./local/skills");
|
|
1986
2274
|
clack.outro(chalk.red("No source provided"));
|
|
1987
2275
|
process.exit(EXIT_ERROR);
|
|
1988
2276
|
}
|
|
@@ -2602,10 +2890,42 @@ async function runUpdate(_skillNames, _options) {
|
|
|
2602
2890
|
clack.log.info(" 2. Reinstall from the source: skai <source>");
|
|
2603
2891
|
clack.outro(chalk.yellow("Update not yet implemented"));
|
|
2604
2892
|
}
|
|
2893
|
+
async function runManage() {
|
|
2894
|
+
if (!process.stdin.isTTY) {
|
|
2895
|
+
clack.log.error("Interactive mode requires a TTY.");
|
|
2896
|
+
clack.log.info('Use "skai list" to view installed skills.');
|
|
2897
|
+
process.exit(EXIT_ERROR);
|
|
2898
|
+
}
|
|
2899
|
+
clack.intro(chalk.cyan("skai - Skill Manager"));
|
|
2900
|
+
const result = await manageSkills();
|
|
2901
|
+
if (result === null) {
|
|
2902
|
+
clack.outro(chalk.yellow("Cancelled"));
|
|
2903
|
+
return;
|
|
2904
|
+
}
|
|
2905
|
+
if (result.enabled === 0 && result.disabled === 0 && result.failed === 0) {
|
|
2906
|
+
clack.outro(chalk.dim("No changes made"));
|
|
2907
|
+
return;
|
|
2908
|
+
}
|
|
2909
|
+
const parts = [];
|
|
2910
|
+
if (result.enabled > 0) parts.push(chalk.green(`${result.enabled} enabled`));
|
|
2911
|
+
if (result.disabled > 0) parts.push(chalk.yellow(`${result.disabled} disabled`));
|
|
2912
|
+
if (result.failed > 0) parts.push(chalk.red(`${result.failed} failed`));
|
|
2913
|
+
for (const err of result.errors) {
|
|
2914
|
+
clack.log.warn(`Failed to update ${err.skill} (${err.agent}): ${err.error}`);
|
|
2915
|
+
}
|
|
2916
|
+
if (result.enabled > 0 || result.disabled > 0) {
|
|
2917
|
+
clack.note("Restart your AI agent to apply changes.", "Next steps");
|
|
2918
|
+
}
|
|
2919
|
+
clack.outro(parts.join(", "));
|
|
2920
|
+
}
|
|
2605
2921
|
async function main() {
|
|
2606
2922
|
const program = new Command();
|
|
2607
2923
|
program.name("skai").description("The package manager for AI agent skills").version(getVersion(), "-V, --version", "Display version");
|
|
2608
2924
|
program.argument("[source]", "GitHub repo, URL, or local path to install skills from").option("-g, --global", "Install to user directory instead of project", false).option("-a, --agent <agents...>", "Target specific agents").option("-s, --skill <skills...>", "Install specific skills by name").option("-l, --list", "List available skills without installing", false).option("-y, --yes", "Skip confirmation prompts", false).option("--json", "Output results in JSON format", false).option("--dry-run", "Preview installation without making changes", false).action(async (source, options) => {
|
|
2925
|
+
if (!source) {
|
|
2926
|
+
await runManage();
|
|
2927
|
+
return;
|
|
2928
|
+
}
|
|
2609
2929
|
await runInstall(source, options);
|
|
2610
2930
|
});
|
|
2611
2931
|
program.command("install <source>").description("Install skills from a source").option("-g, --global", "Install to user directory instead of project", false).option("-a, --agent <agents...>", "Target specific agents").option("-s, --skill <skills...>", "Install specific skills by name").option("-l, --list", "List available skills without installing", false).option("-y, --yes", "Skip confirmation prompts", false).option("--json", "Output results in JSON format", false).option("--dry-run", "Preview installation without making changes", false).action(async (source, options) => {
|
|
@@ -2620,24 +2940,50 @@ async function main() {
|
|
|
2620
2940
|
program.command("update [skills...]").alias("up").description("Update installed skills (coming soon)").option("-g, --global", "Update global skills", false).option("-a, --agent <agents...>", "Target specific agents").option("-y, --yes", "Skip confirmation prompts", false).option("--json", "Output results in JSON format", false).action(async (skills, options) => {
|
|
2621
2941
|
await runUpdate(skills, options);
|
|
2622
2942
|
});
|
|
2943
|
+
program.command("manage").description("Interactively enable/disable installed skills").action(async () => {
|
|
2944
|
+
await runManage();
|
|
2945
|
+
});
|
|
2623
2946
|
program.addHelpText(
|
|
2624
2947
|
"after",
|
|
2625
2948
|
`
|
|
2626
|
-
|
|
2627
|
-
$
|
|
2628
|
-
$ skai
|
|
2629
|
-
|
|
2630
|
-
$
|
|
2631
|
-
$ skai
|
|
2632
|
-
$ skai pproenca/dot-skills --dry-run Preview installation
|
|
2633
|
-
$ skai list List installed skills
|
|
2634
|
-
$ skai list -a cursor List skills for specific agent
|
|
2635
|
-
$ skai uninstall typescript Uninstall a skill
|
|
2636
|
-
$ skai uninstall typescript -a cursor Uninstall from specific agent
|
|
2949
|
+
${chalk.yellow("EXAMPLES")}
|
|
2950
|
+
${chalk.dim("# Install skills from GitHub")}
|
|
2951
|
+
$ skai pproenca/dot-skills
|
|
2952
|
+
|
|
2953
|
+
${chalk.dim("# Install from full URL")}
|
|
2954
|
+
$ skai https://github.com/org/repo
|
|
2637
2955
|
|
|
2638
|
-
|
|
2956
|
+
${chalk.dim("# Install from local directory")}
|
|
2957
|
+
$ skai ./local/skills
|
|
2958
|
+
|
|
2959
|
+
${chalk.dim("# Install specific skill to specific agent")}
|
|
2960
|
+
$ skai pproenca/dot-skills -s typescript -a claude-code
|
|
2961
|
+
|
|
2962
|
+
${chalk.dim("# Preview installation without changes")}
|
|
2963
|
+
$ skai pproenca/dot-skills --dry-run
|
|
2964
|
+
|
|
2965
|
+
${chalk.dim("# List installed skills")}
|
|
2966
|
+
$ skai list
|
|
2967
|
+
|
|
2968
|
+
${chalk.dim("# List skills for specific agent")}
|
|
2969
|
+
$ skai list -a cursor
|
|
2970
|
+
|
|
2971
|
+
${chalk.dim("# Uninstall a skill")}
|
|
2972
|
+
$ skai uninstall typescript
|
|
2973
|
+
|
|
2974
|
+
${chalk.dim("# Uninstall from specific agent")}
|
|
2975
|
+
$ skai uninstall typescript -a cursor
|
|
2976
|
+
|
|
2977
|
+
${chalk.dim("# Manage skills (enable/disable)")}
|
|
2978
|
+
$ skai
|
|
2979
|
+
$ skai manage
|
|
2980
|
+
|
|
2981
|
+
${chalk.yellow("SUPPORTED AGENTS")}
|
|
2639
2982
|
claude-code, cursor, copilot, windsurf, codex, opencode, amp,
|
|
2640
2983
|
kilo-code, roo-code, goose, gemini, antigravity, clawdbot, droid
|
|
2984
|
+
|
|
2985
|
+
${chalk.yellow("LEARN MORE")}
|
|
2986
|
+
GitHub: ${chalk.cyan("https://github.com/pproenca/skai")}
|
|
2641
2987
|
`
|
|
2642
2988
|
);
|
|
2643
2989
|
await program.parseAsync(process.argv);
|