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:
airano
2026-03-14 05:05:37 +03:30
parent 4212b5ba47
commit 3e22d2e238
34 changed files with 929 additions and 194 deletions

View File

@@ -7,7 +7,7 @@
import { INSTRUCTION_FILE_PATTERNS, type SourceFormat } from 'skillhub-core';
import { scheduleFullCrawl, scheduleIncrementalCrawl, getQueueStats, getQueue } from './queue.js';
import { syncAllSkillsToMeilisearch, checkMeilisearchHealth } from './meilisearch-sync.js';
import { createDb, skillQueries, categoryQueries, discoveredRepoQueries, awesomeListQueries, addRequestQueries, userQueries, skills, sql } from '@skillhub/db';
import { createDb, skillQueries, categoryQueries, discoveredRepoQueries, awesomeListQueries, addRequestQueries, userQueries, sql } from '@skillhub/db';
import { createStrategyOrchestrator, createDeepScanCrawler, createAwesomeListCrawler, createPopularReposCrawler, createCommitsSearchCrawler } from './strategies/index.js';
import { createCrawler } from './crawler.js';
import { indexSkill } from './skill-indexer.js';

View File

@@ -92,6 +92,8 @@ async function initializeIndex(): Promise<void> {
'isFeatured',
'securityScore',
'githubStars',
'reviewStatus',
'aiScore',
]);
// Configure sortable attributes
@@ -100,6 +102,7 @@ async function initializeIndex(): Promise<void> {
'downloadCount',
'rating',
'indexedAt',
'aiScore',
]);
// Configure ranking rules
@@ -144,6 +147,8 @@ export async function syncSkillToMeilisearch(skill: {
securityStatus?: 'pass' | 'warning' | 'fail' | null;
isFeatured?: boolean | null;
isVerified?: boolean | null;
reviewStatus?: string | null;
latestAiScore?: number | null;
indexedAt?: Date | null;
}): Promise<boolean> {
const meili = getMeilisearchClient();
@@ -171,6 +176,8 @@ export async function syncSkillToMeilisearch(skill: {
securityStatus: skill.securityStatus || null,
isFeatured: skill.isFeatured || false,
isVerified: skill.isVerified || false,
reviewStatus: skill.reviewStatus || null,
aiScore: skill.latestAiScore || 0,
indexedAt: skill.indexedAt?.toISOString() || new Date().toISOString(),
};
@@ -254,6 +261,8 @@ export async function syncAllSkillsToMeilisearch(
securityStatus?: 'pass' | 'warning' | 'fail' | null;
isFeatured?: boolean | null;
isVerified?: boolean | null;
reviewStatus?: string | null;
latestAiScore?: number | null;
indexedAt?: Date | null;
}>
): Promise<{ success: number; failed: number }> {
@@ -284,6 +293,8 @@ export async function syncAllSkillsToMeilisearch(
securityStatus: skill.securityStatus || null,
isFeatured: skill.isFeatured || false,
isVerified: skill.isVerified || false,
reviewStatus: skill.reviewStatus || null,
aiScore: skill.latestAiScore || 0,
indexedAt: skill.indexedAt?.toISOString() || new Date().toISOString(),
}));