use octl_core::Kind;
use serde::Serialize;
use crate::config::{config_path, Config, CONFIG_SCHEMA_VERSION};
use crate::error::CliError;
use crate::harness::select::{self, HarnessChoice, HARNESS_ENV};
use crate::output::{self, OutputFormat, OutputSpec};
use crate::run::kind_kebab;
const REDACTED: &str = "<redacted>";
const CREATABLE_KINDS: &[Kind] = &[
Kind::Spinoff,
Kind::Research,
Kind::TechnicalDecision,
Kind::FanOut,
];
#[derive(Debug, Serialize)]
struct ConfigShowPayload {
schema_version_config: u32,
path: String,
exists: bool,
keys: Vec<ConfigKey>,
}
#[derive(Debug, Serialize)]
struct ConfigKey {
key: String,
value: String,
source: &'static str,
secret: bool,
}
impl ConfigKey {
fn harness(key: impl Into<String>, choice: &HarnessChoice) -> Self {
ConfigKey {
key: key.into(),
value: choice.name.clone(),
source: choice.source.as_str(),
secret: false,
}
}
}
pub fn run(show_secrets: bool, spec: &OutputSpec, warnings: &[String]) -> Result<(), CliError> {
let path = config_path()?;
let config = Config::load_from(&path)?;
let env = std::env::var(HARNESS_ENV).ok();
let env = env.as_deref();
let mut keys = Vec::with_capacity(1 + CREATABLE_KINDS.len());
keys.push(ConfigKey::harness(
"harness.default",
&select::resolve_default(env, &config)?,
));
for &kind in CREATABLE_KINDS {
let choice = select::resolve_with(kind, None, env, &config)?;
keys.push(ConfigKey::harness(
format!("harness.{}", kind_kebab(kind)),
&choice,
));
}
let any_secret = keys.iter().any(|k| k.secret);
if !show_secrets {
for k in keys.iter_mut().filter(|k| k.secret) {
k.value = REDACTED.to_string();
}
}
if show_secrets && any_secret {
eprintln!("warning: --show-secrets: secret-valued config keys are shown in plaintext");
}
let payload = ConfigShowPayload {
schema_version_config: CONFIG_SCHEMA_VERSION,
path: path.display().to_string(),
exists: path.exists(),
keys,
};
match spec.format {
OutputFormat::Json | OutputFormat::Jsonl => {
output::emit_envelope(&payload, spec, warnings)?;
}
OutputFormat::Text => {
println!("path: {}", payload.path);
println!("exists: {}", payload.exists);
let key_w = payload.keys.iter().map(|k| k.key.len()).max().unwrap_or(0);
for k in &payload.keys {
println!("{:<key_w$} {:<10} ({})", k.key, k.value, k.source);
}
output::emit_text_warnings(warnings);
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn creatable_kinds_match_wire_names() {
let names: Vec<&str> = CREATABLE_KINDS.iter().map(|k| k.wire_name()).collect();
assert_eq!(names, Kind::WIRE_NAMES);
}
}