reskill 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/index.d.ts +3 -3
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/info.d.ts +1 -1
- package/dist/cli/commands/init.d.ts +1 -1
- package/dist/cli/commands/install.d.ts +11 -11
- package/dist/cli/commands/install.d.ts.map +1 -1
- package/dist/cli/commands/list.d.ts +1 -1
- package/dist/cli/commands/list.d.ts.map +1 -1
- package/dist/cli/commands/outdated.d.ts +1 -1
- package/dist/cli/commands/outdated.d.ts.map +1 -1
- package/dist/cli/commands/uninstall.d.ts +1 -1
- package/dist/cli/commands/update.d.ts +1 -1
- package/dist/cli/index.js +668 -634
- package/dist/core/agent-registry.d.ts +16 -16
- package/dist/core/agent-registry.d.ts.map +1 -1
- package/dist/core/cache-manager.d.ts +17 -17
- package/dist/core/cache-manager.d.ts.map +1 -1
- package/dist/core/config-loader.d.ts +18 -18
- package/dist/core/config-loader.d.ts.map +1 -1
- package/dist/core/git-resolver.d.ts +23 -23
- package/dist/core/git-resolver.d.ts.map +1 -1
- package/dist/core/index.d.ts +8 -8
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/installer.d.ts +30 -30
- package/dist/core/installer.d.ts.map +1 -1
- package/dist/core/lock-manager.d.ts +17 -17
- package/dist/core/lock-manager.d.ts.map +1 -1
- package/dist/core/skill-manager.d.ts +57 -39
- package/dist/core/skill-manager.d.ts.map +1 -1
- package/dist/core/skill-parser.d.ts +43 -43
- package/dist/core/skill-parser.d.ts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +615 -581
- package/dist/types/index.d.ts +84 -84
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/fs.d.ts +7 -7
- package/dist/utils/fs.d.ts.map +1 -1
- package/package.json +18 -12
package/dist/index.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import * as __WEBPACK_EXTERNAL_MODULE_node_fs__ from "node:fs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as __WEBPACK_EXTERNAL_MODULE_node_os__ from "node:os";
|
|
3
|
+
import * as __WEBPACK_EXTERNAL_MODULE_node_path__ from "node:path";
|
|
3
4
|
import * as __WEBPACK_EXTERNAL_MODULE_node_child_process__ from "node:child_process";
|
|
4
5
|
import * as __WEBPACK_EXTERNAL_MODULE_node_util__ from "node:util";
|
|
5
|
-
import * as
|
|
6
|
-
import * as __WEBPACK_EXTERNAL_MODULE_os__ from "os";
|
|
7
|
-
import * as __WEBPACK_EXTERNAL_MODULE_path__ from "path";
|
|
8
|
-
import * as __WEBPACK_EXTERNAL_MODULE_fs__ from "fs";
|
|
6
|
+
import * as __WEBPACK_EXTERNAL_MODULE_semver__ from "semver";
|
|
9
7
|
import * as __WEBPACK_EXTERNAL_MODULE_chalk__ from "chalk";
|
|
10
8
|
var __webpack_modules__ = {
|
|
11
9
|
"node:fs": function(module) {
|
|
@@ -22,6 +20,258 @@ function __webpack_require__(moduleId) {
|
|
|
22
20
|
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
|
23
21
|
return module.exports;
|
|
24
22
|
}
|
|
23
|
+
var external_node_fs_ = __webpack_require__("node:fs");
|
|
24
|
+
const agent_registry_home = (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)();
|
|
25
|
+
const agents = {
|
|
26
|
+
amp: {
|
|
27
|
+
name: 'amp',
|
|
28
|
+
displayName: 'Amp',
|
|
29
|
+
skillsDir: '.agents/skills',
|
|
30
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/agents/skills'),
|
|
31
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/amp'))
|
|
32
|
+
},
|
|
33
|
+
antigravity: {
|
|
34
|
+
name: 'antigravity',
|
|
35
|
+
displayName: 'Antigravity',
|
|
36
|
+
skillsDir: '.agent/skills',
|
|
37
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.gemini/antigravity/skills'),
|
|
38
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(process.cwd(), '.agent')) || (0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.gemini/antigravity'))
|
|
39
|
+
},
|
|
40
|
+
'claude-code': {
|
|
41
|
+
name: 'claude-code',
|
|
42
|
+
displayName: 'Claude Code',
|
|
43
|
+
skillsDir: '.claude/skills',
|
|
44
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.claude/skills'),
|
|
45
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.claude'))
|
|
46
|
+
},
|
|
47
|
+
clawdbot: {
|
|
48
|
+
name: 'clawdbot',
|
|
49
|
+
displayName: 'Clawdbot',
|
|
50
|
+
skillsDir: 'skills',
|
|
51
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.clawdbot/skills'),
|
|
52
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.clawdbot'))
|
|
53
|
+
},
|
|
54
|
+
codex: {
|
|
55
|
+
name: 'codex',
|
|
56
|
+
displayName: 'Codex',
|
|
57
|
+
skillsDir: '.codex/skills',
|
|
58
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.codex/skills'),
|
|
59
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.codex'))
|
|
60
|
+
},
|
|
61
|
+
cursor: {
|
|
62
|
+
name: 'cursor',
|
|
63
|
+
displayName: 'Cursor',
|
|
64
|
+
skillsDir: '.cursor/skills',
|
|
65
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.cursor/skills'),
|
|
66
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.cursor'))
|
|
67
|
+
},
|
|
68
|
+
droid: {
|
|
69
|
+
name: 'droid',
|
|
70
|
+
displayName: 'Droid',
|
|
71
|
+
skillsDir: '.factory/skills',
|
|
72
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.factory/skills'),
|
|
73
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.factory/skills'))
|
|
74
|
+
},
|
|
75
|
+
'gemini-cli': {
|
|
76
|
+
name: 'gemini-cli',
|
|
77
|
+
displayName: 'Gemini CLI',
|
|
78
|
+
skillsDir: '.gemini/skills',
|
|
79
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.gemini/skills'),
|
|
80
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.gemini'))
|
|
81
|
+
},
|
|
82
|
+
'github-copilot': {
|
|
83
|
+
name: 'github-copilot',
|
|
84
|
+
displayName: 'GitHub Copilot',
|
|
85
|
+
skillsDir: '.github/skills',
|
|
86
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.copilot/skills'),
|
|
87
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(process.cwd(), '.github')) || (0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.copilot'))
|
|
88
|
+
},
|
|
89
|
+
goose: {
|
|
90
|
+
name: 'goose',
|
|
91
|
+
displayName: 'Goose',
|
|
92
|
+
skillsDir: '.goose/skills',
|
|
93
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/goose/skills'),
|
|
94
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/goose'))
|
|
95
|
+
},
|
|
96
|
+
kilo: {
|
|
97
|
+
name: 'kilo',
|
|
98
|
+
displayName: 'Kilo Code',
|
|
99
|
+
skillsDir: '.kilocode/skills',
|
|
100
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.kilocode/skills'),
|
|
101
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.kilocode'))
|
|
102
|
+
},
|
|
103
|
+
'kiro-cli': {
|
|
104
|
+
name: 'kiro-cli',
|
|
105
|
+
displayName: 'Kiro CLI',
|
|
106
|
+
skillsDir: '.kiro/skills',
|
|
107
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.kiro/skills'),
|
|
108
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.kiro'))
|
|
109
|
+
},
|
|
110
|
+
opencode: {
|
|
111
|
+
name: 'opencode',
|
|
112
|
+
displayName: 'OpenCode',
|
|
113
|
+
skillsDir: '.opencode/skills',
|
|
114
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/opencode/skills'),
|
|
115
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/opencode')) || (0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.claude/skills'))
|
|
116
|
+
},
|
|
117
|
+
roo: {
|
|
118
|
+
name: 'roo',
|
|
119
|
+
displayName: 'Roo Code',
|
|
120
|
+
skillsDir: '.roo/skills',
|
|
121
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.roo/skills'),
|
|
122
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.roo'))
|
|
123
|
+
},
|
|
124
|
+
trae: {
|
|
125
|
+
name: 'trae',
|
|
126
|
+
displayName: 'Trae',
|
|
127
|
+
skillsDir: '.trae/skills',
|
|
128
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.trae/skills'),
|
|
129
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.trae'))
|
|
130
|
+
},
|
|
131
|
+
windsurf: {
|
|
132
|
+
name: 'windsurf',
|
|
133
|
+
displayName: 'Windsurf',
|
|
134
|
+
skillsDir: '.windsurf/skills',
|
|
135
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.codeium/windsurf/skills'),
|
|
136
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.codeium/windsurf'))
|
|
137
|
+
},
|
|
138
|
+
neovate: {
|
|
139
|
+
name: 'neovate',
|
|
140
|
+
displayName: 'Neovate',
|
|
141
|
+
skillsDir: '.neovate/skills',
|
|
142
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.neovate/skills'),
|
|
143
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.neovate'))
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
function getAllAgentTypes() {
|
|
147
|
+
return Object.keys(agents);
|
|
148
|
+
}
|
|
149
|
+
async function detectInstalledAgents() {
|
|
150
|
+
const installed = [];
|
|
151
|
+
for (const [type, config] of Object.entries(agents))if (await config.detectInstalled()) installed.push(type);
|
|
152
|
+
return installed;
|
|
153
|
+
}
|
|
154
|
+
function getAgentConfig(type) {
|
|
155
|
+
return agents[type];
|
|
156
|
+
}
|
|
157
|
+
function isValidAgentType(type) {
|
|
158
|
+
return type in agents;
|
|
159
|
+
}
|
|
160
|
+
function getAgentSkillsDir(type, options = {}) {
|
|
161
|
+
const config = agents[type];
|
|
162
|
+
if (options.global) return config.globalSkillsDir;
|
|
163
|
+
const cwd = options.cwd || process.cwd();
|
|
164
|
+
return (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(cwd, config.skillsDir);
|
|
165
|
+
}
|
|
166
|
+
function exists(filePath) {
|
|
167
|
+
return external_node_fs_.existsSync(filePath);
|
|
168
|
+
}
|
|
169
|
+
function readJson(filePath) {
|
|
170
|
+
const content = external_node_fs_.readFileSync(filePath, 'utf-8');
|
|
171
|
+
return JSON.parse(content);
|
|
172
|
+
}
|
|
173
|
+
function writeJson(filePath, data, indent = 2) {
|
|
174
|
+
const dir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(filePath);
|
|
175
|
+
if (!exists(dir)) external_node_fs_.mkdirSync(dir, {
|
|
176
|
+
recursive: true
|
|
177
|
+
});
|
|
178
|
+
external_node_fs_.writeFileSync(filePath, `${JSON.stringify(data, null, indent)}\n`, 'utf-8');
|
|
179
|
+
}
|
|
180
|
+
function ensureDir(dirPath) {
|
|
181
|
+
if (!exists(dirPath)) external_node_fs_.mkdirSync(dirPath, {
|
|
182
|
+
recursive: true
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
function remove(targetPath) {
|
|
186
|
+
if (exists(targetPath)) external_node_fs_.rmSync(targetPath, {
|
|
187
|
+
recursive: true,
|
|
188
|
+
force: true
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
function copyDir(src, dest, options) {
|
|
192
|
+
const exclude = options?.exclude || [];
|
|
193
|
+
ensureDir(dest);
|
|
194
|
+
const entries = external_node_fs_.readdirSync(src, {
|
|
195
|
+
withFileTypes: true
|
|
196
|
+
});
|
|
197
|
+
for (const entry of entries){
|
|
198
|
+
if (exclude.includes(entry.name)) continue;
|
|
199
|
+
const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
|
|
200
|
+
const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
|
|
201
|
+
if (entry.isDirectory()) copyDir(srcPath, destPath, options);
|
|
202
|
+
else external_node_fs_.copyFileSync(srcPath, destPath);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function listDir(dirPath) {
|
|
206
|
+
if (!exists(dirPath)) return [];
|
|
207
|
+
return external_node_fs_.readdirSync(dirPath);
|
|
208
|
+
}
|
|
209
|
+
function isDirectory(targetPath) {
|
|
210
|
+
if (!exists(targetPath)) return false;
|
|
211
|
+
return external_node_fs_.statSync(targetPath).isDirectory();
|
|
212
|
+
}
|
|
213
|
+
function isSymlink(targetPath) {
|
|
214
|
+
if (!exists(targetPath)) return false;
|
|
215
|
+
return external_node_fs_.lstatSync(targetPath).isSymbolicLink();
|
|
216
|
+
}
|
|
217
|
+
function createSymlink(target, linkPath) {
|
|
218
|
+
const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
|
|
219
|
+
ensureDir(linkDir);
|
|
220
|
+
if (exists(linkPath)) remove(linkPath);
|
|
221
|
+
external_node_fs_.symlinkSync(target, linkPath, 'dir');
|
|
222
|
+
}
|
|
223
|
+
function getRealPath(linkPath) {
|
|
224
|
+
return external_node_fs_.realpathSync(linkPath);
|
|
225
|
+
}
|
|
226
|
+
function getSkillsJsonPath(projectRoot) {
|
|
227
|
+
const root = projectRoot || process.cwd();
|
|
228
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(root, 'skills.json');
|
|
229
|
+
}
|
|
230
|
+
function getSkillsLockPath(projectRoot) {
|
|
231
|
+
const root = projectRoot || process.cwd();
|
|
232
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(root, 'skills.lock');
|
|
233
|
+
}
|
|
234
|
+
function getCacheDir() {
|
|
235
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
236
|
+
return process.env.RESKILL_CACHE_DIR || __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.reskill-cache');
|
|
237
|
+
}
|
|
238
|
+
function getHomeDir() {
|
|
239
|
+
return process.env.HOME || process.env.USERPROFILE || '';
|
|
240
|
+
}
|
|
241
|
+
function getGlobalSkillsDir() {
|
|
242
|
+
const home = getHomeDir();
|
|
243
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.claude', 'skills');
|
|
244
|
+
}
|
|
245
|
+
const AGENTS_DIR = '.agents';
|
|
246
|
+
const SKILLS_SUBDIR = 'skills';
|
|
247
|
+
function getCanonicalSkillsDir(options = {}) {
|
|
248
|
+
const { global: isGlobal = false, cwd } = options;
|
|
249
|
+
const baseDir = isGlobal ? getHomeDir() : cwd || process.cwd();
|
|
250
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, AGENTS_DIR, SKILLS_SUBDIR);
|
|
251
|
+
}
|
|
252
|
+
function getCanonicalSkillPath(skillName, options = {}) {
|
|
253
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(getCanonicalSkillsDir(options), skillName);
|
|
254
|
+
}
|
|
255
|
+
function shortenPath(fullPath, cwd) {
|
|
256
|
+
const home = getHomeDir();
|
|
257
|
+
const currentDir = cwd || process.cwd();
|
|
258
|
+
if (fullPath.startsWith(home)) return fullPath.replace(home, '~');
|
|
259
|
+
if (fullPath.startsWith(currentDir)) return `.${fullPath.slice(currentDir.length)}`;
|
|
260
|
+
return fullPath;
|
|
261
|
+
}
|
|
262
|
+
function isPathSafe(basePath, targetPath) {
|
|
263
|
+
const normalizedBase = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(basePath));
|
|
264
|
+
const normalizedTarget = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(targetPath));
|
|
265
|
+
return normalizedTarget.startsWith(normalizedBase + __WEBPACK_EXTERNAL_MODULE_node_path__.sep) || normalizedTarget === normalizedBase;
|
|
266
|
+
}
|
|
267
|
+
function sanitizeName(name) {
|
|
268
|
+
let sanitized = name.replace(/[/\\:\0]/g, '');
|
|
269
|
+
sanitized = sanitized.replace(/^[.\s]+|[.\s]+$/g, '');
|
|
270
|
+
sanitized = sanitized.replace(/^\.+/, '');
|
|
271
|
+
if (!sanitized || 0 === sanitized.length) sanitized = 'unnamed-skill';
|
|
272
|
+
if (sanitized.length > 255) sanitized = sanitized.substring(0, 255);
|
|
273
|
+
return sanitized;
|
|
274
|
+
}
|
|
25
275
|
const execAsync = (0, __WEBPACK_EXTERNAL_MODULE_node_util__.promisify)(__WEBPACK_EXTERNAL_MODULE_node_child_process__.exec);
|
|
26
276
|
class GitCloneError extends Error {
|
|
27
277
|
repoUrl;
|
|
@@ -33,7 +283,7 @@ class GitCloneError extends Error {
|
|
|
33
283
|
if (isAuthError) {
|
|
34
284
|
message += '\n\nTip: For private repos, ensure git SSH keys or credentials are configured:';
|
|
35
285
|
message += '\n - SSH: Check ~/.ssh/id_rsa or ~/.ssh/id_ed25519';
|
|
36
|
-
message +=
|
|
286
|
+
message += "\n - HTTPS: Run 'git config --global credential.helper store'";
|
|
37
287
|
message += '\n - Or use a personal access token in the URL';
|
|
38
288
|
}
|
|
39
289
|
super(message);
|
|
@@ -151,328 +401,46 @@ function buildRepoUrl(registry, ownerRepo) {
|
|
|
151
401
|
gitlab: 'https://gitlab.com'
|
|
152
402
|
};
|
|
153
403
|
const baseUrl = registryUrls[registry] || `https://${registry}`;
|
|
154
|
-
return `${baseUrl}/${ownerRepo}`;
|
|
155
|
-
}
|
|
156
|
-
function isGitUrl(source) {
|
|
157
|
-
return source.startsWith('git@') || source.startsWith('git://') || source.startsWith('http://') || source.startsWith('https://') || source.endsWith('.git');
|
|
158
|
-
}
|
|
159
|
-
function parseGitUrl(url) {
|
|
160
|
-
const cleanUrl = url.replace(/\.git$/, '');
|
|
161
|
-
const sshMatch = cleanUrl.match(/^git@([^:]+):(.+)$/);
|
|
162
|
-
if (sshMatch) {
|
|
163
|
-
const [, host, path] = sshMatch;
|
|
164
|
-
const parts = path.split('/');
|
|
165
|
-
if (parts.length >= 2) {
|
|
166
|
-
const owner = parts.slice(0, -1).join('/');
|
|
167
|
-
const repo = parts[parts.length - 1];
|
|
168
|
-
return {
|
|
169
|
-
host,
|
|
170
|
-
owner,
|
|
171
|
-
repo,
|
|
172
|
-
url,
|
|
173
|
-
type: 'ssh'
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
const httpMatch = cleanUrl.match(/^(https?|git):\/\/([^/]+)\/(.+)$/);
|
|
178
|
-
if (httpMatch) {
|
|
179
|
-
const [, protocol, host, path] = httpMatch;
|
|
180
|
-
const parts = path.split('/');
|
|
181
|
-
if (parts.length >= 2) {
|
|
182
|
-
const owner = parts.slice(0, -1).join('/');
|
|
183
|
-
const repo = parts[parts.length - 1];
|
|
184
|
-
return {
|
|
185
|
-
host,
|
|
186
|
-
owner,
|
|
187
|
-
repo,
|
|
188
|
-
url,
|
|
189
|
-
type: 'git' === protocol ? 'git' : 'https'
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
return null;
|
|
194
|
-
}
|
|
195
|
-
class GitResolver {
|
|
196
|
-
defaultRegistry;
|
|
197
|
-
constructor(defaultRegistry = 'github'){
|
|
198
|
-
this.defaultRegistry = defaultRegistry;
|
|
199
|
-
}
|
|
200
|
-
parseRef(ref) {
|
|
201
|
-
const raw = ref;
|
|
202
|
-
if (isGitUrl(ref)) return this.parseGitUrlRef(ref);
|
|
203
|
-
let remaining = ref;
|
|
204
|
-
let registry = this.defaultRegistry;
|
|
205
|
-
let version;
|
|
206
|
-
const registryMatch = remaining.match(/^([a-zA-Z0-9.-]+):(.+)$/);
|
|
207
|
-
if (registryMatch) {
|
|
208
|
-
registry = registryMatch[1];
|
|
209
|
-
remaining = registryMatch[2];
|
|
210
|
-
}
|
|
211
|
-
const atIndex = remaining.lastIndexOf('@');
|
|
212
|
-
if (atIndex > 0) {
|
|
213
|
-
version = remaining.slice(atIndex + 1);
|
|
214
|
-
remaining = remaining.slice(0, atIndex);
|
|
215
|
-
}
|
|
216
|
-
const parts = remaining.split('/');
|
|
217
|
-
if (parts.length < 2) throw new Error(`Invalid skill reference: ${ref}. Expected format: owner/repo[@version]`);
|
|
218
|
-
const owner = parts[0];
|
|
219
|
-
const repo = parts[1];
|
|
220
|
-
const subPath = parts.length > 2 ? parts.slice(2).join('/') : void 0;
|
|
221
|
-
return {
|
|
222
|
-
registry,
|
|
223
|
-
owner,
|
|
224
|
-
repo,
|
|
225
|
-
subPath,
|
|
226
|
-
version,
|
|
227
|
-
raw
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
parseGitUrlRef(ref) {
|
|
231
|
-
const raw = ref;
|
|
232
|
-
let gitUrl = ref;
|
|
233
|
-
let version;
|
|
234
|
-
let subPath;
|
|
235
|
-
const gitSuffixIndex = ref.indexOf('.git');
|
|
236
|
-
if (-1 !== gitSuffixIndex) {
|
|
237
|
-
const afterGit = ref.slice(gitSuffixIndex + 4);
|
|
238
|
-
if (afterGit) {
|
|
239
|
-
const atIndex = afterGit.lastIndexOf('@');
|
|
240
|
-
if (-1 !== atIndex) {
|
|
241
|
-
version = afterGit.slice(atIndex + 1);
|
|
242
|
-
const pathPart = afterGit.slice(0, atIndex);
|
|
243
|
-
if (pathPart.startsWith('/')) subPath = pathPart.slice(1);
|
|
244
|
-
} else if (afterGit.startsWith('/')) subPath = afterGit.slice(1);
|
|
245
|
-
gitUrl = ref.slice(0, gitSuffixIndex + 4);
|
|
246
|
-
}
|
|
247
|
-
} else {
|
|
248
|
-
const atIndex = ref.lastIndexOf('@');
|
|
249
|
-
if (atIndex > 4) {
|
|
250
|
-
version = ref.slice(atIndex + 1);
|
|
251
|
-
gitUrl = ref.slice(0, atIndex);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
const parsed = parseGitUrl(gitUrl);
|
|
255
|
-
if (!parsed) throw new Error(`Invalid Git URL: ${ref}. Expected format: git@host:owner/repo.git or https://host/owner/repo.git`);
|
|
256
|
-
return {
|
|
257
|
-
registry: parsed.host,
|
|
258
|
-
owner: parsed.owner,
|
|
259
|
-
repo: parsed.repo,
|
|
260
|
-
subPath,
|
|
261
|
-
version,
|
|
262
|
-
raw,
|
|
263
|
-
gitUrl
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
parseVersion(versionSpec) {
|
|
267
|
-
if (!versionSpec) return {
|
|
268
|
-
type: 'branch',
|
|
269
|
-
value: 'main',
|
|
270
|
-
raw: ''
|
|
271
|
-
};
|
|
272
|
-
const raw = versionSpec;
|
|
273
|
-
if ('latest' === versionSpec) return {
|
|
274
|
-
type: 'latest',
|
|
275
|
-
value: 'latest',
|
|
276
|
-
raw
|
|
277
|
-
};
|
|
278
|
-
if (versionSpec.startsWith('branch:')) return {
|
|
279
|
-
type: 'branch',
|
|
280
|
-
value: versionSpec.slice(7),
|
|
281
|
-
raw
|
|
282
|
-
};
|
|
283
|
-
if (versionSpec.startsWith('commit:')) return {
|
|
284
|
-
type: 'commit',
|
|
285
|
-
value: versionSpec.slice(7),
|
|
286
|
-
raw
|
|
287
|
-
};
|
|
288
|
-
if (/^[\^~><]/.test(versionSpec)) return {
|
|
289
|
-
type: 'range',
|
|
290
|
-
value: versionSpec,
|
|
291
|
-
raw
|
|
292
|
-
};
|
|
293
|
-
return {
|
|
294
|
-
type: 'exact',
|
|
295
|
-
value: versionSpec,
|
|
296
|
-
raw
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
buildRepoUrl(parsed) {
|
|
300
|
-
if (parsed.gitUrl) return parsed.gitUrl;
|
|
301
|
-
return buildRepoUrl(parsed.registry, `${parsed.owner}/${parsed.repo}`);
|
|
302
|
-
}
|
|
303
|
-
async resolveVersion(repoUrl, versionSpec) {
|
|
304
|
-
switch(versionSpec.type){
|
|
305
|
-
case 'exact':
|
|
306
|
-
return {
|
|
307
|
-
ref: versionSpec.value
|
|
308
|
-
};
|
|
309
|
-
case 'latest':
|
|
310
|
-
{
|
|
311
|
-
const latestTag = await getLatestTag(repoUrl);
|
|
312
|
-
if (!latestTag) {
|
|
313
|
-
const defaultBranch = await getDefaultBranch(repoUrl);
|
|
314
|
-
return {
|
|
315
|
-
ref: defaultBranch
|
|
316
|
-
};
|
|
317
|
-
}
|
|
318
|
-
return {
|
|
319
|
-
ref: latestTag.name,
|
|
320
|
-
commit: latestTag.commit
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
case 'range':
|
|
324
|
-
{
|
|
325
|
-
const tags = await getRemoteTags(repoUrl);
|
|
326
|
-
const matchingTags = tags.filter((tag)=>{
|
|
327
|
-
const version = tag.name.replace(/^v/, '');
|
|
328
|
-
return __WEBPACK_EXTERNAL_MODULE_semver__.satisfies(version, versionSpec.value);
|
|
329
|
-
});
|
|
330
|
-
if (0 === matchingTags.length) throw new Error(`No version found matching ${versionSpec.raw} for ${repoUrl}`);
|
|
331
|
-
matchingTags.sort((a, b)=>{
|
|
332
|
-
const aVer = a.name.replace(/^v/, '');
|
|
333
|
-
const bVer = b.name.replace(/^v/, '');
|
|
334
|
-
return __WEBPACK_EXTERNAL_MODULE_semver__.compare(bVer, aVer);
|
|
335
|
-
});
|
|
336
|
-
return {
|
|
337
|
-
ref: matchingTags[0].name,
|
|
338
|
-
commit: matchingTags[0].commit
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
case 'branch':
|
|
342
|
-
return {
|
|
343
|
-
ref: versionSpec.value
|
|
344
|
-
};
|
|
345
|
-
case 'commit':
|
|
346
|
-
return {
|
|
347
|
-
ref: versionSpec.value,
|
|
348
|
-
commit: versionSpec.value
|
|
349
|
-
};
|
|
350
|
-
default:
|
|
351
|
-
throw new Error(`Unknown version type: ${versionSpec.type}`);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
async resolve(ref) {
|
|
355
|
-
const parsed = this.parseRef(ref);
|
|
356
|
-
const repoUrl = this.buildRepoUrl(parsed);
|
|
357
|
-
const versionSpec = this.parseVersion(parsed.version);
|
|
358
|
-
const resolved = await this.resolveVersion(repoUrl, versionSpec);
|
|
359
|
-
return {
|
|
360
|
-
parsed,
|
|
361
|
-
repoUrl,
|
|
362
|
-
ref: resolved.ref,
|
|
363
|
-
commit: resolved.commit
|
|
364
|
-
};
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
var external_node_fs_ = __webpack_require__("node:fs");
|
|
368
|
-
function exists(filePath) {
|
|
369
|
-
return external_node_fs_.existsSync(filePath);
|
|
370
|
-
}
|
|
371
|
-
function readJson(filePath) {
|
|
372
|
-
const content = external_node_fs_.readFileSync(filePath, 'utf-8');
|
|
373
|
-
return JSON.parse(content);
|
|
374
|
-
}
|
|
375
|
-
function writeJson(filePath, data, indent = 2) {
|
|
376
|
-
const dir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(filePath);
|
|
377
|
-
if (!exists(dir)) external_node_fs_.mkdirSync(dir, {
|
|
378
|
-
recursive: true
|
|
379
|
-
});
|
|
380
|
-
external_node_fs_.writeFileSync(filePath, JSON.stringify(data, null, indent) + '\n', 'utf-8');
|
|
381
|
-
}
|
|
382
|
-
function ensureDir(dirPath) {
|
|
383
|
-
if (!exists(dirPath)) external_node_fs_.mkdirSync(dirPath, {
|
|
384
|
-
recursive: true
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
function remove(targetPath) {
|
|
388
|
-
if (exists(targetPath)) external_node_fs_.rmSync(targetPath, {
|
|
389
|
-
recursive: true,
|
|
390
|
-
force: true
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
function copyDir(src, dest, options) {
|
|
394
|
-
const exclude = options?.exclude || [];
|
|
395
|
-
ensureDir(dest);
|
|
396
|
-
const entries = external_node_fs_.readdirSync(src, {
|
|
397
|
-
withFileTypes: true
|
|
398
|
-
});
|
|
399
|
-
for (const entry of entries){
|
|
400
|
-
if (exclude.includes(entry.name)) continue;
|
|
401
|
-
const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
|
|
402
|
-
const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
|
|
403
|
-
if (entry.isDirectory()) copyDir(srcPath, destPath, options);
|
|
404
|
-
else external_node_fs_.copyFileSync(srcPath, destPath);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
function listDir(dirPath) {
|
|
408
|
-
if (!exists(dirPath)) return [];
|
|
409
|
-
return external_node_fs_.readdirSync(dirPath);
|
|
410
|
-
}
|
|
411
|
-
function isDirectory(targetPath) {
|
|
412
|
-
if (!exists(targetPath)) return false;
|
|
413
|
-
return external_node_fs_.statSync(targetPath).isDirectory();
|
|
414
|
-
}
|
|
415
|
-
function isSymlink(targetPath) {
|
|
416
|
-
if (!exists(targetPath)) return false;
|
|
417
|
-
return external_node_fs_.lstatSync(targetPath).isSymbolicLink();
|
|
418
|
-
}
|
|
419
|
-
function createSymlink(target, linkPath) {
|
|
420
|
-
const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
|
|
421
|
-
ensureDir(linkDir);
|
|
422
|
-
if (exists(linkPath)) remove(linkPath);
|
|
423
|
-
external_node_fs_.symlinkSync(target, linkPath, 'dir');
|
|
424
|
-
}
|
|
425
|
-
function getRealPath(linkPath) {
|
|
426
|
-
return external_node_fs_.realpathSync(linkPath);
|
|
427
|
-
}
|
|
428
|
-
function getSkillsJsonPath(projectRoot) {
|
|
429
|
-
const root = projectRoot || process.cwd();
|
|
430
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(root, 'skills.json');
|
|
431
|
-
}
|
|
432
|
-
function getSkillsLockPath(projectRoot) {
|
|
433
|
-
const root = projectRoot || process.cwd();
|
|
434
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(root, 'skills.lock');
|
|
435
|
-
}
|
|
436
|
-
function getCacheDir() {
|
|
437
|
-
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
438
|
-
return process.env.RESKILL_CACHE_DIR || __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.reskill-cache');
|
|
439
|
-
}
|
|
440
|
-
function getHomeDir() {
|
|
441
|
-
return process.env.HOME || process.env.USERPROFILE || '';
|
|
442
|
-
}
|
|
443
|
-
function getGlobalSkillsDir() {
|
|
444
|
-
const home = getHomeDir();
|
|
445
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.claude', 'skills');
|
|
446
|
-
}
|
|
447
|
-
const AGENTS_DIR = '.agents';
|
|
448
|
-
const SKILLS_SUBDIR = 'skills';
|
|
449
|
-
function getCanonicalSkillsDir(options = {}) {
|
|
450
|
-
const { global: isGlobal = false, cwd } = options;
|
|
451
|
-
const baseDir = isGlobal ? getHomeDir() : cwd || process.cwd();
|
|
452
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, AGENTS_DIR, SKILLS_SUBDIR);
|
|
453
|
-
}
|
|
454
|
-
function getCanonicalSkillPath(skillName, options = {}) {
|
|
455
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(getCanonicalSkillsDir(options), skillName);
|
|
456
|
-
}
|
|
457
|
-
function shortenPath(fullPath, cwd) {
|
|
458
|
-
const home = getHomeDir();
|
|
459
|
-
const currentDir = cwd || process.cwd();
|
|
460
|
-
if (fullPath.startsWith(home)) return fullPath.replace(home, '~');
|
|
461
|
-
if (fullPath.startsWith(currentDir)) return '.' + fullPath.slice(currentDir.length);
|
|
462
|
-
return fullPath;
|
|
463
|
-
}
|
|
464
|
-
function isPathSafe(basePath, targetPath) {
|
|
465
|
-
const normalizedBase = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(basePath));
|
|
466
|
-
const normalizedTarget = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(targetPath));
|
|
467
|
-
return normalizedTarget.startsWith(normalizedBase + __WEBPACK_EXTERNAL_MODULE_node_path__.sep) || normalizedTarget === normalizedBase;
|
|
404
|
+
return `${baseUrl}/${ownerRepo}`;
|
|
468
405
|
}
|
|
469
|
-
function
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
406
|
+
function isGitUrl(source) {
|
|
407
|
+
return source.startsWith('git@') || source.startsWith('git://') || source.startsWith('http://') || source.startsWith('https://') || source.endsWith('.git');
|
|
408
|
+
}
|
|
409
|
+
function parseGitUrl(url) {
|
|
410
|
+
const cleanUrl = url.replace(/\.git$/, '');
|
|
411
|
+
const sshMatch = cleanUrl.match(/^git@([^:]+):(.+)$/);
|
|
412
|
+
if (sshMatch) {
|
|
413
|
+
const [, host, path] = sshMatch;
|
|
414
|
+
const parts = path.split('/');
|
|
415
|
+
if (parts.length >= 2) {
|
|
416
|
+
const owner = parts.slice(0, -1).join('/');
|
|
417
|
+
const repo = parts[parts.length - 1];
|
|
418
|
+
return {
|
|
419
|
+
host,
|
|
420
|
+
owner,
|
|
421
|
+
repo,
|
|
422
|
+
url,
|
|
423
|
+
type: 'ssh'
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
const httpMatch = cleanUrl.match(/^(https?|git):\/\/([^/]+)\/(.+)$/);
|
|
428
|
+
if (httpMatch) {
|
|
429
|
+
const [, protocol, host, path] = httpMatch;
|
|
430
|
+
const parts = path.split('/');
|
|
431
|
+
if (parts.length >= 2) {
|
|
432
|
+
const owner = parts.slice(0, -1).join('/');
|
|
433
|
+
const repo = parts[parts.length - 1];
|
|
434
|
+
return {
|
|
435
|
+
host,
|
|
436
|
+
owner,
|
|
437
|
+
repo,
|
|
438
|
+
url,
|
|
439
|
+
type: 'git' === protocol ? 'git' : 'https'
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return null;
|
|
476
444
|
}
|
|
477
445
|
class CacheManager {
|
|
478
446
|
cacheDir;
|
|
@@ -649,8 +617,8 @@ class ConfigLoader {
|
|
|
649
617
|
getDefaults() {
|
|
650
618
|
const config = this.config || (this.exists() ? this.load() : DEFAULT_SKILLS_JSON);
|
|
651
619
|
return {
|
|
652
|
-
registry: config.defaults?.registry ||
|
|
653
|
-
installDir: config.defaults?.installDir ||
|
|
620
|
+
registry: config.defaults?.registry || 'github',
|
|
621
|
+
installDir: config.defaults?.installDir || '.skills',
|
|
654
622
|
targetAgents: config.defaults?.targetAgents || [],
|
|
655
623
|
installMode: config.defaults?.installMode || 'symlink'
|
|
656
624
|
};
|
|
@@ -667,12 +635,12 @@ class ConfigLoader {
|
|
|
667
635
|
}
|
|
668
636
|
addSkill(name, ref) {
|
|
669
637
|
if (!this.config) this.load();
|
|
670
|
-
this.config.skills[name] = ref;
|
|
638
|
+
if (this.config) this.config.skills[name] = ref;
|
|
671
639
|
this.save();
|
|
672
640
|
}
|
|
673
641
|
removeSkill(name) {
|
|
674
642
|
if (!this.config) this.load();
|
|
675
|
-
if (this.config
|
|
643
|
+
if (this.config?.skills[name]) {
|
|
676
644
|
delete this.config.skills[name];
|
|
677
645
|
this.save();
|
|
678
646
|
return true;
|
|
@@ -685,7 +653,7 @@ class ConfigLoader {
|
|
|
685
653
|
this.load();
|
|
686
654
|
}
|
|
687
655
|
return {
|
|
688
|
-
...this.config
|
|
656
|
+
...this.config?.skills
|
|
689
657
|
};
|
|
690
658
|
}
|
|
691
659
|
hasSkill(name) {
|
|
@@ -697,247 +665,177 @@ class ConfigLoader {
|
|
|
697
665
|
return skills[name];
|
|
698
666
|
}
|
|
699
667
|
}
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
lockData = null;
|
|
705
|
-
constructor(projectRoot){
|
|
706
|
-
this.projectRoot = projectRoot || process.cwd();
|
|
707
|
-
this.lockPath = getSkillsLockPath(this.projectRoot);
|
|
708
|
-
}
|
|
709
|
-
getLockPath() {
|
|
710
|
-
return this.lockPath;
|
|
711
|
-
}
|
|
712
|
-
exists() {
|
|
713
|
-
return exists(this.lockPath);
|
|
668
|
+
class GitResolver {
|
|
669
|
+
defaultRegistry;
|
|
670
|
+
constructor(defaultRegistry = 'github'){
|
|
671
|
+
this.defaultRegistry = defaultRegistry;
|
|
714
672
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
if (
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
673
|
+
parseRef(ref) {
|
|
674
|
+
const raw = ref;
|
|
675
|
+
if (isGitUrl(ref)) return this.parseGitUrlRef(ref);
|
|
676
|
+
let remaining = ref;
|
|
677
|
+
let registry = this.defaultRegistry;
|
|
678
|
+
let version;
|
|
679
|
+
const registryMatch = remaining.match(/^([a-zA-Z0-9.-]+):(.+)$/);
|
|
680
|
+
if (registryMatch) {
|
|
681
|
+
registry = registryMatch[1];
|
|
682
|
+
remaining = registryMatch[2];
|
|
723
683
|
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
throw new Error(`Failed to parse skills.lock: ${error.message}`);
|
|
684
|
+
const atIndex = remaining.lastIndexOf('@');
|
|
685
|
+
if (atIndex > 0) {
|
|
686
|
+
version = remaining.slice(atIndex + 1);
|
|
687
|
+
remaining = remaining.slice(0, atIndex);
|
|
729
688
|
}
|
|
689
|
+
const parts = remaining.split('/');
|
|
690
|
+
if (parts.length < 2) throw new Error(`Invalid skill reference: ${ref}. Expected format: owner/repo[@version]`);
|
|
691
|
+
const owner = parts[0];
|
|
692
|
+
const repo = parts[1];
|
|
693
|
+
const subPath = parts.length > 2 ? parts.slice(2).join('/') : void 0;
|
|
694
|
+
return {
|
|
695
|
+
registry,
|
|
696
|
+
owner,
|
|
697
|
+
repo,
|
|
698
|
+
subPath,
|
|
699
|
+
version,
|
|
700
|
+
raw
|
|
701
|
+
};
|
|
730
702
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
const
|
|
737
|
-
if (
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
this.save();
|
|
755
|
-
return true;
|
|
703
|
+
parseGitUrlRef(ref) {
|
|
704
|
+
const raw = ref;
|
|
705
|
+
let gitUrl = ref;
|
|
706
|
+
let version;
|
|
707
|
+
let subPath;
|
|
708
|
+
const gitSuffixIndex = ref.indexOf('.git');
|
|
709
|
+
if (-1 !== gitSuffixIndex) {
|
|
710
|
+
const afterGit = ref.slice(gitSuffixIndex + 4);
|
|
711
|
+
if (afterGit) {
|
|
712
|
+
const atIndex = afterGit.lastIndexOf('@');
|
|
713
|
+
if (-1 !== atIndex) {
|
|
714
|
+
version = afterGit.slice(atIndex + 1);
|
|
715
|
+
const pathPart = afterGit.slice(0, atIndex);
|
|
716
|
+
if (pathPart.startsWith('/')) subPath = pathPart.slice(1);
|
|
717
|
+
} else if (afterGit.startsWith('/')) subPath = afterGit.slice(1);
|
|
718
|
+
gitUrl = ref.slice(0, gitSuffixIndex + 4);
|
|
719
|
+
}
|
|
720
|
+
} else {
|
|
721
|
+
const atIndex = ref.lastIndexOf('@');
|
|
722
|
+
if (atIndex > 4) {
|
|
723
|
+
version = ref.slice(atIndex + 1);
|
|
724
|
+
gitUrl = ref.slice(0, atIndex);
|
|
725
|
+
}
|
|
756
726
|
}
|
|
757
|
-
|
|
727
|
+
const parsed = parseGitUrl(gitUrl);
|
|
728
|
+
if (!parsed) throw new Error(`Invalid Git URL: ${ref}. Expected format: git@host:owner/repo.git or https://host/owner/repo.git`);
|
|
729
|
+
return {
|
|
730
|
+
registry: parsed.host,
|
|
731
|
+
owner: parsed.owner,
|
|
732
|
+
repo: parsed.repo,
|
|
733
|
+
subPath,
|
|
734
|
+
version,
|
|
735
|
+
raw,
|
|
736
|
+
gitUrl
|
|
737
|
+
};
|
|
758
738
|
}
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
commit: options.commit,
|
|
765
|
-
installedAt: new Date().toISOString()
|
|
739
|
+
parseVersion(versionSpec) {
|
|
740
|
+
if (!versionSpec) return {
|
|
741
|
+
type: 'branch',
|
|
742
|
+
value: 'main',
|
|
743
|
+
raw: ''
|
|
766
744
|
};
|
|
767
|
-
|
|
768
|
-
return
|
|
745
|
+
const raw = versionSpec;
|
|
746
|
+
if ('latest' === versionSpec) return {
|
|
747
|
+
type: 'latest',
|
|
748
|
+
value: 'latest',
|
|
749
|
+
raw
|
|
750
|
+
};
|
|
751
|
+
if (versionSpec.startsWith('branch:')) return {
|
|
752
|
+
type: 'branch',
|
|
753
|
+
value: versionSpec.slice(7),
|
|
754
|
+
raw
|
|
755
|
+
};
|
|
756
|
+
if (versionSpec.startsWith('commit:')) return {
|
|
757
|
+
type: 'commit',
|
|
758
|
+
value: versionSpec.slice(7),
|
|
759
|
+
raw
|
|
760
|
+
};
|
|
761
|
+
if (/^[\^~><]/.test(versionSpec)) return {
|
|
762
|
+
type: 'range',
|
|
763
|
+
value: versionSpec,
|
|
764
|
+
raw
|
|
765
|
+
};
|
|
766
|
+
return {
|
|
767
|
+
type: 'exact',
|
|
768
|
+
value: versionSpec,
|
|
769
|
+
raw
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
buildRepoUrl(parsed) {
|
|
773
|
+
if (parsed.gitUrl) return parsed.gitUrl;
|
|
774
|
+
return buildRepoUrl(parsed.registry, `${parsed.owner}/${parsed.repo}`);
|
|
775
|
+
}
|
|
776
|
+
async resolveVersion(repoUrl, versionSpec) {
|
|
777
|
+
switch(versionSpec.type){
|
|
778
|
+
case 'exact':
|
|
779
|
+
return {
|
|
780
|
+
ref: versionSpec.value
|
|
781
|
+
};
|
|
782
|
+
case 'latest':
|
|
783
|
+
{
|
|
784
|
+
const latestTag = await getLatestTag(repoUrl);
|
|
785
|
+
if (!latestTag) {
|
|
786
|
+
const defaultBranch = await getDefaultBranch(repoUrl);
|
|
787
|
+
return {
|
|
788
|
+
ref: defaultBranch
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
return {
|
|
792
|
+
ref: latestTag.name,
|
|
793
|
+
commit: latestTag.commit
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
case 'range':
|
|
797
|
+
{
|
|
798
|
+
const tags = await getRemoteTags(repoUrl);
|
|
799
|
+
const matchingTags = tags.filter((tag)=>{
|
|
800
|
+
const version = tag.name.replace(/^v/, '');
|
|
801
|
+
return __WEBPACK_EXTERNAL_MODULE_semver__.satisfies(version, versionSpec.value);
|
|
802
|
+
});
|
|
803
|
+
if (0 === matchingTags.length) throw new Error(`No version found matching ${versionSpec.raw} for ${repoUrl}`);
|
|
804
|
+
matchingTags.sort((a, b)=>{
|
|
805
|
+
const aVer = a.name.replace(/^v/, '');
|
|
806
|
+
const bVer = b.name.replace(/^v/, '');
|
|
807
|
+
return __WEBPACK_EXTERNAL_MODULE_semver__.compare(bVer, aVer);
|
|
808
|
+
});
|
|
809
|
+
return {
|
|
810
|
+
ref: matchingTags[0].name,
|
|
811
|
+
commit: matchingTags[0].commit
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
case 'branch':
|
|
815
|
+
return {
|
|
816
|
+
ref: versionSpec.value
|
|
817
|
+
};
|
|
818
|
+
case 'commit':
|
|
819
|
+
return {
|
|
820
|
+
ref: versionSpec.value,
|
|
821
|
+
commit: versionSpec.value
|
|
822
|
+
};
|
|
823
|
+
default:
|
|
824
|
+
throw new Error(`Unknown version type: ${versionSpec.type}`);
|
|
825
|
+
}
|
|
769
826
|
}
|
|
770
|
-
|
|
771
|
-
const
|
|
827
|
+
async resolve(ref) {
|
|
828
|
+
const parsed = this.parseRef(ref);
|
|
829
|
+
const repoUrl = this.buildRepoUrl(parsed);
|
|
830
|
+
const versionSpec = this.parseVersion(parsed.version);
|
|
831
|
+
const resolved = await this.resolveVersion(repoUrl, versionSpec);
|
|
772
832
|
return {
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
const lock = this.load();
|
|
778
|
-
return name in lock.skills;
|
|
779
|
-
}
|
|
780
|
-
isVersionMatch(name, version) {
|
|
781
|
-
const locked = this.get(name);
|
|
782
|
-
if (!locked) return false;
|
|
783
|
-
return locked.version === version;
|
|
784
|
-
}
|
|
785
|
-
clear() {
|
|
786
|
-
this.lockData = {
|
|
787
|
-
lockfileVersion: LOCKFILE_VERSION,
|
|
788
|
-
skills: {}
|
|
833
|
+
parsed,
|
|
834
|
+
repoUrl,
|
|
835
|
+
ref: resolved.ref,
|
|
836
|
+
commit: resolved.commit
|
|
789
837
|
};
|
|
790
|
-
this.save();
|
|
791
|
-
}
|
|
792
|
-
delete() {
|
|
793
|
-
if (this.exists()) {
|
|
794
|
-
const fs = __webpack_require__("node:fs");
|
|
795
|
-
fs.unlinkSync(this.lockPath);
|
|
796
|
-
}
|
|
797
|
-
this.lockData = null;
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
const agent_registry_home = (0, __WEBPACK_EXTERNAL_MODULE_os__.homedir)();
|
|
801
|
-
const agents = {
|
|
802
|
-
amp: {
|
|
803
|
-
name: 'amp',
|
|
804
|
-
displayName: 'Amp',
|
|
805
|
-
skillsDir: '.agents/skills',
|
|
806
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.config/agents/skills'),
|
|
807
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.config/amp'))
|
|
808
|
-
},
|
|
809
|
-
antigravity: {
|
|
810
|
-
name: 'antigravity',
|
|
811
|
-
displayName: 'Antigravity',
|
|
812
|
-
skillsDir: '.agent/skills',
|
|
813
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.gemini/antigravity/skills'),
|
|
814
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(process.cwd(), '.agent')) || (0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.gemini/antigravity'))
|
|
815
|
-
},
|
|
816
|
-
'claude-code': {
|
|
817
|
-
name: 'claude-code',
|
|
818
|
-
displayName: 'Claude Code',
|
|
819
|
-
skillsDir: '.claude/skills',
|
|
820
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.claude/skills'),
|
|
821
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.claude'))
|
|
822
|
-
},
|
|
823
|
-
clawdbot: {
|
|
824
|
-
name: 'clawdbot',
|
|
825
|
-
displayName: 'Clawdbot',
|
|
826
|
-
skillsDir: 'skills',
|
|
827
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.clawdbot/skills'),
|
|
828
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.clawdbot'))
|
|
829
|
-
},
|
|
830
|
-
codex: {
|
|
831
|
-
name: 'codex',
|
|
832
|
-
displayName: 'Codex',
|
|
833
|
-
skillsDir: '.codex/skills',
|
|
834
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.codex/skills'),
|
|
835
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.codex'))
|
|
836
|
-
},
|
|
837
|
-
cursor: {
|
|
838
|
-
name: 'cursor',
|
|
839
|
-
displayName: 'Cursor',
|
|
840
|
-
skillsDir: '.cursor/skills',
|
|
841
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.cursor/skills'),
|
|
842
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.cursor'))
|
|
843
|
-
},
|
|
844
|
-
droid: {
|
|
845
|
-
name: 'droid',
|
|
846
|
-
displayName: 'Droid',
|
|
847
|
-
skillsDir: '.factory/skills',
|
|
848
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.factory/skills'),
|
|
849
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.factory/skills'))
|
|
850
|
-
},
|
|
851
|
-
'gemini-cli': {
|
|
852
|
-
name: 'gemini-cli',
|
|
853
|
-
displayName: 'Gemini CLI',
|
|
854
|
-
skillsDir: '.gemini/skills',
|
|
855
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.gemini/skills'),
|
|
856
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.gemini'))
|
|
857
|
-
},
|
|
858
|
-
'github-copilot': {
|
|
859
|
-
name: 'github-copilot',
|
|
860
|
-
displayName: 'GitHub Copilot',
|
|
861
|
-
skillsDir: '.github/skills',
|
|
862
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.copilot/skills'),
|
|
863
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(process.cwd(), '.github')) || (0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.copilot'))
|
|
864
|
-
},
|
|
865
|
-
goose: {
|
|
866
|
-
name: 'goose',
|
|
867
|
-
displayName: 'Goose',
|
|
868
|
-
skillsDir: '.goose/skills',
|
|
869
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.config/goose/skills'),
|
|
870
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.config/goose'))
|
|
871
|
-
},
|
|
872
|
-
kilo: {
|
|
873
|
-
name: 'kilo',
|
|
874
|
-
displayName: 'Kilo Code',
|
|
875
|
-
skillsDir: '.kilocode/skills',
|
|
876
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.kilocode/skills'),
|
|
877
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.kilocode'))
|
|
878
|
-
},
|
|
879
|
-
'kiro-cli': {
|
|
880
|
-
name: 'kiro-cli',
|
|
881
|
-
displayName: 'Kiro CLI',
|
|
882
|
-
skillsDir: '.kiro/skills',
|
|
883
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.kiro/skills'),
|
|
884
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.kiro'))
|
|
885
|
-
},
|
|
886
|
-
opencode: {
|
|
887
|
-
name: 'opencode',
|
|
888
|
-
displayName: 'OpenCode',
|
|
889
|
-
skillsDir: '.opencode/skills',
|
|
890
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.config/opencode/skills'),
|
|
891
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.config/opencode')) || (0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.claude/skills'))
|
|
892
|
-
},
|
|
893
|
-
roo: {
|
|
894
|
-
name: 'roo',
|
|
895
|
-
displayName: 'Roo Code',
|
|
896
|
-
skillsDir: '.roo/skills',
|
|
897
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.roo/skills'),
|
|
898
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.roo'))
|
|
899
|
-
},
|
|
900
|
-
trae: {
|
|
901
|
-
name: 'trae',
|
|
902
|
-
displayName: 'Trae',
|
|
903
|
-
skillsDir: '.trae/skills',
|
|
904
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.trae/skills'),
|
|
905
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.trae'))
|
|
906
|
-
},
|
|
907
|
-
windsurf: {
|
|
908
|
-
name: 'windsurf',
|
|
909
|
-
displayName: 'Windsurf',
|
|
910
|
-
skillsDir: '.windsurf/skills',
|
|
911
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.codeium/windsurf/skills'),
|
|
912
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.codeium/windsurf'))
|
|
913
|
-
},
|
|
914
|
-
neovate: {
|
|
915
|
-
name: 'neovate',
|
|
916
|
-
displayName: 'Neovate',
|
|
917
|
-
skillsDir: '.neovate/skills',
|
|
918
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.neovate/skills'),
|
|
919
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.neovate'))
|
|
920
838
|
}
|
|
921
|
-
};
|
|
922
|
-
function getAllAgentTypes() {
|
|
923
|
-
return Object.keys(agents);
|
|
924
|
-
}
|
|
925
|
-
async function detectInstalledAgents() {
|
|
926
|
-
const installed = [];
|
|
927
|
-
for (const [type, config] of Object.entries(agents))if (await config.detectInstalled()) installed.push(type);
|
|
928
|
-
return installed;
|
|
929
|
-
}
|
|
930
|
-
function getAgentConfig(type) {
|
|
931
|
-
return agents[type];
|
|
932
|
-
}
|
|
933
|
-
function isValidAgentType(type) {
|
|
934
|
-
return type in agents;
|
|
935
|
-
}
|
|
936
|
-
function getAgentSkillsDir(type, options = {}) {
|
|
937
|
-
const config = agents[type];
|
|
938
|
-
if (options.global) return config.globalSkillsDir;
|
|
939
|
-
const cwd = options.cwd || process.cwd();
|
|
940
|
-
return (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(cwd, config.skillsDir);
|
|
941
839
|
}
|
|
942
840
|
const installer_AGENTS_DIR = '.agents';
|
|
943
841
|
const installer_SKILLS_SUBDIR = 'skills';
|
|
@@ -955,7 +853,7 @@ function installer_isPathSafe(basePath, targetPath) {
|
|
|
955
853
|
return normalizedTarget.startsWith(normalizedBase + __WEBPACK_EXTERNAL_MODULE_node_path__.sep) || normalizedTarget === normalizedBase;
|
|
956
854
|
}
|
|
957
855
|
function installer_getCanonicalSkillsDir(isGlobal, cwd) {
|
|
958
|
-
const baseDir = isGlobal ? (0,
|
|
856
|
+
const baseDir = isGlobal ? (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)() : cwd || process.cwd();
|
|
959
857
|
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, installer_AGENTS_DIR, installer_SKILLS_SUBDIR);
|
|
960
858
|
}
|
|
961
859
|
function installer_ensureDir(dirPath) {
|
|
@@ -1009,7 +907,7 @@ async function installer_createSymlink(target, linkPath) {
|
|
|
1009
907
|
const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
|
|
1010
908
|
installer_ensureDir(linkDir);
|
|
1011
909
|
const relativePath = __WEBPACK_EXTERNAL_MODULE_node_path__.relative(linkDir, target);
|
|
1012
|
-
const symlinkType = 'win32' === (0,
|
|
910
|
+
const symlinkType = 'win32' === (0, __WEBPACK_EXTERNAL_MODULE_node_os__.platform)() ? 'junction' : void 0;
|
|
1013
911
|
external_node_fs_.symlinkSync(relativePath, linkPath, symlinkType);
|
|
1014
912
|
return true;
|
|
1015
913
|
} catch {
|
|
@@ -1132,6 +1030,106 @@ class Installer {
|
|
|
1132
1030
|
}).filter((entry)=>entry.isDirectory() || entry.isSymbolicLink()).map((entry)=>entry.name);
|
|
1133
1031
|
}
|
|
1134
1032
|
}
|
|
1033
|
+
const LOCKFILE_VERSION = 1;
|
|
1034
|
+
class LockManager {
|
|
1035
|
+
projectRoot;
|
|
1036
|
+
lockPath;
|
|
1037
|
+
lockData = null;
|
|
1038
|
+
constructor(projectRoot){
|
|
1039
|
+
this.projectRoot = projectRoot || process.cwd();
|
|
1040
|
+
this.lockPath = getSkillsLockPath(this.projectRoot);
|
|
1041
|
+
}
|
|
1042
|
+
getLockPath() {
|
|
1043
|
+
return this.lockPath;
|
|
1044
|
+
}
|
|
1045
|
+
exists() {
|
|
1046
|
+
return exists(this.lockPath);
|
|
1047
|
+
}
|
|
1048
|
+
load() {
|
|
1049
|
+
if (this.lockData) return this.lockData;
|
|
1050
|
+
if (!this.exists()) {
|
|
1051
|
+
this.lockData = {
|
|
1052
|
+
lockfileVersion: LOCKFILE_VERSION,
|
|
1053
|
+
skills: {}
|
|
1054
|
+
};
|
|
1055
|
+
return this.lockData;
|
|
1056
|
+
}
|
|
1057
|
+
try {
|
|
1058
|
+
this.lockData = readJson(this.lockPath);
|
|
1059
|
+
return this.lockData;
|
|
1060
|
+
} catch (error) {
|
|
1061
|
+
throw new Error(`Failed to parse skills.lock: ${error.message}`);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
reload() {
|
|
1065
|
+
this.lockData = null;
|
|
1066
|
+
return this.load();
|
|
1067
|
+
}
|
|
1068
|
+
save(lockToSave) {
|
|
1069
|
+
const toSave = lockToSave || this.lockData;
|
|
1070
|
+
if (!toSave) throw new Error('No lock to save');
|
|
1071
|
+
writeJson(this.lockPath, toSave);
|
|
1072
|
+
this.lockData = toSave;
|
|
1073
|
+
}
|
|
1074
|
+
get(name) {
|
|
1075
|
+
const lock = this.load();
|
|
1076
|
+
return lock.skills[name];
|
|
1077
|
+
}
|
|
1078
|
+
set(name, skill) {
|
|
1079
|
+
const lock = this.load();
|
|
1080
|
+
lock.skills[name] = skill;
|
|
1081
|
+
this.save();
|
|
1082
|
+
}
|
|
1083
|
+
remove(name) {
|
|
1084
|
+
const lock = this.load();
|
|
1085
|
+
if (lock.skills[name]) {
|
|
1086
|
+
delete lock.skills[name];
|
|
1087
|
+
this.save();
|
|
1088
|
+
return true;
|
|
1089
|
+
}
|
|
1090
|
+
return false;
|
|
1091
|
+
}
|
|
1092
|
+
lockSkill(name, options) {
|
|
1093
|
+
const lockedSkill = {
|
|
1094
|
+
source: options.source,
|
|
1095
|
+
version: options.version,
|
|
1096
|
+
resolved: options.resolved,
|
|
1097
|
+
commit: options.commit,
|
|
1098
|
+
installedAt: new Date().toISOString()
|
|
1099
|
+
};
|
|
1100
|
+
this.set(name, lockedSkill);
|
|
1101
|
+
return lockedSkill;
|
|
1102
|
+
}
|
|
1103
|
+
getAll() {
|
|
1104
|
+
const lock = this.load();
|
|
1105
|
+
return {
|
|
1106
|
+
...lock.skills
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
has(name) {
|
|
1110
|
+
const lock = this.load();
|
|
1111
|
+
return name in lock.skills;
|
|
1112
|
+
}
|
|
1113
|
+
isVersionMatch(name, version) {
|
|
1114
|
+
const locked = this.get(name);
|
|
1115
|
+
if (!locked) return false;
|
|
1116
|
+
return locked.version === version;
|
|
1117
|
+
}
|
|
1118
|
+
clear() {
|
|
1119
|
+
this.lockData = {
|
|
1120
|
+
lockfileVersion: LOCKFILE_VERSION,
|
|
1121
|
+
skills: {}
|
|
1122
|
+
};
|
|
1123
|
+
this.save();
|
|
1124
|
+
}
|
|
1125
|
+
delete() {
|
|
1126
|
+
if (this.exists()) {
|
|
1127
|
+
const fs = __webpack_require__("node:fs");
|
|
1128
|
+
fs.unlinkSync(this.lockPath);
|
|
1129
|
+
}
|
|
1130
|
+
this.lockData = null;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1135
1133
|
const logger = {
|
|
1136
1134
|
info (message) {
|
|
1137
1135
|
console.log(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].blue('ℹ'), message);
|
|
@@ -1199,8 +1197,17 @@ class SkillManager {
|
|
|
1199
1197
|
if (this.isGlobal) return getGlobalSkillsDir();
|
|
1200
1198
|
return this.config.getInstallDir();
|
|
1201
1199
|
}
|
|
1200
|
+
getCanonicalSkillsDir() {
|
|
1201
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
1202
|
+
const baseDir = this.isGlobal ? home : this.projectRoot;
|
|
1203
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, '.agents', 'skills');
|
|
1204
|
+
}
|
|
1202
1205
|
getSkillPath(name) {
|
|
1203
|
-
|
|
1206
|
+
const canonicalPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getCanonicalSkillsDir(), name);
|
|
1207
|
+
if (exists(canonicalPath)) return canonicalPath;
|
|
1208
|
+
const legacyPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getInstallDir(), name);
|
|
1209
|
+
if (exists(legacyPath)) return legacyPath;
|
|
1210
|
+
return canonicalPath;
|
|
1204
1211
|
}
|
|
1205
1212
|
async install(ref, options = {}) {
|
|
1206
1213
|
const { force = false, save = true } = options;
|
|
@@ -1213,11 +1220,13 @@ class SkillManager {
|
|
|
1213
1220
|
const locked = this.lockManager.get(skillName);
|
|
1214
1221
|
if (locked && locked.version === version) {
|
|
1215
1222
|
logger.info(`${skillName}@${version} is already installed`);
|
|
1216
|
-
|
|
1223
|
+
const installed = this.getInstalledSkill(skillName);
|
|
1224
|
+
if (installed) return installed;
|
|
1217
1225
|
}
|
|
1218
1226
|
if (!force) {
|
|
1219
1227
|
logger.warn(`${skillName} is already installed. Use --force to reinstall.`);
|
|
1220
|
-
|
|
1228
|
+
const installed = this.getInstalledSkill(skillName);
|
|
1229
|
+
if (installed) return installed;
|
|
1221
1230
|
}
|
|
1222
1231
|
}
|
|
1223
1232
|
logger["package"](`Installing ${skillName}@${version}...`);
|
|
@@ -1231,7 +1240,7 @@ class SkillManager {
|
|
|
1231
1240
|
if (exists(skillPath)) remove(skillPath);
|
|
1232
1241
|
await this.cache.copyTo(parsed, version, skillPath);
|
|
1233
1242
|
if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
|
|
1234
|
-
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ?
|
|
1243
|
+
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
|
|
1235
1244
|
version,
|
|
1236
1245
|
resolved: repoUrl,
|
|
1237
1246
|
commit: cacheResult.commit
|
|
@@ -1239,7 +1248,9 @@ class SkillManager {
|
|
|
1239
1248
|
if (!this.isGlobal && save && this.config.exists()) this.config.addSkill(skillName, ref);
|
|
1240
1249
|
const locationHint = this.isGlobal ? '(global)' : '';
|
|
1241
1250
|
logger.success(`Installed ${skillName}@${version} to ${skillPath} ${locationHint}`.trim());
|
|
1242
|
-
|
|
1251
|
+
const installed = this.getInstalledSkill(skillName);
|
|
1252
|
+
if (!installed) throw new Error(`Failed to get installed skill info for ${skillName}`);
|
|
1253
|
+
return installed;
|
|
1243
1254
|
}
|
|
1244
1255
|
async installAll(options = {}) {
|
|
1245
1256
|
const skills = this.config.getSkills();
|
|
@@ -1306,7 +1317,7 @@ class SkillManager {
|
|
|
1306
1317
|
skillName = name || skillJson.name || skillName;
|
|
1307
1318
|
} catch {}
|
|
1308
1319
|
const linkPath = this.getSkillPath(skillName);
|
|
1309
|
-
ensureDir(
|
|
1320
|
+
ensureDir(__WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath));
|
|
1310
1321
|
createSymlink(absolutePath, linkPath);
|
|
1311
1322
|
logger.success(`Linked ${skillName} → ${absolutePath}`);
|
|
1312
1323
|
return {
|
|
@@ -1332,20 +1343,36 @@ class SkillManager {
|
|
|
1332
1343
|
return true;
|
|
1333
1344
|
}
|
|
1334
1345
|
list() {
|
|
1335
|
-
const installDir = this.getInstallDir();
|
|
1336
|
-
if (!exists(installDir)) return [];
|
|
1337
1346
|
const skills = [];
|
|
1338
|
-
const
|
|
1339
|
-
|
|
1340
|
-
|
|
1347
|
+
const seenNames = new Set();
|
|
1348
|
+
const canonicalDir = this.getCanonicalSkillsDir();
|
|
1349
|
+
if (exists(canonicalDir)) for (const name of listDir(canonicalDir)){
|
|
1350
|
+
const skillPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalDir, name);
|
|
1351
|
+
if (!isDirectory(skillPath)) continue;
|
|
1352
|
+
const skill = this.getInstalledSkillFromPath(name, skillPath);
|
|
1353
|
+
if (skill) {
|
|
1354
|
+
skills.push(skill);
|
|
1355
|
+
seenNames.add(name);
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
const legacyDir = this.getInstallDir();
|
|
1359
|
+
if (exists(legacyDir) && legacyDir !== canonicalDir) for (const name of listDir(legacyDir)){
|
|
1360
|
+
if (seenNames.has(name)) continue;
|
|
1361
|
+
const skillPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(legacyDir, name);
|
|
1341
1362
|
if (!isDirectory(skillPath)) continue;
|
|
1342
|
-
|
|
1343
|
-
|
|
1363
|
+
if (isSymlink(skillPath)) try {
|
|
1364
|
+
const realPath = getRealPath(skillPath);
|
|
1365
|
+
if (realPath.includes(__WEBPACK_EXTERNAL_MODULE_node_path__.join('.agents', 'skills'))) continue;
|
|
1366
|
+
} catch {}
|
|
1367
|
+
const skill = this.getInstalledSkillFromPath(name, skillPath);
|
|
1368
|
+
if (skill) {
|
|
1369
|
+
skills.push(skill);
|
|
1370
|
+
seenNames.add(name);
|
|
1371
|
+
}
|
|
1344
1372
|
}
|
|
1345
1373
|
return skills;
|
|
1346
1374
|
}
|
|
1347
|
-
|
|
1348
|
-
const skillPath = this.getSkillPath(name);
|
|
1375
|
+
getInstalledSkillFromPath(name, skillPath) {
|
|
1349
1376
|
if (!exists(skillPath)) return null;
|
|
1350
1377
|
const isLinked = isSymlink(skillPath);
|
|
1351
1378
|
const locked = this.lockManager.get(name);
|
|
@@ -1363,6 +1390,13 @@ class SkillManager {
|
|
|
1363
1390
|
isLinked
|
|
1364
1391
|
};
|
|
1365
1392
|
}
|
|
1393
|
+
getInstalledSkill(name) {
|
|
1394
|
+
const canonicalPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getCanonicalSkillsDir(), name);
|
|
1395
|
+
if (exists(canonicalPath)) return this.getInstalledSkillFromPath(name, canonicalPath);
|
|
1396
|
+
const legacyPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getInstallDir(), name);
|
|
1397
|
+
if (exists(legacyPath)) return this.getInstalledSkillFromPath(name, legacyPath);
|
|
1398
|
+
return null;
|
|
1399
|
+
}
|
|
1366
1400
|
getInfo(name) {
|
|
1367
1401
|
return {
|
|
1368
1402
|
installed: this.getInstalledSkill(name),
|
|
@@ -1424,7 +1458,7 @@ class SkillManager {
|
|
|
1424
1458
|
mode: mode
|
|
1425
1459
|
});
|
|
1426
1460
|
if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
|
|
1427
|
-
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ?
|
|
1461
|
+
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
|
|
1428
1462
|
version,
|
|
1429
1463
|
resolved: repoUrl,
|
|
1430
1464
|
commit: cacheResult.commit
|
|
@@ -1438,7 +1472,7 @@ class SkillManager {
|
|
|
1438
1472
|
name: skillName,
|
|
1439
1473
|
path: sourcePath,
|
|
1440
1474
|
version,
|
|
1441
|
-
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ?
|
|
1475
|
+
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`
|
|
1442
1476
|
};
|
|
1443
1477
|
return {
|
|
1444
1478
|
skill,
|