ma-agents 1.6.0 → 1.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/CLAUDE.md +14 -0
- package/lib/agents.js +12 -6
- package/lib/installer.js +99 -3
- package/package.json +1 -1
- package/skills/git-workflow-skill/skill.json +7 -1
- package/skills/js-ts-security-skill/skill.json +13 -2
- package/skills/logging-best-practices/skill.json +5 -0
- package/skills/test-accompanied-development/skill.json +5 -0
- package/skills/test-generator/skill.json +12 -2
- package/skills/vercel-react-best-practices/skill.json +14 -2
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
<!-- MA-AGENTS-START -->
|
|
3
|
+
# AI Agent Skills - Planning Instruction
|
|
4
|
+
|
|
5
|
+
You have access to a library of skills in your skills directory. Before starting any task:
|
|
6
|
+
|
|
7
|
+
1. Read the skill manifest at skills/MANIFEST.yaml
|
|
8
|
+
2. Based on the task description, select which skills are relevant
|
|
9
|
+
3. Read only the selected skill files
|
|
10
|
+
4. Then proceed with the task
|
|
11
|
+
|
|
12
|
+
Always load skills marked with always_load: true.
|
|
13
|
+
Do not load skills that are not relevant to the current task.
|
|
14
|
+
<!-- MA-AGENTS-END -->
|
package/lib/agents.js
CHANGED
|
@@ -31,7 +31,8 @@ const agents = [
|
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
33
|
fileExtension: '.md',
|
|
34
|
-
template: 'claude-code'
|
|
34
|
+
template: 'claude-code',
|
|
35
|
+
instructionFiles: ['CLAUDE.md']
|
|
35
36
|
},
|
|
36
37
|
{
|
|
37
38
|
id: 'gemini',
|
|
@@ -50,7 +51,8 @@ const agents = [
|
|
|
50
51
|
}
|
|
51
52
|
},
|
|
52
53
|
fileExtension: '.md',
|
|
53
|
-
template: 'generic'
|
|
54
|
+
template: 'generic',
|
|
55
|
+
instructionFiles: [] // Gemini doesn't have a standard project-level instruction file yet
|
|
54
56
|
},
|
|
55
57
|
{
|
|
56
58
|
id: 'copilot',
|
|
@@ -69,7 +71,8 @@ const agents = [
|
|
|
69
71
|
}
|
|
70
72
|
},
|
|
71
73
|
fileExtension: '.md',
|
|
72
|
-
template: 'generic'
|
|
74
|
+
template: 'generic',
|
|
75
|
+
instructionFiles: [] // Copilot uses path-scoped instructions, maybe support .github/instructions/ later
|
|
73
76
|
},
|
|
74
77
|
{
|
|
75
78
|
id: 'kilocode',
|
|
@@ -88,7 +91,8 @@ const agents = [
|
|
|
88
91
|
}
|
|
89
92
|
},
|
|
90
93
|
fileExtension: '.md',
|
|
91
|
-
template: 'generic'
|
|
94
|
+
template: 'generic',
|
|
95
|
+
instructionFiles: []
|
|
92
96
|
},
|
|
93
97
|
{
|
|
94
98
|
id: 'cline',
|
|
@@ -112,7 +116,8 @@ const agents = [
|
|
|
112
116
|
resourceMap: {
|
|
113
117
|
'references': 'docs',
|
|
114
118
|
'assets': 'templates'
|
|
115
|
-
}
|
|
119
|
+
},
|
|
120
|
+
instructionFiles: ['.clinerules']
|
|
116
121
|
},
|
|
117
122
|
{
|
|
118
123
|
id: 'cursor',
|
|
@@ -131,7 +136,8 @@ const agents = [
|
|
|
131
136
|
}
|
|
132
137
|
},
|
|
133
138
|
fileExtension: '.md',
|
|
134
|
-
template: 'generic'
|
|
139
|
+
template: 'generic',
|
|
140
|
+
instructionFiles: [] // Cursor uses .cursorrules or individual .mdc files
|
|
135
141
|
}
|
|
136
142
|
];
|
|
137
143
|
|
package/lib/installer.js
CHANGED
|
@@ -52,6 +52,84 @@ function getInstalledSkillInfo(installPath, skillId) {
|
|
|
52
52
|
return manifest.skills[skillId];
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
async function generateSkillsManifest(installPath, agent) {
|
|
56
|
+
const skills = listSkills();
|
|
57
|
+
const manifest = readManifest(installPath);
|
|
58
|
+
if (!manifest || !manifest.skills) return;
|
|
59
|
+
|
|
60
|
+
const manifestYamlPath = path.join(installPath, 'MANIFEST.yaml');
|
|
61
|
+
let yamlContent = '# skills/MANIFEST.yaml\n\nskills:\n';
|
|
62
|
+
|
|
63
|
+
const skillIds = Object.keys(manifest.skills).sort();
|
|
64
|
+
for (const skillId of skillIds) {
|
|
65
|
+
const skill = skills.find(s => s.id === skillId);
|
|
66
|
+
if (!skill) continue;
|
|
67
|
+
|
|
68
|
+
yamlContent += ` - id: ${skillId}\n`;
|
|
69
|
+
yamlContent += ` file: skills/${skillId}/SKILL.md\n`;
|
|
70
|
+
yamlContent += ` description: ${skill.description}\n`;
|
|
71
|
+
|
|
72
|
+
if (skill.applies_when && Array.isArray(skill.applies_when)) {
|
|
73
|
+
yamlContent += ' applies_when:\n';
|
|
74
|
+
skill.applies_when.forEach(cond => {
|
|
75
|
+
yamlContent += ` - ${cond}\n`;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (skill.always_load) {
|
|
80
|
+
yamlContent += ' always_load: true\n';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
yamlContent += '\n';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
await fs.writeFile(manifestYamlPath, yamlContent, 'utf-8');
|
|
87
|
+
console.log(chalk.cyan(` + Generated ${manifestYamlPath}`));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function updateAgentInstructions(agent, projectRoot) {
|
|
91
|
+
if (!agent.instructionFiles || agent.instructionFiles.length === 0) return;
|
|
92
|
+
|
|
93
|
+
const planningInstruction = `
|
|
94
|
+
# AI Agent Skills - Planning Instruction
|
|
95
|
+
|
|
96
|
+
You have access to a library of skills in your skills directory. Before starting any task:
|
|
97
|
+
|
|
98
|
+
1. Read the skill manifest at skills/MANIFEST.yaml
|
|
99
|
+
2. Based on the task description, select which skills are relevant
|
|
100
|
+
3. Read only the selected skill files
|
|
101
|
+
4. Then proceed with the task
|
|
102
|
+
|
|
103
|
+
Always load skills marked with always_load: true.
|
|
104
|
+
Do not load skills that are not relevant to the current task.
|
|
105
|
+
`;
|
|
106
|
+
|
|
107
|
+
const markerStart = '<!-- MA-AGENTS-START -->';
|
|
108
|
+
const markerEnd = '<!-- MA-AGENTS-END -->';
|
|
109
|
+
const wrappedInstruction = `\n${markerStart}${planningInstruction}${markerEnd}\n`;
|
|
110
|
+
|
|
111
|
+
for (const fileName of agent.instructionFiles) {
|
|
112
|
+
const filePath = path.join(projectRoot, fileName);
|
|
113
|
+
let content = '';
|
|
114
|
+
|
|
115
|
+
if (fs.existsSync(filePath)) {
|
|
116
|
+
content = await fs.readFile(filePath, 'utf-8');
|
|
117
|
+
|
|
118
|
+
const regex = new RegExp(`${markerStart}[\\s\\S]*?${markerEnd}`, 'g');
|
|
119
|
+
if (regex.test(content)) {
|
|
120
|
+
content = content.replace(regex, wrappedInstruction.trim());
|
|
121
|
+
} else {
|
|
122
|
+
content += wrappedInstruction;
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
content = wrappedInstruction;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
await fs.writeFile(filePath, content, 'utf-8');
|
|
129
|
+
console.log(chalk.cyan(` + Updated ${fileName}`));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
55
133
|
/**
|
|
56
134
|
* Compare two semver strings. Returns -1, 0, or 1.
|
|
57
135
|
*/
|
|
@@ -252,6 +330,12 @@ async function installSkill(skillId, agentIds, customPath = '', scope = 'project
|
|
|
252
330
|
delete manifest.skills[skillId];
|
|
253
331
|
writeManifest(installPath, manifest);
|
|
254
332
|
console.log(chalk.green(` - Removed ${skill.name} from ${agent.name}`));
|
|
333
|
+
|
|
334
|
+
// Generate MANIFEST.yaml and update agent instruction files
|
|
335
|
+
await generateSkillsManifest(installPath, agent);
|
|
336
|
+
if (scope === 'project') {
|
|
337
|
+
await updateAgentInstructions(agent, process.cwd());
|
|
338
|
+
}
|
|
255
339
|
continue;
|
|
256
340
|
}
|
|
257
341
|
|
|
@@ -281,6 +365,12 @@ async function installSkill(skillId, agentIds, customPath = '', scope = 'project
|
|
|
281
365
|
agentVersion: agent.version
|
|
282
366
|
};
|
|
283
367
|
writeManifest(installPath, manifest);
|
|
368
|
+
|
|
369
|
+
// Generate MANIFEST.yaml and update agent instruction files
|
|
370
|
+
await generateSkillsManifest(installPath, agent);
|
|
371
|
+
if (scope === 'project') {
|
|
372
|
+
await updateAgentInstructions(agent, process.cwd());
|
|
373
|
+
}
|
|
284
374
|
}
|
|
285
375
|
} catch (error) {
|
|
286
376
|
console.log(chalk.red(` x Failed: ${error.message}`));
|
|
@@ -330,6 +420,12 @@ async function uninstallSkill(skillId, agentIds, customPath = '', scope = 'proje
|
|
|
330
420
|
writeManifest(installPath, manifest);
|
|
331
421
|
|
|
332
422
|
console.log(chalk.green(` - Removed ${skillId} v${installed.version} from ${agent.name}`));
|
|
423
|
+
|
|
424
|
+
// Generate MANIFEST.yaml and update agent instruction files
|
|
425
|
+
await generateSkillsManifest(installPath, agent);
|
|
426
|
+
if (scope === 'project') {
|
|
427
|
+
await updateAgentInstructions(agent, process.cwd());
|
|
428
|
+
}
|
|
333
429
|
} catch (error) {
|
|
334
430
|
console.log(chalk.red(` x Failed: ${error.message}`));
|
|
335
431
|
}
|
|
@@ -353,9 +449,9 @@ function getStatus(agentIds, customPath = '', scope = 'project') {
|
|
|
353
449
|
const pathsToCheck = customPath
|
|
354
450
|
? [{ path: customPath, scope: 'custom' }]
|
|
355
451
|
: [
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
452
|
+
{ path: projectPath, scope: 'project' },
|
|
453
|
+
{ path: globalPath, scope: 'global' }
|
|
454
|
+
];
|
|
359
455
|
|
|
360
456
|
for (const { path: checkPath, scope: checkScope } of pathsToCheck) {
|
|
361
457
|
const manifest = readManifest(checkPath);
|
package/package.json
CHANGED
|
@@ -3,5 +3,16 @@
|
|
|
3
3
|
"description": "Verify security of JavaScript and TypeScript codebases against OWASP Top 10 2025 standards",
|
|
4
4
|
"version": "1.0.0",
|
|
5
5
|
"author": "AI Agent Skills",
|
|
6
|
-
"tags": [
|
|
7
|
-
|
|
6
|
+
"tags": [
|
|
7
|
+
"javascript",
|
|
8
|
+
"typescript",
|
|
9
|
+
"security",
|
|
10
|
+
"OWASP",
|
|
11
|
+
"vulnerability-scanning"
|
|
12
|
+
],
|
|
13
|
+
"applies_when": [
|
|
14
|
+
"writing or reviewing security-critical code",
|
|
15
|
+
"analyzing third-party dependencies",
|
|
16
|
+
"performing security audits"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -3,5 +3,15 @@
|
|
|
3
3
|
"description": "Generates comprehensive unit and integration tests",
|
|
4
4
|
"version": "1.0.0",
|
|
5
5
|
"author": "AI Agent Skills",
|
|
6
|
-
"tags": [
|
|
7
|
-
|
|
6
|
+
"tags": [
|
|
7
|
+
"testing",
|
|
8
|
+
"unit-tests",
|
|
9
|
+
"integration-tests",
|
|
10
|
+
"quality"
|
|
11
|
+
],
|
|
12
|
+
"applies_when": [
|
|
13
|
+
"creating new code files",
|
|
14
|
+
"adding complex logic",
|
|
15
|
+
"refactoring existing code"
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -4,5 +4,17 @@
|
|
|
4
4
|
"version": "1.0.0",
|
|
5
5
|
"author": "vercel-labs",
|
|
6
6
|
"source": "https://skills.sh/vercel-labs/agent-skills/vercel-react-best-practices",
|
|
7
|
-
"tags": [
|
|
8
|
-
|
|
7
|
+
"tags": [
|
|
8
|
+
"react",
|
|
9
|
+
"nextjs",
|
|
10
|
+
"performance",
|
|
11
|
+
"optimization",
|
|
12
|
+
"vercel",
|
|
13
|
+
"best-practices"
|
|
14
|
+
],
|
|
15
|
+
"applies_when": [
|
|
16
|
+
"working on React or Next.js components",
|
|
17
|
+
"optimizing page performance",
|
|
18
|
+
"reviewing frontend code architecture"
|
|
19
|
+
]
|
|
20
|
+
}
|