Skip to content

Commit 8589063

Browse files
committed
feat: Add Agent Skills system for modular instruction packages
Agent Skills are specialized workflows that extend the agent with domain expertise. Skills work like on-demand AGENTS.md files that can be activated for specific tasks. Features: - /skills command to list, activate, and deactivate skills - /skills new command to create skills with LLM assistance - --auto-skill flag to generate skills from project analysis - Skill discovery from ~/.autohand/skills/, ~/.claude/skills/, ~/.codex/skills/ - Auto-copy vendor skills (Claude/Codex) to Autohand location - Community skills backup and sync via API - SKILL.md format with YAML frontmatter + markdown body Skill locations (in precedence order): - ~/.codex/skills/**/SKILL.md (user, recursive) - ~/.claude/skills/*/SKILL.md (user, one level) - ~/.autohand/skills/**/SKILL.md (user, recursive) - <project>/.claude/skills/*/SKILL.md (project) - <project>/.autohand/skills/**/SKILL.md (project)
1 parent f5cd1a6 commit 8589063

27 files changed

+5938
-106
lines changed

.github/workflows/release.yml

Lines changed: 81 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,12 @@ jobs:
8282
MINOR=$(echo $CURRENT_VERSION | cut -d. -f2)
8383
PATCH=$(echo $CURRENT_VERSION | cut -d. -f3 | cut -d- -f1)
8484
85-
# Determine version bump based on commit messages
85+
# Standard semver: bump patch by default, minor for features, major for breaking
8686
if git log --format=%B -n 20 | grep -qi "BREAKING CHANGE\|!:"; then
8787
MAJOR=$((MAJOR + 1))
8888
MINOR=0
8989
PATCH=0
90-
elif git log --format=%B -n 10 | grep -qi "^feat"; then
90+
elif git log --format=%B -n 10 | grep -qiE "^feat(\(|:)"; then
9191
MINOR=$((MINOR + 1))
9292
PATCH=0
9393
else
@@ -240,70 +240,116 @@ jobs:
240240
241241
// Get commits since last tag
242242
let commits;
243+
let lastTag = null;
243244
try {
244-
const lastTag = execSync('git describe --tags --abbrev=0', { encoding: 'utf8' }).trim();
245-
commits = execSync(`git log ${lastTag}..HEAD --pretty=format:"%h %s"`, { encoding: 'utf8' });
245+
lastTag = execSync('git describe --tags --abbrev=0', { encoding: 'utf8' }).trim();
246+
commits = execSync(`git log ${lastTag}..HEAD --pretty=format:"%s"`, { encoding: 'utf8' });
246247
} catch {
247-
commits = execSync('git log --pretty=format:"%h %s" -n 20', { encoding: 'utf8' });
248+
commits = execSync('git log --pretty=format:"%s" -n 20', { encoding: 'utf8' });
248249
}
249250
250-
const lines = commits.split('\n').filter(line => line.trim());
251+
const lines = commits.split('\n').filter(line => line.trim() && !line.includes('chore(release)'));
252+
253+
// Helper to humanize commit messages
254+
const humanize = (msg) => {
255+
return msg
256+
.replace(/^feat(\([^)]+\))?:\s*/i, '')
257+
.replace(/^fix(\([^)]+\))?:\s*/i, '')
258+
.replace(/^chore(\([^)]+\))?:\s*/i, '')
259+
.replace(/^docs(\([^)]+\))?:\s*/i, '')
260+
.replace(/^refactor(\([^)]+\))?:\s*/i, '')
261+
.replace(/^test(\([^)]+\))?:\s*/i, '')
262+
.replace(/^ci(\([^)]+\))?:\s*/i, '')
263+
.replace(/^perf(\([^)]+\))?:\s*/i, '')
264+
.trim();
265+
};
266+
267+
// Capitalize first letter
268+
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
251269
252270
// Categorize commits
253271
const features = [];
254272
const fixes = [];
255-
const chores = [];
273+
const improvements = [];
256274
const breaking = [];
257275
258-
for (const line of lines) {
259-
const [hash, ...msgParts] = line.split(' ');
260-
const msg = msgParts.join(' ');
276+
for (const msg of lines) {
277+
const clean = humanize(msg);
278+
if (!clean) continue;
261279
262280
if (msg.includes('BREAKING CHANGE') || msg.includes('!:')) {
263-
breaking.push(`- ${msg} (${hash})`);
264-
} else if (msg.startsWith('feat')) {
265-
features.push(`- ${msg.replace('feat:', '').replace('feat(', '(').trim()} (${hash})`);
266-
} else if (msg.startsWith('fix')) {
267-
fixes.push(`- ${msg.replace('fix:', '').replace('fix(', '(').trim()} (${hash})`);
268-
} else if (!msg.startsWith('chore(release)')) {
269-
chores.push(`- ${msg} (${hash})`);
281+
breaking.push(capitalize(clean));
282+
} else if (msg.match(/^feat(\(|:)/i)) {
283+
features.push(capitalize(clean));
284+
} else if (msg.match(/^fix(\(|:)/i)) {
285+
fixes.push(capitalize(clean));
286+
} else if (msg.match(/^(refactor|perf|chore|docs|test|ci)(\(|:)/i)) {
287+
improvements.push(capitalize(clean));
270288
}
271289
}
272290
273-
// Build changelog
274-
let changelog = '## 🚀 What\'s Changed\n\n';
291+
// Build a friendly changelog
292+
let changelog = '';
275293
294+
// Intro
295+
if (lastTag) {
296+
changelog += `Hey there! We've been busy making Autohand better. Here's what's new since ${lastTag}:\n\n`;
297+
} else {
298+
changelog += `Hey there! Here's what's new in this release:\n\n`;
299+
}
300+
301+
// Breaking changes (serious tone)
276302
if (breaking.length > 0) {
277-
changelog += '### ⚠️ BREAKING CHANGES\n' + breaking.join('\n') + '\n\n';
303+
changelog += '### Heads up! Breaking Changes\n\n';
304+
changelog += 'These changes might require updates to your setup:\n\n';
305+
breaking.forEach(item => { changelog += `- ${item}\n`; });
306+
changelog += '\n';
278307
}
279308
309+
// Features (excited tone)
280310
if (features.length > 0) {
281-
changelog += '### ✨ Features\n' + features.join('\n') + '\n\n';
311+
changelog += '### New Stuff\n\n';
312+
features.forEach(item => { changelog += `- ${item}\n`; });
313+
changelog += '\n';
282314
}
283315
316+
// Fixes (helpful tone)
284317
if (fixes.length > 0) {
285-
changelog += '### 🐛 Bug Fixes\n' + fixes.join('\n') + '\n\n';
318+
changelog += '### Bug Fixes\n\n';
319+
if (fixes.length === 1) {
320+
changelog += `We squashed a bug:\n\n`;
321+
} else {
322+
changelog += `We squashed ${fixes.length} bugs:\n\n`;
323+
}
324+
fixes.forEach(item => { changelog += `- ${item}\n`; });
325+
changelog += '\n';
326+
}
327+
328+
// Improvements (casual tone)
329+
if (improvements.length > 0 && improvements.length <= 8) {
330+
changelog += '### Under the Hood\n\n';
331+
changelog += 'Some housekeeping and improvements:\n\n';
332+
improvements.forEach(item => { changelog += `- ${item}\n`; });
333+
changelog += '\n';
286334
}
287335
288-
if (chores.length > 0 && chores.length < 10) {
289-
changelog += '### 🔧 Maintenance\n' + chores.join('\n') + '\n\n';
336+
// If nothing categorized, add a generic message
337+
if (features.length === 0 && fixes.length === 0 && improvements.length === 0 && breaking.length === 0) {
338+
changelog += 'Minor updates and improvements to keep things running smoothly.\n\n';
290339
}
291340
292-
// Add installation instructions
341+
// Installation section
293342
const cb = '`' + '`' + '`';
294-
changelog += '\n## 📦 Installation\n\n';
295-
changelog += '### Recommended: Install Script\n';
343+
changelog += '---\n\n';
344+
changelog += '### Get it\n\n';
345+
changelog += '**Quickest way:**\n';
296346
changelog += cb + 'bash\ncurl -fsSL https://autohand.ai/install.sh | sh\n' + cb + '\n\n';
297-
changelog += '### Or install a specific version\n';
298-
changelog += cb + 'bash\nAUTOHAND_VERSION=' + version + ' curl -fsSL https://autohand.ai/install.sh | sh\n' + cb + '\n\n';
299-
changelog += '### Via npm/bun\n';
300-
changelog += cb + 'bash\nnpm install -g autohand-cli\n# or\nbun install -g autohand-cli\n' + cb + '\n\n';
301-
changelog += '### Manual Download\n';
302-
changelog += 'Download the appropriate binary for your system from the assets below.\n\n';
303-
changelog += '## 📋 Available Binaries\n';
347+
changelog += '**Via npm or bun:**\n';
348+
changelog += cb + 'bash\nnpm install -g autohand-cli\n' + cb + '\n\n';
349+
changelog += '**Or grab a binary below** for your platform.\n\n';
304350
changelog += '| Platform | Architecture | Binary |\n';
305351
changelog += '|----------|--------------|--------|\n';
306-
changelog += '| macOS | Apple Silicon (M1/M2/M3/M4) | `autohand-macos-arm64` |\n';
352+
changelog += '| macOS | Apple Silicon | `autohand-macos-arm64` |\n';
307353
changelog += '| macOS | Intel | `autohand-macos-x64` |\n';
308354
changelog += '| Linux | x64 | `autohand-linux-x64` |\n';
309355
changelog += '| Linux | ARM64 | `autohand-linux-arm64` |\n';

0 commit comments

Comments
 (0)