Skip to content

Commit 879da2f

Browse files
committed
add: usage analysis status
1 parent 4c954b9 commit 879da2f

File tree

9 files changed

+917
-7
lines changed

9 files changed

+917
-7
lines changed

bun.lock

Lines changed: 89 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313
"@radix-ui/react-dialog": "^1.1.14",
1414
"@radix-ui/react-dropdown-menu": "^2.1.15",
1515
"@radix-ui/react-popover": "^1.1.15",
16+
"@radix-ui/react-progress": "^1.1.7",
1617
"@radix-ui/react-slot": "^1.2.3",
17-
"@radix-ui/react-tabs": "^1.1.12",
18+
"@radix-ui/react-tabs": "^1.1.13",
1819
"@radix-ui/react-tooltip": "^1.2.8",
1920
"@tailwindcss/vite": "^4.1.11",
2021
"@tauri-apps/api": "^2",
@@ -37,6 +38,7 @@
3738
"react-rnd": "^10.5.2",
3839
"react-router-dom": "^7.8.0",
3940
"react-syntax-highlighter": "^15.6.1",
41+
"recharts": "^3.1.2",
4042
"rehype-highlight": "^7.0.2",
4143
"rehype-prism-plus": "^2.0.1",
4244
"rehype-shiki": "^0.0.9",

src-tauri/src/commands.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::protocol::CodexConfig;
22
use crate::services::{codex, session};
33
use crate::state::CodexState;
44
use tauri::{AppHandle, State};
5+
use std::fs;
56

67
// Re-export types for external use
78
pub use crate::services::session::Conversation;
@@ -75,3 +76,66 @@ pub async fn delete_session_file(file_path: String) -> Result<(), String> {
7576
pub async fn get_latest_session_id() -> Result<Option<String>, String> {
7677
session::get_latest_session_id().await
7778
}
79+
80+
#[tauri::command]
81+
pub async fn get_session_files() -> Result<Vec<String>, String> {
82+
let home = dirs::home_dir().ok_or("Could not find home directory")?;
83+
let sessions_dir = home.join(".codex").join("sessions");
84+
85+
if !sessions_dir.exists() {
86+
return Ok(vec![]);
87+
}
88+
89+
let mut session_files = Vec::new();
90+
91+
// Walk through year/month/day directories
92+
if let Ok(entries) = fs::read_dir(&sessions_dir) {
93+
for entry in entries.flatten() {
94+
if entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false) {
95+
let year_path = entry.path();
96+
if let Ok(month_entries) = fs::read_dir(&year_path) {
97+
for month_entry in month_entries.flatten() {
98+
if month_entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false) {
99+
let month_path = month_entry.path();
100+
if let Ok(day_entries) = fs::read_dir(&month_path) {
101+
for day_entry in day_entries.flatten() {
102+
if day_entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false) {
103+
let day_path = day_entry.path();
104+
if let Ok(file_entries) = fs::read_dir(&day_path) {
105+
for file_entry in file_entries.flatten() {
106+
if let Some(filename) = file_entry.file_name().to_str() {
107+
if filename.ends_with(".jsonl") {
108+
session_files.push(file_entry.path().to_string_lossy().to_string());
109+
}
110+
}
111+
}
112+
}
113+
}
114+
}
115+
}
116+
}
117+
}
118+
}
119+
}
120+
}
121+
}
122+
123+
Ok(session_files)
124+
}
125+
126+
#[tauri::command]
127+
pub async fn read_session_file(file_path: String) -> Result<String, String> {
128+
fs::read_to_string(&file_path).map_err(|e| format!("Failed to read session file: {}", e))
129+
}
130+
131+
#[tauri::command]
132+
pub async fn read_history_file() -> Result<String, String> {
133+
let home = dirs::home_dir().ok_or("Could not find home directory")?;
134+
let history_path = home.join(".codex").join("history.jsonl");
135+
136+
if !history_path.exists() {
137+
return Ok(String::new());
138+
}
139+
140+
fs::read_to_string(&history_path).map_err(|e| format!("Failed to read history file: {}", e))
141+
}

src-tauri/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ mod utils;
99

1010
use commands::{
1111
approve_execution, check_codex_version, close_session, delete_session_file,
12-
get_latest_session_id, get_running_sessions, load_sessions_from_disk, pause_session, send_message,
13-
start_codex_session, stop_session,
12+
get_latest_session_id, get_running_sessions, get_session_files, read_session_file, read_history_file,
13+
load_sessions_from_disk, pause_session, send_message, start_codex_session, stop_session,
1414
};
1515
use config::{
1616
add_mcp_server, add_or_update_model_provider, add_or_update_profile, delete_mcp_server,
@@ -60,6 +60,9 @@ pub fn run() {
6060
load_sessions_from_disk,
6161
delete_session_file,
6262
get_latest_session_id,
63+
get_session_files,
64+
read_session_file,
65+
read_history_file,
6366
check_codex_version,
6467
read_directory,
6568
get_default_directories,

src/App.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import ChatPage from "@/pages/chat";
55
import ProjectsPage from "@/pages/projects";
66
import DxtPage from "./pages/dxt";
77
import SettingsPage from "./pages/settings";
8+
import UsagePage from "./pages/usage";
89
import { useLayoutStore } from "./stores/layoutStore";
910
import "./App.css";
1011

@@ -32,6 +33,10 @@ export default function App() {
3233
path: "settings",
3334
element: <SettingsPage />,
3435
},
36+
{
37+
path: "usage",
38+
element: <UsagePage />,
39+
},
3540
],
3641
},
3742
]);

src/components/layout/AppHeader.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PartyPopper, Usb, PanelLeft, Settings, MessageCircleCode } from "lucide-react";
1+
import { PartyPopper, Usb, PanelLeft, Settings, MessageCircleCode, BarChart3 } from "lucide-react";
22
import { Button } from "@/components/ui/button";
33
import { Badge } from "@/components/ui/badge";
44
import { Link, useLocation } from "react-router-dom";
@@ -44,6 +44,10 @@ export function AppHeader() {
4444
<MessageCircleCode className="w-5 h-5" />
4545
</Link>
4646

47+
<Link to="/usage" className="hover:text-blue-500">
48+
<BarChart3 className="w-5 h-5" />
49+
</Link>
50+
4751
{location.pathname === "/chat" && (
4852
<Button
4953
variant="ghost"

src/components/ui/progress.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as React from "react"
2+
import * as ProgressPrimitive from "@radix-ui/react-progress"
3+
4+
import { cn } from "@/lib/utils"
5+
6+
function Progress({
7+
className,
8+
value,
9+
...props
10+
}: React.ComponentProps<typeof ProgressPrimitive.Root>) {
11+
return (
12+
<ProgressPrimitive.Root
13+
data-slot="progress"
14+
className={cn(
15+
"bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
16+
className
17+
)}
18+
{...props}
19+
>
20+
<ProgressPrimitive.Indicator
21+
data-slot="progress-indicator"
22+
className="bg-primary h-full w-full flex-1 transition-all"
23+
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
24+
/>
25+
</ProgressPrimitive.Root>
26+
)
27+
}
28+
29+
export { Progress }

0 commit comments

Comments
 (0)