pocketrb 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +32 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +456 -0
  5. data/exe/pocketrb +6 -0
  6. data/lib/pocketrb/agent/compaction.rb +187 -0
  7. data/lib/pocketrb/agent/context.rb +171 -0
  8. data/lib/pocketrb/agent/loop.rb +276 -0
  9. data/lib/pocketrb/agent/spawn_tool.rb +72 -0
  10. data/lib/pocketrb/agent/subagent_manager.rb +196 -0
  11. data/lib/pocketrb/bus/events.rb +99 -0
  12. data/lib/pocketrb/bus/message_bus.rb +148 -0
  13. data/lib/pocketrb/channels/base.rb +69 -0
  14. data/lib/pocketrb/channels/cli.rb +109 -0
  15. data/lib/pocketrb/channels/telegram.rb +607 -0
  16. data/lib/pocketrb/channels/whatsapp.rb +242 -0
  17. data/lib/pocketrb/cli/base.rb +119 -0
  18. data/lib/pocketrb/cli/chat.rb +67 -0
  19. data/lib/pocketrb/cli/config.rb +52 -0
  20. data/lib/pocketrb/cli/cron.rb +144 -0
  21. data/lib/pocketrb/cli/gateway.rb +132 -0
  22. data/lib/pocketrb/cli/init.rb +39 -0
  23. data/lib/pocketrb/cli/plans.rb +28 -0
  24. data/lib/pocketrb/cli/skills.rb +34 -0
  25. data/lib/pocketrb/cli/start.rb +55 -0
  26. data/lib/pocketrb/cli/telegram.rb +93 -0
  27. data/lib/pocketrb/cli/version.rb +18 -0
  28. data/lib/pocketrb/cli/whatsapp.rb +60 -0
  29. data/lib/pocketrb/cli.rb +124 -0
  30. data/lib/pocketrb/config.rb +190 -0
  31. data/lib/pocketrb/cron/job.rb +155 -0
  32. data/lib/pocketrb/cron/service.rb +395 -0
  33. data/lib/pocketrb/heartbeat/service.rb +175 -0
  34. data/lib/pocketrb/mcp/client.rb +172 -0
  35. data/lib/pocketrb/mcp/memory_tool.rb +133 -0
  36. data/lib/pocketrb/media/processor.rb +258 -0
  37. data/lib/pocketrb/memory.rb +283 -0
  38. data/lib/pocketrb/planning/manager.rb +159 -0
  39. data/lib/pocketrb/planning/plan.rb +223 -0
  40. data/lib/pocketrb/planning/tool.rb +176 -0
  41. data/lib/pocketrb/providers/anthropic.rb +333 -0
  42. data/lib/pocketrb/providers/base.rb +98 -0
  43. data/lib/pocketrb/providers/claude_cli.rb +412 -0
  44. data/lib/pocketrb/providers/claude_max_proxy.rb +347 -0
  45. data/lib/pocketrb/providers/openrouter.rb +205 -0
  46. data/lib/pocketrb/providers/registry.rb +59 -0
  47. data/lib/pocketrb/providers/ruby_llm_provider.rb +136 -0
  48. data/lib/pocketrb/providers/types.rb +111 -0
  49. data/lib/pocketrb/session/manager.rb +192 -0
  50. data/lib/pocketrb/session/session.rb +204 -0
  51. data/lib/pocketrb/skills/builtin/github/SKILL.md +113 -0
  52. data/lib/pocketrb/skills/builtin/proactive/SKILL.md +101 -0
  53. data/lib/pocketrb/skills/builtin/reflection/SKILL.md +109 -0
  54. data/lib/pocketrb/skills/builtin/tmux/SKILL.md +130 -0
  55. data/lib/pocketrb/skills/builtin/weather/SKILL.md +130 -0
  56. data/lib/pocketrb/skills/create_tool.rb +115 -0
  57. data/lib/pocketrb/skills/loader.rb +164 -0
  58. data/lib/pocketrb/skills/modify_tool.rb +123 -0
  59. data/lib/pocketrb/skills/skill.rb +75 -0
  60. data/lib/pocketrb/tools/background_job_manager.rb +261 -0
  61. data/lib/pocketrb/tools/base.rb +118 -0
  62. data/lib/pocketrb/tools/browser.rb +152 -0
  63. data/lib/pocketrb/tools/browser_advanced.rb +470 -0
  64. data/lib/pocketrb/tools/browser_session.rb +167 -0
  65. data/lib/pocketrb/tools/cron.rb +222 -0
  66. data/lib/pocketrb/tools/edit_file.rb +101 -0
  67. data/lib/pocketrb/tools/exec.rb +194 -0
  68. data/lib/pocketrb/tools/jobs.rb +127 -0
  69. data/lib/pocketrb/tools/list_dir.rb +102 -0
  70. data/lib/pocketrb/tools/memory.rb +167 -0
  71. data/lib/pocketrb/tools/message.rb +70 -0
  72. data/lib/pocketrb/tools/para_memory.rb +264 -0
  73. data/lib/pocketrb/tools/read_file.rb +65 -0
  74. data/lib/pocketrb/tools/registry.rb +160 -0
  75. data/lib/pocketrb/tools/send_file.rb +158 -0
  76. data/lib/pocketrb/tools/think.rb +35 -0
  77. data/lib/pocketrb/tools/web_fetch.rb +150 -0
  78. data/lib/pocketrb/tools/web_search.rb +102 -0
  79. data/lib/pocketrb/tools/write_file.rb +55 -0
  80. data/lib/pocketrb/version.rb +5 -0
  81. data/lib/pocketrb.rb +75 -0
  82. data/pocketrb.gemspec +60 -0
  83. metadata +327 -0
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pocketrb
4
+ class CLI
5
+ # Gateway command - starts all services together
6
+ class Gateway < Base
7
+ desc "gateway", "Start the gateway with all services"
8
+ option :model, type: :string, aliases: "-m", desc: "Model to use"
9
+ option :provider, type: :string, aliases: "-p", desc: "LLM provider"
10
+ option :telegram_token, type: :string, desc: "Telegram bot token"
11
+ option :telegram_users, type: :array, desc: "Allowed Telegram users"
12
+ option :whatsapp_bridge, type: :string, default: "ws://localhost:3001", desc: "WhatsApp bridge URL"
13
+ option :whatsapp_users, type: :array, desc: "Allowed WhatsApp numbers"
14
+ option :heartbeat_interval, type: :numeric, default: 1800, desc: "Heartbeat interval in seconds"
15
+ option :enable_cron, type: :boolean, default: true, desc: "Enable cron service"
16
+ option :enable_heartbeat, type: :boolean, default: true, desc: "Enable heartbeat service"
17
+ option :autonomous, type: :boolean, default: false, desc: "Skip permission prompts (for sandboxed environments)"
18
+
19
+ # Starts the gateway with all configured services (Telegram, WhatsApp, cron, heartbeat)
20
+ # @return [void]
21
+ def call
22
+ setup_logging
23
+ workspace = resolve_workspace
24
+ memory_dir = resolve_memory_dir
25
+
26
+ config = Pocketrb::Config.load(memory_dir)
27
+ config[:model] = options[:model] if options[:model]
28
+ config[:provider] = options[:provider] if options[:provider]
29
+ config[:autonomous] = options[:autonomous] if options[:autonomous]
30
+
31
+ provider = create_provider(config)
32
+ bus = Pocketrb::Bus::MessageBus.new
33
+
34
+ agent_loop = Pocketrb::Agent::Loop.new(
35
+ bus: bus,
36
+ provider: provider,
37
+ workspace: workspace,
38
+ memory_dir: memory_dir,
39
+ model: config[:model],
40
+ max_iterations: config[:max_iterations]
41
+ )
42
+
43
+ say "Starting Pocketrb Gateway", :green
44
+ say "Provider: #{config[:provider]}/#{config[:model]}"
45
+ say "Workspace: #{workspace}"
46
+ say "Memory: #{memory_dir}" if memory_dir != workspace
47
+
48
+ channels = []
49
+ services = []
50
+ cron_service = nil
51
+
52
+ # Start Telegram if token provided
53
+ telegram_token = options[:telegram_token] || ENV.fetch("TELEGRAM_BOT_TOKEN", nil)
54
+ if telegram_token
55
+ channels << Pocketrb::Channels::Telegram.new(
56
+ bus: bus,
57
+ token: telegram_token,
58
+ allowed_users: options[:telegram_users]
59
+ )
60
+ say " - Telegram: enabled"
61
+ end
62
+
63
+ # Start WhatsApp if bridge available
64
+ if options[:whatsapp_bridge]
65
+ channels << Pocketrb::Channels::WhatsApp.new(
66
+ bus: bus,
67
+ bridge_url: options[:whatsapp_bridge],
68
+ allowed_users: options[:whatsapp_users]
69
+ )
70
+ say " - WhatsApp: enabled (#{options[:whatsapp_bridge]})"
71
+ end
72
+
73
+ # Start Cron service
74
+ if options[:enable_cron]
75
+ cron_store = memory_dir.join(".pocketrb", "data", "cron", "jobs.json")
76
+ cron_service = Pocketrb::Cron::Service.new(
77
+ store_path: cron_store,
78
+ on_job: ->(job) { handle_cron_job(agent_loop, bus, job) }
79
+ )
80
+ services << cron_service
81
+ # Pass cron_service to tools so agent can manage jobs
82
+ agent_loop.tools.update_context(cron_service: cron_service)
83
+ say " - Cron: enabled"
84
+ end
85
+
86
+ # Start Heartbeat service
87
+ if options[:enable_heartbeat]
88
+ heartbeat_service = Pocketrb::Heartbeat::Service.new(
89
+ workspace: workspace,
90
+ interval: options[:heartbeat_interval],
91
+ on_heartbeat: ->(prompt) { process_heartbeat(agent_loop, prompt) }
92
+ )
93
+ services << heartbeat_service
94
+ say " - Heartbeat: enabled (#{options[:heartbeat_interval]}s)"
95
+ end
96
+
97
+ # Set up status context for /status command on Telegram channels
98
+ status_context = {
99
+ provider: provider,
100
+ model: config[:model],
101
+ sessions: agent_loop.sessions,
102
+ memory_dir: memory_dir,
103
+ cron_service: cron_service
104
+ }
105
+ channels.each do |ch|
106
+ ch.status_context = status_context if ch.respond_to?(:status_context=)
107
+ end
108
+
109
+ say "\nPress Ctrl+C to stop\n"
110
+
111
+ Async do
112
+ # Start agent loop
113
+ agent_loop.run
114
+
115
+ # Start all channels
116
+ channels.each(&:run)
117
+
118
+ # Start all services
119
+ services.each(&:start)
120
+
121
+ # Keep running
122
+ sleep
123
+ end
124
+ rescue Interrupt
125
+ say "\nShutting down gateway...", :yellow
126
+ services.each(&:stop)
127
+ end
128
+
129
+ default_task :call
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pocketrb
4
+ class CLI
5
+ # Init command - initializes a new Pocketrb workspace
6
+ class Init < Base
7
+ desc "init", "Initialize a new Pocketrb workspace"
8
+ # Initializes a new Pocketrb workspace with config and default structure
9
+ # @return [void]
10
+ def call
11
+ workspace = resolve_workspace
12
+ config_dir = workspace.join(".pocketrb")
13
+
14
+ if config_dir.exist?
15
+ say "Workspace already initialized at #{workspace}", :yellow
16
+ return
17
+ end
18
+
19
+ FileUtils.mkdir_p(config_dir)
20
+ FileUtils.mkdir_p(workspace.join("skills"))
21
+
22
+ Pocketrb::Config.new(workspace: workspace).save!
23
+
24
+ # Create default TOOLS.md
25
+ tools_file = workspace.join("TOOLS.md")
26
+ File.write(tools_file, default_tools_content) unless tools_file.exist?
27
+
28
+ say "Initialized Pocketrb workspace at #{workspace}", :green
29
+ say " - Created .pocketrb/config.yml"
30
+ say " - Created skills/"
31
+ say "\nNext steps:"
32
+ say " 1. Set your API key: export ANTHROPIC_API_KEY=your-key"
33
+ say " 2. Start chatting: pocketrb chat"
34
+ end
35
+
36
+ default_task :call
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pocketrb
4
+ class CLI
5
+ # Plans command - lists active execution plans
6
+ class Plans < Base
7
+ desc "plans", "List active plans"
8
+ # Lists all active execution plans in the workspace
9
+ # @return [void]
10
+ def call
11
+ workspace = resolve_workspace
12
+ manager = Pocketrb::Planning::Manager.new(workspace: workspace)
13
+
14
+ plans = manager.list_plans
15
+ if plans.empty?
16
+ say "No plans found", :yellow
17
+ return
18
+ end
19
+
20
+ plans.each do |plan|
21
+ say "\n#{plan.to_markdown}"
22
+ end
23
+ end
24
+
25
+ default_task :call
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pocketrb
4
+ class CLI
5
+ # Skills command - lists available skills from workspace
6
+ class Skills < Base
7
+ desc "skills", "List available skills"
8
+ # Lists all available skills from the workspace skills directory
9
+ # @return [void]
10
+ def call
11
+ workspace = resolve_workspace
12
+ loader = Pocketrb::Skills::Loader.new(workspace: workspace)
13
+
14
+ skills = loader.list_skills
15
+ if skills.empty?
16
+ say "No skills found in #{workspace}/skills/", :yellow
17
+ return
18
+ end
19
+
20
+ say "Available skills:"
21
+ skills.each do |skill|
22
+ flags = []
23
+ flags << "always" if skill.always?
24
+ flags << "triggers: #{skill.triggers.join(", ")}" if skill.triggers.any?
25
+
26
+ flag_str = flags.any? ? " (#{flags.join(", ")})" : ""
27
+ say " - #{skill.name}: #{skill.description}#{flag_str}"
28
+ end
29
+ end
30
+
31
+ default_task :call
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pocketrb
4
+ class CLI
5
+ # Start command - continuous mode with CLI channel
6
+ class Start < Base
7
+ desc "start", "Start the agent in continuous mode"
8
+ option :model, type: :string, aliases: "-m", desc: "Model to use"
9
+ option :provider, type: :string, aliases: "-p", desc: "LLM provider (anthropic, openrouter)"
10
+ option :channel, type: :string, aliases: "-c", default: "cli", desc: "Channel to connect to"
11
+
12
+ # Starts the agent in continuous mode with CLI channel
13
+ # @return [void]
14
+ def call
15
+ setup_logging
16
+ workspace = resolve_workspace
17
+ memory_dir = resolve_memory_dir
18
+
19
+ config = Pocketrb::Config.load(memory_dir)
20
+ config[:model] = options[:model] if options[:model]
21
+ config[:provider] = options[:provider] if options[:provider]
22
+
23
+ provider = create_provider(config)
24
+ bus = Pocketrb::Bus::MessageBus.new
25
+
26
+ agent_loop = Pocketrb::Agent::Loop.new(
27
+ bus: bus,
28
+ provider: provider,
29
+ workspace: workspace,
30
+ memory_dir: memory_dir,
31
+ model: config[:model],
32
+ max_iterations: config[:max_iterations],
33
+ mcp_endpoint: config[:mcp_endpoint]
34
+ )
35
+
36
+ say "Pocketrb started with #{config[:provider]}/#{config[:model]}", :green
37
+ say "Workspace: #{workspace}"
38
+ say "Memory: #{memory_dir}" if memory_dir != workspace
39
+ say "Press Ctrl+C to stop\n"
40
+
41
+ # Start CLI channel
42
+ channel = Pocketrb::Channels::CLI.new(bus: bus)
43
+
44
+ Async do
45
+ agent_loop.run
46
+ channel.run
47
+ end
48
+ rescue Interrupt
49
+ say "\nShutting down...", :yellow
50
+ end
51
+
52
+ default_task :call
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pocketrb
4
+ class CLI
5
+ # Telegram command - runs agent as a Telegram bot
6
+ class Telegram < Base
7
+ desc "telegram", "Run as a Telegram bot"
8
+ option :model, type: :string, aliases: "-m", desc: "Model to use"
9
+ option :provider, type: :string, aliases: "-p", desc: "LLM provider"
10
+ option :token, type: :string, aliases: "-t", desc: "Telegram bot token (or TELEGRAM_BOT_TOKEN env)"
11
+ option :allowed_users, type: :array, aliases: "-u", desc: "Allowed usernames or user IDs"
12
+ option :enable_cron, type: :boolean, default: true, desc: "Enable cron/scheduling service"
13
+ option :autonomous, type: :boolean, default: false, desc: "Skip permission prompts (for sandboxed environments)"
14
+
15
+ # Runs the agent as a Telegram bot
16
+ # @return [void]
17
+ def call
18
+ setup_logging
19
+ workspace = resolve_workspace
20
+ memory_dir = resolve_memory_dir
21
+
22
+ token = options[:token] || ENV.fetch("TELEGRAM_BOT_TOKEN", nil)
23
+ unless token
24
+ say "Error: Telegram bot token required", :red
25
+ say "Set TELEGRAM_BOT_TOKEN env var or use --token", :yellow
26
+ exit 1
27
+ end
28
+
29
+ config = Pocketrb::Config.load(memory_dir)
30
+ config[:model] = options[:model] if options[:model]
31
+ config[:provider] = options[:provider] if options[:provider]
32
+ config[:autonomous] = options[:autonomous] if options[:autonomous]
33
+
34
+ provider = create_provider(config)
35
+ bus = Pocketrb::Bus::MessageBus.new
36
+
37
+ agent_loop = Pocketrb::Agent::Loop.new(
38
+ bus: bus,
39
+ provider: provider,
40
+ workspace: workspace,
41
+ memory_dir: memory_dir,
42
+ model: config[:model],
43
+ max_iterations: config[:max_iterations]
44
+ )
45
+
46
+ # Enable cron service for proactive scheduling
47
+ cron_service = nil
48
+ if options[:enable_cron]
49
+ cron_store = memory_dir.join(".pocketrb", "data", "cron", "jobs.json")
50
+ cron_service = Pocketrb::Cron::Service.new(
51
+ store_path: cron_store,
52
+ on_job: ->(job) { handle_cron_job(agent_loop, bus, job) }
53
+ )
54
+ agent_loop.tools.update_context(cron_service: cron_service)
55
+ end
56
+
57
+ say "Starting Pocketrb Telegram Bot", :green
58
+ say "Provider: #{config[:provider]}/#{config[:model]}"
59
+ say "Workspace: #{workspace}"
60
+ say "Memory: #{memory_dir}" if memory_dir != workspace
61
+ say "Cron: #{options[:enable_cron] ? "enabled" : "disabled"}"
62
+ say "Autonomous: #{options[:autonomous] ? "yes (claude_cli only)" : "no"}" if options[:autonomous]
63
+ say "Press Ctrl+C to stop\n"
64
+
65
+ channel = Pocketrb::Channels::Telegram.new(
66
+ bus: bus,
67
+ token: token,
68
+ allowed_users: options[:allowed_users]
69
+ )
70
+
71
+ # Set up status context for /status command
72
+ channel.status_context = {
73
+ provider: provider,
74
+ model: config[:model],
75
+ sessions: agent_loop.sessions,
76
+ memory_dir: memory_dir,
77
+ cron_service: cron_service
78
+ }
79
+
80
+ Async do
81
+ agent_loop.run
82
+ channel.run
83
+ cron_service&.start
84
+ end
85
+ rescue Interrupt
86
+ say "\nShutting down Telegram bot...", :yellow
87
+ cron_service&.stop
88
+ end
89
+
90
+ default_task :call
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pocketrb
4
+ class CLI
5
+ # Version command - displays current Pocketrb version
6
+ class Version < Base
7
+ desc "version", "Show version"
8
+ # Displays the current Pocketrb version
9
+ # @return [void]
10
+ def call
11
+ say "Pocketrb #{Pocketrb::VERSION}"
12
+ end
13
+
14
+ # Thor doesn't support default task name, so alias it
15
+ default_task :call
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pocketrb
4
+ class CLI
5
+ # WhatsApp command - runs agent as a WhatsApp bot
6
+ class WhatsApp < Base
7
+ desc "whatsapp", "Run as a WhatsApp bot (requires Node.js bridge)"
8
+ option :model, type: :string, aliases: "-m", desc: "Model to use"
9
+ option :provider, type: :string, aliases: "-p", desc: "LLM provider"
10
+ option :bridge_url, type: :string, default: "ws://localhost:3001", desc: "WhatsApp bridge WebSocket URL"
11
+ option :allowed_users, type: :array, aliases: "-u", desc: "Allowed phone numbers"
12
+
13
+ # Runs the agent as a WhatsApp bot using a WebSocket bridge
14
+ # @return [void]
15
+ def call
16
+ setup_logging
17
+ workspace = resolve_workspace
18
+ memory_dir = resolve_memory_dir
19
+
20
+ config = Pocketrb::Config.load(memory_dir)
21
+ config[:model] = options[:model] if options[:model]
22
+ config[:provider] = options[:provider] if options[:provider]
23
+
24
+ provider = create_provider(config)
25
+ bus = Pocketrb::Bus::MessageBus.new
26
+
27
+ agent_loop = Pocketrb::Agent::Loop.new(
28
+ bus: bus,
29
+ provider: provider,
30
+ workspace: workspace,
31
+ memory_dir: memory_dir,
32
+ model: config[:model],
33
+ max_iterations: config[:max_iterations]
34
+ )
35
+
36
+ say "Starting Pocketrb WhatsApp Bot", :green
37
+ say "Provider: #{config[:provider]}/#{config[:model]}"
38
+ say "Bridge: #{options[:bridge_url]}"
39
+ say "Workspace: #{workspace}"
40
+ say "Memory: #{memory_dir}" if memory_dir != workspace
41
+ say "Press Ctrl+C to stop\n"
42
+
43
+ channel = Pocketrb::Channels::WhatsApp.new(
44
+ bus: bus,
45
+ bridge_url: options[:bridge_url],
46
+ allowed_users: options[:allowed_users]
47
+ )
48
+
49
+ Async do
50
+ agent_loop.run
51
+ channel.run
52
+ end
53
+ rescue Interrupt
54
+ say "\nShutting down WhatsApp bot...", :yellow
55
+ end
56
+
57
+ default_task :call
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+
5
+ # Main namespace for Pocketrb gem
6
+ module Pocketrb
7
+ # Command-line interface
8
+ class CLI < Thor
9
+ include Thor::Actions
10
+
11
+ # Configures Thor to exit with error status on command failure
12
+ # @return [Boolean] true to exit on failure
13
+ def self.exit_on_failure?
14
+ true
15
+ end
16
+
17
+ # Global options available to all commands
18
+ class_option :workspace, type: :string, aliases: "-w",
19
+ desc: "Workspace directory for file access (default: current directory)"
20
+ class_option :memory_dir, type: :string, aliases: "-M",
21
+ desc: "Memory/persona directory (default: same as workspace)"
22
+ class_option :verbose, type: :boolean, aliases: "-v",
23
+ desc: "Enable verbose output"
24
+ class_option :quiet, type: :boolean, aliases: "-q",
25
+ desc: "Suppress non-essential output"
26
+
27
+ # Register subcommands
28
+ desc "config SUBCOMMAND", "Manage configuration"
29
+ subcommand "config", CLI::Config
30
+
31
+ desc "cron SUBCOMMAND", "Manage scheduled jobs"
32
+ subcommand "cron", CLI::Cron
33
+
34
+ # Register individual commands by delegating to their classes
35
+ desc "version", "Show version"
36
+ # Displays the current Pocketrb version
37
+ # @return [void]
38
+ def version
39
+ invoke CLI::Version, :call, [], options
40
+ end
41
+
42
+ desc "skills", "List available skills"
43
+ # Lists available skills from the workspace
44
+ # @return [void]
45
+ def skills
46
+ invoke CLI::Skills, :call, [], options
47
+ end
48
+
49
+ desc "plans", "List active plans"
50
+ # Lists all active execution plans
51
+ # @return [void]
52
+ def plans
53
+ invoke CLI::Plans, :call, [], options
54
+ end
55
+
56
+ desc "init", "Initialize a new Pocketrb workspace"
57
+ # Initializes a new Pocketrb workspace with configuration
58
+ # @return [void]
59
+ def init
60
+ invoke CLI::Init, :call, [], options
61
+ end
62
+
63
+ desc "chat", "Interactive chat mode (single session)"
64
+ option :model, type: :string, aliases: "-m", desc: "Model to use"
65
+ option :provider, type: :string, aliases: "-p", desc: "LLM provider"
66
+ option :system_prompt, type: :string, aliases: "-s", desc: "Custom system prompt"
67
+ # Starts an interactive chat session
68
+ # @return [void]
69
+ def chat
70
+ invoke CLI::Chat, :call, [], options
71
+ end
72
+
73
+ desc "start", "Start the agent in continuous mode"
74
+ option :model, type: :string, aliases: "-m", desc: "Model to use"
75
+ option :provider, type: :string, aliases: "-p", desc: "LLM provider (anthropic, openrouter)"
76
+ option :channel, type: :string, aliases: "-c", default: "cli", desc: "Channel to connect to"
77
+ # Starts the agent in continuous mode with CLI channel
78
+ # @return [void]
79
+ def start
80
+ invoke CLI::Start, :call, [], options
81
+ end
82
+
83
+ desc "telegram", "Run as a Telegram bot"
84
+ option :model, type: :string, aliases: "-m", desc: "Model to use"
85
+ option :provider, type: :string, aliases: "-p", desc: "LLM provider"
86
+ option :token, type: :string, aliases: "-t", desc: "Telegram bot token (or TELEGRAM_BOT_TOKEN env)"
87
+ option :allowed_users, type: :array, aliases: "-u", desc: "Allowed usernames or user IDs"
88
+ option :enable_cron, type: :boolean, default: true, desc: "Enable cron/scheduling service"
89
+ option :autonomous, type: :boolean, default: false, desc: "Skip permission prompts (for sandboxed environments)"
90
+ # Runs the agent as a Telegram bot
91
+ # @return [void]
92
+ def telegram
93
+ invoke CLI::Telegram, :call, [], options
94
+ end
95
+
96
+ desc "whatsapp", "Run as a WhatsApp bot (requires Node.js bridge)"
97
+ option :model, type: :string, aliases: "-m", desc: "Model to use"
98
+ option :provider, type: :string, aliases: "-p", desc: "LLM provider"
99
+ option :bridge_url, type: :string, default: "ws://localhost:3001", desc: "WhatsApp bridge WebSocket URL"
100
+ option :allowed_users, type: :array, aliases: "-u", desc: "Allowed phone numbers"
101
+ # Runs the agent as a WhatsApp bot
102
+ # @return [void]
103
+ def whatsapp
104
+ invoke CLI::WhatsApp, :call, [], options
105
+ end
106
+
107
+ desc "gateway", "Start the gateway with all services"
108
+ option :model, type: :string, aliases: "-m", desc: "Model to use"
109
+ option :provider, type: :string, aliases: "-p", desc: "LLM provider"
110
+ option :telegram_token, type: :string, desc: "Telegram bot token"
111
+ option :telegram_users, type: :array, desc: "Allowed Telegram users"
112
+ option :whatsapp_bridge, type: :string, default: "ws://localhost:3001", desc: "WhatsApp bridge URL"
113
+ option :whatsapp_users, type: :array, desc: "Allowed WhatsApp numbers"
114
+ option :heartbeat_interval, type: :numeric, default: 1800, desc: "Heartbeat interval in seconds"
115
+ option :enable_cron, type: :boolean, default: true, desc: "Enable cron service"
116
+ option :enable_heartbeat, type: :boolean, default: true, desc: "Enable heartbeat service"
117
+ option :autonomous, type: :boolean, default: false, desc: "Skip permission prompts (for sandboxed environments)"
118
+ # Starts the gateway with all configured services
119
+ # @return [void]
120
+ def gateway
121
+ invoke CLI::Gateway, :call, [], options
122
+ end
123
+ end
124
+ end