sophhub 0.1.0 → 0.1.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.
package/bin/sophhub.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sophhub",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "SophHub CLI - Manage and download AI Agent skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,27 +1,27 @@
1
1
  # Skill Versions
2
2
 
3
- | Skill | Type | Version | Updated At |
4
- | --- | --- | --- | --- |
5
- | clawhub | builtin | 1.0.0 | 2026-04-08 |
6
- | flight-booking | builtin | 1.1.0 | 2026-04-08 |
7
- | inventory-management | builtin | 1.0.0 | 2026-04-08 |
8
- | schedule-reminder | builtin | 1.0.0 | 2026-04-08 |
9
- | skill-creator | builtin | 1.0.0 | 2026-04-08 |
10
- | sophnet-customer-management | builtin | 1.0.0 | 2026-04-08 |
11
- | sophnet-customized-marketing | builtin | 1.0.0 | 2026-04-08 |
12
- | sophnet-face-search | builtin | 1.0.0 | 2026-04-08 |
13
- | sophnet-image-edit | builtin | 1.0.0 | 2026-04-08 |
14
- | sophnet-image-generate | builtin | 1.0.0 | 2026-04-08 |
15
- | sophnet-image-ocr | builtin | 1.0.0 | 2026-04-08 |
16
- | sophnet-infinite-talk | builtin | 1.0.0 | 2026-04-08 |
17
- | sophnet-oss | builtin | 1.0.0 | 2026-04-08 |
18
- | sophnet-qa-install | builtin | 2.0.0 | 2026-04-08 |
19
- | sophnet-training-install | builtin | 2.0.0 | 2026-04-08 |
20
- | sophnet-tts | builtin | 1.0.0 | 2026-04-08 |
21
- | sophnet-video-generate | builtin | 1.0.0 | 2026-04-08 |
22
- | video-understand | builtin | 1.0.0 | 2026-04-08 |
23
- | weather | builtin | 1.0.0 | 2026-04-08 |
24
- | web-scraper | builtin | 1.0.0 | 2026-04-08 |
25
- | website-builder | builtin | 1.0.0 | 2026-04-08 |
26
- | didi-ride | store | 1.0.0 | 2026-04-09 |
27
- | flyai | store | 1.0.10 | 2026-04-09 |
3
+ | Skill | Type | Version | Updated At | Display Name | Description |
4
+ | --- | --- | --- | --- | --- | --- |
5
+ | clawhub | builtin | 1.0.0 | 2026-04-08 | | |
6
+ | flight-booking | builtin | 1.1.0 | 2026-04-08 | | |
7
+ | inventory-management | builtin | 1.0.0 | 2026-04-08 | | |
8
+ | schedule-reminder | builtin | 1.0.0 | 2026-04-08 | | |
9
+ | skill-creator | builtin | 1.0.0 | 2026-04-08 | | |
10
+ | sophnet-customer-management | builtin | 1.0.0 | 2026-04-08 | | |
11
+ | sophnet-customized-marketing | builtin | 1.0.0 | 2026-04-08 | | |
12
+ | sophnet-face-search | builtin | 1.0.0 | 2026-04-08 | | |
13
+ | sophnet-image-edit | builtin | 1.0.0 | 2026-04-08 | | |
14
+ | sophnet-image-generate | builtin | 1.0.0 | 2026-04-08 | | |
15
+ | sophnet-image-ocr | builtin | 1.0.0 | 2026-04-08 | | |
16
+ | sophnet-infinite-talk | builtin | 1.0.0 | 2026-04-08 | | |
17
+ | sophnet-oss | builtin | 1.0.0 | 2026-04-08 | | |
18
+ | sophnet-qa-install | builtin | 2.0.0 | 2026-04-08 | | |
19
+ | sophnet-training-install | builtin | 2.0.0 | 2026-04-08 | | |
20
+ | sophnet-tts | builtin | 1.0.0 | 2026-04-08 | | |
21
+ | sophnet-video-generate | builtin | 1.0.0 | 2026-04-08 | | |
22
+ | video-understand | builtin | 1.0.0 | 2026-04-08 | | |
23
+ | weather | builtin | 1.0.0 | 2026-04-08 | | |
24
+ | web-scraper | builtin | 1.0.0 | 2026-04-08 | | |
25
+ | website-builder | builtin | 1.0.0 | 2026-04-08 | | |
26
+ | didi-ride | store | 1.0.0 | 2026-04-09 | 滴滴出行 | 打车、路线规划、周边搜索、订单查询 |
27
+ | flyai | store | 1.0.10 | 2026-04-09 | 飞猪旅行 | 机票、酒店、景点门票、旅行搜索与预订 |
@@ -5,7 +5,6 @@ import readline from 'node:readline/promises';
5
5
  import { findSkill } from '../utils/versions.js';
6
6
  import { getSkillDir } from '../utils/paths.js';
7
7
  import { loadConfig } from '../utils/config.js';
8
- import { downloadFromGitlab } from '../utils/gitlab.js';
9
8
 
10
9
  async function confirmOverwrite(destDir) {
11
10
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
@@ -19,41 +18,17 @@ async function confirmOverwrite(destDir) {
19
18
  }
20
19
  }
21
20
 
22
- async function downloadFromBuiltin(type, skillName, outputDir) {
23
- const srcDir = getSkillDir(type, skillName);
24
-
25
- try {
26
- await fs.access(srcDir);
27
- } catch {
28
- throw new Error(
29
- `Skill directory not found in package: ${srcDir}\n` +
30
- 'The bundled skills may be outdated. Try --source gitlab for the latest version.',
31
- );
32
- }
33
-
34
- const destDir = path.join(outputDir, skillName);
35
- await fs.cp(srcDir, destDir, { recursive: true });
36
- return destDir;
37
- }
38
-
39
21
  export function registerDownloadCommand(program) {
40
22
  program
41
23
  .command('download')
42
24
  .description('Download a skill to local directory')
43
25
  .argument('<skill-name>', 'Name of the skill to download')
44
26
  .option('-o, --output <dir>', 'Target directory (default: current directory)')
45
- .option('-s, --source <source>', 'Data source: builtin (default) or gitlab')
46
27
  .action(async (skillName, opts) => {
47
28
  try {
48
29
  const config = await loadConfig();
49
- const source = opts.source || config.defaultSource || 'builtin';
50
30
  const outputDir = path.resolve(opts.output || config.defaultOutput || '.');
51
31
 
52
- if (source !== 'builtin' && source !== 'gitlab') {
53
- console.error(chalk.red(`Invalid source "${source}". Use "builtin" or "gitlab".`));
54
- process.exit(1);
55
- }
56
-
57
32
  const skill = await findSkill(skillName);
58
33
  if (!skill) {
59
34
  console.error(chalk.red(`Skill "${skillName}" not found.`));
@@ -78,22 +53,22 @@ export function registerDownloadCommand(program) {
78
53
  await fs.mkdir(outputDir, { recursive: true });
79
54
 
80
55
  console.log();
81
- console.log(chalk.gray(` Downloading ${skillName} from ${source}...`));
56
+ console.log(chalk.gray(` Downloading ${skillName}...`));
82
57
 
83
- let result;
84
- if (source === 'gitlab') {
85
- const repoUrl = config.gitlabRepo;
86
- result = await downloadFromGitlab(repoUrl, skill.type, skillName, outputDir);
87
- } else {
88
- result = await downloadFromBuiltin(skill.type, skillName, outputDir);
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}`);
89
63
  }
90
64
 
65
+ await fs.cp(srcDir, destDir, { recursive: true });
66
+
91
67
  console.log();
92
68
  console.log(chalk.green(' ✓ Download complete'));
93
69
  console.log(chalk.gray(` Skill: ${skill.name}`));
94
70
  console.log(chalk.gray(` Version: ${skill.version}`));
95
- console.log(chalk.gray(` Source: ${source}`));
96
- console.log(chalk.gray(` Path: ${result}`));
71
+ console.log(chalk.gray(` Path: ${destDir}`));
97
72
  console.log();
98
73
  } catch (err) {
99
74
  console.error(chalk.red(`\n Failed to download: ${err.message}\n`));
@@ -35,23 +35,34 @@ export function registerListCommand(program) {
35
35
  return;
36
36
  }
37
37
 
38
+ const hasDisplayInfo = skills.some((s) => s.displayName || s.description);
39
+
40
+ const head = [
41
+ chalk.cyan('Skill'),
42
+ chalk.cyan('Type'),
43
+ chalk.cyan('Version'),
44
+ chalk.cyan('Updated At'),
45
+ ];
46
+ if (hasDisplayInfo) {
47
+ head.push(chalk.cyan('Display Name'), chalk.cyan('Description'));
48
+ }
49
+
38
50
  const table = new Table({
39
- head: [
40
- chalk.cyan('Skill'),
41
- chalk.cyan('Type'),
42
- chalk.cyan('Version'),
43
- chalk.cyan('Updated At'),
44
- ],
51
+ head,
45
52
  style: { head: [], border: [] },
46
53
  });
47
54
 
48
55
  for (const s of skills) {
49
- table.push([
56
+ const row = [
50
57
  s.name,
51
58
  s.type === 'builtin' ? chalk.blue(s.type) : chalk.green(s.type),
52
59
  s.version,
53
60
  s.updatedAt,
54
- ]);
61
+ ];
62
+ if (hasDisplayInfo) {
63
+ row.push(s.displayName, s.description);
64
+ }
65
+ table.push(row);
55
66
  }
56
67
 
57
68
  console.log();
@@ -6,8 +6,6 @@ const CONFIG_PATH = path.join(os.homedir(), '.sophhubrc.json');
6
6
 
7
7
  const DEFAULTS = {
8
8
  defaultOutput: '.',
9
- defaultSource: 'builtin',
10
- gitlabRepo: 'git@gitlab.sophgo.vip:llm-open-platform/sophclaw-skills.git',
11
9
  };
12
10
 
13
11
  export async function loadConfig() {
@@ -1,18 +1,8 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import { getVersionsPath } from './paths.js';
3
3
 
4
- /**
5
- * Parse VERSIONS.md markdown table into an array of skill objects.
6
- * Expected format:
7
- * | Skill | Type | Version | Updated At |
8
- * | --- | --- | --- | --- |
9
- * | weather | builtin | 1.0.0 | 2026-04-08 |
10
- */
11
- export async function parseVersions() {
12
- const content = await fs.readFile(getVersionsPath(), 'utf-8');
4
+ function parseMarkdownTable(content) {
13
5
  const lines = content.split('\n').filter((l) => l.trim().startsWith('|'));
14
-
15
- // skip header row and separator row (first two | lines)
16
6
  const dataLines = lines.slice(2);
17
7
 
18
8
  return dataLines
@@ -27,11 +17,18 @@ export async function parseVersions() {
27
17
  type: cells[1],
28
18
  version: cells[2],
29
19
  updatedAt: cells[3],
20
+ displayName: cells[4] || '',
21
+ description: cells[5] || '',
30
22
  };
31
23
  })
32
24
  .filter(Boolean);
33
25
  }
34
26
 
27
+ export async function parseVersions() {
28
+ const content = await fs.readFile(getVersionsPath(), 'utf-8');
29
+ return parseMarkdownTable(content);
30
+ }
31
+
35
32
  export async function findSkill(skillName) {
36
33
  const skills = await parseVersions();
37
34
  return skills.find((s) => s.name === skillName) || null;
@@ -1,67 +0,0 @@
1
- import { execFile } from 'node:child_process';
2
- import { promisify } from 'node:util';
3
- import fs from 'node:fs/promises';
4
- import path from 'node:path';
5
- import os from 'node:os';
6
-
7
- const execFileAsync = promisify(execFile);
8
-
9
- /**
10
- * Download a skill directory from GitLab using `git archive --remote`.
11
- * Falls back to sparse-checkout if archive is not supported by the server.
12
- */
13
- export async function downloadFromGitlab(repoUrl, type, skillName, outputDir) {
14
- const destDir = path.join(outputDir, skillName);
15
- const subPath = `${type}/${skillName}`;
16
-
17
- // Try git archive first (most efficient, single-command)
18
- try {
19
- await fs.mkdir(destDir, { recursive: true });
20
- const { stdout } = await execFileAsync(
21
- 'git',
22
- ['archive', '--remote', repoUrl, 'HEAD', subPath],
23
- { maxBuffer: 50 * 1024 * 1024 },
24
- );
25
-
26
- // pipe tar output through extraction
27
- const tar = execFileAsync('tar', ['-x', '-C', outputDir], {
28
- maxBuffer: 50 * 1024 * 1024,
29
- });
30
- tar.child.stdin.write(stdout);
31
- tar.child.stdin.end();
32
- await tar;
33
-
34
- // git archive extracts to {type}/{skillName}/, move to {outputDir}/{skillName}/
35
- const extracted = path.join(outputDir, type, skillName);
36
- if (extracted !== destDir) {
37
- await fs.cp(extracted, destDir, { recursive: true });
38
- await fs.rm(path.join(outputDir, type), { recursive: true, force: true });
39
- }
40
- return destDir;
41
- } catch {
42
- // archive --remote not supported, fall back to sparse checkout
43
- }
44
-
45
- return downloadViaSparseCheckout(repoUrl, subPath, destDir);
46
- }
47
-
48
- async function downloadViaSparseCheckout(repoUrl, subPath, destDir) {
49
- const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'sophhub-'));
50
-
51
- try {
52
- await execFileAsync(
53
- 'git',
54
- ['clone', '--filter=blob:none', '--sparse', '--depth=1', repoUrl, tmpDir],
55
- { timeout: 120_000 },
56
- );
57
-
58
- await execFileAsync('git', ['sparse-checkout', 'set', subPath], { cwd: tmpDir });
59
-
60
- const src = path.join(tmpDir, subPath);
61
- await fs.cp(src, destDir, { recursive: true });
62
-
63
- return destDir;
64
- } finally {
65
- await fs.rm(tmpDir, { recursive: true, force: true }).catch(() => {});
66
- }
67
- }