mirror of
https://github.com/hanzoai/dev.git
synced 2026-10-25 03:32:32 +00:00
@@ -1,3 +1,5 @@
|
||||
use anyhow::anyhow;
|
||||
use anyhow::Context;
|
||||
use clap::CommandFactory;
|
||||
use clap::Parser;
|
||||
use clap_complete::Shell;
|
||||
@@ -15,9 +17,14 @@ use codex_cli::proto;
|
||||
mod llm;
|
||||
use llm::{LlmCli, run_llm};
|
||||
use codex_common::CliConfigOverrides;
|
||||
use codex_core::find_conversation_path_by_id_str;
|
||||
use codex_core::RolloutRecorder;
|
||||
use codex_exec::Cli as ExecCli;
|
||||
use codex_tui::Cli as TuiCli;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use tokio::runtime::Builder as TokioRuntimeBuilder;
|
||||
|
||||
mod mcp_cmd;
|
||||
|
||||
@@ -211,6 +218,8 @@ async fn cli_main(codex_linux_sandbox_exe: Option<PathBuf>) -> anyhow::Result<()
|
||||
subcommand,
|
||||
} = MultitoolCli::parse();
|
||||
|
||||
interactive.finalize_defaults();
|
||||
|
||||
match subcommand {
|
||||
None => {
|
||||
prepend_config_flags(
|
||||
@@ -237,8 +246,9 @@ async fn cli_main(codex_linux_sandbox_exe: Option<PathBuf>) -> anyhow::Result<()
|
||||
Some(Subcommand::Resume(ResumeCommand {
|
||||
session_id,
|
||||
last,
|
||||
config_overrides,
|
||||
mut config_overrides,
|
||||
})) => {
|
||||
config_overrides.finalize_defaults();
|
||||
interactive = finalize_resume_interactive(
|
||||
interactive,
|
||||
root_config_overrides.clone(),
|
||||
@@ -353,16 +363,24 @@ fn prepend_config_flags(
|
||||
fn finalize_resume_interactive(
|
||||
mut interactive: TuiCli,
|
||||
root_config_overrides: CliConfigOverrides,
|
||||
_session_id: Option<String>,
|
||||
_last: bool,
|
||||
resume_cli: TuiCli,
|
||||
session_id: Option<String>,
|
||||
last: bool,
|
||||
mut resume_cli: TuiCli,
|
||||
) -> TuiCli {
|
||||
// Our fork does not expose explicit resume fields on the TUI CLI.
|
||||
// We simply merge resume-scoped flags and root overrides and run the TUI.
|
||||
|
||||
interactive.finalize_defaults();
|
||||
resume_cli.finalize_defaults();
|
||||
|
||||
// Merge resume-scoped flags and overrides with highest precedence.
|
||||
merge_resume_cli_flags(&mut interactive, resume_cli);
|
||||
|
||||
if let Err(err) = apply_resume_directives(&mut interactive, session_id, last) {
|
||||
eprintln!("{}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
// Propagate any root-level config overrides (e.g. `-c key=value`).
|
||||
prepend_config_flags(&mut interactive.config_overrides, root_config_overrides);
|
||||
|
||||
@@ -404,12 +422,87 @@ fn merge_resume_cli_flags(interactive: &mut TuiCli, resume_cli: TuiCli) {
|
||||
interactive.prompt = Some(prompt);
|
||||
}
|
||||
|
||||
if resume_cli.enable_web_search || resume_cli.disable_web_search {
|
||||
interactive.enable_web_search = resume_cli.enable_web_search;
|
||||
interactive.disable_web_search = resume_cli.disable_web_search;
|
||||
interactive.web_search = resume_cli.web_search;
|
||||
}
|
||||
|
||||
interactive
|
||||
.config_overrides
|
||||
.raw_overrides
|
||||
.extend(resume_cli.config_overrides.raw_overrides);
|
||||
}
|
||||
|
||||
fn apply_resume_directives(
|
||||
interactive: &mut TuiCli,
|
||||
session_id: Option<String>,
|
||||
last: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
interactive.resume_picker = false;
|
||||
interactive.resume_last = false;
|
||||
interactive.resume_session_id = None;
|
||||
|
||||
match (session_id, last) {
|
||||
(Some(id), _) => {
|
||||
let path = resolve_resume_path(Some(id.as_str()), false)?
|
||||
.ok_or_else(|| anyhow!("No recorded session found with id {id}"))?;
|
||||
interactive.resume_session_id = Some(id);
|
||||
push_experimental_resume_override(interactive, &path);
|
||||
}
|
||||
(None, true) => {
|
||||
let path = resolve_resume_path(None, true)?
|
||||
.ok_or_else(|| anyhow!("No recent sessions found to resume. Start a session with `code` first."))?;
|
||||
interactive.resume_last = true;
|
||||
push_experimental_resume_override(interactive, &path);
|
||||
}
|
||||
(None, false) => {
|
||||
interactive.resume_picker = true;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn resolve_resume_path(session_id: Option<&str>, last: bool) -> anyhow::Result<Option<PathBuf>> {
|
||||
if session_id.is_none() && !last {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let codex_home = codex_core::config::find_codex_home()
|
||||
.context("failed to locate Codex home directory")?;
|
||||
|
||||
let runtime = TokioRuntimeBuilder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.context("failed to create async runtime for resume lookup")?;
|
||||
|
||||
runtime.block_on(async {
|
||||
if let Some(id) = session_id {
|
||||
let maybe = find_conversation_path_by_id_str(&codex_home, id)
|
||||
.await
|
||||
.context("failed to look up session by id")?;
|
||||
Ok(maybe)
|
||||
} else if last {
|
||||
let page = RolloutRecorder::list_conversations(&codex_home, 1, None)
|
||||
.await
|
||||
.context("failed to list recorded sessions")?;
|
||||
Ok(page.items.first().map(|it| it.path.clone()))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn push_experimental_resume_override(interactive: &mut TuiCli, path: &Path) {
|
||||
let raw = path.to_string_lossy();
|
||||
let escaped = raw.replace('\\', "\\\\").replace('"', "\\\"");
|
||||
interactive
|
||||
.config_overrides
|
||||
.raw_overrides
|
||||
.push(format!("experimental_resume=\"{escaped}\""));
|
||||
}
|
||||
|
||||
fn print_completion(cmd: CompletionCommand) {
|
||||
let mut app = MultitoolCli::command();
|
||||
let name = "code";
|
||||
|
||||
@@ -152,6 +152,7 @@ pub(crate) struct ChatWidgetArgs {
|
||||
terminal_info: TerminalInfo,
|
||||
show_order_overlay: bool,
|
||||
enable_perf: bool,
|
||||
resume_picker: bool,
|
||||
}
|
||||
|
||||
impl App<'_> {
|
||||
@@ -166,6 +167,7 @@ impl App<'_> {
|
||||
show_order_overlay: bool,
|
||||
terminal_info: TerminalInfo,
|
||||
enable_perf: bool,
|
||||
resume_picker: bool,
|
||||
startup_footer_notice: Option<String>,
|
||||
) -> Self {
|
||||
let conversation_manager = Arc::new(ConversationManager::new(AuthManager::shared(
|
||||
@@ -273,6 +275,7 @@ impl App<'_> {
|
||||
terminal_info: terminal_info.clone(),
|
||||
show_order_overlay,
|
||||
enable_perf,
|
||||
resume_picker,
|
||||
};
|
||||
AppState::Onboarding {
|
||||
screen: OnboardingScreen::new(OnboardingScreenArgs {
|
||||
@@ -296,6 +299,9 @@ impl App<'_> {
|
||||
show_order_overlay,
|
||||
);
|
||||
chat_widget.enable_perf(enable_perf);
|
||||
if resume_picker {
|
||||
chat_widget.show_resume_picker();
|
||||
}
|
||||
// Check for initial animations after widget is created
|
||||
chat_widget.check_for_initial_animations();
|
||||
if let Some(notice) = startup_footer_notice {
|
||||
@@ -1668,6 +1674,7 @@ impl App<'_> {
|
||||
terminal_info,
|
||||
show_order_overlay,
|
||||
enable_perf,
|
||||
resume_picker,
|
||||
}) => {
|
||||
let mut w = ChatWidget::new(
|
||||
config,
|
||||
@@ -1679,6 +1686,9 @@ impl App<'_> {
|
||||
show_order_overlay,
|
||||
);
|
||||
w.enable_perf(enable_perf);
|
||||
if resume_picker {
|
||||
w.show_resume_picker();
|
||||
}
|
||||
self.app_state = AppState::Chat { widget: Box::new(w) };
|
||||
self.terminal_runs.clear();
|
||||
}
|
||||
|
||||
+37
-2
@@ -1,3 +1,4 @@
|
||||
use clap::ArgAction;
|
||||
use clap::Parser;
|
||||
use codex_common::ApprovalModeCliArg;
|
||||
use codex_common::CliConfigOverrides;
|
||||
@@ -60,8 +61,18 @@ pub struct Cli {
|
||||
#[clap(long = "cd", short = 'C', value_name = "DIR")]
|
||||
pub cwd: Option<PathBuf>,
|
||||
|
||||
// Web search is now enabled by default via an internal override.
|
||||
// Intentionally not exposed as a command-line option.
|
||||
/// Enable web search support. Enabled by default; use --no-search to disable.
|
||||
#[arg(long = "search", action = ArgAction::SetTrue)]
|
||||
pub enable_web_search: bool,
|
||||
|
||||
/// Disable web search support explicitly.
|
||||
#[arg(long = "no-search", action = ArgAction::SetTrue, hide = true)]
|
||||
pub disable_web_search: bool,
|
||||
|
||||
/// Effective web search toggle after applying flags.
|
||||
#[clap(skip)]
|
||||
pub web_search: bool,
|
||||
|
||||
/// Enable debug logging of all LLM requests and responses to files.
|
||||
#[clap(long = "debug", short = 'd', default_value_t = false)]
|
||||
pub debug: bool,
|
||||
@@ -79,4 +90,28 @@ pub struct Cli {
|
||||
|
||||
#[clap(skip)]
|
||||
pub config_overrides: CliConfigOverrides,
|
||||
|
||||
/// Start in resume picker mode when true (used by `code resume`).
|
||||
#[clap(skip)]
|
||||
pub resume_picker: bool,
|
||||
|
||||
/// Resume the most recent session automatically when true.
|
||||
#[clap(skip)]
|
||||
pub resume_last: bool,
|
||||
|
||||
/// Resume a specific session id when provided.
|
||||
#[clap(skip)]
|
||||
pub resume_session_id: Option<String>,
|
||||
}
|
||||
|
||||
impl Cli {
|
||||
pub fn finalize_defaults(&mut self) {
|
||||
self.web_search = if self.disable_web_search {
|
||||
false
|
||||
} else if self.enable_web_search {
|
||||
true
|
||||
} else {
|
||||
true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,9 +97,11 @@ pub use cli::Cli;
|
||||
// (tests access modules directly within the crate)
|
||||
|
||||
pub async fn run_main(
|
||||
cli: Cli,
|
||||
mut cli: Cli,
|
||||
codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
) -> std::io::Result<codex_core::protocol::TokenUsage> {
|
||||
cli.finalize_defaults();
|
||||
|
||||
let (sandbox_mode, approval_policy) = if cli.full_auto {
|
||||
(
|
||||
Some(SandboxMode::WorkspaceWrite),
|
||||
@@ -153,8 +155,7 @@ pub async fn run_main(
|
||||
disable_response_storage: cli.oss.then_some(true),
|
||||
show_raw_agent_reasoning: cli.oss.then_some(true),
|
||||
debug: Some(cli.debug),
|
||||
// Enable web search by default (no CLI flag).
|
||||
tools_web_search_request: Some(true),
|
||||
tools_web_search_request: Some(cli.web_search),
|
||||
};
|
||||
|
||||
// Parse `-c` overrides from the CLI.
|
||||
@@ -388,6 +389,9 @@ fn run_ratatui_app(
|
||||
debug,
|
||||
order,
|
||||
timing,
|
||||
resume_picker,
|
||||
resume_last: _,
|
||||
resume_session_id: _,
|
||||
..
|
||||
} = cli;
|
||||
let mut app = App::new(
|
||||
@@ -399,6 +403,7 @@ fn run_ratatui_app(
|
||||
order,
|
||||
terminal_info,
|
||||
timing,
|
||||
resume_picker,
|
||||
startup_footer_notice,
|
||||
);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ fn main() -> anyhow::Result<()> {
|
||||
arg0_dispatch_or_else(|codex_linux_sandbox_exe| async move {
|
||||
let top_cli = TopCli::parse();
|
||||
let mut inner = top_cli.inner;
|
||||
inner.finalize_defaults();
|
||||
inner
|
||||
.config_overrides
|
||||
.raw_overrides
|
||||
|
||||
Reference in New Issue
Block a user