@open-skills-hub/cli 1.0.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/commands/cache.d.ts +6 -0
- package/dist/commands/cache.d.ts.map +1 -0
- package/dist/commands/cache.js +145 -0
- package/dist/commands/cache.js.map +1 -0
- package/dist/commands/config.d.ts +6 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +128 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/create.d.ts +7 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +449 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/feedback.d.ts +6 -0
- package/dist/commands/feedback.d.ts.map +1 -0
- package/dist/commands/feedback.js +137 -0
- package/dist/commands/feedback.js.map +1 -0
- package/dist/commands/get.d.ts +6 -0
- package/dist/commands/get.d.ts.map +1 -0
- package/dist/commands/get.js +122 -0
- package/dist/commands/get.js.map +1 -0
- package/dist/commands/index.d.ts +13 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +13 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/publish.d.ts +7 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +593 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/scan.d.ts +6 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +165 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/search.d.ts +6 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +80 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/validate.d.ts +7 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +328 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +107 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
- package/src/commands/cache.ts +166 -0
- package/src/commands/config.ts +142 -0
- package/src/commands/create.ts +490 -0
- package/src/commands/feedback.ts +161 -0
- package/src/commands/get.ts +141 -0
- package/src/commands/index.ts +13 -0
- package/src/commands/publish.ts +688 -0
- package/src/commands/scan.ts +190 -0
- package/src/commands/search.ts +92 -0
- package/src/commands/validate.ts +391 -0
- package/src/index.ts +118 -0
- package/tsconfig.json +13 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Open Skills Hub CLI - Entry Point
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import { initConfig } from '@open-skills-hub/core';
|
|
8
|
+
import { searchCommand } from './commands/search.js';
|
|
9
|
+
import { getCommand } from './commands/get.js';
|
|
10
|
+
import { publishCommand } from './commands/publish.js';
|
|
11
|
+
import { validateCommand } from './commands/validate.js';
|
|
12
|
+
import { createCommand } from './commands/create.js';
|
|
13
|
+
import { scanCommand } from './commands/scan.js';
|
|
14
|
+
import { feedbackCommand } from './commands/feedback.js';
|
|
15
|
+
import { cacheCommand } from './commands/cache.js';
|
|
16
|
+
import { configCommand } from './commands/config.js';
|
|
17
|
+
// Package info
|
|
18
|
+
const VERSION = '1.0.0';
|
|
19
|
+
const DESCRIPTION = 'Open Skills Hub CLI - AI 时代的 npm + Docker Hub';
|
|
20
|
+
// Create the CLI program
|
|
21
|
+
const program = new Command();
|
|
22
|
+
program
|
|
23
|
+
.name('skills')
|
|
24
|
+
.version(VERSION)
|
|
25
|
+
.description(DESCRIPTION)
|
|
26
|
+
.option('-v, --verbose', 'Enable verbose output')
|
|
27
|
+
.option('-q, --quiet', 'Suppress output')
|
|
28
|
+
.option('--config <path>', 'Path to configuration file')
|
|
29
|
+
.hook('preAction', async (thisCommand) => {
|
|
30
|
+
// Initialize configuration
|
|
31
|
+
const options = thisCommand.opts();
|
|
32
|
+
const config = initConfig(options['config']);
|
|
33
|
+
await config.load();
|
|
34
|
+
// Set log level based on flags
|
|
35
|
+
if (options['verbose']) {
|
|
36
|
+
config.setValue('logLevel', 'debug');
|
|
37
|
+
}
|
|
38
|
+
else if (options['quiet']) {
|
|
39
|
+
config.setValue('logLevel', 'error');
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
// Register commands
|
|
43
|
+
program.addCommand(searchCommand);
|
|
44
|
+
program.addCommand(getCommand);
|
|
45
|
+
program.addCommand(createCommand);
|
|
46
|
+
program.addCommand(validateCommand);
|
|
47
|
+
program.addCommand(publishCommand);
|
|
48
|
+
program.addCommand(scanCommand);
|
|
49
|
+
program.addCommand(feedbackCommand);
|
|
50
|
+
program.addCommand(cacheCommand);
|
|
51
|
+
program.addCommand(configCommand);
|
|
52
|
+
// Help text customization
|
|
53
|
+
program.configureHelp({
|
|
54
|
+
sortSubcommands: true,
|
|
55
|
+
subcommandTerm: (cmd) => cmd.name(),
|
|
56
|
+
});
|
|
57
|
+
// Custom help
|
|
58
|
+
program.addHelpText('after', `
|
|
59
|
+
${chalk.bold('Examples:')}
|
|
60
|
+
${chalk.gray('# Create a new skill')}
|
|
61
|
+
$ skills create my-skill
|
|
62
|
+
|
|
63
|
+
${chalk.gray('# Validate a skill')}
|
|
64
|
+
$ skills validate ./my-skill
|
|
65
|
+
|
|
66
|
+
${chalk.gray('# Publish a skill directory')}
|
|
67
|
+
$ skills publish ./my-skill
|
|
68
|
+
|
|
69
|
+
${chalk.gray('# Search for skills')}
|
|
70
|
+
$ skills search "code review"
|
|
71
|
+
|
|
72
|
+
${chalk.gray('# Get skill content')}
|
|
73
|
+
$ skills get code-reviewer
|
|
74
|
+
|
|
75
|
+
${chalk.gray('# Scan content for security issues')}
|
|
76
|
+
$ skills scan ./my-skill.md
|
|
77
|
+
|
|
78
|
+
${chalk.bold('Documentation:')}
|
|
79
|
+
https://github.com/OpenSkillsHub/open-skills-hub
|
|
80
|
+
`);
|
|
81
|
+
// Error handling
|
|
82
|
+
program.exitOverride();
|
|
83
|
+
// Run the CLI
|
|
84
|
+
async function main() {
|
|
85
|
+
try {
|
|
86
|
+
await program.parseAsync(process.argv);
|
|
87
|
+
// Explicitly exit after successful command execution
|
|
88
|
+
// This ensures the process doesn't hang waiting for async operations
|
|
89
|
+
process.exit(0);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
if (error instanceof Error) {
|
|
93
|
+
// Commander's exit override throws errors for help/version
|
|
94
|
+
if (error.message.includes('(commander.helpDisplayed)') ||
|
|
95
|
+
error.message.includes('(commander.version)')) {
|
|
96
|
+
process.exit(0);
|
|
97
|
+
}
|
|
98
|
+
console.error(chalk.red('\nError:'), error.message);
|
|
99
|
+
if (process.env['DEBUG']) {
|
|
100
|
+
console.error(chalk.gray(error.stack));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
main();
|
|
107
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAU,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,eAAe;AACf,MAAM,OAAO,GAAG,OAAO,CAAC;AACxB,MAAM,WAAW,GAAG,+CAA+C,CAAC;AAEpE,yBAAyB;AACzB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,WAAW,CAAC;KACxB,MAAM,CAAC,eAAe,EAAE,uBAAuB,CAAC;KAChD,MAAM,CAAC,aAAa,EAAE,iBAAiB,CAAC;KACxC,MAAM,CAAC,iBAAiB,EAAE,4BAA4B,CAAC;KACvD,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE;IACvC,2BAA2B;IAC3B,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7C,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IAEpB,+BAA+B;IAC/B,IAAI,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACvB,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;SAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,oBAAoB;AACpB,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AAC/B,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAElC,0BAA0B;AAC1B,OAAO,CAAC,aAAa,CAAC;IACpB,eAAe,EAAE,IAAI;IACrB,cAAc,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE;CACpC,CAAC,CAAC;AAEH,cAAc;AACd,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE;EAC3B,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC;IACrB,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC;;;IAGlC,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC;;;IAGhC,KAAK,CAAC,IAAI,CAAC,6BAA6B,CAAC;;;IAGzC,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC;;;IAGjC,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC;;;IAGjC,KAAK,CAAC,IAAI,CAAC,oCAAoC,CAAC;;;EAGlD,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC;;CAE7B,CAAC,CAAC;AAEH,iBAAiB;AACjB,OAAO,CAAC,YAAY,EAAE,CAAC;AAEvB,cAAc;AACd,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,qDAAqD;QACrD,qEAAqE;QACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,2DAA2D;YAC3D,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAC;gBACnD,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;gBAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YAEpD,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@open-skills-hub/cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI for Open Skills Hub",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"skills": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"dev": "tsx watch src/index.ts",
|
|
14
|
+
"start": "node dist/index.js",
|
|
15
|
+
"clean": "rm -rf dist"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@open-skills-hub/core": "1.0.0",
|
|
19
|
+
"commander": "^11.1.0",
|
|
20
|
+
"chalk": "^5.3.0",
|
|
21
|
+
"ora": "^8.0.1",
|
|
22
|
+
"inquirer": "^9.2.12",
|
|
23
|
+
"cli-table3": "^0.6.3",
|
|
24
|
+
"yaml": "^2.3.4",
|
|
25
|
+
"zod": "^3.22.4"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"tsx": "^4.7.0",
|
|
29
|
+
"@types/node": "^20.10.6",
|
|
30
|
+
"@types/inquirer": "^9.0.7"
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/OpenSkillsHub/open-skills-hub.git",
|
|
35
|
+
"directory": "packages/cli"
|
|
36
|
+
},
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/OpenSkillsHub/open-skills-hub/issues"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/OpenSkillsHub/open-skills-hub#readme",
|
|
41
|
+
"keywords": [
|
|
42
|
+
"skills",
|
|
43
|
+
"ai",
|
|
44
|
+
"agent",
|
|
45
|
+
"cli",
|
|
46
|
+
"command-line",
|
|
47
|
+
"mcp"
|
|
48
|
+
],
|
|
49
|
+
"author": "Open Skills Hub Team",
|
|
50
|
+
"license": "MIT"
|
|
51
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Open Skills Hub CLI - Cache Command
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import ora from 'ora';
|
|
8
|
+
import Table from 'cli-table3';
|
|
9
|
+
import { getStorage, getConfig, formatBytes } from '@open-skills-hub/core';
|
|
10
|
+
|
|
11
|
+
export const cacheCommand = new Command('cache')
|
|
12
|
+
.description('Manage local cache')
|
|
13
|
+
.addCommand(
|
|
14
|
+
new Command('list')
|
|
15
|
+
.description('List cached skills')
|
|
16
|
+
.option('--json', 'Output as JSON')
|
|
17
|
+
.action(async (options) => {
|
|
18
|
+
const spinner = ora('Loading cache info...').start();
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const storage = await getStorage();
|
|
22
|
+
await storage.initialize();
|
|
23
|
+
|
|
24
|
+
const cacheEntries = await storage.getAllCacheMetadata();
|
|
25
|
+
spinner.stop();
|
|
26
|
+
|
|
27
|
+
if (options.json) {
|
|
28
|
+
console.log(JSON.stringify(cacheEntries, null, 2));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (cacheEntries.length === 0) {
|
|
33
|
+
console.log(chalk.yellow('\nNo cached skills found.'));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.log(chalk.bold(`\nCached Skills (${cacheEntries.length}):\n`));
|
|
38
|
+
|
|
39
|
+
const table = new Table({
|
|
40
|
+
head: [
|
|
41
|
+
chalk.cyan('Skill'),
|
|
42
|
+
chalk.cyan('Version'),
|
|
43
|
+
chalk.cyan('Size'),
|
|
44
|
+
chalk.cyan('Hits'),
|
|
45
|
+
chalk.cyan('Cached At'),
|
|
46
|
+
],
|
|
47
|
+
colWidths: [30, 12, 12, 8, 25],
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
let totalSize = 0;
|
|
51
|
+
let totalHits = 0;
|
|
52
|
+
|
|
53
|
+
for (const entry of cacheEntries) {
|
|
54
|
+
table.push([
|
|
55
|
+
entry.skillName,
|
|
56
|
+
entry.version,
|
|
57
|
+
formatBytes(entry.size ?? 0),
|
|
58
|
+
entry.hitCount.toString(),
|
|
59
|
+
entry.cachedAt.split('T')[0] ?? '',
|
|
60
|
+
]);
|
|
61
|
+
totalSize += entry.size ?? 0;
|
|
62
|
+
totalHits += entry.hitCount;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.log(table.toString());
|
|
66
|
+
console.log();
|
|
67
|
+
console.log(chalk.gray(`Total size: ${formatBytes(totalSize)}`));
|
|
68
|
+
console.log(chalk.gray(`Total hits: ${totalHits}`));
|
|
69
|
+
|
|
70
|
+
await storage.close();
|
|
71
|
+
} catch (error) {
|
|
72
|
+
spinner.fail('Failed to list cache');
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
)
|
|
77
|
+
.addCommand(
|
|
78
|
+
new Command('clear')
|
|
79
|
+
.description('Clear cached skills')
|
|
80
|
+
.option('-n, --name <name>', 'Clear specific skill')
|
|
81
|
+
.option('-a, --all', 'Clear all cache')
|
|
82
|
+
.option('-e, --expired', 'Clear only expired entries')
|
|
83
|
+
.action(async (options) => {
|
|
84
|
+
const spinner = ora('Clearing cache...').start();
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const storage = await getStorage();
|
|
88
|
+
await storage.initialize();
|
|
89
|
+
|
|
90
|
+
let cleared = 0;
|
|
91
|
+
|
|
92
|
+
if (options.expired) {
|
|
93
|
+
const expiredEntries = await storage.getExpiredCacheEntries();
|
|
94
|
+
for (const entry of expiredEntries) {
|
|
95
|
+
await storage.deleteCacheMetadata(entry.skillName, entry.version);
|
|
96
|
+
cleared++;
|
|
97
|
+
}
|
|
98
|
+
} else if (options.name) {
|
|
99
|
+
const deleted = await storage.deleteCacheMetadata(options.name);
|
|
100
|
+
if (deleted) cleared++;
|
|
101
|
+
} else if (options.all) {
|
|
102
|
+
const allEntries = await storage.getAllCacheMetadata();
|
|
103
|
+
for (const entry of allEntries) {
|
|
104
|
+
await storage.deleteCacheMetadata(entry.skillName, entry.version);
|
|
105
|
+
cleared++;
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
spinner.info('Specify --all, --expired, or --name <skill>');
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
spinner.succeed(`Cleared ${cleared} cache entries`);
|
|
113
|
+
await storage.close();
|
|
114
|
+
} catch (error) {
|
|
115
|
+
spinner.fail('Failed to clear cache');
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
)
|
|
120
|
+
.addCommand(
|
|
121
|
+
new Command('stats')
|
|
122
|
+
.description('Show cache statistics')
|
|
123
|
+
.action(async () => {
|
|
124
|
+
const spinner = ora('Calculating statistics...').start();
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
const storage = await getStorage();
|
|
128
|
+
await storage.initialize();
|
|
129
|
+
const config = getConfig();
|
|
130
|
+
|
|
131
|
+
const cacheEntries = await storage.getAllCacheMetadata();
|
|
132
|
+
const expiredEntries = await storage.getExpiredCacheEntries();
|
|
133
|
+
|
|
134
|
+
spinner.stop();
|
|
135
|
+
|
|
136
|
+
const totalSize = cacheEntries.reduce((sum, c) => sum + (c.size ?? 0), 0);
|
|
137
|
+
const totalHits = cacheEntries.reduce((sum, c) => sum + c.hitCount, 0);
|
|
138
|
+
const uniqueSkills = new Set(cacheEntries.map(c => c.skillName)).size;
|
|
139
|
+
|
|
140
|
+
console.log(chalk.bold('\nCache Statistics:\n'));
|
|
141
|
+
console.log(` ${chalk.cyan('Total entries:')} ${cacheEntries.length}`);
|
|
142
|
+
console.log(` ${chalk.cyan('Unique skills:')} ${uniqueSkills}`);
|
|
143
|
+
console.log(` ${chalk.cyan('Total size:')} ${formatBytes(totalSize)}`);
|
|
144
|
+
console.log(` ${chalk.cyan('Max size:')} ${formatBytes(config.get().cache.maxSize)}`);
|
|
145
|
+
console.log(` ${chalk.cyan('Usage:')} ${Math.round((totalSize / config.get().cache.maxSize) * 100)}%`);
|
|
146
|
+
console.log(` ${chalk.cyan('Total hits:')} ${totalHits}`);
|
|
147
|
+
console.log(` ${chalk.cyan('Expired:')} ${expiredEntries.length}`);
|
|
148
|
+
console.log(` ${chalk.cyan('TTL:')} ${config.get().cache.ttl}s`);
|
|
149
|
+
console.log();
|
|
150
|
+
|
|
151
|
+
// Most accessed
|
|
152
|
+
if (cacheEntries.length > 0) {
|
|
153
|
+
const sorted = [...cacheEntries].sort((a, b) => b.hitCount - a.hitCount);
|
|
154
|
+
console.log(chalk.bold('Most accessed:'));
|
|
155
|
+
for (const entry of sorted.slice(0, 5)) {
|
|
156
|
+
console.log(` • ${entry.skillName}@${entry.version} (${entry.hitCount} hits)`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
await storage.close();
|
|
161
|
+
} catch (error) {
|
|
162
|
+
spinner.fail('Failed to get statistics');
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
);
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Open Skills Hub CLI - Config Command
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import ora from 'ora';
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import { getConfig, initConfig } from '@open-skills-hub/core';
|
|
10
|
+
import { stringify as stringifyYaml } from 'yaml';
|
|
11
|
+
|
|
12
|
+
export const configCommand = new Command('config')
|
|
13
|
+
.description('Manage configuration')
|
|
14
|
+
.addCommand(
|
|
15
|
+
new Command('show')
|
|
16
|
+
.description('Show current configuration')
|
|
17
|
+
.option('--json', 'Output as JSON')
|
|
18
|
+
.action(async (options) => {
|
|
19
|
+
const config = getConfig();
|
|
20
|
+
const current = config.get();
|
|
21
|
+
|
|
22
|
+
if (options.json) {
|
|
23
|
+
console.log(JSON.stringify(current, null, 2));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
console.log(chalk.bold('\nCurrent Configuration:\n'));
|
|
28
|
+
console.log(stringifyYaml(current, { indent: 2 }));
|
|
29
|
+
})
|
|
30
|
+
)
|
|
31
|
+
.addCommand(
|
|
32
|
+
new Command('get')
|
|
33
|
+
.description('Get a specific configuration value')
|
|
34
|
+
.argument('<key>', 'Configuration key (e.g., mode, server.port)')
|
|
35
|
+
.action(async (key) => {
|
|
36
|
+
const config = getConfig();
|
|
37
|
+
const current = config.get();
|
|
38
|
+
|
|
39
|
+
// Navigate nested keys
|
|
40
|
+
const keys = key.split('.');
|
|
41
|
+
let value: unknown = current;
|
|
42
|
+
for (const k of keys) {
|
|
43
|
+
if (value && typeof value === 'object' && k in value) {
|
|
44
|
+
value = (value as Record<string, unknown>)[k];
|
|
45
|
+
} else {
|
|
46
|
+
console.log(chalk.red(`Key not found: ${key}`));
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (typeof value === 'object') {
|
|
52
|
+
console.log(JSON.stringify(value, null, 2));
|
|
53
|
+
} else {
|
|
54
|
+
console.log(value);
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
)
|
|
58
|
+
.addCommand(
|
|
59
|
+
new Command('set')
|
|
60
|
+
.description('Set a configuration value')
|
|
61
|
+
.argument('<key>', 'Configuration key')
|
|
62
|
+
.argument('<value>', 'Value to set')
|
|
63
|
+
.action(async (key, value) => {
|
|
64
|
+
const spinner = ora('Saving configuration...').start();
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const config = getConfig();
|
|
68
|
+
const current = config.get();
|
|
69
|
+
|
|
70
|
+
// Parse value
|
|
71
|
+
let parsedValue: unknown = value;
|
|
72
|
+
if (value === 'true') parsedValue = true;
|
|
73
|
+
else if (value === 'false') parsedValue = false;
|
|
74
|
+
else if (/^\d+$/.test(value)) parsedValue = parseInt(value, 10);
|
|
75
|
+
else if (/^\d+\.\d+$/.test(value)) parsedValue = parseFloat(value);
|
|
76
|
+
|
|
77
|
+
// Navigate and set nested keys
|
|
78
|
+
const keys = key.split('.');
|
|
79
|
+
if (keys.length === 1) {
|
|
80
|
+
config.setValue(key as keyof typeof current, parsedValue as typeof current[keyof typeof current]);
|
|
81
|
+
} else {
|
|
82
|
+
// Handle nested keys
|
|
83
|
+
let target: Record<string, unknown> = current;
|
|
84
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
85
|
+
const k = keys[i]!;
|
|
86
|
+
if (!(k in target)) {
|
|
87
|
+
target[k] = {};
|
|
88
|
+
}
|
|
89
|
+
target = target[k] as Record<string, unknown>;
|
|
90
|
+
}
|
|
91
|
+
target[keys[keys.length - 1]!] = parsedValue;
|
|
92
|
+
config.set(current);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
await config.save();
|
|
96
|
+
spinner.succeed(`Set ${key} = ${parsedValue}`);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
spinner.fail('Failed to save configuration');
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
)
|
|
103
|
+
.addCommand(
|
|
104
|
+
new Command('reset')
|
|
105
|
+
.description('Reset configuration to defaults')
|
|
106
|
+
.option('-y, --yes', 'Skip confirmation')
|
|
107
|
+
.action(async (options) => {
|
|
108
|
+
if (!options.yes) {
|
|
109
|
+
console.log(chalk.yellow('This will reset all configuration to defaults.'));
|
|
110
|
+
console.log('Use --yes to confirm.');
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const spinner = ora('Resetting configuration...').start();
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
const config = getConfig();
|
|
118
|
+
config.reset();
|
|
119
|
+
await config.save();
|
|
120
|
+
spinner.succeed('Configuration reset to defaults');
|
|
121
|
+
} catch (error) {
|
|
122
|
+
spinner.fail('Failed to reset configuration');
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
)
|
|
127
|
+
.addCommand(
|
|
128
|
+
new Command('path')
|
|
129
|
+
.description('Show configuration file paths')
|
|
130
|
+
.action(async () => {
|
|
131
|
+
const config = getConfig();
|
|
132
|
+
|
|
133
|
+
console.log(chalk.bold('\nConfiguration Paths:\n'));
|
|
134
|
+
console.log(` ${chalk.cyan('Storage:')} ${config.getStoragePath()}`);
|
|
135
|
+
console.log(` ${chalk.cyan('Database:')} ${config.getDatabasePath()}`);
|
|
136
|
+
console.log(` ${chalk.cyan('Cache:')} ${config.getCachePath()}`);
|
|
137
|
+
console.log(` ${chalk.cyan('Local:')} ${config.getLocalSkillsPath()}`);
|
|
138
|
+
console.log(` ${chalk.cyan('Logs:')} ${config.getLogsPath()}`);
|
|
139
|
+
console.log(` ${chalk.cyan('Queue:')} ${config.getQueuePath()}`);
|
|
140
|
+
console.log();
|
|
141
|
+
})
|
|
142
|
+
);
|