@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,328 @@
|
|
|
1
|
+
import {
|
|
2
|
+
detectProvenance,
|
|
3
|
+
injectSourceIntoSkillMd
|
|
4
|
+
} from "./chunk-KCQY4IDO.js";
|
|
5
|
+
import {
|
|
6
|
+
filterableMultiselect
|
|
7
|
+
} from "./chunk-UJX6VJ3S.js";
|
|
8
|
+
import {
|
|
9
|
+
resolveSkillFromTaps
|
|
10
|
+
} from "./chunk-YXCEZ3EY.js";
|
|
11
|
+
import {
|
|
12
|
+
AGENTS
|
|
13
|
+
} from "./chunk-R2TJ3UDO.js";
|
|
14
|
+
import {
|
|
15
|
+
discoverSkills,
|
|
16
|
+
parseGitHubUrl
|
|
17
|
+
} from "./chunk-EU54UQ4C.js";
|
|
18
|
+
import {
|
|
19
|
+
createSkillRecord,
|
|
20
|
+
getSkill,
|
|
21
|
+
listSkills,
|
|
22
|
+
readRegistry,
|
|
23
|
+
shortSha,
|
|
24
|
+
writeRegistry
|
|
25
|
+
} from "./chunk-ZW6ZKHTF.js";
|
|
26
|
+
|
|
27
|
+
// src/commands/scan.ts
|
|
28
|
+
import { readdir, readFile } from "fs/promises";
|
|
29
|
+
import { existsSync } from "fs";
|
|
30
|
+
import { join } from "path";
|
|
31
|
+
import {
|
|
32
|
+
cancel,
|
|
33
|
+
confirm,
|
|
34
|
+
intro,
|
|
35
|
+
isCancel,
|
|
36
|
+
outro,
|
|
37
|
+
spinner,
|
|
38
|
+
text
|
|
39
|
+
} from "@clack/prompts";
|
|
40
|
+
import chalk from "chalk";
|
|
41
|
+
import { homedir } from "os";
|
|
42
|
+
async function scanCommand() {
|
|
43
|
+
intro(chalk.bold("augy") + chalk.dim(" \u2014 scan"));
|
|
44
|
+
const registry = await readRegistry();
|
|
45
|
+
const s = spinner();
|
|
46
|
+
s.start("Scanning agent skill directories\u2026");
|
|
47
|
+
const onDisk = await findAllOnDiskSkills();
|
|
48
|
+
s.stop(`Scanned ${AGENTS.length} agent(s)`);
|
|
49
|
+
const untracked = [];
|
|
50
|
+
for (const [name, agents] of onDisk) {
|
|
51
|
+
if (!getSkill(registry, name)) {
|
|
52
|
+
untracked.push({ name, agents });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const tracked = listSkills(registry);
|
|
56
|
+
if (!untracked.length) {
|
|
57
|
+
outro(chalk.green("All installed skills are already tracked by augy."));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const s2 = spinner();
|
|
61
|
+
s2.start(`Detecting provenance for ${untracked.length} skill(s)\u2026`);
|
|
62
|
+
await Promise.allSettled(
|
|
63
|
+
untracked.map(async (sk) => {
|
|
64
|
+
const firstPath = sk.agents[0]?.path;
|
|
65
|
+
if (!firstPath) return;
|
|
66
|
+
const result = await detectProvenance(firstPath, sk.name);
|
|
67
|
+
if (result) {
|
|
68
|
+
sk.provenance = result;
|
|
69
|
+
} else {
|
|
70
|
+
const tapMatch = await tryResolveTapSource(registry, sk.name);
|
|
71
|
+
if (tapMatch) {
|
|
72
|
+
sk.provenance = {
|
|
73
|
+
source: `${tapMatch.tapKey}/${tapMatch.repoPath}`,
|
|
74
|
+
gigetSource: tapMatch.gigetSource,
|
|
75
|
+
sha: tapMatch.sha,
|
|
76
|
+
confidence: "tap",
|
|
77
|
+
description: `tap: ${tapMatch.tapKey}`
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (!sk.provenance) {
|
|
82
|
+
sk.description = await readSkillDescription(firstPath);
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
);
|
|
86
|
+
const detected = untracked.filter((sk) => sk.provenance);
|
|
87
|
+
const unknown = untracked.filter((sk) => !sk.provenance);
|
|
88
|
+
s2.stop(
|
|
89
|
+
detected.length === untracked.length ? chalk.green(`Provenance found for all ${detected.length} skill(s)`) : detected.length > 0 ? `Provenance found for ${chalk.green(String(detected.length))} of ${untracked.length} \xB7 ` + chalk.yellow(`${unknown.length} unknown`) : chalk.yellow(`No provenance found for any of the ${untracked.length} skill(s)`)
|
|
90
|
+
);
|
|
91
|
+
const managedNote = tracked.length ? chalk.dim(` ${tracked.length} already managed by augy`) : "";
|
|
92
|
+
console.log(
|
|
93
|
+
`
|
|
94
|
+
${chalk.bold(String(untracked.length))} untracked skill(s) found${managedNote}
|
|
95
|
+
`
|
|
96
|
+
);
|
|
97
|
+
if (detected.length) {
|
|
98
|
+
console.log(
|
|
99
|
+
chalk.bold(" Provenance detected") + chalk.dim(` (${detected.length})`) + " " + chalk.dim("\u2500".repeat(36))
|
|
100
|
+
);
|
|
101
|
+
for (const sk of detected) {
|
|
102
|
+
printDetected(sk);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (unknown.length) {
|
|
106
|
+
console.log(
|
|
107
|
+
chalk.bold(" No provenance found") + chalk.dim(` (${unknown.length})`) + " " + chalk.dim("\u2500".repeat(35))
|
|
108
|
+
);
|
|
109
|
+
for (const sk of unknown) {
|
|
110
|
+
printUnknown(sk);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const doImport = await confirm({ message: "Import untracked skills into augy?" });
|
|
114
|
+
if (isCancel(doImport) || !doImport) {
|
|
115
|
+
cancel("No changes made.");
|
|
116
|
+
process.exit(0);
|
|
117
|
+
}
|
|
118
|
+
const toImport = untracked.length === 1 ? untracked : await selectSkillsToImport(untracked);
|
|
119
|
+
if (isCancel(toImport) || !toImport.length) {
|
|
120
|
+
cancel("Cancelled");
|
|
121
|
+
process.exit(0);
|
|
122
|
+
}
|
|
123
|
+
let importedCount = 0;
|
|
124
|
+
for (const sk of toImport) {
|
|
125
|
+
console.log();
|
|
126
|
+
console.log(` ${chalk.cyan.bold(sk.name)}`);
|
|
127
|
+
const detected2 = sk.provenance;
|
|
128
|
+
let resolvedSource;
|
|
129
|
+
let resolvedGigetSource;
|
|
130
|
+
let resolvedSha;
|
|
131
|
+
let resolvedTap;
|
|
132
|
+
if (detected2) {
|
|
133
|
+
const confidenceLabel = {
|
|
134
|
+
git: chalk.green("git remote"),
|
|
135
|
+
frontmatter: chalk.cyan("SKILL.md frontmatter"),
|
|
136
|
+
tap: chalk.cyan("tap match"),
|
|
137
|
+
unknown: chalk.dim("unknown")
|
|
138
|
+
};
|
|
139
|
+
console.log(
|
|
140
|
+
` ${chalk.dim("via")} ${confidenceLabel[detected2.confidence] ?? detected2.confidence}
|
|
141
|
+
${chalk.dim("source")} ${detected2.source}` + (detected2.sha ? ` ${chalk.dim("@" + shortSha(detected2.sha))}` : "")
|
|
142
|
+
);
|
|
143
|
+
const useDetected = await confirm({ message: "Use detected source?", initialValue: true });
|
|
144
|
+
if (isCancel(useDetected)) {
|
|
145
|
+
cancel("Cancelled");
|
|
146
|
+
process.exit(0);
|
|
147
|
+
}
|
|
148
|
+
if (useDetected) {
|
|
149
|
+
resolvedSource = detected2.source;
|
|
150
|
+
resolvedGigetSource = detected2.gigetSource;
|
|
151
|
+
resolvedSha = detected2.sha;
|
|
152
|
+
if (detected2.confidence === "tap") {
|
|
153
|
+
const tm = await tryResolveTapSource(registry, sk.name);
|
|
154
|
+
resolvedTap = tm?.tapKey;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (!resolvedSource) {
|
|
159
|
+
if (!detected2) {
|
|
160
|
+
console.log(` ${chalk.dim("Locations:")}`);
|
|
161
|
+
for (const { agent, path } of sk.agents) {
|
|
162
|
+
console.log(` ${chalk.bold(agent.name.padEnd(10))} ${chalk.dim(tildefy(path))}`);
|
|
163
|
+
}
|
|
164
|
+
if (sk.description) {
|
|
165
|
+
console.log(` ${chalk.dim("Description:")} ${chalk.dim(sk.description)}`);
|
|
166
|
+
}
|
|
167
|
+
console.log();
|
|
168
|
+
}
|
|
169
|
+
const sourceInput = await text({
|
|
170
|
+
message: "GitHub URL or owner/repo[/path]",
|
|
171
|
+
placeholder: "https://github.com/owner/repo (leave blank to import without source)",
|
|
172
|
+
defaultValue: ""
|
|
173
|
+
});
|
|
174
|
+
if (isCancel(sourceInput)) {
|
|
175
|
+
cancel("Cancelled");
|
|
176
|
+
process.exit(0);
|
|
177
|
+
}
|
|
178
|
+
resolvedSource = (sourceInput ?? "").trim();
|
|
179
|
+
}
|
|
180
|
+
const s3 = spinner();
|
|
181
|
+
let sha;
|
|
182
|
+
let gigetSource;
|
|
183
|
+
if (resolvedSha && resolvedGigetSource) {
|
|
184
|
+
sha = resolvedSha;
|
|
185
|
+
gigetSource = resolvedGigetSource;
|
|
186
|
+
} else if (!resolvedSource) {
|
|
187
|
+
sha = "unversioned";
|
|
188
|
+
gigetSource = "";
|
|
189
|
+
} else {
|
|
190
|
+
s3.start(`Fetching SHA for ${chalk.cyan(sk.name)}\u2026`);
|
|
191
|
+
try {
|
|
192
|
+
const coords = parseGitHubUrl(resolvedSource);
|
|
193
|
+
const remote = await discoverSkills(coords);
|
|
194
|
+
const match = remote.find((r) => r.name === sk.name) ?? remote[0];
|
|
195
|
+
if (!match) throw new Error("Skill not found at that source");
|
|
196
|
+
sha = match.sha;
|
|
197
|
+
gigetSource = match.gigetSource;
|
|
198
|
+
s3.stop(chalk.dim("@" + shortSha(sha)));
|
|
199
|
+
} catch (err) {
|
|
200
|
+
s3.stop(chalk.yellow("Could not fetch SHA \u2014 importing as unversioned"));
|
|
201
|
+
console.log(chalk.dim(` ${String(err)}`));
|
|
202
|
+
sha = "unversioned";
|
|
203
|
+
gigetSource = resolvedGigetSource ?? `github:${resolvedSource.replace("https://github.com/", "")}`;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const record = createSkillRecord({
|
|
207
|
+
name: sk.name,
|
|
208
|
+
source: resolvedSource,
|
|
209
|
+
gigetSource,
|
|
210
|
+
sha,
|
|
211
|
+
agentIds: sk.agents.map((a) => a.agent.id),
|
|
212
|
+
agentPaths: Object.fromEntries(sk.agents.map((a) => [a.agent.id, a.path])),
|
|
213
|
+
tap: resolvedTap
|
|
214
|
+
});
|
|
215
|
+
registry.skills[sk.name] = record;
|
|
216
|
+
importedCount++;
|
|
217
|
+
await writeRegistry(registry);
|
|
218
|
+
if (sha !== "unversioned" && resolvedSource) {
|
|
219
|
+
await injectSourceIntoSkillMd(sk.agents[0].path, resolvedSource).catch(() => void 0);
|
|
220
|
+
}
|
|
221
|
+
const sourceTag = !resolvedSource ? chalk.yellow(" (no source \u2014 add one later with `augy set-source`)") : sha !== "unversioned" ? chalk.dim(` @${shortSha(sha)}`) : chalk.yellow(" (unversioned)");
|
|
222
|
+
console.log(` ${chalk.green("\u2713")} ${chalk.cyan(sk.name)} imported${sourceTag}`);
|
|
223
|
+
}
|
|
224
|
+
outro(
|
|
225
|
+
importedCount > 0 ? chalk.green(`${importedCount} skill(s) imported into augy`) : chalk.dim("No skills imported.")
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
function printDetected(sk) {
|
|
229
|
+
const p = sk.provenance;
|
|
230
|
+
const confidenceColor = {
|
|
231
|
+
git: chalk.green,
|
|
232
|
+
frontmatter: chalk.cyan,
|
|
233
|
+
tap: chalk.cyan
|
|
234
|
+
};
|
|
235
|
+
const color = confidenceColor[p.confidence] ?? chalk.dim;
|
|
236
|
+
const agents = sk.agents.map((a) => chalk.bold(a.agent.name)).join(", ");
|
|
237
|
+
console.log(
|
|
238
|
+
`
|
|
239
|
+
${chalk.cyan.bold(sk.name)} ${chalk.dim("\u2192")} ${agents}`
|
|
240
|
+
);
|
|
241
|
+
console.log(
|
|
242
|
+
` ${chalk.dim("source")} ${p.source}` + (p.sha ? chalk.dim(` @${shortSha(p.sha)}`) : "") + ` ${color(`[${p.confidence}]`)}`
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
function printUnknown(sk) {
|
|
246
|
+
console.log(`
|
|
247
|
+
${chalk.cyan.bold(sk.name)} ${chalk.yellow("(no provenance found)")}`);
|
|
248
|
+
for (const { agent, path } of sk.agents) {
|
|
249
|
+
console.log(` ${chalk.dim(agent.name.padEnd(10))} ${tildefy(path)}`);
|
|
250
|
+
}
|
|
251
|
+
if (sk.description) {
|
|
252
|
+
console.log(` ${chalk.dim(sk.description)}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
async function selectSkillsToImport(skills) {
|
|
256
|
+
return filterableMultiselect({
|
|
257
|
+
message: "Which skills do you want to import?",
|
|
258
|
+
options: skills.map((sk) => ({
|
|
259
|
+
value: sk,
|
|
260
|
+
label: sk.name,
|
|
261
|
+
hint: sk.provenance ? chalk.green(sk.provenance.confidence) + " " + chalk.dim(sk.provenance.source) : chalk.yellow("no provenance") + " " + chalk.dim(tildefy(sk.agents[0]?.path ?? "")),
|
|
262
|
+
selected: true
|
|
263
|
+
}))
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
async function findAllOnDiskSkills() {
|
|
267
|
+
const result = /* @__PURE__ */ new Map();
|
|
268
|
+
await Promise.all(
|
|
269
|
+
AGENTS.map(async (agent) => {
|
|
270
|
+
if (!existsSync(agent.skillsPath)) return;
|
|
271
|
+
let entries;
|
|
272
|
+
try {
|
|
273
|
+
const dirents = await readdir(agent.skillsPath, { withFileTypes: true });
|
|
274
|
+
entries = dirents.filter((d) => d.isDirectory()).map((d) => d.name);
|
|
275
|
+
} catch {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
for (const name of entries) {
|
|
279
|
+
const skillPath = join(agent.skillsPath, name);
|
|
280
|
+
if (!existsSync(join(skillPath, agent.skillFile))) continue;
|
|
281
|
+
if (!result.has(name)) result.set(name, []);
|
|
282
|
+
result.get(name).push({ agent, path: skillPath });
|
|
283
|
+
}
|
|
284
|
+
})
|
|
285
|
+
);
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
288
|
+
async function readSkillDescription(skillPath) {
|
|
289
|
+
const skillMd = join(skillPath, "SKILL.md");
|
|
290
|
+
if (!existsSync(skillMd)) return void 0;
|
|
291
|
+
try {
|
|
292
|
+
const content = await readFile(skillMd, "utf8");
|
|
293
|
+
const lines = content.split("\n");
|
|
294
|
+
let inFrontmatter = false;
|
|
295
|
+
let pastFrontmatter = false;
|
|
296
|
+
for (const line of lines) {
|
|
297
|
+
if (line.trim() === "---") {
|
|
298
|
+
if (!pastFrontmatter) {
|
|
299
|
+
inFrontmatter = !inFrontmatter;
|
|
300
|
+
if (!inFrontmatter) pastFrontmatter = true;
|
|
301
|
+
}
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
if (inFrontmatter) continue;
|
|
305
|
+
if (!line.trim() || line.startsWith("#")) continue;
|
|
306
|
+
return line.trim().slice(0, 80) + (line.trim().length > 80 ? "\u2026" : "");
|
|
307
|
+
}
|
|
308
|
+
} catch {
|
|
309
|
+
}
|
|
310
|
+
return void 0;
|
|
311
|
+
}
|
|
312
|
+
function tildefy(p) {
|
|
313
|
+
const home = homedir();
|
|
314
|
+
return p.startsWith(home) ? "~" + p.slice(home.length) : p;
|
|
315
|
+
}
|
|
316
|
+
async function tryResolveTapSource(registry, name) {
|
|
317
|
+
if (!Object.keys(registry.taps).length) return void 0;
|
|
318
|
+
try {
|
|
319
|
+
const result = await resolveSkillFromTaps(registry, name);
|
|
320
|
+
if (!result) return void 0;
|
|
321
|
+
return Array.isArray(result) ? result[0] : result;
|
|
322
|
+
} catch {
|
|
323
|
+
return void 0;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
export {
|
|
327
|
+
scanCommand
|
|
328
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {
|
|
2
|
+
searchTaps
|
|
3
|
+
} from "./chunk-YXCEZ3EY.js";
|
|
4
|
+
import "./chunk-EU54UQ4C.js";
|
|
5
|
+
import {
|
|
6
|
+
listSkills,
|
|
7
|
+
readRegistry,
|
|
8
|
+
shortSha
|
|
9
|
+
} from "./chunk-ZW6ZKHTF.js";
|
|
10
|
+
|
|
11
|
+
// src/commands/search.ts
|
|
12
|
+
import { spinner } from "@clack/prompts";
|
|
13
|
+
import chalk from "chalk";
|
|
14
|
+
async function searchCommand(query) {
|
|
15
|
+
const registry = await readRegistry();
|
|
16
|
+
const taps = Object.keys(registry.taps);
|
|
17
|
+
if (!taps.length) {
|
|
18
|
+
console.log(
|
|
19
|
+
chalk.dim("No taps registered. Add one first:\n") + ` ${chalk.bold("augy tap add owner/repo")}`
|
|
20
|
+
);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const s = spinner();
|
|
24
|
+
s.start(
|
|
25
|
+
query ? `Searching ${taps.length} tap(s) for "${query}"\u2026` : `Fetching skill index from ${taps.length} tap(s)\u2026`
|
|
26
|
+
);
|
|
27
|
+
let results;
|
|
28
|
+
try {
|
|
29
|
+
results = await searchTaps(registry, query);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
s.stop(chalk.red("Search failed"));
|
|
32
|
+
console.error(String(err));
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
const totalMatches = results.reduce((n, r) => n + r.skills.length, 0);
|
|
36
|
+
s.stop(
|
|
37
|
+
totalMatches > 0 ? `Found ${chalk.green(String(totalMatches))} skill(s)` : chalk.yellow("No skills found")
|
|
38
|
+
);
|
|
39
|
+
if (!totalMatches) {
|
|
40
|
+
if (query) {
|
|
41
|
+
console.log(chalk.dim(`
|
|
42
|
+
No skills match "${query}". Try a broader term.`));
|
|
43
|
+
}
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const installed = new Map(listSkills(registry).map((s2) => [s2.name, s2]));
|
|
47
|
+
console.log();
|
|
48
|
+
for (const result of results) {
|
|
49
|
+
if (result.skills.length === 0 && !result.error) continue;
|
|
50
|
+
console.log(chalk.bold(result.tapKey) + chalk.dim(` (${result.tap.skillsPath || "root"})`));
|
|
51
|
+
if (result.error) {
|
|
52
|
+
console.log(` ${chalk.red("Error:")} ${result.error}`);
|
|
53
|
+
console.log();
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
for (const skill of result.skills) {
|
|
57
|
+
printSkillRow(skill, installed);
|
|
58
|
+
}
|
|
59
|
+
console.log();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function printSkillRow(skill, installed) {
|
|
63
|
+
const inst = installed.get(skill.name);
|
|
64
|
+
let statusBadge;
|
|
65
|
+
if (!inst) {
|
|
66
|
+
statusBadge = chalk.dim("not installed");
|
|
67
|
+
} else if (inst.sha === skill.sha) {
|
|
68
|
+
statusBadge = chalk.green("\u2713 up to date");
|
|
69
|
+
} else {
|
|
70
|
+
statusBadge = chalk.yellow(`\u2191 update available ${chalk.dim(inst.shortSha + " \u2192 " + shortSha(skill.sha))}`);
|
|
71
|
+
}
|
|
72
|
+
console.log(
|
|
73
|
+
` ${chalk.cyan.bold(skill.name.padEnd(24))} ${chalk.dim("@" + shortSha(skill.sha))} ${statusBadge}`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
export {
|
|
77
|
+
searchCommand
|
|
78
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {
|
|
2
|
+
injectSourceIntoSkillMd
|
|
3
|
+
} from "./chunk-KCQY4IDO.js";
|
|
4
|
+
import {
|
|
5
|
+
buildGigetSource,
|
|
6
|
+
latestShaForPath,
|
|
7
|
+
parseGitHubUrl
|
|
8
|
+
} from "./chunk-EU54UQ4C.js";
|
|
9
|
+
import {
|
|
10
|
+
getSkill,
|
|
11
|
+
readRegistry,
|
|
12
|
+
shortSha,
|
|
13
|
+
writeRegistry
|
|
14
|
+
} from "./chunk-ZW6ZKHTF.js";
|
|
15
|
+
|
|
16
|
+
// src/commands/set-source.ts
|
|
17
|
+
import { cancel, intro, outro, spinner } from "@clack/prompts";
|
|
18
|
+
import chalk from "chalk";
|
|
19
|
+
async function setSourceCommand(skillName, sourceArg) {
|
|
20
|
+
intro(chalk.bold("augy") + chalk.dim(" \u2014 set-source"));
|
|
21
|
+
const registry = await readRegistry();
|
|
22
|
+
const skill = getSkill(registry, skillName);
|
|
23
|
+
if (!skill) {
|
|
24
|
+
cancel(`Skill "${skillName}" not found. Run \`augy list\` to see installed skills.`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
const s = spinner();
|
|
28
|
+
s.start(`Resolving ${chalk.cyan(sourceArg)}\u2026`);
|
|
29
|
+
let sha;
|
|
30
|
+
let gigetSource;
|
|
31
|
+
try {
|
|
32
|
+
const coords = parseGitHubUrl(sourceArg);
|
|
33
|
+
const { owner, repo, path, ref } = coords;
|
|
34
|
+
sha = await latestShaForPath(owner, repo, path || ".", ref);
|
|
35
|
+
gigetSource = buildGigetSource(owner, repo, path, ref);
|
|
36
|
+
s.stop(
|
|
37
|
+
`Resolved ${chalk.dim(`${owner}/${repo}/${path}`)} ${chalk.green("@" + shortSha(sha))}`
|
|
38
|
+
);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
s.stop(chalk.red("Failed to resolve source"));
|
|
41
|
+
cancel(String(err));
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
skill.source = sourceArg;
|
|
45
|
+
skill.gigetSource = gigetSource;
|
|
46
|
+
skill.sha = sha;
|
|
47
|
+
skill.shortSha = shortSha(sha);
|
|
48
|
+
skill.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
49
|
+
registry.skills[skillName] = skill;
|
|
50
|
+
await writeRegistry(registry);
|
|
51
|
+
for (const [, install] of Object.entries(skill.agents)) {
|
|
52
|
+
if (install.active) {
|
|
53
|
+
await injectSourceIntoSkillMd(install.path, sourceArg).catch(() => void 0);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
outro(
|
|
57
|
+
chalk.green(`${skillName} source set`) + chalk.dim(` @${shortSha(sha)}`) + `
|
|
58
|
+
${chalk.dim("Updates and diffs are now available.")}`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
export {
|
|
62
|
+
setSourceCommand
|
|
63
|
+
};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseTapArg,
|
|
3
|
+
tapSource
|
|
4
|
+
} from "./chunk-YXCEZ3EY.js";
|
|
5
|
+
import {
|
|
6
|
+
discoverSkills,
|
|
7
|
+
parseGitHubUrl
|
|
8
|
+
} from "./chunk-EU54UQ4C.js";
|
|
9
|
+
import {
|
|
10
|
+
addTap,
|
|
11
|
+
listTaps,
|
|
12
|
+
readRegistry,
|
|
13
|
+
removeTap,
|
|
14
|
+
tapKey,
|
|
15
|
+
writeRegistry
|
|
16
|
+
} from "./chunk-ZW6ZKHTF.js";
|
|
17
|
+
|
|
18
|
+
// src/commands/tap.ts
|
|
19
|
+
import { cancel, confirm, intro, isCancel, outro, spinner, text } from "@clack/prompts";
|
|
20
|
+
import chalk from "chalk";
|
|
21
|
+
async function tapAddCommand(repoArg, opts) {
|
|
22
|
+
intro(chalk.bold("augy tap") + chalk.dim(" \u2014 add"));
|
|
23
|
+
let parsed;
|
|
24
|
+
try {
|
|
25
|
+
parsed = parseTapArg(repoArg);
|
|
26
|
+
} catch (err) {
|
|
27
|
+
cancel(String(err));
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
const { owner, repo } = parsed;
|
|
31
|
+
const key = tapKey(owner, repo);
|
|
32
|
+
const registry = await readRegistry();
|
|
33
|
+
if (registry.taps[key]) {
|
|
34
|
+
cancel(`Tap "${key}" is already registered.`);
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
let skillsPath = opts.path;
|
|
38
|
+
if (skillsPath === void 0) {
|
|
39
|
+
const answer = await text({
|
|
40
|
+
message: "Path within the repo where skills live (leave blank for repo root)",
|
|
41
|
+
placeholder: "skills",
|
|
42
|
+
defaultValue: "skills"
|
|
43
|
+
});
|
|
44
|
+
if (isCancel(answer)) {
|
|
45
|
+
cancel("Cancelled");
|
|
46
|
+
process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
skillsPath = answer.trim();
|
|
49
|
+
}
|
|
50
|
+
const s = spinner();
|
|
51
|
+
s.start(`Verifying ${chalk.cyan(key)}\u2026`);
|
|
52
|
+
let skillCount = 0;
|
|
53
|
+
try {
|
|
54
|
+
const source = tapSource(owner, repo, skillsPath);
|
|
55
|
+
const coords = parseGitHubUrl(source);
|
|
56
|
+
const skills = await discoverSkills(coords);
|
|
57
|
+
skillCount = skills.length;
|
|
58
|
+
s.stop(`Found ${chalk.green(String(skillCount))} skill(s) in ${chalk.cyan(key)}`);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
s.stop(chalk.yellow("Could not verify tap \u2014 will add anyway"));
|
|
61
|
+
console.log(chalk.dim(` ${String(err)}`));
|
|
62
|
+
}
|
|
63
|
+
const tap = {
|
|
64
|
+
owner,
|
|
65
|
+
repo,
|
|
66
|
+
skillsPath,
|
|
67
|
+
addedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
68
|
+
...opts.description ? { description: opts.description } : {}
|
|
69
|
+
};
|
|
70
|
+
addTap(registry, tap);
|
|
71
|
+
await writeRegistry(registry);
|
|
72
|
+
outro(
|
|
73
|
+
chalk.green(`Tap ${chalk.bold(key)} added`) + chalk.dim(skillCount ? ` (${skillCount} skills available)` : "")
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
async function tapRemoveCommand(repoArg) {
|
|
77
|
+
intro(chalk.bold("augy tap") + chalk.dim(" \u2014 remove"));
|
|
78
|
+
let parsed;
|
|
79
|
+
try {
|
|
80
|
+
parsed = parseTapArg(repoArg);
|
|
81
|
+
} catch (err) {
|
|
82
|
+
cancel(String(err));
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
const key = tapKey(parsed.owner, parsed.repo);
|
|
86
|
+
const registry = await readRegistry();
|
|
87
|
+
if (!registry.taps[key]) {
|
|
88
|
+
cancel(`Tap "${key}" is not registered.`);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
const affected = Object.values(registry.skills).filter((sk) => sk.tap === key);
|
|
92
|
+
if (affected.length) {
|
|
93
|
+
console.log(
|
|
94
|
+
chalk.yellow(
|
|
95
|
+
` ${affected.length} installed skill(s) came from this tap: ` + affected.map((s) => chalk.cyan(s.name)).join(", ")
|
|
96
|
+
)
|
|
97
|
+
);
|
|
98
|
+
console.log(chalk.dim(" They will remain installed but lose their tap association.\n"));
|
|
99
|
+
}
|
|
100
|
+
const ok = await confirm({ message: `Remove tap "${key}"?` });
|
|
101
|
+
if (isCancel(ok) || !ok) {
|
|
102
|
+
cancel("Cancelled");
|
|
103
|
+
process.exit(0);
|
|
104
|
+
}
|
|
105
|
+
for (const sk of affected) {
|
|
106
|
+
delete sk.tap;
|
|
107
|
+
registry.skills[sk.name] = sk;
|
|
108
|
+
}
|
|
109
|
+
removeTap(registry, key);
|
|
110
|
+
await writeRegistry(registry);
|
|
111
|
+
outro(chalk.green(`Tap ${chalk.bold(key)} removed`));
|
|
112
|
+
}
|
|
113
|
+
async function tapListCommand() {
|
|
114
|
+
const registry = await readRegistry();
|
|
115
|
+
const taps = listTaps(registry);
|
|
116
|
+
if (!taps.length) {
|
|
117
|
+
console.log(
|
|
118
|
+
chalk.dim("No taps registered.\n") + chalk.dim("Add one with: ") + chalk.bold("augy tap add owner/repo")
|
|
119
|
+
);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
console.log(`
|
|
123
|
+
${chalk.bold("Registered taps")} ${chalk.dim(`(${taps.length} total)`)}
|
|
124
|
+
`);
|
|
125
|
+
for (const tap of taps) {
|
|
126
|
+
const skillsFrom = Object.values(registry.skills).filter((s) => s.tap === tap.key).length;
|
|
127
|
+
const pathLabel = tap.skillsPath ? chalk.dim(`/${tap.skillsPath}`) : "";
|
|
128
|
+
console.log(
|
|
129
|
+
` ${chalk.cyan.bold(tap.key)}${pathLabel}` + (tap.description ? ` ${chalk.dim("\u2014")} ${tap.description}` : "")
|
|
130
|
+
);
|
|
131
|
+
console.log(` ${chalk.dim("added:")} ${new Date(tap.addedAt).toLocaleDateString()}`);
|
|
132
|
+
if (skillsFrom > 0) {
|
|
133
|
+
console.log(` ${chalk.dim("installed:")} ${skillsFrom} skill(s) from this tap`);
|
|
134
|
+
}
|
|
135
|
+
console.log();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
export {
|
|
139
|
+
tapAddCommand,
|
|
140
|
+
tapListCommand,
|
|
141
|
+
tapRemoveCommand
|
|
142
|
+
};
|