a11y_agent 0.0.5.pre.alpha.3 → 0.0.11
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/.ruby-version +1 -0
- data/LICENSE +661 -0
- data/fixtures/react/.eslintrc +13 -0
- data/fixtures/react/.gitignore +3 -0
- data/fixtures/react/package-lock.json +16453 -0
- data/fixtures/react/package.json +42 -0
- data/fixtures/react/public/index.html +19 -0
- data/fixtures/react/readme.md +42 -0
- data/fixtures/react/src/index.js +16 -0
- data/fixtures/react/src/todo/app.css +87 -0
- data/fixtures/react/src/todo/app.jsx +20 -0
- data/fixtures/react/src/todo/components/footer.jsx +46 -0
- data/fixtures/react/src/todo/components/header.jsx +15 -0
- data/fixtures/react/src/todo/components/input.jsx +46 -0
- data/fixtures/react/src/todo/components/item.jsx +55 -0
- data/fixtures/react/src/todo/components/main.jsx +45 -0
- data/fixtures/react/src/todo/constants.js +7 -0
- data/fixtures/react/src/todo/reducer.js +64 -0
- data/fixtures/react/webpack.common.js +43 -0
- data/fixtures/react/webpack.dev.js +18 -0
- data/fixtures/react/webpack.prod.js +35 -0
- data/fixtures/sample.html +93 -0
- data/lib/a11y_agent/version.rb +1 -1
- data/lib/agents/a11y_agent.rb +131 -0
- data/lib/generators/confirmable_fix_generator.rb +56 -0
- data/lib/generators/fix_a11y_generator.rb +35 -0
- data/lib/tasks/release.rake +7 -4
- data/package.json +12 -7
- data/yarn.lock +114 -1810
- metadata +87 -12
- data/eslint.config.mjs +0 -23
- data/lib/a11y_agent.rb +0 -119
- data/lib/fix_a11y_generator.rb +0 -32
metadata
CHANGED
@@ -1,15 +1,28 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: a11y_agent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cameron Cundiff
|
8
|
-
|
9
|
-
bindir: bin
|
8
|
+
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-01-04 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: axe-core-api
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '4.9'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '4.9'
|
13
26
|
- !ruby/object:Gem::Dependency
|
14
27
|
name: diffy
|
15
28
|
requirement: !ruby/object:Gem::Requirement
|
@@ -24,6 +37,20 @@ dependencies:
|
|
24
37
|
- - "~>"
|
25
38
|
- !ruby/object:Gem::Version
|
26
39
|
version: '3.4'
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: dotenv
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '3.1'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3.1'
|
27
54
|
- !ruby/object:Gem::Dependency
|
28
55
|
name: rainbow
|
29
56
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,20 +65,34 @@ dependencies:
|
|
38
65
|
- - "~>"
|
39
66
|
- !ruby/object:Gem::Version
|
40
67
|
version: '3.0'
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: selenium-webdriver
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '4.23'
|
75
|
+
type: :runtime
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '4.23'
|
41
82
|
- !ruby/object:Gem::Dependency
|
42
83
|
name: sublayer
|
43
84
|
requirement: !ruby/object:Gem::Requirement
|
44
85
|
requirements:
|
45
86
|
- - "~>"
|
46
87
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0.
|
88
|
+
version: '0.2'
|
48
89
|
type: :runtime
|
49
90
|
prerelease: false
|
50
91
|
version_requirements: !ruby/object:Gem::Requirement
|
51
92
|
requirements:
|
52
93
|
- - "~>"
|
53
94
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0.
|
95
|
+
version: '0.2'
|
55
96
|
- !ruby/object:Gem::Dependency
|
56
97
|
name: tty-prompt
|
57
98
|
requirement: !ruby/object:Gem::Requirement
|
@@ -68,6 +109,20 @@ dependencies:
|
|
68
109
|
version: '0.23'
|
69
110
|
- !ruby/object:Gem::Dependency
|
70
111
|
name: rake
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '13.2'
|
117
|
+
type: :development
|
118
|
+
prerelease: false
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '13.2'
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: rubocop
|
71
126
|
requirement: !ruby/object:Gem::Requirement
|
72
127
|
requirements:
|
73
128
|
- - ">="
|
@@ -88,13 +143,35 @@ extensions: []
|
|
88
143
|
extra_rdoc_files: []
|
89
144
|
files:
|
90
145
|
- ".env.sample"
|
146
|
+
- ".ruby-version"
|
147
|
+
- LICENSE
|
91
148
|
- README.md
|
92
149
|
- Rakefile
|
93
|
-
-
|
150
|
+
- fixtures/react/.eslintrc
|
151
|
+
- fixtures/react/.gitignore
|
152
|
+
- fixtures/react/package-lock.json
|
153
|
+
- fixtures/react/package.json
|
154
|
+
- fixtures/react/public/index.html
|
155
|
+
- fixtures/react/readme.md
|
156
|
+
- fixtures/react/src/index.js
|
157
|
+
- fixtures/react/src/todo/app.css
|
158
|
+
- fixtures/react/src/todo/app.jsx
|
159
|
+
- fixtures/react/src/todo/components/footer.jsx
|
160
|
+
- fixtures/react/src/todo/components/header.jsx
|
161
|
+
- fixtures/react/src/todo/components/input.jsx
|
162
|
+
- fixtures/react/src/todo/components/item.jsx
|
163
|
+
- fixtures/react/src/todo/components/main.jsx
|
164
|
+
- fixtures/react/src/todo/constants.js
|
165
|
+
- fixtures/react/src/todo/reducer.js
|
166
|
+
- fixtures/react/webpack.common.js
|
167
|
+
- fixtures/react/webpack.dev.js
|
168
|
+
- fixtures/react/webpack.prod.js
|
169
|
+
- fixtures/sample.html
|
94
170
|
- fixtures/sample.tsx
|
95
|
-
- lib/a11y_agent.rb
|
96
171
|
- lib/a11y_agent/version.rb
|
97
|
-
- lib/
|
172
|
+
- lib/agents/a11y_agent.rb
|
173
|
+
- lib/generators/confirmable_fix_generator.rb
|
174
|
+
- lib/generators/fix_a11y_generator.rb
|
98
175
|
- lib/tasks/release.rake
|
99
176
|
- package.json
|
100
177
|
- trigger.txt
|
@@ -106,7 +183,6 @@ metadata:
|
|
106
183
|
allowed_push_host: https://rubygems.org
|
107
184
|
homepage_uri: https://github.com/accesslint/a11y-agent
|
108
185
|
source_code_uri: https://github.com/accesslint/a11y-agent
|
109
|
-
post_install_message:
|
110
186
|
rdoc_options: []
|
111
187
|
require_paths:
|
112
188
|
- lib
|
@@ -121,8 +197,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
197
|
- !ruby/object:Gem::Version
|
122
198
|
version: '0'
|
123
199
|
requirements: []
|
124
|
-
rubygems_version: 3.
|
125
|
-
signing_key:
|
200
|
+
rubygems_version: 3.6.2
|
126
201
|
specification_version: 4
|
127
202
|
summary: AI agent that fixes accessibility issues
|
128
203
|
test_files: []
|
data/eslint.config.mjs
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
import globals from "globals";
|
2
|
-
import pluginJs from "@eslint/js";
|
3
|
-
import tseslint from "typescript-eslint";
|
4
|
-
import pluginReact from "eslint-plugin-react";
|
5
|
-
import jsxA11y from "eslint-plugin-jsx-a11y";
|
6
|
-
|
7
|
-
export default [
|
8
|
-
{
|
9
|
-
files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"],
|
10
|
-
languageOptions: {
|
11
|
-
parserOptions: {
|
12
|
-
ecmaFeatures: {
|
13
|
-
jsx: true,
|
14
|
-
},
|
15
|
-
},
|
16
|
-
},
|
17
|
-
},
|
18
|
-
{ languageOptions: { globals: globals.browser } },
|
19
|
-
jsxA11y.flatConfigs.strict,
|
20
|
-
pluginJs.configs.recommended,
|
21
|
-
...tseslint.configs.recommended,
|
22
|
-
pluginReact.configs.flat.recommended,
|
23
|
-
];
|
data/lib/a11y_agent.rb
DELETED
@@ -1,119 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'diffy'
|
4
|
-
require 'fileutils'
|
5
|
-
require 'json'
|
6
|
-
require 'open3'
|
7
|
-
require 'rainbow/refinement'
|
8
|
-
require 'sublayer'
|
9
|
-
require 'tty-prompt'
|
10
|
-
require_relative './fix_a11y_generator'
|
11
|
-
|
12
|
-
Diffy::Diff.default_format = :color
|
13
|
-
|
14
|
-
# Sublayer.configuration.ai_provider = Sublayer::Providers::OpenAi
|
15
|
-
# Sublayer.configuration.ai_model = "gpt-4o-mini"
|
16
|
-
|
17
|
-
# Sublayer.configuration.ai_provider = Sublayer::Providers::Gemini
|
18
|
-
# Sublayer.configuration.ai_model = "gemini-1.5-flash-latest"
|
19
|
-
|
20
|
-
Sublayer.configuration.ai_provider = Sublayer::Providers::Claude
|
21
|
-
Sublayer.configuration.ai_model = 'claude-3-haiku-20240307'
|
22
|
-
|
23
|
-
module Sublayer
|
24
|
-
module Agents
|
25
|
-
class A11yAgent < Base
|
26
|
-
using Rainbow
|
27
|
-
|
28
|
-
def initialize(file:)
|
29
|
-
@accessibility_issues = []
|
30
|
-
@issue_types = []
|
31
|
-
@file = file
|
32
|
-
@file_contents = File.read(@file)
|
33
|
-
end
|
34
|
-
|
35
|
-
trigger_on_files_changed do
|
36
|
-
['./trigger.txt']
|
37
|
-
end
|
38
|
-
|
39
|
-
check_status do
|
40
|
-
puts "🔍 Checking accessibility issues in #{@file}..."
|
41
|
-
stdout, _stderr, _status = Open3.capture3("eslint #{@file} --format stylish")
|
42
|
-
|
43
|
-
@accessibility_issues = stdout.split("\n")[2..]
|
44
|
-
@accessibility_issues = @accessibility_issues.map { |issue| issue.gsub(/\s+/, ' ').strip }
|
45
|
-
|
46
|
-
puts "🚨 Found #{@accessibility_issues.length} accessibility issues" unless @accessibility_issues.empty?
|
47
|
-
end
|
48
|
-
|
49
|
-
goal_condition do
|
50
|
-
puts '🎉 All accessibility issues have been fixed!' if @accessibility_issues.empty?
|
51
|
-
@accessibility_issues.empty?
|
52
|
-
end
|
53
|
-
|
54
|
-
step do
|
55
|
-
prompt = TTY::Prompt.new
|
56
|
-
|
57
|
-
@accessibility_issues.each do |issue|
|
58
|
-
contents = File.read(@file)
|
59
|
-
|
60
|
-
user_input = nil
|
61
|
-
fixed = nil
|
62
|
-
additional_prompt = nil
|
63
|
-
|
64
|
-
until %i[yes no].include?(user_input)
|
65
|
-
puts "🔧 Attempting a fix: #{issue}"
|
66
|
-
result = FixA11yGenerator.new(contents:, issue:,
|
67
|
-
additional_prompt:).generate
|
68
|
-
result << "\n" unless result.end_with?("\n")
|
69
|
-
|
70
|
-
Diffy::Diff.new(contents, result).each_chunk do |chunk|
|
71
|
-
case chunk
|
72
|
-
when /^\+/
|
73
|
-
print chunk.to_s.green
|
74
|
-
when /^-/
|
75
|
-
print chunk.to_s.red
|
76
|
-
else
|
77
|
-
lines = chunk.to_s.split("\n")
|
78
|
-
puts lines[0..2].join("\n")
|
79
|
-
puts '...'
|
80
|
-
puts lines[-3..].join("\n")
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
choices = [
|
85
|
-
{ key: 'y', name: 'approve and continue', value: :yes },
|
86
|
-
{ key: 'n', name: 'skip this change', value: :no },
|
87
|
-
{ key: 'r', name: 'retry with optional instructions', value: :retry },
|
88
|
-
{ key: 'q', name: 'quit; stop making changes', value: :quit }
|
89
|
-
]
|
90
|
-
|
91
|
-
user_input = prompt.expand('Approve changes?', choices)
|
92
|
-
|
93
|
-
case user_input
|
94
|
-
when :yes
|
95
|
-
fixed = result
|
96
|
-
when :no
|
97
|
-
fixed = contents
|
98
|
-
when :retry
|
99
|
-
additional_prompt = prompt.ask('Additional instructions:')
|
100
|
-
fixed = nil
|
101
|
-
when :quit
|
102
|
-
puts 'Quitting...'
|
103
|
-
exit
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
contents = fixed
|
108
|
-
|
109
|
-
puts 'Writing to file...'
|
110
|
-
File.write(@file, contents)
|
111
|
-
end
|
112
|
-
|
113
|
-
puts '🎉 Done!'
|
114
|
-
puts '✅ Complete diff:'
|
115
|
-
puts Diffy::Diff.new(@file_contents, File.read(@file))
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
data/lib/fix_a11y_generator.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
class FixA11yGenerator < Sublayer::Generators::Base
|
2
|
-
llm_output_adapter type: :single_string,
|
3
|
-
name: "fix_accessibility_issue_based_on_a11y_issue",
|
4
|
-
description: "Given a JSX file and an accessibility issue, generate a new JSX file with the issue fixed."
|
5
|
-
|
6
|
-
def initialize(contents:, issue:, additional_prompt: nil)
|
7
|
-
@contents = contents
|
8
|
-
@issue = issue
|
9
|
-
@additional_prompt = additional_prompt
|
10
|
-
end
|
11
|
-
|
12
|
-
def generate
|
13
|
-
super
|
14
|
-
end
|
15
|
-
|
16
|
-
def prompt
|
17
|
-
<<~PROMPT
|
18
|
-
Given the following JSX contents and an individual accessibility issue, generate a new JSX file with the individual issue fixed, leaving the rest of the contents unchanged.:
|
19
|
-
|
20
|
-
Code:
|
21
|
-
#{@contents}
|
22
|
-
|
23
|
-
Accessibility issue:
|
24
|
-
#{@issue}
|
25
|
-
|
26
|
-
Additional user instructions (if any):
|
27
|
-
#{@additional_prompt || "None"}
|
28
|
-
|
29
|
-
Return the JSX contents with the issue fixed.
|
30
|
-
PROMPT
|
31
|
-
end
|
32
|
-
end
|