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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions assets/keymaps/default-linux.json
Original file line number Diff line number Diff line change
Expand Up @@ -1288,5 +1288,13 @@
"home": "settings_editor::FocusFirstNavEntry",
"end": "settings_editor::FocusLastNavEntry"
}
},
{
"context": "Zeta2Feedback > Editor",
"bindings": {
"enter": "editor::Newline",
"ctrl-enter up": "dev::Zeta2RatePredictionPositive",
"ctrl-enter down": "dev::Zeta2RatePredictionNegative"
}
}
]
8 changes: 8 additions & 0 deletions assets/keymaps/default-macos.json
Original file line number Diff line number Diff line change
Expand Up @@ -1394,5 +1394,13 @@
"home": "settings_editor::FocusFirstNavEntry",
"end": "settings_editor::FocusLastNavEntry"
}
},
{
"context": "Zeta2Feedback > Editor",
"bindings": {
"enter": "editor::Newline",
"cmd-enter up": "dev::Zeta2RatePredictionPositive",
"cmd-enter down": "dev::Zeta2RatePredictionNegative"
}
}
]
8 changes: 8 additions & 0 deletions assets/keymaps/default-windows.json
Original file line number Diff line number Diff line change
Expand Up @@ -1317,5 +1317,13 @@
"home": "settings_editor::FocusFirstNavEntry",
"end": "settings_editor::FocusLastNavEntry"
}
},
{
"context": "Zeta2Feedback > Editor",
"bindings": {
"enter": "editor::Newline",
"ctrl-enter up": "dev::Zeta2RatePredictionPositive",
"ctrl-enter down": "dev::Zeta2RatePredictionNegative"
}
}
]
16 changes: 1 addition & 15 deletions crates/agent/src/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,10 @@ use util::rel_path::RelPath;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ProjectSnapshot {
pub worktree_snapshots: Vec<WorktreeSnapshot>,
pub worktree_snapshots: Vec<project::telemetry_snapshot::TelemetryWorktreeSnapshot>,
pub timestamp: DateTime<Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct WorktreeSnapshot {
pub worktree_path: String,
pub git_state: Option<GitState>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct GitState {
pub remote_url: Option<String>,
pub head_sha: Option<String>,
pub current_branch: Option<String>,
pub diff: Option<String>,
}

const RULES_FILE_NAMES: [&str; 9] = [
".rules",
".cursorrules",
Expand Down
99 changes: 5 additions & 94 deletions crates/agent/src/thread.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use crate::{
ContextServerRegistry, CopyPathTool, CreateDirectoryTool, DbLanguageModel, DbThread,
DeletePathTool, DiagnosticsTool, EditFileTool, FetchTool, FindPathTool, GitState, GrepTool,
DeletePathTool, DiagnosticsTool, EditFileTool, FetchTool, FindPathTool, GrepTool,
ListDirectoryTool, MovePathTool, NowTool, OpenTool, ProjectSnapshot, ReadFileTool,
SystemPromptTemplate, Template, Templates, TerminalTool, ThinkingTool, WebSearchTool,
WorktreeSnapshot,
};
use acp_thread::{MentionUri, UserMessageId};
use action_log::ActionLog;
Expand All @@ -26,7 +25,6 @@ use futures::{
future::Shared,
stream::FuturesUnordered,
};
use git::repository::DiffType;
use gpui::{
App, AppContext, AsyncApp, Context, Entity, EventEmitter, SharedString, Task, WeakEntity,
};
Expand All @@ -37,10 +35,7 @@ use language_model::{
LanguageModelToolResultContent, LanguageModelToolSchemaFormat, LanguageModelToolUse,
LanguageModelToolUseId, Role, SelectedModel, StopReason, TokenUsage, ZED_CLOUD_PROVIDER_ID,
};
use project::{
Project,
git_store::{GitStore, RepositoryState},
};
use project::Project;
use prompt_store::ProjectContext;
use schemars::{JsonSchema, Schema};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -880,101 +875,17 @@ impl Thread {
project: Entity<Project>,
cx: &mut Context<Self>,
) -> Task<Arc<ProjectSnapshot>> {
let git_store = project.read(cx).git_store().clone();
let worktree_snapshots: Vec<_> = project
.read(cx)
.visible_worktrees(cx)
.map(|worktree| Self::worktree_snapshot(worktree, git_store.clone(), cx))
.collect();

let task = project::telemetry_snapshot::TelemetrySnapshot::new(&project, cx);
cx.spawn(async move |_, _| {
let worktree_snapshots = futures::future::join_all(worktree_snapshots).await;
let snapshot = task.await;

Arc::new(ProjectSnapshot {
worktree_snapshots,
worktree_snapshots: snapshot.worktree_snapshots,
timestamp: Utc::now(),
})
})
}

fn worktree_snapshot(
worktree: Entity<project::Worktree>,
git_store: Entity<GitStore>,
cx: &App,
) -> Task<WorktreeSnapshot> {
cx.spawn(async move |cx| {
// Get worktree path and snapshot
let worktree_info = cx.update(|app_cx| {
let worktree = worktree.read(app_cx);
let path = worktree.abs_path().to_string_lossy().into_owned();
let snapshot = worktree.snapshot();
(path, snapshot)
});

let Ok((worktree_path, _snapshot)) = worktree_info else {
return WorktreeSnapshot {
worktree_path: String::new(),
git_state: None,
};
};

let git_state = git_store
.update(cx, |git_store, cx| {
git_store
.repositories()
.values()
.find(|repo| {
repo.read(cx)
.abs_path_to_repo_path(&worktree.read(cx).abs_path())
.is_some()
})
.cloned()
})
.ok()
.flatten()
.map(|repo| {
repo.update(cx, |repo, _| {
let current_branch =
repo.branch.as_ref().map(|branch| branch.name().to_owned());
repo.send_job(None, |state, _| async move {
let RepositoryState::Local { backend, .. } = state else {
return GitState {
remote_url: None,
head_sha: None,
current_branch,
diff: None,
};
};

let remote_url = backend.remote_url("origin");
let head_sha = backend.head_sha().await;
let diff = backend.diff(DiffType::HeadToWorktree).await.ok();

GitState {
remote_url,
head_sha,
current_branch,
diff,
}
})
})
});

let git_state = match git_state {
Some(git_state) => match git_state.ok() {
Some(git_state) => git_state.await.ok(),
None => None,
},
None => None,
};

WorktreeSnapshot {
worktree_path,
git_state,
}
})
}

pub fn project_context(&self) -> &Entity<ProjectContext> {
&self.project_context
}
Expand Down
1 change: 1 addition & 0 deletions crates/project/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub mod project_settings;
pub mod search;
mod task_inventory;
pub mod task_store;
pub mod telemetry_snapshot;
pub mod terminals;
pub mod toolchain_store;
pub mod worktree_store;
Expand Down
125 changes: 125 additions & 0 deletions crates/project/src/telemetry_snapshot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
use git::repository::DiffType;
use gpui::{App, Entity, Task};
use serde::{Deserialize, Serialize};
use worktree::Worktree;

use crate::{
Project,
git_store::{GitStore, RepositoryState},
};

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TelemetrySnapshot {
pub worktree_snapshots: Vec<TelemetryWorktreeSnapshot>,
}

impl TelemetrySnapshot {
pub fn new(project: &Entity<Project>, cx: &mut App) -> Task<TelemetrySnapshot> {
let git_store = project.read(cx).git_store().clone();
let worktree_snapshots: Vec<_> = project
.read(cx)
.visible_worktrees(cx)
.map(|worktree| TelemetryWorktreeSnapshot::new(worktree, git_store.clone(), cx))
.collect();

cx.spawn(async move |_| {
let worktree_snapshots = futures::future::join_all(worktree_snapshots).await;

Self { worktree_snapshots }
})
}
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct TelemetryWorktreeSnapshot {
pub worktree_path: String,
pub git_state: Option<GitState>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct GitState {
pub remote_url: Option<String>,
pub head_sha: Option<String>,
pub current_branch: Option<String>,
pub diff: Option<String>,
}

impl TelemetryWorktreeSnapshot {
fn new(
worktree: Entity<Worktree>,
git_store: Entity<GitStore>,
cx: &App,
) -> Task<TelemetryWorktreeSnapshot> {
cx.spawn(async move |cx| {
// Get worktree path and snapshot
let worktree_info = cx.update(|app_cx| {
let worktree = worktree.read(app_cx);
let path = worktree.abs_path().to_string_lossy().into_owned();
let snapshot = worktree.snapshot();
(path, snapshot)
});

let Ok((worktree_path, _snapshot)) = worktree_info else {
return TelemetryWorktreeSnapshot {
worktree_path: String::new(),
git_state: None,
};
};

let git_state = git_store
.update(cx, |git_store, cx| {
git_store
.repositories()
.values()
.find(|repo| {
repo.read(cx)
.abs_path_to_repo_path(&worktree.read(cx).abs_path())
.is_some()
})
.cloned()
})
.ok()
.flatten()
.map(|repo| {
repo.update(cx, |repo, _| {
let current_branch =
repo.branch.as_ref().map(|branch| branch.name().to_owned());
repo.send_job(None, |state, _| async move {
let RepositoryState::Local { backend, .. } = state else {
return GitState {
remote_url: None,
head_sha: None,
current_branch,
diff: None,
};
};

let remote_url = backend.remote_url("origin");
let head_sha = backend.head_sha().await;
let diff = backend.diff(DiffType::HeadToWorktree).await.ok();

GitState {
remote_url,
head_sha,
current_branch,
diff,
}
})
})
});

let git_state = match git_state {
Some(git_state) => match git_state.ok() {
Some(git_state) => git_state.await.ok(),
None => None,
},
None => None,
};

TelemetryWorktreeSnapshot {
worktree_path,
git_state,
}
})
}
}
Loading
Loading