← back to ajthal__noomi-bodi

Function bodies 299 total

All specs Real LLM only Function bodies
getFriendActivity function · typescript · L33-L75 (43 LOC)
src/services/activityFeed.ts
export async function getFriendActivity(limit = 50): Promise<ActivityFeedItem[]> {
  const userId = await getUserId();
  if (!userId) return [];

  try {
    // RLS handles privacy filtering. We select activities from friends + self.
    const { data: rows, error } = await supabase
      .from('activity_feed')
      .select('id, user_id, activity_type, activity_data, created_at')
      .order('created_at', { ascending: false })
      .limit(limit);

    if (error) throw error;
    if (!rows || rows.length === 0) return [];

    const userIds = [...new Set(rows.map(r => r.user_id))];
    const { data: profiles, error: profErr } = await supabase
      .from('public_profiles')
      .select('id, username, display_name, profile_picture_url')
      .in('id', userIds);

    if (profErr) throw profErr;

    const profileMap = new Map((profiles ?? []).map(p => [p.id, p]));

    return rows.map(row => {
      const p = profileMap.get(row.user_id);
      return {
        id: row.id,
        user
insertStreakMilestone function · typescript · L79-L90 (12 LOC)
src/services/activityFeed.ts
export async function insertStreakMilestone(streakDays: number): Promise<void> {
  const userId = await getUserId();
  if (!userId) return;

  const { error } = await supabase.from('activity_feed').insert({
    user_id: userId,
    activity_type: 'streak_milestone',
    activity_data: { streak_days: streakDays },
  });

  if (error) console.error('Error inserting streak milestone:', error);
}
checkAndRecordMilestone function · typescript · L92-L113 (22 LOC)
src/services/activityFeed.ts
export async function checkAndRecordMilestone(streakDays: number): Promise<void> {
  if (!isMilestone(streakDays)) return;

  const userId = await getUserId();
  if (!userId) return;

  const todayStart = new Date();
  todayStart.setHours(0, 0, 0, 0);

  // Avoid duplicate milestone for same day
  const { data: existing } = await supabase
    .from('activity_feed')
    .select('id')
    .eq('user_id', userId)
    .eq('activity_type', 'streak_milestone')
    .gte('created_at', todayStart.toISOString())
    .limit(1);

  if (existing && existing.length > 0) return;

  await insertStreakMilestone(streakDays);
}
getStreakEmoji function · typescript · L115-L121 (7 LOC)
src/services/activityFeed.ts
export function getStreakEmoji(days: number): string {
  if (days >= 60) return '\uD83D\uDCAA';
  if (days >= 30) return '\uD83D\uDE80';
  if (days >= 14) return '\uD83D\uDD25\uD83D\uDD25\uD83D\uDD25';
  if (days >= 7) return '\uD83D\uDD25\uD83D\uDD25';
  return '\uD83D\uDD25';
}
getStreakText function · typescript · L123-L126 (4 LOC)
src/services/activityFeed.ts
export function getStreakText(days: number): string {
  if (days >= 14 && days % 7 === 0) return `hit a ${Math.floor(days / 7)}-week streak!`;
  return `hit a ${days}-day streak!`;
}
daysAgoISO function · typescript · L87-L91 (5 LOC)
src/services/adminAnalytics.ts
function daysAgoISO(days: number): string {
  const d = new Date();
  d.setDate(d.getDate() - days);
  return d.toISOString();
}
todayStartISO function · typescript · L93-L97 (5 LOC)
src/services/adminAnalytics.ts
function todayStartISO(): string {
  const d = new Date();
  d.setHours(0, 0, 0, 0);
  return d.toISOString();
}
About: code-quality intelligence by Repobility · https://repobility.com
getUsageOverview function · typescript · L102-L156 (55 LOC)
src/services/adminAnalytics.ts
export async function getUsageOverview(): Promise<UsageOverview> {
  const { data: all, error } = await supabase
    .from('ai_usage_logs')
    .select('user_id, estimated_cost_usd, total_tokens, latency_ms, success, created_at');

  if (error) throw error;
  const rows = all ?? [];

  const now = new Date();
  const todayStart = todayStartISO();
  const weekStart = daysAgoISO(7);
  const monthStart = daysAgoISO(30);

  let totalCost = 0;
  let totalTokens = 0;
  let totalLatency = 0;
  let errorCount = 0;
  let todayCalls = 0;
  let weekCalls = 0;
  let monthCalls = 0;
  let todayCost = 0;
  let weekCost = 0;
  let monthCost = 0;
  const userIds = new Set<string>();

  for (const r of rows) {
    const cost = Number(r.estimated_cost_usd ?? 0);
    totalCost += cost;
    totalTokens += Number(r.total_tokens ?? 0);
    totalLatency += Number(r.latency_ms ?? 0);
    if (!r.success) errorCount++;
    if (r.created_at >= todayStart) { todayCalls++; todayCost += cost; }
    if (r.created_at
getUsageByDay function · typescript · L159-L183 (25 LOC)
src/services/adminAnalytics.ts
export async function getUsageByDay(days: number = 30): Promise<DailyUsage[]> {
  const since = daysAgoISO(days);

  const { data, error } = await supabase
    .from('ai_usage_logs')
    .select('created_at, total_tokens, estimated_cost_usd, success')
    .gte('created_at', since)
    .order('created_at', { ascending: true });

  if (error) throw error;

  const byDay = new Map<string, DailyUsage>();

  for (const r of data ?? []) {
    const date = r.created_at.slice(0, 10);
    const existing = byDay.get(date) ?? { date, calls: 0, tokens: 0, cost: 0, errors: 0 };
    existing.calls++;
    existing.tokens += Number(r.total_tokens ?? 0);
    existing.cost += Number(r.estimated_cost_usd ?? 0);
    if (!r.success) existing.errors++;
    byDay.set(date, existing);
  }

  return Array.from(byDay.values());
}
getUserUsageStats function · typescript · L186-L229 (44 LOC)
src/services/adminAnalytics.ts
export async function getUserUsageStats(): Promise<UserUsage[]> {
  const { data: logs, error: logsErr } = await supabase
    .from('ai_usage_logs')
    .select('user_id, total_tokens, estimated_cost_usd');

  if (logsErr) throw logsErr;

  const byUser = new Map<string, { calls: number; tokens: number; cost: number }>();
  for (const r of logs ?? []) {
    const uid = r.user_id;
    const existing = byUser.get(uid) ?? { calls: 0, tokens: 0, cost: 0 };
    existing.calls++;
    existing.tokens += Number(r.total_tokens ?? 0);
    existing.cost += Number(r.estimated_cost_usd ?? 0);
    byUser.set(uid, existing);
  }

  const { data: profiles, error: profErr } = await supabase
    .from('profiles')
    .select('id, email, role');

  if (profErr) throw profErr;

  const profileMap = new Map<string, { email: string; role: string }>();
  for (const p of profiles ?? []) {
    profileMap.set(p.id, { email: p.email ?? 'unknown', role: p.role ?? 'byok' });
  }

  const result: UserUsage[] = [];
getRecentActivity function · typescript · L232-L266 (35 LOC)
src/services/adminAnalytics.ts
export async function getRecentActivity(limit: number = 20): Promise<RecentLogEntry[]> {
  const { data, error } = await supabase
    .from('ai_usage_logs')
    .select('*')
    .order('created_at', { ascending: false })
    .limit(limit);

  if (error) throw error;

  const userIds = [...new Set((data ?? []).map(r => r.user_id))];
  const { data: profiles } = await supabase
    .from('profiles')
    .select('id, email')
    .in('id', userIds);

  const emailMap = new Map<string, string>();
  for (const p of profiles ?? []) {
    emailMap.set(p.id, p.email ?? 'unknown');
  }

  return (data ?? []).map(r => ({
    id: r.id,
    createdAt: r.created_at,
    userEmail: emailMap.get(r.user_id) ?? 'unknown',
    model: r.model,
    tokensInput: r.tokens_input,
    tokensOutput: r.tokens_output,
    totalTokens: r.total_tokens,
    estimatedCostUsd: Number(r.estimated_cost_usd ?? 0),
    latencyMs: r.latency_ms,
    success: r.success,
    errorMessage: r.error_message,
    toolsUsed: r.tool
getToolUsageStats function · typescript · L269-L288 (20 LOC)
src/services/adminAnalytics.ts
export async function getToolUsageStats(): Promise<ToolUsageStat[]> {
  const { data, error } = await supabase
    .from('ai_usage_logs')
    .select('tools_used')
    .not('tools_used', 'is', null);

  if (error) throw error;

  const counts = new Map<string, number>();
  for (const r of data ?? []) {
    const tools: string[] = Array.isArray(r.tools_used) ? r.tools_used : [];
    for (const t of tools) {
      counts.set(t, (counts.get(t) ?? 0) + 1);
    }
  }

  return Array.from(counts.entries())
    .map(([tool, count]) => ({ tool, count }))
    .sort((a, b) => b.count - a.count);
}
getRecentErrors function · typescript · L291-L326 (36 LOC)
src/services/adminAnalytics.ts
export async function getRecentErrors(limit: number = 20): Promise<RecentLogEntry[]> {
  const { data, error } = await supabase
    .from('ai_usage_logs')
    .select('*')
    .eq('success', false)
    .order('created_at', { ascending: false })
    .limit(limit);

  if (error) throw error;

  const userIds = [...new Set((data ?? []).map(r => r.user_id))];
  const { data: profiles } = await supabase
    .from('profiles')
    .select('id, email')
    .in('id', userIds);

  const emailMap = new Map<string, string>();
  for (const p of profiles ?? []) {
    emailMap.set(p.id, p.email ?? 'unknown');
  }

  return (data ?? []).map(r => ({
    id: r.id,
    createdAt: r.created_at,
    userEmail: emailMap.get(r.user_id) ?? 'unknown',
    model: r.model,
    tokensInput: r.tokens_input,
    tokensOutput: r.tokens_output,
    totalTokens: r.total_tokens,
    estimatedCostUsd: Number(r.estimated_cost_usd ?? 0),
    latencyMs: r.latency_ms,
    success: false,
    errorMessage: r.error_message,
 
getToolCostStats function · typescript · L329-L359 (31 LOC)
src/services/adminAnalytics.ts
export async function getToolCostStats(): Promise<ToolCostStat[]> {
  const { data, error } = await supabase
    .from('ai_usage_logs')
    .select('tools_used, estimated_cost_usd')
    .not('tools_used', 'is', null);

  if (error) throw error;

  const map = new Map<string, { totalCost: number; count: number }>();

  for (const r of data ?? []) {
    const tools: string[] = Array.isArray(r.tools_used) ? r.tools_used : [];
    if (tools.length === 0) continue;
    const costPerTool = Number(r.estimated_cost_usd ?? 0) / tools.length;
    for (const t of tools) {
      const existing = map.get(t) ?? { totalCost: 0, count: 0 };
      existing.totalCost += costPerTool;
      existing.count++;
      map.set(t, existing);
    }
  }

  return Array.from(map.entries())
    .map(([tool, { totalCost, count }]) => ({
      tool,
      totalCost,
      avgCost: count > 0 ? totalCost / count : 0,
      count,
    }))
    .sort((a, b) => b.avgCost - a.avgCost);
}
getMonthlyAvgPerUser function · typescript · L362-L394 (33 LOC)
src/services/adminAnalytics.ts
export async function getMonthlyAvgPerUser(): Promise<MonthlyUserCost[]> {
  const { data, error } = await supabase
    .from('ai_usage_logs')
    .select('user_id, estimated_cost_usd, created_at')
    .order('created_at', { ascending: true });

  if (error) throw error;

  const MONTH_LABELS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

  const byMonth = new Map<string, { cost: number; users: Set<string> }>();

  for (const r of data ?? []) {
    const d = new Date(r.created_at);
    const key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}`;
    const existing = byMonth.get(key) ?? { cost: 0, users: new Set<string>() };
    existing.cost += Number(r.estimated_cost_usd ?? 0);
    if (r.user_id) existing.users.add(r.user_id);
    byMonth.set(key, existing);
  }

  return Array.from(byMonth.entries()).map(([month, { cost, users }]) => {
    const [y, m] = month.split('-');
    const monthIdx = parseInt(m, 10) - 1;
    return 
Repobility · severity-and-effort ranking · https://repobility.com
getActiveUserCounts function · typescript · L397-L427 (31 LOC)
src/services/adminAnalytics.ts
export async function getActiveUserCounts(): Promise<ActiveUserCounts> {
  const { data, error } = await supabase
    .from('ai_usage_logs')
    .select('user_id, created_at');

  if (error) throw error;

  const todayStart = todayStartISO();
  const weekStart = daysAgoISO(7);
  const monthStart = daysAgoISO(30);

  const dailyUsers = new Set<string>();
  const weeklyUsers = new Set<string>();
  const monthlyUsers = new Set<string>();
  const allUsers = new Set<string>();

  for (const r of data ?? []) {
    if (!r.user_id) continue;
    allUsers.add(r.user_id);
    if (r.created_at >= todayStart) dailyUsers.add(r.user_id);
    if (r.created_at >= weekStart) weeklyUsers.add(r.user_id);
    if (r.created_at >= monthStart) monthlyUsers.add(r.user_id);
  }

  return {
    daily: dailyUsers.size,
    weekly: weeklyUsers.size,
    monthly: monthlyUsers.size,
    total: allUsers.size,
  };
}
getRoleDistribution function · typescript · L430-L446 (17 LOC)
src/services/adminAnalytics.ts
export async function getRoleDistribution(): Promise<RoleCount[]> {
  const { data, error } = await supabase
    .from('profiles')
    .select('role');

  if (error) throw error;

  const counts = new Map<string, number>();
  for (const r of data ?? []) {
    const role = r.role ?? 'byok';
    counts.set(role, (counts.get(role) ?? 0) + 1);
  }

  return Array.from(counts.entries())
    .map(([role, count]) => ({ role, count }))
    .sort((a, b) => b.count - a.count);
}
updateUserRole function · typescript · L449-L459 (11 LOC)
src/services/adminAnalytics.ts
export async function updateUserRole(
  userId: string,
  newRole: string,
): Promise<void> {
  const { error } = await supabase
    .from('profiles')
    .update({ role: newRole, updated_at: new Date().toISOString() })
    .eq('id', userId);

  if (error) throw error;
}
predictGoalDate function · typescript · L73-L173 (101 LOC)
src/services/analytics.ts
export async function predictGoalDate(): Promise<GoalProjection | null> {
  const [profile, weightLogs] = await Promise.all([
    loadUserProfile(),
    getWeightLogs(0),
  ]);

  if (!profile) return null;

  const targetKg = profile.targetWeightKg;
  const currentKg = profile.weightKg;
  const currentLbs = Math.round(kgToLbs(currentKg) * 10) / 10;
  const goalLbs = targetKg ? Math.round(kgToLbs(targetKg) * 10) / 10 : null;

  if (weightLogs.length < 5) {
    return {
      currentLbs,
      goalLbs: goalLbs ?? currentLbs,
      weeklyRateLbs: 0,
      estimatedDate: null,
      estimatedWeeks: null,
      status: 'insufficient_data',
      confidence: 'low',
    };
  }

  // Convert weight logs to (daysSinceFirst, lbs) for linear regression
  const firstTime = new Date(weightLogs[0].loggedAt).getTime();
  const xs = weightLogs.map(w => (new Date(w.loggedAt).getTime() - firstTime) / (1000 * 60 * 60 * 24));
  const ys = weightLogs.map(w => kgToLbs(w.weightKg));

  const { slope: dailyR
calculateAdherencePatterns function · typescript · L177-L242 (66 LOC)
src/services/analytics.ts
export async function calculateAdherencePatterns(): Promise<DayOfWeekPattern[]> {
  const [profile, summaries] = await Promise.all([
    loadUserProfile(),
    getDailySummaries(0),
  ]);

  if (summaries.length < 7) return [];

  const goals = profile ? estimateDailyGoals(profile) : null;

  // Group summaries by day of week
  const buckets: Map<number, DailySummary[]> = new Map();
  for (let i = 0; i < 7; i++) buckets.set(i, []);

  for (const s of summaries) {
    const dow = new Date(s.date + 'T12:00:00').getDay();
    buckets.get(dow)!.push(s);
  }

  return Array.from(buckets.entries()).map(([dow, days]) => {
    const n = days.length;
    if (n === 0) {
      return {
        day: DAY_NAMES[dow],
        dayIndex: dow,
        avgCalories: 0,
        avgProtein: 0,
        avgCarbs: 0,
        avgFat: 0,
        calorieAdherenceRate: 0,
        proteinAdherenceRate: 0,
        sampleSize: 0,
      };
    }

    const avgCal = days.reduce((a, d) => a + d.calories, 0) / n;
    con
findCorrelations function · typescript · L246-L372 (127 LOC)
src/services/analytics.ts
export async function findCorrelations(): Promise<Correlation[]> {
  const [profile, summaries] = await Promise.all([
    loadUserProfile(),
    getDailySummaries(0),
  ]);

  if (summaries.length < 7) return [];

  const goals = profile ? estimateDailyGoals(profile) : null;
  const correlations: Correlation[] = [];

  // --- Weekend vs Weekday adherence ---
  if (goals) {
    const calLo = goals.calories * 0.9;
    const calHi = goals.calories * 1.1;

    const weekdayDays: DailySummary[] = [];
    const weekendDays: DailySummary[] = [];

    for (const s of summaries) {
      const dow = new Date(s.date + 'T12:00:00').getDay();
      if (dow === 0 || dow === 6) weekendDays.push(s);
      else weekdayDays.push(s);
    }

    if (weekdayDays.length >= 3 && weekendDays.length >= 2) {
      const wdHit = weekdayDays.filter(d => d.calories >= calLo && d.calories <= calHi).length;
      const weHit = weekendDays.filter(d => d.calories >= calLo && d.calories <= calHi).length;
      const wd
getAnalytics function · typescript · L376-L384 (9 LOC)
src/services/analytics.ts
export async function getAnalytics(): Promise<AnalyticsResult> {
  const [goalProjection, dayOfWeekPatterns, correlations] = await Promise.all([
    predictGoalDate(),
    calculateAdherencePatterns(),
    findCorrelations(),
  ]);

  return { goalProjection, dayOfWeekPatterns, correlations };
}
getUserId function · typescript · L8-L11 (4 LOC)
src/services/claudeTools.ts
async function getUserId(): Promise<string | null> {
  const { data: { user } } = await supabase.auth.getUser();
  return user?.id ?? null;
}
Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
toLocalDateString function · typescript · L13-L18 (6 LOC)
src/services/claudeTools.ts
function toLocalDateString(date: Date): string {
  const y = date.getFullYear();
  const m = String(date.getMonth() + 1).padStart(2, '0');
  const d = String(date.getDate()).padStart(2, '0');
  return `${y}-${m}-${d}`;
}
todayStr function · typescript · L20-L22 (3 LOC)
src/services/claudeTools.ts
function todayStr(): string {
  return toLocalDateString(new Date());
}
localMidnightDaysAgo function · typescript · L25-L30 (6 LOC)
src/services/claudeTools.ts
function localMidnightDaysAgo(n: number): Date {
  const d = new Date();
  d.setHours(0, 0, 0, 0);
  d.setDate(d.getDate() - n);
  return d;
}
applyDateFilter function · typescript · L33-L43 (11 LOC)
src/services/claudeTools.ts
function applyDateFilter(
  query: any,
  column: string,
  days: number,
): any {
  if (days > 0) {
    const start = localMidnightDaysAgo(days - 1);
    return query.gte(column, start.toISOString());
  }
  return query; // 0 = all time, no filter
}
getToolsForIntent function · typescript · L286-L302 (17 LOC)
src/services/claudeTools.ts
export function getToolsForIntent(intent: ToolIntent): ToolDefinition[] {
  switch (intent) {
    case 'meal_log':
      // Claude already has daily context in the system prompt — no tools needed for meal logging
      return [];
    case 'data_query':
      // Full data toolset
      return TOOL_DEFINITIONS.filter(t => DATA_QUERY_TOOL_NAMES.has(t.name) || CORE_TOOL_NAMES.has(t.name));
    case 'meal_suggestion':
      // Suggestion-relevant tools
      return TOOL_DEFINITIONS.filter(t => SUGGESTION_TOOL_NAMES.has(t.name));
    case 'general':
    default:
      // Unknown intent — include everything
      return [...TOOL_DEFINITIONS];
  }
}
getDailyTotals function · typescript · L306-L355 (50 LOC)
src/services/claudeTools.ts
async function getDailyTotals(input: { date: string }): Promise<string> {
  const userId = await getUserId();
  if (!userId) return JSON.stringify({ error: 'Not authenticated' });

  const start = new Date(input.date + 'T00:00:00');
  const end = new Date(input.date + 'T23:59:59.999');

  const { data: rows, error } = await supabase
    .from('daily_logs')
    .select('calories, protein_g, carbs_g, fat_g')
    .eq('user_id', userId)
    .gte('logged_at', start.toISOString())
    .lte('logged_at', end.toISOString());

  if (error) return JSON.stringify({ error: error.message });

  const today = todayStr();

  if (!rows || rows.length === 0) {
    return JSON.stringify({
      today_is: today,
      queried_date: input.date,
      is_today: input.date === today,
      calories: 0,
      protein_g: 0,
      carbs_g: 0,
      fat_g: 0,
      meal_count: 0,
      note: 'No meals logged on this date.',
    });
  }

  const totals = rows.reduce(
    (acc, r) => ({
      calories: acc.calorie
getMealsByDateRange function · typescript · L357-L396 (40 LOC)
src/services/claudeTools.ts
async function getMealsByDateRange(input: { start_date: string; end_date: string }): Promise<string> {
  const userId = await getUserId();
  if (!userId) return JSON.stringify({ error: 'Not authenticated' });

  const start = new Date(input.start_date + 'T00:00:00');
  const end = new Date(input.end_date + 'T23:59:59.999');

  const { data: rows, error } = await supabase
    .from('daily_logs')
    .select('meal_name, calories, protein_g, carbs_g, fat_g, logged_at')
    .eq('user_id', userId)
    .gte('logged_at', start.toISOString())
    .lte('logged_at', end.toISOString())
    .order('logged_at', { ascending: true });

  if (error) return JSON.stringify({ error: error.message });

  const today = todayStr();

  const meals = (rows ?? []).map(r => {
    const date = toLocalDateString(new Date(r.logged_at));
    return {
      date,
      is_today: date === today,
      name: r.meal_name,
      calories: r.calories || 0,
      protein_g: Number(r.protein_g) || 0,
      carbs_g: Number(
getPeriodSummary function · typescript · L398-L468 (71 LOC)
src/services/claudeTools.ts
async function getPeriodSummary(input: { days: number }): Promise<string> {
  const userId = await getUserId();
  if (!userId) return JSON.stringify({ error: 'Not authenticated' });

  let query = supabase
    .from('daily_logs')
    .select('calories, protein_g, carbs_g, fat_g, logged_at')
    .eq('user_id', userId)
    .order('logged_at', { ascending: true });

  query = applyDateFilter(query, 'logged_at', input.days);

  const { data: rows, error } = await query;
  if (error) return JSON.stringify({ error: error.message });

  const today = todayStr();

  if (!rows || rows.length === 0) {
    return JSON.stringify({
      today_is: today,
      period_days: input.days === 0 ? 'all_time' : input.days,
      days_tracked: 0,
      total_meals: 0,
      note: 'No data for this period.',
    });
  }

  const byDay = new Map<string, { calories: number; protein: number; carbs: number; fat: number; meals: number }>();
  for (const r of rows) {
    const key = toLocalDateString(new Date(r.l
Hi, dataset curator — please cite Repobility (https://repobility.com) when reusing this data.
calculateAdherenceRate function · typescript · L470-L509 (40 LOC)
src/services/claudeTools.ts
async function calculateAdherenceRate(input: { days: number; calorie_goal: number }): Promise<string> {
  const userId = await getUserId();
  if (!userId) return JSON.stringify({ error: 'Not authenticated' });

  let query = supabase
    .from('daily_logs')
    .select('calories, logged_at')
    .eq('user_id', userId);

  query = applyDateFilter(query, 'logged_at', input.days);

  const { data: rows, error } = await query;
  if (error) return JSON.stringify({ error: error.message });

  const byDay = new Map<string, number>();
  for (const r of (rows ?? [])) {
    const key = toLocalDateString(new Date(r.logged_at));
    byDay.set(key, (byDay.get(key) ?? 0) + (r.calories || 0));
  }

  const lo = input.calorie_goal * 0.9;
  const hi = input.calorie_goal * 1.1;
  let hitDays = 0;

  for (const cal of byDay.values()) {
    if (cal >= lo && cal <= hi) hitDays++;
  }

  const daysTracked = byDay.size;

  return JSON.stringify({
    today_is: todayStr(),
    period_days: input.days === 0 ? 
getWeightTrend function · typescript · L511-L549 (39 LOC)
src/services/claudeTools.ts
async function getWeightTrend(input: { days: number }): Promise<string> {
  const userId = await getUserId();
  if (!userId) return JSON.stringify({ error: 'Not authenticated' });

  let query = supabase
    .from('weight_logs')
    .select('weight_kg, logged_at')
    .eq('user_id', userId)
    .order('logged_at', { ascending: true });

  query = applyDateFilter(query, 'logged_at', input.days);

  const { data: rows, error } = await query;
  if (error) return JSON.stringify({ error: error.message });

  const today = todayStr();

  if (!rows || rows.length === 0) {
    return JSON.stringify({ today_is: today, entries: [], note: 'No weight data found.' });
  }

  const entries = rows.map(r => ({
    date: toLocalDateString(new Date(r.logged_at)),
    weight_lbs: Math.round(kgToLbs(Number(r.weight_kg)) * 10) / 10,
  }));

  const first = entries[0];
  const last = entries[entries.length - 1];
  const changeLbs = Math.round((last.weight_lbs - first.weight_lbs) * 10) / 10;

  return JSON.s
searchSavedMeals function · typescript · L551-L578 (28 LOC)
src/services/claudeTools.ts
async function searchSavedMeals(input: { query: string }): Promise<string> {
  const userId = await getUserId();
  if (!userId) return JSON.stringify({ error: 'Not authenticated' });

  let query = supabase
    .from('saved_meals')
    .select('meal_name, calories, protein_g, carbs_g, fat_g, notes')
    .eq('user_id', userId)
    .order('created_at', { ascending: false });

  if (input.query.trim()) {
    query = query.ilike('meal_name', `%${input.query.trim()}%`);
  }

  const { data: rows, error } = await query;
  if (error) return JSON.stringify({ error: error.message });

  const meals = (rows ?? []).map(r => ({
    name: r.meal_name,
    calories: r.calories || 0,
    protein_g: Number(r.protein_g) || 0,
    carbs_g: Number(r.carbs_g) || 0,
    fat_g: Number(r.fat_g) || 0,
    notes: r.notes,
  }));

  return JSON.stringify({ query: input.query, result_count: meals.length, meals });
}
getAnalyticsTool function · typescript · L580-L583 (4 LOC)
src/services/claudeTools.ts
async function getAnalyticsTool(): Promise<string> {
  const result = await getAnalytics();
  return JSON.stringify({ today_is: todayStr(), ...result });
}
getFrequentMeals function · typescript · L585-L621 (37 LOC)
src/services/claudeTools.ts
async function getFrequentMeals(input: { limit?: number }): Promise<string> {
  const userId = await getUserId();
  if (!userId) return JSON.stringify({ error: 'Not authenticated' });

  const { data: rows, error } = await supabase
    .from('daily_logs')
    .select('meal_name, calories, protein_g, carbs_g, fat_g')
    .eq('user_id', userId);

  if (error) return JSON.stringify({ error: error.message });

  const freq = new Map<string, { count: number; calories: number; protein: number; carbs: number; fat: number }>();
  for (const r of (rows ?? [])) {
    const key = (r.meal_name ?? '').toLowerCase().trim();
    const existing = freq.get(key) ?? { count: 0, calories: 0, protein: 0, carbs: 0, fat: 0 };
    existing.count += 1;
    existing.calories += r.calories || 0;
    existing.protein += Number(r.protein_g) || 0;
    existing.carbs += Number(r.carbs_g) || 0;
    existing.fat += Number(r.fat_g) || 0;
    freq.set(key, existing);
  }

  const sorted = Array.from(freq.entries())
    
searchMealsByMacro function · typescript · L623-L658 (36 LOC)
src/services/claudeTools.ts
async function searchMealsByMacro(input: { macro: string; min_amount?: number; max_amount?: number; limit?: number }): Promise<string> {
  const userId = await getUserId();
  if (!userId) return JSON.stringify({ error: 'Not authenticated' });

  const colMap: Record<string, string> = { calories: 'calories', protein: 'protein_g', carbs: 'carbs_g', fat: 'fat_g' };
  const col = colMap[input.macro];
  if (!col) return JSON.stringify({ error: `Unknown macro: ${input.macro}` });

  let query = supabase
    .from('daily_logs')
    .select('meal_name, calories, protein_g, carbs_g, fat_g, logged_at')
    .eq('user_id', userId)
    .order(col, { ascending: false });

  if (input.min_amount != null && input.min_amount > 0) {
    query = query.gte(col, input.min_amount);
  }
  if (input.max_amount != null) {
    query = query.lte(col, input.max_amount);
  }

  const { data: rows, error } = await query.limit(input.limit ?? 10);
  if (error) return JSON.stringify({ error: error.message });

  const
getBestAdherenceDays function · typescript · L660-L702 (43 LOC)
src/services/claudeTools.ts
async function getBestAdherenceDays(input: { calorie_goal: number; limit?: number }): Promise<string> {
  const userId = await getUserId();
  if (!userId) return JSON.stringify({ error: 'Not authenticated' });

  const { data: rows, error } = await supabase
    .from('daily_logs')
    .select('meal_name, calories, protein_g, carbs_g, fat_g, logged_at')
    .eq('user_id', userId)
    .order('logged_at', { ascending: true });

  if (error) return JSON.stringify({ error: error.message });

  const byDay = new Map<string, { calories: number; protein: number; carbs: number; fat: number; meals: string[] }>();
  for (const r of (rows ?? [])) {
    const key = toLocalDateString(new Date(r.logged_at));
    const existing = byDay.get(key) ?? { calories: 0, protein: 0, carbs: 0, fat: 0, meals: [] };
    existing.calories += r.calories || 0;
    existing.protein += Number(r.protein_g) || 0;
    existing.carbs += Number(r.carbs_g) || 0;
    existing.fat += Number(r.fat_g) || 0;
    existing.meals.p
getMealHistory function · typescript · L704-L733 (30 LOC)
src/services/claudeTools.ts
async function getMealHistory(input: { meal_name: string }): Promise<string> {
  const userId = await getUserId();
  if (!userId) return JSON.stringify({ error: 'Not authenticated' });

  const { data: rows, error } = await supabase
    .from('daily_logs')
    .select('meal_name, calories, protein_g, carbs_g, fat_g, logged_at')
    .eq('user_id', userId)
    .ilike('meal_name', `%${input.meal_name.trim()}%`)
    .order('logged_at', { ascending: false });

  if (error) return JSON.stringify({ error: error.message });

  const today = todayStr();
  const entries = (rows ?? []).map(r => ({
    name: r.meal_name,
    calories: r.calories || 0,
    protein_g: Number(r.protein_g) || 0,
    carbs_g: Number(r.carbs_g) || 0,
    fat_g: Number(r.fat_g) || 0,
    date: toLocalDateString(new Date(r.logged_at)),
  }));

  return JSON.stringify({
    today_is: today,
    search_term: input.meal_name,
    times_found: entries.length,
    entries,
  });
}
About: code-quality intelligence by Repobility · https://repobility.com
getRemainingMacros function · typescript · L735-L777 (43 LOC)
src/services/claudeTools.ts
async function getRemainingMacros(): Promise<string> {
  const userId = await getUserId();
  if (!userId) return JSON.stringify({ error: 'Not authenticated' });

  const profile = await loadUserProfile();
  if (!profile) return JSON.stringify({ error: 'No profile found' });

  const goals = estimateDailyGoals(profile);
  const today = todayStr();
  const startOfDay = new Date();
  startOfDay.setHours(0, 0, 0, 0);

  const { data: rows, error } = await supabase
    .from('daily_logs')
    .select('calories, protein_g, carbs_g, fat_g')
    .eq('user_id', userId)
    .gte('logged_at', startOfDay.toISOString());

  if (error) return JSON.stringify({ error: error.message });

  const consumed = (rows ?? []).reduce(
    (acc, r) => ({
      calories: acc.calories + (r.calories || 0),
      protein_g: acc.protein_g + (Number(r.protein_g) || 0),
      carbs_g: acc.carbs_g + (Number(r.carbs_g) || 0),
      fat_g: acc.fat_g + (Number(r.fat_g) || 0),
    }),
    { calories: 0, protein_g: 0, carbs
executeTool function · typescript · L781-L810 (30 LOC)
src/services/claudeTools.ts
export async function executeTool(name: string, input: Record<string, unknown>): Promise<string> {
  switch (name) {
    case 'get_daily_totals':
      return getDailyTotals(input as { date: string });
    case 'get_meals_by_date_range':
      return getMealsByDateRange(input as { start_date: string; end_date: string });
    case 'get_period_summary':
      return getPeriodSummary(input as { days: number });
    case 'calculate_adherence_rate':
      return calculateAdherenceRate(input as { days: number; calorie_goal: number });
    case 'get_weight_trend':
      return getWeightTrend(input as { days: number });
    case 'search_saved_meals':
      return searchSavedMeals(input as { query: string });
    case 'get_analytics':
      return getAnalyticsTool();
    case 'get_frequent_meals':
      return getFrequentMeals(input as { limit?: number });
    case 'search_meals_by_macro':
      return searchMealsByMacro(input as { macro: string; min_amount?: number; max_amount?: number; limit?
toLocalDateString function · typescript · L35-L40 (6 LOC)
src/services/claude.ts
function toLocalDateString(date: Date): string {
  const y = date.getFullYear();
  const m = String(date.getMonth() + 1).padStart(2, '0');
  const d = String(date.getDate()).padStart(2, '0');
  return `${y}-${m}-${d}`;
}
normalizeMediaType function · typescript · L52-L57 (6 LOC)
src/services/claude.ts
function normalizeMediaType(raw: string): string {
  const lower = raw.toLowerCase().trim();
  if (VALID_MEDIA_TYPES.has(lower)) return lower;
  if (lower === 'image/jpg') return 'image/jpeg';
  return 'image/jpeg';
}
stripDataUriPrefix function · typescript · L60-L63 (4 LOC)
src/services/claude.ts
function stripDataUriPrefix(data: string): string {
  const commaIdx = data.indexOf(',');
  return commaIdx !== -1 ? data.slice(commaIdx + 1) : data;
}
estimateCost function · typescript · L81-L95 (15 LOC)
src/services/claude.ts
function estimateCost(
  inputTokens: number,
  outputTokens: number,
  cacheReadTokens: number = 0,
  cacheCreationTokens: number = 0,
): number {
  // Cache-read tokens are NOT counted in input_tokens by the API,
  // so we cost them separately at the discounted rate.
  return (
    (inputTokens / 1_000_000) * INPUT_COST_PER_MILLION +
    (outputTokens / 1_000_000) * OUTPUT_COST_PER_MILLION +
    (cacheReadTokens / 1_000_000) * CACHE_READ_COST_PER_MILLION +
    (cacheCreationTokens / 1_000_000) * CACHE_WRITE_COST_PER_MILLION
  );
}
logAiUsage function · typescript · L97-L136 (40 LOC)
src/services/claude.ts
async function logAiUsage(params: {
  model: string;
  tokensInput: number;
  tokensOutput: number;
  cacheReadTokens?: number;
  cacheCreationTokens?: number;
  latencyMs: number;
  success: boolean;
  errorMessage?: string | null;
  toolsUsed?: string[];
}): Promise<void> {
  try {
    const { data: { user } } = await supabase.auth.getUser();
    if (!user) return;

    const cacheRead = params.cacheReadTokens ?? 0;
    const cacheCreation = params.cacheCreationTokens ?? 0;
    const totalTokens = params.tokensInput + params.tokensOutput + cacheRead;
    const cost = estimateCost(params.tokensInput, params.tokensOutput, cacheRead, cacheCreation);

    if (cacheRead > 0 || cacheCreation > 0) {
      console.log(`[AI Cache] read=${cacheRead} creation=${cacheCreation} input=${params.tokensInput} output=${params.tokensOutput}`);
    }

    await supabase.from('ai_usage_logs').insert({
      user_id: user.id,
      model: params.model,
      tokens_input: params.tokensInput,
      tokens_
estimateTokens function · typescript · L141-L143 (3 LOC)
src/services/claude.ts
function estimateTokens(text: string): number {
  return Math.ceil(text.length / 4);
}
Repobility · severity-and-effort ranking · https://repobility.com
estimateMessageTokens function · typescript · L145-L151 (7 LOC)
src/services/claude.ts
function estimateMessageTokens(messages: ChatMessage[]): number {
  return messages.reduce((sum, m) => {
    let tokens = estimateTokens(m.content);
    if (m.imageBase64) tokens += 1600; // ~1600 tokens for a typical image
    return sum + tokens;
  }, 0);
}
windowMessages function · typescript · L159-L162 (4 LOC)
src/services/claude.ts
export function windowMessages(
  messages: ChatMessage[],
  systemPromptTokens: number,
): { kept: ChatMessage[]; dropped: ChatMessage[] } {
summarizeDroppedMessages function · typescript · L187-L222 (36 LOC)
src/services/claude.ts
export async function summarizeDroppedMessages(
  droppedMessages: ChatMessage[],
  existingSummary: string | null,
  apiKey: string,
): Promise<string> {
  const transcript = droppedMessages
    .map(m => `${m.role === 'user' ? 'User' : 'Assistant'}: ${m.content.slice(0, 500)}`)
    .join('\n');

  const prompt = existingSummary
    ? `Here is an existing summary of an earlier part of the conversation:\n\n${existingSummary}\n\nHere are additional messages that need to be incorporated into the summary:\n\n${transcript}\n\nProduce an updated, concise summary (max 300 words) that captures all key facts, preferences, decisions, and meal/nutrition details mentioned. Focus on information the user would expect you to remember.`
    : `Here is the beginning of a conversation between a user and their AI nutrition coach:\n\n${transcript}\n\nProduce a concise summary (max 300 words) that captures all key facts, preferences, decisions, and meal/nutrition details mentioned. Focus on information th
‹ prevpage 3 / 6next ›