@sstar/skill-install 1.2.0 → 1.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/dist/ui/prompts.d.ts +21 -2
- package/dist/ui/prompts.js +148 -58
- package/dist/wiki/skill-selector.js +29 -16
- package/dist/wiki/wiki-searcher.d.ts +1 -0
- package/dist/wiki/wiki-searcher.js +2 -1
- package/package.json +3 -4
package/dist/ui/prompts.d.ts
CHANGED
|
@@ -1,8 +1,27 @@
|
|
|
1
|
-
import { intro, outro, spinner, isCancel } from '@clack/prompts';
|
|
2
1
|
import { AiTool } from '../skills/skills-manager';
|
|
3
2
|
import { SkillInPackage } from '../installer/install-service';
|
|
4
3
|
import { PluginInfo } from '../plugins/types';
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Display intro message
|
|
6
|
+
*/
|
|
7
|
+
export declare function intro(title?: string): void;
|
|
8
|
+
/**
|
|
9
|
+
* Display outro message
|
|
10
|
+
*/
|
|
11
|
+
export declare function outro(message?: string): void;
|
|
12
|
+
/**
|
|
13
|
+
* Create a spinner
|
|
14
|
+
*/
|
|
15
|
+
export declare function spinner(): {
|
|
16
|
+
start(msg: string): void;
|
|
17
|
+
stop(msg?: string): void;
|
|
18
|
+
message(msg: string): void;
|
|
19
|
+
error(msg: string): void;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Check if value is a cancel symbol (inquirer uses Ctrl+C which throws)
|
|
23
|
+
*/
|
|
24
|
+
export declare function isCancel(value: unknown): boolean;
|
|
6
25
|
/**
|
|
7
26
|
* Prompt for AI tool selection
|
|
8
27
|
*/
|
package/dist/ui/prompts.js
CHANGED
|
@@ -3,7 +3,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.intro = intro;
|
|
7
|
+
exports.outro = outro;
|
|
8
|
+
exports.spinner = spinner;
|
|
9
|
+
exports.isCancel = isCancel;
|
|
7
10
|
exports.promptAiTool = promptAiTool;
|
|
8
11
|
exports.promptSkillsDir = promptSkillsDir;
|
|
9
12
|
exports.promptPassword = promptPassword;
|
|
@@ -16,21 +19,84 @@ exports.success = success;
|
|
|
16
19
|
exports.error = error;
|
|
17
20
|
exports.info = info;
|
|
18
21
|
exports.warn = warn;
|
|
19
|
-
const prompts_1 = require("@
|
|
20
|
-
Object.defineProperty(exports, "intro", { enumerable: true, get: function () { return prompts_1.intro; } });
|
|
21
|
-
Object.defineProperty(exports, "outro", { enumerable: true, get: function () { return prompts_1.outro; } });
|
|
22
|
-
Object.defineProperty(exports, "spinner", { enumerable: true, get: function () { return prompts_1.spinner; } });
|
|
23
|
-
Object.defineProperty(exports, "isCancel", { enumerable: true, get: function () { return prompts_1.isCancel; } });
|
|
22
|
+
const prompts_1 = require("@inquirer/prompts");
|
|
24
23
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
25
24
|
/**
|
|
26
|
-
*
|
|
25
|
+
* Common theme for prompts - clack-like style
|
|
27
26
|
*/
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
const commonTheme = {
|
|
28
|
+
icon: {
|
|
29
|
+
cursor: picocolors_1.default.cyan('❯'),
|
|
30
|
+
},
|
|
31
|
+
style: {
|
|
32
|
+
description: (text) => picocolors_1.default.green(text),
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Display intro message
|
|
37
|
+
*/
|
|
38
|
+
function intro(title) {
|
|
39
|
+
console.log();
|
|
40
|
+
console.log(picocolors_1.default.cyan('◆') + (title ? ` ${title}` : ''));
|
|
41
|
+
console.log(picocolors_1.default.gray('│'));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Display outro message
|
|
45
|
+
*/
|
|
46
|
+
function outro(message) {
|
|
47
|
+
console.log(picocolors_1.default.gray('│'));
|
|
48
|
+
console.log(picocolors_1.default.cyan('└') + (message ? ` ${message}` : ''));
|
|
49
|
+
console.log();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Create a spinner
|
|
53
|
+
*/
|
|
54
|
+
function spinner() {
|
|
55
|
+
let intervalId = null;
|
|
56
|
+
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
57
|
+
let frameIndex = 0;
|
|
58
|
+
let currentMsg = '';
|
|
59
|
+
const clearLine = () => {
|
|
60
|
+
process.stdout.write('\r\x1b[K');
|
|
61
|
+
};
|
|
62
|
+
return {
|
|
63
|
+
start(msg) {
|
|
64
|
+
currentMsg = msg;
|
|
65
|
+
intervalId = setInterval(() => {
|
|
66
|
+
const frame = picocolors_1.default.cyan(frames[frameIndex]);
|
|
67
|
+
clearLine();
|
|
68
|
+
process.stdout.write(`${frame} ${currentMsg}`);
|
|
69
|
+
frameIndex = (frameIndex + 1) % frames.length;
|
|
70
|
+
}, 80);
|
|
71
|
+
},
|
|
72
|
+
stop(msg) {
|
|
73
|
+
if (intervalId) {
|
|
74
|
+
clearInterval(intervalId);
|
|
75
|
+
intervalId = null;
|
|
76
|
+
}
|
|
77
|
+
clearLine();
|
|
78
|
+
if (msg) {
|
|
79
|
+
console.log(picocolors_1.default.green('✓') + ` ${msg}`);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
message(msg) {
|
|
83
|
+
currentMsg = msg;
|
|
84
|
+
},
|
|
85
|
+
error(msg) {
|
|
86
|
+
if (intervalId) {
|
|
87
|
+
clearInterval(intervalId);
|
|
88
|
+
intervalId = null;
|
|
89
|
+
}
|
|
90
|
+
clearLine();
|
|
91
|
+
console.log(picocolors_1.default.red('✗') + ` ${msg}`);
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Check if value is a cancel symbol (inquirer uses Ctrl+C which throws)
|
|
97
|
+
*/
|
|
98
|
+
function isCancel(value) {
|
|
99
|
+
return value === null || value === undefined;
|
|
34
100
|
}
|
|
35
101
|
/**
|
|
36
102
|
* Prompt for AI tool selection
|
|
@@ -38,12 +104,13 @@ function handleCancel(value) {
|
|
|
38
104
|
async function promptAiTool() {
|
|
39
105
|
const choice = await (0, prompts_1.select)({
|
|
40
106
|
message: 'Select AI tool',
|
|
41
|
-
|
|
42
|
-
{ value: 'claude',
|
|
43
|
-
{ value: 'codex',
|
|
107
|
+
choices: [
|
|
108
|
+
{ value: 'claude', name: 'Claude Code', description: '~/.claude/skills/' },
|
|
109
|
+
{ value: 'codex', name: 'Codex', description: '~/.codex/skills/' },
|
|
44
110
|
],
|
|
111
|
+
theme: commonTheme,
|
|
45
112
|
});
|
|
46
|
-
return
|
|
113
|
+
return choice;
|
|
47
114
|
}
|
|
48
115
|
/**
|
|
49
116
|
* Prompt for skills directory (global vs local)
|
|
@@ -51,12 +118,13 @@ async function promptAiTool() {
|
|
|
51
118
|
async function promptSkillsDir(aiTool, globalDir, localDir) {
|
|
52
119
|
const choice = await (0, prompts_1.select)({
|
|
53
120
|
message: 'Select installation directory',
|
|
54
|
-
|
|
55
|
-
{ value: globalDir,
|
|
56
|
-
{ value: localDir,
|
|
121
|
+
choices: [
|
|
122
|
+
{ value: globalDir, name: 'Global', description: globalDir },
|
|
123
|
+
{ value: localDir, name: 'Local', description: localDir },
|
|
57
124
|
],
|
|
125
|
+
theme: commonTheme,
|
|
58
126
|
});
|
|
59
|
-
return
|
|
127
|
+
return choice;
|
|
60
128
|
}
|
|
61
129
|
/**
|
|
62
130
|
* Prompt for password (masked input)
|
|
@@ -66,7 +134,7 @@ async function promptPassword(message = 'Password') {
|
|
|
66
134
|
message,
|
|
67
135
|
mask: '*',
|
|
68
136
|
});
|
|
69
|
-
return
|
|
137
|
+
return value;
|
|
70
138
|
}
|
|
71
139
|
/**
|
|
72
140
|
* Prompt for yes/no confirmation
|
|
@@ -74,20 +142,19 @@ async function promptPassword(message = 'Password') {
|
|
|
74
142
|
async function promptYesNo(message, initialValue = true) {
|
|
75
143
|
const value = await (0, prompts_1.confirm)({
|
|
76
144
|
message,
|
|
77
|
-
initialValue,
|
|
145
|
+
default: initialValue,
|
|
78
146
|
});
|
|
79
|
-
return
|
|
147
|
+
return value;
|
|
80
148
|
}
|
|
81
149
|
/**
|
|
82
150
|
* Prompt for text input
|
|
83
151
|
*/
|
|
84
152
|
async function promptText(message, placeholder, initialValue) {
|
|
85
|
-
const value = await (0, prompts_1.
|
|
153
|
+
const value = await (0, prompts_1.input)({
|
|
86
154
|
message,
|
|
87
|
-
|
|
88
|
-
initialValue,
|
|
155
|
+
default: initialValue,
|
|
89
156
|
});
|
|
90
|
-
return
|
|
157
|
+
return value;
|
|
91
158
|
}
|
|
92
159
|
/**
|
|
93
160
|
* Select skills from a multi-skill package
|
|
@@ -99,21 +166,28 @@ async function selectSkillsFromPackage(skills) {
|
|
|
99
166
|
const install = await promptYesNo(`Install skill "${skills[0].name}"?`);
|
|
100
167
|
return install ? skills : [];
|
|
101
168
|
}
|
|
102
|
-
const
|
|
103
|
-
value: index,
|
|
104
|
-
label: skill.name,
|
|
105
|
-
hint: skill.description.length > 50
|
|
106
|
-
? skill.description.slice(0, 50) + '...'
|
|
107
|
-
: skill.description,
|
|
108
|
-
}));
|
|
109
|
-
const selected = await (0, prompts_1.multiselect)({
|
|
169
|
+
const indices = await (0, prompts_1.checkbox)({
|
|
110
170
|
message: `Select skills to install (${skills.length} found)`,
|
|
111
|
-
|
|
171
|
+
choices: skills.map((skill, index) => ({
|
|
172
|
+
value: index,
|
|
173
|
+
name: skill.name,
|
|
174
|
+
description: skill.description.length > 50
|
|
175
|
+
? skill.description.slice(0, 50) + '...'
|
|
176
|
+
: skill.description,
|
|
177
|
+
})),
|
|
112
178
|
required: false,
|
|
179
|
+
theme: {
|
|
180
|
+
icon: {
|
|
181
|
+
checked: picocolors_1.default.green('◉'),
|
|
182
|
+
unchecked: '○',
|
|
183
|
+
cursor: picocolors_1.default.cyan('❯'),
|
|
184
|
+
},
|
|
185
|
+
style: {
|
|
186
|
+
description: (text) => picocolors_1.default.green(text),
|
|
187
|
+
},
|
|
188
|
+
},
|
|
113
189
|
});
|
|
114
|
-
const indices = handleCancel(selected);
|
|
115
190
|
if (indices.length === 0) {
|
|
116
|
-
// If nothing selected, ask if they want all
|
|
117
191
|
const installAll = await promptYesNo('No skills selected. Install all?', false);
|
|
118
192
|
return installAll ? skills : [];
|
|
119
193
|
}
|
|
@@ -125,19 +199,27 @@ async function selectSkillsFromPackage(skills) {
|
|
|
125
199
|
async function promptSkillSelection(skills) {
|
|
126
200
|
if (skills.length === 0)
|
|
127
201
|
return [];
|
|
128
|
-
const
|
|
129
|
-
value: index,
|
|
130
|
-
label: skill.name,
|
|
131
|
-
hint: skill.description.length > 50
|
|
132
|
-
? skill.description.slice(0, 50) + '...'
|
|
133
|
-
: skill.description,
|
|
134
|
-
}));
|
|
135
|
-
const selected = await (0, prompts_1.multiselect)({
|
|
202
|
+
const indices = await (0, prompts_1.checkbox)({
|
|
136
203
|
message: 'Select skills to uninstall',
|
|
137
|
-
|
|
204
|
+
choices: skills.map((skill, index) => ({
|
|
205
|
+
value: index,
|
|
206
|
+
name: skill.name,
|
|
207
|
+
description: skill.description.length > 50
|
|
208
|
+
? skill.description.slice(0, 50) + '...'
|
|
209
|
+
: skill.description,
|
|
210
|
+
})),
|
|
138
211
|
required: false,
|
|
212
|
+
theme: {
|
|
213
|
+
icon: {
|
|
214
|
+
checked: picocolors_1.default.green('◉'),
|
|
215
|
+
unchecked: '○',
|
|
216
|
+
cursor: picocolors_1.default.cyan('❯'),
|
|
217
|
+
},
|
|
218
|
+
style: {
|
|
219
|
+
description: (text) => picocolors_1.default.green(text),
|
|
220
|
+
},
|
|
221
|
+
},
|
|
139
222
|
});
|
|
140
|
-
const indices = handleCancel(selected);
|
|
141
223
|
return indices;
|
|
142
224
|
}
|
|
143
225
|
/**
|
|
@@ -150,17 +232,25 @@ async function selectPluginsFromMarketplace(plugins) {
|
|
|
150
232
|
const install = await promptYesNo(`Install plugin "${plugins[0].name}"?`);
|
|
151
233
|
return install ? [{ name: plugins[0].name, version: plugins[0].version }] : [];
|
|
152
234
|
}
|
|
153
|
-
const
|
|
154
|
-
value: index,
|
|
155
|
-
label: `${plugin.name} v${plugin.version || 'unknown'}`,
|
|
156
|
-
hint: plugin.metadata.description?.slice(0, 50) || '',
|
|
157
|
-
}));
|
|
158
|
-
const selected = await (0, prompts_1.multiselect)({
|
|
235
|
+
const indices = await (0, prompts_1.checkbox)({
|
|
159
236
|
message: `Select plugins to install (${plugins.length} found)`,
|
|
160
|
-
|
|
237
|
+
choices: plugins.map((plugin, index) => ({
|
|
238
|
+
value: index,
|
|
239
|
+
name: `${plugin.name} v${plugin.version || 'unknown'}`,
|
|
240
|
+
description: plugin.metadata.description?.slice(0, 50) || '',
|
|
241
|
+
})),
|
|
161
242
|
required: false,
|
|
243
|
+
theme: {
|
|
244
|
+
icon: {
|
|
245
|
+
checked: picocolors_1.default.green('◉'),
|
|
246
|
+
unchecked: '○',
|
|
247
|
+
cursor: picocolors_1.default.cyan('❯'),
|
|
248
|
+
},
|
|
249
|
+
style: {
|
|
250
|
+
description: (text) => picocolors_1.default.green(text),
|
|
251
|
+
},
|
|
252
|
+
},
|
|
162
253
|
});
|
|
163
|
-
const indices = handleCancel(selected);
|
|
164
254
|
if (indices.length === 0) {
|
|
165
255
|
const installAll = await promptYesNo('No plugins selected. Install all?', false);
|
|
166
256
|
return installAll ? plugins.map(p => ({ name: p.name, version: p.version })) : [];
|
|
@@ -183,7 +273,7 @@ function error(message) {
|
|
|
183
273
|
* Display info message
|
|
184
274
|
*/
|
|
185
275
|
function info(message) {
|
|
186
|
-
console.log(picocolors_1.default.
|
|
276
|
+
console.log(picocolors_1.default.cyan(`ℹ ${message}`));
|
|
187
277
|
}
|
|
188
278
|
/**
|
|
189
279
|
* Display warning message
|
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.SkillSelector = void 0;
|
|
7
|
-
const
|
|
7
|
+
const checkbox_1 = __importDefault(require("@inquirer/checkbox"));
|
|
8
8
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
9
9
|
const logger_1 = require("../core/logger");
|
|
10
10
|
class SkillSelector {
|
|
@@ -20,26 +20,39 @@ class SkillSelector {
|
|
|
20
20
|
this.logger.info('No skills found to display.');
|
|
21
21
|
return [];
|
|
22
22
|
}
|
|
23
|
-
const
|
|
24
|
-
value: index,
|
|
25
|
-
label: item.description
|
|
26
|
-
? `${item.name}: ${item.description.slice(0, 50)}${item.description.length > 50 ? '...' : ''}`
|
|
27
|
-
: item.name,
|
|
28
|
-
hint: item.pageUrl,
|
|
29
|
-
}));
|
|
30
|
-
const choice = await (0, prompts_1.multiselect)({
|
|
23
|
+
const selectedIndices = await (0, checkbox_1.default)({
|
|
31
24
|
message: `Found ${items.length} skill(s)`,
|
|
32
|
-
|
|
25
|
+
pageSize: 30, // Show more items since each takes 3 lines
|
|
26
|
+
choices: items.map((item, index) => {
|
|
27
|
+
// Build multi-line name with colors
|
|
28
|
+
const num = picocolors_1.default.bold(picocolors_1.default.white(`[${index + 1}/${items.length}]`));
|
|
29
|
+
const name = picocolors_1.default.bold(picocolors_1.default.yellow(item.name));
|
|
30
|
+
const uploader = item.uploader ? picocolors_1.default.cyan(` (${item.uploader})`) : '';
|
|
31
|
+
const desc = picocolors_1.default.green(item.description);
|
|
32
|
+
const url = picocolors_1.default.magenta(item.pageUrl);
|
|
33
|
+
return {
|
|
34
|
+
value: index,
|
|
35
|
+
name: `${num} ${name}${uploader}\n ${desc}\n ${url}`,
|
|
36
|
+
description: '', // Disable default description
|
|
37
|
+
};
|
|
38
|
+
}),
|
|
39
|
+
required: false,
|
|
40
|
+
theme: {
|
|
41
|
+
icon: {
|
|
42
|
+
checked: picocolors_1.default.green('◉'),
|
|
43
|
+
unchecked: '○',
|
|
44
|
+
cursor: picocolors_1.default.cyan('❯'),
|
|
45
|
+
},
|
|
46
|
+
style: {
|
|
47
|
+
description: (text) => text, // No extra styling
|
|
48
|
+
},
|
|
49
|
+
},
|
|
33
50
|
});
|
|
34
|
-
if (
|
|
35
|
-
(0, prompts_1.outro)(picocolors_1.default.yellow('Cancelled'));
|
|
36
|
-
return [];
|
|
37
|
-
}
|
|
38
|
-
if (choice.length === 0) {
|
|
51
|
+
if (selectedIndices.length === 0) {
|
|
39
52
|
this.logger.info('No skills selected.');
|
|
40
53
|
return [];
|
|
41
54
|
}
|
|
42
|
-
const selectedItems =
|
|
55
|
+
const selectedItems = selectedIndices.map(index => items[index]);
|
|
43
56
|
this.logger.info(`Selected: ${selectedItems.map(s => s.name).join(', ')}`);
|
|
44
57
|
return selectedItems.map(s => s.downloadUrl);
|
|
45
58
|
}
|
|
@@ -70,7 +70,8 @@ class WikiSearcher {
|
|
|
70
70
|
name: filename,
|
|
71
71
|
downloadUrl: this.buildDownloadUrl(baseUrl, item),
|
|
72
72
|
containerId: item.container?.id || '',
|
|
73
|
-
pageUrl: item._links?.webui ? `${baseUrl}${item._links.webui}` : ''
|
|
73
|
+
pageUrl: item._links?.webui ? `${baseUrl}${item._links.webui}` : '',
|
|
74
|
+
uploader: item.version?.by?.displayName
|
|
74
75
|
});
|
|
75
76
|
}
|
|
76
77
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sstar/skill-install",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Agent Skill installation tool - download, extract, validate, and install skills for Claude Code and Codex",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -37,12 +37,12 @@
|
|
|
37
37
|
"node": ">=18.0.0"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@
|
|
40
|
+
"@inquirer/prompts": "^8.3.0",
|
|
41
|
+
"@inquirer/type": "^4.0.3",
|
|
41
42
|
"adm-zip": "^0.5.16",
|
|
42
43
|
"axios": "^1.6.0",
|
|
43
44
|
"cheerio": "^1.0.0-rc.12",
|
|
44
45
|
"commander": "^12.0.0",
|
|
45
|
-
"inquirer": "^13.2.2",
|
|
46
46
|
"js-yaml": "^4.1.1",
|
|
47
47
|
"picocolors": "^1.1.1",
|
|
48
48
|
"tar": "^7.5.6",
|
|
@@ -50,7 +50,6 @@
|
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/adm-zip": "^0.5.7",
|
|
53
|
-
"@types/inquirer": "^9.0.9",
|
|
54
53
|
"@types/js-yaml": "^4.0.9",
|
|
55
54
|
"@types/node": "^20.0.0",
|
|
56
55
|
"@types/tar": "^6.1.13",
|