reskill 1.10.0 → 1.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -97,6 +97,10 @@ export declare class ConfigLoader {
97
97
  * @param updates - Partial defaults to merge
98
98
  */
99
99
  updateDefaults(updates: Partial<SkillsDefaults>): void;
100
+ /**
101
+ * Get all configured registries (custom + default).
102
+ */
103
+ getRegistries(): Record<string, string>;
100
104
  /**
101
105
  * Get registry URL by name
102
106
  *
@@ -1 +1 @@
1
- {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/core/config-loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAiCpE;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAGrD,CAAC;AAMF;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,MAAM,CAA2B;gBAE7B,WAAW,CAAC,EAAE,MAAM;IAShC;;OAEG;IACH,cAAc,IAAI,MAAM;IAIxB;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,aAAa,IAAI,MAAM;IASvB;;OAEG;IACH,MAAM,IAAI,OAAO;IAIjB;;;;OAIG;IACH,IAAI,IAAI,UAAU;IAiBlB;;OAEG;IACH,MAAM,IAAI,UAAU;IAKpB;;;;;OAKG;IACH,IAAI,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI;IAS/B;;;;OAIG;IACH,YAAY,IAAI,OAAO;IAQvB;;;;OAIG;IACH,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU;IAwBjD;;;;;;OAMG;IACH,WAAW,IAAI,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,iBAAiB,CAAC,GAAG;QACjE,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;KACrC;IAYD;;;;;;OAMG;IACH,kBAAkB,IAAI,MAAM,GAAG,SAAS;IAKxC;;;;;;OAMG;IACH,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI;IAgBtD;;;;;;;OAOG;IACH,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAiB5C;;;;;;;;OAQG;IACH,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IA2BnD;;;;;;;;;OASG;IACH,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAoBtC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAuCzB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA8B1B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAgBzC;;;;;;;;;;OAUG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAiB5C;;;;;;;OAOG;IACH,OAAO,CAAC,sBAAsB;IAa9B;;;;OAIG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAWlC;;OAEG;IACH,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAUnC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAK/B;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAS7C;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAU1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAK3B;AAED,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/core/config-loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAiCpE;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAGrD,CAAC;AAMF;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,MAAM,CAA2B;gBAE7B,WAAW,CAAC,EAAE,MAAM;IAShC;;OAEG;IACH,cAAc,IAAI,MAAM;IAIxB;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,aAAa,IAAI,MAAM;IASvB;;OAEG;IACH,MAAM,IAAI,OAAO;IAIjB;;;;OAIG;IACH,IAAI,IAAI,UAAU;IAiBlB;;OAEG;IACH,MAAM,IAAI,UAAU;IAKpB;;;;;OAKG;IACH,IAAI,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI;IAS/B;;;;OAIG;IACH,YAAY,IAAI,OAAO;IAQvB;;;;OAIG;IACH,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU;IAwBjD;;;;;;OAMG;IACH,WAAW,IAAI,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,iBAAiB,CAAC,GAAG;QACjE,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;KACrC;IAYD;;;;;;OAMG;IACH,kBAAkB,IAAI,MAAM,GAAG,SAAS;IAKxC;;;;;;OAMG;IACH,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI;IAgBtD;;OAEG;IACH,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAQvC;;;;;;;OAOG;IACH,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAiB5C;;;;;;;;OAQG;IACH,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IA2BnD;;;;;;;;;OASG;IACH,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAoBtC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAuCzB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA8B1B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAgBzC;;;;;;;;;;OAUG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAiB5C;;;;;;;OAOG;IACH,OAAO,CAAC,sBAAsB;IAa9B;;;;OAIG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAWlC;;OAEG;IACH,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAUnC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAK/B;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAS7C;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAU1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAK3B;AAED,eAAe,YAAY,CAAC"}
@@ -50,6 +50,7 @@ export declare class LockManager {
50
50
  ref: string;
51
51
  resolved: string;
52
52
  commit: string;
53
+ registry?: string;
53
54
  }): LockedSkill;
54
55
  /**
55
56
  * Get all locked skills
@@ -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;AAQjE;;;;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;KAChB,GACA,WAAW;IAcd;;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"}
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;AAQjE;;;;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"}
@@ -7,7 +7,7 @@ import { type ParsedSkillWithPath } from './skill-parser.js';
7
7
  * SkillManager configuration options
8
8
  */
9
9
  export interface SkillManagerOptions {
10
- /** Global mode, install to ~/.claude/skills */
10
+ /** Global mode, install to ~/.agents/skills/ */
11
11
  global?: boolean;
12
12
  }
13
13
  /**
@@ -17,8 +17,8 @@ export interface SkillManagerOptions {
17
17
  * Provides complete skill installation, update, and uninstall functionality
18
18
  *
19
19
  * Installation directories:
20
- * - Project mode (default): .skills/ or directory configured in skills.json
21
- * - Global mode (-g): ~/.claude/skills/
20
+ * - Project mode (default): .agents/skills/ (canonical) or .skills/ (legacy)
21
+ * - Global mode (-g): ~/.agents/skills/
22
22
  */
23
23
  export declare class SkillManager {
24
24
  private projectRoot;
@@ -41,7 +41,7 @@ export declare class SkillManager {
41
41
  /**
42
42
  * Get legacy installation directory (for backward compatibility)
43
43
  *
44
- * - Global mode: ~/.claude/skills/
44
+ * - Global mode: ~/.agents/skills/ (canonical)
45
45
  * - Project mode: .skills/ or directory configured in skills.json
46
46
  */
47
47
  getInstallDir(): string;
@@ -113,12 +113,46 @@ export declare class SkillManager {
113
113
  * Update skill
114
114
  */
115
115
  update(name?: string): Promise<InstalledSkill[]>;
116
+ /**
117
+ * Resolve registry URL for a skill reference.
118
+ *
119
+ * Resolution order:
120
+ * 1. Explicit CLI override (options.registry)
121
+ * 2. Scoped skills → getRegistryUrl(scope)
122
+ * 3. Unscoped skills → lock file registry (O(1), no network)
123
+ * 4. Unscoped skills → probe skills.json registries (non-git-host, network)
124
+ * 5. Default → PUBLIC_REGISTRY
125
+ */
126
+ private resolveRegistryUrl;
127
+ /**
128
+ * Check if a registry entry is a git host (github, gitlab, etc.)
129
+ * Git hosts are not skill registries and should be skipped during probe.
130
+ */
131
+ private isGitHostRegistry;
132
+ /**
133
+ * Derive a registry name from a URL for storing in skills.json.registries.
134
+ * Returns null for git hosts (already in DEFAULT_REGISTRIES).
135
+ */
136
+ private deriveRegistryName;
137
+ /**
138
+ * Install skill for update flow. Uses installToAgents so registry refs are
139
+ * routed correctly (Registry > HTTP > Git).
140
+ */
141
+ private installForUpdate;
116
142
  /**
117
143
  * List installed skills
118
144
  *
119
145
  * Checks both canonical (.agents/skills/) and legacy (.skills/) locations.
120
146
  */
121
147
  list(): InstalledSkill[];
148
+ /**
149
+ * Detect which agents have a skill installed (symlink or copy)
150
+ *
151
+ * Scans all known agent directories to check if the skill exists there.
152
+ * Excludes the canonical directory (.agents/skills/) to avoid false positives
153
+ * from agents whose skillsDir overlaps with the canonical path (e.g. amp).
154
+ */
155
+ private detectSkillAgents;
122
156
  /**
123
157
  * Get installed skill information from a specific path
124
158
  */
@@ -209,6 +243,23 @@ export declare class SkillManager {
209
243
  * - local: downloads tarball via Registry API
210
244
  */
211
245
  private installFromWebPublished;
246
+ /**
247
+ * Build a Git ref for web-published github/gitlab skills.
248
+ *
249
+ * When `skillPath` is provided (multi-skill repo), constructs a shorthand ref
250
+ * like `github:owner/repo/skills/my-skill` so that only the sub-directory is
251
+ * cached and installed.
252
+ *
253
+ * Fallback: if `parseGitUrl` fails (non-standard URL), appends `#shortName`
254
+ * as a skill-name selector. The `#` fragment is extracted by
255
+ * `GitResolver.parseRef()` as `parsed.skillName`, then matched against
256
+ * SKILL.md `name` fields via `resolveSourcePath` / `discoverSkillsInDir`.
257
+ * This differs from the subPath approach (directory-based) but works because
258
+ * skill names typically match their directory basenames.
259
+ *
260
+ * Returns the raw `sourceUrl` when no `skillPath` is available.
261
+ */
262
+ private buildGitRefForWebPublished;
212
263
  /**
213
264
  * Install a skill published via "local folder" mode.
214
265
  *
@@ -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
@@ -297,13 +297,6 @@ var external_node_fs_ = __webpack_require__("node:fs");
297
297
  */ function getHomeDir() {
298
298
  return process.env.HOME || process.env.USERPROFILE || '';
299
299
  }
300
- /**
301
- * Get global skills installation directory (~/.claude/skills)
302
- * @deprecated Use getAgentGlobalSkillsDir from agent-registry instead
303
- */ function getGlobalSkillsDir() {
304
- const home = getHomeDir();
305
- return __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.claude', 'skills');
306
- }
307
300
  // ============================================================================
308
301
  // Multi-Agent path utilities
309
302
  // ============================================================================
@@ -1994,6 +1987,15 @@ ${CURSOR_BRIDGE_MARKER}
1994
1987
  // Registry Management
1995
1988
  // ==========================================================================
1996
1989
  /**
1990
+ * Get all configured registries (custom + default).
1991
+ */ getRegistries() {
1992
+ const config = this.getConfigOrDefault();
1993
+ return {
1994
+ ...DEFAULT_REGISTRIES,
1995
+ ...config.registries
1996
+ };
1997
+ }
1998
+ /**
1997
1999
  * Get registry URL by name
1998
2000
  *
1999
2001
  * Resolution order:
@@ -2835,6 +2837,8 @@ ${CURSOR_BRIDGE_MARKER}
2835
2837
  commit: options.commit,
2836
2838
  installedAt: new Date().toISOString()
2837
2839
  };
2840
+ // Only persist registry URL for registry-sourced skills
2841
+ if (options.registry) lockedSkill.registry = options.registry;
2838
2842
  this.set(name, lockedSkill);
2839
2843
  return lockedSkill;
2840
2844
  }
@@ -2899,6 +2903,23 @@ ${CURSOR_BRIDGE_MARKER}
2899
2903
  // Local development
2900
2904
  'http://localhost:3000': '@kanyun-test'
2901
2905
  };
2906
+ /**
2907
+ * Get the scope for a given registry URL
2908
+ *
2909
+ * @param registry - Registry URL
2910
+ * @returns Scope string (e.g., "@kanyun") or null if not found
2911
+ *
2912
+ * @example
2913
+ * getScopeForRegistry('https://rush-test.zhenguanyu.com') // '@kanyun'
2914
+ * getScopeForRegistry('https://unknown.com') // null
2915
+ */ function getScopeForRegistry(registry) {
2916
+ if (!registry) return null;
2917
+ // Try exact match first
2918
+ if (REGISTRY_SCOPE_MAP[registry]) return REGISTRY_SCOPE_MAP[registry];
2919
+ // Try with/without trailing slash
2920
+ const normalized = registry.endsWith('/') ? registry.slice(0, -1) : `${registry}/`;
2921
+ return REGISTRY_SCOPE_MAP[normalized] || null;
2922
+ }
2902
2923
  /**
2903
2924
  * Get the registry URL for a given scope (reverse lookup)
2904
2925
  *
@@ -3736,8 +3757,8 @@ class RegistryResolver {
3736
3757
  * Provides complete skill installation, update, and uninstall functionality
3737
3758
  *
3738
3759
  * Installation directories:
3739
- * - Project mode (default): .skills/ or directory configured in skills.json
3740
- * - Global mode (-g): ~/.claude/skills/
3760
+ * - Project mode (default): .agents/skills/ (canonical) or .skills/ (legacy)
3761
+ * - Global mode (-g): ~/.agents/skills/
3741
3762
  */ class SkillManager {
3742
3763
  projectRoot;
3743
3764
  resolver;
@@ -3771,10 +3792,10 @@ class RegistryResolver {
3771
3792
  /**
3772
3793
  * Get legacy installation directory (for backward compatibility)
3773
3794
  *
3774
- * - Global mode: ~/.claude/skills/
3795
+ * - Global mode: ~/.agents/skills/ (canonical)
3775
3796
  * - Project mode: .skills/ or directory configured in skills.json
3776
3797
  */ getInstallDir() {
3777
- if (this.isGlobal) return getGlobalSkillsDir();
3798
+ if (this.isGlobal) return this.getCanonicalSkillsDir();
3778
3799
  return this.config.getInstallDir();
3779
3800
  }
3780
3801
  /**
@@ -3990,8 +4011,11 @@ class RegistryResolver {
3990
4011
  */ async installAll(options = {}) {
3991
4012
  const skills = this.config.getSkills();
3992
4013
  const installed = [];
4014
+ const targetAgents = await detectInstalledAgents();
3993
4015
  for (const [name, ref] of Object.entries(skills))try {
3994
- const skill = await this.install(ref, {
4016
+ // Use installToAgents (not install) to correctly route registry refs
4017
+ // resolveRegistryUrl inside handles lock file / registries probe fallback
4018
+ const { skill } = await this.installToAgents(ref, targetAgents, {
3995
4019
  ...options,
3996
4020
  save: false
3997
4021
  });
@@ -4037,6 +4061,7 @@ class RegistryResolver {
4037
4061
  * Update skill
4038
4062
  */ async update(name) {
4039
4063
  const updated = [];
4064
+ const targetAgents = await detectInstalledAgents();
4040
4065
  if (name) {
4041
4066
  // Update single skill
4042
4067
  const ref = this.config.getSkillRef(name);
@@ -4044,9 +4069,10 @@ class RegistryResolver {
4044
4069
  logger_logger.error(`Skill ${name} not found in skills.json`);
4045
4070
  return [];
4046
4071
  }
4047
- // Check if update is needed (skip check for HTTP sources - always re-download)
4048
- if (this.isHttpSource(ref)) // For HTTP sources, log that we're re-downloading
4049
- logger_logger.info(`${name} is from HTTP source, re-downloading...`);
4072
+ // Check if update is needed (skip for HTTP and Registry - always re-download/reinstall)
4073
+ const isRegistry = this.isRegistrySource(ref);
4074
+ if (isRegistry) logger_logger.info(`${name} is from registry, re-installing...`);
4075
+ else if (this.isHttpSource(ref)) logger_logger.info(`${name} is from HTTP source, re-downloading...`);
4050
4076
  else {
4051
4077
  const resolved = await this.resolver.resolve(ref);
4052
4078
  const remoteCommit = await this.cache.getRemoteCommit(resolved.repoUrl, resolved.ref);
@@ -4055,7 +4081,7 @@ class RegistryResolver {
4055
4081
  return [];
4056
4082
  }
4057
4083
  }
4058
- const skill = await this.install(ref, {
4084
+ const skill = await this.installForUpdate(ref, targetAgents, {
4059
4085
  force: true,
4060
4086
  save: false
4061
4087
  });
@@ -4064,8 +4090,9 @@ class RegistryResolver {
4064
4090
  // Update all
4065
4091
  const skills = this.config.getSkills();
4066
4092
  for (const [skillName, ref] of Object.entries(skills))try {
4067
- // Check if update is needed (skip check for HTTP sources)
4068
- if (this.isHttpSource(ref)) logger_logger.info(`${skillName} is from HTTP source, re-downloading...`);
4093
+ // Check if update is needed (skip for HTTP and Registry)
4094
+ if (this.isRegistrySource(ref)) logger_logger.info(`${skillName} is from registry, re-installing...`);
4095
+ else if (this.isHttpSource(ref)) logger_logger.info(`${skillName} is from HTTP source, re-downloading...`);
4069
4096
  else {
4070
4097
  const resolved = await this.resolver.resolve(ref);
4071
4098
  const remoteCommit = await this.cache.getRemoteCommit(resolved.repoUrl, resolved.ref);
@@ -4074,7 +4101,7 @@ class RegistryResolver {
4074
4101
  continue;
4075
4102
  }
4076
4103
  }
4077
- const skill = await this.install(ref, {
4104
+ const skill = await this.installForUpdate(ref, targetAgents, {
4078
4105
  force: true,
4079
4106
  save: false
4080
4107
  });
@@ -4086,6 +4113,70 @@ class RegistryResolver {
4086
4113
  return updated;
4087
4114
  }
4088
4115
  /**
4116
+ * Resolve registry URL for a skill reference.
4117
+ *
4118
+ * Resolution order:
4119
+ * 1. Explicit CLI override (options.registry)
4120
+ * 2. Scoped skills → getRegistryUrl(scope)
4121
+ * 3. Unscoped skills → lock file registry (O(1), no network)
4122
+ * 4. Unscoped skills → probe skills.json registries (non-git-host, network)
4123
+ * 5. Default → PUBLIC_REGISTRY
4124
+ */ async resolveRegistryUrl(ref, explicitRegistry) {
4125
+ if (explicitRegistry) return explicitRegistry;
4126
+ const parsed = parseSkillIdentifier(ref);
4127
+ if (parsed.scope) return getRegistryUrl(parsed.scope);
4128
+ // Fast path: lock file has registry URL
4129
+ const locked = this.lockManager.get(parsed.name);
4130
+ if (locked?.registry) return locked.registry;
4131
+ // Slow path: probe configured registries (skip git hosts)
4132
+ const registries = this.config.getRegistries();
4133
+ for (const [name, url] of Object.entries(registries))if (!this.isGitHostRegistry(name, url)) try {
4134
+ const client = new RegistryClient({
4135
+ registry: url
4136
+ });
4137
+ await client.getSkillInfo(parsed.fullName);
4138
+ return url; // Found it
4139
+ } catch {}
4140
+ return getRegistryUrl(null); // PUBLIC_REGISTRY
4141
+ }
4142
+ /**
4143
+ * Check if a registry entry is a git host (github, gitlab, etc.)
4144
+ * Git hosts are not skill registries and should be skipped during probe.
4145
+ */ isGitHostRegistry(name, url) {
4146
+ const gitHostNames = new Set(Object.keys(DEFAULT_REGISTRIES));
4147
+ if (gitHostNames.has(name)) return true;
4148
+ const gitHostPatterns = [
4149
+ 'github.com',
4150
+ 'gitlab.com'
4151
+ ];
4152
+ const normalizedUrl = url.toLowerCase();
4153
+ return gitHostPatterns.some((pattern)=>normalizedUrl.includes(pattern));
4154
+ }
4155
+ /**
4156
+ * Derive a registry name from a URL for storing in skills.json.registries.
4157
+ * Returns null for git hosts (already in DEFAULT_REGISTRIES).
4158
+ */ deriveRegistryName(registryUrl) {
4159
+ // Skip git hosts
4160
+ if (this.isGitHostRegistry('', registryUrl)) return null;
4161
+ // Try known scope mapping first (e.g., kanyun registries)
4162
+ const scope = getScopeForRegistry(registryUrl);
4163
+ if (scope) return scope;
4164
+ // Use hostname as registry name
4165
+ try {
4166
+ const url = new URL(registryUrl);
4167
+ return url.hostname;
4168
+ } catch {
4169
+ return null;
4170
+ }
4171
+ }
4172
+ /**
4173
+ * Install skill for update flow. Uses installToAgents so registry refs are
4174
+ * routed correctly (Registry > HTTP > Git).
4175
+ */ async installForUpdate(ref, targetAgents, options) {
4176
+ const { skill } = await this.installToAgents(ref, targetAgents, options);
4177
+ return skill;
4178
+ }
4179
+ /**
4089
4180
  * List installed skills
4090
4181
  *
4091
4182
  * Checks both canonical (.agents/skills/) and legacy (.skills/) locations.
@@ -4126,6 +4217,24 @@ class RegistryResolver {
4126
4217
  return skills;
4127
4218
  }
4128
4219
  /**
4220
+ * Detect which agents have a skill installed (symlink or copy)
4221
+ *
4222
+ * Scans all known agent directories to check if the skill exists there.
4223
+ * Excludes the canonical directory (.agents/skills/) to avoid false positives
4224
+ * from agents whose skillsDir overlaps with the canonical path (e.g. amp).
4225
+ */ detectSkillAgents(skillName) {
4226
+ const canonicalDir = this.getCanonicalSkillsDir();
4227
+ const installed = [];
4228
+ for (const [type, config] of Object.entries(agents)){
4229
+ const agentBase = this.isGlobal ? config.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.projectRoot, config.skillsDir);
4230
+ // Skip agents whose skillsDir is the canonical directory itself
4231
+ if (__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(agentBase) === __WEBPACK_EXTERNAL_MODULE_node_path__.resolve(canonicalDir)) continue;
4232
+ const agentSkillDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, skillName);
4233
+ if (exists(agentSkillDir)) installed.push(type);
4234
+ }
4235
+ return installed;
4236
+ }
4237
+ /**
4129
4238
  * Get installed skill information from a specific path
4130
4239
  */ getInstalledSkillFromPath(name, skillPath) {
4131
4240
  if (!exists(skillPath)) return null;
@@ -4140,7 +4249,8 @@ class RegistryResolver {
4140
4249
  path: skillPath,
4141
4250
  version,
4142
4251
  source: isLinked ? getRealPath(skillPath) : locked?.source || '',
4143
- isLinked
4252
+ isLinked,
4253
+ agents: this.detectSkillAgents(name)
4144
4254
  };
4145
4255
  }
4146
4256
  /**
@@ -4333,7 +4443,7 @@ class RegistryResolver {
4333
4443
  /**
4334
4444
  * Install skill from Git to multiple agents
4335
4445
  */ async installToAgentsFromGit(ref, targetAgents, options = {}) {
4336
- const { save = true, mode = 'symlink' } = options;
4446
+ const { save = true, mode = 'symlink', registryContext } = options;
4337
4447
  // Parse reference
4338
4448
  const resolved = await this.resolver.resolve(ref);
4339
4449
  const { parsed, repoUrl } = resolved;
@@ -4351,7 +4461,8 @@ class RegistryResolver {
4351
4461
  const sourcePath = this.resolveSourcePath(cachePath, parsed);
4352
4462
  // Get the real skill name from SKILL.md in cache
4353
4463
  const metadata = this.getSkillMetadataFromDir(sourcePath);
4354
- const skillName = metadata?.name ?? fallbackName;
4464
+ // Priority: registryContext name > SKILL.md name > fallback from Git URL
4465
+ const skillName = registryContext?.skillName ?? metadata?.name ?? fallbackName;
4355
4466
  const semanticVersion = metadata?.version ?? gitRef;
4356
4467
  logger_logger["package"](`Installing ${skillName}@${gitRef} to ${targetAgents.length} agent(s)...`);
4357
4468
  // Create Installer with custom installDir from config
@@ -4366,19 +4477,22 @@ class RegistryResolver {
4366
4477
  mode: mode
4367
4478
  });
4368
4479
  // Update lock file (project mode only)
4369
- if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
4370
- source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`,
4371
- version: semanticVersion,
4372
- ref: gitRef,
4373
- resolved: repoUrl,
4374
- commit: cacheResult.commit
4375
- });
4480
+ if (!this.isGlobal) {
4481
+ const lockSource = registryContext?.lockSource ?? `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? `/${parsed.subPath}` : ''}`;
4482
+ this.lockManager.lockSkill(skillName, {
4483
+ source: lockSource,
4484
+ version: semanticVersion,
4485
+ ref: gitRef,
4486
+ resolved: repoUrl,
4487
+ commit: cacheResult.commit,
4488
+ registry: registryContext?.registryUrl
4489
+ });
4490
+ }
4376
4491
  // Update skills.json (project mode only)
4377
4492
  if (!this.isGlobal && save) {
4378
4493
  this.config.ensureExists();
4379
- // Normalize the reference to use registry shorthand if possible
4380
- const normalizedRef = this.config.normalizeSkillRef(ref);
4381
- this.config.addSkill(skillName, normalizedRef);
4494
+ const configRef = registryContext?.configRef ?? this.config.normalizeSkillRef(ref);
4495
+ this.config.addSkill(skillName, configRef);
4382
4496
  }
4383
4497
  // Count results
4384
4498
  const successCount = Array.from(results.values()).filter((r)=>r.success).length;
@@ -4401,7 +4515,7 @@ class RegistryResolver {
4401
4515
  /**
4402
4516
  * Install skill from HTTP/OSS to multiple agents
4403
4517
  */ async installToAgentsFromHttp(ref, targetAgents, options = {}) {
4404
- const { save = true, mode = 'symlink' } = options;
4518
+ const { save = true, mode = 'symlink', registryContext } = options;
4405
4519
  // Parse HTTP reference
4406
4520
  const resolved = await this.httpResolver.resolve(ref);
4407
4521
  const { parsed, repoUrl, httpInfo } = resolved;
@@ -4418,7 +4532,8 @@ class RegistryResolver {
4418
4532
  const sourcePath = this.cache.getCachePath(parsed, version);
4419
4533
  // Get the real skill name from SKILL.md in cache
4420
4534
  const metadata = this.getSkillMetadataFromDir(sourcePath);
4421
- const skillName = metadata?.name ?? fallbackName;
4535
+ // Priority: registryContext name > SKILL.md name > fallback from URL
4536
+ const skillName = registryContext?.skillName ?? metadata?.name ?? fallbackName;
4422
4537
  const semanticVersion = metadata?.version ?? version;
4423
4538
  logger_logger["package"](`Installing ${skillName}@${version} from ${httpInfo.host} to ${targetAgents.length} agent(s)...`);
4424
4539
  // Create Installer with custom installDir from config
@@ -4433,17 +4548,22 @@ class RegistryResolver {
4433
4548
  mode: mode
4434
4549
  });
4435
4550
  // Update lock file (project mode only)
4436
- if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
4437
- source: `http:${httpInfo.host}/${skillName}`,
4438
- version: semanticVersion,
4439
- ref: version,
4440
- resolved: repoUrl,
4441
- commit: cacheResult.commit
4442
- });
4551
+ if (!this.isGlobal) {
4552
+ const lockSource = registryContext?.lockSource ?? `http:${httpInfo.host}/${skillName}`;
4553
+ this.lockManager.lockSkill(skillName, {
4554
+ source: lockSource,
4555
+ version: semanticVersion,
4556
+ ref: version,
4557
+ resolved: repoUrl,
4558
+ commit: cacheResult.commit,
4559
+ registry: registryContext?.registryUrl
4560
+ });
4561
+ }
4443
4562
  // Update skills.json (project mode only)
4444
4563
  if (!this.isGlobal && save) {
4445
4564
  this.config.ensureExists();
4446
- this.config.addSkill(skillName, ref);
4565
+ const configRef = registryContext?.configRef ?? ref;
4566
+ this.config.addSkill(skillName, configRef);
4447
4567
  }
4448
4568
  // Count results
4449
4569
  const successCount = Array.from(results.values()).filter((r)=>r.success).length;
@@ -4474,7 +4594,7 @@ class RegistryResolver {
4474
4594
  const { force = false, save = true, mode = 'symlink' } = options;
4475
4595
  // Parse skill identifier and resolve registry URL once (single source of truth)
4476
4596
  const parsed = parseSkillIdentifier(ref);
4477
- const registryUrl = options.registry || getRegistryUrl(parsed.scope);
4597
+ const registryUrl = await this.resolveRegistryUrl(ref, options.registry);
4478
4598
  const client = new RegistryClient({
4479
4599
  registry: registryUrl
4480
4600
  });
@@ -4561,13 +4681,22 @@ class RegistryResolver {
4561
4681
  version,
4562
4682
  ref: version,
4563
4683
  resolved: resolvedRegistryUrl,
4564
- commit: resolved.integrity
4684
+ commit: resolved.integrity,
4685
+ registry: resolvedRegistryUrl
4565
4686
  });
4566
4687
  // 8. Update skills.json (project mode only)
4567
4688
  if (!this.isGlobal && save) {
4568
4689
  this.config.ensureExists();
4569
4690
  // Save with full name for registry skills
4570
4691
  this.config.addSkill(shortName, ref);
4692
+ // Save custom registry to skills.json.registries (for reinstall without lock file)
4693
+ if (options.registry) {
4694
+ const registryName = this.deriveRegistryName(options.registry);
4695
+ if (registryName) {
4696
+ this.config.addRegistry(registryName, options.registry);
4697
+ this.config.save();
4698
+ }
4699
+ }
4571
4700
  }
4572
4701
  // 9. Count results and log
4573
4702
  const successCount = Array.from(results.values()).filter((r)=>r.success).length;
@@ -4607,16 +4736,41 @@ class RegistryResolver {
4607
4736
  if (parsed.version && 'latest' !== parsed.version) throw new Error(`Version specifier not supported for web-published skills.\n'${parsed.fullName}' was published via web and does not support versioning.\nUse: reskill install ${parsed.fullName}`);
4608
4737
  if (!source_url) throw new Error(`Missing source_url for web-published skill: ${parsed.fullName}`);
4609
4738
  logger_logger["package"](`Installing ${parsed.fullName} from ${source_type} source...`);
4739
+ // Build registry context so downstream methods use the registry name
4740
+ // instead of deriving from the source URL (e.g., Git repo name)
4741
+ const shortName = getShortName(parsed.fullName);
4742
+ const registryUrl = await this.resolveRegistryUrl(parsed.fullName, options.registry);
4743
+ const registryContext = {
4744
+ skillName: shortName,
4745
+ configRef: parsed.fullName,
4746
+ lockSource: `registry:${parsed.fullName}`,
4747
+ registryUrl
4748
+ };
4749
+ const optionsWithContext = {
4750
+ ...options,
4751
+ registryContext
4752
+ };
4753
+ // Save custom registry to skills.json.registries (for reinstall without lock file)
4754
+ if (!this.isGlobal && options.registry) {
4755
+ const registryName = this.deriveRegistryName(options.registry);
4756
+ if (registryName) {
4757
+ this.config.ensureExists();
4758
+ this.config.load();
4759
+ this.config.addRegistry(registryName, options.registry);
4760
+ this.config.save();
4761
+ }
4762
+ }
4610
4763
  switch(source_type){
4611
4764
  case 'github':
4612
4765
  case 'gitlab':
4613
- // source_url is a full Git URL (includes ref and path)
4614
- // Reuse existing Git installation logic
4615
- return this.installToAgentsFromGit(source_url, targetAgents, options);
4766
+ {
4767
+ const gitRef = this.buildGitRefForWebPublished(source_type, source_url, skillInfo.skill_path, parsed);
4768
+ return this.installToAgentsFromGit(gitRef, targetAgents, optionsWithContext);
4769
+ }
4616
4770
  case 'oss_url':
4617
4771
  case 'custom_url':
4618
4772
  // Direct download URL
4619
- return this.installToAgentsFromHttp(source_url, targetAgents, options);
4773
+ return this.installToAgentsFromHttp(source_url, targetAgents, optionsWithContext);
4620
4774
  case 'local':
4621
4775
  // Download tarball via Registry API
4622
4776
  return this.installFromRegistryLocal(parsed, targetAgents, options);
@@ -4625,13 +4779,36 @@ class RegistryResolver {
4625
4779
  }
4626
4780
  }
4627
4781
  /**
4782
+ * Build a Git ref for web-published github/gitlab skills.
4783
+ *
4784
+ * When `skillPath` is provided (multi-skill repo), constructs a shorthand ref
4785
+ * like `github:owner/repo/skills/my-skill` so that only the sub-directory is
4786
+ * cached and installed.
4787
+ *
4788
+ * Fallback: if `parseGitUrl` fails (non-standard URL), appends `#shortName`
4789
+ * as a skill-name selector. The `#` fragment is extracted by
4790
+ * `GitResolver.parseRef()` as `parsed.skillName`, then matched against
4791
+ * SKILL.md `name` fields via `resolveSourcePath` / `discoverSkillsInDir`.
4792
+ * This differs from the subPath approach (directory-based) but works because
4793
+ * skill names typically match their directory basenames.
4794
+ *
4795
+ * Returns the raw `sourceUrl` when no `skillPath` is available.
4796
+ */ buildGitRefForWebPublished(sourceType, sourceUrl, skillPath, parsed) {
4797
+ if (!skillPath) return sourceUrl;
4798
+ const urlParsed = parseGitUrl(sourceUrl);
4799
+ if (urlParsed) return `${sourceType}:${urlParsed.owner}/${urlParsed.repo}/${skillPath}`;
4800
+ const shortName = getShortName(parsed.fullName);
4801
+ if (shortName) return `${sourceUrl}#${shortName}`;
4802
+ return sourceUrl;
4803
+ }
4804
+ /**
4628
4805
  * Install a skill published via "local folder" mode.
4629
4806
  *
4630
4807
  * Downloads tarball via RegistryClient (handles 302 redirects to signed OSS URLs),
4631
4808
  * then extracts and installs using the same flow as registry source_type.
4632
4809
  */ async installFromRegistryLocal(parsed, targetAgents, options = {}) {
4633
4810
  const { save = true, mode = 'symlink' } = options;
4634
- const registryUrl = options.registry || getRegistryUrl(parsed.scope);
4811
+ const registryUrl = await this.resolveRegistryUrl(parsed.fullName, options.registry);
4635
4812
  const shortName = getShortName(parsed.fullName);
4636
4813
  const version = 'latest';
4637
4814
  // Download tarball via RegistryClient (handles auth + 302 redirect to signed URL)
@@ -4667,12 +4844,21 @@ class RegistryResolver {
4667
4844
  version: semanticVersion,
4668
4845
  ref: version,
4669
4846
  resolved: registryUrl,
4670
- commit: ''
4847
+ commit: '',
4848
+ registry: registryUrl
4671
4849
  });
4672
4850
  // Update skills.json (project mode only)
4673
4851
  if (!this.isGlobal && save) {
4674
4852
  this.config.ensureExists();
4675
4853
  this.config.addSkill(skillName, parsed.fullName);
4854
+ // Save custom registry to skills.json.registries (for reinstall without lock file)
4855
+ if (options.registry) {
4856
+ const registryName = this.deriveRegistryName(options.registry);
4857
+ if (registryName) {
4858
+ this.config.addRegistry(registryName, options.registry);
4859
+ this.config.save();
4860
+ }
4861
+ }
4676
4862
  }
4677
4863
  return {
4678
4864
  skill: {