sophhub 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -40,7 +40,7 @@ sophhub list --type store --json
40
40
 
41
41
  ### 下载 Skill
42
42
 
43
- 下载到当前目录:
43
+ 下载单个 Skill 到当前目录:
44
44
 
45
45
  ```bash
46
46
  sophhub download weather
@@ -52,6 +52,13 @@ sophhub download weather
52
52
  sophhub download didi-ride -o ./my-skills
53
53
  ```
54
54
 
55
+ 批量下载某个类型的所有 Skill:
56
+
57
+ ```bash
58
+ sophhub download --type builtin -o ./skills
59
+ sophhub download --type store -o ./skills
60
+ ```
61
+
55
62
  ### 查看版本
56
63
 
57
64
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sophhub",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "SophHub CLI - Manage and download AI Agent skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -2,7 +2,7 @@
2
2
 
3
3
  | Skill | Type | Version | Updated At | Display Name | Description |
4
4
  | --- | --- | --- | --- | --- | --- |
5
- | skillhub | builtin | 2.0.0 | 2026-04-09 | | |
5
+ | skillhub | builtin | 1.0.0 | 2026-04-09 | | |
6
6
  | flight-booking | builtin | 1.1.0 | 2026-04-08 | | |
7
7
  | inventory-management | builtin | 1.0.0 | 2026-04-08 | | |
8
8
  | schedule-reminder | builtin | 1.0.0 | 2026-04-08 | | |
@@ -1,74 +1,101 @@
1
1
  import chalk from 'chalk';
2
2
  import fs from 'node:fs/promises';
3
3
  import path from 'node:path';
4
- import readline from 'node:readline/promises';
5
- import { findSkill } from '../utils/versions.js';
4
+ import { findSkill, parseVersions } from '../utils/versions.js';
6
5
  import { getSkillDir } from '../utils/paths.js';
7
6
  import { loadConfig } from '../utils/config.js';
8
7
 
9
- async function confirmOverwrite(destDir) {
10
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
8
+ async function downloadSingle(skillName, outputDir) {
9
+ const skill = await findSkill(skillName);
10
+ if (!skill) {
11
+ console.error(chalk.red(`Skill "${skillName}" not found.`));
12
+ console.error(chalk.gray('Run "sophhub list" to see all available skills.'));
13
+ process.exit(1);
14
+ }
15
+
16
+ const destDir = path.join(outputDir, skillName);
17
+
18
+ try {
19
+ await fs.access(destDir);
20
+ await fs.rm(destDir, { recursive: true, force: true });
21
+ } catch {
22
+ // dest does not exist
23
+ }
24
+
25
+ const srcDir = getSkillDir(skill.type, skillName);
11
26
  try {
12
- const answer = await rl.question(
13
- chalk.yellow(` "${destDir}" already exists. Overwrite? [y/N] `),
14
- );
15
- return answer.trim().toLowerCase() === 'y';
16
- } finally {
17
- rl.close();
27
+ await fs.access(srcDir);
28
+ } catch {
29
+ throw new Error(`Skill directory not found in package: ${srcDir}`);
18
30
  }
31
+
32
+ await fs.cp(srcDir, destDir, { recursive: true });
33
+
34
+ console.log(chalk.green(` ✓ ${skill.name}`) + chalk.gray(` (${skill.version}) → ${destDir}`));
19
35
  }
20
36
 
21
37
  export function registerDownloadCommand(program) {
22
38
  program
23
39
  .command('download')
24
- .description('Download a skill to local directory')
25
- .argument('<skill-name>', 'Name of the skill to download')
40
+ .description('Download skill(s) to local directory')
41
+ .argument('[skill-name]', 'Name of the skill to download')
26
42
  .option('-o, --output <dir>', 'Target directory (default: current directory)')
43
+ .option('-t, --type <type>', 'Download all skills of the given type (builtin/store)')
27
44
  .action(async (skillName, opts) => {
28
45
  try {
29
46
  const config = await loadConfig();
30
47
  const outputDir = path.resolve(opts.output || config.defaultOutput || '.');
48
+ await fs.mkdir(outputDir, { recursive: true });
31
49
 
32
- const skill = await findSkill(skillName);
33
- if (!skill) {
34
- console.error(chalk.red(`Skill "${skillName}" not found.`));
35
- console.error(chalk.gray('Run "sophhub list" to see all available skills.'));
36
- process.exit(1);
37
- }
50
+ if (opts.type) {
51
+ const typeFilter = opts.type.toLowerCase();
52
+ if (typeFilter !== 'builtin' && typeFilter !== 'store') {
53
+ console.error(chalk.red('\n --type must be "builtin" or "store"\n'));
54
+ process.exit(1);
55
+ }
38
56
 
39
- const destDir = path.join(outputDir, skillName);
57
+ const skills = await parseVersions();
58
+ const filtered = skills.filter((s) => s.type === typeFilter);
40
59
 
41
- try {
42
- await fs.access(destDir);
43
- const ok = await confirmOverwrite(destDir);
44
- if (!ok) {
45
- console.log(chalk.gray('Cancelled.'));
60
+ if (filtered.length === 0) {
61
+ console.log(chalk.yellow(`\n No skills found for type "${typeFilter}".\n`));
46
62
  return;
47
63
  }
48
- await fs.rm(destDir, { recursive: true, force: true });
49
- } catch {
50
- // dest does not exist, proceed
51
- }
52
64
 
53
- await fs.mkdir(outputDir, { recursive: true });
65
+ console.log();
66
+ console.log(chalk.cyan(` Downloading all ${typeFilter} skills (${filtered.length})...`));
67
+ console.log();
54
68
 
55
- console.log();
56
- console.log(chalk.gray(` Downloading ${skillName}...`));
69
+ let success = 0;
70
+ for (const skill of filtered) {
71
+ try {
72
+ await downloadSingle(skill.name, outputDir);
73
+ success++;
74
+ } catch (err) {
75
+ console.error(chalk.red(` ✗ ${skill.name}: ${err.message}`));
76
+ }
77
+ }
57
78
 
58
- const srcDir = getSkillDir(skill.type, skillName);
59
- try {
60
- await fs.access(srcDir);
61
- } catch {
62
- throw new Error(`Skill directory not found in package: ${srcDir}`);
79
+ console.log();
80
+ console.log(chalk.green(` Done. ${success}/${filtered.length} skills downloaded to ${outputDir}`));
81
+ console.log();
82
+ return;
63
83
  }
64
84
 
65
- await fs.cp(srcDir, destDir, { recursive: true });
85
+ if (!skillName) {
86
+ console.error(chalk.red('\n Please specify a skill name or use --type to batch download.\n'));
87
+ console.error(chalk.gray(' Examples:'));
88
+ console.error(chalk.gray(' sophhub download <skill-name>'));
89
+ console.error(chalk.gray(' sophhub download --type builtin'));
90
+ console.error(chalk.gray(' sophhub download --type store\n'));
91
+ process.exit(1);
92
+ }
66
93
 
67
94
  console.log();
68
- console.log(chalk.green(' Download complete'));
69
- console.log(chalk.gray(` Skill: ${skill.name}`));
70
- console.log(chalk.gray(` Version: ${skill.version}`));
71
- console.log(chalk.gray(` Path: ${destDir}`));
95
+ console.log(chalk.gray(` Downloading ${skillName}...`));
96
+
97
+ await downloadSingle(skillName, outputDir);
98
+
72
99
  console.log();
73
100
  } catch (err) {
74
101
  console.error(chalk.red(`\n Failed to download: ${err.message}\n`));