roast-ai 0.1.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yaml +1 -1
  3. data/CHANGELOG.md +48 -0
  4. data/CLAUDE.md +20 -0
  5. data/Gemfile +1 -0
  6. data/Gemfile.lock +11 -6
  7. data/README.md +225 -13
  8. data/bin/roast +27 -0
  9. data/docs/INSTRUMENTATION.md +42 -1
  10. data/docs/ITERATION_SYNTAX.md +119 -0
  11. data/examples/conditional/README.md +161 -0
  12. data/examples/conditional/check_condition/prompt.md +1 -0
  13. data/examples/conditional/simple_workflow.yml +15 -0
  14. data/examples/conditional/workflow.yml +23 -0
  15. data/examples/dot_notation/README.md +37 -0
  16. data/examples/dot_notation/workflow.yml +44 -0
  17. data/examples/exit_on_error/README.md +50 -0
  18. data/examples/exit_on_error/analyze_lint_output/prompt.md +9 -0
  19. data/examples/exit_on_error/apply_fixes/prompt.md +2 -0
  20. data/examples/exit_on_error/workflow.yml +19 -0
  21. data/examples/grading/workflow.yml +5 -1
  22. data/examples/iteration/IMPLEMENTATION.md +88 -0
  23. data/examples/iteration/README.md +68 -0
  24. data/examples/iteration/analyze_complexity/prompt.md +22 -0
  25. data/examples/iteration/generate_recommendations/prompt.md +21 -0
  26. data/examples/iteration/generate_report/prompt.md +129 -0
  27. data/examples/iteration/implement_fix/prompt.md +25 -0
  28. data/examples/iteration/prioritize_issues/prompt.md +24 -0
  29. data/examples/iteration/prompts/analyze_file.md +28 -0
  30. data/examples/iteration/prompts/generate_summary.md +24 -0
  31. data/examples/iteration/prompts/update_report.md +29 -0
  32. data/examples/iteration/prompts/write_report.md +22 -0
  33. data/examples/iteration/read_file/prompt.md +9 -0
  34. data/examples/iteration/select_next_issue/prompt.md +25 -0
  35. data/examples/iteration/simple_workflow.md +39 -0
  36. data/examples/iteration/simple_workflow.yml +58 -0
  37. data/examples/iteration/update_fix_count/prompt.md +26 -0
  38. data/examples/iteration/verify_fix/prompt.md +29 -0
  39. data/examples/iteration/workflow.yml +42 -0
  40. data/examples/openrouter_example/workflow.yml +2 -2
  41. data/examples/workflow_generator/README.md +27 -0
  42. data/examples/workflow_generator/analyze_user_request/prompt.md +34 -0
  43. data/examples/workflow_generator/create_workflow_files/prompt.md +32 -0
  44. data/examples/workflow_generator/get_user_input/prompt.md +14 -0
  45. data/examples/workflow_generator/info_from_roast.rb +22 -0
  46. data/examples/workflow_generator/workflow.yml +35 -0
  47. data/lib/roast/errors.rb +9 -0
  48. data/lib/roast/factories/api_provider_factory.rb +61 -0
  49. data/lib/roast/helpers/function_caching_interceptor.rb +1 -1
  50. data/lib/roast/helpers/minitest_coverage_runner.rb +1 -1
  51. data/lib/roast/helpers/prompt_loader.rb +50 -1
  52. data/lib/roast/resources/base_resource.rb +7 -0
  53. data/lib/roast/resources.rb +6 -6
  54. data/lib/roast/tools/ask_user.rb +40 -0
  55. data/lib/roast/tools/cmd.rb +1 -1
  56. data/lib/roast/tools/search_file.rb +1 -1
  57. data/lib/roast/tools/update_files.rb +413 -0
  58. data/lib/roast/tools.rb +12 -1
  59. data/lib/roast/value_objects/api_token.rb +49 -0
  60. data/lib/roast/value_objects/step_name.rb +39 -0
  61. data/lib/roast/value_objects/workflow_path.rb +77 -0
  62. data/lib/roast/value_objects.rb +5 -0
  63. data/lib/roast/version.rb +1 -1
  64. data/lib/roast/workflow/api_configuration.rb +61 -0
  65. data/lib/roast/workflow/base_iteration_step.rb +165 -0
  66. data/lib/roast/workflow/base_step.rb +4 -24
  67. data/lib/roast/workflow/base_workflow.rb +76 -73
  68. data/lib/roast/workflow/command_executor.rb +88 -0
  69. data/lib/roast/workflow/conditional_executor.rb +50 -0
  70. data/lib/roast/workflow/conditional_step.rb +96 -0
  71. data/lib/roast/workflow/configuration.rb +35 -158
  72. data/lib/roast/workflow/configuration_loader.rb +78 -0
  73. data/lib/roast/workflow/configuration_parser.rb +13 -248
  74. data/lib/roast/workflow/context_path_resolver.rb +43 -0
  75. data/lib/roast/workflow/dot_access_hash.rb +198 -0
  76. data/lib/roast/workflow/each_step.rb +86 -0
  77. data/lib/roast/workflow/error_handler.rb +97 -0
  78. data/lib/roast/workflow/expression_utils.rb +36 -0
  79. data/lib/roast/workflow/file_state_repository.rb +3 -2
  80. data/lib/roast/workflow/interpolator.rb +34 -0
  81. data/lib/roast/workflow/iteration_executor.rb +85 -0
  82. data/lib/roast/workflow/llm_boolean_coercer.rb +55 -0
  83. data/lib/roast/workflow/output_handler.rb +35 -0
  84. data/lib/roast/workflow/output_manager.rb +77 -0
  85. data/lib/roast/workflow/parallel_executor.rb +49 -0
  86. data/lib/roast/workflow/repeat_step.rb +75 -0
  87. data/lib/roast/workflow/replay_handler.rb +123 -0
  88. data/lib/roast/workflow/resource_resolver.rb +77 -0
  89. data/lib/roast/workflow/session_manager.rb +6 -2
  90. data/lib/roast/workflow/state_manager.rb +97 -0
  91. data/lib/roast/workflow/step_executor_coordinator.rb +205 -0
  92. data/lib/roast/workflow/step_executor_factory.rb +47 -0
  93. data/lib/roast/workflow/step_executor_registry.rb +79 -0
  94. data/lib/roast/workflow/step_executors/base_step_executor.rb +23 -0
  95. data/lib/roast/workflow/step_executors/hash_step_executor.rb +43 -0
  96. data/lib/roast/workflow/step_executors/parallel_step_executor.rb +54 -0
  97. data/lib/roast/workflow/step_executors/string_step_executor.rb +29 -0
  98. data/lib/roast/workflow/step_finder.rb +97 -0
  99. data/lib/roast/workflow/step_loader.rb +154 -0
  100. data/lib/roast/workflow/step_orchestrator.rb +45 -0
  101. data/lib/roast/workflow/step_runner.rb +23 -0
  102. data/lib/roast/workflow/step_type_resolver.rb +117 -0
  103. data/lib/roast/workflow/workflow_context.rb +60 -0
  104. data/lib/roast/workflow/workflow_executor.rb +90 -209
  105. data/lib/roast/workflow/workflow_initializer.rb +112 -0
  106. data/lib/roast/workflow/workflow_runner.rb +87 -0
  107. data/lib/roast/workflow.rb +3 -0
  108. data/lib/roast.rb +96 -3
  109. data/roast.gemspec +3 -1
  110. data/schema/workflow.json +85 -0
  111. metadata +112 -4
@@ -0,0 +1,119 @@
1
+ # Using Iteration with Standardized Syntax
2
+
3
+ ## Overview
4
+
5
+ Roast supports powerful iteration constructs with the `repeat` and `each` workflow steps. These features now support a standardized approach to evaluating expressions using the double-curly braces syntax (`{{...}}`).
6
+
7
+ ## Syntax Options for Iteration Inputs
8
+
9
+ Both `until` conditions (in `repeat`) and collection expressions (in `each`) accept the following formats:
10
+
11
+ ### 1. Ruby Expressions with `{{...}}` Syntax
12
+
13
+ For evaluating Ruby code in the workflow context:
14
+
15
+ ```yaml
16
+ # Repeat until a condition is met
17
+ - repeat:
18
+ steps:
19
+ - process_item
20
+ until: "{{output['counter'] >= 5}}"
21
+ max_iterations: 10
22
+
23
+ # Iterate over a collection
24
+ - each: "{{output['items'].filter { |item| item.active? }}}"
25
+ as: "current_item"
26
+ steps:
27
+ - process_item
28
+ ```
29
+
30
+ ### 2. Bash Commands with `$(...)` Syntax
31
+
32
+ For executing shell commands and using their results:
33
+
34
+ ```yaml
35
+ # Repeat until a command succeeds
36
+ - repeat:
37
+ steps:
38
+ - check_service
39
+ until: "$(curl -s -o /dev/null -w '%{http_code}' http://service.local/ | grep -q 200)"
40
+ max_iterations: 20
41
+
42
+ # Iterate over files returned by a command
43
+ - each: "$(find . -name '*.rb' -type f)"
44
+ as: "current_file"
45
+ steps:
46
+ - process_file
47
+ ```
48
+
49
+ ### 3. Step Names (as strings)
50
+
51
+ For using the result of another step:
52
+
53
+ ```yaml
54
+ # Repeat until a step returns a truthy value
55
+ - repeat:
56
+ steps:
57
+ - process_batch
58
+ until: "check_completion"
59
+ max_iterations: 100
60
+
61
+ # Iterate over items returned by a step
62
+ - each: "get_pending_items"
63
+ as: "pending_item"
64
+ steps:
65
+ - process_pending_item
66
+ ```
67
+
68
+ ### 4. Prompt Content
69
+
70
+ For defining prompts directly in the workflow:
71
+
72
+ ```yaml
73
+ # Using a prompt to determine continuation
74
+ - repeat:
75
+ steps:
76
+ - process_content
77
+ until:
78
+ prompt: prompts/check_completion.md
79
+ model: claude-3-haiku
80
+ max_iterations: 10
81
+
82
+ # Using a prompt to generate a collection
83
+ - each:
84
+ prompt: prompts/generate_test_cases.md
85
+ model: claude-3-haiku
86
+ as: "test_case"
87
+ steps:
88
+ - run_test
89
+ ```
90
+
91
+ ## Type Coercion
92
+
93
+ Values are automatically coerced to the appropriate types:
94
+
95
+ - For `until` conditions: Values are coerced to booleans (using Ruby's truthiness rules)
96
+ - For `each` collections: Values are coerced to iterables (converted to arrays of lines if needed)
97
+
98
+ ## Migrating Existing Workflows
99
+
100
+ If you're updating existing workflows:
101
+
102
+ 1. For Ruby expressions, wrap them in `{{...}}`:
103
+ ```yaml
104
+ # Old
105
+ until: "output['counter'] >= 5"
106
+
107
+ # New
108
+ until: "{{output['counter'] >= 5}}"
109
+ ```
110
+
111
+ 2. Bash commands, step names, and prompts can remain unchanged.
112
+
113
+ ## Best Practices
114
+
115
+ - Use `{{...}}` for all Ruby expressions to make them explicit
116
+ - For complex conditions, consider creating a dedicated step that returns a boolean
117
+ - For collections, ensure they return iterable objects (arrays, hashes, etc.)
118
+ - Always set reasonable `max_iterations` limits on repeat loops
119
+ - Use meaningful variable names in `each` loops
@@ -0,0 +1,161 @@
1
+ # Conditional Execution in Roast Workflows
2
+
3
+ This example demonstrates how to use conditional execution (`if` and `unless`) in Roast workflows.
4
+
5
+ ## Overview
6
+
7
+ Conditional execution allows workflows to execute different steps based on runtime conditions. This feature supports:
8
+
9
+ - `if` conditions - execute steps when a condition is true
10
+ - `unless` conditions - execute steps when a condition is false
11
+ - `then` branches - steps to execute when the condition matches
12
+ - `else` branches - steps to execute when the condition doesn't match (optional, only for `if`)
13
+
14
+ ## Syntax
15
+
16
+ ### If Statement
17
+
18
+ ```yaml
19
+ - if: "{{expression}}"
20
+ then:
21
+ - step1
22
+ - step2
23
+ else:
24
+ - step3
25
+ - step4
26
+ ```
27
+
28
+ ### Unless Statement
29
+
30
+ ```yaml
31
+ - unless: "{{expression}}"
32
+ then:
33
+ - step1
34
+ - step2
35
+ ```
36
+
37
+ ## Condition Types
38
+
39
+ Conditions can be:
40
+
41
+ 1. **Ruby Expressions** - Wrapped in `{{...}}`
42
+ ```yaml
43
+ - if: "{{output.previous_step.success == true}}"
44
+ ```
45
+
46
+ 2. **Bash Commands** - Wrapped in `$(...)`
47
+ ```yaml
48
+ - if: "$(test -f /path/to/file && echo true || echo false)"
49
+ ```
50
+
51
+ 3. **Step References** - Reference to previous step output
52
+ ```yaml
53
+ - if: "check_condition" # References a previous step
54
+ ```
55
+
56
+ 4. **File Checks**
57
+ ```yaml
58
+ - if: "{{File.exist?('/tmp/myfile.txt')}}"
59
+ ```
60
+
61
+ ## Examples
62
+
63
+ ### Basic Example
64
+
65
+ ```yaml
66
+ name: Conditional Example
67
+ tools:
68
+ - Roast::Tools::Cmd
69
+
70
+ steps:
71
+ - check_status: "echo 'success'"
72
+
73
+ - if: "{{output.check_status.strip == 'success'}}"
74
+ then:
75
+ - success_action: "echo 'Operation succeeded!'"
76
+ else:
77
+ - failure_action: "echo 'Operation failed!'"
78
+ ```
79
+
80
+ ### Unless Example
81
+
82
+ ```yaml
83
+ name: Unless Example
84
+ tools: []
85
+
86
+ steps:
87
+ - check_file: "test -f /tmp/important.txt && echo exists || echo missing"
88
+
89
+ - unless: "{{output.check_file.strip == 'exists'}}"
90
+ then:
91
+ - create_file: "touch /tmp/important.txt"
92
+ - notify: "echo 'Created missing file'"
93
+ ```
94
+
95
+ ### Nested Conditionals
96
+
97
+ ```yaml
98
+ name: Nested Conditionals
99
+ tools: []
100
+
101
+ steps:
102
+ - outer_check: "echo 'true'"
103
+ - inner_check: "echo 'false'"
104
+
105
+ - if: "{{output.outer_check.strip == 'true'}}"
106
+ then:
107
+ - if: "{{output.inner_check.strip == 'true'}}"
108
+ then:
109
+ - both_true: "echo 'Both conditions are true'"
110
+ else:
111
+ - only_outer: "echo 'Only outer condition is true'"
112
+ else:
113
+ - outer_false: "echo 'Outer condition is false'"
114
+ ```
115
+
116
+ ### Platform-Specific Actions
117
+
118
+ ```yaml
119
+ name: Platform Detection
120
+ tools:
121
+ - Roast::Tools::Cmd
122
+
123
+ steps:
124
+ - detect_os: "uname -s"
125
+
126
+ - if: "{{output.detect_os.strip == 'Darwin'}}"
127
+ then:
128
+ - mac_setup: "brew --version || echo 'Homebrew not installed'"
129
+ else:
130
+ - if: "{{output.detect_os.strip == 'Linux'}}"
131
+ then:
132
+ - linux_setup: "apt-get --version || yum --version"
133
+ else:
134
+ - unknown_os: "echo 'Unknown operating system'"
135
+ ```
136
+
137
+ ## Best Practices
138
+
139
+ 1. **Use Clear Conditions**: Make your conditions explicit and easy to understand
140
+ 2. **Handle Edge Cases**: Always consider what happens when conditions fail
141
+ 3. **Test Both Branches**: Ensure both `then` and `else` branches work correctly
142
+ 4. **Avoid Deep Nesting**: Keep conditional logic simple and readable
143
+ 5. **Use Unless Sparingly**: `unless` can be less intuitive than `if` with negation
144
+
145
+ ## Debugging
146
+
147
+ To debug conditional execution:
148
+
149
+ 1. Check the workflow output to see which branch was executed
150
+ 2. Look for keys like `if_condition_name` or `unless_condition_name` in the output
151
+ 3. These keys contain information about the condition evaluation and branch taken
152
+
153
+ ## Running the Example
154
+
155
+ ```bash
156
+ # Run the simple conditional example
157
+ roast execute examples/conditional/simple_workflow.yml
158
+
159
+ # Run the full conditional example (requires API configuration)
160
+ roast execute examples/conditional/workflow.yml
161
+ ```
@@ -0,0 +1 @@
1
+ Check if the OS is macOS or Linux and return true if it's macOS, false otherwise.
@@ -0,0 +1,15 @@
1
+ name: Simple Conditional Test
2
+ tools: []
3
+
4
+ steps:
5
+ - set_value: "$(echo 'true')"
6
+
7
+ - if: "{{output.set_value.strip == 'true'}}"
8
+ then:
9
+ - success: "$(echo 'If condition worked!')"
10
+ else:
11
+ - failure: "$(echo 'If condition failed!')"
12
+
13
+ - unless: "{{output.set_value.strip == 'false'}}"
14
+ then:
15
+ - unless_success: "$(echo 'Unless condition worked!')"
@@ -0,0 +1,23 @@
1
+ name: Conditional Execution Example
2
+ tools:
3
+ - Roast::Tools::Cmd
4
+
5
+ steps:
6
+ - check_os: "$(uname -s)"
7
+
8
+ - if: "{{output.check_os.strip == 'Darwin'}}"
9
+ then:
10
+ - mac_message: "$(echo 'Running on macOS!')"
11
+ - mac_info: "$(sw_vers)"
12
+ else:
13
+ - linux_message: "$(echo 'Running on Linux!')"
14
+ - linux_info: "$(lsb_release -a)"
15
+
16
+ - check_file: "$(test -f /tmp/roast_test.txt && echo exists || echo missing)"
17
+
18
+ - unless: "{{output.check_file.strip == 'exists'}}"
19
+ then:
20
+ - create_file: "$(touch /tmp/roast_test.txt && echo 'File created')"
21
+
22
+ - verify_file: "$(ls -la /tmp/roast_test.txt)"
23
+ - cleanup: "$(rm -f /tmp/roast_test.txt)"
@@ -0,0 +1,37 @@
1
+ # Dot Notation Access Example
2
+
3
+ This example demonstrates the new dot notation access feature for workflow outputs.
4
+
5
+ ## Usage
6
+
7
+ With the new dot notation feature, you can access output values using Ruby's method syntax instead of hash syntax:
8
+
9
+ ### Before (hash syntax):
10
+ ```yaml
11
+ until: "output[:update_fix_count][:fixes_applied] >= 5 || output[:select_next_issue][:no_issues_left] == true"
12
+ ```
13
+
14
+ ### After (dot notation):
15
+ ```yaml
16
+ until: "output.update_fix_count.fixes_applied >= 5 || output.select_next_issue.no_issues_left?"
17
+ ```
18
+
19
+ ### Even cleaner (omitting output prefix):
20
+ ```yaml
21
+ until: "update_fix_count.fixes_applied >= 5 || select_next_issue.no_issues_left?"
22
+ ```
23
+
24
+ ## Features
25
+
26
+ 1. **Nested access**: `output.step_name.nested.value`
27
+ 2. **Boolean predicates**: `output.step_name.is_complete?` returns false for nil/false values
28
+ 3. **Direct access**: Omit the `output.` prefix for cleaner syntax
29
+ 4. **Backward compatible**: Hash syntax still works (`output[:step_name][:value]`)
30
+
31
+ ## Example Workflow
32
+
33
+ See `workflow.yml` for a complete example that demonstrates:
34
+ - Setting values in output
35
+ - Using dot notation in conditions
36
+ - Boolean predicate methods
37
+ - Nested value access
@@ -0,0 +1,44 @@
1
+ name: dot_notation_example
2
+ description: Example demonstrating dot notation access for workflow outputs
3
+
4
+ steps:
5
+ initialize:
6
+ prompt: |
7
+ Initialize the workflow with some sample data.
8
+
9
+ Set output.counter to 0
10
+ Set output.config.max_iterations to 5
11
+ Set output.config.enabled to true
12
+
13
+ process_items:
14
+ repeat:
15
+ # Using dot notation in conditions
16
+ until: "counter >= config.max_iterations || !config.enabled?"
17
+ steps:
18
+ - increment_counter
19
+ - check_status
20
+
21
+ increment_counter:
22
+ prompt: |
23
+ Increment the counter by 1.
24
+ Current counter value: {{counter}}
25
+
26
+ Set output.counter to {{counter}} + 1
27
+
28
+ check_status:
29
+ prompt: |
30
+ Check if we should continue processing.
31
+
32
+ Current counter: {{counter}}
33
+ Max iterations: {{config.max_iterations}}
34
+
35
+ If counter is 3, set output.config.enabled to false
36
+ Set output.status.last_checked to current counter value
37
+
38
+ summarize:
39
+ prompt: |
40
+ Summarize the results:
41
+ - Total iterations: {{counter}}
42
+ - Last checked at: {{status.last_checked}}
43
+ - Was enabled: {{config.enabled}}
44
+ - Hit max iterations: {{counter >= config.max_iterations ? "Yes" : "No"}}
@@ -0,0 +1,50 @@
1
+ # Exit on Error Example
2
+
3
+ This example demonstrates how to use the `exit_on_error` configuration option to continue workflow execution even when a command fails.
4
+
5
+ ## Use Case
6
+
7
+ When running a linter like RuboCop on a file with syntax errors or style violations, the command will exit with a non-zero status. By default, this would halt the workflow. However, we often want to:
8
+
9
+ 1. Capture the linter output (including errors)
10
+ 2. Analyze what went wrong
11
+ 3. Apply fixes based on the analysis
12
+
13
+ ## Configuration
14
+
15
+ The key configuration is in the step configuration section:
16
+
17
+ ```yaml
18
+ lint_check:
19
+ exit_on_error: false
20
+ ```
21
+
22
+ This tells Roast to:
23
+ - Continue workflow execution even if the command fails
24
+ - Capture the full output (stdout and stderr)
25
+ - Append the exit status to the output
26
+
27
+ ## Output Format
28
+
29
+ When a command fails with `exit_on_error: false`, the output will look like:
30
+
31
+ ```
32
+ lib/example.rb:5:3: C: Style/StringLiterals: Prefer double-quoted strings
33
+ 'hello'
34
+ ^^^^^^^
35
+ [Exit status: 1]
36
+ ```
37
+
38
+ This allows subsequent steps to process both the error output and the exit status.
39
+
40
+ ## Running the Example
41
+
42
+ ```bash
43
+ roast execute workflow.yml path/to/file.rb
44
+ ```
45
+
46
+ The workflow will:
47
+ 1. Run RuboCop on the file
48
+ 2. Continue even if RuboCop finds issues
49
+ 3. Analyze the linter output
50
+ 4. Apply fixes based on the analysis
@@ -0,0 +1,9 @@
1
+ The linter output from the previous step shows issues with the code.
2
+ Please analyze the output and identify the specific problems that need to be fixed.
3
+
4
+ Focus on:
5
+ - Syntax errors
6
+ - Style violations
7
+ - Best practice violations
8
+
9
+ Provide a structured list of issues found.
@@ -0,0 +1,2 @@
1
+ Based on the analysis, please generate the fixes for the identified issues.
2
+ Use the CodingAgent tool to apply the necessary changes to the file.
@@ -0,0 +1,19 @@
1
+ name: Linting with Error Recovery
2
+ tools:
3
+ - Roast::Tools::ReadFile
4
+ - Roast::Tools::WriteFile
5
+ - Roast::Tools::CodingAgent
6
+
7
+ steps:
8
+ # Run linter on the file - may fail if there are syntax errors
9
+ - lint_check: $(rubocop {{file}})
10
+
11
+ # Analyze linter output and fix issues even if linter failed
12
+ - analyze_lint_output
13
+
14
+ # Apply fixes based on the analysis
15
+ - apply_fixes
16
+
17
+ # Step configuration
18
+ lint_check:
19
+ exit_on_error: false # Continue even if rubocop exits with non-zero status
@@ -1,10 +1,12 @@
1
- name: Grading current test changes
1
+ name: Test Grading
2
+ model: anthropic:claude-opus-4
2
3
 
3
4
  tools:
4
5
  - Roast::Tools::Grep
5
6
  - Roast::Tools::ReadFile
6
7
  - Roast::Tools::SearchFile
7
8
 
9
+ # Uncomment this to run the workflow on modified tests automatically
8
10
  # each: '% cd $(git rev-parse --show-toplevel) && git status --porcelain | grep "_test\.rb" | cut -c4- | xargs realpath'
9
11
 
10
12
  steps:
@@ -35,3 +37,5 @@ generate_recommendations:
35
37
  json: true
36
38
  params:
37
39
  max_completion_tokens: 5_000
40
+
41
+
@@ -0,0 +1,88 @@
1
+ # Iteration Mechanisms Implementation
2
+
3
+ This document provides an overview of how the iteration mechanisms are implemented in Roast.
4
+
5
+ ## Core Components
6
+
7
+ ### 1. Schema Extensions
8
+
9
+ The workflow schema has been extended to support two new iteration constructs:
10
+
11
+ - **Repeat** - For conditional repetition until a condition is met
12
+ - **Each** - For iterating over collections with a variable binding
13
+
14
+ These schema extensions define the structure and validation rules for the iteration YAML syntax.
15
+
16
+ ### 2. Step Classes
17
+
18
+ Two new step classes handle the actual iteration logic:
19
+
20
+ - **RepeatStep** - Executes steps repeatedly until a condition is met or a maximum iteration count is reached
21
+ - **EachStep** - Iterates over a collection, binding each item to a variable, and executes steps for each item
22
+
23
+ Both inherit from a common `BaseIterationStep` class that provides shared functionality.
24
+
25
+ ### 3. Pattern Matching
26
+
27
+ The `WorkflowExecutor` has been enhanced with pattern matching to recognize the `repeat` and `each` keywords and dispatch to the appropriate step classes:
28
+
29
+ ```ruby
30
+ case name
31
+ when "repeat"
32
+ execute_repeat_step(command)
33
+ when "each"
34
+ # Handle 'each' step with its special format
35
+ execute_each_step(step)
36
+ else
37
+ # Handle regular steps
38
+ end
39
+ ```
40
+
41
+ ### 4. State Management
42
+
43
+ Both iteration types include state management to:
44
+
45
+ - Track current iteration number
46
+ - Save state after each iteration
47
+ - Support resumption after failures
48
+ - Provide safety limits against infinite loops
49
+
50
+ ## Iteration Flow
51
+
52
+ ### RepeatStep Flow
53
+
54
+ 1. Start with iteration count = 0
55
+ 2. Execute the nested steps in sequence
56
+ 3. Evaluate the until condition
57
+ 4. If condition is true or max_iterations is reached, stop
58
+ 5. Otherwise, increment iteration count and go back to step 2
59
+ 6. Return the results of all iterations
60
+
61
+ ### EachStep Flow
62
+
63
+ 1. Resolve the collection expression
64
+ 2. For each item in the collection:
65
+ a. Set the named variable (accessible in steps through a getter method)
66
+ b. Execute the nested steps
67
+ c. Save state
68
+ 3. Return the results from all iterations
69
+
70
+ ## Safety Mechanisms
71
+
72
+ - **max_iterations** parameter prevents infinite loops
73
+ - State is saved after each iteration for resumption capability
74
+ - Robust error handling during condition evaluation and step execution
75
+ - Collection type checking ensures iterable objects
76
+
77
+ ## Usage Examples
78
+
79
+ The workflow.yml and step files in this directory demonstrate practical applications of these iteration mechanisms for code quality analysis.
80
+
81
+ ## Integration with Existing Workflow Engine
82
+
83
+ The iteration mechanism integrates seamlessly with the existing workflow engine:
84
+
85
+ - Uses the same state persistence mechanisms
86
+ - Follows the same execution models
87
+ - Maintains compatibility with all existing steps
88
+ - Supports interpolation within iteration constructs
@@ -0,0 +1,68 @@
1
+ # Code Quality Analysis Workflow
2
+
3
+ This example demonstrates the use of Roast's iteration features to analyze and improve code quality across a codebase.
4
+
5
+ ## What it does
6
+
7
+ 1. Collects Ruby files from the codebase for analysis
8
+ 2. Analyzes each file for complexity, code smells, and potential improvements
9
+ 3. Generates recommendations for each file
10
+ 4. Prioritizes the identified issues by impact and difficulty
11
+ 5. Automatically implements fixes for the highest-priority issues
12
+ 6. Verifies each fix before moving to the next one
13
+ 7. Continues until either 5 fixes have been applied or all issues are addressed
14
+ 8. Generates a summary report of changes made
15
+
16
+ ## Iteration Features Demonstrated
17
+
18
+ ### Collection Iteration with `each`
19
+
20
+ The workflow uses the `each` construct to iterate through Ruby files:
21
+
22
+ ```yaml
23
+ - each: "output['get_files_to_analyze'].split('\n')"
24
+ as: "current_file"
25
+ steps:
26
+ - read_file
27
+ - analyze_complexity
28
+ - generate_recommendations
29
+ ```
30
+
31
+ This makes the current file available as `current_file` in each step, allowing the analysis steps to process each file individually.
32
+
33
+ ### Conditional Repetition with `repeat`
34
+
35
+ The workflow uses the `repeat` construct to iteratively fix issues until a condition is met:
36
+
37
+ ```yaml
38
+ - repeat:
39
+ steps:
40
+ - select_next_issue
41
+ - implement_fix
42
+ - verify_fix
43
+ - update_fix_count
44
+ until: "output['update_fix_count']['fixes_applied'] >= 5 || output['select_next_issue']['no_issues_left'] == true"
45
+ max_iterations: 10
46
+ ```
47
+
48
+ This continues applying fixes until either:
49
+ - 5 fixes have been successfully applied
50
+ - No more issues remain to be fixed
51
+ - The maximum of 10 iterations is reached (safety limit)
52
+
53
+ ## Running the Example
54
+
55
+ To run this workflow:
56
+
57
+ ```bash
58
+ roast run examples/iteration/workflow.yml --target=/path/to/your/project
59
+ ```
60
+
61
+ The workflow will analyze the Ruby files in your project, suggest improvements, and apply the highest-priority fixes.
62
+
63
+ ## Customizing
64
+
65
+ - Adjust the file selection criteria in `get_files_to_analyze`
66
+ - Modify the analysis criteria in `analyze_complexity`
67
+ - Change the fix limit in the `until` condition
68
+ - Set a different `max_iterations` value to control the maximum number of fixes
@@ -0,0 +1,22 @@
1
+ I'll analyze the code complexity of the file {{current_file}}, which I've read in the previous step.
2
+
3
+ I'll examine the following aspects:
4
+ 1. Cyclomatic complexity (number of decision paths)
5
+ 2. Method length and complexity
6
+ 3. Class size and responsibilities
7
+ 4. Code smells (long parameter lists, deeply nested blocks, etc.)
8
+ 5. Potential performance bottlenecks
9
+ 6. Opportunities for refactoring
10
+
11
+ ```ruby
12
+ {{output.read_file}}
13
+ ```
14
+
15
+ Based on this analysis, I'll provide a structured assessment of the code quality issues found.
16
+
17
+ For each issue identified, I'll assign:
18
+ - Severity (high, medium, low)
19
+ - Type (complexity, maintainability, performance, style)
20
+ - Location (line numbers, method/class names)
21
+ - Brief description of the issue
22
+ - Suggested improvement