add-skill-kit 3.2.7 → 3.2.8
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/kit.js +89 -89
- package/bin/lib/agents.js +208 -208
- package/bin/lib/commands/analyze.js +70 -70
- package/bin/lib/commands/cache.js +65 -65
- package/bin/lib/commands/doctor.js +75 -75
- package/bin/lib/commands/help.js +155 -155
- package/bin/lib/commands/info.js +38 -38
- package/bin/lib/commands/init.js +39 -39
- package/bin/lib/commands/install.js +803 -803
- package/bin/lib/commands/list.js +43 -43
- package/bin/lib/commands/lock.js +57 -57
- package/bin/lib/commands/uninstall.js +307 -307
- package/bin/lib/commands/update.js +55 -55
- package/bin/lib/commands/validate.js +69 -69
- package/bin/lib/commands/verify.js +56 -56
- package/bin/lib/config.js +81 -81
- package/bin/lib/helpers.js +196 -196
- package/bin/lib/helpers.test.js +60 -60
- package/bin/lib/installer.js +164 -164
- package/bin/lib/skills.js +119 -119
- package/bin/lib/skills.test.js +109 -109
- package/bin/lib/types.js +82 -82
- package/bin/lib/ui.js +329 -329
- package/package.json +1 -1
package/bin/lib/ui.js
CHANGED
|
@@ -1,329 +1,329 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview UI components - Install Agent Skill theme
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import kleur from "kleur";
|
|
6
|
-
import boxen from "boxen";
|
|
7
|
-
import { intro, outro, multiselect, select, confirm, isCancel, cancel, text } from "@clack/prompts";
|
|
8
|
-
import ora from "ora";
|
|
9
|
-
import gradient from "gradient-string";
|
|
10
|
-
|
|
11
|
-
export { intro, outro, multiselect, select, confirm, isCancel, cancel, text };
|
|
12
|
-
|
|
13
|
-
// --- ASCII Art Banner ---
|
|
14
|
-
const PIKAKIT_BANNER = `
|
|
15
|
-
____ _ _ _ ___ _
|
|
16
|
-
| _ \\(_) | ____ _| |/ (_) |_
|
|
17
|
-
| |_) | | |/ / _\` | ' /| | __|
|
|
18
|
-
| __/| | < (_| | . \\| | |_
|
|
19
|
-
|_| |_|_|\\_\\__,_|_|\\_\\_|\\__|
|
|
20
|
-
`;
|
|
21
|
-
|
|
22
|
-
// Custom gradient: white
|
|
23
|
-
const pikaGradient = gradient(['#ffffff', '#bbbbbb', '#888888', '#555555']);
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Create a spinner
|
|
27
|
-
*/
|
|
28
|
-
export function spinner() {
|
|
29
|
-
return {
|
|
30
|
-
_s: null,
|
|
31
|
-
start(msg) {
|
|
32
|
-
this._s = ora({
|
|
33
|
-
text: " " + msg,
|
|
34
|
-
prefixText: "",
|
|
35
|
-
color: "blue",
|
|
36
|
-
spinner: {
|
|
37
|
-
interval: 80,
|
|
38
|
-
frames: ['
|
|
39
|
-
}
|
|
40
|
-
}).start();
|
|
41
|
-
},
|
|
42
|
-
stop(msg) {
|
|
43
|
-
if (this._s) {
|
|
44
|
-
this._s.stopAndPersist({
|
|
45
|
-
symbol: c.cyan(S.diamond),
|
|
46
|
-
text: " " + msg
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
fail(msg) {
|
|
51
|
-
if (this._s) {
|
|
52
|
-
this._s.stopAndPersist({
|
|
53
|
-
symbol: c.red(S.cross),
|
|
54
|
-
text: " " + msg
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
message(msg) {
|
|
59
|
-
if (this._s) this._s.text = " " + msg;
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// --- Symbols ---
|
|
65
|
-
|
|
66
|
-
/** UI symbols for tree structure */
|
|
67
|
-
export const S = {
|
|
68
|
-
branch: "
|
|
69
|
-
diamond: "
|
|
70
|
-
diamondFilled: "
|
|
71
|
-
check: "
|
|
72
|
-
cross: "x",
|
|
73
|
-
arrow: "
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
// --- Colors ---
|
|
77
|
-
|
|
78
|
-
/** Color helper functions */
|
|
79
|
-
export const c = {
|
|
80
|
-
cyan: kleur.cyan,
|
|
81
|
-
gray: kleur.gray,
|
|
82
|
-
green: kleur.green,
|
|
83
|
-
red: kleur.red,
|
|
84
|
-
yellow: kleur.yellow,
|
|
85
|
-
magenta: kleur.magenta,
|
|
86
|
-
blue: kleur.blue,
|
|
87
|
-
white: kleur.white,
|
|
88
|
-
bgBlue: kleur.bgBlue,
|
|
89
|
-
bold: kleur.bold,
|
|
90
|
-
dim: kleur.dim,
|
|
91
|
-
inverse: kleur.inverse
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
// --- UI Functions ---
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Print a step in the tree
|
|
98
|
-
* @param {string} text - Step text
|
|
99
|
-
* @param {string} [icon] - Icon to use
|
|
100
|
-
* @param {keyof typeof c} [color] - Color name
|
|
101
|
-
*/
|
|
102
|
-
export function step(text, icon = S.diamond, color = "cyan") {
|
|
103
|
-
const colorFn = c[color] || c.cyan;
|
|
104
|
-
console.log(`${colorFn(icon)} ${text}`);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Print an active step (Blue Filled Diamond)
|
|
109
|
-
* @param {string} text - Step text
|
|
110
|
-
*/
|
|
111
|
-
export function activeStep(text) {
|
|
112
|
-
console.log(`${c.blue(S.diamondFilled)} ${text}`);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Print empty branch line
|
|
117
|
-
*/
|
|
118
|
-
export function stepLine() {
|
|
119
|
-
console.log(`${c.gray(S.branch)}`);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Print fatal error and exit
|
|
124
|
-
* @param {string} msg - Error message
|
|
125
|
-
*/
|
|
126
|
-
export function fatal(msg) {
|
|
127
|
-
console.log(`${c.red(S.cross)} ${c.red(msg)}`);
|
|
128
|
-
process.exit(1);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Print success message
|
|
133
|
-
* @param {string} msg - Success message
|
|
134
|
-
*/
|
|
135
|
-
export function success(msg) {
|
|
136
|
-
console.log(`${c.cyan(S.diamond)} ${c.cyan(msg)}`);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Output JSON if JSON_OUTPUT mode
|
|
141
|
-
* @param {any} data - Data to output
|
|
142
|
-
* @param {boolean} jsonMode - Whether to output JSON
|
|
143
|
-
*/
|
|
144
|
-
export function outputJSON(data, jsonMode) {
|
|
145
|
-
if (jsonMode) console.log(JSON.stringify(data, null, 2));
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Create a nice box message
|
|
150
|
-
* @param {string} message - Message content
|
|
151
|
-
* @param {object} options - Box options
|
|
152
|
-
*/
|
|
153
|
-
export function box(message, options = {}) {
|
|
154
|
-
return "\n" + boxen(message, {
|
|
155
|
-
padding: { top: 0, bottom: 0, left: 1, right: 1 },
|
|
156
|
-
margin: { top: 0, bottom: 0, left: 0, right: 0 },
|
|
157
|
-
borderStyle: "round",
|
|
158
|
-
borderColor: "blue",
|
|
159
|
-
...options
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Show branded intro with version (matches agent CLI style)
|
|
165
|
-
* @param {string} version - Package version
|
|
166
|
-
* @param {string} [status] - Optional status text
|
|
167
|
-
*/
|
|
168
|
-
export function brandedIntro(version, status = "") {
|
|
169
|
-
// Split banner and filter to get content lines only
|
|
170
|
-
const bannerLines = PIKAKIT_BANNER.split('\n').filter(line => line.trim() !== '');
|
|
171
|
-
|
|
172
|
-
// Print all lines except the last with gradient
|
|
173
|
-
for (let i = 0; i < bannerLines.length - 1; i++) {
|
|
174
|
-
console.log(pikaGradient(bannerLines[i]));
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Last line: gradient ASCII + dim version (aligned at bottom)
|
|
178
|
-
const lastLine = bannerLines[bannerLines.length - 1];
|
|
179
|
-
console.log(pikaGradient(lastLine) + ` ${c.dim(`v${version}`)}`);
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
if (status) {
|
|
183
|
-
console.log(`${c.dim(status)}`);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// --- Vercel-Style Installation Prompts ---
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Prompt user to select which agents to install to
|
|
191
|
-
* @param {Array<{name: string, displayName: string, skillsDir: string}>} detectedAgents
|
|
192
|
-
* @returns {Promise<Array<{name: string, displayName: string, skillsDir: string}> | null>}
|
|
193
|
-
*/
|
|
194
|
-
export async function selectAgentsPrompt(detectedAgents) {
|
|
195
|
-
if (detectedAgents.length === 0) {
|
|
196
|
-
return null;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// First ask: All detected or select specific?
|
|
200
|
-
const installChoice = await select({
|
|
201
|
-
message: "Install to",
|
|
202
|
-
options: [
|
|
203
|
-
{
|
|
204
|
-
value: "all",
|
|
205
|
-
label: `All detected agents (Recommended)`,
|
|
206
|
-
hint: `Install to all ${detectedAgents.length} detected agents`
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
value: "select",
|
|
210
|
-
label: "Select specific agents",
|
|
211
|
-
hint: "Choose which agents to install to"
|
|
212
|
-
}
|
|
213
|
-
]
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
if (isCancel(installChoice)) {
|
|
217
|
-
cancel("Installation cancelled");
|
|
218
|
-
return null;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (installChoice === "all") {
|
|
222
|
-
return detectedAgents;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Let user select specific agents
|
|
226
|
-
const selectedAgents = await multiselect({
|
|
227
|
-
message: "Select agents to install skills to",
|
|
228
|
-
options: detectedAgents.map(agent => ({
|
|
229
|
-
value: agent.name,
|
|
230
|
-
label: agent.displayName,
|
|
231
|
-
hint: agent.skillsDir
|
|
232
|
-
})),
|
|
233
|
-
required: true
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
if (isCancel(selectedAgents)) {
|
|
237
|
-
cancel("Installation cancelled");
|
|
238
|
-
return null;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return detectedAgents.filter(a => selectedAgents.includes(a.name));
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Prompt user to select installation scope (Project or Global)
|
|
246
|
-
* @returns {Promise<"project" | "global" | null>}
|
|
247
|
-
*/
|
|
248
|
-
export async function selectScopePrompt() {
|
|
249
|
-
const scope = await select({
|
|
250
|
-
message: "Installation scope",
|
|
251
|
-
options: [
|
|
252
|
-
{
|
|
253
|
-
value: "project",
|
|
254
|
-
label: "Project",
|
|
255
|
-
hint: "Install in current directory (committed with your project)"
|
|
256
|
-
},
|
|
257
|
-
{
|
|
258
|
-
value: "global",
|
|
259
|
-
label: "Global",
|
|
260
|
-
hint: "Install globally (available across all projects)"
|
|
261
|
-
}
|
|
262
|
-
]
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
if (isCancel(scope)) {
|
|
266
|
-
cancel("Installation cancelled");
|
|
267
|
-
return null;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
return scope;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Prompt user to select installation method (Symlink or Copy)
|
|
275
|
-
* @returns {Promise<"symlink" | "copy" | null>}
|
|
276
|
-
*/
|
|
277
|
-
export async function selectMethodPrompt() {
|
|
278
|
-
const method = await select({
|
|
279
|
-
message: "Installation method",
|
|
280
|
-
options: [
|
|
281
|
-
{
|
|
282
|
-
value: "symlink",
|
|
283
|
-
label: "Symlink (Recommended)",
|
|
284
|
-
hint: "Single source of truth, easy updates"
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
value: "copy",
|
|
288
|
-
label: "Copy to all agents",
|
|
289
|
-
hint: "Independent copies for each agent"
|
|
290
|
-
}
|
|
291
|
-
]
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
if (isCancel(method)) {
|
|
295
|
-
cancel("Installation cancelled");
|
|
296
|
-
return null;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
return method;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Prompt user to select skills to install (multiselect with descriptions)
|
|
304
|
-
* @param {Array<{name: string, description: string, path: string}>} skills
|
|
305
|
-
* @returns {Promise<Array<{name: string, description: string, path: string}> | null>}
|
|
306
|
-
*/
|
|
307
|
-
export async function selectSkillsPrompt(skills) {
|
|
308
|
-
if (skills.length === 0) {
|
|
309
|
-
return null;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
const selectedNames = await multiselect({
|
|
313
|
-
message: "Select skills to install",
|
|
314
|
-
options: skills.map(skill => ({
|
|
315
|
-
value: skill.name,
|
|
316
|
-
label: skill.name,
|
|
317
|
-
hint: skill.description ? skill.description.substring(0, 60) + "..." : ""
|
|
318
|
-
})),
|
|
319
|
-
required: true
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
if (isCancel(selectedNames)) {
|
|
323
|
-
cancel("Installation cancelled");
|
|
324
|
-
return null;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
return skills.filter(s => selectedNames.includes(s.name));
|
|
328
|
-
}
|
|
329
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview UI components - Install Agent Skill theme
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import kleur from "kleur";
|
|
6
|
+
import boxen from "boxen";
|
|
7
|
+
import { intro, outro, multiselect, select, confirm, isCancel, cancel, text } from "@clack/prompts";
|
|
8
|
+
import ora from "ora";
|
|
9
|
+
import gradient from "gradient-string";
|
|
10
|
+
|
|
11
|
+
export { intro, outro, multiselect, select, confirm, isCancel, cancel, text };
|
|
12
|
+
|
|
13
|
+
// --- ASCII Art Banner ---
|
|
14
|
+
const PIKAKIT_BANNER = `
|
|
15
|
+
____ _ _ _ ___ _
|
|
16
|
+
| _ \\(_) | ____ _| |/ (_) |_
|
|
17
|
+
| |_) | | |/ / _\` | ' /| | __|
|
|
18
|
+
| __/| | < (_| | . \\| | |_
|
|
19
|
+
|_| |_|_|\\_\\__,_|_|\\_\\_|\\__|
|
|
20
|
+
`;
|
|
21
|
+
|
|
22
|
+
// Custom gradient: white → gray (like vercel style)
|
|
23
|
+
const pikaGradient = gradient(['#ffffff', '#bbbbbb', '#888888', '#555555']);
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Create a spinner
|
|
27
|
+
*/
|
|
28
|
+
export function spinner() {
|
|
29
|
+
return {
|
|
30
|
+
_s: null,
|
|
31
|
+
start(msg) {
|
|
32
|
+
this._s = ora({
|
|
33
|
+
text: " " + msg,
|
|
34
|
+
prefixText: "",
|
|
35
|
+
color: "blue",
|
|
36
|
+
spinner: {
|
|
37
|
+
interval: 80,
|
|
38
|
+
frames: ['â—’', 'â—', 'â—“', 'â—‘']
|
|
39
|
+
}
|
|
40
|
+
}).start();
|
|
41
|
+
},
|
|
42
|
+
stop(msg) {
|
|
43
|
+
if (this._s) {
|
|
44
|
+
this._s.stopAndPersist({
|
|
45
|
+
symbol: c.cyan(S.diamond),
|
|
46
|
+
text: " " + msg
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
fail(msg) {
|
|
51
|
+
if (this._s) {
|
|
52
|
+
this._s.stopAndPersist({
|
|
53
|
+
symbol: c.red(S.cross),
|
|
54
|
+
text: " " + msg
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
message(msg) {
|
|
59
|
+
if (this._s) this._s.text = " " + msg;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// --- Symbols ---
|
|
65
|
+
|
|
66
|
+
/** UI symbols for tree structure */
|
|
67
|
+
export const S = {
|
|
68
|
+
branch: "│",
|
|
69
|
+
diamond: "â—‡",
|
|
70
|
+
diamondFilled: "â—†",
|
|
71
|
+
check: "✓",
|
|
72
|
+
cross: "x",
|
|
73
|
+
arrow: "→"
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// --- Colors ---
|
|
77
|
+
|
|
78
|
+
/** Color helper functions */
|
|
79
|
+
export const c = {
|
|
80
|
+
cyan: kleur.cyan,
|
|
81
|
+
gray: kleur.gray,
|
|
82
|
+
green: kleur.green,
|
|
83
|
+
red: kleur.red,
|
|
84
|
+
yellow: kleur.yellow,
|
|
85
|
+
magenta: kleur.magenta,
|
|
86
|
+
blue: kleur.blue,
|
|
87
|
+
white: kleur.white,
|
|
88
|
+
bgBlue: kleur.bgBlue,
|
|
89
|
+
bold: kleur.bold,
|
|
90
|
+
dim: kleur.dim,
|
|
91
|
+
inverse: kleur.inverse
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// --- UI Functions ---
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Print a step in the tree
|
|
98
|
+
* @param {string} text - Step text
|
|
99
|
+
* @param {string} [icon] - Icon to use
|
|
100
|
+
* @param {keyof typeof c} [color] - Color name
|
|
101
|
+
*/
|
|
102
|
+
export function step(text, icon = S.diamond, color = "cyan") {
|
|
103
|
+
const colorFn = c[color] || c.cyan;
|
|
104
|
+
console.log(`${colorFn(icon)} ${text}`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Print an active step (Blue Filled Diamond)
|
|
109
|
+
* @param {string} text - Step text
|
|
110
|
+
*/
|
|
111
|
+
export function activeStep(text) {
|
|
112
|
+
console.log(`${c.blue(S.diamondFilled)} ${text}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Print empty branch line
|
|
117
|
+
*/
|
|
118
|
+
export function stepLine() {
|
|
119
|
+
console.log(`${c.gray(S.branch)}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Print fatal error and exit
|
|
124
|
+
* @param {string} msg - Error message
|
|
125
|
+
*/
|
|
126
|
+
export function fatal(msg) {
|
|
127
|
+
console.log(`${c.red(S.cross)} ${c.red(msg)}`);
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Print success message
|
|
133
|
+
* @param {string} msg - Success message
|
|
134
|
+
*/
|
|
135
|
+
export function success(msg) {
|
|
136
|
+
console.log(`${c.cyan(S.diamond)} ${c.cyan(msg)}`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Output JSON if JSON_OUTPUT mode
|
|
141
|
+
* @param {any} data - Data to output
|
|
142
|
+
* @param {boolean} jsonMode - Whether to output JSON
|
|
143
|
+
*/
|
|
144
|
+
export function outputJSON(data, jsonMode) {
|
|
145
|
+
if (jsonMode) console.log(JSON.stringify(data, null, 2));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Create a nice box message
|
|
150
|
+
* @param {string} message - Message content
|
|
151
|
+
* @param {object} options - Box options
|
|
152
|
+
*/
|
|
153
|
+
export function box(message, options = {}) {
|
|
154
|
+
return "\n" + boxen(message, {
|
|
155
|
+
padding: { top: 0, bottom: 0, left: 1, right: 1 },
|
|
156
|
+
margin: { top: 0, bottom: 0, left: 0, right: 0 },
|
|
157
|
+
borderStyle: "round",
|
|
158
|
+
borderColor: "blue",
|
|
159
|
+
...options
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Show branded intro with version (matches agent CLI style)
|
|
165
|
+
* @param {string} version - Package version
|
|
166
|
+
* @param {string} [status] - Optional status text
|
|
167
|
+
*/
|
|
168
|
+
export function brandedIntro(version, status = "") {
|
|
169
|
+
// Split banner and filter to get content lines only
|
|
170
|
+
const bannerLines = PIKAKIT_BANNER.split('\n').filter(line => line.trim() !== '');
|
|
171
|
+
|
|
172
|
+
// Print all lines except the last with gradient
|
|
173
|
+
for (let i = 0; i < bannerLines.length - 1; i++) {
|
|
174
|
+
console.log(pikaGradient(bannerLines[i]));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Last line: gradient ASCII + dim version (aligned at bottom)
|
|
178
|
+
const lastLine = bannerLines[bannerLines.length - 1];
|
|
179
|
+
console.log(pikaGradient(lastLine) + ` ${c.dim(`v${version}`)}`);
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
if (status) {
|
|
183
|
+
console.log(`${c.dim(status)}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// --- Vercel-Style Installation Prompts ---
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Prompt user to select which agents to install to
|
|
191
|
+
* @param {Array<{name: string, displayName: string, skillsDir: string}>} detectedAgents
|
|
192
|
+
* @returns {Promise<Array<{name: string, displayName: string, skillsDir: string}> | null>}
|
|
193
|
+
*/
|
|
194
|
+
export async function selectAgentsPrompt(detectedAgents) {
|
|
195
|
+
if (detectedAgents.length === 0) {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// First ask: All detected or select specific?
|
|
200
|
+
const installChoice = await select({
|
|
201
|
+
message: "Install to",
|
|
202
|
+
options: [
|
|
203
|
+
{
|
|
204
|
+
value: "all",
|
|
205
|
+
label: `All detected agents (Recommended)`,
|
|
206
|
+
hint: `Install to all ${detectedAgents.length} detected agents`
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
value: "select",
|
|
210
|
+
label: "Select specific agents",
|
|
211
|
+
hint: "Choose which agents to install to"
|
|
212
|
+
}
|
|
213
|
+
]
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
if (isCancel(installChoice)) {
|
|
217
|
+
cancel("Installation cancelled");
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (installChoice === "all") {
|
|
222
|
+
return detectedAgents;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Let user select specific agents
|
|
226
|
+
const selectedAgents = await multiselect({
|
|
227
|
+
message: "Select agents to install skills to",
|
|
228
|
+
options: detectedAgents.map(agent => ({
|
|
229
|
+
value: agent.name,
|
|
230
|
+
label: agent.displayName,
|
|
231
|
+
hint: agent.skillsDir
|
|
232
|
+
})),
|
|
233
|
+
required: true
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
if (isCancel(selectedAgents)) {
|
|
237
|
+
cancel("Installation cancelled");
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return detectedAgents.filter(a => selectedAgents.includes(a.name));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Prompt user to select installation scope (Project or Global)
|
|
246
|
+
* @returns {Promise<"project" | "global" | null>}
|
|
247
|
+
*/
|
|
248
|
+
export async function selectScopePrompt() {
|
|
249
|
+
const scope = await select({
|
|
250
|
+
message: "Installation scope",
|
|
251
|
+
options: [
|
|
252
|
+
{
|
|
253
|
+
value: "project",
|
|
254
|
+
label: "Project",
|
|
255
|
+
hint: "Install in current directory (committed with your project)"
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
value: "global",
|
|
259
|
+
label: "Global",
|
|
260
|
+
hint: "Install globally (available across all projects)"
|
|
261
|
+
}
|
|
262
|
+
]
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
if (isCancel(scope)) {
|
|
266
|
+
cancel("Installation cancelled");
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return scope;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Prompt user to select installation method (Symlink or Copy)
|
|
275
|
+
* @returns {Promise<"symlink" | "copy" | null>}
|
|
276
|
+
*/
|
|
277
|
+
export async function selectMethodPrompt() {
|
|
278
|
+
const method = await select({
|
|
279
|
+
message: "Installation method",
|
|
280
|
+
options: [
|
|
281
|
+
{
|
|
282
|
+
value: "symlink",
|
|
283
|
+
label: "Symlink (Recommended)",
|
|
284
|
+
hint: "Single source of truth, easy updates"
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
value: "copy",
|
|
288
|
+
label: "Copy to all agents",
|
|
289
|
+
hint: "Independent copies for each agent"
|
|
290
|
+
}
|
|
291
|
+
]
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
if (isCancel(method)) {
|
|
295
|
+
cancel("Installation cancelled");
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return method;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Prompt user to select skills to install (multiselect with descriptions)
|
|
304
|
+
* @param {Array<{name: string, description: string, path: string}>} skills
|
|
305
|
+
* @returns {Promise<Array<{name: string, description: string, path: string}> | null>}
|
|
306
|
+
*/
|
|
307
|
+
export async function selectSkillsPrompt(skills) {
|
|
308
|
+
if (skills.length === 0) {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const selectedNames = await multiselect({
|
|
313
|
+
message: "Select skills to install",
|
|
314
|
+
options: skills.map(skill => ({
|
|
315
|
+
value: skill.name,
|
|
316
|
+
label: skill.name,
|
|
317
|
+
hint: skill.description ? skill.description.substring(0, 60) + "..." : ""
|
|
318
|
+
})),
|
|
319
|
+
required: true
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
if (isCancel(selectedNames)) {
|
|
323
|
+
cancel("Installation cancelled");
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return skills.filter(s => selectedNames.includes(s.name));
|
|
328
|
+
}
|
|
329
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "add-skill-kit",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.8",
|
|
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": "agentskillkit <agentskillkit@gmail.com>",
|