Class: Rubino::Tools::ShellKillTool

Inherits:
Base
  • Object
show all
Defined in:
lib/rubino/tools/shell_kill_tool.rb

Overview

Terminates a background shell. Sends SIGTERM to the whole process group first; if the process is still alive after a 2s grace period, follows up with SIGKILL.

Constant Summary collapse

GRACE_SECONDS =
2

Instance Attribute Summary

Attributes inherited from Base

#cancel_token, #read_tracker, #stream_chunk, #stream_kind

Instance Method Summary collapse

Methods inherited from Base

#cancellation_requested?, #config_key, #display_name, #emit_chunk, #mcp?, #risky?, #to_tool_definition, workspace_root, workspace_roots

Instance Method Details

#call(arguments) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/rubino/tools/shell_kill_tool.rb', line 38

def call(arguments)
  run_id = arguments["run_id"] || arguments[:run_id]
  return "Error: run_id is required" if run_id.nil? || run_id.to_s.empty?

  registry = ShellRegistry.instance
  entry    = registry.find(run_id)
  return "Error: no background shell with run_id=#{run_id}" unless entry

  unless entry.wait_thr.alive?
    # Already finished cleanly — nothing to signal. Retire (don't drop) so
    # its captured output stays retrievable via shell_output (#78).
    registry.retire(run_id)
    return "[#{run_id}] already exited (exit=#{registry.exit_code(entry)})"
  end

  send_signal(entry.pgid, "TERM")
  GRACE_SECONDS.times do
    break unless entry.wait_thr.alive?

    sleep 1
  end

  if entry.wait_thr.alive?
    send_signal(entry.pgid, "KILL")
    sleep 0.1
  end

  # Retire (don't drop) so the partial output captured before the kill
  # stays retrievable via shell_output on a later turn (#78).
  registry.retire(run_id)
  "[#{run_id}] terminated (SIGTERM" + (entry.wait_thr.alive? ? "+SIGKILL" : "") + ")"
end

#descriptionObject



15
16
17
18
19
# File 'lib/rubino/tools/shell_kill_tool.rb', line 15

def description
  "Terminate a background shell started via `shell` with run_in_background: true. " \
    "Sends SIGTERM to the process group, waits #{GRACE_SECONDS}s, then SIGKILL if " \
    "the process is still alive."
end

#input_schemaObject



21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/rubino/tools/shell_kill_tool.rb', line 21

def input_schema
  {
    type: "object",
    properties: {
      run_id: {
        type: "string",
        description: "The run_id returned by `shell` when launched in background"
      }
    },
    required: %w[run_id]
  }
end

#nameObject



11
12
13
# File 'lib/rubino/tools/shell_kill_tool.rb', line 11

def name
  "shell_kill"
end

#risk_levelObject



34
35
36
# File 'lib/rubino/tools/shell_kill_tool.rb', line 34

def risk_level
  :medium
end