ai-wrapped 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/.0spec/config.toml +50 -0
  2. package/.0spec/flows/ai-stats-build.toml +291 -0
  3. package/.0spec/flows/ai-stats-fix.toml +285 -0
  4. package/.0spec/flows/ai-stats.toml +400 -0
  5. package/.github/workflows/publish.yml +28 -0
  6. package/CLAUDE.md +111 -0
  7. package/README.md +64 -0
  8. package/bun.lock +635 -0
  9. package/electrobun.config.ts +25 -0
  10. package/package.json +36 -0
  11. package/public/tray-icon.png +0 -0
  12. package/src/bun/aggregator.test.ts +49 -0
  13. package/src/bun/aggregator.ts +130 -0
  14. package/src/bun/discovery/claude.ts +18 -0
  15. package/src/bun/discovery/codex.ts +20 -0
  16. package/src/bun/discovery/copilot.ts +13 -0
  17. package/src/bun/discovery/droid.ts +13 -0
  18. package/src/bun/discovery/gemini.ts +13 -0
  19. package/src/bun/discovery/index.ts +28 -0
  20. package/src/bun/discovery/opencode.ts +13 -0
  21. package/src/bun/discovery/types.ts +13 -0
  22. package/src/bun/discovery/utils.ts +48 -0
  23. package/src/bun/index.ts +722 -0
  24. package/src/bun/normalizer.test.ts +101 -0
  25. package/src/bun/normalizer.ts +454 -0
  26. package/src/bun/parsers/claude.ts +234 -0
  27. package/src/bun/parsers/codex.test.ts +180 -0
  28. package/src/bun/parsers/codex.ts +435 -0
  29. package/src/bun/parsers/copilot.ts +4 -0
  30. package/src/bun/parsers/droid.ts +4 -0
  31. package/src/bun/parsers/gemini.ts +4 -0
  32. package/src/bun/parsers/generic.test.ts +97 -0
  33. package/src/bun/parsers/generic.ts +260 -0
  34. package/src/bun/parsers/index.ts +37 -0
  35. package/src/bun/parsers/opencode.ts +4 -0
  36. package/src/bun/parsers/types.ts +23 -0
  37. package/src/bun/pricing.ts +52 -0
  38. package/src/bun/scan.ts +77 -0
  39. package/src/bun/session-schema.ts +1 -0
  40. package/src/bun/store.ts +283 -0
  41. package/src/mainview/App.tsx +42 -0
  42. package/src/mainview/components/AgentBadge.tsx +17 -0
  43. package/src/mainview/components/Dashboard.tsx +229 -0
  44. package/src/mainview/components/DashboardCharts.tsx +499 -0
  45. package/src/mainview/components/EmptyState.tsx +17 -0
  46. package/src/mainview/components/Sidebar.tsx +30 -0
  47. package/src/mainview/components/StatsCards.tsx +118 -0
  48. package/src/mainview/hooks/useDashboardData.ts +315 -0
  49. package/src/mainview/hooks/useRPC.ts +29 -0
  50. package/src/mainview/index.css +195 -0
  51. package/src/mainview/index.html +12 -0
  52. package/src/mainview/index.ts +12 -0
  53. package/src/mainview/lib/constants.ts +32 -0
  54. package/src/mainview/lib/formatters.ts +82 -0
  55. package/src/shared/constants.ts +1 -0
  56. package/src/shared/schema.ts +71 -0
  57. package/src/shared/session-types.ts +61 -0
  58. package/src/shared/types.ts +59 -0
  59. package/src/types/electrobun-bun.d.ts +117 -0
  60. package/src/types/electrobun-root.d.ts +3 -0
  61. package/src/types/electrobun-view.d.ts +38 -0
  62. package/tsconfig.json +18 -0
  63. package/tsconfig.typecheck.json +11 -0
  64. package/vite.config.ts +23 -0
@@ -0,0 +1,50 @@
1
+ # ai-stats — AI analytics dashboard desktop app (Electrobun)
2
+
3
+ [settings]
4
+ default_team = "global"
5
+ default_model = "claude-opus-4-6"
6
+ bypass_permissions = true
7
+ fail_fast = true
8
+ retries = 1
9
+
10
+ [settings.doctor]
11
+ enabled = true
12
+ agent = "doctor"
13
+
14
+ # ─── Teams ──────────────────────────────────────────────
15
+
16
+ [teams.global]
17
+ description = "Single agent — general tasks"
18
+ agents = ["claude-agent"]
19
+
20
+ [teams.research]
21
+ description = "Research & analysis"
22
+ agents = ["planner-claude"]
23
+ rules = "Analyze documentation, produce structured reference material. No code changes."
24
+
25
+ [teams.planners]
26
+ description = "Architecture & planning"
27
+ agents = ["planner-claude"]
28
+ rules = "Design architecture, produce implementation specs. No implementation."
29
+
30
+ [teams.implementors]
31
+ description = "Implementation team"
32
+ agents = ["coder-codex"]
33
+
34
+ [teams.reviewers]
35
+ description = "QA & review"
36
+ agents = ["reviewer-codex"]
37
+ rules = "Review code, run tests, verify builds. Output structured QA verdicts."
38
+
39
+ # ─── Agents ─────────────────────────────────────────────
40
+
41
+ [agents.claude-agent]
42
+ engine = "claude"
43
+ model = "claude-opus-4-6"
44
+ timeout = 600
45
+
46
+ [agents.doctor]
47
+ engine = "claude"
48
+ model = "haiku"
49
+ timeout = 30
50
+ max_turns = 3
@@ -0,0 +1,291 @@
1
+ [flow]
2
+ name = "ai-stats-build"
3
+ description = "Build ai-stats from existing architecture spec — scaffold through commit"
4
+
5
+ # NOTE: ARCHITECTURE.md (1462 lines), SESSION_FORMATS.md, and AGENT_SESSIONS_REFERENCE.md
6
+ # are pre-seeded in the project root from prior research/planning runs.
7
+ # No consolidation stage needed — ARCHITECTURE.md is the authoritative spec.
8
+
9
+ # ─── Phase 1: Scaffold ─────────────────────────────────
10
+
11
+ [[stages]]
12
+ id = "scaffold"
13
+ name = "Project Scaffold"
14
+ type = "seq"
15
+ team = "implementors"
16
+ prompt = """
17
+ Read ARCHITECTURE.md in the project root — it is the authoritative spec.
18
+
19
+ Create the project scaffold as specified in Section 1 (Project Structure) and Section 9 (Build & Dev Workflow).
20
+
21
+ Constraints:
22
+ - Use Electrobun react-tailwind-vite pattern (Vite builds to dist/, copy config maps to views/)
23
+ - Remove "type": "module" and "module" from package.json if present
24
+ - SQLite via bun:sqlite (built into Bun, no extra deps)
25
+ - Tailwind v4 via @tailwindcss/vite plugin
26
+ - Use concurrently for dev:hmr script
27
+
28
+ Only skeleton — stub files with empty exports/components. No business logic.
29
+
30
+ Verify:
31
+ - `bun install` succeeds
32
+ - Vite build compiles without errors
33
+ - Main process file parses without errors
34
+ """
35
+ output = { format = "markdown", name = "scaffold.md" }
36
+
37
+ [[stages]]
38
+ id = "qa-scaffold"
39
+ name = "QA Scaffold"
40
+ type = "seq"
41
+ team = "reviewers"
42
+ depends_on = ["scaffold"]
43
+ input_from = ["scaffold"]
44
+ prompt = """
45
+ Read ARCHITECTURE.md for the expected project structure.
46
+
47
+ Verify the scaffold:
48
+ 1. `bun install` succeeds
49
+ 2. Vite build compiles without errors
50
+ 3. All files from Section 1 of ARCHITECTURE.md exist (check file tree)
51
+ 4. package.json has correct scripts (dev, dev:hmr, build)
52
+ 5. electrobun.config.ts is valid
53
+ 6. No "type": "module" in package.json
54
+
55
+ Output JSON: { "verdict": "pass" or "fail", "issues": [...] }
56
+ """
57
+ output = { format = "json", name = "qa-scaffold.json" }
58
+
59
+ [[stages]]
60
+ id = "fix-scaffold"
61
+ name = "Fix Scaffold Issues"
62
+ type = "loop"
63
+ team = "implementors"
64
+ depends_on = ["qa-scaffold"]
65
+ input_from = ["qa-scaffold"]
66
+ prompt = "Fix all issues from QA report."
67
+ max_loops = 2
68
+ loop_to = "qa-scaffold"
69
+ condition = "qa-scaffold.verdict != 'pass'"
70
+ output = { format = "diff", name = "scaffold-fixes.diff" }
71
+
72
+ # ─── Phase 2: Parsers & Data Layer ─────────────────────
73
+
74
+ [[stages]]
75
+ id = "data-layer"
76
+ name = "Session Parsers + SQLite + RPC"
77
+ type = "seq"
78
+ team = "implementors"
79
+ depends_on = ["fix-scaffold"]
80
+ prompt = """
81
+ Read ARCHITECTURE.md (Sections 2-6) and SESSION_FORMATS.md in the project root. Implement:
82
+
83
+ 1. Session discovery (src/bun/discovery/):
84
+ - Discover Claude Code sessions: ~/.claude/projects/*/*.jsonl
85
+ - Discover Codex CLI sessions: ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl
86
+ - Discover other agents if present (Gemini, Copilot, OpenCode)
87
+ - Return file paths with agent source type
88
+
89
+ 2. JSONL parsers (src/bun/parsers/):
90
+ - Claude Code parser — handle nested message.content, uuid/parentUuid threading
91
+ - Codex CLI parser — handle top-level content, delta streaming chunks
92
+ - Generic parser fallback
93
+ - All parsers produce normalized SessionEvent[]
94
+
95
+ 3. Normalizer (src/bun/normalizer.ts):
96
+ - Map raw event types to SessionEventKind (user, assistant, tool_call, tool_result, error, meta)
97
+ - Extract text from various content formats
98
+ - Handle timestamp format variations (ISO 8601, epoch seconds/ms)
99
+
100
+ 4. SQLite database (src/bun/db.ts):
101
+ - Tables as specified in Section 3 of ARCHITECTURE.md
102
+ - Migration/init, upsert parsed sessions, query functions
103
+
104
+ 5. RPC types (src/shared/types.ts) + wiring (src/bun/index.ts):
105
+ - As specified in Section 6 of ARCHITECTURE.md
106
+
107
+ Verify:
108
+ - TypeScript compiles without errors
109
+ - DB initializes and creates tables
110
+ - At least one real session file parses successfully
111
+ """
112
+ output = { format = "markdown", name = "data-layer.md" }
113
+
114
+ [[stages]]
115
+ id = "qa-data"
116
+ name = "QA Data Layer"
117
+ type = "seq"
118
+ team = "reviewers"
119
+ depends_on = ["data-layer"]
120
+ input_from = ["data-layer"]
121
+ prompt = """
122
+ Read ARCHITECTURE.md for the expected schema and RPC surface.
123
+
124
+ Verify the data layer:
125
+ 1. SQLite schema matches Section 3 of ARCHITECTURE.md
126
+ 2. Session discovery finds real session files on this machine
127
+ 3. At least one Claude Code and one Codex session parses without errors
128
+ 4. Normalized events have correct kind, text, timestamps
129
+ 5. RPC types are complete and type-safe
130
+ 6. TypeScript compiles
131
+
132
+ Output JSON: { "verdict": "pass" or "fail", "issues": [...] }
133
+ """
134
+ output = { format = "json", name = "qa-data.json" }
135
+
136
+ [[stages]]
137
+ id = "fix-data"
138
+ name = "Fix Data Layer Issues"
139
+ type = "loop"
140
+ team = "implementors"
141
+ depends_on = ["qa-data"]
142
+ input_from = ["qa-data"]
143
+ prompt = "Fix all issues from QA report."
144
+ max_loops = 2
145
+ loop_to = "qa-data"
146
+ condition = "qa-data.verdict != 'pass'"
147
+ output = { format = "diff", name = "data-fixes.diff" }
148
+
149
+ # ─── Phase 3: Dashboard UI ─────────────────────────────
150
+
151
+ [[stages]]
152
+ id = "dashboard-ui"
153
+ name = "Dashboard UI Components"
154
+ type = "seq"
155
+ team = "implementors"
156
+ depends_on = ["fix-data"]
157
+ prompt = """
158
+ Read ARCHITECTURE.md Section 7 (Component Tree). Implement the React dashboard UI:
159
+
160
+ 1. App shell (App.tsx) — sidebar nav + main content area
161
+ 2. Dashboard page — summary cards (total sessions, total events, tool calls today) + charts
162
+ 3. Charts — session count over time (line), events by agent (bar), tool call frequency (bar), model usage (pie)
163
+ 4. Session browser page — filterable list of all sessions, search by repo/agent/date
164
+ 5. Session detail page — event timeline with kind icons, expandable tool call details
165
+ 6. Settings page — configure watched directories, rescan interval
166
+ 7. useRPC hook — typed wrapper around Electroview RPC calls
167
+
168
+ Use Tailwind v4 for all styling. Dark theme by default.
169
+ Use Recharts for charts.
170
+
171
+ Verify:
172
+ - Vite build compiles without errors
173
+ - All components render (no runtime crashes on import)
174
+ """
175
+ output = { format = "markdown", name = "dashboard-ui.md" }
176
+
177
+ [[stages]]
178
+ id = "qa-ui"
179
+ name = "QA Dashboard UI"
180
+ type = "seq"
181
+ team = "reviewers"
182
+ depends_on = ["dashboard-ui"]
183
+ input_from = ["dashboard-ui"]
184
+ prompt = """
185
+ Read ARCHITECTURE.md Section 7 for expected components.
186
+
187
+ Verify the dashboard UI:
188
+ 1. Vite build compiles without errors
189
+ 2. All pages/components exist per spec
190
+ 3. RPC hooks are properly typed
191
+ 4. Tailwind classes are valid
192
+ 5. Dark theme is consistent
193
+ 6. No hardcoded data — all data comes through RPC
194
+
195
+ Output JSON: { "verdict": "pass" or "fail", "issues": [...] }
196
+ """
197
+ output = { format = "json", name = "qa-ui.json" }
198
+
199
+ [[stages]]
200
+ id = "fix-ui"
201
+ name = "Fix UI Issues"
202
+ type = "loop"
203
+ team = "implementors"
204
+ depends_on = ["qa-ui"]
205
+ input_from = ["qa-ui"]
206
+ prompt = "Fix all issues from QA report."
207
+ max_loops = 2
208
+ loop_to = "qa-ui"
209
+ condition = "qa-ui.verdict != 'pass'"
210
+ output = { format = "diff", name = "ui-fixes.diff" }
211
+
212
+ # ─── Phase 4: Native Integration ───────────────────────
213
+
214
+ [[stages]]
215
+ id = "native"
216
+ name = "Tray, Menu & Window Polish"
217
+ type = "seq"
218
+ team = "implementors"
219
+ depends_on = ["fix-ui"]
220
+ prompt = """
221
+ Read ARCHITECTURE.md Section 11 (Main Process Behavior). Implement native desktop integration:
222
+
223
+ 1. System tray:
224
+ - Show app icon in tray
225
+ - Tray menu: quick stats (today's sessions/events), "Show Dashboard", "Rescan Sessions", "Quit"
226
+ - Clicking tray icon shows/hides main window
227
+
228
+ 2. Application menu:
229
+ - Standard Edit menu (undo, redo, cut, copy, paste, selectAll)
230
+ - File menu: "Rescan Sessions" action, "Quit"
231
+ - View menu: "Toggle Dark Mode"
232
+
233
+ 3. Window behavior:
234
+ - Close button minimizes to tray (on macOS)
235
+ - Proper quit via menu or tray
236
+
237
+ Verify:
238
+ - Main process starts without errors
239
+ - Tray icon appears
240
+ - Menu items are functional
241
+ """
242
+ output = { format = "markdown", name = "native.md" }
243
+
244
+ [[stages]]
245
+ id = "qa-native"
246
+ name = "QA Native Integration"
247
+ type = "seq"
248
+ team = "reviewers"
249
+ depends_on = ["native"]
250
+ input_from = ["native"]
251
+ prompt = """
252
+ Verify native integration:
253
+ 1. Tray icon creates without errors
254
+ 2. Application menu has all required items
255
+ 3. Menu actions are wired to handlers
256
+ 4. Window close behavior is correct
257
+ 5. Main process starts and creates window + tray
258
+
259
+ Output JSON: { "verdict": "pass" or "fail", "issues": [...] }
260
+ """
261
+ output = { format = "json", name = "qa-native.json" }
262
+
263
+ [[stages]]
264
+ id = "fix-native"
265
+ name = "Fix Native Issues"
266
+ type = "loop"
267
+ team = "implementors"
268
+ depends_on = ["qa-native"]
269
+ input_from = ["qa-native"]
270
+ prompt = "Fix all issues from QA report."
271
+ max_loops = 2
272
+ loop_to = "qa-native"
273
+ condition = "qa-native.verdict != 'pass'"
274
+ output = { format = "diff", name = "native-fixes.diff" }
275
+
276
+ # ─── Phase 5: Final ────────────────────────────────────
277
+
278
+ [[stages]]
279
+ id = "commit"
280
+ name = "Final Commit"
281
+ type = "seq"
282
+ team = "global"
283
+ depends_on = ["fix-native"]
284
+ prompt = """
285
+ Review git diff. Stage all new/modified files. Commit with descriptive message:
286
+ "feat: ai-stats — Electrobun desktop dashboard for AI agent session analytics"
287
+
288
+ Do NOT push.
289
+ """
290
+ tools = ["Read", "Glob", "Grep", "Bash"]
291
+ output = { format = "markdown", name = "commit.md" }
@@ -0,0 +1,285 @@
1
+ [flow]
2
+ name = "ai-stats-fix"
3
+ description = "Fix ai-stats: remove SQLite, simplify to JSON store, Spotify Wrapped-style dashboard"
4
+
5
+ # ─── Phase 1: Rip out SQLite, replace with JSON file store ─────
6
+
7
+ [[stages]]
8
+ id = "json-store"
9
+ name = "Replace SQLite with JSON File Store"
10
+ type = "seq"
11
+ team = "implementors"
12
+ prompt = """
13
+ The app currently uses SQLite (bun:sqlite) for all data storage. This causes crashes
14
+ (UNIQUE constraint errors on events.id) and is overkill. Replace it entirely.
15
+
16
+ **What to do:**
17
+
18
+ 1. Delete `src/bun/db.ts` entirely.
19
+
20
+ 2. Create `src/bun/store.ts` — a simple JSON file store:
21
+ - Data dir: `~/.ai-stats/` (create with mkdirSync recursive)
22
+ - Files:
23
+ - `~/.ai-stats/scan-state.json` — record of parsed files: `Record<filePath, { source, fileSize, mtimeMs, parsedAt }>`
24
+ - `~/.ai-stats/daily.json` — daily aggregates: `Record<date, { bySource: Record<source, DayStats>, byModel: Record<model, DayStats>, totals: DayStats }>`
25
+ where DayStats = `{ sessions, messages, toolCalls, inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens, reasoningTokens, costUsd, durationMs }`
26
+ - `~/.ai-stats/settings.json` — app settings
27
+ - Read/write with Bun.file() / Bun.write() + JSON.parse/stringify
28
+ - No locking needed — single process app
29
+ - Load lazily on first access, cache in memory, flush on write
30
+
31
+ 3. Update `src/bun/scan.ts`:
32
+ - Remove all DB imports
33
+ - Use the new store for scan state checks (skip already-parsed files by path+mtime+size)
34
+ - After parsing sessions, aggregate into daily.json instead of SQLite
35
+ - Do NOT store individual sessions or events — only aggregate stats per day
36
+ - Each scan: discover files → parse → compute daily aggregates → merge into daily.json
37
+
38
+ 4. Update `src/bun/aggregator.ts`:
39
+ - Implement actual aggregation: take parsed sessions, group by date, accumulate stats
40
+ - Merge into existing daily.json (additive for new dates, replace for re-scanned dates)
41
+
42
+ 5. Update `src/bun/index.ts` (main process):
43
+ - Remove `import { openDatabase } from "./db"` and all `db.` calls
44
+ - Import from `./store` instead
45
+ - Update RPC handlers to read from JSON store
46
+
47
+ 6. Update `src/shared/types.ts` — simplify RPC:
48
+ - REMOVE these RPCs: getSessions, getSession, getSessionEvents, getDistinctModels, getDistinctRepos, getDbStats, vacuumDatabase
49
+ - KEEP these RPCs: getDashboardSummary, getDailyTimeline, triggerScan, getScanStatus, getTrayStats, getSettings, updateSettings
50
+ - getDashboardSummary reads from daily.json and computes totals
51
+ - getDailyTimeline reads date range from daily.json
52
+
53
+ 7. Update `src/shared/schema.ts`:
54
+ - Remove `Session`, `SessionEvent`, `SessionFilters`, `ScanState` interfaces (no longer exposed to frontend)
55
+ - Keep `TokenUsage`, `DashboardSummary`, `DailyAggregate`, `TrayStats`, `SessionSource`
56
+
57
+ 8. Remove `bun:sqlite` from any imports. Remove sqlite-related deps from package.json if any.
58
+
59
+ **Verify:**
60
+ - `bun install` succeeds
61
+ - Vite build compiles without errors
62
+ - No references to bun:sqlite remain
63
+ - No references to db.ts remain
64
+ """
65
+ output = { format = "markdown", name = "json-store.md" }
66
+
67
+ [[stages]]
68
+ id = "qa-store"
69
+ name = "QA JSON Store"
70
+ type = "seq"
71
+ team = "reviewers"
72
+ depends_on = ["json-store"]
73
+ input_from = ["json-store"]
74
+ prompt = """
75
+ Verify the SQLite removal and JSON store replacement:
76
+
77
+ 1. `bun:sqlite` is not imported anywhere: `grep -r "bun:sqlite" src/`
78
+ 2. `db.ts` does not exist
79
+ 3. `src/bun/store.ts` exists and implements read/write for scan-state.json, daily.json, settings.json
80
+ 4. `src/bun/scan.ts` uses store, not db
81
+ 5. `src/bun/index.ts` uses store, not db
82
+ 6. RPC types in shared/types.ts have no session/event RPCs
83
+ 7. schema.ts has no Session/SessionEvent/SessionFilters interfaces
84
+ 8. Vite build compiles without errors
85
+ 9. TypeScript has no type errors (check with `bunx tsc --noEmit` or esbuild)
86
+
87
+ Output JSON: { "verdict": "pass" or "fail", "issues": [...] }
88
+ """
89
+ output = { format = "json", name = "qa-store.json" }
90
+
91
+ [[stages]]
92
+ id = "fix-store"
93
+ name = "Fix Store Issues"
94
+ type = "loop"
95
+ team = "implementors"
96
+ depends_on = ["qa-store"]
97
+ input_from = ["qa-store"]
98
+ prompt = "Fix all issues from QA report."
99
+ max_loops = 2
100
+ loop_to = "qa-store"
101
+ condition = "qa-store.verdict != 'pass'"
102
+ output = { format = "diff", name = "store-fixes.diff" }
103
+
104
+ # ─── Phase 2: Spotify Wrapped-style UI ─────────────────────
105
+
106
+ [[stages]]
107
+ id = "wrapped-ui"
108
+ name = "Spotify Wrapped Dashboard"
109
+ type = "seq"
110
+ team = "implementors"
111
+ depends_on = ["fix-store"]
112
+ prompt = """
113
+ Transform the dashboard into a Spotify Wrapped-style visual experience. This should feel like
114
+ an annual review / "Your Year in Code" summary — bold typography, gradient backgrounds,
115
+ animated stat reveals, and visual flair.
116
+
117
+ **Delete these files** (session detail features removed):
118
+ - src/mainview/components/SessionDetail.tsx
119
+ - src/mainview/components/SessionList.tsx
120
+ - src/mainview/components/SessionListItem.tsx
121
+ - src/mainview/components/EventTimeline.tsx
122
+ - src/mainview/components/EventItem.tsx
123
+ - src/mainview/components/FilterBar.tsx
124
+ - src/mainview/components/SearchInput.tsx
125
+ - src/mainview/hooks/useSessionDetail.ts
126
+ - src/mainview/hooks/useSessions.ts
127
+ - src/mainview/lib/filters.ts
128
+ - All *.test.tsx files
129
+
130
+ **Redesign App.tsx:**
131
+ - Remove sidebar navigation — single-page "Wrapped" scroll experience
132
+ - Remove "sessions" and "session-detail" views entirely
133
+ - Keep a small gear icon for settings (modal overlay, not separate page)
134
+ - Full-screen scrollable cards
135
+
136
+ **Create new Wrapped-style Dashboard (replace existing Dashboard.tsx, DashboardCharts.tsx, StatsCards.tsx):**
137
+
138
+ The dashboard is a vertical scroll of full-width "cards" — each card fills most of the viewport
139
+ and showcases one stat category with bold visuals:
140
+
141
+ Card 1: "Your AI Coding Year" hero
142
+ - Big animated counter: total sessions, total cost, total tokens
143
+ - Gradient background (dark purple → blue → teal)
144
+ - Date range shown subtly
145
+
146
+ Card 2: "Time Spent Coding with AI"
147
+ - Total hours/days spent
148
+ - Average session duration
149
+ - Longest session highlight
150
+ - Animated circular progress ring
151
+
152
+ Card 3: "Your Top Models"
153
+ - Ranked list of models by usage (tokens or cost)
154
+ - Horizontal bar chart with model colors
155
+ - Percentage breakdown
156
+
157
+ Card 4: "Your Agents"
158
+ - Agent breakdown (Claude, Codex, Gemini, etc.)
159
+ - Each agent gets an icon/emoji and stats
160
+ - Donut chart showing distribution
161
+
162
+ Card 5: "Daily Activity"
163
+ - Heatmap-style grid (like GitHub contribution graph) or area chart
164
+ - Shows daily token usage or session count over time
165
+
166
+ Card 6: "Cost Breakdown"
167
+ - Total spend with big number
168
+ - Daily average
169
+ - Most expensive day
170
+ - Trend line
171
+
172
+ Card 7: "Your Top Repos"
173
+ - List of repos by session count and cost
174
+ - Bar chart
175
+
176
+ **Visual style:**
177
+ - Dark theme default — deep navy/charcoal backgrounds
178
+ - Each card has a subtle gradient or accent color
179
+ - Use CSS animations for number counters (count up on scroll into view)
180
+ - Large typography (3xl-6xl for hero numbers)
181
+ - Rounded cards with glassmorphism borders (subtle white/10 border, backdrop-blur)
182
+ - Recharts for data visualization where needed
183
+ - Smooth scroll-snap between cards
184
+ - Responsive — works on smaller windows too
185
+
186
+ **Data source:**
187
+ - All data comes from RPC `getDashboardSummary` and `getDailyTimeline`
188
+ - No session-level data needed
189
+
190
+ **Hooks:**
191
+ - Keep `useDashboardData.ts` but simplify to only fetch summary + timeline
192
+ - Remove session-related hooks
193
+ - Update `useRPC.ts` to remove session RPCs
194
+
195
+ **Update Sidebar.tsx:**
196
+ - Remove it entirely or replace with a minimal floating nav
197
+ - Just a small settings gear + app title
198
+
199
+ **Verify:**
200
+ - Vite build compiles
201
+ - No imports of deleted files remain
202
+ - No TypeScript errors
203
+ """
204
+ output = { format = "markdown", name = "wrapped-ui.md" }
205
+
206
+ [[stages]]
207
+ id = "qa-wrapped"
208
+ name = "QA Wrapped UI"
209
+ type = "seq"
210
+ team = "reviewers"
211
+ depends_on = ["wrapped-ui"]
212
+ input_from = ["wrapped-ui"]
213
+ prompt = """
214
+ Verify the Wrapped UI transformation:
215
+
216
+ 1. Deleted files are gone (SessionDetail, SessionList, EventTimeline, etc.)
217
+ 2. No imports of deleted files remain anywhere
218
+ 3. Sidebar is removed or minimal
219
+ 4. App.tsx has no "sessions" or "session-detail" views
220
+ 5. Dashboard renders a scroll of visual cards (check component structure)
221
+ 6. RPC calls are only getDashboardSummary and getDailyTimeline
222
+ 7. Vite build compiles
223
+ 8. TypeScript has no errors
224
+ 9. All Recharts imports are valid
225
+ 10. CSS uses dark theme with gradients
226
+
227
+ Output JSON: { "verdict": "pass" or "fail", "issues": [...] }
228
+ """
229
+ output = { format = "json", name = "qa-wrapped.json" }
230
+
231
+ [[stages]]
232
+ id = "fix-wrapped"
233
+ name = "Fix Wrapped UI Issues"
234
+ type = "loop"
235
+ team = "implementors"
236
+ depends_on = ["qa-wrapped"]
237
+ input_from = ["qa-wrapped"]
238
+ prompt = "Fix all issues from QA report."
239
+ max_loops = 2
240
+ loop_to = "qa-wrapped"
241
+ condition = "qa-wrapped.verdict != 'pass'"
242
+ output = { format = "diff", name = "wrapped-fixes.diff" }
243
+
244
+ # ─── Phase 3: Integration test + commit ─────────────────────
245
+
246
+ [[stages]]
247
+ id = "integration"
248
+ name = "Integration Smoke Test"
249
+ type = "seq"
250
+ team = "implementors"
251
+ depends_on = ["fix-wrapped"]
252
+ prompt = """
253
+ Final integration check:
254
+
255
+ 1. Run `bun install` — must succeed
256
+ 2. Run Vite build — must succeed with no errors
257
+ 3. Run `bunx tsc --noEmit` or esbuild check — no type errors
258
+ 4. Verify no references to:
259
+ - bun:sqlite
260
+ - db.ts
261
+ - SessionDetail, SessionList, EventTimeline, EventItem
262
+ - querySessions, getSessionEvents, getSession
263
+ 5. Verify ~/.ai-stats/ directory structure works:
264
+ - The store module can create the directory
265
+ - Can write and read JSON files
266
+ 6. Fix any remaining issues.
267
+
268
+ Report what you found and fixed.
269
+ """
270
+ output = { format = "markdown", name = "integration.md" }
271
+
272
+ [[stages]]
273
+ id = "commit"
274
+ name = "Final Commit"
275
+ type = "seq"
276
+ team = "global"
277
+ depends_on = ["integration"]
278
+ prompt = """
279
+ Review git diff. Stage all new/modified files and deleted files. Commit with message:
280
+ "refactor: remove SQLite, add JSON store, Spotify Wrapped-style dashboard"
281
+
282
+ Do NOT push.
283
+ """
284
+ tools = ["Read", "Glob", "Grep", "Bash"]
285
+ output = { format = "markdown", name = "commit.md" }