reskill 1.13.0 → 1.15.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 +5 -2
- package/README.zh-CN.md +5 -2
- package/dist/cli/commands/doctor.d.ts +34 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/install.d.ts.map +1 -1
- package/dist/cli/index.js +453 -138
- package/dist/core/lock-manager.d.ts +4 -0
- package/dist/core/lock-manager.d.ts.map +1 -1
- package/dist/core/skill-manager.d.ts +17 -0
- package/dist/core/skill-manager.d.ts.map +1 -1
- package/dist/index.js +48 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -117,7 +117,7 @@ npx reskill@latest install github:user/skill1 github:user/skill2@v1.0.0
|
|
|
117
117
|
|
|
118
118
|
### Monorepo Support
|
|
119
119
|
|
|
120
|
-
For repositories containing multiple skills (monorepo),
|
|
120
|
+
For repositories containing multiple skills (monorepo), you can install a specific skill by path or install all skills from a parent directory:
|
|
121
121
|
|
|
122
122
|
```bash
|
|
123
123
|
# Shorthand format with subpath
|
|
@@ -130,9 +130,12 @@ npx reskill@latest install git@gitlab.company.com:team/skills.git/backend/apis@v
|
|
|
130
130
|
|
|
131
131
|
# GitHub web URL automatically extracts subpath
|
|
132
132
|
npx reskill@latest install https://github.com/org/monorepo/tree/main/skills/planning
|
|
133
|
+
|
|
134
|
+
# Point to a parent directory — auto-detects and installs all child skills
|
|
135
|
+
npx reskill@latest install https://github.com/org/monorepo/tree/main/skills
|
|
133
136
|
```
|
|
134
137
|
|
|
135
|
-
|
|
138
|
+
When the target directory has no root `SKILL.md` but contains subdirectories with `SKILL.md` files, reskill automatically discovers and installs all child skills. Each skill is saved separately in `skills.json`.
|
|
136
139
|
|
|
137
140
|
### HTTP/OSS URL Support
|
|
138
141
|
|
package/README.zh-CN.md
CHANGED
|
@@ -117,7 +117,7 @@ npx reskill@latest install github:user/skill1 github:user/skill2@v1.0.0
|
|
|
117
117
|
|
|
118
118
|
### Monorepo 支持
|
|
119
119
|
|
|
120
|
-
对于包含多个技能的仓库(monorepo
|
|
120
|
+
对于包含多个技能的仓库(monorepo),可以指定技能目录的路径安装单个技能,也可以指向父目录一键安装所有技能:
|
|
121
121
|
|
|
122
122
|
```bash
|
|
123
123
|
# 简写格式带子路径
|
|
@@ -130,9 +130,12 @@ npx reskill@latest install git@gitlab.company.com:team/skills.git/backend/apis@v
|
|
|
130
130
|
|
|
131
131
|
# GitHub 网页 URL 自动提取子路径
|
|
132
132
|
npx reskill@latest install https://github.com/org/monorepo/tree/main/skills/planning
|
|
133
|
+
|
|
134
|
+
# 指向父目录 — 自动发现并安装所有子技能
|
|
135
|
+
npx reskill@latest install https://github.com/org/monorepo/tree/main/skills
|
|
133
136
|
```
|
|
134
137
|
|
|
135
|
-
|
|
138
|
+
当目标目录没有根 `SKILL.md` 但包含带有 `SKILL.md` 的子目录时,reskill 会自动发现并安装所有子技能。每个技能会分别保存到 `skills.json` 中。
|
|
136
139
|
|
|
137
140
|
### HTTP/OSS URL 支持
|
|
138
141
|
|
|
@@ -49,6 +49,21 @@ export declare function checkGitVersion(): CheckResult;
|
|
|
49
49
|
* Check Git authentication
|
|
50
50
|
*/
|
|
51
51
|
export declare function checkGitAuth(): CheckResult;
|
|
52
|
+
/**
|
|
53
|
+
* Check registry authentication status
|
|
54
|
+
*
|
|
55
|
+
* Verifies actual token availability, not just file existence.
|
|
56
|
+
* Uses AuthManager.getToken() which checks RESKILL_TOKEN env first,
|
|
57
|
+
* then reads ~/.reskillrc for the configured registry.
|
|
58
|
+
*/
|
|
59
|
+
export declare function checkAuthStatus(): CheckResult;
|
|
60
|
+
/**
|
|
61
|
+
* Check environment variables used by reskill
|
|
62
|
+
*
|
|
63
|
+
* Security: Only report variable names, never values.
|
|
64
|
+
* RESKILL_TOKEN contains a secret and must not be displayed.
|
|
65
|
+
*/
|
|
66
|
+
export declare function checkEnvVars(): CheckResult;
|
|
52
67
|
/**
|
|
53
68
|
* Check cache directory
|
|
54
69
|
*/
|
|
@@ -65,6 +80,14 @@ export declare function checkRegistryConflicts(cwd: string): CheckResult[];
|
|
|
65
80
|
* Check for dangerous installDir configuration
|
|
66
81
|
*/
|
|
67
82
|
export declare function checkInstallDir(cwd: string): CheckResult | null;
|
|
83
|
+
/**
|
|
84
|
+
* Check for invalid installMode configuration
|
|
85
|
+
*/
|
|
86
|
+
export declare function checkInstallMode(cwd: string): CheckResult | null;
|
|
87
|
+
/**
|
|
88
|
+
* Check for invalid publishRegistry configuration
|
|
89
|
+
*/
|
|
90
|
+
export declare function checkPublishRegistry(cwd: string): CheckResult | null;
|
|
68
91
|
/**
|
|
69
92
|
* Check for invalid targetAgents configuration
|
|
70
93
|
*/
|
|
@@ -95,6 +118,17 @@ export interface SkillIssue {
|
|
|
95
118
|
* Only checks for SKILL.md since that's the sole source of metadata
|
|
96
119
|
*/
|
|
97
120
|
export declare function checkInstalledSkills(cwd: string): CheckResult[];
|
|
121
|
+
/**
|
|
122
|
+
* Check detected agents
|
|
123
|
+
*/
|
|
124
|
+
export declare function checkDetectedAgents(): Promise<CheckResult>;
|
|
125
|
+
/**
|
|
126
|
+
* Get custom registry URLs for network checks
|
|
127
|
+
*
|
|
128
|
+
* Reads registries from skills.json and publishRegistry,
|
|
129
|
+
* excluding built-in github.com/gitlab.com and deduplicating.
|
|
130
|
+
*/
|
|
131
|
+
export declare function getCustomRegistryUrls(cwd: string): string[];
|
|
98
132
|
/**
|
|
99
133
|
* Check network connectivity
|
|
100
134
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/install.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/install.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAs5BpC;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,SA8GvB,CAAC;AAEL,eAAe,cAAc,CAAC"}
|
package/dist/cli/index.js
CHANGED
|
@@ -4338,6 +4338,54 @@ class RegistryResolver {
|
|
|
4338
4338
|
// Multi-Agent installation methods
|
|
4339
4339
|
// ============================================================================
|
|
4340
4340
|
/**
|
|
4341
|
+
* Detect whether a ref points to a single skill or a multi-skill directory.
|
|
4342
|
+
*
|
|
4343
|
+
* Returns `{ type: 'single' }` when the cached root contains a SKILL.md (or
|
|
4344
|
+
* when the source is registry/HTTP — those are always single-skill).
|
|
4345
|
+
* Returns `{ type: 'multi', skills }` when the root has **no** SKILL.md but
|
|
4346
|
+
* `discoverSkillsInDir()` finds child skills underneath.
|
|
4347
|
+
*
|
|
4348
|
+
* The method caches the repo as a side-effect so that the subsequent
|
|
4349
|
+
* `installToAgents` / `installSkillsFromRepo` call hits the cache.
|
|
4350
|
+
*/ async detectSkillsInRef(ref) {
|
|
4351
|
+
// Only Git refs can be multi-skill directories
|
|
4352
|
+
if (this.isRegistrySource(ref) || this.isHttpSource(ref)) return {
|
|
4353
|
+
type: 'single'
|
|
4354
|
+
};
|
|
4355
|
+
const resolved = await this.resolver.resolve(ref);
|
|
4356
|
+
const { parsed } = resolved;
|
|
4357
|
+
const gitRef = resolved.ref;
|
|
4358
|
+
// Ensure the repo is cached (result unused — we only need the side-effect)
|
|
4359
|
+
if (!await this.cache.get(parsed, gitRef)) await this.cache.cache(resolved.repoUrl, parsed, gitRef, gitRef);
|
|
4360
|
+
const cachePath = this.cache.getCachePath(parsed, gitRef);
|
|
4361
|
+
// When parsed.skillName is set (ref has #fragment), resolve to the
|
|
4362
|
+
// specific skill subdirectory so we check the right SKILL.md.
|
|
4363
|
+
const sourcePath = this.resolveSourcePath(cachePath, parsed);
|
|
4364
|
+
const metadata = this.getSkillMetadataFromDir(sourcePath);
|
|
4365
|
+
if (metadata) return {
|
|
4366
|
+
type: 'single'
|
|
4367
|
+
};
|
|
4368
|
+
// No SKILL.md at root — check for child skills.
|
|
4369
|
+
// cachePath is correct here (not sourcePath) for two reasons:
|
|
4370
|
+
// 1. When parsed.skillName is set, resolveSourcePath() either returns a
|
|
4371
|
+
// subdirectory (→ metadata found → already returned 'single' above) or
|
|
4372
|
+
// throws (skill not found). So we never reach this line with
|
|
4373
|
+
// sourcePath ≠ cachePath.
|
|
4374
|
+
// 2. When parsed.subPath is set, CacheManager.cache() already copies only
|
|
4375
|
+
// the subPath subdirectory into cachePath, so discovery is scoped to
|
|
4376
|
+
// the intended directory automatically.
|
|
4377
|
+
const discovered = discoverSkillsInDir(cachePath);
|
|
4378
|
+
if (discovered.length > 0) return {
|
|
4379
|
+
type: 'multi',
|
|
4380
|
+
skills: discovered
|
|
4381
|
+
};
|
|
4382
|
+
// No skills found at all. Return 'single' so the caller proceeds to
|
|
4383
|
+
// installToAgents, which will produce a clear error ("no SKILL.md found").
|
|
4384
|
+
return {
|
|
4385
|
+
type: 'single'
|
|
4386
|
+
};
|
|
4387
|
+
}
|
|
4388
|
+
/**
|
|
4341
4389
|
* Install skill to multiple agents
|
|
4342
4390
|
*
|
|
4343
4391
|
* @param ref - Skill reference (e.g., github:user/repo@v1.0.0 or HTTP URL)
|
|
@@ -5189,6 +5237,133 @@ class RegistryResolver {
|
|
|
5189
5237
|
}
|
|
5190
5238
|
return false;
|
|
5191
5239
|
}
|
|
5240
|
+
/**
|
|
5241
|
+
* AuthManager - Handle authentication token management
|
|
5242
|
+
*
|
|
5243
|
+
* Manages tokens for registry authentication.
|
|
5244
|
+
* Tokens are stored in ~/.reskillrc or via RESKILL_TOKEN environment variable.
|
|
5245
|
+
*/ // ============================================================================
|
|
5246
|
+
// Constants
|
|
5247
|
+
// ============================================================================
|
|
5248
|
+
const CONFIG_FILE_NAME = '.reskillrc';
|
|
5249
|
+
// ============================================================================
|
|
5250
|
+
// AuthManager Class
|
|
5251
|
+
// ============================================================================
|
|
5252
|
+
class AuthManager {
|
|
5253
|
+
configPath;
|
|
5254
|
+
constructor(){
|
|
5255
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
5256
|
+
this.configPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, CONFIG_FILE_NAME);
|
|
5257
|
+
}
|
|
5258
|
+
/**
|
|
5259
|
+
* Get the default registry URL from environment variable
|
|
5260
|
+
*
|
|
5261
|
+
* Returns undefined if no registry is configured - there is no hardcoded default
|
|
5262
|
+
* to prevent accidental publishing to unintended registries.
|
|
5263
|
+
*/ getDefaultRegistry() {
|
|
5264
|
+
return process.env.RESKILL_REGISTRY;
|
|
5265
|
+
}
|
|
5266
|
+
/**
|
|
5267
|
+
* Get path to config file
|
|
5268
|
+
*/ getConfigPath() {
|
|
5269
|
+
return this.configPath;
|
|
5270
|
+
}
|
|
5271
|
+
/**
|
|
5272
|
+
* Get token for a registry
|
|
5273
|
+
*
|
|
5274
|
+
* Priority:
|
|
5275
|
+
* 1. RESKILL_TOKEN environment variable
|
|
5276
|
+
* 2. Token from ~/.reskillrc for the specified registry
|
|
5277
|
+
*/ getToken(registry) {
|
|
5278
|
+
// Check environment variable first
|
|
5279
|
+
const envToken = process.env.RESKILL_TOKEN;
|
|
5280
|
+
if (envToken) return envToken;
|
|
5281
|
+
// Read from config file
|
|
5282
|
+
const config = this.readConfig();
|
|
5283
|
+
if (!config?.registries) return;
|
|
5284
|
+
const targetRegistry = registry || this.getDefaultRegistry();
|
|
5285
|
+
if (!targetRegistry) return;
|
|
5286
|
+
const auth = config.registries[targetRegistry];
|
|
5287
|
+
return auth?.token;
|
|
5288
|
+
}
|
|
5289
|
+
/**
|
|
5290
|
+
* Check if token exists for a registry
|
|
5291
|
+
*/ hasToken(registry) {
|
|
5292
|
+
return void 0 !== this.getToken(registry);
|
|
5293
|
+
}
|
|
5294
|
+
/**
|
|
5295
|
+
* Get email for a registry
|
|
5296
|
+
*/ getEmail(registry) {
|
|
5297
|
+
const config = this.readConfig();
|
|
5298
|
+
if (!config?.registries) return;
|
|
5299
|
+
const targetRegistry = registry || this.getDefaultRegistry();
|
|
5300
|
+
if (!targetRegistry) return;
|
|
5301
|
+
const auth = config.registries[targetRegistry];
|
|
5302
|
+
return auth?.email;
|
|
5303
|
+
}
|
|
5304
|
+
/**
|
|
5305
|
+
* Get handle for a registry
|
|
5306
|
+
*/ getHandle(registry) {
|
|
5307
|
+
const config = this.readConfig();
|
|
5308
|
+
if (!config?.registries) return;
|
|
5309
|
+
const targetRegistry = registry || this.getDefaultRegistry();
|
|
5310
|
+
if (!targetRegistry) return;
|
|
5311
|
+
const auth = config.registries[targetRegistry];
|
|
5312
|
+
return auth?.handle;
|
|
5313
|
+
}
|
|
5314
|
+
/**
|
|
5315
|
+
* Set token for a registry
|
|
5316
|
+
*
|
|
5317
|
+
* Note: When no registry is specified and RESKILL_REGISTRY env var is not set,
|
|
5318
|
+
* this method will throw an error. The calling code should ensure a registry
|
|
5319
|
+
* is always provided (either explicitly or via environment variable).
|
|
5320
|
+
*/ setToken(token, registry, email, handle) {
|
|
5321
|
+
const config = this.readConfig() || {};
|
|
5322
|
+
const targetRegistry = registry || this.getDefaultRegistry();
|
|
5323
|
+
if (!targetRegistry) throw new Error('No registry specified. Set RESKILL_REGISTRY environment variable or provide registry explicitly.');
|
|
5324
|
+
if (!config.registries) config.registries = {};
|
|
5325
|
+
config.registries[targetRegistry] = {
|
|
5326
|
+
token,
|
|
5327
|
+
...email && {
|
|
5328
|
+
email
|
|
5329
|
+
},
|
|
5330
|
+
...handle && {
|
|
5331
|
+
handle
|
|
5332
|
+
}
|
|
5333
|
+
};
|
|
5334
|
+
this.writeConfig(config);
|
|
5335
|
+
}
|
|
5336
|
+
/**
|
|
5337
|
+
* Remove token for a registry
|
|
5338
|
+
*/ removeToken(registry) {
|
|
5339
|
+
const config = this.readConfig();
|
|
5340
|
+
if (!config?.registries) return;
|
|
5341
|
+
const targetRegistry = registry || this.getDefaultRegistry();
|
|
5342
|
+
if (!targetRegistry) return;
|
|
5343
|
+
delete config.registries[targetRegistry];
|
|
5344
|
+
this.writeConfig(config);
|
|
5345
|
+
}
|
|
5346
|
+
/**
|
|
5347
|
+
* Read config file
|
|
5348
|
+
*/ readConfig() {
|
|
5349
|
+
try {
|
|
5350
|
+
if (!external_node_fs_.existsSync(this.configPath)) return null;
|
|
5351
|
+
const content = external_node_fs_.readFileSync(this.configPath, 'utf-8');
|
|
5352
|
+
if (!content.trim()) return null;
|
|
5353
|
+
return JSON.parse(content);
|
|
5354
|
+
} catch {
|
|
5355
|
+
return null;
|
|
5356
|
+
}
|
|
5357
|
+
}
|
|
5358
|
+
/**
|
|
5359
|
+
* Write config file
|
|
5360
|
+
*/ writeConfig(config) {
|
|
5361
|
+
const content = JSON.stringify(config, null, 2);
|
|
5362
|
+
external_node_fs_.writeFileSync(this.configPath, content, {
|
|
5363
|
+
mode: 384
|
|
5364
|
+
});
|
|
5365
|
+
}
|
|
5366
|
+
}
|
|
5192
5367
|
/**
|
|
5193
5368
|
* Get status icon
|
|
5194
5369
|
*/ function getStatusIcon(status) {
|
|
@@ -5396,6 +5571,73 @@ class RegistryResolver {
|
|
|
5396
5571
|
hint: 'For private repos, add SSH key: ssh-keygen -t ed25519'
|
|
5397
5572
|
};
|
|
5398
5573
|
}
|
|
5574
|
+
/**
|
|
5575
|
+
* Valid install modes
|
|
5576
|
+
*
|
|
5577
|
+
* Must stay in sync with InstallMode type from installer.ts ('symlink' | 'copy').
|
|
5578
|
+
* TypeScript literal union types are erased at runtime, so we maintain this list manually.
|
|
5579
|
+
*/ const VALID_INSTALL_MODES = [
|
|
5580
|
+
'symlink',
|
|
5581
|
+
'copy'
|
|
5582
|
+
];
|
|
5583
|
+
/**
|
|
5584
|
+
* Check registry authentication status
|
|
5585
|
+
*
|
|
5586
|
+
* Verifies actual token availability, not just file existence.
|
|
5587
|
+
* Uses AuthManager.getToken() which checks RESKILL_TOKEN env first,
|
|
5588
|
+
* then reads ~/.reskillrc for the configured registry.
|
|
5589
|
+
*/ function checkAuthStatus() {
|
|
5590
|
+
const hasEnvToken = !!process.env.RESKILL_TOKEN;
|
|
5591
|
+
if (hasEnvToken) return {
|
|
5592
|
+
name: 'Registry auth',
|
|
5593
|
+
status: 'ok',
|
|
5594
|
+
message: 'RESKILL_TOKEN set'
|
|
5595
|
+
};
|
|
5596
|
+
// Check if ~/.reskillrc has any valid tokens
|
|
5597
|
+
const authManager = new AuthManager();
|
|
5598
|
+
const configPath = authManager.getConfigPath();
|
|
5599
|
+
if (!(0, external_node_fs_.existsSync)(configPath)) return {
|
|
5600
|
+
name: 'Registry auth',
|
|
5601
|
+
status: 'warn',
|
|
5602
|
+
message: 'no token configured',
|
|
5603
|
+
hint: 'Run: reskill login (needed for publish and private skills)'
|
|
5604
|
+
};
|
|
5605
|
+
// File exists — check if it actually contains a token for any registry
|
|
5606
|
+
const hasToken = authManager.hasToken();
|
|
5607
|
+
if (hasToken) return {
|
|
5608
|
+
name: 'Registry auth',
|
|
5609
|
+
status: 'ok',
|
|
5610
|
+
message: 'token configured via ~/.reskillrc'
|
|
5611
|
+
};
|
|
5612
|
+
return {
|
|
5613
|
+
name: 'Registry auth',
|
|
5614
|
+
status: 'warn',
|
|
5615
|
+
message: '~/.reskillrc exists but no token found for current registry',
|
|
5616
|
+
hint: 'Run: reskill login (needed for publish and private skills)'
|
|
5617
|
+
};
|
|
5618
|
+
}
|
|
5619
|
+
/**
|
|
5620
|
+
* Check environment variables used by reskill
|
|
5621
|
+
*
|
|
5622
|
+
* Security: Only report variable names, never values.
|
|
5623
|
+
* RESKILL_TOKEN contains a secret and must not be displayed.
|
|
5624
|
+
*/ function checkEnvVars() {
|
|
5625
|
+
// Only collect names, never values (RESKILL_TOKEN is a secret)
|
|
5626
|
+
const vars = [];
|
|
5627
|
+
if (process.env.RESKILL_TOKEN) vars.push('RESKILL_TOKEN');
|
|
5628
|
+
if (process.env.RESKILL_REGISTRY) vars.push('RESKILL_REGISTRY');
|
|
5629
|
+
if (process.env.RESKILL_CACHE_DIR) vars.push('RESKILL_CACHE_DIR');
|
|
5630
|
+
if (0 === vars.length) return {
|
|
5631
|
+
name: 'Environment vars',
|
|
5632
|
+
status: 'ok',
|
|
5633
|
+
message: 'none set'
|
|
5634
|
+
};
|
|
5635
|
+
return {
|
|
5636
|
+
name: 'Environment vars',
|
|
5637
|
+
status: 'ok',
|
|
5638
|
+
message: `${vars.join(', ')} set`
|
|
5639
|
+
};
|
|
5640
|
+
}
|
|
5399
5641
|
/**
|
|
5400
5642
|
* Check cache directory
|
|
5401
5643
|
*/ function checkCacheDir() {
|
|
@@ -5487,12 +5729,21 @@ class RegistryResolver {
|
|
|
5487
5729
|
try {
|
|
5488
5730
|
const config = configLoader.load();
|
|
5489
5731
|
const registries = config.registries || {};
|
|
5490
|
-
for (const name of Object.
|
|
5491
|
-
name
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5732
|
+
for (const [name, url] of Object.entries(registries)){
|
|
5733
|
+
if (RESERVED_REGISTRIES.includes(name.toLowerCase())) results.push({
|
|
5734
|
+
name: 'Registry conflict',
|
|
5735
|
+
status: 'warn',
|
|
5736
|
+
message: `"${name}" overrides built-in registry`,
|
|
5737
|
+
hint: 'Consider using a different name for custom registries'
|
|
5738
|
+
});
|
|
5739
|
+
// Validate URL format
|
|
5740
|
+
if ('string' == typeof url && !/^https?:\/\//.test(url)) results.push({
|
|
5741
|
+
name: 'Invalid registry URL',
|
|
5742
|
+
status: 'error',
|
|
5743
|
+
message: `"${name}": "${url}" is not a valid URL`,
|
|
5744
|
+
hint: 'Registry URLs must start with http:// or https://'
|
|
5745
|
+
});
|
|
5746
|
+
}
|
|
5496
5747
|
} catch {
|
|
5497
5748
|
// Ignore parse errors, handled by checkSkillsJson
|
|
5498
5749
|
}
|
|
@@ -5527,6 +5778,46 @@ class RegistryResolver {
|
|
|
5527
5778
|
}
|
|
5528
5779
|
return null;
|
|
5529
5780
|
}
|
|
5781
|
+
/**
|
|
5782
|
+
* Check for invalid installMode configuration
|
|
5783
|
+
*/ function checkInstallMode(cwd) {
|
|
5784
|
+
const configLoader = new ConfigLoader(cwd);
|
|
5785
|
+
if (!configLoader.exists()) return null;
|
|
5786
|
+
try {
|
|
5787
|
+
const defaults = configLoader.getDefaults();
|
|
5788
|
+
const installMode = defaults.installMode;
|
|
5789
|
+
if (!installMode) return null;
|
|
5790
|
+
if (!VALID_INSTALL_MODES.includes(installMode)) return {
|
|
5791
|
+
name: 'Invalid installMode',
|
|
5792
|
+
status: 'error',
|
|
5793
|
+
message: `"${installMode}" is not a valid install mode`,
|
|
5794
|
+
hint: 'Valid values: symlink, copy'
|
|
5795
|
+
};
|
|
5796
|
+
} catch {
|
|
5797
|
+
// Ignore parse errors
|
|
5798
|
+
}
|
|
5799
|
+
return null;
|
|
5800
|
+
}
|
|
5801
|
+
/**
|
|
5802
|
+
* Check for invalid publishRegistry configuration
|
|
5803
|
+
*/ function checkPublishRegistry(cwd) {
|
|
5804
|
+
const configLoader = new ConfigLoader(cwd);
|
|
5805
|
+
if (!configLoader.exists()) return null;
|
|
5806
|
+
try {
|
|
5807
|
+
const defaults = configLoader.getDefaults();
|
|
5808
|
+
const publishRegistry = defaults.publishRegistry;
|
|
5809
|
+
if (!publishRegistry) return null;
|
|
5810
|
+
if (!/^https?:\/\//.test(publishRegistry)) return {
|
|
5811
|
+
name: 'Invalid publishRegistry',
|
|
5812
|
+
status: 'warn',
|
|
5813
|
+
message: `"${publishRegistry}" is not a valid URL`,
|
|
5814
|
+
hint: 'publishRegistry must start with http:// or https://'
|
|
5815
|
+
};
|
|
5816
|
+
} catch {
|
|
5817
|
+
// Ignore parse errors
|
|
5818
|
+
}
|
|
5819
|
+
return null;
|
|
5820
|
+
}
|
|
5530
5821
|
/**
|
|
5531
5822
|
* Check for invalid targetAgents configuration
|
|
5532
5823
|
*/ function checkTargetAgents(cwd) {
|
|
@@ -5663,6 +5954,15 @@ class RegistryResolver {
|
|
|
5663
5954
|
hint: 'Run: reskill install'
|
|
5664
5955
|
};
|
|
5665
5956
|
}
|
|
5957
|
+
// Check lockfile version compatibility before sync check
|
|
5958
|
+
// If version is unsupported, sync results would be meaningless
|
|
5959
|
+
const lockData = lockManager.load();
|
|
5960
|
+
if (lockData.lockfileVersion !== LOCKFILE_VERSION) return {
|
|
5961
|
+
name: 'skills.lock',
|
|
5962
|
+
status: 'warn',
|
|
5963
|
+
message: `unsupported lockfile version: ${lockData.lockfileVersion}`,
|
|
5964
|
+
hint: 'Run: reskill install to regenerate'
|
|
5965
|
+
};
|
|
5666
5966
|
// Check if lock is in sync with config
|
|
5667
5967
|
const configSkills = configLoader.getSkills();
|
|
5668
5968
|
const lockedSkills = lockManager.getAll();
|
|
@@ -5773,6 +6073,66 @@ class RegistryResolver {
|
|
|
5773
6073
|
}
|
|
5774
6074
|
return results;
|
|
5775
6075
|
}
|
|
6076
|
+
/**
|
|
6077
|
+
* Check detected agents
|
|
6078
|
+
*/ async function checkDetectedAgents() {
|
|
6079
|
+
try {
|
|
6080
|
+
const installed = await detectInstalledAgents();
|
|
6081
|
+
if (0 === installed.length) return {
|
|
6082
|
+
name: 'Detected agents',
|
|
6083
|
+
status: 'ok',
|
|
6084
|
+
message: 'none detected'
|
|
6085
|
+
};
|
|
6086
|
+
return {
|
|
6087
|
+
name: 'Detected agents',
|
|
6088
|
+
status: 'ok',
|
|
6089
|
+
message: `${installed.length} detected: ${installed.join(', ')}`
|
|
6090
|
+
};
|
|
6091
|
+
} catch {
|
|
6092
|
+
return {
|
|
6093
|
+
name: 'Detected agents',
|
|
6094
|
+
status: 'warn',
|
|
6095
|
+
message: 'detection failed'
|
|
6096
|
+
};
|
|
6097
|
+
}
|
|
6098
|
+
}
|
|
6099
|
+
/**
|
|
6100
|
+
* Normalize a URL to its origin for comparison.
|
|
6101
|
+
* Handles trailing slashes and case differences (e.g., GITHUB.COM → github.com).
|
|
6102
|
+
*/ function normalizeUrlOrigin(url) {
|
|
6103
|
+
try {
|
|
6104
|
+
return new URL(url).origin;
|
|
6105
|
+
} catch {
|
|
6106
|
+
return url;
|
|
6107
|
+
}
|
|
6108
|
+
}
|
|
6109
|
+
/**
|
|
6110
|
+
* Get custom registry URLs for network checks
|
|
6111
|
+
*
|
|
6112
|
+
* Reads registries from skills.json and publishRegistry,
|
|
6113
|
+
* excluding built-in github.com/gitlab.com and deduplicating.
|
|
6114
|
+
*/ function getCustomRegistryUrls(cwd) {
|
|
6115
|
+
const urls = new Set();
|
|
6116
|
+
const builtinOrigins = new Set(Object.values(DEFAULT_REGISTRIES).map((u)=>normalizeUrlOrigin(u)));
|
|
6117
|
+
try {
|
|
6118
|
+
const configLoader = new ConfigLoader(cwd);
|
|
6119
|
+
if (!configLoader.exists()) return [];
|
|
6120
|
+
// Collect custom registry URLs
|
|
6121
|
+
const config = configLoader.load();
|
|
6122
|
+
const registries = config.registries || {};
|
|
6123
|
+
for (const url of Object.values(registries))if ('string' == typeof url && /^https?:\/\//.test(url) && !builtinOrigins.has(normalizeUrlOrigin(url))) urls.add(url);
|
|
6124
|
+
// Collect publishRegistry
|
|
6125
|
+
const defaults = configLoader.getDefaults();
|
|
6126
|
+
if (defaults.publishRegistry && /^https?:\/\//.test(defaults.publishRegistry)) {
|
|
6127
|
+
if (!builtinOrigins.has(normalizeUrlOrigin(defaults.publishRegistry))) urls.add(defaults.publishRegistry);
|
|
6128
|
+
}
|
|
6129
|
+
} catch {
|
|
6130
|
+
// Ignore errors
|
|
6131
|
+
}
|
|
6132
|
+
return [
|
|
6133
|
+
...urls
|
|
6134
|
+
];
|
|
6135
|
+
}
|
|
5776
6136
|
/**
|
|
5777
6137
|
* Check network connectivity
|
|
5778
6138
|
*/ async function checkNetwork(host) {
|
|
@@ -5819,23 +6179,32 @@ class RegistryResolver {
|
|
|
5819
6179
|
*/ async function runDoctorChecks(options) {
|
|
5820
6180
|
const { cwd, packageName, packageVersion, skipNetwork, skipConfigChecks } = options;
|
|
5821
6181
|
const results = [];
|
|
5822
|
-
//
|
|
6182
|
+
// Environment checks
|
|
5823
6183
|
results.push(await checkReskillVersion(packageVersion, packageName));
|
|
5824
6184
|
results.push(checkNodeVersion());
|
|
5825
6185
|
results.push(checkGitVersion());
|
|
5826
6186
|
results.push(checkGitAuth());
|
|
6187
|
+
results.push(checkAuthStatus());
|
|
6188
|
+
results.push(checkEnvVars());
|
|
5827
6189
|
// Directory checks
|
|
5828
6190
|
results.push(checkCacheDir());
|
|
5829
6191
|
results.push(checkSkillsJson(cwd));
|
|
5830
6192
|
results.push(checkSkillsLock(cwd));
|
|
5831
6193
|
results.push(...checkInstalledSkills(cwd));
|
|
6194
|
+
results.push(await checkDetectedAgents());
|
|
5832
6195
|
// Deep config checks (can be skipped for faster checks)
|
|
5833
6196
|
if (!skipConfigChecks) {
|
|
5834
|
-
// Registry conflicts
|
|
6197
|
+
// Registry conflicts + URL validation
|
|
5835
6198
|
results.push(...checkRegistryConflicts(cwd));
|
|
5836
6199
|
// installDir validation
|
|
5837
6200
|
const installDirCheck = checkInstallDir(cwd);
|
|
5838
6201
|
if (installDirCheck) results.push(installDirCheck);
|
|
6202
|
+
// installMode validation
|
|
6203
|
+
const installModeCheck = checkInstallMode(cwd);
|
|
6204
|
+
if (installModeCheck) results.push(installModeCheck);
|
|
6205
|
+
// publishRegistry validation
|
|
6206
|
+
const publishRegistryCheck = checkPublishRegistry(cwd);
|
|
6207
|
+
if (publishRegistryCheck) results.push(publishRegistryCheck);
|
|
5839
6208
|
// targetAgents validation
|
|
5840
6209
|
results.push(...checkTargetAgents(cwd));
|
|
5841
6210
|
// Skill reference format validation
|
|
@@ -5847,6 +6216,9 @@ class RegistryResolver {
|
|
|
5847
6216
|
if (!skipNetwork) {
|
|
5848
6217
|
results.push(await checkNetwork('https://github.com'));
|
|
5849
6218
|
results.push(await checkNetwork('https://gitlab.com'));
|
|
6219
|
+
// Custom registry connectivity
|
|
6220
|
+
const customUrls = getCustomRegistryUrls(cwd);
|
|
6221
|
+
for (const url of customUrls)results.push(await checkNetwork(url));
|
|
5850
6222
|
}
|
|
5851
6223
|
return results;
|
|
5852
6224
|
}
|
|
@@ -6143,133 +6515,6 @@ const DEFAULT_INSTALL_DIR = '.skills';
|
|
|
6143
6515
|
// Display summary (use options.installDir directly since we just set it)
|
|
6144
6516
|
displayConfigSummary(options.installDir);
|
|
6145
6517
|
});
|
|
6146
|
-
/**
|
|
6147
|
-
* AuthManager - Handle authentication token management
|
|
6148
|
-
*
|
|
6149
|
-
* Manages tokens for registry authentication.
|
|
6150
|
-
* Tokens are stored in ~/.reskillrc or via RESKILL_TOKEN environment variable.
|
|
6151
|
-
*/ // ============================================================================
|
|
6152
|
-
// Constants
|
|
6153
|
-
// ============================================================================
|
|
6154
|
-
const CONFIG_FILE_NAME = '.reskillrc';
|
|
6155
|
-
// ============================================================================
|
|
6156
|
-
// AuthManager Class
|
|
6157
|
-
// ============================================================================
|
|
6158
|
-
class AuthManager {
|
|
6159
|
-
configPath;
|
|
6160
|
-
constructor(){
|
|
6161
|
-
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
6162
|
-
this.configPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, CONFIG_FILE_NAME);
|
|
6163
|
-
}
|
|
6164
|
-
/**
|
|
6165
|
-
* Get the default registry URL from environment variable
|
|
6166
|
-
*
|
|
6167
|
-
* Returns undefined if no registry is configured - there is no hardcoded default
|
|
6168
|
-
* to prevent accidental publishing to unintended registries.
|
|
6169
|
-
*/ getDefaultRegistry() {
|
|
6170
|
-
return process.env.RESKILL_REGISTRY;
|
|
6171
|
-
}
|
|
6172
|
-
/**
|
|
6173
|
-
* Get path to config file
|
|
6174
|
-
*/ getConfigPath() {
|
|
6175
|
-
return this.configPath;
|
|
6176
|
-
}
|
|
6177
|
-
/**
|
|
6178
|
-
* Get token for a registry
|
|
6179
|
-
*
|
|
6180
|
-
* Priority:
|
|
6181
|
-
* 1. RESKILL_TOKEN environment variable
|
|
6182
|
-
* 2. Token from ~/.reskillrc for the specified registry
|
|
6183
|
-
*/ getToken(registry) {
|
|
6184
|
-
// Check environment variable first
|
|
6185
|
-
const envToken = process.env.RESKILL_TOKEN;
|
|
6186
|
-
if (envToken) return envToken;
|
|
6187
|
-
// Read from config file
|
|
6188
|
-
const config = this.readConfig();
|
|
6189
|
-
if (!config?.registries) return;
|
|
6190
|
-
const targetRegistry = registry || this.getDefaultRegistry();
|
|
6191
|
-
if (!targetRegistry) return;
|
|
6192
|
-
const auth = config.registries[targetRegistry];
|
|
6193
|
-
return auth?.token;
|
|
6194
|
-
}
|
|
6195
|
-
/**
|
|
6196
|
-
* Check if token exists for a registry
|
|
6197
|
-
*/ hasToken(registry) {
|
|
6198
|
-
return void 0 !== this.getToken(registry);
|
|
6199
|
-
}
|
|
6200
|
-
/**
|
|
6201
|
-
* Get email for a registry
|
|
6202
|
-
*/ getEmail(registry) {
|
|
6203
|
-
const config = this.readConfig();
|
|
6204
|
-
if (!config?.registries) return;
|
|
6205
|
-
const targetRegistry = registry || this.getDefaultRegistry();
|
|
6206
|
-
if (!targetRegistry) return;
|
|
6207
|
-
const auth = config.registries[targetRegistry];
|
|
6208
|
-
return auth?.email;
|
|
6209
|
-
}
|
|
6210
|
-
/**
|
|
6211
|
-
* Get handle for a registry
|
|
6212
|
-
*/ getHandle(registry) {
|
|
6213
|
-
const config = this.readConfig();
|
|
6214
|
-
if (!config?.registries) return;
|
|
6215
|
-
const targetRegistry = registry || this.getDefaultRegistry();
|
|
6216
|
-
if (!targetRegistry) return;
|
|
6217
|
-
const auth = config.registries[targetRegistry];
|
|
6218
|
-
return auth?.handle;
|
|
6219
|
-
}
|
|
6220
|
-
/**
|
|
6221
|
-
* Set token for a registry
|
|
6222
|
-
*
|
|
6223
|
-
* Note: When no registry is specified and RESKILL_REGISTRY env var is not set,
|
|
6224
|
-
* this method will throw an error. The calling code should ensure a registry
|
|
6225
|
-
* is always provided (either explicitly or via environment variable).
|
|
6226
|
-
*/ setToken(token, registry, email, handle) {
|
|
6227
|
-
const config = this.readConfig() || {};
|
|
6228
|
-
const targetRegistry = registry || this.getDefaultRegistry();
|
|
6229
|
-
if (!targetRegistry) throw new Error('No registry specified. Set RESKILL_REGISTRY environment variable or provide registry explicitly.');
|
|
6230
|
-
if (!config.registries) config.registries = {};
|
|
6231
|
-
config.registries[targetRegistry] = {
|
|
6232
|
-
token,
|
|
6233
|
-
...email && {
|
|
6234
|
-
email
|
|
6235
|
-
},
|
|
6236
|
-
...handle && {
|
|
6237
|
-
handle
|
|
6238
|
-
}
|
|
6239
|
-
};
|
|
6240
|
-
this.writeConfig(config);
|
|
6241
|
-
}
|
|
6242
|
-
/**
|
|
6243
|
-
* Remove token for a registry
|
|
6244
|
-
*/ removeToken(registry) {
|
|
6245
|
-
const config = this.readConfig();
|
|
6246
|
-
if (!config?.registries) return;
|
|
6247
|
-
const targetRegistry = registry || this.getDefaultRegistry();
|
|
6248
|
-
if (!targetRegistry) return;
|
|
6249
|
-
delete config.registries[targetRegistry];
|
|
6250
|
-
this.writeConfig(config);
|
|
6251
|
-
}
|
|
6252
|
-
/**
|
|
6253
|
-
* Read config file
|
|
6254
|
-
*/ readConfig() {
|
|
6255
|
-
try {
|
|
6256
|
-
if (!external_node_fs_.existsSync(this.configPath)) return null;
|
|
6257
|
-
const content = external_node_fs_.readFileSync(this.configPath, 'utf-8');
|
|
6258
|
-
if (!content.trim()) return null;
|
|
6259
|
-
return JSON.parse(content);
|
|
6260
|
-
} catch {
|
|
6261
|
-
return null;
|
|
6262
|
-
}
|
|
6263
|
-
}
|
|
6264
|
-
/**
|
|
6265
|
-
* Write config file
|
|
6266
|
-
*/ writeConfig(config) {
|
|
6267
|
-
const content = JSON.stringify(config, null, 2);
|
|
6268
|
-
external_node_fs_.writeFileSync(this.configPath, content, {
|
|
6269
|
-
mode: 384
|
|
6270
|
-
});
|
|
6271
|
-
}
|
|
6272
|
-
}
|
|
6273
6518
|
// ============================================================================
|
|
6274
6519
|
// Utility Functions
|
|
6275
6520
|
// ============================================================================
|
|
@@ -6540,6 +6785,18 @@ class AuthManager {
|
|
|
6540
6785
|
const { skills, options, configLoader, skipConfirm } = ctx;
|
|
6541
6786
|
const skill = skills[0];
|
|
6542
6787
|
const cwd = process.cwd();
|
|
6788
|
+
const skillManager = new SkillManager(void 0, {
|
|
6789
|
+
global: installGlobally
|
|
6790
|
+
});
|
|
6791
|
+
// Detect whether the ref points to a multi-skill directory
|
|
6792
|
+
spinner.start('Resolving skill...');
|
|
6793
|
+
const detection = await skillManager.detectSkillsInRef(skill);
|
|
6794
|
+
spinner.stop('Resolved');
|
|
6795
|
+
if ('multi' === detection.type) {
|
|
6796
|
+
await installAutoDetectedMultiSkill(skill, detection.skills, ctx, skillManager, targetAgents, installGlobally, installMode, spinner);
|
|
6797
|
+
return;
|
|
6798
|
+
}
|
|
6799
|
+
// --- Single skill path (existing behaviour) ---
|
|
6543
6800
|
// Show installation summary
|
|
6544
6801
|
const summaryLines = [
|
|
6545
6802
|
__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(skill),
|
|
@@ -6559,9 +6816,6 @@ class AuthManager {
|
|
|
6559
6816
|
}
|
|
6560
6817
|
// Execute installation
|
|
6561
6818
|
spinner.start(`Installing ${skill}...`);
|
|
6562
|
-
const skillManager = new SkillManager(void 0, {
|
|
6563
|
-
global: installGlobally
|
|
6564
|
-
});
|
|
6565
6819
|
const { skill: installed, results } = await skillManager.installToAgents(skill, targetAgents, {
|
|
6566
6820
|
force: options.force,
|
|
6567
6821
|
save: false !== options.save && !installGlobally,
|
|
@@ -6583,6 +6837,67 @@ class AuthManager {
|
|
|
6583
6837
|
});
|
|
6584
6838
|
}
|
|
6585
6839
|
}
|
|
6840
|
+
/**
|
|
6841
|
+
* Handle auto-detected multi-skill directory: show summary, confirm, install all.
|
|
6842
|
+
*
|
|
6843
|
+
* Called when `detectSkillsInRef` discovers that the ref points to a parent
|
|
6844
|
+
* directory (no SKILL.md at root) containing multiple child skills.
|
|
6845
|
+
*/ async function installAutoDetectedMultiSkill(ref, discoveredSkills, ctx, skillManager, targetAgents, installGlobally, installMode, spinner) {
|
|
6846
|
+
const { options, configLoader, skipConfirm } = ctx;
|
|
6847
|
+
const skillNames = discoveredSkills.map((s)=>s.name);
|
|
6848
|
+
// Show discovered skills
|
|
6849
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.step(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].bold(`Found ${discoveredSkills.length} skill(s)`));
|
|
6850
|
+
for (const s of discoveredSkills)__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.message(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(s.name)}${s.description ? ` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(s.description)}` : ''}`);
|
|
6851
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.message('');
|
|
6852
|
+
// Show installation summary
|
|
6853
|
+
const summaryLines = [
|
|
6854
|
+
__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(ref),
|
|
6855
|
+
` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('→')} ${formatAgentNames(targetAgents)}`,
|
|
6856
|
+
` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('Skills:')} ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].cyan(skillNames.join(', '))}`,
|
|
6857
|
+
` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('Scope:')} ${installGlobally ? 'Global' : 'Project'}${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(', Mode:')} ${installMode}`
|
|
6858
|
+
];
|
|
6859
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.note(summaryLines.join('\n'), 'Multi-Skill Install');
|
|
6860
|
+
// Confirm
|
|
6861
|
+
if (!skipConfirm) {
|
|
6862
|
+
const confirmed = await __WEBPACK_EXTERNAL_MODULE__clack_prompts__.confirm({
|
|
6863
|
+
message: 'Install all discovered skills?'
|
|
6864
|
+
});
|
|
6865
|
+
if (__WEBPACK_EXTERNAL_MODULE__clack_prompts__.isCancel(confirmed) || !confirmed) {
|
|
6866
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.cancel('Installation cancelled');
|
|
6867
|
+
process.exit(0);
|
|
6868
|
+
}
|
|
6869
|
+
}
|
|
6870
|
+
// Install all discovered skills (empty skillNames = install all)
|
|
6871
|
+
spinner.start('Installing skills...');
|
|
6872
|
+
const result = await skillManager.installSkillsFromRepo(ref, [], targetAgents, {
|
|
6873
|
+
force: options.force,
|
|
6874
|
+
save: false !== options.save && !installGlobally,
|
|
6875
|
+
mode: installMode,
|
|
6876
|
+
registry: options.registry,
|
|
6877
|
+
token: options.token
|
|
6878
|
+
});
|
|
6879
|
+
spinner.stop('Installation complete');
|
|
6880
|
+
if (result.listOnly) return;
|
|
6881
|
+
const { installed, skipped } = result;
|
|
6882
|
+
// Display results
|
|
6883
|
+
if (0 === installed.length && skipped.length > 0) {
|
|
6884
|
+
const skipLines = skipped.map((s)=>` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('–')} ${s.name}: ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(s.reason)}`);
|
|
6885
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.note(skipLines.join('\n'), __WEBPACK_EXTERNAL_MODULE_chalk__["default"].yellow('All skills were already installed'));
|
|
6886
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.log.info('Use --force to reinstall.');
|
|
6887
|
+
return;
|
|
6888
|
+
}
|
|
6889
|
+
const resultLines = installed.map((r)=>` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].green('✓')} ${r.skill.name}@${r.skill.version}`);
|
|
6890
|
+
if (skipped.length > 0) for (const s of skipped)resultLines.push(` ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim('–')} ${s.name}: ${__WEBPACK_EXTERNAL_MODULE_chalk__["default"].dim(s.reason)}`);
|
|
6891
|
+
__WEBPACK_EXTERNAL_MODULE__clack_prompts__.note(resultLines.join('\n'), __WEBPACK_EXTERNAL_MODULE_chalk__["default"].green(`Installed ${installed.length} skill(s)`));
|
|
6892
|
+
// Save installation defaults
|
|
6893
|
+
if (!installGlobally && installed.length > 0 && configLoader.exists()) {
|
|
6894
|
+
configLoader.reload();
|
|
6895
|
+
configLoader.updateDefaults({
|
|
6896
|
+
targetAgents,
|
|
6897
|
+
installMode
|
|
6898
|
+
});
|
|
6899
|
+
}
|
|
6900
|
+
}
|
|
6586
6901
|
/**
|
|
6587
6902
|
* Multi-skill path: list or install selected skills from a single repo (--skill / --list)
|
|
6588
6903
|
*/ async function installMultiSkillFromRepo(ref, skillNames, listOnly, ctx, targetAgents, installGlobally, installMode, spinner) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lock-manager.d.ts","sourceRoot":"","sources":["../../src/core/lock-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"lock-manager.d.ts","sourceRoot":"","sources":["../../src/core/lock-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGjE;;GAEG;AACH,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC;;;;GAIG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAA2B;gBAE/B,WAAW,CAAC,EAAE,MAAM;IAKhC;;OAEG;IACH,WAAW,IAAI,MAAM;IAIrB;;OAEG;IACH,MAAM,IAAI,OAAO;IAIjB;;OAEG;IACH,IAAI,IAAI,UAAU;IAsBlB;;OAEG;IACH,MAAM,IAAI,UAAU;IAKpB;;OAEG;IACH,IAAI,CAAC,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI;IASnC;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAK1C;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI;IAM3C;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAU7B;;OAEG;IACH,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GACA,WAAW;IAmBd;;OAEG;IACH,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;IAKrC;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAK1B;;OAEG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAQtD;;OAEG;IACH,KAAK,IAAI,IAAI;IAQb;;OAEG;IACH,MAAM,IAAI,IAAI;CAOf;AAED,eAAe,WAAW,CAAC"}
|
|
@@ -180,6 +180,23 @@ export declare class SkillManager {
|
|
|
180
180
|
latest: string;
|
|
181
181
|
updateAvailable: boolean;
|
|
182
182
|
}>>;
|
|
183
|
+
/**
|
|
184
|
+
* Detect whether a ref points to a single skill or a multi-skill directory.
|
|
185
|
+
*
|
|
186
|
+
* Returns `{ type: 'single' }` when the cached root contains a SKILL.md (or
|
|
187
|
+
* when the source is registry/HTTP — those are always single-skill).
|
|
188
|
+
* Returns `{ type: 'multi', skills }` when the root has **no** SKILL.md but
|
|
189
|
+
* `discoverSkillsInDir()` finds child skills underneath.
|
|
190
|
+
*
|
|
191
|
+
* The method caches the repo as a side-effect so that the subsequent
|
|
192
|
+
* `installToAgents` / `installSkillsFromRepo` call hits the cache.
|
|
193
|
+
*/
|
|
194
|
+
detectSkillsInRef(ref: string): Promise<{
|
|
195
|
+
type: 'single';
|
|
196
|
+
} | {
|
|
197
|
+
type: 'multi';
|
|
198
|
+
skills: ParsedSkillWithPath[];
|
|
199
|
+
}>;
|
|
183
200
|
/**
|
|
184
201
|
* Install skill to multiple agents
|
|
185
202
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-manager.d.ts","sourceRoot":"","sources":["../../src/core/skill-manager.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"skill-manager.d.ts","sourceRoot":"","sources":["../../src/core/skill-manager.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -4333,6 +4333,54 @@ class RegistryResolver {
|
|
|
4333
4333
|
// Multi-Agent installation methods
|
|
4334
4334
|
// ============================================================================
|
|
4335
4335
|
/**
|
|
4336
|
+
* Detect whether a ref points to a single skill or a multi-skill directory.
|
|
4337
|
+
*
|
|
4338
|
+
* Returns `{ type: 'single' }` when the cached root contains a SKILL.md (or
|
|
4339
|
+
* when the source is registry/HTTP — those are always single-skill).
|
|
4340
|
+
* Returns `{ type: 'multi', skills }` when the root has **no** SKILL.md but
|
|
4341
|
+
* `discoverSkillsInDir()` finds child skills underneath.
|
|
4342
|
+
*
|
|
4343
|
+
* The method caches the repo as a side-effect so that the subsequent
|
|
4344
|
+
* `installToAgents` / `installSkillsFromRepo` call hits the cache.
|
|
4345
|
+
*/ async detectSkillsInRef(ref) {
|
|
4346
|
+
// Only Git refs can be multi-skill directories
|
|
4347
|
+
if (this.isRegistrySource(ref) || this.isHttpSource(ref)) return {
|
|
4348
|
+
type: 'single'
|
|
4349
|
+
};
|
|
4350
|
+
const resolved = await this.resolver.resolve(ref);
|
|
4351
|
+
const { parsed } = resolved;
|
|
4352
|
+
const gitRef = resolved.ref;
|
|
4353
|
+
// Ensure the repo is cached (result unused — we only need the side-effect)
|
|
4354
|
+
if (!await this.cache.get(parsed, gitRef)) await this.cache.cache(resolved.repoUrl, parsed, gitRef, gitRef);
|
|
4355
|
+
const cachePath = this.cache.getCachePath(parsed, gitRef);
|
|
4356
|
+
// When parsed.skillName is set (ref has #fragment), resolve to the
|
|
4357
|
+
// specific skill subdirectory so we check the right SKILL.md.
|
|
4358
|
+
const sourcePath = this.resolveSourcePath(cachePath, parsed);
|
|
4359
|
+
const metadata = this.getSkillMetadataFromDir(sourcePath);
|
|
4360
|
+
if (metadata) return {
|
|
4361
|
+
type: 'single'
|
|
4362
|
+
};
|
|
4363
|
+
// No SKILL.md at root — check for child skills.
|
|
4364
|
+
// cachePath is correct here (not sourcePath) for two reasons:
|
|
4365
|
+
// 1. When parsed.skillName is set, resolveSourcePath() either returns a
|
|
4366
|
+
// subdirectory (→ metadata found → already returned 'single' above) or
|
|
4367
|
+
// throws (skill not found). So we never reach this line with
|
|
4368
|
+
// sourcePath ≠ cachePath.
|
|
4369
|
+
// 2. When parsed.subPath is set, CacheManager.cache() already copies only
|
|
4370
|
+
// the subPath subdirectory into cachePath, so discovery is scoped to
|
|
4371
|
+
// the intended directory automatically.
|
|
4372
|
+
const discovered = discoverSkillsInDir(cachePath);
|
|
4373
|
+
if (discovered.length > 0) return {
|
|
4374
|
+
type: 'multi',
|
|
4375
|
+
skills: discovered
|
|
4376
|
+
};
|
|
4377
|
+
// No skills found at all. Return 'single' so the caller proceeds to
|
|
4378
|
+
// installToAgents, which will produce a clear error ("no SKILL.md found").
|
|
4379
|
+
return {
|
|
4380
|
+
type: 'single'
|
|
4381
|
+
};
|
|
4382
|
+
}
|
|
4383
|
+
/**
|
|
4336
4384
|
* Install skill to multiple agents
|
|
4337
4385
|
*
|
|
4338
4386
|
* @param ref - Skill reference (e.g., github:user/repo@v1.0.0 or HTTP URL)
|