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/cli/index.js
CHANGED
|
@@ -3,13 +3,11 @@ import * as __WEBPACK_EXTERNAL_MODULE_node_fs__ from "node:fs";
|
|
|
3
3
|
import * as __WEBPACK_EXTERNAL_MODULE_commander__ from "commander";
|
|
4
4
|
import * as __WEBPACK_EXTERNAL_MODULE_node_path__ from "node:path";
|
|
5
5
|
import * as __WEBPACK_EXTERNAL_MODULE_chalk__ from "chalk";
|
|
6
|
-
import * as
|
|
7
|
-
import * as __WEBPACK_EXTERNAL_MODULE_semver__ from "semver";
|
|
6
|
+
import * as __WEBPACK_EXTERNAL_MODULE_node_os__ from "node:os";
|
|
8
7
|
import * as __WEBPACK_EXTERNAL_MODULE_node_child_process__ from "node:child_process";
|
|
9
8
|
import * as __WEBPACK_EXTERNAL_MODULE_node_util__ from "node:util";
|
|
10
|
-
import * as
|
|
11
|
-
import * as
|
|
12
|
-
import * as __WEBPACK_EXTERNAL_MODULE_fs__ from "fs";
|
|
9
|
+
import * as __WEBPACK_EXTERNAL_MODULE_semver__ from "semver";
|
|
10
|
+
import * as __WEBPACK_EXTERNAL_MODULE__clack_prompts__ from "@clack/prompts";
|
|
13
11
|
import * as __WEBPACK_EXTERNAL_MODULE_ora__ from "ora";
|
|
14
12
|
var __webpack_modules__ = {
|
|
15
13
|
"node:fs": function(module) {
|
|
@@ -39,7 +37,7 @@ function writeJson(filePath, data, indent = 2) {
|
|
|
39
37
|
if (!exists(dir)) external_node_fs_.mkdirSync(dir, {
|
|
40
38
|
recursive: true
|
|
41
39
|
});
|
|
42
|
-
external_node_fs_.writeFileSync(filePath, JSON.stringify(data, null, indent)
|
|
40
|
+
external_node_fs_.writeFileSync(filePath, `${JSON.stringify(data, null, indent)}\n`, 'utf-8');
|
|
43
41
|
}
|
|
44
42
|
function ensureDir(dirPath) {
|
|
45
43
|
if (!exists(dirPath)) external_node_fs_.mkdirSync(dirPath, {
|
|
@@ -110,121 +108,9 @@ function shortenPath(fullPath, cwd) {
|
|
|
110
108
|
const home = getHomeDir();
|
|
111
109
|
const currentDir = cwd || process.cwd();
|
|
112
110
|
if (fullPath.startsWith(home)) return fullPath.replace(home, '~');
|
|
113
|
-
if (fullPath.startsWith(currentDir)) return
|
|
111
|
+
if (fullPath.startsWith(currentDir)) return `.${fullPath.slice(currentDir.length)}`;
|
|
114
112
|
return fullPath;
|
|
115
113
|
}
|
|
116
|
-
const DEFAULT_SKILLS_JSON = {
|
|
117
|
-
skills: {},
|
|
118
|
-
defaults: {
|
|
119
|
-
registry: 'github',
|
|
120
|
-
installDir: '.skills'
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
const DEFAULT_REGISTRIES = {
|
|
124
|
-
github: 'https://github.com',
|
|
125
|
-
gitlab: 'https://gitlab.com'
|
|
126
|
-
};
|
|
127
|
-
class ConfigLoader {
|
|
128
|
-
projectRoot;
|
|
129
|
-
configPath;
|
|
130
|
-
config = null;
|
|
131
|
-
constructor(projectRoot){
|
|
132
|
-
this.projectRoot = projectRoot || process.cwd();
|
|
133
|
-
this.configPath = getSkillsJsonPath(this.projectRoot);
|
|
134
|
-
}
|
|
135
|
-
getProjectRoot() {
|
|
136
|
-
return this.projectRoot;
|
|
137
|
-
}
|
|
138
|
-
getConfigPath() {
|
|
139
|
-
return this.configPath;
|
|
140
|
-
}
|
|
141
|
-
exists() {
|
|
142
|
-
return exists(this.configPath);
|
|
143
|
-
}
|
|
144
|
-
load() {
|
|
145
|
-
if (this.config) return this.config;
|
|
146
|
-
if (!this.exists()) throw new Error(`skills.json not found in ${this.projectRoot}. Run 'reskill init' first.`);
|
|
147
|
-
try {
|
|
148
|
-
this.config = readJson(this.configPath);
|
|
149
|
-
return this.config;
|
|
150
|
-
} catch (error) {
|
|
151
|
-
throw new Error(`Failed to parse skills.json: ${error.message}`);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
reload() {
|
|
155
|
-
this.config = null;
|
|
156
|
-
return this.load();
|
|
157
|
-
}
|
|
158
|
-
save(config) {
|
|
159
|
-
const toSave = config || this.config;
|
|
160
|
-
if (!toSave) throw new Error('No config to save');
|
|
161
|
-
writeJson(this.configPath, toSave);
|
|
162
|
-
this.config = toSave;
|
|
163
|
-
}
|
|
164
|
-
create(options) {
|
|
165
|
-
const config = {
|
|
166
|
-
...DEFAULT_SKILLS_JSON,
|
|
167
|
-
...options,
|
|
168
|
-
skills: options?.skills || {},
|
|
169
|
-
defaults: {
|
|
170
|
-
...DEFAULT_SKILLS_JSON.defaults,
|
|
171
|
-
...options?.defaults
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
this.save(config);
|
|
175
|
-
return config;
|
|
176
|
-
}
|
|
177
|
-
getDefaults() {
|
|
178
|
-
const config = this.config || (this.exists() ? this.load() : DEFAULT_SKILLS_JSON);
|
|
179
|
-
return {
|
|
180
|
-
registry: config.defaults?.registry || DEFAULT_SKILLS_JSON.defaults.registry,
|
|
181
|
-
installDir: config.defaults?.installDir || DEFAULT_SKILLS_JSON.defaults.installDir,
|
|
182
|
-
targetAgents: config.defaults?.targetAgents || [],
|
|
183
|
-
installMode: config.defaults?.installMode || 'symlink'
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
getRegistryUrl(registryName) {
|
|
187
|
-
const config = this.config || (this.exists() ? this.load() : DEFAULT_SKILLS_JSON);
|
|
188
|
-
if (config.registries?.[registryName]) return config.registries[registryName];
|
|
189
|
-
if (DEFAULT_REGISTRIES[registryName]) return DEFAULT_REGISTRIES[registryName];
|
|
190
|
-
return `https://${registryName}`;
|
|
191
|
-
}
|
|
192
|
-
getInstallDir() {
|
|
193
|
-
const defaults = this.getDefaults();
|
|
194
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.projectRoot, defaults.installDir);
|
|
195
|
-
}
|
|
196
|
-
addSkill(name, ref) {
|
|
197
|
-
if (!this.config) this.load();
|
|
198
|
-
this.config.skills[name] = ref;
|
|
199
|
-
this.save();
|
|
200
|
-
}
|
|
201
|
-
removeSkill(name) {
|
|
202
|
-
if (!this.config) this.load();
|
|
203
|
-
if (this.config.skills[name]) {
|
|
204
|
-
delete this.config.skills[name];
|
|
205
|
-
this.save();
|
|
206
|
-
return true;
|
|
207
|
-
}
|
|
208
|
-
return false;
|
|
209
|
-
}
|
|
210
|
-
getSkills() {
|
|
211
|
-
if (!this.config) {
|
|
212
|
-
if (!this.exists()) return {};
|
|
213
|
-
this.load();
|
|
214
|
-
}
|
|
215
|
-
return {
|
|
216
|
-
...this.config.skills
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
hasSkill(name) {
|
|
220
|
-
const skills = this.getSkills();
|
|
221
|
-
return name in skills;
|
|
222
|
-
}
|
|
223
|
-
getSkillRef(name) {
|
|
224
|
-
const skills = this.getSkills();
|
|
225
|
-
return skills[name];
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
114
|
const logger = {
|
|
229
115
|
info (message) {
|
|
230
116
|
console.log(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].blue('ℹ'), message);
|
|
@@ -266,30 +152,139 @@ const logger = {
|
|
|
266
152
|
}
|
|
267
153
|
}
|
|
268
154
|
};
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
155
|
+
const agent_registry_home = (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)();
|
|
156
|
+
const agents = {
|
|
157
|
+
amp: {
|
|
158
|
+
name: 'amp',
|
|
159
|
+
displayName: 'Amp',
|
|
160
|
+
skillsDir: '.agents/skills',
|
|
161
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/agents/skills'),
|
|
162
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/amp'))
|
|
163
|
+
},
|
|
164
|
+
antigravity: {
|
|
165
|
+
name: 'antigravity',
|
|
166
|
+
displayName: 'Antigravity',
|
|
167
|
+
skillsDir: '.agent/skills',
|
|
168
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.gemini/antigravity/skills'),
|
|
169
|
+
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'))
|
|
170
|
+
},
|
|
171
|
+
'claude-code': {
|
|
172
|
+
name: 'claude-code',
|
|
173
|
+
displayName: 'Claude Code',
|
|
174
|
+
skillsDir: '.claude/skills',
|
|
175
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.claude/skills'),
|
|
176
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.claude'))
|
|
177
|
+
},
|
|
178
|
+
clawdbot: {
|
|
179
|
+
name: 'clawdbot',
|
|
180
|
+
displayName: 'Clawdbot',
|
|
181
|
+
skillsDir: 'skills',
|
|
182
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.clawdbot/skills'),
|
|
183
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.clawdbot'))
|
|
184
|
+
},
|
|
185
|
+
codex: {
|
|
186
|
+
name: 'codex',
|
|
187
|
+
displayName: 'Codex',
|
|
188
|
+
skillsDir: '.codex/skills',
|
|
189
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.codex/skills'),
|
|
190
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.codex'))
|
|
191
|
+
},
|
|
192
|
+
cursor: {
|
|
193
|
+
name: 'cursor',
|
|
194
|
+
displayName: 'Cursor',
|
|
195
|
+
skillsDir: '.cursor/skills',
|
|
196
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.cursor/skills'),
|
|
197
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.cursor'))
|
|
198
|
+
},
|
|
199
|
+
droid: {
|
|
200
|
+
name: 'droid',
|
|
201
|
+
displayName: 'Droid',
|
|
202
|
+
skillsDir: '.factory/skills',
|
|
203
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.factory/skills'),
|
|
204
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.factory/skills'))
|
|
205
|
+
},
|
|
206
|
+
'gemini-cli': {
|
|
207
|
+
name: 'gemini-cli',
|
|
208
|
+
displayName: 'Gemini CLI',
|
|
209
|
+
skillsDir: '.gemini/skills',
|
|
210
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.gemini/skills'),
|
|
211
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.gemini'))
|
|
212
|
+
},
|
|
213
|
+
'github-copilot': {
|
|
214
|
+
name: 'github-copilot',
|
|
215
|
+
displayName: 'GitHub Copilot',
|
|
216
|
+
skillsDir: '.github/skills',
|
|
217
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.copilot/skills'),
|
|
218
|
+
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'))
|
|
219
|
+
},
|
|
220
|
+
goose: {
|
|
221
|
+
name: 'goose',
|
|
222
|
+
displayName: 'Goose',
|
|
223
|
+
skillsDir: '.goose/skills',
|
|
224
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/goose/skills'),
|
|
225
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/goose'))
|
|
226
|
+
},
|
|
227
|
+
kilo: {
|
|
228
|
+
name: 'kilo',
|
|
229
|
+
displayName: 'Kilo Code',
|
|
230
|
+
skillsDir: '.kilocode/skills',
|
|
231
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.kilocode/skills'),
|
|
232
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.kilocode'))
|
|
233
|
+
},
|
|
234
|
+
'kiro-cli': {
|
|
235
|
+
name: 'kiro-cli',
|
|
236
|
+
displayName: 'Kiro CLI',
|
|
237
|
+
skillsDir: '.kiro/skills',
|
|
238
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.kiro/skills'),
|
|
239
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.kiro'))
|
|
240
|
+
},
|
|
241
|
+
opencode: {
|
|
242
|
+
name: 'opencode',
|
|
243
|
+
displayName: 'OpenCode',
|
|
244
|
+
skillsDir: '.opencode/skills',
|
|
245
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.config/opencode/skills'),
|
|
246
|
+
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'))
|
|
247
|
+
},
|
|
248
|
+
roo: {
|
|
249
|
+
name: 'roo',
|
|
250
|
+
displayName: 'Roo Code',
|
|
251
|
+
skillsDir: '.roo/skills',
|
|
252
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.roo/skills'),
|
|
253
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.roo'))
|
|
254
|
+
},
|
|
255
|
+
trae: {
|
|
256
|
+
name: 'trae',
|
|
257
|
+
displayName: 'Trae',
|
|
258
|
+
skillsDir: '.trae/skills',
|
|
259
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.trae/skills'),
|
|
260
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.trae'))
|
|
261
|
+
},
|
|
262
|
+
windsurf: {
|
|
263
|
+
name: 'windsurf',
|
|
264
|
+
displayName: 'Windsurf',
|
|
265
|
+
skillsDir: '.windsurf/skills',
|
|
266
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.codeium/windsurf/skills'),
|
|
267
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.codeium/windsurf'))
|
|
268
|
+
},
|
|
269
|
+
neovate: {
|
|
270
|
+
name: 'neovate',
|
|
271
|
+
displayName: 'Neovate',
|
|
272
|
+
skillsDir: '.neovate/skills',
|
|
273
|
+
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.neovate/skills'),
|
|
274
|
+
detectInstalled: async ()=>(0, external_node_fs_.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_node_path__.join)(agent_registry_home, '.neovate'))
|
|
274
275
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
logger.log(` Install directory: ${config.defaults?.installDir}`);
|
|
288
|
-
logger.newline();
|
|
289
|
-
logger.log('Next steps:');
|
|
290
|
-
logger.log(' reskill install <skill> Install a skill');
|
|
291
|
-
logger.log(' reskill list List installed skills');
|
|
292
|
-
});
|
|
276
|
+
};
|
|
277
|
+
async function detectInstalledAgents() {
|
|
278
|
+
const installed = [];
|
|
279
|
+
for (const [type, config] of Object.entries(agents))if (await config.detectInstalled()) installed.push(type);
|
|
280
|
+
return installed;
|
|
281
|
+
}
|
|
282
|
+
function getAgentConfig(type) {
|
|
283
|
+
return agents[type];
|
|
284
|
+
}
|
|
285
|
+
function isValidAgentType(type) {
|
|
286
|
+
return type in agents;
|
|
287
|
+
}
|
|
293
288
|
const execAsync = (0, __WEBPACK_EXTERNAL_MODULE_node_util__.promisify)(__WEBPACK_EXTERNAL_MODULE_node_child_process__.exec);
|
|
294
289
|
class GitCloneError extends Error {
|
|
295
290
|
repoUrl;
|
|
@@ -301,7 +296,7 @@ class GitCloneError extends Error {
|
|
|
301
296
|
if (isAuthError) {
|
|
302
297
|
message += '\n\nTip: For private repos, ensure git SSH keys or credentials are configured:';
|
|
303
298
|
message += '\n - SSH: Check ~/.ssh/id_rsa or ~/.ssh/id_ed25519';
|
|
304
|
-
message +=
|
|
299
|
+
message += "\n - HTTPS: Run 'git config --global credential.helper store'";
|
|
305
300
|
message += '\n - Or use a personal access token in the URL';
|
|
306
301
|
}
|
|
307
302
|
super(message);
|
|
@@ -460,182 +455,10 @@ function parseGitUrl(url) {
|
|
|
460
455
|
}
|
|
461
456
|
return null;
|
|
462
457
|
}
|
|
463
|
-
class
|
|
464
|
-
|
|
465
|
-
constructor(
|
|
466
|
-
this.
|
|
467
|
-
}
|
|
468
|
-
parseRef(ref) {
|
|
469
|
-
const raw = ref;
|
|
470
|
-
if (isGitUrl(ref)) return this.parseGitUrlRef(ref);
|
|
471
|
-
let remaining = ref;
|
|
472
|
-
let registry = this.defaultRegistry;
|
|
473
|
-
let version;
|
|
474
|
-
const registryMatch = remaining.match(/^([a-zA-Z0-9.-]+):(.+)$/);
|
|
475
|
-
if (registryMatch) {
|
|
476
|
-
registry = registryMatch[1];
|
|
477
|
-
remaining = registryMatch[2];
|
|
478
|
-
}
|
|
479
|
-
const atIndex = remaining.lastIndexOf('@');
|
|
480
|
-
if (atIndex > 0) {
|
|
481
|
-
version = remaining.slice(atIndex + 1);
|
|
482
|
-
remaining = remaining.slice(0, atIndex);
|
|
483
|
-
}
|
|
484
|
-
const parts = remaining.split('/');
|
|
485
|
-
if (parts.length < 2) throw new Error(`Invalid skill reference: ${ref}. Expected format: owner/repo[@version]`);
|
|
486
|
-
const owner = parts[0];
|
|
487
|
-
const repo = parts[1];
|
|
488
|
-
const subPath = parts.length > 2 ? parts.slice(2).join('/') : void 0;
|
|
489
|
-
return {
|
|
490
|
-
registry,
|
|
491
|
-
owner,
|
|
492
|
-
repo,
|
|
493
|
-
subPath,
|
|
494
|
-
version,
|
|
495
|
-
raw
|
|
496
|
-
};
|
|
497
|
-
}
|
|
498
|
-
parseGitUrlRef(ref) {
|
|
499
|
-
const raw = ref;
|
|
500
|
-
let gitUrl = ref;
|
|
501
|
-
let version;
|
|
502
|
-
let subPath;
|
|
503
|
-
const gitSuffixIndex = ref.indexOf('.git');
|
|
504
|
-
if (-1 !== gitSuffixIndex) {
|
|
505
|
-
const afterGit = ref.slice(gitSuffixIndex + 4);
|
|
506
|
-
if (afterGit) {
|
|
507
|
-
const atIndex = afterGit.lastIndexOf('@');
|
|
508
|
-
if (-1 !== atIndex) {
|
|
509
|
-
version = afterGit.slice(atIndex + 1);
|
|
510
|
-
const pathPart = afterGit.slice(0, atIndex);
|
|
511
|
-
if (pathPart.startsWith('/')) subPath = pathPart.slice(1);
|
|
512
|
-
} else if (afterGit.startsWith('/')) subPath = afterGit.slice(1);
|
|
513
|
-
gitUrl = ref.slice(0, gitSuffixIndex + 4);
|
|
514
|
-
}
|
|
515
|
-
} else {
|
|
516
|
-
const atIndex = ref.lastIndexOf('@');
|
|
517
|
-
if (atIndex > 4) {
|
|
518
|
-
version = ref.slice(atIndex + 1);
|
|
519
|
-
gitUrl = ref.slice(0, atIndex);
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
const parsed = parseGitUrl(gitUrl);
|
|
523
|
-
if (!parsed) throw new Error(`Invalid Git URL: ${ref}. Expected format: git@host:owner/repo.git or https://host/owner/repo.git`);
|
|
524
|
-
return {
|
|
525
|
-
registry: parsed.host,
|
|
526
|
-
owner: parsed.owner,
|
|
527
|
-
repo: parsed.repo,
|
|
528
|
-
subPath,
|
|
529
|
-
version,
|
|
530
|
-
raw,
|
|
531
|
-
gitUrl
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
|
-
parseVersion(versionSpec) {
|
|
535
|
-
if (!versionSpec) return {
|
|
536
|
-
type: 'branch',
|
|
537
|
-
value: 'main',
|
|
538
|
-
raw: ''
|
|
539
|
-
};
|
|
540
|
-
const raw = versionSpec;
|
|
541
|
-
if ('latest' === versionSpec) return {
|
|
542
|
-
type: 'latest',
|
|
543
|
-
value: 'latest',
|
|
544
|
-
raw
|
|
545
|
-
};
|
|
546
|
-
if (versionSpec.startsWith('branch:')) return {
|
|
547
|
-
type: 'branch',
|
|
548
|
-
value: versionSpec.slice(7),
|
|
549
|
-
raw
|
|
550
|
-
};
|
|
551
|
-
if (versionSpec.startsWith('commit:')) return {
|
|
552
|
-
type: 'commit',
|
|
553
|
-
value: versionSpec.slice(7),
|
|
554
|
-
raw
|
|
555
|
-
};
|
|
556
|
-
if (/^[\^~><]/.test(versionSpec)) return {
|
|
557
|
-
type: 'range',
|
|
558
|
-
value: versionSpec,
|
|
559
|
-
raw
|
|
560
|
-
};
|
|
561
|
-
return {
|
|
562
|
-
type: 'exact',
|
|
563
|
-
value: versionSpec,
|
|
564
|
-
raw
|
|
565
|
-
};
|
|
566
|
-
}
|
|
567
|
-
buildRepoUrl(parsed) {
|
|
568
|
-
if (parsed.gitUrl) return parsed.gitUrl;
|
|
569
|
-
return buildRepoUrl(parsed.registry, `${parsed.owner}/${parsed.repo}`);
|
|
570
|
-
}
|
|
571
|
-
async resolveVersion(repoUrl, versionSpec) {
|
|
572
|
-
switch(versionSpec.type){
|
|
573
|
-
case 'exact':
|
|
574
|
-
return {
|
|
575
|
-
ref: versionSpec.value
|
|
576
|
-
};
|
|
577
|
-
case 'latest':
|
|
578
|
-
{
|
|
579
|
-
const latestTag = await getLatestTag(repoUrl);
|
|
580
|
-
if (!latestTag) {
|
|
581
|
-
const defaultBranch = await getDefaultBranch(repoUrl);
|
|
582
|
-
return {
|
|
583
|
-
ref: defaultBranch
|
|
584
|
-
};
|
|
585
|
-
}
|
|
586
|
-
return {
|
|
587
|
-
ref: latestTag.name,
|
|
588
|
-
commit: latestTag.commit
|
|
589
|
-
};
|
|
590
|
-
}
|
|
591
|
-
case 'range':
|
|
592
|
-
{
|
|
593
|
-
const tags = await getRemoteTags(repoUrl);
|
|
594
|
-
const matchingTags = tags.filter((tag)=>{
|
|
595
|
-
const version = tag.name.replace(/^v/, '');
|
|
596
|
-
return __WEBPACK_EXTERNAL_MODULE_semver__.satisfies(version, versionSpec.value);
|
|
597
|
-
});
|
|
598
|
-
if (0 === matchingTags.length) throw new Error(`No version found matching ${versionSpec.raw} for ${repoUrl}`);
|
|
599
|
-
matchingTags.sort((a, b)=>{
|
|
600
|
-
const aVer = a.name.replace(/^v/, '');
|
|
601
|
-
const bVer = b.name.replace(/^v/, '');
|
|
602
|
-
return __WEBPACK_EXTERNAL_MODULE_semver__.compare(bVer, aVer);
|
|
603
|
-
});
|
|
604
|
-
return {
|
|
605
|
-
ref: matchingTags[0].name,
|
|
606
|
-
commit: matchingTags[0].commit
|
|
607
|
-
};
|
|
608
|
-
}
|
|
609
|
-
case 'branch':
|
|
610
|
-
return {
|
|
611
|
-
ref: versionSpec.value
|
|
612
|
-
};
|
|
613
|
-
case 'commit':
|
|
614
|
-
return {
|
|
615
|
-
ref: versionSpec.value,
|
|
616
|
-
commit: versionSpec.value
|
|
617
|
-
};
|
|
618
|
-
default:
|
|
619
|
-
throw new Error(`Unknown version type: ${versionSpec.type}`);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
async resolve(ref) {
|
|
623
|
-
const parsed = this.parseRef(ref);
|
|
624
|
-
const repoUrl = this.buildRepoUrl(parsed);
|
|
625
|
-
const versionSpec = this.parseVersion(parsed.version);
|
|
626
|
-
const resolved = await this.resolveVersion(repoUrl, versionSpec);
|
|
627
|
-
return {
|
|
628
|
-
parsed,
|
|
629
|
-
repoUrl,
|
|
630
|
-
ref: resolved.ref,
|
|
631
|
-
commit: resolved.commit
|
|
632
|
-
};
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
class CacheManager {
|
|
636
|
-
cacheDir;
|
|
637
|
-
constructor(cacheDir){
|
|
638
|
-
this.cacheDir = cacheDir || getCacheDir();
|
|
458
|
+
class CacheManager {
|
|
459
|
+
cacheDir;
|
|
460
|
+
constructor(cacheDir){
|
|
461
|
+
this.cacheDir = cacheDir || getCacheDir();
|
|
639
462
|
}
|
|
640
463
|
getCacheDir() {
|
|
641
464
|
return this.cacheDir;
|
|
@@ -743,238 +566,289 @@ class CacheManager {
|
|
|
743
566
|
};
|
|
744
567
|
}
|
|
745
568
|
}
|
|
746
|
-
const
|
|
747
|
-
|
|
569
|
+
const DEFAULT_SKILLS_JSON = {
|
|
570
|
+
skills: {},
|
|
571
|
+
defaults: {
|
|
572
|
+
registry: 'github',
|
|
573
|
+
installDir: '.skills'
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
const DEFAULT_REGISTRIES = {
|
|
577
|
+
github: 'https://github.com',
|
|
578
|
+
gitlab: 'https://gitlab.com'
|
|
579
|
+
};
|
|
580
|
+
class ConfigLoader {
|
|
748
581
|
projectRoot;
|
|
749
|
-
|
|
750
|
-
|
|
582
|
+
configPath;
|
|
583
|
+
config = null;
|
|
751
584
|
constructor(projectRoot){
|
|
752
585
|
this.projectRoot = projectRoot || process.cwd();
|
|
753
|
-
this.
|
|
586
|
+
this.configPath = getSkillsJsonPath(this.projectRoot);
|
|
754
587
|
}
|
|
755
|
-
|
|
756
|
-
return this.
|
|
588
|
+
getProjectRoot() {
|
|
589
|
+
return this.projectRoot;
|
|
590
|
+
}
|
|
591
|
+
getConfigPath() {
|
|
592
|
+
return this.configPath;
|
|
757
593
|
}
|
|
758
594
|
exists() {
|
|
759
|
-
return exists(this.
|
|
595
|
+
return exists(this.configPath);
|
|
760
596
|
}
|
|
761
597
|
load() {
|
|
762
|
-
if (this.
|
|
763
|
-
if (!this.exists()) {
|
|
764
|
-
this.lockData = {
|
|
765
|
-
lockfileVersion: LOCKFILE_VERSION,
|
|
766
|
-
skills: {}
|
|
767
|
-
};
|
|
768
|
-
return this.lockData;
|
|
769
|
-
}
|
|
598
|
+
if (this.config) return this.config;
|
|
599
|
+
if (!this.exists()) throw new Error(`skills.json not found in ${this.projectRoot}. Run 'reskill init' first.`);
|
|
770
600
|
try {
|
|
771
|
-
this.
|
|
772
|
-
return this.
|
|
601
|
+
this.config = readJson(this.configPath);
|
|
602
|
+
return this.config;
|
|
773
603
|
} catch (error) {
|
|
774
|
-
throw new Error(`Failed to parse skills.
|
|
604
|
+
throw new Error(`Failed to parse skills.json: ${error.message}`);
|
|
775
605
|
}
|
|
776
606
|
}
|
|
777
607
|
reload() {
|
|
778
|
-
this.
|
|
608
|
+
this.config = null;
|
|
779
609
|
return this.load();
|
|
780
610
|
}
|
|
781
|
-
save(
|
|
782
|
-
const toSave =
|
|
783
|
-
if (!toSave) throw new Error('No
|
|
784
|
-
writeJson(this.
|
|
785
|
-
this.
|
|
611
|
+
save(config) {
|
|
612
|
+
const toSave = config || this.config;
|
|
613
|
+
if (!toSave) throw new Error('No config to save');
|
|
614
|
+
writeJson(this.configPath, toSave);
|
|
615
|
+
this.config = toSave;
|
|
786
616
|
}
|
|
787
|
-
|
|
788
|
-
const
|
|
789
|
-
|
|
617
|
+
create(options) {
|
|
618
|
+
const config = {
|
|
619
|
+
...DEFAULT_SKILLS_JSON,
|
|
620
|
+
...options,
|
|
621
|
+
skills: options?.skills || {},
|
|
622
|
+
defaults: {
|
|
623
|
+
...DEFAULT_SKILLS_JSON.defaults,
|
|
624
|
+
...options?.defaults
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
this.save(config);
|
|
628
|
+
return config;
|
|
790
629
|
}
|
|
791
|
-
|
|
792
|
-
const
|
|
793
|
-
|
|
630
|
+
getDefaults() {
|
|
631
|
+
const config = this.config || (this.exists() ? this.load() : DEFAULT_SKILLS_JSON);
|
|
632
|
+
return {
|
|
633
|
+
registry: config.defaults?.registry || 'github',
|
|
634
|
+
installDir: config.defaults?.installDir || '.skills',
|
|
635
|
+
targetAgents: config.defaults?.targetAgents || [],
|
|
636
|
+
installMode: config.defaults?.installMode || 'symlink'
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
getRegistryUrl(registryName) {
|
|
640
|
+
const config = this.config || (this.exists() ? this.load() : DEFAULT_SKILLS_JSON);
|
|
641
|
+
if (config.registries?.[registryName]) return config.registries[registryName];
|
|
642
|
+
if (DEFAULT_REGISTRIES[registryName]) return DEFAULT_REGISTRIES[registryName];
|
|
643
|
+
return `https://${registryName}`;
|
|
644
|
+
}
|
|
645
|
+
getInstallDir() {
|
|
646
|
+
const defaults = this.getDefaults();
|
|
647
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.projectRoot, defaults.installDir);
|
|
648
|
+
}
|
|
649
|
+
addSkill(name, ref) {
|
|
650
|
+
if (!this.config) this.load();
|
|
651
|
+
if (this.config) this.config.skills[name] = ref;
|
|
794
652
|
this.save();
|
|
795
653
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
if (
|
|
799
|
-
delete
|
|
654
|
+
removeSkill(name) {
|
|
655
|
+
if (!this.config) this.load();
|
|
656
|
+
if (this.config?.skills[name]) {
|
|
657
|
+
delete this.config.skills[name];
|
|
800
658
|
this.save();
|
|
801
659
|
return true;
|
|
802
660
|
}
|
|
803
661
|
return false;
|
|
804
662
|
}
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
663
|
+
getSkills() {
|
|
664
|
+
if (!this.config) {
|
|
665
|
+
if (!this.exists()) return {};
|
|
666
|
+
this.load();
|
|
667
|
+
}
|
|
668
|
+
return {
|
|
669
|
+
...this.config?.skills
|
|
812
670
|
};
|
|
813
|
-
this.set(name, lockedSkill);
|
|
814
|
-
return lockedSkill;
|
|
815
671
|
}
|
|
816
|
-
|
|
817
|
-
const
|
|
672
|
+
hasSkill(name) {
|
|
673
|
+
const skills = this.getSkills();
|
|
674
|
+
return name in skills;
|
|
675
|
+
}
|
|
676
|
+
getSkillRef(name) {
|
|
677
|
+
const skills = this.getSkills();
|
|
678
|
+
return skills[name];
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
class GitResolver {
|
|
682
|
+
defaultRegistry;
|
|
683
|
+
constructor(defaultRegistry = 'github'){
|
|
684
|
+
this.defaultRegistry = defaultRegistry;
|
|
685
|
+
}
|
|
686
|
+
parseRef(ref) {
|
|
687
|
+
const raw = ref;
|
|
688
|
+
if (isGitUrl(ref)) return this.parseGitUrlRef(ref);
|
|
689
|
+
let remaining = ref;
|
|
690
|
+
let registry = this.defaultRegistry;
|
|
691
|
+
let version;
|
|
692
|
+
const registryMatch = remaining.match(/^([a-zA-Z0-9.-]+):(.+)$/);
|
|
693
|
+
if (registryMatch) {
|
|
694
|
+
registry = registryMatch[1];
|
|
695
|
+
remaining = registryMatch[2];
|
|
696
|
+
}
|
|
697
|
+
const atIndex = remaining.lastIndexOf('@');
|
|
698
|
+
if (atIndex > 0) {
|
|
699
|
+
version = remaining.slice(atIndex + 1);
|
|
700
|
+
remaining = remaining.slice(0, atIndex);
|
|
701
|
+
}
|
|
702
|
+
const parts = remaining.split('/');
|
|
703
|
+
if (parts.length < 2) throw new Error(`Invalid skill reference: ${ref}. Expected format: owner/repo[@version]`);
|
|
704
|
+
const owner = parts[0];
|
|
705
|
+
const repo = parts[1];
|
|
706
|
+
const subPath = parts.length > 2 ? parts.slice(2).join('/') : void 0;
|
|
818
707
|
return {
|
|
819
|
-
|
|
708
|
+
registry,
|
|
709
|
+
owner,
|
|
710
|
+
repo,
|
|
711
|
+
subPath,
|
|
712
|
+
version,
|
|
713
|
+
raw
|
|
820
714
|
};
|
|
821
715
|
}
|
|
822
|
-
|
|
823
|
-
const
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
const
|
|
828
|
-
if (
|
|
829
|
-
|
|
716
|
+
parseGitUrlRef(ref) {
|
|
717
|
+
const raw = ref;
|
|
718
|
+
let gitUrl = ref;
|
|
719
|
+
let version;
|
|
720
|
+
let subPath;
|
|
721
|
+
const gitSuffixIndex = ref.indexOf('.git');
|
|
722
|
+
if (-1 !== gitSuffixIndex) {
|
|
723
|
+
const afterGit = ref.slice(gitSuffixIndex + 4);
|
|
724
|
+
if (afterGit) {
|
|
725
|
+
const atIndex = afterGit.lastIndexOf('@');
|
|
726
|
+
if (-1 !== atIndex) {
|
|
727
|
+
version = afterGit.slice(atIndex + 1);
|
|
728
|
+
const pathPart = afterGit.slice(0, atIndex);
|
|
729
|
+
if (pathPart.startsWith('/')) subPath = pathPart.slice(1);
|
|
730
|
+
} else if (afterGit.startsWith('/')) subPath = afterGit.slice(1);
|
|
731
|
+
gitUrl = ref.slice(0, gitSuffixIndex + 4);
|
|
732
|
+
}
|
|
733
|
+
} else {
|
|
734
|
+
const atIndex = ref.lastIndexOf('@');
|
|
735
|
+
if (atIndex > 4) {
|
|
736
|
+
version = ref.slice(atIndex + 1);
|
|
737
|
+
gitUrl = ref.slice(0, atIndex);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
const parsed = parseGitUrl(gitUrl);
|
|
741
|
+
if (!parsed) throw new Error(`Invalid Git URL: ${ref}. Expected format: git@host:owner/repo.git or https://host/owner/repo.git`);
|
|
742
|
+
return {
|
|
743
|
+
registry: parsed.host,
|
|
744
|
+
owner: parsed.owner,
|
|
745
|
+
repo: parsed.repo,
|
|
746
|
+
subPath,
|
|
747
|
+
version,
|
|
748
|
+
raw,
|
|
749
|
+
gitUrl
|
|
750
|
+
};
|
|
830
751
|
}
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
752
|
+
parseVersion(versionSpec) {
|
|
753
|
+
if (!versionSpec) return {
|
|
754
|
+
type: 'branch',
|
|
755
|
+
value: 'main',
|
|
756
|
+
raw: ''
|
|
757
|
+
};
|
|
758
|
+
const raw = versionSpec;
|
|
759
|
+
if ('latest' === versionSpec) return {
|
|
760
|
+
type: 'latest',
|
|
761
|
+
value: 'latest',
|
|
762
|
+
raw
|
|
763
|
+
};
|
|
764
|
+
if (versionSpec.startsWith('branch:')) return {
|
|
765
|
+
type: 'branch',
|
|
766
|
+
value: versionSpec.slice(7),
|
|
767
|
+
raw
|
|
768
|
+
};
|
|
769
|
+
if (versionSpec.startsWith('commit:')) return {
|
|
770
|
+
type: 'commit',
|
|
771
|
+
value: versionSpec.slice(7),
|
|
772
|
+
raw
|
|
773
|
+
};
|
|
774
|
+
if (/^[\^~><]/.test(versionSpec)) return {
|
|
775
|
+
type: 'range',
|
|
776
|
+
value: versionSpec,
|
|
777
|
+
raw
|
|
778
|
+
};
|
|
779
|
+
return {
|
|
780
|
+
type: 'exact',
|
|
781
|
+
value: versionSpec,
|
|
782
|
+
raw
|
|
835
783
|
};
|
|
836
|
-
this.save();
|
|
837
784
|
}
|
|
838
|
-
|
|
839
|
-
if (
|
|
840
|
-
|
|
841
|
-
|
|
785
|
+
buildRepoUrl(parsed) {
|
|
786
|
+
if (parsed.gitUrl) return parsed.gitUrl;
|
|
787
|
+
return buildRepoUrl(parsed.registry, `${parsed.owner}/${parsed.repo}`);
|
|
788
|
+
}
|
|
789
|
+
async resolveVersion(repoUrl, versionSpec) {
|
|
790
|
+
switch(versionSpec.type){
|
|
791
|
+
case 'exact':
|
|
792
|
+
return {
|
|
793
|
+
ref: versionSpec.value
|
|
794
|
+
};
|
|
795
|
+
case 'latest':
|
|
796
|
+
{
|
|
797
|
+
const latestTag = await getLatestTag(repoUrl);
|
|
798
|
+
if (!latestTag) {
|
|
799
|
+
const defaultBranch = await getDefaultBranch(repoUrl);
|
|
800
|
+
return {
|
|
801
|
+
ref: defaultBranch
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
return {
|
|
805
|
+
ref: latestTag.name,
|
|
806
|
+
commit: latestTag.commit
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
case 'range':
|
|
810
|
+
{
|
|
811
|
+
const tags = await getRemoteTags(repoUrl);
|
|
812
|
+
const matchingTags = tags.filter((tag)=>{
|
|
813
|
+
const version = tag.name.replace(/^v/, '');
|
|
814
|
+
return __WEBPACK_EXTERNAL_MODULE_semver__.satisfies(version, versionSpec.value);
|
|
815
|
+
});
|
|
816
|
+
if (0 === matchingTags.length) throw new Error(`No version found matching ${versionSpec.raw} for ${repoUrl}`);
|
|
817
|
+
matchingTags.sort((a, b)=>{
|
|
818
|
+
const aVer = a.name.replace(/^v/, '');
|
|
819
|
+
const bVer = b.name.replace(/^v/, '');
|
|
820
|
+
return __WEBPACK_EXTERNAL_MODULE_semver__.compare(bVer, aVer);
|
|
821
|
+
});
|
|
822
|
+
return {
|
|
823
|
+
ref: matchingTags[0].name,
|
|
824
|
+
commit: matchingTags[0].commit
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
case 'branch':
|
|
828
|
+
return {
|
|
829
|
+
ref: versionSpec.value
|
|
830
|
+
};
|
|
831
|
+
case 'commit':
|
|
832
|
+
return {
|
|
833
|
+
ref: versionSpec.value,
|
|
834
|
+
commit: versionSpec.value
|
|
835
|
+
};
|
|
836
|
+
default:
|
|
837
|
+
throw new Error(`Unknown version type: ${versionSpec.type}`);
|
|
842
838
|
}
|
|
843
|
-
this.lockData = null;
|
|
844
839
|
}
|
|
845
|
-
|
|
846
|
-
const
|
|
847
|
-
const
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
name: 'antigravity',
|
|
857
|
-
displayName: 'Antigravity',
|
|
858
|
-
skillsDir: '.agent/skills',
|
|
859
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.gemini/antigravity/skills'),
|
|
860
|
-
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'))
|
|
861
|
-
},
|
|
862
|
-
'claude-code': {
|
|
863
|
-
name: 'claude-code',
|
|
864
|
-
displayName: 'Claude Code',
|
|
865
|
-
skillsDir: '.claude/skills',
|
|
866
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.claude/skills'),
|
|
867
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.claude'))
|
|
868
|
-
},
|
|
869
|
-
clawdbot: {
|
|
870
|
-
name: 'clawdbot',
|
|
871
|
-
displayName: 'Clawdbot',
|
|
872
|
-
skillsDir: 'skills',
|
|
873
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.clawdbot/skills'),
|
|
874
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.clawdbot'))
|
|
875
|
-
},
|
|
876
|
-
codex: {
|
|
877
|
-
name: 'codex',
|
|
878
|
-
displayName: 'Codex',
|
|
879
|
-
skillsDir: '.codex/skills',
|
|
880
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.codex/skills'),
|
|
881
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.codex'))
|
|
882
|
-
},
|
|
883
|
-
cursor: {
|
|
884
|
-
name: 'cursor',
|
|
885
|
-
displayName: 'Cursor',
|
|
886
|
-
skillsDir: '.cursor/skills',
|
|
887
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.cursor/skills'),
|
|
888
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.cursor'))
|
|
889
|
-
},
|
|
890
|
-
droid: {
|
|
891
|
-
name: 'droid',
|
|
892
|
-
displayName: 'Droid',
|
|
893
|
-
skillsDir: '.factory/skills',
|
|
894
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.factory/skills'),
|
|
895
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.factory/skills'))
|
|
896
|
-
},
|
|
897
|
-
'gemini-cli': {
|
|
898
|
-
name: 'gemini-cli',
|
|
899
|
-
displayName: 'Gemini CLI',
|
|
900
|
-
skillsDir: '.gemini/skills',
|
|
901
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.gemini/skills'),
|
|
902
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.gemini'))
|
|
903
|
-
},
|
|
904
|
-
'github-copilot': {
|
|
905
|
-
name: 'github-copilot',
|
|
906
|
-
displayName: 'GitHub Copilot',
|
|
907
|
-
skillsDir: '.github/skills',
|
|
908
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.copilot/skills'),
|
|
909
|
-
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'))
|
|
910
|
-
},
|
|
911
|
-
goose: {
|
|
912
|
-
name: 'goose',
|
|
913
|
-
displayName: 'Goose',
|
|
914
|
-
skillsDir: '.goose/skills',
|
|
915
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.config/goose/skills'),
|
|
916
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.config/goose'))
|
|
917
|
-
},
|
|
918
|
-
kilo: {
|
|
919
|
-
name: 'kilo',
|
|
920
|
-
displayName: 'Kilo Code',
|
|
921
|
-
skillsDir: '.kilocode/skills',
|
|
922
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.kilocode/skills'),
|
|
923
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.kilocode'))
|
|
924
|
-
},
|
|
925
|
-
'kiro-cli': {
|
|
926
|
-
name: 'kiro-cli',
|
|
927
|
-
displayName: 'Kiro CLI',
|
|
928
|
-
skillsDir: '.kiro/skills',
|
|
929
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.kiro/skills'),
|
|
930
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.kiro'))
|
|
931
|
-
},
|
|
932
|
-
opencode: {
|
|
933
|
-
name: 'opencode',
|
|
934
|
-
displayName: 'OpenCode',
|
|
935
|
-
skillsDir: '.opencode/skills',
|
|
936
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.config/opencode/skills'),
|
|
937
|
-
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'))
|
|
938
|
-
},
|
|
939
|
-
roo: {
|
|
940
|
-
name: 'roo',
|
|
941
|
-
displayName: 'Roo Code',
|
|
942
|
-
skillsDir: '.roo/skills',
|
|
943
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.roo/skills'),
|
|
944
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.roo'))
|
|
945
|
-
},
|
|
946
|
-
trae: {
|
|
947
|
-
name: 'trae',
|
|
948
|
-
displayName: 'Trae',
|
|
949
|
-
skillsDir: '.trae/skills',
|
|
950
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.trae/skills'),
|
|
951
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.trae'))
|
|
952
|
-
},
|
|
953
|
-
windsurf: {
|
|
954
|
-
name: 'windsurf',
|
|
955
|
-
displayName: 'Windsurf',
|
|
956
|
-
skillsDir: '.windsurf/skills',
|
|
957
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.codeium/windsurf/skills'),
|
|
958
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.codeium/windsurf'))
|
|
959
|
-
},
|
|
960
|
-
neovate: {
|
|
961
|
-
name: 'neovate',
|
|
962
|
-
displayName: 'Neovate',
|
|
963
|
-
skillsDir: '.neovate/skills',
|
|
964
|
-
globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.neovate/skills'),
|
|
965
|
-
detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.neovate'))
|
|
840
|
+
async resolve(ref) {
|
|
841
|
+
const parsed = this.parseRef(ref);
|
|
842
|
+
const repoUrl = this.buildRepoUrl(parsed);
|
|
843
|
+
const versionSpec = this.parseVersion(parsed.version);
|
|
844
|
+
const resolved = await this.resolveVersion(repoUrl, versionSpec);
|
|
845
|
+
return {
|
|
846
|
+
parsed,
|
|
847
|
+
repoUrl,
|
|
848
|
+
ref: resolved.ref,
|
|
849
|
+
commit: resolved.commit
|
|
850
|
+
};
|
|
966
851
|
}
|
|
967
|
-
};
|
|
968
|
-
async function detectInstalledAgents() {
|
|
969
|
-
const installed = [];
|
|
970
|
-
for (const [type, config] of Object.entries(agents))if (await config.detectInstalled()) installed.push(type);
|
|
971
|
-
return installed;
|
|
972
|
-
}
|
|
973
|
-
function getAgentConfig(type) {
|
|
974
|
-
return agents[type];
|
|
975
|
-
}
|
|
976
|
-
function isValidAgentType(type) {
|
|
977
|
-
return type in agents;
|
|
978
852
|
}
|
|
979
853
|
const installer_AGENTS_DIR = '.agents';
|
|
980
854
|
const installer_SKILLS_SUBDIR = 'skills';
|
|
@@ -992,7 +866,7 @@ function installer_isPathSafe(basePath, targetPath) {
|
|
|
992
866
|
return normalizedTarget.startsWith(normalizedBase + __WEBPACK_EXTERNAL_MODULE_node_path__.sep) || normalizedTarget === normalizedBase;
|
|
993
867
|
}
|
|
994
868
|
function installer_getCanonicalSkillsDir(isGlobal, cwd) {
|
|
995
|
-
const baseDir = isGlobal ? (0,
|
|
869
|
+
const baseDir = isGlobal ? (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)() : cwd || process.cwd();
|
|
996
870
|
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, installer_AGENTS_DIR, installer_SKILLS_SUBDIR);
|
|
997
871
|
}
|
|
998
872
|
function installer_ensureDir(dirPath) {
|
|
@@ -1046,7 +920,7 @@ async function installer_createSymlink(target, linkPath) {
|
|
|
1046
920
|
const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
|
|
1047
921
|
installer_ensureDir(linkDir);
|
|
1048
922
|
const relativePath = __WEBPACK_EXTERNAL_MODULE_node_path__.relative(linkDir, target);
|
|
1049
|
-
const symlinkType = 'win32' === (0,
|
|
923
|
+
const symlinkType = 'win32' === (0, __WEBPACK_EXTERNAL_MODULE_node_os__.platform)() ? 'junction' : void 0;
|
|
1050
924
|
external_node_fs_.symlinkSync(relativePath, linkPath, symlinkType);
|
|
1051
925
|
return true;
|
|
1052
926
|
} catch {
|
|
@@ -1135,38 +1009,138 @@ class Installer {
|
|
|
1135
1009
|
};
|
|
1136
1010
|
}
|
|
1137
1011
|
}
|
|
1138
|
-
async installToAgents(sourcePath, skillName, targetAgents, options = {}) {
|
|
1139
|
-
const results = new Map();
|
|
1140
|
-
for (const agent of targetAgents){
|
|
1141
|
-
const result = await this.installForAgent(sourcePath, skillName, agent, options);
|
|
1142
|
-
results.set(agent, result);
|
|
1012
|
+
async installToAgents(sourcePath, skillName, targetAgents, options = {}) {
|
|
1013
|
+
const results = new Map();
|
|
1014
|
+
for (const agent of targetAgents){
|
|
1015
|
+
const result = await this.installForAgent(sourcePath, skillName, agent, options);
|
|
1016
|
+
results.set(agent, result);
|
|
1017
|
+
}
|
|
1018
|
+
return results;
|
|
1019
|
+
}
|
|
1020
|
+
isInstalled(skillName, agentType) {
|
|
1021
|
+
const skillPath = this.getAgentSkillPath(skillName, agentType);
|
|
1022
|
+
return external_node_fs_.existsSync(skillPath);
|
|
1023
|
+
}
|
|
1024
|
+
uninstallFromAgent(skillName, agentType) {
|
|
1025
|
+
const skillPath = this.getAgentSkillPath(skillName, agentType);
|
|
1026
|
+
if (!external_node_fs_.existsSync(skillPath)) return false;
|
|
1027
|
+
installer_remove(skillPath);
|
|
1028
|
+
return true;
|
|
1029
|
+
}
|
|
1030
|
+
uninstallFromAgents(skillName, targetAgents) {
|
|
1031
|
+
const results = new Map();
|
|
1032
|
+
for (const agent of targetAgents)results.set(agent, this.uninstallFromAgent(skillName, agent));
|
|
1033
|
+
const canonicalPath = this.getCanonicalPath(skillName);
|
|
1034
|
+
if (external_node_fs_.existsSync(canonicalPath)) installer_remove(canonicalPath);
|
|
1035
|
+
return results;
|
|
1036
|
+
}
|
|
1037
|
+
listInstalledSkills(agentType) {
|
|
1038
|
+
const agent = getAgentConfig(agentType);
|
|
1039
|
+
const skillsDir = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
|
|
1040
|
+
if (!external_node_fs_.existsSync(skillsDir)) return [];
|
|
1041
|
+
return external_node_fs_.readdirSync(skillsDir, {
|
|
1042
|
+
withFileTypes: true
|
|
1043
|
+
}).filter((entry)=>entry.isDirectory() || entry.isSymbolicLink()).map((entry)=>entry.name);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
const LOCKFILE_VERSION = 1;
|
|
1047
|
+
class LockManager {
|
|
1048
|
+
projectRoot;
|
|
1049
|
+
lockPath;
|
|
1050
|
+
lockData = null;
|
|
1051
|
+
constructor(projectRoot){
|
|
1052
|
+
this.projectRoot = projectRoot || process.cwd();
|
|
1053
|
+
this.lockPath = getSkillsLockPath(this.projectRoot);
|
|
1054
|
+
}
|
|
1055
|
+
getLockPath() {
|
|
1056
|
+
return this.lockPath;
|
|
1057
|
+
}
|
|
1058
|
+
exists() {
|
|
1059
|
+
return exists(this.lockPath);
|
|
1060
|
+
}
|
|
1061
|
+
load() {
|
|
1062
|
+
if (this.lockData) return this.lockData;
|
|
1063
|
+
if (!this.exists()) {
|
|
1064
|
+
this.lockData = {
|
|
1065
|
+
lockfileVersion: LOCKFILE_VERSION,
|
|
1066
|
+
skills: {}
|
|
1067
|
+
};
|
|
1068
|
+
return this.lockData;
|
|
1069
|
+
}
|
|
1070
|
+
try {
|
|
1071
|
+
this.lockData = readJson(this.lockPath);
|
|
1072
|
+
return this.lockData;
|
|
1073
|
+
} catch (error) {
|
|
1074
|
+
throw new Error(`Failed to parse skills.lock: ${error.message}`);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
reload() {
|
|
1078
|
+
this.lockData = null;
|
|
1079
|
+
return this.load();
|
|
1080
|
+
}
|
|
1081
|
+
save(lockToSave) {
|
|
1082
|
+
const toSave = lockToSave || this.lockData;
|
|
1083
|
+
if (!toSave) throw new Error('No lock to save');
|
|
1084
|
+
writeJson(this.lockPath, toSave);
|
|
1085
|
+
this.lockData = toSave;
|
|
1086
|
+
}
|
|
1087
|
+
get(name) {
|
|
1088
|
+
const lock = this.load();
|
|
1089
|
+
return lock.skills[name];
|
|
1090
|
+
}
|
|
1091
|
+
set(name, skill) {
|
|
1092
|
+
const lock = this.load();
|
|
1093
|
+
lock.skills[name] = skill;
|
|
1094
|
+
this.save();
|
|
1095
|
+
}
|
|
1096
|
+
remove(name) {
|
|
1097
|
+
const lock = this.load();
|
|
1098
|
+
if (lock.skills[name]) {
|
|
1099
|
+
delete lock.skills[name];
|
|
1100
|
+
this.save();
|
|
1101
|
+
return true;
|
|
1143
1102
|
}
|
|
1144
|
-
return
|
|
1103
|
+
return false;
|
|
1145
1104
|
}
|
|
1146
|
-
|
|
1147
|
-
const
|
|
1148
|
-
|
|
1105
|
+
lockSkill(name, options) {
|
|
1106
|
+
const lockedSkill = {
|
|
1107
|
+
source: options.source,
|
|
1108
|
+
version: options.version,
|
|
1109
|
+
resolved: options.resolved,
|
|
1110
|
+
commit: options.commit,
|
|
1111
|
+
installedAt: new Date().toISOString()
|
|
1112
|
+
};
|
|
1113
|
+
this.set(name, lockedSkill);
|
|
1114
|
+
return lockedSkill;
|
|
1149
1115
|
}
|
|
1150
|
-
|
|
1151
|
-
const
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1116
|
+
getAll() {
|
|
1117
|
+
const lock = this.load();
|
|
1118
|
+
return {
|
|
1119
|
+
...lock.skills
|
|
1120
|
+
};
|
|
1155
1121
|
}
|
|
1156
|
-
|
|
1157
|
-
const
|
|
1158
|
-
|
|
1159
|
-
const canonicalPath = this.getCanonicalPath(skillName);
|
|
1160
|
-
if (external_node_fs_.existsSync(canonicalPath)) installer_remove(canonicalPath);
|
|
1161
|
-
return results;
|
|
1122
|
+
has(name) {
|
|
1123
|
+
const lock = this.load();
|
|
1124
|
+
return name in lock.skills;
|
|
1162
1125
|
}
|
|
1163
|
-
|
|
1164
|
-
const
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1126
|
+
isVersionMatch(name, version) {
|
|
1127
|
+
const locked = this.get(name);
|
|
1128
|
+
if (!locked) return false;
|
|
1129
|
+
return locked.version === version;
|
|
1130
|
+
}
|
|
1131
|
+
clear() {
|
|
1132
|
+
this.lockData = {
|
|
1133
|
+
lockfileVersion: LOCKFILE_VERSION,
|
|
1134
|
+
skills: {}
|
|
1135
|
+
};
|
|
1136
|
+
this.save();
|
|
1137
|
+
}
|
|
1138
|
+
delete() {
|
|
1139
|
+
if (this.exists()) {
|
|
1140
|
+
const fs = __webpack_require__("node:fs");
|
|
1141
|
+
fs.unlinkSync(this.lockPath);
|
|
1142
|
+
}
|
|
1143
|
+
this.lockData = null;
|
|
1170
1144
|
}
|
|
1171
1145
|
}
|
|
1172
1146
|
class SkillManager {
|
|
@@ -1195,8 +1169,17 @@ class SkillManager {
|
|
|
1195
1169
|
if (this.isGlobal) return getGlobalSkillsDir();
|
|
1196
1170
|
return this.config.getInstallDir();
|
|
1197
1171
|
}
|
|
1172
|
+
getCanonicalSkillsDir() {
|
|
1173
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
1174
|
+
const baseDir = this.isGlobal ? home : this.projectRoot;
|
|
1175
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, '.agents', 'skills');
|
|
1176
|
+
}
|
|
1198
1177
|
getSkillPath(name) {
|
|
1199
|
-
|
|
1178
|
+
const canonicalPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getCanonicalSkillsDir(), name);
|
|
1179
|
+
if (exists(canonicalPath)) return canonicalPath;
|
|
1180
|
+
const legacyPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getInstallDir(), name);
|
|
1181
|
+
if (exists(legacyPath)) return legacyPath;
|
|
1182
|
+
return canonicalPath;
|
|
1200
1183
|
}
|
|
1201
1184
|
async install(ref, options = {}) {
|
|
1202
1185
|
const { force = false, save = true } = options;
|
|
@@ -1209,11 +1192,13 @@ class SkillManager {
|
|
|
1209
1192
|
const locked = this.lockManager.get(skillName);
|
|
1210
1193
|
if (locked && locked.version === version) {
|
|
1211
1194
|
logger.info(`${skillName}@${version} is already installed`);
|
|
1212
|
-
|
|
1195
|
+
const installed = this.getInstalledSkill(skillName);
|
|
1196
|
+
if (installed) return installed;
|
|
1213
1197
|
}
|
|
1214
1198
|
if (!force) {
|
|
1215
1199
|
logger.warn(`${skillName} is already installed. Use --force to reinstall.`);
|
|
1216
|
-
|
|
1200
|
+
const installed = this.getInstalledSkill(skillName);
|
|
1201
|
+
if (installed) return installed;
|
|
1217
1202
|
}
|
|
1218
1203
|
}
|
|
1219
1204
|
logger["package"](`Installing ${skillName}@${version}...`);
|
|
@@ -1227,7 +1212,7 @@ class SkillManager {
|
|
|
1227
1212
|
if (exists(skillPath)) remove(skillPath);
|
|
1228
1213
|
await this.cache.copyTo(parsed, version, skillPath);
|
|
1229
1214
|
if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
|
|
1230
|
-
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ?
|
|
1215
|
+
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
|
|
1231
1216
|
version,
|
|
1232
1217
|
resolved: repoUrl,
|
|
1233
1218
|
commit: cacheResult.commit
|
|
@@ -1235,7 +1220,9 @@ class SkillManager {
|
|
|
1235
1220
|
if (!this.isGlobal && save && this.config.exists()) this.config.addSkill(skillName, ref);
|
|
1236
1221
|
const locationHint = this.isGlobal ? '(global)' : '';
|
|
1237
1222
|
logger.success(`Installed ${skillName}@${version} to ${skillPath} ${locationHint}`.trim());
|
|
1238
|
-
|
|
1223
|
+
const installed = this.getInstalledSkill(skillName);
|
|
1224
|
+
if (!installed) throw new Error(`Failed to get installed skill info for ${skillName}`);
|
|
1225
|
+
return installed;
|
|
1239
1226
|
}
|
|
1240
1227
|
async installAll(options = {}) {
|
|
1241
1228
|
const skills = this.config.getSkills();
|
|
@@ -1302,7 +1289,7 @@ class SkillManager {
|
|
|
1302
1289
|
skillName = name || skillJson.name || skillName;
|
|
1303
1290
|
} catch {}
|
|
1304
1291
|
const linkPath = this.getSkillPath(skillName);
|
|
1305
|
-
ensureDir(
|
|
1292
|
+
ensureDir(__WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath));
|
|
1306
1293
|
createSymlink(absolutePath, linkPath);
|
|
1307
1294
|
logger.success(`Linked ${skillName} → ${absolutePath}`);
|
|
1308
1295
|
return {
|
|
@@ -1328,20 +1315,36 @@ class SkillManager {
|
|
|
1328
1315
|
return true;
|
|
1329
1316
|
}
|
|
1330
1317
|
list() {
|
|
1331
|
-
const installDir = this.getInstallDir();
|
|
1332
|
-
if (!exists(installDir)) return [];
|
|
1333
1318
|
const skills = [];
|
|
1334
|
-
const
|
|
1335
|
-
|
|
1336
|
-
|
|
1319
|
+
const seenNames = new Set();
|
|
1320
|
+
const canonicalDir = this.getCanonicalSkillsDir();
|
|
1321
|
+
if (exists(canonicalDir)) for (const name of listDir(canonicalDir)){
|
|
1322
|
+
const skillPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalDir, name);
|
|
1337
1323
|
if (!isDirectory(skillPath)) continue;
|
|
1338
|
-
const skill = this.
|
|
1339
|
-
if (skill)
|
|
1324
|
+
const skill = this.getInstalledSkillFromPath(name, skillPath);
|
|
1325
|
+
if (skill) {
|
|
1326
|
+
skills.push(skill);
|
|
1327
|
+
seenNames.add(name);
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
const legacyDir = this.getInstallDir();
|
|
1331
|
+
if (exists(legacyDir) && legacyDir !== canonicalDir) for (const name of listDir(legacyDir)){
|
|
1332
|
+
if (seenNames.has(name)) continue;
|
|
1333
|
+
const skillPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(legacyDir, name);
|
|
1334
|
+
if (!isDirectory(skillPath)) continue;
|
|
1335
|
+
if (isSymlink(skillPath)) try {
|
|
1336
|
+
const realPath = getRealPath(skillPath);
|
|
1337
|
+
if (realPath.includes(__WEBPACK_EXTERNAL_MODULE_node_path__.join('.agents', 'skills'))) continue;
|
|
1338
|
+
} catch {}
|
|
1339
|
+
const skill = this.getInstalledSkillFromPath(name, skillPath);
|
|
1340
|
+
if (skill) {
|
|
1341
|
+
skills.push(skill);
|
|
1342
|
+
seenNames.add(name);
|
|
1343
|
+
}
|
|
1340
1344
|
}
|
|
1341
1345
|
return skills;
|
|
1342
1346
|
}
|
|
1343
|
-
|
|
1344
|
-
const skillPath = this.getSkillPath(name);
|
|
1347
|
+
getInstalledSkillFromPath(name, skillPath) {
|
|
1345
1348
|
if (!exists(skillPath)) return null;
|
|
1346
1349
|
const isLinked = isSymlink(skillPath);
|
|
1347
1350
|
const locked = this.lockManager.get(name);
|
|
@@ -1359,6 +1362,13 @@ class SkillManager {
|
|
|
1359
1362
|
isLinked
|
|
1360
1363
|
};
|
|
1361
1364
|
}
|
|
1365
|
+
getInstalledSkill(name) {
|
|
1366
|
+
const canonicalPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getCanonicalSkillsDir(), name);
|
|
1367
|
+
if (exists(canonicalPath)) return this.getInstalledSkillFromPath(name, canonicalPath);
|
|
1368
|
+
const legacyPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.getInstallDir(), name);
|
|
1369
|
+
if (exists(legacyPath)) return this.getInstalledSkillFromPath(name, legacyPath);
|
|
1370
|
+
return null;
|
|
1371
|
+
}
|
|
1362
1372
|
getInfo(name) {
|
|
1363
1373
|
return {
|
|
1364
1374
|
installed: this.getInstalledSkill(name),
|
|
@@ -1420,7 +1430,7 @@ class SkillManager {
|
|
|
1420
1430
|
mode: mode
|
|
1421
1431
|
});
|
|
1422
1432
|
if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
|
|
1423
|
-
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ?
|
|
1433
|
+
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
|
|
1424
1434
|
version,
|
|
1425
1435
|
resolved: repoUrl,
|
|
1426
1436
|
commit: cacheResult.commit
|
|
@@ -1434,7 +1444,7 @@ class SkillManager {
|
|
|
1434
1444
|
name: skillName,
|
|
1435
1445
|
path: sourcePath,
|
|
1436
1446
|
version,
|
|
1437
|
-
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ?
|
|
1447
|
+
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`
|
|
1438
1448
|
};
|
|
1439
1449
|
return {
|
|
1440
1450
|
skill,
|
|
@@ -1477,6 +1487,69 @@ class SkillManager {
|
|
|
1477
1487
|
return results;
|
|
1478
1488
|
}
|
|
1479
1489
|
}
|
|
1490
|
+
const infoCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('info').description('Show skill details').argument('<skill>', 'Skill name').option('-j, --json', 'Output as JSON').action((skillName, options)=>{
|
|
1491
|
+
const skillManager = new SkillManager();
|
|
1492
|
+
const info = skillManager.getInfo(skillName);
|
|
1493
|
+
if (options.json) {
|
|
1494
|
+
console.log(JSON.stringify(info, null, 2));
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1497
|
+
if (!info.installed && !info.config) {
|
|
1498
|
+
logger.error(`Skill ${skillName} not found`);
|
|
1499
|
+
process.exit(1);
|
|
1500
|
+
}
|
|
1501
|
+
logger.log(`Skill: ${skillName}`);
|
|
1502
|
+
logger.newline();
|
|
1503
|
+
if (info.config) {
|
|
1504
|
+
logger.log("Configuration (skills.json):");
|
|
1505
|
+
logger.log(` Reference: ${info.config}`);
|
|
1506
|
+
}
|
|
1507
|
+
if (info.locked) {
|
|
1508
|
+
logger.log("Locked Version (skills.lock):");
|
|
1509
|
+
logger.log(` Version: ${info.locked.version}`);
|
|
1510
|
+
logger.log(` Source: ${info.locked.source}`);
|
|
1511
|
+
logger.log(` Commit: ${info.locked.commit}`);
|
|
1512
|
+
logger.log(` Installed: ${info.locked.installedAt}`);
|
|
1513
|
+
}
|
|
1514
|
+
if (info.installed) {
|
|
1515
|
+
logger.log("Installed:");
|
|
1516
|
+
logger.log(` Path: ${info.installed.path}`);
|
|
1517
|
+
logger.log(` Version: ${info.installed.version}`);
|
|
1518
|
+
logger.log(` Linked: ${info.installed.isLinked ? 'Yes' : 'No'}`);
|
|
1519
|
+
if (info.installed.metadata) {
|
|
1520
|
+
const meta = info.installed.metadata;
|
|
1521
|
+
logger.log("Metadata (skill.json):");
|
|
1522
|
+
if (meta.description) logger.log(` Description: ${meta.description}`);
|
|
1523
|
+
if (meta.author) logger.log(` Author: ${meta.author}`);
|
|
1524
|
+
if (meta.license) logger.log(` License: ${meta.license}`);
|
|
1525
|
+
if (meta.keywords?.length) logger.log(` Keywords: ${meta.keywords.join(', ')}`);
|
|
1526
|
+
}
|
|
1527
|
+
} else logger.warn(`Skill ${skillName} is not installed`);
|
|
1528
|
+
});
|
|
1529
|
+
const initCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('init').description('Initialize a new skills.json configuration').option('-n, --name <name>', 'Project name').option('-r, --registry <registry>', 'Default registry', 'github').option('-d, --install-dir <dir>', 'Skills installation directory', '.skills').option('-y, --yes', 'Skip prompts and use defaults').action(async (options)=>{
|
|
1530
|
+
const configLoader = new ConfigLoader();
|
|
1531
|
+
if (configLoader.exists()) {
|
|
1532
|
+
logger.warn('skills.json already exists');
|
|
1533
|
+
return;
|
|
1534
|
+
}
|
|
1535
|
+
const config = configLoader.create({
|
|
1536
|
+
name: options.name,
|
|
1537
|
+
defaults: {
|
|
1538
|
+
registry: options.registry,
|
|
1539
|
+
installDir: options.installDir
|
|
1540
|
+
}
|
|
1541
|
+
});
|
|
1542
|
+
logger.success('Created skills.json');
|
|
1543
|
+
logger.newline();
|
|
1544
|
+
logger.log('Configuration:');
|
|
1545
|
+
logger.log(` Name: ${config.name || '(not set)'}`);
|
|
1546
|
+
logger.log(` Default registry: ${config.defaults?.registry}`);
|
|
1547
|
+
logger.log(` Install directory: ${config.defaults?.installDir}`);
|
|
1548
|
+
logger.newline();
|
|
1549
|
+
logger.log('Next steps:');
|
|
1550
|
+
logger.log(' reskill install <skill> Install a skill');
|
|
1551
|
+
logger.log(' reskill list List installed skills');
|
|
1552
|
+
});
|
|
1480
1553
|
function formatAgentNames(agentTypes, maxShow = 5) {
|
|
1481
1554
|
const names = agentTypes.map((a)=>agents[a].displayName);
|
|
1482
1555
|
if (names.length <= maxShow) return names.join(', ');
|
|
@@ -1721,6 +1794,23 @@ const installCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('instal
|
|
|
1721
1794
|
process.exit(1);
|
|
1722
1795
|
}
|
|
1723
1796
|
});
|
|
1797
|
+
const linkCmd = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('link').description('Link a local skill for development').argument('<path>', 'Path to local skill directory').option('-n, --name <name>', 'Custom skill name').action((localPath, options)=>{
|
|
1798
|
+
const skillManager = new SkillManager();
|
|
1799
|
+
try {
|
|
1800
|
+
const linked = skillManager.link(localPath, options.name);
|
|
1801
|
+
logger.log(`Linked skill available at: ${linked.path}`);
|
|
1802
|
+
} catch (error) {
|
|
1803
|
+
logger.error(error.message);
|
|
1804
|
+
process.exit(1);
|
|
1805
|
+
}
|
|
1806
|
+
});
|
|
1807
|
+
const unlinkCmd = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('unlink').description('Unlink a linked skill').argument('<skill>', 'Skill name to unlink').action((skillName)=>{
|
|
1808
|
+
const skillManager = new SkillManager();
|
|
1809
|
+
const result = skillManager.unlink(skillName);
|
|
1810
|
+
if (!result) process.exit(1);
|
|
1811
|
+
});
|
|
1812
|
+
const linkCommand = linkCmd;
|
|
1813
|
+
const unlinkCommand = unlinkCmd;
|
|
1724
1814
|
const listCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('list').alias('ls').description('List installed skills').option('-j, --json', 'Output as JSON').option('-g, --global', 'List globally installed skills').action((options)=>{
|
|
1725
1815
|
const isGlobal = options.global || false;
|
|
1726
1816
|
const skillManager = new SkillManager(void 0, {
|
|
@@ -1753,68 +1843,6 @@ const listCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('list').al
|
|
|
1753
1843
|
logger.newline();
|
|
1754
1844
|
logger.log(`Total: ${skills.length} skill(s)`);
|
|
1755
1845
|
});
|
|
1756
|
-
const infoCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('info').description('Show skill details').argument('<skill>', 'Skill name').option('-j, --json', 'Output as JSON').action((skillName, options)=>{
|
|
1757
|
-
const skillManager = new SkillManager();
|
|
1758
|
-
const info = skillManager.getInfo(skillName);
|
|
1759
|
-
if (options.json) {
|
|
1760
|
-
console.log(JSON.stringify(info, null, 2));
|
|
1761
|
-
return;
|
|
1762
|
-
}
|
|
1763
|
-
if (!info.installed && !info.config) {
|
|
1764
|
-
logger.error(`Skill ${skillName} not found`);
|
|
1765
|
-
process.exit(1);
|
|
1766
|
-
}
|
|
1767
|
-
logger.log(`Skill: ${skillName}`);
|
|
1768
|
-
logger.newline();
|
|
1769
|
-
if (info.config) {
|
|
1770
|
-
logger.log("Configuration (skills.json):");
|
|
1771
|
-
logger.log(` Reference: ${info.config}`);
|
|
1772
|
-
}
|
|
1773
|
-
if (info.locked) {
|
|
1774
|
-
logger.log("Locked Version (skills.lock):");
|
|
1775
|
-
logger.log(` Version: ${info.locked.version}`);
|
|
1776
|
-
logger.log(` Source: ${info.locked.source}`);
|
|
1777
|
-
logger.log(` Commit: ${info.locked.commit}`);
|
|
1778
|
-
logger.log(` Installed: ${info.locked.installedAt}`);
|
|
1779
|
-
}
|
|
1780
|
-
if (info.installed) {
|
|
1781
|
-
logger.log("Installed:");
|
|
1782
|
-
logger.log(` Path: ${info.installed.path}`);
|
|
1783
|
-
logger.log(` Version: ${info.installed.version}`);
|
|
1784
|
-
logger.log(` Linked: ${info.installed.isLinked ? 'Yes' : 'No'}`);
|
|
1785
|
-
if (info.installed.metadata) {
|
|
1786
|
-
const meta = info.installed.metadata;
|
|
1787
|
-
logger.log("Metadata (skill.json):");
|
|
1788
|
-
if (meta.description) logger.log(` Description: ${meta.description}`);
|
|
1789
|
-
if (meta.author) logger.log(` Author: ${meta.author}`);
|
|
1790
|
-
if (meta.license) logger.log(` License: ${meta.license}`);
|
|
1791
|
-
if (meta.keywords?.length) logger.log(` Keywords: ${meta.keywords.join(', ')}`);
|
|
1792
|
-
}
|
|
1793
|
-
} else logger.warn(`Skill ${skillName} is not installed`);
|
|
1794
|
-
});
|
|
1795
|
-
const updateCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('update').alias('up').description('Update installed skills').argument('[skill]', 'Skill name to update (updates all if not specified)').action(async (skill)=>{
|
|
1796
|
-
const configLoader = new ConfigLoader();
|
|
1797
|
-
if (!configLoader.exists()) {
|
|
1798
|
-
logger.error("skills.json not found. Run 'reskill init' first.");
|
|
1799
|
-
process.exit(1);
|
|
1800
|
-
}
|
|
1801
|
-
const skillManager = new SkillManager();
|
|
1802
|
-
const spinner = (0, __WEBPACK_EXTERNAL_MODULE_ora__["default"])(skill ? `Updating ${skill}...` : 'Updating all skills...').start();
|
|
1803
|
-
try {
|
|
1804
|
-
const updated = await skillManager.update(skill);
|
|
1805
|
-
spinner.stop();
|
|
1806
|
-
if (0 === updated.length) {
|
|
1807
|
-
logger.info('No skills to update');
|
|
1808
|
-
return;
|
|
1809
|
-
}
|
|
1810
|
-
logger.success(`Updated ${updated.length} skill(s):`);
|
|
1811
|
-
for (const s of updated)logger.log(` - ${s.name}@${s.version}`);
|
|
1812
|
-
} catch (error) {
|
|
1813
|
-
spinner.fail('Update failed');
|
|
1814
|
-
logger.error(error.message);
|
|
1815
|
-
process.exit(1);
|
|
1816
|
-
}
|
|
1817
|
-
});
|
|
1818
1846
|
const outdatedCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('outdated').description('Check for outdated skills').option('-j, --json', 'Output as JSON').action(async (options)=>{
|
|
1819
1847
|
const configLoader = new ConfigLoader();
|
|
1820
1848
|
if (!configLoader.exists()) {
|
|
@@ -1874,23 +1902,29 @@ const uninstallCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('unin
|
|
|
1874
1902
|
const result = skillManager.uninstall(skillName);
|
|
1875
1903
|
if (!result) process.exit(1);
|
|
1876
1904
|
});
|
|
1877
|
-
const
|
|
1905
|
+
const updateCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('update').alias('up').description('Update installed skills').argument('[skill]', 'Skill name to update (updates all if not specified)').action(async (skill)=>{
|
|
1906
|
+
const configLoader = new ConfigLoader();
|
|
1907
|
+
if (!configLoader.exists()) {
|
|
1908
|
+
logger.error("skills.json not found. Run 'reskill init' first.");
|
|
1909
|
+
process.exit(1);
|
|
1910
|
+
}
|
|
1878
1911
|
const skillManager = new SkillManager();
|
|
1912
|
+
const spinner = (0, __WEBPACK_EXTERNAL_MODULE_ora__["default"])(skill ? `Updating ${skill}...` : 'Updating all skills...').start();
|
|
1879
1913
|
try {
|
|
1880
|
-
const
|
|
1881
|
-
|
|
1914
|
+
const updated = await skillManager.update(skill);
|
|
1915
|
+
spinner.stop();
|
|
1916
|
+
if (0 === updated.length) {
|
|
1917
|
+
logger.info('No skills to update');
|
|
1918
|
+
return;
|
|
1919
|
+
}
|
|
1920
|
+
logger.success(`Updated ${updated.length} skill(s):`);
|
|
1921
|
+
for (const s of updated)logger.log(` - ${s.name}@${s.version}`);
|
|
1882
1922
|
} catch (error) {
|
|
1923
|
+
spinner.fail('Update failed');
|
|
1883
1924
|
logger.error(error.message);
|
|
1884
1925
|
process.exit(1);
|
|
1885
1926
|
}
|
|
1886
1927
|
});
|
|
1887
|
-
const unlinkCmd = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('unlink').description('Unlink a linked skill').argument('<skill>', 'Skill name to unlink').action((skillName)=>{
|
|
1888
|
-
const skillManager = new SkillManager();
|
|
1889
|
-
const result = skillManager.unlink(skillName);
|
|
1890
|
-
if (!result) process.exit(1);
|
|
1891
|
-
});
|
|
1892
|
-
const linkCommand = linkCmd;
|
|
1893
|
-
const unlinkCommand = unlinkCmd;
|
|
1894
1928
|
const program = new __WEBPACK_EXTERNAL_MODULE_commander__.Command();
|
|
1895
1929
|
program.name('reskill').description('AI Skills Package Manager - Git-based skills management for AI agents').version('0.1.0');
|
|
1896
1930
|
program.addCommand(initCommand);
|