mirror of
https://github.com/openai/codex.git
synced 2026-06-01 19:02:59 +00:00
hooks: emit Bash PostToolUse when exec_command completes via write_stdin (#18888)
Fixes #16246. ## Why `exec_command` already emits `PreToolUse`, but long-running unified exec commands that finish on a later `write_stdin` poll could miss the matching `PostToolUse`. That left the Bash hook lifecycle inconsistent, broke expectations around `tool_use_id` and `tool_input.command`, and meant `PostToolUse` block/replacement feedback could fail to replace the final session output before it reached model context. This keeps the fix scoped to the `exec_command` / `write_stdin` lifecycle. Broader non-Bash hook expansion is still out of scope here and remains tracked separately in #16732. ## What changed - Compute and store `PostToolUsePayload` while handlers still have access to their concrete output type, and carry `tool_use_id` through that payload. - Preserve the original hook-facing `exec_command` string through unified exec state (`ExecCommandRequest`, `ProcessEntry`, `PreparedProcessHandles`, and `ExecCommandToolOutput`) via `hook_command`, and remove the now-unused `session_command` output metadata. - Emit exactly one Bash `PostToolUse` for long-running `exec_command` sessions when a later `write_stdin` poll observes final completion, using the original `exec_command` call id and hook-facing command. - Keep one-shot `exec_command` behavior aligned with the same payload construction, including interactive completions that return a final result directly. - Apply `PostToolUse` block/replacement feedback before the final `write_stdin` completion output is sent back to the model. - Keep `write_stdin` itself out of `PreToolUse` matching so it continues to act as transport/polling for the original Bash tool call. - Restore plain matcher behavior for tool-name matchers such as `Bash` and `Edit|Write`, while still treating patterns with regex characters (for example `mcp__.*`) as regexes. - Add unit coverage for unified exec payload construction and parallel session separation, plus a core integration regression that verifies a blocked `PostToolUse` replaces the final `write_stdin` output in model context. ## Testing - `cargo test -p codex-hooks` - `cargo test -p codex-core post_tool_use_payload` - `cargo test -p codex-core post_tool_use_blocks_when_exec_session_completes_via_write_stdin`
This commit is contained in:
@@ -370,7 +370,7 @@ pub struct ExecCommandToolOutput {
|
||||
pub process_id: Option<i32>,
|
||||
pub exit_code: Option<i32>,
|
||||
pub original_token_count: Option<usize>,
|
||||
pub session_command: Option<Vec<String>>,
|
||||
pub hook_command: Option<String>,
|
||||
}
|
||||
|
||||
impl ToolOutput for ExecCommandToolOutput {
|
||||
@@ -394,7 +394,7 @@ impl ToolOutput for ExecCommandToolOutput {
|
||||
}
|
||||
|
||||
fn post_tool_use_response(&self, _call_id: &str, _payload: &ToolPayload) -> Option<JsonValue> {
|
||||
if self.process_id.is_some() || self.session_command.is_none() {
|
||||
if self.process_id.is_some() || self.hook_command.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
||||
@@ -390,7 +390,7 @@ fn exec_command_tool_output_formats_truncated_response() {
|
||||
process_id: None,
|
||||
exit_code: Some(0),
|
||||
original_token_count: Some(10),
|
||||
session_command: None,
|
||||
hook_command: None,
|
||||
}
|
||||
.to_response_item("call-42", &payload);
|
||||
|
||||
|
||||
@@ -324,11 +324,12 @@ impl ToolHandler for ApplyPatchHandler {
|
||||
&self,
|
||||
call_id: &str,
|
||||
payload: &ToolPayload,
|
||||
result: &dyn ToolOutput,
|
||||
result: &Self::Output,
|
||||
) -> Option<PostToolUsePayload> {
|
||||
let tool_response = result.post_tool_use_response(call_id, payload)?;
|
||||
Some(PostToolUsePayload {
|
||||
tool_name: HookToolName::apply_patch(),
|
||||
tool_use_id: call_id.to_string(),
|
||||
command: apply_patch_payload_command(payload)?,
|
||||
tool_response,
|
||||
})
|
||||
|
||||
@@ -90,6 +90,7 @@ fn post_tool_use_payload_uses_patch_input_and_tool_output() {
|
||||
handler.post_tool_use_payload("call-apply-patch", &payload, &output),
|
||||
Some(PostToolUsePayload {
|
||||
tool_name: HookToolName::apply_patch(),
|
||||
tool_use_id: "call-apply-patch".to_string(),
|
||||
command: patch.to_string(),
|
||||
tool_response: json!("Success. Updated files."),
|
||||
})
|
||||
|
||||
@@ -216,11 +216,12 @@ impl ToolHandler for ShellHandler {
|
||||
&self,
|
||||
call_id: &str,
|
||||
payload: &ToolPayload,
|
||||
result: &dyn ToolOutput,
|
||||
result: &Self::Output,
|
||||
) -> Option<PostToolUsePayload> {
|
||||
let tool_response = result.post_tool_use_response(call_id, payload)?;
|
||||
Some(PostToolUsePayload {
|
||||
tool_name: HookToolName::bash(),
|
||||
tool_use_id: call_id.to_string(),
|
||||
command: shell_payload_command(payload)?,
|
||||
tool_response,
|
||||
})
|
||||
@@ -328,11 +329,12 @@ impl ToolHandler for ShellCommandHandler {
|
||||
&self,
|
||||
call_id: &str,
|
||||
payload: &ToolPayload,
|
||||
result: &dyn ToolOutput,
|
||||
result: &Self::Output,
|
||||
) -> Option<PostToolUsePayload> {
|
||||
let tool_response = result.post_tool_use_response(call_id, payload)?;
|
||||
Some(PostToolUsePayload {
|
||||
tool_name: HookToolName::bash(),
|
||||
tool_use_id: call_id.to_string(),
|
||||
command: shell_command_payload_command(payload)?,
|
||||
tool_response,
|
||||
})
|
||||
|
||||
@@ -284,6 +284,7 @@ fn build_post_tool_use_payload_uses_tool_output_wire_value() {
|
||||
handler.post_tool_use_payload("call-42", &payload, &output),
|
||||
Some(crate::tools::registry::PostToolUsePayload {
|
||||
tool_name: HookToolName::bash(),
|
||||
tool_use_id: "call-42".to_string(),
|
||||
command: "printf shell command".to_string(),
|
||||
tool_response: json!("shell output"),
|
||||
})
|
||||
|
||||
@@ -147,21 +147,23 @@ impl ToolHandler for UnifiedExecHandler {
|
||||
&self,
|
||||
call_id: &str,
|
||||
payload: &ToolPayload,
|
||||
result: &dyn ToolOutput,
|
||||
result: &Self::Output,
|
||||
) -> Option<PostToolUsePayload> {
|
||||
let ToolPayload::Function { arguments } = payload else {
|
||||
let ToolPayload::Function { .. } = payload else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let args = parse_arguments::<ExecCommandArgs>(arguments).ok()?;
|
||||
if args.tty {
|
||||
return None;
|
||||
}
|
||||
|
||||
let tool_response = result.post_tool_use_response(call_id, payload)?;
|
||||
let command = result.hook_command.clone()?;
|
||||
let tool_use_id = if result.event_call_id.is_empty() {
|
||||
call_id.to_string()
|
||||
} else {
|
||||
result.event_call_id.clone()
|
||||
};
|
||||
let tool_response = result.post_tool_use_response(&tool_use_id, payload)?;
|
||||
Some(PostToolUsePayload {
|
||||
tool_name: HookToolName::bash(),
|
||||
command: args.cmd,
|
||||
tool_use_id,
|
||||
command,
|
||||
tool_response,
|
||||
})
|
||||
}
|
||||
@@ -200,11 +202,12 @@ impl ToolHandler for UnifiedExecHandler {
|
||||
"exec_command" => {
|
||||
let cwd = resolve_workdir_base_path(&arguments, &context.turn.cwd)?;
|
||||
let args: ExecCommandArgs = parse_arguments_with_base_path(&arguments, &cwd)?;
|
||||
let hook_command = args.cmd.clone();
|
||||
let workdir = context.turn.resolve_path(args.workdir.clone());
|
||||
maybe_emit_implicit_skill_invocation(
|
||||
session.as_ref(),
|
||||
context.turn.as_ref(),
|
||||
&args.cmd,
|
||||
&hook_command,
|
||||
&workdir,
|
||||
)
|
||||
.await;
|
||||
@@ -313,17 +316,16 @@ impl ToolHandler for UnifiedExecHandler {
|
||||
process_id: None,
|
||||
exit_code: None,
|
||||
original_token_count: None,
|
||||
session_command: None,
|
||||
hook_command: None,
|
||||
});
|
||||
}
|
||||
|
||||
emit_unified_exec_tty_metric(&turn.session_telemetry, tty);
|
||||
let session_command = command.clone();
|
||||
match manager
|
||||
.exec_command(
|
||||
ExecCommandRequest {
|
||||
command,
|
||||
hook_command: args.cmd,
|
||||
hook_command: hook_command.clone(),
|
||||
process_id,
|
||||
yield_time_ms,
|
||||
max_output_tokens,
|
||||
@@ -357,7 +359,7 @@ impl ToolHandler for UnifiedExecHandler {
|
||||
process_id: None,
|
||||
exit_code: Some(output.exit_code),
|
||||
original_token_count: Some(original_token_count),
|
||||
session_command: Some(session_command),
|
||||
hook_command: Some(hook_command),
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
|
||||
@@ -252,7 +252,7 @@ fn exec_command_post_tool_use_payload_uses_output_for_noninteractive_one_shot_co
|
||||
arguments: serde_json::json!({ "cmd": "echo three", "tty": false }).to_string(),
|
||||
};
|
||||
let output = ExecCommandToolOutput {
|
||||
event_call_id: "event-43".to_string(),
|
||||
event_call_id: "call-43".to_string(),
|
||||
chunk_id: "chunk-1".to_string(),
|
||||
wall_time: std::time::Duration::from_millis(498),
|
||||
raw_output: b"three".to_vec(),
|
||||
@@ -260,17 +260,14 @@ fn exec_command_post_tool_use_payload_uses_output_for_noninteractive_one_shot_co
|
||||
process_id: None,
|
||||
exit_code: Some(0),
|
||||
original_token_count: None,
|
||||
session_command: Some(vec![
|
||||
"/bin/zsh".to_string(),
|
||||
"-lc".to_string(),
|
||||
"echo three".to_string(),
|
||||
]),
|
||||
hook_command: Some("echo three".to_string()),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
UnifiedExecHandler.post_tool_use_payload("call-43", &payload, &output),
|
||||
Some(crate::tools::registry::PostToolUsePayload {
|
||||
tool_name: HookToolName::bash(),
|
||||
tool_use_id: "call-43".to_string(),
|
||||
command: "echo three".to_string(),
|
||||
tool_response: serde_json::json!("three"),
|
||||
})
|
||||
@@ -278,12 +275,12 @@ fn exec_command_post_tool_use_payload_uses_output_for_noninteractive_one_shot_co
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_command_post_tool_use_payload_skips_interactive_exec() {
|
||||
fn exec_command_post_tool_use_payload_uses_output_for_interactive_completion() {
|
||||
let payload = ToolPayload::Function {
|
||||
arguments: serde_json::json!({ "cmd": "echo three", "tty": true }).to_string(),
|
||||
};
|
||||
let output = ExecCommandToolOutput {
|
||||
event_call_id: "event-44".to_string(),
|
||||
event_call_id: "call-44".to_string(),
|
||||
chunk_id: "chunk-1".to_string(),
|
||||
wall_time: std::time::Duration::from_millis(498),
|
||||
raw_output: b"three".to_vec(),
|
||||
@@ -291,16 +288,17 @@ fn exec_command_post_tool_use_payload_skips_interactive_exec() {
|
||||
process_id: None,
|
||||
exit_code: Some(0),
|
||||
original_token_count: None,
|
||||
session_command: Some(vec![
|
||||
"/bin/zsh".to_string(),
|
||||
"-lc".to_string(),
|
||||
"echo three".to_string(),
|
||||
]),
|
||||
hook_command: Some("echo three".to_string()),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
UnifiedExecHandler.post_tool_use_payload("call-44", &payload, &output),
|
||||
None
|
||||
Some(crate::tools::registry::PostToolUsePayload {
|
||||
tool_name: HookToolName::bash(),
|
||||
tool_use_id: "call-44".to_string(),
|
||||
command: "echo three".to_string(),
|
||||
tool_response: serde_json::json!("three"),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -318,11 +316,7 @@ fn exec_command_post_tool_use_payload_skips_running_sessions() {
|
||||
process_id: Some(45),
|
||||
exit_code: None,
|
||||
original_token_count: None,
|
||||
session_command: Some(vec![
|
||||
"/bin/zsh".to_string(),
|
||||
"-lc".to_string(),
|
||||
"echo three".to_string(),
|
||||
]),
|
||||
hook_command: Some("echo three".to_string()),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
@@ -330,3 +324,87 @@ fn exec_command_post_tool_use_payload_skips_running_sessions() {
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_stdin_post_tool_use_payload_uses_original_exec_call_id_and_command_on_completion() {
|
||||
let payload = ToolPayload::Function {
|
||||
arguments: serde_json::json!({
|
||||
"session_id": 45,
|
||||
"chars": "",
|
||||
})
|
||||
.to_string(),
|
||||
};
|
||||
let output = ExecCommandToolOutput {
|
||||
event_call_id: "exec-call-45".to_string(),
|
||||
chunk_id: "chunk-2".to_string(),
|
||||
wall_time: std::time::Duration::from_millis(498),
|
||||
raw_output: b"finished\n".to_vec(),
|
||||
max_output_tokens: None,
|
||||
process_id: None,
|
||||
exit_code: Some(0),
|
||||
original_token_count: None,
|
||||
hook_command: Some("sleep 1; echo finished".to_string()),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
UnifiedExecHandler.post_tool_use_payload("write-stdin-call", &payload, &output),
|
||||
Some(crate::tools::registry::PostToolUsePayload {
|
||||
tool_name: HookToolName::bash(),
|
||||
tool_use_id: "exec-call-45".to_string(),
|
||||
command: "sleep 1; echo finished".to_string(),
|
||||
tool_response: serde_json::json!("finished\n"),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_stdin_post_tool_use_payload_keeps_parallel_session_metadata_separate() {
|
||||
let payload = ToolPayload::Function {
|
||||
arguments: serde_json::json!({ "session_id": 45, "chars": "" }).to_string(),
|
||||
};
|
||||
let output_a = ExecCommandToolOutput {
|
||||
event_call_id: "exec-call-a".to_string(),
|
||||
chunk_id: "chunk-a".to_string(),
|
||||
wall_time: std::time::Duration::from_millis(498),
|
||||
raw_output: b"alpha\n".to_vec(),
|
||||
max_output_tokens: None,
|
||||
process_id: None,
|
||||
exit_code: Some(0),
|
||||
original_token_count: None,
|
||||
hook_command: Some("sleep 2; echo alpha".to_string()),
|
||||
};
|
||||
let output_b = ExecCommandToolOutput {
|
||||
event_call_id: "exec-call-b".to_string(),
|
||||
chunk_id: "chunk-b".to_string(),
|
||||
wall_time: std::time::Duration::from_millis(498),
|
||||
raw_output: b"beta\n".to_vec(),
|
||||
max_output_tokens: None,
|
||||
process_id: None,
|
||||
exit_code: Some(0),
|
||||
original_token_count: None,
|
||||
hook_command: Some("sleep 1; echo beta".to_string()),
|
||||
};
|
||||
|
||||
let payloads = [
|
||||
UnifiedExecHandler.post_tool_use_payload("write-call-b", &payload, &output_b),
|
||||
UnifiedExecHandler.post_tool_use_payload("write-call-a", &payload, &output_a),
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
payloads,
|
||||
[
|
||||
Some(crate::tools::registry::PostToolUsePayload {
|
||||
tool_name: HookToolName::bash(),
|
||||
tool_use_id: "exec-call-b".to_string(),
|
||||
command: "sleep 1; echo beta".to_string(),
|
||||
tool_response: serde_json::json!("beta\n"),
|
||||
}),
|
||||
Some(crate::tools::registry::PostToolUsePayload {
|
||||
tool_name: HookToolName::bash(),
|
||||
tool_use_id: "exec-call-a".to_string(),
|
||||
command: "sleep 2; echo alpha".to_string(),
|
||||
tool_response: serde_json::json!("alpha\n"),
|
||||
}),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -178,6 +178,7 @@ impl ToolCallRuntime {
|
||||
result: Box::new(AbortedToolOutput {
|
||||
message: Self::abort_message(call, secs),
|
||||
}),
|
||||
post_tool_use_payload: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ pub trait ToolHandler: Send + Sync {
|
||||
&self,
|
||||
_call_id: &str,
|
||||
_payload: &ToolPayload,
|
||||
_result: &dyn ToolOutput,
|
||||
_result: &Self::Output,
|
||||
) -> Option<PostToolUsePayload> {
|
||||
None
|
||||
}
|
||||
@@ -107,6 +107,7 @@ pub(crate) struct AnyToolResult {
|
||||
pub(crate) call_id: String,
|
||||
pub(crate) payload: ToolPayload,
|
||||
pub(crate) result: Box<dyn ToolOutput>,
|
||||
pub(crate) post_tool_use_payload: Option<PostToolUsePayload>,
|
||||
}
|
||||
|
||||
impl AnyToolResult {
|
||||
@@ -143,9 +144,11 @@ pub(crate) struct PreToolUsePayload {
|
||||
pub(crate) struct PostToolUsePayload {
|
||||
/// Hook-facing tool name model.
|
||||
///
|
||||
/// Keep this aligned with the corresponding pre-use payload so external
|
||||
/// hook consumers can pair events by `tool_use_id`.
|
||||
/// The canonical name is serialized to hook stdin, while aliases are used
|
||||
/// only for matcher compatibility.
|
||||
pub(crate) tool_name: HookToolName,
|
||||
/// The originating tool-use id exposed at `tool_use_id`.
|
||||
pub(crate) tool_use_id: String,
|
||||
/// Command-shaped input exposed at `tool_input.command`.
|
||||
pub(crate) command: String,
|
||||
/// Tool result exposed at `tool_response`.
|
||||
@@ -159,15 +162,7 @@ trait AnyToolHandler: Send + Sync {
|
||||
|
||||
fn pre_tool_use_payload(&self, invocation: &ToolInvocation) -> Option<PreToolUsePayload>;
|
||||
|
||||
fn post_tool_use_payload(
|
||||
&self,
|
||||
call_id: &str,
|
||||
payload: &ToolPayload,
|
||||
result: &dyn ToolOutput,
|
||||
) -> Option<PostToolUsePayload>;
|
||||
|
||||
fn create_diff_consumer(&self) -> Option<Box<dyn ToolArgumentDiffConsumer>>;
|
||||
|
||||
fn handle_any<'a>(
|
||||
&'a self,
|
||||
invocation: ToolInvocation,
|
||||
@@ -190,19 +185,9 @@ where
|
||||
ToolHandler::pre_tool_use_payload(self, invocation)
|
||||
}
|
||||
|
||||
fn post_tool_use_payload(
|
||||
&self,
|
||||
call_id: &str,
|
||||
payload: &ToolPayload,
|
||||
result: &dyn ToolOutput,
|
||||
) -> Option<PostToolUsePayload> {
|
||||
ToolHandler::post_tool_use_payload(self, call_id, payload, result)
|
||||
}
|
||||
|
||||
fn create_diff_consumer(&self) -> Option<Box<dyn ToolArgumentDiffConsumer>> {
|
||||
ToolHandler::create_diff_consumer(self)
|
||||
}
|
||||
|
||||
fn handle_any<'a>(
|
||||
&'a self,
|
||||
invocation: ToolInvocation,
|
||||
@@ -211,10 +196,13 @@ where
|
||||
let call_id = invocation.call_id.clone();
|
||||
let payload = invocation.payload.clone();
|
||||
let output = self.handle(invocation).await?;
|
||||
let post_tool_use_payload =
|
||||
ToolHandler::post_tool_use_payload(self, &call_id, &payload, &output);
|
||||
Ok(AnyToolResult {
|
||||
call_id,
|
||||
payload,
|
||||
result: Box::new(output),
|
||||
post_tool_use_payload,
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -400,13 +388,9 @@ impl ToolRegistry {
|
||||
emit_metric_for_tool_read(&invocation, success).await;
|
||||
let post_tool_use_payload = if success {
|
||||
let guard = response_cell.lock().await;
|
||||
guard.as_ref().and_then(|result| {
|
||||
handler.post_tool_use_payload(
|
||||
&result.call_id,
|
||||
&result.payload,
|
||||
result.result.as_ref(),
|
||||
)
|
||||
})
|
||||
guard
|
||||
.as_ref()
|
||||
.and_then(|result| result.post_tool_use_payload.clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -415,7 +399,7 @@ impl ToolRegistry {
|
||||
run_post_tool_use_hooks(
|
||||
&invocation.session,
|
||||
&invocation.turn,
|
||||
invocation.call_id.clone(),
|
||||
post_tool_use_payload.tool_use_id,
|
||||
post_tool_use_payload.tool_name.name().to_string(),
|
||||
post_tool_use_payload.tool_name.matcher_aliases().to_vec(),
|
||||
post_tool_use_payload.command,
|
||||
|
||||
@@ -148,7 +148,7 @@ struct ProcessEntry {
|
||||
process: Arc<UnifiedExecProcess>,
|
||||
call_id: String,
|
||||
process_id: i32,
|
||||
command: Vec<String>,
|
||||
hook_command: String,
|
||||
tty: bool,
|
||||
network_approval_id: Option<String>,
|
||||
session: Weak<Session>,
|
||||
|
||||
@@ -113,7 +113,7 @@ async fn exec_command_with_tty(
|
||||
process: Arc::clone(&process),
|
||||
call_id: context.call_id.clone(),
|
||||
process_id,
|
||||
command: command.clone(),
|
||||
hook_command: cmd.to_string(),
|
||||
tty,
|
||||
network_approval_id: None,
|
||||
session: Arc::downgrade(session),
|
||||
@@ -165,7 +165,7 @@ async fn exec_command_with_tty(
|
||||
process_id: response_process_id,
|
||||
exit_code,
|
||||
original_token_count: Some(approx_token_count(&text)),
|
||||
session_command: Some(command),
|
||||
hook_command: Some(cmd.to_string()),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ struct PreparedProcessHandles {
|
||||
output_closed_notify: Arc<Notify>,
|
||||
cancellation_token: CancellationToken,
|
||||
pause_state: Option<watch::Receiver<bool>>,
|
||||
command: Vec<String>,
|
||||
hook_command: String,
|
||||
process_id: i32,
|
||||
tty: bool,
|
||||
}
|
||||
@@ -279,6 +279,7 @@ impl UnifiedExecProcessManager {
|
||||
Arc::clone(&process),
|
||||
context,
|
||||
&request.command,
|
||||
request.hook_command.clone(),
|
||||
cwd.clone(),
|
||||
start,
|
||||
request.process_id,
|
||||
@@ -398,7 +399,7 @@ impl UnifiedExecProcessManager {
|
||||
process_id: response_process_id,
|
||||
exit_code,
|
||||
original_token_count: Some(original_token_count),
|
||||
session_command: Some(request.command.clone()),
|
||||
hook_command: Some(request.hook_command.clone()),
|
||||
};
|
||||
|
||||
Ok(response)
|
||||
@@ -418,7 +419,7 @@ impl UnifiedExecProcessManager {
|
||||
output_closed_notify,
|
||||
cancellation_token,
|
||||
pause_state,
|
||||
command: session_command,
|
||||
hook_command,
|
||||
process_id,
|
||||
tty,
|
||||
..
|
||||
@@ -517,7 +518,7 @@ impl UnifiedExecProcessManager {
|
||||
process_id,
|
||||
exit_code,
|
||||
original_token_count: Some(original_token_count),
|
||||
session_command: Some(session_command.clone()),
|
||||
hook_command: Some(hook_command),
|
||||
};
|
||||
|
||||
Ok(response)
|
||||
@@ -585,7 +586,7 @@ impl UnifiedExecProcessManager {
|
||||
output_closed_notify,
|
||||
cancellation_token,
|
||||
pause_state,
|
||||
command: entry.command.clone(),
|
||||
hook_command: entry.hook_command.clone(),
|
||||
process_id: entry.process_id,
|
||||
tty: entry.tty,
|
||||
})
|
||||
@@ -597,6 +598,7 @@ impl UnifiedExecProcessManager {
|
||||
process: Arc<UnifiedExecProcess>,
|
||||
context: &UnifiedExecContext,
|
||||
command: &[String],
|
||||
hook_command: String,
|
||||
cwd: AbsolutePathBuf,
|
||||
started_at: Instant,
|
||||
process_id: i32,
|
||||
@@ -608,7 +610,7 @@ impl UnifiedExecProcessManager {
|
||||
process: Arc::clone(&process),
|
||||
call_id: context.call_id.clone(),
|
||||
process_id,
|
||||
command: command.to_vec(),
|
||||
hook_command,
|
||||
tty,
|
||||
network_approval_id,
|
||||
session: Arc::downgrade(&context.session),
|
||||
|
||||
Reference in New Issue
Block a user