/** Weights applied to each component of the unified AI Readiness score. */ export const SCORE_WEIGHTS = { visibility: 0.45, catalog: 0.45, agent: 0.1, } as const; const GRADE_BANDS: Array<{ min: number; grade: string }> = [ { min: 80, grade: 'A' }, { min: 65, grade: 'B' }, { min: 50, grade: 'C' }, { min: 35, grade: 'D' }, { min: 0, grade: 'F' }, ]; /** * @param {number} score - Score in [0, 100]. * @return {string} Letter grade. */ export function gradeForScore(score: number): string { const clamped = Math.max(0, Math.min(100, Math.round(score))); for (const band of GRADE_BANDS) { if (clamped >= band.min) return band.grade; } return 'F'; } /** * @param {object} args * @param {number | undefined} args.totalConversations * @param {number | undefined} args.gapCount * @return {number} Agent quality in [0, 100]. */ export function computeAgentQuality(args: { totalConversations?: number; gapCount?: number; }): number { const total = args.totalConversations ?? 0; if (total <= 0) return 0; const gaps = Math.max(0, Math.min(total, args.gapCount ?? 0)); return Math.max(0, Math.min(100, Math.round((1 - gaps / total) * 100))); } /** * @param {object} args * @param {number} args.visibility * @param {number} args.catalog * @param {number} args.agent * @return {{ total: number; grade: string }} */ export function computeReadinessScore(args: { visibility: number; catalog: number; agent: number; }): { total: number; grade: string } { const total = Math.round( SCORE_WEIGHTS.visibility * args.visibility + SCORE_WEIGHTS.catalog * args.catalog + SCORE_WEIGHTS.agent * args.agent ); return { total, grade: gradeForScore(total) }; } /** * @param {Date} now * @return {"morning" | "afternoon" | "evening"} */ export function greetingBucket( now: Date = new Date() ): 'morning' | 'afternoon' | 'evening' { const hour = now.getHours(); if (hour < 12) return 'morning'; if (hour < 18) return 'afternoon'; return 'evening'; } /** * @param {Date} now * @param {string} name * @return {string} */ export function buildGreeting(now: Date, name: string): string { const word = `Good ${greetingBucket(now)}`; return name ? `${word}, ${name}` : word; } /** * @param {string | null | undefined} domain * @return {string} */ export function displayNameFromDomain( domain: string | null | undefined ): string { if (!domain) return ''; let trimmed = String(domain).trim().toLowerCase(); if (trimmed.startsWith('http://')) trimmed = trimmed.slice('http://'.length); if (trimmed.startsWith('https://')) trimmed = trimmed.slice('https://'.length); trimmed = trimmed.replace(/^www\./, '').split('/')[0] ?? ''; const firstLabel = trimmed.split('.')[0] ?? ''; if (!firstLabel) return ''; return firstLabel.charAt(0).toUpperCase() + firstLabel.slice(1); }