@callmeradical/augy 0.1.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/LICENSE +21 -0
- package/README.md +185 -0
- package/dist/chunk-EU54UQ4C.js +144 -0
- package/dist/chunk-KCQY4IDO.js +142 -0
- package/dist/chunk-PX2LVUHV.js +53 -0
- package/dist/chunk-R2TJ3UDO.js +43 -0
- package/dist/chunk-UJX6VJ3S.js +508 -0
- package/dist/chunk-YXCEZ3EY.js +74 -0
- package/dist/chunk-ZW6ZKHTF.js +136 -0
- package/dist/diff-KYSWUXMH.js +303 -0
- package/dist/index.js +92 -0
- package/dist/info-7BO4LXXS.js +119 -0
- package/dist/install-FPAGHWX2.js +192 -0
- package/dist/list-UJX2MYXK.js +70 -0
- package/dist/registry-QVCNZXBZ.js +38 -0
- package/dist/rollback-WAZV5HNG.js +105 -0
- package/dist/scan-DKN7YBT5.js +328 -0
- package/dist/search-2V2U23KC.js +78 -0
- package/dist/set-source-TITL27N3.js +63 -0
- package/dist/tap-3RD3XZ56.js +142 -0
- package/dist/uninstall-3C3XZZEC.js +101 -0
- package/dist/update-A3PSROUK.js +163 -0
- package/dist/versions-OMI6OFJC.js +13 -0
- package/package.json +57 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import {
|
|
2
|
+
pruneVersions
|
|
3
|
+
} from "./chunk-PX2LVUHV.js";
|
|
4
|
+
import {
|
|
5
|
+
getSkill,
|
|
6
|
+
readRegistry,
|
|
7
|
+
removeSkill,
|
|
8
|
+
versionsDir,
|
|
9
|
+
writeRegistry
|
|
10
|
+
} from "./chunk-ZW6ZKHTF.js";
|
|
11
|
+
|
|
12
|
+
// src/commands/uninstall.ts
|
|
13
|
+
import { cancel, confirm, intro, isCancel, outro, spinner } from "@clack/prompts";
|
|
14
|
+
import chalk from "chalk";
|
|
15
|
+
import { rm } from "fs/promises";
|
|
16
|
+
import { existsSync } from "fs";
|
|
17
|
+
import { join } from "path";
|
|
18
|
+
async function uninstallCommand(nameArg) {
|
|
19
|
+
intro(chalk.bold("augy") + chalk.dim(" \u2014 uninstall"));
|
|
20
|
+
const registry = await readRegistry();
|
|
21
|
+
const skill = getSkill(registry, nameArg);
|
|
22
|
+
if (!skill) {
|
|
23
|
+
cancel(`Skill "${nameArg}" not found in registry.`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
const agentPaths = Object.entries(skill.agents).filter(([, a]) => a.active).map(([id, a]) => ({ id, path: a.path }));
|
|
27
|
+
console.log(`
|
|
28
|
+
${chalk.cyan.bold(skill.name)} ${chalk.dim("@" + skill.shortSha)}
|
|
29
|
+
`);
|
|
30
|
+
if (agentPaths.length) {
|
|
31
|
+
console.log(` ${chalk.dim("Agent paths to remove:")}`);
|
|
32
|
+
for (const { id, path } of agentPaths) {
|
|
33
|
+
const exists = existsSync(path);
|
|
34
|
+
console.log(
|
|
35
|
+
` ${chalk.bold(id)} ${path}` + (exists ? "" : chalk.dim(" (already missing)"))
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const archiveCount = skill.history.length;
|
|
40
|
+
if (archiveCount > 0) {
|
|
41
|
+
console.log(
|
|
42
|
+
`
|
|
43
|
+
${chalk.dim(`${archiveCount} archived version(s) in version store`)}`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
console.log();
|
|
47
|
+
const ok = await confirm({ message: `Uninstall "${nameArg}"?` });
|
|
48
|
+
if (isCancel(ok) || !ok) {
|
|
49
|
+
cancel("Uninstall cancelled");
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
let pruneArchives = false;
|
|
53
|
+
if (archiveCount > 0) {
|
|
54
|
+
const pruneAnswer = await confirm({
|
|
55
|
+
message: `Also delete ${archiveCount} archived version(s) from the version store?`,
|
|
56
|
+
initialValue: false
|
|
57
|
+
});
|
|
58
|
+
if (isCancel(pruneAnswer)) {
|
|
59
|
+
cancel("Uninstall cancelled");
|
|
60
|
+
process.exit(0);
|
|
61
|
+
}
|
|
62
|
+
pruneArchives = pruneAnswer;
|
|
63
|
+
}
|
|
64
|
+
const s = spinner();
|
|
65
|
+
s.start(`Removing ${chalk.cyan(nameArg)}\u2026`);
|
|
66
|
+
const errors = [];
|
|
67
|
+
for (const { path } of agentPaths) {
|
|
68
|
+
if (existsSync(path)) {
|
|
69
|
+
try {
|
|
70
|
+
await rm(path, { recursive: true, force: true });
|
|
71
|
+
} catch (err) {
|
|
72
|
+
errors.push(`Failed to remove ${path}: ${String(err)}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (pruneArchives) {
|
|
77
|
+
try {
|
|
78
|
+
await pruneVersions(nameArg);
|
|
79
|
+
const skillVersionDir = join(versionsDir(), nameArg);
|
|
80
|
+
if (existsSync(skillVersionDir)) {
|
|
81
|
+
await rm(skillVersionDir, { recursive: true, force: true });
|
|
82
|
+
}
|
|
83
|
+
} catch (err) {
|
|
84
|
+
errors.push(`Failed to prune archives: ${String(err)}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
removeSkill(registry, nameArg);
|
|
88
|
+
await writeRegistry(registry);
|
|
89
|
+
if (errors.length) {
|
|
90
|
+
s.stop(chalk.yellow(`Uninstalled with warnings`));
|
|
91
|
+
for (const e of errors) console.log(` ${chalk.yellow("!")} ${e}`);
|
|
92
|
+
} else {
|
|
93
|
+
s.stop(`${chalk.green("\u2713")} ${chalk.cyan(nameArg)} uninstalled`);
|
|
94
|
+
}
|
|
95
|
+
outro(
|
|
96
|
+
pruneArchives ? chalk.dim("Skill and all version archives removed.") : chalk.dim("Skill removed. Version archives retained in ~/.augy/versions/.")
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
export {
|
|
100
|
+
uninstallCommand
|
|
101
|
+
};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import {
|
|
2
|
+
archiveVersion
|
|
3
|
+
} from "./chunk-PX2LVUHV.js";
|
|
4
|
+
import {
|
|
5
|
+
agentById,
|
|
6
|
+
agentSkillPath
|
|
7
|
+
} from "./chunk-R2TJ3UDO.js";
|
|
8
|
+
import {
|
|
9
|
+
discoverSkills,
|
|
10
|
+
downloadSkill,
|
|
11
|
+
parseGitHubUrl
|
|
12
|
+
} from "./chunk-EU54UQ4C.js";
|
|
13
|
+
import {
|
|
14
|
+
listSkills,
|
|
15
|
+
readRegistry,
|
|
16
|
+
shortSha,
|
|
17
|
+
writeRegistry
|
|
18
|
+
} from "./chunk-ZW6ZKHTF.js";
|
|
19
|
+
|
|
20
|
+
// src/commands/update.ts
|
|
21
|
+
import { cancel, confirm, intro, isCancel, multiselect, outro, spinner } from "@clack/prompts";
|
|
22
|
+
import chalk from "chalk";
|
|
23
|
+
import { mkdir, rm } from "fs/promises";
|
|
24
|
+
async function updateCommand(nameArg) {
|
|
25
|
+
intro(chalk.bold("augy") + chalk.dim(" \u2014 update"));
|
|
26
|
+
const registry = await readRegistry();
|
|
27
|
+
let skills = listSkills(registry);
|
|
28
|
+
if (!skills.length) {
|
|
29
|
+
cancel("No skills installed. Run `augy install` first.");
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
if (nameArg) {
|
|
33
|
+
const found = skills.find((s2) => s2.name === nameArg);
|
|
34
|
+
if (!found) {
|
|
35
|
+
cancel(`Skill "${nameArg}" not found in registry.`);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
skills = [found];
|
|
39
|
+
}
|
|
40
|
+
const unpinned = skills.filter((s2) => !s2.pinned);
|
|
41
|
+
const pinned = skills.filter((s2) => s2.pinned);
|
|
42
|
+
if (pinned.length) {
|
|
43
|
+
console.log(
|
|
44
|
+
chalk.dim(`Skipping ${pinned.length} pinned skill(s): `) + chalk.dim(pinned.map((s2) => s2.name).join(", "))
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
if (!unpinned.length) {
|
|
48
|
+
outro(chalk.yellow("All skills are pinned \u2014 nothing to update."));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const s = spinner();
|
|
52
|
+
s.start(`Checking ${unpinned.length} skill(s) for updates\u2026`);
|
|
53
|
+
const candidates = [];
|
|
54
|
+
const errors = [];
|
|
55
|
+
await Promise.allSettled(
|
|
56
|
+
unpinned.map(async (skill) => {
|
|
57
|
+
try {
|
|
58
|
+
const coords = parseGitHubUrl(skill.source);
|
|
59
|
+
const remote = await discoverSkills(coords);
|
|
60
|
+
const match = remote.find((r) => r.name === skill.name) ?? remote[0];
|
|
61
|
+
if (!match) return;
|
|
62
|
+
if (match.sha !== skill.sha) {
|
|
63
|
+
candidates.push({
|
|
64
|
+
skill,
|
|
65
|
+
remoteSha: match.sha,
|
|
66
|
+
remoteShortSha: shortSha(match.sha),
|
|
67
|
+
gigetSource: match.gigetSource
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
} catch (err) {
|
|
71
|
+
errors.push({ name: skill.name, err: String(err) });
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
);
|
|
75
|
+
s.stop();
|
|
76
|
+
if (errors.length) {
|
|
77
|
+
for (const { name, err } of errors) {
|
|
78
|
+
console.log(` ${chalk.red("\u2717")} ${chalk.cyan(name)} \u2014 ${err}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (!candidates.length) {
|
|
82
|
+
outro(chalk.green("All skills are up to date!"));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
console.log(
|
|
86
|
+
`
|
|
87
|
+
${chalk.bold(String(candidates.length))} skill(s) have updates available:
|
|
88
|
+
`
|
|
89
|
+
);
|
|
90
|
+
for (const c of candidates) {
|
|
91
|
+
console.log(
|
|
92
|
+
` ${chalk.cyan(c.skill.name)} ` + chalk.dim(shortSha(c.skill.sha)) + chalk.dim(" \u2192 ") + chalk.green(c.remoteShortSha)
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
console.log();
|
|
96
|
+
const toUpdate = candidates.length === 1 ? candidates : await promptUpdateSelection(candidates);
|
|
97
|
+
if (isCancel(toUpdate) || !toUpdate.length) {
|
|
98
|
+
cancel("Update cancelled");
|
|
99
|
+
process.exit(0);
|
|
100
|
+
}
|
|
101
|
+
const ok = await confirm({ message: `Upgrade ${toUpdate.length} skill(s)?` });
|
|
102
|
+
if (isCancel(ok) || !ok) {
|
|
103
|
+
cancel("Update cancelled");
|
|
104
|
+
process.exit(0);
|
|
105
|
+
}
|
|
106
|
+
for (const candidate of toUpdate) {
|
|
107
|
+
const { skill, remoteSha, remoteShortSha, gigetSource } = candidate;
|
|
108
|
+
const s2 = spinner();
|
|
109
|
+
s2.start(`Upgrading ${chalk.cyan(skill.name)}\u2026`);
|
|
110
|
+
try {
|
|
111
|
+
const firstAgent = Object.entries(skill.agents)[0];
|
|
112
|
+
if (firstAgent) {
|
|
113
|
+
const [, install] = firstAgent;
|
|
114
|
+
if (install.active) {
|
|
115
|
+
await archiveVersion(install.path, skill.name, skill.sha);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
for (const [agentId, install] of Object.entries(skill.agents)) {
|
|
119
|
+
if (!install.active) continue;
|
|
120
|
+
const agent = agentById(agentId);
|
|
121
|
+
if (!agent) continue;
|
|
122
|
+
const dest = agentSkillPath(agent, skill.name);
|
|
123
|
+
await rm(dest, { recursive: true, force: true });
|
|
124
|
+
await mkdir(dest, { recursive: true });
|
|
125
|
+
await downloadSkill(gigetSource, dest);
|
|
126
|
+
}
|
|
127
|
+
const archivedEntry = {
|
|
128
|
+
sha: skill.sha,
|
|
129
|
+
installedAt: skill.updatedAt,
|
|
130
|
+
archivePath: `${process.env["HOME"] ?? "~"}/.augy/versions/${skill.name}/${skill.sha}`
|
|
131
|
+
};
|
|
132
|
+
skill.history.push(archivedEntry);
|
|
133
|
+
skill.sha = remoteSha;
|
|
134
|
+
skill.shortSha = reShort(remoteSha);
|
|
135
|
+
skill.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
136
|
+
registry.skills[skill.name] = skill;
|
|
137
|
+
s2.stop(
|
|
138
|
+
`${chalk.green("\u2713")} ${chalk.cyan(skill.name)} ` + chalk.dim(shortSha(skill.sha.slice(0, 7))) + " \u2192 " + chalk.green(reShort(remoteSha))
|
|
139
|
+
);
|
|
140
|
+
} catch (err) {
|
|
141
|
+
s2.stop(`${chalk.red("\u2717")} ${chalk.cyan(skill.name)} \u2014 ${String(err)}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
await writeRegistry(registry);
|
|
145
|
+
outro(chalk.green("Update complete!"));
|
|
146
|
+
}
|
|
147
|
+
function reShort(sha) {
|
|
148
|
+
return sha.slice(0, 7);
|
|
149
|
+
}
|
|
150
|
+
async function promptUpdateSelection(candidates) {
|
|
151
|
+
return multiselect({
|
|
152
|
+
message: "Which skills do you want to upgrade?",
|
|
153
|
+
options: candidates.map((c) => ({
|
|
154
|
+
value: c,
|
|
155
|
+
label: c.skill.name,
|
|
156
|
+
hint: chalk.dim(shortSha(c.skill.sha)) + " \u2192 " + chalk.green(c.remoteShortSha)
|
|
157
|
+
})),
|
|
158
|
+
required: true
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
export {
|
|
162
|
+
updateCommand
|
|
163
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@callmeradical/augy",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Homebrew for AI agent skills — install, version, update, rollback",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Lars Cromley",
|
|
8
|
+
"homepage": "https://callmeradical.github.io/augy",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/callmeradical/augy.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/callmeradical/augy/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"ai",
|
|
18
|
+
"skills",
|
|
19
|
+
"cli",
|
|
20
|
+
"package-manager",
|
|
21
|
+
"opencode",
|
|
22
|
+
"claude",
|
|
23
|
+
"codex",
|
|
24
|
+
"agent"
|
|
25
|
+
],
|
|
26
|
+
"files": [
|
|
27
|
+
"dist/**/*",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"bin": {
|
|
32
|
+
"augy": "./dist/index.js"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsup src/index.ts --format esm --outDir dist --clean",
|
|
36
|
+
"dev": "tsx src/index.ts",
|
|
37
|
+
"typecheck": "tsc --noEmit",
|
|
38
|
+
"prepublishOnly": "npm run typecheck && npm run build"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@clack/prompts": "^0.9.0",
|
|
42
|
+
"chalk": "^5.3.0",
|
|
43
|
+
"commander": "^12.1.0",
|
|
44
|
+
"diff": "^9.0.0",
|
|
45
|
+
"giget": "^3.2.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/diff": "^7.0.2",
|
|
49
|
+
"@types/node": "^22.0.0",
|
|
50
|
+
"tsup": "^8.3.0",
|
|
51
|
+
"tsx": "^4.19.0",
|
|
52
|
+
"typescript": "^5.7.0"
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=18"
|
|
56
|
+
}
|
|
57
|
+
}
|