ma-agents 1.3.0 → 1.5.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/index.js CHANGED
@@ -1,20 +1,22 @@
1
1
  /**
2
- * AI Agent Skills - Programmatic API
2
+ * ma-agents - Programmatic API
3
3
  *
4
4
  * This module exports the core functionality for use as a library.
5
- * For CLI usage, use: npx ai-agent-skills
5
+ * For CLI usage, use: npx ma-agents
6
6
  */
7
7
 
8
- const { installSkill, listSkills, listAgents } = require('./lib/installer');
8
+ const { installSkill, uninstallSkill, getStatus, listSkills, listAgents, readManifest, getInstalledSkillInfo, compareSemver } = require('./lib/installer');
9
9
  const { getAgent, getAllAgents } = require('./lib/agents');
10
10
 
11
11
  module.exports = {
12
- // Installer functions
13
12
  installSkill,
13
+ uninstallSkill,
14
+ getStatus,
14
15
  listSkills,
15
16
  listAgents,
16
-
17
- // Agent functions
17
+ readManifest,
18
+ getInstalledSkillInfo,
19
+ compareSemver,
18
20
  getAgent,
19
21
  getAllAgents
20
22
  };
package/lib/agents.js CHANGED
@@ -17,6 +17,7 @@ const agents = [
17
17
  {
18
18
  id: 'claude-code',
19
19
  name: 'Claude Code',
20
+ version: '1.0.0',
20
21
  description: 'Anthropic Claude Code CLI',
21
22
  getProjectPath: () => path.join(process.cwd(), '.claude', 'skills'),
22
23
  getGlobalPath: () => {
@@ -35,6 +36,7 @@ const agents = [
35
36
  {
36
37
  id: 'gemini',
37
38
  name: 'Google Gemini',
39
+ version: '1.0.0',
38
40
  description: 'Google Gemini Code Assist',
39
41
  getProjectPath: () => path.join(process.cwd(), '.gemini', 'skills'),
40
42
  getGlobalPath: () => {
@@ -53,6 +55,7 @@ const agents = [
53
55
  {
54
56
  id: 'copilot',
55
57
  name: 'GitHub Copilot',
58
+ version: '1.0.0',
56
59
  description: 'GitHub Copilot Agent Mode',
57
60
  getProjectPath: () => path.join(process.cwd(), '.github', 'copilot', 'skills'),
58
61
  getGlobalPath: () => {
@@ -71,6 +74,7 @@ const agents = [
71
74
  {
72
75
  id: 'kilocode',
73
76
  name: 'Kilocode',
77
+ version: '1.0.0',
74
78
  description: 'Kilocode AI Assistant',
75
79
  getProjectPath: () => path.join(process.cwd(), '.kilocode', 'skills'),
76
80
  getGlobalPath: () => {
@@ -89,6 +93,7 @@ const agents = [
89
93
  {
90
94
  id: 'cline',
91
95
  name: 'Cline',
96
+ version: '1.0.0',
92
97
  description: 'Cline AI Assistant',
93
98
  getProjectPath: () => path.join(process.cwd(), '.cline', 'skills'),
94
99
  getGlobalPath: () => {
@@ -102,11 +107,17 @@ const agents = [
102
107
  }
103
108
  },
104
109
  fileExtension: '.md',
105
- template: 'cline'
110
+ template: 'cline',
111
+ // Cline uses different directory names than the generic structure
112
+ resourceMap: {
113
+ 'references': 'docs',
114
+ 'assets': 'templates'
115
+ }
106
116
  },
107
117
  {
108
118
  id: 'cursor',
109
119
  name: 'Cursor',
120
+ version: '1.0.0',
110
121
  description: 'Cursor AI Editor',
111
122
  getProjectPath: () => path.join(process.cwd(), '.cursor', 'skills'),
112
123
  getGlobalPath: () => {
package/lib/installer.js CHANGED
@@ -1,11 +1,72 @@
1
1
  const fs = require('fs-extra');
2
2
  const path = require('path');
3
3
  const chalk = require('chalk');
4
+ const prompts = require('prompts');
4
5
  const { getAgent, getAllAgents } = require('./agents');
5
6
 
7
+ const MANIFEST_FILE = '.ma-agents.json';
8
+ const MANIFEST_VERSION = '1.0.0';
9
+
10
+ function getPackageVersion() {
11
+ const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8'));
12
+ return pkg.version;
13
+ }
14
+
15
+ // --- Manifest functions ---
16
+
17
+ function readManifest(installPath) {
18
+ const manifestPath = path.join(installPath, MANIFEST_FILE);
19
+ if (!fs.existsSync(manifestPath)) {
20
+ return null;
21
+ }
22
+ try {
23
+ return JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
24
+ } catch {
25
+ return null;
26
+ }
27
+ }
28
+
29
+ function writeManifest(installPath, manifest) {
30
+ const manifestPath = path.join(installPath, MANIFEST_FILE);
31
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
32
+ }
33
+
34
+ function ensureManifest(installPath, agentId, scope) {
35
+ let manifest = readManifest(installPath);
36
+ if (!manifest) {
37
+ manifest = {
38
+ manifestVersion: MANIFEST_VERSION,
39
+ agent: agentId,
40
+ scope: scope,
41
+ skills: {}
42
+ };
43
+ }
44
+ return manifest;
45
+ }
46
+
47
+ function getInstalledSkillInfo(installPath, skillId) {
48
+ const manifest = readManifest(installPath);
49
+ if (!manifest || !manifest.skills || !manifest.skills[skillId]) {
50
+ return null;
51
+ }
52
+ return manifest.skills[skillId];
53
+ }
54
+
6
55
  /**
7
- * Get all available skills
56
+ * Compare two semver strings. Returns -1, 0, or 1.
8
57
  */
58
+ function compareSemver(a, b) {
59
+ const pa = (a || '0.0.0').split('.').map(Number);
60
+ const pb = (b || '0.0.0').split('.').map(Number);
61
+ for (let i = 0; i < 3; i++) {
62
+ if (pa[i] > pb[i]) return 1;
63
+ if (pa[i] < pb[i]) return -1;
64
+ }
65
+ return 0;
66
+ }
67
+
68
+ // --- Skill listing ---
69
+
9
70
  function listSkills() {
10
71
  const skillsDir = path.join(__dirname, '..', 'skills');
11
72
 
@@ -32,17 +93,82 @@ function listSkills() {
32
93
  }).filter(Boolean);
33
94
  }
34
95
 
35
- /**
36
- * Get all supported agents
37
- */
38
96
  function listAgents() {
39
97
  return getAllAgents();
40
98
  }
41
99
 
42
- /**
43
- * Install a skill for specified agents
44
- */
45
- async function installSkill(skillId, agentIds, customPath = '', scope = 'project') {
100
+ // --- Core install logic (no prompts) ---
101
+
102
+ async function performInstall(skillId, skill, agent, installPath) {
103
+ const skillSourceDir = path.join(__dirname, '..', 'skills', skillId);
104
+ let sourceFile = path.join(skillSourceDir, `${agent.template}${agent.fileExtension}`);
105
+
106
+ if (!fs.existsSync(sourceFile)) {
107
+ sourceFile = path.join(skillSourceDir, `generic${agent.fileExtension}`);
108
+ }
109
+
110
+ if (!fs.existsSync(sourceFile)) {
111
+ const skillMdPath = path.join(skillSourceDir, 'SKILL.md');
112
+ if (fs.existsSync(skillMdPath)) {
113
+ sourceFile = skillMdPath;
114
+ }
115
+ }
116
+
117
+ if (!fs.existsSync(sourceFile)) {
118
+ console.log(chalk.yellow(` Warning: No template found for ${agent.name}, skipping`));
119
+ return false;
120
+ }
121
+
122
+ const skillDir = path.join(installPath, skillId);
123
+ await fs.ensureDir(skillDir);
124
+
125
+ let content = await fs.readFile(sourceFile, 'utf-8');
126
+
127
+ // Strip any existing YAML frontmatter from the source
128
+ const frontmatterRegex = /^---\s*\n[\s\S]*?\n---\s*\n/;
129
+ content = content.replace(frontmatterRegex, '');
130
+
131
+ // Inject YAML frontmatter from skill.json (single source of truth)
132
+ const frontmatter = [
133
+ '---',
134
+ `name: ${skill.name}`,
135
+ `description: ${skill.description}`,
136
+ '---',
137
+ ''
138
+ ].join('\n');
139
+ content = frontmatter + content;
140
+
141
+ const targetFile = path.join(skillDir, 'SKILL.md');
142
+ await fs.writeFile(targetFile, content, 'utf-8');
143
+ console.log(chalk.green(` + Installed to ${targetFile}`));
144
+
145
+ // Copy bundled resources
146
+ const resourceMap = agent.resourceMap || {};
147
+ const resourceDirs = ['scripts', 'references', 'assets', 'examples', 'hooks', 'docs', 'templates'];
148
+ for (const dir of resourceDirs) {
149
+ const resourceSource = path.join(skillSourceDir, dir);
150
+ if (fs.existsSync(resourceSource)) {
151
+ const targetDirName = resourceMap[dir] || dir;
152
+ const resourceTarget = path.join(skillDir, targetDirName);
153
+ await fs.copy(resourceSource, resourceTarget);
154
+ console.log(chalk.green(` + Copied ${dir}/ → ${targetDirName}/`));
155
+ }
156
+ }
157
+
158
+ // Copy template.md if it exists
159
+ const templateSource = path.join(skillSourceDir, 'template.md');
160
+ if (fs.existsSync(templateSource)) {
161
+ await fs.copy(templateSource, path.join(skillDir, 'template.md'));
162
+ console.log(chalk.green(` + Copied template.md`));
163
+ }
164
+
165
+ return true;
166
+ }
167
+
168
+ // --- Install with upgrade detection ---
169
+
170
+ async function installSkill(skillId, agentIds, customPath = '', scope = 'project', options = {}) {
171
+ const { force = false } = options;
46
172
  const skills = listSkills();
47
173
  const skill = skills.find(s => s.id === skillId);
48
174
 
@@ -50,7 +176,7 @@ async function installSkill(skillId, agentIds, customPath = '', scope = 'project
50
176
  throw new Error(`Skill '${skillId}' not found. Run "list" to see available skills.`);
51
177
  }
52
178
 
53
- console.log(chalk.cyan(`\nInstalling skill: ${skill.name}`));
179
+ console.log(chalk.cyan(`\nInstalling skill: ${skill.name} v${skill.version}`));
54
180
 
55
181
  for (const agentId of agentIds) {
56
182
  const agent = getAgent(agentId);
@@ -60,61 +186,202 @@ async function installSkill(skillId, agentIds, customPath = '', scope = 'project
60
186
  continue;
61
187
  }
62
188
 
63
- console.log(chalk.gray(` Installing for ${agent.name}...`));
64
-
65
189
  try {
66
- // Determine installation path
67
190
  const installPath = customPath || (scope === 'global' ? agent.getGlobalPath() : agent.getProjectPath());
68
-
69
- // Ensure the skills directory exists
70
191
  await fs.ensureDir(installPath);
71
192
 
72
- // Get the skill source file based on agent template
73
- const skillSourceDir = path.join(__dirname, '..', 'skills', skillId);
74
- let sourceFile = path.join(skillSourceDir, `${agent.template}${agent.fileExtension}`);
193
+ const installed = getInstalledSkillInfo(installPath, skillId);
75
194
 
76
- // Fallback to generic template if specific template doesn't exist
77
- if (!fs.existsSync(sourceFile)) {
78
- sourceFile = path.join(skillSourceDir, `generic${agent.fileExtension}`);
79
- }
195
+ if (installed && !force) {
196
+ const cmp = compareSemver(skill.version, installed.version);
80
197
 
81
- // Fallback to SKILL.md if no agent-specific or generic template exists
82
- if (!fs.existsSync(sourceFile)) {
83
- const skillMdPath = path.join(skillSourceDir, 'SKILL.md');
84
- if (fs.existsSync(skillMdPath)) {
85
- sourceFile = skillMdPath;
198
+ let action;
199
+ if (cmp > 0) {
200
+ // Upgrade available
201
+ console.log(chalk.yellow(` ${skill.name} v${installed.version} → v${skill.version} update available for ${agent.name}`));
202
+ const { choice } = await prompts({
203
+ type: 'select',
204
+ name: 'choice',
205
+ message: 'What would you like to do?',
206
+ choices: [
207
+ { title: 'Update (recommended)', value: 'update' },
208
+ { title: 'Skip (keep current)', value: 'skip' },
209
+ { title: 'Clean reinstall', value: 'reinstall' },
210
+ { title: 'Remove (uninstall)', value: 'remove' }
211
+ ]
212
+ });
213
+ action = choice;
214
+ } else if (cmp === 0) {
215
+ // Same version
216
+ console.log(chalk.gray(` ${skill.name} v${installed.version} already installed for ${agent.name}`));
217
+ const { choice } = await prompts({
218
+ type: 'select',
219
+ name: 'choice',
220
+ message: 'What would you like to do?',
221
+ choices: [
222
+ { title: 'Skip (keep current)', value: 'skip' },
223
+ { title: 'Clean reinstall', value: 'reinstall' },
224
+ { title: 'Remove (uninstall)', value: 'remove' }
225
+ ]
226
+ });
227
+ action = choice;
228
+ } else {
229
+ // Downgrade
230
+ console.log(chalk.yellow(` ${skill.name} v${installed.version} installed, package has v${skill.version} for ${agent.name}`));
231
+ const { choice } = await prompts({
232
+ type: 'select',
233
+ name: 'choice',
234
+ message: 'What would you like to do?',
235
+ choices: [
236
+ { title: 'Skip (keep current)', value: 'skip' },
237
+ { title: `Downgrade to v${skill.version}`, value: 'update' },
238
+ { title: 'Remove (uninstall)', value: 'remove' }
239
+ ]
240
+ });
241
+ action = choice;
86
242
  }
243
+
244
+ if (!action || action === 'skip') {
245
+ console.log(chalk.gray(` Skipped`));
246
+ continue;
247
+ }
248
+
249
+ if (action === 'remove') {
250
+ await performUninstall(skillId, installPath);
251
+ const manifest = ensureManifest(installPath, agentId, scope);
252
+ delete manifest.skills[skillId];
253
+ writeManifest(installPath, manifest);
254
+ console.log(chalk.green(` - Removed ${skill.name} from ${agent.name}`));
255
+ continue;
256
+ }
257
+
258
+ if (action === 'reinstall') {
259
+ await performUninstall(skillId, installPath);
260
+ }
261
+
262
+ // action === 'update' or 'reinstall' → proceed to install below
87
263
  }
88
264
 
89
- if (!fs.existsSync(sourceFile)) {
90
- console.log(chalk.yellow(` Warning: No template found for ${agent.name}, skipping`));
91
- continue;
265
+ if (!installed || force) {
266
+ console.log(chalk.gray(` Installing for ${agent.name}...`));
92
267
  }
93
268
 
94
- // Copy the skill file
95
- const targetFile = path.join(installPath, `${skillId}${agent.fileExtension}`);
96
- await fs.copy(sourceFile, targetFile);
97
- console.log(chalk.green(` + Installed to ${targetFile}`));
98
-
99
- // Copy bundled resources (scripts/, references/, assets/) if they exist
100
- const resourceDirs = ['scripts', 'references', 'assets'];
101
- for (const dir of resourceDirs) {
102
- const resourceSource = path.join(skillSourceDir, dir);
103
- if (fs.existsSync(resourceSource)) {
104
- const resourceTarget = path.join(installPath, skillId, dir);
105
- await fs.ensureDir(path.join(installPath, skillId));
106
- await fs.copy(resourceSource, resourceTarget);
107
- console.log(chalk.green(` + Copied ${dir}/ resources`));
269
+ const success = await performInstall(skillId, skill, agent, installPath);
270
+
271
+ if (success) {
272
+ // Update manifest
273
+ const manifest = ensureManifest(installPath, agentId, scope);
274
+ const now = new Date().toISOString();
275
+ const existing = manifest.skills[skillId];
276
+ manifest.skills[skillId] = {
277
+ version: skill.version,
278
+ installedAt: existing ? existing.installedAt : now,
279
+ updatedAt: now,
280
+ installerVersion: getPackageVersion(),
281
+ agentVersion: agent.version
282
+ };
283
+ writeManifest(installPath, manifest);
284
+ }
285
+ } catch (error) {
286
+ console.log(chalk.red(` x Failed: ${error.message}`));
287
+ }
288
+ }
289
+ }
290
+
291
+ // --- Uninstall ---
292
+
293
+ async function performUninstall(skillId, installPath) {
294
+ const skillDir = path.join(installPath, skillId);
295
+ if (fs.existsSync(skillDir)) {
296
+ await fs.remove(skillDir);
297
+ }
298
+ }
299
+
300
+ async function uninstallSkill(skillId, agentIds, customPath = '', scope = 'project') {
301
+ console.log(chalk.cyan(`\nUninstalling skill: ${skillId}`));
302
+
303
+ for (const agentId of agentIds) {
304
+ const agent = getAgent(agentId);
305
+
306
+ if (!agent) {
307
+ console.log(chalk.yellow(` Warning: Skipping unknown agent: ${agentId}`));
308
+ continue;
309
+ }
310
+
311
+ try {
312
+ const installPath = customPath || (scope === 'global' ? agent.getGlobalPath() : agent.getProjectPath());
313
+ const installed = getInstalledSkillInfo(installPath, skillId);
314
+
315
+ if (!installed) {
316
+ const skillDir = path.join(installPath, skillId);
317
+ if (fs.existsSync(skillDir)) {
318
+ await performUninstall(skillId, installPath);
319
+ console.log(chalk.green(` - Removed ${skillId} from ${agent.name} (legacy install)`));
320
+ } else {
321
+ console.log(chalk.gray(` ${skillId} is not installed for ${agent.name}`));
108
322
  }
323
+ continue;
109
324
  }
325
+
326
+ await performUninstall(skillId, installPath);
327
+
328
+ const manifest = ensureManifest(installPath, agentId, scope);
329
+ delete manifest.skills[skillId];
330
+ writeManifest(installPath, manifest);
331
+
332
+ console.log(chalk.green(` - Removed ${skillId} v${installed.version} from ${agent.name}`));
110
333
  } catch (error) {
111
334
  console.log(chalk.red(` x Failed: ${error.message}`));
112
335
  }
113
336
  }
114
337
  }
115
338
 
339
+ // --- Status ---
340
+
341
+ function getStatus(agentIds, customPath = '', scope = 'project') {
342
+ const results = [];
343
+
344
+ const targetAgents = agentIds && agentIds.length > 0
345
+ ? agentIds.map(id => getAgent(id)).filter(Boolean)
346
+ : getAllAgents();
347
+
348
+ for (const agent of targetAgents) {
349
+ const projectPath = agent.getProjectPath();
350
+ const globalPath = agent.getGlobalPath();
351
+
352
+ // Check both scopes unless custom path is specified
353
+ const pathsToCheck = customPath
354
+ ? [{ path: customPath, scope: 'custom' }]
355
+ : [
356
+ { path: projectPath, scope: 'project' },
357
+ { path: globalPath, scope: 'global' }
358
+ ];
359
+
360
+ for (const { path: checkPath, scope: checkScope } of pathsToCheck) {
361
+ const manifest = readManifest(checkPath);
362
+ if (!manifest || !manifest.skills || Object.keys(manifest.skills).length === 0) {
363
+ continue;
364
+ }
365
+
366
+ results.push({
367
+ agent: agent,
368
+ installPath: checkPath,
369
+ scope: checkScope,
370
+ skills: manifest.skills
371
+ });
372
+ }
373
+ }
374
+
375
+ return results;
376
+ }
377
+
116
378
  module.exports = {
117
379
  listSkills,
118
380
  listAgents,
119
- installSkill
381
+ installSkill,
382
+ uninstallSkill,
383
+ getStatus,
384
+ readManifest,
385
+ getInstalledSkillInfo,
386
+ compareSemver
120
387
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ma-agents",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
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": {
@@ -32,4 +32,4 @@
32
32
  "engines": {
33
33
  "node": ">=14.0.0"
34
34
  }
35
- }
35
+ }
package/skills/README.md CHANGED
@@ -191,6 +191,31 @@ Creates production-ready hardened Docker configurations following security best
191
191
 
192
192
  ---
193
193
 
194
+ ### 5. Test-Accompanied Development (TAD)
195
+ **Directory:** `test-accompanied-development/`
196
+
197
+ Enforces a "Test-Alongside" policy where every public method is accompanied by a corresponding unit test. It ensures high code quality by mandating that all public interfaces are verified by automated tests at the moment of creation.
198
+
199
+ **Key Features:**
200
+ - ✅ **Automatic Enforcement**: Mandates tests for every new public method.
201
+ - ✅ **Integration**: References `test-generator` for implementation standards.
202
+ - ✅ **Workflow Guardrail**: Prevents "test debt" by requiring tests alongside code.
203
+
204
+ ---
205
+
206
+ ### 6. Logging Best Practices
207
+ **Directory:** `logging-best-practices/`
208
+
209
+ Standardizes structured logging (JSON) across Backend, Frontend, Realtime, and Algorithmic domains. Enforces mandatory exception logging and OpenTelemetry-aligned context fields.
210
+
211
+ **Key Features:**
212
+ - ✅ **Structured Logging**: Mandates JSON format for machine-readability.
213
+ - ✅ **Domain-Specific**: Tailored guidance for Web, Server, and High-Performance Algorithm domains.
214
+ - ✅ **Mandatory Exceptions**: Every catch block must log full stack traces.
215
+ - ✅ **Context-Rich**: Standardizes fields like `trace_id`, `placement`, and `process_name`.
216
+
217
+ ---
218
+
194
219
  ## Requirements
195
220
 
196
221
  ### All Skills
@@ -0,0 +1,39 @@
1
+ # Code Review
2
+
3
+ Perform comprehensive code reviews following industry best practices.
4
+
5
+ ## What to Review
6
+
7
+ 1. **Code Quality**: Readability, naming conventions, structure
8
+ 2. **Best Practices**: Language-specific patterns, error handling, performance
9
+ 3. **Security**: Common vulnerabilities (SQL injection, XSS, CSRF, etc.)
10
+ 4. **Testing**: Coverage, edge cases, test quality
11
+ 5. **Documentation**: Comments, API docs, clarity
12
+
13
+ ## Review Process
14
+
15
+ - Analyze code for bugs and logical errors
16
+ - Check adherence to coding standards
17
+ - Identify security vulnerabilities
18
+ - Suggest refactoring opportunities
19
+ - Assess test coverage and documentation
20
+
21
+ ## Output Format
22
+
23
+ ```
24
+ ## Code Review Summary
25
+
26
+ ### Strengths
27
+ - [Positive aspects]
28
+
29
+ ### Issues Found
30
+ - **[High/Medium/Low]** [Issue description]
31
+ - Location: [file:line]
32
+ - Fix: [recommendation]
33
+
34
+ ### Suggestions
35
+ - [Improvements]
36
+
37
+ ### Overall Assessment
38
+ [Summary and rating]
39
+ ```
@@ -0,0 +1,75 @@
1
+ # Commit Message Generator
2
+
3
+ Generate meaningful commit messages following Conventional Commits specification.
4
+
5
+ ## Format
6
+
7
+ ```
8
+ <type>(<scope>): <subject>
9
+
10
+ <body>
11
+
12
+ <footer>
13
+ ```
14
+
15
+ ## Types
16
+
17
+ - `feat`: New feature
18
+ - `fix`: Bug fix
19
+ - `docs`: Documentation changes
20
+ - `style`: Code style/formatting
21
+ - `refactor`: Code refactoring
22
+ - `test`: Adding/updating tests
23
+ - `chore`: Maintenance tasks
24
+ - `perf`: Performance improvements
25
+ - `ci`: CI/CD changes
26
+ - `build`: Build system changes
27
+ - `revert`: Revert previous commit
28
+
29
+ ## Guidelines
30
+
31
+ 1. **Subject line** (max 50 chars):
32
+ - Use imperative mood ("Add" not "Added")
33
+ - Don't capitalize first letter
34
+ - No period at the end
35
+
36
+ 2. **Body** (optional):
37
+ - Explain what and why, not how
38
+ - Wrap at 72 characters
39
+
40
+ 3. **Footer** (optional):
41
+ - Breaking changes: `BREAKING CHANGE: description`
42
+ - Issue references: `Fixes #123`
43
+
44
+ ## Examples
45
+
46
+ ```
47
+ feat(auth): add JWT token refresh mechanism
48
+
49
+ Implement automatic token refresh to improve user experience
50
+ and reduce re-authentication prompts.
51
+
52
+ Fixes #456
53
+ ```
54
+
55
+ ```
56
+ fix(api): resolve memory leak in user service
57
+
58
+ The user cache was not being cleared properly, causing
59
+ memory to grow over time.
60
+ ```
61
+
62
+ ```
63
+ docs: update installation instructions
64
+
65
+ Add steps for Windows users and clarify dependency requirements.
66
+ ```
67
+
68
+ ## Process
69
+
70
+ 1. Analyze the code changes
71
+ 2. Determine the type of change
72
+ 3. Identify the scope (component/module affected)
73
+ 4. Write clear, concise subject
74
+ 5. Add body if changes need explanation
75
+ 6. Add footer for breaking changes or issue refs
@@ -1,8 +1,3 @@
1
- ---
2
- name: create-hardened-docker
3
- description: Creates production-ready hardened Docker configurations (Dockerfile, docker-compose.yml, nginx.conf, .dockerignore) following CIS Docker Benchmark, OWASP, and NIST SP 800-190 standards. Includes multi-stage builds, non-root execution, read-only filesystems, capability dropping, and comprehensive security hardening.
4
- ---
5
-
6
1
  # Create Hardened Docker
7
2
 
8
3
  ## Overview
@@ -1,8 +1,3 @@
1
- ---
2
- name: git-workflow-skill
3
- description: Mandatory feature branch workflow using git worktrees for parallel multi-agent development. Use this skill BEFORE making ANY change to files in a Git repository that are not ignored by .gitignore. Enforces isolated worktrees per feature, conventional commits, and PR-based merging. Supports multiple AI agents working simultaneously on different features without conflicts.
4
- ---
5
-
6
1
  # Git Workflow (Worktree-Based)
7
2
 
8
3
  Multi-agent parallel development using git worktrees. Each agent gets an isolated working directory — no branch switching, no conflicts between agents.
@@ -1,7 +1,3 @@
1
- ---
2
- name: js-ts-security-skill
3
- description: Verify the security of JavaScript and TypeScript codebases against OWASP Top 10 2025 standards.
4
- ---
5
1
 
6
2
  # JS/TS Security Skill
7
3