reskill 1.14.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.
@@ -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;AAUpC;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,MAAM,GAAG,OAAO,CAAC;AAElD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CASzD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM1D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAkBlD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMjD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA2B1D;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,WAAW,CAAC,CAuBtB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,WAAW,CAmB9C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,WAAW,CAqB7C;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,WAAW,CAiD1C;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,WAAW,CAmB3C;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CA4BxD;AAwCD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE,CA2BjE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAwC/D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE,CA2B5D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE,CAoDzD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE,CAkEhE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAsExD;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;CAC5B;AAmBD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE,CA2E/D;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAoCrE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAUrD;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CA4CzB;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,SAgDtB,CAAC;AAEL,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
package/dist/cli/index.js CHANGED
@@ -5237,6 +5237,133 @@ class RegistryResolver {
5237
5237
  }
5238
5238
  return false;
5239
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
+ }
5240
5367
  /**
5241
5368
  * Get status icon
5242
5369
  */ function getStatusIcon(status) {
@@ -5444,6 +5571,73 @@ class RegistryResolver {
5444
5571
  hint: 'For private repos, add SSH key: ssh-keygen -t ed25519'
5445
5572
  };
5446
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
+ }
5447
5641
  /**
5448
5642
  * Check cache directory
5449
5643
  */ function checkCacheDir() {
@@ -5535,12 +5729,21 @@ class RegistryResolver {
5535
5729
  try {
5536
5730
  const config = configLoader.load();
5537
5731
  const registries = config.registries || {};
5538
- for (const name of Object.keys(registries))if (RESERVED_REGISTRIES.includes(name.toLowerCase())) results.push({
5539
- name: 'Registry conflict',
5540
- status: 'warn',
5541
- message: `"${name}" overrides built-in registry`,
5542
- hint: 'Consider using a different name for custom registries'
5543
- });
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
+ }
5544
5747
  } catch {
5545
5748
  // Ignore parse errors, handled by checkSkillsJson
5546
5749
  }
@@ -5575,6 +5778,46 @@ class RegistryResolver {
5575
5778
  }
5576
5779
  return null;
5577
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
+ }
5578
5821
  /**
5579
5822
  * Check for invalid targetAgents configuration
5580
5823
  */ function checkTargetAgents(cwd) {
@@ -5711,6 +5954,15 @@ class RegistryResolver {
5711
5954
  hint: 'Run: reskill install'
5712
5955
  };
5713
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
+ };
5714
5966
  // Check if lock is in sync with config
5715
5967
  const configSkills = configLoader.getSkills();
5716
5968
  const lockedSkills = lockManager.getAll();
@@ -5821,6 +6073,66 @@ class RegistryResolver {
5821
6073
  }
5822
6074
  return results;
5823
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
+ }
5824
6136
  /**
5825
6137
  * Check network connectivity
5826
6138
  */ async function checkNetwork(host) {
@@ -5867,23 +6179,32 @@ class RegistryResolver {
5867
6179
  */ async function runDoctorChecks(options) {
5868
6180
  const { cwd, packageName, packageVersion, skipNetwork, skipConfigChecks } = options;
5869
6181
  const results = [];
5870
- // Version checks
6182
+ // Environment checks
5871
6183
  results.push(await checkReskillVersion(packageVersion, packageName));
5872
6184
  results.push(checkNodeVersion());
5873
6185
  results.push(checkGitVersion());
5874
6186
  results.push(checkGitAuth());
6187
+ results.push(checkAuthStatus());
6188
+ results.push(checkEnvVars());
5875
6189
  // Directory checks
5876
6190
  results.push(checkCacheDir());
5877
6191
  results.push(checkSkillsJson(cwd));
5878
6192
  results.push(checkSkillsLock(cwd));
5879
6193
  results.push(...checkInstalledSkills(cwd));
6194
+ results.push(await checkDetectedAgents());
5880
6195
  // Deep config checks (can be skipped for faster checks)
5881
6196
  if (!skipConfigChecks) {
5882
- // Registry conflicts
6197
+ // Registry conflicts + URL validation
5883
6198
  results.push(...checkRegistryConflicts(cwd));
5884
6199
  // installDir validation
5885
6200
  const installDirCheck = checkInstallDir(cwd);
5886
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);
5887
6208
  // targetAgents validation
5888
6209
  results.push(...checkTargetAgents(cwd));
5889
6210
  // Skill reference format validation
@@ -5895,6 +6216,9 @@ class RegistryResolver {
5895
6216
  if (!skipNetwork) {
5896
6217
  results.push(await checkNetwork('https://github.com'));
5897
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));
5898
6222
  }
5899
6223
  return results;
5900
6224
  }
@@ -6191,133 +6515,6 @@ const DEFAULT_INSTALL_DIR = '.skills';
6191
6515
  // Display summary (use options.installDir directly since we just set it)
6192
6516
  displayConfigSummary(options.installDir);
6193
6517
  });
6194
- /**
6195
- * AuthManager - Handle authentication token management
6196
- *
6197
- * Manages tokens for registry authentication.
6198
- * Tokens are stored in ~/.reskillrc or via RESKILL_TOKEN environment variable.
6199
- */ // ============================================================================
6200
- // Constants
6201
- // ============================================================================
6202
- const CONFIG_FILE_NAME = '.reskillrc';
6203
- // ============================================================================
6204
- // AuthManager Class
6205
- // ============================================================================
6206
- class AuthManager {
6207
- configPath;
6208
- constructor(){
6209
- const home = process.env.HOME || process.env.USERPROFILE || '';
6210
- this.configPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, CONFIG_FILE_NAME);
6211
- }
6212
- /**
6213
- * Get the default registry URL from environment variable
6214
- *
6215
- * Returns undefined if no registry is configured - there is no hardcoded default
6216
- * to prevent accidental publishing to unintended registries.
6217
- */ getDefaultRegistry() {
6218
- return process.env.RESKILL_REGISTRY;
6219
- }
6220
- /**
6221
- * Get path to config file
6222
- */ getConfigPath() {
6223
- return this.configPath;
6224
- }
6225
- /**
6226
- * Get token for a registry
6227
- *
6228
- * Priority:
6229
- * 1. RESKILL_TOKEN environment variable
6230
- * 2. Token from ~/.reskillrc for the specified registry
6231
- */ getToken(registry) {
6232
- // Check environment variable first
6233
- const envToken = process.env.RESKILL_TOKEN;
6234
- if (envToken) return envToken;
6235
- // Read from config file
6236
- const config = this.readConfig();
6237
- if (!config?.registries) return;
6238
- const targetRegistry = registry || this.getDefaultRegistry();
6239
- if (!targetRegistry) return;
6240
- const auth = config.registries[targetRegistry];
6241
- return auth?.token;
6242
- }
6243
- /**
6244
- * Check if token exists for a registry
6245
- */ hasToken(registry) {
6246
- return void 0 !== this.getToken(registry);
6247
- }
6248
- /**
6249
- * Get email for a registry
6250
- */ getEmail(registry) {
6251
- const config = this.readConfig();
6252
- if (!config?.registries) return;
6253
- const targetRegistry = registry || this.getDefaultRegistry();
6254
- if (!targetRegistry) return;
6255
- const auth = config.registries[targetRegistry];
6256
- return auth?.email;
6257
- }
6258
- /**
6259
- * Get handle for a registry
6260
- */ getHandle(registry) {
6261
- const config = this.readConfig();
6262
- if (!config?.registries) return;
6263
- const targetRegistry = registry || this.getDefaultRegistry();
6264
- if (!targetRegistry) return;
6265
- const auth = config.registries[targetRegistry];
6266
- return auth?.handle;
6267
- }
6268
- /**
6269
- * Set token for a registry
6270
- *
6271
- * Note: When no registry is specified and RESKILL_REGISTRY env var is not set,
6272
- * this method will throw an error. The calling code should ensure a registry
6273
- * is always provided (either explicitly or via environment variable).
6274
- */ setToken(token, registry, email, handle) {
6275
- const config = this.readConfig() || {};
6276
- const targetRegistry = registry || this.getDefaultRegistry();
6277
- if (!targetRegistry) throw new Error('No registry specified. Set RESKILL_REGISTRY environment variable or provide registry explicitly.');
6278
- if (!config.registries) config.registries = {};
6279
- config.registries[targetRegistry] = {
6280
- token,
6281
- ...email && {
6282
- email
6283
- },
6284
- ...handle && {
6285
- handle
6286
- }
6287
- };
6288
- this.writeConfig(config);
6289
- }
6290
- /**
6291
- * Remove token for a registry
6292
- */ removeToken(registry) {
6293
- const config = this.readConfig();
6294
- if (!config?.registries) return;
6295
- const targetRegistry = registry || this.getDefaultRegistry();
6296
- if (!targetRegistry) return;
6297
- delete config.registries[targetRegistry];
6298
- this.writeConfig(config);
6299
- }
6300
- /**
6301
- * Read config file
6302
- */ readConfig() {
6303
- try {
6304
- if (!external_node_fs_.existsSync(this.configPath)) return null;
6305
- const content = external_node_fs_.readFileSync(this.configPath, 'utf-8');
6306
- if (!content.trim()) return null;
6307
- return JSON.parse(content);
6308
- } catch {
6309
- return null;
6310
- }
6311
- }
6312
- /**
6313
- * Write config file
6314
- */ writeConfig(config) {
6315
- const content = JSON.stringify(config, null, 2);
6316
- external_node_fs_.writeFileSync(this.configPath, content, {
6317
- mode: 384
6318
- });
6319
- }
6320
- }
6321
6518
  // ============================================================================
6322
6519
  // Utility Functions
6323
6520
  // ============================================================================
@@ -1,4 +1,8 @@
1
1
  import type { LockedSkill, SkillsLock } from '../types/index.js';
2
+ /**
3
+ * Current lockfile version
4
+ */
5
+ export declare const LOCKFILE_VERSION = 1;
2
6
  /**
3
7
  * LockManager - Manage skills.lock file
4
8
  *
@@ -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;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"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reskill",
3
- "version": "1.14.0",
3
+ "version": "1.15.0",
4
4
  "description": "AI Skills Package Manager - Git-based skills management for AI agents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",