roast-ai 0.4.3 → 0.4.5

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 (232) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +2 -0
  3. data/.github/workflows/ci.yaml +1 -0
  4. data/.gitignore +0 -26
  5. data/.rubocop.yml +13 -0
  6. data/.rubocop_todo.yml +21 -0
  7. data/CHANGELOG.md +29 -0
  8. data/Gemfile +4 -0
  9. data/Gemfile.lock +47 -29
  10. data/bin/rubocop +27 -0
  11. data/bin/spoom +27 -0
  12. data/bin/srb +27 -0
  13. data/bin/srb-rbi +27 -0
  14. data/bin/tapioca +27 -0
  15. data/docs/INSTRUMENTATION.md +3 -3
  16. data/dsl/simple.rb +10 -0
  17. data/lib/roast/dsl/executor.rb +26 -0
  18. data/lib/roast/dsl.rb +7 -0
  19. data/lib/roast/errors.rb +1 -0
  20. data/lib/roast/factories/api_provider_factory.rb +1 -0
  21. data/lib/roast/helpers/function_caching_interceptor.rb +3 -0
  22. data/lib/roast/helpers/logger.rb +6 -9
  23. data/lib/roast/helpers/metadata_access.rb +1 -0
  24. data/lib/roast/helpers/minitest_coverage_runner.rb +1 -0
  25. data/lib/roast/helpers/path_resolver.rb +8 -18
  26. data/lib/roast/helpers/prompt_loader.rb +3 -2
  27. data/lib/roast/helpers/timeout_handler.rb +3 -5
  28. data/lib/roast/initializers.rb +1 -0
  29. data/lib/roast/resources/api_resource.rb +4 -3
  30. data/lib/roast/resources/base_resource.rb +1 -0
  31. data/lib/roast/resources/directory_resource.rb +1 -0
  32. data/lib/roast/resources/file_resource.rb +1 -0
  33. data/lib/roast/resources/none_resource.rb +1 -0
  34. data/lib/roast/resources/url_resource.rb +2 -1
  35. data/lib/roast/resources.rb +1 -2
  36. data/lib/roast/services/context_threshold_checker.rb +1 -0
  37. data/lib/roast/services/token_counting_service.rb +1 -0
  38. data/lib/roast/tools/apply_diff.rb +1 -0
  39. data/lib/roast/tools/ask_user.rb +1 -0
  40. data/lib/roast/tools/bash.rb +1 -0
  41. data/lib/roast/tools/cmd.rb +1 -0
  42. data/lib/roast/tools/coding_agent.rb +1 -0
  43. data/lib/roast/tools/context_summarizer.rb +1 -0
  44. data/lib/roast/tools/grep.rb +1 -0
  45. data/lib/roast/tools/helpers/coding_agent_message_formatter.rb +1 -0
  46. data/lib/roast/tools/read_file.rb +1 -0
  47. data/lib/roast/tools/search_file.rb +1 -0
  48. data/lib/roast/tools/swarm.rb +1 -0
  49. data/lib/roast/tools/update_files.rb +1 -0
  50. data/lib/roast/tools/write_file.rb +1 -0
  51. data/lib/roast/tools.rb +2 -0
  52. data/lib/roast/value_objects/api_token.rb +1 -0
  53. data/lib/roast/value_objects/step_name.rb +1 -0
  54. data/lib/roast/value_objects/uri_base.rb +1 -0
  55. data/lib/roast/value_objects/workflow_path.rb +1 -0
  56. data/lib/roast/value_objects.rb +1 -0
  57. data/lib/roast/version.rb +2 -1
  58. data/lib/roast/workflow/agent_step.rb +1 -0
  59. data/lib/roast/workflow/api_configuration.rb +1 -0
  60. data/lib/roast/workflow/base_iteration_step.rb +1 -0
  61. data/lib/roast/workflow/base_step.rb +1 -0
  62. data/lib/roast/workflow/base_workflow.rb +1 -0
  63. data/lib/roast/workflow/case_executor.rb +1 -0
  64. data/lib/roast/workflow/case_step.rb +1 -0
  65. data/lib/roast/workflow/command_executor.rb +1 -0
  66. data/lib/roast/workflow/conditional_executor.rb +1 -0
  67. data/lib/roast/workflow/conditional_step.rb +1 -0
  68. data/lib/roast/workflow/configuration.rb +9 -0
  69. data/lib/roast/workflow/configuration_loader.rb +4 -1
  70. data/lib/roast/workflow/context_manager.rb +1 -0
  71. data/lib/roast/workflow/context_path_resolver.rb +1 -0
  72. data/lib/roast/workflow/dot_access_hash.rb +1 -0
  73. data/lib/roast/workflow/each_step.rb +1 -0
  74. data/lib/roast/workflow/error_handler.rb +7 -1
  75. data/lib/roast/workflow/expression_evaluator.rb +1 -0
  76. data/lib/roast/workflow/expression_utils.rb +1 -0
  77. data/lib/roast/workflow/file_state_repository.rb +2 -1
  78. data/lib/roast/workflow/input_executor.rb +1 -0
  79. data/lib/roast/workflow/input_step.rb +1 -0
  80. data/lib/roast/workflow/interpolator.rb +2 -1
  81. data/lib/roast/workflow/iteration_executor.rb +1 -0
  82. data/lib/roast/workflow/llm_boolean_coercer.rb +1 -0
  83. data/lib/roast/workflow/metadata_manager.rb +1 -0
  84. data/lib/roast/workflow/output_handler.rb +1 -0
  85. data/lib/roast/workflow/output_manager.rb +1 -0
  86. data/lib/roast/workflow/parallel_executor.rb +1 -0
  87. data/lib/roast/workflow/prompt_step.rb +1 -0
  88. data/lib/roast/workflow/repeat_step.rb +1 -0
  89. data/lib/roast/workflow/replay_handler.rb +1 -0
  90. data/lib/roast/workflow/resource_resolver.rb +2 -6
  91. data/lib/roast/workflow/session_manager.rb +1 -0
  92. data/lib/roast/workflow/shell_script_step.rb +1 -0
  93. data/lib/roast/workflow/sqlite_state_repository.rb +1 -0
  94. data/lib/roast/workflow/state_manager.rb +1 -0
  95. data/lib/roast/workflow/state_repository.rb +1 -0
  96. data/lib/roast/workflow/state_repository_factory.rb +4 -2
  97. data/lib/roast/workflow/step_completion_reporter.rb +1 -0
  98. data/lib/roast/workflow/step_executor_coordinator.rb +9 -5
  99. data/lib/roast/workflow/step_executor_factory.rb +1 -0
  100. data/lib/roast/workflow/step_executor_registry.rb +2 -3
  101. data/lib/roast/workflow/step_executor_with_reporting.rb +1 -0
  102. data/lib/roast/workflow/step_executors/base_step_executor.rb +1 -0
  103. data/lib/roast/workflow/step_executors/hash_step_executor.rb +1 -0
  104. data/lib/roast/workflow/step_executors/parallel_step_executor.rb +1 -0
  105. data/lib/roast/workflow/step_executors/string_step_executor.rb +1 -0
  106. data/lib/roast/workflow/step_factory.rb +1 -0
  107. data/lib/roast/workflow/step_finder.rb +1 -0
  108. data/lib/roast/workflow/step_loader.rb +1 -0
  109. data/lib/roast/workflow/step_name_extractor.rb +1 -0
  110. data/lib/roast/workflow/step_runner.rb +1 -0
  111. data/lib/roast/workflow/step_type_resolver.rb +1 -0
  112. data/lib/roast/workflow/validation_command.rb +1 -0
  113. data/lib/roast/workflow/validator.rb +1 -0
  114. data/lib/roast/workflow/validators/base_validator.rb +1 -0
  115. data/lib/roast/workflow/validators/dependency_validator.rb +1 -0
  116. data/lib/roast/workflow/validators/linting_validator.rb +1 -0
  117. data/lib/roast/workflow/validators/schema_validator.rb +1 -0
  118. data/lib/roast/workflow/validators/step_collector.rb +1 -0
  119. data/lib/roast/workflow/validators/validation_orchestrator.rb +1 -0
  120. data/lib/roast/workflow/workflow_context.rb +1 -0
  121. data/lib/roast/workflow/workflow_execution_context.rb +1 -0
  122. data/lib/roast/workflow/workflow_executor.rb +2 -1
  123. data/lib/roast/workflow/workflow_initializer.rb +1 -0
  124. data/lib/roast/workflow/workflow_runner.rb +66 -55
  125. data/lib/roast/workflow.rb +1 -0
  126. data/lib/roast/workflow_diagram_generator.rb +3 -2
  127. data/lib/roast.rb +23 -8
  128. data/roast.gemspec +1 -1
  129. data/sorbet/config +8 -0
  130. data/sorbet/rbi/dsl/.gitattributes +1 -0
  131. data/sorbet/rbi/dsl/active_support/callbacks.rbi +21 -0
  132. data/sorbet/rbi/gems/.gitattributes +1 -0
  133. data/sorbet/rbi/gems/activesupport@8.0.2.rbi +19107 -0
  134. data/sorbet/rbi/gems/addressable@2.8.7.rbi +1994 -0
  135. data/sorbet/rbi/gems/ast@2.4.3.rbi +585 -0
  136. data/sorbet/rbi/gems/base64@0.3.0.rbi +545 -0
  137. data/sorbet/rbi/gems/benchmark@0.4.1.rbi +619 -0
  138. data/sorbet/rbi/gems/bigdecimal@3.2.2.rbi +62 -0
  139. data/sorbet/rbi/gems/cgi@0.5.0.rbi +2961 -0
  140. data/sorbet/rbi/gems/claude_swarm@0.1.19.rbi +568 -0
  141. data/sorbet/rbi/gems/cli-kit@5.0.1.rbi +1991 -0
  142. data/sorbet/rbi/gems/cli-ui@2.3.0.rbi +3181 -0
  143. data/sorbet/rbi/gems/coderay@1.1.3.rbi +9 -0
  144. data/sorbet/rbi/gems/concurrent-ruby@1.3.5.rbi +11657 -0
  145. data/sorbet/rbi/gems/connection_pool@2.5.3.rbi +9 -0
  146. data/sorbet/rbi/gems/crack@1.0.0.rbi +145 -0
  147. data/sorbet/rbi/gems/diff-lcs@1.6.2.rbi +972 -0
  148. data/sorbet/rbi/gems/dotenv@3.1.8.rbi +295 -0
  149. data/sorbet/rbi/gems/drb@2.2.3.rbi +1661 -0
  150. data/sorbet/rbi/gems/dry-configurable@1.3.0.rbi +672 -0
  151. data/sorbet/rbi/gems/dry-core@1.1.0.rbi +1894 -0
  152. data/sorbet/rbi/gems/dry-inflector@1.2.0.rbi +659 -0
  153. data/sorbet/rbi/gems/dry-initializer@3.2.0.rbi +781 -0
  154. data/sorbet/rbi/gems/dry-logic@1.6.0.rbi +1127 -0
  155. data/sorbet/rbi/gems/dry-schema@1.14.1.rbi +3727 -0
  156. data/sorbet/rbi/gems/dry-types@1.8.3.rbi +3969 -0
  157. data/sorbet/rbi/gems/erubi@1.13.1.rbi +155 -0
  158. data/sorbet/rbi/gems/event_stream_parser@1.0.0.rbi +49 -0
  159. data/sorbet/rbi/gems/faraday-multipart@1.1.1.rbi +283 -0
  160. data/sorbet/rbi/gems/faraday-net_http@3.4.1.rbi +147 -0
  161. data/sorbet/rbi/gems/faraday-retry@2.3.2.rbi +9 -0
  162. data/sorbet/rbi/gems/faraday@2.13.1.rbi +2977 -0
  163. data/sorbet/rbi/gems/fast-mcp-annotations@1.5.3.rbi +1588 -0
  164. data/sorbet/rbi/gems/ffi@1.17.2.rbi +9 -0
  165. data/sorbet/rbi/gems/formatador@1.1.0.rbi +9 -0
  166. data/sorbet/rbi/gems/guard-compat@1.2.1.rbi +102 -0
  167. data/sorbet/rbi/gems/guard-minitest@2.4.6.rbi +402 -0
  168. data/sorbet/rbi/gems/guard@2.19.1.rbi +2283 -0
  169. data/sorbet/rbi/gems/hashdiff@1.2.0.rbi +355 -0
  170. data/sorbet/rbi/gems/i18n@1.14.7.rbi +2359 -0
  171. data/sorbet/rbi/gems/json-schema@5.1.1.rbi +1466 -0
  172. data/sorbet/rbi/gems/json@2.12.2.rbi +2051 -0
  173. data/sorbet/rbi/gems/language_server-protocol@3.17.0.5.rbi +9 -0
  174. data/sorbet/rbi/gems/lint_roller@1.1.0.rbi +9 -0
  175. data/sorbet/rbi/gems/listen@3.9.0.rbi +1206 -0
  176. data/sorbet/rbi/gems/logger@1.7.0.rbi +963 -0
  177. data/sorbet/rbi/gems/lumberjack@1.2.10.rbi +1830 -0
  178. data/sorbet/rbi/gems/method_source@1.1.0.rbi +9 -0
  179. data/sorbet/rbi/gems/mime-types-data@3.2025.0617.rbi +136 -0
  180. data/sorbet/rbi/gems/mime-types@3.7.0.rbi +1342 -0
  181. data/sorbet/rbi/gems/minitest-rg@5.3.0.rbi +160 -0
  182. data/sorbet/rbi/gems/minitest@5.25.5.rbi +1640 -0
  183. data/sorbet/rbi/gems/mocha@2.7.1.rbi +12 -0
  184. data/sorbet/rbi/gems/multipart-post@2.4.1.rbi +244 -0
  185. data/sorbet/rbi/gems/nenv@0.3.0.rbi +147 -0
  186. data/sorbet/rbi/gems/net-http@0.6.0.rbi +4247 -0
  187. data/sorbet/rbi/gems/netrc@0.11.0.rbi +159 -0
  188. data/sorbet/rbi/gems/notiffany@0.1.3.rbi +1079 -0
  189. data/sorbet/rbi/gems/open_router@0.3.3.rbi +230 -0
  190. data/sorbet/rbi/gems/ostruct@0.6.2.rbi +354 -0
  191. data/sorbet/rbi/gems/parallel@1.27.0.rbi +291 -0
  192. data/sorbet/rbi/gems/parser@3.3.8.0.rbi +5535 -0
  193. data/sorbet/rbi/gems/prism@1.4.0.rbi +41732 -0
  194. data/sorbet/rbi/gems/pry@0.15.2.rbi +9 -0
  195. data/sorbet/rbi/gems/public_suffix@6.0.2.rbi +936 -0
  196. data/sorbet/rbi/gems/racc@1.8.1.rbi +158 -0
  197. data/sorbet/rbi/gems/rack@2.2.17.rbi +5659 -0
  198. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +9 -0
  199. data/sorbet/rbi/gems/raix@1.0.2.rbi +1104 -0
  200. data/sorbet/rbi/gems/rake@13.3.0.rbi +3036 -0
  201. data/sorbet/rbi/gems/rb-fsevent@0.11.2.rbi +9 -0
  202. data/sorbet/rbi/gems/rb-inotify@0.11.1.rbi +9 -0
  203. data/sorbet/rbi/gems/rbi@0.3.6.rbi +6893 -0
  204. data/sorbet/rbi/gems/rbs@3.9.4.rbi +6978 -0
  205. data/sorbet/rbi/gems/regexp_parser@2.10.0.rbi +9 -0
  206. data/sorbet/rbi/gems/rexml@3.4.1.rbi +5346 -0
  207. data/sorbet/rbi/gems/rubocop-ast@1.45.1.rbi +9 -0
  208. data/sorbet/rbi/gems/rubocop-shopify@2.17.1.rbi +9 -0
  209. data/sorbet/rbi/gems/rubocop@1.77.0.rbi +9 -0
  210. data/sorbet/rbi/gems/ruby-graphviz@1.2.5.rbi +1333 -0
  211. data/sorbet/rbi/gems/ruby-openai@8.1.0.rbi +758 -0
  212. data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +9 -0
  213. data/sorbet/rbi/gems/ruby2_keywords@0.0.5.rbi +9 -0
  214. data/sorbet/rbi/gems/securerandom@0.4.1.rbi +75 -0
  215. data/sorbet/rbi/gems/shellany@0.0.1.rbi +102 -0
  216. data/sorbet/rbi/gems/spoom@1.6.3.rbi +6985 -0
  217. data/sorbet/rbi/gems/sqlite3@2.7.0.rbi +1900 -0
  218. data/sorbet/rbi/gems/tapioca@0.16.11.rbi +3628 -0
  219. data/sorbet/rbi/gems/thor@1.4.0.rbi +4399 -0
  220. data/sorbet/rbi/gems/tzinfo@2.0.6.rbi +5918 -0
  221. data/sorbet/rbi/gems/unicode-display_width@3.1.4.rbi +9 -0
  222. data/sorbet/rbi/gems/unicode-emoji@4.0.4.rbi +9 -0
  223. data/sorbet/rbi/gems/uri@1.0.3.rbi +2349 -0
  224. data/sorbet/rbi/gems/vcr@6.3.1.rbi +3040 -0
  225. data/sorbet/rbi/gems/webmock@3.25.1.rbi +1792 -0
  226. data/sorbet/rbi/gems/yard-sorbet@0.9.0.rbi +435 -0
  227. data/sorbet/rbi/gems/yard@0.9.37.rbi +18492 -0
  228. data/sorbet/rbi/gems/zeitwerk@2.7.3.rbi +1429 -0
  229. data/sorbet/tapioca/config.yml +13 -0
  230. data/sorbet/tapioca/require.rb +36 -0
  231. metadata +116 -5
  232. data/lib/roast/workflow/configuration_parser.rb +0 -54
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 22264361960a52b5d21b2dcc715a77c23ad8601170dbf02daa531416b2180035
4
- data.tar.gz: 581b96d84ca59f702e591f18b0ae1e10823fccaaef6ad44757f38b607d146d94
3
+ metadata.gz: 70a8b9b5eb5427205d65f9e2d3eb989c53a0cd449aa83d2e8df712f3b06ae203
4
+ data.tar.gz: 29d8236ed59630399b69ddc7286d9f80428620158117a68bc14048c8ac0a1e78
5
5
  SHA512:
6
- metadata.gz: a1316b637cb27f19c467faebc6e21853cdac1ce69439db50e56a1bc7c8d69240f0eb7ae51e4a856d2ac0be3bf2f406b21d5a5e51131e7bcee2a5298b8b9799ae
7
- data.tar.gz: d41214b70dd0d1755d7c8b49673ccc4b0296d911e97ebbc18c72c08ecf80b916277518bf0087d0286fc32a471c807f225a3262c5049381f42999ace482e196b6
6
+ metadata.gz: 48fcaf3988124ce0d627ff22f11fc563a990b96eb92afa27b75294f4c21ed2341c240f5ecf1fcf2b618f87078b19876adaa5cc493419a6be3b05c6b2137abd58
7
+ data.tar.gz: 4df2dfb16ff49b3bfe53102d878de8c356330621e4267a07fbfd35642251b512eab974cbe4c3377fbdaf29933b4a36c91010abc741ccb6b11321fcc4decf191a
@@ -0,0 +1,2 @@
1
+ * @nfgrep @dersam @obie @juniper-shopify
2
+
@@ -30,4 +30,5 @@ jobs:
30
30
  ruby-version: ${{ matrix.ruby }}
31
31
  bundler-cache: true
32
32
  - run: bundle exec rake ci
33
+ - run: bin/srb tc
33
34
 
data/.gitignore CHANGED
@@ -13,32 +13,6 @@
13
13
  **/CLAUDE.local.md
14
14
  .roast/
15
15
 
16
- bin/_guard-core
17
- bin/bundle
18
- bin/coderay
19
- bin/dotenv
20
- bin/erb
21
- bin/guard
22
- bin/htmldiff
23
- bin/irb
24
- bin/ldiff
25
- bin/listen
26
- bin/pry
27
- bin/racc
28
- bin/rake
29
- bin/rbs
30
- bin/rdbg
31
- bin/rdoc
32
- bin/ri
33
- bin/rubocop
34
- bin/ruby-lsp
35
- bin/ruby-lsp-check
36
- bin/ruby-lsp-launcher
37
- bin/ruby-lsp-test-exec
38
- bin/ruby-parse
39
- bin/ruby-rewrite
40
- bin/thor
41
-
42
16
  gemfiles/*.lock
43
17
  bin/claude-swarm
44
18
  *.gem
data/.rubocop.yml CHANGED
@@ -1,3 +1,8 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ plugins:
4
+ - rubocop-sorbet
5
+
1
6
  inherit_gem:
2
7
  rubocop-shopify: rubocop.yml
3
8
 
@@ -10,3 +15,11 @@ AllCops:
10
15
  SuggestExtensions: false
11
16
  TargetRubyVersion: 3.4
12
17
  UseCache: true
18
+
19
+ Sorbet/FalseSigil:
20
+ Enabled: true
21
+ Include:
22
+ - "lib/**/*.rb"
23
+ Exclude:
24
+ - "test/**/*"
25
+ - "examples/**/*"
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,21 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2025-08-17 17:40:01 UTC using RuboCop version 1.77.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 4
10
+ Sorbet/ConstantsFromStrings:
11
+ Exclude:
12
+ - 'lib/roast/helpers/logger.rb'
13
+ - 'lib/roast/workflow/step_loader.rb'
14
+ - 'lib/roast/workflow/validators/dependency_validator.rb'
15
+ - 'lib/roast/workflow/workflow_initializer.rb'
16
+
17
+ # Offense count: 1
18
+ # This cop supports safe autocorrection (--autocorrect).
19
+ Sorbet/SelectByIsA:
20
+ Exclude:
21
+ - 'lib/roast/workflow/configuration_loader.rb'
data/CHANGELOG.md CHANGED
@@ -5,6 +5,35 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.4.5]
9
+
10
+ ### Added
11
+ - **Sorbet static type checking** (#359, #360, #362)
12
+ - Initial setup of Sorbet for static type analysis
13
+ - Added `bin/srb tc` command for type checking
14
+ - Gradually adding type signatures to improve code safety and navigation
15
+ - Fixed invalid constants that were undefined and never reached
16
+ - Added to CI pipeline for continuous type checking
17
+ - **Workflow name in step event payloads** (#333, #351)
18
+ - Added `workflow_name` field to all step-related ActiveSupport::Notification events
19
+ - Enables better tracking of which workflow a step belongs to in monitoring systems
20
+ - Updated events: `roast.step.start`, `roast.step.complete`, `roast.step.error`
21
+
22
+ ### Changed
23
+ - **Improved error output formatting** (#358)
24
+ - Error messages now show concise output by default (just the error message)
25
+ - Full exception details and stack traces only shown in verbose mode (`-v`)
26
+ - Makes error output cleaner and more user-friendly
27
+ - **Consolidated workflow runner architecture** (#355)
28
+ - Merged ConfigurationParser functionality into WorkflowRunner for better cohesion
29
+ - Simplified the codebase by removing redundant abstraction layers
30
+
31
+ ### Fixed
32
+ - **Removed duplicated pre/post processing code** (#357)
33
+ - Extracted common pre/post processing logic from individual step executors
34
+ - Eliminated code duplication across different step types
35
+ - Improved maintainability and consistency
36
+
8
37
  ## [0.4.3] - 2025-07-10
9
38
 
10
39
  ### Changed
data/Gemfile CHANGED
@@ -15,8 +15,12 @@ gem "guard-minitest"
15
15
  gem "mocha"
16
16
  gem "rake", require: false
17
17
  gem "rubocop-shopify", require: false
18
+ gem "rubocop-sorbet", require: false
18
19
  gem "vcr", require: false
19
20
  gem "webmock", require: false
20
21
  gem "minitest-rg"
21
22
 
23
+ gem "sorbet", require: false
24
+ gem "tapioca", require: false
25
+
22
26
  gem "claude_swarm"
data/Gemfile.lock CHANGED
@@ -1,14 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- roast-ai (0.4.3)
4
+ roast-ai (0.4.5)
5
5
  activesupport (>= 7.0)
6
6
  cli-kit (~> 5.0)
7
7
  cli-ui (= 2.3.0)
8
8
  diff-lcs (~> 1.5)
9
9
  json-schema
10
10
  open_router (~> 0.3)
11
- raix-openai-eight (~> 1.0)
11
+ raix (~> 1.0.2)
12
12
  ruby-graphviz (~> 1.2)
13
13
  sqlite3 (~> 2.6)
14
14
  thor (~> 1.3)
@@ -81,6 +81,7 @@ GEM
81
81
  dry-inflector (~> 1.0)
82
82
  dry-logic (~> 1.4)
83
83
  zeitwerk (~> 2.6)
84
+ erubi (1.13.1)
84
85
  event_stream_parser (1.0.0)
85
86
  faraday (2.13.1)
86
87
  faraday-net_http (>= 2.0, < 3.5)
@@ -99,16 +100,8 @@ GEM
99
100
  json (~> 2.0)
100
101
  mime-types (~> 3.4)
101
102
  rack (< 3)
102
- ffi (1.17.2-aarch64-linux-gnu)
103
- ffi (1.17.2-aarch64-linux-musl)
104
- ffi (1.17.2-arm-linux-gnu)
105
- ffi (1.17.2-arm-linux-musl)
106
103
  ffi (1.17.2-arm64-darwin)
107
- ffi (1.17.2-x86-linux-gnu)
108
- ffi (1.17.2-x86-linux-musl)
109
- ffi (1.17.2-x86_64-darwin)
110
104
  ffi (1.17.2-x86_64-linux-gnu)
111
- ffi (1.17.2-x86_64-linux-musl)
112
105
  formatador (1.1.0)
113
106
  guard (2.19.1)
114
107
  formatador (>= 0.2.4)
@@ -153,6 +146,7 @@ GEM
153
146
  nenv (0.3.0)
154
147
  net-http (0.6.0)
155
148
  uri
149
+ netrc (0.11.0)
156
150
  notiffany (0.1.3)
157
151
  nenv (~> 0.1)
158
152
  shellany (~> 0.0)
@@ -174,7 +168,7 @@ GEM
174
168
  racc (1.8.1)
175
169
  rack (2.2.17)
176
170
  rainbow (3.1.1)
177
- raix-openai-eight (1.0.1)
171
+ raix (1.0.2)
178
172
  activesupport (>= 6.0)
179
173
  faraday-retry (~> 2.0)
180
174
  open_router (~> 0.2)
@@ -184,6 +178,11 @@ GEM
184
178
  rb-fsevent (0.11.2)
185
179
  rb-inotify (0.11.1)
186
180
  ffi (~> 1.0)
181
+ rbi (0.3.6)
182
+ prism (~> 1.0)
183
+ rbs (>= 3.4.4)
184
+ rbs (3.9.4)
185
+ logger
187
186
  regexp_parser (2.10.0)
188
187
  rexml (3.4.1)
189
188
  rubocop (1.77.0)
@@ -202,6 +201,9 @@ GEM
202
201
  prism (~> 1.4)
203
202
  rubocop-shopify (2.17.1)
204
203
  rubocop (~> 1.62)
204
+ rubocop-sorbet (0.10.5)
205
+ lint_roller
206
+ rubocop (>= 1.75.2)
205
207
  ruby-graphviz (1.2.5)
206
208
  rexml
207
209
  ruby-openai (8.1.0)
@@ -212,17 +214,34 @@ GEM
212
214
  ruby2_keywords (0.0.5)
213
215
  securerandom (0.4.1)
214
216
  shellany (0.0.1)
215
- sqlite3 (2.7.0-aarch64-linux-gnu)
216
- sqlite3 (2.7.0-aarch64-linux-musl)
217
- sqlite3 (2.7.0-arm-linux-gnu)
218
- sqlite3 (2.7.0-arm-linux-musl)
217
+ sorbet (0.5.12414)
218
+ sorbet-static (= 0.5.12414)
219
+ sorbet-runtime (0.5.12414)
220
+ sorbet-static (0.5.12414-universal-darwin)
221
+ sorbet-static (0.5.12414-x86_64-linux)
222
+ sorbet-static-and-runtime (0.5.12414)
223
+ sorbet (= 0.5.12414)
224
+ sorbet-runtime (= 0.5.12414)
225
+ spoom (1.6.3)
226
+ erubi (>= 1.10.0)
227
+ prism (>= 0.28.0)
228
+ rbi (>= 0.3.3)
229
+ rexml (>= 3.2.6)
230
+ sorbet-static-and-runtime (>= 0.5.10187)
231
+ thor (>= 0.19.2)
219
232
  sqlite3 (2.7.0-arm64-darwin)
220
- sqlite3 (2.7.0-x86-linux-gnu)
221
- sqlite3 (2.7.0-x86-linux-musl)
222
- sqlite3 (2.7.0-x86_64-darwin)
223
233
  sqlite3 (2.7.0-x86_64-linux-gnu)
224
- sqlite3 (2.7.0-x86_64-linux-musl)
225
- thor (1.3.2)
234
+ tapioca (0.16.11)
235
+ benchmark
236
+ bundler (>= 2.2.25)
237
+ netrc (>= 0.11.0)
238
+ parallel (>= 1.21.0)
239
+ rbi (~> 0.2)
240
+ sorbet-static-and-runtime (>= 0.5.11087)
241
+ spoom (>= 1.2.0)
242
+ thor (>= 1.2.0)
243
+ yard-sorbet
244
+ thor (1.4.0)
226
245
  tzinfo (2.0.6)
227
246
  concurrent-ruby (~> 1.0)
228
247
  unicode-display_width (3.1.4)
@@ -235,19 +254,15 @@ GEM
235
254
  addressable (>= 2.8.0)
236
255
  crack (>= 0.3.2)
237
256
  hashdiff (>= 0.4.0, < 2.0.0)
257
+ yard (0.9.37)
258
+ yard-sorbet (0.9.0)
259
+ sorbet-runtime
260
+ yard
238
261
  zeitwerk (2.7.3)
239
262
 
240
263
  PLATFORMS
241
- aarch64-linux-gnu
242
- aarch64-linux-musl
243
- arm-linux-gnu
244
- arm-linux-musl
245
264
  arm64-darwin
246
- x86-linux-gnu
247
- x86-linux-musl
248
- x86_64-darwin
249
- x86_64-linux-gnu
250
- x86_64-linux-musl
265
+ x86_64-linux
251
266
 
252
267
  DEPENDENCIES
253
268
  cgi
@@ -261,6 +276,9 @@ DEPENDENCIES
261
276
  rake
262
277
  roast-ai!
263
278
  rubocop-shopify
279
+ rubocop-sorbet
280
+ sorbet
281
+ tapioca
264
282
  vcr
265
283
  webmock
266
284
 
data/bin/rubocop ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rubocop' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("rubocop", "rubocop")
data/bin/spoom ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'spoom' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("spoom", "spoom")
data/bin/srb ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'srb' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("sorbet", "srb")
data/bin/srb-rbi ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'srb-rbi' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("sorbet", "srb-rbi")
data/bin/tapioca ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'tapioca' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("tapioca", "tapioca")
@@ -39,13 +39,13 @@ your-project/
39
39
  ### Step Events
40
40
 
41
41
  - `roast.step.start` - Emitted when a step begins execution
42
- - Payload: `{ step_name: }`
42
+ - Payload: `{ step_name:, resource_type:, workflow_name: }`
43
43
 
44
44
  - `roast.step.complete` - Emitted when a step completes successfully
45
- - Payload: `{ step_name:, success: true, execution_time:, result_size: }`
45
+ - Payload: `{ step_name:, resource_type:, workflow_name:, success: true, execution_time:, result_size: }`
46
46
 
47
47
  - `roast.step.error` - Emitted when a step encounters an error
48
- - Payload: `{ step_name:, error:, message:, execution_time: }`
48
+ - Payload: `{ step_name:, resource_type:, workflow_name:, error:, message:, execution_time: }`
49
49
 
50
50
  ### AI/Chat Completion Events
51
51
 
data/dsl/simple.rb ADDED
@@ -0,0 +1,10 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ #: self as Roast::DSL::Executor
5
+
6
+ # This is a dead simple workflow that calls two shell scripts
7
+ shell <<~SHELLSTEP
8
+ echo "I have no idea what's going on"
9
+ SHELLSTEP
10
+ shell "pwd"
@@ -0,0 +1,26 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Roast
5
+ module DSL
6
+ class Executor
7
+ class << self
8
+ def from_file(workflow_path)
9
+ execute(File.read(workflow_path))
10
+ end
11
+
12
+ private
13
+
14
+ def execute(input)
15
+ new.instance_eval(input)
16
+ end
17
+ end
18
+
19
+ # Define methods to be used in workflows below.
20
+
21
+ def shell(command_string)
22
+ puts %x(#{command_string})
23
+ end
24
+ end
25
+ end
26
+ end
data/lib/roast/dsl.rb ADDED
@@ -0,0 +1,7 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Roast
5
+ module DSL
6
+ end
7
+ end
data/lib/roast/errors.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Roast
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Roast
@@ -1,9 +1,12 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Roast
4
5
  module Helpers
5
6
  # Intercepts function dispatching to add caching capabilities
6
7
  # This module wraps around Raix::FunctionDispatch to provide caching for tool functions
8
+ # @requires_ancestor: Kernel
9
+ # @requires_ancestor: Raix::ChatCompletion
7
10
  module FunctionCachingInterceptor
8
11
  def dispatch_tool_function(function_name, params)
9
12
  start_time = Time.now
@@ -1,28 +1,25 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Roast
4
5
  module Helpers
5
6
  # Central logger for the Roast application
6
7
  class Logger
7
- VALID_LOG_LEVELS = ["DEBUG", "INFO", "WARN", "ERROR", "FATAL"].freeze
8
+ VALID_LOG_LEVELS = ["DEBUG", "INFO", "WARN", "ERROR", "FATAL"].freeze #: Array[String]
8
9
 
9
- delegate_missing_to :@logger
10
+ delegate :debug, :info, :warn, :error, :fatal, to: :@logger
10
11
 
11
12
  attr_reader :logger
12
13
 
13
14
  class << self
14
- delegate_missing_to :instance
15
+ delegate :debug, :info, :warn, :error, :fatal, to: :instance
15
16
 
17
+ #: -> Roast::Helpers::Logger
16
18
  def instance
17
19
  @instance ||= new
18
20
  end
19
21
 
20
- # Override Kernel#warn to ensure proper delegation
21
- def warn(*args)
22
- instance.warn(*args)
23
- end
24
-
25
- # For testing purposes
22
+ #: -> void
26
23
  def reset
27
24
  @instance = nil
28
25
  end
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Roast
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require "coverage"
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Roast
@@ -38,17 +39,14 @@ module Roast
38
39
  next if i == 0 # Skip the first segment
39
40
 
40
41
  # Check if this segment appears earlier in the path
41
- next unless path_parts[0...i].include?(part)
42
+ next unless path_parts[0...i]&.include?(part)
42
43
 
43
44
  # Create a new path without this segment
44
45
  test_parts = path_parts.dup
45
46
  test_parts.delete_at(i)
47
+ test_parts.prepend("/") if original_path.start_with?("/")
46
48
 
47
- test_path = if original_path.start_with?("/")
48
- File.join("/", *test_parts)
49
- else
50
- File.join(test_parts)
51
- end
49
+ test_path = File.join(test_parts)
52
50
 
53
51
  # If this path exists, return it
54
52
  return test_path if File.exist?(test_path)
@@ -66,12 +64,8 @@ module Roast
66
64
  filtered_parts = path_parts.dup
67
65
  # Remove from end to beginning to keep indices valid
68
66
  duplicate_indices.reverse_each { |idx| filtered_parts.delete_at(idx) }
69
-
70
- test_path = if original_path.start_with?("/")
71
- File.join("/", *filtered_parts)
72
- else
73
- File.join(filtered_parts)
74
- end
67
+ filtered_parts.prepend("/") if original_path.start_with?("/")
68
+ test_path = File.join(filtered_parts)
75
69
 
76
70
  return test_path if File.exist?(test_path)
77
71
  end
@@ -93,12 +87,8 @@ module Roast
93
87
  unique_parts = path_parts.dup
94
88
  # Remove from end to beginning to keep indices valid
95
89
  duplicate_indices.reverse_each { |i| unique_parts.delete_at(i) }
96
-
97
- test_path = if original_path.start_with?("/")
98
- File.join("/", *unique_parts)
99
- else
100
- File.join(unique_parts)
101
- end
90
+ unique_parts.prepend("/") if original_path.start_with?("/")
91
+ test_path = File.join(unique_parts)
102
92
 
103
93
  return test_path if File.exist?(test_path)
104
94
  end
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Roast
@@ -58,7 +59,7 @@ module Roast
58
59
  glob_pattern = File.join(context_dir, "{#{base_name},prompt}.*+*.md")
59
60
  Dir.glob(glob_pattern).each do |combined_path|
60
61
  basename = File.basename(combined_path, ".md")
61
- combined_exts = basename.split(".", 2)[1].split("+")
62
+ combined_exts = basename.split(".", 2)[1]&.split("+")
62
63
 
63
64
  # Return the first matching combined format
64
65
  return combined_path if extensions.intersect?(combined_exts)
@@ -77,7 +78,7 @@ module Roast
77
78
 
78
79
  if file_basename.end_with?(".md") && file_basename.count(".") > 1
79
80
  without_md = file_basename[0...-3] # Remove .md
80
- without_md.split(".", 2)[1]&.split("+") || []
81
+ without_md&.split(".", 2)&.[](1)&.split("+") || []
81
82
  else
82
83
  ext = File.extname(target_file)[1..]
83
84
  ext&.empty? ? [] : [ext]