reskill 0.1.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3,6 +3,9 @@ import * as __WEBPACK_EXTERNAL_MODULE_semver__ from "semver";
3
3
  import * as __WEBPACK_EXTERNAL_MODULE_node_child_process__ from "node:child_process";
4
4
  import * as __WEBPACK_EXTERNAL_MODULE_node_util__ from "node:util";
5
5
  import * as __WEBPACK_EXTERNAL_MODULE_node_path__ from "node:path";
6
+ import * as __WEBPACK_EXTERNAL_MODULE_os__ from "os";
7
+ import * as __WEBPACK_EXTERNAL_MODULE_path__ from "path";
8
+ import * as __WEBPACK_EXTERNAL_MODULE_fs__ from "fs";
6
9
  import * as __WEBPACK_EXTERNAL_MODULE_chalk__ from "chalk";
7
10
  var __webpack_modules__ = {
8
11
  "node:fs": function(module) {
@@ -441,6 +444,36 @@ function getGlobalSkillsDir() {
441
444
  const home = getHomeDir();
442
445
  return __WEBPACK_EXTERNAL_MODULE_node_path__.join(home, '.claude', 'skills');
443
446
  }
447
+ const AGENTS_DIR = '.agents';
448
+ const SKILLS_SUBDIR = 'skills';
449
+ function getCanonicalSkillsDir(options = {}) {
450
+ const { global: isGlobal = false, cwd } = options;
451
+ const baseDir = isGlobal ? getHomeDir() : cwd || process.cwd();
452
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, AGENTS_DIR, SKILLS_SUBDIR);
453
+ }
454
+ function getCanonicalSkillPath(skillName, options = {}) {
455
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(getCanonicalSkillsDir(options), skillName);
456
+ }
457
+ function shortenPath(fullPath, cwd) {
458
+ const home = getHomeDir();
459
+ const currentDir = cwd || process.cwd();
460
+ if (fullPath.startsWith(home)) return fullPath.replace(home, '~');
461
+ if (fullPath.startsWith(currentDir)) return '.' + fullPath.slice(currentDir.length);
462
+ return fullPath;
463
+ }
464
+ function isPathSafe(basePath, targetPath) {
465
+ const normalizedBase = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(basePath));
466
+ const normalizedTarget = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(targetPath));
467
+ return normalizedTarget.startsWith(normalizedBase + __WEBPACK_EXTERNAL_MODULE_node_path__.sep) || normalizedTarget === normalizedBase;
468
+ }
469
+ function sanitizeName(name) {
470
+ let sanitized = name.replace(/[/\\:\0]/g, '');
471
+ sanitized = sanitized.replace(/^[.\s]+|[.\s]+$/g, '');
472
+ sanitized = sanitized.replace(/^\.+/, '');
473
+ if (!sanitized || 0 === sanitized.length) sanitized = 'unnamed-skill';
474
+ if (sanitized.length > 255) sanitized = sanitized.substring(0, 255);
475
+ return sanitized;
476
+ }
444
477
  class CacheManager {
445
478
  cacheDir;
446
479
  constructor(cacheDir){
@@ -452,6 +485,9 @@ class CacheManager {
452
485
  getSkillCachePath(parsed, version) {
453
486
  return __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cacheDir, parsed.registry, parsed.owner, parsed.repo, version);
454
487
  }
488
+ getCachePath(parsed, version) {
489
+ return this.getSkillCachePath(parsed, version);
490
+ }
455
491
  isCached(parsed, version) {
456
492
  const cachePath = this.getSkillCachePath(parsed, version);
457
493
  return exists(cachePath) && isDirectory(cachePath);
@@ -614,7 +650,9 @@ class ConfigLoader {
614
650
  const config = this.config || (this.exists() ? this.load() : DEFAULT_SKILLS_JSON);
615
651
  return {
616
652
  registry: config.defaults?.registry || DEFAULT_SKILLS_JSON.defaults.registry,
617
- installDir: config.defaults?.installDir || DEFAULT_SKILLS_JSON.defaults.installDir
653
+ installDir: config.defaults?.installDir || DEFAULT_SKILLS_JSON.defaults.installDir,
654
+ targetAgents: config.defaults?.targetAgents || [],
655
+ installMode: config.defaults?.installMode || 'symlink'
618
656
  };
619
657
  }
620
658
  getRegistryUrl(registryName) {
@@ -759,6 +797,341 @@ class LockManager {
759
797
  this.lockData = null;
760
798
  }
761
799
  }
800
+ const agent_registry_home = (0, __WEBPACK_EXTERNAL_MODULE_os__.homedir)();
801
+ const agents = {
802
+ amp: {
803
+ name: 'amp',
804
+ displayName: 'Amp',
805
+ skillsDir: '.agents/skills',
806
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.config/agents/skills'),
807
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.config/amp'))
808
+ },
809
+ antigravity: {
810
+ name: 'antigravity',
811
+ displayName: 'Antigravity',
812
+ skillsDir: '.agent/skills',
813
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.gemini/antigravity/skills'),
814
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(process.cwd(), '.agent')) || (0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.gemini/antigravity'))
815
+ },
816
+ 'claude-code': {
817
+ name: 'claude-code',
818
+ displayName: 'Claude Code',
819
+ skillsDir: '.claude/skills',
820
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.claude/skills'),
821
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.claude'))
822
+ },
823
+ clawdbot: {
824
+ name: 'clawdbot',
825
+ displayName: 'Clawdbot',
826
+ skillsDir: 'skills',
827
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.clawdbot/skills'),
828
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.clawdbot'))
829
+ },
830
+ codex: {
831
+ name: 'codex',
832
+ displayName: 'Codex',
833
+ skillsDir: '.codex/skills',
834
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.codex/skills'),
835
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.codex'))
836
+ },
837
+ cursor: {
838
+ name: 'cursor',
839
+ displayName: 'Cursor',
840
+ skillsDir: '.cursor/skills',
841
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.cursor/skills'),
842
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.cursor'))
843
+ },
844
+ droid: {
845
+ name: 'droid',
846
+ displayName: 'Droid',
847
+ skillsDir: '.factory/skills',
848
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.factory/skills'),
849
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.factory/skills'))
850
+ },
851
+ 'gemini-cli': {
852
+ name: 'gemini-cli',
853
+ displayName: 'Gemini CLI',
854
+ skillsDir: '.gemini/skills',
855
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.gemini/skills'),
856
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.gemini'))
857
+ },
858
+ 'github-copilot': {
859
+ name: 'github-copilot',
860
+ displayName: 'GitHub Copilot',
861
+ skillsDir: '.github/skills',
862
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.copilot/skills'),
863
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(process.cwd(), '.github')) || (0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.copilot'))
864
+ },
865
+ goose: {
866
+ name: 'goose',
867
+ displayName: 'Goose',
868
+ skillsDir: '.goose/skills',
869
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.config/goose/skills'),
870
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.config/goose'))
871
+ },
872
+ kilo: {
873
+ name: 'kilo',
874
+ displayName: 'Kilo Code',
875
+ skillsDir: '.kilocode/skills',
876
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.kilocode/skills'),
877
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.kilocode'))
878
+ },
879
+ 'kiro-cli': {
880
+ name: 'kiro-cli',
881
+ displayName: 'Kiro CLI',
882
+ skillsDir: '.kiro/skills',
883
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.kiro/skills'),
884
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.kiro'))
885
+ },
886
+ opencode: {
887
+ name: 'opencode',
888
+ displayName: 'OpenCode',
889
+ skillsDir: '.opencode/skills',
890
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.config/opencode/skills'),
891
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.config/opencode')) || (0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.claude/skills'))
892
+ },
893
+ roo: {
894
+ name: 'roo',
895
+ displayName: 'Roo Code',
896
+ skillsDir: '.roo/skills',
897
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.roo/skills'),
898
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.roo'))
899
+ },
900
+ trae: {
901
+ name: 'trae',
902
+ displayName: 'Trae',
903
+ skillsDir: '.trae/skills',
904
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.trae/skills'),
905
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.trae'))
906
+ },
907
+ windsurf: {
908
+ name: 'windsurf',
909
+ displayName: 'Windsurf',
910
+ skillsDir: '.windsurf/skills',
911
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.codeium/windsurf/skills'),
912
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.codeium/windsurf'))
913
+ },
914
+ neovate: {
915
+ name: 'neovate',
916
+ displayName: 'Neovate',
917
+ skillsDir: '.neovate/skills',
918
+ globalSkillsDir: (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.neovate/skills'),
919
+ detectInstalled: async ()=>(0, __WEBPACK_EXTERNAL_MODULE_fs__.existsSync)((0, __WEBPACK_EXTERNAL_MODULE_path__.join)(agent_registry_home, '.neovate'))
920
+ }
921
+ };
922
+ function getAllAgentTypes() {
923
+ return Object.keys(agents);
924
+ }
925
+ async function detectInstalledAgents() {
926
+ const installed = [];
927
+ for (const [type, config] of Object.entries(agents))if (await config.detectInstalled()) installed.push(type);
928
+ return installed;
929
+ }
930
+ function getAgentConfig(type) {
931
+ return agents[type];
932
+ }
933
+ function isValidAgentType(type) {
934
+ return type in agents;
935
+ }
936
+ function getAgentSkillsDir(type, options = {}) {
937
+ const config = agents[type];
938
+ if (options.global) return config.globalSkillsDir;
939
+ const cwd = options.cwd || process.cwd();
940
+ return (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(cwd, config.skillsDir);
941
+ }
942
+ const installer_AGENTS_DIR = '.agents';
943
+ const installer_SKILLS_SUBDIR = 'skills';
944
+ function installer_sanitizeName(name) {
945
+ let sanitized = name.replace(/[/\\:\0]/g, '');
946
+ sanitized = sanitized.replace(/^[.\s]+|[.\s]+$/g, '');
947
+ sanitized = sanitized.replace(/^\.+/, '');
948
+ if (!sanitized || 0 === sanitized.length) sanitized = 'unnamed-skill';
949
+ if (sanitized.length > 255) sanitized = sanitized.substring(0, 255);
950
+ return sanitized;
951
+ }
952
+ function installer_isPathSafe(basePath, targetPath) {
953
+ const normalizedBase = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(basePath));
954
+ const normalizedTarget = __WEBPACK_EXTERNAL_MODULE_node_path__.normalize(__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(targetPath));
955
+ return normalizedTarget.startsWith(normalizedBase + __WEBPACK_EXTERNAL_MODULE_node_path__.sep) || normalizedTarget === normalizedBase;
956
+ }
957
+ function installer_getCanonicalSkillsDir(isGlobal, cwd) {
958
+ const baseDir = isGlobal ? (0, __WEBPACK_EXTERNAL_MODULE_os__.homedir)() : cwd || process.cwd();
959
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(baseDir, installer_AGENTS_DIR, installer_SKILLS_SUBDIR);
960
+ }
961
+ function installer_ensureDir(dirPath) {
962
+ if (!external_node_fs_.existsSync(dirPath)) external_node_fs_.mkdirSync(dirPath, {
963
+ recursive: true
964
+ });
965
+ }
966
+ function installer_remove(targetPath) {
967
+ if (external_node_fs_.existsSync(targetPath)) external_node_fs_.rmSync(targetPath, {
968
+ recursive: true,
969
+ force: true
970
+ });
971
+ }
972
+ function copyDirectory(src, dest, options) {
973
+ const exclude = new Set(options?.exclude || [
974
+ 'README.md',
975
+ 'metadata.json'
976
+ ]);
977
+ installer_ensureDir(dest);
978
+ const entries = external_node_fs_.readdirSync(src, {
979
+ withFileTypes: true
980
+ });
981
+ for (const entry of entries){
982
+ if (exclude.has(entry.name) || entry.name.startsWith('_')) continue;
983
+ const srcPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(src, entry.name);
984
+ const destPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dest, entry.name);
985
+ if (entry.isDirectory()) copyDirectory(srcPath, destPath, options);
986
+ else external_node_fs_.copyFileSync(srcPath, destPath);
987
+ }
988
+ }
989
+ async function installer_createSymlink(target, linkPath) {
990
+ try {
991
+ try {
992
+ const stats = external_node_fs_.lstatSync(linkPath);
993
+ if (stats.isSymbolicLink()) {
994
+ const existingTarget = external_node_fs_.readlinkSync(linkPath);
995
+ if (__WEBPACK_EXTERNAL_MODULE_node_path__.resolve(existingTarget) === __WEBPACK_EXTERNAL_MODULE_node_path__.resolve(target)) return true;
996
+ external_node_fs_.rmSync(linkPath);
997
+ } else external_node_fs_.rmSync(linkPath, {
998
+ recursive: true
999
+ });
1000
+ } catch (err) {
1001
+ if (err && 'object' == typeof err && 'code' in err) {
1002
+ if ('ELOOP' === err.code) try {
1003
+ external_node_fs_.rmSync(linkPath, {
1004
+ force: true
1005
+ });
1006
+ } catch {}
1007
+ }
1008
+ }
1009
+ const linkDir = __WEBPACK_EXTERNAL_MODULE_node_path__.dirname(linkPath);
1010
+ installer_ensureDir(linkDir);
1011
+ const relativePath = __WEBPACK_EXTERNAL_MODULE_node_path__.relative(linkDir, target);
1012
+ const symlinkType = 'win32' === (0, __WEBPACK_EXTERNAL_MODULE_os__.platform)() ? 'junction' : void 0;
1013
+ external_node_fs_.symlinkSync(relativePath, linkPath, symlinkType);
1014
+ return true;
1015
+ } catch {
1016
+ return false;
1017
+ }
1018
+ }
1019
+ class Installer {
1020
+ cwd;
1021
+ isGlobal;
1022
+ constructor(options = {}){
1023
+ this.cwd = options.cwd || process.cwd();
1024
+ this.isGlobal = options.global || false;
1025
+ }
1026
+ getCanonicalPath(skillName) {
1027
+ const sanitized = installer_sanitizeName(skillName);
1028
+ const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
1029
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
1030
+ }
1031
+ getAgentSkillPath(skillName, agentType) {
1032
+ const agent = getAgentConfig(agentType);
1033
+ const sanitized = installer_sanitizeName(skillName);
1034
+ const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
1035
+ return __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
1036
+ }
1037
+ async installForAgent(sourcePath, skillName, agentType, options = {}) {
1038
+ const agent = getAgentConfig(agentType);
1039
+ const installMode = options.mode || 'symlink';
1040
+ const sanitized = installer_sanitizeName(skillName);
1041
+ const canonicalBase = installer_getCanonicalSkillsDir(this.isGlobal, this.cwd);
1042
+ const canonicalDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(canonicalBase, sanitized);
1043
+ const agentBase = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
1044
+ const agentDir = __WEBPACK_EXTERNAL_MODULE_node_path__.join(agentBase, sanitized);
1045
+ if (!installer_isPathSafe(canonicalBase, canonicalDir)) return {
1046
+ success: false,
1047
+ path: agentDir,
1048
+ mode: installMode,
1049
+ error: 'Invalid skill name: potential path traversal detected'
1050
+ };
1051
+ if (!installer_isPathSafe(agentBase, agentDir)) return {
1052
+ success: false,
1053
+ path: agentDir,
1054
+ mode: installMode,
1055
+ error: 'Invalid skill name: potential path traversal detected'
1056
+ };
1057
+ try {
1058
+ if ('copy' === installMode) {
1059
+ installer_ensureDir(agentDir);
1060
+ installer_remove(agentDir);
1061
+ copyDirectory(sourcePath, agentDir);
1062
+ return {
1063
+ success: true,
1064
+ path: agentDir,
1065
+ mode: 'copy'
1066
+ };
1067
+ }
1068
+ installer_ensureDir(canonicalDir);
1069
+ installer_remove(canonicalDir);
1070
+ copyDirectory(sourcePath, canonicalDir);
1071
+ const symlinkCreated = await installer_createSymlink(canonicalDir, agentDir);
1072
+ if (!symlinkCreated) {
1073
+ try {
1074
+ installer_remove(agentDir);
1075
+ } catch {}
1076
+ installer_ensureDir(agentDir);
1077
+ copyDirectory(sourcePath, agentDir);
1078
+ return {
1079
+ success: true,
1080
+ path: agentDir,
1081
+ canonicalPath: canonicalDir,
1082
+ mode: 'symlink',
1083
+ symlinkFailed: true
1084
+ };
1085
+ }
1086
+ return {
1087
+ success: true,
1088
+ path: agentDir,
1089
+ canonicalPath: canonicalDir,
1090
+ mode: 'symlink'
1091
+ };
1092
+ } catch (error) {
1093
+ return {
1094
+ success: false,
1095
+ path: agentDir,
1096
+ mode: installMode,
1097
+ error: error instanceof Error ? error.message : 'Unknown error'
1098
+ };
1099
+ }
1100
+ }
1101
+ async installToAgents(sourcePath, skillName, targetAgents, options = {}) {
1102
+ const results = new Map();
1103
+ for (const agent of targetAgents){
1104
+ const result = await this.installForAgent(sourcePath, skillName, agent, options);
1105
+ results.set(agent, result);
1106
+ }
1107
+ return results;
1108
+ }
1109
+ isInstalled(skillName, agentType) {
1110
+ const skillPath = this.getAgentSkillPath(skillName, agentType);
1111
+ return external_node_fs_.existsSync(skillPath);
1112
+ }
1113
+ uninstallFromAgent(skillName, agentType) {
1114
+ const skillPath = this.getAgentSkillPath(skillName, agentType);
1115
+ if (!external_node_fs_.existsSync(skillPath)) return false;
1116
+ installer_remove(skillPath);
1117
+ return true;
1118
+ }
1119
+ uninstallFromAgents(skillName, targetAgents) {
1120
+ const results = new Map();
1121
+ for (const agent of targetAgents)results.set(agent, this.uninstallFromAgent(skillName, agent));
1122
+ const canonicalPath = this.getCanonicalPath(skillName);
1123
+ if (external_node_fs_.existsSync(canonicalPath)) installer_remove(canonicalPath);
1124
+ return results;
1125
+ }
1126
+ listInstalledSkills(agentType) {
1127
+ const agent = getAgentConfig(agentType);
1128
+ const skillsDir = this.isGlobal ? agent.globalSkillsDir : __WEBPACK_EXTERNAL_MODULE_node_path__.join(this.cwd, agent.skillsDir);
1129
+ if (!external_node_fs_.existsSync(skillsDir)) return [];
1130
+ return external_node_fs_.readdirSync(skillsDir, {
1131
+ withFileTypes: true
1132
+ }).filter((entry)=>entry.isDirectory() || entry.isSymbolicLink()).map((entry)=>entry.name);
1133
+ }
1134
+ }
762
1135
  const logger = {
763
1136
  info (message) {
764
1137
  console.log(__WEBPACK_EXTERNAL_MODULE_chalk__["default"].blue('ℹ'), message);
@@ -1029,5 +1402,226 @@ class SkillManager {
1029
1402
  }
1030
1403
  return results;
1031
1404
  }
1405
+ async installToAgents(ref, targetAgents, options = {}) {
1406
+ const { save = true, mode = 'symlink' } = options;
1407
+ const resolved = await this.resolver.resolve(ref);
1408
+ const { parsed, repoUrl } = resolved;
1409
+ const version = resolved.ref;
1410
+ const skillName = parsed.subPath ? __WEBPACK_EXTERNAL_MODULE_node_path__.basename(parsed.subPath) : parsed.repo;
1411
+ logger["package"](`Installing ${skillName}@${version} to ${targetAgents.length} agent(s)...`);
1412
+ let cacheResult = await this.cache.get(parsed, version);
1413
+ if (cacheResult) logger.debug(`Using cached ${skillName}@${version}`);
1414
+ else {
1415
+ logger.debug(`Caching ${skillName}@${version} from ${repoUrl}`);
1416
+ cacheResult = await this.cache.cache(repoUrl, parsed, version, version);
1417
+ }
1418
+ const sourcePath = this.cache.getCachePath(parsed, version);
1419
+ const installer = new Installer({
1420
+ cwd: this.projectRoot,
1421
+ global: this.isGlobal
1422
+ });
1423
+ const results = await installer.installToAgents(sourcePath, skillName, targetAgents, {
1424
+ mode: mode
1425
+ });
1426
+ if (!this.isGlobal) this.lockManager.lockSkill(skillName, {
1427
+ source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? '/' + parsed.subPath : ''}`,
1428
+ version,
1429
+ resolved: repoUrl,
1430
+ commit: cacheResult.commit
1431
+ });
1432
+ if (!this.isGlobal && save && this.config.exists()) this.config.addSkill(skillName, ref);
1433
+ const successCount = Array.from(results.values()).filter((r)=>r.success).length;
1434
+ const failCount = results.size - successCount;
1435
+ if (0 === failCount) logger.success(`Installed ${skillName}@${version} to ${successCount} agent(s)`);
1436
+ else logger.warn(`Installed ${skillName}@${version} to ${successCount} agent(s), ${failCount} failed`);
1437
+ const skill = {
1438
+ name: skillName,
1439
+ path: sourcePath,
1440
+ version,
1441
+ source: `${parsed.registry}:${parsed.owner}/${parsed.repo}${parsed.subPath ? '/' + parsed.subPath : ''}`
1442
+ };
1443
+ return {
1444
+ skill,
1445
+ results
1446
+ };
1447
+ }
1448
+ async getDefaultTargetAgents() {
1449
+ const defaults = this.config.getDefaults();
1450
+ if (defaults.targetAgents && defaults.targetAgents.length > 0) return defaults.targetAgents.filter(isValidAgentType);
1451
+ return detectInstalledAgents();
1452
+ }
1453
+ getDefaultInstallMode() {
1454
+ const defaults = this.config.getDefaults();
1455
+ if ('copy' === defaults.installMode || 'symlink' === defaults.installMode) return defaults.installMode;
1456
+ return 'symlink';
1457
+ }
1458
+ validateAgentTypes(agentNames) {
1459
+ const valid = [];
1460
+ const invalid = [];
1461
+ for (const name of agentNames)if (isValidAgentType(name)) valid.push(name);
1462
+ else invalid.push(name);
1463
+ return {
1464
+ valid,
1465
+ invalid
1466
+ };
1467
+ }
1468
+ getAllAgentTypes() {
1469
+ return Object.keys(agents);
1470
+ }
1471
+ uninstallFromAgents(name, targetAgents) {
1472
+ const installer = new Installer({
1473
+ cwd: this.projectRoot,
1474
+ global: this.isGlobal
1475
+ });
1476
+ const results = installer.uninstallFromAgents(name, targetAgents);
1477
+ if (!this.isGlobal) this.lockManager.remove(name);
1478
+ if (!this.isGlobal && this.config.exists()) this.config.removeSkill(name);
1479
+ const successCount = Array.from(results.values()).filter((r)=>r).length;
1480
+ logger.success(`Uninstalled ${name} from ${successCount} agent(s)`);
1481
+ return results;
1482
+ }
1483
+ }
1484
+ class SkillValidationError extends Error {
1485
+ field;
1486
+ constructor(message, field){
1487
+ super(message), this.field = field;
1488
+ this.name = 'SkillValidationError';
1489
+ }
1490
+ }
1491
+ function parseFrontmatter(content) {
1492
+ const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/;
1493
+ const match = content.match(frontmatterRegex);
1494
+ if (!match) return {
1495
+ data: {},
1496
+ content
1497
+ };
1498
+ const yamlContent = match[1];
1499
+ const markdownContent = match[2];
1500
+ const data = {};
1501
+ const lines = yamlContent.split('\n');
1502
+ let currentKey = '';
1503
+ let currentValue = '';
1504
+ let inMultiline = false;
1505
+ for (const line of lines){
1506
+ const trimmedLine = line.trim();
1507
+ if (!trimmedLine || trimmedLine.startsWith('#')) continue;
1508
+ const keyValueMatch = line.match(/^([a-zA-Z_-]+):\s*(.*)$/);
1509
+ if (keyValueMatch && !inMultiline) {
1510
+ if (currentKey) data[currentKey] = parseYamlValue(currentValue.trim());
1511
+ currentKey = keyValueMatch[1];
1512
+ currentValue = keyValueMatch[2];
1513
+ if ('|' === currentValue || '>' === currentValue) {
1514
+ inMultiline = true;
1515
+ currentValue = '';
1516
+ }
1517
+ } else if (inMultiline && line.startsWith(' ')) currentValue += (currentValue ? '\n' : '') + line.slice(2);
1518
+ else if (inMultiline && !line.startsWith(' ')) {
1519
+ inMultiline = false;
1520
+ data[currentKey] = currentValue.trim();
1521
+ const newKeyMatch = line.match(/^([a-zA-Z_-]+):\s*(.*)$/);
1522
+ if (newKeyMatch) {
1523
+ currentKey = newKeyMatch[1];
1524
+ currentValue = newKeyMatch[2];
1525
+ }
1526
+ }
1527
+ }
1528
+ if (currentKey) data[currentKey] = parseYamlValue(currentValue.trim());
1529
+ return {
1530
+ data,
1531
+ content: markdownContent
1532
+ };
1533
+ }
1534
+ function parseYamlValue(value) {
1535
+ if (!value) return '';
1536
+ if ('true' === value) return true;
1537
+ if ('false' === value) return false;
1538
+ if (/^-?\d+$/.test(value)) return parseInt(value, 10);
1539
+ if (/^-?\d+\.\d+$/.test(value)) return parseFloat(value);
1540
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) return value.slice(1, -1);
1541
+ return value;
1542
+ }
1543
+ function validateSkillName(name) {
1544
+ if (!name) throw new SkillValidationError('Skill name is required', 'name');
1545
+ if (name.length > 64) throw new SkillValidationError('Skill name must be at most 64 characters', 'name');
1546
+ if (!/^[a-z0-9]/.test(name)) throw new SkillValidationError('Skill name must start with a lowercase letter or number', 'name');
1547
+ if (!/[a-z0-9]$/.test(name)) throw new SkillValidationError('Skill name must end with a lowercase letter or number', 'name');
1548
+ if (/--/.test(name)) throw new SkillValidationError('Skill name cannot contain consecutive hyphens', 'name');
1549
+ if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(name) && name.length > 1) throw new SkillValidationError('Skill name can only contain lowercase letters, numbers, and hyphens', 'name');
1550
+ if (1 === name.length && !/^[a-z0-9]$/.test(name)) throw new SkillValidationError('Single character skill name must be a lowercase letter or number', 'name');
1551
+ }
1552
+ function validateSkillDescription(description) {
1553
+ if (!description) throw new SkillValidationError('Skill description is required', 'description');
1554
+ if (description.length > 1024) throw new SkillValidationError('Skill description must be at most 1024 characters', 'description');
1555
+ if (/<|>/.test(description)) throw new SkillValidationError('Skill description cannot contain angle brackets', 'description');
1556
+ }
1557
+ function parseSkillMd(content, options = {}) {
1558
+ const { strict = false } = options;
1559
+ try {
1560
+ const { data, content: body } = parseFrontmatter(content);
1561
+ if (!data.name || !data.description) {
1562
+ if (strict) throw new SkillValidationError('SKILL.md must have name and description in frontmatter');
1563
+ return null;
1564
+ }
1565
+ const name = String(data.name);
1566
+ const description = String(data.description);
1567
+ if (strict) {
1568
+ validateSkillName(name);
1569
+ validateSkillDescription(description);
1570
+ }
1571
+ let allowedTools;
1572
+ if (data['allowed-tools']) {
1573
+ const toolsStr = String(data['allowed-tools']);
1574
+ allowedTools = toolsStr.split(/\s+/).filter(Boolean);
1575
+ }
1576
+ return {
1577
+ name,
1578
+ description,
1579
+ license: data.license ? String(data.license) : void 0,
1580
+ compatibility: data.compatibility ? String(data.compatibility) : void 0,
1581
+ metadata: data.metadata,
1582
+ allowedTools,
1583
+ content: body,
1584
+ rawContent: content
1585
+ };
1586
+ } catch (error) {
1587
+ if (error instanceof SkillValidationError) throw error;
1588
+ if (strict) throw new SkillValidationError(`Failed to parse SKILL.md: ${error}`);
1589
+ return null;
1590
+ }
1591
+ }
1592
+ function parseSkillMdFile(filePath, options = {}) {
1593
+ if (!external_node_fs_.existsSync(filePath)) {
1594
+ if (options.strict) throw new SkillValidationError(`SKILL.md not found: ${filePath}`);
1595
+ return null;
1596
+ }
1597
+ const content = external_node_fs_.readFileSync(filePath, 'utf-8');
1598
+ return parseSkillMd(content, options);
1599
+ }
1600
+ function parseSkillFromDir(dirPath, options = {}) {
1601
+ const skillMdPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dirPath, 'SKILL.md');
1602
+ return parseSkillMdFile(skillMdPath, options);
1603
+ }
1604
+ function hasValidSkillMd(dirPath) {
1605
+ const skillMdPath = __WEBPACK_EXTERNAL_MODULE_node_path__.join(dirPath, 'SKILL.md');
1606
+ if (!external_node_fs_.existsSync(skillMdPath)) return false;
1607
+ try {
1608
+ const skill = parseSkillMdFile(skillMdPath);
1609
+ return null !== skill;
1610
+ } catch {
1611
+ return false;
1612
+ }
1613
+ }
1614
+ function generateSkillMd(skill) {
1615
+ const frontmatter = [
1616
+ '---'
1617
+ ];
1618
+ frontmatter.push(`name: ${skill.name}`);
1619
+ frontmatter.push(`description: ${skill.description}`);
1620
+ if (skill.license) frontmatter.push(`license: ${skill.license}`);
1621
+ if (skill.compatibility) frontmatter.push(`compatibility: ${skill.compatibility}`);
1622
+ if (skill.allowedTools && skill.allowedTools.length > 0) frontmatter.push(`allowed-tools: ${skill.allowedTools.join(' ')}`);
1623
+ frontmatter.push('---');
1624
+ frontmatter.push('');
1625
+ return frontmatter.join('\n') + skill.content;
1032
1626
  }
1033
- export { CacheManager, ConfigLoader, DEFAULT_REGISTRIES, GitResolver, LockManager, SkillManager, logger };
1627
+ export { CacheManager, ConfigLoader, DEFAULT_REGISTRIES, GitResolver, Installer, LockManager, SkillManager, SkillValidationError, agents, detectInstalledAgents, generateSkillMd, getAgentConfig, getAgentSkillsDir, getAllAgentTypes, getCanonicalSkillPath, getCanonicalSkillsDir, hasValidSkillMd, isPathSafe, isValidAgentType, logger, parseSkillFromDir, parseSkillMd, parseSkillMdFile, sanitizeName, shortenPath, validateSkillDescription, validateSkillName };
@@ -2,6 +2,18 @@
2
2
  * Skills Package Manager Type Definitions
3
3
  * Based on: docs/skills-management-design.md
4
4
  */
5
+ /**
6
+ * 支持的 Agent 类型
7
+ */
8
+ export type { AgentType, AgentConfig, } from '../core/agent-registry.js';
9
+ /**
10
+ * 安装模式
11
+ */
12
+ export type { InstallMode, InstallResult } from '../core/installer.js';
13
+ /**
14
+ * SKILL.md 解析相关类型 (遵循 agentskills.io 规范)
15
+ */
16
+ export type { SkillMdFrontmatter, ParsedSkill, } from '../core/skill-parser.js';
5
17
  /**
6
18
  * 版本规范格式
7
19
  * - 精确版本: @v1.0.0
@@ -32,6 +44,10 @@ export interface SkillsDefaults {
32
44
  registry?: string;
33
45
  /** 安装目录,默认 .skills */
34
46
  installDir?: string;
47
+ /** 目标 agents 列表 */
48
+ targetAgents?: string[];
49
+ /** 安装模式: symlink | copy */
50
+ installMode?: 'symlink' | 'copy';
35
51
  }
36
52
  /**
37
53
  * Skill 覆盖配置
@@ -193,8 +209,14 @@ export interface InstallOptions {
193
209
  force?: boolean;
194
210
  /** 保存到 skills.json */
195
211
  save?: boolean;
196
- /** 全局安装到 ~/.claude/skills */
212
+ /** 全局安装 */
197
213
  global?: boolean;
214
+ /** 目标 agents 列表 */
215
+ agents?: string[];
216
+ /** 安装模式: symlink | copy */
217
+ mode?: 'symlink' | 'copy';
218
+ /** 跳过确认 */
219
+ yes?: boolean;
198
220
  }
199
221
  /**
200
222
  * 更新选项