claude_swarm 1.0.1 → 1.0.2
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.
- checksums.yaml +4 -4
- data/.claude/commands/release.md +1 -1
- data/.claude/hooks/lint-code-files.rb +65 -0
- data/.rubocop.yml +22 -2
- data/CHANGELOG.md +14 -1
- data/CLAUDE.md +1 -1
- data/CONTRIBUTING.md +69 -0
- data/README.md +27 -2
- data/Rakefile +71 -3
- data/analyze_coverage.rb +94 -0
- data/docs/v2/CHANGELOG.swarm_cli.md +43 -0
- data/docs/v2/CHANGELOG.swarm_memory.md +379 -0
- data/docs/v2/CHANGELOG.swarm_sdk.md +362 -0
- data/docs/v2/README.md +308 -0
- data/docs/v2/guides/claude-code-agents.md +262 -0
- data/docs/v2/guides/complete-tutorial.md +3088 -0
- data/docs/v2/guides/getting-started.md +1456 -0
- data/docs/v2/guides/memory-adapters.md +998 -0
- data/docs/v2/guides/plugins.md +816 -0
- data/docs/v2/guides/quick-start-cli.md +1745 -0
- data/docs/v2/guides/rails-integration.md +1902 -0
- data/docs/v2/guides/swarm-memory.md +599 -0
- data/docs/v2/reference/cli.md +729 -0
- data/docs/v2/reference/ruby-dsl.md +2154 -0
- data/docs/v2/reference/yaml.md +1835 -0
- data/docs-team-swarm.yml +2222 -0
- data/examples/learning-assistant/assistant.md +7 -0
- data/examples/learning-assistant/example-memories/concept-example.md +90 -0
- data/examples/learning-assistant/example-memories/experience-example.md +66 -0
- data/examples/learning-assistant/example-memories/fact-example.md +76 -0
- data/examples/learning-assistant/example-memories/memory-index.md +78 -0
- data/examples/learning-assistant/example-memories/skill-example.md +168 -0
- data/examples/learning-assistant/learning_assistant.rb +34 -0
- data/examples/learning-assistant/learning_assistant.yml +20 -0
- data/examples/v2/dsl/01_basic.rb +44 -0
- data/examples/v2/dsl/02_core_parameters.rb +59 -0
- data/examples/v2/dsl/03_capabilities.rb +71 -0
- data/examples/v2/dsl/04_llm_parameters.rb +56 -0
- data/examples/v2/dsl/05_advanced_flags.rb +73 -0
- data/examples/v2/dsl/06_permissions.rb +80 -0
- data/examples/v2/dsl/07_mcp_server.rb +62 -0
- data/examples/v2/dsl/08_swarm_hooks.rb +53 -0
- data/examples/v2/dsl/09_agent_hooks.rb +67 -0
- data/examples/v2/dsl/10_all_agents_hooks.rb +67 -0
- data/examples/v2/dsl/11_delegation.rb +60 -0
- data/examples/v2/dsl/12_complete_integration.rb +137 -0
- data/examples/v2/file_tools_swarm.yml +102 -0
- data/examples/v2/hooks/01_basic_hooks.rb +133 -0
- data/examples/v2/hooks/02_usage_tracking.rb +201 -0
- data/examples/v2/hooks/03_production_monitoring.rb +429 -0
- data/examples/v2/hooks/agent_stop_exit_0.yml +21 -0
- data/examples/v2/hooks/agent_stop_exit_1.yml +21 -0
- data/examples/v2/hooks/agent_stop_exit_2.yml +26 -0
- data/examples/v2/hooks/multiple_hooks_all_pass.yml +37 -0
- data/examples/v2/hooks/multiple_hooks_first_fails.yml +37 -0
- data/examples/v2/hooks/multiple_hooks_second_fails.yml +37 -0
- data/examples/v2/hooks/multiple_hooks_warnings.yml +37 -0
- data/examples/v2/hooks/post_tool_use_exit_0.yml +24 -0
- data/examples/v2/hooks/post_tool_use_exit_1.yml +24 -0
- data/examples/v2/hooks/post_tool_use_exit_2.yml +24 -0
- data/examples/v2/hooks/post_tool_use_multi_matcher_exit_0.yml +26 -0
- data/examples/v2/hooks/post_tool_use_multi_matcher_exit_1.yml +26 -0
- data/examples/v2/hooks/post_tool_use_multi_matcher_exit_2.yml +26 -0
- data/examples/v2/hooks/pre_tool_use_exit_0.yml +24 -0
- data/examples/v2/hooks/pre_tool_use_exit_1.yml +24 -0
- data/examples/v2/hooks/pre_tool_use_exit_2.yml +24 -0
- data/examples/v2/hooks/pre_tool_use_multi_matcher_exit_0.yml +26 -0
- data/examples/v2/hooks/pre_tool_use_multi_matcher_exit_1.yml +26 -0
- data/examples/v2/hooks/pre_tool_use_multi_matcher_exit_2.yml +27 -0
- data/examples/v2/hooks/swarm_summary.sh +44 -0
- data/examples/v2/hooks/user_prompt_exit_0.yml +21 -0
- data/examples/v2/hooks/user_prompt_exit_1.yml +21 -0
- data/examples/v2/hooks/user_prompt_exit_2.yml +21 -0
- data/examples/v2/hooks/validate_bash.rb +59 -0
- data/examples/v2/multi_directory_permissions.yml +221 -0
- data/examples/v2/node_context_demo.rb +127 -0
- data/examples/v2/node_workflow.rb +173 -0
- data/examples/v2/path_resolution_demo.rb +216 -0
- data/examples/v2/simple-swarm-v2.rb +90 -0
- data/examples/v2/simple-swarm-v2.yml +62 -0
- data/examples/v2/swarm.yml +71 -0
- data/examples/v2/swarm_with_hooks.yml +61 -0
- data/examples/v2/swarm_with_hooks_simple.yml +25 -0
- data/examples/v2/think_tool_demo.rb +62 -0
- data/exe/swarm +6 -0
- data/lib/claude_swarm/claude_mcp_server.rb +0 -6
- data/lib/claude_swarm/cli.rb +10 -3
- data/lib/claude_swarm/commands/ps.rb +19 -20
- data/lib/claude_swarm/commands/show.rb +1 -1
- data/lib/claude_swarm/configuration.rb +10 -12
- data/lib/claude_swarm/mcp_generator.rb +10 -1
- data/lib/claude_swarm/orchestrator.rb +73 -49
- data/lib/claude_swarm/system_utils.rb +37 -11
- data/lib/claude_swarm/version.rb +1 -1
- data/lib/claude_swarm/worktree_manager.rb +1 -0
- data/lib/claude_swarm/yaml_loader.rb +22 -0
- data/lib/claude_swarm.rb +6 -2
- data/lib/swarm_cli/cli.rb +201 -0
- data/lib/swarm_cli/command_registry.rb +61 -0
- data/lib/swarm_cli/commands/mcp_serve.rb +130 -0
- data/lib/swarm_cli/commands/mcp_tools.rb +148 -0
- data/lib/swarm_cli/commands/migrate.rb +55 -0
- data/lib/swarm_cli/commands/run.rb +173 -0
- data/lib/swarm_cli/config_loader.rb +97 -0
- data/lib/swarm_cli/formatters/human_formatter.rb +711 -0
- data/lib/swarm_cli/formatters/json_formatter.rb +51 -0
- data/lib/swarm_cli/interactive_repl.rb +918 -0
- data/lib/swarm_cli/mcp_serve_options.rb +44 -0
- data/lib/swarm_cli/mcp_tools_options.rb +59 -0
- data/lib/swarm_cli/migrate_options.rb +54 -0
- data/lib/swarm_cli/migrator.rb +132 -0
- data/lib/swarm_cli/options.rb +151 -0
- data/lib/swarm_cli/ui/components/agent_badge.rb +33 -0
- data/lib/swarm_cli/ui/components/content_block.rb +120 -0
- data/lib/swarm_cli/ui/components/divider.rb +57 -0
- data/lib/swarm_cli/ui/components/panel.rb +62 -0
- data/lib/swarm_cli/ui/components/usage_stats.rb +70 -0
- data/lib/swarm_cli/ui/formatters/cost.rb +49 -0
- data/lib/swarm_cli/ui/formatters/number.rb +58 -0
- data/lib/swarm_cli/ui/formatters/text.rb +77 -0
- data/lib/swarm_cli/ui/formatters/time.rb +73 -0
- data/lib/swarm_cli/ui/icons.rb +59 -0
- data/lib/swarm_cli/ui/renderers/event_renderer.rb +188 -0
- data/lib/swarm_cli/ui/state/agent_color_cache.rb +45 -0
- data/lib/swarm_cli/ui/state/depth_tracker.rb +40 -0
- data/lib/swarm_cli/ui/state/spinner_manager.rb +170 -0
- data/lib/swarm_cli/ui/state/usage_tracker.rb +62 -0
- data/lib/swarm_cli/version.rb +5 -0
- data/lib/swarm_cli.rb +44 -0
- data/lib/swarm_memory/adapters/base.rb +141 -0
- data/lib/swarm_memory/adapters/filesystem_adapter.rb +845 -0
- data/lib/swarm_memory/chat_extension.rb +34 -0
- data/lib/swarm_memory/cli/commands.rb +306 -0
- data/lib/swarm_memory/core/entry.rb +37 -0
- data/lib/swarm_memory/core/frontmatter_parser.rb +108 -0
- data/lib/swarm_memory/core/metadata_extractor.rb +68 -0
- data/lib/swarm_memory/core/path_normalizer.rb +75 -0
- data/lib/swarm_memory/core/semantic_index.rb +244 -0
- data/lib/swarm_memory/core/storage.rb +288 -0
- data/lib/swarm_memory/core/storage_read_tracker.rb +63 -0
- data/lib/swarm_memory/dsl/builder_extension.rb +40 -0
- data/lib/swarm_memory/dsl/memory_config.rb +113 -0
- data/lib/swarm_memory/embeddings/embedder.rb +36 -0
- data/lib/swarm_memory/embeddings/informers_embedder.rb +152 -0
- data/lib/swarm_memory/errors.rb +21 -0
- data/lib/swarm_memory/integration/cli_registration.rb +30 -0
- data/lib/swarm_memory/integration/configuration.rb +43 -0
- data/lib/swarm_memory/integration/registration.rb +31 -0
- data/lib/swarm_memory/integration/sdk_plugin.rb +531 -0
- data/lib/swarm_memory/optimization/analyzer.rb +244 -0
- data/lib/swarm_memory/optimization/defragmenter.rb +863 -0
- data/lib/swarm_memory/prompts/memory.md.erb +109 -0
- data/lib/swarm_memory/prompts/memory_assistant.md.erb +181 -0
- data/lib/swarm_memory/prompts/memory_researcher.md.erb +281 -0
- data/lib/swarm_memory/prompts/memory_retrieval.md.erb +78 -0
- data/lib/swarm_memory/search/semantic_search.rb +112 -0
- data/lib/swarm_memory/search/text_search.rb +42 -0
- data/lib/swarm_memory/search/text_similarity.rb +80 -0
- data/lib/swarm_memory/skills/meta/deep-learning.md +101 -0
- data/lib/swarm_memory/skills/meta/deep-learning.yml +14 -0
- data/lib/swarm_memory/tools/load_skill.rb +313 -0
- data/lib/swarm_memory/tools/memory_defrag.rb +382 -0
- data/lib/swarm_memory/tools/memory_delete.rb +99 -0
- data/lib/swarm_memory/tools/memory_edit.rb +185 -0
- data/lib/swarm_memory/tools/memory_glob.rb +160 -0
- data/lib/swarm_memory/tools/memory_grep.rb +247 -0
- data/lib/swarm_memory/tools/memory_multi_edit.rb +281 -0
- data/lib/swarm_memory/tools/memory_read.rb +123 -0
- data/lib/swarm_memory/tools/memory_write.rb +231 -0
- data/lib/swarm_memory/utils.rb +50 -0
- data/lib/swarm_memory/version.rb +5 -0
- data/lib/swarm_memory.rb +166 -0
- data/lib/swarm_sdk/agent/RETRY_LOGIC.md +127 -0
- data/lib/swarm_sdk/agent/builder.rb +461 -0
- data/lib/swarm_sdk/agent/chat/context_tracker.rb +314 -0
- data/lib/swarm_sdk/agent/chat/hook_integration.rb +372 -0
- data/lib/swarm_sdk/agent/chat/logging_helpers.rb +116 -0
- data/lib/swarm_sdk/agent/chat/system_reminder_injector.rb +152 -0
- data/lib/swarm_sdk/agent/chat.rb +1159 -0
- data/lib/swarm_sdk/agent/context.rb +112 -0
- data/lib/swarm_sdk/agent/context_manager.rb +309 -0
- data/lib/swarm_sdk/agent/definition.rb +556 -0
- data/lib/swarm_sdk/claude_code_agent_adapter.rb +205 -0
- data/lib/swarm_sdk/configuration.rb +296 -0
- data/lib/swarm_sdk/context_compactor/metrics.rb +147 -0
- data/lib/swarm_sdk/context_compactor/token_counter.rb +106 -0
- data/lib/swarm_sdk/context_compactor.rb +340 -0
- data/lib/swarm_sdk/hooks/adapter.rb +359 -0
- data/lib/swarm_sdk/hooks/context.rb +197 -0
- data/lib/swarm_sdk/hooks/definition.rb +80 -0
- data/lib/swarm_sdk/hooks/error.rb +29 -0
- data/lib/swarm_sdk/hooks/executor.rb +146 -0
- data/lib/swarm_sdk/hooks/registry.rb +147 -0
- data/lib/swarm_sdk/hooks/result.rb +150 -0
- data/lib/swarm_sdk/hooks/shell_executor.rb +254 -0
- data/lib/swarm_sdk/hooks/tool_call.rb +35 -0
- data/lib/swarm_sdk/hooks/tool_result.rb +62 -0
- data/lib/swarm_sdk/log_collector.rb +51 -0
- data/lib/swarm_sdk/log_stream.rb +69 -0
- data/lib/swarm_sdk/markdown_parser.rb +75 -0
- data/lib/swarm_sdk/model_aliases.json +5 -0
- data/lib/swarm_sdk/models.json +1 -0
- data/lib/swarm_sdk/models.rb +120 -0
- data/lib/swarm_sdk/node/agent_config.rb +49 -0
- data/lib/swarm_sdk/node/builder.rb +439 -0
- data/lib/swarm_sdk/node/transformer_executor.rb +248 -0
- data/lib/swarm_sdk/node_context.rb +170 -0
- data/lib/swarm_sdk/node_orchestrator.rb +384 -0
- data/lib/swarm_sdk/permissions/config.rb +239 -0
- data/lib/swarm_sdk/permissions/error_formatter.rb +121 -0
- data/lib/swarm_sdk/permissions/path_matcher.rb +35 -0
- data/lib/swarm_sdk/permissions/validator.rb +173 -0
- data/lib/swarm_sdk/permissions_builder.rb +122 -0
- data/lib/swarm_sdk/plugin.rb +147 -0
- data/lib/swarm_sdk/plugin_registry.rb +101 -0
- data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +243 -0
- data/lib/swarm_sdk/providers/openai_with_responses.rb +582 -0
- data/lib/swarm_sdk/result.rb +97 -0
- data/lib/swarm_sdk/swarm/agent_initializer.rb +334 -0
- data/lib/swarm_sdk/swarm/all_agents_builder.rb +140 -0
- data/lib/swarm_sdk/swarm/builder.rb +586 -0
- data/lib/swarm_sdk/swarm/mcp_configurator.rb +151 -0
- data/lib/swarm_sdk/swarm/tool_configurator.rb +419 -0
- data/lib/swarm_sdk/swarm.rb +982 -0
- data/lib/swarm_sdk/tools/bash.rb +274 -0
- data/lib/swarm_sdk/tools/clock.rb +44 -0
- data/lib/swarm_sdk/tools/delegate.rb +164 -0
- data/lib/swarm_sdk/tools/document_converters/base_converter.rb +83 -0
- data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +99 -0
- data/lib/swarm_sdk/tools/document_converters/html_converter.rb +101 -0
- data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +78 -0
- data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +194 -0
- data/lib/swarm_sdk/tools/edit.rb +150 -0
- data/lib/swarm_sdk/tools/glob.rb +158 -0
- data/lib/swarm_sdk/tools/grep.rb +228 -0
- data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +43 -0
- data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +163 -0
- data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +65 -0
- data/lib/swarm_sdk/tools/multi_edit.rb +232 -0
- data/lib/swarm_sdk/tools/path_resolver.rb +43 -0
- data/lib/swarm_sdk/tools/read.rb +251 -0
- data/lib/swarm_sdk/tools/registry.rb +93 -0
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +96 -0
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +76 -0
- data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +91 -0
- data/lib/swarm_sdk/tools/stores/read_tracker.rb +61 -0
- data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +224 -0
- data/lib/swarm_sdk/tools/stores/storage.rb +148 -0
- data/lib/swarm_sdk/tools/stores/todo_manager.rb +65 -0
- data/lib/swarm_sdk/tools/think.rb +95 -0
- data/lib/swarm_sdk/tools/todo_write.rb +216 -0
- data/lib/swarm_sdk/tools/web_fetch.rb +261 -0
- data/lib/swarm_sdk/tools/write.rb +117 -0
- data/lib/swarm_sdk/utils.rb +50 -0
- data/lib/swarm_sdk/version.rb +5 -0
- data/lib/swarm_sdk.rb +157 -0
- data/llm.v2.txt +13407 -0
- data/rubocop/cop/security/no_reflection_methods.rb +47 -0
- data/rubocop/cop/security/no_ruby_llm_logger.rb +32 -0
- data/swarm_cli.gemspec +57 -0
- data/swarm_memory.gemspec +28 -0
- data/swarm_sdk.gemspec +41 -0
- data/team.yml +1 -1
- data/team_full.yml +1875 -0
- data/{team_v2.yml → team_sdk.yml} +121 -52
- metadata +247 -4
- data/EXAMPLES.md +0 -164
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SwarmCLI
|
|
4
|
+
module Commands
|
|
5
|
+
# Run command executes a swarm with the given configuration and prompt.
|
|
6
|
+
#
|
|
7
|
+
# Supports both YAML (.yml, .yaml) and Ruby DSL (.rb) configuration files.
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# swarm run config.yml -p "Build a REST API"
|
|
11
|
+
# swarm run config.rb -p "Build a REST API"
|
|
12
|
+
# echo "Build a REST API" | swarm run config.yml
|
|
13
|
+
# swarm run config.yml -p "Task" --output-format json
|
|
14
|
+
#
|
|
15
|
+
class Run
|
|
16
|
+
attr_reader :options
|
|
17
|
+
|
|
18
|
+
def initialize(options)
|
|
19
|
+
@options = options
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def execute
|
|
23
|
+
# Validate options
|
|
24
|
+
options.validate!
|
|
25
|
+
|
|
26
|
+
# Load swarm configuration
|
|
27
|
+
swarm = load_swarm
|
|
28
|
+
|
|
29
|
+
# Check if interactive mode (no prompt provided and stdin is a tty)
|
|
30
|
+
if options.interactive_mode?
|
|
31
|
+
run_interactive_mode(swarm)
|
|
32
|
+
else
|
|
33
|
+
run_non_interactive_mode(swarm)
|
|
34
|
+
end
|
|
35
|
+
rescue SwarmSDK::ConfigurationError, SwarmSDK::AgentNotFoundError => e
|
|
36
|
+
# Configuration errors - show user-friendly message
|
|
37
|
+
handle_error(e, formatter: create_formatter)
|
|
38
|
+
exit(1)
|
|
39
|
+
rescue SwarmCLI::ExecutionError => e
|
|
40
|
+
# CLI-specific errors (e.g., missing prompt)
|
|
41
|
+
handle_error(e, formatter: create_formatter)
|
|
42
|
+
exit(1)
|
|
43
|
+
rescue Interrupt
|
|
44
|
+
# User cancelled (Ctrl+C)
|
|
45
|
+
$stderr.puts "\n\nExecution cancelled by user"
|
|
46
|
+
exit(130)
|
|
47
|
+
rescue StandardError => e
|
|
48
|
+
# Unexpected errors
|
|
49
|
+
handle_error(e, formatter: create_formatter)
|
|
50
|
+
exit(1)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def run_interactive_mode(swarm)
|
|
56
|
+
# Launch the interactive REPL with optional initial message
|
|
57
|
+
initial_message = options.initial_message
|
|
58
|
+
repl = SwarmCLI::InteractiveREPL.new(
|
|
59
|
+
swarm: swarm,
|
|
60
|
+
options: options,
|
|
61
|
+
initial_message: initial_message,
|
|
62
|
+
)
|
|
63
|
+
repl.run
|
|
64
|
+
exit(0)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def run_non_interactive_mode(swarm)
|
|
68
|
+
# Create formatter based on output format
|
|
69
|
+
formatter = create_formatter
|
|
70
|
+
|
|
71
|
+
# Get prompt text
|
|
72
|
+
prompt = options.prompt_text
|
|
73
|
+
|
|
74
|
+
# Notify formatter of start
|
|
75
|
+
formatter.on_start(
|
|
76
|
+
config_path: options.config_file,
|
|
77
|
+
swarm_name: swarm.name,
|
|
78
|
+
lead_agent: swarm.lead_agent,
|
|
79
|
+
prompt: prompt,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Emit validation warnings before execution
|
|
83
|
+
emit_validation_warnings(swarm, formatter)
|
|
84
|
+
|
|
85
|
+
# Execute swarm with logging
|
|
86
|
+
start_time = Time.now
|
|
87
|
+
result = swarm.execute(prompt) do |log_entry|
|
|
88
|
+
# Skip model warnings - already emitted above
|
|
89
|
+
next if log_entry[:type] == "model_lookup_warning"
|
|
90
|
+
|
|
91
|
+
formatter.on_log(log_entry)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Check for errors
|
|
95
|
+
if result.failure?
|
|
96
|
+
duration = Time.now - start_time
|
|
97
|
+
formatter.on_error(error: result.error, duration: duration)
|
|
98
|
+
exit(1)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Notify formatter of success
|
|
102
|
+
formatter.on_success(result: result)
|
|
103
|
+
|
|
104
|
+
# Exit successfully
|
|
105
|
+
exit(0)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def load_swarm
|
|
109
|
+
config_path = options.config_file
|
|
110
|
+
|
|
111
|
+
ConfigLoader.load(config_path)
|
|
112
|
+
rescue SwarmCLI::ConfigurationError => e
|
|
113
|
+
# ConfigLoader already provides good context
|
|
114
|
+
raise SwarmCLI::ExecutionError, e.message
|
|
115
|
+
rescue SwarmSDK::ConfigurationError => e
|
|
116
|
+
# SDK errors - add context
|
|
117
|
+
raise SwarmCLI::ExecutionError, "Configuration error: #{e.message}"
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def create_formatter
|
|
121
|
+
case options.output_format
|
|
122
|
+
when "json"
|
|
123
|
+
Formatters::JsonFormatter.new
|
|
124
|
+
when "human"
|
|
125
|
+
Formatters::HumanFormatter.new(
|
|
126
|
+
quiet: options.quiet?,
|
|
127
|
+
truncate: options.truncate?,
|
|
128
|
+
verbose: options.verbose?,
|
|
129
|
+
)
|
|
130
|
+
else
|
|
131
|
+
raise SwarmCLI::ExecutionError, "Unknown output format: #{options.output_format}"
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def emit_validation_warnings(swarm, formatter)
|
|
136
|
+
# Setup temporary logging to capture and emit warnings
|
|
137
|
+
SwarmSDK::LogCollector.on_log do |log_entry|
|
|
138
|
+
formatter.on_log(log_entry) if log_entry[:type] == "model_lookup_warning"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
SwarmSDK::LogStream.emitter = SwarmSDK::LogCollector
|
|
142
|
+
|
|
143
|
+
# Emit validation warnings as log events
|
|
144
|
+
swarm.emit_validation_warnings
|
|
145
|
+
|
|
146
|
+
# Clean up
|
|
147
|
+
SwarmSDK::LogCollector.reset!
|
|
148
|
+
SwarmSDK::LogStream.reset!
|
|
149
|
+
rescue StandardError
|
|
150
|
+
# Ignore errors during validation emission
|
|
151
|
+
begin
|
|
152
|
+
SwarmSDK::LogCollector.reset!
|
|
153
|
+
rescue
|
|
154
|
+
nil
|
|
155
|
+
end
|
|
156
|
+
begin
|
|
157
|
+
SwarmSDK::LogStream.reset!
|
|
158
|
+
rescue
|
|
159
|
+
nil
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def handle_error(error, formatter: nil)
|
|
164
|
+
if formatter
|
|
165
|
+
formatter.on_error(error: error)
|
|
166
|
+
else
|
|
167
|
+
# Fallback if formatter not available
|
|
168
|
+
$stderr.puts "Error: #{error.message}"
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SwarmCLI
|
|
4
|
+
# ConfigLoader handles loading swarm configurations from both YAML and Ruby DSL files.
|
|
5
|
+
#
|
|
6
|
+
# Supports:
|
|
7
|
+
# - YAML files (.yml, .yaml) - loaded via SwarmSDK::Swarm.load
|
|
8
|
+
# - Ruby DSL files (.rb) - executed and expected to return a SwarmSDK::Swarm instance
|
|
9
|
+
#
|
|
10
|
+
# @example Load YAML config
|
|
11
|
+
# swarm = ConfigLoader.load("config.yml")
|
|
12
|
+
#
|
|
13
|
+
# @example Load Ruby DSL config
|
|
14
|
+
# swarm = ConfigLoader.load("config.rb")
|
|
15
|
+
#
|
|
16
|
+
class ConfigLoader
|
|
17
|
+
class << self
|
|
18
|
+
# Load a swarm configuration from file (YAML or Ruby DSL)
|
|
19
|
+
#
|
|
20
|
+
# Detects file type by extension:
|
|
21
|
+
# - .yml, .yaml -> Load as YAML using SwarmSDK::Swarm.load
|
|
22
|
+
# - .rb -> Execute as Ruby DSL and expect SwarmSDK::Swarm instance
|
|
23
|
+
#
|
|
24
|
+
# @param path [String, Pathname] Path to configuration file
|
|
25
|
+
# @return [SwarmSDK::Swarm] Configured swarm instance
|
|
26
|
+
# @raise [SwarmCLI::ConfigurationError] If file not found or invalid format
|
|
27
|
+
def load(path)
|
|
28
|
+
path = Pathname.new(path).expand_path
|
|
29
|
+
|
|
30
|
+
unless path.exist?
|
|
31
|
+
raise ConfigurationError, "Configuration file not found: #{path}"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
case path.extname.downcase
|
|
35
|
+
when ".yml", ".yaml"
|
|
36
|
+
load_yaml(path)
|
|
37
|
+
when ".rb"
|
|
38
|
+
load_ruby_dsl(path)
|
|
39
|
+
else
|
|
40
|
+
raise ConfigurationError,
|
|
41
|
+
"Unsupported configuration file format: #{path.extname}. " \
|
|
42
|
+
"Supported formats: .yml, .yaml (YAML), .rb (Ruby DSL)"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
# Load YAML configuration file
|
|
49
|
+
#
|
|
50
|
+
# @param path [Pathname] Path to YAML file
|
|
51
|
+
# @return [SwarmSDK::Swarm] Configured swarm instance
|
|
52
|
+
def load_yaml(path)
|
|
53
|
+
SwarmSDK::Swarm.load(path.to_s)
|
|
54
|
+
rescue SwarmSDK::ConfigurationError => e
|
|
55
|
+
# Re-raise with CLI context
|
|
56
|
+
raise ConfigurationError, "Configuration error in #{path}: #{e.message}"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Load Ruby DSL configuration file
|
|
60
|
+
#
|
|
61
|
+
# Executes the Ruby file in a clean binding and expects it to return
|
|
62
|
+
# a SwarmSDK::Swarm instance. The file should use SwarmSDK.build or
|
|
63
|
+
# create a Swarm instance directly.
|
|
64
|
+
#
|
|
65
|
+
# @param path [Pathname] Path to Ruby DSL file
|
|
66
|
+
# @return [SwarmSDK::Swarm] Configured swarm instance
|
|
67
|
+
# @raise [ConfigurationError] If file doesn't return a Swarm instance
|
|
68
|
+
def load_ruby_dsl(path)
|
|
69
|
+
# Read the file content
|
|
70
|
+
content = path.read
|
|
71
|
+
|
|
72
|
+
# Execute in a clean binding with SwarmSDK available
|
|
73
|
+
# This allows the DSL file to use SwarmSDK.build directly
|
|
74
|
+
result = eval(content, binding, path.to_s, 1) # rubocop:disable Security/Eval
|
|
75
|
+
|
|
76
|
+
# Validate result is a Swarm instance
|
|
77
|
+
unless result.is_a?(SwarmSDK::Swarm)
|
|
78
|
+
raise ConfigurationError,
|
|
79
|
+
"Ruby DSL file must return a SwarmSDK::Swarm instance. " \
|
|
80
|
+
"Got: #{result.class}. " \
|
|
81
|
+
"Use: SwarmSDK.build { ... } or Swarm.new(...)"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
result
|
|
85
|
+
rescue SwarmSDK::ConfigurationError => e
|
|
86
|
+
# Re-raise SDK configuration errors with CLI context
|
|
87
|
+
raise ConfigurationError, "Configuration error in #{path}: #{e.message}"
|
|
88
|
+
rescue SyntaxError => e
|
|
89
|
+
# Ruby syntax errors
|
|
90
|
+
raise ConfigurationError, "Syntax error in #{path}: #{e.message}"
|
|
91
|
+
rescue StandardError => e
|
|
92
|
+
# Other Ruby errors during execution
|
|
93
|
+
raise ConfigurationError, "Error loading #{path}: #{e.message}"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|