reskill 0.14.0 → 0.16.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/README.md +62 -31
- package/README.zh-CN.md +81 -50
- package/dist/cli/commands/completion.d.ts +13 -0
- package/dist/cli/commands/completion.d.ts.map +1 -0
- package/dist/cli/commands/index.d.ts +1 -0
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/uninstall.d.ts.map +1 -1
- package/dist/cli/index.js +856 -494
- package/dist/core/cache-manager.d.ts +13 -0
- package/dist/core/cache-manager.d.ts.map +1 -1
- package/dist/core/installer.d.ts +9 -0
- package/dist/core/installer.d.ts.map +1 -1
- package/dist/core/lock-manager.d.ts +1 -0
- package/dist/core/lock-manager.d.ts.map +1 -1
- package/dist/core/skill-manager.d.ts +8 -0
- package/dist/core/skill-manager.d.ts.map +1 -1
- package/dist/index.js +301 -239
- package/dist/types/index.d.ts +3 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/fs.d.ts +6 -0
- package/dist/utils/fs.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/update-notifier.d.ts +49 -0
- package/dist/utils/update-notifier.d.ts.map +1 -0
- package/package.json +3 -2
package/dist/cli/index.js
CHANGED
|
@@ -4,10 +4,11 @@ import * as __WEBPACK_EXTERNAL_MODULE_node_path__ from "node:path";
|
|
|
4
4
|
import * as __WEBPACK_EXTERNAL_MODULE_node_url__ from "node:url";
|
|
5
5
|
import * as __WEBPACK_EXTERNAL_MODULE_commander__ from "commander";
|
|
6
6
|
import * as __WEBPACK_EXTERNAL_MODULE_chalk__ from "chalk";
|
|
7
|
+
import * as __WEBPACK_EXTERNAL_MODULE_semver__ from "semver";
|
|
8
|
+
import * as __WEBPACK_EXTERNAL_MODULE_tabtab__ from "tabtab";
|
|
7
9
|
import * as __WEBPACK_EXTERNAL_MODULE_node_os__ from "node:os";
|
|
8
10
|
import * as __WEBPACK_EXTERNAL_MODULE_node_child_process__ from "node:child_process";
|
|
9
11
|
import * as __WEBPACK_EXTERNAL_MODULE_node_util__ from "node:util";
|
|
10
|
-
import * as __WEBPACK_EXTERNAL_MODULE_semver__ from "semver";
|
|
11
12
|
import * as __WEBPACK_EXTERNAL_MODULE__clack_prompts__ from "@clack/prompts";
|
|
12
13
|
import * as __WEBPACK_EXTERNAL_MODULE_ora__ from "ora";
|
|
13
14
|
var __webpack_modules__ = {
|
|
@@ -26,93 +27,7 @@ function __webpack_require__(moduleId) {
|
|
|
26
27
|
return module.exports;
|
|
27
28
|
}
|
|
28
29
|
var external_node_fs_ = __webpack_require__("node:fs");
|
|
29
|
-
|
|
30
|
-
return external_node_fs_.existsSync(filePath);
|
|
31
|
-
}
|
|
32
|
-
function readJson(filePath) {
|
|
33
|
-
const content = external_node_fs_.readFileSync(filePath, 'utf-8');
|
|
34
|
-
return JSON.parse(content);
|
|
35
|
-
}
|
|
36
|
-
function writeJson(filePath, data, indent = 2) {
|
|
37
|
-
const dir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(filePath);
|
|
38
|
-
if (!exists(dir)) external_node_fs_.mkdirSync(dir, {
|
|
39
|
-
recursive: true
|
|
40
|
-
});
|
|
41
|
-
external_node_fs_.writeFileSync(filePath, `${JSON.stringify(data, null, indent)}\n`, 'utf-8');
|
|
42
|
-
}
|
|
43
|
-
function ensureDir(dirPath) {
|
|
44
|
-
if (!exists(dirPath)) external_node_fs_.mkdirSync(dirPath, {
|
|
45
|
-
recursive: true
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
function remove(targetPath) {
|
|
49
|
-
if (exists(targetPath)) external_node_fs_.rmSync(targetPath, {
|
|
50
|
-
recursive: true,
|
|
51
|
-
force: true
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
function copyDir(src, dest, options) {
|
|
55
|
-
const exclude = options?.exclude || [];
|
|
56
|
-
ensureDir(dest);
|
|
57
|
-
const entries = external_node_fs_.readdirSync(src, {
|
|
58
|
-
withFileTypes: true
|
|
59
|
-
});
|
|
60
|
-
for (const entry of entries){
|
|
61
|
-
if (exclude.includes(entry.name)) continue;
|
|
62
|
-
const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
|
|
63
|
-
const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
|
|
64
|
-
if (entry.isDirectory()) copyDir(srcPath, destPath, options);
|
|
65
|
-
else external_node_fs_.copyFileSync(srcPath, destPath);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function listDir(dirPath) {
|
|
69
|
-
if (!exists(dirPath)) return [];
|
|
70
|
-
return external_node_fs_.readdirSync(dirPath);
|
|
71
|
-
}
|
|
72
|
-
function isDirectory(targetPath) {
|
|
73
|
-
if (!exists(targetPath)) return false;
|
|
74
|
-
return external_node_fs_.statSync(targetPath).isDirectory();
|
|
75
|
-
}
|
|
76
|
-
function isSymlink(targetPath) {
|
|
77
|
-
if (!exists(targetPath)) return false;
|
|
78
|
-
return external_node_fs_.lstatSync(targetPath).isSymbolicLink();
|
|
79
|
-
}
|
|
80
|
-
function createSymlink(target, linkPath) {
|
|
81
|
-
const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
|
|
82
|
-
ensureDir(linkDir);
|
|
83
|
-
if (exists(linkPath)) remove(linkPath);
|
|
84
|
-
external_node_fs_.symlinkSync(target, linkPath, 'dir');
|
|
85
|
-
}
|
|
86
|
-
function getRealPath(linkPath) {
|
|
87
|
-
return external_node_fs_.realpathSync(linkPath);
|
|
88
|
-
}
|
|
89
|
-
function getSkillsJsonPath(projectRoot) {
|
|
90
|
-
const root = projectRoot || process.cwd();
|
|
91
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(root, 'skills.json');
|
|
92
|
-
}
|
|
93
|
-
function getSkillsLockPath(projectRoot) {
|
|
94
|
-
const root = projectRoot || process.cwd();
|
|
95
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(root, 'skills.lock');
|
|
96
|
-
}
|
|
97
|
-
function getCacheDir() {
|
|
98
|
-
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
99
|
-
return process.env.RESKILL_CACHE_DIR || __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.reskill-cache');
|
|
100
|
-
}
|
|
101
|
-
function getHomeDir() {
|
|
102
|
-
return process.env.HOME || process.env.USERPROFILE || '';
|
|
103
|
-
}
|
|
104
|
-
function getGlobalSkillsDir() {
|
|
105
|
-
const home = getHomeDir();
|
|
106
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.claude', 'skills');
|
|
107
|
-
}
|
|
108
|
-
function shortenPath(fullPath, cwd) {
|
|
109
|
-
const home = getHomeDir();
|
|
110
|
-
const currentDir = cwd || process.cwd();
|
|
111
|
-
if (fullPath.startsWith(home)) return fullPath.replace(home, '~');
|
|
112
|
-
if (fullPath.startsWith(currentDir)) return `.${fullPath.slice(currentDir.length)}`;
|
|
113
|
-
return fullPath;
|
|
114
|
-
}
|
|
115
|
-
const logger = {
|
|
30
|
+
const logger_logger = {
|
|
116
31
|
info (message) {
|
|
117
32
|
console.log(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].blue('ℹ'), message);
|
|
118
33
|
},
|
|
@@ -153,6 +68,40 @@ const logger = {
|
|
|
153
68
|
}
|
|
154
69
|
}
|
|
155
70
|
};
|
|
71
|
+
async function checkForUpdate(packageName, currentVersion, options = {}) {
|
|
72
|
+
const timeout = options.timeout ?? 3000;
|
|
73
|
+
try {
|
|
74
|
+
const controller = new AbortController();
|
|
75
|
+
const timeoutId = setTimeout(()=>controller.abort(), timeout);
|
|
76
|
+
const response = await fetch(`https://registry.npmjs.org/${packageName}`, {
|
|
77
|
+
signal: controller.signal
|
|
78
|
+
});
|
|
79
|
+
clearTimeout(timeoutId);
|
|
80
|
+
if (!response.ok) return null;
|
|
81
|
+
const data = await response.json();
|
|
82
|
+
const latest = data['dist-tags']?.latest;
|
|
83
|
+
if (!latest) return null;
|
|
84
|
+
const hasUpdate = __WEBPACK_EXTERNAL_MODULE_semver__["default"].gt(latest, currentVersion);
|
|
85
|
+
return {
|
|
86
|
+
current: currentVersion,
|
|
87
|
+
latest,
|
|
88
|
+
hasUpdate
|
|
89
|
+
};
|
|
90
|
+
} catch {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function formatUpdateMessage(result) {
|
|
95
|
+
if (!result.hasUpdate) return '';
|
|
96
|
+
return `
|
|
97
|
+
┌────────────────────────────────────────────────────┐
|
|
98
|
+
│ │
|
|
99
|
+
│ Update available: ${result.current} → ${result.latest.padEnd(10)} │
|
|
100
|
+
│ Run: npm install -g reskill@latest │
|
|
101
|
+
│ │
|
|
102
|
+
└────────────────────────────────────────────────────┘
|
|
103
|
+
`;
|
|
104
|
+
}
|
|
156
105
|
const agent_registry_home = (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)();
|
|
157
106
|
const agents = {
|
|
158
107
|
amp: {
|
|
@@ -286,7 +235,94 @@ function getAgentConfig(type) {
|
|
|
286
235
|
function isValidAgentType(type) {
|
|
287
236
|
return type in agents;
|
|
288
237
|
}
|
|
289
|
-
|
|
238
|
+
function exists(filePath) {
|
|
239
|
+
return external_node_fs_.existsSync(filePath);
|
|
240
|
+
}
|
|
241
|
+
function readJson(filePath) {
|
|
242
|
+
const content = external_node_fs_.readFileSync(filePath, 'utf-8');
|
|
243
|
+
return JSON.parse(content);
|
|
244
|
+
}
|
|
245
|
+
function writeJson(filePath, data, indent = 2) {
|
|
246
|
+
const dir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(filePath);
|
|
247
|
+
if (!exists(dir)) external_node_fs_.mkdirSync(dir, {
|
|
248
|
+
recursive: true
|
|
249
|
+
});
|
|
250
|
+
external_node_fs_.writeFileSync(filePath, `${JSON.stringify(data, null, indent)}\n`, 'utf-8');
|
|
251
|
+
}
|
|
252
|
+
function ensureDir(dirPath) {
|
|
253
|
+
if (!exists(dirPath)) external_node_fs_.mkdirSync(dirPath, {
|
|
254
|
+
recursive: true
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
function remove(targetPath) {
|
|
258
|
+
if (exists(targetPath)) external_node_fs_.rmSync(targetPath, {
|
|
259
|
+
recursive: true,
|
|
260
|
+
force: true
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
function copyDir(src, dest, options) {
|
|
264
|
+
const exclude = options?.exclude || [];
|
|
265
|
+
const excludePrefix = options?.excludePrefix || '_';
|
|
266
|
+
ensureDir(dest);
|
|
267
|
+
const entries = external_node_fs_.readdirSync(src, {
|
|
268
|
+
withFileTypes: true
|
|
269
|
+
});
|
|
270
|
+
for (const entry of entries){
|
|
271
|
+
if (exclude.includes(entry.name) || entry.name.startsWith(excludePrefix)) continue;
|
|
272
|
+
const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
|
|
273
|
+
const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
|
|
274
|
+
if (entry.isDirectory()) copyDir(srcPath, destPath, options);
|
|
275
|
+
else external_node_fs_.copyFileSync(srcPath, destPath);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
function listDir(dirPath) {
|
|
279
|
+
if (!exists(dirPath)) return [];
|
|
280
|
+
return external_node_fs_.readdirSync(dirPath);
|
|
281
|
+
}
|
|
282
|
+
function isDirectory(targetPath) {
|
|
283
|
+
if (!exists(targetPath)) return false;
|
|
284
|
+
return external_node_fs_.statSync(targetPath).isDirectory();
|
|
285
|
+
}
|
|
286
|
+
function isSymlink(targetPath) {
|
|
287
|
+
if (!exists(targetPath)) return false;
|
|
288
|
+
return external_node_fs_.lstatSync(targetPath).isSymbolicLink();
|
|
289
|
+
}
|
|
290
|
+
function createSymlink(target, linkPath) {
|
|
291
|
+
const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
|
|
292
|
+
ensureDir(linkDir);
|
|
293
|
+
if (exists(linkPath)) remove(linkPath);
|
|
294
|
+
external_node_fs_.symlinkSync(target, linkPath, 'dir');
|
|
295
|
+
}
|
|
296
|
+
function getRealPath(linkPath) {
|
|
297
|
+
return external_node_fs_.realpathSync(linkPath);
|
|
298
|
+
}
|
|
299
|
+
function getSkillsJsonPath(projectRoot) {
|
|
300
|
+
const root = projectRoot || process.cwd();
|
|
301
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(root, 'skills.json');
|
|
302
|
+
}
|
|
303
|
+
function getSkillsLockPath(projectRoot) {
|
|
304
|
+
const root = projectRoot || process.cwd();
|
|
305
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(root, 'skills.lock');
|
|
306
|
+
}
|
|
307
|
+
function getCacheDir() {
|
|
308
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
309
|
+
return process.env.RESKILL_CACHE_DIR || __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.reskill-cache');
|
|
310
|
+
}
|
|
311
|
+
function getHomeDir() {
|
|
312
|
+
return process.env.HOME || process.env.USERPROFILE || '';
|
|
313
|
+
}
|
|
314
|
+
function getGlobalSkillsDir() {
|
|
315
|
+
const home = getHomeDir();
|
|
316
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.claude', 'skills');
|
|
317
|
+
}
|
|
318
|
+
function shortenPath(fullPath, cwd) {
|
|
319
|
+
const home = getHomeDir();
|
|
320
|
+
const currentDir = cwd || process.cwd();
|
|
321
|
+
if (fullPath.startsWith(home)) return fullPath.replace(home, '~');
|
|
322
|
+
if (fullPath.startsWith(currentDir)) return `.${fullPath.slice(currentDir.length)}`;
|
|
323
|
+
return fullPath;
|
|
324
|
+
}
|
|
325
|
+
const git_execAsync = (0, __WEBPACK_EXTERNAL_MODULE_node_util__.promisify)(__WEBPACK_EXTERNAL_MODULE_node_child_process__.exec);
|
|
290
326
|
class GitCloneError extends Error {
|
|
291
327
|
repoUrl;
|
|
292
328
|
originalError;
|
|
@@ -334,7 +370,7 @@ class GitCloneError extends Error {
|
|
|
334
370
|
}
|
|
335
371
|
}
|
|
336
372
|
async function git(args, cwd) {
|
|
337
|
-
const { stdout } = await
|
|
373
|
+
const { stdout } = await git_execAsync(`git ${args.join(' ')}`, {
|
|
338
374
|
cwd,
|
|
339
375
|
encoding: 'utf-8'
|
|
340
376
|
});
|
|
@@ -468,40 +504,236 @@ function parseGitUrl(url) {
|
|
|
468
504
|
}
|
|
469
505
|
return null;
|
|
470
506
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
507
|
+
const installer_AGENTS_DIR = '.agents';
|
|
508
|
+
const installer_SKILLS_SUBDIR = 'skills';
|
|
509
|
+
const DEFAULT_EXCLUDE_FILES = [
|
|
510
|
+
'README.md',
|
|
511
|
+
'metadata.json',
|
|
512
|
+
'.reskill-commit'
|
|
513
|
+
];
|
|
514
|
+
const EXCLUDE_PREFIX = '_';
|
|
515
|
+
function installer_sanitizeName(name) {
|
|
516
|
+
let sanitized = name.replace(/[/\\:\0]/g, '');
|
|
517
|
+
sanitized = sanitized.replace(/^[.\s]+|[.\s]+$/g, '');
|
|
518
|
+
sanitized = sanitized.replace(/^\.+/, '');
|
|
519
|
+
if (!sanitized || 0 === sanitized.length) sanitized = 'unnamed-skill';
|
|
520
|
+
if (sanitized.length > 255) sanitized = sanitized.substring(0, 255);
|
|
521
|
+
return sanitized;
|
|
522
|
+
}
|
|
523
|
+
function installer_isPathSafe(basePath, targetPath) {
|
|
524
|
+
const normalizedBase = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(basePath));
|
|
525
|
+
const normalizedTarget = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(targetPath));
|
|
526
|
+
return normalizedTarget.startsWith(normalizedBase + __WEBPACK_EXTERNAL_MODULE_node_path__.sep) || normalizedTarget === normalizedBase;
|
|
527
|
+
}
|
|
528
|
+
function installer_getCanonicalSkillsDir(isGlobal, cwd) {
|
|
529
|
+
const baseDir = isGlobal ? (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)() : cwd || process.cwd();
|
|
530
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, installer_AGENTS_DIR, installer_SKILLS_SUBDIR);
|
|
531
|
+
}
|
|
532
|
+
function installer_ensureDir(dirPath) {
|
|
533
|
+
if (!external_node_fs_.existsSync(dirPath)) external_node_fs_.mkdirSync(dirPath, {
|
|
534
|
+
recursive: true
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
function installer_remove(targetPath) {
|
|
538
|
+
if (external_node_fs_.existsSync(targetPath)) external_node_fs_.rmSync(targetPath, {
|
|
539
|
+
recursive: true,
|
|
540
|
+
force: true
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
function copyDirectory(src, dest, options) {
|
|
544
|
+
const exclude = new Set(options?.exclude || DEFAULT_EXCLUDE_FILES);
|
|
545
|
+
installer_ensureDir(dest);
|
|
546
|
+
const entries = external_node_fs_.readdirSync(src, {
|
|
547
|
+
withFileTypes: true
|
|
548
|
+
});
|
|
549
|
+
for (const entry of entries){
|
|
550
|
+
if (exclude.has(entry.name) || entry.name.startsWith(EXCLUDE_PREFIX)) continue;
|
|
551
|
+
const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
|
|
552
|
+
const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
|
|
553
|
+
if (entry.isDirectory()) copyDirectory(srcPath, destPath, options);
|
|
554
|
+
else external_node_fs_.copyFileSync(srcPath, destPath);
|
|
488
555
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
const commitFile = __WEBPACK_EXTERNAL_MODULE_node_path__.join(cachePath, '.reskill-commit');
|
|
493
|
-
let commit = '';
|
|
556
|
+
}
|
|
557
|
+
async function installer_createSymlink(target, linkPath) {
|
|
558
|
+
try {
|
|
494
559
|
try {
|
|
495
|
-
const
|
|
496
|
-
if (
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
560
|
+
const stats = external_node_fs_.lstatSync(linkPath);
|
|
561
|
+
if (stats.isSymbolicLink()) {
|
|
562
|
+
const existingTarget = external_node_fs_.readlinkSync(linkPath);
|
|
563
|
+
if (__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(existingTarget) === __WEBPACK_EXTERNAL_MODULE_node_path__.resolve(target)) return true;
|
|
564
|
+
external_node_fs_.rmSync(linkPath);
|
|
565
|
+
} else external_node_fs_.rmSync(linkPath, {
|
|
566
|
+
recursive: true
|
|
567
|
+
});
|
|
568
|
+
} catch (err) {
|
|
569
|
+
if (err && 'object' == typeof err && 'code' in err) {
|
|
570
|
+
if ('ELOOP' === err.code) try {
|
|
571
|
+
external_node_fs_.rmSync(linkPath, {
|
|
572
|
+
force: true
|
|
573
|
+
});
|
|
574
|
+
} catch {}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
|
|
578
|
+
installer_ensureDir(linkDir);
|
|
579
|
+
const relativePath = __WEBPACK_EXTERNAL_MODULE_node_path__.relative(linkDir, target);
|
|
580
|
+
const symlinkType = 'win32' === (0, __WEBPACK_EXTERNAL_MODULE_node_os__.platform)() ? 'junction' : void 0;
|
|
581
|
+
external_node_fs_.symlinkSync(relativePath, linkPath, symlinkType);
|
|
582
|
+
return true;
|
|
583
|
+
} catch {
|
|
584
|
+
return false;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
class Installer {
|
|
588
|
+
cwd;
|
|
589
|
+
isGlobal;
|
|
590
|
+
constructor(options = {}){
|
|
591
|
+
this.cwd = options.cwd || process.cwd();
|
|
592
|
+
this.isGlobal = options.global || false;
|
|
593
|
+
}
|
|
594
|
+
getCanonicalPath(skillName) {
|
|
595
|
+
const sanitized = installer_sanitizeName(skillName);
|
|
596
|
+
const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
|
|
597
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
|
|
598
|
+
}
|
|
599
|
+
getAgentSkillPath(skillName, agentType) {
|
|
600
|
+
const agent = getAgentConfig(agentType);
|
|
601
|
+
const sanitized = installer_sanitizeName(skillName);
|
|
602
|
+
const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
|
|
603
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
|
|
604
|
+
}
|
|
605
|
+
async installForAgent(sourcePath, skillName, agentType, options = {}) {
|
|
606
|
+
const agent = getAgentConfig(agentType);
|
|
607
|
+
const installMode = options.mode || 'symlink';
|
|
608
|
+
const sanitized = installer_sanitizeName(skillName);
|
|
609
|
+
const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
|
|
610
|
+
const canonicalDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
|
|
611
|
+
const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
|
|
612
|
+
const agentDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
|
|
613
|
+
if (!installer_isPathSafe(canonicalBase, canonicalDir)) return {
|
|
614
|
+
success: false,
|
|
615
|
+
path: agentDir,
|
|
616
|
+
mode: installMode,
|
|
617
|
+
error: 'Invalid skill name: potential path traversal detected'
|
|
618
|
+
};
|
|
619
|
+
if (!installer_isPathSafe(agentBase, agentDir)) return {
|
|
620
|
+
success: false,
|
|
621
|
+
path: agentDir,
|
|
622
|
+
mode: installMode,
|
|
623
|
+
error: 'Invalid skill name: potential path traversal detected'
|
|
624
|
+
};
|
|
625
|
+
try {
|
|
626
|
+
if ('copy' === installMode) {
|
|
627
|
+
installer_ensureDir(agentDir);
|
|
628
|
+
installer_remove(agentDir);
|
|
629
|
+
copyDirectory(sourcePath, agentDir);
|
|
630
|
+
return {
|
|
631
|
+
success: true,
|
|
632
|
+
path: agentDir,
|
|
633
|
+
mode: 'copy'
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
installer_ensureDir(canonicalDir);
|
|
637
|
+
installer_remove(canonicalDir);
|
|
638
|
+
copyDirectory(sourcePath, canonicalDir);
|
|
639
|
+
const symlinkCreated = await installer_createSymlink(canonicalDir, agentDir);
|
|
640
|
+
if (!symlinkCreated) {
|
|
641
|
+
try {
|
|
642
|
+
installer_remove(agentDir);
|
|
643
|
+
} catch {}
|
|
644
|
+
installer_ensureDir(agentDir);
|
|
645
|
+
copyDirectory(sourcePath, agentDir);
|
|
646
|
+
return {
|
|
647
|
+
success: true,
|
|
648
|
+
path: agentDir,
|
|
649
|
+
canonicalPath: canonicalDir,
|
|
650
|
+
mode: 'symlink',
|
|
651
|
+
symlinkFailed: true
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
return {
|
|
655
|
+
success: true,
|
|
656
|
+
path: agentDir,
|
|
657
|
+
canonicalPath: canonicalDir,
|
|
658
|
+
mode: 'symlink'
|
|
659
|
+
};
|
|
660
|
+
} catch (error) {
|
|
661
|
+
return {
|
|
662
|
+
success: false,
|
|
663
|
+
path: agentDir,
|
|
664
|
+
mode: installMode,
|
|
665
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
async installToAgents(sourcePath, skillName, targetAgents, options = {}) {
|
|
670
|
+
const results = new Map();
|
|
671
|
+
for (const agent of targetAgents){
|
|
672
|
+
const result = await this.installForAgent(sourcePath, skillName, agent, options);
|
|
673
|
+
results.set(agent, result);
|
|
674
|
+
}
|
|
675
|
+
return results;
|
|
676
|
+
}
|
|
677
|
+
isInstalled(skillName, agentType) {
|
|
678
|
+
const skillPath = this.getAgentSkillPath(skillName, agentType);
|
|
679
|
+
return external_node_fs_.existsSync(skillPath);
|
|
680
|
+
}
|
|
681
|
+
uninstallFromAgent(skillName, agentType) {
|
|
682
|
+
const skillPath = this.getAgentSkillPath(skillName, agentType);
|
|
683
|
+
if (!external_node_fs_.existsSync(skillPath)) return false;
|
|
684
|
+
installer_remove(skillPath);
|
|
685
|
+
return true;
|
|
686
|
+
}
|
|
687
|
+
uninstallFromAgents(skillName, targetAgents) {
|
|
688
|
+
const results = new Map();
|
|
689
|
+
for (const agent of targetAgents)results.set(agent, this.uninstallFromAgent(skillName, agent));
|
|
690
|
+
const canonicalPath = this.getCanonicalPath(skillName);
|
|
691
|
+
if (external_node_fs_.existsSync(canonicalPath)) installer_remove(canonicalPath);
|
|
692
|
+
return results;
|
|
693
|
+
}
|
|
694
|
+
listInstalledSkills(agentType) {
|
|
695
|
+
const agent = getAgentConfig(agentType);
|
|
696
|
+
const skillsDir = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
|
|
697
|
+
if (!external_node_fs_.existsSync(skillsDir)) return [];
|
|
698
|
+
return external_node_fs_.readdirSync(skillsDir, {
|
|
699
|
+
withFileTypes: true
|
|
700
|
+
}).filter((entry)=>entry.isDirectory() || entry.isSymbolicLink()).map((entry)=>entry.name);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
class CacheManager {
|
|
704
|
+
cacheDir;
|
|
705
|
+
constructor(cacheDir){
|
|
706
|
+
this.cacheDir = cacheDir || getCacheDir();
|
|
707
|
+
}
|
|
708
|
+
getCacheDir() {
|
|
709
|
+
return this.cacheDir;
|
|
710
|
+
}
|
|
711
|
+
getSkillCachePath(parsed, version) {
|
|
712
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, parsed.registry, parsed.owner, parsed.repo, version);
|
|
713
|
+
}
|
|
714
|
+
getCachePath(parsed, version) {
|
|
715
|
+
return this.getSkillCachePath(parsed, version);
|
|
716
|
+
}
|
|
717
|
+
isCached(parsed, version) {
|
|
718
|
+
const cachePath = this.getSkillCachePath(parsed, version);
|
|
719
|
+
return exists(cachePath) && isDirectory(cachePath);
|
|
720
|
+
}
|
|
721
|
+
async get(parsed, version) {
|
|
722
|
+
const cachePath = this.getSkillCachePath(parsed, version);
|
|
723
|
+
if (!this.isCached(parsed, version)) return null;
|
|
724
|
+
const commitFile = __WEBPACK_EXTERNAL_MODULE_node_path__.join(cachePath, '.reskill-commit');
|
|
725
|
+
let commit = '';
|
|
726
|
+
try {
|
|
727
|
+
const fs = await import("node:fs");
|
|
728
|
+
if (exists(commitFile)) commit = fs.readFileSync(commitFile, 'utf-8').trim();
|
|
729
|
+
} catch {}
|
|
730
|
+
return {
|
|
731
|
+
path: cachePath,
|
|
732
|
+
commit
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
async cache(repoUrl, parsed, ref, version) {
|
|
736
|
+
const cachePath = this.getSkillCachePath(parsed, version);
|
|
505
737
|
if (exists(cachePath)) remove(cachePath);
|
|
506
738
|
ensureDir(__WEBPACK_EXTERNAL_MODULE_node_path__.dirname(cachePath));
|
|
507
739
|
const tempPath = `${cachePath}.tmp`;
|
|
@@ -540,9 +772,7 @@ class CacheManager {
|
|
|
540
772
|
if (!cached) throw new Error(`Skill ${parsed.raw} version ${version} not found in cache`);
|
|
541
773
|
if (exists(destPath)) remove(destPath);
|
|
542
774
|
copyDir(cached.path, destPath, {
|
|
543
|
-
exclude:
|
|
544
|
-
'.reskill-commit'
|
|
545
|
-
]
|
|
775
|
+
exclude: DEFAULT_EXCLUDE_FILES
|
|
546
776
|
});
|
|
547
777
|
}
|
|
548
778
|
clearSkill(parsed, version) {
|
|
@@ -578,6 +808,31 @@ class CacheManager {
|
|
|
578
808
|
registries
|
|
579
809
|
};
|
|
580
810
|
}
|
|
811
|
+
async getRemoteCommit(repoUrl, ref) {
|
|
812
|
+
const { exec } = await import("node:child_process");
|
|
813
|
+
const { promisify } = await import("node:util");
|
|
814
|
+
const execAsync = promisify(exec);
|
|
815
|
+
try {
|
|
816
|
+
const { stdout } = await execAsync(`git ls-remote ${repoUrl} ${ref}`, {
|
|
817
|
+
encoding: 'utf-8'
|
|
818
|
+
});
|
|
819
|
+
if (stdout.trim()) {
|
|
820
|
+
const [commit] = stdout.trim().split('\t');
|
|
821
|
+
return commit;
|
|
822
|
+
}
|
|
823
|
+
const { stdout: allRefs } = await execAsync(`git ls-remote ${repoUrl}`, {
|
|
824
|
+
encoding: 'utf-8'
|
|
825
|
+
});
|
|
826
|
+
const lines = allRefs.trim().split('\n');
|
|
827
|
+
for (const line of lines){
|
|
828
|
+
const [commit, refPath] = line.split('\t');
|
|
829
|
+
if (refPath === `refs/heads/${ref}` || refPath === `refs/tags/${ref}` || refPath === ref) return commit;
|
|
830
|
+
}
|
|
831
|
+
return '';
|
|
832
|
+
} catch {
|
|
833
|
+
return '';
|
|
834
|
+
}
|
|
835
|
+
}
|
|
581
836
|
}
|
|
582
837
|
const DEFAULT_SKILLS_JSON = {
|
|
583
838
|
skills: {},
|
|
@@ -795,287 +1050,93 @@ class GitResolver {
|
|
|
795
1050
|
value: 'latest',
|
|
796
1051
|
raw
|
|
797
1052
|
};
|
|
798
|
-
if (versionSpec.startsWith('branch:')) return {
|
|
799
|
-
type: 'branch',
|
|
800
|
-
value: versionSpec.slice(7),
|
|
801
|
-
raw
|
|
802
|
-
};
|
|
803
|
-
if (versionSpec.startsWith('commit:')) return {
|
|
804
|
-
type: 'commit',
|
|
805
|
-
value: versionSpec.slice(7),
|
|
806
|
-
raw
|
|
807
|
-
};
|
|
808
|
-
if (/^[\^~><]/.test(versionSpec)) return {
|
|
809
|
-
type: 'range',
|
|
810
|
-
value: versionSpec,
|
|
811
|
-
raw
|
|
812
|
-
};
|
|
813
|
-
return {
|
|
814
|
-
type: 'exact',
|
|
815
|
-
value: versionSpec,
|
|
816
|
-
raw
|
|
817
|
-
};
|
|
818
|
-
}
|
|
819
|
-
buildRepoUrl(parsed) {
|
|
820
|
-
if (parsed.gitUrl) return parsed.gitUrl;
|
|
821
|
-
return buildRepoUrl(parsed.registry, `${parsed.owner}/${parsed.repo}`);
|
|
822
|
-
}
|
|
823
|
-
async resolveVersion(repoUrl, versionSpec) {
|
|
824
|
-
switch(versionSpec.type){
|
|
825
|
-
case 'exact':
|
|
826
|
-
return {
|
|
827
|
-
ref: versionSpec.value
|
|
828
|
-
};
|
|
829
|
-
case 'latest':
|
|
830
|
-
{
|
|
831
|
-
const latestTag = await getLatestTag(repoUrl);
|
|
832
|
-
if (!latestTag) {
|
|
833
|
-
const defaultBranch = await getDefaultBranch(repoUrl);
|
|
834
|
-
return {
|
|
835
|
-
ref: defaultBranch
|
|
836
|
-
};
|
|
837
|
-
}
|
|
838
|
-
return {
|
|
839
|
-
ref: latestTag.name,
|
|
840
|
-
commit: latestTag.commit
|
|
841
|
-
};
|
|
842
|
-
}
|
|
843
|
-
case 'range':
|
|
844
|
-
{
|
|
845
|
-
const tags = await getRemoteTags(repoUrl);
|
|
846
|
-
const matchingTags = tags.filter((tag)=>{
|
|
847
|
-
const version = tag.name.replace(/^v/, '');
|
|
848
|
-
return __WEBPACK_EXTERNAL_MODULE_semver__.satisfies(version, versionSpec.value);
|
|
849
|
-
});
|
|
850
|
-
if (0 === matchingTags.length) throw new Error(`No version found matching ${versionSpec.raw} for ${repoUrl}`);
|
|
851
|
-
matchingTags.sort((a, b)=>{
|
|
852
|
-
const aVer = a.name.replace(/^v/, '');
|
|
853
|
-
const bVer = b.name.replace(/^v/, '');
|
|
854
|
-
return __WEBPACK_EXTERNAL_MODULE_semver__.compare(bVer, aVer);
|
|
855
|
-
});
|
|
856
|
-
return {
|
|
857
|
-
ref: matchingTags[0].name,
|
|
858
|
-
commit: matchingTags[0].commit
|
|
859
|
-
};
|
|
860
|
-
}
|
|
861
|
-
case 'branch':
|
|
862
|
-
return {
|
|
863
|
-
ref: versionSpec.value
|
|
864
|
-
};
|
|
865
|
-
case 'commit':
|
|
866
|
-
return {
|
|
867
|
-
ref: versionSpec.value,
|
|
868
|
-
commit: versionSpec.value
|
|
869
|
-
};
|
|
870
|
-
default:
|
|
871
|
-
throw new Error(`Unknown version type: ${versionSpec.type}`);
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
async resolve(ref) {
|
|
875
|
-
const parsed = this.parseRef(ref);
|
|
876
|
-
const repoUrl = this.buildRepoUrl(parsed);
|
|
877
|
-
const versionSpec = this.parseVersion(parsed.version);
|
|
878
|
-
const resolved = await this.resolveVersion(repoUrl, versionSpec);
|
|
879
|
-
return {
|
|
880
|
-
parsed,
|
|
881
|
-
repoUrl,
|
|
882
|
-
ref: resolved.ref,
|
|
883
|
-
commit: resolved.commit
|
|
884
|
-
};
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
const installer_AGENTS_DIR = '.agents';
|
|
888
|
-
const installer_SKILLS_SUBDIR = 'skills';
|
|
889
|
-
function installer_sanitizeName(name) {
|
|
890
|
-
let sanitized = name.replace(/[/\\:\0]/g, '');
|
|
891
|
-
sanitized = sanitized.replace(/^[.\s]+|[.\s]+$/g, '');
|
|
892
|
-
sanitized = sanitized.replace(/^\.+/, '');
|
|
893
|
-
if (!sanitized || 0 === sanitized.length) sanitized = 'unnamed-skill';
|
|
894
|
-
if (sanitized.length > 255) sanitized = sanitized.substring(0, 255);
|
|
895
|
-
return sanitized;
|
|
896
|
-
}
|
|
897
|
-
function installer_isPathSafe(basePath, targetPath) {
|
|
898
|
-
const normalizedBase = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(basePath));
|
|
899
|
-
const normalizedTarget = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(targetPath));
|
|
900
|
-
return normalizedTarget.startsWith(normalizedBase + __WEBPACK_EXTERNAL_MODULE_node_path__.sep) || normalizedTarget === normalizedBase;
|
|
901
|
-
}
|
|
902
|
-
function installer_getCanonicalSkillsDir(isGlobal, cwd) {
|
|
903
|
-
const baseDir = isGlobal ? (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)() : cwd || process.cwd();
|
|
904
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, installer_AGENTS_DIR, installer_SKILLS_SUBDIR);
|
|
905
|
-
}
|
|
906
|
-
function installer_ensureDir(dirPath) {
|
|
907
|
-
if (!external_node_fs_.existsSync(dirPath)) external_node_fs_.mkdirSync(dirPath, {
|
|
908
|
-
recursive: true
|
|
909
|
-
});
|
|
910
|
-
}
|
|
911
|
-
function installer_remove(targetPath) {
|
|
912
|
-
if (external_node_fs_.existsSync(targetPath)) external_node_fs_.rmSync(targetPath, {
|
|
913
|
-
recursive: true,
|
|
914
|
-
force: true
|
|
915
|
-
});
|
|
916
|
-
}
|
|
917
|
-
function copyDirectory(src, dest, options) {
|
|
918
|
-
const exclude = new Set(options?.exclude || [
|
|
919
|
-
'README.md',
|
|
920
|
-
'metadata.json',
|
|
921
|
-
'.reskill-commit'
|
|
922
|
-
]);
|
|
923
|
-
installer_ensureDir(dest);
|
|
924
|
-
const entries = external_node_fs_.readdirSync(src, {
|
|
925
|
-
withFileTypes: true
|
|
926
|
-
});
|
|
927
|
-
for (const entry of entries){
|
|
928
|
-
if (exclude.has(entry.name) || entry.name.startsWith('_')) continue;
|
|
929
|
-
const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
|
|
930
|
-
const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
|
|
931
|
-
if (entry.isDirectory()) copyDirectory(srcPath, destPath, options);
|
|
932
|
-
else external_node_fs_.copyFileSync(srcPath, destPath);
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
async function installer_createSymlink(target, linkPath) {
|
|
936
|
-
try {
|
|
937
|
-
try {
|
|
938
|
-
const stats = external_node_fs_.lstatSync(linkPath);
|
|
939
|
-
if (stats.isSymbolicLink()) {
|
|
940
|
-
const existingTarget = external_node_fs_.readlinkSync(linkPath);
|
|
941
|
-
if (__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(existingTarget) === __WEBPACK_EXTERNAL_MODULE_node_path__.resolve(target)) return true;
|
|
942
|
-
external_node_fs_.rmSync(linkPath);
|
|
943
|
-
} else external_node_fs_.rmSync(linkPath, {
|
|
944
|
-
recursive: true
|
|
945
|
-
});
|
|
946
|
-
} catch (err) {
|
|
947
|
-
if (err && 'object' == typeof err && 'code' in err) {
|
|
948
|
-
if ('ELOOP' === err.code) try {
|
|
949
|
-
external_node_fs_.rmSync(linkPath, {
|
|
950
|
-
force: true
|
|
951
|
-
});
|
|
952
|
-
} catch {}
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
|
|
956
|
-
installer_ensureDir(linkDir);
|
|
957
|
-
const relativePath = __WEBPACK_EXTERNAL_MODULE_node_path__.relative(linkDir, target);
|
|
958
|
-
const symlinkType = 'win32' === (0, __WEBPACK_EXTERNAL_MODULE_node_os__.platform)() ? 'junction' : void 0;
|
|
959
|
-
external_node_fs_.symlinkSync(relativePath, linkPath, symlinkType);
|
|
960
|
-
return true;
|
|
961
|
-
} catch {
|
|
962
|
-
return false;
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
class Installer {
|
|
966
|
-
cwd;
|
|
967
|
-
isGlobal;
|
|
968
|
-
constructor(options = {}){
|
|
969
|
-
this.cwd = options.cwd || process.cwd();
|
|
970
|
-
this.isGlobal = options.global || false;
|
|
971
|
-
}
|
|
972
|
-
getCanonicalPath(skillName) {
|
|
973
|
-
const sanitized = installer_sanitizeName(skillName);
|
|
974
|
-
const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
|
|
975
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
|
|
976
|
-
}
|
|
977
|
-
getAgentSkillPath(skillName, agentType) {
|
|
978
|
-
const agent = getAgentConfig(agentType);
|
|
979
|
-
const sanitized = installer_sanitizeName(skillName);
|
|
980
|
-
const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
|
|
981
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
|
|
982
|
-
}
|
|
983
|
-
async installForAgent(sourcePath, skillName, agentType, options = {}) {
|
|
984
|
-
const agent = getAgentConfig(agentType);
|
|
985
|
-
const installMode = options.mode || 'symlink';
|
|
986
|
-
const sanitized = installer_sanitizeName(skillName);
|
|
987
|
-
const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
|
|
988
|
-
const canonicalDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
|
|
989
|
-
const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
|
|
990
|
-
const agentDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
|
|
991
|
-
if (!installer_isPathSafe(canonicalBase, canonicalDir)) return {
|
|
992
|
-
success: false,
|
|
993
|
-
path: agentDir,
|
|
994
|
-
mode: installMode,
|
|
995
|
-
error: 'Invalid skill name: potential path traversal detected'
|
|
996
|
-
};
|
|
997
|
-
if (!installer_isPathSafe(agentBase, agentDir)) return {
|
|
998
|
-
success: false,
|
|
999
|
-
path: agentDir,
|
|
1000
|
-
mode: installMode,
|
|
1001
|
-
error: 'Invalid skill name: potential path traversal detected'
|
|
1053
|
+
if (versionSpec.startsWith('branch:')) return {
|
|
1054
|
+
type: 'branch',
|
|
1055
|
+
value: versionSpec.slice(7),
|
|
1056
|
+
raw
|
|
1002
1057
|
};
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1058
|
+
if (versionSpec.startsWith('commit:')) return {
|
|
1059
|
+
type: 'commit',
|
|
1060
|
+
value: versionSpec.slice(7),
|
|
1061
|
+
raw
|
|
1062
|
+
};
|
|
1063
|
+
if (/^[\^~><]/.test(versionSpec)) return {
|
|
1064
|
+
type: 'range',
|
|
1065
|
+
value: versionSpec,
|
|
1066
|
+
raw
|
|
1067
|
+
};
|
|
1068
|
+
return {
|
|
1069
|
+
type: 'exact',
|
|
1070
|
+
value: versionSpec,
|
|
1071
|
+
raw
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
buildRepoUrl(parsed) {
|
|
1075
|
+
if (parsed.gitUrl) return parsed.gitUrl;
|
|
1076
|
+
return buildRepoUrl(parsed.registry, `${parsed.owner}/${parsed.repo}`);
|
|
1077
|
+
}
|
|
1078
|
+
async resolveVersion(repoUrl, versionSpec) {
|
|
1079
|
+
switch(versionSpec.type){
|
|
1080
|
+
case 'exact':
|
|
1008
1081
|
return {
|
|
1009
|
-
|
|
1010
|
-
path: agentDir,
|
|
1011
|
-
mode: 'copy'
|
|
1082
|
+
ref: versionSpec.value
|
|
1012
1083
|
};
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1084
|
+
case 'latest':
|
|
1085
|
+
{
|
|
1086
|
+
const latestTag = await getLatestTag(repoUrl);
|
|
1087
|
+
if (!latestTag) {
|
|
1088
|
+
const defaultBranch = await getDefaultBranch(repoUrl);
|
|
1089
|
+
return {
|
|
1090
|
+
ref: defaultBranch
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
return {
|
|
1094
|
+
ref: latestTag.name,
|
|
1095
|
+
commit: latestTag.commit
|
|
1096
|
+
};
|
|
1097
|
+
}
|
|
1098
|
+
case 'range':
|
|
1099
|
+
{
|
|
1100
|
+
const tags = await getRemoteTags(repoUrl);
|
|
1101
|
+
const matchingTags = tags.filter((tag)=>{
|
|
1102
|
+
const version = tag.name.replace(/^v/, '');
|
|
1103
|
+
return __WEBPACK_EXTERNAL_MODULE_semver__.satisfies(version, versionSpec.value);
|
|
1104
|
+
});
|
|
1105
|
+
if (0 === matchingTags.length) throw new Error(`No version found matching ${versionSpec.raw} for ${repoUrl}`);
|
|
1106
|
+
matchingTags.sort((a, b)=>{
|
|
1107
|
+
const aVer = a.name.replace(/^v/, '');
|
|
1108
|
+
const bVer = b.name.replace(/^v/, '');
|
|
1109
|
+
return __WEBPACK_EXTERNAL_MODULE_semver__.compare(bVer, aVer);
|
|
1110
|
+
});
|
|
1111
|
+
return {
|
|
1112
|
+
ref: matchingTags[0].name,
|
|
1113
|
+
commit: matchingTags[0].commit
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
case 'branch':
|
|
1024
1117
|
return {
|
|
1025
|
-
|
|
1026
|
-
path: agentDir,
|
|
1027
|
-
canonicalPath: canonicalDir,
|
|
1028
|
-
mode: 'symlink',
|
|
1029
|
-
symlinkFailed: true
|
|
1118
|
+
ref: versionSpec.value
|
|
1030
1119
|
};
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
} catch (error) {
|
|
1039
|
-
return {
|
|
1040
|
-
success: false,
|
|
1041
|
-
path: agentDir,
|
|
1042
|
-
mode: installMode,
|
|
1043
|
-
error: error instanceof Error ? error.message : 'Unknown error'
|
|
1044
|
-
};
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
async installToAgents(sourcePath, skillName, targetAgents, options = {}) {
|
|
1048
|
-
const results = new Map();
|
|
1049
|
-
for (const agent of targetAgents){
|
|
1050
|
-
const result = await this.installForAgent(sourcePath, skillName, agent, options);
|
|
1051
|
-
results.set(agent, result);
|
|
1120
|
+
case 'commit':
|
|
1121
|
+
return {
|
|
1122
|
+
ref: versionSpec.value,
|
|
1123
|
+
commit: versionSpec.value
|
|
1124
|
+
};
|
|
1125
|
+
default:
|
|
1126
|
+
throw new Error(`Unknown version type: ${versionSpec.type}`);
|
|
1052
1127
|
}
|
|
1053
|
-
return results;
|
|
1054
|
-
}
|
|
1055
|
-
isInstalled(skillName, agentType) {
|
|
1056
|
-
const skillPath = this.getAgentSkillPath(skillName, agentType);
|
|
1057
|
-
return external_node_fs_.existsSync(skillPath);
|
|
1058
|
-
}
|
|
1059
|
-
uninstallFromAgent(skillName, agentType) {
|
|
1060
|
-
const skillPath = this.getAgentSkillPath(skillName, agentType);
|
|
1061
|
-
if (!external_node_fs_.existsSync(skillPath)) return false;
|
|
1062
|
-
installer_remove(skillPath);
|
|
1063
|
-
return true;
|
|
1064
|
-
}
|
|
1065
|
-
uninstallFromAgents(skillName, targetAgents) {
|
|
1066
|
-
const results = new Map();
|
|
1067
|
-
for (const agent of targetAgents)results.set(agent, this.uninstallFromAgent(skillName, agent));
|
|
1068
|
-
const canonicalPath = this.getCanonicalPath(skillName);
|
|
1069
|
-
if (external_node_fs_.existsSync(canonicalPath)) installer_remove(canonicalPath);
|
|
1070
|
-
return results;
|
|
1071
1128
|
}
|
|
1072
|
-
|
|
1073
|
-
const
|
|
1074
|
-
const
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1129
|
+
async resolve(ref) {
|
|
1130
|
+
const parsed = this.parseRef(ref);
|
|
1131
|
+
const repoUrl = this.buildRepoUrl(parsed);
|
|
1132
|
+
const versionSpec = this.parseVersion(parsed.version);
|
|
1133
|
+
const resolved = await this.resolveVersion(repoUrl, versionSpec);
|
|
1134
|
+
return {
|
|
1135
|
+
parsed,
|
|
1136
|
+
repoUrl,
|
|
1137
|
+
ref: resolved.ref,
|
|
1138
|
+
commit: resolved.commit
|
|
1139
|
+
};
|
|
1079
1140
|
}
|
|
1080
1141
|
}
|
|
1081
1142
|
const LOCKFILE_VERSION = 1;
|
|
@@ -1141,6 +1202,7 @@ class LockManager {
|
|
|
1141
1202
|
const lockedSkill = {
|
|
1142
1203
|
source: options.source,
|
|
1143
1204
|
version: options.version,
|
|
1205
|
+
ref: options.ref,
|
|
1144
1206
|
resolved: options.resolved,
|
|
1145
1207
|
commit: options.commit,
|
|
1146
1208
|
installedAt: new Date().toISOString()
|
|
@@ -1220,35 +1282,43 @@ class SkillManager {
|
|
|
1220
1282
|
const { force = false, save = true } = options;
|
|
1221
1283
|
const resolved = await this.resolver.resolve(ref);
|
|
1222
1284
|
const { parsed, repoUrl } = resolved;
|
|
1223
|
-
const
|
|
1285
|
+
const gitRef = resolved.ref;
|
|
1224
1286
|
const skillName = parsed.subPath ? __WEBPACK_EXTERNAL_MODULE_node_path__.basename(parsed.subPath) : parsed.repo;
|
|
1225
1287
|
const skillPath = this.getSkillPath(skillName);
|
|
1226
1288
|
if (exists(skillPath) && !force) {
|
|
1227
1289
|
const locked = this.lockManager.get(skillName);
|
|
1228
|
-
|
|
1229
|
-
|
|
1290
|
+
const lockedRef = locked?.ref || locked?.version;
|
|
1291
|
+
if (locked && lockedRef === gitRef) {
|
|
1292
|
+
logger_logger.info(`${skillName}@${gitRef} is already installed`);
|
|
1230
1293
|
const installed = this.getInstalledSkill(skillName);
|
|
1231
1294
|
if (installed) return installed;
|
|
1232
1295
|
}
|
|
1233
1296
|
if (!force) {
|
|
1234
|
-
|
|
1297
|
+
logger_logger.warn(`${skillName} is already installed. Use --force to reinstall.`);
|
|
1235
1298
|
const installed = this.getInstalledSkill(skillName);
|
|
1236
1299
|
if (installed) return installed;
|
|
1237
1300
|
}
|
|
1238
1301
|
}
|
|
1239
|
-
|
|
1240
|
-
let cacheResult = await this.cache.get(parsed,
|
|
1241
|
-
if (cacheResult)
|
|
1302
|
+
logger_logger["package"](`Installing ${skillName}@${gitRef}...`);
|
|
1303
|
+
let cacheResult = await this.cache.get(parsed, gitRef);
|
|
1304
|
+
if (cacheResult) logger_logger.debug(`Using cached ${skillName}@${gitRef}`);
|
|
1242
1305
|
else {
|
|
1243
|
-
|
|
1244
|
-
cacheResult = await this.cache.cache(repoUrl, parsed,
|
|
1306
|
+
logger_logger.debug(`Caching ${skillName}@${gitRef} from ${repoUrl}`);
|
|
1307
|
+
cacheResult = await this.cache.cache(repoUrl, parsed, gitRef, gitRef);
|
|
1245
1308
|
}
|
|
1246
1309
|
ensureDir(this.getInstallDir());
|
|
1247
1310
|
if (exists(skillPath)) remove(skillPath);
|
|
1248
|
-
await this.cache.copyTo(parsed,
|
|
1311
|
+
await this.cache.copyTo(parsed, gitRef, skillPath);
|
|
1312
|
+
let semanticVersion = gitRef;
|
|
1313
|
+
const skillJsonPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(skillPath, 'skill.json');
|
|
1314
|
+
if (exists(skillJsonPath)) try {
|
|
1315
|
+
const skillJson = readJson(skillJsonPath);
|
|
1316
|
+
if (skillJson.version) semanticVersion = skillJson.version;
|
|
1317
|
+
} catch {}
|
|
1249
1318
|
if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
|
|
1250
1319
|
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
|
|
1251
|
-
version,
|
|
1320
|
+
version: semanticVersion,
|
|
1321
|
+
ref: gitRef,
|
|
1252
1322
|
resolved: repoUrl,
|
|
1253
1323
|
commit: cacheResult.commit
|
|
1254
1324
|
});
|
|
@@ -1256,8 +1326,9 @@ class SkillManager {
|
|
|
1256
1326
|
this.config.ensureExists();
|
|
1257
1327
|
this.config.addSkill(skillName, ref);
|
|
1258
1328
|
}
|
|
1329
|
+
const displayVersion = semanticVersion !== gitRef ? `${semanticVersion} (${gitRef})` : gitRef;
|
|
1259
1330
|
const locationHint = this.isGlobal ? '(global)' : '';
|
|
1260
|
-
|
|
1331
|
+
logger_logger.success(`Installed ${skillName}@${displayVersion} to ${skillPath} ${locationHint}`.trim());
|
|
1261
1332
|
const installed = this.getInstalledSkill(skillName);
|
|
1262
1333
|
if (!installed) throw new Error(`Failed to get installed skill info for ${skillName}`);
|
|
1263
1334
|
return installed;
|
|
@@ -1272,7 +1343,7 @@ class SkillManager {
|
|
|
1272
1343
|
});
|
|
1273
1344
|
installed.push(skill);
|
|
1274
1345
|
} catch (error) {
|
|
1275
|
-
|
|
1346
|
+
logger_logger.error(`Failed to install ${name}: ${error.message}`);
|
|
1276
1347
|
}
|
|
1277
1348
|
return installed;
|
|
1278
1349
|
}
|
|
@@ -1280,22 +1351,33 @@ class SkillManager {
|
|
|
1280
1351
|
const skillPath = this.getSkillPath(name);
|
|
1281
1352
|
if (!exists(skillPath)) {
|
|
1282
1353
|
const location = this.isGlobal ? '(global)' : '';
|
|
1283
|
-
|
|
1354
|
+
logger_logger.warn(`Skill ${name} is not installed ${location}`.trim());
|
|
1284
1355
|
return false;
|
|
1285
1356
|
}
|
|
1286
1357
|
remove(skillPath);
|
|
1287
1358
|
if (!this.isGlobal) this.lockManager.remove(name);
|
|
1288
1359
|
if (!this.isGlobal && this.config.exists()) this.config.removeSkill(name);
|
|
1289
1360
|
const locationHint = this.isGlobal ? '(global)' : '';
|
|
1290
|
-
|
|
1361
|
+
logger_logger.success(`Uninstalled ${name} ${locationHint}`.trim());
|
|
1291
1362
|
return true;
|
|
1292
1363
|
}
|
|
1364
|
+
checkNeedsUpdate(name, remoteCommit) {
|
|
1365
|
+
const locked = this.lockManager.get(name);
|
|
1366
|
+
if (!locked?.commit) return true;
|
|
1367
|
+
return locked.commit !== remoteCommit;
|
|
1368
|
+
}
|
|
1293
1369
|
async update(name) {
|
|
1294
1370
|
const updated = [];
|
|
1295
1371
|
if (name) {
|
|
1296
1372
|
const ref = this.config.getSkillRef(name);
|
|
1297
1373
|
if (!ref) {
|
|
1298
|
-
|
|
1374
|
+
logger_logger.error(`Skill ${name} not found in skills.json`);
|
|
1375
|
+
return [];
|
|
1376
|
+
}
|
|
1377
|
+
const resolved = await this.resolver.resolve(ref);
|
|
1378
|
+
const remoteCommit = await this.cache.getRemoteCommit(resolved.repoUrl, resolved.ref);
|
|
1379
|
+
if (!this.checkNeedsUpdate(name, remoteCommit)) {
|
|
1380
|
+
logger_logger.info(`${name} is already up to date`);
|
|
1299
1381
|
return [];
|
|
1300
1382
|
}
|
|
1301
1383
|
const skill = await this.install(ref, {
|
|
@@ -1306,13 +1388,19 @@ class SkillManager {
|
|
|
1306
1388
|
} else {
|
|
1307
1389
|
const skills = this.config.getSkills();
|
|
1308
1390
|
for (const [skillName, ref] of Object.entries(skills))try {
|
|
1391
|
+
const resolved = await this.resolver.resolve(ref);
|
|
1392
|
+
const remoteCommit = await this.cache.getRemoteCommit(resolved.repoUrl, resolved.ref);
|
|
1393
|
+
if (!this.checkNeedsUpdate(skillName, remoteCommit)) {
|
|
1394
|
+
logger_logger.info(`${skillName} is already up to date`);
|
|
1395
|
+
continue;
|
|
1396
|
+
}
|
|
1309
1397
|
const skill = await this.install(ref, {
|
|
1310
1398
|
force: true,
|
|
1311
1399
|
save: false
|
|
1312
1400
|
});
|
|
1313
1401
|
updated.push(skill);
|
|
1314
1402
|
} catch (error) {
|
|
1315
|
-
|
|
1403
|
+
logger_logger.error(`Failed to update ${skillName}: ${error.message}`);
|
|
1316
1404
|
}
|
|
1317
1405
|
}
|
|
1318
1406
|
return updated;
|
|
@@ -1329,7 +1417,7 @@ class SkillManager {
|
|
|
1329
1417
|
const linkPath = this.getSkillPath(skillName);
|
|
1330
1418
|
ensureDir(__WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath));
|
|
1331
1419
|
createSymlink(absolutePath, linkPath);
|
|
1332
|
-
|
|
1420
|
+
logger_logger.success(`Linked ${skillName} → ${absolutePath}`);
|
|
1333
1421
|
return {
|
|
1334
1422
|
name: skillName,
|
|
1335
1423
|
path: linkPath,
|
|
@@ -1341,15 +1429,15 @@ class SkillManager {
|
|
|
1341
1429
|
unlink(name) {
|
|
1342
1430
|
const skillPath = this.getSkillPath(name);
|
|
1343
1431
|
if (!exists(skillPath)) {
|
|
1344
|
-
|
|
1432
|
+
logger_logger.warn(`Skill ${name} is not installed`);
|
|
1345
1433
|
return false;
|
|
1346
1434
|
}
|
|
1347
1435
|
if (!isSymlink(skillPath)) {
|
|
1348
|
-
|
|
1436
|
+
logger_logger.warn(`Skill ${name} is not a linked skill`);
|
|
1349
1437
|
return false;
|
|
1350
1438
|
}
|
|
1351
1439
|
remove(skillPath);
|
|
1352
|
-
|
|
1440
|
+
logger_logger.success(`Unlinked ${name}`);
|
|
1353
1441
|
return true;
|
|
1354
1442
|
}
|
|
1355
1443
|
list() {
|
|
@@ -1419,7 +1507,8 @@ class SkillManager {
|
|
|
1419
1507
|
const skills = this.config.getSkills();
|
|
1420
1508
|
for (const [name, ref] of Object.entries(skills))try {
|
|
1421
1509
|
const locked = this.lockManager.get(name);
|
|
1422
|
-
const
|
|
1510
|
+
const currentRef = locked?.ref || locked?.version || 'unknown';
|
|
1511
|
+
const currentVersion = locked?.version || 'unknown';
|
|
1423
1512
|
const parsed = this.resolver.parseRef(ref);
|
|
1424
1513
|
const repoUrl = this.resolver.buildRepoUrl(parsed);
|
|
1425
1514
|
const latestResolved = await this.resolver.resolveVersion(repoUrl, {
|
|
@@ -1428,15 +1517,15 @@ class SkillManager {
|
|
|
1428
1517
|
raw: 'latest'
|
|
1429
1518
|
});
|
|
1430
1519
|
const latest = latestResolved.ref;
|
|
1431
|
-
const updateAvailable =
|
|
1520
|
+
const updateAvailable = currentRef !== latest && 'unknown' !== currentRef;
|
|
1432
1521
|
results.push({
|
|
1433
1522
|
name,
|
|
1434
|
-
current,
|
|
1523
|
+
current: currentVersion !== currentRef ? `${currentVersion} (${currentRef})` : currentRef,
|
|
1435
1524
|
latest,
|
|
1436
1525
|
updateAvailable
|
|
1437
1526
|
});
|
|
1438
1527
|
} catch (error) {
|
|
1439
|
-
|
|
1528
|
+
logger_logger.debug(`Failed to check ${name}: ${error.message}`);
|
|
1440
1529
|
results.push({
|
|
1441
1530
|
name,
|
|
1442
1531
|
current: 'unknown',
|
|
@@ -1450,16 +1539,22 @@ class SkillManager {
|
|
|
1450
1539
|
const { save = true, mode = 'symlink' } = options;
|
|
1451
1540
|
const resolved = await this.resolver.resolve(ref);
|
|
1452
1541
|
const { parsed, repoUrl } = resolved;
|
|
1453
|
-
const
|
|
1542
|
+
const gitRef = resolved.ref;
|
|
1454
1543
|
const skillName = parsed.subPath ? __WEBPACK_EXTERNAL_MODULE_node_path__.basename(parsed.subPath) : parsed.repo;
|
|
1455
|
-
|
|
1456
|
-
let cacheResult = await this.cache.get(parsed,
|
|
1457
|
-
if (cacheResult)
|
|
1544
|
+
logger_logger["package"](`Installing ${skillName}@${gitRef} to ${targetAgents.length} agent(s)...`);
|
|
1545
|
+
let cacheResult = await this.cache.get(parsed, gitRef);
|
|
1546
|
+
if (cacheResult) logger_logger.debug(`Using cached ${skillName}@${gitRef}`);
|
|
1458
1547
|
else {
|
|
1459
|
-
|
|
1460
|
-
cacheResult = await this.cache.cache(repoUrl, parsed,
|
|
1548
|
+
logger_logger.debug(`Caching ${skillName}@${gitRef} from ${repoUrl}`);
|
|
1549
|
+
cacheResult = await this.cache.cache(repoUrl, parsed, gitRef, gitRef);
|
|
1461
1550
|
}
|
|
1462
|
-
const sourcePath = this.cache.getCachePath(parsed,
|
|
1551
|
+
const sourcePath = this.cache.getCachePath(parsed, gitRef);
|
|
1552
|
+
let semanticVersion = gitRef;
|
|
1553
|
+
const skillJsonPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(sourcePath, 'skill.json');
|
|
1554
|
+
if (exists(skillJsonPath)) try {
|
|
1555
|
+
const skillJson = readJson(skillJsonPath);
|
|
1556
|
+
if (skillJson.version) semanticVersion = skillJson.version;
|
|
1557
|
+
} catch {}
|
|
1463
1558
|
const installer = new Installer({
|
|
1464
1559
|
cwd: this.projectRoot,
|
|
1465
1560
|
global: this.isGlobal
|
|
@@ -1469,7 +1564,8 @@ class SkillManager {
|
|
|
1469
1564
|
});
|
|
1470
1565
|
if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
|
|
1471
1566
|
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
|
|
1472
|
-
version,
|
|
1567
|
+
version: semanticVersion,
|
|
1568
|
+
ref: gitRef,
|
|
1473
1569
|
resolved: repoUrl,
|
|
1474
1570
|
commit: cacheResult.commit
|
|
1475
1571
|
});
|
|
@@ -1479,12 +1575,13 @@ class SkillManager {
|
|
|
1479
1575
|
}
|
|
1480
1576
|
const successCount = Array.from(results.values()).filter((r)=>r.success).length;
|
|
1481
1577
|
const failCount = results.size - successCount;
|
|
1482
|
-
|
|
1483
|
-
|
|
1578
|
+
const displayVersion = semanticVersion !== gitRef ? `${semanticVersion} (${gitRef})` : gitRef;
|
|
1579
|
+
if (0 === failCount) logger_logger.success(`Installed ${skillName}@${displayVersion} to ${successCount} agent(s)`);
|
|
1580
|
+
else logger_logger.warn(`Installed ${skillName}@${displayVersion} to ${successCount} agent(s), ${failCount} failed`);
|
|
1484
1581
|
const skill = {
|
|
1485
1582
|
name: skillName,
|
|
1486
1583
|
path: sourcePath,
|
|
1487
|
-
version,
|
|
1584
|
+
version: semanticVersion,
|
|
1488
1585
|
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`
|
|
1489
1586
|
};
|
|
1490
1587
|
return {
|
|
@@ -1524,10 +1621,233 @@ class SkillManager {
|
|
|
1524
1621
|
if (!this.isGlobal) this.lockManager.remove(name);
|
|
1525
1622
|
if (!this.isGlobal && this.config.exists()) this.config.removeSkill(name);
|
|
1526
1623
|
const successCount = Array.from(results.values()).filter((r)=>r).length;
|
|
1527
|
-
|
|
1624
|
+
logger_logger.success(`Uninstalled ${name} from ${successCount} agent(s)`);
|
|
1528
1625
|
return results;
|
|
1529
1626
|
}
|
|
1530
1627
|
}
|
|
1628
|
+
const SUBCOMMANDS = [
|
|
1629
|
+
{
|
|
1630
|
+
name: 'install',
|
|
1631
|
+
description: 'Install a skill or all skills from skills.json'
|
|
1632
|
+
},
|
|
1633
|
+
{
|
|
1634
|
+
name: 'uninstall',
|
|
1635
|
+
description: 'Uninstall a skill'
|
|
1636
|
+
},
|
|
1637
|
+
{
|
|
1638
|
+
name: 'update',
|
|
1639
|
+
description: 'Update installed skills'
|
|
1640
|
+
},
|
|
1641
|
+
{
|
|
1642
|
+
name: 'info',
|
|
1643
|
+
description: 'Show skill details'
|
|
1644
|
+
},
|
|
1645
|
+
{
|
|
1646
|
+
name: 'list',
|
|
1647
|
+
description: 'List installed skills'
|
|
1648
|
+
},
|
|
1649
|
+
{
|
|
1650
|
+
name: 'link',
|
|
1651
|
+
description: 'Link a local skill for development'
|
|
1652
|
+
},
|
|
1653
|
+
{
|
|
1654
|
+
name: 'unlink',
|
|
1655
|
+
description: 'Unlink a linked skill'
|
|
1656
|
+
},
|
|
1657
|
+
{
|
|
1658
|
+
name: 'init',
|
|
1659
|
+
description: 'Initialize skills.json'
|
|
1660
|
+
},
|
|
1661
|
+
{
|
|
1662
|
+
name: 'outdated',
|
|
1663
|
+
description: 'Check for outdated skills'
|
|
1664
|
+
},
|
|
1665
|
+
{
|
|
1666
|
+
name: 'completion',
|
|
1667
|
+
description: 'Setup shell completion'
|
|
1668
|
+
}
|
|
1669
|
+
];
|
|
1670
|
+
const SKILL_COMPLETION_COMMANDS = [
|
|
1671
|
+
'info',
|
|
1672
|
+
'uninstall',
|
|
1673
|
+
'update'
|
|
1674
|
+
];
|
|
1675
|
+
const LINKED_SKILL_COMMANDS = [
|
|
1676
|
+
'unlink'
|
|
1677
|
+
];
|
|
1678
|
+
function getAgentNames() {
|
|
1679
|
+
return Object.keys(agents);
|
|
1680
|
+
}
|
|
1681
|
+
function getInstalledSkillNames() {
|
|
1682
|
+
try {
|
|
1683
|
+
const skillManager = new SkillManager();
|
|
1684
|
+
const skills = skillManager.list();
|
|
1685
|
+
return skills.map((s)=>s.name);
|
|
1686
|
+
} catch {
|
|
1687
|
+
return [];
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
function getLinkedSkillNames() {
|
|
1691
|
+
try {
|
|
1692
|
+
const skillManager = new SkillManager();
|
|
1693
|
+
const skills = skillManager.list();
|
|
1694
|
+
return skills.filter((s)=>s.isLinked).map((s)=>s.name);
|
|
1695
|
+
} catch {
|
|
1696
|
+
return [];
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
function handleCompletion() {
|
|
1700
|
+
const env = __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].parseEnv(process.env);
|
|
1701
|
+
if (!env.complete) return;
|
|
1702
|
+
const { prev, line } = env;
|
|
1703
|
+
const parts = line.trim().split(/\s+/);
|
|
1704
|
+
const command = parts[1];
|
|
1705
|
+
if (1 === parts.length || 2 === parts.length && !line.endsWith(' ')) {
|
|
1706
|
+
const completions = SUBCOMMANDS.map((c)=>({
|
|
1707
|
+
name: c.name,
|
|
1708
|
+
description: c.description
|
|
1709
|
+
}));
|
|
1710
|
+
__WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log(completions);
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1713
|
+
if (SKILL_COMPLETION_COMMANDS.includes(command)) {
|
|
1714
|
+
if (parts.length > 2 && line.endsWith(' ')) {
|
|
1715
|
+
__WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log([]);
|
|
1716
|
+
return;
|
|
1717
|
+
}
|
|
1718
|
+
if (parts.length > 3) {
|
|
1719
|
+
__WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log([]);
|
|
1720
|
+
return;
|
|
1721
|
+
}
|
|
1722
|
+
const skills = getInstalledSkillNames();
|
|
1723
|
+
__WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log(skills);
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1726
|
+
if (LINKED_SKILL_COMMANDS.includes(command)) {
|
|
1727
|
+
if (parts.length > 2 && line.endsWith(' ')) {
|
|
1728
|
+
__WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log([]);
|
|
1729
|
+
return;
|
|
1730
|
+
}
|
|
1731
|
+
if (parts.length > 3) {
|
|
1732
|
+
__WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log([]);
|
|
1733
|
+
return;
|
|
1734
|
+
}
|
|
1735
|
+
const skills = getLinkedSkillNames();
|
|
1736
|
+
__WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log(skills);
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
1739
|
+
if ('install' === command && ('-a' === prev || '--agent' === prev)) {
|
|
1740
|
+
const agentNames = getAgentNames();
|
|
1741
|
+
__WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log(agentNames);
|
|
1742
|
+
return;
|
|
1743
|
+
}
|
|
1744
|
+
if ('install' === command) {
|
|
1745
|
+
const { last } = env;
|
|
1746
|
+
if (last.startsWith('-')) {
|
|
1747
|
+
const options = [
|
|
1748
|
+
{
|
|
1749
|
+
name: '-f',
|
|
1750
|
+
description: 'Force reinstall'
|
|
1751
|
+
},
|
|
1752
|
+
{
|
|
1753
|
+
name: '--force',
|
|
1754
|
+
description: 'Force reinstall'
|
|
1755
|
+
},
|
|
1756
|
+
{
|
|
1757
|
+
name: '-g',
|
|
1758
|
+
description: 'Install globally'
|
|
1759
|
+
},
|
|
1760
|
+
{
|
|
1761
|
+
name: '--global',
|
|
1762
|
+
description: 'Install globally'
|
|
1763
|
+
},
|
|
1764
|
+
{
|
|
1765
|
+
name: '-a',
|
|
1766
|
+
description: 'Specify target agents'
|
|
1767
|
+
},
|
|
1768
|
+
{
|
|
1769
|
+
name: '--agent',
|
|
1770
|
+
description: 'Specify target agents'
|
|
1771
|
+
},
|
|
1772
|
+
{
|
|
1773
|
+
name: '-y',
|
|
1774
|
+
description: 'Skip confirmation'
|
|
1775
|
+
},
|
|
1776
|
+
{
|
|
1777
|
+
name: '--yes',
|
|
1778
|
+
description: 'Skip confirmation'
|
|
1779
|
+
},
|
|
1780
|
+
{
|
|
1781
|
+
name: '--all',
|
|
1782
|
+
description: 'Install to all agents'
|
|
1783
|
+
}
|
|
1784
|
+
];
|
|
1785
|
+
__WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log(options);
|
|
1786
|
+
return;
|
|
1787
|
+
}
|
|
1788
|
+
__WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log([]);
|
|
1789
|
+
return;
|
|
1790
|
+
}
|
|
1791
|
+
__WEBPACK_EXTERNAL_MODULE_tabtab__["default"].log([]);
|
|
1792
|
+
}
|
|
1793
|
+
const completionCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('completion').description('Setup shell completion for reskill').argument('[action]', 'Action: install, uninstall, or shell name (bash, zsh, fish)').action(async (action)=>{
|
|
1794
|
+
const env = __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].parseEnv(process.env);
|
|
1795
|
+
if (env.complete) {
|
|
1796
|
+
handleCompletion();
|
|
1797
|
+
return;
|
|
1798
|
+
}
|
|
1799
|
+
if (!action) {
|
|
1800
|
+
logger_logger.log('Shell completion for reskill');
|
|
1801
|
+
logger_logger.newline();
|
|
1802
|
+
logger_logger.log('Usage:');
|
|
1803
|
+
logger_logger.log(' reskill completion install Install completion (interactive)');
|
|
1804
|
+
logger_logger.log(' reskill completion uninstall Remove completion');
|
|
1805
|
+
logger_logger.newline();
|
|
1806
|
+
logger_logger.log('Supported shells: bash, zsh, fish');
|
|
1807
|
+
logger_logger.newline();
|
|
1808
|
+
logger_logger.log('After installation, restart your shell or run:');
|
|
1809
|
+
logger_logger.log(' source ~/.bashrc # for bash');
|
|
1810
|
+
logger_logger.log(' source ~/.zshrc # for zsh');
|
|
1811
|
+
return;
|
|
1812
|
+
}
|
|
1813
|
+
if ('install' === action) {
|
|
1814
|
+
try {
|
|
1815
|
+
await __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].install({
|
|
1816
|
+
name: 'reskill',
|
|
1817
|
+
completer: 'reskill'
|
|
1818
|
+
});
|
|
1819
|
+
logger_logger.success('Completion installed successfully!');
|
|
1820
|
+
logger_logger.log('Restart your shell or source your shell config file.');
|
|
1821
|
+
} catch (error) {
|
|
1822
|
+
logger_logger.error(`Failed to install completion: ${error.message}`);
|
|
1823
|
+
process.exit(1);
|
|
1824
|
+
}
|
|
1825
|
+
return;
|
|
1826
|
+
}
|
|
1827
|
+
if ('uninstall' === action) {
|
|
1828
|
+
try {
|
|
1829
|
+
await __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].uninstall({
|
|
1830
|
+
name: 'reskill'
|
|
1831
|
+
});
|
|
1832
|
+
logger_logger.success('Completion uninstalled successfully!');
|
|
1833
|
+
} catch (error) {
|
|
1834
|
+
logger_logger.error(`Failed to uninstall completion: ${error.message}`);
|
|
1835
|
+
process.exit(1);
|
|
1836
|
+
}
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1839
|
+
logger_logger.error(`Unknown action: ${action}`);
|
|
1840
|
+
logger_logger.log('Use "reskill completion install" or "reskill completion uninstall"');
|
|
1841
|
+
process.exit(1);
|
|
1842
|
+
});
|
|
1843
|
+
function maybeHandleCompletion() {
|
|
1844
|
+
const env = __WEBPACK_EXTERNAL_MODULE_tabtab__["default"].parseEnv(process.env);
|
|
1845
|
+
if (env.complete) {
|
|
1846
|
+
handleCompletion();
|
|
1847
|
+
return true;
|
|
1848
|
+
}
|
|
1849
|
+
return false;
|
|
1850
|
+
}
|
|
1531
1851
|
const infoCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('info').description('Show skill details').argument('<skill>', 'Skill name').option('-j, --json', 'Output as JSON').action((skillName, options)=>{
|
|
1532
1852
|
const skillManager = new SkillManager();
|
|
1533
1853
|
const info = skillManager.getInfo(skillName);
|
|
@@ -1536,41 +1856,41 @@ const infoCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('info').de
|
|
|
1536
1856
|
return;
|
|
1537
1857
|
}
|
|
1538
1858
|
if (!info.installed && !info.config) {
|
|
1539
|
-
|
|
1859
|
+
logger_logger.error(`Skill ${skillName} not found`);
|
|
1540
1860
|
process.exit(1);
|
|
1541
1861
|
}
|
|
1542
|
-
|
|
1543
|
-
|
|
1862
|
+
logger_logger.log(`Skill: ${skillName}`);
|
|
1863
|
+
logger_logger.newline();
|
|
1544
1864
|
if (info.config) {
|
|
1545
|
-
|
|
1546
|
-
|
|
1865
|
+
logger_logger.log("Configuration (skills.json):");
|
|
1866
|
+
logger_logger.log(` Reference: ${info.config}`);
|
|
1547
1867
|
}
|
|
1548
1868
|
if (info.locked) {
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1869
|
+
logger_logger.log("Locked Version (skills.lock):");
|
|
1870
|
+
logger_logger.log(` Version: ${info.locked.version}`);
|
|
1871
|
+
logger_logger.log(` Source: ${info.locked.source}`);
|
|
1872
|
+
logger_logger.log(` Commit: ${info.locked.commit}`);
|
|
1873
|
+
logger_logger.log(` Installed: ${info.locked.installedAt}`);
|
|
1554
1874
|
}
|
|
1555
1875
|
if (info.installed) {
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1876
|
+
logger_logger.log("Installed:");
|
|
1877
|
+
logger_logger.log(` Path: ${info.installed.path}`);
|
|
1878
|
+
logger_logger.log(` Version: ${info.installed.version}`);
|
|
1879
|
+
logger_logger.log(` Linked: ${info.installed.isLinked ? 'Yes' : 'No'}`);
|
|
1560
1880
|
if (info.installed.metadata) {
|
|
1561
1881
|
const meta = info.installed.metadata;
|
|
1562
|
-
|
|
1563
|
-
if (meta.description)
|
|
1564
|
-
if (meta.author)
|
|
1565
|
-
if (meta.license)
|
|
1566
|
-
if (meta.keywords?.length)
|
|
1882
|
+
logger_logger.log("Metadata (skill.json):");
|
|
1883
|
+
if (meta.description) logger_logger.log(` Description: ${meta.description}`);
|
|
1884
|
+
if (meta.author) logger_logger.log(` Author: ${meta.author}`);
|
|
1885
|
+
if (meta.license) logger_logger.log(` License: ${meta.license}`);
|
|
1886
|
+
if (meta.keywords?.length) logger_logger.log(` Keywords: ${meta.keywords.join(', ')}`);
|
|
1567
1887
|
}
|
|
1568
|
-
} else
|
|
1888
|
+
} else logger_logger.warn(`Skill ${skillName} is not installed`);
|
|
1569
1889
|
});
|
|
1570
1890
|
const initCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('init').description('Initialize a new skills.json configuration').option('-n, --name <name>', 'Project name').option('-r, --registry <registry>', 'Default registry', 'github').option('-d, --install-dir <dir>', 'Skills installation directory', '.skills').option('-y, --yes', 'Skip prompts and use defaults').action(async (options)=>{
|
|
1571
1891
|
const configLoader = new ConfigLoader();
|
|
1572
1892
|
if (configLoader.exists()) {
|
|
1573
|
-
|
|
1893
|
+
logger_logger.warn('skills.json already exists');
|
|
1574
1894
|
return;
|
|
1575
1895
|
}
|
|
1576
1896
|
const config = configLoader.create({
|
|
@@ -1580,16 +1900,16 @@ const initCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('init').de
|
|
|
1580
1900
|
installDir: options.installDir
|
|
1581
1901
|
}
|
|
1582
1902
|
});
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1903
|
+
logger_logger.success('Created skills.json');
|
|
1904
|
+
logger_logger.newline();
|
|
1905
|
+
logger_logger.log('Configuration:');
|
|
1906
|
+
logger_logger.log(` Name: ${config.name || '(not set)'}`);
|
|
1907
|
+
logger_logger.log(` Default registry: ${config.defaults?.registry}`);
|
|
1908
|
+
logger_logger.log(` Install directory: ${config.defaults?.installDir}`);
|
|
1909
|
+
logger_logger.newline();
|
|
1910
|
+
logger_logger.log('Next steps:');
|
|
1911
|
+
logger_logger.log(' reskill install <skill> Install a skill');
|
|
1912
|
+
logger_logger.log(' reskill list List installed skills');
|
|
1593
1913
|
});
|
|
1594
1914
|
function formatAgentNames(agentTypes, maxShow = 5) {
|
|
1595
1915
|
const names = agentTypes.map((a)=>agents[a].displayName);
|
|
@@ -1842,9 +2162,9 @@ const linkCmd = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('link').descri
|
|
|
1842
2162
|
const skillManager = new SkillManager();
|
|
1843
2163
|
try {
|
|
1844
2164
|
const linked = skillManager.link(localPath, options.name);
|
|
1845
|
-
|
|
2165
|
+
logger_logger.log(`Linked skill available at: ${linked.path}`);
|
|
1846
2166
|
} catch (error) {
|
|
1847
|
-
|
|
2167
|
+
logger_logger.error(error.message);
|
|
1848
2168
|
process.exit(1);
|
|
1849
2169
|
}
|
|
1850
2170
|
});
|
|
@@ -1863,7 +2183,7 @@ const listCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('list').al
|
|
|
1863
2183
|
const skills = skillManager.list();
|
|
1864
2184
|
if (0 === skills.length) {
|
|
1865
2185
|
const location = isGlobal ? 'globally' : 'in this project';
|
|
1866
|
-
|
|
2186
|
+
logger_logger.info(`No skills installed ${location}`);
|
|
1867
2187
|
return;
|
|
1868
2188
|
}
|
|
1869
2189
|
if (options.json) {
|
|
@@ -1871,8 +2191,8 @@ const listCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('list').al
|
|
|
1871
2191
|
return;
|
|
1872
2192
|
}
|
|
1873
2193
|
const locationLabel = isGlobal ? __WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(' (global)') : '';
|
|
1874
|
-
|
|
1875
|
-
|
|
2194
|
+
logger_logger.log(`Installed Skills (${skillManager.getInstallDir()})${locationLabel}:`);
|
|
2195
|
+
logger_logger.newline();
|
|
1876
2196
|
const headers = [
|
|
1877
2197
|
'Name',
|
|
1878
2198
|
'Version',
|
|
@@ -1883,19 +2203,19 @@ const listCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('list').al
|
|
|
1883
2203
|
skill.isLinked ? `${skill.version} (linked)` : skill.version,
|
|
1884
2204
|
skill.source || '-'
|
|
1885
2205
|
]);
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
2206
|
+
logger_logger.table(headers, rows);
|
|
2207
|
+
logger_logger.newline();
|
|
2208
|
+
logger_logger.log(`Total: ${skills.length} skill(s)`);
|
|
1889
2209
|
});
|
|
1890
2210
|
const outdatedCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('outdated').description('Check for outdated skills').option('-j, --json', 'Output as JSON').action(async (options)=>{
|
|
1891
2211
|
const configLoader = new ConfigLoader();
|
|
1892
2212
|
if (!configLoader.exists()) {
|
|
1893
|
-
|
|
2213
|
+
logger_logger.error("skills.json not found. Run 'reskill init' first.");
|
|
1894
2214
|
process.exit(1);
|
|
1895
2215
|
}
|
|
1896
2216
|
const skills = configLoader.getSkills();
|
|
1897
2217
|
if (0 === Object.keys(skills).length) {
|
|
1898
|
-
|
|
2218
|
+
logger_logger.info('No skills defined in skills.json');
|
|
1899
2219
|
return;
|
|
1900
2220
|
}
|
|
1901
2221
|
const skillManager = new SkillManager();
|
|
@@ -1909,11 +2229,11 @@ const outdatedCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('outda
|
|
|
1909
2229
|
}
|
|
1910
2230
|
const outdated = results.filter((r)=>r.updateAvailable);
|
|
1911
2231
|
if (0 === outdated.length) {
|
|
1912
|
-
|
|
2232
|
+
logger_logger.success('All skills are up to date!');
|
|
1913
2233
|
return;
|
|
1914
2234
|
}
|
|
1915
|
-
|
|
1916
|
-
|
|
2235
|
+
logger_logger["package"]('Checking for updates...');
|
|
2236
|
+
logger_logger.newline();
|
|
1917
2237
|
const headers = [
|
|
1918
2238
|
'Skill',
|
|
1919
2239
|
'Current',
|
|
@@ -1926,30 +2246,66 @@ const outdatedCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('outda
|
|
|
1926
2246
|
r.latest,
|
|
1927
2247
|
r.updateAvailable ? __WEBPACK_EXTERNAL_MODULE_chalk__["default"].yellow('⬆️ Update available') : __WEBPACK_EXTERNAL_MODULE_chalk__["default"].green('✅ Up to date')
|
|
1928
2248
|
]);
|
|
1929
|
-
|
|
1930
|
-
|
|
2249
|
+
logger_logger.table(headers, rows);
|
|
2250
|
+
logger_logger.newline();
|
|
1931
2251
|
if (outdated.length > 0) {
|
|
1932
|
-
|
|
1933
|
-
|
|
2252
|
+
logger_logger.log(`Run ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan('reskill update')} to update all skills`);
|
|
2253
|
+
logger_logger.log(`Or ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan('reskill update <skill>')} to update a specific skill`);
|
|
1934
2254
|
}
|
|
1935
2255
|
} catch (error) {
|
|
1936
2256
|
spinner.fail('Check failed');
|
|
1937
|
-
|
|
2257
|
+
logger_logger.error(error.message);
|
|
1938
2258
|
process.exit(1);
|
|
1939
2259
|
}
|
|
1940
2260
|
});
|
|
1941
|
-
const uninstallCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('uninstall').alias('un').alias('remove').alias('rm').description('Uninstall a skill').argument('<skill>', 'Skill name to uninstall').option('-g, --global', 'Uninstall from global installation (~/.claude/skills)').action((skillName, options)=>{
|
|
2261
|
+
const uninstallCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('uninstall').alias('un').alias('remove').alias('rm').description('Uninstall a skill').argument('<skill>', 'Skill name to uninstall').option('-g, --global', 'Uninstall from global installation (~/.claude/skills)').option('-y, --yes', 'Skip confirmation prompts').action(async (skillName, options)=>{
|
|
1942
2262
|
const isGlobal = options.global || false;
|
|
2263
|
+
const skipConfirm = options.yes || false;
|
|
1943
2264
|
const skillManager = new SkillManager(void 0, {
|
|
1944
2265
|
global: isGlobal
|
|
1945
2266
|
});
|
|
1946
|
-
|
|
1947
|
-
|
|
2267
|
+
console.log();
|
|
2268
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.intro(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].bgCyan.black(' reskill '));
|
|
2269
|
+
const installer = new Installer({
|
|
2270
|
+
cwd: process.cwd(),
|
|
2271
|
+
global: isGlobal
|
|
2272
|
+
});
|
|
2273
|
+
const allAgentTypes = Object.keys(agents);
|
|
2274
|
+
const installedAgents = allAgentTypes.filter((agent)=>installer.isInstalled(skillName, agent));
|
|
2275
|
+
if (0 === installedAgents.length) {
|
|
2276
|
+
const location = isGlobal ? '(global)' : '';
|
|
2277
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.warn(`Skill ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(skillName)} is not installed ${location}`.trim());
|
|
2278
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.outro('Done');
|
|
2279
|
+
process.exit(0);
|
|
2280
|
+
}
|
|
2281
|
+
const summaryLines = [];
|
|
2282
|
+
summaryLines.push(`${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(skillName)}`);
|
|
2283
|
+
summaryLines.push(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('→')} ${installedAgents.map((a)=>agents[a].displayName).join(', ')}`);
|
|
2284
|
+
summaryLines.push(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('Scope:')} ${isGlobal ? 'Global' : 'Project'}`);
|
|
2285
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.note(summaryLines.join('\n'), 'Uninstallation Summary');
|
|
2286
|
+
if (!skipConfirm) {
|
|
2287
|
+
const confirmed = await __WEBPACK_EXTERNAL_MODULE__clack_prompts__.confirm({
|
|
2288
|
+
message: 'Proceed with uninstallation?'
|
|
2289
|
+
});
|
|
2290
|
+
if (__WEBPACK_EXTERNAL_MODULE__clack_prompts__.isCancel(confirmed) || !confirmed) {
|
|
2291
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.cancel('Uninstallation cancelled');
|
|
2292
|
+
process.exit(0);
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
const results = skillManager.uninstallFromAgents(skillName, installedAgents);
|
|
2296
|
+
const successCount = Array.from(results.values()).filter((r)=>r).length;
|
|
2297
|
+
if (successCount > 0) __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.success(`Uninstalled ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(skillName)} from ${successCount} agent(s)`);
|
|
2298
|
+
else {
|
|
2299
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.error(`Failed to uninstall ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(skillName)}`);
|
|
2300
|
+
process.exit(1);
|
|
2301
|
+
}
|
|
2302
|
+
console.log();
|
|
2303
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.outro(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green('Done!'));
|
|
1948
2304
|
});
|
|
1949
2305
|
const updateCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('update').alias('up').description('Update installed skills').argument('[skill]', 'Skill name to update (updates all if not specified)').action(async (skill)=>{
|
|
1950
2306
|
const configLoader = new ConfigLoader();
|
|
1951
2307
|
if (!configLoader.exists()) {
|
|
1952
|
-
|
|
2308
|
+
logger_logger.error("skills.json not found. Run 'reskill init' first.");
|
|
1953
2309
|
process.exit(1);
|
|
1954
2310
|
}
|
|
1955
2311
|
const skillManager = new SkillManager();
|
|
@@ -1958,17 +2314,18 @@ const updateCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('update'
|
|
|
1958
2314
|
const updated = await skillManager.update(skill);
|
|
1959
2315
|
spinner.stop();
|
|
1960
2316
|
if (0 === updated.length) {
|
|
1961
|
-
|
|
2317
|
+
logger_logger.info('No skills to update');
|
|
1962
2318
|
return;
|
|
1963
2319
|
}
|
|
1964
|
-
|
|
1965
|
-
for (const s of updated)
|
|
2320
|
+
logger_logger.success(`Updated ${updated.length} skill(s):`);
|
|
2321
|
+
for (const s of updated)logger_logger.log(` - ${s.name}@${s.version}`);
|
|
1966
2322
|
} catch (error) {
|
|
1967
2323
|
spinner.fail('Update failed');
|
|
1968
|
-
|
|
2324
|
+
logger_logger.error(error.message);
|
|
1969
2325
|
process.exit(1);
|
|
1970
2326
|
}
|
|
1971
2327
|
});
|
|
2328
|
+
if (maybeHandleCompletion()) process.exit(0);
|
|
1972
2329
|
const cli_rslib_entry_dirname = (0, __WEBPACK_EXTERNAL_MODULE_node_path__.dirname)((0, __WEBPACK_EXTERNAL_MODULE_node_url__.fileURLToPath)(import.meta.url));
|
|
1973
2330
|
const packageJson = JSON.parse((0, external_node_fs_.readFileSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(cli_rslib_entry_dirname, '../../package.json'), 'utf-8'));
|
|
1974
2331
|
const program = new __WEBPACK_EXTERNAL_MODULE_commander__.Command();
|
|
@@ -1982,4 +2339,9 @@ program.addCommand(outdatedCommand);
|
|
|
1982
2339
|
program.addCommand(uninstallCommand);
|
|
1983
2340
|
program.addCommand(linkCommand);
|
|
1984
2341
|
program.addCommand(unlinkCommand);
|
|
1985
|
-
program.
|
|
2342
|
+
program.addCommand(completionCommand);
|
|
2343
|
+
const updateCheckPromise = checkForUpdate(packageJson.name, packageJson.version);
|
|
2344
|
+
program.parseAsync().then(async ()=>{
|
|
2345
|
+
const result = await updateCheckPromise;
|
|
2346
|
+
if (result?.hasUpdate) logger_logger.log(formatUpdateMessage(result));
|
|
2347
|
+
});
|