a11y-devkit-deploy 0.7.0 → 0.7.1

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/config/a11y.json CHANGED
@@ -31,18 +31,50 @@
31
31
  "description": "Orchestrate accessibility audits"
32
32
  }
33
33
  ],
34
- "ideSkillsPaths": {
35
- "claude": ".claude/skills",
36
- "cursor": ".cursor/skills",
37
- "codex": ".codex/skills",
38
- "vscode": ".github/skills"
39
- },
40
- "ideMcpPaths": {
41
- "claude": ".claude/mcp.json",
42
- "cursor": ".cursor/mcp.json",
43
- "codex": ".codex/mcp.json",
44
- "vscode": ".github/mcp.json"
45
- },
34
+ "ides": [
35
+ {
36
+ "id": "claude",
37
+ "displayName": "Claude Code",
38
+ "mcpServerKey": "servers",
39
+ "skillsFolder": ".claude/skills",
40
+ "mcpConfigFile": ".claude/mcp.json"
41
+ },
42
+ {
43
+ "id": "cursor",
44
+ "displayName": "Cursor",
45
+ "mcpServerKey": "mcpServers",
46
+ "skillsFolder": ".cursor/skills",
47
+ "mcpConfigFile": ".cursor/mcp.json"
48
+ },
49
+ {
50
+ "id": "codex",
51
+ "displayName": "Codex",
52
+ "mcpServerKey": "servers",
53
+ "skillsFolder": ".codex/skills",
54
+ "mcpConfigFile": ".codex/mcp.json"
55
+ },
56
+ {
57
+ "id": "vscode",
58
+ "displayName": "VSCode",
59
+ "mcpServerKey": "servers",
60
+ "skillsFolder": ".github/skills",
61
+ "mcpConfigFile": ".github/mcp.json"
62
+ },
63
+ {
64
+ "id": "windsurf",
65
+ "displayName": "Windsurf",
66
+ "mcpServerKey": "servers",
67
+ "skillsFolder": ".codeium/windsurf/skills",
68
+ "mcpConfigFile": ".codeium/windsurf/mcp_config.json"
69
+ },
70
+ {
71
+ "id": "factory",
72
+ "displayName": "Factory",
73
+ "mcpServerKey": "mcpServers",
74
+ "skillsFolder": ".factory/skills",
75
+ "mcpConfigFile": ".factory/mcp.json"
76
+ }
77
+ ],
46
78
  "mcpServers": [
47
79
  {
48
80
  "name": "wcag",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "a11y-devkit-deploy",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
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
@@ -27,7 +27,11 @@ function parseArgs(argv) {
27
27
  const args = new Set(argv.slice(2));
28
28
  return {
29
29
  autoYes: args.has("--yes") || args.has("-y"),
30
- scope: args.has("--global") ? "global" : args.has("--local") ? "local" : null
30
+ scope: args.has("--global")
31
+ ? "global"
32
+ : args.has("--local")
33
+ ? "local"
34
+ : null,
31
35
  };
32
36
  }
33
37
 
@@ -43,17 +47,23 @@ async function run() {
43
47
  const platformInfo = getPlatform();
44
48
  const config = await loadConfig();
45
49
  const pkg = await loadPackageJson();
46
- const idePaths = getIdePaths(projectRoot, platformInfo, config.ideSkillsPaths, config.ideMcpPaths);
50
+ const idePaths = getIdePaths(projectRoot, platformInfo, config.ides);
47
51
  const args = parseArgs(process.argv);
48
52
 
49
- header(`A11y Devkit Deploy v${pkg.version}`, "Install skills + MCP servers across IDEs");
53
+ header(
54
+ `A11y Devkit Deploy v${pkg.version}`,
55
+ "Install skills + MCP servers across IDEs",
56
+ );
50
57
  info(`Detected OS: ${formatOs(platformInfo)}`);
51
58
 
52
59
  console.log("\nSkills to install:");
53
60
  config.skills.forEach((skill) => {
54
61
  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}`);
62
+ const description =
63
+ typeof skill === "string"
64
+ ? "No description"
65
+ : skill.description || "No description";
66
+ console.log(`- ${name}: ${description}`);
57
67
  });
58
68
 
59
69
  console.log("\nMCP Servers to install:");
@@ -63,16 +73,14 @@ async function run() {
63
73
  });
64
74
  console.log("");
65
75
 
66
- const ideChoices = [
67
- { title: "Claude Code", value: "claude" },
68
- { title: "Cursor", value: "cursor" },
69
- { title: "Codex", value: "codex" },
70
- { title: "VSCode", value: "vscode" }
71
- ];
76
+ const ideChoices = config.ides.map((ide) => ({
77
+ title: ide.displayName,
78
+ value: ide.id,
79
+ }));
72
80
 
73
81
  let scope = args.scope;
74
82
  let mcpScope = null;
75
- let ideSelection = ["claude", "cursor", "codex", "vscode"];
83
+ let ideSelection = config.ides.map((ide) => ide.id);
76
84
  let installSkills = true;
77
85
 
78
86
  if (!args.autoYes) {
@@ -83,10 +91,13 @@ async function run() {
83
91
  name: "scope",
84
92
  message: "Install skills + repo locally or globally?",
85
93
  choices: [
86
- { title: `Local to this project (${formatPath(projectRoot)})`, value: "local" },
87
- { title: "Global for this user", value: "global" }
94
+ {
95
+ title: `Local to this project (${formatPath(projectRoot)})`,
96
+ value: "local",
97
+ },
98
+ { title: "Global for this user", value: "global" },
88
99
  ],
89
- initial: 0
100
+ initial: 0,
90
101
  },
91
102
  {
92
103
  type: "select",
@@ -96,22 +107,23 @@ async function run() {
96
107
  {
97
108
  title: `Local to this project (${formatPath(projectRoot)})`,
98
109
  value: "local",
99
- description: "Write to project-level IDE config folders (version-controllable)"
110
+ description:
111
+ "Write to project-level IDE config folders (version-controllable)",
100
112
  },
101
113
  {
102
114
  title: "Global for this user",
103
115
  value: "global",
104
- description: "Write to user-level IDE config folders"
105
- }
116
+ description: "Write to user-level IDE config folders",
117
+ },
106
118
  ],
107
- initial: 0
119
+ initial: 0,
108
120
  },
109
121
  {
110
122
  type: "multiselect",
111
123
  name: "ides",
112
124
  message: "Configure MCP for which IDEs?",
113
125
  choices: ideChoices,
114
- initial: ideChoices.map((_, index) => index)
126
+ initial: ideChoices.map((_, index) => index),
115
127
  },
116
128
  {
117
129
  type: "toggle",
@@ -119,15 +131,15 @@ async function run() {
119
131
  message: "Install skills into IDE skills folders?",
120
132
  active: "yes",
121
133
  inactive: "no",
122
- initial: true
123
- }
134
+ initial: true,
135
+ },
124
136
  ],
125
137
  {
126
138
  onCancel: () => {
127
139
  warn("Setup cancelled.");
128
140
  process.exit(0);
129
- }
130
- }
141
+ },
142
+ },
131
143
  );
132
144
 
133
145
  scope = scope || response.scope;
@@ -158,13 +170,24 @@ async function run() {
158
170
  const skillsSpinner = startSpinner("Installing skills from npm...");
159
171
 
160
172
  try {
161
- const skillTargets = scope === "local"
162
- ? ideSelection.map((ide) => idePaths[ide].localSkillsDir)
163
- : ideSelection.map((ide) => idePaths[ide].skillsDir);
164
-
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);
167
- skillsSpinner.succeed(`${result.installed} skills installed to ${skillTargets.length} IDE location(s).`);
173
+ const skillTargets =
174
+ scope === "local"
175
+ ? ideSelection.map((ide) => idePaths[ide].localSkillsDir)
176
+ : ideSelection.map((ide) => idePaths[ide].skillsDir);
177
+
178
+ const skillNames = config.skills.map((skill) =>
179
+ typeof skill === "string" ? skill : skill.name,
180
+ );
181
+ const result = await installSkillsFromNpm(
182
+ skillNames,
183
+ skillTargets,
184
+ tempDir,
185
+ config.skillsFolder,
186
+ config.readmeTemplate,
187
+ );
188
+ skillsSpinner.succeed(
189
+ `${result.installed} skills installed to ${skillTargets.length} IDE location(s).`,
190
+ );
168
191
  } catch (error) {
169
192
  skillsSpinner.fail(`Failed to install skills: ${error.message}`);
170
193
  }
@@ -174,19 +197,22 @@ async function run() {
174
197
 
175
198
  // Configure MCP servers using npx (no local installation needed!)
176
199
  const mcpSpinner = startSpinner("Updating MCP configurations...");
177
- const mcpConfigPaths = mcpScope === "local"
178
- ? ideSelection.map((ide) => idePaths[ide].localMcpConfig)
179
- : ideSelection.map((ide) => idePaths[ide].mcpConfig);
200
+ const mcpConfigPaths =
201
+ mcpScope === "local"
202
+ ? ideSelection.map((ide) => idePaths[ide].localMcpConfig)
203
+ : ideSelection.map((ide) => idePaths[ide].mcpConfig);
180
204
 
181
205
  for (let i = 0; i < ideSelection.length; i++) {
182
206
  const ide = ideSelection[i];
183
207
  await installMcpConfig(
184
208
  mcpConfigPaths[i],
185
209
  config.mcpServers,
186
- idePaths[ide].mcpServerKey
210
+ idePaths[ide].mcpServerKey,
187
211
  );
188
212
  }
189
- mcpSpinner.succeed(`MCP configs updated for ${ideSelection.length} IDE(s) (${mcpScope} scope).`);
213
+ mcpSpinner.succeed(
214
+ `MCP configs updated for ${ideSelection.length} IDE(s) (${mcpScope} scope).`,
215
+ );
190
216
 
191
217
  // Clean up temporary directory
192
218
  const cleanupSpinner = startSpinner("Cleaning up temporary files...");
@@ -199,17 +225,18 @@ async function run() {
199
225
  console.log("");
200
226
  success("Next Steps:");
201
227
  const skillsFolderPath = config.skillsFolder ? `${config.skillsFolder}/` : "";
202
- const skillsPath = scope === "local"
203
- ? `.claude/skills/${skillsFolderPath}README.md (or your IDE's equivalent)`
204
- : `~/.claude/skills/${skillsFolderPath}README.md (or your IDE's global skills directory)`;
228
+ const skillsPath =
229
+ scope === "local"
230
+ ? `.claude/skills/${skillsFolderPath}README.md (or your IDE's equivalent)`
231
+ : `~/.claude/skills/${skillsFolderPath}README.md (or your IDE's global skills directory)`;
205
232
  info(`📖 Check ${skillsPath} for comprehensive usage guide`);
206
233
  info("✨ Includes 70+ example prompts for all skills and MCP servers");
207
- info("🚀 Start with the 'Getting Started' section for your first accessibility check");
234
+ info(
235
+ "🚀 Start with the 'Getting Started' section for your first accessibility check",
236
+ );
208
237
  console.log("");
209
238
  info("You can re-run this CLI any time to update skills and configs.");
210
239
  info("Documentation: https://github.com/joe-watkins/a11y-devkit#readme");
211
240
  }
212
241
 
213
- export {
214
- run
215
- };
242
+ export { run };
package/src/paths.js CHANGED
@@ -30,60 +30,26 @@ function getAppSupportDir(platformInfo = getPlatform()) {
30
30
  return process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config");
31
31
  }
32
32
 
33
- function getIdePaths(projectRoot, platformInfo = getPlatform(), ideSkillsPaths = null, ideMcpPaths = null) {
34
- const appSupport = getAppSupportDir(platformInfo);
33
+ function getIdePaths(projectRoot, platformInfo = getPlatform(), ideConfigs = []) {
35
34
  const home = os.homedir();
35
+ const paths = {};
36
+
37
+ for (const ide of ideConfigs) {
38
+ // Use custom paths from config, or fall back to default pattern: ~/.{id}/
39
+ const skillsFolder = ide.skillsFolder || `.${ide.id}/skills`;
40
+ const mcpConfigFile = ide.mcpConfigFile || `.${ide.id}/mcp.json`;
41
+
42
+ paths[ide.id] = {
43
+ name: ide.displayName,
44
+ mcpConfig: path.join(home, mcpConfigFile),
45
+ localMcpConfig: path.join(projectRoot, mcpConfigFile),
46
+ mcpServerKey: ide.mcpServerKey,
47
+ skillsDir: path.join(home, skillsFolder),
48
+ localSkillsDir: path.join(projectRoot, skillsFolder)
49
+ };
50
+ }
36
51
 
37
- // Default paths if not provided via config
38
- const skillsPaths = ideSkillsPaths || {
39
- claude: ".claude/skills",
40
- cursor: ".cursor/skills",
41
- codex: ".codex/skills",
42
- vscode: ".vscode/skills",
43
- local: ".github/skills"
44
- };
45
-
46
- const mcpPaths = ideMcpPaths || {
47
- claude: ".claude/mcp.json",
48
- cursor: ".cursor/mcp.json",
49
- codex: ".codex/mcp.json",
50
- vscode: ".vscode/mcp.json"
51
- };
52
-
53
- return {
54
- claude: {
55
- name: "Claude Code",
56
- mcpConfig: path.join(appSupport, "Claude", "mcp.json"),
57
- localMcpConfig: path.join(projectRoot, mcpPaths.claude),
58
- mcpServerKey: "servers",
59
- skillsDir: path.join(home, skillsPaths.claude),
60
- localSkillsDir: path.join(projectRoot, skillsPaths.claude)
61
- },
62
- cursor: {
63
- name: "Cursor",
64
- mcpConfig: path.join(appSupport, "Cursor", "mcp.json"),
65
- localMcpConfig: path.join(projectRoot, mcpPaths.cursor),
66
- mcpServerKey: "mcpServers",
67
- skillsDir: path.join(home, skillsPaths.cursor),
68
- localSkillsDir: path.join(projectRoot, skillsPaths.cursor)
69
- },
70
- codex: {
71
- name: "Codex",
72
- mcpConfig: path.join(home, ".codex", "mcp.json"),
73
- localMcpConfig: path.join(projectRoot, mcpPaths.codex),
74
- mcpServerKey: "servers",
75
- skillsDir: path.join(home, skillsPaths.codex),
76
- localSkillsDir: path.join(projectRoot, skillsPaths.codex)
77
- },
78
- vscode: {
79
- name: "VSCode",
80
- mcpConfig: path.join(appSupport, "Code", "User", "mcp.json"),
81
- localMcpConfig: path.join(projectRoot, mcpPaths.vscode),
82
- mcpServerKey: "servers",
83
- skillsDir: path.join(home, skillsPaths.vscode),
84
- localSkillsDir: path.join(projectRoot, skillsPaths.vscode)
85
- }
86
- };
52
+ return paths;
87
53
  }
88
54
 
89
55
  export {