commit 904af9764976d7546c92bac36448e4ec9f61b75f
parent 410a3a0d8f4109567e171bdf7d550b18582208b5
Author: triesap <tyson@radroots.org>
Date: Sat, 25 Apr 2026 01:21:31 +0000
runtime: root repo-local workspace config
- resolve repo-local workspace config from the explicit root
- keep interactive workspace config resolution unchanged
- report repo-local config.toml in config show output
- cover explicit-root workspace relay loading in tests
Diffstat:
3 files changed, 67 insertions(+), 1 deletion(-)
diff --git a/src/runtime/config.rs b/src/runtime/config.rs
@@ -2194,6 +2194,10 @@ target = "https://rpc.workspace.test/jsonrpc"
)
);
assert_eq!(
+ resolved.paths.workspace_config_path,
+ PathBuf::from("/workspaces/radroots-cli/.local/radroots/dev/config.toml")
+ );
+ assert_eq!(
resolved.paths.app_data_root,
PathBuf::from("/workspaces/radroots-cli/.local/radroots/dev/data/apps/cli")
);
@@ -2250,6 +2254,10 @@ RADROOTS_CLI_PATHS_REPO_LOCAL_ROOT=.local/radroots/dev
resolved.paths.app_data_root,
PathBuf::from("/workspaces/radroots-cli/.local/radroots/dev/data/apps/cli")
);
+ assert_eq!(
+ resolved.paths.workspace_config_path,
+ PathBuf::from("/workspaces/radroots-cli/.local/radroots/dev/config.toml")
+ );
}
#[test]
diff --git a/src/runtime/paths.rs b/src/runtime/paths.rs
@@ -51,6 +51,8 @@ pub(crate) fn resolve_paths(
let (profile, profile_label, profile_source) = resolve_cli_path_profile(env, env_file)?;
let override_selection =
resolve_cli_path_overrides(current_dir.as_path(), env, env_file, profile)?;
+ let workspace_config_path =
+ resolve_workspace_config_path(current_dir.as_path(), profile, &override_selection)?;
let resolved = resolver
.resolve(profile, &override_selection.overrides)
.map_err(|err| RuntimeError::Config(format!("resolve Radroots path roots: {err}")))?;
@@ -91,7 +93,7 @@ pub(crate) fn resolve_paths(
.display()
.to_string(),
app_config_path: app_paths.config.join(DEFAULT_CONFIG_FILE_NAME),
- workspace_config_path: current_dir.join(DEFAULT_WORKSPACE_CONFIG_PATH),
+ workspace_config_path,
app_data_root: app_paths.data,
app_logs_root: app_paths.logs,
shared_accounts_data_root: shared_accounts_paths.data,
@@ -190,6 +192,28 @@ fn normalize_explicit_path_root(current_dir: &Path, value: &str) -> PathBuf {
}
}
+fn resolve_workspace_config_path(
+ current_dir: &Path,
+ profile: RadrootsPathProfile,
+ override_selection: &CliPathOverrideSelection,
+) -> Result<PathBuf, RuntimeError> {
+ match profile {
+ RadrootsPathProfile::InteractiveUser => Ok(current_dir.join(DEFAULT_WORKSPACE_CONFIG_PATH)),
+ RadrootsPathProfile::RepoLocal => override_selection
+ .repo_local_root
+ .as_ref()
+ .map(|root| root.join(DEFAULT_CONFIG_FILE_NAME))
+ .ok_or_else(|| {
+ RuntimeError::Config(format!(
+ "{ENV_CLI_PATHS_REPO_LOCAL_ROOT} must be resolved when {ENV_CLI_PATHS_PROFILE}=repo_local"
+ ))
+ }),
+ _ => Err(RuntimeError::Config(
+ "cli only supports interactive_user and repo_local path profiles".to_owned(),
+ )),
+ }
+}
+
struct PathEnvValueEntry {
key: String,
value: String,
diff --git a/tests/runtime_show.rs b/tests/runtime_show.rs
@@ -435,6 +435,10 @@ fn config_show_json_reports_repo_local_paths_when_requested() {
.to_string()
);
assert_eq!(
+ json["paths"]["workspace_config_path"],
+ repo_local_root.join("config.toml").display().to_string()
+ );
+ assert_eq!(
json["paths"]["app_data_root"],
repo_local_root.join("data/apps/cli").display().to_string()
);
@@ -466,6 +470,36 @@ fn config_show_json_reports_repo_local_paths_when_requested() {
}
#[test]
+fn config_show_json_reads_repo_local_workspace_config_from_explicit_root() {
+ let dir = tempdir().expect("tempdir");
+ let repo_local_root = dir.path().join("repo-runtime");
+ fs::create_dir_all(&repo_local_root).expect("repo-local root");
+ fs::write(
+ repo_local_root.join("config.toml"),
+ "[relay]\nurls = [\"wss://relay.repo-local\"]\npublish_policy = \"any\"\n",
+ )
+ .expect("write repo-local workspace config");
+
+ let output = runtime_show_command_in(dir.path())
+ .env("RADROOTS_CLI_PATHS_PROFILE", "repo_local")
+ .env("RADROOTS_CLI_PATHS_REPO_LOCAL_ROOT", &repo_local_root)
+ .args(["--json", "config", "show"])
+ .output()
+ .expect("run config show");
+
+ assert!(output.status.success());
+ let json: Value = serde_json::from_slice(output.stdout.as_slice()).expect("json output");
+ assert_eq!(
+ json["paths"]["workspace_config_path"],
+ repo_local_root.join("config.toml").display().to_string()
+ );
+ assert_eq!(json["config_files"]["workspace_present"], true);
+ assert_eq!(json["relay"]["count"], 1);
+ assert_eq!(json["relay"]["urls"][0], "wss://relay.repo-local");
+ assert_eq!(json["relay"]["source"], "workspace config ยท local first");
+}
+
+#[test]
fn config_show_json_reflects_environment_configuration() {
let dir = tempdir().expect("tempdir");
let output = runtime_show_command_in(dir.path())