aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-07-22 23:06:52 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-07-22 23:06:52 +0300
commit7e821ba7a362cc634a705ea56e11b070b7b95784 (patch)
tree5d046524a8f0379090832a212d901bba3388ad45
parentcd5ea1be0e69ed49b6f32f7ed5b333f6c8526874 (diff)
fix: respect OMP config directory override
refs #1696
-rw-r--r--docs/next/CHANGELOG.md3
-rw-r--r--docs/next/website/src/content/docs/integrations.mdx2
-rw-r--r--src/integration/env.rs18
-rw-r--r--src/integration/targets.rs7
-rw-r--r--src/integration/tests.rs34
5 files changed, 55 insertions, 9 deletions
diff --git a/docs/next/CHANGELOG.md b/docs/next/CHANGELOG.md
index 1c2ec2a4..d9f789ec 100644
--- a/docs/next/CHANGELOG.md
+++ b/docs/next/CHANGELOG.md
@@ -5,6 +5,9 @@
### Changed
- Relicensed Herdr from AGPL-3.0-or-later to Apache-2.0.
+### Fixed
+- OMP integration install, status, and uninstall now respect `PI_CONFIG_DIR` when `PI_CODING_AGENT_DIR` is not set, and installation refuses extension-directory collisions with Pi. (#1696)
+
## [0.7.5] - 2026-07-21
### Breaking Changes
diff --git a/docs/next/website/src/content/docs/integrations.mdx b/docs/next/website/src/content/docs/integrations.mdx
index ea26b892..940d1deb 100644
--- a/docs/next/website/src/content/docs/integrations.mdx
+++ b/docs/next/website/src/content/docs/integrations.mdx
@@ -92,7 +92,7 @@ Herdr writes the bundled extension to:
~/.omp/agent/extensions/herdr-omp-agent-state.ts
```
-If `PI_CODING_AGENT_DIR` is set, Herdr writes to `$PI_CODING_AGENT_DIR/extensions/herdr-omp-agent-state.ts` instead. Herdr creates the extensions directory when the OMP agent directory already exists. Uninstall removes only that extension file.
+Herdr uses `PI_CODING_AGENT_DIR` as the complete agent directory when set. Otherwise, it uses `$HOME/$PI_CONFIG_DIR/agent` when `PI_CONFIG_DIR` is set, falling back to `~/.omp/agent`. If Pi and OMP resolve to the same extension directory, Herdr refuses the OMP install so the OMP extension cannot be loaded by Pi. Configure separate agent directories before installing both integrations. Herdr creates the extensions directory when the resolved OMP agent directory already exists. Uninstall removes only that extension file.
The OMP integration reports `omp` as the agent label, lifecycle state, and native session identity through Herdr's socket API. It does not require native process detection for the `omp` executable, and Herdr can resume an OMP pane with `omp --resume=<session>` after a server restart.
diff --git a/src/integration/env.rs b/src/integration/env.rs
index ef946729..3cd1b604 100644
--- a/src/integration/env.rs
+++ b/src/integration/env.rs
@@ -10,6 +10,7 @@ pub(crate) const HERDR_TAB_ID_ENV_VAR: &str = "HERDR_TAB_ID";
pub(crate) const HERDR_WORKSPACE_ID_ENV_VAR: &str = "HERDR_WORKSPACE_ID";
pub(crate) const PI_CODING_AGENT_DIR_ENV_VAR: &str = "PI_CODING_AGENT_DIR";
+pub(crate) const OMP_CONFIG_DIR_ENV_VAR: &str = "PI_CONFIG_DIR";
pub(crate) const CLAUDE_CONFIG_DIR_ENV_VAR: &str = "CLAUDE_CONFIG_DIR";
pub(crate) const CODEX_HOME_ENV_VAR: &str = "CODEX_HOME";
pub(crate) const KIMI_CODE_HOME_ENV_VAR: &str = "KIMI_CODE_HOME";
@@ -29,10 +30,19 @@ pub(crate) fn pi_extension_dir() -> io::Result<PathBuf> {
}
pub(crate) fn omp_extension_dir() -> io::Result<PathBuf> {
- Ok(
- config_dir_from_env_or_home(PI_CODING_AGENT_DIR_ENV_VAR, &[".omp", "agent"])?
- .join("extensions"),
- )
+ if let Some(value) =
+ std::env::var_os(PI_CODING_AGENT_DIR_ENV_VAR).filter(|value| !value.is_empty())
+ {
+ return expand_tilde_path(PathBuf::from(value)).map(|path| path.join("extensions"));
+ }
+
+ let config_dir = std::env::var_os(OMP_CONFIG_DIR_ENV_VAR)
+ .filter(|value| !value.is_empty())
+ .unwrap_or_else(|| ".omp".into());
+ Ok(home_dir()?
+ .join(config_dir)
+ .join("agent")
+ .join("extensions"))
}
pub(crate) fn claude_dir() -> io::Result<PathBuf> {
diff --git a/src/integration/targets.rs b/src/integration/targets.rs
index 99c150a3..5d5e730c 100644
--- a/src/integration/targets.rs
+++ b/src/integration/targets.rs
@@ -69,6 +69,13 @@ pub(crate) fn install_pi() -> io::Result<PathBuf> {
pub(crate) fn install_omp() -> io::Result<OmpInstallPaths> {
let dir = omp_extension_dir()?;
+ let pi_dir = pi_extension_dir()?;
+ if dir == pi_dir {
+ return Err(io::Error::other(format!(
+ "Pi and OMP resolve to the same extension directory at {}; configure separate agent directories before installing OMP",
+ dir.display()
+ )));
+ }
ensure_extension_dir(&dir, "omp")?;
let removed_legacy_pi_extension = remove_legacy_pi_extension_from_omp_dir(&dir)?;
diff --git a/src/integration/tests.rs b/src/integration/tests.rs
index fc332a84..78b728f9 100644
--- a/src/integration/tests.rs
+++ b/src/integration/tests.rs
@@ -94,6 +94,7 @@ fn enforce_agent_version_accepts_current_version() {
fn clear_integration_path_env() {
std::env::remove_var(PI_CODING_AGENT_DIR_ENV_VAR);
+ std::env::remove_var(OMP_CONFIG_DIR_ENV_VAR);
std::env::remove_var(CLAUDE_CONFIG_DIR_ENV_VAR);
std::env::remove_var(CODEX_HOME_ENV_VAR);
std::env::remove_var(COPILOT_HOME_ENV_VAR);
@@ -625,13 +626,14 @@ fn install_omp_preserves_non_herdr_file_with_pi_install_name() {
}
#[test]
-fn install_omp_uses_pi_coding_agent_dir_env() {
+fn install_omp_uses_pi_config_dir_env() {
let _lock = integration_env_lock();
let base = unique_base();
- let agent_dir = base.join("custom-omp-agent");
- let ext_dir = agent_dir.join("extensions");
+ let home = base.join("home");
+ let ext_dir = home.join("custom-omp/agent/extensions");
fs::create_dir_all(&ext_dir).unwrap();
- std::env::set_var(PI_CODING_AGENT_DIR_ENV_VAR, &agent_dir);
+ std::env::set_var("HOME", &home);
+ std::env::set_var(OMP_CONFIG_DIR_ENV_VAR, "custom-omp");
let installed = install_omp().unwrap();
@@ -641,6 +643,30 @@ fn install_omp_uses_pi_coding_agent_dir_env() {
);
assert!(!installed.removed_legacy_pi_extension);
+ std::env::remove_var("HOME");
+ clear_integration_path_env();
+ let _ = fs::remove_dir_all(base);
+}
+
+#[test]
+fn install_omp_refuses_shared_pi_extension_directory() {
+ let _lock = integration_env_lock();
+ let base = unique_base();
+ let agent_dir = base.join("shared-agent");
+ let ext_dir = agent_dir.join("extensions");
+ let pi_extension = ext_dir.join(PI_EXTENSION_INSTALL_NAME);
+ fs::create_dir_all(&ext_dir).unwrap();
+ fs::write(&pi_extension, PI_EXTENSION_ASSET).unwrap();
+ std::env::set_var(PI_CODING_AGENT_DIR_ENV_VAR, &agent_dir);
+ std::env::set_var(OMP_CONFIG_DIR_ENV_VAR, "ignored-omp-config");
+
+ let err = install_omp().unwrap_err().to_string();
+
+ assert!(err.contains("Pi and OMP resolve to the same extension directory"));
+ assert!(err.contains(&ext_dir.display().to_string()));
+ assert!(pi_extension.is_file());
+ assert!(!ext_dir.join(OMP_EXTENSION_INSTALL_NAME).exists());
+
clear_integration_path_env();
let _ = fs::remove_dir_all(base);
}