ace-lint 0.25.0 → 0.27.4
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.
- checksums.yaml +4 -4
- data/.ace-defaults/lint/config.yml +3 -2
- data/CHANGELOG.md +84 -0
- data/README.md +4 -2
- data/lib/ace/lint/cli/commands/lint.rb +71 -8
- data/lib/ace/lint/molecules/kramdown_formatter.rb +76 -9
- data/lib/ace/lint/molecules/markdown_linter.rb +171 -50
- data/lib/ace/lint/molecules/markdown_surgical_fixer.rb +247 -0
- data/lib/ace/lint/organisms/auto_fix_orchestrator.rb +382 -0
- data/lib/ace/lint/organisms/lint_orchestrator.rb +35 -3
- data/lib/ace/lint/version.rb +1 -1
- data/lib/ace/lint.rb +1 -0
- metadata +11 -9
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "ace/support/cli"
|
|
4
|
+
require "set"
|
|
5
|
+
require_relative "../atoms/type_detector"
|
|
6
|
+
|
|
7
|
+
module Ace
|
|
8
|
+
module Lint
|
|
9
|
+
module Organisms
|
|
10
|
+
# Coordinates deterministic and agent-assisted auto-fix flows.
|
|
11
|
+
class AutoFixOrchestrator
|
|
12
|
+
FIX_CAPABLE_TYPES = [:markdown, :skill, :workflow, :agent, :ruby].freeze
|
|
13
|
+
DEFAULT_PROVIDER_MODEL = "gemini:flash-latest@yolo".freeze
|
|
14
|
+
|
|
15
|
+
def initialize(
|
|
16
|
+
orchestrator:,
|
|
17
|
+
lint_options:,
|
|
18
|
+
with_agent:,
|
|
19
|
+
model:,
|
|
20
|
+
file_block_start:,
|
|
21
|
+
file_block_end:,
|
|
22
|
+
no_changes_marker:,
|
|
23
|
+
max_file_bytes:,
|
|
24
|
+
max_total_bytes:
|
|
25
|
+
)
|
|
26
|
+
@orchestrator = orchestrator
|
|
27
|
+
@lint_options = lint_options
|
|
28
|
+
@with_agent = with_agent
|
|
29
|
+
@model = model
|
|
30
|
+
@file_block_start = file_block_start
|
|
31
|
+
@file_block_end = file_block_end
|
|
32
|
+
@no_changes_marker = no_changes_marker
|
|
33
|
+
@max_file_bytes = max_file_bytes
|
|
34
|
+
@max_total_bytes = max_total_bytes
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def run(paths)
|
|
38
|
+
fix_options = @lint_options.merge(fix: true)
|
|
39
|
+
fix_options.delete(:format)
|
|
40
|
+
|
|
41
|
+
fixable_paths, lint_only_paths = partition_fixable_paths(paths)
|
|
42
|
+
fixed_results = if fixable_paths.empty?
|
|
43
|
+
[]
|
|
44
|
+
else
|
|
45
|
+
@orchestrator.lint_files(fixable_paths, options: fix_options)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
paths_for_final_lint = if lint_only_paths.empty?
|
|
49
|
+
paths
|
|
50
|
+
else
|
|
51
|
+
fixable_paths + lint_only_paths
|
|
52
|
+
end
|
|
53
|
+
lint_results = @orchestrator.lint_files(paths_for_final_lint, options: lint_only_options(@lint_options))
|
|
54
|
+
merged_results = merge_fix_and_lint_results(fixed_results, lint_results)
|
|
55
|
+
|
|
56
|
+
return merged_results unless @with_agent
|
|
57
|
+
|
|
58
|
+
run_agent_fix(paths, initial_results: merged_results)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def run_dry_run(paths)
|
|
62
|
+
lint_results = @orchestrator.lint_files(paths, options: lint_only_options(@lint_options))
|
|
63
|
+
|
|
64
|
+
issues = collect_issues(lint_results)
|
|
65
|
+
if issues.empty?
|
|
66
|
+
puts "No violations found."
|
|
67
|
+
else
|
|
68
|
+
issues.each do |issue|
|
|
69
|
+
puts "Would attempt to fix: #{issue}"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
file_count = lint_results.select { |result| result.has_errors? || result.has_warnings? }.map(&:file_path).uniq.count
|
|
73
|
+
puts "#{issues.count} issue(s) detected in #{file_count} file(s) during dry-run."
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
return unless @with_agent
|
|
77
|
+
return puts "\nNo remaining issues for agent prompt." if lint_results.none? { |result| result.has_errors? || result.has_warnings? }
|
|
78
|
+
|
|
79
|
+
prompt = build_agent_prompt(lint_results)
|
|
80
|
+
puts "\nAgent prompt (dry-run):"
|
|
81
|
+
puts prompt
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
def run_agent_fix(paths, initial_results:)
|
|
87
|
+
remaining_results = initial_results.select { |result| result.has_errors? || result.has_warnings? }
|
|
88
|
+
if remaining_results.empty?
|
|
89
|
+
puts "\nAll violations resolved by deterministic auto-fix; agent not launched."
|
|
90
|
+
return initial_results
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
prompt = build_agent_prompt(remaining_results)
|
|
94
|
+
editable_files = remaining_results.map(&:file_path).uniq.sort
|
|
95
|
+
original_contents = snapshot_file_contents(editable_files)
|
|
96
|
+
provider_model = @model || Ace::Lint.config.dig("lint", "doctor_agent_model") || DEFAULT_PROVIDER_MODEL
|
|
97
|
+
puts "\nLaunching agent to fix remaining violations..."
|
|
98
|
+
warn "[ace-lint] Warning: --auto-fix-with-agent sends full file contents to #{provider_model}."
|
|
99
|
+
|
|
100
|
+
ensure_ace_llm_available!
|
|
101
|
+
|
|
102
|
+
begin
|
|
103
|
+
response = Ace::LLM::QueryInterface.query(
|
|
104
|
+
provider_model,
|
|
105
|
+
prompt,
|
|
106
|
+
system: nil,
|
|
107
|
+
timeout: 600,
|
|
108
|
+
fallback: false,
|
|
109
|
+
sandbox: "workspace-write",
|
|
110
|
+
working_dir: Dir.pwd
|
|
111
|
+
)
|
|
112
|
+
response_text = response[:text].to_s
|
|
113
|
+
puts response_text unless response_text.empty?
|
|
114
|
+
|
|
115
|
+
edits = parse_agent_file_edits(response_text, allowed_files: editable_files)
|
|
116
|
+
if edits.empty?
|
|
117
|
+
raise Ace::Support::Cli::Error.new(
|
|
118
|
+
"Agent returned no editable file blocks (expected #{@file_block_start}path>> ... #{@file_block_end}).",
|
|
119
|
+
exit_code: 2
|
|
120
|
+
)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
changed_files = apply_agent_file_edits(edits, original_contents: original_contents)
|
|
124
|
+
if changed_files.empty?
|
|
125
|
+
raise Ace::Support::Cli::Error.new(
|
|
126
|
+
"Agent response parsed, but no file content changed on disk.",
|
|
127
|
+
exit_code: 2
|
|
128
|
+
)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
puts "Applied agent edits to #{changed_files.count} file(s): #{changed_files.join(", ")}"
|
|
132
|
+
rescue => e
|
|
133
|
+
raise Ace::Support::Cli::Error.new("Agent fix failed: #{e.message}", exit_code: 2)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
@orchestrator.lint_files(paths, options: lint_only_options(@lint_options))
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def build_agent_prompt(results)
|
|
140
|
+
issue_lines = []
|
|
141
|
+
files = Set.new
|
|
142
|
+
total_payload_bytes = 0
|
|
143
|
+
|
|
144
|
+
results.each do |result|
|
|
145
|
+
(result.errors + result.warnings).each do |issue|
|
|
146
|
+
severity = issue.severity == :warning ? "WARNING" : "ERROR"
|
|
147
|
+
location = issue.line ? " (#{result.file_path}:#{issue.line})" : " (#{result.file_path})"
|
|
148
|
+
issue_lines << "- [#{severity}] #{issue.message}#{location}"
|
|
149
|
+
end
|
|
150
|
+
files << result.file_path if result.has_errors? || result.has_warnings?
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
file_sections = files.to_a.sort.map do |path|
|
|
154
|
+
content = File.exist?(path) ? File.read(path) : "(file missing)"
|
|
155
|
+
if content.bytesize > @max_file_bytes
|
|
156
|
+
raise Ace::Support::Cli::Error.new(
|
|
157
|
+
"Agent fix input too large for #{path} (#{content.bytesize} bytes, max #{@max_file_bytes}).",
|
|
158
|
+
exit_code: 2
|
|
159
|
+
)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
total_payload_bytes += content.bytesize
|
|
163
|
+
if total_payload_bytes > @max_total_bytes
|
|
164
|
+
raise Ace::Support::Cli::Error.new(
|
|
165
|
+
"Agent fix payload exceeds #{@max_total_bytes} bytes; narrow file selection.",
|
|
166
|
+
exit_code: 2
|
|
167
|
+
)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
fence = markdown_fence_for(content)
|
|
171
|
+
<<~SECTION
|
|
172
|
+
## File: #{path}
|
|
173
|
+
|
|
174
|
+
#{fence}text
|
|
175
|
+
#{content}
|
|
176
|
+
#{fence}
|
|
177
|
+
SECTION
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
<<~PROMPT
|
|
181
|
+
The following lint issues remain after deterministic auto-fix:
|
|
182
|
+
|
|
183
|
+
#{issue_lines.join("\n")}
|
|
184
|
+
|
|
185
|
+
Fix the remaining issues in-place in this repository.
|
|
186
|
+
|
|
187
|
+
Full content for files with remaining issues:
|
|
188
|
+
|
|
189
|
+
#{file_sections.join("\n")}
|
|
190
|
+
|
|
191
|
+
Output contract (required):
|
|
192
|
+
- Return one or more full-file replacement blocks using this exact format:
|
|
193
|
+
#{@file_block_start}relative/path>>
|
|
194
|
+
<full updated file content>
|
|
195
|
+
#{@file_block_end}
|
|
196
|
+
- Only include files listed above.
|
|
197
|
+
- Do not wrap response in markdown code fences.
|
|
198
|
+
- If no changes are possible, respond exactly with: #{@no_changes_marker}
|
|
199
|
+
|
|
200
|
+
After fixing, run:
|
|
201
|
+
ace-lint #{files.to_a.sort.join(" ")}
|
|
202
|
+
PROMPT
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def ensure_ace_llm_available!
|
|
206
|
+
require "ace/llm"
|
|
207
|
+
rescue LoadError
|
|
208
|
+
raise Ace::Support::Cli::Error.new(
|
|
209
|
+
"--auto-fix-with-agent requires ace-llm gem. Install with: gem install ace-llm",
|
|
210
|
+
exit_code: 2
|
|
211
|
+
)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def snapshot_file_contents(paths)
|
|
215
|
+
paths.each_with_object({}) do |path, acc|
|
|
216
|
+
acc[path] = File.exist?(path) ? File.read(path) : nil
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def parse_agent_file_edits(response_text, allowed_files:)
|
|
221
|
+
response = response_text.to_s
|
|
222
|
+
return {} if response.strip == @no_changes_marker
|
|
223
|
+
|
|
224
|
+
allowed_map = allowed_files.each_with_object({}) do |path, acc|
|
|
225
|
+
normalized = path.sub(%r{\A\./}, "")
|
|
226
|
+
acc[File.expand_path(normalized, Dir.pwd)] = normalized
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
edits = {}
|
|
230
|
+
current_path = nil
|
|
231
|
+
current_buffer = []
|
|
232
|
+
|
|
233
|
+
response.each_line do |line|
|
|
234
|
+
stripped = line.strip
|
|
235
|
+
|
|
236
|
+
if current_path
|
|
237
|
+
if stripped == @file_block_end
|
|
238
|
+
edits[current_path] = current_buffer.join
|
|
239
|
+
current_path = nil
|
|
240
|
+
current_buffer = []
|
|
241
|
+
else
|
|
242
|
+
current_buffer << line
|
|
243
|
+
end
|
|
244
|
+
next
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
next unless stripped.start_with?(@file_block_start) && stripped.end_with?(">>")
|
|
248
|
+
|
|
249
|
+
raw_path = stripped.delete_prefix(@file_block_start).delete_suffix(">>").strip
|
|
250
|
+
expanded = File.expand_path(raw_path, Dir.pwd)
|
|
251
|
+
resolved_path = allowed_map[expanded]
|
|
252
|
+
unless resolved_path
|
|
253
|
+
raise Ace::Support::Cli::Error.new(
|
|
254
|
+
"Agent attempted to edit unexpected file: #{raw_path}",
|
|
255
|
+
exit_code: 2
|
|
256
|
+
)
|
|
257
|
+
end
|
|
258
|
+
if edits.key?(resolved_path)
|
|
259
|
+
raise Ace::Support::Cli::Error.new(
|
|
260
|
+
"Agent returned duplicate edit block for #{resolved_path}",
|
|
261
|
+
exit_code: 2
|
|
262
|
+
)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
current_path = resolved_path
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
if current_path
|
|
269
|
+
raise Ace::Support::Cli::Error.new(
|
|
270
|
+
"Agent response ended before #{@file_block_end}",
|
|
271
|
+
exit_code: 2
|
|
272
|
+
)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
edits
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def apply_agent_file_edits(edits, original_contents:)
|
|
279
|
+
changed_files = []
|
|
280
|
+
|
|
281
|
+
edits.each do |path, content|
|
|
282
|
+
next if original_contents[path] == content
|
|
283
|
+
|
|
284
|
+
File.write(path, content)
|
|
285
|
+
changed_files << path
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
changed_files
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def lint_only_options(options)
|
|
292
|
+
lint_options = options.dup
|
|
293
|
+
lint_options.delete(:fix)
|
|
294
|
+
lint_options.delete(:format)
|
|
295
|
+
lint_options
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def partition_fixable_paths(paths)
|
|
299
|
+
forced_type = @lint_options[:type]
|
|
300
|
+
if forced_type
|
|
301
|
+
return fix_capable_type?(forced_type) ? [paths, []] : [[], paths]
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
paths.partition do |path|
|
|
305
|
+
content = begin
|
|
306
|
+
File.read(path)
|
|
307
|
+
rescue
|
|
308
|
+
nil
|
|
309
|
+
end
|
|
310
|
+
type = Ace::Lint::Atoms::TypeDetector.detect(path, content: content)
|
|
311
|
+
fix_capable_type?(type)
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def fix_capable_type?(type)
|
|
316
|
+
FIX_CAPABLE_TYPES.include?(type)
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def markdown_fence_for(content)
|
|
320
|
+
max_backticks = content.to_s.scan(/`+/).map(&:length).max || 0
|
|
321
|
+
"`" * [3, max_backticks + 1].max
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def merge_fix_and_lint_results(fixed_results, lint_results)
|
|
325
|
+
fixed_by_path = fixed_results.each_with_object({}) { |result, acc| acc[result.file_path] = result }
|
|
326
|
+
lint_paths = lint_results.map(&:file_path)
|
|
327
|
+
merged = lint_results.map do |lint_result|
|
|
328
|
+
merge_result = fixed_by_path[lint_result.file_path]
|
|
329
|
+
next lint_result unless merge_result
|
|
330
|
+
|
|
331
|
+
merged_errors = lint_result.errors.dup
|
|
332
|
+
merged_warnings = merge_validation_errors(merge_result.warnings, lint_result.warnings)
|
|
333
|
+
merged_errors = merge_validation_errors(merge_result.errors, merged_errors) if merge_result.failed?
|
|
334
|
+
|
|
335
|
+
Models::LintResult.new(
|
|
336
|
+
file_path: lint_result.file_path,
|
|
337
|
+
success: merged_errors.empty?,
|
|
338
|
+
errors: merged_errors,
|
|
339
|
+
warnings: merged_warnings,
|
|
340
|
+
formatted: merge_result.formatted? || lint_result.formatted?,
|
|
341
|
+
skipped: lint_result.skipped?,
|
|
342
|
+
skip_reason: lint_result.skip_reason,
|
|
343
|
+
runner: lint_result.runner
|
|
344
|
+
)
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
fixed_results.each do |fixed_result|
|
|
348
|
+
next if lint_paths.include?(fixed_result.file_path)
|
|
349
|
+
|
|
350
|
+
merged << fixed_result
|
|
351
|
+
end
|
|
352
|
+
merged
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def merge_validation_errors(left, right)
|
|
356
|
+
combined = []
|
|
357
|
+
seen = {}
|
|
358
|
+
|
|
359
|
+
(Array(left) + Array(right)).each do |issue|
|
|
360
|
+
key = "#{issue.line}|#{issue.message}|#{issue.severity}"
|
|
361
|
+
next if seen[key]
|
|
362
|
+
|
|
363
|
+
seen[key] = true
|
|
364
|
+
combined << issue
|
|
365
|
+
end
|
|
366
|
+
combined
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
def collect_issues(results)
|
|
370
|
+
issues = []
|
|
371
|
+
results.each do |result|
|
|
372
|
+
(result.errors + result.warnings).each do |issue|
|
|
373
|
+
location = issue.line ? "#{result.file_path}:#{issue.line}" : result.file_path
|
|
374
|
+
issues << "#{location}: #{issue.message}"
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
issues
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
end
|
|
@@ -5,6 +5,7 @@ require_relative "../molecules/markdown_linter"
|
|
|
5
5
|
require_relative "../molecules/yaml_linter"
|
|
6
6
|
require_relative "../molecules/frontmatter_validator"
|
|
7
7
|
require_relative "../molecules/kramdown_formatter"
|
|
8
|
+
require_relative "../molecules/markdown_surgical_fixer"
|
|
8
9
|
require_relative "../molecules/ruby_linter"
|
|
9
10
|
require_relative "../molecules/group_resolver"
|
|
10
11
|
require_relative "../molecules/skill_validator"
|
|
@@ -268,16 +269,47 @@ module Ace
|
|
|
268
269
|
# Skill, workflow, and agent files are markdown-based and support formatting
|
|
269
270
|
return nil unless [:markdown, :skill, :workflow, :agent].include?(type)
|
|
270
271
|
|
|
272
|
+
warnings = []
|
|
273
|
+
formatted = false
|
|
274
|
+
|
|
275
|
+
if options[:fix]
|
|
276
|
+
fix_result = Molecules::MarkdownSurgicalFixer.fix_file(file_path)
|
|
277
|
+
unless fix_result[:success]
|
|
278
|
+
return Models::LintResult.new(
|
|
279
|
+
file_path: file_path,
|
|
280
|
+
success: false,
|
|
281
|
+
errors: fix_result[:errors].map { |msg| Models::ValidationError.new(message: msg) },
|
|
282
|
+
warnings: [],
|
|
283
|
+
formatted: false
|
|
284
|
+
)
|
|
285
|
+
end
|
|
286
|
+
warnings.concat(Array(fix_result[:warnings]).map { |msg| Models::ValidationError.new(message: msg, severity: :warning) })
|
|
287
|
+
formatted ||= fix_result[:formatted]
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
return nil unless options[:format] || options[:fix]
|
|
291
|
+
|
|
292
|
+
unless options[:format]
|
|
293
|
+
return Models::LintResult.new(
|
|
294
|
+
file_path: file_path,
|
|
295
|
+
success: true,
|
|
296
|
+
errors: [],
|
|
297
|
+
warnings: warnings,
|
|
298
|
+
formatted: formatted
|
|
299
|
+
)
|
|
300
|
+
end
|
|
301
|
+
|
|
271
302
|
kramdown_opts = options[:kramdown_options] || {}
|
|
272
|
-
format_result = Molecules::KramdownFormatter.format_file(file_path, options: kramdown_opts)
|
|
303
|
+
format_result = Molecules::KramdownFormatter.format_file(file_path, options: kramdown_opts, guardrails: true)
|
|
273
304
|
|
|
274
305
|
if format_result[:success]
|
|
306
|
+
warnings.concat(Array(format_result[:warnings]).map { |msg| Models::ValidationError.new(message: msg, severity: :warning) })
|
|
275
307
|
Models::LintResult.new(
|
|
276
308
|
file_path: file_path,
|
|
277
309
|
success: true,
|
|
278
310
|
errors: [],
|
|
279
|
-
warnings:
|
|
280
|
-
formatted: format_result[:formatted]
|
|
311
|
+
warnings: warnings,
|
|
312
|
+
formatted: formatted || format_result[:formatted]
|
|
281
313
|
)
|
|
282
314
|
else
|
|
283
315
|
Models::LintResult.new(
|
data/lib/ace/lint/version.rb
CHANGED
data/lib/ace/lint.rb
CHANGED
|
@@ -29,6 +29,7 @@ require_relative "lint/molecules/markdown_linter"
|
|
|
29
29
|
require_relative "lint/molecules/yaml_linter"
|
|
30
30
|
require_relative "lint/molecules/frontmatter_validator"
|
|
31
31
|
require_relative "lint/molecules/kramdown_formatter"
|
|
32
|
+
require_relative "lint/molecules/markdown_surgical_fixer"
|
|
32
33
|
require_relative "lint/molecules/group_resolver"
|
|
33
34
|
require_relative "lint/molecules/validator_chain"
|
|
34
35
|
require_relative "lint/molecules/skill_validator"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ace-lint
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.27.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michal Czyz
|
|
@@ -15,56 +15,56 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '0.
|
|
18
|
+
version: '0.9'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: '0.
|
|
25
|
+
version: '0.9'
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: ace-support-core
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - "~>"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: '0.
|
|
32
|
+
version: '0.29'
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: '0.
|
|
39
|
+
version: '0.29'
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: ace-b36ts
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
44
|
- - "~>"
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: '0.
|
|
46
|
+
version: '0.13'
|
|
47
47
|
type: :runtime
|
|
48
48
|
prerelease: false
|
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
50
|
requirements:
|
|
51
51
|
- - "~>"
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '0.
|
|
53
|
+
version: '0.13'
|
|
54
54
|
- !ruby/object:Gem::Dependency
|
|
55
55
|
name: ace-support-cli
|
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
|
57
57
|
requirements:
|
|
58
58
|
- - "~>"
|
|
59
59
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: '0.
|
|
60
|
+
version: '0.6'
|
|
61
61
|
type: :runtime
|
|
62
62
|
prerelease: false
|
|
63
63
|
version_requirements: !ruby/object:Gem::Requirement
|
|
64
64
|
requirements:
|
|
65
65
|
- - "~>"
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
|
-
version: '0.
|
|
67
|
+
version: '0.6'
|
|
68
68
|
- !ruby/object:Gem::Dependency
|
|
69
69
|
name: kramdown
|
|
70
70
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -211,11 +211,13 @@ files:
|
|
|
211
211
|
- lib/ace/lint/molecules/group_resolver.rb
|
|
212
212
|
- lib/ace/lint/molecules/kramdown_formatter.rb
|
|
213
213
|
- lib/ace/lint/molecules/markdown_linter.rb
|
|
214
|
+
- lib/ace/lint/molecules/markdown_surgical_fixer.rb
|
|
214
215
|
- lib/ace/lint/molecules/offense_deduplicator.rb
|
|
215
216
|
- lib/ace/lint/molecules/ruby_linter.rb
|
|
216
217
|
- lib/ace/lint/molecules/skill_validator.rb
|
|
217
218
|
- lib/ace/lint/molecules/validator_chain.rb
|
|
218
219
|
- lib/ace/lint/molecules/yaml_linter.rb
|
|
220
|
+
- lib/ace/lint/organisms/auto_fix_orchestrator.rb
|
|
219
221
|
- lib/ace/lint/organisms/lint_doctor.rb
|
|
220
222
|
- lib/ace/lint/organisms/lint_orchestrator.rb
|
|
221
223
|
- lib/ace/lint/organisms/report_generator.rb
|