swarm_memory 2.1.4 → 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 (184) hide show
  1. checksums.yaml +4 -4
  2. data/lib/swarm_memory/version.rb +1 -1
  3. data/lib/swarm_memory.rb +7 -2
  4. metadata +6 -185
  5. data/lib/claude_swarm/base_executor.rb +0 -133
  6. data/lib/claude_swarm/claude_code_executor.rb +0 -349
  7. data/lib/claude_swarm/claude_mcp_server.rb +0 -78
  8. data/lib/claude_swarm/cli.rb +0 -697
  9. data/lib/claude_swarm/commands/ps.rb +0 -215
  10. data/lib/claude_swarm/commands/show.rb +0 -139
  11. data/lib/claude_swarm/configuration.rb +0 -373
  12. data/lib/claude_swarm/hooks/session_start_hook.rb +0 -42
  13. data/lib/claude_swarm/json_handler.rb +0 -91
  14. data/lib/claude_swarm/mcp_generator.rb +0 -243
  15. data/lib/claude_swarm/openai/chat_completion.rb +0 -256
  16. data/lib/claude_swarm/openai/executor.rb +0 -256
  17. data/lib/claude_swarm/openai/responses.rb +0 -319
  18. data/lib/claude_swarm/orchestrator.rb +0 -878
  19. data/lib/claude_swarm/process_tracker.rb +0 -78
  20. data/lib/claude_swarm/session_cost_calculator.rb +0 -209
  21. data/lib/claude_swarm/session_path.rb +0 -42
  22. data/lib/claude_swarm/settings_generator.rb +0 -77
  23. data/lib/claude_swarm/system_utils.rb +0 -46
  24. data/lib/claude_swarm/templates/generation_prompt.md.erb +0 -230
  25. data/lib/claude_swarm/tools/reset_session_tool.rb +0 -24
  26. data/lib/claude_swarm/tools/session_info_tool.rb +0 -24
  27. data/lib/claude_swarm/tools/task_tool.rb +0 -63
  28. data/lib/claude_swarm/version.rb +0 -5
  29. data/lib/claude_swarm/worktree_manager.rb +0 -475
  30. data/lib/claude_swarm/yaml_loader.rb +0 -22
  31. data/lib/claude_swarm.rb +0 -67
  32. data/lib/swarm_cli/cli.rb +0 -201
  33. data/lib/swarm_cli/command_registry.rb +0 -61
  34. data/lib/swarm_cli/commands/mcp_serve.rb +0 -130
  35. data/lib/swarm_cli/commands/mcp_tools.rb +0 -148
  36. data/lib/swarm_cli/commands/migrate.rb +0 -55
  37. data/lib/swarm_cli/commands/run.rb +0 -173
  38. data/lib/swarm_cli/config_loader.rb +0 -98
  39. data/lib/swarm_cli/formatters/human_formatter.rb +0 -781
  40. data/lib/swarm_cli/formatters/json_formatter.rb +0 -51
  41. data/lib/swarm_cli/interactive_repl.rb +0 -924
  42. data/lib/swarm_cli/mcp_serve_options.rb +0 -44
  43. data/lib/swarm_cli/mcp_tools_options.rb +0 -59
  44. data/lib/swarm_cli/migrate_options.rb +0 -54
  45. data/lib/swarm_cli/migrator.rb +0 -132
  46. data/lib/swarm_cli/options.rb +0 -151
  47. data/lib/swarm_cli/ui/components/agent_badge.rb +0 -33
  48. data/lib/swarm_cli/ui/components/content_block.rb +0 -120
  49. data/lib/swarm_cli/ui/components/divider.rb +0 -57
  50. data/lib/swarm_cli/ui/components/panel.rb +0 -62
  51. data/lib/swarm_cli/ui/components/usage_stats.rb +0 -70
  52. data/lib/swarm_cli/ui/formatters/cost.rb +0 -49
  53. data/lib/swarm_cli/ui/formatters/number.rb +0 -58
  54. data/lib/swarm_cli/ui/formatters/text.rb +0 -77
  55. data/lib/swarm_cli/ui/formatters/time.rb +0 -73
  56. data/lib/swarm_cli/ui/icons.rb +0 -36
  57. data/lib/swarm_cli/ui/renderers/event_renderer.rb +0 -188
  58. data/lib/swarm_cli/ui/state/agent_color_cache.rb +0 -45
  59. data/lib/swarm_cli/ui/state/depth_tracker.rb +0 -40
  60. data/lib/swarm_cli/ui/state/spinner_manager.rb +0 -170
  61. data/lib/swarm_cli/ui/state/usage_tracker.rb +0 -62
  62. data/lib/swarm_cli/version.rb +0 -5
  63. data/lib/swarm_cli.rb +0 -46
  64. data/lib/swarm_sdk/agent/RETRY_LOGIC.md +0 -127
  65. data/lib/swarm_sdk/agent/builder.rb +0 -552
  66. data/lib/swarm_sdk/agent/chat.rb +0 -774
  67. data/lib/swarm_sdk/agent/chat_helpers/context_tracker.rb +0 -268
  68. data/lib/swarm_sdk/agent/chat_helpers/event_emitter.rb +0 -204
  69. data/lib/swarm_sdk/agent/chat_helpers/hook_integration.rb +0 -480
  70. data/lib/swarm_sdk/agent/chat_helpers/instrumentation.rb +0 -78
  71. data/lib/swarm_sdk/agent/chat_helpers/llm_configuration.rb +0 -233
  72. data/lib/swarm_sdk/agent/chat_helpers/logging_helpers.rb +0 -116
  73. data/lib/swarm_sdk/agent/chat_helpers/serialization.rb +0 -83
  74. data/lib/swarm_sdk/agent/chat_helpers/system_reminder_injector.rb +0 -136
  75. data/lib/swarm_sdk/agent/chat_helpers/system_reminders.rb +0 -79
  76. data/lib/swarm_sdk/agent/chat_helpers/token_tracking.rb +0 -98
  77. data/lib/swarm_sdk/agent/context.rb +0 -116
  78. data/lib/swarm_sdk/agent/context_manager.rb +0 -315
  79. data/lib/swarm_sdk/agent/definition.rb +0 -477
  80. data/lib/swarm_sdk/agent/llm_instrumentation_middleware.rb +0 -182
  81. data/lib/swarm_sdk/agent/system_prompt_builder.rb +0 -161
  82. data/lib/swarm_sdk/builders/base_builder.rb +0 -409
  83. data/lib/swarm_sdk/claude_code_agent_adapter.rb +0 -205
  84. data/lib/swarm_sdk/concerns/cleanupable.rb +0 -39
  85. data/lib/swarm_sdk/concerns/snapshotable.rb +0 -67
  86. data/lib/swarm_sdk/concerns/validatable.rb +0 -55
  87. data/lib/swarm_sdk/configuration/parser.rb +0 -353
  88. data/lib/swarm_sdk/configuration/translator.rb +0 -255
  89. data/lib/swarm_sdk/configuration.rb +0 -135
  90. data/lib/swarm_sdk/context_compactor/metrics.rb +0 -147
  91. data/lib/swarm_sdk/context_compactor/token_counter.rb +0 -106
  92. data/lib/swarm_sdk/context_compactor.rb +0 -335
  93. data/lib/swarm_sdk/context_management/builder.rb +0 -128
  94. data/lib/swarm_sdk/context_management/context.rb +0 -328
  95. data/lib/swarm_sdk/defaults.rb +0 -196
  96. data/lib/swarm_sdk/events_to_messages.rb +0 -199
  97. data/lib/swarm_sdk/hooks/adapter.rb +0 -359
  98. data/lib/swarm_sdk/hooks/context.rb +0 -197
  99. data/lib/swarm_sdk/hooks/definition.rb +0 -80
  100. data/lib/swarm_sdk/hooks/error.rb +0 -29
  101. data/lib/swarm_sdk/hooks/executor.rb +0 -146
  102. data/lib/swarm_sdk/hooks/registry.rb +0 -147
  103. data/lib/swarm_sdk/hooks/result.rb +0 -150
  104. data/lib/swarm_sdk/hooks/shell_executor.rb +0 -255
  105. data/lib/swarm_sdk/hooks/tool_call.rb +0 -35
  106. data/lib/swarm_sdk/hooks/tool_result.rb +0 -62
  107. data/lib/swarm_sdk/log_collector.rb +0 -227
  108. data/lib/swarm_sdk/log_stream.rb +0 -127
  109. data/lib/swarm_sdk/markdown_parser.rb +0 -75
  110. data/lib/swarm_sdk/model_aliases.json +0 -8
  111. data/lib/swarm_sdk/models.json +0 -1
  112. data/lib/swarm_sdk/models.rb +0 -120
  113. data/lib/swarm_sdk/node_context.rb +0 -245
  114. data/lib/swarm_sdk/observer/builder.rb +0 -81
  115. data/lib/swarm_sdk/observer/config.rb +0 -45
  116. data/lib/swarm_sdk/observer/manager.rb +0 -236
  117. data/lib/swarm_sdk/patterns/agent_observer.rb +0 -160
  118. data/lib/swarm_sdk/permissions/config.rb +0 -239
  119. data/lib/swarm_sdk/permissions/error_formatter.rb +0 -121
  120. data/lib/swarm_sdk/permissions/path_matcher.rb +0 -35
  121. data/lib/swarm_sdk/permissions/validator.rb +0 -173
  122. data/lib/swarm_sdk/permissions_builder.rb +0 -122
  123. data/lib/swarm_sdk/plugin.rb +0 -309
  124. data/lib/swarm_sdk/plugin_registry.rb +0 -101
  125. data/lib/swarm_sdk/proc_helpers.rb +0 -53
  126. data/lib/swarm_sdk/prompts/base_system_prompt.md.erb +0 -117
  127. data/lib/swarm_sdk/restore_result.rb +0 -65
  128. data/lib/swarm_sdk/result.rb +0 -123
  129. data/lib/swarm_sdk/snapshot.rb +0 -156
  130. data/lib/swarm_sdk/snapshot_from_events.rb +0 -397
  131. data/lib/swarm_sdk/state_restorer.rb +0 -476
  132. data/lib/swarm_sdk/state_snapshot.rb +0 -334
  133. data/lib/swarm_sdk/swarm/agent_initializer.rb +0 -683
  134. data/lib/swarm_sdk/swarm/all_agents_builder.rb +0 -167
  135. data/lib/swarm_sdk/swarm/builder.rb +0 -249
  136. data/lib/swarm_sdk/swarm/executor.rb +0 -213
  137. data/lib/swarm_sdk/swarm/hook_triggers.rb +0 -150
  138. data/lib/swarm_sdk/swarm/logging_callbacks.rb +0 -340
  139. data/lib/swarm_sdk/swarm/mcp_configurator.rb +0 -154
  140. data/lib/swarm_sdk/swarm/swarm_registry_builder.rb +0 -67
  141. data/lib/swarm_sdk/swarm/tool_configurator.rb +0 -358
  142. data/lib/swarm_sdk/swarm.rb +0 -717
  143. data/lib/swarm_sdk/swarm_loader.rb +0 -145
  144. data/lib/swarm_sdk/swarm_registry.rb +0 -136
  145. data/lib/swarm_sdk/tools/bash.rb +0 -282
  146. data/lib/swarm_sdk/tools/clock.rb +0 -44
  147. data/lib/swarm_sdk/tools/delegate.rb +0 -267
  148. data/lib/swarm_sdk/tools/document_converters/base_converter.rb +0 -83
  149. data/lib/swarm_sdk/tools/document_converters/docx_converter.rb +0 -99
  150. data/lib/swarm_sdk/tools/document_converters/html_converter.rb +0 -101
  151. data/lib/swarm_sdk/tools/document_converters/pdf_converter.rb +0 -78
  152. data/lib/swarm_sdk/tools/document_converters/xlsx_converter.rb +0 -194
  153. data/lib/swarm_sdk/tools/edit.rb +0 -145
  154. data/lib/swarm_sdk/tools/glob.rb +0 -166
  155. data/lib/swarm_sdk/tools/grep.rb +0 -235
  156. data/lib/swarm_sdk/tools/image_extractors/docx_image_extractor.rb +0 -43
  157. data/lib/swarm_sdk/tools/image_extractors/pdf_image_extractor.rb +0 -163
  158. data/lib/swarm_sdk/tools/image_formats/tiff_builder.rb +0 -65
  159. data/lib/swarm_sdk/tools/multi_edit.rb +0 -236
  160. data/lib/swarm_sdk/tools/path_resolver.rb +0 -92
  161. data/lib/swarm_sdk/tools/read.rb +0 -261
  162. data/lib/swarm_sdk/tools/registry.rb +0 -205
  163. data/lib/swarm_sdk/tools/scratchpad/scratchpad_list.rb +0 -117
  164. data/lib/swarm_sdk/tools/scratchpad/scratchpad_read.rb +0 -97
  165. data/lib/swarm_sdk/tools/scratchpad/scratchpad_write.rb +0 -108
  166. data/lib/swarm_sdk/tools/stores/read_tracker.rb +0 -96
  167. data/lib/swarm_sdk/tools/stores/scratchpad_storage.rb +0 -272
  168. data/lib/swarm_sdk/tools/stores/storage.rb +0 -142
  169. data/lib/swarm_sdk/tools/stores/todo_manager.rb +0 -65
  170. data/lib/swarm_sdk/tools/think.rb +0 -98
  171. data/lib/swarm_sdk/tools/todo_write.rb +0 -235
  172. data/lib/swarm_sdk/tools/web_fetch.rb +0 -262
  173. data/lib/swarm_sdk/tools/write.rb +0 -112
  174. data/lib/swarm_sdk/utils.rb +0 -68
  175. data/lib/swarm_sdk/validation_result.rb +0 -33
  176. data/lib/swarm_sdk/version.rb +0 -5
  177. data/lib/swarm_sdk/workflow/agent_config.rb +0 -79
  178. data/lib/swarm_sdk/workflow/builder.rb +0 -143
  179. data/lib/swarm_sdk/workflow/executor.rb +0 -497
  180. data/lib/swarm_sdk/workflow/node_builder.rb +0 -555
  181. data/lib/swarm_sdk/workflow/transformer_executor.rb +0 -249
  182. data/lib/swarm_sdk/workflow.rb +0 -554
  183. data/lib/swarm_sdk.rb +0 -524
  184. /data/lib/swarm_memory/{errors.rb → error.rb} +0 -0
@@ -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