@mhmdreza-rafiei/agentry 0.1.0 → 0.2.0

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/cli.mjs ADDED
@@ -0,0 +1,1687 @@
1
+ #!/usr/bin/env node
2
+ import { parseSource } from "./_chunks/source_parser2.mjs";
3
+ import { animateLogo, badge, delay, printHelp, theme } from "./_chunks/theme2.mjs";
4
+ import { execFileSync, execSync } from "node:child_process";
5
+ import https from "node:https";
6
+ import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
7
+ import { homedir, tmpdir } from "node:os";
8
+ import { join } from "node:path";
9
+ import { xdgConfig } from "xdg-basedir";
10
+ import { parse } from "yaml";
11
+ import { z } from "zod";
12
+ import * as clack from "@clack/prompts";
13
+ import c from "picocolors";
14
+ import { determineAgent } from "@vercel/detect-agent";
15
+ import * as readline from "node:readline";
16
+ import { stripVTControlCharacters } from "node:util";
17
+ import { Writable } from "node:stream";
18
+ var name = "@mhmdreza-rafiei/agentry";
19
+ var version = "0.2.0";
20
+ const ARTIFACT_KINDS = [
21
+ "skill",
22
+ "rule",
23
+ "agent",
24
+ "profile",
25
+ "script"
26
+ ];
27
+ function resolveSource(source) {
28
+ const parsed = typeof source === "string" ? parseSource(source) : source;
29
+ if (parsed.kind === "local" && parsed.local) {
30
+ if (!existsSync(parsed.local)) throw new Error(`Path not found: ${parsed.raw}`);
31
+ return {
32
+ root: parsed.local,
33
+ cleanup: () => {}
34
+ };
35
+ }
36
+ const url = parsed.url;
37
+ if (!url) throw new Error(`Cannot resolve source "${parsed.raw}".`);
38
+ const tmp = mkdtempSync(join(tmpdir(), "agentry-src-"));
39
+ try {
40
+ execFileSync("git", [
41
+ "clone",
42
+ "--quiet",
43
+ ...parsed.ref ? [
44
+ "--branch",
45
+ parsed.ref,
46
+ "--depth",
47
+ "1"
48
+ ] : ["--depth", "1"],
49
+ url,
50
+ tmp
51
+ ], { stdio: [
52
+ "ignore",
53
+ "ignore",
54
+ "pipe"
55
+ ] });
56
+ } catch (e) {
57
+ rmSync(tmp, {
58
+ recursive: true,
59
+ force: true
60
+ });
61
+ const detail = e.stderr ? e.stderr.toString().trim() : e.message;
62
+ throw new Error(`git clone failed for ${url}\n${detail}`);
63
+ }
64
+ if (parsed.subpath) {
65
+ const sub = join(tmp, parsed.subpath);
66
+ if (!existsSync(sub)) {
67
+ rmSync(tmp, {
68
+ recursive: true,
69
+ force: true
70
+ });
71
+ throw new Error(`Subpath "${parsed.subpath}" not found in ${url}.`);
72
+ }
73
+ return {
74
+ root: sub,
75
+ cleanup: () => rmSync(tmp, {
76
+ recursive: true,
77
+ force: true
78
+ })
79
+ };
80
+ }
81
+ return {
82
+ root: tmp,
83
+ cleanup: () => rmSync(tmp, {
84
+ recursive: true,
85
+ force: true
86
+ })
87
+ };
88
+ }
89
+ const SKILL_MARKER = "SKILL.md";
90
+ const FILE_EXT = ".mdc";
91
+ const PROFILE_EXTS = [".yaml", ".yml"];
92
+ const KIND_DIRS = {
93
+ skill: "skills",
94
+ rule: "rules",
95
+ agent: "agents",
96
+ profile: "profiles",
97
+ script: "scripts"
98
+ };
99
+ const ROOT_SKIP = /* @__PURE__ */ new Set([
100
+ ".",
101
+ "node_modules",
102
+ "skills",
103
+ "rules",
104
+ "agents",
105
+ "profiles",
106
+ "scripts"
107
+ ]);
108
+ function entries(dir) {
109
+ try {
110
+ return readdirSync(dir, { withFileTypes: true });
111
+ } catch {
112
+ return [];
113
+ }
114
+ }
115
+ function firstHeading(md) {
116
+ const m = md.match(/^#\s+(.+)$/m);
117
+ return m ? m[1].trim() : "";
118
+ }
119
+ function frontmatterDescription(md) {
120
+ const fm = md.match(/^---\r?\n([\s\S]*?)\r?\n---/);
121
+ if (!fm) return "";
122
+ const lines = fm[1].split(/\r?\n/);
123
+ for (let i = 0; i < lines.length; i++) {
124
+ const dm = lines[i].match(/^description:\s*(.*)$/);
125
+ if (!dm) continue;
126
+ let val = dm[1].trim();
127
+ if (val === "" || val === ">" || val === "|" || val === ">-" || val === "|-") {
128
+ const collected = [];
129
+ for (let j = i + 1; j < lines.length; j++) if (/^\s+\S/.test(lines[j])) collected.push(lines[j].trim());
130
+ else break;
131
+ val = collected.join(" ");
132
+ }
133
+ return val.trim();
134
+ }
135
+ return "";
136
+ }
137
+ function readDescription(filePath) {
138
+ try {
139
+ const md = readFileSync(filePath, "utf8");
140
+ return frontmatterDescription(md) || firstHeading(md);
141
+ } catch {
142
+ return "";
143
+ }
144
+ }
145
+ function folderDescription(dir) {
146
+ for (const f of [SKILL_MARKER, "README.md"]) {
147
+ const p = join(dir, f);
148
+ if (existsSync(p)) {
149
+ const d = readDescription(p);
150
+ if (d) return d;
151
+ }
152
+ }
153
+ return "";
154
+ }
155
+ function makeArtifact(kind, category, name, srcPath, isFile) {
156
+ return {
157
+ kind,
158
+ category,
159
+ name,
160
+ id: category ? `${category}/${name}` : name,
161
+ dir: srcPath,
162
+ isFile,
163
+ description: isFile ? readDescription(srcPath) : folderDescription(srcPath)
164
+ };
165
+ }
166
+ function collectSkills(base, out) {
167
+ for (const child of entries(base)) {
168
+ if (!child.isDirectory()) continue;
169
+ const childDir = join(base, child.name);
170
+ if (existsSync(join(childDir, SKILL_MARKER))) out.push(makeArtifact("skill", null, child.name, childDir, false));
171
+ else for (const item of entries(childDir)) {
172
+ if (!item.isDirectory()) continue;
173
+ const itemDir = join(childDir, item.name);
174
+ if (existsSync(join(itemDir, SKILL_MARKER))) out.push(makeArtifact("skill", child.name, item.name, itemDir, false));
175
+ }
176
+ }
177
+ }
178
+ function collectMdc(kind, base, out) {
179
+ for (const child of entries(base)) if (child.isFile() && child.name.endsWith(FILE_EXT)) out.push(makeArtifact(kind, null, child.name.slice(0, -4), join(base, child.name), true));
180
+ else if (child.isDirectory()) {
181
+ const subDir = join(base, child.name);
182
+ for (const item of entries(subDir)) if (item.isFile() && item.name.endsWith(FILE_EXT)) out.push(makeArtifact(kind, child.name, item.name.slice(0, -4), join(subDir, item.name), true));
183
+ }
184
+ }
185
+ function collectProfiles(base, out) {
186
+ for (const child of entries(base)) if (child.isFile() && PROFILE_EXTS.some((e) => child.name.endsWith(e))) {
187
+ const stem = child.name.replace(/\.(yaml|yml)$/, "");
188
+ out.push(makeArtifact("profile", null, stem, join(base, child.name), true));
189
+ } else if (child.isDirectory()) {
190
+ const subDir = join(base, child.name);
191
+ for (const item of entries(subDir)) if (item.isFile() && PROFILE_EXTS.some((e) => item.name.endsWith(e))) {
192
+ const stem = item.name.replace(/\.(yaml|yml)$/, "");
193
+ out.push(makeArtifact("profile", child.name, stem, join(subDir, item.name), true));
194
+ }
195
+ }
196
+ }
197
+ function collectScripts(base, out) {
198
+ for (const child of entries(base)) {
199
+ if (!child.isDirectory()) continue;
200
+ const childDir = join(base, child.name);
201
+ if (entries(childDir).some((e) => e.isFile())) out.push(makeArtifact("script", null, child.name, childDir, false));
202
+ else for (const item of entries(childDir)) if (item.isDirectory() && entries(join(childDir, item.name)).some((e) => e.isFile())) out.push(makeArtifact("script", child.name, item.name, join(childDir, item.name), false));
203
+ }
204
+ }
205
+ function collectRootSkills(root, out) {
206
+ for (const child of entries(root)) {
207
+ if (!child.isDirectory() || child.name.startsWith(".") || ROOT_SKIP.has(child.name)) continue;
208
+ const childDir = join(root, child.name);
209
+ if (existsSync(join(childDir, SKILL_MARKER))) out.push(makeArtifact("skill", null, child.name, childDir, false));
210
+ else for (const item of entries(childDir)) if (item.isDirectory() && existsSync(join(childDir, item.name, SKILL_MARKER))) out.push(makeArtifact("skill", child.name, item.name, join(childDir, item.name), false));
211
+ }
212
+ }
213
+ function collectRootMdc(kind, root, out) {
214
+ for (const child of entries(root)) if (child.isFile() && child.name.endsWith(FILE_EXT) && !child.name.startsWith(".")) out.push(makeArtifact(kind, null, child.name.slice(0, -4), join(root, child.name), true));
215
+ else if (child.isDirectory() && !child.name.startsWith(".") && !ROOT_SKIP.has(child.name)) {
216
+ const subDir = join(root, child.name);
217
+ for (const item of entries(subDir)) if (item.isFile() && item.name.endsWith(FILE_EXT)) out.push(makeArtifact(kind, child.name, item.name.slice(0, -4), join(subDir, item.name), true));
218
+ }
219
+ }
220
+ function listKind(root, kind) {
221
+ const out = [];
222
+ const base = join(root, KIND_DIRS[kind]);
223
+ if (existsSync(base)) if (kind === "skill") collectSkills(base, out);
224
+ else if (kind === "profile") collectProfiles(base, out);
225
+ else if (kind === "script") collectScripts(base, out);
226
+ else collectMdc(kind, base, out);
227
+ if (kind === "skill") collectRootSkills(root, out);
228
+ else if (kind === "agent" || kind === "rule") collectRootMdc(kind, root, out);
229
+ const seen = /* @__PURE__ */ new Set();
230
+ return out.filter((a) => seen.has(a.id) ? false : seen.add(a.id)).sort((a, b) => a.id.localeCompare(b.id));
231
+ }
232
+ function listAll(root) {
233
+ return [
234
+ "skill",
235
+ "rule",
236
+ "agent",
237
+ "profile"
238
+ ].flatMap((k) => listKind(root, k));
239
+ }
240
+ function select(root, kind, selector) {
241
+ const items = listKind(root, kind);
242
+ if (!selector) return items;
243
+ if (selector.includes("/")) return items.filter((a) => a.id === selector);
244
+ const byCategory = items.filter((a) => a.category === selector);
245
+ if (byCategory.length) return byCategory;
246
+ return items.filter((a) => a.name === selector);
247
+ }
248
+ const home$1 = homedir();
249
+ const configHome = xdgConfig ?? join(home$1, ".config");
250
+ const codexHome = process.env.CODEX_HOME?.trim() || join(home$1, ".codex");
251
+ const claudeHome = process.env.CLAUDE_CONFIG_DIR?.trim() || join(home$1, ".claude");
252
+ const vibeHome = process.env.VIBE_HOME?.trim() || join(home$1, ".vibe");
253
+ const hermesHome = process.env.HERMES_HOME?.trim() || join(home$1, ".hermes");
254
+ const autohandHome = process.env.AUTOHAND_HOME?.trim() || join(home$1, ".autohand");
255
+ const grokHome = process.env.GROK_HOME?.trim() || join(home$1, ".grok");
256
+ const zedAppDataHome = process.env.APPDATA?.trim();
257
+ const zedFlatpakConfigHome = process.env.FLATPAK_XDG_CONFIG_HOME?.trim();
258
+ function packageJsonHasDependency(packageJsonPath, dependencyName) {
259
+ try {
260
+ const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
261
+ return !!(pkg.dependencies?.[dependencyName] || pkg.devDependencies?.[dependencyName]);
262
+ } catch {
263
+ return false;
264
+ }
265
+ }
266
+ function getOpenClawGlobalSkillsDir(homeDir = home$1) {
267
+ if (existsSync(join(homeDir, ".openclaw"))) return join(homeDir, ".openclaw/skills");
268
+ if (existsSync(join(homeDir, ".clawdbot"))) return join(homeDir, ".clawdbot/skills");
269
+ if (existsSync(join(homeDir, ".moltbot"))) return join(homeDir, ".moltbot/skills");
270
+ return join(homeDir, ".openclaw/skills");
271
+ }
272
+ function isZCodeInstalled(homeDir = home$1) {
273
+ return existsSync(join(homeDir, ".zcode")) || existsSync("/Applications/ZCode.app");
274
+ }
275
+ function isKimchiInstalled(homeDir = home$1) {
276
+ return existsSync(join(homeDir, ".config", "kimchi"));
277
+ }
278
+ function make(name, displayName, skillsDir, globalSkillsDir, detect, flags = {}) {
279
+ return {
280
+ name,
281
+ displayName,
282
+ skillsDir,
283
+ globalSkillsDir,
284
+ configDir: deriveConfigDir(skillsDir),
285
+ globalConfigDir: deriveConfigDir(globalSkillsDir || skillsDir),
286
+ detectInstalled: detect,
287
+ showInUniversalList: flags.showInUniversalList ?? true,
288
+ showInUniversalPrompt: flags.showInUniversalPrompt ?? true
289
+ };
290
+ }
291
+ function deriveConfigDir(dir) {
292
+ if (!dir) return dir;
293
+ const p = dir.replace(/\\/g, "/");
294
+ if (p === "skills" || p.endsWith("/skills")) {
295
+ const i = p.lastIndexOf("/skills");
296
+ return i < 0 ? "" : p.slice(0, i);
297
+ }
298
+ return p;
299
+ }
300
+ const ex = (p) => {
301
+ try {
302
+ return existsSync(p);
303
+ } catch {
304
+ return false;
305
+ }
306
+ };
307
+ const AGENTS = {};
308
+ AGENTS["aider-desk"] = make("aider-desk", "AiderDesk", ".aider-desk/skills", join(home$1, ".aider-desk/skills"), () => ex(join(home$1, ".aider-desk")));
309
+ AGENTS["amp"] = make("amp", "Amp", ".agents/skills", join(configHome, "agents/skills"), () => ex(join(configHome, "amp")));
310
+ AGENTS["antigravity"] = make("antigravity", "Antigravity", ".agents/skills", join(home$1, ".gemini/antigravity/skills"), () => ex(join(home$1, ".gemini/antigravity")));
311
+ AGENTS["antigravity-cli"] = make("antigravity-cli", "Antigravity CLI", ".agents/skills", join(home$1, ".gemini/antigravity-cli/skills"), () => ex(join(home$1, ".gemini/antigravity-cli")));
312
+ AGENTS["astrbot"] = make("astrbot", "AstrBot", "data/skills", join(home$1, ".astrbot/data/skills"), () => ex(join(process.cwd(), "data/skills")) || ex(join(home$1, ".astrbot")));
313
+ AGENTS["autohand-code"] = make("autohand-code", "Autohand Code CLI", ".autohand/skills", join(autohandHome, "skills"), () => ex(autohandHome));
314
+ AGENTS["augment"] = make("augment", "Augment", ".augment/skills", join(home$1, ".augment/skills"), () => ex(join(home$1, ".augment")));
315
+ AGENTS["bob"] = make("bob", "IBM Bob", ".bob/skills", join(home$1, ".bob/skills"), () => ex(join(home$1, ".bob")));
316
+ AGENTS["claude-code"] = make("claude-code", "Claude Code", ".claude/skills", join(claudeHome, "skills"), () => ex(claudeHome));
317
+ AGENTS["openclaw"] = make("openclaw", "OpenClaw", "skills", getOpenClawGlobalSkillsDir(), () => ex(join(home$1, ".openclaw")) || ex(join(home$1, ".clawdbot")) || ex(join(home$1, ".moltbot")));
318
+ AGENTS["cline"] = make("cline", "Cline", ".agents/skills", join(home$1, ".agents", "skills"), () => ex(join(home$1, ".cline")));
319
+ AGENTS["codearts-agent"] = make("codearts-agent", "CodeArts Agent", ".codeartsdoer/skills", join(home$1, ".codeartsdoer/skills"), () => ex(join(home$1, ".codeartsdoer")));
320
+ AGENTS["codebuddy"] = make("codebuddy", "CodeBuddy", ".codebuddy/skills", join(home$1, ".codebuddy/skills"), () => ex(join(process.cwd(), ".codebuddy")) || ex(join(home$1, ".codebuddy")));
321
+ AGENTS["codemaker"] = make("codemaker", "Codemaker", ".codemaker/skills", join(home$1, ".codemaker/skills"), () => ex(join(home$1, ".codemaker")));
322
+ AGENTS["codestudio"] = make("codestudio", "Code Studio", ".codestudio/skills", join(home$1, ".codestudio/skills"), () => ex(join(home$1, ".codestudio")));
323
+ AGENTS["codex"] = make("codex", "Codex", ".agents/skills", join(codexHome, "skills"), () => ex(codexHome) || ex("/etc/codex"));
324
+ AGENTS["command-code"] = make("command-code", "Command Code", ".commandcode/skills", join(home$1, ".commandcode/skills"), () => ex(join(home$1, ".commandcode")));
325
+ AGENTS["continue"] = make("continue", "Continue", ".continue/skills", join(home$1, ".continue/skills"), () => ex(join(process.cwd(), ".continue")) || ex(join(home$1, ".continue")));
326
+ AGENTS["cortex"] = make("cortex", "Cortex Code", ".cortex/skills", join(home$1, ".snowflake/cortex/skills"), () => ex(join(home$1, ".snowflake/cortex")));
327
+ AGENTS["crush"] = make("crush", "Crush", ".crush/skills", join(home$1, ".config/crush/skills"), () => ex(join(home$1, ".config/crush")));
328
+ AGENTS["cursor"] = make("cursor", "Cursor", ".agents/skills", join(home$1, ".cursor/skills"), () => ex(join(home$1, ".cursor")));
329
+ AGENTS["deepagents"] = make("deepagents", "Deep Agents", ".agents/skills", join(home$1, ".deepagents/agent/skills"), () => ex(join(home$1, ".deepagents")));
330
+ AGENTS["devin"] = make("devin", "Devin for Terminal", ".devin/skills", join(configHome, "devin/skills"), () => ex(join(configHome, "devin")));
331
+ AGENTS["dexto"] = make("dexto", "Dexto", ".agents/skills", join(home$1, ".agents/skills"), () => ex(join(home$1, ".dexto")), { showInUniversalPrompt: false });
332
+ AGENTS["droid"] = make("droid", "Droid", ".factory/skills", join(home$1, ".factory/skills"), () => ex(join(home$1, ".factory")));
333
+ AGENTS["eve"] = make("eve", "Eve", "agent/skills", null, () => ex(join(process.cwd(), "agent")) && packageJsonHasDependency(join(process.cwd(), "package.json"), "eve"));
334
+ AGENTS["firebender"] = make("firebender", "Firebender", ".agents/skills", join(home$1, ".firebender/skills"), () => ex(join(home$1, ".firebender")), { showInUniversalPrompt: false });
335
+ AGENTS["forgecode"] = make("forgecode", "ForgeCode", ".forge/skills", join(home$1, ".forge/skills"), () => ex(join(home$1, ".forge")));
336
+ AGENTS["gemini-cli"] = make("gemini-cli", "Gemini CLI", ".agents/skills", join(home$1, ".gemini/skills"), () => ex(join(home$1, ".gemini")));
337
+ AGENTS["github-copilot"] = make("github-copilot", "GitHub Copilot", ".agents/skills", join(home$1, ".copilot/skills"), () => ex(join(home$1, ".copilot")));
338
+ AGENTS["goose"] = make("goose", "Goose", ".goose/skills", join(configHome, "goose/skills"), () => ex(join(configHome, "goose")));
339
+ AGENTS["grok"] = make("grok", "Grok Build", ".grok/skills", join(grokHome, "skills"), () => ex(grokHome));
340
+ AGENTS["hermes-agent"] = make("hermes-agent", "Hermes Agent", ".hermes/skills", join(hermesHome, "skills"), () => ex(hermesHome));
341
+ AGENTS["inference-sh"] = make("inference-sh", "inference.sh", ".inferencesh/skills", join(home$1, ".inferencesh/skills"), () => ex(join(home$1, ".inferencesh")));
342
+ AGENTS["jazz"] = make("jazz", "Jazz", ".jazz/skills", join(home$1, ".jazz/skills"), () => ex(join(home$1, ".jazz")) || ex(join(process.cwd(), ".jazz")));
343
+ AGENTS["junie"] = make("junie", "Junie", ".junie/skills", join(home$1, ".junie/skills"), () => ex(join(home$1, ".junie")));
344
+ AGENTS["iflow-cli"] = make("iflow-cli", "iFlow CLI", ".iflow/skills", join(home$1, ".iflow/skills"), () => ex(join(home$1, ".iflow")));
345
+ AGENTS["kilo"] = make("kilo", "Kilo Code", ".kilocode/skills", join(home$1, ".kilocode/skills"), () => ex(join(home$1, ".kilocode")));
346
+ AGENTS["kimchi"] = make("kimchi", "Kimchi", ".kimchi/skills", join(home$1, ".config", "kimchi", "harness", "skills"), () => isKimchiInstalled());
347
+ AGENTS["kimi-code-cli"] = make("kimi-code-cli", "Kimi Code CLI", ".agents/skills", join(home$1, ".agents/skills"), () => ex(join(home$1, ".kimi-code")) || ex(join(home$1, ".kimi")));
348
+ AGENTS["kiro-cli"] = make("kiro-cli", "Kiro CLI", ".kiro/skills", join(home$1, ".kiro/skills"), () => ex(join(home$1, ".kiro")));
349
+ AGENTS["kode"] = make("kode", "Kode", ".kode/skills", join(home$1, ".kode/skills"), () => ex(join(home$1, ".kode")));
350
+ AGENTS["lingma"] = make("lingma", "Lingma", ".lingma/skills", join(home$1, ".lingma/skills"), () => ex(join(home$1, ".lingma")));
351
+ AGENTS["loaf"] = make("loaf", "Loaf", ".agents/skills", join(home$1, ".agents/skills"), () => ex(join(home$1, ".loaf")), { showInUniversalPrompt: false });
352
+ AGENTS["mcpjam"] = make("mcpjam", "MCPJam", ".mcpjam/skills", join(home$1, ".mcpjam/skills"), () => ex(join(home$1, ".mcpjam")));
353
+ AGENTS["mistral-vibe"] = make("mistral-vibe", "Mistral Vibe", ".vibe/skills", join(vibeHome, "skills"), () => ex(vibeHome));
354
+ AGENTS["moxby"] = make("moxby", "Moxby", ".moxby/skills", join(home$1, ".moxby/skills"), () => ex(join(home$1, ".moxby")));
355
+ AGENTS["mux"] = make("mux", "Mux", ".mux/skills", join(home$1, ".mux/skills"), () => ex(join(home$1, ".mux")));
356
+ AGENTS["opencode"] = make("opencode", "OpenCode", ".agents/skills", join(configHome, "opencode/skills"), () => ex(join(configHome, "opencode")));
357
+ AGENTS["openhands"] = make("openhands", "OpenHands", ".openhands/skills", join(home$1, ".openhands/skills"), () => ex(join(home$1, ".openhands")));
358
+ AGENTS["ona"] = make("ona", "Ona", ".ona/skills", join(home$1, ".ona/skills"), () => ex(join(home$1, ".ona")));
359
+ AGENTS["pi"] = make("pi", "Pi", ".pi/skills", join(home$1, ".pi/agent/skills"), () => ex(join(home$1, ".pi/agent")));
360
+ AGENTS["qoder"] = make("qoder", "Qoder", ".qoder/skills", join(home$1, ".qoder/skills"), () => ex(join(home$1, ".qoder")));
361
+ AGENTS["qoder-cn"] = make("qoder-cn", "Qoder CN", ".qoder/skills", join(home$1, ".qoder-cn/skills"), () => ex(join(home$1, ".qoder-cn")));
362
+ AGENTS["qwen-code"] = make("qwen-code", "Qwen Code", ".qwen/skills", join(home$1, ".qwen/skills"), () => ex(join(home$1, ".qwen")));
363
+ AGENTS["replit"] = make("replit", "Replit", ".agents/skills", join(configHome, "agents/skills"), () => ex(join(process.cwd(), ".replit")), { showInUniversalList: false });
364
+ AGENTS["reasonix"] = make("reasonix", "Reasonix", ".reasonix/skills", join(home$1, ".reasonix/skills"), () => ex(join(home$1, ".reasonix")));
365
+ AGENTS["rovodev"] = make("rovodev", "Rovo Dev", ".rovodev/skills", join(home$1, ".rovodev/skills"), () => ex(join(home$1, ".rovodev")));
366
+ AGENTS["roo"] = make("roo", "Roo Code", ".roo/skills", join(home$1, ".roo/skills"), () => ex(join(home$1, ".roo")));
367
+ AGENTS["tabnine-cli"] = make("tabnine-cli", "Tabnine CLI", ".tabnine/agent/skills", join(home$1, ".tabnine/agent/skills"), () => ex(join(home$1, ".tabnine")));
368
+ AGENTS["terramind"] = make("terramind", "Terramind", ".terramind/skills", join(home$1, ".terramind/skills"), () => ex(join(home$1, ".terramind")));
369
+ AGENTS["tinycloud"] = make("tinycloud", "Tinycloud", ".tinycloud/skills", join(home$1, ".tinycloud/skills"), () => ex(join(home$1, ".tinycloud")));
370
+ AGENTS["trae"] = make("trae", "Trae", ".trae/skills", join(home$1, ".trae/skills"), () => ex(join(home$1, ".trae")));
371
+ AGENTS["trae-cn"] = make("trae-cn", "Trae CN", ".trae/skills", join(home$1, ".trae-cn/skills"), () => ex(join(home$1, ".trae-cn")));
372
+ AGENTS["warp"] = make("warp", "Warp", ".agents/skills", join(home$1, ".agents/skills"), () => ex(join(home$1, ".warp")));
373
+ AGENTS["windsurf"] = make("windsurf", "Windsurf", ".windsurf/skills", join(home$1, ".codeium/windsurf/skills"), () => ex(join(home$1, ".codeium/windsurf")));
374
+ AGENTS["zed"] = make("zed", "Zed", ".agents/skills", join(home$1, ".agents/skills"), () => ex(join(configHome, "zed")) || !!zedAppDataHome && ex(join(zedAppDataHome, "Zed")) || !!zedFlatpakConfigHome && ex(join(zedFlatpakConfigHome, "zed")));
375
+ AGENTS["zcode"] = make("zcode", "ZCode", ".zcode/skills", join(home$1, ".zcode/skills"), () => isZCodeInstalled());
376
+ AGENTS["zencoder"] = make("zencoder", "Zencoder", ".zencoder/skills", join(home$1, ".zencoder/skills"), () => ex(join(home$1, ".zencoder")));
377
+ AGENTS["zenflow"] = make("zenflow", "Zenflow", ".zencoder/skills", join(home$1, ".zencoder/skills"), () => ex(join(home$1, ".zencoder")));
378
+ AGENTS["neovate"] = make("neovate", "Neovate", ".neovate/skills", join(home$1, ".neovate/skills"), () => ex(join(home$1, ".neovate")));
379
+ AGENTS["pochi"] = make("pochi", "Pochi", ".pochi/skills", join(home$1, ".pochi/skills"), () => ex(join(home$1, ".pochi")));
380
+ AGENTS["promptscript"] = make("promptscript", "PromptScript", ".agents/skills", null, () => ex(join(process.cwd(), ".promptscript")) || ex(join(process.cwd(), "promptscript.yaml")), { showInUniversalPrompt: false });
381
+ AGENTS["adal"] = make("adal", "AdaL", ".adal/skills", join(home$1, ".adal/skills"), () => ex(join(home$1, ".adal")));
382
+ AGENTS["universal"] = make("universal", "Universal", ".agents/skills", join(configHome, "agents/skills"), () => false, { showInUniversalList: false });
383
+ function getAgent(name) {
384
+ return AGENTS[name] ?? null;
385
+ }
386
+ function listAgents() {
387
+ return Object.values(AGENTS);
388
+ }
389
+ function detectInstalledAgents() {
390
+ return listAgents().filter((a) => {
391
+ try {
392
+ return a.detectInstalled();
393
+ } catch {
394
+ return false;
395
+ }
396
+ });
397
+ }
398
+ function resolveAgents(names) {
399
+ if (!names || names.length === 0) return {
400
+ agents: [],
401
+ unknown: []
402
+ };
403
+ if (names.includes("*")) return {
404
+ agents: listAgents(),
405
+ unknown: []
406
+ };
407
+ const agents = [];
408
+ const unknown = [];
409
+ for (const n of names) {
410
+ const a = getAgent(n);
411
+ if (a) agents.push(a);
412
+ else unknown.push(n);
413
+ }
414
+ return {
415
+ agents,
416
+ unknown
417
+ };
418
+ }
419
+ function getUniversalAgents() {
420
+ return listAgents().filter((a) => a.skillsDir === ".agents/skills" && a.showInUniversalList !== false);
421
+ }
422
+ function getVisibleUniversalAgents() {
423
+ return listAgents().filter((a) => a.skillsDir === ".agents/skills" && a.showInUniversalList !== false && a.showInUniversalPrompt !== false);
424
+ }
425
+ function getNonUniversalAgents() {
426
+ return listAgents().filter((a) => a.skillsDir !== ".agents/skills");
427
+ }
428
+ const home = homedir();
429
+ function lockBase(opts) {
430
+ return opts.scope === "global" ? home : opts.dir || process.cwd();
431
+ }
432
+ function lockPath(opts) {
433
+ return join(lockBase(opts), ".agentry", "lock.json");
434
+ }
435
+ function legacyLockPath(opts) {
436
+ return join(lockBase(opts), ".cursor", "agentry.lock.json");
437
+ }
438
+ function tryReadLockFile(file) {
439
+ try {
440
+ return JSON.parse(readFileSync(file, "utf8"));
441
+ } catch {
442
+ return null;
443
+ }
444
+ }
445
+ function readLock(opts) {
446
+ const fromCurrent = tryReadLockFile(lockPath(opts));
447
+ if (fromCurrent) return fromCurrent;
448
+ const fromLegacy = tryReadLockFile(legacyLockPath(opts));
449
+ if (fromLegacy) return fromLegacy;
450
+ return {
451
+ version: 1,
452
+ items: {}
453
+ };
454
+ }
455
+ function removeLegacyLockIfPresent(opts) {
456
+ const legacy = legacyLockPath(opts);
457
+ if (existsSync(legacy)) rmSync(legacy, { force: true });
458
+ }
459
+ function writeLock(opts, lock) {
460
+ const file = lockPath(opts);
461
+ mkdirSync(join(file, ".."), { recursive: true });
462
+ writeFileSync(file, JSON.stringify(lock, null, 2) + "\n");
463
+ removeLegacyLockIfPresent(opts);
464
+ }
465
+ function listInstalled(opts) {
466
+ return Object.entries(readLock(opts).items).map(([id, v]) => ({
467
+ id,
468
+ ...v
469
+ }));
470
+ }
471
+ function pluralKind(kind) {
472
+ return kind === "skill" ? "skills" : kind === "rule" ? "rules" : kind === "agent" ? "agents" : kind === "script" ? "scripts" : "profiles";
473
+ }
474
+ function installOne(artifact, opts, agentList, source) {
475
+ const list = agentList.length ? agentList : [getAgent("cursor")];
476
+ const base = lockBase(opts);
477
+ const dests = [];
478
+ if (opts.dryRun) {
479
+ for (const a of list) dests.push({
480
+ agent: a.name,
481
+ dir: agentDir(artifact, a, base)
482
+ });
483
+ return dests;
484
+ }
485
+ if (artifact.kind === "skill") {
486
+ const canonical = join(base, ".agents", "skills", artifact.id);
487
+ rmSync(canonical, {
488
+ recursive: true,
489
+ force: true
490
+ });
491
+ mkdirSync(join(canonical, ".."), { recursive: true });
492
+ if (opts.copy) cpSync(artifact.dir, canonical, { recursive: true });
493
+ else try {
494
+ symlinkSync(artifact.dir, canonical, "junction");
495
+ } catch {
496
+ cpSync(artifact.dir, canonical, { recursive: true });
497
+ }
498
+ for (const a of list) if (a.skillsDir === ".agents/skills") dests.push({
499
+ agent: a.name,
500
+ dir: canonical
501
+ });
502
+ else {
503
+ const dir = join(base, a.skillsDir, artifact.id);
504
+ rmSync(dir, {
505
+ recursive: true,
506
+ force: true
507
+ });
508
+ mkdirSync(join(dir, ".."), { recursive: true });
509
+ if (opts.copy) {
510
+ cpSync(canonical, dir, { recursive: true });
511
+ dests.push({
512
+ agent: a.name,
513
+ dir
514
+ });
515
+ } else try {
516
+ symlinkSync(canonical, dir, "junction");
517
+ dests.push({
518
+ agent: a.name,
519
+ dir,
520
+ symlinked: true
521
+ });
522
+ } catch {
523
+ cpSync(canonical, dir, { recursive: true });
524
+ dests.push({
525
+ agent: a.name,
526
+ dir
527
+ });
528
+ }
529
+ }
530
+ } else for (const a of list) {
531
+ const dir = agentDir(artifact, a, base);
532
+ rmSync(dir, {
533
+ recursive: true,
534
+ force: true
535
+ });
536
+ mkdirSync(join(dir, ".."), { recursive: true });
537
+ if (opts.copy) cpSync(artifact.dir, dir, { recursive: true });
538
+ else try {
539
+ symlinkSync(artifact.dir, dir, "junction");
540
+ } catch {
541
+ cpSync(artifact.dir, dir, { recursive: true });
542
+ }
543
+ dests.push({
544
+ agent: a.name,
545
+ dir
546
+ });
547
+ }
548
+ const lock = readLock(opts);
549
+ lock.items[`${artifact.kind}/${artifact.id}`] = {
550
+ source: source || null,
551
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
552
+ agents: list.map((a) => a.name),
553
+ kind: artifact.kind
554
+ };
555
+ writeLock(opts, lock);
556
+ return dests;
557
+ }
558
+ function agentDir(artifact, a, base) {
559
+ if (artifact.kind === "skill") return join(base, a.skillsDir, artifact.id);
560
+ if (artifact.isFile) {
561
+ const ext = artifact.kind === "profile" ? ".yaml" : ".mdc";
562
+ return join(base, a.configDir || a.skillsDir, pluralKind(artifact.kind), artifact.name + ext);
563
+ }
564
+ return join(base, a.configDir || a.skillsDir, pluralKind(artifact.kind), artifact.id);
565
+ }
566
+ function removeSelection(kind, selector, opts, agentList) {
567
+ const base = lockBase(opts);
568
+ const list = agentList.length ? agentList : [getAgent("cursor")];
569
+ const rel = [kind, selector].filter(Boolean).join("/");
570
+ const removedKeys = [];
571
+ const lock = readLock(opts);
572
+ const pkind = pluralKind(kind);
573
+ for (const a of list) {
574
+ let dir;
575
+ if (kind === "skill") dir = join(base, a.skillsDir, selector || "");
576
+ else if (kind === "agent" || kind === "rule" || kind === "profile") {
577
+ const ext = kind === "profile" ? ".yaml" : ".mdc";
578
+ if (!selector) dir = join(base, a.configDir || a.skillsDir, pkind);
579
+ else if (selector.includes("/")) {
580
+ const [cat, name] = selector.split("/");
581
+ dir = join(base, a.configDir || a.skillsDir, pkind, cat, name + ext);
582
+ } else dir = join(base, a.configDir || a.skillsDir, pkind, selector + ext);
583
+ } else dir = join(base, a.configDir || a.skillsDir, pkind, selector || "");
584
+ if (existsSync(dir)) rmSync(dir, {
585
+ recursive: true,
586
+ force: true
587
+ });
588
+ }
589
+ for (const key of Object.keys(lock.items)) if (key === rel || key.startsWith(rel + "/")) {
590
+ delete lock.items[key];
591
+ removedKeys.push(key);
592
+ }
593
+ writeLock(opts, lock);
594
+ return {
595
+ existed: removedKeys.length > 0,
596
+ removedKeys
597
+ };
598
+ }
599
+ const ProfileArtifactRefSchema = z.object({
600
+ source: z.string().optional(),
601
+ id: z.string()
602
+ });
603
+ const ProfileSchema = z.object({
604
+ name: z.string(),
605
+ description: z.string().optional(),
606
+ scope: z.enum(["global", "project"]).default("project"),
607
+ targets: z.object({ agents: z.array(z.string()).default([]) }).default({ agents: [] }),
608
+ artifacts: z.object({
609
+ skills: z.array(ProfileArtifactRefSchema).default([]),
610
+ rules: z.array(ProfileArtifactRefSchema).default([]),
611
+ agents: z.array(ProfileArtifactRefSchema).default([]),
612
+ scripts: z.array(ProfileArtifactRefSchema).default([])
613
+ }).default({})
614
+ });
615
+ function loadProfileFile(file) {
616
+ let raw;
617
+ try {
618
+ raw = readFileSync(file, "utf8");
619
+ } catch {
620
+ throw new Error(`Profile not found: ${file}`);
621
+ }
622
+ let data;
623
+ try {
624
+ data = parse(raw);
625
+ } catch (e) {
626
+ throw new Error(`Invalid YAML in ${file}: ${e.message}`);
627
+ }
628
+ const result = ProfileSchema.safeParse(data);
629
+ if (!result.success) throw new Error(`Invalid profile ${file}: ${result.error.message}`);
630
+ return result.data;
631
+ }
632
+ function loadProfile(name, baseDir) {
633
+ const file = join(baseDir || process.cwd(), "profile", `${name}.yaml`);
634
+ return {
635
+ file,
636
+ profile: loadProfileFile(file)
637
+ };
638
+ }
639
+ let runningInsideAgent = false;
640
+ try {
641
+ const result = await determineAgent();
642
+ runningInsideAgent = !!(result && result.isAgent);
643
+ } catch {}
644
+ function isCI() {
645
+ if (process.env.CI === "true" || process.env.CI === "1") return true;
646
+ if (!process.stdout.isTTY) return true;
647
+ return runningInsideAgent;
648
+ }
649
+ const silentOutput = new Writable({ write(_chunk, _encoding, callback) {
650
+ callback();
651
+ } });
652
+ const cancelSymbol = Symbol("cancel");
653
+ const ALL_VALUE = "__all__";
654
+ const BLUE = c.blue;
655
+ const BLUE_BOLD = (s) => c.bold(c.blue(s));
656
+ const S_STEP_ACTIVE = BLUE("◆");
657
+ const S_STEP_CANCEL = c.red("■");
658
+ const S_STEP_SUBMIT = BLUE("◇");
659
+ const S_RADIO_ACTIVE = BLUE("●");
660
+ const S_RADIO_INACTIVE = c.dim("○");
661
+ const S_RADIO_DISABLED = c.dim("◌");
662
+ const S_BULLET = BLUE("•");
663
+ const S_BAR = c.dim("│");
664
+ const S_BAR_H = c.dim("─");
665
+ const S_CORNER = c.dim("└");
666
+ const S_BOX_TL = c.dim("┌");
667
+ const S_BOX_TR = c.dim("┐");
668
+ const S_BOX_BL = c.dim("└");
669
+ const S_BOX_BR = c.dim("┘");
670
+ const S_BOX_H = c.dim("─");
671
+ const S_BOX_V = c.dim("│");
672
+ function approxStringWidth(plain) {
673
+ let width = 0;
674
+ for (const ch of plain) {
675
+ const code = ch.codePointAt(0);
676
+ if (code === 0) continue;
677
+ width += code >= 4352 && code <= 4447 || code >= 11904 && code <= 42191 && code !== 12351 || code >= 44032 && code <= 55203 || code >= 63744 && code <= 64255 || code >= 65280 && code <= 65376 || code >= 126976 && code <= 129535 ? 2 : 1;
678
+ }
679
+ return width;
680
+ }
681
+ function visualRowsForLine(line, columns) {
682
+ const plain = stripVTControlCharacters(line);
683
+ const cols = Math.max(1, columns);
684
+ return Math.max(1, Math.ceil(approxStringWidth(plain) / cols));
685
+ }
686
+ function countVisualRowsForLines(lines, columns) {
687
+ const cols = columns !== void 0 && columns > 0 ? columns : process.stdout.columns && process.stdout.columns > 0 ? process.stdout.columns : 80;
688
+ return lines.reduce((sum, line) => sum + visualRowsForLine(line, cols), 0);
689
+ }
690
+ function truncateToWidth(text, width) {
691
+ let truncated = "";
692
+ for (const char of text) {
693
+ if (approxStringWidth(truncated + char) > width) break;
694
+ truncated += char;
695
+ }
696
+ return truncated;
697
+ }
698
+ function padPlain(text, width) {
699
+ const w = approxStringWidth(text);
700
+ if (w >= width) return truncateToWidth(text, width);
701
+ return text + " ".repeat(width - w);
702
+ }
703
+ function wrapPlain(text, width, maxLines) {
704
+ const normalized = text.replace(/\s+/g, " ").trim();
705
+ if (!normalized) return [""];
706
+ const lines = [];
707
+ let remaining = normalized;
708
+ while (remaining && lines.length < maxLines) {
709
+ if (approxStringWidth(remaining) <= width) {
710
+ lines.push(remaining);
711
+ remaining = "";
712
+ break;
713
+ }
714
+ const candidate = truncateToWidth(remaining, width);
715
+ const breakAt = candidate.lastIndexOf(" ");
716
+ if (breakAt > 0) {
717
+ lines.push(candidate.slice(0, breakAt).trimEnd());
718
+ remaining = remaining.slice(breakAt).trimStart();
719
+ } else {
720
+ lines.push(candidate);
721
+ remaining = remaining.slice(candidate.length).trimStart();
722
+ }
723
+ }
724
+ if (remaining && lines.length > 0) {
725
+ const last = lines.length - 1;
726
+ lines[last] = `${truncateToWidth(lines[last], Math.max(0, width - 1)).trimEnd()}…`;
727
+ }
728
+ return lines.length ? lines : [""];
729
+ }
730
+ function renderInfoBox(fields, innerWidth, rows) {
731
+ const title = " Info ";
732
+ const topPad = Math.max(0, innerWidth - approxStringWidth(title));
733
+ const top = `${S_BOX_TL}${S_BOX_H}${title}${S_BOX_H.repeat(topPad)}${S_BOX_TR}`;
734
+ const bottom = `${S_BOX_BL}${S_BOX_H.repeat(innerWidth + 1)}${S_BOX_BR}`;
735
+ const contentWidth = Math.max(12, innerWidth - 1);
736
+ const labelW = 10;
737
+ const valueW = Math.max(8, contentWidth - labelW - 1);
738
+ const longLabels = /* @__PURE__ */ new Set([
739
+ "about",
740
+ "description",
741
+ "desc",
742
+ "note",
743
+ "action"
744
+ ]);
745
+ const expanded = [];
746
+ for (const f of fields) {
747
+ if (!f.label && !f.value) continue;
748
+ if (longLabels.has(f.label.toLowerCase())) wrapPlain(f.value || "—", valueW, 4).forEach((line, idx) => {
749
+ expanded.push({
750
+ label: idx === 0 ? f.label : "",
751
+ value: line,
752
+ cont: idx > 0
753
+ });
754
+ });
755
+ else expanded.push({
756
+ label: f.label,
757
+ value: truncateToWidth((f.value || "—").replace(/\s+/g, " ").trim(), valueW)
758
+ });
759
+ }
760
+ while (expanded.length > rows) expanded.pop();
761
+ while (expanded.length < rows) expanded.push({
762
+ label: "",
763
+ value: ""
764
+ });
765
+ const body = expanded.map((r) => {
766
+ if (!r.label && !r.value) return `${S_BOX_V} ${" ".repeat(contentWidth)} ${S_BOX_V}`;
767
+ const content = `${r.label ? `${c.blue(padPlain(r.label, labelW))} ` : `${" ".repeat(labelW)} `}${r.cont ? c.dim(r.value) : c.bold(r.value)}`;
768
+ const plainW = approxStringWidth(stripVTControlCharacters(content));
769
+ const pad = Math.max(0, contentWidth - plainW);
770
+ return `${S_BOX_V} ${content}${" ".repeat(pad)} ${S_BOX_V}`;
771
+ });
772
+ return [
773
+ `${S_BAR} ${top}`,
774
+ ...body.map((b) => `${S_BAR} ${b}`),
775
+ `${S_BAR} ${bottom}`
776
+ ];
777
+ }
778
+ function fieldsForItem(item, allSelected, total) {
779
+ if (!item) return [{
780
+ label: "Name",
781
+ value: "—"
782
+ }, {
783
+ label: "About",
784
+ value: "No item highlighted"
785
+ }];
786
+ if (String(item.value) === "__all__") return [
787
+ {
788
+ label: "Name",
789
+ value: item.label
790
+ },
791
+ {
792
+ label: "About",
793
+ value: allSelected ? `All ${total} items selected. Individual rows are locked until you turn All off.` : `Select every item in the list (${total}). Space toggles All; Enter confirms.`
794
+ },
795
+ {
796
+ label: "Count",
797
+ value: String(total)
798
+ }
799
+ ];
800
+ if (item.fields && item.fields.length) return item.fields;
801
+ const desc = (item.detail || item.hint || "").replace(/\s+/g, " ").trim();
802
+ return [
803
+ {
804
+ label: "Name",
805
+ value: item.label
806
+ },
807
+ {
808
+ label: "Id",
809
+ value: String(item.value)
810
+ },
811
+ {
812
+ label: "About",
813
+ value: desc || "—"
814
+ }
815
+ ];
816
+ }
817
+ async function searchMultiselect(options) {
818
+ const { message, items, maxVisible = 8, initialSelected = [], required = false, lockedSection, searchable = true, showDetail = true, detailLines = 8, showSelectedSummary = true, includeAllOption = false, allLabel, allHint = "select every item · disables others" } = options;
819
+ const seen = /* @__PURE__ */ new Set();
820
+ const uniqueItems = items.filter((item) => {
821
+ const key = String(item.value);
822
+ if (seen.has(key) || key === "__all__") return false;
823
+ seen.add(key);
824
+ return true;
825
+ });
826
+ const allItem = includeAllOption ? {
827
+ value: ALL_VALUE,
828
+ label: allLabel || `All (${uniqueItems.length})`,
829
+ hint: allHint,
830
+ fields: [
831
+ {
832
+ label: "Name",
833
+ value: allLabel || `All (${uniqueItems.length})`
834
+ },
835
+ {
836
+ label: "Action",
837
+ value: "Install every listed item"
838
+ },
839
+ {
840
+ label: "Count",
841
+ value: String(uniqueItems.length)
842
+ },
843
+ {
844
+ label: "Note",
845
+ value: "When All is on, other rows are disabled"
846
+ },
847
+ {
848
+ label: "",
849
+ value: ""
850
+ }
851
+ ]
852
+ } : null;
853
+ allItem && [...uniqueItems];
854
+ return new Promise((resolve) => {
855
+ const rl = readline.createInterface({
856
+ input: process.stdin,
857
+ output: silentOutput,
858
+ terminal: false
859
+ });
860
+ if (process.stdin.isTTY) process.stdin.setRawMode(true);
861
+ readline.emitKeypressEvents(process.stdin, rl);
862
+ let query = "";
863
+ let cursor = 0;
864
+ const selected = new Set(initialSelected.filter((v) => String(v) !== ALL_VALUE));
865
+ let lastRenderHeight = 0;
866
+ let requiredFlash = false;
867
+ const lockedValues = lockedSection ? lockedSection.items.map((i) => i.value) : [];
868
+ const isAllOn = () => selected.has(ALL_VALUE);
869
+ const getFiltered = () => {
870
+ const rest = uniqueItems;
871
+ if (!query) return allItem ? [allItem, ...rest] : rest;
872
+ const lowerQ = query.toLowerCase();
873
+ const matched = rest.filter((item) => item.label.toLowerCase().includes(lowerQ) || String(item.value).toLowerCase().includes(lowerQ) || item.hint && item.hint.toLowerCase().includes(lowerQ));
874
+ return allItem && (allItem.label.toLowerCase().includes(lowerQ) || "all".includes(lowerQ)) && allItem ? [allItem, ...matched] : matched;
875
+ };
876
+ const render = (state = "active") => {
877
+ const lines = [];
878
+ const filtered = getFiltered();
879
+ const allOn = isAllOn();
880
+ const icon = state === "active" ? S_STEP_ACTIVE : state === "cancel" ? S_STEP_CANCEL : S_STEP_SUBMIT;
881
+ lines.push(`${icon} ${c.bold(message)}`);
882
+ lines.push(`${S_BAR}`);
883
+ if (state === "active") {
884
+ if (lockedSection && lockedSection.items.length > 0) {
885
+ const lockedTitle = `${c.bold(lockedSection.title)} ${c.dim("── always included")}`;
886
+ lines.push(`${S_BAR} ${S_BAR_H}${S_BAR_H} ${lockedTitle} ${S_BAR_H.repeat(8)}`);
887
+ for (const item of lockedSection.items.slice(0, 3)) lines.push(`${S_BAR} ${S_BULLET} ${c.bold(item.label)}`);
888
+ const more = (lockedSection.hiddenCount ?? 0) + Math.max(0, lockedSection.items.length - 3);
889
+ if (more > 0) lines.push(`${S_BAR} ${c.dim(`…and ${more} more`)}`);
890
+ lines.push(`${S_BAR}`);
891
+ lines.push(`${S_BAR} ${S_BAR_H}${S_BAR_H} ${c.bold("Additional")} ${S_BAR_H.repeat(26)}`);
892
+ lines.push(`${S_BAR}`);
893
+ }
894
+ if (searchable) {
895
+ lines.push(`${S_BAR} ${c.dim("Search:")} ${query}${c.inverse(" ")}`);
896
+ lines.push(`${S_BAR} ${c.dim("↑↓ move · space select · enter confirm")}`);
897
+ lines.push(`${S_BAR}`);
898
+ }
899
+ const visibleStart = Math.max(0, Math.min(cursor - Math.floor(maxVisible / 2), Math.max(0, filtered.length - maxVisible)));
900
+ const visibleEnd = Math.min(filtered.length, visibleStart + maxVisible);
901
+ const visible = filtered.slice(visibleStart, visibleEnd);
902
+ if (filtered.length === 0) lines.push(`${S_BAR} ${c.dim("No matches found")}`);
903
+ else {
904
+ for (let i = 0; i < visible.length; i++) {
905
+ const item = visible[i];
906
+ const isCursor = visibleStart + i === cursor;
907
+ const isAllRow = String(item.value) === ALL_VALUE;
908
+ const disabled = allOn && !isAllRow;
909
+ const isSelected = isAllRow ? allOn : allOn ? true : selected.has(item.value);
910
+ let radio;
911
+ if (disabled) radio = S_RADIO_DISABLED;
912
+ else if (isSelected) radio = S_RADIO_ACTIVE;
913
+ else radio = S_RADIO_INACTIVE;
914
+ let label;
915
+ if (disabled) label = c.dim(item.label);
916
+ else if (isCursor) label = c.underline(BLUE_BOLD(item.label));
917
+ else if (isAllRow) label = c.bold(item.label);
918
+ else label = item.label;
919
+ const hint = disabled || !item.hint ? "" : c.dim(` · ${item.hint.slice(0, 36)}`);
920
+ const prefix = isCursor ? BLUE("❯") : " ";
921
+ lines.push(`${S_BAR} ${prefix} ${radio} ${label}${hint}`);
922
+ }
923
+ const hiddenBefore = visibleStart;
924
+ const hiddenAfter = filtered.length - visibleEnd;
925
+ if (hiddenBefore > 0 || hiddenAfter > 0) {
926
+ const parts = [];
927
+ if (hiddenBefore > 0) parts.push(`↑ ${hiddenBefore} more`);
928
+ if (hiddenAfter > 0) parts.push(`↓ ${hiddenAfter} more`);
929
+ lines.push(`${S_BAR} ${c.dim(parts.join(" "))}`);
930
+ }
931
+ }
932
+ if (showDetail) {
933
+ const columns = process.stdout.columns && process.stdout.columns > 0 ? process.stdout.columns : 80;
934
+ const boxInner = Math.min(72, Math.max(48, columns - 6));
935
+ const fields = fieldsForItem(filtered[cursor], allOn, uniqueItems.length);
936
+ lines.push(`${S_BAR}`);
937
+ lines.push(...renderInfoBox(fields, boxInner, detailLines));
938
+ }
939
+ if (showSelectedSummary) {
940
+ lines.push(`${S_BAR}`);
941
+ if (allOn) lines.push(`${S_BAR} ${BLUE("Selected:")} ${c.bold(`All ${uniqueItems.length}`)}`);
942
+ else {
943
+ const labels = uniqueItems.filter((item) => selected.has(item.value)).map((item) => item.label);
944
+ if (labels.length === 0) lines.push(`${S_BAR} ${requiredFlash ? c.red("Selected: pick at least one") : c.dim("Selected: (none)")}`);
945
+ else {
946
+ const summary = labels.length <= 3 ? labels.join(", ") : `${labels.slice(0, 3).join(", ")} +${labels.length - 3} more`;
947
+ lines.push(`${S_BAR} ${BLUE("Selected:")} ${summary}`);
948
+ }
949
+ }
950
+ }
951
+ lines.push(`${S_CORNER}`);
952
+ } else if (state === "submit") {
953
+ const labels = allOn ? [`All (${uniqueItems.length})`] : uniqueItems.filter((item) => selected.has(item.value)).map((item) => item.label);
954
+ lines.push(`${S_BAR} ${c.dim(labels.join(", ") || "none")}`);
955
+ } else lines.push(`${S_BAR} ${c.strikethrough(c.dim("Cancelled"))}`);
956
+ const clearPreviousFrame = lastRenderHeight > 0 ? `\x1b[${lastRenderHeight}A\x1b[J` : "";
957
+ process.stdout.write(clearPreviousFrame + lines.join("\n") + "\n");
958
+ lastRenderHeight = countVisualRowsForLines(lines, process.stdout.columns);
959
+ };
960
+ const cleanup = () => {
961
+ process.stdin.removeListener("keypress", keypressHandler);
962
+ if (process.stdin.isTTY) process.stdin.setRawMode(false);
963
+ rl.close();
964
+ };
965
+ const submit = () => {
966
+ const allOn = isAllOn();
967
+ if (required && !allOn && selected.size === 0 && lockedValues.length === 0) {
968
+ requiredFlash = true;
969
+ render();
970
+ return;
971
+ }
972
+ render("submit");
973
+ cleanup();
974
+ if (allOn) resolve([...lockedValues, ...uniqueItems.map((i) => i.value)]);
975
+ else resolve([...lockedValues, ...Array.from(selected).filter((v) => String(v) !== ALL_VALUE)]);
976
+ };
977
+ const cancel = () => {
978
+ render("cancel");
979
+ cleanup();
980
+ resolve(cancelSymbol);
981
+ };
982
+ const keypressHandler = (_str, key) => {
983
+ if (!key) return;
984
+ const filtered = getFiltered();
985
+ if (key.name === "return") {
986
+ submit();
987
+ return;
988
+ }
989
+ if (key.name === "escape" || key.ctrl && key.name === "c") {
990
+ cancel();
991
+ return;
992
+ }
993
+ if (key.name === "up") {
994
+ cursor = Math.max(0, cursor - 1);
995
+ requiredFlash = false;
996
+ render();
997
+ return;
998
+ }
999
+ if (key.name === "down") {
1000
+ cursor = Math.min(Math.max(0, filtered.length - 1), cursor + 1);
1001
+ requiredFlash = false;
1002
+ render();
1003
+ return;
1004
+ }
1005
+ if (key.name === "space") {
1006
+ const item = filtered[cursor];
1007
+ if (!item) return;
1008
+ if (String(item.value) === "__all__") if (isAllOn()) selected.delete(ALL_VALUE);
1009
+ else {
1010
+ selected.clear();
1011
+ selected.add(ALL_VALUE);
1012
+ }
1013
+ else if (isAllOn()) {
1014
+ requiredFlash = false;
1015
+ render();
1016
+ return;
1017
+ } else if (selected.has(item.value)) selected.delete(item.value);
1018
+ else selected.add(item.value);
1019
+ requiredFlash = false;
1020
+ render();
1021
+ return;
1022
+ }
1023
+ if (key.name === "backspace") {
1024
+ query = query.slice(0, -1);
1025
+ cursor = 0;
1026
+ render();
1027
+ return;
1028
+ }
1029
+ if (searchable && key.sequence && !key.ctrl && !key.meta && key.sequence.length === 1) {
1030
+ query += key.sequence;
1031
+ cursor = 0;
1032
+ render();
1033
+ return;
1034
+ }
1035
+ };
1036
+ process.stdin.on("keypress", keypressHandler);
1037
+ render();
1038
+ });
1039
+ }
1040
+ function isQuiet() {
1041
+ return isCI() || !process.stdout.isTTY;
1042
+ }
1043
+ function isCancelLike(res) {
1044
+ return res == null || res === cancelSymbol || clack.isCancel(res);
1045
+ }
1046
+ function intro() {
1047
+ if (isQuiet()) return;
1048
+ clack.intro(badge());
1049
+ }
1050
+ function outro(message) {
1051
+ if (isQuiet()) {
1052
+ process.stdout.write(message + "\n");
1053
+ return;
1054
+ }
1055
+ clack.outro(message);
1056
+ }
1057
+ function log(message) {
1058
+ process.stdout.write(message + "\n");
1059
+ }
1060
+ function blank() {
1061
+ process.stdout.write("\n");
1062
+ }
1063
+ async function sectionTransition(doneLabel, nextLabel) {
1064
+ if (isQuiet()) return;
1065
+ blank();
1066
+ log(`${c.blue("◇")} ${c.dim("Done:")} ${c.bold(doneLabel)}`);
1067
+ await delay(320);
1068
+ for (const ch of [
1069
+ "│",
1070
+ "│",
1071
+ "↓"
1072
+ ]) {
1073
+ process.stdout.write(`${c.dim(` ${ch}`)}\n`);
1074
+ await delay(140);
1075
+ }
1076
+ await delay(200);
1077
+ log(`${c.blue("◆")} ${c.bold("Next:")} ${nextLabel}`);
1078
+ await delay(420);
1079
+ blank();
1080
+ }
1081
+ function step(message) {
1082
+ process.stdout.write(` ${c.blue("→")} ${message}\n`);
1083
+ }
1084
+ function ok(message) {
1085
+ process.stdout.write(`${c.blue("✓")} ${message}\n`);
1086
+ }
1087
+ function err(message) {
1088
+ process.stdout.write(`${c.red("✗")} ${message}\n`);
1089
+ }
1090
+ function warn(message) {
1091
+ process.stdout.write(`${c.yellow("⚠")} ${message}\n`);
1092
+ }
1093
+ function info(message) {
1094
+ process.stdout.write(`${c.blue("ℹ")} ${message}\n`);
1095
+ }
1096
+ async function spinner(startMsg, fn, stopWith, minMs = 480) {
1097
+ if (isQuiet()) {
1098
+ process.stdout.write(c.dim(`• ${startMsg}...`) + "\n");
1099
+ const r = await fn();
1100
+ if (stopWith) process.stdout.write(`${c.blue("◇")} ${stopWith(r)}\n`);
1101
+ return r;
1102
+ }
1103
+ const frames = [
1104
+ "⠋",
1105
+ "⠙",
1106
+ "⠹",
1107
+ "⠸",
1108
+ "⠼",
1109
+ "⠴",
1110
+ "⠦",
1111
+ "⠧",
1112
+ "⠇",
1113
+ "⠏"
1114
+ ];
1115
+ let i = 0;
1116
+ let alive = true;
1117
+ process.stdout.write(`${c.blue(frames[0])} ${startMsg}`);
1118
+ const tick = setInterval(() => {
1119
+ if (!alive) return;
1120
+ i = (i + 1) % frames.length;
1121
+ process.stdout.write(`\r${c.blue(frames[i])} ${startMsg} `);
1122
+ }, 80);
1123
+ const started = Date.now();
1124
+ try {
1125
+ const result = await fn();
1126
+ const wait = Math.max(0, minMs - (Date.now() - started));
1127
+ if (wait) await delay(wait);
1128
+ alive = false;
1129
+ clearInterval(tick);
1130
+ const msg = stopWith ? stopWith(result) : startMsg;
1131
+ process.stdout.write(`\r\x1b[K${c.blue("◇")} ${msg}\n`);
1132
+ return result;
1133
+ } catch (e) {
1134
+ alive = false;
1135
+ clearInterval(tick);
1136
+ process.stdout.write(`\r\x1b[K${c.red("■")} ${startMsg}\n`);
1137
+ throw e;
1138
+ }
1139
+ }
1140
+ function artifactFields(a) {
1141
+ return [
1142
+ {
1143
+ label: "Name",
1144
+ value: a.name
1145
+ },
1146
+ {
1147
+ label: "Kind",
1148
+ value: a.kind
1149
+ },
1150
+ {
1151
+ label: "Id",
1152
+ value: a.id
1153
+ },
1154
+ {
1155
+ label: "About",
1156
+ value: a.description ? a.description.replace(/\s+/g, " ").trim() : "No description provided."
1157
+ },
1158
+ {
1159
+ label: "Path",
1160
+ value: a.dir
1161
+ }
1162
+ ];
1163
+ }
1164
+ function agentFields(a, installed) {
1165
+ return [
1166
+ {
1167
+ label: "Name",
1168
+ value: a.displayName
1169
+ },
1170
+ {
1171
+ label: "Id",
1172
+ value: a.name
1173
+ },
1174
+ {
1175
+ label: "Project",
1176
+ value: a.skillsDir
1177
+ },
1178
+ {
1179
+ label: "Global",
1180
+ value: a.globalSkillsDir || "—"
1181
+ },
1182
+ {
1183
+ label: "About",
1184
+ value: [
1185
+ a.skillsDir === ".agents/skills" ? "Universal provider (.agents/skills)." : "Provider-specific install path.",
1186
+ installed ? "Detected on this machine." : "Not detected on this machine.",
1187
+ a.globalSkillsDir ? `Global skills: ${a.globalSkillsDir}` : ""
1188
+ ].filter(Boolean).join(" ")
1189
+ }
1190
+ ];
1191
+ }
1192
+ async function selectArtifacts(message, artifacts) {
1193
+ if (isQuiet() || artifacts.length <= 1) return artifacts;
1194
+ blank();
1195
+ const res = await searchMultiselect({
1196
+ message,
1197
+ items: artifacts.map((a) => ({
1198
+ value: a.id,
1199
+ label: a.id,
1200
+ hint: a.description ? a.description.replace(/\s+/g, " ").slice(0, 42) : a.kind,
1201
+ fields: artifactFields(a)
1202
+ })),
1203
+ maxVisible: 8,
1204
+ required: true,
1205
+ searchable: true,
1206
+ showDetail: true,
1207
+ detailLines: 8,
1208
+ showSelectedSummary: true,
1209
+ includeAllOption: true,
1210
+ allLabel: `All (${artifacts.length})`,
1211
+ allHint: "every skill below · disables others"
1212
+ });
1213
+ if (res === cancelSymbol) return null;
1214
+ blank();
1215
+ const ids = new Set(res);
1216
+ return artifacts.filter((a) => ids.has(a.id));
1217
+ }
1218
+ async function selectAgents(message, universal, others, detectedNames = []) {
1219
+ const seen = /* @__PURE__ */ new Set();
1220
+ const uniqueOthers = others.filter((o) => {
1221
+ if (seen.has(o.name)) return false;
1222
+ seen.add(o.name);
1223
+ return true;
1224
+ });
1225
+ const detected = uniqueOthers.filter((o) => detectedNames.includes(o.name));
1226
+ if (isQuiet()) return [...universal, ...detected];
1227
+ if (!uniqueOthers.length) return universal;
1228
+ blank();
1229
+ const installedSet = new Set(detectedNames);
1230
+ const items = uniqueOthers.map((a) => ({
1231
+ value: a.name,
1232
+ label: a.displayName,
1233
+ hint: installedSet.has(a.name) ? `${a.skillsDir} · detected` : a.skillsDir,
1234
+ fields: agentFields(a, installedSet.has(a.name))
1235
+ }));
1236
+ const locked = universal.length > 0 ? {
1237
+ title: "Universal",
1238
+ items: universal.slice(0, 6).map((a) => ({
1239
+ value: a.name,
1240
+ label: a.displayName,
1241
+ fields: agentFields(a, true)
1242
+ })),
1243
+ hiddenCount: Math.max(0, universal.length - 6)
1244
+ } : void 0;
1245
+ const res = await searchMultiselect({
1246
+ message,
1247
+ items,
1248
+ maxVisible: 8,
1249
+ required: false,
1250
+ initialSelected: detected.map((d) => d.name),
1251
+ lockedSection: locked,
1252
+ searchable: true,
1253
+ showDetail: true,
1254
+ detailLines: 8,
1255
+ showSelectedSummary: true,
1256
+ includeAllOption: true,
1257
+ allLabel: `All additional (${uniqueOthers.length})`,
1258
+ allHint: "every provider below · disables others"
1259
+ });
1260
+ if (res === cancelSymbol) return null;
1261
+ blank();
1262
+ const picked = new Set(res);
1263
+ const byName = new Map([...universal, ...uniqueOthers].map((a) => [a.name, a]));
1264
+ const out = [];
1265
+ for (const name of picked) {
1266
+ const a = byName.get(name);
1267
+ if (a) out.push(a);
1268
+ }
1269
+ for (const u of universal) if (!out.some((a) => a.name === u.name)) out.unshift(u);
1270
+ return out;
1271
+ }
1272
+ function installSummary(artifacts, agents, scopeLabel) {
1273
+ blank();
1274
+ const bar = c.dim("│");
1275
+ const corner = c.dim("└");
1276
+ log(`${c.blue("◆")} ${c.bold("Install summary")}`);
1277
+ log(bar);
1278
+ log(`${bar} ${c.blue("Scope")} ${scopeLabel}`);
1279
+ const universalCount = agents.filter((a) => a.skillsDir === ".agents/skills").length;
1280
+ const otherCount = agents.length - universalCount;
1281
+ log(`${bar} ${c.blue("Targets")} ${agents.length} agent${agents.length === 1 ? "" : "s"}` + c.dim(` · ${universalCount} universal` + (otherCount ? ` · ${otherCount} additional` : "")));
1282
+ const names = agents.map((a) => a.displayName);
1283
+ const chunks = [];
1284
+ let line = "";
1285
+ for (const n of names) {
1286
+ const next = line ? `${line}, ${n}` : n;
1287
+ if (next.length > 56) {
1288
+ if (line) chunks.push(line);
1289
+ line = n;
1290
+ } else line = next;
1291
+ }
1292
+ if (line) chunks.push(line);
1293
+ for (const ch of chunks.slice(0, 3)) log(`${bar} ${c.dim(ch)}`);
1294
+ if (chunks.length > 3) log(`${bar} ${c.dim(`… +${chunks.length - 3} more lines`)}`);
1295
+ log(bar);
1296
+ log(`${bar} ${c.bold("Artifacts")} ${artifacts.length} selected`);
1297
+ log(bar);
1298
+ for (const a of artifacts) {
1299
+ const desc = (a.description || "").replace(/\s+/g, " ").trim().slice(0, 52);
1300
+ log(`${bar} ${c.blue("•")} ${c.bold(`${a.kind}/${a.id}`)}`);
1301
+ if (desc) log(`${bar} ${c.dim(desc)}`);
1302
+ }
1303
+ log(bar);
1304
+ log(`${corner} ${c.dim("Review before use — artifacts run with full agent permissions.")}`);
1305
+ blank();
1306
+ }
1307
+ function preview(artifacts, agents) {
1308
+ installSummary(artifacts, agents, "preview (dry-run)");
1309
+ }
1310
+ async function cmdAdd(kind, source, selector, opts) {
1311
+ if (!source) throw new Error(`Missing source. e.g. agentry add ${kind} author/repo`);
1312
+ intro();
1313
+ await delayQuiet(180);
1314
+ await spinner("Parsing source…", () => parseSourceForUi(source), (p) => {
1315
+ const where = p.url || p.local || source;
1316
+ return `${c.blue("Source:")} ${where}${p.ref ? c.dim(` @ ${p.ref}`) : ""}${p.subpath ? c.dim(` (${p.subpath})`) : ""}`;
1317
+ }, 520);
1318
+ await delayQuiet(280);
1319
+ const { root, cleanup } = resolveSource(source);
1320
+ try {
1321
+ const artifacts = await spinner("Discovering…", () => kind === "all" ? listAll(root) : select(root, kind, selector), (a) => {
1322
+ const noun = kind === "all" ? "artifact" : kind;
1323
+ return `Found ${a.length} ${noun}${a.length === 1 ? "" : "s"}`;
1324
+ }, 620);
1325
+ if (!artifacts.length) {
1326
+ outro(c.red(`Nothing found for "${kind}${selector ? " " + selector : ""}" in ${source}.`));
1327
+ return;
1328
+ }
1329
+ await delayQuiet(320);
1330
+ blank();
1331
+ if (opts.dryRun) {
1332
+ preview(artifacts, await resolveAgentList(opts));
1333
+ return;
1334
+ }
1335
+ let chosen = artifacts;
1336
+ if (!selector && kind !== "all" && artifacts.length > 1 && !opts.all && !opts.yes && !isQuiet()) {
1337
+ await sectionTransition("source discovery", `select ${kind}s to install`);
1338
+ const picked = await selectArtifacts(`Select ${kind}s to install`, artifacts);
1339
+ if (isCancelLike(picked)) {
1340
+ outro("Cancelled.");
1341
+ return;
1342
+ }
1343
+ chosen = picked;
1344
+ await sectionTransition(`${chosen.length} ${kind}${chosen.length === 1 ? "" : "s"} selected`, "choose target agents");
1345
+ } else if (!isQuiet() && !opts.agents.length && !opts.all && !opts.yes) await sectionTransition(`${chosen.length} ${kind}${chosen.length === 1 ? "" : "s"} ready`, "choose target agents");
1346
+ else {
1347
+ await delayQuiet(200);
1348
+ blank();
1349
+ }
1350
+ const agentList = await resolveAgentList(opts);
1351
+ if (!isQuiet() && !opts.agents.length && !opts.all && !opts.yes) await sectionTransition(`${agentList.length} agent${agentList.length === 1 ? "" : "s"} selected`, "install summary");
1352
+ installAll(chosen, opts, agentList, source);
1353
+ } finally {
1354
+ cleanup();
1355
+ }
1356
+ }
1357
+ async function delayQuiet(ms) {
1358
+ if (isQuiet()) return;
1359
+ const { delay } = await import("./_chunks/theme.mjs");
1360
+ await delay(ms);
1361
+ }
1362
+ function parseSourceForUi(source) {
1363
+ return import("./_chunks/source_parser.mjs").then((m) => m.parseSource(source));
1364
+ }
1365
+ async function cmdAddProfile(name, source, opts) {
1366
+ const { file, profile } = loadProfile(name);
1367
+ const repo = source || (profile.artifacts.skills[0]?.source ?? profile.artifacts.rules[0]?.source);
1368
+ if (!repo) throw new Error(`No source given and ${file} lists none. Try: agentry add profile ${name} author/repo`);
1369
+ const agentList = await resolveAgentList(opts);
1370
+ const { root, cleanup } = resolveSource(repo);
1371
+ try {
1372
+ const artifacts = [];
1373
+ const plural = (k) => k === "skill" ? "skills" : k === "rule" ? "rules" : k === "script" ? "scripts" : "agents";
1374
+ for (const k of ARTIFACT_KINDS) {
1375
+ if (k === "profile") continue;
1376
+ const refs = profile.artifacts[plural(k)] ?? [];
1377
+ for (const ref of refs) {
1378
+ const src = ref.source ? resolveSource(ref.source) : {
1379
+ root,
1380
+ cleanup: () => {}
1381
+ };
1382
+ artifacts.push(...select(src.root, k, ref.id));
1383
+ if (ref.source) src.cleanup();
1384
+ }
1385
+ }
1386
+ if (opts.dryRun) {
1387
+ preview(artifacts, agentList);
1388
+ return;
1389
+ }
1390
+ installAll(artifacts, opts, agentList, repo);
1391
+ } finally {
1392
+ cleanup();
1393
+ }
1394
+ }
1395
+ async function resolveAgentList(opts) {
1396
+ if (opts.all) return listAgents();
1397
+ if (opts.agents.length) {
1398
+ const { agents, unknown } = resolveAgents(opts.agents);
1399
+ if (unknown.length) throw new Error(`Unknown agent(s): ${unknown.join(", ")}. See --help for supported agents.`);
1400
+ return agents;
1401
+ }
1402
+ const detected = detectInstalledAgents().map((a) => a.name);
1403
+ const universal = getUniversalAgents();
1404
+ const visibleUniversal = getVisibleUniversalAgents();
1405
+ const others = getNonUniversalAgents();
1406
+ const detectedOthers = detected.filter((n) => others.some((o) => o.name === n));
1407
+ if (isQuiet() || opts.yes) {
1408
+ const picked = detectedOthers.length ? detectedOthers : ["cursor"];
1409
+ return [...universal, ...others.filter((o) => picked.includes(o.name))];
1410
+ }
1411
+ const selected = await selectAgents("Which agents do you want to install to?", visibleUniversal, others, detectedOthers);
1412
+ if (isCancelLike(selected)) throw new Error("Cancelled.");
1413
+ return selected;
1414
+ }
1415
+ function installAll(artifacts, opts, agentList, source) {
1416
+ if (!artifacts.length) {
1417
+ warn("Nothing matched - nothing installed.");
1418
+ return;
1419
+ }
1420
+ const where = opts.scope === "global" ? "global (~)" : `project (${opts.dir || process.cwd()})`;
1421
+ for (const a of artifacts) installOne(a, toInstallOpts(opts), agentList, source);
1422
+ installSummary(artifacts, agentList, where);
1423
+ }
1424
+ function toInstallOpts(opts) {
1425
+ return {
1426
+ scope: opts.scope,
1427
+ dir: opts.dir,
1428
+ agents: opts.agents,
1429
+ copy: opts.copy,
1430
+ dryRun: opts.dryRun
1431
+ };
1432
+ }
1433
+ async function cmdRemove(kind, selector, opts) {
1434
+ const agentList = await resolveAgentList(opts);
1435
+ const installOpts = toInstallOpts(opts);
1436
+ const scope = [kind, selector].filter(Boolean).join("/");
1437
+ if (kind === "all") {
1438
+ let count = 0;
1439
+ for (const t of ARTIFACT_KINDS) count += removeSelection(t, void 0, installOpts, agentList).removedKeys.length;
1440
+ ok(`Removed ${count} item(s).`);
1441
+ return;
1442
+ }
1443
+ const r = removeSelection(kind, selector, installOpts, agentList);
1444
+ if (!r.existed) {
1445
+ warn(`Nothing installed at "${scope}".`);
1446
+ return;
1447
+ }
1448
+ for (const k of r.removedKeys) step(`removed ${k}`);
1449
+ ok(`Removed ${r.removedKeys.length} item(s).`);
1450
+ }
1451
+ function cmdList(source, kind) {
1452
+ if (!source) throw new Error("Missing source. e.g. agentry list author/repo");
1453
+ const { root, cleanup } = resolveSource(source);
1454
+ try {
1455
+ for (const k of kind ? [kind] : ARTIFACT_KINDS) {
1456
+ log(theme.info(`${k}s:`));
1457
+ const items = listKind(root, k);
1458
+ if (!items.length) {
1459
+ step("(none)");
1460
+ continue;
1461
+ }
1462
+ for (const it of items) {
1463
+ const desc = (it.description || "").replace(/\s+/g, " ").slice(0, 80);
1464
+ step(`${it.id}${desc ? " - " + desc : ""}`);
1465
+ }
1466
+ }
1467
+ } finally {
1468
+ cleanup();
1469
+ }
1470
+ }
1471
+ function cmdListInstalled(opts) {
1472
+ const installed = listInstalled(toInstallOpts(opts));
1473
+ if (!installed.length) {
1474
+ info("Nothing installed.");
1475
+ return;
1476
+ }
1477
+ for (const it of installed) step(`${it.id} -> ${it.agents.join(", ")}`);
1478
+ }
1479
+ async function cmdUpdateAssets(kind, source, selector, opts) {
1480
+ const installOpts = toInstallOpts(opts);
1481
+ const agentList = await resolveAgentList(opts);
1482
+ if (source) {
1483
+ const { root, cleanup } = resolveSource(source);
1484
+ try {
1485
+ const artifacts = kind === "all" ? listAll(root) : select(root, kind, selector);
1486
+ if (!artifacts.length) {
1487
+ warn(`Nothing found in ${source}.`);
1488
+ return;
1489
+ }
1490
+ installAll(artifacts, opts, agentList, source);
1491
+ } finally {
1492
+ cleanup();
1493
+ }
1494
+ return;
1495
+ }
1496
+ const installed = listInstalled(installOpts).filter((it) => kind === "all" || it.id.startsWith(kind + "/"));
1497
+ if (!installed.length) {
1498
+ warn(`No installed ${kind} recorded in lockfile. Provide a source.`);
1499
+ return;
1500
+ }
1501
+ const bySource = /* @__PURE__ */ new Map();
1502
+ for (const it of installed) if (it.source) {
1503
+ const arr = bySource.get(it.source) || [];
1504
+ arr.push(it.id);
1505
+ bySource.set(it.source, arr);
1506
+ }
1507
+ if (!bySource.size) {
1508
+ warn(`Installed ${kind} artifacts have no recorded source. Provide a source.`);
1509
+ return;
1510
+ }
1511
+ for (const [s, ids] of bySource) {
1512
+ const { root, cleanup } = resolveSource(s);
1513
+ try {
1514
+ installAll(ids.map((id) => select(root, id.split("/")[0], id.split("/").slice(1).join("/") || void 0)).flat(), opts, agentList, s);
1515
+ } finally {
1516
+ cleanup();
1517
+ }
1518
+ }
1519
+ }
1520
+ function parseArgs(argv) {
1521
+ const opts = {
1522
+ scope: "project",
1523
+ agents: [],
1524
+ copy: false,
1525
+ dryRun: false,
1526
+ yes: false,
1527
+ all: false
1528
+ };
1529
+ const positional = [];
1530
+ const flags = {};
1531
+ for (let i = 0; i < argv.length; i++) {
1532
+ const a = argv[i];
1533
+ if (a === "-g" || a === "--global") {
1534
+ opts.scope = "global";
1535
+ flags.global = true;
1536
+ } else if (a === "--project") {
1537
+ opts.scope = "project";
1538
+ flags.project = true;
1539
+ } else if (a === "-y" || a === "--yes") {
1540
+ opts.yes = true;
1541
+ flags.yes = true;
1542
+ } else if (a === "--dir") {
1543
+ opts.dir = argv[++i];
1544
+ flags.dir = opts.dir;
1545
+ } else if (a === "-a" || a === "--agent") {
1546
+ opts.agents.push(argv[++i]);
1547
+ flags.agent = true;
1548
+ } else if (a === "-l" || a === "--list") {
1549
+ opts.dryRun = true;
1550
+ flags.list = true;
1551
+ } else if (a === "--copy") {
1552
+ opts.copy = true;
1553
+ flags.copy = true;
1554
+ } else if (a === "--all") {
1555
+ opts.all = true;
1556
+ flags.all = true;
1557
+ } else if (a === "-v" || a === "--version") flags.version = true;
1558
+ else if (a === "-h" || a === "--help") flags.help = true;
1559
+ else positional.push(a);
1560
+ }
1561
+ return {
1562
+ opts,
1563
+ positional,
1564
+ flags
1565
+ };
1566
+ }
1567
+ function fetchJson(url) {
1568
+ return new Promise((resolve, reject) => {
1569
+ https.get(url, (res) => {
1570
+ let body = "";
1571
+ res.on("data", (c) => body += c);
1572
+ res.on("end", () => {
1573
+ try {
1574
+ resolve(JSON.parse(body));
1575
+ } catch (e) {
1576
+ reject(e);
1577
+ }
1578
+ });
1579
+ }).on("error", reject);
1580
+ });
1581
+ }
1582
+ async function runUpdateSelf() {
1583
+ log(theme.info("Checking agentry version..."));
1584
+ let latest;
1585
+ try {
1586
+ latest = (await fetchJson(`https://registry.npmjs.org/${encodeURIComponent(name)}/latest`))?.version;
1587
+ } catch {
1588
+ warn("Could not reach npm registry; running self-update anyway.");
1589
+ runNpmInstall(`${name}@latest`);
1590
+ return;
1591
+ }
1592
+ if (latest && latest === version) {
1593
+ ok(`Already up to date (v${version}).`);
1594
+ return;
1595
+ }
1596
+ log(`Current v${version} -> latest ${latest || "unknown"}`);
1597
+ runNpmInstall(`${name}@latest`);
1598
+ }
1599
+ function runNpmInstall(spec) {
1600
+ spinner(`Updating agentry CLI`, () => {
1601
+ try {
1602
+ execSync(`npm install -g ${spec}`, { stdio: "inherit" });
1603
+ } catch {
1604
+ err("Update failed. Once published, run: npm install -g " + spec);
1605
+ process.exit(1);
1606
+ }
1607
+ });
1608
+ }
1609
+ function runUninstall() {
1610
+ spinner("Uninstalling agentry CLI", () => {
1611
+ try {
1612
+ execSync(`npm uninstall -g ${name}`, { stdio: "inherit" });
1613
+ } catch {
1614
+ err("Uninstall failed. Try: npm uninstall -g " + name);
1615
+ process.exit(1);
1616
+ }
1617
+ });
1618
+ }
1619
+ function isKind(s) {
1620
+ return ARTIFACT_KINDS.includes(s);
1621
+ }
1622
+ function normalizeKind(s) {
1623
+ return s.endsWith("s") ? s.slice(0, -1) : s;
1624
+ }
1625
+ async function main() {
1626
+ const { opts, positional, flags } = parseArgs(process.argv.slice(2));
1627
+ if (flags.version) {
1628
+ log(version);
1629
+ return;
1630
+ }
1631
+ if (flags.help || positional.length === 0) {
1632
+ if (!isQuiet()) await animateLogo();
1633
+ printHelp();
1634
+ return;
1635
+ }
1636
+ const [action] = positional;
1637
+ if (!isQuiet()) await animateLogo();
1638
+ if (action === "uninstall") {
1639
+ runUninstall();
1640
+ return;
1641
+ }
1642
+ if (action === "update") {
1643
+ if (positional.length === 1) {
1644
+ await runUpdateSelf();
1645
+ return;
1646
+ }
1647
+ const kind = normalizeKind(positional[1]);
1648
+ if (kind !== "all" && !isKind(kind)) throw new Error(`Unknown kind: ${kind}`);
1649
+ await cmdUpdateAssets(kind, positional[2], positional[3], opts);
1650
+ return;
1651
+ }
1652
+ if (action === "list") {
1653
+ if (positional.length === 1) {
1654
+ cmdListInstalled(opts);
1655
+ return;
1656
+ }
1657
+ const k = positional[2] ? normalizeKind(positional[2]) : void 0;
1658
+ cmdList(positional[1], k && isKind(k) ? k : void 0);
1659
+ return;
1660
+ }
1661
+ if (action === "add") {
1662
+ const kind = positional[1] ? normalizeKind(positional[1]) : void 0;
1663
+ if (!kind) throw new Error("Missing kind. e.g. agentry add skills author/repo");
1664
+ if (kind === "profile") {
1665
+ await cmdAddProfile(positional[2], positional[3], opts);
1666
+ return;
1667
+ }
1668
+ if (kind !== "all" && !isKind(kind)) throw new Error(`Unknown kind: ${kind}`);
1669
+ await cmdAdd(kind, positional[2], positional[3], opts);
1670
+ return;
1671
+ }
1672
+ if (action === "remove" || action === "rm") {
1673
+ const kind = positional[1] ? normalizeKind(positional[1]) : void 0;
1674
+ if (!kind) throw new Error("Missing kind. e.g. agentry remove skills enhance-prompt");
1675
+ if (kind !== "all" && !isKind(kind)) throw new Error(`Unknown kind: ${kind}`);
1676
+ await cmdRemove(kind, positional[2], opts);
1677
+ return;
1678
+ }
1679
+ err(`Unknown action: ${action}`);
1680
+ printHelp();
1681
+ process.exit(1);
1682
+ }
1683
+ main().catch((e) => {
1684
+ err(e.message || String(e));
1685
+ process.exit(1);
1686
+ });
1687
+ export {};