sync: AI review scores, reviewed page, search improvements, score filter
- Surface AI review scores across skill pages, browse, and search - Add dedicated /reviewed page with score filtering - Add recommended sort using Meilisearch relevance + AI scores - Fix search sort defaulting to stars instead of recommended - Fix CLI TypeScript null check for aiScore in search command - Adjust cache TTL for reviewed content Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "skillhub",
|
||||
"version": "0.2.5",
|
||||
"version": "0.2.9",
|
||||
"description": "CLI tool for managing AI Agent skills - search, install, and update skills for Claude, Codex, Copilot, and more",
|
||||
"author": "SkillHub Contributors",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -39,7 +39,12 @@ export async function install(skillId: string, options: InstallOptions): Promise
|
||||
try {
|
||||
skillInfo = await getSkill(skillId);
|
||||
if (skillInfo) {
|
||||
spinner.succeed(`Found in registry: ${skillInfo.name}`);
|
||||
const reviewBadge = skillInfo.aiScore && skillInfo.reviewStatus === 'ai-reviewed'
|
||||
? chalk.dim(` | AI: ${skillInfo.aiScore}/100`)
|
||||
: skillInfo.reviewStatus === 'verified'
|
||||
? chalk.green(` | AI: ${skillInfo.aiScore}/100 ✓`)
|
||||
: '';
|
||||
spinner.succeed(`Found in registry: ${skillInfo.name}${reviewBadge}`);
|
||||
spinner.start('Preparing installation...');
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -18,7 +18,7 @@ export async function search(query: string, options: SearchOptions): Promise<voi
|
||||
try {
|
||||
const limit = parseInt(options.limit || '10');
|
||||
const page = parseInt(options.page || '1');
|
||||
const sort = options.sort || 'downloads';
|
||||
const sort = options.sort || 'recommended';
|
||||
const result = await searchSkills(query, {
|
||||
platform: options.platform,
|
||||
limit,
|
||||
@@ -34,7 +34,7 @@ export async function search(query: string, options: SearchOptions): Promise<voi
|
||||
return;
|
||||
}
|
||||
|
||||
const sortLabel = { downloads: 'downloads', stars: 'GitHub stars', rating: 'rating', recent: 'recently updated' }[sort] || sort;
|
||||
const sortLabel = { recommended: 'recommended', downloads: 'downloads', stars: 'GitHub stars', rating: 'rating', recent: 'recently updated', aiScore: 'AI score' }[sort] || sort;
|
||||
console.log(chalk.bold(`Found ${result.pagination.total} skills (sorted by ${sortLabel}):\n`));
|
||||
|
||||
// Print results as a table
|
||||
@@ -57,9 +57,14 @@ export async function search(query: string, options: SearchOptions): Promise<voi
|
||||
`${num} ${verified} ${chalk.cyan(skill.id.padEnd(38))} ${security}`
|
||||
);
|
||||
|
||||
// Second line: downloads, stars, description
|
||||
// Second line: AI score (if reviewed) + downloads + stars + description
|
||||
const aiScore = skill.aiScore;
|
||||
const hasAiScore = aiScore != null && aiScore > 0 && skill.reviewStatus && skill.reviewStatus !== 'unreviewed' && skill.reviewStatus !== 'auto-scored';
|
||||
const aiPrefix = hasAiScore
|
||||
? `${chalk.magenta('AI')} ${(aiScore >= 75 ? chalk.green : aiScore >= 50 ? chalk.yellow : chalk.dim)(String(aiScore))} `
|
||||
: '';
|
||||
console.log(
|
||||
` ⬇ ${formatNumber(skill.downloadCount).padStart(6)} ⭐ ${formatNumber(skill.githubStars).padStart(6)} ${chalk.dim(skill.description.slice(0, 55))}${skill.description.length > 55 ? '...' : ''}`
|
||||
` ${aiPrefix}⬇ ${formatNumber(skill.downloadCount).padStart(6)} ⭐ ${formatNumber(skill.githubStars).padStart(6)} ${chalk.dim(skill.description.slice(0, hasAiScore ? 45 : 55))}${skill.description.length > (hasAiScore ? 45 : 55) ? '...' : ''}`
|
||||
);
|
||||
|
||||
// Third line: Rating (only if ratingCount >= 3)
|
||||
@@ -83,8 +88,8 @@ export async function search(query: string, options: SearchOptions): Promise<voi
|
||||
);
|
||||
}
|
||||
|
||||
if (sort === 'downloads') {
|
||||
console.log(chalk.dim(`Sort options: ${chalk.white('--sort stars|rating|recent')}`));
|
||||
if (sort === 'recommended') {
|
||||
console.log(chalk.dim(`Sort options: ${chalk.white('--sort aiScore|downloads|stars|rating|recent')}`));
|
||||
}
|
||||
} catch (error) {
|
||||
spinner.fail('Search failed');
|
||||
|
||||
@@ -46,7 +46,7 @@ program
|
||||
.command('search <query>')
|
||||
.description('Search for skills in the registry')
|
||||
.option('-p, --platform <platform>', 'Filter by platform')
|
||||
.option('-s, --sort <sort>', 'Sort by: downloads, stars, rating, recent', 'downloads')
|
||||
.option('-s, --sort <sort>', 'Sort by: recommended, aiScore, downloads, stars, rating, recent', 'recommended')
|
||||
.option('-l, --limit <number>', 'Number of results', '10')
|
||||
.option('--page <number>', 'Page number', '1')
|
||||
.action(async (query: string, options) => {
|
||||
|
||||
@@ -126,6 +126,8 @@ export interface SkillInfo {
|
||||
sourceFormat?: string;
|
||||
rating?: number | null;
|
||||
ratingCount?: number | null;
|
||||
reviewStatus?: string | null;
|
||||
aiScore?: number | null;
|
||||
isVerified: boolean;
|
||||
compatibility: {
|
||||
platforms: string[];
|
||||
|
||||
Reference in New Issue
Block a user