eskill 1.2.4 → 1.3.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.
Files changed (3) hide show
  1. package/cli.js +21 -2
  2. package/lib/installer.js +103 -0
  3. package/package.json +1 -1
package/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
3
  import ora from 'ora';
4
- import { installFromGitUrl, listSkills, removeSkill, linkSkill, cleanupAllSkills, cleanupAll, updateSkill, updateAllSkills } from './lib/installer.js';
4
+ import { installFromGitUrl, listSkills, removeSkill, linkSkill, uploadSkill, cleanupAllSkills, cleanupAll, updateSkill, updateAllSkills } from './lib/installer.js';
5
5
  import { AGENTS, getDefaultAgent } from './lib/agent-config.js';
6
6
  import { bashCompletionScript, zshCompletionScript, listSkillsForCompletion } from './lib/completion.js';
7
7
  import { searchSkills, formatSkillList } from './lib/search.js';
@@ -13,7 +13,7 @@ const program = new Command();
13
13
  program
14
14
  .name('eskill')
15
15
  .description('Unified AI Agent Skills Management - Install skills from Git URLs')
16
- .version('1.2.4')
16
+ .version('1.3.0')
17
17
  .option('-g, --global', '使用全局技能目录(~/.eskill/skills/),否则使用当前目录(./.claude/skills/)', false);
18
18
 
19
19
  // 安装命令
@@ -141,6 +141,25 @@ program
141
141
  }
142
142
  });
143
143
 
144
+ // 上传命令
145
+ program
146
+ .command('upload')
147
+ .description('上传本地技能到全局仓库')
148
+ .argument('<name>', '技能名称(支持 name@author 格式)')
149
+ .action(async (name) => {
150
+ try {
151
+ const result = await uploadSkill(name);
152
+
153
+ // 如果用户取消上传,正常退出
154
+ if (result && result.cancelled) {
155
+ process.exit(0);
156
+ }
157
+ } catch (error) {
158
+ console.error(`\n❌ 上传失败: ${error.message}`);
159
+ process.exit(1);
160
+ }
161
+ });
162
+
144
163
  // 更新命令
145
164
  program
146
165
  .command('update')
package/lib/installer.js CHANGED
@@ -842,6 +842,109 @@ export async function linkSkill(skillName) {
842
842
  }
843
843
  }
844
844
 
845
+ /**
846
+ * 上传本地技能到全局仓库
847
+ */
848
+ export async function uploadSkill(skillName) {
849
+ // 解析 skill-name@author 格式,提取实际技能名
850
+ let actualSkillName = skillName;
851
+ const match = skillName.match(/^([^@]+)@([^@]+)$/);
852
+ if (match) {
853
+ actualSkillName = match[1];
854
+ }
855
+
856
+ const localSkillsDir = getSkillsDir(false);
857
+ const globalSkillsDir = getSkillsDir(true);
858
+
859
+ const localSkillPath = join(localSkillsDir, actualSkillName);
860
+ const globalSkillPath = join(globalSkillsDir, actualSkillName);
861
+
862
+ // 检查本地是否存在该技能
863
+ if (!existsSync(localSkillPath)) {
864
+ console.log(`\n❌ 本地不存在技能: ${actualSkillName}`);
865
+ console.log(` 位置: ${localSkillPath}\n`);
866
+ console.log(`💡 提示:`);
867
+ console.log(` - 使用 "eskill list" 查看本地已安装的技能`);
868
+ console.log(` - 使用 "eskill install" 先安装技能到本地\n`);
869
+ throw new Error(`本地不存在技能: ${actualSkillName}`);
870
+ }
871
+
872
+ // 检查是否为符号链接
873
+ try {
874
+ const stat = lstatSync(localSkillPath);
875
+ if (stat.isSymbolicLink()) {
876
+ console.log(`\n❌ 无法上传软链接技能: ${actualSkillName}`);
877
+ console.log(` 软链接指向全局仓库,无法上传\n`);
878
+ console.log(`💡 提示:`);
879
+ console.log(` - 软链接技能已经存在于全局仓库`);
880
+ console.log(` - 如需更新全局技能,请直接在全局仓库中使用 eskill update\n`);
881
+ throw new Error(`无法上传软链接技能`);
882
+ }
883
+ } catch (error) {
884
+ console.error(`检测技能类型失败: ${error.message}`);
885
+ throw error;
886
+ }
887
+
888
+ // 确保全局技能目录存在
889
+ if (!existsSync(globalSkillsDir)) {
890
+ mkdirSync(globalSkillsDir, { recursive: true });
891
+ }
892
+
893
+ // 检查全局是否已存在同名技能
894
+ if (existsSync(globalSkillPath)) {
895
+ console.log(`\n⚠️ 全局仓库已存在同名技能: ${actualSkillName}`);
896
+ console.log(` 位置: ${globalSkillPath}\n`);
897
+
898
+ const overwrite = await confirmAction('是否覆盖全局仓库中的技能?');
899
+ if (!overwrite) {
900
+ console.log('\n已取消上传\n');
901
+ return { success: false, cancelled: true };
902
+ }
903
+
904
+ console.log(`删除全局仓库中已存在的技能: ${globalSkillPath}`);
905
+ rmSync(globalSkillPath, { recursive: true, force: true });
906
+ }
907
+
908
+ // 复制技能到全局仓库
909
+ console.log(`\n上传技能到全局仓库: ${actualSkillName}`);
910
+ console.log(` 源: ${localSkillPath}`);
911
+ console.log(` 目标: ${globalSkillPath}\n`);
912
+
913
+ // 使用 -L 选项解引用符号链接
914
+ if (process.platform === 'win32') {
915
+ execSync(`xcopy "${localSkillPath}" "${globalSkillPath}" /E /I /H /Y`, { stdio: 'inherit' });
916
+ } else {
917
+ execSync(`cp -rL "${localSkillPath}" "${globalSkillPath}"`, { stdio: 'inherit' });
918
+ }
919
+
920
+ // 读取本地元数据
921
+ const localMeta = getSkillMeta(actualSkillName, false);
922
+
923
+ // 保存/更新全局元数据
924
+ if (localMeta) {
925
+ saveSkillMeta(actualSkillName, {
926
+ ...localMeta,
927
+ source: 'github', // 上传到全局后,来源标记为 github
928
+ updatedAt: new Date().toISOString()
929
+ }, true);
930
+ } else {
931
+ // 如果本地没有元数据,创建基础元数据
932
+ saveSkillMeta(actualSkillName, {
933
+ name: actualSkillName,
934
+ source: 'github',
935
+ installedAt: new Date().toISOString(),
936
+ updatedAt: new Date().toISOString()
937
+ }, true);
938
+ }
939
+
940
+ console.log(`\n✓ 技能已上传到全局仓库`);
941
+ console.log(` 技能: ${actualSkillName}`);
942
+ console.log(` 全局位置: ${globalSkillPath}`);
943
+ console.log(` 说明: 技现已可在全局仓库中使用\n`);
944
+
945
+ return { success: true, path: globalSkillPath };
946
+ }
947
+
845
948
  /**
846
949
  * 清理所有技能(用于卸载)
847
950
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eskill",
3
- "version": "1.2.4",
3
+ "version": "1.3.0",
4
4
  "description": "Unified AI Agent Skills Management - Install skills from Git URLs",
5
5
  "main": "index.js",
6
6
  "type": "module",