a11y-devkit-deploy 0.6.5 → 0.7.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.
- package/README.md +71 -14
- package/config/a11y.json +42 -30
- package/package.json +1 -1
- package/src/cli.js +9 -24
- package/src/installers/skills.js +50 -22
- /package/templates/{skills-README.md → deploy-README.md} +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# A11y Devkit Deploy
|
|
2
2
|
|
|
3
|
-
A cross-platform CLI for deploying accessibility skills and MCP servers across Claude Code, Cursor, Codex, and VSCode.
|
|
3
|
+
A **fully config-driven**, cross-platform CLI for deploying accessibility skills and MCP servers across Claude Code, Cursor, Codex, and VSCode.
|
|
4
|
+
|
|
5
|
+
**Add new skills or MCP servers without writing code** - just edit the JSON config and re-run.
|
|
4
6
|
|
|
5
7
|
## Install
|
|
6
8
|
|
|
@@ -61,17 +63,23 @@ All MCP servers are configured to run via `npx`, which means:
|
|
|
61
63
|
|
|
62
64
|
This CLI automates the setup of accessibility tooling by:
|
|
63
65
|
|
|
64
|
-
1. **Installing skills from npm** - Downloads and installs
|
|
65
|
-
2. **Configuring MCP servers** - Updates each IDE's MCP config to enable
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
- **
|
|
69
|
-
- **
|
|
70
|
-
|
|
66
|
+
1. **Installing skills from npm** - Downloads and installs accessibility skill packages (configurable in `config/a11y.json`)
|
|
67
|
+
2. **Configuring MCP servers** - Updates each IDE's MCP config to enable accessibility-focused MCP servers (also configurable)
|
|
68
|
+
|
|
69
|
+
**Default configuration includes:**
|
|
70
|
+
- **7 accessibility skills** - Testing, remediation, validation, documentation, and orchestration
|
|
71
|
+
- **5 MCP servers**:
|
|
72
|
+
- **wcag** - WCAG 2.2 guidelines, success criteria, and techniques
|
|
73
|
+
- **aria** - WAI-ARIA roles, states, properties, and patterns
|
|
74
|
+
- **magentaa11y** - Component accessibility acceptance criteria
|
|
75
|
+
- **a11y-personas** - Accessibility personas for diverse user needs
|
|
76
|
+
- **arc-issues** - Format AxeCore violations into standardized issue templates
|
|
71
77
|
|
|
72
|
-
|
|
78
|
+
**Fully customizable** - add/remove skills or MCP servers by editing the config file.
|
|
73
79
|
|
|
74
|
-
|
|
80
|
+
### Skills Installed (Default)
|
|
81
|
+
|
|
82
|
+
The following skill packages are installed from npm by default. **Add your own by editing `config/a11y.json`**:
|
|
75
83
|
|
|
76
84
|
| Skill | Package | Description |
|
|
77
85
|
|-------|---------|-------------|
|
|
@@ -110,11 +118,58 @@ The generated MCP config looks like this:
|
|
|
110
118
|
|
|
111
119
|
## Configuration
|
|
112
120
|
|
|
113
|
-
Edit `config/a11y.json` to customize
|
|
121
|
+
The entire tool is **fully config-driven**. Edit `config/a11y.json` to customize everything without touching code:
|
|
122
|
+
|
|
123
|
+
### Example: Adding a New Skill
|
|
124
|
+
|
|
125
|
+
Simply add an object to the `skills` array with a `name` (npm package) and `description`:
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"skills": [
|
|
130
|
+
{
|
|
131
|
+
"name": "a11y-tester-skill",
|
|
132
|
+
"description": "Run accessibility tests"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"name": "your-custom-skill",
|
|
136
|
+
"description": "Your custom skill description"
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Example: Adding a New MCP Server
|
|
143
|
+
|
|
144
|
+
Add an object to the `mcpServers` array with name, description, command, and args:
|
|
114
145
|
|
|
115
|
-
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"mcpServers": [
|
|
149
|
+
{
|
|
150
|
+
"name": "wcag",
|
|
151
|
+
"description": "WCAG guidelines reference",
|
|
152
|
+
"command": "npx",
|
|
153
|
+
"args": ["-y", "wcag-mcp"]
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"name": "your-custom-mcp",
|
|
157
|
+
"description": "Your custom MCP server",
|
|
158
|
+
"command": "npx",
|
|
159
|
+
"args": ["-y", "your-mcp-package"]
|
|
160
|
+
}
|
|
161
|
+
]
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Config Structure
|
|
166
|
+
|
|
167
|
+
- `skills` - Array of skill objects with `name` (npm package) and `description`
|
|
116
168
|
- `ideSkillsPaths` - IDE-specific skills directories (configurable per IDE)
|
|
117
|
-
- `
|
|
169
|
+
- `ideMcpPaths` - IDE-specific MCP config file paths
|
|
170
|
+
- `mcpServers` - MCP server definitions with name, description, command, and args
|
|
171
|
+
|
|
172
|
+
All changes take effect immediately - just re-run the CLI to deploy your updated config.
|
|
118
173
|
|
|
119
174
|
## Directory Structure
|
|
120
175
|
|
|
@@ -142,7 +197,9 @@ MCP configurations are written to each IDE's OS-specific config path:
|
|
|
142
197
|
- **Windows**: `%APPDATA%\{IDE}\mcp.json`
|
|
143
198
|
- **Linux**: `~/.config/{IDE}/mcp.json`
|
|
144
199
|
|
|
145
|
-
## MCP Servers Included
|
|
200
|
+
## MCP Servers Included (Default)
|
|
201
|
+
|
|
202
|
+
**Add your own by editing `config/a11y.json`**:
|
|
146
203
|
|
|
147
204
|
| Server | Package | Description |
|
|
148
205
|
|--------|---------|-------------|
|
package/config/a11y.json
CHANGED
|
@@ -1,19 +1,41 @@
|
|
|
1
1
|
{
|
|
2
|
+
"skillsFolder": "a11y",
|
|
3
|
+
"readmeTemplate": "deploy-README.md",
|
|
2
4
|
"skills": [
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
{
|
|
6
|
+
"name": "a11y-base-web-skill",
|
|
7
|
+
"description": "Core accessibility testing utilities"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"name": "a11y-issue-writer-skill",
|
|
11
|
+
"description": "Document accessibility issues"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "a11y-tester-skill",
|
|
15
|
+
"description": "Run accessibility tests"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "a11y-remediator-skill",
|
|
19
|
+
"description": "Fix accessibility issues"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"name": "a11y-validator-skill",
|
|
23
|
+
"description": "Validate accessibility compliance"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "web-standards-skill",
|
|
27
|
+
"description": "Web standards reference"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "a11y-audit-fix-agent-orchestrator-skill",
|
|
31
|
+
"description": "Orchestrate accessibility audits"
|
|
32
|
+
}
|
|
10
33
|
],
|
|
11
34
|
"ideSkillsPaths": {
|
|
12
35
|
"claude": ".claude/skills",
|
|
13
36
|
"cursor": ".cursor/skills",
|
|
14
37
|
"codex": ".codex/skills",
|
|
15
|
-
"vscode": ".github/skills"
|
|
16
|
-
"local": ".github/skills"
|
|
38
|
+
"vscode": ".github/skills"
|
|
17
39
|
},
|
|
18
40
|
"ideMcpPaths": {
|
|
19
41
|
"claude": ".claude/mcp.json",
|
|
@@ -24,43 +46,33 @@
|
|
|
24
46
|
"mcpServers": [
|
|
25
47
|
{
|
|
26
48
|
"name": "wcag",
|
|
49
|
+
"description": "WCAG guidelines reference",
|
|
27
50
|
"command": "npx",
|
|
28
|
-
"args": [
|
|
29
|
-
"-y",
|
|
30
|
-
"wcag-mcp"
|
|
31
|
-
]
|
|
51
|
+
"args": ["-y", "wcag-mcp"]
|
|
32
52
|
},
|
|
33
53
|
{
|
|
34
54
|
"name": "aria",
|
|
55
|
+
"description": "ARIA specification reference",
|
|
35
56
|
"command": "npx",
|
|
36
|
-
"args": [
|
|
37
|
-
"-y",
|
|
38
|
-
"aria-mcp"
|
|
39
|
-
]
|
|
57
|
+
"args": ["-y", "aria-mcp"]
|
|
40
58
|
},
|
|
41
59
|
{
|
|
42
60
|
"name": "magentaa11y",
|
|
61
|
+
"description": "MagentaA11y accessibility acceptance criteria tool",
|
|
43
62
|
"command": "npx",
|
|
44
|
-
"args": [
|
|
45
|
-
"-y",
|
|
46
|
-
"magentaa11y-mcp"
|
|
47
|
-
]
|
|
63
|
+
"args": ["-y", "magentaa11y-mcp"]
|
|
48
64
|
},
|
|
49
65
|
{
|
|
50
66
|
"name": "a11y-personas",
|
|
67
|
+
"description": "Accessibility personas and user scenarios",
|
|
51
68
|
"command": "npx",
|
|
52
|
-
"args": [
|
|
53
|
-
"-y",
|
|
54
|
-
"a11y-personas-mcp"
|
|
55
|
-
]
|
|
69
|
+
"args": ["-y", "a11y-personas-mcp"]
|
|
56
70
|
},
|
|
57
71
|
{
|
|
58
72
|
"name": "arc-issues",
|
|
73
|
+
"description": "Pre-formatted a11y issue templates",
|
|
59
74
|
"command": "npx",
|
|
60
|
-
"args": [
|
|
61
|
-
"-y",
|
|
62
|
-
"arc-issues-mcp"
|
|
63
|
-
]
|
|
75
|
+
"args": ["-y", "arc-issues-mcp"]
|
|
64
76
|
}
|
|
65
77
|
]
|
|
66
|
-
}
|
|
78
|
+
}
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -23,24 +23,6 @@ async function loadPackageJson() {
|
|
|
23
23
|
return JSON.parse(raw);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const skillDescriptions = {
|
|
27
|
-
"a11y-base-web-skill": "Core accessibility testing utilities",
|
|
28
|
-
"a11y-issue-writer-skill": "Document accessibility issues",
|
|
29
|
-
"a11y-tester-skill": "Run accessibility tests",
|
|
30
|
-
"a11y-remediator-skill": "Fix accessibility issues",
|
|
31
|
-
"a11y-validator-skill": "Validate accessibility compliance",
|
|
32
|
-
"web-standards-skill": "Web standards reference",
|
|
33
|
-
"a11y-audit-fix-agent-orchestrator-skill": "Orchestrate accessibility audits"
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const mcpDescriptions = {
|
|
37
|
-
"wcag": "WCAG guidelines reference",
|
|
38
|
-
"aria": "ARIA specification reference",
|
|
39
|
-
"magentaa11y": "MagentaA11y accessibility acceptance criteria tool",
|
|
40
|
-
"a11y-personas": "Accessibility personas and user scenarios",
|
|
41
|
-
"arc-issues": "Pre-formatted a11y issue templates"
|
|
42
|
-
};
|
|
43
|
-
|
|
44
26
|
function parseArgs(argv) {
|
|
45
27
|
const args = new Set(argv.slice(2));
|
|
46
28
|
return {
|
|
@@ -69,13 +51,14 @@ async function run() {
|
|
|
69
51
|
|
|
70
52
|
console.log("\nSkills to install:");
|
|
71
53
|
config.skills.forEach((skill) => {
|
|
72
|
-
const
|
|
73
|
-
|
|
54
|
+
const name = typeof skill === "string" ? skill : skill.name;
|
|
55
|
+
const description = typeof skill === "string" ? "No description" : (skill.description || "No description");
|
|
56
|
+
console.log(`${name} - ${description}`);
|
|
74
57
|
});
|
|
75
58
|
|
|
76
59
|
console.log("\nMCP Servers to install:");
|
|
77
60
|
config.mcpServers.forEach((server) => {
|
|
78
|
-
const description =
|
|
61
|
+
const description = server.description || "No description";
|
|
79
62
|
console.log(`${server.name} - ${description}`);
|
|
80
63
|
});
|
|
81
64
|
console.log("");
|
|
@@ -179,7 +162,8 @@ async function run() {
|
|
|
179
162
|
? ideSelection.map((ide) => idePaths[ide].localSkillsDir)
|
|
180
163
|
: ideSelection.map((ide) => idePaths[ide].skillsDir);
|
|
181
164
|
|
|
182
|
-
const
|
|
165
|
+
const skillNames = config.skills.map((skill) => typeof skill === "string" ? skill : skill.name);
|
|
166
|
+
const result = await installSkillsFromNpm(skillNames, skillTargets, tempDir, config.skillsFolder, config.readmeTemplate);
|
|
183
167
|
skillsSpinner.succeed(`${result.installed} skills installed to ${skillTargets.length} IDE location(s).`);
|
|
184
168
|
} catch (error) {
|
|
185
169
|
skillsSpinner.fail(`Failed to install skills: ${error.message}`);
|
|
@@ -214,9 +198,10 @@ async function run() {
|
|
|
214
198
|
info("MCP servers use npx - no local installation needed!");
|
|
215
199
|
console.log("");
|
|
216
200
|
success("Next Steps:");
|
|
201
|
+
const skillsFolderPath = config.skillsFolder ? `${config.skillsFolder}/` : "";
|
|
217
202
|
const skillsPath = scope === "local"
|
|
218
|
-
? `.claude/skills
|
|
219
|
-
: `~/.claude/skills
|
|
203
|
+
? `.claude/skills/${skillsFolderPath}README.md (or your IDE's equivalent)`
|
|
204
|
+
: `~/.claude/skills/${skillsFolderPath}README.md (or your IDE's global skills directory)`;
|
|
220
205
|
info(`📖 Check ${skillsPath} for comprehensive usage guide`);
|
|
221
206
|
info("✨ Includes 70+ example prompts for all skills and MCP servers");
|
|
222
207
|
info("🚀 Start with the 'Getting Started' section for your first accessibility check");
|
package/src/installers/skills.js
CHANGED
|
@@ -17,20 +17,32 @@ async function pathExists(target) {
|
|
|
17
17
|
|
|
18
18
|
function run(command, args, options = {}) {
|
|
19
19
|
return new Promise((resolve, reject) => {
|
|
20
|
-
const child = spawn(command, args, {
|
|
20
|
+
const child = spawn(command, args, {
|
|
21
|
+
stdio: "pipe",
|
|
22
|
+
shell: true,
|
|
23
|
+
...options,
|
|
24
|
+
});
|
|
21
25
|
let stdout = "";
|
|
22
26
|
let stderr = "";
|
|
23
|
-
|
|
24
|
-
child.stdout?.on("data", (data) => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
|
|
28
|
+
child.stdout?.on("data", (data) => {
|
|
29
|
+
stdout += data;
|
|
30
|
+
});
|
|
31
|
+
child.stderr?.on("data", (data) => {
|
|
32
|
+
stderr += data;
|
|
33
|
+
});
|
|
34
|
+
|
|
27
35
|
child.on("error", reject);
|
|
28
36
|
child.on("close", (code) => {
|
|
29
37
|
if (code === 0) {
|
|
30
38
|
resolve({ stdout, stderr });
|
|
31
39
|
return;
|
|
32
40
|
}
|
|
33
|
-
reject(
|
|
41
|
+
reject(
|
|
42
|
+
new Error(
|
|
43
|
+
`${command} ${args.join(" ")} failed with code ${code}: ${stderr}`,
|
|
44
|
+
),
|
|
45
|
+
);
|
|
34
46
|
});
|
|
35
47
|
});
|
|
36
48
|
}
|
|
@@ -43,18 +55,26 @@ async function cleanupTemp(tempDir) {
|
|
|
43
55
|
|
|
44
56
|
/**
|
|
45
57
|
* Install skills from npm packages into IDE skills directories.
|
|
46
|
-
*
|
|
58
|
+
*
|
|
47
59
|
* 1. Creates temp directory with package.json listing skills as dependencies
|
|
48
60
|
* 2. Runs npm install in temp directory
|
|
49
61
|
* 3. Copies installed skill packages (SKILL.md files) to target directories
|
|
50
62
|
* 4. Returns temp directory path for cleanup
|
|
51
|
-
*
|
|
63
|
+
*
|
|
52
64
|
* @param {string[]} skills - Array of npm package names
|
|
53
65
|
* @param {string[]} targetDirs - Array of target directories to install skills to
|
|
54
66
|
* @param {string} tempDir - Temporary directory for npm install
|
|
67
|
+
* @param {string} skillsFolder - Optional subfolder name to bundle skills (e.g., "a11y")
|
|
68
|
+
* @param {string} readmeTemplate - README template filename from templates folder
|
|
55
69
|
* @returns {Promise<{installed: number, tempDir: string}>}
|
|
56
70
|
*/
|
|
57
|
-
async function installSkillsFromNpm(
|
|
71
|
+
async function installSkillsFromNpm(
|
|
72
|
+
skills,
|
|
73
|
+
targetDirs,
|
|
74
|
+
tempDir,
|
|
75
|
+
skillsFolder = null,
|
|
76
|
+
readmeTemplate = "deploy-README.md",
|
|
77
|
+
) {
|
|
58
78
|
// Create temp directory
|
|
59
79
|
await fs.mkdir(tempDir, { recursive: true });
|
|
60
80
|
|
|
@@ -63,7 +83,7 @@ async function installSkillsFromNpm(skills, targetDirs, tempDir) {
|
|
|
63
83
|
name: "a11y-skills-temp",
|
|
64
84
|
version: "1.0.0",
|
|
65
85
|
private: true,
|
|
66
|
-
dependencies: {}
|
|
86
|
+
dependencies: {},
|
|
67
87
|
};
|
|
68
88
|
|
|
69
89
|
for (const skill of skills) {
|
|
@@ -72,7 +92,7 @@ async function installSkillsFromNpm(skills, targetDirs, tempDir) {
|
|
|
72
92
|
|
|
73
93
|
await fs.writeFile(
|
|
74
94
|
path.join(tempDir, "package.json"),
|
|
75
|
-
JSON.stringify(packageJson, null, 2)
|
|
95
|
+
JSON.stringify(packageJson, null, 2),
|
|
76
96
|
);
|
|
77
97
|
|
|
78
98
|
// Run npm install
|
|
@@ -83,7 +103,12 @@ async function installSkillsFromNpm(skills, targetDirs, tempDir) {
|
|
|
83
103
|
let installedCount = 0;
|
|
84
104
|
|
|
85
105
|
for (const targetDir of targetDirs) {
|
|
86
|
-
|
|
106
|
+
// Determine the actual skills directory (with or without bundle folder)
|
|
107
|
+
const skillsDir = skillsFolder
|
|
108
|
+
? path.join(targetDir, skillsFolder)
|
|
109
|
+
: targetDir;
|
|
110
|
+
|
|
111
|
+
await fs.mkdir(skillsDir, { recursive: true });
|
|
87
112
|
|
|
88
113
|
for (const skill of skills) {
|
|
89
114
|
const skillPackageDir = path.join(nodeModulesDir, skill);
|
|
@@ -92,7 +117,7 @@ async function installSkillsFromNpm(skills, targetDirs, tempDir) {
|
|
|
92
117
|
if (await pathExists(skillMdPath)) {
|
|
93
118
|
// Create skill directory in target (use package name without -skill suffix)
|
|
94
119
|
const skillDirName = skill.replace(/-skill$/, "");
|
|
95
|
-
const targetSkillDir = path.join(
|
|
120
|
+
const targetSkillDir = path.join(skillsDir, skillDirName);
|
|
96
121
|
await fs.mkdir(targetSkillDir, { recursive: true });
|
|
97
122
|
|
|
98
123
|
// Copy SKILL.md
|
|
@@ -102,20 +127,23 @@ async function installSkillsFromNpm(skills, targetDirs, tempDir) {
|
|
|
102
127
|
}
|
|
103
128
|
|
|
104
129
|
// Copy the comprehensive README template to the skills directory
|
|
105
|
-
const readmeTemplatePath = path.join(
|
|
106
|
-
|
|
130
|
+
const readmeTemplatePath = path.join(
|
|
131
|
+
__dirname,
|
|
132
|
+
"..",
|
|
133
|
+
"..",
|
|
134
|
+
"templates",
|
|
135
|
+
readmeTemplate,
|
|
136
|
+
);
|
|
137
|
+
const targetReadmePath = path.join(skillsDir, "a11y-devkit-README.md");
|
|
107
138
|
if (await pathExists(readmeTemplatePath)) {
|
|
108
139
|
await fs.copyFile(readmeTemplatePath, targetReadmePath);
|
|
109
140
|
}
|
|
110
141
|
}
|
|
111
142
|
|
|
112
|
-
return {
|
|
113
|
-
installed: installedCount / targetDirs.length,
|
|
114
|
-
tempDir
|
|
143
|
+
return {
|
|
144
|
+
installed: installedCount / targetDirs.length,
|
|
145
|
+
tempDir,
|
|
115
146
|
};
|
|
116
147
|
}
|
|
117
148
|
|
|
118
|
-
export {
|
|
119
|
-
installSkillsFromNpm,
|
|
120
|
-
cleanupTemp
|
|
121
|
-
};
|
|
149
|
+
export { installSkillsFromNpm, cleanupTemp };
|
|
File without changes
|