spiracha 2.0.0 → 2.2.0

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 (162) hide show
  1. package/AGENTS.md +27 -12
  2. package/README.md +42 -19
  3. package/apps/ui/AGENTS.md +18 -10
  4. package/apps/ui/README.md +36 -11
  5. package/apps/ui/src/components/analytics-breakdowns.tsx +106 -0
  6. package/apps/ui/src/components/antigravity-conversations-table.tsx +51 -11
  7. package/apps/ui/src/components/antigravity-workspaces-table.tsx +1 -1
  8. package/apps/ui/src/components/app-shell.tsx +46 -3
  9. package/apps/ui/src/components/breadcrumbs.tsx +21 -3
  10. package/apps/ui/src/components/claude-code-sessions-table.tsx +42 -6
  11. package/apps/ui/src/components/claude-code-workspaces-table.tsx +3 -1
  12. package/apps/ui/src/components/cursor-threads-table.tsx +10 -47
  13. package/apps/ui/src/components/data-table.tsx +23 -5
  14. package/apps/ui/src/components/delete-confirm-dialog.tsx +4 -3
  15. package/apps/ui/src/components/export-dialog.tsx +79 -74
  16. package/apps/ui/src/components/grok-sessions-table.tsx +146 -0
  17. package/apps/ui/src/components/grok-workspaces-table.tsx +53 -0
  18. package/apps/ui/src/components/kiro-sessions-table.tsx +40 -4
  19. package/apps/ui/src/components/opencode-sessions-table.tsx +40 -4
  20. package/apps/ui/src/components/page-header.tsx +15 -9
  21. package/apps/ui/src/components/projects-table.tsx +4 -1
  22. package/apps/ui/src/components/qoder-sessions-table.tsx +23 -2
  23. package/apps/ui/src/components/qoder-workspaces-table.tsx +5 -1
  24. package/apps/ui/src/components/route-error-panel.tsx +13 -0
  25. package/apps/ui/src/components/selection-actions-toolbar.tsx +80 -0
  26. package/apps/ui/src/components/thread-goals-panel.tsx +50 -0
  27. package/apps/ui/src/components/thread-tools-panel.tsx +142 -0
  28. package/apps/ui/src/components/threads-table.tsx +13 -47
  29. package/apps/ui/src/components/transcript-view.tsx +148 -52
  30. package/apps/ui/src/components/ui/select.tsx +1 -1
  31. package/apps/ui/src/lib/antigravity-conversation-state.ts +17 -4
  32. package/apps/ui/src/lib/antigravity-server.ts +209 -11
  33. package/apps/ui/src/lib/antigravity-transcript-events.ts +57 -73
  34. package/apps/ui/src/lib/claude-code-queries.ts +8 -0
  35. package/apps/ui/src/lib/claude-code-server.ts +185 -7
  36. package/apps/ui/src/lib/claude-code-transcript-events.ts +8 -1
  37. package/apps/ui/src/lib/codex-queries.ts +16 -0
  38. package/apps/ui/src/lib/codex-server.ts +134 -52
  39. package/apps/ui/src/lib/cursor-server.ts +68 -53
  40. package/apps/ui/src/lib/cursor-transcript-events.ts +11 -86
  41. package/apps/ui/src/lib/delete-batch.ts +52 -0
  42. package/apps/ui/src/lib/error-presentation.ts +43 -0
  43. package/apps/ui/src/lib/export-mutation.ts +20 -0
  44. package/apps/ui/src/lib/export-options.ts +15 -0
  45. package/apps/ui/src/lib/formatters.ts +3 -5
  46. package/apps/ui/src/lib/grok-queries.ts +22 -0
  47. package/apps/ui/src/lib/grok-server.ts +168 -0
  48. package/apps/ui/src/lib/grok-transcript-events.ts +149 -0
  49. package/apps/ui/src/lib/kiro-server.ts +97 -7
  50. package/apps/ui/src/lib/mutation-error.ts +15 -0
  51. package/apps/ui/src/lib/opencode-server.ts +96 -7
  52. package/apps/ui/src/lib/path-utils.ts +1 -1
  53. package/apps/ui/src/lib/qoder-queries.ts +15 -0
  54. package/apps/ui/src/lib/qoder-server.ts +67 -11
  55. package/apps/ui/src/lib/qoder-transcript-events.ts +1 -1
  56. package/apps/ui/src/lib/route-search.ts +114 -0
  57. package/apps/ui/src/lib/route-state-reset.tsx +10 -0
  58. package/apps/ui/src/lib/settings-server.ts +33 -0
  59. package/apps/ui/src/lib/settings-store.tsx +82 -38
  60. package/apps/ui/src/lib/settings.ts +65 -0
  61. package/apps/ui/src/lib/source-session-export-server.ts +86 -3
  62. package/apps/ui/src/lib/thread-metadata.ts +22 -0
  63. package/apps/ui/src/lib/thread-transcript-load.ts +15 -0
  64. package/apps/ui/src/lib/thread-transcript-stats.ts +10 -1
  65. package/apps/ui/src/lib/workspace-delete-navigation.ts +20 -0
  66. package/apps/ui/src/routeTree.gen.ts +341 -234
  67. package/apps/ui/src/routes/__root.tsx +12 -15
  68. package/apps/ui/src/routes/analytics.tsx +10 -61
  69. package/apps/ui/src/routes/antigravity-conversations.$conversationId.tsx +149 -29
  70. package/apps/ui/src/routes/antigravity.$workspaceKey.tsx +262 -42
  71. package/apps/ui/src/routes/antigravity.index.tsx +2 -2
  72. package/apps/ui/src/routes/api.v1.conversations.$source.$id.ts +4 -0
  73. package/apps/ui/src/routes/api.v1.conversations.delete.ts +12 -0
  74. package/apps/ui/src/routes/api.v1.conversations.export.ts +12 -0
  75. package/apps/ui/src/routes/claude-code-sessions.$sessionId.tsx +168 -28
  76. package/apps/ui/src/routes/claude-code.$workspaceKey.tsx +179 -45
  77. package/apps/ui/src/routes/claude-code.index.tsx +2 -2
  78. package/apps/ui/src/routes/codex.$project.tsx +33 -31
  79. package/apps/ui/src/routes/codex.index.tsx +5 -10
  80. package/apps/ui/src/routes/cursor-threads.$composerId.tsx +31 -18
  81. package/apps/ui/src/routes/cursor.$workspaceKey.tsx +44 -28
  82. package/apps/ui/src/routes/cursor.index.tsx +5 -2
  83. package/apps/ui/src/routes/grok-sessions.$sessionId.tsx +401 -0
  84. package/apps/ui/src/routes/grok.$workspaceKey.tsx +295 -0
  85. package/apps/ui/src/routes/grok.index.tsx +48 -0
  86. package/apps/ui/src/routes/index.tsx +2 -18
  87. package/apps/ui/src/routes/kiro-sessions.$sessionId.tsx +91 -27
  88. package/apps/ui/src/routes/kiro.$workspaceKey.tsx +213 -51
  89. package/apps/ui/src/routes/kiro.index.tsx +2 -2
  90. package/apps/ui/src/routes/opencode-sessions.$sessionId.tsx +108 -29
  91. package/apps/ui/src/routes/opencode.$workspaceKey.tsx +231 -55
  92. package/apps/ui/src/routes/opencode.index.tsx +6 -2
  93. package/apps/ui/src/routes/qoder-sessions.$sessionId.tsx +19 -15
  94. package/apps/ui/src/routes/qoder.$workspaceKey.tsx +89 -48
  95. package/apps/ui/src/routes/qoder.index.tsx +2 -2
  96. package/apps/ui/src/routes/threads.$threadId.tsx +620 -105
  97. package/apps/ui/vite.config.ts +22 -12
  98. package/bin/spiracha.ts +28 -1
  99. package/package.json +37 -27
  100. package/src/client.ts +183 -5
  101. package/src/lib/antigravity-db.ts +424 -94
  102. package/src/lib/antigravity-exporter-types.ts +3 -0
  103. package/src/lib/antigravity-keychain.ts +7 -8
  104. package/src/lib/antigravity-projects.ts +201 -0
  105. package/src/lib/antigravity-transcript-phase.ts +47 -0
  106. package/src/lib/claude-code-db.ts +534 -42
  107. package/src/lib/claude-code-exporter-types.ts +5 -0
  108. package/src/lib/claude-code-transcript-phase.ts +60 -1
  109. package/src/lib/claude-code-transcript.ts +8 -5
  110. package/src/lib/codex-analytics.ts +32 -5
  111. package/src/lib/codex-browser-db.ts +540 -137
  112. package/src/lib/codex-browser-export.ts +18 -27
  113. package/src/lib/codex-browser-types.ts +21 -1
  114. package/src/lib/codex-thread-cache.ts +106 -23
  115. package/src/lib/codex-thread-parser.ts +149 -55
  116. package/src/lib/codex-thread-recovery.ts +38 -11
  117. package/src/lib/codex-transcript-filter.ts +31 -0
  118. package/src/lib/codex-transcript-renderer.ts +87 -79
  119. package/src/lib/concurrency.ts +56 -3
  120. package/src/lib/conversation-api.ts +410 -27
  121. package/src/lib/conversation-data/adapter-helpers.ts +25 -3
  122. package/src/lib/conversation-data/antigravity-adapter.ts +70 -26
  123. package/src/lib/conversation-data/claude-code-adapter.ts +69 -12
  124. package/src/lib/conversation-data/codex-adapter.ts +108 -73
  125. package/src/lib/conversation-data/cursor-adapter.ts +77 -29
  126. package/src/lib/conversation-data/grok-adapter.ts +223 -0
  127. package/src/lib/conversation-data/index.ts +105 -11
  128. package/src/lib/conversation-data/kiro-adapter.ts +59 -12
  129. package/src/lib/conversation-data/message-selector.ts +2 -5
  130. package/src/lib/conversation-data/opencode-adapter.ts +67 -17
  131. package/src/lib/conversation-data/path-match.ts +1 -13
  132. package/src/lib/conversation-data/qoder-adapter.ts +67 -37
  133. package/src/lib/conversation-data/types.ts +43 -0
  134. package/src/lib/conversation-zip-export.ts +75 -0
  135. package/src/lib/cursor-db.ts +68 -28
  136. package/src/lib/cursor-id.ts +17 -0
  137. package/src/lib/cursor-recovery.ts +146 -35
  138. package/src/lib/cursor-transcript-phase.ts +40 -0
  139. package/src/lib/cursor-transcript.ts +21 -5
  140. package/src/lib/grok-db.ts +1068 -0
  141. package/src/lib/grok-exporter-types.ts +110 -0
  142. package/src/lib/grok-transcript-phase.ts +61 -0
  143. package/src/lib/grok-transcript.ts +167 -0
  144. package/src/lib/kiro-db.ts +187 -43
  145. package/src/lib/kiro-transcript.ts +0 -4
  146. package/src/lib/model-label.ts +11 -3
  147. package/src/lib/opencode-db.ts +599 -60
  148. package/src/lib/opencode-think-tags.ts +17 -3
  149. package/src/lib/opencode-transcript.ts +8 -5
  150. package/src/lib/portable-path.ts +9 -0
  151. package/src/lib/qoder-acp-client.ts +11 -2
  152. package/src/lib/qoder-db.ts +51 -17
  153. package/src/lib/qoder-transcript-phase.ts +64 -0
  154. package/src/lib/qoder-transcript.ts +30 -2
  155. package/src/lib/shared.ts +63 -15
  156. package/src/lib/sqlite-error.ts +31 -5
  157. package/src/lib/transcript-load-limiter.ts +87 -0
  158. package/src/lib/ui-cache.ts +185 -24
  159. package/src/lib/ui-export-archive.ts +58 -39
  160. package/src/lib/ui-export-files.ts +75 -15
  161. package/src/lib/ui-export-zip.ts +40 -0
  162. package/apps/ui/package.json +0 -65
package/AGENTS.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Purpose
4
4
 
5
- This repo is a Bun-first local app for browsing, exporting, and exposing agent conversation history from Codex, Claude Code, Kiro, Qoder, Cursor, Antigravity, and OpenCode.
5
+ This repo is a Bun-first local app for browsing, exporting, and exposing agent conversation history from Codex, Claude Code, Grok, Kiro, Qoder, Cursor, Antigravity, and OpenCode.
6
6
 
7
7
  The command-line exporter, MCP server, and Codex plugin were removed in the 2.0 hard cut. Do not add bridge commands, compatibility aliases, or deprecated entrypoints back. New client workflows should use the stable HTTP API exposed by the UI server or the stable `spiracha/client` package export.
8
8
 
@@ -52,10 +52,14 @@ Codex browser/export modules:
52
52
  - project/thread browsing queries, delete flows, dashboard summaries, DB path resolution
53
53
  - `src/lib/codex-browser-export.ts`
54
54
  - UI-facing thread download rendering
55
+ - `src/lib/codex-browser-types.ts`
56
+ - Codex browser query and presentation contracts
55
57
  - `src/lib/codex-thread-types.ts`
56
58
  - Codex DB row and transcript rendering types
57
59
  - `src/lib/codex-transcript-renderer.ts`
58
60
  - Markdown/plain text rendering for Codex session files
61
+ - `src/lib/codex-transcript-filter.ts`
62
+ - centralized hidden bootstrap and transcript-text filtering
59
63
  - `src/lib/codex-thread-parser.ts`
60
64
  - structured Codex event parsing used by analytics and the UI
61
65
  - `src/lib/codex-analytics.ts`
@@ -66,29 +70,35 @@ Codex browser/export modules:
66
70
  - Codex project recovery helpers
67
71
 
68
72
  Source-specific browser/export modules:
69
- - `src/lib/claude-code-db.ts`, `src/lib/claude-code-transcript-phase.ts`, `src/lib/claude-code-transcript.ts`
70
- - `src/lib/kiro-db.ts`, `src/lib/kiro-transcript-phase.ts`, `src/lib/kiro-transcript.ts`
71
- - `src/lib/qoder-db.ts`, `src/lib/qoder-transcript-phase.ts`, `src/lib/qoder-transcript.ts`
72
- - `src/lib/cursor-db.ts`, `src/lib/cursor-recovery.ts`, `src/lib/cursor-transcript.ts`
73
- - `src/lib/antigravity-db.ts`, `src/lib/antigravity-keychain.ts`
74
- - `src/lib/opencode-db.ts`, `src/lib/opencode-transcript-phase.ts`, `src/lib/opencode-think-tags.ts`, `src/lib/opencode-transcript.ts`
73
+ - `src/lib/claude-code-db.ts`, `src/lib/claude-code-exporter-types.ts`, `src/lib/claude-code-transcript-phase.ts`, `src/lib/claude-code-transcript.ts`
74
+ - `src/lib/grok-db.ts`, `src/lib/grok-exporter-types.ts`, `src/lib/grok-transcript-phase.ts`, `src/lib/grok-transcript.ts`
75
+ - `src/lib/kiro-db.ts`, `src/lib/kiro-exporter-types.ts`, `src/lib/kiro-transcript-phase.ts`, `src/lib/kiro-transcript.ts`
76
+ - `src/lib/qoder-db.ts`, `src/lib/qoder-acp-client.ts`, `src/lib/qoder-exporter-types.ts`, `src/lib/qoder-transcript-phase.ts`, `src/lib/qoder-transcript.ts`
77
+ - `src/lib/cursor-db.ts`, `src/lib/cursor-exporter-types.ts`, `src/lib/cursor-recovery.ts`, `src/lib/cursor-transcript-phase.ts`, `src/lib/cursor-transcript.ts`
78
+ - `src/lib/antigravity-db.ts`, `src/lib/antigravity-exporter-types.ts`, `src/lib/antigravity-keychain.ts`, `src/lib/antigravity-projects.ts`, `src/lib/antigravity-transcript-phase.ts`
79
+ - `src/lib/opencode-db.ts`, `src/lib/opencode-exporter-types.ts`, `src/lib/opencode-transcript-phase.ts`, `src/lib/opencode-think-tags.ts`, `src/lib/opencode-transcript.ts`
75
80
 
76
81
  Shared utilities:
77
82
  - `src/lib/concurrency.ts`
78
83
  - `src/lib/model-label.ts`
79
84
  - `src/lib/path-transforms.ts`
85
+ - `src/lib/portable-path.ts`
80
86
  - `src/lib/shared.ts`
81
87
  - `src/lib/sqlite-error.ts`
82
88
  - `src/lib/sqlite-retry.ts`
83
89
  - `src/lib/ui-cache.ts`
84
90
  - `src/lib/ui-export-archive.ts`
85
91
  - `src/lib/ui-export-files.ts`
92
+ - `src/lib/ui-export-zip.ts`
93
+ - `src/lib/conversation-zip-export.ts`
94
+ - `src/lib/transcript-load-limiter.ts`
95
+ - `src/coverage-check.ts`
86
96
 
87
- UI package:
97
+ UI source tree:
88
98
  - `apps/ui/`
89
99
  - TanStack Start browser UI
90
100
  - API routes live under `apps/ui/src/routes/api.v1.*.ts`
91
- - source routes include `/threads/$threadId`, `/claude-code-sessions/$sessionId`, `/kiro-sessions/$sessionId`, `/qoder-sessions/$sessionId`, `/cursor-threads/$composerId`, `/antigravity-conversations/$conversationId`, and `/opencode-sessions/$sessionId`
101
+ - source routes include `/threads/$threadId`, `/claude-code-sessions/$sessionId`, `/grok-sessions/$sessionId`, `/kiro-sessions/$sessionId`, `/qoder-sessions/$sessionId`, `/cursor-threads/$composerId`, `/antigravity-conversations/$conversationId`, and `/opencode-sessions/$sessionId`
92
102
 
93
103
  ## Stable API Contract
94
104
 
@@ -105,6 +115,9 @@ The local UI server exposes:
105
115
  - `POST /api/v1/conversation-query`
106
116
  - `GET /api/v1/conversations/:source/:id`
107
117
  - `GET /api/v1/conversations/:source/:id/export`
118
+ - `DELETE /api/v1/conversations/:source/:id`
119
+ - `POST /api/v1/conversations/delete`
120
+ - `POST /api/v1/conversations/export`
108
121
  - `GET /api/v1/resolve?ref=<url-or-deeplink>`
109
122
 
110
123
  Defaults:
@@ -126,8 +139,9 @@ Current tests cover:
126
139
  - Cursor recovery/prune behavior
127
140
  - Antigravity discovery, transcript parsing, Keychain state, and artifact export rendering
128
141
  - OpenCode MiniMax `<think>` tag extraction, including code-literal preservation
129
- - UI component and adapter behavior through the Vitest suite wrapped by `src/ui-package.test.ts`
142
+ - UI component and adapter behavior through the Vitest suite wrapped by `src/ui-suite.test.ts`
130
143
  - package manifest hard-cut guarantees through `src/package-manifest.test.ts`
144
+ - a 90% line-coverage gate for both the root Bun suite and UI Vitest suite, with function and hotspot reporting
131
145
 
132
146
  When changing risky areas:
133
147
  - Stable API changes: update `src/lib/conversation-api.test.ts` and focused tests under `src/lib/conversation-data/`.
@@ -147,13 +161,14 @@ rtk bun run build
147
161
  rtk bun run coverage
148
162
  rtk bun start
149
163
  rtk bun run ui:preview
150
- rtk bun run --cwd apps/ui test
164
+ rtk bun run test:ui
151
165
  ```
152
166
 
153
167
  ## Notes
154
168
 
155
169
  - Keep root-package source modules imported by the UI available through `@spiracha/lib/*`.
156
- - The UI package runs Vite through `bun --bun` because server functions depend on Bun-only modules like `bun:sqlite`.
170
+ - The repository has one package manifest. Keep UI runtime dependencies needed by packaged `bunx spiracha` in root `dependencies` and build/test-only tooling in root `devDependencies`.
171
+ - Root-owned UI Vite commands use `apps/ui` as their internal working directory and run through `bun --bun` because TanStack and server functions depend on that application root and Bun-only modules like `bun:sqlite`. Do not add a nested manifest to achieve this. UI Vitest commands use the normal Node runtime.
157
172
  - TanStack Start server functions should use `.validator(...)`, not deprecated `.inputValidator(...)`.
158
173
  - API routes should use route-level `server.handlers`.
159
174
  - Keep `*-transcript-phase.ts` modules browser-safe; UI client adapters import them directly.
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  [![license](https://img.shields.io/npm/l/spiracha)](LICENSE.md)
8
8
  [![runtime](https://img.shields.io/badge/runtime-Bun-000000?logo=bun)](https://bun.sh)
9
9
 
10
- Spiracha is a local TanStack Start app for browsing and exporting agent conversation history from Codex, Claude Code, Kiro, Qoder, Cursor, Antigravity, and OpenCode.
10
+ Spiracha is a Bun package with a local TanStack Start UI and a direct data client for browsing and exporting agent conversation history from Codex, Claude Code, Grok, Kiro, Qoder, Cursor, Antigravity, and OpenCode.
11
11
 
12
12
  The legacy CLI, MCP server, and Codex plugin surfaces have been removed in the 2.0 hard cut. Spiracha now exposes the UI and a stable local data API; client-specific workflows such as review collection belong in the client that calls the API.
13
13
 
@@ -24,17 +24,20 @@ Spiracha asks Vite for port 3000 and automatically uses the next available port
24
24
  For repository development:
25
25
 
26
26
  ```bash
27
- rtk bun install
28
- rtk bun start
27
+ bun install
28
+ bun start
29
29
  ```
30
30
 
31
31
  Open the local URL printed by Vite.
32
32
 
33
+ Spiracha requires Bun 1.3.14 or newer. Set `PORT` to request a different starting port, for example `PORT=4100 bunx spiracha`; the launcher uses the next available port if that one is occupied.
34
+
33
35
  ## What It Does
34
36
 
35
- - Browse local conversations across Codex, Claude Code, Kiro, Qoder, Cursor, Antigravity, and OpenCode.
36
- - Inspect source-specific detail pages with transcript, tool, reasoning, metadata, raw event, export, and delete flows where supported by the source.
37
- - Export transcripts from the UI as Markdown, text, or zip bundles with source-specific commentary/final-answer filtering.
37
+ - Browse local conversations across Codex, Claude Code, Grok, Kiro, Qoder, Cursor, Antigravity, and OpenCode.
38
+ - Search Codex projects from the app shell, with results delegated to the shareable `/codex?q=...` inventory filter.
39
+ - Inspect source-specific detail pages with transcript, tool, reasoning, metadata, raw event, export, and delete flows where supported by the source. Codex thread detail includes a tool-focused activity view plus recorded goals and sandbox policy.
40
+ - Export transcripts from the UI as Markdown, text, or zip bundles with source-specific commentary/final-answer filtering. The last submitted export choices persist across dialog openings; canceled drafts do not.
38
41
  - Expose a stable API for local clients that need normalized conversation metadata and message payloads.
39
42
  - Resolve Spiracha UI links and native source links into normalized `{ source, id }` references for cross-thread context lookup.
40
43
 
@@ -54,11 +57,16 @@ GET /api/v1/conversations?cwd=/absolute/project&include_messages=true
54
57
  POST /api/v1/conversation-query
55
58
  GET /api/v1/conversations/:source/:id
56
59
  GET /api/v1/conversations/:source/:id/export
60
+ DELETE /api/v1/conversations/:source/:id
61
+ POST /api/v1/conversations/delete
62
+ POST /api/v1/conversations/export
57
63
  GET /api/v1/resolve?ref=<url-or-deeplink>
58
64
  ```
59
65
 
60
66
  The default list selector is `last_final_answer`, which keeps `fgh --collect` style clients fast and small. Use `message_selector=all` when a client needs the full normalized thread.
61
67
 
68
+ Batch delete requires an explicit source and ID list. It returns `deletedIds`, `missingIds`, and a result for each requested ID, so partial success is represented in a `200` response body. Batch export also requires an explicit source and ID list, but is atomic: any missing ID returns an error instead of a partial archive.
69
+
62
70
  Example:
63
71
 
64
72
  ```bash
@@ -90,13 +98,13 @@ Response envelope:
90
98
  }
91
99
  ],
92
100
  "meta": {
93
- "hasNext": false,
101
+ "has_next": false,
94
102
  "next_cursor": null
95
103
  }
96
104
  }
97
105
  ```
98
106
 
99
- For serverless access from Bun, use the public client export:
107
+ For direct access from Bun scripts and CLIs, use the public client export. Local mode reads the source data without starting the TanStack server:
100
108
 
101
109
  ```ts
102
110
  import { createConversationClient } from "spiracha/client";
@@ -109,12 +117,16 @@ const page = await client.listConversations({
109
117
  });
110
118
  ```
111
119
 
120
+ Library and CLI use is quiet by default. Set `SPIRACHA_TRANSCRIPT_LOAD_LOGS=1` or
121
+ `SPIRACHA_OPENCODE_DB_LOGS=1` only when diagnosing loader or OpenCode database timing.
122
+
112
123
  ## Source Locations
113
124
 
114
125
  | Source | Default location | Primary override |
115
126
  | --- | --- | --- |
116
127
  | Codex | shared Codex DB probe list | `SPIRACHA_CODEX_DB` |
117
128
  | Claude Code | `~/.claude/projects` | `SPIRACHA_CLAUDE_CODE_PROJECTS_DIR` |
129
+ | Grok | `~/.grok/sessions` | `SPIRACHA_GROK_SESSIONS_DIR` |
118
130
  | Kiro | `~/Library/Application Support/Kiro/User/globalStorage/kiro.kiroagent/workspace-sessions` | `SPIRACHA_KIRO_WORKSPACE_SESSIONS_DIR` |
119
131
  | Qoder | `~/Library/Application Support/Qoder/User/globalStorage/state.vscdb` and `~/Library/Application Support/Qoder/User/workspaceStorage` | `SPIRACHA_QODER_GLOBAL_STATE_DB`, `SPIRACHA_QODER_WORKSPACE_STORAGE_DIR` |
120
132
  | Cursor | `~/Library/Application Support/Cursor/User` on macOS | `SPIRACHA_CURSOR_USER_DIR`, `SPIRACHA_CURSOR_PROJECTS_DIR` |
@@ -122,27 +134,38 @@ const page = await client.listConversations({
122
134
  | OpenCode | `${XDG_DATA_HOME:-~/.local/share}/opencode/opencode.db` | `SPIRACHA_OPENCODE_DB` |
123
135
  | UI exports | OS temp directory under `spiracha-ui-exports` | `SPIRACHA_UI_EXPORT_DIR` |
124
136
 
137
+ ### Qoder live ACP hydration
138
+
139
+ Qoder detail/export reads first use persisted state and CLI transcript files. When those do not contain assistant messages and Qoder is running, Spiracha can connect to Qoder's local JSON-RPC ACP Unix socket, issue `initialize` and `session/load`, and collect the streamed session updates. The default socket is the Qoder `SharedClientCache/qoder.sock`; override it with `SPIRACHA_QODER_SOCKET_PATH` (or the legacy environment spelling `SPIRACHA_QODER_SOCKET`). Connection failures and timeouts fall back to the persisted transcript rather than preventing the session from loading.
140
+
125
141
  ## UI Routes
126
142
 
127
143
  - `/codex` and `/codex/$project` for Codex inventory and project threads.
128
144
  - `/threads/$threadId` for Codex thread detail.
129
- - `/claude-code`, `/kiro`, `/qoder`, `/cursor`, `/antigravity`, and `/opencode` for source inventories.
130
- - Source detail routes include `/claude-code-sessions/$sessionId`, `/kiro-sessions/$sessionId`, `/qoder-sessions/$sessionId`, `/cursor-threads/$composerId`, `/antigravity-conversations/$conversationId`, and `/opencode-sessions/$sessionId`.
131
- - `/analytics` for Codex token and tool-call analytics.
145
+ - `/claude-code`, `/grok`, `/kiro`, `/qoder`, `/cursor`, `/antigravity`, and `/opencode` for source inventories.
146
+ - Source detail routes include `/claude-code-sessions/$sessionId`, `/grok-sessions/$sessionId`, `/kiro-sessions/$sessionId`, `/qoder-sessions/$sessionId`, `/cursor-threads/$composerId`, `/antigravity-conversations/$conversationId`, and `/opencode-sessions/$sessionId`.
147
+ - `/analytics` for project-scoped Codex token totals, average and median thread size, archive counts, tool usage, model tokens, client sources, and reasoning-effort breakdowns.
148
+ - `/settings` for transcript path conversion and username redaction. Export dialogs remember their own last submitted options.
132
149
 
133
150
  ## Development
134
151
 
135
152
  ```bash
136
- rtk bun test
137
- rtk bun run lint
138
- rtk bun run typecheck
139
- rtk bun run build
140
- rtk bun run coverage
141
- rtk bun start
142
- rtk bun run --cwd apps/ui test
153
+ bun test
154
+ bun run lint
155
+ bun run typecheck
156
+ bun run build
157
+ bun run coverage
158
+ bun start
159
+ bun run test:ui
143
160
  ```
144
161
 
145
- The UI package runs Vite through `bun --bun` because server functions import Bun-only modules such as `bun:sqlite`.
162
+ `bun run coverage` enforces at least 90% line coverage independently for the root Bun suite and the UI Vitest suite, and reports function coverage and per-file hotspots for follow-up.
163
+
164
+ Run one root test file with `bun test src/lib/shared.test.ts`. Run one UI test file with `bun run test:ui --run apps/ui/src/components/export-dialog.vitest.tsx`.
165
+
166
+ Spiracha has one package manifest. The `apps/ui` directory remains a source boundary, but all UI and direct-client commands and dependencies are owned at the repository root. Root-owned Vite commands use `apps/ui` as their internal working directory and run through `bun --bun` because TanStack server functions import Bun-only modules such as `bun:sqlite`; Vitest uses its normal Node runtime.
167
+
168
+ TanStack Router generates `apps/ui/src/routeTree.gen.ts` during development/build. Do not edit it manually; after adding or renaming route files, run `bun run build` (or start the dev server) and include the generated update.
146
169
 
147
170
  ## Breaking Consequences
148
171
 
package/apps/ui/AGENTS.md CHANGED
@@ -2,22 +2,26 @@
2
2
 
3
3
  ## Purpose
4
4
 
5
- This package is the local browser UI for Spiracha. It reads Codex, Claude Code, Kiro, Qoder, Cursor, Antigravity, and OpenCode local data through TanStack Start server functions and shared root-package helpers.
5
+ This directory is the local browser UI source tree for Spiracha. It reads Codex, Claude Code, Grok, Kiro, Qoder, Cursor, Antigravity, and OpenCode local data through TanStack Start server functions and shared root-package helpers.
6
6
 
7
7
  ## Commands
8
8
 
9
9
  ```bash
10
- rtk bun run dev
10
+ rtk bun start
11
11
  rtk bun run build
12
- rtk bun run test
12
+ rtk bun run test:ui
13
13
  rtk bun run typecheck
14
14
  rtk bun run coverage
15
15
  ```
16
16
 
17
+ Run these commands from the repository root. There is intentionally no nested UI package manifest.
18
+
17
19
  Important:
18
20
 
19
- - `dev`, `build`, and `preview` run through `bun --bun ...` on purpose. Do not switch them back to plain `vite` or Node execution, because the server functions import Bun-only modules such as `bun:sqlite`.
20
- - The root package mirrors UI runtime dependencies needed by the packaged `bunx spiracha` launcher. Keep `apps/ui/package.json` and the root `dependencies` aligned when browser/runtime dependencies change.
21
+ - `start`, `build`, and `ui:preview` run Vite through `bun --bun ...` on purpose. Do not switch them back to Node execution, because the server functions import Bun-only modules such as `bun:sqlite`.
22
+ - Those root-owned Vite scripts use `apps/ui` as their internal working directory because TanStack Start derives part of its dev-server plan from the process working directory.
23
+ - Keep UI runtime dependencies needed by the packaged `bunx spiracha` launcher in the root `dependencies`. Keep build and test tooling in the root `devDependencies`.
24
+ - Keep Vitest on its normal Node runtime; forcing it through `bun --bun` breaks test-environment module and global behavior.
21
25
 
22
26
  ## Routing
23
27
 
@@ -29,12 +33,13 @@ Important:
29
33
  - Codex project inventory and project-thread search use route search params. `/codex` and `/codex/$project` use `q`.
30
34
  - Codex analytics uses the `project` route search param so filtered analytics links can be bookmarked and reloaded.
31
35
  - Claude Code session detail lives at `/claude-code-sessions/$sessionId`.
36
+ - Grok session detail lives at `/grok-sessions/$sessionId`.
32
37
  - Kiro session detail lives at `/kiro-sessions/$sessionId`.
33
38
  - Qoder session detail lives at `/qoder-sessions/$sessionId`.
34
39
  - Cursor thread detail lives at `/cursor-threads/$composerId`.
35
40
  - Antigravity conversation detail lives at `/antigravity-conversations/$conversationId`.
36
41
  - OpenCode session detail lives at `/opencode-sessions/$sessionId`.
37
- - Keep the Codex, Claude Code, Kiro, Qoder, Cursor, Antigravity, and OpenCode list/detail pages aligned around the same table-driven index/detail pattern when adding new source integrations.
42
+ - Keep the Codex, Claude Code, Grok, Kiro, Qoder, Cursor, Antigravity, and OpenCode list/detail pages aligned around the same table-driven index/detail pattern when adding new source integrations.
38
43
 
39
44
  ## Shared Data Layer
40
45
 
@@ -48,6 +53,9 @@ The UI depends on root-package helpers via `@spiracha/*` path aliases:
48
53
  - `@spiracha/lib/claude-code-db`
49
54
  - `@spiracha/lib/claude-code-transcript-phase`
50
55
  - `@spiracha/lib/claude-code-transcript`
56
+ - `@spiracha/lib/grok-db`
57
+ - `@spiracha/lib/grok-transcript-phase`
58
+ - `@spiracha/lib/grok-transcript`
51
59
  - `@spiracha/lib/kiro-db`
52
60
  - `@spiracha/lib/kiro-transcript-phase`
53
61
  - `@spiracha/lib/kiro-transcript`
@@ -73,10 +81,10 @@ The `*-transcript-phase` helpers are intentionally browser-safe and may be impor
73
81
 
74
82
  Use the existing layers consistently:
75
83
 
76
- - TanStack Start server functions in `src/lib/codex-server.ts`, `src/lib/claude-code-server.ts`, `src/lib/kiro-server.ts`, `src/lib/qoder-server.ts`, `src/lib/cursor-server.ts`, `src/lib/antigravity-server.ts`, and `src/lib/opencode-server.ts`
84
+ - TanStack Start server functions in `src/lib/codex-server.ts`, `src/lib/claude-code-server.ts`, `src/lib/grok-server.ts`, `src/lib/kiro-server.ts`, `src/lib/qoder-server.ts`, `src/lib/cursor-server.ts`, `src/lib/antigravity-server.ts`, and `src/lib/opencode-server.ts`
77
85
  - Use for any browser-triggered read/write that needs Bun-only modules, DB access, filesystem access, Keychain access, or shared root-package helpers.
78
86
  - Use `.validator(...)` for input validation. Do not add new `.inputValidator(...)` calls.
79
- - TanStack Query query options in `src/lib/codex-queries.ts`, `src/lib/claude-code-queries.ts`, `src/lib/kiro-queries.ts`, `src/lib/qoder-queries.ts`, `src/lib/cursor-queries.ts`, `src/lib/antigravity-queries.ts`, and `src/lib/opencode-queries.ts`
87
+ - TanStack Query query options in `src/lib/codex-queries.ts`, `src/lib/claude-code-queries.ts`, `src/lib/grok-queries.ts`, `src/lib/kiro-queries.ts`, `src/lib/qoder-queries.ts`, `src/lib/cursor-queries.ts`, `src/lib/antigravity-queries.ts`, and `src/lib/opencode-queries.ts`
80
88
  - Use for client-side fetching, caching, retries, and invalidation of server-function results.
81
89
  - Shared root-package helpers under `@spiracha/lib/*`
82
90
  - Extend these when the behavior should stay shared between the UI and the stable data API.
@@ -103,7 +111,7 @@ For URL-backed route state, use `src/lib/route-search.ts` instead of ad hoc pars
103
111
  - UI component tests live under `src/**/*.vitest.tsx`.
104
112
  - Source-specific transcript adapter tests live next to their adapter files under `src/lib/*.vitest.ts`.
105
113
  - Route search parsing tests live next to the helper in `src/lib/route-search.vitest.ts`.
106
- - The root package wraps this Vitest suite from `src/ui-package.test.ts` so `rtk bun test` at the repo root exercises both the Bun suite and the UI suite.
114
+ - The root package wraps this Vitest suite from `src/ui-suite.test.ts` so `rtk bun test` exercises both the Bun suite and the UI suite.
107
115
 
108
116
  ## Design
109
117
 
@@ -113,5 +121,5 @@ For URL-backed route state, use `src/lib/route-search.ts` instead of ad hoc pars
113
121
  ## Constraints
114
122
 
115
123
  - Do not add a second database.
116
- - Do not duplicate transcript parsing or export rendering in this package.
124
+ - Do not duplicate transcript parsing or export rendering in the UI source tree.
117
125
  - Use the shared root-package helpers instead.
package/apps/ui/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Spiracha UI
2
2
 
3
- The browser UI for browsing local Codex, Claude Code, Kiro, Qoder, Cursor, Antigravity, and OpenCode history, inspecting transcript details, exporting chats, and analyzing Codex usage patterns.
3
+ The browser UI for browsing local Codex, Claude Code, Grok, Kiro, Qoder, Cursor, Antigravity, and OpenCode history, inspecting transcript details, exporting chats, and analyzing Codex usage patterns.
4
4
 
5
5
  ## Stack
6
6
 
@@ -17,10 +17,13 @@ The browser UI for browsing local Codex, Claude Code, Kiro, Qoder, Cursor, Antig
17
17
 
18
18
  - lists derived Codex projects from the Codex SQLite database
19
19
  - lists Codex threads within a project in chronological order
20
- - shows Codex thread timelines, tool calls, metadata, and raw event context
21
- - exports Codex, Claude Code, Kiro, Qoder, Cursor, and OpenCode sessions or threads as Markdown, plain text, or optional zip archives with optional metadata, commentary, and tool-call inclusion
20
+ - shows Codex thread timelines, a dedicated tool activity and definition view, recorded goals, readable sandbox policy, metadata, and raw event context
21
+ - searches Codex projects from the app shell through the URL-backed `/codex?q=...` inventory filter
22
+ - exports Codex, Claude Code, Grok, Kiro, Qoder, Cursor, and OpenCode sessions or threads as Markdown, plain text, or optional zip archives with optional metadata, commentary, and tool-call inclusion; the last submitted choices persist while canceled drafts are discarded
22
23
  - lists Claude Code workspaces and sessions from local `~/.claude/projects` JSONL files
23
24
  - shows dedicated Claude Code session detail pages with reasoning, tool calls, token metadata, and export actions
25
+ - lists Grok workspaces and sessions from local Grok session archives
26
+ - shows dedicated Grok session detail pages with compacted-history recovery, tool calls, metadata, export, and delete actions
24
27
  - lists Kiro workspaces and sessions from local Kiro workspace session files
25
28
  - shows dedicated Kiro session detail pages with image attachments, prompt logs, execution-derived tool calls, metadata, and export actions
26
29
  - lists Qoder workspaces and sessions from local Qoder history and checkpoint storage
@@ -33,26 +36,26 @@ The browser UI for browsing local Codex, Claude Code, Kiro, Qoder, Cursor, Antig
33
36
  - unlocks Antigravity transcript export through macOS Keychain and exports conversations or artifacts as Markdown
34
37
  - lists OpenCode workspaces and sessions from the local OpenCode SQLite database
35
38
  - shows dedicated OpenCode session detail pages with reasoning, tool parts, MiniMax `<think>` blocks, token metadata, and export actions
36
- - shows dashboard and analytics summaries, including Codex token totals and tool-call frequency
39
+ - shows dashboard and project-scoped Codex analytics for token totals, average and median thread size, archive counts, tool usage, model tokens, client sources, and reasoning effort
37
40
  - keeps Codex inventory search and analytics project filters in URL search params for reloadable and shareable views
38
41
  - keeps source-specific commentary hidden by default while preserving final answers, with matching export filtering for Claude Code, Kiro, Qoder, and OpenCode
39
42
 
40
43
  ## Commands
41
44
 
42
45
  ```bash
43
- rtk bun run dev
46
+ rtk bun start
44
47
  rtk bun run build
45
- rtk bun run test
48
+ rtk bun run test:ui
46
49
  rtk bun run typecheck
47
50
  ```
48
51
 
49
52
  ## Runtime Note
50
53
 
51
- This package runs `vite` through `bun --bun ...`.
54
+ Run these commands from the repository root. The UI is part of the root package and intentionally has no nested package manifest.
52
55
 
53
- That is required because the TanStack Start server functions import shared root-package modules that use Bun-only features such as `bun:sqlite`.
56
+ Root-owned Vite commands use `apps/ui` as their internal working directory and run through `bun --bun`. That is required because TanStack Start derives part of its server plan from the application directory and the server functions use Bun-only modules such as `bun:sqlite`.
54
57
 
55
- If you change the scripts back to plain `vite` or a Node execution path, the UI server functions will fail at runtime.
58
+ Vitest uses its normal Node runtime.
56
59
 
57
60
  ## Configuration
58
61
 
@@ -67,9 +70,17 @@ Runtime configuration is intentionally small:
67
70
  - `SPIRACHA_ANALYTICS_TRANSCRIPT_CONCURRENCY`
68
71
  - Optional positive integer for Codex analytics transcript parsing concurrency.
69
72
  - Defaults to `8`.
73
+ - `SPIRACHA_TRANSCRIPT_LOAD_CONCURRENCY`
74
+ - Optional positive integer for detail-page transcript loading concurrency across sources.
75
+ - Defaults to `3` and is capped at `16` to protect the server from excessive parallel disk and database work.
76
+ - `SPIRACHA_TRANSCRIPT_LOAD_LOGS`
77
+ - Set to `1` to log transcript-loader queue and timing diagnostics. Disabled by default so library and CLI consumers stay quiet.
70
78
  - `SPIRACHA_CLAUDE_CODE_PROJECTS_DIR`
71
79
  - Optional absolute path to the Claude Code projects directory.
72
80
  - If unset, Spiracha reads `${SPIRACHA_CLAUDE_CODE_DATA_DIR:-~/.claude}/projects`. `SPIRACHA_CLAUDE_CODE_DIR` and `SPIRACHA_CLAUDE_HOME` are also accepted aliases for the Claude Code data directory.
81
+ - `SPIRACHA_GROK_SESSIONS_DIR`
82
+ - Optional path to the Grok sessions directory.
83
+ - If unset, Spiracha reads `${SPIRACHA_GROK_HOME:-~/.grok}/sessions`. `SPIRACHA_GROK_DIR` is accepted as a Grok home-directory alias.
73
84
  - `SPIRACHA_KIRO_WORKSPACE_SESSIONS_DIR`
74
85
  - Optional absolute path to the Kiro workspace sessions directory.
75
86
  - If unset, Spiracha reads `${SPIRACHA_KIRO_DATA_DIR:-~/Library/Application Support/Kiro/User/globalStorage/kiro.kiroagent}/workspace-sessions`. `SPIRACHA_KIRO_AGENT_DIR` and `SPIRACHA_KIRO_DIR` are also accepted aliases for the Kiro data directory.
@@ -82,6 +93,11 @@ Runtime configuration is intentionally small:
82
93
  - `SPIRACHA_OPENCODE_DB`
83
94
  - Optional absolute path to the OpenCode SQLite database.
84
95
  - If unset, Spiracha reads `${SPIRACHA_OPENCODE_DATA_DIR:-${XDG_DATA_HOME:-~/.local/share}/opencode}/opencode.db`. `SPIRACHA_OPENCODE_DIR` is also accepted as an OpenCode data-directory alias.
96
+ - `SPIRACHA_OPENCODE_DB_CONCURRENCY`
97
+ - Optional positive integer for concurrent OpenCode database reads.
98
+ - Defaults to `2`.
99
+ - `SPIRACHA_OPENCODE_DB_LOGS`
100
+ - Set to `1` to log OpenCode database queue and timing diagnostics. Disabled by default.
85
101
  - `SPIRACHA_CURSOR_USER_DIR`
86
102
  - Optional absolute path to Cursor's `User` directory.
87
103
  - If unset, Spiracha reads the platform default Cursor user-data directory.
@@ -100,6 +116,7 @@ Default source locations:
100
116
  | --- | --- | --- |
101
117
  | Codex | shared Codex DB probe list | `SPIRACHA_CODEX_DB` |
102
118
  | Claude Code | `~/.claude/projects` | `SPIRACHA_CLAUDE_CODE_PROJECTS_DIR` |
119
+ | Grok | `~/.grok/sessions` | `SPIRACHA_GROK_SESSIONS_DIR`, `SPIRACHA_GROK_HOME` |
103
120
  | Kiro | `~/Library/Application Support/Kiro/User/globalStorage/kiro.kiroagent/workspace-sessions` | `SPIRACHA_KIRO_WORKSPACE_SESSIONS_DIR` |
104
121
  | Qoder | `~/Library/Application Support/Qoder/User/globalStorage/state.vscdb` + `~/Library/Application Support/Qoder/User/workspaceStorage` | `SPIRACHA_QODER_GLOBAL_STATE_DB`, `SPIRACHA_QODER_WORKSPACE_STORAGE_DIR` |
105
122
  | Cursor | `~/Library/Application Support/Cursor/User` on macOS | `SPIRACHA_CURSOR_USER_DIR`, `SPIRACHA_CURSOR_PROJECTS_DIR` |
@@ -109,6 +126,8 @@ Default source locations:
109
126
 
110
127
  Codex analytics cache keys are based on Codex DB row metadata instead of statting every rollout file before cache hits. That keeps large histories responsive. The tradeoff is that manual JSONL edits outside Codex do not invalidate analytics unless DB row metadata changes or the temporary UI cache is cleared.
111
128
 
129
+ The temporary UI cache is pruned opportunistically at read/write boundaries, with cleanup scans throttled to once per minute. Entries expire after 24 hours and the retained cache is capped at 256 MiB; recently accessed entries refresh their age so hot data survives eviction.
130
+
112
131
  Transcript detail pages expose the same display controls across sources: user messages, commentary, tool calls, extra events, and raw JSON. Claude Code assistant lead-ins are classified from `stop_reason`, Kiro assistant phases are classified per user turn from session and execution files, Qoder shows local prompt history plus checkpoint file operations, and OpenCode assistant phases are classified per assistant run after stripping MiniMax `<think>` blocks into commentary. OpenCode think-tag extraction preserves literal `<think>` examples inside Markdown code spans and fenced code blocks.
113
132
 
114
133
  ## Routes
@@ -125,6 +144,12 @@ Transcript detail pages expose the same display controls across sources: user me
125
144
  - Claude Code workspace session listing
126
145
  - `/claude-code-sessions/$sessionId`
127
146
  - Claude Code session detail and export
147
+ - `/grok`
148
+ - Grok workspace inventory and search
149
+ - `/grok/$workspaceKey`
150
+ - Grok workspace session listing
151
+ - `/grok-sessions/$sessionId`
152
+ - Grok session detail, export, and delete
128
153
  - `/kiro`
129
154
  - Kiro workspace inventory and search
130
155
  - `/kiro/$workspaceKey`
@@ -160,11 +185,11 @@ Transcript detail pages expose the same display controls across sources: user me
160
185
  - `/$threadId`
161
186
  - shortcut redirect to the thread detail page for pasted Codex thread UUIDs
162
187
  - `/analytics`
163
- - Codex token and tool-call analytics, with `project` as the route search param
188
+ - project-scoped Codex token, archive, tool, model, client-source, and reasoning-effort analytics, with `project` as the route search param
164
189
 
165
190
  ## Testing
166
191
 
167
192
  - UI component tests live under `src/**/*.vitest.tsx`.
168
193
  - Source-specific transcript event adapter tests live under `src/lib/*.vitest.ts`.
169
194
  - Route search parsing tests live in `src/lib/route-search.vitest.ts`.
170
- - The repo root wraps this Vitest suite from `src/ui-package.test.ts`, so `rtk bun test` at the root covers both the Bun tests and the UI tests.
195
+ - The repo root wraps this Vitest suite from `src/ui-suite.test.ts`, so `rtk bun test` at the root covers both the Bun tests and the UI tests.
@@ -0,0 +1,106 @@
1
+ import type {
2
+ CodexAnalytics,
3
+ DistributionItem,
4
+ ModelTokenSummary,
5
+ ToolUsageSummary,
6
+ } from '@spiracha/lib/codex-browser-types';
7
+ import { createColumnHelper } from '@tanstack/react-table';
8
+ import { formatNumber, formatTokens } from '#/lib/formatters';
9
+ import { DataTable } from './data-table';
10
+
11
+ const toolUsageColumnHelper = createColumnHelper<ToolUsageSummary>();
12
+ const toolUsageColumns = [
13
+ toolUsageColumnHelper.accessor('name', {
14
+ cell: (info) => <span className="font-mono text-sm">{info.getValue()}</span>,
15
+ header: 'Tool',
16
+ }),
17
+ toolUsageColumnHelper.accessor('count', {
18
+ cell: (info) => <span className="font-mono text-sm">{formatNumber(info.getValue())}</span>,
19
+ header: 'Calls',
20
+ }),
21
+ ] as const;
22
+
23
+ const modelColumnHelper = createColumnHelper<ModelTokenSummary>();
24
+ const modelColumns = [
25
+ modelColumnHelper.accessor('model', {
26
+ cell: (info) => <span className="font-mono text-sm">{info.getValue()}</span>,
27
+ header: 'Model',
28
+ }),
29
+ modelColumnHelper.accessor('threadCount', {
30
+ cell: (info) => <span className="font-mono text-sm">{formatNumber(info.getValue())}</span>,
31
+ header: 'Threads',
32
+ }),
33
+ modelColumnHelper.accessor('totalTokens', {
34
+ cell: (info) => <span className="font-mono text-sm">{formatTokens(info.getValue())}</span>,
35
+ header: 'Tokens',
36
+ }),
37
+ ] as const;
38
+
39
+ const distributionColumnHelper = createColumnHelper<DistributionItem>();
40
+ const distributionColumns = [
41
+ distributionColumnHelper.accessor('label', {
42
+ cell: (info) => <span className="font-mono text-sm">{info.getValue()}</span>,
43
+ header: 'Value',
44
+ }),
45
+ distributionColumnHelper.accessor('count', {
46
+ cell: (info) => <span className="font-mono text-sm">{formatNumber(info.getValue())}</span>,
47
+ header: 'Threads',
48
+ }),
49
+ ] as const;
50
+
51
+ type AnalyticsBreakdownsProps = Pick<CodexAnalytics, 'modelsByTokens' | 'reasoningEfforts' | 'sources' | 'toolUsage'>;
52
+
53
+ export const AnalyticsBreakdowns = ({
54
+ modelsByTokens,
55
+ reasoningEfforts,
56
+ sources,
57
+ toolUsage,
58
+ }: AnalyticsBreakdownsProps) => {
59
+ return (
60
+ <div className="grid gap-6 xl:grid-cols-2">
61
+ <section className="space-y-4">
62
+ <div>
63
+ <h3 className="font-semibold text-sm">Most frequent tool calls</h3>
64
+ <p className="mt-1 text-[var(--muted-foreground)] text-sm">
65
+ Useful for future prompt and tool optimization work.
66
+ </p>
67
+ </div>
68
+ <DataTable columns={toolUsageColumns} data={toolUsage} emptyMessage="No tool calls recorded." />
69
+ </section>
70
+
71
+ <section className="space-y-4">
72
+ <div>
73
+ <h3 className="font-semibold text-sm">Model token breakdown</h3>
74
+ <p className="mt-1 text-[var(--muted-foreground)] text-sm">
75
+ Compare model usage and token concentration within the current project scope.
76
+ </p>
77
+ </div>
78
+ <DataTable columns={modelColumns} data={modelsByTokens} emptyMessage="No model usage recorded." />
79
+ </section>
80
+
81
+ <section className="space-y-4">
82
+ <div>
83
+ <h3 className="font-semibold text-sm">Client source breakdown</h3>
84
+ <p className="mt-1 text-[var(--muted-foreground)] text-sm">
85
+ See which Codex clients created threads in the current scope.
86
+ </p>
87
+ </div>
88
+ <DataTable columns={distributionColumns} data={sources} emptyMessage="No client sources recorded." />
89
+ </section>
90
+
91
+ <section className="space-y-4">
92
+ <div>
93
+ <h3 className="font-semibold text-sm">Reasoning effort breakdown</h3>
94
+ <p className="mt-1 text-[var(--muted-foreground)] text-sm">
95
+ Compare configured reasoning effort across threads.
96
+ </p>
97
+ </div>
98
+ <DataTable
99
+ columns={distributionColumns}
100
+ data={reasoningEfforts}
101
+ emptyMessage="No reasoning effort recorded."
102
+ />
103
+ </section>
104
+ </div>
105
+ );
106
+ };