cleo_quality_review 0.1.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 (45) hide show
  1. checksums.yaml +7 -0
  2. data/cleo_quality_review.gemspec +31 -0
  3. data/config/default.yml +7 -0
  4. data/exe/check_quality +20 -0
  5. data/lib/cleo_quality_review/changes_diff.rb +67 -0
  6. data/lib/cleo_quality_review/checks/debride.rb +65 -0
  7. data/lib/cleo_quality_review/checks/fasterer.rb +35 -0
  8. data/lib/cleo_quality_review/checks/flog.rb +35 -0
  9. data/lib/cleo_quality_review/checks/quality_check.rb +143 -0
  10. data/lib/cleo_quality_review/checks/reek.rb +53 -0
  11. data/lib/cleo_quality_review/checks/registry.rb +72 -0
  12. data/lib/cleo_quality_review/checks.rb +38 -0
  13. data/lib/cleo_quality_review/cli.rb +105 -0
  14. data/lib/cleo_quality_review/command_result.rb +21 -0
  15. data/lib/cleo_quality_review/command_runner.rb +27 -0
  16. data/lib/cleo_quality_review/configuration.rb +193 -0
  17. data/lib/cleo_quality_review/diff_map.rb +95 -0
  18. data/lib/cleo_quality_review/formatter.rb +58 -0
  19. data/lib/cleo_quality_review/github_review_builder.rb +140 -0
  20. data/lib/cleo_quality_review/github_review_publisher.rb +150 -0
  21. data/lib/cleo_quality_review/llm_client.rb +59 -0
  22. data/lib/cleo_quality_review/llm_config.rb +40 -0
  23. data/lib/cleo_quality_review/llm_errors.rb +19 -0
  24. data/lib/cleo_quality_review/llm_logger.rb +66 -0
  25. data/lib/cleo_quality_review/llm_providers/open_ai.rb +188 -0
  26. data/lib/cleo_quality_review/llm_providers/open_ai_config.rb +83 -0
  27. data/lib/cleo_quality_review/llm_providers/registry.rb +61 -0
  28. data/lib/cleo_quality_review/llm_providers/stub.rb +107 -0
  29. data/lib/cleo_quality_review/llm_providers.rb +44 -0
  30. data/lib/cleo_quality_review/options.rb +171 -0
  31. data/lib/cleo_quality_review/prompt_builder.rb +95 -0
  32. data/lib/cleo_quality_review/prompt_loader.rb +49 -0
  33. data/lib/cleo_quality_review/result.rb +58 -0
  34. data/lib/cleo_quality_review/run.rb +78 -0
  35. data/lib/cleo_quality_review/run_artifacts/raw_check_outputs.rb +97 -0
  36. data/lib/cleo_quality_review/run_artifacts.rb +146 -0
  37. data/lib/cleo_quality_review/runner.rb +158 -0
  38. data/lib/cleo_quality_review/target_resolver.rb +127 -0
  39. data/lib/cleo_quality_review/version.rb +7 -0
  40. data/lib/cleo_quality_review.rb +23 -0
  41. data/prompts/agent.md +53 -0
  42. data/prompts/github.md +29 -0
  43. data/prompts/human.md +23 -0
  44. data/prompts/pr_review.md +62 -0
  45. metadata +141 -0
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest"
4
+ require "json"
5
+
6
+ require_relative "changes_diff"
7
+ require_relative "checks"
8
+ require_relative "command_runner"
9
+ require_relative "run"
10
+ require_relative "run_artifacts"
11
+ require_relative "target_resolver"
12
+
13
+ module CleoQualityReview
14
+ ##
15
+ # Orchestrates a complete quality review run
16
+ class Runner
17
+ ##
18
+ # Grouped values resolved at the start of an analysis run
19
+ AnalysisContext = Struct.new(:timestamp, :target, :changes, :review_id, :check_classes, keyword_init: true) do
20
+ ##
21
+ # @return [Hash] run construction attributes derived from this context
22
+ def run_attributes
23
+ {
24
+ timestamp: timestamp,
25
+ review_id: review_id,
26
+ checks: check_classes.map(&:check_name),
27
+ target_files: target.files,
28
+ ruby_files: target.ruby_files,
29
+ }
30
+ end
31
+ end
32
+
33
+ ##
34
+ # @param [Options::ParseResult] options parsed command-line options
35
+ # @param [CommandRunner] command_runner for executing shell commands
36
+ # @param [#now] clock time source for timestamps
37
+ # @param [CheckRegistry] check_registry registry for resolving check names
38
+ def initialize(options:, command_runner: CommandRunner.new, clock: Time, check_registry: Checks)
39
+ @options = options
40
+ @command_runner = command_runner
41
+ @clock = clock
42
+ @check_registry = check_registry
43
+ end
44
+
45
+ ##
46
+ # Execute the quality review
47
+ # @return [Run] results of the quality review
48
+ def run
49
+ context = analysis_context
50
+ artifacts = prepare_artifacts(context)
51
+ return reusable_run(artifacts) if artifacts.complete?
52
+
53
+ execute_fresh_run(context, artifacts)
54
+ end
55
+
56
+ private
57
+
58
+ attr_reader :options, :command_runner, :clock, :check_registry
59
+
60
+ def epoch_milliseconds
61
+ (clock.now.to_r * 1_000).to_i
62
+ end
63
+
64
+ def analysis_context
65
+ timestamp = epoch_milliseconds
66
+ target = resolve_target
67
+ changes = changes_diff(target)
68
+ check_classes = resolve_checks
69
+
70
+ AnalysisContext.new(
71
+ timestamp: timestamp,
72
+ target: target,
73
+ changes: changes,
74
+ review_id: review_id_for(changes, check_classes),
75
+ check_classes: check_classes,
76
+ )
77
+ end
78
+
79
+ def resolve_target
80
+ files = options.files
81
+ changed = options.changed || files.empty?
82
+ TargetResolver.new(command_runner: command_runner).resolve(files, changed: changed)
83
+ end
84
+
85
+ def changes_diff(target)
86
+ ChangesDiff.new(target_files: target.files, command_runner: command_runner)
87
+ end
88
+
89
+ def prepare_artifacts(context)
90
+ RunArtifacts.new(
91
+ timestamp: context.timestamp,
92
+ review_id: context.review_id,
93
+ target_files: context.target.files,
94
+ changes_diff: context.changes.to_s,
95
+ ).prepare!
96
+ end
97
+
98
+ def reusable_run(artifacts)
99
+ artifacts.to_run(format: options.format, log: options.log)
100
+ end
101
+
102
+ def execute_fresh_run(context, artifacts)
103
+ check_outputs = run_checks(context.check_classes, context.target.ruby_files, context.timestamp)
104
+ write_check_outputs(artifacts, check_outputs)
105
+ run = build_run(context, artifacts, check_outputs)
106
+ persist_run(artifacts, run)
107
+ run
108
+ end
109
+
110
+ def resolve_checks
111
+ all_checks = check_registry.resolve(options.checks)
112
+ filter_excluded_checks(all_checks, options.exclude)
113
+ end
114
+
115
+ def filter_excluded_checks(checks, excluded)
116
+ return checks if excluded.empty?
117
+
118
+ excluded_names = excluded.map(&:downcase)
119
+ checks.reject { |check| excluded_names.include?(check.check_name.downcase) }
120
+ end
121
+
122
+ def run_checks(check_classes, ruby_files, timestamp)
123
+ check_classes.map do |check_class|
124
+ check_class.new(command_runner: command_runner, timestamp: timestamp).run(ruby_files)
125
+ end
126
+ end
127
+
128
+ def write_check_outputs(artifacts, check_outputs)
129
+ check_outputs.each do |output|
130
+ artifacts.write_check_output(output)
131
+ end
132
+ end
133
+
134
+ def build_run(context, artifacts, check_outputs)
135
+ Run.new(
136
+ **context.run_attributes,
137
+ format: options.format,
138
+ run_directory: artifacts.to_s,
139
+ results: check_outputs.flat_map(&:results),
140
+ artifacts: artifacts,
141
+ log: options.log,
142
+ )
143
+ end
144
+
145
+ def persist_run(artifacts, run)
146
+ artifacts.write_run(run)
147
+ end
148
+
149
+ def review_id_for(changes, check_classes)
150
+ Digest::SHA256.hexdigest(
151
+ JSON.generate(
152
+ diff: changes.to_s,
153
+ checks: check_classes.map(&:check_name).sort,
154
+ ),
155
+ )
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "configuration"
4
+
5
+ module CleoQualityReview
6
+ ##
7
+ # Resolves target files for quality review based on git changes and configuration
8
+ class TargetResolver
9
+ BASE_REF = "origin/main"
10
+
11
+ ##
12
+ # Value object containing resolved file lists
13
+ #
14
+ # @!attribute [r] files
15
+ # @return [Array<String>] all target file paths
16
+ # @!attribute [r] ruby_files
17
+ # @return [Array<String>] Ruby file paths
18
+ Target = Struct.new(:files, :ruby_files, keyword_init: true)
19
+
20
+ ##
21
+ # @param [CommandRunner] command_runner for executing git commands
22
+ # @param [Configuration] configuration file filtering configuration
23
+ def initialize(command_runner:, configuration: Configuration.load)
24
+ @command_runner = command_runner
25
+ @configuration = configuration
26
+ end
27
+
28
+ ##
29
+ # Resolve target files for quality review
30
+ # @param [Array<String>] files explicit file paths
31
+ # @param [Boolean] changed when true, filter to git-changed files only
32
+ # @return [Target]
33
+ def resolve(files, changed: false)
34
+ target_files = resolve_target_files(files, changed: changed)
35
+
36
+ Target.new(
37
+ files: target_files,
38
+ ruby_files: target_files,
39
+ )
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :command_runner, :configuration
45
+
46
+ def resolve_target_files(files, changed:)
47
+ candidates = resolve_candidates(files, changed: changed)
48
+ filter_to_configured(candidates)
49
+ end
50
+
51
+ def resolve_candidates(files, changed:)
52
+ return changed_files if files.empty?
53
+
54
+ resolve_explicit_paths(files, changed: changed)
55
+ end
56
+
57
+ def resolve_explicit_paths(files, changed:)
58
+ expanded = expand_target_paths(files)
59
+ changed ? filter_to_changed(expanded) : expanded
60
+ end
61
+
62
+ def filter_to_configured(candidates)
63
+ candidates.select { |path| File.file?(path) && configuration.target_file?(path) }
64
+ end
65
+
66
+ def filter_to_changed(paths)
67
+ git_changed = changed_files
68
+ paths.select { |path| git_changed.include?(path) }
69
+ end
70
+
71
+ def changed_files
72
+ (tracked_changed_files + untracked_files).uniq
73
+ end
74
+
75
+ def tracked_changed_files
76
+ result = command_runner.run(
77
+ "git",
78
+ "diff",
79
+ "--name-only",
80
+ "--diff-filter=ACMRT",
81
+ diff_base,
82
+ )
83
+
84
+ result.stdout.lines.map(&:strip)
85
+ end
86
+
87
+ def untracked_files
88
+ result = command_runner.run("git", "ls-files", "--others", "--exclude-standard")
89
+
90
+ result.stdout.lines.map(&:strip)
91
+ end
92
+
93
+ def diff_base
94
+ @diff_base ||= begin
95
+ result = command_runner.run("git", "merge-base", BASE_REF, "HEAD")
96
+ base = result.stdout.strip
97
+
98
+ result.success? && !base.empty? ? base : BASE_REF
99
+ end
100
+ end
101
+
102
+ def expand_target_paths(paths)
103
+ cleaned_paths = paths.map(&:to_s).map(&:strip).reject(&:empty?)
104
+ files, directories, missing = classify_paths(cleaned_paths)
105
+ raise ArgumentError, "Path not found: #{missing.join(', ')}" unless missing.empty?
106
+
107
+ (files + directories.flat_map { |path| directory_files(path) }).uniq
108
+ end
109
+
110
+ def classify_paths(paths)
111
+ paths.group_by { |path| path_type(path) }.values_at(:file, :directory, :missing).map { |v| v || [] }
112
+ end
113
+
114
+ def path_type(path)
115
+ return :file if File.file?(path)
116
+ return :directory if File.directory?(path)
117
+
118
+ :missing
119
+ end
120
+
121
+ def directory_files(path)
122
+ Dir.glob(File.join(path, "**", "*"), File::FNM_DOTMATCH).sort.select do |expanded_path|
123
+ File.file?(expanded_path)
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CleoQualityReview
4
+ ##
5
+ # Gem version
6
+ VERSION = "0.1.0"
7
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # Quality review tool for Ruby code analysis
5
+ module CleoQualityReview
6
+ class Error < StandardError;end
7
+
8
+ require_relative "cleo_quality_review/version"
9
+ require_relative "cleo_quality_review/checks"
10
+ require_relative "cleo_quality_review/llm_providers"
11
+
12
+ ##
13
+ # Register all supported tools for analysing code here
14
+ Checks.register("Reek", Checks::Reek, tool_type: :smell_detection)
15
+ Checks.register("Flog", Checks::Flog, tool_type: :complexity)
16
+ Checks.register("Fasterer", Checks::Fasterer, tool_type: :performance)
17
+ Checks.register("Debride", Checks::Debride, tool_type: :dead_code)
18
+
19
+ ##
20
+ # Register all supported LLM APIs for formatting output here
21
+ LlmProviders.register("openai", LlmProviders::OpenAi::Provider)
22
+ LlmProviders.register("stub", LlmProviders::Stub::Provider)
23
+ end
data/prompts/agent.md ADDED
@@ -0,0 +1,53 @@
1
+ You are reviewing Ruby code quality findings for consumption by AI coding assistants.
2
+
3
+ Analyze the raw tool outputs and git diff provided. Prioritize actionable issues affecting maintainability, readability, performance, and complexity. Filter out low-signal findings.
4
+
5
+ ## Tool Thresholds
6
+
7
+ - **Flog**: Ignore scores below 40.0
8
+ - **Reek**: Focus on FeatureEnvy, TooManyStatements, DuplicateMethodCall, NestedIterators, LongParameterList
9
+ - **Fasterer**: Include all performance suggestions
10
+ - **Debride**: Treat as lower-confidence static dead-code detection. Include only findings that are clearly actionable and avoid recommending deletion without checking dynamic call paths.
11
+
12
+ ## Output Format
13
+
14
+ Output valid JSON matching this exact schema:
15
+
16
+ ```json
17
+ {
18
+ "run": {
19
+ "timestamp": <integer from metadata>,
20
+ "checks": [<check names from metadata>],
21
+ "target_files": [<file paths from metadata>],
22
+ "findings": [
23
+ {
24
+ "tool_name": "<reek|flog|fasterer|debride>",
25
+ "tool_type": "<smell_detection|complexity|performance|dead_code>",
26
+ "check": "<specific check type>",
27
+ "filepath": "<relative file path>",
28
+ "line": <line number or null>,
29
+ "result": "<concise description of the issue>"
30
+ }
31
+ ]
32
+ },
33
+ "check_outputs": [
34
+ {
35
+ "check_name": "<check name>",
36
+ "tool_name": "<reek|flog|fasterer|debride>",
37
+ "tool_type": "<smell_detection|complexity|performance|dead_code>",
38
+ "extension": "<json|txt>",
39
+ "path": "<raw output artifact path>",
40
+ "raw_output": "<raw tool output>"
41
+ }
42
+ ],
43
+ "instructions": "Prioritized code quality findings for automated remediation."
44
+ }
45
+ ```
46
+
47
+ ## Guidelines
48
+
49
+ 1. Include only findings that exceed thresholds and are actionable
50
+ 2. Order findings by priority: high-complexity methods first, then code smells, then performance
51
+ 3. Write concise `result` descriptions an agent can act on
52
+ 4. Include the raw check outputs in `check_outputs` for reference
53
+ 5. Output ONLY valid JSON - no markdown fences, no explanatory text
data/prompts/github.md ADDED
@@ -0,0 +1,29 @@
1
+ You are the pipeline interface between a series of code reviews for a git diff, and the GitHub Actions automation pipeline.
2
+
3
+ You will collate data about code from multiple code sources (including, but not limited to Flog, Flay, Reek, Fasterer, Brakeman, etc.), and produce useful, meaningful output for the engineer whose PR has triggered this flow.
4
+
5
+ The output from all of these reports together is very noisy, and so your role is to determine what is the most important things to report back on the PR, and what items can be disregarded.
6
+
7
+ For weighting, consider the following values as guides:
8
+
9
+ Flog:
10
+ Threshold: 40.0
11
+ ThresholdType: GreaterThanOrEqual
12
+ Severity: Medium to High
13
+
14
+ Reek:
15
+ Severity: Low to Medium
16
+
17
+ Fasterer:
18
+ Severity: Low
19
+
20
+ Debride:
21
+ Severity: Low
22
+ Notes: Lower-confidence static dead-code signal. Only report when the finding is specific, actionable, and unlikely to be a dynamic Rails call.
23
+
24
+
25
+ You MUST NOT return so many items that the feedback is noisy and confusing. Limit yourself to maximum 10 comments.
26
+
27
+ You MUST return your feedback in the Github Workflow Annotations format, as described on their website. (You can use this link as a source if you need to: https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-commands).
28
+
29
+ You SHOULD group feedback from the various tools in the Github workflow logs using the `::group::{title}` ...`::endgroup::` notation.
data/prompts/human.md ADDED
@@ -0,0 +1,23 @@
1
+ You are reviewing a local code change for code quality.
2
+
3
+ The files provided include git diffs for local code changes, as well as generated output files from various code quality assessment tools including (but not limited to) Reek, Flog, Fasterer, Debride, etc.
4
+
5
+ Your task is to parse the static output files generated by these tools, and provide feedback to the human user. The diff provided is to allow you to map tool output to changes in the code.
6
+
7
+ YOU MUST NOT comment on the code diff itself, unless the comment is in relatinon to an issue reported by a tool.
8
+
9
+ Prioritize issues that are likely to matter to maintainability, correctness, readability, or long-term ownership.
10
+
11
+ Avoid repeating tool output mechanically. If multiple issues of the same sort are reported, it's fine to highlight a couple of examples and then make a general comment for improvement.
12
+
13
+ If a tool finding is low value or likely a false positive, say so briefly or omit it.
14
+
15
+ Debride findings are lower-confidence static dead-code candidates. Do not recommend deleting code unless the finding is clearly supported by the changed code and dynamic call paths have been considered.
16
+
17
+ The output will be printed in a unix terminal, and so colour-coded feedback is preferrable.
18
+
19
+ 1. Highest-impact issues first, with file and line references as clickable links when available.
20
+ 2. Suggested changes that are specific enough for an engineer or coding agent to implement.
21
+ 3. A short note if the automated checks found no meaningful issues.
22
+
23
+ Finish your feedback with a short note (one or two sentences) that begin with: `Summary:`, and then summarise the report findings.
@@ -0,0 +1,62 @@
1
+ You are the pipeline interface between code quality tools and GitHub pull request review comments.
2
+
3
+ You will collate data from code quality tools including Reek, Flog, Fasterer, and Debride. The raw output is noisy, so your job is to identify only the most useful comments for the engineer whose PR triggered this flow.
4
+
5
+ You MUST NOT comment on the code diff itself unless the comment is directly supported by a tool finding.
6
+
7
+ ## Tool Thresholds
8
+
9
+ - **Flog**: Ignore scores below 40.0. Prioritize high-complexity methods because they are the most expensive to maintain.
10
+ - **Reek**: Prefer actionable smells such as FeatureEnvy, TooManyStatements, DuplicateMethodCall, NestedIterators, and LongParameterList.
11
+ - **Fasterer**: Low severity. Include only when the finding is clearly on code changed by this PR and the fix is straightforward.
12
+ - **Debride**: Lower-confidence static dead-code signal. Include only when the candidate method is clearly made obsolete by this PR, and do not suggest deletion without noting possible dynamic Rails calls.
13
+
14
+ ## Comment Selection
15
+
16
+ 1. Limit yourself to ten comments at most.
17
+ 2. Prefer findings that map directly to a changed or commentable right-side line in the git diff.
18
+ 3. Omit low-value, duplicated, stale, or ambiguous findings.
19
+ 4. If a tool finding points to a file or line that is not visible in the provided diff, omit the inline comment.
20
+ 5. Keep comments concise and actionable. Mention the tool and check name.
21
+
22
+ ## Output Format
23
+
24
+ Output ONLY valid JSON. Do not wrap it in markdown fences. Do not include explanatory text before or after the JSON.
25
+
26
+ The JSON MUST match this schema:
27
+
28
+ ```json
29
+ {
30
+ "body": "<short markdown summary for the PR review body>",
31
+ "comments": [
32
+ {
33
+ "path": "<repository-relative file path>",
34
+ "line": <right-side line number from the diff>,
35
+ "body": "<markdown review comment>"
36
+ }
37
+ ]
38
+ }
39
+ ```
40
+
41
+
42
+ ## Comment format:
43
+
44
+ The comments should prioritise readability and actionabilty. Assume the reader is a junior developer, or someone who is not familiar with the language and framework. Be helpful, without being overly verbose.
45
+
46
+ Example format:
47
+ ```
48
+ This code appears to have X issue. That may be likely to cause Y problem. Consider an alternative soltion, such as Z.
49
+
50
+ _(Ref: Reek TooManyStatements, DuplicateMethodCall; Fasterer HashKeysEach)_
51
+ ```
52
+
53
+ ## Empty output:
54
+
55
+ If there are no high-confidence inline comments, return:
56
+
57
+ ```json
58
+ {
59
+ "body": "Cleo quality review did not find any high-confidence issues worth inline PR comments.",
60
+ "comments": []
61
+ }
62
+ ```
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cleo_quality_review
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Gavin Morrice
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: debride
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: fasterer
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: flog
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: reek
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ description: Runs local quality checks and summarizes their output for humans, agents,
69
+ or GitHub.
70
+ email:
71
+ - gavin@gavinmorrice.com
72
+ executables:
73
+ - check_quality
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - cleo_quality_review.gemspec
78
+ - config/default.yml
79
+ - exe/check_quality
80
+ - lib/cleo_quality_review.rb
81
+ - lib/cleo_quality_review/changes_diff.rb
82
+ - lib/cleo_quality_review/checks.rb
83
+ - lib/cleo_quality_review/checks/debride.rb
84
+ - lib/cleo_quality_review/checks/fasterer.rb
85
+ - lib/cleo_quality_review/checks/flog.rb
86
+ - lib/cleo_quality_review/checks/quality_check.rb
87
+ - lib/cleo_quality_review/checks/reek.rb
88
+ - lib/cleo_quality_review/checks/registry.rb
89
+ - lib/cleo_quality_review/cli.rb
90
+ - lib/cleo_quality_review/command_result.rb
91
+ - lib/cleo_quality_review/command_runner.rb
92
+ - lib/cleo_quality_review/configuration.rb
93
+ - lib/cleo_quality_review/diff_map.rb
94
+ - lib/cleo_quality_review/formatter.rb
95
+ - lib/cleo_quality_review/github_review_builder.rb
96
+ - lib/cleo_quality_review/github_review_publisher.rb
97
+ - lib/cleo_quality_review/llm_client.rb
98
+ - lib/cleo_quality_review/llm_config.rb
99
+ - lib/cleo_quality_review/llm_errors.rb
100
+ - lib/cleo_quality_review/llm_logger.rb
101
+ - lib/cleo_quality_review/llm_providers.rb
102
+ - lib/cleo_quality_review/llm_providers/open_ai.rb
103
+ - lib/cleo_quality_review/llm_providers/open_ai_config.rb
104
+ - lib/cleo_quality_review/llm_providers/registry.rb
105
+ - lib/cleo_quality_review/llm_providers/stub.rb
106
+ - lib/cleo_quality_review/options.rb
107
+ - lib/cleo_quality_review/prompt_builder.rb
108
+ - lib/cleo_quality_review/prompt_loader.rb
109
+ - lib/cleo_quality_review/result.rb
110
+ - lib/cleo_quality_review/run.rb
111
+ - lib/cleo_quality_review/run_artifacts.rb
112
+ - lib/cleo_quality_review/run_artifacts/raw_check_outputs.rb
113
+ - lib/cleo_quality_review/runner.rb
114
+ - lib/cleo_quality_review/target_resolver.rb
115
+ - lib/cleo_quality_review/version.rb
116
+ - prompts/agent.md
117
+ - prompts/github.md
118
+ - prompts/human.md
119
+ - prompts/pr_review.md
120
+ licenses:
121
+ - MIT
122
+ metadata:
123
+ rubygems_mfa_required: 'true'
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: 3.2.0
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubygems_version: 4.0.10
139
+ specification_version: 4
140
+ summary: Local Cleo code quality checks
141
+ test_files: []