reskill 0.15.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 +26 -0
- package/README.zh-CN.md +55 -29
- 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 +696 -391
- 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/skill-manager.d.ts +8 -0
- package/dist/core/skill-manager.d.ts.map +1 -1
- package/dist/index.js +243 -200
- package/dist/utils/fs.d.ts +6 -0
- package/dist/utils/fs.d.ts.map +1 -1
- package/package.json +3 -2
package/dist/cli/index.js
CHANGED
|
@@ -5,6 +5,7 @@ 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
7
|
import * as __WEBPACK_EXTERNAL_MODULE_semver__ from "semver";
|
|
8
|
+
import * as __WEBPACK_EXTERNAL_MODULE_tabtab__ from "tabtab";
|
|
8
9
|
import * as __WEBPACK_EXTERNAL_MODULE_node_os__ from "node:os";
|
|
9
10
|
import * as __WEBPACK_EXTERNAL_MODULE_node_child_process__ from "node:child_process";
|
|
10
11
|
import * as __WEBPACK_EXTERNAL_MODULE_node_util__ from "node:util";
|
|
@@ -101,92 +102,6 @@ function formatUpdateMessage(result) {
|
|
|
101
102
|
└────────────────────────────────────────────────────┘
|
|
102
103
|
`;
|
|
103
104
|
}
|
|
104
|
-
function exists(filePath) {
|
|
105
|
-
return external_node_fs_.existsSync(filePath);
|
|
106
|
-
}
|
|
107
|
-
function readJson(filePath) {
|
|
108
|
-
const content = external_node_fs_.readFileSync(filePath, 'utf-8');
|
|
109
|
-
return JSON.parse(content);
|
|
110
|
-
}
|
|
111
|
-
function writeJson(filePath, data, indent = 2) {
|
|
112
|
-
const dir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(filePath);
|
|
113
|
-
if (!exists(dir)) external_node_fs_.mkdirSync(dir, {
|
|
114
|
-
recursive: true
|
|
115
|
-
});
|
|
116
|
-
external_node_fs_.writeFileSync(filePath, `${JSON.stringify(data, null, indent)}\n`, 'utf-8');
|
|
117
|
-
}
|
|
118
|
-
function ensureDir(dirPath) {
|
|
119
|
-
if (!exists(dirPath)) external_node_fs_.mkdirSync(dirPath, {
|
|
120
|
-
recursive: true
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
function remove(targetPath) {
|
|
124
|
-
if (exists(targetPath)) external_node_fs_.rmSync(targetPath, {
|
|
125
|
-
recursive: true,
|
|
126
|
-
force: true
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
function copyDir(src, dest, options) {
|
|
130
|
-
const exclude = options?.exclude || [];
|
|
131
|
-
ensureDir(dest);
|
|
132
|
-
const entries = external_node_fs_.readdirSync(src, {
|
|
133
|
-
withFileTypes: true
|
|
134
|
-
});
|
|
135
|
-
for (const entry of entries){
|
|
136
|
-
if (exclude.includes(entry.name)) continue;
|
|
137
|
-
const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
|
|
138
|
-
const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
|
|
139
|
-
if (entry.isDirectory()) copyDir(srcPath, destPath, options);
|
|
140
|
-
else external_node_fs_.copyFileSync(srcPath, destPath);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
function listDir(dirPath) {
|
|
144
|
-
if (!exists(dirPath)) return [];
|
|
145
|
-
return external_node_fs_.readdirSync(dirPath);
|
|
146
|
-
}
|
|
147
|
-
function isDirectory(targetPath) {
|
|
148
|
-
if (!exists(targetPath)) return false;
|
|
149
|
-
return external_node_fs_.statSync(targetPath).isDirectory();
|
|
150
|
-
}
|
|
151
|
-
function isSymlink(targetPath) {
|
|
152
|
-
if (!exists(targetPath)) return false;
|
|
153
|
-
return external_node_fs_.lstatSync(targetPath).isSymbolicLink();
|
|
154
|
-
}
|
|
155
|
-
function createSymlink(target, linkPath) {
|
|
156
|
-
const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
|
|
157
|
-
ensureDir(linkDir);
|
|
158
|
-
if (exists(linkPath)) remove(linkPath);
|
|
159
|
-
external_node_fs_.symlinkSync(target, linkPath, 'dir');
|
|
160
|
-
}
|
|
161
|
-
function getRealPath(linkPath) {
|
|
162
|
-
return external_node_fs_.realpathSync(linkPath);
|
|
163
|
-
}
|
|
164
|
-
function getSkillsJsonPath(projectRoot) {
|
|
165
|
-
const root = projectRoot || process.cwd();
|
|
166
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(root, 'skills.json');
|
|
167
|
-
}
|
|
168
|
-
function getSkillsLockPath(projectRoot) {
|
|
169
|
-
const root = projectRoot || process.cwd();
|
|
170
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(root, 'skills.lock');
|
|
171
|
-
}
|
|
172
|
-
function getCacheDir() {
|
|
173
|
-
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
174
|
-
return process.env.RESKILL_CACHE_DIR || __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.reskill-cache');
|
|
175
|
-
}
|
|
176
|
-
function getHomeDir() {
|
|
177
|
-
return process.env.HOME || process.env.USERPROFILE || '';
|
|
178
|
-
}
|
|
179
|
-
function getGlobalSkillsDir() {
|
|
180
|
-
const home = getHomeDir();
|
|
181
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.claude', 'skills');
|
|
182
|
-
}
|
|
183
|
-
function shortenPath(fullPath, cwd) {
|
|
184
|
-
const home = getHomeDir();
|
|
185
|
-
const currentDir = cwd || process.cwd();
|
|
186
|
-
if (fullPath.startsWith(home)) return fullPath.replace(home, '~');
|
|
187
|
-
if (fullPath.startsWith(currentDir)) return `.${fullPath.slice(currentDir.length)}`;
|
|
188
|
-
return fullPath;
|
|
189
|
-
}
|
|
190
105
|
const agent_registry_home = (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)();
|
|
191
106
|
const agents = {
|
|
192
107
|
amp: {
|
|
@@ -320,7 +235,94 @@ function getAgentConfig(type) {
|
|
|
320
235
|
function isValidAgentType(type) {
|
|
321
236
|
return type in agents;
|
|
322
237
|
}
|
|
323
|
-
|
|
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);
|
|
324
326
|
class GitCloneError extends Error {
|
|
325
327
|
repoUrl;
|
|
326
328
|
originalError;
|
|
@@ -368,7 +370,7 @@ class GitCloneError extends Error {
|
|
|
368
370
|
}
|
|
369
371
|
}
|
|
370
372
|
async function git(args, cwd) {
|
|
371
|
-
const { stdout } = await
|
|
373
|
+
const { stdout } = await git_execAsync(`git ${args.join(' ')}`, {
|
|
372
374
|
cwd,
|
|
373
375
|
encoding: 'utf-8'
|
|
374
376
|
});
|
|
@@ -484,23 +486,219 @@ function parseGitUrl(url) {
|
|
|
484
486
|
};
|
|
485
487
|
}
|
|
486
488
|
}
|
|
487
|
-
const httpMatch = cleanUrl.match(/^(https?|git):\/\/([^/]+)\/(.+)$/);
|
|
488
|
-
if (httpMatch) {
|
|
489
|
-
const [, protocol, host, path] = httpMatch;
|
|
490
|
-
const parts = path.split('/');
|
|
491
|
-
if (parts.length >= 2) {
|
|
492
|
-
const owner = parts.slice(0, -1).join('/');
|
|
493
|
-
const repo = parts[parts.length - 1];
|
|
494
|
-
return {
|
|
495
|
-
host,
|
|
496
|
-
owner,
|
|
497
|
-
repo,
|
|
498
|
-
url,
|
|
499
|
-
type: 'git' === protocol ? 'git' : 'https'
|
|
500
|
-
};
|
|
489
|
+
const httpMatch = cleanUrl.match(/^(https?|git):\/\/([^/]+)\/(.+)$/);
|
|
490
|
+
if (httpMatch) {
|
|
491
|
+
const [, protocol, host, path] = httpMatch;
|
|
492
|
+
const parts = path.split('/');
|
|
493
|
+
if (parts.length >= 2) {
|
|
494
|
+
const owner = parts.slice(0, -1).join('/');
|
|
495
|
+
const repo = parts[parts.length - 1];
|
|
496
|
+
return {
|
|
497
|
+
host,
|
|
498
|
+
owner,
|
|
499
|
+
repo,
|
|
500
|
+
url,
|
|
501
|
+
type: 'git' === protocol ? 'git' : 'https'
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return null;
|
|
506
|
+
}
|
|
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);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
async function installer_createSymlink(target, linkPath) {
|
|
558
|
+
try {
|
|
559
|
+
try {
|
|
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);
|
|
501
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);
|
|
502
701
|
}
|
|
503
|
-
return null;
|
|
504
702
|
}
|
|
505
703
|
class CacheManager {
|
|
506
704
|
cacheDir;
|
|
@@ -574,9 +772,7 @@ class CacheManager {
|
|
|
574
772
|
if (!cached) throw new Error(`Skill ${parsed.raw} version ${version} not found in cache`);
|
|
575
773
|
if (exists(destPath)) remove(destPath);
|
|
576
774
|
copyDir(cached.path, destPath, {
|
|
577
|
-
exclude:
|
|
578
|
-
'.reskill-commit'
|
|
579
|
-
]
|
|
775
|
+
exclude: DEFAULT_EXCLUDE_FILES
|
|
580
776
|
});
|
|
581
777
|
}
|
|
582
778
|
clearSkill(parsed, version) {
|
|
@@ -612,6 +808,31 @@ class CacheManager {
|
|
|
612
808
|
registries
|
|
613
809
|
};
|
|
614
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
|
+
}
|
|
615
836
|
}
|
|
616
837
|
const DEFAULT_SKILLS_JSON = {
|
|
617
838
|
skills: {},
|
|
@@ -820,296 +1041,102 @@ class GitResolver {
|
|
|
820
1041
|
parseVersion(versionSpec) {
|
|
821
1042
|
if (!versionSpec) return {
|
|
822
1043
|
type: 'branch',
|
|
823
|
-
value: 'main',
|
|
824
|
-
raw: ''
|
|
825
|
-
};
|
|
826
|
-
const raw = versionSpec;
|
|
827
|
-
if ('latest' === versionSpec) return {
|
|
828
|
-
type: 'latest',
|
|
829
|
-
value: 'latest',
|
|
830
|
-
raw
|
|
831
|
-
};
|
|
832
|
-
if (versionSpec.startsWith('branch:')) return {
|
|
833
|
-
type: 'branch',
|
|
834
|
-
value: versionSpec.slice(7),
|
|
835
|
-
raw
|
|
836
|
-
};
|
|
837
|
-
if (versionSpec.startsWith('commit:')) return {
|
|
838
|
-
type: 'commit',
|
|
839
|
-
value: versionSpec.slice(7),
|
|
840
|
-
raw
|
|
841
|
-
};
|
|
842
|
-
if (/^[\^~><]/.test(versionSpec)) return {
|
|
843
|
-
type: 'range',
|
|
844
|
-
value: versionSpec,
|
|
845
|
-
raw
|
|
846
|
-
};
|
|
847
|
-
return {
|
|
848
|
-
type: 'exact',
|
|
849
|
-
value: versionSpec,
|
|
850
|
-
raw
|
|
851
|
-
};
|
|
852
|
-
}
|
|
853
|
-
buildRepoUrl(parsed) {
|
|
854
|
-
if (parsed.gitUrl) return parsed.gitUrl;
|
|
855
|
-
return buildRepoUrl(parsed.registry, `${parsed.owner}/${parsed.repo}`);
|
|
856
|
-
}
|
|
857
|
-
async resolveVersion(repoUrl, versionSpec) {
|
|
858
|
-
switch(versionSpec.type){
|
|
859
|
-
case 'exact':
|
|
860
|
-
return {
|
|
861
|
-
ref: versionSpec.value
|
|
862
|
-
};
|
|
863
|
-
case 'latest':
|
|
864
|
-
{
|
|
865
|
-
const latestTag = await getLatestTag(repoUrl);
|
|
866
|
-
if (!latestTag) {
|
|
867
|
-
const defaultBranch = await getDefaultBranch(repoUrl);
|
|
868
|
-
return {
|
|
869
|
-
ref: defaultBranch
|
|
870
|
-
};
|
|
871
|
-
}
|
|
872
|
-
return {
|
|
873
|
-
ref: latestTag.name,
|
|
874
|
-
commit: latestTag.commit
|
|
875
|
-
};
|
|
876
|
-
}
|
|
877
|
-
case 'range':
|
|
878
|
-
{
|
|
879
|
-
const tags = await getRemoteTags(repoUrl);
|
|
880
|
-
const matchingTags = tags.filter((tag)=>{
|
|
881
|
-
const version = tag.name.replace(/^v/, '');
|
|
882
|
-
return __WEBPACK_EXTERNAL_MODULE_semver__.satisfies(version, versionSpec.value);
|
|
883
|
-
});
|
|
884
|
-
if (0 === matchingTags.length) throw new Error(`No version found matching ${versionSpec.raw} for ${repoUrl}`);
|
|
885
|
-
matchingTags.sort((a, b)=>{
|
|
886
|
-
const aVer = a.name.replace(/^v/, '');
|
|
887
|
-
const bVer = b.name.replace(/^v/, '');
|
|
888
|
-
return __WEBPACK_EXTERNAL_MODULE_semver__.compare(bVer, aVer);
|
|
889
|
-
});
|
|
890
|
-
return {
|
|
891
|
-
ref: matchingTags[0].name,
|
|
892
|
-
commit: matchingTags[0].commit
|
|
893
|
-
};
|
|
894
|
-
}
|
|
895
|
-
case 'branch':
|
|
896
|
-
return {
|
|
897
|
-
ref: versionSpec.value
|
|
898
|
-
};
|
|
899
|
-
case 'commit':
|
|
900
|
-
return {
|
|
901
|
-
ref: versionSpec.value,
|
|
902
|
-
commit: versionSpec.value
|
|
903
|
-
};
|
|
904
|
-
default:
|
|
905
|
-
throw new Error(`Unknown version type: ${versionSpec.type}`);
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
async resolve(ref) {
|
|
909
|
-
const parsed = this.parseRef(ref);
|
|
910
|
-
const repoUrl = this.buildRepoUrl(parsed);
|
|
911
|
-
const versionSpec = this.parseVersion(parsed.version);
|
|
912
|
-
const resolved = await this.resolveVersion(repoUrl, versionSpec);
|
|
913
|
-
return {
|
|
914
|
-
parsed,
|
|
915
|
-
repoUrl,
|
|
916
|
-
ref: resolved.ref,
|
|
917
|
-
commit: resolved.commit
|
|
918
|
-
};
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
const installer_AGENTS_DIR = '.agents';
|
|
922
|
-
const installer_SKILLS_SUBDIR = 'skills';
|
|
923
|
-
function installer_sanitizeName(name) {
|
|
924
|
-
let sanitized = name.replace(/[/\\:\0]/g, '');
|
|
925
|
-
sanitized = sanitized.replace(/^[.\s]+|[.\s]+$/g, '');
|
|
926
|
-
sanitized = sanitized.replace(/^\.+/, '');
|
|
927
|
-
if (!sanitized || 0 === sanitized.length) sanitized = 'unnamed-skill';
|
|
928
|
-
if (sanitized.length > 255) sanitized = sanitized.substring(0, 255);
|
|
929
|
-
return sanitized;
|
|
930
|
-
}
|
|
931
|
-
function installer_isPathSafe(basePath, targetPath) {
|
|
932
|
-
const normalizedBase = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(basePath));
|
|
933
|
-
const normalizedTarget = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(targetPath));
|
|
934
|
-
return normalizedTarget.startsWith(normalizedBase + __WEBPACK_EXTERNAL_MODULE_node_path__.sep) || normalizedTarget === normalizedBase;
|
|
935
|
-
}
|
|
936
|
-
function installer_getCanonicalSkillsDir(isGlobal, cwd) {
|
|
937
|
-
const baseDir = isGlobal ? (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)() : cwd || process.cwd();
|
|
938
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, installer_AGENTS_DIR, installer_SKILLS_SUBDIR);
|
|
939
|
-
}
|
|
940
|
-
function installer_ensureDir(dirPath) {
|
|
941
|
-
if (!external_node_fs_.existsSync(dirPath)) external_node_fs_.mkdirSync(dirPath, {
|
|
942
|
-
recursive: true
|
|
943
|
-
});
|
|
944
|
-
}
|
|
945
|
-
function installer_remove(targetPath) {
|
|
946
|
-
if (external_node_fs_.existsSync(targetPath)) external_node_fs_.rmSync(targetPath, {
|
|
947
|
-
recursive: true,
|
|
948
|
-
force: true
|
|
949
|
-
});
|
|
950
|
-
}
|
|
951
|
-
function copyDirectory(src, dest, options) {
|
|
952
|
-
const exclude = new Set(options?.exclude || [
|
|
953
|
-
'README.md',
|
|
954
|
-
'metadata.json',
|
|
955
|
-
'.reskill-commit'
|
|
956
|
-
]);
|
|
957
|
-
installer_ensureDir(dest);
|
|
958
|
-
const entries = external_node_fs_.readdirSync(src, {
|
|
959
|
-
withFileTypes: true
|
|
960
|
-
});
|
|
961
|
-
for (const entry of entries){
|
|
962
|
-
if (exclude.has(entry.name) || entry.name.startsWith('_')) continue;
|
|
963
|
-
const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
|
|
964
|
-
const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
|
|
965
|
-
if (entry.isDirectory()) copyDirectory(srcPath, destPath, options);
|
|
966
|
-
else external_node_fs_.copyFileSync(srcPath, destPath);
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
async function installer_createSymlink(target, linkPath) {
|
|
970
|
-
try {
|
|
971
|
-
try {
|
|
972
|
-
const stats = external_node_fs_.lstatSync(linkPath);
|
|
973
|
-
if (stats.isSymbolicLink()) {
|
|
974
|
-
const existingTarget = external_node_fs_.readlinkSync(linkPath);
|
|
975
|
-
if (__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(existingTarget) === __WEBPACK_EXTERNAL_MODULE_node_path__.resolve(target)) return true;
|
|
976
|
-
external_node_fs_.rmSync(linkPath);
|
|
977
|
-
} else external_node_fs_.rmSync(linkPath, {
|
|
978
|
-
recursive: true
|
|
979
|
-
});
|
|
980
|
-
} catch (err) {
|
|
981
|
-
if (err && 'object' == typeof err && 'code' in err) {
|
|
982
|
-
if ('ELOOP' === err.code) try {
|
|
983
|
-
external_node_fs_.rmSync(linkPath, {
|
|
984
|
-
force: true
|
|
985
|
-
});
|
|
986
|
-
} catch {}
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
|
|
990
|
-
installer_ensureDir(linkDir);
|
|
991
|
-
const relativePath = __WEBPACK_EXTERNAL_MODULE_node_path__.relative(linkDir, target);
|
|
992
|
-
const symlinkType = 'win32' === (0, __WEBPACK_EXTERNAL_MODULE_node_os__.platform)() ? 'junction' : void 0;
|
|
993
|
-
external_node_fs_.symlinkSync(relativePath, linkPath, symlinkType);
|
|
994
|
-
return true;
|
|
995
|
-
} catch {
|
|
996
|
-
return false;
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
class Installer {
|
|
1000
|
-
cwd;
|
|
1001
|
-
isGlobal;
|
|
1002
|
-
constructor(options = {}){
|
|
1003
|
-
this.cwd = options.cwd || process.cwd();
|
|
1004
|
-
this.isGlobal = options.global || false;
|
|
1005
|
-
}
|
|
1006
|
-
getCanonicalPath(skillName) {
|
|
1007
|
-
const sanitized = installer_sanitizeName(skillName);
|
|
1008
|
-
const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
|
|
1009
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
|
|
1010
|
-
}
|
|
1011
|
-
getAgentSkillPath(skillName, agentType) {
|
|
1012
|
-
const agent = getAgentConfig(agentType);
|
|
1013
|
-
const sanitized = installer_sanitizeName(skillName);
|
|
1014
|
-
const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
|
|
1015
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
|
|
1016
|
-
}
|
|
1017
|
-
async installForAgent(sourcePath, skillName, agentType, options = {}) {
|
|
1018
|
-
const agent = getAgentConfig(agentType);
|
|
1019
|
-
const installMode = options.mode || 'symlink';
|
|
1020
|
-
const sanitized = installer_sanitizeName(skillName);
|
|
1021
|
-
const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
|
|
1022
|
-
const canonicalDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
|
|
1023
|
-
const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
|
|
1024
|
-
const agentDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
|
|
1025
|
-
if (!installer_isPathSafe(canonicalBase, canonicalDir)) return {
|
|
1026
|
-
success: false,
|
|
1027
|
-
path: agentDir,
|
|
1028
|
-
mode: installMode,
|
|
1029
|
-
error: 'Invalid skill name: potential path traversal detected'
|
|
1044
|
+
value: 'main',
|
|
1045
|
+
raw: ''
|
|
1030
1046
|
};
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1047
|
+
const raw = versionSpec;
|
|
1048
|
+
if ('latest' === versionSpec) return {
|
|
1049
|
+
type: 'latest',
|
|
1050
|
+
value: 'latest',
|
|
1051
|
+
raw
|
|
1036
1052
|
};
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1053
|
+
if (versionSpec.startsWith('branch:')) return {
|
|
1054
|
+
type: 'branch',
|
|
1055
|
+
value: versionSpec.slice(7),
|
|
1056
|
+
raw
|
|
1057
|
+
};
|
|
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':
|
|
1042
1081
|
return {
|
|
1043
|
-
|
|
1044
|
-
path: agentDir,
|
|
1045
|
-
mode: 'copy'
|
|
1082
|
+
ref: versionSpec.value
|
|
1046
1083
|
};
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
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':
|
|
1058
1117
|
return {
|
|
1059
|
-
|
|
1060
|
-
path: agentDir,
|
|
1061
|
-
canonicalPath: canonicalDir,
|
|
1062
|
-
mode: 'symlink',
|
|
1063
|
-
symlinkFailed: true
|
|
1118
|
+
ref: versionSpec.value
|
|
1064
1119
|
};
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
} catch (error) {
|
|
1073
|
-
return {
|
|
1074
|
-
success: false,
|
|
1075
|
-
path: agentDir,
|
|
1076
|
-
mode: installMode,
|
|
1077
|
-
error: error instanceof Error ? error.message : 'Unknown error'
|
|
1078
|
-
};
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1081
|
-
async installToAgents(sourcePath, skillName, targetAgents, options = {}) {
|
|
1082
|
-
const results = new Map();
|
|
1083
|
-
for (const agent of targetAgents){
|
|
1084
|
-
const result = await this.installForAgent(sourcePath, skillName, agent, options);
|
|
1085
|
-
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}`);
|
|
1086
1127
|
}
|
|
1087
|
-
return results;
|
|
1088
1128
|
}
|
|
1089
|
-
|
|
1090
|
-
const
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
const results = new Map();
|
|
1101
|
-
for (const agent of targetAgents)results.set(agent, this.uninstallFromAgent(skillName, agent));
|
|
1102
|
-
const canonicalPath = this.getCanonicalPath(skillName);
|
|
1103
|
-
if (external_node_fs_.existsSync(canonicalPath)) installer_remove(canonicalPath);
|
|
1104
|
-
return results;
|
|
1105
|
-
}
|
|
1106
|
-
listInstalledSkills(agentType) {
|
|
1107
|
-
const agent = getAgentConfig(agentType);
|
|
1108
|
-
const skillsDir = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
|
|
1109
|
-
if (!external_node_fs_.existsSync(skillsDir)) return [];
|
|
1110
|
-
return external_node_fs_.readdirSync(skillsDir, {
|
|
1111
|
-
withFileTypes: true
|
|
1112
|
-
}).filter((entry)=>entry.isDirectory() || entry.isSymbolicLink()).map((entry)=>entry.name);
|
|
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
|
+
};
|
|
1113
1140
|
}
|
|
1114
1141
|
}
|
|
1115
1142
|
const LOCKFILE_VERSION = 1;
|
|
@@ -1334,6 +1361,11 @@ class SkillManager {
|
|
|
1334
1361
|
logger_logger.success(`Uninstalled ${name} ${locationHint}`.trim());
|
|
1335
1362
|
return true;
|
|
1336
1363
|
}
|
|
1364
|
+
checkNeedsUpdate(name, remoteCommit) {
|
|
1365
|
+
const locked = this.lockManager.get(name);
|
|
1366
|
+
if (!locked?.commit) return true;
|
|
1367
|
+
return locked.commit !== remoteCommit;
|
|
1368
|
+
}
|
|
1337
1369
|
async update(name) {
|
|
1338
1370
|
const updated = [];
|
|
1339
1371
|
if (name) {
|
|
@@ -1342,6 +1374,12 @@ class SkillManager {
|
|
|
1342
1374
|
logger_logger.error(`Skill ${name} not found in skills.json`);
|
|
1343
1375
|
return [];
|
|
1344
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`);
|
|
1381
|
+
return [];
|
|
1382
|
+
}
|
|
1345
1383
|
const skill = await this.install(ref, {
|
|
1346
1384
|
force: true,
|
|
1347
1385
|
save: false
|
|
@@ -1350,6 +1388,12 @@ class SkillManager {
|
|
|
1350
1388
|
} else {
|
|
1351
1389
|
const skills = this.config.getSkills();
|
|
1352
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
|
+
}
|
|
1353
1397
|
const skill = await this.install(ref, {
|
|
1354
1398
|
force: true,
|
|
1355
1399
|
save: false
|
|
@@ -1581,6 +1625,229 @@ class SkillManager {
|
|
|
1581
1625
|
return results;
|
|
1582
1626
|
}
|
|
1583
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
|
+
}
|
|
1584
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)=>{
|
|
1585
1852
|
const skillManager = new SkillManager();
|
|
1586
1853
|
const info = skillManager.getInfo(skillName);
|
|
@@ -1991,13 +2258,49 @@ const outdatedCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('outda
|
|
|
1991
2258
|
process.exit(1);
|
|
1992
2259
|
}
|
|
1993
2260
|
});
|
|
1994
|
-
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)=>{
|
|
1995
2262
|
const isGlobal = options.global || false;
|
|
2263
|
+
const skipConfirm = options.yes || false;
|
|
1996
2264
|
const skillManager = new SkillManager(void 0, {
|
|
1997
2265
|
global: isGlobal
|
|
1998
2266
|
});
|
|
1999
|
-
|
|
2000
|
-
|
|
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!'));
|
|
2001
2304
|
});
|
|
2002
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)=>{
|
|
2003
2306
|
const configLoader = new ConfigLoader();
|
|
@@ -2022,6 +2325,7 @@ const updateCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('update'
|
|
|
2022
2325
|
process.exit(1);
|
|
2023
2326
|
}
|
|
2024
2327
|
});
|
|
2328
|
+
if (maybeHandleCompletion()) process.exit(0);
|
|
2025
2329
|
const cli_rslib_entry_dirname = (0, __WEBPACK_EXTERNAL_MODULE_node_path__.dirname)((0, __WEBPACK_EXTERNAL_MODULE_node_url__.fileURLToPath)(import.meta.url));
|
|
2026
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'));
|
|
2027
2331
|
const program = new __WEBPACK_EXTERNAL_MODULE_commander__.Command();
|
|
@@ -2035,6 +2339,7 @@ program.addCommand(outdatedCommand);
|
|
|
2035
2339
|
program.addCommand(uninstallCommand);
|
|
2036
2340
|
program.addCommand(linkCommand);
|
|
2037
2341
|
program.addCommand(unlinkCommand);
|
|
2342
|
+
program.addCommand(completionCommand);
|
|
2038
2343
|
const updateCheckPromise = checkForUpdate(packageJson.name, packageJson.version);
|
|
2039
2344
|
program.parseAsync().then(async ()=>{
|
|
2040
2345
|
const result = await updateCheckPromise;
|