mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-04-12 04:33:29 +08:00
feat: add ecc2 harness compatibility env
This commit is contained in:
@@ -3018,6 +3018,7 @@ fn build_agent_command(
|
|||||||
if let Some(runner) = cfg.harness_runner(&SessionHarnessInfo::runner_key(agent_type)) {
|
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_type,
|
||||||
agent_program,
|
agent_program,
|
||||||
task,
|
task,
|
||||||
session_id,
|
session_id,
|
||||||
@@ -3028,7 +3029,7 @@ fn build_agent_command(
|
|||||||
|
|
||||||
let task = normalize_task_for_harness(harness, task, profile);
|
let task = normalize_task_for_harness(harness, task, profile);
|
||||||
let mut command = Command::new(agent_program);
|
let mut command = Command::new(agent_program);
|
||||||
command.env("ECC_SESSION_ID", session_id);
|
apply_shared_harness_runtime_env(&mut command, agent_type, session_id, working_dir, profile);
|
||||||
match harness {
|
match harness {
|
||||||
HarnessKind::Claude => {
|
HarnessKind::Claude => {
|
||||||
command
|
command
|
||||||
@@ -3125,6 +3126,7 @@ fn build_agent_command(
|
|||||||
|
|
||||||
fn build_configured_harness_command(
|
fn build_configured_harness_command(
|
||||||
runner: &crate::config::HarnessRunnerConfig,
|
runner: &crate::config::HarnessRunnerConfig,
|
||||||
|
agent_type: &str,
|
||||||
agent_program: &Path,
|
agent_program: &Path,
|
||||||
task: &str,
|
task: &str,
|
||||||
session_id: &str,
|
session_id: &str,
|
||||||
@@ -3132,7 +3134,7 @@ fn build_configured_harness_command(
|
|||||||
profile: Option<&SessionAgentProfile>,
|
profile: Option<&SessionAgentProfile>,
|
||||||
) -> Command {
|
) -> Command {
|
||||||
let mut command = Command::new(agent_program);
|
let mut command = Command::new(agent_program);
|
||||||
command.env("ECC_SESSION_ID", session_id);
|
apply_shared_harness_runtime_env(&mut command, agent_type, session_id, working_dir, profile);
|
||||||
for (key, value) in &runner.env {
|
for (key, value) in &runner.env {
|
||||||
if !value.trim().is_empty() {
|
if !value.trim().is_empty() {
|
||||||
command.env(key, value);
|
command.env(key, value);
|
||||||
@@ -3211,6 +3213,52 @@ fn build_configured_harness_command(
|
|||||||
command
|
command
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn apply_shared_harness_runtime_env(
|
||||||
|
command: &mut Command,
|
||||||
|
agent_type: &str,
|
||||||
|
session_id: &str,
|
||||||
|
working_dir: &Path,
|
||||||
|
profile: Option<&SessionAgentProfile>,
|
||||||
|
) {
|
||||||
|
let harness_label = SessionHarnessInfo::runner_key(agent_type);
|
||||||
|
command.env("ECC_SESSION_ID", session_id);
|
||||||
|
command.env("ECC_HARNESS", &harness_label);
|
||||||
|
command.env("ECC_WORKING_DIR", working_dir);
|
||||||
|
command.env("ECC_PROJECT_DIR", working_dir);
|
||||||
|
command.env("CLAUDE_SESSION_ID", session_id);
|
||||||
|
command.env("CLAUDE_PROJECT_DIR", working_dir);
|
||||||
|
command.env("CLAUDE_CODE_ENTRYPOINT", "cli");
|
||||||
|
if let Some(model) = profile.and_then(|profile| profile.model.as_ref()) {
|
||||||
|
command.env("CLAUDE_MODEL", model);
|
||||||
|
}
|
||||||
|
if let Some(plugin_root) = resolve_ecc_plugin_root() {
|
||||||
|
command.env("ECC_PLUGIN_ROOT", &plugin_root);
|
||||||
|
command.env("CLAUDE_PLUGIN_ROOT", &plugin_root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_ecc_plugin_root() -> Option<PathBuf> {
|
||||||
|
let mut seeds = Vec::new();
|
||||||
|
if let Ok(current_exe) = std::env::current_exe() {
|
||||||
|
seeds.push(current_exe);
|
||||||
|
}
|
||||||
|
seeds.push(PathBuf::from(env!("CARGO_MANIFEST_DIR")));
|
||||||
|
|
||||||
|
for seed in seeds {
|
||||||
|
for candidate in seed.ancestors() {
|
||||||
|
if is_ecc_plugin_root(candidate) {
|
||||||
|
return Some(candidate.to_path_buf());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ecc_plugin_root(candidate: &Path) -> bool {
|
||||||
|
candidate.join("scripts/lib/utils.js").is_file() && candidate.join("hooks/hooks.json").is_file()
|
||||||
|
}
|
||||||
|
|
||||||
fn normalize_task_for_harness(
|
fn normalize_task_for_harness(
|
||||||
harness: HarnessKind,
|
harness: HarnessKind,
|
||||||
task: &str,
|
task: &str,
|
||||||
@@ -4246,6 +4294,24 @@ mod tests {
|
|||||||
"System instructions:\nReview thoroughly.\n\nECC execution profile:\n- Allowed tools: Read\n- Disallowed tools: Bash\n- Permission mode: plan\n- Max budget USD: 1.25\n- Token budget: 750\n\nTask:\nreview this change",
|
"System instructions:\nReview thoroughly.\n\nECC execution profile:\n- Allowed tools: Read\n- Disallowed tools: Bash\n- Permission mode: plan\n- Max budget USD: 1.25\n- Token budget: 750\n\nTask:\nreview this change",
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let envs = command_env_map(&command);
|
||||||
|
assert_eq!(envs.get("ECC_SESSION_ID"), Some(&"sess-1234".to_string()));
|
||||||
|
assert_eq!(
|
||||||
|
envs.get("CLAUDE_SESSION_ID"),
|
||||||
|
Some(&"sess-1234".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
envs.get("CLAUDE_PROJECT_DIR"),
|
||||||
|
Some(&"/tmp/repo".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(envs.get("CLAUDE_CODE_ENTRYPOINT"), Some(&"cli".to_string()));
|
||||||
|
assert_eq!(envs.get("ECC_HARNESS"), Some(&"codex".to_string()));
|
||||||
|
assert_eq!(envs.get("CLAUDE_MODEL"), Some(&"gpt-5.4".to_string()));
|
||||||
|
assert!(
|
||||||
|
envs.contains_key("CLAUDE_PLUGIN_ROOT"),
|
||||||
|
"shared compatibility env should expose the ECC plugin root"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -4441,24 +4507,20 @@ mod tests {
|
|||||||
"System instructions:\nUse repo context carefully.\n\nTask:\nfix callback regression",
|
"System instructions:\nUse repo context carefully.\n\nTask:\nfix callback regression",
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
let mut envs = command
|
let envs = command_env_map(&command);
|
||||||
.as_std()
|
assert_eq!(envs.get("ECC_SESSION_ID"), Some(&"sess-cur1".to_string()));
|
||||||
.get_envs()
|
|
||||||
.map(|(key, value)| {
|
|
||||||
(
|
|
||||||
key.to_string_lossy().to_string(),
|
|
||||||
value.map(|value| value.to_string_lossy().to_string()),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
envs.sort();
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
envs,
|
envs.get("CLAUDE_SESSION_ID"),
|
||||||
vec![
|
Some(&"sess-cur1".to_string())
|
||||||
("ECC_HARNESS".to_string(), Some("cursor".to_string())),
|
|
||||||
("ECC_SESSION_ID".to_string(), Some("sess-cur1".to_string())),
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
envs.get("CLAUDE_PROJECT_DIR"),
|
||||||
|
Some(&"/tmp/repo".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(envs.get("CLAUDE_CODE_ENTRYPOINT"), Some(&"cli".to_string()));
|
||||||
|
assert_eq!(envs.get("ECC_HARNESS"), Some(&"cursor".to_string()));
|
||||||
|
assert_eq!(envs.get("CLAUDE_MODEL"), Some(&"gpt-5.4".to_string()));
|
||||||
|
assert_eq!(envs.get("ECC_PLUGIN_ROOT"), envs.get("CLAUDE_PLUGIN_ROOT"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -4806,7 +4868,7 @@ mod tests {
|
|||||||
let script_path = root.join("fake-claude.sh");
|
let script_path = root.join("fake-claude.sh");
|
||||||
let log_path = root.join("fake-claude.log");
|
let log_path = root.join("fake-claude.log");
|
||||||
let script = format!(
|
let script = format!(
|
||||||
"#!/usr/bin/env python3\nimport os\nimport pathlib\nimport signal\nimport sys\nimport time\n\nlog_path = pathlib.Path(r\"{}\")\nlog_path.write_text(os.getcwd() + \"\\n\", encoding=\"utf-8\")\nwith log_path.open(\"a\", encoding=\"utf-8\") as handle:\n handle.write(\" \".join(sys.argv[1:]) + \"\\n\")\n handle.write(\"ECC_SESSION_ID=\" + os.environ.get(\"ECC_SESSION_ID\", \"\") + \"\\n\")\n\ndef handle_term(signum, frame):\n raise SystemExit(0)\n\nsignal.signal(signal.SIGTERM, handle_term)\nwhile True:\n time.sleep(0.1)\n",
|
"#!/usr/bin/env python3\nimport os\nimport pathlib\nimport signal\nimport sys\nimport time\n\nlog_path = pathlib.Path(r\"{}\")\nlog_path.write_text(os.getcwd() + \"\\n\", encoding=\"utf-8\")\nwith log_path.open(\"a\", encoding=\"utf-8\") as handle:\n handle.write(\" \".join(sys.argv[1:]) + \"\\n\")\n handle.write(\"ECC_SESSION_ID=\" + os.environ.get(\"ECC_SESSION_ID\", \"\") + \"\\n\")\n handle.write(\"CLAUDE_SESSION_ID=\" + os.environ.get(\"CLAUDE_SESSION_ID\", \"\") + \"\\n\")\n handle.write(\"CLAUDE_PROJECT_DIR=\" + os.environ.get(\"CLAUDE_PROJECT_DIR\", \"\") + \"\\n\")\n handle.write(\"CLAUDE_CODE_ENTRYPOINT=\" + os.environ.get(\"CLAUDE_CODE_ENTRYPOINT\", \"\") + \"\\n\")\n handle.write(\"CLAUDE_PLUGIN_ROOT=\" + os.environ.get(\"CLAUDE_PLUGIN_ROOT\", \"\") + \"\\n\")\n handle.write(\"ECC_HARNESS=\" + os.environ.get(\"ECC_HARNESS\", \"\") + \"\\n\")\n\ndef handle_term(signum, frame):\n raise SystemExit(0)\n\nsignal.signal(signal.SIGTERM, handle_term)\nwhile True:\n time.sleep(0.1)\n",
|
||||||
log_path.display()
|
log_path.display()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -4834,6 +4896,21 @@ mod tests {
|
|||||||
anyhow::bail!("timed out waiting for {}", path.display());
|
anyhow::bail!("timed out waiting for {}", path.display());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn command_env_map(command: &Command) -> BTreeMap<String, String> {
|
||||||
|
command
|
||||||
|
.as_std()
|
||||||
|
.get_envs()
|
||||||
|
.filter_map(|(key, value)| {
|
||||||
|
value.map(|value| {
|
||||||
|
(
|
||||||
|
key.to_string_lossy().to_string(),
|
||||||
|
value.to_string_lossy().to_string(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "current_thread")]
|
#[tokio::test(flavor = "current_thread")]
|
||||||
async fn create_session_spawns_process_and_marks_session_running() -> Result<()> {
|
async fn create_session_spawns_process_and_marks_session_running() -> Result<()> {
|
||||||
let tempdir = TestDir::new("manager-create-session")?;
|
let tempdir = TestDir::new("manager-create-session")?;
|
||||||
@@ -4869,6 +4946,13 @@ mod tests {
|
|||||||
assert!(log.contains("--print"));
|
assert!(log.contains("--print"));
|
||||||
assert!(log.contains("implement lifecycle"));
|
assert!(log.contains("implement lifecycle"));
|
||||||
assert!(log.contains(&format!("ECC_SESSION_ID={session_id}")));
|
assert!(log.contains(&format!("ECC_SESSION_ID={session_id}")));
|
||||||
|
assert!(log.contains(&format!("CLAUDE_SESSION_ID={session_id}")));
|
||||||
|
assert!(log.contains(&format!(
|
||||||
|
"CLAUDE_PROJECT_DIR={}",
|
||||||
|
repo_root.to_string_lossy()
|
||||||
|
)));
|
||||||
|
assert!(log.contains("CLAUDE_CODE_ENTRYPOINT=cli"));
|
||||||
|
assert!(log.contains("ECC_HARNESS=claude"));
|
||||||
|
|
||||||
stop_session_with_options(&db, &session_id, false).await?;
|
stop_session_with_options(&db, &session_id, false).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user