repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
The Living OS cockpit
stars
latest
clone command
git clone gitlawb://did:key:z6Mku78K...XywC/living-os-cockp...git clone gitlawb://did:key:z6Mku78K.../living-os-cockp...59751530feat: surface worker supervisor health in live work5h ago| #1 | 'use client'; |
| #2 | |
| #3 | import useSWR from 'swr'; |
| #4 | import { swrFetcher } from '@/lib/client-api'; |
| #5 | |
| #6 | const fetcher = swrFetcher; |
| #7 | |
| #8 | function formatCost(usd: number): string { |
| #9 | if (usd === 0) return '$0.00'; |
| #10 | if (usd < 0.01) return `$${usd.toFixed(4)}`; |
| #11 | if (usd < 1) return `$${usd.toFixed(3)}`; |
| #12 | return `$${usd.toFixed(2)}`; |
| #13 | } |
| #14 | |
| #15 | function formatUsdc(value?: number | null): string { |
| #16 | if (typeof value !== 'number' || !Number.isFinite(value)) return '-'; |
| #17 | if (value === 0) return '0.00'; |
| #18 | if (value < 1) return value.toFixed(4); |
| #19 | return value.toFixed(2); |
| #20 | } |
| #21 | |
| #22 | export default function DiemPanel() { |
| #23 | const { data } = useSWR('/api/spend', fetcher, { refreshInterval: 10000 }); |
| #24 | const { data: antseed } = useSWR('/api/antseed', fetcher, { refreshInterval: 30000 }); |
| #25 | |
| #26 | if (!data) return <div className="text-zinc-500 text-sm">Loading spend data...</div>; |
| #27 | |
| #28 | const burnColor = data.todayBurnPercent < 50 |
| #29 | ? 'bg-green-500' |
| #30 | : data.todayBurnPercent < 80 |
| #31 | ? 'bg-amber-500' |
| #32 | : 'bg-red-500'; |
| #33 | const balance = antseed?.buyerBalance; |
| #34 | |
| #35 | return ( |
| #36 | <div className="space-y-3 text-sm"> |
| #37 | <div> |
| #38 | <div className="flex justify-between mb-1"> |
| #39 | <span className="text-zinc-400">Today's spend</span> |
| #40 | <span className="font-mono">{formatCost(data.today.usd)} / ${data.dailyCapacityUsd.toFixed(2)}</span> |
| #41 | </div> |
| #42 | <div className="w-full bg-zinc-800 rounded h-2"> |
| #43 | <div |
| #44 | className={`h-2 rounded transition-all ${burnColor}`} |
| #45 | style={{ width: `${Math.min(100, data.todayBurnPercent)}%` }} |
| #46 | /> |
| #47 | </div> |
| #48 | <div className="text-xs text-zinc-500 mt-1"> |
| #49 | {data.today.messages} messages - {data.todayBurnPercent.toFixed(1)}% of DIEM daily capacity |
| #50 | </div> |
| #51 | </div> |
| #52 | |
| #53 | {Object.keys(data.today.byModel || {}).length > 0 && ( |
| #54 | <div> |
| #55 | <div className="text-zinc-400 text-xs mb-1">By model today:</div> |
| #56 | <div className="space-y-0.5"> |
| #57 | {Object.entries(data.today.byModel) |
| #58 | .sort(([, a]: any, [, b]: any) => b.usd - a.usd) |
| #59 | .map(([model, stats]: [string, any]) => ( |
| #60 | <div key={model} className="flex justify-between text-xs"> |
| #61 | <span className="text-zinc-300 truncate pr-2">{model}</span> |
| #62 | <span className="font-mono text-zinc-400"> |
| #63 | {stats.count}x - {formatCost(stats.usd)} |
| #64 | </span> |
| #65 | </div> |
| #66 | ))} |
| #67 | </div> |
| #68 | </div> |
| #69 | )} |
| #70 | |
| #71 | <div> |
| #72 | <div className="text-zinc-400 text-xs mb-1">Last 7 days:</div> |
| #73 | <div className="flex items-end gap-1 h-12"> |
| #74 | {Object.entries(data.last7Days).map(([date, usd]: [string, any]) => { |
| #75 | const max = Math.max(...Object.values(data.last7Days as Record<string, number>), 0.01); |
| #76 | const h = Math.max(2, (usd / max) * 100); |
| #77 | return ( |
| #78 | <div key={date} className="flex-1 flex flex-col items-center gap-0.5"> |
| #79 | <div |
| #80 | className="w-full bg-amber-700/60 rounded-sm" |
| #81 | style={{ height: `${h}%` }} |
| #82 | title={`${date}: ${formatCost(usd)}`} |
| #83 | /> |
| #84 | <div className="text-[9px] text-zinc-600">{date.slice(5)}</div> |
| #85 | </div> |
| #86 | ); |
| #87 | })} |
| #88 | </div> |
| #89 | </div> |
| #90 | |
| #91 | <div className="pt-2 border-t border-zinc-800 space-y-1 text-xs"> |
| #92 | <div className="flex justify-between"><span className="text-zinc-400">DIEM staked</span><span>{data.diemStaked}</span></div> |
| #93 | <div className="flex justify-between"><span className="text-zinc-400">AntSeed wallet</span><span>{formatUsdc(balance?.walletUsdc)} USDC</span></div> |
| #94 | <div className="flex justify-between"><span className="text-zinc-400">AntSeed deposit</span><span>{formatUsdc(balance?.depositsAvailable)} USDC</span></div> |
| #95 | </div> |
| #96 | </div> |
| #97 | ); |
| #98 | } |
| #99 |