Class: Ask::AppServer::CLI

Inherits:
Object
  • Object
show all
Defined in:
lib/ask/app_server/cli.rb

Overview

CLI for the ask-app-server command.

Usage:

ask-app-server                   # Start in stdio mode (default)
ask-app-server --socket PATH    # Also listen on a unix socket (multi-client)
ask-app-server --version        # Show version
ask-app-server --help           # Show help
ask-app-server --config PATH    # Use specific config file

Environment variables:

ASK_APP_SERVER_CONFIG   - Path to config file (default: auto-detect)
ASK_APP_SERVER_MODEL    - Model to use (overrides config file)
ASK_APP_SERVER_PERMISSIONS - Permission mode (overrides config file)
ASK_APP_SERVER_SOCKET   - Unix socket path (same as --socket)
DEBUG                   - Enable debug logging (1/0)

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.run!(args = ARGV) ⇒ Object



23
24
25
# File 'lib/ask/app_server/cli.rb', line 23

def self.run!(args = ARGV)
  new.run(args)
end

Instance Method Details

#run(args) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
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
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
# File 'lib/ask/app_server/cli.rb', line 27

def run(args)
  case args.first
  when "--version", "-v"
    puts "ask-app-server v#{Ask::AppServer::VERSION}"
    return
  when "--help", "-h"
    show_help
    return
  end

  # Parse --config and --socket from args
  config_path = nil
  socket_path = nil
  args.each_with_index do |arg, i|
    if arg == "--config" && i + 1 < args.length
      config_path = args[i + 1]
    elsif arg == "--socket" && i + 1 < args.length
      socket_path = args[i + 1]
    end
  end

  # Load configuration
  config = Config.new(config_path: config_path)

  # Register custom models from config into the model catalog
  config.register_models!

  # Preload hook: ASK_APP_SERVER_PRELOAD names a Ruby file required
  # at boot, so deployments can register extra tools (e.g. board
  # tools for the executor sessions) before any session is created.
  if (preload = ENV["ASK_APP_SERVER_PRELOAD"])
    require File.expand_path(preload)
  end

  $stdout.sync = true
  $stderr.sync = true

  if config.debug?
    $stderr.puts "[ask-app-server] Starting v#{Ask::AppServer::VERSION}"
    $stderr.puts "[ask-app-server] Config: #{JSON.pretty_generate(config.to_h)}"
  end

  # Build the session manager with config values
  store = build_state_store(config)
  session_manager = SessionManager.new(
    store: store,
    permission_mode: config.permission_mode,
    blocked_tools: config.blocked_tools,
    permission_timeout: config.permission_timeout
  )

  # Pane integration: when running inside a terminal workspace,
  # keep its agent-state sidebar accurate from first-party host
  # events.
  herdr_reporter = HerdrReporter.attach(session_manager)

  # Optional unix-socket transport for multi-client attach (runs
  # alongside the stdio transport, sharing the session manager).
  socket_path ||= ENV["ASK_APP_SERVER_SOCKET"]
  socket_server = nil
  if socket_path
    socket_server = SocketServer.new(session_manager: session_manager, socket_path: socket_path)
    socket_server.start
    $stderr.puts "socket:    #{socket_server.socket_path}"
  end

  # Start the server (stdio transport, blocks)
  server = Server.new(session_manager: session_manager)

  begin
    server.start
  rescue Interrupt
    $stderr.puts "\n[ask-app-server] Shutting down..." if config.debug?
  ensure
    # Clean up on Ctrl-C AND on normal exit (stdin EOF): the socket
    # file must not outlive the host.
    server.stop
    socket_server&.stop
    herdr_reporter&.close
  end
end