Skip to content
Open
40 changes: 37 additions & 3 deletions src-tauri/src/bin/codex_monitor_daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,13 @@ use shared::process_core::kill_child_process_tree;
use shared::prompts_core::{self, CustomPromptEntry};
use shared::{
agents_config_core, codex_aux_core, codex_core, files_core, git_core, git_ui_core,
local_usage_core, settings_core, workspaces_core, worktree_core,
local_usage_core, settings_core, thread_usage_core, workspaces_core, worktree_core,
};
use storage::{read_settings, read_workspaces};
use types::{
AppSettings, GitCommitDiff, GitFileDiff, GitHubIssuesResponse, GitHubPullRequestComment,
GitHubPullRequestDiff, GitHubPullRequestsResponse, GitLogResponse, LocalUsageSnapshot,
WorkspaceEntry, WorkspaceInfo, WorkspaceSettings, WorktreeSetupStatus,
GitHubPullRequestDiff, GitHubPullRequestsResponse, GitLogResponse, LocalThreadUsageSnapshot,
LocalUsageSnapshot, WorkspaceEntry, WorkspaceInfo, WorkspaceSettings, WorktreeSetupStatus,
};
use workspace_settings::apply_workspace_settings_update;

Expand Down Expand Up @@ -1325,6 +1325,19 @@ impl DaemonState {
local_usage_core::local_usage_snapshot_core(&self.workspaces, days, workspace_path).await
}

async fn local_thread_usage_snapshot(
&self,
thread_ids: Vec<String>,
workspace_path: Option<String>,
) -> Result<LocalThreadUsageSnapshot, String> {
thread_usage_core::local_thread_usage_snapshot_core(
&self.workspaces,
thread_ids,
workspace_path,
)
.await
}

async fn menu_set_accelerators(&self, _updates: Vec<Value>) -> Result<(), String> {
// Daemon has no native menu runtime; treat as no-op for remote parity.
Ok(())
Expand Down Expand Up @@ -1754,6 +1767,27 @@ mod tests {
});
}

#[test]
fn rpc_local_thread_usage_snapshot_returns_snapshot_shape() {
run_async_test(async {
let tmp = make_temp_dir("rpc-local-thread-usage");
let state = test_state(&tmp);

let result = rpc::handle_rpc_request(
&state,
"local_thread_usage_snapshot",
json!({ "threadIds": ["thread-1"] }),
"daemon-test".to_string(),
)
.await
.expect("local_thread_usage_snapshot should succeed");

assert!(result.get("updatedAt").and_then(Value::as_i64).is_some());
assert!(result.get("usageByThread").and_then(Value::as_object).is_some());
let _ = std::fs::remove_dir_all(&tmp);
});
}

#[test]
fn rpc_daemon_info_reports_identity() {
run_async_test(async {
Expand Down
8 changes: 8 additions & 0 deletions src-tauri/src/bin/codex_monitor_daemon/rpc/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,14 @@ pub(super) async fn try_handle(
let workspace_path = parse_optional_string(params, "workspacePath");
Some(serialize_result(state.local_usage_snapshot(days, workspace_path)).await)
}
"local_thread_usage_snapshot" => {
let thread_ids = parse_optional_string_array(params, "threadIds").unwrap_or_default();
let workspace_path = parse_optional_string(params, "workspacePath");
Some(
serialize_result(state.local_thread_usage_snapshot(thread_ids, workspace_path))
.await,
)
}
_ => None,
}
}
2 changes: 2 additions & 0 deletions src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod files;
mod git;
mod git_utils;
mod local_usage;
mod local_thread_usage;
#[cfg(desktop)]
mod menu;
#[cfg(not(desktop))]
Expand Down Expand Up @@ -286,6 +287,7 @@ pub fn run() {
dictation::dictation_stop,
dictation::dictation_cancel,
local_usage::local_usage_snapshot,
local_thread_usage::local_thread_usage_snapshot,
notifications::is_macos_debug_build,
notifications::app_build_type,
notifications::send_notification_fallback,
Expand Down
33 changes: 33 additions & 0 deletions src-tauri/src/local_thread_usage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use serde_json::json;
use tauri::{AppHandle, State};

use crate::remote_backend;
use crate::shared::thread_usage_core;
use crate::state::AppState;
use crate::types::LocalThreadUsageSnapshot;

#[tauri::command]
pub(crate) async fn local_thread_usage_snapshot(
thread_ids: Vec<String>,
workspace_path: Option<String>,
state: State<'_, AppState>,
app: AppHandle,
) -> Result<LocalThreadUsageSnapshot, String> {
if remote_backend::is_remote_mode(&*state).await {
let response = remote_backend::call_remote(
&*state,
app,
"local_thread_usage_snapshot",
json!({ "threadIds": thread_ids, "workspacePath": workspace_path }),
)
.await?;
return serde_json::from_value(response).map_err(|err| err.to_string());
}

thread_usage_core::local_thread_usage_snapshot_core(
&state.workspaces,
thread_ids,
workspace_path,
)
.await
}
2 changes: 2 additions & 0 deletions src-tauri/src/remote_backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ fn can_retry_after_disconnect(method: &str) -> bool {
| "list_mcp_server_status"
| "list_threads"
| "local_usage_snapshot"
| "local_thread_usage_snapshot"
| "list_workspace_files"
| "list_workspaces"
| "model_list"
Expand Down Expand Up @@ -266,6 +267,7 @@ mod tests {
assert!(can_retry_after_disconnect("resume_thread"));
assert!(can_retry_after_disconnect("list_threads"));
assert!(can_retry_after_disconnect("local_usage_snapshot"));
assert!(can_retry_after_disconnect("local_thread_usage_snapshot"));
assert!(!can_retry_after_disconnect("send_user_message"));
assert!(!can_retry_after_disconnect("start_thread"));
assert!(!can_retry_after_disconnect("remove_workspace"));
Expand Down
1 change: 1 addition & 0 deletions src-tauri/src/shared/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub(crate) mod git_core;
pub(crate) mod git_rpc;
pub(crate) mod git_ui_core;
pub(crate) mod local_usage_core;
pub(crate) mod thread_usage_core;
pub(crate) mod process_core;
pub(crate) mod prompts_core;
pub(crate) mod settings_core;
Expand Down
Loading
Loading