use clap::ValueEnum;
use sha2::{Digest, Sha256};
use std::collections::BTreeSet;
use std::path::{Path, PathBuf};
use std::time::Duration;
pub(crate) const CODEX_REMOTE_TOKEN_ENV: &str = "SUPERCODE_CODEX_REMOTE_TOKEN";
pub(crate) const GOOSE_BRIDGE_ADDRESS_ENV: &str = "SUPERCODE_GOOSE_BRIDGE_ADDRESS";
pub(crate) const GOOSE_BRIDGE_NONCE_ENV: &str = "SUPERCODE_GOOSE_BRIDGE_NONCE";
pub(crate) const GOOSE_NODE_VERSION: &str = "23.9.0";
pub(crate) const GOOSE_TUI_VERSION: &str = "0.20.1";
pub(crate) const GOOSE_TUI_SOURCE_ENV: &str = "SUPERCODE_GOOSE_TUI_SOURCE";
pub(crate) const PI_FRONTEND_URL_ENV: &str = "SUPERCODE_PI_FRONTEND_URL";
pub(crate) const PI_FRONTEND_CLIENT_ID_ENV: &str = "SUPERCODE_PI_FRONTEND_CLIENT_ID";
pub(crate) const PI_FRONTEND_CREDENTIAL_FILE_ENV: &str = "SUPERCODE_PI_FRONTEND_CREDENTIAL_FILE";
pub(crate) const PI_FRONTEND_PERMISSIONS_ENV: &str = "SUPERCODE_PI_FRONTEND_PERMISSIONS";
pub(crate) const PI_FRONTEND_TAKE_CONTROL_ENV: &str = "SUPERCODE_PI_FRONTEND_TAKE_CONTROL";
const SECRET_ENVIRONMENT: &[&str] = &[
"OPENAI_API_KEY",
"OPENROUTER_API_KEY",
"ANTHROPIC_API_KEY",
"SUPERCODE_API_KEY",
"SUPERCODE_SUPERVISED_API_KEY",
"SUPERCODE_SERVER_TOKEN",
];
const OPENCODE_DISABLE_ENVIRONMENT: &[&str] = &[
"OPENCODE_DISABLE_AUTOUPDATE",
"OPENCODE_DISABLE_AUTOCOMPACT",
"OPENCODE_DISABLE_CLAUDE_CODE",
"OPENCODE_DISABLE_DEFAULT_PLUGINS",
"OPENCODE_DISABLE_EXTERNAL_SKILLS",
"OPENCODE_DISABLE_FILETIME_CHECK",
"OPENCODE_DISABLE_LSP_DOWNLOAD",
"OPENCODE_DISABLE_MODELS_FETCH",
"OPENCODE_DISABLE_PROJECT_CONFIG",
"OPENCODE_DISABLE_PRUNE",
"OPENCODE_DISABLE_SHARE",
"OPENCODE_DISABLE_TERMINAL_TITLE",
];
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, ValueEnum)]
pub(crate) enum FrontendClientId {
#[default]
Embedded,
Codex,
Opencode,
Goose,
Pi,
}
impl FrontendClientId {
pub(crate) const fn as_str(self) -> &'static str {
match self {
Self::Embedded => "embedded",
Self::Codex => "codex",
Self::Opencode => "opencode",
Self::Goose => "goose",
Self::Pi => "pi",
}
}
pub(crate) const fn spec(self) -> &'static FrontendClientSpec {
match self {
Self::Embedded => &CLIENTS[0],
Self::Codex => &CLIENTS[1],
Self::Opencode => &CLIENTS[2],
Self::Goose => &CLIENTS[3],
Self::Pi => &CLIENTS[4],
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum ClientTransport {
EmbeddedSdk,
CodexAppServerWebSocket,
OpenCodeHttp,
AcpStdio,
FrontendHttpV2,
}
impl ClientTransport {
pub(crate) const fn as_str(self) -> &'static str {
match self {
Self::EmbeddedSdk => "embedded-sdk",
Self::CodexAppServerWebSocket => "codex-app-server-websocket",
Self::OpenCodeHttp => "opencode-http",
Self::AcpStdio => "acp-stdio",
Self::FrontendHttpV2 => "frontend-http-v2",
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct FrontendClientSpec {
pub(crate) id: FrontendClientId,
pub(crate) binary: Option<&'static str>,
pub(crate) version_args: &'static [&'static str],
pub(crate) supported_version: Option<&'static str>,
pub(crate) transports: &'static [ClientTransport],
pub(crate) compatible: bool,
pub(crate) install_guidance: &'static str,
pub(crate) features: &'static [&'static str],
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct FrontendClientProbe {
pub(crate) id: FrontendClientId,
pub(crate) installed: bool,
pub(crate) compatible: bool,
pub(crate) version: Option<String>,
pub(crate) detail: String,
}
pub(crate) struct PiLaunch<'a> {
pub(crate) cwd: &'a Path,
pub(crate) client_root: &'a Path,
pub(crate) base_url: &'a str,
pub(crate) client_id: &'a str,
pub(crate) credential_path: &'a Path,
pub(crate) permissions: &'a str,
pub(crate) take_control: bool,
}
impl FrontendClientSpec {
pub(crate) async fn probe(&self) -> FrontendClientProbe {
self.probe_untrusted().await.sanitized()
}
async fn probe_untrusted(&self) -> FrontendClientProbe {
if self.id == FrontendClientId::Goose {
if let Err(detail) = pinned_goose_tui() {
return FrontendClientProbe {
id: self.id,
installed: false,
compatible: false,
version: None,
detail,
};
}
}
let Some(binary) = self.binary else {
return FrontendClientProbe {
id: self.id,
installed: true,
compatible: true,
version: Some(env!("CARGO_PKG_VERSION").into()),
detail: "embedded frontend is included with supercode".into(),
};
};
let root = match ProbeRoot::create(self.id.as_str()) {
Ok(root) => root,
Err(error) => {
return FrontendClientProbe {
id: self.id,
installed: false,
compatible: false,
version: None,
detail: format!("cannot create isolated probe home: {error}"),
}
}
};
let mut command = tokio::process::Command::new(binary);
command
.args(self.version_args)
.current_dir(root.path())
.kill_on_drop(true);
isolate_environment(&mut command, root.path());
let output = match tokio::time::timeout(Duration::from_secs(5), command.output()).await {
Err(_) => {
return FrontendClientProbe {
id: self.id,
installed: true,
compatible: false,
version: None,
detail: "version probe exceeded the five-second deadline".into(),
}
}
Ok(Err(error)) if error.kind() == std::io::ErrorKind::NotFound => {
return FrontendClientProbe {
id: self.id,
installed: false,
compatible: false,
version: None,
detail: self.install_guidance.into(),
}
}
Ok(Err(error)) => {
return FrontendClientProbe {
id: self.id,
installed: false,
compatible: false,
version: None,
detail: format!("version probe failed: {error}"),
}
}
Ok(Ok(output)) => output,
};
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
let version = if stdout.is_empty() { stderr } else { stdout };
let version_matches = self.supported_version.is_none_or(|expected| {
version == expected
|| version
.split_whitespace()
.any(|part| part == expected || part.trim_start_matches('v') == expected)
});
let compatible = output.status.success() && version_matches && self.compatible;
let detail = if !output.status.success() {
format!("version probe exited with {}", output.status)
} else if !version_matches {
format!(
"protocol_version_mismatch: expected {}, found `{}`",
self.supported_version.unwrap_or("declared version"),
if version.is_empty() {
"unknown"
} else {
&version
}
)
} else if !self.compatible {
self.install_guidance.into()
} else {
format!("installed compatible client `{version}`")
};
FrontendClientProbe {
id: self.id,
installed: true,
compatible,
version: (!version.is_empty()).then_some(version),
detail,
}
}
pub(crate) fn codex_launch_command(
&self,
cwd: &Path,
client_home: &Path,
remote: &str,
) -> Result<tokio::process::Command, &'static str> {
if self.id != FrontendClientId::Codex {
return Err("only the codex registry row builds a Codex launch");
}
let mut command =
tokio::process::Command::new(self.binary.ok_or("Codex registry row has no binary")?);
command
.current_dir(cwd)
.arg("--remote")
.arg(remote)
.arg("--remote-auth-token-env")
.arg(CODEX_REMOTE_TOKEN_ENV)
.arg("--disable")
.arg("plugins")
.kill_on_drop(true);
#[cfg(unix)]
{
use std::os::unix::process::CommandExt;
command.as_std_mut().process_group(0);
}
isolate_stock_codex_environment(&mut command, client_home);
Ok(command)
}
pub(crate) fn opencode_launch_command(
&self,
cwd: &Path,
client_root: &Path,
endpoint: &str,
session_id: &str,
) -> Result<tokio::process::Command, &'static str> {
if self.id != FrontendClientId::Opencode {
return Err("only the opencode registry row builds an OpenCode launch");
}
let mut command =
tokio::process::Command::new(self.binary.ok_or("OpenCode registry row has no binary")?);
command
.current_dir(cwd)
.arg("attach")
.arg(endpoint)
.arg("--dir")
.arg(cwd)
.arg("--session")
.arg(session_id)
.kill_on_drop(true);
#[cfg(unix)]
{
use std::os::unix::process::CommandExt;
command.as_std_mut().process_group(0);
}
isolate_stock_opencode_environment(&mut command, client_root);
Ok(command)
}
pub(crate) fn goose_launch_command(
&self,
cwd: &Path,
client_root: &Path,
supercode_executable: &Path,
pinned_tui: &PinnedGooseTui,
bridge_address: &str,
bridge_nonce: &str,
) -> Result<tokio::process::Command, &'static str> {
if self.id != FrontendClientId::Goose {
return Err("only the goose registry row builds a Goose launch");
}
let mut command =
tokio::process::Command::new(self.binary.ok_or("Goose registry row has no binary")?);
command
.current_dir(cwd)
.arg(&pinned_tui.tsx_loader)
.arg("--tsconfig")
.arg(pinned_tui.runtime_root.join("text/tsconfig.json"))
.arg(&pinned_tui.source)
.kill_on_drop(true);
#[cfg(unix)]
{
use std::os::unix::process::CommandExt;
command.as_std_mut().process_group(0);
}
isolate_stock_goose_environment(&mut command, client_root);
command
.env("GOOSE_BINARY", supercode_executable)
.env(GOOSE_BRIDGE_ADDRESS_ENV, bridge_address)
.env(GOOSE_BRIDGE_NONCE_ENV, bridge_nonce);
Ok(command)
}
pub(crate) fn pi_launch_command(
&self,
launch: PiLaunch<'_>,
) -> Result<tokio::process::Command, &'static str> {
if self.id != FrontendClientId::Pi {
return Err("only the pi registry row builds a Pi frontend launch");
}
let mut command =
tokio::process::Command::new(self.binary.ok_or("Pi registry row has no binary")?);
command.current_dir(launch.cwd).kill_on_drop(true);
isolate_pi_frontend_environment(&mut command, launch.client_root);
command
.env(PI_FRONTEND_URL_ENV, launch.base_url)
.env(PI_FRONTEND_CLIENT_ID_ENV, launch.client_id)
.env(PI_FRONTEND_CREDENTIAL_FILE_ENV, launch.credential_path)
.env(PI_FRONTEND_PERMISSIONS_ENV, launch.permissions)
.env(
PI_FRONTEND_TAKE_CONTROL_ENV,
if launch.take_control { "1" } else { "0" },
);
Ok(command)
}
}
impl FrontendClientProbe {
fn sanitized(mut self) -> Self {
self.version = self.version.map(|value| sanitize_probe_text(&value));
self.detail = sanitize_probe_text(&self.detail);
self
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct PinnedGooseTui {
runtime_root: PathBuf,
pub(crate) source: PathBuf,
pub(crate) tsx_loader: PathBuf,
}
const GOOSE_RUNTIME_CLOSURE: &str =
include_str!("../embedded/goose-runtime-closure-acd3c135.sha256");
fn verify_hashed_file_set(root: &Path, manifest: &str) -> Result<usize, String> {
let mut seen = BTreeSet::new();
for (index, line) in manifest.lines().enumerate() {
if line.is_empty() || line.starts_with('#') {
continue;
}
let (expected, relative) = line
.split_once(" ")
.ok_or_else(|| format!("invalid pinned Goose runtime manifest line {}", index + 1))?;
if expected.len() != 64
|| !expected
.bytes()
.all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
{
return Err(format!(
"invalid hash on pinned Goose runtime manifest line {}",
index + 1
));
}
let relative = Path::new(relative);
if relative.is_absolute()
|| !relative
.components()
.all(|component| matches!(component, std::path::Component::Normal(_)))
{
return Err(format!(
"unsafe path on pinned Goose runtime manifest line {}",
index + 1
));
}
if !seen.insert(relative.to_path_buf()) {
return Err(format!(
"duplicate path on pinned Goose runtime manifest line {}",
index + 1
));
}
let path = root.join(relative);
let bytes = std::fs::read(&path).map_err(|error| {
format!(
"reading pinned Goose runtime module {}: {error}",
path.display()
)
})?;
let actual = format!("{:x}", Sha256::digest(bytes));
if actual != expected {
return Err(format!(
"pinned Goose runtime module hash mismatch for {}: expected {expected}, found {actual}",
path.display()
));
}
}
Ok(seen.len())
}
fn materialize_hashed_file_set(
source_root: &Path,
destination_root: &Path,
manifest: &str,
) -> Result<usize, String> {
std::fs::create_dir(destination_root).map_err(|error| {
format!(
"creating private pinned Goose runtime {}: {error}",
destination_root.display()
)
})?;
let mut seen = BTreeSet::new();
for (index, line) in manifest.lines().enumerate() {
if line.is_empty() || line.starts_with('#') {
continue;
}
let (expected, relative) = line
.split_once(" ")
.ok_or_else(|| format!("invalid pinned Goose runtime manifest line {}", index + 1))?;
let relative = Path::new(relative);
if expected.len() != 64
|| !expected
.bytes()
.all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
|| relative.is_absolute()
|| !relative
.components()
.all(|component| matches!(component, std::path::Component::Normal(_)))
|| !seen.insert(relative.to_path_buf())
{
return Err(format!(
"invalid pinned Goose materialization manifest line {}",
index + 1
));
}
let source = source_root.join(relative);
let bytes = std::fs::read(&source).map_err(|error| {
format!(
"reading pinned Goose runtime module {}: {error}",
source.display()
)
})?;
let actual = format!("{:x}", Sha256::digest(&bytes));
if actual != expected {
return Err(format!(
"pinned Goose runtime module hash mismatch for {}: expected {expected}, found {actual}",
source.display()
));
}
let destination = destination_root.join(relative);
std::fs::create_dir_all(destination.parent().expect("manifest file has a parent"))
.map_err(|error| {
format!(
"creating pinned Goose runtime directory for {}: {error}",
destination.display()
)
})?;
let mut output = std::fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(&destination)
.map_err(|error| {
format!(
"creating pinned Goose runtime module {}: {error}",
destination.display()
)
})?;
use std::io::Write as _;
output.write_all(&bytes).map_err(|error| {
format!(
"writing pinned Goose runtime module {}: {error}",
destination.display()
)
})?;
#[cfg(unix)]
if is_pinned_esbuild_helper(relative) {
use std::os::unix::fs::PermissionsExt as _;
std::fs::set_permissions(&destination, std::fs::Permissions::from_mode(0o500))
.map_err(|error| {
format!(
"marking pinned Goose runtime helper {} executable: {error}",
destination.display()
)
})?;
}
}
Ok(seen.len())
}
fn is_pinned_esbuild_helper(relative: &Path) -> bool {
let components = relative
.components()
.filter_map(|component| match component {
std::path::Component::Normal(value) => Some(value),
_ => None,
})
.collect::<Vec<_>>();
components.len() == 5
&& components[0] == "node_modules"
&& components[1] == "@esbuild"
&& components[3] == "bin"
&& components[4] == "esbuild"
}
pub(crate) fn materialize_pinned_goose_tui(
pinned: &PinnedGooseTui,
destination_root: &Path,
) -> Result<PinnedGooseTui, String> {
let count = materialize_hashed_file_set(
&pinned.runtime_root,
destination_root,
GOOSE_RUNTIME_CLOSURE,
)?;
if count < 800 {
return Err(format!(
"pinned Goose runtime manifest is incomplete: only {count} modules"
));
}
Ok(PinnedGooseTui {
runtime_root: destination_root.to_path_buf(),
source: destination_root.join("text/src/tui.tsx"),
tsx_loader: destination_root.join("node_modules/tsx/dist/cli.mjs"),
})
}
pub(crate) fn pinned_goose_tui() -> Result<PinnedGooseTui, String> {
resolve_pinned_goose_tui(true)
}
pub(crate) fn pinned_goose_tui_for_materialization() -> Result<PinnedGooseTui, String> {
resolve_pinned_goose_tui(false)
}
fn resolve_pinned_goose_tui(verify_runtime_closure: bool) -> Result<PinnedGooseTui, String> {
const FILES: &[(&str, &str)] = &[
(
"text/src/tui.tsx",
"1317711954269af9f01f46ffe3260a95f340b163ac31da9c166d97d18ebb68c1",
),
(
"text/package.json",
"1d6001425eccbf3d0c32319f4cbb8c1a6ba12c6165bd15c07fe2ddd203cbdd9d",
),
(
"sdk/src/goose-client.ts",
"17c085d23d7025a917dac1055f7905b7dc7937d2d229e89779ac4c9512760e08",
),
(
"sdk/src/resolve-binary.ts",
"dd5675d4e5c1f790b13cf237ffb666d6d3133e418d59d3a41a7f042b215234e1",
),
(
"sdk/package.json",
"c7bd484589579d85f76313c91dd8a88ccb4ea99b37cb8e48fcd0e558eb8fa19a",
),
(
"pnpm-lock.yaml",
"23657ec74c96954ad06e7fb511ee433729c383fc5131ebf592ab4b59963d1207",
),
];
let source = std::env::var_os(GOOSE_TUI_SOURCE_ENV).ok_or_else(|| {
format!(
"set {GOOSE_TUI_SOURCE_ENV} to ui/text/src/tui.tsx from aaif-goose/goose@acd3c135cff7e06421050327b3b5a3e414c5adff"
)
})?;
let source = PathBuf::from(source)
.canonicalize()
.map_err(|error| format!("resolving pinned Goose TUI source: {error}"))?;
let text = source
.parent()
.and_then(Path::parent)
.ok_or_else(|| "pinned Goose TUI source must be ui/text/src/tui.tsx".to_string())?;
let ui = text
.parent()
.ok_or_else(|| "pinned Goose TUI source has no ui parent".to_string())?;
let expected_source = ui
.join("text/src/tui.tsx")
.canonicalize()
.map_err(|error| format!("resolving expected pinned Goose TUI source: {error}"))?;
if source != expected_source {
return Err(format!(
"{GOOSE_TUI_SOURCE_ENV} must identify the exact pinned ui/text/src/tui.tsx entrypoint"
));
}
if verify_runtime_closure {
let verified_modules = verify_hashed_file_set(ui, GOOSE_RUNTIME_CLOSURE)?;
if verified_modules < 800 {
return Err(format!(
"pinned Goose runtime manifest is incomplete: only {verified_modules} modules"
));
}
}
for (relative, expected) in FILES {
let path = ui.join(relative);
let bytes = std::fs::read(&path)
.map_err(|error| format!("reading pinned Goose source {}: {error}", path.display()))?;
let actual = format!("{:x}", Sha256::digest(bytes));
if actual != *expected {
return Err(format!(
"pinned Goose source hash mismatch for {}: expected {expected}, found {actual}",
path.display()
));
}
}
let tsx_loader = ui.join("node_modules/tsx/dist/cli.mjs");
let loader = std::fs::read(&tsx_loader).map_err(|error| {
format!(
"reading pinned Goose tsx loader {}: {error}",
tsx_loader.display()
)
})?;
let actual = format!("{:x}", Sha256::digest(loader));
const EXPECTED_TSX_LOADER: &str =
"8729ecfb90d9d568939e4190e6f1d3317c946583b7d37a776e0c23a21c021cf8";
if actual != EXPECTED_TSX_LOADER {
return Err(format!(
"pinned Goose tsx loader hash mismatch for {}: expected {EXPECTED_TSX_LOADER}, found {actual}",
tsx_loader.display()
));
}
Ok(PinnedGooseTui {
runtime_root: ui.to_path_buf(),
source,
tsx_loader,
})
}
fn sanitize_probe_text(input: &str) -> String {
const MAX_PROBE_CHARS: usize = 240;
let mut output = String::new();
let mut output_chars = 0;
let mut pending_space = false;
for character in input.chars() {
if character.is_control() || character.is_whitespace() {
pending_space = !output.is_empty();
continue;
}
if pending_space && output_chars < MAX_PROBE_CHARS {
output.push(' ');
output_chars += 1;
}
pending_space = false;
if output_chars >= MAX_PROBE_CHARS {
break;
}
output.push(character);
output_chars += 1;
}
output
}
struct ProbeRoot(PathBuf);
impl ProbeRoot {
fn create(client: &str) -> std::io::Result<Self> {
let root = std::env::temp_dir().join(format!(
"sc-ui-probe-{client}-{}-{:x}",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_nanos()
));
crate::create_private_frontend_dir(&root)
.map_err(|error| std::io::Error::other(error.to_string()))?;
for child in [
"home",
"tmp",
"config",
"data",
"state",
"cache",
"opencode-config",
"codex",
"goose",
"pi",
] {
crate::create_private_frontend_dir(&root.join(child))
.map_err(|error| std::io::Error::other(error.to_string()))?;
}
Ok(Self(root))
}
fn path(&self) -> &Path {
&self.0
}
}
impl Drop for ProbeRoot {
fn drop(&mut self) {
std::fs::remove_dir_all(&self.0).ok();
}
}
fn isolate_environment(command: &mut tokio::process::Command, root: &Path) {
let path = std::env::var_os("PATH");
#[cfg(windows)]
let windows_environment =
["SystemRoot", "WINDIR", "PATHEXT", "COMSPEC"].map(|name| (name, std::env::var_os(name)));
command.env_clear();
if let Some(path) = path {
command.env("PATH", path);
}
#[cfg(windows)]
for (name, value) in windows_environment {
if let Some(value) = value {
command.env(name, value);
}
}
command
.env("HOME", root.join("home"))
.env("TMPDIR", root.join("tmp"))
.env("TMP", root.join("tmp"))
.env("TEMP", root.join("tmp"))
.env("CODEX_HOME", root.join("codex"))
.env("XDG_CONFIG_HOME", root.join("config"))
.env("XDG_DATA_HOME", root.join("data"))
.env("XDG_STATE_HOME", root.join("state"))
.env("XDG_CACHE_HOME", root.join("cache"))
.env("OPENCODE_CONFIG_DIR", root.join("opencode-config"))
.env("GOOSE_HOME", root.join("goose"))
.env("PI_CODING_AGENT_DIR", root.join("pi"))
.env_remove(CODEX_REMOTE_TOKEN_ENV);
for variable in SECRET_ENVIRONMENT {
command.env_remove(variable);
}
for variable in OPENCODE_DISABLE_ENVIRONMENT {
command.env(variable, "1");
}
}
pub(crate) fn isolate_stock_codex_environment(
command: &mut tokio::process::Command,
client_home: &Path,
) {
command
.env("CODEX_HOME", client_home)
.env_remove(CODEX_REMOTE_TOKEN_ENV);
for variable in SECRET_ENVIRONMENT {
command.env_remove(variable);
}
}
pub(crate) fn isolate_stock_opencode_environment(
command: &mut tokio::process::Command,
client_root: &Path,
) {
const PASSTHROUGH: &[&str] = &[
"PATH",
"TERM",
"COLORTERM",
"LANG",
"LC_ALL",
"LC_CTYPE",
"NO_COLOR",
"CLICOLOR",
"CLICOLOR_FORCE",
];
let passthrough = PASSTHROUGH
.iter()
.map(|name| (*name, std::env::var_os(name)))
.collect::<Vec<_>>();
#[cfg(windows)]
let windows_environment =
["SystemRoot", "WINDIR", "PATHEXT", "COMSPEC"].map(|name| (name, std::env::var_os(name)));
command.env_clear();
for (name, value) in passthrough {
if let Some(value) = value {
command.env(name, value);
}
}
#[cfg(windows)]
for (name, value) in windows_environment {
if let Some(value) = value {
command.env(name, value);
}
}
command
.env("HOME", client_root.join("home"))
.env("TMPDIR", client_root.join("tmp"))
.env("TMP", client_root.join("tmp"))
.env("TEMP", client_root.join("tmp"))
.env("XDG_CONFIG_HOME", client_root.join("config"))
.env("XDG_DATA_HOME", client_root.join("data"))
.env("XDG_STATE_HOME", client_root.join("state"))
.env("XDG_CACHE_HOME", client_root.join("cache"))
.env("OPENCODE_CONFIG_DIR", client_root.join("opencode-config"));
for variable in OPENCODE_DISABLE_ENVIRONMENT {
command.env(variable, "1");
}
}
pub(crate) fn isolate_stock_goose_environment(
command: &mut tokio::process::Command,
client_root: &Path,
) {
const PASSTHROUGH: &[&str] = &[
"PATH",
"TERM",
"COLORTERM",
"LANG",
"LC_ALL",
"LC_CTYPE",
"NO_COLOR",
"CLICOLOR",
"CLICOLOR_FORCE",
];
let passthrough = PASSTHROUGH
.iter()
.map(|name| (*name, std::env::var_os(name)))
.collect::<Vec<_>>();
#[cfg(windows)]
let windows_environment =
["SystemRoot", "WINDIR", "PATHEXT", "COMSPEC"].map(|name| (name, std::env::var_os(name)));
command.env_clear();
for (name, value) in passthrough {
if let Some(value) = value {
command.env(name, value);
}
}
#[cfg(windows)]
for (name, value) in windows_environment {
if let Some(value) = value {
command.env(name, value);
}
}
command
.env("HOME", client_root.join("home"))
.env("TMPDIR", client_root.join("tmp"))
.env("TMP", client_root.join("tmp"))
.env("TEMP", client_root.join("tmp"))
.env("XDG_CONFIG_HOME", client_root.join("config"))
.env("XDG_DATA_HOME", client_root.join("data"))
.env("XDG_STATE_HOME", client_root.join("state"))
.env("XDG_CACHE_HOME", client_root.join("cache"))
.env("GOOSE_HOME", client_root.join("goose"))
.env("GOOSE_PATH_ROOT", client_root.join("goose"))
.env("GOOSE_DISABLE_KEYRING", "true")
.env_remove("GOOSE_BINARY")
.env_remove(GOOSE_BRIDGE_ADDRESS_ENV)
.env_remove(GOOSE_BRIDGE_NONCE_ENV);
}
fn isolate_pi_frontend_environment(command: &mut tokio::process::Command, client_root: &Path) {
const PASSTHROUGH: &[&str] = &[
"PATH",
"TERM",
"COLORTERM",
"LANG",
"LC_ALL",
"LC_CTYPE",
"NO_COLOR",
"CLICOLOR",
"CLICOLOR_FORCE",
];
let passthrough = PASSTHROUGH
.iter()
.map(|name| (*name, std::env::var_os(name)))
.collect::<Vec<_>>();
#[cfg(windows)]
let windows_environment =
["SystemRoot", "WINDIR", "PATHEXT", "COMSPEC"].map(|name| (name, std::env::var_os(name)));
command.env_clear();
for (name, value) in passthrough {
if let Some(value) = value {
command.env(name, value);
}
}
#[cfg(windows)]
for (name, value) in windows_environment {
if let Some(value) = value {
command.env(name, value);
}
}
command
.env("HOME", client_root.join("home"))
.env("TMPDIR", client_root.join("tmp"))
.env("TMP", client_root.join("tmp"))
.env("TEMP", client_root.join("tmp"))
.env("XDG_CONFIG_HOME", client_root.join("config"))
.env("XDG_DATA_HOME", client_root.join("data"))
.env("XDG_STATE_HOME", client_root.join("state"))
.env("XDG_CACHE_HOME", client_root.join("cache"));
}
const EMPTY_ARGS: &[&str] = &[];
const VERSION_ARGS: &[&str] = &["--version"];
const EMBEDDED_TRANSPORTS: &[ClientTransport] = &[ClientTransport::EmbeddedSdk];
const CODEX_TRANSPORTS: &[ClientTransport] = &[ClientTransport::CodexAppServerWebSocket];
const OPENCODE_TRANSPORTS: &[ClientTransport] = &[ClientTransport::OpenCodeHttp];
const GOOSE_TRANSPORTS: &[ClientTransport] = &[ClientTransport::AcpStdio];
const PI_TRANSPORTS: &[ClientTransport] = &[ClientTransport::FrontendHttpV2];
#[cfg(not(windows))]
const PI_FRONTEND_BINARY: &str = "supercode-pi";
#[cfg(windows)]
const PI_FRONTEND_BINARY: &str = "supercode-pi.cmd";
pub(crate) const CLIENTS: [FrontendClientSpec; 5] = [
FrontendClientSpec {
id: FrontendClientId::Embedded,
binary: None,
version_args: EMPTY_ARGS,
supported_version: None,
transports: EMBEDDED_TRANSPORTS,
compatible: true,
install_guidance: "included with supercode",
features: &["history", "events", "input", "requests", "control"],
},
FrontendClientSpec {
id: FrontendClientId::Codex,
binary: Some("codex"),
version_args: VERSION_ARGS,
supported_version: Some(supercode_codex_frontend::CODEX_CLI_VERSION),
transports: CODEX_TRANSPORTS,
compatible: true,
install_guidance: "install @openai/codex@0.144.4 and ensure `codex` is on PATH",
features: &["history", "events", "input", "requests", "control"],
},
FrontendClientSpec {
id: FrontendClientId::Opencode,
binary: Some("opencode"),
version_args: VERSION_ARGS,
supported_version: Some(supercode_opencode_frontend::OPENCODE_CLI_VERSION),
transports: OPENCODE_TRANSPORTS,
compatible: true,
install_guidance: "install OpenCode 1.2.15 and ensure `opencode` is on PATH",
features: &["history", "events", "input", "requests", "control"],
},
FrontendClientSpec {
id: FrontendClientId::Goose,
binary: Some("node"),
version_args: VERSION_ARGS,
supported_version: Some(GOOSE_NODE_VERSION),
transports: GOOSE_TRANSPORTS,
compatible: true,
install_guidance: "install the pinned Goose source workspace with its locked dependencies and Node 23.9.0, then set SUPERCODE_GOOSE_TUI_SOURCE",
features: &["events", "input"],
},
FrontendClientSpec {
id: FrontendClientId::Pi,
binary: Some(PI_FRONTEND_BINARY),
version_args: VERSION_ARGS,
supported_version: Some("0.1.0"),
transports: PI_TRANSPORTS,
compatible: true,
install_guidance: "install @volter-ai-dev/supercode-frontend-pi@0.1.0 and ensure `supercode-pi` is on PATH",
features: &["history", "events", "input", "requests", "control"],
},
];
#[cfg(test)]
mod tests {
use super::*;
#[cfg(supercode_workspace_protocol_contracts)]
#[test]
fn packaged_goose_runtime_contract_matches_workspace_source() {
assert_eq!(
GOOSE_RUNTIME_CLOSURE.as_bytes(),
include_bytes!(
"../../../scripts/client-protocol-corpus/contracts/goose-runtime-closure-acd3c135.sha256"
)
);
}
#[test]
fn registry_has_exactly_one_declarative_row_per_stable_id() {
let ids = CLIENTS
.iter()
.map(|client| client.id.as_str())
.collect::<Vec<_>>();
assert_eq!(ids, ["embedded", "codex", "opencode", "goose", "pi"]);
for client in CLIENTS {
assert!(!client.transports.is_empty());
assert!(!client.install_guidance.is_empty());
assert!(!client.features.is_empty());
if client.binary.is_some() {
assert!(!client.version_args.is_empty());
}
}
}
#[test]
fn only_clients_with_implemented_adapters_claim_compatibility() {
assert!(FrontendClientId::Embedded.spec().compatible);
assert!(FrontendClientId::Codex.spec().compatible);
assert!(FrontendClientId::Opencode.spec().compatible);
assert!(FrontendClientId::Goose.spec().compatible);
assert!(FrontendClientId::Pi.spec().compatible);
}
#[test]
fn registry_contains_no_shell_fragments_or_download_actions() {
for client in CLIENTS {
for value in client
.binary
.into_iter()
.chain(client.version_args.iter().copied())
{
assert!(!value.contains([';', '|', '&', '`', '$']));
}
assert!(!client.install_guidance.contains("curl |"));
assert!(!client.install_guidance.contains("wget |"));
}
}
#[tokio::test]
async fn embedded_probe_is_available_without_spawning_or_downloading() {
let probe = FrontendClientId::Embedded.spec().probe().await;
assert!(probe.installed);
assert!(probe.compatible);
assert_eq!(probe.id, FrontendClientId::Embedded);
}
#[tokio::test]
#[ignore = "requires unmodified OpenCode 1.2.15 on PATH"]
async fn pinned_stock_opencode_probe_succeeds_inside_the_disposable_environment() {
let probe = FrontendClientId::Opencode.spec().probe().await;
assert!(probe.installed, "{}", probe.detail);
assert!(probe.compatible, "{}", probe.detail);
assert_eq!(
probe.version.as_deref(),
Some(supercode_opencode_frontend::OPENCODE_CLI_VERSION)
);
}
#[test]
fn probe_output_is_one_bounded_control_free_line() {
let secret = "DO_NOT_LOG";
let probe = FrontendClientProbe {
id: FrontendClientId::Codex,
installed: true,
compatible: false,
version: Some(format!("0.144.4\n\u{1b}[31m{secret}\u{7}")),
detail: "first\r\nsecond\t".repeat(100),
}
.sanitized();
let version = probe.version.unwrap();
assert_eq!(version, format!("0.144.4 [31m{secret}"));
assert!(version.chars().all(|character| !character.is_control()));
assert!(probe.detail.chars().count() <= 240);
assert!(probe
.detail
.chars()
.all(|character| !character.is_control()));
assert!(!probe.detail.contains('\n'));
}
#[tokio::test]
async fn probe_environment_does_not_inherit_arbitrary_secrets() {
let mut command = tokio::process::Command::new("probe-client");
command.env("UNRELATED_SECRET", "must-not-survive");
isolate_environment(&mut command, Path::new("/private-probe"));
let environment = command
.as_std()
.get_envs()
.collect::<std::collections::BTreeMap<_, _>>();
assert_eq!(
environment.get(std::ffi::OsStr::new("UNRELATED_SECRET")),
None
);
assert_eq!(
environment
.get(std::ffi::OsStr::new("HOME"))
.and_then(|value| *value),
Some(std::ffi::OsStr::new("/private-probe/home"))
);
}
#[test]
fn codex_launch_is_direct_argv_and_keeps_credentials_out_of_arguments() {
let command = FrontendClientId::Codex
.spec()
.codex_launch_command(
Path::new("/workspace"),
Path::new("/private"),
"ws://127.0.0.1:1",
)
.unwrap();
let command = command.as_std();
let args = command
.get_args()
.map(|value| value.to_string_lossy().into_owned())
.collect::<Vec<_>>();
assert_eq!(
args,
[
"--remote",
"ws://127.0.0.1:1",
"--remote-auth-token-env",
CODEX_REMOTE_TOKEN_ENV,
"--disable",
"plugins",
]
);
assert!(args.iter().all(|arg| !arg.contains("Bearer")));
}
#[test]
fn goose_launch_is_direct_isolated_and_keeps_nonce_out_of_arguments() {
let command = FrontendClientId::Goose
.spec()
.goose_launch_command(
Path::new("/workspace"),
Path::new("/private"),
Path::new("/bin/supercode"),
&PinnedGooseTui {
runtime_root: PathBuf::from("/goose/ui"),
source: PathBuf::from("/goose/ui/text/src/tui.tsx"),
tsx_loader: PathBuf::from("/goose/ui/node_modules/tsx/dist/cli.mjs"),
},
"127.0.0.1:43123",
"bridge-secret",
)
.unwrap();
let command = command.as_std();
assert_eq!(command.get_program(), "node");
assert_eq!(
command.get_args().collect::<Vec<_>>(),
[
std::ffi::OsStr::new("/goose/ui/node_modules/tsx/dist/cli.mjs"),
std::ffi::OsStr::new("--tsconfig"),
std::ffi::OsStr::new("/goose/ui/text/tsconfig.json"),
std::ffi::OsStr::new("/goose/ui/text/src/tui.tsx")
]
);
let environment = command
.get_envs()
.collect::<std::collections::BTreeMap<_, _>>();
assert_eq!(
environment
.get(std::ffi::OsStr::new("GOOSE_BINARY"))
.and_then(|value| *value),
Some(std::ffi::OsStr::new("/bin/supercode"))
);
assert_eq!(
environment
.get(std::ffi::OsStr::new(GOOSE_BRIDGE_ADDRESS_ENV))
.and_then(|value| *value),
Some(std::ffi::OsStr::new("127.0.0.1:43123"))
);
assert_eq!(
environment
.get(std::ffi::OsStr::new(GOOSE_BRIDGE_NONCE_ENV))
.and_then(|value| *value),
Some(std::ffi::OsStr::new("bridge-secret"))
);
assert_eq!(
environment.get(std::ffi::OsStr::new("OPENROUTER_API_KEY")),
None
);
}
#[test]
fn pi_launch_is_argument_free_isolated_and_passes_only_a_credential_path() {
let command = FrontendClientId::Pi
.spec()
.pi_launch_command(PiLaunch {
cwd: Path::new("/workspace"),
client_root: Path::new("/private"),
base_url: "http://127.0.0.1:43123",
client_id: "ui-pi-test",
credential_path: Path::new("/private/credential"),
permissions: "observe,interact,approve",
take_control: true,
})
.unwrap();
let command = command.as_std();
assert_eq!(command.get_program(), PI_FRONTEND_BINARY);
assert_eq!(command.get_args().count(), 0);
let environment = command
.get_envs()
.collect::<std::collections::BTreeMap<_, _>>();
assert_eq!(
environment.get(std::ffi::OsStr::new("PI_DEBUG_REDRAW")),
None
);
assert_eq!(
environment.get(std::ffi::OsStr::new("OPENROUTER_API_KEY")),
None
);
assert_eq!(
environment
.get(std::ffi::OsStr::new(PI_FRONTEND_CREDENTIAL_FILE_ENV))
.and_then(|value| *value),
Some(std::ffi::OsStr::new("/private/credential"))
);
assert_eq!(
environment
.get(std::ffi::OsStr::new(PI_FRONTEND_TAKE_CONTROL_ENV))
.and_then(|value| *value),
Some(std::ffi::OsStr::new("1"))
);
let rendered = command
.get_envs()
.filter_map(|(name, value)| value.map(|value| (name, value)))
.flat_map(|(name, value)| [name.to_string_lossy(), value.to_string_lossy()])
.collect::<Vec<_>>()
.join(" ");
assert!(!rendered.contains("must-not-survive"));
assert!(!rendered.contains("Bearer"));
let mut hostile = tokio::process::Command::new("supercode-pi");
hostile
.env("PI_DEBUG_REDRAW", "1")
.env("OPENROUTER_API_KEY", "must-not-survive");
isolate_pi_frontend_environment(&mut hostile, Path::new("/private"));
let environment = hostile
.as_std()
.get_envs()
.collect::<std::collections::BTreeMap<_, _>>();
assert_eq!(
environment.get(std::ffi::OsStr::new("PI_DEBUG_REDRAW")),
None
);
assert_eq!(
environment.get(std::ffi::OsStr::new("OPENROUTER_API_KEY")),
None
);
}
#[cfg(windows)]
#[tokio::test]
#[ignore = "requires the packed @volter-ai-dev/supercode-frontend-pi package on PATH"]
async fn windows_packaged_pi_frontend_is_probed_and_spawned_through_its_cmd_entrypoint() {
let spec = FrontendClientId::Pi.spec();
let probe = spec.probe().await;
assert!(probe.installed, "{}", probe.detail);
assert!(probe.compatible, "{}", probe.detail);
assert_eq!(probe.version.as_deref(), Some("supercode-pi 0.1.0"));
let root = std::env::temp_dir().join(format!(
"supercode-packaged-pi-windows-{}",
std::process::id()
));
std::fs::remove_dir_all(&root).ok();
std::fs::create_dir_all(&root).unwrap();
let credential = root.join("intentionally-absent-credential");
let mut command = spec
.pi_launch_command(PiLaunch {
cwd: &root,
client_root: &root,
base_url: "http://127.0.0.1:1",
client_id: "ui-pi-windows-package-proof",
credential_path: &credential,
permissions: "observe",
take_control: false,
})
.unwrap();
assert_eq!(command.as_std().get_program(), "supercode-pi.cmd");
assert_eq!(command.as_std().get_args().count(), 0);
let output = tokio::time::timeout(Duration::from_secs(10), command.output())
.await
.expect("packaged Pi frontend launch timed out")
.expect("Rust could not spawn the packaged Pi .cmd entrypoint");
assert!(!output.status.success());
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(stderr.contains("supercode-pi:"), "{stderr}");
assert!(
stderr.contains("intentionally-absent-credential"),
"{stderr}"
);
std::fs::remove_dir_all(root).ok();
}
#[test]
fn goose_runtime_closure_rejects_a_modified_non_entrypoint_module() {
let root = std::env::temp_dir().join(format!(
"supercode-goose-closure-test-{}",
std::process::id()
));
std::fs::remove_dir_all(&root).ok();
std::fs::create_dir_all(root.join("text/src")).unwrap();
let module = root.join("text/src/slashCommands.tsx");
std::fs::write(&module, b"reviewed module").unwrap();
let expected = format!("{:x}", Sha256::digest(b"reviewed module"));
let manifest = format!("{expected} text/src/slashCommands.tsx\n");
assert_eq!(verify_hashed_file_set(&root, &manifest).unwrap(), 1);
std::fs::write(&module, b"substituted module").unwrap();
let error = verify_hashed_file_set(&root, &manifest).unwrap_err();
assert!(error.contains("runtime module hash mismatch"), "{error}");
std::fs::remove_dir_all(root).ok();
}
#[test]
fn goose_runtime_materialization_pins_config_and_excludes_shadow_packages() {
let base = std::env::temp_dir().join(format!(
"supercode-goose-materialization-test-{}",
std::process::id()
));
std::fs::remove_dir_all(&base).ok();
let source = base.join("source");
let destination = base.join("sealed");
std::fs::create_dir_all(source.join("text/src/node_modules/injected")).unwrap();
std::fs::write(source.join("text/src/tui.tsx"), b"reviewed entrypoint").unwrap();
let tsconfig = b"{\"compilerOptions\":{}}";
std::fs::write(source.join("text/tsconfig.json"), tsconfig).unwrap();
std::fs::write(
source.join("text/src/node_modules/injected/index.js"),
b"bridge nonce theft",
)
.unwrap();
let esbuild = source.join("node_modules/@esbuild/linux-x64/bin/esbuild");
std::fs::create_dir_all(esbuild.parent().unwrap()).unwrap();
std::fs::write(&esbuild, b"reviewed executable").unwrap();
let expected_entry = format!("{:x}", Sha256::digest(b"reviewed entrypoint"));
let expected_config = format!("{:x}", Sha256::digest(tsconfig));
let expected_esbuild = format!("{:x}", Sha256::digest(b"reviewed executable"));
let manifest = format!(
"{expected_entry} text/src/tui.tsx\n{expected_config} text/tsconfig.json\n{expected_esbuild} node_modules/@esbuild/linux-x64/bin/esbuild\n"
);
assert_eq!(
materialize_hashed_file_set(&source, &destination, &manifest).unwrap(),
3
);
assert_eq!(
std::fs::read(destination.join("text/src/tui.tsx")).unwrap(),
b"reviewed entrypoint"
);
assert_eq!(
std::fs::read(destination.join("text/tsconfig.json")).unwrap(),
tsconfig
);
assert!(!destination.join("text/src/node_modules").exists());
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt as _;
assert_eq!(
std::fs::metadata(destination.join("node_modules/@esbuild/linux-x64/bin/esbuild"))
.unwrap()
.permissions()
.mode()
& 0o777,
0o500
);
}
let rejected = base.join("rejected");
std::fs::write(
source.join("text/tsconfig.json"),
b"{\"compilerOptions\":{\"paths\":{\"*\":[\"src/node_modules/*\"]}}}",
)
.unwrap();
let error = materialize_hashed_file_set(&source, &rejected, &manifest).unwrap_err();
assert!(error.contains("runtime module hash mismatch"), "{error}");
std::fs::remove_dir_all(base).ok();
}
#[test]
fn opencode_launch_is_direct_argv_and_keeps_credentials_out_of_arguments() {
let command = FrontendClientId::Opencode
.spec()
.opencode_launch_command(
Path::new("/workspace"),
Path::new("/private"),
"http://127.0.0.1:1",
"ses_adapter",
)
.unwrap();
let command = command.as_std();
let args = command
.get_args()
.map(|value| value.to_string_lossy().into_owned())
.collect::<Vec<_>>();
assert_eq!(
args,
[
"attach",
"http://127.0.0.1:1",
"--dir",
"/workspace",
"--session",
"ses_adapter",
]
);
assert!(args.iter().all(|arg| !arg.contains("password")));
assert!(args.iter().all(|arg| !arg.contains("Bearer")));
}
#[test]
fn opencode_launch_clears_parent_state_and_uses_only_private_roots() {
let mut command = tokio::process::Command::new("opencode");
command
.env("UNRELATED_SECRET", "must-not-survive")
.env("OPENCODE_SERVER_PASSWORD", "must-not-survive")
.env("ANTHROPIC_API_KEY", "must-not-survive");
isolate_stock_opencode_environment(&mut command, Path::new("/private"));
let environment = command
.as_std()
.get_envs()
.collect::<std::collections::BTreeMap<_, _>>();
for variable in [
"UNRELATED_SECRET",
"OPENCODE_SERVER_PASSWORD",
"ANTHROPIC_API_KEY",
] {
assert_eq!(environment.get(std::ffi::OsStr::new(variable)), None);
}
for (variable, expected) in [
("HOME", "/private/home"),
("TMPDIR", "/private/tmp"),
("XDG_CONFIG_HOME", "/private/config"),
("XDG_DATA_HOME", "/private/data"),
("XDG_STATE_HOME", "/private/state"),
("XDG_CACHE_HOME", "/private/cache"),
("OPENCODE_CONFIG_DIR", "/private/opencode-config"),
] {
assert_eq!(
environment
.get(std::ffi::OsStr::new(variable))
.and_then(|value| *value),
Some(std::ffi::OsStr::new(expected)),
"{variable}"
);
}
for variable in OPENCODE_DISABLE_ENVIRONMENT {
assert_eq!(
environment
.get(std::ffi::OsStr::new(variable))
.and_then(|value| *value),
Some(std::ffi::OsStr::new("1")),
"{variable}"
);
}
}
}