Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 3 additions & 15 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
GOOGLE_CLIENT_ID=
# Required whenever HOST binds beyond loopback (e.g. 0.0.0.0 for phone/LAN).
ALLOWED_EMAILS=
# Required for phone/LAN (raw IP) access. Google GIS cannot use raw IP origins.
DASHBOARD_PIN=
# Google-compatible public UI origin (Vercel static host). Default below.
PUBLIC_ORIGIN=https://agent-dashboard-ctt.vercel.app
# Optional: override auto-generated secret for cookie + Bearer token signing
# (~/.config/agent-deck/session-secret)
SESSION_SECRET=
# Optional LAN bind for phone access (LaunchAgent / serve:lan also set this)
# HOST=0.0.0.0
# Optional overrides (all have defaults).
# PORT=3847
# UI → Mac API base for a Vercel (or other) static build. Use an HTTPS tunnel URL
# when the UI is on HTTPS; leave empty for same-origin Mac serve.
# VITE_API_BASE=https://your-mac-api.example
# CACHE_TTL_MS=10000
# USAGE_RESETS_TTL_MS=180000
135 changes: 26 additions & 109 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@

Local macOS dashboard for AI agent usage (Cursor, Claude Code, Codex), Mac resource meters, and your GitHub contribution calendar.

Runs entirely on your machine. Usage-reset lookups send your local Cursor, Codex, and Claude auth tokens from this Mac only to those vendors' usage APIs (api2.cursor.sh, auth.openai.com / chatgpt.com, api.anthropic.com) - not to Agent Deck or any other service.
Runs entirely on your machine at **http://127.0.0.1:3847**. No cloud host and no sign-in - open the URL and the dashboard loads.

Usage-reset lookups send your local Cursor, Codex, and Claude auth tokens from this Mac only to those vendors' usage APIs (api2.cursor.sh, auth.openai.com / chatgpt.com, api.anthropic.com) - not to Agent Deck or any other service.

![Agent Deck](https://img.shields.io/badge/platform-macOS-black) ![Node](https://img.shields.io/badge/node-%3E%3D22-brightgreen) ![License](https://img.shields.io/badge/license-MIT-blue)

## Why the Mac still runs the API
## Why localhost

Your machine is the source of truth:

Expand All @@ -17,116 +19,47 @@ Your machine is the source of truth:
- **CPU / GPU / Memory** only exist on this Mac
- **GitHub** calendar is fetched with your local `gh` auth

Collectors must stay on this Mac. You can host a **static UI** on Vercel (see below) that talks to the Mac API over a tunnel or LAN URL - do not deploy the collectors to a public cloud.

## Recommended setup (auto-start + dual auth)

You do **not** need `npm run dev` day to day. That is only for developers hacking on the UI.
Collectors must stay on this Mac. This app is **localhost-only**.

1. Install once:
## Recommended setup

```bash
git clone https://github.com/ctt062/agent-dashboard.git
cd agent-dashboard
npm install
cp .env.example .env
```

2. Configure `.env`:

```bash
GOOGLE_CLIENT_ID=your-id.apps.googleusercontent.com
ALLOWED_EMAILS=you@gmail.com
DASHBOARD_PIN=your-phone-pin
PUBLIC_ORIGIN=https://agent-dashboard-ctt.vercel.app
```

Authorized JavaScript origins (Google Cloud Console) - Google GIS does **not** accept raw LAN IPs:

- `http://127.0.0.1:3847` and `http://localhost:3847` (production serve)
- `http://127.0.0.1:5174` and `http://localhost:5174` (`npm run dev`)
- `https://agent-dashboard-ctt.vercel.app` (or your `PUBLIC_ORIGIN`)

3. Build + install login auto-start:

```bash
npm run setup
```

`npm run setup` defaults to LAN bind (`HOST=0.0.0.0`) and refuses to install unless `GOOGLE_CLIENT_ID`, `ALLOWED_EMAILS`, and `DASHBOARD_PIN` are set.

After that, Agent Deck starts when you log into your Mac:

- Desktop / localhost and the Vercel UI origin use **Google** sign-in (verified email + allowlist).
- Phone on a raw LAN IP uses **PIN** sign-in (`DASHBOARD_PIN`).
That builds the UI, installs a macOS LaunchAgent so Agent Deck starts at login, and opens **http://127.0.0.1:3847**.

`npm run dev` is optional (hot reload for coding). Prefer `npm run setup` for normal use.

## Optional: static UI on Vercel

Public UI: [https://agent-dashboard-ctt.vercel.app/](https://agent-dashboard-ctt.vercel.app/)

1. Deploy the Vite `dist/` (SPA rewrite is in `vercel.json`).
2. Point the UI at your Mac API with either:
- build-time `VITE_API_BASE=https://your-mac-tunnel.example`, or
- runtime `public/runtime-config.js` → `window.__AGENT_DECK_API_BASE__`
3. Prefer an **HTTPS tunnel** to the Mac when the UI is on HTTPS (browsers block mixed content to bare `http://192.168.x.x`).
4. On the Mac, keep `PUBLIC_ORIGIN=https://agent-dashboard-ctt.vercel.app` so CORS allows that origin + localhost only (no wildcard, no raw LAN origins).
5. Sign-in returns a **Bearer token** stored in the browser (`sessionStorage`) and sent as `Authorization: Bearer …`. Do not rely on third-party cookies for Vercel → Mac.

Collectors and `/api/*` still run on the Mac.
`npm run dev` is optional (hot reload for coding).

## Download

Day-to-day install is [Recommended setup](#recommended-setup-auto-start--dual-auth) (`.env` auth + `npm run setup`). Auth is required for dashboard data.

### ZIP (no Git)

1. Open https://github.com/ctt062/agent-dashboard
2. Click **Code → Download ZIP**
3. Unzip, then continue from `cp .env.example .env` in Recommended setup.
3. Unzip, then `npm install` and `npm run setup`.

### One-command production serve

After `.env` is configured (see Recommended setup), build and serve API + static UI on one port:

```bash
npm run serve
```

Open **http://127.0.0.1:3847** (Google sign-in).

`npm start` alone also works after `npm run build` (serves `dist/` when present). Hot-reload coding: `npm run dev` → **http://127.0.0.1:5174**.

## View on your phone (same Wi-Fi)

Agent Deck is a local web app. Your Mac still runs the API; your phone opens it in Safari/Chrome and signs in with the **PIN** (Google cannot authorize raw IP origins).

```bash
npm run serve:lan
```

The terminal prints a LAN URL like `http://192.168.x.x:3847`. Open that on your phone (same Wi-Fi) and enter `DASHBOARD_PIN`. On iOS you can use **Share → Add to Home Screen** for an app-like icon.

Dev equivalent:

```bash
npm run dev:lan
```

Then open the printed Vite URL (port `5174`) on your phone.
Open **http://127.0.0.1:3847**.

Only do this on a trusted network - LAN mode exposes local agent + Mac metrics to devices on that Wi-Fi.
`npm start` alone also works after `npm run build`. Hot-reload coding: `npm run dev` → **http://127.0.0.1:5174**.

## Start at login (macOS)

Use `npm run setup` from [Recommended setup](#recommended-setup-auto-start--dual-auth) (requires `.env` auth when LAN-bound). LaunchAgent only:

```bash
npm run launchagent:install
npm run setup
```

Remove with `npm run launchagent:uninstall`.
LaunchAgent only: `npm run launchagent:install`
Remove: `npm run launchagent:uninstall`

## Requirements

Expand All @@ -142,18 +75,17 @@ Missing collectors degrade gracefully - each panel shows a short hint instead of

## Features

- **Date range**: Today / 7 days / 30 days / This month for agent share and charts
- **Usage resets**: Per-provider token/limit reset times (Cursor billing cycle via local dashboard API, Codex ChatGPT wham/usage windows, Claude rolling 5h/weekly with `/usage` guidance when exact times are unavailable)
- **Billing cycle view**: Plan usage % / limits plus relative agent activity for each provider’s current billing window
- **Usage resets**: Per-provider token/limit reset times
- **Detailed agent stats**: period total, avg/day, active days, peak day, acceptance rate (Cursor), input/output tokens
- **Dual-series charts** plus a cross-agent comparison chart
- **Dual auth**: Google on localhost / `PUBLIC_ORIGIN`; PIN on LAN IPs; Bearer token for Vercel → Mac API; `GOOGLE_CLIENT_ID` + `ALLOWED_EMAILS` + `DASHBOARD_PIN` required for LAN bind
- **Local web app**: `npm run setup` auto-starts at login; `serve:lan` / LaunchAgent for phone on the same Wi-Fi
- **Cached collectors** (~10s TTL) with parallel collection; usage-reset lookups cache separately (~3 min). Refresh bypasses both caches
- **Auto-start** at login via `npm run setup`
- **Cached collectors** (~10s TTL) with parallel collection; usage-reset lookups cache separately (~3 min)

## Stack

- Vite + React + TypeScript UI
- Express API on port `3847` (Local Mac; also serves `dist/` after build)
- Express API on port `3847` (also serves `dist/` after build)
- Collectors read local files / `top` / `ioreg` / `gh api`

## What the percentages mean
Expand All @@ -162,40 +94,25 @@ Agent % is **relative share** of a local activity score across Cursor, Claude Co

| Agent | Primary signal |
|-------|----------------|
| Cursor | Accepted AI lines (`aiCodeTracking.dailyStats`) |
| Cursor | Accepted AI lines when present; otherwise Agent transcript / ACP session volume |
| Claude Code | Tokens from `~/.claude/projects/**/*.jsonl`, else message volume |
| Codex | Tokens from `~/.codex/sessions/**/*.jsonl`, else event volume |

## API

Default bind is `127.0.0.1`. Use `HOST=0.0.0.0` (or `npm run serve:lan`) for LAN/phone access.

`/api/dashboard` and `/api/system` require auth (session cookie and/or `Authorization: Bearer …`). `/api/health` and `/api/auth/*` are reachable without a prior session (sign-in routes issue the token).
Bind is `127.0.0.1` only. Non-loopback `HOST` values are rejected.

| Endpoint | Description |
|----------|-------------|
| `GET /api/dashboard?range=1d\|7d\|30d\|month` | Full payload (agents + system + GitHub). Add `refresh=1` to bypass cache. Auth required. |
| `GET /api/system` | Mac snapshot only. Auth required. |
| `GET /api/health` | Liveness check (no auth) |
| `GET /api/auth/config` | Auth mode for this Host/Origin (`google` or `pin`) |

Override host/port if needed:

```bash
HOST=0.0.0.0 PORT=4000 npm start
```
| `GET /api/dashboard` | Full payload for this billing cycle (agents + system + GitHub). Add `refresh=1` to bypass cache. |
| `GET /api/system` | Mac snapshot only. |
| `GET /api/health` | Liveness check. |

## Privacy

- Dashboard stats come from files and tools already on your Mac
- Google sign-in uses Google Identity Services on localhost and `PUBLIC_ORIGIN`; LAN IPs use PIN instead
- Cross-origin Vercel UI uses Bearer tokens (not third-party cookies); Mac same-origin UI may still use session cookies
- When LAN bind is enabled, `GOOGLE_CLIENT_ID`, `ALLOWED_EMAILS`, and `DASHBOARD_PIN` are required
- Failed PIN attempts are rate-limited in memory per client IP
- Usage-reset times use local Cursor / Codex / Claude credentials on this machine only to call those vendors' usage APIs; tokens are not sent to Agent Deck or any other service
- Default LaunchAgent bind is LAN-capable (`HOST=0.0.0.0`) - use only on trusted Wi-Fi
- CORS allowlists localhost + `PUBLIC_ORIGIN` only (no wildcard)
- Static UI may live on Vercel; collectors and the API stay on your Mac
- Bound to localhost only - not exposed on your LAN or the public internet
- Usage-reset times use local Cursor / Codex / Claude credentials on this machine only to call those vendors' usage APIs

## License

Expand Down
1 change: 0 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
</head>
<body>
<div id="root"></div>
<script src="/runtime-config.js"></script>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading
Loading