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 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 7 accessibility skill packages
65
- 2. **Configuring MCP servers** - Updates each IDE's MCP config to enable 5 accessibility-focused MCP servers:
66
- - **wcag** - WCAG 2.2 guidelines, success criteria, and techniques
67
- - **aria** - WAI-ARIA roles, states, properties, and patterns
68
- - **magentaa11y** - Component accessibility acceptance criteria
69
- - **a11y-personas** - Accessibility personas for diverse user needs
70
- - **arc-issues** - Format AxeCore violations into standardized issue templates
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
- ### Skills Installed
78
+ **Fully customizable** - add/remove skills or MCP servers by editing the config file.
73
79
 
74
- The following skill packages are installed from npm:
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 the deployment:
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
- - `skills` - Array of npm package names to install as skills
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
- - `mcpServers` - MCP server definitions using npx
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
- "a11y-base-web-skill",
4
- "a11y-issue-writer-skill",
5
- "a11y-tester-skill",
6
- "a11y-remediator-skill",
7
- "a11y-validator-skill",
8
- "web-standards-skill",
9
- "a11y-audit-fix-agent-orchestrator-skill"
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "a11y-devkit-deploy",
3
- "version": "0.6.5",
3
+ "version": "0.7.0",
4
4
  "description": "CLI to deploy a11y skills and MCP servers across IDEs",
5
5
  "license": "MIT",
6
6
  "type": "module",
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 description = skillDescriptions[skill] || "No description";
73
- console.log(`${skill} - ${description}`);
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 = mcpDescriptions[server.name] || "No 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 result = await installSkillsFromNpm(config.skills, skillTargets, tempDir);
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/README.md (or your IDE's equivalent)`
219
- : `~/.claude/skills/README.md (or your IDE's global skills directory)`;
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");
@@ -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, { stdio: "pipe", shell: true, ...options });
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) => { stdout += data; });
25
- child.stderr?.on("data", (data) => { stderr += data; });
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(new Error(`${command} ${args.join(" ")} failed with code ${code}: ${stderr}`));
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(skills, targetDirs, tempDir) {
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
- await fs.mkdir(targetDir, { recursive: true });
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(targetDir, skillDirName);
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(__dirname, "..", "templates", "skills-README.md");
106
- const targetReadmePath = path.join(targetDir, "README.md");
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 };