Nicholai bb90d15209 feat: unified feed bots for discord
combines reddit digest, github trending, new ai repos,
and claude code release tracking into one CLI tool.

usage: bun run feed <reddit|trending|new-repos|claude-releases|all>
2026-01-24 01:39:42 -07:00

71 lines
1.8 KiB
TypeScript

export function daysAgo(n: number): string {
const d = new Date();
d.setDate(d.getDate() - n);
return d.toISOString().split('T')[0];
}
export function log(...args: unknown[]) {
console.error(...args);
}
export function sleep(ms: number): Promise<void> {
return new Promise((r) => setTimeout(r, ms));
}
export async function ghSearch(query: string): Promise<GHRepo[]> {
const url =
`https://api.github.com/search/repositories` +
`?q=${encodeURIComponent(query)}&sort=stars&order=desc&per_page=30`;
log(` fetching: ${query}`);
const res = await fetch(url, {
headers: { Accept: 'application/vnd.github.v3+json' },
});
if (!res.ok) {
log(` ⚠ GitHub API ${res.status}: ${await res.text()}`);
return [];
}
const data = (await res.json()) as { items: GHRepo[] };
return data.items ?? [];
}
export interface GHRepo {
full_name: string;
description: string | null;
stargazers_count: number;
language: string | null;
html_url: string;
created_at: string;
pushed_at: string;
topics?: string[];
}
export function formatRepos(repos: GHRepo[], title: string): string {
if (!repos.length) return `## ${title}\n\n_No results found._\n`;
const lines = [`## ${title}\n`];
for (const r of repos) {
const desc = r.description
? r.description.slice(0, 120)
: '_No description_';
const lang = r.language ?? '?';
lines.push(
`**[${r.full_name}](${r.html_url})** ` +
`${r.stargazers_count.toLocaleString()} | \`${lang}\``
);
lines.push(`> ${desc}\n`);
}
return lines.join('\n');
}
export function dedupeRepos(repos: GHRepo[]): GHRepo[] {
const seen = new Set<string>();
return repos.filter((r) => {
if (seen.has(r.full_name)) return false;
seen.add(r.full_name);
return true;
});
}