reskill 0.1.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/README.md +161 -104
- package/README.zh-CN.md +257 -0
- 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 +12 -4
- 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 +999 -353
- package/dist/core/agent-registry.d.ts +54 -0
- package/dist/core/agent-registry.d.ts.map +1 -0
- package/dist/core/cache-manager.d.ts +20 -16
- 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 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/installer.d.ts +96 -0
- package/dist/core/installer.d.ts.map +1 -0
- 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 +83 -24
- package/dist/core/skill-manager.d.ts.map +1 -1
- package/dist/core/skill-parser.d.ts +116 -0
- package/dist/core/skill-parser.d.ts.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +951 -323
- package/dist/types/index.d.ts +96 -74
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/fs.d.ts +30 -0
- package/dist/utils/fs.d.ts.map +1 -1
- package/package.json +29 -13
package/dist/cli/index.js
CHANGED
|
@@ -3,10 +3,12 @@ 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";
|
|
9
|
+
import * as __WEBPACK_EXTERNAL_MODULE_semver__ from "semver";
|
|
10
|
+
import * as __WEBPACK_EXTERNAL_MODULE__clack_prompts__ from "@clack/prompts";
|
|
11
|
+
import * as __WEBPACK_EXTERNAL_MODULE_ora__ from "ora";
|
|
10
12
|
var __webpack_modules__ = {
|
|
11
13
|
"node:fs": function(module) {
|
|
12
14
|
module.exports = __WEBPACK_EXTERNAL_MODULE_node_fs__;
|
|
@@ -35,7 +37,7 @@ function writeJson(filePath, data, indent = 2) {
|
|
|
35
37
|
if (!exists(dir)) external_node_fs_.mkdirSync(dir, {
|
|
36
38
|
recursive: true
|
|
37
39
|
});
|
|
38
|
-
external_node_fs_.writeFileSync(filePath, JSON.stringify(data, null, indent)
|
|
40
|
+
external_node_fs_.writeFileSync(filePath, `${JSON.stringify(data, null, indent)}\n`, 'utf-8');
|
|
39
41
|
}
|
|
40
42
|
function ensureDir(dirPath) {
|
|
41
43
|
if (!exists(dirPath)) external_node_fs_.mkdirSync(dirPath, {
|
|
@@ -102,115 +104,12 @@ function getGlobalSkillsDir() {
|
|
|
102
104
|
const home = getHomeDir();
|
|
103
105
|
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.claude', 'skills');
|
|
104
106
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
};
|
|
112
|
-
const DEFAULT_REGISTRIES = {
|
|
113
|
-
github: 'https://github.com',
|
|
114
|
-
gitlab: 'https://gitlab.com'
|
|
115
|
-
};
|
|
116
|
-
class ConfigLoader {
|
|
117
|
-
projectRoot;
|
|
118
|
-
configPath;
|
|
119
|
-
config = null;
|
|
120
|
-
constructor(projectRoot){
|
|
121
|
-
this.projectRoot = projectRoot || process.cwd();
|
|
122
|
-
this.configPath = getSkillsJsonPath(this.projectRoot);
|
|
123
|
-
}
|
|
124
|
-
getProjectRoot() {
|
|
125
|
-
return this.projectRoot;
|
|
126
|
-
}
|
|
127
|
-
getConfigPath() {
|
|
128
|
-
return this.configPath;
|
|
129
|
-
}
|
|
130
|
-
exists() {
|
|
131
|
-
return exists(this.configPath);
|
|
132
|
-
}
|
|
133
|
-
load() {
|
|
134
|
-
if (this.config) return this.config;
|
|
135
|
-
if (!this.exists()) throw new Error(`skills.json not found in ${this.projectRoot}. Run 'reskill init' first.`);
|
|
136
|
-
try {
|
|
137
|
-
this.config = readJson(this.configPath);
|
|
138
|
-
return this.config;
|
|
139
|
-
} catch (error) {
|
|
140
|
-
throw new Error(`Failed to parse skills.json: ${error.message}`);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
reload() {
|
|
144
|
-
this.config = null;
|
|
145
|
-
return this.load();
|
|
146
|
-
}
|
|
147
|
-
save(config) {
|
|
148
|
-
const toSave = config || this.config;
|
|
149
|
-
if (!toSave) throw new Error('No config to save');
|
|
150
|
-
writeJson(this.configPath, toSave);
|
|
151
|
-
this.config = toSave;
|
|
152
|
-
}
|
|
153
|
-
create(options) {
|
|
154
|
-
const config = {
|
|
155
|
-
...DEFAULT_SKILLS_JSON,
|
|
156
|
-
...options,
|
|
157
|
-
skills: options?.skills || {},
|
|
158
|
-
defaults: {
|
|
159
|
-
...DEFAULT_SKILLS_JSON.defaults,
|
|
160
|
-
...options?.defaults
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
this.save(config);
|
|
164
|
-
return config;
|
|
165
|
-
}
|
|
166
|
-
getDefaults() {
|
|
167
|
-
const config = this.config || (this.exists() ? this.load() : DEFAULT_SKILLS_JSON);
|
|
168
|
-
return {
|
|
169
|
-
registry: config.defaults?.registry || DEFAULT_SKILLS_JSON.defaults.registry,
|
|
170
|
-
installDir: config.defaults?.installDir || DEFAULT_SKILLS_JSON.defaults.installDir
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
getRegistryUrl(registryName) {
|
|
174
|
-
const config = this.config || (this.exists() ? this.load() : DEFAULT_SKILLS_JSON);
|
|
175
|
-
if (config.registries?.[registryName]) return config.registries[registryName];
|
|
176
|
-
if (DEFAULT_REGISTRIES[registryName]) return DEFAULT_REGISTRIES[registryName];
|
|
177
|
-
return `https://${registryName}`;
|
|
178
|
-
}
|
|
179
|
-
getInstallDir() {
|
|
180
|
-
const defaults = this.getDefaults();
|
|
181
|
-
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.projectRoot, defaults.installDir);
|
|
182
|
-
}
|
|
183
|
-
addSkill(name, ref) {
|
|
184
|
-
if (!this.config) this.load();
|
|
185
|
-
this.config.skills[name] = ref;
|
|
186
|
-
this.save();
|
|
187
|
-
}
|
|
188
|
-
removeSkill(name) {
|
|
189
|
-
if (!this.config) this.load();
|
|
190
|
-
if (this.config.skills[name]) {
|
|
191
|
-
delete this.config.skills[name];
|
|
192
|
-
this.save();
|
|
193
|
-
return true;
|
|
194
|
-
}
|
|
195
|
-
return false;
|
|
196
|
-
}
|
|
197
|
-
getSkills() {
|
|
198
|
-
if (!this.config) {
|
|
199
|
-
if (!this.exists()) return {};
|
|
200
|
-
this.load();
|
|
201
|
-
}
|
|
202
|
-
return {
|
|
203
|
-
...this.config.skills
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
hasSkill(name) {
|
|
207
|
-
const skills = this.getSkills();
|
|
208
|
-
return name in skills;
|
|
209
|
-
}
|
|
210
|
-
getSkillRef(name) {
|
|
211
|
-
const skills = this.getSkills();
|
|
212
|
-
return skills[name];
|
|
213
|
-
}
|
|
107
|
+
function shortenPath(fullPath, cwd) {
|
|
108
|
+
const home = getHomeDir();
|
|
109
|
+
const currentDir = cwd || process.cwd();
|
|
110
|
+
if (fullPath.startsWith(home)) return fullPath.replace(home, '~');
|
|
111
|
+
if (fullPath.startsWith(currentDir)) return `.${fullPath.slice(currentDir.length)}`;
|
|
112
|
+
return fullPath;
|
|
214
113
|
}
|
|
215
114
|
const logger = {
|
|
216
115
|
info (message) {
|
|
@@ -253,30 +152,139 @@ const logger = {
|
|
|
253
152
|
}
|
|
254
153
|
}
|
|
255
154
|
};
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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'))
|
|
261
275
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
logger.log(` Install directory: ${config.defaults?.installDir}`);
|
|
275
|
-
logger.newline();
|
|
276
|
-
logger.log('Next steps:');
|
|
277
|
-
logger.log(' reskill install <skill> Install a skill');
|
|
278
|
-
logger.log(' reskill list List installed skills');
|
|
279
|
-
});
|
|
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
|
+
}
|
|
280
288
|
const execAsync = (0, __WEBPACK_EXTERNAL_MODULE_node_util__.promisify)(__WEBPACK_EXTERNAL_MODULE_node_child_process__.exec);
|
|
281
289
|
class GitCloneError extends Error {
|
|
282
290
|
repoUrl;
|
|
@@ -288,7 +296,7 @@ class GitCloneError extends Error {
|
|
|
288
296
|
if (isAuthError) {
|
|
289
297
|
message += '\n\nTip: For private repos, ensure git SSH keys or credentials are configured:';
|
|
290
298
|
message += '\n - SSH: Check ~/.ssh/id_rsa or ~/.ssh/id_ed25519';
|
|
291
|
-
message +=
|
|
299
|
+
message += "\n - HTTPS: Run 'git config --global credential.helper store'";
|
|
292
300
|
message += '\n - Or use a personal access token in the URL';
|
|
293
301
|
}
|
|
294
302
|
super(message);
|
|
@@ -447,6 +455,229 @@ function parseGitUrl(url) {
|
|
|
447
455
|
}
|
|
448
456
|
return null;
|
|
449
457
|
}
|
|
458
|
+
class CacheManager {
|
|
459
|
+
cacheDir;
|
|
460
|
+
constructor(cacheDir){
|
|
461
|
+
this.cacheDir = cacheDir || getCacheDir();
|
|
462
|
+
}
|
|
463
|
+
getCacheDir() {
|
|
464
|
+
return this.cacheDir;
|
|
465
|
+
}
|
|
466
|
+
getSkillCachePath(parsed, version) {
|
|
467
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, parsed.registry, parsed.owner, parsed.repo, version);
|
|
468
|
+
}
|
|
469
|
+
getCachePath(parsed, version) {
|
|
470
|
+
return this.getSkillCachePath(parsed, version);
|
|
471
|
+
}
|
|
472
|
+
isCached(parsed, version) {
|
|
473
|
+
const cachePath = this.getSkillCachePath(parsed, version);
|
|
474
|
+
return exists(cachePath) && isDirectory(cachePath);
|
|
475
|
+
}
|
|
476
|
+
async get(parsed, version) {
|
|
477
|
+
const cachePath = this.getSkillCachePath(parsed, version);
|
|
478
|
+
if (!this.isCached(parsed, version)) return null;
|
|
479
|
+
const commitFile = __WEBPACK_EXTERNAL_MODULE_node_path__.join(cachePath, '.reskill-commit');
|
|
480
|
+
let commit = '';
|
|
481
|
+
try {
|
|
482
|
+
const fs = await import("node:fs");
|
|
483
|
+
if (exists(commitFile)) commit = fs.readFileSync(commitFile, 'utf-8').trim();
|
|
484
|
+
} catch {}
|
|
485
|
+
return {
|
|
486
|
+
path: cachePath,
|
|
487
|
+
commit
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
async cache(repoUrl, parsed, ref, version) {
|
|
491
|
+
const cachePath = this.getSkillCachePath(parsed, version);
|
|
492
|
+
if (exists(cachePath)) remove(cachePath);
|
|
493
|
+
ensureDir(__WEBPACK_EXTERNAL_MODULE_node_path__.dirname(cachePath));
|
|
494
|
+
const tempPath = `${cachePath}.tmp`;
|
|
495
|
+
remove(tempPath);
|
|
496
|
+
await clone(repoUrl, tempPath, {
|
|
497
|
+
depth: 1,
|
|
498
|
+
branch: ref
|
|
499
|
+
});
|
|
500
|
+
const commit = await getCurrentCommit(tempPath);
|
|
501
|
+
if (parsed.subPath) {
|
|
502
|
+
const subDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(tempPath, parsed.subPath);
|
|
503
|
+
if (!exists(subDir)) {
|
|
504
|
+
remove(tempPath);
|
|
505
|
+
throw new Error(`Subpath ${parsed.subPath} not found in repository`);
|
|
506
|
+
}
|
|
507
|
+
copyDir(subDir, cachePath, {
|
|
508
|
+
exclude: [
|
|
509
|
+
'.git'
|
|
510
|
+
]
|
|
511
|
+
});
|
|
512
|
+
} else copyDir(tempPath, cachePath, {
|
|
513
|
+
exclude: [
|
|
514
|
+
'.git'
|
|
515
|
+
]
|
|
516
|
+
});
|
|
517
|
+
const fs = await import("node:fs");
|
|
518
|
+
fs.writeFileSync(__WEBPACK_EXTERNAL_MODULE_node_path__.join(cachePath, '.reskill-commit'), commit);
|
|
519
|
+
remove(tempPath);
|
|
520
|
+
return {
|
|
521
|
+
path: cachePath,
|
|
522
|
+
commit
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
async copyTo(parsed, version, destPath) {
|
|
526
|
+
const cached = await this.get(parsed, version);
|
|
527
|
+
if (!cached) throw new Error(`Skill ${parsed.raw} version ${version} not found in cache`);
|
|
528
|
+
if (exists(destPath)) remove(destPath);
|
|
529
|
+
copyDir(cached.path, destPath, {
|
|
530
|
+
exclude: [
|
|
531
|
+
'.reskill-commit'
|
|
532
|
+
]
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
clearSkill(parsed, version) {
|
|
536
|
+
if (version) {
|
|
537
|
+
const cachePath = this.getSkillCachePath(parsed, version);
|
|
538
|
+
remove(cachePath);
|
|
539
|
+
} else {
|
|
540
|
+
const skillDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, parsed.registry, parsed.owner, parsed.repo);
|
|
541
|
+
remove(skillDir);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
clearAll() {
|
|
545
|
+
remove(this.cacheDir);
|
|
546
|
+
}
|
|
547
|
+
getStats() {
|
|
548
|
+
if (!exists(this.cacheDir)) return {
|
|
549
|
+
totalSkills: 0,
|
|
550
|
+
registries: []
|
|
551
|
+
};
|
|
552
|
+
const registries = listDir(this.cacheDir).filter((name)=>isDirectory(__WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, name)));
|
|
553
|
+
let totalSkills = 0;
|
|
554
|
+
for (const registry of registries){
|
|
555
|
+
const registryPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, registry);
|
|
556
|
+
const owners = listDir(registryPath).filter((name)=>isDirectory(__WEBPACK_EXTERNAL_MODULE_node_path__.join(registryPath, name)));
|
|
557
|
+
for (const owner of owners){
|
|
558
|
+
const ownerPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(registryPath, owner);
|
|
559
|
+
const repos = listDir(ownerPath).filter((name)=>isDirectory(__WEBPACK_EXTERNAL_MODULE_node_path__.join(ownerPath, name)));
|
|
560
|
+
totalSkills += repos.length;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
return {
|
|
564
|
+
totalSkills,
|
|
565
|
+
registries
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
}
|
|
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 {
|
|
581
|
+
projectRoot;
|
|
582
|
+
configPath;
|
|
583
|
+
config = null;
|
|
584
|
+
constructor(projectRoot){
|
|
585
|
+
this.projectRoot = projectRoot || process.cwd();
|
|
586
|
+
this.configPath = getSkillsJsonPath(this.projectRoot);
|
|
587
|
+
}
|
|
588
|
+
getProjectRoot() {
|
|
589
|
+
return this.projectRoot;
|
|
590
|
+
}
|
|
591
|
+
getConfigPath() {
|
|
592
|
+
return this.configPath;
|
|
593
|
+
}
|
|
594
|
+
exists() {
|
|
595
|
+
return exists(this.configPath);
|
|
596
|
+
}
|
|
597
|
+
load() {
|
|
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.`);
|
|
600
|
+
try {
|
|
601
|
+
this.config = readJson(this.configPath);
|
|
602
|
+
return this.config;
|
|
603
|
+
} catch (error) {
|
|
604
|
+
throw new Error(`Failed to parse skills.json: ${error.message}`);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
reload() {
|
|
608
|
+
this.config = null;
|
|
609
|
+
return this.load();
|
|
610
|
+
}
|
|
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;
|
|
616
|
+
}
|
|
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;
|
|
629
|
+
}
|
|
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;
|
|
652
|
+
this.save();
|
|
653
|
+
}
|
|
654
|
+
removeSkill(name) {
|
|
655
|
+
if (!this.config) this.load();
|
|
656
|
+
if (this.config?.skills[name]) {
|
|
657
|
+
delete this.config.skills[name];
|
|
658
|
+
this.save();
|
|
659
|
+
return true;
|
|
660
|
+
}
|
|
661
|
+
return false;
|
|
662
|
+
}
|
|
663
|
+
getSkills() {
|
|
664
|
+
if (!this.config) {
|
|
665
|
+
if (!this.exists()) return {};
|
|
666
|
+
this.load();
|
|
667
|
+
}
|
|
668
|
+
return {
|
|
669
|
+
...this.config?.skills
|
|
670
|
+
};
|
|
671
|
+
}
|
|
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
|
+
}
|
|
450
681
|
class GitResolver {
|
|
451
682
|
defaultRegistry;
|
|
452
683
|
constructor(defaultRegistry = 'github'){
|
|
@@ -619,112 +850,197 @@ class GitResolver {
|
|
|
619
850
|
};
|
|
620
851
|
}
|
|
621
852
|
}
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
853
|
+
const installer_AGENTS_DIR = '.agents';
|
|
854
|
+
const installer_SKILLS_SUBDIR = 'skills';
|
|
855
|
+
function installer_sanitizeName(name) {
|
|
856
|
+
let sanitized = name.replace(/[/\\:\0]/g, '');
|
|
857
|
+
sanitized = sanitized.replace(/^[.\s]+|[.\s]+$/g, '');
|
|
858
|
+
sanitized = sanitized.replace(/^\.+/, '');
|
|
859
|
+
if (!sanitized || 0 === sanitized.length) sanitized = 'unnamed-skill';
|
|
860
|
+
if (sanitized.length > 255) sanitized = sanitized.substring(0, 255);
|
|
861
|
+
return sanitized;
|
|
862
|
+
}
|
|
863
|
+
function installer_isPathSafe(basePath, targetPath) {
|
|
864
|
+
const normalizedBase = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(basePath));
|
|
865
|
+
const normalizedTarget = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(targetPath));
|
|
866
|
+
return normalizedTarget.startsWith(normalizedBase + __WEBPACK_EXTERNAL_MODULE_node_path__.sep) || normalizedTarget === normalizedBase;
|
|
867
|
+
}
|
|
868
|
+
function installer_getCanonicalSkillsDir(isGlobal, cwd) {
|
|
869
|
+
const baseDir = isGlobal ? (0, __WEBPACK_EXTERNAL_MODULE_node_os__.homedir)() : cwd || process.cwd();
|
|
870
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, installer_AGENTS_DIR, installer_SKILLS_SUBDIR);
|
|
871
|
+
}
|
|
872
|
+
function installer_ensureDir(dirPath) {
|
|
873
|
+
if (!external_node_fs_.existsSync(dirPath)) external_node_fs_.mkdirSync(dirPath, {
|
|
874
|
+
recursive: true
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
function installer_remove(targetPath) {
|
|
878
|
+
if (external_node_fs_.existsSync(targetPath)) external_node_fs_.rmSync(targetPath, {
|
|
879
|
+
recursive: true,
|
|
880
|
+
force: true
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
function copyDirectory(src, dest, options) {
|
|
884
|
+
const exclude = new Set(options?.exclude || [
|
|
885
|
+
'README.md',
|
|
886
|
+
'metadata.json'
|
|
887
|
+
]);
|
|
888
|
+
installer_ensureDir(dest);
|
|
889
|
+
const entries = external_node_fs_.readdirSync(src, {
|
|
890
|
+
withFileTypes: true
|
|
891
|
+
});
|
|
892
|
+
for (const entry of entries){
|
|
893
|
+
if (exclude.has(entry.name) || entry.name.startsWith('_')) continue;
|
|
894
|
+
const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
|
|
895
|
+
const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
|
|
896
|
+
if (entry.isDirectory()) copyDirectory(srcPath, destPath, options);
|
|
897
|
+
else external_node_fs_.copyFileSync(srcPath, destPath);
|
|
636
898
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
const commitFile = __WEBPACK_EXTERNAL_MODULE_node_path__.join(cachePath, '.reskill-commit');
|
|
641
|
-
let commit = '';
|
|
899
|
+
}
|
|
900
|
+
async function installer_createSymlink(target, linkPath) {
|
|
901
|
+
try {
|
|
642
902
|
try {
|
|
643
|
-
const
|
|
644
|
-
if (
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
}
|
|
651
|
-
async cache(repoUrl, parsed, ref, version) {
|
|
652
|
-
const cachePath = this.getSkillCachePath(parsed, version);
|
|
653
|
-
if (exists(cachePath)) remove(cachePath);
|
|
654
|
-
ensureDir(__WEBPACK_EXTERNAL_MODULE_node_path__.dirname(cachePath));
|
|
655
|
-
const tempPath = `${cachePath}.tmp`;
|
|
656
|
-
remove(tempPath);
|
|
657
|
-
await clone(repoUrl, tempPath, {
|
|
658
|
-
depth: 1,
|
|
659
|
-
branch: ref
|
|
660
|
-
});
|
|
661
|
-
const commit = await getCurrentCommit(tempPath);
|
|
662
|
-
if (parsed.subPath) {
|
|
663
|
-
const subDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(tempPath, parsed.subPath);
|
|
664
|
-
if (!exists(subDir)) {
|
|
665
|
-
remove(tempPath);
|
|
666
|
-
throw new Error(`Subpath ${parsed.subPath} not found in repository`);
|
|
667
|
-
}
|
|
668
|
-
copyDir(subDir, cachePath, {
|
|
669
|
-
exclude: [
|
|
670
|
-
'.git'
|
|
671
|
-
]
|
|
903
|
+
const stats = external_node_fs_.lstatSync(linkPath);
|
|
904
|
+
if (stats.isSymbolicLink()) {
|
|
905
|
+
const existingTarget = external_node_fs_.readlinkSync(linkPath);
|
|
906
|
+
if (__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(existingTarget) === __WEBPACK_EXTERNAL_MODULE_node_path__.resolve(target)) return true;
|
|
907
|
+
external_node_fs_.rmSync(linkPath);
|
|
908
|
+
} else external_node_fs_.rmSync(linkPath, {
|
|
909
|
+
recursive: true
|
|
672
910
|
});
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
'.
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
return {
|
|
682
|
-
path: cachePath,
|
|
683
|
-
commit
|
|
684
|
-
};
|
|
685
|
-
}
|
|
686
|
-
async copyTo(parsed, version, destPath) {
|
|
687
|
-
const cached = await this.get(parsed, version);
|
|
688
|
-
if (!cached) throw new Error(`Skill ${parsed.raw} version ${version} not found in cache`);
|
|
689
|
-
if (exists(destPath)) remove(destPath);
|
|
690
|
-
copyDir(cached.path, destPath, {
|
|
691
|
-
exclude: [
|
|
692
|
-
'.reskill-commit'
|
|
693
|
-
]
|
|
694
|
-
});
|
|
695
|
-
}
|
|
696
|
-
clearSkill(parsed, version) {
|
|
697
|
-
if (version) {
|
|
698
|
-
const cachePath = this.getSkillCachePath(parsed, version);
|
|
699
|
-
remove(cachePath);
|
|
700
|
-
} else {
|
|
701
|
-
const skillDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, parsed.registry, parsed.owner, parsed.repo);
|
|
702
|
-
remove(skillDir);
|
|
911
|
+
} catch (err) {
|
|
912
|
+
if (err && 'object' == typeof err && 'code' in err) {
|
|
913
|
+
if ('ELOOP' === err.code) try {
|
|
914
|
+
external_node_fs_.rmSync(linkPath, {
|
|
915
|
+
force: true
|
|
916
|
+
});
|
|
917
|
+
} catch {}
|
|
918
|
+
}
|
|
703
919
|
}
|
|
920
|
+
const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
|
|
921
|
+
installer_ensureDir(linkDir);
|
|
922
|
+
const relativePath = __WEBPACK_EXTERNAL_MODULE_node_path__.relative(linkDir, target);
|
|
923
|
+
const symlinkType = 'win32' === (0, __WEBPACK_EXTERNAL_MODULE_node_os__.platform)() ? 'junction' : void 0;
|
|
924
|
+
external_node_fs_.symlinkSync(relativePath, linkPath, symlinkType);
|
|
925
|
+
return true;
|
|
926
|
+
} catch {
|
|
927
|
+
return false;
|
|
704
928
|
}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
929
|
+
}
|
|
930
|
+
class Installer {
|
|
931
|
+
cwd;
|
|
932
|
+
isGlobal;
|
|
933
|
+
constructor(options = {}){
|
|
934
|
+
this.cwd = options.cwd || process.cwd();
|
|
935
|
+
this.isGlobal = options.global || false;
|
|
936
|
+
}
|
|
937
|
+
getCanonicalPath(skillName) {
|
|
938
|
+
const sanitized = installer_sanitizeName(skillName);
|
|
939
|
+
const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
|
|
940
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
|
|
941
|
+
}
|
|
942
|
+
getAgentSkillPath(skillName, agentType) {
|
|
943
|
+
const agent = getAgentConfig(agentType);
|
|
944
|
+
const sanitized = installer_sanitizeName(skillName);
|
|
945
|
+
const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
|
|
946
|
+
return __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
|
|
947
|
+
}
|
|
948
|
+
async installForAgent(sourcePath, skillName, agentType, options = {}) {
|
|
949
|
+
const agent = getAgentConfig(agentType);
|
|
950
|
+
const installMode = options.mode || 'symlink';
|
|
951
|
+
const sanitized = installer_sanitizeName(skillName);
|
|
952
|
+
const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
|
|
953
|
+
const canonicalDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
|
|
954
|
+
const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
|
|
955
|
+
const agentDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
|
|
956
|
+
if (!installer_isPathSafe(canonicalBase, canonicalDir)) return {
|
|
957
|
+
success: false,
|
|
958
|
+
path: agentDir,
|
|
959
|
+
mode: installMode,
|
|
960
|
+
error: 'Invalid skill name: potential path traversal detected'
|
|
712
961
|
};
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
962
|
+
if (!installer_isPathSafe(agentBase, agentDir)) return {
|
|
963
|
+
success: false,
|
|
964
|
+
path: agentDir,
|
|
965
|
+
mode: installMode,
|
|
966
|
+
error: 'Invalid skill name: potential path traversal detected'
|
|
967
|
+
};
|
|
968
|
+
try {
|
|
969
|
+
if ('copy' === installMode) {
|
|
970
|
+
installer_ensureDir(agentDir);
|
|
971
|
+
installer_remove(agentDir);
|
|
972
|
+
copyDirectory(sourcePath, agentDir);
|
|
973
|
+
return {
|
|
974
|
+
success: true,
|
|
975
|
+
path: agentDir,
|
|
976
|
+
mode: 'copy'
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
installer_ensureDir(canonicalDir);
|
|
980
|
+
installer_remove(canonicalDir);
|
|
981
|
+
copyDirectory(sourcePath, canonicalDir);
|
|
982
|
+
const symlinkCreated = await installer_createSymlink(canonicalDir, agentDir);
|
|
983
|
+
if (!symlinkCreated) {
|
|
984
|
+
try {
|
|
985
|
+
installer_remove(agentDir);
|
|
986
|
+
} catch {}
|
|
987
|
+
installer_ensureDir(agentDir);
|
|
988
|
+
copyDirectory(sourcePath, agentDir);
|
|
989
|
+
return {
|
|
990
|
+
success: true,
|
|
991
|
+
path: agentDir,
|
|
992
|
+
canonicalPath: canonicalDir,
|
|
993
|
+
mode: 'symlink',
|
|
994
|
+
symlinkFailed: true
|
|
995
|
+
};
|
|
722
996
|
}
|
|
997
|
+
return {
|
|
998
|
+
success: true,
|
|
999
|
+
path: agentDir,
|
|
1000
|
+
canonicalPath: canonicalDir,
|
|
1001
|
+
mode: 'symlink'
|
|
1002
|
+
};
|
|
1003
|
+
} catch (error) {
|
|
1004
|
+
return {
|
|
1005
|
+
success: false,
|
|
1006
|
+
path: agentDir,
|
|
1007
|
+
mode: installMode,
|
|
1008
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
1009
|
+
};
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
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);
|
|
723
1017
|
}
|
|
724
|
-
return
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
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);
|
|
728
1044
|
}
|
|
729
1045
|
}
|
|
730
1046
|
const LOCKFILE_VERSION = 1;
|
|
@@ -853,8 +1169,17 @@ class SkillManager {
|
|
|
853
1169
|
if (this.isGlobal) return getGlobalSkillsDir();
|
|
854
1170
|
return this.config.getInstallDir();
|
|
855
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
|
+
}
|
|
856
1177
|
getSkillPath(name) {
|
|
857
|
-
|
|
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;
|
|
858
1183
|
}
|
|
859
1184
|
async install(ref, options = {}) {
|
|
860
1185
|
const { force = false, save = true } = options;
|
|
@@ -867,11 +1192,13 @@ class SkillManager {
|
|
|
867
1192
|
const locked = this.lockManager.get(skillName);
|
|
868
1193
|
if (locked && locked.version === version) {
|
|
869
1194
|
logger.info(`${skillName}@${version} is already installed`);
|
|
870
|
-
|
|
1195
|
+
const installed = this.getInstalledSkill(skillName);
|
|
1196
|
+
if (installed) return installed;
|
|
871
1197
|
}
|
|
872
1198
|
if (!force) {
|
|
873
1199
|
logger.warn(`${skillName} is already installed. Use --force to reinstall.`);
|
|
874
|
-
|
|
1200
|
+
const installed = this.getInstalledSkill(skillName);
|
|
1201
|
+
if (installed) return installed;
|
|
875
1202
|
}
|
|
876
1203
|
}
|
|
877
1204
|
logger["package"](`Installing ${skillName}@${version}...`);
|
|
@@ -885,7 +1212,7 @@ class SkillManager {
|
|
|
885
1212
|
if (exists(skillPath)) remove(skillPath);
|
|
886
1213
|
await this.cache.copyTo(parsed, version, skillPath);
|
|
887
1214
|
if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
|
|
888
|
-
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ?
|
|
1215
|
+
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
|
|
889
1216
|
version,
|
|
890
1217
|
resolved: repoUrl,
|
|
891
1218
|
commit: cacheResult.commit
|
|
@@ -893,7 +1220,9 @@ class SkillManager {
|
|
|
893
1220
|
if (!this.isGlobal && save && this.config.exists()) this.config.addSkill(skillName, ref);
|
|
894
1221
|
const locationHint = this.isGlobal ? '(global)' : '';
|
|
895
1222
|
logger.success(`Installed ${skillName}@${version} to ${skillPath} ${locationHint}`.trim());
|
|
896
|
-
|
|
1223
|
+
const installed = this.getInstalledSkill(skillName);
|
|
1224
|
+
if (!installed) throw new Error(`Failed to get installed skill info for ${skillName}`);
|
|
1225
|
+
return installed;
|
|
897
1226
|
}
|
|
898
1227
|
async installAll(options = {}) {
|
|
899
1228
|
const skills = this.config.getSkills();
|
|
@@ -960,7 +1289,7 @@ class SkillManager {
|
|
|
960
1289
|
skillName = name || skillJson.name || skillName;
|
|
961
1290
|
} catch {}
|
|
962
1291
|
const linkPath = this.getSkillPath(skillName);
|
|
963
|
-
ensureDir(
|
|
1292
|
+
ensureDir(__WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath));
|
|
964
1293
|
createSymlink(absolutePath, linkPath);
|
|
965
1294
|
logger.success(`Linked ${skillName} → ${absolutePath}`);
|
|
966
1295
|
return {
|
|
@@ -986,20 +1315,36 @@ class SkillManager {
|
|
|
986
1315
|
return true;
|
|
987
1316
|
}
|
|
988
1317
|
list() {
|
|
989
|
-
const installDir = this.getInstallDir();
|
|
990
|
-
if (!exists(installDir)) return [];
|
|
991
1318
|
const skills = [];
|
|
992
|
-
const
|
|
993
|
-
|
|
994
|
-
|
|
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);
|
|
1323
|
+
if (!isDirectory(skillPath)) continue;
|
|
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);
|
|
995
1334
|
if (!isDirectory(skillPath)) continue;
|
|
996
|
-
|
|
997
|
-
|
|
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
|
+
}
|
|
998
1344
|
}
|
|
999
1345
|
return skills;
|
|
1000
1346
|
}
|
|
1001
|
-
|
|
1002
|
-
const skillPath = this.getSkillPath(name);
|
|
1347
|
+
getInstalledSkillFromPath(name, skillPath) {
|
|
1003
1348
|
if (!exists(skillPath)) return null;
|
|
1004
1349
|
const isLinked = isSymlink(skillPath);
|
|
1005
1350
|
const locked = this.lockManager.get(name);
|
|
@@ -1017,6 +1362,13 @@ class SkillManager {
|
|
|
1017
1362
|
isLinked
|
|
1018
1363
|
};
|
|
1019
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
|
+
}
|
|
1020
1372
|
getInfo(name) {
|
|
1021
1373
|
return {
|
|
1022
1374
|
installed: this.getInstalledSkill(name),
|
|
@@ -1056,91 +1408,85 @@ class SkillManager {
|
|
|
1056
1408
|
}
|
|
1057
1409
|
return results;
|
|
1058
1410
|
}
|
|
1059
|
-
}
|
|
1060
|
-
const
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
force: options.force,
|
|
1072
|
-
save: options.save && !isGlobal,
|
|
1073
|
-
global: isGlobal
|
|
1074
|
-
});
|
|
1075
|
-
const location = isGlobal ? __WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(' (global)') : '';
|
|
1076
|
-
spinner.succeed(`Installed ${installed.name}@${installed.version}${location}`);
|
|
1077
|
-
} catch (error) {
|
|
1078
|
-
spinner.fail('Installation failed');
|
|
1079
|
-
logger.error(error.message);
|
|
1080
|
-
process.exit(1);
|
|
1081
|
-
}
|
|
1082
|
-
} else {
|
|
1083
|
-
if (isGlobal) {
|
|
1084
|
-
logger.error('Cannot install all skills globally. Please specify a skill to install.');
|
|
1085
|
-
process.exit(1);
|
|
1086
|
-
}
|
|
1087
|
-
if (!configLoader.exists()) {
|
|
1088
|
-
logger.error("skills.json not found. Run 'reskill init' first.");
|
|
1089
|
-
process.exit(1);
|
|
1090
|
-
}
|
|
1091
|
-
const skills = configLoader.getSkills();
|
|
1092
|
-
if (0 === Object.keys(skills).length) {
|
|
1093
|
-
logger.info('No skills defined in skills.json');
|
|
1094
|
-
return;
|
|
1095
|
-
}
|
|
1096
|
-
logger["package"]('Installing all skills from skills.json...');
|
|
1097
|
-
const spinner = (0, __WEBPACK_EXTERNAL_MODULE_ora__["default"])('Installing...').start();
|
|
1098
|
-
try {
|
|
1099
|
-
const installed = await skillManager.installAll({
|
|
1100
|
-
force: options.force
|
|
1101
|
-
});
|
|
1102
|
-
spinner.stop();
|
|
1103
|
-
logger.newline();
|
|
1104
|
-
logger.success(`Installed ${installed.length} skill(s)`);
|
|
1105
|
-
} catch (error) {
|
|
1106
|
-
spinner.fail('Installation failed');
|
|
1107
|
-
logger.error(error.message);
|
|
1108
|
-
process.exit(1);
|
|
1411
|
+
async installToAgents(ref, targetAgents, options = {}) {
|
|
1412
|
+
const { save = true, mode = 'symlink' } = options;
|
|
1413
|
+
const resolved = await this.resolver.resolve(ref);
|
|
1414
|
+
const { parsed, repoUrl } = resolved;
|
|
1415
|
+
const version = resolved.ref;
|
|
1416
|
+
const skillName = parsed.subPath ? __WEBPACK_EXTERNAL_MODULE_node_path__.basename(parsed.subPath) : parsed.repo;
|
|
1417
|
+
logger["package"](`Installing ${skillName}@${version} to ${targetAgents.length} agent(s)...`);
|
|
1418
|
+
let cacheResult = await this.cache.get(parsed, version);
|
|
1419
|
+
if (cacheResult) logger.debug(`Using cached ${skillName}@${version}`);
|
|
1420
|
+
else {
|
|
1421
|
+
logger.debug(`Caching ${skillName}@${version} from ${repoUrl}`);
|
|
1422
|
+
cacheResult = await this.cache.cache(repoUrl, parsed, version, version);
|
|
1109
1423
|
}
|
|
1424
|
+
const sourcePath = this.cache.getCachePath(parsed, version);
|
|
1425
|
+
const installer = new Installer({
|
|
1426
|
+
cwd: this.projectRoot,
|
|
1427
|
+
global: this.isGlobal
|
|
1428
|
+
});
|
|
1429
|
+
const results = await installer.installToAgents(sourcePath, skillName, targetAgents, {
|
|
1430
|
+
mode: mode
|
|
1431
|
+
});
|
|
1432
|
+
if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
|
|
1433
|
+
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
|
|
1434
|
+
version,
|
|
1435
|
+
resolved: repoUrl,
|
|
1436
|
+
commit: cacheResult.commit
|
|
1437
|
+
});
|
|
1438
|
+
if (!this.isGlobal && save && this.config.exists()) this.config.addSkill(skillName, ref);
|
|
1439
|
+
const successCount = Array.from(results.values()).filter((r)=>r.success).length;
|
|
1440
|
+
const failCount = results.size - successCount;
|
|
1441
|
+
if (0 === failCount) logger.success(`Installed ${skillName}@${version} to ${successCount} agent(s)`);
|
|
1442
|
+
else logger.warn(`Installed ${skillName}@${version} to ${successCount} agent(s), ${failCount} failed`);
|
|
1443
|
+
const skill = {
|
|
1444
|
+
name: skillName,
|
|
1445
|
+
path: sourcePath,
|
|
1446
|
+
version,
|
|
1447
|
+
source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`
|
|
1448
|
+
};
|
|
1449
|
+
return {
|
|
1450
|
+
skill,
|
|
1451
|
+
results
|
|
1452
|
+
};
|
|
1110
1453
|
}
|
|
1111
|
-
|
|
1112
|
-
const
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
global: isGlobal
|
|
1116
|
-
});
|
|
1117
|
-
const skills = skillManager.list();
|
|
1118
|
-
if (0 === skills.length) {
|
|
1119
|
-
const location = isGlobal ? 'globally' : 'in this project';
|
|
1120
|
-
logger.info(`No skills installed ${location}`);
|
|
1121
|
-
return;
|
|
1454
|
+
async getDefaultTargetAgents() {
|
|
1455
|
+
const defaults = this.config.getDefaults();
|
|
1456
|
+
if (defaults.targetAgents && defaults.targetAgents.length > 0) return defaults.targetAgents.filter(isValidAgentType);
|
|
1457
|
+
return detectInstalledAgents();
|
|
1122
1458
|
}
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
return;
|
|
1459
|
+
getDefaultInstallMode() {
|
|
1460
|
+
const defaults = this.config.getDefaults();
|
|
1461
|
+
if ('copy' === defaults.installMode || 'symlink' === defaults.installMode) return defaults.installMode;
|
|
1462
|
+
return 'symlink';
|
|
1463
|
+
}
|
|
1464
|
+
validateAgentTypes(agentNames) {
|
|
1465
|
+
const valid = [];
|
|
1466
|
+
const invalid = [];
|
|
1467
|
+
for (const name of agentNames)if (isValidAgentType(name)) valid.push(name);
|
|
1468
|
+
else invalid.push(name);
|
|
1469
|
+
return {
|
|
1470
|
+
valid,
|
|
1471
|
+
invalid
|
|
1472
|
+
};
|
|
1126
1473
|
}
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
});
|
|
1474
|
+
getAllAgentTypes() {
|
|
1475
|
+
return Object.keys(agents);
|
|
1476
|
+
}
|
|
1477
|
+
uninstallFromAgents(name, targetAgents) {
|
|
1478
|
+
const installer = new Installer({
|
|
1479
|
+
cwd: this.projectRoot,
|
|
1480
|
+
global: this.isGlobal
|
|
1481
|
+
});
|
|
1482
|
+
const results = installer.uninstallFromAgents(name, targetAgents);
|
|
1483
|
+
if (!this.isGlobal) this.lockManager.remove(name);
|
|
1484
|
+
if (!this.isGlobal && this.config.exists()) this.config.removeSkill(name);
|
|
1485
|
+
const successCount = Array.from(results.values()).filter((r)=>r).length;
|
|
1486
|
+
logger.success(`Uninstalled ${name} from ${successCount} agent(s)`);
|
|
1487
|
+
return results;
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1144
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)=>{
|
|
1145
1491
|
const skillManager = new SkillManager();
|
|
1146
1492
|
const info = skillManager.getInfo(skillName);
|
|
@@ -1180,29 +1526,323 @@ const infoCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('info').de
|
|
|
1180
1526
|
}
|
|
1181
1527
|
} else logger.warn(`Skill ${skillName} is not installed`);
|
|
1182
1528
|
});
|
|
1183
|
-
const
|
|
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)=>{
|
|
1184
1530
|
const configLoader = new ConfigLoader();
|
|
1185
|
-
if (
|
|
1186
|
-
logger.
|
|
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
|
+
});
|
|
1553
|
+
function formatAgentNames(agentTypes, maxShow = 5) {
|
|
1554
|
+
const names = agentTypes.map((a)=>agents[a].displayName);
|
|
1555
|
+
if (names.length <= maxShow) return names.join(', ');
|
|
1556
|
+
const shown = names.slice(0, maxShow);
|
|
1557
|
+
const remaining = names.length - maxShow;
|
|
1558
|
+
return `${shown.join(', ')} +${remaining} more`;
|
|
1559
|
+
}
|
|
1560
|
+
const installCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('install').alias('i').description('Install a skill or all skills from skills.json').argument('[skill]', 'Skill reference (e.g., github:user/skill@v1.0.0 or git@github.com:user/repo.git)').option('-f, --force', 'Force reinstall even if already installed').option('-g, --global', 'Install globally to user home directory').option('--no-save', 'Do not save to skills.json').option('-a, --agent <agents...>', 'Specify target agents (e.g., cursor, claude-code)').option('--mode <mode>', 'Installation mode: symlink or copy').option('-y, --yes', 'Skip confirmation prompts').option('--all', 'Install to all agents (implies -y -g)').action(async (skill, options)=>{
|
|
1561
|
+
if (options.all) {
|
|
1562
|
+
options.yes = true;
|
|
1563
|
+
options.global = true;
|
|
1564
|
+
}
|
|
1565
|
+
const skipConfirm = options.yes || false;
|
|
1566
|
+
const configLoader = new ConfigLoader();
|
|
1567
|
+
const allAgentTypes = Object.keys(agents);
|
|
1568
|
+
console.log();
|
|
1569
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.intro(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].bgCyan.black(' reskill '));
|
|
1570
|
+
try {
|
|
1571
|
+
const spinner = __WEBPACK_EXTERNAL_MODULE__clack_prompts__.spinner();
|
|
1572
|
+
let targetAgents;
|
|
1573
|
+
if (options.all) {
|
|
1574
|
+
targetAgents = allAgentTypes;
|
|
1575
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.info(`Installing to all ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(targetAgents.length)} agents`);
|
|
1576
|
+
} else if (options.agent && options.agent.length > 0) {
|
|
1577
|
+
const validAgents = Object.keys(agents);
|
|
1578
|
+
const invalidAgents = options.agent.filter((a)=>!validAgents.includes(a));
|
|
1579
|
+
if (invalidAgents.length > 0) {
|
|
1580
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.error(`Invalid agents: ${invalidAgents.join(', ')}`);
|
|
1581
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.info(`Valid agents: ${validAgents.join(', ')}`);
|
|
1582
|
+
process.exit(1);
|
|
1583
|
+
}
|
|
1584
|
+
targetAgents = options.agent;
|
|
1585
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.info(`Installing to: ${formatAgentNames(targetAgents)}`);
|
|
1586
|
+
} else {
|
|
1587
|
+
spinner.start('Detecting installed agents...');
|
|
1588
|
+
const installedAgents = await detectInstalledAgents();
|
|
1589
|
+
spinner.stop(`Detected ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green(installedAgents.length)} agent${1 !== installedAgents.length ? 's' : ''}`);
|
|
1590
|
+
if (0 === installedAgents.length) {
|
|
1591
|
+
if (skipConfirm) {
|
|
1592
|
+
targetAgents = allAgentTypes;
|
|
1593
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.info('Installing to all agents (none detected)');
|
|
1594
|
+
} else {
|
|
1595
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.warn('No coding agents detected. You can still install skills.');
|
|
1596
|
+
const allAgentChoices = Object.entries(agents).map(([key, config])=>({
|
|
1597
|
+
value: key,
|
|
1598
|
+
label: config.displayName
|
|
1599
|
+
}));
|
|
1600
|
+
const selected = await __WEBPACK_EXTERNAL_MODULE__clack_prompts__.multiselect({
|
|
1601
|
+
message: 'Select agents to install skills to',
|
|
1602
|
+
options: allAgentChoices,
|
|
1603
|
+
required: true,
|
|
1604
|
+
initialValues: allAgentTypes
|
|
1605
|
+
});
|
|
1606
|
+
if (__WEBPACK_EXTERNAL_MODULE__clack_prompts__.isCancel(selected)) {
|
|
1607
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.cancel('Installation cancelled');
|
|
1608
|
+
process.exit(0);
|
|
1609
|
+
}
|
|
1610
|
+
targetAgents = selected;
|
|
1611
|
+
}
|
|
1612
|
+
} else if (1 === installedAgents.length || skipConfirm) {
|
|
1613
|
+
targetAgents = installedAgents;
|
|
1614
|
+
if (1 === installedAgents.length) __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.info(`Installing to: ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(agents[installedAgents[0]].displayName)}`);
|
|
1615
|
+
else __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.info(`Installing to: ${installedAgents.map((a)=>__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(agents[a].displayName)).join(', ')}`);
|
|
1616
|
+
} else {
|
|
1617
|
+
const agentChoices = installedAgents.map((a)=>({
|
|
1618
|
+
value: a,
|
|
1619
|
+
label: agents[a].displayName,
|
|
1620
|
+
hint: agents[a].skillsDir
|
|
1621
|
+
}));
|
|
1622
|
+
const selected = await __WEBPACK_EXTERNAL_MODULE__clack_prompts__.multiselect({
|
|
1623
|
+
message: 'Select agents to install skills to',
|
|
1624
|
+
options: agentChoices,
|
|
1625
|
+
required: true,
|
|
1626
|
+
initialValues: installedAgents
|
|
1627
|
+
});
|
|
1628
|
+
if (__WEBPACK_EXTERNAL_MODULE__clack_prompts__.isCancel(selected)) {
|
|
1629
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.cancel('Installation cancelled');
|
|
1630
|
+
process.exit(0);
|
|
1631
|
+
}
|
|
1632
|
+
targetAgents = selected;
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
let installGlobally = options.global ?? false;
|
|
1636
|
+
if (void 0 === options.global && !skipConfirm) {
|
|
1637
|
+
const scope = await __WEBPACK_EXTERNAL_MODULE__clack_prompts__.select({
|
|
1638
|
+
message: 'Installation scope',
|
|
1639
|
+
options: [
|
|
1640
|
+
{
|
|
1641
|
+
value: false,
|
|
1642
|
+
label: 'Project',
|
|
1643
|
+
hint: 'Install in current directory (committed with your project)'
|
|
1644
|
+
},
|
|
1645
|
+
{
|
|
1646
|
+
value: true,
|
|
1647
|
+
label: 'Global',
|
|
1648
|
+
hint: 'Install in home directory (available across all projects)'
|
|
1649
|
+
}
|
|
1650
|
+
]
|
|
1651
|
+
});
|
|
1652
|
+
if (__WEBPACK_EXTERNAL_MODULE__clack_prompts__.isCancel(scope)) {
|
|
1653
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.cancel('Installation cancelled');
|
|
1654
|
+
process.exit(0);
|
|
1655
|
+
}
|
|
1656
|
+
installGlobally = scope;
|
|
1657
|
+
}
|
|
1658
|
+
let installMode = options.mode || 'symlink';
|
|
1659
|
+
if (!options.mode && !skipConfirm) {
|
|
1660
|
+
const modeChoice = await __WEBPACK_EXTERNAL_MODULE__clack_prompts__.select({
|
|
1661
|
+
message: 'Installation method',
|
|
1662
|
+
options: [
|
|
1663
|
+
{
|
|
1664
|
+
value: 'symlink',
|
|
1665
|
+
label: 'Symlink (Recommended)',
|
|
1666
|
+
hint: 'Single source of truth, easy updates'
|
|
1667
|
+
},
|
|
1668
|
+
{
|
|
1669
|
+
value: 'copy',
|
|
1670
|
+
label: 'Copy to all agents',
|
|
1671
|
+
hint: 'Independent copies for each agent'
|
|
1672
|
+
}
|
|
1673
|
+
]
|
|
1674
|
+
});
|
|
1675
|
+
if (__WEBPACK_EXTERNAL_MODULE__clack_prompts__.isCancel(modeChoice)) {
|
|
1676
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.cancel('Installation cancelled');
|
|
1677
|
+
process.exit(0);
|
|
1678
|
+
}
|
|
1679
|
+
installMode = modeChoice;
|
|
1680
|
+
}
|
|
1681
|
+
const skillManager = new SkillManager(void 0, {
|
|
1682
|
+
global: installGlobally
|
|
1683
|
+
});
|
|
1684
|
+
const cwd = process.cwd();
|
|
1685
|
+
if (skill) {
|
|
1686
|
+
const summaryLines = [];
|
|
1687
|
+
summaryLines.push(`${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(skill)}`);
|
|
1688
|
+
summaryLines.push(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('→')} ${formatAgentNames(targetAgents)}`);
|
|
1689
|
+
summaryLines.push(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('Scope:')} ${installGlobally ? 'Global' : 'Project'}${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(', Mode:')} ${installMode}`);
|
|
1690
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.note(summaryLines.join('\n'), 'Installation Summary');
|
|
1691
|
+
if (!skipConfirm) {
|
|
1692
|
+
const confirmed = await __WEBPACK_EXTERNAL_MODULE__clack_prompts__.confirm({
|
|
1693
|
+
message: 'Proceed with installation?'
|
|
1694
|
+
});
|
|
1695
|
+
if (__WEBPACK_EXTERNAL_MODULE__clack_prompts__.isCancel(confirmed) || !confirmed) {
|
|
1696
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.cancel('Installation cancelled');
|
|
1697
|
+
process.exit(0);
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
spinner.start(`Installing ${skill}...`);
|
|
1701
|
+
const { skill: installed, results } = await skillManager.installToAgents(skill, targetAgents, {
|
|
1702
|
+
force: options.force,
|
|
1703
|
+
save: options.save && !installGlobally,
|
|
1704
|
+
mode: installMode
|
|
1705
|
+
});
|
|
1706
|
+
spinner.stop('Installation complete');
|
|
1707
|
+
const successful = Array.from(results.entries()).filter(([, r])=>r.success);
|
|
1708
|
+
const failed = Array.from(results.entries()).filter(([, r])=>!r.success);
|
|
1709
|
+
const symlinkFailed = successful.filter(([, r])=>'symlink' === r.mode && r.symlinkFailed);
|
|
1710
|
+
if (successful.length > 0) {
|
|
1711
|
+
const resultLines = [];
|
|
1712
|
+
const firstResult = successful[0][1];
|
|
1713
|
+
if ('copy' === firstResult.mode) {
|
|
1714
|
+
resultLines.push(`${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green('✓')} ${installed.name}@${installed.version} ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('(copied)')}`);
|
|
1715
|
+
for (const [, result] of successful){
|
|
1716
|
+
const shortPath = shortenPath(result.path, cwd);
|
|
1717
|
+
resultLines.push(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('→')} ${shortPath}`);
|
|
1718
|
+
}
|
|
1719
|
+
} else {
|
|
1720
|
+
if (firstResult.canonicalPath) {
|
|
1721
|
+
const shortPath = shortenPath(firstResult.canonicalPath, cwd);
|
|
1722
|
+
resultLines.push(`${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green('✓')} ${shortPath}`);
|
|
1723
|
+
} else resultLines.push(`${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green('✓')} ${installed.name}@${installed.version}`);
|
|
1724
|
+
const symlinked = successful.filter(([, r])=>!r.symlinkFailed).map(([a])=>agents[a].displayName);
|
|
1725
|
+
const copied = successful.filter(([, r])=>r.symlinkFailed).map(([a])=>agents[a].displayName);
|
|
1726
|
+
if (symlinked.length > 0) resultLines.push(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('symlink →')} ${symlinked.join(', ')}`);
|
|
1727
|
+
if (copied.length > 0) resultLines.push(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].yellow('copied →')} ${copied.join(', ')}`);
|
|
1728
|
+
}
|
|
1729
|
+
const title = __WEBPACK_EXTERNAL_MODULE_chalk__["default"].green(`Installed 1 skill to ${successful.length} agent${1 !== successful.length ? 's' : ''}`);
|
|
1730
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.note(resultLines.join('\n'), title);
|
|
1731
|
+
if (symlinkFailed.length > 0) {
|
|
1732
|
+
const copiedAgentNames = symlinkFailed.map(([a])=>agents[a].displayName);
|
|
1733
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.warn(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].yellow(`Symlinks failed for: ${copiedAgentNames.join(', ')}`));
|
|
1734
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.message(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(' Files were copied instead. On Windows, enable Developer Mode for symlink support.'));
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
if (failed.length > 0) {
|
|
1738
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.error(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].red(`Failed to install to ${failed.length} agent(s)`));
|
|
1739
|
+
for (const [agent, result] of failed)__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.message(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].red('✗')} ${agents[agent].displayName}: ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(result.error)}`);
|
|
1740
|
+
}
|
|
1741
|
+
} else {
|
|
1742
|
+
if (installGlobally) {
|
|
1743
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.error('Cannot install all skills globally. Please specify a skill to install.');
|
|
1744
|
+
process.exit(1);
|
|
1745
|
+
}
|
|
1746
|
+
if (!configLoader.exists()) {
|
|
1747
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.error("skills.json not found. Run 'reskill init' first.");
|
|
1748
|
+
process.exit(1);
|
|
1749
|
+
}
|
|
1750
|
+
const skills = configLoader.getSkills();
|
|
1751
|
+
if (0 === Object.keys(skills).length) {
|
|
1752
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.info('No skills defined in skills.json');
|
|
1753
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.outro('Done');
|
|
1754
|
+
return;
|
|
1755
|
+
}
|
|
1756
|
+
const summaryLines = [];
|
|
1757
|
+
summaryLines.push(`${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(Object.keys(skills).length)} skill(s) → ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(targetAgents.length)} agent(s)`);
|
|
1758
|
+
summaryLines.push(`${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('Scope:')} ${installGlobally ? 'Global (~/)' : 'Project (./)'}${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(', Mode:')} ${installMode}`);
|
|
1759
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.note(summaryLines.join('\n'), 'Installation Summary');
|
|
1760
|
+
if (!skipConfirm) {
|
|
1761
|
+
const confirmed = await __WEBPACK_EXTERNAL_MODULE__clack_prompts__.confirm({
|
|
1762
|
+
message: 'Proceed with installation?'
|
|
1763
|
+
});
|
|
1764
|
+
if (__WEBPACK_EXTERNAL_MODULE__clack_prompts__.isCancel(confirmed) || !confirmed) {
|
|
1765
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.cancel('Installation cancelled');
|
|
1766
|
+
process.exit(0);
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
spinner.start('Installing skills...');
|
|
1770
|
+
let totalInstalled = 0;
|
|
1771
|
+
let totalFailed = 0;
|
|
1772
|
+
for (const [name, ref] of Object.entries(skills))try {
|
|
1773
|
+
const { results } = await skillManager.installToAgents(ref, targetAgents, {
|
|
1774
|
+
force: options.force,
|
|
1775
|
+
save: false,
|
|
1776
|
+
mode: installMode
|
|
1777
|
+
});
|
|
1778
|
+
const successCount = Array.from(results.values()).filter((r)=>r.success).length;
|
|
1779
|
+
totalInstalled += successCount;
|
|
1780
|
+
totalFailed += results.size - successCount;
|
|
1781
|
+
} catch (error) {
|
|
1782
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.error(`Failed to install ${name}: ${error.message}`);
|
|
1783
|
+
totalFailed += targetAgents.length;
|
|
1784
|
+
}
|
|
1785
|
+
spinner.stop('Installation complete');
|
|
1786
|
+
if (0 === totalFailed) __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.success(`Installed ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green(Object.keys(skills).length)} skill(s) to ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green(targetAgents.length)} agent(s)`);
|
|
1787
|
+
else __WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.warn(`Installed ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green(totalInstalled)} successfully, ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].red(totalFailed)} failed`);
|
|
1788
|
+
}
|
|
1789
|
+
console.log();
|
|
1790
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.outro(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green('Done!'));
|
|
1791
|
+
} catch (error) {
|
|
1792
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.error(error.message);
|
|
1793
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.outro(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].red('Installation failed'));
|
|
1187
1794
|
process.exit(1);
|
|
1188
1795
|
}
|
|
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)=>{
|
|
1189
1798
|
const skillManager = new SkillManager();
|
|
1190
|
-
const spinner = (0, __WEBPACK_EXTERNAL_MODULE_ora__["default"])(skill ? `Updating ${skill}...` : 'Updating all skills...').start();
|
|
1191
1799
|
try {
|
|
1192
|
-
const
|
|
1193
|
-
|
|
1194
|
-
if (0 === updated.length) {
|
|
1195
|
-
logger.info('No skills to update');
|
|
1196
|
-
return;
|
|
1197
|
-
}
|
|
1198
|
-
logger.success(`Updated ${updated.length} skill(s):`);
|
|
1199
|
-
for (const s of updated)logger.log(` - ${s.name}@${s.version}`);
|
|
1800
|
+
const linked = skillManager.link(localPath, options.name);
|
|
1801
|
+
logger.log(`Linked skill available at: ${linked.path}`);
|
|
1200
1802
|
} catch (error) {
|
|
1201
|
-
spinner.fail('Update failed');
|
|
1202
1803
|
logger.error(error.message);
|
|
1203
1804
|
process.exit(1);
|
|
1204
1805
|
}
|
|
1205
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;
|
|
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)=>{
|
|
1815
|
+
const isGlobal = options.global || false;
|
|
1816
|
+
const skillManager = new SkillManager(void 0, {
|
|
1817
|
+
global: isGlobal
|
|
1818
|
+
});
|
|
1819
|
+
const skills = skillManager.list();
|
|
1820
|
+
if (0 === skills.length) {
|
|
1821
|
+
const location = isGlobal ? 'globally' : 'in this project';
|
|
1822
|
+
logger.info(`No skills installed ${location}`);
|
|
1823
|
+
return;
|
|
1824
|
+
}
|
|
1825
|
+
if (options.json) {
|
|
1826
|
+
console.log(JSON.stringify(skills, null, 2));
|
|
1827
|
+
return;
|
|
1828
|
+
}
|
|
1829
|
+
const locationLabel = isGlobal ? __WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(' (global)') : '';
|
|
1830
|
+
logger.log(`Installed Skills (${skillManager.getInstallDir()})${locationLabel}:`);
|
|
1831
|
+
logger.newline();
|
|
1832
|
+
const headers = [
|
|
1833
|
+
'Name',
|
|
1834
|
+
'Version',
|
|
1835
|
+
'Source'
|
|
1836
|
+
];
|
|
1837
|
+
const rows = skills.map((skill)=>[
|
|
1838
|
+
skill.name,
|
|
1839
|
+
skill.isLinked ? `${skill.version} (linked)` : skill.version,
|
|
1840
|
+
skill.source || '-'
|
|
1841
|
+
]);
|
|
1842
|
+
logger.table(headers, rows);
|
|
1843
|
+
logger.newline();
|
|
1844
|
+
logger.log(`Total: ${skills.length} skill(s)`);
|
|
1845
|
+
});
|
|
1206
1846
|
const outdatedCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('outdated').description('Check for outdated skills').option('-j, --json', 'Output as JSON').action(async (options)=>{
|
|
1207
1847
|
const configLoader = new ConfigLoader();
|
|
1208
1848
|
if (!configLoader.exists()) {
|
|
@@ -1262,23 +1902,29 @@ const uninstallCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('unin
|
|
|
1262
1902
|
const result = skillManager.uninstall(skillName);
|
|
1263
1903
|
if (!result) process.exit(1);
|
|
1264
1904
|
});
|
|
1265
|
-
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
|
+
}
|
|
1266
1911
|
const skillManager = new SkillManager();
|
|
1912
|
+
const spinner = (0, __WEBPACK_EXTERNAL_MODULE_ora__["default"])(skill ? `Updating ${skill}...` : 'Updating all skills...').start();
|
|
1267
1913
|
try {
|
|
1268
|
-
const
|
|
1269
|
-
|
|
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}`);
|
|
1270
1922
|
} catch (error) {
|
|
1923
|
+
spinner.fail('Update failed');
|
|
1271
1924
|
logger.error(error.message);
|
|
1272
1925
|
process.exit(1);
|
|
1273
1926
|
}
|
|
1274
1927
|
});
|
|
1275
|
-
const unlinkCmd = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('unlink').description('Unlink a linked skill').argument('<skill>', 'Skill name to unlink').action((skillName)=>{
|
|
1276
|
-
const skillManager = new SkillManager();
|
|
1277
|
-
const result = skillManager.unlink(skillName);
|
|
1278
|
-
if (!result) process.exit(1);
|
|
1279
|
-
});
|
|
1280
|
-
const linkCommand = linkCmd;
|
|
1281
|
-
const unlinkCommand = unlinkCmd;
|
|
1282
1928
|
const program = new __WEBPACK_EXTERNAL_MODULE_commander__.Command();
|
|
1283
1929
|
program.name('reskill').description('AI Skills Package Manager - Git-based skills management for AI agents').version('0.1.0');
|
|
1284
1930
|
program.addCommand(initCommand);
|