ma-agents 2.16.0 → 2.16.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/.agent/workflows/bmad-agent-bmad-master.md +15 -0
- package/.agent/workflows/bmad-agent-bmm-analyst.md +15 -0
- package/.agent/workflows/bmad-agent-bmm-architect.md +15 -0
- package/.agent/workflows/bmad-agent-bmm-dev.md +15 -0
- package/.agent/workflows/bmad-agent-bmm-pm.md +15 -0
- package/.agent/workflows/bmad-agent-bmm-qa.md +15 -0
- package/.agent/workflows/bmad-agent-bmm-quick-flow-solo-dev.md +15 -0
- package/.agent/workflows/bmad-agent-bmm-sm.md +15 -0
- package/.agent/workflows/bmad-agent-bmm-tech-writer.md +15 -0
- package/.agent/workflows/bmad-agent-bmm-ux-designer.md +15 -0
- package/.agent/workflows/bmad-agent-cis-brainstorming-coach.md +15 -0
- package/.agent/workflows/bmad-agent-cis-creative-problem-solver.md +15 -0
- package/.agent/workflows/bmad-agent-cis-design-thinking-coach.md +15 -0
- package/.agent/workflows/bmad-agent-cis-innovation-strategist.md +15 -0
- package/.agent/workflows/bmad-agent-cis-presentation-master.md +15 -0
- package/.agent/workflows/bmad-agent-cis-storyteller.md +15 -0
- package/.agent/workflows/bmad-bmm-check-implementation-readiness.md +6 -0
- package/.agent/workflows/bmad-bmm-code-review.md +14 -0
- package/.agent/workflows/bmad-bmm-correct-course.md +14 -0
- package/.agent/workflows/bmad-bmm-create-architecture.md +6 -0
- package/.agent/workflows/bmad-bmm-create-epics-and-stories.md +6 -0
- package/.agent/workflows/bmad-bmm-create-prd.md +6 -0
- package/.agent/workflows/bmad-bmm-create-product-brief.md +6 -0
- package/.agent/workflows/bmad-bmm-create-story.md +14 -0
- package/.agent/workflows/bmad-bmm-create-ux-design.md +6 -0
- package/.agent/workflows/bmad-bmm-dev-story.md +14 -0
- package/.agent/workflows/bmad-bmm-document-project.md +14 -0
- package/.agent/workflows/bmad-bmm-domain-research.md +6 -0
- package/.agent/workflows/bmad-bmm-edit-prd.md +6 -0
- package/.agent/workflows/bmad-bmm-generate-project-context.md +6 -0
- package/.agent/workflows/bmad-bmm-market-research.md +6 -0
- package/.agent/workflows/bmad-bmm-qa-generate-e2e-tests.md +14 -0
- package/.agent/workflows/bmad-bmm-quick-dev.md +6 -0
- package/.agent/workflows/bmad-bmm-quick-spec.md +6 -0
- package/.agent/workflows/bmad-bmm-retrospective.md +14 -0
- package/.agent/workflows/bmad-bmm-sprint-planning.md +14 -0
- package/.agent/workflows/bmad-bmm-sprint-status.md +14 -0
- package/.agent/workflows/bmad-bmm-technical-research.md +6 -0
- package/.agent/workflows/bmad-bmm-validate-prd.md +6 -0
- package/.agent/workflows/bmad-brainstorming.md +6 -0
- package/.agent/workflows/bmad-cis-design-thinking.md +14 -0
- package/.agent/workflows/bmad-cis-innovation-strategy.md +14 -0
- package/.agent/workflows/bmad-cis-problem-solving.md +14 -0
- package/.agent/workflows/bmad-cis-storytelling.md +14 -0
- package/.agent/workflows/bmad-editorial-review-prose.md +10 -0
- package/.agent/workflows/bmad-editorial-review-structure.md +10 -0
- package/.agent/workflows/bmad-help.md +10 -0
- package/.agent/workflows/bmad-index-docs.md +10 -0
- package/.agent/workflows/bmad-party-mode.md +6 -0
- package/.agent/workflows/bmad-review-adversarial-general.md +10 -0
- package/.agent/workflows/bmad-review-edge-case-hunter.md +10 -0
- package/.agent/workflows/bmad-shard-doc.md +10 -0
- package/README.md +43 -27
- package/bin/cli.js +37 -11
- package/lib/agents.js +18 -1
- package/lib/bmad.js +33 -8
- package/lib/installer.js +112 -38
- package/package.json +3 -3
package/lib/installer.js
CHANGED
|
@@ -5,7 +5,7 @@ const prompts = require('prompts');
|
|
|
5
5
|
const { getAgent, getAllAgents } = require('./agents');
|
|
6
6
|
|
|
7
7
|
const MANIFEST_FILE = '.ma-agents.json';
|
|
8
|
-
const MANIFEST_VERSION = '1.
|
|
8
|
+
const MANIFEST_VERSION = '1.1.0';
|
|
9
9
|
|
|
10
10
|
function getPackageVersion() {
|
|
11
11
|
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
@@ -37,13 +37,33 @@ function ensureManifest(installPath, agentId, scope) {
|
|
|
37
37
|
manifest = {
|
|
38
38
|
manifestVersion: MANIFEST_VERSION,
|
|
39
39
|
agent: agentId,
|
|
40
|
+
agents: [agentId],
|
|
40
41
|
scope: scope,
|
|
41
42
|
skills: {}
|
|
42
43
|
};
|
|
44
|
+
} else {
|
|
45
|
+
// Migrate v1.0.0 manifests: add agents array if missing
|
|
46
|
+
if (!manifest.agents) {
|
|
47
|
+
manifest.agents = manifest.agent ? [manifest.agent] : [];
|
|
48
|
+
}
|
|
49
|
+
// Add current agent if not already present
|
|
50
|
+
if (agentId && !manifest.agents.includes(agentId)) {
|
|
51
|
+
manifest.agents.push(agentId);
|
|
52
|
+
}
|
|
53
|
+
// Keep backward-compat agent field as first agent
|
|
54
|
+
manifest.agent = manifest.agents[0] || null;
|
|
43
55
|
}
|
|
44
56
|
return manifest;
|
|
45
57
|
}
|
|
46
58
|
|
|
59
|
+
function getManifestAgents(manifest) {
|
|
60
|
+
if (!manifest) return [];
|
|
61
|
+
if (manifest.agents && Array.isArray(manifest.agents)) {
|
|
62
|
+
return manifest.agents;
|
|
63
|
+
}
|
|
64
|
+
return manifest.agent ? [manifest.agent] : [];
|
|
65
|
+
}
|
|
66
|
+
|
|
47
67
|
function getInstalledSkillInfo(installPath, skillId) {
|
|
48
68
|
const manifest = readManifest(installPath);
|
|
49
69
|
if (!manifest || !manifest.skills || !manifest.skills[skillId]) {
|
|
@@ -52,13 +72,13 @@ function getInstalledSkillInfo(installPath, skillId) {
|
|
|
52
72
|
return manifest.skills[skillId];
|
|
53
73
|
}
|
|
54
74
|
|
|
55
|
-
async function generateSkillsManifest(installPath
|
|
75
|
+
async function generateSkillsManifest(installPath) {
|
|
56
76
|
const skills = listSkills();
|
|
57
77
|
const manifest = readManifest(installPath);
|
|
58
78
|
if (!manifest || !manifest.skills) return;
|
|
59
79
|
|
|
60
80
|
const manifestYamlPath = path.join(installPath, 'MANIFEST.yaml');
|
|
61
|
-
let yamlContent = '#
|
|
81
|
+
let yamlContent = '# MANIFEST.yaml\n\nskills:\n';
|
|
62
82
|
|
|
63
83
|
const skillIds = Object.keys(manifest.skills).sort();
|
|
64
84
|
for (const skillId of skillIds) {
|
|
@@ -66,7 +86,7 @@ async function generateSkillsManifest(installPath, agent) {
|
|
|
66
86
|
if (!skill) continue;
|
|
67
87
|
|
|
68
88
|
yamlContent += ` - id: ${skillId}\n`;
|
|
69
|
-
yamlContent += ` file:
|
|
89
|
+
yamlContent += ` file: ${skillId}/SKILL.md\n`;
|
|
70
90
|
yamlContent += ` description: ${skill.description}\n`;
|
|
71
91
|
|
|
72
92
|
if (skill.applies_when && Array.isArray(skill.applies_when)) {
|
|
@@ -91,7 +111,7 @@ async function updateAgentInstructions(agent, projectRoot) {
|
|
|
91
111
|
if (!agent.instructionFiles || agent.instructionFiles.length === 0) return;
|
|
92
112
|
|
|
93
113
|
const agentProjectPath = agent.getProjectPath();
|
|
94
|
-
const relManifestPath = path.relative(
|
|
114
|
+
const relManifestPath = path.relative(projectRoot, path.join(agentProjectPath, 'MANIFEST.yaml')).replace(/\\/g, '/');
|
|
95
115
|
|
|
96
116
|
const planningInstruction = `
|
|
97
117
|
# AI Agent Skills - Planning Instruction
|
|
@@ -259,16 +279,26 @@ async function installSkill(skillId, agentIds, customPath = '', scope = 'project
|
|
|
259
279
|
|
|
260
280
|
console.log(chalk.cyan(`\nInstalling skill: ${skill.name} v${skill.version}`));
|
|
261
281
|
|
|
282
|
+
// Group agents by their resolved install path to avoid redundant installs
|
|
283
|
+
const pathGroups = new Map();
|
|
262
284
|
for (const agentId of agentIds) {
|
|
263
285
|
const agent = getAgent(agentId);
|
|
264
|
-
|
|
265
286
|
if (!agent) {
|
|
266
287
|
console.log(chalk.yellow(` Warning: Skipping unknown agent: ${agentId}`));
|
|
267
288
|
continue;
|
|
268
289
|
}
|
|
290
|
+
const installPath = customPath || (scope === 'global' ? agent.getGlobalPath() : agent.getProjectPath());
|
|
291
|
+
if (!pathGroups.has(installPath)) {
|
|
292
|
+
pathGroups.set(installPath, []);
|
|
293
|
+
}
|
|
294
|
+
pathGroups.get(installPath).push({ agentId, agent });
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
for (const [installPath, agentEntries] of pathGroups) {
|
|
298
|
+
const primaryAgent = agentEntries[0].agent;
|
|
299
|
+
const agentNames = agentEntries.map(e => e.agent.name).join(', ');
|
|
269
300
|
|
|
270
301
|
try {
|
|
271
|
-
const installPath = customPath || (scope === 'global' ? agent.getGlobalPath() : agent.getProjectPath());
|
|
272
302
|
await fs.ensureDir(installPath);
|
|
273
303
|
|
|
274
304
|
const installed = getInstalledSkillInfo(installPath, skillId);
|
|
@@ -284,7 +314,7 @@ async function installSkill(skillId, agentIds, customPath = '', scope = 'project
|
|
|
284
314
|
action = batchState.globalAction;
|
|
285
315
|
} else if (cmp > 0) {
|
|
286
316
|
// Upgrade available
|
|
287
|
-
console.log(chalk.yellow(` ${skill.name} v${installed.version} → v${skill.version} update available for ${
|
|
317
|
+
console.log(chalk.yellow(` ${skill.name} v${installed.version} → v${skill.version} update available for ${agentNames}`));
|
|
288
318
|
const { choice } = await prompts({
|
|
289
319
|
type: 'select',
|
|
290
320
|
name: 'choice',
|
|
@@ -301,7 +331,7 @@ async function installSkill(skillId, agentIds, customPath = '', scope = 'project
|
|
|
301
331
|
action = choice;
|
|
302
332
|
} else if (cmp === 0) {
|
|
303
333
|
// Same version
|
|
304
|
-
console.log(chalk.gray(` ${skill.name} v${installed.version} already installed for ${
|
|
334
|
+
console.log(chalk.gray(` ${skill.name} v${installed.version} already installed for ${agentNames}`));
|
|
305
335
|
const { choice } = await prompts({
|
|
306
336
|
type: 'select',
|
|
307
337
|
name: 'choice',
|
|
@@ -316,7 +346,7 @@ async function installSkill(skillId, agentIds, customPath = '', scope = 'project
|
|
|
316
346
|
action = choice;
|
|
317
347
|
} else {
|
|
318
348
|
// Downgrade
|
|
319
|
-
console.log(chalk.yellow(` ${skill.name} v${installed.version} installed, package has v${skill.version} for ${
|
|
349
|
+
console.log(chalk.yellow(` ${skill.name} v${installed.version} installed, package has v${skill.version} for ${agentNames}`));
|
|
320
350
|
const { choice } = await prompts({
|
|
321
351
|
type: 'select',
|
|
322
352
|
name: 'choice',
|
|
@@ -353,15 +383,17 @@ async function installSkill(skillId, agentIds, customPath = '', scope = 'project
|
|
|
353
383
|
|
|
354
384
|
if (action === 'remove') {
|
|
355
385
|
await performUninstall(skillId, installPath);
|
|
356
|
-
const manifest = ensureManifest(installPath, agentId, scope);
|
|
386
|
+
const manifest = ensureManifest(installPath, agentEntries[0].agentId, scope);
|
|
357
387
|
delete manifest.skills[skillId];
|
|
358
388
|
writeManifest(installPath, manifest);
|
|
359
|
-
console.log(chalk.green(` - Removed ${skill.name} from ${
|
|
389
|
+
console.log(chalk.green(` - Removed ${skill.name} from ${agentNames}`));
|
|
360
390
|
|
|
361
391
|
// Generate MANIFEST.yaml and update agent instruction files
|
|
362
|
-
await generateSkillsManifest(installPath
|
|
392
|
+
await generateSkillsManifest(installPath);
|
|
363
393
|
if (scope === 'project') {
|
|
364
|
-
|
|
394
|
+
for (const entry of agentEntries) {
|
|
395
|
+
await updateAgentInstructions(entry.agent, process.cwd());
|
|
396
|
+
}
|
|
365
397
|
}
|
|
366
398
|
continue;
|
|
367
399
|
}
|
|
@@ -374,14 +406,22 @@ async function installSkill(skillId, agentIds, customPath = '', scope = 'project
|
|
|
374
406
|
}
|
|
375
407
|
|
|
376
408
|
if (!installed || force) {
|
|
377
|
-
console.log(chalk.gray(` Installing for ${
|
|
409
|
+
console.log(chalk.gray(` Installing for ${agentNames}...`));
|
|
378
410
|
}
|
|
379
411
|
|
|
380
|
-
|
|
412
|
+
// Perform the install ONCE for this shared path
|
|
413
|
+
const success = await performInstall(skillId, skill, primaryAgent, installPath);
|
|
381
414
|
|
|
382
415
|
if (success) {
|
|
383
|
-
// Update manifest
|
|
384
|
-
const manifest = ensureManifest(installPath, agentId, scope);
|
|
416
|
+
// Update manifest with ALL agents that share this path
|
|
417
|
+
const manifest = ensureManifest(installPath, agentEntries[0].agentId, scope);
|
|
418
|
+
for (const entry of agentEntries) {
|
|
419
|
+
if (!manifest.agents.includes(entry.agentId)) {
|
|
420
|
+
manifest.agents.push(entry.agentId);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
manifest.agent = manifest.agents[0];
|
|
424
|
+
|
|
385
425
|
const now = new Date().toISOString();
|
|
386
426
|
const existing = manifest.skills[skillId];
|
|
387
427
|
manifest.skills[skillId] = {
|
|
@@ -389,14 +429,16 @@ async function installSkill(skillId, agentIds, customPath = '', scope = 'project
|
|
|
389
429
|
installedAt: existing ? existing.installedAt : now,
|
|
390
430
|
updatedAt: now,
|
|
391
431
|
installerVersion: getPackageVersion(),
|
|
392
|
-
agentVersion:
|
|
432
|
+
agentVersion: primaryAgent.version
|
|
393
433
|
};
|
|
394
434
|
writeManifest(installPath, manifest);
|
|
395
435
|
|
|
396
|
-
// Generate MANIFEST.yaml and update
|
|
397
|
-
await generateSkillsManifest(installPath
|
|
436
|
+
// Generate MANIFEST.yaml and update instruction files for ALL agents
|
|
437
|
+
await generateSkillsManifest(installPath);
|
|
398
438
|
if (scope === 'project') {
|
|
399
|
-
|
|
439
|
+
for (const entry of agentEntries) {
|
|
440
|
+
await updateAgentInstructions(entry.agent, process.cwd());
|
|
441
|
+
}
|
|
400
442
|
}
|
|
401
443
|
}
|
|
402
444
|
} catch (error) {
|
|
@@ -417,41 +459,65 @@ async function performUninstall(skillId, installPath) {
|
|
|
417
459
|
async function uninstallSkill(skillId, agentIds, customPath = '', scope = 'project') {
|
|
418
460
|
console.log(chalk.cyan(`\nUninstalling skill: ${skillId}`));
|
|
419
461
|
|
|
462
|
+
// Group agents by their resolved install path
|
|
463
|
+
const pathGroups = new Map();
|
|
420
464
|
for (const agentId of agentIds) {
|
|
421
465
|
const agent = getAgent(agentId);
|
|
422
|
-
|
|
423
466
|
if (!agent) {
|
|
424
467
|
console.log(chalk.yellow(` Warning: Skipping unknown agent: ${agentId}`));
|
|
425
468
|
continue;
|
|
426
469
|
}
|
|
470
|
+
const installPath = customPath || (scope === 'global' ? agent.getGlobalPath() : agent.getProjectPath());
|
|
471
|
+
if (!pathGroups.has(installPath)) {
|
|
472
|
+
pathGroups.set(installPath, []);
|
|
473
|
+
}
|
|
474
|
+
pathGroups.get(installPath).push({ agentId, agent });
|
|
475
|
+
}
|
|
427
476
|
|
|
477
|
+
for (const [installPath, agentEntries] of pathGroups) {
|
|
428
478
|
try {
|
|
429
|
-
const installPath = customPath || (scope === 'global' ? agent.getGlobalPath() : agent.getProjectPath());
|
|
430
479
|
const installed = getInstalledSkillInfo(installPath, skillId);
|
|
431
480
|
|
|
432
481
|
if (!installed) {
|
|
433
482
|
const skillDir = path.join(installPath, skillId);
|
|
434
483
|
if (fs.existsSync(skillDir)) {
|
|
435
484
|
await performUninstall(skillId, installPath);
|
|
436
|
-
console.log(chalk.green(` - Removed ${skillId} from ${
|
|
485
|
+
console.log(chalk.green(` - Removed ${skillId} from ${installPath} (legacy install)`));
|
|
437
486
|
} else {
|
|
438
|
-
console.log(chalk.gray(` ${skillId} is not installed
|
|
487
|
+
console.log(chalk.gray(` ${skillId} is not installed at ${installPath}`));
|
|
439
488
|
}
|
|
440
489
|
continue;
|
|
441
490
|
}
|
|
442
491
|
|
|
443
|
-
|
|
492
|
+
// Read current manifest to check which agents still need this path
|
|
493
|
+
const manifest = readManifest(installPath) || { agents: [], skills: {} };
|
|
494
|
+
const currentAgents = getManifestAgents(manifest);
|
|
444
495
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
496
|
+
// Remove the requested agents from the manifest's agent list
|
|
497
|
+
const agentIdsToRemove = new Set(agentEntries.map(e => e.agentId));
|
|
498
|
+
const remainingAgents = currentAgents.filter(id => !agentIdsToRemove.has(id));
|
|
499
|
+
|
|
500
|
+
if (remainingAgents.length === 0) {
|
|
501
|
+
// No agents left that need this skill at this path -> delete the files
|
|
502
|
+
await performUninstall(skillId, installPath);
|
|
503
|
+
delete manifest.skills[skillId];
|
|
504
|
+
console.log(chalk.green(` - Removed ${skillId} v${installed.version} from ${installPath}`));
|
|
505
|
+
} else {
|
|
506
|
+
// Other agents still need the files, just update the manifest
|
|
507
|
+
console.log(chalk.gray(` ${skillId} still needed by ${remainingAgents.join(', ')} at ${installPath}, keeping files`));
|
|
508
|
+
}
|
|
448
509
|
|
|
449
|
-
|
|
510
|
+
// Update the agents list in manifest
|
|
511
|
+
manifest.agents = remainingAgents;
|
|
512
|
+
manifest.agent = remainingAgents[0] || null;
|
|
513
|
+
writeManifest(installPath, manifest);
|
|
450
514
|
|
|
451
|
-
//
|
|
452
|
-
await generateSkillsManifest(installPath
|
|
515
|
+
// Regenerate MANIFEST.yaml and update instruction files
|
|
516
|
+
await generateSkillsManifest(installPath);
|
|
453
517
|
if (scope === 'project') {
|
|
454
|
-
|
|
518
|
+
for (const entry of agentEntries) {
|
|
519
|
+
await updateAgentInstructions(entry.agent, process.cwd());
|
|
520
|
+
}
|
|
455
521
|
}
|
|
456
522
|
} catch (error) {
|
|
457
523
|
console.log(chalk.red(` x Failed: ${error.message}`));
|
|
@@ -472,13 +538,20 @@ function getStatus(agentIds, customPath = '', scope = 'project') {
|
|
|
472
538
|
const projectPath = agent.getProjectPath();
|
|
473
539
|
const globalPath = agent.getGlobalPath();
|
|
474
540
|
|
|
475
|
-
//
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
:
|
|
541
|
+
// Filter paths based on scope
|
|
542
|
+
let pathsToCheck;
|
|
543
|
+
if (customPath) {
|
|
544
|
+
pathsToCheck = [{ path: customPath, scope: 'custom' }];
|
|
545
|
+
} else if (scope === 'global') {
|
|
546
|
+
pathsToCheck = [{ path: globalPath, scope: 'global' }];
|
|
547
|
+
} else if (scope === 'project') {
|
|
548
|
+
pathsToCheck = [{ path: projectPath, scope: 'project' }];
|
|
549
|
+
} else {
|
|
550
|
+
pathsToCheck = [
|
|
479
551
|
{ path: projectPath, scope: 'project' },
|
|
480
552
|
{ path: globalPath, scope: 'global' }
|
|
481
553
|
];
|
|
554
|
+
}
|
|
482
555
|
|
|
483
556
|
for (const { path: checkPath, scope: checkScope } of pathsToCheck) {
|
|
484
557
|
const manifest = readManifest(checkPath);
|
|
@@ -506,5 +579,6 @@ module.exports = {
|
|
|
506
579
|
getStatus,
|
|
507
580
|
readManifest,
|
|
508
581
|
getInstalledSkillInfo,
|
|
582
|
+
getManifestAgents,
|
|
509
583
|
compareSemver
|
|
510
584
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ma-agents",
|
|
3
|
-
"version": "2.16.
|
|
3
|
+
"version": "2.16.1",
|
|
4
4
|
"description": "NPX tool to install skills for AI coding agents (Claude Code, Gemini, Copilot, Kilocode, Cline, Cursor)",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -30,6 +30,6 @@
|
|
|
30
30
|
"fs-extra": "^11.1.1"
|
|
31
31
|
},
|
|
32
32
|
"engines": {
|
|
33
|
-
"node": ">=
|
|
33
|
+
"node": ">=16.0.0"
|
|
34
34
|
}
|
|
35
|
-
}
|
|
35
|
+
}
|