@mhmdreza-rafiei/agentry 0.3.0 → 0.3.2

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.
@@ -85,34 +85,35 @@ function printHelp() {
85
85
  `${badge()} ${dim("install agents, skills, rules, scripts & profiles")}`,
86
86
  "",
87
87
  h("Usage"),
88
- ` ${cmd("agentry")} ${flag("add")} ${dim("<kind> <source> [selector] [options]")}`,
89
- ` ${cmd("agentry")} ${flag("add")} ${dim("profile <name> [source] [options]")}`,
90
- ` ${cmd("agentry")} ${flag("remove")} ${dim("<kind> [source] [selector] [options]")}`,
91
- ` ${cmd("agentry")} ${flag("list")} ${dim("[source] [kind] [selector]")}`,
92
- ` ${cmd("agentry")} ${flag("update")} ${dim("[kind] [source] [selector]")}`,
93
- ` ${cmd("agentry")} ${flag("init")} ${dim("<kind> [name] [category] [options]")}`,
88
+ ` ${cmd("agentry")} ${flag("add")} ${dim("[kind] <source> [selector] [options]")}`,
89
+ ` ${cmd("agentry")} ${flag("add from")} ${dim("<url> [selector] [options]")}`,
90
+ ` ${cmd("agentry")} ${flag("add")} ${dim("profile <name> [source] [options]")}`,
91
+ ` ${cmd("agentry")} ${flag("remove")} ${dim("[kind] [source] [selector] [options]")}`,
92
+ ` ${cmd("agentry")} ${flag("list")} ${dim("[source] [kind] [selector]")}`,
93
+ ` ${cmd("agentry")} ${flag("update")} ${dim("[kind] [source] [selector]")}`,
94
+ ` ${cmd("agentry")} ${flag("init")} ${dim("<kind> [name] [category] [options]")}`,
94
95
  ` ${cmd("agentry")} ${flag("uninstall")}`,
95
96
  "",
96
97
  h("Kinds"),
97
98
  bullet(`${c.bold("skill")} ${c.bold("rule")} ${c.bold("agent")} ${c.bold("profile")} ${c.bold("script")} ${dim("(or all)")}`),
98
- dim(" Plurals accepted: skills → skill, agents → agent, …"),
99
+ dim(" Plurals accepted: skills → skill, agents → agent, … (optional on add/remove)"),
99
100
  "",
100
101
  h("Sources"),
101
102
  bullet(`${cmd("author/repo")} ${dim("GitHub shorthand")}`),
102
103
  bullet(`${cmd("https://github.com/…")} ${dim("GitHub URL or /tree/<ref>/<dir>")}`),
104
+ bullet(`${cmd("https://awesomeskill.ai/…")} ${dim("Skill directory/hub website")}`),
103
105
  bullet(`${cmd("https://gitlab.com/…")} ${dim("GitLab URL")}`),
104
106
  bullet(`${cmd("git@host:owner/repo.git")} ${dim("any git URL")}`),
105
107
  bullet(`${cmd("./path")} ${dim("|")} ${cmd("/path")} ${dim("|")} ${cmd("~/path")} ${dim("local directory")}`),
106
108
  "",
107
109
  h("Examples"),
108
- bullet(`${cmd("agentry add skills")} mhmdreza-rafiei/agent-tools`),
110
+ bullet(`${cmd("agentry add")} mhmdreza-rafiei/agent-tools`),
111
+ bullet(`${cmd("agentry add from")} https://awesomeskill.ai/skill/vercel-labs-agent-skills-web-design-guidelines`),
109
112
  bullet(`${cmd("agentry add skills")} mhmdreza-rafiei/agent-tools enhance-prompt ${flag("-a")} cursor`),
110
113
  bullet(`${cmd("agentry list")}`),
111
114
  bullet(`${cmd("agentry list skills")}`),
112
115
  bullet(`${cmd("agentry list")} mhmdreza-rafiei/agent-tools`),
113
- bullet(`${cmd("agentry list")} mhmdreza-rafiei/agent-tools skills`),
114
- bullet(`${cmd("agentry list")} mhmdreza-rafiei/agent-tools skills enhance-prompt`),
115
- bullet(`${cmd("agentry remove skills")} enhance-prompt`),
116
+ bullet(`${cmd("agentry remove")} enhance-prompt`),
116
117
  bullet(`${cmd("agentry remove skills")} mhmdreza-rafiei/agent-tools`),
117
118
  bullet(`${cmd("agentry update skills")} mhmdreza-rafiei/agent-tools`),
118
119
  bullet(`${cmd("agentry init skill")} enhance-prompt prompt ${flag("--reference")}`),
@@ -130,20 +131,15 @@ function printHelp() {
130
131
  ` ${flag("--all")} ${dim("Install everything to all agents, no prompts")}`,
131
132
  ` ${flag("-y, --yes")} ${dim("Don't prompt (scope defaults to project)")}`,
132
133
  ` ${flag("--description")} ${dim("<t>")} ${dim("init: frontmatter description")}`,
133
- ` ${flag("--alwaysApply")} ${dim("init rule: alwaysApply: true")}`,
134
- ` ${flag("--reference")} ${dim("init skill: add references/TEMPLATE.md")}`,
135
- ` ${flag("--no-reference")} ${dim("init skill: skip references/")}`,
134
+ ` ${flag("--alwaysApply")} ${dim("init rule: alwaysApply: true")}`,
135
+ ` ${flag("--reference")} ${dim("init skill: include references/TEMPLATE.md")}`,
136
+ ` ${flag("--no-reference")} ${dim("init skill: omit references/ folder")}`,
136
137
  ` ${flag("--skills")} ${dim("[src]")} ${dim("init profile: include skills (optional source)")}`,
137
138
  ` ${flag("--agents")} ${dim("[src]")} ${dim("init profile: include agents")}`,
138
139
  ` ${flag("--rules")} ${dim("[src]")} ${dim("init profile: include rules")}`,
139
140
  ` ${flag("--scripts")} ${dim("[src]")} ${dim("init profile: include scripts")}`,
140
- ` ${flag("-v, --version")} ${dim("Print version")}`,
141
- ` ${flag("-h, --help")} ${dim("Show this help")}`,
142
- "",
143
- dim("Tip: omit --agent to pick providers interactively (universal locked + searchable list)."),
144
- dim("Tip: remove/update accept a GitHub repo or local path to filter by install source."),
145
141
  ""
146
142
  ];
147
- process.stdout.write(lines.join("\n"));
143
+ process.stdout.write(lines.join("\n") + "\n");
148
144
  }
149
145
  export { PALETTE, animateLogo, badge, delay, logo, printHelp, sky, tagline, theme };
@@ -0,0 +1,111 @@
1
+ import { frontmatterName, resolveSource } from "./discovery.mjs";
2
+ import https from "node:https";
3
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import http from "node:http";
7
+ function fetchUrl(url, maxRedirects = 5) {
8
+ return new Promise((resolve, reject) => {
9
+ const req = (url.startsWith("https://") ? https : http).get(url, { headers: {
10
+ "User-Agent": "agentry/0.3.2 (+https://github.com/mhmdreza-rafiei/agentry)",
11
+ Accept: "text/html,application/xhtml+xml,text/plain,text/markdown,application/json,*/*"
12
+ } }, (res) => {
13
+ if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
14
+ if (maxRedirects <= 0) return reject(/* @__PURE__ */ new Error(`Too many redirects while fetching ${url}`));
15
+ return resolve(fetchUrl(new URL(res.headers.location, url).toString(), maxRedirects - 1));
16
+ }
17
+ if (res.statusCode && (res.statusCode < 200 || res.statusCode >= 300)) return reject(/* @__PURE__ */ new Error(`HTTP ${res.statusCode} when fetching ${url}`));
18
+ let body = "";
19
+ res.on("data", (chunk) => {
20
+ body += chunk;
21
+ });
22
+ res.on("end", () => {
23
+ resolve({
24
+ body,
25
+ status: res.statusCode || 200,
26
+ contentType: res.headers["content-type"] || "",
27
+ finalUrl: url
28
+ });
29
+ });
30
+ });
31
+ req.on("error", reject);
32
+ req.setTimeout(2e4, () => {
33
+ req.destroy();
34
+ reject(/* @__PURE__ */ new Error(`Request timed out while fetching ${url}`));
35
+ });
36
+ });
37
+ }
38
+ function cleanHtml(raw) {
39
+ return raw.replace(/\\/g, "");
40
+ }
41
+ async function resolveWebSource(url, opts = {}, fetcher = fetchUrl, sourceResolver = resolveSource) {
42
+ const gistMatch = url.match(/^https?:\/\/gist\.github\.com\/([a-zA-Z0-9_.-]+)\/([a-f0-9]+)/i);
43
+ if (gistMatch) return sourceResolver({
44
+ kind: "git-url",
45
+ raw: url,
46
+ url: `https://gist.github.com/${gistMatch[2]}.git`,
47
+ subpath: "",
48
+ local: null
49
+ }, opts);
50
+ const { body, contentType } = await fetcher(url);
51
+ const clean = cleanHtml(body);
52
+ const treeMatch = clean.match(/https:\/\/github\.com\/([\w.-]+\/[\w.-]+)\/tree\/([^/\s"'>]+)\/([^\s"'>]+)/i);
53
+ if (treeMatch) {
54
+ const ownerRepo = treeMatch[1];
55
+ const ref = treeMatch[2];
56
+ const subpath = treeMatch[3].replace(/\/+$/, "");
57
+ return sourceResolver({
58
+ kind: "github-url",
59
+ raw: url,
60
+ url: `https://github.com/${ownerRepo}.git`,
61
+ ref,
62
+ subpath,
63
+ local: null
64
+ }, opts);
65
+ }
66
+ const repoMatches = clean.match(/https:\/\/github\.com\/([\w.-]+\/[\w.-]+)(?:\.git)?\b/gi);
67
+ if (repoMatches) {
68
+ const ignoredPaths = /* @__PURE__ */ new Set([
69
+ "features",
70
+ "pricing",
71
+ "about",
72
+ "topics",
73
+ "trending",
74
+ "collections",
75
+ "site",
76
+ "security"
77
+ ]);
78
+ for (const match of repoMatches) {
79
+ const m = match.match(/https:\/\/github\.com\/([\w.-]+\/[\w.-]+)/i);
80
+ if (m) {
81
+ const ownerRepo = m[1];
82
+ const [owner, repo] = ownerRepo.split("/");
83
+ if (owner && repo && !ignoredPaths.has(owner.toLowerCase()) && !ignoredPaths.has(repo.toLowerCase())) return sourceResolver(`https://github.com/${ownerRepo}`, opts);
84
+ }
85
+ }
86
+ }
87
+ const isHtml = contentType.includes("html");
88
+ let content = body;
89
+ if (isHtml) {
90
+ const codeBlockMatch = body.match(/<pre[^>]*><code[^>]*>([\s\S]*?)<\/code><\/pre>/i);
91
+ if (codeBlockMatch && codeBlockMatch[1]) content = codeBlockMatch[1].replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
92
+ }
93
+ if (/^---\r?\n[\s\S]*?name:[\s\S]*?\r?\n---/m.test(content) || content.includes("# ") || !isHtml) {
94
+ const tmp = mkdtempSync(join(tmpdir(), "agentry-web-"));
95
+ const isMdc = url.endsWith(".mdc");
96
+ const isYaml = url.endsWith(".yaml") || url.endsWith(".yml");
97
+ let filename = "SKILL.md";
98
+ if (isMdc) filename = `${frontmatterName(content) || "agent"}.mdc`;
99
+ else if (isYaml) filename = "profile.yaml";
100
+ writeFileSync(join(tmp, filename), content);
101
+ return {
102
+ root: tmp,
103
+ cleanup: () => rmSync(tmp, {
104
+ recursive: true,
105
+ force: true
106
+ })
107
+ };
108
+ }
109
+ throw new Error(`Could not find a skill or git repository at ${url}`);
110
+ }
111
+ export { resolveWebSource };