use crate::execution_contract::create_execution_contract_registry_from_config;
use crate::graph_context::create_graph_context_readiness_payload;
use crate::lifecycle_hooks::{
create_lifecycle_hook_schema_compatibility_payload, is_supported_hook_runner_command,
};
use crate::lsp_runtime::create_lsp_runtime_readiness_payload;
use crate::memory::create_memory_status_payload;
use crate::request_routing::create_route_modularity_check_payload;
use crate::setup_config::{
collect_ccc_config_install_state_at, CccConfigInstallState, CURRENT_GENERATED_DEFAULTS_VERSION,
};
use crate::skill_manifest::load_skill_ssl_manifest_from_path;
use crate::skill_registry::load_skill_registry_for_agent;
use crate::specialist_roles::{
create_configured_role_models_payload_from_config, create_multi_agent_runtime_contract_payload,
expected_skill_ssl_mutation_allowed_for_agent, expected_skill_ssl_role_family_for_agent,
inspect_generated_custom_agents_from_config, managed_custom_agent_role_count,
managed_skill_ssl_agent_names,
};
use crate::{
read_optional_toml_document, resolve_codex_home, resolve_legacy_shared_json_config_path,
resolve_legacy_shared_json_config_path_for, resolve_legacy_shared_toml_config_path,
resolve_legacy_shared_toml_config_path_for, resolve_shared_config_path, SessionContext,
PUBLIC_ENTRY_LABEL, PUBLIC_ENTRY_SKILL_NAME, SERVER_NAME,
};
use serde::Deserialize;
use serde_json::{json, Value};
use std::env;
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::process::Command;
#[derive(Clone, Debug)]
struct PackagedPluginFileLookup {
name: String,
crate_relative_path: PathBuf,
plugin_relative_path: PathBuf,
}
#[derive(Clone, Debug)]
struct PluginCacheFileLookup {
name: String,
relative_path: PathBuf,
crate_relative_path: Option<PathBuf>,
source: &'static str,
}
#[derive(Clone, Debug, Deserialize)]
struct CodexMcpRegistryRecord {
name: String,
enabled: bool,
transport: Option<CodexMcpRegistryTransport>,
}
#[derive(Clone, Debug, Deserialize)]
struct CodexMcpRegistryTransport {
#[serde(rename = "type")]
transport_type: String,
command: Option<String>,
args: Option<Vec<String>>,
}
pub(crate) fn create_server_identity_payload(session_context: &SessionContext) -> Value {
json!({
"server_name": SERVER_NAME,
"server_version": env!("CARGO_PKG_VERSION"),
"session_id": session_context.session_id,
"process_id": session_context.process_id,
"started_at": session_context.started_at,
"build_identity": session_context.build_identity,
"entrypoint_path": session_context.entrypoint_path,
"shared_config_path": session_context.shared_config_path,
})
}
fn normalize_registered_command(command: &str) -> String {
let candidate = PathBuf::from(command);
if candidate.is_absolute() {
fs::canonicalize(&candidate)
.unwrap_or(candidate)
.to_string_lossy()
.into_owned()
} else {
command.to_string()
}
}
fn ccc_binary_name() -> &'static str {
if cfg!(windows) {
"ccc.exe"
} else {
"ccc"
}
}
fn resolve_home_path(relative: &[&str]) -> Option<PathBuf> {
let mut path = PathBuf::from(env::var_os("HOME")?);
for component in relative {
path.push(component);
}
Some(path)
}
fn display_path(path: &Path) -> String {
fs::canonicalize(path)
.unwrap_or_else(|_| path.to_path_buf())
.to_string_lossy()
.into_owned()
}
fn same_path(left: &Path, right: &Path) -> bool {
let normalized_left = fs::canonicalize(left).unwrap_or_else(|_| left.to_path_buf());
let normalized_right = fs::canonicalize(right).unwrap_or_else(|_| right.to_path_buf());
normalized_left == normalized_right
}
fn shell_resolve_ccc_from_path(path_value: Option<&OsStr>) -> Option<PathBuf> {
let path_value = path_value?;
for directory in env::split_paths(path_value) {
let candidate = directory.join(ccc_binary_name());
if candidate.is_file() {
return Some(candidate);
}
if !cfg!(windows) {
continue;
}
let plain_candidate = directory.join("ccc");
if plain_candidate.is_file() {
return Some(plain_candidate);
}
}
None
}
fn read_ccc_binary_version(path: &Path) -> Result<String, String> {
let output = Command::new(path)
.arg("--version")
.output()
.map_err(|error| error.to_string())?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
return Err(if stderr.is_empty() {
format!(
"{} --version exited with {}.",
path.display(),
output.status
)
} else {
stderr
});
}
Ok(String::from_utf8_lossy(&output.stdout)
.lines()
.next()
.unwrap_or_default()
.trim()
.to_string())
}
fn create_path_shadow_diagnostics_at(
home: Option<&Path>,
path_value: Option<&OsStr>,
current_exe: Option<&Path>,
cargo_version_probe: Option<Result<String, String>>,
) -> Value {
let cargo_candidate = home.map(|path| path.join(".cargo").join("bin").join(ccc_binary_name()));
let legacy_candidate = home.map(|path| path.join(".local").join("bin").join(ccc_binary_name()));
let shell_resolved = shell_resolve_ccc_from_path(path_value);
let cargo_exists = cargo_candidate
.as_ref()
.map(|path| path.is_file())
.unwrap_or(false);
let legacy_exists = legacy_candidate
.as_ref()
.map(|path| path.is_file())
.unwrap_or(false);
let cargo_version = cargo_version_probe
.as_ref()
.and_then(|probe| probe.as_ref().ok())
.cloned();
let cargo_version_error = cargo_version_probe
.as_ref()
.and_then(|probe| probe.as_ref().err())
.cloned();
let cargo_version_matches = cargo_version.as_deref() == Some(env!("CARGO_PKG_VERSION"));
let shell_resolved_is_legacy = match (&shell_resolved, &legacy_candidate) {
(Some(shell), Some(legacy)) => same_path(shell, legacy),
_ => false,
};
let current_exe_is_legacy = match (current_exe, &legacy_candidate) {
(Some(current), Some(legacy)) => same_path(current, legacy),
_ => false,
};
let legacy_shadows_cargo = cargo_exists && legacy_exists && shell_resolved_is_legacy;
let expected_launch_command_source = if cargo_version_matches {
"cargo_binary"
} else {
"current_exe"
};
let status = if legacy_shadows_cargo
|| (current_exe_is_legacy && cargo_exists)
|| (cargo_exists && !cargo_version_matches)
{
"warning"
} else {
"ok"
};
let cargo_display = cargo_candidate
.as_ref()
.map(|path| display_path(path))
.unwrap_or_else(|| "~/.cargo/bin/ccc".to_string());
let summary = if legacy_shadows_cargo {
format!("WARNING: ~/.local/bin/ccc is shadowing the Cargo install at {cargo_display}.")
} else if current_exe_is_legacy && cargo_exists {
format!(
"WARNING: this process is running from legacy ~/.local/bin/ccc while a Cargo candidate exists at {cargo_display}."
)
} else if cargo_exists && !cargo_version_matches {
format!(
"WARNING: Cargo candidate {cargo_display} exists but does not report package version {}.",
env!("CARGO_PKG_VERSION")
)
} else if cargo_version_matches {
format!("Cargo candidate {cargo_display} reports the current package version.")
} else {
"No Cargo PATH shadowing was detected.".to_string()
};
let recommendation = if status == "warning" {
format!(
"Run `{cargo_display} setup`, put ~/.cargo/bin earlier in PATH, or remove/demote the legacy ~/.local/bin/ccc binary after reviewing cleanup."
)
} else {
"No PATH migration action is required.".to_string()
};
json!({
"schema": "ccc.path_shadow_diagnostics.v1",
"status": status,
"summary": summary,
"recommendation": recommendation,
"shellResolvedCcc": shell_resolved.as_ref().map(|path| display_path(path)),
"cargoBinaryCandidate": cargo_candidate.as_ref().map(|path| display_path(path)),
"cargoBinaryCandidateExists": cargo_exists,
"cargoBinaryCandidateVersion": cargo_version,
"cargoBinaryCandidateVersionError": cargo_version_error,
"cargoBinaryCandidateVersionMatches": cargo_version_matches,
"currentExe": current_exe.map(display_path),
"legacyBinaryCandidate": legacy_candidate.as_ref().map(|path| display_path(path)),
"legacyBinaryCandidateExists": legacy_exists,
"shellResolvedIsLegacy": shell_resolved_is_legacy,
"currentExeIsLegacy": current_exe_is_legacy,
"legacyShadowsCargo": legacy_shadows_cargo,
"expectedLaunchCommandSource": expected_launch_command_source,
})
}
fn collect_path_shadow_diagnostics() -> Value {
let home = env::var_os("HOME").map(PathBuf::from);
let path_value = env::var_os("PATH");
let current_exe = env::current_exe().ok();
let cargo_candidate = resolve_home_path(&[".cargo", "bin", ccc_binary_name()]);
let cargo_version_probe = cargo_candidate
.as_ref()
.filter(|path| path.is_file())
.map(|path| read_ccc_binary_version(path));
create_path_shadow_diagnostics_at(
home.as_deref(),
path_value.as_deref(),
current_exe.as_deref(),
cargo_version_probe,
)
}
fn preferred_cargo_launch_command_from_diagnostics(diagnostics: &Value) -> Option<String> {
diagnostics
.get("cargoBinaryCandidateVersionMatches")
.and_then(Value::as_bool)
.filter(|matches| *matches)
.and_then(|_| {
diagnostics
.get("cargoBinaryCandidate")
.and_then(Value::as_str)
})
.map(str::to_string)
}
fn resolve_expected_launch_command() -> io::Result<(String, Vec<String>)> {
let diagnostics = collect_path_shadow_diagnostics();
if let Some(cargo_command) = preferred_cargo_launch_command_from_diagnostics(&diagnostics) {
return Ok((cargo_command, vec!["mcp".to_string()]));
}
let current_exe = env::current_exe()?;
let normalized = fs::canonicalize(¤t_exe).unwrap_or(current_exe);
Ok((
normalized.to_string_lossy().into_owned(),
vec!["mcp".to_string()],
))
}
fn resolve_plugin_cache_launch_command() -> io::Result<String> {
resolve_plugin_cache_launch_command_at(&resolve_codex_home()?)
}
fn resolve_plugin_cache_launch_command_at(codex_home: &Path) -> io::Result<String> {
let command = codex_home
.join("plugins")
.join("cache")
.join("ccc-local")
.join("ccc")
.join(env!("CARGO_PKG_VERSION"))
.join("bin")
.join("ccc");
if !command.is_file() {
return Err(io::Error::new(
io::ErrorKind::NotFound,
format!(
"CCC plugin-cache MCP binary is not installed at {}.",
command.display()
),
));
}
let normalized = fs::canonicalize(&command).unwrap_or(command);
Ok(normalized.to_string_lossy().into_owned())
}
fn plugin_cache_root_at(codex_home: &Path) -> PathBuf {
codex_home
.join("plugins")
.join("cache")
.join("ccc-local")
.join("ccc")
.join(env!("CARGO_PKG_VERSION"))
}
fn plugin_marketplace_root_at_home(home: &Path) -> PathBuf {
home.join(".local")
.join("share")
.join("ccc")
.join("plugin-marketplace")
}
fn plugin_manifest_destination_relative_path() -> PathBuf {
PathBuf::from(".codex-plugin").join("plugin.json")
}
fn required_packaged_plugin_file_lookups() -> Vec<PackagedPluginFileLookup> {
let mut lookups = vec![
PackagedPluginFileLookup {
name: "plugin_manifest".to_string(),
crate_relative_path: PathBuf::from("assets/plugin/.codex-plugin/plugin.json"),
plugin_relative_path: PathBuf::from(".codex-plugin/plugin.json"),
},
PackagedPluginFileLookup {
name: "mcp_manifest".to_string(),
crate_relative_path: PathBuf::from("assets/plugin/.mcp.json"),
plugin_relative_path: PathBuf::from(".mcp.json"),
},
PackagedPluginFileLookup {
name: "hooks_source".to_string(),
crate_relative_path: PathBuf::from("assets/plugin/hooks/hooks.json"),
plugin_relative_path: PathBuf::from("hooks/hooks.json"),
},
PackagedPluginFileLookup {
name: "cap_skill".to_string(),
crate_relative_path: PathBuf::from("assets/skills/cap/SKILL.md"),
plugin_relative_path: PathBuf::from("skills/cap/SKILL.md"),
},
PackagedPluginFileLookup {
name: "ccc_plugin_skill".to_string(),
crate_relative_path: PathBuf::from("assets/plugin/skills/ccc/SKILL.md"),
plugin_relative_path: PathBuf::from("skills/ccc/SKILL.md"),
},
PackagedPluginFileLookup {
name: "coding_comment_discipline_skill".to_string(),
crate_relative_path: PathBuf::from(
"assets/plugin/skills/coding-comment-discipline/SKILL.md",
),
plugin_relative_path: PathBuf::from("skills/coding-comment-discipline/SKILL.md"),
},
];
lookups.extend(managed_skill_ssl_agent_names().into_iter().map(|agent| {
let file_name = format!("{agent}.skill.ssl.json");
PackagedPluginFileLookup {
name: format!("ssl_manifest:{agent}"),
crate_relative_path: PathBuf::from("assets/skills/ssl").join(&file_name),
plugin_relative_path: PathBuf::from("skills/ssl").join(file_name),
}
}));
lookups
}
fn required_plugin_cache_file_lookups() -> Vec<PluginCacheFileLookup> {
let mut lookups = required_packaged_plugin_file_lookups()
.into_iter()
.map(|lookup| PluginCacheFileLookup {
name: lookup.name,
relative_path: lookup.plugin_relative_path,
crate_relative_path: Some(lookup.crate_relative_path),
source: "packaged_plugin_file",
})
.collect::<Vec<_>>();
lookups.push(PluginCacheFileLookup {
name: "mcp_binary".to_string(),
relative_path: PathBuf::from("bin").join(ccc_binary_name()),
crate_relative_path: None,
source: "plugin_cache_only",
});
lookups
}
fn required_plugin_marketplace_surface_lookups() -> Vec<PackagedPluginFileLookup> {
required_packaged_plugin_file_lookups()
.into_iter()
.filter(|lookup| {
matches!(
lookup.name.as_str(),
"plugin_manifest"
| "mcp_manifest"
| "hooks_source"
| "cap_skill"
| "ccc_plugin_skill"
)
})
.collect()
}
fn version_aligned_plugin_manifest_bytes(
source_bytes: &[u8],
source_path: &Path,
) -> io::Result<Vec<u8>> {
let mut manifest = serde_json::from_slice::<Value>(source_bytes).map_err(|error| {
io::Error::new(
io::ErrorKind::InvalidData,
format!(
"parse packaged CCC plugin manifest {}: {error}",
source_path.display()
),
)
})?;
let Some(manifest_object) = manifest.as_object_mut() else {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"packaged CCC plugin manifest {} must be a JSON object",
source_path.display()
),
));
};
manifest_object.insert(
"version".to_string(),
Value::String(env!("CARGO_PKG_VERSION").to_string()),
);
let mut bytes = serde_json::to_vec_pretty(&manifest).map_err(|error| {
io::Error::new(
io::ErrorKind::InvalidData,
format!(
"serialize cache-aligned CCC plugin manifest {}: {error}",
source_path.display()
),
)
})?;
bytes.push(b'\n');
Ok(bytes)
}
fn expected_packaged_asset_bytes(
crate_relative_path: &Path,
destination_relative_path: &Path,
align_plugin_manifest_version: bool,
) -> io::Result<Vec<u8>> {
let source_path = Path::new(env!("CARGO_MANIFEST_DIR")).join(crate_relative_path);
let source_bytes = fs::read(&source_path).map_err(|error| {
io::Error::new(
error.kind(),
format!(
"read packaged CCC plugin asset {}: {error}",
source_path.display()
),
)
})?;
if align_plugin_manifest_version
&& destination_relative_path == plugin_manifest_destination_relative_path()
{
version_aligned_plugin_manifest_bytes(&source_bytes, &source_path)
} else {
Ok(source_bytes)
}
}
fn inspect_packaged_plugin_file_lookup_at(crate_root: &Path) -> Value {
let lookups = required_packaged_plugin_file_lookups();
let mut present = Vec::new();
let mut missing = Vec::new();
let assets = lookups
.iter()
.map(|lookup| {
let source_path = crate_root.join(&lookup.crate_relative_path);
let exists = source_path.is_file();
if exists {
present.push(Value::String(lookup.name.clone()));
} else {
missing.push(Value::String(lookup.name.clone()));
}
json!({
"name": lookup.name.clone(),
"crate_relative_path": lookup.crate_relative_path.to_string_lossy(),
"plugin_relative_path": lookup.plugin_relative_path.to_string_lossy(),
"source_path": source_path.to_string_lossy(),
"exists": exists,
})
})
.collect::<Vec<_>>();
let status = if missing.is_empty() {
"coherent_surface"
} else if present.is_empty() {
"missing_surface"
} else {
"incomplete_surface"
};
json!({
"schema": "ccc.packaged_plugin_file_lookup.v1",
"status": status,
"crate_root": crate_root.to_string_lossy(),
"required_asset_count": lookups.len(),
"present": present,
"missing": missing,
"assets": assets,
"summary": if status == "coherent_surface" {
"The installed Cargo crate layout exposes all packaged CCC plugin files needed for runtime lookup."
} else {
"The installed Cargo crate layout does not expose all packaged CCC plugin files needed for runtime lookup."
},
})
}
fn inspect_packaged_plugin_file_lookup() -> Value {
inspect_packaged_plugin_file_lookup_at(Path::new(env!("CARGO_MANIFEST_DIR")))
}
fn packaged_harness_surface_status_from_cap_skill_source(
source: io::Result<PathBuf>,
) -> &'static str {
if source.is_ok() {
"coherent_surface"
} else {
"incomplete_surface"
}
}
pub(crate) fn create_plugin_discovery_payload_at(codex_home: &Path) -> Value {
let root = plugin_cache_root_at(codex_home);
let required_paths = required_plugin_cache_file_lookups();
let mut present = Vec::new();
let mut missing = Vec::new();
let mut stale = Vec::new();
let mut unreadable = Vec::new();
let assets = required_paths
.iter()
.map(|lookup| {
let path = root.join(&lookup.relative_path);
let exists = path.is_file();
if exists {
present.push(Value::String(lookup.name.clone()));
} else {
missing.push(Value::String(lookup.name.clone()));
}
let state = if !exists {
"missing"
} else if let Some(crate_relative_path) = lookup.crate_relative_path.as_ref() {
match (
fs::read(&path),
expected_packaged_asset_bytes(crate_relative_path, &lookup.relative_path, true),
) {
(Ok(installed), Ok(expected)) if installed == expected => "current",
(Ok(_), Ok(_)) => {
stale.push(Value::String(lookup.name.clone()));
"stale"
}
_ => {
unreadable.push(Value::String(lookup.name.clone()));
"unreadable"
}
}
} else {
"current"
};
json!({
"name": lookup.name,
"relative_path": lookup.relative_path.to_string_lossy(),
"source": lookup.source,
"path": path.to_string_lossy(),
"exists": exists,
"state": state,
})
})
.collect::<Vec<_>>();
let status = if !missing.is_empty() {
"missing"
} else if !stale.is_empty() || !unreadable.is_empty() {
"stale"
} else {
"current"
};
let diagnostic_severity = match status {
"current" => "ok",
"stale" => "warning",
_ => "error",
};
let missing_count = missing.len();
let stale_count = stale.len();
json!({
"schema": "ccc.plugin_discovery.v1",
"status": status,
"check_install_status": if status == "current" { "ok" } else { "warning" },
"diagnostic_severity": diagnostic_severity,
"restart_required": status != "current",
"plugin_cache_root": root.to_string_lossy(),
"required_asset_count": required_paths.len(),
"present": present,
"missing": missing,
"stale": stale,
"unreadable": unreadable,
"missing_count": missing_count,
"stale_count": stale_count,
"assets": assets,
"summary": if status == "current" {
"Current CCC plugin cache discovery is complete; restart/compaction can rediscover $cap from the plugin skill path."
} else if status == "stale" {
"Current CCC plugin cache discovery is stale; run `ccc setup` and restart Codex CLI before relying on $cap continuity."
} else {
"Current CCC plugin cache discovery is incomplete; run `ccc setup` and restart Codex CLI before relying on $cap continuity."
},
})
}
fn inspect_plugin_marketplace_surface_at(root: &Path) -> Value {
let surface_root = root.join("plugins").join("ccc");
let lookups = required_plugin_marketplace_surface_lookups();
let mut missing = Vec::new();
let mut stale = Vec::new();
let assets = lookups
.iter()
.map(|lookup| {
let path = surface_root.join(&lookup.plugin_relative_path);
let exists = path.is_file();
let state = if !exists {
missing.push(Value::String(lookup.name.clone()));
"missing"
} else {
match (
fs::read(&path),
expected_packaged_asset_bytes(
&lookup.crate_relative_path,
&lookup.plugin_relative_path,
false,
),
) {
(Ok(installed), Ok(expected)) if installed == expected => "current",
_ => {
stale.push(Value::String(lookup.name.clone()));
"stale"
}
}
};
json!({
"name": lookup.name,
"relative_path": lookup.plugin_relative_path.to_string_lossy(),
"path": path.to_string_lossy(),
"exists": exists,
"state": state,
})
})
.collect::<Vec<_>>();
let status = if !missing.is_empty() {
"missing"
} else if !stale.is_empty() {
"stale"
} else {
"current"
};
json!({
"status": status,
"path": surface_root.to_string_lossy(),
"missing": missing,
"stale": stale,
"assets": assets,
})
}
fn marketplace_index_status_at(index_path: &Path) -> &'static str {
let Ok(index) = fs::read(index_path) else {
return "missing";
};
let Ok(index) = serde_json::from_slice::<Value>(&index) else {
return "stale";
};
let has_canonical_ccc_entry = index
.get("plugins")
.and_then(Value::as_array)
.into_iter()
.flatten()
.any(|plugin| {
plugin.get("name").and_then(Value::as_str) == Some("ccc")
&& plugin.pointer("/source/source").and_then(Value::as_str) == Some("local")
&& plugin.pointer("/source/path").and_then(Value::as_str) == Some("./plugins/ccc")
});
if has_canonical_ccc_entry {
"current"
} else {
"stale"
}
}
pub(crate) fn create_plugin_marketplace_discovery_payload_at_home(home: &Path) -> Value {
let root = plugin_marketplace_root_at_home(home);
let index_path = root
.join(".agents")
.join("plugins")
.join("marketplace.json");
let index_status = marketplace_index_status_at(&index_path);
let surface = inspect_plugin_marketplace_surface_at(&root);
let surface_status = surface
.get("status")
.and_then(Value::as_str)
.unwrap_or("unreadable");
let status = if index_status == "missing" || surface_status == "missing" {
"missing"
} else if index_status == "stale" || surface_status == "stale" {
"stale"
} else {
"current"
};
json!({
"schema": "ccc.plugin_marketplace_discovery.v1",
"status": status,
"restart_required": status != "current",
"root": root.to_string_lossy(),
"index": {
"status": index_status,
"path": index_path.to_string_lossy(),
},
"surface": surface,
"summary": if status == "current" {
"CCC plugin marketplace discovery is current."
} else {
"CCC plugin marketplace discovery is missing or stale; run `ccc setup` and restart Codex CLI."
},
})
}
fn create_plugin_marketplace_discovery_payload() -> Value {
let Some(home) = env::var_os("HOME").map(PathBuf::from) else {
return json!({
"schema": "ccc.plugin_marketplace_discovery.v1",
"status": "unreadable",
"restart_required": true,
"summary": "CCC plugin marketplace discovery could not resolve HOME.",
});
};
create_plugin_marketplace_discovery_payload_at_home(&home)
}
fn run_codex_text_command(args: &[&str]) -> Result<String, String> {
let output = Command::new("codex")
.args(args)
.output()
.map_err(|error| error.to_string())?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
return Err(if stderr.is_empty() {
format!("codex {} exited with {}.", args.join(" "), output.status)
} else {
stderr
});
}
Ok(String::from_utf8_lossy(&output.stdout).to_string())
}
pub(crate) fn create_plugin_cli_parity_payload_from_text(
plugin_list_text: &str,
marketplace_list_text: &str,
) -> Value {
let ccc_marketplace_line = marketplace_list_text
.lines()
.find(|line| line.trim_start().starts_with("ccc-local"))
.map(str::trim)
.unwrap_or_default();
let ccc_plugin_line = plugin_list_text
.lines()
.find(|line| line.contains("ccc@ccc-local"))
.map(str::trim)
.unwrap_or_default();
let marketplace_mentions_ccc = !ccc_marketplace_line.is_empty();
let plugin_mentions_ccc = !ccc_plugin_line.is_empty();
let plugin_installed = ccc_plugin_line.contains("installed");
let plugin_enabled = ccc_plugin_line.contains("enabled");
let status = if marketplace_mentions_ccc && plugin_installed && plugin_enabled {
"current"
} else if marketplace_mentions_ccc || plugin_mentions_ccc {
"stale"
} else {
"missing"
};
json!({
"schema": "ccc.plugin_cli_parity.v1",
"status": status,
"source": "codex_plugin_cli_text_surfaces",
"commands": ["codex plugin marketplace list", "codex plugin list"],
"marketplace_mentions_ccc": marketplace_mentions_ccc,
"plugin_mentions_ccc": plugin_mentions_ccc,
"plugin_installed": plugin_installed,
"plugin_enabled": plugin_enabled,
"ccc_marketplace_line": ccc_marketplace_line,
"ccc_plugin_line": ccc_plugin_line,
"summary": if status == "current" {
"Codex Plugin CLI surfaces mention ccc-local and show ccc@ccc-local installed and enabled."
} else {
"Codex Plugin CLI surfaces do not yet show ccc@ccc-local as installed and enabled."
},
})
}
fn create_plugin_cli_parity_payload() -> Value {
let plugin_list = run_codex_text_command(&["plugin", "list"]);
let marketplace_list = run_codex_text_command(&["plugin", "marketplace", "list"]);
match (plugin_list, marketplace_list) {
(Ok(plugin_list), Ok(marketplace_list)) => {
create_plugin_cli_parity_payload_from_text(&plugin_list, &marketplace_list)
}
(plugin_result, marketplace_result) => json!({
"schema": "ccc.plugin_cli_parity.v1",
"status": "unreadable",
"source": "codex_plugin_cli_text_surfaces",
"commands": ["codex plugin marketplace list", "codex plugin list"],
"plugin_list_error": plugin_result.err().unwrap_or_default(),
"marketplace_list_error": marketplace_result.err().unwrap_or_default(),
"summary": "Codex Plugin CLI parity could not be inspected.",
}),
}
}
pub(crate) fn create_permission_profile_payload(
session_context: &SessionContext,
workspace_root: &Path,
config: &Value,
current_task_card: Option<&Value>,
) -> Value {
let current_role = current_task_card
.and_then(|task| task.get("assigned_role").and_then(Value::as_str))
.unwrap_or("unassigned");
let role_snapshot = current_task_card
.and_then(|task| task.get("role_config_snapshot"))
.or_else(|| {
config
.get("agents")
.and_then(|agents| agents.get(current_role))
});
let configured_profile = role_snapshot
.and_then(|snapshot| snapshot.get("profile"))
.cloned()
.unwrap_or(Value::Null);
let sandbox_mode = current_task_card
.and_then(|task| task.get("sandbox_mode"))
.cloned()
.unwrap_or(Value::Null);
let mut roots = vec![
json!({
"kind": "workspace_root",
"path": workspace_root.to_string_lossy(),
"effective": true,
"writable_by_ccc": true,
}),
json!({
"kind": "workspace_ccc_store",
"path": workspace_root.join(".ccc").to_string_lossy(),
"effective": true,
"writable_by_ccc": true,
}),
json!({
"kind": "shared_config",
"path": session_context.shared_config_path,
"effective": true,
"writable_by_ccc": true,
}),
];
if let Ok(codex_home) = resolve_codex_home() {
roots.push(json!({
"kind": "codex_home",
"path": codex_home.to_string_lossy(),
"effective": true,
"writable_by_ccc": false,
}));
}
json!({
"schema": "ccc.permission_profile.v1",
"status": "available",
"current_role": current_role,
"configured_profile": configured_profile,
"sandbox_mode": sandbox_mode,
"host_permission_profile_source": "codex_session_context_and_ccc_config",
"host_sandbox_reported_by_codex": false,
"effective_workspace_roots": roots,
"summary": "CCC surfaces the role profile, sandbox mode, and effective workspace roots it can derive from the current session and config.",
})
}
pub(crate) fn create_plugin_discovery_surfaces_payload(
plugin_cache: &Value,
marketplace: &Value,
cap_skill: &Value,
legacy_bundle_cleanup: &Value,
install_surface_visibility: &Value,
) -> Value {
let plugin_cache_status = plugin_cache
.get("status")
.and_then(Value::as_str)
.unwrap_or("unknown");
let marketplace_status = marketplace
.get("status")
.and_then(Value::as_str)
.unwrap_or("unknown");
let cap_skill_status = cap_skill
.get("status")
.and_then(Value::as_str)
.unwrap_or("unknown");
let stale_path_count = legacy_bundle_cleanup
.get("stalePathCount")
.and_then(Value::as_u64)
.unwrap_or(0);
let restart_required = install_surface_visibility
.get("restart_required")
.and_then(Value::as_bool)
.unwrap_or(false)
|| plugin_cache
.get("restart_required")
.and_then(Value::as_bool)
.unwrap_or(false)
|| marketplace
.get("restart_required")
.and_then(Value::as_bool)
.unwrap_or(false);
let status = if [plugin_cache_status, marketplace_status, cap_skill_status]
.iter()
.any(|status| matches!(*status, "missing" | "missing_install"))
{
"missing"
} else if [plugin_cache_status, marketplace_status, cap_skill_status]
.iter()
.any(|status| matches!(*status, "stale" | "mismatched_install"))
{
"stale"
} else if [plugin_cache_status, marketplace_status, cap_skill_status]
.iter()
.all(|status| matches!(*status, "current" | "matching_install"))
{
"current"
} else {
"warning"
};
json!({
"schema": "ccc.plugin_discovery_surfaces.v1",
"status": status,
"marketplace_status": marketplace_status,
"plugin_cache_status": plugin_cache_status,
"cap_skill_status": cap_skill_status,
"stale_path_count": stale_path_count,
"restart_required": restart_required,
"restart_requirement": if restart_required { "required" } else { "not-required" },
"summary": format!(
"Discovery surfaces: status={status} marketplace={marketplace_status} plugin_cache={plugin_cache_status} cap_skill={cap_skill_status} stale_paths={stale_path_count} restart={}",
if restart_required { "required" } else { "not-required" }
),
})
}
fn create_plugin_discovery_payload() -> Value {
match resolve_codex_home() {
Ok(codex_home) => create_plugin_discovery_payload_at(&codex_home),
Err(error) => {
let required_paths = required_plugin_cache_file_lookups();
json!({
"schema": "ccc.plugin_discovery.v1",
"status": "unreadable",
"check_install_status": "warning",
"diagnostic_severity": "error",
"restart_required": true,
"plugin_cache_root": Value::Null,
"required_asset_count": required_paths.len(),
"present": [],
"missing": required_paths
.iter()
.map(|lookup| lookup.name.clone())
.collect::<Vec<_>>(),
"assets": [],
"summary": format!("CCC plugin cache discovery could not resolve CODEX_HOME: {error}."),
})
}
}
}
fn resolve_accepted_launch_commands(expected_command: &str) -> Vec<String> {
let mut commands = vec![expected_command.to_string()];
if let Ok(plugin_cache_command) = resolve_plugin_cache_launch_command() {
if !commands.contains(&plugin_cache_command) {
commands.push(plugin_cache_command);
}
}
commands
}
fn read_codex_mcp_registry() -> io::Result<Vec<CodexMcpRegistryRecord>> {
let output = Command::new("codex")
.arg("mcp")
.arg("list")
.arg("--json")
.output()?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
return Err(io::Error::new(
io::ErrorKind::Other,
format!(
"codex mcp list --json failed with {}. {}",
output.status,
if stderr.is_empty() {
"No stderr output.".to_string()
} else {
stderr
}
),
));
}
serde_json::from_slice::<Vec<CodexMcpRegistryRecord>>(&output.stdout).map_err(|error| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("Unable to parse codex mcp list --json output: {error}"),
)
})
}
fn find_ccc_registration(records: &[CodexMcpRegistryRecord]) -> Option<&CodexMcpRegistryRecord> {
records.iter().find(|record| record.name == SERVER_NAME)
}
fn registration_matches_expected(
record: &CodexMcpRegistryRecord,
expected_command: &str,
expected_args: &[String],
) -> bool {
let accepted_commands = resolve_accepted_launch_commands(expected_command);
registration_matches_any_expected(record, &accepted_commands, expected_args)
}
fn registration_matches_any_expected(
record: &CodexMcpRegistryRecord,
accepted_commands: &[String],
expected_args: &[String],
) -> bool {
if !record.enabled {
return false;
}
let Some(transport) = record.transport.as_ref() else {
return false;
};
if transport.transport_type != "stdio" {
return false;
}
let Some(command) = transport.command.as_ref() else {
return false;
};
accepted_commands.contains(&normalize_registered_command(command))
&& transport.args.clone().unwrap_or_default() == expected_args
}
fn resolve_cap_skill_install_path() -> io::Result<PathBuf> {
Ok(resolve_codex_home()?
.join("plugins")
.join("cache")
.join("ccc-local")
.join("ccc")
.join(env!("CARGO_PKG_VERSION"))
.join("skills")
.join(PUBLIC_ENTRY_SKILL_NAME)
.join("SKILL.md"))
}
fn resolve_packaged_cap_skill_source() -> io::Result<PathBuf> {
let current_exe = env::current_exe()?;
let current_exe = fs::canonicalize(¤t_exe).unwrap_or(current_exe);
let mut candidates = Vec::new();
if let Some(cap_skill_lookup) = required_packaged_plugin_file_lookups()
.into_iter()
.find(|lookup| lookup.name == "cap_skill")
{
candidates.push(
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(cap_skill_lookup.crate_relative_path),
);
}
if let Some(parent) = current_exe.parent() {
candidates.push(
parent
.join("share")
.join("skills")
.join(PUBLIC_ENTRY_SKILL_NAME)
.join("SKILL.md"),
);
if let Some(grandparent) = parent.parent() {
candidates.push(
grandparent
.join("share")
.join("skills")
.join(PUBLIC_ENTRY_SKILL_NAME)
.join("SKILL.md"),
);
}
for ancestor in parent.ancestors().take(6) {
candidates.push(
ancestor
.join("skills")
.join(PUBLIC_ENTRY_SKILL_NAME)
.join("SKILL.md"),
);
}
}
candidates.push(
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../../skills")
.join(PUBLIC_ENTRY_SKILL_NAME)
.join("SKILL.md"),
);
for candidate in candidates {
if candidate.exists() {
return Ok(candidate);
}
}
Err(io::Error::new(
io::ErrorKind::NotFound,
"Unable to locate the packaged $cap skill next to the Rust binary or source tree.",
))
}
pub(crate) fn install_packaged_cap_skill() -> io::Result<(PathBuf, bool)> {
let source = resolve_packaged_cap_skill_source()?;
let destination = resolve_cap_skill_install_path()?;
if let Some(parent) = destination.parent() {
fs::create_dir_all(parent)?;
}
let destination_exists = destination.exists();
fs::copy(source, &destination)?;
Ok((destination, !destination_exists))
}
pub(crate) fn inspect_packaged_cap_skill_install_at(
source_path: &Path,
install_path: &Path,
) -> io::Result<Value> {
let source_contents = fs::read_to_string(source_path)?;
let installed_contents = match fs::read_to_string(install_path) {
Ok(contents) => Some(contents),
Err(error) if error.kind() == io::ErrorKind::NotFound => None,
Err(error) => return Err(error),
};
let (status, action_status, restart_status, summary) = match installed_contents {
Some(contents) if contents == source_contents => (
"matching_install",
"preserved",
"not-required",
format!(
"The packaged $cap skill is current under {}.",
install_path.display()
),
),
Some(_) => (
"mismatched_install",
"setup-refresh-available",
"restart-required-after-setup",
format!(
"The packaged $cap skill under {} differs from {}; run setup and restart Codex CLI.",
install_path.display(),
source_path.display()
),
),
None => (
"missing_install",
"setup-install-available",
"restart-required-after-setup",
format!(
"The packaged $cap skill is missing under {}; run setup and restart Codex CLI.",
install_path.display()
),
),
};
Ok(json!({
"status": status,
"action_status": action_status,
"restart_status": restart_status,
"summary": summary,
"path": install_path.to_string_lossy(),
"source_path": source_path.to_string_lossy(),
}))
}
fn inspect_packaged_cap_skill_install() -> Value {
let install_path = match resolve_cap_skill_install_path() {
Ok(path) => path,
Err(error) => {
return json!({
"status": "unreadable_install",
"action_status": "inspection-blocked",
"restart_status": "unknown",
"summary": error.to_string(),
"path": Value::Null,
"source_path": Value::Null,
});
}
};
let source_path = match resolve_packaged_cap_skill_source() {
Ok(path) => path,
Err(error) => {
return json!({
"status": "packaged-source-unavailable",
"action_status": "blocked",
"restart_status": "unknown",
"summary": error.to_string(),
"path": install_path.to_string_lossy(),
"source_path": Value::Null,
});
}
};
inspect_packaged_cap_skill_install_at(&source_path, &install_path).unwrap_or_else(|error| {
json!({
"status": "unreadable_install",
"action_status": "inspection-blocked",
"restart_status": "unknown",
"summary": error.to_string(),
"path": install_path.to_string_lossy(),
"source_path": source_path.to_string_lossy(),
})
})
}
pub(crate) fn ensure_matching_mcp_registration() -> io::Result<&'static str> {
let (expected_command, expected_args) = resolve_expected_launch_command()?;
let records = read_codex_mcp_registry()?;
if let Some(record) = find_ccc_registration(&records) {
if registration_matches_expected(record, &expected_command, &expected_args) {
return Ok("already_registered");
}
let remove_status = Command::new("codex")
.arg("mcp")
.arg("remove")
.arg(SERVER_NAME)
.status()?;
if !remove_status.success() {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("Failed to remove the existing {SERVER_NAME} MCP registration."),
));
}
}
let mut add_command = Command::new("codex");
add_command
.arg("mcp")
.arg("add")
.arg(SERVER_NAME)
.arg("--")
.arg(&expected_command);
for arg in &expected_args {
add_command.arg(arg);
}
let add_status = add_command.status()?;
if !add_status.success() {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("Failed to add the {SERVER_NAME} MCP registration."),
));
}
Ok("registered")
}
pub(crate) fn create_registration_visibility_payload(status: &str, summary: &str) -> Value {
let (surface_status, action_status, restart_status) = match status {
"matching_registration" => ("current", "preserved", "not-required"),
"missing_registration" => (
"missing",
"setup-register-available",
"restart-required-after-setup",
),
"mismatched_registration" => (
"stale",
"setup-refresh-available",
"restart-required-after-setup",
),
"unreadable_registration" => ("unreadable", "inspection-blocked", "unknown"),
_ => ("unknown", "inspection-blocked", "unknown"),
};
json!({
"status": surface_status,
"raw_status": status,
"action_status": action_status,
"restart_status": restart_status,
"summary": summary,
})
}
pub(crate) fn create_config_visibility_payload(state: &CccConfigInstallState) -> Value {
let surface_status = match state.status {
"canonical-current" => "current",
"canonical-needs-backfill" => "stale",
"legacy-only" | "missing" => "missing",
"migrated-from-previous" | "created" | "rollback-restored" => "migrated",
"conflict" => "conflict",
"unreadable" => "unreadable",
_ => "unknown",
};
json!({
"status": surface_status,
"raw_status": state.status,
"action_status": state.action_status,
"backup_status": state.backup_status,
"restart_status": state.restart_status,
"summary": state.summary.clone(),
"source_path": state.source_path_value(),
"backup_source_path": state.backup_source_path_value(),
"backup_path": state.backup_path_value(),
"entry_policy_mode_status": state.entry_policy_mode_status,
"entry_policy_mode_raw": state.entry_policy_mode_raw_value(),
"entry_policy_mode_canonical": state.entry_policy_mode_canonical_value(),
"entry_policy_mode_summary": state.entry_policy_mode_summary.clone(),
"setup_migration_deltas": state.setup_migration_deltas_value(),
})
}
pub(crate) fn create_custom_agent_visibility_payload(sync: &Value) -> Value {
let raw_status = sync
.get("status")
.and_then(Value::as_str)
.unwrap_or("unavailable");
let (surface_status, action_status, restart_status) = match raw_status {
"matching_sync" => ("current", "preserved", "not-required"),
"missing_sync" => (
"missing",
"setup-sync-available",
"restart-required-after-setup",
),
"mismatched_sync" => (
"stale",
"setup-sync-available",
"restart-required-after-setup",
),
"unreadable_sync" => ("unreadable", "inspection-blocked", "unknown"),
_ => ("unknown", "inspection-blocked", "unknown"),
};
json!({
"status": surface_status,
"raw_status": raw_status,
"action_status": action_status,
"restart_status": restart_status,
"summary": sync.get("summary").cloned().unwrap_or(Value::Null),
"directory_path": sync.get("directory_path").cloned().unwrap_or(Value::Null),
"missing_files": sync.get("missing_files").cloned().unwrap_or_else(|| Value::Array(Vec::new())),
"mismatched_files": sync.get("mismatched_files").cloned().unwrap_or_else(|| Value::Array(Vec::new())),
"stale_managed_files": sync.get("stale_managed_files").cloned().unwrap_or_else(|| Value::Array(Vec::new())),
})
}
pub(crate) fn create_skill_visibility_payload(skill: &Value) -> Value {
let raw_status = skill
.get("status")
.and_then(Value::as_str)
.unwrap_or("unavailable");
let surface_status = match raw_status {
"matching_install" => "current",
"missing_install" => "missing",
"mismatched_install" => "stale",
"packaged-source-unavailable" | "unreadable_install" => "unreadable",
_ => "unknown",
};
json!({
"status": surface_status,
"raw_status": raw_status,
"action_status": skill.get("action_status").cloned().unwrap_or(Value::String("inspection-blocked".to_string())),
"restart_status": skill.get("restart_status").cloned().unwrap_or(Value::String("unknown".to_string())),
"summary": skill.get("summary").cloned().unwrap_or(Value::Null),
"path": skill.get("path").cloned().unwrap_or(Value::Null),
"source_path": skill.get("source_path").cloned().unwrap_or(Value::Null),
})
}
fn create_cap_continuity_payload(cap_skill: &Value, plugin_discovery: &Value) -> Value {
let cap_status = cap_skill
.get("status")
.and_then(Value::as_str)
.unwrap_or("unavailable");
let plugin_status = plugin_discovery
.get("status")
.and_then(Value::as_str)
.unwrap_or("unavailable");
let continuity_status = if cap_status == "matching_install" && plugin_status == "current" {
"current"
} else {
"lost"
};
json!({
"schema": "ccc.cap_continuity.v1",
"status": continuity_status,
"cap_skill_status": cap_status,
"plugin_discovery_status": plugin_status,
"cap_skill_path": cap_skill.get("path").cloned().unwrap_or(Value::Null),
"cap_skill_source_path": cap_skill.get("source_path").cloned().unwrap_or(Value::Null),
"plugin_cache_root": plugin_discovery.get("plugin_cache_root").cloned().unwrap_or(Value::Null),
"restart_required": continuity_status != "current",
"automatic_restart": false,
"slash_command_execution": false,
"resume_command_template": "$cap continue <run_id>",
"checkpoint_command_template": "ccc orchestrate --quiet --json '{\"run_id\":\"<run_id>\",\"compact\":true,\"resolve_summary\":\"Checkpoint before Codex CLI session rollover.\"}'",
"restart_sequence": [
"run the checkpoint command when status recommends rollover",
"operator chooses /compact, /new, /exit, or restarts Codex CLI manually",
"resume with $cap continue <run_id>"
],
"slash_command_boundary": "CCC records restart/compaction handoff guidance but does not execute Codex TUI slash commands or restart Codex CLI automatically.",
"summary": if continuity_status == "current" {
"$cap continuity is available through the current plugin cache skill path after restart or context compaction."
} else {
"$cap continuity is not fully discoverable; run `ccc setup` and restart Codex CLI before relying on restart or compaction handoff."
},
})
}
fn create_skill_registry_health_payload() -> Value {
let agents = managed_skill_ssl_agent_names()
.into_iter()
.map(|agent_name| {
let registry = load_skill_registry_for_agent(&agent_name, &json!({}));
json!({
"agent_name": agent_name,
"status": registry.get("status").cloned().unwrap_or(Value::String("missing".to_string())),
"manifest_status": registry.get("manifest_status").cloned().unwrap_or(Value::String("missing".to_string())),
"path": registry.pointer("/skill_ssl_manifest/path").cloned().unwrap_or(Value::Null),
"reason": registry.pointer("/skill_ssl_manifest/reason").cloned().unwrap_or(Value::Null),
})
})
.collect::<Vec<_>>();
let available_count = agents
.iter()
.filter(|agent| agent.get("status").and_then(Value::as_str) == Some("available"))
.count();
let non_available = agents
.iter()
.filter(|agent| agent.get("status").and_then(Value::as_str) != Some("available"))
.cloned()
.collect::<Vec<_>>();
json!({
"schema": "ccc.skill_registry_health.v1",
"status": if non_available.is_empty() { "ok" } else { "warning" },
"agent_count": agents.len(),
"available_count": available_count,
"non_available_count": non_available.len(),
"agents": agents,
"non_available": non_available,
"summary": if non_available.is_empty() {
"All managed custom-agent SSL manifests are available."
} else {
"One or more managed custom-agent SSL manifests are missing, stale, invalid, or drifted."
},
})
}
fn source_repo_root_from_manifest_dir_at(manifest_dir: &Path) -> Option<PathBuf> {
let source_root = manifest_dir
.parent()
.and_then(Path::parent)
.map(Path::to_path_buf)?;
source_root
.join("skills")
.join("ssl")
.is_dir()
.then_some(source_root)
}
fn source_repo_root_from_manifest_dir() -> Option<PathBuf> {
source_repo_root_from_manifest_dir_at(Path::new(env!("CARGO_MANIFEST_DIR")))
}
fn resolve_public_or_packaged_cap_skill_source() -> io::Result<PathBuf> {
if let Some(repo_root) = source_repo_root_from_manifest_dir() {
let public_source = repo_root.join("skills").join("cap").join("SKILL.md");
if public_source.exists() {
return Ok(public_source);
}
}
resolve_packaged_cap_skill_source()
}
fn expected_ssl_manifest_source_paths_at(
manifest_dir: &Path,
agent_name: &str,
) -> Vec<(String, Option<PathBuf>)> {
let file_name = format!("{agent_name}.skill.ssl.json");
let mut paths = Vec::new();
if let Some(repo_root) = source_repo_root_from_manifest_dir_at(manifest_dir) {
paths.push((
"public".to_string(),
Some(repo_root.join("skills").join("ssl").join(&file_name)),
));
}
paths.push((
"packaged".to_string(),
Some(
manifest_dir
.join("assets")
.join("skills")
.join("ssl")
.join(file_name),
),
));
paths
}
fn missing_ssl_manifest_source(agent_name: &str, source: &str, path: Option<&Path>) -> Value {
json!({
"status": "missing",
"agent_name": agent_name,
"source": source,
"path": path.map(|value| value.to_string_lossy().to_string()).unwrap_or_default(),
"reason": format!("{source} SSL manifest source is missing."),
})
}
fn create_command_budget_ssl_manifest_sources(
agent_name: &str,
) -> Vec<(String, String, Option<PathBuf>, Value)> {
create_command_budget_ssl_manifest_sources_at(Path::new(env!("CARGO_MANIFEST_DIR")), agent_name)
}
fn create_command_budget_ssl_manifest_sources_at(
manifest_dir: &Path,
agent_name: &str,
) -> Vec<(String, String, Option<PathBuf>, Value)> {
expected_ssl_manifest_source_paths_at(manifest_dir, agent_name)
.into_iter()
.map(|(source, path)| {
let manifest = path
.as_ref()
.filter(|candidate| candidate.exists())
.map(|candidate| load_skill_ssl_manifest_from_path(agent_name, candidate))
.unwrap_or_else(|| {
missing_ssl_manifest_source(agent_name, &source, path.as_deref())
});
(agent_name.to_string(), source, path, manifest)
})
.collect()
}
#[cfg(test)]
pub(crate) fn create_command_budget_route_modularity_payload_from_sources(
cap_skill_source_path: Option<&Path>,
cap_skill_text: Option<&str>,
cap_skill_source_error: Option<&str>,
ssl_manifests: Vec<(String, Value)>,
route_modularity: Value,
) -> Value {
let ssl_manifest_sources = ssl_manifests
.into_iter()
.map(|(agent_name, manifest)| {
let path = manifest
.get("path")
.and_then(Value::as_str)
.filter(|value| !value.is_empty())
.map(PathBuf::from);
(agent_name, "provided".to_string(), path, manifest)
})
.collect::<Vec<_>>();
create_command_budget_route_modularity_payload_from_manifest_sources(
cap_skill_source_path,
cap_skill_text,
cap_skill_source_error,
ssl_manifest_sources,
route_modularity,
)
}
pub(crate) fn create_command_budget_route_modularity_payload_from_manifest_sources(
cap_skill_source_path: Option<&Path>,
cap_skill_text: Option<&str>,
cap_skill_source_error: Option<&str>,
ssl_manifests: Vec<(String, String, Option<PathBuf>, Value)>,
route_modularity: Value,
) -> Value {
const CAP_SKILL_MAX_LINES: usize = 80;
const CAP_SKILL_MAX_WORDS: usize = 700;
const SSL_SCENE_MAX_COUNT: usize = 4;
const SSL_ACTION_MAX_COUNT: usize = 3;
let mut problems = Vec::new();
let cap_text = cap_skill_text.unwrap_or_default();
let cap_line_count = cap_text.lines().count();
let cap_word_count = cap_text.split_whitespace().count();
let hidden_routing_fragments = [
"routing.categories",
"selected_category",
"selected_role",
"request_shape",
"intent_types",
"companion_tool_route",
"operator_control",
"write_code",
"read_repo",
"keywords",
];
let cap_text_lower = cap_text.to_ascii_lowercase();
let hidden_routing_hits = hidden_routing_fragments
.iter()
.filter(|fragment| cap_text_lower.contains(&fragment.to_ascii_lowercase()))
.copied()
.collect::<Vec<_>>();
if cap_skill_text.is_none() {
problems.push(json!({
"surface": "skills/cap/SKILL.md",
"reason": "$cap skill source missing or unreadable",
"path": cap_skill_source_path
.map(|path| path.to_string_lossy().to_string())
.unwrap_or_default(),
"detail": cap_skill_source_error.unwrap_or("No public or packaged $cap skill source could be read."),
}));
}
if cap_line_count > CAP_SKILL_MAX_LINES {
problems.push(json!({
"surface": "skills/cap/SKILL.md",
"reason": "public cap skill line budget exceeded",
"actual": cap_line_count,
"max": CAP_SKILL_MAX_LINES,
}));
}
if cap_word_count > CAP_SKILL_MAX_WORDS {
problems.push(json!({
"surface": "skills/cap/SKILL.md",
"reason": "public cap skill word budget exceeded",
"actual": cap_word_count,
"max": CAP_SKILL_MAX_WORDS,
}));
}
if !hidden_routing_hits.is_empty() {
problems.push(json!({
"surface": "skills/cap/SKILL.md",
"reason": "public cap skill contains route-table policy fragments",
"fragments": hidden_routing_hits,
}));
}
let ssl_checks = ssl_manifests
.into_iter()
.map(|(agent_name, source, source_path, manifest)| {
let status = manifest
.get("status")
.and_then(Value::as_str)
.unwrap_or("missing");
let role_family = manifest
.pointer("/scheduling/role_family")
.and_then(Value::as_str)
.unwrap_or("missing");
let mutation_allowed = manifest
.pointer("/scheduling/mutation_allowed")
.and_then(Value::as_bool);
let scene_count = manifest
.pointer("/structural/scenes")
.and_then(Value::as_array)
.map(Vec::len)
.unwrap_or(0);
let action_count = manifest
.pointer("/logical/actions")
.and_then(Value::as_array)
.map(Vec::len)
.unwrap_or(0);
let expected_role_family =
expected_skill_ssl_role_family_for_agent(&agent_name).unwrap_or("unknown");
let expected_mutation_allowed =
expected_skill_ssl_mutation_allowed_for_agent(&agent_name);
let mut agent_problems = Vec::new();
if status != "available" {
agent_problems.push("manifest_unavailable");
}
if role_family != expected_role_family {
agent_problems.push("role_family_drift");
}
if mutation_allowed != expected_mutation_allowed {
agent_problems.push("mutation_allowed_drift");
}
if scene_count > SSL_SCENE_MAX_COUNT {
agent_problems.push("scene_budget_exceeded");
}
if action_count > SSL_ACTION_MAX_COUNT {
agent_problems.push("action_budget_exceeded");
}
if !agent_problems.is_empty() {
problems.push(json!({
"surface": format!("skills/ssl/{agent_name}.skill.ssl.json"),
"source": source,
"path": source_path
.as_ref()
.map(|path| path.to_string_lossy().to_string())
.unwrap_or_default(),
"reason": "SSL manifest drifted from Rust specialist role or budget",
"problems": agent_problems,
}));
}
json!({
"agent_name": agent_name,
"source": source,
"path": source_path
.as_ref()
.map(|path| path.to_string_lossy().to_string())
.unwrap_or_default(),
"status": status,
"role_family": role_family,
"expected_role_family": expected_role_family,
"mutation_allowed": mutation_allowed,
"expected_mutation_allowed": expected_mutation_allowed,
"scene_count": scene_count,
"scene_max": SSL_SCENE_MAX_COUNT,
"action_count": action_count,
"action_max": SSL_ACTION_MAX_COUNT,
})
})
.collect::<Vec<_>>();
if route_modularity.get("status").and_then(Value::as_str) != Some("ok") {
problems.push(json!({
"surface": "request_routing.rs",
"reason": "route modularity check reported drift",
"details": route_modularity.get("problems").cloned().unwrap_or_else(|| Value::Array(Vec::new())),
}));
}
json!({
"schema": "ccc.command_budget_route_modularity.v1",
"status": if problems.is_empty() { "ok" } else { "warning" },
"runtime_truth": false,
"cap_skill": {
"status": if cap_skill_text.is_some() { "available" } else { "missing_or_unreadable" },
"path": cap_skill_source_path
.map(|path| path.to_string_lossy().to_string())
.unwrap_or_default(),
"read_error": cap_skill_source_error.unwrap_or_default(),
"line_count": cap_line_count,
"line_max": CAP_SKILL_MAX_LINES,
"word_count": cap_word_count,
"word_max": CAP_SKILL_MAX_WORDS,
"hidden_routing_fragment_hits": hidden_routing_hits,
},
"ssl_manifest_checks": ssl_checks,
"route_modularity": route_modularity,
"problem_count": problems.len(),
"problems": problems,
"summary": if problems.is_empty() {
"Public cap text, SSL manifests, and route categories stay within the command-budget and modularity bounds."
} else {
"Command-budget or route-modularity drift was detected in source surfaces."
},
})
}
fn create_command_budget_route_modularity_payload(config: &Value) -> Value {
let (cap_skill_source_path, cap_skill_text, cap_skill_source_error) =
match resolve_public_or_packaged_cap_skill_source() {
Ok(path) => match fs::read_to_string(&path) {
Ok(text) => (Some(path), Some(text), None),
Err(error) => (
Some(path.clone()),
None,
Some(format!(
"Unable to read $cap skill source {}: {error}",
path.display()
)),
),
},
Err(error) => (
None,
None,
Some(format!(
"Unable to locate packaged $cap skill source: {error}"
)),
),
};
let ssl_manifests = managed_skill_ssl_agent_names()
.into_iter()
.flat_map(|agent_name| create_command_budget_ssl_manifest_sources(&agent_name))
.collect::<Vec<_>>();
create_command_budget_route_modularity_payload_from_manifest_sources(
cap_skill_source_path.as_deref(),
cap_skill_text.as_deref(),
cap_skill_source_error.as_deref(),
ssl_manifests,
create_route_modularity_check_payload(config),
)
}
fn surface_payload(id: &str, status: &str, summary: impl Into<String>, source: &str) -> Value {
json!({
"surface": id,
"status": status,
"source": source,
"summary": summary.into(),
})
}
fn optional_missing_surface_payload(id: &str, summary: impl Into<String>, source: &str) -> Value {
surface_payload(id, "optional_missing", summary, source)
}
fn create_shared_config_version_surface(config_state: &CccConfigInstallState) -> Value {
let expected_version = env!("CARGO_PKG_VERSION");
let config = &config_state.value;
if !config_state.canonical_ready {
return json!({
"surface": "shared_config_version",
"status": "missing",
"source": "ccc_config.version",
"current_version": "unknown",
"expected_version": expected_version,
"summary": "Shared config version is unavailable until ccc-config.toml is migrated.",
});
}
let version = config.get("version");
let (status, current_version, summary) = match version {
None | Some(Value::Null) => (
"missing",
Value::String("unknown".to_string()),
"Shared config version is missing from ccc-config.toml.".to_string(),
),
Some(Value::String(version)) if version == expected_version => (
"current",
Value::String(version.clone()),
"Shared config version matches the current package version.".to_string(),
),
Some(Value::String(version)) => (
"stale",
Value::String(version.clone()),
format!("Shared config version is {version}; expected {expected_version}."),
),
Some(Value::Number(number)) => (
"stale",
Value::String(number.to_string()),
format!("Shared config version is {number}; expected {expected_version}."),
),
Some(Value::Bool(value)) => (
"stale",
Value::String(value.to_string()),
format!("Shared config version is {value}; expected {expected_version}."),
),
Some(other) => (
"conflict",
Value::String(other.to_string()),
format!(
"Shared config version has unsupported TOML type {other}. Expected {expected_version}."
),
),
};
json!({
"surface": "shared_config_version",
"status": status,
"source": "ccc_config.version",
"current_version": current_version,
"expected_version": expected_version,
"summary": summary,
})
}
fn create_config_surface_readiness_payload(
config_state: &CccConfigInstallState,
execution_contract_registry: &Value,
custom_agent_sync: &Value,
) -> Value {
let config = &config_state.value;
let canonical_ready = config_state.canonical_ready;
let runtime = config.get("runtime").and_then(Value::as_object);
let generated_version = config
.pointer("/generated_defaults/version")
.and_then(Value::as_u64)
.unwrap_or(0);
let compact_defaults_cover_internal_sections =
generated_version >= CURRENT_GENERATED_DEFAULTS_VERSION;
let canonical_missing = |id| {
surface_payload(
id,
"missing",
"Canonical ccc-config.toml is not ready; inspect setup migration guidance.",
"ccc_config",
)
};
let valid_mode = |mode| {
matches!(
mode,
"codex_subagent" | "codex_exec" | "visible_degraded_host_fallback"
)
};
let positive = |value: Option<&Value>| {
value.map(|value| {
value.as_u64().filter(|number| *number > 0).is_some()
|| value.as_i64().filter(|number| *number > 0).is_some()
})
};
let role_count = execution_contract_registry
.get("role_count")
.and_then(Value::as_u64)
.unwrap_or(0);
let expected_role_count = managed_custom_agent_role_count() as u64;
let registry = if execution_contract_registry
.get("status")
.and_then(Value::as_str)
== Some("available")
&& role_count == expected_role_count
{
surface_payload(
"registry",
"current",
"Execution contract registry covers all managed ccc_* roles.",
"execution_contract_registry",
)
} else if role_count > 0 {
surface_payload(
"registry",
"stale",
format!(
"Execution contract registry is partial: roles={role_count}/{expected_role_count}."
),
"execution_contract_registry",
)
} else {
surface_payload(
"registry",
"missing",
"Execution contract registry is unavailable.",
"execution_contract_registry",
)
};
let category_routing = match (
canonical_ready,
config.get("routing").and_then(Value::as_object),
) {
(false, _) => canonical_missing("category_routing"),
(true, None) if compact_defaults_cover_internal_sections => optional_missing_surface_payload(
"category_routing",
"Routing taxonomy is absent from the compact generated config; runtime will use Rust defaults.",
"ccc_config.routing",
),
(true, None) => surface_payload(
"category_routing",
"missing",
"Routing taxonomy is absent; runtime will use Rust defaults.",
"ccc_config.routing",
),
(true, Some(routing))
if routing.get("mode").and_then(Value::as_str) != Some("category_shortlist") =>
{
surface_payload(
"category_routing",
"conflict",
"Routing mode is unsupported for category shortlist routing.",
"ccc_config.routing.mode",
)
}
(true, Some(routing)) => {
let category_count = routing
.get("categories")
.and_then(Value::as_object)
.map(|categories| categories.len())
.unwrap_or(0);
if category_count == 0 {
surface_payload(
"category_routing",
"conflict",
"Routing categories are missing or empty.",
"ccc_config.routing.categories",
)
} else {
surface_payload(
"category_routing",
"current",
format!("Category routing is configured with {category_count} categories."),
"ccc_config.routing",
)
}
}
};
let fallback_policy = match (canonical_ready, runtime) {
(false, _) => canonical_missing("fallback_policy"),
(true, None) if compact_defaults_cover_internal_sections => optional_missing_surface_payload(
"fallback_policy",
"Runtime fallback policy is absent from the compact generated config; runtime will use Rust defaults.",
"ccc_config.runtime",
),
(true, None) => surface_payload(
"fallback_policy",
"missing",
"Runtime fallback policy is absent; runtime will use Rust defaults.",
"ccc_config.runtime",
),
(true, Some(runtime)) => {
let preferred = runtime
.get("preferred_specialist_execution_mode")
.and_then(Value::as_str);
let fallback = runtime
.get("fallback_specialist_execution_mode")
.and_then(Value::as_str);
match (preferred, fallback) {
(Some(preferred), Some(fallback))
if valid_mode(preferred) && valid_mode(fallback) =>
{
if fallback == "visible_degraded_host_fallback" {
surface_payload(
"fallback_policy",
"stale",
"Fallback policy uses the legacy visible degraded host fallback alias.",
"ccc_config.runtime.fallback_specialist_execution_mode",
)
} else {
surface_payload(
"fallback_policy",
"current",
format!(
"Fallback policy is configured: preferred={preferred} fallback={fallback}."
),
"ccc_config.runtime",
)
}
}
(Some(_), Some(_)) => surface_payload(
"fallback_policy",
"conflict",
"Fallback policy contains an unsupported execution mode.",
"ccc_config.runtime",
),
_ => surface_payload(
"fallback_policy",
"missing",
"Fallback policy is missing preferred or fallback execution mode.",
"ccc_config.runtime",
),
}
}
};
let concurrency = match (canonical_ready, runtime) {
(false, _) => canonical_missing("concurrency"),
(true, None) => optional_missing_surface_payload(
"concurrency",
"Optional host subagent concurrency settings are absent; runtime will use Rust defaults.",
"ccc_config.runtime",
),
(true, Some(runtime)) => match runtime.get("host_subagent_concurrency") {
Some(value) if !value.is_object() => surface_payload(
"concurrency",
"conflict",
"host_subagent_concurrency must be an object.",
"ccc_config.runtime.host_subagent_concurrency",
),
Some(value) => {
let nested = value.as_object().expect("checked object");
let invalid_limit = [
"default_provider_concurrency_limit",
"default_model_concurrency_limit",
]
.iter()
.any(|key| positive(nested.get(*key)) == Some(false));
if invalid_limit {
surface_payload(
"concurrency",
"conflict",
"Concurrency default limits must be positive integers when set.",
"ccc_config.runtime.host_subagent_concurrency",
)
} else {
surface_payload(
"concurrency",
"current",
"Host subagent concurrency is nested under runtime.host_subagent_concurrency.",
"ccc_config.runtime.host_subagent_concurrency",
)
}
}
None => {
let has_flat_keys = [
"host_subagent_default_provider_concurrency_limit",
"default_provider_concurrency_limit",
"host_subagent_default_model_concurrency_limit",
"default_model_concurrency_limit",
"host_subagent_provider_concurrency_limits",
"provider_concurrency_limits",
"host_subagent_model_concurrency_limits",
"model_concurrency_limits",
]
.iter()
.any(|key| runtime.contains_key(*key));
surface_payload(
"concurrency",
if has_flat_keys {
"stale"
} else {
"optional_missing"
},
if has_flat_keys {
"Host subagent concurrency uses legacy flat runtime keys."
} else {
"Optional host subagent concurrency settings are absent; runtime will use Rust defaults."
},
"ccc_config.runtime.host_subagent_concurrency",
)
}
},
};
let prompt_sections = match (
canonical_ready,
config.get("prompt_sections").and_then(Value::as_object),
) {
(false, _) => canonical_missing("prompt_sections"),
(true, None) => optional_missing_surface_payload(
"prompt_sections",
"Named prompt sections are not configured; prompt composition will use Rust defaults.",
"ccc_config.prompt_sections",
),
(true, Some(sections)) => {
let required = [
"identity",
"task",
"routing",
"hard_blocks",
"evidence",
"verification",
"anti_duplication",
"reporting",
];
let missing = required
.iter()
.filter(|section| !sections.contains_key(**section))
.copied()
.collect::<Vec<_>>();
if missing.is_empty() {
surface_payload(
"prompt_sections",
"current",
"Named prompt sections cover the 0.0.1 prompt-composition contract.",
"ccc_config.prompt_sections",
)
} else {
surface_payload(
"prompt_sections",
"stale",
format!(
"Named prompt sections are incomplete: missing={}.",
missing.join(",")
),
"ccc_config.prompt_sections",
)
}
}
};
let directory_rule_injection = match (
canonical_ready,
config
.get("directory_rule_injection")
.or_else(|| config.get("directory_rules")),
) {
(false, _) => canonical_missing("directory_rule_injection"),
(true, None) => optional_missing_surface_payload(
"directory_rule_injection",
"Directory-rule injection settings are absent; runtime will use Rust defaults.",
"ccc_config.directory_rule_injection",
),
(true, Some(value)) if !value.is_object() => surface_payload(
"directory_rule_injection",
"conflict",
"Directory-rule injection settings must be an object.",
"ccc_config.directory_rule_injection",
),
(true, Some(value)) => {
if value.get("enabled").and_then(Value::as_bool).is_some() {
surface_payload(
"directory_rule_injection",
"current",
"Directory-rule injection settings are configured.",
"ccc_config.directory_rule_injection",
)
} else {
surface_payload(
"directory_rule_injection",
"stale",
"Directory-rule injection settings are missing an enabled flag.",
"ccc_config.directory_rule_injection.enabled",
)
}
}
};
let hook_settings = match (
canonical_ready,
runtime.and_then(|runtime| runtime.get("lifecycle_hooks")),
) {
(false, _) => canonical_missing("hook_settings"),
(true, None) => optional_missing_surface_payload(
"hook_settings",
"Lifecycle hook settings are absent; runtime will use Rust defaults.",
"ccc_config.runtime.lifecycle_hooks",
),
(true, Some(value)) if !value.is_object() => surface_payload(
"hook_settings",
"conflict",
"lifecycle_hooks must be an object.",
"ccc_config.runtime.lifecycle_hooks",
),
(true, Some(value)) => {
let unsupported_command = value
.as_object()
.expect("checked object")
.values()
.filter_map(|tier| tier.get("command").and_then(Value::as_str))
.any(|command| !is_supported_hook_runner_command(command));
let has_multi_command = value
.as_object()
.expect("checked object")
.values()
.any(|tier| tier.get("commands").is_some());
surface_payload(
"hook_settings",
if unsupported_command || has_multi_command {
"conflict"
} else {
"current"
},
if unsupported_command || has_multi_command {
"Lifecycle hooks may only use the internal `ccc hook run` host integration runner."
} else {
"Lifecycle hook settings are configured for internal Sentinel host integration."
},
"ccc_config.runtime.lifecycle_hooks",
)
}
};
let lsp_runtime = match (
canonical_ready,
config.get("lsp").and_then(Value::as_object),
) {
(false, _) => canonical_missing("lsp_runtime"),
(true, None) => optional_missing_surface_payload(
"lsp_runtime",
"LSP runtime settings are absent; runtime will use bounded readiness defaults.",
"ccc_config.lsp",
),
(true, Some(lsp)) => {
let runtime_execution = lsp
.get("runtime_execution")
.and_then(Value::as_str)
.unwrap_or("bounded_readiness");
let enabled = lsp.get("enabled").and_then(Value::as_bool).unwrap_or(true);
if runtime_execution == "bounded_readiness" && enabled {
surface_payload(
"lsp_runtime",
"current",
"LSP runtime is configured for bounded readiness/diagnostics probes.",
"ccc_config.lsp",
)
} else if runtime_execution == "deferred" {
surface_payload(
"lsp_runtime",
"stale",
"LSP runtime still uses deferred execution.",
"ccc_config.lsp.runtime_execution",
)
} else {
surface_payload(
"lsp_runtime",
"conflict",
"LSP runtime has unsupported execution settings.",
"ccc_config.lsp",
)
}
}
};
let custom_agent_sync = match custom_agent_sync
.get("status")
.and_then(Value::as_str)
.unwrap_or("unavailable")
{
"matching_sync" => surface_payload(
"custom_agent_sync",
"current",
"CCC-managed custom agents match generated config.",
"custom_agent_sync",
),
"missing_sync" => surface_payload(
"custom_agent_sync",
"missing",
"One or more CCC-managed custom-agent files are missing.",
"custom_agent_sync",
),
"mismatched_sync" => surface_payload(
"custom_agent_sync",
"stale",
"One or more CCC-managed custom-agent files are stale or extra.",
"custom_agent_sync",
),
_ => surface_payload(
"custom_agent_sync",
"conflict",
"Custom-agent sync state is unreadable or unavailable.",
"custom_agent_sync",
),
};
let shared_config_version = create_shared_config_version_surface(config_state);
let generated_defaults = if !canonical_ready {
surface_payload(
"generated_defaults_version",
"missing",
"Generated-defaults version is unavailable until ccc-config.toml is migrated.",
"ccc_config.generated_defaults",
)
} else if generated_version < CURRENT_GENERATED_DEFAULTS_VERSION {
surface_payload(
"generated_defaults_version",
"stale",
format!(
"Generated defaults version is {generated_version}; expected {}.",
CURRENT_GENERATED_DEFAULTS_VERSION
),
"ccc_config.generated_defaults.version",
)
} else {
surface_payload(
"generated_defaults_version",
"current",
format!("Generated defaults version is current: {generated_version}."),
"ccc_config.generated_defaults.version",
)
};
let surfaces = vec![
registry,
shared_config_version.clone(),
category_routing,
fallback_policy,
concurrency,
prompt_sections,
directory_rule_injection,
hook_settings,
lsp_runtime,
custom_agent_sync,
generated_defaults.clone(),
];
let mut missing_count = 0;
let mut optional_missing_count = 0;
let mut stale_count = 0;
let mut conflict_count = 0;
for surface in &surfaces {
match surface
.get("status")
.and_then(Value::as_str)
.unwrap_or("unknown")
{
"missing" => missing_count += 1,
"optional_missing" => optional_missing_count += 1,
"stale" => stale_count += 1,
"conflict" | "unknown" => conflict_count += 1,
_ => {}
}
}
let status = if conflict_count > 0 {
"conflict"
} else if stale_count > 0 {
"stale"
} else if missing_count > 0 {
"missing"
} else {
"current"
};
let setup_guidance = json!({
"dry_run": "ccc setup --dry-run",
"apply": "ccc setup",
"backup": config_state.backup_status,
"backup_path": config_state.backup_path_value(),
"rollback": "ccc setup --rollback-config <backup_path>",
"restart": config_state.restart_status,
"preservation": "setup preserves user-owned config values while backfilling generated defaults",
});
json!({
"schema": "ccc.config_surface_readiness.v1",
"status": status,
"surface_count": surfaces.len(),
"missing_count": missing_count,
"optional_missing_count": optional_missing_count,
"stale_count": stale_count,
"conflict_count": conflict_count,
"surfaces": surfaces,
"shared_config_version": shared_config_version,
"generated_defaults": generated_defaults,
"setup_guidance": setup_guidance,
"summary": if status == "current" && optional_missing_count == 0 {
format!("All {} config/check-install surfaces are current.", env!("CARGO_PKG_VERSION"))
} else if status == "current" {
format!("Required {} config/check-install surfaces are current; optional deferred surfaces are absent and covered by Rust defaults.", env!("CARGO_PKG_VERSION"))
} else {
format!("One or more {} config/check-install surfaces are missing, stale, or conflicting.", env!("CARGO_PKG_VERSION"))
},
})
}
fn find_config_surface<'a>(
config_surface_readiness: &'a Value,
surface_id: &str,
) -> Option<&'a Value> {
config_surface_readiness
.get("surfaces")
.and_then(Value::as_array)?
.iter()
.find(|surface| surface.get("surface").and_then(Value::as_str) == Some(surface_id))
}
fn concurrency_readiness_label(status: &str) -> &'static str {
match status {
"current" => "ready",
"optional_missing" => "ready_with_defaults",
"stale" => "migration_recommended",
"missing" => "missing",
"conflict" => "conflict",
_ => "unknown",
}
}
fn create_concurrency_readiness_payload(config_surface_readiness: &Value) -> Value {
let surface = find_config_surface(config_surface_readiness, "concurrency");
let status = surface
.and_then(|surface| surface.get("status").and_then(Value::as_str))
.unwrap_or("unknown");
let source = surface
.and_then(|surface| surface.get("source").and_then(Value::as_str))
.unwrap_or("configSurfaceReadiness.concurrency");
let summary = surface
.and_then(|surface| surface.get("summary").and_then(Value::as_str))
.unwrap_or("Concurrency config surface is unavailable.");
json!({
"schema": "ccc.check_install.concurrency_readiness.v1",
"status": status,
"readiness": concurrency_readiness_label(status),
"configSurface": "configSurfaceReadiness.concurrency",
"configSurfaceStatus": config_surface_readiness
.get("status")
.and_then(Value::as_str)
.unwrap_or("unknown"),
"source": source,
"summary": summary,
})
}
pub(crate) fn create_check_install_status(
registration_status: &str,
config_install_state: &CccConfigInstallState,
cap_skill_status: &str,
custom_agent_status: &str,
config_surface_readiness: &Value,
) -> &'static str {
let config_surface_current = config_surface_readiness
.get("status")
.and_then(Value::as_str)
== Some("current");
if registration_status == "matching_registration"
&& config_install_state.canonical_ready
&& config_install_state.status == "canonical-current"
&& cap_skill_status == "matching_install"
&& custom_agent_status == "matching_sync"
&& config_surface_current
{
"ok"
} else {
"warning"
}
}
pub(crate) fn create_graph_context_check_install_readiness_payload(
config: &Value,
workspace_root: &Path,
) -> Value {
match create_graph_context_readiness_payload(config, workspace_root) {
Ok(payload) => annotate_graph_context_check_install_readiness(payload, workspace_root),
Err(error) => json!({
"schema": "ccc.graph_context_readiness.check_install.v1",
"provider": "graphify",
"opt_in": false,
"graphify_state": "fallback",
"readiness": "unavailable",
"reason": "inspection_error",
"fallback_when_unavailable": "scout_source_evidence",
"fallback": "scout_source_evidence",
"check_install_status": "warning",
"check_install_blocking": false,
"workspace_root": workspace_root.to_string_lossy(),
"setup_policy": {
"state": "fallback",
"opt_in": false,
"managed_by_ccc_setup": false,
"auto_install_external_dependency": false,
"allow_missing_provider_fallback": true,
"install_behavior": "external_install_not_performed_by_ccc_setup",
"configure_behavior": "readiness inspection failed before setup policy could be evaluated",
"attach_behavior": "await_existing_graphify_artifacts_or_use_fallback",
"fallback_behavior": "use scout_source_evidence and keep legacy code graph fallback disabled when Graphify is missing or unavailable"
},
"inventory_evidence": {
"status": "complete",
"scope": "graphify_or_explicit_scout_fallback",
"provider_path_complete": false,
"fallback_path_complete": true,
"fallback": "scout_source_evidence",
"legacy_code_graph_fallback_disabled": true,
"reason": "inspection_error"
},
"summary": format!(
"Graphify graph_context readiness could not be inspected: {error}."
),
}),
}
}
fn annotate_graph_context_check_install_readiness(
mut payload: Value,
workspace_root: &Path,
) -> Value {
let readiness = payload
.get("readiness")
.and_then(Value::as_str)
.unwrap_or("unavailable");
let graphify_state = payload
.get("graphify_state")
.and_then(Value::as_str)
.unwrap_or("fallback");
let setup_state = payload
.pointer("/setup_policy/state")
.and_then(Value::as_str)
.unwrap_or("fallback");
let fallback_allowed = payload
.pointer("/setup_policy/allow_missing_provider_fallback")
.and_then(Value::as_bool)
.unwrap_or(true);
let configured = payload
.get("configured")
.and_then(Value::as_bool)
.unwrap_or(false);
let check_install_status = match graphify_state {
"config-managed" if !configured => "warning",
"available" | "config-managed" | "missing" | "fallback" if fallback_allowed => "ok",
"available" | "fallback" => "ok",
_ if readiness == "disabled" || graphify_state == "disabled" => "disabled",
"stale" => "stale",
_ => "warning",
};
let fallback = payload
.get("fallback")
.and_then(Value::as_str)
.or_else(|| {
payload
.get("fallback_when_unavailable")
.and_then(Value::as_str)
})
.unwrap_or("scout_source_evidence");
let reason = payload
.get("reason")
.and_then(Value::as_str)
.unwrap_or("unknown");
let summary = match graphify_state {
"available" => "Graphify graph_context artifacts are available; setup attaches existing artifacts and does not install external dependencies.".to_string(),
"config-managed" => {
format!("Graphify graph_context config is managed, but artifact generation is not opted in; fallback={fallback} is ready.")
}
"missing" => {
format!("Graphify graph_context artifacts are missing; setup={setup_state} does not install external Graphify by default; fallback={fallback} is ready.")
}
"disabled" | "fallback" if readiness == "disabled" => {
format!("Graphify graph_context is disabled; fallback={fallback} remains active.")
}
"fallback" => {
format!("Graphify graph_context is not opted in; fallback={fallback} remains active.")
}
"stale" | "managed" => format!("Graphify graph_context is managed but not current ({reason}); fallback={fallback}."),
"opt-in-mismatch" => format!("Graphify graph_context opt-in/configuration mismatch ({reason}); fallback={fallback}."),
_ => format!("Graphify graph_context is unavailable ({reason}); fallback={fallback}."),
};
if let Some(object) = payload.as_object_mut() {
object.insert(
"schema".to_string(),
Value::String("ccc.graph_context_readiness.check_install.v1".to_string()),
);
object.insert(
"check_install_status".to_string(),
Value::String(check_install_status.to_string()),
);
object.insert("check_install_blocking".to_string(), Value::Bool(false));
object.insert(
"workspace_root".to_string(),
Value::String(workspace_root.to_string_lossy().into_owned()),
);
object.insert("summary".to_string(), Value::String(summary));
}
payload
}
fn status_rank(status: &str) -> u8 {
match status {
"unreadable" | "conflict" | "unknown" => 4,
"stale" => 3,
"missing" => 2,
"migrated" => 1,
_ => 0,
}
}
pub(crate) fn create_install_surface_visibility_payload(
registration: Value,
config: Value,
skill: Value,
custom_agents: Value,
) -> Value {
let components = json!({
"mcp_registration": registration,
"ccc_config": config,
"cap_skill": skill,
"custom_agents": custom_agents,
});
let mut component_statuses = components
.as_object()
.into_iter()
.flat_map(|object| object.iter())
.filter_map(|(name, component)| {
Some((
name.to_string(),
component.get("status").and_then(Value::as_str)?.to_string(),
component
.get("restart_status")
.and_then(Value::as_str)
.unwrap_or("unknown")
.to_string(),
))
})
.collect::<Vec<_>>();
component_statuses.sort_by(|left, right| {
status_rank(&right.1)
.cmp(&status_rank(&left.1))
.then_with(|| left.0.cmp(&right.0))
});
let overall_status = component_statuses
.first()
.map(|(_, status, _)| status.as_str())
.unwrap_or("unknown");
let restart_required = component_statuses
.iter()
.any(|(_, _, restart_status)| restart_status.starts_with("restart-required"));
let needs_setup = component_statuses
.iter()
.any(|(_, status, _)| matches!(status.as_str(), "missing" | "stale" | "migrated"));
let summary = if overall_status == "current" && !restart_required {
"Install surface is current; no setup or restart action is required.".to_string()
} else if needs_setup {
"Install surface needs setup refresh and Codex CLI restart before the host session sees all changes.".to_string()
} else {
"Install surface visibility has warnings; inspect component summaries before continuing."
.to_string()
};
json!({
"status": overall_status,
"restart_required": restart_required,
"setup_refresh_recommended": needs_setup,
"summary": summary,
"components": components,
})
}
fn create_legacy_direct_registration_cleanup_payload() -> Value {
let codex_home = match resolve_codex_home() {
Ok(path) => path,
Err(error) => {
return json!({
"schema": "ccc.legacy_direct_registration_cleanup.v1",
"status": "unreadable",
"blocking": false,
"summary": error.to_string(),
});
}
};
create_legacy_direct_registration_cleanup_payload_at(&codex_home)
}
pub(crate) fn create_legacy_direct_registration_cleanup_payload_at(codex_home: &Path) -> Value {
let config_path = codex_home.join("config.toml");
let config = read_optional_toml_document(&config_path)
.ok()
.flatten()
.unwrap_or(Value::Null);
let direct_mcp_present = config.pointer("/mcp_servers/ccc").is_some();
let direct_mcp_current = direct_mcp_present && direct_mcp_config_matches_expected(&config);
let legacy_direct_mcp_present = direct_mcp_present && !direct_mcp_current;
let standalone_cap_skill_path = codex_home.join("skills").join("cap").join("SKILL.md");
let standalone_cap_skill_present = standalone_cap_skill_path.exists();
let status = if legacy_direct_mcp_present || standalone_cap_skill_present {
"legacy_surface_present"
} else {
"verified_clean"
};
json!({
"schema": "ccc.legacy_direct_registration_cleanup.v1",
"status": status,
"blocking": false,
"direct_mcp_servers_ccc_present": direct_mcp_present,
"direct_mcp_servers_ccc_current": direct_mcp_current,
"legacy_direct_mcp_servers_ccc_present": legacy_direct_mcp_present,
"legacy_direct_mcp_servers_ccc_path": config_path.to_string_lossy(),
"standalone_skills_cap_present": standalone_cap_skill_present,
"standalone_skills_cap_path": standalone_cap_skill_path.to_string_lossy(),
"summary": if status == "verified_clean" {
"Legacy direct mcp_servers.ccc and standalone skills/cap surfaces are absent; current Cargo MCP registration is allowed."
} else {
"Legacy direct mcp_servers.ccc or standalone skills/cap surfaces are still present; setup/check-install surfaces this for cleanup."
}
})
}
fn direct_mcp_config_matches_expected(config: &Value) -> bool {
let Some(server) = config.pointer("/mcp_servers/ccc") else {
return false;
};
let Some(command) = server.get("command").and_then(Value::as_str) else {
return false;
};
let args = server
.get("args")
.and_then(Value::as_array)
.map(|values| {
values
.iter()
.filter_map(Value::as_str)
.map(str::to_string)
.collect::<Vec<_>>()
})
.unwrap_or_default();
let Ok((expected_command, expected_args)) = resolve_expected_launch_command() else {
return false;
};
let accepted_commands = resolve_accepted_launch_commands(&expected_command);
accepted_commands.contains(&normalize_registered_command(command)) && args == expected_args
}
fn push_existing_path(paths: &mut Vec<String>, path: &Path) {
if path.exists() {
paths.push(display_path(path));
}
}
fn create_legacy_bundle_cleanup_payload_at(
home: Option<&Path>,
codex_home: Option<&Path>,
) -> Value {
let mut paths = Vec::new();
if let Some(home) = home {
let ccc_root = home.join(".local").join("share").join("ccc");
let releases_dir = ccc_root.join("releases");
if let Ok(entries) = fs::read_dir(&releases_dir) {
let mut release_paths = entries
.filter_map(Result::ok)
.map(|entry| display_path(&entry.path()))
.collect::<Vec<_>>();
release_paths.sort();
paths.extend(release_paths);
}
push_existing_path(&mut paths, &ccc_root.join("current"));
push_existing_path(&mut paths, &ccc_root.join("plugin-marketplace"));
}
if let Some(codex_home) = codex_home {
let plugin_versions_dir = codex_home
.join("plugins")
.join("cache")
.join("ccc-local")
.join("ccc");
if let Ok(entries) = fs::read_dir(plugin_versions_dir) {
let mut stale_plugin_cache_paths = entries
.filter_map(Result::ok)
.filter(|entry| entry.file_name().to_string_lossy() != env!("CARGO_PKG_VERSION"))
.map(|entry| display_path(&entry.path()))
.collect::<Vec<_>>();
stale_plugin_cache_paths.sort();
paths.extend(stale_plugin_cache_paths);
}
}
let status = if paths.is_empty() {
"absent"
} else {
"present"
};
json!({
"schema": "ccc.legacy_bundle_cleanup.v1",
"status": status,
"stalePathCount": paths.len(),
"stalePaths": paths,
"summary": if status == "present" {
"Legacy release-bundle paths or caches are present. They are reported for Cargo migration cleanup review only; no files were removed."
} else {
"No legacy release-bundle paths or stale caches were found."
},
})
}
fn create_legacy_bundle_cleanup_payload() -> Value {
let home = env::var_os("HOME").map(PathBuf::from);
let codex_home = resolve_codex_home().ok();
create_legacy_bundle_cleanup_payload_at(home.as_deref(), codex_home.as_deref())
}
pub(crate) fn create_display_alias_contract_payload() -> Value {
json!({
"schema": "ccc.display_alias_contract.v1",
"stable_routing_id": "ccc_raider",
"preferred_callsign": "Marauder",
"preferred_bracket_label": "Marauder",
"stable_id_label": "ccc_raider",
"host_toast_alias_supported": false,
"substitute_surfaces": ["status", "subagents", "projection", "check-install", "app-panel"],
"summary": "CCC exposes callsign-only preferred labels and stable IDs separately; host-owned spawn toasts are not controlled by CCC."
})
}
pub(crate) fn create_app_server_remote_parity_payload() -> Value {
json!({
"schema": "ccc.app_server_remote_parity.v1",
"app_panel_payload_available": true,
"status_payload_available": true,
"check_install_payload_available": true,
"remote_visibility_parity": "explicit_payload_fields",
"app_server_required": false,
"blocking": false,
"summary": "Status, app-panel, and check-install expose the same non-blocking parity contract for local app and remote hosts."
})
}
fn status_string_for(value: &Value) -> String {
value
.get("status")
.and_then(Value::as_str)
.unwrap_or("unknown")
.to_string()
}
fn create_update_parity_payload(
path_shadow_diagnostics: &Value,
config_surface_readiness: &Value,
plugin_discovery: &Value,
plugin_marketplace_discovery: &Value,
cap_skill: &Value,
cap_continuity: &Value,
custom_agent_sync: &Value,
install_surface_visibility: &Value,
configured_role_models: &[Value],
concurrency_readiness: &Value,
hooks_readiness: &Value,
model_policy_status: &str,
model_policy_summary: &str,
) -> Value {
let shared_config_version = config_surface_readiness
.get("shared_config_version")
.cloned()
.unwrap_or(Value::Null);
let generated_defaults = config_surface_readiness
.get("generated_defaults")
.cloned()
.unwrap_or(Value::Null);
let package_binary_status = match path_shadow_diagnostics
.get("cargoBinaryCandidateVersionMatches")
.and_then(Value::as_bool)
{
Some(true) => "current",
Some(false)
if path_shadow_diagnostics
.get("cargoBinaryCandidateVersionError")
.is_some() =>
{
"conflict"
}
Some(false)
if path_shadow_diagnostics
.get("cargoBinaryCandidateVersion")
.and_then(Value::as_str)
.is_some() =>
{
"stale"
}
Some(false) => "missing",
None => "unknown",
};
let plugin_cache_status = status_string_for(plugin_discovery);
let plugin_marketplace_status = status_string_for(plugin_marketplace_discovery);
let cap_skill_status = status_string_for(cap_skill);
let cap_continuity_status = status_string_for(cap_continuity);
let custom_agents_status = status_string_for(custom_agent_sync);
let concurrency_status = concurrency_readiness
.get("status")
.and_then(Value::as_str)
.unwrap_or("unknown");
let hooks_state = hooks_readiness
.get("state")
.and_then(Value::as_str)
.unwrap_or("unknown");
let hooks_schema_compatibility = hooks_readiness
.pointer("/schema_compatibility/status")
.and_then(Value::as_str)
.unwrap_or("fail");
let hooks_status = if hooks_schema_compatibility != "pass" {
"stale"
} else {
match hooks_state {
"available" => "current",
"disabled" => "missing",
"missing" => "missing",
"plugin_hook_trusted_but_disabled"
| "plugin_hook_untrusted"
| "plugin_hooks_disabled"
| "needs_trust_or_enablement"
| "unsupported"
| "untrusted" => "stale",
_ => "stale",
}
};
let role_defaults_status = if !configured_role_models.is_empty() {
"current"
} else {
"missing"
};
let visibility_status = install_surface_visibility
.get("status")
.and_then(Value::as_str)
.unwrap_or("unknown");
let restart_required = install_surface_visibility
.get("restart_required")
.and_then(Value::as_bool)
.unwrap_or(false)
|| plugin_marketplace_status != "current"
|| plugin_cache_status != "current"
|| cap_skill_status != "current"
|| cap_continuity_status != "current"
|| custom_agents_status != "current"
|| hooks_status != "current";
let cache_reload_required = plugin_marketplace_status != "current"
|| plugin_cache_status != "current"
|| cap_skill_status != "current"
|| custom_agents_status != "current"
|| hooks_status != "current";
let summary = if restart_required || cache_reload_required {
"Restart Codex CLI or reload the plugin cache after `ccc setup` so marketplace, skill, hook, and managed custom-agent visibility changes become visible."
.to_string()
} else {
"Update parity surfaces are current and visible without a restart or cache reload."
.to_string()
};
let overall_status = {
let statuses = [
package_binary_status,
shared_config_version
.get("status")
.and_then(Value::as_str)
.unwrap_or("unknown"),
generated_defaults
.get("status")
.and_then(Value::as_str)
.unwrap_or("unknown"),
plugin_cache_status.as_str(),
plugin_marketplace_status.as_str(),
cap_skill_status.as_str(),
cap_continuity_status.as_str(),
custom_agents_status.as_str(),
role_defaults_status,
concurrency_status,
hooks_status,
];
let worst = statuses
.iter()
.map(|status| status_rank(status))
.max()
.unwrap_or(0);
match worst {
4 => "conflict",
3 => "stale",
2 => "missing",
_ => "current",
}
};
json!({
"schema": "ccc.update_parity.v1",
"status": overall_status,
"summary": summary,
"package": {
"name": env!("CARGO_PKG_NAME"),
"version": env!("CARGO_PKG_VERSION"),
"binary_version": path_shadow_diagnostics
.get("cargoBinaryCandidateVersion")
.cloned()
.unwrap_or(Value::Null),
"binary_version_matches": path_shadow_diagnostics
.get("cargoBinaryCandidateVersionMatches")
.cloned()
.unwrap_or(Value::Bool(false)),
"binary_status": package_binary_status,
"path_shadow_status": path_shadow_diagnostics
.get("status")
.cloned()
.unwrap_or(Value::Null),
},
"shared_config_version": shared_config_version,
"generated_defaults": generated_defaults,
"plugin_cache": {
"status": plugin_cache_status,
"summary": plugin_discovery
.get("summary")
.cloned()
.unwrap_or(Value::Null),
"restart_required": plugin_discovery
.get("restart_required")
.cloned()
.unwrap_or(Value::Bool(false)),
},
"plugin_marketplace": {
"status": plugin_marketplace_status,
"summary": plugin_marketplace_discovery
.get("summary")
.cloned()
.unwrap_or(Value::Null),
},
"cap_skill": {
"status": cap_skill_status,
"summary": cap_skill.get("summary").cloned().unwrap_or(Value::Null),
"restart_status": cap_skill
.get("restart_status")
.cloned()
.unwrap_or(Value::Null),
},
"cap_continuity": cap_continuity.clone(),
"managed_custom_agents": {
"status": custom_agents_status,
"summary": custom_agent_sync.get("summary").cloned().unwrap_or(Value::Null),
"action_status": install_surface_visibility
.pointer("/components/custom_agents/action_status")
.cloned()
.unwrap_or(Value::String("inspection-blocked".to_string())),
"restart_status": install_surface_visibility
.pointer("/components/custom_agents/restart_status")
.cloned()
.unwrap_or(Value::String("unknown".to_string())),
},
"role_defaults": {
"status": model_policy_status,
"summary": model_policy_summary,
"configured_count": configured_role_models.len(),
},
"concurrency": concurrency_readiness.clone(),
"hooks": hooks_readiness.clone(),
"restart_guidance": {
"restart_required": restart_required,
"cache_reload_required": cache_reload_required,
"visibility_status": visibility_status,
"visibility_targets": ["marketplace", "skill", "hook", "custom_agents"],
"summary": summary,
},
})
}
fn toml_bool_at(path: &Path, pointer: &str) -> Result<Option<bool>, String> {
read_optional_toml_document(path)
.map_err(|error| error.to_string())
.map(|document| document.and_then(|value| value.pointer(pointer).and_then(Value::as_bool)))
}
const USER_PROMPT_SUBMIT_PLUGIN_HOOK_STATE_KEY: &str =
"ccc@ccc-local:hooks/hooks.json:user_prompt_submit:0:0";
fn plugin_hook_state_entry<'a>(config: Option<&'a Value>, state_key: &str) -> Option<&'a Value> {
config
.and_then(|value| value.get("hooks"))
.and_then(|hooks| hooks.get("state"))
.and_then(|state| state.get(state_key))
}
fn project_trust_level_from_codex_config(config: Option<&Value>, workspace_root: &Path) -> String {
let workspace_key = workspace_root.to_string_lossy();
config
.and_then(|value| value.get("projects"))
.and_then(Value::as_object)
.and_then(|projects| projects.get(workspace_key.as_ref()))
.and_then(|project| project.get("trust_level"))
.and_then(Value::as_str)
.unwrap_or("unknown")
.to_string()
}
fn command_hook_source_loadable(path: &Path) -> Result<bool, String> {
if !path.is_file() {
return Ok(false);
}
let raw = fs::read_to_string(path).map_err(|error| error.to_string())?;
let parsed = serde_json::from_str::<Value>(&raw).map_err(|error| error.to_string())?;
let Some(hooks) = parsed.get("hooks").and_then(Value::as_object) else {
return Ok(false);
};
let required_events = [
"UserPromptSubmit",
"SessionStart",
"PermissionRequest",
"PostToolUse",
"Stop",
];
Ok(required_events.iter().all(|event| {
hooks
.get(*event)
.and_then(Value::as_array)
.is_some_and(|groups| {
groups.iter().any(|group| {
group
.get("hooks")
.and_then(Value::as_array)
.is_some_and(|handlers| {
handlers.iter().any(|handler| {
handler.get("type").and_then(Value::as_str) == Some("command")
&& handler
.get("command")
.and_then(Value::as_str)
.is_some_and(is_supported_hook_runner_command)
})
})
})
})
}))
}
pub(crate) fn create_hooks_readiness_payload_at(codex_home: &Path, workspace_root: &Path) -> Value {
let user_config_path = codex_home.join("config.toml");
let user_hooks_json_path = codex_home.join("hooks.json");
let project_codex_dir = workspace_root.join(".codex");
let project_config_path = project_codex_dir.join("config.toml");
let project_hooks_json_path = project_codex_dir.join("hooks.json");
let plugin_hooks_path = plugin_cache_root_at(codex_home)
.join("hooks")
.join("hooks.json");
let user_config = read_optional_toml_document(&user_config_path)
.ok()
.flatten();
let project_config = read_optional_toml_document(&project_config_path)
.ok()
.flatten();
let hooks_feature = toml_bool_at(&user_config_path, "/features/hooks")
.ok()
.flatten()
.unwrap_or(true);
let plugin_hooks_feature = toml_bool_at(&user_config_path, "/features/plugin_hooks")
.ok()
.flatten()
.unwrap_or(false);
let user_inline_hooks = user_config
.as_ref()
.and_then(|value| value.get("hooks"))
.is_some();
let project_inline_hooks = project_config
.as_ref()
.and_then(|value| value.get("hooks"))
.is_some();
let user_hooks_json_exists = user_hooks_json_path.is_file();
let project_hooks_json_exists = project_hooks_json_path.is_file();
let plugin_hooks_exists = plugin_hooks_path.is_file();
let plugin_hooks_loadable = command_hook_source_loadable(&plugin_hooks_path).unwrap_or(false);
let project_trust_level =
project_trust_level_from_codex_config(user_config.as_ref(), workspace_root);
let project_hooks_present = project_hooks_json_exists || project_inline_hooks;
let project_hooks_trusted = !project_hooks_present || project_trust_level == "trusted";
let user_prompt_submit_state_entry = plugin_hook_state_entry(
user_config.as_ref(),
USER_PROMPT_SUBMIT_PLUGIN_HOOK_STATE_KEY,
);
let user_prompt_submit_trusted_hash_present = user_prompt_submit_state_entry
.and_then(|state| state.get("trusted_hash"))
.and_then(Value::as_str)
.is_some_and(|trusted_hash| !trusted_hash.trim().is_empty());
let user_prompt_submit_enabled_flag_present = user_prompt_submit_state_entry
.and_then(|state| state.get("enabled"))
.and_then(Value::as_bool)
== Some(true);
let user_prompt_submit_active_after_restart = hooks_feature
&& plugin_hooks_exists
&& plugin_hooks_loadable
&& plugin_hooks_feature
&& user_prompt_submit_trusted_hash_present
&& user_prompt_submit_enabled_flag_present;
let user_prompt_submit_state = if user_prompt_submit_active_after_restart {
"active_after_restart"
} else if user_prompt_submit_trusted_hash_present && !user_prompt_submit_enabled_flag_present {
"trusted_but_disabled"
} else if plugin_hooks_exists && plugin_hooks_loadable && plugin_hooks_feature {
"needs_trust_or_enablement"
} else if plugin_hooks_exists && plugin_hooks_loadable {
"asset_ready_plugin_hooks_disabled"
} else if plugin_hooks_exists {
"asset_unloadable"
} else {
"asset_missing"
};
let user_prompt_submit_reason = if user_prompt_submit_active_after_restart {
"UserPromptSubmit is trusted and enabled; it becomes active after Codex restart."
} else if user_prompt_submit_trusted_hash_present && !user_prompt_submit_enabled_flag_present {
"UserPromptSubmit has trusted_hash but enabled = true is missing or false; it remains inactive until enabled = true is set and Codex is restarted."
} else if plugin_hooks_exists && plugin_hooks_loadable && plugin_hooks_feature {
"UserPromptSubmit plugin hook asset is loadable and plugin hooks are enabled, but trusted_hash and enabled = true are both required before restart activation."
} else if plugin_hooks_exists && plugin_hooks_loadable {
"UserPromptSubmit plugin hook asset is loadable, but features.plugin_hooks is not enabled."
} else if plugin_hooks_exists {
"UserPromptSubmit plugin hook asset is present, but the hook source is not loadable by Codex."
} else {
"UserPromptSubmit plugin hook asset is not installed."
};
let schema_compatibility = create_lifecycle_hook_schema_compatibility_payload();
let schema_compatibility_status = schema_compatibility
.get("status")
.and_then(Value::as_str)
.unwrap_or("fail");
let (state, reason, runtime_path) = if !hooks_feature {
(
"disabled",
"features.hooks is false in Codex config; CCC runtime fallback remains active.",
"ccc_fallback",
)
} else if project_hooks_present && !project_hooks_trusted {
(
"untrusted",
"Project-local hook source exists but the project .codex layer is not trusted.",
"ccc_fallback",
)
} else if plugin_hooks_exists && !plugin_hooks_loadable {
(
"unsupported",
"CCC plugin hook assets are present, but the hook source is not loadable by Codex.",
"ccc_fallback",
)
} else if plugin_hooks_exists && !plugin_hooks_feature {
(
"plugin_hooks_disabled",
"CCC plugin hook assets are present, but features.plugin_hooks is not enabled.",
"ccc_fallback",
)
} else if plugin_hooks_exists
&& plugin_hooks_feature
&& !user_prompt_submit_trusted_hash_present
{
(
"plugin_hook_untrusted",
"CCC UserPromptSubmit plugin hook asset is loadable, but trusted_hash is missing; it remains inactive until Codex records trust and Codex is restarted.",
"ccc_fallback",
)
} else if plugin_hooks_exists
&& plugin_hooks_feature
&& user_prompt_submit_trusted_hash_present
&& !user_prompt_submit_enabled_flag_present
{
(
"plugin_hook_trusted_but_disabled",
"CCC UserPromptSubmit plugin hook is trusted, but enabled = true is missing or false; it remains inactive until enabled = true is set and Codex is restarted.",
"ccc_fallback",
)
} else if plugin_hooks_exists && plugin_hooks_feature && user_prompt_submit_active_after_restart
{
(
"available",
"CCC UserPromptSubmit plugin hook asset is installed, trusted, enabled, and active after Codex restart.",
"hooks_first",
)
} else {
(
"missing",
"CCC hook assets are not installed yet; CCC CLI/MCP/status/fan-in fallback remains active.",
"ccc_fallback",
)
};
let fallback_active = runtime_path == "ccc_fallback";
json!({
"schema": "ccc.codex_hooks_readiness.v1",
"state": state,
"readiness": if state == "available" { "ready" } else { "fallback" },
"runtime_path": runtime_path,
"fallback": "ccc_cli_mcp_status_fan_in",
"fallback_active": fallback_active,
"blocking": false,
"check_install_status": if schema_compatibility_status == "pass" { "ok" } else { "error" },
"reason": reason,
"schema_compatibility": schema_compatibility,
"features": {
"hooks": hooks_feature,
"plugin_hooks": plugin_hooks_feature,
"hooks_default_enabled": true,
"plugin_hooks_default_enabled": false
},
"sources": {
"user_config": {
"path": user_config_path.to_string_lossy(),
"exists": user_config_path.is_file(),
"inline_hooks": user_inline_hooks
},
"user_hooks_json": {
"path": user_hooks_json_path.to_string_lossy(),
"exists": user_hooks_json_exists
},
"project_config": {
"path": project_config_path.to_string_lossy(),
"exists": project_config_path.is_file(),
"inline_hooks": project_inline_hooks,
"trust_level": project_trust_level,
"trusted": project_hooks_trusted
},
"project_hooks_json": {
"path": project_hooks_json_path.to_string_lossy(),
"exists": project_hooks_json_exists
},
"plugin_hooks": {
"path": plugin_hooks_path.to_string_lossy(),
"exists": plugin_hooks_exists,
"loadable": plugin_hooks_loadable,
"requires_feature": "features.plugin_hooks"
}
},
"per_hook": {
"UserPromptSubmit": {
"event": "UserPromptSubmit",
"state": user_prompt_submit_state,
"state_key": USER_PROMPT_SUBMIT_PLUGIN_HOOK_STATE_KEY,
"asset_present": plugin_hooks_exists,
"source_loadable": plugin_hooks_loadable,
"plugin_hooks_feature_enabled": plugin_hooks_feature,
"trusted_hash_present": user_prompt_submit_trusted_hash_present,
"enabled_flag_present": user_prompt_submit_enabled_flag_present,
"active_after_restart": user_prompt_submit_active_after_restart,
"reason": user_prompt_submit_reason
}
},
"event_contract": {
"preferred_events": ["UserPromptSubmit", "SessionStart", "PermissionRequest", "PostToolUse", "Stop"],
"guardrail_not_authority_boundary": true,
"coverage_limitations": [
"PreToolUse and PostToolUse do not intercept every shell or tool path.",
"Plugin-bundled hooks require features.plugin_hooks=true.",
"Project-local hooks require trusted project config."
]
}
})
}
pub(crate) fn create_hooks_readiness_payload(workspace_root: &Path) -> Value {
resolve_codex_home()
.map(|codex_home| create_hooks_readiness_payload_at(&codex_home, workspace_root))
.unwrap_or_else(|error| {
json!({
"schema": "ccc.codex_hooks_readiness.v1",
"state": "unsupported",
"readiness": "fallback",
"runtime_path": "ccc_fallback",
"fallback": "ccc_cli_mcp_status_fan_in",
"fallback_active": true,
"blocking": false,
"check_install_status": "ok",
"reason": format!("Codex home could not be resolved: {error}.")
})
})
}
pub(crate) fn refresh_install_surface_config_visibility(
payload: &mut Value,
state: &CccConfigInstallState,
) {
let Some(object) = payload.as_object_mut() else {
return;
};
let existing = object
.get("installSurfaceVisibility")
.cloned()
.unwrap_or(Value::Null);
let component = |name: &str| {
existing
.pointer(&format!("/components/{name}"))
.cloned()
.unwrap_or_else(|| {
json!({
"status": "unknown",
"raw_status": "unknown",
"action_status": "inspection-blocked",
"restart_status": "unknown",
"summary": Value::Null,
})
})
};
object.insert(
"installSurfaceVisibility".to_string(),
create_install_surface_visibility_payload(
component("mcp_registration"),
create_config_visibility_payload(state),
component("cap_skill"),
component("custom_agents"),
),
);
}
pub(crate) fn collect_install_check_payload_for_config_path(
session_context: &SessionContext,
preferred_config_path: PathBuf,
) -> Value {
let workspace_root = env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
collect_install_check_payload_for_config_path_at_workspace(
session_context,
preferred_config_path,
&workspace_root,
)
}
pub(crate) fn collect_install_check_payload_for_config_path_at_workspace(
session_context: &SessionContext,
preferred_config_path: PathBuf,
workspace_root: &Path,
) -> Value {
let legacy_toml_path = resolve_legacy_shared_toml_config_path_for(&preferred_config_path)
.unwrap_or_else(resolve_legacy_shared_toml_config_path);
let legacy_json_path = resolve_legacy_shared_json_config_path_for(&preferred_config_path)
.unwrap_or_else(resolve_legacy_shared_json_config_path);
let config_install_state = collect_ccc_config_install_state_at(
&preferred_config_path,
&legacy_toml_path,
&legacy_json_path,
)
.unwrap_or_else(|error| CccConfigInstallState {
status: "unreadable",
action_status: "skipped",
backup_status: "unavailable",
summary: error.to_string(),
source_path: Some(preferred_config_path.clone()),
backup_source_path: None,
backup_path: None,
value: Value::Null,
canonical_ready: false,
config_exists: preferred_config_path.exists(),
restart_status: "not-required",
entry_policy_mode_status: "unavailable",
entry_policy_mode_raw: None,
entry_policy_mode_canonical: None,
entry_policy_mode_summary:
"Entry policy mode health is unavailable because the CCC config could not be read."
.to_string(),
setup_migration_deltas: json!({
"schema": "ccc.setup_migration_deltas.v1",
"status": "unavailable",
"action_status": "inspection-blocked",
"family_count": 0,
"changed_count": 0,
"backfilled_count": 0,
"migrated_count": 0,
"preserved_override_count": 0,
"families": [],
"summary": "Setup migration deltas are unavailable because the CCC config could not be read.",
}),
});
let config_exists = config_install_state.config_exists;
let config_value = config_install_state.value.clone();
let configured_role_models = create_configured_role_models_payload_from_config(&config_value);
let execution_contract_registry = create_execution_contract_registry_from_config(&config_value);
let custom_agent_sync = inspect_generated_custom_agents_from_config(&config_value)
.unwrap_or_else(|error| {
json!({
"status": "unreadable_sync",
"summary": error.to_string(),
"directory_path": Value::Null,
"generated_names": [],
"generated_files": [],
"file_count": 0,
"missing_files": [],
"mismatched_files": [],
"stale_managed_files": [],
})
});
let (expected_command, expected_args) =
resolve_expected_launch_command().unwrap_or_else(|_| {
(
session_context.entrypoint_path.clone().unwrap_or_default(),
vec!["mcp".to_string()],
)
});
let registry_result = read_codex_mcp_registry();
let (
registration_status,
registration_summary,
registered_launch_command,
registered_launch_args,
) = match registry_result {
Ok(records) => {
if let Some(record) = find_ccc_registration(&records) {
let command = record
.transport
.as_ref()
.and_then(|transport| transport.command.clone());
let args = record
.transport
.as_ref()
.and_then(|transport| transport.args.clone())
.unwrap_or_default();
if registration_matches_expected(record, &expected_command, &expected_args) {
(
"matching_registration",
"Codex CLI MCP registration matches the expected CCC launch command."
.to_string(),
command.map(Value::String).unwrap_or(Value::Null),
Value::Array(args.into_iter().map(Value::String).collect()),
)
} else {
(
"mismatched_registration",
format!(
"Codex CLI has a CCC MCP entry, but it does not point at the expected CCC {} launch command.",
env!("CARGO_PKG_VERSION")
),
command.map(Value::String).unwrap_or(Value::Null),
Value::Array(args.into_iter().map(Value::String).collect()),
)
}
} else {
(
"missing_registration",
"Codex CLI does not currently have a CCC MCP registration.".to_string(),
Value::Null,
Value::Array(Vec::new()),
)
}
}
Err(error) => (
"unreadable_registration",
error.to_string(),
Value::Null,
Value::Array(Vec::new()),
),
};
let packaged_plugin_file_lookup = inspect_packaged_plugin_file_lookup();
let packaged_skill_source_status =
packaged_harness_surface_status_from_cap_skill_source(resolve_packaged_cap_skill_source());
let cap_skill_visibility = inspect_packaged_cap_skill_install();
let cap_skill_status = cap_skill_visibility
.get("status")
.and_then(Value::as_str)
.unwrap_or("unreadable_install");
let cap_skill_summary = cap_skill_visibility
.get("summary")
.and_then(Value::as_str)
.unwrap_or("The packaged $cap skill install state is unavailable.");
let plugin_discovery = create_plugin_discovery_payload();
let plugin_marketplace_discovery = create_plugin_marketplace_discovery_payload();
let cap_continuity = create_cap_continuity_payload(&cap_skill_visibility, &plugin_discovery);
let registration_visibility =
create_registration_visibility_payload(registration_status, ®istration_summary);
let config_visibility = create_config_visibility_payload(&config_install_state);
let custom_agent_visibility = create_custom_agent_visibility_payload(&custom_agent_sync);
let skill_visibility = create_skill_visibility_payload(&cap_skill_visibility);
let skill_registry_health = create_skill_registry_health_payload();
let command_budget_route_modularity =
create_command_budget_route_modularity_payload(&config_value);
let plugin_cli_parity = create_plugin_cli_parity_payload();
let permission_profile =
create_permission_profile_payload(session_context, workspace_root, &config_value, None);
let multi_agent_runtime_contract = create_multi_agent_runtime_contract_payload(&config_value);
let config_surface_readiness = create_config_surface_readiness_payload(
&config_install_state,
&execution_contract_registry,
&custom_agent_sync,
);
let concurrency_readiness = create_concurrency_readiness_payload(&config_surface_readiness);
let graph_context_readiness =
create_graph_context_check_install_readiness_payload(&config_value, workspace_root);
let lsp_runtime_readiness = create_lsp_runtime_readiness_payload(&config_value, workspace_root);
let memory_readiness = create_memory_status_payload(workspace_root);
let hooks_readiness = create_hooks_readiness_payload(workspace_root);
let path_shadow_diagnostics = collect_path_shadow_diagnostics();
let legacy_direct_registration_cleanup = create_legacy_direct_registration_cleanup_payload();
let legacy_bundle_cleanup = create_legacy_bundle_cleanup_payload();
let display_alias_contract = create_display_alias_contract_payload();
let app_server_remote_parity = create_app_server_remote_parity_payload();
let install_surface_visibility = create_install_surface_visibility_payload(
registration_visibility,
config_visibility,
skill_visibility.clone(),
custom_agent_visibility,
);
let update_parity = create_update_parity_payload(
&path_shadow_diagnostics,
&config_surface_readiness,
&plugin_discovery,
&plugin_marketplace_discovery,
&skill_visibility,
&cap_continuity,
&custom_agent_sync,
&install_surface_visibility,
configured_role_models.as_slice(),
&concurrency_readiness,
&hooks_readiness,
if configured_role_models.is_empty() {
"missing"
} else {
"current"
},
if configured_role_models.is_empty() {
"No shared role-model configuration was found."
} else {
"Shared role-model configuration was loaded from the CCC config."
},
);
let plugin_discovery_surfaces = create_plugin_discovery_surfaces_payload(
&plugin_discovery,
&plugin_marketplace_discovery,
&cap_skill_visibility,
&legacy_bundle_cleanup,
&install_surface_visibility,
);
let custom_agent_status = custom_agent_sync
.get("status")
.and_then(Value::as_str)
.unwrap_or("unavailable");
let mut status = create_check_install_status(
registration_status,
&config_install_state,
cap_skill_status,
custom_agent_status,
&config_surface_readiness,
);
if path_shadow_diagnostics
.get("status")
.and_then(Value::as_str)
== Some("warning")
|| plugin_discovery
.get("status")
.and_then(Value::as_str)
.is_some_and(|value| value != "current")
|| plugin_marketplace_discovery
.get("status")
.and_then(Value::as_str)
.is_some_and(|value| value != "current")
|| cap_continuity
.get("status")
.and_then(Value::as_str)
.is_some_and(|value| value != "current")
{
status = "warning";
}
let mut payload = json!({
"status": status,
"packageName": env!("CARGO_PKG_NAME"),
"packageVersion": env!("CARGO_PKG_VERSION"),
"publicEntrySkillName": PUBLIC_ENTRY_SKILL_NAME,
"publicEntryLabel": PUBLIC_ENTRY_LABEL,
"serverName": SERVER_NAME,
"expectedLaunchCommand": expected_command,
"expectedLaunchArgs": expected_args,
"expectedEntrypointPath": session_context.entrypoint_path,
"registrationStatus": registration_status,
"registrationSummary": registration_summary,
"registeredLaunchCommand": registered_launch_command,
"registeredLaunchArgs": registered_launch_args,
"registeredEntrypointPath": Value::Null,
"configPath": preferred_config_path,
"configExists": config_exists,
"configCanonicalReady": config_install_state.canonical_ready,
"configStatus": config_install_state.status,
"configActionStatus": config_install_state.action_status,
"configBackupStatus": config_install_state.backup_status,
"configBackupSourcePath": config_install_state.backup_source_path_value(),
"configBackupPath": config_install_state.backup_path_value(),
"configSummary": config_install_state.summary.clone(),
"configSourcePath": config_install_state.source_path_value(),
"configRestartStatus": config_install_state.restart_status,
"entryPolicyModeStatus": config_install_state.entry_policy_mode_status,
"entryPolicyModeRaw": config_install_state.entry_policy_mode_raw_value(),
"entryPolicyModeCanonical": config_install_state.entry_policy_mode_canonical_value(),
"entryPolicyModeSummary": config_install_state.entry_policy_mode_summary.clone(),
"registryInspectionStatus": "available",
"registryInspectionSummary": "Codex CLI MCP registry was inspected successfully.",
"otherInstalledMcpServers": [],
"companionMcpUsageSummary": format!(
"Companion MCP inspection is outside the Rust {} install contract.",
env!("CARGO_PKG_VERSION")
),
"notebookLmArchiveTargetStatus": "disabled",
"notebookLmArchiveTargetSummary": format!(
"NotebookLM archive inspection is not part of the Rust {} baseline.",
env!("CARGO_PKG_VERSION")
),
"packagedHarnessSurfaceStatus": packaged_skill_source_status,
"packagedHarnessSurfaceSummary": if packaged_skill_source_status == "coherent_surface" {
"The packaged Rust install surface includes a resolvable $cap skill asset."
} else {
"The Rust binary could not resolve its packaged $cap skill asset."
},
"packagedPluginFileLookup": packaged_plugin_file_lookup,
"capSkillStatus": cap_skill_status,
"capSkillSummary": cap_skill_summary,
"capSkillPath": cap_skill_visibility.get("path").cloned().unwrap_or(Value::Null),
"capSkillActionStatus": cap_skill_visibility.get("action_status").cloned().unwrap_or(Value::String("inspection-blocked".to_string())),
"capSkillRestartStatus": cap_skill_visibility.get("restart_status").cloned().unwrap_or(Value::String("unknown".to_string())),
"capSkillSourcePath": cap_skill_visibility.get("source_path").cloned().unwrap_or(Value::Null),
"customAgentStatus": custom_agent_sync.get("status").cloned().unwrap_or(Value::String("unavailable".to_string())),
"customAgentSummary": custom_agent_sync.get("summary").cloned().unwrap_or(Value::String("Custom-agent sync state is unavailable.".to_string())),
"customAgentActionStatus": install_surface_visibility.pointer("/components/custom_agents/action_status").cloned().unwrap_or(Value::String("inspection-blocked".to_string())),
"customAgentRestartStatus": install_surface_visibility.pointer("/components/custom_agents/restart_status").cloned().unwrap_or(Value::String("unknown".to_string())),
"customAgentDirectoryPath": custom_agent_sync.get("directory_path").cloned().unwrap_or(Value::Null),
"customAgentNames": custom_agent_sync.get("generated_names").cloned().unwrap_or_else(|| Value::Array(Vec::new())),
"customAgentFileCount": custom_agent_sync.get("file_count").cloned().unwrap_or(Value::from(0)),
"customAgentMissingFiles": custom_agent_sync.get("missing_files").cloned().unwrap_or_else(|| Value::Array(Vec::new())),
"customAgentMismatchedFiles": custom_agent_sync.get("mismatched_files").cloned().unwrap_or_else(|| Value::Array(Vec::new())),
"customAgentStaleManagedFiles": custom_agent_sync.get("stale_managed_files").cloned().unwrap_or_else(|| Value::Array(Vec::new())),
"skillRegistryHealth": skill_registry_health,
"commandBudgetRouteModularity": command_budget_route_modularity,
"pluginDiscovery": plugin_discovery,
"pluginMarketplaceDiscovery": plugin_marketplace_discovery,
"pluginDiscoverySurfaces": plugin_discovery_surfaces,
"capContinuity": cap_continuity,
"executionContractRegistry": execution_contract_registry,
"configSurfaceReadiness": config_surface_readiness,
"concurrencyReadiness": concurrency_readiness,
"graphContextReadiness": graph_context_readiness,
"lspRuntimeReadiness": lsp_runtime_readiness,
"memoryReadiness": memory_readiness,
"hooksReadiness": hooks_readiness,
"pathShadowDiagnostics": path_shadow_diagnostics,
"legacyDirectRegistrationCleanup": legacy_direct_registration_cleanup,
"legacyBundleCleanup": legacy_bundle_cleanup,
"displayAliasContract": display_alias_contract,
"appServerRemoteParity": app_server_remote_parity,
"updateParity": update_parity,
"modelPolicyStatus": if configured_role_models.is_empty() { "missing_config" } else { "configured" },
"modelPolicySummary": if configured_role_models.is_empty() {
"No shared role-model configuration was found."
} else {
"Shared role-model configuration was loaded from the CCC config."
},
"configuredRoleModels": configured_role_models,
"toolRoutingPolicyStatus": "not_packaged",
"toolRoutingPolicySummary": format!(
"Companion tool-routing inspection is not part of the Rust {} install contract.",
env!("CARGO_PKG_VERSION")
),
"configuredToolRoutes": [],
"activeRunHygieneStatus": "clean",
"activeRunHygieneSummary": format!(
"No run-hygiene issues are reported by the Rust {} installer surface.",
env!("CARGO_PKG_VERSION")
),
"installSurfaceVisibility": install_surface_visibility,
"recommendedRunId": Value::Null,
"session_registration_match": if registration_status == "matching_registration" { "matching" } else { "unknown" },
});
if let Some(object) = payload.as_object_mut() {
object.insert(
"setupMigrationDeltas".to_string(),
config_install_state.setup_migration_deltas_value(),
);
object.insert("pluginCliParity".to_string(), plugin_cli_parity);
object.insert("permissionProfile".to_string(), permission_profile);
object.insert(
"multiAgentRuntimeContract".to_string(),
multi_agent_runtime_contract,
);
}
payload
}
pub(crate) fn collect_install_check_payload(session_context: &SessionContext) -> Value {
collect_install_check_payload_for_config_path(session_context, resolve_shared_config_path())
}
pub(crate) fn create_install_check_payload(session_context: &SessionContext) -> Value {
collect_install_check_payload(session_context)
}
pub(crate) fn create_server_identity_text(session_context: &SessionContext) -> String {
format!(
"Attached CCC MCP session {} is running through the Rust {} runtime.",
session_context.session_id,
env!("CARGO_PKG_VERSION")
)
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeSet;
use std::time::{SystemTime, UNIX_EPOCH};
fn create_temp_codex_home(label: &str) -> PathBuf {
let suffix = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_nanos();
env::temp_dir().join(format!("ccc-install-check-{label}-{suffix}"))
}
fn create_plugin_cache_binary(codex_home: &Path) -> String {
let command = codex_home
.join("plugins")
.join("cache")
.join("ccc-local")
.join("ccc")
.join(env!("CARGO_PKG_VERSION"))
.join("bin")
.join("ccc");
fs::create_dir_all(command.parent().expect("plugin command parent"))
.expect("create plugin-cache bin dir");
fs::write(&command, "#!/bin/sh\n").expect("write plugin-cache binary stub");
resolve_plugin_cache_launch_command_at(codex_home).expect("resolve plugin-cache command")
}
fn registry_record(command: String, args: Vec<&str>) -> CodexMcpRegistryRecord {
CodexMcpRegistryRecord {
name: SERVER_NAME.to_string(),
enabled: true,
transport: Some(CodexMcpRegistryTransport {
transport_type: "stdio".to_string(),
command: Some(command),
args: Some(args.into_iter().map(str::to_string).collect()),
}),
}
}
#[test]
fn installed_crate_layout_resolves_packaged_plugin_files() {
let crate_root = create_temp_codex_home("installed-crate-assets");
let lookups = required_packaged_plugin_file_lookups();
for lookup in &lookups {
let path = crate_root.join(&lookup.crate_relative_path);
fs::create_dir_all(path.parent().expect("asset parent")).expect("create asset parent");
fs::write(&path, format!("{}\n", lookup.name)).expect("write packaged asset");
}
let payload = inspect_packaged_plugin_file_lookup_at(&crate_root);
assert_eq!(payload["schema"], "ccc.packaged_plugin_file_lookup.v1");
assert_eq!(payload["status"], "coherent_surface");
assert_eq!(payload["required_asset_count"], lookups.len());
assert!(payload["missing"]
.as_array()
.expect("missing assets")
.is_empty());
let asset_for = |name: &str| {
payload["assets"]
.as_array()
.expect("assets")
.iter()
.find(|asset| asset["name"] == name)
.unwrap_or_else(|| panic!("missing asset payload for {name}"))
};
assert_eq!(
asset_for("plugin_manifest")["plugin_relative_path"],
".codex-plugin/plugin.json"
);
assert_eq!(
asset_for("mcp_manifest")["plugin_relative_path"],
".mcp.json"
);
assert_eq!(
asset_for("cap_skill")["crate_relative_path"],
"assets/skills/cap/SKILL.md"
);
assert_eq!(
asset_for("ccc_plugin_skill")["crate_relative_path"],
"assets/plugin/skills/ccc/SKILL.md"
);
let ssl_assets = payload["assets"]
.as_array()
.expect("assets")
.iter()
.filter(|asset| {
asset["name"]
.as_str()
.unwrap_or_default()
.starts_with("ssl_manifest:")
})
.collect::<Vec<_>>();
assert_eq!(ssl_assets.len(), managed_skill_ssl_agent_names().len());
assert!(ssl_assets.iter().all(|asset| asset["plugin_relative_path"]
.as_str()
.unwrap_or_default()
.starts_with("skills/ssl/")));
let _ = fs::remove_dir_all(&crate_root);
}
#[test]
fn installed_crate_layout_checks_packaged_ssl_manifests_without_public_drift() {
let crate_root = create_temp_codex_home("installed-crate-ssl");
let source_asset_dir = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("assets")
.join("skills")
.join("ssl");
let crate_asset_dir = crate_root.join("assets").join("skills").join("ssl");
fs::create_dir_all(&crate_asset_dir).expect("create installed ssl asset dir");
for agent_name in managed_skill_ssl_agent_names() {
let file_name = format!("{agent_name}.skill.ssl.json");
fs::copy(
source_asset_dir.join(&file_name),
crate_asset_dir.join(&file_name),
)
.expect("copy ssl manifest fixture");
}
let ssl_manifests = managed_skill_ssl_agent_names()
.into_iter()
.flat_map(|agent_name| {
create_command_budget_ssl_manifest_sources_at(&crate_root, &agent_name)
})
.collect::<Vec<_>>();
let payload = create_command_budget_route_modularity_payload_from_manifest_sources(
None,
Some("$cap\n"),
None,
ssl_manifests,
create_route_modularity_check_payload(&json!({})),
);
let checks = payload["ssl_manifest_checks"]
.as_array()
.expect("ssl manifest checks");
assert_eq!(payload["status"], "ok");
assert_eq!(payload["problem_count"], 0);
assert_eq!(checks.len(), managed_skill_ssl_agent_names().len());
assert!(checks.iter().all(|check| check["source"] == "packaged"));
assert!(checks.iter().all(|check| check["status"] == "available"));
assert!(checks.iter().all(|check| {
check["path"]
.as_str()
.unwrap_or_default()
.contains("assets/skills/ssl/")
}));
let _ = fs::remove_dir_all(&crate_root);
}
#[test]
fn plugin_cache_discovery_reuses_packaged_plugin_runtime_paths() {
let packaged_paths = required_packaged_plugin_file_lookups()
.into_iter()
.map(|lookup| {
(
lookup.name,
lookup.plugin_relative_path.to_string_lossy().to_string(),
)
})
.collect::<BTreeSet<_>>();
let cache_lookups = required_plugin_cache_file_lookups();
let cache_packaged_paths = cache_lookups
.iter()
.filter(|lookup| lookup.source == "packaged_plugin_file")
.map(|lookup| {
(
lookup.name.clone(),
lookup.relative_path.to_string_lossy().to_string(),
)
})
.collect::<BTreeSet<_>>();
assert_eq!(cache_packaged_paths, packaged_paths);
assert!(cache_packaged_paths
.iter()
.any(|(name, path)| name == "plugin_manifest" && path == ".codex-plugin/plugin.json"));
assert!(cache_packaged_paths
.iter()
.any(|(name, path)| name == "mcp_manifest" && path == ".mcp.json"));
assert!(cache_packaged_paths
.iter()
.any(|(name, path)| name == "cap_skill" && path == "skills/cap/SKILL.md"));
assert!(cache_packaged_paths
.iter()
.any(|(name, path)| name == "ccc_plugin_skill" && path == "skills/ccc/SKILL.md"));
assert_eq!(
cache_packaged_paths
.iter()
.filter(|(name, path)| {
name.starts_with("ssl_manifest:") && path.starts_with("skills/ssl/")
})
.count(),
managed_skill_ssl_agent_names().len()
);
let cache_only = cache_lookups
.iter()
.filter(|lookup| lookup.source == "plugin_cache_only")
.collect::<Vec<_>>();
assert_eq!(cache_only.len(), 1);
assert_eq!(cache_only[0].name, "mcp_binary");
assert_eq!(
cache_only[0].relative_path,
PathBuf::from("bin").join(ccc_binary_name())
);
assert!(!packaged_paths
.iter()
.any(|(name, path)| name == "mcp_binary" || path.starts_with("bin/")));
}
#[test]
fn packaged_harness_surface_status_remains_cap_skill_specific() {
let crate_root = create_temp_codex_home("cap-specific-harness-status");
let cap_skill = crate_root.join("assets/skills/cap/SKILL.md");
fs::create_dir_all(cap_skill.parent().expect("cap skill parent"))
.expect("create cap skill parent");
fs::write(&cap_skill, "name: cap\n").expect("write cap skill");
let plugin_lookup = inspect_packaged_plugin_file_lookup_at(&crate_root);
let harness_status =
packaged_harness_surface_status_from_cap_skill_source(Ok(cap_skill.clone()));
assert_eq!(harness_status, "coherent_surface");
assert_eq!(plugin_lookup["status"], "incomplete_surface");
assert!(plugin_lookup["missing"]
.as_array()
.expect("missing assets")
.iter()
.any(|asset| asset == "mcp_manifest"));
assert!(plugin_lookup["missing"]
.as_array()
.expect("missing assets")
.iter()
.any(|asset| asset == "ccc_plugin_skill"));
let _ = fs::remove_dir_all(&crate_root);
}
#[test]
fn packaged_cap_skill_source_prefers_crate_asset_over_repo_root_skill() {
let source = resolve_packaged_cap_skill_source().expect("resolve packaged cap skill");
let expected = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("assets")
.join("skills")
.join(PUBLIC_ENTRY_SKILL_NAME)
.join("SKILL.md");
assert!(
same_path(&source, &expected),
"resolved {} but expected packaged crate asset {}",
source.display(),
expected.display()
);
}
#[test]
fn path_shadow_diagnostics_reports_legacy_bin_shadowing_cargo() {
let home = create_temp_codex_home("path-shadow-home");
let cargo_bin = home.join(".cargo").join("bin");
let legacy_bin = home.join(".local").join("bin");
fs::create_dir_all(&cargo_bin).expect("create cargo bin");
fs::create_dir_all(&legacy_bin).expect("create legacy bin");
let cargo_ccc = cargo_bin.join(ccc_binary_name());
let legacy_ccc = legacy_bin.join(ccc_binary_name());
fs::write(&cargo_ccc, "#!/bin/sh\n").expect("write cargo ccc");
fs::write(&legacy_ccc, "#!/bin/sh\n").expect("write legacy ccc");
let path_value = env::join_paths([legacy_bin.as_path(), cargo_bin.as_path()])
.expect("join path entries");
let diagnostics = create_path_shadow_diagnostics_at(
Some(&home),
Some(path_value.as_os_str()),
Some(&legacy_ccc),
Some(Ok(env!("CARGO_PKG_VERSION").to_string())),
);
assert_eq!(diagnostics["status"], "warning");
assert_eq!(diagnostics["legacyShadowsCargo"], true);
assert_eq!(diagnostics["cargoBinaryCandidateVersionMatches"], true);
assert_eq!(diagnostics["expectedLaunchCommandSource"], "cargo_binary");
assert!(diagnostics["summary"]
.as_str()
.expect("summary")
.contains("~/.local/bin/ccc is shadowing the Cargo install"));
assert!(diagnostics["recommendation"]
.as_str()
.expect("recommendation")
.contains("setup"));
let _ = fs::remove_dir_all(&home);
}
#[test]
fn legacy_bundle_cleanup_reports_bundle_and_stale_plugin_cache_paths() {
let home = create_temp_codex_home("legacy-bundle-home");
let codex_home = create_temp_codex_home("legacy-bundle-codex");
let release_path = home
.join(".local")
.join("share")
.join("ccc")
.join("releases")
.join("0.0.0-darwin-arm64");
let current_path = home
.join(".local")
.join("share")
.join("ccc")
.join("current");
let marketplace_path = home
.join(".local")
.join("share")
.join("ccc")
.join("plugin-marketplace");
let stale_plugin_path = codex_home
.join("plugins")
.join("cache")
.join("ccc-local")
.join("ccc")
.join("0.0.0");
let current_plugin_path = codex_home
.join("plugins")
.join("cache")
.join("ccc-local")
.join("ccc")
.join(env!("CARGO_PKG_VERSION"));
fs::create_dir_all(&release_path).expect("create release path");
fs::create_dir_all(¤t_path).expect("create current path");
fs::create_dir_all(&marketplace_path).expect("create marketplace path");
fs::create_dir_all(&stale_plugin_path).expect("create stale plugin path");
fs::create_dir_all(¤t_plugin_path).expect("create current plugin path");
let cleanup = create_legacy_bundle_cleanup_payload_at(Some(&home), Some(&codex_home));
let paths = cleanup["stalePaths"].as_array().expect("stale paths");
assert_eq!(cleanup["status"], "present");
assert_eq!(cleanup["stalePathCount"], 4);
assert!(paths.iter().any(|path| path
.as_str()
.unwrap_or_default()
.contains("0.0.0-darwin-arm64")));
assert!(paths
.iter()
.any(|path| path.as_str().unwrap_or_default().ends_with("/current")));
assert!(paths.iter().any(|path| path
.as_str()
.unwrap_or_default()
.ends_with("/plugin-marketplace")));
assert!(paths
.iter()
.any(|path| path.as_str().unwrap_or_default().ends_with("/0.0.0")));
assert!(!paths.iter().any(|path| {
path.as_str()
.unwrap_or_default()
.ends_with(env!("CARGO_PKG_VERSION"))
}));
let _ = fs::remove_dir_all(&home);
let _ = fs::remove_dir_all(&codex_home);
}
#[test]
fn legacy_direct_registration_cleanup_allows_current_mcp_registration() {
let codex_home = create_temp_codex_home("current-direct-mcp");
fs::create_dir_all(&codex_home).expect("create codex home");
let (expected_command, expected_args) =
resolve_expected_launch_command().expect("expected launch command");
fs::write(
codex_home.join("config.toml"),
format!(
"[mcp_servers.ccc]\ncommand = \"{}\"\nargs = [{}]\n",
expected_command,
expected_args
.iter()
.map(|arg| format!("\"{arg}\""))
.collect::<Vec<_>>()
.join(", ")
),
)
.expect("write codex config");
let cleanup = create_legacy_direct_registration_cleanup_payload_at(&codex_home);
assert_eq!(cleanup["status"], "verified_clean");
assert_eq!(cleanup["direct_mcp_servers_ccc_present"], true);
assert_eq!(cleanup["direct_mcp_servers_ccc_current"], true);
assert_eq!(cleanup["legacy_direct_mcp_servers_ccc_present"], false);
let _ = fs::remove_dir_all(&codex_home);
}
fn current_config_state(value: Value) -> CccConfigInstallState {
CccConfigInstallState {
status: "canonical-current",
action_status: "preserved",
backup_status: "not-required",
summary: "Canonical config is current.".to_string(),
source_path: None,
backup_source_path: None,
backup_path: None,
value,
canonical_ready: true,
config_exists: true,
restart_status: "not-required",
entry_policy_mode_status: "canonical",
entry_policy_mode_raw: Some("guided_explicit".to_string()),
entry_policy_mode_canonical: Some("guided_explicit".to_string()),
entry_policy_mode_summary:
"Entry policy mode `guided_explicit` is canonical and supported.".to_string(),
setup_migration_deltas: Value::Null,
}
}
#[test]
fn optional_missing_config_surfaces_do_not_block_current_readiness() {
let config_state = current_config_state(json!({
"version": env!("CARGO_PKG_VERSION"),
"generated_defaults": {
"version": CURRENT_GENERATED_DEFAULTS_VERSION,
},
"routing": {
"mode": "category_shortlist",
"categories": {
"write_code": {
"agents": ["raider"],
},
},
},
"runtime": {
"preferred_specialist_execution_mode": "codex_subagent",
"fallback_specialist_execution_mode": "codex_exec",
},
}));
let readiness = create_config_surface_readiness_payload(
&config_state,
&json!({
"status": "available",
"role_count": managed_custom_agent_role_count(),
}),
&json!({
"status": "matching_sync",
}),
);
let status_for = |surface_id: &str| {
readiness["surfaces"]
.as_array()
.expect("surfaces")
.iter()
.find(|surface| surface["surface"] == surface_id)
.and_then(|surface| surface["status"].as_str())
.unwrap_or("missing")
.to_string()
};
assert_eq!(readiness["status"], "current");
assert_eq!(readiness["missing_count"], 0);
assert_eq!(readiness["optional_missing_count"], 5);
assert_eq!(status_for("concurrency"), "optional_missing");
assert_eq!(status_for("prompt_sections"), "optional_missing");
assert_eq!(status_for("directory_rule_injection"), "optional_missing");
assert_eq!(status_for("hook_settings"), "optional_missing");
assert_eq!(status_for("lsp_runtime"), "optional_missing");
assert_eq!(
create_check_install_status(
"matching_registration",
&config_state,
"matching_install",
"matching_sync",
&readiness,
),
"ok"
);
let partial_role_count = managed_custom_agent_role_count() - 1;
let partial_readiness = create_config_surface_readiness_payload(
&config_state,
&json!({
"status": "available",
"role_count": partial_role_count,
}),
&json!({
"status": "matching_sync",
}),
);
let partial_registry = partial_readiness["surfaces"]
.as_array()
.expect("surfaces")
.iter()
.find(|surface| surface["surface"] == "registry")
.expect("registry surface");
assert_eq!(partial_registry["status"], "stale");
assert_eq!(
partial_registry["summary"],
format!(
"Execution contract registry is partial: roles={partial_role_count}/{}.",
managed_custom_agent_role_count()
)
);
assert_eq!(
create_check_install_status(
"matching_registration",
&config_state,
"matching_install",
"matching_sync",
&partial_readiness,
),
"warning"
);
}
#[test]
fn registration_match_accepts_versioned_plugin_cache_mcp_command() {
let expected_command =
"/Users/example/.local/share/ccc/releases/0.0.1-darwin-arm64/bin/ccc".to_string();
let expected_args = vec!["mcp".to_string()];
let codex_home = create_temp_codex_home("matching-plugin-cache");
let plugin_cache_command = create_plugin_cache_binary(&codex_home);
let accepted_commands = vec![expected_command.clone(), plugin_cache_command.clone()];
let record = registry_record(plugin_cache_command, vec!["mcp"]);
assert!(registration_matches_any_expected(
&record,
&accepted_commands,
&expected_args
));
}
#[test]
fn registration_match_rejects_wrong_plugin_cache_version_and_args() {
let expected_command =
"/Users/example/.local/share/ccc/releases/0.0.1-darwin-arm64/bin/ccc".to_string();
let expected_args = vec!["mcp".to_string()];
let codex_home = create_temp_codex_home("wrong-plugin-cache");
let plugin_cache_command = create_plugin_cache_binary(&codex_home);
let accepted_commands = vec![expected_command.clone(), plugin_cache_command.clone()];
let wrong_version_command = codex_home
.join("plugins")
.join("cache")
.join("ccc-local")
.join("ccc")
.join("0.0.0")
.join("bin")
.join("ccc")
.to_string_lossy()
.into_owned();
assert!(!registration_matches_any_expected(
®istry_record(wrong_version_command, vec!["mcp"]),
&accepted_commands,
&expected_args
));
assert!(!registration_matches_any_expected(
®istry_record(plugin_cache_command, vec!["status"]),
&accepted_commands,
&expected_args
));
}
}