@callmeradical/augy 0.2.0 → 0.4.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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  listSkills,
3
3
  readRegistry
4
- } from "./chunk-ZW6ZKHTF.js";
4
+ } from "./chunk-JM4VVAHN.js";
5
5
 
6
6
  // src/commands/bundle.ts
7
7
  import { outro, spinner } from "@clack/prompts";
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  discoverSkills,
3
3
  parseGitHubUrl
4
- } from "./chunk-EU54UQ4C.js";
4
+ } from "./chunk-2E5SVRSR.js";
5
5
  import {
6
6
  listTaps,
7
7
  tapKey
8
- } from "./chunk-ZW6ZKHTF.js";
8
+ } from "./chunk-JM4VVAHN.js";
9
9
 
10
10
  // src/taps.ts
11
11
  async function searchTaps(registry, query) {
@@ -112,6 +112,12 @@ function addTap(registry, tap) {
112
112
  function removeTap(registry, key) {
113
113
  delete registry.taps[key];
114
114
  }
115
+ function getHomeConfig(registry) {
116
+ return registry.home;
117
+ }
118
+ function setHomeConfig(registry, config) {
119
+ registry.home = config;
120
+ }
115
121
 
116
122
  export {
117
123
  __commonJS,
@@ -132,5 +138,7 @@ export {
132
138
  getTap,
133
139
  listTaps,
134
140
  addTap,
135
- removeTap
141
+ removeTap,
142
+ getHomeConfig,
143
+ setHomeConfig
136
144
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  __commonJS,
3
3
  __toESM
4
- } from "./chunk-ZW6ZKHTF.js";
4
+ } from "./chunk-JM4VVAHN.js";
5
5
 
6
6
  // node_modules/sisteransi/src/index.js
7
7
  var require_src = __commonJS({
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  versionArchivePath
3
- } from "./chunk-ZW6ZKHTF.js";
3
+ } from "./chunk-JM4VVAHN.js";
4
4
 
5
5
  // src/versions.ts
6
6
  import { cp, mkdir, rm } from "fs/promises";
@@ -32,7 +32,7 @@ Archive path: ${src}`
32
32
  }
33
33
  async function pruneVersions(skillName, keepShas = []) {
34
34
  const { join } = await import("path");
35
- const { versionArchivePath: archivePath, versionsDir } = await import("./registry-QVCNZXBZ.js");
35
+ const { versionArchivePath: archivePath, versionsDir } = await import("./registry-2B52E3ME.js");
36
36
  const skillVersionsDir = join(versionsDir(), skillName);
37
37
  if (!existsSync(skillVersionsDir)) return;
38
38
  const { readdir } = await import("fs/promises");
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  discoverSkills,
3
3
  parseGitHubUrl
4
- } from "./chunk-EU54UQ4C.js";
4
+ } from "./chunk-2E5SVRSR.js";
5
5
  import {
6
6
  archiveExists
7
- } from "./chunk-PX2LVUHV.js";
7
+ } from "./chunk-Z4R7NYGP.js";
8
8
  import {
9
9
  getSkill,
10
10
  readRegistry,
11
11
  shortSha,
12
12
  versionArchivePath
13
- } from "./chunk-ZW6ZKHTF.js";
13
+ } from "./chunk-JM4VVAHN.js";
14
14
 
15
15
  // src/commands/diff.ts
16
16
  import { cancel, intro, isCancel, outro, select, spinner } from "@clack/prompts";
@@ -0,0 +1,205 @@
1
+ import {
2
+ AGENTS,
3
+ agentSkillPath,
4
+ detectInstalledAgents
5
+ } from "./chunk-V5GA2ZHU.js";
6
+ import {
7
+ createSkillRecord,
8
+ getHomeConfig,
9
+ listSkills,
10
+ readRegistry,
11
+ setHomeConfig,
12
+ upsertSkill,
13
+ writeRegistry
14
+ } from "./chunk-JM4VVAHN.js";
15
+
16
+ // src/commands/home.ts
17
+ import { intro, outro, spinner } from "@clack/prompts";
18
+ import chalk from "chalk";
19
+ import { cp, mkdir, readdir, writeFile } from "fs/promises";
20
+ import { existsSync } from "fs";
21
+ import { join } from "path";
22
+ import { tmpdir } from "os";
23
+
24
+ // src/git.ts
25
+ import { execFile } from "child_process";
26
+ function run(cmd, args) {
27
+ return new Promise((resolve, reject) => {
28
+ execFile(cmd, args, (err) => {
29
+ if (err) reject(err);
30
+ else resolve();
31
+ });
32
+ });
33
+ }
34
+ function repoToUrl(ownerRepoOrUrl) {
35
+ if (ownerRepoOrUrl.startsWith("https://") || ownerRepoOrUrl.startsWith("git@")) {
36
+ return ownerRepoOrUrl;
37
+ }
38
+ return `https://github.com/${ownerRepoOrUrl}.git`;
39
+ }
40
+ async function cloneRepo(url, destDir) {
41
+ await run("git", ["clone", "--depth=1", url, destDir]);
42
+ }
43
+ async function gitAddAll(dir) {
44
+ await run("git", ["-C", dir, "add", "-A"]);
45
+ }
46
+ async function gitCommit(dir, message) {
47
+ await run("git", ["-C", dir, "commit", "-m", message]);
48
+ }
49
+ async function gitPush(dir) {
50
+ await run("git", ["-C", dir, "push"]);
51
+ }
52
+
53
+ // src/commands/home.ts
54
+ var DEFAULT_PATH = "augy.json";
55
+ var DEFAULT_SKILLS_DIR = "skills";
56
+ async function homeSetCommand(repo, opts = {}) {
57
+ const parts = repo.split("/");
58
+ if (parts.length !== 2 || !parts[0] || !parts[1]) {
59
+ throw new Error(`Invalid repo "${repo}" \u2014 expected owner/repo format (e.g. alice/my-skills)`);
60
+ }
61
+ const path = opts.path ?? DEFAULT_PATH;
62
+ const skillsPath = opts.skillsPath ?? DEFAULT_SKILLS_DIR;
63
+ const registry = await readRegistry();
64
+ setHomeConfig(registry, { repo, path, skillsPath });
65
+ await writeRegistry(registry);
66
+ outro(
67
+ `${chalk.green("\u2713")} Home repo set to ${chalk.cyan(repo)}
68
+ ` + chalk.dim(` manifest : ${path}
69
+ `) + chalk.dim(` skills : ${skillsPath}/`)
70
+ );
71
+ }
72
+ async function homeShowCommand() {
73
+ const registry = await readRegistry();
74
+ const home = getHomeConfig(registry);
75
+ if (!home) {
76
+ console.log(chalk.dim("No home repo configured. Run `augy home set <owner/repo>` to set one."));
77
+ return;
78
+ }
79
+ console.log(`${chalk.bold("Home repo")} ${chalk.cyan(home.repo)}`);
80
+ console.log(`${chalk.dim("manifest ")} ${home.path}`);
81
+ console.log(`${chalk.dim("skills ")} ${home.skillsPath}/`);
82
+ }
83
+ async function homePushCommand() {
84
+ intro(chalk.bold("augy") + chalk.dim(" \u2014 home push"));
85
+ const registry = await readRegistry();
86
+ const home = getHomeConfig(registry);
87
+ if (!home) {
88
+ console.error(
89
+ chalk.red("No home repo configured.") + "\nRun `augy home set <owner/repo>` first."
90
+ );
91
+ process.exit(1);
92
+ }
93
+ const allSkills = listSkills(registry);
94
+ const authored = allSkills.filter((s3) => !s3.source);
95
+ const external = allSkills.filter((s3) => s3.source);
96
+ const cloneDir = join(tmpdir(), `augy-home-push-${Date.now()}`);
97
+ const s = spinner();
98
+ s.start(`Cloning ${chalk.cyan(home.repo)}\u2026`);
99
+ await cloneRepo(repoToUrl(home.repo), cloneDir);
100
+ s.stop(`${chalk.green("\u2713")} Cloned`);
101
+ const homeRepo = home.repo;
102
+ for (const skill of authored) {
103
+ const sourcePath = Object.values(skill.agents).find((a) => a.active && existsSync(a.path))?.path;
104
+ if (!sourcePath) continue;
105
+ const destPath = home.skillsPath ? join(cloneDir, home.skillsPath, skill.name) : join(cloneDir, skill.name);
106
+ await mkdir(destPath, { recursive: true });
107
+ await cp(sourcePath, destPath, { recursive: true, force: true });
108
+ const newSource = `https://github.com/${homeRepo}/tree/main/${home.skillsPath ? home.skillsPath + "/" : ""}${skill.name}`;
109
+ skill.source = newSource;
110
+ upsertSkill(registry, skill);
111
+ }
112
+ const bundle = { version: 1, skills: {} };
113
+ for (const skill of allSkills) {
114
+ bundle.skills[skill.name] = skill.source;
115
+ }
116
+ await writeFile(
117
+ join(cloneDir, home.path),
118
+ JSON.stringify(bundle, null, 2) + "\n",
119
+ "utf8"
120
+ );
121
+ const s2 = spinner();
122
+ s2.start("Committing and pushing\u2026");
123
+ await gitAddAll(cloneDir);
124
+ const skillCount = allSkills.length;
125
+ const authoredNote = authored.length ? ` (${authored.length} authored)` : "";
126
+ await gitCommit(cloneDir, `chore: update skills via augy \u2014 ${skillCount} skill(s)${authoredNote}`);
127
+ await gitPush(cloneDir);
128
+ s2.stop(`${chalk.green("\u2713")} Pushed`);
129
+ if (authored.length) await writeRegistry(registry);
130
+ outro(
131
+ `${chalk.bold(String(skillCount))} skill(s) saved to ${chalk.cyan(home.repo)}
132
+ ` + (authored.length ? chalk.dim(` ${authored.length} authored skill(s) committed + source registered
133
+ `) : "") + chalk.dim(` Run \`augy home pull\` on a new machine to restore.`)
134
+ );
135
+ }
136
+ async function homePullCommand(opts = {}) {
137
+ intro(chalk.bold("augy") + chalk.dim(" \u2014 home pull"));
138
+ const registry = await readRegistry();
139
+ const home = getHomeConfig(registry);
140
+ if (!home) {
141
+ console.error(
142
+ chalk.red("No home repo configured.") + "\nRun `augy home set <owner/repo>` first."
143
+ );
144
+ process.exit(1);
145
+ }
146
+ const cloneDir = join(tmpdir(), `augy-home-pull-${Date.now()}`);
147
+ const s = spinner();
148
+ s.start(`Cloning ${chalk.cyan(home.repo)}\u2026`);
149
+ await cloneRepo(repoToUrl(home.repo), cloneDir);
150
+ s.stop(`${chalk.green("\u2713")} Cloned`);
151
+ const targetAgents = opts.agent?.length ? AGENTS.filter((a) => opts.agent.includes(a.id)) : detectInstalledAgents();
152
+ if (!targetAgents.length) {
153
+ console.error(chalk.red("No agents detected. Install an agent or use --agent to specify one."));
154
+ process.exit(1);
155
+ }
156
+ const skillsDir = home.skillsPath ? join(cloneDir, home.skillsPath) : cloneDir;
157
+ const authoredInstalled = [];
158
+ if (existsSync(skillsDir)) {
159
+ const entries = await readdir(skillsDir, { withFileTypes: true });
160
+ const skillDirs = entries.filter((e) => e.isDirectory());
161
+ for (const dir of skillDirs) {
162
+ const skillName = dir.name;
163
+ const srcPath = join(skillsDir, skillName);
164
+ const source = `https://github.com/${home.repo}/tree/main/${home.skillsPath ? home.skillsPath + "/" : ""}${skillName}`;
165
+ if (opts.dryRun) {
166
+ console.log(` ${chalk.cyan("+")} ${skillName} ${chalk.dim("(authored)")}`);
167
+ continue;
168
+ }
169
+ const agentPaths = {};
170
+ for (const agent of targetAgents) {
171
+ const dest = agentSkillPath(agent, skillName);
172
+ await mkdir(dest, { recursive: true });
173
+ await cp(srcPath, dest, { recursive: true, force: true });
174
+ agentPaths[agent.id] = dest;
175
+ }
176
+ const record = createSkillRecord({
177
+ name: skillName,
178
+ source,
179
+ gigetSource: "",
180
+ sha: "home",
181
+ agentIds: targetAgents.map((a) => a.id),
182
+ agentPaths
183
+ });
184
+ upsertSkill(registry, record);
185
+ authoredInstalled.push(skillName);
186
+ }
187
+ }
188
+ const manifestPath = join(cloneDir, home.path);
189
+ if (existsSync(manifestPath)) {
190
+ const { syncCommand } = await import("./sync-QQFXUXCN.js");
191
+ await syncCommand(manifestPath, opts);
192
+ }
193
+ if (!opts.dryRun && authoredInstalled.length) {
194
+ await writeRegistry(registry);
195
+ }
196
+ if (opts.dryRun) {
197
+ outro(chalk.dim("Dry run \u2014 no changes made."));
198
+ }
199
+ }
200
+ export {
201
+ homePullCommand,
202
+ homePushCommand,
203
+ homeSetCommand,
204
+ homeShowCommand
205
+ };
package/dist/index.js CHANGED
@@ -10,66 +10,66 @@ var pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf8")
10
10
  var program = new Command();
11
11
  program.name("augy").description("Homebrew for AI agent skills \u2014 install, version, update, rollback").version(pkg.version);
12
12
  program.command("install [url]").description("Install skills from a GitHub URL or owner/repo[/path]").option("-a, --agent <agents...>", "Target agent(s): opencode, claude, codex").action(async (url, opts) => {
13
- const { installCommand } = await import("./install-WXJUM6CM.js");
13
+ const { installCommand } = await import("./install-7ZWHGCFN.js");
14
14
  await installCommand(url, opts ?? {});
15
15
  });
16
16
  program.command("update [skill]").description("Check for upstream changes and upgrade installed skills").action(async (skill) => {
17
- const { updateCommand } = await import("./update-NIBPLLHU.js");
17
+ const { updateCommand } = await import("./update-VEXE6ZKZ.js");
18
18
  await updateCommand(skill);
19
19
  });
20
20
  program.command("list").description("Show all installed skills with version + agent info").option("--json", "Output raw JSON registry").action(async (opts) => {
21
- const { listCommand } = await import("./list-ZTG6RVGD.js");
21
+ const { listCommand } = await import("./list-FTEIYHCK.js");
22
22
  await listCommand(opts ?? {});
23
23
  });
24
24
  program.command("diff <skill> [sha1] [sha2]").description(
25
25
  "Browse file-level diffs for a skill\n augy diff <skill> installed \u2194 upstream HEAD\n augy diff <skill> <sha> installed \u2194 specific SHA (archive or GitHub)\n augy diff <skill> <sha1> <sha2> two local archives side-by-side"
26
26
  ).action(async (skill, sha1, sha2) => {
27
- const { diffCommand } = await import("./diff-VQU63ORX.js");
27
+ const { diffCommand } = await import("./diff-JQ5L3GEO.js");
28
28
  await diffCommand(skill, sha1, sha2);
29
29
  });
30
30
  program.command("bundle").description("Write an augy.json manifest from installed skills for team sharing").option("-o, --output <path>", "Output path (default: ./augy.json)").option("--include-untracked", "Include skills without a known source").action(async (opts) => {
31
- const { bundleCommand } = await import("./bundle-76RCX45C.js");
31
+ const { bundleCommand } = await import("./bundle-L4LMJLKN.js");
32
32
  await bundleCommand(opts);
33
33
  });
34
34
  program.command("sync [path]").description("Install/update skills from an augy.json manifest (default: ./augy.json)").option("--dry-run", "Preview changes without applying them").option("-a, --agent <agents...>", "Target agent(s) (default: all detected)").action(async (path, opts) => {
35
- const { syncCommand } = await import("./sync-VPBC2PBH.js");
35
+ const { syncCommand } = await import("./sync-QQFXUXCN.js");
36
36
  await syncCommand(path, opts ?? {});
37
37
  });
38
38
  program.command("scan").description("Find skills installed outside augy and optionally import them into the registry").action(async () => {
39
- const { scanCommand } = await import("./scan-MWUT7G4V.js");
39
+ const { scanCommand } = await import("./scan-4KFMTKHO.js");
40
40
  await scanCommand();
41
41
  });
42
42
  program.command("info <skill>").description("Show full metadata, version history, and description for an installed skill").action(async (skill) => {
43
- const { infoCommand } = await import("./info-JKGYNOPV.js");
43
+ const { infoCommand } = await import("./info-2AD4VEXX.js");
44
44
  await infoCommand(skill);
45
45
  });
46
46
  program.command("search [query]").description("Search all taps for available skills (optionally filter by name)").action(async (query) => {
47
- const { searchCommand } = await import("./search-2V2U23KC.js");
47
+ const { searchCommand } = await import("./search-Y3ID5H4Z.js");
48
48
  await searchCommand(query);
49
49
  });
50
50
  var tap = program.command("tap").description("Manage trusted repos (taps) for skill name resolution");
51
51
  tap.command("add <repo>").description("Register a tap e.g. augy tap add owner/repo").option("--path <skills-dir>", "Subdirectory where skills live (default: skills)").option("--description <text>", "Optional description").action(async (repo, opts) => {
52
- const { tapAddCommand } = await import("./tap-3RD3XZ56.js");
52
+ const { tapAddCommand } = await import("./tap-OWJLWLKR.js");
53
53
  await tapAddCommand(repo, opts);
54
54
  });
55
55
  tap.command("remove <repo>").description("Unregister a tap").action(async (repo) => {
56
- const { tapRemoveCommand } = await import("./tap-3RD3XZ56.js");
56
+ const { tapRemoveCommand } = await import("./tap-OWJLWLKR.js");
57
57
  await tapRemoveCommand(repo);
58
58
  });
59
59
  tap.command("list").description("List all registered taps").action(async () => {
60
- const { tapListCommand } = await import("./tap-3RD3XZ56.js");
60
+ const { tapListCommand } = await import("./tap-OWJLWLKR.js");
61
61
  await tapListCommand();
62
62
  });
63
63
  program.command("set-source <skill> <url>").description("Attach a GitHub source URL to a skill imported without one").action(async (skill, url) => {
64
- const { setSourceCommand } = await import("./set-source-TITL27N3.js");
64
+ const { setSourceCommand } = await import("./set-source-GRYHJOX6.js");
65
65
  await setSourceCommand(skill, url);
66
66
  });
67
67
  program.command("uninstall <skill>").description("Remove a skill from all agent paths and the registry").action(async (skill) => {
68
- const { uninstallCommand } = await import("./uninstall-3C3XZZEC.js");
68
+ const { uninstallCommand } = await import("./uninstall-EYLNWP2L.js");
69
69
  await uninstallCommand(skill);
70
70
  });
71
71
  program.command("rollback <skill> [sha]").description("Restore a skill to a previous archived version").action(async (skill, sha) => {
72
- const { rollbackCommand } = await import("./rollback-QXPWOF3Q.js");
72
+ const { rollbackCommand } = await import("./rollback-NSDZL7WA.js");
73
73
  await rollbackCommand(skill, sha);
74
74
  });
75
75
  program.command("pin <skill>").description("Pin a skill so it is skipped during `augy update`").action(async (skill) => {
@@ -78,14 +78,31 @@ program.command("pin <skill>").description("Pin a skill so it is skipped during
78
78
  program.command("unpin <skill>").description("Allow a pinned skill to receive updates again").action(async (skill) => {
79
79
  await setPinned(skill, false);
80
80
  });
81
+ var home = program.command("home").description("Manage a personal GitHub repo for backing up your skills manifest");
82
+ home.command("set <repo>").description("Set the home repo e.g. augy home set alice/my-skills").option("--path <file>", "Manifest path within the repo (default: augy.json)").option("--skills-path <dir>", "Dir for authored skills in the repo (default: skills)").action(async (repo, opts) => {
83
+ const { homeSetCommand } = await import("./home-TWK3PMCL.js");
84
+ await homeSetCommand(repo, opts);
85
+ });
86
+ home.command("push").description("Push your installed skills manifest to the home repo").action(async () => {
87
+ const { homePushCommand } = await import("./home-TWK3PMCL.js");
88
+ await homePushCommand();
89
+ });
90
+ home.command("pull").description("Fetch the manifest from the home repo and sync skills").option("--dry-run", "Preview changes without applying them").option("-a, --agent <agents...>", "Target agent(s) (default: all detected)").action(async (opts) => {
91
+ const { homePullCommand } = await import("./home-TWK3PMCL.js");
92
+ await homePullCommand(opts);
93
+ });
94
+ home.command("show").description("Show the current home repo configuration").action(async () => {
95
+ const { homeShowCommand } = await import("./home-TWK3PMCL.js");
96
+ await homeShowCommand();
97
+ });
81
98
  program.action(async () => {
82
- const { installCommand } = await import("./install-WXJUM6CM.js");
99
+ const { installCommand } = await import("./install-7ZWHGCFN.js");
83
100
  await installCommand();
84
101
  });
85
102
  program.parse();
86
103
  async function setPinned(skillName, pinned) {
87
104
  const chalk = (await import("chalk")).default;
88
- const { readRegistry, writeRegistry, getSkill } = await import("./registry-QVCNZXBZ.js");
105
+ const { readRegistry, writeRegistry, getSkill } = await import("./registry-2B52E3ME.js");
89
106
  const registry = await readRegistry();
90
107
  const skill = getSkill(registry, skillName);
91
108
  if (!skill) {
@@ -3,12 +3,12 @@ import {
3
3
  } from "./chunk-V5GA2ZHU.js";
4
4
  import {
5
5
  archiveExists
6
- } from "./chunk-PX2LVUHV.js";
6
+ } from "./chunk-Z4R7NYGP.js";
7
7
  import {
8
8
  getSkill,
9
9
  readRegistry,
10
10
  shortSha
11
- } from "./chunk-ZW6ZKHTF.js";
11
+ } from "./chunk-JM4VVAHN.js";
12
12
 
13
13
  // src/commands/info.ts
14
14
  import chalk from "chalk";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  filterableMultiselect
3
- } from "./chunk-UJX6VJ3S.js";
3
+ } from "./chunk-RBF4Q6N4.js";
4
4
  import {
5
5
  resolveSkillFromTaps
6
- } from "./chunk-YXCEZ3EY.js";
6
+ } from "./chunk-HZSFPII7.js";
7
7
  import {
8
8
  AGENTS,
9
9
  agentSkillPath,
@@ -13,14 +13,14 @@ import {
13
13
  discoverSkills,
14
14
  downloadSkill,
15
15
  parseGitHubUrl
16
- } from "./chunk-EU54UQ4C.js";
16
+ } from "./chunk-2E5SVRSR.js";
17
17
  import {
18
18
  createSkillRecord,
19
19
  getSkill,
20
20
  readRegistry,
21
21
  shortSha,
22
22
  writeRegistry
23
- } from "./chunk-ZW6ZKHTF.js";
23
+ } from "./chunk-JM4VVAHN.js";
24
24
 
25
25
  // src/commands/install.ts
26
26
  import {
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  listSkills,
6
6
  readRegistry
7
- } from "./chunk-ZW6ZKHTF.js";
7
+ } from "./chunk-JM4VVAHN.js";
8
8
 
9
9
  // src/commands/list.ts
10
10
  import chalk from "chalk";
@@ -2,6 +2,7 @@ import {
2
2
  addTap,
3
3
  augyHome,
4
4
  createSkillRecord,
5
+ getHomeConfig,
5
6
  getSkill,
6
7
  getTap,
7
8
  listSkills,
@@ -10,17 +11,19 @@ import {
10
11
  registryPath,
11
12
  removeSkill,
12
13
  removeTap,
14
+ setHomeConfig,
13
15
  shortSha,
14
16
  tapKey,
15
17
  upsertSkill,
16
18
  versionArchivePath,
17
19
  versionsDir,
18
20
  writeRegistry
19
- } from "./chunk-ZW6ZKHTF.js";
21
+ } from "./chunk-JM4VVAHN.js";
20
22
  export {
21
23
  addTap,
22
24
  augyHome,
23
25
  createSkillRecord,
26
+ getHomeConfig,
24
27
  getSkill,
25
28
  getTap,
26
29
  listSkills,
@@ -29,6 +32,7 @@ export {
29
32
  registryPath,
30
33
  removeSkill,
31
34
  removeTap,
35
+ setHomeConfig,
32
36
  shortSha,
33
37
  tapKey,
34
38
  upsertSkill,
@@ -5,13 +5,13 @@ import {
5
5
  import {
6
6
  archiveExists,
7
7
  restoreVersion
8
- } from "./chunk-PX2LVUHV.js";
8
+ } from "./chunk-Z4R7NYGP.js";
9
9
  import {
10
10
  getSkill,
11
11
  readRegistry,
12
12
  shortSha,
13
13
  writeRegistry
14
- } from "./chunk-ZW6ZKHTF.js";
14
+ } from "./chunk-JM4VVAHN.js";
15
15
 
16
16
  // src/commands/rollback.ts
17
17
  import { cancel, intro, isCancel, outro, select, spinner } from "@clack/prompts";
@@ -74,7 +74,7 @@ The snapshot may have been pruned.`
74
74
  try {
75
75
  const currentDest = destPaths[0];
76
76
  if (currentDest) {
77
- const { archiveVersion } = await import("./versions-OMI6OFJC.js");
77
+ const { archiveVersion } = await import("./versions-BGGRVKJ2.js");
78
78
  await archiveVersion(currentDest, nameArg, skill.sha);
79
79
  }
80
80
  await restoreVersion(nameArg, targetSha, destPaths);
@@ -4,17 +4,17 @@ import {
4
4
  } from "./chunk-KCQY4IDO.js";
5
5
  import {
6
6
  filterableMultiselect
7
- } from "./chunk-UJX6VJ3S.js";
7
+ } from "./chunk-RBF4Q6N4.js";
8
8
  import {
9
9
  resolveSkillFromTaps
10
- } from "./chunk-YXCEZ3EY.js";
10
+ } from "./chunk-HZSFPII7.js";
11
11
  import {
12
12
  AGENTS
13
13
  } from "./chunk-V5GA2ZHU.js";
14
14
  import {
15
15
  discoverSkills,
16
16
  parseGitHubUrl
17
- } from "./chunk-EU54UQ4C.js";
17
+ } from "./chunk-2E5SVRSR.js";
18
18
  import {
19
19
  createSkillRecord,
20
20
  getSkill,
@@ -22,7 +22,7 @@ import {
22
22
  readRegistry,
23
23
  shortSha,
24
24
  writeRegistry
25
- } from "./chunk-ZW6ZKHTF.js";
25
+ } from "./chunk-JM4VVAHN.js";
26
26
 
27
27
  // src/commands/scan.ts
28
28
  import { readdir, readFile } from "fs/promises";
@@ -52,6 +52,7 @@ async function scanCommand() {
52
52
  untracked.push({ name, agents });
53
53
  }
54
54
  }
55
+ const additionalInstalls = findAdditionalAgentInstalls(onDisk, registry);
55
56
  const tracked = listSkills(registry);
56
57
  if (!untracked.length) {
57
58
  outro(chalk.green("All installed skills are already tracked by augy."));
@@ -224,6 +225,36 @@ async function scanCommand() {
224
225
  outro(
225
226
  importedCount > 0 ? chalk.green(`${importedCount} skill(s) imported into augy`) : chalk.dim("No skills imported.")
226
227
  );
228
+ if (additionalInstalls.length) {
229
+ console.log(
230
+ `
231
+ ${chalk.bold("Additional installs found")}` + chalk.dim(` (${additionalInstalls.length} skill(s) installed in new agent(s))`) + "\n"
232
+ );
233
+ for (const { skillName, newAgents } of additionalInstalls) {
234
+ console.log(` ${chalk.cyan.bold(skillName)}`);
235
+ for (const { agent, path } of newAgents) {
236
+ console.log(` ${chalk.bold(agent.name.padEnd(10))} ${chalk.dim(tildefy(path))}`);
237
+ }
238
+ }
239
+ console.log();
240
+ const doRegister = await confirm({
241
+ message: "Register these additional agent paths in the registry?"
242
+ });
243
+ if (!isCancel(doRegister) && doRegister) {
244
+ let registered = 0;
245
+ for (const { skillName, newAgents } of additionalInstalls) {
246
+ const skill = getSkill(registry, skillName);
247
+ for (const { agent, path } of newAgents) {
248
+ skill.agents[agent.id] = { path, active: true };
249
+ registered++;
250
+ }
251
+ registry.skills[skillName] = skill;
252
+ await writeRegistry(registry);
253
+ }
254
+ console.log(chalk.green(`
255
+ \u2713 Registered ${registered} additional path(s)`));
256
+ }
257
+ }
227
258
  }
228
259
  function printDetected(sk) {
229
260
  const p = sk.provenance;
@@ -309,6 +340,18 @@ async function readSkillDescription(skillPath) {
309
340
  }
310
341
  return void 0;
311
342
  }
343
+ function findAdditionalAgentInstalls(onDisk, registry) {
344
+ const result = [];
345
+ for (const [name, agents] of onDisk) {
346
+ const tracked = getSkill(registry, name);
347
+ if (!tracked) continue;
348
+ const newAgents = agents.filter((a) => !tracked.agents[a.agent.id]);
349
+ if (newAgents.length) {
350
+ result.push({ skillName: name, newAgents });
351
+ }
352
+ }
353
+ return result;
354
+ }
312
355
  function tildefy(p) {
313
356
  const home = homedir();
314
357
  return p.startsWith(home) ? "~" + p.slice(home.length) : p;
@@ -324,5 +367,6 @@ async function tryResolveTapSource(registry, name) {
324
367
  }
325
368
  }
326
369
  export {
370
+ findAdditionalAgentInstalls,
327
371
  scanCommand
328
372
  };
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  searchTaps
3
- } from "./chunk-YXCEZ3EY.js";
4
- import "./chunk-EU54UQ4C.js";
3
+ } from "./chunk-HZSFPII7.js";
4
+ import "./chunk-2E5SVRSR.js";
5
5
  import {
6
6
  listSkills,
7
7
  readRegistry,
8
8
  shortSha
9
- } from "./chunk-ZW6ZKHTF.js";
9
+ } from "./chunk-JM4VVAHN.js";
10
10
 
11
11
  // src/commands/search.ts
12
12
  import { spinner } from "@clack/prompts";
@@ -5,13 +5,13 @@ import {
5
5
  buildGigetSource,
6
6
  latestShaForPath,
7
7
  parseGitHubUrl
8
- } from "./chunk-EU54UQ4C.js";
8
+ } from "./chunk-2E5SVRSR.js";
9
9
  import {
10
10
  getSkill,
11
11
  readRegistry,
12
12
  shortSha,
13
13
  writeRegistry
14
- } from "./chunk-ZW6ZKHTF.js";
14
+ } from "./chunk-JM4VVAHN.js";
15
15
 
16
16
  // src/commands/set-source.ts
17
17
  import { cancel, intro, outro, spinner } from "@clack/prompts";
@@ -8,14 +8,14 @@ import {
8
8
  downloadSkill,
9
9
  latestShaForPath,
10
10
  parseGitHubUrl
11
- } from "./chunk-EU54UQ4C.js";
11
+ } from "./chunk-2E5SVRSR.js";
12
12
  import {
13
13
  createSkillRecord,
14
14
  getSkill,
15
15
  readRegistry,
16
16
  shortSha,
17
17
  writeRegistry
18
- } from "./chunk-ZW6ZKHTF.js";
18
+ } from "./chunk-JM4VVAHN.js";
19
19
 
20
20
  // src/commands/sync.ts
21
21
  import {
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  parseTapArg,
3
3
  tapSource
4
- } from "./chunk-YXCEZ3EY.js";
4
+ } from "./chunk-HZSFPII7.js";
5
5
  import {
6
6
  discoverSkills,
7
7
  parseGitHubUrl
8
- } from "./chunk-EU54UQ4C.js";
8
+ } from "./chunk-2E5SVRSR.js";
9
9
  import {
10
10
  addTap,
11
11
  listTaps,
@@ -13,7 +13,7 @@ import {
13
13
  removeTap,
14
14
  tapKey,
15
15
  writeRegistry
16
- } from "./chunk-ZW6ZKHTF.js";
16
+ } from "./chunk-JM4VVAHN.js";
17
17
 
18
18
  // src/commands/tap.ts
19
19
  import { cancel, confirm, intro, isCancel, outro, spinner, text } from "@clack/prompts";
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  pruneVersions
3
- } from "./chunk-PX2LVUHV.js";
3
+ } from "./chunk-Z4R7NYGP.js";
4
4
  import {
5
5
  getSkill,
6
6
  readRegistry,
7
7
  removeSkill,
8
8
  versionsDir,
9
9
  writeRegistry
10
- } from "./chunk-ZW6ZKHTF.js";
10
+ } from "./chunk-JM4VVAHN.js";
11
11
 
12
12
  // src/commands/uninstall.ts
13
13
  import { cancel, confirm, intro, isCancel, outro, spinner } from "@clack/prompts";
@@ -6,16 +6,16 @@ import {
6
6
  discoverSkills,
7
7
  downloadSkill,
8
8
  parseGitHubUrl
9
- } from "./chunk-EU54UQ4C.js";
9
+ } from "./chunk-2E5SVRSR.js";
10
10
  import {
11
11
  archiveVersion
12
- } from "./chunk-PX2LVUHV.js";
12
+ } from "./chunk-Z4R7NYGP.js";
13
13
  import {
14
14
  listSkills,
15
15
  readRegistry,
16
16
  shortSha,
17
17
  writeRegistry
18
- } from "./chunk-ZW6ZKHTF.js";
18
+ } from "./chunk-JM4VVAHN.js";
19
19
 
20
20
  // src/commands/update.ts
21
21
  import { cancel, confirm, intro, isCancel, multiselect, outro, spinner } from "@clack/prompts";
@@ -3,8 +3,8 @@ import {
3
3
  archiveVersion,
4
4
  pruneVersions,
5
5
  restoreVersion
6
- } from "./chunk-PX2LVUHV.js";
7
- import "./chunk-ZW6ZKHTF.js";
6
+ } from "./chunk-Z4R7NYGP.js";
7
+ import "./chunk-JM4VVAHN.js";
8
8
  export {
9
9
  archiveExists,
10
10
  archiveVersion,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@callmeradical/augy",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Homebrew for AI agent skills — install, version, update, rollback",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -35,7 +35,9 @@
35
35
  "build": "tsup src/index.ts --format esm --outDir dist --clean",
36
36
  "dev": "tsx src/index.ts",
37
37
  "typecheck": "tsc --noEmit",
38
- "prepublishOnly": "npm run build"
38
+ "test": "vitest run",
39
+ "test:watch": "vitest",
40
+ "prepublishOnly": "npm run build && npm test"
39
41
  },
40
42
  "dependencies": {
41
43
  "@clack/prompts": "^0.9.0",
@@ -47,9 +49,11 @@
47
49
  "devDependencies": {
48
50
  "@types/diff": "^7.0.2",
49
51
  "@types/node": "^22.0.0",
52
+ "@vitest/coverage-v8": "^4.1.8",
50
53
  "tsup": "^8.3.0",
51
54
  "tsx": "^4.19.0",
52
- "typescript": "^5.7.0"
55
+ "typescript": "^5.7.0",
56
+ "vitest": "^4.1.8"
53
57
  },
54
58
  "engines": {
55
59
  "node": ">=18"
File without changes