skai 0.0.6 → 0.0.8
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 +368 -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,225 @@ 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("\u25FC");
|
|
1743
|
+
var S_TOGGLE_OFF = import_picocolors2.default.dim("\u25FB");
|
|
1744
|
+
var S_TOGGLE_ACTIVE_ON = import_picocolors2.default.green("\u25FC");
|
|
1745
|
+
var S_TOGGLE_ACTIVE_OFF = import_picocolors2.default.cyan("\u25FB");
|
|
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";
|
|
1851
|
+
lines.push(
|
|
1852
|
+
`${import_picocolors2.default.cyan(S_BAR2)} ${import_picocolors2.default.dim(" " + headerName + headerAgent + headerScope)}`
|
|
1853
|
+
);
|
|
1854
|
+
const aboveCount = scrollOffset;
|
|
1855
|
+
const belowCount = Math.max(0, skills.length - scrollOffset - this.maxItems);
|
|
1856
|
+
if (aboveCount > 0) {
|
|
1857
|
+
lines.push(`${import_picocolors2.default.cyan(S_BAR2)} ${import_picocolors2.default.dim(`\u2191 ${aboveCount} more above`)}`);
|
|
1858
|
+
}
|
|
1859
|
+
const visibleSkills = skills.slice(scrollOffset, scrollOffset + this.maxItems);
|
|
1860
|
+
for (let i = 0; i < visibleSkills.length; i++) {
|
|
1861
|
+
const skill = visibleSkills[i];
|
|
1862
|
+
const globalIndex = scrollOffset + i;
|
|
1863
|
+
const isActive = globalIndex === cursor;
|
|
1864
|
+
const enabled = this.getEffectiveState(skill);
|
|
1865
|
+
const wasChanged = changes.has(getSkillKey(skill));
|
|
1866
|
+
let toggle;
|
|
1867
|
+
if (isActive && enabled) {
|
|
1868
|
+
toggle = S_TOGGLE_ACTIVE_ON;
|
|
1869
|
+
} else if (isActive && !enabled) {
|
|
1870
|
+
toggle = S_TOGGLE_ACTIVE_OFF;
|
|
1871
|
+
} else if (enabled) {
|
|
1872
|
+
toggle = S_TOGGLE_ON;
|
|
1873
|
+
} else {
|
|
1874
|
+
toggle = S_TOGGLE_OFF;
|
|
1875
|
+
}
|
|
1876
|
+
const name = skill.name.length > MAX_NAME_WIDTH ? skill.name.slice(0, MAX_NAME_WIDTH - 2) + ".." : skill.name.padEnd(MAX_NAME_WIDTH);
|
|
1877
|
+
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);
|
|
1878
|
+
const scope = skill.scope;
|
|
1879
|
+
const changedMarker = wasChanged ? import_picocolors2.default.yellow(" *") : "";
|
|
1880
|
+
const line = isActive ? `${toggle} ${name}${agent}${scope}${changedMarker}` : `${toggle} ${import_picocolors2.default.dim(name)}${import_picocolors2.default.dim(agent)}${import_picocolors2.default.dim(scope)}${changedMarker}`;
|
|
1881
|
+
lines.push(`${import_picocolors2.default.cyan(S_BAR2)} ${line}`);
|
|
1882
|
+
}
|
|
1883
|
+
if (belowCount > 0) {
|
|
1884
|
+
lines.push(`${import_picocolors2.default.cyan(S_BAR2)} ${import_picocolors2.default.dim(`\u2193 ${belowCount} more below`)}`);
|
|
1885
|
+
}
|
|
1886
|
+
lines.push(`${import_picocolors2.default.cyan(S_BAR_END2)}`);
|
|
1887
|
+
return lines.join("\n");
|
|
1888
|
+
}
|
|
1889
|
+
async run() {
|
|
1890
|
+
const result = await this.prompt();
|
|
1891
|
+
if (BD(result)) {
|
|
1892
|
+
return result;
|
|
1893
|
+
}
|
|
1894
|
+
return {
|
|
1895
|
+
skills: this.state_data.skills,
|
|
1896
|
+
changes: this.state_data.changes
|
|
1897
|
+
};
|
|
1898
|
+
}
|
|
1899
|
+
};
|
|
1900
|
+
async function manageSkills() {
|
|
1901
|
+
let targetAgents = detectInstalledAgents();
|
|
1902
|
+
if (targetAgents.length === 0) {
|
|
1903
|
+
targetAgents = getAllAgents();
|
|
1904
|
+
}
|
|
1905
|
+
const allSkills = [];
|
|
1906
|
+
for (const agent of targetAgents) {
|
|
1907
|
+
const skills2 = listManagedSkills(agent);
|
|
1908
|
+
allSkills.push(...skills2);
|
|
1909
|
+
}
|
|
1910
|
+
allSkills.sort((a, b2) => {
|
|
1911
|
+
const agentCmp = a.agent.displayName.localeCompare(b2.agent.displayName);
|
|
1912
|
+
if (agentCmp !== 0) return agentCmp;
|
|
1913
|
+
const scopeCmp = a.scope.localeCompare(b2.scope);
|
|
1914
|
+
if (scopeCmp !== 0) return scopeCmp;
|
|
1915
|
+
return a.name.localeCompare(b2.name);
|
|
1916
|
+
});
|
|
1917
|
+
const prompt = new SkillManagerPrompt(allSkills);
|
|
1918
|
+
const result = await prompt.run();
|
|
1919
|
+
if (BD(result)) {
|
|
1920
|
+
return null;
|
|
1921
|
+
}
|
|
1922
|
+
const { skills, changes } = result;
|
|
1923
|
+
if (changes.size === 0) {
|
|
1924
|
+
return { enabled: 0, disabled: 0, failed: 0, errors: [] };
|
|
1925
|
+
}
|
|
1926
|
+
const results = { enabled: 0, disabled: 0, failed: 0, errors: [] };
|
|
1927
|
+
for (const skill of skills) {
|
|
1928
|
+
const key = getSkillKey(skill);
|
|
1929
|
+
if (!changes.has(key)) continue;
|
|
1930
|
+
const newState = changes.get(key);
|
|
1931
|
+
if (newState === skill.enabled) continue;
|
|
1932
|
+
const toggleResult = toggleSkill(skill);
|
|
1933
|
+
if (toggleResult.success) {
|
|
1934
|
+
if (toggleResult.enabled) {
|
|
1935
|
+
results.enabled++;
|
|
1936
|
+
} else {
|
|
1937
|
+
results.disabled++;
|
|
1938
|
+
}
|
|
1939
|
+
} else {
|
|
1940
|
+
results.failed++;
|
|
1941
|
+
results.errors.push({
|
|
1942
|
+
skill: skill.name,
|
|
1943
|
+
agent: skill.agent.displayName,
|
|
1944
|
+
error: toggleResult.error || "Unknown error"
|
|
1945
|
+
});
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
return results;
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1659
1951
|
// src/dependencies.ts
|
|
1660
1952
|
import * as fs6 from "fs";
|
|
1661
1953
|
import * as path6 from "path";
|
|
@@ -1929,31 +2221,31 @@ function formatInstallStatus(statuses, isDryRun) {
|
|
|
1929
2221
|
${agent}:`));
|
|
1930
2222
|
for (const skill of skills) {
|
|
1931
2223
|
let icon;
|
|
1932
|
-
let
|
|
2224
|
+
let color3;
|
|
1933
2225
|
let suffix = "";
|
|
1934
2226
|
switch (skill.status) {
|
|
1935
2227
|
case "installed":
|
|
1936
2228
|
icon = "\u2713";
|
|
1937
|
-
|
|
2229
|
+
color3 = chalk.green;
|
|
1938
2230
|
suffix = skill.path ? chalk.dim(` \u2192 ${skill.path}`) : "";
|
|
1939
2231
|
break;
|
|
1940
2232
|
case "would-install":
|
|
1941
2233
|
icon = "\u25CB";
|
|
1942
|
-
|
|
2234
|
+
color3 = chalk.cyan;
|
|
1943
2235
|
suffix = skill.path ? chalk.dim(` \u2192 ${skill.path}`) : "";
|
|
1944
2236
|
break;
|
|
1945
2237
|
case "skipped":
|
|
1946
2238
|
icon = "\u2013";
|
|
1947
|
-
|
|
2239
|
+
color3 = chalk.yellow;
|
|
1948
2240
|
suffix = skill.reason ? chalk.dim(` (${skill.reason})`) : "";
|
|
1949
2241
|
break;
|
|
1950
2242
|
case "failed":
|
|
1951
2243
|
icon = "\u2717";
|
|
1952
|
-
|
|
2244
|
+
color3 = chalk.red;
|
|
1953
2245
|
suffix = skill.reason ? chalk.dim(` (${skill.reason})`) : "";
|
|
1954
2246
|
break;
|
|
1955
2247
|
}
|
|
1956
|
-
console.log(` ${
|
|
2248
|
+
console.log(` ${color3(icon)} ${skill.skillName}${suffix}`);
|
|
1957
2249
|
}
|
|
1958
2250
|
}
|
|
1959
2251
|
if (isDryRun) {
|
|
@@ -1977,12 +2269,6 @@ async function runInstall(source, options) {
|
|
|
1977
2269
|
clack.intro(chalk.cyan("skai - AI Agent Skills Package Manager"));
|
|
1978
2270
|
if (!source) {
|
|
1979
2271
|
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
2272
|
clack.outro(chalk.red("No source provided"));
|
|
1987
2273
|
process.exit(EXIT_ERROR);
|
|
1988
2274
|
}
|
|
@@ -2602,10 +2888,42 @@ async function runUpdate(_skillNames, _options) {
|
|
|
2602
2888
|
clack.log.info(" 2. Reinstall from the source: skai <source>");
|
|
2603
2889
|
clack.outro(chalk.yellow("Update not yet implemented"));
|
|
2604
2890
|
}
|
|
2891
|
+
async function runManage() {
|
|
2892
|
+
if (!process.stdin.isTTY) {
|
|
2893
|
+
clack.log.error("Interactive mode requires a TTY.");
|
|
2894
|
+
clack.log.info('Use "skai list" to view installed skills.');
|
|
2895
|
+
process.exit(EXIT_ERROR);
|
|
2896
|
+
}
|
|
2897
|
+
clack.intro(chalk.cyan("skai - Skill Manager"));
|
|
2898
|
+
const result = await manageSkills();
|
|
2899
|
+
if (result === null) {
|
|
2900
|
+
clack.outro(chalk.yellow("Cancelled"));
|
|
2901
|
+
return;
|
|
2902
|
+
}
|
|
2903
|
+
if (result.enabled === 0 && result.disabled === 0 && result.failed === 0) {
|
|
2904
|
+
clack.outro(chalk.dim("No changes made"));
|
|
2905
|
+
return;
|
|
2906
|
+
}
|
|
2907
|
+
const parts = [];
|
|
2908
|
+
if (result.enabled > 0) parts.push(chalk.green(`${result.enabled} enabled`));
|
|
2909
|
+
if (result.disabled > 0) parts.push(chalk.yellow(`${result.disabled} disabled`));
|
|
2910
|
+
if (result.failed > 0) parts.push(chalk.red(`${result.failed} failed`));
|
|
2911
|
+
for (const err of result.errors) {
|
|
2912
|
+
clack.log.warn(`Failed to update ${err.skill} (${err.agent}): ${err.error}`);
|
|
2913
|
+
}
|
|
2914
|
+
if (result.enabled > 0 || result.disabled > 0) {
|
|
2915
|
+
clack.note("Restart your AI agent to apply changes.", "Next steps");
|
|
2916
|
+
}
|
|
2917
|
+
clack.outro(parts.join(", "));
|
|
2918
|
+
}
|
|
2605
2919
|
async function main() {
|
|
2606
2920
|
const program = new Command();
|
|
2607
2921
|
program.name("skai").description("The package manager for AI agent skills").version(getVersion(), "-V, --version", "Display version");
|
|
2608
2922
|
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) => {
|
|
2923
|
+
if (!source) {
|
|
2924
|
+
await runManage();
|
|
2925
|
+
return;
|
|
2926
|
+
}
|
|
2609
2927
|
await runInstall(source, options);
|
|
2610
2928
|
});
|
|
2611
2929
|
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 +2938,50 @@ async function main() {
|
|
|
2620
2938
|
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
2939
|
await runUpdate(skills, options);
|
|
2622
2940
|
});
|
|
2941
|
+
program.command("manage").description("Interactively enable/disable installed skills").action(async () => {
|
|
2942
|
+
await runManage();
|
|
2943
|
+
});
|
|
2623
2944
|
program.addHelpText(
|
|
2624
2945
|
"after",
|
|
2625
2946
|
`
|
|
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
|
|
2947
|
+
${chalk.yellow("EXAMPLES")}
|
|
2948
|
+
${chalk.dim("# Install skills from GitHub")}
|
|
2949
|
+
$ skai pproenca/dot-skills
|
|
2950
|
+
|
|
2951
|
+
${chalk.dim("# Install from full URL")}
|
|
2952
|
+
$ skai https://github.com/org/repo
|
|
2637
2953
|
|
|
2638
|
-
|
|
2954
|
+
${chalk.dim("# Install from local directory")}
|
|
2955
|
+
$ skai ./local/skills
|
|
2956
|
+
|
|
2957
|
+
${chalk.dim("# Install specific skill to specific agent")}
|
|
2958
|
+
$ skai pproenca/dot-skills -s typescript -a claude-code
|
|
2959
|
+
|
|
2960
|
+
${chalk.dim("# Preview installation without changes")}
|
|
2961
|
+
$ skai pproenca/dot-skills --dry-run
|
|
2962
|
+
|
|
2963
|
+
${chalk.dim("# List installed skills")}
|
|
2964
|
+
$ skai list
|
|
2965
|
+
|
|
2966
|
+
${chalk.dim("# List skills for specific agent")}
|
|
2967
|
+
$ skai list -a cursor
|
|
2968
|
+
|
|
2969
|
+
${chalk.dim("# Uninstall a skill")}
|
|
2970
|
+
$ skai uninstall typescript
|
|
2971
|
+
|
|
2972
|
+
${chalk.dim("# Uninstall from specific agent")}
|
|
2973
|
+
$ skai uninstall typescript -a cursor
|
|
2974
|
+
|
|
2975
|
+
${chalk.dim("# Manage skills (enable/disable)")}
|
|
2976
|
+
$ skai
|
|
2977
|
+
$ skai manage
|
|
2978
|
+
|
|
2979
|
+
${chalk.yellow("SUPPORTED AGENTS")}
|
|
2639
2980
|
claude-code, cursor, copilot, windsurf, codex, opencode, amp,
|
|
2640
2981
|
kilo-code, roo-code, goose, gemini, antigravity, clawdbot, droid
|
|
2982
|
+
|
|
2983
|
+
${chalk.yellow("LEARN MORE")}
|
|
2984
|
+
GitHub: ${chalk.cyan("https://github.com/pproenca/skai")}
|
|
2641
2985
|
`
|
|
2642
2986
|
);
|
|
2643
2987
|
await program.parseAsync(process.argv);
|