Add cloud tasks (#3197)

Adds a TUI for managing, applying, and creating cloud tasks

(cherry picked from commit 5a8f545d05)
This commit is contained in:
easong-openai
2025-10-01 04:20:19 +10:00
committed by James Peter
parent b0e445a4ef
commit 5421288ed1
6 changed files with 24 additions and 14 deletions
+1
View File
@@ -65,6 +65,7 @@ codex-ollama = { path = "ollama" }
codex-process-hardening = { path = "process-hardening" }
codex-protocol = { path = "protocol" }
codex-protocol-ts = { path = "protocol-ts" }
codex-responses-api-proxy = { path = "responses-api-proxy" }
codex-rmcp-client = { path = "rmcp-client" }
codex-otel = { path = "otel" }
codex-tui = { path = "tui" }
+1
View File
@@ -29,6 +29,7 @@ codex-mcp-server = { workspace = true }
codex-process-hardening = { workspace = true }
codex-protocol = { workspace = true }
codex-protocol-ts = { workspace = true }
codex-responses-api-proxy = { workspace = true }
codex-tui = { workspace = true }
codex-version = { path = "../codex-version" }
codex-cloud-tasks = { workspace = true }
+10
View File
@@ -22,6 +22,8 @@ use codex_core::find_conversation_path_by_id_str;
use codex_core::RolloutRecorder;
use codex_cloud_tasks::Cli as CloudTasksCli;
use codex_exec::Cli as ExecCli;
use codex_responses_api_proxy::Args as ResponsesApiProxyArgs;
use codex_tui::AppExitInfo;
use codex_tui::Cli as TuiCli;
use codex_tui::ExitSummary;
use codex_tui::RESUME_COMMAND_NAME;
@@ -133,6 +135,10 @@ enum Subcommand {
#[clap(name = "cloud", alias = "cloud-tasks")]
Cloud(CloudTasksCli),
/// Internal: run the responses API proxy.
#[clap(hide = true)]
ResponsesApiProxy(ResponsesApiProxyArgs),
/// Diagnose PATH, binary collisions, and versions.
Doctor,
@@ -423,6 +429,10 @@ async fn cli_main(codex_linux_sandbox_exe: Option<PathBuf>) -> anyhow::Result<()
);
run_apply_command(apply_cli, None).await?;
}
Some(Subcommand::ResponsesApiProxy(args)) => {
tokio::task::spawn_blocking(move || codex_responses_api_proxy::run_main(args))
.await??;
}
Some(Subcommand::GenerateTs(gen_cli)) => {
codex_protocol_ts::generate_ts(&gen_cli.out_dir, gen_cli.prettier.as_deref())?;
}
+1 -2
View File
@@ -194,8 +194,7 @@ impl McpConnectionManager {
// Validate server name before spawning
if !is_valid_mcp_server_name(&server_name) {
let error = anyhow::anyhow!(
"invalid server name '{}': must match pattern ^[a-zA-Z0-9_-]+$",
server_name
"invalid server name '{server_name}': must match pattern ^[a-zA-Z0-9_-]+$"
);
errors.insert(server_name, error);
continue;
+10 -10
View File
@@ -59,16 +59,16 @@ pub fn generate_ts(out_dir: &Path, prettier: Option<&Path>) -> Result<()> {
}
// Format with Prettier by passing individual files (no shell globbing)
if let Some(prettier_bin) = prettier {
if !ts_files.is_empty() {
let status = Command::new(prettier_bin)
.arg("--write")
.args(ts_files.iter().map(|p| p.as_os_str()))
.status()
.with_context(|| format!("Failed to invoke Prettier at {}", prettier_bin.display()))?;
if !status.success() {
return Err(anyhow!("Prettier failed with status {}", status));
}
if let Some(prettier_bin) = prettier
&& !ts_files.is_empty()
{
let status = Command::new(prettier_bin)
.arg("--write")
.args(ts_files.iter().map(|p| p.as_os_str()))
.status()
.with_context(|| format!("Failed to invoke Prettier at {}", prettier_bin.display()))?;
if !status.success() {
return Err(anyhow!("Prettier failed with status {status}"));
}
}
+1 -2
View File
@@ -99,8 +99,8 @@ mod chatwidget_stream_tests;
mod updates;
pub use cli::Cli;
pub use public_widgets::composer_input::ComposerInput;
pub use self::markdown_render::render_markdown_text;
pub use public_widgets::composer_input::{ComposerAction, ComposerInput};
fn theme_configured_in_config_file(codex_home: &std::path::Path) -> bool {
let config_path = codex_home.join("config.toml");
@@ -116,7 +116,6 @@ fn theme_configured_in_config_file(codex_home: &std::path::Path) -> bool {
let inline_pattern = Regex::new(r"(?m)^\s*tui\.theme\s*=").expect("valid regex");
inline_pattern.is_match(&contents)
}
// (tests access modules directly within the crate)
#[derive(Debug)]