swarm_memory 2.1.5 → 2.1.6

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 (182) hide show
  1. checksums.yaml +4 -4
  2. data/lib/swarm_memory/version.rb +1 -1
  3. metadata +5 -184
  4. data/lib/claude_swarm/base_executor.rb +0 -133
  5. data/lib/claude_swarm/claude_code_executor.rb +0 -349
  6. data/lib/claude_swarm/claude_mcp_server.rb +0 -78
  7. data/lib/claude_swarm/cli.rb +0 -697
  8. data/lib/claude_swarm/commands/ps.rb +0 -215
  9. data/lib/claude_swarm/commands/show.rb +0 -139
  10. data/lib/claude_swarm/configuration.rb +0 -373
  11. data/lib/claude_swarm/hooks/session_start_hook.rb +0 -42
  12. data/lib/claude_swarm/json_handler.rb +0 -91
  13. data/lib/claude_swarm/mcp_generator.rb +0 -230
  14. data/lib/claude_swarm/openai/chat_completion.rb +0 -256
  15. data/lib/claude_swarm/openai/executor.rb +0 -256
  16. data/lib/claude_swarm/openai/responses.rb +0 -319
  17. data/lib/claude_swarm/orchestrator.rb +0 -878
  18. data/lib/claude_swarm/process_tracker.rb +0 -78
  19. data/lib/claude_swarm/session_cost_calculator.rb +0 -209
  20. data/lib/claude_swarm/session_path.rb +0 -42
  21. data/lib/claude_swarm/settings_generator.rb +0 -77
  22. data/lib/claude_swarm/system_utils.rb +0 -46
  23. data/lib/claude_swarm/templates/generation_prompt.md.erb +0 -230
  24. data/lib/claude_swarm/tools/reset_session_tool.rb +0 -24
  25. data/lib/claude_swarm/tools/session_info_tool.rb +0 -24
  26. data/lib/claude_swarm/tools/task_tool.rb +0 -63
  27. data/lib/claude_swarm/version.rb +0 -5
  28. data/lib/claude_swarm/worktree_manager.rb +0 -475
  29. data/lib/claude_swarm/yaml_loader.rb +0 -22
  30. data/lib/claude_swarm.rb +0 -67
  31. data/lib/swarm_cli/cli.rb +0 -201
  32. data/lib/swarm_cli/command_registry.rb +0 -61
  33. data/lib/swarm_cli/commands/mcp_serve.rb +0 -130
  34. data/lib/swarm_cli/commands/mcp_tools.rb +0 -148
  35. data/lib/swarm_cli/commands/migrate.rb +0 -55
  36. data/lib/swarm_cli/commands/run.rb +0 -173
  37. data/lib/swarm_cli/config_loader.rb +0 -98
  38. data/lib/swarm_cli/formatters/human_formatter.rb +0 -781
  39. data/lib/swarm_cli/formatters/json_formatter.rb +0 -51
  40. data/lib/swarm_cli/interactive_repl.rb +0 -924
  41. data/lib/swarm_cli/mcp_serve_options.rb +0 -44
  42. data/lib/swarm_cli/mcp_tools_options.rb +0 -59
  43. data/lib/swarm_cli/migrate_options.rb +0 -54
  44. data/lib/swarm_cli/migrator.rb +0 -132
  45. data/lib/swarm_cli/options.rb +0 -151
  46. data/lib/swarm_cli/ui/components/agent_badge.rb +0 -33
  47. data/lib/swarm_cli/ui/components/content_block.rb +0 -120
  48. data/lib/swarm_cli/ui/components/divider.rb +0 -57
  49. data/lib/swarm_cli/ui/components/panel.rb +0 -62
  50. data/lib/swarm_cli/ui/components/usage_stats.rb +0 -70
  51. data/lib/swarm_cli/ui/formatters/cost.rb +0 -49
  52. data/lib/swarm_cli/ui/formatters/number.rb +0 -58
  53. data/lib/swarm_cli/ui/formatters/text.rb +0 -77
  54. data/lib/swarm_cli/ui/formatters/time.rb +0 -73
  55. data/lib/swarm_cli/ui/icons.rb +0 -36
  56. data/lib/swarm_cli/ui/renderers/event_renderer.rb +0 -188
  57. data/lib/swarm_cli/ui/state/agent_color_cache.rb +0 -45
  58. data/lib/swarm_cli/ui/state/depth_tracker.rb +0 -40
  59. data/lib/swarm_cli/ui/state/spinner_manager.rb +0 -170
  60. data/lib/swarm_cli/ui/state/usage_tracker.rb +0 -62
  61. data/lib/swarm_cli/version.rb +0 -5
  62. data/lib/swarm_cli.rb +0 -46
  63. data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -127
  64. data/lib/swarm_sdk/agent/builder.rb +0 -552
  65. data/lib/swarm_sdk/agent/chat.rb +0 -774
  66. data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -268
  67. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
  68. data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
  69. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -78
  70. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -233
  71. data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
  72. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
  73. data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -136
  74. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
  75. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -98
  76. data/lib/swarm_sdk/agent/context.rb +0 -116
  77. data/lib/swarm_sdk/agent/context_manager.rb +0 -315
  78. data/lib/swarm_sdk/agent/definition.rb +0 -477
  79. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -182
  80. data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
  81. data/lib/swarm_sdk/builders/base_builder.rb +0 -409
  82. data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
  83. data/lib/swarm_sdk/concerns/cleanupable.rb +0 -39
  84. data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
  85. data/lib/swarm_sdk/concerns/validatable.rb +0 -55
  86. data/lib/swarm_sdk/configuration/parser.rb +0 -353
  87. data/lib/swarm_sdk/configuration/translator.rb +0 -255
  88. data/lib/swarm_sdk/configuration.rb +0 -135
  89. data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
  90. data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -106
  91. data/lib/swarm_sdk/context_compactor.rb +0 -335
  92. data/lib/swarm_sdk/context_management/builder.rb +0 -128
  93. data/lib/swarm_sdk/context_management/context.rb +0 -328
  94. data/lib/swarm_sdk/defaults.rb +0 -196
  95. data/lib/swarm_sdk/events_to_messages.rb +0 -199
  96. data/lib/swarm_sdk/hooks/adapter.rb +0 -359
  97. data/lib/swarm_sdk/hooks/context.rb +0 -197
  98. data/lib/swarm_sdk/hooks/definition.rb +0 -80
  99. data/lib/swarm_sdk/hooks/error.rb +0 -29
  100. data/lib/swarm_sdk/hooks/executor.rb +0 -146
  101. data/lib/swarm_sdk/hooks/registry.rb +0 -147
  102. data/lib/swarm_sdk/hooks/result.rb +0 -150
  103. data/lib/swarm_sdk/hooks/shell_executor.rb +0 -255
  104. data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
  105. data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
  106. data/lib/swarm_sdk/log_collector.rb +0 -227
  107. data/lib/swarm_sdk/log_stream.rb +0 -127
  108. data/lib/swarm_sdk/markdown_parser.rb +0 -75
  109. data/lib/swarm_sdk/model_aliases.json +0 -8
  110. data/lib/swarm_sdk/models.json +0 -1
  111. data/lib/swarm_sdk/models.rb +0 -120
  112. data/lib/swarm_sdk/node_context.rb +0 -245
  113. data/lib/swarm_sdk/observer/builder.rb +0 -81
  114. data/lib/swarm_sdk/observer/config.rb +0 -45
  115. data/lib/swarm_sdk/observer/manager.rb +0 -236
  116. data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
  117. data/lib/swarm_sdk/permissions/config.rb +0 -239
  118. data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
  119. data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
  120. data/lib/swarm_sdk/permissions/validator.rb +0 -173
  121. data/lib/swarm_sdk/permissions_builder.rb +0 -122
  122. data/lib/swarm_sdk/plugin.rb +0 -309
  123. data/lib/swarm_sdk/plugin_registry.rb +0 -101
  124. data/lib/swarm_sdk/proc_helpers.rb +0 -53
  125. data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -117
  126. data/lib/swarm_sdk/restore_result.rb +0 -65
  127. data/lib/swarm_sdk/result.rb +0 -123
  128. data/lib/swarm_sdk/snapshot.rb +0 -156
  129. data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
  130. data/lib/swarm_sdk/state_restorer.rb +0 -476
  131. data/lib/swarm_sdk/state_snapshot.rb +0 -334
  132. data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -683
  133. data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -167
  134. data/lib/swarm_sdk/swarm/builder.rb +0 -249
  135. data/lib/swarm_sdk/swarm/executor.rb +0 -213
  136. data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -150
  137. data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -340
  138. data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -154
  139. data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
  140. data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -358
  141. data/lib/swarm_sdk/swarm.rb +0 -717
  142. data/lib/swarm_sdk/swarm_loader.rb +0 -145
  143. data/lib/swarm_sdk/swarm_registry.rb +0 -136
  144. data/lib/swarm_sdk/tools/bash.rb +0 -282
  145. data/lib/swarm_sdk/tools/clock.rb +0 -44
  146. data/lib/swarm_sdk/tools/delegate.rb +0 -267
  147. data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
  148. data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
  149. data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
  150. data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
  151. data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
  152. data/lib/swarm_sdk/tools/edit.rb +0 -145
  153. data/lib/swarm_sdk/tools/glob.rb +0 -166
  154. data/lib/swarm_sdk/tools/grep.rb +0 -235
  155. data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
  156. data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -163
  157. data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
  158. data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
  159. data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
  160. data/lib/swarm_sdk/tools/read.rb +0 -261
  161. data/lib/swarm_sdk/tools/registry.rb +0 -205
  162. data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
  163. data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
  164. data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
  165. data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
  166. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -272
  167. data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
  168. data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
  169. data/lib/swarm_sdk/tools/think.rb +0 -98
  170. data/lib/swarm_sdk/tools/todo_write.rb +0 -235
  171. data/lib/swarm_sdk/tools/web_fetch.rb +0 -262
  172. data/lib/swarm_sdk/tools/write.rb +0 -112
  173. data/lib/swarm_sdk/utils.rb +0 -68
  174. data/lib/swarm_sdk/validation_result.rb +0 -33
  175. data/lib/swarm_sdk/version.rb +0 -5
  176. data/lib/swarm_sdk/workflow/agent_config.rb +0 -79
  177. data/lib/swarm_sdk/workflow/builder.rb +0 -143
  178. data/lib/swarm_sdk/workflow/executor.rb +0 -497
  179. data/lib/swarm_sdk/workflow/node_builder.rb +0 -555
  180. data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -249
  181. data/lib/swarm_sdk/workflow.rb +0 -554
  182. data/lib/swarm_sdk.rb +0 -524
@@ -1,121 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Permissions
5
- # ErrorFormatter generates user-friendly error messages for permission violations
6
- class ErrorFormatter
7
- class << self
8
- # Generate a permission denied error message
9
- #
10
- # @param path [String] The path that was denied
11
- # @param allowed_patterns [Array<String>] List of allowed path patterns
12
- # @param denied_patterns [Array<String>] List of denied path patterns
13
- # @param matching_pattern [String, nil] The specific pattern that blocked this path
14
- # @param tool_name [String] Name of the tool that was denied
15
- # @return [String] Formatted error message with system reminder
16
- def permission_denied(path:, allowed_patterns:, denied_patterns: [], matching_pattern: nil, tool_name:)
17
- operation_verb = case tool_name.to_s
18
- when "Read" then "read"
19
- when "Write" then "write to"
20
- when "Edit", "MultiEdit" then "edit"
21
- when "Glob" then "access directory"
22
- when "Grep" then "search in"
23
- else "access"
24
- end
25
-
26
- # Build policy explanation
27
- policy_info = if matching_pattern && matching_pattern != "(not in allowed list)"
28
- # Show the specific denied pattern that blocked this path
29
- "Blocked by policy: #{matching_pattern}"
30
- elsif matching_pattern == "(not in allowed list)" && allowed_patterns.any?
31
- # Show allowed patterns when path doesn't match any
32
- patterns = allowed_patterns.map { |p| " - #{p}" }.join("\n")
33
- "Path not in allowed list. Allowed paths:\n#{patterns}"
34
- elsif denied_patterns.any?
35
- # Show denied patterns
36
- patterns = denied_patterns.map { |p| " - #{p}" }.join("\n")
37
- "Denied paths:\n#{patterns}"
38
- elsif allowed_patterns.any?
39
- # Show allowed patterns
40
- patterns = allowed_patterns.map { |p| " - #{p}" }.join("\n")
41
- "Allowed paths (not matched):\n#{patterns}"
42
- else
43
- "No access policy configured"
44
- end
45
-
46
- reminder = <<~REMINDER
47
-
48
- <system-reminder>
49
- PERMISSION DENIED: You do not have permission to #{operation_verb} '#{path}'.
50
-
51
- #{policy_info}
52
-
53
- This is an UNRECOVERABLE error set by user policy. You MUST stop trying to access files matching this pattern.
54
-
55
- Policy explanation:
56
- - This policy blocks ALL files matching the pattern, not just this specific file
57
- - Do not attempt to access other files matching this pattern - they will also be denied
58
- - Do not try to work around this restriction by using different tool arguments
59
- - The user has explicitly denied access to these resources via security policy
60
-
61
- You should inform the user that you cannot proceed due to permission restrictions on this file pattern.
62
- </system-reminder>
63
- REMINDER
64
-
65
- "Permission denied: Cannot #{operation_verb} '#{path}'#{reminder}"
66
- end
67
-
68
- # Generate a command permission denied error message
69
- #
70
- # @param command [String] The command that was denied
71
- # @param allowed_patterns [Array<Regexp>] List of allowed command regex patterns
72
- # @param denied_patterns [Array<Regexp>] List of denied command regex patterns
73
- # @param matching_pattern [String, nil] The specific pattern that blocked this command
74
- # @param tool_name [String] Name of the tool (typically "bash")
75
- # @return [String] Formatted error message with system reminder
76
- def command_permission_denied(command:, allowed_patterns:, denied_patterns: [], matching_pattern: nil, tool_name:)
77
- # Build policy explanation
78
- policy_info = if matching_pattern && matching_pattern != "(not in allowed list)"
79
- # Show the specific denied pattern that blocked this command
80
- "Blocked by policy: #{matching_pattern}"
81
- elsif matching_pattern == "(not in allowed list)" && allowed_patterns.any?
82
- # Show allowed patterns when command doesn't match any
83
- patterns = allowed_patterns.map { |p| " - #{p.source}" }.join("\n")
84
- "Command not in allowed list. Allowed command patterns:\n#{patterns}"
85
- elsif denied_patterns.any?
86
- # Show denied patterns
87
- patterns = denied_patterns.map { |p| " - #{p.source}" }.join("\n")
88
- "Denied command patterns:\n#{patterns}"
89
- elsif allowed_patterns.any?
90
- # Show allowed patterns
91
- patterns = allowed_patterns.map { |p| " - #{p.source}" }.join("\n")
92
- "Allowed command patterns (not matched):\n#{patterns}"
93
- else
94
- "No command policy configured"
95
- end
96
-
97
- reminder = <<~REMINDER
98
-
99
- <system-reminder>
100
- PERMISSION DENIED: You do not have permission to execute command '#{command}'.
101
-
102
- #{policy_info}
103
-
104
- This is an UNRECOVERABLE error set by user policy. You MUST stop trying to execute commands matching this pattern.
105
-
106
- Policy explanation:
107
- - This policy blocks ALL commands matching the pattern, not just this specific command
108
- - Do not attempt to execute other commands matching this pattern - they will also be denied
109
- - Do not try to work around this restriction by modifying the command slightly
110
- - The user has explicitly denied access to these commands via security policy
111
-
112
- You should inform the user that you cannot proceed due to permission restrictions on this command.
113
- </system-reminder>
114
- REMINDER
115
-
116
- "Permission denied: Cannot execute command '#{command}'#{reminder}"
117
- end
118
- end
119
- end
120
- end
121
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Permissions
5
- # PathMatcher handles glob pattern matching for file paths
6
- #
7
- # Supports gitignore-style glob patterns with:
8
- # - Standard globs: *, **, ?, [abc], {a,b}
9
- # - Recursive matching: **/* matches all nested files
10
- # - Negation: !pattern to explicitly deny
11
- #
12
- # Examples:
13
- # PathMatcher.matches?("tmp/**/*", "tmp/foo/bar.rb") # => true
14
- # PathMatcher.matches?("*.log", "debug.log") # => true
15
- # PathMatcher.matches?("src/**/*.{rb,js}", "src/a/b.rb") # => true
16
- class PathMatcher
17
- class << self
18
- # Check if a path matches a glob pattern
19
- #
20
- # @param pattern [String] Glob pattern to match against
21
- # @param path [String] File path to check
22
- # @return [Boolean] True if path matches pattern
23
- def matches?(pattern, path)
24
- # Remove leading ! for negation patterns (handled by caller)
25
- pattern = pattern.delete_prefix("!")
26
-
27
- # Use File.fnmatch with pathname and extglob flags
28
- # FNM_PATHNAME: ** matches directories recursively
29
- # FNM_EXTGLOB: Support {a,b} patterns
30
- File.fnmatch(pattern, path, File::FNM_PATHNAME | File::FNM_EXTGLOB)
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,173 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- module Permissions
5
- # Validator decorates tools to enforce permission checks before execution
6
- #
7
- # Uses the Decorator pattern (via SimpleDelegator) to wrap tool instances
8
- # and validate file paths and commands before allowing tool execution.
9
- #
10
- # Example:
11
- # write_tool = Tools::Write.new
12
- # permissions = Config.new(
13
- # {
14
- # allowed_paths: ["tmp/**/*"],
15
- # allowed_commands: ["^git (status|diff)$"]
16
- # },
17
- # base_directories: ["."]
18
- # )
19
- # validated_tool = Validator.new(write_tool, permissions)
20
- #
21
- # # This will be denied:
22
- # validated_tool.call({"file_path" => "/etc/passwd", "content" => "..."})
23
- class Validator < SimpleDelegator
24
- # Initialize validator decorator
25
- #
26
- # @param tool [RubyLLM::Tool] Tool instance to wrap
27
- # @param permissions_config [Config] Permission configuration
28
- def initialize(tool, permissions_config)
29
- super(tool)
30
- @permissions = permissions_config
31
- @tool = tool
32
- end
33
-
34
- # Intercept RubyLLM's call method to validate permissions
35
- #
36
- # RubyLLM calls tool.call(args) where args have string keys.
37
- # We must override call (not execute) because SimpleDelegator doesn't
38
- # automatically intercept methods defined in the superclass.
39
- #
40
- # @param args [Hash] Tool arguments with string keys
41
- # @return [String] Tool result or permission denied message
42
- def call(args)
43
- # Validate Bash commands if this is the Bash tool
44
- if bash_tool?
45
- command = args["command"]
46
- if command && !@permissions.command_allowed?(command)
47
- # Find the specific pattern that blocks this command
48
- matching_pattern = @permissions.find_blocking_command_pattern(command)
49
-
50
- return ErrorFormatter.command_permission_denied(
51
- command: command,
52
- allowed_patterns: @permissions.allowed_commands,
53
- denied_patterns: @permissions.denied_commands,
54
- matching_pattern: matching_pattern,
55
- tool_name: @tool.name,
56
- )
57
- end
58
- end
59
-
60
- # Extract paths from arguments (handles both string and symbol keys)
61
- paths = extract_paths_from_args(args)
62
-
63
- # Determine if this is a directory search tool (Glob/Grep)
64
- directory_search = directory_search_tool?
65
-
66
- # Validate each path
67
- paths.each do |path|
68
- next if @permissions.allowed?(path, directory_search: directory_search)
69
-
70
- # Show absolute path in error message for clarity
71
- absolute_path = @permissions.to_absolute(path)
72
-
73
- # Find the specific pattern that blocks this path
74
- matching_pattern = @permissions.find_blocking_pattern(path, directory_search: directory_search)
75
-
76
- return ErrorFormatter.permission_denied(
77
- path: absolute_path,
78
- allowed_patterns: @permissions.allowed_patterns,
79
- denied_patterns: @permissions.denied_patterns,
80
- matching_pattern: matching_pattern,
81
- tool_name: @tool.name,
82
- )
83
- end
84
-
85
- # All permissions validated, call wrapped tool
86
- __getobj__.call(args)
87
- end
88
-
89
- private
90
-
91
- # Check if the tool is the Bash tool
92
- #
93
- # @return [Boolean] True if tool is Bash
94
- def bash_tool?
95
- @tool.name.to_s == "Bash"
96
- end
97
-
98
- # Check if the tool is a directory search tool (Glob or Grep)
99
- #
100
- # @return [Boolean] True if tool searches directories
101
- def directory_search_tool?
102
- tool_name = @tool.name.to_s
103
- tool_name == "Glob" || tool_name == "Grep"
104
- end
105
-
106
- # Extract file paths from tool arguments
107
- #
108
- # RubyLLM always passes arguments with string keys to call().
109
- #
110
- # Different tools have different parameter structures:
111
- # - Write/Edit/Read: file_path parameter
112
- # - MultiEdit: edits array with file_path in each edit
113
- # - Glob/Grep: path parameter (directory to search)
114
- # - Glob: pattern parameter may contain directory (e.g., "lib/**/*.rb")
115
- # - Bash: command parameter (validated separately via command_allowed?)
116
- #
117
- # @param args [Hash] Tool arguments with string keys
118
- # @return [Array<String>] List of file paths to validate
119
- def extract_paths_from_args(args)
120
- paths = []
121
-
122
- # Single file path parameter (Write, Edit, Read)
123
- paths << args["file_path"] if args["file_path"]
124
-
125
- # Path parameter (Glob, Grep)
126
- paths << args["path"] if args["path"]
127
-
128
- # Glob pattern may contain directory prefix (e.g., "lib/**/*.rb")
129
- # Extract the base directory from the pattern for validation
130
- # Note: Only do this for Glob, not Grep (Grep pattern is a regex, not a path)
131
- if @tool.name.to_s == "Glob"
132
- pattern = args["pattern"]
133
- if pattern && !pattern.start_with?("/")
134
- # Extract first directory component from relative patterns
135
- base_dir = extract_base_directory(pattern)
136
- paths << base_dir if base_dir
137
- end
138
- end
139
-
140
- # MultiEdit has array of edits
141
- edits = args["edits"]
142
- edits&.each do |edit|
143
- paths << edit["file_path"] if edit.is_a?(Hash) && edit["file_path"]
144
- end
145
-
146
- paths.compact.uniq
147
- end
148
-
149
- # Extract base directory from a glob pattern
150
- #
151
- # Examples:
152
- # "lib/**/*.rb" => "lib"
153
- # "src/main.rb" => "src"
154
- # "**/*.rb" => nil (no specific directory)
155
- # "*.rb" => nil (current directory)
156
- #
157
- # @param pattern [String] Glob pattern
158
- # @return [String, nil] Base directory or nil
159
- def extract_base_directory(pattern)
160
- return if pattern.nil? || pattern.empty?
161
-
162
- # Split on / and take first component
163
- parts = pattern.split("/")
164
- first_part = parts.first
165
-
166
- # Skip if pattern starts with wildcard (means current directory)
167
- return if first_part.include?("*") || first_part.include?("?")
168
-
169
- first_part
170
- end
171
- end
172
- end
173
- end
@@ -1,122 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SwarmSDK
4
- # DSL builder for tool permissions configuration
5
- #
6
- # Provides fluent API for configuring tool permissions using underscore syntax:
7
- #
8
- # @example Basic usage
9
- # permissions do
10
- # tool(:Write).allow_paths "tmp/**/*"
11
- # tool(:Write).deny_paths "tmp/secrets/**"
12
- # tool(:Read).deny_paths "lib/**/*"
13
- # end
14
- #
15
- # @example Bash commands
16
- # permissions do
17
- # tool(:Bash).allow_commands "^git (status|diff|log)$"
18
- # tool(:Bash).deny_commands "^rm -rf"
19
- # end
20
- #
21
- class PermissionsBuilder
22
- def initialize
23
- @permissions = {}
24
- end
25
-
26
- class << self
27
- # Build permissions from block
28
- #
29
- # @yield Block for configuring permissions
30
- # @return [Hash] Permissions configuration
31
- def build(&block)
32
- builder = new
33
- builder.instance_eval(&block)
34
- builder.to_h
35
- end
36
- end
37
-
38
- # Convert to hash format expected by AgentDefinition
39
- #
40
- # @return [Hash] Permissions config
41
- def to_h
42
- @permissions
43
- end
44
-
45
- # Get a tool permissions proxy for configuring a specific tool
46
- #
47
- # @param tool_name [Symbol, String] Tool name
48
- # @return [ToolPermissionsProxy] Proxy for configuring this tool
49
- #
50
- # @example
51
- # tool(:Write).allow_paths "tmp/**/*"
52
- # tool(:Bash).deny_commands "^rm -rf"
53
- def tool(tool_name)
54
- ToolPermissionsProxy.new(tool_name, @permissions)
55
- end
56
- end
57
-
58
- # Proxy for configuring permissions on a specific tool
59
- #
60
- # @example
61
- # tool(:Write).allow_paths "tmp/**/*"
62
- # tool(:Write).deny_paths "tmp/secrets/**"
63
- # tool(:Bash).allow_commands "^git status$"
64
- #
65
- class ToolPermissionsProxy
66
- def initialize(tool_name, permissions_hash)
67
- @tool_name = tool_name.to_sym
68
- @permissions = permissions_hash
69
- end
70
-
71
- # Add allowed path patterns
72
- #
73
- # @param patterns [Array<String>] Glob patterns for allowed paths
74
- # @return [self]
75
- def allow_paths(*patterns)
76
- ensure_tool_config
77
- @permissions[@tool_name][:allowed_paths] ||= []
78
- @permissions[@tool_name][:allowed_paths].concat(patterns.flatten)
79
- self
80
- end
81
-
82
- # Add denied path patterns
83
- #
84
- # @param patterns [Array<String>] Glob patterns for denied paths
85
- # @return [self]
86
- def deny_paths(*patterns)
87
- ensure_tool_config
88
- @permissions[@tool_name][:denied_paths] ||= []
89
- @permissions[@tool_name][:denied_paths].concat(patterns.flatten)
90
- self
91
- end
92
-
93
- # Add allowed command patterns (Bash tool only)
94
- #
95
- # @param patterns [Array<String>] Regex patterns for allowed commands
96
- # @return [self]
97
- def allow_commands(*patterns)
98
- ensure_tool_config
99
- @permissions[@tool_name][:allowed_commands] ||= []
100
- @permissions[@tool_name][:allowed_commands].concat(patterns.flatten)
101
- self
102
- end
103
-
104
- # Add denied command patterns (Bash tool only)
105
- #
106
- # @param patterns [Array<String>] Regex patterns for denied commands
107
- # @return [self]
108
- def deny_commands(*patterns)
109
- ensure_tool_config
110
- @permissions[@tool_name][:denied_commands] ||= []
111
- @permissions[@tool_name][:denied_commands].concat(patterns.flatten)
112
- self
113
- end
114
-
115
- private
116
-
117
- # Ensure tool entry exists in permissions hash
118
- def ensure_tool_config
119
- @permissions[@tool_name] ||= {}
120
- end
121
- end
122
- end