mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-04-24 13:08:13 +08:00
feat: preserve custom ecc2 harness labels
This commit is contained in:
parent
bcd869d520
commit
4a1f3cbd3f
@ -1230,8 +1230,8 @@ async fn main() -> Result<()> {
|
|||||||
for s in sessions {
|
for s in sessions {
|
||||||
let harness = harnesses
|
let harness = harnesses
|
||||||
.get(&s.id)
|
.get(&s.id)
|
||||||
.map(|info| info.primary.to_string())
|
.map(|info| info.primary_label.clone())
|
||||||
.unwrap_or_else(|| "unknown".to_string());
|
.unwrap_or_else(|| session::SessionHarnessInfo::runner_key(&s.agent_type));
|
||||||
println!("{} [{}] [{}] {}", s.id, s.state, harness, s.task);
|
println!("{} [{}] [{}] {}", s.id, s.state, harness, s.task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2004,10 +2004,11 @@ pub async fn delete_session(db: &StateStore, id: &str) -> Result<()> {
|
|||||||
|
|
||||||
fn agent_program(cfg: &Config, agent_type: &str) -> Result<PathBuf> {
|
fn agent_program(cfg: &Config, agent_type: &str) -> Result<PathBuf> {
|
||||||
let harness = HarnessKind::from_agent_type(agent_type);
|
let harness = HarnessKind::from_agent_type(agent_type);
|
||||||
if let Some(runner) = cfg.harness_runner(harness.as_str()) {
|
let runner_key = SessionHarnessInfo::runner_key(agent_type);
|
||||||
|
if let Some(runner) = cfg.harness_runner(&runner_key) {
|
||||||
let program = runner.program.trim();
|
let program = runner.program.trim();
|
||||||
if program.is_empty() {
|
if program.is_empty() {
|
||||||
anyhow::bail!("Configured harness runner for {harness} is missing a program");
|
anyhow::bail!("Configured harness runner for {runner_key} is missing a program");
|
||||||
}
|
}
|
||||||
return Ok(PathBuf::from(program));
|
return Ok(PathBuf::from(program));
|
||||||
}
|
}
|
||||||
@ -2685,7 +2686,7 @@ fn build_agent_command(
|
|||||||
profile: Option<&SessionAgentProfile>,
|
profile: Option<&SessionAgentProfile>,
|
||||||
) -> Command {
|
) -> Command {
|
||||||
let harness = HarnessKind::from_agent_type(agent_type);
|
let harness = HarnessKind::from_agent_type(agent_type);
|
||||||
if let Some(runner) = cfg.harness_runner(harness.as_str()) {
|
if let Some(runner) = cfg.harness_runner(&SessionHarnessInfo::runner_key(agent_type)) {
|
||||||
return build_configured_harness_command(
|
return build_configured_harness_command(
|
||||||
runner,
|
runner,
|
||||||
agent_program,
|
agent_program,
|
||||||
@ -3327,7 +3328,7 @@ impl fmt::Display for SessionStatus {
|
|||||||
writeln!(f, "Session: {}", s.id)?;
|
writeln!(f, "Session: {}", s.id)?;
|
||||||
writeln!(f, "Task: {}", s.task)?;
|
writeln!(f, "Task: {}", s.task)?;
|
||||||
writeln!(f, "Agent: {}", s.agent_type)?;
|
writeln!(f, "Agent: {}", s.agent_type)?;
|
||||||
writeln!(f, "Harness: {}", self.harness.primary)?;
|
writeln!(f, "Harness: {}", self.harness.primary_label)?;
|
||||||
writeln!(f, "Detected: {}", self.harness.detected_summary())?;
|
writeln!(f, "Detected: {}", self.harness.detected_summary())?;
|
||||||
writeln!(f, "State: {}", s.state)?;
|
writeln!(f, "State: {}", s.state)?;
|
||||||
if let Some(profile) = self.profile.as_ref() {
|
if let Some(profile) = self.profile.as_ref() {
|
||||||
@ -3880,6 +3881,24 @@ mod tests {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn agent_program_uses_configured_runner_for_unknown_custom_harness() -> Result<()> {
|
||||||
|
let mut cfg = Config::default();
|
||||||
|
cfg.harness_runners.insert(
|
||||||
|
"acme-runner".to_string(),
|
||||||
|
crate::config::HarnessRunnerConfig {
|
||||||
|
program: "acme-agent".to_string(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
agent_program(&cfg, "acme-runner")?,
|
||||||
|
PathBuf::from("acme-agent")
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn build_agent_command_uses_configured_runner_for_cursor() {
|
fn build_agent_command_uses_configured_runner_for_cursor() {
|
||||||
let mut cfg = Config::default();
|
let mut cfg = Config::default();
|
||||||
|
|||||||
@ -109,11 +109,38 @@ impl fmt::Display for HarnessKind {
|
|||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
pub struct SessionHarnessInfo {
|
pub struct SessionHarnessInfo {
|
||||||
pub primary: HarnessKind,
|
pub primary: HarnessKind,
|
||||||
|
pub primary_label: String,
|
||||||
pub detected: Vec<HarnessKind>,
|
pub detected: Vec<HarnessKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SessionHarnessInfo {
|
impl SessionHarnessInfo {
|
||||||
|
pub fn runner_key(agent_type: &str) -> String {
|
||||||
|
let canonical = HarnessKind::canonical_agent_type(agent_type);
|
||||||
|
match HarnessKind::from_agent_type(&canonical) {
|
||||||
|
HarnessKind::Unknown if canonical.is_empty() => {
|
||||||
|
HarnessKind::Unknown.as_str().to_string()
|
||||||
|
}
|
||||||
|
HarnessKind::Unknown => canonical,
|
||||||
|
harness => harness.as_str().to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn primary_label_for(agent_type: &str, primary: HarnessKind) -> String {
|
||||||
|
match primary {
|
||||||
|
HarnessKind::Unknown => {
|
||||||
|
let label = Self::runner_key(agent_type);
|
||||||
|
if label.is_empty() {
|
||||||
|
HarnessKind::Unknown.as_str().to_string()
|
||||||
|
} else {
|
||||||
|
label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
harness => harness.as_str().to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn detect(agent_type: &str, working_dir: &Path) -> Self {
|
pub fn detect(agent_type: &str, working_dir: &Path) -> Self {
|
||||||
|
let runner_key = Self::runner_key(agent_type);
|
||||||
let detected = [
|
let detected = [
|
||||||
HarnessKind::Claude,
|
HarnessKind::Claude,
|
||||||
HarnessKind::Codex,
|
HarnessKind::Codex,
|
||||||
@ -132,12 +159,43 @@ impl SessionHarnessInfo {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let primary = match HarnessKind::from_agent_type(agent_type) {
|
let primary = match HarnessKind::from_agent_type(&runner_key) {
|
||||||
HarnessKind::Unknown => detected.first().copied().unwrap_or(HarnessKind::Unknown),
|
HarnessKind::Unknown if runner_key == HarnessKind::Unknown.as_str() => {
|
||||||
|
detected.first().copied().unwrap_or(HarnessKind::Unknown)
|
||||||
|
}
|
||||||
|
HarnessKind::Unknown => HarnessKind::Unknown,
|
||||||
harness => harness,
|
harness => harness,
|
||||||
};
|
};
|
||||||
|
|
||||||
Self { primary, detected }
|
Self {
|
||||||
|
primary,
|
||||||
|
primary_label: Self::primary_label_for(agent_type, primary),
|
||||||
|
detected,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_persisted(
|
||||||
|
harness_label: &str,
|
||||||
|
agent_type: &str,
|
||||||
|
working_dir: &Path,
|
||||||
|
detected: Vec<HarnessKind>,
|
||||||
|
) -> Self {
|
||||||
|
let primary = HarnessKind::from_db_value(harness_label);
|
||||||
|
if primary == HarnessKind::Unknown && detected.is_empty() && harness_label.trim().is_empty()
|
||||||
|
{
|
||||||
|
return Self::detect(agent_type, working_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
let normalized_label = harness_label.trim().to_ascii_lowercase();
|
||||||
|
Self {
|
||||||
|
primary,
|
||||||
|
primary_label: if normalized_label.is_empty() {
|
||||||
|
Self::primary_label_for(agent_type, primary)
|
||||||
|
} else {
|
||||||
|
normalized_label
|
||||||
|
},
|
||||||
|
detected,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn detected_summary(&self) -> String {
|
pub fn detected_summary(&self) -> String {
|
||||||
@ -510,6 +568,7 @@ mod tests {
|
|||||||
|
|
||||||
let harness = SessionHarnessInfo::detect("claude", repo.path());
|
let harness = SessionHarnessInfo::detect("claude", repo.path());
|
||||||
assert_eq!(harness.primary, HarnessKind::Claude);
|
assert_eq!(harness.primary, HarnessKind::Claude);
|
||||||
|
assert_eq!(harness.primary_label, "claude");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
harness.detected,
|
harness.detected,
|
||||||
vec![HarnessKind::Claude, HarnessKind::Codex]
|
vec![HarnessKind::Claude, HarnessKind::Codex]
|
||||||
@ -519,13 +578,14 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn detect_session_harness_falls_back_to_project_markers_for_unknown_agent(
|
fn detect_session_harness_falls_back_to_project_markers_when_agent_unspecified(
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let repo = TestDir::new("session-harness-markers")?;
|
let repo = TestDir::new("session-harness-markers")?;
|
||||||
fs::create_dir_all(repo.path().join(".gemini"))?;
|
fs::create_dir_all(repo.path().join(".gemini"))?;
|
||||||
|
|
||||||
let harness = SessionHarnessInfo::detect("custom-runner", repo.path());
|
let harness = SessionHarnessInfo::detect("", repo.path());
|
||||||
assert_eq!(harness.primary, HarnessKind::Gemini);
|
assert_eq!(harness.primary, HarnessKind::Gemini);
|
||||||
|
assert_eq!(harness.primary_label, "gemini");
|
||||||
assert_eq!(harness.detected, vec![HarnessKind::Gemini]);
|
assert_eq!(harness.detected, vec![HarnessKind::Gemini]);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -543,4 +603,38 @@ mod tests {
|
|||||||
"custom-runner"
|
"custom-runner"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn detect_session_harness_preserves_custom_agent_label_without_markers() {
|
||||||
|
let harness = SessionHarnessInfo::detect(" custom-runner ", Path::new("."));
|
||||||
|
assert_eq!(harness.primary, HarnessKind::Unknown);
|
||||||
|
assert_eq!(harness.primary_label, "custom-runner");
|
||||||
|
assert!(harness.detected.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn detect_session_harness_preserves_custom_agent_label_with_project_markers(
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let repo = TestDir::new("session-harness-custom-markers")?;
|
||||||
|
fs::create_dir_all(repo.path().join(".claude"))?;
|
||||||
|
fs::create_dir_all(repo.path().join(".codex"))?;
|
||||||
|
|
||||||
|
let harness = SessionHarnessInfo::detect("custom-runner", repo.path());
|
||||||
|
assert_eq!(harness.primary, HarnessKind::Unknown);
|
||||||
|
assert_eq!(harness.primary_label, "custom-runner");
|
||||||
|
assert_eq!(
|
||||||
|
harness.detected,
|
||||||
|
vec![HarnessKind::Claude, HarnessKind::Codex]
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn runner_key_uses_canonical_label_for_unknown_harnesses() {
|
||||||
|
assert_eq!(
|
||||||
|
SessionHarnessInfo::runner_key(" custom-runner "),
|
||||||
|
"custom-runner"
|
||||||
|
);
|
||||||
|
assert_eq!(SessionHarnessInfo::runner_key("claude-code"), "claude");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -706,7 +706,7 @@ impl StateStore {
|
|||||||
rusqlite::params![
|
rusqlite::params![
|
||||||
session_id,
|
session_id,
|
||||||
canonical_agent_type,
|
canonical_agent_type,
|
||||||
harness.primary.to_string(),
|
harness.primary_label,
|
||||||
detected_json
|
detected_json
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
@ -728,7 +728,7 @@ impl StateStore {
|
|||||||
session.project,
|
session.project,
|
||||||
session.task_group,
|
session.task_group,
|
||||||
session.agent_type,
|
session.agent_type,
|
||||||
harness.primary.to_string(),
|
harness.primary_label,
|
||||||
detected_json,
|
detected_json,
|
||||||
session.working_dir.to_string_lossy().to_string(),
|
session.working_dir.to_string_lossy().to_string(),
|
||||||
session.state.to_string(),
|
session.state.to_string(),
|
||||||
@ -1763,16 +1763,17 @@ impl StateStore {
|
|||||||
let harnesses = stmt
|
let harnesses = stmt
|
||||||
.query_map([], |row| {
|
.query_map([], |row| {
|
||||||
let session_id: String = row.get(0)?;
|
let session_id: String = row.get(0)?;
|
||||||
let primary = HarnessKind::from_db_value(&row.get::<_, String>(1)?);
|
let harness_label: String = row.get(1)?;
|
||||||
let detected = serde_json::from_str::<Vec<HarnessKind>>(&row.get::<_, String>(2)?)
|
let detected = serde_json::from_str::<Vec<HarnessKind>>(&row.get::<_, String>(2)?)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let agent_type: String = row.get(3)?;
|
let agent_type: String = row.get(3)?;
|
||||||
let working_dir = PathBuf::from(row.get::<_, String>(4)?);
|
let working_dir = PathBuf::from(row.get::<_, String>(4)?);
|
||||||
let info = if primary == HarnessKind::Unknown && detected.is_empty() {
|
let info = SessionHarnessInfo::from_persisted(
|
||||||
SessionHarnessInfo::detect(&agent_type, &working_dir)
|
&harness_label,
|
||||||
} else {
|
&agent_type,
|
||||||
SessionHarnessInfo { primary, detected }
|
&working_dir,
|
||||||
};
|
detected,
|
||||||
|
);
|
||||||
Ok((session_id, info))
|
Ok((session_id, info))
|
||||||
})?
|
})?
|
||||||
.collect::<std::result::Result<HashMap<_, _>, _>>()?;
|
.collect::<std::result::Result<HashMap<_, _>, _>>()?;
|
||||||
@ -1788,16 +1789,17 @@ impl StateStore {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
stmt.query_row([session_id], |row| {
|
stmt.query_row([session_id], |row| {
|
||||||
let primary = HarnessKind::from_db_value(&row.get::<_, String>(0)?);
|
let harness_label: String = row.get(0)?;
|
||||||
let detected = serde_json::from_str::<Vec<HarnessKind>>(&row.get::<_, String>(1)?)
|
let detected = serde_json::from_str::<Vec<HarnessKind>>(&row.get::<_, String>(1)?)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let agent_type: String = row.get(2)?;
|
let agent_type: String = row.get(2)?;
|
||||||
let working_dir = PathBuf::from(row.get::<_, String>(3)?);
|
let working_dir = PathBuf::from(row.get::<_, String>(3)?);
|
||||||
let info = if primary == HarnessKind::Unknown && detected.is_empty() {
|
let info = SessionHarnessInfo::from_persisted(
|
||||||
SessionHarnessInfo::detect(&agent_type, &working_dir)
|
&harness_label,
|
||||||
} else {
|
&agent_type,
|
||||||
SessionHarnessInfo { primary, detected }
|
&working_dir,
|
||||||
};
|
detected,
|
||||||
|
);
|
||||||
Ok(info)
|
Ok(info)
|
||||||
})
|
})
|
||||||
.optional()
|
.optional()
|
||||||
@ -4191,10 +4193,41 @@ mod tests {
|
|||||||
.get_session_harness_info("sess-legacy")?
|
.get_session_harness_info("sess-legacy")?
|
||||||
.expect("legacy row should be backfilled");
|
.expect("legacy row should be backfilled");
|
||||||
assert_eq!(harness.primary, HarnessKind::Gemini);
|
assert_eq!(harness.primary, HarnessKind::Gemini);
|
||||||
|
assert_eq!(harness.primary_label, "gemini");
|
||||||
assert_eq!(harness.detected, vec![HarnessKind::Codex]);
|
assert_eq!(harness.detected, vec![HarnessKind::Codex]);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn insert_session_preserves_custom_harness_label_for_unknown_agent_types() -> Result<()> {
|
||||||
|
let tempdir = TestDir::new("store-custom-harness-label")?;
|
||||||
|
let db = StateStore::open(&tempdir.path().join("state.db"))?;
|
||||||
|
let now = Utc::now();
|
||||||
|
|
||||||
|
db.insert_session(&Session {
|
||||||
|
id: "sess-custom".to_string(),
|
||||||
|
task: "Run custom harness".to_string(),
|
||||||
|
project: "ecc".to_string(),
|
||||||
|
task_group: "compat".to_string(),
|
||||||
|
agent_type: "acme-runner".to_string(),
|
||||||
|
working_dir: PathBuf::from(tempdir.path()),
|
||||||
|
state: SessionState::Pending,
|
||||||
|
pid: None,
|
||||||
|
worktree: None,
|
||||||
|
created_at: now,
|
||||||
|
updated_at: now,
|
||||||
|
last_heartbeat_at: now,
|
||||||
|
metrics: SessionMetrics::default(),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let harness = db
|
||||||
|
.get_session_harness_info("sess-custom")?
|
||||||
|
.expect("custom session should have harness info");
|
||||||
|
assert_eq!(harness.primary, HarnessKind::Unknown);
|
||||||
|
assert_eq!(harness.primary_label, "acme-runner");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn session_profile_round_trips_with_launch_settings() -> Result<()> {
|
fn session_profile_round_trips_with_launch_settings() -> Result<()> {
|
||||||
let tempdir = TestDir::new("store-session-profile")?;
|
let tempdir = TestDir::new("store-session-profile")?;
|
||||||
|
|||||||
@ -6347,7 +6347,7 @@ impl Dashboard {
|
|||||||
if let Some(harness) = self.session_harnesses.get(&session.id) {
|
if let Some(harness) = self.session_harnesses.get(&session.id) {
|
||||||
lines.push(format!(
|
lines.push(format!(
|
||||||
"Harness {} | Detected {}",
|
"Harness {} | Detected {}",
|
||||||
harness.primary,
|
harness.primary_label,
|
||||||
harness.detected_summary()
|
harness.detected_summary()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user