askill-cli 0.1.3 → 0.1.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/README.md +8 -2
- package/dist/cli.mjs +388 -40
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,9 @@ You are an AI agent helping a user with askill - a package manager for AI agent
|
|
|
12
12
|
|
|
13
13
|
**Quick Commands:**
|
|
14
14
|
```bash
|
|
15
|
+
# Install a published skill (@author/skill-name)
|
|
16
|
+
askill add @johndoe/awesome-tool -y
|
|
17
|
+
|
|
15
18
|
# Install a skill
|
|
16
19
|
askill add owner/repo@skill-name -y
|
|
17
20
|
|
|
@@ -55,9 +58,9 @@ After installation, read the skill's `SKILL.md` file for usage instructions. Ski
|
|
|
55
58
|
|
|
56
59
|
---
|
|
57
60
|
|
|
58
|
-
askill is a universal package manager for AI agent skills. It enables agents to discover, install, and use skills across Claude Code,
|
|
61
|
+
askill is a universal package manager for AI agent skills. It enables agents to discover, install, and use skills across Claude Code, Codex, OpenCode, OpenClaw, Cursor, and 40+ other AI coding assistants.
|
|
59
62
|
|
|
60
|
-
Every skill on [askill.sh](https://askill.sh) is automatically reviewed by AI across 5
|
|
63
|
+
Every skill on [askill.sh](https://askill.sh) is automatically reviewed by AI across 5 strict dimensions - Safety, Clarity, Reusability, Completeness, and Actionability - so risky or malicious skills are filtered out, and truly excellent skills rise to the top of the rankings.
|
|
61
64
|
|
|
62
65
|
## Quick Start
|
|
63
66
|
|
|
@@ -65,6 +68,9 @@ Every skill on [askill.sh](https://askill.sh) is automatically reviewed by AI ac
|
|
|
65
68
|
# Install
|
|
66
69
|
curl -fsSL https://askill.sh | sh
|
|
67
70
|
|
|
71
|
+
# Install a published skill
|
|
72
|
+
askill add @johndoe/awesome-tool
|
|
73
|
+
|
|
68
74
|
# Install a skill
|
|
69
75
|
askill add owner/repo@skill-name
|
|
70
76
|
|
package/dist/cli.mjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { homedir } from "os";
|
|
5
5
|
import { join } from "path";
|
|
6
6
|
import { existsSync } from "fs";
|
|
7
|
-
var VERSION = "0.1.
|
|
7
|
+
var VERSION = "0.1.5";
|
|
8
8
|
var API_BASE_URL = "https://askill.sh/api/v1";
|
|
9
9
|
var REGISTRY_URL = "https://askill.sh";
|
|
10
10
|
var RESET = "\x1B[0m";
|
|
@@ -419,11 +419,13 @@ var APIClient = class {
|
|
|
419
419
|
* Publish a skill from local content or GitHub URL
|
|
420
420
|
*/
|
|
421
421
|
async publish(payload) {
|
|
422
|
+
const headers = {};
|
|
423
|
+
if (payload.token) {
|
|
424
|
+
headers.Authorization = `Bearer ${payload.token}`;
|
|
425
|
+
}
|
|
422
426
|
return this.fetch("/publish", {
|
|
423
427
|
method: "POST",
|
|
424
|
-
headers
|
|
425
|
-
Authorization: `Bearer ${payload.token}`
|
|
426
|
-
},
|
|
428
|
+
headers,
|
|
427
429
|
body: JSON.stringify({
|
|
428
430
|
content: payload.content,
|
|
429
431
|
githubUrl: payload.githubUrl
|
|
@@ -788,28 +790,29 @@ async function fetchVersionInfo() {
|
|
|
788
790
|
return null;
|
|
789
791
|
}
|
|
790
792
|
}
|
|
791
|
-
async function
|
|
793
|
+
async function getAvailableUpdate(force = false) {
|
|
792
794
|
if (!force && !await shouldCheckUpdate()) {
|
|
793
|
-
return;
|
|
795
|
+
return null;
|
|
794
796
|
}
|
|
795
797
|
await saveUpdateCheckTime();
|
|
796
798
|
const versionInfo = await fetchVersionInfo();
|
|
797
|
-
if (!versionInfo) return;
|
|
799
|
+
if (!versionInfo) return null;
|
|
798
800
|
const current = VERSION;
|
|
799
|
-
const latest = versionInfo.latest;
|
|
800
|
-
if (semver.lt(current, latest)) {
|
|
801
|
-
console.log();
|
|
802
|
-
console.log(`${YELLOW}\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E${RESET}`);
|
|
803
|
-
console.log(`${YELLOW}\u2502${RESET} Update available: ${DIM}${current}${RESET} \u2192 ${GREEN}${latest}${RESET} ${YELLOW}\u2502${RESET}`);
|
|
804
|
-
console.log(`${YELLOW}\u2502${RESET} Run ${CYAN}askill upgrade${RESET} to update ${YELLOW}\u2502${RESET}`);
|
|
805
|
-
console.log(`${YELLOW}\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F${RESET}`);
|
|
806
|
-
console.log();
|
|
807
|
-
}
|
|
808
801
|
if (semver.lt(current, versionInfo.minimum)) {
|
|
809
802
|
console.log(`${RED}Your askill version is too old. Please update to continue.${RESET}`);
|
|
810
803
|
console.log(`Minimum required: ${versionInfo.minimum}`);
|
|
811
804
|
process.exit(1);
|
|
812
805
|
}
|
|
806
|
+
if (!semver.lt(current, versionInfo.latest)) {
|
|
807
|
+
return null;
|
|
808
|
+
}
|
|
809
|
+
return {
|
|
810
|
+
current,
|
|
811
|
+
latest: versionInfo.latest,
|
|
812
|
+
minimum: versionInfo.minimum,
|
|
813
|
+
releaseNotes: versionInfo.releaseNotes,
|
|
814
|
+
releaseUrl: versionInfo.releaseUrl
|
|
815
|
+
};
|
|
813
816
|
}
|
|
814
817
|
async function selfUpdate() {
|
|
815
818
|
console.log(`${CYAN}Checking for updates...${RESET}`);
|
|
@@ -1522,7 +1525,7 @@ function showBanner() {
|
|
|
1522
1525
|
console.log(` ${DIM}$${RESET} askill init${RESET} ${DIM}Create a new skill${RESET}`);
|
|
1523
1526
|
console.log(` ${DIM}$${RESET} askill submit ${DIM}<url>${RESET} ${DIM}Submit GitHub skill URL${RESET}`);
|
|
1524
1527
|
console.log(` ${DIM}$${RESET} askill login${RESET} ${DIM}Login with API token${RESET}`);
|
|
1525
|
-
console.log(` ${DIM}$${RESET} askill publish${RESET} ${DIM}Publish
|
|
1528
|
+
console.log(` ${DIM}$${RESET} askill publish${RESET} ${DIM}Publish to @author/slug${RESET}`);
|
|
1526
1529
|
console.log(` ${DIM}$${RESET} askill run ${DIM}<skill:cmd>${RESET} ${DIM}Run a skill command${RESET}`);
|
|
1527
1530
|
console.log();
|
|
1528
1531
|
console.log(`${DIM}Browse skills at${RESET} ${CYAN}https://askill.sh${RESET}`);
|
|
@@ -1546,12 +1549,13 @@ ${BOLD}Commands:${RESET}
|
|
|
1546
1549
|
login [--token <token>] Login with API token
|
|
1547
1550
|
logout Clear saved API token
|
|
1548
1551
|
whoami Show current authenticated user
|
|
1549
|
-
publish [path] Publish SKILL.md
|
|
1550
|
-
publish --github <url> Publish SKILL.md
|
|
1552
|
+
publish [path] Publish local SKILL.md (login required)
|
|
1553
|
+
publish --github <url> Publish GitHub SKILL.md (author=repo owner)
|
|
1551
1554
|
run <skill:cmd> Run a skill command
|
|
1552
1555
|
upgrade Update askill CLI to latest version
|
|
1553
1556
|
|
|
1554
1557
|
${BOLD}Skill Source Formats:${RESET}
|
|
1558
|
+
@author/skill-name Published skill from askill registry
|
|
1555
1559
|
owner/repo All skills from a GitHub repo
|
|
1556
1560
|
owner/repo@skill-name Specific skill by name
|
|
1557
1561
|
owner/repo/path/to/skill Specific skill by path
|
|
@@ -1560,6 +1564,7 @@ ${BOLD}Skill Source Formats:${RESET}
|
|
|
1560
1564
|
gh:owner/repo@skill-name Explicit GitHub prefix (optional)
|
|
1561
1565
|
|
|
1562
1566
|
${BOLD}Install Options:${RESET}
|
|
1567
|
+
(default) Install to current project: .agents/skills/
|
|
1563
1568
|
-g, --global Install globally (user-level)
|
|
1564
1569
|
-a, --agent <agents> Install to specific agents
|
|
1565
1570
|
-y, --yes Skip confirmation prompts
|
|
@@ -1570,21 +1575,298 @@ ${BOLD}Install Options:${RESET}
|
|
|
1570
1575
|
${BOLD}Run Options:${RESET}
|
|
1571
1576
|
askill run <skill>:<command> Run a skill's command
|
|
1572
1577
|
|
|
1578
|
+
${BOLD}Search Options:${RESET}
|
|
1579
|
+
--full-desc Show full skill descriptions in find/search
|
|
1580
|
+
|
|
1573
1581
|
${BOLD}Options:${RESET}
|
|
1574
1582
|
--help, -h Show this help message
|
|
1575
1583
|
--version, -v Show version number
|
|
1576
1584
|
|
|
1585
|
+
${BOLD}Per-command Help:${RESET}
|
|
1586
|
+
askill <command> --help
|
|
1587
|
+
askill help <command>
|
|
1588
|
+
|
|
1589
|
+
${BOLD}For Agents:${RESET}
|
|
1590
|
+
Official usage guide: ${CYAN}https://github.com/avibe-bot/askill/tree/main/skills/use-askill${RESET}
|
|
1591
|
+
|
|
1577
1592
|
${BOLD}Examples:${RESET}
|
|
1578
1593
|
${DIM}$${RESET} askill add anthropic/courses@prompt-eng
|
|
1579
1594
|
${DIM}$${RESET} askill add anthropic/courses
|
|
1580
1595
|
${DIM}$${RESET} askill add ./my-skills/custom-skill
|
|
1581
1596
|
${DIM}$${RESET} askill find memory
|
|
1597
|
+
${DIM}$${RESET} askill find memory --full-desc
|
|
1582
1598
|
${DIM}$${RESET} askill list -g
|
|
1583
1599
|
${DIM}$${RESET} askill info gh:anthropic/courses@prompt-eng
|
|
1584
1600
|
|
|
1585
1601
|
${DIM}Browse more at${RESET} ${CYAN}https://askill.sh${RESET}
|
|
1586
1602
|
`);
|
|
1587
1603
|
}
|
|
1604
|
+
function createSpinner(plain) {
|
|
1605
|
+
if (!plain) {
|
|
1606
|
+
return p.spinner();
|
|
1607
|
+
}
|
|
1608
|
+
return {
|
|
1609
|
+
start: () => {
|
|
1610
|
+
},
|
|
1611
|
+
stop: () => {
|
|
1612
|
+
},
|
|
1613
|
+
message: () => {
|
|
1614
|
+
}
|
|
1615
|
+
};
|
|
1616
|
+
}
|
|
1617
|
+
function normalizeCommand(command) {
|
|
1618
|
+
switch (command) {
|
|
1619
|
+
case "install":
|
|
1620
|
+
case "i":
|
|
1621
|
+
return "add";
|
|
1622
|
+
case "search":
|
|
1623
|
+
case "s":
|
|
1624
|
+
return "find";
|
|
1625
|
+
case "ls":
|
|
1626
|
+
return "list";
|
|
1627
|
+
case "rm":
|
|
1628
|
+
case "uninstall":
|
|
1629
|
+
return "remove";
|
|
1630
|
+
case "show":
|
|
1631
|
+
return "info";
|
|
1632
|
+
default:
|
|
1633
|
+
return command;
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
function showCommandHelp(commandInput) {
|
|
1637
|
+
const command = normalizeCommand(commandInput);
|
|
1638
|
+
const helps = {
|
|
1639
|
+
add: `${BOLD}askill add${RESET}
|
|
1640
|
+
|
|
1641
|
+
Usage:
|
|
1642
|
+
askill add <source> [options]
|
|
1643
|
+
|
|
1644
|
+
Description:
|
|
1645
|
+
Install skills from published slugs, GitHub, or local directories.
|
|
1646
|
+
|
|
1647
|
+
Sources:
|
|
1648
|
+
@author/skill-name
|
|
1649
|
+
gh:owner/repo@skill-name
|
|
1650
|
+
gh:owner/repo/path/to/skill
|
|
1651
|
+
owner/repo
|
|
1652
|
+
./local/path
|
|
1653
|
+
|
|
1654
|
+
Scope:
|
|
1655
|
+
default: current project (.agents/skills/)
|
|
1656
|
+
-g, --global: user-level install
|
|
1657
|
+
|
|
1658
|
+
Options:
|
|
1659
|
+
-g, --global Install globally
|
|
1660
|
+
-a, --agent <agents...> Install to specific agents
|
|
1661
|
+
-y, --yes Skip confirmation prompts
|
|
1662
|
+
--copy Copy files instead of symlink
|
|
1663
|
+
-l, --list Preview discovered skills only
|
|
1664
|
+
--all Install all discovered skills
|
|
1665
|
+
|
|
1666
|
+
Examples:
|
|
1667
|
+
askill add @johndoe/awesome-tool -y
|
|
1668
|
+
askill add gh:facebook/react@extract-errors
|
|
1669
|
+
askill add owner/repo --all -a claude-code opencode -y
|
|
1670
|
+
|
|
1671
|
+
Guide:
|
|
1672
|
+
https://github.com/avibe-bot/askill/tree/main/skills/use-askill`,
|
|
1673
|
+
remove: `${BOLD}askill remove${RESET}
|
|
1674
|
+
|
|
1675
|
+
Usage:
|
|
1676
|
+
askill remove <skill> [options]
|
|
1677
|
+
|
|
1678
|
+
Description:
|
|
1679
|
+
Remove an installed skill from detected agents.
|
|
1680
|
+
|
|
1681
|
+
Options:
|
|
1682
|
+
-g, --global Remove global installation
|
|
1683
|
+
|
|
1684
|
+
Examples:
|
|
1685
|
+
askill remove memory
|
|
1686
|
+
askill remove memory -g`,
|
|
1687
|
+
list: `${BOLD}askill list${RESET}
|
|
1688
|
+
|
|
1689
|
+
Usage:
|
|
1690
|
+
askill list [options]
|
|
1691
|
+
|
|
1692
|
+
Description:
|
|
1693
|
+
List installed skills and where they are available.
|
|
1694
|
+
|
|
1695
|
+
Options:
|
|
1696
|
+
-g, --global Show global skills only
|
|
1697
|
+
|
|
1698
|
+
Examples:
|
|
1699
|
+
askill list
|
|
1700
|
+
askill list -g`,
|
|
1701
|
+
find: `${BOLD}askill find${RESET}
|
|
1702
|
+
|
|
1703
|
+
Usage:
|
|
1704
|
+
askill find [query] [options]
|
|
1705
|
+
|
|
1706
|
+
Description:
|
|
1707
|
+
Search indexed and published skills on askill.sh.
|
|
1708
|
+
|
|
1709
|
+
Options:
|
|
1710
|
+
--full-desc Show full descriptions
|
|
1711
|
+
|
|
1712
|
+
Examples:
|
|
1713
|
+
askill find memory
|
|
1714
|
+
askill find code review --full-desc`,
|
|
1715
|
+
info: `${BOLD}askill info${RESET}
|
|
1716
|
+
|
|
1717
|
+
Usage:
|
|
1718
|
+
askill info <slug>
|
|
1719
|
+
|
|
1720
|
+
Description:
|
|
1721
|
+
Show detailed metadata and installation info for one skill.
|
|
1722
|
+
|
|
1723
|
+
Examples:
|
|
1724
|
+
askill info @johndoe/awesome-tool
|
|
1725
|
+
askill info gh:facebook/react@extract-errors`,
|
|
1726
|
+
check: `${BOLD}askill check${RESET}
|
|
1727
|
+
|
|
1728
|
+
Usage:
|
|
1729
|
+
askill check [skill]
|
|
1730
|
+
|
|
1731
|
+
Description:
|
|
1732
|
+
Check installed skills for available updates without installing.
|
|
1733
|
+
|
|
1734
|
+
Examples:
|
|
1735
|
+
askill check
|
|
1736
|
+
askill check memory`,
|
|
1737
|
+
update: `${BOLD}askill update${RESET}
|
|
1738
|
+
|
|
1739
|
+
Usage:
|
|
1740
|
+
askill update [skill]
|
|
1741
|
+
|
|
1742
|
+
Description:
|
|
1743
|
+
Update one installed skill or all installed skills.
|
|
1744
|
+
|
|
1745
|
+
Examples:
|
|
1746
|
+
askill update
|
|
1747
|
+
askill update memory`,
|
|
1748
|
+
run: `${BOLD}askill run${RESET}
|
|
1749
|
+
|
|
1750
|
+
Usage:
|
|
1751
|
+
askill run <skill>:<command> [args...]
|
|
1752
|
+
|
|
1753
|
+
Description:
|
|
1754
|
+
Run a command declared in a skill's SKILL.md frontmatter.
|
|
1755
|
+
|
|
1756
|
+
Examples:
|
|
1757
|
+
askill run @anthropic/memory:save --key name --value "Alice"
|
|
1758
|
+
askill run my-skill:_setup`,
|
|
1759
|
+
validate: `${BOLD}askill validate${RESET}
|
|
1760
|
+
|
|
1761
|
+
Usage:
|
|
1762
|
+
askill validate [path]
|
|
1763
|
+
|
|
1764
|
+
Description:
|
|
1765
|
+
Validate SKILL.md frontmatter and command structure.
|
|
1766
|
+
|
|
1767
|
+
Examples:
|
|
1768
|
+
askill validate
|
|
1769
|
+
askill validate ./my-skill/SKILL.md`,
|
|
1770
|
+
init: `${BOLD}askill init${RESET}
|
|
1771
|
+
|
|
1772
|
+
Usage:
|
|
1773
|
+
askill init [dir] [options]
|
|
1774
|
+
|
|
1775
|
+
Description:
|
|
1776
|
+
Generate a new SKILL.md template interactively or non-interactively.
|
|
1777
|
+
|
|
1778
|
+
Options:
|
|
1779
|
+
-y, --yes Use defaults without prompts
|
|
1780
|
+
|
|
1781
|
+
Examples:
|
|
1782
|
+
askill init
|
|
1783
|
+
askill init ./my-skill -y`,
|
|
1784
|
+
submit: `${BOLD}askill submit${RESET}
|
|
1785
|
+
|
|
1786
|
+
Usage:
|
|
1787
|
+
askill submit <github-url>
|
|
1788
|
+
|
|
1789
|
+
Description:
|
|
1790
|
+
Submit a GitHub repository or SKILL.md URL for indexing on askill.sh.
|
|
1791
|
+
|
|
1792
|
+
Examples:
|
|
1793
|
+
askill submit https://github.com/owner/repo
|
|
1794
|
+
askill submit https://github.com/owner/repo/blob/main/skills/foo/SKILL.md`,
|
|
1795
|
+
login: `${BOLD}askill login${RESET}
|
|
1796
|
+
|
|
1797
|
+
Usage:
|
|
1798
|
+
askill login [--token <ask_xxx>]
|
|
1799
|
+
|
|
1800
|
+
Description:
|
|
1801
|
+
Save and verify an askill API token for publishing.
|
|
1802
|
+
|
|
1803
|
+
Examples:
|
|
1804
|
+
askill login
|
|
1805
|
+
askill login --token ask_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`,
|
|
1806
|
+
logout: `${BOLD}askill logout${RESET}
|
|
1807
|
+
|
|
1808
|
+
Usage:
|
|
1809
|
+
askill logout
|
|
1810
|
+
|
|
1811
|
+
Description:
|
|
1812
|
+
Clear saved local credentials.`,
|
|
1813
|
+
whoami: `${BOLD}askill whoami${RESET}
|
|
1814
|
+
|
|
1815
|
+
Usage:
|
|
1816
|
+
askill whoami
|
|
1817
|
+
|
|
1818
|
+
Description:
|
|
1819
|
+
Show current authenticated account and masked token.`,
|
|
1820
|
+
publish: `${BOLD}askill publish${RESET}
|
|
1821
|
+
|
|
1822
|
+
Usage:
|
|
1823
|
+
askill publish [path]
|
|
1824
|
+
askill publish --github <blob-url-to-SKILL.md>
|
|
1825
|
+
|
|
1826
|
+
Description:
|
|
1827
|
+
Publish a skill to canonical slug @author/slug.
|
|
1828
|
+
|
|
1829
|
+
Rules:
|
|
1830
|
+
- SKILL.md must include valid frontmatter fields: name, slug, version
|
|
1831
|
+
- Local publish requires askill login token (author is your GitHub user)
|
|
1832
|
+
- --github publish uses repository owner as author and does not require login
|
|
1833
|
+
|
|
1834
|
+
Examples:
|
|
1835
|
+
askill publish
|
|
1836
|
+
askill publish ./skills/my-skill
|
|
1837
|
+
askill publish --github https://github.com/owner/repo/blob/main/skills/my-skill/SKILL.md`,
|
|
1838
|
+
upgrade: `${BOLD}askill upgrade${RESET}
|
|
1839
|
+
|
|
1840
|
+
Usage:
|
|
1841
|
+
askill upgrade
|
|
1842
|
+
|
|
1843
|
+
Description:
|
|
1844
|
+
Self-update askill CLI to the latest available version.`,
|
|
1845
|
+
help: `${BOLD}askill help${RESET}
|
|
1846
|
+
|
|
1847
|
+
Usage:
|
|
1848
|
+
askill help
|
|
1849
|
+
askill help <command>
|
|
1850
|
+
|
|
1851
|
+
Description:
|
|
1852
|
+
Show global help or detailed help for a specific command.`
|
|
1853
|
+
};
|
|
1854
|
+
const text2 = helps[command];
|
|
1855
|
+
if (!text2) return false;
|
|
1856
|
+
console.log();
|
|
1857
|
+
console.log(text2);
|
|
1858
|
+
console.log();
|
|
1859
|
+
return true;
|
|
1860
|
+
}
|
|
1861
|
+
async function maybeAutoUpgradeOnStartup(commandInput) {
|
|
1862
|
+
const command = normalizeCommand(commandInput);
|
|
1863
|
+
const skipCommands = /* @__PURE__ */ new Set(["upgrade", "help", "version", "--version", "-v", "--help", "-h"]);
|
|
1864
|
+
if (skipCommands.has(command)) return;
|
|
1865
|
+
const available = await getAvailableUpdate(false).catch(() => null);
|
|
1866
|
+
if (!available) return;
|
|
1867
|
+
console.log(`${DIM}Auto-updating askill: ${available.current} -> ${available.latest}${RESET}`);
|
|
1868
|
+
await selfUpdate();
|
|
1869
|
+
}
|
|
1588
1870
|
function parseInstallOptions(args) {
|
|
1589
1871
|
const options = {};
|
|
1590
1872
|
let skillName = "";
|
|
@@ -1716,11 +1998,13 @@ async function resolveSkillsViaApi(parsed, spinner2, options) {
|
|
|
1716
1998
|
}
|
|
1717
1999
|
async function runInstall(args) {
|
|
1718
2000
|
const { skillName, options } = parseInstallOptions(args);
|
|
2001
|
+
const plainMode = Boolean(options.yes) || !process.stdout.isTTY;
|
|
1719
2002
|
if (!skillName) {
|
|
1720
2003
|
console.log(`${RED}Error: Missing skill identifier${RESET}`);
|
|
1721
2004
|
console.log(`Usage: askill add <source>`);
|
|
1722
2005
|
console.log(`
|
|
1723
2006
|
Formats supported:`);
|
|
2007
|
+
console.log(` askill add @author/skill-name ${DIM}# published skill${RESET}`);
|
|
1724
2008
|
console.log(` askill add owner/repo ${DIM}# all skills from repo${RESET}`);
|
|
1725
2009
|
console.log(` askill add owner/repo@skill-name ${DIM}# specific skill${RESET}`);
|
|
1726
2010
|
console.log(` askill add owner/repo/path/to/skill ${DIM}# skill by path${RESET}`);
|
|
@@ -1728,9 +2012,11 @@ Formats supported:`);
|
|
|
1728
2012
|
console.log(` askill add ./local/path ${DIM}# local directory${RESET}`);
|
|
1729
2013
|
process.exit(1);
|
|
1730
2014
|
}
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
2015
|
+
if (!plainMode) {
|
|
2016
|
+
console.log();
|
|
2017
|
+
p.intro(pc.bgCyan(pc.black(" askill install ")));
|
|
2018
|
+
}
|
|
2019
|
+
const spinner2 = createSpinner(plainMode);
|
|
1734
2020
|
const { skills: discoveredSkills, parsed: sourceParsed, tempDir } = await resolveSkills(skillName, spinner2, options);
|
|
1735
2021
|
const cleanup = async () => {
|
|
1736
2022
|
if (tempDir) await cleanupTempDir(tempDir).catch(() => {
|
|
@@ -1739,7 +2025,11 @@ Formats supported:`);
|
|
|
1739
2025
|
try {
|
|
1740
2026
|
if (discoveredSkills.length === 0) {
|
|
1741
2027
|
p.log.warning("No skills found");
|
|
1742
|
-
|
|
2028
|
+
if (plainMode) {
|
|
2029
|
+
console.log(`Browse skills at ${pc.cyan("https://askill.sh")}`);
|
|
2030
|
+
} else {
|
|
2031
|
+
p.outro(`Browse skills at ${pc.cyan("https://askill.sh")}`);
|
|
2032
|
+
}
|
|
1743
2033
|
return;
|
|
1744
2034
|
}
|
|
1745
2035
|
if (options.list) {
|
|
@@ -1756,7 +2046,11 @@ Formats supported:`);
|
|
|
1756
2046
|
}
|
|
1757
2047
|
console.log();
|
|
1758
2048
|
}
|
|
1759
|
-
|
|
2049
|
+
if (plainMode) {
|
|
2050
|
+
console.log(`Install with: ${pc.cyan(`askill add ${skillName} --all`)}`);
|
|
2051
|
+
} else {
|
|
2052
|
+
p.outro(`Install with: ${pc.cyan(`askill add ${skillName} --all`)}`);
|
|
2053
|
+
}
|
|
1760
2054
|
return;
|
|
1761
2055
|
}
|
|
1762
2056
|
let skillsToInstall;
|
|
@@ -2011,12 +2305,16 @@ Formats supported:`);
|
|
|
2011
2305
|
}
|
|
2012
2306
|
}
|
|
2013
2307
|
console.log();
|
|
2014
|
-
|
|
2308
|
+
if (plainMode) {
|
|
2309
|
+
console.log(pc.green("Done!"));
|
|
2310
|
+
} else {
|
|
2311
|
+
p.outro(pc.green("Done!"));
|
|
2312
|
+
}
|
|
2015
2313
|
} finally {
|
|
2016
2314
|
await cleanup();
|
|
2017
2315
|
}
|
|
2018
2316
|
}
|
|
2019
|
-
var SEARCH_DESCRIPTION_MAX_LENGTH =
|
|
2317
|
+
var SEARCH_DESCRIPTION_MAX_LENGTH = 500;
|
|
2020
2318
|
function toNumber(value) {
|
|
2021
2319
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
2022
2320
|
return null;
|
|
@@ -2128,8 +2426,28 @@ function getAIScoreDimensions(skill) {
|
|
|
2128
2426
|
return a.label.localeCompare(b.label);
|
|
2129
2427
|
});
|
|
2130
2428
|
}
|
|
2429
|
+
function normalizeInfoTarget(input) {
|
|
2430
|
+
const trimmed = input.trim();
|
|
2431
|
+
if (!trimmed) {
|
|
2432
|
+
return trimmed;
|
|
2433
|
+
}
|
|
2434
|
+
const withoutGh = trimmed.replace(/^gh:/i, "");
|
|
2435
|
+
const askillSkillUrl = withoutGh.match(/^https?:\/\/askill\.sh\/skills\/(.+)$/i);
|
|
2436
|
+
if (askillSkillUrl && askillSkillUrl[1]) {
|
|
2437
|
+
return askillSkillUrl[1];
|
|
2438
|
+
}
|
|
2439
|
+
return withoutGh;
|
|
2440
|
+
}
|
|
2441
|
+
function parseSearchOptions(args) {
|
|
2442
|
+
const fullDesc = args.includes("--full-desc");
|
|
2443
|
+
const query = args.filter((arg) => arg !== "--full-desc").join(" ");
|
|
2444
|
+
return {
|
|
2445
|
+
fullDesc,
|
|
2446
|
+
query
|
|
2447
|
+
};
|
|
2448
|
+
}
|
|
2131
2449
|
async function runSearch(args) {
|
|
2132
|
-
const query = args
|
|
2450
|
+
const { fullDesc, query } = parseSearchOptions(args);
|
|
2133
2451
|
console.log();
|
|
2134
2452
|
p.intro(pc.bgCyan(pc.black(" askill search ")));
|
|
2135
2453
|
const spinner2 = p.spinner();
|
|
@@ -2152,7 +2470,11 @@ async function runSearch(args) {
|
|
|
2152
2470
|
console.log(` ${pc.cyan(displayName)} ${pc.dim(`by ${owner}`)}`);
|
|
2153
2471
|
console.log(` ${pc.dim("AI score:")} ${formatScore(aiScore)}`);
|
|
2154
2472
|
if (description) {
|
|
2155
|
-
|
|
2473
|
+
if (fullDesc) {
|
|
2474
|
+
console.log(` ${pc.dim(description)}`);
|
|
2475
|
+
} else {
|
|
2476
|
+
console.log(` ${pc.dim(description.slice(0, SEARCH_DESCRIPTION_MAX_LENGTH))}${description.length > SEARCH_DESCRIPTION_MAX_LENGTH ? "..." : ""}`);
|
|
2477
|
+
}
|
|
2156
2478
|
}
|
|
2157
2479
|
const installCmd = skill.owner && skill.repo ? `gh:${skill.owner}/${skill.repo}@${displayName}` : `gh:${displayName}`;
|
|
2158
2480
|
console.log(` ${pc.dim("askill add")} ${installCmd}`);
|
|
@@ -2236,12 +2558,13 @@ async function runRemove(args) {
|
|
|
2236
2558
|
p.outro(pc.green(`Removed ${skillName} from ${agentsWithSkill.length} agent(s)`));
|
|
2237
2559
|
}
|
|
2238
2560
|
async function runInfo(args) {
|
|
2239
|
-
const
|
|
2240
|
-
if (!
|
|
2561
|
+
const inputTarget = args[0];
|
|
2562
|
+
if (!inputTarget) {
|
|
2241
2563
|
console.log(`${RED}Error: Missing skill name${RESET}`);
|
|
2242
2564
|
console.log(`Usage: askill info <skill-name>`);
|
|
2243
2565
|
process.exit(1);
|
|
2244
2566
|
}
|
|
2567
|
+
const skillName = normalizeInfoTarget(inputTarget);
|
|
2245
2568
|
console.log();
|
|
2246
2569
|
p.intro(pc.bgCyan(pc.black(" askill info ")));
|
|
2247
2570
|
const spinner2 = p.spinner();
|
|
@@ -3036,11 +3359,6 @@ async function runWhoami() {
|
|
|
3036
3359
|
}
|
|
3037
3360
|
}
|
|
3038
3361
|
async function runPublish(args) {
|
|
3039
|
-
const creds = await loadCredentials();
|
|
3040
|
-
if (!creds?.token) {
|
|
3041
|
-
p.log.error("Not logged in. Run askill login first.");
|
|
3042
|
-
process.exit(1);
|
|
3043
|
-
}
|
|
3044
3362
|
const githubFlagIndex = args.findIndex((a) => a === "--github");
|
|
3045
3363
|
const githubUrl = githubFlagIndex >= 0 ? args[githubFlagIndex + 1] : void 0;
|
|
3046
3364
|
const localPath = args.find((a) => !a.startsWith("-")) || ".";
|
|
@@ -3073,13 +3391,32 @@ async function runPublish(args) {
|
|
|
3073
3391
|
}
|
|
3074
3392
|
const parsed = parseSkillMd(content);
|
|
3075
3393
|
const name = typeof parsed.frontmatter.name === "string" ? parsed.frontmatter.name.trim() : "";
|
|
3394
|
+
const slug = typeof parsed.frontmatter.slug === "string" ? parsed.frontmatter.slug.trim() : "";
|
|
3076
3395
|
const version = typeof parsed.frontmatter.version === "string" ? parsed.frontmatter.version.trim() : "";
|
|
3077
3396
|
if (!name) {
|
|
3078
3397
|
p.log.error("SKILL.md must include frontmatter name");
|
|
3079
3398
|
process.exit(1);
|
|
3080
3399
|
}
|
|
3081
|
-
if (!
|
|
3082
|
-
p.log.error("SKILL.md must include
|
|
3400
|
+
if (!slug) {
|
|
3401
|
+
p.log.error("SKILL.md must include frontmatter slug");
|
|
3402
|
+
p.log.info("Add slug using lowercase letters, numbers, and hyphens (example: slug: my-skill)");
|
|
3403
|
+
process.exit(1);
|
|
3404
|
+
}
|
|
3405
|
+
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug)) {
|
|
3406
|
+
p.log.error(`Invalid slug in SKILL.md: "${slug}"`);
|
|
3407
|
+
p.log.info("Expected format: lowercase letters, numbers, hyphens (example: my-skill)");
|
|
3408
|
+
process.exit(1);
|
|
3409
|
+
}
|
|
3410
|
+
if (!version) {
|
|
3411
|
+
p.log.error('SKILL.md is missing frontmatter field "version".');
|
|
3412
|
+
p.log.info("Add a semver version, for example: version: 0.1.0");
|
|
3413
|
+
p.log.info("Valid examples: 1.0.0, 1.2.3-beta.1, 2.0.0+build.5");
|
|
3414
|
+
process.exit(1);
|
|
3415
|
+
}
|
|
3416
|
+
if (!/^\d+\.\d+\.\d+(?:-[\w.]+)?(?:\+[\w.]+)?$/.test(version)) {
|
|
3417
|
+
p.log.error(`Invalid semver version in SKILL.md: "${version}"`);
|
|
3418
|
+
p.log.info("Expected format: MAJOR.MINOR.PATCH with optional prerelease/build");
|
|
3419
|
+
p.log.info("Examples: 1.0.0, 1.1.0-beta.1, 2.0.0+build.7");
|
|
3083
3420
|
process.exit(1);
|
|
3084
3421
|
}
|
|
3085
3422
|
console.log();
|
|
@@ -3087,8 +3424,14 @@ async function runPublish(args) {
|
|
|
3087
3424
|
const spinner2 = p.spinner();
|
|
3088
3425
|
spinner2.start("Publishing skill...");
|
|
3089
3426
|
try {
|
|
3427
|
+
const creds = githubUrl ? null : await loadCredentials();
|
|
3428
|
+
if (!githubUrl && !creds?.token) {
|
|
3429
|
+
spinner2.stop(pc.red("Publish failed"));
|
|
3430
|
+
p.log.error("Not logged in. Run askill login first for local publish.");
|
|
3431
|
+
process.exit(1);
|
|
3432
|
+
}
|
|
3090
3433
|
const result = await api.publish({
|
|
3091
|
-
token: creds
|
|
3434
|
+
token: creds?.token,
|
|
3092
3435
|
githubUrl,
|
|
3093
3436
|
content: githubUrl ? void 0 : content
|
|
3094
3437
|
});
|
|
@@ -3113,14 +3456,16 @@ function toRawGitHubUrl(url) {
|
|
|
3113
3456
|
}
|
|
3114
3457
|
async function main() {
|
|
3115
3458
|
const args = process.argv.slice(2);
|
|
3116
|
-
checkForUpdates().catch(() => {
|
|
3117
|
-
});
|
|
3118
3459
|
if (args.length === 0) {
|
|
3119
3460
|
showBanner();
|
|
3120
3461
|
return;
|
|
3121
3462
|
}
|
|
3122
3463
|
const command = args[0];
|
|
3123
3464
|
const restArgs = args.slice(1);
|
|
3465
|
+
if ((restArgs.includes("--help") || restArgs.includes("-h")) && showCommandHelp(command)) {
|
|
3466
|
+
return;
|
|
3467
|
+
}
|
|
3468
|
+
await maybeAutoUpgradeOnStartup(command);
|
|
3124
3469
|
switch (command) {
|
|
3125
3470
|
case "install":
|
|
3126
3471
|
case "i":
|
|
@@ -3181,6 +3526,9 @@ async function main() {
|
|
|
3181
3526
|
case "--help":
|
|
3182
3527
|
case "-h":
|
|
3183
3528
|
case "help":
|
|
3529
|
+
if (restArgs[0] && showCommandHelp(restArgs[0])) {
|
|
3530
|
+
break;
|
|
3531
|
+
}
|
|
3184
3532
|
showHelp();
|
|
3185
3533
|
break;
|
|
3186
3534
|
case "--version":
|