add-skill-kit 2.3.2 → 3.2.1
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/lib/agents.js +208 -0
- package/bin/lib/commands/install.js +135 -135
- package/bin/lib/installer.js +115 -0
- package/bin/lib/ui.js +167 -6
- package/package.json +67 -64
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Agent definitions and detection
|
|
3
|
+
* Based on Vercel's agent-skills CLI structure
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { existsSync } from "fs";
|
|
7
|
+
import { homedir } from "os";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
|
|
10
|
+
const home = homedir();
|
|
11
|
+
|
|
12
|
+
// Environment-based paths
|
|
13
|
+
const codexHome = process.env.CODEX_HOME?.trim() || join(home, ".codex");
|
|
14
|
+
const claudeHome = process.env.CLAUDE_CONFIG_DIR?.trim() || join(home, ".claude");
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {Object} AgentConfig
|
|
18
|
+
* @property {string} name - Internal agent ID
|
|
19
|
+
* @property {string} displayName - Display name for UI
|
|
20
|
+
* @property {string} skillsDir - Project-level skills directory
|
|
21
|
+
* @property {string} globalSkillsDir - Global skills directory
|
|
22
|
+
* @property {() => boolean} detect - Detection function
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* All supported agents with detection logic
|
|
27
|
+
* @type {Record<string, AgentConfig>}
|
|
28
|
+
*/
|
|
29
|
+
export const AGENTS = {
|
|
30
|
+
antigravity: {
|
|
31
|
+
name: "antigravity",
|
|
32
|
+
displayName: "Antigravity",
|
|
33
|
+
skillsDir: ".agent/skills",
|
|
34
|
+
globalSkillsDir: join(home, ".gemini/antigravity/global_skills"),
|
|
35
|
+
detect: () => existsSync(join(process.cwd(), ".agent")) || existsSync(join(home, ".gemini/antigravity"))
|
|
36
|
+
},
|
|
37
|
+
"claude-code": {
|
|
38
|
+
name: "claude-code",
|
|
39
|
+
displayName: "Claude Code",
|
|
40
|
+
skillsDir: ".claude/skills",
|
|
41
|
+
globalSkillsDir: join(claudeHome, "skills"),
|
|
42
|
+
detect: () => existsSync(claudeHome)
|
|
43
|
+
},
|
|
44
|
+
codex: {
|
|
45
|
+
name: "codex",
|
|
46
|
+
displayName: "Codex",
|
|
47
|
+
skillsDir: ".codex/skills",
|
|
48
|
+
globalSkillsDir: join(codexHome, "skills"),
|
|
49
|
+
detect: () => existsSync(codexHome) || existsSync("/etc/codex")
|
|
50
|
+
},
|
|
51
|
+
"gemini-cli": {
|
|
52
|
+
name: "gemini-cli",
|
|
53
|
+
displayName: "Gemini CLI",
|
|
54
|
+
skillsDir: ".gemini/skills",
|
|
55
|
+
globalSkillsDir: join(home, ".gemini/skills"),
|
|
56
|
+
detect: () => existsSync(join(home, ".gemini"))
|
|
57
|
+
},
|
|
58
|
+
"github-copilot": {
|
|
59
|
+
name: "github-copilot",
|
|
60
|
+
displayName: "GitHub Copilot",
|
|
61
|
+
skillsDir: ".github/skills",
|
|
62
|
+
globalSkillsDir: join(home, ".copilot/skills"),
|
|
63
|
+
detect: () => existsSync(join(process.cwd(), ".github")) || existsSync(join(home, ".copilot"))
|
|
64
|
+
},
|
|
65
|
+
windsurf: {
|
|
66
|
+
name: "windsurf",
|
|
67
|
+
displayName: "Windsurf",
|
|
68
|
+
skillsDir: ".windsurf/skills",
|
|
69
|
+
globalSkillsDir: join(home, ".codeium/windsurf/skills"),
|
|
70
|
+
detect: () => existsSync(join(home, ".codeium/windsurf"))
|
|
71
|
+
},
|
|
72
|
+
cursor: {
|
|
73
|
+
name: "cursor",
|
|
74
|
+
displayName: "Cursor",
|
|
75
|
+
skillsDir: ".cursor/skills",
|
|
76
|
+
globalSkillsDir: join(home, ".cursor/skills"),
|
|
77
|
+
detect: () => existsSync(join(home, ".cursor"))
|
|
78
|
+
},
|
|
79
|
+
cline: {
|
|
80
|
+
name: "cline",
|
|
81
|
+
displayName: "Cline",
|
|
82
|
+
skillsDir: ".cline/skills",
|
|
83
|
+
globalSkillsDir: join(home, ".cline/skills"),
|
|
84
|
+
detect: () => existsSync(join(home, ".cline"))
|
|
85
|
+
},
|
|
86
|
+
roo: {
|
|
87
|
+
name: "roo",
|
|
88
|
+
displayName: "Roo Code",
|
|
89
|
+
skillsDir: ".roo/skills",
|
|
90
|
+
globalSkillsDir: join(home, ".roo/skills"),
|
|
91
|
+
detect: () => existsSync(join(home, ".roo"))
|
|
92
|
+
},
|
|
93
|
+
continue: {
|
|
94
|
+
name: "continue",
|
|
95
|
+
displayName: "Continue",
|
|
96
|
+
skillsDir: ".continue/skills",
|
|
97
|
+
globalSkillsDir: join(home, ".continue/skills"),
|
|
98
|
+
detect: () => existsSync(join(process.cwd(), ".continue")) || existsSync(join(home, ".continue"))
|
|
99
|
+
},
|
|
100
|
+
goose: {
|
|
101
|
+
name: "goose",
|
|
102
|
+
displayName: "Goose",
|
|
103
|
+
skillsDir: ".goose/skills",
|
|
104
|
+
globalSkillsDir: join(home, ".config/goose/skills"),
|
|
105
|
+
detect: () => existsSync(join(home, ".config/goose"))
|
|
106
|
+
},
|
|
107
|
+
trae: {
|
|
108
|
+
name: "trae",
|
|
109
|
+
displayName: "Trae",
|
|
110
|
+
skillsDir: ".trae/skills",
|
|
111
|
+
globalSkillsDir: join(home, ".trae/skills"),
|
|
112
|
+
detect: () => existsSync(join(home, ".trae"))
|
|
113
|
+
},
|
|
114
|
+
kilo: {
|
|
115
|
+
name: "kilo",
|
|
116
|
+
displayName: "Kilo Code",
|
|
117
|
+
skillsDir: ".kilocode/skills",
|
|
118
|
+
globalSkillsDir: join(home, ".kilocode/skills"),
|
|
119
|
+
detect: () => existsSync(join(home, ".kilocode"))
|
|
120
|
+
},
|
|
121
|
+
opencode: {
|
|
122
|
+
name: "opencode",
|
|
123
|
+
displayName: "OpenCode",
|
|
124
|
+
skillsDir: ".opencode/skills",
|
|
125
|
+
globalSkillsDir: join(home, ".config/opencode/skills"),
|
|
126
|
+
detect: () => existsSync(join(home, ".config/opencode"))
|
|
127
|
+
},
|
|
128
|
+
amp: {
|
|
129
|
+
name: "amp",
|
|
130
|
+
displayName: "Amp",
|
|
131
|
+
skillsDir: ".agents/skills",
|
|
132
|
+
globalSkillsDir: join(home, ".config/agents/skills"),
|
|
133
|
+
detect: () => existsSync(join(home, ".config/amp"))
|
|
134
|
+
},
|
|
135
|
+
junie: {
|
|
136
|
+
name: "junie",
|
|
137
|
+
displayName: "Junie",
|
|
138
|
+
skillsDir: ".junie/skills",
|
|
139
|
+
globalSkillsDir: join(home, ".junie/skills"),
|
|
140
|
+
detect: () => existsSync(join(home, ".junie"))
|
|
141
|
+
},
|
|
142
|
+
"kiro-cli": {
|
|
143
|
+
name: "kiro-cli",
|
|
144
|
+
displayName: "Kiro CLI",
|
|
145
|
+
skillsDir: ".kiro/skills",
|
|
146
|
+
globalSkillsDir: join(home, ".kiro/skills"),
|
|
147
|
+
detect: () => existsSync(join(home, ".kiro"))
|
|
148
|
+
},
|
|
149
|
+
zencoder: {
|
|
150
|
+
name: "zencoder",
|
|
151
|
+
displayName: "Zencoder",
|
|
152
|
+
skillsDir: ".zencoder/skills",
|
|
153
|
+
globalSkillsDir: join(home, ".zencoder/skills"),
|
|
154
|
+
detect: () => existsSync(join(home, ".zencoder"))
|
|
155
|
+
},
|
|
156
|
+
openhands: {
|
|
157
|
+
name: "openhands",
|
|
158
|
+
displayName: "OpenHands",
|
|
159
|
+
skillsDir: ".openhands/skills",
|
|
160
|
+
globalSkillsDir: join(home, ".openhands/skills"),
|
|
161
|
+
detect: () => existsSync(join(home, ".openhands"))
|
|
162
|
+
},
|
|
163
|
+
"qwen-code": {
|
|
164
|
+
name: "qwen-code",
|
|
165
|
+
displayName: "Qwen Code",
|
|
166
|
+
skillsDir: ".qwen/skills",
|
|
167
|
+
globalSkillsDir: join(home, ".qwen/skills"),
|
|
168
|
+
detect: () => existsSync(join(home, ".qwen"))
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Detect all installed agents on the system
|
|
174
|
+
* @returns {Array<{name: string, displayName: string, skillsDir: string, globalSkillsDir: string}>}
|
|
175
|
+
*/
|
|
176
|
+
export function detectInstalledAgents() {
|
|
177
|
+
const detected = [];
|
|
178
|
+
|
|
179
|
+
for (const [key, config] of Object.entries(AGENTS)) {
|
|
180
|
+
if (config.detect()) {
|
|
181
|
+
detected.push({
|
|
182
|
+
name: config.name,
|
|
183
|
+
displayName: config.displayName,
|
|
184
|
+
skillsDir: config.skillsDir,
|
|
185
|
+
globalSkillsDir: config.globalSkillsDir
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return detected;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Get agent config by name
|
|
195
|
+
* @param {string} name - Agent name
|
|
196
|
+
* @returns {AgentConfig | undefined}
|
|
197
|
+
*/
|
|
198
|
+
export function getAgentConfig(name) {
|
|
199
|
+
return AGENTS[name];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Get all agent names
|
|
204
|
+
* @returns {string[]}
|
|
205
|
+
*/
|
|
206
|
+
export function getAllAgentNames() {
|
|
207
|
+
return Object.keys(AGENTS);
|
|
208
|
+
}
|
|
@@ -133,10 +133,11 @@ export async function run(spec) {
|
|
|
133
133
|
if (fs.statSync(sp).isDirectory() && fs.existsSync(path.join(sp, "SKILL.md"))) {
|
|
134
134
|
const m = parseSkillMdFrontmatter(path.join(sp, "SKILL.md"));
|
|
135
135
|
skillsInRepo.push({
|
|
136
|
-
title: e
|
|
136
|
+
title: e, // Only show folder name
|
|
137
137
|
value: e,
|
|
138
|
+
description: m.description || "",
|
|
138
139
|
selected: singleSkill ? e === singleSkill : true,
|
|
139
|
-
_path: sp
|
|
140
|
+
_path: sp
|
|
140
141
|
});
|
|
141
142
|
}
|
|
142
143
|
}
|
|
@@ -167,177 +168,155 @@ export async function run(spec) {
|
|
|
167
168
|
stepLine();
|
|
168
169
|
step(`Auto-selected: ${c.cyan(singleSkill)}`);
|
|
169
170
|
} else {
|
|
170
|
-
//
|
|
171
|
-
|
|
171
|
+
// Group skills by category - expanded keywords for 75+ skills
|
|
172
|
+
const CATEGORY_KEYWORDS = {
|
|
173
|
+
"⚙️ Backend & API": ["backend", "api", "nodejs", "server", "database", "prisma", "mcp", "python", "cache", "input-validator"],
|
|
174
|
+
"🎨 Frontend & UI": ["frontend", "react", "nextjs", "tailwind", "css", "ui", "ux", "design", "visual", "studio", "web-core"],
|
|
175
|
+
"🧪 Testing & Quality": ["test", "tdd", "testing", "lint", "review", "code-review", "clean", "validate", "webapp-testing", "e2e", "integration-tester", "load-tester", "code-quality", "code-craft"],
|
|
176
|
+
"🔒 Security & DevOps": ["security", "vulnerability", "deploy", "git", "docker", "server-management", "red-team", "governance", "offensive", "gitops", "cicd", "pipeline", "incident", "chaos"],
|
|
177
|
+
"📱 Mobile": ["mobile", "react-native", "flutter", "ios", "android"],
|
|
178
|
+
"🧠 AI & Agents": ["agent", "routing", "brainstorm", "behavioral", "intelligent", "parallel", "reasoning", "creative", "idea", "context", "self-evolution", "auto-learn", "smart", "multi-agent"],
|
|
179
|
+
"📦 Architecture": ["architecture", "system", "pattern", "app-builder", "performance", "profiling", "perf", "scaffold", "workflow", "lifecycle", "state", "execution"],
|
|
180
|
+
"📝 Documentation": ["documentation", "plan", "writing", "geo", "seo", "i18n", "localization", "global", "doc-", "requirement", "diagram"],
|
|
181
|
+
"🎮 Game Development": ["game"],
|
|
182
|
+
"🖥️ CLI & Tools": ["bash", "linux", "powershell", "windows", "debugging", "systematic", "debug", "shell", "script", "logging", "tracing", "metrics", "observability"],
|
|
183
|
+
"🔧 Code Tools": ["skill-forge", "code-constitution", "typescript", "problem", "checker"]
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
function categorizeSkill(skillName) {
|
|
187
|
+
const lower = skillName.toLowerCase();
|
|
188
|
+
for (const [category, keywords] of Object.entries(CATEGORY_KEYWORDS)) {
|
|
189
|
+
if (keywords.some(kw => lower.includes(kw))) {
|
|
190
|
+
return category;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return "📚 Other";
|
|
194
|
+
}
|
|
172
195
|
|
|
173
|
-
//
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
//
|
|
182
|
-
|
|
196
|
+
// Group skills by category
|
|
197
|
+
const grouped = {};
|
|
198
|
+
for (const skill of skillsInRepo) {
|
|
199
|
+
const cat = categorizeSkill(skill.value);
|
|
200
|
+
if (!grouped[cat]) grouped[cat] = [];
|
|
201
|
+
grouped[cat].push(skill);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Custom sort: alphabetical but "Other" always last
|
|
205
|
+
const sortedCategories = Object.keys(grouped).sort((a, b) => {
|
|
206
|
+
if (a.includes("Other")) return 1;
|
|
207
|
+
if (b.includes("Other")) return -1;
|
|
208
|
+
return a.localeCompare(b);
|
|
209
|
+
});
|
|
183
210
|
|
|
184
|
-
activeStep("Select skills to install");
|
|
185
211
|
|
|
186
|
-
|
|
212
|
+
stepLine();
|
|
213
|
+
activeStep("Select skill categories to install");
|
|
214
|
+
|
|
215
|
+
// Show only categories, not individual skills
|
|
216
|
+
const selectedCategories = await multiselect({
|
|
187
217
|
message: `${c.cyan("space")} select · ${c.cyan("enter")} confirm`,
|
|
188
|
-
options:
|
|
189
|
-
label:
|
|
190
|
-
value:
|
|
218
|
+
options: sortedCategories.map(cat => ({
|
|
219
|
+
label: `${cat} (${grouped[cat].length} skills)`,
|
|
220
|
+
value: cat,
|
|
221
|
+
hint: grouped[cat].slice(0, 3).map(s => s.value).join(", ") + (grouped[cat].length > 3 ? "..." : "")
|
|
191
222
|
})),
|
|
192
|
-
initialValues:
|
|
223
|
+
initialValues: sortedCategories, // Pre-select all
|
|
193
224
|
required: true
|
|
194
225
|
});
|
|
195
226
|
|
|
196
|
-
if (isCancel(
|
|
227
|
+
if (isCancel(selectedCategories)) {
|
|
197
228
|
cancel("Cancelled.");
|
|
198
229
|
fs.rmSync(tmp, { recursive: true, force: true });
|
|
199
230
|
return;
|
|
200
231
|
}
|
|
201
232
|
|
|
202
|
-
|
|
233
|
+
// Get all skills from selected categories
|
|
234
|
+
selectedSkills = selectedCategories.flatMap(cat => grouped[cat].map(s => s.value));
|
|
203
235
|
}
|
|
204
236
|
|
|
205
|
-
|
|
237
|
+
|
|
238
|
+
|
|
206
239
|
stepLine();
|
|
207
240
|
step("Select skills to install");
|
|
208
241
|
console.log(`${c.gray(S.branch)} ${c.dim(selectedSkills.join(", "))}`);
|
|
209
242
|
|
|
210
|
-
// ---
|
|
243
|
+
// --- Detect installed agents ---
|
|
244
|
+
stepLine();
|
|
245
|
+
const { detectInstalledAgents } = await import("../agents.js");
|
|
246
|
+
const detectedAgents = detectInstalledAgents();
|
|
247
|
+
|
|
248
|
+
if (detectedAgents.length === 0) {
|
|
249
|
+
step(c.yellow("No agents detected"), S.diamond, "yellow");
|
|
250
|
+
step(c.dim("Please install at least one AI agent (Antigravity, Claude Code, etc.)"), S.branch, "gray");
|
|
251
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
211
254
|
|
|
212
|
-
|
|
213
|
-
let isGlobal = false;
|
|
255
|
+
step(`Detected ${detectedAgents.length} agents`);
|
|
214
256
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
} else {
|
|
218
|
-
activeStep("Select installation scope");
|
|
219
|
-
|
|
220
|
-
const scopeSelection = await select({
|
|
221
|
-
message: " ",
|
|
222
|
-
options: [
|
|
223
|
-
{
|
|
224
|
-
label: "Current Project",
|
|
225
|
-
value: "local",
|
|
226
|
-
hint: "Installs to .agent/ (Best for project-specific skills)"
|
|
227
|
-
},
|
|
228
|
-
{
|
|
229
|
-
label: "Global System",
|
|
230
|
-
value: "global",
|
|
231
|
-
hint: "Installs to ~/.gemini/ (Available to all projects via 'agent' command)"
|
|
232
|
-
}
|
|
233
|
-
],
|
|
234
|
-
initialValue: "local"
|
|
235
|
-
});
|
|
257
|
+
// --- Select agents (Vercel-style) ---
|
|
258
|
+
const { selectAgentsPrompt, selectScopePrompt, selectMethodPrompt } = await import("../ui.js");
|
|
236
259
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
260
|
+
stepLine();
|
|
261
|
+
activeStep("Install to");
|
|
262
|
+
const selectedAgents = await selectAgentsPrompt(detectedAgents);
|
|
242
263
|
|
|
243
|
-
|
|
264
|
+
if (!selectedAgents || selectedAgents.length === 0) {
|
|
265
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
266
|
+
return;
|
|
244
267
|
}
|
|
245
|
-
const targetScope = isGlobal ? GLOBAL_DIR : WORKSPACE;
|
|
246
268
|
|
|
247
269
|
stepLine();
|
|
248
|
-
step("
|
|
249
|
-
console.log(`${c.gray(S.branch)} ${c.dim(
|
|
250
|
-
|
|
251
|
-
// Agent selection - currently only Antigravity supported
|
|
252
|
-
const availableAgents = [
|
|
253
|
-
{ label: "Antigravity (.agent/skills)", value: "antigravity", available: true },
|
|
254
|
-
{ label: "Claude Code (coming soon)", value: "claude", available: false },
|
|
255
|
-
{ label: "Codex (coming soon)", value: "codex", available: false },
|
|
256
|
-
{ label: "Gemini CLI (coming soon)", value: "gemini", available: false },
|
|
257
|
-
{ label: "Windsurf (coming soon)", value: "windsurf", available: false }
|
|
258
|
-
];
|
|
259
|
-
const activeAgentCount = availableAgents.filter(a => a.available).length;
|
|
260
|
-
stepLine();
|
|
261
|
-
step(`Detected ${availableAgents.length} agents (${activeAgentCount} available)`);
|
|
270
|
+
step("Install to");
|
|
271
|
+
console.log(`${c.gray(S.branch)} ${c.dim(selectedAgents.map(a => a.displayName).join(", "))}`);
|
|
262
272
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
// Active Step
|
|
266
|
-
activeStep("Select agents to install skills to (Antigravity only)");
|
|
273
|
+
// --- Select installation scope ---
|
|
274
|
+
let isGlobal = GLOBAL;
|
|
267
275
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
value: a.value
|
|
273
|
-
})),
|
|
274
|
-
initialValues: ["antigravity"],
|
|
275
|
-
required: true
|
|
276
|
-
});
|
|
276
|
+
if (!GLOBAL) {
|
|
277
|
+
stepLine();
|
|
278
|
+
activeStep("Installation scope");
|
|
279
|
+
const scope = await selectScopePrompt();
|
|
277
280
|
|
|
278
|
-
if (
|
|
279
|
-
cancel("Cancelled.");
|
|
281
|
+
if (!scope) {
|
|
280
282
|
fs.rmSync(tmp, { recursive: true, force: true });
|
|
281
283
|
return;
|
|
282
284
|
}
|
|
283
285
|
|
|
284
|
-
|
|
285
|
-
if (invalidAgents.length > 0) {
|
|
286
|
-
step(`Selection contains coming soon agents. Only Antigravity is currently supported.`, S.cross, "red");
|
|
287
|
-
stepLine();
|
|
288
|
-
continue;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
break;
|
|
286
|
+
isGlobal = scope === "global";
|
|
292
287
|
}
|
|
293
288
|
|
|
294
|
-
if (!agents || agents.length === 0) {
|
|
295
|
-
console.log(`\n ${c.yellow("No agents selected.")}`);
|
|
296
|
-
fs.rmSync(tmp, { recursive: true, force: true });
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// Agent summary
|
|
301
289
|
stepLine();
|
|
302
|
-
step("
|
|
303
|
-
console.log(`${c.gray(S.branch)} ${c.dim(
|
|
290
|
+
step("Installation scope");
|
|
291
|
+
console.log(`${c.gray(S.branch)} ${c.dim(isGlobal ? "Global" : "Project")}`);
|
|
304
292
|
|
|
305
|
-
//
|
|
293
|
+
// --- Select installation method ---
|
|
294
|
+
stepLine();
|
|
306
295
|
activeStep("Installation method");
|
|
296
|
+
const installMethod = await selectMethodPrompt();
|
|
307
297
|
|
|
308
|
-
|
|
309
|
-
message: " ",
|
|
310
|
-
options: [
|
|
311
|
-
{ label: "Symlink (Recommended)", value: "symlink", hint: "Single source of truth, easy updates" },
|
|
312
|
-
{ label: "Copy to all agents", value: "copy" }
|
|
313
|
-
],
|
|
314
|
-
initialValue: "symlink"
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
if (isCancel(installMethod)) {
|
|
318
|
-
cancel("Cancelled.");
|
|
298
|
+
if (!installMethod) {
|
|
319
299
|
fs.rmSync(tmp, { recursive: true, force: true });
|
|
320
300
|
return;
|
|
321
301
|
}
|
|
322
302
|
|
|
303
|
+
|
|
323
304
|
// Installation Summary Box
|
|
324
305
|
stepLine();
|
|
325
|
-
step("Installation
|
|
306
|
+
step("Installation method");
|
|
307
|
+
console.log(`${c.gray(S.branch)} ${c.dim(installMethod === "symlink" ? "Symlink" : "Copy")}`);
|
|
308
|
+
|
|
309
|
+
stepLine();
|
|
310
|
+
step("Installation Summary");
|
|
326
311
|
stepLine();
|
|
327
312
|
|
|
328
|
-
const
|
|
329
|
-
const agentsString = selectedAgentsList.map(a =>
|
|
330
|
-
a === "antigravity" ? "Antigravity" :
|
|
331
|
-
a.charAt(0).toUpperCase() + a.slice(1)
|
|
332
|
-
).join(", ");
|
|
313
|
+
const agentsString = selectedAgents.map(a => a.displayName).join(", ");
|
|
333
314
|
|
|
334
315
|
let summaryContent = "";
|
|
335
316
|
const methodVerb = installMethod === "symlink" ? "symlink" : "copy";
|
|
336
317
|
|
|
337
318
|
for (const sn of selectedSkills) {
|
|
338
|
-
|
|
339
|
-
const targetPath = path.relative(process.cwd(), path.join(targetScope, sn));
|
|
340
|
-
summaryContent += `${c.cyan(targetPath)}\n`;
|
|
319
|
+
summaryContent += `${c.cyan(sn)}\n`;
|
|
341
320
|
summaryContent += ` ${c.dim(methodVerb)} ${c.gray("→")} ${c.dim(agentsString)}\n\n`;
|
|
342
321
|
}
|
|
343
322
|
|
|
@@ -356,7 +335,6 @@ export async function run(spec) {
|
|
|
356
335
|
stepLine();
|
|
357
336
|
|
|
358
337
|
// Confirmation
|
|
359
|
-
// Active Step
|
|
360
338
|
activeStep("Proceed with installation?");
|
|
361
339
|
const shouldProceed = await confirm({ message: " ", initialValue: true });
|
|
362
340
|
|
|
@@ -366,29 +344,51 @@ export async function run(spec) {
|
|
|
366
344
|
return;
|
|
367
345
|
}
|
|
368
346
|
|
|
369
|
-
// Install
|
|
347
|
+
// Install skills to multiple agents
|
|
370
348
|
stepLine();
|
|
371
|
-
|
|
349
|
+
const { installSkillForAgents } = await import("../installer.js");
|
|
372
350
|
|
|
373
351
|
// Create a map for skill paths
|
|
374
352
|
const skillPathMap = Object.fromEntries(skillsInRepo.map(s => [s.value, s._path]));
|
|
375
353
|
|
|
354
|
+
const installResults = { success: [], failed: [] };
|
|
355
|
+
|
|
376
356
|
for (const sn of selectedSkills) {
|
|
377
357
|
const src = skillPathMap[sn] || path.join(skillsDir || tmp, sn);
|
|
378
|
-
const dest = path.join(targetScope, sn);
|
|
379
358
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
359
|
+
const is = spinner();
|
|
360
|
+
is.start(`Installing ${sn} to ${selectedAgents.length} agents`);
|
|
361
|
+
|
|
362
|
+
const result = await installSkillForAgents(src, sn, selectedAgents, {
|
|
363
|
+
method: installMethod,
|
|
364
|
+
scope: isGlobal ? "global" : "project",
|
|
365
|
+
metadata: {
|
|
366
|
+
repo: `${org}/${repo}`,
|
|
367
|
+
ref: ref || null
|
|
368
|
+
}
|
|
384
369
|
});
|
|
370
|
+
|
|
371
|
+
installResults.success.push(...result.success);
|
|
372
|
+
installResults.failed.push(...result.failed);
|
|
373
|
+
|
|
374
|
+
if (result.failed.length === 0) {
|
|
375
|
+
is.stop(`Installed ${sn} (${result.success.length} agents)`);
|
|
376
|
+
} else {
|
|
377
|
+
is.stop(`${sn}: ${result.success.length} success, ${result.failed.length} failed`);
|
|
378
|
+
}
|
|
385
379
|
}
|
|
386
380
|
|
|
381
|
+
|
|
382
|
+
// Derive base .agent directory from skillsDir
|
|
383
|
+
// If skillsDir is .../skills, then baseAgentDir is parent (.agent)
|
|
384
|
+
const baseAgentDir = skillsDir ? path.dirname(skillsDir) : path.join(tmp, ".agent");
|
|
385
|
+
|
|
387
386
|
// Install workflows if they exist
|
|
388
|
-
const workflowsDir = path.join(
|
|
387
|
+
const workflowsDir = path.join(baseAgentDir, "workflows");
|
|
389
388
|
const targetWorkflowsDir = path.join(WORKSPACE, "..", "workflows");
|
|
390
389
|
let workflowsInstalled = 0;
|
|
391
390
|
|
|
391
|
+
|
|
392
392
|
if (fs.existsSync(workflowsDir)) {
|
|
393
393
|
stepLine();
|
|
394
394
|
const ws = spinner();
|
|
@@ -411,7 +411,7 @@ export async function run(spec) {
|
|
|
411
411
|
}
|
|
412
412
|
|
|
413
413
|
// Install GEMINI.md if it exists
|
|
414
|
-
const geminiSrc = path.join(
|
|
414
|
+
const geminiSrc = path.join(baseAgentDir, "GEMINI.md");
|
|
415
415
|
const geminiDest = path.join(WORKSPACE, "..", "GEMINI.md");
|
|
416
416
|
let geminiInstalled = false;
|
|
417
417
|
|
|
@@ -423,7 +423,7 @@ export async function run(spec) {
|
|
|
423
423
|
}
|
|
424
424
|
|
|
425
425
|
// Install agents if they exist
|
|
426
|
-
const agentsDir = path.join(
|
|
426
|
+
const agentsDir = path.join(baseAgentDir, "agents");
|
|
427
427
|
const targetAgentsDir = path.join(WORKSPACE, "..", "agents");
|
|
428
428
|
let agentsInstalled = 0;
|
|
429
429
|
|
|
@@ -449,7 +449,7 @@ export async function run(spec) {
|
|
|
449
449
|
}
|
|
450
450
|
|
|
451
451
|
// Install ARCHITECTURE.md if it exists
|
|
452
|
-
const archSrc = path.join(
|
|
452
|
+
const archSrc = path.join(baseAgentDir, "ARCHITECTURE.md");
|
|
453
453
|
const archDest = path.join(WORKSPACE, "..", "ARCHITECTURE.md");
|
|
454
454
|
let archInstalled = false;
|
|
455
455
|
|
|
@@ -460,7 +460,7 @@ export async function run(spec) {
|
|
|
460
460
|
}
|
|
461
461
|
|
|
462
462
|
// Install knowledge if it exists
|
|
463
|
-
const knowledgeDir = path.join(
|
|
463
|
+
const knowledgeDir = path.join(baseAgentDir, "knowledge");
|
|
464
464
|
const targetKnowledgeDir = path.join(WORKSPACE, "..", "knowledge");
|
|
465
465
|
let knowledgeInstalled = false;
|
|
466
466
|
|
|
@@ -471,7 +471,7 @@ export async function run(spec) {
|
|
|
471
471
|
}
|
|
472
472
|
|
|
473
473
|
// Install rules if they exist
|
|
474
|
-
const rulesDir = path.join(
|
|
474
|
+
const rulesDir = path.join(baseAgentDir, "rules");
|
|
475
475
|
const targetRulesDir = path.join(WORKSPACE, "..", "rules");
|
|
476
476
|
let rulesInstalled = 0;
|
|
477
477
|
|
package/bin/lib/installer.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
+
import { homedir } from "os";
|
|
3
4
|
import { GLOBAL_DIR } from "./config.js";
|
|
4
5
|
import { merkleHash } from "./helpers.js";
|
|
6
|
+
import { AGENTS } from "./agents.js";
|
|
7
|
+
|
|
8
|
+
const home = homedir();
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* Install a skill to the destination using the specified method.
|
|
@@ -47,3 +51,114 @@ export async function installSkill(src, dest, method, metadata) {
|
|
|
47
51
|
method: method
|
|
48
52
|
}, null, 2));
|
|
49
53
|
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Install a skill to multiple agents
|
|
57
|
+
* @param {string} src - Source directory containing the skill
|
|
58
|
+
* @param {string} skillName - Name of the skill
|
|
59
|
+
* @param {Array<{name: string, displayName: string, skillsDir: string, globalSkillsDir: string}>} agents - Agents to install to
|
|
60
|
+
* @param {Object} options - Installation options
|
|
61
|
+
* @param {string} options.method - 'symlink' or 'copy'
|
|
62
|
+
* @param {string} options.scope - 'project' or 'global'
|
|
63
|
+
* @param {Object} options.metadata - Metadata for tracking
|
|
64
|
+
* @returns {Promise<{success: Array, failed: Array}>}
|
|
65
|
+
*/
|
|
66
|
+
export async function installSkillForAgents(src, skillName, agents, options = {}) {
|
|
67
|
+
const { method = "symlink", scope = "project", metadata = {} } = options;
|
|
68
|
+
const results = { success: [], failed: [] };
|
|
69
|
+
|
|
70
|
+
// For symlink mode: first copy to canonical location
|
|
71
|
+
let canonicalPath = null;
|
|
72
|
+
|
|
73
|
+
if (method === "symlink") {
|
|
74
|
+
// Canonical: .agents/skills/<skill-name> or ~/.agents/skills/<skill-name>
|
|
75
|
+
const baseDir = scope === "global" ? home : process.cwd();
|
|
76
|
+
canonicalPath = path.join(baseDir, ".agents", "skills", skillName);
|
|
77
|
+
|
|
78
|
+
// Ensure fresh copy in canonical
|
|
79
|
+
if (fs.existsSync(canonicalPath)) {
|
|
80
|
+
fs.rmSync(canonicalPath, { recursive: true, force: true });
|
|
81
|
+
}
|
|
82
|
+
fs.mkdirSync(path.dirname(canonicalPath), { recursive: true });
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
await fs.promises.cp(src, canonicalPath, { recursive: true });
|
|
86
|
+
|
|
87
|
+
// Write metadata to canonical location
|
|
88
|
+
const hash = merkleHash(canonicalPath);
|
|
89
|
+
const metaFile = path.join(canonicalPath, ".skill-source.json");
|
|
90
|
+
fs.writeFileSync(metaFile, JSON.stringify({
|
|
91
|
+
...metadata,
|
|
92
|
+
skillName,
|
|
93
|
+
checksum: hash,
|
|
94
|
+
installedAt: new Date().toISOString(),
|
|
95
|
+
method: method,
|
|
96
|
+
scope: scope,
|
|
97
|
+
agents: agents.map(a => a.name)
|
|
98
|
+
}, null, 2));
|
|
99
|
+
} catch (err) {
|
|
100
|
+
// If canonical copy fails, abort
|
|
101
|
+
return {
|
|
102
|
+
success: [],
|
|
103
|
+
failed: agents.map(a => ({ agent: a.displayName, error: `Canonical copy failed: ${err.message}` }))
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Install to each agent
|
|
109
|
+
for (const agent of agents) {
|
|
110
|
+
const agentConfig = AGENTS[agent.name];
|
|
111
|
+
if (!agentConfig) {
|
|
112
|
+
results.failed.push({ agent: agent.displayName, error: "Unknown agent" });
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Determine destination path
|
|
117
|
+
const baseDir = scope === "global" ? agentConfig.globalSkillsDir : path.join(process.cwd(), agentConfig.skillsDir);
|
|
118
|
+
const destPath = path.join(baseDir, skillName);
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
// Ensure parent directory exists
|
|
122
|
+
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
|
123
|
+
|
|
124
|
+
// Remove existing if any
|
|
125
|
+
if (fs.existsSync(destPath)) {
|
|
126
|
+
fs.rmSync(destPath, { recursive: true, force: true });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (method === "symlink" && canonicalPath) {
|
|
130
|
+
// Create symlink to canonical location
|
|
131
|
+
try {
|
|
132
|
+
fs.symlinkSync(canonicalPath, destPath, "junction");
|
|
133
|
+
results.success.push({ agent: agent.displayName, path: destPath, mode: "symlink" });
|
|
134
|
+
} catch (symlinkErr) {
|
|
135
|
+
// Fallback to copy if symlink fails (Windows permissions)
|
|
136
|
+
await fs.promises.cp(canonicalPath, destPath, { recursive: true });
|
|
137
|
+
results.success.push({ agent: agent.displayName, path: destPath, mode: "copy (symlink failed)" });
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
// Direct copy
|
|
141
|
+
await fs.promises.cp(src, destPath, { recursive: true });
|
|
142
|
+
|
|
143
|
+
// Write metadata
|
|
144
|
+
const hash = merkleHash(destPath);
|
|
145
|
+
const metaFile = path.join(destPath, ".skill-source.json");
|
|
146
|
+
fs.writeFileSync(metaFile, JSON.stringify({
|
|
147
|
+
...metadata,
|
|
148
|
+
skillName,
|
|
149
|
+
checksum: hash,
|
|
150
|
+
installedAt: new Date().toISOString(),
|
|
151
|
+
method: "copy",
|
|
152
|
+
scope: scope
|
|
153
|
+
}, null, 2));
|
|
154
|
+
|
|
155
|
+
results.success.push({ agent: agent.displayName, path: destPath, mode: "copy" });
|
|
156
|
+
}
|
|
157
|
+
} catch (err) {
|
|
158
|
+
results.failed.push({ agent: agent.displayName, error: err.message });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return results;
|
|
163
|
+
}
|
|
164
|
+
|
package/bin/lib/ui.js
CHANGED
|
@@ -6,9 +6,23 @@ import kleur from "kleur";
|
|
|
6
6
|
import boxen from "boxen";
|
|
7
7
|
import { intro, outro, multiselect, select, confirm, isCancel, cancel, text } from "@clack/prompts";
|
|
8
8
|
import ora from "ora";
|
|
9
|
+
import gradient from "gradient-string";
|
|
9
10
|
|
|
10
11
|
export { intro, outro, multiselect, select, confirm, isCancel, cancel, text };
|
|
11
12
|
|
|
13
|
+
// --- ASCII Art Banner ---
|
|
14
|
+
const PIKAKIT_BANNER = `
|
|
15
|
+
██████╗ ██╗██╗ ██╗ █████╗ ██╗ ██╗██╗████████╗
|
|
16
|
+
██╔══██╗██║██║ ██╔╝██╔══██╗██║ ██╔╝██║╚══██╔══╝
|
|
17
|
+
██████╔╝██║█████╔╝ ███████║█████╔╝ ██║ ██║
|
|
18
|
+
██╔═══╝ ██║██╔═██╗ ██╔══██║██╔═██╗ ██║ ██║
|
|
19
|
+
██║ ██║██║ ██╗██║ ██║██║ ██╗██║ ██║
|
|
20
|
+
╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
// Custom gradient: white → gray (like vercel style)
|
|
24
|
+
const pikaGradient = gradient(['#ffffff', '#bbbbbb', '#888888', '#555555']);
|
|
25
|
+
|
|
12
26
|
/**
|
|
13
27
|
* Create a spinner
|
|
14
28
|
*/
|
|
@@ -148,15 +162,162 @@ export function box(message, options = {}) {
|
|
|
148
162
|
}
|
|
149
163
|
|
|
150
164
|
/**
|
|
151
|
-
* Show branded intro with version
|
|
165
|
+
* Show branded intro with version (matches agent CLI style)
|
|
152
166
|
* @param {string} version - Package version
|
|
153
167
|
* @param {string} [status] - Optional status text
|
|
154
168
|
*/
|
|
155
169
|
export function brandedIntro(version, status = "") {
|
|
156
|
-
|
|
157
|
-
console.log(
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
));
|
|
170
|
+
// Print ASCII art banner with gradient
|
|
171
|
+
console.log(pikaGradient(PIKAKIT_BANNER));
|
|
172
|
+
|
|
173
|
+
// Version info
|
|
174
|
+
console.log(c.dim(` v${version}\n`));
|
|
175
|
+
|
|
176
|
+
if (status) {
|
|
177
|
+
console.log(`${c.dim(status)}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// --- Vercel-Style Installation Prompts ---
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Prompt user to select which agents to install to
|
|
185
|
+
* @param {Array<{name: string, displayName: string, skillsDir: string}>} detectedAgents
|
|
186
|
+
* @returns {Promise<Array<{name: string, displayName: string, skillsDir: string}> | null>}
|
|
187
|
+
*/
|
|
188
|
+
export async function selectAgentsPrompt(detectedAgents) {
|
|
189
|
+
if (detectedAgents.length === 0) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// First ask: All detected or select specific?
|
|
194
|
+
const installChoice = await select({
|
|
195
|
+
message: "Install to",
|
|
196
|
+
options: [
|
|
197
|
+
{
|
|
198
|
+
value: "all",
|
|
199
|
+
label: `All detected agents (Recommended)`,
|
|
200
|
+
hint: `Install to all ${detectedAgents.length} detected agents`
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
value: "select",
|
|
204
|
+
label: "Select specific agents",
|
|
205
|
+
hint: "Choose which agents to install to"
|
|
206
|
+
}
|
|
207
|
+
]
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
if (isCancel(installChoice)) {
|
|
211
|
+
cancel("Installation cancelled");
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (installChoice === "all") {
|
|
216
|
+
return detectedAgents;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Let user select specific agents
|
|
220
|
+
const selectedAgents = await multiselect({
|
|
221
|
+
message: "Select agents to install skills to",
|
|
222
|
+
options: detectedAgents.map(agent => ({
|
|
223
|
+
value: agent.name,
|
|
224
|
+
label: agent.displayName,
|
|
225
|
+
hint: agent.skillsDir
|
|
226
|
+
})),
|
|
227
|
+
required: true
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
if (isCancel(selectedAgents)) {
|
|
231
|
+
cancel("Installation cancelled");
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return detectedAgents.filter(a => selectedAgents.includes(a.name));
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Prompt user to select installation scope (Project or Global)
|
|
240
|
+
* @returns {Promise<"project" | "global" | null>}
|
|
241
|
+
*/
|
|
242
|
+
export async function selectScopePrompt() {
|
|
243
|
+
const scope = await select({
|
|
244
|
+
message: "Installation scope",
|
|
245
|
+
options: [
|
|
246
|
+
{
|
|
247
|
+
value: "project",
|
|
248
|
+
label: "Project",
|
|
249
|
+
hint: "Install in current directory (committed with your project)"
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
value: "global",
|
|
253
|
+
label: "Global",
|
|
254
|
+
hint: "Install globally (available across all projects)"
|
|
255
|
+
}
|
|
256
|
+
]
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
if (isCancel(scope)) {
|
|
260
|
+
cancel("Installation cancelled");
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return scope;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Prompt user to select installation method (Symlink or Copy)
|
|
269
|
+
* @returns {Promise<"symlink" | "copy" | null>}
|
|
270
|
+
*/
|
|
271
|
+
export async function selectMethodPrompt() {
|
|
272
|
+
const method = await select({
|
|
273
|
+
message: "Installation method",
|
|
274
|
+
options: [
|
|
275
|
+
{
|
|
276
|
+
value: "symlink",
|
|
277
|
+
label: "Symlink (Recommended)",
|
|
278
|
+
hint: "Single source of truth, easy updates"
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
value: "copy",
|
|
282
|
+
label: "Copy to all agents",
|
|
283
|
+
hint: "Independent copies for each agent"
|
|
284
|
+
}
|
|
285
|
+
]
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
if (isCancel(method)) {
|
|
289
|
+
cancel("Installation cancelled");
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return method;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Prompt user to select skills to install (multiselect with descriptions)
|
|
298
|
+
* @param {Array<{name: string, description: string, path: string}>} skills
|
|
299
|
+
* @returns {Promise<Array<{name: string, description: string, path: string}> | null>}
|
|
300
|
+
*/
|
|
301
|
+
export async function selectSkillsPrompt(skills) {
|
|
302
|
+
if (skills.length === 0) {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const selectedNames = await multiselect({
|
|
307
|
+
message: "Select skills to install",
|
|
308
|
+
options: skills.map(skill => ({
|
|
309
|
+
value: skill.name,
|
|
310
|
+
label: skill.name,
|
|
311
|
+
hint: skill.description ? skill.description.substring(0, 60) + "..." : ""
|
|
312
|
+
})),
|
|
313
|
+
required: true
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
if (isCancel(selectedNames)) {
|
|
317
|
+
cancel("Installation cancelled");
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return skills.filter(s => selectedNames.includes(s.name));
|
|
161
322
|
}
|
|
162
323
|
|
package/package.json
CHANGED
|
@@ -1,64 +1,67 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "add-skill-kit",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Enterprise-grade Agent Skill Manager with Antigravity Skills support, Progressive Disclosure detection, and semantic routing validation",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": "agentskillkit <agentskillkit@gmail.com>",
|
|
7
|
-
"homepage": "https://github.com/agentskillkit/add-skill-kit",
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "https://github.com/agentskillkit/add-skill-kit.git"
|
|
11
|
-
},
|
|
12
|
-
"bugs": {
|
|
13
|
-
"url": "https://github.com/agentskillkit/add-skill-kit/issues"
|
|
14
|
-
},
|
|
15
|
-
"type": "module",
|
|
16
|
-
"bin": {
|
|
17
|
-
"kit": "./bin/cli.js"
|
|
18
|
-
},
|
|
19
|
-
"files": [
|
|
20
|
-
"bin/",
|
|
21
|
-
"specs/",
|
|
22
|
-
"README.md",
|
|
23
|
-
"LICENSE"
|
|
24
|
-
],
|
|
25
|
-
"engines": {
|
|
26
|
-
"node": ">=18.0.0"
|
|
27
|
-
},
|
|
28
|
-
"keywords": [
|
|
29
|
-
"agent",
|
|
30
|
-
"ai",
|
|
31
|
-
"skills",
|
|
32
|
-
"cli",
|
|
33
|
-
"tooling",
|
|
34
|
-
"registry",
|
|
35
|
-
"security",
|
|
36
|
-
"devops",
|
|
37
|
-
"automation",
|
|
38
|
-
"antigravity"
|
|
39
|
-
],
|
|
40
|
-
"scripts": {
|
|
41
|
-
"lint": "eslint bin/",
|
|
42
|
-
"lint:fix": "eslint bin/ --fix",
|
|
43
|
-
"format": "prettier --write bin/",
|
|
44
|
-
"test": "vitest run",
|
|
45
|
-
"test:watch": "vitest",
|
|
46
|
-
"ci": "npm run lint && npm test && node bin/cli.js verify --strict && node bin/cli.js doctor --strict"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"
|
|
63
|
-
|
|
64
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "add-skill-kit",
|
|
3
|
+
"version": "3.2.1",
|
|
4
|
+
"description": "Enterprise-grade Agent Skill Manager with Antigravity Skills support, Progressive Disclosure detection, and semantic routing validation",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "agentskillkit <agentskillkit@gmail.com>",
|
|
7
|
+
"homepage": "https://github.com/agentskillkit/add-skill-kit",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/agentskillkit/add-skill-kit.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/agentskillkit/add-skill-kit/issues"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"bin": {
|
|
17
|
+
"kit": "./bin/cli.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"bin/",
|
|
21
|
+
"specs/",
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18.0.0"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"agent",
|
|
30
|
+
"ai",
|
|
31
|
+
"skills",
|
|
32
|
+
"cli",
|
|
33
|
+
"tooling",
|
|
34
|
+
"registry",
|
|
35
|
+
"security",
|
|
36
|
+
"devops",
|
|
37
|
+
"automation",
|
|
38
|
+
"antigravity"
|
|
39
|
+
],
|
|
40
|
+
"scripts": {
|
|
41
|
+
"lint": "eslint bin/",
|
|
42
|
+
"lint:fix": "eslint bin/ --fix",
|
|
43
|
+
"format": "prettier --write bin/",
|
|
44
|
+
"test": "vitest run",
|
|
45
|
+
"test:watch": "vitest",
|
|
46
|
+
"ci": "npm run lint && npm test && node bin/cli.js verify --strict && node bin/cli.js doctor --strict",
|
|
47
|
+
"agent": "agent"
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@clack/prompts": "^0.9.1",
|
|
54
|
+
"boxen": "^8.0.1",
|
|
55
|
+
"chalk": "^5.4.1",
|
|
56
|
+
"gradient-string": "^2.0.2",
|
|
57
|
+
"kleur": "^4.1.5",
|
|
58
|
+
"ora": "^8.1.0",
|
|
59
|
+
"prompts": "^2.4.2"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"agentskillskit-cli": "^3.2.0",
|
|
63
|
+
"eslint": "^8.57.0",
|
|
64
|
+
"prettier": "^3.2.5",
|
|
65
|
+
"vitest": "^1.6.0"
|
|
66
|
+
}
|
|
67
|
+
}
|