Class: SwarmCLI::V3::CLI

Inherits:
Object
  • Object
show all
Defined in:
lib/swarm_cli/v3/cli.rb

Overview

Entry point for the V3 agent chat CLI.

Supports three run modes:

  • Interactive: REPL with always-available input, history

  • Prompt: Run a single prompt and exit (non-interactive)

  • Maintenance: Run memory defrag and exit

Examples:

SwarmCLI::V3::CLI.start(ARGV)

Constant Summary collapse

HISTORY_FILE =
File.expand_path(ENV.fetch("SWARM_V3_HISTORY", "~/.swarm/v3_history"))
HISTORY_SIZE =
1000
CONFIG_FILE =
File.expand_path("~/.config/swarm/cli.json")
DEFAULT_REFINE_PROMPT =
"Review what you just did. Identify weaknesses, errors, " \
"or areas for improvement, then make the improvements."

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(argv) ⇒ CLI

Returns a new instance of CLI.

Parameters:

  • argv (Array<String>)

    command-line arguments



33
34
35
36
37
# File 'lib/swarm_cli/v3/cli.rb', line 33

def initialize(argv)
  @original_argv = strip_reboot_flag(argv.dup).freeze
  @argv = argv.dup
  @options = {}
end

Class Method Details

.start(argv) ⇒ void

This method returns an undefined value.

Parse arguments and run the appropriate mode.

Parameters:

  • argv (Array<String>)

    command-line arguments



27
28
29
# File 'lib/swarm_cli/v3/cli.rb', line 27

def start(argv)
  new(argv).run
end

Instance Method Details

#expand_file_mentions(prompt, display: nil) ⇒ String

Expand @file mentions to include file contents. This is a public utility method that can be used for testing. Uses Read tool for consistent file handling including documents.

Parameters:

  • prompt (String)

    the prompt text with @file mentions

  • display (Display, nil) (defaults to: nil)

    optional display to show read status

Returns:

  • (String)

    the expanded prompt with file contents



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/swarm_cli/v3/cli.rb', line 66

def expand_file_mentions(prompt, display: nil)
  # Create Read tool for consistent file handling (including documents)
  read_tracker = SwarmSDK::V3::Tools::ReadTracker.new
  read_tool = SwarmSDK::V3::Tools::Read.new(
    agent_name: :cli,
    directory: Dir.pwd,
    read_tracker: read_tracker,
  )

  prompt.gsub(%r{@([\w/.~-]+)}) do |match|
    path = Regexp.last_match(1)

    if File.file?(path)
      result = read_tool.execute(file_path: path)

      # Handle result types
      case result
      when RubyLLM::Content
        # Document with images
        display&.agent_print(ANSIColors.dim("  \u{1F4C4} Read @#{path} (with images)"))
        "\n\n<file path=\"#{path}\">\n#{result.text}\n</file>\n"
      when /^<system-reminder>/
        # Missing gem
        display&.agent_print(ANSIColors.yellow("  \u26A0\uFE0F  @#{path} requires gem"))
        match # Keep original
      when /^Error:/
        # Conversion error
        display&.agent_print(ANSIColors.yellow("  \u26A0\uFE0F  Could not read @#{path}"))
        match # Keep original
      else
        # Text content
        display&.agent_print(ANSIColors.dim("  \u{1F4C4} Read @#{path}"))
        "\n\n<file path=\"#{path}\">\n#{result}\n</file>\n"
      end
    elsif File.directory?(path)
      entries = Dir.children(path).sort
      display&.agent_print(ANSIColors.dim("  \u{1F4C2} Read @#{path}/ (#{entries.size} entries)"))
      "\n\n<directory path=\"#{path}\">\n#{entries.join("\n")}\n</directory>\n"
    else
      match # Keep original if path doesn't exist
    end
  rescue StandardError => _e
    match # Keep original on error
  end
end

#runvoid

This method returns an undefined value.

Parse arguments, load agent, and dispatch to the appropriate mode.



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/swarm_cli/v3/cli.rb', line 42

def run
  parse_options!
  configure_providers!
  agent = load_agent(@argv.first)
  register_reboot_tool!

  handle_reboot_continuation(agent) if @options[:reboot_from]

  if @options[:defrag]
    run_maintenance(agent)
  elsif @options[:prompt] && !@options[:reboot_from]
    run_prompt(agent)
  else
    run_interactive(agent)
  end
end