diff --git a/worker.js b/worker.js index ad3dfa2..ac3fc23 100644 --- a/worker.js +++ b/worker.js @@ -26,13 +26,14 @@ export default { return new Response('Updated'); } - const [revenuesRaw, metricsRaw] = await Promise.all([ + const competitors = defaultCompetitors(); + + const [revenuesRaw, metricsRaw, ...commitArrays] = await Promise.all([ env.MILLY_METRICS.get('revenues'), env.MILLY_METRICS.get('metrics'), + ...Object.values(competitors).map(c => fetchCommits(env, c.repo)), ]); - // Static config always comes from code — KV only stores revenue numbers - const competitors = defaultCompetitors(); const revenues = revenuesRaw ? JSON.parse(revenuesRaw) : {}; const metrics = metricsRaw ? JSON.parse(metricsRaw) : {}; @@ -42,6 +43,10 @@ export default { for (const id of ['rhys', 'pussy', 'patty']) { if (revenues[id] != null) competitors[id].revenue = revenues[id]; } + // Attach commits + Object.keys(competitors).forEach((id, i) => { + competitors[id].commits = commitArrays[i] || []; + }); return new Response(render(competitors), { headers: { 'Content-Type': 'text/html;charset=UTF-8', 'Cache-Control': 'no-store' } @@ -51,13 +56,34 @@ export default { function defaultCompetitors() { return { - omar: { name:'King Omar', ai:'Claude Pro', revenue:0, color:'#6366f1', emoji:'👑', github:'kingomarwashere' }, - rhys: { name:'Basic Rhys', ai:'Codex', revenue:0, color:'#f59e0b', emoji:'🤓', github:'rhy-collab' }, - pussy: { name:'Pussy', ai:'Hermes Plus Ching Chong',revenue:0, color:'#ec4899', emoji:'🐱', github:'QuixThe2nd' }, - patty: { name:'Patty', ai:'Copilot & Clawpilot', revenue:0, color:'#10b981', emoji:'🤠', github:null }, + omar: { name:'King Omar', ai:'Claude Pro', revenue:0, color:'#6366f1', emoji:'👑', github:'kingomarwashere', repo:'Bored-investments/chuckasickie' }, + rhys: { name:'Basic Rhys', ai:'Codex', revenue:0, color:'#f59e0b', emoji:'🤓', github:'rhy-collab', repo:'Bored-investments/milly-countdown' }, + pussy: { name:'Pussy', ai:'Hermes Plus Ching Chong',revenue:0, color:'#ec4899', emoji:'🐱', github:'QuixThe2nd', repo:null }, + patty: { name:'Patty', ai:'Copilot & Clawpilot', revenue:0, color:'#10b981', emoji:'🤠', github:null, repo:null }, }; } +async function fetchCommits(env, repo) { + if (!repo) return []; + const cacheKey = `commits:${repo}`; + const cached = await env.MILLY_METRICS.get(cacheKey); + if (cached) return JSON.parse(cached); + try { + const res = await fetch(`https://api.github.com/repos/${repo}/commits?per_page=3`, { + headers: { 'User-Agent': 'milly-countdown' } + }); + const data = await res.json(); + if (!Array.isArray(data)) return []; + const commits = data.map(c => ({ + sha: c.sha?.slice(0, 7), + message: c.commit?.message?.split('\n')[0]?.slice(0, 72), + date: c.commit?.author?.date, + })); + await env.MILLY_METRICS.put(cacheKey, JSON.stringify(commits), { expirationTtl: 300 }); + return commits; + } catch { return []; } +} + const fmt = n => n >= 1e6 ? `$${(n/1e6).toFixed(3)}M` : n >= 1000 ? `$${(n/1000).toFixed(1)}K` : `$${n.toFixed(0)}`; const pct = r => Math.min((r / GOAL) * 100, 100); @@ -223,6 +249,14 @@ html,body{min-height:100vh;background:#080401;color:#fff;font-family:'Inter',san .org-btn:hover{background:#1f1f1f;border-color:#6366f1;color:#fff} .org-btn svg{width:16px;height:16px;fill:currentColor} +/* === COMMITS === */ +.card-commits{margin-top:10px;border-top:1px solid rgba(255,255,255,0.05);padding-top:8px;display:flex;flex-direction:column;gap:4px} +.card-commit{display:flex;align-items:baseline;gap:6px;font-size:11px;line-height:1.4} +.commit-sha{font-family:'Courier New',monospace;color:#4b5563;text-decoration:none;flex-shrink:0; + transition:color 0.2s} +.commit-sha:hover{color:#9ca3af} +.commit-msg{color:#6b7280;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} + /* === FOOTER === */ footer{text-align:center;padding:24px 20px;border-top:1px solid #140900;color:#374151;font-size:12px} footer a{color:#4b5563;text-decoration:none} @@ -301,6 +335,12 @@ footer a:hover{color:#9ca3af} github.com/${c.github} ` : `no github connected`} + ${c.commits?.length ? `
+ ${c.commits.map(cm => `
+ ${cm.sha} + ${cm.message} +
`).join('')} +
` : ''} `).join('')}