install-agent-skill 1.2.4 → 1.2.7
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/bin/add-skill.modular.js +103 -0
- package/bin/add-skill.v2.js +86 -35
- package/bin/lib/commands/install.js +28 -20
- package/bin/lib/commands/update.js +7 -10
- package/bin/lib/ui.js +3 -0
- package/package.json +2 -2
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* install-agent-skill
|
|
4
|
+
* Vercel-Style CLI - Modular Entry Point v2.1
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { c, step, fatal, intro, outro } from "./lib/ui.js";
|
|
8
|
+
import { command, params, flags, VERSION } from "./lib/config.js";
|
|
9
|
+
|
|
10
|
+
// --- MAIN ---
|
|
11
|
+
async function main() {
|
|
12
|
+
// Basic command routing
|
|
13
|
+
let cmdModule;
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
switch (command) {
|
|
17
|
+
case "list":
|
|
18
|
+
case "ls":
|
|
19
|
+
cmdModule = await import("./lib/commands/list.js");
|
|
20
|
+
await cmdModule.run();
|
|
21
|
+
break;
|
|
22
|
+
case "init":
|
|
23
|
+
cmdModule = await import("./lib/commands/init.js");
|
|
24
|
+
await cmdModule.run();
|
|
25
|
+
break;
|
|
26
|
+
case "install":
|
|
27
|
+
case "add":
|
|
28
|
+
case "i":
|
|
29
|
+
cmdModule = await import("./lib/commands/install.js");
|
|
30
|
+
await cmdModule.run(params[0]);
|
|
31
|
+
break;
|
|
32
|
+
case "uninstall":
|
|
33
|
+
case "remove":
|
|
34
|
+
case "rm":
|
|
35
|
+
cmdModule = await import("./lib/commands/uninstall.js");
|
|
36
|
+
await cmdModule.run(params[0]);
|
|
37
|
+
break;
|
|
38
|
+
case "update":
|
|
39
|
+
cmdModule = await import("./lib/commands/update.js");
|
|
40
|
+
await cmdModule.run(params[0]);
|
|
41
|
+
break;
|
|
42
|
+
case "lock":
|
|
43
|
+
cmdModule = await import("./lib/commands/lock.js");
|
|
44
|
+
await cmdModule.run();
|
|
45
|
+
break;
|
|
46
|
+
case "verify":
|
|
47
|
+
cmdModule = await import("./lib/commands/verify.js");
|
|
48
|
+
await cmdModule.run();
|
|
49
|
+
break;
|
|
50
|
+
case "doctor":
|
|
51
|
+
cmdModule = await import("./lib/commands/doctor.js");
|
|
52
|
+
await cmdModule.run();
|
|
53
|
+
break;
|
|
54
|
+
case "cache":
|
|
55
|
+
cmdModule = await import("./lib/commands/cache.js");
|
|
56
|
+
await cmdModule.run(params[0]);
|
|
57
|
+
break;
|
|
58
|
+
case "validate":
|
|
59
|
+
case "check":
|
|
60
|
+
cmdModule = await import("./lib/commands/validate.js");
|
|
61
|
+
await cmdModule.run(params[0]);
|
|
62
|
+
break;
|
|
63
|
+
case "analyze":
|
|
64
|
+
cmdModule = await import("./lib/commands/analyze.js");
|
|
65
|
+
await cmdModule.run(params[0]);
|
|
66
|
+
break;
|
|
67
|
+
case "info":
|
|
68
|
+
case "show":
|
|
69
|
+
cmdModule = await import("./lib/commands/info.js");
|
|
70
|
+
await cmdModule.run(params[0]);
|
|
71
|
+
break;
|
|
72
|
+
case "help":
|
|
73
|
+
case "--help":
|
|
74
|
+
case "-h":
|
|
75
|
+
cmdModule = await import("./lib/commands/help.js");
|
|
76
|
+
await cmdModule.run();
|
|
77
|
+
break;
|
|
78
|
+
case "--version":
|
|
79
|
+
case "-V":
|
|
80
|
+
console.log(VERSION);
|
|
81
|
+
break;
|
|
82
|
+
default:
|
|
83
|
+
// Handle direct install via org/repo syntax
|
|
84
|
+
if (command.includes("/")) {
|
|
85
|
+
cmdModule = await import("./lib/commands/install.js");
|
|
86
|
+
await cmdModule.run(command);
|
|
87
|
+
} else {
|
|
88
|
+
console.log(`Unknown command: ${command}`);
|
|
89
|
+
cmdModule = await import("./lib/commands/help.js");
|
|
90
|
+
await cmdModule.run();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} catch (err) {
|
|
94
|
+
console.error(c.red("\nError: " + err.message));
|
|
95
|
+
if (process.env.DEBUG) console.error(err.stack);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
main().catch(err => {
|
|
101
|
+
console.error(c.red("\nFatal Error: " + err.message));
|
|
102
|
+
process.exit(1);
|
|
103
|
+
});
|
package/bin/add-skill.v2.js
CHANGED
|
@@ -10,9 +10,9 @@ import os from "os";
|
|
|
10
10
|
import { execSync } from "child_process";
|
|
11
11
|
import crypto from "crypto";
|
|
12
12
|
import prompts from "prompts";
|
|
13
|
-
import { multiselect, isCancel, cancel, intro, outro, select, confirm } from "@clack/prompts";
|
|
13
|
+
import { multiselect, isCancel, cancel, intro, outro, select, confirm, log, spinner } from "@clack/prompts";
|
|
14
14
|
import kleur from "kleur";
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
import boxen from "boxen";
|
|
17
17
|
import { createRequire } from "module";
|
|
18
18
|
|
|
@@ -250,24 +250,54 @@ async function runInstall(spec) {
|
|
|
250
250
|
if (!spec) { fatal("Missing skill spec. Usage: add-skill <org/repo>"); return; }
|
|
251
251
|
const { org, repo, skill: singleSkill, ref } = parseSkillSpec(spec);
|
|
252
252
|
if (!org || !repo) { fatal("Invalid spec. Format: org/repo or org/repo#skill"); return; }
|
|
253
|
+
|
|
254
|
+
// Start Clack UI session
|
|
255
|
+
intro(c.bgCyan(c.black(" add-skill ")));
|
|
256
|
+
|
|
253
257
|
const url = `https://github.com/${org}/${repo}.git`;
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
const spinner = ora({ text: "Cloning repository", prefixText: ` ${c.gray(S.branch)} ${c.cyan(S.diamondFilled)} `, color: "cyan" }).start();
|
|
258
|
+
log.info(`Source: ${c.cyan(url)}`);
|
|
259
|
+
|
|
260
|
+
const s = spinner();
|
|
261
|
+
s.start("Cloning repository");
|
|
262
|
+
|
|
260
263
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "add-skill-"));
|
|
261
|
-
try {
|
|
262
|
-
|
|
264
|
+
try {
|
|
265
|
+
execSync(`git clone --depth=1 ${url} "${tmp}"`, { stdio: "pipe" });
|
|
266
|
+
if (ref) execSync(`git -C "${tmp}" checkout ${ref}`, { stdio: "pipe" });
|
|
267
|
+
} catch {
|
|
268
|
+
s.stop("Failed to clone", 1);
|
|
269
|
+
log.error("Failed to clone repository");
|
|
270
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
271
|
+
cancel("Operation cancelled");
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
s.stop("Repository cloned");
|
|
275
|
+
|
|
263
276
|
const skillsInRepo = [];
|
|
264
|
-
for (const e of fs.readdirSync(tmp)) {
|
|
265
|
-
|
|
266
|
-
|
|
277
|
+
for (const e of fs.readdirSync(tmp)) {
|
|
278
|
+
const sp = path.join(tmp, e);
|
|
279
|
+
if (fs.statSync(sp).isDirectory() && fs.existsSync(path.join(sp, "SKILL.md"))) {
|
|
280
|
+
const m = parseSkillMdFrontmatter(path.join(sp, "SKILL.md"));
|
|
281
|
+
skillsInRepo.push({
|
|
282
|
+
title: e + (m.description ? c.dim(` (${m.description.substring(0, 40)}...)`) : ""),
|
|
283
|
+
value: e,
|
|
284
|
+
selected: singleSkill ? e === singleSkill : true
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (skillsInRepo.length === 0) {
|
|
290
|
+
log.warn("No valid skills found in repository");
|
|
291
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
292
|
+
cancel("Operation cancelled");
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
log.info(`Found ${skillsInRepo.length} skills`);
|
|
267
297
|
|
|
268
298
|
// Use @clack/prompts for multiselect
|
|
269
299
|
const skillsR = await multiselect({
|
|
270
|
-
message: 'Select skills to install',
|
|
300
|
+
message: 'Select skills to install (Press Space to select, Enter to continue)',
|
|
271
301
|
options: skillsInRepo.map(s => ({
|
|
272
302
|
label: s.title,
|
|
273
303
|
value: s.value,
|
|
@@ -284,46 +314,66 @@ async function runInstall(spec) {
|
|
|
284
314
|
}
|
|
285
315
|
|
|
286
316
|
const selectedSkills = skillsR;
|
|
287
|
-
if (selectedSkills.length === 0) {
|
|
317
|
+
if (selectedSkills.length === 0) {
|
|
318
|
+
log.warn("No skills selected");
|
|
319
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
320
|
+
cancel("Operation cancelled");
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
288
323
|
|
|
324
|
+
// Agent selection
|
|
289
325
|
stepLine();
|
|
290
|
-
|
|
291
|
-
// but focusing on the requested "green square" UI which is multiselect.
|
|
292
|
-
// To match style, let's use clack select for scope too.
|
|
326
|
+
step("Detected 5 agents", S.diamond);
|
|
293
327
|
|
|
294
|
-
const
|
|
295
|
-
message: '
|
|
328
|
+
const agentsR = await multiselect({
|
|
329
|
+
message: 'Select agents to install skills to',
|
|
296
330
|
options: [
|
|
297
|
-
{ label: '
|
|
298
|
-
{ label: '
|
|
331
|
+
{ label: 'Antigravity (.agent/skills)', value: 'antigravity', selected: true },
|
|
332
|
+
{ label: c.dim('Claude Code'), value: 'claude', hint: c.dim('(not supported)') },
|
|
333
|
+
{ label: c.dim('Codex'), value: 'codex', hint: c.dim('(not supported)') },
|
|
334
|
+
{ label: c.dim('Gemini CLI'), value: 'gemini', hint: c.dim('(not supported)') },
|
|
335
|
+
{ label: c.dim('Windsurf'), value: 'windsurf', hint: c.dim('(not supported)') }
|
|
299
336
|
],
|
|
300
|
-
|
|
337
|
+
required: true
|
|
301
338
|
});
|
|
302
339
|
|
|
303
|
-
if (isCancel(
|
|
340
|
+
if (isCancel(agentsR)) {
|
|
304
341
|
cancel('Operation cancelled.');
|
|
305
342
|
fs.rmSync(tmp, { recursive: true, force: true });
|
|
306
343
|
return;
|
|
307
344
|
}
|
|
308
345
|
|
|
309
|
-
const
|
|
346
|
+
const selectedAgents = agentsR;
|
|
347
|
+
if (selectedAgents.includes('antigravity') === false) {
|
|
348
|
+
log.warn("Antigravity is currently the only supported agent. Selecting it automatically.");
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// For now, we only support Antigravity, effectively just checking if we continue
|
|
352
|
+
const targetScope = WORKSPACE;
|
|
310
353
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
354
|
+
log.info("Installing skills...");
|
|
355
|
+
fs.mkdirSync(targetScope, { recursive: true });
|
|
356
|
+
|
|
357
|
+
// Install loop
|
|
358
|
+
const sInstall = spinner();
|
|
359
|
+
sInstall.start("Copying files");
|
|
315
360
|
|
|
316
|
-
stepLine(); fs.mkdirSync(targetScope, { recursive: true });
|
|
317
361
|
for (const sn of selectedSkills) {
|
|
318
362
|
const src = path.join(tmp, sn), dest = path.join(targetScope, sn);
|
|
319
363
|
if (fs.existsSync(dest)) fs.rmSync(dest, { recursive: true, force: true });
|
|
320
364
|
fs.cpSync(src, dest, { recursive: true });
|
|
321
365
|
const hash = merkleHash(dest);
|
|
322
366
|
fs.writeFileSync(path.join(dest, ".skill-source.json"), JSON.stringify({ repo: `${org}/${repo}`, skill: sn, ref: ref || null, checksum: hash, installedAt: new Date().toISOString() }, null, 2));
|
|
323
|
-
step(`Installed: ${c.bold(sn)}`, S.check, "green");
|
|
324
367
|
}
|
|
368
|
+
sInstall.stop("Files copied");
|
|
369
|
+
|
|
370
|
+
for (const sn of selectedSkills) {
|
|
371
|
+
log.success(`Installed ${c.bold(sn)}`);
|
|
372
|
+
}
|
|
373
|
+
|
|
325
374
|
fs.rmSync(tmp, { recursive: true, force: true });
|
|
326
|
-
|
|
375
|
+
|
|
376
|
+
outro("Done!");
|
|
327
377
|
}
|
|
328
378
|
|
|
329
379
|
async function runUninstall(skillName) {
|
|
@@ -348,12 +398,13 @@ async function runUpdate(skillName) {
|
|
|
348
398
|
const meta = JSON.parse(fs.readFileSync(metaFile, "utf-8"));
|
|
349
399
|
if (!meta.repo || meta.repo === "local") fatal("Cannot update local skill");
|
|
350
400
|
stepLine();
|
|
351
|
-
const
|
|
401
|
+
const s = spinner();
|
|
402
|
+
s.start(`Updating ${skillName}`);
|
|
352
403
|
try {
|
|
353
404
|
if (!DRY) { createBackup(targetDir, skillName); fs.rmSync(targetDir, { recursive: true, force: true }); }
|
|
354
405
|
const spec = `${meta.repo}#${meta.skill}${meta.ref ? "@" + meta.ref : ""}`;
|
|
355
|
-
if (DRY) {
|
|
356
|
-
} catch (err) {
|
|
406
|
+
if (DRY) { s.stop(); step(`Would update: ${skillName}`, S.diamond); } else { await runInstall(spec); s.stop(); }
|
|
407
|
+
} catch (err) { s.stop(`Failed: ${err.message}`, 1); step(`Failed: ${err.message}`, S.cross, "red"); }
|
|
357
408
|
}
|
|
358
409
|
|
|
359
410
|
function runLock() {
|
|
@@ -7,11 +7,11 @@ import path from "path";
|
|
|
7
7
|
import os from "os";
|
|
8
8
|
import { execSync } from "child_process";
|
|
9
9
|
import prompts from "prompts";
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
import boxen from "boxen";
|
|
12
12
|
import { parseSkillSpec, merkleHash } from "../helpers.js";
|
|
13
13
|
import { parseSkillMdFrontmatter } from "../skills.js";
|
|
14
|
-
import { step, stepLine, S, c, fatal } from "../ui.js";
|
|
14
|
+
import { step, stepLine, S, c, fatal, spinner } from "../ui.js";
|
|
15
15
|
import { WORKSPACE, GLOBAL_DIR } from "../config.js";
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -36,11 +36,8 @@ export async function run(spec) {
|
|
|
36
36
|
stepLine();
|
|
37
37
|
step("Source: " + c.cyan(url), S.diamond);
|
|
38
38
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
prefixText: ` ${c.gray(S.branch)} ${c.cyan(S.diamondFilled)} `,
|
|
42
|
-
color: "cyan"
|
|
43
|
-
}).start();
|
|
39
|
+
const s = spinner();
|
|
40
|
+
s.start("Cloning repository");
|
|
44
41
|
|
|
45
42
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "add-skill-"));
|
|
46
43
|
|
|
@@ -48,14 +45,13 @@ export async function run(spec) {
|
|
|
48
45
|
execSync(`git clone --depth=1 ${url} "${tmp}"`, { stdio: "pipe" });
|
|
49
46
|
if (ref) execSync(`git -C "${tmp}" checkout ${ref}`, { stdio: "pipe" });
|
|
50
47
|
} catch {
|
|
51
|
-
|
|
48
|
+
s.stop("Failed to clone");
|
|
52
49
|
step(c.red("Failed to clone"), S.cross, "red");
|
|
53
50
|
fs.rmSync(tmp, { recursive: true, force: true });
|
|
54
51
|
return;
|
|
55
52
|
}
|
|
56
53
|
|
|
57
|
-
|
|
58
|
-
step("Repository cloned", S.check, "green");
|
|
54
|
+
s.stop("Repository cloned");
|
|
59
55
|
|
|
60
56
|
// Find skills in repo
|
|
61
57
|
const skillsInRepo = [];
|
|
@@ -109,7 +105,7 @@ export async function run(spec) {
|
|
|
109
105
|
value: s.value,
|
|
110
106
|
selected: true // Pre-select all by default
|
|
111
107
|
})),
|
|
112
|
-
hint: "- Space to
|
|
108
|
+
hint: "- Press Space to select, Enter to continue",
|
|
113
109
|
instructions: false
|
|
114
110
|
});
|
|
115
111
|
|
|
@@ -122,20 +118,32 @@ export async function run(spec) {
|
|
|
122
118
|
selectedSkills = skillsR.skills;
|
|
123
119
|
}
|
|
124
120
|
|
|
125
|
-
//
|
|
121
|
+
// Agent selection
|
|
126
122
|
stepLine();
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
123
|
+
step("Detected 5 agents", S.diamond);
|
|
124
|
+
|
|
125
|
+
const agentsR = await prompts({
|
|
126
|
+
type: "multiselect",
|
|
127
|
+
name: "agents",
|
|
128
|
+
message: "Select agents to install skills to",
|
|
131
129
|
choices: [
|
|
132
|
-
{ title: "
|
|
133
|
-
{ title: "
|
|
130
|
+
{ title: "Antigravity (.agent/skills)", value: "antigravity", selected: true },
|
|
131
|
+
{ title: c.dim("Claude Code"), value: "claude", disabled: true },
|
|
132
|
+
{ title: c.dim("Codex"), value: "codex", disabled: true },
|
|
133
|
+
{ title: c.dim("Gemini CLI"), value: "gemini", disabled: true },
|
|
134
|
+
{ title: c.dim("Windsurf"), value: "windsurf", disabled: true }
|
|
134
135
|
],
|
|
135
|
-
|
|
136
|
+
hint: "- Space to toggle. Enter to submit",
|
|
137
|
+
instructions: false
|
|
136
138
|
});
|
|
137
139
|
|
|
138
|
-
|
|
140
|
+
if (!agentsR.agents || agentsR.agents.length === 0) {
|
|
141
|
+
console.log(`\n ${c.yellow("No agents selected.")}`);
|
|
142
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const targetScope = WORKSPACE;
|
|
139
147
|
|
|
140
148
|
// Summary
|
|
141
149
|
stepLine();
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
import fs from "fs";
|
|
6
6
|
import path from "path";
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
import { resolveScope, createBackup } from "../helpers.js";
|
|
9
|
-
import { step, stepLine, S, c, fatal } from "../ui.js";
|
|
9
|
+
import { step, stepLine, S, c, fatal, spinner } from "../ui.js";
|
|
10
10
|
import { DRY } from "../config.js";
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -29,11 +29,8 @@ export async function run(skillName) {
|
|
|
29
29
|
|
|
30
30
|
stepLine();
|
|
31
31
|
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
prefixText: ` ${c.gray(S.branch)} ${c.cyan(S.diamondFilled)} `,
|
|
35
|
-
color: "cyan"
|
|
36
|
-
}).start();
|
|
32
|
+
const s = spinner();
|
|
33
|
+
s.start(`Updating ${skillName}`);
|
|
37
34
|
|
|
38
35
|
try {
|
|
39
36
|
if (!DRY) {
|
|
@@ -44,15 +41,15 @@ export async function run(skillName) {
|
|
|
44
41
|
const spec = `${meta.repo}#${meta.skill}${meta.ref ? "@" + meta.ref : ""}`;
|
|
45
42
|
|
|
46
43
|
if (DRY) {
|
|
47
|
-
|
|
44
|
+
s.stop();
|
|
48
45
|
step(`Would update: ${skillName}`);
|
|
49
46
|
} else {
|
|
50
47
|
// Dynamically import install command
|
|
51
48
|
const { run: install } = await import("./install.js");
|
|
52
49
|
await install(spec);
|
|
50
|
+
s.stop();
|
|
53
51
|
}
|
|
54
52
|
} catch (err) {
|
|
55
|
-
|
|
56
|
-
step(`Failed: ${err.message}`, S.cross, "red");
|
|
53
|
+
s.stop(`Failed: ${err.message}`);
|
|
57
54
|
}
|
|
58
55
|
}
|
package/bin/lib/ui.js
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import kleur from "kleur";
|
|
6
|
+
import { intro, outro, spinner, multiselect, select, confirm, isCancel, cancel, text } from "@clack/prompts";
|
|
7
|
+
|
|
8
|
+
export { intro, outro, spinner, multiselect, select, confirm, isCancel, cancel, text };
|
|
6
9
|
|
|
7
10
|
// --- Symbols ---
|
|
8
11
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "install-agent-skill",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.7",
|
|
4
4
|
"description": "Enterprise-grade Agent Skill Manager with Antigravity Skills support, Progressive Disclosure detection, and semantic routing validation",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "DataGuruIn <contact@dataguruin.com>",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"type": "module",
|
|
16
16
|
"bin": {
|
|
17
|
-
"add-skill": "./bin/add-skill.
|
|
17
|
+
"add-skill": "./bin/add-skill.modular.js"
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
20
|
"bin/",
|