@sstar/skill-install 1.1.1 → 1.2.0
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/cli.js +254 -589
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.js +17 -0
- package/dist/ui/prompts.d.ts +59 -0
- package/dist/ui/prompts.js +193 -0
- package/dist/wiki/skill-selector.d.ts +3 -7
- package/dist/wiki/skill-selector.js +25 -82
- package/package.json +5 -1
package/dist/cli.js
CHANGED
|
@@ -5,28 +5,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
};
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
const commander_1 = require("commander");
|
|
8
|
-
const readline_1 = __importDefault(require("readline"));
|
|
9
8
|
const os_1 = __importDefault(require("os"));
|
|
9
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
10
10
|
const install_service_1 = require("./installer/install-service");
|
|
11
11
|
const skills_manager_1 = require("./skills/skills-manager");
|
|
12
12
|
const plugin_manager_1 = require("./plugins/plugin-manager");
|
|
13
13
|
const logger_1 = require("./core/logger");
|
|
14
14
|
const wiki_1 = require("./wiki");
|
|
15
15
|
const types_1 = require("./plugins/types");
|
|
16
|
-
|
|
17
|
-
const colors = {
|
|
18
|
-
reset: '\x1b[0m',
|
|
19
|
-
bright: '\x1b[1m',
|
|
20
|
-
dim: '\x1b[2m',
|
|
21
|
-
red: '\x1b[31m',
|
|
22
|
-
green: '\x1b[32m',
|
|
23
|
-
yellow: '\x1b[33m',
|
|
24
|
-
blue: '\x1b[34m',
|
|
25
|
-
magenta: '\x1b[35m',
|
|
26
|
-
cyan: '\x1b[36m',
|
|
27
|
-
white: '\x1b[37m',
|
|
28
|
-
gray: '\x1b[90m'
|
|
29
|
-
};
|
|
16
|
+
const ui_1 = require("./ui");
|
|
30
17
|
const program = new commander_1.Command();
|
|
31
18
|
const skillsManager = new skills_manager_1.SkillsManager();
|
|
32
19
|
program
|
|
@@ -54,19 +41,18 @@ program
|
|
|
54
41
|
logger_1.Logger.setLevel('debug');
|
|
55
42
|
}
|
|
56
43
|
try {
|
|
44
|
+
(0, ui_1.intro)(picocolors_1.default.cyan('Agent Skill Installer'));
|
|
57
45
|
// Determine AI tool - prompt if not specified
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
aiTool = await promptAiTool();
|
|
64
|
-
}
|
|
46
|
+
const aiTool = globalOpts.tool
|
|
47
|
+
? globalOpts.tool
|
|
48
|
+
: await (0, ui_1.promptAiTool)();
|
|
65
49
|
// Determine skills directory
|
|
66
50
|
let skillsDir = globalOpts.skillsDir;
|
|
67
51
|
// If neither --global nor --local nor explicit --skills-dir, prompt interactively
|
|
68
52
|
if (!skillsDir && !options.global && !options.local) {
|
|
69
|
-
|
|
53
|
+
const globalDir = skillsManager.getGlobalSkillsDir(aiTool);
|
|
54
|
+
const localDir = skillsManager.getLocalSkillsDir(aiTool);
|
|
55
|
+
skillsDir = await (0, ui_1.promptSkillsDir)(aiTool, globalDir, localDir);
|
|
70
56
|
}
|
|
71
57
|
else if (options.global) {
|
|
72
58
|
skillsDir = skillsManager.getGlobalSkillsDir(aiTool);
|
|
@@ -81,285 +67,293 @@ program
|
|
|
81
67
|
// Auto-detect username from system if not provided
|
|
82
68
|
let username = options.username || process.env.WIKI_USERNAME || os_1.default.userInfo().username;
|
|
83
69
|
let password = options.password || process.env.WIKI_PASSWORD || '';
|
|
70
|
+
// Collect sources to install
|
|
71
|
+
let sources = source ? [source] : [];
|
|
84
72
|
// If no source provided, trigger search flow
|
|
85
|
-
if (
|
|
73
|
+
if (sources.length === 0) {
|
|
86
74
|
// Only require password, username is auto-detected
|
|
87
75
|
if (!password) {
|
|
88
|
-
password = await promptPassword();
|
|
76
|
+
password = await (0, ui_1.promptPassword)('Enter your Wiki password');
|
|
89
77
|
}
|
|
90
|
-
const
|
|
91
|
-
if (
|
|
78
|
+
const selectedUrls = await searchAndSelectSkill(username, password, options.wikiUrl, options.allowSelfSigned);
|
|
79
|
+
if (selectedUrls.length === 0) {
|
|
92
80
|
console.log('No skill selected.');
|
|
93
81
|
process.exit(0);
|
|
94
82
|
}
|
|
95
|
-
|
|
83
|
+
sources = selectedUrls;
|
|
96
84
|
}
|
|
97
|
-
// Check if source appears to be a wiki URL
|
|
98
|
-
const needsAuth =
|
|
99
|
-
|
|
100
|
-
|
|
85
|
+
// Check if any source appears to be a wiki URL
|
|
86
|
+
const needsAuth = sources.some(s => s.includes('/download/attachments/') ||
|
|
87
|
+
s.includes('/wiki/download/') ||
|
|
88
|
+
s.includes('/confluence/download/'));
|
|
101
89
|
if (needsAuth && !username) {
|
|
102
90
|
console.error('Error: Wiki URL detected. Username is required. Use -u option or set WIKI_USERNAME environment variable.');
|
|
103
91
|
process.exit(1);
|
|
104
92
|
}
|
|
105
93
|
if (needsAuth && !password) {
|
|
106
|
-
password = await promptPassword();
|
|
107
|
-
}
|
|
108
|
-
console.log(`Installing skill from: ${source}`);
|
|
109
|
-
if (needsAuth) {
|
|
110
|
-
console.log(`Username: ${username}`);
|
|
94
|
+
password = await (0, ui_1.promptPassword)();
|
|
111
95
|
}
|
|
112
|
-
|
|
96
|
+
// Install all sources
|
|
113
97
|
const installer = new install_service_1.InstallService();
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
force: options.force
|
|
121
|
-
});
|
|
122
|
-
// Handle multi-skill package
|
|
123
|
-
if (result.isMultiSkill && result.skills) {
|
|
124
|
-
const selectedSkills = await selectSkillsFromPackage(result.skills);
|
|
125
|
-
if (selectedSkills.length === 0) {
|
|
126
|
-
console.log('No skills selected.');
|
|
127
|
-
// Clean up temp directory before exit
|
|
128
|
-
if (result.tempDir) {
|
|
129
|
-
await installer.cleanup(result.tempDir);
|
|
130
|
-
}
|
|
131
|
-
process.exit(0);
|
|
98
|
+
let totalSuccessCount = 0;
|
|
99
|
+
let totalFailCount = 0;
|
|
100
|
+
for (let i = 0; i < sources.length; i++) {
|
|
101
|
+
const currentSource = sources[i];
|
|
102
|
+
if (sources.length > 1) {
|
|
103
|
+
console.log(`\n[${i + 1}/${sources.length}] Installing from: ${currentSource}`);
|
|
132
104
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
105
|
+
else {
|
|
106
|
+
console.log(`Installing skill from: ${currentSource}`);
|
|
107
|
+
}
|
|
108
|
+
if (needsAuth) {
|
|
109
|
+
console.log(`Username: ${username}`);
|
|
110
|
+
}
|
|
111
|
+
console.log('');
|
|
112
|
+
const result = await installer.install({
|
|
113
|
+
source: currentSource,
|
|
137
114
|
skillsDir,
|
|
138
115
|
username,
|
|
139
116
|
password,
|
|
140
117
|
allowSelfSigned: options.allowSelfSigned,
|
|
141
118
|
force: options.force
|
|
142
119
|
});
|
|
143
|
-
//
|
|
144
|
-
if (result.
|
|
145
|
-
await
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
for (const res of installResults) {
|
|
152
|
-
if (res.success) {
|
|
153
|
-
console.log(`✓ Skill "${res.skillName}" installed successfully!`);
|
|
154
|
-
console.log(` Path: ${res.skillPath}`);
|
|
155
|
-
successCount++;
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
console.error(`✗ Failed to install skill: ${res.error}`);
|
|
159
|
-
failCount++;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
console.log('');
|
|
163
|
-
console.log(`Installation complete: ${successCount} succeeded, ${failCount} failed.`);
|
|
164
|
-
process.exit(failCount > 0 ? 1 : 0);
|
|
165
|
-
}
|
|
166
|
-
// Handle Marketplace installation
|
|
167
|
-
if (result.packageType === types_1.PackageType.MARKETPLACE && result.singleSkillResult?.marketplaceResult) {
|
|
168
|
-
// Plugins only support Claude Code, not Codex
|
|
169
|
-
// For Codex, fallback to skill installation
|
|
170
|
-
if (aiTool === 'codex') {
|
|
171
|
-
console.log('');
|
|
172
|
-
console.log(`${colors.yellow}⚠ Note: Plugins and Marketplaces are only supported for Claude Code.${colors.reset}`);
|
|
173
|
-
console.log(` Selected AI Tool: ${colors.cyan}Codex${colors.reset}`);
|
|
174
|
-
console.log(` Scanning for Skills in this package...`);
|
|
175
|
-
console.log('');
|
|
176
|
-
// Re-scan for skills in the package
|
|
177
|
-
const skills = await installer.scanForSkills(result.tempDir || '');
|
|
178
|
-
if (skills.length > 0) {
|
|
179
|
-
const selectedSkills = await selectSkillsFromPackage(skills);
|
|
180
|
-
if (selectedSkills.length > 0) {
|
|
181
|
-
const installResults = await installer.installSelectedSkills(selectedSkills, result.tempDir || '', {
|
|
182
|
-
source,
|
|
183
|
-
skillsDir,
|
|
184
|
-
username,
|
|
185
|
-
password,
|
|
186
|
-
allowSelfSigned: options.allowSelfSigned,
|
|
187
|
-
force: options.force
|
|
188
|
-
});
|
|
189
|
-
// Display results
|
|
190
|
-
console.log('');
|
|
191
|
-
let successCount = 0;
|
|
192
|
-
let failCount = 0;
|
|
193
|
-
for (const res of installResults) {
|
|
194
|
-
if (res.success) {
|
|
195
|
-
console.log(`✓ Skill "${res.skillName}" installed successfully!`);
|
|
196
|
-
console.log(` Path: ${res.skillPath}`);
|
|
197
|
-
successCount++;
|
|
198
|
-
}
|
|
199
|
-
else {
|
|
200
|
-
console.error(`✗ Failed to install skill: ${res.error}`);
|
|
201
|
-
failCount++;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
console.log('');
|
|
205
|
-
console.log(`Installation complete: ${successCount} succeeded, ${failCount} failed.`);
|
|
120
|
+
// Handle multi-skill package
|
|
121
|
+
if (result.isMultiSkill && result.skills) {
|
|
122
|
+
const selectedSkills = await (0, ui_1.selectSkillsFromPackage)(result.skills);
|
|
123
|
+
if (selectedSkills.length === 0) {
|
|
124
|
+
console.log('No skills selected.');
|
|
125
|
+
// Clean up temp directory before continuing
|
|
126
|
+
if (result.tempDir) {
|
|
127
|
+
await installer.cleanup(result.tempDir);
|
|
206
128
|
}
|
|
129
|
+
continue;
|
|
207
130
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
131
|
+
// Install selected skills
|
|
132
|
+
const installResults = await installer.installSelectedSkills(selectedSkills, '', // extractDir is already handled in install()
|
|
133
|
+
{
|
|
134
|
+
source: currentSource,
|
|
135
|
+
skillsDir,
|
|
136
|
+
username,
|
|
137
|
+
password,
|
|
138
|
+
allowSelfSigned: options.allowSelfSigned,
|
|
139
|
+
force: options.force
|
|
140
|
+
});
|
|
141
|
+
// Clean up temp directory after installation
|
|
212
142
|
if (result.tempDir) {
|
|
213
143
|
await installer.cleanup(result.tempDir);
|
|
214
144
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (result.packageStructure && result.packageStructure.plugins.length > 0) {
|
|
226
|
-
const plugins = result.packageStructure.plugins;
|
|
227
|
-
console.log(`This marketplace contains ${plugins.length} plugin(s):`);
|
|
228
|
-
console.log('');
|
|
229
|
-
for (const plugin of plugins) {
|
|
230
|
-
console.log(` - ${colors.green}${plugin.name}${colors.reset} v${plugin.version || 'unknown'}`);
|
|
231
|
-
if (plugin.metadata.description) {
|
|
232
|
-
console.log(` ${plugin.metadata.description}`);
|
|
145
|
+
// Count results
|
|
146
|
+
for (const res of installResults) {
|
|
147
|
+
if (res.success) {
|
|
148
|
+
console.log(`✓ Skill "${res.skillName}" installed successfully!`);
|
|
149
|
+
console.log(` Path: ${res.skillPath}`);
|
|
150
|
+
totalSuccessCount++;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
console.error(`✗ Failed to install skill: ${res.error}`);
|
|
154
|
+
totalFailCount++;
|
|
233
155
|
}
|
|
234
156
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
157
|
+
}
|
|
158
|
+
// Handle Marketplace installation
|
|
159
|
+
if (result.packageType === types_1.PackageType.MARKETPLACE && result.singleSkillResult?.marketplaceResult) {
|
|
160
|
+
// Plugins only support Claude Code, not Codex
|
|
161
|
+
// For Codex, fallback to skill installation
|
|
162
|
+
if (aiTool === 'codex') {
|
|
163
|
+
console.log('');
|
|
164
|
+
console.log(picocolors_1.default.yellow('⚠ Note: Plugins and Marketplaces are only supported for Claude Code.'));
|
|
165
|
+
console.log(` Selected AI Tool: ${picocolors_1.default.cyan('Codex')}`);
|
|
166
|
+
console.log(` Scanning for Skills in this package...`);
|
|
167
|
+
console.log('');
|
|
168
|
+
// Re-scan for skills in the package
|
|
169
|
+
const skills = await installer.scanForSkills(result.tempDir || '');
|
|
170
|
+
if (skills.length > 0) {
|
|
171
|
+
const selectedSkills = await (0, ui_1.selectSkillsFromPackage)(skills);
|
|
172
|
+
if (selectedSkills.length > 0) {
|
|
173
|
+
const installResults = await installer.installSelectedSkills(selectedSkills, result.tempDir || '', {
|
|
174
|
+
source: currentSource,
|
|
175
|
+
skillsDir,
|
|
176
|
+
username,
|
|
177
|
+
password,
|
|
178
|
+
allowSelfSigned: options.allowSelfSigned,
|
|
179
|
+
force: options.force
|
|
180
|
+
});
|
|
181
|
+
// Count results
|
|
182
|
+
for (const res of installResults) {
|
|
183
|
+
if (res.success) {
|
|
184
|
+
console.log(`✓ Skill "${res.skillName}" installed successfully!`);
|
|
185
|
+
console.log(` Path: ${res.skillPath}`);
|
|
186
|
+
totalSuccessCount++;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
console.error(`✗ Failed to install skill: ${res.error}`);
|
|
190
|
+
totalFailCount++;
|
|
191
|
+
}
|
|
254
192
|
}
|
|
255
193
|
}
|
|
256
194
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
// Also check if marketplace can be installed as a plugin
|
|
260
|
-
if (result.packageStructure?.marketplaceAsPlugin) {
|
|
261
|
-
console.log('');
|
|
262
|
-
console.log(`${colors.yellow}💡 Note: This marketplace can also be installed as a plugin.${colors.reset}`);
|
|
263
|
-
console.log(` As a plugin, it provides: ${result.packageStructure.marketplaceAsPlugin.description || ''}`);
|
|
264
|
-
const installAsPlugin = await promptYesNo('Install as plugin as well?');
|
|
265
|
-
if (installAsPlugin) {
|
|
266
|
-
try {
|
|
267
|
-
const pluginResult = await pluginManager.installPluginFromMarketplace(marketplaceResult.marketplace, result.packageStructure.marketplaceAsPlugin.name, result.packageStructure.marketplaceAsPlugin.version);
|
|
268
|
-
console.log(`${colors.green}✓${colors.reset} Plugin "${pluginResult.plugin}" installed as well!`);
|
|
269
|
-
console.log(` Path: ${pluginResult.path}`);
|
|
195
|
+
else {
|
|
196
|
+
console.log('No Skills found in this package.');
|
|
270
197
|
}
|
|
271
|
-
|
|
272
|
-
|
|
198
|
+
// Clean up temp directory
|
|
199
|
+
if (result.tempDir) {
|
|
200
|
+
await installer.cleanup(result.tempDir);
|
|
273
201
|
}
|
|
202
|
+
continue;
|
|
274
203
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
if (result.tempDir) {
|
|
278
|
-
await installer.cleanup(result.tempDir);
|
|
279
|
-
}
|
|
280
|
-
console.log('');
|
|
281
|
-
console.log('Installation complete!');
|
|
282
|
-
process.exit(0);
|
|
283
|
-
}
|
|
284
|
-
// Handle Plugin installation
|
|
285
|
-
if (result.packageType === types_1.PackageType.PLUGIN && result.singleSkillResult?.pluginResult) {
|
|
286
|
-
// Plugins only support Claude Code, not Codex
|
|
287
|
-
// For Codex, fallback to skill installation
|
|
288
|
-
if (aiTool === 'codex') {
|
|
204
|
+
const marketplaceResult = result.singleSkillResult.marketplaceResult;
|
|
205
|
+
const pluginManager = new plugin_manager_1.PluginManager();
|
|
289
206
|
console.log('');
|
|
290
|
-
console.log(
|
|
291
|
-
console.log(`
|
|
292
|
-
console.log(`
|
|
207
|
+
console.log(picocolors_1.default.cyan('📦 Marketplace installed successfully!'));
|
|
208
|
+
console.log(` Name: ${marketplaceResult.marketplace}`);
|
|
209
|
+
console.log(` Path: ${marketplaceResult.path}`);
|
|
293
210
|
console.log('');
|
|
294
|
-
//
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
console.log(
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
211
|
+
// Ask if user wants to install plugins from this marketplace
|
|
212
|
+
if (result.packageStructure && result.packageStructure.plugins.length > 0) {
|
|
213
|
+
const plugins = result.packageStructure.plugins;
|
|
214
|
+
console.log(`This marketplace contains ${plugins.length} plugin(s):`);
|
|
215
|
+
console.log('');
|
|
216
|
+
for (const plugin of plugins) {
|
|
217
|
+
console.log(` - ${picocolors_1.default.green(plugin.name)} v${plugin.version || 'unknown'}`);
|
|
218
|
+
if (plugin.metadata.description) {
|
|
219
|
+
console.log(` ${plugin.metadata.description}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
console.log('');
|
|
223
|
+
const installPlugins = await (0, ui_1.promptYesNo)('Would you like to install plugins from this marketplace?');
|
|
224
|
+
if (installPlugins) {
|
|
225
|
+
// Select plugins to install
|
|
226
|
+
const selectedPlugins = await (0, ui_1.selectPluginsFromMarketplace)(plugins);
|
|
227
|
+
if (selectedPlugins.length > 0) {
|
|
228
|
+
console.log('');
|
|
229
|
+
const results = await installer.installPluginsFromMarketplace(marketplaceResult.marketplace, selectedPlugins, (current, total, plugin) => {
|
|
230
|
+
console.log(`[${current}/${total}] Installing ${plugin}...`);
|
|
231
|
+
});
|
|
232
|
+
// Display plugin installation results
|
|
233
|
+
console.log('');
|
|
234
|
+
for (const res of results) {
|
|
235
|
+
if (res.success) {
|
|
236
|
+
console.log(`${picocolors_1.default.green('✓')} Plugin "${res.plugin}" installed successfully!`);
|
|
237
|
+
console.log(` Path: ${res.path}`);
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
console.error(`${picocolors_1.default.red('✗')} Failed to install plugin: ${res.error || 'Unknown error'}`);
|
|
241
|
+
}
|
|
320
242
|
}
|
|
321
243
|
}
|
|
322
|
-
console.log('');
|
|
323
|
-
console.log(`Installation complete: ${successCount} succeeded, ${failCount} failed.`);
|
|
324
244
|
}
|
|
325
245
|
}
|
|
326
|
-
|
|
327
|
-
|
|
246
|
+
// Also check if marketplace can be installed as a plugin
|
|
247
|
+
if (result.packageStructure?.marketplaceAsPlugin) {
|
|
248
|
+
console.log('');
|
|
249
|
+
console.log(picocolors_1.default.yellow('💡 Note: This marketplace can also be installed as a plugin.'));
|
|
250
|
+
console.log(` As a plugin, it provides: ${result.packageStructure.marketplaceAsPlugin.description || ''}`);
|
|
251
|
+
const installAsPlugin = await (0, ui_1.promptYesNo)('Install as plugin as well?');
|
|
252
|
+
if (installAsPlugin) {
|
|
253
|
+
try {
|
|
254
|
+
const pluginResult = await pluginManager.installPluginFromMarketplace(marketplaceResult.marketplace, result.packageStructure.marketplaceAsPlugin.name, result.packageStructure.marketplaceAsPlugin.version);
|
|
255
|
+
console.log(`${picocolors_1.default.green('✓')} Plugin "${pluginResult.plugin}" installed as well!`);
|
|
256
|
+
console.log(` Path: ${pluginResult.path}`);
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
console.error(`${picocolors_1.default.red('✗')} Failed to install as plugin: ${error}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
328
262
|
}
|
|
329
263
|
// Clean up temp directory
|
|
330
264
|
if (result.tempDir) {
|
|
331
265
|
await installer.cleanup(result.tempDir);
|
|
332
266
|
}
|
|
333
|
-
|
|
267
|
+
totalSuccessCount++;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
// Handle Plugin installation
|
|
271
|
+
if (result.packageType === types_1.PackageType.PLUGIN && result.singleSkillResult?.pluginResult) {
|
|
272
|
+
// Plugins only support Claude Code, not Codex
|
|
273
|
+
// For Codex, fallback to skill installation
|
|
274
|
+
if (aiTool === 'codex') {
|
|
275
|
+
console.log('');
|
|
276
|
+
console.log(picocolors_1.default.yellow('⚠ Note: Plugins are only supported for Claude Code.'));
|
|
277
|
+
console.log(` Selected AI Tool: ${picocolors_1.default.cyan('Codex')}`);
|
|
278
|
+
console.log(` Scanning for Skills in this package...`);
|
|
279
|
+
console.log('');
|
|
280
|
+
// Re-scan for skills in the package
|
|
281
|
+
const skills = await installer.scanForSkills(result.tempDir || '');
|
|
282
|
+
if (skills.length > 0) {
|
|
283
|
+
const selectedSkills = await (0, ui_1.selectSkillsFromPackage)(skills);
|
|
284
|
+
if (selectedSkills.length > 0) {
|
|
285
|
+
const installResults = await installer.installSelectedSkills(selectedSkills, result.tempDir || '', {
|
|
286
|
+
source: currentSource,
|
|
287
|
+
skillsDir,
|
|
288
|
+
username,
|
|
289
|
+
password,
|
|
290
|
+
allowSelfSigned: options.allowSelfSigned,
|
|
291
|
+
force: options.force
|
|
292
|
+
});
|
|
293
|
+
// Count results
|
|
294
|
+
for (const res of installResults) {
|
|
295
|
+
if (res.success) {
|
|
296
|
+
console.log(`✓ Skill "${res.skillName}" installed successfully!`);
|
|
297
|
+
console.log(` Path: ${res.skillPath}`);
|
|
298
|
+
totalSuccessCount++;
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
console.error(`✗ Failed to install skill: ${res.error}`);
|
|
302
|
+
totalFailCount++;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
console.log('No Skills found in this package.');
|
|
309
|
+
}
|
|
310
|
+
// Clean up temp directory
|
|
311
|
+
if (result.tempDir) {
|
|
312
|
+
await installer.cleanup(result.tempDir);
|
|
313
|
+
}
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
const pluginResult = result.singleSkillResult.pluginResult;
|
|
317
|
+
console.log('');
|
|
318
|
+
console.log(picocolors_1.default.cyan('🔌 Plugin installed successfully!'));
|
|
319
|
+
console.log(` Name: ${pluginResult.plugin}`);
|
|
320
|
+
if (pluginResult.version) {
|
|
321
|
+
console.log(` Version: ${pluginResult.version}`);
|
|
322
|
+
}
|
|
323
|
+
console.log(` Path: ${pluginResult.path}`);
|
|
324
|
+
console.log('');
|
|
325
|
+
totalSuccessCount++;
|
|
326
|
+
continue;
|
|
334
327
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
console.log(` Version: ${pluginResult.version}`);
|
|
328
|
+
// Handle single skill result (legacy behavior)
|
|
329
|
+
const singleResult = result.singleSkillResult;
|
|
330
|
+
if (!singleResult) {
|
|
331
|
+
console.error('✗ Installation failed: No result returned');
|
|
332
|
+
totalFailCount++;
|
|
341
333
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
334
|
+
else if (singleResult.success) {
|
|
335
|
+
console.log('');
|
|
336
|
+
console.log(`✓ Skill "${singleResult.skillName}" installed successfully!`);
|
|
337
|
+
console.log(` Path: ${singleResult.skillPath}`);
|
|
338
|
+
totalSuccessCount++;
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
console.error('✗ Installation failed!');
|
|
342
|
+
console.error(` Error: ${singleResult.error || 'Unknown error'}`);
|
|
343
|
+
totalFailCount++;
|
|
344
|
+
}
|
|
345
|
+
} // End of for loop
|
|
346
|
+
// Display final summary
|
|
353
347
|
console.log('');
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
console.log(`
|
|
357
|
-
|
|
358
|
-
|
|
348
|
+
console.log('─'.repeat(50));
|
|
349
|
+
if (sources.length > 1) {
|
|
350
|
+
console.log(`Installation complete: ${totalSuccessCount} succeeded, ${totalFailCount} failed`);
|
|
351
|
+
}
|
|
352
|
+
else if (totalSuccessCount > 0) {
|
|
353
|
+
console.log('Installation complete!');
|
|
359
354
|
}
|
|
360
355
|
else {
|
|
361
|
-
console.
|
|
362
|
-
console.error(` Error: ${singleResult.error || 'Unknown error'}`);
|
|
356
|
+
console.log('Installation failed.');
|
|
363
357
|
process.exit(1);
|
|
364
358
|
}
|
|
365
359
|
}
|
|
@@ -389,7 +383,7 @@ program
|
|
|
389
383
|
aiTool = globalOpts.tool;
|
|
390
384
|
}
|
|
391
385
|
else {
|
|
392
|
-
aiTool = await promptAiTool();
|
|
386
|
+
aiTool = await (0, ui_1.promptAiTool)();
|
|
393
387
|
}
|
|
394
388
|
// If no specific directory and --all flag, show both directories
|
|
395
389
|
if (!globalOpts.skillsDir && options.all) {
|
|
@@ -441,7 +435,7 @@ program
|
|
|
441
435
|
aiTool = globalOpts.tool;
|
|
442
436
|
}
|
|
443
437
|
else {
|
|
444
|
-
aiTool = await promptAiTool();
|
|
438
|
+
aiTool = await (0, ui_1.promptAiTool)();
|
|
445
439
|
}
|
|
446
440
|
const skills = await skillsManager.listInstalled(globalOpts.skillsDir, aiTool);
|
|
447
441
|
if (skills.length === 0) {
|
|
@@ -450,7 +444,7 @@ program
|
|
|
450
444
|
}
|
|
451
445
|
// If no name provided, prompt to select from list
|
|
452
446
|
if (!name) {
|
|
453
|
-
const selectedIndices = await promptSkillSelection(skills);
|
|
447
|
+
const selectedIndices = await (0, ui_1.promptSkillSelection)(skills);
|
|
454
448
|
if (selectedIndices.length === 0) {
|
|
455
449
|
console.log('No skills selected.');
|
|
456
450
|
process.exit(0);
|
|
@@ -463,7 +457,7 @@ program
|
|
|
463
457
|
try {
|
|
464
458
|
// Confirm uninstall unless --yes flag is provided
|
|
465
459
|
if (!options.yes) {
|
|
466
|
-
const confirmed = await
|
|
460
|
+
const confirmed = await (0, ui_1.promptYesNo)(`Uninstall skill "${skill.name}" from ${aiTool}?`);
|
|
467
461
|
if (!confirmed) {
|
|
468
462
|
console.log(`Skipped: ${skill.name}`);
|
|
469
463
|
continue;
|
|
@@ -494,7 +488,7 @@ program
|
|
|
494
488
|
}
|
|
495
489
|
// Confirm uninstall unless --yes flag is provided
|
|
496
490
|
if (!options.yes) {
|
|
497
|
-
const confirmed = await
|
|
491
|
+
const confirmed = await (0, ui_1.promptYesNo)(`Uninstall skill "${name}" from ${aiTool}?`);
|
|
498
492
|
if (!confirmed) {
|
|
499
493
|
console.log('Uninstall cancelled.');
|
|
500
494
|
process.exit(0);
|
|
@@ -513,245 +507,6 @@ program
|
|
|
513
507
|
process.exit(1);
|
|
514
508
|
}
|
|
515
509
|
});
|
|
516
|
-
function promptPassword() {
|
|
517
|
-
return new Promise((resolve, reject) => {
|
|
518
|
-
// Check if setRawMode is available (TTY required)
|
|
519
|
-
if (typeof process.stdin.setRawMode !== 'function') {
|
|
520
|
-
console.error('\nError: Interactive password input requires a TTY.');
|
|
521
|
-
console.error('Please use -p option or WIKI_PASSWORD environment variable.');
|
|
522
|
-
reject(new Error('TTY not available for interactive password input'));
|
|
523
|
-
return;
|
|
524
|
-
}
|
|
525
|
-
const rl = readline_1.default.createInterface({
|
|
526
|
-
input: process.stdin,
|
|
527
|
-
output: process.stdout
|
|
528
|
-
});
|
|
529
|
-
// Turn off echo
|
|
530
|
-
process.stdout.write('Password: ');
|
|
531
|
-
process.stdin.setRawMode(true);
|
|
532
|
-
let password = '';
|
|
533
|
-
const onData = (char) => {
|
|
534
|
-
const str = char.toString();
|
|
535
|
-
if (str === '\n' || str === '\r' || str === '\u0004') {
|
|
536
|
-
// Enter or Ctrl-D
|
|
537
|
-
process.stdin.setRawMode(false);
|
|
538
|
-
process.stdin.removeListener('data', onData);
|
|
539
|
-
process.stdout.write('\n');
|
|
540
|
-
rl.close();
|
|
541
|
-
resolve(password);
|
|
542
|
-
}
|
|
543
|
-
else if (str === '\u0003') {
|
|
544
|
-
// Ctrl-C
|
|
545
|
-
process.stdout.write('\n');
|
|
546
|
-
process.exit(1);
|
|
547
|
-
}
|
|
548
|
-
else if (str === '\u007f') {
|
|
549
|
-
// Backspace
|
|
550
|
-
if (password.length > 0) {
|
|
551
|
-
password = password.slice(0, -1);
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
else {
|
|
555
|
-
// Regular character
|
|
556
|
-
password += str;
|
|
557
|
-
}
|
|
558
|
-
};
|
|
559
|
-
process.stdin.on('data', onData);
|
|
560
|
-
process.stdin.setRawMode(true);
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
function confirm(message) {
|
|
564
|
-
return new Promise((resolve) => {
|
|
565
|
-
const rl = readline_1.default.createInterface({
|
|
566
|
-
input: process.stdin,
|
|
567
|
-
output: process.stdout
|
|
568
|
-
});
|
|
569
|
-
rl.question(`${message} (y/N): `, (answer) => {
|
|
570
|
-
rl.close();
|
|
571
|
-
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
572
|
-
});
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
function promptSkillsDir(aiTool) {
|
|
576
|
-
return new Promise((resolve) => {
|
|
577
|
-
const rl = readline_1.default.createInterface({
|
|
578
|
-
input: process.stdin,
|
|
579
|
-
output: process.stdout
|
|
580
|
-
});
|
|
581
|
-
const globalDir = skillsManager.getGlobalSkillsDir(aiTool);
|
|
582
|
-
const localDir = skillsManager.getLocalSkillsDir(aiTool);
|
|
583
|
-
console.log('');
|
|
584
|
-
console.log('Select installation directory:');
|
|
585
|
-
console.log(` 1. Global: ${globalDir}`);
|
|
586
|
-
console.log(` 2. Local: ${localDir}`);
|
|
587
|
-
console.log('');
|
|
588
|
-
rl.question('Choose [1/2] (default: 1): ', (answer) => {
|
|
589
|
-
rl.close();
|
|
590
|
-
const choice = answer.trim() || '1';
|
|
591
|
-
if (choice === '1') {
|
|
592
|
-
resolve(globalDir);
|
|
593
|
-
}
|
|
594
|
-
else if (choice === '2') {
|
|
595
|
-
resolve(localDir);
|
|
596
|
-
}
|
|
597
|
-
else {
|
|
598
|
-
console.log('Invalid choice, using global directory.');
|
|
599
|
-
resolve(globalDir);
|
|
600
|
-
}
|
|
601
|
-
});
|
|
602
|
-
});
|
|
603
|
-
}
|
|
604
|
-
function promptAiTool() {
|
|
605
|
-
return new Promise((resolve) => {
|
|
606
|
-
const rl = readline_1.default.createInterface({
|
|
607
|
-
input: process.stdin,
|
|
608
|
-
output: process.stdout
|
|
609
|
-
});
|
|
610
|
-
console.log('');
|
|
611
|
-
console.log('Select AI tool:');
|
|
612
|
-
console.log(' 1. Claude Code (~/.claude/skills/)');
|
|
613
|
-
console.log(' 2. Codex (~/.codex/skills/)');
|
|
614
|
-
console.log('');
|
|
615
|
-
rl.question('Choose [1/2] (default: 1): ', (answer) => {
|
|
616
|
-
rl.close();
|
|
617
|
-
const choice = answer.trim() || '1';
|
|
618
|
-
if (choice === '1') {
|
|
619
|
-
resolve('claude');
|
|
620
|
-
}
|
|
621
|
-
else if (choice === '2') {
|
|
622
|
-
resolve('codex');
|
|
623
|
-
}
|
|
624
|
-
else {
|
|
625
|
-
console.log('Invalid choice, using claude.');
|
|
626
|
-
resolve('claude');
|
|
627
|
-
}
|
|
628
|
-
});
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
function selectSkillsFromPackage(skills) {
|
|
632
|
-
return new Promise((resolve) => {
|
|
633
|
-
const rl = readline_1.default.createInterface({
|
|
634
|
-
input: process.stdin,
|
|
635
|
-
output: process.stdout
|
|
636
|
-
});
|
|
637
|
-
console.log('');
|
|
638
|
-
console.log(`${colors.cyan}Multi-skill package detected!${colors.reset}`);
|
|
639
|
-
console.log(`${colors.cyan}Found ${skills.length} skill(s) in this package:${colors.reset}`);
|
|
640
|
-
console.log('');
|
|
641
|
-
// Display all skills with colors and separators
|
|
642
|
-
for (let i = 0; i < skills.length; i++) {
|
|
643
|
-
const skill = skills[i];
|
|
644
|
-
// Separator line before each skill
|
|
645
|
-
console.log(`${colors.dim}${'─'.repeat(60)}${colors.reset}`);
|
|
646
|
-
// Index and skill name
|
|
647
|
-
console.log(`${colors.bright}${colors.green}[${i + 1}]${colors.reset} ${colors.bright}${colors.yellow}${skill.name}${colors.reset}`);
|
|
648
|
-
// Description
|
|
649
|
-
const lines = skill.description.split('\n');
|
|
650
|
-
for (const line of lines) {
|
|
651
|
-
console.log(`${colors.dim} ${line}${colors.reset}`);
|
|
652
|
-
}
|
|
653
|
-
// Relative path in package
|
|
654
|
-
console.log(`${colors.dim} Package path: ${skill.relativePath}${colors.reset}`);
|
|
655
|
-
}
|
|
656
|
-
// Separator line after last skill
|
|
657
|
-
console.log(`${colors.dim}${'─'.repeat(60)}${colors.reset}`);
|
|
658
|
-
console.log('');
|
|
659
|
-
console.log('Enter the numbers of the skills to install (separated by spaces, e.g., "1 3 5"):');
|
|
660
|
-
console.log('Press Enter to install all skills:');
|
|
661
|
-
rl.question('Your choice: ', (answer) => {
|
|
662
|
-
rl.close();
|
|
663
|
-
const input = answer.trim();
|
|
664
|
-
if (!input) {
|
|
665
|
-
// Install all skills
|
|
666
|
-
console.log(`Installing all ${skills.length} skills...`);
|
|
667
|
-
resolve(skills);
|
|
668
|
-
return;
|
|
669
|
-
}
|
|
670
|
-
// Parse the input and extract valid indices
|
|
671
|
-
const selectedNumbers = input.split(/\s+/).map(s => parseInt(s, 10));
|
|
672
|
-
const selectedSkills = [];
|
|
673
|
-
for (const num of selectedNumbers) {
|
|
674
|
-
if (isNaN(num)) {
|
|
675
|
-
console.log(`Skipping invalid number: ${input}`);
|
|
676
|
-
continue;
|
|
677
|
-
}
|
|
678
|
-
if (num < 1 || num > skills.length) {
|
|
679
|
-
console.log(`Skipping out of range number: ${num}`);
|
|
680
|
-
continue;
|
|
681
|
-
}
|
|
682
|
-
selectedSkills.push(skills[num - 1]);
|
|
683
|
-
}
|
|
684
|
-
if (selectedSkills.length === 0) {
|
|
685
|
-
console.log('No valid skills selected.');
|
|
686
|
-
resolve([]);
|
|
687
|
-
return;
|
|
688
|
-
}
|
|
689
|
-
console.log('');
|
|
690
|
-
console.log(`Selected skills: ${selectedSkills.map(s => s.name).join(', ')}`);
|
|
691
|
-
resolve(selectedSkills);
|
|
692
|
-
});
|
|
693
|
-
});
|
|
694
|
-
}
|
|
695
|
-
function promptSkillSelection(skills) {
|
|
696
|
-
return new Promise((resolve) => {
|
|
697
|
-
const rl = readline_1.default.createInterface({
|
|
698
|
-
input: process.stdin,
|
|
699
|
-
output: process.stdout
|
|
700
|
-
});
|
|
701
|
-
console.log('');
|
|
702
|
-
console.log(`${colors.cyan}Installed skills:${colors.reset}`);
|
|
703
|
-
console.log('');
|
|
704
|
-
// Display all skills with colors and separators
|
|
705
|
-
for (let i = 0; i < skills.length; i++) {
|
|
706
|
-
const skill = skills[i];
|
|
707
|
-
// Separator line before each skill
|
|
708
|
-
console.log(`${colors.dim}${'─'.repeat(60)}${colors.reset}`);
|
|
709
|
-
// Index and skill name
|
|
710
|
-
console.log(`${colors.bright}${colors.green}[${i + 1}]${colors.reset} ${colors.bright}${colors.yellow}${skill.name}${colors.reset}`);
|
|
711
|
-
// Description
|
|
712
|
-
console.log(`${colors.dim} ${skill.description}${colors.reset}`);
|
|
713
|
-
// Path
|
|
714
|
-
console.log(`${colors.dim} ${skill.path}${colors.reset}`);
|
|
715
|
-
}
|
|
716
|
-
// Separator line after last skill
|
|
717
|
-
console.log(`${colors.dim}${'─'.repeat(60)}${colors.reset}`);
|
|
718
|
-
console.log('');
|
|
719
|
-
console.log('Enter the numbers of the skills to uninstall (separated by spaces, e.g., "1 3 5"):');
|
|
720
|
-
console.log('Press Enter to cancel:');
|
|
721
|
-
rl.question('Your choice: ', (answer) => {
|
|
722
|
-
rl.close();
|
|
723
|
-
const input = answer.trim();
|
|
724
|
-
if (!input) {
|
|
725
|
-
resolve([]);
|
|
726
|
-
return;
|
|
727
|
-
}
|
|
728
|
-
// Parse the input and extract valid indices
|
|
729
|
-
const selectedNumbers = input.split(/\s+/).map(s => parseInt(s, 10));
|
|
730
|
-
const validIndices = [];
|
|
731
|
-
for (const num of selectedNumbers) {
|
|
732
|
-
if (isNaN(num)) {
|
|
733
|
-
console.log(`Skipping invalid number: ${input}`);
|
|
734
|
-
continue;
|
|
735
|
-
}
|
|
736
|
-
if (num < 1 || num > skills.length) {
|
|
737
|
-
console.log(`Skipping out of range number: ${num}`);
|
|
738
|
-
continue;
|
|
739
|
-
}
|
|
740
|
-
validIndices.push(num - 1); // Convert to 0-based index
|
|
741
|
-
}
|
|
742
|
-
// Remove duplicates
|
|
743
|
-
const uniqueIndices = [...new Set(validIndices)];
|
|
744
|
-
if (uniqueIndices.length === 0) {
|
|
745
|
-
console.log('No valid skills selected.');
|
|
746
|
-
resolve([]);
|
|
747
|
-
return;
|
|
748
|
-
}
|
|
749
|
-
console.log('');
|
|
750
|
-
console.log(`Selected skills: ${uniqueIndices.map(i => skills[i].name).join(', ')}`);
|
|
751
|
-
resolve(uniqueIndices);
|
|
752
|
-
});
|
|
753
|
-
});
|
|
754
|
-
}
|
|
755
510
|
async function listSkillsFromBothDirectories(aiTool) {
|
|
756
511
|
const globalDir = skillsManager.getGlobalSkillsDir(aiTool);
|
|
757
512
|
const localDir = skillsManager.getLocalSkillsDir(aiTool);
|
|
@@ -793,18 +548,6 @@ async function listSkillsFromBothDirectories(aiTool) {
|
|
|
793
548
|
console.log('No skills installed in either location.');
|
|
794
549
|
}
|
|
795
550
|
}
|
|
796
|
-
function promptUsername() {
|
|
797
|
-
return new Promise((resolve) => {
|
|
798
|
-
const rl = readline_1.default.createInterface({
|
|
799
|
-
input: process.stdin,
|
|
800
|
-
output: process.stdout
|
|
801
|
-
});
|
|
802
|
-
rl.question('Wiki username: ', (answer) => {
|
|
803
|
-
rl.close();
|
|
804
|
-
resolve(answer.trim());
|
|
805
|
-
});
|
|
806
|
-
});
|
|
807
|
-
}
|
|
808
551
|
async function searchAndSelectSkill(username, password, wikiUrl, allowSelfSigned) {
|
|
809
552
|
const searcher = new wiki_1.WikiSearcher();
|
|
810
553
|
const selector = new wiki_1.SkillSelector();
|
|
@@ -821,96 +564,18 @@ async function searchAndSelectSkill(username, password, wikiUrl, allowSelfSigned
|
|
|
821
564
|
});
|
|
822
565
|
if (items.length === 0) {
|
|
823
566
|
console.log('No skills found.');
|
|
824
|
-
return
|
|
567
|
+
return [];
|
|
825
568
|
}
|
|
826
569
|
// Parse items (fetch comments)
|
|
827
570
|
const parser = new wiki_1.WikiParser(searcher.httpClientInstance);
|
|
828
571
|
const parsed = await parser.parseSkillItems(items);
|
|
829
572
|
// Display and select
|
|
830
|
-
const
|
|
831
|
-
return
|
|
573
|
+
const selectedUrls = await selector.displayAndSelect(parsed);
|
|
574
|
+
return selectedUrls;
|
|
832
575
|
}
|
|
833
576
|
catch (error) {
|
|
834
577
|
console.error(`Search failed: ${error.message}`);
|
|
835
|
-
return
|
|
578
|
+
return [];
|
|
836
579
|
}
|
|
837
580
|
}
|
|
838
|
-
/**
|
|
839
|
-
* Prompt user for yes/no confirmation
|
|
840
|
-
*/
|
|
841
|
-
function promptYesNo(message) {
|
|
842
|
-
return new Promise((resolve) => {
|
|
843
|
-
const rl = readline_1.default.createInterface({
|
|
844
|
-
input: process.stdin,
|
|
845
|
-
output: process.stdout
|
|
846
|
-
});
|
|
847
|
-
rl.question(`${message} [Y/n]: `, (answer) => {
|
|
848
|
-
rl.close();
|
|
849
|
-
const trimmed = answer.trim().toLowerCase();
|
|
850
|
-
resolve(trimmed === '' || trimmed === 'y' || trimmed === 'yes');
|
|
851
|
-
});
|
|
852
|
-
});
|
|
853
|
-
}
|
|
854
|
-
/**
|
|
855
|
-
* Select plugins from a marketplace
|
|
856
|
-
*/
|
|
857
|
-
function selectPluginsFromMarketplace(plugins) {
|
|
858
|
-
return new Promise((resolve) => {
|
|
859
|
-
const rl = readline_1.default.createInterface({
|
|
860
|
-
input: process.stdin,
|
|
861
|
-
output: process.stdout
|
|
862
|
-
});
|
|
863
|
-
console.log('');
|
|
864
|
-
console.log(`${colors.cyan}Available plugins:${colors.reset}`);
|
|
865
|
-
console.log('');
|
|
866
|
-
for (let i = 0; i < plugins.length; i++) {
|
|
867
|
-
const plugin = plugins[i];
|
|
868
|
-
console.log(`${colors.dim}${'─'.repeat(60)}${colors.reset}`);
|
|
869
|
-
console.log(`${colors.bright}${colors.green}[${i + 1}]${colors.reset} ${colors.bright}${colors.yellow}${plugin.name}${colors.reset} v${plugin.version || 'unknown'}`);
|
|
870
|
-
if (plugin.metadata.description) {
|
|
871
|
-
const lines = plugin.metadata.description.split('\n');
|
|
872
|
-
for (const line of lines) {
|
|
873
|
-
console.log(`${colors.dim} ${line}${colors.reset}`);
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
console.log(`${colors.dim}${'─'.repeat(60)}${colors.reset}`);
|
|
878
|
-
console.log('');
|
|
879
|
-
console.log('Enter the numbers of the plugins to install (separated by spaces, e.g., "1 3 5"):');
|
|
880
|
-
console.log('Press Enter to install all plugins:');
|
|
881
|
-
rl.question('Your choice: ', (answer) => {
|
|
882
|
-
rl.close();
|
|
883
|
-
const input = answer.trim();
|
|
884
|
-
if (!input) {
|
|
885
|
-
// Install all
|
|
886
|
-
console.log(`Installing all ${plugins.length} plugins...`);
|
|
887
|
-
resolve(plugins.map(p => ({ name: p.name, version: p.version })));
|
|
888
|
-
return;
|
|
889
|
-
}
|
|
890
|
-
// Parse selection
|
|
891
|
-
const selectedNumbers = input.split(/\s+/).map(s => parseInt(s, 10));
|
|
892
|
-
const selected = [];
|
|
893
|
-
for (const num of selectedNumbers) {
|
|
894
|
-
if (isNaN(num)) {
|
|
895
|
-
console.log(`Skipping invalid number: ${input}`);
|
|
896
|
-
continue;
|
|
897
|
-
}
|
|
898
|
-
if (num < 1 || num > plugins.length) {
|
|
899
|
-
console.log(`Skipping out of range number: ${num}`);
|
|
900
|
-
continue;
|
|
901
|
-
}
|
|
902
|
-
const plugin = plugins[num - 1];
|
|
903
|
-
selected.push({ name: plugin.name, version: plugin.version });
|
|
904
|
-
}
|
|
905
|
-
if (selected.length === 0) {
|
|
906
|
-
console.log('No valid plugins selected.');
|
|
907
|
-
resolve([]);
|
|
908
|
-
return;
|
|
909
|
-
}
|
|
910
|
-
console.log('');
|
|
911
|
-
console.log(`Selected plugins: ${selected.map(p => p.name).join(', ')}`);
|
|
912
|
-
resolve(selected);
|
|
913
|
-
});
|
|
914
|
-
});
|
|
915
|
-
}
|
|
916
581
|
program.parse();
|