From b50f9ddce307efb955e6eb50672d8736710aef31 Mon Sep 17 00:00:00 2001 From: Alex Netsch Date: Mon, 24 Nov 2025 19:12:29 +0000 Subject: [PATCH] Smooth codex login (#1155) * Add codex setup helper Pass exit result Move codex setup to routes FIx fmt Fix finalize * Rename scriptcontext (vibe-kanban 79207902) Rename the gh cli script context to something more general and use it for installs in crates/server/src/routes/task_attempts/cursor_setup.rs Rename scriptcontext (vibe-kanban 79207902) Rename the gh cli script context to something more general and use it for installs in crates/server/src/routes/task_attempts/cursor_setup.rs Fmt * Fix missing overrides for codex --- crates/executors/src/actions/script.rs | 2 +- crates/executors/src/executors/acp/harness.rs | 10 +-- crates/executors/src/executors/codex.rs | 56 ++++++++++--- .../executors/src/executors/codex/client.rs | 21 +++-- .../executors/src/executors/codex/jsonrpc.rs | 13 +-- .../src/executors/codex/normalize_logs.rs | 26 ++++-- crates/executors/src/executors/mod.rs | 20 ++++- crates/local-deployment/src/container.rs | 35 ++++++-- crates/server/src/routes/task_attempts.rs | 4 + .../src/routes/task_attempts/codex_setup.rs | 79 +++++++++++++++++++ .../src/routes/task_attempts/cursor_setup.rs | 4 +- .../src/routes/task_attempts/gh_cli_setup.rs | 4 +- crates/services/src/services/container.rs | 8 ++ .../DisplayConversationEntry.tsx | 2 +- frontend/src/hooks/useConversationHistory.ts | 4 +- shared/types.ts | 2 +- 16 files changed, 234 insertions(+), 56 deletions(-) create mode 100644 crates/server/src/routes/task_attempts/codex_setup.rs diff --git a/crates/executors/src/actions/script.rs b/crates/executors/src/actions/script.rs index 47e1733f..d92b59d2 100644 --- a/crates/executors/src/actions/script.rs +++ b/crates/executors/src/actions/script.rs @@ -23,7 +23,7 @@ pub enum ScriptContext { SetupScript, CleanupScript, DevServer, - GithubCliSetupScript, + ToolInstallScript, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, TS)] diff --git a/crates/executors/src/executors/acp/harness.rs b/crates/executors/src/executors/acp/harness.rs index 2f299b16..d0ad87a0 100644 --- a/crates/executors/src/executors/acp/harness.rs +++ b/crates/executors/src/executors/acp/harness.rs @@ -19,7 +19,7 @@ use workspace_utils::stream_lines::LinesStreamExt; use super::{AcpClient, SessionManager}; use crate::{ command::CommandParts, - executors::{ExecutorError, SpawnedChild, acp::AcpEvent}, + executors::{ExecutorError, ExecutorExitResult, SpawnedChild, acp::AcpEvent}, }; /// Reusable harness for ACP-based conns (Gemini, Qwen, etc.) @@ -68,7 +68,7 @@ impl AcpAgentHarness { let mut child = command.group_spawn()?; - let (exit_tx, exit_rx) = tokio::sync::oneshot::channel::<()>(); + let (exit_tx, exit_rx) = tokio::sync::oneshot::channel::(); Self::bootstrap_acp_connection( &mut child, current_dir.to_path_buf(), @@ -105,7 +105,7 @@ impl AcpAgentHarness { let mut child = command.group_spawn()?; - let (exit_tx, exit_rx) = tokio::sync::oneshot::channel::<()>(); + let (exit_tx, exit_rx) = tokio::sync::oneshot::channel::(); Self::bootstrap_acp_connection( &mut child, current_dir.to_path_buf(), @@ -127,7 +127,7 @@ impl AcpAgentHarness { cwd: PathBuf, existing_session: Option, prompt: String, - exit_signal: Option>, + exit_signal: Option>, session_namespace: String, ) -> Result<(), ExecutorError> { // Take child's stdio for ACP wiring @@ -387,7 +387,7 @@ impl AcpAgentHarness { } // Notify container of completion if let Some(tx) = exit_signal_tx.take() { - let _ = tx.send(()); + let _ = tx.send(ExecutorExitResult::Success); } // Cancel session work diff --git a/crates/executors/src/executors/codex.rs b/crates/executors/src/executors/codex.rs index f5a4a515..42ab7e75 100644 --- a/crates/executors/src/executors/codex.rs +++ b/crates/executors/src/executors/codex.rs @@ -33,7 +33,8 @@ use crate::{ approvals::ExecutorApprovalService, command::{CmdOverrides, CommandBuilder, CommandParts, apply_overrides}, executors::{ - AppendPrompt, AvailabilityInfo, ExecutorError, SpawnedChild, StandardCodingAgentExecutor, + AppendPrompt, AvailabilityInfo, ExecutorError, ExecutorExitResult, SpawnedChild, + StandardCodingAgentExecutor, codex::{jsonrpc::ExitSignalSender, normalize_logs::Error}, }, stdout_dup::create_stdout_pipe_writer, @@ -195,9 +196,13 @@ impl StandardCodingAgentExecutor for Codex { } impl Codex { - fn build_command_builder(&self) -> CommandBuilder { - let mut builder = CommandBuilder::new("npx -y @openai/codex@0.60.1 app-server"); + pub fn base_command() -> &'static str { + "npx -y @openai/codex@0.60.1" + } + fn build_command_builder(&self) -> CommandBuilder { + let mut builder = CommandBuilder::new(Self::base_command()); + builder = builder.extend_params(["app-server"]); if self.oss.unwrap_or(false) { builder = builder.extend_params(["--oss"]); } @@ -328,17 +333,36 @@ impl Codex { ) .await { - if matches!(&err, ExecutorError::Io(io_err) if io_err.kind() == std::io::ErrorKind::BrokenPipe) - { - // Broken pipe likely means the parent process exited, so we can ignore it - return; + match &err { + ExecutorError::Io(io_err) + if io_err.kind() == std::io::ErrorKind::BrokenPipe => + { + // Broken pipe likely means the parent process exited, so we can ignore it + return; + } + ExecutorError::AuthRequired(message) => { + log_writer + .log_raw(&Error::auth_required(message.clone()).raw()) + .await + .ok(); + // Send failure signal so the process is marked as failed + exit_signal_tx + .send_exit_signal(ExecutorExitResult::Failure) + .await; + return; + } + _ => { + tracing::error!("Codex spawn error: {}", err); + log_writer + .log_raw(&Error::launch_error(err.to_string()).raw()) + .await + .ok(); + } } - tracing::error!("Codex spawn error: {}", err); - log_writer - .log_raw(&Error::launch_error(err.to_string()).raw()) - .await - .ok(); - exit_signal_tx.send_exit_signal().await; + // For other errors, also send failure signal + exit_signal_tx + .send_exit_signal(ExecutorExitResult::Failure) + .await; } }); @@ -365,6 +389,12 @@ impl Codex { JsonRpcPeer::spawn(child_stdin, child_stdout, client.clone(), exit_signal_tx); client.connect(rpc_peer); client.initialize().await?; + let auth_status = client.get_auth_status().await?; + if auth_status.auth_method.is_none() { + return Err(ExecutorError::AuthRequired( + "Codex authentication required".to_string(), + )); + } match resume_session { None => { let params = conversation_params; diff --git a/crates/executors/src/executors/codex/client.rs b/crates/executors/src/executors/codex/client.rs index 13138832..61c83a80 100644 --- a/crates/executors/src/executors/codex/client.rs +++ b/crates/executors/src/executors/codex/client.rs @@ -8,11 +8,11 @@ use std::{ use async_trait::async_trait; use codex_app_server_protocol::{ AddConversationListenerParams, AddConversationSubscriptionResponse, ApplyPatchApprovalResponse, - ClientInfo, ClientNotification, ClientRequest, ExecCommandApprovalResponse, InitializeParams, - InitializeResponse, InputItem, JSONRPCError, JSONRPCNotification, JSONRPCRequest, - JSONRPCResponse, NewConversationParams, NewConversationResponse, RequestId, - ResumeConversationParams, ResumeConversationResponse, SendUserMessageParams, - SendUserMessageResponse, ServerNotification, ServerRequest, + ClientInfo, ClientNotification, ClientRequest, ExecCommandApprovalResponse, + GetAuthStatusParams, GetAuthStatusResponse, InitializeParams, InitializeResponse, InputItem, + JSONRPCError, JSONRPCNotification, JSONRPCRequest, JSONRPCResponse, NewConversationParams, + NewConversationResponse, RequestId, ResumeConversationParams, ResumeConversationResponse, + SendUserMessageParams, SendUserMessageResponse, ServerNotification, ServerRequest, }; use codex_protocol::{ConversationId, protocol::ReviewDecision}; use serde::{Serialize, de::DeserializeOwned}; @@ -131,6 +131,16 @@ impl AppServerClient { self.send_request(request, "sendUserMessage").await } + pub async fn get_auth_status(&self) -> Result { + let request = ClientRequest::GetAuthStatus { + request_id: self.next_request_id(), + params: GetAuthStatusParams { + include_token: Some(true), + refresh_token: Some(false), + }, + }; + self.send_request(request, "getAuthStatus").await + } async fn handle_server_request( &self, peer: &JsonRpcPeer, @@ -454,6 +464,7 @@ fn request_id(request: &ClientRequest) -> RequestId { match request { ClientRequest::Initialize { request_id, .. } | ClientRequest::NewConversation { request_id, .. } + | ClientRequest::GetAuthStatus { request_id, .. } | ClientRequest::ResumeConversation { request_id, .. } | ClientRequest::AddConversationListener { request_id, .. } | ClientRequest::SendUserMessage { request_id, .. } => request_id.clone(), diff --git a/crates/executors/src/executors/codex/jsonrpc.rs b/crates/executors/src/executors/codex/jsonrpc.rs index 25c01a7d..4717afa7 100644 --- a/crates/executors/src/executors/codex/jsonrpc.rs +++ b/crates/executors/src/executors/codex/jsonrpc.rs @@ -27,7 +27,7 @@ use tokio::{ sync::{Mutex, oneshot}, }; -use crate::executors::ExecutorError; +use crate::executors::{ExecutorError, ExecutorExitResult}; #[derive(Debug)] pub enum PendingResponse { @@ -38,18 +38,19 @@ pub enum PendingResponse { #[derive(Clone)] pub struct ExitSignalSender { - inner: Arc>>>, + inner: Arc>>>, } impl ExitSignalSender { - pub fn new(sender: oneshot::Sender<()>) -> Self { + pub fn new(sender: oneshot::Sender) -> Self { Self { inner: Arc::new(Mutex::new(Some(sender))), } } - pub async fn send_exit_signal(&self) { + + pub async fn send_exit_signal(&self, result: ExecutorExitResult) { if let Some(sender) = self.inner.lock().await.take() { - let _ = sender.send(()); + let _ = sender.send(result); } } } @@ -155,7 +156,7 @@ impl JsonRpcPeer { } } - exit_tx.send_exit_signal().await; + exit_tx.send_exit_signal(ExecutorExitResult::Success).await; let _ = reader_peer.shutdown().await; }); diff --git a/crates/executors/src/executors/codex/normalize_logs.rs b/crates/executors/src/executors/codex/normalize_logs.rs index ecd37393..b726b1f5 100644 --- a/crates/executors/src/executors/codex/normalize_logs.rs +++ b/crates/executors/src/executors/codex/normalize_logs.rs @@ -1035,12 +1035,16 @@ lazy_static! { #[derive(Serialize, Deserialize, Debug)] pub enum Error { LaunchError { error: String }, + AuthRequired { error: String }, } impl Error { pub fn launch_error(error: String) -> Self { Self::LaunchError { error } } + pub fn auth_required(error: String) -> Self { + Self::AuthRequired { error } + } pub fn raw(&self) -> String { serde_json::to_string(self).unwrap_or_default() @@ -1049,15 +1053,23 @@ impl Error { impl ToNormalizedEntry for Error { fn to_normalized_entry(&self) -> NormalizedEntry { - NormalizedEntry { - timestamp: None, - entry_type: NormalizedEntryType::ErrorMessage { - error_type: NormalizedEntryError::Other, + match self { + Error::LaunchError { error } => NormalizedEntry { + timestamp: None, + entry_type: NormalizedEntryType::ErrorMessage { + error_type: NormalizedEntryError::Other, + }, + content: error.clone(), + metadata: None, }, - content: match self { - Error::LaunchError { error } => error.clone(), + Error::AuthRequired { error } => NormalizedEntry { + timestamp: None, + entry_type: NormalizedEntryType::ErrorMessage { + error_type: NormalizedEntryError::SetupRequired, + }, + content: error.clone(), + metadata: None, }, - metadata: None, } } } diff --git a/crates/executors/src/executors/mod.rs b/crates/executors/src/executors/mod.rs index 809df34e..a13d5564 100644 --- a/crates/executors/src/executors/mod.rs +++ b/crates/executors/src/executors/mod.rs @@ -67,6 +67,8 @@ pub enum ExecutorError { ExecutableNotFound { program: String }, #[error("Setup helper not supported")] SetupHelperNotSupported, + #[error("Auth required: {0}")] + AuthRequired(String), } #[enum_dispatch] @@ -154,10 +156,13 @@ impl CodingAgent { match self { Self::ClaudeCode(_) | Self::Amp(_) - | Self::Codex(_) | Self::Gemini(_) | Self::QwenCode(_) | Self::Droid(_) => vec![BaseAgentCapability::SessionFork], + Self::Codex(_) => vec![ + BaseAgentCapability::SessionFork, + BaseAgentCapability::SetupHelper, + ], Self::CursorAgent(_) => vec![BaseAgentCapability::SetupHelper], Self::Opencode(_) | Self::Copilot(_) => vec![], } @@ -217,10 +222,19 @@ pub trait StandardCodingAgentExecutor { } } +/// Result communicated through the exit signal +#[derive(Debug, Clone, Copy)] +pub enum ExecutorExitResult { + /// Process completed successfully (exit code 0) + Success, + /// Process should be marked as failed (non-zero exit) + Failure, +} + /// Optional exit notification from an executor. /// When this receiver resolves, the container should gracefully stop the process -/// and mark it as successful (exit code 0). -pub type ExecutorExitSignal = tokio::sync::oneshot::Receiver<()>; +/// and mark it according to the result. +pub type ExecutorExitSignal = tokio::sync::oneshot::Receiver; #[derive(Debug)] pub struct SpawnedChild { diff --git a/crates/local-deployment/src/container.rs b/crates/local-deployment/src/container.rs index d51011b0..855c342a 100644 --- a/crates/local-deployment/src/container.rs +++ b/crates/local-deployment/src/container.rs @@ -28,7 +28,7 @@ use deployment::{DeploymentError, RemoteClientNotConfigured}; use executors::{ actions::{Executable, ExecutorAction}, approvals::{ExecutorApprovalService, NoopExecutorApprovalService}, - executors::BaseCodingAgent, + executors::{BaseCodingAgent, ExecutorExitResult, ExecutorExitSignal}, logs::{ NormalizedEntryType, utils::{ @@ -284,7 +284,7 @@ impl LocalContainerService { pub fn spawn_exit_monitor( &self, exec_id: &Uuid, - exit_signal: Option>, + exit_signal: Option, ) -> JoinHandle<()> { let exec_id = *exec_id; let child_store = self.child_store.clone(); @@ -299,25 +299,31 @@ impl LocalContainerService { tokio::spawn(async move { let mut exit_signal_future = exit_signal - .map(|rx| rx.map(|_| ()).boxed()) // wait for signal - .unwrap_or_else(|| std::future::pending::<()>().boxed()); // no signal, stall forever + .map(|rx| rx.boxed()) // wait for result + .unwrap_or_else(|| std::future::pending().boxed()); // no signal, stall forever let status_result: std::io::Result; // Wait for process to exit, or exit signal from executor tokio::select! { - // Exit signal. + // Exit signal with result. // Some coding agent processes do not automatically exit after processing the user request; instead the executor // signals when processing has finished to gracefully kill the process. - _ = &mut exit_signal_future => { - // Executor signaled completion: kill group and remember to force Completed(0) + exit_result = &mut exit_signal_future => { + // Executor signaled completion: kill group and use the provided result if let Some(child_lock) = child_store.read().await.get(&exec_id).cloned() { let mut child = child_lock.write().await ; if let Err(err) = command::kill_process_group(&mut child).await { tracing::error!("Failed to kill process group after exit signal: {} {}", exec_id, err); } } - status_result = Ok(success_exit_status()); + + // Map the exit result to appropriate exit status + status_result = match exit_result { + Ok(ExecutorExitResult::Success) => Ok(success_exit_status()), + Ok(ExecutorExitResult::Failure) => Ok(failure_exit_status()), + Err(_) => Ok(success_exit_status()), // Channel closed, assume success + }; } // Process exit exit_status_result = &mut process_exit_rx => { @@ -810,6 +816,19 @@ impl LocalContainerService { } } +fn failure_exit_status() -> std::process::ExitStatus { + #[cfg(unix)] + { + use std::os::unix::process::ExitStatusExt; + ExitStatusExt::from_raw(256) // Exit code 1 (shifted by 8 bits) + } + #[cfg(windows)] + { + use std::os::windows::process::ExitStatusExt; + ExitStatusExt::from_raw(1) + } +} + #[async_trait] impl ContainerService for LocalContainerService { fn msg_stores(&self) -> &Arc>>> { diff --git a/crates/server/src/routes/task_attempts.rs b/crates/server/src/routes/task_attempts.rs index ea4ab99c..9b4695ea 100644 --- a/crates/server/src/routes/task_attempts.rs +++ b/crates/server/src/routes/task_attempts.rs @@ -1,3 +1,4 @@ +pub mod codex_setup; pub mod cursor_setup; pub mod drafts; pub mod gh_cli_setup; @@ -191,6 +192,9 @@ pub async fn run_agent_setup( CodingAgent::CursorAgent(_) => { cursor_setup::run_cursor_setup(&deployment, &task_attempt).await?; } + CodingAgent::Codex(codex) => { + codex_setup::run_codex_setup(&deployment, &task_attempt, &codex).await?; + } _ => return Err(ApiError::Executor(ExecutorError::SetupHelperNotSupported)), } diff --git a/crates/server/src/routes/task_attempts/codex_setup.rs b/crates/server/src/routes/task_attempts/codex_setup.rs new file mode 100644 index 00000000..675fc9ce --- /dev/null +++ b/crates/server/src/routes/task_attempts/codex_setup.rs @@ -0,0 +1,79 @@ +use db::models::{ + execution_process::{ExecutionProcess, ExecutionProcessRunReason}, + task_attempt::{TaskAttempt, TaskAttemptError}, +}; +use deployment::Deployment; +use executors::{actions::ExecutorAction, executors::ExecutorError}; +#[cfg(unix)] +use executors::{ + actions::{ + ExecutorActionType, + script::{ScriptContext, ScriptRequest, ScriptRequestLanguage}, + }, + command::CommandBuilder, + command::apply_overrides, + executors::codex::Codex, +}; +use services::services::container::ContainerService; + +use crate::{error::ApiError, routes::task_attempts::ensure_worktree_path}; + +pub async fn run_codex_setup( + deployment: &crate::DeploymentImpl, + task_attempt: &TaskAttempt, + codex: &Codex, +) -> Result { + let latest_process = ExecutionProcess::find_latest_by_task_attempt_and_run_reason( + &deployment.db().pool, + task_attempt.id, + &ExecutionProcessRunReason::CodingAgent, + ) + .await?; + + let executor_action = if let Some(latest_process) = latest_process { + let latest_action = latest_process + .executor_action() + .map_err(|e| ApiError::TaskAttempt(TaskAttemptError::ValidationError(e.to_string())))?; + get_setup_helper_action(codex) + .await? + .append_action(latest_action.to_owned()) + } else { + get_setup_helper_action(codex).await? + }; + + let _ = ensure_worktree_path(deployment, task_attempt).await?; + + let execution_process = deployment + .container() + .start_execution( + task_attempt, + &executor_action, + &ExecutionProcessRunReason::SetupScript, + ) + .await?; + Ok(execution_process) +} + +async fn get_setup_helper_action(codex: &Codex) -> Result { + let mut login_command = CommandBuilder::new(Codex::base_command()); + login_command = login_command.extend_params(["login"]); + login_command = apply_overrides(login_command, &codex.cmd); + + let (program_path, args) = login_command + .build_initial() + .map_err(|err| ApiError::Executor(ExecutorError::from(err)))? + .into_resolved() + .await + .map_err(ApiError::Executor)?; + let login_script = format!("{} {}", program_path.to_string_lossy(), args.join(" ")); + let login_request = ScriptRequest { + script: login_script, + language: ScriptRequestLanguage::Bash, + context: ScriptContext::ToolInstallScript, + }; + + Ok(ExecutorAction::new( + ExecutorActionType::ScriptRequest(login_request), + None, + )) +} diff --git a/crates/server/src/routes/task_attempts/cursor_setup.rs b/crates/server/src/routes/task_attempts/cursor_setup.rs index 426c576f..aebc81f2 100644 --- a/crates/server/src/routes/task_attempts/cursor_setup.rs +++ b/crates/server/src/routes/task_attempts/cursor_setup.rs @@ -85,7 +85,7 @@ fi"# let install_request = ScriptRequest { script: install_script, language: ScriptRequestLanguage::Bash, - context: ScriptContext::SetupScript, + context: ScriptContext::ToolInstallScript, }; // Second action (chained): Login let login_script = format!( @@ -98,7 +98,7 @@ export PATH="$HOME/.local/bin:$PATH" let login_request = ScriptRequest { script: login_script, language: ScriptRequestLanguage::Bash, - context: ScriptContext::SetupScript, + context: ScriptContext::ToolInstallScript, }; // Chain them: install → login diff --git a/crates/server/src/routes/task_attempts/gh_cli_setup.rs b/crates/server/src/routes/task_attempts/gh_cli_setup.rs index e24af967..61d22aeb 100644 --- a/crates/server/src/routes/task_attempts/gh_cli_setup.rs +++ b/crates/server/src/routes/task_attempts/gh_cli_setup.rs @@ -71,7 +71,7 @@ fi"# let install_request = ScriptRequest { script: install_script, language: ScriptRequestLanguage::Bash, - context: ScriptContext::GithubCliSetupScript, + context: ScriptContext::ToolInstallScript, }; // Auth script @@ -85,7 +85,7 @@ gh auth login --web --git-protocol https --skip-ssh-key let auth_request = ScriptRequest { script: auth_script, language: ScriptRequestLanguage::Bash, - context: ScriptContext::GithubCliSetupScript, + context: ScriptContext::ToolInstallScript, }; // Chain them: install → auth diff --git a/crates/services/src/services/container.rs b/crates/services/src/services/container.rs index d3f217b6..86b7e913 100644 --- a/crates/services/src/services/container.rs +++ b/crates/services/src/services/container.rs @@ -125,6 +125,14 @@ pub trait ContainerService { /// - The next action is None (no follow-up actions) /// - The run reason is not DevServer fn should_finalize(&self, ctx: &ExecutionContext) -> bool { + // Always finalize failed or killed executions + if matches!( + ctx.execution_process.status, + ExecutionProcessStatus::Failed | ExecutionProcessStatus::Killed + ) { + return true; + } + // Otherwise, finalize only if no next action and not a dev server ctx.execution_process .executor_action() .unwrap() diff --git a/frontend/src/components/NormalizedConversation/DisplayConversationEntry.tsx b/frontend/src/components/NormalizedConversation/DisplayConversationEntry.tsx index 57cfce0a..2a97fd24 100644 --- a/frontend/src/components/NormalizedConversation/DisplayConversationEntry.tsx +++ b/frontend/src/components/NormalizedConversation/DisplayConversationEntry.tsx @@ -434,7 +434,7 @@ const ToolCallCard: React.FC<{ : undefined; // Compute defaults from entry - const linkifyUrls = entryType?.tool_name === 'GitHub CLI Setup Script'; + const linkifyUrls = entryType?.tool_name === 'Tool Install Script'; const defaultExpanded = linkifyUrls; const [expanded, toggle] = useExpandable( diff --git a/frontend/src/hooks/useConversationHistory.ts b/frontend/src/hooks/useConversationHistory.ts index 6d93c539..23bba636 100644 --- a/frontend/src/hooks/useConversationHistory.ts +++ b/frontend/src/hooks/useConversationHistory.ts @@ -326,8 +326,8 @@ export const useConversationHistory = ({ case 'CleanupScript': toolName = 'Cleanup Script'; break; - case 'GithubCliSetupScript': - toolName = 'GitHub CLI Setup Script'; + case 'ToolInstallScript': + toolName = 'Tool Install Script'; break; default: return []; diff --git a/shared/types.ts b/shared/types.ts index 8af8d0e3..44d7d263 100644 --- a/shared/types.ts +++ b/shared/types.ts @@ -28,7 +28,7 @@ export type McpConfig = { servers: { [key in string]?: JsonValue }, servers_path export type ExecutorActionType = { "type": "CodingAgentInitialRequest" } & CodingAgentInitialRequest | { "type": "CodingAgentFollowUpRequest" } & CodingAgentFollowUpRequest | { "type": "ScriptRequest" } & ScriptRequest; -export type ScriptContext = "SetupScript" | "CleanupScript" | "DevServer" | "GithubCliSetupScript"; +export type ScriptContext = "SetupScript" | "CleanupScript" | "DevServer" | "ToolInstallScript"; export type ScriptRequest = { script: string, language: ScriptRequestLanguage, context: ScriptContext, };