mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-04-11 20:13:30 +08:00
feat: canonicalize ecc2 harness aliases
This commit is contained in:
@@ -2103,11 +2103,12 @@ async fn queue_session_in_dir_with_runner_program(
|
|||||||
grouping: SessionGrouping,
|
grouping: SessionGrouping,
|
||||||
) -> Result<String> {
|
) -> Result<String> {
|
||||||
let profile = resolve_launch_profile(db, cfg, profile_name, inherited_profile_session_id)?;
|
let profile = resolve_launch_profile(db, cfg, profile_name, inherited_profile_session_id)?;
|
||||||
|
let canonical_agent_type = HarnessKind::canonical_agent_type(agent_type);
|
||||||
queue_session_with_resolved_profile_and_runner_program(
|
queue_session_with_resolved_profile_and_runner_program(
|
||||||
db,
|
db,
|
||||||
cfg,
|
cfg,
|
||||||
task,
|
task,
|
||||||
agent_type,
|
&canonical_agent_type,
|
||||||
use_worktree,
|
use_worktree,
|
||||||
repo_root,
|
repo_root,
|
||||||
runner_program,
|
runner_program,
|
||||||
@@ -2132,10 +2133,11 @@ async fn queue_session_with_resolved_profile_and_runner_program(
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|profile| profile.agent.as_deref())
|
.and_then(|profile| profile.agent.as_deref())
|
||||||
.unwrap_or(agent_type);
|
.unwrap_or(agent_type);
|
||||||
|
let effective_agent_type = HarnessKind::canonical_agent_type(effective_agent_type);
|
||||||
let session = build_session_record(
|
let session = build_session_record(
|
||||||
db,
|
db,
|
||||||
task,
|
task,
|
||||||
effective_agent_type,
|
&effective_agent_type,
|
||||||
use_worktree,
|
use_worktree,
|
||||||
cfg,
|
cfg,
|
||||||
repo_root,
|
repo_root,
|
||||||
@@ -2188,6 +2190,7 @@ fn build_session_record(
|
|||||||
repo_root: &Path,
|
repo_root: &Path,
|
||||||
grouping: SessionGrouping,
|
grouping: SessionGrouping,
|
||||||
) -> Result<Session> {
|
) -> Result<Session> {
|
||||||
|
let canonical_agent_type = HarnessKind::canonical_agent_type(agent_type);
|
||||||
let id = uuid::Uuid::new_v4().to_string()[..8].to_string();
|
let id = uuid::Uuid::new_v4().to_string()[..8].to_string();
|
||||||
let now = chrono::Utc::now();
|
let now = chrono::Utc::now();
|
||||||
|
|
||||||
@@ -2216,7 +2219,7 @@ fn build_session_record(
|
|||||||
task: task.to_string(),
|
task: task.to_string(),
|
||||||
project,
|
project,
|
||||||
task_group,
|
task_group,
|
||||||
agent_type: agent_type.to_string(),
|
agent_type: canonical_agent_type,
|
||||||
working_dir,
|
working_dir,
|
||||||
state: SessionState::Pending,
|
state: SessionState::Pending,
|
||||||
pid: None,
|
pid: None,
|
||||||
@@ -2341,13 +2344,18 @@ fn direct_delegate_sessions(
|
|||||||
lead_id: &str,
|
lead_id: &str,
|
||||||
agent_type: &str,
|
agent_type: &str,
|
||||||
) -> Result<Vec<Session>> {
|
) -> Result<Vec<Session>> {
|
||||||
|
let target_harness = HarnessKind::from_agent_type(agent_type);
|
||||||
let mut sessions = Vec::new();
|
let mut sessions = Vec::new();
|
||||||
for child_id in db.delegated_children(lead_id, 50)? {
|
for child_id in db.delegated_children(lead_id, 50)? {
|
||||||
let Some(session) = db.get_session(&child_id)? else {
|
let Some(session) = db.get_session(&child_id)? else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
if session.agent_type != agent_type {
|
if target_harness != HarnessKind::Unknown {
|
||||||
|
if HarnessKind::from_agent_type(&session.agent_type) != target_harness {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if session.agent_type != HarnessKind::canonical_agent_type(agent_type) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3575,6 +3583,81 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn build_session_record_canonicalizes_known_agent_aliases() -> Result<()> {
|
||||||
|
let tempdir = TestDir::new("manager-canonical-agent-type")?;
|
||||||
|
let repo_root = tempdir.path().join("repo");
|
||||||
|
init_git_repo(&repo_root)?;
|
||||||
|
|
||||||
|
let cfg = build_config(tempdir.path());
|
||||||
|
let db = StateStore::open(&cfg.db_path)?;
|
||||||
|
let session = build_session_record(
|
||||||
|
&db,
|
||||||
|
"Investigate auth callback",
|
||||||
|
"gemini-cli",
|
||||||
|
false,
|
||||||
|
&cfg,
|
||||||
|
&repo_root,
|
||||||
|
SessionGrouping::default(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
assert_eq!(session.agent_type, "gemini");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn direct_delegate_sessions_matches_harness_aliases_for_existing_rows() -> Result<()> {
|
||||||
|
let tempdir = TestDir::new("manager-delegate-alias-match")?;
|
||||||
|
let repo_root = tempdir.path().join("repo");
|
||||||
|
init_git_repo(&repo_root)?;
|
||||||
|
|
||||||
|
let cfg = build_config(tempdir.path());
|
||||||
|
let db = StateStore::open(&cfg.db_path)?;
|
||||||
|
let now = Utc::now();
|
||||||
|
|
||||||
|
db.insert_session(&Session {
|
||||||
|
id: "lead".to_string(),
|
||||||
|
task: "Lead task".to_string(),
|
||||||
|
project: "workspace".to_string(),
|
||||||
|
task_group: "general".to_string(),
|
||||||
|
agent_type: "claude".to_string(),
|
||||||
|
working_dir: repo_root.clone(),
|
||||||
|
state: SessionState::Running,
|
||||||
|
pid: Some(42),
|
||||||
|
worktree: None,
|
||||||
|
created_at: now,
|
||||||
|
updated_at: now,
|
||||||
|
last_heartbeat_at: now,
|
||||||
|
metrics: SessionMetrics::default(),
|
||||||
|
})?;
|
||||||
|
db.insert_session(&Session {
|
||||||
|
id: "child".to_string(),
|
||||||
|
task: "Delegate task".to_string(),
|
||||||
|
project: "workspace".to_string(),
|
||||||
|
task_group: "general".to_string(),
|
||||||
|
agent_type: "claude-code".to_string(),
|
||||||
|
working_dir: repo_root.clone(),
|
||||||
|
state: SessionState::Idle,
|
||||||
|
pid: Some(7),
|
||||||
|
worktree: None,
|
||||||
|
created_at: now,
|
||||||
|
updated_at: now,
|
||||||
|
last_heartbeat_at: now,
|
||||||
|
metrics: SessionMetrics::default(),
|
||||||
|
})?;
|
||||||
|
db.send_message(
|
||||||
|
"lead",
|
||||||
|
"child",
|
||||||
|
"{\"task\":\"Delegate task\",\"context\":\"Delegated from lead\"}",
|
||||||
|
"task_handoff",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let delegates = direct_delegate_sessions(&db, "lead", "claude")?;
|
||||||
|
assert_eq!(delegates.len(), 1);
|
||||||
|
assert_eq!(delegates[0].id, "child");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn enforce_session_heartbeats_marks_overdue_running_sessions_stale() -> Result<()> {
|
fn enforce_session_heartbeats_marks_overdue_running_sessions_stale() -> Result<()> {
|
||||||
let tempdir = TestDir::new("manager-heartbeat-stale")?;
|
let tempdir = TestDir::new("manager-heartbeat-stale")?;
|
||||||
|
|||||||
@@ -79,6 +79,13 @@ impl HarnessKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn canonical_agent_type(agent_type: &str) -> String {
|
||||||
|
match Self::from_agent_type(agent_type) {
|
||||||
|
Self::Unknown => agent_type.trim().to_ascii_lowercase(),
|
||||||
|
harness => harness.as_str().to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn project_markers(self) -> &'static [&'static str] {
|
fn project_markers(self) -> &'static [&'static str] {
|
||||||
match self {
|
match self {
|
||||||
Self::Claude => &[".claude"],
|
Self::Claude => &[".claude"],
|
||||||
@@ -505,4 +512,18 @@ mod tests {
|
|||||||
assert_eq!(harness.detected, vec![HarnessKind::Gemini]);
|
assert_eq!(harness.detected, vec![HarnessKind::Gemini]);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn canonical_agent_type_normalizes_known_aliases() {
|
||||||
|
assert_eq!(HarnessKind::canonical_agent_type("claude-code"), "claude");
|
||||||
|
assert_eq!(HarnessKind::canonical_agent_type("gemini-cli"), "gemini");
|
||||||
|
assert_eq!(
|
||||||
|
HarnessKind::canonical_agent_type("factory-droid"),
|
||||||
|
"factory_droid"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
HarnessKind::canonical_agent_type(" custom-runner "),
|
||||||
|
"custom-runner"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -675,15 +675,23 @@ impl StateStore {
|
|||||||
.collect::<std::result::Result<Vec<_>, _>>()?;
|
.collect::<std::result::Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
for (session_id, agent_type, working_dir) in updates {
|
for (session_id, agent_type, working_dir) in updates {
|
||||||
let harness = SessionHarnessInfo::detect(&agent_type, Path::new(&working_dir));
|
let canonical_agent_type = HarnessKind::canonical_agent_type(&agent_type);
|
||||||
|
let harness =
|
||||||
|
SessionHarnessInfo::detect(&canonical_agent_type, Path::new(&working_dir));
|
||||||
let detected_json =
|
let detected_json =
|
||||||
serde_json::to_string(&harness.detected).context("serialize detected harnesses")?;
|
serde_json::to_string(&harness.detected).context("serialize detected harnesses")?;
|
||||||
self.conn.execute(
|
self.conn.execute(
|
||||||
"UPDATE sessions
|
"UPDATE sessions
|
||||||
SET harness = ?2,
|
SET agent_type = ?2,
|
||||||
detected_harnesses_json = ?3
|
harness = ?3,
|
||||||
|
detected_harnesses_json = ?4
|
||||||
WHERE id = ?1",
|
WHERE id = ?1",
|
||||||
rusqlite::params![session_id, harness.primary.to_string(), detected_json],
|
rusqlite::params![
|
||||||
|
session_id,
|
||||||
|
canonical_agent_type,
|
||||||
|
harness.primary.to_string(),
|
||||||
|
detected_json
|
||||||
|
],
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3968,7 +3976,7 @@ mod tests {
|
|||||||
"Backfill harness metadata",
|
"Backfill harness metadata",
|
||||||
"ecc",
|
"ecc",
|
||||||
"legacy",
|
"legacy",
|
||||||
"claude",
|
"gemini-cli",
|
||||||
repo_root.display().to_string(),
|
repo_root.display().to_string(),
|
||||||
now,
|
now,
|
||||||
],
|
],
|
||||||
@@ -3976,10 +3984,14 @@ mod tests {
|
|||||||
drop(conn);
|
drop(conn);
|
||||||
|
|
||||||
let db = StateStore::open(&db_path)?;
|
let db = StateStore::open(&db_path)?;
|
||||||
|
let session = db
|
||||||
|
.get_session("sess-legacy")?
|
||||||
|
.expect("legacy row should still exist");
|
||||||
|
assert_eq!(session.agent_type, "gemini");
|
||||||
let harness = db
|
let harness = db
|
||||||
.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::Claude);
|
assert_eq!(harness.primary, HarnessKind::Gemini);
|
||||||
assert_eq!(harness.detected, vec![HarnessKind::Codex]);
|
assert_eq!(harness.detected, vec![HarnessKind::Codex]);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user