a11y-devkit-deploy 0.8.2 → 0.8.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.
- package/README.md +7 -7
- package/config/a11y.json +2 -12
- package/package.json +1 -1
- package/src/cli.js +51 -51
- package/src/paths.js +11 -37
package/README.md
CHANGED
|
@@ -186,13 +186,13 @@ Add an object to the `mcpServers` array with name, description, command, and arg
|
|
|
186
186
|
}
|
|
187
187
|
```
|
|
188
188
|
|
|
189
|
-
### Adding a New
|
|
189
|
+
### Adding a New Host Application
|
|
190
190
|
|
|
191
|
-
Add an object to the `
|
|
191
|
+
Add an object to the `hostApplications` array with the host application's configuration:
|
|
192
192
|
|
|
193
193
|
```json
|
|
194
194
|
{
|
|
195
|
-
"
|
|
195
|
+
"hostApplications": [
|
|
196
196
|
{
|
|
197
197
|
"id": "windsurf",
|
|
198
198
|
"displayName": "Windsurf",
|
|
@@ -204,8 +204,8 @@ Add an object to the `ides` array with the IDE's configuration:
|
|
|
204
204
|
}
|
|
205
205
|
```
|
|
206
206
|
|
|
207
|
-
**
|
|
208
|
-
- `id` - Unique identifier for the
|
|
207
|
+
**Host Application Configuration Properties:**
|
|
208
|
+
- `id` - Unique identifier for the host application
|
|
209
209
|
- `displayName` - Human-readable name shown in prompts
|
|
210
210
|
- `mcpServerKey` - MCP config key name (`"servers"` or `"mcpServers"`)
|
|
211
211
|
- `skillsFolder` - Path to skills directory (relative to home/project root)
|
|
@@ -216,7 +216,7 @@ Add an object to the `ides` array with the IDE's configuration:
|
|
|
216
216
|
- `skillsFolder` - Subfolder name to bundle skills under (e.g., "a11y")
|
|
217
217
|
- `readmeTemplate` - README template file to copy into skills directories
|
|
218
218
|
- `skills` - Array of skill objects with `name` (npm package) and `description`
|
|
219
|
-
- `
|
|
219
|
+
- `hostApplications` - Array of host application configuration objects
|
|
220
220
|
- `mcpServers` - MCP server definitions with name, description, command, and args
|
|
221
221
|
|
|
222
222
|
All changes take effect immediately - just re-run the CLI to deploy your updated config.
|
|
@@ -307,7 +307,7 @@ Here's what a complete `config/a11y.json` looks like:
|
|
|
307
307
|
"description": "Run accessibility tests"
|
|
308
308
|
}
|
|
309
309
|
],
|
|
310
|
-
"
|
|
310
|
+
"hostApplications": [
|
|
311
311
|
{
|
|
312
312
|
"id": "claude",
|
|
313
313
|
"displayName": "Claude Code",
|
package/config/a11y.json
CHANGED
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"description": "Orchestrate accessibility audits"
|
|
46
46
|
}
|
|
47
47
|
],
|
|
48
|
-
"
|
|
48
|
+
"hostApplications": [
|
|
49
49
|
{
|
|
50
50
|
"id": "claude",
|
|
51
51
|
"displayName": "Claude Code",
|
|
@@ -72,17 +72,7 @@
|
|
|
72
72
|
"displayName": "VSCode",
|
|
73
73
|
"mcpServerKey": "servers",
|
|
74
74
|
"skillsFolder": ".github/skills",
|
|
75
|
-
"mcpConfigFile": ".github/mcp.json"
|
|
76
|
-
"globalPaths": {
|
|
77
|
-
"Win": {
|
|
78
|
-
"mcpConfigFile": "Code/User/mcp.json",
|
|
79
|
-
"skillsFolder": "Code/User/skills"
|
|
80
|
-
},
|
|
81
|
-
"macOS": {
|
|
82
|
-
"mcpConfigFile": "Code/User/mcp.json",
|
|
83
|
-
"skillsFolder": "Code/User/skills"
|
|
84
|
-
}
|
|
85
|
-
}
|
|
75
|
+
"mcpConfigFile": ".github/mcp.json"
|
|
86
76
|
},
|
|
87
77
|
{
|
|
88
78
|
"id": "windsurf",
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import { fileURLToPath } from "url";
|
|
|
4
4
|
import prompts from "prompts";
|
|
5
5
|
|
|
6
6
|
import { header, info, warn, success, startSpinner, formatPath } from "./ui.js";
|
|
7
|
-
import { getPlatform,
|
|
7
|
+
import { getPlatform, getHostApplicationPaths, getTempDir, getMcpRepoDir } from "./paths.js";
|
|
8
8
|
import { installSkillsFromNpm, cleanupTemp } from "./installers/skills.js";
|
|
9
9
|
import { installMcpConfig } from "./installers/mcp.js";
|
|
10
10
|
import { getGitMcpPrompts, parseArgsString } from "./prompts/git-mcp.js";
|
|
@@ -50,20 +50,20 @@ async function run() {
|
|
|
50
50
|
const platformInfo = getPlatform();
|
|
51
51
|
const config = await loadConfig();
|
|
52
52
|
const pkg = await loadPackageJson();
|
|
53
|
-
const
|
|
53
|
+
const hostPaths = getHostApplicationPaths(projectRoot, platformInfo, config.hostApplications);
|
|
54
54
|
const args = parseArgs(process.argv);
|
|
55
55
|
|
|
56
56
|
header(
|
|
57
57
|
`A11y Devkit Deploy v${pkg.version}`,
|
|
58
58
|
args.gitMcp
|
|
59
59
|
? "Install MCP server from Git repository"
|
|
60
|
-
: "Install skills + MCP servers across
|
|
60
|
+
: "Install skills + MCP servers across host applications",
|
|
61
61
|
);
|
|
62
62
|
info(`Detected OS: ${formatOs(platformInfo)}`);
|
|
63
63
|
|
|
64
64
|
// Branch to Git MCP installation flow
|
|
65
65
|
if (args.gitMcp) {
|
|
66
|
-
await runGitMcpInstallation(projectRoot, platformInfo, config,
|
|
66
|
+
await runGitMcpInstallation(projectRoot, platformInfo, config, hostPaths, args);
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -165,14 +165,14 @@ async function run() {
|
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
const
|
|
169
|
-
title:
|
|
170
|
-
value:
|
|
168
|
+
const hostChoices = config.hostApplications.map((host) => ({
|
|
169
|
+
title: host.displayName,
|
|
170
|
+
value: host.id,
|
|
171
171
|
}));
|
|
172
172
|
|
|
173
173
|
let scope = args.scope;
|
|
174
174
|
let mcpScope = null;
|
|
175
|
-
let
|
|
175
|
+
let hostSelection = config.hostApplications.map((host) => host.id);
|
|
176
176
|
|
|
177
177
|
if (!args.autoYes) {
|
|
178
178
|
const response = await prompts(
|
|
@@ -183,7 +183,7 @@ async function run() {
|
|
|
183
183
|
message: "Install skills locally or globally?",
|
|
184
184
|
choices: [
|
|
185
185
|
{
|
|
186
|
-
title: `Local to this project (${formatPath(projectRoot)})`,
|
|
186
|
+
title: `Local to this project (${formatPath(projectRoot)}) [recommended]`,
|
|
187
187
|
value: "local",
|
|
188
188
|
},
|
|
189
189
|
{ title: "Global for this user", value: "global" },
|
|
@@ -199,22 +199,22 @@ async function run() {
|
|
|
199
199
|
title: `Local to this project (${formatPath(projectRoot)})`,
|
|
200
200
|
value: "local",
|
|
201
201
|
description:
|
|
202
|
-
"Write to project-level
|
|
202
|
+
"Write to project-level host application config folders (version-controllable)",
|
|
203
203
|
},
|
|
204
204
|
{
|
|
205
205
|
title: "Global for this user",
|
|
206
206
|
value: "global",
|
|
207
|
-
description: "Write to user-level
|
|
207
|
+
description: "Write to user-level host application config folders",
|
|
208
208
|
},
|
|
209
209
|
],
|
|
210
210
|
initial: 0,
|
|
211
211
|
},
|
|
212
212
|
{
|
|
213
213
|
type: "multiselect",
|
|
214
|
-
name: "
|
|
215
|
-
message: "Configure for which
|
|
216
|
-
choices:
|
|
217
|
-
initial:
|
|
214
|
+
name: "hosts",
|
|
215
|
+
message: "Configure for which host applications?",
|
|
216
|
+
choices: hostChoices,
|
|
217
|
+
initial: hostChoices.map((_, index) => index),
|
|
218
218
|
},
|
|
219
219
|
],
|
|
220
220
|
{
|
|
@@ -227,7 +227,7 @@ async function run() {
|
|
|
227
227
|
|
|
228
228
|
scope = scope || response.scope;
|
|
229
229
|
mcpScope = response.mcpScope || "local";
|
|
230
|
-
|
|
230
|
+
hostSelection = response.hosts || hostSelection;
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
if (!scope) {
|
|
@@ -237,8 +237,8 @@ async function run() {
|
|
|
237
237
|
mcpScope = "local";
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
if (!
|
|
241
|
-
warn("No
|
|
240
|
+
if (!hostSelection.length) {
|
|
241
|
+
warn("No host applications selected. MCP installation requires at least one host application.");
|
|
242
242
|
process.exit(1);
|
|
243
243
|
}
|
|
244
244
|
|
|
@@ -253,8 +253,8 @@ async function run() {
|
|
|
253
253
|
try {
|
|
254
254
|
const skillTargets =
|
|
255
255
|
scope === "local"
|
|
256
|
-
?
|
|
257
|
-
:
|
|
256
|
+
? hostSelection.map((host) => hostPaths[host].localSkillsDir)
|
|
257
|
+
: hostSelection.map((host) => hostPaths[host].skillsDir);
|
|
258
258
|
|
|
259
259
|
const skillNames = skillsToInstall.map((skill) =>
|
|
260
260
|
typeof skill === "string" ? skill : skill.npmName,
|
|
@@ -267,7 +267,7 @@ async function run() {
|
|
|
267
267
|
config.readmeTemplate,
|
|
268
268
|
);
|
|
269
269
|
skillsSpinner.succeed(
|
|
270
|
-
`${result.installed} skills installed to ${skillTargets.length}
|
|
270
|
+
`${result.installed} skills installed to ${skillTargets.length} host application location(s).`,
|
|
271
271
|
);
|
|
272
272
|
} catch (error) {
|
|
273
273
|
skillsSpinner.fail(`Failed to install skills: ${error.message}`);
|
|
@@ -277,19 +277,19 @@ async function run() {
|
|
|
277
277
|
const mcpSpinner = startSpinner("Updating MCP configurations...");
|
|
278
278
|
const mcpConfigPaths =
|
|
279
279
|
mcpScope === "local"
|
|
280
|
-
?
|
|
281
|
-
:
|
|
280
|
+
? hostSelection.map((host) => hostPaths[host].localMcpConfig)
|
|
281
|
+
: hostSelection.map((host) => hostPaths[host].mcpConfig);
|
|
282
282
|
|
|
283
|
-
for (let i = 0; i <
|
|
284
|
-
const
|
|
283
|
+
for (let i = 0; i < hostSelection.length; i++) {
|
|
284
|
+
const host = hostSelection[i];
|
|
285
285
|
await installMcpConfig(
|
|
286
286
|
mcpConfigPaths[i],
|
|
287
287
|
mcpServersToInstall,
|
|
288
|
-
|
|
288
|
+
hostPaths[host].mcpServerKey,
|
|
289
289
|
);
|
|
290
290
|
}
|
|
291
291
|
mcpSpinner.succeed(
|
|
292
|
-
`MCP configs updated for ${
|
|
292
|
+
`MCP configs updated for ${hostSelection.length} host application(s) (${mcpScope} scope).`,
|
|
293
293
|
);
|
|
294
294
|
|
|
295
295
|
// Clean up temporary directory
|
|
@@ -305,8 +305,8 @@ async function run() {
|
|
|
305
305
|
const skillsFolderPath = config.skillsFolder ? `${config.skillsFolder}/` : "";
|
|
306
306
|
const skillsPath =
|
|
307
307
|
scope === "local"
|
|
308
|
-
? `.claude/skills/${skillsFolderPath}README.md (or your
|
|
309
|
-
: `~/.claude/skills/${skillsFolderPath}README.md (or your
|
|
308
|
+
? `.claude/skills/${skillsFolderPath}README.md (or your host application's equivalent)`
|
|
309
|
+
: `~/.claude/skills/${skillsFolderPath}README.md (or your host application's global skills directory)`;
|
|
310
310
|
info(`📖 Check ${skillsPath} for comprehensive usage guide`);
|
|
311
311
|
info("✨ Includes 70+ example prompts for all skills and MCP servers");
|
|
312
312
|
info(
|
|
@@ -317,7 +317,7 @@ async function run() {
|
|
|
317
317
|
info("Documentation: https://github.com/joe-watkins/a11y-devkit#readme");
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
-
async function runGitMcpInstallation(projectRoot, platformInfo, config,
|
|
320
|
+
async function runGitMcpInstallation(projectRoot, platformInfo, config, hostPaths, args) {
|
|
321
321
|
// Check if --yes flag is used with --git-mcp
|
|
322
322
|
if (args.autoYes) {
|
|
323
323
|
warn("--yes flag not supported for Git MCP installation");
|
|
@@ -397,19 +397,19 @@ async function runGitMcpInstallation(projectRoot, platformInfo, config, idePaths
|
|
|
397
397
|
},
|
|
398
398
|
);
|
|
399
399
|
|
|
400
|
-
// Prompt for
|
|
401
|
-
const
|
|
402
|
-
title:
|
|
403
|
-
value:
|
|
400
|
+
// Prompt for host application selection
|
|
401
|
+
const hostChoices = config.hostApplications.map((host) => ({
|
|
402
|
+
title: host.displayName,
|
|
403
|
+
value: host.id,
|
|
404
404
|
}));
|
|
405
405
|
|
|
406
|
-
const
|
|
406
|
+
const hostResponse = await prompts(
|
|
407
407
|
{
|
|
408
408
|
type: "multiselect",
|
|
409
|
-
name: "
|
|
410
|
-
message: "Configure MCP for which
|
|
411
|
-
choices:
|
|
412
|
-
initial:
|
|
409
|
+
name: "hosts",
|
|
410
|
+
message: "Configure MCP for which host applications?",
|
|
411
|
+
choices: hostChoices,
|
|
412
|
+
initial: hostChoices.map((_, index) => index),
|
|
413
413
|
},
|
|
414
414
|
{
|
|
415
415
|
onCancel: () => {
|
|
@@ -419,10 +419,10 @@ async function runGitMcpInstallation(projectRoot, platformInfo, config, idePaths
|
|
|
419
419
|
},
|
|
420
420
|
);
|
|
421
421
|
|
|
422
|
-
const
|
|
422
|
+
const hostSelection = hostResponse.hosts || [];
|
|
423
423
|
|
|
424
|
-
if (!
|
|
425
|
-
warn("No
|
|
424
|
+
if (!hostSelection.length) {
|
|
425
|
+
warn("No host applications selected. MCP installation requires at least one host application.");
|
|
426
426
|
process.exit(1);
|
|
427
427
|
}
|
|
428
428
|
|
|
@@ -457,13 +457,13 @@ async function runGitMcpInstallation(projectRoot, platformInfo, config, idePaths
|
|
|
457
457
|
process.exit(1);
|
|
458
458
|
}
|
|
459
459
|
|
|
460
|
-
// Install MCP configurations to selected
|
|
460
|
+
// Install MCP configurations to selected host applications
|
|
461
461
|
const mcpConfigSpinner = startSpinner("Updating MCP configurations...");
|
|
462
462
|
|
|
463
463
|
const mcpConfigPaths =
|
|
464
464
|
mcpScope === "local"
|
|
465
|
-
?
|
|
466
|
-
:
|
|
465
|
+
? hostSelection.map((host) => hostPaths[host].localMcpConfig)
|
|
466
|
+
: hostSelection.map((host) => hostPaths[host].mcpConfig);
|
|
467
467
|
|
|
468
468
|
// Construct the MCP server configuration with absolute path
|
|
469
469
|
const mcpServerConfig = {
|
|
@@ -487,26 +487,26 @@ async function runGitMcpInstallation(projectRoot, platformInfo, config, idePaths
|
|
|
487
487
|
delete mcpServerConfig.args;
|
|
488
488
|
}
|
|
489
489
|
|
|
490
|
-
for (let i = 0; i <
|
|
491
|
-
const
|
|
490
|
+
for (let i = 0; i < hostSelection.length; i++) {
|
|
491
|
+
const host = hostSelection[i];
|
|
492
492
|
await installMcpConfig(
|
|
493
493
|
mcpConfigPaths[i],
|
|
494
494
|
[mcpServerConfig],
|
|
495
|
-
|
|
495
|
+
hostPaths[host].mcpServerKey,
|
|
496
496
|
);
|
|
497
497
|
}
|
|
498
498
|
|
|
499
499
|
mcpConfigSpinner.succeed(
|
|
500
|
-
`MCP configs updated for ${
|
|
500
|
+
`MCP configs updated for ${hostSelection.length} host application(s) (${mcpScope} scope).`,
|
|
501
501
|
);
|
|
502
502
|
|
|
503
503
|
// Display success message
|
|
504
504
|
success("Git MCP installation complete!");
|
|
505
505
|
info(`Repository location: ${mcpServer.repoPath}`);
|
|
506
|
-
info(`MCP server '${mcpServer.name}' configured in ${
|
|
506
|
+
info(`MCP server '${mcpServer.name}' configured in ${hostSelection.length} host application(s)`);
|
|
507
507
|
console.log("");
|
|
508
508
|
success("Next Steps:");
|
|
509
|
-
info("Restart your
|
|
509
|
+
info("Restart your host application to load the new MCP server");
|
|
510
510
|
info(`Repository cloned to: ${mcpServer.repoPath}`);
|
|
511
511
|
info("You can manually edit the MCP configuration files if needed");
|
|
512
512
|
}
|
package/src/paths.js
CHANGED
|
@@ -30,47 +30,21 @@ function getAppSupportDir(platformInfo = getPlatform()) {
|
|
|
30
30
|
return process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config");
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
function
|
|
33
|
+
function getHostApplicationPaths(projectRoot, platformInfo = getPlatform(), hostConfigs = []) {
|
|
34
34
|
const home = os.homedir();
|
|
35
|
-
const appSupport = getAppSupportDir(platformInfo);
|
|
36
35
|
const paths = {};
|
|
37
36
|
|
|
38
|
-
for (const
|
|
39
|
-
// Default paths
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// Check for platform-specific global path overrides
|
|
44
|
-
let globalSkillsFolder = skillsFolder;
|
|
45
|
-
let globalMcpConfigFile = mcpConfigFile;
|
|
46
|
-
|
|
47
|
-
if (ide.globalPaths) {
|
|
48
|
-
const platformKey = platformInfo.isWindows ? 'Win' : platformInfo.isMac ? 'macOS' : null;
|
|
49
|
-
|
|
50
|
-
if (platformKey && ide.globalPaths[platformKey]) {
|
|
51
|
-
const globalOverrides = ide.globalPaths[platformKey];
|
|
52
|
-
|
|
53
|
-
// Use app support directory + override path for global
|
|
54
|
-
if (globalOverrides.skillsFolder) {
|
|
55
|
-
globalSkillsFolder = globalOverrides.skillsFolder;
|
|
56
|
-
}
|
|
57
|
-
if (globalOverrides.mcpConfigFile) {
|
|
58
|
-
globalMcpConfigFile = globalOverrides.mcpConfigFile;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Determine base directory for global paths
|
|
64
|
-
const useAppSupport = ide.globalPaths &&
|
|
65
|
-
(platformInfo.isWindows || platformInfo.isMac);
|
|
66
|
-
const globalBase = useAppSupport ? appSupport : home;
|
|
37
|
+
for (const host of hostConfigs) {
|
|
38
|
+
// Default paths for both local and global scope
|
|
39
|
+
const skillsFolder = host.skillsFolder || `.${host.id}/skills`;
|
|
40
|
+
const mcpConfigFile = host.mcpConfigFile || `.${host.id}/mcp.json`;
|
|
67
41
|
|
|
68
|
-
paths[
|
|
69
|
-
name:
|
|
70
|
-
mcpConfig: path.join(
|
|
42
|
+
paths[host.id] = {
|
|
43
|
+
name: host.displayName,
|
|
44
|
+
mcpConfig: path.join(home, mcpConfigFile),
|
|
71
45
|
localMcpConfig: path.join(projectRoot, mcpConfigFile),
|
|
72
|
-
mcpServerKey:
|
|
73
|
-
skillsDir: path.join(
|
|
46
|
+
mcpServerKey: host.mcpServerKey,
|
|
47
|
+
skillsDir: path.join(home, skillsFolder),
|
|
74
48
|
localSkillsDir: path.join(projectRoot, skillsFolder)
|
|
75
49
|
};
|
|
76
50
|
}
|
|
@@ -90,7 +64,7 @@ function getMcpRepoDir(scope, projectRoot, platformInfo, mcpName) {
|
|
|
90
64
|
export {
|
|
91
65
|
getPlatform,
|
|
92
66
|
getAppSupportDir,
|
|
93
|
-
|
|
67
|
+
getHostApplicationPaths,
|
|
94
68
|
getTempDir,
|
|
95
69
|
getMcpRepoDir
|
|
96
70
|
};
|