reskill 0.11.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +106 -20
- package/README.zh-CN.md +106 -20
- 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 +700 -642
- 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 +24 -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 +641 -583
- 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/dist/utils/git.d.ts +5 -0
- package/dist/utils/git.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,25 +20,289 @@ 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;
|
|
28
278
|
originalError;
|
|
29
279
|
isAuthError;
|
|
280
|
+
urlType;
|
|
30
281
|
constructor(repoUrl, originalError){
|
|
31
282
|
const isAuthError = GitCloneError.isAuthenticationError(originalError.message);
|
|
283
|
+
const urlType = GitCloneError.detectUrlType(repoUrl);
|
|
32
284
|
let message = `Failed to clone repository: ${repoUrl}`;
|
|
33
285
|
if (isAuthError) {
|
|
34
|
-
message += '\n\nTip: For private repos, ensure git
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
286
|
+
message += '\n\nTip: For private repos, ensure git credentials are configured:';
|
|
287
|
+
if ('ssh' === urlType) {
|
|
288
|
+
message += '\n - Check ~/.ssh/id_rsa or ~/.ssh/id_ed25519';
|
|
289
|
+
message += '\n - Ensure SSH key is added to your Git hosting service';
|
|
290
|
+
} else {
|
|
291
|
+
message += "\n - Run 'git config --global credential.helper store'";
|
|
292
|
+
message += '\n - Or use a personal access token in the URL';
|
|
293
|
+
}
|
|
38
294
|
}
|
|
39
295
|
super(message);
|
|
40
296
|
this.name = 'GitCloneError';
|
|
41
297
|
this.repoUrl = repoUrl;
|
|
42
298
|
this.originalError = originalError;
|
|
43
299
|
this.isAuthError = isAuthError;
|
|
300
|
+
this.urlType = urlType;
|
|
301
|
+
}
|
|
302
|
+
static detectUrlType(url) {
|
|
303
|
+
if (url.startsWith('git@') || url.startsWith('ssh://')) return 'ssh';
|
|
304
|
+
if (url.startsWith('http://') || url.startsWith('https://')) return 'https';
|
|
305
|
+
return 'unknown';
|
|
44
306
|
}
|
|
45
307
|
static isAuthenticationError(message) {
|
|
46
308
|
const authPatterns = [
|
|
@@ -156,323 +418,41 @@ function buildRepoUrl(registry, ownerRepo) {
|
|
|
156
418
|
function isGitUrl(source) {
|
|
157
419
|
return source.startsWith('git@') || source.startsWith('git://') || source.startsWith('http://') || source.startsWith('https://') || source.endsWith('.git');
|
|
158
420
|
}
|
|
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;
|
|
468
|
-
}
|
|
469
|
-
function sanitizeName(name) {
|
|
470
|
-
let sanitized = name.replace(/[/\\:\0]/g, '');
|
|
471
|
-
sanitized = sanitized.replace(/^[.\s]+|[.\s]+$/g, '');
|
|
472
|
-
sanitized = sanitized.replace(/^\.+/, '');
|
|
473
|
-
if (!sanitized || 0 === sanitized.length) sanitized = 'unnamed-skill';
|
|
474
|
-
if (sanitized.length > 255) sanitized = sanitized.substring(0, 255);
|
|
475
|
-
return sanitized;
|
|
421
|
+
function parseGitUrl(url) {
|
|
422
|
+
const cleanUrl = url.replace(/\.git$/, '');
|
|
423
|
+
const sshMatch = cleanUrl.match(/^git@([^:]+):(.+)$/);
|
|
424
|
+
if (sshMatch) {
|
|
425
|
+
const [, host, path] = sshMatch;
|
|
426
|
+
const parts = path.split('/');
|
|
427
|
+
if (parts.length >= 2) {
|
|
428
|
+
const owner = parts.slice(0, -1).join('/');
|
|
429
|
+
const repo = parts[parts.length - 1];
|
|
430
|
+
return {
|
|
431
|
+
host,
|
|
432
|
+
owner,
|
|
433
|
+
repo,
|
|
434
|
+
url,
|
|
435
|
+
type: 'ssh'
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
const httpMatch = cleanUrl.match(/^(https?|git):\/\/([^/]+)\/(.+)$/);
|
|
440
|
+
if (httpMatch) {
|
|
441
|
+
const [, protocol, host, path] = httpMatch;
|
|
442
|
+
const parts = path.split('/');
|
|
443
|
+
if (parts.length >= 2) {
|
|
444
|
+
const owner = parts.slice(0, -1).join('/');
|
|
445
|
+
const repo = parts[parts.length - 1];
|
|
446
|
+
return {
|
|
447
|
+
host,
|
|
448
|
+
owner,
|
|
449
|
+
repo,
|
|
450
|
+
url,
|
|
451
|
+
type: 'git' === protocol ? 'git' : 'https'
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return null;
|
|
476
456
|
}
|
|
477
457
|
class CacheManager {
|
|
478
458
|
cacheDir;
|
|
@@ -633,6 +613,11 @@ class ConfigLoader {
|
|
|
633
613
|
writeJson(this.configPath, toSave);
|
|
634
614
|
this.config = toSave;
|
|
635
615
|
}
|
|
616
|
+
ensureExists() {
|
|
617
|
+
if (this.exists()) return false;
|
|
618
|
+
this.create();
|
|
619
|
+
return true;
|
|
620
|
+
}
|
|
636
621
|
create(options) {
|
|
637
622
|
const config = {
|
|
638
623
|
...DEFAULT_SKILLS_JSON,
|
|
@@ -649,8 +634,8 @@ class ConfigLoader {
|
|
|
649
634
|
getDefaults() {
|
|
650
635
|
const config = this.config || (this.exists() ? this.load() : DEFAULT_SKILLS_JSON);
|
|
651
636
|
return {
|
|
652
|
-
registry: config.defaults?.registry ||
|
|
653
|
-
installDir: config.defaults?.installDir ||
|
|
637
|
+
registry: config.defaults?.registry || 'github',
|
|
638
|
+
installDir: config.defaults?.installDir || '.skills',
|
|
654
639
|
targetAgents: config.defaults?.targetAgents || [],
|
|
655
640
|
installMode: config.defaults?.installMode || 'symlink'
|
|
656
641
|
};
|
|
@@ -667,12 +652,12 @@ class ConfigLoader {
|
|
|
667
652
|
}
|
|
668
653
|
addSkill(name, ref) {
|
|
669
654
|
if (!this.config) this.load();
|
|
670
|
-
this.config.skills[name] = ref;
|
|
655
|
+
if (this.config) this.config.skills[name] = ref;
|
|
671
656
|
this.save();
|
|
672
657
|
}
|
|
673
658
|
removeSkill(name) {
|
|
674
659
|
if (!this.config) this.load();
|
|
675
|
-
if (this.config
|
|
660
|
+
if (this.config?.skills[name]) {
|
|
676
661
|
delete this.config.skills[name];
|
|
677
662
|
this.save();
|
|
678
663
|
return true;
|
|
@@ -685,7 +670,7 @@ class ConfigLoader {
|
|
|
685
670
|
this.load();
|
|
686
671
|
}
|
|
687
672
|
return {
|
|
688
|
-
...this.config
|
|
673
|
+
...this.config?.skills
|
|
689
674
|
};
|
|
690
675
|
}
|
|
691
676
|
hasSkill(name) {
|
|
@@ -697,247 +682,177 @@ class ConfigLoader {
|
|
|
697
682
|
return skills[name];
|
|
698
683
|
}
|
|
699
684
|
}
|
|
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);
|
|
685
|
+
class GitResolver {
|
|
686
|
+
defaultRegistry;
|
|
687
|
+
constructor(defaultRegistry = 'github'){
|
|
688
|
+
this.defaultRegistry = defaultRegistry;
|
|
714
689
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
if (
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
690
|
+
parseRef(ref) {
|
|
691
|
+
const raw = ref;
|
|
692
|
+
if (isGitUrl(ref)) return this.parseGitUrlRef(ref);
|
|
693
|
+
let remaining = ref;
|
|
694
|
+
let registry = this.defaultRegistry;
|
|
695
|
+
let version;
|
|
696
|
+
const registryMatch = remaining.match(/^([a-zA-Z0-9.-]+):(.+)$/);
|
|
697
|
+
if (registryMatch) {
|
|
698
|
+
registry = registryMatch[1];
|
|
699
|
+
remaining = registryMatch[2];
|
|
723
700
|
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
throw new Error(`Failed to parse skills.lock: ${error.message}`);
|
|
701
|
+
const atIndex = remaining.lastIndexOf('@');
|
|
702
|
+
if (atIndex > 0) {
|
|
703
|
+
version = remaining.slice(atIndex + 1);
|
|
704
|
+
remaining = remaining.slice(0, atIndex);
|
|
729
705
|
}
|
|
706
|
+
const parts = remaining.split('/');
|
|
707
|
+
if (parts.length < 2) throw new Error(`Invalid skill reference: ${ref}. Expected format: owner/repo[@version]`);
|
|
708
|
+
const owner = parts[0];
|
|
709
|
+
const repo = parts[1];
|
|
710
|
+
const subPath = parts.length > 2 ? parts.slice(2).join('/') : void 0;
|
|
711
|
+
return {
|
|
712
|
+
registry,
|
|
713
|
+
owner,
|
|
714
|
+
repo,
|
|
715
|
+
subPath,
|
|
716
|
+
version,
|
|
717
|
+
raw
|
|
718
|
+
};
|
|
730
719
|
}
|
|
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;
|
|
720
|
+
parseGitUrlRef(ref) {
|
|
721
|
+
const raw = ref;
|
|
722
|
+
let gitUrl = ref;
|
|
723
|
+
let version;
|
|
724
|
+
let subPath;
|
|
725
|
+
const gitSuffixIndex = ref.indexOf('.git');
|
|
726
|
+
if (-1 !== gitSuffixIndex) {
|
|
727
|
+
const afterGit = ref.slice(gitSuffixIndex + 4);
|
|
728
|
+
if (afterGit) {
|
|
729
|
+
const atIndex = afterGit.lastIndexOf('@');
|
|
730
|
+
if (-1 !== atIndex) {
|
|
731
|
+
version = afterGit.slice(atIndex + 1);
|
|
732
|
+
const pathPart = afterGit.slice(0, atIndex);
|
|
733
|
+
if (pathPart.startsWith('/')) subPath = pathPart.slice(1);
|
|
734
|
+
} else if (afterGit.startsWith('/')) subPath = afterGit.slice(1);
|
|
735
|
+
gitUrl = ref.slice(0, gitSuffixIndex + 4);
|
|
736
|
+
}
|
|
737
|
+
} else {
|
|
738
|
+
const atIndex = ref.lastIndexOf('@');
|
|
739
|
+
if (atIndex > 4) {
|
|
740
|
+
version = ref.slice(atIndex + 1);
|
|
741
|
+
gitUrl = ref.slice(0, atIndex);
|
|
742
|
+
}
|
|
756
743
|
}
|
|
757
|
-
|
|
744
|
+
const parsed = parseGitUrl(gitUrl);
|
|
745
|
+
if (!parsed) throw new Error(`Invalid Git URL: ${ref}. Expected format: git@host:owner/repo.git or https://host/owner/repo.git`);
|
|
746
|
+
return {
|
|
747
|
+
registry: parsed.host,
|
|
748
|
+
owner: parsed.owner,
|
|
749
|
+
repo: parsed.repo,
|
|
750
|
+
subPath,
|
|
751
|
+
version,
|
|
752
|
+
raw,
|
|
753
|
+
gitUrl
|
|
754
|
+
};
|
|
758
755
|
}
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
commit: options.commit,
|
|
765
|
-
installedAt: new Date().toISOString()
|
|
756
|
+
parseVersion(versionSpec) {
|
|
757
|
+
if (!versionSpec) return {
|
|
758
|
+
type: 'branch',
|
|
759
|
+
value: 'main',
|
|
760
|
+
raw: ''
|
|
766
761
|
};
|
|
767
|
-
|
|
768
|
-
return
|
|
762
|
+
const raw = versionSpec;
|
|
763
|
+
if ('latest' === versionSpec) return {
|
|
764
|
+
type: 'latest',
|
|
765
|
+
value: 'latest',
|
|
766
|
+
raw
|
|
767
|
+
};
|
|
768
|
+
if (versionSpec.startsWith('branch:')) return {
|
|
769
|
+
type: 'branch',
|
|
770
|
+
value: versionSpec.slice(7),
|
|
771
|
+
raw
|
|
772
|
+
};
|
|
773
|
+
if (versionSpec.startsWith('commit:')) return {
|
|
774
|
+
type: 'commit',
|
|
775
|
+
value: versionSpec.slice(7),
|
|
776
|
+
raw
|
|
777
|
+
};
|
|
778
|
+
if (/^[\^~><]/.test(versionSpec)) return {
|
|
779
|
+
type: 'range',
|
|
780
|
+
value: versionSpec,
|
|
781
|
+
raw
|
|
782
|
+
};
|
|
783
|
+
return {
|
|
784
|
+
type: 'exact',
|
|
785
|
+
value: versionSpec,
|
|
786
|
+
raw
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
buildRepoUrl(parsed) {
|
|
790
|
+
if (parsed.gitUrl) return parsed.gitUrl;
|
|
791
|
+
return buildRepoUrl(parsed.registry, `${parsed.owner}/${parsed.repo}`);
|
|
792
|
+
}
|
|
793
|
+
async resolveVersion(repoUrl, versionSpec) {
|
|
794
|
+
switch(versionSpec.type){
|
|
795
|
+
case 'exact':
|
|
796
|
+
return {
|
|
797
|
+
ref: versionSpec.value
|
|
798
|
+
};
|
|
799
|
+
case 'latest':
|
|
800
|
+
{
|
|
801
|
+
const latestTag = await getLatestTag(repoUrl);
|
|
802
|
+
if (!latestTag) {
|
|
803
|
+
const defaultBranch = await getDefaultBranch(repoUrl);
|
|
804
|
+
return {
|
|
805
|
+
ref: defaultBranch
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
return {
|
|
809
|
+
ref: latestTag.name,
|
|
810
|
+
commit: latestTag.commit
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
case 'range':
|
|
814
|
+
{
|
|
815
|
+
const tags = await getRemoteTags(repoUrl);
|
|
816
|
+
const matchingTags = tags.filter((tag)=>{
|
|
817
|
+
const version = tag.name.replace(/^v/, '');
|
|
818
|
+
return __WEBPACK_EXTERNAL_MODULE_semver__.satisfies(version, versionSpec.value);
|
|
819
|
+
});
|
|
820
|
+
if (0 === matchingTags.length) throw new Error(`No version found matching ${versionSpec.raw} for ${repoUrl}`);
|
|
821
|
+
matchingTags.sort((a, b)=>{
|
|
822
|
+
const aVer = a.name.replace(/^v/, '');
|
|
823
|
+
const bVer = b.name.replace(/^v/, '');
|
|
824
|
+
return __WEBPACK_EXTERNAL_MODULE_semver__.compare(bVer, aVer);
|
|
825
|
+
});
|
|
826
|
+
return {
|
|
827
|
+
ref: matchingTags[0].name,
|
|
828
|
+
commit: matchingTags[0].commit
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
case 'branch':
|
|
832
|
+
return {
|
|
833
|
+
ref: versionSpec.value
|
|
834
|
+
};
|
|
835
|
+
case 'commit':
|
|
836
|
+
return {
|
|
837
|
+
ref: versionSpec.value,
|
|
838
|
+
commit: versionSpec.value
|
|
839
|
+
};
|
|
840
|
+
default:
|
|
841
|
+
throw new Error(`Unknown version type: ${versionSpec.type}`);
|
|
842
|
+
}
|
|
769
843
|
}
|
|
770
|
-
|
|
771
|
-
const
|
|
844
|
+
async resolve(ref) {
|
|
845
|
+
const parsed = this.parseRef(ref);
|
|
846
|
+
const repoUrl = this.buildRepoUrl(parsed);
|
|
847
|
+
const versionSpec = this.parseVersion(parsed.version);
|
|
848
|
+
const resolved = await this.resolveVersion(repoUrl, versionSpec);
|
|
772
849
|
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: {}
|
|
850
|
+
parsed,
|
|
851
|
+
repoUrl,
|
|
852
|
+
ref: resolved.ref,
|
|
853
|
+
commit: resolved.commit
|
|
789
854
|
};
|
|
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
855
|
}
|
|
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
856
|
}
|
|
942
857
|
const installer_AGENTS_DIR = '.agents';
|
|
943
858
|
const installer_SKILLS_SUBDIR = 'skills';
|
|
@@ -955,7 +870,7 @@ function installer_isPathSafe(basePath, targetPath) {
|
|
|
955
870
|
return normalizedTarget.startsWith(normalizedBase + __WEBPACK_EXTERNAL_MODULE_node_path__.sep) || normalizedTarget === normalizedBase;
|
|
956
871
|
}
|
|
957
872
|
function installer_getCanonicalSkillsDir(isGlobal, cwd) {
|
|
958
|
-
const baseDir = isGlobal ? (0,
|
|
873
|
+
const baseDir = isGlobal ? (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)() : cwd || process.cwd();
|
|
959
874
|
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, installer_AGENTS_DIR, installer_SKILLS_SUBDIR);
|
|
960
875
|
}
|
|
961
876
|
function installer_ensureDir(dirPath) {
|
|
@@ -972,7 +887,8 @@ function installer_remove(targetPath) {
|
|
|
972
887
|
function copyDirectory(src, dest, options) {
|
|
973
888
|
const exclude = new Set(options?.exclude || [
|
|
974
889
|
'README.md',
|
|
975
|
-
'metadata.json'
|
|
890
|
+
'metadata.json',
|
|
891
|
+
'.reskill-commit'
|
|
976
892
|
]);
|
|
977
893
|
installer_ensureDir(dest);
|
|
978
894
|
const entries = external_node_fs_.readdirSync(src, {
|
|
@@ -1009,7 +925,7 @@ async function installer_createSymlink(target, linkPath) {
|
|
|
1009
925
|
const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
|
|
1010
926
|
installer_ensureDir(linkDir);
|
|
1011
927
|
const relativePath = __WEBPACK_EXTERNAL_MODULE_node_path__.relative(linkDir, target);
|
|
1012
|
-
const symlinkType = 'win32' === (0,
|
|
928
|
+
const symlinkType = 'win32' === (0, __WEBPACK_EXTERNAL_MODULE_node_os__.platform)() ? 'junction' : void 0;
|
|
1013
929
|
external_node_fs_.symlinkSync(relativePath, linkPath, symlinkType);
|
|
1014
930
|
return true;
|
|
1015
931
|
} catch {
|
|
@@ -1132,6 +1048,106 @@ class Installer {
|
|
|
1132
1048
|
}).filter((entry)=>entry.isDirectory() || entry.isSymbolicLink()).map((entry)=>entry.name);
|
|
1133
1049
|
}
|
|
1134
1050
|
}
|
|
1051
|
+
const LOCKFILE_VERSION = 1;
|
|
1052
|
+
class LockManager {
|
|
1053
|
+
projectRoot;
|
|
1054
|
+
lockPath;
|
|
1055
|
+
lockData = null;
|
|
1056
|
+
constructor(projectRoot){
|
|
1057
|
+
this.projectRoot = projectRoot || process.cwd();
|
|
1058
|
+
this.lockPath = getSkillsLockPath(this.projectRoot);
|
|
1059
|
+
}
|
|
1060
|
+
getLockPath() {
|
|
1061
|
+
return this.lockPath;
|
|
1062
|
+
}
|
|
1063
|
+
exists() {
|
|
1064
|
+
return exists(this.lockPath);
|
|
1065
|
+
}
|
|
1066
|
+
load() {
|
|
1067
|
+
if (this.lockData) return this.lockData;
|
|
1068
|
+
if (!this.exists()) {
|
|
1069
|
+
this.lockData = {
|
|
1070
|
+
lockfileVersion: LOCKFILE_VERSION,
|
|
1071
|
+
skills: {}
|
|
1072
|
+
};
|
|
1073
|
+
return this.lockData;
|
|
1074
|
+
}
|
|
1075
|
+
try {
|
|
1076
|
+
this.lockData = readJson(this.lockPath);
|
|
1077
|
+
return this.lockData;
|
|
1078
|
+
} catch (error) {
|
|
1079
|
+
throw new Error(`Failed to parse skills.lock: ${error.message}`);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
reload() {
|
|
1083
|
+
this.lockData = null;
|
|
1084
|
+
return this.load();
|
|
1085
|
+
}
|
|
1086
|
+
save(lockToSave) {
|
|
1087
|
+
const toSave = lockToSave || this.lockData;
|
|
1088
|
+
if (!toSave) throw new Error('No lock to save');
|
|
1089
|
+
writeJson(this.lockPath, toSave);
|
|
1090
|
+
this.lockData = toSave;
|
|
1091
|
+
}
|
|
1092
|
+
get(name) {
|
|
1093
|
+
const lock = this.load();
|
|
1094
|
+
return lock.skills[name];
|
|
1095
|
+
}
|
|
1096
|
+
set(name, skill) {
|
|
1097
|
+
const lock = this.load();
|
|
1098
|
+
lock.skills[name] = skill;
|
|
1099
|
+
this.save();
|
|
1100
|
+
}
|
|
1101
|
+
remove(name) {
|
|
1102
|
+
const lock = this.load();
|
|
1103
|
+
if (lock.skills[name]) {
|
|
1104
|
+
delete lock.skills[name];
|
|
1105
|
+
this.save();
|
|
1106
|
+
return true;
|
|
1107
|
+
}
|
|
1108
|
+
return false;
|
|
1109
|
+
}
|
|
1110
|
+
lockSkill(name, options) {
|
|
1111
|
+
const lockedSkill = {
|
|
1112
|
+
source: options.source,
|
|
1113
|
+
version: options.version,
|
|
1114
|
+
resolved: options.resolved,
|
|
1115
|
+
commit: options.commit,
|
|
1116
|
+
installedAt: new Date().toISOString()
|
|
1117
|
+
};
|
|
1118
|
+
this.set(name, lockedSkill);
|
|
1119
|
+
return lockedSkill;
|
|
1120
|
+
}
|
|
1121
|
+
getAll() {
|
|
1122
|
+
const lock = this.load();
|
|
1123
|
+
return {
|
|
1124
|
+
...lock.skills
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
has(name) {
|
|
1128
|
+
const lock = this.load();
|
|
1129
|
+
return name in lock.skills;
|
|
1130
|
+
}
|
|
1131
|
+
isVersionMatch(name, version) {
|
|
1132
|
+
const locked = this.get(name);
|
|
1133
|
+
if (!locked) return false;
|
|
1134
|
+
return locked.version === version;
|
|
1135
|
+
}
|
|
1136
|
+
clear() {
|
|
1137
|
+
this.lockData = {
|
|
1138
|
+
lockfileVersion: LOCKFILE_VERSION,
|
|
1139
|
+
skills: {}
|
|
1140
|
+
};
|
|
1141
|
+
this.save();
|
|
1142
|
+
}
|
|
1143
|
+
delete() {
|
|
1144
|
+
if (this.exists()) {
|
|
1145
|
+
const fs = __webpack_require__("node:fs");
|
|
1146
|
+
fs.unlinkSync(this.lockPath);
|
|
1147
|
+
}
|
|
1148
|
+
this.lockData = null;
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1135
1151
|
const logger = {
|
|
1136
1152
|
info (message) {
|
|
1137
1153
|
console.log(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].blue('ℹ'), message);
|
|
@@ -1199,8 +1215,17 @@ class SkillManager {
|
|
|
1199
1215
|
if (this.isGlobal) return getGlobalSkillsDir();
|
|
1200
1216
|
return this.config.getInstallDir();
|
|
1201
1217
|
}
|
|
1218
|
+
getCanonicalSkillsDir() {
|
|
1219
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
1220
|
+
const baseDir = this.isGlobal ? home : this.projectRoot;
|
|
1221
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, '.agents', 'skills');
|
|
1222
|
+
}
|
|
1202
1223
|
getSkillPath(name) {
|
|
1203
|
-
|
|
1224
|
+
const canonicalPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getCanonicalSkillsDir(), name);
|
|
1225
|
+
if (exists(canonicalPath)) return canonicalPath;
|
|
1226
|
+
const legacyPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getInstallDir(), name);
|
|
1227
|
+
if (exists(legacyPath)) return legacyPath;
|
|
1228
|
+
return canonicalPath;
|
|
1204
1229
|
}
|
|
1205
1230
|
async install(ref, options = {}) {
|
|
1206
1231
|
const { force = false, save = true } = options;
|
|
@@ -1213,11 +1238,13 @@ class SkillManager {
|
|
|
1213
1238
|
const locked = this.lockManager.get(skillName);
|
|
1214
1239
|
if (locked && locked.version === version) {
|
|
1215
1240
|
logger.info(`${skillName}@${version} is already installed`);
|
|
1216
|
-
|
|
1241
|
+
const installed = this.getInstalledSkill(skillName);
|
|
1242
|
+
if (installed) return installed;
|
|
1217
1243
|
}
|
|
1218
1244
|
if (!force) {
|
|
1219
1245
|
logger.warn(`${skillName} is already installed. Use --force to reinstall.`);
|
|
1220
|
-
|
|
1246
|
+
const installed = this.getInstalledSkill(skillName);
|
|
1247
|
+
if (installed) return installed;
|
|
1221
1248
|
}
|
|
1222
1249
|
}
|
|
1223
1250
|
logger["package"](`Installing ${skillName}@${version}...`);
|
|
@@ -1231,15 +1258,20 @@ class SkillManager {
|
|
|
1231
1258
|
if (exists(skillPath)) remove(skillPath);
|
|
1232
1259
|
await this.cache.copyTo(parsed, version, skillPath);
|
|
1233
1260
|
if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
|
|
1234
|
-
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ?
|
|
1261
|
+
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
|
|
1235
1262
|
version,
|
|
1236
1263
|
resolved: repoUrl,
|
|
1237
1264
|
commit: cacheResult.commit
|
|
1238
1265
|
});
|
|
1239
|
-
if (!this.isGlobal && save
|
|
1266
|
+
if (!this.isGlobal && save) {
|
|
1267
|
+
this.config.ensureExists();
|
|
1268
|
+
this.config.addSkill(skillName, ref);
|
|
1269
|
+
}
|
|
1240
1270
|
const locationHint = this.isGlobal ? '(global)' : '';
|
|
1241
1271
|
logger.success(`Installed ${skillName}@${version} to ${skillPath} ${locationHint}`.trim());
|
|
1242
|
-
|
|
1272
|
+
const installed = this.getInstalledSkill(skillName);
|
|
1273
|
+
if (!installed) throw new Error(`Failed to get installed skill info for ${skillName}`);
|
|
1274
|
+
return installed;
|
|
1243
1275
|
}
|
|
1244
1276
|
async installAll(options = {}) {
|
|
1245
1277
|
const skills = this.config.getSkills();
|
|
@@ -1306,7 +1338,7 @@ class SkillManager {
|
|
|
1306
1338
|
skillName = name || skillJson.name || skillName;
|
|
1307
1339
|
} catch {}
|
|
1308
1340
|
const linkPath = this.getSkillPath(skillName);
|
|
1309
|
-
ensureDir(
|
|
1341
|
+
ensureDir(__WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath));
|
|
1310
1342
|
createSymlink(absolutePath, linkPath);
|
|
1311
1343
|
logger.success(`Linked ${skillName} → ${absolutePath}`);
|
|
1312
1344
|
return {
|
|
@@ -1332,20 +1364,36 @@ class SkillManager {
|
|
|
1332
1364
|
return true;
|
|
1333
1365
|
}
|
|
1334
1366
|
list() {
|
|
1335
|
-
const installDir = this.getInstallDir();
|
|
1336
|
-
if (!exists(installDir)) return [];
|
|
1337
1367
|
const skills = [];
|
|
1338
|
-
const
|
|
1339
|
-
|
|
1340
|
-
|
|
1368
|
+
const seenNames = new Set();
|
|
1369
|
+
const canonicalDir = this.getCanonicalSkillsDir();
|
|
1370
|
+
if (exists(canonicalDir)) for (const name of listDir(canonicalDir)){
|
|
1371
|
+
const skillPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalDir, name);
|
|
1372
|
+
if (!isDirectory(skillPath)) continue;
|
|
1373
|
+
const skill = this.getInstalledSkillFromPath(name, skillPath);
|
|
1374
|
+
if (skill) {
|
|
1375
|
+
skills.push(skill);
|
|
1376
|
+
seenNames.add(name);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
const legacyDir = this.getInstallDir();
|
|
1380
|
+
if (exists(legacyDir) && legacyDir !== canonicalDir) for (const name of listDir(legacyDir)){
|
|
1381
|
+
if (seenNames.has(name)) continue;
|
|
1382
|
+
const skillPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(legacyDir, name);
|
|
1341
1383
|
if (!isDirectory(skillPath)) continue;
|
|
1342
|
-
|
|
1343
|
-
|
|
1384
|
+
if (isSymlink(skillPath)) try {
|
|
1385
|
+
const realPath = getRealPath(skillPath);
|
|
1386
|
+
if (realPath.includes(__WEBPACK_EXTERNAL_MODULE_node_path__.join('.agents', 'skills'))) continue;
|
|
1387
|
+
} catch {}
|
|
1388
|
+
const skill = this.getInstalledSkillFromPath(name, skillPath);
|
|
1389
|
+
if (skill) {
|
|
1390
|
+
skills.push(skill);
|
|
1391
|
+
seenNames.add(name);
|
|
1392
|
+
}
|
|
1344
1393
|
}
|
|
1345
1394
|
return skills;
|
|
1346
1395
|
}
|
|
1347
|
-
|
|
1348
|
-
const skillPath = this.getSkillPath(name);
|
|
1396
|
+
getInstalledSkillFromPath(name, skillPath) {
|
|
1349
1397
|
if (!exists(skillPath)) return null;
|
|
1350
1398
|
const isLinked = isSymlink(skillPath);
|
|
1351
1399
|
const locked = this.lockManager.get(name);
|
|
@@ -1363,6 +1411,13 @@ class SkillManager {
|
|
|
1363
1411
|
isLinked
|
|
1364
1412
|
};
|
|
1365
1413
|
}
|
|
1414
|
+
getInstalledSkill(name) {
|
|
1415
|
+
const canonicalPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getCanonicalSkillsDir(), name);
|
|
1416
|
+
if (exists(canonicalPath)) return this.getInstalledSkillFromPath(name, canonicalPath);
|
|
1417
|
+
const legacyPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getInstallDir(), name);
|
|
1418
|
+
if (exists(legacyPath)) return this.getInstalledSkillFromPath(name, legacyPath);
|
|
1419
|
+
return null;
|
|
1420
|
+
}
|
|
1366
1421
|
getInfo(name) {
|
|
1367
1422
|
return {
|
|
1368
1423
|
installed: this.getInstalledSkill(name),
|
|
@@ -1424,12 +1479,15 @@ class SkillManager {
|
|
|
1424
1479
|
mode: mode
|
|
1425
1480
|
});
|
|
1426
1481
|
if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
|
|
1427
|
-
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ?
|
|
1482
|
+
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
|
|
1428
1483
|
version,
|
|
1429
1484
|
resolved: repoUrl,
|
|
1430
1485
|
commit: cacheResult.commit
|
|
1431
1486
|
});
|
|
1432
|
-
if (!this.isGlobal && save
|
|
1487
|
+
if (!this.isGlobal && save) {
|
|
1488
|
+
this.config.ensureExists();
|
|
1489
|
+
this.config.addSkill(skillName, ref);
|
|
1490
|
+
}
|
|
1433
1491
|
const successCount = Array.from(results.values()).filter((r)=>r.success).length;
|
|
1434
1492
|
const failCount = results.size - successCount;
|
|
1435
1493
|
if (0 === failCount) logger.success(`Installed ${skillName}@${version} to ${successCount} agent(s)`);
|
|
@@ -1438,7 +1496,7 @@ class SkillManager {
|
|
|
1438
1496
|
name: skillName,
|
|
1439
1497
|
path: sourcePath,
|
|
1440
1498
|
version,
|
|
1441
|
-
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ?
|
|
1499
|
+
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`
|
|
1442
1500
|
};
|
|
1443
1501
|
return {
|
|
1444
1502
|
skill,
|