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/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 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
-
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.7",
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>",