@callmeradical/augy 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/README.md +105 -33
- package/dist/bundle-76RCX45C.js +49 -0
- package/dist/chunk-V5GA2ZHU.js +65 -0
- package/dist/index.js +16 -8
- package/dist/{info-7BO4LXXS.js → info-JKGYNOPV.js} +3 -3
- package/dist/{install-FPAGHWX2.js → install-WXJUM6CM.js} +8 -7
- package/dist/{list-UJX2MYXK.js → list-ZTG6RVGD.js} +1 -1
- package/dist/{rollback-WAZV5HNG.js → rollback-QXPWOF3Q.js} +4 -4
- package/dist/{scan-DKN7YBT5.js → scan-MWUT7G4V.js} +1 -1
- package/dist/sync-VPBC2PBH.js +189 -0
- package/dist/{update-A3PSROUK.js → update-NIBPLLHU.js} +4 -4
- package/package.json +2 -2
- package/dist/chunk-R2TJ3UDO.js +0 -43
- package/dist/{diff-KYSWUXMH.js → diff-VQU63ORX.js} +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# augy
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@callmeradical/augy)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](package.json)
|
|
6
|
+
|
|
7
|
+
**Homebrew for AI agent skills.** No marketplace. No accounts. No central service. Just Git repos, a lockfile, and full control over what runs in your agents.
|
|
4
8
|
|
|
5
9
|
```
|
|
6
10
|
augy install tdd # install by name via a tap
|
|
@@ -11,53 +15,87 @@ augy rollback tdd abc1234 # something broke — go back
|
|
|
11
15
|
|
|
12
16
|
---
|
|
13
17
|
|
|
18
|
+
## The philosophy
|
|
19
|
+
|
|
20
|
+
Other skill managers route you through a hosted registry — a central service you have to trust, that can go down, that doesn't work with private repos, and that you can't use behind a firewall.
|
|
21
|
+
|
|
22
|
+
augy works differently. **Skills are just files in Git repos. GitHub is the registry.**
|
|
23
|
+
|
|
24
|
+
- Any GitHub repo is a valid skill source — public or private
|
|
25
|
+
- `~/.augy/registry.json` is your lockfile — a plain JSON file you can read, diff, commit, and share
|
|
26
|
+
- No account required. No API key for the registry. No SaaS dependency
|
|
27
|
+
- Works in enterprise environments, behind proxies, with internal repos
|
|
28
|
+
- You decide which repos to trust — not a third-party curation team
|
|
29
|
+
|
|
30
|
+
The tap system is Homebrew's model: register a repo once, install skills by name. Remove the tap and you've unregistered the source. Simple, transparent, yours.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
14
34
|
## Install
|
|
15
35
|
|
|
16
36
|
```bash
|
|
17
|
-
npm install -g augy
|
|
37
|
+
npm install -g @callmeradical/augy
|
|
18
38
|
```
|
|
19
39
|
|
|
40
|
+
> The npm package is `@callmeradical/augy`. The CLI command is `augy`.
|
|
41
|
+
|
|
20
42
|
Requires Node.js ≥ 18.
|
|
21
43
|
|
|
22
44
|
---
|
|
23
45
|
|
|
24
46
|
## How it works
|
|
25
47
|
|
|
26
|
-
Skills are directories containing a `SKILL.md` file that an AI agent loads as context. augy tracks which skills you have installed, where they came from (GitHub), and what version (commit SHA) is on disk — then lets you update, diff, and roll back just like a package manager.
|
|
48
|
+
Skills are directories containing a `SKILL.md` file that an AI agent loads as context. augy tracks which skills you have installed, where they came from (a GitHub path), and what exact version (commit SHA) is on disk — then lets you update, diff, and roll back just like a package manager.
|
|
27
49
|
|
|
28
50
|
**Supported agents**
|
|
29
51
|
|
|
30
|
-
|
|
31
|
-
|---|---|
|
|
32
|
-
| OpenCode | `~/.opencode/skills/` |
|
|
33
|
-
| Claude | `~/.claude/skills/` |
|
|
34
|
-
| Codex | `~/.codex/skills/` (or `$CODEX_HOME/skills`) |
|
|
52
|
+
augy auto-detects which agents are installed on your machine and pre-selects them in the install prompt. All 33 are supported:
|
|
35
53
|
|
|
36
|
-
|
|
54
|
+
Claude · OpenCode · Codex · Cursor · Windsurf · GitHub Copilot · Gemini CLI · Goose · Amp · Roo Code · Cline · Kiro · Kimi CLI · Kilo Code · Trae · Trae CN · Augment · OpenHands · Replit · Crush · Antigravity · Droid · OpenClaw · CodeBuddy · Command Code · Kode · Mistral Vibe · Mux · OpenClaude IDE · Qoder · Qwen Code · Neovate · AdaL
|
|
55
|
+
|
|
56
|
+
A single skill can be deployed to multiple agents simultaneously and stays in sync on every update.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Quick start
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# 1. Add a tap — a GitHub repo you trust
|
|
64
|
+
augy tap add mattpocock/skills
|
|
65
|
+
|
|
66
|
+
# 2. See what's available
|
|
67
|
+
augy search
|
|
68
|
+
|
|
69
|
+
# 3. Install by name
|
|
70
|
+
augy install tdd
|
|
71
|
+
|
|
72
|
+
# Already have skills installed manually? Bring them under augy management:
|
|
73
|
+
augy scan
|
|
74
|
+
```
|
|
37
75
|
|
|
38
76
|
---
|
|
39
77
|
|
|
40
78
|
## Commands
|
|
41
79
|
|
|
42
80
|
### `augy install [url]`
|
|
43
|
-
Install skills from a GitHub URL, `owner/repo[/path]` shorthand, or a bare name resolved via a
|
|
81
|
+
Install skills from a GitHub URL, `owner/repo[/path]` shorthand, or a bare name resolved via a tap. When a repo contains multiple skills, shows a filterable picker.
|
|
44
82
|
|
|
45
83
|
```bash
|
|
84
|
+
augy install tdd # via tap
|
|
85
|
+
augy install mattpocock/skills # all skills in a repo
|
|
46
86
|
augy install https://github.com/mattpocock/skills/tree/main
|
|
47
|
-
augy install
|
|
48
|
-
augy install tdd # resolves via taps
|
|
49
|
-
augy install tdd --agent opencode # target a specific agent
|
|
87
|
+
augy install tdd --agent opencode claude # specific agents
|
|
50
88
|
```
|
|
51
89
|
|
|
52
90
|
### `augy scan`
|
|
53
|
-
|
|
91
|
+
Walk all agent skill directories, find skills augy doesn't know about, auto-detect their GitHub source via git remotes and `SKILL.md` frontmatter, and import them into the registry. Skills without a detectable source show their filesystem path so you can look them up.
|
|
54
92
|
|
|
55
93
|
```bash
|
|
56
94
|
augy scan
|
|
57
95
|
```
|
|
58
96
|
|
|
59
97
|
### `augy update [skill]`
|
|
60
|
-
Check all installed skills for upstream SHA drift.
|
|
98
|
+
Check all installed skills for upstream SHA drift. Archives the current version, then deploys the new one.
|
|
61
99
|
|
|
62
100
|
```bash
|
|
63
101
|
augy update # check + upgrade everything
|
|
@@ -70,19 +108,19 @@ Interactive file-level diff browser. Three modes:
|
|
|
70
108
|
```bash
|
|
71
109
|
augy diff tdd # installed ↔ upstream HEAD
|
|
72
110
|
augy diff tdd abc1234 # installed ↔ specific SHA
|
|
73
|
-
augy diff tdd abc1234 def5678 # two local archives
|
|
111
|
+
augy diff tdd abc1234 def5678 # two local archives side-by-side
|
|
74
112
|
```
|
|
75
113
|
|
|
76
114
|
### `augy rollback <skill> [sha]`
|
|
77
|
-
Restore a skill to any previously archived version.
|
|
115
|
+
Restore a skill to any previously archived version. Without a SHA, shows an interactive picker.
|
|
78
116
|
|
|
79
117
|
```bash
|
|
80
|
-
augy rollback tdd
|
|
81
|
-
augy rollback tdd abc1234
|
|
118
|
+
augy rollback tdd
|
|
119
|
+
augy rollback tdd abc1234
|
|
82
120
|
```
|
|
83
121
|
|
|
84
122
|
### `augy list`
|
|
85
|
-
Show all installed skills, their SHAs, agents, and
|
|
123
|
+
Show all installed skills, their SHAs, agents, and version history.
|
|
86
124
|
|
|
87
125
|
```bash
|
|
88
126
|
augy list
|
|
@@ -90,32 +128,63 @@ augy list --json # raw registry JSON
|
|
|
90
128
|
```
|
|
91
129
|
|
|
92
130
|
### `augy info <skill>`
|
|
93
|
-
Full metadata: source, SHA, agents with paths, version history, and a preview
|
|
131
|
+
Full metadata: source, SHA, agents with paths, version history, and a description preview from `SKILL.md`.
|
|
94
132
|
|
|
95
133
|
```bash
|
|
96
134
|
augy info tdd
|
|
97
135
|
```
|
|
98
136
|
|
|
99
137
|
### `augy search [query]`
|
|
100
|
-
Search all registered taps for available skills.
|
|
138
|
+
Search all registered taps for available skills. Shows install status and whether each skill is up to date.
|
|
101
139
|
|
|
102
140
|
```bash
|
|
103
|
-
augy search # full index
|
|
141
|
+
augy search # full index across all taps
|
|
104
142
|
augy search tdd # filter by name
|
|
105
143
|
```
|
|
106
144
|
|
|
107
145
|
### `augy tap add|remove|list`
|
|
108
|
-
Manage trusted repos
|
|
146
|
+
Manage trusted repos. Once tapped, install by bare name.
|
|
109
147
|
|
|
110
148
|
```bash
|
|
111
149
|
augy tap add mattpocock/skills
|
|
150
|
+
augy tap add org/internal-skills # private repos work too
|
|
112
151
|
augy tap add mattpocock/skills --path skills/engineering
|
|
113
152
|
augy tap list
|
|
114
153
|
augy tap remove mattpocock/skills
|
|
115
154
|
```
|
|
116
155
|
|
|
156
|
+
### `augy bundle`
|
|
157
|
+
Generate an `augy.json` manifest from your currently installed skills. Commit this file so teammates can reproduce your exact skill set with `augy sync`.
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
augy bundle # writes ./augy.json
|
|
161
|
+
augy bundle --output ~/augy.json # custom path
|
|
162
|
+
augy bundle --include-untracked # include skills with no known source
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
`augy.json` format:
|
|
166
|
+
```json
|
|
167
|
+
{
|
|
168
|
+
"version": 1,
|
|
169
|
+
"skills": {
|
|
170
|
+
"tdd": "mattpocock/skills/skills/engineering/tdd",
|
|
171
|
+
"commit": "anomalyco/agent-skills/skills/commit"
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### `augy sync [path]`
|
|
177
|
+
Install and update skills from an `augy.json` manifest. Skills in your registry but not in the manifest are left alone — nothing is auto-removed.
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
augy sync # reads ./augy.json
|
|
181
|
+
augy sync ~/team/augy.json # explicit path
|
|
182
|
+
augy sync --dry-run # preview changes without applying
|
|
183
|
+
augy sync --agent opencode claude # target specific agents
|
|
184
|
+
```
|
|
185
|
+
|
|
117
186
|
### `augy set-source <skill> <url>`
|
|
118
|
-
Attach a GitHub source to a skill imported without one
|
|
187
|
+
Attach a GitHub source to a skill imported without one. Accepts tree and blob URLs. Enables updates, diffs, and rollbacks.
|
|
119
188
|
|
|
120
189
|
```bash
|
|
121
190
|
augy set-source commit https://github.com/owner/repo/tree/main/skills/commit
|
|
@@ -129,7 +198,7 @@ augy uninstall tdd
|
|
|
129
198
|
```
|
|
130
199
|
|
|
131
200
|
### `augy pin|unpin <skill>`
|
|
132
|
-
Pin a skill to
|
|
201
|
+
Pin a skill to freeze it at the current version, skipping it during `augy update`.
|
|
133
202
|
|
|
134
203
|
```bash
|
|
135
204
|
augy pin tdd
|
|
@@ -140,22 +209,25 @@ augy unpin tdd
|
|
|
140
209
|
|
|
141
210
|
## Taps
|
|
142
211
|
|
|
143
|
-
Taps are
|
|
212
|
+
Taps are GitHub repos you trust as skill sources. The tap system is how augy stays decentralized — there is no central index, just repos you choose to register.
|
|
144
213
|
|
|
145
214
|
```bash
|
|
146
|
-
augy tap add mattpocock/skills
|
|
147
|
-
augy
|
|
215
|
+
augy tap add mattpocock/skills # public repo
|
|
216
|
+
augy tap add your-org/private-skills # private repo — works the same way
|
|
217
|
+
augy install tdd # resolves via taps automatically
|
|
148
218
|
```
|
|
149
219
|
|
|
220
|
+
Any GitHub repo containing a `SKILL.md` file (or subdirectories that do) is a valid tap. The source of truth is GitHub. augy just tracks what you've installed and from where.
|
|
221
|
+
|
|
150
222
|
---
|
|
151
223
|
|
|
152
224
|
## Version storage
|
|
153
225
|
|
|
154
|
-
Every upgrade archives the current skill to `~/.augy/versions/<skill>/<sha>/` before overwriting
|
|
226
|
+
Every upgrade archives the current skill files to `~/.augy/versions/<skill>/<sha>/` before overwriting. No external service required — snapshots live on your machine.
|
|
155
227
|
|
|
156
228
|
```
|
|
157
229
|
~/.augy/
|
|
158
|
-
registry.json ← lockfile
|
|
230
|
+
registry.json ← lockfile — plain JSON, human-readable
|
|
159
231
|
versions/
|
|
160
232
|
tdd/
|
|
161
233
|
7afa86d.../ ← snapshot before last upgrade
|
|
@@ -170,13 +242,13 @@ Every upgrade archives the current skill to `~/.augy/versions/<skill>/<sha>/` be
|
|
|
170
242
|
|---|---|---|
|
|
171
243
|
| `AUGY_HOME` | `~/.augy` | Override augy's home directory |
|
|
172
244
|
| `CODEX_HOME` | `~/.codex` | Override Codex agent path |
|
|
173
|
-
| `GITHUB_TOKEN` | — | Raise GitHub API rate limit from 60
|
|
245
|
+
| `GITHUB_TOKEN` | — | Raise GitHub API rate limit from 60 → 5,000 req/hr |
|
|
174
246
|
|
|
175
247
|
---
|
|
176
248
|
|
|
177
249
|
## Docs
|
|
178
250
|
|
|
179
|
-
Full documentation at **[augy
|
|
251
|
+
Full documentation at **[callmeradical.github.io/augy](https://callmeradical.github.io/augy)**
|
|
180
252
|
|
|
181
253
|
---
|
|
182
254
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
listSkills,
|
|
3
|
+
readRegistry
|
|
4
|
+
} from "./chunk-ZW6ZKHTF.js";
|
|
5
|
+
|
|
6
|
+
// src/commands/bundle.ts
|
|
7
|
+
import { outro, spinner } from "@clack/prompts";
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
import { writeFile } from "fs/promises";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
import { cwd } from "process";
|
|
12
|
+
var DEFAULT_FILENAME = "augy.json";
|
|
13
|
+
async function bundleCommand(opts) {
|
|
14
|
+
const registry = await readRegistry();
|
|
15
|
+
const skills = listSkills(registry);
|
|
16
|
+
if (!skills.length) {
|
|
17
|
+
console.log(chalk.dim("No skills installed. Nothing to bundle."));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const tracked = skills.filter((s2) => s2.source);
|
|
21
|
+
const untracked = skills.filter((s2) => !s2.source);
|
|
22
|
+
const bundle = {
|
|
23
|
+
version: 1,
|
|
24
|
+
skills: {}
|
|
25
|
+
};
|
|
26
|
+
for (const skill of tracked) {
|
|
27
|
+
bundle.skills[skill.name] = skill.source;
|
|
28
|
+
}
|
|
29
|
+
if (opts.includeUntracked) {
|
|
30
|
+
for (const skill of untracked) {
|
|
31
|
+
bundle.skills[skill.name] = "";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const outputPath = opts.output ?? join(cwd(), DEFAULT_FILENAME);
|
|
35
|
+
const s = spinner();
|
|
36
|
+
s.start(`Writing ${chalk.cyan(outputPath)}\u2026`);
|
|
37
|
+
await writeFile(outputPath, JSON.stringify(bundle, null, 2) + "\n", "utf8");
|
|
38
|
+
s.stop(`${chalk.green("\u2713")} Bundle written ${chalk.dim(outputPath)}`);
|
|
39
|
+
const skillCount = Object.keys(bundle.skills).length;
|
|
40
|
+
const skippedNote = !opts.includeUntracked && untracked.length > 0 ? chalk.dim(`
|
|
41
|
+
${untracked.length} untracked skill(s) omitted \u2014 use --include-untracked to add them`) : "";
|
|
42
|
+
outro(
|
|
43
|
+
`${chalk.bold(String(skillCount))} skill(s) bundled${skippedNote}
|
|
44
|
+
` + chalk.dim(" Commit augy.json to share this skill set with your team.\n") + chalk.dim(" Teammates run `augy sync` to install from it.")
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
bundleCommand
|
|
49
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// src/agents.ts
|
|
2
|
+
import { homedir } from "os";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { existsSync } from "fs";
|
|
5
|
+
function h(p) {
|
|
6
|
+
return p.startsWith("~") ? join(homedir(), p.slice(1)) : p;
|
|
7
|
+
}
|
|
8
|
+
function codexSkillsPath() {
|
|
9
|
+
const codexHome = process.env["CODEX_HOME"];
|
|
10
|
+
return codexHome ? join(codexHome, "skills") : h("~/.codex/skills");
|
|
11
|
+
}
|
|
12
|
+
var AGENTS = [
|
|
13
|
+
// ── Tier 1: most widely used ────────────────────────────────────
|
|
14
|
+
{ id: "opencode", name: "OpenCode", skillsPath: h("~/.opencode/skills"), skillFile: "SKILL.md" },
|
|
15
|
+
{ id: "claude", name: "Claude", skillsPath: h("~/.claude/skills"), skillFile: "SKILL.md" },
|
|
16
|
+
{ id: "codex", name: "Codex", skillsPath: codexSkillsPath(), skillFile: "SKILL.md" },
|
|
17
|
+
{ id: "cursor", name: "Cursor", skillsPath: h("~/.cursor/skills"), skillFile: "SKILL.md" },
|
|
18
|
+
{ id: "windsurf", name: "Windsurf", skillsPath: h("~/.codeium/windsurf/skills"), skillFile: "SKILL.md" },
|
|
19
|
+
{ id: "copilot", name: "GitHub Copilot", skillsPath: h("~/.github/skills"), skillFile: "SKILL.md" },
|
|
20
|
+
{ id: "gemini", name: "Gemini CLI", skillsPath: h("~/.gemini/skills"), skillFile: "SKILL.md" },
|
|
21
|
+
{ id: "goose", name: "Goose", skillsPath: h("~/.goose/skills"), skillFile: "SKILL.md" },
|
|
22
|
+
{ id: "amp", name: "Amp", skillsPath: h("~/.agents/skills"), skillFile: "SKILL.md" },
|
|
23
|
+
{ id: "roo", name: "Roo Code", skillsPath: h("~/.roo/skills"), skillFile: "SKILL.md" },
|
|
24
|
+
{ id: "cline", name: "Cline", skillsPath: h("~/.cline/skills"), skillFile: "SKILL.md" },
|
|
25
|
+
// ── Tier 2: growing ─────────────────────────────────────────────
|
|
26
|
+
{ id: "kiro", name: "Kiro", skillsPath: h("~/.kiro/skills"), skillFile: "SKILL.md" },
|
|
27
|
+
{ id: "kimi", name: "Kimi CLI", skillsPath: h("~/.kimi/skills"), skillFile: "SKILL.md" },
|
|
28
|
+
{ id: "kilocode", name: "Kilo Code", skillsPath: h("~/.kilocode/skills"), skillFile: "SKILL.md" },
|
|
29
|
+
{ id: "trae", name: "Trae", skillsPath: h("~/.trae/skills"), skillFile: "SKILL.md" },
|
|
30
|
+
{ id: "trae-cn", name: "Trae CN", skillsPath: h("~/.trae-cn/skills"), skillFile: "SKILL.md" },
|
|
31
|
+
{ id: "augment", name: "Augment", skillsPath: h("~/.augment/rules"), skillFile: "SKILL.md" },
|
|
32
|
+
{ id: "openhands", name: "OpenHands", skillsPath: h("~/.openhands/skills"), skillFile: "SKILL.md" },
|
|
33
|
+
{ id: "replit", name: "Replit", skillsPath: h("~/.replit/skills"), skillFile: "SKILL.md" },
|
|
34
|
+
{ id: "crush", name: "Crush", skillsPath: h("~/.config/crush/skills"), skillFile: "SKILL.md" },
|
|
35
|
+
// ── Tier 3: long tail ───────────────────────────────────────────
|
|
36
|
+
{ id: "antigravity", name: "Antigravity", skillsPath: h("~/.gemini/antigravity/skills"), skillFile: "SKILL.md" },
|
|
37
|
+
{ id: "droid", name: "Droid", skillsPath: h("~/.factory/skills"), skillFile: "SKILL.md" },
|
|
38
|
+
{ id: "openclaw", name: "OpenClaw", skillsPath: h("~/.openclaw/skills"), skillFile: "SKILL.md" },
|
|
39
|
+
{ id: "codebuddy", name: "CodeBuddy", skillsPath: h("~/.codebuddy/skills"), skillFile: "SKILL.md" },
|
|
40
|
+
{ id: "commandcode", name: "Command Code", skillsPath: h("~/.commandcode/skills"), skillFile: "SKILL.md" },
|
|
41
|
+
{ id: "kode", name: "Kode", skillsPath: h("~/.kode/skills"), skillFile: "SKILL.md" },
|
|
42
|
+
{ id: "mistralvibe", name: "Mistral Vibe", skillsPath: h("~/.vibe/skills"), skillFile: "SKILL.md" },
|
|
43
|
+
{ id: "mux", name: "Mux", skillsPath: h("~/.mux/skills"), skillFile: "SKILL.md" },
|
|
44
|
+
{ id: "openclaude", name: "OpenClaude IDE", skillsPath: h("~/.openclaude/skills"), skillFile: "SKILL.md" },
|
|
45
|
+
{ id: "qoder", name: "Qoder", skillsPath: h("~/.qoder/skills"), skillFile: "SKILL.md" },
|
|
46
|
+
{ id: "qwen", name: "Qwen Code", skillsPath: h("~/.qwen/skills"), skillFile: "SKILL.md" },
|
|
47
|
+
{ id: "neovate", name: "Neovate", skillsPath: h("~/.neovate/skills"), skillFile: "SKILL.md" },
|
|
48
|
+
{ id: "adal", name: "AdaL", skillsPath: h("~/.adal/skills"), skillFile: "SKILL.md" }
|
|
49
|
+
];
|
|
50
|
+
function agentById(id) {
|
|
51
|
+
return AGENTS.find((a) => a.id === id);
|
|
52
|
+
}
|
|
53
|
+
function agentSkillPath(agent, skillName) {
|
|
54
|
+
return join(agent.skillsPath, skillName);
|
|
55
|
+
}
|
|
56
|
+
function detectInstalledAgents() {
|
|
57
|
+
return AGENTS.filter((a) => existsSync(a.skillsPath));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export {
|
|
61
|
+
AGENTS,
|
|
62
|
+
agentById,
|
|
63
|
+
agentSkillPath,
|
|
64
|
+
detectInstalledAgents
|
|
65
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -10,29 +10,37 @@ 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-
|
|
13
|
+
const { installCommand } = await import("./install-WXJUM6CM.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-
|
|
17
|
+
const { updateCommand } = await import("./update-NIBPLLHU.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-
|
|
21
|
+
const { listCommand } = await import("./list-ZTG6RVGD.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-
|
|
27
|
+
const { diffCommand } = await import("./diff-VQU63ORX.js");
|
|
28
28
|
await diffCommand(skill, sha1, sha2);
|
|
29
29
|
});
|
|
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");
|
|
32
|
+
await bundleCommand(opts);
|
|
33
|
+
});
|
|
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");
|
|
36
|
+
await syncCommand(path, opts ?? {});
|
|
37
|
+
});
|
|
30
38
|
program.command("scan").description("Find skills installed outside augy and optionally import them into the registry").action(async () => {
|
|
31
|
-
const { scanCommand } = await import("./scan-
|
|
39
|
+
const { scanCommand } = await import("./scan-MWUT7G4V.js");
|
|
32
40
|
await scanCommand();
|
|
33
41
|
});
|
|
34
42
|
program.command("info <skill>").description("Show full metadata, version history, and description for an installed skill").action(async (skill) => {
|
|
35
|
-
const { infoCommand } = await import("./info-
|
|
43
|
+
const { infoCommand } = await import("./info-JKGYNOPV.js");
|
|
36
44
|
await infoCommand(skill);
|
|
37
45
|
});
|
|
38
46
|
program.command("search [query]").description("Search all taps for available skills (optionally filter by name)").action(async (query) => {
|
|
@@ -61,7 +69,7 @@ program.command("uninstall <skill>").description("Remove a skill from all agent
|
|
|
61
69
|
await uninstallCommand(skill);
|
|
62
70
|
});
|
|
63
71
|
program.command("rollback <skill> [sha]").description("Restore a skill to a previous archived version").action(async (skill, sha) => {
|
|
64
|
-
const { rollbackCommand } = await import("./rollback-
|
|
72
|
+
const { rollbackCommand } = await import("./rollback-QXPWOF3Q.js");
|
|
65
73
|
await rollbackCommand(skill, sha);
|
|
66
74
|
});
|
|
67
75
|
program.command("pin <skill>").description("Pin a skill so it is skipped during `augy update`").action(async (skill) => {
|
|
@@ -71,7 +79,7 @@ program.command("unpin <skill>").description("Allow a pinned skill to receive up
|
|
|
71
79
|
await setPinned(skill, false);
|
|
72
80
|
});
|
|
73
81
|
program.action(async () => {
|
|
74
|
-
const { installCommand } = await import("./install-
|
|
82
|
+
const { installCommand } = await import("./install-WXJUM6CM.js");
|
|
75
83
|
await installCommand();
|
|
76
84
|
});
|
|
77
85
|
program.parse();
|
|
@@ -6,8 +6,9 @@ import {
|
|
|
6
6
|
} from "./chunk-YXCEZ3EY.js";
|
|
7
7
|
import {
|
|
8
8
|
AGENTS,
|
|
9
|
-
agentSkillPath
|
|
10
|
-
|
|
9
|
+
agentSkillPath,
|
|
10
|
+
detectInstalledAgents
|
|
11
|
+
} from "./chunk-V5GA2ZHU.js";
|
|
11
12
|
import {
|
|
12
13
|
discoverSkills,
|
|
13
14
|
downloadSkill,
|
|
@@ -27,7 +28,6 @@ import {
|
|
|
27
28
|
confirm,
|
|
28
29
|
intro,
|
|
29
30
|
isCancel,
|
|
30
|
-
multiselect,
|
|
31
31
|
outro,
|
|
32
32
|
select,
|
|
33
33
|
spinner,
|
|
@@ -173,14 +173,15 @@ async function promptSkillSelection(skills) {
|
|
|
173
173
|
});
|
|
174
174
|
}
|
|
175
175
|
async function promptAgentSelection() {
|
|
176
|
-
|
|
176
|
+
const detected = new Set(detectInstalledAgents().map((a) => a.id));
|
|
177
|
+
return filterableMultiselect({
|
|
177
178
|
message: "Install for which agents?",
|
|
178
179
|
options: AGENTS.map((a) => ({
|
|
179
180
|
value: a,
|
|
180
181
|
label: a.name,
|
|
181
|
-
hint: chalk.dim(a.skillsPath)
|
|
182
|
-
|
|
183
|
-
|
|
182
|
+
hint: detected.has(a.id) ? chalk.dim(a.skillsPath) : chalk.dim("not detected"),
|
|
183
|
+
selected: detected.has(a.id)
|
|
184
|
+
}))
|
|
184
185
|
});
|
|
185
186
|
}
|
|
186
187
|
function bail() {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
agentById,
|
|
3
|
+
agentSkillPath
|
|
4
|
+
} from "./chunk-V5GA2ZHU.js";
|
|
1
5
|
import {
|
|
2
6
|
archiveExists,
|
|
3
7
|
restoreVersion
|
|
4
8
|
} from "./chunk-PX2LVUHV.js";
|
|
5
|
-
import {
|
|
6
|
-
agentById,
|
|
7
|
-
agentSkillPath
|
|
8
|
-
} from "./chunk-R2TJ3UDO.js";
|
|
9
9
|
import {
|
|
10
10
|
getSkill,
|
|
11
11
|
readRegistry,
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AGENTS,
|
|
3
|
+
agentSkillPath,
|
|
4
|
+
detectInstalledAgents
|
|
5
|
+
} from "./chunk-V5GA2ZHU.js";
|
|
6
|
+
import {
|
|
7
|
+
discoverSkills,
|
|
8
|
+
downloadSkill,
|
|
9
|
+
latestShaForPath,
|
|
10
|
+
parseGitHubUrl
|
|
11
|
+
} from "./chunk-EU54UQ4C.js";
|
|
12
|
+
import {
|
|
13
|
+
createSkillRecord,
|
|
14
|
+
getSkill,
|
|
15
|
+
readRegistry,
|
|
16
|
+
shortSha,
|
|
17
|
+
writeRegistry
|
|
18
|
+
} from "./chunk-ZW6ZKHTF.js";
|
|
19
|
+
|
|
20
|
+
// src/commands/sync.ts
|
|
21
|
+
import {
|
|
22
|
+
confirm,
|
|
23
|
+
intro,
|
|
24
|
+
isCancel,
|
|
25
|
+
outro,
|
|
26
|
+
spinner
|
|
27
|
+
} from "@clack/prompts";
|
|
28
|
+
import chalk from "chalk";
|
|
29
|
+
import { existsSync } from "fs";
|
|
30
|
+
import { readFile } from "fs/promises";
|
|
31
|
+
import { join } from "path";
|
|
32
|
+
import { cwd } from "process";
|
|
33
|
+
import { mkdir, rm } from "fs/promises";
|
|
34
|
+
var DEFAULT_FILENAME = "augy.json";
|
|
35
|
+
async function syncCommand(pathArg, opts = {}) {
|
|
36
|
+
intro(chalk.bold("augy") + chalk.dim(" \u2014 sync"));
|
|
37
|
+
const manifestPath = pathArg ?? join(cwd(), DEFAULT_FILENAME);
|
|
38
|
+
if (!existsSync(manifestPath)) {
|
|
39
|
+
console.error(
|
|
40
|
+
chalk.red(`No manifest found at ${manifestPath}
|
|
41
|
+
`) + chalk.dim("Run `augy bundle` to create one.")
|
|
42
|
+
);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
let bundle;
|
|
46
|
+
try {
|
|
47
|
+
bundle = JSON.parse(await readFile(manifestPath, "utf8"));
|
|
48
|
+
} catch {
|
|
49
|
+
console.error(chalk.red(`Could not parse ${manifestPath}`));
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
const entries = Object.entries(bundle.skills);
|
|
53
|
+
if (!entries.length) {
|
|
54
|
+
outro(chalk.dim("Manifest is empty \u2014 nothing to sync."));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
console.log(
|
|
58
|
+
chalk.dim(`
|
|
59
|
+
Manifest: ${manifestPath}`) + chalk.dim(` (${entries.length} skill(s))
|
|
60
|
+
`)
|
|
61
|
+
);
|
|
62
|
+
const targetAgents = opts.agent?.length ? AGENTS.filter((a) => opts.agent.includes(a.id)) : detectInstalledAgents();
|
|
63
|
+
if (!targetAgents.length) {
|
|
64
|
+
console.error(chalk.red("No agents detected. Install an agent or use --agent to specify one."));
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
const registry = await readRegistry();
|
|
68
|
+
const s = spinner();
|
|
69
|
+
s.start("Resolving skills\u2026");
|
|
70
|
+
const plan = [];
|
|
71
|
+
await Promise.allSettled(
|
|
72
|
+
entries.map(async ([name, source]) => {
|
|
73
|
+
if (!source) {
|
|
74
|
+
plan.push({ name, source: "", action: "no-source" });
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const installed = getSkill(registry, name);
|
|
78
|
+
try {
|
|
79
|
+
const coords = parseGitHubUrl(source);
|
|
80
|
+
const remoteSha = await latestShaForPath(
|
|
81
|
+
coords.owner,
|
|
82
|
+
coords.repo,
|
|
83
|
+
coords.path || ".",
|
|
84
|
+
coords.ref
|
|
85
|
+
);
|
|
86
|
+
if (!installed) {
|
|
87
|
+
plan.push({ name, source, action: "install", remoteSha });
|
|
88
|
+
} else if (installed.sha !== remoteSha) {
|
|
89
|
+
plan.push({ name, source, action: "upgrade", remoteSha });
|
|
90
|
+
} else {
|
|
91
|
+
plan.push({ name, source, action: "up-to-date", remoteSha });
|
|
92
|
+
}
|
|
93
|
+
} catch {
|
|
94
|
+
plan.push({ name, source, action: "no-source" });
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
);
|
|
98
|
+
const order = { install: 0, upgrade: 1, "up-to-date": 2, "no-source": 3 };
|
|
99
|
+
plan.sort((a, b) => order[a.action] - order[b.action]);
|
|
100
|
+
s.stop("Resolved");
|
|
101
|
+
const toInstall = plan.filter((p) => p.action === "install");
|
|
102
|
+
const toUpgrade = plan.filter((p) => p.action === "upgrade");
|
|
103
|
+
const upToDate = plan.filter((p) => p.action === "up-to-date");
|
|
104
|
+
const noSource = plan.filter((p) => p.action === "no-source");
|
|
105
|
+
if (toInstall.length) {
|
|
106
|
+
console.log(chalk.bold(` Install (${toInstall.length})`));
|
|
107
|
+
for (const p of toInstall) {
|
|
108
|
+
console.log(` ${chalk.cyan(p.name)} ${chalk.dim(p.remoteSha ? "@" + shortSha(p.remoteSha) : "")}`);
|
|
109
|
+
}
|
|
110
|
+
console.log();
|
|
111
|
+
}
|
|
112
|
+
if (toUpgrade.length) {
|
|
113
|
+
console.log(chalk.bold(` Upgrade (${toUpgrade.length})`));
|
|
114
|
+
for (const p of toUpgrade) {
|
|
115
|
+
const installed = getSkill(registry, p.name);
|
|
116
|
+
console.log(
|
|
117
|
+
` ${chalk.cyan(p.name)} ${chalk.dim(installed.shortSha)} \u2192 ${chalk.green(shortSha(p.remoteSha))}`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
console.log();
|
|
121
|
+
}
|
|
122
|
+
if (upToDate.length) {
|
|
123
|
+
console.log(chalk.dim(` Up to date (${upToDate.length}): `) + chalk.dim(upToDate.map((p) => p.name).join(", ")));
|
|
124
|
+
console.log();
|
|
125
|
+
}
|
|
126
|
+
if (noSource.length) {
|
|
127
|
+
console.log(chalk.yellow(` Skipped \u2014 no source (${noSource.length}): `) + chalk.dim(noSource.map((p) => p.name).join(", ")));
|
|
128
|
+
console.log();
|
|
129
|
+
}
|
|
130
|
+
if (!toInstall.length && !toUpgrade.length) {
|
|
131
|
+
outro(chalk.green("Everything is up to date."));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (opts.dryRun) {
|
|
135
|
+
outro(chalk.dim("Dry run \u2014 no changes made."));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const actionCount = toInstall.length + toUpgrade.length;
|
|
139
|
+
const ok = await confirm({
|
|
140
|
+
message: `Apply ${actionCount} change(s) to ${targetAgents.map((a) => a.name).join(", ")}?`
|
|
141
|
+
});
|
|
142
|
+
if (isCancel(ok) || !ok) {
|
|
143
|
+
console.log(chalk.dim("Cancelled."));
|
|
144
|
+
process.exit(0);
|
|
145
|
+
}
|
|
146
|
+
for (const entry of [...toInstall, ...toUpgrade]) {
|
|
147
|
+
const s2 = spinner();
|
|
148
|
+
s2.start(`${entry.action === "install" ? "Installing" : "Upgrading"} ${chalk.cyan(entry.name)}\u2026`);
|
|
149
|
+
try {
|
|
150
|
+
const coords = parseGitHubUrl(entry.source);
|
|
151
|
+
const remote = await discoverSkills(coords);
|
|
152
|
+
const match = remote.find((r) => r.name === entry.name) ?? remote[0];
|
|
153
|
+
if (!match) throw new Error("Skill not found at source");
|
|
154
|
+
const agentPaths = {};
|
|
155
|
+
for (const agent of targetAgents) {
|
|
156
|
+
const dest = agentSkillPath(agent, entry.name);
|
|
157
|
+
agentPaths[agent.id] = dest;
|
|
158
|
+
await rm(dest, { recursive: true, force: true });
|
|
159
|
+
await mkdir(dest, { recursive: true });
|
|
160
|
+
await downloadSkill(match.gigetSource, dest);
|
|
161
|
+
}
|
|
162
|
+
const existing = getSkill(registry, entry.name);
|
|
163
|
+
const record = createSkillRecord({
|
|
164
|
+
name: entry.name,
|
|
165
|
+
source: entry.source,
|
|
166
|
+
gigetSource: match.gigetSource,
|
|
167
|
+
sha: match.sha,
|
|
168
|
+
agentIds: targetAgents.map((a) => a.id),
|
|
169
|
+
agentPaths
|
|
170
|
+
});
|
|
171
|
+
if (existing) {
|
|
172
|
+
record.installedAt = existing.installedAt;
|
|
173
|
+
record.pinned = existing.pinned;
|
|
174
|
+
record.history = existing.history;
|
|
175
|
+
}
|
|
176
|
+
registry.skills[entry.name] = record;
|
|
177
|
+
await writeRegistry(registry);
|
|
178
|
+
s2.stop(
|
|
179
|
+
`${chalk.green("\u2713")} ${chalk.cyan(entry.name)} ${chalk.dim("@" + shortSha(match.sha))}`
|
|
180
|
+
);
|
|
181
|
+
} catch (err) {
|
|
182
|
+
s2.stop(`${chalk.red("\u2717")} ${chalk.cyan(entry.name)} \u2014 ${String(err)}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
outro(chalk.green(`Sync complete ${chalk.dim(`(${actionCount} change(s) applied)`)}`));
|
|
186
|
+
}
|
|
187
|
+
export {
|
|
188
|
+
syncCommand
|
|
189
|
+
};
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
archiveVersion
|
|
3
|
-
} from "./chunk-PX2LVUHV.js";
|
|
4
1
|
import {
|
|
5
2
|
agentById,
|
|
6
3
|
agentSkillPath
|
|
7
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-V5GA2ZHU.js";
|
|
8
5
|
import {
|
|
9
6
|
discoverSkills,
|
|
10
7
|
downloadSkill,
|
|
11
8
|
parseGitHubUrl
|
|
12
9
|
} from "./chunk-EU54UQ4C.js";
|
|
10
|
+
import {
|
|
11
|
+
archiveVersion
|
|
12
|
+
} from "./chunk-PX2LVUHV.js";
|
|
13
13
|
import {
|
|
14
14
|
listSkills,
|
|
15
15
|
readRegistry,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@callmeradical/augy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Homebrew for AI agent skills — install, version, update, rollback",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,7 +35,7 @@
|
|
|
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
|
|
38
|
+
"prepublishOnly": "npm run build"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@clack/prompts": "^0.9.0",
|
package/dist/chunk-R2TJ3UDO.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
// src/agents.ts
|
|
2
|
-
import { homedir } from "os";
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
function resolveHome(p) {
|
|
5
|
-
return p.startsWith("~") ? join(homedir(), p.slice(1)) : p;
|
|
6
|
-
}
|
|
7
|
-
function codexSkillsPath() {
|
|
8
|
-
const codexHome = process.env["CODEX_HOME"];
|
|
9
|
-
if (codexHome) return join(codexHome, "skills");
|
|
10
|
-
return resolveHome("~/.codex/skills");
|
|
11
|
-
}
|
|
12
|
-
var AGENTS = [
|
|
13
|
-
{
|
|
14
|
-
id: "opencode",
|
|
15
|
-
name: "OpenCode",
|
|
16
|
-
skillsPath: resolveHome("~/.opencode/skills"),
|
|
17
|
-
skillFile: "SKILL.md"
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
id: "claude",
|
|
21
|
-
name: "Claude",
|
|
22
|
-
skillsPath: resolveHome("~/.claude/skills"),
|
|
23
|
-
skillFile: "SKILL.md"
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
id: "codex",
|
|
27
|
-
name: "Codex",
|
|
28
|
-
skillsPath: codexSkillsPath(),
|
|
29
|
-
skillFile: "SKILL.md"
|
|
30
|
-
}
|
|
31
|
-
];
|
|
32
|
-
function agentById(id) {
|
|
33
|
-
return AGENTS.find((a) => a.id === id);
|
|
34
|
-
}
|
|
35
|
-
function agentSkillPath(agent, skillName) {
|
|
36
|
-
return join(agent.skillsPath, skillName);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export {
|
|
40
|
-
AGENTS,
|
|
41
|
-
agentById,
|
|
42
|
-
agentSkillPath
|
|
43
|
-
};
|