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.
Files changed (3) hide show
  1. package/README.md +8 -2
  2. package/dist/cli.mjs +388 -40
  3. 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, Cursor, Windsurf, and 40+ other AI coding assistants.
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 quality dimensions safety, clarity, reusability, completeness, and actionability so you can evaluate quality before you install.
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.3";
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 checkForUpdates(force = false) {
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 a skill${RESET}`);
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 from local path
1550
- publish --github <url> Publish SKILL.md from GitHub URL
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
- console.log();
1732
- p.intro(pc.bgCyan(pc.black(" askill install ")));
1733
- const spinner2 = p.spinner();
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
- p.outro(`Browse skills at ${pc.cyan("https://askill.sh")}`);
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
- p.outro(`Install with: ${pc.cyan(`askill add ${skillName} --all`)}`);
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
- p.outro(pc.green("Done!"));
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 = 180;
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.join(" ");
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
- console.log(` ${pc.dim(description.slice(0, SEARCH_DESCRIPTION_MAX_LENGTH))}${description.length > SEARCH_DESCRIPTION_MAX_LENGTH ? "..." : ""}`);
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 skillName = args[0];
2240
- if (!skillName) {
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 (!version || !/^\d+\.\d+\.\d+(?:-[\w.]+)?(?:\+[\w.]+)?$/.test(version)) {
3082
- p.log.error("SKILL.md must include a valid semver version");
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.token,
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":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "askill-cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "askill - The Agent Skill Package Manager",
5
5
  "type": "module",
6
6
  "bin": {